Commit 59b75a2
Plan 130: ship npm + PyPI distribution and tag-driven version stamp (#239)
* Plan 130: ship npm + PyPI distribution and a tag-driven version stamp
Adds the npm root + platform-package layout, the PyPI wheel skeleton,
the VS Code Marketplace + Open VSX publish steps, and a smoke-test
job that asserts mdsmith version matches the tag on every channel.
scripts/set-version.sh rewrites every tracked manifest from the
0.0.0-dev sentinel to the cleaned tag; scripts/check-versions.sh
runs in a new ci.yml version-guard so a hand edit on main fails fast.
asdf and mise registry submissions are still pending and remain
follow-ups in plan/130 because they live outside this repo.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* Address Copilot review on PR #239
- set-version.sh: accept SemVer with both pre-release and build
metadata (1.2.3-rc.1+build.5) and fail fast when a required
manifest is missing instead of silently skipping.
- check-versions.sh: detect a deleted optionalDependencies key in
npm/mdsmith/package.json so the guard catches drift, not just
pin mismatches.
- build-wheels.sh: retag wheels with `python -m wheel tags` so the
dist-info/WHEEL metadata matches the filename instead of leaving
it stamped py3-none-any. Install `wheel` alongside `build` in
the pypi job.
- pyproject.toml: drop the comment that mentioned a non-existent
marker file.
- release.yml smoke-test: switch the npm channel from node:lts-alpine
to node:lts so the default bash shell exists before the install
step runs.
- internal/release: add TestBuildWheelsLayout that exercises
build-wheels.sh and asserts the WHEEL metadata reflects each
platform tag.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* Address Copilot review pass 2 on PR #239
- check-versions.sh: fail fast when a tracked manifest is missing,
matching set-version.sh's require_file behavior. A renamed or
deleted manifest now blows up the version-guard CI job rather
than silently passing.
- release.yml smoke-test: wrap the npm and mise install commands
in the same retry-with-backoff loop the pip channel uses, since
npm registry propagation can lag the publish by ~60s.
- internal/release: add TestCheckVersionsFailsOnMissingManifest.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* Address Copilot review pass 3 on PR #239
- README.md: drop the misleading mise/asdf one-liner. Until the
registry/plugin follow-ups land, the short forms don't resolve.
- docs/guides/install.md: replace the mise row with the working
`mise use -g ubi:jeduden/mdsmith@latest` form (no registry PR
required), drop the asdf row from the quick-start table, and
flag both the asdf section and the short mise form as
pending-follow-up.
- release.yml smoke-test: switch the mise channel from
`mdsmith@VER` to `ubi:jeduden/mdsmith@VER` so the smoke test
passes on the very first tag, before the mise registry PR.
- build-wheels.sh: wrap each per-wheel build in a subshell with
an EXIT trap so a `python -m build` failure under `set -e`
still cleans up the staging directory. The previous RETURN
trap only fired on a normal return.
- ci.yml test job: install build/wheel/hatchling so the new
TestBuildWheelsLayout actually runs in CI instead of skipping.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* Fix bogus action SHA pins so the test job can resolve setup-python
The setup-python pin I added in the previous commit pointed at a
SHA that does not exist on actions/setup-python, causing the
`test` CI job to fail with "Unable to resolve action" before any
step ran. Same problem for the setup-node and
gh-action-pypi-publish pins introduced in the npm/pypi jobs.
Re-pin each to a real SHA looked up via the GitHub API, with
versions matching what the rest of the repo uses for adjacent
actions:
- actions/setup-python@a309ff8b … # v6.2.0 (matches setup-go v6.2.0)
- actions/setup-node@48b55a01 … # v6.4.0 (latest)
- pypa/gh-action-pypi-publish@6733eb7d … # v1.14.0 (latest)
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* Address Copilot review pass 4 on PR #239
- set-version.sh: pre-flight grep before each rewrite. If a
manifest is missing the expected version field (or the npm root
has no @mdsmith/* optionalDependencies block), abort with an
actionable error instead of letting perl no-op silently and
shipping 0.0.0-dev. Same guard is added to
rewrite_pyproject_version.
- release.yml smoke-test: track an `ok` flag inside each retry
loop and `exit 1` after the loop if no attempt succeeded. The
previous `if cmd; then break; fi` pattern fell through under
bash -e, so a registry that stayed unresolvable would surface
later as an opaque "mdsmith: command not found" instead of
"install never succeeded".
- internal/release: add two regression tests covering the new
rewrite-fails-fast paths.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* Address Copilot review pass 5 on PR #239
- set-version.sh: tighten the SemVer regex to reject leading zeros
in MAJOR/MINOR/PATCH (per semver.org grammar). Both npm and
PyPI reject 01.2.3-style tags downstream; refuse them here so
the failure has an actionable message.
- check-versions.sh: name the drifted pin in error output, e.g.
"@mdsmith/linux-x64 pin '1.2.3'" instead of just "pin '1.2.3'",
so a multi-pin drift produces actionable lines.
- internal/release: add TestSetVersionRejectsLeadingZero and
update TestCheckVersionsRejectsOptionalDepDrift to assert on
the new error format.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* Address Copilot review pass 6 on PR #239
- set-version.sh: tighten the SemVer regex to the full
semver.org grammar. Pre-release identifiers that are purely
numeric must not have leading zeros (so "-01" is rejected, but
"-rc01" stays valid because it is alphanumeric). Build metadata
identifiers keep the spec-mandated leading-zero allowance.
- docs/guides/install.md: clarify the PyPI console script runs
the binary via os.execv on POSIX and subprocess.run on Windows,
matching the actual entrypoint instead of implying execv on
every platform.
- internal/release: add TestSetVersionAcceptsValidSemverShapes
and extend TestSetVersionRejectsLeadingZero to cover prerelease
numeric identifiers.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* Rename npm root to @mdsmith/cli (unscoped 'mdsmith' is taken)
The unscoped `mdsmith` package on npm was registered by another
project (afroldo, 2026-01-31, "CLI para gerar READMEs e arquivos
Markdown"), so we cannot publish a root named `mdsmith`. The
`@mdsmith` scope we already use for the platform sub-packages is
free, so the root publishes there as `@mdsmith/cli`.
The installed binary is still called `mdsmith` because the
package's `bin` field maps the command name independent of the
package name. Users run `npm install -g @mdsmith/cli` and the
`mdsmith` CLI lands on `$PATH` exactly as before.
Updated:
- npm/mdsmith/package.json `name` and the README's install snippet
- README.md install quick-start
- docs/guides/install.md table row, npm section, and prose
- release.yml smoke-test (npm channel pulls @mdsmith/cli@VER)
- plan/130 npm strategy section + acceptance criteria
The bun shim tests didn't need changes — they only exercise the
platform-package resolver, which already lives under @mdsmith/.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* Guard Marketplace/Open VSX publish secrets before continue-on-error
The two extension-publish steps run with `continue-on-error: true`
so a transient Marketplace or Open VSX outage does not block the
downstream `release` job. The same flag would also hide an unset
or empty `VSCE_PAT` / `OVSX_PAT`, leaving us with a "successful"
release that never reached either marketplace.
Add a `Verify Marketplace and Open VSX tokens are set` step (no
continue-on-error) that fails the job if either secret is empty.
The publish steps themselves stay tolerant of registry errors,
so misconfiguration fails fast while outages still allow the
GitHub release to ship.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* Replace bash release scripts with cmd/mdsmith-release Go CLI
The four bash scripts (set-version, check-versions,
build-npm-platforms, build-wheels) used perl regex to edit JSON
and TOML manifests, which was both fragile and indirectly tested
— Go tests shelled out to bash and grepped the output, so a
regression pointed at the wrapper rather than the bug.
Port the logic to internal/release/ (version.go, buildnpm.go,
buildwheels.go) and expose it through a separate cmd/mdsmith-release
binary with four subcommands (stamp, check, build-npm,
build-wheels). The release workflow invokes the Go CLI via
`go run ./cmd/mdsmith-release ...`. Tests now exercise the
exported functions directly.
Behaviour parity:
- Stamp's SemVer regex stays at the full semver.org grammar
(rejects leading zeros in MAJOR/MINOR/PATCH and in numeric
prerelease identifiers).
- Pre-flight checks still fail fast when a manifest is missing,
has no version field, or — for the npm root — drops its
@mdsmith/* optionalDependencies block.
- Check accumulates every problem instead of exiting on the
first, so a multi-pin drift produces multiple actionable
lines.
- BuildWheels still orchestrates `python -m build` and
`python -m wheel tags` (no native Go wheel builder exists),
but the staging directories now clean up on failure via Go
`defer` instead of bash's leak-prone `trap RETURN`.
- Test for BuildWheels skips when python/build/wheel/hatchling
aren't on PATH; the test job in ci.yml already installs them.
Net: -3 toolchain (bash + perl + grep) and +1 (Go), with the
JSON/TOML editing now happening in code that compiles, lints,
and tests under the same toolchain as the rest of the repo.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* Disable setup-go cache in release.yml + raise release-toolkit coverage
zizmor flagged the three new actions/setup-go invocations I added
to the vscode, npm, and pypi jobs as cache-poisoning surfaces.
The existing build job already uses cache: false; mirror that.
Codecov also dropped on the patch — exercise the easy uncovered
paths in cmd/mdsmith-release and internal/release:
- cmd/mdsmith-release: cover bad-arity dispatcher branches for
every subcommand, the invalid-version stamp path, and the
reportError nil/non-nil exit-code mapping.
- internal/release: cover BuildNpmPlatforms when the npm root
manifest is missing, BuildWheels when the python source is
missing, the LICENSE-copy branch, and ValidateSemver on empty
input.
Coverage on the new code: internal/release 79.4% → 81.8%,
cmd/mdsmith-release 50.0% → 81.6%.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* mdsmith-release: switch to pflag and add helper-level coverage
The CLI now uses spf13/pflag with one FlagSet per subcommand,
matching the conventions in cmd/mdsmith/main.go (subcommand
Usage, ContinueOnError, the reportFlagParseErr helper that
pretty-prints non-help parse errors). None of the subcommands
take flags today; the FlagSets exist so adding one later is a
local edit and so help/error messages match the user-facing
binary.
Also raise patch coverage on the release toolkit by exercising
the small helpers directly:
- listWheels (empty, mixed-extension, missing dir)
- moveWheels (empty staging, multi-file relocate)
- copyDir (nested tree)
- stagePythonTree (missing asset)
- BuildWheels (missing artifact, no python invocation needed)
- subcommand --help and --bogus dispatch (covers reportFlagParseErr)
Coverage on the new code: internal/release 81.8% → 84.6%,
cmd/mdsmith-release 81.6% → 88.9%.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* testify on release tests + spin asdf/mise out into plan/145
- Convert internal/release and cmd/mdsmith-release tests to use
testify per CLAUDE.md ("require for preconditions that abort,
assert for checks that continue"). Behaviour unchanged; just
shorter, more idiomatic test code.
- Spin the asdf-plugin repo (jeduden/asdf-mdsmith) and the
mise-plugins/registry submission out of plan/130 into
plan/145 — they ship in separate repos and don't gate the
multi-channel release this branch enables. Plan/130 now points
at plan/145 for the asdf+mise narrative; plan/145 owns the
task list and acceptance criteria for both registry
submissions plus the doc/smoke-test cleanup that follows.
- mdsmith fix . to keep PLAN.md and the catalog in
CLAUDE.md/docs/guides/index.md in sync.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* Push CLI dispatcher coverage to 94% + drop bogus author from pyproject
- cmd/mdsmith-release tests now exercise the success branch of
runCheck (println "all manifests pinned at"), the happy-path
build-npm dispatch end-to-end, and reportError-translated
failures for both build-npm and build-wheels. Coverage on the
CLI: 88.9% → 94.4%.
- python/pyproject.toml: remove the made-up `authors = [...]`
entry I added when scaffolding the wheel. The PyPI metadata
field is optional; until the real author info is provided, no
entry is better than a wrong one.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* Cover release-toolkit error branches: 95.8% CLI, 88.3% library
CI's codecov gate failed because patch coverage (79.82%) was
well below the project's auto-target (95.14%). Push the new
code's coverage by exercising the small but numerous IO error
returns directly:
- internal/release helpers: stage / list / move / copy / retag
primitives all get direct error-path tests (missing source,
rename target as a file, missing dir, etc.).
- BuildNpmPlatforms: cover the per-platform mkdir-fails branch
by colliding the platform path with a regular file.
- TrackedManifests: pin the readdir-of-platform-subpackages
branch so the slice growth path is observable.
- cmd/mdsmith-release: direct unit test for the
reportFlagParseErr nil branch and end-to-end dispatch paths
that surface reportError-translated failures for build-npm
and build-wheels.
Coverage: cmd/mdsmith-release 88.9% → 95.8%, internal/release
84.6% → 88.3%. Remaining uncovered statements in the library
are IO-error returns (mkdir failure mid-stage, write failure)
that need OS-level fault injection to trigger reliably; those
will catch up when codecov re-measures with the new tests.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* release: route all IO through an injectable FS interface
The codecov gate kept failing because the release-toolkit's IO
error returns (mkdir-failure mid-pipeline, ReadFile/WriteFile
faults, Rename onto a non-directory) cannot be triggered against
a healthy filesystem, leaving entire `if err != nil { return err }`
arms uncovered.
Introduce a small writable FS interface alongside the existing
read-only fs.FS pattern in the rest of the codebase. The Toolkit
struct holds an FS field, defaults to osFS in production, and
accepts a fault-injecting fakeFS in tests so every error-return
branch is exercised.
- internal/release/fs.go — FS interface + osFS impl + Toolkit
- internal/release/{version,buildnpm,buildwheels}.go — methods on
Toolkit; package-level Stamp / Check / BuildNpmPlatforms /
BuildWheels keep the original signatures by delegating to a
default Toolkit.
- internal/release/fault_test.go — fakeFS with per-method
failOn{N}Call counters plus a battery of fault-injection tests
covering each IO error return.
Coverage on the package: 88.3% → 94.2%. The remaining holes are
the python-orchestration branches (require python on PATH) and
two unreachable defaults.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* release: route python invocations through an injectable Runner
The remaining patch-coverage gap was the python-orchestration
failure branches in buildwheels.go (runPythonBuild's "python -m
build" failed, retagWheels' "python -m wheel tags" failed). Both
paths require python on PATH AND a way to make python fail —
hard to drive against a real interpreter.
Add a tiny Runner interface alongside FS:
type Runner interface {
RunCommand(dir, name string, args ...string) error
}
Toolkit grows a runner field; New() defaults to osRunner, tests
construct via NewWithDeps(fakeFS, fakeRunner). runPythonBuild
becomes a method on Toolkit; retagWheels switches its inner
exec.Command to t.runner.RunCommand.
Three new fault tests (runPythonBuild fail, retagWheels fail,
buildOneWheel propagates python-build fail) close the
orchestration-failure coverage holes.
Coverage on internal/release: 94.2% → 95.6%.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* release: cover the manifest-write and listWheels-skip-dir cases
Two small gaps left after the FS / Runner refactor:
- buildOneNpmPlatform 93.8% — the package.json WriteFile failure
(the second per-platform write, between the binary copy and an
optional LICENSE) had no fault test. Add one.
- listWheels 90% — the IsDir-skip branch (a directory whose name
ends in `.whl`) was never exercised. Drop a `subdir.whl/` into
the filter test so the skip path runs.
Coverage on internal/release: 95.6% → 96.4%.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* release: cover the retagWheels and moveWheels error branches in buildOneWheel
After the FS+Runner refactor, the only buildOneWheel statements
left uncovered were the two error returns following
runPythonBuild: retagWheels-fails and moveWheels-fails. Both
need a wheel actually present in staging so the helpers have
work to do (otherwise their inner loops short-circuit and never
trigger the failure paths).
Add a preStageWheel helper that drops a real fake.whl into the
staging dir before the test calls buildOneWheel, then arm
either the Runner (for retagWheels) or FS.Rename (for
moveWheels) to fail.
Coverage on internal/release: 96.4% → 96.9%.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* release: cover the no-version-field and copyDir-mkdir branches
Two unreached statements left after the buildOneWheel coverage
push:
- checkManifest's "no version field found" note() — a manifest
that exists but has no top-level version key. Add a Check
test against an edited fixture.
- copyDir's MkdirAll(dst) failure — an FS where ReadDir(src)
succeeds but the destination mkdir fails. Use the existing
failOnMkdirAllCall harness.
Coverage on internal/release: 96.9% → 98.2%.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* release: cover staging-mkdir, recursive-copyDir, and moveWheels-list errors
Three remaining unreachable lines after the FS+Runner refactor:
- buildOneWheel's outDir/.staging-<plat> mkdir failure — fixed
the existing TestBuildWheelsFailsOnStagingMkdir which counted
off by one (staging is MkdirAll call #4, not #3).
- copyDir's recursive call error — stage src with a subdir so
the inner copyDir is invoked, then fail the inner copyFile to
bubble the error back through the outer call.
- moveWheels' listWheels error — direct fault test that
asserts a ReadDir failure surfaces as a moveWheels error
rather than a silent no-op.
Coverage on internal/release: 98.2% → 99.1%. Remaining lines
are physically unreachable: main()'s 1-line os.Exit wrapper,
run()'s os.Getwd error path (cwd was deleted under us), and
copyDir's e.Info() race (entry vanished between ReadDir and
Info).
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* docs/install: point asdf+mise follow-up callouts at plan/145
The asdf-plugin repo and mise-registry submission moved out of
plan/130 into plan/145 in an earlier commit, but the install
guide's two "Pending follow-up" callouts still linked back to
plan/130. Update both references so readers land on the right
tracking plan.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* Address Copilot pass: 100% release coverage + 5 doc/code nits
Remaining reachable lines in internal/release got direct fault
tests (buildOneWheel propagates stagePythonTree failure, copyDir
propagates DirEntry.Info() error via a bespoke errInfoEntry).
internal/release coverage: 99.1% → 100.0%.
Then five Copilot review comments on top:
- internal/release/version.go: clarify the TrackedManifests
comment about npm/platforms/. BuildNpmPlatforms writes to its
outDir argument (npm/dist in CI), not to npm/platforms/; the
helper just stamps platform sub-package manifests if some
prior step happened to materialise them.
- internal/release/buildwheels_test.go: fix the assert.Failf
mis-call. failureMessage is the title; %q verbs belong in the
msg+args parameters, not the title.
- internal/release/buildwheels.go: pick python executable at
runtime via pythonExecutable() (python first, fall back to
python3) so the binary works on hosts that only ship python3.
Test gating uses the same resolver.
- docs/guides/install.md: the direct-download snippet now
curl's checksums.txt before sha256sum -c so a copy-paste
install actually works.
- PR description (via gh pr edit): drop the
scripts/{set,check}-version.sh references, mention the Go
cmd/mdsmith-release CLI, and link plan/145.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
* Fix BuildWheels source-tree path regression + plan/130 stale ref
Two Copilot findings:
- internal/release/buildwheels.go: the previous over-eager
`replace_all` of "python" → pythonExecutable() also rewrote
`filepath.Join(rootDir, "python")`, which is the source-tree
path. On hosts where `python` isn't on PATH (Debian/Ubuntu
with only python3) BuildWheels would have looked for
<rootDir>/python3 instead of <rootDir>/python and failed
every wheel build. Revert that one site to the literal
"python".
- TestBuildWheelsFailsWhenPythonSourceMissing now also asserts
the error names <root>/python so the same regression cannot
return.
- plan/130: the vscode-publish task still said run
`set-version.sh` before vsce package; flip the wording to
`mdsmith-release stamp` to match the implemented workflow.
https://claude.ai/code/session_015MPUo4nJ4iySQES6J3ByQ6
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 79b8ad8 commit 59b75a2
35 files changed
Lines changed: 3617 additions & 122 deletions
File tree
- .github
- workflows
- cmd/mdsmith-release
- docs/guides
- editors/vscode
- internal/release
- npm/mdsmith
- bin
- test
- plan
- python
- mdsmith
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| 44 | + | |
44 | 45 | | |
45 | 46 | | |
46 | 47 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
46 | 61 | | |
47 | 62 | | |
48 | 63 | | |
| |||
138 | 153 | | |
139 | 154 | | |
140 | 155 | | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
141 | 166 | | |
142 | 167 | | |
143 | 168 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
65 | 78 | | |
66 | 79 | | |
67 | 80 | | |
| |||
76 | 89 | | |
77 | 90 | | |
78 | 91 | | |
79 | | - | |
80 | 92 | | |
81 | 93 | | |
82 | 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 | + | |
83 | 152 | | |
84 | 153 | | |
85 | 154 | | |
86 | 155 | | |
87 | 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 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
88 | 247 | | |
89 | 248 | | |
90 | 249 | | |
| |||
105 | 264 | | |
106 | 265 | | |
107 | 266 | | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
72 | 72 | | |
73 | 73 | | |
74 | 74 | | |
| 75 | + | |
| 76 | + | |
75 | 77 | | |
76 | 78 | | |
77 | 79 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| 50 | + | |
50 | 51 | | |
51 | 52 | | |
52 | 53 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| 36 | + | |
36 | 37 | | |
37 | 38 | | |
38 | 39 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
| 46 | + | |
46 | 47 | | |
47 | 48 | | |
48 | 49 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
| 85 | + | |
| 86 | + | |
85 | 87 | | |
86 | 88 | | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
87 | 94 | | |
88 | 95 | | |
89 | 96 | | |
| |||
0 commit comments