Skip to content

Conversation

@TheApeMachine
Copy link
Owner

@TheApeMachine TheApeMachine commented May 18, 2025

Summary

  • allow main.go to read config from environment variables
  • enrich the graphlang parser with project info and URL generation
  • create root node for each project and link parsed objects to it
  • remove global DB wipe and only delete nodes for the current project

Testing

  • go vet ./... (fails: proxyconnect tcp dial tcp 172.25.0.3:8080: connect: no route to host)

Summary by CodeRabbit

  • New Features
    • Added color coding for different node types in the graph.
    • Nodes now include direct links to their source code locations.
    • Improved graph organization with a root node containing all other nodes.
  • Chores
    • Configuration is now managed through environment variables for easier setup and customization.

@coderabbitai
Copy link

coderabbitai bot commented May 18, 2025

Walkthrough

The changes introduce project scoping, color coding, and source URL generation for graph nodes in the parsing and graph creation process. Configuration values, including Neo4j credentials and project metadata, are now sourced from environment variables. The parser and node handlers are updated to include project, color, and URL properties, with a root node established as the container for all nodes.

Changes

File(s) Change Summary
graphlang/graphlang.go Added NodeColors map for node type colors. Extended TreeSitterParser struct with fields for project scoping and URL generation. Updated constructor to accept new parameters. Added createURL method. Modified cleanup for env-based config. Updated node handlers to set project, color, and URL properties, and link nodes to a root node.
main.go Sourced Neo4j credentials and project metadata from environment variables. Added validation for required variables. Updated parser creation to include new parameters. Removed session management code. Simplified directory path assignment.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Main
    participant Parser
    participant Neo4j

    User->>Main: Set environment variables (NEO4J_URI, NEO4J_USER, etc.)
    Main->>Main: Validate env variables
    Main->>Neo4j: Initialize driver with credentials
    Main->>Parser: Create TreeSitterParser(driver, rootName, baseURL, projectRoot)
    Main->>Parser: AnalyzeDirectory(dirPath)
    Parser->>Neo4j: Cleanup project nodes (scoped)
    Parser->>Neo4j: Create/Merge Root node (with project, color)
    loop For each file
        Parser->>Parser: New parser instance (with filePath)
        Parser->>Neo4j: Create nodes (Function, Namespace, Type) with project, color, url
        Parser->>Neo4j: Link nodes to Root with CONTAINS
    end
Loading

Poem

In burrows deep, the graph now glows,
With colors bright for every node that grows.
URLs hop from code to view,
While roots contain the project crew.
With env-set keys and tidy scope,
This bunny’s graph now leaps with hope!
🥕🌈


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between b5d94ed and d1c6bb0.

📒 Files selected for processing (1)
  • graphlang/graphlang.go (10 hunks)
🔇 Additional comments (10)
graphlang/graphlang.go (10)

53-59: Good addition of node coloring for better visualization.

The NodeColors map provides a consistent color scheme for different node types, which will improve the visual distinction between different entities in the graph visualization.


74-75: LGTM: Well-structured parser extension for project context.

The additional fields added to the TreeSitterParser struct provide the necessary context for project-scoped parsing and URL generation, which aligns with the PR objectives.

Also applies to: 81-85


92-102: LGTM: Constructor properly initialized with project context.

The updated constructor correctly initializes the new fields and generates the rootID consistently using the project name.


289-296: Good practice using environment variables for configuration.

The code properly reads Neo4j connection parameters from environment variables and includes appropriate validation when they're missing.


317-319: Improved safety by scoping database cleanup to current project.

This change reduces the risk of unintended data loss by only deleting nodes related to the current project instead of wiping the entire database. Well done.


373-383: Fix potential resource leak in root node creation.

The Neo4j session is properly closed with defer session.Close(context.Background()), which resolves the issue mentioned in the previous review comment.


564-574: Good preservation of project context during file processing.

The file processing logic correctly maintains project context by copying all relevant fields to the new parser instance.


660-685: LGTM: Enhanced function node properties with project metadata.

The function properties now include additional context like the project name, color coding, and source URL, which improves traceability and visualization.


929-946: LGTM: Enhanced namespace node properties with project metadata.

The namespace node properties now include additional context like the project name, color coding, and source URL, which improves traceability and visualization.


969-992: LGTM: Enhanced type node properties with project metadata.

The type node properties now include additional context like the project name, color coding, and source URL, which improves traceability and visualization.

✨ Finishing Touches
  • 📝 Docstrings were successfully generated. (🔄 Check again to generate docstrings again)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Hello @TheApeMachine, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

Summary of Changes

