Skip to content

feat: add -sw (strict-wildcard) flag for automatic wildcard detection and filtering#945

Open
assakafpix wants to merge 2 commits intoprojectdiscovery:devfrom
assakafpix:dev
Open

feat: add -sw (strict-wildcard) flag for automatic wildcard detection and filtering#945
assakafpix wants to merge 2 commits intoprojectdiscovery:devfrom
assakafpix:dev

Conversation

@assakafpix
Copy link

@assakafpix assakafpix commented Feb 16, 2026

/claim #924

Proposed Changes

The current -wd flag requires manually specifying a single domain and uses IP-threshold grouping to detect wildcards. This fails for load-balanced wildcards like *.herokuapp.com (8 disjoint IP pools, 31 unique IPs — no single IP reaches the threshold).

This PR adds a new -sw (strict-wildcard) flag that automatically detects and filters wildcard subdomains from any input, without requiring the user to know which domains are wildcards.

How it works

Phase 1 — Normal resolution (main DNS client, -retry 2 default)

  1. Resolve all input domains through the existing pipeline (unchanged)
  2. Store results in HybridMap (hostname -> DNS data)

Phase 2 — Wildcard detection (separate DNS client, -wildcard-retry 5 default)

  1. Collect all hosts that resolved with A records from HybridMap
  2. Extract candidate parent domains at every hierarchy level
  3. Test candidates depth by depth (shallowest first, all depth N complete before depth N+1 starts):
    • For each candidate, query one random subdomain (<xid>.<parent>)
    • If it resolves -> wildcard root. If NXDOMAIN -> not wildcard. DNS errors are retried up to --wildcard-retry times.
    • Candidates within a depth level are tested concurrently (limited by -t threads)
  4. Filter output: remove subdomains of wildcard roots

Key design decisions

  • Non-breaking: -wd is unchanged, -sw is a new additive flag. They are mutually exclusive.
  • Top-down detection: tests example.com before sub.example.com. If the parent is wildcard, all children are skipped.
  • NXDOMAIN-only negative: REFUSED (rate limiting) and timeouts are transient — only NXDOMAIN definitively rules out a wildcard. This matches how puredns and shuffledns handle DNS errors.
  • Flags: concurrency via -t (threads). New flag: --wildcard-retry (default 5, matching shuffledns) for wildcard DNS retries, independent from -retry (default 2) used for normal resolution.
  • Same random ID library: uses xid for random subdomain generation, consistent with both the existing IsWildcard() in dnsx and shuffledns.

Files modified

File Changes
internal/runner/options.go Added StrictWildcard, WildcardRetry fields and -sw, --wildcard-retry flags
internal/runner/wildcard.go Added isStrictWildcard(), detectWildcardRoots(), isSubdomainOfWildcard(). Existing IsWildcard() untouched.
internal/runner/runner.go Added wildcardDnsx client (retries default 5), strict wildcard filtering block, lookupAndOutput() with -resp support.
internal/runner/wildcard_test.go New file, 3 tests using projectdiscovery.io domains (pure logic + live DNS)

Proof

Test domain list (domains.txt - 18 domains)

herokuapp.com
test.herokuapp.com
ok.example.com
test.example.com
test.vercel.app
ok.vercel.app
vercel.app
example.com
netlify.app
test.netlify.app
test.test.netlify.app
test.vercel.netlify.com
vercel.app.github.io
test.ngrok.io
test.wordpress.com
projectdiscovery.io
bob.dev.projectdiscovery.io
hello.dev.projectdiscovery.io

This list contains 18 domains across 8 root domains, many of which are known wildcard providers (herokuapp.com, vercel.app, netlify.app, ngrok.io, wordpress.com, github.io) plus *.dev.projectdiscovery.io.

puredns (baseline)

puredns resolve domains.txt -w puredns_out.txt --write-wildcards puredns_wc.txt

                          _
                         | |
 _ __  _   _ _ __ ___  __| |_ __  ___
