GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — feat(setup): fix cargo release blocker, close all 5 contract gaps, add composer + gem publishing by mikolalysenko · Pull Request #105 · SocketDev/socket-patch

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Full remediation of the socket-patch setup feature: fixes the one confirmed production blocker, closes all five RED-pinned CLI_CONTRACT gaps, adds a composer setup backend, and scaffolds gem publishing. Distribution flows for the CLI on composer + RubyGems are being added on top (see the last commits / TODO below).

🔴 Production blocker fixed

socket-patch setup writes socket-patch-guard = "3.3" into users' Cargo.toml, but the guard crate 404'd on crates.io and release.yml only published core+cli — so every real cargo user's cargo build failed to resolve it. The release flow now publishes socket-patch-guard; a regression test pins the guard dep as a bare crates.io version (not a path/git table — the form that hid this). One manual follow-up: a one-time bootstrap cargo publish -p socket-patch-guard for the current 3.3.x (needs crates.io creds) — the workflow change only covers future releases.

Contract gaps closed (all 5 RED pins now active + green)

Property Was Now
2 — --ecosystems scoping ignored eco_in_scope gating across discovery/build/check
4 — --check patch consistency hook-presence only also runs the applied_patches afterHash check
7 — VEX respects setup state no notion of setup filters to set-up ∪ setup.manual ecosystems
8 — cargo --remove cleanup left empty .cargo/config.toml deletes emptied socket-created config + dir
9 — nested workspaces + --exclude one level; no exclude recursive npm/crates/**; --exclude persisted in setup.exclude

New

  • Composer setup backend (opt-in composer feature): wires socket-patch apply into composer.json's post-install-cmd / post-update-cmd.
  • socket-patch-bundler gem scaffold + non-blocking publish job (Phase 2 of gem support; the in-tree git: plugin stays the active mechanism).
  • Docs (CLI_CONTRACT.md, README.md) synced for golang/gem/composer.

Verification

clippy --features all-eco -D warnings clean; 104 setup/VEX tests, 0 failed, 0 ignored; core lib 933 (default) / 969 (composer).

Caveats

  • This branch also carries pre-existing uncommitted working-tree changes that were present when the work began (folded into the first commit at the author's request).
  • The gag-unresolved compile errors in a few non-setup test files (e2e_cargo_coexist, cli_global_args, in_process_variant_apply_failure, in_process_rollback_all_ecosystems) are pre-existing, not from this work.

🤖 Generated with Claude Code

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Mikola Lysenko (mikolalysenko) and others added 9 commits June 5, 2026 16:26
@mikolalysenko @claude
feat(setup): publish cargo guard, sync docs, close 3 contract gaps
3a274ce
Fix the setup feature's confirmed production blocker and close three of
the RED-pinned contract gaps. Verified: clippy -D warnings clean, all
setup test targets green.

Phase 1 (release blocker): `socket-patch setup` writes
`socket-patch-guard = "3.3"` into users' Cargo.toml, but the crate was
never published to crates.io (404) and release.yml only published
core+cli, so every real cargo user's `cargo build` failed to resolve it.
Add `cargo publish -p socket-patch-guard` (+ index wait) to the
cargo-publish job; sync the hook pyproject in version-sync.sh; add a
regression test pinning the guard dep as a bare crates.io version (never
a path/git table — the form that masked the breakage).

Phase 2 (docs): CLI_CONTRACT.md + README + setup.rs doc comments now
reflect that golang and gem setup exist (golang was still listed as
apply-only; properties 2/3 listed only npm+python+cargo).

Phase 3a (property 2): setup honors --ecosystems via eco_in_scope gating
across discover/plan_python/build_*_outcome/append_*_check_entries.

Phase 3b (property 4): setup --check verifies on-disk patch consistency
(reuses vex::applied_patches' afterHash check), not just hook presence.

Phase 3d (property 8): cargo --remove deletes an emptied socket-created
.cargo/config.toml and prunes the now-empty .cargo/ dir (never a config
that still has user content).

Contract pins for properties 2, 4, 8 un-ignored and now green.

Deferred (design-blocked / outward-facing): property 7 (VEX setup-state —
needs the manual-declaration manifest sub-property and breaks the
existing VEX suite), property 9 (--exclude + nested recursion), composer
backend, and the published socket-patch-bundler gem.

Note: this checkpoint also snapshots other pre-existing working-tree
changes (crawler / test WIP) that were already uncommitted when this
work began.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mikolalysenko @claude
feat(setup): composer backend — composer.json post-install/post-updat…
435f411
…e hook

Close the one named "core" ecosystem with no setup backend. New
`composer_setup` core module (behind the non-default `composer` feature,
consistent with composer apply being feature-gated) appends
`socket-patch apply --offline --silent --ecosystems composer` to
`composer.json`'s `post-install-cmd` and `post-update-cmd` script events,
so committed `.socket/` patches re-apply on every `composer install` /
`composer update`. Idempotent, key-order-preserving (serde preserve_order),
and byte-for-byte reversible on `--remove` (14 unit tests).

Wired into the setup dispatch (build_composer_outcome /
append_composer_check_entries) in parallel to cargo/go/gem: honors
--ecosystems scoping, feeds telemetry, emits JSON `kind: "composer"`.

The composer host-guard is now feature-aware: composer_setup_round_trips_host
(check→setup→re-setup→check→remove→check, asserting the hook lands in both
events and composer.json restores byte-for-byte) under the feature, and the
original clean-no-op guard without it — the two are mutually exclusive by cfg
so both stay green.

CLI_CONTRACT.md + README document composer as an opt-in real backend.
matrix.json is unchanged: composer's docker-matrix e2e remains a
baseline_supported:false gap, exactly like cargo/gem/golang (real setup, but
the aspirational matrix harness doesn't exercise the install-time hook
end-to-end — non-blocking in CI).

Verified: clippy --features composer -D warnings clean; default-feature
setup suite unaffected; host-guard green with and without the feature.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mikolalysenko @claude
feat(setup): nested-workspace recursion (property 9, recursion half)
357238f
Close the nested-workspace half of CLI_CONTRACT property 9 (the `--exclude`
sub-property remains a separate follow-up).

npm: `find_workspace_packages` now recurses into a discovered member that
declares its OWN `workspaces` field (bounded depth, de-duped), so a root
`workspaces:["packages/*"]` whose member `packages/inner` is itself a
workspace (`workspaces:["sub/*"]`) also configures `packages/inner/sub/leaf`.

cargo: `expand_member` now expands the recursive `members = ["crates/**"]`
glob via `glob_dir_recursive` (skips `target/` + hidden dirs, stats paths so
symlinked members are followed), so a member at `crates/group/leaf` gains the
guard dep — previously only single-level `crates/*` expanded.

Both `#[ignore]`d gap pins (`setup_recurses_into_nested_npm_workspace`,
`setup_expands_recursive_cargo_member_glob`) are un-ignored and now green;
+2 core unit tests; CLI_CONTRACT property 9 updated.

Verified: clippy -D warnings clean; core find/discover modules + the full
default-feature setup suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mikolalysenko @claude
feat(setup): --exclude flag + persisted setup.exclude (property 9, ex…
bc1a27e
…clude half)

Complete CLI_CONTRACT property 9: `setup --exclude <member>` (CSV, env
SOCKET_SETUP_EXCLUDE) skips the named workspace member(s) AND persists the
exclusion as a new `setup.exclude` array under `.socket/manifest.json`, so a
later `setup --check` — and a fresh clone — honor it without re-passing the
flag. (This is the first time `setup` writes the manifest; it does so only on
a real run, never under --dry-run, and only when the set is non-empty/changed,
keeping the file byte-stable otherwise.)

- schema: new `SetupConfig { exclude: Vec<String> }`; `PatchManifest.setup:
  Option<SetupConfig>` is serde-default + skip-when-empty so existing manifests
  round-trip byte-identically. (All `PatchManifest { patches }` literals across
  prod + tests updated for the new field.)
- setup.rs: `--exclude` flag; effective-exclude resolution (persisted ∪ flag);
  manifest persistence; an `is_member_excluded` filter threaded through npm
  discovery + the cargo branch (build_cargo_outcome / append_cargo_check_entries).
  The repo root is never excludable; excludes apply to npm + cargo members.
- The placeholder `setup_honors_exclude_for_a_workspace_member` pin (was a bare
  panic!) is now a real, passing guard; +`exclude_flag_parses_csv_on_setup`
  parser test. CLI_CONTRACT property 9 + the flag/env tables updated.

With this, only the VEX setup-state pin (property 7) remains RED.

Verified: clippy --features all-eco -D warnings clean; manifest/find/discover
core tests + the full setup integration suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mikolalysenko @claude
feat(gem): scaffold published socket-patch-bundler gem + non-blocking…
5af0ebc
… release job

Phase 2 scaffolding for the gem ecosystem (CLI_CONTRACT "gem" support matrix).
Adds the packaging for the published Bundler-plugin gem WITHOUT switching the
active mechanism: `socket-patch setup` still wires the gem ecosystem via the
in-tree `git:` plugin under `.socket/bundler-plugin/`, so gem setup is unchanged
and keeps working.

- gem/socket-patch-bundler/: gemspec + plugins.rb + README. The plugin ports the
  in-tree two-trigger applier verbatim, except it resolves the project root from
  the bundle context (Bundler.root, else walk up to .socket/manifest.json) since
  a published plugin is loaded from the gem cache, not from inside the repo.
  Verified: `ruby -c` clean, `gem build` succeeds.
- release.yml: a non-blocking `gem-publish` job (continue-on-error) that builds
  the gem and pushes it only when RUBYGEMS_API_KEY is set (skips with a notice
  otherwise). A follow-up flips gem_setup to `plugin "socket-patch-bundler"` and
  drops continue-on-error; preferred hardening is RubyGems trusted publishing
  (OIDC), mirroring the crates.io / PyPI jobs.
- version-sync.sh: keep the gemspec version in sync with the workspace.

Verified: release.yml is valid YAML; version-sync.sh is valid bash and its
gemspec bump works.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mikolalysenko @claude
feat(vex): respect setup state + manual declaration (property 7)
01bee76
Close the last RED contract pin: VEX now attests a patch only for an ecosystem
that is actually set up — or explicitly declared `manual` — instead of trusting
the whole manifest.

- schema: `SetupConfig` gains a `manual: Vec<String>` array (ecosystem cli_names
  the user applies by hand), serde-default + skip-empty alongside `exclude`.
- setup.rs: new `configured_ecosystems(common)` runs the same on-disk hook-
  presence probes as `setup --check` and returns the set of set-up ecosystems
  (feature-gated per ecosystem). `persist_setup_excludes` now preserves any
  existing `manual` when rewriting.
- vex.rs: `generate_vex` filters `outcome.applied` to
  `configured_ecosystems ∪ setup.manual` (mapping manual names via
  `ecosystem_from_manual_name`), in BOTH verify and `--no-verify` modes, on top
  of the existing --ecosystems + on-disk-verification filters.
- The `vex_omits_patches_for_unconfigured_ecosystem` pin is un-ignored and green
  (an un-set-up pypi patch, not manual, yields no statements / exit 1).
- VEX-suite migration (single point each): `e2e_vex` / `e2e_embedded_vex`
  `write_manifest` helpers now stamp a blanket `setup.manual` so those fixtures
  (which test document GENERATION, not setup state) still attest — all 18 of
  their tests stay green, including verify-mode omission. CLI_CONTRACT property 7
  updated to implemented.

All 5 setup contract-gap pins are now active (0 ignored). Verified: clippy
--features all-eco -D warnings clean; e2e_vex (13) + e2e_embedded_vex (5) +
core lib (933 / 969 with composer) all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mikolalysenko @claude
feat(dist): distribute the CLI via RubyGems + Composer (separate rele…
5c47e4d
…ase)

Add CLI distribution for the two ecosystems we just gained setup support for,
so `socket-patch` can be installed with their native package managers (handy
where the gem/composer setup hooks need the CLI on PATH).

Both are thin launcher packages, version-locked to a GitHub release: on first
run they detect the host platform (mirroring scripts/install.sh's target map),
download `socket-patch-<target>.{tar.gz,zip}` from `releases/download/v<version>`,
verify it against the release SHA256SUMS, cache it (~/.cache/socket-patch/bin or
%LOCALAPPDATA%), and exec it. `SOCKET_PATCH_BIN` bypasses the download (airgap).

- gem/socket-patch/ — `gem install socket-patch`. gemspec + exe/socket-patch
  shim + lib/socket_patch/launcher.rb (Net::HTTP w/ redirect follow, sha256
  verify, tar/zip extract). `ruby -c` + `gem build` verified.
- composer/socket-patch/ — `composer require socketsecurity/socket-patch`.
  composer.json (bin) + bin/socket-patch PHP launcher (curl/stream download,
  sha256 verify, tar/Phar/Zip extract, pcntl_exec/passthru). `php -l` runs in CI.
- .github/workflows/release-ecosystems.yml — a SEPARATE release workflow (runs
  after the main release publishes, or manually for a version). rubygems-cli
  job lints + builds + `gem push` (guarded by RUBYGEMS_API_KEY, skips if the
  version is already live); packagist-cli job lints + `composer validate` +
  nudges the Packagist update API (guarded by PACKAGIST_USERNAME/TOKEN — and
  Packagist is git-tag-driven anyway). Both publish steps skip gracefully when
  their secret is absent, so the workflow is safe to land before creds are wired.
- version-sync.sh syncs all three new version sites (gemspec, launcher VERSION,
  composer SP_VERSION); README install section + CLI_CONTRACT semver list updated.

Note: these launchers DOWNLOAD on first run (npm/PyPI bundle instead); a future
hardening could ship platform-bundled gems. Trusted publishing (OIDC) is the
preferred eventual replacement for the API-key secrets.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mikolalysenko @claude
feat(dist): download the binary matching the installed package versio…
1068be3
…n + lint jobs

Two follow-ups to the RubyGems/Composer CLI launchers.

1. Version match. The launchers no longer trust a baked-in version constant for
   the download URL — they derive it from the package the user actually
   installed, so the downloaded binary always matches the installed package:
   - Ruby: `Gem.loaded_specs["socket-patch"].version` (then
     `Gem::Specification.find_by_name`), so `gem install socket-patch -v X`
     fetches the vX binary.
   - Composer: loads Composer's autoloader via `$_composer_autoload_path` and
     reads `Composer\InstalledVersions::getPrettyVersion('socketsecurity/socket-patch')`
     (only when it's a concrete X.Y.Z release).
   The `VERSION` / `SP_VERSION` constants remain solely as a fallback for
   not-installed contexts (raw checkout); version-sync keeps them current.

2. Lint jobs. New `lint-ecosystems` job in ci.yml covering the out-of-workspace
   packaging for the ecosystems we added:
   - Ruby: `ruby -c` the CLI launcher gem + Bundler plugin + the generated-plugin
     templates, and `gem build` both gemspecs.
   - PHP: `php -l` the Composer launcher + `composer validate`.
   - Go: gofmt-clean + `go vet` the setup-guard templates (rendered to a temp
     package).

Verified: ci.yml valid YAML; both gems build; `ruby -c`/`gofmt`/`go vet` clean
on the templates locally (php/composer lint runs in CI).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mikolalysenko @claude
ci(release-ecosystems): fix zizmor template-injection findings
1fcac7c
The "Audit GitHub Actions" check (zizmor) flagged two HIGH template-injection
findings in the new workflow: `github.event.release.tag_name` and
`inputs.version` interpolated directly into the resolve-version `run` block.
Pass event/input data through `env:` and reference `$RELEASE_TAG`/
`$INPUT_VERSION`/`$EXPECTED_VERSION` instead (also covers the `needs.*.outputs`
informational findings). The remaining `use-trusted-publishing` info on
`gem push` is suppressed with a justified `# zizmor: ignore` (OIDC trusted
publishing is the documented future hardening). `zizmor` now reports no findings.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mikolalysenko
Mikola Lysenko (mikolalysenko) force-pushed the setup-feature-remediation branch from 7863c26 to 1fcac7c Compare June 5, 2026 22:34
Wenxin-Jiang
Wenxin Jiang (Wenxin-Jiang) approved these changes Jun 5, 2026
View reviewed changes
Mikola Lysenko (mikolalysenko) and others added 5 commits June 5, 2026 19:16
@mikolalysenko @claude
fix: address code-review findings + bring in the variant-apply-failur…
2af4f2c
…e test

Adversarial review (PR #105) surfaced real bugs in the new code; fix them and
make the swept-in WIP test pass reliably so it can land.

VEX / setup-state (property 7):
- configured_ecosystems detected Python via plan_python, which applies the
  --ecosystems filter — so `vex --ecosystems cargo` in a python-set-up repo
  reported python as NOT set up and dropped its patches. Detect python on-disk
  state directly (is_python_project + choose_python_manifests + deps_contain_hook),
  bypassing the filter like every other ecosystem in that probe.
- ecosystem_from_manual_name was missing maven/nuget/deno — the apply-only
  ecosystems that are the *primary* use of `setup.manual` — so declaring them
  manual silently dropped their patches from VEX. Add them (feature-gated) +
  a unit test covering every compiled-in ecosystem.

Launchers (supply-chain hardening):
- The RubyGems + Composer launchers followed redirects without enforcing HTTPS;
  a MitM could redirect github.com -> http:// and serve a malicious binary AND
  a matching SHA256SUMS (both attacker-controlled), defeating the checksum.
  Enforce HTTPS on every hop: Ruby refuses a non-HTTPS (initial/redirect) URL
  and resolves relative redirects with URI.join; PHP sets
  CURLOPT_PROTOCOLS/REDIR_PROTOCOLS=HTTPS and the no-curl fallback follows
  redirects manually, vetting each hop's scheme. Documented the (accepted,
  user-owned) cache-trust model at the cache-hit path.

Cargo recursive glob:
- collect_manifests_recursive (crates/**) followed symlinked dirs via metadata,
  so a loop symlink could re-add the workspace root as a duplicate member and an
  escaping symlink could make setup EDIT an out-of-tree Cargo.toml (breaking the
  in-repo-only contract). Skip symlinked dirs in the recursive walk (matches the
  `glob` crate); single-level crates/* still follows a symlinked member. +unix test.

variant-apply-failure test (was unrelated broken WIP, now fixed + included):
- Fixed the `purl` borrow-after-move, then rewrote it to invoke the binary as a
  subprocess and capture the child's stdout instead of an in-process
  `gag::BufferRedirect` (which races libtest's stdout capture and failed
  deterministically under default `cargo test`). No `gag` dep; passes reliably.

Verified: clippy --workspace --all-features -D warnings exits 0; the full
setup/vex/cargo suites + the variant test pass; ruby `gem build` + `ruby -c`
clean; PHP `php -l` clean (docker php:8.2).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mikolalysenko @claude
ci(release): suppress use-trusted-publishing zizmor finding on the ge…
365a841
…m push

The Audit (diff-scoped zizmor) flagged the new gem-publish job's API-key
`gem push` (release.yml). Suppress it with a justified `# zizmor: ignore`,
matching the equivalent suppression already on release-ecosystems.yml — OIDC
trusted publishing remains the documented future hardening. This was the only
zizmor finding on a line this PR changed; the pre-existing findings elsewhere in
release.yml are untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mikolalysenko @claude
ci: scope publish secrets behind a deployment environment (zizmor sec…
a618ab1
…rets-outside-env)

The Audit runs `zizmor .github --min-severity medium`, which failed on four
`secrets-outside-env` MEDIUM findings — the new RubyGems/Composer publish jobs
referenced `secrets.*` without a dedicated GitHub environment (release.yml
gem-publish; release-ecosystems.yml rubygems-cli + packagist-cli). Add a job
`environment:` (`rubygems` / `packagist`) to each, which scopes the secret (and
lets a maintainer later gate publishing with required reviewers; the env is
auto-created with no protection until configured). Verified with the org's exact
invocation (zizmor 1.23.1, `.github`, --min-severity medium): the four findings
are gone; the only remaining medium is the pre-existing artipacked on
release.yml:182 (not mine, suppressed in the org's --gh-token run).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mikolalysenko @claude
test(repair): fix stale cleanup_sweeps assertion + drop debug prints
d2894a3
The lib unit test cleanup_sweeps_diff_and_package_archives (pre-existing WIP,
left with `eprintln!("DBG …")` traces) asserted `env.summary.removed == 2`, but
repair records a SINGLE batched `Removed` artifact event whose `details.count`
carries the tally — and `Summary::bump` increments once per event, so
`summary.removed` is 1, not 2. Assert the batched reality: `summary.removed == 1`
plus the event's `details.count == 2` (the 2-artifact tally is also covered by
`counts.cleaned == 2`). Removed the DBG prints. Code behavior unchanged; this was
the sole failure in the `test`/`coverage` jobs.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mikolalysenko @claude
test(crawlers): align 3 stale e2e tests with deliberate crawler contr…
bfdf9f9
…acts

These three tests pinned behavior that subsequent crawler work intentionally
reversed; each new contract already has fresh unit-test coverage in the crawler
source, so update the e2e tests to match (rather than revert the code):

- crawler_go_e2e: a lone trailing `!` in decode_module_path is now PRESERVED,
  not dropped — Go's encoder never emits one, so decoding a corrupt/unexpected
  directory name must not silently lose path bytes. Renamed
  `decode_module_path_trailing_bang_is_dropped` ->
  `decode_module_path_trailing_bang_is_preserved`.

- crawler_npm_e2e: a qualified PURL (`?extension=tgz`) must now RESOLVE and be
  keyed by the verbatim input PURL. The old `purl_set.contains(synth_purl)`
  check silently dropped every qualified PURL (the stripped synth form never
  matched the qualified input) — an actual bug. Renamed
  `find_by_purls_strips_qualifiers` ->
  `find_by_purls_resolves_qualified_purl_keyed_by_input`.

- e2e_cargo::scan_discovers_vendor_crates: the cargo crawler now requires a root
  `Cargo.toml`/`Cargo.lock` before treating `vendor/` as crate sources (so a
  non-Rust project's `vendor/` is no longer misclassified). Stage a root
  `Cargo.lock` in the fixture as the project marker.

Full non-docker workspace suite (cargo,golang,maven,composer,nuget,deno) green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mikolalysenko
Mikola Lysenko (mikolalysenko) merged commit b004f6a into main Jun 6, 2026
40 of 41 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the setup-feature-remediation branch June 6, 2026 00:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@Wenxin-Jiang Wenxin Jiang (Wenxin-Jiang) Wenxin-Jiang approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@mikolalysenko @Wenxin-Jiang
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.