Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POA index out of bounds #549

Open
wdecoster opened this issue Aug 24, 2023 · 26 comments · Fixed by #569 · May be fixed by #575
Open

POA index out of bounds #549

wdecoster opened this issue Aug 24, 2023 · 26 comments · Fixed by #569 · May be fixed by #575

Comments

@wdecoster
Copy link

wdecoster commented Aug 24, 2023

Hi,

I ran into the panic below while creating a consensus from poa:

thread '<unnamed>' panicked at 'index out of bounds: the len is 478 but the index is 478', /home/wdecoster/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bio-1.3.1/src/alignment/poa.rs:339:28

That corresponds to https://github.com/rust-bio/rust-bio/blob/master/src/alignment/poa.rs#L339

I don't have much to help you reproduce the error, as random downsampling was used to limit the number of sequences for POA, and with a different random sampling the panic was not reproduced.

@wdecoster
Copy link
Author

To add to this, running my code for many more loci, I see this happening more often:

thread '<unnamed>' panicked at 'index out of bounds: the len is 2269 but the index is 2269', /home/wdecoster/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bio-1.3.1/src/alignment/poa.rs:339:28
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread '<unnamed>' panicked at 'index out of bounds: the len is 3147 but the index is 3147', /home/wdecoster/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bio-1.3.1/src/alignment/poa.rs:339:28
thread '<unnamed>' panicked at 'index out of bounds: the len is 1144 but the index is 1144', /home/wdecoster/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bio-1.3.1/src/alignment/poa.rs:339:28
thread '<unnamed>' panicked at 'index out of bounds: the len is 1154 but the index is 1154', /home/wdecoster/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bio-1.3.1/src/alignment/poa.rs:339:28

@lorewar2
Copy link
Member

lorewar2 commented Sep 6, 2023

Is it possible to provide the graph of any of these?
e.g

let graph = aligner.graph();
println!("{:?}", Dot::new(&graph.map(|_, n| (*n) as char, |_, e| *e)));

@wdecoster
Copy link
Author

Certainly! I ran my tool single-threaded, and after 105 successful POAs, the panic happened. You can find a graph here:
faulthy_poa.txt

Feel free to let me know if there is anything else I can give you to help debug this.

@lorewar2
Copy link
Member

lorewar2 commented Sep 7, 2023

There is a cycle in the graph, which seems to be where the problem is coming from,
Could you provide the sequences used to get the graph?

@wdecoster
Copy link
Author

Yes, but after rerunning the code to get the sequences too, it crashes on a different locus. Presumably the cause is the same... You can find the sequences and graph here:

faulthy_poa_with_seqs.txt

My code:

let mut seqs_bytes = vec![];
for seq in seqs.iter() {
    seqs_bytes.push(seq.to_string().bytes().collect::<Vec<u8>>());
}

let scoring = Scoring::new(-12, -6, |a: u8, b: u8| if a == b { 3 } else { -4 });
let mut aligner = Aligner::new(scoring, &seqs_bytes[0]);
for seq in seqs_bytes.iter().skip(1) {
    aligner.global_banded(seq, 20).add_to_graph();
}
let consensus = aligner.consensus();

@lorewar2
Copy link
Member

I tested this with latest rust bio and it ran without crashing.
Maybe the latest update fixes it, could you update rustbio and retest it?

@wdecoster
Copy link
Author

wdecoster commented Sep 13, 2023

Yes indeed, but after updating I ran into a new error:

thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 24', /home/wdecoster/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bio-1.4.0/src/alignment/poa.rs:186:21

This was caused by the sequences below:

GGGGGGAGGAGGGGGGAGGAGGGGGGAGGAGGACAGGCAAGGAGGCCTCGAAGAGGGAAGACCAGAGAAGGAGGGGAAGGGGAGAGCGGAGGGAAAGAGGTGGGATAAGGAAGAGAAGGAGGAGGAAGGGGAAGAGGGAGG
GGGGGGAGGAGGGGGGAGGAGGGGGGAGGAGGACAGGCAAGGAGGCCTCGAAGAGGGAAGACCAGAGAAGGAGGGGAAGGGGAGAGCGGAGGGAAAGAGGTGGGATAAGGAAGAGAAGGAGGAGGAAGGGGAAGAGGGAGG
AGGAGGAGGGAGGCGGGGGGAGGAGGGGGGAGGAGGGGGGAGGAAGGACAGGCAAGGAGGCCTCGAAGAGGGAAGACCAGAGAAGGAGGGGAAGGGGAGAGCGAGAAGAAGGTGGGATGAGGAAGGAAAGGAGC
GGGGGAGGAGGGGGGAGGAGGGGGGAGGAGGACAGGCAGTGGTGGCTCCGAAGAGGGAAGACCAGAGAAGGAGGGGAAGGGGAGAGCGGAGGGAAAGAGGTGGGATAAGGAAGAGAAGGAGGAGGAAGGGGAAGAGGGAGG
GGGGGGAGGAGGGGGGAGGAGGGGGGAGGAGGGACAGGGCAAGGAGGCCTCGAAGAGGGAAGACCAGAGAAGGAGGGGAAGGGGAGAGCGAGGGAGAGAAGGATGAGGGAGTAGGGAAGGAAAGGAGGAGGAAGGGGAAGAGGGAGG
GGGGGGAGGAGGGGGGAGGAGGGGGAGGAGGACAGGCAAGGAGGCCTCGAAGAGGGAAGACCAGAGAAGGAGGGGAAGGGGAGAGCGGAGGGAAAGAGGTGGGATAAGGAAGAGAAGGAGGAGGAAGGGAAGAGGGAGG
GGGGGGAGGAGGGGGAGGAGGGGAGGAGGACAGGCAAGGAGGCCTCGAAGAGGGAAGACCAGAGAAGGAGGGGAAGGGGAGAGCGGAGGGAAAGAGGTGGGATAAGGAAGAGAAGGAGGAGGAAGGGGAAGAGGGAGG
GGGGGGAGGAGGGGGGAGGAGGGGGGAGGAGGACAGGCAAGGAGGCCTCGAAGAGGGAAGACCAGAGAAGGAGGGGAAGGGGAGAGCGGAGGGAAAGAGGTGGGATAAGGAAGAGAAGGAGGAGGAAGGGGAAGAGGGAGG
GGGGGGAGGAGGGGGAGGAGGGGGGAGGAGGACAGGCAAGGAGGCCTGGGAGAGAGGGAAGACCAGAGAAGGAGGGGAAGGGGAGAGCGAGGAAAGAGGTGGGATAAGGAAGAAGGAGGAGGAAGGGGAAGAGGGAGG
GGGGGGAGGAGGGGGGAGGAGGGGGAGGAGGACAGGCAAGGAGGCCTCGAAGAGGGAAGACCAGAGAAGGAGGGGAAGGGGAGAGCGGAGGGAAAGAGGTGGGATAAGGAAGAGAAGGAGGAGGAAGGGGAAGAGGGAGG
GGGGGGAGGAGGGGGGAGGAGGGGGAGGAGGACAGGCAAGGAGGCCTCGAAGAGGGAAGACCAGAGAAGGAGGGGAAAGGGGAGAGCGGAGGGAAGAGGTGGGATAAGGAAGAGAAGGAGGAGGAAGGGGAAGAGGGAGG
GGGGGGAGGAGGGGGAGGAGGGGGGAGGAGGACAGGCAAGGAGGCCTCGAAGAGGGAAGACCAGAGAAGGAGGGGAAGGGGAGAGCGGAGGGAAAGAGGTGGGATAAGGAAGAGAAGGAGGAGGAAGGGGAAGAGGGAGG
GGGGGGAGGAGGGGGAGGAGGGGAGGAGGACAGGCAAGGAGGCCTCGAAGAGGGAAGACCAGAGAAGGAGGGGAAGGGGAGAGCGGAGGGAAAGAGGTGGGATAAGAAGAGAAGGAGGAGGAAGGGGAAGAGGGAGG
GGGGGGAGGAGGGGGGAGGAGGGGGGAGGAGGACAGGCAAGGAGGCCTCGAAGAGGGAAGACCAGAGAAGGAGGGGAAGGGGAGAGCGGAGGGAAAGAGGTGGGATAAGGAAGAGAAGGAGGAGGAAGGGGAAGAGGGAGG
GGGGGAGGAGGGGGGAGGAGGGGGGAGGAGGACAGGCAAGGAGGCCTCGAAGAGGGAAGACCAGAGAAGGAGGGGAAGGGGAGAGCGGAGGGAAAGAGGTGGGATAAGGAAGAGAAGGAGGAGGAAGGGGAAGAGGGAGG
GGGGGGAGGAGGGGGAGGAGGGGGAGGAGGACAGGGAAGGAGGCCTCGAAGAGGGAAGACCAGAGAAGGAGGGGGAAGGGAGAGCGGAGGGGAAAAGAGGTGGGATAAGGAAGAGAAGGAGGAGGAAGGGGAAGAGGGAGG

I was also able to reproduce this in a test outside of my application, with the sequences pasted above.

@wdecoster
Copy link
Author

Hi @lorewar2

I see you opened #552 with a fix, thanks!

Wouter

@lorewar2
Copy link
Member

lorewar2 commented Sep 20, 2023

It's not a complete fix, I ran into some bugs while testing. I need to debug them and update the fix. Thank you for pointing out the errors.

@wdecoster
Copy link
Author

Hi @lorewar2, do you have further ideas on how to fix those bugs? Is there anything I can do to help, or should I look for an alternative?

@lorewar2
Copy link
Member

lorewar2 commented Nov 2, 2023

Hi,
Sorry, I haven't looked into it as it works fine for my use case (processing pacbio ccs).
I'll take a look and try to figure something out.
If you want an alternative, I suggest abPOA.

@wdecoster
Copy link
Author

Thanks for the suggestion, but I would prefer to have it in Rust to use it within a Rust tool. I am not familiar with creating bindings for things like that.

@lorewar2
Copy link
Member

I made a fix for the poa, hopefully it will work correctly now.
I think it'll take some time for the fix to be merged, meanwhile could you test this out?
poa_fixed

@wdecoster
Copy link
Author

Hi,

Thanks for that, but I am afraid I still found a case that fails:

        let seqs = vec![
            "TCTTTCTTTCTTTCTTTCCTTTCCTTTCCTTTCCTTTCCTTCCTTTCCTTCCTTCCTTCCTTCCTTCCTTCCTCCCTCACTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCCCTCTCCCTCTCTCTCTCTCTCTCCCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCTCTCCTCTCTCTCCTCTCCTCTCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCTGCTCCCTCTCCTCTCCCTCTCCCTCCTCCTCCCTCTCCTCTCCCTCCCTCCTTTCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCCTCTCCTCTCCTCTCCCTCTCCCTCTCCCCTCTCCCTCTCCCTCCTCCCTCTCCTCTCCCTCTCCCTCTCCTCCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCCTCTCCCTCTCCCCTCTCCTCTCCTCTCCCCCTCTCCTCTCCTCTCCCTCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTTTCTTTCTTT".to_string(),
            "TTCTTTCCTTCCTTTCCTTTCTTTCCTTTCCTTCCTTCCTTTCCTTCCTTCCTTCCTTCCTTCCTTCCTCCCTCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCTCCCTCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCTCTCTCTCTCTCTCTCCCTCTCCCTCCCTCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCTCTCTCTCTCCCTCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCCCTCCCTCCCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCCTCCCTCTCTCTCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTTTCTTTCTTTCTTTCTTCCC".to_string(),
            "CTTTTCTTTCCTTTCCTTTCCTTTCCTTTCCTTTCCTTCCTTTCCTTCCTTCCTTCCTTCCTTCCTTCCCTCCCTCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCCTTTCTCCTCTCCCTCCCTCCCTCTCCCTCTCCCCCCTCCCTCTCCCTCCCTCTCCCTCTCTCCCTCTCTCTCCCTCCTCCTCTCCTCCCTCCCTCCTCTCCTCTCCCTCCTCCTCTCCTCTCCTCTCTCCTCCTCTCCCTCTCCTCTCCTCCCTCCTCTCCTCCTCCCTCTCCTCTCCTCCTCTCCTCTCCTCTCCTCTCCTCCTCTCCTCTCTCCCTCCTCTCCTCCCTCCTCCCTCCCTCCTCCTCTTCCCTCCTCTCCTCCTCCTCCTCCTCTCCTCTCCTCCTCCTCCCTCCCTCCTCTTCCTCTCTCCCTCTCCTTCTCCCTCTCTCTCCCTCCCTCCTCTCCTCCTCTCCCTCTCCTCCTCTCCCTCTCCTCTCCTCCTCCTCTCCTCTCCTCTCCTCTCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCCCTCTCCCTCTCCCTCTCTCTCCCTCCCTCTCCCTCCCTCTCCTCTCTCTCTCTCTCTTCTTTTTCTTTCTTTCCTCG".to_string(),
            "TCTTTCTTTCTTTCTTTTCCTTTCCTTTCCTTTCCTTTCCTTTCCTTCCTTTCCTTCCTTCCTTCCTTCCTTCCTTCCTCCCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCCCTCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCTCCCTCCCTCCCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCCCTCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTTTCTTTCTTT".to_string(),
            "TCTTTCTTTCCTTTCCTTTCCTTTCTTTCTCCTTCCTTCCTTCCTTCCTTCCTTCCTTCCTTCCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCTCCTCTCCCTCTCCTCTCCCTCTCTCTCTCCCTCTCCCTCTCCCTCCCTTCCTCCCTCTCCTCCTCCCTCTCTCTCCTCTCCCTCTCTCTCTCTCCCTCTCCCTCTCCCTCTCTCTCTCTCCCCTCTCCCTCTCCCTCCTCCCTCTCCCTCTCCTTCTCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCCTCCCTCTCCCTCTCCCTCTCCCTTCTCCCTCCTCTTCTCCTCTCCTCTCCTCTCCTCTCCCTCCTCCTCTCCTCCTCTCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCTCTCCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCTCTCCTCTCCCTCTCCCTCTCCCTCCTCCCTCTCCCTCTCCTCCCTCTCCCTCCTCCCTCTCCCTCTCCTCCTCCCTCCCTCCCTCCCTCTCCCCTCTCCCTCTCCCTCCCTCCCTCTCCTCTCCCTCTCCTCTCCTCTCCTCCTCCCTCTCCCTCCCTCCCTCTCTCCCTCTCTCTCTCTCTCTCTCTCTTTCTTTCTTTCTTTTTC".to_string(),
            "TCTTTCTTTCTTTCTTTCCTTTCCTTTCCTTTCTTTCCTTTCCTTCCTTTCCTTCCTTCCTTCCTTCCTTCCTTCCTCCCTCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCTCTCCTCTCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTTTCTTTCTTT".to_string(),
            "TCTTTCTTTCTTTCTTTCCTTTCCTTTCCTTTCCTTTCCTTTCCTTCCTTTTCCTTCCTTCCTTCCTTCCTTCCTTCCTCCCTCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCCCTCTCCCTCTCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCTCTCCCTCTCCCTCTCCCTCTTTCCCTCTCCCTCTCCCTCTCCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCCCTCTCCCTCTCCCTCCTCTCTCTCCCTCTCCCTCCTCCCTCTCCTCCTCCTCTCCCTTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTTCTCCCTCTCCCTCCTCTCCCTCTCCCTCTCTCTCCCTCTCCTCTCCCTCCCTCCCTTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCTCTCCCTCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTTTCTTTCTTT".to_string(),
            "TCTTCCTTTTCCTTCTTTCCTTTTCCTTTTCCTTCCTTCCTTCCTCCTTCCTTCCTTCCTTCCTCCCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCCCTCCCTCCCTCCCTCTCCCTCCCTTCTCCCTCTCCCTTCTTCCTTCCTTTTCTTCCTTTTTCTTCCTTCTTTCCTTCTTCCTTTCTTCTTTCTTTCCTTTCCTTTCTTTCTTTCTTTCTTCTTTTTCTTCTTTCTTTCTTTTTTCTTTCTTTCTTCCTTTTTTCTTTCTTTTTCTTTCCTTTTTCTTCTTTTTCTTTCTTTCTTTCTTCTTTTCTTTCTTTCTTTCTTTCTTTCCTTTTTCTTCCTTTCTTTCTTTCCTTTTTCTTTCTTTCTTCCTTCTTTCTTTCTTTCTTTCTTTTTCTTTCCTTCCTTTTCTTTCTTTCTTTCTTTCTTTCTTTCCTTTTTCTTCTTTCCTTCTCTCTTTTCTTCCTTTTTCCTTTCTTTCCTTCTTTTTCTTTCCTTTCTTTTTCTTCCTTTCTCTCTTTTTCTTTCTTTCCTTTTCTTTCCTTTCTCTCTTTCTTCCTTTTTCTTCCTTTTCTTTCTTCTTCTTTCTTTCCTTTTCTTTCCTTTCTTTCCTTTTTCTTCCTTTTCTTTCTTTCTTTCTTTCTTCCTTCTTTCTTTCCTTTCTTTCTTTCTTCTTTCTTTCCTTTCTTTCTTTCCTTTTTCTTCTTTCCTTCTTCTTTCCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTTTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTTTCTTCTTTCTTTCTTTCCTG".to_string(),
            "TCTTTCTTTCTTTCTTTGCTTTCCTTTCTTTCCTTTCCTTTCCTTTCCTTCCTTCCTTCTTCCTTCCTTCCCTTCCTCCCTCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCCCTCTCTCTGCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCCCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCCCTCCCTCCCTCTCTCTCCTCTCCCTCACCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCTCTCCCTCCCTCTCCCCTCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCCTCCTCCTCCCTCTCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCTCCCTCTCCCTCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTTTCTTTCTTT".to_string(),
            "TCTTTCTTTCTTTCTTTCCTTTCCTTTCCTTTCCTTTCCTTTCCTTCCTTTCCTTCCTTCCTTCCTTCCTTCCTTCCTCCCTCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCCCCTCTCCCTCTCCTCCTCCTCCTCTCCTCTCCTCTCCCTCTCCTCTCCTCTCCCTCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCCTCTCCCTCTCCTCTCCCTCTCCTCTCCTCTCCCTCTCCTCCTCTCCCTCTCCTCTCCCTCTCCTCTCCCCTCTCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCTCTCCTCTCCTCTCCCTCTCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTTTCTTTCTTT".to_string(),
            "TCTTTCTTTTCTTTCTTTCCTTTCCTTTCCTTTCTTTCCTTTCCTTCCTTTCCTTCCTTCCTTCCTTCCTTCCTTCCTCCCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCCCTCTCCCTCTCCCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCTCTCCCTCTCCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCTCTCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTTTCTTTTTCTTT".to_string(),
            "TCTTTCTTTCTTTCTGCTTTCCTTTCCTTTCCTTTCCTTTCCTTTCCTTCCTTTCCTTCCTTCCTTCCTTCCTTCCTTCCTCCCTCCTCTCTCTCTCTCTCTCTCTCTCTCTTTCCTCCTCCCTCCCTCCCTCCCTCTCCCTCCCTCTCCCTCCTCCCTCTCCCTCTCCCTCCTCTCCCTCCCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCTCTCCTCTCCCTCTCCCTCTCCTCTCCCTCCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCCCTCTCTCCCACCTCTCCCTCTCCCTCTCCCTCCCTCCCTCTCCTCTCCCTCTCCCTCCCTCCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCCTCTCCCCCTCTCCCTCTCCCTCTCCCTCCTCCCTCTCCCCTCTCCCCCACCCCTCTCCCCTCTCCCTCCCTCTCCCTCTCCCCTCTCCCTCTCCCTCTCCCTACTCCCTCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTTTCTTTCTTT".to_string(),
            "TCTTTCTTTCTTTCTTTCCTTCCTTTCCTTTTCCTTTCCTTTCCTTCCTTTCCTTCCTTCCTTCCTTCCTTCCTTCCTCCCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCCCTCTCCCTCCCTCTCTCCCTCCCTCTCCCTCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCTCCCTCCCTCTCCCTCTCCCTCTCTCTCCCTCCCTCTCCCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCTCTCTCTCTCTCCCTCTCCCTCTCTCCCTCCCTCCCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCTCTCCCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTTTCTTTCTTT".to_string(),
            "TCTTTCTTTCTTTCTTTCCTTTCCTTTCCTTTCCTTTCCTTTCCTTCCTTTCCTTCCTTCCTTCCTTCCTTCCTCCCTCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCCTCTCCTCTCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTTCTCCTCTCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCCTCTCCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCTCCCTCTCCCTCCTCTCCCTCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTTTCTTTCTTT".to_string(),
            "CTTTCTTTCTTTCTTTCTTTCCTTTCCTTTCCTTTCCTTTCCTTCCTTTCCTTCCTTCCTTCCTTCCTTCCTTCCTCCCTCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCCTCTCCCTCCTCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCTCCTCCCTCCCTCCCTCTCCCTCTCCCTCCTCCCTCTCCTCTCCTCTCCCTCTCCCTCTTTCCCTCTCCTCTCCCTCTCCTCTCCCTCTCCCCTCTCCCTCTCCTCTCCTCTCCCTCTCCTCTCCTCTCCCTCTCCTCTCCCTCTCCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCCCTCTCCTCTCCCTCTCCCTCTCCTCTCCCTCTCCTCTCCCTCTCCCTCTCCCCTCTCCCTCTCCCCTCTCCCTCTCCTCTCCTCTCCCTCTCCCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTTTCTTTCTTTTCTTTC".to_string(),        
                ];
        let mut seqs_bytes = vec![];
        for seq in seqs.iter() {
            seqs_bytes.push(seq.to_string().bytes().collect::<Vec<u8>>());
        }

        // I empirically determined the following parameters to be suitable,
        // but further testing on other repeats would be good
        // mainly have to make sure the consensus does not get longer than the individual insertions
        let scoring = Scoring::new(-12, -6, |a: u8, b: u8| if a == b { 3 } else { -4 });
        let mut aligner = Aligner::new(scoring, &seqs_bytes[0]);
        for seq in seqs_bytes.iter().skip(1) {
            aligner.global_banded(seq, 20).add_to_graph();
        }

        let consensus = aligner.consensus();
        let score = aligner.global_banded(&consensus, 20).alignment().score;


        println!("Consensus: {}", std::str::from_utf8(&consensus).unwrap());
        println!("Consensus score: {}", score);

resulting in thread 'consensus::tests::test_consensus_3' panicked at 'index out of bounds: the len is 0 but the index is 9', /home/wdecoster/.cargo/git/checkouts/rust-bio-36f8e3e6afd269e3/fab758d/src/alignment/poa.rs:186:21

@lorewar2
Copy link
Member

Hi,
In this case it seems the traceback goes into a undefined region,
banding is done in a very simple way in the poa code so it is possible for this to happen if traceback goes out of the band.
you could use unbanded poa (aligner.global) or increase the band size.

@wdecoster
Copy link
Author

Bingo! unbanded poa is doing fine. Thank you!

Side note, I see the alignment score aligner.global(&consensus).alignment().score; is often very negative, e.g. -858993459... probably not what it should be?

@wdecoster
Copy link
Author

I am afraid I found another one:

fn test_consensus_4() {
    let seqs = vec![
        "TTTCTTTCTTTCTTTCTTTCTT".to_string(),
        "TTTCTTTCTTTCTTTCTTTCTTTCTTTTTTTT".to_string(),
        "TTTCTTTCTTTCTTTCTTTCTTTCTTTTT".to_string(),
        "TTTCTTTCTTTCTTTCTTTCTT".to_string(),
        "TTTCTTTCTTTCTTTCTTTCTTTCTTT".to_string(),
        "ACTTCTTTCTTTCTTTCTTTCTTTCTTTT".to_string(),
        "TTTCTTTCTTTTCTTTCTTTCTTTCTT".to_string(),
        "TTTTCTTTCTTTCTTTCTTTCTTTCTTTT".to_string(),
        "TTTCTTTTCTTTCTTTCTTTCTTTCTTTTT".to_string(),
        "TTTCTTTCTTTTCTTTCTTTCTTTCTTT".to_string(),
        "TTTCTTTCTTTCTTTCTTTCTTTCT".to_string(),
        "TTTCTTTCTTTCTTTCTTTCTTTCTTTT".to_string(),
        "CTCTCTTTCTTTTCTTTCTTTCTTTTTCTTT".to_string(),
        "TTTCTTTCTTTCTTTCTTTCTT".to_string(),
        "TTTCTTTCTTTCTTTCTTTTCTTTCTTTT".to_string(),
        "TCGTTTCTTTCTTTCTTTCTTTCTTTCTTT".to_string(),
        "TTCTTTCTTTCTTTCTTTTTTTTTC".to_string(),
        "TTTCTTTCTTTCTTTCTTTCTTTCTT".to_string(),
        "TTTCTTTCTTTTTTTTCTTTCTTTCTTTCTTTT".to_string(),
        "TTTCTTTCTTTCTTTCTTTCTTTCTTTTT".to_string()];
    let mut seqs_bytes = vec![];
    for seq in seqs.iter() {
        seqs_bytes.push(seq.to_string().bytes().collect::<Vec<u8>>());
    }

    // I empirically determined the following parameters to be suitable,
    // but further testing on other repeats would be good
    // mainly have to make sure the consensus does not get longer than the individual insertions
    let scoring = Scoring::new(-12, -6, |a: u8, b: u8| if a == b { 3 } else { -4 });
    let mut aligner = Aligner::new(scoring, &seqs_bytes[0]);
    for seq in seqs_bytes.iter().skip(1) {
        aligner.global(seq).add_to_graph();
    }

    let consensus = aligner.consensus();
    let score = aligner.global(&consensus).alignment().score;
    
    println!("Consensus: {}", std::str::from_utf8(&consensus).unwrap());
    println!("Consensus score: {}", score);
}

