Skip to content

fix: nested effects rendering#36

Merged
antouhou merged 1 commit into
mainfrom
fix-effects-nesting
Feb 19, 2026
Merged

fix: nested effects rendering#36
antouhou merged 1 commit into
mainfrom
fix-effects-nesting

Conversation

@antouhou
Copy link
Copy Markdown
Owner

@antouhou antouhou commented Feb 19, 2026

Summary by CodeRabbit

  • New Features

    • Added example demonstrating analytical box shadow rendering with rounded corner support.
    • Added example showcasing combined box shadow and backdrop blur effects on panels.
  • Improvements

    • Enhanced rendering pipeline with backdrop-aware effect composition for more sophisticated visual effects.
    • Improved texture pooling to better support multi-sample anti-aliasing configurations.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 19, 2026

📝 Walkthrough

Walkthrough

The PR adds two new examples demonstrating box shadow and backdrop blur effects using analytical WGSL shaders. Core framework changes include exposing texture resources in PooledTexture and significantly refactoring the renderer to support backdrop-aware, segment-based rendering with separate offscreen passes for proper effect composition.

Changes

Cohort / File(s) Summary
Example: Box Shadow
examples/box_shadow.rs
New self-contained example demonstrating analytical box shadow rendering via WGSL shader. Introduces BoxShadowParams struct with shadow geometry/color/offset/sigma parameters, draw_card helper, fragment shader with Gaussian integral and rounded-box SDF for corners, and ApplicationHandler implementation for windowing and rendering lifecycle.
Example: Shadow and Blur
examples/shadow_and_blur.rs
New example combining box shadow and backdrop blur effects on a frosted-glass panel. Defines BOX_SHADOW_EFFECT and BLUR_EFFECT identifiers, shader parameters (BoxShadowParams, BlurParams), separable Gaussian blur shaders (horizontal/vertical), and ApplicationHandler managing group effects and backdrop rendering.
Texture Resource Exposure
src/effect.rs
PooledTexture struct gains public fields: color_texture, resolve_texture, and resolve_view. Updated OffscreenTexturePool creation logic to explicitly initialize and expose these texture resources, with resolve texture handling for MSAA paths.
Backdrop-Aware Rendering Pipeline
src/renderer.rs
Major refactor introducing segment-based rendering for subtrees with backdrop effects. Adds BackdropContext and associated helpers (plan_traversal, render_segments, render_scene_behind_group) to handle multi-pass offscreen rendering: pre-render scene behind target, render group subtree, execute backdrop effect passes, and compose with stencil-based masking. Phase 2 logic integrated to preserve fast path for non-backdrop subtrees.

Sequence Diagram(s)

sequenceDiagram
    participant Renderer
    participant BackdropContext
    participant OffscreenTexture as Offscreen<br/>Textures
    participant Shader as WGSL<br/>Shaders
    participant Output as Final<br/>Output

    Renderer->>BackdropContext: plan_traversal (subtree structure)
    BackdropContext->>OffscreenTexture: create "behind" texture
    Renderer->>OffscreenTexture: render scene behind group
    Renderer->>OffscreenTexture: render group subtree (color_texture)
    Renderer->>OffscreenTexture: copy output to snapshot
    Renderer->>Shader: execute backdrop effect passes
    Shader->>OffscreenTexture: ping-pong processing (if needed)
    Renderer->>Output: stencil increment (prep mask)
    Renderer->>Output: backdrop quad (apply effect)
    Renderer->>Output: shape color composition
    Output->>Output: final image with backdrop effect
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • grafo#35: Modifies core effect and renderer systems with similar backdrop-rendering pipelines, effect API design, and shader-backed infrastructure for analytical effects

Poem

🐰 Whiskers twitch at shadows cast,
Analytical shaders render fast,
Blurred backdrops dance and sway,
Glass panels glow in algorithmic play!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The PR title 'fix: nested effects rendering' is vague and does not clearly convey the substantial new functionality being added (two complete example files, effect pool texture exposure, and significant rendering refactoring for backdrop effects). Consider clarifying the title to better reflect the main changes, such as 'Add backdrop effects support and example demonstrations' or 'Implement segment-based backdrop effect rendering' to better communicate the primary intent.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-effects-nesting

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

@antouhou antouhou merged commit ea6c5ee into main Feb 19, 2026
4 of 5 checks passed
Copy link
Copy Markdown

@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: 2

🧹 Nitpick comments (1)
src/renderer.rs (1)

2466-2470: Prefer structured logging over println! in library code.

Using the logging macros keeps output controllable and avoids polluting stdout.

♻️ Suggested change
-        println!(
-            "Loading effect {} with {} passes",
-            effect_id,
-            pass_sources.len()
-        );
+        log::debug!(
+            "Loading effect {} with {} passes",
+            effect_id,
+            pass_sources.len()
+        );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer.rs` around lines 2466 - 2470, Replace the stdout println! in the
renderer (the call that prints "Loading effect {} with {} passes" using
effect_id and pass_sources.len()) with a structured logging macro (e.g.,
log::info! or tracing::info!) so logs are controllable; update imports to use
the chosen logging crate and ensure the application initializes a logger at
startup. Keep the same message and variables (effect_id and pass_sources.len())
but use the logger macro inside the same function that currently contains the
println! call.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/renderer.rs`:
- Around line 3475-3504: subtree_has_backdrop_effects currently only scans
descendants and misses checking the root itself; update the function
(subtree_has_backdrop_effects) to first test whether
backdrop_effects.contains_key(&root_id) and return true if so before calling
scan, leaving scan and the descendant iteration unchanged so nodes that have
both group and backdrop effects are correctly detected.
- Around line 1330-1374: The effect-node ordering is unstable because
effect_node_ids is built from HashMap::keys() and only sorted by depth, causing
siblings at the same depth to be processed in nondeterministic order and miss
earlier siblings' effect_results in render_scene_behind_group; fix by adding a
secondary sort key that reflects deterministic tree draw order (e.g., a
pre-order/traversal index) when sorting effect_node_ids so ties on depth are
broken by traversal/draw order (ensure you reference the same traversal index or
ordering method used by your draw tree), guaranteeing effect_results contains
all previously drawn siblings before creating a behind snapshot for node_id.

---

Nitpick comments:
In `@src/renderer.rs`:
- Around line 2466-2470: Replace the stdout println! in the renderer (the call
that prints "Loading effect {} with {} passes" using effect_id and
pass_sources.len()) with a structured logging macro (e.g., log::info! or
tracing::info!) so logs are controllable; update imports to use the chosen
logging crate and ensure the application initializes a logger at startup. Keep
the same message and variables (effect_id and pass_sources.len()) but use the
logger macro inside the same function that currently contains the println! call.

Comment thread src/renderer.rs
Comment on lines +1330 to +1374
// Pre-render the scene content behind this group
let behind_tex = self.offscreen_texture_pool.acquire(
&self.device,
width,
height,
self.config.format,
self.msaa_sample_count,
);
let behind_depth = create_and_depth_texture(
&self.device,
(width, height),
self.msaa_sample_count,
);
let behind_depth_view =
behind_depth.create_view(&wgpu::TextureViewDescriptor::default());

let (behind_color_view, behind_resolve_target) = if behind_tex.sample_count > 1
{
(
&behind_tex.color_view,
Some(behind_tex.resolve_view.as_ref().unwrap() as &wgpu::TextureView),
)
} else {
(&behind_tex.color_view as &wgpu::TextureView, None)
};

render_scene_behind_group(
&mut self.draw_tree,
&mut encoder,
&effect_results,
node_id,
behind_color_view,
behind_resolve_target,
&behind_depth_view,
self.composite_pipeline.as_ref(),
&pipelines,
&buffers,
);

// The backdrop copy source is the resolved behind texture
let behind_copy_source = if behind_tex.sample_count > 1 {
behind_tex.resolve_texture.as_ref().unwrap()
} else {
&behind_tex.color_texture
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for effect_results ordering and traversal logic
rg -n "effect_results" src/renderer.rs | head -30

Repository: antouhou/grafo

Length of output: 1719


🏁 Script executed:

#!/bin/bash
# Search for HashMap-related effect construction
rg -n "HashMap|effect_node_ids|group_effects|compute_node_depth" src/renderer.rs | head -40

Repository: antouhou/grafo

Length of output: 2372


🏁 Script executed:

#!/bin/bash
# Search for traversal methods
rg -n "traverse" src/renderer.rs | head -30

Repository: antouhou/grafo

Length of output: 766


🏁 Script executed:

#!/bin/bash
# Find render_scene_behind_group definition and examine it
rg -n "fn render_scene_behind_group" src/renderer.rs -A 50

Repository: antouhou/grafo

Length of output: 2244


🏁 Script executed:

#!/bin/bash
# Check the context around line 1359 to see how render_scene_behind_group is called
sed -n '1355,1375p' src/renderer.rs

Repository: antouhou/grafo

Length of output: 877


🏁 Script executed:

#!/bin/bash
# Check if there's any ordering logic related to siblings or draw order
rg -n "draw.?order|sibling|postorder|preorder|post_order|pre_order" src/renderer.rs

Repository: antouhou/grafo

Length of output: 249


🏁 Script executed:

#!/bin/bash
# Get the full context around line 1359 and the loop at 1295
sed -n '1284,1370p' src/renderer.rs

Repository: antouhou/grafo

Length of output: 4052


🏁 Script executed:

#!/bin/bash
# Check what traverse_mut does - look at its signature and behavior
rg -n "fn traverse_mut|impl.*Tree" src/renderer.rs | head -20

Repository: antouhou/grafo

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Search for the draw_tree definition to understand its traversal order
rg -n "draw_tree" src/renderer.rs | grep "new\|Tree" | head -10

Repository: antouhou/grafo

Length of output: 322


🏁 Script executed:

#!/bin/bash
# Check if there's documentation or implementation about traversal order
rg -n "easy_tree" src/renderer.rs | head -5

Repository: antouhou/grafo

Length of output: 308


🏁 Script executed:

#!/bin/bash
# Look for where the draw tree is populated/built to understand its structure
rg -n "push_back\|append\|insert.*draw_tree" src/renderer.rs | head -20

Repository: antouhou/grafo

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Check the full render_scene_behind_group to see what it actually renders
sed -n '4202,4350p' src/renderer.rs

Repository: antouhou/grafo

Length of output: 5214


🏁 Script executed:

#!/bin/bash
# Check if easy_tree provides deterministic traversal by tree structure
rg -n "pub fn traverse" --type rust | head -10

Repository: antouhou/grafo

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Look for any post-order or draw-order sorting logic around effect_node_ids
sed -n '1280,1300p' src/renderer.rs

Repository: antouhou/grafo

Length of output: 1006


🏁 Script executed:

#!/bin/bash
# Check how nodes are added to the tree to understand their natural order
rg -n "add_node\|add_child\|insert_node" src/renderer.rs | head -15

Repository: antouhou/grafo

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Verify the easy_tree crate to understand traversal ordering
cat Cargo.toml | grep -A 2 "easy_tree"

Repository: antouhou/grafo

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Search for how draw order is maintained or if there's a secondary sort key
rg -n "depth|draw_order|draw.order" src/renderer.rs | grep -E "(sort|cmp)" | head -20

Repository: antouhou/grafo

Length of output: 132


🏁 Script executed:

#!/bin/bash
# Check if there's a way to get siblings in order from the tree
rg -n "children|sibling|next_sibling" src/renderer.rs | head -20

Repository: antouhou/grafo

Length of output: 290


🏁 Script executed:

#!/bin/bash
# Look for postorder or depth-first traversal functions
rg -n "postorder|post_order|dfs|depth_first" src/renderer.rs

Repository: antouhou/grafo

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Check how the draw tree is built and if sibling insertion order is preserved
rg -n "fn handle.*group|DrawCommand::Group" src/renderer.rs | head -20

Repository: antouhou/grafo

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Check the exact sorting logic and see if there's a secondary sort key
sed -n '1284,1295p' src/renderer.rs

Repository: antouhou/grafo

Length of output: 602


🏁 Script executed:

#!/bin/bash
# Look for any deterministic ordering that might be used elsewhere
rg -n "node_id.*sort\|sort.*node" src/renderer.rs | head -10

Repository: antouhou/grafo

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Check how plan_traversal orders nodes to see if that pattern could apply here
sed -n '3540,3610p' src/renderer.rs

Repository: antouhou/grafo

Length of output: 2523


🏁 Script executed:

#!/bin/bash
# Look for how nodes are inserted into the tree to understand if insertion order equals draw order
rg -n "add_child\|push_child\|children_ref_mut" src/renderer.rs | head -20

Repository: antouhou/grafo

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Check if easy_tree maintains insertion order (which would be draw order)
rg -n "easy_tree::" Cargo.lock | head -5

Repository: antouhou/grafo

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Examine the loop structure more carefully to understand when effect_results is updated
sed -n '1295,1705p' src/renderer.rs | head -100

Repository: antouhou/grafo

Length of output: 4712


🏁 Script executed:

#!/bin/bash
# Check where effect_results is updated during the loop
rg -n "effect_results.insert" src/renderer.rs

Repository: antouhou/grafo

Length of output: 124


🏁 Script executed:

#!/bin/bash
# See the full context of effect result insertion to understand when it's updated
sed -n '1690,1710p' src/renderer.rs

Repository: antouhou/grafo

Length of output: 913


🏁 Script executed:

#!/bin/bash
# Check if there's any logic that ensures all earlier effects are processed before later ones
sed -n '1275,1310p' src/renderer.rs

Repository: antouhou/grafo

Length of output: 1726


🏁 Script executed:

#!/bin/bash
# Check what happens with the behind texture after it's created
sed -n '1360,1430p' src/renderer.rs

Repository: antouhou/grafo

Length of output: 3682


🏁 Script executed:

#!/bin/bash
# Verify that easy_tree.traverse_mut respects tree structure (insertion order of children)
rg -n "struct Tree\|impl.*Tree" src/renderer.rs | head -5

Repository: antouhou/grafo

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Check if there's any documentation or pattern that guarantees sibling order
rg -n "insertion order\|draw order\|sibling" src/renderer.rs | head -10

Repository: antouhou/grafo

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Check if node_id is assigned in a deterministic order (e.g., breadth-first or depth-first)
rg -n "node_id.*=" src/renderer.rs | grep -E "(push|insert|add)" | head -15

Repository: antouhou/grafo

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Look for tree traversal to understand if there's a natural tree iteration order
sed -n '4248,4270p' src/renderer.rs

Repository: antouhou/grafo

Length of output: 1080


🏁 Script executed:

#!/bin/bash
# Understand the precise timing: when is behind texture created vs effect_results populated
sed -n '1320,1370p' src/renderer.rs

Repository: antouhou/grafo

Length of output: 2470


Effect-result ordering can cause incorrect backdrop snapshots when siblings have backdrop effects.

When effect_node_ids is built from HashMap::keys() and sorted only by depth, siblings at the same depth retain HashMap's nondeterministic iteration order. If sibling A is processed before sibling B (both with effects), render_scene_behind_group for A uses effect_results that doesn't yet contain B's entry—so B's rendered content is omitted from A's behind snapshot. Add a secondary sort key (using tree traversal order) to ensure siblings are processed in deterministic draw order, guaranteeing all earlier-drawn siblings are in effect_results before their behind textures are created.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer.rs` around lines 1330 - 1374, The effect-node ordering is
unstable because effect_node_ids is built from HashMap::keys() and only sorted
by depth, causing siblings at the same depth to be processed in nondeterministic
order and miss earlier siblings' effect_results in render_scene_behind_group;
fix by adding a secondary sort key that reflects deterministic tree draw order
(e.g., a pre-order/traversal index) when sorting effect_node_ids so ties on
depth are broken by traversal/draw order (ensure you reference the same
traversal index or ordering method used by your draw tree), guaranteeing
effect_results contains all previously drawn siblings before creating a behind
snapshot for node_id.

Comment thread src/renderer.rs
Comment on lines +3475 to +3504
/// Check whether any descendant of `root_id` (exclusive) has a backdrop effect.
///
/// Returns `true` if any child, grandchild, etc. of the given root node has a
/// backdrop effect attached. Used to decide whether Phase 1 subtree rendering
/// needs the segment-based render loop with pass-breaking support.
fn subtree_has_backdrop_effects(
tree: &easy_tree::Tree<DrawCommand>,
backdrop_effects: &HashMap<usize, EffectInstance>,
root_id: usize,
) -> bool {
if backdrop_effects.is_empty() {
return false;
}
fn scan(
tree: &easy_tree::Tree<DrawCommand>,
backdrop_effects: &HashMap<usize, EffectInstance>,
node_id: usize,
) -> bool {
for &child_id in tree.children(node_id) {
if backdrop_effects.contains_key(&child_id) {
return true;
}
if scan(tree, backdrop_effects, child_id) {
return true;
}
}
false
}
scan(tree, backdrop_effects, root_id)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Search for calls to subtree_has_backdrop_effects to understand its usage
rg -n "subtree_has_backdrop_effects" src/renderer.rs -A 3 -B 3

Repository: antouhou/grafo

Length of output: 850


🏁 Script executed:

# Look for context around group effects and backdrop effects
rg -n "set_group_effect|set_shape_backdrop_effect" src/renderer.rs -A 2 -B 2

Repository: antouhou/grafo

Length of output: 592


🏁 Script executed:

# Search for Phase 1 rendering logic and how backdrop effects are handled
rg -n "Phase 1|phase.1|phase1" src/renderer.rs -A 2 -B 2

Repository: antouhou/grafo

Length of output: 1175


🏁 Script executed:

# Look for any validation or guards about combining group + backdrop effects
rg -n "group_effect.*backdrop|backdrop.*group_effect" src/renderer.rs -i

Repository: antouhou/grafo

Length of output: 40


🏁 Script executed:

# Examine the Phase 1 rendering logic around where subtree_has_backdrop_effects is called
sed -n '1300,1350p' src/renderer.rs

Repository: antouhou/grafo

Length of output: 2528


🏁 Script executed:

# Search for where group_effects and backdrop_effects are populated to understand if both can exist on same node
rg -n "group_effects.insert|backdrop_effects.insert" src/renderer.rs -B 2 -A 2

Repository: antouhou/grafo

Length of output: 285


🏁 Script executed:

# Check the set_group_effect and set_shape_backdrop_effect methods for any validation
sed -n '2487,2530p' src/renderer.rs

Repository: antouhou/grafo

Length of output: 1765


🏁 Script executed:

# Check the set_shape_backdrop_effect method
sed -n '2629,2660p' src/renderer.rs

Repository: antouhou/grafo

Length of output: 1313


Check root node for backdrop effects in subtree_has_backdrop_effects.

The function only checks descendants, so if a node has both a group effect and a backdrop effect, Phase 1 will take the fast path and skip applying the backdrop effect on that node. Add a check for the root node before scanning descendants.

Suggested fix
 fn subtree_has_backdrop_effects(
     tree: &easy_tree::Tree<DrawCommand>,
     backdrop_effects: &HashMap<usize, EffectInstance>,
     root_id: usize,
 ) -> bool {
     if backdrop_effects.is_empty() {
         return false;
     }
+    if backdrop_effects.contains_key(&root_id) {
+        return true;
+    }
     fn scan(
         tree: &easy_tree::Tree<DrawCommand>,
         backdrop_effects: &HashMap<usize, EffectInstance>,
         node_id: usize,
     ) -> bool {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// Check whether any descendant of `root_id` (exclusive) has a backdrop effect.
///
/// Returns `true` if any child, grandchild, etc. of the given root node has a
/// backdrop effect attached. Used to decide whether Phase 1 subtree rendering
/// needs the segment-based render loop with pass-breaking support.
fn subtree_has_backdrop_effects(
tree: &easy_tree::Tree<DrawCommand>,
backdrop_effects: &HashMap<usize, EffectInstance>,
root_id: usize,
) -> bool {
if backdrop_effects.is_empty() {
return false;
}
fn scan(
tree: &easy_tree::Tree<DrawCommand>,
backdrop_effects: &HashMap<usize, EffectInstance>,
node_id: usize,
) -> bool {
for &child_id in tree.children(node_id) {
if backdrop_effects.contains_key(&child_id) {
return true;
}
if scan(tree, backdrop_effects, child_id) {
return true;
}
}
false
}
scan(tree, backdrop_effects, root_id)
}
/// Check whether any descendant of `root_id` (exclusive) has a backdrop effect.
///
/// Returns `true` if any child, grandchild, etc. of the given root node has a
/// backdrop effect attached. Used to decide whether Phase 1 subtree rendering
/// needs the segment-based render loop with pass-breaking support.
fn subtree_has_backdrop_effects(
tree: &easy_tree::Tree<DrawCommand>,
backdrop_effects: &HashMap<usize, EffectInstance>,
root_id: usize,
) -> bool {
if backdrop_effects.is_empty() {
return false;
}
if backdrop_effects.contains_key(&root_id) {
return true;
}
fn scan(
tree: &easy_tree::Tree<DrawCommand>,
backdrop_effects: &HashMap<usize, EffectInstance>,
node_id: usize,
) -> bool {
for &child_id in tree.children(node_id) {
if backdrop_effects.contains_key(&child_id) {
return true;
}
if scan(tree, backdrop_effects, child_id) {
return true;
}
}
false
}
scan(tree, backdrop_effects, root_id)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer.rs` around lines 3475 - 3504, subtree_has_backdrop_effects
currently only scans descendants and misses checking the root itself; update the
function (subtree_has_backdrop_effects) to first test whether
backdrop_effects.contains_key(&root_id) and return true if so before calling
scan, leaving scan and the descendant iteration unchanged so nodes that have
both group and backdrop effects are correctly detected.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant