File size: 162,779 Bytes
064f504
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
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
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
495
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
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
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
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
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
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
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "43a754fe",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Basic libraries\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "import plotly.express as px\n",
    "\n",
    "# Deep learning & graph\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim\n",
    "import torch.nn.functional as F\n",
    "\n",
    "# RDKit\n",
    "from rdkit import Chem\n",
    "from rdkit.Chem import AllChem\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "1f1844fd",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[13:03:26] WARNING: not removing hydrogen atom without neighbors\n"
     ]
    }
   ],
   "source": [
    "# Load Tox21 data\n",
    "df = pd.read_csv(\"tox21.csv\")  # Ensure this file is uploaded in your Colab environment\n",
    "df = df[['smiles', 'SR-HSE']].dropna()\n",
    "\n",
    "# Updated Morgan Fingerprint Generator\n",
    "from rdkit.Chem.rdFingerprintGenerator import GetMorganGenerator\n",
    "\n",
    "generator = GetMorganGenerator(radius=2, fpSize=1024)\n",
    "\n",
    "def mol_to_fp(smiles):\n",
    "    mol = Chem.MolFromSmiles(smiles)\n",
    "    if mol:\n",
    "        return np.array(generator.GetFingerprint(mol))\n",
    "    return None\n",
    "\n",
    "# Convert SMILES to fingerprints\n",
    "fps, labels = [], []\n",
    "for _, row in df.iterrows():\n",
    "    fp = mol_to_fp(row['smiles'])\n",
    "    if fp is not None:\n",
    "        fps.append(fp)\n",
    "        labels.append(row['SR-HSE'])\n",
    "\n",
    "X, y = np.array(fps), np.array(labels)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "bbd5aeb9",
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.utils.class_weight import compute_class_weight\n",
    "\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)\n",
    "\n",
    "classes = np.unique(y_train)\n",
    "weights = compute_class_weight(class_weight=\"balanced\", classes=classes, y=y_train)\n",
    "pos_weight = torch.tensor(weights[1] / weights[0])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d0d532aa",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1: Loss = 1.3065\n",
      "Epoch 2: Loss = 1.2969\n",
      "Epoch 3: Loss = 1.2842\n",
      "Epoch 4: Loss = 1.2674\n",
      "Epoch 5: Loss = 1.2448\n",
      "Epoch 6: Loss = 1.2137\n",
      "Epoch 7: Loss = 1.1772\n",
      "Epoch 8: Loss = 1.1343\n",
      "Epoch 9: Loss = 1.0832\n",
      "Epoch 10: Loss = 1.0278\n",
      "Epoch 11: Loss = 0.9664\n",
      "Epoch 12: Loss = 0.9063\n",
      "Epoch 13: Loss = 0.8500\n",
      "Epoch 14: Loss = 0.7909\n",
      "Epoch 15: Loss = 0.7270\n",
      "Epoch 16: Loss = 0.6784\n",
      "Epoch 17: Loss = 0.6211\n",
      "Epoch 18: Loss = 0.5691\n",
      "Epoch 19: Loss = 0.5257\n",
      "Epoch 20: Loss = 0.4756\n",
      "Epoch 21: Loss = 0.4371\n",
      "Epoch 22: Loss = 0.3983\n",
      "Epoch 23: Loss = 0.3618\n",
      "Epoch 24: Loss = 0.3357\n",
      "Epoch 25: Loss = 0.3059\n",
      "Epoch 26: Loss = 0.2791\n",
      "Epoch 27: Loss = 0.2531\n",
      "Epoch 28: Loss = 0.2352\n",
      "Epoch 29: Loss = 0.2114\n",
      "Epoch 30: Loss = 0.1910\n"
     ]
    }
   ],
   "source": [
    "class ToxicityNet(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(ToxicityNet, self).__init__()\n",
    "        self.model = nn.Sequential(\n",
    "            nn.Linear(1024, 512),\n",
    "            nn.ReLU(),\n",
    "            nn.Dropout(0.3),\n",
    "            nn.Linear(512, 128),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(128, 1)\n",
    "        )\n",
    "\n",
    "    def forward(self, x):\n",
    "        return self.model(x)\n",
    "\n",
    "# Prepare tensors\n",
    "X_train_tensor = torch.tensor(X_train).float()\n",
    "y_train_tensor = torch.tensor(y_train).float().unsqueeze(1)\n",
    "X_test_tensor = torch.tensor(X_test).float()\n",
    "y_test_tensor = torch.tensor(y_test).float().unsqueeze(1)\n",
    "\n",
    "# Training loop\n",
    "model = ToxicityNet()\n",
    "criterion = nn.BCEWithLogitsLoss(pos_weight=pos_weight)\n",
    "optimizer = optim.Adam(model.parameters(), lr=0.001)\n",
    "\n",
    "for epoch in range(30):\n",
    "    model.train()\n",
    "    optimizer.zero_grad()\n",
    "    output = model(X_train_tensor)\n",
    "    loss = criterion(output, y_train_tensor)\n",
    "    loss.backward()\n",
    "    optimizer.step()\n",
    "    print(f\"Epoch {epoch+1}: Loss = {loss.item():.4f}\")\n",
    "\n",
    "torch.save(model.state_dict(), \"tox_model.pt\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "ed7b8671",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy: 0.9011, ROC-AUC: 0.6676\n"
     ]
    },
    {
     "data": {
      "application/vnd.plotly.v1+json": {
       "config": {
        "plotlyServerURL": "https://plot.ly"
       },
       "data": [
        {
         "bingroup": "x",
         "hovertemplate": "color=0.0<br>Predicted Probability=%{x}<br>count=%{y}<extra></extra>",
         "legendgroup": "0.0",
         "marker": {
          "color": "#636efa",
          "opacity": 0.5,
          "pattern": {
           "shape": ""
          }
         },
         "name": "0.0",
         "orientation": "v",
         "showlegend": true,
         "type": "histogram",
         "x": {
          "bdata": "JDx0OeFZcTdYrR07OvSGProxMjvKEDU/m6jrOs5sFj9Aloo8LCu8Pj/5Ij5YitYzCuaBMvKVjTgxuY46oMWyO5Lv6TfAPZU8pRWsPSHX0D02y3M5sLHJPMYzZzqcH6s4W/+EO4bhkTzUJ5c8oKSsPDwyID8cWI88jfDFPazQGjltZJ81WcHaOSLqVDxMZ/0+2eMRPEjkkD1zxxo7rAsZObGFfzya6qI9BjaePYQwEzuuNH4+zdjGNptXKD/Jn2g8SQxZPMZ/ZD6qeUU1ye6DOfpP9zy91Yg8yBHBPHn7GjwNKBM/gs+SOmUNUTm+NX46xBuGOxtn7zjHQB08PVOuO0XMvT0cjbk6Ot7MMkOVWzv2x1M/louiOi/o3jyc7687+DiHPkIYFjycTgY7ToMFPVeoXDx09gg6rU42OTRQVjnZOXA83UEfP1Kv1j09bHU/95JZPRL/bD0xo4068iaUPvWdVjqJeD09NqMkOzly2Tv27Rs/69/IPpztqDwivbo+QbQqPfsb1TnaDK06t4KuNae1Az1eI9E9wEBnPR2XIj3xPFs+e9TyOmfv6Tuo4S83pGcUPLImBD6GagQ6ueu4OzHATDzs7Hc4F2X6Pm/Tmzexpsw+DYBPPPNv/zxC5BY7l+6NNmh1ST20PWA9AwMnNv1gUjrJ8AE9kUHBOr4GoDutQFE/wFQJPFtzpjh8bis/bPMeO1N4GzpaIX44uzMxO/nMQz4GS8Y+xYCWPhAeoTrf/bA6s35TNhuXAjtkyqc5fSdjO3fqqDlTGaM6N/fdOtjcbD/XzYI9Zv+CN8ok6Di63Hw/9sayPbZ4Qj7R/Mo3F2X6PiztBDctIiw6VX7iO2veizv/gYI9aiE+Ophl5Tn/eEk+WiD2PN10Jz64mPI7Cka/OF9FQzvBLX44chCDOn5UTD8ByiA9Kj5cPUGzBD2G6FA/CiuNPclsgToT6gU2FNfsPvCtvz47/+c+NF+UOkcO2z1wsfE9rPWKPbdfYzpuO/U5De6zMuWvGj7CHg0+IvMqNO6mejw4lr41p2NVPBWjTD9epSo8Sp6VOgcaMjwpXME4FjaHPaAu7zsPHQg8wAfQPN1HjDxvyf027MmBPPbCwT3tv4Y9HZplPe+bhTrvru49pdgcNLCeQTsqPmE8VHfEPT5ALzojaAY5ghM0PGXgzjw7syY7JiF+PRJp6ztlUUM8j7hrPRJ4vT186bY0kb4nO656Nzm5BaQ4NcHBPgzYFTzOvAQ/MqM+O5ansD4TaG447WL+O27AlDz0mmM6ZCXWPdtgDDlI/wU63hv+OsCovD6kf349T5GrOzarbT02Sec8n/poPmWfmjwIguY8mm0dPeQ/tzwPcQ07jbykOj0VWDaeH6o9IrqiPBIIMD6vBvM3cF1ZPz6LITrDsCU/Y5w2PCdhqD5mczcxxVluP8eBizvod3U8GoG+Pk9ylj4FQm84khL8ODoLADsPjH4+wKQiOu6qjTiKVSM/PpbkOKSmlD4WTYE89RRSPKUS+DvKCH0+lgqePF98wT7Omb46w3yiNKc3nTn42x87WJwcOpz/qT7UeIs12b6OOh4fAzqZHZ898sWYPDMBoDocy3A+GlkwPCQs0DuD+uI7P1UTO361fzoNvWU/51lzNwSvZzkgro464S/PPIFrrTUI3SM69PeRO1gutz1rcqo20e8nOgoKPz6tj4k7FH0FPDsDnzxvlwc+CtAbPOe8ijw+ykU1dTbgPfhHzT1fCIg68YOTO7olgzgXdDo9IedzPRy9hjtm4Nw4jEvBPt54vTsrcDA780sEPuxGhDxdG44+4ws9OPJMtj7uLY47NXfaPuI3Azm+BSQ91NnWPbtEwTfW4g08J66HOXUx3j3aqQo48UcEP5LuqD2wVrc73/A+Pb20Jj/ifG40wovcOGZ9wDhycfY8TJ6hOfyqIDxGicA8lkQAPiIjEDl2r9s7Lh2fPPbH1T31Rpo8aWwMPNNa/z2+Fpg59vonPvL6UD283Ag5Fl0jPsxbEzv4uRI8o+pLPPHlejm+1ME7NLBZMUHYZzllDMo6ZUHYOGZyuTZLqmY/ksURPpTByD3da9k7bAUSOGCRDzrg3bE8qsaFOoCs5jqAdpM8l8JHP3HgoDZqBVo6S94ZPu+FIzkvOkk6jtjnPGhc+TpGAic4SIxJPQ9PDTxkMjI0pbLFO+ALozyT6LM+P3X8Nngogz6Bi2c2n64IPkX2CzlVEmc8GdT0PBv2ED0z02A/CYT2O1nboTpBZg85zGNqPGnAgjxX7Nc5vRIzOoYCwjUcy3A+ZUDHPGWTYz7zmIU82eAbPFmGQjhQAXE7jDFyPjzGojwDNJI76LIKPSqc+zrw3sA85hycPfQ6YDytarU7uosFO/vQRzuZlbg97ajuPF+XfjFeSik6Lw29N59SaD0eHlg7q2e9O1uh5Db2Jdg5ra1HPLleBj1UGw0/8cW7OnvX4zY2lww96ILRNlMIhzs07YE+GQwVP0HZCj6OBvM4K2YjPIcaCD3gjt43BJ51PeptQj3hLT89pMA7OGKubj8+i889N+0JPD4SWDoa7Ss6DdmcPlZ1jjuCow870xgePv/VhD7AGL41Q+ctP4Z4fj2cdXU7cgA9Pkn8STREhSc+gxjuOgQJnztCXcg7CxHFPHerpD7odK08zGynPho0HDib0Qc8eAQ6P1ys1zwRGCE7MYK7OkLZzzudOUs4b2FGN0n+3D4manY/m3ajOljDXjyKgJ4+hlTQOiUZWDsGH4oz+kPAPUCjHjof0uY+OsU8OvuD6T3vriA9jBy8OV0B5z2FEtE9As8hOsXJlzwu6l8/fvDANpc+LjPwgLE9oURsP+B0+zynsjk66pvMN+9GPD0uzMg9Rn0VPSTfNzq6P2o/ElmgO/yrvj6lTf04YMDvNBxYjzxUDEc48HlTOVtN8T6jc7o+wZT1Puw45j57HJI7awNOPa8i0zc6UAM7XAwwOOXHLz5H2Q83GDPpO4eKUzTQ/DU9wEKdOxM3JD+a4Mk3KDRwOq5xCT4MP2E+E2l3O3Ixzzz/56o9I7wtOsXAoDzdQR8/QRUUPbHxXj5kjjc5BB2MOc0OXDooz3Y72I4AO9eh2TjRDJ8+oiaFN8PFqjcVIw45cpdTPVx9bj/GAZM8Cd3lObtOpTwfpSo8J4GDNuWvGj63tyg52JXsPBfP2zsc+p876UeyOed2/j6QLaU2cYADPv0dOjru58U76fXNOzA7QDxSKGw/WQIPNzRrvTdkMvA9vdKAO3ozDjc54nU8wRjhPQdj8Tyw9DU+ZQqKOAk55j79m3o7YDhqOhoVkD2fYw49Vku5PI9jDT/F0c87Ny0COP2eRzuCqcY8hllpOCKY7zxdIdg3W8iaPW/H5ThycfY8n2y8OGJxij2y7gA/jlxdPcKP7jxlRhA1RRJrOutrqD7jldU4sJ5qO6N8dDyitAY5VsUOPI7a0joVK+o7G08KNwVf3TqrRIc63t9DP8dCGTghgYU+v4k+PyZZgDzYlew8q9sxPbqLBTu1saI+S4gPPWEjIzk31LE7ypSxOzfm0zhNZno/Wk8FPOISCzy7Iwg8CppfNdGxBjeLBnM9TOwfOAIm/zqUyDA71pU1O3Jx9jzBN043BNh9PYIGQDzh70Y9UYKDOGn9wTo+Iqkz97YKPbvFCDwg0O0+fJNKP+wLMz8tX04+/ElkODv1ITwYBGY2IOknNEKVJT8KcWI89UBvO5Vrpzujkt49nuh/Pjxt9TkbbBE+hLcOP/qXdD+vKgY+c6qmO7ReJzyztLo74D6QOcWAlj7KDEE6SI63PnyNpD54JMY5VF8DO1tNJD2LCFo0AYMlO1qOCj9XtME5wYtqNozyBT2EzGs+M/gnN9AVTz+dSWY+GETBOMlTej4xBIU7FW9kPdvaITreCL0+4g72PrQcuD342+s66DwuOurcgz4M3z49R6xgPTbWHT/KmLQ9KA9XO/oMQjvJSu42NUaXOS7QYztIvgM/NNeNPBHcfzWeK/U6fDcROZpyCjvALrQ7kGjHOyrxNTdzBgk6sxIrNHHnXju9Ano3Gj9vOEhbTDtAusE8ibVLPiQhgjrxTK083BGIPBDo6jhvGeY2zufINqBtlz7E2ps50LzAPJfR2z0qFb06pDvyPL1Qlj5AAJE803HoOpL3qzxESLY7SGixPpfohjxTXKM5aezJPleC9DshVPM67V6HO7V80ThWsZc4gxqWPTG3izVdW306m2W7Oetl+DufYk87+76CPRj3rD5g5/E97IE+OkN8FTlPHVE6Niy5OzknBzzPf6k81QAmOsn5Ujz4aIY7e74HNpZ5nzxs7Dc7noHJPc/k3TmC2g83aJy2PC1CKD6PkME7Jj9ePGo3sjzyoPw8GJd2OdmZlTsH0U83XJwYPN1R9T1A0Ck9UVxIPLdl8T16ewE9MEfBOQB1hjuLiII+azKMOnhBWzqHYx89cAEjNhOsQzsmNbo41hvkOoJelz37YLs3eky/Pg9VTz38Yls9adAfNrIeLzlEzS86MmoiPJCYazuZMAI7TLL4PsihGD3dQwc9D0S6PARMEzyd91c+jTmLMj/5Ij6nj0w5os3tO2GJGz0tCvQ71uINPKHnGD7YIeA67B9HPVcEBjkCP1c/Q8uNNk9hZzwlPyg8Vg+zNeAreztPIXA5ODMyORHcADlGo4M4d00lOkoj1z5yWgE5oZJYOqT0BTt6+qE9VqhRP2oewDsWxkM7cLVPOOOvnjynTIw9rUjGPCf4gjlnoY09ISfCPCBvfjo76Po+xEFhPwFOUT8dCZQ9/Q+JOsCzjzytA7o44jVXPpfjZz8eC3s9m/BsO+K8VjSzfNA769pxPTHgtz6kO/I8vTa6PK5LTD89K2s/ok8ZPv1pmT3Lqjs9JL8yPXYZ4jNkfkE9r2KnNYKBoTcvkLA74uqnPGNmZz0ffVM8lDsQPADGtDm/oCQ9hAMdO0DNzD7OkZM893BPPsWAlj4NCpg5gQqNO93+Bjm4/3M+k27NOXuWMj4836Q7YC4cOR9Z9T4RWfA3dvWzNMTkyzqLhBA8X+LKPM/Q3TtTJEg64HyYNeX0RD8a874+31K/N+odNz8IS5U9ZPhZN3X79z13tFA1Bmb9PjEIwjq/MXU4hTIBOvtqqDqQkbo4F7qkOT28HTzraD09ToGvO+yAPT0oy7A7YYkbPcrQMjy21Nw9oHXwOdj/WD5F0Oo2k3/GO1HkGD6iW085vN3yPkSOKj6rTdU4xDN3N4sz7j7eCDI5YXErPAJ6jT09cbk5qRBqN6bSkDp1Mos6L392PQ5AKDq2wUo0B7+7O5LRZzinY1U8bQAKPrqtCDlAnE48LVnBNvgw8zn+jrA+GPSFPk+U1DzVVZA6L4mjOtQRDzyeH6o9e+M0PRdWLT3H/7g4/utpOA4QkTYQWv09j3CnPHsyjz1jowo4PdKjN/9FIzrgrZY7l+m6ON/yyzzRmiY0YuvcOjMB+zvBZhs+wZI9Pv70FzxiKJU69BnzPa1YTz4F+IM6Av1FPKvW8z2PQ14/iPfwPGSoyDfgC6M8MG8/PLP9mTNu3mw9MetuPj0Sxz7ATz85ktFnONrTADdBUYc4NhB4P6g7FjytMCQ/oYWfOgYoAj1DXKs99sPPPTEYHTpoS7M720JjOqsQcz2blcQ53DD7OwvIJjr8K9Y6IRgtPF8epDw2Ggw3EdKOOnyG5DyzNpc8xle9Om8rpzphXRM8xYqOOpaV3Dnls8U7HMtwPgt+lTt3mCE5hivCPMopljjWDuo4w4GGPh8aiz0PLXM8BzGJPrDyJj5unmM7WA5DPnieDzvp4sc74U8nPwqLCDps3qM9K06/OlMVzT3d/iU7ANNUN8duDz45yao+SyuUOGx2yzqKldw8u7MTPd9soTr+76E8HJIROys1LjplRgk92EQtObbC3TqYejo9GQolO3lp3DOgA+M9mfaLOw54Bz1nwAE/1r9COiBljz7a/Fk/C50DN8eYATpVjkg50FshN3jnVDudEXk3u6dUPjMBZTm7l7Y7zqp1P+mMVD0qK4s5mqPFOtAl3jrwltU6ULzAONbOpjuuUqM5SLMFPEQnvjreGdc9EDDqOoqLDzd6LzY4tqNrO4etZDpcagE/LAIfOw14hzm9b0A/DQOKPb/ykzsJ/uc4UlloPn4Wfz5MSs49QLKhPgXclTv0Ytc56LEIP9V02TtoEV8+oq6KPiJn8TjJSa48MAsqPo6nGT8pObI5d6qjOXGaCT3zuN460d6CPdM8PjZIULw+oKSsPI58BD4o8uA6TgE4PM5ANz2Rkgw8tGKYPRPK9T2oBDo6BY1+PF0/8Dgvp2U7UgWWOm6qmzgu14M4crE+O0+EBDyWRa49UDVKP7rshj3p7pc8mnQzPOixCD+EehE+yX3AOvIPUD6ChCk3eIcYP4GLZzZ0eJ88rAl7PC1JYzo2O748W2PrPBz4/T6gbFo8PEuBPdaf1zzypX8/VoP3OzNICT4bOjsyFvyUOg3JKTnFToA9URoYPORFXDw=",
          "dtype": "f4"
         },
         "xaxis": "x",
         "yaxis": "y"
        },
        {
         "bingroup": "x",
         "hovertemplate": "color=1.0<br>Predicted Probability=%{x}<br>count=%{y}<extra></extra>",
         "legendgroup": "1.0",
         "marker": {
          "color": "#EF553B",
          "opacity": 0.5,
          "pattern": {
           "shape": ""
          }
         },
         "name": "1.0",
         "orientation": "v",
         "showlegend": true,
         "type": "histogram",
         "x": {
          "bdata": "IM53PWrDTT9yOkg6fQQdP0tw6zgVRTo+Y2iRPhFt6jeFpqY7V9F/PxqxKTmqfbo4qAhGPw4ymjQeJmQ/lhEHPmUb1Du3vYk+H3NrO9bjPz2h5w8+f8M2P7Yw+ziU+GM9YHmxPiEHeT8axQU/LRvEPqvZUj39VMY72vZ4P0kFVjw5ge89D+w8P6E7dT/tnIU6ihf0O7Z8sD72g24/y3X8O4A4pzqjdaQ5RFAlPVr4fz/eJQY/6fKxPQnl3j7KdL468aN9PzA2hzvFk403mshbO+LHOT0X7n8/Dxt9Px0pVD9KFaw295JZPSANlTbAHYQ+OKSUPMBGdT+8IDM/B9QCOZ5bED2YelI/cs52P49X7j0IrLg449KKPZtFrj6L6H04VgJ8P8xwKj8=",
          "dtype": "f4"
         },
         "xaxis": "x",
         "yaxis": "y"
        }
       ],
       "layout": {
        "barmode": "overlay",
        "legend": {
         "title": {
          "text": "color"
         },
         "tracegroupgap": 0
        },
        "template": {
         "data": {
          "bar": [
           {
            "error_x": {
             "color": "#2a3f5f"
            },
            "error_y": {
             "color": "#2a3f5f"
            },
            "marker": {
             "line": {
              "color": "#E5ECF6",
              "width": 0.5
             },
             "pattern": {
              "fillmode": "overlay",
              "size": 10,
              "solidity": 0.2
             }
            },
            "type": "bar"
           }
          ],
          "barpolar": [
           {
            "marker": {
             "line": {
              "color": "#E5ECF6",
              "width": 0.5
             },
             "pattern": {
              "fillmode": "overlay",
              "size": 10,
              "solidity": 0.2
             }
            },
            "type": "barpolar"
           }
          ],
          "carpet": [
           {
            "aaxis": {
             "endlinecolor": "#2a3f5f",
             "gridcolor": "white",
             "linecolor": "white",
             "minorgridcolor": "white",
             "startlinecolor": "#2a3f5f"
            },
            "baxis": {
             "endlinecolor": "#2a3f5f",
             "gridcolor": "white",
             "linecolor": "white",
             "minorgridcolor": "white",
             "startlinecolor": "#2a3f5f"
            },
            "type": "carpet"
           }
          ],
          "choropleth": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "type": "choropleth"
           }
          ],
          "contour": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "colorscale": [
             [
              0,
              "#0d0887"
             ],
             [
              0.1111111111111111,
              "#46039f"
             ],
             [
              0.2222222222222222,
              "#7201a8"
             ],
             [
              0.3333333333333333,
              "#9c179e"
             ],
             [
              0.4444444444444444,
              "#bd3786"
             ],
             [
              0.5555555555555556,
              "#d8576b"
             ],
             [
              0.6666666666666666,
              "#ed7953"
             ],
             [
              0.7777777777777778,
              "#fb9f3a"
             ],
             [
              0.8888888888888888,
              "#fdca26"
             ],
             [
              1,
              "#f0f921"
             ]
            ],
            "type": "contour"
           }
          ],
          "contourcarpet": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "type": "contourcarpet"
           }
          ],
          "heatmap": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "colorscale": [
             [
              0,
              "#0d0887"
             ],
             [
              0.1111111111111111,
              "#46039f"
             ],
             [
              0.2222222222222222,
              "#7201a8"
             ],
             [
              0.3333333333333333,
              "#9c179e"
             ],
             [
              0.4444444444444444,
              "#bd3786"
             ],
             [
              0.5555555555555556,
              "#d8576b"
             ],
             [
              0.6666666666666666,
              "#ed7953"
             ],
             [
              0.7777777777777778,
              "#fb9f3a"
             ],
             [
              0.8888888888888888,
              "#fdca26"
             ],
             [
              1,
              "#f0f921"
             ]
            ],
            "type": "heatmap"
           }
          ],
          "histogram": [
           {
            "marker": {
             "pattern": {
              "fillmode": "overlay",
              "size": 10,
              "solidity": 0.2
             }
            },
            "type": "histogram"
           }
          ],
          "histogram2d": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "colorscale": [
             [
              0,
              "#0d0887"
             ],
             [
              0.1111111111111111,
              "#46039f"
             ],
             [
              0.2222222222222222,
              "#7201a8"
             ],
             [
              0.3333333333333333,
              "#9c179e"
             ],
             [
              0.4444444444444444,
              "#bd3786"
             ],
             [
              0.5555555555555556,
              "#d8576b"
             ],
             [
              0.6666666666666666,
              "#ed7953"
             ],
             [
              0.7777777777777778,
              "#fb9f3a"
             ],
             [
              0.8888888888888888,
              "#fdca26"
             ],
             [
              1,
              "#f0f921"
             ]
            ],
            "type": "histogram2d"
           }
          ],
          "histogram2dcontour": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "colorscale": [
             [
              0,
              "#0d0887"
             ],
             [
              0.1111111111111111,
              "#46039f"
             ],
             [
              0.2222222222222222,
              "#7201a8"
             ],
             [
              0.3333333333333333,
              "#9c179e"
             ],
             [
              0.4444444444444444,
              "#bd3786"
             ],
             [
              0.5555555555555556,
              "#d8576b"
             ],
             [
              0.6666666666666666,
              "#ed7953"
             ],
             [
              0.7777777777777778,
              "#fb9f3a"
             ],
             [
              0.8888888888888888,
              "#fdca26"
             ],
             [
              1,
              "#f0f921"
             ]
            ],
            "type": "histogram2dcontour"
           }
          ],
          "mesh3d": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "type": "mesh3d"
           }
          ],
          "parcoords": [
           {
            "line": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "parcoords"
           }
          ],
          "pie": [
           {
            "automargin": true,
            "type": "pie"
           }
          ],
          "scatter": [
           {
            "fillpattern": {
             "fillmode": "overlay",
             "size": 10,
             "solidity": 0.2
            },
            "type": "scatter"
           }
          ],
          "scatter3d": [
           {
            "line": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scatter3d"
           }
          ],
          "scattercarpet": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scattercarpet"
           }
          ],
          "scattergeo": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scattergeo"
           }
          ],
          "scattergl": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scattergl"
           }
          ],
          "scattermap": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scattermap"
           }
          ],
          "scattermapbox": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scattermapbox"
           }
          ],
          "scatterpolar": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scatterpolar"
           }
          ],
          "scatterpolargl": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scatterpolargl"
           }
          ],
          "scatterternary": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scatterternary"
           }
          ],
          "surface": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "colorscale": [
             [
              0,
              "#0d0887"
             ],
             [
              0.1111111111111111,
              "#46039f"
             ],
             [
              0.2222222222222222,
              "#7201a8"
             ],
             [
              0.3333333333333333,
              "#9c179e"
             ],
             [
              0.4444444444444444,
              "#bd3786"
             ],
             [
              0.5555555555555556,
              "#d8576b"
             ],
             [
              0.6666666666666666,
              "#ed7953"
             ],
             [
              0.7777777777777778,
              "#fb9f3a"
             ],
             [
              0.8888888888888888,
              "#fdca26"
             ],
             [
              1,
              "#f0f921"
             ]
            ],
            "type": "surface"
           }
          ],
          "table": [
           {
            "cells": {
             "fill": {
              "color": "#EBF0F8"
             },
             "line": {
              "color": "white"
             }
            },
            "header": {
             "fill": {
              "color": "#C8D4E3"
             },
             "line": {
              "color": "white"
             }
            },
            "type": "table"
           }
          ]
         },
         "layout": {
          "annotationdefaults": {
           "arrowcolor": "#2a3f5f",
           "arrowhead": 0,
           "arrowwidth": 1
          },
          "autotypenumbers": "strict",
          "coloraxis": {
           "colorbar": {
            "outlinewidth": 0,
            "ticks": ""
           }
          },
          "colorscale": {
           "diverging": [
            [
             0,
             "#8e0152"
            ],
            [
             0.1,
             "#c51b7d"
            ],
            [
             0.2,
             "#de77ae"
            ],
            [
             0.3,
             "#f1b6da"
            ],
            [
             0.4,
             "#fde0ef"
            ],
            [
             0.5,
             "#f7f7f7"
            ],
            [
             0.6,
             "#e6f5d0"
            ],
            [
             0.7,
             "#b8e186"
            ],
            [
             0.8,
             "#7fbc41"
            ],
            [
             0.9,
             "#4d9221"
            ],
            [
             1,
             "#276419"
            ]
           ],
           "sequential": [
            [
             0,
             "#0d0887"
            ],
            [
             0.1111111111111111,
             "#46039f"
            ],
            [
             0.2222222222222222,
             "#7201a8"
            ],
            [
             0.3333333333333333,
             "#9c179e"
            ],
            [
             0.4444444444444444,
             "#bd3786"
            ],
            [
             0.5555555555555556,
             "#d8576b"
            ],
            [
             0.6666666666666666,
             "#ed7953"
            ],
            [
             0.7777777777777778,
             "#fb9f3a"
            ],
            [
             0.8888888888888888,
             "#fdca26"
            ],
            [
             1,
             "#f0f921"
            ]
           ],
           "sequentialminus": [
            [
             0,
             "#0d0887"
            ],
            [
             0.1111111111111111,
             "#46039f"
            ],
            [
             0.2222222222222222,
             "#7201a8"
            ],
            [
             0.3333333333333333,
             "#9c179e"
            ],
            [
             0.4444444444444444,
             "#bd3786"
            ],
            [
             0.5555555555555556,
             "#d8576b"
            ],
            [
             0.6666666666666666,
             "#ed7953"
            ],
            [
             0.7777777777777778,
             "#fb9f3a"
            ],
            [
             0.8888888888888888,
             "#fdca26"
            ],
            [
             1,
             "#f0f921"
            ]
           ]
          },
          "colorway": [
           "#636efa",
           "#EF553B",
           "#00cc96",
           "#ab63fa",
           "#FFA15A",
           "#19d3f3",
           "#FF6692",
           "#B6E880",
           "#FF97FF",
           "#FECB52"
          ],
          "font": {
           "color": "#2a3f5f"
          },
          "geo": {
           "bgcolor": "white",
           "lakecolor": "white",
           "landcolor": "#E5ECF6",
           "showlakes": true,
           "showland": true,
           "subunitcolor": "white"
          },
          "hoverlabel": {
           "align": "left"
          },
          "hovermode": "closest",
          "mapbox": {
           "style": "light"
          },
          "paper_bgcolor": "white",
          "plot_bgcolor": "#E5ECF6",
          "polar": {
           "angularaxis": {
            "gridcolor": "white",
            "linecolor": "white",
            "ticks": ""
           },
           "bgcolor": "#E5ECF6",
           "radialaxis": {
            "gridcolor": "white",
            "linecolor": "white",
            "ticks": ""
           }
          },
          "scene": {
           "xaxis": {
            "backgroundcolor": "#E5ECF6",
            "gridcolor": "white",
            "gridwidth": 2,
            "linecolor": "white",
            "showbackground": true,
            "ticks": "",
            "zerolinecolor": "white"
           },
           "yaxis": {
            "backgroundcolor": "#E5ECF6",
            "gridcolor": "white",
            "gridwidth": 2,
            "linecolor": "white",
            "showbackground": true,
            "ticks": "",
            "zerolinecolor": "white"
           },
           "zaxis": {
            "backgroundcolor": "#E5ECF6",
            "gridcolor": "white",
            "gridwidth": 2,
            "linecolor": "white",
            "showbackground": true,
            "ticks": "",
            "zerolinecolor": "white"
           }
          },
          "shapedefaults": {
           "line": {
            "color": "#2a3f5f"
           }
          },
          "ternary": {
           "aaxis": {
            "gridcolor": "white",
            "linecolor": "white",
            "ticks": ""
           },
           "baxis": {
            "gridcolor": "white",
            "linecolor": "white",
            "ticks": ""
           },
           "bgcolor": "#E5ECF6",
           "caxis": {
            "gridcolor": "white",
            "linecolor": "white",
            "ticks": ""
           }
          },
          "title": {
           "x": 0.05
          },
          "xaxis": {
           "automargin": true,
           "gridcolor": "white",
           "linecolor": "white",
           "ticks": "",
           "title": {
            "standoff": 15
           },
           "zerolinecolor": "white",
           "zerolinewidth": 2
          },
          "yaxis": {
           "automargin": true,
           "gridcolor": "white",
           "linecolor": "white",
           "ticks": "",
           "title": {
            "standoff": 15
           },
           "zerolinecolor": "white",
           "zerolinewidth": 2
          }
         }
        },
        "title": {
         "text": "Prediction Probability Distribution"
        },
        "xaxis": {
         "anchor": "y",
         "domain": [
          0,
          1
         ],
         "title": {
          "text": "Predicted Probability"
         }
        },
        "yaxis": {
         "anchor": "x",
         "domain": [
          0,
          1
         ],
         "title": {
          "text": "count"
         }
        }
       }
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from sklearn.metrics import accuracy_score, roc_auc_score\n",
    "\n",
    "model.eval()\n",
    "logits = model(X_test_tensor)\n",
    "probs = torch.sigmoid(logits).detach().numpy()\n",
    "preds_binary = (probs > 0.5).astype(int)\n",
    "\n",
    "acc = accuracy_score(y_test, preds_binary)\n",
    "roc = roc_auc_score(y_test, probs)\n",
    "print(f\"Accuracy: {acc:.4f}, ROC-AUC: {roc:.4f}\")\n",
    "\n",
    "df_viz = pd.DataFrame({\"Predicted Probability\": probs.flatten(), \"Actual Label\": y_test.flatten()})\n",
    "fig = px.histogram(df_viz, x=\"Predicted Probability\", color=df_viz[\"Actual Label\"].astype(str),\n",
    "                   barmode=\"overlay\", title=\"Prediction Probability Distribution\")\n",
    "fig.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "cbf9e13f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Fold 1\n",
      "Accuracy: 0.9134, ROC-AUC: 0.6759\n",
      "\n",
      "Fold 2\n",
      "Accuracy: 0.9219, ROC-AUC: 0.7198\n",
      "\n",
      "Fold 3\n",
      "Accuracy: 0.9180, ROC-AUC: 0.6641\n",
      "\n",
      "Fold 4\n",
      "Accuracy: 0.9165, ROC-AUC: 0.7039\n",
      "\n",
      "Fold 5\n",
      "Accuracy: 0.9180, ROC-AUC: 0.6340\n",
      "\n",
      "Avg Accuracy: 0.9176, Avg ROC-AUC: 0.6795\n"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import StratifiedKFold\n",
    "\n",
    "skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\n",
    "accuracies, rocs = [], []\n",
    "\n",
    "for fold, (train_idx, val_idx) in enumerate(skf.split(X, y)):\n",
    "    print(f\"\\nFold {fold+1}\")\n",
    "    model = ToxicityNet()\n",
    "    optimizer = optim.Adam(model.parameters(), lr=0.001)\n",
    "    criterion = nn.BCEWithLogitsLoss(pos_weight=pos_weight)\n",
    "\n",
    "    X_train_tensor = torch.tensor(X[train_idx]).float()\n",
    "    y_train_tensor = torch.tensor(y[train_idx]).float().unsqueeze(1)\n",
    "    X_val_tensor = torch.tensor(X[val_idx]).float()\n",
    "    y_val_tensor = torch.tensor(y[val_idx]).float().unsqueeze(1)\n",
    "\n",
    "    for epoch in range(30):\n",
    "        model.train()\n",
    "        optimizer.zero_grad()\n",
    "        out = model(X_train_tensor)\n",
    "        loss = criterion(out, y_train_tensor)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "\n",
    "    model.eval()\n",
    "    preds = model(X_val_tensor).detach().numpy()\n",
    "    preds_binary = (preds > 0.5).astype(int)\n",
    "\n",
    "    acc = accuracy_score(y[val_idx], preds_binary)\n",
    "    roc = roc_auc_score(y[val_idx], preds)\n",
    "    accuracies.append(acc)\n",
    "    rocs.append(roc)\n",
    "    print(f\"Accuracy: {acc:.4f}, ROC-AUC: {roc:.4f}\")\n",
    "\n",
    "print(f\"\\nAvg Accuracy: {np.mean(accuracies):.4f}, Avg ROC-AUC: {np.mean(rocs):.4f}\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "0070e8bb",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[13:03:45] WARNING: not removing hydrogen atom without neighbors\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "from rdkit import Chem\n",
    "from torch_geometric.data import Data, DataLoader\n",
    "from torch_geometric.nn import GCNConv, global_mean_pool\n",
    "\n",
    "def atom_to_features_gcn(atom):\n",
    "    return [\n",
    "        atom.GetAtomicNum(),\n",
    "        atom.GetDegree(),\n",
    "        atom.GetFormalCharge(),\n",
    "        atom.GetNumExplicitHs(),\n",
    "        atom.GetNumImplicitHs(),\n",
    "        atom.GetIsAromatic(),\n",
    "        atom.GetMass(),\n",
    "        int(atom.IsInRing()),\n",
    "        int(atom.GetChiralTag()),\n",
    "        int(atom.GetHybridization())\n",
    "    ]\n",
    "\n",
    "\n",
    "def smiles_to_graph(smiles, label):\n",
    "    mol = Chem.MolFromSmiles(smiles)\n",
    "    if mol is None:\n",
    "        return None\n",
    "    atoms = [atom_to_features_gcn(atom) for atom in mol.GetAtoms()]\n",
    "    edges = []\n",
    "    for bond in mol.GetBonds():\n",
    "        i, j = bond.GetBeginAtomIdx(), bond.GetEndAtomIdx()\n",
    "        edges += [[i, j], [j, i]]\n",
    "    return Data(\n",
    "        x=torch.tensor(atoms, dtype=torch.float),\n",
    "        edge_index=torch.tensor(edges, dtype=torch.long).t().contiguous(),\n",
    "        y=torch.tensor([label], dtype=torch.float)\n",
    "    )\n",
    "\n",
    "graph_list = [smiles_to_graph(row['smiles'], row['SR-HSE']) for _, row in df.iterrows()]\n",
    "graph_list = [g for g in graph_list if g is not None]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "423aee98",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1: Loss = 12.3552\n",
      "Epoch 2: Loss = 11.6987\n",
      "Epoch 3: Loss = 11.5087\n",
      "Epoch 4: Loss = 11.3516\n",
      "Epoch 5: Loss = 11.0372\n",
      "Epoch 6: Loss = 10.8276\n",
      "Epoch 7: Loss = 10.6924\n",
      "Epoch 8: Loss = 10.5455\n",
      "Epoch 9: Loss = 10.4237\n",
      "Epoch 10: Loss = 10.1036\n",
      "Epoch 11: Loss = 9.8674\n",
      "Epoch 12: Loss = 9.6282\n",
      "Epoch 13: Loss = 9.5379\n",
      "Epoch 14: Loss = 9.3837\n",
      "Epoch 15: Loss = 9.1642\n",
      "Epoch 16: Loss = 9.0637\n",
      "Epoch 17: Loss = 8.9081\n",
      "Epoch 18: Loss = 8.8186\n",
      "Epoch 19: Loss = 8.7428\n",
      "Epoch 20: Loss = 8.5393\n",
      "Epoch 21: Loss = 8.4428\n",
      "Epoch 22: Loss = 8.3589\n",
      "Epoch 23: Loss = 8.1729\n",
      "Epoch 24: Loss = 8.3536\n",
      "Epoch 25: Loss = 8.0637\n",
      "Epoch 26: Loss = 7.8841\n",
      "Epoch 27: Loss = 7.6743\n",
      "Epoch 28: Loss = 7.5485\n",
      "Epoch 29: Loss = 7.4686\n",
      "Epoch 30: Loss = 7.4676\n",
      "Epoch 31: Loss = 7.4335\n",
      "Epoch 32: Loss = 7.3320\n",
      "Epoch 33: Loss = 7.1483\n",
      "Epoch 34: Loss = 6.8631\n",
      "Epoch 35: Loss = 6.9407\n",
      "Epoch 36: Loss = 6.8493\n",
      "Epoch 37: Loss = 6.8033\n",
      "Epoch 38: Loss = 6.7108\n",
      "Epoch 39: Loss = 6.5782\n",
      "Epoch 40: Loss = 6.7144\n"
     ]
    }
   ],
   "source": [
    "from random import choices\n",
    "from sklearn.model_selection import train_test_split\n",
    "from torch_geometric.loader import DataLoader\n",
    "\n",
    "# 1. Split into train/test\n",
    "train_graphs, test_graphs = train_test_split(\n",
    "    graph_list, test_size=0.2, stratify=[g.y.item() for g in graph_list], random_state=42\n",
    ")\n",
    "\n",
    "# 2. Balance the training set\n",
    "toxic = [g for g in train_graphs if g.y.item() == 1]\n",
    "non_toxic = [g for g in train_graphs if g.y.item() == 0]\n",
    "toxic_upsampled = choices(toxic, k=len(non_toxic))  # upsample to match\n",
    "train_graphs_balanced = non_toxic + toxic_upsampled\n",
    "\n",
    "# 3. Loaders\n",
    "train_loader = DataLoader(train_graphs_balanced, batch_size=32, shuffle=True)\n",
    "test_loader = DataLoader(test_graphs, batch_size=32)\n",
    "\n",
    "# 4. Focal Loss\n",
    "class FocalLoss(nn.Module):\n",
    "    def __init__(self, alpha=0.25, gamma=2.0):\n",
    "        super().__init__()\n",
    "        self.alpha = alpha\n",
    "        self.gamma = gamma\n",
    "\n",
    "    def forward(self, inputs, targets):\n",
    "        BCE = F.binary_cross_entropy_with_logits(inputs, targets, reduction='none')\n",
    "        pt = torch.exp(-BCE)\n",
    "        loss = self.alpha * (1 - pt) ** self.gamma * BCE\n",
    "        return loss.mean()\n",
    "\n",
    "# 5. Rich GCN Model\n",
    "class RichGCNModel(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.conv1 = GCNConv(10, 64)\n",
    "        self.bn1 = nn.BatchNorm1d(64)\n",
    "        self.conv2 = GCNConv(64, 128)\n",
    "        self.bn2 = nn.BatchNorm1d(128)\n",
    "        self.dropout = nn.Dropout(0.2)\n",
    "        self.fc1 = nn.Linear(128, 64)\n",
    "        self.fc2 = nn.Linear(64, 1)\n",
    "\n",
    "    def forward(self, data):\n",
    "        x, edge_index, batch = data.x, data.edge_index, data.batch\n",
    "        x = F.relu(self.bn1(self.conv1(x, edge_index)))\n",
    "        x = F.relu(self.bn2(self.conv2(x, edge_index)))\n",
    "        x = global_mean_pool(x, batch)\n",
    "        x = self.dropout(x)\n",
    "        x = F.relu(self.fc1(x))\n",
    "        return self.fc2(x)\n",
    "\n",
    "# 6. Training\n",
    "gnn = RichGCNModel()\n",
    "optimizer = optim.Adam(gnn.parameters(), lr=0.001)\n",
    "loss_fn = FocalLoss(alpha=0.25, gamma=2.0)\n",
    "\n",
    "for epoch in range(40):\n",
    "    gnn.train()\n",
    "    total_loss = 0\n",
    "    for batch in train_loader:\n",
    "        optimizer.zero_grad()\n",
    "        out = gnn(batch)\n",
    "        loss = loss_fn(out, batch.y.unsqueeze(1))\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        total_loss += loss.item()\n",
    "    print(f\"Epoch {epoch+1}: Loss = {total_loss:.4f}\")\n",
    "\n",
    "# 7. Save model\n",
    "torch.save(gnn.state_dict(), \"gcn_model.pt\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "50d2e4e8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Best threshold (F1): 0.498\n",
      "\n",
      "===== GCN Final Evaluation =====\n",
      "Accuracy: 0.9243\n",
      "ROC-AUC: 0.7838\n",
      "              precision    recall  f1-score   support\n",
      "\n",
      "   Non-toxic       0.96      0.96      0.96      1220\n",
      "       Toxic       0.33      0.32      0.33        74\n",
      "\n",
      "    accuracy                           0.92      1294\n",
      "   macro avg       0.65      0.64      0.64      1294\n",
      "weighted avg       0.92      0.92      0.92      1294\n",
      "\n",
      "GCN Model - Accuracy: 0.9243, ROC-AUC: 0.7838\n"
     ]
    },
    {
     "data": {
      "application/vnd.plotly.v1+json": {
       "config": {
        "plotlyServerURL": "https://plot.ly"
       },
       "data": [
        {
         "bingroup": "x",
         "hovertemplate": "color=0.0<br>Predicted Probability=%{x}<br>count=%{y}<extra></extra>",
         "legendgroup": "0.0",
         "marker": {
          "color": "#636efa",
          "opacity": 0.5,
          "pattern": {
           "shape": ""
          }
         },
         "name": "0.0",
         "orientation": "v",
         "showlegend": true,
         "type": "histogram",
         "x": {
          "bdata": "H2fJPGIxYD59KQk90i8MPmAzID7FUMg9/ganPpJt+T4MQ24+iJeIO6g1dD5gh5I93t4DPmh6Oz7p5Qs+K4EvPg9bET94BKA7U4T2Pl1jHjytVT88oiSzPYUouj4x9go+KriFPBROtT6qXKI+ErsaPitn9D5Uj7o9waaAPiVsKz6X9ZU+MC9aPrY3TD4shY4+12ZNPjWKiz5aeBg+R/GAPsQvIT1mCxQ+Ry+APrdzgz16KeE6xjoJPodVfT41yHU9EbKsPGpwRD8B9Bg+pa3mPXQ73DsXy7w+UnkzPrmdGT5Ifb08d0LvPWpiDz4w89I9rqE4PUxxsT20NEY+3EKWO2YmBT4LFaI+XsBqPowM/zvg99A9yOLSPnv3+T1xvK8+HVGiPq90Kjw4AA8+bOsYPxqfEj0QguM9JKmVPlxqqj2fqA4+L6G7PhfG3jxWivw+PQZPPmTswz6Ua6Q8ZFAnPQxWkj1ddbg6XRxwPvblkj76HYQ+VlbTPZ5qCj/Tjdw+tkURPuQ6SD3+sZk+kGRAPlHZrTw5sVo+RM1fPfoVRT4ZACw+1J+APtRleD0zDUE+aq+mPfRIoj2uSNE+UCZsPZvv/z2f8gI+4VetPrMJOj1lfB0/VTmcPkDGcDtfmIk6UbtbPlSGOD4er1Y+aKpuPk4dyT3KhoM9nUXXO/AmMDwhjFo+hHM2Pd2cPT4sgzU/PwxmPvYczT3XCVM+d446Pg8rSTtMX/k9FBxNPkonWj0X0h4+igXTPdtmHz2I/7082YT1PZqWqT5Y5UA9H2ftPUfEuD5XN3g+N5dnPXHjNT762HA+Vft7PN/ygT5GdT0+Nh66PgDIfD5DKLg+UeZOPhIwJD4C7AM/l8mTPslejT1qtUM+cBSBPtdbQz6/ROo74dCOPieGYT61gaA9SVxTPYRDLT8p3ww/keMfPt1DST4/56M+35BdPOcCnT5X6xk+QjPjPTV94z7lrIs9Oad7PU5KJzsryP099cunPndLVz6imRA+OvoUPKXD5T5aHZI+HHC/PV83MT4eGgI+ZMvOPqAeXz5nYqM35RyqPfC0uz7NSeM9GA+DPg/iJD6z45I+wKCQPh4HOT3xKUs+3LUvPUhhdD1qgiA+5sxrPr6Bvj5/K6I865WmPmOsJjw1y00+u33iPhtfHz6/zE8+71+iPhsMUD28hus9aAh0PlwkaD3nOcw6BebtPToLSj7iEp4+lsdHPkOYpz1ezCk9QMagPu1oUD0wfQg9MlGxPgmFtTzNf+09cLGTPv3lpDiQtMw9Xa8fPxEupz6l71U+RDixPuWrlT58/EA93nyAPqHjdD7ET7E9AXYQP3mR0j4wPTg+wb4dPYIFLD2TPKw9GN1FPjEMKT1LXfM+scDRPRcYvzxCgZk+OV+ZPsNaAT4aRIk+UNIhPprkQz7lTKw+xhHVPpIO+z7C1QE8gcuOPocyZj5l+rg+ImCPPZk1TT4ZJpc+nCF/Psl0ID7opj4/6lwnPaQt7D2PH4Y+81LhPT8CqD66po89nXAnPVNbxz5NUIo+IXE3PmR7+T1wiYg+kWAePqg4vT7TAH8+5yYjPu9OLT2ERPk8oCe8Ph61yT3uo3A+ImL/PTSlNTpPTPE9pJsyPjOdoz1lRAk/gOL0PXcwMT5gnAs+6r78PGaSEj9KSIY+y7mqPuH2tD45j40+i7wcPkCkvz7Ff/k+XKkZPmx1WT2lawg7ZYc9PnMz8j2wHd4+D+LnPtmlfj1y2e49X7EHPrMbRz5obgw+wROtPYjxCD2trN49DhujPR9tpT55INM8nw5HPrLyaD5hOqk+6VsmPuUPUD5cBno+xx6cPsC6qT791l89SJKCPkPZ3T2fAUQ9G++GPu0qDD8uqwc+Q5wFPqNvCD5rogs+mK9lPCoNkT7ASZg9RTEQP/uhhD5bOmo+7BRxPqKknz3heiU+roD1PF1J6T0bTwQ+EQjuPZ5eyz29pUo+UyEgPpDrmD6mrQ8+ZMADPSsTxj2rasw93hObPWxZDz58lrI92EkDPqnGqz4eWe48jMWOPZwMwz5V7Tg+49R+PiDB+T2jNy8/0/9aPhw+uD6OduI93BwMPozGVj5N1gA+OWIyPvKEmD7nTk4+v62UPnr8Mj4+aE4+6pUgPWueGT6WjiE974+lPX5XhT68rYc94/x7PrLO6T1EiBo9AAmMPlbLMDdJoz49VcM9Pv4fDj4aaww+phr8PQDPRD7LERM+iB/aPdM4Rj6pJK8+mVoRP2wnbj63QWU+2X+EPZNFOT4Afm0+5yi1PeylBj7p7K0+NmOEPNTVAT4PHhs+INXEPuAciD4ioOs+BLSZPhIKFz7xyJk+eqy3PrJBvz2Er7I+KkEgPkQUAD5FdaY7v7GNPUxbLD7vS4Y+6cVkPn4pgT7vZ1M+yemhPt1Hsj7D1YA+pVSuPVaSvj2+c2I+YpITPQenNT5aFvI+jMoZO0uxZT0nGP898rZyPizKXz7rU1s+upmYPk1A1T6Isfc9goW0Pi6ZoD00SIY+cHqqPlZyZDwdVgk+Rz26PjYQlj5VtHM+ea8ePgnzSz6+BiY9jyl+PtXX4T2Ezho+A0yCPY5sYD3lYhM+8v26PbCLDz9vvhU+9YmPPSDugT6+P0Y+w/cMPgzh0T5XZs49HZhKPf0S8Tx5nrI+McMkPVHfkT5yOAc/gfEHPqR8uT76XLE95VbGPYPfmz5U55s9WOl4PAS2+T53Xx8+S3jyPPNMVD6EFpE+hVTLPcq1zz7Ye0I+CwFZPKSeiD00ci4+VUxFPj+GYz5ziIE8YDoKPuy4Gj2ICSU97g4DPdDWuTwip+g+BuEXPuxZ/z1b+s076JutPsW5JD2vSFU+550KPggEGT5uQGI+0XFtPOLhFD5VTSI+SfHvPNf/5z4gXcU9/T2EPp3KrDyi8PM90mdwPuLkhz7OVEY8ElssP8pLMD7T8iw84G60PYO63z10Whs+QccrPr+taD0Kyxs+39lwPRp4oz2eRfE9FOURP3A5rT6Dd4I94h98PisgUz1PhGk9F6O5PYRDMz6kTmw+IW1tPoXNYT45ULc+NTLnPe9t3j1m9zc+XqQXPlCAiT477Gw+nlL9O7OirTz3+Cw8jVWJPjkwLT6h7BI+ImgNP2Z2Oz92qbY8IHrwPjE+7j268Wc9OZetPWALCz9Z7CQ+kSaJPq2R5TtRukk82NfKPnLRUT4vCeo99Y+7PlHqdj77nfA93QkQPjfQAT64iPs+kg4GPnErxT0EYhs8p7uGPo1wiD6gxJ8+z3+ePohybT6+6Qc96md1Pg/4DT+QSE0++NbfPZJjLj2hfV8+TlQrPewBSjyOhus3z//4PbSoEj3LI+I7wn1KPk1yRz4x1p09nkOUPmE95T3t3EY+lkl5PhDegz4XLso+nYYoPS3GXT5fe5g952IoPWACrz5q/fA8QBGjPclx5D0rE74+K+iUO2f4WzzvYBQ9EMLzPXY0jT4kXLQ9PO6oPuem2j0uhZM9I7+zPpXEhT67oEk+8HwEPai+Lz6RpFs+364FPosjdj0nffQ90Xc3PTx9kT66mHM+UrxZPOm/FT4lcio+RkLZPUAl/D1gWqw96u3ZPRiEPT4pcCc8npP1PVyiIz5eFIM+PL52Pur5Mjx1zfY+RlH5PBOsGj74AnE+0XxrPm6sZD0IWKU+jUkzPv7z5z5liyQ+iWE5Ph2E4z37dVE+jLdXPpES7j6geww+1pQZPtxRFT6NxQs8Vb5WPZbx6j0U8VU+M9jlPt+QKj8bKFA+ed5BPRjXBz73m4U8dIORPnyzET4wSZ8+hBk5Pzr/CT1opQc8v9qdPk8/4j5awEk9USwFPahSfD6yBrc+swA0PXdMbz4/thU/tq2vPcVBHz2IsT0+Of7DPewXhz5aVRE9HRcyPlPLdT5/bEE9lsi3PhY/7z7xFZs9z+A8PuzvJD48cSw9LjkGO7WgCT9CQCw+rE61PhINLD0lkAs+EcezPo3Y9D3KpOo71xV2PjgdDz68VhI+7GHUPkuhQD1c8iQ+oEe0PSNMMj7wadg+qUGFPM2IWj66kI8+8qWUPVeFCD6AhGs+6HVYPcq4yT2UKrY+6EdrPftX7T3dhiA+deATPrUhuD4A1Vk+aio0PQqtYj6yrLs+gsN6PlkrxD7rAbo+VRU8PqwLUT6cE18+fNWdPkCFwz3j8AI9dii/Purphj4Umw4+GneXPeThBz5y8gU+3DhiPfGX/j0aAU0+0odcPcSPoj3YqqU+DbpbPZDjED9OxrI8O7E0PohMTz3RR9U9qEguPR9iOz4/BqA+W4o/PIMIwT2U5Yw+aZdLPXtW4j4c9Co+GyxsPrTuuj0w+dg+DNdhPsBgvTrwHl48eqqdPvXGKDyQZa495UAZPVVznD5//Hc+YXsCP6KPtj26Fgk+M4SYPjFSDTxbDD4+ZkVjPUrMfz4c5yQ9TY+KO3YxBT7y6IQ9vl3XOxTK0T7i+uA9q0CTPpj+KT5Yts89UsR7PjOwLDy+mdU+lZ+WPnn5HT5sJKs9pYDpOx0kkDyt0U4+0peCPtInyT5BC7Q9AUDDPknC0z7WdY0+1FpqPJuEgj5Bwoc+ZAwtPuHbVD4AKxk+lEbaPf8nJD7RFFs+i+U9Pnprkji85WQ+tv6CPsOlCT47Mac9uyq5PgvQ8T4o3OY9V/kGP17e3T1BLvw9mCwCPvWWQj6t+049TMq2PnFZtT7mC1I+tc5OPt3DYz4EH5Y7Do2tPWSZmD3BTf0+KbkpPtPZxT1QUUQ8KOafPfgysj1u4Ac/JXCBPpnFAj8MzmA+hrK7PlnqBz4ktN89UFzpPg64lD5Y7y8+JeQQPuiWRT7+b40+IirbPh6Onz6Cw3o+ds0vPnEQpD5H/Ic+OqgEPv2L+Dwg07k980wCP/A2GT7vQJU+ya9lPsWZxT5L0+o+dKyqPiHERD6UNwQ/BmxgPeRAlj6IHWs+zWYgPho9FT5JDkc+kF/RPi71gD0E5Zw+xjWzPbfQjT1aFCs+33KQPW1APTxNSis+C0m3PVUiRT6VsXU+3oQpPqxYIT6zJZE9w2yjPXNvpD6WM6s9W3RuPheNZD6Cb00/CR7GPfBJHz6Vwmc9hZYnPV1GSD/ba50+JliVPsFRCD7P3TI9+FaFPkdzSz60Ick9+OeXPQb5hj3ExSQ+/bUSPayxaT7NVSc9YtfJPvVo7j5rGZw+gStQPLKl6TwNUrw+is1uPlGUBz4d6fY9TnQzPiPzuj6not89P1IuPh8Yjj4bh8k9wNuoPSa5ID7cFcY9vs+dPZtcMj4ZeL89NrGyPMgsij3JjoQ+RC7rPZmEvD6sudA+TUQnPhXaHD7zEpc9/ZRoPht6BTywNBM9TgXzPkbjWzxOI7A9fNw+PiDyhD5UQeM+fSfQPID2rj5iFJI9kjupPlCniz5XRc8+W18FPtADnz4bu+09h9ZJPhjHKj0w1PM+Fjy0Pc0urT3lda094xuNPfqflj3dqJs+HtqjPnrKij3vVxY+5z8/PrjYuT6YtTA+R8qaOuwGuz5GHcY+dQC1Ptx5Hz7qQxA3GEkVPGM0mT5ZUA49BmbIPtl96D6ukj0+SeSiPtl9jTynTY0+ecNgPlrqED79DA8/m0uSPig/ZT6NxYs9hS9vPjE/Jjyoqh8+gWkJP+/CoT7p9OM9wvmBPjeqpDzRj9c+vLOePdSPIT7Ahyw+JSddPrFGkz6z62M+svsfPf4Rmj5H4ao+9WfwPJT1jD6a7Fk+gLhVPqhPcj7Te589DqBUPme4sT0bQk89crMnPgKLwTzEGz8+Dr6+PMpldTsZZns9FIQiP4UdFT6viKA7GDHhPukLoD1ahns+RfDMPiMsMT72aMc+Yho9Plg9GD4z64Y88Nd4PqoKuT5C1+c9bev5PVVliz2tZew+nwE2Pr+kiT60jA0+h7PVPvXMKD5vegQ+tpkNPbtNTj3ucYs6Jt8XPK8NLz6fQwE/imIRPpuYcT7MPGo+boUgPgC1uT1WKWM++jdYPvNDST6h+4k7OExHPRvAgD5wbEs+islePqmkyTyzp2A+u5RxPNX/aj2glp4+eXSbPTkquz5LStA9xMueOUklCzxOSaM+EUU3PkHunD3bEQU+7EgyPtYzjzwNM2Q9PqQrPaGm1j3rczA+i6vrPaDDZj1Ka1Y+/YyxPlxMCT9qIRo+na7iPnOPbz6Hh5Q+iH+aPmmigj3QVhI+xNq+PiAj9D3aeX4+YJIhP90Ubj5pbMg6ni+sPd2NFDyOoAA+JfXVPMlugT30dCk9v6FUPR8aKD++2Ho+Jp/xPZQbjz7de/o+K4yQPSICFT5CSIQ+sChkPZk1rj2/ymg+bGgPPU8WLD5LaGs99SmJPq8fPz69WFc+Hy1bPvPOpD1YeVA+CdXPPmEsnj6fXWg9b5hEPo0mED90KAE+DwTrPn3h/T2NvFI9rc+hPKJsSz3QR/E+qxKWPohstT7Bk4Q8KWBkPBJXrj6LcCU/RYNhPTO3sj6r5xg+PpNzPsGs2D5iE708PEAaPn578j0=",
          "dtype": "f4"
         },
         "xaxis": "x",
         "yaxis": "y"
        },
        {
         "bingroup": "x",
         "hovertemplate": "color=1.0<br>Predicted Probability=%{x}<br>count=%{y}<extra></extra>",
         "legendgroup": "1.0",
         "marker": {
          "color": "#EF553B",
          "opacity": 0.5,
          "pattern": {
           "shape": ""
          }
         },
         "name": "1.0",
         "orientation": "v",
         "showlegend": true,
         "type": "histogram",
         "x": {
          "bdata": "IfXuPmeM8j74eHo+FrmWPm1DTz6n7gU/MZDrPaQypj4ftpY++14YP/sM1z3Zxps+IfUTP91rZz5aUQk/REUAPzKaST5uDBg/5c+aPZzEQTzjH7I+EpOOPkHTQT5LK8o+EzwgP+zhMT/MYRU/gcW7PiyJ3j713gs+2E1WP4Id3j6MUSU/doT/PtMdIT8mSLo+7sbfPlxqGz+jTgA/ZubMPQD68z5Mlrs+vHMWPi6mIj/j2iE+lgXdPm750j4065Q+c0/lPgkEFj7Dwbo+eswZPtdcxT400Rc/GQ4DP9R9ST+q+k4+dBJCPnzAZz6anB0+qdrAPmi3hD4UEps+RCatPg8hlT4RTyg/iAz/Pie1Jz/sfuY9hScnP9UDIz54gks98HwxP1tACT8=",
          "dtype": "f4"
         },
         "xaxis": "x",
         "yaxis": "y"
        }
       ],
       "layout": {
        "barmode": "overlay",
        "legend": {
         "title": {
          "text": "color"
         },
         "tracegroupgap": 0
        },
        "template": {
         "data": {
          "bar": [
           {
            "error_x": {
             "color": "#2a3f5f"
            },
            "error_y": {
             "color": "#2a3f5f"
            },
            "marker": {
             "line": {
              "color": "#E5ECF6",
              "width": 0.5
             },
             "pattern": {
              "fillmode": "overlay",
              "size": 10,
              "solidity": 0.2
             }
            },
            "type": "bar"
           }
          ],
          "barpolar": [
           {
            "marker": {
             "line": {
              "color": "#E5ECF6",
              "width": 0.5
             },
             "pattern": {
              "fillmode": "overlay",
              "size": 10,
              "solidity": 0.2
             }
            },
            "type": "barpolar"
           }
          ],
          "carpet": [
           {
            "aaxis": {
             "endlinecolor": "#2a3f5f",
             "gridcolor": "white",
             "linecolor": "white",
             "minorgridcolor": "white",
             "startlinecolor": "#2a3f5f"
            },
            "baxis": {
             "endlinecolor": "#2a3f5f",
             "gridcolor": "white",
             "linecolor": "white",
             "minorgridcolor": "white",
             "startlinecolor": "#2a3f5f"
            },
            "type": "carpet"
           }
          ],
          "choropleth": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "type": "choropleth"
           }
          ],
          "contour": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "colorscale": [
             [
              0,
              "#0d0887"
             ],
             [
              0.1111111111111111,
              "#46039f"
             ],
             [
              0.2222222222222222,
              "#7201a8"
             ],
             [
              0.3333333333333333,
              "#9c179e"
             ],
             [
              0.4444444444444444,
              "#bd3786"
             ],
             [
              0.5555555555555556,
              "#d8576b"
             ],
             [
              0.6666666666666666,
              "#ed7953"
             ],
             [
              0.7777777777777778,
              "#fb9f3a"
             ],
             [
              0.8888888888888888,
              "#fdca26"
             ],
             [
              1,
              "#f0f921"
             ]
            ],
            "type": "contour"
           }
          ],
          "contourcarpet": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "type": "contourcarpet"
           }
          ],
          "heatmap": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "colorscale": [
             [
              0,
              "#0d0887"
             ],
             [
              0.1111111111111111,
              "#46039f"
             ],
             [
              0.2222222222222222,
              "#7201a8"
             ],
             [
              0.3333333333333333,
              "#9c179e"
             ],
             [
              0.4444444444444444,
              "#bd3786"
             ],
             [
              0.5555555555555556,
              "#d8576b"
             ],
             [
              0.6666666666666666,
              "#ed7953"
             ],
             [
              0.7777777777777778,
              "#fb9f3a"
             ],
             [
              0.8888888888888888,
              "#fdca26"
             ],
             [
              1,
              "#f0f921"
             ]
            ],
            "type": "heatmap"
           }
          ],
          "histogram": [
           {
            "marker": {
             "pattern": {
              "fillmode": "overlay",
              "size": 10,
              "solidity": 0.2
             }
            },
            "type": "histogram"
           }
          ],
          "histogram2d": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "colorscale": [
             [
              0,
              "#0d0887"
             ],
             [
              0.1111111111111111,
              "#46039f"
             ],
             [
              0.2222222222222222,
              "#7201a8"
             ],
             [
              0.3333333333333333,
              "#9c179e"
             ],
             [
              0.4444444444444444,
              "#bd3786"
             ],
             [
              0.5555555555555556,
              "#d8576b"
             ],
             [
              0.6666666666666666,
              "#ed7953"
             ],
             [
              0.7777777777777778,
              "#fb9f3a"
             ],
             [
              0.8888888888888888,
              "#fdca26"
             ],
             [
              1,
              "#f0f921"
             ]
            ],
            "type": "histogram2d"
           }
          ],
          "histogram2dcontour": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "colorscale": [
             [
              0,
              "#0d0887"
             ],
             [
              0.1111111111111111,
              "#46039f"
             ],
             [
              0.2222222222222222,
              "#7201a8"
             ],
             [
              0.3333333333333333,
              "#9c179e"
             ],
             [
              0.4444444444444444,
              "#bd3786"
             ],
             [
              0.5555555555555556,
              "#d8576b"
             ],
             [
              0.6666666666666666,
              "#ed7953"
             ],
             [
              0.7777777777777778,
              "#fb9f3a"
             ],
             [
              0.8888888888888888,
              "#fdca26"
             ],
             [
              1,
              "#f0f921"
             ]
            ],
            "type": "histogram2dcontour"
           }
          ],
          "mesh3d": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "type": "mesh3d"
           }
          ],
          "parcoords": [
           {
            "line": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "parcoords"
           }
          ],
          "pie": [
           {
            "automargin": true,
            "type": "pie"
           }
          ],
          "scatter": [
           {
            "fillpattern": {
             "fillmode": "overlay",
             "size": 10,
             "solidity": 0.2
            },
            "type": "scatter"
           }
          ],
          "scatter3d": [
           {
            "line": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scatter3d"
           }
          ],
          "scattercarpet": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scattercarpet"
           }
          ],
          "scattergeo": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scattergeo"
           }
          ],
          "scattergl": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scattergl"
           }
          ],
          "scattermap": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scattermap"
           }
          ],
          "scattermapbox": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scattermapbox"
           }
          ],
          "scatterpolar": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scatterpolar"
           }
          ],
          "scatterpolargl": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scatterpolargl"
           }
          ],
          "scatterternary": [
           {
            "marker": {
             "colorbar": {
              "outlinewidth": 0,
              "ticks": ""
             }
            },
            "type": "scatterternary"
           }
          ],
          "surface": [
           {
            "colorbar": {
             "outlinewidth": 0,
             "ticks": ""
            },
            "colorscale": [
             [
              0,
              "#0d0887"
             ],
             [
              0.1111111111111111,
              "#46039f"
             ],
             [
              0.2222222222222222,
              "#7201a8"
             ],
             [
              0.3333333333333333,
              "#9c179e"
             ],
             [
              0.4444444444444444,
              "#bd3786"
             ],
             [
              0.5555555555555556,
              "#d8576b"
             ],
             [
              0.6666666666666666,
              "#ed7953"
             ],
             [
              0.7777777777777778,
              "#fb9f3a"
             ],
             [
              0.8888888888888888,
              "#fdca26"
             ],
             [
              1,
              "#f0f921"
             ]
            ],
            "type": "surface"
           }
          ],
          "table": [
           {
            "cells": {
             "fill": {
              "color": "#EBF0F8"
             },
             "line": {
              "color": "white"
             }
            },
            "header": {
             "fill": {
              "color": "#C8D4E3"
             },
             "line": {
              "color": "white"
             }
            },
            "type": "table"
           }
          ]
         },
         "layout": {
          "annotationdefaults": {
           "arrowcolor": "#2a3f5f",
           "arrowhead": 0,
           "arrowwidth": 1
          },
          "autotypenumbers": "strict",
          "coloraxis": {
           "colorbar": {
            "outlinewidth": 0,
            "ticks": ""
           }
          },
          "colorscale": {
           "diverging": [
            [
             0,
             "#8e0152"
            ],
            [
             0.1,
             "#c51b7d"
            ],
            [
             0.2,
             "#de77ae"
            ],
            [
             0.3,
             "#f1b6da"
            ],
            [
             0.4,
             "#fde0ef"
            ],
            [
             0.5,
             "#f7f7f7"
            ],
            [
             0.6,
             "#e6f5d0"
            ],
            [
             0.7,
             "#b8e186"
            ],
            [
             0.8,
             "#7fbc41"
            ],
            [
             0.9,
             "#4d9221"
            ],
            [
             1,
             "#276419"
            ]
           ],
           "sequential": [
            [
             0,
             "#0d0887"
            ],
            [
             0.1111111111111111,
             "#46039f"
            ],
            [
             0.2222222222222222,
             "#7201a8"
            ],
            [
             0.3333333333333333,
             "#9c179e"
            ],
            [
             0.4444444444444444,
             "#bd3786"
            ],
            [
             0.5555555555555556,
             "#d8576b"
            ],
            [
             0.6666666666666666,
             "#ed7953"
            ],
            [
             0.7777777777777778,
             "#fb9f3a"
            ],
            [
             0.8888888888888888,
             "#fdca26"
            ],
            [
             1,
             "#f0f921"
            ]
           ],
           "sequentialminus": [
            [
             0,
             "#0d0887"
            ],
            [
             0.1111111111111111,
             "#46039f"
            ],
            [
             0.2222222222222222,
             "#7201a8"
            ],
            [
             0.3333333333333333,
             "#9c179e"
            ],
            [
             0.4444444444444444,
             "#bd3786"
            ],
            [
             0.5555555555555556,
             "#d8576b"
            ],
            [
             0.6666666666666666,
             "#ed7953"
            ],
            [
             0.7777777777777778,
             "#fb9f3a"
            ],
            [
             0.8888888888888888,
             "#fdca26"
            ],
            [
             1,
             "#f0f921"
            ]
           ]
          },
          "colorway": [
           "#636efa",
           "#EF553B",
           "#00cc96",
           "#ab63fa",
           "#FFA15A",
           "#19d3f3",
           "#FF6692",
           "#B6E880",
           "#FF97FF",
           "#FECB52"
          ],
          "font": {
           "color": "#2a3f5f"
          },
          "geo": {
           "bgcolor": "white",
           "lakecolor": "white",
           "landcolor": "#E5ECF6",
           "showlakes": true,
           "showland": true,
           "subunitcolor": "white"
          },
          "hoverlabel": {
           "align": "left"
          },
          "hovermode": "closest",
          "mapbox": {
           "style": "light"
          },
          "paper_bgcolor": "white",
          "plot_bgcolor": "#E5ECF6",
          "polar": {
           "angularaxis": {
            "gridcolor": "white",
            "linecolor": "white",
            "ticks": ""
           },
           "bgcolor": "#E5ECF6",
           "radialaxis": {
            "gridcolor": "white",
            "linecolor": "white",
            "ticks": ""
           }
          },
          "scene": {
           "xaxis": {
            "backgroundcolor": "#E5ECF6",
            "gridcolor": "white",
            "gridwidth": 2,
            "linecolor": "white",
            "showbackground": true,
            "ticks": "",
            "zerolinecolor": "white"
           },
           "yaxis": {
            "backgroundcolor": "#E5ECF6",
            "gridcolor": "white",
            "gridwidth": 2,
            "linecolor": "white",
            "showbackground": true,
            "ticks": "",
            "zerolinecolor": "white"
           },
           "zaxis": {
            "backgroundcolor": "#E5ECF6",
            "gridcolor": "white",
            "gridwidth": 2,
            "linecolor": "white",
            "showbackground": true,
            "ticks": "",
            "zerolinecolor": "white"
           }
          },
          "shapedefaults": {
           "line": {
            "color": "#2a3f5f"
           }
          },
          "ternary": {
           "aaxis": {
            "gridcolor": "white",
            "linecolor": "white",
            "ticks": ""
           },
           "baxis": {
            "gridcolor": "white",
            "linecolor": "white",
            "ticks": ""
           },
           "bgcolor": "#E5ECF6",
           "caxis": {
            "gridcolor": "white",
            "linecolor": "white",
            "ticks": ""
           }
          },
          "title": {
           "x": 0.05
          },
          "xaxis": {
           "automargin": true,
           "gridcolor": "white",
           "linecolor": "white",
           "ticks": "",
           "title": {
            "standoff": 15
           },
           "zerolinecolor": "white",
           "zerolinewidth": 2
          },
          "yaxis": {
           "automargin": true,
           "gridcolor": "white",
           "linecolor": "white",
           "ticks": "",
           "title": {
            "standoff": 15
           },
           "zerolinecolor": "white",
           "zerolinewidth": 2
          }
         }
        },
        "title": {
         "text": "GCN Model - Prediction Probability Distribution"
        },
        "xaxis": {
         "anchor": "y",
         "domain": [
          0,
          1
         ],
         "title": {
          "text": "Predicted Probability"
         }
        },
        "yaxis": {
         "anchor": "x",
         "domain": [
          0,
          1
         ],
         "title": {
          "text": "count"
         }
        }
       }
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import plotly.express as px\n",
    "import torch\n",
    "from sklearn.metrics import accuracy_score, roc_auc_score\n",
    "\n",
    "# Evaluate the GCN model\n",
    "from sklearn.metrics import precision_recall_curve, classification_report\n",
    "\n",
    "gnn.eval()\n",
    "all_preds, all_labels = [], []\n",
    "\n",
    "with torch.no_grad():\n",
    "    for batch in test_loader:\n",
    "        out = gnn(batch)\n",
    "        probs = torch.sigmoid(out)\n",
    "        all_preds.extend(probs.cpu().numpy())\n",
    "        all_labels.extend(batch.y.cpu().numpy())\n",
    "\n",
    "all_preds = np.array(all_preds).flatten()\n",
    "all_labels = np.array(all_labels).flatten()\n",
    "\n",
    "precision, recall, thresholds = precision_recall_curve(all_labels, all_preds)\n",
    "f1_scores = 2 * (precision * recall) / (precision + recall + 1e-8)\n",
    "best_threshold = thresholds[np.argmax(f1_scores)]\n",
    "\n",
    "# 🔽 Save threshold for use in Streamlit/Dash\n",
    "np.save(\"gcn_best_threshold.npy\", best_threshold)\n",
    "print(f\"Best threshold (F1): {best_threshold:.3f}\")\n",
    "\n",
    "preds_binary = (all_preds > best_threshold).astype(int)\n",
    "\n",
    "print(\"\\n===== GCN Final Evaluation =====\")\n",
    "print(f\"Accuracy: {accuracy_score(all_labels, preds_binary):.4f}\")\n",
    "print(f\"ROC-AUC: {roc_auc_score(all_labels, all_preds):.4f}\")\n",
    "print(classification_report(all_labels, preds_binary, target_names=[\"Non-toxic\", \"Toxic\"]))\n",
    "\n",
    "\n",
    "#all_preds = np.array(all_preds)\n",
    "#all_labels = np.array(all_labels)\n",
    "#preds_binary = (all_preds > 0.5).astype(int)\n",
    "\n",
    "gnn_acc = accuracy_score(all_labels, preds_binary)\n",
    "gnn_roc = roc_auc_score(all_labels, all_preds)\n",
    "print(f\"GCN Model - Accuracy: {gnn_acc:.4f}, ROC-AUC: {gnn_roc:.4f}\")\n",
    "\n",
    "# Visualization\n",
    "df_gnn_viz = pd.DataFrame({\n",
    "    \"Predicted Probability\": all_preds.flatten(),\n",
    "    \"Actual Label\": all_labels.flatten()\n",
    "})\n",
    "fig_gnn = px.histogram(df_gnn_viz, x=\"Predicted Probability\", \n",
    "                       color=df_gnn_viz[\"Actual Label\"].astype(str),\n",
    "                       barmode=\"overlay\", \n",
    "                       title=\"GCN Model - Prediction Probability Distribution\")\n",
    "fig_gnn.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "d15e4039",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAArMAAAIjCAYAAAAQgZNYAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAd5ZJREFUeJzt3Qd4k9X3wPFTZtmobGSJgCzZW2SDMkRZZckWZAgCAsreAgKCylAUEESmiCiIIIqogCBDhuwhyEZkj5aS/3Ou/+TXlrZ0JW/e5Pt5ntAmzbjJTcvJfc89J8DhcDgEAAAAsKFEVg8AAAAAiCuCWQAAANgWwSwAAABsi2AWAAAAtkUwCwAAANsimAUAAIBtEcwCAADAtghmAQAAYFsEswAAALAtglkAcLPcuXNLu3bt4nTbgIAAGT58eIKPCQB8BcEsgARx/Phx6dGjh+TPn19SpkxpToUKFZLu3bvL7t27I73Nrl27pHXr1pIjRw5Jnjy5PProo1KzZk2ZM2eOhIaGhgvo9DRp0qQH7mPu3LnmZ7///nu049uwYYPrfj777LNIr1OpUiXz8yJFiogvc74OzlPatGmlSpUqsmrVqihvs2/fPjNX2bNnN3OVLVs2adWqlbk8KkePHpUuXbrIE088IYGBgeZx9DWeOnWq3L59O0Zj1Xlr1KiRZMmSRZIlSyaZMmWSBg0ayPLly+P03AH4niRWDwCA/X3zzTcSFBQkSZIkMQFOsWLFJFGiRHLgwAETdMyYMcMEu7ly5XLd5uOPP5ZXX31VMmfOLC+//LLky5dPrl+/LuvXr5eOHTvK2bNnZeDAgeEe55133pGuXbuaQDmuNKj6/PPPTWAW1okTJ2TTpk3m5/6gVq1a0qZNG3E4HPLXX3+ZOdIg8dtvv5U6deqEu67OYYsWLcyHDZ2bPHnymNfrk08+kWXLlsmiRYvkpZdeCncbDYybNm1qAl99HP2AEBwcLL/88ov069fPBMEfffRRtGMcNmyYjBw50rw3NCjW988///wjq1evlsaNG8uCBQukZcuWbnl9ANiIAwDi4ciRI45UqVI5ChYs6Dhz5swDPw8JCXFMnTrVcfLkSddlmzdvdiROnNjxzDPPOK5du/bAbbZt2+aYM2eO67z+qSpevLj5OmnSpHDX1evp5Xqb6Pz444/meo0aNXIkSZLEcfHixXA/HzNmjCNz5sxmTIULF3YkpFy5cjnatm0bp9vqmIcNG5ag49H77N69e7jL/vzzT3P5888//8D8pkyZ0vHUU085Lly4EO5n+hrq5Tr/R48edV1+7NgxR+rUqc3PIntPHD582DFlypRox7h06VIzniZNmjiCg4Mf+PmaNWscX3/9tSMh3Lx5M0HuB4A1SDMAEC8TJkyQmzdvmtSArFmzPvBzXa3t2bOnSSVwGjFihDm8rStradKkeeA2pUuXfiDHVA9PV69e3TxeTA9RR6Zhw4ZmtXDp0qXhLtfV2mbNmknixIkfuM29e/dk1KhRkjdvXnNbzYHVVeO7d++Gu57GiaNHj5bHH3/crB5Xq1YtysPwV65ckddff92VYvHkk0/K+PHj5f79+2KFggULSoYMGUxqQMTV8Fu3bplV1IwZM4b7mV7/ww8/NPOv8+Kk39+4ccOs3Eb2ntDn2qtXr2jHM2TIELMSPHv2bEmaNOkDP9fV4/r164dLNdHV4shSS/SrU9WqVc0q8fbt2+XZZ58186Rzqfel6RCRqVChgnlPhqWpKqVKlZIUKVKYcTZv3lxOnToV7XMC4B4EswDinWKgwUm5cuVidH0NjDSVQAOJnDlzxuqxdCPU+fPnzSHxuNLgRQPahQsXui77448/TNAZ1SHrTp06ydChQ6VkyZLy7rvvmvzSt99+2wQwYel1NAjTNAsNAjU4ql27tgn2Ir4Geh8aEOkh+Pfee88E62+99Zb06dNHrHD16lX5999/5ZFHHgl3+ddff22C98qVK0d6O51H/XnYfFu9jT73ihUrxmkshw8fNikqL774YqQfduJLUxWef/55KV68uEyZMsV86NA0GU2F2bZtW7jragrGli1bws31mDFjzLxp+sPkyZPNhxLne1o/pADwLHJmAcTZtWvX5MyZMyboiEj/U9cVTadUqVKZVawjR45ISEiIFC1aNNaPpwGVBh7O3Fm9v7jQoFXzQ3UlTVdGdYVYg6/y5cs/cF0NdD/99FMT0M6aNctc1q1bN7MRaeLEifLjjz+aMV28eNGsSNarV88Ec7oiqAYNGiRjx44Nd58aAOkK6M6dO01ApDQnVDdV6XPr27dvuJVsd7hz545cunTJrCafPHlSBg8ebDbdNWnSJFyAq/OrwX90nn76aVm5cqXJedb7O3369ENvE539+/ebr3F5j8TEuXPnZObMmeY1D/te1hXyxYsXS5kyZVyXL1myxMylrto7g1vN5dUV+LA53bpJrUSJEjJ9+vQHcr0BuBcrswDiTAMAlTp16gd+podz9bC08zRt2rRwt4nripuuzjqDkbjS1VI9NKwblzT40q+6wSkyutlIRVwx1YBTOVckv//+e7PB6bXXXnMFskpX7SLSFAcNzHUVVANK50krOWhAuXHjRnE3TQHQedGgXA+h68pi//79wz1PDU5jMlfOn+vcxnd+nfcT3/uIjgat7du3D3eZVlrQ1VoNXv9LK/6PBrf6Icd5FEE3w2kqiAa3YedOqy3oBxP9cAPAs1iZBRBnzmBD8yMj0lxKDYY0LSBs5QANGsIGSrGlh3J1JVRXQbUaQlxoDqbutNc82bJly5oV2qhSDHQlTiszaCpFWBq8pE+f3vzceT3lXGl10oAx4qF7PYyu5coi5qA6XbhwIVbPR4P7sNKlS/fQVWtdOdVSahqA66F1XT3W9Ad9rhHn92FzFVnQG9f5TYj3yMNoeTEt8xWRphqsWLFCNm/ebFIkdPVcc2s1FSHs3GmwG3GenSLL7wXgXgSzAOJMgybd4LN3794HfubMoY24KUeDQt0UtmfPnjg/rh7m1ZVfDZg1oIwLDV51dVdXejXHVWviRifsamt86cqelsbSldDIaK3e2Ii4yUo34z2sSYNuUtOVYFW3bl2zmUuDW/2goIfMw85vVHWCnfTnGiA6g1BNl4jsPRFTTz31lPka0/dIVHMTtlZxWFEF+pp6ojnVujqrwax+1eBeP/iEnTt9PC1hFtlmwciOUgBwL9IMAMSL5ohqHuzWrVtjdH0NFrQqgR5Kj+vub908pcGs7v6Pa2WDZ555xhw61p3u0dUq1dqmGsDoilxYuuKsecHO2rnOrxGvp7m0urEqLK2KoKvZGkxGdortxrh169aFO0WsExsTmj+q49Lc2bCH2XWXv26M0vqwkfn555/NBxZnZQHnbXRVU1c440KD+QIFCshXX30V6ap/RM6V74ibr5yr5TGled06dk0D0TnXFANNB9Hg3ElfI319tNZuZHMXWd41APcimAUQL7q6qAFqhw4dTIAXUdjAKOzKql6uzRIiC1b00K5uuopJ7uzDCu9HRVfXtIqAjkXHERVdtVRhDzU7N3E5g3mlgYweYn7//ffDPeeIt1Oab6mB3nfffffQjXMxETGgiqwc1sPoarnmAevmKw0inbTBga5karCrVQDCunz5skn10PnX64V9T2hgqJvmIntPaKCrXcCio+Xb9PH0PiJ7PdauXWsqaTgDTBU211hXZePy3tBUA930pk09dPOfng9LV611RVbHF/G9recjvkYA3I80AwDxormDmnuqG6h0Nc3ZAUz/Y9cVPf2ZHqrVw9pOeghXN4RpVQA9pBy2A5iulOrOeN0t/rDVWT399NNPcR675o0+bNe9Ppe2bduawEgDTX1MXYXWYFurOOhheaX5r2+88YYp2aWrexoEa7UCPRyth/DD0sBPn6NeT9MBtF6plu/Sw+raUUtXOiPexhN0LFpeTFe8nRUqdF70ueq8anWBiB3AdPOTljlzBpRKv9d510BQ69eG7QCmXdZ05fNhaRB6W309tAyWvo76/nJ2AFuzZo3ZsKaPoQoXLmxWRLW0mQbYzs19sf1QoHTeNPdX51KDVu00FpY+N31v6mPpa+AsH6bv9S+//FI6d+5sbgvAgyxq1gDAx2inqK5duzqefPJJR2BgoCNFihSmA9Srr77q2LVrV6S32b59u6Nly5aObNmyOZImTep45JFHHDVq1HB8+umnjtDQ0Gg7VoXt6hWbDmDaWSo6VapUeaADmHYxGzFihCNPnjxmnDly5HC89dZbjjt37oS7no5Zr5c1a1bz/KtWrerYu3dvpB3Arl+/bu5DX69kyZI5MmTI4KhYsaJj4sSJ4TpeeaoDmNPw4cPNz/X1Cmv37t2OFi1amOemr0GWLFnM+T179kT5OIcOHXK88sorjty5c5vnmCZNGkelSpUc77///gOvXVTWr1/vaNiwoSNTpkymc1vGjBkdDRo0cHz11VfhrqcdyGrWrOlInjy56eQ2cOBAx7p16x54LpHNb0StWrUyt9P7i8oXX3xhusVp9zM96XtdX9ODBw/G6HkBSDgB+o8ng2cAAAAgoZAzCwAAANsimAUAAIBtEcwCAADAtghmAQAAYFsEswAAALAtglkAAADYlt81TdAWhdrdRYtcJ2SvdQAAACQMrRyrjXS0nbQ23omO3wWzGsjmyJHD6mEAAADgIU6dOhWug2Rk/C6Y1RVZ54uTNm1atz9eSEiI6SFeu3Zt07cd9sMc2h9zaH/Mob0xf/YX4uE5vHbtmll8dMZt0fG7YNaZWqCBrKeC2ZQpU5rH4hfYnphD+2MO7Y85tDfmz/5CLJrDmKSEsgEMAAAAtkUwCwAAANsimAUAAIBt+V3ObEzLQdy7d09CQ0MTJMckSZIkcufOnQS5P3iep+cwceLE5vEoHQcAwMMRzEYQHBwsZ8+elVu3biVYYJwlSxZTPYHgxJ6smENNss+aNaskS5bMI48HAIBdEcxGaKhw/PhxszKmRXo1kIhv8KL3eePGDUmdOvVDi/7CO3lyDjVw1g9UFy9eNO/FfPny8b4BACAaBLNhaBChgYvWNdOVsYSg96f3GxgYSFBiU56ewxQpUpiyJ3/99ZfrcQEAQOSIriJB0Amr8R4EACBm+B8TAAAAtkUwCwAAANsimAUAAIBtEcz6iHbt2pnKC3rSzUN58uSR/v37m9qoEX3zzTdSpUoVSZMmjdnoVqZMGZk7d26k9/vFF19I1apVJV26dGY3/9NPPy0jR46Uy5cvP3RMCxcuNJUhunfv/sDP9PHSp08f6e30OaxYsSLBxhHWhg0bpGTJkpI8eXJ58skno3zeTsOHDzfP4ZFHHjFfna9xqlSpwl1vypQpUqBAAbN5SzcQ9u7dO9LXXo0bN87cx+uvvx6rsQMAgAcRzPqQ5557ztTIPXbsmLz77rvy4YcfyrBhw8Jd5/3335eGDRtKpUqV5LfffpPdu3dL8+bN5dVXX5U33ngj3HUHDRokQUFBJtj99ttvZe/evTJp0iT5448/ZP78+Q8dzyeffGICag1qowrsYiK+43DSUlf16tWTatWqya5du0ww2alTJ/nuu++ivI2+JqdPn5YDBw6Yr/r6FipUSJo2beq6zueffy5vvvmmea33799vnvfixYtl4MCBD9zftm3bzLxoMA4AABKAw89cvXrVoU9bv0Z0+/Ztx59//mm+JpTQ0FDHv//+a766U9u2bR0NGzYMd1mjRo0cJUqUcJ0/efKkI2nSpI4+ffo8cPv33nvPvC5btmwx53/77TdzfsqUKZE+nj6n6Bw7dsyRIkUKx5UrVxzlypVzLFiwINzP58yZ40iXLl2kt9XH/fLLLxNkHGH179/fUbhw4XCXBQUFOerUqRPjOdy1a5cZz8aNG10/7969u6N69erhbqOvcaVKlcJddv36dUe+fPkc69atc1SpUsXRq1evKB/THe9FfxYcHOxYsWKF+Qp7Yg7tjfmzv2APz2F08VpEltaZ3bhxo7zzzjuyfft2s+L15ZdfyosvvvjQw8R9+vSRffv2mcO5gwcPNofY3anB+7/Ixet343hrh9x3OCSRab4QuwYMGdMkl69feyZOj6qrl5s2bZJcuXK5Llu2bJlpzRpxBVZ16dLFrCTqKmq5cuVkwYIF5nB+t27dIr3/qFIEnObMmWNWQTUtoHXr1ma1smXLlrF+HjEdx4kTJ0xqxY8//mjSESKzefNmqVmzZrjL6tSpE6vD/R9//LHkz59fKleu7LqsYsWK8tlnn8nWrVulbNmyZmV89erV8vLLL4e7raZb6GuiYxg9enSMHxMAAETN0mD25s2bUqxYMenQoYM0atQoxoeJ9ZC4Bjnr1683h4m17acGJe6igey5a3E/TO4pmgurgd+9e/fk7t27plbpBx984Pr5oUOHTHCpr1dE2u3siSeeMNdRhw8fNuc1/zYuTQY0F1VTGpSmMfTt29fMnwacsRHTcejPNWc1umYX586dk8yZM4e7TM9fu3ZNbt++bfJdo6OpEvq+05SCsDRIv3TpkjzzzDOmg5e+/voeDZtmsGjRItmxY4dJMwAAAD4SzD7//PPmFFMzZ840wZDmS6qCBQvKL7/8YvJD3RnM6gpp3MVvZTY2NBd0xowZ5kOCviZJkiSRxo0bS1z8d7Q/eidPnjT5o04avOlp3bp1Zgx169Y1l2fIkEFq1aols2fPllGjRiX4OFT27NlNXqs76ZGD69evS9u2bR84WjB27FiZPn26WdU+cuSI9OrVyzzXIUOGyKlTp8x5fV3o5gUAsKN79+6Jt7JVO9u4HCbWFUo9OekqnNLD7XoKS89r8KQri3py+qp7xTiPWe9PAyCtHKA72GMr7Dge9ji6KqmrmM7D4SVKlJBZs2ZJx44dzWX58uWTq1evyt9//y3ZsmULd3ttm3r06FFziF4fU6+rHxT0tYtqVTRLlixmtdHp0UcfNbfVx9YqA2FXOvVy3Wymm6R0xVhXkDXg1V+OsN2urly5Yr7q6xXTccSUjldXZ8O+pprekjZtWlPdIKrX2hlQa6qEHhnImDFjuOtqwKqpFHqEQRUuXNjMua7OvvXWW2Y19sKFC6aKglNoaKhJs9GVc10V1koJYen96+PqezLizxB7zt/1iL/zsA/m0N6Yv4Tx7d5zMmX9UbkZ7LnA0uFwyMXfv5Xzm5bLE23HyUcnNsuKbhXc/rixea/YKpiNy2Hit99+W0aMGPHA5WvXrn3gkLSuZGrAc+PGDRPcJSQNbtw96RoYOoN1pauBmlNcv35989ro6qgGhFoaKmLOpu6w1+CyQYMG5j5eeOEFkyagK7walEWkQbGmLGTKlCnc5Zq7unLlShP4PfXUU+GCN12p1ZJb+oFEV1J1vL/++qtJNXHSwFVpKkRsxhETGtzr6mjY10irI2iVhLCXReavv/4yK7BauSDidXVu9fUPe7nz/aPj0/vX5xlWjx49TKCuc6Sve0R6e31Pa8DrzZ+G7UbnH/bGHNob8xc/Y3cllvO3Y78wFlf3796Sf76bJrf2/2TOn/7tW0lcpanZF+Jut27d8s1gNi50ZUw3jDlpwKEbx2rXrm1W5CLmROohYV01TKjDwfFdmY0pDVI1GA/7nNq0aWPqpOrmJM1Z1RXD8ePHmw1gej1dTdTbafCpK6b6OlWvXt3cVr/269fPBMP//POP2Zinq7l6CF0DX80P7dmzZ6Qbvx577DFzKD7i89WUEs0d1fxoPRyvwbUGc7oJUFeUDx48aEp5NWvWzBUIx3QcWjZL709zdXUTVmT0erpqPGbMGGnfvr3ZLKbB9ddff+163aZNm2YuC/sHV+dQX0MNsDVtI+JKqZY602Bbn5MzzUA/MOiHCK1PqycN3sPSx9MPTuXLl490rPpe1A8gzz77LKkJCUA/bOicOj/QwX6YQ3tj/hLG2H0/idy+K4kC4psC+XA3zxyRI4tGy91/ToskSiSP12wvj5R9QR5/LK3Urev+ldmHLTLZNpjV//zPnz8f7jI9r4FBVJt39PCxniLSX6aIv1C6eqgBmB72DnvoOz6ch6Od9+suzmL+YR9DN3XpCqAGi1oNQAv9azH/vHnzysSJE+W9994zz1mDXM211QAvrAkTJkjp0qVNgKeBoz4XvW2TJk1MBYnIno8Gsy+99FKkh8b1drrDX1MQNI92yZIlJoju2rWrnDlzRh5//HFzWz1sH/a+YzIOfR4aDGsQGNXrrLdZtWqVeQ30uevjaXAbNm9bA2ZNtwh7H7oyqiuyGqBH9kfYOd6hQ4eaoFrTEHSFW4Pm6OY8uveEXu5sgMEf/oTD62l/zKG9MX/xE/D/e28ypQmULQNruOUxHA6H2aPUe2Rvk+KnC4C6EKVHGXVFVgNZT8xhbB4jQOtziRfQ/7gfVpprwIAB5oXcs2dPuJ3kGhytWbMmxpG+HpbWw7+Rrcw6d9wn1GqYBl76mPpY7gxm4T5WzKE73ov+vir03x/huvxHalPMob0xfwmj/Nj1prpSlrTuC2YPHz5sFrl0znRhxnnE1dNzGF285lUrs5qbqodknfQ/b+3MpBuJcubMaVIEdKVr3rx55ueaM6kbZvRQtG62+eGHH8zqnq62AQAA37Vq91mZvO6g3LwbKv7qwnX3lwnNly+fTJ482QSvusHenSmSCcXSYPb333835aScnLmtejhXcx91p7mWf3LSVSrnYeKpU6e6DhO7sywXAACwngayRy8+uGHWH6VKnnBVbhwOh1ko1GZAxYsXN5dpiqKdWBrMahmo6LIcNKCN7DY7d+5088gAAIA3ca7I6uYnzRn150C2b+0CCXJf//77rynfqWmeuiKr8ZXur7EbW20AAwAA/s2dm5/8yW+//SZBQUGm9KRuGNeKP9F10fRm7EgCAADwEw6Hw3RS1dKWGshqpZ9NmzaZ1AI75MdGhpVZAAAAP3Djxg1p0aKFfPPNN+a81nXXTqEPqxbg7QhmAQDwc+6uFOAQh9y5k9gU/XfWSvXGnfy+LmXKlKZ2rNbf1430nTt3tu1qbFgEswAA+DnPVAoIkKvBd71qJ7+/1EoPCQkxAazWSp8/f76cO3cuXCt5uyOYBQDAz7m7UsB/K7N3TBOYuK7MJvROfn9w4cIF09pea/d/9NFH5rLMmTObky8hmIVHurcBAPy3UsD/ukdVoQOYh/z0008mP1Zr9qdIkcI0otJ6/b6IagY+ol27diao1JP+odA3rHZK00/CAADAP4SGhsqoUaOkevXqJpAtWLCgbN261WcDWcXKrA957rnnTA9l/QS8fft200lNg9vx48dbPTQAAOBm586dk9atW8v69etdC13a3cuOjRBig2A2hm7ejDoxPnHixCYPKLLrauK1ntfraOK1nnS5/2H3G5c3niZ3Z8mSxXyfI0cOqVmzpqxbt84Es//884+pIbdx40bT8UPryg0cONAcggjbXe3pp582z0XbBGsR5VdffVWGDx/uus7hw4dNtxD9lPfEE0+Y3ZAR7dmzR3r16iWbN282OycbN25s+jynTp3a9ct15coVKVu2rLm97qzUVsY6Hj0M8sknn5jb6SfL9u3bx/p1AAB/qRKQUKgUYH/37983/+/v27fP/B86Y8YMky/rDwhmY8gZiEWmbt26smrVKtf5TJkyya1btyK9bpUqVWTDhg2u87lz55ZLly49cL3o2vzGxN69e00R5Fy5cpnzmm5QqlQpGTBggKknp+N9+eWXTVCrQaXTp59+agJL7QyiwagGnpUqVZJatWqZX5RGjRqZxHH9+dWrV+X1118P97ganNepU0cqVKgg27ZtM8nnnTp1MoF02PbEP/zwgzz++OMmuP71119NgKzjffbZZ819L168WLp06WIeV68HAHbkmSoBCYdKAfaVKFEis3ilC0P6f+hTTz0l/oJg1odoEWQNuu/du2dWO/WNrYcXVPbs2eWNN95wXfe1116T7777TpYsWRIumNWV2WHDhpnvtU+z3l4PV2hQ+f3338uBAwfM7bJly2auM3bsWHn++eddt//8889N4Dxv3jzX6rLeR4MGDcwvmXMH5aOPPirvvfeeGWOBAgVkwoQJ5gOA/hIqXaEdN26c/PLLL9K8eXOPvH4AYLcqAQmJSgH2c+bMGTly5IhZCFL16tUzC0pJkvhXeOdfzzaeXTOioikEYelqpJOuZl67ds2shjrTDMI6ceJEgo2xWrVq5rCCro6+++675s2sh/idCeEaeGrwevr0aQkODjYBb8Q+zBrMhpU1a1bX89m/f79JX3AGskpXYMPS62jturBpErqyq6/DwYMHXcFs4cKFw70WenmRIkXCvaaPPfZYuNcSAOzKXVUC4L90YUmPsIaEhMiuXbtcR2L9LZBV/veM4yg2Oaxhr6tBnAaSelnEQDa29xuTx33yySfN97NnzzZBpeaf6iH8d955x+SnTpkyRYoWLWquqykCGtSGFbFkim4g0+eQ0CJ7HE89NgAAdqVHX4cMGWKOXqrixYuby/wZwayP0sBZD9lr/mvLli1NXmrDhg3NLkelQeKhQ4ekUKFCMb5PLe9x6tQpU+pDV2zVli1bHriO5sbq6rAzUNfHdqYTAIA/bfZiYxUSkv4frBu39f9V1a1bN5k0aVK4Tej+iDqzPqxp06bmcP20adNM/qtWNtBNVpoKoJurzp8/H6v7012S+fPnNyW//vjjD/n5559l0KBB4a7TqlUr80ul19FNaD/++KPJz9VDIb7WcQQAItvsde7aHdfp/v/v5WVjFeJLN27rKqwGspq6qGmD+v97oJ8Hsopg1odp3oxWEdDNVX379pWSJUuaxHAtwaUlvGLbsUtXV7XT1+3bt82mMa1SMGbMmHDX0RxczeO5fPmylClTRpo0aSI1atRwbUQDAH/Y7JUlbaDrlDdjKjZWIUGCWf2/tXTp0rJz506zYIX/kGbgI8KWvQrrzTffNCe1YsWKaO8jbMkwp4i30ZVZXZGNroyY5uRq6a3YjDWyx07IzXEA4Cls9oI7aL12Leepddy1rjz+h5VZAAAAL6OLSXp0UzeRK00n0Db1BLIPIpgFAADwElo2U1dfX3rpJfniiy9MVSJEjzQDAAASoB0tlQsQX0ePHpWgoCDZvn27Oa/Njmjr/nAEswAAJGA7WioXIC6WLl1qNlZroyXtkqmdNLWjFx6OYDYSETc0AZ7GexCwZztaWsIiLt5++21XO3ftmrlw4ULTcRMxQzAbhrMD1a1btyRFihRWDwd+TN+DKmJXNADWoEIB3Kl+/foyevRokys7cuRIv2xJGx+8WmFog4H06dPLhQsXXDVTtaVqfGinLW0Ze+fOnUjb2cL7eXIOdUVWA1l9D+p7Ud+TAADfo104tdyls6TlkSNHXN01ETsEsxFoMwHlDGgTIjjRJgO60hvfwBjWsGIONZB1vhcBAL5D/z/RFdg5c+aYuu3ly5c3lxPIxh3BbAQarOgbKlOmTBISEhLv+9P72Lhxozz77LMcMrYpT8+hPgYrsoB3VC+gQgESkraTb9asmWn3rvHG1q1bXcEs4o5gNgoaTCREQKH3ce/ePVPsmGDWnphDwH9EVb2ACgWIr08//VS6detmUskyZ84sCxYsMO3eEX8EswAARFO9gAoFiI+bN29K9+7dTTCrNID97LPPSCVLQASzAABEQPUCJJRFixaZQFY3EI8YMULeeustUskSGMEsAACAm3To0MHkxrZs2VKqVKli9XB8EsEsAMDrWsNG5BCH3LmTWMbu+0kCxH1VRdjwhfi6fv26jBo1SoYMGSJp0qQxG70+/PBDq4fl0whmAQBe2xo2vAC5GnxXPIENX4iLP/74w1Qr0Bqy58+fd+XJwr0IZgEAXtka9sGV2Tumqog7V2YVG74Ql3rkuvr6+uuvy927d+Xxxx+Xzp07Wz0sv0EwCwDw+s1VWu959erVUrduFUrkwatcvXrVBK5LlixxtaadO3euPPbYY1YPzW8QzAIAAMTBvn37pGHDhnL06FFJkiSJjB8/Xnr37k3HTw8jmAUAAIiDDBkyyI0bNyRXrlyyePFiKVeunNVD8ksEswAAt1YicKJSAHzB7du3JUWKFOZ77eSl6S958uSRRx55xOqh+S2CWQCAByoR/A+VAmBXv/32mwQFBcm4ceOkefPm5rKSJUtaPSy/RzALAHBrJYKwqBQAu1YrePfdd2XAgAFy7949kxurJbi0qxesRzALAIgx2rzC3/zzzz/Srl07+eabb8z5pk2byqxZswhkvQgzAQAAEIlNmzZJiRIlTCCbPHlymTFjhtnolS5dOquHhjBYmQUAAIjg+PHjUqVKFZNWkC9fPlNHtnjx4lYPC5EgmAUAAIhAKxT06tVLzp49KzNnzpQ0adJYPSREgWAWAABARH766ScTxObMmdOc141emhtLEwTvRs4sAADwa6GhoTJq1CipXr26Kbml7ZNV4sSJCWRtgJVZAADgt86fPy+tWrWS9evXm/P58+c3wWzSpEmtHhpiiGAWAAD4pR9++EFatmxpAtqUKVPK9OnTpW3btlYPC7FEMAsAeGjLWlrRwtfSCkaOHGlSC7QhQpEiRUzJrUKFClk9NMQBwSwAIMYta2lFC1+gaQQrVqwwgWynTp1k6tSpZmUW9kQwCwCIUctaWtHCVwQGBpq6sdu3bzdpBrA3glkAQDi0rIWv0cYHQ4YMkVSpUsngwYPNZQUKFDAn2B/BLAAA8FmnTp2SFi1ayK+//mpqxgYFBZmOXvAd1JkFAAA+adWqVaYFrQayadOmlYULFxLI+iBWZgHAD0VWuYCKBfClDV4DBw6UiRMnmvOlSpUy1Qry5s1r9dDgBgSzAOCHoqtcQMUC2JlWKKhTp478+OOP5nzPnj1lwoQJkjx5cquHBjchmAUAPxRV5QIqFsDutP2s5sXu3LlTZs+eLS+99JLVQ4KbEcwCgB+jcgF8wd27d+Xvv/92pRF07txZXnzxRcmcObPVQ4MHsAEMAADY1rFjx6RSpUpSo0YN+ffff12rswSy/oNgFgAA2NKyZcukRIkSpvnB9evX5dChQ1YPCRYgzQAAfLxKQWSoXAA7u3PnjvTt21emT59uzuvKrJbdypEjh9VDgwUIZgHAT6oURIbKBbCbw4cPS7NmzWTXrl3m/JtvvikjR46UpEmTWj00WIRgFgD8oEpBZKhcADsaOnSoCWQzZMgg8+fPl+eee87qIcFiBLMA4IOoUgBf9cEHH5gNXu+8845kz57d6uHAC7ABDAAAeK39+/fLsGHDTDME9dhjj8nnn39OIAsXVmYBAIBXmjdvnnTt2lVu3bplasi2adPG6iHBC7EyCwAAvMrNmzelffv20rZtWxPIVq9eXWrXrm31sOClCGYBAIDX2Lt3r5QpU0bmzp0riRIlMpUK1q5dK1myZLF6aPBSpBkAAACvoLViO3bsKLdv35asWbOa3NiqVataPSx4OVZmAQCAV8iUKZNpiKApBVp+i0AWMcHKLAAAsDQ/NlWqVOb7GjVqyE8//WQ6emmKARATBLMAkMCtYq1Em1rYhZba+vDDD00ThE2bNsmTTz5pLq9cubLVQ4PNEMwCgJtaxVqJNrXwZteuXZNXXnlFlixZYs5rUKtNEABbBrPTpk0zb+Bz585JsWLF5P3335eyZctGef0pU6bIjBkz5OTJk6aVXZMmTeTtt9+WwMDo2zYCgCdbxVqJNrXwZtu3b5egoCA5evSoJEmSRMaNGye9e/e2eliwMUuD2cWLF0ufPn1k5syZUq5cOROo1qlTRw4ePGiSwCPSXY1vvvmmzJ49WypWrCiHDh2Sdu3ambZ2kydPtuQ5APA/tIoF4pZWoAtYAwYMkODgYMmVK5csWrRIypcvb/XQYHOWZldrAKqHGbQwcqFChUxQmzJlShOsRkZzajQpvGXLlpI7d26z27FFixaydetWj48dAADE3A8//GBWYDWQffHFF2Xnzp0EsrD3yqy+mfVQw1tvveW6THcu1qxZUzZv3hzpbXQ19rPPPjPBq6YiHDt2TFavXi0vv/xylI9z9+5dcwqbp6NCQkLMyd2cj+GJx4J7MIf2l1Bz6BCH6yvvB8/i99DedN6effZZ8/++pgd2797dHFVlPu0jxMO/g7F5nACHrvtb4MyZM5I9e3az2lqhQgXX5f379zdlOX777bdIb/fee+/JG2+8YQ5X3Lt3T1599VWTQxuV4cOHy4gRIyJNWdBVYACIqaHbE8vV4ABJl8whI0t5b0UDwBvo/9MbN240R1Q1N1bdv3+fkluIEW1jrEfir169KmnTpvXuDWCxsWHDBhk7dqxMnz7d5NgeOXJEevXqJaNGjZIhQ4ZEehtd+dW83LArszly5DApCg97cRLqk8W6deukVq1akjRpUrc/HhIec2h/CTWHY/f9JFeD75oNp3XrVknQMSJ6/B7ay+XLl00nr1WrVplAVheWdP50XwzzZ08hHv4ddB5JjwnLglmtRJA4cWI5f/58uMv1fFT9lzVg1ZSCTp06mfNFixY1xZY7d+4sgwYNivTTXvLkyc0pIp0IT/5CefrxkPCYQ/uL7xwGSIDrK+8Fa/B76P30iGvz5s3l1KlTkixZMsmTJ49rzpg/+0vqoTmMzWNYttavb/BSpUrJ+vXrXZfp4Qc9HzbtIOKSc8SAVQNiZVG2BAAA+P//w8ePH29yYzWQzZcvn0kZ7Nq1q9VDg4+zNM1AD/+3bdtWSpcubTZ0aWkuXWnV6gaqTZs2Jq9W68iqBg0amAoIJUqUcKUZ6GqtXu4MagEAgGddvHjR/H/+7bffmvNaaUgbIaRJk8bqocEPWBrMatFk/QXQVnbaNKF48eKyZs0ayZw5s/m5NkYIuxI7ePBgs/tRv54+fVoyZsxoAtkxY8ZY+CwAAPBvmiOrm700n1ybH2m+rP5/DXiC5RvAevToYU5RbfgKS5PIhw0bZk4AkBBW7T5r2tQ6u3tF58L1Ox4ZE2A3BQoUkAULFsgTTzxh9rMAfhXMAoCVNJA9evFmrNvFAv5MN2trWsHAgQNNjqxq2LCh1cOCnyKYBeDXnCuyiQL+a1Mbk0C2b+0CHhgZ4J10o3arVq1MQKvNi/bv38++FViKYBYA5L9AdsvAGlYPA/BaoaGhMnLkSFPbXSsIFS5cWJYsWUIgC8sRzAIAgId27dTVWOdeFt3gpR056aQJb0AwC8DnN3Y5xCF37iQ2HbycjQ+c2NQFRE9rxmpdeK0+lCpVKlNySwNbwFsQzALwk41dAaYVbVTY1AVE7vHHH5dq1arJwYMHTVpB/vz5rR4SEA7BLACf39iVMU1yuXPnjqmBGXFlVrGpCwjv77//ltSpU0v69OlNvdiPP/7YlMdMkSKF1UMDHkAwC8DnN3b93O9ZWb16tdStW4W+8MBDrFq1ypTdqlq1qixdutQEs3Tygjf7X3stAADgt0JCQqRfv35Sv359+eeff+T48eNy9epVq4cFPBTBLAAAfu6vv/4yzQ8mTpxozr/22muyadMmk2YAeDvSDAAA8GMrVqyQ9u3by5UrVyRdunQye/ZsadSokdXDAmKMYBYAAD91+/Zt6dmzpwlky5YtK4sWLZI8efJYPSwgVkgzAADAT2l1goULF0rfvn3l559/JpCFLbEyCwCAH1m2bJncvXvX1figUqVK5gTYFcEsAAB+QGst6wrs9OnTzYpsmTJlaIAAn0AwCwCAjzt8+LAEBQXJzp07zXnNkyWlAL6CYBaAW63afda0lnV25PKUC9fvePTxAG+lm7peeeUVuXHjhmTIkEHmzZsnzz//vNXDAhIMwSwAt9JA9ujFm5Y9vraqBfyRw+GQbt26ycyZM835ypUrm81e2bNnt3poQIIimAXgVs4V2UQB/7WW9XQg27d2AY8+JuAttA2trsTq10GDBsmwYcMkSRL+24fv4V0NwCM0kN0ysIZlbToBf6HpBKlTpzbfawBbt25dqVChgtXDAtyGOrMAAPiAmzdvSocOHaRq1aqm9JbSlVgCWfg6glkAAGxu3759poPXnDlzTMWCDRs2WD0kwGMIZgEAsPEmr9mzZ5uasX/++adkzZpV1q9fL3Xq1LF6aIDHkDMLAIANXb9+Xbp27SoLFiww52vXri3z58+XTJkyWT00wKNYmQUAwIa6dOliAtnEiRPL2LFj5dtvvyWQhV9iZRYAABsaPXq07N6929SRfeaZZ6weDmAZVmYBALCBa9euyZIlS1znn3jiCRPMEsjC37EyC/g5d7ebpa0sEH87duyQZs2aydGjRyVdunSuDV6JErEmBRDMAn7OU+1maSsLxK1awbRp06Rv374SHBwsOXPmNMEsgP8hmAX8nCfazdJWFoi9K1euSMeOHWX58uXm/AsvvGDqyD766KNWDw3wKgSzACxvNwsgvG3btklQUJAcP35ckiZNKu+884707NlTAgICrB4a4HUIZgEA8DL79+83gWyePHlk8eLFpikCgMgRzAIA4CX5sc6V1zZt2sjNmzelRYsWkj59equHBng1glnAzysQnLtGtQHAaps2bZI33nhDVq5cKRkyZDCXaXcvAA9HMAvYkDsqEFBtAPC8+/fvy8SJE2XgwIESGhoqgwcPNk0QAMQcwSxgQwldgYBqA4DnXbx4Udq2bWva0KrmzZvLhAkTrB4WYDsEs4CNUYEAsKeNGzeafNgzZ85IYGCgvPfee9KpUyeqFQBxQDALAIAHrVixQho3bmxSDAoUKGBa1D799NNWDwuwLYJZwIabt2gRC9hXtWrVJHfu3FKpUiWZPn26pE6d2uohAbZGMAvYePMWm7YAe9i9e7cULVrUpBFoO9qtW7eaTl6kFQDxRzAL2HTzFpu2AO+nFQpGjRolI0eOlA8++EC6detmLn/sscesHhrgMwhmAYuweQvwbWfPnpVWrVrJjz/+aM7v3bvX6iEBPolgFgCABLZu3Tpp3bq1XLhwQVKlSmVqx+p5AAkvkRvuEwAAv3Tv3j3T+KBOnTomkNUqBb///juBLOBGrMwCHq5QQCUCwLc3eo0bN04cDod06dJF3n33XUmRIoXVwwJ8GsEsYFGFAioRAL6nZMmS8s4770i2bNkkKCjI6uEAfoFgFrCgQgGVCADfEBISIsOGDZOXX35ZChYsaC7r3bu31cMC/ArBLJCAqFAA+I+TJ09K8+bNZfPmzfL111/Ljh07JGnSpFYPC/A7bAADACCWVq5cKcWLFzeBrDZBGD58OIEsYBGCWQAAYig4ONikETRs2FD+/fdfKVOmjOzcuVMaN25s9dAAv0WaAQAAMXDx4kWpV6+ebNu2zZzXoFYrFyRLlszqoQF+jWAWAIAYeOSRRyQwMNB8nTt3rrzwwgtWDwkAwSwAAFG7e/euBAQEmNXXJEmSyMKFC01jhFy5clk9NAD/j5xZAAAiceTIEalQoYIMGDDAdVn27NkJZAEvQzALAEAEixcvNg0QdHPXZ599JpcuXbJ6SACiQJoBkADta2lRC/iG27dvy+uvvy4fffSROV+5cmX5/PPPJUOGDFYPDUAUCGaBBGxfS4tawL4OHDggzZo1kz179pg82YEDB5r6sZorC8B78RsKJFD7WlrUAvbe6FWzZk05ffq0ZMqUyaQW1KpVy+phAXB3MHvnzh1TpgTwV7SvBXxD8uTJ5d1335UZM2bIggULJGvWrFYPCYC7NoDdv39fRo0aZXZ0pk6dWo4dO2YuHzJkiHzyySexvTsAACyxb98+2bhxo+t806ZNZf369QSygK8Hs6NHjzbFoidMmBCu60mRIkXk448/TujxAQCQoBwOh8yZM8e0om3SpImcPXvW9TPNlQXg48HsvHnzzC7PVq1aSeLE/9vsUqxYMZM8DwCAt7px44a0bdtWOnToYCoXFC9ePNz/ZQD8IJjV5Pgnn3wy0vSDkJCQhBoXAAAJavfu3VK6dGmZP3++JEqUSMaMGSNr1qwxG74A+FEwW6hQIfn5558fuHzZsmVSokSJhBoXAAAJllagRxTLlSsnBw8eNHs+NmzYYEpvaVALwM+qGQwdOtQcotEVWl2NXb58ufnjoOkH33zzjXtGCQBAHGke7K+//moq8Dz//PPm/yuaIAC+I9YfSRs2bChff/21fP/995IqVSoT3O7fv99cRk0+AIA3rcg6TZs2TWbOnGkWXQhkAd8Spzqz2t5v3bp1CT8aAAASIIidPn26/PDDD7J06VKTSqClJLt06WL10AB4QzD7xBNPyLZt2+Sxxx4Ld/mVK1ekZMmSrrqzgC9YtfusTFp7UP65lljG7vtJAuS/sj0Xrt+xemgAIqH/F73yyitmH4f68ssvpXHjxlYPC4A3BbMnTpyQ0ND/WnlGbAWoebSAL5m87qAcu3RTs+7kavDdB36uLWwBeAddaAkKCpLjx49L0qRJTT30Ro0aWT0sAN4SzK5cudL1/XfffSfp0qVzndfgVrum5M6dO+FHCFjo5t3/PrgFiEMypQ10rcw6A9m+tQtYODoAzrSCqVOnSv/+/U2JSP2/aMmSJaYpAgDfF+Ng9sUXX3TtCtVqBmHpJ2D94zFp0qSEHyHgBdImE/mlXxXzXgfgXXr27CkffPCB+V5XYrW1evr06a0eFgBvq2agZbj0lDNnTrlw4YLrvJ40xUDLc9WvX9+9owUAIII2bdqYDV4a0GquLIEs4F9inTOruUgAAFhFF1G0m5e2olWaTvDXX3/Jo48+avXQAFggTq1Pbt68KatXrzY1+957771wp9jS2n+aohAYGGi6s2zduvWhO1W7d+8uWbNmleTJk0v+/PnNWAAAvu/SpUvSoEEDKV++vOzatct1OYEs4L9ivTK7c+dOqVu3rty6dcsEtfoHRP+4pEyZ0vS31tylmFq8eLH06dPHBMUayE6ZMkXq1KljUhYi65UdHBxsGjPoz/RQkrYk1E/jHFICAN+3b98+s5ihlXN0MUP/r3CuzgLwX7Feme3du7f5VPzvv/9KihQpZMuWLSagLFWqlEycODFW9zV58mRTD7B9+/ZSqFAhE9RqUDx79uxIr6+XX758WVasWCGVKlUyK7pVqlSRYsWKxfZpAABslFYwbtw4GTJkiAlk9YicHsXTMlwAEOuVWT2s8+GHH5qOKokTJzabv7SRgtbz0yoHMa3pp6us27dvl7feest1md5nzZo1ZfPmzVGWB6tQoYL5ZP7VV19JxowZpWXLljJgwAAzlsjo+PTkdO3aNfNVy7foyd2cj+GJx0LCc8j/2mEyh/bF76F96YZjXfBwdp1s3ry56e6lG76YT/vgd9D+Qjw8h7F5nFgHs1qaSINOpYf7T548KQULFjR1Z0+dOhXj+9HUBK1Pmzlz5nCX6/kDBw5EehvtLqbtCVu1amXyZI8cOSLdunUzT3jYsGGR3ubtt9+WESNGPHD52rVrzSqwp9D+157u3NEPSf/VlmUO7Y85tB9duNB5S5YsmWlHW716ddm4caPVw0Ic8Ttof+s8NIeazuq2YLZEiRKmy0q+fPnMIf6hQ4eawHT+/PlSpEgRcfehJg2gP/roI7MSq6kNesjpnXfeiTKY1ZVfzcsNuzKbI0cOqV27tqRNm1bcTQNtnXjN9aVGqWd9u/ecTFl/VG4G34vzfVwP+d+qPnNoX/we2tdzzz1n8mM7duxo/t4zh/bE76D9hXh4Dp1H0t0SzI4dO1auX79uvh8zZoyp79e1a1cT3Gqh6pjKkCGDCUjPnz8f7nI9nyVLlkhvoxUM9AUMm1Kgq8Lnzp0zaQv6yT0i/SOop4j0fjz5C+Xpx4PI1B+O/n8r2vgLTMwc+gLm0PudPXtWRo4cafZU6L4MNWPGDPMfqQazzKG9MX/2l9RDcxibx4h1MFu6dGnX97pKumbNGokLDTx1ZVXb4Dq7i+nKq57v0aNHpLfRTV+ff/65uZ4z1eHQoUMmyI0skIV/c7aiTRQgkilNYJzvJ2WyxFLl0Zh/QgQQN7rq07p1a5MnmyRJEnn//fetHhIAG4h1MBuVHTt2mJSDb775Jsa30cP/umlMA+SyZcua0lxa7kuT/ZWu+mr5Lc17VboCrB1eevXqJa+99pocPnzYrBTHphwY/I8GslsG1ojz7XVFiFrGgPvcu3dPhg8fbv6eOxwOKVq0qNnoCwAJHsx+9913rkT8Tp06mSoGulnrzTfflK+//trUiI0NLaty8eJFEwRrqoDWC9SVXuemMN1c5lyBVZrrqmPQ8mBPP/20CXQ1sNVqBgAA+9HUgRYtWsjPP/9sznfu3NksbDhTDAAgwYJZzYfVmrDaJEFrzH788ccmp0lXSDUo3bt3r8lfjS1NKYgqrWDDhg0PXKalubS2LQDA3n799VeTZqabiLXU1qxZs0zpLQBwSzA7depUGT9+vPTr10+++OILadq0qan1t2fPHnn88cdj9aBAQlm1+6xMXnfQlR8b1oXrdywZE4CYyZkzp9kDoVVytCOkbiQGALcFs0ePHjUBrNLGCJqcryWxCGRhJQ1kj16MvmJBquSRN9QA4HlXr141dcmdqWNaO7xAgQISGBj3TZoA/FuM29nevn3b1WQgICDAlLvSKgKAt1QsyJI28IFT3oyppG/tAlYPE4CI2Vuhey20m6OTtiMnkAXgsQ1gmiereU3O3adz58419WLDorIA7FixAID7aB1wbWCj+yyUpqi98MILVg8LgL8Fs5rbpMn5TtrYQLt+haUrtgSzAACn48ePm01dW7duNedff/11s/8CADwezJ44cSLBHhRIqI1ebPICvNfy5culQ4cOJk82ffr05mhew4YNrR4WAB+TYE0TACs3erHJC/AuO3fulMaNG5vvy5cvL4sWLZJcuXJZPSwAPohgFrZvTauBLJu8AO+i5ba0a6PusxgzZoxHerkD8E8Es7AVNnoB3mvZsmXyzDPPmD0Vatq0aWYvBQB4RWkuAACiKt346quvmlrkrVq1ktDQ/46kEMgC8ARWZgEAcXbw4EFp1qyZ7N692wSvmh/rcDisHhYAPxKnYFa7gc2ZM8d81Ta3mTJlkm+//daU7ypcuHDCjxI+33r2YahaAHifBQsWSJcuXeTmzZuSMWNG+eyzz6R27dpWDwuAn4l1msFPP/0kRYsWld9++82UXblx44a5/I8//pBhw4a5Y4zwsYoE567difXp/v8v9FC1ALDerVu3pFOnTtK6dWsTyFatWlV27dpFIAvAHiuzb775powePVr69OkjadKkcV1evXp1+eCDDxJ6fPCTigQxQdUCwDvcv39ffv31V5NWMHToUBkyZIgkTswHTQA2CWb37Nkjn3/++QOXa6rBpUuXEmpc8GFUJADsSXNhNYDVcltLliyRCxcuSI0a/C4DsFmagXZxOXv2bKQFsrNnz55Q4wIAeAlNJ2vbtq28++67rss03YxAFoAtg1ntsT1gwAA5d+6c+YTuPNz0xhtvSJs2bdwzSgCAJfRoXJkyZWTevHkyaNAgOX/+vNVDAoD4BbNjx46Vp556SnLkyGE+rRcqVEieffZZqVixogwePDi2dwcA8NKUglmzZknZsmXlwIEDki1bNvnuu+8kc+bMVg8NAOKXM5ssWTLzB04T/vfu3WsCWm1bmC9fvtjeFQDAC127ds2U3Fq0aJE5/9xzz5mVWS2/BQC2D2Z/+eUX065Qa8rqCQDgO0JCQqRChQry559/mgoFejRO08gSJaJhJADvFOu/TlqCK0+ePDJw4EDzxw4A4DuSJk0qHTt2NKlkGzdulP79+xPIAvBqsf4LdebMGenbt69pnlCkSBEpXry4vPPOO/L333+7Z4QAALe6evWqHD582HW+d+/eZuOX7oUAAJ8LZjNkyCA9evQwFQy0nW3Tpk3l008/ldy5c5tVWyCqVrbayQuAd/n999/Nvof69evL9evXzWVaqSZdunRWDw0AYiRex4403UA7go0bN87UHNTVWiCqVrZOtKQFvKNawdSpU83q6/HjxyU4OFhOnz5t9bAAwHPBrK7MduvWTbJmzSotW7Y0KQerVq2K693BT1rZKlrSAtb6999/pVGjRvL666+bDV8vvfSSaXyjZRcBwOerGbz11lumXIvmztaqVct8sm/YsKGkTJnSPSOET8mSNlDqFs1q9TAAv7VlyxbT/Oavv/4ypRYnTZok3bt3N6kFAOAXwazubu3Xr580a9bM5M8CAOxj5MiRJpDNmzevLF68WEqVKmX1kADAs8GsphcAAOxp9uzZMmLECBk/frykTZvW6uEAgGeC2ZUrV8rzzz9v6g/q99F54YUX4j8q+FQVA938deE6lQwAK2ijm7Vr15oVWZUlSxaZMWOG1cMCAM8Gsy+++KKcO3dOMmXKZL6PiuZchYb+b6MPoIHs0Ys3XeepZAB4xv37983qq7Ye17/LJUuWjPbvNwD4dDCrfxQj+x6IaRWDRAEieTKkopIB4AEXLlyQl19+2azIqtatW0vNmjWtHhYAeEdprnnz5sndu3cfuFxrFOrPgMhkShMo6/tWpZIB4GYbNmwwnRk1kE2RIoV88skn5m9z6tSprR4aAHhHMNu+fXvT+jAi7RyjPwMAWOPdd9+VGjVqyNmzZ6VgwYKybds26dChA2W3APi0RHHpGhPZH8a///6b9ocAYKEnn3zSpIK1a9fOBLKFCxe2ekgA4D2lubR3twaxetJP/kmS/O+murlA2yE+99xz7honbFS5IGy3L6oYAO515coVSZ8+vfm+QYMGJogtXbq01cMCAO8LZp27YHft2iV16tQJl3+lXWRy584tjRs3ds8oYcvKBWFRxQBIWPfu3TP1YmfOnCnbt2+XnDlzmssJZAH4mxgHs8OGDTNfNWgNCgqSwMBAd44LNq9coBu+wgayVDEAEs7p06elZcuWpiOjWrZsmfTp08fqYQGAPTqAtW3b1j0jgc/QQHbLwBpWDwPwSWvWrDFlty5dumSOkM2aNUuaN29u9bAAwLuD2UcffVQOHTokGTJkkEceeSTanbGXL19OyPEBAEQkJCREhg4dKuPGjTPntfzWkiVLJF++fFYPDQC8P5jVci9p0qRxfU+ZF4RFy1rA/aZOneoKZLt37y4TJ04k3QsAYhrMhk0t0JIvQFi0rAXcTwPYlStXSs+ePaVJkyZWDwcA7FtndseOHbJnzx7X+a+++spUOhg4cKDpAgb/3viVNyMta4GEoH9PtVKBlj5U2s3rp59+IpAFgPgGs126dDH5s+rYsWOmskHKlCll6dKl0r9//9jeHXwILWuBhHHixAmpXLmydO3aVcaOHeu6nBQvAEiAYFYDWd14oDSArVKlinz++ecyd+5c+eKLL2J7dwCAML788kvTpGbr1q2mGcLTTz9t9ZAAwPfa2Wq7RPX9999L3bp1zfc5cuQwpWIAALF39+5dkw/bqFEj09WrfPnypklNw4YNrR4aAPhWnVntLjN69GipWbOmyd+aMWOGuVzb2WbOnNkdY4SXt66ligEQP0ePHjUpW9rJS73xxhsmvSBp0qRWDw0AfC+YnTJlirRq1UpWrFghgwYNkieffNLVgaZixYruGCNs0rqWKgZA3Ny4cUP27t1ranrPmzdP6tWrZ/WQAMB3g1nN3wpbzcDpnXfekcSJCWb8tXUtLWuB2KdsOTd0FStWTBYvXiwlS5Y0KVsAADcGs056OGz//v3m+0KFCpk/wvA/tK4FYk830rZu3Vo++OADKVu2rLmM3FgA8FAwe+HCBZPbpfmyutNW6WaFatWqyaJFiyRjxoxxHAoA+D6t/qIlDjW14LXXXpMtW7ZQcgsAPFnNQP/46h/hffv2yeXLl81Jc72uXbtmduICAB5069Yt6dSpk9lzoH9Dq1atavYeEMgCgIdXZtesWWNKchUsWNB1maYZTJs2TWrXrh3P4cBbKxZERAUDIOY0JatZs2bmg78Gr0OHDpUhQ4awzwAArAhmtcZsZOVi9DJn/Vn4bsWCiKhgAERPj2JpXqyuzGr5Qk0zqF69utXDAgD/DWb1j3CvXr1k4cKFki1bNnPZ6dOnpXfv3lKjBhuBfLliQURUMAAeTo9c6d/N27dvy2effSZZsmSxekgA4N/BrO6+feGFFyR37tyuEjKnTp2SIkWKmD/U8D1ULABivxqbK1cuSZ06tUkr0A//KVKkIK0AALwhmNUAdseOHbJ+/XpXaS7Nn9WOYADg77VjP/nkE7NRtkmTJqYBggazGtQCALwgmNWi3itXrpTg4GCTUqB/sOG7m73Y5AXE3PXr1+XVV181ObHq0qVLcvfuXQkMfDBFBwBgQTA7Y8YM6d69u+TLl88cLlu+fLnpJ66dv+Dbm73Y5AVEb9euXaZaweHDh00qwdixY+WNN96QRIliXf0QABBLiWKTKzts2DA5ePCg+cP96aefyvTp02P7eLDBZq8saQNdp7wZU7HJC4gmrUA/6JcvX94EspqGtXHjRunfvz+BLAB428rssWPHpG3btq7zLVu2lI4dO8rZs2cla9as7hofPIzNXkDM/fvvvzJ8+HCTTtCgQQOZM2eOPPbYY1YPCwD8SoyDWf1jnSpVKtd5XXVIliyZKTcDAP7o0UcflQULFsiePXvk9ddfp5sXAHj7BjDtWJMyZUrXed0INmbMGEmXLp3rssmTJyfsCAHAi9IK3n//fVNjW6sVKK3kQjUXALBBMPvss8+afNmwKlasaNIPnFiVAODLKQUdOnSQFStWSJo0aaRChQqSPXt2q4cFAH4vxsHshg0b3DsSAPBSv/32mwQFBclff/1l0qu0WoGzAyIAwFpstwWAKNy/f18mTZokzzzzjAlk8+bNK5s2bZIePXpwJAoA7NoBDAD8wb1796RRo0by9ddfm/NaR3bWrFmSNm1aq4cGAAiDlVkAiESSJEnkySeflOTJk8vMmTNl0aJFBLIA4IUIZgEgTFrBlStXXOfHjRsnO3bskC5dupBWAABeimAWsmr3WTl37Y7VwwAsdfHiRalXr57Ur19fQkJCzGW62atQoUJWDw0AkNDB7M8//yytW7c2pWlOnz5tLps/f7788ssvcbk7WGzyuv+VXEuVPLGlYwGs8NNPP0nx4sVlzZo1ZiV2586dVg8JAOCuYPaLL76QOnXqSIoUKcwffO0Mpq5evWrK1cB+bt4NdX3ft3YBS8cCeFJoaKiMGjVKqlevLmfOnJGCBQvK1q1bpWzZslYPDQDgrmB29OjRZjOE7upNmjSp6/JKlSqZFQ3YV5a0gVK3aFarhwF4xLlz58wH86FDh5pc2Xbt2sm2bdukSJEiVg8NAODO0lzaBUy7gUWkLW3DbpwAAG/Wpk0bWb9+vWnRPWPGDHMeAOAHK7NZsmSRI0eOPHC55ss+8cQTcRrEtGnTJHfu3BIYGCjlypUzh/liQkvl6A7jF198MU6PC8B/vffeeybvf/v27QSyAOBPwewrr7wivXr1Mu0dNZDUPLMFCxbIG2+8IV27do31ABYvXix9+vSRYcOGmTSFYsWKmUN/Fy5ciPZ2J06cMI9ZuXLlWD8mAP9z+fJlWbhwoev8U089Jb/++qv5CgDwozSDN9980+SX1ahRQ27dumVSDrSouAaWr732WqwHMHnyZBMgt2/f3pzXfNxVq1bJ7NmzzWNFtWmjVatWMmLECFNZgfQGANFZu3atvP7663Ljxg1zFMiZKkXtWADww2BW//gPGjRI+vXrZ9IN9D8HrcOYOnXqWD94cHCwOcT31ltvuS5LlCiR1KxZUzZv3hzl7UaOHCmZMmWSjh07mmA2OlptwVlxQV27ds181TqSzlqS7uR8DE88Vlw5xOH66s3jtIod5hBRt6TVoz7vvPOOOf/000/LY489xlzaEL+H9sb82V+Ih+cwNo8T62DWKSGKiV+6dMmssmbOnDnc5Xr+wIEDkd5Gc3M/+eQT2bVrV4we4+233zYruJGt1OjGD09Zt26deKs7d7S2bIDcuXNHVq9ebfVwvJY3zyEib4KgR372799vzj///PPmCJB+CI8s7x/2wO+hvTF/9rfOQ3OoR//dFsxWq1Yt2kNzP/zwg7jL9evX5eWXXzZlwTJkyBCj2+iqr+bkhl2ZzZEjh9SuXdsjfdb1k4VOfK1atcKVMvMmY/f9JFeD75oNeHXrVrF6OF7HDnOI8PRD2YABA0yerP6e6ybTNGnSMIc2xu+hvTF/9hfi4Tl0Hkl3SzCrXXIiPjldJd27d6+0bds2VvelAWnixInl/Pnz4S7X81o1IaKjR4+ajV8NGjRwXab5uypJkiSmbFjevHnD3UbzefUUkU6EJ3+hPP14MWlhq52/tGHCxev/pWEESIBXjdHbeNscImq6MVUD2VKlSplNpjlz5jQBLnNof8yhvTF/9pfUQ3MYm8eIdTD77rvvRnr58OHDTf5sbGiqgv5no7UeneW1NDjV8z169Hjg+rrreM+ePeEuGzx4sFmxnTp1qllxRcxoIHv04s1wl9HKFnbmcDhcR41effVV06WwRYsW5sMseXoA4LtiXZorKq1btzYVCGJLUwA0beDTTz81uW1a3uvmzZuu6gZa/9G5QUwPg2t3nrCn9OnTm8OH+r0Gx4hdC9tEAf91/sqbMRWtbGFbK1askNKlS7sqm2hQqx29IjsqAwDwLXHeABaRVh/QYDO2goKCzEYNbSmp7SU1jWHNmjWuTWEnT540FQ7gHpnSBMqWgTWsHgYQJ1qpRHNj9ciMmjRpkowaNcrqYQEAvDmYbdSo0QOH9s6ePSu///67DBkyJE6D0JSCyNIK1IYNG6K97dy5c+P0mADsTXPo9cOwlvdTWutaPxQDAPxLrIPZdOnShTuvq6YFChQwtV+1QgAAuNvSpUulU6dOZrer1o3VNKV69epZPSwAgLcHs1oTVnNZixYtKo888oj7RoUEr1gQ0YXrdywZExBfH330kXTp0sV8X6lSJVm0aJE8/vjjVg8LAGCRWCWjahktXX2lfay9Khacu3bngdP9/5p+UcEAtqOpTlq5RDeGahoSgSwA+LdYpxlo1YBjx45Jnjx53DMiuKVigW70ikgDWSoYwA50g2mFChVc9an37dtnqpgAABDrYHb06NFmo4XuGNYasalSpQr3c0901ULsULEAdnX79m3p2bOnfPzxxzJnzhxTbksRyAIAYh3M6gavvn37St26dc35F154IVxbW2fBcs2rBYD40rrTzZo1M90F9W+LVk0BACDOweyIESNMV50ff/wxpjeBxRu/2OQFu5o3b55poHLr1i1Tc3rBggVSowZHFwAA8QhmdeVVValSJaY3gZe0qmWTF+xCu/9pzWln/eiaNWvKZ5995mqiAgBAvKoZhE0rgD02ftGmFnaizVe0ZqzWr9a8/LDdAAEAiPcGsPz58z80oL18+XJs7hJu3vi1vm9Vq4cBxJge+Zk4caLZXMpRIABAggezmjcbsQMYAMTV9evXTXWU/v37S968ec1lffr0sXpYAABfDWabN28umTJlct9oAPiNP/74w1QrOHTokOzevVs2bdpEKhMAwH05s/wnY59KBtrhC/BWupl05syZUq5cORPIagcvTS3gbwwAwCPVDOD9lQycqGIAb3P16lXp3LmzLFmyxJyvX7++qVzw2GOPWT00AICvB7P3799370iQoJUMFFUM4E2OHz8utWrVkqNHj0qSJElk/Pjx0rt3b1ZkAQCebWcLe8iSNlDqFs1q9TAAl+zZs8sjjzwiuXLlksWLF5s0AwAA4otgFoDbXLlyRVKnTm1WYpMlSybLly835zWoBQDA400TACCmtm7dKiVKlJBhw4a5LsuRIweBLAAgQbEya/PKBbrhK2ye7IXrVDKAtXSz6LvvvisDBgyQe/fumc1eAwcOlFSpUlk9NACADyKYtTENZI9evBnpz6hkACtoB8B27drJ119/bc43bdpUZs2aRSALAHAbglkbc67IJgr4r3Vt2ECWSgbwNG16oI1VTp06JcmTJ5cpU6ZIly5dqFYAAHArglkfoIHsloE1rB4G/Lx+bN26dc3XfPnymdSC4sWLWz0sAIAfIJgFEG/p0qWTqVOnytq1a013rzRp0lg9JACAnyCYBRAnGzduNCW3KlasaM63bdtW2rRpQ1oBAMCjKM0FIFZCQ0Nl9OjRUq1aNWnWrJlcunTJ9TMCWQCAp7EyCyDGzp8/L61bt5bvv//enK9Zs6akSJHC6mEBAPwYwSyAGPnhhx+kZcuWJqBNmTKlTJ8+3aQWAABgJdIMAETr/v37pouXrsJqIFukSBH5/fffCWQBAF6BYBZAtDQP9s8//zSdvTp16iS//fabFCxY0OphAQBgkGYAIMoV2USJEplg9uOPP5agoCBp0qSJ1cMCACAcVmYBhHPv3j156623TDcvXY111pElkAUAeCNWZgG4aCvaFi1ayK+//mrOd+/eXapUqWL1sAAAiBIrswCMVatWmRa0GsimTZvWtKQlkAUAeDuCWcDPhYSESL9+/aR+/fpy+fJlKVWqlOzYsUOaNm1q9dAAAHgo0gwAP6dpBV988YX5vmfPnjJhwgRJnjy51cMCACBGWJkF/FyvXr0kQ4YM8uWXX8rUqVMJZAEAtsLKLOBn7t69K7t27ZJy5cqZ85UrV5YTJ05IqlSprB4aAACxxsos4EeOHTsmlSpVkurVq8v+/ftdlxPIAgDsimAW8BPLli2TEiVKyPbt2yUwMFDOnj1r9ZAAAIg3glnAx925c8fUi9XqBNeuXZOKFSuaNANdnQUAwO4IZgEfdvjwYalQoYJMnz7dnH/zzTdlw4YNkiNHDquHBgBAgmADmA2t2n1WJq87KBeu37F6KPByn332mVmF1WoF8+fPl+eee87qIQEAkKAIZm1IA9mjF2+6zqdKntjS8cB7DRkyRK5fvy59+/aV7NmzWz0cAAASHGkGNnTzbqj5mihAJG/GVNK3dgGrhwQvceDAAWnbtq0pv6WSJEkikydPJpAFAPgsVmZtLFOaQFnft6rVw4CXmDdvnnTt2lVu3bplcmJHjx5t9ZAAAHA7VmYBm7t586a0b9/erMhqIFujRg3p0aOH1cMCAMAjCGZtuPnr3DU2fuE/+/btk7Jly8rcuXMlUaJEMnLkSPnuu+8kS5YsVg8NAACPIM3Ahpu/nNj45d+++uoradGihdy+fVuyZs0qCxculCpVqlg9LAAAPIpg1qabvxQbv/xbkSJFJGnSpPLss8+afNlMmTJZPSQAADyOYNamsqQNlLpFs1o9DHjYhQsXXEFr3rx5ZcuWLVKgQAGTYgAAgD/if0DABhwOh8ycOVNy584t69atc11esGBBAlkAgF/jf0HAy129elWaN29uym5pfuznn39u9ZAAAPAapBnYBC1s/dP27dslKChIjh49ahogjBs3Tnr37m31sAAA8BoEszZBC1v/Syv44IMP5I033pDg4GDJlSuXLFq0SMqXL2/10AAA8CqkGdgELWz9yw8//CA9e/Y0geyLL74oO3fuJJAFACASrMzaDC1s/YN28XrllVdM+a3XXntNAgICrB4SAABeiWAW8JK0ghkzZkizZs0kQ4YM5rKPPvrI6mEBAOD1SDMALPbPP//ICy+8IN27d5d27drJ/fv3rR4SAAC2wcosYKFNmzaZslunTp2S5MmTS7169UgpAAAgFliZBSygq6/jx483rWg1kM2XL5/p5qW1ZAlmAQCIOVZmAQvSClq3bi1r1qwx51u0aCEffvihpEmTxuqhAQBgO6zMAh6WOHFiOXjwoAQGBsqsWbNkwYIFBLIAAMQRK7OAh9IKNH1AT+nTp5dly5ZJ0qRJpWjRolYPDQAAWyOY9aJWtc7GCJGhja19nT9/3qQVNGrUyOTEqpIlS1o9LAAAfALBrBe2qo0ObWzt18mrZcuWJqDdsWOHCWpJKQAAIOEQzHpZq1rt8BVdIEsbW3sIDQ2VkSNHyqhRo0xDhMKFC8uSJUsIZAEASGAEs15EA9ktA2tYPQzE05kzZ6RVq1ayYcMGc75jx47y3nvvScqUKa0eGgAAPodgFkhAN27ckNKlS8vZs2clVapUpuSWBrYAAMA9KM0FJKDUqVObtrTFihUzObIEsgAAuBfBLBBPf//9txw+fNh1/s033zTdvPLnz2/puAAA8AcEs0A8rFq1SooXLy6NGzeW27dvu5oiaEMEAADgfgSzQByEhIRIv379pH79+qY9rTZAuHz5stXDAgDA7xDMArH0119/ybPPPisTJ04051977TXZtGmTZM+e3eqhAQDgd7wimJ02bZrkzp3bHJotV66cbN26Ncrrai/7ypUryyOPPGJONWvWjPb6QEL66quvTFqB5sSmS5dOvvjiC1N2K3ny5FYPDQAAv2R5MLt48WLp06ePDBs2zOz+1l3gderUkQsXLkR6fa3d2aJFC/nxxx9l8+bNkiNHDqldu7acPn3a42OHf7l//75Zjb1y5YqUKVNGdu7caVrUAgAAPw5mJ0+eLK+88oq0b99eChUqJDNnzjTF5WfPnh3p9RcsWCDdunUzq2NPPfWUfPzxxybIWL9+vcfHDv+SKFEi+fzzz2XgwIHyyy+/SJ48eaweEgAAfs/SpgnBwcGyfft2eeutt8IFDJo6oKuuMXHr1i2zGefRRx+N9Od37941J6dr166Zr3obPbmb8zGieyyHOFxfPTEmxJymEfzxxx9Svnx5MzdZsmSR4cOHm58xV/YRk99DeDfm0N6YP/sL8fAcxuZxLA1mL126ZHrYZ86cOdzlev7AgQMxuo8BAwZItmzZTAAcmbfffltGjBjxwOVr1671aHvRdevWRfmzO3cSi0iA3LlzR1avXu2xMSH6D1pz5syRb7/91pwfNWqU1UOCm38PYQ/Mob0xf/a3zkNzqIuVftHOdty4cbJo0SKTRxtVXU9d9dWc3LArs84827Rp03rkk4VOfK1atUz5psiM3feTXA2+a55D3bpV3D4mRE8bIGjnrl27dpnz+v4pWLBgtHMI7xaT30N4N+bQ3pg/+wvx8Bw6j6THhKXBbIYMGUyB+fPnz4e7XM/r4dzo6EYcDWa///57efrpp6O8nu4yj2ynuU6EJ3+honu8AAlwfeWX3FoLFy6Uzp07y40bN8z7c/78+VKjRg2zYu7p9wwSHnNof8yhvTF/9pfUQ3MYm8ewdANYsmTJpFSpUuE2bzk3c1WoUCHK202YMMEc9l2zZo2ULl3aQ6OFr+vbt6+0bNnSBLJaR1ZXZp977jmrhwUAALy5moEewtXasZ9++qns379funbtKjdv3jTVDVSbNm3CbRAbP368DBkyxFQ70Nq0586dMycNQID40BrHAQEBMnjwYPOBiiYIAAB4P8tzZoOCguTixYsydOhQE5RqyS1dcXVuCjt58qSpcOA0Y8YMszmnSZMm4e5H69Q6d5kDMaUpLc73WrNmzUzKipZ8AwAA9mB5MKt69OhhTpHRzV1hnThxwkOjgi/T1X99z2m1Ak0ncOZoE8gCAGAvlqcZAJ62b98+KVu2rMydO9ccFaDhBgAA9kUwC7/hcDhMrrW2ov3zzz8la9asJpDVMlwAAMCevCLNAHA33SD46quvmnbISusMa9mtTJkyWT00AAAQD6zMwi+MHj3aBLJa13js2LEmV5ZAFgAA+2NlFn5By21t377dVL145plnrB4OAABIIKzMwidpG7xJkyaZPFmVOnVq04aPQBYAAN/Cyix8zo4dO0z94iNHjrg6ewEAAN/Eyix8hq7CfvDBB6YVsgayOXPmlEqVKlk9LAAA4EaszFps1e6zcu7aHauHYXtXrlyRjh07yvLly835hg0bmjJcjz76qNVDAwAAbsTKrMUmrzvo+j5V8sSWjsWufv/9dylRooQJZJMmTSpTpkyRL7/8kkAWAAA/wMqsxW7eDXV937d2AUvHYlf379+Xv//+W/LkySOLFy82TREAAIB/IJj1ElnSBkrdolmtHoZthIaGmpqxSlvT6kqsVipInz691UMDAAAeRJoBbGfTpk1SqFAh+eOPP1yX1a9fn0AWAAA/RDBrITZ/xT6dYMKECfLss8/KoUOHZODAgVYPCQAAWIw0Awux+SvmLl68KG3btjVtaFXz5s3lww8/tHpYAADAYgSzFmLzV8z8/PPPJng9c+aMBAYGynvvvSedOnWSgIAAq4cGAAAsRjDrBdj8FbVffvlFqlatalIMChQoIEuWLJGnn37a6mEBAAAvQTALr6bdvKpVqybZsmWT6dOnS+rUqa0eEgAA8CIEs/A6v/76q5QsWVJSpEhhym99/fXX5nsAAICIqGYAr6odO3z4cKlcubL07t3bdTmBLAAAiAors/AKZ8+elZYtW8qGDRvM+ZCQkHCNEQAAACLDyiwst3btWilWrJgJZFOlSiXz58+XTz75hEAWAAA8FMEsLHPv3j0ZNGiQPPfcc6aOrFYp+P3336V169ZWDw0AANgEwSwsc+HCBZk5c6Y4HA7p0qWLbNmyRZ566imrhwUAAGyEnFlYRsttzZs3T65fv26aIgAAAMQWwaxFVu0+K+eu3RF/opu6Bg8eLM8884w0aNDAXFavXj2rhwUAAGyMNAOLTF530PV9quS+v9Hp5MmTUqVKFZkwYYK0a9dOrly5YvWQAACADyCYtcjNu6Gu7/vWLiC+bOXKlVK8eHHZvHmzpEuXTmbNmiXp06e3elgAAMAHEMxaLEvaQKlbNKv4ouDgYNP8oGHDhvLvv/9KmTJlZOfOndKoUSOrhwYAAHwEObNwi1u3bknVqlVl27Zt5rwGtePGjZNkyZJZPTQAAOBDCGbhFilTppQSJUrIkSNHZO7cufLCCy9YPSQAAOCDSDNAgrlz545cvnzZdX7KlCmya9cuAlkAAOA2BLNIELoCW7FiRWnWrJmEhv63uS1FihSSM2dOq4cGAAB8GMEs4m3RokVSsmRJs7lLV2KPHj1q9ZAAAICfIJhFnN2+fdu0oW3RooXp4qXNEDSYzZ8/v9VDAwAAfoJgFnFy8OBBKV++vHz00UcSEBAggwYNkh9//FEef/xxq4cGAAD8CNUMEGsOh0NatWolu3fvlowZM8qCBQukVq1aVg8LAAD4IVZmEWu6EvvJJ5/I888/L3/88QeBLAAAsAzBLGJk37598tlnn7nOFytWTFavXi1Zs/pm9zIAAGAPpBngoSkF2vSge/fucu/ePbO5q2zZslYPCwAAwGBlFlG6ceOGtG3bVjp06GAqF2h72ty5c1s9LAAAABeCWURKN3eVLl1a5s+fL4kSJZIxY8bImjVrJFOmTFYPDQAAwIU0Azzg448/lh49esjdu3cle/bssnDhQqlcubLVwwIAAHgAK7N4wNWrV00gq9UKtAkCgSwAAPBWrMzC0M1dSZL893bo06eP5MyZUxo3bmxSDAAAALwVkYqf02oF06ZNM/mxuuHLWUe2adOmBLIAAMDrEa34sStXrpigVfNjtfmBNkIAAACwE9IM/NS2bdskKChIjh8/LkmTJpUJEyZIz549rR4WAABArBDM+mFawdSpU6V///4SEhJi6sYuWbJEypQpY/XQAAAAYo00Az8zevRo6d27twlkGzVqJDt37iSQBQAAtkUw62deeeUVU6nggw8+kGXLlkn69OmtHhIAAECckWbg4+7fvy/r16+XWrVqmfNZsmSRgwcPSmBgoNVDAwAAiDdWZn3YpUuXpEGDBlK7dm2TF+tEIAsAAHwFK7Metmr3WZm87qBcuH7HrY/z888/S4sWLeT06dOSPHlyuXXrllsfDwAAwAqszHqYBrJHL96U+47/zqdKnjjB0wrGjh0r1apVM4Fs/vz5ZevWrdKuXbsEfRwAAABvwMqsh928G2q+JgoQyZMhlfStXSDB7vvChQvSunVrWbdunTmv38+YMUNSp06dYI8BAADgTQhmLZIpTaCs71s1Qe9TV2A1kE2RIoVpUaursdqaFgAAwFcRzPqQ+vXry6RJk6ROnTpSuHBhq4cDAADgduTM2tjZs2elSZMmcurUKddlffr0IZAFAAB+g5VZm9J0As2J1TzZGzduyJo1a6weEgAAgMexMmsz9+7dk8GDB5tUAg1kixYtKlOmTLF6WAAAAJZgZdZG/v77b2nZsqWpIas6d+5sAlnd8AUAAOCPCGZtYteuXVKzZk35559/TKmtWbNmSfPmza0eFgAAgKUIZm1Cmx9kzZpVcubMKYsXL5Z8+fJZPSQAAADLEcx6wM5/AmTq1F/lVnBorNrYarWCzJkzS6JEiSRlypSyevVqyZgxowQGBrp1vAAAAHbBBjAP+PZUIjl26aacu3Ynxm1sV65caUpsvf32267LcuTIQSALAAAQBsGsB9z5r4OtaWGbJW2g5M0YdRvb4OBgUyu2YcOG8u+//8o333xjKhgAAADgQaQZeLiF7ZaBNaL8+fHjx82mLm1Lq15//XUZP368JEnCNAEAAESGKMlLLF++XDp06CBXr16V9OnTy9y5c83qLAAAAKJGMOsFzpw5Y+rH3r17V8qXLy+LFi2SXLlyWT0sAAAAr0cw62bf7j0nV4MDor1OtmzZTPODo0ePytixYyVp0qQeGx8AAICdEcy62ZT1R13fh61gsGTJEsmTJ4+UKVPGnH/11VctGR8AAICdUc3AzW4G/68SgVYwuH37tglcg4KCzElzZAEAAGDjYHbatGmSO3duU0O1XLlyrt38UVm6dKk89dRT5vpFixY1zQS8Xea0ySVvsmsmJ/bDDz+UgIAAadGihaRKlcrqoQEAANiW5cGstmbVuqrDhg2THTt2SLFixaROnTpy4cKFSK+/adMmEwR27NhRdu7cKS+++KI57d27V7zZpV3fS6lSpWT37t2mi9eaNWtkzJgxlN0CAACwczA7efJkeeWVV6R9+/ZSqFAhmTlzpmndOnv27EivP3XqVHnuueekX79+UrBgQRk1apSULFlSPvjgA/FG9+8Fy6XVU+XY0vFy8+ZNqVq1qvzxxx9Su3Ztq4cGAABge5YuC2q3q+3bt8tbb73luixRokRSs2ZN2bx5c6S30ct1JTcsXcldsWJFpNfXcld6crp27Zr5GhISYk7uFhCQRO7f/Fe/kcGDBsmgQYMkceLEHnlsJAznXDFn9sUc2h9zaG/Mn/2FeHgOY/M4lgazly5dktDQUMmcOXO4y/X8gQMHIr3NuXPnIr2+Xh6Zt99+W0aMGPHA5WvXrjUrwO52NySxPFavtyS78peULl1IvvvuO7c/Jtxj3bp1Vg8B8cQc2h9zaG/Mn/15ag5v3boV4+v6fMKmrvqGXcnVldkcOXKYw/xp06Z1++N/dOK/FebH81aSunUruP3x4J5Ph/rLW6tWLWoA2xRzaH/Mob0xf/YX4uE5dB5J9/pgNkOGDOaQ+/nz58NdruezZMkS6W308thcP3ny5OYUkU6EJyZjRbcKptqCBrL8Atubp94zcB/m0P6YQ3tj/uwvqYfmMDaPYekGsGTJkpkd/uvXr3dddv/+fXO+QoXIVzH18rDXV/pJIarrAwAAwHdZnmagKQBt27aV0qVLS9myZU1bV931r9UNVJs2bSR79uwm91X16tVLqlSpIpMmTZJ69erJokWL5Pfff5ePPvrI4mcCAAAAvwtmtQvWxYsXZejQoWYTV/HixU0NVucmr5MnT5oKB04VK1aUzz//XAYPHiwDBw6UfPnymUoGRYoUsfBZAAAAwC+DWdWjRw9zisyGDRseuKxp06bmBAAAAP9medMEAAAAIK4IZgEAAGBbBLMAAACwLYJZAAAA2BbBLAAAAGyLYBYAAAC2RTALAAAA2yKYBQAAgG0RzAIAAMC2CGYBAABgWwSzAAAAsC2CWQAAANgWwSwAAABsK4n4GYfDYb5eu3bNI48XEhIit27dMo+XNGlSjzwmEhZzaH/Mof0xh/bG/NlfiIfn0BmnOeO26PhdMHv9+nXzNUeOHFYPBQAAAA+J29KlSxfdVSTAEZOQ14fcv39fzpw5I2nSpJGAgACPfLLQwPnUqVOSNm1atz8eEh5zaH/Mof0xh/bG/NnfNQ/PoYanGshmy5ZNEiWKPivW71Zm9QV5/PHHPf64OvH8Atsbc2h/zKH9MYf2xvzZX1oPzuHDVmSd2AAGAAAA2yKYBQAAgG0RzLpZ8uTJZdiwYeYr7Ik5tD/m0P6YQ3tj/uwvuRfPod9tAAMAAIDvYGUWAAAAtkUwCwAAANsimAUAAIBtEcwCAADAtghmE8C0adMkd+7cEhgYKOXKlZOtW7dGe/2lS5fKU089Za5ftGhRWb16tcfGivjP4axZs6Ry5cryyCOPmFPNmjUfOufwvt9Dp0WLFplugC+++KLbx4iEncMrV65I9+7dJWvWrGaHdf78+fl7aqP5mzJlihQoUEBSpEhhOkv17t1b7ty547HxIryNGzdKgwYNTMct/Zu4YsUKeZgNGzZIyZIlze/fk08+KXPnzhVLaDUDxN2iRYscyZIlc8yePduxb98+xyuvvOJInz694/z585Fe/9dff3UkTpzYMWHCBMeff/7pGDx4sCNp0qSOPXv2eHzsiNsctmzZ0jFt2jTHzp07Hfv373e0a9fOkS5dOsfff//t8bEjbnPodPz4cUf27NkdlStXdjRs2NBj40X85/Du3buO0qVLO+rWrev45ZdfzFxu2LDBsWvXLo+PHbGfvwULFjiSJ09uvurcfffdd46sWbM6evfu7fGx4z+rV692DBo0yLF8+XKtcuX48ssvHdE5duyYI2XKlI4+ffqYeOb999838c2aNWscnkYwG09ly5Z1dO/e3XU+NDTUkS1bNsfbb78d6fWbNWvmqFevXrjLypUr5+jSpYvbx4qEmcOI7t2750iTJo3j008/deMokdBzqPNWsWJFx8cff+xo27YtwazN5nDGjBmOJ554whEcHOzBUSKh5k+vW7169XCXaVBUqVIlt48VDxeTYLZ///6OwoULh7ssKCjIUadOHYenkWYQD8HBwbJ9+3ZzmNkpUaJE5vzmzZsjvY1eHvb6qk6dOlFeH943hxHdunVLQkJC5NFHH3XjSJHQczhy5EjJlCmTdOzY0UMjRULO4cqVK6VChQomzSBz5sxSpEgRGTt2rISGhnpw5Ijr/FWsWNHcxpmKcOzYMZMiUrduXY+NG/HjTfFMEo8/og+5dOmS+cOpf0jD0vMHDhyI9Dbnzp2L9Pp6OewxhxENGDDA5BhF/KWG987hL7/8Ip988ons2rXLQ6NEQs+hBj8//PCDtGrVygRBR44ckW7dupkPltqlCN49fy1btjS3e+aZZ/QIsdy7d09effVVGThwoIdGjfiKKp65du2a3L592+RCewors0A8jBs3zmwg+vLLL82mB3i/69evy8svv2w28mXIkMHq4SCO7t+/b1bWP/roIylVqpQE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",
      "text/plain": [
       "<Figure size 800x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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YltzlfSe0xZk+rnS6z311FNur6Ofi+eff9689vpe0v9f9OzZ03zmtE0gYEV++h9vB2oAAACgIqiZBQAAgGURZgEAAGBZhFkAAABYFmEWAAAAlkWYBQAAgGURZgEAAGBZNW7RBF19Ze/evabpNsv5AQAA+B7tHKuLADVs2LDUBVtqXJjVIFuRdewBAADgWbt27XJZ/dKdGhdmdUbW/uLo0oZVTZdM1OUShw0bZtach/UwhtbHGFofY2htjJ/15Xh4DFNTU83koz23laTGhVl7aYEGWU+F2fDwcPNYfICtiTG0PsbQ+hhDa2P8rC/HS2NYlpJQdgADAACAZRFmAQAAYFmEWQAAAFhWjauZBQAAFW+XlJubK3l5eeWutwwMDJTMzMxy3xa+IacKxlBrbwMCAk74fgizAACgVNnZ2bJv3z7JyMioUAiuX7++6SREj3drslXBGOr9aNutyMjIE7ofwiwAACh1waFt27aZWTRtYh8cHFyuQKO3P3LkiAktpTXAh2/Kr+Qx1HCcnJwsu3fvljZt2pzQDC1hFgAAlDorq2FG+35qe6by0tvqfYSGhhJmLSq/Csawbt26sn37dlPCcCJhlncUAAAoE4IoKlNllSvwrgQAAIBlEWYBAABgWYRZAAAAWBZhFgAAVFvXXHONqc3Ug3ZhaN26tTzxxBOmX66aN2+e43I96E5JI0aMkFWrVpXp/nVvfL3fzp07F7lMd27S+1y+fHmRy04//XS58847Xc5btmyZXHLJJRIfH292tNK9/G+44QbZuHFjuZ7zzp075eyzzzY769WrV0/uuecex/N1p/Br4Hz4559/HNebM2eO9OvXT6KioszrdNFFF5nn6M6CBQtMX9ru3btLVSPMAgCAau3MM880PXI3bdokd911lzz22GPy4osvulxnw4YN5jozZsyQrKwsEwZ17/3SfPDBB3LppZdKamqqLFq0qMLbOHXqVDnllFPMY3/66aeybt06+eSTTyQmJkYeeeSRMt9PXl6eY9sXLlwoH374odnGRx99tNjbaEDV5+58uP7666VFixbSq1cvcx1tzXbllVfKoEGDTDjX1yklJUUuvPDCIvd36NAhGT16tJxxxhniCbTmAgAA1VpISIhp+K9uueUW+f777+Wnn36SBx54wHEdncGMjY0119MZ0/POO0/Wr18vXbt2LbFX6pQpU+TNN980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ubm2qKgo24cffliFW4nKHkMdt379+tneffdd25gxYwizFhvDt956y9ayZUtbdna2B7cSlTV+et3Bgwe7nKehqH///lW+rShdWcLsvffea+vUqZPLeZdddplt+PDhNk+jzOAEZGdny5IlS8zPzHb+/v7m9F9//eX2Nnq+8/XV8OHDi70+fG8MC8vIyJCcnBypXbt2FW4pKnsMn3jiCalXr55cd911HtpSVOYY/vTTT9K3b19TZhAfHy+dO3eWZ555RvLy8jy45ajo+PXr18/cxl6KsHXrVlMiMmLECI9tN06ML+WZQI8/YjWSkpJi/sep/yN1pqfXr1/v9jYJCQlur6/nwxpjWNh9991naowKf6jhu2M4f/58ee+992T58uUe2kpU9hhq+Pntt9/kyiuvNCFo8+bNcuutt5ovlrpKEXx7/EaNGmVud+qpp+ovxJKbmys333yzPPjggx7aapyo4vJMamqqHD161NRCewozs8AJeO6558wORN9//73Z6QG+Ly0tTa6++mqzI19cXJy3NwcVlJ+fb2bW3377benZs6dcdtll8tBDD8nkyZO9vWkoA91xSGfS33zzTVm6dKl899138ssvv8iTTz7p7U2DBTEzewL0H8KAgABJTEx0OV9P169f3+1t9PzyXB++N4Z2L730kgmzs2fPlq5du1bxlqKyxnDLli2yfft2s9euczBSgYGBsmHDBmnVqpUHthwn8jnUDgZBQUHmdnYdOnQws0X6s3dwcHCVbzcqPn6PPPKI+VJ5/fXXm9Pa2Sc9PV1uvPFG86VEyxTg2+oXk2eio6M9OiureLecAP2fpc4IzJkzx+UfRT2ttVzu6PnO11ezZs0q9vrwvTFUL7zwgplBmD59uvTq1ctDW4vKGENti7dq1SpTYmA/nHfeeTJo0CBzXFsEwfc/h/379zelBfYvImrjxo0m5BJkfX/8dF+DwoHV/sWkYP8j+Lq+vpRnPL7LWTVsR6LtRT744APTmuLGG2807UgSEhLM5VdffbXt/vvvd2nNFRgYaHvppZdMW6eJEyfSmstiY/jcc8+ZFjTffPONbd++fY5DWlqaF59FzVbeMSyMbgbWG8OdO3eaLiLjxo2zbdiwwTZ16lRbvXr1bE899ZQXn0XNVd7x03/7dPw+//xz0+Jp5syZtlatWpmOP/COtLQ003JSDxoPX3nlFXN8x44d5nIdPx3Hwq257rnnHpNntGUlrbksTHurNW3a1AQcbU/y999/Oy477bTTzD+Uzr766itb27ZtzfW1rcUvv/ziha1GRcewWbNm5oNe+KD/c4Z1PofOCLPWHMOFCxea1oYaorRN19NPP21arsH3xy8nJ8f22GOPmQAbGhpqa9Kkie3WW2+1HTx40Etbj7lz57r9t80+bvpXx7Hwbbp3727GXD+DU6ZM8cq2++l/PD8fDAAAAJw4amYBAABgWYRZAAAAWBZhFgAAAJZFmAUAAIBlEWYBAABgWYRZAAAAWBZhFgAAAJZFmAUAAIBlEWYBoAbz8/OTH374wRzfvn27Ob18+XJvbxYAlBlhFgC85JprrjHhUQ9BQUHSokULuffeeyUzM9PbmwYAlhHo7Q0AgJrszDPPlClTpkhOTo4sWbJExowZY8Lt888/7+1NAwBLYGYWALwoJCRE6tevL02aNJGRI0fKkCFDZNasWeay/Px8efbZZ82MbVhYmHTr1k2++eYbl9uvWbNGzjnnHImOjpaoqCgZMGCAbNmyxVz2zz//yNChQyUuLk5iYmLktNNOk6VLl3rleQJAVSHMAoCPWL16tSxcuFCCg4PNaQ2yH330kUyePNmE1vHjx8tVV10lv//+u7l8z549MnDgQBOIf/vtNzOze+2110pubq65PC0tzcz0zp8/X/7++29p06aNjBgxwpwPANUFZQYA4EVTp06VyMhIE0CzsrLE399f/u///s8cf+aZZ2T27NnSt29fc92WLVuaYPq///3PzLJOmjTJzLh+8cUXpuZWtW3b1nHfgwcPdnmst99+W2JjY00Y1tlcAKgOCLMA4EWDBg2St956S9LT0+XVV1+VwMBAueiii8xMbEZGhikTcJadnS09evQwx7XrgJYV2INsYYmJifLwww/LvHnzJCkpSfLy8sx97ty50yPPDQA8gTALAF4UEREhrVu3Nsfff/99Uxf73nvvSefOnc15v/zyizRq1MjlNlpWoLSOtiRaYrB//37573//K82aNTO301leDcQAUF0QZgHAR2iJwYMPPigTJkyQjRs3mvCps6haUuBO165d5cMPPzSdENzNzi5YsEDefPNNUyerdu3aJSkpKVX+PADAk9gBDAB8yCWXXCIBAQGmLvbuu+82O31pYNUOBdqJ4I033jCn1bhx4yQ1NVUuv/xy+ffff2XTpk3y8ccfy4YNG8zlusOXnl63bp0sWrRIrrzyylJncwHAapiZBQAfojWzGlJfeOEF2bZtm9StW9d0Ndi6davZeeukk04ys7eqTp06povBPffcY2ZvNQR3795d+vfvby7XcoUbb7zR3EZbf+kOZRqQAaA68bPZbDZvbwQAAABQEZQZAAAAwLIIswAAALAswiwAAAAsizALAAAAyyLMAgAAwLIIswAAALAswiwAAAAsizALAAAAyyLMAgAAwLIIswAAALAswiwAAADEqv4fbNDXt8cK1rEAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 800x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from sklearn.metrics import roc_curve, precision_recall_curve\n",
    "\n",
    "# ROC Curve\n",
    "fpr, tpr, _ = roc_curve(all_labels, all_preds)\n",
    "plt.figure(figsize=(8, 6))\n",
    "plt.plot(fpr, tpr, label=f'ROC-AUC: {gnn_roc:.3f}', linewidth=2)\n",
    "plt.plot([0, 1], [0, 1], 'k--', label='Random')\n",
    "plt.xlabel(\"False Positive Rate\")\n",
    "plt.ylabel(\"True Positive Rate\")\n",
    "plt.title(\"GCN Model - ROC Curve\")\n",
    "plt.legend()\n",
    "plt.grid(True)\n",
    "plt.show()\n",
    "\n",
    "# Precision-Recall Curve\n",
    "precision, recall, _ = precision_recall_curve(all_labels, all_preds)\n",
    "plt.figure(figsize=(8, 6))\n",
    "plt.plot(recall, precision, label=f\"PR-AUC: {roc_auc_score(all_labels, all_preds):.3f}\", linewidth=2)\n",
    "plt.xlabel(\"Recall\")\n",
    "plt.ylabel(\"Precision\")\n",
    "plt.title(\"GCN Model - Precision-Recall Curve\")\n",
    "plt.legend()\n",
    "plt.grid(True)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "f619a4e5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "        <iframe\n",
       "            width=\"100%\"\n",
       "            height=\"650\"\n",
       "            src=\"http://127.0.0.1:8050/\"\n",
       "            frameborder=\"0\"\n",
       "            allowfullscreen\n",
       "            \n",
       "        ></iframe>\n",
       "        "
      ],
      "text/plain": [
       "<IPython.lib.display.IFrame at 0x14b862f4760>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from dash import Dash, html, dcc, Input, Output\n",
    "import dash\n",
    "import plotly.express as px\n",
    "import numpy as np\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "from rdkit import Chem\n",
    "from rdkit.Chem import AllChem, rdMolDescriptors\n",
    "from torch_geometric.data import Data\n",
    "from torch_geometric.nn import GCNConv, global_mean_pool\n",
    "import threading, webbrowser, nest_asyncio\n",
    "nest_asyncio.apply()\n",
    "\n",
    "# ============================\n",
    "# Fingerprint-based MLP Model\n",
    "# ============================\n",
    "class ToxicityNet(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.model = nn.Sequential(\n",
    "            nn.Linear(1024, 512),\n",
    "            nn.ReLU(),\n",
    "            nn.Dropout(0.3),\n",
    "            nn.Linear(512, 128),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(128, 1)\n",
    "        )\n",
    "    def forward(self, x):\n",
    "        return self.model(x)\n",
    "\n",
    "model = ToxicityNet()\n",
    "try:\n",
    "    model.load_state_dict(torch.load(\"tox_model.pt\"))\n",
    "    model.eval()\n",
    "    model_loaded = True\n",
    "except:\n",
    "    model_loaded = False\n",
    "\n",
    "fp_generator = GetMorganGenerator(radius=2, fpSize=1024)\n",
    "def predict_toxicity(smiles):\n",
    "    if not model_loaded:\n",
    "        return \"Model not loaded\", 0.0\n",
    "    try:\n",
    "        mol = Chem.MolFromSmiles(smiles)\n",
    "        if mol is None:\n",
    "            return \"Invalid SMILES\", 0.0\n",
    "        fp = fp_generator.GetFingerprint(mol)\n",
    "        fp_array = np.array(fp).reshape(1, -1)\n",
    "        with torch.no_grad():\n",
    "            logits = model(torch.tensor(fp_array).float())\n",
    "            prob = torch.sigmoid(logits).item()\n",
    "        return (\"Toxic\" if prob > 0.5 else \"Non-toxic\"), prob\n",
    "    except Exception as e:\n",
    "        return f\"Error: {str(e)}\", 0.0\n",
    "\n",
    "# ============================\n",
    "# GCN Model\n",
    "# ============================\n",
    "class RichGCNModel(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.conv1 = GCNConv(10, 64)\n",
    "        self.bn1 = nn.BatchNorm1d(64)\n",
    "        self.conv2 = GCNConv(64, 128)\n",
    "        self.bn2 = nn.BatchNorm1d(128)\n",
    "        self.dropout = nn.Dropout(0.2)\n",
    "        self.fc1 = nn.Linear(128, 64)\n",
    "        self.fc2 = nn.Linear(64, 1)\n",
    "\n",
    "    def forward(self, data):\n",
    "        x, edge_index, batch = data.x, data.edge_index, data.batch\n",
    "        x = F.relu(self.bn1(self.conv1(x, edge_index)))\n",
    "        x = F.relu(self.bn2(self.conv2(x, edge_index)))\n",
    "        x = global_mean_pool(x, batch)\n",
    "        x = self.dropout(x)\n",
    "        x = F.relu(self.fc1(x))\n",
    "        return self.fc2(x)\n",
    "\n",
    "\n",
    "gcn_model = RichGCNModel()\n",
    "try:\n",
    "    gcn_model.load_state_dict(torch.load(\"gcn_model.pt\"))\n",
    "    gcn_model.eval()\n",
    "    gcn_model_loaded = True\n",
    "except:\n",
    "    gcn_model_loaded = False\n",
    "\n",
    "def atom_to_features_gcn(atom):\n",
    "    return [\n",
    "        atom.GetAtomicNum(),\n",
    "        atom.GetDegree(),\n",
    "        atom.GetFormalCharge(),\n",
    "        atom.GetNumExplicitHs(),\n",
    "        atom.GetNumImplicitHs(),\n",
    "        atom.GetIsAromatic(),\n",
    "        atom.GetMass(),\n",
    "        int(atom.IsInRing()),\n",
    "        int(atom.GetChiralTag()),\n",
    "        int(atom.GetHybridization())\n",
    "    ]\n",
    "\n",
    "def smiles_to_graph_gcn(smiles):\n",
    "    mol = Chem.MolFromSmiles(smiles)\n",
    "    if mol is None:\n",
    "        return None\n",
    "    atoms = [atom_to_features_gcn(atom) for atom in mol.GetAtoms()]\n",
    "    edges = []\n",
    "    for bond in mol.GetBonds():\n",
    "        i, j = bond.GetBeginAtomIdx(), bond.GetEndAtomIdx()\n",
    "        edges += [[i, j], [j, i]]\n",
    "    if not edges:\n",
    "        edges = [[0, 0]]\n",
    "    return Data(\n",
    "        x=torch.tensor(atoms, dtype=torch.float),\n",
    "        edge_index=torch.tensor(edges, dtype=torch.long).t().contiguous(),\n",
    "        batch=torch.zeros(len(atoms), dtype=torch.long)\n",
    "    )\n",
    "\n",
    "def predict_toxicity_gcn(smiles):\n",
    "    if not gcn_model_loaded:\n",
    "        return \"GCN Model not loaded\", 0.0\n",
    "    try:\n",
    "        graph_data = smiles_to_graph_gcn(smiles)\n",
    "        if graph_data is None:\n",
    "            return \"Invalid SMILES\", 0.0\n",
    "        with torch.no_grad():\n",
    "            logits = gcn_model(graph_data)\n",
    "            prob = torch.sigmoid(logits).item()\n",
    "        return (\"Toxic\" if prob > best_threshold else \"Non-toxic\"), prob\n",
    "    except Exception as e:\n",
    "        return f\"Error: {str(e)}\", 0.0\n",
    "\n",
    "# ============================\n",
    "# Dash App with Tabs\n",
    "# ============================\n",
    "app = Dash(__name__, suppress_callback_exceptions=True)\n",
    "app.title = \"Drug Toxicity Prediction\"\n",
    "\n",
    "# Histogram samples\n",
    "fig_sample_fp = px.histogram(\n",
    "    x=np.random.beta(2, 5, 100),\n",
    "    color=np.random.binomial(1, 0.3, 100).astype(str),\n",
    "    nbins=20,\n",
    "    title=\"Sample Prediction Probability Distribution\",\n",
    "    labels={\"x\": \"Predicted Probability\", \"color\": \"Actual Label\"}\n",
    ")\n",
    "\n",
    "fig_sample_gcn = px.histogram(\n",
    "    x=np.random.beta(2, 5, 100),\n",
    "    color=np.random.binomial(1, 0.3, 100).astype(str),\n",
    "    nbins=20,\n",
    "    title=\"GCN Model - Sample Prediction Probability Distribution\",\n",
    "    labels={\"x\": \"Predicted Probability\", \"color\": \"Actual Label\"}\n",
    ")\n",
    "\n",
    "# App layout with Tabs\n",
    "app.layout = html.Div([\n",
    "    html.H1(\"🧪 Drug Toxicity Prediction Dashboard\", style={\"textAlign\": \"center\", \"color\": \"#2c3e50\"}),\n",
    "    dcc.Tabs(id='tabs', value='tab-fp', children=[\n",
    "        dcc.Tab(label='Fingerprint Model', value='tab-fp'),\n",
    "        dcc.Tab(label='GCN Model', value='tab-gcn'),\n",
    "    ]),\n",
    "    html.Div(id='tab-content')\n",
    "])\n",
    "\n",
    "# ============================\n",
    "# Tab Content Callbacks\n",
    "# ============================\n",
    "@app.callback(Output('tab-content', 'children'), Input('tabs', 'value'))\n",
    "def render_tab(tab):\n",
    "    if tab == 'tab-fp':\n",
    "        return html.Div([\n",
    "            html.Div([dcc.Graph(figure=fig_sample_fp)], style={\"width\": \"48%\", \"display\": \"inline-block\"}),\n",
    "            html.Div([                html.H3(\"Make a Prediction\"),\n",
    "                html.Label(\"Enter SMILES string:\"),\n",
    "                dcc.Input(id='fp-smiles', value='CCO', type='text', debounce=True,\n",
    "                          style={\"width\": \"100%\", \"padding\": \"10px\", \"marginBottom\": \"10px\"}),\n",
    "                html.Div(id='fp-output', style={\"marginTop\": \"1rem\", \"fontSize\": \"18px\", \"padding\": \"10px\"}),\n",
    "                html.Div(id='fp-prob', style={\"marginTop\": \"1rem\", \"fontSize\": \"16px\"}),\n",
    "                html.Hr(),\n",
    "                html.H4(\"Example SMILES:\"), html.P(\"• CCO\"), html.P(\"• CC(=O)O\"), html.P(\"• c1ccccc1\"),\n",
    "            ], style={\"width\": \"48%\", \"float\": \"right\", \"padding\": \"20px\"}),\n",
    "            html.Div(id='fp-info', style={\"marginTop\": \"2rem\", \"padding\": \"20px\"})\n",
    "        ])\n",
    "    elif tab == 'tab-gcn':\n",
    "        return html.Div([\n",
    "            html.Div([dcc.Graph(figure=fig_sample_gcn)], style={\"width\": \"48%\", \"display\": \"inline-block\"}),\n",
    "            html.Div([\n",
    "                html.H3(\"🔬 Graph Neural Network Prediction\"),\n",
    "                html.P(\"This model uses molecular graph structure and atom features\", style={\"fontSize\": \"14px\"}),\n",
    "                html.Label(\"Enter SMILES string:\"),\n",
    "                dcc.Input(id='gcn-smiles', value='CCO', type='text', debounce=True,\n",
    "                          style={\"width\": \"100%\", \"padding\": \"10px\", \"marginBottom\": \"10px\"}),\n",
    "                html.Div(id='gcn-output', style={\"marginTop\": \"1rem\", \"fontSize\": \"18px\", \"padding\": \"10px\"}),\n",
    "                html.Div(id='gcn-prob', style={\"marginTop\": \"1rem\", \"fontSize\": \"16px\"}),\n",
    "                html.Hr(),\n",
    "                html.H4(\"Test Molecules:\"), html.P(\"• c1ccc(cc1)N\"), html.P(\"• C=CC=O\"),\n",
    "            ], style={\"width\": \"48%\", \"float\": \"right\", \"padding\": \"20px\"}),\n",
    "            html.Div(id='gcn-info', style={\"marginTop\": \"2rem\", \"padding\": \"20px\"})\n",
    "        ])\n",
    "\n",
    "# ============================\n",
    "# Callback for Fingerprint Tab\n",
    "# ============================\n",
    "@app.callback(\n",
    "    [Output('fp-output', 'children'), Output('fp-output', 'style'),\n",
    "     Output('fp-prob', 'children'), Output('fp-info', 'children')],\n",
    "    Input('fp-smiles', 'value')\n",
    ")\n",
    "def update_fp_tab(smiles):\n",
    "    if not smiles:\n",
    "        return \"Enter SMILES\", {\"color\": \"gray\"}, \"\", \"\"\n",
    "    result, prob = predict_toxicity(smiles)\n",
    "    color = \"green\" if \"Non\" in result else \"red\" if \"Toxic\" in result else \"orange\"\n",
    "    info = html.Div()\n",
    "    try:\n",
    "        mol = Chem.MolFromSmiles(smiles)\n",
    "        if mol:\n",
    "            info = html.Div([\n",
    "                html.H4(\"Molecule Info:\"),\n",
    "                html.P(f\"Formula: {rdMolDescriptors.CalcMolFormula(mol)}\"),\n",
    "                html.P(f\"Weight: {rdMolDescriptors.CalcExactMolWt(mol):.2f}\"),\n",
    "                html.P(f\"Atoms: {mol.GetNumAtoms()}\"),\n",
    "                html.P(f\"Bonds: {mol.GetNumBonds()}\")\n",
    "            ])\n",
    "    except: pass\n",
    "    return result, {\"color\": color, \"fontWeight\": \"bold\"}, f\"Probability: {prob:.3f}\", info\n",
    "\n",
    "# ============================\n",
    "# Callback for GCN Tab\n",
    "# ============================\n",
    "@app.callback(\n",
    "    [Output('gcn-output', 'children'), Output('gcn-output', 'style'),\n",
    "     Output('gcn-prob', 'children'), Output('gcn-info', 'children')],\n",
    "    Input('gcn-smiles', 'value')\n",
    ")\n",
    "def update_gcn_tab(smiles):\n",
    "    if not smiles:\n",
    "        return \"Enter SMILES\", {\"color\": \"gray\"}, \"\", \"\"\n",
    "    result, prob = predict_toxicity_gcn(smiles)\n",
    "    color = \"green\" if \"Non\" in result else \"red\" if \"Toxic\" in result else \"orange\"\n",
    "    info = html.Div()\n",
    "    try:\n",
    "        mol = Chem.MolFromSmiles(smiles)\n",
    "        graph_data = smiles_to_graph_gcn(smiles)\n",
    "        if mol and graph_data:\n",
    "            info = html.Div([\n",
    "                html.H4(\"Graph Info:\"),\n",
    "                html.P(f\"Formula: {rdMolDescriptors.CalcMolFormula(mol)}\"),\n",
    "                html.P(f\"Weight: {rdMolDescriptors.CalcExactMolWt(mol):.2f}\"),\n",
    "                html.P(f\"Atoms: {mol.GetNumAtoms()}\"),\n",
    "                html.P(f\"Bonds: {mol.GetNumBonds()}\"),\n",
    "                html.P(f\"Edges: {graph_data.edge_index.shape[1]}\"),\n",
    "                html.P(f\"Node Features: 5\")\n",
    "            ])\n",
    "    except: pass\n",
    "    return result, {\"color\": color, \"fontWeight\": \"bold\"}, f\"GCN Probability: {prob:.3f}\", info\n",
    "\n",
    "# ============================\n",
    "# Run App\n",
    "# ============================\n",
    "def open_browser():\n",
    "    webbrowser.open_new(\"http://127.0.0.1:8050\")\n",
    "threading.Timer(1, open_browser).start()\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run(debug=True, port=8050)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dbbddde7",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "drug_env",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}