| '_ \| | | | '__/ _ \/ _` | '_ \/ __|
| |_) | |_| | | |  __/ (_| | | | \__ \
| .__/ \__,_|_|  \___|\__,_|_| |_|___/
| |
|_|                     puredns v2.1.1

Fast and accurate DNS resolving and bruteforcing

Crafted with <3 by @d3mondev
https://github.com/sponsors/d3mondev

------------------------------------------------------------
[+] Mode                 : resolve
[+] File                 : domains.txt
[+] Resolvers            : /Users/adel/.config/puredns/resolvers.txt
[+] Rate Limit           : unlimited
[+] Rate Limit (Trusted) : 500 qps
[+] Wildcard Threads     : 100
[+] Wildcard Tests       : 3
------------------------------------------------------------

Resolving domains with public resolvers
[ETA 00:00:00] |██████████████████████████████████████| 18/18 rate: 18 qps (time: 00:00:00)

Detecting wildcard root subdomains
[ETA 00:00:00] |██████████████████████████████████████| 16/16 queries: 79 (time: 00:00:00)

Found 8 wildcard roots:
*.netlify.com
*.github.io
*.herokuapp.com
*.vercel.app
*.dev.projectdiscovery.io
*.ngrok.io
*.wordpress.com
*.netlify.app

Validating domains against trusted resolvers

Found 5 valid domains:
vercel.app
netlify.app
example.com
projectdiscovery.io
herokuapp.com

2.65s total

puredns detects 8 wildcard roots and outputs 5 valid domains.

Before (original dnsx, no wildcard filtering)

dnsx -l domains.txt

      _             __  __
   __| | _ __   ___ \ \/ /
  / _' || '_ \ / __| \  /
 | (_| || | | |\__ \ /  \
  \__,_||_| |_||___//_/\_\

		projectdiscovery.io

[INF] Current dnsx version 1.2.3 (latest)
ok.vercel.app
test.wordpress.com
example.com
test.test.netlify.app
vercel.app.github.io
netlify.app
test.netlify.app
test.ngrok.io
test.herokuapp.com
herokuapp.com
projectdiscovery.io
test.vercel.app
bob.dev.projectdiscovery.io
hello.dev.projectdiscovery.io
test.vercel.netlify.com

0.67s total — 15 unique hosts (10 are wildcard subdomains)

Original dnsx outputs 15 unique hosts with no wildcard filtering. 10 of these are wildcard subdomains that resolve only because the wildcard catches them.

After (dnsx with -sw flag)

./dnsx -l domains.txt -sw

      _             __  __
   __| | _ __   ___ \ \/ /
  / _' || '_ \ / __| \  /
 | (_| || | | |\__ \ /  \
  \__,_||_| |_||___//_/\_\

		projectdiscovery.io

[INF] Current dnsx version 1.2.3 (latest)
[INF] Detecting wildcard root subdomains
[INF] Found 7 wildcard roots:
[INF]   *.netlify.com
[INF]   *.herokuapp.com
[INF]   *.github.io
[INF]   *.netlify.app
[INF]   *.wordpress.com
[INF]   *.vercel.app
[INF]   *.dev.projectdiscovery.io
example.com
herokuapp.com
netlify.app
projectdiscovery.io
vercel.app
[INF] Found 5 non-wildcard domains (10 wildcard subdomains filtered)

0.77s total — 5 non-wildcard domains, 7 wildcard roots detected

dnsx -sw detects 7 wildcard roots (same as puredns minus *.netlify.com which had no subdomains in the input) and outputs 5 non-wildcard domains — matching puredns exactly.

New flags

   -sw, -strict-wildcard         perform strict wildcard check on all found subdomains
       -wildcard-retry int       number of dns retries for wildcard detection (used with -sw) (default 5)

Performance

Benchmark on subdomains from 8 different root domains (projectdiscovery.io, hackerone.com, bugcrowd.com, github.com, shopify.com, cloudflare.com, uber.com, tesla.com):

# Generate the benchmark list (500 subdomains from 8 root domains)
for d in projectdiscovery.io hackerone.com bugcrowd.com github.com shopify.com cloudflare.com uber.com tesla.com; do
  subfinder -d $d 2>/dev/null | head -100
done | sort -u | shuf | head -500 > bench_500.txt
head -100 bench_500.txt > bench_100.txt
Tool 100 domains 500 domains
puredns v2.1.1 26.0s 1m 11s
dnsx (original) 7s 7s
dnsx -sw (this PR) 7s 25s

For both puredns and dnsx with -sw we found 1 wildcard root for the bench_100.txt file and 2 wildcard roots and for the bench_500.txt file.


Checklist

  • PR created against the correct branch (usually dev)
  • All checks passed (lint, unit/integration/regression tests)
  • Tests added that prove the fix is effective or feature works
  • Documentation added (if appropriate)

Summary by CodeRabbit

  • New Features

    • Added strict wildcard checking with configurable retry count, concurrent wildcard-root discovery, and filtering to skip wildcard-derived subdomains for cleaner results.
  • Bug Fixes

    • Validation now blocks incompatible options (strict-wildcard cannot be used with stream mode or with wildcard-domain).
  • Documentation

    • CLI docs updated with new flags, examples, and notes about strict wildcard filtering and retry configuration.
  • Tests

    • Added tests for wildcard detection and subdomain filtering.

@coderabbitai
Copy link

coderabbitai bot commented Feb 16, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds strict wildcard detection and filtering: new Options fields StrictWildcard and WildcardRetry, CLI flags, a dedicated wildcard DNSX client, concurrent wildcard-root detection/filtering in Runner, unit tests for detection helpers, and README updates.

Changes

Cohort / File(s) Summary
Options & Configuration
internal/runner/options.go
Added StrictWildcard (bool) and WildcardRetry (int) to Options; added --strict-wildcard / -sw and --wildcard-retry flags; validation updated to forbid incompatible combinations (stream mode, WildcardDomain).
Core Runner Logic
internal/runner/runner.go
Added wildcardDnsx *dnsx.DNSX to Runner; new StrictWildcard branch that collects hosts with A records, detects wildcard roots, restarts output worker, filters hosts via isSubdomainOfWildcard, and performs lookups only for non-wildcard hosts; adjusted DNS storage condition and added plural() helper.
Wildcard Detection
internal/runner/wildcard.go
Introduced concurrent detection helpers: isStrictWildcard(), detectWildcardRoots(), isSubdomainOfWildcard(); depth-prioritized probing with semaphore-bounded concurrency and sync primitives to record wildcard roots.
Tests
internal/runner/wildcard_test.go
New tests covering wildcard detection and filtering: newTestRunner() helper, TestIsSubdomainOfWildcard(), TestIsStrictWildcard(), TestDetectWildcardRoots().
Docs
README.md
Documented -sw/--strict-wildcard and --wildcard-retry flags, added a “Strict wildcard filtering” section and example output; clarified wildcard-related notes.

Sequence Diagram

sequenceDiagram
    actor User
    participant Runner
    participant HybridMap
    participant DNSX as "wildcardDnsx (DNSX)"
    participant Output

    User->>Runner: Start run with StrictWildcard
    Runner->>HybridMap: Collect hosts with A records
    HybridMap-->>Runner: Return host list
    Runner->>DNSX: detectWildcardRoots(hosts)
    loop Parallel tests (bounded by Threads)
        DNSX->>DNSX: isStrictWildcard(random-subdomain)
    end
    DNSX-->>Runner: Detected wildcard roots
    Runner->>Output: Restart output worker
    Runner->>Runner: Filter hosts using isSubdomainOfWildcard()
    loop Lookup non-wildcard hosts
        Runner->>DNSX: Perform DNS lookups
        DNSX-->>Runner: Lookup results
    end
    Runner->>Output: Emit filtered results
    Runner->>User: Log summary (wildcard vs non-wildcard)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I sniffed the roots where wildcards creep,

chased random names while others sleep,
pruned the faux and kept the true,
hopped through hosts to find the few,
then thumped my joy — the results are neat.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately and concisely summarizes the main change: introduction of a new -sw (strict-wildcard) flag for automatic wildcard detection and filtering.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
internal/runner/runner.go (1)

566-611: -sw with -re/-ro or other record types only outputs A records.

When StrictWildcard is active, hosts are collected only if they have A records (line 579), and lookupAndOutput in Response mode (lines 640–655) only emits A records. If a user combines -sw with -aaaa -re, the AAAA data stored in the HybridMap is silently dropped in the output phase.

This matches the existing -wd behavior, but consider either:

  1. Documenting this limitation (e.g., in the flag help text), or
  2. Extending lookupAndOutput to emit all requested record types.
internal/runner/wildcard.go (1)

77-84: Single random-subdomain probe may produce false positives.

isStrictWildcard issues a single random query. Some DNS setups (e.g., certain CDN catch-all configurations or resolver-level rewriting) could cause a one-off false positive, filtering out legitimate subdomains of that parent. A second probe with a different random label would greatly reduce the false-positive rate at minimal cost.

💡 Suggested hardening
 func (r *Runner) isStrictWildcard(domain string) bool {
-	randomHost := xid.New().String() + "." + domain
-	resp, err := r.wildcardDnsx.QueryOne(randomHost)
-	if err != nil || resp == nil {
-		return false
-	}
-	return len(resp.A) > 0
+	// Two independent random probes to reduce false positives
+	for i := 0; i < 2; i++ {
+		randomHost := xid.New().String() + "." + domain
+		resp, err := r.wildcardDnsx.QueryOne(randomHost)
+		if err != nil || resp == nil || len(resp.A) == 0 {
+			return false
+		}
+	}
+	return true
 }
internal/runner/wildcard_test.go (2)

52-69: Live DNS tests will be flaky in CI.

TestIsStrictWildcard and TestDetectWildcardRoots depend on dev.projectdiscovery.io being a wildcard and on network availability. DNS behavior can change, and CI environments may have restricted network access or flaky resolvers. These tests will intermittently fail.

Consider gating them behind a build tag or environment variable (e.g., //go:build integration or checking os.Getenv("DNSX_INTEGRATION_TEST")), and keeping TestIsSubdomainOfWildcard as the always-run unit test.

Also applies to: 71-91


10-25: newTestRunner uses hardcoded dns.TypeA magic number.

Line 14 uses the raw value 1 instead of dns.TypeA. Since the dns package isn't imported, consider importing it for clarity, or add a comment.

♻️ Suggested fix
 import (
 	"testing"
 
+	"github.com/miekg/dns"
 	"github.com/projectdiscovery/dnsx/libs/dnsx"
 	"github.com/stretchr/testify/require"
 )
 
 func newTestRunner(t *testing.T) *Runner {
 	t.Helper()
 	options := dnsx.DefaultOptions
-	options.QuestionTypes = []uint16{1} // TypeA
+	options.QuestionTypes = []uint16{dns.TypeA}
 	options.MaxRetries = 3

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
README.md (1)

497-497: ⚠️ Potential issue | 🟡 Minor

Stale note: -wd is no longer the only path to wildcard elimination.

Line 497 reads: "Domain name (wd) input is mandatory for wildcard elimination." This is now incorrect; -sw performs wildcard filtering without any domain argument. The note should be updated to reflect both modes.

✏️ Suggested fix
-  - Domain name (`wd`) input is mandatory for wildcard elimination.
+  - Domain name (`wd`) or the `-sw` flag is required for wildcard elimination (`-sw` and `-wd` are mutually exclusive).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` at line 497, Update the stale README sentence "Domain name (`wd`)
input is mandatory for wildcard elimination." to mention both modes: clarify
that the `-wd`/`wd` domain argument is required for wildcard elimination when
using the domain-based mode, and that the `-sw` flag performs wildcard filtering
without any domain argument; replace the single sentence with a concise
description that references both `-wd` and `-sw` and explains which mode
requires a domain and which does not.
🧹 Nitpick comments (1)
README.md (1)

410-438: Add a ToC entry and document the -sw/-wd mutual exclusivity.

Two minor gaps in this new section:

  1. The top-of-file navigation (line 21) has no anchor link for "Strict wildcard filtering". Consider adding one alongside the existing #wildcard-filtering entry.
  2. The PR description states -sw and -wd are mutually exclusive, but neither the new section nor the CONFIGURATIONS block mentions this. A brief note (e.g., "Cannot be used with -wd" in the flag description or in the section prose) would prevent user confusion.
✏️ Suggested additions

Add a ToC entry (line 21 area):

   <a href="#wildcard-filtering">Wildcard</a> •
+  <a href="#strict-wildcard-filtering">Strict Wildcard</a> •

Note mutual exclusivity in the CONFIGURATIONS block (line 132):

-  -sw, -strict-wildcard         perform strict wildcard check on all found subdomains
+  -sw, -strict-wildcard         perform strict wildcard check on all found subdomains (mutually exclusive with -wd)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` around lines 410 - 438, Add a top-of-file Table-of-Contents anchor
entry for the "Strict wildcard filtering" section (the "Strict wildcard
filtering" header) alongside the existing `#wildcard-filtering` entry so the
section appears in the navigation, and update the CONFIGURATIONS block entry for
the -sw flag to explicitly state it cannot be used with -wd (or add a short
sentence in the new section noting that -sw and -wd are mutually exclusive);
reference the flags by name (-sw and -wd) and the section header "Strict
wildcard filtering" when making the edits.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@README.md`:
- Line 497: Update the stale README sentence "Domain name (`wd`) input is
mandatory for wildcard elimination." to mention both modes: clarify that the
`-wd`/`wd` domain argument is required for wildcard elimination when using the
domain-based mode, and that the `-sw` flag performs wildcard filtering without
any domain argument; replace the single sentence with a concise description that
references both `-wd` and `-sw` and explains which mode requires a domain and
which does not.

---

Nitpick comments:
In `@README.md`:
- Around line 410-438: Add a top-of-file Table-of-Contents anchor entry for the
"Strict wildcard filtering" section (the "Strict wildcard filtering" header)
alongside the existing `#wildcard-filtering` entry so the section appears in the
navigation, and update the CONFIGURATIONS block entry for the -sw flag to
explicitly state it cannot be used with -wd (or add a short sentence in the new
section noting that -sw and -wd are mutually exclusive); reference the flags by
name (-sw and -wd) and the section header "Strict wildcard filtering" when
making the edits.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@README.md`:
- Around line 426-431: Add a short clarifying sentence after the sample output
that explains the filter only removes wildcard subdomains, not the parent/root
domain itself (so entries like herokuapp.com, netlify.app, vercel.app can still
appear even when *.herokuapp.com, *.netlify.app, *.vercel.app were detected);
reference the example output lines (e.g., the shown wildcard roots like
*.herokuapp.com and the non-wildcard results such as herokuapp.com) and state
that this behavior is intentional to avoid confusion.
- Around line 410-438: Add documentation noting that the strict wildcard
detection flag `-sw` and the wildcard-disable flag `-wd` cannot be used
together: update the README section that shows `-sw` and the `-wildcard-retry`
example (or the Notes section) to include a single sentence like "Note: `-sw`
and `-wd` are mutually exclusive; use one or the other." Mention both flags
(`-sw`, `-wd`) explicitly so users see the constraint when reading the wildcard
examples.
- Around line 497-498: Update README.md: change "can not" to "cannot" and revise
the sentence about DNS record flags to state that the restriction applies to
both -wd and -sw flags (wildcard filtering) because the code in runner.go treats
them the same and defaults to A records only; reference the -wd and -sw flags
and the runner.go behavior (defaulting to type A) when rewording to make the
limitation explicit for both flags.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@README.md`:
- Around line 410-438: The README's "Strict wildcard filtering" section omits
that the CLI flags -sw and -wd are mutually exclusive; update the README.md by
adding a short note under that section (near the -sw description) explicitly
stating that -sw and -wd cannot be used together (e.g., "Note: -sw and -wd are
mutually exclusive; use one or the other."), so users combining both flags see
the constraint in the documentation.
- Around line 497-498: Update the README text to correct "can not" to "cannot"
and broaden the DNS record flag restriction so it applies when using wildcard
filtering with either -wd or -sw; specifically, edit the sentence that currently
reads "DNS record flag can not be used when using wildcard filtering with `-wd`"
to something like "The DNS record flag cannot be used when using wildcard
filtering with `-wd` or with automatic wildcard detection `-sw`" so both flags
(`-wd`, `-sw`) are referenced and the wording uses "cannot".

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
README.md (1)

132-132: Nit: "all found subdomains" may mislead — consider "all input hosts".

"Found subdomains" implies subdomains discovered at runtime, whereas -sw processes whatever is in the input list (domains, subdomains, hosts). A clearer phrase:

📝 Suggested wording
-   -sw, -strict-wildcard         perform strict wildcard check on all found subdomains
+   -sw, -strict-wildcard         perform strict wildcard detection and filtering on all input hosts
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` at line 132, The README line describing the -sw / -strict-wildcard
flag is misleading; change the phrase "all found subdomains" to reflect that the
flag operates on the input hosts rather than discovered subdomains — e.g.,
replace with "perform strict wildcard check on all input hosts" and update any
mention of -sw or -strict-wildcard to use this clearer wording.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@README.md`:
- Line 496: Update the README note to explicitly state that the flags -sw
(StrictWildcard) and -wd (WildcardDomain / domain name input) are mutually
exclusive and cannot be used together; replace the current "without needing
`-wd`" language with a clear sentence such as "These flags are mutually
exclusive — use either -sw or -wd, but not both; using both will result in an
error." Reference the exact flag names (-sw and -wd) and the Domain name (`wd`)
wording already in the doc so readers can locate the statement.

---

Nitpick comments:
In `@README.md`:
- Line 132: The README line describing the -sw / -strict-wildcard flag is
misleading; change the phrase "all found subdomains" to reflect that the flag
operates on the input hosts rather than discovered subdomains — e.g., replace
with "perform strict wildcard check on all input hosts" and update any mention
of -sw or -strict-wildcard to use this clearer wording.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments