archaeopteryx 1.0.9 → 2.3.2
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.
- package/LICENSE +504 -0
- package/README.md +206 -103
- package/archaeopteryx.js +8596 -7224
- package/forester.js +1748 -1905
- package/package.json +17 -11
- package/forester_example.js +0 -25
package/forester.js
CHANGED
|
@@ -1,1906 +1,1749 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (C)
|
|
3
|
-
* Copyright (C)
|
|
4
|
-
* Copyright (C)
|
|
5
|
-
* All rights reserved
|
|
6
|
-
*
|
|
7
|
-
* This library is free software; you can redistribute it and/or
|
|
8
|
-
* modify it under the terms of the GNU Lesser General Public
|
|
9
|
-
* License as published by the Free Software Foundation; either
|
|
10
|
-
* version 2.1 of the License, or (at your option) any later version.
|
|
11
|
-
*
|
|
12
|
-
* This library is distributed in the hope that it will be useful,
|
|
13
|
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
15
|
-
* Lesser General Public License for more details.
|
|
16
|
-
*
|
|
17
|
-
* You should have received a copy of the GNU Lesser General Public
|
|
18
|
-
* License along with this library; if not, write to the Free Software
|
|
19
|
-
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
20
|
-
*
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
// v
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
*
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
*
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if (
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
else {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
while (
|
|
495
|
-
if (
|
|
496
|
-
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
};
|
|
561
|
-
|
|
562
|
-
forester.
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
if (
|
|
916
|
-
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
forester.
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
else {
|
|
1384
|
-
|
|
1385
|
-
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
}
|
|
1618
|
-
}
|
|
1619
|
-
if (
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
}
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
props.ref = HOST;
|
|
1750
|
-
props.datatype = STRING;
|
|
1751
|
-
props.applies_to = NODE;
|
|
1752
|
-
props.value = sc.host;
|
|
1753
|
-
addProperties(n, props);
|
|
1754
|
-
}
|
|
1755
|
-
if (sc.year && sc.year.length > 0) {
|
|
1756
|
-
props = {};
|
|
1757
|
-
props.ref = YEAR;
|
|
1758
|
-
props.datatype = INT;
|
|
1759
|
-
props.applies_to = NODE;
|
|
1760
|
-
props.value = parseInt(sc.year);
|
|
1761
|
-
addProperties(n, props);
|
|
1762
|
-
}
|
|
1763
|
-
if (sc.ha && sc.ha.length > 0) {
|
|
1764
|
-
props = {};
|
|
1765
|
-
props.ref = HA;
|
|
1766
|
-
props.datatype = INT;
|
|
1767
|
-
props.applies_to = NODE;
|
|
1768
|
-
props.value = parseInt(sc.ha);
|
|
1769
|
-
addProperties(n, props);
|
|
1770
|
-
}
|
|
1771
|
-
if (sc.na && sc.na.length > 0) {
|
|
1772
|
-
props = {};
|
|
1773
|
-
props.ref = NA;
|
|
1774
|
-
props.datatype = INT;
|
|
1775
|
-
props.applies_to = NODE;
|
|
1776
|
-
props.value = parseInt(sc.na);
|
|
1777
|
-
addProperties(n, props);
|
|
1778
|
-
}
|
|
1779
|
-
n.simple_characteristics = undefined;
|
|
1780
|
-
}
|
|
1781
|
-
});
|
|
1782
|
-
function addProperties(n, props) {
|
|
1783
|
-
if (props) {
|
|
1784
|
-
if (!n.properties) {
|
|
1785
|
-
n.properties = [];
|
|
1786
|
-
}
|
|
1787
|
-
var alreadyHave = false;
|
|
1788
|
-
var l = n.properties.length;
|
|
1789
|
-
for (var i = 0; i < l; ++i) {
|
|
1790
|
-
if (n.properties[i].ref === props.ref) {
|
|
1791
|
-
alreadyHave = true;
|
|
1792
|
-
break;
|
|
1793
|
-
}
|
|
1794
|
-
}
|
|
1795
|
-
if (!alreadyHave) {
|
|
1796
|
-
n.properties.push(props);
|
|
1797
|
-
}
|
|
1798
|
-
}
|
|
1799
|
-
}
|
|
1800
|
-
};
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
/**
|
|
1804
|
-
* To convert a phylogentic tree object to a New Hampshire (Newick) formatted string.
|
|
1805
|
-
*
|
|
1806
|
-
* @param phy - A phylogentic tree object.
|
|
1807
|
-
* @param decPointsMax - Maximal number of decimal points for branch lengths (optional)
|
|
1808
|
-
* @param replaceChars - To replace illegal characters (),:;"' instead of surrounding with quotation marks
|
|
1809
|
-
* @param writeConfidences - to write confidence values in brackets
|
|
1810
|
-
* @returns {*} - a New Hampshire (Newick) formatted string.
|
|
1811
|
-
*/
|
|
1812
|
-
forester.toNewHampshire = function (phy, decPointsMax, replaceChars, writeConfidences) {
|
|
1813
|
-
var nh = "";
|
|
1814
|
-
if (phy.children && phy.children.length === 1) {
|
|
1815
|
-
toNewHampshireHelper(phy.children[0], true);
|
|
1816
|
-
}
|
|
1817
|
-
if (nh.length > 0) {
|
|
1818
|
-
return nh + ";";
|
|
1819
|
-
}
|
|
1820
|
-
return nh;
|
|
1821
|
-
|
|
1822
|
-
function toNewHampshireHelper(node, last) {
|
|
1823
|
-
if (node.children) {
|
|
1824
|
-
var l = node.children.length;
|
|
1825
|
-
nh += "(";
|
|
1826
|
-
for (var i = 0; i < l; ++i) {
|
|
1827
|
-
toNewHampshireHelper(node.children[i], i === l - 1);
|
|
1828
|
-
}
|
|
1829
|
-
nh += ")";
|
|
1830
|
-
}
|
|
1831
|
-
else if (node._children) {
|
|
1832
|
-
var ll = node._children.length;
|
|
1833
|
-
nh += "(";
|
|
1834
|
-
for (var ii = 0; ii < ll; ++ii) {
|
|
1835
|
-
toNewHampshireHelper(node._children[ii], ii === ll - 1);
|
|
1836
|
-
}
|
|
1837
|
-
nh += ")";
|
|
1838
|
-
}
|
|
1839
|
-
if (node.name && node.name.length > 0) {
|
|
1840
|
-
if (replaceChars === true) {
|
|
1841
|
-
nh += replaceUnsafeChars(node.name);
|
|
1842
|
-
}
|
|
1843
|
-
else {
|
|
1844
|
-
var myName = node.name.replace(/\s+/g, ' ');
|
|
1845
|
-
if (/[\s,():;'"\[\]]/.test(myName)) {
|
|
1846
|
-
if ((myName.indexOf('"') > -1) && (myName.indexOf("'") > -1 )) {
|
|
1847
|
-
nh += '"' + myName.replace(/"/g, "'") + '"';
|
|
1848
|
-
}
|
|
1849
|
-
else if (myName.indexOf('"') > -1) {
|
|
1850
|
-
nh += "'" + myName + "'";
|
|
1851
|
-
}
|
|
1852
|
-
else {
|
|
1853
|
-
nh += '"' + myName + '"';
|
|
1854
|
-
}
|
|
1855
|
-
}
|
|
1856
|
-
else {
|
|
1857
|
-
nh += myName;
|
|
1858
|
-
}
|
|
1859
|
-
}
|
|
1860
|
-
}
|
|
1861
|
-
if (node.branch_length !== undefined && node.branch_length !== null) {
|
|
1862
|
-
if (decPointsMax && decPointsMax > 0) {
|
|
1863
|
-
nh += ":" + forester.roundNumber(node.branch_length, decPointsMax);
|
|
1864
|
-
}
|
|
1865
|
-
else {
|
|
1866
|
-
nh += ":" + node.branch_length;
|
|
1867
|
-
}
|
|
1868
|
-
}
|
|
1869
|
-
if (writeConfidences && node.confidences && node.confidences.length === 1 && node.confidences[0].value !== undefined && node.confidences[0].value !== null) {
|
|
1870
|
-
if (decPointsMax && decPointsMax > 0) {
|
|
1871
|
-
nh += "[" + forester.roundNumber(node.confidences[0].value, decPointsMax) + "]";
|
|
1872
|
-
}
|
|
1873
|
-
else {
|
|
1874
|
-
nh += "[" + node.confidences[0].value + "]";
|
|
1875
|
-
}
|
|
1876
|
-
}
|
|
1877
|
-
if (!last) {
|
|
1878
|
-
nh += ",";
|
|
1879
|
-
}
|
|
1880
|
-
}
|
|
1881
|
-
|
|
1882
|
-
function replaceUnsafeChars(str) {
|
|
1883
|
-
return str.replace(/[\s,():;'"\[\]]+/g, '_');
|
|
1884
|
-
}
|
|
1885
|
-
};
|
|
1886
|
-
|
|
1887
|
-
forester.roundNumber = function (num, dec) {
|
|
1888
|
-
return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
|
|
1889
|
-
};
|
|
1890
|
-
|
|
1891
|
-
forester.isString = function (s) {
|
|
1892
|
-
return (typeof s === 'string' || s instanceof String);
|
|
1893
|
-
};
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
// --------------------------------------------------------------
|
|
1897
|
-
// For exporting
|
|
1898
|
-
// --------------------------------------------------------------
|
|
1899
|
-
if (typeof module !== 'undefined' && module.exports && !global.xmldocAssumeBrowser)
|
|
1900
|
-
module.exports.forester = forester;
|
|
1901
|
-
else if (typeof window !== "undefined")
|
|
1902
|
-
window.forester = forester;
|
|
1903
|
-
else
|
|
1904
|
-
this.forester = forester;
|
|
1905
|
-
})();
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2026 Christian M. Zmasek
|
|
3
|
+
* Copyright (C) 2026 Yun Zhang
|
|
4
|
+
* Copyright (C) 2026 J. Craig Venter Institute
|
|
5
|
+
* All rights reserved
|
|
6
|
+
*
|
|
7
|
+
* This library is free software; you can redistribute it and/or
|
|
8
|
+
* modify it under the terms of the GNU Lesser General Public
|
|
9
|
+
* License as published by the Free Software Foundation; either
|
|
10
|
+
* version 2.1 of the License, or (at your option) any later version.
|
|
11
|
+
*
|
|
12
|
+
* This library is distributed in the hope that it will be useful,
|
|
13
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
15
|
+
* Lesser General Public License for more details.
|
|
16
|
+
*
|
|
17
|
+
* You should have received a copy of the GNU Lesser General Public
|
|
18
|
+
* License along with this library; if not, write to the Free Software
|
|
19
|
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
20
|
+
*
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// v 2.3.2
|
|
24
|
+
// 2026-04-22
|
|
25
|
+
//
|
|
26
|
+
// forester.js is a general suite for dealing with phylogenetic trees.
|
|
27
|
+
//
|
|
28
|
+
// forester.js is used by Archaeopteryx.js:
|
|
29
|
+
// https://github.com/cmzmasek/archaeopteryx-js
|
|
30
|
+
// https://www.npmjs.com/package/archaeopteryx
|
|
31
|
+
//
|
|
32
|
+
// Availability:
|
|
33
|
+
// https://github.com/cmzmasek/archaeopteryx-js
|
|
34
|
+
// https://www.npmjs.com/package/archaeopteryx
|
|
35
|
+
//
|
|
36
|
+
// Dependencies: none
|
|
37
|
+
//
|
|
38
|
+
//
|
|
39
|
+
// In the following is a basic example shows how to parse a New Hampshire formatted String
|
|
40
|
+
// into to a object representing a phylogenetic tree.
|
|
41
|
+
// Followed by pre- and post-order traversal,
|
|
42
|
+
// and writing back to a New Hampshire formatted String.
|
|
43
|
+
//
|
|
44
|
+
// Change './forester' to 'forester' if you use this code outside of this package
|
|
45
|
+
//
|
|
46
|
+
// let forester = require('./forester').forester;
|
|
47
|
+
//
|
|
48
|
+
// let newHampshireFormattedString = "(((a:1,b:1,c:1)N:2,(d:1,e:1)M:4)O:4,f:1)R:1;";
|
|
49
|
+
// let phylogeneticTree = forester.parseNewHampshire(newHampshireFormattedString);
|
|
50
|
+
//
|
|
51
|
+
// console.log('Pre-order traversal:');
|
|
52
|
+
// forester.preOrderTraversalAll(forester.getTreeRoot(phylogeneticTree), function (n) {
|
|
53
|
+
// console.log(n.name + ':' + n.branch_length);
|
|
54
|
+
// });
|
|
55
|
+
//
|
|
56
|
+
// console.log('Post-order traversal:');
|
|
57
|
+
// forester.postOrderTraversalAll(forester.getTreeRoot(phylogeneticTree), function (n) {
|
|
58
|
+
// console.log(n.name + ':' + n.branch_length);
|
|
59
|
+
// });
|
|
60
|
+
//
|
|
61
|
+
// console.log('In New Hampshire format:');
|
|
62
|
+
// let nh = forester.toNewHampshire(phylogeneticTree);
|
|
63
|
+
// console.log(nh);
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
(function forester() {
|
|
67
|
+
|
|
68
|
+
"use strict";
|
|
69
|
+
|
|
70
|
+
const BRANCH_EVENT_REF = 'aptx:branch_event';
|
|
71
|
+
const BRANCH_EVENT_DATATYPE = 'xsd:string';
|
|
72
|
+
const BRANCH_EVENT_APPLIES_TO = 'parent_branch';
|
|
73
|
+
const NH_FORMAT_ERR = 'New Hampshire (Newick) format error: ';
|
|
74
|
+
|
|
75
|
+
const NUMBERS_ONLY_PATTERN = /^[-+]?[0-9\\.]+$/;
|
|
76
|
+
|
|
77
|
+
const MSA_RESIDUE_SORT_MAP = new Map();
|
|
78
|
+
MSA_RESIDUE_SORT_MAP.set('A', 0);
|
|
79
|
+
MSA_RESIDUE_SORT_MAP.set('C', 1);
|
|
80
|
+
MSA_RESIDUE_SORT_MAP.set('D', 2);
|
|
81
|
+
MSA_RESIDUE_SORT_MAP.set('E', 3);
|
|
82
|
+
MSA_RESIDUE_SORT_MAP.set('F', 4);
|
|
83
|
+
MSA_RESIDUE_SORT_MAP.set('G', 5);
|
|
84
|
+
MSA_RESIDUE_SORT_MAP.set('H', 6);
|
|
85
|
+
MSA_RESIDUE_SORT_MAP.set('I', 7);
|
|
86
|
+
MSA_RESIDUE_SORT_MAP.set('K', 8);
|
|
87
|
+
MSA_RESIDUE_SORT_MAP.set('L', 9);
|
|
88
|
+
MSA_RESIDUE_SORT_MAP.set('M', 10);
|
|
89
|
+
MSA_RESIDUE_SORT_MAP.set('N', 11);
|
|
90
|
+
MSA_RESIDUE_SORT_MAP.set('P', 12);
|
|
91
|
+
MSA_RESIDUE_SORT_MAP.set('Q', 13);
|
|
92
|
+
MSA_RESIDUE_SORT_MAP.set('R', 14);
|
|
93
|
+
MSA_RESIDUE_SORT_MAP.set('S', 15);
|
|
94
|
+
MSA_RESIDUE_SORT_MAP.set('T', 16);
|
|
95
|
+
MSA_RESIDUE_SORT_MAP.set('U', 17);// Uracil
|
|
96
|
+
MSA_RESIDUE_SORT_MAP.set('V', 18);
|
|
97
|
+
MSA_RESIDUE_SORT_MAP.set('W', 19);
|
|
98
|
+
MSA_RESIDUE_SORT_MAP.set('Y', 20);
|
|
99
|
+
MSA_RESIDUE_SORT_MAP.set('B', 21);// Asparagine or aspartic acid
|
|
100
|
+
MSA_RESIDUE_SORT_MAP.set('Z', 22);// Glutamine or glutamic acid
|
|
101
|
+
MSA_RESIDUE_SORT_MAP.set('X', 23);
|
|
102
|
+
MSA_RESIDUE_SORT_MAP.set('?', 24);
|
|
103
|
+
MSA_RESIDUE_SORT_MAP.set('-', 25);
|
|
104
|
+
MSA_RESIDUE_SORT_MAP.set('.', 26);
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Sets links to parent nodes for all nodes in a
|
|
109
|
+
* phyloXML-based tree object
|
|
110
|
+
*
|
|
111
|
+
* @param phy - A phyloXML-based tree object.
|
|
112
|
+
*/
|
|
113
|
+
forester.addParents = function (phy) {
|
|
114
|
+
if (phy.children) {
|
|
115
|
+
for (let i = phy.children.length - 1; i >= 0; --i) {
|
|
116
|
+
let c = phy.children[i];
|
|
117
|
+
c.parent = phy;
|
|
118
|
+
forester.addParents(c);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Returns the real root node of a
|
|
125
|
+
* phyloXML-based tree object.
|
|
126
|
+
* Precondition: needs to have parents set.
|
|
127
|
+
*
|
|
128
|
+
* @param phy - A phyloXML-based tree object or node.
|
|
129
|
+
* @returns {*} - The real tree root node.
|
|
130
|
+
*/
|
|
131
|
+
forester.getTreeRoot = function (phy) {
|
|
132
|
+
let root = phy;
|
|
133
|
+
if (!root.parent && root.children && root.children.length === 1) {
|
|
134
|
+
root = root.children[0];
|
|
135
|
+
}
|
|
136
|
+
while (root.parent && root.parent.parent) {
|
|
137
|
+
root = root.parent;
|
|
138
|
+
}
|
|
139
|
+
return root;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Visits all non-collapsed child nodes of a node
|
|
144
|
+
* while applying a function in pre-order.
|
|
145
|
+
*
|
|
146
|
+
* @param node - The root of the subtree to traverse.
|
|
147
|
+
* @param fn - The function to apply.
|
|
148
|
+
*/
|
|
149
|
+
forester.preOrderTraversal = function (node, fn) {
|
|
150
|
+
fn(node);
|
|
151
|
+
if (node.children) {
|
|
152
|
+
for (let i = node.children.length - 1; i >= 0; --i) {
|
|
153
|
+
forester.preOrderTraversal(node.children[i], fn);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Visits all child nodes of a node
|
|
160
|
+
* while applying a function in pre-order.
|
|
161
|
+
*
|
|
162
|
+
* @param node - The root of the subtree to traverse.
|
|
163
|
+
* @param fn - The function to apply.
|
|
164
|
+
*/
|
|
165
|
+
forester.preOrderTraversalAll = function (node, fn) {
|
|
166
|
+
fn(node);
|
|
167
|
+
if (node.children) {
|
|
168
|
+
for (let i = node.children.length - 1; i >= 0; --i) {
|
|
169
|
+
forester.preOrderTraversalAll(node.children[i], fn);
|
|
170
|
+
}
|
|
171
|
+
} else if (node._children) {
|
|
172
|
+
for (let ii = node._children.length - 1; ii >= 0; --ii) {
|
|
173
|
+
forester.preOrderTraversalAll(node._children[ii], fn);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
forester.postOrderTraversalAll = function (node, fn) {
|
|
179
|
+
if (node.children) {
|
|
180
|
+
let l = node.children.length;
|
|
181
|
+
for (let i = 0; i < l; ++i) {
|
|
182
|
+
forester.postOrderTraversalAll(node.children[i], fn);
|
|
183
|
+
}
|
|
184
|
+
} else if (node._children) {
|
|
185
|
+
let ll = node._children.length;
|
|
186
|
+
for (let ii = 0; ii < ll; ++ii) {
|
|
187
|
+
forester.postOrderTraversalAll(node._children[ii], fn);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
fn(node);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
forester.findByNodeName = function (node, name) {
|
|
195
|
+
let found = [];
|
|
196
|
+
forester.preOrderTraversalAll(node, function (n) {
|
|
197
|
+
if (n.name === name) {
|
|
198
|
+
found.push(n);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
return found;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
forester.findByTaxonomyCode = function (node, code) {
|
|
205
|
+
let found = [];
|
|
206
|
+
forester.preOrderTraversalAll(node, function (n) {
|
|
207
|
+
if (n.taxonomies && n.taxonomies.length > 0 && n.taxonomies[0].code === code) {
|
|
208
|
+
found.push(n);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
return found;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
forester.findByTaxonomyScientificName = function (node, scientificName) {
|
|
215
|
+
let found = [];
|
|
216
|
+
forester.preOrderTraversalAll(node, function (n) {
|
|
217
|
+
if (n.taxonomies && n.taxonomies.length > 0 && n.taxonomies[0].scientific_name === scientificName) {
|
|
218
|
+
found.push(n);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
return found;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
forester.filterByNodeProperty = function (positive, phy, propertyMap) {
|
|
226
|
+
if (!phy) {
|
|
227
|
+
throw ("cannot delete null tree");
|
|
228
|
+
}
|
|
229
|
+
if (!propertyMap) {
|
|
230
|
+
throw ("property list is null");
|
|
231
|
+
}
|
|
232
|
+
const toDelete = [];
|
|
233
|
+
forester.preOrderTraversalAll(phy, function (n) {
|
|
234
|
+
if (!n.children && !n._children) {
|
|
235
|
+
if (n.properties && n.properties.length > 0) {
|
|
236
|
+
const propertiesLength = n.properties.length;
|
|
237
|
+
for (let i = 0; i < propertiesLength; ++i) {
|
|
238
|
+
const property = n.properties[i];
|
|
239
|
+
if (property.ref && property.value && property.applies_to === 'node') {
|
|
240
|
+
if (positive) {
|
|
241
|
+
if (property.ref in propertyMap && !propertyMap[property.ref].includes(property.value)) {
|
|
242
|
+
toDelete.push(n);
|
|
243
|
+
}
|
|
244
|
+
} else {
|
|
245
|
+
if (property.ref in propertyMap && propertyMap[property.ref].includes(property.value)) {
|
|
246
|
+
toDelete.push(n);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
const l = toDelete.length;
|
|
255
|
+
console.log(toDelete);
|
|
256
|
+
for (let i = 0; i < l; ++i) {
|
|
257
|
+
forester.deleteSubtree(phy, toDelete[i]);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* To delete a sub-tree or external node.
|
|
264
|
+
*
|
|
265
|
+
* @param phy
|
|
266
|
+
* @param nodeToDelete
|
|
267
|
+
*/
|
|
268
|
+
forester.deleteSubtree = function (phy, nodeToDelete) {
|
|
269
|
+
if (!phy) {
|
|
270
|
+
throw ("cannot delete null tree");
|
|
271
|
+
}
|
|
272
|
+
if (!nodeToDelete) {
|
|
273
|
+
throw ("cannot delete null node");
|
|
274
|
+
}
|
|
275
|
+
if (!nodeToDelete.parent || !nodeToDelete.parent.parent) {
|
|
276
|
+
throw ("cannot delete root");
|
|
277
|
+
}
|
|
278
|
+
if (!nodeToDelete.parent.parent.parent) {
|
|
279
|
+
throw ("cannot delete direct child of root");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
let p = nodeToDelete.parent;
|
|
283
|
+
|
|
284
|
+
if ((p.children) && (p.children.length > 1)) {
|
|
285
|
+
let i = p.children.indexOf(nodeToDelete);
|
|
286
|
+
if (i !== -1) {
|
|
287
|
+
p.children.splice(i, 1);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if ((p._children) && (p._children.length > 1)) {
|
|
291
|
+
let ii = p._children.indexOf(nodeToDelete);
|
|
292
|
+
if (ii !== -1) {
|
|
293
|
+
p._children.splice(ii, 1);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (p.children.length === 1) {
|
|
298
|
+
let pp = p.parent;
|
|
299
|
+
let cni = forester.getChildNodeIndex(pp, p);
|
|
300
|
+
if ((cni < 0) || (cni > (pp.children.length - 1))) {
|
|
301
|
+
throw ("this should never have happened, child node index = " + cni);
|
|
302
|
+
}
|
|
303
|
+
let x = p.children[0];
|
|
304
|
+
let nbl = undefined;
|
|
305
|
+
if (x.branch_length || p.branch_length) {
|
|
306
|
+
nbl = (x.branch_length > 0 ? x.branch_length : 0) + (p.branch_length > 0 ? p.branch_length : 0);
|
|
307
|
+
}
|
|
308
|
+
x.parent = pp;
|
|
309
|
+
pp.children[cni] = x;
|
|
310
|
+
x.branch_length = nbl;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* To re-root a tree object.
|
|
318
|
+
*
|
|
319
|
+
* @param phy - The tree to be re-rooted.
|
|
320
|
+
* @param node - The node on where to place the new root (on its parent branch).
|
|
321
|
+
* @param branchLength - The branch length to use if new root is not placed in the middle (if
|
|
322
|
+
* non-negative).
|
|
323
|
+
*/
|
|
324
|
+
forester.reRoot = function (phy, node, branchLength) {
|
|
325
|
+
if (!phy) {
|
|
326
|
+
throw ("cannot re-root null tree");
|
|
327
|
+
}
|
|
328
|
+
if (!node) {
|
|
329
|
+
throw ("cannot re-root on null node");
|
|
330
|
+
}
|
|
331
|
+
if (!branchLength) {
|
|
332
|
+
branchLength = -1;
|
|
333
|
+
}
|
|
334
|
+
if (forester.isString(node)) {
|
|
335
|
+
let nodes = forester.findByNodeName(phy, node);
|
|
336
|
+
if (nodes.length > 1) {
|
|
337
|
+
throw ("node name '" + node + "' is not unique");
|
|
338
|
+
} else if (nodes.length < 1) {
|
|
339
|
+
throw ("node name '" + node + "' is not found");
|
|
340
|
+
}
|
|
341
|
+
node = nodes[0];
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
phy.rooted = true;
|
|
345
|
+
let root = forester.getTreeRoot(phy);
|
|
346
|
+
|
|
347
|
+
if (!node.parent || !node.parent.parent) {
|
|
348
|
+
//do noting
|
|
349
|
+
} else if (!node.parent.parent.parent) {
|
|
350
|
+
if ((node.parent.children.length === 2) && (branchLength >= 0)) {
|
|
351
|
+
let d = node.parent.children[0].branch_length + node.parent.children[1].branch_length;
|
|
352
|
+
let other;
|
|
353
|
+
if (node.parent.children[0] === node) {
|
|
354
|
+
other = node.parent.children[1];
|
|
355
|
+
} else {
|
|
356
|
+
other = node.parent.children[0];
|
|
357
|
+
}
|
|
358
|
+
node.branch_length = branchLength;
|
|
359
|
+
let dm = d - branchLength;
|
|
360
|
+
if (dm >= 0) {
|
|
361
|
+
other.branch_length = dm;
|
|
362
|
+
} else {
|
|
363
|
+
other.branch_length = 0;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
if (node.parent.children.length > 2) {
|
|
367
|
+
let index = forester.getChildNodeIndex(node.parent, node);
|
|
368
|
+
let dn = node.branch_length;
|
|
369
|
+
let prev_root = root;
|
|
370
|
+
prev_root.children.splice(index, 1);
|
|
371
|
+
let nr = {};
|
|
372
|
+
nr.children = [];
|
|
373
|
+
forester.setChildNode(nr, 0, node);
|
|
374
|
+
forester.setChildNode(nr, 1, prev_root);
|
|
375
|
+
|
|
376
|
+
forester.copyBranchData(node, prev_root);
|
|
377
|
+
|
|
378
|
+
phy.children[0] = nr;
|
|
379
|
+
nr.parent = phy;
|
|
380
|
+
if (branchLength >= 0) {
|
|
381
|
+
node.branch_length = branchLength;
|
|
382
|
+
let dnmp = dn - branchLength;
|
|
383
|
+
if (dnmp >= 0) {
|
|
384
|
+
prev_root.branch_length = dnmp;
|
|
385
|
+
} else {
|
|
386
|
+
prev_root.branch_length = 0;
|
|
387
|
+
}
|
|
388
|
+
} else {
|
|
389
|
+
if (dn >= 0) {
|
|
390
|
+
let dn2 = dn / 2.0;
|
|
391
|
+
node.branch_length = dn2;
|
|
392
|
+
prev_root.branch_length = dn2;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
} else {
|
|
397
|
+
let a = node;
|
|
398
|
+
let new_root = {};
|
|
399
|
+
let distance1;
|
|
400
|
+
let distance2 = 0.0;
|
|
401
|
+
let branch_data_1;
|
|
402
|
+
let branch_data_2 = null;
|
|
403
|
+
let b = a.parent;
|
|
404
|
+
let c = b.parent;
|
|
405
|
+
|
|
406
|
+
new_root.children = [];
|
|
407
|
+
forester.setChildNode(new_root, 0, a);
|
|
408
|
+
forester.setChildNode(new_root, 1, b);
|
|
409
|
+
|
|
410
|
+
distance1 = c.branch_length;
|
|
411
|
+
|
|
412
|
+
branch_data_1 = forester.getBranchData(c);
|
|
413
|
+
|
|
414
|
+
c.branch_length = b.branch_length;
|
|
415
|
+
|
|
416
|
+
forester.copyBranchData(b, c);
|
|
417
|
+
forester.copyBranchData(a, b);
|
|
418
|
+
|
|
419
|
+
// New root is always placed in the middle of the branch:
|
|
420
|
+
if (!a.branch_length) {
|
|
421
|
+
b.branch_length = undefined;
|
|
422
|
+
} else {
|
|
423
|
+
if (branchLength >= 0.0) {
|
|
424
|
+
let diff = a.branch_length - branchLength;
|
|
425
|
+
a.branch_length = branchLength;
|
|
426
|
+
b.branch_length = (diff >= 0.0 ? diff : 0.0);
|
|
427
|
+
} else {
|
|
428
|
+
let d2 = a.branch_length / 2.0;
|
|
429
|
+
a.branch_length = d2;
|
|
430
|
+
b.branch_length = d2;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
setChildNodeOnly(b, forester.getChildNodeIndex(b, a), c);
|
|
434
|
+
// moving to the old root, swapping references:
|
|
435
|
+
while (c.parent.parent) {
|
|
436
|
+
a = b;
|
|
437
|
+
b = c;
|
|
438
|
+
c = c.parent;
|
|
439
|
+
setChildNodeOnly(b, forester.getChildNodeIndex(b, a), c);
|
|
440
|
+
b.parent = a;
|
|
441
|
+
distance2 = c.branch_length;
|
|
442
|
+
branch_data_2 = forester.getBranchData(c);
|
|
443
|
+
c.branch_length = distance1;
|
|
444
|
+
forester.setBranchData(c, branch_data_1);
|
|
445
|
+
distance1 = distance2;
|
|
446
|
+
branch_data_1 = branch_data_2;
|
|
447
|
+
}
|
|
448
|
+
// removing the old root:
|
|
449
|
+
if (c.children.length === 2) {
|
|
450
|
+
let node2 = c.children[1 - forester.getChildNodeIndex(c, b)];
|
|
451
|
+
node2.parent = b;
|
|
452
|
+
if ((!c.branch_length) && (!node2.branch_length)) {
|
|
453
|
+
node2.branch_length = undefined;
|
|
454
|
+
} else {
|
|
455
|
+
node2.branch_length = (c.branch_length >= 0.0 ? c.branch_length : 0.0) + (node2.branch_length >= 0.0 ? node2.branch_length : 0.0);
|
|
456
|
+
}
|
|
457
|
+
let cbd = forester.getBranchData(c);
|
|
458
|
+
if (cbd) {
|
|
459
|
+
forester.setBranchData(node2, cbd);
|
|
460
|
+
}
|
|
461
|
+
let l = b.children.length;
|
|
462
|
+
for (let i = 0; i < l; ++i) {
|
|
463
|
+
if (b.children[i] === c) {
|
|
464
|
+
setChildNodeOnly(b, i, node2);
|
|
465
|
+
break;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
} else {
|
|
469
|
+
c.parent = b;
|
|
470
|
+
forester.removeChildNode(c, forester.getChildNodeIndex(c, b));
|
|
471
|
+
}
|
|
472
|
+
phy.children[0] = new_root;
|
|
473
|
+
new_root.parent = phy;
|
|
474
|
+
forester.addParents(phy);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function setChildNodeOnly(parentNode, i, node) {
|
|
478
|
+
if (parentNode.children.length <= i) {
|
|
479
|
+
parentNode.children.push(node);
|
|
480
|
+
} else {
|
|
481
|
+
parentNode.children[i] = node;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
forester.midpointRoot = function (phy) {
|
|
487
|
+
let root = forester.getTreeRoot(phy);
|
|
488
|
+
let extNodes = forester.getAllExternalNodes(root);
|
|
489
|
+
if ((extNodes.length < 2) || (forester.calcMaxBranchLength(root) <= 0)) {
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
let counter = 0;
|
|
493
|
+
let totalNodes = forester.getAllNodes(phy).length;
|
|
494
|
+
while (true) {
|
|
495
|
+
if (++counter > (totalNodes + 1)) {
|
|
496
|
+
throw('this should not have happened: midpoint rooting does not converge');
|
|
497
|
+
}
|
|
498
|
+
let a = null;
|
|
499
|
+
let da = 0;
|
|
500
|
+
let db = 0;
|
|
501
|
+
let cl = forester.getTreeRoot(phy).children.length;
|
|
502
|
+
for (let i = 0; i < cl; ++i) {
|
|
503
|
+
let f = forester.getFurthestDescendant(forester.getTreeRoot(phy).children[i]);
|
|
504
|
+
let df = forester.getDistance(f, forester.getTreeRoot(phy));
|
|
505
|
+
if (df > 0) {
|
|
506
|
+
if (df > da) {
|
|
507
|
+
db = da;
|
|
508
|
+
da = df;
|
|
509
|
+
a = f;
|
|
510
|
+
} else if (df > db) {
|
|
511
|
+
db = df;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
let diff = da - db;
|
|
516
|
+
if (diff < 0.0001) {
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
let x = da - (diff / 2.0);
|
|
520
|
+
while ((x > a.branch_length) && a.parent) {
|
|
521
|
+
x -= (a.branch_length > 0 ? a.branch_length : 0);
|
|
522
|
+
a = a.parent;
|
|
523
|
+
}
|
|
524
|
+
forester.reRoot(phy, a, x);
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
forester.getFurthestDescendant = function (node) {
|
|
529
|
+
let children = forester.getAllExternalNodes(node);
|
|
530
|
+
let farthest = null;
|
|
531
|
+
let longest = -1000000;
|
|
532
|
+
let l = children.length;
|
|
533
|
+
for (let i = 0; i < l; ++i) {
|
|
534
|
+
let dist = forester.getDistance(children[i], node);
|
|
535
|
+
if (dist > longest) {
|
|
536
|
+
farthest = children[i];
|
|
537
|
+
longest = dist;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return farthest;
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Calculates the distance between PhylogenyNodes n1 and n2.
|
|
545
|
+
* PRECONDITION: n1 is a descendant of n2.
|
|
546
|
+
*
|
|
547
|
+
* @param n1 a descendant of n2
|
|
548
|
+
* @param n2
|
|
549
|
+
* @returns {number} distance between n1 and n2
|
|
550
|
+
*/
|
|
551
|
+
forester.getDistance = function (n1, n2) {
|
|
552
|
+
let d = 0.0;
|
|
553
|
+
while (n1 !== n2) {
|
|
554
|
+
if (n1.branch_length > 0.0) {
|
|
555
|
+
d += n1.branch_length;
|
|
556
|
+
}
|
|
557
|
+
n1 = n1.parent;
|
|
558
|
+
}
|
|
559
|
+
return d;
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
forester.removeChildNode = function (parentNode, i) {
|
|
563
|
+
if (!parentNode.children) {
|
|
564
|
+
throw ("cannot remove the child node for a external node");
|
|
565
|
+
}
|
|
566
|
+
if ((i >= parentNode.children.length) || (i < 0)) {
|
|
567
|
+
throw ("attempt to get child node " + i + " of a node with " + parentNode.children.length + " child nodes.");
|
|
568
|
+
}
|
|
569
|
+
parentNode.children[i].parent = undefined;
|
|
570
|
+
parentNode.children.splice(i, 1);
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Inserts node node at the specified position i into the list of
|
|
576
|
+
* child nodes of parentNode. This does not allow null slots in the list of child nodes:
|
|
577
|
+
* If i is larger than the number of child nodes, node is just added to the
|
|
578
|
+
* list, not placed at index i.
|
|
579
|
+
*/
|
|
580
|
+
forester.setChildNode = function (parentNode, i, node) {
|
|
581
|
+
node.parent = parentNode;
|
|
582
|
+
if (parentNode.children.length <= i) {
|
|
583
|
+
parentNode.children.push(node);
|
|
584
|
+
} else {
|
|
585
|
+
parentNode.children[i] = node;
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
forester.getBranchData = function (node) {
|
|
591
|
+
let branchData = null;
|
|
592
|
+
if (node.width || node.color || node.confidences) {
|
|
593
|
+
branchData = {};
|
|
594
|
+
branchData.width = node.width;
|
|
595
|
+
branchData.color = node.color;
|
|
596
|
+
branchData.confidences = node.confidences;
|
|
597
|
+
}
|
|
598
|
+
return branchData;
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
forester.setBranchData = function (node, branchData) {
|
|
603
|
+
if (branchData) {
|
|
604
|
+
node.width = branchData.width;
|
|
605
|
+
node.color = branchData.color;
|
|
606
|
+
node.confidences = branchData.confidences;
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
forester.unCollapseAll = function (node) {
|
|
611
|
+
forester.preOrderTraversal(node, function (d) {
|
|
612
|
+
if (d._children) {
|
|
613
|
+
d.children = d._children;
|
|
614
|
+
d._children = null;
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
};
|
|
618
|
+
|
|
619
|
+
forester.copyBranchData = function (nodeFrom, nodeTo) {
|
|
620
|
+
nodeTo.width = nodeFrom.width;
|
|
621
|
+
nodeTo.color = nodeFrom.color;
|
|
622
|
+
nodeTo.confidences = nodeFrom.confidences;
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
forester.getChildNodeIndex = function (parentNode, childNode) {
|
|
627
|
+
if (!parentNode) {
|
|
628
|
+
throw ("cannot get the child index for a root node");
|
|
629
|
+
}
|
|
630
|
+
let c = parentNode.children.length;
|
|
631
|
+
for (let i = 0; i < c; ++i) {
|
|
632
|
+
if (parentNode.children[i] === childNode) {
|
|
633
|
+
return i;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
throw ("unexpected exception: Could not determine the child index for a node");
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
forester.getChildren = function (node) {
|
|
641
|
+
return node._children ? node._children : (node.children ? node.children : []);
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
forester.calcAverageTreeHeight = function (node, externalDescendants) {
|
|
646
|
+
let c = externalDescendants ? externalDescendants : forester.getAllExternalNodes(node);
|
|
647
|
+
let l = c.length;
|
|
648
|
+
let s = 0;
|
|
649
|
+
for (let i = 0; i < l; ++i) {
|
|
650
|
+
let cc = c[i];
|
|
651
|
+
while (cc !== node) {
|
|
652
|
+
if (cc.branch_length > 0) {
|
|
653
|
+
s += cc.branch_length;
|
|
654
|
+
}
|
|
655
|
+
cc = cc.parent;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
return s / l;
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
forester.setToArray = function (set) {
|
|
662
|
+
let array = [];
|
|
663
|
+
if (set) {
|
|
664
|
+
set.forEach(function (e) {
|
|
665
|
+
array.push(e);
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
return array;
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
forester.setToSortedArray = function (set) {
|
|
672
|
+
let array = [];
|
|
673
|
+
if (set) {
|
|
674
|
+
set.forEach(function (e) {
|
|
675
|
+
array.push(e);
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
return array.sort();
|
|
679
|
+
};
|
|
680
|
+
|
|
681
|
+
forester.calcMinMaxInSet = function (set) {
|
|
682
|
+
let array = [];
|
|
683
|
+
let first = true;
|
|
684
|
+
let min = 0;
|
|
685
|
+
let max = 0;
|
|
686
|
+
if (set) {
|
|
687
|
+
set.forEach(function (e) {
|
|
688
|
+
e = parseFloat(e);
|
|
689
|
+
if (first) {
|
|
690
|
+
first = false;
|
|
691
|
+
min = e;
|
|
692
|
+
max = e;
|
|
693
|
+
} else {
|
|
694
|
+
if (e < min) {
|
|
695
|
+
min = e;
|
|
696
|
+
}
|
|
697
|
+
if (e > max) {
|
|
698
|
+
max = e;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
array[0] = min;
|
|
704
|
+
array[1] = max;
|
|
705
|
+
return array;
|
|
706
|
+
};
|
|
707
|
+
|
|
708
|
+
forester.calcMinMeanMaxInSet = function (set) {
|
|
709
|
+
let array = [];
|
|
710
|
+
let first = true;
|
|
711
|
+
let min = 0;
|
|
712
|
+
let max = 0;
|
|
713
|
+
let mean = 0;
|
|
714
|
+
let sum = 0;
|
|
715
|
+
let n = 0;
|
|
716
|
+
if (set) {
|
|
717
|
+
set.forEach(function (e) {
|
|
718
|
+
e = parseFloat(e);
|
|
719
|
+
++n;
|
|
720
|
+
sum += e;
|
|
721
|
+
if (first) {
|
|
722
|
+
first = false;
|
|
723
|
+
min = e;
|
|
724
|
+
max = e;
|
|
725
|
+
} else {
|
|
726
|
+
if (e < min) {
|
|
727
|
+
min = e;
|
|
728
|
+
}
|
|
729
|
+
if (e > max) {
|
|
730
|
+
max = e;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
if (n > 0) {
|
|
736
|
+
mean = sum / n;
|
|
737
|
+
}
|
|
738
|
+
array[0] = min;
|
|
739
|
+
array[1] = mean;
|
|
740
|
+
array[2] = max;
|
|
741
|
+
return array;
|
|
742
|
+
};
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* This collects all properties in a tree
|
|
747
|
+
* and returns them as dictionary of Sets mapping
|
|
748
|
+
* keys to values.
|
|
749
|
+
* It only collects properly formed properties
|
|
750
|
+
* (as per phyloXML standard), which means
|
|
751
|
+
* that 'applies_to' and 'datatype' have to be present.
|
|
752
|
+
*
|
|
753
|
+
*
|
|
754
|
+
* @param phy - A phyloXML-based tree object or node.
|
|
755
|
+
* @param appliesTo - 'phylogeny', 'clade', 'node', 'annotation', 'parent_branch', or 'other'.
|
|
756
|
+
* @param externalOnly - To collect from external nodes only.
|
|
757
|
+
* @returns {{}}
|
|
758
|
+
*/
|
|
759
|
+
forester.collectProperties = function (phy, appliesTo, externalOnly) {
|
|
760
|
+
let props = {};
|
|
761
|
+
forester.preOrderTraversalAll(phy, function (n) {
|
|
762
|
+
|
|
763
|
+
if (!externalOnly || externalOnly !== true || (!n.children && !n._children)) {
|
|
764
|
+
if (n.properties && n.properties.length > 0) {
|
|
765
|
+
let propertiesLength = n.properties.length;
|
|
766
|
+
for (let i = 0; i < propertiesLength; ++i) {
|
|
767
|
+
let property = n.properties[i];
|
|
768
|
+
if (property.ref && property.value && property.datatype && property.applies_to && property.applies_to === appliesTo) {
|
|
769
|
+
let ref = property.ref;
|
|
770
|
+
if (!props[ref]) {
|
|
771
|
+
props[ref] = new Set();
|
|
772
|
+
}
|
|
773
|
+
props[ref].add(property.value);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
return props;
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
/**
|
|
784
|
+
*
|
|
785
|
+
* Special method for IRD database.
|
|
786
|
+
* Returns true if at least one 'ird:Host' property with 'Avian' found
|
|
787
|
+
*
|
|
788
|
+
* @param phy
|
|
789
|
+
* @param targetValue
|
|
790
|
+
* @param fromRef
|
|
791
|
+
* @param toRef
|
|
792
|
+
* @returns {boolean}
|
|
793
|
+
*/
|
|
794
|
+
forester.splitProperty = function (phy, targetValue, fromRef, toRef) {
|
|
795
|
+
let found = false;
|
|
796
|
+
let targetValue_ = targetValue + ' ';
|
|
797
|
+
forester.preOrderTraversalAll(phy, function (n) {
|
|
798
|
+
if (n.properties && n.properties.length > 0) {
|
|
799
|
+
let propertiesLength = n.properties.length;
|
|
800
|
+
for (let i = 0; i < propertiesLength; ++i) {
|
|
801
|
+
let property = n.properties[i];
|
|
802
|
+
if (property.ref === fromRef && property.value) {
|
|
803
|
+
let newValue = '';
|
|
804
|
+
if (property.value.startsWith(targetValue_)) {
|
|
805
|
+
newValue = targetValue;
|
|
806
|
+
found = true;
|
|
807
|
+
} else {
|
|
808
|
+
newValue = property.value;
|
|
809
|
+
}
|
|
810
|
+
let newproperty = {};
|
|
811
|
+
newproperty.ref = toRef;
|
|
812
|
+
newproperty.value = newValue;
|
|
813
|
+
newproperty.datatype = 'xsd:string';
|
|
814
|
+
newproperty.applies_to = 'node';
|
|
815
|
+
n.properties.push(newproperty);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
});
|
|
820
|
+
return found;
|
|
821
|
+
};
|
|
822
|
+
|
|
823
|
+
forester.collectPropertyRefs = function (phy, appliesTo, externalOnly) {
|
|
824
|
+
let propertyRefs = new Set();
|
|
825
|
+
forester.preOrderTraversalAll(phy, function (n) {
|
|
826
|
+
|
|
827
|
+
if (!externalOnly || externalOnly !== true || (!n.children && !n._children)) {
|
|
828
|
+
if (n.properties && n.properties.length > 0) {
|
|
829
|
+
let propertiesLength = n.properties.length;
|
|
830
|
+
for (let i = 0; i < propertiesLength; ++i) {
|
|
831
|
+
let property = n.properties[i];
|
|
832
|
+
if (property.ref && property.value && property.datatype && property.applies_to && property.applies_to === appliesTo) {
|
|
833
|
+
propertyRefs.add(property.ref);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
return propertyRefs;
|
|
840
|
+
};
|
|
841
|
+
|
|
842
|
+
|
|
843
|
+
forester.shortenProperties = function (phy, appliesTo, externalOnly, sourceRef, targetRef) {
|
|
844
|
+
forester.preOrderTraversalAll(phy, function (n) {
|
|
845
|
+
if (!externalOnly || externalOnly !== true || (!n.children && !n._children)) {
|
|
846
|
+
if (n.properties && n.properties.length > 0) {
|
|
847
|
+
let propertiesLength = n.properties.length;
|
|
848
|
+
for (let i = 0; i < propertiesLength; ++i) {
|
|
849
|
+
let property = n.properties[i];
|
|
850
|
+
if (property.ref && property.value && property.datatype && property.applies_to && property.applies_to === appliesTo) {
|
|
851
|
+
if (property.ref === sourceRef) {
|
|
852
|
+
let s = property.value.trim().split(/\s+/);
|
|
853
|
+
if (s && s.length > 1) {
|
|
854
|
+
let newProp = {};
|
|
855
|
+
newProp.ref = targetRef;
|
|
856
|
+
if (s.length === 2) {
|
|
857
|
+
newProp.value = s[0];
|
|
858
|
+
} else {
|
|
859
|
+
newProp.value = s[0] + ' ' + s[1];
|
|
860
|
+
}
|
|
861
|
+
newProp.datatype = property.datatype;
|
|
862
|
+
newProp.applies_to = property.applies_to;
|
|
863
|
+
n.properties.push(newProp);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
});
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
forester.collectBasicTreeProperties = function (tree) {
|
|
874
|
+
let properties = {};
|
|
875
|
+
properties.internalNodeData = false;
|
|
876
|
+
properties.nodeNames = false;
|
|
877
|
+
properties.longestNodeName = 0;
|
|
878
|
+
properties.branchLengths = false;
|
|
879
|
+
properties.confidences = false;
|
|
880
|
+
properties.nodeEvents = false;
|
|
881
|
+
properties.sequences = false;
|
|
882
|
+
properties.taxonomies = false;
|
|
883
|
+
properties.alignedMolSeqs = true;
|
|
884
|
+
properties.maxMolSeqLength = 0;
|
|
885
|
+
properties.externalNodesCount = 0;
|
|
886
|
+
properties.molSeqResiduesPerPosition = null;
|
|
887
|
+
properties.averageBranchLength = 0;
|
|
888
|
+
let bl_counter = 0;
|
|
889
|
+
let bl_sum = 0;
|
|
890
|
+
let molSeqs = [];
|
|
891
|
+
forester.preOrderTraversalAll(tree, function (n) {
|
|
892
|
+
if (n.name && n.name.length > 0) {
|
|
893
|
+
properties.nodeNames = true;
|
|
894
|
+
if (n.name.length > properties.longestNodeName) {
|
|
895
|
+
properties.longestNodeName = n.name.length;
|
|
896
|
+
}
|
|
897
|
+
if ((n.children || n._children) && (n.parent)) {
|
|
898
|
+
properties.internalNodeData = true;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
if (!(n.children || n._children)) {
|
|
902
|
+
properties.externalNodesCount += 1;
|
|
903
|
+
}
|
|
904
|
+
if (n.branch_length && n.branch_length > 0) {
|
|
905
|
+
properties.branchLengths = true;
|
|
906
|
+
bl_sum += n.branch_length;
|
|
907
|
+
bl_counter += 1;
|
|
908
|
+
}
|
|
909
|
+
if (n.events) {
|
|
910
|
+
properties.nodeEvents = true;
|
|
911
|
+
}
|
|
912
|
+
if (n.sequences && n.sequences.length > 0) {
|
|
913
|
+
properties.sequences = true;
|
|
914
|
+
|
|
915
|
+
if (n.children || n._children) {
|
|
916
|
+
properties.internalNodeData = true;
|
|
917
|
+
} else {
|
|
918
|
+
let s = n.sequences[0];
|
|
919
|
+
if (s.mol_seq && s.mol_seq.value) {
|
|
920
|
+
if (s.mol_seq.value.length > properties.maxMolSeqLength) {
|
|
921
|
+
properties.maxMolSeqLength = s.mol_seq.value.length;
|
|
922
|
+
}
|
|
923
|
+
if (!s.mol_seq.is_aligned) {
|
|
924
|
+
properties.alignedMolSeqs = false;
|
|
925
|
+
} else {
|
|
926
|
+
molSeqs.push(s.mol_seq.value);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
if (n.taxonomies && n.taxonomies.length > 0) {
|
|
932
|
+
properties.taxonomies = true;
|
|
933
|
+
if (n.children || n._children) {
|
|
934
|
+
properties.internalNodeData = true;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
if (n.confidences && n.confidences.length > 0) {
|
|
938
|
+
properties.confidences = true;
|
|
939
|
+
}
|
|
940
|
+
if (n.properties && n.properties.length > 0) {
|
|
941
|
+
let l = n.properties.length;
|
|
942
|
+
for (let p = 0; p < l; ++p) {
|
|
943
|
+
if (n.properties[p].ref === BRANCH_EVENT_REF && n.properties[p].datatype === BRANCH_EVENT_DATATYPE && n.properties[p].applies_to === BRANCH_EVENT_APPLIES_TO) {
|
|
944
|
+
properties.branchEvents = true;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
});
|
|
950
|
+
|
|
951
|
+
if (properties.alignedMolSeqs) {
|
|
952
|
+
properties.molSeqResiduesPerPosition = [];
|
|
953
|
+
for (let p = 0, maxLen = properties.maxMolSeqLength; p < maxLen; ++p) {
|
|
954
|
+
let mySet = new Set();
|
|
955
|
+
for (let i = 0, seqsLen = molSeqs.length; i < seqsLen; ++i) {
|
|
956
|
+
let molSeq = molSeqs[i];
|
|
957
|
+
let c = molSeq[p];
|
|
958
|
+
if (c) {
|
|
959
|
+
c = c.toUpperCase();
|
|
960
|
+
mySet.add(c);
|
|
961
|
+
if (!MSA_RESIDUE_SORT_MAP.has(c)) {
|
|
962
|
+
throw ("Unknown MSA residue '" + c + "'");
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
}
|
|
967
|
+
let myArray = forester.setToArray(mySet);
|
|
968
|
+
myArray.sort(function (a, b) {
|
|
969
|
+
return MSA_RESIDUE_SORT_MAP.get(a) - MSA_RESIDUE_SORT_MAP.get(b);
|
|
970
|
+
});
|
|
971
|
+
properties.molSeqResiduesPerPosition.push(myArray);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
if (bl_counter > 0) {
|
|
976
|
+
properties.averageBranchLength = bl_sum / bl_counter;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
|
|
980
|
+
return properties;
|
|
981
|
+
};
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* This calculates the sum of the external
|
|
985
|
+
* descendants of a node. It does not count descendants
|
|
986
|
+
* of collapsed nodes.
|
|
987
|
+
*
|
|
988
|
+
* @param node - A node.
|
|
989
|
+
* @returns {number} - The sum of external descendants.
|
|
990
|
+
*/
|
|
991
|
+
forester.calcSumOfExternalDescendants = function (node) {
|
|
992
|
+
let nodes = 0;
|
|
993
|
+
forester.preOrderTraversal(node, function (n) {
|
|
994
|
+
if (!n.children) {
|
|
995
|
+
++nodes;
|
|
996
|
+
}
|
|
997
|
+
});
|
|
998
|
+
return nodes;
|
|
999
|
+
};
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* This calculates the sum of all the external
|
|
1003
|
+
* descendants of a node. It does count descendants
|
|
1004
|
+
* of collapsed nodes.
|
|
1005
|
+
*
|
|
1006
|
+
* @param node - A node.
|
|
1007
|
+
* @returns {number} - The sum of all external descendants.
|
|
1008
|
+
*/
|
|
1009
|
+
forester.calcSumOfAllExternalDescendants = function (node) {
|
|
1010
|
+
let nodes = 0;
|
|
1011
|
+
forester.preOrderTraversalAll(node, function (n) {
|
|
1012
|
+
if (!(n.children || n._children)) {
|
|
1013
|
+
++nodes;
|
|
1014
|
+
}
|
|
1015
|
+
});
|
|
1016
|
+
return nodes;
|
|
1017
|
+
};
|
|
1018
|
+
|
|
1019
|
+
/**
|
|
1020
|
+
* Returns true if at least one of the child nodes
|
|
1021
|
+
* of node is collapsed.
|
|
1022
|
+
*
|
|
1023
|
+
* @param node - A node.
|
|
1024
|
+
* @returns {boolean} - true if at least one of the child nodes is
|
|
1025
|
+
* collapsed
|
|
1026
|
+
*/
|
|
1027
|
+
forester.isHasCollapsedNodes = function (node) {
|
|
1028
|
+
let collapsed = false;
|
|
1029
|
+
forester.preOrderTraversalAll(node, function (n) {
|
|
1030
|
+
if (n._children) {
|
|
1031
|
+
collapsed = true;
|
|
1032
|
+
|
|
1033
|
+
}
|
|
1034
|
+
});
|
|
1035
|
+
return collapsed;
|
|
1036
|
+
};
|
|
1037
|
+
|
|
1038
|
+
forester.getAllExternalNodes = function (node) {
|
|
1039
|
+
let nodes = [];
|
|
1040
|
+
forester.preOrderTraversalAll(node, function (n) {
|
|
1041
|
+
if (!n.children && !n._children) {
|
|
1042
|
+
nodes.push(n);
|
|
1043
|
+
}
|
|
1044
|
+
});
|
|
1045
|
+
return nodes;
|
|
1046
|
+
};
|
|
1047
|
+
|
|
1048
|
+
forester.getAllNodes = function (phy) {
|
|
1049
|
+
let nodes = [];
|
|
1050
|
+
forester.preOrderTraversalAll(forester.getTreeRoot(phy), function (n) {
|
|
1051
|
+
nodes.push(n);
|
|
1052
|
+
});
|
|
1053
|
+
return nodes;
|
|
1054
|
+
};
|
|
1055
|
+
|
|
1056
|
+
forester.calcMaxDepth = function (node) {
|
|
1057
|
+
let max = 0;
|
|
1058
|
+
forester.preOrderTraversalAll(node, function (n) {
|
|
1059
|
+
if (!n.children && !n._children) {
|
|
1060
|
+
let steps = forester.calcDepth(n);
|
|
1061
|
+
if (steps > max) {
|
|
1062
|
+
max = steps;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
});
|
|
1066
|
+
return max;
|
|
1067
|
+
};
|
|
1068
|
+
|
|
1069
|
+
forester.calcDepth = function (node) {
|
|
1070
|
+
|
|
1071
|
+
let steps = 0;
|
|
1072
|
+
while (node.parent && node.parent.parent) {
|
|
1073
|
+
steps++;
|
|
1074
|
+
node = node.parent;
|
|
1075
|
+
}
|
|
1076
|
+
return steps;
|
|
1077
|
+
};
|
|
1078
|
+
|
|
1079
|
+
|
|
1080
|
+
forester.calcBranchLengthSimpleStatistics = function (node) {
|
|
1081
|
+
let stats = {};
|
|
1082
|
+
stats.mean = 0;
|
|
1083
|
+
stats.min = Number.MAX_VALUE;
|
|
1084
|
+
stats.max = 0;
|
|
1085
|
+
stats.n = 0;
|
|
1086
|
+
let sum = 0;
|
|
1087
|
+
forester.preOrderTraversalAll(node, function (n) {
|
|
1088
|
+
if (n !== node && n.branch_length && n.branch_length >= 0) {
|
|
1089
|
+
++stats.n;
|
|
1090
|
+
sum += n.branch_length;
|
|
1091
|
+
if (n.branch_length < stats.min) {
|
|
1092
|
+
stats.min = n.branch_length;
|
|
1093
|
+
}
|
|
1094
|
+
if (n.branch_length > stats.max) {
|
|
1095
|
+
stats.max = n.branch_length;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
});
|
|
1099
|
+
if (stats.n > 0) {
|
|
1100
|
+
stats.mean = sum / stats.n;
|
|
1101
|
+
}
|
|
1102
|
+
return stats;
|
|
1103
|
+
};
|
|
1104
|
+
|
|
1105
|
+
forester.calcMaxBranchLength = function (node) {
|
|
1106
|
+
let max = 0;
|
|
1107
|
+
forester.preOrderTraversalAll(node, function (n) {
|
|
1108
|
+
if (n !== node && n.branch_length && (n.branch_length > max)) {
|
|
1109
|
+
max = n.branch_length;
|
|
1110
|
+
}
|
|
1111
|
+
});
|
|
1112
|
+
return max;
|
|
1113
|
+
};
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
forester.isHasNodeData = function (node) {
|
|
1117
|
+
return ((node.name && node.name.length > 0) || (node.taxonomies && node.taxonomies.length > 0) || (node.sequences && node.sequences.length > 0) || (node.properties && node.properties.length > 0));
|
|
1118
|
+
};
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
forester.removeMaxBranchLength = function (node) {
|
|
1122
|
+
forester.preOrderTraversalAll(node, function (n) {
|
|
1123
|
+
if (n.max) {
|
|
1124
|
+
n.max = undefined;
|
|
1125
|
+
}
|
|
1126
|
+
});
|
|
1127
|
+
};
|
|
1128
|
+
|
|
1129
|
+
|
|
1130
|
+
forester.collapseToBranchLength = function (root, branchLength) {
|
|
1131
|
+
if (root.children && root.children.length === 1) {
|
|
1132
|
+
collapseToBranchLengthHelper(root.children[0], branchLength);
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
function collapseToBranchLengthHelper(n, branchLength) {
|
|
1136
|
+
if (!(n.children || n._children)) {
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
if (!n.max) {
|
|
1141
|
+
n.max = forester.calcMaxBranchLength(n);
|
|
1142
|
+
}
|
|
1143
|
+
let max = n.max;
|
|
1144
|
+
if (max < branchLength) {
|
|
1145
|
+
forester.collapse(n);
|
|
1146
|
+
} else {
|
|
1147
|
+
forester.unCollapse(n);
|
|
1148
|
+
for (let i = n.children.length - 1; i >= 0; i--) {
|
|
1149
|
+
collapseToBranchLengthHelper(n.children[i], branchLength);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
};
|
|
1154
|
+
|
|
1155
|
+
forester.collapseToDepth = function (root, depth) {
|
|
1156
|
+
if (root.children && root.children.length === 1) {
|
|
1157
|
+
collapseToDepthHelper(root.children[0], 0, depth);
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
function collapseToDepthHelper(n, d, depth) {
|
|
1161
|
+
if (!n.children && !n._children) {
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
if (d >= depth) {
|
|
1165
|
+
forester.collapse(n);
|
|
1166
|
+
} else {
|
|
1167
|
+
forester.unCollapse(n);
|
|
1168
|
+
++d;
|
|
1169
|
+
for (let i = n.children.length - 1; i >= 0; i--) {
|
|
1170
|
+
collapseToDepthHelper(n.children[i], d, depth);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
};
|
|
1175
|
+
|
|
1176
|
+
forester.collapse = function (node) {
|
|
1177
|
+
if (node.children) {
|
|
1178
|
+
node._children = node.children;
|
|
1179
|
+
node.children = null;
|
|
1180
|
+
}
|
|
1181
|
+
};
|
|
1182
|
+
|
|
1183
|
+
forester.unCollapse = function (node) {
|
|
1184
|
+
if (node._children) {
|
|
1185
|
+
node.children = node._children;
|
|
1186
|
+
node._children = null;
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
1189
|
+
|
|
1190
|
+
/**
|
|
1191
|
+
* To parse a New Hampshire (Newick) formatted tree.
|
|
1192
|
+
*
|
|
1193
|
+
* @param nhStr - A New Hampshire (Newick) formatted string.
|
|
1194
|
+
* @param confidenceValuesInBrackets - Set to true if confidence values are in brackets (default: true)
|
|
1195
|
+
* Format is: name:distance[confidence]
|
|
1196
|
+
* Example: "bcl2:0.000393[95]"
|
|
1197
|
+
* @param confidenceValuesAsInternalNames - Set to true if confidence values are represented by internal names (default: false).
|
|
1198
|
+
* @returns {{}} - A phylogenetic tree object.
|
|
1199
|
+
*/
|
|
1200
|
+
forester.parseNewHampshire = function (nhStr, confidenceValuesInBrackets, confidenceValuesAsInternalNames) {
|
|
1201
|
+
|
|
1202
|
+
let NH_FORMAT_ERR_OPEN_PARENS = NH_FORMAT_ERR + 'likely cause: number of open parentheses is larger than number of close parentheses';
|
|
1203
|
+
let NH_FORMAT_ERR_CLOSE_PARENS = NH_FORMAT_ERR + 'likely cause: number of close parentheses is larger than number of open parentheses';
|
|
1204
|
+
|
|
1205
|
+
if (confidenceValuesInBrackets === undefined) {
|
|
1206
|
+
confidenceValuesInBrackets = true;
|
|
1207
|
+
}
|
|
1208
|
+
if (confidenceValuesAsInternalNames === undefined) {
|
|
1209
|
+
confidenceValuesAsInternalNames = false;
|
|
1210
|
+
}
|
|
1211
|
+
if ((confidenceValuesInBrackets === true) && (confidenceValuesAsInternalNames === true)) {
|
|
1212
|
+
throw ("confidence values cannot be both in brackets and as internal node names");
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
let ancs = [];
|
|
1216
|
+
let x = {};
|
|
1217
|
+
|
|
1218
|
+
let sss = nhStr.replace(/\[\s*&.+?\]/g, '');
|
|
1219
|
+
|
|
1220
|
+
let ss = sss.split(/(;|\(|\)|,|:|"|')/);
|
|
1221
|
+
let ssl = ss.length;
|
|
1222
|
+
let in_double_q = false;
|
|
1223
|
+
let in_single_q = false;
|
|
1224
|
+
let buffer = '';
|
|
1225
|
+
for (let i = 0; i < ssl; ++i) {
|
|
1226
|
+
let element = ss[i].replace(/\s+/g, '');
|
|
1227
|
+
|
|
1228
|
+
if (element === '"' && !in_single_q) {
|
|
1229
|
+
if (!in_double_q) {
|
|
1230
|
+
in_double_q = true;
|
|
1231
|
+
} else {
|
|
1232
|
+
in_double_q = false;
|
|
1233
|
+
if (x.name && x.name.length > 0) {
|
|
1234
|
+
x.name = x.name + buffer;
|
|
1235
|
+
} else {
|
|
1236
|
+
x.name = buffer;
|
|
1237
|
+
}
|
|
1238
|
+
buffer = '';
|
|
1239
|
+
}
|
|
1240
|
+
} else if (element === "'" && !in_double_q) {
|
|
1241
|
+
if (!in_single_q) {
|
|
1242
|
+
in_single_q = true;
|
|
1243
|
+
} else {
|
|
1244
|
+
in_single_q = false;
|
|
1245
|
+
if (x.name && x.name.length > 0) {
|
|
1246
|
+
x.name = x.name + buffer;
|
|
1247
|
+
} else {
|
|
1248
|
+
x.name = buffer;
|
|
1249
|
+
}
|
|
1250
|
+
buffer = '';
|
|
1251
|
+
}
|
|
1252
|
+
} else {
|
|
1253
|
+
if (in_double_q || in_single_q) {
|
|
1254
|
+
buffer += ss[i].replace(/\s+/g, ' ');
|
|
1255
|
+
} else {
|
|
1256
|
+
if (element === '(') {
|
|
1257
|
+
if (!x) {
|
|
1258
|
+
throw (NH_FORMAT_ERR_CLOSE_PARENS);
|
|
1259
|
+
}
|
|
1260
|
+
let subtree1 = {};
|
|
1261
|
+
x.children = [subtree1];
|
|
1262
|
+
ancs.push(x);
|
|
1263
|
+
x = subtree1;
|
|
1264
|
+
} else if (element === ',') {
|
|
1265
|
+
if (ancs.length === 0) {
|
|
1266
|
+
throw (NH_FORMAT_ERR_CLOSE_PARENS);
|
|
1267
|
+
}
|
|
1268
|
+
let subtree2 = {};
|
|
1269
|
+
ancs[ancs.length - 1].children.push(subtree2);
|
|
1270
|
+
x = subtree2;
|
|
1271
|
+
} else if (element === ')') {
|
|
1272
|
+
x = ancs.pop();
|
|
1273
|
+
} else if (element === ':') {
|
|
1274
|
+
} else {
|
|
1275
|
+
let e = ss[i - 1];
|
|
1276
|
+
if (e) {
|
|
1277
|
+
e = e.trim();
|
|
1278
|
+
if ((e === ')') || (e === '(') || (e === ',')) {
|
|
1279
|
+
if (element && element.length > 0) {
|
|
1280
|
+
if (element.charAt(element.length - 1) === "]") {
|
|
1281
|
+
let o = element.indexOf('[');
|
|
1282
|
+
if (o > -1) {
|
|
1283
|
+
if (confidenceValuesInBrackets === true) {
|
|
1284
|
+
addConfidence(x, element);
|
|
1285
|
+
}
|
|
1286
|
+
x.name = element.substring(0, o);
|
|
1287
|
+
} else {
|
|
1288
|
+
x.name = element;
|
|
1289
|
+
}
|
|
1290
|
+
} else {
|
|
1291
|
+
x.name = element;
|
|
1292
|
+
let op = x.name.indexOf('[');
|
|
1293
|
+
if (op > -1) {
|
|
1294
|
+
let cl = x.name.indexOf(']');
|
|
1295
|
+
if (cl > op) {
|
|
1296
|
+
x.name = x.name.substring(0, op) + x.name.substring(cl + 1, x.name.length);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
} else if (e === ':') {
|
|
1302
|
+
if (element && element.length > 0) {
|
|
1303
|
+
if (element.charAt(element.length - 1) === ']') {
|
|
1304
|
+
let o1 = element.indexOf('[');
|
|
1305
|
+
if (o1 > -1) {
|
|
1306
|
+
if (confidenceValuesInBrackets === true) {
|
|
1307
|
+
addConfidence(x, element);
|
|
1308
|
+
}
|
|
1309
|
+
let bl = parseFloat(element.substring(0, o1));
|
|
1310
|
+
if (forester.isNumber(bl)) {
|
|
1311
|
+
x.branch_length = bl;
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
} else {
|
|
1315
|
+
let b = parseFloat(element);
|
|
1316
|
+
if (forester.isNumber(b)) {
|
|
1317
|
+
x.branch_length = b;
|
|
1318
|
+
} else {
|
|
1319
|
+
throw (NH_FORMAT_ERR + 'could not parse branch-length from "' + element + '"');
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
} else if (e === '"' || e === "'") {
|
|
1324
|
+
if ((element && element.length > 0) && (x.name && x.name.length > 0)) {
|
|
1325
|
+
if (element.charAt(element.length - 1) === "]") {
|
|
1326
|
+
let opp = element.indexOf('[');
|
|
1327
|
+
if (opp > -1) {
|
|
1328
|
+
if (confidenceValuesInBrackets === true) {
|
|
1329
|
+
addConfidence(x, element);
|
|
1330
|
+
}
|
|
1331
|
+
x.name = x.name + element.substring(0, opp);
|
|
1332
|
+
} else {
|
|
1333
|
+
x.name = x.name + element;
|
|
1334
|
+
}
|
|
1335
|
+
} else {
|
|
1336
|
+
x.name = x.name + element;
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
if (ancs.length !== 0) {
|
|
1347
|
+
throw (NH_FORMAT_ERR_OPEN_PARENS);
|
|
1348
|
+
}
|
|
1349
|
+
if (!x) {
|
|
1350
|
+
throw (NH_FORMAT_ERR_CLOSE_PARENS);
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
let phy = {};
|
|
1354
|
+
phy.children = [x];
|
|
1355
|
+
|
|
1356
|
+
forester.addParents(phy);
|
|
1357
|
+
|
|
1358
|
+
if (confidenceValuesAsInternalNames === true) {
|
|
1359
|
+
moveInternalNodeNamesToConfidenceValues(phy);
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
return phy;
|
|
1363
|
+
|
|
1364
|
+
function addConfidence(x, element) {
|
|
1365
|
+
let confValue = parseConfidence(element);
|
|
1366
|
+
if (confValue != null) {
|
|
1367
|
+
x.confidences = [];
|
|
1368
|
+
let conf = {};
|
|
1369
|
+
conf.value = confValue;
|
|
1370
|
+
conf.type = 'unknown';
|
|
1371
|
+
x.confidences.push(conf);
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
function parseConfidence(element) {
|
|
1376
|
+
let o = element.indexOf('[');
|
|
1377
|
+
if (o > -1) {
|
|
1378
|
+
let s = element.substring(o + 1, element.length - 1);
|
|
1379
|
+
if (NUMBERS_ONLY_PATTERN.test(s)) {
|
|
1380
|
+
let confValue = parseFloat(s);
|
|
1381
|
+
if (forester.isNumber(confValue)) {
|
|
1382
|
+
return confValue;
|
|
1383
|
+
} else {
|
|
1384
|
+
throw (NH_FORMAT_ERR + 'could not parse confidence value from "' + element + '"');
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
return null;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
function moveInternalNodeNamesToConfidenceValues(node) {
|
|
1392
|
+
forester.preOrderTraversalAll(node, function (n) {
|
|
1393
|
+
if (n.children || n._children) {
|
|
1394
|
+
if (n.name) {
|
|
1395
|
+
let s = n.name;
|
|
1396
|
+
if (NUMBERS_ONLY_PATTERN.test(s)) {
|
|
1397
|
+
let confValue = parseFloat(s);
|
|
1398
|
+
if ((confValue != null) && (forester.isNumber(confValue))) {
|
|
1399
|
+
n.confidences = [];
|
|
1400
|
+
let conf1 = {};
|
|
1401
|
+
conf1.value = confValue;
|
|
1402
|
+
conf1.type = 'unknown';
|
|
1403
|
+
n.confidences.push(conf1);
|
|
1404
|
+
n.name = undefined;
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1412
|
+
|
|
1413
|
+
forester.isNumber = function (v) {
|
|
1414
|
+
if (v === undefined || v === null) {
|
|
1415
|
+
return false;
|
|
1416
|
+
}
|
|
1417
|
+
if (v != v) {
|
|
1418
|
+
// This can only be true if the v is NaN
|
|
1419
|
+
return false;
|
|
1420
|
+
}
|
|
1421
|
+
return true;
|
|
1422
|
+
};
|
|
1423
|
+
|
|
1424
|
+
forester.getOneDistinctTaxonomy = function (node) {
|
|
1425
|
+
let id = null;
|
|
1426
|
+
let code = null;
|
|
1427
|
+
let sn = null;
|
|
1428
|
+
let cn = null;
|
|
1429
|
+
let result = true;
|
|
1430
|
+
let sawTax = false;
|
|
1431
|
+
forester.preOrderTraversalAll(node, function (n) {
|
|
1432
|
+
if (n.taxonomies && n.taxonomies.length === 1) {
|
|
1433
|
+
let tax = n.taxonomies[0];
|
|
1434
|
+
if (tax.code && tax.code.length > 0) {
|
|
1435
|
+
sawTax = true;
|
|
1436
|
+
if (code === null) {
|
|
1437
|
+
code = tax.code;
|
|
1438
|
+
} else if (code !== tax.code) {
|
|
1439
|
+
result = false;
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
if (tax.scientific_name && tax.scientific_name.length > 0) {
|
|
1444
|
+
sawTax = true;
|
|
1445
|
+
if (sn === null) {
|
|
1446
|
+
sn = tax.scientific_name;
|
|
1447
|
+
} else if (sn !== tax.scientific_name) {
|
|
1448
|
+
result = false;
|
|
1449
|
+
return;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
if (tax.common_name && tax.common_name.length > 0) {
|
|
1453
|
+
sawTax = true;
|
|
1454
|
+
if (cn === null) {
|
|
1455
|
+
cn = tax.common_name;
|
|
1456
|
+
} else if (cn !== tax.common_name) {
|
|
1457
|
+
result = false;
|
|
1458
|
+
return;
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
if (tax.id && tax.id.value && tax.id.value.length > 0) {
|
|
1462
|
+
sawTax = true;
|
|
1463
|
+
let myid;
|
|
1464
|
+
if (tax.id.provider && tax.id.provider.length > 0) {
|
|
1465
|
+
myid = tax.id.provider + ':' + tax.id.value;
|
|
1466
|
+
} else {
|
|
1467
|
+
myid = tax.id.value;
|
|
1468
|
+
}
|
|
1469
|
+
if (id === null) {
|
|
1470
|
+
id = myid;
|
|
1471
|
+
} else if (id !== myid) {
|
|
1472
|
+
result = false;
|
|
1473
|
+
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
} else if (!n.children && !n._children) {
|
|
1477
|
+
// If an external node lacks taxonomy, return false.
|
|
1478
|
+
result = false;
|
|
1479
|
+
}
|
|
1480
|
+
});
|
|
1481
|
+
if (!sawTax) {
|
|
1482
|
+
return null;
|
|
1483
|
+
}
|
|
1484
|
+
if (result === true) {
|
|
1485
|
+
|
|
1486
|
+
if (sn) {
|
|
1487
|
+
return sn;
|
|
1488
|
+
} else if (code) {
|
|
1489
|
+
return code;
|
|
1490
|
+
} else if (cn) {
|
|
1491
|
+
return cn;
|
|
1492
|
+
} else if (id) {
|
|
1493
|
+
return id;
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
return null;
|
|
1497
|
+
};
|
|
1498
|
+
|
|
1499
|
+
forester.getOneDistinctNodePropertyValue = function (node, propertyRef) {
|
|
1500
|
+
let propValue = null;
|
|
1501
|
+
let result = true;
|
|
1502
|
+
forester.preOrderTraversalAll(node, function (n) {
|
|
1503
|
+
if (n.properties && n.properties.length > 0) {
|
|
1504
|
+
let propertiesLength = n.properties.length;
|
|
1505
|
+
let gotIt = false;
|
|
1506
|
+
for (let i = 0; i < propertiesLength; ++i) {
|
|
1507
|
+
let property = n.properties[i];
|
|
1508
|
+
if (property.ref && property.value && (property.applies_to === 'node') && (property.ref === propertyRef) && (property.value.length > 0)) {
|
|
1509
|
+
if (propValue === null) {
|
|
1510
|
+
propValue = property.value;
|
|
1511
|
+
} else if (propValue !== property.value) {
|
|
1512
|
+
result = false;
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
gotIt = true;
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
if (!gotIt && !n.children && !n._children) {
|
|
1519
|
+
// If an external node lacks propertyRef, return false.
|
|
1520
|
+
result = false;
|
|
1521
|
+
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
});
|
|
1525
|
+
if (propValue === null) {
|
|
1526
|
+
return null;
|
|
1527
|
+
}
|
|
1528
|
+
if (result === true) {
|
|
1529
|
+
return propValue;
|
|
1530
|
+
} else {
|
|
1531
|
+
return null;
|
|
1532
|
+
}
|
|
1533
|
+
};
|
|
1534
|
+
|
|
1535
|
+
/**
|
|
1536
|
+
* To be deprecated!
|
|
1537
|
+
*
|
|
1538
|
+
* @param phy
|
|
1539
|
+
* @returns {{}}
|
|
1540
|
+
*/
|
|
1541
|
+
forester.moveSimpleCharacteristicsToProperties = function (phy) {
|
|
1542
|
+
let apptype;
|
|
1543
|
+
if (phy.desc) {
|
|
1544
|
+
apptype = 'ird:'
|
|
1545
|
+
} else {
|
|
1546
|
+
apptype = 'vipr:'
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
let HOST = apptype + 'Host';
|
|
1550
|
+
let COUNTRY = apptype + 'Country';
|
|
1551
|
+
let YEAR = apptype + 'Year';
|
|
1552
|
+
let HA = apptype + 'HA';
|
|
1553
|
+
let NA = apptype + 'NA';
|
|
1554
|
+
let NODE = 'node';
|
|
1555
|
+
let STRING = 'xsd:string';
|
|
1556
|
+
let INT = 'xsd:integer';
|
|
1557
|
+
|
|
1558
|
+
forester.preOrderTraversalAll(phy, function (n) {
|
|
1559
|
+
if (n.simple_characteristics) {
|
|
1560
|
+
let sc = n.simple_characteristics;
|
|
1561
|
+
let props;
|
|
1562
|
+
if (sc.country && sc.country.length > 0) {
|
|
1563
|
+
props = {};
|
|
1564
|
+
props.ref = COUNTRY;
|
|
1565
|
+
props.datatype = STRING;
|
|
1566
|
+
props.applies_to = NODE;
|
|
1567
|
+
props.value = sc.country;
|
|
1568
|
+
addProperties(n, props);
|
|
1569
|
+
}
|
|
1570
|
+
if (sc.host && sc.host.length > 0) {
|
|
1571
|
+
props = {};
|
|
1572
|
+
props.ref = HOST;
|
|
1573
|
+
props.datatype = STRING;
|
|
1574
|
+
props.applies_to = NODE;
|
|
1575
|
+
props.value = sc.host;
|
|
1576
|
+
addProperties(n, props);
|
|
1577
|
+
}
|
|
1578
|
+
if (sc.year && sc.year.length > 0) {
|
|
1579
|
+
props = {};
|
|
1580
|
+
props.ref = YEAR;
|
|
1581
|
+
props.datatype = INT;
|
|
1582
|
+
props.applies_to = NODE;
|
|
1583
|
+
props.value = parseInt(sc.year);
|
|
1584
|
+
addProperties(n, props);
|
|
1585
|
+
}
|
|
1586
|
+
if (sc.ha && sc.ha.length > 0) {
|
|
1587
|
+
props = {};
|
|
1588
|
+
props.ref = HA;
|
|
1589
|
+
props.datatype = INT;
|
|
1590
|
+
props.applies_to = NODE;
|
|
1591
|
+
props.value = parseInt(sc.ha);
|
|
1592
|
+
addProperties(n, props);
|
|
1593
|
+
}
|
|
1594
|
+
if (sc.na && sc.na.length > 0) {
|
|
1595
|
+
props = {};
|
|
1596
|
+
props.ref = NA;
|
|
1597
|
+
props.datatype = INT;
|
|
1598
|
+
props.applies_to = NODE;
|
|
1599
|
+
props.value = parseInt(sc.na);
|
|
1600
|
+
addProperties(n, props);
|
|
1601
|
+
}
|
|
1602
|
+
n.simple_characteristics = undefined;
|
|
1603
|
+
}
|
|
1604
|
+
});
|
|
1605
|
+
|
|
1606
|
+
function addProperties(n, props) {
|
|
1607
|
+
if (props) {
|
|
1608
|
+
if (!n.properties) {
|
|
1609
|
+
n.properties = [];
|
|
1610
|
+
}
|
|
1611
|
+
let alreadyHave = false;
|
|
1612
|
+
let l = n.properties.length;
|
|
1613
|
+
for (let i = 0; i < l; ++i) {
|
|
1614
|
+
if (n.properties[i].ref === props.ref) {
|
|
1615
|
+
alreadyHave = true;
|
|
1616
|
+
break;
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
if (!alreadyHave) {
|
|
1620
|
+
n.properties.push(props);
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
};
|
|
1625
|
+
|
|
1626
|
+
|
|
1627
|
+
/**
|
|
1628
|
+
* To convert a phylogentic tree object to a New Hampshire (Newick) formatted string.
|
|
1629
|
+
*
|
|
1630
|
+
* @param phy - A phylogentic tree object.
|
|
1631
|
+
* @param decPointsMax - Maximal number of decimal points for branch lengths (optional)
|
|
1632
|
+
* @param replaceChars - To replace illegal characters (),:;"' instead of surrounding with quotation marks
|
|
1633
|
+
* @param writeConfidences - to write confidence values in brackets
|
|
1634
|
+
* @returns {*} - a New Hampshire (Newick) formatted string.
|
|
1635
|
+
*/
|
|
1636
|
+
forester.toNewHampshire = function (phy, decPointsMax, replaceChars, writeConfidences) {
|
|
1637
|
+
let nh = "";
|
|
1638
|
+
if (phy.children && phy.children.length === 1) {
|
|
1639
|
+
toNewHampshireHelper(phy.children[0], true);
|
|
1640
|
+
}
|
|
1641
|
+
if (nh.length > 0) {
|
|
1642
|
+
return nh + ";";
|
|
1643
|
+
}
|
|
1644
|
+
return nh;
|
|
1645
|
+
|
|
1646
|
+
function toNewHampshireHelper(node, last) {
|
|
1647
|
+
if (node.children) {
|
|
1648
|
+
let l = node.children.length;
|
|
1649
|
+
nh += "(";
|
|
1650
|
+
for (let i = 0; i < l; ++i) {
|
|
1651
|
+
toNewHampshireHelper(node.children[i], i === l - 1);
|
|
1652
|
+
}
|
|
1653
|
+
nh += ")";
|
|
1654
|
+
} else if (node._children) {
|
|
1655
|
+
let ll = node._children.length;
|
|
1656
|
+
nh += "(";
|
|
1657
|
+
for (let ii = 0; ii < ll; ++ii) {
|
|
1658
|
+
toNewHampshireHelper(node._children[ii], ii === ll - 1);
|
|
1659
|
+
}
|
|
1660
|
+
nh += ")";
|
|
1661
|
+
}
|
|
1662
|
+
if (node.name && node.name.length > 0) {
|
|
1663
|
+
if (replaceChars === true) {
|
|
1664
|
+
nh += replaceUnsafeChars(node.name);
|
|
1665
|
+
} else {
|
|
1666
|
+
let myName = node.name.replace(/\s+/g, ' ');
|
|
1667
|
+
if (/[\s,():;'"\[\]]/.test(myName)) {
|
|
1668
|
+
if ((myName.indexOf('"') > -1) && (myName.indexOf("'") > -1)) {
|
|
1669
|
+
nh += '"' + myName.replace(/"/g, "'") + '"';
|
|
1670
|
+
} else if (myName.indexOf('"') > -1) {
|
|
1671
|
+
nh += "'" + myName + "'";
|
|
1672
|
+
} else {
|
|
1673
|
+
nh += '"' + myName + '"';
|
|
1674
|
+
}
|
|
1675
|
+
} else {
|
|
1676
|
+
nh += myName;
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
if (node.branch_length !== undefined && node.branch_length !== null) {
|
|
1681
|
+
if (decPointsMax && decPointsMax > 0) {
|
|
1682
|
+
nh += ":" + forester.roundNumber(node.branch_length, decPointsMax);
|
|
1683
|
+
} else {
|
|
1684
|
+
nh += ":" + node.branch_length;
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
if (writeConfidences && node.confidences && node.confidences.length === 1 && node.confidences[0].value !== undefined && node.confidences[0].value !== null) {
|
|
1688
|
+
if (decPointsMax && decPointsMax > 0) {
|
|
1689
|
+
nh += "[" + forester.roundNumber(node.confidences[0].value, decPointsMax) + "]";
|
|
1690
|
+
} else {
|
|
1691
|
+
nh += "[" + node.confidences[0].value + "]";
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
if (!last) {
|
|
1695
|
+
nh += ",";
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
function replaceUnsafeChars(str) {
|
|
1700
|
+
return str.replace(/[\s,():;'"\[\]]+/g, '_');
|
|
1701
|
+
}
|
|
1702
|
+
};
|
|
1703
|
+
|
|
1704
|
+
forester.getMolecularSequencesAsFasta = function (node, sep) {
|
|
1705
|
+
let fasta_all = '';
|
|
1706
|
+
let ext_nodes = forester.getAllExternalNodes(node).reverse();
|
|
1707
|
+
for (let j = 0, l = ext_nodes.length; j < l; ++j) {
|
|
1708
|
+
let n = ext_nodes[j];
|
|
1709
|
+
if (n.sequences) {
|
|
1710
|
+
for (let i = 0; i < n.sequences.length; ++i) {
|
|
1711
|
+
let s = n.sequences[i];
|
|
1712
|
+
if (s.mol_seq && s.mol_seq.value && s.mol_seq.value.length > 0) {
|
|
1713
|
+
let seq = s.mol_seq.value;
|
|
1714
|
+
let seqname = j;
|
|
1715
|
+
if (s.name && s.name.length > 0) {
|
|
1716
|
+
seqname = s.name
|
|
1717
|
+
} else if (n.name && n.name.length > 0) {
|
|
1718
|
+
seqname = n.name
|
|
1719
|
+
}
|
|
1720
|
+
let split_seq_ary = seq.match(/.{1,80}/g);
|
|
1721
|
+
let split_seq = '';
|
|
1722
|
+
for (let ii = 0; ii < split_seq_ary.length; ++ii) {
|
|
1723
|
+
split_seq += split_seq_ary[ii] + sep;
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
let fasta = '>' + seqname + sep + split_seq;
|
|
1727
|
+
fasta_all += fasta;
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
return fasta_all;
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
forester.roundNumber = function (num, dec) {
|
|
1736
|
+
return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
|
|
1737
|
+
};
|
|
1738
|
+
|
|
1739
|
+
forester.isString = function (s) {
|
|
1740
|
+
return (typeof s === 'string' || s instanceof String);
|
|
1741
|
+
};
|
|
1742
|
+
|
|
1743
|
+
|
|
1744
|
+
// --------------------------------------------------------------
|
|
1745
|
+
// For exporting
|
|
1746
|
+
// --------------------------------------------------------------
|
|
1747
|
+
if (typeof module !== 'undefined' && module.exports && !global.xmldocAssumeBrowser) module.exports.forester = forester; else if (typeof window !== "undefined") window.forester = forester; else this.forester = forester;
|
|
1748
|
+
})();
|
|
1906
1749
|
|