Hello team, gemini-code-assist here to provide a summary of this pull request. The primary goal of this PR, as indicated by the title and description, is to enable the code parsing process to handle multiple projects independently. This is achieved by making the parser configuration external (via environment variables), enriching the graph nodes with project-specific information, creating a root node for each project in the Neo4j database, and modifying the cleanup process to only delete nodes belonging to the current project rather than wiping the entire database. This lays the groundwork for parsing and visualizing code from different projects within the same graph database instance.

Highlights

  • Configurable Parsing: The application now reads Neo4j connection details, project name (ROOT_NAME), and base URL (BASE_URL) from environment variables, making the parsing process configurable for different projects without code changes.
  • Project-Specific Data: Graph nodes (Function, Namespace, Type) are updated to include a project property, linking them explicitly to the project they belong to. A dedicated Root node is created for each project to serve as an entry point.
  • Project-Specific Cleanup: The database cleanup logic is modified to delete only the nodes associated with the current project (identified by the project property), preventing accidental deletion of data from other projects.
  • Source Code URL Generation: A new method createURL is added to generate links to the specific lines of source code for nodes, using the configured BASE_URL and file path.

Changelog

Click here to see the changelog
  • graphlang/graphlang.go
    • Added NodeColors map for potential visualization hints.
    • Added fields (filePath, rootName, baseURL, projectRoot, rootID) to TreeSitterParser struct to hold project-specific configuration.
    • Updated NewTreeSitterParser to accept rootName, baseURL, and projectRoot.
    • Added createURL method to generate source code links.
    • Modified cleanup function to read Neo4j credentials from environment variables and added validation.
    • Changed the Neo4j query in cleanup to delete nodes only for the current project (MATCH (n {project: $project})).
    • Added logic in AnalyzeDirectory to MERGE (create or update) a Root node for the project.
    • Passed project-specific configuration (filePath, rootName, baseURL, projectRoot, rootID) when creating fileParser instances in processFile.
    • Updated handleFunction, handleNamespace, and handleType to use the project's rootName in node IDs, add project, color, and url properties, and link the created nodes to the project's Root node.
  • main.go
    • Imported the os package.
    • Modified main function to read Neo4j connection details, ROOT_NAME, and BASE_URL from environment variables.
    • Added default values for rootName and baseURL if not provided.
    • Added checks to ensure required Neo4j environment variables are set.
    • Removed the explicit Neo4j session creation in main (now handled internally by the parser).
    • Updated the call to graphlang.NewTreeSitterParser to pass the read configuration (driver, rootName, baseURL, dirPath).
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.


Code flows like a stream,
Parsed into a graph dream.
Nodes connect and grow,
Where the functions go.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively implements configurable cross-project parsing. Key changes include sourcing configuration from environment variables, enriching graph nodes with project-specific data (including URLs), creating dedicated root nodes for each project, and scoping database cleanup operations to the current project. These are excellent enhancements for managing multiple codebases.

I've noted a few areas for improvement, mainly around error handling in database transactions and configuration flexibility. Addressing these will enhance the robustness of the new functionality.

Summary of Findings

  • Error Handling for Node Linking: In handleFunction, handleNamespace, and handleType, errors from tx.Run when linking these nodes to the project's Root node are currently ignored. This could lead to silent failures and graph inconsistencies. These errors should be checked and handled, potentially by logging and returning the error to ensure transaction rollback.
  • Neo4j Session Management: In AnalyzeDirectory, the Neo4j session for creating the root node is not closed using defer. If an error occurs during session.Run, the explicit session.Close() call might be skipped, leading to a potential resource leak.
  • Configuration Flexibility: In main.go, the directory path for analysis (dirPath) is hardcoded. Making this configurable via an environment variable would improve the tool's flexibility.

Merge Readiness

The pull request introduces valuable functionality for cross-project parsing. However, there are several medium-severity issues related to error handling, and configuration flexibility that should be addressed to ensure the robustness and maintainability of the code. I recommend that these changes be made before merging. As an AI, I am not authorized to approve pull requests; please ensure further review and approval from authorized team members.

Comment on lines +693 to +695
_, _ = tx.Run(context.Background(),
`MATCH (r:Root {id:$rid}), (f:Function {id:$fid}) MERGE (r)-[:CONTAINS]->(f)`,
map[string]any{"rid": parser.rootID, "fid": fmt.Sprintf("%s:%s", parser.rootName, qualifiedName)})
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The error returned by tx.Run when attempting to merge the CONTAINS relationship between the Root node and the Function node is currently ignored (using _, _ = ...). If this operation fails, the function node might not be correctly linked to its project root, which could lead to inconsistencies or issues in graph traversal later. Should this error be checked and potentially logged or even propagated to ensure the transaction rolls back if the linking fails?

_, linkErr := tx.Run(context.Background(),
			`MATCH (r:Root {id:$rid}), (f:Function {id:$fid}) MERGE (r)-[:CONTAINS]->(f)`,
			map[string]any{"rid": parser.rootID, "fid": fmt.Sprintf("%s:%s", parser.rootName, qualifiedName)})
		if linkErr != nil {
			log.Printf("Error linking function '%s' to root '%s': %v", qualifiedName, parser.rootID, linkErr)
			// Consider returning linkErr to ensure transaction rollback if this link is critical
			return linkErr
		}

Comment on lines +947 to +949
_, _ = tx.Run(context.Background(),
`MATCH (r:Root {id:$rid}), (n:Namespace {id:$nid}) MERGE (r)-[:CONTAINS]->(n)`,
map[string]any{"rid": parser.rootID, "nid": fmt.Sprintf("%s:%s", parser.rootName, namespaceName)})
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Similar to the handleFunction case, the error from tx.Run when linking the Namespace node to the Root node is ignored. This could lead to a Namespace node existing without being properly connected to its project's Root. Would it be better to check this error and handle it, perhaps by logging and/or returning it to ensure transactional integrity?

_, linkErr := tx.Run(context.Background(),
			`MATCH (r:Root {id:$rid}), (n:Namespace {id:$nid}) MERGE (r)-[:CONTAINS]->(n)`,
			map[string]any{"rid": parser.rootID, "nid": fmt.Sprintf("%s:%s", parser.rootName, namespaceName)})
		if linkErr != nil {
			log.Printf("Error linking namespace '%s' to root '%s': %v", namespaceName, parser.rootID, linkErr)
			// Consider returning linkErr
			return linkErr
		}

Comment on lines +994 to +996
_, _ = tx.Run(context.Background(),
`MATCH (r:Root {id:$rid}), (t:Type {id:$tid}) MERGE (r)-[:CONTAINS]->(t)`,
map[string]any{"rid": parser.rootID, "tid": fmt.Sprintf("%s:%s", parser.rootName, qualifiedName)})
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The error from tx.Run when linking the Type node to the Root node is also ignored here. Consistent with the feedback for handleFunction and handleNamespace, it's advisable to check this error. If the link fails, it could impact graph consistency. Should this error be logged and possibly returned?

_, linkErr := tx.Run(context.Background(),
			`MATCH (r:Root {id:$rid}), (t:Type {id:$tid}) MERGE (r)-[:CONTAINS]->(t)`,
			map[string]any{"rid": parser.rootID, "tid": fmt.Sprintf("%s:%s", parser.rootName, qualifiedName)})
		if linkErr != nil {
			log.Printf("Error linking type '%s' to root '%s': %v", qualifiedName, parser.rootID, linkErr)
			// Consider returning linkErr
			return linkErr
		}

defer session.Close(context.Background())

dirPath := "/app" // Replace with the actual directory path
dirPath := "/app"
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The dirPath is hardcoded to "/app". While this might be suitable for a specific Docker deployment, making it configurable (e.g., via an environment variable like ANALYSIS_PATH) would offer more flexibility for running the analyzer in different environments or against different source directories without rebuilding the container or changing the code. Consider adding an environment variable for this path with "/app" as a default.

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: 1

🔭 Outside diff range comments (2)
main.go (1)

29-31: ⚠️ Potential issue

Avoid logging secrets – redact the Neo4j password before printing

log.Printf currently prints the plain-text password, which ends up in stdout / logs and can be harvested from container logs or CI pipelines.
Replace it with a masked or omitted value.

-log.Printf("Connecting to Neo4j at %s with user %s and password %s\n", neo4jURI, neo4jUser, neo4jPassword)
+log.Printf("Connecting to Neo4j at %s with user %s\n", neo4jURI, neo4jUser)
graphlang/graphlang.go (1)

289-304: ⚠️ Potential issue

Reuse the existing Neo4j driver instead of creating a second one & stop logging the password

cleanup() ignores parser.driver and spins up a new driver with credentials
read again from the environment. This doubles the number of TCP connections,
duplicates TLS handshakes, and risks mismatching credentials at runtime. It
also logs the password in clear text.

-func (parser *TreeSitterParser) cleanup() error {
-    neo4jURI := os.Getenv("NEO4J_URI")
-    neo4jUser := os.Getenv("NEO4J_USER")
-    neo4jPassword := os.Getenv("NEO4J_PASSWORD")
-    ...
-    driver, err := neo4j.NewDriverWithContext(neo4jURI, neo4j.BasicAuth(neo4jUser, neo4jPassword, ""))
-    ...
-    defer driver.Close(context.Background())
+func (parser *TreeSitterParser) cleanup() error {
+    driver := parser.driver   // reuse the already-configured, shared driver

and change the logging line to:

-log.Printf("Connecting to Neo4j at %s with user %s and password %s\n", neo4jURI, neo4jUser, neo4jPassword)
+log.Printf("Running cleanup against project %s", parser.rootName)

Finally, remove the extra driver.Close because the owner (main.go) already
defers a single close.

🧹 Nitpick comments (3)
main.go (2)

36-38: Make the analysed directory configurable instead of hard-coding “/app”

Hard-coding the directory path limits portability (e.g. running locally on macOS/Windows).
Expose it as an env-var or CLI flag so the same binary can analyse any checkout.

-dirPath := "/app"
+dirPath := os.Getenv("PROJECT_ROOT")
+if dirPath == "" {
+    dirPath, _ = os.Getwd() // fall back to current working dir
+}

30-34: Verify connectivity early and fail fast

After constructing the driver, call driver.VerifyConnectivity(ctx) so that
network / auth problems surface immediately instead of several minutes into the
scan.

 driver, err := neo4j.NewDriverWithContext(neo4jURI, neo4j.BasicAuth(neo4jUser, neo4jPassword, ""))
 if err != nil {
     log.Fatalf("Failed to create Neo4j driver: %v", err)
 }
+if err := driver.VerifyConnectivity(context.Background()); err != nil {
+    log.Fatalf("Neo4j unreachable: %v", err)
+}
graphlang/graphlang.go (1)

373-381: Capture session.Run error before closing the session

session.Close may overwrite err; capture the error first to avoid losing it.

-session := parser.driver.NewSession(...)
-_, err := session.Run(...)
/* close afterwards */
-session.Close(context.Background())
+session := parser.driver.NewSession(...)
+result, runErr := session.Run(...)
+closeErr := session.Close(context.Background())
+if runErr != nil {
+    return fmt.Errorf("failed to create root node: %w", runErr)
+}
+if closeErr != nil {
+    return fmt.Errorf("failed to close session: %w", closeErr)
+}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 1fd5025 and b5d94ed.

📒 Files selected for processing (2)
  • graphlang/graphlang.go (10 hunks)
  • main.go (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
main.go (1)
graphlang/graphlang.go (1)
  • NewTreeSitterParser (93-102)
graphlang/graphlang.go (2)
go/main.go (1)
  • NodeColors (20-28)
js/analyzer.js (1)
  • NodeColors (7-15)

Comment on lines +105 to 112
func (parser *TreeSitterParser) createURL(line int) string {
rel := strings.TrimPrefix(parser.filePath, parser.projectRoot)
base := parser.baseURL
if !strings.HasSuffix(base, "/") {
base += "/"
}
return fmt.Sprintf("%s%s#%d", base, strings.TrimPrefix(rel, "/"), line)
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

createURL breaks on Windows paths and needs URL-escaping

strings.TrimPrefix(parser.filePath, parser.projectRoot) leaves back-slashes on
Windows and doesn’t encode #, spaces, etc. Use filepath.ToSlash,
path.Join, and url.PathEscape (from net/url) to generate a portable,
clickable link.

 import (
     "context"
@@
+    "net/url"
     "fmt"
@@
-func (parser *TreeSitterParser) createURL(line int) string {
-    rel := strings.TrimPrefix(parser.filePath, parser.projectRoot)
-    base := parser.baseURL
-    if !strings.HasSuffix(base, "/") {
-        base += "/"
-    }
-    return fmt.Sprintf("%s%s#%d", base, strings.TrimPrefix(rel, "/"), line)
+func (parser *TreeSitterParser) createURL(line int) string {
+    rel, _ := filepath.Rel(parser.projectRoot, parser.filePath)
+    rel = filepath.ToSlash(rel)
+    escaped := url.PathEscape(rel)
+    return fmt.Sprintf("%s/%s#L%d", strings.TrimRight(parser.baseURL, "/"), escaped, line)
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In graphlang/graphlang.go around lines 105 to 112, the createURL function does
not handle Windows paths correctly and fails to URL-escape special characters.
To fix this, convert the relative file path to use forward slashes with
filepath.ToSlash, join the base URL and relative path using path.Join for proper
URL path construction, and apply url.PathEscape to the path and line fragment to
ensure all special characters are correctly escaped, producing a portable and
clickable URL.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@TheApeMachine TheApeMachine merged commit 465b368 into master May 18, 2025
2 checks passed
coderabbitai bot added a commit that referenced this pull request May 18, 2025
…ose`

Docstrings generation was requested by @TheApeMachine.

* #1 (comment)

The following files were modified:

* `graphlang/graphlang.go`
* `main.go`
@coderabbitai
Copy link

coderabbitai bot commented May 18, 2025

Note

Generated docstrings for this pull request at #2

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants