@datagrok/sequence-translator 1.10.14 → 1.10.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,38 @@
1
+ id,target,status,length_s,length_as,sense_helm,antisense_helm,oligo_helm,tm_c,ic50_nm,kd_pct,off_target_count
2
+ siR-0001,KRAS,lead,19,19,RNA1{m(G)[sp].m(A)[sp].m(C)p.m(U)p.m(G)p.m(A)p.m(A)p.m(U)p.m(A)p.m(U)p.m(A)p.m(A)p.m(A)p.m(C)p.m(U)p.m(U)p.m(G)[sp].m(U)[sp].m(G).[L3]}$$$$,RNA1{m(C)[sp].m(A)[sp].m(C)p.m(A)p.m(A)p.m(G)p.m(U)p.m(U)p.m(U)p.m(A)p.m(U)p.m(A)p.m(U)p.m(U)p.m(C)p.m(A)p.m(G)[sp].m(U)[sp].m(C)}$$$$,RNA1{m(G)[sp].m(A)[sp].m(C)p.m(U)p.m(G)p.m(A)p.m(A)p.m(U)p.m(A)p.m(U)p.m(A)p.m(A)p.m(A)p.m(C)p.m(U)p.m(U)p.m(G)[sp].m(U)[sp].m(G).[L3]}|RNA2{m(C)[sp].m(A)[sp].m(C)p.m(A)p.m(A)p.m(G)p.m(U)p.m(U)p.m(U)p.m(A)p.m(U)p.m(A)p.m(U)p.m(U)p.m(C)p.m(A)p.m(G)[sp].m(U)[sp].m(C)}$$$$,76.9,0.29,99,7
3
+ siR-0002,KRAS,clinical,19,19,RNA1{[Chol].m(G)[sp].[fl2r](A)[sp].m(C)p.[fl2r](U)p.m(G)p.[fl2r](A)p.m(A)p.[fl2r](U)p.m(A)p.[fl2r](U)p.m(A)p.[fl2r](A)p.m(A)p.[fl2r](C)p.m(U)p.[fl2r](U)p.m(G)[sp].[fl2r](U)[sp].m(G).[L3]}$$$$,RNA1{m(C)[sp].[fl2r](A)[sp].m(C)p.[fl2r](A)p.m(A)p.[fl2r](G)p.m(U)p.[fl2r](U)p.m(U)p.[fl2r](A)p.m(U)p.[fl2r](A)p.m(U)p.[fl2r](U)p.m(C)p.[fl2r](A)p.m(G)[sp].[fl2r](U)[sp].m(C)}$$$$,RNA1{[Chol].m(G)[sp].[fl2r](A)[sp].m(C)p.[fl2r](U)p.m(G)p.[fl2r](A)p.m(A)p.[fl2r](U)p.m(A)p.[fl2r](U)p.m(A)p.[fl2r](A)p.m(A)p.[fl2r](C)p.m(U)p.[fl2r](U)p.m(G)[sp].[fl2r](U)[sp].m(G).[L3]}|RNA2{m(C)[sp].[fl2r](A)[sp].m(C)p.[fl2r](A)p.m(A)p.[fl2r](G)p.m(U)p.[fl2r](U)p.m(U)p.[fl2r](A)p.m(U)p.[fl2r](A)p.m(U)p.[fl2r](U)p.m(C)p.[fl2r](A)p.m(G)[sp].[fl2r](U)[sp].m(C)}$$$$,83.8,0.28,99,7
4
+ siR-0003,KRAS,parent,19,19,RNA1{r(G)p.r(A)p.r(C)p.r(U)p.r(G)p.r(A)p.r(A)p.r(U)p.r(A)p.r(U)p.r(A)p.r(A)p.r(A)p.r(C)p.r(U)p.r(U)p.r(G)p.r(U)p.r(G)}$$$$,RNA1{r(C)p.r(A)p.r(C)p.r(A)p.r(A)p.r(G)p.r(U)p.r(U)p.r(U)p.r(A)p.r(U)p.r(A)p.r(U)p.r(U)p.r(C)p.r(A)p.r(G)p.r(U)p.r(C)}$$$$,RNA1{r(G)p.r(A)p.r(C)p.r(U)p.r(G)p.r(A)p.r(A)p.r(U)p.r(A)p.r(U)p.r(A)p.r(A)p.r(A)p.r(C)p.r(U)p.r(U)p.r(G)p.r(U)p.r(G)}|RNA2{r(C)p.r(A)p.r(C)p.r(A)p.r(A)p.r(G)p.r(U)p.r(U)p.r(U)p.r(A)p.r(U)p.r(A)p.r(U)p.r(U)p.r(C)p.r(A)p.r(G)p.r(U)p.r(C)}$$$$,59.6,0.17,65,4
5
+ siR-0004,PCSK9,lead,19,19,RNA1{m(U)[sp].m(C)[sp].m(A)p.m(G)p.m(G)p.m(A)p.m(C)p.m(A)p.m(U)p.m(G)p.m(G)p.m(A)p.m(A)p.m(G)p.m(C)p.m(U)p.m(G)[sp].m(A)[sp].m(A).[L3]}$$$$,RNA1{m(U)[sp].m(U)[sp].m(C)p.m(A)p.m(G)p.m(C)p.m(U)p.m(U)p.m(C)p.m(C)p.m(A)p.m(U)p.m(G)p.m(U)p.m(C)p.m(C)p.m(U)[sp].m(G)[sp].m(A)}$$$$,RNA1{m(U)[sp].m(C)[sp].m(A)p.m(G)p.m(G)p.m(A)p.m(C)p.m(A)p.m(U)p.m(G)p.m(G)p.m(A)p.m(A)p.m(G)p.m(C)p.m(U)p.m(G)[sp].m(A)[sp].m(A).[L3]}|RNA2{m(U)[sp].m(U)[sp].m(C)p.m(A)p.m(G)p.m(C)p.m(U)p.m(U)p.m(C)p.m(C)p.m(A)p.m(U)p.m(G)p.m(U)p.m(C)p.m(C)p.m(U)[sp].m(G)[sp].m(A)}$$$$,79,0.38,99,10
6
+ siR-0005,PCSK9,clinical,19,19,RNA1{[Chol].m(U)[sp].[fl2r](C)[sp].m(A)p.[fl2r](G)p.m(G)p.[fl2r](A)p.m(C)p.[fl2r](A)p.m(U)p.[fl2r](G)p.m(G)p.[fl2r](A)p.m(A)p.[fl2r](G)p.m(C)p.[fl2r](U)p.m(G)[sp].[fl2r](A)[sp].m(A).[L3]}$$$$,RNA1{m(U)[sp].[fl2r](U)[sp].m(C)p.[fl2r](A)p.m(G)p.[fl2r](C)p.m(U)p.[fl2r](U)p.m(C)p.[fl2r](C)p.m(A)p.[fl2r](U)p.m(G)p.[fl2r](U)p.m(C)p.[fl2r](C)p.m(U)[sp].[fl2r](G)[sp].m(A)}$$$$,RNA1{[Chol].m(U)[sp].[fl2r](C)[sp].m(A)p.[fl2r](G)p.m(G)p.[fl2r](A)p.m(C)p.[fl2r](A)p.m(U)p.[fl2r](G)p.m(G)p.[fl2r](A)p.m(A)p.[fl2r](G)p.m(C)p.[fl2r](U)p.m(G)[sp].[fl2r](A)[sp].m(A).[L3]}|RNA2{m(U)[sp].[fl2r](U)[sp].m(C)p.[fl2r](A)p.m(G)p.[fl2r](C)p.m(U)p.[fl2r](U)p.m(C)p.[fl2r](C)p.m(A)p.[fl2r](U)p.m(G)p.[fl2r](U)p.m(C)p.[fl2r](C)p.m(U)[sp].[fl2r](G)[sp].m(A)}$$$$,82.1,0.23,99,5
7
+ siR-0006,PCSK9,parent,19,19,RNA1{r(U)p.r(C)p.r(A)p.r(G)p.r(G)p.r(A)p.r(C)p.r(A)p.r(U)p.r(G)p.r(G)p.r(A)p.r(A)p.r(G)p.r(C)p.r(U)p.r(G)p.r(A)p.r(A)}$$$$,RNA1{r(U)p.r(U)p.r(C)p.r(A)p.r(G)p.r(C)p.r(U)p.r(U)p.r(C)p.r(C)p.r(A)p.r(U)p.r(G)p.r(U)p.r(C)p.r(C)p.r(U)p.r(G)p.r(A)}$$$$,RNA1{r(U)p.r(C)p.r(A)p.r(G)p.r(G)p.r(A)p.r(C)p.r(A)p.r(U)p.r(G)p.r(G)p.r(A)p.r(A)p.r(G)p.r(C)p.r(U)p.r(G)p.r(A)p.r(A)}|RNA2{r(U)p.r(U)p.r(C)p.r(A)p.r(G)p.r(C)p.r(U)p.r(U)p.r(C)p.r(C)p.r(A)p.r(U)p.r(G)p.r(U)p.r(C)p.r(C)p.r(U)p.r(G)p.r(A)}$$$$,64.8,0.56,81,15
8
+ siR-0007,TTR,lead,19,19,RNA1{m(A)[sp].m(U)[sp].m(U)p.m(G)p.m(G)p.m(G)p.m(A)p.m(U)p.m(U)p.m(U)p.m(C)p.m(A)p.m(U)p.m(G)p.m(A)p.m(G)p.m(A)[sp].m(A)[sp].m(U).[L3]}$$$$,RNA1{m(A)[sp].m(U)[sp].m(U)p.m(C)p.m(U)p.m(C)p.m(A)p.m(U)p.m(G)p.m(A)p.m(A)p.m(A)p.m(U)p.m(C)p.m(C)p.m(C)p.m(A)[sp].m(A)[sp].m(U)}$$$$,RNA1{m(A)[sp].m(U)[sp].m(U)p.m(G)p.m(G)p.m(G)p.m(A)p.m(U)p.m(U)p.m(U)p.m(C)p.m(A)p.m(U)p.m(G)p.m(A)p.m(G)p.m(A)[sp].m(A)[sp].m(U).[L3]}|RNA2{m(A)[sp].m(U)[sp].m(U)p.m(C)p.m(U)p.m(C)p.m(A)p.m(U)p.m(G)p.m(A)p.m(A)p.m(A)p.m(U)p.m(C)p.m(C)p.m(C)p.m(A)[sp].m(A)[sp].m(U)}$$$$,78.1,0.34,99,9
9
+ siR-0008,TTR,clinical,19,19,RNA1{[Chol].m(A)[sp].[fl2r](U)[sp].m(U)p.[fl2r](G)p.m(G)p.[fl2r](G)p.m(A)p.[fl2r](U)p.m(U)p.[fl2r](U)p.m(C)p.[fl2r](A)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](G)p.m(A)[sp].[fl2r](A)[sp].m(U).[L3]}$$$$,RNA1{m(A)[sp].[fl2r](U)[sp].m(U)p.[fl2r](C)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](U)p.m(G)p.[fl2r](A)p.m(A)p.[fl2r](A)p.m(U)p.[fl2r](C)p.m(C)p.[fl2r](C)p.m(A)[sp].[fl2r](A)[sp].m(U)}$$$$,RNA1{[Chol].m(A)[sp].[fl2r](U)[sp].m(U)p.[fl2r](G)p.m(G)p.[fl2r](G)p.m(A)p.[fl2r](U)p.m(U)p.[fl2r](U)p.m(C)p.[fl2r](A)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](G)p.m(A)[sp].[fl2r](A)[sp].m(U).[L3]}|RNA2{m(A)[sp].[fl2r](U)[sp].m(U)p.[fl2r](C)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](U)p.m(G)p.[fl2r](A)p.m(A)p.[fl2r](A)p.m(U)p.[fl2r](C)p.m(C)p.[fl2r](C)p.m(A)[sp].[fl2r](A)[sp].m(U)}$$$$,80.7,0.19,99,4
10
+ siR-0009,TTR,parent,19,19,RNA1{r(A)p.r(U)p.r(U)p.r(G)p.r(G)p.r(G)p.r(A)p.r(U)p.r(U)p.r(U)p.r(C)p.r(A)p.r(U)p.r(G)p.r(A)p.r(G)p.r(A)p.r(A)p.r(U)}$$$$,RNA1{r(A)p.r(U)p.r(U)p.r(C)p.r(U)p.r(C)p.r(A)p.r(U)p.r(G)p.r(A)p.r(A)p.r(A)p.r(U)p.r(C)p.r(C)p.r(C)p.r(A)p.r(A)p.r(U)}$$$$,RNA1{r(A)p.r(U)p.r(U)p.r(G)p.r(G)p.r(G)p.r(A)p.r(U)p.r(U)p.r(U)p.r(C)p.r(A)p.r(U)p.r(G)p.r(A)p.r(G)p.r(A)p.r(A)p.r(U)}|RNA2{r(A)p.r(U)p.r(U)p.r(C)p.r(U)p.r(C)p.r(A)p.r(U)p.r(G)p.r(A)p.r(A)p.r(A)p.r(U)p.r(C)p.r(C)p.r(C)p.r(A)p.r(A)p.r(U)}$$$$,59.5,0.16,65,3
11
+ siR-0010,APOC3,lead,19,19,RNA1{m(A)[sp].m(U)[sp].m(C)p.m(A)p.m(G)p.m(U)p.m(A)p.m(C)p.m(G)p.m(U)p.m(U)p.m(G)p.m(U)p.m(C)p.m(A)p.m(A)p.m(C)[sp].m(G)[sp].m(G).[L3]}$$$$,RNA1{m(C)[sp].m(C)[sp].m(G)p.m(U)p.m(U)p.m(G)p.m(A)p.m(C)p.m(A)p.m(A)p.m(C)p.m(G)p.m(U)p.m(A)p.m(C)p.m(U)p.m(G)[sp].m(A)[sp].m(U)}$$$$,RNA1{m(A)[sp].m(U)[sp].m(C)p.m(A)p.m(G)p.m(U)p.m(A)p.m(C)p.m(G)p.m(U)p.m(U)p.m(G)p.m(U)p.m(C)p.m(A)p.m(A)p.m(C)[sp].m(G)[sp].m(G).[L3]}|RNA2{m(C)[sp].m(C)[sp].m(G)p.m(U)p.m(U)p.m(G)p.m(A)p.m(C)p.m(A)p.m(A)p.m(C)p.m(G)p.m(U)p.m(A)p.m(C)p.m(U)p.m(G)[sp].m(A)[sp].m(U)}$$$$,77.5,0.32,99,8
12
+ siR-0011,APOC3,clinical,19,19,RNA1{[Chol].m(A)[sp].[fl2r](U)[sp].m(C)p.[fl2r](A)p.m(G)p.[fl2r](U)p.m(A)p.[fl2r](C)p.m(G)p.[fl2r](U)p.m(U)p.[fl2r](G)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](A)p.m(C)[sp].[fl2r](G)[sp].m(G).[L3]}$$$$,RNA1{m(C)[sp].[fl2r](C)[sp].m(G)p.[fl2r](U)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](C)p.m(A)p.[fl2r](A)p.m(C)p.[fl2r](G)p.m(U)p.[fl2r](A)p.m(C)p.[fl2r](U)p.m(G)[sp].[fl2r](A)[sp].m(U)}$$$$,RNA1{[Chol].m(A)[sp].[fl2r](U)[sp].m(C)p.[fl2r](A)p.m(G)p.[fl2r](U)p.m(A)p.[fl2r](C)p.m(G)p.[fl2r](U)p.m(U)p.[fl2r](G)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](A)p.m(C)[sp].[fl2r](G)[sp].m(G).[L3]}|RNA2{m(C)[sp].[fl2r](C)[sp].m(G)p.[fl2r](U)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](C)p.m(A)p.[fl2r](A)p.m(C)p.[fl2r](G)p.m(U)p.[fl2r](A)p.m(C)p.[fl2r](U)p.m(G)[sp].[fl2r](A)[sp].m(U)}$$$$,76.8,0.07,92,1
13
+ siR-0012,APOC3,parent,19,19,RNA1{r(A)p.r(U)p.r(C)p.r(A)p.r(G)p.r(U)p.r(A)p.r(C)p.r(G)p.r(U)p.r(U)p.r(G)p.r(U)p.r(C)p.r(A)p.r(A)p.r(C)p.r(G)p.r(G)}$$$$,RNA1{r(C)p.r(C)p.r(G)p.r(U)p.r(U)p.r(G)p.r(A)p.r(C)p.r(A)p.r(A)p.r(C)p.r(G)p.r(U)p.r(A)p.r(C)p.r(U)p.r(G)p.r(A)p.r(U)}$$$$,RNA1{r(A)p.r(U)p.r(C)p.r(A)p.r(G)p.r(U)p.r(A)p.r(C)p.r(G)p.r(U)p.r(U)p.r(G)p.r(U)p.r(C)p.r(A)p.r(A)p.r(C)p.r(G)p.r(G)}|RNA2{r(C)p.r(C)p.r(G)p.r(U)p.r(U)p.r(G)p.r(A)p.r(C)p.r(A)p.r(A)p.r(C)p.r(G)p.r(U)p.r(A)p.r(C)p.r(U)p.r(G)p.r(A)p.r(U)}$$$$,60.2,0.21,67,5
14
+ siR-0013,ANGPTL3,lead,19,19,RNA1{m(G)[sp].m(A)[sp].m(A)p.m(C)p.m(U)p.m(C)p.m(U)p.m(G)p.m(A)p.m(U)p.m(G)p.m(A)p.m(G)p.m(G)p.m(C)p.m(A)p.m(U)[sp].m(U)[sp].m(C).[L3]}$$$$,RNA1{m(G)[sp].m(A)[sp].m(A)p.m(U)p.m(G)p.m(C)p.m(C)p.m(U)p.m(C)p.m(A)p.m(U)p.m(C)p.m(A)p.m(G)p.m(A)p.m(G)p.m(U)[sp].m(U)[sp].m(C)}$$$$,RNA1{m(G)[sp].m(A)[sp].m(A)p.m(C)p.m(U)p.m(C)p.m(U)p.m(G)p.m(A)p.m(U)p.m(G)p.m(A)p.m(G)p.m(G)p.m(C)p.m(A)p.m(U)[sp].m(U)[sp].m(C).[L3]}|RNA2{m(G)[sp].m(A)[sp].m(A)p.m(U)p.m(G)p.m(C)p.m(C)p.m(U)p.m(C)p.m(A)p.m(U)p.m(C)p.m(A)p.m(G)p.m(A)p.m(G)p.m(U)[sp].m(U)[sp].m(C)}$$$$,76.6,0.28,99,7
15
+ siR-0014,ANGPTL3,clinical,19,19,RNA1{[Chol].m(G)[sp].[fl2r](A)[sp].m(A)p.[fl2r](C)p.m(U)p.[fl2r](C)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](U)p.m(G)p.[fl2r](A)p.m(G)p.[fl2r](G)p.m(C)p.[fl2r](A)p.m(U)[sp].[fl2r](U)[sp].m(C).[L3]}$$$$,RNA1{m(G)[sp].[fl2r](A)[sp].m(A)p.[fl2r](U)p.m(G)p.[fl2r](C)p.m(C)p.[fl2r](U)p.m(C)p.[fl2r](A)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](G)p.m(A)p.[fl2r](G)p.m(U)[sp].[fl2r](U)[sp].m(C)}$$$$,RNA1{[Chol].m(G)[sp].[fl2r](A)[sp].m(A)p.[fl2r](C)p.m(U)p.[fl2r](C)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](U)p.m(G)p.[fl2r](A)p.m(G)p.[fl2r](G)p.m(C)p.[fl2r](A)p.m(U)[sp].[fl2r](U)[sp].m(C).[L3]}|RNA2{m(G)[sp].[fl2r](A)[sp].m(A)p.[fl2r](U)p.m(G)p.[fl2r](C)p.m(C)p.[fl2r](U)p.m(C)p.[fl2r](A)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](G)p.m(A)p.[fl2r](G)p.m(U)[sp].[fl2r](U)[sp].m(C)}$$$$,76.6,0.07,92,1
16
+ siR-0015,ANGPTL3,parent,19,19,RNA1{r(G)p.r(A)p.r(A)p.r(C)p.r(U)p.r(C)p.r(U)p.r(G)p.r(A)p.r(U)p.r(G)p.r(A)p.r(G)p.r(G)p.r(C)p.r(A)p.r(U)p.r(U)p.r(C)}$$$$,RNA1{r(G)p.r(A)p.r(A)p.r(U)p.r(G)p.r(C)p.r(C)p.r(U)p.r(C)p.r(A)p.r(U)p.r(C)p.r(A)p.r(G)p.r(A)p.r(G)p.r(U)p.r(U)p.r(C)}$$$$,RNA1{r(G)p.r(A)p.r(A)p.r(C)p.r(U)p.r(C)p.r(U)p.r(G)p.r(A)p.r(U)p.r(G)p.r(A)p.r(G)p.r(G)p.r(C)p.r(A)p.r(U)p.r(U)p.r(C)}|RNA2{r(G)p.r(A)p.r(A)p.r(U)p.r(G)p.r(C)p.r(C)p.r(U)p.r(C)p.r(A)p.r(U)p.r(C)p.r(A)p.r(G)p.r(A)p.r(G)p.r(U)p.r(U)p.r(C)}$$$$,65,0.58,82,16
17
+ siR-0016,HBV,lead,19,19,RNA1{m(G)[sp].m(G)[sp].m(A)p.m(A)p.m(C)p.m(U)p.m(C)p.m(U)p.m(U)p.m(U)p.m(A)p.m(C)p.m(A)p.m(U)p.m(G)p.m(C)p.m(U)[sp].m(G)[sp].m(U).[L3]}$$$$,RNA1{m(A)[sp].m(C)[sp].m(A)p.m(G)p.m(C)p.m(A)p.m(U)p.m(G)p.m(U)p.m(A)p.m(A)p.m(A)p.m(G)p.m(A)p.m(G)p.m(U)p.m(U)[sp].m(C)[sp].m(C)}$$$$,RNA1{m(G)[sp].m(G)[sp].m(A)p.m(A)p.m(C)p.m(U)p.m(C)p.m(U)p.m(U)p.m(U)p.m(A)p.m(C)p.m(A)p.m(U)p.m(G)p.m(C)p.m(U)[sp].m(G)[sp].m(U).[L3]}|RNA2{m(A)[sp].m(C)[sp].m(A)p.m(G)p.m(C)p.m(A)p.m(U)p.m(G)p.m(U)p.m(A)p.m(A)p.m(A)p.m(G)p.m(A)p.m(G)p.m(U)p.m(U)[sp].m(C)[sp].m(C)}$$$$,78.9,0.37,99,10
18
+ siR-0017,HBV,clinical,19,19,RNA1{[Chol].m(G)[sp].[fl2r](G)[sp].m(A)p.[fl2r](A)p.m(C)p.[fl2r](U)p.m(C)p.[fl2r](U)p.m(U)p.[fl2r](U)p.m(A)p.[fl2r](C)p.m(A)p.[fl2r](U)p.m(G)p.[fl2r](C)p.m(U)[sp].[fl2r](G)[sp].m(U).[L3]}$$$$,RNA1{m(A)[sp].[fl2r](C)[sp].m(A)p.[fl2r](G)p.m(C)p.[fl2r](A)p.m(U)p.[fl2r](G)p.m(U)p.[fl2r](A)p.m(A)p.[fl2r](A)p.m(G)p.[fl2r](A)p.m(G)p.[fl2r](U)p.m(U)[sp].[fl2r](C)[sp].m(C)}$$$$,RNA1{[Chol].m(G)[sp].[fl2r](G)[sp].m(A)p.[fl2r](A)p.m(C)p.[fl2r](U)p.m(C)p.[fl2r](U)p.m(U)p.[fl2r](U)p.m(A)p.[fl2r](C)p.m(A)p.[fl2r](U)p.m(G)p.[fl2r](C)p.m(U)[sp].[fl2r](G)[sp].m(U).[L3]}|RNA2{m(A)[sp].[fl2r](C)[sp].m(A)p.[fl2r](G)p.m(C)p.[fl2r](A)p.m(U)p.[fl2r](G)p.m(U)p.[fl2r](A)p.m(A)p.[fl2r](A)p.m(G)p.[fl2r](A)p.m(G)p.[fl2r](U)p.m(U)[sp].[fl2r](C)[sp].m(C)}$$$$,76.2,0.06,91,0
19
+ siR-0018,HBV,parent,19,19,RNA1{r(G)p.r(G)p.r(A)p.r(A)p.r(C)p.r(U)p.r(C)p.r(U)p.r(U)p.r(U)p.r(A)p.r(C)p.r(A)p.r(U)p.r(G)p.r(C)p.r(U)p.r(G)p.r(U)}$$$$,RNA1{r(A)p.r(C)p.r(A)p.r(G)p.r(C)p.r(A)p.r(U)p.r(G)p.r(U)p.r(A)p.r(A)p.r(A)p.r(G)p.r(A)p.r(G)p.r(U)p.r(U)p.r(C)p.r(C)}$$$$,RNA1{r(G)p.r(G)p.r(A)p.r(A)p.r(C)p.r(U)p.r(C)p.r(U)p.r(U)p.r(U)p.r(A)p.r(C)p.r(A)p.r(U)p.r(G)p.r(C)p.r(U)p.r(G)p.r(U)}|RNA2{r(A)p.r(C)p.r(A)p.r(G)p.r(C)p.r(A)p.r(U)p.r(G)p.r(U)p.r(A)p.r(A)p.r(A)p.r(G)p.r(A)p.r(G)p.r(U)p.r(U)p.r(C)p.r(C)}$$$$,59,0.13,63,2
20
+ siR-0019,HSD17B13,lead,19,19,RNA1{m(C)[sp].m(A)[sp].m(U)p.m(G)p.m(G)p.m(U)p.m(U)p.m(G)p.m(A)p.m(A)p.m(C)p.m(A)p.m(U)p.m(G)p.m(A)p.m(G)p.m(C)[sp].m(A)[sp].m(A).[L3]}$$$$,RNA1{m(U)[sp].m(U)[sp].m(G)p.m(C)p.m(U)p.m(C)p.m(A)p.m(U)p.m(G)p.m(U)p.m(U)p.m(C)p.m(A)p.m(A)p.m(C)p.m(C)p.m(A)[sp].m(U)[sp].m(G)}$$$$,RNA1{m(C)[sp].m(A)[sp].m(U)p.m(G)p.m(G)p.m(U)p.m(U)p.m(G)p.m(A)p.m(A)p.m(C)p.m(A)p.m(U)p.m(G)p.m(A)p.m(G)p.m(C)[sp].m(A)[sp].m(A).[L3]}|RNA2{m(U)[sp].m(U)[sp].m(G)p.m(C)p.m(U)p.m(C)p.m(A)p.m(U)p.m(G)p.m(U)p.m(U)p.m(C)p.m(A)p.m(A)p.m(C)p.m(C)p.m(A)[sp].m(U)[sp].m(G)}$$$$,77.4,0.31,99,8
21
+ siR-0020,HSD17B13,clinical,19,19,RNA1{[Chol].m(C)[sp].[fl2r](A)[sp].m(U)p.[fl2r](G)p.m(G)p.[fl2r](U)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](A)p.m(C)p.[fl2r](A)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](G)p.m(C)[sp].[fl2r](A)[sp].m(A).[L3]}$$$$,RNA1{m(U)[sp].[fl2r](U)[sp].m(G)p.[fl2r](C)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](U)p.m(G)p.[fl2r](U)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](A)p.m(C)p.[fl2r](C)p.m(A)[sp].[fl2r](U)[sp].m(G)}$$$$,RNA1{[Chol].m(C)[sp].[fl2r](A)[sp].m(U)p.[fl2r](G)p.m(G)p.[fl2r](U)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](A)p.m(C)p.[fl2r](A)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](G)p.m(C)[sp].[fl2r](A)[sp].m(A).[L3]}|RNA2{m(U)[sp].[fl2r](U)[sp].m(G)p.[fl2r](C)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](U)p.m(G)p.[fl2r](U)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](A)p.m(C)p.[fl2r](C)p.m(A)[sp].[fl2r](U)[sp].m(G)}$$$$,79.6,0.16,99,3
22
+ siR-0021,HSD17B13,parent,19,19,RNA1{r(C)p.r(A)p.r(U)p.r(G)p.r(G)p.r(U)p.r(U)p.r(G)p.r(A)p.r(A)p.r(C)p.r(A)p.r(U)p.r(G)p.r(A)p.r(G)p.r(C)p.r(A)p.r(A)}$$$$,RNA1{r(U)p.r(U)p.r(G)p.r(C)p.r(U)p.r(C)p.r(A)p.r(U)p.r(G)p.r(U)p.r(U)p.r(C)p.r(A)p.r(A)p.r(C)p.r(C)p.r(A)p.r(U)p.r(G)}$$$$,RNA1{r(C)p.r(A)p.r(U)p.r(G)p.r(G)p.r(U)p.r(U)p.r(G)p.r(A)p.r(A)p.r(C)p.r(A)p.r(U)p.r(G)p.r(A)p.r(G)p.r(C)p.r(A)p.r(A)}|RNA2{r(U)p.r(U)p.r(G)p.r(C)p.r(U)p.r(C)p.r(A)p.r(U)p.r(G)p.r(U)p.r(U)p.r(C)p.r(A)p.r(A)p.r(C)p.r(C)p.r(A)p.r(U)p.r(G)}$$$$,62.5,0.38,74,10
23
+ siR-0022,AGT,lead,19,19,RNA1{m(A)[sp].m(A)[sp].m(A)p.m(C)p.m(U)p.m(A)p.m(C)p.m(G)p.m(U)p.m(G)p.m(G)p.m(U)p.m(U)p.m(C)p.m(A)p.m(U)p.m(G)[sp].m(G)[sp].m(C).[L3]}$$$$,RNA1{m(G)[sp].m(C)[sp].m(C)p.m(A)p.m(U)p.m(G)p.m(A)p.m(A)p.m(C)p.m(C)p.m(A)p.m(C)p.m(G)p.m(U)p.m(A)p.m(G)p.m(U)[sp].m(U)[sp].m(U)}$$$$,RNA1{m(A)[sp].m(A)[sp].m(A)p.m(C)p.m(U)p.m(A)p.m(C)p.m(G)p.m(U)p.m(G)p.m(G)p.m(U)p.m(U)p.m(C)p.m(A)p.m(U)p.m(G)[sp].m(G)[sp].m(C).[L3]}|RNA2{m(G)[sp].m(C)[sp].m(C)p.m(A)p.m(U)p.m(G)p.m(A)p.m(A)p.m(C)p.m(C)p.m(A)p.m(C)p.m(G)p.m(U)p.m(A)p.m(G)p.m(U)[sp].m(U)[sp].m(U)}$$$$,75.1,0.21,94,5
24
+ siR-0023,AGT,clinical,19,19,RNA1{[Chol].m(A)[sp].[fl2r](A)[sp].m(A)p.[fl2r](C)p.m(U)p.[fl2r](A)p.m(C)p.[fl2r](G)p.m(U)p.[fl2r](G)p.m(G)p.[fl2r](U)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](U)p.m(G)[sp].[fl2r](G)[sp].m(C).[L3]}$$$$,RNA1{m(G)[sp].[fl2r](C)[sp].m(C)p.[fl2r](A)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](A)p.m(C)p.[fl2r](C)p.m(A)p.[fl2r](C)p.m(G)p.[fl2r](U)p.m(A)p.[fl2r](G)p.m(U)[sp].[fl2r](U)[sp].m(U)}$$$$,RNA1{[Chol].m(A)[sp].[fl2r](A)[sp].m(A)p.[fl2r](C)p.m(U)p.[fl2r](A)p.m(C)p.[fl2r](G)p.m(U)p.[fl2r](G)p.m(G)p.[fl2r](U)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](U)p.m(G)[sp].[fl2r](G)[sp].m(C).[L3]}|RNA2{m(G)[sp].[fl2r](C)[sp].m(C)p.[fl2r](A)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](A)p.m(C)p.[fl2r](C)p.m(A)p.[fl2r](C)p.m(G)p.[fl2r](U)p.m(A)p.[fl2r](G)p.m(U)[sp].[fl2r](U)[sp].m(U)}$$$$,82.4,0.24,99,6
25
+ siR-0024,AGT,parent,19,19,RNA1{r(A)p.r(A)p.r(A)p.r(C)p.r(U)p.r(A)p.r(C)p.r(G)p.r(U)p.r(G)p.r(G)p.r(U)p.r(U)p.r(C)p.r(A)p.r(U)p.r(G)p.r(G)p.r(C)}$$$$,RNA1{r(G)p.r(C)p.r(C)p.r(A)p.r(U)p.r(G)p.r(A)p.r(A)p.r(C)p.r(C)p.r(A)p.r(C)p.r(G)p.r(U)p.r(A)p.r(G)p.r(U)p.r(U)p.r(U)}$$$$,RNA1{r(A)p.r(A)p.r(A)p.r(C)p.r(U)p.r(A)p.r(C)p.r(G)p.r(U)p.r(G)p.r(G)p.r(U)p.r(U)p.r(C)p.r(A)p.r(U)p.r(G)p.r(G)p.r(C)}|RNA2{r(G)p.r(C)p.r(C)p.r(A)p.r(U)p.r(G)p.r(A)p.r(A)p.r(C)p.r(C)p.r(A)p.r(C)p.r(G)p.r(U)p.r(A)p.r(G)p.r(U)p.r(U)p.r(U)}$$$$,59.7,0.18,65,4
26
+ siR-0025,KRAS,backup,19,19,RNA1{[Chol].m(G)[sp].[fl2r](A)[sp].m(C)p.[fl2r](U)p.m(G)p.[fl2r](A)p.m(A)p.[fl2r](U)p.m(A)p.[fl2r](U)p.m(A)p.[fl2r](A)p.m(A)p.[fl2r](C)p.m(U)p.[fl2r](U)p.m(G)[sp].[fl2r](U)[sp].m(G)}$$$$,RNA1{m(C)[sp].[fl2r](A)[sp].m(C)p.[fl2r](A)p.m(A)p.[fl2r](G)p.m(U)p.[fl2r](U)p.m(U)p.[fl2r](A)p.m(U)p.[fl2r](A)p.m(U)p.[fl2r](U)p.m(C)p.[fl2r](A)p.m(G)[sp].[fl2r](U)[sp].m(C)}$$$$,RNA1{[Chol].m(G)[sp].[fl2r](A)[sp].m(C)p.[fl2r](U)p.m(G)p.[fl2r](A)p.m(A)p.[fl2r](U)p.m(A)p.[fl2r](U)p.m(A)p.[fl2r](A)p.m(A)p.[fl2r](C)p.m(U)p.[fl2r](U)p.m(G)[sp].[fl2r](U)[sp].m(G)}|RNA2{m(C)[sp].[fl2r](A)[sp].m(C)p.[fl2r](A)p.m(A)p.[fl2r](G)p.m(U)p.[fl2r](U)p.m(U)p.[fl2r](A)p.m(U)p.[fl2r](A)p.m(U)p.[fl2r](U)p.m(C)p.[fl2r](A)p.m(G)[sp].[fl2r](U)[sp].m(C)}$$$$,72.7,0.24,90,6
27
+ siR-0026,PCSK9,backup,19,19,RNA1{[Chol].m(U)[sp].m(C)[sp].m(A)p.m(G)p.m(G)p.m(A)p.m(C)p.m(A)p.m(U)p.m(G)p.m(G)p.m(A)p.m(A)p.m(G)p.m(C)p.m(U)p.m(G)[sp].m(A)[sp].m(A)}$$$$,RNA1{m(U)[sp].m(U)[sp].m(C)p.m(A)p.m(G)p.m(C)p.m(U)p.m(U)p.m(C)p.m(C)p.m(A)p.m(U)p.m(G)p.m(U)p.m(C)p.m(C)p.m(U)[sp].m(G)[sp].m(A).[Toc]}$$$$,RNA1{[Chol].m(U)[sp].m(C)[sp].m(A)p.m(G)p.m(G)p.m(A)p.m(C)p.m(A)p.m(U)p.m(G)p.m(G)p.m(A)p.m(A)p.m(G)p.m(C)p.m(U)p.m(G)[sp].m(A)[sp].m(A)}|RNA2{m(U)[sp].m(U)[sp].m(C)p.m(A)p.m(G)p.m(C)p.m(U)p.m(U)p.m(C)p.m(C)p.m(A)p.m(U)p.m(G)p.m(U)p.m(C)p.m(C)p.m(U)[sp].m(G)[sp].m(A).[Toc]}$$$$,78.3,0.22,99,5
28
+ siR-0027,TTR,lead,19,19,RNA1{m(A)[sp].[fl2r](U)[sp].m(U)p.[fl2r](G)p.m(G)p.[fl2r](G)p.m(A)p.[fl2r](U)p.m(U)p.[fl2r](U)p.m(C)p.[fl2r](A)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](G)p.m(A)[sp].[fl2r](A)[sp].m(U).[L3]}$$$$,RNA1{m(A)[sp].[fl2r](U)[sp].m(U)p.[fl2r](C)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](U)p.m(G)p.[fl2r](A)p.m(A)p.[fl2r](A)p.m(U)p.[fl2r](C)p.m(C)p.[fl2r](C)p.m(A)[sp].[fl2r](A)[sp].m(U).[Bio]}$$$$,RNA1{m(A)[sp].[fl2r](U)[sp].m(U)p.[fl2r](G)p.m(G)p.[fl2r](G)p.m(A)p.[fl2r](U)p.m(U)p.[fl2r](U)p.m(C)p.[fl2r](A)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](G)p.m(A)[sp].[fl2r](A)[sp].m(U).[L3]}|RNA2{m(A)[sp].[fl2r](U)[sp].m(U)p.[fl2r](C)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](U)p.m(G)p.[fl2r](A)p.m(A)p.[fl2r](A)p.m(U)p.[fl2r](C)p.m(C)p.[fl2r](C)p.m(A)[sp].[fl2r](A)[sp].m(U).[Bio]}$$$$,78.5,0.29,99,7
29
+ siR-0028,APOC3,backup,19,19,RNA1{m(A)[sp].[fl2r](U)[sp].m(C)p.[fl2r](A)p.m(G)p.[fl2r](U)p.m(A)p.[fl2r](C)p.m(G)p.[fl2r](U)p.m(U)p.[fl2r](G)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](A)p.m(C)[sp].[fl2r](G)[sp].m(G)}$$$$,RNA1{[Bio].m(C)[sp].[fl2r](C)[sp].m(G)p.[fl2r](U)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](C)p.m(A)p.[fl2r](A)p.m(C)p.[fl2r](G)p.m(U)p.[fl2r](A)p.m(C)p.[fl2r](U)p.m(G)[sp].[fl2r](A)[sp].m(U)}$$$$,RNA1{m(A)[sp].[fl2r](U)[sp].m(C)p.[fl2r](A)p.m(G)p.[fl2r](U)p.m(A)p.[fl2r](C)p.m(G)p.[fl2r](U)p.m(U)p.[fl2r](G)p.m(U)p.[fl2r](C)p.m(A)p.[fl2r](A)p.m(C)[sp].[fl2r](G)[sp].m(G)}|RNA2{[Bio].m(C)[sp].[fl2r](C)[sp].m(G)p.[fl2r](U)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](C)p.m(A)p.[fl2r](A)p.m(C)p.[fl2r](G)p.m(U)p.[fl2r](A)p.m(C)p.[fl2r](U)p.m(G)[sp].[fl2r](A)[sp].m(U)}$$$$,70.5,0.07,81,1
30
+ siR-0029,ANGPTL3,deprio,19,19,RNA1{[Chol].m(G)[sp].m(A)[sp].m(A)p.m(C)p.m(U)p.m(C)p.m(U)p.m(G)p.m(A)p.m(U)p.m(G)p.m(A)p.m(G)p.m(G)p.m(C)p.m(A)p.m(U)[sp].m(U)[sp].m(C).[L3]}$$$$,RNA1{[Pal].m(G)[sp].m(A)[sp].m(A)p.m(U)p.m(G)p.m(C)p.m(C)p.m(U)p.m(C)p.m(A)p.m(U)p.m(C)p.m(A)p.m(G)p.m(A)p.m(G)p.m(U)[sp].m(U)[sp].m(C).[Bio]}$$$$,RNA1{[Chol].m(G)[sp].m(A)[sp].m(A)p.m(C)p.m(U)p.m(C)p.m(U)p.m(G)p.m(A)p.m(U)p.m(G)p.m(A)p.m(G)p.m(G)p.m(C)p.m(A)p.m(U)[sp].m(U)[sp].m(C).[L3]}|RNA2{[Pal].m(G)[sp].m(A)[sp].m(A)p.m(U)p.m(G)p.m(C)p.m(C)p.m(U)p.m(C)p.m(A)p.m(U)p.m(C)p.m(A)p.m(G)p.m(A)p.m(G)p.m(U)[sp].m(U)[sp].m(C).[Bio]}$$$$,80.1,0.22,99,5
31
+ siR-0030,HBV,lead,19,19,RNA1{[Pal].m(G)[sp].[fl2r](G)[sp].m(A)p.[fl2r](A)p.m(C)p.[fl2r](U)p.m(C)p.[fl2r](U)p.m(U)p.[fl2r](U)p.m(A)p.[fl2r](C)p.m(A)p.[fl2r](U)p.m(G)p.[fl2r](C)p.m(U)[sp].[fl2r](G)[sp].m(U)}$$$$,RNA1{m(A)[sp].m(C)[sp].m(A)p.m(G)p.m(C)p.m(A)p.m(U)p.m(G)p.m(U)p.m(A)p.m(A)p.m(A)p.m(G)p.m(A)p.m(G)p.m(U)p.m(U)[sp].m(C)[sp].m(C).[L3]}$$$$,RNA1{[Pal].m(G)[sp].[fl2r](G)[sp].m(A)p.[fl2r](A)p.m(C)p.[fl2r](U)p.m(C)p.[fl2r](U)p.m(U)p.[fl2r](U)p.m(A)p.[fl2r](C)p.m(A)p.[fl2r](U)p.m(G)p.[fl2r](C)p.m(U)[sp].[fl2r](G)[sp].m(U)}|RNA2{m(A)[sp].m(C)[sp].m(A)p.m(G)p.m(C)p.m(A)p.m(U)p.m(G)p.m(U)p.m(A)p.m(A)p.m(A)p.m(G)p.m(A)p.m(G)p.m(U)p.m(U)[sp].m(C)[sp].m(C).[L3]}$$$$,76.7,0.28,99,7
32
+ siR-0031,HSD17B13,backup,19,19,RNA1{[DBCO].m(C)[sp].[fl2r](A)[sp].m(U)p.[fl2r](G)p.m(G)p.[fl2r](U)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](A)p.m(C)p.[fl2r](A)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](G)p.m(C)[sp].[fl2r](A)[sp].m(A)}$$$$,RNA1{m(U)[sp].m(U)[sp].m(G)p.m(C)p.m(U)p.m(C)p.m(A)p.m(U)p.m(G)p.m(U)p.m(U)p.m(C)p.m(A)p.m(A)p.m(C)p.m(C)p.m(A)[sp].m(U)[sp].m(G)}$$$$,RNA1{[DBCO].m(C)[sp].[fl2r](A)[sp].m(U)p.[fl2r](G)p.m(G)p.[fl2r](U)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](A)p.m(C)p.[fl2r](A)p.m(U)p.[fl2r](G)p.m(A)p.[fl2r](G)p.m(C)[sp].[fl2r](A)[sp].m(A)}|RNA2{m(U)[sp].m(U)[sp].m(G)p.m(C)p.m(U)p.m(C)p.m(A)p.m(U)p.m(G)p.m(U)p.m(U)p.m(C)p.m(A)p.m(A)p.m(C)p.m(C)p.m(A)[sp].m(U)[sp].m(G)}$$$$,72.6,0.3,92,8
33
+ siR-0032,TTR,backup,19,19,RNA1{m(A)[sp].m(U)[sp].[fl2r](U)p.[fl2r](G)p.[fl2r](G)p.[fl2r](G)p.[fl2r](A)p.[fl2r](U)p.m(U)p.m(U)p.m(C)p.m(A)p.m(U)p.m(G)p.m(A)p.m(G)p.m(A)[sp].m(A)[sp].m(U).[L3]}$$$$,RNA1{m(A)[sp].m(U)[sp].m(U)p.m(C)p.m(U)p.m(C)p.m(A)p.m(U)p.m(G)p.m(A)p.m(A)p.m(A)p.m(U)p.m(C)p.m(C)p.m(C)p.m(A)[sp].m(A)[sp].m(U)}$$$$,RNA1{m(A)[sp].m(U)[sp].[fl2r](U)p.[fl2r](G)p.[fl2r](G)p.[fl2r](G)p.[fl2r](A)p.[fl2r](U)p.m(U)p.m(U)p.m(C)p.m(A)p.m(U)p.m(G)p.m(A)p.m(G)p.m(A)[sp].m(A)[sp].m(U).[L3]}|RNA2{m(A)[sp].m(U)[sp].m(U)p.m(C)p.m(U)p.m(C)p.m(A)p.m(U)p.m(G)p.m(A)p.m(A)p.m(A)p.m(U)p.m(C)p.m(C)p.m(C)p.m(A)[sp].m(A)[sp].m(U)}$$$$,69.7,0.16,83,3
34
+ siR-0033,KRAS,deprio,19,19,RNA1{[r](G)p.m(A)p.m(C)p.m(U)p.m(G)p.[r](A)p.m(A)p.m(U)p.m(A)p.m(U)p.m(A)p.m(A)p.m(A)p.m(C)p.m(U)p.m(U)p.m(G)p.m(U)p.m(G)}$$$$,RNA1{m(C)[sp].m(A)[sp].m(C)p.m(A)p.m(A)p.m(G)p.m(U)p.m(U)p.m(U)p.m(A)p.m(U)p.m(A)p.m(U)p.m(U)p.m(C)p.m(A)p.m(G)[sp].m(U)[sp].m(C)}$$$$,RNA1{[r](G)p.m(A)p.m(C)p.m(U)p.m(G)p.[r](A)p.m(A)p.m(U)p.m(A)p.m(U)p.m(A)p.m(A)p.m(A)p.m(C)p.m(U)p.m(U)p.m(G)p.m(U)p.m(G)}|RNA2{m(C)[sp].m(A)[sp].m(C)p.m(A)p.m(A)p.m(G)p.m(U)p.m(U)p.m(U)p.m(A)p.m(U)p.m(A)p.m(U)p.m(U)p.m(C)p.m(A)p.m(G)[sp].m(U)[sp].m(C)}$$$$,63.7,0.11,71,2
35
+ aso-0034,TTR_ASO,clinical,19,0,RNA1{[lna](C)[sp].[lna](A)[sp].[lna](G)[sp].d(T)[sp].d(G)[sp].d(T)[sp].d(T)[sp].d(C)[sp].d(T)[sp].d(T)[sp].d(G)[sp].d(C)[sp].d(T)[sp].d(C)[sp].d(T)[sp].d(A)[sp].[lna](T)[sp].[lna](A)[sp].[lna](A)}$$$$,,RNA1{[lna](C)[sp].[lna](A)[sp].[lna](G)[sp].d(T)[sp].d(G)[sp].d(T)[sp].d(T)[sp].d(C)[sp].d(T)[sp].d(T)[sp].d(G)[sp].d(C)[sp].d(T)[sp].d(C)[sp].d(T)[sp].d(A)[sp].[lna](T)[sp].[lna](A)[sp].[lna](A)}$$$$,79.6,0.3,99,7
36
+ aso-0035,PCSK9_ASO,lead,19,0,RNA1{[moe](C)[sp].[moe](C)[sp].[moe](A)[sp].[moe](G)[sp].[moe](G)[sp].d(A)[sp].d(C)[sp].d(T)[sp].d(G)[sp].d(A)[sp].d(G)[sp].d(G)[sp].d(C)[sp].d(T)[sp].[moe](T)[sp].[moe](A)[sp].[moe](C)[sp].[moe](G)[sp].[moe](T)}$$$$,,RNA1{[moe](C)[sp].[moe](C)[sp].[moe](A)[sp].[moe](G)[sp].[moe](G)[sp].d(A)[sp].d(C)[sp].d(T)[sp].d(G)[sp].d(A)[sp].d(G)[sp].d(G)[sp].d(C)[sp].d(T)[sp].[moe](T)[sp].[moe](A)[sp].[moe](C)[sp].[moe](G)[sp].[moe](T)}$$$$,74.4,0.1,89,2
37
+ aso-0036,AGT_ASO,lead,19,0,RNA1{[Chol].[lna](C)[sp].[lna](A)[sp].[lna](C)[sp].d(A)[sp].d(G)[sp].d(T)[sp].d(A)[sp].d(C)[sp].d(T)[sp].d(G)[sp].d(G)[sp].d(A)[sp].d(G)[sp].d(C)[sp].d(A)[sp].d(T)[sp].[lna](G)[sp].[lna](G)[sp].[lna](T).[GalNAc]}$$$$,,RNA1{[Chol].[lna](C)[sp].[lna](A)[sp].[lna](C)[sp].d(A)[sp].d(G)[sp].d(T)[sp].d(A)[sp].d(C)[sp].d(T)[sp].d(G)[sp].d(G)[sp].d(A)[sp].d(G)[sp].d(C)[sp].d(A)[sp].d(T)[sp].[lna](G)[sp].[lna](G)[sp].[lna](T).[GalNAc]}$$$$,74.7,0.11,90,2
38
+ aso-0037,TTR_ASO,backup,19,0,RNA1{[Bio].[moe](C)[sp].[moe](A)[sp].[moe](G)[sp].[moe](T)[sp].[moe](G)[sp].d(T)[sp].d(T)[sp].d(C)[sp].d(T)[sp].d(T)[sp].d(G)[sp].d(C)[sp].d(T)[sp].d(C)[sp].[moe](T)[sp].[moe](A)[sp].[moe](T)[sp].[moe](A)[sp].[moe](A)}$$$$,,RNA1{[Bio].[moe](C)[sp].[moe](A)[sp].[moe](G)[sp].[moe](T)[sp].[moe](G)[sp].d(T)[sp].d(T)[sp].d(C)[sp].d(T)[sp].d(T)[sp].d(G)[sp].d(C)[sp].d(T)[sp].d(C)[sp].[moe](T)[sp].[moe](A)[sp].[moe](T)[sp].[moe](A)[sp].[moe](A)}$$$$,77.9,0.24,99,6
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@datagrok/sequence-translator",
3
3
  "friendlyName": "Sequence Translator",
4
- "version": "1.10.14",
4
+ "version": "1.10.16",
5
5
  "author": {
6
6
  "name": "Davit Rizhinashvili",
7
7
  "email": "drizhinashvili@datagrok.ai"
@@ -22,7 +22,7 @@
22
22
  }
23
23
  ],
24
24
  "dependencies": {
25
- "@datagrok-libraries/bio": "^5.63.6",
25
+ "@datagrok-libraries/bio": "^5.65.0",
26
26
  "@datagrok-libraries/chem-meta": "^1.2.8",
27
27
  "@datagrok-libraries/tutorials": "^1.6.1",
28
28
  "@datagrok-libraries/utils": "^4.6.5",
@@ -0,0 +1,500 @@
1
+ /**
2
+ * Canvas drawing for the OligoNucleotide cell renderer.
3
+ *
4
+ * Pure functions — no DG / DOM dependencies — so the renderer is easy to
5
+ * unit-test and to drive from the HTML prototype as well.
6
+ *
7
+ * Visual model:
8
+ * - Chip body uses base-canonical color (A green / C blue / G tan / U pink).
9
+ * - Sugar modifications are shown as a colored stripe at the bottom of the
10
+ * chip (so the chip itself stays readable for the base sequence, and the
11
+ * modification track scans easily horizontally).
12
+ * - Phosphate linkage modifications (PS) are shown as a saturated bar in
13
+ * the gap *between* chips — this is the actual chemistry: the linkage
14
+ * belongs to the bond, not to either nucleotide.
15
+ * - Wide gaps between chips give the modification markers room to breathe.
16
+ * - Antisense is rendered 3'→5' (reversed) so position N of sense visually
17
+ * pairs with position N of antisense (anti-parallel base-pair register).
18
+ * - Conjugates are rendered as wider pills at the chain ends; their actual
19
+ * width is propagated through layout so adjacent chips don't overlap.
20
+ *
21
+ * Sizing is fully adaptive: chip dimensions scale to fit the cell, preserving
22
+ * aspect ratio, down to a minimum below which the cell falls back to a text
23
+ * summary.
24
+ */
25
+
26
+ import {
27
+ BASE_COLORS, FALLBACK_COLOR,
28
+ canonicalSugarSymbol,
29
+ ParsedDuplex, ParsedMonomer, ParsedNucleotide, ParsedStrand,
30
+ resolveConjugate, resolvePhosphate, resolveSugar,
31
+ } from './types';
32
+
33
+ export interface RenderOpts {
34
+ /** Show base letter inside chip. False at very small sizes. */
35
+ showLetters: boolean;
36
+ /** Draw antisense 3'→5' for base-pair alignment with sense. Default true. */
37
+ pairAlign: boolean;
38
+ /** Optional column-level scheme name (currently ignored — palette is fixed). */
39
+ scheme?: string;
40
+ }
41
+
42
+ const DEFAULT_OPTS: RenderOpts = {showLetters: true, pairAlign: true};
43
+
44
+ /* Visual tuning. */
45
+ const ASPECT_H_OVER_W = 1.25;
46
+ const STRAND_GAP_RATIO = 0.5;
47
+ const CHIP_GAP_RATIO = 0.32; // wider — gives PS bar room to breathe
48
+ const MIN_CHIP_W = 5;
49
+ const MAX_CHIP_W = 17;
50
+ const PAD = 4;
51
+ const LABEL_W = 30;
52
+ const CHIP_FILL_ALPHA = 0.85; // chip body, base-canonical pale color
53
+ const CHIP_BORDER_W = 0.5;
54
+ const SUGAR_STRIPE_RATIO = 0.22; // height of bottom sugar-mod stripe
55
+ const PS_BAR_RATIO = 0.55; // PS bar width as fraction of chip gap
56
+
57
+ /** Cached layout for one rendered cell. */
58
+ export interface DuplexLayout {
59
+ chipW: number;
60
+ chipH: number;
61
+ chipGap: number;
62
+ strandGap: number;
63
+ fontSize: number;
64
+ labelW: number;
65
+ padding: number;
66
+ senseY: number;
67
+ antiY: number; // -1 if no antisense
68
+ seqX: number;
69
+ textOnlyFallback: boolean;
70
+ senseChips: ChipPos[];
71
+ antiChips: ChipPos[];
72
+ senseLinks: LinkagePos[];
73
+ antiLinks: LinkagePos[];
74
+ /** Whether antisense was rendered in reversed (3'→5') order. */
75
+ antiReversed: boolean;
76
+ }
77
+
78
+ export interface ChipPos {
79
+ x: number;
80
+ w: number;
81
+ monomer: ParsedMonomer;
82
+ /** Original 0-based index in the data strand (regardless of display order). */
83
+ origIdx: number;
84
+ strand: StrandSide;
85
+ }
86
+
87
+ export interface LinkagePos {
88
+ x: number; w: number; y: number; h: number;
89
+ phosphateSymbol: string;
90
+ /** Original index of the nucleotide that owns the 3' phosphate. */
91
+ ownerOrigIdx: number;
92
+ strand: StrandSide;
93
+ }
94
+
95
+ export type StrandSide = 'sense' | 'antisense';
96
+
97
+ /* ---------------------------------------------------------------- *
98
+ * Layout
99
+ * ---------------------------------------------------------------- */
100
+
101
+ export function computeLayout(
102
+ cellW: number, cellH: number, model: ParsedDuplex, opts: Partial<RenderOpts> = {},
103
+ ): DuplexLayout {
104
+ const o: RenderOpts = {...DEFAULT_OPTS, ...opts};
105
+ const senseLen = model.sense.monomers.length;
106
+ const antiLen = model.antisense ? model.antisense.monomers.length : 0;
107
+ const hasAnti = antiLen > 0;
108
+ const strandsCount = hasAnti ? 2 : 1;
109
+ const maxLen = Math.max(1, senseLen, antiLen);
110
+
111
+ const availW = Math.max(0, cellW - LABEL_W - 2 * PAD);
112
+ const wChipW = availW / (maxLen + Math.max(0, maxLen - 1) * CHIP_GAP_RATIO);
113
+
114
+ const heightFactor = strandsCount + Math.max(0, strandsCount - 1) * STRAND_GAP_RATIO;
115
+ const hChipH = (cellH - 2 * PAD) / heightFactor;
116
+ const hChipW = hChipH / ASPECT_H_OVER_W;
117
+
118
+ let chipW = Math.min(MAX_CHIP_W, wChipW, hChipW);
119
+ const textOnlyFallback = chipW < MIN_CHIP_W;
120
+ if (chipW < MIN_CHIP_W) chipW = MIN_CHIP_W;
121
+
122
+ const chipH = chipW * ASPECT_H_OVER_W;
123
+ const chipGap = Math.max(2, chipW * CHIP_GAP_RATIO);
124
+ const strandGap = chipH * STRAND_GAP_RATIO;
125
+ const fontSize = Math.max(7, Math.min(13, chipW * 0.62));
126
+
127
+ const blockH = strandsCount * chipH + (strandsCount - 1) * strandGap;
128
+ const blockTop = Math.max(PAD, (cellH - blockH) / 2);
129
+ const senseY = blockTop;
130
+ const antiY = hasAnti ? blockTop + chipH + strandGap : -1;
131
+ const seqX = PAD + LABEL_W;
132
+ const seqEndX = cellW - PAD;
133
+
134
+ const layoutBase: Omit<DuplexLayout, 'senseChips' | 'antiChips' | 'senseLinks' | 'antiLinks' | 'antiReversed'> = {
135
+ chipW, chipH, chipGap, strandGap, fontSize,
136
+ labelW: LABEL_W, padding: PAD,
137
+ senseY, antiY, seqX, textOnlyFallback,
138
+ };
139
+
140
+ if (textOnlyFallback) {
141
+ return {
142
+ ...layoutBase,
143
+ senseChips: [], antiChips: [], senseLinks: [], antiLinks: [],
144
+ antiReversed: false,
145
+ };
146
+ }
147
+
148
+ // Conjugates on either strand's leftmost end push back the start of
149
+ // *that* strand's nucleotide region. To keep base pairs aligned across
150
+ // strands, we measure the leading-conjugate width of each strand (in
151
+ // its display order — antisense is reversed when pair-aligned) and
152
+ // shift each strand right by the difference, so the first NUCLEOTIDE
153
+ // of each strand sits at the same X coordinate.
154
+ const antiReversed = hasAnti && o.pairAlign;
155
+ const senseLeadW = leadingConjugateWidth(model.sense.monomers, false, chipW, fontSize, chipGap);
156
+ const antiLeadW = hasAnti ?
157
+ leadingConjugateWidth(model.antisense!.monomers, antiReversed, chipW, fontSize, chipGap) : 0;
158
+ const alignAt = Math.max(senseLeadW, antiLeadW);
159
+ const senseStartX = seqX + (alignAt - senseLeadW);
160
+ const antiStartX = seqX + (alignAt - antiLeadW);
161
+
162
+ const senseRes = placeStrand(model.sense, false, senseY, senseStartX, seqEndX, layoutBase, 'sense');
163
+ const antiRes = hasAnti ?
164
+ placeStrand(model.antisense!, antiReversed, antiY, antiStartX, seqEndX, layoutBase, 'antisense') :
165
+ {chips: [], links: []};
166
+
167
+ return {
168
+ ...layoutBase,
169
+ senseChips: senseRes.chips,
170
+ antiChips: antiRes.chips,
171
+ senseLinks: senseRes.links,
172
+ antiLinks: antiRes.links,
173
+ antiReversed,
174
+ };
175
+ }
176
+
177
+ /** Place chips for one strand, optionally reversed. Returns chip and linkage positions. */
178
+ function placeStrand(
179
+ strand: ParsedStrand, reverse: boolean, y: number, startX: number, endX: number,
180
+ layout: Omit<DuplexLayout, 'senseChips' | 'antiChips' | 'senseLinks' | 'antiLinks' | 'antiReversed'>,
181
+ side: StrandSide,
182
+ ): { chips: ChipPos[]; links: LinkagePos[] } {
183
+ const monomers = reverse ? strand.monomers.slice().reverse() : strand.monomers;
184
+ const chips: ChipPos[] = [];
185
+ const links: LinkagePos[] = [];
186
+ let x = startX;
187
+
188
+ for (let i = 0; i < monomers.length; i++) {
189
+ const m = monomers[i];
190
+ const w = m.kind === 'conjugate' ?
191
+ estimateConjugateWidth(m.symbol, layout.chipW, layout.fontSize) :
192
+ layout.chipW;
193
+
194
+ if (x + w > endX) break; // truncate at cell edge
195
+
196
+ chips.push({x, w, monomer: m, origIdx: m.position, strand: side});
197
+
198
+ // Linkage from this monomer's 3'-phosphate goes in the gap to the right.
199
+ // When the strand is reversed (anti-parallel), the linkage that was
200
+ // "owned by monomer N's 3' end" connects monomer N to monomer N+1 in the
201
+ // data; in display these are still adjacent, so the gap-to-right is still
202
+ // the right place to draw it. We just need to look up the correct owner.
203
+ if (m.kind === 'nucleotide' && i < monomers.length - 1) {
204
+ const nt = m as ParsedNucleotide;
205
+ if (nt.phosphate) {
206
+ links.push({
207
+ x: x + w, w: layout.chipGap, y, h: layout.chipH,
208
+ phosphateSymbol: nt.phosphate,
209
+ ownerOrigIdx: nt.position,
210
+ strand: side,
211
+ });
212
+ }
213
+ }
214
+ x += w + layout.chipGap;
215
+ }
216
+ return {chips, links};
217
+ }
218
+
219
+ /** Width estimate for a conjugate pill, using only chip metrics (no canvas measure). */
220
+ function estimateConjugateWidth(symbol: string, chipW: number, fontSize: number): number {
221
+ const meta = resolveConjugate(symbol).meta;
222
+ const charW = fontSize * 0.55;
223
+ const textW = meta.short.length * charW;
224
+ const padding = chipW * 0.6;
225
+ return Math.max(chipW, Math.min(chipW * 4, textW + padding));
226
+ }
227
+
228
+ /** Sum of widths of leading conjugates in display order (after reversal if any),
229
+ * including their trailing chipGap, so antisense and sense can be shifted
230
+ * independently to align their first nucleotides at the same X coordinate. */
231
+ function leadingConjugateWidth(
232
+ monomers: ParsedMonomer[], reversed: boolean,
233
+ chipW: number, fontSize: number, chipGap: number,
234
+ ): number {
235
+ const seq = reversed ? monomers.slice().reverse() : monomers;
236
+ let w = 0;
237
+ for (const m of seq) {
238
+ if (m.kind !== 'conjugate') break;
239
+ w += estimateConjugateWidth(m.symbol, chipW, fontSize) + chipGap;
240
+ }
241
+ return w;
242
+ }
243
+
244
+ /* ---------------------------------------------------------------- *
245
+ * Drawing
246
+ * ---------------------------------------------------------------- */
247
+
248
+ export function drawDuplex(
249
+ g: CanvasRenderingContext2D, cellX: number, cellY: number,
250
+ cellW: number, cellH: number, model: ParsedDuplex,
251
+ opts: Partial<RenderOpts> = {},
252
+ ): DuplexLayout {
253
+ const o: RenderOpts = {...DEFAULT_OPTS, ...opts};
254
+ const layout = computeLayout(cellW, cellH, model, o);
255
+
256
+ g.save();
257
+ g.beginPath();
258
+ g.rect(cellX, cellY, cellW, cellH);
259
+ g.clip();
260
+ g.translate(cellX, cellY);
261
+
262
+ if (layout.textOnlyFallback) {
263
+ drawFallbackText(g, cellW, cellH, model, layout);
264
+ g.restore();
265
+ return layout;
266
+ }
267
+
268
+ // Strand label "S 5'" left of sense
269
+ drawStrandLabel(g, 'S', '5\'', layout.padding, layout.senseY + layout.chipH / 2, layout);
270
+
271
+ // Linkages first (so chips paint over their rounded edges cleanly)
272
+ for (const link of layout.senseLinks) drawLinkage(g, link);
273
+ drawChips(g, layout.senseChips, layout, o);
274
+ drawTruncationMarker(g, layout.senseChips, model.sense.monomers.length, layout);
275
+
276
+ if (layout.antiY >= 0 && model.antisense) {
277
+ // When reversed, the leftmost chip in display is the 3' end of antisense.
278
+ const leftLabel = layout.antiReversed ? '3\'' : '5\'';
279
+ drawStrandLabel(g, 'AS', leftLabel, layout.padding, layout.antiY + layout.chipH / 2, layout);
280
+ for (const link of layout.antiLinks) drawLinkage(g, link);
281
+ drawChips(g, layout.antiChips, layout, o);
282
+ drawTruncationMarker(g, layout.antiChips, model.antisense.monomers.length, layout);
283
+ }
284
+
285
+ g.restore();
286
+ return layout;
287
+ }
288
+
289
+ function drawStrandLabel(
290
+ g: CanvasRenderingContext2D, strand: string, terminus: string, x: number, y: number, layout: DuplexLayout,
291
+ ): void {
292
+ g.fillStyle = '#8b949e';
293
+ g.font = `${Math.max(8, layout.fontSize - 1)}px ui-monospace, Menlo, monospace`;
294
+ g.textBaseline = 'middle';
295
+ g.textAlign = 'left';
296
+ g.fillText(`${strand} ${terminus}`, x, y);
297
+ }
298
+
299
+ function drawTruncationMarker(
300
+ g: CanvasRenderingContext2D, chips: ChipPos[], totalCount: number, layout: DuplexLayout,
301
+ ): void {
302
+ if (chips.length >= totalCount) return;
303
+ const last = chips[chips.length - 1];
304
+ if (!last) return;
305
+ g.fillStyle = '#6e7681';
306
+ g.font = `${Math.max(7, layout.fontSize - 1)}px ui-monospace, Menlo, monospace`;
307
+ g.textBaseline = 'middle';
308
+ g.textAlign = 'left';
309
+ g.fillText('…', last.x + last.w + 1, layout.senseY + layout.chipH / 2);
310
+ }
311
+
312
+ function drawChips(g: CanvasRenderingContext2D, chips: ChipPos[], layout: DuplexLayout, opts: RenderOpts): void {
313
+ const y = chips[0]?.strand === 'sense' ? layout.senseY : layout.antiY;
314
+ for (const cp of chips) {
315
+ if (cp.monomer.kind === 'conjugate')
316
+ drawConjugate(g, cp.monomer.symbol, cp.x, y, cp.w, layout.chipH, layout.fontSize);
317
+ else
318
+ drawChip(g, cp.monomer as ParsedNucleotide, cp.x, y, cp.w, layout.chipH, layout.fontSize, opts);
319
+ }
320
+ }
321
+
322
+ function drawChip(
323
+ g: CanvasRenderingContext2D, m: ParsedNucleotide, x: number, y: number,
324
+ w: number, h: number, fontSize: number, opts: RenderOpts,
325
+ ): void {
326
+ const sugarRes = resolveSugar(m.sugar, m.base);
327
+ const baseColor = BASE_COLORS[m.base ?? ''] ?? FALLBACK_COLOR;
328
+ const isModSugar = isModifiedSugar(m.sugar);
329
+ const r = Math.min(2.5, w / 4);
330
+
331
+ // Chip body — base-canonical pale color
332
+ drawRoundRect(g, x, y, w, h, r);
333
+ g.fillStyle = withAlpha(baseColor, CHIP_FILL_ALPHA);
334
+ g.fill();
335
+ g.lineWidth = CHIP_BORDER_W;
336
+ g.strokeStyle = 'rgba(0,0,0,0.22)';
337
+ g.stroke();
338
+
339
+ // Sugar modification stripe at chip bottom — clipped to rounded shape
340
+ if (isModSugar) {
341
+ const stripeH = Math.max(2, h * SUGAR_STRIPE_RATIO);
342
+ g.save();
343
+ drawRoundRect(g, x, y, w, h, r);
344
+ g.clip();
345
+ g.fillStyle = sugarRes.color;
346
+ g.fillRect(x, y + h - stripeH, w, stripeH);
347
+ g.restore();
348
+ }
349
+
350
+ // Base letter — biased upward to leave room for stripe
351
+ if (opts.showLetters && m.base && fontSize >= 8) {
352
+ const stripeH = isModSugar ? Math.max(2, h * SUGAR_STRIPE_RATIO) : 0;
353
+ g.fillStyle = '#1a1a1a';
354
+ g.font = `600 ${fontSize}px system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif`;
355
+ g.textBaseline = 'middle';
356
+ g.textAlign = 'center';
357
+ g.fillText(m.base, x + w / 2, y + (h - stripeH) / 2 + 0.5);
358
+ }
359
+ }
360
+
361
+ function isModifiedSugar(sugar: string): boolean {
362
+ const c = canonicalSugarSymbol(sugar);
363
+ return c !== 'r' && c !== 'd';
364
+ }
365
+
366
+ function drawLinkage(g: CanvasRenderingContext2D, link: LinkagePos): void {
367
+ const ps = resolvePhosphate(link.phosphateSymbol);
368
+ if (ps.meta.short !== 'PS' && ps.meta.short !== 'PS₂' && ps.meta.short !== 'MeP')
369
+ return; // only draw markers for non-canonical linkages
370
+ const barW = Math.max(2.5, link.w * PS_BAR_RATIO);
371
+ const barX = link.x + (link.w - barW) / 2;
372
+ g.fillStyle = ps.color;
373
+ g.fillRect(barX, link.y + 1, barW, link.h - 2);
374
+ }
375
+
376
+ function drawConjugate(
377
+ g: CanvasRenderingContext2D, symbol: string, x: number, y: number,
378
+ w: number, chipH: number, fontSize: number,
379
+ ): void {
380
+ const conj = resolveConjugate(symbol);
381
+ const r = chipH / 2;
382
+ drawRoundRect(g, x, y, w, chipH, r);
383
+ g.fillStyle = conj.color;
384
+ g.fill();
385
+ g.lineWidth = 0.5;
386
+ g.strokeStyle = 'rgba(0,0,0,0.2)';
387
+ g.stroke();
388
+
389
+ if (fontSize >= 8) {
390
+ g.fillStyle = '#ffffff';
391
+ g.font = `600 ${Math.max(8, fontSize - 1)}px system-ui, sans-serif`;
392
+ g.textBaseline = 'middle';
393
+ g.textAlign = 'center';
394
+ g.fillText(conj.meta.short, x + w / 2, y + chipH / 2 + 0.5);
395
+ }
396
+ }
397
+
398
+ function drawRoundRect(
399
+ g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, r: number,
400
+ ): void {
401
+ g.beginPath();
402
+ g.moveTo(x + r, y);
403
+ g.lineTo(x + w - r, y);
404
+ g.quadraticCurveTo(x + w, y, x + w, y + r);
405
+ g.lineTo(x + w, y + h - r);
406
+ g.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
407
+ g.lineTo(x + r, y + h);
408
+ g.quadraticCurveTo(x, y + h, x, y + h - r);
409
+ g.lineTo(x, y + r);
410
+ g.quadraticCurveTo(x, y, x + r, y);
411
+ g.closePath();
412
+ }
413
+
414
+ function drawFallbackText(
415
+ g: CanvasRenderingContext2D, _w: number, h: number, model: ParsedDuplex, layout: DuplexLayout,
416
+ ): void {
417
+ const sLen = model.sense.monomers.length;
418
+ const aLen = model.antisense ? model.antisense.monomers.length : 0;
419
+ const summary = model.antisense ? `${sLen}+${aLen} nt duplex` : `${sLen} nt`;
420
+ g.fillStyle = '#8b949e';
421
+ g.font = `${Math.max(8, layout.fontSize)}px ui-monospace, Menlo, monospace`;
422
+ g.textBaseline = 'middle';
423
+ g.textAlign = 'left';
424
+ g.fillText(summary, 4, h / 2);
425
+ }
426
+
427
+ /** Apply alpha to any CSS color string, returning rgba(...). Memoized. */
428
+ const _alphaCache = new Map<string, string>();
429
+ function withAlpha(color: string, alpha: number): string {
430
+ const key = `${color}|${alpha}`;
431
+ const cached = _alphaCache.get(key);
432
+ if (cached) return cached;
433
+ const probe = document.createElement('span');
434
+ probe.style.color = color;
435
+ document.body.appendChild(probe);
436
+ const rgb = getComputedStyle(probe).color;
437
+ document.body.removeChild(probe);
438
+ const m = rgb.match(/\d+/g);
439
+ const out = m ? `rgba(${m[0]},${m[1]},${m[2]},${alpha})` : color;
440
+ if (_alphaCache.size > 256) _alphaCache.clear();
441
+ _alphaCache.set(key, out);
442
+ return out;
443
+ }
444
+
445
+ /* ---------------------------------------------------------------- *
446
+ * Hit testing — uses the cached chip / linkage positions so it works
447
+ * correctly with variable widths (conjugate pills) and reversed antisense.
448
+ * ---------------------------------------------------------------- */
449
+
450
+ export interface HitResult {
451
+ strand: StrandSide;
452
+ /** Original 0-based index in the data strand. */
453
+ position: number;
454
+ monomer: ParsedMonomer;
455
+ /** Set if the hit is on an inter-chip linkage marker (PS, etc.). */
456
+ linkage?: { phosphateSymbol: string };
457
+ }
458
+
459
+ export function hitTest(
460
+ localX: number, localY: number, model: ParsedDuplex, layout: DuplexLayout,
461
+ ): HitResult | null {
462
+ if (layout.textOnlyFallback) return null;
463
+
464
+ // Sense chip?
465
+ if (localY >= layout.senseY && localY <= layout.senseY + layout.chipH) {
466
+ const cp = findChip(localX, layout.senseChips);
467
+ if (cp) return {strand: 'sense', position: cp.origIdx, monomer: cp.monomer};
468
+ const link = findLink(localX, localY, layout.senseLinks);
469
+ if (link) return resolveLinkHit(link, model.sense, 'sense');
470
+ }
471
+ // Antisense chip?
472
+ if (layout.antiY >= 0 && localY >= layout.antiY && localY <= layout.antiY + layout.chipH) {
473
+ const cp = findChip(localX, layout.antiChips);
474
+ if (cp) return {strand: 'antisense', position: cp.origIdx, monomer: cp.monomer};
475
+ const link = findLink(localX, localY, layout.antiLinks);
476
+ if (link && model.antisense) return resolveLinkHit(link, model.antisense, 'antisense');
477
+ }
478
+ return null;
479
+ }
480
+
481
+ function findChip(x: number, chips: ChipPos[]): ChipPos | null {
482
+ for (const cp of chips) if (x >= cp.x && x < cp.x + cp.w) return cp;
483
+ return null;
484
+ }
485
+
486
+ function findLink(x: number, y: number, links: LinkagePos[]): LinkagePos | null {
487
+ for (const l of links)
488
+ if (x >= l.x && x < l.x + l.w && y >= l.y && y < l.y + l.h) return l;
489
+ return null;
490
+ }
491
+
492
+ function resolveLinkHit(link: LinkagePos, strand: ParsedStrand, side: StrandSide): HitResult {
493
+ const owner = strand.monomers.find((m) => m.position === link.ownerOrigIdx)!;
494
+ return {
495
+ strand: side,
496
+ position: link.ownerOrigIdx,
497
+ monomer: owner,
498
+ linkage: {phosphateSymbol: link.phosphateSymbol},
499
+ };
500
+ }