resulting in

thread 'consensus::tests::test_consensus_4' panicked at 'index out of bounds: the len is 0 but the index is 0', /home/wdecoster/.cargo/git/checkouts/rust-bio-36f8e3e6afd269e3/fab758d/src/alignment/poa.rs:186:21
stack backtrace:
   0: rust_begin_unwind
             at /rustc/eb26296b556cef10fb713a38f3d16b9886080f26/library/std/src/panicking.rs:593:5
   1: core::panicking::panic_fmt
             at /rustc/eb26296b556cef10fb713a38f3d16b9886080f26/library/core/src/panicking.rs:67:14
   2: core::panicking::panic_bounds_check
             at /rustc/eb26296b556cef10fb713a38f3d16b9886080f26/library/core/src/panicking.rs:162:5
   3: <usize as core::slice::index::SliceIndex<[T]>>::index
             at /rustc/eb26296b556cef10fb713a38f3d16b9886080f26/library/core/src/slice/index.rs:258:10
   4: core::slice::index::<impl core::ops::index::Index<I> for [T]>::index
             at /rustc/eb26296b556cef10fb713a38f3d16b9886080f26/library/core/src/slice/index.rs:18:9
   5: <alloc::vec::Vec<T,A> as core::ops::index::Index<I>>::index
             at /rustc/eb26296b556cef10fb713a38f3d16b9886080f26/library/alloc/src/vec/mod.rs:2690:9
   6: bio::alignment::poa::Traceback::get
             at /home/wdecoster/.cargo/git/checkouts/rust-bio-36f8e3e6afd269e3/fab758d/src/alignment/poa.rs:186:21
   7: bio::alignment::poa::Traceback::alignment
             at /home/wdecoster/.cargo/git/checkouts/rust-bio-36f8e3e6afd269e3/fab758d/src/alignment/poa.rs:222:22
   8: bio::alignment::poa::Aligner<F>::add_to_graph
             at /home/wdecoster/.cargo/git/checkouts/rust-bio-36f8e3e6afd269e3/fab758d/src/alignment/poa.rs:279:25
   9: STRdust::consensus::tests::test_consensus_4
             at ./src/consensus.rs:316:9
  10: STRdust::consensus::tests::test_consensus_4::{{closure}}
             at ./src/consensus.rs:283:23
  11: core::ops::function::FnOnce::call_once
             at /rustc/eb26296b556cef10fb713a38f3d16b9886080f26/library/core/src/ops/function.rs:250:5
  12: core::ops::function::FnOnce::call_once
             at /rustc/eb26296b556cef10fb713a38f3d16b9886080f26/library/core/src/ops/function.rs:250:5

@lorewar2
Copy link
Member

This code ran without panic on my machine,
I made some changes to the fix, could you check it out poa_fixed?

@wdecoster
Copy link
Author

Everything seems fine now!

@wdecoster
Copy link
Author

I am very sorry, but I just found another example that results into an error:

    #[test]
    fn test_consensus_5(){
        let seqs = vec!["TATATATATATAAACATATATTATATATATAAAATATAACATATATAAACATATATATTATATATATA".to_string(),
            "TATATATATATAAACATATATTATATATGTAATATAAACATATATAAACATATATTATATATA".to_string(),
            "TATATATATATAAACATATATTATATATAATATAAACATATATAAACATATATTATATATATA".to_string(),
            "TATATATATATAAACATATATTATATATGTAATATAAACATATATAAACATATATTATATATATA".to_string(),
            "ATATATATAAACATATATTATATATGTAATATAAATATATATAAACATATATTTATATATATA".to_string(),
            "TATATATATATAAACATATATTATATATGTAATATAAACATATATGTATACATATATATACA".to_string(),
            "TATATATATATAAACATATATTATATATGTAATATAAATATATATAAACATATATTATATATATA".to_string(),
            "TATATATATATAAACATATATTATATATGTAATATAAACATATATAAACATATATTATATATATA".to_string(),
            "TATATATTTATAAACATATATTATGTATGTAATATAAACATATATAAACATATATTATATATA".to_string(),
            "TATATATATATAAACATATATTATATATATATAAACATATATAAACATATATTATATATATA".to_string(),
            "TATATATATATAAACATATATTCTATATATGTAATATAAACATATATAAACATATATTATCTATATA".to_string(),
            "TATATATATATAAACATATATTATATATAATATAAACATATAAACATATATTATATATATA".to_string(),
            "TATATATATATAAACATATATTATATATGTAATATAAACATATATAAACATATATTATATATATA".to_string(),
            "TATATATATATAAACATATATTATATATGTAATATGTTTTCTATATGTTGCTATATTATACAACATA".to_string(),
            "ATATATATATATAAACATATATTATATATGTAATATAAACATATATAAACATATATTATATATATATA".to_string(),
            "TATATATATATAAACATATATTATATATGTAATATAACATATATAAACATATATTATATATATA".to_string(),
            ];
        let mut seqs_bytes = vec![];
        for seq in seqs.iter() {
            seqs_bytes.push(seq.to_string().bytes().collect::<Vec<u8>>());
        }

        let scoring = Scoring::new(-12, -6, |a: u8, b: u8| if a == b { 3 } else { -4 });
        let mut aligner = Aligner::new(scoring, &seqs_bytes[0]);
        for seq in seqs_bytes.iter().skip(1) {
            aligner.global(seq).add_to_graph();
        }

        let consensus = aligner.consensus();
        let score = aligner.global(&consensus).alignment().score;
        
        println!("Consensus: {}", std::str::from_utf8(&consensus).unwrap());
        println!("Consensus score: {}", score);
}

Results in

thread 'consensus::tests::test_consensus_5' panicked at /home/wdecoster/.cargo/git/checkouts/rust-bio-36f8e3e6afd269e3/8cadb79/src/alignment/poa.rs:344:28:
index out of bounds: the len is 95 but the index is 95

@lorewar2
Copy link
Member

Thanks for pointing it out, there seems to be a reverse edge on the graph, I'll take a look but I'm not sure if I'll be able to fix it.
Screen Shot 2023-12-13 at 2 49 48 PM

@lorewar2
Copy link
Member

@wdecoster i made a fix for this reverse edge issue, could you test it out if possible? thanks. fix

@wdecoster
Copy link
Author

Thank you! Will do, but I will need some days, I am away for the weekend.

@lorewar2
Copy link
Member

There's no rush, thank you for your help.

@wdecoster
Copy link
Author

hi @lorewar2, this fixes the tests that used to fail and has (so far) not run into another error when testing more loci. So it seems to be fixed! Thank you!

@lorewar2
Copy link
Member

Great, thanks a lot. I think we can close this issue once the pull request gets merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants