From 8864393735fc1e9882ff03c96d937f0cff3504a0 Mon Sep 17 00:00:00 2001 From: harrylaucngd Date: Sun, 15 Mar 2026 17:09:13 -0400 Subject: [PATCH 1/5] v1.5 model zoo implementation. --- .gitignore | 3 + README.md | 74 + checkpoints/README.md | 43 + data/exclude_inchikeys.csv | 40885 ++++++++++++++++ massspecgym/data/__init__.py | 9 +- massspecgym/data/download.py | 82 + massspecgym/data/fp2mol_dataset.py | 220 + massspecgym/data/mist_data_mixin.py | 103 + massspecgym/data/mist_format.py | 184 + massspecgym/data/sanity_check.py | 157 + massspecgym/data/subformulae.py | 388 + massspecgym/models/de_novo/__init__.py | 32 +- massspecgym/models/de_novo/fp2mol/__init__.py | 34 + massspecgym/models/de_novo/fp2mol/base.py | 160 + .../models/de_novo/fp2mol/diffms/__init__.py | 8 + .../de_novo/fp2mol/diffms/diffusion_utils.py | 195 + .../fp2mol/diffms/graph_transformer.py | 255 + .../models/de_novo/fp2mol/diffms/model.py | 252 + .../models/de_novo/fp2mol/formula_utils.py | 138 + .../models/de_novo/fp2mol/frigid/__init__.py | 15 + .../fp2mol/frigid/bert_cross_attention.py | 231 + .../de_novo/fp2mol/frigid/components.py | 336 + .../models/de_novo/fp2mol/frigid/mdlm.py | 246 + .../models/de_novo/fp2mol/frigid/model.py | 404 + .../de_novo/fp2mol/molforge/__init__.py | 8 + .../de_novo/fp2mol/molforge/decoder_search.py | 138 + .../models/de_novo/fp2mol/molforge/model.py | 272 + massspecgym/models/encoders/__init__.py | 11 + .../models/encoders/dreams/__init__.py | 20 + massspecgym/models/encoders/dreams/api.py | 118 + .../models/encoders/dreams/feed_forward.py | 43 + .../encoders/dreams/fourier_features.py | 79 + massspecgym/models/encoders/dreams/layers.py | 216 + massspecgym/models/encoders/dreams/model.py | 186 + .../models/encoders/dreams/preprocessing.py | 90 + massspecgym/models/encoders/mist/__init__.py | 24 + .../models/encoders/mist/chem_constants.py | 232 + massspecgym/models/encoders/mist/encoder.py | 171 + .../models/encoders/mist/form_embedders.py | 199 + massspecgym/models/encoders/mist/modules.py | 347 + .../models/encoders/mist/transformer_layer.py | 336 + massspecgym/models/oracles/__init__.py | 15 + massspecgym/models/oracles/base.py | 37 + .../models/oracles/iceberg/__init__.py | 10 + massspecgym/models/oracles/iceberg/predict.py | 97 + .../models/oracles/mist_cf/__init__.py | 18 + massspecgym/models/oracles/mist_cf/model.py | 264 + massspecgym/models/oracles/mist_cf/predict.py | 222 + massspecgym/models/retrieval/__init__.py | 18 +- .../models/retrieval/generative_retrieval.py | 127 + .../models/retrieval/iceberg_retrieval.py | 114 + .../models/retrieval/mist_retrieval.py | 81 + .../models/simulation/iceberg/__init__.py | 24 + .../models/simulation/iceberg/adapter.py | 61 + .../models/simulation/iceberg/dag_data.py | 218 + .../models/simulation/iceberg/gen_model.py | 234 + .../models/simulation/iceberg/inten_model.py | 244 + .../models/simulation/iceberg/joint_model.py | 115 + .../simulation/iceberg/magma/__init__.py | 11 + .../simulation/iceberg/magma/fragmentation.py | 503 + scripts/convert_to_parquet.py | 142 + scripts/download_data.py | 29 + scripts/run.py | 60 +- setup.py | 9 +- tests/test_fp2mol_v15.py | 552 + tests/test_v15_data_oracles.py | 326 + 66 files changed, 50464 insertions(+), 11 deletions(-) create mode 100644 checkpoints/README.md create mode 100644 data/exclude_inchikeys.csv create mode 100644 massspecgym/data/download.py create mode 100644 massspecgym/data/fp2mol_dataset.py create mode 100644 massspecgym/data/mist_data_mixin.py create mode 100644 massspecgym/data/mist_format.py create mode 100644 massspecgym/data/sanity_check.py create mode 100644 massspecgym/data/subformulae.py create mode 100644 massspecgym/models/de_novo/fp2mol/__init__.py create mode 100644 massspecgym/models/de_novo/fp2mol/base.py create mode 100644 massspecgym/models/de_novo/fp2mol/diffms/__init__.py create mode 100644 massspecgym/models/de_novo/fp2mol/diffms/diffusion_utils.py create mode 100644 massspecgym/models/de_novo/fp2mol/diffms/graph_transformer.py create mode 100644 massspecgym/models/de_novo/fp2mol/diffms/model.py create mode 100644 massspecgym/models/de_novo/fp2mol/formula_utils.py create mode 100644 massspecgym/models/de_novo/fp2mol/frigid/__init__.py create mode 100644 massspecgym/models/de_novo/fp2mol/frigid/bert_cross_attention.py create mode 100644 massspecgym/models/de_novo/fp2mol/frigid/components.py create mode 100644 massspecgym/models/de_novo/fp2mol/frigid/mdlm.py create mode 100644 massspecgym/models/de_novo/fp2mol/frigid/model.py create mode 100644 massspecgym/models/de_novo/fp2mol/molforge/__init__.py create mode 100644 massspecgym/models/de_novo/fp2mol/molforge/decoder_search.py create mode 100644 massspecgym/models/de_novo/fp2mol/molforge/model.py create mode 100644 massspecgym/models/encoders/__init__.py create mode 100644 massspecgym/models/encoders/dreams/__init__.py create mode 100644 massspecgym/models/encoders/dreams/api.py create mode 100644 massspecgym/models/encoders/dreams/feed_forward.py create mode 100644 massspecgym/models/encoders/dreams/fourier_features.py create mode 100644 massspecgym/models/encoders/dreams/layers.py create mode 100644 massspecgym/models/encoders/dreams/model.py create mode 100644 massspecgym/models/encoders/dreams/preprocessing.py create mode 100644 massspecgym/models/encoders/mist/__init__.py create mode 100644 massspecgym/models/encoders/mist/chem_constants.py create mode 100644 massspecgym/models/encoders/mist/encoder.py create mode 100644 massspecgym/models/encoders/mist/form_embedders.py create mode 100644 massspecgym/models/encoders/mist/modules.py create mode 100644 massspecgym/models/encoders/mist/transformer_layer.py create mode 100644 massspecgym/models/oracles/__init__.py create mode 100644 massspecgym/models/oracles/base.py create mode 100644 massspecgym/models/oracles/iceberg/__init__.py create mode 100644 massspecgym/models/oracles/iceberg/predict.py create mode 100644 massspecgym/models/oracles/mist_cf/__init__.py create mode 100644 massspecgym/models/oracles/mist_cf/model.py create mode 100644 massspecgym/models/oracles/mist_cf/predict.py create mode 100644 massspecgym/models/retrieval/generative_retrieval.py create mode 100644 massspecgym/models/retrieval/iceberg_retrieval.py create mode 100644 massspecgym/models/retrieval/mist_retrieval.py create mode 100644 massspecgym/models/simulation/iceberg/__init__.py create mode 100644 massspecgym/models/simulation/iceberg/adapter.py create mode 100644 massspecgym/models/simulation/iceberg/dag_data.py create mode 100644 massspecgym/models/simulation/iceberg/gen_model.py create mode 100644 massspecgym/models/simulation/iceberg/inten_model.py create mode 100644 massspecgym/models/simulation/iceberg/joint_model.py create mode 100644 massspecgym/models/simulation/iceberg/magma/__init__.py create mode 100644 massspecgym/models/simulation/iceberg/magma/fragmentation.py create mode 100644 scripts/convert_to_parquet.py create mode 100644 scripts/download_data.py create mode 100644 tests/test_fp2mol_v15.py create mode 100644 tests/test_v15_data_oracles.py diff --git a/.gitignore b/.gitignore index 80c8a7f..6fde53c 100644 --- a/.gitignore +++ b/.gitignore @@ -139,3 +139,6 @@ dmypy.json # W&B wandb/ + +# External codebases +external/ \ No newline at end of file diff --git a/README.md b/README.md index fbbbfe8..c1d3499 100644 --- a/README.md +++ b/README.md @@ -217,6 +217,80 @@ trainer.fit(model, datamodule=data_module) trainer.test(model, datamodule=data_module) ``` +## ๐Ÿงช v1.5 Model Zoo + +MassSpecGym v1.5 extends the benchmark with a comprehensive suite of state-of-the-art models, data utilities, and official oracles. + +### Spectrum Encoders (`massspecgym/models/encoders/`) + +| Encoder | Description | Output | +|---------|-------------|--------| +| **MIST** | FormulaTransformer over subformulae-annotated peaks (Goldman et al., NMI 2023) | 4096-bit Morgan fingerprint | +| **DreaMS** | BERT-style transformer over (m/z, intensity) tokens (Bushuiev et al., Nat. Biotech. 2025) | 1024-D spectrum embedding | + +### De Novo Models (`massspecgym/models/de_novo/`) + +| Model | Type | Approach | +|-------|------|----------| +| **SmilesTransformer** | Autoregressive | Spectrum โ†’ SMILES (encoder-decoder transformer) | +| **FRIGID** | MIST + MDLM decoder | Fingerprint + formula โ†’ SAFE via masked diffusion | +| **DiffMS** | MIST + graph diffusion decoder | Fingerprint โ†’ molecular graph via discrete diffusion | +| **MolForge** | MIST + seq2seq decoder | Fingerprint bit IDs โ†’ SMILES via autoregressive transformer | + +### Retrieval Models (`massspecgym/models/retrieval/`) + +| Model | Strategy | Description | +|-------|----------|-------------| +| **FingerprintFFN** | Direct | FFN predicts fingerprint from binned spectrum | +| **DeepSets** | Direct | DeepSets predicts fingerprint from peak list | +| **MISTFingerprintRetrieval** | Bonus | MIST predicts FP, rank by Tanimoto similarity | +| **GenerativeRetrieval** | Bonus | Any FP2Mol decoder generates molecule, rank by FP similarity | +| **IcebergRetrieval** | Bonus | ICEBERG simulates spectra, rank by cosine similarity | + +### Simulation Models (`massspecgym/models/simulation/`) + +| Model | Description | +|-------|-------------| +| **FP** | Fingerprint + metadata โ†’ spectrum via FFN | +| **GNN** | Molecular graph + metadata โ†’ spectrum via GNN | +| **ICEBERG** | DAG-based fragmentation with FragGNN + IntenGNN | + +### Official Oracles (`massspecgym/models/oracles/`) + +| Oracle | Task | Data-Safe | +|--------|------|-----------| +| **MIST-CF** | Chemical formula prediction from MS/MS spectrum | Yes | +| **ICEBERG** | MS/MS spectrum simulation from molecular structure | Yes | + +### Data Utilities (`massspecgym/data/`) + +| Module | Function | +|--------|----------| +| `subformulae.py` | Subformulae assignment for MIST-based models | +| `mist_format.py` | Convert MassSpecGym TSV to MIST-compatible format | +| `sanity_check.py` | InChIKey-based data leakage prevention | +| `fp2mol_dataset.py` | Parquet-based dataset for FP2Mol decoder pretraining | +| `download.py` | Download MassSpecGym data from HuggingFace | + +### Quick Start with Checkpoints + +Place pretrained checkpoints in `checkpoints/` and load any model directly: + +```python +# DreaMS spectrum embedding +from massspecgym.models.encoders.dreams.api import PreTrainedDreaMS +model = PreTrainedDreaMS.from_checkpoint("checkpoints/dreams/embedding_model.ckpt") +embedding = model.embed_spectrum(mzs, intensities, precursor_mz) + +# MIST-CF formula prediction +from massspecgym.models.oracles.mist_cf import predict_formulas +candidates = predict_formulas(mzs, intensities, precursor_mz, adduct="[M+H]+") + +# FP2Mol decoder pretraining with data safety +from massspecgym.data.fp2mol_dataset import FP2MolDataset +dataset = FP2MolDataset("molecules.parquet") # auto InChIKey sanity check +``` + ## ๐Ÿ”— References If you use MassSpecGym in your work, please cite the following paper: diff --git a/checkpoints/README.md b/checkpoints/README.md new file mode 100644 index 0000000..4db47a6 --- /dev/null +++ b/checkpoints/README.md @@ -0,0 +1,43 @@ +# MassSpecGym Checkpoints + +Place pretrained model checkpoints here for inference. + +## Directory Structure + +``` +checkpoints/ + mist/ # MIST spectrum encoder + mist_encoder.ckpt + mist_cf/ # MIST-CF formula prediction oracle + mist_cf.ckpt + iceberg/ # ICEBERG spectrum simulation + gen_model.ckpt + inten_model.ckpt + dreams/ # DreaMS spectrum encoder + embedding_model.ckpt + frigid/ # FRIGID MDLM decoder + frigid.ckpt + diffms/ # DiffMS graph diffusion decoder + diffms.ckpt + molforge/ # MolForge seq2seq decoder + molforge.ckpt +``` + +## Usage + +All models can be loaded from checkpoints using their respective classes: + +```python +# MIST encoder +from massspecgym.models.encoders.mist import SpectraEncoderGrowing +encoder = SpectraEncoderGrowing(...) +encoder.load_state_dict(torch.load("checkpoints/mist/mist_encoder.ckpt")) + +# DreaMS encoder +from massspecgym.models.encoders.dreams import PreTrainedDreaMS +model = PreTrainedDreaMS.from_checkpoint("checkpoints/dreams/embedding_model.ckpt") + +# FRIGID decoder +from massspecgym.models.de_novo import FRIGIDDecoder +model = FRIGIDDecoder.load_from_checkpoint("checkpoints/frigid/frigid.ckpt") +``` diff --git a/data/exclude_inchikeys.csv b/data/exclude_inchikeys.csv new file mode 100644 index 0000000..eb7ad68 --- /dev/null +++ b/data/exclude_inchikeys.csv @@ -0,0 +1,40885 @@ +inchi +GWGKNTICBPKKKW +FFCLYSVFZQXUHI +GRJSOZDXIUZXEW +CTBBEXWJRAPJIZ +BTVYFIMKUHNOBZ +BKUKTJSDOUXYFL +JYGXADMDTFJGBT +XUBOMFCQGDBHNK +XUBOMFCQGDBHNK +ZNRGQMMCGHDTEI +CNPVJJQCETWNEU +PMXMIIMHBWHSKN +DCCSDBARQIPTGU +PIDANAQULIKBQS +ZUXABONWMNSFBN +VSJKWCGYPAHWDS +IXOXBSCIXZEQEQ +IXOXBSCIXZEQEQ +WJEOLQLKVOPQFV +JBMKAUGHUNFTOL +LQOLIRLGBULYKD +WLBDLEIVQGMNCG +NETARJWZTMGMRM +BOLGBOZCCGUULF +ROQRBGPOJLWCGH +ZVXLOXYROPHNQQ +OFDNQWIFNXBECV +VYIQDOVNWPEWRJ +NHLBOKNHQIEJIH +LGNSRQOKLMYSFC +NVXHLYRVFXNJGK +KMRMSYHYOVGWCM +DCIHLTIBNFDPMW +QOZZMIMTOTZWNP +ZPJLQAOTGYKOBJ +ZNMZYHOEYPCVMP +SKVKIGSFTGVBOX +VOHAPZCYHVKGHA +LVIQQCFQNQKTNJ +LVIQQCFQNQKTNJ +CHHLANXNIQPKBE +CHHLANXNIQPKBE +MRGBMROKFAMEML +HBZNVZIRJWODIB +BMBUWKNHXZNMFT +SSRRIJSEUKHYFB +LUTADWBBHJXPTH +CZOSTDZGCCEZTJ +CZOSTDZGCCEZTJ +JQKOHRZNEOQNJE +QGVFETJQEKVSJA +CKENYJFJGHNNLP +FZFYFSUIOSWLHW +HWCWBPUPNDMKIV +FEBLZLNTKCEFIT +FZCHYNWYXKICIO +BGDKAVGWHJFAGW +ZKLPARSLTMPFCP +RMUCZJUITONUFY +XYLWKHKCYHMVMA +APJYDQYYACXCRM +YPIQVCUJEKAZCP +IXOXBSCIXZEQEQ +WKGXYQFOCVYPAC +JCCNYMKQOSZNPW +OGSBUKJUDHAQEA +XFCLJVABOIYOMF +CPEUVMUXAHMANV +ZIUSSTSXXLLKKK +RAOCRURYZCVHMG +TVQZAMVBTVNYLA +ZZORFUFYDOWNEF +XBHBWNFJWIASRO +GKQPCPXONLDCMU +ALLWOAVDORUJLA +KPBZROQVTHLCDU +YWLXLRUDGLRYDR +FEBLZLNTKCEFIT +PVHUJELLJLJGLN +KVWDHTXUZHCGIO +CUIHSIWYWATEQL +QMLVECGLEOSESV +WBPYTXDJUQJLPQ +VWAUPFMBXBWEQY +RLQUGMOZSOFTJC +SVKSSWZXLVXEJI +ZIUSSTSXXLLKKK +RSJIHDBGVSYSFI +DLNWZIVYKQXLTN +CAGLGYNQQSIUGX +HFXBOPGUQAUMHA +JNLNEIIZZQABDP +PNVNVHUZROJLTJ +GCKMFJBGXUYNAG +NRNCYVBFPDDJNE +FIHJKUPKCHIPAT +KEEYRKYKLYARHO +NJCJBUHJQLFDSW +VWVSBHGCDBMOOT +OKBVVJOGVLARMR +UKTAZPQNNNJVKR +RCKCYCDBDYUIGM +BGOQGUHWXBGXJW +ACWBQPMHZXGDFX +BPZSYCZIITTYBL +ZEWQUBUPAILYHI +SLVMESMUVMCQIY +NDAUXUAQIAJITI +WPVVMKYQOMJPIN +YHSMSRREJYOGQJ +DKMFBWQBDIGMHM +VKHAHZOOUSRJNA +PVHUJELLJLJGLN +OPWCHZIQXUKNMP +UWRCXFLYVGTCAN +SRNFRTSVHROPLE +DWHHXZAZGAWQDF +DLLZYSNYQLEBDM +WAZZQDMECLXFPW +OWRGTCNIAMOXMJ +PGFKZUOYIFDMQJ +KFWLSTWDVTUEHP +ONNIQHQMYBDPDM +RRJWTPLXCYHWGJ +GFVZTAWQXORWCC +BAKYVUHOODEWGV +KFQFFSFVCKZEMA +VCXROLZIPAFETE +XDHMIOKEPFUOJT +YWKMPSBOOTVYHX +UUBNGEFLZPEMIV +FONHTANVJZLRTJ +CILMVYLOUANTLX +BIUZXRRWYROHHD +NSRJSISNDPOJOP +USXFKYQAUYLZOT +WHZXJVJVGGWZQI +OJUPJYPBBXUCNE +DFMAXQKDIGCMTL +KQUTXXWSXHOINZ +RPNCFIWEUHDOMG +WQXKOBYLQWJFPY +MDHMFQLJCYZIRM +AKCNARCKRKZAHX +ICQSMOIRUNOHQP +QHBOBFSAKTUMRH +COBBNRKBTCBWQP +SQWWOLPKBDNQLV +YYGSCYQUDZCDBG +BTQSOPJJNTXHCY +IYRHSWAOHIYAIM +MDKAWFIEKHSDSV +IQAMTZLKUHMPPE +POMGXFJJUDSWMP +BPTYIBFPGCGEDI +FMSWDQKKHNMTCT +HWGSIQVTOVKMIE +IXJYBHDPOWDVBJ +MUVNCRDMSIAYKY +MINFCKXAWKNBAP +OCYJXSUPZMNXEN +JGOQQRJLZBEXQB +HMWJZUXCXLSLJO +BNZPDENCVXRJMM +MFLKAHOBCOBBJX +IYBLVRRCNVHZQJ +CILJSZLWPHTUIP +FVIBWHVCUMNZLO +VGBKUEYXIHVZRQ +FZERGOGCRZMSTP +XCIGKBBPJQAESH +IECSQLKWZBEUGA +YLCKQNHDIIGLSU +QSDALNKTMACYSH +HYTBGBFBMYXFFD +AMJALMUHGMYUPN +YSOKENZJQWPLRA +PMTSPAGBAFCORP +IYRMWMYZSQPJKC +WFSYATBEJTUDQA +SHZFSEANVASGEO +LQSGRURSAZWYKP +IDYLZBMYUOISRS +LKZDFKLGDGSGEO +WLMNOQLTEBGVAO +SDFDJNSQTCCFRD +XIWCDUHPYMOFIL +XIWCDUHPYMOFIL +FMCWKGDGAHVFMC +BDIZBBGNYDRCCA +MAUDUGHKVZOSRY +NIDRYBLTWYFCFV +XMFNWUGXDIPNJY +CDBRAQGRBQMVMA +CSYGMMBAZUTWOT +KSGUPXSMQDCSNG +RCJINVKJESWGOW +HVHOUBUTSQGNJT +WSEGRADBFAKNHQ +LPMKRELFHFSDTK +UFSOZYKZIKZDGN +QXZBWKNTBOEWLH +FFYMBAHMSYIJOC +VBFXAALSKCTOAO +LDOPGQBXVCXINY +RZMUABAAIKIJCD +OGKLVJMNCMVUAQ +GHKUMLWXBYYVNR +POVQJQHUPJJVAW +VBXUEFAIPJPNBO +TYNBQERPUSLOCV +TXGYAFMZOGJQPI +YSYIHPDPLHTIRM +IINSYDKEJXOBGR +LWAFJAUWIUJDHP +BGEBZHIAGXMEMV +ZXZPFGGUUZDXND +NBSGYTDQQVCASP +UXDAWVUDZLBBAM +UUQHKWMIDYRWHH +OBZJZDHRXBKKTJ +RSDDHGSKLOSQFK +GLBWBVLCGWIKCB +CCDVHOPGVALFAG +JRYNNKSSMKSHIQ +PLFGRBPWZRSCHW +UZOWNJLPOYFYLR +LPNBCGIVZXHHHO +MLECIHPSKWCZFV +OYSKVILZFAAMME +WUJIVYPXVXGIJD +HKBYEHNTKISRIN +HCNLDGTUMBOHKT +LIIALPBMIOVAHH +RTIXKCRFFJGDFG +AIVKMXQXXMVVJY +ASTVQIYCKUTUJK +JBQIHOASDQXPJU +PVSWCIQNCLYJJV +MSXOSDJERSCOQW +JOFKCNJIUXPJAC +YEDUAINPPJYDJZ +ZSYSVZDAQKHYJN +LETKKDJDILSMMC +HPSPCMSCDNHZJM +NYNOIMNCLKTWCG +OOCLJYAMEFPTPK +BLKPFCUMGVQKSL +DPIAJERHFDBLPT +SVPDNNKLQWHTPC +INBPQAJYHSJVRY +TYNNXAMDNHTMLY +HGWDKWJYTURSFE +GAIYJSQKRRARSH +HVYQNVUUFHVCHX +CEDINFOMXSQPIQ +VZPASGPLDDVYCL +PNARHJLMOIEDMU +KYOZFCGRLRKQNZ +UDVBEJLZYOEXNX +SPZXXUUDYMHBSG +LSGKMZLPZFPAIN +SRTJRFVGRIMETK +YPBINYWGYJDKCF +VRZNREAVGVERFB +NZRYVUZCFKOPIU +KQYNNEFXSOOTEY +PIQWYJBYGQBLRX +CGYNVHQAIUIQLZ +NDYMQXYDSVBNLL +WAGZSQGCUXDBOA +NEQVOBXBOFZEMR +MYXNWGACZJSMBT +SJGXLSYEYLGFRT +MVIJSQNWYLPBGP +YJPIDPAGJSWWBE +HUJXGQILHAUCCV +GSYQNAMOFFWAPF +DEFAKPKFXYITPZ +RQXCLMGKHJWMOA +SYNOVMDJYWJCON +ALFGDCNSEBJYSP +LOMMDWBTANPFEJ +TUFADSGTJUOBEH +JTVPZMFULRWINT +AYYCFGDXLUPJAQ +JGOAIQNSOGZNBX +SEBFKMXJBCUCAI +NWIUTZDMDHAVTP +TWUSDDMONZULSC +MDJRZSNPHZEMJH +DJHCCTTVDRAMEH +DWYHDSLIWMUSOO +VPGRYOFKCNULNK +PUMYFTJOWAJIKF +NMKSAYKQLCHXDK +CKWHSYRZDLWQFV +RLJFTICUTYVZDG +UOMKBIIXHQIERR +XJLATMLVMSFZBN +GHWJEDJMOVUXEC +HFVMLYAGWXSTQI +HNJJXZKZRAWDPF +OUDSBRTVNLOZBN +JHBWYQRKOUBPCA +ITJNARMNRKSWTA +DEQITUUQPICUMR +DSFGXPJYDCSWTA +HMBHRMFLDKKSCT +SLVMESMUVMCQIY +NSHMVLOWOAQFTP +VIKNJXKGJWUCNN +ZXNRTKGTQJPIJK +ZFXYFBGIUFBOJW +QVYRGXJJSLMXQH +VWVSBHGCDBMOOT +SKVLYVHULOWXTD +WOXKDUGGOYFFRN +YSSBJODGIYRAMI +YAWWQIFONIPBKT +JVBLTQQBEQQLEV +WEUCDJCFJHYFRL +HDOVUKNUBWVHOX +NTNZDKLXIBVSQQ +YGCODSQDUUUKIV +LGZYEDZSPHLISU +BXJHWYVXLGLDMZ +QTTRZHGPGKRAFB +NVEPPWDVLBMNMB +CURUTKGFNZGFSE +ZSNNBSPEFVIUDS +XOFYZVNMUHMLCC +MYNBDRGQYBNWEN +YTLQFZVCLXFFRK +DZTHIGRZJZPRDV +UNBRKDKAWYKMIV +WAOQONBSWFLFPE +YYVYAPXYZVYDHN +WJFKNYWRSNBZNX +VXJABHHJLXLNMP +QVCMHGGNRFRMAD +OGJGQVFWEPNYSB +KPQZUUQMTUIKBP +BQJODPIMMWWMFC +FZCHYNWYXKICIO +PJVWKTKQMONHTI +QJHCTHPYUOXOGM +ODQWQRRAPPTVAG +IORPOFJLSIHJOG +UDFPKNSWSYBIHO +QOYHHIBFXOOADH +VJJPUSNTGOMMGY +JFRJCQJVFMHZOO +JYGXADMDTFJGBT +CRRKVZVYZQXICQ +BGKFPRIGXAVYNX +LBVZWEWTNUDWNS +QQBPLXNESPTPNU +NYKCGQQJNVPOLU +HRSANNODOVBCST +KNADXBVKFAUMCR +MJFJKKXQDNNUJF +LGQCVMYAEFTEFN +YLJREFDVOIBQDA +JXMYTVOBSFOHAF +YEHCICAEULNIGD +BYBLEWFAAKGYCD +CWXYHOHYCJXYFQ +FVWANTDQRFSCAL +BGHFNLPNJHBAHX +YMUOZXZDDBRJEP +UIKYAUSFWRLFDK +ILZBYZQNJIYYNP +FBPFZTCFMRRESA +HVAUUPRFYPCOCA +HZMKSGSOBKQGJX +WCIZHDREQJXEQO +NBDNEUOVIJYCGZ +XVNJBDKWBSRNOE +WRFCJLBPEINJNJ +RLIACMHWGOIUBV +NLKSLCYYSLLAMB +OACSANJOUKCFPQ +NOERPJFUTRUZHQ +OFUTZNNUWRTXHO +UKVKACNHLXTJKA +DIRGAGXDBYDWQB +DQOWHTFHFLRPDX +IXGXYZXRENQKBA +WWNWMZIUAQDDRB +WWNWMZIUAQDDRB +MKBNTPDMOZKDSO +OFUDGDJEKOUEKG +CYZZFSCFKCNCLO +LGYQYCWMQRMLJJ +PNDDYPOQKFXUHY +DWQQWNRHLJPIDV +DSHVEBDLSYMWSX +FTGOWEQDZZMPNJ +HKSURPHWRMGDOZ +QBTIITFMJQCGKE +YXJMPPIPGTWBHE +FMPIFABORGZGFA +UKFUHWPKKCYCQR +NHAFYGMKGLAVPH +XYRSQOXRWJBEIG +HTPODFYRHLWACU +PHEDXBVPIONUQT +DGOSGFYDFDYMCW +YZQRMJFPWMHAJV +CFJMAERFDLWMJL +FEQKQISWJNDCPC +KMVGZHAXSWPDLJ +BNZZZUQOYBAEPR +PJPKEOASXRGMDD +RKXDYKMWUHSLGF +OSZKDAKKYIIJBK +BKNDRWLBSMZASB +UORGKBIHVJEQBO +IRTSNPJRIJTNNN +NYVFUDQEAURUPX +HTCVSLIHSFBUEL +BRLXWEGCLDQJEL +KJPAOKCLRDGPMI +BJGUEPXNQKBVBW +LBRJFDBQNUVAGM +LBRJFDBQNUVAGM +JYCYCQGMUFHEDI +MTEWLNRVQLKTFS +LRWWIPZJXHBJSP +JVNVHNHITFVWIX +VEVJTUNLALKRNO +BNNIEBYABSNREN +AFSHUZFNMVJNKX +XUJNEKJLAYXESH +DUXYWXYOBMKGIN +GUBGYTABKSRVRQ +ZUKWGQJERAFPPP +UFLYYPBSJUQZFA +CZFMBNIKGDJPJQ +OBNLKIYUNMSGTC +OBNLKIYUNMSGTC +LIKKXXHSQQGZKK +DFHAFZIZPJQODZ +LIKKXXHSQQGZKK +OYMAGMAEFPAAGU +GQPFUOPPYJYZHE +VADXJHCQZHEEOX +PKVYWDGNNJJGMX +ZHHKJHQJBVODGP +VDFMWZBFYMHHDB +VCMDZWFWWFIEOO +ZJNHNDJYASOIMA +LQGNIRWAURPTIG +QYTBDYVUMOVEHG +QTNFTTFYVXJGEA +FUGMHZCDRCPQDM +IAJYQKUPYJPDLQ +NKBHDXJJPQYANN +KDXYYRZHRDVSQM +KUKQXNQRXXTUEM +GYSCAQFHASJXRS +RJFAYQIBOAGBLC +BZQFBWGGLXLEPQ +AHLPHDHHMVZTML +YHHSONZFOIEMCP +MXNRLFUSFKVQSK +OSJPPGNTCRNQQC +ZOOGRGPOEVQQDX +QGWNDRXFNXRZMB +ZWIADYZPOWUWEW +KLZGKIDSEJWEDW +CPAGZVLINCPJEH +SPLUHYDIQKURQW +VCKPUUFAIGNJHC +ZOAMBXDOGPRZLP +ZHSOTLOTTDYIIK +HUMNYLRZRPPJDN +VRFDHCWJQWIDHH +NPYICXUUGUJPMM +RZVAJINKPMORJF +JMTMSDXUXJISAY +YFNKIDBQEZZDLK +LRUDIIUSNGCQKF +BPEXTIMJLDWDTL +YEDUAINPPJYDJZ +MVWVFYHBGMAFLY +ZEUITGRIYCTCEM +HOASVNMVYBSLSU +PYVRVRFVLRNJLY +ZUPHXNBLQCSEIA +MXWJVTOOROXGIU +PVHUJELLJLJGLN +OUXMJRMYZCEVKO +QHOQHJPRIBSPCY +DNTGGZPQPQTDQF +VTNQPKFIQCLBDU +PSGQCCSGKGJLRL +SEGLCEQVOFDUPX +RUEPXZDDWQCITK +CGEQZXRFQKBBQJ +OLRLUJCFUDJRGB +LUIGTZGBXWZJAX +LUIGTZGBXWZJAX +XMWOVKVFIVCVPN +XMWOVKVFIVCVPN +NRQJFEDEWHTAPZ +OCLJUQSRRLIINU +VIHRKOVEWCGJQP +IGWDEVSBEKYORK +FOINLJRVEBYARJ +ZVMKPMYSSLDZJO +MHGLNDDJLDJDBG +FCMYLROGVKJIDN +UPEZCKBFRMILAV +UPEZCKBFRMILAV +DUMQPTRUYCCSEZ +PAUVEHXCLNBAPG +XHFZCGJKWBSHAG +BIIZWIKNPOIDLS +BIZAJDCIOZNYLQ +CZOXIGOPZRIBJM +GODZRCRSZUIPBM +FHIJMQWMMZEFBL +FXGOBECSEIQDAS +CLFOWTUGPBWLGH +JSGVRMXIAILPPO +LRLROPFPFABQRF +STNNWPKHRBGYMO +NUYFKDBCHFKOBT +QERAXRDNYJPTRN +NKNHYXCDCIOHRT +LARSXHUKWMVHRB +KHCREUNEQGORAM +LCAZOMIGFDQMNC +UTECWQIXBMWRRR +SMVZSPTUXANNGQ +JURQVQJHQONKKH +QDDILOVMGWUNGD +RIPKCRCUFJSKKD +VOTMSYBBJIFRQZ +XLUAWXQORJEMBD +FMEUWIKCSICJBO +SVGOJJZXRJJDLY +RPVIQWDFJPYNJM +ISTWCKNDZOSMPU +YTFVRYKNXDADBI +CCNKTMMNRPJQHV +ZSKDVJYWOHBGNI +AOUZZRQCLQLQIF +HMOMGSPWDYKCAH +JLINBAUQGJKNRS +JGCNXPIMJMUVKE +MAQMWSUGBCIGLJ +BCNBWICEIXAVQF +HNNQILZBIHECCU +MFSMRLNNRGLWQD +LYGRISUQIZNHGM +LWONLPZQFYNCMG +GGLFMIALTLLMEJ +DKEANOQWICTXTP +JGHUOJAZXGSFRI +TUSDEZXZIZRFGC +LIIALPBMIOVAHH +HIVUDBSYRZRZSH +XAQHSTCVGOTLHK +MUBLYIKZGKHTMF +PCUOEOPTDCUNQQ +YXZYFHXWEOAXLF +RZILTIPWCHNOKU +SETVRSKZJJWOPA +OQLFZIMUPPRHDP +ZULGBROEAWAPKY +NSIUWPVISVFSGF +HFSJWNXFQYKQNX +CZVGIALASULOAU +HAVWRBANWNTOJX +KQQLSXWIDDTWRR +QACRJXSXSVUOFZ +DXBGTODWNFZHCD +HILBWEPXZDMOAE +ZLAQYJKDQSZARB +SXPBJYHKMRWZNA +ORJDDOBAOGKRJV +QLSUUELDMMCCEI +JGGWNGRBXJWAOC +JGGWNGRBXJWAOC +YBUWNKPGCLTWJO +UDHCHDJLZGYDDM +PUDXYWKCEYLTMQ +PKKTXAMCHLIVDS +ZFABEUFWUOOQMI +VROIYIJLFIRSJU +IJEHYEVNWOYGMS +CCTUVGJRXQPMOJ +XFNIQDLOQLIJTQ +BYYDEEAJCDGLER +DFPMSGMNTNDNHN +RNKMOGIPOMVCHO +DFKDHZBMIJQPIK +RWTAMSAIOGWNBT +RWTAMSAIOGWNBT +WCFYXOLUODJLKB +WCFYXOLUODJLKB +MLOMRDQPPYHSAX +JRWYAESVJOLYCQ +KNCNSYQYJUBLPW +QXXKEARZEYWTST +KIDYUEHQXIEBGK +SITDJJDXDVFCAP +WHNBKYRXAOMPAE +FSYVGCMCWALMCX +KSQUXZFVIOCIHF +JGMROMZJBQKIDK +XREDRJVZJRMVHB +SOJLUKNFWGXUFS +KZJQLAODESHSCC +MCTDXPDDZLFJHR +PVPDIJGSCANSAG +PGOMXBOHQUBUMI +YUGLDRNZSJJFIK +LRIXRCMMIFKCDB +LADPNODMUXOPRG +QPLSCFLMIOADPA +QPLSCFLMIOADPA +FNMHEHXNBNCPCI +DGYASNDHNSXGSL +MIZMDSVSLSIMSC +RCCBGOMNZWYBTJ +RCCBGOMNZWYBTJ +FFDULTAFAQRACT +JZCRGJSEBZCNAR +SUYLTDFWHNXGDX +BKJYMZRGLINXRP +XFTFIFNAWKMLKL +XFTFIFNAWKMLKL +TUUBGLDJKKCMRH +PAIASCMUTMHGHU +RVWWDDKOKZXKCJ +UCJHITBUIWHISE +OFLCPNIRDVOOEZ +UFCLZKMFXSILNL +BEDSGEULUAVXQH +CUCNRHYDISBEQH +UEVWVMGTABEFID +NZLXTWAEDURRNL +CJUHWKPMXGYAGR +IKHAPHPJWABCCU +ZECKKAHILSTZLB +QUHYUSAHBDACNG +ZPINJJOPURFFNV +LFAZJMJJLQUOPK +DIRWTXHNLLFBAL +NXSUIALRPVXVTA +CEBXXEKPIIDJHL +ISHXRANDGDVGJS +ZBVKFVTUHVIICH +IJSJXKCVRHBPSG +YTRXIFNFFGXRFV +PQQITYGQJLPDFC +PACBNJFGEWTGCE +IZSBMDHDBLUZOI +WAPMVTHIMHEOAB +WOCSYFBKPNKGJB +MFOVLHFTNQGRLH +SYXFLGVZXNKIOY +PKZLCDIEFSFXDK +AWCUZBLYCWUTRL +AWCUZBLYCWUTRL +OWWJIYCJJLVSON +OWWJIYCJJLVSON +OIXPKFRMEUTHOG +CBEIHVWVTGRGDR +BOCUVDNZFZFUED +JYXSWDCPHRTYGU +YPHMISFOHDHNIV +RNVUDWOQYYWXBJ +UHWIZIJICYWABA +NXDNDRJNQJPXGJ +VCJBNRNRYLKSGX +WHICJDPSYBJDEN +WHICJDPSYBJDEN +CZCOHVXNUPVUBC +MHJLKHNHGMUAPQ +SUDVQVUJMZQNHR +ASPYFUBXNRBCEV +BMFPATPGMGPSGR +YVHLLZXSGPDXOA +PBYPZVMETKFGQR +AZYVCLJYWIHOAD +FNVCLGWRMXTDSM +QAUDHOGPLBDVAX +RVPPNKOUWPOQRX +KWEIJKWXQKCOKC +QPNFBUARICHXGG +YEHDMSUNJUONMW +DVLLGHPCJPEUHA +KNKHXYYGNZZSEJ +LXGTXWCOSLFWKC +VLOGACFISZMMCN +TVKGYMYAOVADOP +FEMTVABTBAWCEK +SFUCGABQOMYVJW +KLCSKEIAIWQUEE +MRDZSBVJWOXBRW +ZCYXGVJUZBKJAI +BENIATCKWZLKMA +PWDXABLHFDFFEB +HOFGZJTZROMXRO +ZBFSUZGUYFFWGY +UIWUAELYQAENKN +JJZBHTNQMXMCHH +DHAXSUMTBBBFBJ +BVSLLGGUGCRTFA +LJSWMDKKEBOERP +DXHRROZVQMDXOO +DXHRROZVQMDXOO +KKEKLEUWEJUCRA +OQXBCMJIIDQITC +ORXQGKIUCDPEAJ +JCUIPEIMZRLNKQ +HJDODWXISWRQIF +QEGXBXBKQLQOHP +PGRWPWIGJLNDHN +WKHWTIZYRUWECB +KJWFOHVSTFGWGZ +IZODPOCIKVLNIL +SCHVWZLYQPLPJV +VUVWVGLISBHUCV +UDIXYHJHYVDNOG +DTOUWTJYUCZJQD +DTOUWTJYUCZJQD +KNZZAAGBIUZSNV +WTPJPYNIRFDQSR +MXEZBPCVRNMVLQ +MYXNOIIPXWBFFR +YUXUTEAAGHFKKH +KHWHODOWEXOYIJ +KHWHODOWEXOYIJ +AQCKKGIVKOHRLM +RXAXTTGJEMODPY +RXAXTTGJEMODPY +SVCPILBFQWTZFW +UCAFTLMODRRASO +ZKOTUWJMGBWBEO +YJXRPXBRYBCYRH +YJXRPXBRYBCYRH +BDCDNTVZSILEOY +SYEZZRGTJNNHEL +ABOPTWOWDLNBOE +VSUOKLTVXQRUSG +IQOUQPBWTJSPDL +RBQNDQOKFICJGL +UJKUPLFZLUIDFV +PBQMALAAFQMDSP +LSQRGMPMJOCLHX +UWNADLMLMRTPFL +MEIWPHMJWJAVIY +XJTXBUKLGQCZHC +PKRPFNXROFUNDE +IKUQEFGEUOOPGY +FKMASXTUONWHBB +DCZPAFXGNAJXHQ +BHPGSJYBVOBTHV +WSGPLSDARZNMCW +MSHWJYPCLRLDEB +MSHWJYPCLRLDEB +ALLQMEDAYDKMIO +GYUCMTKUEQLBJW +IKQSIKPOUMLPKK +IHXLRPOTFALLKF +YOSAXDOXINGSJA +VNQNUULCMPXFER +VTEOBBGFBSSFNH +YLHOHANRUSKHKO +VNXYHRRGEDIKJZ +HRTKMOMTMZCGLF +WEKCEGQSIIQPAQ +SNKFFCBZYFGCQN +YMWRMAOPKNYHMZ +WVHDCAPOGJJVCD +TXIKNNOOLCGADE +FQWZGEBZILOCET +OWOJTAHJWVECHR +KSNWZOGDNCZVEN +KKYNVNUZEODDKF +GFMGOVRWOOAPMN +GFMGOVRWOOAPMN +GVRDYBOOMKTYKH +FKCYENFBFZUSDP +CLYLZXCYEKJUEK +PQQRNPDHSJDAGV +GVVXPMORGFYVOO +YVCVYCSAAZQOJI +ZITBJWXLODLDRH +UJZQBMQZMKFSRV +OFNCUIXPAFLTJZ +FJYFQXJJSFYJQV +LQEYIIJYBJCNKH +CXVPYCSNJZJTRF +IDPRQTHSAHGSDW +IDPRQTHSAHGSDW +PJHJORWYAZKNAL +FSBUXLDOLNLABB +RFEPDQFPTNCOBK +CAUANPLJFMVCHO +AIPGFMVNUMXXEM +ULOAWPSYNSJWGI +NUJWBDOJBSCJEG +GMXMKSFJQLFOSO +ACYXDIZTQDLTCB +FOBNRKTURPWTQX +FADFGCOCHHNRHF +GFMYIOGFYYHKLA +GFMYIOGFYYHKLA +ZGNUJHGCJSHIQU +XKKQZJGDCFDION +GNDDBOHLMOANGU +QZONBCFTKCIUKE +KSENPDOZJGRJHR +XYPWCJWXFYYGPA +KMPAOJFBQSXEAI +WGPOPPKSQRZUTP +UTMLPTPULBHGMZ +AEKPZNDJHWFONI +KYDNOVLBVBYOSW +UWTOESDPWKUNBD +AXUYMUBJXHVZEL +PNBMEXOTFKNHLQ +KRZBCHWVBQOTNZ +VNBPNPCSBYXRNC +MPOXQBRZHHNMER +ORMBYUPZHHWUEM +JMCVYQUHLKARLD +JMCVYQUHLKARLD +MGQMHWZXSBFPMH +AERAMEUFSDVACO +RBKWJAHRWPDNPM +VJVXQSFKTVUEFY +VJVXQSFKTVUEFY +QGQSOVLOEOVNRW +AEPMKZIOUKHDOO +HYBRYAPKQCZIAE +LSEDQFLRUJOXDX +DCSLTSSPIJWEJN +IFAIUWDLBBYPMZ +JCJPVNDLAAXNEX +LAUJMTGOOIBBOB +JGXZVDAPLSTBGZ +FCYCVETXTGWXBR +MLMDACHSXKCQIF +MFLWBVVCOWPUBA +QFOFNCNFUGQWTO +WGVQPPKZKAJDGR +PICOUNAPKDEPCA +MYQAATJJIDGOMQ +YSORAXGDTRAEMV +NFOCYHUCMXEHDG +FCANTWZHYAQEKU +WCAMADNGWUBZMH +AFDANKUHSLVEBJ +XPLMUADTACCMDJ +NLDDIKRKFXEWBK +NLDDIKRKFXEWBK +LBZXZXIGWNHGTB +TXCAFRVNHJUDMI +VJWYQRXPCZNDKS +ZFSLOJRJABHMTL +XYUXECAMXQZDMY +IYBDDRJHJMFFBB +GZAQAICYIHWIAX +CKGKQISENBKOCA +RIVNVLITMUKUQK +TURHNAJJDDIVGC +YHJDRJVMBSUEDI +SYVFGLXUEAXFAP +WRSGLSMQZLBGNH +IQTTZQQJJBEAIM +IQTTZQQJJBEAIM +OAGXTVOZBKKJKA +KOWMJRJXZMEZLD +JWWFVRMFYKPZNE +IMXVXFLNNGIIDL +RTTRTWCKPYQXFS +YFIMUDXPJZVJJO +SWLNXMJZQXZBCB +VLHOVPZUSXEINR +MZNIJRAPCCELQX +BEFBCLTWLOLKAQ +SQSRYWNOKPJENY +SQSRYWNOKPJENY +XCQNRWMPPLJRCM +IPWPEUJWMOPJDG +ACGWJYPSNRKNPW +VRHZMFGDDGFRLP +IIEIJMSDKBAFFP +AODBEDTXATXPNK +UFCLZKMFXSILNL +FVXAJZRADGVLQM +QUCKZYFUROTIBC +ZBUMLAXYOMYUCL +CAXDNOAMAQQQMX +HOXFNEPVXKQDSO +ZWBYHLQWDBQQQU +ZLHVIYHWWQYJID +PPZVSYXNLXFYAD +FOMYLMGOSTVYEE +OLLIISPFUQXHLB +NJYYDRBRLSOFNG +ITWCBKGNWXDVFP +RTZKSTLPRTWFEV +RTZKSTLPRTWFEV +AQRNEKDRSXYJIN +IPUBQCBQSUVXEV +LKOCXGZSSYQSLN +FRZOQPPWSKEZAA +NVXJDQXVTHYURW +QXRDTLAXUJONPD +QXRDTLAXUJONPD +CDYGRHOHQUXDMN +JFVKWCYZKMUTLH +YEFOAORQXAOVJQ +MFQIWHVVFBCURA +XKXZAYIPFRBKHT +RZQNQMRSGMXXMH +PBAZKMWQUBDDLZ +BUKNGVJDVSRYIT +SOXXAFVUSIMAGB +ZUPASDOWHXCIHQ +YRVGYJMSCQFOCA +AYJLVEAOIKOWIP +LJBQMFMENPSWTI +DGYASNDHNSXGSL +VOCJFEUCJDTXSA +LJYPJWICCCIAKW +OFUTZNNUWRTXHO +ZJSJQWDXAYNLNS +ZJSJQWDXAYNLNS +WWWGLKAMMZTBJU +ICLRNDIRYAEKCT +DXSMIOSVACQXTE +DXSMIOSVACQXTE +SNPUUTQIPHTWGL +VVSZRCIUFBADJQ +TUGWPJJTQNLKCL +HTCUURQJNZBKIA +VOYCJQSSBDMXNQ +VRWFEVIVOZKBJA +MLSVKXQHUTYXHD +PEERGVFNQUXNQA +WTLZPZUWOZQDLR +ZIMOUPHGHTXJRD +ZIMOUPHGHTXJRD +HGHSJJSYVZPIAW +HGHSJJSYVZPIAW +WLSOGIGMSWCVID +LOTLMZWGLBOKFL +YCWBXVBPBPUAQF +GSOJAKKBDGPDIS +CRAONLIHLOSKGE +BMRSEYFENKXDIS +BMRSEYFENKXDIS +RPHNSADJHUEKRG +RPHNSADJHUEKRG +BVHCIBPROINFPQ +HNLDKIWEAVTCKP +BQAWIDAQBDWCGH +AKMKWHBDPUOPSK +LLENXGNWVNSBQG +QJVXKWHHAMZTBY +RIPMDUQTRRLJTE +HKIKAXXIWJHWLY +BPWYDRTYBYRFDY +TWSUSRQZTZUYSD +XCWGCTNGDUDAMO +JWOGUUIOCYMBPV +SDRRSTAVRUERNC +JQKLZAQSMGFZSI +YUTUUOJFXIMELV +GIKJADRKBZHVCY +XBEDTLDOFCRJHC +LKZDFKLGDGSGEO +LKZDFKLGDGSGEO +ADEFODYSLAAMOM +FTVKHUHJWDMWIR +FAXXHNWVMKTOFF +GGIDHIBVLYVTAU +KISJFUMXCJBLJV +NSRJSISNDPOJOP +QZUDEXAHKXCIDG +UFDJVOQZZQZYJG +FCWYNTDTQPCVPG +WMBWREPUVVBILR +NPDSHTNEKLQQIJ +UEXPKLJRGIWQBF +DSXFHNSGLYXPNG +DHVXMTMJTVCPBB +HZUURLOSYMEMET +KUASSSAVQTUJGE +CYAWKJKAMCXLET +YTEWAPMLXIWBPY +KPLBOWKEQXYXSD +DQOOFQPFNNGTHL +OMQADRGFMLGFJF +RTCISXKUWWQSRF +RFYNAVYPYXLVOM +GTNPVPDWWGQDMU +BGPMMCPSTAYIEL +BFJZLVDYMQIIMI +ROYIOVVKJBERGN +ZPUOWQZPFGUNIS +HHXMOTDTSDYYEI +VRCXJKSBSNVDFC +UGWAFWFSLCHCJD +LGOQXEQWOCSLEC +XGPBRZDOJDLKOT +QUSMURJIBTWAOP +QUSMURJIBTWAOP +QUSMURJIBTWAOP +JXJRJDNSPWNZOK +VUXVICJLLYFORC +YRAQEMCYCSSHJG +HLPXMGYELYMAQM +MYFFDMMUGIQJQM +GXLQUHPXGLZNGE +HRLFUIXSXUASEX +ZLACPIJRVKLLJM +YGXBITSXQZFVOX +QMPHZIPNNJOWQI +FTFZXPBVBBJTHV +LIJMMUDJSMCVDJ +ZOEFIRUNMVHSJA +ZGHAVKULRAPSKM +KZPINWADEGOBQG +KZPINWADEGOBQG +QDWGYCCSJIYJAE +YDHSGSSEZHFAJJ +UQKKDJWFQBNZBJ +QPQHCRKTYXPSQG +RWMOXJYSVNRRGE +YWEIWRDWTNXMJK +YWEIWRDWTNXMJK +CXFDTBRNJQYDLK +LZXXRASHAINSDN +CRSFLLTWRCYNNX +MUPQSGHACLOUTE +XCYFMYRAJQOAQT +CJGRGYBLAHPYOM +NLBYRERHXBTBBR +CDZUQIFWCXAIFB +ZGNRVILZVRTZON +LKYNAQSYQLFTCM +RLGRBYHBNWLGER +HKXQUNNSKMWIKJ +MGJLSBDCWOSMHL +HRLFUIXSXUASEX +LFXMHSJWYXKODM +ZDJWTWORZULMCQ +SCZSILIHRULXII +HGXBRUKMWQGOIE +BHHRYVYZZQIPGU +VATOSFCFMOPAHX +FCYKAQOGGFGCMD +IBDPEULNUMJDEE +RNWHJFUXZQBBLK +JMBINOWGIHWPJI +XFLTYUCKJRFDOU +NSFCLBVWJYYZMR +NLZZWSRYPUGPEO +SPWHQAUMLDQOFU +SPWHQAUMLDQOFU +OKBWVJGQTFYYQA +PIXYPRXKMCTYQV +ZSTCCLUBWBHJMP +OMIHCBSQSYMFDP +LYUZYPKZQDYMEE +AQBZCCQCDWNNJQ +WCMUUYZSUQJWRX +IAFDNCWNSBMBIV +AVBLSPPEZPLINV +HTPFCQBRMHUAEU +JDRLMOFOBWKOPI +PKLGRWSJBLGIBF +ZIUSSTSXXLLKKK +LYTOSEBVFHNSFK +VJAXSGXKVCCJNY +VJAXSGXKVCCJNY +PSFMBXYUQFAGAM +QQDLPJHEFJKVHT +VZXPWVDKXCYHSI +DKEANOQWICTXTP +DKEANOQWICTXTP +RWEVZSYWIIZZFV +YQORPGJDFBRUFL +RPWASDJXFDDBFQ +RPWASDJXFDDBFQ +RPMNUQRUHXIGHK +OMQVQJDDMZUVNL +YPZBTERWDWUANF +ZQFOLQKZDARIIB +OCPITUSJSRGORS +OCPITUSJSRGORS +TURXCFUGBPBPRS +CPKXIKIVLSMABL +KCIQZCNOUZCRGH +MGEVYVDQMTWJNV +SIVAITYPYQQYAP +WKIHBIBUCQPPBY +PEYUIKBAABKQKQ +HQKAYCHMYMSSEQ +MACFXELYCBWKGT +MACFXELYCBWKGT +VIORQNDMAWQQCV +FEOYRZYUONWQSO +OOGZWXIAHJKVAH +UZYZCCWBBBCDAD +GQNUDXCKVPLQBI +WHICJDPSYBJDEN +SFLVCICJLIKJKU +RSNBAEGFNZIXPM +OXQSHEREUUUCEE +APAWOEBSLLGWDF +CJBZJZGULKATPY +DBPWCIPDCMVUFT +XQAQIFDOJYUBEV +FVQOMEDMFUMIMO +LWOXGQKLDYQLMZ +WUGDTLGNIVJAFV +WUGDTLGNIVJAFV +AWCDBKHWVKLXEE +BBRMJCAPNGJKEM +LKPQNZRGGNOPPU +GMMHQFAVUZIMEL +MMPBHSBVPREJQC +NOFGKTVEZONBCG +WBAVLTNIRYDCPM +MHWAHKIDOYBXCN +KHWKLNXMSVVKCH +XSUATNGSAZMWRU +XSUATNGSAZMWRU +GVRIYIMNJGULCZ +GVBNSPFBYXGREE +PUCLKHYBLVYMRK +PVSIWGFKCZWYGE +VWZAZEGRFSUWHJ +LHVARDGCCWIXJA +JUXUXBIHGDQKND +DZRVGBRAMLSZDQ +ZVUYNAQSHSSBDQ +YTDNHMHONBWCBV +INBMTJJPUABOQJ +QBKMGAJNGCTGFA +IPQVTOJGNYVQEO +GZVIQGVWSNEONZ +QRWNMJBTANFMHA +IVRQZYXJBVMHCW +IWINXMWZYVGFKC +UEYWXBQABUNMMN +IWGKJEFGMDTVIL +RGTONEMDTVVDMY +RGTONEMDTVVDMY +IJRBORPEVKCEQD +KGGUASRIGLRPAX +KGGUASRIGLRPAX +VNADFOGBKXRWGC +FTPHYXGWMIZVMP +XIEXZMWPZITEKI +YDDGKXBLOXEEMN +HUCNZRPYZDCCEF +OVMFOVNOXASTPA +GTLYLWQDKQVONL +PBKUOHTZGOWWBK +HBCGNAJUSBIBGA +CEJSYHIZUAMEQV +YYIPXGSVFFKMDD +DBPWCIPDCMVUFT +JLSIEPYLSSNFSK +GBRZTUJCDFSIHM +IZCOBQSZMYGEDP +IKMYHRZEPWIULH +XJOBKBUGVMLSEJ +VTTCGBFKWPZDFS +XCRBJSLPMIXFOO +QFTPTUOKFIIFJH +YMFLMFCNFNRUFO +YNEMPXKRLPZFAX +PKPHZFVECLENRP +AEXJMQYVIPHZDJ +IXDHJNNHLVGCLC +VXNMHZVTDWLWRX +YFPYXTNSQOUHPS +XOLNJKHCNSNACU +QUVRUINWOFZNJL +AVFIYMSJDDGDBQ +YGVDLUVQOOJTBM +QVUUGDKCVIHHKR +ROWCOMZNXJCEGO +MPXXSICHRNCHHK +PEUUVVGQIVMSAW +YPFUHFNAEWURDN +SOOVMLNBEBDSMV +MKLSDOYALQNPMS +YSINCDVRUMTOPK +NFUHNVZGHNEYRG +NFUHNVZGHNEYRG +NXVJTGLCCSFGAT +PQQRNPDHSJDAGV +YCUWMGPYKGLQQF +ZTDRTMVBTLHQII +FCJIWTZAADYCGI +RATQVALKDAUZBW +AHYOMNWKYGMYMB +BUBVKRMIMSPLND +QHZLMUACJMDIAE +OMXHMQVMAFLCRB +HHKGQYGYEDKXNE +ASKKBGQVSVTIAW +LETBAZLAGJPEIM +IGQSSJMCEJLHAO +HHHJANBAZIPBMQ +IBSNNVHJJNLMJW +OPKOYMHTMXJHRG +UXJMURXRQMFKJC +BSGBVUOHKNZIES +WROHFEWGWYQNPP +WUGDNVYHMVWTAP +GACFDZLPFMYBKT +KZJNKSIORXDWKH +FQWZGEBZILOCET +ISQUNAAALVXWGI +BOZILQFLQYBIIY +KBJKWXDTUOJWAI +GXBAKQFLYWSOJH +RSFFUWNYMOEBFP +DUNFAZHEVVYXGG +RIFCMNAQMNUNKD +RVMPLOSJMIQORE +YWGAKIGNXGAAQR +QDFJNOVWEADTGJ +DNTCXDVSHGJREC +GQSKRVQYDWZFKS +OAWJOZQLMVETKE +WYZSLJFHERMCAN +WYZSLJFHERMCAN +GPFVBJYXFRIOFB +ITDOFWOJEDZPCF +ZPKOPBUGDKNHJM +ZPKOPBUGDKNHJM +PVCLMZBWMWIHKX +LZNVQLZWBFBDBG +IIIOQVDDEWZCEQ +FZBGZDZLYSLJFE +FZBGZDZLYSLJFE +KPJIGLLMDBHXEB +SCJIZBIZKYTHRQ +SCJIZBIZKYTHRQ +FEGXTMHRTZJSIG +JSQKCXPOJUGOCX +PCASZNXKLGTEGB +SVUDFAVZLCGQAU +ZFHBPZHOLGMDMW +IBMKFRJIFFORNR +HSTZMXCBWJGKHG +JOLLIDAUJSAZHE +OWPWFVVPBYFKBG +YGBHBIXCSYCCOR +BVEVSYQMQABMQM +GYBMMZYCUFIKJQ +HYMAKZYMIDUXML +IUXOFSAPFXGQID +CSVNMGCNZRUZHN +SLWJVQQNDGLXTK +UZIOUZHBUYLDHW +PJDABWGWSDUIAM +AWDKYYYAAQQLEF +ZNYZPDGJGQZDPM +OHMWGMHIZWOKHV +OHMWGMHIZWOKHV +BOZGEGDMHAOPIQ +FNVXTGOURNXUCQ +FUUXIPLOLSVADM +NOCZJUUWDACQEY +NOCZJUUWDACQEY +FCLYQYOJLQDQNA +YORZZUYHPOREJM +IHDCTQODJUDCDH +IHDCTQODJUDCDH +ZMIQCOSRPMWYLS +ZMIQCOSRPMWYLS +ZMIQCOSRPMWYLS +QVQZNEIQAZVOQQ +QVQZNEIQAZVOQQ +GUROHWQMGNHVRS +GUROHWQMGNHVRS +JEKOGXYPZLTPCU +JEKOGXYPZLTPCU +PHHROXLDZHUIGO +GWTQDEWQHCDBEI +JORLYMGTWNNOMY +JORLYMGTWNNOMY +QQRZPCAYYGRGJD +WGMNBGJQXOIVGA +NNCVVPLZMBGDIK +HOBUOCPDAWXJKO +XWOZTQQJYJMHSX +QKRNXYDUTFTSBG +AEYUKLGVHVHAGC +AEYUKLGVHVHAGC +ZTMPDTJBTNGZJH +JXSVIVRDWWRQRT +MIJYXULNPSFWEK +RXRSNDCGNOOFLH +YAJZEISZRAKFLZ +YAJZEISZRAKFLZ +JGHUOJAZXGSFRI +JGHUOJAZXGSFRI +XYLREKXEZFHHSV +BYCOQXVBFQHWPL +VUGMGEQWBOCMAV +RWXIFXNRCLMQCD +FUSHLLXGTXLRMJ +MVTLXFDHKDVAIC +ZCBRYYRPNSHPER +MQYXUWHLBZFQQO +DYNISIGUMYFVJW +FZALQGCQQJLGKE +XYPJAWWDSQFSQA +FIADIPXEFYWJQV +DBRXOUCRJQVYJQ +VZJHQHUOVIDRCF +VXHVLJHZFYIFJE +GVUHIWDAWNDBKR +BFCZPWYLRHFBNO +CBJQFIAJZLMMPW +KWJHGUHLTYVPID +GVRNTWSGBWPJGS +LQUPEGJECBPTCO +CNEAFYADRZPYEP +ILMVSYUTBLQVNQ +BTPYUWOBZFGKAI +SRUILBLGVMJFPG +FILAAKXJIYRSAW +BUKBJIBZOCTYLQ +LLEMMFPELBNINR +FHIREUBIEIPPMC +AKNILCMFRRDTEY +CUANCTHYEDWUMU +LBVPDFGFLMFDPI +ADDLXGZBTXNVDS +LSGOTAXPWMCUCK +SLSYEBAZQRZQID +WVPPLOSRTXOZAP +JFQBNOIJWROZGE +KFNWMXLJLRPJCL +MVWXLRYZCZSBKW +UZQBOFAUUTZOQE +XKJPVKHJPNQLKG +WQJXWXRSOBXAGZ +ITXARCZXQRQZRW +PEFFBGFCZXFQSX +LZGVQJDYLAUCGI +JIDXOGPQCVBGSC +JGWDBQRLOBLTHU +GKQGIQVSMCHAFX +PNZRSLXZPKJLEN +IBQVOWQTGYYRJP +MQVLYVXFAYNRER +CHSDMOZSQFIUGK +OFPMGMVAOWDSRN +OFPMGMVAOWDSRN +KDNJTHIKZATBIB +TUKYTUMQZQFKNX +TUKYTUMQZQFKNX +VHNBSWKVDGABEV +WBEFPLHFVLPKHQ +WBEFPLHFVLPKHQ +BZNOZGOVIXEHMX +CPWPNTRWIIAFEG +APQFDHZCDLNMLA +CUOZRGBQTOSWAY +CUOZRGBQTOSWAY +IFIQVSCCFRXSJV +HOCKGUMMVOPFFC +OXKMZIABKYHLAR +YINNEDVQUNYQEZ +AEBORMNUOJEQOL +DJDISCKFJXDADJ +DJDISCKFJXDADJ +OZDABLANSWPSGY +RFWGABANNQMHMZ +LIVNOUBJFOXZOR +BRVXVMOWTHQKHC +BRVXVMOWTHQKHC +ACGHJVZDNQZJOV +ALFUZUYJAXAEKE +VGYPZLGWVQQOST +MIQMVCTWXSPFSC +XQCGNURMLWFQJR +IRPFOXRBPHCCTG +LOOFGUAWTZPQEG +AAIIJIOWYALNCC +MLWSQMMSROWDTI +COBSHSDADSYWJI +QBSZVMLDNVHDKB +QBSZVMLDNVHDKB +JHAXQRDTTACRKJ +BCXXBFMWUYYHIF +QBOFNNDGXMMAOI +YRQNFHSTTZXQBU +GOHHRVCULPSXEU +JDBBFQGXBSMMHP +KKSYAZCUYVRKML +BZXXSUZFEIFGEX +GZNCPAASLBFTKY +CFJLERBDXYGARW +RNUHPRWYDXEBOM +WDMUSPSWMAOXCK +REBRERQNUHGTMS +HUIHUOGNNSDDIV +KQBFNIVRWYGXRN +PRWWZXHOHQRKDQ +SSYUWECTPJGUGD +GIGLNPLPIFRSFH +FCHJZJFIDNMNBS +NJEWNTGSXKRWKA +XRIRDTGIFOWQDB +HPDJFHJDZYIBCP +CIGQQQTZOIDQQR +SGKBPTZDIUXCMW +RMSKZOXJAHOIER +PLGNVFSTPJUFKJ +MXJRGHQPKCPBAN +AVZATKWNGXCSDN +HYLKKEXCEIKCIN +ZJCOLWRTVHBIBE +LJGOHKSMJNTMAH +NGNMVXFBFBZQAG +NVKSXODNGLJJHQ +ALPIUWBZQOROIJ +QATFYHWTNMSERU +QATFYHWTNMSERU +OJAGBDHRHPCDLN +OJAGBDHRHPCDLN +LMODNMXJBXUOQF +FLROYCKIIJCTDY +WWVATHTYIDDAQF +KFKSQOIZZRZEFC +GLACGTLACKLUJX +SIOXYUXOHTZOOM +QIOMMMCQFIBVKA +SIMPNXWTAVEOTO +WJPRKOJNQIZCGY +WJPRKOJNQIZCGY +VUEPOIYXKZTLMD +PUQSUZTXKPLAPR +XMJAJFVLHDIEHF +NUXKLJINNAOFAH +UFEHYRPBLFGEJW +NRNSOEIINXSQRA +RROGHRHLBLVQSG +IZODPOCIKVLNIL +FKBUODICGDOIGB +YGCYRQKJYWQXHG +YURJSTAIMNSZAE +ARNBRPDSKOETGW +QPBNFQKLPIXNFL +FFXYBQSGDXRLHS +IUXQFJTWMSIYNY +QYTFUUGRKFACBM +PCHWYSGBVKSPAM +IBJRJSQUSVUUDO +JBFBTBFJYNNYPW +VMCFTVWDHVWSOB +AVJNWIDNAJCPRK +ULZFTGWWPHYLGI +LKOARHYUMOKAPJ +QCZUWKYBDIHUEP +RLTDMRMWVUCOAI +OJPOTPLCXUWMGI +JRWJBFDOAUKNJA +XJNQXTISSHEQKD +FPUXKXIZEIDQKW +RNZIQNGNLJSLHV +CBJNLOVRAFQEQH +CBJNLOVRAFQEQH +KVRQGMOSZKPBNS +CMUOOPXNBJLJQK +JJGYRVZPUJUFTR +DFGYGTWTXGTQIC +NHAQNKDEUQPSIX +IQVNREJWRXOHEO +LZMRDTLRSDRUSU +QJALTHDWQWOLLT +RXWXPKXKJZHTEJ +RXWXPKXKJZHTEJ +SUAPQGLGNKUSLY +MTZOEZDNESUECO +IAYQFYAFBVYKJZ +CHQMIQBQLGDCJJ +AKFIXMYXISUTAF +AKFIXMYXISUTAF +RFFYIBOJHUSIGD +HRDMCVCODUFPBQ +FIOZUJXSEZUYCS +FLSPBPZSXFDRFE +WTAMGABZURYMPQ +AKARZXADDNXORH +DFGOIVFBKDWNBI +PUFYSEQCTZERQM +TVDMUSYVWJLIDK +ZAXZBJSXSOISTF +LABWQTNVUKYYIP +MLKQAGPAYHTNQQ +MLKQAGPAYHTNQQ +FXOBIDROVMXPBW +PRXFPPAVWQDTHT +PRXFPPAVWQDTHT +BHSDLJXQKBYFNH +GLNIOASGXMEGTM +QUCGBWQRLWOVBR +NOFXXAHHOJWYAL +AFYIWKNGSIYXCQ +RKAXEWSQYMGBAP +QMSHPPRVWMLFFL +LKKDASYGWYYFIK +IXQJBPRUTQTCMW +STOYMKJWHHPSDH +ZLOTZUGMLIVSJQ +PWXPWSCNXVCOCA +ORUMCUXABQCFEG +JYFOSWJYZIVJPO +ZPEFYJBGAZLAKK +LIGLPZJMSAQJSF +HRYIDVZLDQBLFF +XJMYUPJDAFKICJ +JYVLOGILHBWLAE +JYVLOGILHBWLAE +HUZKUSWQRONLOJ +UEAATLOMPYZOFF +PNKLMTPXERFKEN +HAMGMFWBTYYRFD +VOXQNTWMJFAWIA +RLGYLKXDNQBDCU +RLGYLKXDNQBDCU +NZNHJGNBLPBNLU +NZNHJGNBLPBNLU +QOFWRHWADNWKSU +PCZOHLXUXFIOCF +SOLWETWNPWWTPC +FJMAAWBVQJUJKZ +KEDZPHBUEGYHGC +YNKJSQIXVXWFBK +GHRNLKSWTKHISE +RKSBJQZDPAGEQW +GVRDYBOOMKTYKH +JDNUVLAJLPVYNP +VLHQGQCFFBCKMV +VLHQGQCFFBCKMV +UTPBMRNHPNUBLT +VAZXQMYIQNKBRG +MVZQKKYLZHTDHU +SKOYDNZXMHBVBB +SKOYDNZXMHBVBB +QMWJARHMJRTJMQ +XTDOKCBBQODVJW +XTDOKCBBQODVJW +DGDWCRWJRNMRKX +DGDWCRWJRNMRKX +BRXNFHGWRDJMSF +NZNSTOHSZZLSNP +QNFWPNYXMSTZBB +JNZBACSLMIGXCA +MFIJTASICGGFJA +AUVKOEQGZIDTGI +RUMMZUFGTMKLMC +DOFMBNVUGRDDTK +CZDNLUMNELLDDD +PBILEZBWIBJOSA +AKTRFOPOAKDICT +FTAAFHHJONDBNZ +SFNQVDIXXKZSCB +REUGOQDHLPXDSB +LYENYJFQVIXEAI +XWYDFNHNSVTJFP +XWYDFNHNSVTJFP +WKUOPGZYLRFCHJ +GODSXGJMZIRXOG +LTVCFOSNIVVOBK +XZYBSTWAAUDUQG +QPVGQZZKAUMQSM +JACNBJFTXZEQNC +FQWZUBQXMVKRSM +SZSNPNCTSHASFJ +YSOBQIMODQOGKQ +YSOBQIMODQOGKQ +ZQHJXKYYELWEOK +GQLQVPZSTWXDBQ +NAHTXVIXCMUDLF +YRARGBWFOYODHQ +XWKYXEIGWQYOCY +OXHVZEZYYQQCRJ +KHLABRVSJLTKHQ +DRZYJIXQEOTQDA +MZHPYFUVDWYNQP +MZHPYFUVDWYNQP +DORFFLQTHPKFDY +KJIWCKSQHHNTTL +NVTNXPADRDASMP +GBKBPIXSSQJOPJ +NXCYBYJXCJWMRY +QKFYQBBBSKOMPQ +ZBLWKSUMHLVXAM +OSHZDTNWJYPSSP +OSHZDTNWJYPSSP +JPYYWXPAHJBKJX +WFMPZQDIRPRCNA +AAHSTEUFCXJGIV +QFWCWMZSCXWBAK +KTYZKXFERQUCPX +BKYJGKRXUHPPLR +HIVVBTLNCFFLPO +BKISVXZMCJBOKR +XKQFWJXMPAGPGP +VZSGMNVXQXYFPI +MPUKHERSKPLKHP +ZHECNBLIOXZXBL +ATNAJMVRCNQHAG +CHRIGVPNNGMWMG +ATAIRWBABKGUFL +ATAIRWBABKGUFL +CBJRVSWMDLZAQD +HVBQZYOWNDKXFI +ALDOLERJIYTYDY +GGYFTLUVQMVCMN +GFYNKSLVMQVEBT +UKJMISFXPQGTPF +BVALVRBXQYLPOW +JUTSMXHGEKYOLZ +HIENDSLJNWIKCF +KHQNSSJNIXVKMK +PWAOOJDMFUQOKB +FNIRVWPHRMMRQI +XFPSRAYOBUHKRV +QOPSZFXPZWQLOG +CAFTUQNGDROXEZ +HUSISCNTLUEZCN +HUSISCNTLUEZCN +HPLALXILNGTIHC +PHKSUFCCGLWIMC +MQLSOVRLZHTATK +AZKQDXZMKREFDY +CJHYKSSBQRABTM +FLZGWKBABNBFOA +URTXXFGOVQACIC +OXNYNKGAOAFFBD +ZBHRERABGSTQPS +VVWSVSOPOPDXMM +HITLMPHPGUZLGI +WEWBWVMTOYUPHH +DQTBTFHCLVMGBP +DQTBTFHCLVMGBP +RLCWEUBIDIWNEA +WTDIRAZPDUAJEB +VHPDNWQKZMURPV +JZWZFNOVWZEQMF +VPRPYNVJJXOFKZ +GJZJZRWFRZFTEE +XDHNQDDQEHDUTM +AEGZYCGXUREGSM +AVIRMQMUBGNCKS +QTVCLHJYLZANIP +QTVCLHJYLZANIP +GVQACOLUOBLBLO +KBTSKABIWIUJAS +KBTSKABIWIUJAS +YOELDOOOBJSHSZ +QJVVGCSWIOLQDG +JLMGCBFIPZDHLZ +JLMGCBFIPZDHLZ +ALJXWCROGAMOBL +APZDDWSEXQOLKA +APZDDWSEXQOLKA +HDDNZVWBRRAOGK +KHQMXKRETWUVJU +RTQZACYXEASSEF +XMIDHJQDTWKJIZ +XEQHVCXFKPCQNM +AZKQDXZMKREFDY +YNPOIPFNQJKGQJ +QUOZWMJFTQUXON +HXJGKPQYSSUARF +BIHIEAXOTSXYAE +RJFVWGBZBUWHAM +STSLPRRNSYCFTQ +QVYMNCVNZVHQEC +ARPKCZZZMDEOIF +ABVDJKDAAWCYKH +MTOYSSPTNNWDSB +QTWFZVHPPOTAGN +DFXWNJDFYDFQCW +CPHPAWJXZHHPEN +SZLZWPPUNLXJEA +VQJMXGXETFHHGG +LIIOJBIJVPGVGO +STKUCSFEBXPTAY +YCKKAXDZPAQYOF +TYXFVKGQQWDJKA +XPUOZJJNPJXFTD +YXSQSVWHKZZWDD +MLCMEHUPTMULKN +NFINSJKQOBJWEB +ZPEADZHVGOCGKH +HMSYAPGFKGSXAJ +CDCIKAPGWWMGGE +OEWYXUOBTOXNMX +CMKFQVZJOWHHDV +RPJBXUNEXVNBIF +NUBAAWQBTGSVGH +NIYWWSSZSAHRIW +NIYWWSSZSAHRIW +QIXOVYGMZDYDIN +WCVUIHQUPRXYKT +CAFTUQNGDROXEZ +WZYGIALDVOKLLL +UUZWMJQAEYBHAO +ROWKODQLOIEBHL +LARPFJIXBULVPK +FVWJYYTZTCVBKE +PMMWVYKBDULGDG +VJLVPUFVTPJHDI +PDUNPLZHIQQDAD +WYZMMUAUJZZQCB +WYZMMUAUJZZQCB +CUAPOUHDJKWLOB +QNQBPPQLRODXET +QNQBPPQLRODXET +AFHCRQREQZIDSI +WYQVAPGDARQUBT +WQMBCGHXXVLQTE +SCUSKAVTYFDOEU +CLQAMCIMWDLXGK +BPYRVOCFRMKMIP +BRBRVKOYZAMSBL +VFYACENSDOLJGQ +UPJBUABBBFMLGN +GCIKKGSNXSCKCP +LEXLFIULVWKBPT +VUKHFRDPHIDEAW +BBUQNXDJRVCZTI +WTCVROXOIQEIRC +WTCVROXOIQEIRC +UWKRNCNWJVCHGZ +YLGANLNQTUGMCH +WQQJTVODGXZMHF +JEQWQKAKFXGXKA +UTGBBPSEQPITLF +YSNRSVKJRYQIIA +ALSZHZPQTCVXIR +DJSLHAARKMNBDB +PUIAUUSJWDDCLR +WXCWCGGJYLUDJP +WLZSOFWXYPEZCP +MGHSCXCFVZJHPT +WMABCPOXSNGIJO +NDUFGVRVJKHNKE +RNYROHPATJSIAO +RWCCSDWQXFKGJW +RWCCSDWQXFKGJW +SSUMVVHRTRQNRG +SSUMVVHRTRQNRG +ZYZHMHXSPPAVCD +BARAUATXLYPTGX +LPLWWIHUJXWQSS +YVYNMIFMUKDFEC +OLFRCQFNQXYDGW +YYLAARMDRFESOL +YYLAARMDRFESOL +JCNYBRAUXUDAEQ +ZRTBPOAMWLLGTO +OJDSCNUKKOKOQJ +AONLJCCUYGGOSW +AHTRGGWSBFOEEG +FSLDBYNJYAUPDI +WVFNARDJAJTRAI +KNDPLJZJPQWOMQ +QDEYKGKBMCIYCT +NHOIBRJOQAYBJT +QKEJRKXVLGOJMB +XUCIJNAGGSZNQT +YOSRLTNUOCHBEA +HZGGHVGIXDRDDH +IDUNGWJLADYQNW +RHOKVADXUJGRSQ +LVFCLUMIBMHAFL +MDZKJHQSJHYOHJ +YGSIRXHFAUFUEJ +UOWGLBYIKHMCIS +RTFKMVMUZLBFEW +GZSQKOFXMZDKPV +DPFSNFFFCPHBOW +LUNCZNVVYHFMOQ +NTEIYTQTTHYBTI +SZNYTCZAXYAIIP +GFFOBQNFESRPJR +VNQRSFQBEKLVHZ +BPSJMBKZSUTYNF +YOBMRYYTHXIXSD +TZPGGHIYBMWPBI +MUYUFHKTKLPWIW +UTAIBCIOWTVUDJ +KANZNGGFUBNDNY +JZEZLAAJRKPOFM +JECOCDKQCZSANH +XBTCTDQFKYYTLT +GNBHVMBELHWUIF +WBXFRPMHPXIXQL +OKNPZRJNRSGKME +JAGNFEYYASZAOT +SDMFWFQLYZEILE +YVOIYLIDBGUQGX +RYVGCUJETSKZDU +COUZJTKJINDPEN +PQYVXRPPFDHTSV +YJXDGWUNRYLINJ +YJXDGWUNRYLINJ +KYVUMEGNMQDSHO +ZROMRLOBUYCHGL +NFZYDZXHKFHPGA +ZZSVMUQQFFDKCD +MAUAGULXOHJIER +YUXPMUIKXCUNQY +IBXDTZNDJHAVNK +LZXXRASHAINSDN +JNKDXWGGWNLKOD +JNKDXWGGWNLKOD +GWEGFCVAOPNYPT +NADMMFBMXKYHID +KRODDZHZLZSLCJ +DRWAFTJWJQAXRC +FCNYTFYALYEECS +UQUYXFBISSCISA +IAWGZKRQDHPFCZ +BWAZUXQZSXFTJK +QYCVLCCQAORDAF +ZPHQZULZLQMWGY +ZPHQZULZLQMWGY +WIKNHJPJHDNAME +ARHZXCIVYQVVOK +VQHYUBJDKHMCEY +QIDMCIFFMHMTBT +ZMZWVJLMOBCSEP +DFQMKYUSAALDDY +DVWKMCPPEMUHBE +CWDBCXIAEGDANA +SEOZHEFAHJQWFY +BOJKULTULYSRAS +MMQUESDXUKYFEN +WBDMFFSFFQSHFV +ZQIOVWYOYSNXID +RLAUJYFETVMGAO +OKUGUNDXBGUFPA +HHSKNLJWHGXWPK +NJMQSVWMCODQIP +IBFYXTRXDNAPMM +AWFZJSUJFSUBQU +UTBCORIJXVSSBE +YPQNDHHCUQGPFN +DAELTTGCCPRYTP +PGZQNTPBISAIJS +SEEGHKWOBVVBTQ +SEEGHKWOBVVBTQ +SYFJYRUTNACAQV +DBUOUVZMYWYRRI +NZESEVTYUVXOTC +VWHCJIZYMBSOMV +PRZVXHGUJJPSME +WCMJLEULXWUCRF +YJSHRIGISKAHBT +RSKTWDAINBIMPD +UKSHFSUBKYPKMO +LIHVMLWWVHJRMA +BXFOFFBJRFZBQZ +SGHWOXDXPYEOMN +HUZKUSWQRONLOJ +XTSYDGXYRUWSFF +SKCDPGIEMVQDCR +MQGBHJVUCRXIRM +GKMFOEIZCLMZDE +DJBWDHVUJCXYBH +CDTIMEVVBBGLIF +PXBJHMFLTVPWQM +QFYFLJZBZITPGX +NNOMPFCNQCRAIO +KCPUSSJDCHTZSH +FSLWKIHHQUNBQK +LQZXAHKUYJVAAR +MRTYYJWDYPABSE +OMPFZUXZCIVLSI +CFTZBGSPPBNRNF +CGZNTHDUAFIKOH +JYQIWENZJDPRSV +YSXFDQZXVFAMSB +UIEGOKVPCRANSU +MWLKXILGJPSPKZ +CAMYXILYLXYDFE +CAMYXILYLXYDFE +LIDPBIULZNRIJE +VDNBKSIMLSGEHD +XGODCDTVQAHYAH +SWNBFQKIMCBNRL +TWHBYJSVDCWICV +GXQZOQHVBGNFHI +AQBQBBLJTDSVLC +QYINOGPWFQBOJX +BTGVTHAIJREEMO +WTVZRLMVNARECX +BEHHXVQQPLISNN +LWORTIDRRYUBBP +KNHGVVIGMKZOJB +KNHGVVIGMKZOJB +OZFIJBRLEXJLPY +QVSFEOQJKPOOHP +BCCAHEPMXHPBGZ +GQDFYCPPHMEHJL +PKKZJBBNWQFEBZ +IMVOEOLJLDDJRP +XWGNIHFUPLLNBR +RBEATXBLUJTDQZ +HHDWDLBSGSYIQQ +MLRIJUWUQTVDQE +IVUFRBWVXKXZMM +ZRGXCWYRIBRSQA +KMQUGCQVIDIVLT +QIYRQEHCCPTEPY +NVTNFOILVVPXHM +LVOGPECZHVNNHD +LVOGPECZHVNNHD +CTNBJOXYBJWTBJ +XLGNZQXMDVSKOV +UVBLDLGZDSGCSN +MJNAZPNWAXZOTC +WBCMGDNFDRNGGZ +QHMVDJGMBDTIEY +CNNXMGXBAZQZDE +BGABBPGRYJSRGX +SJRACCTZSAUMGO +ARNXUXYPWUWNPP +JBGBTPGEYVDMRV +JBGBTPGEYVDMRV +MTYBVLBBQPTSAU +MTYBVLBBQPTSAU +NRQCIBSGSINRCF +INOKSQLHQGQUNF +WGFGSGMOAHUFDZ +UJFQJDAESQJXTG +HBAVPWHKFSXASX +DZRVGBRAMLSZDQ +CAKZQSFFOAEEET +RCOCBDNPQGVEDL +UQCSETXJXJTMKO +SFQLDKSMEHBZRN +SFQLDKSMEHBZRN +MUVPZRLZLOTAOL +KWXCZSMMAKGXBP +KWXCZSMMAKGXBP +VHUNCYDAXJGCLO +BOHOBTRHAFBJOW +HHGREWJPFBZWTH +DNABNTQMDXKPON +DNABNTQMDXKPON +XRCPVTIMWPBGBZ +MRLXXQBBRNRWDA +CSYVMZMEBKUDRQ +VNBOCIKTDWMWMX +RQBYQAQHXGPEBG +RQBYQAQHXGPEBG +SMUMBCREXHTKFN +MUEUOXPTUMGVJS +OZIPFYKAIOOVEJ +HVNSMSNIQCASPS +XHFQOXMGWOLQDQ +AWTYKUNFPBFFHC +QNBLVYVBWDIWDM +ZWIVVTOKXTZAOT +LVPZJIGICMPWFH +ADIALAZTBGIRSN +GDCHGVOUTCXBSI +QCHGZRADLYPSQB +FIDNWEXBAPOGEH +MMHTXEATDNFMMY +ZTVXBYHCHQJAQR +KTEXNACQROZXEV +IJGMVUXEZUEDJR +KQTYDMMVMJEHAN +KLDSZMWMGCWFKH +PAZOLAPVCOLMKJ +NERNKRPBSOBEHC +PMWFORPJUWEXBG +QPNFBUARICHXGG +LHNFRFAOVVPESM +OUSLYTBGQGKTME +SGAYOTORECIFCJ +MAIBJLULESJFCV +FKMMWCMRFJRLIO +ZHCNENZBEJDTHH +NQXDDVZOWBZZHN +IVYAOUHUAWZJDB +IILRAPUPZQMHJL +XFCLFWWTDWKJAH +RZQHWSDMLZHIRN +GRNFGBBADZIGAQ +WGNDRSIKIXVFLD +ZITIZEOASAIDKB +HRISLEUGLBNLRB +LRKGVEXMBFESEF +NBWDKCDWCBQNQQ +NFGQKKGYMKRYEF +PGEAMAHHYHSLDB +OSDVNRJELRKKGM +KLSSFMQBLMDBRQ +USQLNPJSDYEFJF +DHPGIJYSTONUPM +FVQYDVAAZIXQID +HNVJWWBKFFDQAA +OYTCTPHTVUEGCL +COCNEZCGILVYSK +ILAQTUNYLVMXNW +QIWWLKDHHMGRQL +ITKDSJDYFJAVTJ +FXKCXGBBUBCRPU +JVOQYXVFJHETKK +ZRZQXSGEIJXJEO +VBZYLQJSPMDPOO +OFOUJHGWJJEVMF +BSUNYCAAALCBNU +GSAWBDXYMSQMRT +LPCRSLMVMNEPGT +RYBXJAJHOPCXHS +LSWAGZSQKSSVQE +AALLCALQGXXWNA +LFDLVXYMKUPPOT +VJVGTGQETNCOEX +XQWLUDAZDUBMCD +APZBLWQCTHVAMR +CBHWSKLIWKFSRU +MLRZPRGBFKQPOT +SPPYHEUQJYKKII +ARYSAKCPIBLSDO +MIPXDZVPQOJPHM +PMTMAFAPLCGXGK +VPZCNCFYAPSUAL +COWWBPRRBQOULA +PFCVZKFJHRCLCC +FPNYZEUDIBOJQA +IXQBRUSHWUDFSM +GWQSYRUODDDVOT +CROUPKILZUPLQA +UWRDCNVTKORVMI +DUQSSEQKLJQACA +RJWJHRPNHPHBRN +KCTBPFMPBFTHKQ +RTGDGVVYWQUBLM +UHBMKIHOBUKYRH +SXGSYHDLSPXCMU +SZIDPCXTWHHMAY +WUTLOXOGFQPKLT +ZTYDPVHKIPHQAR +ZTYDPVHKIPHQAR +SKNVKBJSSSJNCI +BRXADWYLMDAXBU +NZIVCAVTGFEAJT +QIWWLKDHHMGRQL +ZBDGIMZKOJALMU +JHTCFCGNHFWDBQ +OSICWVVWEXKSBD +OWPORVMZZJAHEF +SRPHMISUTWFFKJ +XJMPAUZQVRGFRE +SWJOMZRFHWDJCX +NBGQZFQREPIKMG +GKZSILIAFXNPRA +NEIIKBWBBCJSQU +ZONXEWIGPLHXNT +UGVBFHUWZNNKIK +ZOTYCHIFTCFAHC +LSADDRSUZRRBAN +BGKHCLZFGPIKKU +WLOUCHKFBGGNEB +RHSUJRQZTQNSLL +UQOQENZZLBSFKO +PUIYMUZLKQOUOZ +DZUXGQBLFALXCR +VHLKTXFWDRXILV +HZRSNVGNWUDEFX +YRRKLBAKDXSTNC +VBCVPMMZEGZULK +YNEVBPNZHBAYOA +QGLZXHRNAYXIBU +HFCYZXMHUIHAQI +RHSUJRQZTQNSLL +RHSUJRQZTQNSLL +WZJZMXBKUWKXTQ +QGHREAKMXXNCOA +RRVIAQKBTUQODI +FYZBOYWSHKHDMT +FYZBOYWSHKHDMT +FYZBOYWSHKHDMT +HAWJXYBZNNRMNO +HAWJXYBZNNRMNO +YKBZOVFACRVRJN +JXCGFZXSOMJFOA +QHMTXANCGGJZRX +GMAUQNJOSOMMHI +PUIYMUZLKQOUOZ +FYZBOYWSHKHDMT +XERJKGMBORTKEO +FYZBOYWSHKHDMT +DIRFUJHNVNOBMY +HAWJXYBZNNRMNO +XERJKGMBORTKEO +UWVQIROCRJWDKL +HOKKPVIRMVDYPB +PZBPKYOVPCNPJY +ZQEIXNIJLIKNTD +OORLZFUTLGXMEF +DQJCHOQLCLEDLL +ZJMZZNVGNSWOOM +NWUWYYSKZYIQAE +PSOVNZZNOMJUBI +FZSVSABTBYGOQH +VHLKTXFWDRXILV +LMVPQMGRYSRMIW +HZRSNVGNWUDEFX +AAEVYOVXGOFMJO +VBCVPMMZEGZULK +YXKMMRDKEKCERS +YRRKLBAKDXSTNC +UFEODZBUAFNAEU +KZAUOCCYDRDERY +QYPNKSZPJQQLRK +QGLZXHRNAYXIBU +QGHREAKMXXNCOA +QGHREAKMXXNCOA +MLKCGVHIFJBRCD +WXUZAHCNPWONDH +HEZNVIYQEUHLNI +LQDARGUHUSPFNL +RRVIAQKBTUQODI +SOUGWDPPRBKJEX +SOUGWDPPRBKJEX +CJPQIRJHIZUAQP +GMAUQNJOSOMMHI +FQKUGOMFVDPBIZ +FYZBOYWSHKHDMT +BZMIHNKNQJJVRO +FYZBOYWSHKHDMT +VGPIBGGRCVEHQZ +FBOUIAKEJMZPQG +WZJZMXBKUWKXTQ +RRZXIRBKKLTSOM +RRZXIRBKKLTSOM +PZXOQEXFMJCDPG +OGYFATSSENRIKG +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +QLFZZSKTJWDQOS +QLFZZSKTJWDQOS +CLSVJBIHYWPGQY +GEPDYQSQVLXLEU +YZBLFMPOMVTDJY +YFVOXLJXJBQDEF +YZBLFMPOMVTDJY +AZSNMRSAGSSBNP +AZSNMRSAGSSBNP +DTDSAWVUFPGDMX +XERJKGMBORTKEO +XERJKGMBORTKEO +VEENJGZXVHKXNB +MCWXGJITAZMZEV +PZBPKYOVPCNPJY +YFVOXLJXJBQDEF +ZQEIXNIJLIKNTD +PSOVNZZNOMJUBI +LESVOLZBIFDZGS +NWWZPOKUUAIXIW +NWWZPOKUUAIXIW +OORLZFUTLGXMEF +WWJZWCUNLNYYAU +OORLZFUTLGXMEF +NWWZPOKUUAIXIW +NWWZPOKUUAIXIW +FZSVSABTBYGOQH +HOKKPVIRMVDYPB +IRCMYGHHKLLGHV +HZJKXKUJVSEEFU +UFEODZBUAFNAEU +FZSVSABTBYGOQH +QYPNKSZPJQQLRK +IRCMYGHHKLLGHV +IRCMYGHHKLLGHV +XIGAUIHYSDTJHW +DSKJPMWIHSOYEA +YXKMMRDKEKCERS +LMVPQMGRYSRMIW +MLKCGVHIFJBRCD +IANUJLZYFUDJIH +SOUGWDPPRBKJEX +XIGAUIHYSDTJHW +BZMIHNKNQJJVRO +YXKMMRDKEKCERS +HJJVPARKXDDIQD +MNHVNIJQQRJYDH +LQDARGUHUSPFNL +XGWIJUOSCAQSSV +ZYHMJXZULPZUED +RRZXIRBKKLTSOM +URDNHJIVMYZFRT +ZMYFCFLJBGAQRS +LVQDKIWDGQRHTE +FQKUGOMFVDPBIZ +YKBZOVFACRVRJN +VGPIBGGRCVEHQZ +QLFZZSKTJWDQOS +QHMTXANCGGJZRX +YZBLFMPOMVTDJY +FBOUIAKEJMZPQG +QTYCMDBMOLSEAM +XERJKGMBORTKEO +UWVQIROCRJWDKL +RHSUJRQZTQNSLL +PZBPKYOVPCNPJY +ZQEIXNIJLIKNTD +ZJMZZNVGNSWOOM +IDQNBVFPZMCDDN +WYEMLYFITZORAB +PUIYMUZLKQOUOZ +QYPNKSZPJQQLRK +IBSNKSODLGJUMQ +WXUZAHCNPWONDH +HZRSNVGNWUDEFX +CJPQIRJHIZUAQP +CJPQIRJHIZUAQP +VBCVPMMZEGZULK +BZMIHNKNQJJVRO +BZMIHNKNQJJVRO +WZJZMXBKUWKXTQ +RRZXIRBKKLTSOM +ZKWQQXZUCOBISE +CLSVJBIHYWPGQY +AZSNMRSAGSSBNP +GOENIMGKWNZVDA +GOLXNESZZPUPJE +GOLXNESZZPUPJE +UFNOUKDBUJZYDE +LQDARGUHUSPFNL +FQKUGOMFVDPBIZ +VGPIBGGRCVEHQZ +FBOUIAKEJMZPQG +QTYCMDBMOLSEAM +HSMVPDGQOIQYSR +WDJGJWYTCVGGJZ +DFOPQRXSRGHTRC +JAISCAWSAHCRJE +SHYCFZYQNVKAAU +RFMSTHTUAZETPD +VJNPDLZENXBRLB +XYYHNDVKALDFHQ +UBEIMDKGOYBUKT +BPLYVSYSBPLDOA +LRYZPFWEZHSTHD +NYNQTTOUQMCOEM +GXWBCAVCOMAOHT +DQKMNCLZNGAXNX +HYVJNYYVNIYMDK +POQRWMRXUOPCLD +DRAWQKGUORNASA +LSOWKZULVQWMLY +QZGYPUQNTDWNBR +KWIGMCRWEINBIR +GNADFLWMYUNMMR +GFAZGHREJPXDMH +BHGPPCIWDXQOMA +SWYCMJAKZYLTJN +SWXTUPVWUZCBPV +RKIDALSACBQVTN +YJEMDFYSDGNQNM +VKBBGCKYUQMBMB +BXVYQJJBMVVALQ +RJCZACBLQGCNCW +SKIQVURLERJJCK +MHWLWQUZZRMNGJ +WNLRTRBMVRJNCN +ASWBNKHCZGQVJV +ARIWANIATODDMH +BIABMEZBCHDPBV +OUYCCCASQSFEME +WCNLFPKXBGWWDS +WQZGKKKJIJFFOK +LPNBCGIVZXHHHO +DSWOVBIRJNAJAF +JHJCHCSUEGPIGE +UVKZSORBKUEBAZ +CQMYCPZZIPXILQ +PVXPPJIGRGXGCY +LKDRXBCSQODPBY +UYIFTLBWAOGQBI +OIWCYIUQAVBPGV +ZZORFUFYDOWNEF +DWONJCNDULPHLV +SMEROWZSTRWXGI +SIEDNCDNGMIKST +TUYOFUHICRWDGA +FBUKMFOXMZRGRB +LKPQNZRGGNOPPU +OWRNLGZKEZSHGO +PJCNSVHWHHVSMK +GPQVVJQEBXAKBJ +IDXZDKMBEXLFMB +UNSRRHDPHVZAHH +BBYWOYAFBUOUFP +LKDRXBCSQODPBY +KGIJOOYOSFUGPC +QZAYGJVTTNCVMB +XEBKSQSGNGRGDW +JCQLYHFGKNRPGE +CYDRXTMLKJDRQH +ORJDDOBAOGKRJV +RJZVWDTYEWCUAR +HTZINLFNXLXRBC +RFVFQQWKPSOBED +DLRVVLDZNNYCBX +DLRVVLDZNNYCBX +VAWYEUIPHLMNNF +KXGVEGMKQFWNSR +PVXPPJIGRGXGCY +MIJYXULNPSFWEK +IBLKWZIFZMJLFL +PSVXZQVXSXSQRO +MWRBNPKJOOWZPW +ZTRWPEHMGCHTIT +NIQCNGHVCWTJSM +JCQLYHFGKNRPGE +PVXPPJIGRGXGCY +CVNYHSDFZXHMMJ +OSZHSESNQIMXMZ +XEYBRNLFEZDVAW +MXXWOMGUGJBKIW +UPUKKDCTWWVPCJ +SNXPWYFWAZVIAU +UBWZMPMLSDJDSU +CYDRXTMLKJDRQH +QURCVMIEKCOAJU +CQSLTKIXAJTQGA +XYYHNDVKALDFHQ +LBDXVTOFXXDOGH +QVCMHGGNRFRMAD +OGHAROSJZRTIOK +LBDXVTOFXXDOGH +UTSVPXMQSFGQTM +GKJZMAHZJGSBKD +AVEGDIAXTDVBJS +ACYNJBAUKQMZDF +WHSXTWFYRGOBGO +GPWHCUUIQMGELX +FYGDTMLNYKFZSV +IGQBPDJNUXPEMT +WVULKSPCQVQLCU +FUJLYHJROOYKRA +JCQLYHFGKNRPGE +JSFATNQSLKRBCI +IMMPMHKLUUZKAZ +NJGXXYLPDMMFJB +VXUOFDJKYGDUJI +DDKGKOOLFLYZDL +OFBHPPMPBOJXRT +KRNYOVHEKOBTEF +QADHLRWLCPCEKT +UVKZSORBKUEBAZ +PWTCCMJTPHCGMS +BOPIMTNSYWYZOC +ADFCQWZHKCXPAJ +YVGCHYVFHLTZIM +CPYJUQBXJXCLAY +JHXAZBBVQSRKJR +IOWMKBFJCNLRTC +YYWYJAHZRFSIIU +SLXKOJJOQWFEFD +WLOUCHKFBGGNEB +TVIDDXQYHWJXFK +HTJSZHKGNMXZJN +UZMAPBJVXOGOFT +ZVMLLPSSQZSZOA +PYVRVRFVLRNJLY +FBTYOQIYBULKEH +MWRBNPKJOOWZPW +OXOPDAZWPWFJEW +LNCFUHAPNTYMJB +CXQWRCVTCMQVQX +FTAGQROYQYQRHF +SECPZKHBENQXJG +YAMUFBLWGFFICM +FFYIZOYJCCKMDJ +ORJDDOBAOGKRJV +GCZRCCHPLVMMJE +WCNLFPKXBGWWDS +DANYIYRPLHHOCZ +XCTHZFGSVQBHBW +RFWGABANNQMHMZ +XCCDCYFQYUARAY +AZLASBBHHSLQDB +ZKHQWZAMYRWXGA +QZCMHXPXGACWLJ +GHCZAUBVMUEKKP +CWVRJTMFETXNAD +IKGXIBQEEMLURG +YEJYLHKQOBOSCP +HBFCVDJQUPEEIC +WVULKSPCQVQLCU +BDJRBEYXGGNYIS +SFLSHLFXELFNJZ +LSHVYAFMTMFKBA +FFYIZOYJCCKMDJ +AZKVWQKMDGGDSV +RAPBJBKXYYMYAY +KLAOKWJLUQKWIF +IDEHSDHMEMMYIR +MUFXDFWAJSPHIQ +MGJLSBDCWOSMHL +PPQRSMGDOHLTBE +BCXBIONYYJCSDF +WMDZARSFSMZOQO +HVYWMOMLDIMFJA +DUBPGEJGGVZKDD +RBEJCQPPFCKTRZ +ZZEANNAZZVVPKU +UNSRRHDPHVZAHH +WQZGKKKJIJFFOK +PROQIPRRNZUXQM +ZQBULZYTDGUSSK +TWVKGYNQQAUNRN +FEMXZDUTFRTWPE +KRNYOVHEKOBTEF +IUKXMNDGTWTNTP +SCZVLDHREVKTSH +NLUNAYAEIJYXRB +UDMBCSSLTHHNCD +ZTRWPEHMGCHTIT +DXOYQVHGIODESM +XMBSYZWANAQXEV +BMZFZTMWBCFKSS +XCTHZFGSVQBHBW +JPKNLFVGUZRHOB +HEGSGKPQLMEBJL +XNBNKCLBGTWWSD +UQZIYBXSHAGNOE +RIGGEAZDTKMXSI +BHQCQFFYRZLCQQ +NTISAKGPIGTIJJ +PESKGJQREUXSRR +YAPQBXQYLJRXSA +KLLGGGQNRTVBSU +REBBZOCNEVVAPX +WRGQSWVCFNIUNZ +RUDATBOHQWOJDD +YEJYLHKQOBOSCP +OEYIOHPDSNJKLS +HDTRYLNUVZCQOY +SEWFWJUQVJHATO +WMBWREPUVVBILR +PYVRVRFVLRNJLY +ARIWANIATODDMH +AZLASBBHHSLQDB +XGILAAMKEQUXLS +IKIIZLYTISPENI +TUYOFUHICRWDGA +JSFATNQSLKRBCI +FKWGLFXEKQAERS +SQVRNKJHWKZAKO +BIABMEZBCHDPBV +LKDRXBCSQODPBY +NNDIXBJHNLFJJP +WRGQSWVCFNIUNZ +OFIDNKMQBYGNIW +SKIQVURLERJJCK +YAPQBXQYLJRXSA +DTSWLLBBGHRXQH +CZMRCDWAGMRECN +JVSPTYZZNUXJHN +HYBRYAPKQCZIAE +IMMPMHKLUUZKAZ +FYGDTMLNYKFZSV +CBWALJHXHCJYTE +KYQZWONCHDNPDP +OTKJDMGTUTTYMP +RCMABBHQYMBYKV +OUYCCCASQSFEME +MUCMKTPAZLSKTL +VOXZDWNPVJITMN +CWVRJTMFETXNAD +APIDTRXFGYOLLH +POMQYTSPMKEQNB +HYIFFZAQXPUEAU +FBAPNCMXWMGHJY +DFMAXQKDIGCMTL +MIJYXULNPSFWEK +RYJBYRAOLAWKPE +WSXQQVWDFOHOIB +DAGPUIPHACXCSU +GRTOGORTSDXSFK +GELZMWSFAYTMRI +VSJKWCGYPAHWDS +QIZNWMMOECVGAP +CMKFQVZJOWHHDV +WJNDCLTZZJQWQW +CBBXXVJTZYTTBO +NWYINGBEUFKIIL +BLJOXWGKDCMTMU +QLSITYRYHBQHBY +KXNXUEUDDUKJMK +CMGYMWAXDJQKLJ +IFFBQMRDVLQSPU +RWIBVEZSMNDHAB +LUMKFAALHXMJDY +BLGXFZZNTVWLAY +GRTOGORTSDXSFK +QMGVPVSNSZLJIA +LYRBFJCNZKRZPT +DXTTUINJHHYHFN +DOUQNGAJTIRQPP +JSLDLCGKZDUQSH +UFUDXCDPABDFHK +SZTJJANUFCDKIH +YFIUIQDIYVFGFI +FSVJFNAIGNNGKK +TYZROVQLWOKYKF +VXKBOWDIIISNFX +UQOCJNOTNWYZQR +XBISYWZDDQVGLM +PYIOPAPWQWWKQU +SSVQZTAKKRVHAK +GQTSUQOPBVDUAA +WEUCDJCFJHYFRL +ARFHIAQFJWUCFH +PQLXHQMOHUQAKB +RTHCYVBBDHJXIQ +DFDRXSQUDNWXGK +RFDAIACWWDREDC +RFDAIACWWDREDC +WVULKSPCQVQLCU +ZQYUKJFJPJDMMR +ZQYUKJFJPJDMMR +GHCZAUBVMUEKKP +DKPMWHFRUGMUKF +SMEROWZSTRWXGI +BHTRKEVKTKCXOH +BHTRKEVKTKCXOH +WBWWGRHZICKQGZ +AWDRATDZQPNJFN +AWDRATDZQPNJFN +AWDRATDZQPNJFN +XSOLDPYUICCHJX +XSOLDPYUICCHJX +XSOLDPYUICCHJX +HMXPOCDLAFAFNT +HMXPOCDLAFAFNT +HMXPOCDLAFAFNT +QBYUNVOYXHFVKC +QBYUNVOYXHFVKC +QBYUNVOYXHFVKC +CZMRCDWAGMRECN +MVAWJSIDNICKHF +WXNXCEHXYPACJF +WXNXCEHXYPACJF +LKDRXBCSQODPBY +PVXPPJIGRGXGCY +AUTOLBMXDDTRRT +JVGVDSSUAVXRDY +SRBFZHDQGSBBOR +TYFQFVWCELRYAO +WNLRTRBMVRJNCN +FBWPWWWZWKPJFL +QBYUNVOYXHFVKC +WHBHBVVOGNECLV +WBYWAXJHAXSJNI +ZDHCZVWCTKTBRY +ZDHCZVWCTKTBRY +ZDHCZVWCTKTBRY +OMFXVFTZEKFJBZ +KXGVEGMKQFWNSR +BHQCQFFYRZLCQQ +KXGVEGMKQFWNSR +BTNMPGBKDVTSJY +DCBSHORRWZKAKO +SNDPXSYFESPGGJ +JJMDCOVWQOJGCB +KZSNJWFQEVHDMF +KVQGGLZHHFGHPU +KVQGGLZHHFGHPU +KWIUHFFTVRNATP +KWIUHFFTVRNATP +CVSVTCORWBXHQV +PMMYEEVYMWASQN +DCXYFEDJOCDNAF +JFCQEDHGNNZCLN +KTHDTJVBEPMMGL +JFCQEDHGNNZCLN +TUHVEAJXIMEOSA +UYTPUPDQBNUYGX +XOAAWQZATWQOTB +UZTFMUBKZQVKLK +MBBOMCVGYCRMEA +VEYYWZRYIYDQJM +GNMSLDIYJOSUSW +NPOAOTPXWNWTSH +PYUSHNKNPOHWEZ +HNDVDQJCIGZPNO +JXOHGGNKMLTUBP +MSWZFWKMSRAUBD +MSWZFWKMSRAUBD +POJWUDADGALRAB +OTCCIMWXFLJLIA +ODKSFYDXXFIFQN +SFLSHLFXELFNJZ +HXFOXFJUNFFYMO +MSWZFWKMSRAUBD +MSWZFWKMSRAUBD +VRYALKFFQXWPIH +LXNHXLLTXMVWPM +LXNHXLLTXMVWPM +XVOYSCVBGLVSOL +MSWZFWKMSRAUBD +MSWZFWKMSRAUBD +YJCJVMMDTBEITC +YJCJVMMDTBEITC +ZJTJUVIJVLLGSP +GUNURVWAJRRUAV +OIRDTQYFTABQOQ +RDHQFKQIGNGIED +JCMUOFQHZLPHQP +DRTQHJPVMGBUCF +GHOKWGTUZJEAQD +OLXZPDWKRNYJJZ +FCCDDURTIIUXBY +CQOVPNPJLQNMDC +QIVBCDIJIAJPQS +GFYLSDSUCHVORB +UFYKDFXCZBTLOO +IQFYYKKMVGJFEH +XGYIMTFOTBMPFP +QIVBCDIJIAJPQS +GNISQJGXJIDKDJ +MXHRCPNRJAMMIM +LDCYZAJDBXYCGN +AEMOLEFTQBMNLQ +RWSXRVCMGQZWBV +AEMOLEFTQBMNLQ +SQVRNKJHWKZAKO +SQVRNKJHWKZAKO +NMPZCCZXCOMSDQ +XHMJOUIAFHJHBW +LEVWYRKDKASIDU +DZTHIGRZJZPRDV +XUYPXLNMDZIRQH +BIRSGZKFKXLSJQ +IVOMOUWHDPKRLL +AUNGANRZJHBGPY +GHCZAUBVMUEKKP +GHCZAUBVMUEKKP +IVOMOUWHDPKRLL +GRSZFWQUAKGDAV +MLKLDGSYMHFAOC +XNSAINXGIQZQOO +ALEXXDVDDISNDU +JYGXADMDTFJGBT +RFDAIACWWDREDC +RFDAIACWWDREDC +ZJUKTBDSGOFHSH +RIGHMQLKMHLMQD +RIGHMQLKMHLMQD +RIGHMQLKMHLMQD +XOUBHVKCXRSUEN +XOUBHVKCXRSUEN +DAKYVYUAVGJDRK +DAKYVYUAVGJDRK +CGPYXOCZBMZIIR +CGPYXOCZBMZIIR +MCVJTZAENNGXTM +MCVJTZAENNGXTM +MCVJTZAENNGXTM +MCVJTZAENNGXTM +ZHCAAZIHTDCFJX +ZHCAAZIHTDCFJX +ZHCAAZIHTDCFJX +GYUVAHWOVINGNE +GYUVAHWOVINGNE +COCMFMBNEAMQMA +COCMFMBNEAMQMA +IARHCMRRHHVLLT +IARHCMRRHHVLLT +IARHCMRRHHVLLT +HMXPOCDLAFAFNT +HMXPOCDLAFAFNT +DSADZYPPAGRNLW +DSADZYPPAGRNLW +WBWWGRHZICKQGZ +QYYDXDSPYPOWRO +QYYDXDSPYPOWRO +QYYDXDSPYPOWRO +ZBAVIUQLFUYWMT +ZBAVIUQLFUYWMT +DKPMWHFRUGMUKF +CVNYHSDFZXHMMJ +OEKUSRBIIZNLHZ +OEKUSRBIIZNLHZ +OEKUSRBIIZNLHZ +XZDJHXFLHVJPMG +BBQNKFCDPDYHLC +BBQNKFCDPDYHLC +BBQNKFCDPDYHLC +JWZBXKZZDYMDCJ +JWZBXKZZDYMDCJ +IOOKJGQHLHXYEF +IOOKJGQHLHXYEF +IOOKJGQHLHXYEF +JVQJVQQIJKFTBS +JVQJVQQIJKFTBS +BASPEALOGWANGT +BASPEALOGWANGT +SUURIJQKBCDQEB +SUURIJQKBCDQEB +SUURIJQKBCDQEB +KIQFUORWRVZTHT +KIQFUORWRVZTHT +OTRAYPQDIGAWSD +OTRAYPQDIGAWSD +AUVYDCOKXDDYKR +OGSDYCPNYNWUNN +OGSDYCPNYNWUNN +LKUNZSUKADSCME +LKUNZSUKADSCME +LKUNZSUKADSCME +LKUNZSUKADSCME +SXNROIKPQUADKR +SXNROIKPQUADKR +AIHWGPJJINPTRP +AIHWGPJJINPTRP +AIHWGPJJINPTRP +WGGZRKVUOFMQHM +WGGZRKVUOFMQHM +MIHNUBCEFJLAGN +MIHNUBCEFJLAGN +BHHUWPSLCSJSDB +BHHUWPSLCSJSDB +IEOSQPSRJLFLLS +DGABKXLVXPYZII +AWINBLVINXVKTE +MEFHLJCGADQRRZ +MEFHLJCGADQRRZ +MAFJMPFLJJCSTB +MAFJMPFLJJCSTB +MAFJMPFLJJCSTB +NNEIBJNHWVDJBA +NNEIBJNHWVDJBA +NNEIBJNHWVDJBA +GIQXKAXWRLHLDD +RBLDVEUUCHVWMW +RBLDVEUUCHVWMW +IPSHXEXQGICLQN +IPSHXEXQGICLQN +IPSHXEXQGICLQN +KXGVEGMKQFWNSR +KXGVEGMKQFWNSR +KXGVEGMKQFWNSR +KXGVEGMKQFWNSR +SMEROWZSTRWXGI +QXADAGXJMAGASS +QXADAGXJMAGASS +QXADAGXJMAGASS +QXADAGXJMAGASS +WBWWGRHZICKQGZ +RUDATBOHQWOJDD +BHQCQFFYRZLCQQ +RFDAIACWWDREDC +RFDAIACWWDREDC +GDNGOAUIUTXUES +GDNGOAUIUTXUES +GDNGOAUIUTXUES +UCVGCHGIKFWAGH +BHQCQFFYRZLCQQ +RFZOTNNDUHYGNN +RFZOTNNDUHYGNN +RFZOTNNDUHYGNN +RFZOTNNDUHYGNN +CFLVYJJIZHNITM +FAYYTQMQTAKHRM +FAYYTQMQTAKHRM +FAYYTQMQTAKHRM +IRLLPYQZIDZRPZ +IRLLPYQZIDZRPZ +IRLLPYQZIDZRPZ +IRLLPYQZIDZRPZ +FAYYTQMQTAKHRM +FAYYTQMQTAKHRM +FAYYTQMQTAKHRM +XZDHXPDYLPEFQI +XZDHXPDYLPEFQI +XZDHXPDYLPEFQI +BHQCQFFYRZLCQQ +BMSROUVLRAQRBY +BMSROUVLRAQRBY +QJKBUSGUNXZSRG +OHFNMJLLKAYZIA +OHFNMJLLKAYZIA +OHFNMJLLKAYZIA +XZDHXPDYLPEFQI +XZDHXPDYLPEFQI +XZDHXPDYLPEFQI +SPOZHYGMBMRPGM +XJZGNVBLVFOSKJ +XJZGNVBLVFOSKJ +XJZGNVBLVFOSKJ +JZAIXDCPNUAWTQ +JZAIXDCPNUAWTQ +JZAIXDCPNUAWTQ +DKPMWHFRUGMUKF +YZYBIGOLMMAZFK +YZYBIGOLMMAZFK +YZYBIGOLMMAZFK +XIWMRKFKSRYSIJ +XZDHXPDYLPEFQI +XZDHXPDYLPEFQI +XZDHXPDYLPEFQI +XJZGNVBLVFOSKJ +XJZGNVBLVFOSKJ +COCMFMBNEAMQMA +COCMFMBNEAMQMA +COCMFMBNEAMQMA +IMMADCCLTPCOKH +IMMADCCLTPCOKH +XSOLDPYUICCHJX +XSOLDPYUICCHJX +XSOLDPYUICCHJX +OQIJRBFRXGIHMI +OQIJRBFRXGIHMI +OQIJRBFRXGIHMI +HAYYIOAHIPQKBA +HAYYIOAHIPQKBA +RUDATBOHQWOJDD +XZDHXPDYLPEFQI +XZDHXPDYLPEFQI +XZDHXPDYLPEFQI +SPOZHYGMBMRPGM +AJOPHDUNANPFKQ +AJOPHDUNANPFKQ +AJOPHDUNANPFKQ +SVWHITUXVZXJRQ +SVWHITUXVZXJRQ +SVWHITUXVZXJRQ +COCMFMBNEAMQMA +COCMFMBNEAMQMA +COCMFMBNEAMQMA +CNWPIIOQKZNXBB +CNWPIIOQKZNXBB +CNWPIIOQKZNXBB +UTBBBXZUPUXYGZ +UTBBBXZUPUXYGZ +UTBBBXZUPUXYGZ +CJLZGUJUXDRHJQ +CJLZGUJUXDRHJQ +CJLZGUJUXDRHJQ +XJZGNVBLVFOSKJ +XJZGNVBLVFOSKJ +XJZGNVBLVFOSKJ +RIVQQZVHIVNQFH +RIVQQZVHIVNQFH +ZHCAAZIHTDCFJX +ZHCAAZIHTDCFJX +ZHCAAZIHTDCFJX +COCMFMBNEAMQMA +COCMFMBNEAMQMA +WVULKSPCQVQLCU +COCMFMBNEAMQMA +COCMFMBNEAMQMA +COCMFMBNEAMQMA +SVWHITUXVZXJRQ +SVWHITUXVZXJRQ +SVWHITUXVZXJRQ +XZDHXPDYLPEFQI +XZDHXPDYLPEFQI +XZDHXPDYLPEFQI +ZQYUKJFJPJDMMR +ZQYUKJFJPJDMMR +ZQYUKJFJPJDMMR +ZQYUKJFJPJDMMR +SMEROWZSTRWXGI +SMEROWZSTRWXGI +GCAHOAMXTYBLNZ +GCAHOAMXTYBLNZ +GCAHOAMXTYBLNZ +DKPMWHFRUGMUKF +MIHNUBCEFJLAGN +MIHNUBCEFJLAGN +MIHNUBCEFJLAGN +BHQCQFFYRZLCQQ +AIHWGPJJINPTRP +AIHWGPJJINPTRP +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +SLDVWYDDPPFGHK +SLDVWYDDPPFGHK +SLDVWYDDPPFGHK +SLDVWYDDPPFGHK +SLDVWYDDPPFGHK +SLDVWYDDPPFGHK +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +WYFHJKKXWBYZIM +WYFHJKKXWBYZIM +PPDYNVKBDBQLEM +PPDYNVKBDBQLEM +SZDHRKMCESZUCV +SZDHRKMCESZUCV +SZDHRKMCESZUCV +STOVTFIIHLYHKA +SHUYNJFEXPRUGR +SHUYNJFEXPRUGR +SHUYNJFEXPRUGR +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +SVWHITUXVZXJRQ +SVWHITUXVZXJRQ +SVWHITUXVZXJRQ +XZDHXPDYLPEFQI +XZDHXPDYLPEFQI +XZDHXPDYLPEFQI +OVBZFPUPFCLMFP +OVBZFPUPFCLMFP +HQPHGZUTNNVZLH +HQPHGZUTNNVZLH +UTTBUMIEHWNKLK +UTTBUMIEHWNKLK +CEMZGPKUKMFNNF +CEMZGPKUKMFNNF +CEMZGPKUKMFNNF +CEMZGPKUKMFNNF +AUVYDCOKXDDYKR +YFAWUWYZXIKWSJ +YFAWUWYZXIKWSJ +YFAWUWYZXIKWSJ +HTKDGIAMGUMIQO +HTKDGIAMGUMIQO +HTKDGIAMGUMIQO +VMFFESMCXOCOIZ +VMFFESMCXOCOIZ +VMFFESMCXOCOIZ +CEMZGPKUKMFNNF +CEMZGPKUKMFNNF +CEMZGPKUKMFNNF +CEMZGPKUKMFNNF +KAOKDEFHEADBNL +KAOKDEFHEADBNL +KAOKDEFHEADBNL +UYVVLXVBEQAATF +UYVVLXVBEQAATF +UYVVLXVBEQAATF +KLRIUOUKRCSWSF +KLRIUOUKRCSWSF +GLVWZDCWCRWVFM +BMSROUVLRAQRBY +BMSROUVLRAQRBY +BMSROUVLRAQRBY +KAOKDEFHEADBNL +KAOKDEFHEADBNL +KAOKDEFHEADBNL +JNMALBXXJSWZQY +JNMALBXXJSWZQY +JNMALBXXJSWZQY +NVTDAUYTNRUBQY +NVTDAUYTNRUBQY +PBXYLMVLLSYZLN +PBXYLMVLLSYZLN +PBXYLMVLLSYZLN +BBQNKFCDPDYHLC +BBQNKFCDPDYHLC +BBQNKFCDPDYHLC +UCVGCHGIKFWAGH +UCVGCHGIKFWAGH +BMSROUVLRAQRBY +BMSROUVLRAQRBY +MRBBYYYXCVLILT +MRBBYYYXCVLILT +CYUZUFOPGIQGBF +GNGSNCPQCZJNBI +GNGSNCPQCZJNBI +GNGSNCPQCZJNBI +KHPHCSMHVCKXMH +KHPHCSMHVCKXMH +BHQCQFFYRZLCQQ +KNVADAPHVNKTEP +KNVADAPHVNKTEP +KNVADAPHVNKTEP +GLVWZDCWCRWVFM +PBXYLMVLLSYZLN +PBXYLMVLLSYZLN +PBXYLMVLLSYZLN +CBTSGRWRWACHRS +CBTSGRWRWACHRS +CBTSGRWRWACHRS +SCZJGLWPRVUGAT +MRBBYYYXCVLILT +MRBBYYYXCVLILT +RUDATBOHQWOJDD +DNRPEPTUACADRG +DNRPEPTUACADRG +DNRPEPTUACADRG +SPOZHYGMBMRPGM +AIHWGPJJINPTRP +AIHWGPJJINPTRP +AIHWGPJJINPTRP +OGSDYCPNYNWUNN +OGSDYCPNYNWUNN +OGSDYCPNYNWUNN +COCMFMBNEAMQMA +COCMFMBNEAMQMA +COCMFMBNEAMQMA +SVWHITUXVZXJRQ +SVWHITUXVZXJRQ +SVWHITUXVZXJRQ +MEYVIHRQCGHFDC +MEYVIHRQCGHFDC +MEYVIHRQCGHFDC +SPOZHYGMBMRPGM +KAOLEMQCYWHOJQ +KAOLEMQCYWHOJQ +KAOLEMQCYWHOJQ +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +HDXFKPPIKDSQGU +HDXFKPPIKDSQGU +FQSTXEWGPYKNPY +MWUBEKFSCVGPKW +COCMFMBNEAMQMA +COCMFMBNEAMQMA +COCMFMBNEAMQMA +SPOZHYGMBMRPGM +CPKBPCHJXMSTOE +CPKBPCHJXMSTOE +CPKBPCHJXMSTOE +KAOLEMQCYWHOJQ +KAOLEMQCYWHOJQ +KAOLEMQCYWHOJQ +UTBBBXZUPUXYGZ +UTBBBXZUPUXYGZ +UTBBBXZUPUXYGZ +SLDVWYDDPPFGHK +SLDVWYDDPPFGHK +SLDVWYDDPPFGHK +SLDVWYDDPPFGHK +CIICTINKDWKIAB +DFSUHDZXXWBENC +DFSUHDZXXWBENC +DFSUHDZXXWBENC +XSOLDPYUICCHJX +XSOLDPYUICCHJX +XSOLDPYUICCHJX +PRQADQZRIHRYCH +PRQADQZRIHRYCH +PRQADQZRIHRYCH +GGQRYMZUAIWDDB +COCMFMBNEAMQMA +COCMFMBNEAMQMA +COCMFMBNEAMQMA +YFAWUWYZXIKWSJ +YFAWUWYZXIKWSJ +YFAWUWYZXIKWSJ +KUXSAFRZQPYINU +KUXSAFRZQPYINU +YKGWNUNKCNTZLA +YKGWNUNKCNTZLA +YKGWNUNKCNTZLA +WVFDPCYTNIXGHI +WVFDPCYTNIXGHI +WVFDPCYTNIXGHI +HMXPOCDLAFAFNT +HMXPOCDLAFAFNT +HMXPOCDLAFAFNT +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +UTTMPNQHQIRCGZ +UTTMPNQHQIRCGZ +UTTMPNQHQIRCGZ +AWDRATDZQPNJFN +AWDRATDZQPNJFN +AWDRATDZQPNJFN +QNRIYEYAHVEGQJ +QNRIYEYAHVEGQJ +UXAHTIGXQXJADE +UXAHTIGXQXJADE +UXAHTIGXQXJADE +HVNRNWTTWOOXEC +HVNRNWTTWOOXEC +HVNRNWTTWOOXEC +MFDHSRQWKNAICJ +MFDHSRQWKNAICJ +WBWWGRHZICKQGZ +UBDJSBRKNHQFPD +JTTGPCRBDUOCGG +JTTGPCRBDUOCGG +AWDRATDZQPNJFN +AWDRATDZQPNJFN +AWDRATDZQPNJFN +PWKMCTSCOMHDIZ +QBYUNVOYXHFVKC +QBYUNVOYXHFVKC +JTTGPCRBDUOCGG +JTTGPCRBDUOCGG +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +FLCYLDUFOVBENV +FLCYLDUFOVBENV +FLCYLDUFOVBENV +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +XSOLDPYUICCHJX +XSOLDPYUICCHJX +XSOLDPYUICCHJX +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +XSOLDPYUICCHJX +XSOLDPYUICCHJX +XSOLDPYUICCHJX +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +RUDATBOHQWOJDD +SKEDGYKXMOKLJX +COCMFMBNEAMQMA +COCMFMBNEAMQMA +COCMFMBNEAMQMA +YTHIOIIKGOBXQQ +YTHIOIIKGOBXQQ +YTHIOIIKGOBXQQ +BXUVIKFICAYYEQ +BXUVIKFICAYYEQ +SMEROWZSTRWXGI +SMEROWZSTRWXGI +WCFIGQHNBJXROP +WCFIGQHNBJXROP +WCFIGQHNBJXROP +BHQCQFFYRZLCQQ +GCAHOAMXTYBLNZ +GCAHOAMXTYBLNZ +PFMAXGIVRQIQPX +PFMAXGIVRQIQPX +PFMAXGIVRQIQPX +WURGVTTXAYJRCC +WURGVTTXAYJRCC +WURGVTTXAYJRCC +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +BHQCQFFYRZLCQQ +BHQCQFFYRZLCQQ +GYUVAHWOVINGNE +GYUVAHWOVINGNE +GYUVAHWOVINGNE +JZAIXDCPNUAWTQ +JZAIXDCPNUAWTQ +JZAIXDCPNUAWTQ +WBWWGRHZICKQGZ +DKPMWHFRUGMUKF +DKPMWHFRUGMUKF +UYVVLXVBEQAATF +UYVVLXVBEQAATF +VOUKAYFXXSUOGA +VOUKAYFXXSUOGA +VOUKAYFXXSUOGA +FAYYTQMQTAKHRM +FAYYTQMQTAKHRM +FAYYTQMQTAKHRM +FAYYTQMQTAKHRM +FAYYTQMQTAKHRM +FAYYTQMQTAKHRM +CGPYXOCZBMZIIR +CGPYXOCZBMZIIR +CGPYXOCZBMZIIR +MCVJTZAENNGXTM +MCVJTZAENNGXTM +MCVJTZAENNGXTM +MCVJTZAENNGXTM +FAYYTQMQTAKHRM +FAYYTQMQTAKHRM +FAYYTQMQTAKHRM +MRBBYYYXCVLILT +MRBBYYYXCVLILT +JNMALBXXJSWZQY +JNMALBXXJSWZQY +JNMALBXXJSWZQY +GNGSNCPQCZJNBI +GNGSNCPQCZJNBI +MEYVIHRQCGHFDC +MEYVIHRQCGHFDC +MEYVIHRQCGHFDC +WJAIFDIPOPXOPB +WJAIFDIPOPXOPB +WJAIFDIPOPXOPB +PWKMCTSCOMHDIZ +PWKMCTSCOMHDIZ +MCVJTZAENNGXTM +MCVJTZAENNGXTM +MCVJTZAENNGXTM +MCVJTZAENNGXTM +SMEROWZSTRWXGI +OGSDYCPNYNWUNN +OGSDYCPNYNWUNN +OGSDYCPNYNWUNN +CYUZUFOPGIQGBF +ARGCPGOJOKCMSW +VMFFESMCXOCOIZ +VMFFESMCXOCOIZ +VMFFESMCXOCOIZ +VFJSXFXCQQBGTM +VFJSXFXCQQBGTM +VNBNDOGLQFEJKP +VNBNDOGLQFEJKP +VNBNDOGLQFEJKP +VNBNDOGLQFEJKP +IGVZUMPVFZKTRH +IGVZUMPVFZKTRH +AZWGEBXBDOIOHW +AZWGEBXBDOIOHW +AZWGEBXBDOIOHW +MIGXYHMLYVAUQT +MIGXYHMLYVAUQT +MIGXYHMLYVAUQT +OYWYHAQWNNRFLI +OYWYHAQWNNRFLI +OYWYHAQWNNRFLI +RIGHMQLKMHLMQD +RIGHMQLKMHLMQD +RIGHMQLKMHLMQD +MHOZNCAVRHAOKT +MHOZNCAVRHAOKT +MHOZNCAVRHAOKT +CEMZGPKUKMFNNF +CEMZGPKUKMFNNF +CEMZGPKUKMFNNF +CEMZGPKUKMFNNF +TZJSDNVVGFIRIY +TZJSDNVVGFIRIY +TZJSDNVVGFIRIY +CHFOVLMTXSAFKC +CHFOVLMTXSAFKC +BAOWHAJSJGJSBV +BAOWHAJSJGJSBV +BAOWHAJSJGJSBV +WKNSSWRPDRZCAQ +WKNSSWRPDRZCAQ +HKYRAGBVPCSLII +FDLBWFQZCBIUPV +FDLBWFQZCBIUPV +FDLBWFQZCBIUPV +XTVWUFJAQMCVQZ +DWKUILAFNXKAFN +DWKUILAFNXKAFN +DWKUILAFNXKAFN +WVFDPCYTNIXGHI +WVFDPCYTNIXGHI +WVFDPCYTNIXGHI +CNGHUSPOYWEVTQ +CNGHUSPOYWEVTQ +UXWZMQPNSYWAHX +UXWZMQPNSYWAHX +HHGKPVQSNIVPPF +HHGKPVQSNIVPPF +HHGKPVQSNIVPPF +CDNGTOVFEUSMMG +CDNGTOVFEUSMMG +CDNGTOVFEUSMMG +OYXZMSRRJOYLLO +OYXZMSRRJOYLLO +RSMUVYRMZCOLBH +DGAIEPBNLOQYER +DQWIIKBKAIPUPY +RTHCYVBBDHJXIQ +SZCMHDLOUVZYST +CSWIKHNSBZVWNQ +RLFWWDJHLFCNIJ +ZRWWEEVEIOGMMT +WSJBSKRPKADYRQ +RVSCDWJKJDBFRS +JZUFKLXOESDKRF +VBLJFQYCTRKKKF +RMMXLENWKUUMAY +DCASRSISIKYPDD +ASOKPJOREAFHNY +LPEPZBJOKDYZAD +DDLIGBOFAVUZHB +OYYDSUSKLWTMMQ +JXTHEWSKYLZVJC +SGOIRFVFHAKUTI +DIWRORZWFLOCLC +UBCHPRBFMUDMNC +LSAMUAYPDHUBQD +DNTGGZPQPQTDQF +HYAFETHFCAUJAY +IQWYAQCHYZHJOS +UZKBSZSTDQSMDR +WRMRXPASUROZGT +KCKCVKAROJRVBA +AYIRNRDRBQJXIF +QMLVECGLEOSESV +NOOCSNJCXJYGPE +DAWYIZBOUQIVNX +LQDARGUHUSPFNL +KYYIDSXMWOZKMP +GRTOGORTSDXSFK +VPUNMTHWNSJUOG +MFHPSBRWDZUZHF +OWQNWJPLMHWHSM +HCJXEOFLVIFFDG +AUZMDLDJTGPIEA +HOPVGFKDVOOCHD +HLGBXKIGYXVIFU +JSIOTGHMQGLKET +WRLCNNSWESNISL +HUJXHFRXWWGYQH +LEVWYRKDKASIDU +COCNDHOPIHDTHK +IYODIJVWGPRBGQ +NFGIENSPALNOON +VGEREEWJJVICBM +AFHJQYHRLPMKHU +IYRMWMYZSQPJKC +DZGWFCGJZKJUFP +HFDLDPJYCIEXJP +AMOGMTLMADGEOQ +AERWTVOXUHXGAE +RQOFTLFCRJDAJR +VDLVEKYIPCXLKO +FQHXRDDMWDQLPV +IWIISBMWNKBQQH +SLVSUVFUFJKMCV +HTBQLUDZPAANPB +WVDDGKGOMKODPV +YUULFXAQUWEYNP +WJNXAFADOMWGIU +UTXNRISXYKZJTH +ZTDUIGVZKPFWOX +IEWHPTFFMRBBPQ +BUUGGTNVRUBNGN +ALCQRUPUCBKBMV +JQWUSEVRGIXWTP +WWBNBPSEKLOHJU +KLPUXMNQDCUPNO +KLPUXMNQDCUPNO +CTZNINKRTKCWGU +KYOXKUIYXAIFBB +IIUWCHJZJFSKMD +DMMVPIYJYFCXOA +USUPWKOUEKWYER +ZRMFMDZIHZKFHY +MYTOZWCQVXHVIO +IUQRTVVZUXBHMO +STLFVIAKHLLGHJ +FAUWZNGPMHRLMW +NGTHIBFWOPPSSB +PLOQCCJPPQJNFO +IINDQALFBNRRJE +KOPJPWSRYZRWPD +AWVNBSKIKNPOBG +WKGYNBDVOPHKOW +SVAPNKGLWRWWCI +MXLZHQOOQIUQGO +WHPZSYIEWQPEHY +FHTSKUYELRWGGJ +QJMXHGRSTYIVBE +GCXJISBMJWCIPK +PFDGTTDLWWKNMI +ZOCMJFMKJRSTTD +ZSLMYYBJYKRANS +XCYFSKKZKGHHRG +FJNCVIHFDLPUHW +QCQACYPNQZJHQN +WSLFSVKKVVFSHV +JOOLMUIIRGMMFV +AGOFFFZRCNJTMQ +KXHAUAFVDYQKLI +ZRDKCABMZXNCMG +OYUVUBMEBPNFOT +XMGOOZIWAWRPGW +FEESWVAHLOUZGM +VGGCLGHLLZKCSW +GEJNVNUFFYATKR +HUVLAOORYMIHTC +FAIPNHMNCVVHLA +FYMIXXOEKMFOIA +VNPGDSQQFDEFHO +KYIPVUWVVGXMKA +MXMCPSADIJXXRC +GOFSCWBZJWJLTF +REAZZDPREXHWNV +YIQGLTKAOHRZOL +ZFQMTVNLDNXRNQ +JJOSIKPABYYKOP +DNSFMKGQWLZMOJ +YUNDIYNGCYJSTC +KQTNKAWCVIBWHG +XBXKOKJLEVOCTF +MZEGXLYZBJHREF +LBSHKCUTMCYUOW +XHCNVUPFYLKTEJ +NSDVLRONTCKCPY +HWLCTPIUUFQVEK +YYICKHZBDGQJBW +RHDVQZWCBQXOJW +CCROUVCATXGAFZ +CQVYQYUSHAXATN +PEKHDQCGVPPILP +SCQIVKOIYXXGEW +OKOVSTKGUBOSTB +KDYYGGKDZBRIIX +ARZWATDYIYAUTA +BAPAICNRGIBFJT +ZMPGJEYFRZCHQC +BTLXPCBPYBNQNR +ALRLPDGCPYIVHP +OIPILFWXSMYKGL +QNAYBMKLOCPYGJ +DMASLKHVQRHNES +JDCJBUJXKILORV +WULISCVZERSMML +CBMQKMMZBOSHHP +VWGCDYGRSUJYGJ +WZRCQWQRFZITDX +QJYNZEYHSMRWBK +YAPIWGCPLZLZGZ +CKXBHBNBEFREKT +RZVYTWRTBDNOPF +PJHBZROILRCFRB +JGOGSKGKPWYQRE +GXKSDIFDAFRNGH +SBZXBUIDTXKZTM +UGGAHNIITODSKB +KZVOHANKAKKFOK +KQYNVUQPVATPHJ +VGXYDZCCQDSGLZ +XYEKESXODZZYMD +FIIRBPHYBLFBSD +SVPQGHIWELZQOE +CBCQWVQNMGNYEO +QWCKQJZIFLGMSD +YOMSJEATGXXYPX +IFXDBKRFNXPGNO +ZXIATBNUWJBBGT +HKXMQLISPYELRD +USPFMEKVPDBMCG +TZRHLKRLEZJVIJ +MFOCDFTXLCYLKU +UUTKICFRNVKFRG +KRVMLPUDAOWOGN +TVIMZSOUQXNWHO +IRTZMJWVZQYURE +UYUWZFRYAAHPDN +DIOYAVUHUXAUPX +UTMRKCQYCLEKDL +WXVLCNREBFDEKS +BPEXJHGGARTCIR +JZWLSXINEVHWEP +SKUCQDOSGKINGP +AOHCBEAZXHZMOR +BIQPSTSCCIEMEI +QLJNETOQFQXTLI +GQLVRVYXAHDDLB +NUENJLVLKHHYJS +PONPPNYZKHNPKZ +KQJGPGHQDDZVHJ +HGJXAVROWQLCTP +DQNFLBXNPGBCOU +IBLFDTIZHJLTIF +ROOSGBDAZNISLI +DZBBOCDYINLWCH +PHHIEOZUONPPQY +LXAMCLNOVGHDMD +QQNSARJGBPMQDI +BPIMOIWHAHUBPJ +YGVHOSGNOYKRIH +CNURKUNYCXCBEK +LDBMLOLBWUOZGG +KVPBAPOAIIQDGQ +HSWIRQIYASIOBE +DBKIEMOKQWYZOA +OJISWUQNQQWEND +ZLPLFUBVEZVYDX +AQLCKWUMMOZIEY +SFLMUHDGSQZDOW +CRVXJSNSTGEXDX +RVGGCRQPGKFZDS +CFNMUZCFSDMZPQ +MRBLTWPEPGRXQN +WKEOZXMSVNVPCM +LOVMOOUQHWMIHZ +BAHUBXAYVOCLNA +HIWJJOYYZFELEZ +ZMELGIPFIBWPHX +GPTPSPAFUZTDEG +HVSMXONXCJBJIF +ILQLITDRYFHAGM +MXLIDYXKRCYRPL +QUKDLMFYXITHBM +PBPYEEMQIFDGSQ +INRCFVYVWPWZJS +GUZJCKBQAGGXGH +QCLBGWSAIHOGCA +QDSDUIWGMCGLHI +DORPKYRPJIIARM +RMAYNNFCPNGTQW +CVPYYBCSHSCXJQ +OGJCZLOIKMTMKF +MWQRAOGWLXTMIC +MMLPRYWSGSVRRN +NZBYUSXAWFZDAY +LOUBNBRAJPSMEC +BMKQPAJRQUUYGC +OIMUSOLEDHKDCV +URBPIXMUXQEKHZ +FTGKHGAVFGGOMW +OTAFZEHRJNHBDI +NJYMCMBDFMRROK +QPRODDKTRBCFPV +ABJOCPBDVGJFLG +KKOLMSSIDZXPLS +KNOJWNDGCRZBBA +BUVGSDAKOBKGFK +JGHTWRZCNLXYPF +IAVJHQVGTRSIOM +NOGWCMMYTAXOCY +FFDNVMGPKVVVOG +PYWZXKKFHNJUIQ +KBHXFAMQPPWLFT +IBIPGYWNOBGEMH +XMVQWNRDPAAMJB +QADCCYSYLNTZHV +BDFCYBFDARSRDM +XWHQCPICYIBGNB +YTLMIHBTPWTPEV +SYGQXRLXOOXDRP +ZIAXNZCTODBCKW +BGLMHEUNVVQFLX +QYCCCSUFDHWKRW +MXZXIBZNZUOHER +LNFRDRVVARCALE +LSMKTLJKBSXMMR +BQRISQXLSXCXSC +OYBHLUBLZHVTKK +GXDJGKMWLJOJFR +PYVBFDCHJDMSMM +BAUXUWNOTMKKET +FDVOVSCQDWKKHH +VEDWXCWBMDQNCV +YWASZTJGPFRWMW +ITJIJDWFGMAIKB +CMIGVNMYXBHBKY +LJONQULKOKMKBR +ZKIRVBNLJKGIEM +KNSDITCTAHCCEB +KCPUSSJDCHTZSH +ZCKITOSCNKNMMO +VBFIGWHJNDFEIS +JJKCJXIYVNHIOS +OHRGHFXATDKGOV +RGTIBVZDHOMOKC +RETJNOLVDRGHMX +ONMLNUSSUHTGJO +LQMRAHHWCLZHQD +OPAORDVBZRVVNQ +QUKCKUMUBOPETR +JBNMHJLAARQCFY +LEXDMFDDGUTINX +BNOWPELKBYSHKU +ZWTDABBYXDAIOL +RLYPFWBODVDUHT +AEUTYOVWOVBAKS +QOIHIEPXTNMSSM +ZDSBUUDXDQSCSK +CFAJIMXUZRPYDP +OVBBFGXDDIFFMB +DSMWJDJWYGMEBO +GBKCPBPYMRGRKL +JAAFNWYGLROOGI +DEJPAJWPCTUPPL +CNIWQELMLPUFOS +ZHVLPKFAODFQST +IRBLIRNSGBXQFB +TXPRZPDVUZCNLB +XPDBYTRMUWQPTF +JDIDEXHTJXTVES +UJQXYSRVSXKEES +KRXLVSZOLMEYHF +MSIMWLAIWYFFLY +CKZNKYSWWCSICZ +MLCMEHUPTMULKN +LGIBRQVYYFOBSF +FLLRZSQAKUHACV +MNLWZCYHJPEFDE +XMBZZLUIFFOAHR +RRUQYJBEEQBWGK +YHEIGYJZSXWHJB +FSTIKTPQGMHLFJ +KLKLIUIRQAMTAJ +CNQCBOHTKBVCFM +KTBAIBUBSGVINZ +PYUSHNKNPOHWEZ +NONWRJXAJGEWOR +OYFVPOABQXXDNO +MPMJLHQXZNLSCP +CAQZFLPWHBKTTR +YAEGHQJYDLCTMR +NWNMAVFXIRDAPM +KNGBXFMEGLRFHV +OLARKEMZPWGFJU +OWCRARVHWCCRAG +FISIJWVRKFHLSM +DVFXEUYOOYUTOA +HGCMCLAKARHJBW +FBFMBWCLBGQEBU +IHOHGVDNDQTZGL +ORXMVTNKIKCWMQ +IWDKJDOUWOTZPS +NJVQCZVYEIAGLE +DGBNCMKQNOJCFB +AVAQRWVGWWNBIN +WJMFXQBNYLYADA +PNYQFRZBMVRYFC +HIFLEGNWVFLGLY +RPIVIODUUUOQDD +YPIDZFLQKNEKRA +KVQVEJPIQHNLTM +VYHHSBHXZVSILO +GIWAJLOUUBQKKA +XIIAYQZJNBULGD +IKSYBPLYPLDCSW +REDMIYQFNIRTDF +SUQFMFHTLHMZNM +GVQWKADEEQMGQO +URSYWCOXEXDCDK +ZCTSQCRTBXPIIU +ZDJZZRYSIFHZLQ +WJRRGYBTGDJBFX +GPMAWZWHYNAUCW +XKFTZKGMDDZMJI +QMPRZWDSUVCETG +QLSNLHRHBUEVMS +UXZFQZANDVDGMM +CULUWZNBISUWAS +IJESFQCCOFNOQG +RIIRZOYVNRZXCK +OJICYBSWSZGRFB +SBJYBAIMQAUWMZ +DHASBUQVETXFTK +JBAGAKSCBHZIIC +FIEWOUZYTHWIGD +FZTRDYSPWWJCOF +QFPXBVYGCDAYMW +IVFHUUHIAMUTGR +OCPFPYJVXUSXGP +MXGQUMNBFGOVSM +RIVXZPCBFQAIEG +UYLYXPZYFFLBLV +GTWOKQIGBJADIZ +NEZTYZLKZFROFG +BVQDZSFUVFXFCD +IGEXZUWFYCYQFB +LOFURYWJDOAONN +KNPCDSZXZHMZNO +UBYPYZJJWXISEX +XCJMUIWIEQFAQX +SERGCCVLLRWNTL +BKHIUIHGKIWMST +DPNGWXJMIILTBS +BJPLCTUJTXVXPC +IIENSJWVEKJWAJ +BKJAMMLKHPCMJI +SVWYOGCKJVQALA +MQBWTDWAWPAFCU +KYOBSHFOBAOFBF +YCCNSZADCQXKKU +INZILOLDAGSVRR +OVBUASHUXKNUMI +SBXFNAPGWOTRJF +GGKQJKPLGLUFPB +YMEAIOHYSIGDJY +KXSOIYZLDANCPG +YWAXVDLXUXRDHL +ZRBOGSQITRZXJM +WSNJPVCNURDQDC +XRSRJBBRTCEBNS +PXFUFMBZHQBOIT +RCEFXZXHYFOPIE +KVKPUNTZFLWTSM +JVZQPGNKHJDEHX +FSYKKLYZXJSNPZ +WXNZTHHGJRFXKQ +AQAKHZVPOOGUCK +AQAKHZVPOOGUCK +SFUVCMKSYKHYLD +RJFFPCHJOFXZQD +HCXVJBMSMIARIN +ZUHZGEOKBKGPSW +IOYNQIMAUDJVEI +PJDINCOFOROBQW +QEIXBXXKTUNWDK +GAPDDBFHNYHZIS +AFOLOMGWVXKIQL +SXYMMDGPXYVCER +JSYDBTWJIIAZPU +BXEZTCOKOLHMKY +OTUCXMIQUNROBJ +NJXPYZHXZZCTNI +OJCPSBCUMRIPFL +ZTVQQQVZCWLTDF +NWXMGUDVXFXRIG +IOYZYMQFUSNATM +BGSZAXLLHYERSY +BGSZAXLLHYERSY +GFWPWSNIXRDQJC +XYPPDQHBNJURHU +XYPPDQHBNJURHU +POUZLUJYBWGJJO +LLSRPENMALNOFW +YAADMLWHGMUGQL +MKMZAENVDZADSW +LJEJBLOFFDLRIH +LJEJBLOFFDLRIH +HMJJWFFZRCLIDN +FSNITHOUQGJHTR +XUXBOSSCMLZGTA +LMILVXQXGKTFSZ +YOTCKRFNSMJTGD +AXXBADPZGFAAHF +CNSUXOYAIZBGRY +KXFFLWDYUNIJNU +URGZBBCARSDFSL +XLRKFSDSKCYZBE +ZFMSMUAANRJZFM +LUHMMHZLDLBAKX +DVZCOQQFPCMIPO +ILRCGYURZSFMEG +SASVNKPCTLROPQ +BJRNKVDFDLYUGJ +PYRZRPSTTNKOCS +OKBNMQXBQLZQEM +AWEFUQDNSBBNCR +HUXJGSHUVDWZAM +VDSCKSOYNLTQSY +CDTMPWYDQKWYFT +WROKSYFOSDWFHL +ZRSCGBGNKZDPOF +JFJZZMVDLULRGK +PYMYPHUHKUWMLA +IKFXPERBVFYFMS +MGQUMSFBIYXTTE +OEWYUGADRFSLPO +XJDJODWHDUVAGF +VJFDKEUBFXWWLI +HCEYJYMNIQHPPK +RZCJYMOBWVJQGV +BSZLLSHGSWKZRE +AZGNIKZHFDJEPU +IMPPSJRGMZYGJW +IRXIEUDBDWXTTL +AXNXSFBKZQIMPF +HEZIERXQNQUEDU +LBHYRBPEXITYTN +IUCHKMAZAWJNBJ +PUOQHFWXBKTHST +CMZFNIMQBCBHEX +DZVIFFMYEULLBY +BBPOLSMDPRNEHZ +XPZGXZBKRPZWMJ +YQDXYGOKFNYKCJ +APFDGFTWPXUJGF +LDCLXZSKVDYDBF +LXBKBIJODOOVOX +BNJOQKFENDDGSC +BFQWBQIYMSVPOL +GXJABQQUPOEUTA +RXZBMPWDPOLZGW +NCEXYHBECQHGNR +UMJHTFHIQDEGKB +PVLJETXTTWAYEW +XQPYFQDHBGUIBQ +LCYPYTJALPJIBU +WUJKEABPANBOBA +MYLOBISKHDRNEW +YBHILYKTIRIUTE +IYRMWMYZSQPJKC +WULISCVZERSMML +MVMBTNNVZQRZQT +PLKUTZNSKRWCCA +UUQINGLDFWYORW +USVMJSALORZVDV +BZLKOORCGCYQJZ +VEVZSMAEJFVWIL +SLCKJKWFULXZBD +JGUZGNYPMHHYRK +RPMNUQRUHXIGHK +USNPULRDBDVJAO +ODBRNZZJSYPIDI +DCYOADKBABEMIQ +ABVCUBUIXWJYSE +HKEAFJYKMMKDOR +KYQZWONCHDNPDP +FEGVSPGUHMGGBO +LZPNXAULYJPXEH +AFDXODALSZRGIH +PXUQTDZNOHRWLI +OLNJUISKUQQNIM +TWBYWOBDOCUKOW +XZKIHKMTEMTJQX +JGUZGNYPMHHYRK +QYPPJABKJHAVHS +PXUQTDZNOHRWLI +CILLXFBAACIQNS +ZZWPMFROUHHAKY +MGJLSBDCWOSMHL +ZUKPVRWZDMRIEO +YHHSONZFOIEMCP +COESHZUDRKCEPA +ZZWPMFROUHHAKY +KRUPPTWQKIEURV +CCQDWIRWKWIUKK +IPVSUYLZIAYTOK +PLKUTZNSKRWCCA +TWYYVOVDSNRIJM +OLBLWNPOURNBCY +GGLZPLKKBSSKCX +SOSLMHZOJATCCP +RNVUDWOQYYWXBJ +SOSLMHZOJATCCP +OLNJUISKUQQNIM +GXLQUHPXGLZNGE +WLPJMCCYDZFCBL +JYXSWDCPHRTYGU +BLBDTBCGPHPIJK +KQCMTOWTPBNWDB +WGQKYBSKWIADBV +DATYUTWESAKQQM +QSNSCYSYFYORTR +YCSBALJAGZKWFF +QSNSCYSYFYORTR +CYESCLHCWJKRKM +METKIMKYRPQLGS +RLFWWDJHLFCNIJ +SPFYMRJSYKOXGV +DBEPLOCGEIEOCV +CMSMOCZEIVJLDB +QIKYZXDTTPVVAC +NUVBSKCKDOMJSU +MLWDGPFGTFOLRJ +SRVJEQWEVJCHCF +JDAPIOVVXOAJOM +URFCJEUYXNAHFI +JRHMMVBOTXEHGJ +ZJMLELXRQUXRIU +DYARIVMCYYQNNQ +FRSRMZNTUGSNRW +QELDJEKNFOQJOY +DEQITUUQPICUMR +VJJPUSNTGOMMGY +BGEBZHIAGXMEMV +IECSQLKWZBEUGA +DANYIYRPLHHOCZ +SGTNSNPWRIOYBX +DANYIYRPLHHOCZ +BLGXFZZNTVWLAY +RTIXKCRFFJGDFG +GBYDSYPGGDKWGZ +GBYDSYPGGDKWGZ +MRWXACSTFXYYMV +MRWXACSTFXYYMV +UDFPKNSWSYBIHO +JQUHMSXLZZWRHU +AYMLQYFMYHISQO +IEMDPPNEUUFQGC +VNLPVWHRKKWDQB +SCZVLDHREVKTSH +JPZXHKDZASGCLU +PYPKJBUJNZMSTH +MOBDZHABRVPJCH +MOBDZHABRVPJCH +BAHHZVVNFAOLAZ +TVKGYMYAOVADOP +REBBZOCNEVVAPX +QVZZPLDJERFENQ +QVZZPLDJERFENQ +QVZZPLDJERFENQ +QVZZPLDJERFENQ +QVZZPLDJERFENQ +QVZZPLDJERFENQ +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +UJYGDMFEEDNVBF +ZRTGPZGAMCJZNA +ZRTGPZGAMCJZNA +ZRTGPZGAMCJZNA +ZRTGPZGAMCJZNA +ZRTGPZGAMCJZNA +ZRTGPZGAMCJZNA +ZRTGPZGAMCJZNA +ZRTGPZGAMCJZNA +ZRTGPZGAMCJZNA +ZRTGPZGAMCJZNA +ZRTGPZGAMCJZNA +ZRTGPZGAMCJZNA +LRXYHMMJJCTUMY +LRXYHMMJJCTUMY +LRXYHMMJJCTUMY +LRXYHMMJJCTUMY +LRXYHMMJJCTUMY +LRXYHMMJJCTUMY +LRXYHMMJJCTUMY +LRXYHMMJJCTUMY +LRXYHMMJJCTUMY +LRXYHMMJJCTUMY +KRQRRZFXHYYNSO +KRQRRZFXHYYNSO +KRQRRZFXHYYNSO +KRQRRZFXHYYNSO +KRQRRZFXHYYNSO +KRQRRZFXHYYNSO +KRQRRZFXHYYNSO +KRQRRZFXHYYNSO +KRQRRZFXHYYNSO +KRQRRZFXHYYNSO +BGHDUTQZGWOQIA +BGHDUTQZGWOQIA +BGHDUTQZGWOQIA +BGHDUTQZGWOQIA +BGHDUTQZGWOQIA +BGHDUTQZGWOQIA +BGHDUTQZGWOQIA +BGHDUTQZGWOQIA +BGHDUTQZGWOQIA +BGHDUTQZGWOQIA +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HWSQVPGTQUYLEQ +HWSQVPGTQUYLEQ +HWSQVPGTQUYLEQ +HWSQVPGTQUYLEQ +HWSQVPGTQUYLEQ +HWSQVPGTQUYLEQ +HWSQVPGTQUYLEQ +HWSQVPGTQUYLEQ +HWSQVPGTQUYLEQ +HWSQVPGTQUYLEQ +MXLWQNCWIIZUQT +MXLWQNCWIIZUQT +MXLWQNCWIIZUQT +MXLWQNCWIIZUQT +MXLWQNCWIIZUQT +MXLWQNCWIIZUQT +MXLWQNCWIIZUQT +MXLWQNCWIIZUQT +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +QFKRKMXPKBHGGO +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +MYDJDVOVZVSVIE +MYDJDVOVZVSVIE +MYDJDVOVZVSVIE +MYDJDVOVZVSVIE +MYDJDVOVZVSVIE +MYDJDVOVZVSVIE +SMUNNMAWNRFDPB +SMUNNMAWNRFDPB +SMUNNMAWNRFDPB +SMUNNMAWNRFDPB +SMUNNMAWNRFDPB +SMUNNMAWNRFDPB +SMUNNMAWNRFDPB +SMUNNMAWNRFDPB +SMUNNMAWNRFDPB +SMUNNMAWNRFDPB +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +WYYKRDVIBOEORL +WYYKRDVIBOEORL +WYYKRDVIBOEORL +WYYKRDVIBOEORL +WYYKRDVIBOEORL +WYYKRDVIBOEORL +XCGSFFUVFURLIX +XCGSFFUVFURLIX +XCGSFFUVFURLIX +XCGSFFUVFURLIX +XCGSFFUVFURLIX +XCGSFFUVFURLIX +XCGSFFUVFURLIX +XCGSFFUVFURLIX +GBUQOBUNFQDAQG +GBUQOBUNFQDAQG +GBUQOBUNFQDAQG +GBUQOBUNFQDAQG +GBUQOBUNFQDAQG +GBUQOBUNFQDAQG +GBUQOBUNFQDAQG +GBUQOBUNFQDAQG +GBUQOBUNFQDAQG +GBUQOBUNFQDAQG +GBUQOBUNFQDAQG +GBUQOBUNFQDAQG +OFVHHCDOMZQVQV +OFVHHCDOMZQVQV +OFVHHCDOMZQVQV +OFVHHCDOMZQVQV +OFVHHCDOMZQVQV +OFVHHCDOMZQVQV +JDUWHZOLEDOQSR +JDUWHZOLEDOQSR +JDUWHZOLEDOQSR +JDUWHZOLEDOQSR +JDUWHZOLEDOQSR +JDUWHZOLEDOQSR +JDUWHZOLEDOQSR +JDUWHZOLEDOQSR +JDUWHZOLEDOQSR +JDUWHZOLEDOQSR +JDUWHZOLEDOQSR +JDUWHZOLEDOQSR +JDUWHZOLEDOQSR +VSWWTKVILIZDGX +VSWWTKVILIZDGX +VSWWTKVILIZDGX +VSWWTKVILIZDGX +VSWWTKVILIZDGX +VSWWTKVILIZDGX +VSWWTKVILIZDGX +VSWWTKVILIZDGX +VSWWTKVILIZDGX +VSWWTKVILIZDGX +KMDKLWZQLMBIBS +KMDKLWZQLMBIBS +KMDKLWZQLMBIBS +KMDKLWZQLMBIBS +KMDKLWZQLMBIBS +KMDKLWZQLMBIBS +KMDKLWZQLMBIBS +KMDKLWZQLMBIBS +KMDKLWZQLMBIBS +KMDKLWZQLMBIBS +SZINUGQCTHLQAZ +SZINUGQCTHLQAZ +SZINUGQCTHLQAZ +SZINUGQCTHLQAZ +SZINUGQCTHLQAZ +SZINUGQCTHLQAZ +SZINUGQCTHLQAZ +SZINUGQCTHLQAZ +SZINUGQCTHLQAZ +SZINUGQCTHLQAZ +SZINUGQCTHLQAZ +SZINUGQCTHLQAZ +SZINUGQCTHLQAZ +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +YDOTUXAWKBPQJW +RIZAHVBYKWUPHQ +RIZAHVBYKWUPHQ +RIZAHVBYKWUPHQ +RIZAHVBYKWUPHQ +RIZAHVBYKWUPHQ +RIZAHVBYKWUPHQ +RIZAHVBYKWUPHQ +RIZAHVBYKWUPHQ +RIZAHVBYKWUPHQ +RIZAHVBYKWUPHQ +QFDPVUTXKUGISP +QFDPVUTXKUGISP +QFDPVUTXKUGISP +QFDPVUTXKUGISP +QFDPVUTXKUGISP +QFDPVUTXKUGISP +QFDPVUTXKUGISP +QFDPVUTXKUGISP +QFDPVUTXKUGISP +QFDPVUTXKUGISP +QXVAWAHULUVLPT +QXVAWAHULUVLPT +QXVAWAHULUVLPT +QXVAWAHULUVLPT +QXVAWAHULUVLPT +QXVAWAHULUVLPT +QXVAWAHULUVLPT +QXVAWAHULUVLPT +QXVAWAHULUVLPT +QXVAWAHULUVLPT +NESVMZOPWPCFAU +NESVMZOPWPCFAU +NESVMZOPWPCFAU +NESVMZOPWPCFAU +NESVMZOPWPCFAU +NESVMZOPWPCFAU +NESVMZOPWPCFAU +NESVMZOPWPCFAU +NESVMZOPWPCFAU +NESVMZOPWPCFAU +OWKLJRMFTXDULF +OWKLJRMFTXDULF +OWKLJRMFTXDULF +OWKLJRMFTXDULF +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +HZRSNVGNWUDEFX +VGHPMIFEKOFHHQ +VGHPMIFEKOFHHQ +VGHPMIFEKOFHHQ +VGHPMIFEKOFHHQ +VGHPMIFEKOFHHQ +VGHPMIFEKOFHHQ +VGHPMIFEKOFHHQ +VGHPMIFEKOFHHQ +VGHPMIFEKOFHHQ +VGHPMIFEKOFHHQ +VGHPMIFEKOFHHQ +VGHPMIFEKOFHHQ +VGHPMIFEKOFHHQ +VGHPMIFEKOFHHQ +ZGHUDSLVQAGWEY +ZGHUDSLVQAGWEY +ZGHUDSLVQAGWEY +ZGHUDSLVQAGWEY +ZGHUDSLVQAGWEY +ZGHUDSLVQAGWEY +ZGHUDSLVQAGWEY +ZGHUDSLVQAGWEY +ZGHUDSLVQAGWEY +ZGHUDSLVQAGWEY +ZGHUDSLVQAGWEY +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +ACTIUHUUMQJHFO +OWICEWMBIBPFAH +OWICEWMBIBPFAH +OWICEWMBIBPFAH +OWICEWMBIBPFAH +OWICEWMBIBPFAH +OWICEWMBIBPFAH +OWICEWMBIBPFAH +OWICEWMBIBPFAH +OWICEWMBIBPFAH +OWICEWMBIBPFAH +OWICEWMBIBPFAH +OWICEWMBIBPFAH +OWICEWMBIBPFAH +OWICEWMBIBPFAH +OWICEWMBIBPFAH +OWICEWMBIBPFAH +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +DUXYWXYOBMKGIN +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +PVNIQBQSYATKKL +WNYXLVFCZZCCLX +WNYXLVFCZZCCLX +WNYXLVFCZZCCLX +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +BQPNUOYXSVUVMY +UEKHZPDUBLCUHN +UEKHZPDUBLCUHN +UEKHZPDUBLCUHN +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +FOUWCSDKDDHKQP +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +FQXWEKADCSXYOC +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +GJPICJJJRGTNOD +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +KPUREKXXPHOJQT +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +UVBUBMSSQKOIBE +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +YOYLLRBMGQRFTN +YOYLLRBMGQRFTN +YOYLLRBMGQRFTN +YOYLLRBMGQRFTN +YOYLLRBMGQRFTN +YOYLLRBMGQRFTN +YOYLLRBMGQRFTN +YOYLLRBMGQRFTN +YOYLLRBMGQRFTN +YOYLLRBMGQRFTN +YOYLLRBMGQRFTN +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CJBJHOAVZSMMDJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +NHDHVHZZCFYRSB +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +KTUFNOKKBVMGRW +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +MBUVEWMHONZEQD +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +YBBLVLTVTVSKRW +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +HTQMVQVXFRQIKW +FHNINJWBTRXEBC +FHNINJWBTRXEBC +FHNINJWBTRXEBC +FHNINJWBTRXEBC +FHNINJWBTRXEBC +FHNINJWBTRXEBC +FHNINJWBTRXEBC +FHNINJWBTRXEBC +FHNINJWBTRXEBC +FHNINJWBTRXEBC +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +MJJALKDDGIKVBE +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +JOOMJVFZQRQWKR +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +DFJVUWAHTQPQCV +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +KJHKTHWMRKYKJE +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +CWKFPEBMTGKLKX +RCTGMCJBQGBLKT +RCTGMCJBQGBLKT +RCTGMCJBQGBLKT +RCTGMCJBQGBLKT +RCTGMCJBQGBLKT +RCTGMCJBQGBLKT +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +IANUJLZYFUDJIH +NXFQHRVNIOXGAQ +NXFQHRVNIOXGAQ +NXFQHRVNIOXGAQ +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +MFFMDFFZMYYVKS +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +ZNNLBTZKUZBEKO +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +AHTPATJNIAFOLR +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +MVWVFYHBGMAFLY +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +WPALTCMYPARVNV +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +YOSHYTLCDANDAN +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RFHAOTPXVQNOHP +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +PQTBTIFWAXVEPB +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +WYEHFWKAOXOVJD +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +IYIKLHRQXLHMJQ +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +HYAFETHFCAUJAY +MOOFYEJFXBSZGE +MOOFYEJFXBSZGE +MOOFYEJFXBSZGE +MOOFYEJFXBSZGE +MOOFYEJFXBSZGE +MOOFYEJFXBSZGE +MOOFYEJFXBSZGE +MOOFYEJFXBSZGE +MOOFYEJFXBSZGE +MOOFYEJFXBSZGE +MOOFYEJFXBSZGE +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +CIJTVUQEURKBDL +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +DBEPLOCGEIEOCV +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +CTTHWASMBLQOFR +IVBOUFAWPCPFTQ +IVBOUFAWPCPFTQ +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +SCEVFJUWLLRELN +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +LTUNNEGNEKBSEH +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +VMXUWOKSQNHOCA +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +KWLVWJPJKJMCSH +QAEDTLFWHIEVPK +QAEDTLFWHIEVPK +QAEDTLFWHIEVPK +QAEDTLFWHIEVPK +QAEDTLFWHIEVPK +QAEDTLFWHIEVPK +QAEDTLFWHIEVPK +QAEDTLFWHIEVPK +QAEDTLFWHIEVPK +QAEDTLFWHIEVPK +QAEDTLFWHIEVPK +QAEDTLFWHIEVPK +QAEDTLFWHIEVPK +QAEDTLFWHIEVPK +QAEDTLFWHIEVPK +HMCCXLBXIJMERM +HMCCXLBXIJMERM +HMCCXLBXIJMERM +HMCCXLBXIJMERM +HMCCXLBXIJMERM +HMCCXLBXIJMERM +HMCCXLBXIJMERM +HMCCXLBXIJMERM +HMCCXLBXIJMERM +HMCCXLBXIJMERM +HMCCXLBXIJMERM +HMCCXLBXIJMERM +HMCCXLBXIJMERM +HMCCXLBXIJMERM +HMCCXLBXIJMERM +HMCCXLBXIJMERM +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +USAWIVMZUYOXCF +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +FROBCXTULYFHEJ +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +RSMUVYRMZCOLBH +OQXVWJQUBIBIHZ +OQXVWJQUBIBIHZ +OQXVWJQUBIBIHZ +OQXVWJQUBIBIHZ +OQXVWJQUBIBIHZ +OQXVWJQUBIBIHZ +OQXVWJQUBIBIHZ +OQXVWJQUBIBIHZ +OQXVWJQUBIBIHZ +OQXVWJQUBIBIHZ +OQXVWJQUBIBIHZ +OQXVWJQUBIBIHZ +OQXVWJQUBIBIHZ +OQXVWJQUBIBIHZ +OQXVWJQUBIBIHZ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +GHXZTYHSJHQHIJ +SXSGXWCSHSVPGB +SXSGXWCSHSVPGB +SXSGXWCSHSVPGB +SXSGXWCSHSVPGB +SXSGXWCSHSVPGB +SXSGXWCSHSVPGB +SXSGXWCSHSVPGB +SXSGXWCSHSVPGB +SXSGXWCSHSVPGB +SXSGXWCSHSVPGB +SXSGXWCSHSVPGB +SXSGXWCSHSVPGB +SXSGXWCSHSVPGB +SXSGXWCSHSVPGB +KPLFPLUCFPRUHU +KPLFPLUCFPRUHU +KPLFPLUCFPRUHU +KPLFPLUCFPRUHU +KPLFPLUCFPRUHU +KPLFPLUCFPRUHU +KPLFPLUCFPRUHU +KPLFPLUCFPRUHU +KPLFPLUCFPRUHU +KPLFPLUCFPRUHU +KPLFPLUCFPRUHU +KPLFPLUCFPRUHU +KPLFPLUCFPRUHU +KPLFPLUCFPRUHU +KPLFPLUCFPRUHU +KPLFPLUCFPRUHU +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +LMEKQMALGUDUQG +MIABSAQIFYEDJP +MIABSAQIFYEDJP +MIABSAQIFYEDJP +MIABSAQIFYEDJP +MIABSAQIFYEDJP +MIABSAQIFYEDJP +MIABSAQIFYEDJP +MIABSAQIFYEDJP +MIABSAQIFYEDJP +MIABSAQIFYEDJP +MIABSAQIFYEDJP +MIABSAQIFYEDJP +MIABSAQIFYEDJP +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +ZOCSXAVNDGMNBV +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +AOWQKFDVSZMKPA +AOWQKFDVSZMKPA +AOWQKFDVSZMKPA +AOWQKFDVSZMKPA +AOWQKFDVSZMKPA +AOWQKFDVSZMKPA +AOWQKFDVSZMKPA +AOWQKFDVSZMKPA +AOWQKFDVSZMKPA +AOWQKFDVSZMKPA +AOWQKFDVSZMKPA +AOWQKFDVSZMKPA +AOWQKFDVSZMKPA +AOWQKFDVSZMKPA +AOWQKFDVSZMKPA +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +WFDXOXNFNRHQEC +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +RWWYLEGWBNMMLJ +RWWYLEGWBNMMLJ +RWWYLEGWBNMMLJ +RWWYLEGWBNMMLJ +RWWYLEGWBNMMLJ +RWWYLEGWBNMMLJ +RWWYLEGWBNMMLJ +RWWYLEGWBNMMLJ +RWWYLEGWBNMMLJ +RWWYLEGWBNMMLJ +RWWYLEGWBNMMLJ +RWWYLEGWBNMMLJ +RWWYLEGWBNMMLJ +RWWYLEGWBNMMLJ +RWWYLEGWBNMMLJ +RWWYLEGWBNMMLJ +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +SKHXRNHSZTXSLP +VHVPQPYKVGDNFY +VHVPQPYKVGDNFY +VHVPQPYKVGDNFY +VHVPQPYKVGDNFY +VHVPQPYKVGDNFY +VHVPQPYKVGDNFY +VHVPQPYKVGDNFY +VHVPQPYKVGDNFY +VHVPQPYKVGDNFY +VHVPQPYKVGDNFY +VHVPQPYKVGDNFY +VHVPQPYKVGDNFY +VHVPQPYKVGDNFY +VHVPQPYKVGDNFY +VHVPQPYKVGDNFY +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +FZTRDYSPWWJCOF +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +NIFKBBMCXCMCAO +LDLMOOXUCMHBMZ +LDLMOOXUCMHBMZ +LDLMOOXUCMHBMZ +LDLMOOXUCMHBMZ +LDLMOOXUCMHBMZ +LDLMOOXUCMHBMZ +LDLMOOXUCMHBMZ +LDLMOOXUCMHBMZ +LDLMOOXUCMHBMZ +LDLMOOXUCMHBMZ +LDLMOOXUCMHBMZ +LDLMOOXUCMHBMZ +LDLMOOXUCMHBMZ +LDLMOOXUCMHBMZ +LDLMOOXUCMHBMZ +LDLMOOXUCMHBMZ +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +MNJVRJDLRVPLFE +MNJVRJDLRVPLFE +MNJVRJDLRVPLFE +MNJVRJDLRVPLFE +MNJVRJDLRVPLFE +MNJVRJDLRVPLFE +MNJVRJDLRVPLFE +MNJVRJDLRVPLFE +MNJVRJDLRVPLFE +MNJVRJDLRVPLFE +MNJVRJDLRVPLFE +MNJVRJDLRVPLFE +MNJVRJDLRVPLFE +MNJVRJDLRVPLFE +MNJVRJDLRVPLFE +MNJVRJDLRVPLFE +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +CSPPKDPQLUUTND +CSPPKDPQLUUTND +CSPPKDPQLUUTND +CSPPKDPQLUUTND +CSPPKDPQLUUTND +CSPPKDPQLUUTND +CSPPKDPQLUUTND +CSPPKDPQLUUTND +CSPPKDPQLUUTND +BNRNXUUZRGQAQC +BNRNXUUZRGQAQC +BNRNXUUZRGQAQC +BNRNXUUZRGQAQC +BNRNXUUZRGQAQC +BNRNXUUZRGQAQC +BNRNXUUZRGQAQC +BNRNXUUZRGQAQC +BNRNXUUZRGQAQC +BNRNXUUZRGQAQC +BNRNXUUZRGQAQC +BNRNXUUZRGQAQC +BNRNXUUZRGQAQC +BNRNXUUZRGQAQC +XSLGFIQRVCXUEU +XSLGFIQRVCXUEU +XSLGFIQRVCXUEU +XSLGFIQRVCXUEU +XSLGFIQRVCXUEU +XSLGFIQRVCXUEU +XSLGFIQRVCXUEU +XSLGFIQRVCXUEU +XSLGFIQRVCXUEU +XSLGFIQRVCXUEU +XSLGFIQRVCXUEU +XSLGFIQRVCXUEU +XSLGFIQRVCXUEU +XSLGFIQRVCXUEU +UONLDZHKYCFZRW +UONLDZHKYCFZRW +UONLDZHKYCFZRW +UONLDZHKYCFZRW +UONLDZHKYCFZRW +UONLDZHKYCFZRW +UONLDZHKYCFZRW +UONLDZHKYCFZRW +UONLDZHKYCFZRW +UONLDZHKYCFZRW +UONLDZHKYCFZRW +UONLDZHKYCFZRW +UONLDZHKYCFZRW +UONLDZHKYCFZRW +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +ZBNZXTGUTAYRHI +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +GFEGEDUIIYDMOX +GFEGEDUIIYDMOX +GFEGEDUIIYDMOX +GFEGEDUIIYDMOX +GFEGEDUIIYDMOX +GFEGEDUIIYDMOX +GFEGEDUIIYDMOX +GFEGEDUIIYDMOX +GFEGEDUIIYDMOX +GFEGEDUIIYDMOX +GFEGEDUIIYDMOX +GFEGEDUIIYDMOX +GFEGEDUIIYDMOX +GFEGEDUIIYDMOX +JRURYQJSLYLRLN +JRURYQJSLYLRLN +JRURYQJSLYLRLN +JRURYQJSLYLRLN +JRURYQJSLYLRLN +JRURYQJSLYLRLN +GAOZTHIDHYLHMS +GAOZTHIDHYLHMS +GAOZTHIDHYLHMS +GAOZTHIDHYLHMS +GAOZTHIDHYLHMS +GAOZTHIDHYLHMS +GAOZTHIDHYLHMS +GAOZTHIDHYLHMS +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +YGFMQPHTQKCJPI +YGFMQPHTQKCJPI +YGFMQPHTQKCJPI +YGFMQPHTQKCJPI +YGFMQPHTQKCJPI +YGFMQPHTQKCJPI +YGFMQPHTQKCJPI +YGFMQPHTQKCJPI +YGFMQPHTQKCJPI +YGFMQPHTQKCJPI +YGFMQPHTQKCJPI +YGFMQPHTQKCJPI +YGFMQPHTQKCJPI +YGFMQPHTQKCJPI +YGFMQPHTQKCJPI +YGFMQPHTQKCJPI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +GUGOEEXESWIERI +IICRGUKQYYOPIG +IICRGUKQYYOPIG +IICRGUKQYYOPIG +IICRGUKQYYOPIG +IICRGUKQYYOPIG +IICRGUKQYYOPIG +IICRGUKQYYOPIG +IICRGUKQYYOPIG +IICRGUKQYYOPIG +IICRGUKQYYOPIG +IICRGUKQYYOPIG +IICRGUKQYYOPIG +IICRGUKQYYOPIG +IICRGUKQYYOPIG +WLPCAERCXQSYLQ +WLPCAERCXQSYLQ +WLPCAERCXQSYLQ +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +XGHOVGYJHWQGCC +XGHOVGYJHWQGCC +XGHOVGYJHWQGCC +XGHOVGYJHWQGCC +XGHOVGYJHWQGCC +XGHOVGYJHWQGCC +XGHOVGYJHWQGCC +XGHOVGYJHWQGCC +XGHOVGYJHWQGCC +XGHOVGYJHWQGCC +XGHOVGYJHWQGCC +XGHOVGYJHWQGCC +XGHOVGYJHWQGCC +XGHOVGYJHWQGCC +XGHOVGYJHWQGCC +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +WBPYTXDJUQJLPQ +NXFQHRVNIOXGAQ +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +RRZXIRBKKLTSOM +RRZXIRBKKLTSOM +RRZXIRBKKLTSOM +RRZXIRBKKLTSOM +RRZXIRBKKLTSOM +RRZXIRBKKLTSOM +RRZXIRBKKLTSOM +RRZXIRBKKLTSOM +RRZXIRBKKLTSOM +GSPPFJJUCULBDC +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +RWTNPBWLLIMQHL +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +OROAFUQRIXKEMV +UXOWGYHJODZGMF +UXOWGYHJODZGMF +UXOWGYHJODZGMF +UXOWGYHJODZGMF +UXOWGYHJODZGMF +UXOWGYHJODZGMF +UXOWGYHJODZGMF +UXOWGYHJODZGMF +UXOWGYHJODZGMF +UXOWGYHJODZGMF +UXOWGYHJODZGMF +UXOWGYHJODZGMF +UXOWGYHJODZGMF +UXOWGYHJODZGMF +UXOWGYHJODZGMF +UXOWGYHJODZGMF +UXOWGYHJODZGMF +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +DZQSHMPRUIQXPF +DZQSHMPRUIQXPF +SBUJHOSQTJFQJX +SBUJHOSQTJFQJX +SBUJHOSQTJFQJX +SBUJHOSQTJFQJX +SBUJHOSQTJFQJX +SBUJHOSQTJFQJX +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +XMAYWYJOQHXEEK +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +JTZCTMAVMHRNTR +ZDYYWMSLMLTXDM +ZDYYWMSLMLTXDM +ZDYYWMSLMLTXDM +ZDYYWMSLMLTXDM +ZDYYWMSLMLTXDM +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +OHWPIAZSHNMBAC +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +ZDOVFDLIJJGVQM +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +KVEQCVKVIFQSGC +PPCUNNLZTNMXFO +PPCUNNLZTNMXFO +PPCUNNLZTNMXFO +PPCUNNLZTNMXFO +PPCUNNLZTNMXFO +PPCUNNLZTNMXFO +PPCUNNLZTNMXFO +PPCUNNLZTNMXFO +PPCUNNLZTNMXFO +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +WNMJYKCGWZFFKR +DGOAXBPOVUPPEB +DGOAXBPOVUPPEB +DGOAXBPOVUPPEB +DGOAXBPOVUPPEB +DGOAXBPOVUPPEB +DGOAXBPOVUPPEB +DGOAXBPOVUPPEB +DGOAXBPOVUPPEB +KQTVWCSONPJJPE +KQTVWCSONPJJPE +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +LKJPYSCBVHEWIU +CRFYLQMIDWBKRT +CRFYLQMIDWBKRT +CRFYLQMIDWBKRT +CRFYLQMIDWBKRT +CRFYLQMIDWBKRT +CRFYLQMIDWBKRT +CRFYLQMIDWBKRT +CRFYLQMIDWBKRT +CRFYLQMIDWBKRT +VSVAQRUUFVBBFS +VSVAQRUUFVBBFS +VSVAQRUUFVBBFS +VSVAQRUUFVBBFS +VSVAQRUUFVBBFS +VSVAQRUUFVBBFS +VSVAQRUUFVBBFS +VSVAQRUUFVBBFS +VSVAQRUUFVBBFS +UZUGTDHNHPYPHX +UZUGTDHNHPYPHX +UZUGTDHNHPYPHX +UZUGTDHNHPYPHX +UZUGTDHNHPYPHX +UZUGTDHNHPYPHX +UZUGTDHNHPYPHX +UZUGTDHNHPYPHX +UZUGTDHNHPYPHX +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +VWGAYSCWLXQJBQ +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +YIJZJEYQBAAWRJ +AWSZRJQNBMEZOI +AWSZRJQNBMEZOI +AWSZRJQNBMEZOI +AWSZRJQNBMEZOI +AWSZRJQNBMEZOI +AWSZRJQNBMEZOI +AWSZRJQNBMEZOI +AWSZRJQNBMEZOI +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +PCCSBWNGDMYFCW +PCCSBWNGDMYFCW +PCCSBWNGDMYFCW +PCCSBWNGDMYFCW +PCCSBWNGDMYFCW +PCCSBWNGDMYFCW +PCCSBWNGDMYFCW +PCCSBWNGDMYFCW +PCCSBWNGDMYFCW +PCCSBWNGDMYFCW +PCCSBWNGDMYFCW +PCCSBWNGDMYFCW +AIGRXSNSLVJMEA +AIGRXSNSLVJMEA +AIGRXSNSLVJMEA +AIGRXSNSLVJMEA +AIGRXSNSLVJMEA +AIGRXSNSLVJMEA +AIGRXSNSLVJMEA +AIGRXSNSLVJMEA +GGWHBJGBERXSLL +GGWHBJGBERXSLL +GGWHBJGBERXSLL +GGWHBJGBERXSLL +GGWHBJGBERXSLL +GGWHBJGBERXSLL +GGWHBJGBERXSLL +GGWHBJGBERXSLL +GGWHBJGBERXSLL +GGWHBJGBERXSLL +GGWHBJGBERXSLL +GGWHBJGBERXSLL +FNELVJVBIYMIMC +FNELVJVBIYMIMC +FNELVJVBIYMIMC +FNELVJVBIYMIMC +FNELVJVBIYMIMC +FNELVJVBIYMIMC +FNELVJVBIYMIMC +FNELVJVBIYMIMC +FNELVJVBIYMIMC +FNELVJVBIYMIMC +FNELVJVBIYMIMC +CWVRPJSBNHNJSI +CWVRPJSBNHNJSI +CWVRPJSBNHNJSI +CWVRPJSBNHNJSI +CWVRPJSBNHNJSI +CWVRPJSBNHNJSI +CWVRPJSBNHNJSI +CWVRPJSBNHNJSI +IUQAXCIUEPFPSF +IUQAXCIUEPFPSF +IUQAXCIUEPFPSF +IUQAXCIUEPFPSF +IUQAXCIUEPFPSF +IUQAXCIUEPFPSF +IUQAXCIUEPFPSF +IUQAXCIUEPFPSF +IUQAXCIUEPFPSF +IUQAXCIUEPFPSF +IUQAXCIUEPFPSF +IUQAXCIUEPFPSF +KKBGNYHHEIAGOH +KKBGNYHHEIAGOH +KKBGNYHHEIAGOH +KKBGNYHHEIAGOH +KKBGNYHHEIAGOH +KKBGNYHHEIAGOH +KKBGNYHHEIAGOH +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +KDRPFIWYMNONLJ +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +VJFRQMMMXJJUSM +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +HRGWILAIPXJBIB +VMNULHCTRPXWFJ +VMNULHCTRPXWFJ +VMNULHCTRPXWFJ +VMNULHCTRPXWFJ +VMNULHCTRPXWFJ +VMNULHCTRPXWFJ +VMNULHCTRPXWFJ +VMNULHCTRPXWFJ +VMNULHCTRPXWFJ +WNZCDFOXYNRBRB +WNZCDFOXYNRBRB +WNZCDFOXYNRBRB +WNZCDFOXYNRBRB +WNZCDFOXYNRBRB +WNZCDFOXYNRBRB +WNZCDFOXYNRBRB +WNZCDFOXYNRBRB +WNZCDFOXYNRBRB +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +KCAKUFQSCADGHZ +NQRFDNJEBWAUBL +NQRFDNJEBWAUBL +NQRFDNJEBWAUBL +NQRFDNJEBWAUBL +NQRFDNJEBWAUBL +NQRFDNJEBWAUBL +NQRFDNJEBWAUBL +NQRFDNJEBWAUBL +NQRFDNJEBWAUBL +LRNJHZNPJSPMGK +LRNJHZNPJSPMGK +LRNJHZNPJSPMGK +LRNJHZNPJSPMGK +LRNJHZNPJSPMGK +LRNJHZNPJSPMGK +LRNJHZNPJSPMGK +VEUZZDOCACZPRY +VEUZZDOCACZPRY +VEUZZDOCACZPRY +VEUZZDOCACZPRY +VEUZZDOCACZPRY +VEUZZDOCACZPRY +VEUZZDOCACZPRY +VEUZZDOCACZPRY +VEUZZDOCACZPRY +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +MEFOUWRMVYJCQC +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +IKCXDZCEWZARFL +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VPRAQYXPZIFIOH +VPRAQYXPZIFIOH +VPRAQYXPZIFIOH +VPRAQYXPZIFIOH +VPRAQYXPZIFIOH +VPRAQYXPZIFIOH +VPRAQYXPZIFIOH +VPRAQYXPZIFIOH +VPRAQYXPZIFIOH +VPRAQYXPZIFIOH +VPRAQYXPZIFIOH +VPRAQYXPZIFIOH +CWFOCCVIPCEQCK +CWFOCCVIPCEQCK +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +QHUWVQWAKAJLTJ +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +FEVBMCJUKWWWBT +APJLTUBHYCOZJI +APJLTUBHYCOZJI +APJLTUBHYCOZJI +APJLTUBHYCOZJI +APJLTUBHYCOZJI +AGKSTYPVMZODRV +AGKSTYPVMZODRV +AGKSTYPVMZODRV +AGKSTYPVMZODRV +AGKSTYPVMZODRV +AGKSTYPVMZODRV +AGKSTYPVMZODRV +AGKSTYPVMZODRV +MXWAGQASUDSFBG +RLLPVAHGXHCWKJ +RLLPVAHGXHCWKJ +RLLPVAHGXHCWKJ +RLLPVAHGXHCWKJ +RLLPVAHGXHCWKJ +RLLPVAHGXHCWKJ +RLLPVAHGXHCWKJ +RLLPVAHGXHCWKJ +RLLPVAHGXHCWKJ +RLLPVAHGXHCWKJ +RLLPVAHGXHCWKJ +RLLPVAHGXHCWKJ +DHWRNDJOGMTCPB +DHWRNDJOGMTCPB +DHWRNDJOGMTCPB +DHWRNDJOGMTCPB +DHWRNDJOGMTCPB +DHWRNDJOGMTCPB +DHWRNDJOGMTCPB +DHWRNDJOGMTCPB +DHWRNDJOGMTCPB +DHWRNDJOGMTCPB +DHWRNDJOGMTCPB +DHWRNDJOGMTCPB +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +SDMSCIWHRZJSRN +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +HPJKCIUCZWXJDR +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IOYNQIMAUDJVEI +IXBQSRWSVIBXNC +IXBQSRWSVIBXNC +IXBQSRWSVIBXNC +IXBQSRWSVIBXNC +IXBQSRWSVIBXNC +IXBQSRWSVIBXNC +IXBQSRWSVIBXNC +IXBQSRWSVIBXNC +IXBQSRWSVIBXNC +MIOBBYRMXGNORL +MIOBBYRMXGNORL +MIOBBYRMXGNORL +MIOBBYRMXGNORL +MIOBBYRMXGNORL +MIOBBYRMXGNORL +MIOBBYRMXGNORL +MIOBBYRMXGNORL +MIOBBYRMXGNORL +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +SVKHAVSUBSUFBQ +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +JWVKNHDSRADFFA +ZGNITFSDLCMLGI +ZGNITFSDLCMLGI +ZGNITFSDLCMLGI +ZGNITFSDLCMLGI +ZGNITFSDLCMLGI +XMQFTWRPUQYINF +XMQFTWRPUQYINF +XMQFTWRPUQYINF +XMQFTWRPUQYINF +XMQFTWRPUQYINF +XMQFTWRPUQYINF +XMQFTWRPUQYINF +XMQFTWRPUQYINF +XMQFTWRPUQYINF +FVQITOLOYMWVFU +FVQITOLOYMWVFU +FVQITOLOYMWVFU +FVQITOLOYMWVFU +FVQITOLOYMWVFU +FVQITOLOYMWVFU +FVQITOLOYMWVFU +FVQITOLOYMWVFU +FVQITOLOYMWVFU +ORFOPKXBNMVMKC +ORFOPKXBNMVMKC +ORFOPKXBNMVMKC +ORFOPKXBNMVMKC +ORFOPKXBNMVMKC +ORFOPKXBNMVMKC +ORFOPKXBNMVMKC +ORFOPKXBNMVMKC +ORFOPKXBNMVMKC +ORFOPKXBNMVMKC +IMEVJVISCHQJRM +IMEVJVISCHQJRM +IMEVJVISCHQJRM +IMEVJVISCHQJRM +IMEVJVISCHQJRM +IMEVJVISCHQJRM +IMEVJVISCHQJRM +IMEVJVISCHQJRM +IMEVJVISCHQJRM +IMEVJVISCHQJRM +IMEVJVISCHQJRM +IMEVJVISCHQJRM +YXWCBRDRVXHABN +YXWCBRDRVXHABN +YXWCBRDRVXHABN +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +XSNMWAPKHUGZGQ +XSNMWAPKHUGZGQ +XSNMWAPKHUGZGQ +XSNMWAPKHUGZGQ +XSNMWAPKHUGZGQ +XSNMWAPKHUGZGQ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +RUZYUOTYCVRMRZ +IENWMYMSXABSSK +IENWMYMSXABSSK +IENWMYMSXABSSK +IENWMYMSXABSSK +IENWMYMSXABSSK +IENWMYMSXABSSK +IENWMYMSXABSSK +IENWMYMSXABSSK +IENWMYMSXABSSK +CQVYQYUSHAXATN +CQVYQYUSHAXATN +CQVYQYUSHAXATN +CQVYQYUSHAXATN +CQVYQYUSHAXATN +CQVYQYUSHAXATN +CQVYQYUSHAXATN +CQVYQYUSHAXATN +CQVYQYUSHAXATN +CQVYQYUSHAXATN +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +ZTEDFROSGMEYCI +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +WZLBVRXZNDXPPW +YMJPJAXIYLCCRB +HZMMMVGQXDUITB +HZMMMVGQXDUITB +HZMMMVGQXDUITB +HZMMMVGQXDUITB +HZMMMVGQXDUITB +HZMMMVGQXDUITB +HZMMMVGQXDUITB +HZMMMVGQXDUITB +HZMMMVGQXDUITB +HZMMMVGQXDUITB +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +LVUVWJASQQPDSL +XRVDJJPAVOFCOR +XRVDJJPAVOFCOR +XRVDJJPAVOFCOR +XRVDJJPAVOFCOR +XRVDJJPAVOFCOR +XRVDJJPAVOFCOR +XRVDJJPAVOFCOR +XRVDJJPAVOFCOR +QSSHJJFVCWMIKH +GINFBXXYGUODAT +GINFBXXYGUODAT +GINFBXXYGUODAT +GINFBXXYGUODAT +GINFBXXYGUODAT +GINFBXXYGUODAT +GINFBXXYGUODAT +GINFBXXYGUODAT +GINFBXXYGUODAT +GINFBXXYGUODAT +GINFBXXYGUODAT +GINFBXXYGUODAT +GINFBXXYGUODAT +GINFBXXYGUODAT +YVIXXPCJZAUQHJ +YVIXXPCJZAUQHJ +YVIXXPCJZAUQHJ +YVIXXPCJZAUQHJ +YVIXXPCJZAUQHJ +YVIXXPCJZAUQHJ +YVIXXPCJZAUQHJ +YVIXXPCJZAUQHJ +YVIXXPCJZAUQHJ +YVIXXPCJZAUQHJ +YVIXXPCJZAUQHJ +YVIXXPCJZAUQHJ +YVIXXPCJZAUQHJ +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +ZETBBVYSBABLHL +KOKXXPKAPFSRCR +KOKXXPKAPFSRCR +KOKXXPKAPFSRCR +KOKXXPKAPFSRCR +KOKXXPKAPFSRCR +KOKXXPKAPFSRCR +KOKXXPKAPFSRCR +KOKXXPKAPFSRCR +KOKXXPKAPFSRCR +KOKXXPKAPFSRCR +KOKXXPKAPFSRCR +KOKXXPKAPFSRCR +KOKXXPKAPFSRCR +QXWJDGMLSMFETH +QXWJDGMLSMFETH +QXWJDGMLSMFETH +QXWJDGMLSMFETH +QXWJDGMLSMFETH +QXWJDGMLSMFETH +QXWJDGMLSMFETH +QXWJDGMLSMFETH +QXWJDGMLSMFETH +QXWJDGMLSMFETH +QXWJDGMLSMFETH +QXWJDGMLSMFETH +QXWJDGMLSMFETH +QXWJDGMLSMFETH +QXWJDGMLSMFETH +VTWQUFUBSCXPOW +VTWQUFUBSCXPOW +VTWQUFUBSCXPOW +VTWQUFUBSCXPOW +VTWQUFUBSCXPOW +VTWQUFUBSCXPOW +VTWQUFUBSCXPOW +VTWQUFUBSCXPOW +VTWQUFUBSCXPOW +ZHMIOPLMFZVSHY +ZHMIOPLMFZVSHY +ZHMIOPLMFZVSHY +ZHMIOPLMFZVSHY +ZHMIOPLMFZVSHY +ZHMIOPLMFZVSHY +ZHMIOPLMFZVSHY +ZHMIOPLMFZVSHY +QIWQQMZFTOCFGF +QIWQQMZFTOCFGF +QIWQQMZFTOCFGF +QIWQQMZFTOCFGF +QIWQQMZFTOCFGF +QIWQQMZFTOCFGF +QIWQQMZFTOCFGF +QIWQQMZFTOCFGF +QIWQQMZFTOCFGF +QIWQQMZFTOCFGF +QIWQQMZFTOCFGF +QIWQQMZFTOCFGF +QIWQQMZFTOCFGF +QIWQQMZFTOCFGF +QIWQQMZFTOCFGF +QOOXCQFWUYVSGU +OUPZKGBUJRBPGC +OUPZKGBUJRBPGC +OUPZKGBUJRBPGC +OUPZKGBUJRBPGC +OUPZKGBUJRBPGC +OUPZKGBUJRBPGC +FTLQSQQQFMZPKO +FTLQSQQQFMZPKO +FTLQSQQQFMZPKO +FTLQSQQQFMZPKO +FTLQSQQQFMZPKO +FTLQSQQQFMZPKO +FTLQSQQQFMZPKO +FTLQSQQQFMZPKO +FTLQSQQQFMZPKO +FTLQSQQQFMZPKO +FTLQSQQQFMZPKO +FTLQSQQQFMZPKO +FTLQSQQQFMZPKO +FTLQSQQQFMZPKO +FTLQSQQQFMZPKO +IPKZCLGGYKRDES +IPKZCLGGYKRDES +IPKZCLGGYKRDES +AUEUBSJNKBZSKK +AUEUBSJNKBZSKK +AUEUBSJNKBZSKK +FYBFGAFWCBMEDG +FYBFGAFWCBMEDG +FYBFGAFWCBMEDG +VETPHHXZEJAYOB +VETPHHXZEJAYOB +VETPHHXZEJAYOB +GWNOTCOIYUNTQP +GWNOTCOIYUNTQP +GWNOTCOIYUNTQP +TVVXHFWWAYXBNC +TVVXHFWWAYXBNC +TVVXHFWWAYXBNC +TVVXHFWWAYXBNC +TVVXHFWWAYXBNC +TVVXHFWWAYXBNC +TVVXHFWWAYXBNC +TVVXHFWWAYXBNC +TVVXHFWWAYXBNC +TVVXHFWWAYXBNC +TVVXHFWWAYXBNC +TVVXHFWWAYXBNC +TVVXHFWWAYXBNC +TVVXHFWWAYXBNC +TVVXHFWWAYXBNC +PQDRCVHHJPMGKO +PQDRCVHHJPMGKO +PQDRCVHHJPMGKO +PQDRCVHHJPMGKO +PQDRCVHHJPMGKO +PQDRCVHHJPMGKO +PQDRCVHHJPMGKO +PQDRCVHHJPMGKO +PQDRCVHHJPMGKO +PQDRCVHHJPMGKO +PQDRCVHHJPMGKO +PQDRCVHHJPMGKO +PQDRCVHHJPMGKO +PQDRCVHHJPMGKO +PQDRCVHHJPMGKO +GRMDKKJYMUDEJO +GRMDKKJYMUDEJO +GRMDKKJYMUDEJO +QUKKMGJVXHURCY +QUKKMGJVXHURCY +QUKKMGJVXHURCY +FXKFFTMLFPWYFH +FXKFFTMLFPWYFH +FXKFFTMLFPWYFH +NHKWRRHZTGQJMT +NHKWRRHZTGQJMT +NHKWRRHZTGQJMT +NHKWRRHZTGQJMT +NHKWRRHZTGQJMT +NHKWRRHZTGQJMT +NHKWRRHZTGQJMT +NHKWRRHZTGQJMT +NHKWRRHZTGQJMT +NHKWRRHZTGQJMT +NHKWRRHZTGQJMT +NHKWRRHZTGQJMT +NHKWRRHZTGQJMT +NHKWRRHZTGQJMT +NHKWRRHZTGQJMT +YIJYFLXQHDOQGW +YIJYFLXQHDOQGW +YIJYFLXQHDOQGW +YILJWHUIUCRKEU +YILJWHUIUCRKEU +YILJWHUIUCRKEU +YILJWHUIUCRKEU +YILJWHUIUCRKEU +YILJWHUIUCRKEU +YILJWHUIUCRKEU +YILJWHUIUCRKEU +YILJWHUIUCRKEU +YILJWHUIUCRKEU +YILJWHUIUCRKEU +YILJWHUIUCRKEU +YILJWHUIUCRKEU +YILJWHUIUCRKEU +YILJWHUIUCRKEU +YDZPKVMVMXBCHP +YDZPKVMVMXBCHP +YDZPKVMVMXBCHP +ATFARZXNCCWOKJ +ATFARZXNCCWOKJ +NIBCDDKWFDEBEP +NIBCDDKWFDEBEP +NIBCDDKWFDEBEP +NIBCDDKWFDEBEP +NIBCDDKWFDEBEP +NIBCDDKWFDEBEP +NIBCDDKWFDEBEP +NIBCDDKWFDEBEP +NIBCDDKWFDEBEP +NIBCDDKWFDEBEP +NIBCDDKWFDEBEP +NIBCDDKWFDEBEP +NIBCDDKWFDEBEP +GWLFIMOOGVXSMZ +GWLFIMOOGVXSMZ +GWLFIMOOGVXSMZ +GWLFIMOOGVXSMZ +GWLFIMOOGVXSMZ +GWLFIMOOGVXSMZ +GWLFIMOOGVXSMZ +GWLFIMOOGVXSMZ +GWLFIMOOGVXSMZ +GWLFIMOOGVXSMZ +GWLFIMOOGVXSMZ +GWLFIMOOGVXSMZ +GWLFIMOOGVXSMZ +GWLFIMOOGVXSMZ +GWLFIMOOGVXSMZ +KCIDXSZMKJKCSV +KCIDXSZMKJKCSV +KCIDXSZMKJKCSV +KCIDXSZMKJKCSV +KCIDXSZMKJKCSV +KCIDXSZMKJKCSV +KCIDXSZMKJKCSV +KCIDXSZMKJKCSV +KCIDXSZMKJKCSV +KCIDXSZMKJKCSV +KCIDXSZMKJKCSV +KCIDXSZMKJKCSV +KCIDXSZMKJKCSV +KCIDXSZMKJKCSV +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +MGUKYHHAGPFJMC +MGUKYHHAGPFJMC +MGUKYHHAGPFJMC +GHKNHBRWJYMSHK +GHKNHBRWJYMSHK +GHKNHBRWJYMSHK +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +OWSLGPREZQMVQP +OWSLGPREZQMVQP +OWSLGPREZQMVQP +OWSLGPREZQMVQP +OWSLGPREZQMVQP +OWSLGPREZQMVQP +OWSLGPREZQMVQP +OWSLGPREZQMVQP +OWSLGPREZQMVQP +OWSLGPREZQMVQP +OWSLGPREZQMVQP +OWSLGPREZQMVQP +OWSLGPREZQMVQP +OWSLGPREZQMVQP +OWSLGPREZQMVQP +HMXDWDSNPRNUKI +HMXDWDSNPRNUKI +HMXDWDSNPRNUKI +HMXDWDSNPRNUKI +HMXDWDSNPRNUKI +HMXDWDSNPRNUKI +HMXDWDSNPRNUKI +HMXDWDSNPRNUKI +HMXDWDSNPRNUKI +HMXDWDSNPRNUKI +HMXDWDSNPRNUKI +HMXDWDSNPRNUKI +HMXDWDSNPRNUKI +HMXDWDSNPRNUKI +HMXDWDSNPRNUKI +VHHGUBHZBLPTKL +VHHGUBHZBLPTKL +VHHGUBHZBLPTKL +VHHGUBHZBLPTKL +VHHGUBHZBLPTKL +VHHGUBHZBLPTKL +VHHGUBHZBLPTKL +VHHGUBHZBLPTKL +VHHGUBHZBLPTKL +VHHGUBHZBLPTKL +VHHGUBHZBLPTKL +VHHGUBHZBLPTKL +VHHGUBHZBLPTKL +VHHGUBHZBLPTKL +VHHGUBHZBLPTKL +OMSPUVWUIHNYCS +OMSPUVWUIHNYCS +OMSPUVWUIHNYCS +OMSPUVWUIHNYCS +OMSPUVWUIHNYCS +OMSPUVWUIHNYCS +OMSPUVWUIHNYCS +OMSPUVWUIHNYCS +OMSPUVWUIHNYCS +OMSPUVWUIHNYCS +OMSPUVWUIHNYCS +OMSPUVWUIHNYCS +OMSPUVWUIHNYCS +OMSPUVWUIHNYCS +NFDFTMICKVDYLQ +NFDFTMICKVDYLQ +NFDFTMICKVDYLQ +NFDFTMICKVDYLQ +NFDFTMICKVDYLQ +NFDFTMICKVDYLQ +XQUPVDVFXZDTLT +XQUPVDVFXZDTLT +XQUPVDVFXZDTLT +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +RAVIZVQZGXBOQO +KYFWUBJMTHVBIF +KYFWUBJMTHVBIF +KYFWUBJMTHVBIF +YNVKAENVJKEMOU +YNVKAENVJKEMOU +YNVKAENVJKEMOU +YNVKAENVJKEMOU +YNVKAENVJKEMOU +YNVKAENVJKEMOU +YNVKAENVJKEMOU +YNVKAENVJKEMOU +YNVKAENVJKEMOU +YNVKAENVJKEMOU +YNVKAENVJKEMOU +YNVKAENVJKEMOU +YNVKAENVJKEMOU +YNVKAENVJKEMOU +YNVKAENVJKEMOU +WXAKEEQOWUHGCI +WXAKEEQOWUHGCI +WXAKEEQOWUHGCI +WXAKEEQOWUHGCI +WXAKEEQOWUHGCI +WXAKEEQOWUHGCI +WXAKEEQOWUHGCI +WXAKEEQOWUHGCI +WXAKEEQOWUHGCI +WXAKEEQOWUHGCI +WXAKEEQOWUHGCI +KMKWGXGSGPYISJ +KMKWGXGSGPYISJ +KMKWGXGSGPYISJ +PCVPVCFOFVFDQX +PCVPVCFOFVFDQX +PCVPVCFOFVFDQX +MRKXXRUHPFFURP +MRKXXRUHPFFURP +MRKXXRUHPFFURP +IRGFNBRYIWLUOO +IRGFNBRYIWLUOO +IRGFNBRYIWLUOO +IRGFNBRYIWLUOO +IRGFNBRYIWLUOO +IRGFNBRYIWLUOO +IRGFNBRYIWLUOO +IRGFNBRYIWLUOO +IRGFNBRYIWLUOO +IRGFNBRYIWLUOO +IRGFNBRYIWLUOO +IRGFNBRYIWLUOO +IRGFNBRYIWLUOO +IRGFNBRYIWLUOO +IRGFNBRYIWLUOO +GJTKAAFWJZWEPS +GJTKAAFWJZWEPS +GJTKAAFWJZWEPS +GQMZKIPSOYKZFR +GQMZKIPSOYKZFR +GQMZKIPSOYKZFR +OAHRHEHKTRXORG +OAHRHEHKTRXORG +OAHRHEHKTRXORG +NJXZWIIMWNEOGJ +NJXZWIIMWNEOGJ +NJXZWIIMWNEOGJ +WCPJDRQPTLGHOD +WCPJDRQPTLGHOD +SRAQFALNAGNAQE +SRAQFALNAGNAQE +SRAQFALNAGNAQE +KAJJGOCSAXKXBD +KAJJGOCSAXKXBD +KAJJGOCSAXKXBD +KAJJGOCSAXKXBD +KAJJGOCSAXKXBD +KAJJGOCSAXKXBD +KAJJGOCSAXKXBD +KAJJGOCSAXKXBD +KAJJGOCSAXKXBD +KAJJGOCSAXKXBD +KAJJGOCSAXKXBD +KAJJGOCSAXKXBD +KAJJGOCSAXKXBD +KAJJGOCSAXKXBD +DRZXDZYWZSKFDL +DRZXDZYWZSKFDL +DRZXDZYWZSKFDL +DRZXDZYWZSKFDL +DRZXDZYWZSKFDL +DRZXDZYWZSKFDL +DRZXDZYWZSKFDL +DRZXDZYWZSKFDL +DRZXDZYWZSKFDL +DRZXDZYWZSKFDL +DRZXDZYWZSKFDL +DRZXDZYWZSKFDL +DRZXDZYWZSKFDL +DRZXDZYWZSKFDL +DRZXDZYWZSKFDL +IGXZMQCLUNTWCC +IGXZMQCLUNTWCC +IGXZMQCLUNTWCC +AVERNFJXXRIVQN +AVERNFJXXRIVQN +FCBQJNCAKZSIAH +FCBQJNCAKZSIAH +FCBQJNCAKZSIAH +FCBQJNCAKZSIAH +FCBQJNCAKZSIAH +FCBQJNCAKZSIAH +FCBQJNCAKZSIAH +FCBQJNCAKZSIAH +FCBQJNCAKZSIAH +FCBQJNCAKZSIAH +FCBQJNCAKZSIAH +FCBQJNCAKZSIAH +FCBQJNCAKZSIAH +FCBQJNCAKZSIAH +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +HBBVCKCCQCQCTJ +AUMLVMKWJGCERZ +AUMLVMKWJGCERZ +AUMLVMKWJGCERZ +AUMLVMKWJGCERZ +AUMLVMKWJGCERZ +AUMLVMKWJGCERZ +AUMLVMKWJGCERZ +AUMLVMKWJGCERZ +AUMLVMKWJGCERZ +AUMLVMKWJGCERZ +AUMLVMKWJGCERZ +AUMLVMKWJGCERZ +AUMLVMKWJGCERZ +AUMLVMKWJGCERZ +AUMLVMKWJGCERZ +OEMJXSVJXPIFMA +OEMJXSVJXPIFMA +OEMJXSVJXPIFMA +OEMJXSVJXPIFMA +OEMJXSVJXPIFMA +OEMJXSVJXPIFMA +OEMJXSVJXPIFMA +OEMJXSVJXPIFMA +OEMJXSVJXPIFMA +OEMJXSVJXPIFMA +OEMJXSVJXPIFMA +OEMJXSVJXPIFMA +OEMJXSVJXPIFMA +OEMJXSVJXPIFMA +OEMJXSVJXPIFMA +CNIGFESSDPOCKS +CNIGFESSDPOCKS +CNIGFESSDPOCKS +ODTQUKVFOLFLIQ +ODTQUKVFOLFLIQ +ODTQUKVFOLFLIQ +YCOYDOIWSSHVCK +YCOYDOIWSSHVCK +YCOYDOIWSSHVCK +QXNACSREWQXWCV +QXNACSREWQXWCV +QXNACSREWQXWCV +QXNACSREWQXWCV +UFKNDVKQCSBIQE +UFKNDVKQCSBIQE +UFKNDVKQCSBIQE +UFKNDVKQCSBIQE +PBXNNDFKPQPJBB +PBXNNDFKPQPJBB +PBXNNDFKPQPJBB +PBXNNDFKPQPJBB +PBXNNDFKPQPJBB +PBXNNDFKPQPJBB +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +QKUUVGNHUMKUAN +QKUUVGNHUMKUAN +QKUUVGNHUMKUAN +QKUUVGNHUMKUAN +QKUUVGNHUMKUAN +QKUUVGNHUMKUAN +QKUUVGNHUMKUAN +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +GYSCAQFHASJXRS +MQSXZQXHIJMNAF +MQSXZQXHIJMNAF +MQSXZQXHIJMNAF +MQSXZQXHIJMNAF +MQSXZQXHIJMNAF +MQSXZQXHIJMNAF +RNCGDQLZIATDOU +RNCGDQLZIATDOU +RNCGDQLZIATDOU +RNCGDQLZIATDOU +RNCGDQLZIATDOU +RNCGDQLZIATDOU +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +ACNHBCIZLNNLRS +RTNMRJRMTGSUAE +RTNMRJRMTGSUAE +RTNMRJRMTGSUAE +RTNMRJRMTGSUAE +RTNMRJRMTGSUAE +RTNMRJRMTGSUAE +WICHONPZVIYWIJ +WICHONPZVIYWIJ +WICHONPZVIYWIJ +CKVKZAJXACTIEL +CKVKZAJXACTIEL +CKVKZAJXACTIEL +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +QFDPVUTXKUGISP +QFDPVUTXKUGISP +QFDPVUTXKUGISP +QFDPVUTXKUGISP +QFDPVUTXKUGISP +QFDPVUTXKUGISP +QFDPVUTXKUGISP +QFDPVUTXKUGISP +GRBXNADBNJGZRK +GRBXNADBNJGZRK +GRBXNADBNJGZRK +GRBXNADBNJGZRK +GRBXNADBNJGZRK +GRBXNADBNJGZRK +OSUHJPCHFDQAIT +OSUHJPCHFDQAIT +OSUHJPCHFDQAIT +OSUHJPCHFDQAIT +OSUHJPCHFDQAIT +OSUHJPCHFDQAIT +OSUHJPCHFDQAIT +OSUHJPCHFDQAIT +OSUHJPCHFDQAIT +OSUHJPCHFDQAIT +OSUHJPCHFDQAIT +OSUHJPCHFDQAIT +PRUGWHGQBHEDAX +PRUGWHGQBHEDAX +PRUGWHGQBHEDAX +PRUGWHGQBHEDAX +PRUGWHGQBHEDAX +PRUGWHGQBHEDAX +PRUGWHGQBHEDAX +PRUGWHGQBHEDAX +PRUGWHGQBHEDAX +PRUGWHGQBHEDAX +PRUGWHGQBHEDAX +PRUGWHGQBHEDAX +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +XGXOSJSGDNPEEF +BPXVHIRIPLPOPT +BPXVHIRIPLPOPT +BPXVHIRIPLPOPT +BPXVHIRIPLPOPT +BPXVHIRIPLPOPT +BPXVHIRIPLPOPT +BPXVHIRIPLPOPT +BPXVHIRIPLPOPT +BPXVHIRIPLPOPT +BPXVHIRIPLPOPT +ONWXNHPOAGOMTG +ONWXNHPOAGOMTG +ONWXNHPOAGOMTG +ONWXNHPOAGOMTG +ONWXNHPOAGOMTG +ONWXNHPOAGOMTG +ONWXNHPOAGOMTG +ONWXNHPOAGOMTG +ONWXNHPOAGOMTG +ONWXNHPOAGOMTG +ONWXNHPOAGOMTG +ONWXNHPOAGOMTG +ONWXNHPOAGOMTG +ONWXNHPOAGOMTG +ONWXNHPOAGOMTG +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +ZDKIAVFEUPUCMR +ZDKIAVFEUPUCMR +ZDKIAVFEUPUCMR +ZDKIAVFEUPUCMR +ZDKIAVFEUPUCMR +ZDKIAVFEUPUCMR +ZDKIAVFEUPUCMR +ZDKIAVFEUPUCMR +ZDKIAVFEUPUCMR +ZDKIAVFEUPUCMR +ZDKIAVFEUPUCMR +ZDKIAVFEUPUCMR +VKHAHZOOUSRJNA +VKHAHZOOUSRJNA +VKHAHZOOUSRJNA +VKHAHZOOUSRJNA +VKHAHZOOUSRJNA +VKHAHZOOUSRJNA +VKHAHZOOUSRJNA +VKHAHZOOUSRJNA +VKHAHZOOUSRJNA +VKHAHZOOUSRJNA +VKHAHZOOUSRJNA +VKHAHZOOUSRJNA +VKHAHZOOUSRJNA +VKHAHZOOUSRJNA +VKHAHZOOUSRJNA +BJELTSYBAHKXRW +BJELTSYBAHKXRW +BJELTSYBAHKXRW +BJELTSYBAHKXRW +BJELTSYBAHKXRW +BJELTSYBAHKXRW +BJELTSYBAHKXRW +BJELTSYBAHKXRW +BJELTSYBAHKXRW +BJELTSYBAHKXRW +BJELTSYBAHKXRW +BJELTSYBAHKXRW +BJELTSYBAHKXRW +BJELTSYBAHKXRW +BJELTSYBAHKXRW +BJELTSYBAHKXRW +BJELTSYBAHKXRW +FXKFFTMLFPWYFH +FXKFFTMLFPWYFH +FXKFFTMLFPWYFH +FXKFFTMLFPWYFH +FXKFFTMLFPWYFH +FXKFFTMLFPWYFH +FXKFFTMLFPWYFH +FXKFFTMLFPWYFH +FXKFFTMLFPWYFH +FXKFFTMLFPWYFH +FXKFFTMLFPWYFH +FXKFFTMLFPWYFH +YYJNOYZRYGDPNH +YYJNOYZRYGDPNH +YYJNOYZRYGDPNH +YYJNOYZRYGDPNH +YYJNOYZRYGDPNH +YYJNOYZRYGDPNH +YYJNOYZRYGDPNH +YYJNOYZRYGDPNH +YYJNOYZRYGDPNH +YYJNOYZRYGDPNH +YYJNOYZRYGDPNH +YYJNOYZRYGDPNH +APTZNLHMIGJTEW +APTZNLHMIGJTEW +APTZNLHMIGJTEW +APTZNLHMIGJTEW +APTZNLHMIGJTEW +APTZNLHMIGJTEW +APTZNLHMIGJTEW +APTZNLHMIGJTEW +APTZNLHMIGJTEW +APTZNLHMIGJTEW +APTZNLHMIGJTEW +APTZNLHMIGJTEW +CNIGFESSDPOCKS +CNIGFESSDPOCKS +CNIGFESSDPOCKS +CNIGFESSDPOCKS +CNIGFESSDPOCKS +CNIGFESSDPOCKS +CNIGFESSDPOCKS +CNIGFESSDPOCKS +CNIGFESSDPOCKS +CNIGFESSDPOCKS +CNIGFESSDPOCKS +CNIGFESSDPOCKS +CNIGFESSDPOCKS +CNIGFESSDPOCKS +CNIGFESSDPOCKS +GJTKAAFWJZWEPS +GJTKAAFWJZWEPS +GJTKAAFWJZWEPS +GJTKAAFWJZWEPS +GJTKAAFWJZWEPS +GJTKAAFWJZWEPS +GJTKAAFWJZWEPS +GJTKAAFWJZWEPS +GJTKAAFWJZWEPS +GJTKAAFWJZWEPS +GJTKAAFWJZWEPS +GJTKAAFWJZWEPS +IQVNEKKDSLOHHK +IQVNEKKDSLOHHK +IQVNEKKDSLOHHK +IQVNEKKDSLOHHK +IQVNEKKDSLOHHK +IQVNEKKDSLOHHK +IQVNEKKDSLOHHK +IQVNEKKDSLOHHK +IQVNEKKDSLOHHK +QULLOTSYPAOTIW +QULLOTSYPAOTIW +QULLOTSYPAOTIW +QULLOTSYPAOTIW +QULLOTSYPAOTIW +QULLOTSYPAOTIW +QULLOTSYPAOTIW +QULLOTSYPAOTIW +QULLOTSYPAOTIW +QULLOTSYPAOTIW +QULLOTSYPAOTIW +QULLOTSYPAOTIW +PCZLQMGFNUNVOM +PCZLQMGFNUNVOM +PCZLQMGFNUNVOM +PCZLQMGFNUNVOM +PCZLQMGFNUNVOM +PCZLQMGFNUNVOM +PCZLQMGFNUNVOM +PCZLQMGFNUNVOM +PCZLQMGFNUNVOM +PCZLQMGFNUNVOM +PCZLQMGFNUNVOM +PCZLQMGFNUNVOM +ZUBPKHVCBGWWGO +ZUBPKHVCBGWWGO +ZUBPKHVCBGWWGO +ZUBPKHVCBGWWGO +ZUBPKHVCBGWWGO +ZUBPKHVCBGWWGO +ZUBPKHVCBGWWGO +ZUBPKHVCBGWWGO +ZUBPKHVCBGWWGO +ZUBPKHVCBGWWGO +ZUBPKHVCBGWWGO +ZUBPKHVCBGWWGO +MWYHLEQJTQJHSS +MWYHLEQJTQJHSS +MWYHLEQJTQJHSS +MWYHLEQJTQJHSS +MWYHLEQJTQJHSS +MWYHLEQJTQJHSS +MWYHLEQJTQJHSS +MWYHLEQJTQJHSS +MWYHLEQJTQJHSS +MWYHLEQJTQJHSS +MWYHLEQJTQJHSS +MWYHLEQJTQJHSS +MWYHLEQJTQJHSS +MWYHLEQJTQJHSS +MWYHLEQJTQJHSS +MWYHLEQJTQJHSS +IXSZQYVWNJNRAL +IXSZQYVWNJNRAL +IXSZQYVWNJNRAL +IXSZQYVWNJNRAL +IXSZQYVWNJNRAL +IXSZQYVWNJNRAL +IXSZQYVWNJNRAL +IXSZQYVWNJNRAL +IXSZQYVWNJNRAL +IXSZQYVWNJNRAL +IXSZQYVWNJNRAL +IXSZQYVWNJNRAL +IXSZQYVWNJNRAL +IXSZQYVWNJNRAL +ZBRHTUMWSDPCMI +ZBRHTUMWSDPCMI +ZBRHTUMWSDPCMI +ZBRHTUMWSDPCMI +ZBRHTUMWSDPCMI +ZBRHTUMWSDPCMI +ZBRHTUMWSDPCMI +ZBRHTUMWSDPCMI +ZBRHTUMWSDPCMI +ZBRHTUMWSDPCMI +ZBRHTUMWSDPCMI +ZBRHTUMWSDPCMI +XEANIURBPHCHMG +XEANIURBPHCHMG +XEANIURBPHCHMG +XEANIURBPHCHMG +XEANIURBPHCHMG +XEANIURBPHCHMG +XEANIURBPHCHMG +XEANIURBPHCHMG +KYFWUBJMTHVBIF +KYFWUBJMTHVBIF +KYFWUBJMTHVBIF +KYFWUBJMTHVBIF +KYFWUBJMTHVBIF +KYFWUBJMTHVBIF +KYFWUBJMTHVBIF +KYFWUBJMTHVBIF +KYFWUBJMTHVBIF +KYFWUBJMTHVBIF +KYFWUBJMTHVBIF +KYFWUBJMTHVBIF +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +BDNFQGRSKSQXRI +IUHMIOAKWHUFKU +IUHMIOAKWHUFKU +IUHMIOAKWHUFKU +IUHMIOAKWHUFKU +IUHMIOAKWHUFKU +IUHMIOAKWHUFKU +IUHMIOAKWHUFKU +IUHMIOAKWHUFKU +IUHMIOAKWHUFKU +IUHMIOAKWHUFKU +RRNIZKPFKNDSRS +RRNIZKPFKNDSRS +RRNIZKPFKNDSRS +RRNIZKPFKNDSRS +RRNIZKPFKNDSRS +RRNIZKPFKNDSRS +RRNIZKPFKNDSRS +RRNIZKPFKNDSRS +AWXQYTLSBPWDMJ +AWXQYTLSBPWDMJ +AWXQYTLSBPWDMJ +AWXQYTLSBPWDMJ +AWXQYTLSBPWDMJ +AWXQYTLSBPWDMJ +AWXQYTLSBPWDMJ +AWXQYTLSBPWDMJ +AWXQYTLSBPWDMJ +AWXQYTLSBPWDMJ +AWXQYTLSBPWDMJ +GWNOTCOIYUNTQP +GWNOTCOIYUNTQP +GWNOTCOIYUNTQP +GWNOTCOIYUNTQP +GWNOTCOIYUNTQP +GWNOTCOIYUNTQP +GWNOTCOIYUNTQP +GWNOTCOIYUNTQP +GWNOTCOIYUNTQP +GWNOTCOIYUNTQP +GWNOTCOIYUNTQP +GWNOTCOIYUNTQP +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +VEMKTZHHVJILDY +RYVIXQCRCQLFCM +RYVIXQCRCQLFCM +RYVIXQCRCQLFCM +RYVIXQCRCQLFCM +RYVIXQCRCQLFCM +RYVIXQCRCQLFCM +RYVIXQCRCQLFCM +RYVIXQCRCQLFCM +RYVIXQCRCQLFCM +RYVIXQCRCQLFCM +DGFVZQGXKQCQGK +DGFVZQGXKQCQGK +DGFVZQGXKQCQGK +DGFVZQGXKQCQGK +DGFVZQGXKQCQGK +DGFVZQGXKQCQGK +DGFVZQGXKQCQGK +DGFVZQGXKQCQGK +UNYCSANQWMNNCS +UNYCSANQWMNNCS +UNYCSANQWMNNCS +UNYCSANQWMNNCS +UNYCSANQWMNNCS +UNYCSANQWMNNCS +UNYCSANQWMNNCS +UNYCSANQWMNNCS +UNYCSANQWMNNCS +UNYCSANQWMNNCS +UNYCSANQWMNNCS +UNYCSANQWMNNCS +NJXZWIIMWNEOGJ +NJXZWIIMWNEOGJ +NJXZWIIMWNEOGJ +NJXZWIIMWNEOGJ +NJXZWIIMWNEOGJ +NJXZWIIMWNEOGJ +NJXZWIIMWNEOGJ +NJXZWIIMWNEOGJ +NJXZWIIMWNEOGJ +NJXZWIIMWNEOGJ +NJXZWIIMWNEOGJ +NJXZWIIMWNEOGJ +GXPHKUHSUJUWKP +GXPHKUHSUJUWKP +GXPHKUHSUJUWKP +GXPHKUHSUJUWKP +SBNFWQZLDJGRLK +SBNFWQZLDJGRLK +SBNFWQZLDJGRLK +SBNFWQZLDJGRLK +MVMBTNNVZQRZQT +MVMBTNNVZQRZQT +MVMBTNNVZQRZQT +MVMBTNNVZQRZQT +DQFPEYARZIQXRM +DQFPEYARZIQXRM +DQFPEYARZIQXRM +DQFPEYARZIQXRM +DQFPEYARZIQXRM +DQFPEYARZIQXRM +FPSYVUBUILNSRF +FPSYVUBUILNSRF +FPSYVUBUILNSRF +FPSYVUBUILNSRF +FPSYVUBUILNSRF +FPSYVUBUILNSRF +YXZZOMVBHPCKMM +YXZZOMVBHPCKMM +YXZZOMVBHPCKMM +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +JZPKLLLUDLHCEL +JZPKLLLUDLHCEL +JZPKLLLUDLHCEL +JZPKLLLUDLHCEL +JZPKLLLUDLHCEL +JZPKLLLUDLHCEL +JZPKLLLUDLHCEL +JZPKLLLUDLHCEL +JZPKLLLUDLHCEL +JZPKLLLUDLHCEL +JZPKLLLUDLHCEL +SMNDVBDBKRCKDY +SMNDVBDBKRCKDY +SMNDVBDBKRCKDY +SMNDVBDBKRCKDY +SMNDVBDBKRCKDY +SMNDVBDBKRCKDY +FTEIMYUBKWFJIG +FTEIMYUBKWFJIG +YYGNTYWPHWGJRM +YYGNTYWPHWGJRM +RJFFPCHJOFXZQD +RJFFPCHJOFXZQD +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +YPZRWBKMTBYPTK +YPZRWBKMTBYPTK +YPZRWBKMTBYPTK +YPZRWBKMTBYPTK +YPZRWBKMTBYPTK +YPZRWBKMTBYPTK +YPZRWBKMTBYPTK +YPZRWBKMTBYPTK +YPZRWBKMTBYPTK +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +XFSBVAOIAHNAPC +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +SQOJOAFXDQDRGF +SQOJOAFXDQDRGF +SQOJOAFXDQDRGF +SQOJOAFXDQDRGF +SQOJOAFXDQDRGF +SQOJOAFXDQDRGF +SQOJOAFXDQDRGF +SQOJOAFXDQDRGF +SQOJOAFXDQDRGF +SQOJOAFXDQDRGF +ZGVSETXHNHBTRK +ZGVSETXHNHBTRK +ZGVSETXHNHBTRK +ZGVSETXHNHBTRK +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +CPINTEKYWNYXNP +CPINTEKYWNYXNP +CPINTEKYWNYXNP +CPINTEKYWNYXNP +CPINTEKYWNYXNP +TYNQWWGVEGFKRU +TYNQWWGVEGFKRU +TYNQWWGVEGFKRU +TYNQWWGVEGFKRU +TYNQWWGVEGFKRU +TYNQWWGVEGFKRU +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +VSUODASNSRJNCP +VSUODASNSRJNCP +VSUODASNSRJNCP +VSUODASNSRJNCP +VSUODASNSRJNCP +VSUODASNSRJNCP +VSUODASNSRJNCP +VSUODASNSRJNCP +VSUODASNSRJNCP +VSUODASNSRJNCP +VSUODASNSRJNCP +VSUODASNSRJNCP +VSUODASNSRJNCP +VSUODASNSRJNCP +VSUODASNSRJNCP +VSUODASNSRJNCP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +HJRVLGWTJSLQIG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +JTXVTHCLTOUSSL +JTXVTHCLTOUSSL +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +BNDDTTIRGZIQSE +BNDDTTIRGZIQSE +QJMQBJILYFAVTF +QJMQBJILYFAVTF +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +VRNUZAWFZDQEGN +VRNUZAWFZDQEGN +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +LXYJZECGEIAZOD +LXYJZECGEIAZOD +ODQBQUXGRYBRTP +ODQBQUXGRYBRTP +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SQOJOAFXDQDRGF +SQOJOAFXDQDRGF +SQOJOAFXDQDRGF +SQOJOAFXDQDRGF +DYJBTUINEBYYQT +DYJBTUINEBYYQT +UISOORRILGPHLE +UISOORRILGPHLE +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +BEHAFIHZKYCTOR +BEHAFIHZKYCTOR +WEVOWEDEHQFZEV +WEVOWEDEHQFZEV +WEVOWEDEHQFZEV +WEVOWEDEHQFZEV +VSUODASNSRJNCP +VSUODASNSRJNCP +GNMXZMIENAWWKB +GNMXZMIENAWWKB +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +BMLIIPOXVWESJG +CROUPKILZUPLQA +CROUPKILZUPLQA +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +ZNWGBWWXJAYIOM +ZNWGBWWXJAYIOM +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +MADZMXIFUWFDJK +MADZMXIFUWFDJK +RBSZCNOWHDHRFZ +RBSZCNOWHDHRFZ +SDJXJLVNEMUOTE +SDJXJLVNEMUOTE +UZLBTLIRYSYTRG +UZLBTLIRYSYTRG +WXNJNHFYIWEHIL +WXNJNHFYIWEHIL +WXNJNHFYIWEHIL +WXNJNHFYIWEHIL +NWEOPKVXZATAQT +NWEOPKVXZATAQT +SKIRLFVEHUVYJK +SKIRLFVEHUVYJK +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +NNDHDYDFEDRMGH +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +QBVLOMJKKLVAPJ +QBVLOMJKKLVAPJ +IUJLIWQDGYFELW +IUJLIWQDGYFELW +OQAFURZDHYCZMF +OQAFURZDHYCZMF +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +HKQZUYOVMYOFIT +LBRPLJCNRZUXLS +LBRPLJCNRZUXLS +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +BNMGUJRJUUDLHW +QPIBCHJEPFSMPX +QPIBCHJEPFSMPX +IBZLICPLPYSFNZ +IBZLICPLPYSFNZ +HXMZQSGMNGTGGB +HXMZQSGMNGTGGB +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +RIPYIJVYDYCPKW +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +NJUXRKMKOFXMRX +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +SKHJNNFXCKTDBG +MNNGEUSDGJJARF +MNNGEUSDGJJARF +KRFYMPRAIPKTAI +KRFYMPRAIPKTAI +LHKZIVMTXZLOTP +LHKZIVMTXZLOTP +UKGNBVDSWBRBDL +UKGNBVDSWBRBDL +HCKWMBTVENMFOU +HCKWMBTVENMFOU +ICLQXMKQSCTZSF +ICLQXMKQSCTZSF +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +FIDOCHXHMJHKRW +WTKUHKWWAMSHEE +WTKUHKWWAMSHEE +OXQONDBZMLPJFL +OXQONDBZMLPJFL +WROKSUMDFCBDIW +WROKSUMDFCBDIW +SZHUMUJGHFQABW +SZHUMUJGHFQABW +RTCOMQOZOQQHTG +RTCOMQOZOQQHTG +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +XUHJBXVYNBQQBD +YPZRWBKMTBYPTK +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +APKHJGDGWQDBGM +APKHJGDGWQDBGM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +MAEIEVLCKWDQJH +IKQRPFTXKQQLJF +IKQRPFTXKQQLJF +IKQRPFTXKQQLJF +IKQRPFTXKQQLJF +IKQRPFTXKQQLJF +IKQRPFTXKQQLJF +IKQRPFTXKQQLJF +IKQRPFTXKQQLJF +IKQRPFTXKQQLJF +IKQRPFTXKQQLJF +UCSJYZPVAKXKNQ +UCSJYZPVAKXKNQ +UCSJYZPVAKXKNQ +UCSJYZPVAKXKNQ +UCSJYZPVAKXKNQ +UCSJYZPVAKXKNQ +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +NCEXYHBECQHGNR +IDBPHNDTYPBSNI +IDBPHNDTYPBSNI +IDBPHNDTYPBSNI +IDBPHNDTYPBSNI +IDBPHNDTYPBSNI +IDBPHNDTYPBSNI +IDBPHNDTYPBSNI +IDBPHNDTYPBSNI +IDBPHNDTYPBSNI +IDBPHNDTYPBSNI +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +HYPPXZBJBPSRLK +HYPPXZBJBPSRLK +HYPPXZBJBPSRLK +HYPPXZBJBPSRLK +HYPPXZBJBPSRLK +HYPPXZBJBPSRLK +HYPPXZBJBPSRLK +HYPPXZBJBPSRLK +HYPPXZBJBPSRLK +HYPPXZBJBPSRLK +HYPPXZBJBPSRLK +HYPPXZBJBPSRLK +WAEXKFONHRHFBZ +WAEXKFONHRHFBZ +WAEXKFONHRHFBZ +WAEXKFONHRHFBZ +WAEXKFONHRHFBZ +WAEXKFONHRHFBZ +STQGQHZAVUOBTE +STQGQHZAVUOBTE +STQGQHZAVUOBTE +STQGQHZAVUOBTE +STQGQHZAVUOBTE +STQGQHZAVUOBTE +STQGQHZAVUOBTE +STQGQHZAVUOBTE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +HEFIYUQVAZFDEE +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +IENZQIKPVFGBNW +YLXBZBPHTNJZQE +YLXBZBPHTNJZQE +YLXBZBPHTNJZQE +YLXBZBPHTNJZQE +YLXBZBPHTNJZQE +YLXBZBPHTNJZQE +YLXBZBPHTNJZQE +YLXBZBPHTNJZQE +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +QQUHMASGPODSIW +IMMQDEUBEIBIPA +OLBSUIITKHHXBA +QJYRVNWHFQHZKI +YCJXTVMUKTWLCR +BTMHRDSTPWZKMJ +AATCBLYHOUOCTO +SPIUTQOUKAMGCX +SPIUTQOUKAMGCX +SPIUTQOUKAMGCX +SPIUTQOUKAMGCX +KGFYHTZWPPHNLQ +KGFYHTZWPPHNLQ +KGFYHTZWPPHNLQ +KGFYHTZWPPHNLQ +FPUXKXIZEIDQKW +FPUXKXIZEIDQKW +FPUXKXIZEIDQKW +FPUXKXIZEIDQKW +FPUXKXIZEIDQKW +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +HYFHYPWGAURHIV +JDAPIOVVXOAJOM +JDAPIOVVXOAJOM +JDAPIOVVXOAJOM +JDAPIOVVXOAJOM +JDAPIOVVXOAJOM +JDAPIOVVXOAJOM +JDAPIOVVXOAJOM +JDAPIOVVXOAJOM +JDAPIOVVXOAJOM +JDAPIOVVXOAJOM +JDAPIOVVXOAJOM +JDAPIOVVXOAJOM +JDAPIOVVXOAJOM +JDAPIOVVXOAJOM +NNZHGEUZKBYASA +NNZHGEUZKBYASA +DEQITUUQPICUMR +DEQITUUQPICUMR +DEQITUUQPICUMR +DEQITUUQPICUMR +DEQITUUQPICUMR +DEQITUUQPICUMR +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +XLTANAWLDBYGFU +SRRSXTUHQTVABO +SRRSXTUHQTVABO +SRRSXTUHQTVABO +SRRSXTUHQTVABO +SRRSXTUHQTVABO +SRRSXTUHQTVABO +WSMQBJMPWPNLTJ +WSMQBJMPWPNLTJ +WSMQBJMPWPNLTJ +WSMQBJMPWPNLTJ +WSMQBJMPWPNLTJ +WSMQBJMPWPNLTJ +WSMQBJMPWPNLTJ +WSMQBJMPWPNLTJ +WSMQBJMPWPNLTJ +WSMQBJMPWPNLTJ +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +IPQVTOJGNYVQEO +DBUOUVZMYWYRRI +DBUOUVZMYWYRRI +DBUOUVZMYWYRRI +DBUOUVZMYWYRRI +DBUOUVZMYWYRRI +DBUOUVZMYWYRRI +DBUOUVZMYWYRRI +DBUOUVZMYWYRRI +HPSILLNWMJOWNM +HPSILLNWMJOWNM +HPSILLNWMJOWNM +HPSILLNWMJOWNM +HPSILLNWMJOWNM +HPSILLNWMJOWNM +HPSILLNWMJOWNM +CXFIQFGADOTDPF +CXFIQFGADOTDPF +CXFIQFGADOTDPF +CXFIQFGADOTDPF +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +QJJXYPPXXYFBGM +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +MVTLXFDHKDVAIC +MVTLXFDHKDVAIC +MVTLXFDHKDVAIC +MVTLXFDHKDVAIC +MVTLXFDHKDVAIC +MVTLXFDHKDVAIC +MVTLXFDHKDVAIC +MVTLXFDHKDVAIC +MVTLXFDHKDVAIC +MVTLXFDHKDVAIC +MVTLXFDHKDVAIC +MVTLXFDHKDVAIC +MVTLXFDHKDVAIC +MVTLXFDHKDVAIC +MVTLXFDHKDVAIC +KQXDHUJYNAXLNZ +KQXDHUJYNAXLNZ +KQXDHUJYNAXLNZ +KQXDHUJYNAXLNZ +KQXDHUJYNAXLNZ +JFACETXYABVHFD +JFACETXYABVHFD +JFACETXYABVHFD +JFACETXYABVHFD +JFACETXYABVHFD +JFACETXYABVHFD +JFACETXYABVHFD +JFACETXYABVHFD +JFACETXYABVHFD +JFACETXYABVHFD +JFACETXYABVHFD +JFACETXYABVHFD +YMWRMAOPKNYHMZ +YMWRMAOPKNYHMZ +YMWRMAOPKNYHMZ +YMWRMAOPKNYHMZ +PIMZUZSSNYHVCU +PIMZUZSSNYHVCU +PIMZUZSSNYHVCU +PIMZUZSSNYHVCU +AKNILCMFRRDTEY +AKNILCMFRRDTEY +AKNILCMFRRDTEY +AKNILCMFRRDTEY +AKNILCMFRRDTEY +AKNILCMFRRDTEY +AKNILCMFRRDTEY +DJWYOLJPSHDSAL +DJWYOLJPSHDSAL +DJWYOLJPSHDSAL +DJWYOLJPSHDSAL +DJWYOLJPSHDSAL +AAHDJEGSJGYRGS +AAHDJEGSJGYRGS +AAHDJEGSJGYRGS +AAHDJEGSJGYRGS +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +ZWTDABBYXDAIOL +ZWTDABBYXDAIOL +ZWTDABBYXDAIOL +ZWTDABBYXDAIOL +AHTRGGWSBFOEEG +AHTRGGWSBFOEEG +AHTRGGWSBFOEEG +AHTRGGWSBFOEEG +AHTRGGWSBFOEEG +AHTRGGWSBFOEEG +AHTRGGWSBFOEEG +AHTRGGWSBFOEEG +DKRXODJAISNRGA +DKRXODJAISNRGA +DKRXODJAISNRGA +ZVTBPVGTFNEYQP +ZVTBPVGTFNEYQP +ZVTBPVGTFNEYQP +ZVTBPVGTFNEYQP +QBKMGAJNGCTGFA +QBKMGAJNGCTGFA +QBKMGAJNGCTGFA +QBKMGAJNGCTGFA +GODSXGJMZIRXOG +GODSXGJMZIRXOG +GODSXGJMZIRXOG +GODSXGJMZIRXOG +GODSXGJMZIRXOG +GODSXGJMZIRXOG +YRARGBWFOYODHQ +YRARGBWFOYODHQ +YRARGBWFOYODHQ +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +MWLKXILGJPSPKZ +MWLKXILGJPSPKZ +JAYAGJDXJIDEKI +JAYAGJDXJIDEKI +ZQLIAKJHIRHCFA +ZQLIAKJHIRHCFA +ZQLIAKJHIRHCFA +ZQLIAKJHIRHCFA +GGNFGJZLCXTJLH +GGNFGJZLCXTJLH +GGNFGJZLCXTJLH +GGNFGJZLCXTJLH +GGNFGJZLCXTJLH +GGNFGJZLCXTJLH +GGNFGJZLCXTJLH +GGNFGJZLCXTJLH +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +VDSCKSOYNLTQSY +VDSCKSOYNLTQSY +VDSCKSOYNLTQSY +GEZHEQNLKAOMCA +GEZHEQNLKAOMCA +GEZHEQNLKAOMCA +GEZHEQNLKAOMCA +GEZHEQNLKAOMCA +GEZHEQNLKAOMCA +JMBINOWGIHWPJI +JMBINOWGIHWPJI +JMBINOWGIHWPJI +JMBINOWGIHWPJI +JMBINOWGIHWPJI +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +FSBUXLDOLNLABB +FSBUXLDOLNLABB +FSBUXLDOLNLABB +FSBUXLDOLNLABB +SAOOBRUHTPONGX +ZZGVJHSBRGZEML +ZZGVJHSBRGZEML +ZZGVJHSBRGZEML +ZZGVJHSBRGZEML +ZZGVJHSBRGZEML +ZZGVJHSBRGZEML +ZZGVJHSBRGZEML +STQGQHZAVUOBTE +STQGQHZAVUOBTE +STQGQHZAVUOBTE +STQGQHZAVUOBTE +STQGQHZAVUOBTE +KQJSQWZMSAGSHN +KQJSQWZMSAGSHN +KQJSQWZMSAGSHN +KQJSQWZMSAGSHN +KQJSQWZMSAGSHN +KQJSQWZMSAGSHN +KQJSQWZMSAGSHN +KQJSQWZMSAGSHN +KQJSQWZMSAGSHN +KQJSQWZMSAGSHN +KQJSQWZMSAGSHN +KQJSQWZMSAGSHN +KQJSQWZMSAGSHN +KQJSQWZMSAGSHN +UXSACQOOWZMGSE +UXSACQOOWZMGSE +UXSACQOOWZMGSE +UXSACQOOWZMGSE +KVAGRMDUXLYLAZ +KVAGRMDUXLYLAZ +FTNJWQUOZFUQQJ +FTNJWQUOZFUQQJ +FTNJWQUOZFUQQJ +FTNJWQUOZFUQQJ +FTNJWQUOZFUQQJ +FTNJWQUOZFUQQJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +AJTULIWKBMDPCJ +XPLMUADTACCMDJ +XPLMUADTACCMDJ +XPLMUADTACCMDJ +XPLMUADTACCMDJ +XPLMUADTACCMDJ +GRBXNADBNJGZRK +GRBXNADBNJGZRK +GRBXNADBNJGZRK +GRBXNADBNJGZRK +GRBXNADBNJGZRK +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +XJLATMLVMSFZBN +XJLATMLVMSFZBN +XJLATMLVMSFZBN +XJLATMLVMSFZBN +XJLATMLVMSFZBN +XJLATMLVMSFZBN +XJLATMLVMSFZBN +XJLATMLVMSFZBN +XJLATMLVMSFZBN +XJLATMLVMSFZBN +XJLATMLVMSFZBN +REDMIYQFNIRTDF +REDMIYQFNIRTDF +REDMIYQFNIRTDF +REDMIYQFNIRTDF +REDMIYQFNIRTDF +HZUURLOSYMEMET +TYTKCJXGLSJWJW +TYTKCJXGLSJWJW +ORMBYUPZHHWUEM +ORMBYUPZHHWUEM +ORMBYUPZHHWUEM +ORMBYUPZHHWUEM +ORMBYUPZHHWUEM +ORMBYUPZHHWUEM +ORMBYUPZHHWUEM +ORMBYUPZHHWUEM +ORMBYUPZHHWUEM +ORMBYUPZHHWUEM +ORMBYUPZHHWUEM +ORMBYUPZHHWUEM +RUMMZUFGTMKLMC +RUMMZUFGTMKLMC +RUMMZUFGTMKLMC +LGFYNKGLEKBLDA +LGFYNKGLEKBLDA +LGFYNKGLEKBLDA +UDHCHDJLZGYDDM +UDHCHDJLZGYDDM +UDHCHDJLZGYDDM +UDHCHDJLZGYDDM +UDHCHDJLZGYDDM +AEUAVVIPDJTEFS +AEUAVVIPDJTEFS +AEUAVVIPDJTEFS +AEUAVVIPDJTEFS +AEUAVVIPDJTEFS +AEUAVVIPDJTEFS +AEUAVVIPDJTEFS +AEUAVVIPDJTEFS +AEUAVVIPDJTEFS +YLGANLNQTUGMCH +YLGANLNQTUGMCH +YLGANLNQTUGMCH +YLGANLNQTUGMCH +ABTNALLHJFCFRZ +ABTNALLHJFCFRZ +LOTLMZWGLBOKFL +LOTLMZWGLBOKFL +LOTLMZWGLBOKFL +LOTLMZWGLBOKFL +LOTLMZWGLBOKFL +YPZBTERWDWUANF +YPZBTERWDWUANF +YPZBTERWDWUANF +YPZBTERWDWUANF +YPZBTERWDWUANF +YPZBTERWDWUANF +AHAVBLFKEFJGPY +AHAVBLFKEFJGPY +AHAVBLFKEFJGPY +HEZIERXQNQUEDU +HEZIERXQNQUEDU +HEZIERXQNQUEDU +OTAFZEHRJNHBDI +WKIHBIBUCQPPBY +WKIHBIBUCQPPBY +WKIHBIBUCQPPBY +WKIHBIBUCQPPBY +WKIHBIBUCQPPBY +WKIHBIBUCQPPBY +WKIHBIBUCQPPBY +WKIHBIBUCQPPBY +WKIHBIBUCQPPBY +WKIHBIBUCQPPBY +QGQSOVLOEOVNRW +QGQSOVLOEOVNRW +QGQSOVLOEOVNRW +QGQSOVLOEOVNRW +QGQSOVLOEOVNRW +QGQSOVLOEOVNRW +QGQSOVLOEOVNRW +QGQSOVLOEOVNRW +QYCCCSUFDHWKRW +QYCCCSUFDHWKRW +QYCCCSUFDHWKRW +QYCCCSUFDHWKRW +QYCCCSUFDHWKRW +QYCCCSUFDHWKRW +QYCCCSUFDHWKRW +QYCCCSUFDHWKRW +QYCCCSUFDHWKRW +ORXMVTNKIKCWMQ +ORXMVTNKIKCWMQ +ORXMVTNKIKCWMQ +ORXMVTNKIKCWMQ +ORXMVTNKIKCWMQ +ORXMVTNKIKCWMQ +XFLTYUCKJRFDOU +XFLTYUCKJRFDOU +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +IGQSSJMCEJLHAO +SDRRSTAVRUERNC +SDRRSTAVRUERNC +SDRRSTAVRUERNC +SDRRSTAVRUERNC +SDRRSTAVRUERNC +NPVUMVVTBDKDDD +OHRGHFXATDKGOV +OHRGHFXATDKGOV +OHRGHFXATDKGOV +OHRGHFXATDKGOV +OHRGHFXATDKGOV +OHRGHFXATDKGOV +YDHSGSSEZHFAJJ +YDHSGSSEZHFAJJ +YDHSGSSEZHFAJJ +YDHSGSSEZHFAJJ +KLSSFMQBLMDBRQ +RMSKZOXJAHOIER +RMSKZOXJAHOIER +RMSKZOXJAHOIER +RMSKZOXJAHOIER +RMSKZOXJAHOIER +LRHHPZILMPIMIY +LRHHPZILMPIMIY +LRHHPZILMPIMIY +PRWWZXHOHQRKDQ +PRWWZXHOHQRKDQ +PRWWZXHOHQRKDQ +PRWWZXHOHQRKDQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UCLZXGHPVJMYSQ +UOWGLBYIKHMCIS +VBZYLQJSPMDPOO +VBZYLQJSPMDPOO +VBZYLQJSPMDPOO +TYDBFNAOFZIICW +TYDBFNAOFZIICW +JUXUXBIHGDQKND +JUXUXBIHGDQKND +JUXUXBIHGDQKND +JUXUXBIHGDQKND +JUXUXBIHGDQKND +SWRXIGFQDQTNKP +SWRXIGFQDQTNKP +SWRXIGFQDQTNKP +SWRXIGFQDQTNKP +SWRXIGFQDQTNKP +SAMXBYLRDCRTCV +SAMXBYLRDCRTCV +SAMXBYLRDCRTCV +SAMXBYLRDCRTCV +SAMXBYLRDCRTCV +SAMXBYLRDCRTCV +SAMXBYLRDCRTCV +SAMXBYLRDCRTCV +SAMXBYLRDCRTCV +SAMXBYLRDCRTCV +MLSVKXQHUTYXHD +MLSVKXQHUTYXHD +MLSVKXQHUTYXHD +MLSVKXQHUTYXHD +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +VDRDRMCAECTSGB +IVYXJYNRIKSGRV +IVYXJYNRIKSGRV +IVYXJYNRIKSGRV +IVYXJYNRIKSGRV +IVYXJYNRIKSGRV +IVYXJYNRIKSGRV +IVYXJYNRIKSGRV +IVYXJYNRIKSGRV +IVYXJYNRIKSGRV +IVYXJYNRIKSGRV +IVYXJYNRIKSGRV +IVYXJYNRIKSGRV +IVYXJYNRIKSGRV +IVYXJYNRIKSGRV +IVYXJYNRIKSGRV +CNIWQELMLPUFOS +CNIWQELMLPUFOS +ZMOXNUGOJSHBRR +ZMOXNUGOJSHBRR +ZMOXNUGOJSHBRR +ZMOXNUGOJSHBRR +JYHXDMQYXCMDPF +JYHXDMQYXCMDPF +JYHXDMQYXCMDPF +JYHXDMQYXCMDPF +JYHXDMQYXCMDPF +JYHXDMQYXCMDPF +JYHXDMQYXCMDPF +NZNSTOHSZZLSNP +NZNSTOHSZZLSNP +NZNSTOHSZZLSNP +NZNSTOHSZZLSNP +NZNSTOHSZZLSNP +NZNSTOHSZZLSNP +NZNSTOHSZZLSNP +NZNSTOHSZZLSNP +NFINSJKQOBJWEB +NFINSJKQOBJWEB +NFINSJKQOBJWEB +NFINSJKQOBJWEB +NFINSJKQOBJWEB +NFINSJKQOBJWEB +NFINSJKQOBJWEB +NFINSJKQOBJWEB +NFINSJKQOBJWEB +NFINSJKQOBJWEB +NFINSJKQOBJWEB +PPRFIMGXDRYLGD +PPRFIMGXDRYLGD +PPRFIMGXDRYLGD +PPRFIMGXDRYLGD +PPRFIMGXDRYLGD +GQOCHCOFYNMUOJ +GQOCHCOFYNMUOJ +GQOCHCOFYNMUOJ +GQOCHCOFYNMUOJ +GQOCHCOFYNMUOJ +GQOCHCOFYNMUOJ +GQOCHCOFYNMUOJ +GQOCHCOFYNMUOJ +GQOCHCOFYNMUOJ +GQCJWFPDXATUKS +GQCJWFPDXATUKS +GQCJWFPDXATUKS +GQCJWFPDXATUKS +GQCJWFPDXATUKS +GQCJWFPDXATUKS +GQCJWFPDXATUKS +GQCJWFPDXATUKS +GQCJWFPDXATUKS +GQCJWFPDXATUKS +GQCJWFPDXATUKS +GQCJWFPDXATUKS +ZBLWKSUMHLVXAM +ZBLWKSUMHLVXAM +ZBLWKSUMHLVXAM +ZBLWKSUMHLVXAM +BSSWIRVAMSGQMG +BSSWIRVAMSGQMG +BSSWIRVAMSGQMG +BSSWIRVAMSGQMG +BSSWIRVAMSGQMG +BSSWIRVAMSGQMG +BSSWIRVAMSGQMG +BSSWIRVAMSGQMG +BSSWIRVAMSGQMG +BSSWIRVAMSGQMG +KBDOXLBZVFQTMH +KBDOXLBZVFQTMH +KBDOXLBZVFQTMH +KBDOXLBZVFQTMH +KBDOXLBZVFQTMH +KBDOXLBZVFQTMH +KBDOXLBZVFQTMH +KBDOXLBZVFQTMH +KBDOXLBZVFQTMH +KQBFNIVRWYGXRN +KQBFNIVRWYGXRN +KQBFNIVRWYGXRN +KQBFNIVRWYGXRN +KQBFNIVRWYGXRN +QPNFBUARICHXGG +QPNFBUARICHXGG +QPNFBUARICHXGG +QPNFBUARICHXGG +QPNFBUARICHXGG +QPNFBUARICHXGG +JGXZVDAPLSTBGZ +JGXZVDAPLSTBGZ +JGXZVDAPLSTBGZ +JGXZVDAPLSTBGZ +JGXZVDAPLSTBGZ +JGXZVDAPLSTBGZ +YHEIGYJZSXWHJB +YHEIGYJZSXWHJB +YHEIGYJZSXWHJB +YHEIGYJZSXWHJB +YHEIGYJZSXWHJB +YHEIGYJZSXWHJB +YHEIGYJZSXWHJB +YHEIGYJZSXWHJB +YHEIGYJZSXWHJB +YHEIGYJZSXWHJB +YHEIGYJZSXWHJB +YHEIGYJZSXWHJB +YHEIGYJZSXWHJB +CNQCBOHTKBVCFM +CNQCBOHTKBVCFM +CNQCBOHTKBVCFM +CNQCBOHTKBVCFM +CNQCBOHTKBVCFM +CNQCBOHTKBVCFM +CNQCBOHTKBVCFM +CNQCBOHTKBVCFM +HKVGJQVJNQRJPO +HKVGJQVJNQRJPO +MGEVYVDQMTWJNV +MGEVYVDQMTWJNV +MGEVYVDQMTWJNV +MGEVYVDQMTWJNV +MGEVYVDQMTWJNV +MGEVYVDQMTWJNV +MGEVYVDQMTWJNV +MGEVYVDQMTWJNV +MGEVYVDQMTWJNV +MGEVYVDQMTWJNV +MGEVYVDQMTWJNV +MGEVYVDQMTWJNV +MGEVYVDQMTWJNV +HWTKLHMQRXNNDR +HWTKLHMQRXNNDR +HWTKLHMQRXNNDR +HWTKLHMQRXNNDR +HWTKLHMQRXNNDR +ZGNUJHGCJSHIQU +ZAWVKTOAAOBPLL +ZAWVKTOAAOBPLL +ZAWVKTOAAOBPLL +XJDJODWHDUVAGF +XJDJODWHDUVAGF +XJDJODWHDUVAGF +XJDJODWHDUVAGF +XJDJODWHDUVAGF +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PTDAHAWQAGSZDD +PQXBZFLVJGBOAD +PQXBZFLVJGBOAD +PQXBZFLVJGBOAD +PQXBZFLVJGBOAD +PQXBZFLVJGBOAD +PQXBZFLVJGBOAD +PQXBZFLVJGBOAD +PQXBZFLVJGBOAD +PQXBZFLVJGBOAD +PQXBZFLVJGBOAD +PQXBZFLVJGBOAD +RWXIFXNRCLMQCD +UZIOUZHBUYLDHW +UZIOUZHBUYLDHW +UZIOUZHBUYLDHW +UZIOUZHBUYLDHW +CKZNKYSWWCSICZ +CKZNKYSWWCSICZ +CKZNKYSWWCSICZ +CKZNKYSWWCSICZ +MEUCDRGPRSOAHE +MEUCDRGPRSOAHE +MEUCDRGPRSOAHE +MEUCDRGPRSOAHE +MEUCDRGPRSOAHE +MEUCDRGPRSOAHE +MEUCDRGPRSOAHE +MEUCDRGPRSOAHE +ZYZHMHXSPPAVCD +ZYZHMHXSPPAVCD +ZYZHMHXSPPAVCD +GFFOBQNFESRPJR +GFFOBQNFESRPJR +GFFOBQNFESRPJR +JLMGCBFIPZDHLZ +QIOMMMCQFIBVKA +QIOMMMCQFIBVKA +QIOMMMCQFIBVKA +QIOMMMCQFIBVKA +QIOMMMCQFIBVKA +JYQIWENZJDPRSV +JYQIWENZJDPRSV +JYQIWENZJDPRSV +JYQIWENZJDPRSV +JYQIWENZJDPRSV +YQDJUXPUIRGKNV +YQDJUXPUIRGKNV +YQDJUXPUIRGKNV +YQDJUXPUIRGKNV +YQDJUXPUIRGKNV +YQDJUXPUIRGKNV +YQDJUXPUIRGKNV +YQDJUXPUIRGKNV +YQDJUXPUIRGKNV +SLGMSTJSVRGVPB +SLGMSTJSVRGVPB +FPJJIWCMASJCHO +FPJJIWCMASJCHO +FPJJIWCMASJCHO +FPJJIWCMASJCHO +FPJJIWCMASJCHO +MFQDKOXWQXOOAO +MFQDKOXWQXOOAO +MFQDKOXWQXOOAO +MFQDKOXWQXOOAO +MFQDKOXWQXOOAO +MFQDKOXWQXOOAO +MFQDKOXWQXOOAO +MFQDKOXWQXOOAO +MFQDKOXWQXOOAO +MFQDKOXWQXOOAO +MFQDKOXWQXOOAO +DQBXBQIOPVLJEV +DQBXBQIOPVLJEV +DQBXBQIOPVLJEV +DQBXBQIOPVLJEV +IUXOFSAPFXGQID +IUXOFSAPFXGQID +IUXOFSAPFXGQID +IUXOFSAPFXGQID +AEBORMNUOJEQOL +AEBORMNUOJEQOL +AEBORMNUOJEQOL +AEBORMNUOJEQOL +AEBORMNUOJEQOL +VTQUQEWGIJRVHB +VTQUQEWGIJRVHB +VTQUQEWGIJRVHB +VTQUQEWGIJRVHB +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +QBKSWRVVCFFDOT +DJWYOLJPSHDSAL +DJWYOLJPSHDSAL +DJWYOLJPSHDSAL +TYTKCJXGLSJWJW +TYTKCJXGLSJWJW +TYTKCJXGLSJWJW +TYTKCJXGLSJWJW +TYTKCJXGLSJWJW +TYTKCJXGLSJWJW +AVAQRWVGWWNBIN +AVAQRWVGWWNBIN +PAEOIXITAYMQRF +PAEOIXITAYMQRF +PAEOIXITAYMQRF +PAEOIXITAYMQRF +PAEOIXITAYMQRF +PAEOIXITAYMQRF +PAEOIXITAYMQRF +ATNAJMVRCNQHAG +ATNAJMVRCNQHAG +JGUYJMIAKPTIAH +JGUYJMIAKPTIAH +JGUYJMIAKPTIAH +JGUYJMIAKPTIAH +JGUYJMIAKPTIAH +JGUYJMIAKPTIAH +JGUYJMIAKPTIAH +AKFIXMYXISUTAF +AKFIXMYXISUTAF +AKFIXMYXISUTAF +AKFIXMYXISUTAF +MVWXLRYZCZSBKW +MVWXLRYZCZSBKW +WJPRKOJNQIZCGY +WJPRKOJNQIZCGY +WJPRKOJNQIZCGY +WJPRKOJNQIZCGY +ISQUNAAALVXWGI +ISQUNAAALVXWGI +AZKQDXZMKREFDY +AZKQDXZMKREFDY +AZKQDXZMKREFDY +AZKQDXZMKREFDY +TYXFVKGQQWDJKA +TYXFVKGQQWDJKA +LEXLFIULVWKBPT +LEXLFIULVWKBPT +LEXLFIULVWKBPT +LEXLFIULVWKBPT +ZFDAUYPBCXMSBF +ZFDAUYPBCXMSBF +ZFDAUYPBCXMSBF +ZFDAUYPBCXMSBF +ZFDAUYPBCXMSBF +ZFDAUYPBCXMSBF +ZFDAUYPBCXMSBF +ZFDAUYPBCXMSBF +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +OUMWCYMRLMEZJH +JMRJLJOBHHWYIV +JMRJLJOBHHWYIV +JMRJLJOBHHWYIV +JMRJLJOBHHWYIV +JMRJLJOBHHWYIV +JMRJLJOBHHWYIV +JMRJLJOBHHWYIV +JMRJLJOBHHWYIV +JMRJLJOBHHWYIV +JMRJLJOBHHWYIV +JMRJLJOBHHWYIV +JMRJLJOBHHWYIV +JMRJLJOBHHWYIV +JMRJLJOBHHWYIV +JFYYCQXZVIOBKU +JFYYCQXZVIOBKU +JFYYCQXZVIOBKU +JFYYCQXZVIOBKU +JFYYCQXZVIOBKU +JFYYCQXZVIOBKU +XYUFCXJZFZPEJD +XYUFCXJZFZPEJD +XYUFCXJZFZPEJD +XYUFCXJZFZPEJD +XYUFCXJZFZPEJD +XYUFCXJZFZPEJD +XYUFCXJZFZPEJD +XYUFCXJZFZPEJD +VWHCJIZYMBSOMV +VWHCJIZYMBSOMV +VWHCJIZYMBSOMV +VWHCJIZYMBSOMV +VWHCJIZYMBSOMV +VWHCJIZYMBSOMV +VWHCJIZYMBSOMV +VWHCJIZYMBSOMV +VWHCJIZYMBSOMV +VWHCJIZYMBSOMV +VWHCJIZYMBSOMV +RBCXKPQLDXSOQW +RBCXKPQLDXSOQW +RBCXKPQLDXSOQW +RBCXKPQLDXSOQW +RBCXKPQLDXSOQW +KRXLVSZOLMEYHF +KRXLVSZOLMEYHF +XZFSMUXVAYCHFO +XZFSMUXVAYCHFO +XZFSMUXVAYCHFO +XZFSMUXVAYCHFO +XZFSMUXVAYCHFO +XZFSMUXVAYCHFO +XZFSMUXVAYCHFO +XZFSMUXVAYCHFO +XZFSMUXVAYCHFO +XZFSMUXVAYCHFO +GAIVGINVGXHEIA +GAIVGINVGXHEIA +GAIVGINVGXHEIA +GAIVGINVGXHEIA +IRBLIRNSGBXQFB +IRBLIRNSGBXQFB +IRBLIRNSGBXQFB +DVLLGHPCJPEUHA +DVLLGHPCJPEUHA +DVLLGHPCJPEUHA +DVLLGHPCJPEUHA +DVLLGHPCJPEUHA +DVLLGHPCJPEUHA +DVLLGHPCJPEUHA +JGQBYBXYRUCBQY +JGQBYBXYRUCBQY +OFUTZNNUWRTXHO +OFUTZNNUWRTXHO +RCOCBDNPQGVEDL +RCOCBDNPQGVEDL +RCOCBDNPQGVEDL +QOMBXPYXWGTFNR +MYLOBISKHDRNEW +MYLOBISKHDRNEW +OFOUJHGWJJEVMF +OFOUJHGWJJEVMF +VVWSVSOPOPDXMM +KFNWMXLJLRPJCL +KFNWMXLJLRPJCL +KFNWMXLJLRPJCL +NNWMHSNRRWMMBI +NNWMHSNRRWMMBI +NNWMHSNRRWMMBI +FOAPBJMMOXYHAN +FOAPBJMMOXYHAN +FOAPBJMMOXYHAN +PSFMBXYUQFAGAM +PSFMBXYUQFAGAM +PSFMBXYUQFAGAM +PSFMBXYUQFAGAM +OTGHTIDLDTWPFJ +OTGHTIDLDTWPFJ +OTGHTIDLDTWPFJ +CBJNLOVRAFQEQH +CBJNLOVRAFQEQH +CBJNLOVRAFQEQH +CBJNLOVRAFQEQH +VJOIIYDQDMELSU +VJOIIYDQDMELSU +VJOIIYDQDMELSU +RXOMDRQVYULRRU +RXOMDRQVYULRRU +RXOMDRQVYULRRU +RXOMDRQVYULRRU +RXOMDRQVYULRRU +RXOMDRQVYULRRU +MJPYNCPSXRTGEE +MJPYNCPSXRTGEE +MJPYNCPSXRTGEE +DHHMFNAGLVIOCZ +DHHMFNAGLVIOCZ +DHHMFNAGLVIOCZ +DHHMFNAGLVIOCZ +DHHMFNAGLVIOCZ +RNUHPRWYDXEBOM +RNUHPRWYDXEBOM +QUCGBWQRLWOVBR +QUCGBWQRLWOVBR +CPRXVUOMCYXPHA +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +UXDPXZQHTDAXOZ +HPLALXILNGTIHC +HPLALXILNGTIHC +HPLALXILNGTIHC +HPLALXILNGTIHC +HPLALXILNGTIHC +HPLALXILNGTIHC +HPLALXILNGTIHC +HPLALXILNGTIHC +HPDJFHJDZYIBCP +HPDJFHJDZYIBCP +HPDJFHJDZYIBCP +HPDJFHJDZYIBCP +VEDWXCWBMDQNCV +VEDWXCWBMDQNCV +VEDWXCWBMDQNCV +VEDWXCWBMDQNCV +VEDWXCWBMDQNCV +VEDWXCWBMDQNCV +VEDWXCWBMDQNCV +VEDWXCWBMDQNCV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +UHJAFZZGOSOFFV +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +OZDABLANSWPSGY +KHQMXKRETWUVJU +KHQMXKRETWUVJU +AROQRNPRGIWLRE +AROQRNPRGIWLRE +AROQRNPRGIWLRE +AROQRNPRGIWLRE +AROQRNPRGIWLRE +MEYZYGMYMLNUHJ +MEYZYGMYMLNUHJ +MEYZYGMYMLNUHJ +MEYZYGMYMLNUHJ +MEYZYGMYMLNUHJ +QZMAEZWZCGBZFK +QZMAEZWZCGBZFK +QZMAEZWZCGBZFK +QZMAEZWZCGBZFK +QZMAEZWZCGBZFK +QZMAEZWZCGBZFK +QZMAEZWZCGBZFK +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +AVJNWIDNAJCPRK +AVJNWIDNAJCPRK +GGYFTLUVQMVCMN +CLQAMCIMWDLXGK +CLQAMCIMWDLXGK +HRDMCVCODUFPBQ +HRDMCVCODUFPBQ +HRDMCVCODUFPBQ +HRDMCVCODUFPBQ +IAGSHEHQJJTLLR +IAGSHEHQJJTLLR +IAGSHEHQJJTLLR +IAGSHEHQJJTLLR +MYHLDHTXTZOTIK +MYHLDHTXTZOTIK +MYHLDHTXTZOTIK +BCUDKRWNGQAFLF +BCUDKRWNGQAFLF +BCUDKRWNGQAFLF +BCUDKRWNGQAFLF +BCUDKRWNGQAFLF +BCUDKRWNGQAFLF +OSHZDTNWJYPSSP +OSHZDTNWJYPSSP +OSHZDTNWJYPSSP +OSHZDTNWJYPSSP +OSHZDTNWJYPSSP +OSHZDTNWJYPSSP +NQXDDVZOWBZZHN +NQXDDVZOWBZZHN +JGHUOJAZXGSFRI +JGHUOJAZXGSFRI +JGHUOJAZXGSFRI +JGHUOJAZXGSFRI +JGHUOJAZXGSFRI +JKLAVFMVEROOKJ +JKLAVFMVEROOKJ +JKLAVFMVEROOKJ +JKLAVFMVEROOKJ +RTQZACYXEASSEF +RTQZACYXEASSEF +RTQZACYXEASSEF +RTQZACYXEASSEF +RTQZACYXEASSEF +RTQZACYXEASSEF +RTQZACYXEASSEF +SCIGYBYAZUFDLA +SCIGYBYAZUFDLA +SCIGYBYAZUFDLA +SCIGYBYAZUFDLA +SCIGYBYAZUFDLA +SCIGYBYAZUFDLA +RYEFFICCPKWYML +RYEFFICCPKWYML +RYEFFICCPKWYML +RYEFFICCPKWYML +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YOFHAHMLGOFXAB +YOFHAHMLGOFXAB +WBCMGDNFDRNGGZ +WBCMGDNFDRNGGZ +TZLCZBLLJUXBSB +TZLCZBLLJUXBSB +TZLCZBLLJUXBSB +TZLCZBLLJUXBSB +TZLCZBLLJUXBSB +QNYOCAYOHKMFCQ +QNYOCAYOHKMFCQ +QNYOCAYOHKMFCQ +QNYOCAYOHKMFCQ +QNYOCAYOHKMFCQ +GBGKVNUYCBHABP +GBGKVNUYCBHABP +GBGKVNUYCBHABP +GBGKVNUYCBHABP +GBGKVNUYCBHABP +GBGKVNUYCBHABP +GBGKVNUYCBHABP +GBGKVNUYCBHABP +GBGKVNUYCBHABP +GBGKVNUYCBHABP +GBGKVNUYCBHABP +GBGKVNUYCBHABP +LSHAJDRFVTXNOB +LSHAJDRFVTXNOB +LSHAJDRFVTXNOB +LSHAJDRFVTXNOB +MIPXDZVPQOJPHM +MIPXDZVPQOJPHM +MIPXDZVPQOJPHM +MIPXDZVPQOJPHM +MIPXDZVPQOJPHM +MIPXDZVPQOJPHM +MIPXDZVPQOJPHM +MIPXDZVPQOJPHM +MIPXDZVPQOJPHM +MIPXDZVPQOJPHM +GSAWBDXYMSQMRT +GSAWBDXYMSQMRT +GSAWBDXYMSQMRT +GSAWBDXYMSQMRT +OIMUSOLEDHKDCV +OIMUSOLEDHKDCV +OIMUSOLEDHKDCV +OIMUSOLEDHKDCV +OIMUSOLEDHKDCV +YKRGDOXKVOZESV +YKRGDOXKVOZESV +YKRGDOXKVOZESV +YKRGDOXKVOZESV +YKRGDOXKVOZESV +YKRGDOXKVOZESV +YKRGDOXKVOZESV +YKRGDOXKVOZESV +YKRGDOXKVOZESV +YKRGDOXKVOZESV +YKRGDOXKVOZESV +YKRGDOXKVOZESV +LPLWWIHUJXWQSS +LPLWWIHUJXWQSS +CNURKUNYCXCBEK +CNURKUNYCXCBEK +JAYAGJDXJIDEKI +JAYAGJDXJIDEKI +JAYAGJDXJIDEKI +RZPAKFUAFGMUPI +RZPAKFUAFGMUPI +RZPAKFUAFGMUPI +ZEASWHWETFMWCV +ZEASWHWETFMWCV +LBRPLJCNRZUXLS +LBRPLJCNRZUXLS +LBRPLJCNRZUXLS +NNOMPFCNQCRAIO +NNOMPFCNQCRAIO +NNOMPFCNQCRAIO +WFMPZQDIRPRCNA +WFMPZQDIRPRCNA +WFMPZQDIRPRCNA +RPJBXUNEXVNBIF +RPJBXUNEXVNBIF +RPJBXUNEXVNBIF +RPJBXUNEXVNBIF +RPJBXUNEXVNBIF +RPJBXUNEXVNBIF +LZXXRASHAINSDN +LZXXRASHAINSDN +PQTARGHEXNJCRK +PQTARGHEXNJCRK +PQTARGHEXNJCRK +NUYFKDBCHFKOBT +JVCNHGXAVMINTN +JVCNHGXAVMINTN +JVCNHGXAVMINTN +RCNSAJSGRJSBKK +RCNSAJSGRJSBKK +RCNSAJSGRJSBKK +RCNSAJSGRJSBKK +RCNSAJSGRJSBKK +RCNSAJSGRJSBKK +RCNSAJSGRJSBKK +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +PYJMYPPFWASOJX +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +WFRQIKSNAYYUJZ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +AMOGMTLMADGEOQ +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +WYQVAPGDARQUBT +CPINTEKYWNYXNP +CPINTEKYWNYXNP +CPINTEKYWNYXNP +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +LWSPRPDSPCBAKK +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +SOFSXTKPGSIDCI +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +RZBFPDQKWUWUCK +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +BAWFJGJZGIEFAR +LLPWNQMSUYAGQI +KVHFYBWKXJPMMM +KVHFYBWKXJPMMM +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +SWIROVJVGRGSPO +SWIROVJVGRGSPO +RXWNCPJZOCPEPQ +RXWNCPJZOCPEPQ +RXWNCPJZOCPEPQ +RXWNCPJZOCPEPQ +RXWNCPJZOCPEPQ +RXWNCPJZOCPEPQ +RXWNCPJZOCPEPQ +YKRGDOXKVOZESV +YKRGDOXKVOZESV +BRZYSWJRSDMWLG +SVQZFPSKTHNMRD +XNBNKCLBGTWWSD +XNBNKCLBGTWWSD +XNBNKCLBGTWWSD +RCNSAJSGRJSBKK +RCNSAJSGRJSBKK +RCNSAJSGRJSBKK +RCNSAJSGRJSBKK +RCNSAJSGRJSBKK +RCNSAJSGRJSBKK +RCNSAJSGRJSBKK +RCNSAJSGRJSBKK +RCNSAJSGRJSBKK +FRKBGPSXUBCIFE +FRKBGPSXUBCIFE +FRKBGPSXUBCIFE +FRKBGPSXUBCIFE +FRKBGPSXUBCIFE +FRKBGPSXUBCIFE +FRKBGPSXUBCIFE +FRKBGPSXUBCIFE +FRKBGPSXUBCIFE +TYEPIVMWBGXYTG +TYEPIVMWBGXYTG +TYEPIVMWBGXYTG +TYEPIVMWBGXYTG +TYEPIVMWBGXYTG +TYEPIVMWBGXYTG +TYEPIVMWBGXYTG +TYEPIVMWBGXYTG +TYEPIVMWBGXYTG +AOJSSPVGVAZWDZ +AOJSSPVGVAZWDZ +AOJSSPVGVAZWDZ +AOJSSPVGVAZWDZ +AOJSSPVGVAZWDZ +AOJSSPVGVAZWDZ +AOJSSPVGVAZWDZ +AOJSSPVGVAZWDZ +ZVLQSTJJNQGNBZ +ZVLQSTJJNQGNBZ +ZVLQSTJJNQGNBZ +ZVLQSTJJNQGNBZ +ZVLQSTJJNQGNBZ +ZVLQSTJJNQGNBZ +ZVLQSTJJNQGNBZ +ZVLQSTJJNQGNBZ +ZVLQSTJJNQGNBZ +ZVLQSTJJNQGNBZ +BUWFHGJSHMKENO +BUWFHGJSHMKENO +BUWFHGJSHMKENO +BUWFHGJSHMKENO +BUWFHGJSHMKENO +BUWFHGJSHMKENO +BUWFHGJSHMKENO +BUWFHGJSHMKENO +BUWFHGJSHMKENO +BUWFHGJSHMKENO +BUWFHGJSHMKENO +ZRBVUIRPSABEGI +ZRBVUIRPSABEGI +ZRBVUIRPSABEGI +ZRBVUIRPSABEGI +ZRBVUIRPSABEGI +ZRBVUIRPSABEGI +ZRBVUIRPSABEGI +ZRBVUIRPSABEGI +ZRBVUIRPSABEGI +ZRBVUIRPSABEGI +ZRBVUIRPSABEGI +ZRBVUIRPSABEGI +ZRBVUIRPSABEGI +ZRBVUIRPSABEGI +HKOVMJGGVHCEHW +HKOVMJGGVHCEHW +SQMNFHPUBGPPHN +PSYJEEMZZIZTSR +VPQYPSQTVRUBGP +UHVGJHQDVDVQHH +PPWXFRKGROMJCW +WZTHYPKDVIMHHT +OORSNEDYAQMZLO +NDEOTZXSBKCQLS +SCLHBVYXOLVAFF +XIPRBTBTNIAVMG +ZLHZLMOSPGACSZ +ZLHZLMOSPGACSZ +ZLHZLMOSPGACSZ +ZLHZLMOSPGACSZ +GZOINQXUFGBYFY +DDIJQXQEXWWXTD +NSJSZWWHLTXYLL +NSJSZWWHLTXYLL +XCJMUIWIEQFAQX +DCTLEVDGGICUNO +UBYPYZJJWXISEX +IQDINESGSGSYHN +LOFURYWJDOAONN +IGEXZUWFYCYQFB +ARFHIAQFJWUCFH +BDFAHNBRQVAVII +BVQDZSFUVFXFCD +OJFZYAQGMWSUID +QXXZLJQFZPCDQK +QXXZLJQFZPCDQK +UVRPNNHYEHVDTJ +SDPWANAOAUDRFV +LNPHKHANJCYWMS +HOPAEXGXDXUDED +OJKRCDAVAIKJBQ +OJKRCDAVAIKJBQ +NEZTYZLKZFROFG +GTWOKQIGBJADIZ +QCGAHSHQTXYFSB +GBDXIBWIVZCVKE +OYZYVBKQMLQLPM +WCSODLHQPQAIJK +SNIHFZNFPCCTSV +FKKOFCADPKTONJ +QOUIVZIZMDEBJC +OCPFPYJVXUSXGP +BAKRJLKWGGXQFY +IVFHUUHIAMUTGR +DSVZIDXLKKIFLU +QFPXBVYGCDAYMW +JWPDWTQSEVDUEU +ROPURQARGDTBBZ +COPJJLIBBWNVEG +RBSANZKTNQQZIF +SHFMWGHKYPJCMB +BRZAJTXRBIYUBT +UFEYZHWROVTPNL +KDGAYIQHBSZFAC +XMBSZPZJLPTFMV +UNZVQFYBJFBZQU +UNZVQFYBJFBZQU +VKIMNIFOQJKBSQ +IZVJGHOBHCELDF +PLLAPLIMUIJMOC +HZXZTAAZILWOMG +RGPLABHTYVGWKB +UCTWSKPOBKSLHG +UOGMFXSUODVZOM +DGDABUQKZBKVNH +KQICDMFHIKZHLQ +LBEJUQWGEGOTNX +SBJYBAIMQAUWMZ +WEGITEKALFVLHV +ZHVMRVMGQKSOKL +ZHVMRVMGQKSOKL +RBWNFHXBUDPAIO +RBWNFHXBUDPAIO +RBWNFHXBUDPAIO +IGCULZQONBAMRE +IGCULZQONBAMRE +YSDVNFWVVPHGFX +WNHCOMJIXJADBK +QREVWNVSFCZWGU +XDAOLTSRNUSPPH +XDAOLTSRNUSPPH +XDAOLTSRNUSPPH +XDAOLTSRNUSPPH +RASUVPIIXQWKQJ +RBKVRSJNDSUKEM +WQRRSTVFXTYOJZ +UGGQJFCPEJWJFR +OWHDETKHTAYSHV +OJICYBSWSZGRFB +QBHZHBVIUINBIU +YZLODHPDCSNHTP +KXSXIFFPCDJUPY +TWSMUNUFSVRHIB +DXBXXUJCXAWKMV +DXBXXUJCXAWKMV +DXOOVGNYSYVTNM +VOVBYBYEYGCZIL +DIWSKHVYMDRMKN +QCGVWURENBVVQG +IXKIZPGJCKVQGU +IXKIZPGJCKVQGU +IXKIZPGJCKVQGU +PBVIXFOZRAMTSN +LCQSRPGLBHQFNF +MMGPENLTZQKVBO +VBWDUFMYAFZXFX +XFSYGJBPBTWLFR +KNVRSNGORYIZSS +KNVRSNGORYIZSS +KNVRSNGORYIZSS +YYPYGOBZSTWBLU +YIPAURBUIQKDKE +BTTNOGHPGJANSW +BTTNOGHPGJANSW +BTTNOGHPGJANSW +BTTNOGHPGJANSW +OEBDJVDLTMRYBT +YIRVBDZTHISHJM +UQOCJNOTNWYZQR +KRQJJEHYENCIHG +GFTNXPVXWMLQCP +IKKCYRJQWCTODP +MCXIERGGMZGONT +IJESFQCCOFNOQG +FPFAZHMPACUKSM +IYSFCDBFTWNNHB +XZLFLNWUBLMFQW +PEVGVQUYBNMZTF +USOJNBCSEBSXNR +GAYJDZZEGOKBID +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +LLRHQEDEAOKTPS +ARLOHHNBCXKXDE +GHSNRIDSNNBBFP +OWLPYRJWFAVURP +ONJKDQWJZQEXIR +WLJYEEIXBTUIEV +IQMMQBXFNFNXIC +XKFTZKGMDDZMJI +XKFTZKGMDDZMJI +XKFTZKGMDDZMJI +XKFTZKGMDDZMJI +DNDNLFXKQSTINI +XUDUGZUGZAXCNW +WFDXOXNFNRHQEC +GPMAWZWHYNAUCW +CGLPUJREKSHIQW +GVZZZLDSLMWJJU +OAUPSHKTJBGBLG +KSXMCLNVFPZRBK +OFNBSFMFHMXOJD +PNKONZIDCALVEW +YWIYJLBXFGWXPU +NQWPKFWLUUOORK +DAGGFCFDRQLXAV +UXFYDSZRRLQYKN +CTLCOPNKIWAGIM +KOVRKEORCJCTNU +JPXAIORZGBCHIB +QJVVTSYNUZFGTP +KJHIZYQJIJRUCX +ZBHUCEVJOSCQTF +GTUIRORNXIOHQR +GTUIRORNXIOHQR +GTUIRORNXIOHQR +GTUIRORNXIOHQR +FIDIQKXIRFUXAF +LVVHGBHCFCKIPX +QUIJNHUBAXPXFS +QUIJNHUBAXPXFS +QUIJNHUBAXPXFS +QUIJNHUBAXPXFS +QUIJNHUBAXPXFS +QUIJNHUBAXPXFS +QUIJNHUBAXPXFS +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +FDQAOULAVFHKBX +FDQAOULAVFHKBX +FDQAOULAVFHKBX +FDQAOULAVFHKBX +FDQAOULAVFHKBX +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +FDQAOULAVFHKBX +FDQAOULAVFHKBX +FDQAOULAVFHKBX +FDQAOULAVFHKBX +FDQAOULAVFHKBX +WZWPYJOPCULCLQ +WZWPYJOPCULCLQ +WZWPYJOPCULCLQ +WZWPYJOPCULCLQ +WZWPYJOPCULCLQ +RANQPHKSRUUPKK +RANQPHKSRUUPKK +RANQPHKSRUUPKK +RANQPHKSRUUPKK +RANQPHKSRUUPKK +CDEVGTJBRPBOPH +CDEVGTJBRPBOPH +CDEVGTJBRPBOPH +CDEVGTJBRPBOPH +CDEVGTJBRPBOPH +CDEVGTJBRPBOPH +CDEVGTJBRPBOPH +CDEVGTJBRPBOPH +VNONINPVFQTJOC +VNONINPVFQTJOC +VNONINPVFQTJOC +VNONINPVFQTJOC +VNONINPVFQTJOC +VNONINPVFQTJOC +VNONINPVFQTJOC +VNONINPVFQTJOC +MFZWMTSUNYWVBU +MFZWMTSUNYWVBU +MFZWMTSUNYWVBU +MFZWMTSUNYWVBU +MFZWMTSUNYWVBU +MFZWMTSUNYWVBU +MFZWMTSUNYWVBU +MFZWMTSUNYWVBU +MFZWMTSUNYWVBU +XCGYUJZMCCFSRP +XCGYUJZMCCFSRP +XCGYUJZMCCFSRP +XCGYUJZMCCFSRP +XCGYUJZMCCFSRP +XCGYUJZMCCFSRP +ZAFYATHCZYHLPB +ZAFYATHCZYHLPB +ZAFYATHCZYHLPB +ZAFYATHCZYHLPB +ZAFYATHCZYHLPB +BCEHBSKCWLPMDN +BCEHBSKCWLPMDN +BCEHBSKCWLPMDN +BCEHBSKCWLPMDN +BCEHBSKCWLPMDN +BCEHBSKCWLPMDN +BCEHBSKCWLPMDN +BCEHBSKCWLPMDN +VCKUSRYTPJJLNI +VCKUSRYTPJJLNI +VCKUSRYTPJJLNI +VCKUSRYTPJJLNI +VCKUSRYTPJJLNI +VCKUSRYTPJJLNI +VCKUSRYTPJJLNI +VCKUSRYTPJJLNI +VCKUSRYTPJJLNI +VCKUSRYTPJJLNI +IKBKZGMPCYNSLU +IKBKZGMPCYNSLU +IKBKZGMPCYNSLU +IKBKZGMPCYNSLU +QWAXKHKRTORLEM +QWAXKHKRTORLEM +QWAXKHKRTORLEM +QWAXKHKRTORLEM +QWAXKHKRTORLEM +QWAXKHKRTORLEM +QWAXKHKRTORLEM +QWAXKHKRTORLEM +QWAXKHKRTORLEM +SMTZFNFIKUPEJC +SMTZFNFIKUPEJC +SMTZFNFIKUPEJC +SMTZFNFIKUPEJC +SMTZFNFIKUPEJC +SMTZFNFIKUPEJC +SMTZFNFIKUPEJC +YASAKCUCGLMORW +YASAKCUCGLMORW +YASAKCUCGLMORW +YASAKCUCGLMORW +YASAKCUCGLMORW +YASAKCUCGLMORW +YASAKCUCGLMORW +YASAKCUCGLMORW +YASAKCUCGLMORW +YASAKCUCGLMORW +YASAKCUCGLMORW +YASAKCUCGLMORW +YASAKCUCGLMORW +YASAKCUCGLMORW +YASAKCUCGLMORW +IVTVGDXNLFLDRM +IVTVGDXNLFLDRM +IVTVGDXNLFLDRM +IVTVGDXNLFLDRM +IVTVGDXNLFLDRM +IVTVGDXNLFLDRM +VGYFMXBACGZSIL +VGYFMXBACGZSIL +VGYFMXBACGZSIL +VGYFMXBACGZSIL +VGYFMXBACGZSIL +UBRKDAVQCKZSPO +UBRKDAVQCKZSPO +UBRKDAVQCKZSPO +UBRKDAVQCKZSPO +UBRKDAVQCKZSPO +UBRKDAVQCKZSPO +OEBPANQZQGQPHF +OEBPANQZQGQPHF +OEBPANQZQGQPHF +OEBPANQZQGQPHF +QAGYKUNXZHXKMR +QAGYKUNXZHXKMR +QAGYKUNXZHXKMR +QAGYKUNXZHXKMR +QAGYKUNXZHXKMR +QAGYKUNXZHXKMR +QAGYKUNXZHXKMR +QAGYKUNXZHXKMR +WIYUZYBFCWCCQJ +WIYUZYBFCWCCQJ +WIYUZYBFCWCCQJ +WIYUZYBFCWCCQJ +WIYUZYBFCWCCQJ +IDZASIQMRGPBCQ +IDZASIQMRGPBCQ +IDZASIQMRGPBCQ +BWWVAEOLVKTZFQ +BWWVAEOLVKTZFQ +BWWVAEOLVKTZFQ +BWWVAEOLVKTZFQ +BWWVAEOLVKTZFQ +BWWVAEOLVKTZFQ +GGXICVAJURFBLW +GGXICVAJURFBLW +GGXICVAJURFBLW +GGXICVAJURFBLW +GGXICVAJURFBLW +GKQPCPXONLDCMU +GKQPCPXONLDCMU +GKQPCPXONLDCMU +GKQPCPXONLDCMU +GKQPCPXONLDCMU +GKQPCPXONLDCMU +GKQPCPXONLDCMU +XDXDZDZNSLXDNA +XDXDZDZNSLXDNA +XDXDZDZNSLXDNA +XDXDZDZNSLXDNA +XDXDZDZNSLXDNA +XDXDZDZNSLXDNA +XDXDZDZNSLXDNA +XDXDZDZNSLXDNA +PMKJGGBYYNEYPA +PMKJGGBYYNEYPA +PMKJGGBYYNEYPA +OFBIFZUFASYYRE +OFBIFZUFASYYRE +OFBIFZUFASYYRE +OFBIFZUFASYYRE +OFBIFZUFASYYRE +OFBIFZUFASYYRE +OFBIFZUFASYYRE +OFBIFZUFASYYRE +OFBIFZUFASYYRE +PQKBPHSEKWERTG +PQKBPHSEKWERTG +PQKBPHSEKWERTG +PQKBPHSEKWERTG +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZFMVWAWSKLAVOE +ZFMVWAWSKLAVOE +ZFMVWAWSKLAVOE +LXFHSCDLMBZYKY +LXFHSCDLMBZYKY +LXFHSCDLMBZYKY +LXFHSCDLMBZYKY +SEERZIQQUAZTOL +SEERZIQQUAZTOL +KXNPVXPOPUZYGB +KXNPVXPOPUZYGB +KXNPVXPOPUZYGB +KXNPVXPOPUZYGB +BUZAJRPLUGXRAB +BUZAJRPLUGXRAB +BUZAJRPLUGXRAB +BUZAJRPLUGXRAB +WDZCUPBHRAEYDL +WDZCUPBHRAEYDL +WDZCUPBHRAEYDL +WDZCUPBHRAEYDL +SKGWNZXOCSYJQL +SKGWNZXOCSYJQL +FDCOHGHEADZEGF +FDCOHGHEADZEGF +FDCOHGHEADZEGF +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NYBZAGXTZXPYND +LPDKPBDXVBTVRR +LPDKPBDXVBTVRR +LPDKPBDXVBTVRR +LPDKPBDXVBTVRR +LPDKPBDXVBTVRR +LPDKPBDXVBTVRR +KSIZLOPUXFSFNR +XNEHMJCUBKZYMV +XNEHMJCUBKZYMV +UVHKHTJWCYXSLC +BAZNCZDJJNWDIP +BAZNCZDJJNWDIP +RKCMTKXTIVZCTQ +DJZCTUVALDDONK +DJZCTUVALDDONK +AQXXGIBOZQZSAT +AQXXGIBOZQZSAT +AQXXGIBOZQZSAT +AQXXGIBOZQZSAT +AQXXGIBOZQZSAT +FUCBQNSQRCPSGC +FUCBQNSQRCPSGC +UAVAEWGJORGZNS +UAVAEWGJORGZNS +KXSGCAPYMUMVSH +KXSGCAPYMUMVSH +KXSGCAPYMUMVSH +KXSGCAPYMUMVSH +QPQMEODQMYOEQT +QPQMEODQMYOEQT +VOJZQYLSWQMIAF +VOJZQYLSWQMIAF +ZFQKIXYNDKWBKW +WUHLDGKUYJARLK +WUHLDGKUYJARLK +QUZHZFAQJATMCA +QUZHZFAQJATMCA +SQIQZZJGWUWAFZ +SQIQZZJGWUWAFZ +NSUHFZHIKMSXME +NSUHFZHIKMSXME +DKZOQKYOEKTNQN +DKZOQKYOEKTNQN +FMFRGVZQZUZQFN +XXQCVDALCBCQSX +XXQCVDALCBCQSX +XXQCVDALCBCQSX +XXQCVDALCBCQSX +FMFRGVZQZUZQFN +FMFRGVZQZUZQFN +DQJKVVGTJNBSOS +DQJKVVGTJNBSOS +FMYQBFRKVMAHBX +FMYQBFRKVMAHBX +OQXBCMJIIDQITC +OQXBCMJIIDQITC +OQXBCMJIIDQITC +OQXBCMJIIDQITC +OQXBCMJIIDQITC +YTRXIFNFFGXRFV +YTRXIFNFFGXRFV +YTRXIFNFFGXRFV +YTRXIFNFFGXRFV +UEVWVMGTABEFID +UEVWVMGTABEFID +CUCNRHYDISBEQH +CUCNRHYDISBEQH +CUCNRHYDISBEQH +CUCNRHYDISBEQH +DYFXVIVUWANJGN +DYFXVIVUWANJGN +DYFXVIVUWANJGN +DYFXVIVUWANJGN +DYFXVIVUWANJGN +DYFXVIVUWANJGN +DYFXVIVUWANJGN +DYFXVIVUWANJGN +RSNBAEGFNZIXPM +RSNBAEGFNZIXPM +RSNBAEGFNZIXPM +BJMXBTRNBWZGEQ +BJMXBTRNBWZGEQ +BJMXBTRNBWZGEQ +BJMXBTRNBWZGEQ +BJMXBTRNBWZGEQ +BJMXBTRNBWZGEQ +BJMXBTRNBWZGEQ +BJMXBTRNBWZGEQ +UTWYSZSEHYRTLP +UTWYSZSEHYRTLP +UTWYSZSEHYRTLP +UTWYSZSEHYRTLP +UTWYSZSEHYRTLP +UTWYSZSEHYRTLP +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +BBMULGJBVDDDNI +CPMFRQHRPWPNMP +CPMFRQHRPWPNMP +CPMFRQHRPWPNMP +CPMFRQHRPWPNMP +CPMFRQHRPWPNMP +CPMFRQHRPWPNMP +CPMFRQHRPWPNMP +DORNRAAPIXGDPH +DORNRAAPIXGDPH +DORNRAAPIXGDPH +DORNRAAPIXGDPH +DORNRAAPIXGDPH +DORNRAAPIXGDPH +DORNRAAPIXGDPH +PIXYPRXKMCTYQV +PVAWVKQDYYTSIE +PVAWVKQDYYTSIE +PVAWVKQDYYTSIE +PVAWVKQDYYTSIE +PVAWVKQDYYTSIE +PVAWVKQDYYTSIE +PVAWVKQDYYTSIE +PVAWVKQDYYTSIE +JQOQJRICPWKBGN +JQOQJRICPWKBGN +JQOQJRICPWKBGN +JQOQJRICPWKBGN +JQOQJRICPWKBGN +JQOQJRICPWKBGN +JQOQJRICPWKBGN +KNKHXYYGNZZSEJ +KNKHXYYGNZZSEJ +KNKHXYYGNZZSEJ +KNKHXYYGNZZSEJ +KNKHXYYGNZZSEJ +KNKHXYYGNZZSEJ +KNKHXYYGNZZSEJ +KNKHXYYGNZZSEJ +KNKHXYYGNZZSEJ +XCYFMYRAJQOAQT +XCYFMYRAJQOAQT +OBKFQZNNFBXVJH +OBKFQZNNFBXVJH +OBKFQZNNFBXVJH +OBKFQZNNFBXVJH +OBKFQZNNFBXVJH +OBKFQZNNFBXVJH +OBKFQZNNFBXVJH +OBKFQZNNFBXVJH +OBKFQZNNFBXVJH +OBKFQZNNFBXVJH +OBKFQZNNFBXVJH +OBKFQZNNFBXVJH +OBKFQZNNFBXVJH +CBEIHVWVTGRGDR +CBEIHVWVTGRGDR +CBEIHVWVTGRGDR +CBEIHVWVTGRGDR +CBEIHVWVTGRGDR +CBEIHVWVTGRGDR +CBEIHVWVTGRGDR +CBEIHVWVTGRGDR +CBEIHVWVTGRGDR +CBEIHVWVTGRGDR +CBEIHVWVTGRGDR +CBEIHVWVTGRGDR +CBEIHVWVTGRGDR +ZXONCHMIIHLRHD +ZXONCHMIIHLRHD +ZXONCHMIIHLRHD +ZXONCHMIIHLRHD +ZXONCHMIIHLRHD +ZXONCHMIIHLRHD +ZXONCHMIIHLRHD +ZXONCHMIIHLRHD +VVUAHGLHHLVKDR +VVUAHGLHHLVKDR +VVUAHGLHHLVKDR +VVUAHGLHHLVKDR +VVUAHGLHHLVKDR +VVUAHGLHHLVKDR +VVUAHGLHHLVKDR +JPGYRFJJNVYGPI +JPGYRFJJNVYGPI +JPGYRFJJNVYGPI +JPGYRFJJNVYGPI +JPGYRFJJNVYGPI +JPGYRFJJNVYGPI +JPGYRFJJNVYGPI +PGRWPWIGJLNDHN +PGRWPWIGJLNDHN +PGRWPWIGJLNDHN +PGRWPWIGJLNDHN +PGRWPWIGJLNDHN +PGRWPWIGJLNDHN +PGRWPWIGJLNDHN +PGRWPWIGJLNDHN +PGRWPWIGJLNDHN +PGRWPWIGJLNDHN +PGRWPWIGJLNDHN +BRELKNNWUMEGDN +BRELKNNWUMEGDN +BRELKNNWUMEGDN +BRELKNNWUMEGDN +GADSICAILMLRQB +GADSICAILMLRQB +GADSICAILMLRQB +GADSICAILMLRQB +GADSICAILMLRQB +GADSICAILMLRQB +GADSICAILMLRQB +QOXHBQOXXZSKON +QOXHBQOXXZSKON +QOXHBQOXXZSKON +QOXHBQOXXZSKON +ZFOBGKZKFOAYTR +ZFOBGKZKFOAYTR +ZFOBGKZKFOAYTR +ZFOBGKZKFOAYTR +ZFOBGKZKFOAYTR +AKMKWHBDPUOPSK +AKMKWHBDPUOPSK +AKMKWHBDPUOPSK +AKMKWHBDPUOPSK +AKMKWHBDPUOPSK +AKMKWHBDPUOPSK +AKMKWHBDPUOPSK +AKMKWHBDPUOPSK +SUDVQVUJMZQNHR +SUDVQVUJMZQNHR +SUDVQVUJMZQNHR +SUDVQVUJMZQNHR +SUDVQVUJMZQNHR +SUDVQVUJMZQNHR +SUDVQVUJMZQNHR +SUDVQVUJMZQNHR +SUDVQVUJMZQNHR +SUDVQVUJMZQNHR +HTPFCQBRMHUAEU +HTPFCQBRMHUAEU +HTPFCQBRMHUAEU +HTPFCQBRMHUAEU +HTPFCQBRMHUAEU +IZBWUVKNXOGJSA +IZBWUVKNXOGJSA +IZBWUVKNXOGJSA +IZBWUVKNXOGJSA +IZBWUVKNXOGJSA +IZBWUVKNXOGJSA +IZBWUVKNXOGJSA +IZBWUVKNXOGJSA +IZBWUVKNXOGJSA +IZBWUVKNXOGJSA +IZBWUVKNXOGJSA +HIVUDBSYRZRZSH +HIVUDBSYRZRZSH +HIVUDBSYRZRZSH +QACRJXSXSVUOFZ +QACRJXSXSVUOFZ +QACRJXSXSVUOFZ +QACRJXSXSVUOFZ +NSNGIRMJTMEZBF +NSNGIRMJTMEZBF +YTEWAPMLXIWBPY +YTEWAPMLXIWBPY +YTEWAPMLXIWBPY +YTEWAPMLXIWBPY +YTEWAPMLXIWBPY +JTLPHVAPUJVXEJ +JTLPHVAPUJVXEJ +JTLPHVAPUJVXEJ +JTLPHVAPUJVXEJ +JTLPHVAPUJVXEJ +CGEQZXRFQKBBQJ +CGEQZXRFQKBBQJ +PBYPZVMETKFGQR +PBYPZVMETKFGQR +PBYPZVMETKFGQR +PBYPZVMETKFGQR +KHWHODOWEXOYIJ +KHWHODOWEXOYIJ +KHWHODOWEXOYIJ +KHWHODOWEXOYIJ +DTOUWTJYUCZJQD +DTOUWTJYUCZJQD +DTOUWTJYUCZJQD +DTOUWTJYUCZJQD +DTOUWTJYUCZJQD +DTOUWTJYUCZJQD +DTOUWTJYUCZJQD +DTOUWTJYUCZJQD +DTOUWTJYUCZJQD +WTPJPYNIRFDQSR +WTPJPYNIRFDQSR +WTPJPYNIRFDQSR +WTPJPYNIRFDQSR +WLQREUAHQSBKHB +WLQREUAHQSBKHB +WLQREUAHQSBKHB +WLQREUAHQSBKHB +JXJRJDNSPWNZOK +DIRWTXHNLLFBAL +DIRWTXHNLLFBAL +DIRWTXHNLLFBAL +ASRBKZHDORPEHO +WSRZQBTZCCBWOL +WSRZQBTZCCBWOL +QLAHWTNCEYYDRR +QLAHWTNCEYYDRR +PDICCECAPKBDBB +DHDSCKPFZHKEJM +DHDSCKPFZHKEJM +DHDSCKPFZHKEJM +DHDSCKPFZHKEJM +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +GRIDHCOCFJSWSY +GRIDHCOCFJSWSY +QBTIITFMJQCGKE +HOQHZAISJNVLMZ +IVIROPAKYIVJMP +XZTQPLIWKFPNAY +RKZYQAJFAZGGKD +RKZYQAJFAZGGKD +BFVCXYLQNGCSNB +BFVCXYLQNGCSNB +XSLGFIQRVCXUEU +HDBHHHCDEYATPY +HDBHHHCDEYATPY +WIYRFQHEAQSKER +WIYRFQHEAQSKER +ANSCENNXWQFDJG +ANSCENNXWQFDJG +DYNPEHYVIZVLIF +DYNPEHYVIZVLIF +MRXDGVXSWIXTQL +MRXDGVXSWIXTQL +WWGFZZYPXWHLAT +WWGFZZYPXWHLAT +BTAKGODFEIZKSQ +BTAKGODFEIZKSQ +KUKQXNQRXXTUEM +KUKQXNQRXXTUEM +GKIMOVAPSAVJHZ +GKIMOVAPSAVJHZ +JSLJRLSXMPKMLE +JSLJRLSXMPKMLE +HJAYZHHYHVLIHY +HJAYZHHYHVLIHY +GYQWUHLAJJRCBK +GYQWUHLAJJRCBK +FUQZXQOTZSUCHH +MHCOGFNVFDFUND +MHCOGFNVFDFUND +LYXDEFOUSRLPID +LYXDEFOUSRLPID +WDMPTRNBGBEFTI +COYRMRLFNZOKND +YHLJXSQTEXOABX +RIHVEJOGUIBAQW +BJPBLPIJEUNNFF +BJPBLPIJEUNNFF +LPRRMKKQWCVICH +VHLWWGUJUDALRY +VHLWWGUJUDALRY +MQRRSNNZKRHXGT +MQRRSNNZKRHXGT +SJGGZNSVPHOEPD +SJGGZNSVPHOEPD +LARXQQSQVITAGF +LARXQQSQVITAGF +DTDKDYCVVOKSAV +DTDKDYCVVOKSAV +KQODQNJLJQHFQV +KQODQNJLJQHFQV +OPQHNERZELMQDK +OPQHNERZELMQDK +OCMXOQFOMBDMCH +OCMXOQFOMBDMCH +HVPYLVISSBODEY +HVPYLVISSBODEY +MFAMPZDMMVTXQD +MFAMPZDMMVTXQD +DFFYMZZNXYPOIR +BVIZHARSPLOVRS +BVIZHARSPLOVRS +DMJNNHOOLUXYBV +DMJNNHOOLUXYBV +UOAUHJWVKNXERD +FBFWDBGUSMGXPI +FBFWDBGUSMGXPI +XFUBJKQWCJERLE +XFUBJKQWCJERLE +XFMVTQWDJPMKHB +XFMVTQWDJPMKHB +SERBHKJMVBATSJ +SERBHKJMVBATSJ +QSJOEQXFYCTBSY +ZFDAUYPBCXMSBF +ZFDAUYPBCXMSBF +PJGMQKGDUJXNPQ +PJGMQKGDUJXNPQ +YUURHHZWHGWCMX +YUURHHZWHGWCMX +UGVNWWLEZYFGOA +UGVNWWLEZYFGOA +UDIWSEZLLVZPLD +UDIWSEZLLVZPLD +GOJAMJAYSLKBTR +GOJAMJAYSLKBTR +FIIRBPHYBLFBSD +YJQCOFNZVFGCAF +ZOCXUHJGZXXIGQ +MHMRAFONCSQAIA +MHMRAFONCSQAIA +HBUNPJGMNVQSBX +HBUNPJGMNVQSBX +XSZYEZVTAAYIFQ +LNFAKRZKBWNLDS +LNFAKRZKBWNLDS +UOAPDHMSZKCUEI +UOAPDHMSZKCUEI +HRBMXGCIASCLFB +HRBMXGCIASCLFB +LONBSPWPPNYRFU +LONBSPWPPNYRFU +OOGKJKAIYXOODY +OOGKJKAIYXOODY +YHHLNGAZCXMCEW +YHHLNGAZCXMCEW +LLMKLMMXMOTPRU +LLMKLMMXMOTPRU +LLMKLMMXMOTPRU +SERBHKJMVBATSJ +SERBHKJMVBATSJ +JHYVWAMMAMCUIR +JHYVWAMMAMCUIR +JHYVWAMMAMCUIR +ICJJPTZLMALYBH +ICJJPTZLMALYBH +RMRJXGBAOAMLHD +RMRJXGBAOAMLHD +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +DZSDDKNXMARQMJ +YWAXVDLXUXRDHL +YWAXVDLXUXRDHL +RAGFPHFDFVNLCG +RAGFPHFDFVNLCG +ZRDKCABMZXNCMG +ZRDKCABMZXNCMG +UQRHBUYDCRKKKW +UQRHBUYDCRKKKW +BKJAMMLKHPCMJI +BKJAMMLKHPCMJI +YMEAIOHYSIGDJY +YMEAIOHYSIGDJY +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +MKCQCEAMNSHUSD +IPXPVEJAQOLVSV +IPXPVEJAQOLVSV +BJPLCTUJTXVXPC +PIQVMFFSPOCAJY +WJPGPAAXALJZKU +WJPGPAAXALJZKU +JRKCOMALDGUIFC +JRKCOMALDGUIFC +FEWFEWDBXQKUQI +XFANDVLPSBUGKD +XFANDVLPSBUGKD +BTWUONYKONENGB +BTWUONYKONENGB +LLUFQNWQFSQYNW +LLUFQNWQFSQYNW +XKWHEBFWMRWHGD +XKWHEBFWMRWHGD +SGZASISEYFQAQM +SGZASISEYFQAQM +WHPZSYIEWQPEHY +WHPZSYIEWQPEHY +WHPZSYIEWQPEHY +WHPZSYIEWQPEHY +WHPZSYIEWQPEHY +SVAPNKGLWRWWCI +SVAPNKGLWRWWCI +SVAPNKGLWRWWCI +SVAPNKGLWRWWCI +SVAPNKGLWRWWCI +SVAPNKGLWRWWCI +SVAPNKGLWRWWCI +MXLZHQOOQIUQGO +MXLZHQOOQIUQGO +MXLZHQOOQIUQGO +MXLZHQOOQIUQGO +MXLZHQOOQIUQGO +NGTHIBFWOPPSSB +NGTHIBFWOPPSSB +NGTHIBFWOPPSSB +NGTHIBFWOPPSSB +NGTHIBFWOPPSSB +NGTHIBFWOPPSSB +NGTHIBFWOPPSSB +NGTHIBFWOPPSSB +FAUWZNGPMHRLMW +FAUWZNGPMHRLMW +FAUWZNGPMHRLMW +FAUWZNGPMHRLMW +FAUWZNGPMHRLMW +FAUWZNGPMHRLMW +FAUWZNGPMHRLMW +FAUWZNGPMHRLMW +ZRMFMDZIHZKFHY +ZRMFMDZIHZKFHY +ZRMFMDZIHZKFHY +ZRMFMDZIHZKFHY +ZRMFMDZIHZKFHY +ZRMFMDZIHZKFHY +ZRMFMDZIHZKFHY +ZRMFMDZIHZKFHY +USUPWKOUEKWYER +USUPWKOUEKWYER +USUPWKOUEKWYER +USUPWKOUEKWYER +USUPWKOUEKWYER +USUPWKOUEKWYER +MYTOZWCQVXHVIO +MYTOZWCQVXHVIO +MYTOZWCQVXHVIO +MYTOZWCQVXHVIO +MYTOZWCQVXHVIO +MYTOZWCQVXHVIO +WKGYNBDVOPHKOW +WKGYNBDVOPHKOW +WKGYNBDVOPHKOW +WKGYNBDVOPHKOW +AWVNBSKIKNPOBG +AWVNBSKIKNPOBG +AWVNBSKIKNPOBG +AWVNBSKIKNPOBG +KOPJPWSRYZRWPD +KOPJPWSRYZRWPD +KOPJPWSRYZRWPD +KOPJPWSRYZRWPD +IINDQALFBNRRJE +IINDQALFBNRRJE +IINDQALFBNRRJE +IINDQALFBNRRJE +STLFVIAKHLLGHJ +STLFVIAKHLLGHJ +STLFVIAKHLLGHJ +STLFVIAKHLLGHJ +STLFVIAKHLLGHJ +STLFVIAKHLLGHJ +STLFVIAKHLLGHJ +STLFVIAKHLLGHJ +KYOXKUIYXAIFBB +KYOXKUIYXAIFBB +KYOXKUIYXAIFBB +KYOXKUIYXAIFBB +KYOXKUIYXAIFBB +KYOXKUIYXAIFBB +KYOXKUIYXAIFBB +KYOXKUIYXAIFBB +KYOXKUIYXAIFBB +KYOXKUIYXAIFBB +IIUWCHJZJFSKMD +IIUWCHJZJFSKMD +IIUWCHJZJFSKMD +IIUWCHJZJFSKMD +IIUWCHJZJFSKMD +IIUWCHJZJFSKMD +IIUWCHJZJFSKMD +IIUWCHJZJFSKMD +UXVNNVWPICKMTE +UXVNNVWPICKMTE +VCDMHIARBYKHSB +LYRBFJCNZKRZPT +YAXAQXBFDAJGGS +YAXAQXBFDAJGGS +NHYWHOQGRJLYBG +NHYWHOQGRJLYBG +IFFBQMRDVLQSPU +IFFBQMRDVLQSPU +QZYBQHBBKYUFTE +QZYBQHBBKYUFTE +SHQQHQZXMPJGOJ +SHQQHQZXMPJGOJ +XWJQTVCPYQVRPY +XWJQTVCPYQVRPY +CLTKURJLSGQYAV +CLTKURJLSGQYAV +FXNSZAOKKBWFLU +FXNSZAOKKBWFLU +RBLMMGLQKIXPQH +RBLMMGLQKIXPQH +AJUAZNUVBAVUAY +UMVSOHBRAQTGQI +UMVSOHBRAQTGQI +VCCUOZSDXVZCSK +QUVRUINWOFZNJL +QUVRUINWOFZNJL +IIENSJWVEKJWAJ +IIENSJWVEKJWAJ +IIENSJWVEKJWAJ +IIENSJWVEKJWAJ +SVWYOGCKJVQALA +SVWYOGCKJVQALA +SVWYOGCKJVQALA +SVWYOGCKJVQALA +KSIHMACFIAFKIG +KSIHMACFIAFKIG +VGXYDZCCQDSGLZ +VGXYDZCCQDSGLZ +LOTZFXULRMRODN +QHONUEZGTQYXKH +QHONUEZGTQYXKH +JBQJQRQPOXLFNB +VTLYZTRDIRBJDH +VTLYZTRDIRBJDH +RSQMJYYPSGXQML +RSQMJYYPSGXQML +RSQMJYYPSGXQML +RSQMJYYPSGXQML +SVPQGHIWELZQOE +SVPQGHIWELZQOE +SLMISZLSXLAAKK +SLMISZLSXLAAKK +RCQTVEFBFUNTGM +FIIRBPHYBLFBSD +FIIRBPHYBLFBSD +XAFNQFHOQPRGAK +XAFNQFHOQPRGAK +ZPJLQAOTGYKOBJ +ZPJLQAOTGYKOBJ +HIYAVKIYRIFSCZ +HIYAVKIYRIFSCZ +HIYAVKIYRIFSCZ +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +NWXMGUDVXFXRIG +QLWPXZGDNPSROH +QLWPXZGDNPSROH +CBVLNMNYILSPBN +CBVLNMNYILSPBN +XMVDIYAEPSBCDQ +XMVDIYAEPSBCDQ +WRKRRZYETOSMBY +BXUDMXDCTTUXLQ +BXUDMXDCTTUXLQ +QRAZUCRROOPZGW +QRAZUCRROOPZGW +XYEKESXODZZYMD +TYOWQSLRVAUSMI +VGXYDZCCQDSGLZ +VGXYDZCCQDSGLZ +BTHUUTBVHUBHNR +BTHUUTBVHUBHNR +NJIOFEXYZOVVKA +NJIOFEXYZOVVKA +ZQCAUNGVEIYRKP +ZQCAUNGVEIYRKP +CODGHFHXEFKOMN +WWJZWCUNLNYYAU +WWJZWCUNLNYYAU +WWJZWCUNLNYYAU +WWJZWCUNLNYYAU +WWJZWCUNLNYYAU +WWJZWCUNLNYYAU +WWJZWCUNLNYYAU +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +GMAUQNJOSOMMHI +LBRPLJCNRZUXLS +LBRPLJCNRZUXLS +LBRPLJCNRZUXLS +LBRPLJCNRZUXLS +LBRPLJCNRZUXLS +QIWWLKDHHMGRQL +QIWWLKDHHMGRQL +QIWWLKDHHMGRQL +QIWWLKDHHMGRQL +SKNVKBJSSSJNCI +SKNVKBJSSSJNCI +SKNVKBJSSSJNCI +SKNVKBJSSSJNCI +NTAHMPNXQOYXSX +NTAHMPNXQOYXSX +NTAHMPNXQOYXSX +NTAHMPNXQOYXSX +NTAHMPNXQOYXSX +UHBMKIHOBUKYRH +UHBMKIHOBUKYRH +UHBMKIHOBUKYRH +XRUAMQHLDNCEHM +XRUAMQHLDNCEHM +XRUAMQHLDNCEHM +XRUAMQHLDNCEHM +WDGSJYYXVXQQHP +WDGSJYYXVXQQHP +WDGSJYYXVXQQHP +WDGSJYYXVXQQHP +CROUPKILZUPLQA +CROUPKILZUPLQA +CROUPKILZUPLQA +CROUPKILZUPLQA +VYXBNIDRQOAAHX +VYXBNIDRQOAAHX +VYXBNIDRQOAAHX +VYXBNIDRQOAAHX +VYXBNIDRQOAAHX +ZAWVKTOAAOBPLL +ZAWVKTOAAOBPLL +ZAWVKTOAAOBPLL +ZAWVKTOAAOBPLL +MLRZPRGBFKQPOT +MLRZPRGBFKQPOT +MLRZPRGBFKQPOT +MLRZPRGBFKQPOT +MLRZPRGBFKQPOT +MLRZPRGBFKQPOT +LPCRSLMVMNEPGT +LPCRSLMVMNEPGT +LPCRSLMVMNEPGT +LPCRSLMVMNEPGT +MBWUSSKCCUMJHO +MBWUSSKCCUMJHO +BSUNYCAAALCBNU +BSUNYCAAALCBNU +QIWWLKDHHMGRQL +QIWWLKDHHMGRQL +QIWWLKDHHMGRQL +QIWWLKDHHMGRQL +QIWWLKDHHMGRQL +QIWWLKDHHMGRQL +QIWWLKDHHMGRQL +YUCVPZILWXKQCX +YUCVPZILWXKQCX +YUCVPZILWXKQCX +YUCVPZILWXKQCX +YUCVPZILWXKQCX +YUCVPZILWXKQCX +YUCVPZILWXKQCX +YUCVPZILWXKQCX +USQLNPJSDYEFJF +USQLNPJSDYEFJF +USQLNPJSDYEFJF +USQLNPJSDYEFJF +RNEQSBBQXWZUJN +RNEQSBBQXWZUJN +IVYAOUHUAWZJDB +IVYAOUHUAWZJDB +IVYAOUHUAWZJDB +IVYAOUHUAWZJDB +IVYAOUHUAWZJDB +IVYAOUHUAWZJDB +IVYAOUHUAWZJDB +LHYCMCBENMMKGY +LHYCMCBENMMKGY +LHYCMCBENMMKGY +LHYCMCBENMMKGY +FKMMWCMRFJRLIO +FKMMWCMRFJRLIO +FKMMWCMRFJRLIO +FKMMWCMRFJRLIO +FKMMWCMRFJRLIO +FKMMWCMRFJRLIO +SZHUMUJGHFQABW +SZHUMUJGHFQABW +SZHUMUJGHFQABW +SZHUMUJGHFQABW +SQOJOAFXDQDRGF +SQOJOAFXDQDRGF +ADIALAZTBGIRSN +ADIALAZTBGIRSN +LQLBJBHPDHBGLH +LQLBJBHPDHBGLH +LQLBJBHPDHBGLH +KWXCZSMMAKGXBP +KWXCZSMMAKGXBP +KWXCZSMMAKGXBP +KWXCZSMMAKGXBP +KWXCZSMMAKGXBP +KWXCZSMMAKGXBP +WGFGSGMOAHUFDZ +WGFGSGMOAHUFDZ +QTAIHYVDCKOYHV +QTAIHYVDCKOYHV +QTAIHYVDCKOYHV +MTYBVLBBQPTSAU +MTYBVLBBQPTSAU +WBCMGDNFDRNGGZ +WBCMGDNFDRNGGZ +WBCMGDNFDRNGGZ +WBCMGDNFDRNGGZ +WBCMGDNFDRNGGZ +WBCMGDNFDRNGGZ +WBCMGDNFDRNGGZ +NNOMPFCNQCRAIO +NNOMPFCNQCRAIO +NNOMPFCNQCRAIO +OHWILISHWFHITP +OHWILISHWFHITP +LVOGPECZHVNNHD +LVOGPECZHVNNHD +LVOGPECZHVNNHD +LVOGPECZHVNNHD +LVOGPECZHVNNHD +BSTJXYXEZBMPBY +BSTJXYXEZBMPBY +BSTJXYXEZBMPBY +BSTJXYXEZBMPBY +BSTJXYXEZBMPBY +LWORTIDRRYUBBP +LWORTIDRRYUBBP +LWORTIDRRYUBBP +LWORTIDRRYUBBP +NOKUIKNJHIHLGT +NOKUIKNJHIHLGT +NOKUIKNJHIHLGT +JUGKCFLQZJYLHO +JUGKCFLQZJYLHO +JUGKCFLQZJYLHO +JUGKCFLQZJYLHO +JUGKCFLQZJYLHO +DHCJHCCWOGTAHR +DHCJHCCWOGTAHR +DHCJHCCWOGTAHR +DHCJHCCWOGTAHR +DHCJHCCWOGTAHR +SCDIIKOGQOUENK +SCDIIKOGQOUENK +SCDIIKOGQOUENK +SCDIIKOGQOUENK +MWLKXILGJPSPKZ +MWLKXILGJPSPKZ +MWLKXILGJPSPKZ +MWLKXILGJPSPKZ +MWLKXILGJPSPKZ +YEOVVCBEYCCOOP +YEOVVCBEYCCOOP +ZFKOTULZHLMUJE +ZFKOTULZHLMUJE +ZFKOTULZHLMUJE +ZFKOTULZHLMUJE +BXGLWTGIQGFBBV +BXGLWTGIQGFBBV +XTSYDGXYRUWSFF +OWGURJWJHWYCIQ +OWGURJWJHWYCIQ +LIHVMLWWVHJRMA +LIHVMLWWVHJRMA +LIHVMLWWVHJRMA +LIHVMLWWVHJRMA +NLFUQHCGODFTIB +NLFUQHCGODFTIB +KJMIDUOUTLARSE +KJMIDUOUTLARSE +KJMIDUOUTLARSE +KJMIDUOUTLARSE +KJMIDUOUTLARSE +SYFJYRUTNACAQV +SYFJYRUTNACAQV +MHNHQOVNRYKGDF +MHNHQOVNRYKGDF +MHNHQOVNRYKGDF +MHNHQOVNRYKGDF +RLAUJYFETVMGAO +RLAUJYFETVMGAO +YDZWHGJRWMQCDP +YDZWHGJRWMQCDP +YDZWHGJRWMQCDP +YDZWHGJRWMQCDP +YDZWHGJRWMQCDP +YDZWHGJRWMQCDP +YDZWHGJRWMQCDP +OTDSQLNKKIPGLS +OTDSQLNKKIPGLS +OTDSQLNKKIPGLS +OTDSQLNKKIPGLS +UKUDXSDOMXVGOK +UKUDXSDOMXVGOK +UKUDXSDOMXVGOK +UKUDXSDOMXVGOK +UABRYEZSGXDDDK +UABRYEZSGXDDDK +LZXXRASHAINSDN +LZXXRASHAINSDN +LZXXRASHAINSDN +LZXXRASHAINSDN +NFZYDZXHKFHPGA +NFZYDZXHKFHPGA +QCKCJABEPSOSMR +QCKCJABEPSOSMR +QCKCJABEPSOSMR +QCKCJABEPSOSMR +QCKCJABEPSOSMR +SDMFWFQLYZEILE +SDMFWFQLYZEILE +KOATXBNOVXBDJE +KOATXBNOVXBDJE +KOATXBNOVXBDJE +KOATXBNOVXBDJE +KOATXBNOVXBDJE +KOATXBNOVXBDJE +KOATXBNOVXBDJE +RYWDJUUPROVLNV +RYWDJUUPROVLNV +ANXMAYKAWZAHMB +ANXMAYKAWZAHMB +ANXMAYKAWZAHMB +ANXMAYKAWZAHMB +GIUVFWDLNFDKHT +LCDHGZGHZZLGHK +LCDHGZGHZZLGHK +LCDHGZGHZZLGHK +JCNYBRAUXUDAEQ +JCNYBRAUXUDAEQ +JCNYBRAUXUDAEQ +JCNYBRAUXUDAEQ +JCNYBRAUXUDAEQ +JCNYBRAUXUDAEQ +JCNYBRAUXUDAEQ +RWCCSDWQXFKGJW +RWCCSDWQXFKGJW +RWCCSDWQXFKGJW +RNYROHPATJSIAO +RNYROHPATJSIAO +RNYROHPATJSIAO +RNYROHPATJSIAO +MGHSCXCFVZJHPT +MGHSCXCFVZJHPT +MGHSCXCFVZJHPT +MGHSCXCFVZJHPT +WLZSOFWXYPEZCP +WLZSOFWXYPEZCP +PUIAUUSJWDDCLR +PUIAUUSJWDDCLR +PUIAUUSJWDDCLR +PUIAUUSJWDDCLR +ALSZHZPQTCVXIR +ALSZHZPQTCVXIR +WTURHHSEHGCTBS +WTURHHSEHGCTBS +WTURHHSEHGCTBS +WTURHHSEHGCTBS +WTURHHSEHGCTBS +WTURHHSEHGCTBS +WZYGIALDVOKLLL +WZYGIALDVOKLLL +QIXOVYGMZDYDIN +QIXOVYGMZDYDIN +QIXOVYGMZDYDIN +QIXOVYGMZDYDIN +HMSYAPGFKGSXAJ +HMSYAPGFKGSXAJ +HMSYAPGFKGSXAJ +MPCIDUFOTGXABA +MPCIDUFOTGXABA +MPCIDUFOTGXABA +MPCIDUFOTGXABA +MPCIDUFOTGXABA +IEQTVHJLWRGNIY +IEQTVHJLWRGNIY +IEQTVHJLWRGNIY +JCHUCLMYSKXMOY +JCHUCLMYSKXMOY +JCHUCLMYSKXMOY +JCHUCLMYSKXMOY +JCHUCLMYSKXMOY +GEXPREATDMYGJF +GEXPREATDMYGJF +GEXPREATDMYGJF +GEXPREATDMYGJF +HXJGKPQYSSUARF +HXJGKPQYSSUARF +HXJGKPQYSSUARF +HXJGKPQYSSUARF +AZKQDXZMKREFDY +AZKQDXZMKREFDY +DBNSETUPZTZJFY +DBNSETUPZTZJFY +DBNSETUPZTZJFY +DBNSETUPZTZJFY +DBNSETUPZTZJFY +KBTSKABIWIUJAS +KBTSKABIWIUJAS +KBTSKABIWIUJAS +KBTSKABIWIUJAS +QTVCLHJYLZANIP +QTVCLHJYLZANIP +QTVCLHJYLZANIP +QTVCLHJYLZANIP +XDHNQDDQEHDUTM +PHSKBYXSIKEPBQ +PHSKBYXSIKEPBQ +PHSKBYXSIKEPBQ +PHSKBYXSIKEPBQ +PHSKBYXSIKEPBQ +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +JZWZFNOVWZEQMF +DQTBTFHCLVMGBP +DQTBTFHCLVMGBP +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +HLYSUPRTSCOCTI +HLYSUPRTSCOCTI +JUTSMXHGEKYOLZ +JUTSMXHGEKYOLZ +JUTSMXHGEKYOLZ +JUTSMXHGEKYOLZ +JUTSMXHGEKYOLZ +JUTSMXHGEKYOLZ +BVALVRBXQYLPOW +BVALVRBXQYLPOW +ALDOLERJIYTYDY +ALDOLERJIYTYDY +GXMVUJPIUWLNDG +GXMVUJPIUWLNDG +GXMVUJPIUWLNDG +GXMVUJPIUWLNDG +ATAIRWBABKGUFL +ATAIRWBABKGUFL +ATAIRWBABKGUFL +ATAIRWBABKGUFL +ATAIRWBABKGUFL +ATAIRWBABKGUFL +ATAIRWBABKGUFL +JPYYWXPAHJBKJX +JPYYWXPAHJBKJX +GBKBPIXSSQJOPJ +GBKBPIXSSQJOPJ +IRSUXHBCTWMHAK +IRSUXHBCTWMHAK +IRSUXHBCTWMHAK +IRSUXHBCTWMHAK +IRSUXHBCTWMHAK +IRSUXHBCTWMHAK +MZHPYFUVDWYNQP +NAHTXVIXCMUDLF +NAHTXVIXCMUDLF +NAHTXVIXCMUDLF +MMOJJYPBNVVCGY +MMOJJYPBNVVCGY +MMOJJYPBNVVCGY +MMOJJYPBNVVCGY +JACNBJFTXZEQNC +JACNBJFTXZEQNC +JACNBJFTXZEQNC +JACNBJFTXZEQNC +JDQAJUDONPAIME +JDQAJUDONPAIME +JDQAJUDONPAIME +JDQAJUDONPAIME +JDQAJUDONPAIME +BRXNFHGWRDJMSF +BRXNFHGWRDJMSF +BRXNFHGWRDJMSF +BRXNFHGWRDJMSF +BRXNFHGWRDJMSF +PACOALGXOJLUSI +PACOALGXOJLUSI +PACOALGXOJLUSI +PACOALGXOJLUSI +SKOYDNZXMHBVBB +SKOYDNZXMHBVBB +SKOYDNZXMHBVBB +SKOYDNZXMHBVBB +KEDZPHBUEGYHGC +KEDZPHBUEGYHGC +KEDZPHBUEGYHGC +KEDZPHBUEGYHGC +KEDZPHBUEGYHGC +SOLWETWNPWWTPC +SOLWETWNPWWTPC +SOLWETWNPWWTPC +SOLWETWNPWWTPC +SOLWETWNPWWTPC +SOLWETWNPWWTPC +ZLOTZUGMLIVSJQ +ZLOTZUGMLIVSJQ +ZLOTZUGMLIVSJQ +ZLOTZUGMLIVSJQ +ZLOTZUGMLIVSJQ +ZLOTZUGMLIVSJQ +STOYMKJWHHPSDH +STOYMKJWHHPSDH +QMSHPPRVWMLFFL +QMSHPPRVWMLFFL +QMSHPPRVWMLFFL +QMSHPPRVWMLFFL +AFYIWKNGSIYXCQ +AFYIWKNGSIYXCQ +AFYIWKNGSIYXCQ +AFYIWKNGSIYXCQ +FTBNYQWFSWKCKW +FTBNYQWFSWKCKW +FTBNYQWFSWKCKW +FTBNYQWFSWKCKW +ZVTVYIVILDSYIK +ZVTVYIVILDSYIK +FLSPBPZSXFDRFE +FLSPBPZSXFDRFE +QOMBXPYXWGTFNR +QOMBXPYXWGTFNR +QOMBXPYXWGTFNR +QOMBXPYXWGTFNR +ZGVSETXHNHBTRK +ZGVSETXHNHBTRK +ZGVSETXHNHBTRK +SWJLTKXURNHVHE +SWJLTKXURNHVHE +CPDCJXCECPCPNL +CPDCJXCECPCPNL +LKOARHYUMOKAPJ +LKOARHYUMOKAPJ +PCHWYSGBVKSPAM +PCHWYSGBVKSPAM +PCHWYSGBVKSPAM +PCHWYSGBVKSPAM +BLUQBEZYLPEUCP +BLUQBEZYLPEUCP +OJAGBDHRHPCDLN +OJAGBDHRHPCDLN +OJAGBDHRHPCDLN +OJAGBDHRHPCDLN +OJAGBDHRHPCDLN +OJAGBDHRHPCDLN +OJAGBDHRHPCDLN +NVKSXODNGLJJHQ +NVKSXODNGLJJHQ +LJGOHKSMJNTMAH +LJGOHKSMJNTMAH +HYLKKEXCEIKCIN +HYLKKEXCEIKCIN +HYLKKEXCEIKCIN +SSYUWECTPJGUGD +SSYUWECTPJGUGD +SSYUWECTPJGUGD +SSYUWECTPJGUGD +SSYUWECTPJGUGD +MKCYAASFWFGIJK +MKCYAASFWFGIJK +MKCYAASFWFGIJK +MKCYAASFWFGIJK +MKCYAASFWFGIJK +ACGHJVZDNQZJOV +ACGHJVZDNQZJOV +ACGHJVZDNQZJOV +ACGHJVZDNQZJOV +ACGHJVZDNQZJOV +MHCDFIFLMYBWIV +MHCDFIFLMYBWIV +MHCDFIFLMYBWIV +BRVXVMOWTHQKHC +BRVXVMOWTHQKHC +BRVXVMOWTHQKHC +DVNQRYDJAAFJBQ +DVNQRYDJAAFJBQ +DVNQRYDJAAFJBQ +DVNQRYDJAAFJBQ +DVNQRYDJAAFJBQ +ZVFMDVFPBVFGPG +ZVFMDVFPBVFGPG +ZVFMDVFPBVFGPG +ZVFMDVFPBVFGPG +ZVFMDVFPBVFGPG +ALJZEGCNMPANDZ +ALJZEGCNMPANDZ +ALJZEGCNMPANDZ +ALJZEGCNMPANDZ +ALJZEGCNMPANDZ +VHNBSWKVDGABEV +VHNBSWKVDGABEV +VHNBSWKVDGABEV +VHNBSWKVDGABEV +VHNBSWKVDGABEV +VHNBSWKVDGABEV +VHNBSWKVDGABEV +BVIXPBFQDINHQZ +BVIXPBFQDINHQZ +BVIXPBFQDINHQZ +IMIAGCONYJPMDY +IMIAGCONYJPMDY +IMIAGCONYJPMDY +IMIAGCONYJPMDY +IMIAGCONYJPMDY +IMIAGCONYJPMDY +UZQBOFAUUTZOQE +UZQBOFAUUTZOQE +UZQBOFAUUTZOQE +UZQBOFAUUTZOQE +LLPWNQMSUYAGQI +LLPWNQMSUYAGQI +KWJHGUHLTYVPID +KWJHGUHLTYVPID +KWJHGUHLTYVPID +KWJHGUHLTYVPID +KWJHGUHLTYVPID +CBJQFIAJZLMMPW +CBJQFIAJZLMMPW +CBJQFIAJZLMMPW +CBJQFIAJZLMMPW +CBJQFIAJZLMMPW +CBJQFIAJZLMMPW +ODNHLYCLMUNJRG +ODNHLYCLMUNJRG +IMABPJDBODVJSN +IMABPJDBODVJSN +IMABPJDBODVJSN +IMABPJDBODVJSN +IMABPJDBODVJSN +RWXIFXNRCLMQCD +JGHUOJAZXGSFRI +JGHUOJAZXGSFRI +JGHUOJAZXGSFRI +JGHUOJAZXGSFRI +IBZLICPLPYSFNZ +IBZLICPLPYSFNZ +AEYUKLGVHVHAGC +AEYUKLGVHVHAGC +AEYUKLGVHVHAGC +AEYUKLGVHVHAGC +QQRZPCAYYGRGJD +JORLYMGTWNNOMY +JORLYMGTWNNOMY +JORLYMGTWNNOMY +JORLYMGTWNNOMY +QTKJPFQTRUDUFR +QTKJPFQTRUDUFR +QTKJPFQTRUDUFR +QTKJPFQTRUDUFR +QTKJPFQTRUDUFR +BIGBTKXKWUHWLH +IYIIGIDPFTYYCU +IYIIGIDPFTYYCU +IYIIGIDPFTYYCU +ODQBQUXGRYBRTP +ODQBQUXGRYBRTP +ODQBQUXGRYBRTP +ODQBQUXGRYBRTP +ODQBQUXGRYBRTP +URTQATADKAKTAX +URTQATADKAKTAX +URTQATADKAKTAX +VQIUANBMNYRFDG +VQIUANBMNYRFDG +ZPKOPBUGDKNHJM +ZPKOPBUGDKNHJM +LBBBWHJWPKKHAK +LBBBWHJWPKKHAK +WYZSLJFHERMCAN +WYZSLJFHERMCAN +UJQFPCFWOKPURJ +UJQFPCFWOKPURJ +QBTPSJBCRQLPLW +QBTPSJBCRQLPLW +QBTPSJBCRQLPLW +QBTPSJBCRQLPLW +QBTPSJBCRQLPLW +GOQQRZOTZSUDEC +GOQQRZOTZSUDEC +GOQQRZOTZSUDEC +GOQQRZOTZSUDEC +GOQQRZOTZSUDEC +DUNFAZHEVVYXGG +DUNFAZHEVVYXGG +GACFDZLPFMYBKT +GACFDZLPFMYBKT +WROHFEWGWYQNPP +WROHFEWGWYQNPP +BSGBVUOHKNZIES +BSGBVUOHKNZIES +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +CYGIJEJDYJOUAN +UEYWXBQABUNMMN +UEYWXBQABUNMMN +UEYWXBQABUNMMN +UEYWXBQABUNMMN +UEYWXBQABUNMMN +UEYWXBQABUNMMN +UEYWXBQABUNMMN +ZVUYNAQSHSSBDQ +ZVUYNAQSHSSBDQ +RCDRNOBFNNSZNW +RCDRNOBFNNSZNW +RCDRNOBFNNSZNW +QARZACKHGQBZLP +QARZACKHGQBZLP +DNDACVRMGDHDQY +DNDACVRMGDHDQY +DNDACVRMGDHDQY +DNDACVRMGDHDQY +DNDACVRMGDHDQY +ZGUNMNCNGJXADK +ZGUNMNCNGJXADK +RLGRBYHBNWLGER +RLGRBYHBNWLGER +RLGRBYHBNWLGER +RLGRBYHBNWLGER +RLGRBYHBNWLGER +ZOEFIRUNMVHSJA +UGWAFWFSLCHCJD +UGWAFWFSLCHCJD +GXUYGLKNAQMTRM +GXUYGLKNAQMTRM +GXUYGLKNAQMTRM +GTNPVPDWWGQDMU +GTNPVPDWWGQDMU +XREZOMRRMAKCRX +XREZOMRRMAKCRX +XREZOMRRMAKCRX +XREZOMRRMAKCRX +XREZOMRRMAKCRX +OMGQCYHSAPWXMS +OMGQCYHSAPWXMS +XBEDTLDOFCRJHC +XBEDTLDOFCRJHC +XBEDTLDOFCRJHC +XBEDTLDOFCRJHC +XBEDTLDOFCRJHC +ADACAMXIRQREOB +ADACAMXIRQREOB +ADACAMXIRQREOB +RZQNQMRSGMXXMH +RZQNQMRSGMXXMH +XVYHBBAKYWDFRE +XVYHBBAKYWDFRE +XVYHBBAKYWDFRE +YIGXPIUPFFVJRJ +YIGXPIUPFFVJRJ +YIGXPIUPFFVJRJ +YIGXPIUPFFVJRJ +WCFJCDWCDZAMPA +WCFJCDWCDZAMPA +WCFJCDWCDZAMPA +FZYKTYOEQYVLEL +FZYKTYOEQYVLEL +CPCRJSQNWHCGOP +CPCRJSQNWHCGOP +LREHNMAHTSUHBC +LREHNMAHTSUHBC +LREHNMAHTSUHBC +LREHNMAHTSUHBC +JFTUBAXWPXSZEH +JFTUBAXWPXSZEH +JFTUBAXWPXSZEH +JFTUBAXWPXSZEH +JFTUBAXWPXSZEH +LZPKHIWZLREKGD +LZPKHIWZLREKGD +LZPKHIWZLREKGD +LZPKHIWZLREKGD +LZPKHIWZLREKGD +AIPGFMVNUMXXEM +AIPGFMVNUMXXEM +OFNCUIXPAFLTJZ +OFNCUIXPAFLTJZ +OFNCUIXPAFLTJZ +OFNCUIXPAFLTJZ +OFNCUIXPAFLTJZ +BJPYMDSMDBCKEP +BJPYMDSMDBCKEP +BJPYMDSMDBCKEP +BJPYMDSMDBCKEP +ZKOTUWJMGBWBEO +LOVVVDDAKZKPHZ +LOVVVDDAKZKPHZ +XUUBSPXZCBAWET +XUUBSPXZCBAWET +XUUBSPXZCBAWET +XUUBSPXZCBAWET +XUUBSPXZCBAWET +SNFRINMTRPQQLE +SNFRINMTRPQQLE +SNFRINMTRPQQLE +LKLNNJGYAYDANM +QYNCIWOOLDANTG +QYNCIWOOLDANTG +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +GJIALGLHOBXNAT +XOEFANNJIKAWGX +XOEFANNJIKAWGX +DNDACVRMGDHDQY +DNDACVRMGDHDQY +DNDACVRMGDHDQY +DNDACVRMGDHDQY +DNDACVRMGDHDQY +DNDACVRMGDHDQY +GAWOMYRLBFCSGL +GAWOMYRLBFCSGL +GAWOMYRLBFCSGL +GAWOMYRLBFCSGL +GAWOMYRLBFCSGL +RMHWAEFAOBGGBH +RMHWAEFAOBGGBH +RMHWAEFAOBGGBH +RMHWAEFAOBGGBH +RMHWAEFAOBGGBH +LJMPEBJKUBHVKR +LJMPEBJKUBHVKR +LJMPEBJKUBHVKR +LJMPEBJKUBHVKR +GVVZGEKYZVYQLY +GVVZGEKYZVYQLY +GVVZGEKYZVYQLY +GVVZGEKYZVYQLY +GVVZGEKYZVYQLY +UVGRPMWFXIDHJC +UVGRPMWFXIDHJC +UVGRPMWFXIDHJC +MYIUHDZRMLFLNJ +VTZLWHIGGFBZBC +VTZLWHIGGFBZBC +FHTSKUYELRWGGJ +FHTSKUYELRWGGJ +FHTSKUYELRWGGJ +IUQRTVVZUXBHMO +IUQRTVVZUXBHMO +IUQRTVVZUXBHMO +IUQRTVVZUXBHMO +DMMVPIYJYFCXOA +DMMVPIYJYFCXOA +DMMVPIYJYFCXOA +DMMVPIYJYFCXOA +KCOULPRVOZDQEL +KCOULPRVOZDQEL +RWSPXLDDWKEOIW +RWSPXLDDWKEOIW +PBTVAODWGBKPII +PBTVAODWGBKPII +COWAHSPQIKCIBE +COWAHSPQIKCIBE +GOFSCWBZJWJLTF +GOFSCWBZJWJLTF +KYIPVUWVVGXMKA +KYIPVUWVVGXMKA +MXMCPSADIJXXRC +MXMCPSADIJXXRC +KYIPVUWVVGXMKA +KYIPVUWVVGXMKA +HUVLAOORYMIHTC +HUVLAOORYMIHTC +GEJNVNUFFYATKR +GEJNVNUFFYATKR +WSLFSVKKVVFSHV +WSLFSVKKVVFSHV +QCQACYPNQZJHQN +QCQACYPNQZJHQN +FWZFLNODDOFQDC +JQWUSEVRGIXWTP +OHBCWVJHZZYAHJ +NPYICXUUGUJPMM +NPYICXUUGUJPMM +CBNRHESAARZEOI +CBNRHESAARZEOI +IMJOKVCCAPZUEO +IMJOKVCCAPZUEO +POJKUXRIPCIWMZ +POJKUXRIPCIWMZ +POJKUXRIPCIWMZ +IEWHPTFFMRBBPQ +GBOGMAARMMDZGR +GBOGMAARMMDZGR +GMJDEOWOJAKXGU +NZSWNNDHPOTJNH +BELBBZDIHDAJOR +BELBBZDIHDAJOR +NPYICXUUGUJPMM +NPYICXUUGUJPMM +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +YUULFXAQUWEYNP +YUULFXAQUWEYNP +VWWQXMAJTJZDQX +VWWQXMAJTJZDQX +XJLXINKUBYWONI +XJLXINKUBYWONI +BAWFJGJZGIEFAR +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +LUZRJRNZXALNLM +DFHAFZIZPJQODZ +DFHAFZIZPJQODZ +OBNLKIYUNMSGTC +OBNLKIYUNMSGTC +CZFMBNIKGDJPJQ +CZFMBNIKGDJPJQ +UFLYYPBSJUQZFA +UFLYYPBSJUQZFA +XGFYCYMDWHFTLH +XGFYCYMDWHFTLH +RGAWRDNXJUOZMG +PXDYILJJHOVNLO +HTBQLUDZPAANPB +VRGWBRLULZUWAJ +LBRJFDBQNUVAGM +LBRJFDBQNUVAGM +LBRJFDBQNUVAGM +LBRJFDBQNUVAGM +OHWILISHWFHITP +OHWILISHWFHITP +FEQKQISWJNDCPC +FEQKQISWJNDCPC +DFVYLDHDFLHIAA +YZQRMJFPWMHAJV +YZQRMJFPWMHAJV +PHEDXBVPIONUQT +PHEDXBVPIONUQT +PHEDXBVPIONUQT +GWLHFNKLJRZBAI +HZWIJOWMGPTNRA +HZWIJOWMGPTNRA +JWOGUUIOCYMBPV +JWOGUUIOCYMBPV +JWOGUUIOCYMBPV +JWOGUUIOCYMBPV +JWOGUUIOCYMBPV +JWOGUUIOCYMBPV +YAGQIZPAJNEIKG +QYRAHJVRFPJIQW +ZUXHELCHEWQXKW +ZITSQIZMRMDQLE +KJHOCLYVJRTASU +KJHOCLYVJRTASU +JJWITJNSXCXULM +GCYCNNNVEBIXIM +GCYCNNNVEBIXIM +OJSUENRPBJADBN +ZZLORXCOISZFNX +RQOFTLFCRJDAJR +HKSURPHWRMGDOZ +HKSURPHWRMGDOZ +HKSURPHWRMGDOZ +HKSURPHWRMGDOZ +FTGOWEQDZZMPNJ +FTGOWEQDZZMPNJ +FTGOWEQDZZMPNJ +FTGOWEQDZZMPNJ +DSHVEBDLSYMWSX +DSHVEBDLSYMWSX +DSHVEBDLSYMWSX +DWQQWNRHLJPIDV +DWQQWNRHLJPIDV +DWQQWNRHLJPIDV +DWQQWNRHLJPIDV +PNDDYPOQKFXUHY +PNDDYPOQKFXUHY +LGYQYCWMQRMLJJ +LGYQYCWMQRMLJJ +VBKOUAVWXRGGDI +VBKOUAVWXRGGDI +AERWTVOXUHXGAE +AERWTVOXUHXGAE +AERWTVOXUHXGAE +MDIRDFOZMJDCMK +MDIRDFOZMJDCMK +MDIRDFOZMJDCMK +JEOAJYYDZYNEAH +FDYWPCLQYXMCJD +FDYWPCLQYXMCJD +FDYWPCLQYXMCJD +XNBNKCLBGTWWSD +CUZZLIJKCADKLX +IUPCWCLVECYZRV +IUPCWCLVECYZRV +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +NSYZCCDSJNWWJL +NSYZCCDSJNWWJL +NSYZCCDSJNWWJL +NSYZCCDSJNWWJL +NSYZCCDSJNWWJL +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +WLOHNSSYAXHWNR +WLOHNSSYAXHWNR +WLOHNSSYAXHWNR +WLOHNSSYAXHWNR +WLOHNSSYAXHWNR +AMOGMTLMADGEOQ +XJLATMLVMSFZBN +XTLROSDJDZHIIK +YOTUXHIWBVZAJQ +YOTUXHIWBVZAJQ +DLQPRUDQTOCNPH +DLQPRUDQTOCNPH +GPPWDBNOAOQQHD +GPPWDBNOAOQQHD +ONNIQHQMYBDPDM +ONNIQHQMYBDPDM +NNLJICJPZZZIFI +NNLJICJPZZZIFI +VMVYMIWOVFQGAH +VMVYMIWOVFQGAH +ZFZHYNHHVLSRHQ +ZFZHYNHHVLSRHQ +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +SDQGXNQDYJJFFE +SDQGXNQDYJJFFE +MJKDGCARCYPVQG +KPYJUZGASBQBNI +KPYJUZGASBQBNI +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +RPWYCEBUPDNVLU +HPTABMIUROHMOU +HPTABMIUROHMOU +KASDHRXLYQOAKZ +KASDHRXLYQOAKZ +STZYTFJPGGDRJD +STZYTFJPGGDRJD +OCINXEZVIIVXFU +OCINXEZVIIVXFU +PBAPPPCECJKMCM +PBAPPPCECJKMCM +PBAPPPCECJKMCM +PBAPPPCECJKMCM +LLJFMFZYVVLQKT +LLJFMFZYVVLQKT +LLJFMFZYVVLQKT +LLJFMFZYVVLQKT +LLJFMFZYVVLQKT +LLJFMFZYVVLQKT +LLJFMFZYVVLQKT +LLJFMFZYVVLQKT +LLJFMFZYVVLQKT +LLJFMFZYVVLQKT +LLJFMFZYVVLQKT +LLJFMFZYVVLQKT +LLJFMFZYVVLQKT +LLJFMFZYVVLQKT +LLJFMFZYVVLQKT +JRURYQJSLYLRLN +JRURYQJSLYLRLN +WSYVIAQNTFPTBI +WSYVIAQNTFPTBI +WSYVIAQNTFPTBI +WSYVIAQNTFPTBI +WSYVIAQNTFPTBI +WSYVIAQNTFPTBI +WSYVIAQNTFPTBI +OOLLAFOLCSJHRE +OOLLAFOLCSJHRE +ZKFQEACEUNWPMT +ZKFQEACEUNWPMT +ZKFQEACEUNWPMT +ZKFQEACEUNWPMT +ZKFQEACEUNWPMT +KGSXMPPBFPAXLY +KGSXMPPBFPAXLY +KGSXMPPBFPAXLY +KGSXMPPBFPAXLY +KGSXMPPBFPAXLY +LTXREWYXXSTFRX +LTXREWYXXSTFRX +LTXREWYXXSTFRX +LTXREWYXXSTFRX +LTXREWYXXSTFRX +LTXREWYXXSTFRX +LTXREWYXXSTFRX +LTXREWYXXSTFRX +LTXREWYXXSTFRX +BMQGVNUXMIRLCK +BMQGVNUXMIRLCK +BMQGVNUXMIRLCK +BMQGVNUXMIRLCK +JZCPYUJPEARBJL +JZCPYUJPEARBJL +JZCPYUJPEARBJL +AGOYDEPGAOXOCK +AGOYDEPGAOXOCK +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +ANEBWFXPVPTEET +ANEBWFXPVPTEET +ANEBWFXPVPTEET +ANEBWFXPVPTEET +ANEBWFXPVPTEET +ANEBWFXPVPTEET +ANEBWFXPVPTEET +ANEBWFXPVPTEET +ANEBWFXPVPTEET +ANEBWFXPVPTEET +ANEBWFXPVPTEET +ANEBWFXPVPTEET +ANEBWFXPVPTEET +ANEBWFXPVPTEET +ANEBWFXPVPTEET +ANEBWFXPVPTEET +ANEBWFXPVPTEET +VHVPQPYKVGDNFY +VHVPQPYKVGDNFY +WHXMKTBCFHIYNQ +WHXMKTBCFHIYNQ +SVOQIEJWJCQGDQ +SVOQIEJWJCQGDQ +SNUDIPVBUUXCDG +SNUDIPVBUUXCDG +KSGXQBZTULBEEQ +KSGXQBZTULBEEQ +KSGXQBZTULBEEQ +KSGXQBZTULBEEQ +KSGXQBZTULBEEQ +KSGXQBZTULBEEQ +KSGXQBZTULBEEQ +MNDBXUUTURYVHR +MNDBXUUTURYVHR +MNDBXUUTURYVHR +MNDBXUUTURYVHR +XVGOZDAJGBALKS +XVGOZDAJGBALKS +XVGOZDAJGBALKS +XVGOZDAJGBALKS +XVGOZDAJGBALKS +KXNPVXPOPUZYGB +KXNPVXPOPUZYGB +ZSZFUDFOPOMEET +ZSZFUDFOPOMEET +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +MLKXDPUZXIRXEP +CZFFBEXEKNGXKS +CZFFBEXEKNGXKS +CZFFBEXEKNGXKS +CZFFBEXEKNGXKS +CZFFBEXEKNGXKS +CZFFBEXEKNGXKS +CZFFBEXEKNGXKS +JUZYLCPPVHEVSV +JUZYLCPPVHEVSV +JUZYLCPPVHEVSV +JUZYLCPPVHEVSV +JUZYLCPPVHEVSV +JUZYLCPPVHEVSV +JUZYLCPPVHEVSV +MQTOSJVFKKJCRP +MQTOSJVFKKJCRP +UAJUXJSXCLUTNU +UAJUXJSXCLUTNU +JVEONPNCICCMNY +AFZFFLVORLEPPO +AFZFFLVORLEPPO +AFZFFLVORLEPPO +JQXXHWHPUNPDRT +JQXXHWHPUNPDRT +WDZCUPBHRAEYDL +WOZSCQDILHKSGG +WOZSCQDILHKSGG +WOZSCQDILHKSGG +WOZSCQDILHKSGG +WOZSCQDILHKSGG +WOZSCQDILHKSGG +YMARZQAQMVYCKC +YMARZQAQMVYCKC +YMARZQAQMVYCKC +YMARZQAQMVYCKC +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +QNZCBYKSOIHPEH +QNZCBYKSOIHPEH +QNZCBYKSOIHPEH +NCEXYHBECQHGNR +NCEXYHBECQHGNR +OGQICQVSFDPSEI +OGQICQVSFDPSEI +OGQICQVSFDPSEI +OGQICQVSFDPSEI +OGQICQVSFDPSEI +OGQICQVSFDPSEI +OGQICQVSFDPSEI +BQSJTQLCZDPROO +BQSJTQLCZDPROO +BQSJTQLCZDPROO +BQSJTQLCZDPROO +BQSJTQLCZDPROO +BQSJTQLCZDPROO +BQSJTQLCZDPROO +BBAWEDCPNXPBQM +BBAWEDCPNXPBQM +BBAWEDCPNXPBQM +BBAWEDCPNXPBQM +WZPBZJONDBGPKJ +WZPBZJONDBGPKJ +WZPBZJONDBGPKJ +OGSBUKJUDHAQEA +OGSBUKJUDHAQEA +OGSBUKJUDHAQEA +OGSBUKJUDHAQEA +XMXHEBAFVSFQEX +XMXHEBAFVSFQEX +XMXHEBAFVSFQEX +XMXHEBAFVSFQEX +XMXHEBAFVSFQEX +XMXHEBAFVSFQEX +XMXHEBAFVSFQEX +DMJNNHOOLUXYBV +DMJNNHOOLUXYBV +HFNKQEVNSGCOJV +HFNKQEVNSGCOJV +HFNKQEVNSGCOJV +AZSNMRSAGSSBNP +AZSNMRSAGSSBNP +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +WIGIZIANZCJQQY +GPXBXXGIAQBQNI +GPXBXXGIAQBQNI +GPXBXXGIAQBQNI +GPXBXXGIAQBQNI +GPXBXXGIAQBQNI +JWJOTENAMICLJG +DBEPLOCGEIEOCV +VWUXBMIQPBEWFH +VWUXBMIQPBEWFH +ATALOFNDEOCMKK +ATALOFNDEOCMKK +FNHKPVJBJVTLMP +FNHKPVJBJVTLMP +FNHKPVJBJVTLMP +FNHKPVJBJVTLMP +FNHKPVJBJVTLMP +FNHKPVJBJVTLMP +FNHKPVJBJVTLMP +FNHKPVJBJVTLMP +FNHKPVJBJVTLMP +FNHKPVJBJVTLMP +FNHKPVJBJVTLMP +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +PURKAOJPTOLRMP +PURKAOJPTOLRMP +PURKAOJPTOLRMP +PURKAOJPTOLRMP +PURKAOJPTOLRMP +BPQMGSKTAYIVFO +BPQMGSKTAYIVFO +KTEIFNKAUNYNJU +KTEIFNKAUNYNJU +KTEIFNKAUNYNJU +KTEIFNKAUNYNJU +KTEIFNKAUNYNJU +KTEIFNKAUNYNJU +KTEIFNKAUNYNJU +KTEIFNKAUNYNJU +WJEOLQLKVOPQFV +WJEOLQLKVOPQFV +WJEOLQLKVOPQFV +WJEOLQLKVOPQFV +WJEOLQLKVOPQFV +WJEOLQLKVOPQFV +WJEOLQLKVOPQFV +WJEOLQLKVOPQFV +WJEOLQLKVOPQFV +OJMMVQQUTAEWLP +OJMMVQQUTAEWLP +NSYZCCDSJNWWJL +NSYZCCDSJNWWJL +NSYZCCDSJNWWJL +NSYZCCDSJNWWJL +NSYZCCDSJNWWJL +NSYZCCDSJNWWJL +NSYZCCDSJNWWJL +NSYZCCDSJNWWJL +NSYZCCDSJNWWJL +NSYZCCDSJNWWJL +NSYZCCDSJNWWJL +NSYZCCDSJNWWJL +RKEBXTALJSALNU +USXIYWCPCGVOKF +USXIYWCPCGVOKF +NGPDQWFWZNXVLZ +MQIAICAGVFTAAN +JFWABYMXSVHLEW +CGZKSPLDUIRCIO +CGZKSPLDUIRCIO +PHYRFZDJEDWWKT +DLSUXMZHOIJLGM +DLSUXMZHOIJLGM +DLSUXMZHOIJLGM +DLSUXMZHOIJLGM +VWUXBMIQPBEWFH +VWUXBMIQPBEWFH +VWUXBMIQPBEWFH +VWUXBMIQPBEWFH +VWUXBMIQPBEWFH +UZMVEOVJASEKLP +HQEBGENSMXBRMP +HQEBGENSMXBRMP +GKWSTXDESFGCFI +GKWSTXDESFGCFI +GKWSTXDESFGCFI +HKSZLNNOFSGOKW +OHBCWVJHZZYAHJ +OHBCWVJHZZYAHJ +OHBCWVJHZZYAHJ +OHBCWVJHZZYAHJ +YQLQWGVOWKPLFR +QURRTAYEASAREY +QURRTAYEASAREY +QURRTAYEASAREY +QURRTAYEASAREY +VCAGNEUDNVLWPT +VCAGNEUDNVLWPT +GRJSOZDXIUZXEW +GRJSOZDXIUZXEW +GRJSOZDXIUZXEW +GRJSOZDXIUZXEW +FFCLYSVFZQXUHI +FFCLYSVFZQXUHI +JSGVRMXIAILPPO +JSGVRMXIAILPPO +JSGVRMXIAILPPO +HFJDWELARBQGBQ +HFJDWELARBQGBQ +HFJDWELARBQGBQ +FVHOUXKYAQHQLA +FVHOUXKYAQHQLA +FVHOUXKYAQHQLA +OVFLBUBMFUWQCS +OVFLBUBMFUWQCS +OVFLBUBMFUWQCS +BADPZPNBPIOSER +BADPZPNBPIOSER +BADPZPNBPIOSER +OGYMUMAKGYYNHV +OGYMUMAKGYYNHV +OGYMUMAKGYYNHV +MPZFKYARTKTCEC +MPZFKYARTKTCEC +MPZFKYARTKTCEC +MPZFKYARTKTCEC +PIXYPRXKMCTYQV +PIXYPRXKMCTYQV +PIXYPRXKMCTYQV +PIXYPRXKMCTYQV +ZOCXUHJGZXXIGQ +ZOCXUHJGZXXIGQ +ZOCXUHJGZXXIGQ +IFFDZLRWLNUFOX +IFFDZLRWLNUFOX +IFFDZLRWLNUFOX +QTTUBTNSWLIYPX +QTTUBTNSWLIYPX +QTTUBTNSWLIYPX +ZPEFYJBGAZLAKK +ZPEFYJBGAZLAKK +ZPEFYJBGAZLAKK +BXGLWTGIQGFBBV +BXGLWTGIQGFBBV +BXGLWTGIQGFBBV +LGIBRQVYYFOBSF +LGIBRQVYYFOBSF +LGIBRQVYYFOBSF +MLCMEHUPTMULKN +MLCMEHUPTMULKN +MLCMEHUPTMULKN +MYLOBISKHDRNEW +MYLOBISKHDRNEW +MYLOBISKHDRNEW +AYCHHMYWQIVWMV +AYCHHMYWQIVWMV +AYCHHMYWQIVWMV +HRNMOJZLZGYPOJ +OJZQWQZTFYKVNT +OJZQWQZTFYKVNT +OJZQWQZTFYKVNT +ICIIUZVGRRIKHJ +ICIIUZVGRRIKHJ +ICIIUZVGRRIKHJ +MRMIYTQOIYVEFZ +MRMIYTQOIYVEFZ +MRMIYTQOIYVEFZ +ATUHCRPOJACLPO +ATUHCRPOJACLPO +ATUHCRPOJACLPO +ZEYMFVVXLAGXAL +ZEYMFVVXLAGXAL +VXUXCAXVQWIEMN +VXUXCAXVQWIEMN +VXUXCAXVQWIEMN +NCHUIUBVZLLXAJ +NCHUIUBVZLLXAJ +NCHUIUBVZLLXAJ +GBKBPIXSSQJOPJ +GBKBPIXSSQJOPJ +GBKBPIXSSQJOPJ +GBKBPIXSSQJOPJ +GBKBPIXSSQJOPJ +GARAEILXWIXANX +GARAEILXWIXANX +GARAEILXWIXANX +PHKITYYXVNXRGE +PHKITYYXVNXRGE +PHKITYYXVNXRGE +PHKITYYXVNXRGE +RJACTZZAVQNVQK +RJACTZZAVQNVQK +RJACTZZAVQNVQK +KXXKOWOCBYEZCA +KXXKOWOCBYEZCA +KXXKOWOCBYEZCA +SWJBHFDLMKOOQE +SWJBHFDLMKOOQE +SWJBHFDLMKOOQE +WNRUALXAFJYRCE +WNRUALXAFJYRCE +WNRUALXAFJYRCE +PDCMAZVDUCREJL +PDCMAZVDUCREJL +MMQMICJUIQBJJJ +MMQMICJUIQBJJJ +MMQMICJUIQBJJJ +MMQMICJUIQBJJJ +GKEXBSIRYODQRM +GKEXBSIRYODQRM +GKEXBSIRYODQRM +UKEKDXCEMCJARX +UKEKDXCEMCJARX +UKEKDXCEMCJARX +AGHDGYYFFAIILP +AGHDGYYFFAIILP +AGHDGYYFFAIILP +AMGBYGMMAJGWQD +AMGBYGMMAJGWQD +AMGBYGMMAJGWQD +NMZCKAXEXHHLDH +NMZCKAXEXHHLDH +NMZCKAXEXHHLDH +CWOLYEAWYFDDKD +CWOLYEAWYFDDKD +CWOLYEAWYFDDKD +UBYKKSNRJIVBEI +UBYKKSNRJIVBEI +UBYKKSNRJIVBEI +GCLURMGOFQYPMX +GCLURMGOFQYPMX +GCLURMGOFQYPMX +GCLURMGOFQYPMX +AVHQSUKHXDQQSC +AVHQSUKHXDQQSC +AVHQSUKHXDQQSC +YEFFYMICJWFTIL +YEFFYMICJWFTIL +YEFFYMICJWFTIL +SQDUHNNBULODLI +SQDUHNNBULODLI +SQDUHNNBULODLI +ZFOFFTSUQWMVNL +ZFOFFTSUQWMVNL +ZFOFFTSUQWMVNL +PHWXQCBABMTLTQ +PHWXQCBABMTLTQ +FQNIZALEELLLNQ +FQNIZALEELLLNQ +FQNIZALEELLLNQ +SSFPOWGTSSRZDF +SSFPOWGTSSRZDF +SSFPOWGTSSRZDF +HDJJPERVTBQOBC +HDJJPERVTBQOBC +HDJJPERVTBQOBC +PWWIFQHUWJQASW +PWWIFQHUWJQASW +PWWIFQHUWJQASW +LLQJFGBIMAPDTJ +LLQJFGBIMAPDTJ +LLQJFGBIMAPDTJ +LLQJFGBIMAPDTJ +USEFEKIFGMLTIB +USEFEKIFGMLTIB +USEFEKIFGMLTIB +KSLXCQVQZMCEPY +KSLXCQVQZMCEPY +VRXZHZLPIYFKDW +VRXZHZLPIYFKDW +VRXZHZLPIYFKDW +FXKUPAGEXVLVEV +FXKUPAGEXVLVEV +FXKUPAGEXVLVEV +WTPJZVZQUQWCMF +WTPJZVZQUQWCMF +WTPJZVZQUQWCMF +YDZBIJNYUJFTNZ +YDZBIJNYUJFTNZ +YDZBIJNYUJFTNZ +AVPFVRKZYHPFBT +AVPFVRKZYHPFBT +AVPFVRKZYHPFBT +OKCMAFOUZDQDBH +OKCMAFOUZDQDBH +OKCMAFOUZDQDBH +GSARVYDKESLKKS +GSARVYDKESLKKS +GSARVYDKESLKKS +LDKHRGLGCZVRAX +LDKHRGLGCZVRAX +LDKHRGLGCZVRAX +YNLGERVNWAHYNI +YNLGERVNWAHYNI +YNLGERVNWAHYNI +FTOJBALCTWZQGM +FTOJBALCTWZQGM +FTOJBALCTWZQGM +YIFXQLQWWPSRLF +YIFXQLQWWPSRLF +YIFXQLQWWPSRLF +USLJNRHZMUHXEP +USLJNRHZMUHXEP +DZWXFJLWJABUHC +DZWXFJLWJABUHC +DZWXFJLWJABUHC +RVWUYWYTAUFLIC +RVWUYWYTAUFLIC +RVWUYWYTAUFLIC +BDPXJTPVQWCGDD +BDPXJTPVQWCGDD +BDPXJTPVQWCGDD +CUAUBJZNRREZCR +CUAUBJZNRREZCR +CUAUBJZNRREZCR +QHDCKXFDMBWWNQ +QHDCKXFDMBWWNQ +QHDCKXFDMBWWNQ +BOVCPOFKWQTUSV +BOVCPOFKWQTUSV +BOVCPOFKWQTUSV +NFBXYDSBMJBNII +NFBXYDSBMJBNII +NFBXYDSBMJBNII +ALVQDLJLHBFZQA +ALVQDLJLHBFZQA +ALVQDLJLHBFZQA +VCZZNWBEZXJEAR +VCZZNWBEZXJEAR +VCZZNWBEZXJEAR +HCWNHTMVKXFNDO +HCWNHTMVKXFNDO +HCWNHTMVKXFNDO +PDLGLENBVYBASR +PDLGLENBVYBASR +LYRSWYUKKSYGHG +LYRSWYUKKSYGHG +LYRSWYUKKSYGHG +MSEXIFQGEYERRX +MSEXIFQGEYERRX +MSEXIFQGEYERRX +PSVNNOPRRYEIFK +PSVNNOPRRYEIFK +PSVNNOPRRYEIFK +JDUHMMCKAJUKRF +JDUHMMCKAJUKRF +JDUHMMCKAJUKRF +AGJMGGRSZQVSTF +AGJMGGRSZQVSTF +AGJMGGRSZQVSTF +AGJMGGRSZQVSTF +NFOPUOMYXLXIJB +NFOPUOMYXLXIJB +NFOPUOMYXLXIJB +FTNRMSPQVKTVAM +FTNRMSPQVKTVAM +FTNRMSPQVKTVAM +RXXVJSOLUYPQPZ +RXXVJSOLUYPQPZ +RXXVJSOLUYPQPZ +YTUFKZZYOYOVLX +YTUFKZZYOYOVLX +YTUFKZZYOYOVLX +RDRBSFWZTUVROA +RDRBSFWZTUVROA +RDRBSFWZTUVROA +RDRBSFWZTUVROA +MEUCDVSQLGGGLX +MEUCDVSQLGGGLX +MEUCDVSQLGGGLX +LHLTWRIQDPRCSZ +LHLTWRIQDPRCSZ +LHLTWRIQDPRCSZ +ROKKUUNJHBSAEF +ROKKUUNJHBSAEF +ROKKUUNJHBSAEF +YHRZGLJNJCTQQV +YHRZGLJNJCTQQV +YHRZGLJNJCTQQV +VOCOFHUEPQVHJE +VOCOFHUEPQVHJE +VOCOFHUEPQVHJE +ZMVMKVLOYDKCTI +ZMVMKVLOYDKCTI +ZMVMKVLOYDKCTI +IIIFYUHQHQOKMO +IIIFYUHQHQOKMO +IIIFYUHQHQOKMO +QNHUPNLLAVHRDJ +QNHUPNLLAVHRDJ +QNHUPNLLAVHRDJ +WOZYCBAXLDHDEB +WOZYCBAXLDHDEB +WOZYCBAXLDHDEB +XRZGRKMPWSSTAF +XRZGRKMPWSSTAF +BXMOTOWNHCSFSP +BXMOTOWNHCSFSP +BXMOTOWNHCSFSP +FARNTXCAKWOTQH +FARNTXCAKWOTQH +FARNTXCAKWOTQH +AILPXCDEDGHWQC +AILPXCDEDGHWQC +AILPXCDEDGHWQC +RLTDFYMTYDXCSF +RLTDFYMTYDXCSF +RLTDFYMTYDXCSF +RLTDFYMTYDXCSF +WFTRFWSEDHVVOE +WFTRFWSEDHVVOE +WFTRFWSEDHVVOE +RFRBIRKPFUGUKT +RFRBIRKPFUGUKT +RFRBIRKPFUGUKT +CNXFTPKHMABMBC +CNXFTPKHMABMBC +CNXFTPKHMABMBC +DTSLQRYTBPWOBN +DTSLQRYTBPWOBN +DTSLQRYTBPWOBN +CSJBKPPSSUQCIE +CSJBKPPSSUQCIE +RNKKSOUENQNNJB +RNKKSOUENQNNJB +RNKKSOUENQNNJB +RXESJWRWQWCTAV +RXESJWRWQWCTAV +RXESJWRWQWCTAV +FAHZXGJFHYJMLU +FAHZXGJFHYJMLU +FAHZXGJFHYJMLU +PMPHCGXWGWRVSJ +PMPHCGXWGWRVSJ +PMPHCGXWGWRVSJ +DIJBCARHXBFGSN +DIJBCARHXBFGSN +DIJBCARHXBFGSN +DIJBCARHXBFGSN +JQTXFWSBYJZDFF +WOXQQQHJNDJPHP +WOXQQQHJNDJPHP +WOXQQQHJNDJPHP +KGNYNVWSNNXUNF +KGNYNVWSNNXUNF +KGNYNVWSNNXUNF +ZVLHPBFYEDFKIY +ZVLHPBFYEDFKIY +ZVLHPBFYEDFKIY +ZDSHEBAVQCBURR +ZDSHEBAVQCBURR +ZDSHEBAVQCBURR +QYBFHUUUTSZUTO +QYBFHUUUTSZUTO +QYBFHUUUTSZUTO +PIZQKOSQBSIESB +PIZQKOSQBSIESB +PIZQKOSQBSIESB +CNYVPRIGBOOHDC +CNYVPRIGBOOHDC +CNYVPRIGBOOHDC +PCANANBJDAQYGI +PCANANBJDAQYGI +PCANANBJDAQYGI +STCRSKDDWLDYSP +STCRSKDDWLDYSP +JBNXLEJYTVBBHC +JBNXLEJYTVBBHC +JBNXLEJYTVBBHC +XBDBMKOPNQANJN +XBDBMKOPNQANJN +XBDBMKOPNQANJN +BPXJXCVYEZUYRH +BPXJXCVYEZUYRH +BPXJXCVYEZUYRH +GREXDTSPJZUSJC +GREXDTSPJZUSJC +GREXDTSPJZUSJC +PNGNXUXNRUYHEL +PNGNXUXNRUYHEL +PNGNXUXNRUYHEL +PNGNXUXNRUYHEL +YJVACXJBQCEFNY +YJVACXJBQCEFNY +YJVACXJBQCEFNY +YQVAQDHJIPZYHG +YQVAQDHJIPZYHG +YQVAQDHJIPZYHG +QMOGVBWGGQQFDH +QMOGVBWGGQQFDH +QMOGVBWGGQQFDH +KLNVHWBMMLHHOC +KLNVHWBMMLHHOC +KLNVHWBMMLHHOC +KLNVHWBMMLHHOC +UPCUESMFMJVGBA +UPCUESMFMJVGBA +UPCUESMFMJVGBA +QTRDVJGBYWSGOO +QTRDVJGBYWSGOO +QTRDVJGBYWSGOO +SOOOWWAEINJSLJ +SOOOWWAEINJSLJ +SOOOWWAEINJSLJ +ONGYBDFXJVCKEV +ONGYBDFXJVCKEV +ONGYBDFXJVCKEV +PZWDSXVJIJBNPG +PZWDSXVJIJBNPG +PZWDSXVJIJBNPG +YHNRWYMFUPQKJZ +YHNRWYMFUPQKJZ +YHNRWYMFUPQKJZ +MESZUNKTCYOZRK +MESZUNKTCYOZRK +MESZUNKTCYOZRK +HXNFQTIYZFUYEW +HXNFQTIYZFUYEW +DDBHATPDKFLXIG +DDBHATPDKFLXIG +DDBHATPDKFLXIG +DDBHATPDKFLXIG +PQVHLIFAUKMJML +PQVHLIFAUKMJML +PQVHLIFAUKMJML +YCARPPJTBWBPDJ +YCARPPJTBWBPDJ +YCARPPJTBWBPDJ +NZAGTSBDUAJJGL +NZAGTSBDUAJJGL +NZAGTSBDUAJJGL +WHLQQOPJXRTWRO +WHLQQOPJXRTWRO +WHLQQOPJXRTWRO +KVANGSRRXKJYSW +KVANGSRRXKJYSW +KVANGSRRXKJYSW +PXUOVQNNQBMWQR +PXUOVQNNQBMWQR +PXUOVQNNQBMWQR +VTZAZJQDVXOLNM +VTZAZJQDVXOLNM +VTZAZJQDVXOLNM +YNYUEFMFBNMXPV +UXZGAUGFBNFFQR +UXZGAUGFBNFFQR +UXZGAUGFBNFFQR +LYLNTQIDHAOMGF +LYLNTQIDHAOMGF +LYLNTQIDHAOMGF +CVSUSOFRKSXEAN +CVSUSOFRKSXEAN +CVSUSOFRKSXEAN +REGKJMCAFMDIKC +REGKJMCAFMDIKC +REGKJMCAFMDIKC +WZAQJAOJSYRYDC +WZAQJAOJSYRYDC +WZAQJAOJSYRYDC +UEIQYRCXPMOTHA +UEIQYRCXPMOTHA +UEIQYRCXPMOTHA +JELCGLNTGJJMGT +JELCGLNTGJJMGT +JELCGLNTGJJMGT +IRVZTSMQCDONTP +IRVZTSMQCDONTP +OUZGZGKAJJLACJ +OUZGZGKAJJLACJ +OUZGZGKAJJLACJ +DROPVPJMRGGPKM +DROPVPJMRGGPKM +DROPVPJMRGGPKM +DROPVPJMRGGPKM +OWVZNLPKMMDHAL +OWVZNLPKMMDHAL +OWVZNLPKMMDHAL +NUGOVDMHSBCPIZ +NUGOVDMHSBCPIZ +NUGOVDMHSBCPIZ +RKUBMBLGFNKPSN +RKUBMBLGFNKPSN +RKUBMBLGFNKPSN +RKUBMBLGFNKPSN +ZGIYTMFOVCZQCW +ZGIYTMFOVCZQCW +ZGIYTMFOVCZQCW +KWLXUCWSOPMBFC +KWLXUCWSOPMBFC +KWLXUCWSOPMBFC +GCQLMMJEZUVBCW +GCQLMMJEZUVBCW +GCQLMMJEZUVBCW +ZXMCQABPFYLXEC +ZXMCQABPFYLXEC +ZXMCQABPFYLXEC +GWJCQMINNOBSGW +GWJCQMINNOBSGW +JRASSONTPQQYOK +JRASSONTPQQYOK +JRASSONTPQQYOK +SENIDMFOGMNMOE +SENIDMFOGMNMOE +SENIDMFOGMNMOE +KEGRENGWTJNAKX +KEGRENGWTJNAKX +KEGRENGWTJNAKX +FTOCKSWYRGPOOT +FTOCKSWYRGPOOT +FTOCKSWYRGPOOT +PEWDJIVDOBJZCY +PEWDJIVDOBJZCY +PEWDJIVDOBJZCY +QESKTGPWJKWNMI +TZRXVHCLACOTIB +TZRXVHCLACOTIB +TZRXVHCLACOTIB +RPSRDQXMWPAPPJ +RPSRDQXMWPAPPJ +RPSRDQXMWPAPPJ +HMFJMHYAVAPOMR +PTDIHRDFLWQSHR +PTDIHRDFLWQSHR +PTDIHRDFLWQSHR +VVBIBQHJRBQKJA +VVBIBQHJRBQKJA +VVBIBQHJRBQKJA +OCFNCZBGPQYSFB +OCFNCZBGPQYSFB +OCFNCZBGPQYSFB +MYDNMWYERUOOAI +MYDNMWYERUOOAI +MYDNMWYERUOOAI +GYUVCMNTGCZTKT +GYUVCMNTGCZTKT +GYUVCMNTGCZTKT +VPRFJIZEFDHWAX +VPRFJIZEFDHWAX +VPRFJIZEFDHWAX +YJZODQMTGYMDAM +YJZODQMTGYMDAM +VNQFXKILOOTCRV +VNQFXKILOOTCRV +VNQFXKILOOTCRV +JXZHAIQRKDRCMH +JXZHAIQRKDRCMH +JXZHAIQRKDRCMH +FRXPSNLWKAAHFZ +FRXPSNLWKAAHFZ +FRXPSNLWKAAHFZ +QESMKVGGPIOKNK +QESMKVGGPIOKNK +QESMKVGGPIOKNK +VQOQYPOVQVTGOG +VQOQYPOVQVTGOG +VQOQYPOVQVTGOG +BRQVONMNQFYHGY +BRQVONMNQFYHGY +BRQVONMNQFYHGY +ZHXIFYRCXUPVBR +ZHXIFYRCXUPVBR +ZHXIFYRCXUPVBR +MCULYHCMQKYZMP +MCULYHCMQKYZMP +MCULYHCMQKYZMP +ROCFJRXVWQSNEA +ROCFJRXVWQSNEA +ROCFJRXVWQSNEA +RCJXONNGEVLXKD +RCJXONNGEVLXKD +RCJXONNGEVLXKD +BVVRLCIBHUVKNW +BVVRLCIBHUVKNW +BVVRLCIBHUVKNW +GBYYTPWELIINLX +GBYYTPWELIINLX +GBYYTPWELIINLX +YTCJLHLTUIDAEH +YTCJLHLTUIDAEH +YTCJLHLTUIDAEH +LSFLWFDRUBYZIP +LSFLWFDRUBYZIP +LSFLWFDRUBYZIP +OXCKGFOSGDWSMV +OXCKGFOSGDWSMV +OXCKGFOSGDWSMV +OXCKGFOSGDWSMV +LCWSIYOSNVKMHK +LCWSIYOSNVKMHK +LCWSIYOSNVKMHK +BTHJFCLLAOTGAB +BTHJFCLLAOTGAB +BTHJFCLLAOTGAB +IBWGYBLOTXJRTJ +IBWGYBLOTXJRTJ +IBWGYBLOTXJRTJ +YNZKVEFJNKSUHC +YNZKVEFJNKSUHC +YNZKVEFJNKSUHC +YHEMYMWBIDVLAL +YHEMYMWBIDVLAL +YHEMYMWBIDVLAL +UZUOPSCSEHJPNP +UZUOPSCSEHJPNP +UZUOPSCSEHJPNP +XDUGYXFHJVWZHK +XDUGYXFHJVWZHK +XDUGYXFHJVWZHK +HPJHEPAGWJSHLV +HPJHEPAGWJSHLV +HPJHEPAGWJSHLV +BMPKOXSAQXZPCM +BMPKOXSAQXZPCM +BMPKOXSAQXZPCM +CHAOJHXKJJCNDG +CHAOJHXKJJCNDG +CHAOJHXKJJCNDG +WAPKDUAGJQAYPS +WAPKDUAGJQAYPS +WAPKDUAGJQAYPS +HXICCMHWNGDAJQ +XIQGXSFCCSYSCP +XIQGXSFCCSYSCP +XIQGXSFCCSYSCP +BPCQXVWZPZOKKC +BPCQXVWZPZOKKC +TUBMBDHHDVCASO +TUBMBDHHDVCASO +TUBMBDHHDVCASO +OXJTVPMAMRSGNT +OXJTVPMAMRSGNT +OXJTVPMAMRSGNT +AHVXEXDRYIGQKJ +AHVXEXDRYIGQKJ +AHVXEXDRYIGQKJ +NDMXAKIPAWWRRZ +NDMXAKIPAWWRRZ +NDMXAKIPAWWRRZ +SVTPXVXFTKTVOC +SVTPXVXFTKTVOC +SVTPXVXFTKTVOC +NZVUPBACKUBKKL +NZVUPBACKUBKKL +DCQUDTJJTJTVFD +DCQUDTJJTJTVFD +DCQUDTJJTJTVFD +WXWPSJSWPSNOHC +WXWPSJSWPSNOHC +WXWPSJSWPSNOHC +YJORWXDBAFCOCD +YJORWXDBAFCOCD +YJORWXDBAFCOCD +AZXVVJPUZKNSRZ +AZXVVJPUZKNSRZ +AZXVVJPUZKNSRZ +XZKDGTWGTSBDNN +XZKDGTWGTSBDNN +XZKDGTWGTSBDNN +CXHXRKINHAOWFS +CXHXRKINHAOWFS +CXHXRKINHAOWFS +YEKKHUHTHMVGBZ +YEKKHUHTHMVGBZ +YEKKHUHTHMVGBZ +GYLSGLQQOWKZHD +GYLSGLQQOWKZHD +GYLSGLQQOWKZHD +GYLSGLQQOWKZHD +GYLSGLQQOWKZHD +DNPHDYQYRGRPAG +DNPHDYQYRGRPAG +DNPHDYQYRGRPAG +ZTOJHAHYTWGMGJ +ZTOJHAHYTWGMGJ +ZTOJHAHYTWGMGJ +FEAFOKYFRFVAFA +FEAFOKYFRFVAFA +ZRRSRYKDUIUGIR +ZRRSRYKDUIUGIR +ZRRSRYKDUIUGIR +WPGKHJAEQXWLAZ +WPGKHJAEQXWLAZ +WPGKHJAEQXWLAZ +IRNUPRQLMCJWCN +IRNUPRQLMCJWCN +IRNUPRQLMCJWCN +JOWUQKNFWBOWCT +JOWUQKNFWBOWCT +JOWUQKNFWBOWCT +LPNOYCNHIDLOGP +LPNOYCNHIDLOGP +LPNOYCNHIDLOGP +MIUKXQLUAYGHTD +MIUKXQLUAYGHTD +MIUKXQLUAYGHTD +AZYRQYLZPXVPSJ +AZYRQYLZPXVPSJ +AZYRQYLZPXVPSJ +PONNJJHIKLFESH +PONNJJHIKLFESH +PONNJJHIKLFESH +VYPKVACBNNLRAS +VYPKVACBNNLRAS +VYPKVACBNNLRAS +TUJLPRBZDNVLJR +TUJLPRBZDNVLJR +TUJLPRBZDNVLJR +XHZOMARNWAHTET +XHZOMARNWAHTET +XHZOMARNWAHTET +VPDCCQRJJKBHBP +VPDCCQRJJKBHBP +VPDCCQRJJKBHBP +MIENDESJFFOVSM +MIENDESJFFOVSM +MIENDESJFFOVSM +URQXIIHSGKEZON +URQXIIHSGKEZON +URQXIIHSGKEZON +UCJCXWLJKXAHSH +UCJCXWLJKXAHSH +UCJCXWLJKXAHSH +QBNSLRXGOOQJFK +QBNSLRXGOOQJFK +QBNSLRXGOOQJFK +FAQWEFDAXRGRBY +FAQWEFDAXRGRBY +FAQWEFDAXRGRBY +FUZPGGMNJUWFEA +FUZPGGMNJUWFEA +FUZPGGMNJUWFEA +BWHBUDJEUBMEPZ +YVEJCBRKBGZAAZ +YVEJCBRKBGZAAZ +YVEJCBRKBGZAAZ +QXRBDLBKKRKMFF +QXRBDLBKKRKMFF +QXRBDLBKKRKMFF +DMRLKRJDAJNMDH +DMRLKRJDAJNMDH +DMRLKRJDAJNMDH +ZOIRQLNDVPGFTM +ZOIRQLNDVPGFTM +ZOIRQLNDVPGFTM +QOADOXLVYMSBSY +QOADOXLVYMSBSY +QOADOXLVYMSBSY +MZDAQXSYVIPJJK +MZDAQXSYVIPJJK +MZDAQXSYVIPJJK +LTPGXAASPNLYQZ +LTPGXAASPNLYQZ +LTPGXAASPNLYQZ +YFPWJEOWQLXZMR +YFPWJEOWQLXZMR +YFPWJEOWQLXZMR +KMPLOJPKAHHWNU +KMPLOJPKAHHWNU +KMPLOJPKAHHWNU +GZGWASQYURNJLM +GZGWASQYURNJLM +GZGWASQYURNJLM +JJWYXHWYBWDXCK +JJWYXHWYBWDXCK +JJWYXHWYBWDXCK +YTEHVKDCLRRSJB +YTEHVKDCLRRSJB +YTEHVKDCLRRSJB +GYRKGFXISUTHLH +GYRKGFXISUTHLH +GYRKGFXISUTHLH +UULVWARUZBRKLD +UULVWARUZBRKLD +UULVWARUZBRKLD +RZAZLALCJQVAPC +RZAZLALCJQVAPC +RZAZLALCJQVAPC +NTGGFYHYQNSRQJ +NTGGFYHYQNSRQJ +NTGGFYHYQNSRQJ +YNZSTFNGSUGXAX +YNZSTFNGSUGXAX +IGOSULLLOBTOCB +IGOSULLLOBTOCB +IGOSULLLOBTOCB +LKAOZIIQNHMHNM +LKAOZIIQNHMHNM +LKAOZIIQNHMHNM +WJMWPAZTLACBKL +WJMWPAZTLACBKL +WJMWPAZTLACBKL +OLDDPHCULUHICE +OLDDPHCULUHICE +OLDDPHCULUHICE +OFMRJFFYTUTRSE +OFMRJFFYTUTRSE +XHDFNMUXFMUHLW +JQYKLQPYSFFNCQ +JQYKLQPYSFFNCQ +JQYKLQPYSFFNCQ +ABNIDCXKNWWRAL +ABNIDCXKNWWRAL +ABNIDCXKNWWRAL +SUUYOTAOHACFEY +SUUYOTAOHACFEY +SUUYOTAOHACFEY +KGRJOSVTPNLALT +KGRJOSVTPNLALT +KGRJOSVTPNLALT +GRFDMYHZHROYFM +GRFDMYHZHROYFM +GRFDMYHZHROYFM +YJLUJJJKJQZZSL +YJLUJJJKJQZZSL +YJLUJJJKJQZZSL +CRWCVOFRPAMKPI +CRWCVOFRPAMKPI +CRWCVOFRPAMKPI +KSXLHOFDCDKQLH +KSXLHOFDCDKQLH +KSXLHOFDCDKQLH +FVZADXISYLXHTO +FVZADXISYLXHTO +FVZADXISYLXHTO +HCCQCYFDTNBIHH +HCCQCYFDTNBIHH +HCCQCYFDTNBIHH +JYLAZDLBJKSPAD +JYLAZDLBJKSPAD +JYLAZDLBJKSPAD +CLSWALKOZRKMDZ +CLSWALKOZRKMDZ +CLSWALKOZRKMDZ +PVWUBOJDSAGOTL +PVWUBOJDSAGOTL +PVWUBOJDSAGOTL +QZJATGWZKQNJSF +QZJATGWZKQNJSF +QZJATGWZKQNJSF +WXTNWRRZZHTAIL +WXTNWRRZZHTAIL +WXTNWRRZZHTAIL +ZEHJCPMBJCCTJJ +ZEHJCPMBJCCTJJ +FFMPRZQCEHLIFH +FFMPRZQCEHLIFH +FFMPRZQCEHLIFH +GLZZPIAWSMQBGB +GLZZPIAWSMQBGB +GLZZPIAWSMQBGB +GLZZPIAWSMQBGB +JDTCAUKPGHHILL +JDTCAUKPGHHILL +JDTCAUKPGHHILL +KUSZTEOAPUVHOT +KUSZTEOAPUVHOT +KUSZTEOAPUVHOT +QPNWNCGKXDUSFR +QPNWNCGKXDUSFR +QPNWNCGKXDUSFR +ZMDDERVSCYEKPQ +ZMDDERVSCYEKPQ +ZMDDERVSCYEKPQ +OLJWUBYLWNNFGF +OLJWUBYLWNNFGF +OLJWUBYLWNNFGF +VEJMFBKFPIFTRC +VEJMFBKFPIFTRC +VEJMFBKFPIFTRC +JDEGGSXDQXULCM +JDEGGSXDQXULCM +JDEGGSXDQXULCM +VOFSUBNULHNYFD +VOFSUBNULHNYFD +VOFSUBNULHNYFD +ISJJEQGKYKEBIA +ISJJEQGKYKEBIA +ISJJEQGKYKEBIA +NPVURCPDPDPBHZ +NPVURCPDPDPBHZ +NPVURCPDPDPBHZ +DAZUNJCWIVRHNL +DAZUNJCWIVRHNL +DAZUNJCWIVRHNL +LQXDKGIREDUPFL +LQXDKGIREDUPFL +LQXDKGIREDUPFL +MXMDZBPPJCQAIR +MXMDZBPPJCQAIR +MXMDZBPPJCQAIR +ZGTXXTZWJCUZSG +ZGTXXTZWJCUZSG +ZGTXXTZWJCUZSG +QWGHKKLFVCGNKI +QWGHKKLFVCGNKI +QWGHKKLFVCGNKI +DCYJCNSRLPAHOP +DCYJCNSRLPAHOP +DCYJCNSRLPAHOP +DJDFHKVJPZXTOW +DJDFHKVJPZXTOW +DJDFHKVJPZXTOW +WTLXQYKLIMSRJP +WTLXQYKLIMSRJP +WTLXQYKLIMSRJP +KNISYJGXVLSADL +KNISYJGXVLSADL +KNISYJGXVLSADL +RJPIAJFYTGIOTN +RJPIAJFYTGIOTN +RJPIAJFYTGIOTN +RJPIAJFYTGIOTN +FKUIDEJNJLBZNV +FKUIDEJNJLBZNV +FKUIDEJNJLBZNV +TUKBLRJBXIQJPU +TUKBLRJBXIQJPU +QTMXCZCRGVTYQT +QTMXCZCRGVTYQT +QTMXCZCRGVTYQT +HAZAWDPYLPMHKM +HAZAWDPYLPMHKM +HAZAWDPYLPMHKM +XINNNPWIWCPFCE +XINNNPWIWCPFCE +XINNNPWIWCPFCE +XFAXLQJMFNJSAN +XFAXLQJMFNJSAN +XFAXLQJMFNJSAN +PNYWECOOWCXIFT +PNYWECOOWCXIFT +PNYWECOOWCXIFT +SBAYCLFSFVEBDA +SBAYCLFSFVEBDA +SBAYCLFSFVEBDA +GTNCRFAMGHPLJD +GTNCRFAMGHPLJD +GTNCRFAMGHPLJD +GTNCRFAMGHPLJD +NBXVKVYHBHZJPB +NBXVKVYHBHZJPB +NBXVKVYHBHZJPB +ANCXPXINDIZHDI +ANCXPXINDIZHDI +ANCXPXINDIZHDI +LNPNMISVXUACCK +LNPNMISVXUACCK +LNPNMISVXUACCK +AZWOXQNMSINONT +AZWOXQNMSINONT +AZWOXQNMSINONT +GAAPCJMMGUQRMH +GAAPCJMMGUQRMH +GAAPCJMMGUQRMH +JWVFKULEDOKKGT +JWVFKULEDOKKGT +JWVFKULEDOKKGT +LECNZVAZHBNWOK +LECNZVAZHBNWOK +LECNZVAZHBNWOK +LECNZVAZHBNWOK +VZWBFVDYUIMNSD +VZWBFVDYUIMNSD +VZWBFVDYUIMNSD +XHKCNJKJHMXOPN +XHKCNJKJHMXOPN +XHKCNJKJHMXOPN +MSAVPRNABPKKQE +MSAVPRNABPKKQE +MSAVPRNABPKKQE +BXJLSOYPEVWPMW +BXJLSOYPEVWPMW +BXJLSOYPEVWPMW +GZDJJIVJQYLZIE +GZDJJIVJQYLZIE +GZDJJIVJQYLZIE +OBAOWCRZOBCQSL +OBAOWCRZOBCQSL +OBAOWCRZOBCQSL +VMJHWEJCVCPBOD +VMJHWEJCVCPBOD +VMJHWEJCVCPBOD +SQIPHRUWGVEURV +SQIPHRUWGVEURV +SQIPHRUWGVEURV +DYLYCRVTCJRBDA +DYLYCRVTCJRBDA +DYLYCRVTCJRBDA +HADUJACARYTABI +HADUJACARYTABI +HADUJACARYTABI +SZWLZSXCHWTRCF +SZWLZSXCHWTRCF +SZWLZSXCHWTRCF +RIAWGGCJKPUTEX +RIAWGGCJKPUTEX +RIAWGGCJKPUTEX +MBAGYNMSWGLOEF +MBAGYNMSWGLOEF +MBAGYNMSWGLOEF +IORDUELLLWDFEK +IORDUELLLWDFEK +IORDUELLLWDFEK +RDMYIAHAAHKFSB +RDMYIAHAAHKFSB +RDMYIAHAAHKFSB +BRAKDVJCMWEMMK +BRAKDVJCMWEMMK +BRAKDVJCMWEMMK +RUGPCVLFKHUQJY +RUGPCVLFKHUQJY +RUGPCVLFKHUQJY +DNJXZHSJZJVKCV +DNJXZHSJZJVKCV +DNJXZHSJZJVKCV +ZYVWDGOLKRWZLE +ZYVWDGOLKRWZLE +ZYVWDGOLKRWZLE +LONXMDGHZKWBMB +LONXMDGHZKWBMB +LONXMDGHZKWBMB +RJCPGPJUIFACNO +RJCPGPJUIFACNO +RJCPGPJUIFACNO +YLYRDWDTCCYTNN +YLYRDWDTCCYTNN +XRPKLMRFQZMVNO +XRPKLMRFQZMVNO +XRPKLMRFQZMVNO +ZFGIUZAQAZODKH +ZFGIUZAQAZODKH +ZFGIUZAQAZODKH +KLRWJQOZDGUOPH +KLRWJQOZDGUOPH +KLRWJQOZDGUOPH +CDXOAKNOQUJSMX +CDXOAKNOQUJSMX +CDXOAKNOQUJSMX +IBCBDMODPBZCBG +IBCBDMODPBZCBG +IBCBDMODPBZCBG +YANRWBSULLZYRN +YANRWBSULLZYRN +YANRWBSULLZYRN +KAAIQAHUUFPVJI +KAAIQAHUUFPVJI +KAAIQAHUUFPVJI +JWKCHKSBFZOLLE +JWKCHKSBFZOLLE +JWKCHKSBFZOLLE +WVXXSUKHZKQJKJ +WVXXSUKHZKQJKJ +WVXXSUKHZKQJKJ +YVPUYXFXKOYVFU +YVPUYXFXKOYVFU +YVPUYXFXKOYVFU +WWNIULNCSKDKAS +WWNIULNCSKDKAS +WWNIULNCSKDKAS +QUCVKFKLHDCJAF +JQKFPJKSBFSDHQ +JQKFPJKSBFSDHQ +JQKFPJKSBFSDHQ +IBEYJQJIGQZOKV +IBEYJQJIGQZOKV +IBEYJQJIGQZOKV +OGFSXYSABGTZPK +OGFSXYSABGTZPK +OGFSXYSABGTZPK +WMOUIXZLFVTNJE +WMOUIXZLFVTNJE +WMOUIXZLFVTNJE +QXTKVGKTATUXJL +QXTKVGKTATUXJL +QXTKVGKTATUXJL +QGMBXIWUBQEPLG +QGMBXIWUBQEPLG +QGMBXIWUBQEPLG +ORVBSZZCPYVXGB +ORVBSZZCPYVXGB +ORVBSZZCPYVXGB +IHNQVQDDPUBUQF +IHNQVQDDPUBUQF +IHNQVQDDPUBUQF +IHNQVQDDPUBUQF +HRJHJSVXCGLCEV +HRJHJSVXCGLCEV +HRJHJSVXCGLCEV +MLLQHNHFSBIRHD +MLLQHNHFSBIRHD +MLLQHNHFSBIRHD +OSDVZXPMFCLPHK +OSDVZXPMFCLPHK +OSDVZXPMFCLPHK +ISWYYLKRYCFCAO +ISWYYLKRYCFCAO +ISWYYLKRYCFCAO +FEJGRKHFSHJKNK +FEJGRKHFSHJKNK +FEJGRKHFSHJKNK +UININGGLMZQDIN +UININGGLMZQDIN +UININGGLMZQDIN +MCQTWYCVSBOGHI +MCQTWYCVSBOGHI +CBBLWVHDLFKUGC +CBBLWVHDLFKUGC +CBBLWVHDLFKUGC +CGDUUTYUUMUYFS +CGDUUTYUUMUYFS +CGDUUTYUUMUYFS +JIGWYYCTMJLQTO +JIGWYYCTMJLQTO +JIGWYYCTMJLQTO +HSCHNBJVZJVSHH +HSCHNBJVZJVSHH +HSCHNBJVZJVSHH +APWIKXDMDMEBBK +APWIKXDMDMEBBK +APWIKXDMDMEBBK +CBXIUTUGCKZFOM +CBXIUTUGCKZFOM +CBXIUTUGCKZFOM +SQPYSPAOTDVCMX +SQPYSPAOTDVCMX +SQPYSPAOTDVCMX +VTQRIYNZYUPLMF +VTQRIYNZYUPLMF +VTQRIYNZYUPLMF +IGWVYCNDUVLPNF +IGWVYCNDUVLPNF +IGWVYCNDUVLPNF +AQZPHKLAAZIRHR +AQZPHKLAAZIRHR +AQZPHKLAAZIRHR +QQUHTNVFSVKOHP +QQUHTNVFSVKOHP +QQUHTNVFSVKOHP +WVZCDNUESSHTIC +WVZCDNUESSHTIC +WVZCDNUESSHTIC +CRBQCTYDCLJXCD +CRBQCTYDCLJXCD +CRBQCTYDCLJXCD +CVKUZAHWFYKSOE +CVKUZAHWFYKSOE +CVKUZAHWFYKSOE +RDCNYYGMDFXXCQ +RDCNYYGMDFXXCQ +RDCNYYGMDFXXCQ +FMGBXCVXVTZSMS +FMGBXCVXVTZSMS +JOYQJNOBYSQGIC +JOYQJNOBYSQGIC +JOYQJNOBYSQGIC +QFBRLXGRJZLCEF +QFBRLXGRJZLCEF +QFBRLXGRJZLCEF +DPXACDJXDLPITG +DPXACDJXDLPITG +BSEVLVCWJOGTCN +BSEVLVCWJOGTCN +BSEVLVCWJOGTCN +XWQVDFNFNSKQER +XWQVDFNFNSKQER +XWQVDFNFNSKQER +XJFGAKWLSFLFAN +XJFGAKWLSFLFAN +XJFGAKWLSFLFAN +POLXXTLPDZTPCH +POLXXTLPDZTPCH +POLXXTLPDZTPCH +PPDUOJLUSWPGHU +PPDUOJLUSWPGHU +PPDUOJLUSWPGHU +BXGZMUUNHAVVAU +BXGZMUUNHAVVAU +MQIRQHUPWWJYLW +MQIRQHUPWWJYLW +MEDHOMCSABAKQW +MEDHOMCSABAKQW +MEDHOMCSABAKQW +YGRFCUJGZUNWQU +YGRFCUJGZUNWQU +YGRFCUJGZUNWQU +ATWLPVSZCJMCNI +ATWLPVSZCJMCNI +ATWLPVSZCJMCNI +ILDVWEINXLWFPN +ILDVWEINXLWFPN +ILDVWEINXLWFPN +URRQVYWHJIUKHU +URRQVYWHJIUKHU +XFIAUWGQYZAGIK +XFIAUWGQYZAGIK +AZANZUXRPZRNKY +AZANZUXRPZRNKY +AZANZUXRPZRNKY +BBECAEYKLOELER +BBECAEYKLOELER +BBECAEYKLOELER +ZPCDZWMTZWCVBI +ZPCDZWMTZWCVBI +ZPCDZWMTZWCVBI +QTOQNLZQVABWHF +QTOQNLZQVABWHF +QTOQNLZQVABWHF +FBFVQRUWIGDBGP +FBFVQRUWIGDBGP +FBFVQRUWIGDBGP +NJRQKJWPQGKBNB +NJRQKJWPQGKBNB +NJRQKJWPQGKBNB +CVIJQJPPTPLPLT +CVIJQJPPTPLPLT +CVIJQJPPTPLPLT +ZFJOLIKZNBKBDZ +ZFJOLIKZNBKBDZ +ZFJOLIKZNBKBDZ +YCDIEINJGZSCNU +YCDIEINJGZSCNU +YCDIEINJGZSCNU +UYOBBROJWHWRPO +UYOBBROJWHWRPO +UYOBBROJWHWRPO +SONJWXZVJLHTOW +SONJWXZVJLHTOW +MKYYHEHSCPKMTH +MKYYHEHSCPKMTH +MKYYHEHSCPKMTH +WIGBQCCYVDBLGJ +WIGBQCCYVDBLGJ +WIGBQCCYVDBLGJ +YNDWRAXFHXWLQR +YNDWRAXFHXWLQR +YNDWRAXFHXWLQR +ZYQISOWAQURPNA +ZYQISOWAQURPNA +ZYQISOWAQURPNA +WNYRDDQJNCCSMI +WNYRDDQJNCCSMI +HKBJRFTYNRTKTA +HKBJRFTYNRTKTA +HKBJRFTYNRTKTA +JONHPUKYDLPXRF +JONHPUKYDLPXRF +JONHPUKYDLPXRF +PTCFMQQUCVLJAF +PTCFMQQUCVLJAF +PTCFMQQUCVLJAF +NATWDNFSGQJWSD +NATWDNFSGQJWSD +NATWDNFSGQJWSD +OBPPXUACHKQZIG +OBPPXUACHKQZIG +OBPPXUACHKQZIG +FMEZHIKNPHZQDL +FMEZHIKNPHZQDL +XZECTQVYSKGNEA +XZECTQVYSKGNEA +XZECTQVYSKGNEA +QLVOERHRMRNQQN +QLVOERHRMRNQQN +QLVOERHRMRNQQN +YQIGEJHOYBUSLR +YQIGEJHOYBUSLR +YQIGEJHOYBUSLR +HWCFNAAYDFUGQA +HWCFNAAYDFUGQA +HWCFNAAYDFUGQA +GEZXVZODDNGZEM +GEZXVZODDNGZEM +GEZXVZODDNGZEM +GZGNXYSGKBXGDS +GZGNXYSGKBXGDS +GZGNXYSGKBXGDS +KNYAAFWRZKZKCR +KNYAAFWRZKZKCR +KNYAAFWRZKZKCR +NVNPIWMHTIWZNW +NVNPIWMHTIWZNW +NVNPIWMHTIWZNW +JOOUTPRWPBQSKK +JOOUTPRWPBQSKK +JOOUTPRWPBQSKK +JOOUTPRWPBQSKK +MPSDYEXKRPCXAK +MPSDYEXKRPCXAK +MPSDYEXKRPCXAK +JLSKHSLZCZVXLZ +JLSKHSLZCZVXLZ +JLSKHSLZCZVXLZ +JLSKHSLZCZVXLZ +ZARDGQYABFDEIT +ZARDGQYABFDEIT +ZARDGQYABFDEIT +ZESGSSDYFCTPBV +ZESGSSDYFCTPBV +ZESGSSDYFCTPBV +JPCHZFNLLLDOPW +JPCHZFNLLLDOPW +JPCHZFNLLLDOPW +CXPCSGBIJHTBOK +CXPCSGBIJHTBOK +CXPCSGBIJHTBOK +CJLMLGQQFLOSFL +CJLMLGQQFLOSFL +CJLMLGQQFLOSFL +YXTSVLAZEKLGLU +YXTSVLAZEKLGLU +YXTSVLAZEKLGLU +NGTXKAGPSMEDBL +NGTXKAGPSMEDBL +NGTXKAGPSMEDBL +SAVHDEOPBGJRPM +SAVHDEOPBGJRPM +SAVHDEOPBGJRPM +SAVHDEOPBGJRPM +SAVHDEOPBGJRPM +SAVHDEOPBGJRPM +JPPFAORTDZSMOS +JPPFAORTDZSMOS +JPPFAORTDZSMOS +JOMTTXQMQRXCSS +JOMTTXQMQRXCSS +JOMTTXQMQRXCSS +UZZFMJXCTBUSMU +UZZFMJXCTBUSMU +UZZFMJXCTBUSMU +VUFMMKYXVSTTGF +VUFMMKYXVSTTGF +VUFMMKYXVSTTGF +XGRVOLPMZJWUHE +XGRVOLPMZJWUHE +XGRVOLPMZJWUHE +JWQFWLIMJXJGKV +JWQFWLIMJXJGKV +JWQFWLIMJXJGKV +RFMKJTDNDOKCKL +RFMKJTDNDOKCKL +RFMKJTDNDOKCKL +IMTKVVNOELUKNI +IMTKVVNOELUKNI +IMTKVVNOELUKNI +SBIFZNWYUGRUDF +SBIFZNWYUGRUDF +SBIFZNWYUGRUDF +DQZYAERRYSISAC +DQZYAERRYSISAC +DQZYAERRYSISAC +NMHWRRODCXZEEL +NMHWRRODCXZEEL +NMHWRRODCXZEEL +DKFALSOLCIKVQC +DKFALSOLCIKVQC +DKFALSOLCIKVQC +WJHWRLHJOZLNAV +WJHWRLHJOZLNAV +WJHWRLHJOZLNAV +WPRZZWNXZYHQMT +WPRZZWNXZYHQMT +WPRZZWNXZYHQMT +GACTVVAPZJSNSL +GACTVVAPZJSNSL +GACTVVAPZJSNSL +IYSIWQVPGLLSSE +IYSIWQVPGLLSSE +IYSIWQVPGLLSSE +RPFBJVLQZHTTLK +RPFBJVLQZHTTLK +RPFBJVLQZHTTLK +DXDLIIDZIXKUMQ +DXDLIIDZIXKUMQ +DXDLIIDZIXKUMQ +YHVYYQPGTQXZBW +YHVYYQPGTQXZBW +MCXBGGRDJYLAKD +MCXBGGRDJYLAKD +MCXBGGRDJYLAKD +GOKYWLHPCGAOEP +GOKYWLHPCGAOEP +GOKYWLHPCGAOEP +IOPYNWMXJNPPTJ +IOPYNWMXJNPPTJ +IOPYNWMXJNPPTJ +VTQIJCYMMUTSFY +VTQIJCYMMUTSFY +VTQIJCYMMUTSFY +KYULBSHJIYUZCN +KYULBSHJIYUZCN +KYULBSHJIYUZCN +PPWSYXRVYARWHS +PPWSYXRVYARWHS +PPWSYXRVYARWHS +YFKNMTKRALCAPE +YFKNMTKRALCAPE +LWIQWPLXBPDEOY +LWIQWPLXBPDEOY +VUOWSRAWVOZPOX +VUOWSRAWVOZPOX +VUOWSRAWVOZPOX +FJMKRORNYNWMGR +FJMKRORNYNWMGR +FJMKRORNYNWMGR +KJBKJXWLNAHWMY +KJBKJXWLNAHWMY +KJBKJXWLNAHWMY +KVKMMGAKYMJFBP +KVKMMGAKYMJFBP +KVKMMGAKYMJFBP +OAPBPZLUROFDHI +OAPBPZLUROFDHI +OAPBPZLUROFDHI +YRLOZCSIOJRBKB +YRLOZCSIOJRBKB +YRLOZCSIOJRBKB +BHPNRVYNJJEBFZ +BHPNRVYNJJEBFZ +BHPNRVYNJJEBFZ +UIHORLPQUXZWPM +UIHORLPQUXZWPM +UIHORLPQUXZWPM +HANKXLMFFOPERW +HOTJGOTUQUQBRQ +HOTJGOTUQUQBRQ +HOTJGOTUQUQBRQ +DPKREOVTWASSJG +DPKREOVTWASSJG +DPKREOVTWASSJG +DPKREOVTWASSJG +LRDCWMSFYCUCEN +LRDCWMSFYCUCEN +HHFCUJIRJYOZNE +HHFCUJIRJYOZNE +BAKZBKUTIPQBKL +BAKZBKUTIPQBKL +BAKZBKUTIPQBKL +YXAKEYNASIPRKW +YXAKEYNASIPRKW +YXAKEYNASIPRKW +CCFSCWGIZHZTRE +CCFSCWGIZHZTRE +CCFSCWGIZHZTRE +GQVQMJUREKNIGI +GQVQMJUREKNIGI +GQVQMJUREKNIGI +SMVCZAAQUUVPND +SMVCZAAQUUVPND +SMVCZAAQUUVPND +LLMWSYQBGRZLJR +LLMWSYQBGRZLJR +LLMWSYQBGRZLJR +VCOLFAJUPFYKHD +VCOLFAJUPFYKHD +VCOLFAJUPFYKHD +JIYDBPYIDPMIEW +JIYDBPYIDPMIEW +JIYDBPYIDPMIEW +SPWSOVSCRHDABQ +SPWSOVSCRHDABQ +SPWSOVSCRHDABQ +PRXNAXUFRNLWPH +PRXNAXUFRNLWPH +PRXNAXUFRNLWPH +XWSIGZWFTKLQNK +XWSIGZWFTKLQNK +XWSIGZWFTKLQNK +HWSDOIOSLOYVET +HWSDOIOSLOYVET +BPRHNYWEZNJZGX +BPRHNYWEZNJZGX +BPRHNYWEZNJZGX +WJUYRENXUVYLQD +WJUYRENXUVYLQD +WJUYRENXUVYLQD +RIHKIVILVWMRSX +RIHKIVILVWMRSX +RIHKIVILVWMRSX +YDLQZXXANBJEEO +YDLQZXXANBJEEO +YDLQZXXANBJEEO +IOFPSMUSWARDPL +IOFPSMUSWARDPL +IOFPSMUSWARDPL +FBQQLZIKUSJPOV +FBQQLZIKUSJPOV +FBQQLZIKUSJPOV +DHMYLNRZDXBYNT +DHMYLNRZDXBYNT +DHMYLNRZDXBYNT +AXJLSBXWFDATBZ +AXJLSBXWFDATBZ +AXJLSBXWFDATBZ +DGJOFBGEAYAWPU +DGJOFBGEAYAWPU +DGJOFBGEAYAWPU +VYHOHMIXFMRXBA +VYHOHMIXFMRXBA +VYHOHMIXFMRXBA +PFDLIIKEYMNVLU +PFDLIIKEYMNVLU +PFDLIIKEYMNVLU +SXLABWWZJRNHSQ +SXLABWWZJRNHSQ +SXLABWWZJRNHSQ +JNUYHMCJPVXZQK +AGEMILMEBQWVTM +AGEMILMEBQWVTM +AGEMILMEBQWVTM +BLPUIYZPEKHSIE +BLPUIYZPEKHSIE +BLPUIYZPEKHSIE +LDLMSMBYZVYYCI +LDLMSMBYZVYYCI +LDLMSMBYZVYYCI +PBOMRRZRASLVBT +PBOMRRZRASLVBT +PBOMRRZRASLVBT +ZKBGULGKHUHTSZ +ZKBGULGKHUHTSZ +ZKBGULGKHUHTSZ +KWBCRDPGKNJHMZ +YINNTOHBIGKREQ +YINNTOHBIGKREQ +YINNTOHBIGKREQ +NNAYMNHYZAAFQB +NNAYMNHYZAAFQB +NNAYMNHYZAAFQB +IZOQMVDCLMTZBW +IZOQMVDCLMTZBW +IZOQMVDCLMTZBW +MUUUPQWIKLLRTM +MUUUPQWIKLLRTM +URGUOPSROBEPRI +URGUOPSROBEPRI +URGUOPSROBEPRI +BPFQUGLKYNSSEC +BPFQUGLKYNSSEC +BPFQUGLKYNSSEC +GRZWFVFYDQLABF +GRZWFVFYDQLABF +GRZWFVFYDQLABF +YHYSJLUYRPLENU +YHYSJLUYRPLENU +YHYSJLUYRPLENU +YSTUMAKEFASIFI +YSTUMAKEFASIFI +YSTUMAKEFASIFI +QEPGQGNCYIOYPR +QEPGQGNCYIOYPR +QEPGQGNCYIOYPR +WQSXFPCEFKUQEH +WQSXFPCEFKUQEH +WQSXFPCEFKUQEH +WQSXFPCEFKUQEH +PVWOGONTRWOQOO +PVWOGONTRWOQOO +PVWOGONTRWOQOO +PVWOGONTRWOQOO +OVAMSAGPVUYDIW +OVAMSAGPVUYDIW +OVAMSAGPVUYDIW +OVAMSAGPVUYDIW +ZSQREIZQPIOWIU +ZSQREIZQPIOWIU +ZSQREIZQPIOWIU +AZWVODXJYJUNOJ +AZWVODXJYJUNOJ +AZWVODXJYJUNOJ +PPKCJEKHDCLMKO +PPKCJEKHDCLMKO +PPKCJEKHDCLMKO +TXKUZNJPGDRCGA +TXKUZNJPGDRCGA +TXKUZNJPGDRCGA +LWZPSPUNOFWTEQ +DSQAHEXQXMJFSD +DSQAHEXQXMJFSD +DSQAHEXQXMJFSD +IGDMRORWPZKYBQ +IGDMRORWPZKYBQ +IGDMRORWPZKYBQ +NKFWVKWAVPYGEH +NKFWVKWAVPYGEH +NKFWVKWAVPYGEH +POWOJWFPOWIRPX +POWOJWFPOWIRPX +POWOJWFPOWIRPX +PGVPJYXSPQNOBQ +PGVPJYXSPQNOBQ +PGVPJYXSPQNOBQ +AXBPZQNWWIKQBR +AXBPZQNWWIKQBR +AXBPZQNWWIKQBR +BATVBXTYVPVEBL +BATVBXTYVPVEBL +BATVBXTYVPVEBL +SQHTZSLPFIQMAT +SQHTZSLPFIQMAT +SQHTZSLPFIQMAT +SLSSACDRLLEJSK +SLSSACDRLLEJSK +SLSSACDRLLEJSK +IQWJMLKROBYNKG +IQWJMLKROBYNKG +IQWJMLKROBYNKG +YPQCYPMDMVLRDB +YPQCYPMDMVLRDB +YPQCYPMDMVLRDB +JYWBCHCOTHPYPI +JYWBCHCOTHPYPI +JYWBCHCOTHPYPI +JYWBCHCOTHPYPI +JYWBCHCOTHPYPI +JYWBCHCOTHPYPI +CKIAZWXGPAVPSH +CKIAZWXGPAVPSH +CKIAZWXGPAVPSH +UHMDDADXRUDLBO +SWAYDMBIVODOHV +SWAYDMBIVODOHV +SWAYDMBIVODOHV +NTSCBPRZHIBADT +NTSCBPRZHIBADT +NTSCBPRZHIBADT +OSWUWBGZDGWUKF +OSWUWBGZDGWUKF +OSWUWBGZDGWUKF +OSWUWBGZDGWUKF +YLAXXWGPBQGFSC +YLAXXWGPBQGFSC +YLAXXWGPBQGFSC +DOBRBGRWVFCUNA +DOBRBGRWVFCUNA +DOBRBGRWVFCUNA +BCEHBSKCWLPMDN +BCEHBSKCWLPMDN +BCEHBSKCWLPMDN +KKDCZJUCXDSDBY +KKDCZJUCXDSDBY +KKDCZJUCXDSDBY +LOLOMNWJVUMOSO +LOLOMNWJVUMOSO +LOLOMNWJVUMOSO +BKSKLJYSDDJGFN +BKSKLJYSDDJGFN +BKSKLJYSDDJGFN +DLJKHMOYXSNEGI +DLJKHMOYXSNEGI +DLJKHMOYXSNEGI +DLJKHMOYXSNEGI +OWQAYOKOQKBEGN +OWQAYOKOQKBEGN +OWQAYOKOQKBEGN +LPRPXPRQHDKSRX +LPRPXPRQHDKSRX +LPRPXPRQHDKSRX +OYJNAFVQOGQRGP +OYJNAFVQOGQRGP +OYJNAFVQOGQRGP +APXGCOSCVFOUAE +APXGCOSCVFOUAE +APXGCOSCVFOUAE +GCPZCSOGTCRJRM +GCPZCSOGTCRJRM +ZRTMPFCXFIXUIK +ZRTMPFCXFIXUIK +ZRTMPFCXFIXUIK +UBNKUJDURMZFFF +UBNKUJDURMZFFF +CHEBZUQOKMTQLQ +CHEBZUQOKMTQLQ +CHEBZUQOKMTQLQ +CGARWUFWLQVPFG +CGARWUFWLQVPFG +HKLUABPLXJLMBF +HKLUABPLXJLMBF +HEYAGYXKWUXLJX +HEYAGYXKWUXLJX +HEYAGYXKWUXLJX +UUPDQVWJAGAYOH +UUPDQVWJAGAYOH +UUPDQVWJAGAYOH +JOAIMUFHEBWQKM +JOAIMUFHEBWQKM +JOAIMUFHEBWQKM +YGJNRQNWNLPHMV +YGJNRQNWNLPHMV +YGJNRQNWNLPHMV +AZRDHOKFYZAELI +PECQRVTUKREGLF +PECQRVTUKREGLF +PECQRVTUKREGLF +LAJAGAVUZGSOQL +LAJAGAVUZGSOQL +LAJAGAVUZGSOQL +QQDRXROVPDEWJH +QQDRXROVPDEWJH +QQDRXROVPDEWJH +ILHOWRNEZVJEER +ILHOWRNEZVJEER +ILHOWRNEZVJEER +DWOIFDXFGPICEI +YDZDREYVCFSUII +YDZDREYVCFSUII +RYVRZTBJJBDZRN +RYVRZTBJJBDZRN +RYVRZTBJJBDZRN +SCXKMKVYMUCOJD +SCXKMKVYMUCOJD +PICBTKJFPZNUFW +PICBTKJFPZNUFW +PICBTKJFPZNUFW +SFVNNNIFLFLRQC +SFVNNNIFLFLRQC +SFVNNNIFLFLRQC +MTZBKESHQICWRO +MTZBKESHQICWRO +MTZBKESHQICWRO +QWTLFPAQGZPACF +BJWVLDKEXLTMNE +BJWVLDKEXLTMNE +BJWVLDKEXLTMNE +BVESMIHPODALHC +BVESMIHPODALHC +BVESMIHPODALHC +YSXHSRDOYYWXIL +YSXHSRDOYYWXIL +YSXHSRDOYYWXIL +RCZRPWUQMOCEPQ +RCZRPWUQMOCEPQ +RCZRPWUQMOCEPQ +YSHGSHRAERUHSF +YSHGSHRAERUHSF +YSHGSHRAERUHSF +WLGZMSWFJHVUQP +WLGZMSWFJHVUQP +WLGZMSWFJHVUQP +XZHOKSHONLVGJP +XZHOKSHONLVGJP +XZHOKSHONLVGJP +HAYXZDYOGCGHIW +HAYXZDYOGCGHIW +ALYMQFTWNCGXEH +ALYMQFTWNCGXEH +ALYMQFTWNCGXEH +ALYMQFTWNCGXEH +GZLZRZLOLFEFII +GZLZRZLOLFEFII +GZLZRZLOLFEFII +NXRRDYDXPIJLFE +NXRRDYDXPIJLFE +NXRRDYDXPIJLFE +DMXBTASQAORIBV +DMXBTASQAORIBV +DMXBTASQAORIBV +YJHJSUUIJRFTIN +YJHJSUUIJRFTIN +YJHJSUUIJRFTIN +JWUZLUSFWZEVHY +JWUZLUSFWZEVHY +JWUZLUSFWZEVHY +CEECXINAAYAKSK +CEECXINAAYAKSK +CEECXINAAYAKSK +ACRHBAYQBXXRTO +ACRHBAYQBXXRTO +ACRHBAYQBXXRTO +BDXIYZOVJXKMLX +BDXIYZOVJXKMLX +BDXIYZOVJXKMLX +CSGVPYSLAIVFGQ +CSGVPYSLAIVFGQ +CSGVPYSLAIVFGQ +PPXBKZBONGWSOB +PPXBKZBONGWSOB +PPXBKZBONGWSOB +GJDQGBOUKVYXGX +GJDQGBOUKVYXGX +GJDQGBOUKVYXGX +QEOIDOAEOWQALB +QEOIDOAEOWQALB +QEOIDOAEOWQALB +UTKOFZPECRJROI +UTKOFZPECRJROI +UTKOFZPECRJROI +BKPSKJNGIIQQHD +BKPSKJNGIIQQHD +BKPSKJNGIIQQHD +VICZYZVNJKFTNP +VICZYZVNJKFTNP +VICZYZVNJKFTNP +ZCNWMGCZLRWPRP +ZCNWMGCZLRWPRP +ZCNWMGCZLRWPRP +JJUMPVHZIRQYKT +JJUMPVHZIRQYKT +JJUMPVHZIRQYKT +RVDGVSHNZZEVRL +RVDGVSHNZZEVRL +RVDGVSHNZZEVRL +RVDGVSHNZZEVRL +GAYLZFLPWHXCEC +UUBMUPVKWWLFCU +UUBMUPVKWWLFCU +UUBMUPVKWWLFCU +MPULTRANVNAACO +MPULTRANVNAACO +MPULTRANVNAACO +ACYIDOUODAIODC +ACYIDOUODAIODC +ACYIDOUODAIODC +TTWPRNYCZGTSHJ +TTWPRNYCZGTSHJ +TTWPRNYCZGTSHJ +HKFBPSOEOJDPPJ +HKFBPSOEOJDPPJ +HKFBPSOEOJDPPJ +ZHICJOIUIGYFNT +KDJXZWQXSNVSMR +KDJXZWQXSNVSMR +KDJXZWQXSNVSMR +LITCPPCXQONGLJ +LITCPPCXQONGLJ +LITCPPCXQONGLJ +KNAKVTWHRLUAOR +KNAKVTWHRLUAOR +KNAKVTWHRLUAOR +PAQLHMFGIODPNZ +PAQLHMFGIODPNZ +PAQLHMFGIODPNZ +PUTAZNMAPHCBIB +PUTAZNMAPHCBIB +HFJQNEIGUNYVSF +HFJQNEIGUNYVSF +HFJQNEIGUNYVSF +LVFRCHAZCSSKAV +LVFRCHAZCSSKAV +LVFRCHAZCSSKAV +NDLXUNDYJMHUIG +NDLXUNDYJMHUIG +NDLXUNDYJMHUIG +QGIXHEXUUFLBMU +QGIXHEXUUFLBMU +QGIXHEXUUFLBMU +MCOPULCVPICNOI +MCOPULCVPICNOI +MCOPULCVPICNOI +CTLUZUGOZRMCDL +CTLUZUGOZRMCDL +CTLUZUGOZRMCDL +XEGLNNAWDNCTCZ +XEGLNNAWDNCTCZ +XEGLNNAWDNCTCZ +FZQRPDOOXSAHBC +FZQRPDOOXSAHBC +FZQRPDOOXSAHBC +RRDAHNLFKMLLBF +RRDAHNLFKMLLBF +RRDAHNLFKMLLBF +VTQMFGZCAGNZKL +VTQMFGZCAGNZKL +VTQMFGZCAGNZKL +HYRNMHWKPGYXFR +HYRNMHWKPGYXFR +HYRNMHWKPGYXFR +VFVPJIWGQISTGL +VFVPJIWGQISTGL +VFVPJIWGQISTGL +ZDJQHJJLKOSBFH +ZDJQHJJLKOSBFH +ZDJQHJJLKOSBFH +ZDJQHJJLKOSBFH +ZDJQHJJLKOSBFH +WCARDDDMQORATQ +WCARDDDMQORATQ +WCARDDDMQORATQ +KWQKKOFWRFGEID +XUIKPLJBRKPSNP +XUIKPLJBRKPSNP +XUIKPLJBRKPSNP +TYPATESISFFBOS +TYPATESISFFBOS +TYPATESISFFBOS +YGWUEIKJBWTKOE +YGWUEIKJBWTKOE +LZVNBQQXJXZLHM +LZVNBQQXJXZLHM +FRZQGZSDMNKEQQ +FRZQGZSDMNKEQQ +FRZQGZSDMNKEQQ +FIVXJRDLPFVERH +FIVXJRDLPFVERH +FIVXJRDLPFVERH +MXUCMLMNYLZPKO +MXUCMLMNYLZPKO +MXUCMLMNYLZPKO +MXFADWBOQBSELT +MXFADWBOQBSELT +MXFADWBOQBSELT +XSAJZPPJMRGVIJ +XSAJZPPJMRGVIJ +XSAJZPPJMRGVIJ +MNISQXJSXTTWOZ +MNISQXJSXTTWOZ +MNISQXJSXTTWOZ +ZKLPYXBVDMORDM +ZKLPYXBVDMORDM +ZKLPYXBVDMORDM +ODERMLDHDHJZLH +ODERMLDHDHJZLH +ODERMLDHDHJZLH +BFCDTNYBVIEHQY +BFCDTNYBVIEHQY +BFCDTNYBVIEHQY +HKZDQZNGACWDFQ +HKZDQZNGACWDFQ +HKZDQZNGACWDFQ +HKZDQZNGACWDFQ +MBYNZIVHGKILFS +MBYNZIVHGKILFS +MBYNZIVHGKILFS +JYTUEZIFQASGBF +JYTUEZIFQASGBF +JYTUEZIFQASGBF +HESQLCIORTYLCJ +HESQLCIORTYLCJ +HESQLCIORTYLCJ +UIXFMXGUDDLIJY +UIXFMXGUDDLIJY +UIXFMXGUDDLIJY +UIXFMXGUDDLIJY +JSBUZJILPORBJV +JSBUZJILPORBJV +JSBUZJILPORBJV +AJMVYDIURQZFSI +AJMVYDIURQZFSI +AJMVYDIURQZFSI +RJOLTERXKKLKFG +RJOLTERXKKLKFG +RJOLTERXKKLKFG +JEJVVLKQKGDPOE +JEJVVLKQKGDPOE +JEJVVLKQKGDPOE +VXTPEHUUYGUKNS +BJBAQYXVQFOBJL +BJBAQYXVQFOBJL +BJBAQYXVQFOBJL +MRDHINXMPHLEMU +MRDHINXMPHLEMU +MRDHINXMPHLEMU +CRALQLRNLXHUMF +CRALQLRNLXHUMF +CRALQLRNLXHUMF +ZCQQTZMBJZXKSZ +ZCQQTZMBJZXKSZ +ZCQQTZMBJZXKSZ +APEJSCXHYCBLOF +APEJSCXHYCBLOF +APEJSCXHYCBLOF +NDDKYJXARNRGFO +NDDKYJXARNRGFO +NDDKYJXARNRGFO +RATHKVVXEKBLAT +RATHKVVXEKBLAT +RATHKVVXEKBLAT +LMENBVVMKGABTP +LMENBVVMKGABTP +LMENBVVMKGABTP +ZJNDALLZZKRJFF +ZJNDALLZZKRJFF +ZJNDALLZZKRJFF +MQOZYYCIPAEBPT +MQOZYYCIPAEBPT +MQOZYYCIPAEBPT +HGWHCIKCOXECHW +HGWHCIKCOXECHW +HGWHCIKCOXECHW +OPXFNRUFTIJJDJ +OPXFNRUFTIJJDJ +OPXFNRUFTIJJDJ +CBNNSJCAKLCTIO +CBNNSJCAKLCTIO +ORTGDACWUOSBME +ORTGDACWUOSBME +ORTGDACWUOSBME +SWTPGOWCTFLPIB +SWTPGOWCTFLPIB +SWTPGOWCTFLPIB +MKRBSGXFJLNULL +MKRBSGXFJLNULL +MKRBSGXFJLNULL +LUVHZDMLEIJVDF +LUVHZDMLEIJVDF +LUVHZDMLEIJVDF +FDGZIXUHSHYXLL +FDGZIXUHSHYXLL +FDGZIXUHSHYXLL +FDGZIXUHSHYXLL +ACTFHESERZGHMQ +ACTFHESERZGHMQ +ACTFHESERZGHMQ +SCILENGBPRNTGR +SCILENGBPRNTGR +SCILENGBPRNTGR +ZLGJCDUAAHQTKI +ZLGJCDUAAHQTKI +ZLGJCDUAAHQTKI +FRFIRTOHMLAHSH +FRFIRTOHMLAHSH +FRFIRTOHMLAHSH +CLKYYORDPOQKBJ +CLKYYORDPOQKBJ +IGOKOMXLEMHIOC +IGOKOMXLEMHIOC +IGOKOMXLEMHIOC +IGOKOMXLEMHIOC +YSJAVHZDZHVELH +YSJAVHZDZHVELH +YSJAVHZDZHVELH +CMJORFBAQMFOKR +CMJORFBAQMFOKR +CMJORFBAQMFOKR +UAKFDBKNIARUEX +UAKFDBKNIARUEX +UAKFDBKNIARUEX +LHFIMKRQTDEKDE +LHFIMKRQTDEKDE +LHFIMKRQTDEKDE +KDBTWMZVHPYIKS +KDBTWMZVHPYIKS +KDBTWMZVHPYIKS +LDXJWHFWVBHENY +LDXJWHFWVBHENY +LDXJWHFWVBHENY +GIOBRZYCIDLIMR +GIOBRZYCIDLIMR +GIOBRZYCIDLIMR +GMOPCRIOXZGXTA +GMOPCRIOXZGXTA +GMOPCRIOXZGXTA +OTQIJVBDFSIBKN +OTQIJVBDFSIBKN +OTQIJVBDFSIBKN +GXKOZRMTQADUDO +GXKOZRMTQADUDO +GXKOZRMTQADUDO +LYVSDCYFURROGR +LYVSDCYFURROGR +LYVSDCYFURROGR +OBGGZMZMMXPCLR +OBGGZMZMMXPCLR +OBGGZMZMMXPCLR +DIIXVTZTPVTPIZ +DIIXVTZTPVTPIZ +DIIXVTZTPVTPIZ +QPCFXQAIJAXKDX +QPCFXQAIJAXKDX +QPCFXQAIJAXKDX +UVWFKFHOSYUSIJ +BALQLFHMRMGAIZ +BALQLFHMRMGAIZ +BALQLFHMRMGAIZ +IXXPZWRDAWWPQF +IXXPZWRDAWWPQF +IXXPZWRDAWWPQF +IXXPZWRDAWWPQF +JWPYJBSRYMQHIX +JWPYJBSRYMQHIX +JWPYJBSRYMQHIX +GVHVJWBXLUCTBD +GVHVJWBXLUCTBD +GVHVJWBXLUCTBD +MBKCCNVJXUMYPE +MBKCCNVJXUMYPE +MBKCCNVJXUMYPE +UCOHTFASGZGQDX +UCOHTFASGZGQDX +UCOHTFASGZGQDX +YQPXNFNTIAWHES +YQPXNFNTIAWHES +YQPXNFNTIAWHES +YQPXNFNTIAWHES +PDKLWPSFFQESMQ +PDKLWPSFFQESMQ +PDKLWPSFFQESMQ +ATLDSOXBPAEQOE +ATLDSOXBPAEQOE +ATLDSOXBPAEQOE +NBHZXSBBFLWTGD +NBHZXSBBFLWTGD +NBHZXSBBFLWTGD +LYJVIGCEIQMNJY +LYJVIGCEIQMNJY +LYJVIGCEIQMNJY +BMCAMMQVILUNCT +BMCAMMQVILUNCT +BMCAMMQVILUNCT +JIAZQMUSVIVHCY +JIAZQMUSVIVHCY +JIAZQMUSVIVHCY +QFXUVUBVPPOPQZ +QFXUVUBVPPOPQZ +QFXUVUBVPPOPQZ +ADOGPUFGFUQERC +ADOGPUFGFUQERC +ADOGPUFGFUQERC +PQLDAXFLQTWNQN +PQLDAXFLQTWNQN +PQLDAXFLQTWNQN +ULYWRYMKLSKBHN +ULYWRYMKLSKBHN +ULYWRYMKLSKBHN +DDQHXSXOOWQTID +UTJNPRKMZIHHGR +UTJNPRKMZIHHGR +UTJNPRKMZIHHGR +VXRCIWYXQIRSDK +VXRCIWYXQIRSDK +VXRCIWYXQIRSDK +SPXUBSVJBSQGAQ +SPXUBSVJBSQGAQ +SPXUBSVJBSQGAQ +FBXRUPQWWWDDEE +FBXRUPQWWWDDEE +FBXRUPQWWWDDEE +NBOUYAASMLELSF +NBOUYAASMLELSF +NBOUYAASMLELSF +ONFSWZFDUPLOPP +ONFSWZFDUPLOPP +ONFSWZFDUPLOPP +NEWXZLFUHRASHG +NEWXZLFUHRASHG +NEWXZLFUHRASHG +RBLIYAYJOXQORG +RBLIYAYJOXQORG +RBLIYAYJOXQORG +OAQZUKJEPUGRRP +OAQZUKJEPUGRRP +OAQZUKJEPUGRRP +ANQVKHGDALCPFZ +ANQVKHGDALCPFZ +ANQVKHGDALCPFZ +DDPRSEQKNAGHRZ +DDPRSEQKNAGHRZ +HLPYVXKTMXQMID +HLPYVXKTMXQMID +HLPYVXKTMXQMID +FDKIETADOUEGFK +FDKIETADOUEGFK +FDKIETADOUEGFK +NBRLQKCSZSDIGJ +NBRLQKCSZSDIGJ +NBRLQKCSZSDIGJ +RECJGDYXLPYVCO +RECJGDYXLPYVCO +RECJGDYXLPYVCO +SQUGJJIRURMMSN +SQUGJJIRURMMSN +SQUGJJIRURMMSN +SQUGJJIRURMMSN +MVOHPGZSJOCAIS +MVOHPGZSJOCAIS +MVOHPGZSJOCAIS +MKVCIYQOSCLVIZ +DADDROYUIOQZLC +DADDROYUIOQZLC +DADDROYUIOQZLC +SDSYSMKJTLMPIK +SDSYSMKJTLMPIK +SDSYSMKJTLMPIK +KHINSOBHNYHTSY +KHINSOBHNYHTSY +KHINSOBHNYHTSY +XVNKRZIRNFITEQ +XVNKRZIRNFITEQ +XVNKRZIRNFITEQ +USEMSBYPDXZBAQ +USEMSBYPDXZBAQ +USEMSBYPDXZBAQ +MZUDMFFXFLFLOG +MZUDMFFXFLFLOG +MZUDMFFXFLFLOG +GVCQUWINIMCEQY +GVCQUWINIMCEQY +GVCQUWINIMCEQY +PTOLYXUCTLQMGW +PTOLYXUCTLQMGW +PTOLYXUCTLQMGW +IZCQFJYFSULSNK +IZCQFJYFSULSNK +IZCQFJYFSULSNK +GNASHUJXPMQFFB +GNASHUJXPMQFFB +MMNZYSSLIPWUHG +MMNZYSSLIPWUHG +MMNZYSSLIPWUHG +MWFIPTRQWFICCC +MWFIPTRQWFICCC +MWFIPTRQWFICCC +REVZUNXTTRAVSR +REVZUNXTTRAVSR +REVZUNXTTRAVSR +JUYGUGZFNZDGHW +JUYGUGZFNZDGHW +JUYGUGZFNZDGHW +VSFYEIARHRAQGF +VSFYEIARHRAQGF +VSFYEIARHRAQGF +WPZROIQXGYQBJB +WPZROIQXGYQBJB +WPZROIQXGYQBJB +IZNAMGDXRXEQDO +IZNAMGDXRXEQDO +IZNAMGDXRXEQDO +QGFZWIJGDSWWST +QGFZWIJGDSWWST +QGFZWIJGDSWWST +QGFZWIJGDSWWST +OOCIYAGKGITJAH +OOCIYAGKGITJAH +OOCIYAGKGITJAH +QFRXNFCIQOTBET +QFRXNFCIQOTBET +QFRXNFCIQOTBET +KXLWPFYBKZYMDQ +KXLWPFYBKZYMDQ +KXLWPFYBKZYMDQ +DNWWLMJFWJSJIO +DNWWLMJFWJSJIO +DNWWLMJFWJSJIO +NMXGURPTOJIXGF +NMXGURPTOJIXGF +NMXGURPTOJIXGF +LOHHERLGJHQIKL +LOHHERLGJHQIKL +LOHHERLGJHQIKL +WDYFZPWKBMYXMD +WDYFZPWKBMYXMD +WDYFZPWKBMYXMD +DAAPQMKUXCGARN +DAAPQMKUXCGARN +DAAPQMKUXCGARN +RCLLUEYANFPMSM +RCLLUEYANFPMSM +RCLLUEYANFPMSM +RCLLUEYANFPMSM +RCLLUEYANFPMSM +HZEUBQRRTOFTQI +HZEUBQRRTOFTQI +HZEUBQRRTOFTQI +OSEAPMFILKGYRR +OSEAPMFILKGYRR +OSEAPMFILKGYRR +XUFRHWPICGJUIO +XUFRHWPICGJUIO +XUFRHWPICGJUIO +BPQLHNFWBGIOHV +BPQLHNFWBGIOHV +BPQLHNFWBGIOHV +SZQKNOWYJSSMDS +SZQKNOWYJSSMDS +SZQKNOWYJSSMDS +XGADIKOFMAPVHQ +XGADIKOFMAPVHQ +XGADIKOFMAPVHQ +QLPQYTXDMVNSJW +QLPQYTXDMVNSJW +QLPQYTXDMVNSJW +IPZDLSZXZLZHOT +IPZDLSZXZLZHOT +IPZDLSZXZLZHOT +ZPZOOQGFJBTWMM +ZPZOOQGFJBTWMM +HLMIISQJUKHPME +HLMIISQJUKHPME +HLMIISQJUKHPME +ZAWSIXZRVQZSTO +ZAWSIXZRVQZSTO +ZAWSIXZRVQZSTO +SOZSSCDTBMFFHX +SOZSSCDTBMFFHX +SOZSSCDTBMFFHX +WWLBKSVQQIEOHQ +WWLBKSVQQIEOHQ +WWLBKSVQQIEOHQ +PCCBWMZDRZJHAX +PCCBWMZDRZJHAX +PCCBWMZDRZJHAX +UAILCIWSUGVIAW +UAILCIWSUGVIAW +UAILCIWSUGVIAW +ZRJOLQGEKCJXDC +ZRJOLQGEKCJXDC +ZRJOLQGEKCJXDC +RDTAAFXREHAATP +RDTAAFXREHAATP +RDTAAFXREHAATP +PHMHMNBAJFRPCN +PHMHMNBAJFRPCN +PHMHMNBAJFRPCN +VFJGGNXTCFBRNT +VFJGGNXTCFBRNT +VFJGGNXTCFBRNT +HWYUYQDGWMJVIJ +HWYUYQDGWMJVIJ +HWYUYQDGWMJVIJ +HNFNNDXTMQRPEQ +HNFNNDXTMQRPEQ +HNFNNDXTMQRPEQ +QOPXJJBDUPTVFU +QOPXJJBDUPTVFU +QOPXJJBDUPTVFU +HTMDNZHOOCFPCJ +HTMDNZHOOCFPCJ +HTMDNZHOOCFPCJ +JGOYSKCDQZZOJN +JGOYSKCDQZZOJN +JGOYSKCDQZZOJN +LIFLIAKZILCEHX +LIFLIAKZILCEHX +LIFLIAKZILCEHX +FNOVJEJTUXZKOG +FNOVJEJTUXZKOG +IZUPUFJGTVBOJL +IZUPUFJGTVBOJL +IZUPUFJGTVBOJL +HKWOAGSHAHKUGV +HKWOAGSHAHKUGV +HKWOAGSHAHKUGV +WCFJJPZMQIIEKB +WCFJJPZMQIIEKB +WCFJJPZMQIIEKB +JMGJKUPANZAQQR +JMGJKUPANZAQQR +JMGJKUPANZAQQR +PVWYURYCPBJONX +PVWYURYCPBJONX +PVWYURYCPBJONX +FTLIIDKRAZGZFS +FTLIIDKRAZGZFS +FTLIIDKRAZGZFS +JZWMEOSWGGSEEF +JZWMEOSWGGSEEF +JZWMEOSWGGSEEF +WXZGDQWUDAANTN +WXZGDQWUDAANTN +WXZGDQWUDAANTN +ATGDHLVANXVEBH +ATGDHLVANXVEBH +OIOHVWKANUXBKG +OIOHVWKANUXBKG +OIOHVWKANUXBKG +FVGBVZPZELYCND +FVGBVZPZELYCND +FVGBVZPZELYCND +FVGBVZPZELYCND +AYXVOMORPYSBRU +AYXVOMORPYSBRU +AYXVOMORPYSBRU +AYXVOMORPYSBRU +CVOFGXQAPUQZAM +CVOFGXQAPUQZAM +PRHRNNSUUOEIOJ +PRHRNNSUUOEIOJ +PRHRNNSUUOEIOJ +YIOMLVGVMQNPSG +YIOMLVGVMQNPSG +YIOMLVGVMQNPSG +NZNUBCLBJSREGO +NZNUBCLBJSREGO +NZNUBCLBJSREGO +FDPQTDXVQVRNLX +FDPQTDXVQVRNLX +FDPQTDXVQVRNLX +NCWURZGZMRDSKD +NCWURZGZMRDSKD +NCWURZGZMRDSKD +QUWJBXIBCWTEAG +QUWJBXIBCWTEAG +KCBJTDNGWZJUGQ +KCBJTDNGWZJUGQ +KCBJTDNGWZJUGQ +YOWDQPWLTJRVQS +YOWDQPWLTJRVQS +YOWDQPWLTJRVQS +OXXKKHBFGKPWRR +OXXKKHBFGKPWRR +OXXKKHBFGKPWRR +GCRWITVFDLJINC +GCRWITVFDLJINC +GCRWITVFDLJINC +YGMMGMBRBMIVOX +YGMMGMBRBMIVOX +DWCIAQFEFPWQTJ +DWCIAQFEFPWQTJ +DWCIAQFEFPWQTJ +VUGGHMZYUWKQCY +VUGGHMZYUWKQCY +VUGGHMZYUWKQCY +DQUKJAXVQOZANT +DQUKJAXVQOZANT +DQUKJAXVQOZANT +CXRNQXFFWARLSJ +CXRNQXFFWARLSJ +PEVCDMDOTQHPPL +PEVCDMDOTQHPPL +XZUMJSXPCYDNNR +XZUMJSXPCYDNNR +OMJZOXYWBVKDMU +KYJFYLKBWMNNEB +KYJFYLKBWMNNEB +KYJFYLKBWMNNEB +WCZDUFOLQSSLBU +WCZDUFOLQSSLBU +WCZDUFOLQSSLBU +LLVLFPAARFZTSA +LLVLFPAARFZTSA +LLVLFPAARFZTSA +CXNSVSMYHQZWIC +CXNSVSMYHQZWIC +CXNSVSMYHQZWIC +CFSIHCAUHXNDFB +CFSIHCAUHXNDFB +MCWCAAJLZAOSDJ +MCWCAAJLZAOSDJ +MCWCAAJLZAOSDJ +YJTJORQWMLCRGZ +OBUJQPRMTVEICT +OBUJQPRMTVEICT +OBUJQPRMTVEICT +ZKLUNVKGUSLYHZ +ZKLUNVKGUSLYHZ +ZKLUNVKGUSLYHZ +BAOVRTLMWZRGTG +BAOVRTLMWZRGTG +BAOVRTLMWZRGTG +WVLHTLFQBUUAAX +WVLHTLFQBUUAAX +WVLHTLFQBUUAAX +WVLHTLFQBUUAAX +OULVCUAHHVEUBB +OULVCUAHHVEUBB +OULVCUAHHVEUBB +MYTHDDPRIDIHPS +MYTHDDPRIDIHPS +MYTHDDPRIDIHPS +NLJPIBKRLGVNLY +NLJPIBKRLGVNLY +NLJPIBKRLGVNLY +NPHFDKAEYQLXKR +NPHFDKAEYQLXKR +NPHFDKAEYQLXKR +KHVICBZYTNFPFH +KHVICBZYTNFPFH +KHVICBZYTNFPFH +QTMFPICDRKUAQW +QTMFPICDRKUAQW +QTMFPICDRKUAQW +KQWMBSZCXFDGIL +KQWMBSZCXFDGIL +KQWMBSZCXFDGIL +VUZRNSJFWJTIPX +VUZRNSJFWJTIPX +VUZRNSJFWJTIPX +VORPQUCDSMJZQV +VORPQUCDSMJZQV +VORPQUCDSMJZQV +YPYJDADWPXNJBB +YPYJDADWPXNJBB +YPYJDADWPXNJBB +HROVAQLKIIJONG +HROVAQLKIIJONG +HROVAQLKIIJONG +RUCWEYBMCQHPJC +RUCWEYBMCQHPJC +RUCWEYBMCQHPJC +KGPKZMNEMUSZEH +KGPKZMNEMUSZEH +KGPKZMNEMUSZEH +YMRCSKYJFITUMF +YMRCSKYJFITUMF +YMRCSKYJFITUMF +RLWSYIWXOMDGSP +RLWSYIWXOMDGSP +RLWSYIWXOMDGSP +JAUFEEHUBCBQOC +JAUFEEHUBCBQOC +JAUFEEHUBCBQOC +HEHGEGYGBSXOSO +HEHGEGYGBSXOSO +HEHGEGYGBSXOSO +LFCOXJOUBMOPGW +LFCOXJOUBMOPGW +LFCOXJOUBMOPGW +FSLNPJUAIFPORZ +FSLNPJUAIFPORZ +FSLNPJUAIFPORZ +OSWLWFDQCSCRQH +OSWLWFDQCSCRQH +OSWLWFDQCSCRQH +NQALIRIOFNHYIP +NQALIRIOFNHYIP +VTCJOVGKIDSTDE +VTCJOVGKIDSTDE +JBLNWWYTSKEHHU +JBLNWWYTSKEHHU +JBLNWWYTSKEHHU +OFMGNMIHBOCNPW +OFMGNMIHBOCNPW +OFMGNMIHBOCNPW +MQXPNGDUUYATTF +MQXPNGDUUYATTF +MQXPNGDUUYATTF +UZKQJJFUEJDXDD +UZKQJJFUEJDXDD +UZKQJJFUEJDXDD +MFDDBQMTPPONPY +MFDDBQMTPPONPY +MFDDBQMTPPONPY +PWYDRUBBDQAQAN +PWYDRUBBDQAQAN +PWYDRUBBDQAQAN +GZMDIBRJAVXBMB +GZMDIBRJAVXBMB +GZMDIBRJAVXBMB +RJNPMJBFVOXECP +RJNPMJBFVOXECP +RJNPMJBFVOXECP +VDQKXPSNVGKNBJ +VDQKXPSNVGKNBJ +VDQKXPSNVGKNBJ +GWMSPQWWDBNDKL +GWMSPQWWDBNDKL +GWMSPQWWDBNDKL +GROBMUNKDQYDRB +GROBMUNKDQYDRB +GROBMUNKDQYDRB +VVJDGWNQKNNRCF +VVJDGWNQKNNRCF +VVJDGWNQKNNRCF +BQFGPDYLAWLHIV +XXDBUSUNENTVTH +XXDBUSUNENTVTH +GZMCKUJVIPGXBF +GZMCKUJVIPGXBF +GZMCKUJVIPGXBF +VTRFYCAOKBNLIC +VTRFYCAOKBNLIC +VTRFYCAOKBNLIC +HFLMTUAFIMJWFQ +HFLMTUAFIMJWFQ +HFLMTUAFIMJWFQ +LHDNKMRQLHZVIW +LHDNKMRQLHZVIW +LHDNKMRQLHZVIW +ZBRUKOSYKWUZDX +ZBRUKOSYKWUZDX +ZBRUKOSYKWUZDX +GAWXOAVYMIVRAC +GAWXOAVYMIVRAC +GAWXOAVYMIVRAC +HGBMBDPOIOGCFQ +HGBMBDPOIOGCFQ +HGBMBDPOIOGCFQ +KYZCMBWWSGDKNY +KYZCMBWWSGDKNY +KXPZNMQARYZTSY +KXPZNMQARYZTSY +KXPZNMQARYZTSY +UGTOXIVUUDKUPL +UGTOXIVUUDKUPL +UGTOXIVUUDKUPL +OPKCEXWIHDGVGQ +OPKCEXWIHDGVGQ +OPKCEXWIHDGVGQ +NLZSMWXSSYKHLL +NLZSMWXSSYKHLL +NLZSMWXSSYKHLL +KOJVDYOVCGBWPB +KOJVDYOVCGBWPB +KOJVDYOVCGBWPB +WCGLMKAQHVFYQQ +WCGLMKAQHVFYQQ +WCGLMKAQHVFYQQ +KQELDVCGBUDTLD +KQELDVCGBUDTLD +KQELDVCGBUDTLD +OURKCVDFEHGZHC +OURKCVDFEHGZHC +OPPBDPIJCANYJL +OPPBDPIJCANYJL +OPPBDPIJCANYJL +BUWZYNWNUYYWDY +BUWZYNWNUYYWDY +BUWZYNWNUYYWDY +BEWARSODUHVIJR +BEWARSODUHVIJR +BEWARSODUHVIJR +GRNMYURASJMHRO +GRNMYURASJMHRO +GRNMYURASJMHRO +KBMQFGIITZIIGF +KBMQFGIITZIIGF +KBMQFGIITZIIGF +LOMMRYJCCCWPRB +LOMMRYJCCCWPRB +LOMMRYJCCCWPRB +ZNRWELKYFJBPSJ +ZNRWELKYFJBPSJ +ZNRWELKYFJBPSJ +AQOXRNJUEXJAJL +AQOXRNJUEXJAJL +AQOXRNJUEXJAJL +ANVJFIICAFPERK +ANVJFIICAFPERK +ANVJFIICAFPERK +HJPQNKRXWKKENN +HJPQNKRXWKKENN +HJPQNKRXWKKENN +OAQKWMKKNKHXFL +OAQKWMKKNKHXFL +OAQKWMKKNKHXFL +FDMNTXQPAPAJSF +FDMNTXQPAPAJSF +FDMNTXQPAPAJSF +DBSQCMPJTRCNSE +DBSQCMPJTRCNSE +DBSQCMPJTRCNSE +HQBGMDJPLUFXNW +HQBGMDJPLUFXNW +HQBGMDJPLUFXNW +HQBGMDJPLUFXNW +KXHGBLSTPHAVHC +KXHGBLSTPHAVHC +KXHGBLSTPHAVHC +AVOAHVSWPURMFF +AVOAHVSWPURMFF +AVOAHVSWPURMFF +OOFIMMUCVFCOJU +OOFIMMUCVFCOJU +OOFIMMUCVFCOJU +OSMNVIGODYLNNL +OSMNVIGODYLNNL +OSMNVIGODYLNNL +SKCSMNARFGREKH +SKCSMNARFGREKH +SKCSMNARFGREKH +DPPJRDIDGHNQFK +DPPJRDIDGHNQFK +DPPJRDIDGHNQFK +UKRIEWSHXMGTDR +UKRIEWSHXMGTDR +UKRIEWSHXMGTDR +QMFTULGIUMWEMD +QMFTULGIUMWEMD +QMFTULGIUMWEMD +WWJWWCMJUNBMKL +WWJWWCMJUNBMKL +WWJWWCMJUNBMKL +KAXRAXSOOYOTKP +KAXRAXSOOYOTKP +LRNKNPGMMOFQIR +LRNKNPGMMOFQIR +LRNKNPGMMOFQIR +ATBXDPPGXZGVTG +ATBXDPPGXZGVTG +ATBXDPPGXZGVTG +AINOADYFTSGHBU +AINOADYFTSGHBU +AINOADYFTSGHBU +LHKLSNTUBPSXOR +LHKLSNTUBPSXOR +LHKLSNTUBPSXOR +JXLLKDVSVDJHDN +JXLLKDVSVDJHDN +JXLLKDVSVDJHDN +SORGYXWMVQZLOC +SORGYXWMVQZLOC +SORGYXWMVQZLOC +DAOFHSHVGMLUIZ +DAOFHSHVGMLUIZ +DAOFHSHVGMLUIZ +DLRXTPWRTAQTNV +DLRXTPWRTAQTNV +DLRXTPWRTAQTNV +WSJSURIJDUBPGO +WSJSURIJDUBPGO +WSJSURIJDUBPGO +MVWWHABIOCDVBQ +MVWWHABIOCDVBQ +MVWWHABIOCDVBQ +HAHRBZQJJMONMI +HAHRBZQJJMONMI +HAHRBZQJJMONMI +HAHRBZQJJMONMI +OQKWHFYGUZQARF +OQKWHFYGUZQARF +OQKWHFYGUZQARF +ANNLYINFXDULOD +ANNLYINFXDULOD +ANNLYINFXDULOD +ANNLYINFXDULOD +QYSGVTJBNQYQRI +QYSGVTJBNQYQRI +QYSGVTJBNQYQRI +GIOVYRFIFRUGOD +GIOVYRFIFRUGOD +GIOVYRFIFRUGOD +XMWQKZOGHQDJQL +XMWQKZOGHQDJQL +XMWQKZOGHQDJQL +UPNUIXSCZBYVBB +UPNUIXSCZBYVBB +UPNUIXSCZBYVBB +UPNUIXSCZBYVBB +BKPPHNVPJAFZCW +BKPPHNVPJAFZCW +BKPPHNVPJAFZCW +XSEBPPOMVWKWBX +XSEBPPOMVWKWBX +XSEBPPOMVWKWBX +NXSISTWUDFKGKE +NXSISTWUDFKGKE +NXSISTWUDFKGKE +XYRQBFYADAIKQV +XYRQBFYADAIKQV +XYRQBFYADAIKQV +WKSZLNLHILLCPS +WKSZLNLHILLCPS +KVYHUBWCOIGRPI +KVYHUBWCOIGRPI +KVYHUBWCOIGRPI +XAXLBFXFAXUEMF +XAXLBFXFAXUEMF +XAXLBFXFAXUEMF +ZPABZGTUJDBGFY +ZPABZGTUJDBGFY +ZPABZGTUJDBGFY +SEYDAAISKBFPCX +SEYDAAISKBFPCX +SEYDAAISKBFPCX +MWFTZXRIXOYEFD +MWFTZXRIXOYEFD +BLMPITSOBCOFNW +BLMPITSOBCOFNW +BLMPITSOBCOFNW +SHNUEAMUNBINOX +SHNUEAMUNBINOX +SHNUEAMUNBINOX +GKCUIAPUURHMNV +GKCUIAPUURHMNV +GKCUIAPUURHMNV +WSZWNIZVWLQAOB +WSZWNIZVWLQAOB +WSZWNIZVWLQAOB +AHRZIILMXPBZGY +AHRZIILMXPBZGY +AHRZIILMXPBZGY +LAYCQQTXYVVFMG +LAYCQQTXYVVFMG +LAYCQQTXYVVFMG +NJYASCROTXYKQP +NJYASCROTXYKQP +NJYASCROTXYKQP +LWXWKPAZKMJLBV +LWXWKPAZKMJLBV +LWXWKPAZKMJLBV +YJUTXCZXRFLVQL +YJUTXCZXRFLVQL +YJUTXCZXRFLVQL +FJGZAPWATMCVRC +FJGZAPWATMCVRC +FJGZAPWATMCVRC +PAMDZGORKBJJKQ +PAMDZGORKBJJKQ +PAMDZGORKBJJKQ +UNMIGPJBUXHYTB +UNMIGPJBUXHYTB +UNMIGPJBUXHYTB +FOPRHRQZBLMDMW +FOPRHRQZBLMDMW +FOPRHRQZBLMDMW +FXRQLAONKFVBBL +FXRQLAONKFVBBL +FXRQLAONKFVBBL +KBXFJPVRVFDWPV +KBXFJPVRVFDWPV +KBXFJPVRVFDWPV +PBAPPPCECJKMCM +PBAPPPCECJKMCM +PBAPPPCECJKMCM +OAAHMOVRZBGFOI +OAAHMOVRZBGFOI +OAAHMOVRZBGFOI +ZNIRSULWJSDHCT +ZNIRSULWJSDHCT +ZNIRSULWJSDHCT +ZNIRSULWJSDHCT +ROCZZHNXACEJRE +ROCZZHNXACEJRE +ROCZZHNXACEJRE +QGDZEMACLCFCJZ +QGDZEMACLCFCJZ +QGDZEMACLCFCJZ +UWYBSELSCUEBLB +UWYBSELSCUEBLB +UWYBSELSCUEBLB +VSXFWRNNVUDVKJ +VSXFWRNNVUDVKJ +VSXFWRNNVUDVKJ +MBXRJKKISHACQM +KVSRIVIUOVLYST +KVSRIVIUOVLYST +KVSRIVIUOVLYST +GMONYMGLEFPUMI +GMONYMGLEFPUMI +GMONYMGLEFPUMI +HDLJVNWBVNRQKI +HDLJVNWBVNRQKI +HDLJVNWBVNRQKI +OQEUENBRVOJYAE +OQEUENBRVOJYAE +OQEUENBRVOJYAE +HLPQAAFPDJGOGL +HLPQAAFPDJGOGL +HLPQAAFPDJGOGL +BSFYYMMRXHJHNV +BSFYYMMRXHJHNV +BSFYYMMRXHJHNV +UTULSHWHFXSBHW +UTULSHWHFXSBHW +UTULSHWHFXSBHW +GBXDZUVMCXOEDD +GBXDZUVMCXOEDD +GBXDZUVMCXOEDD +ZWSLTAMFBNHQMM +ZWSLTAMFBNHQMM +ZWSLTAMFBNHQMM +XQSPACMEHLOYFG +XQSPACMEHLOYFG +XQSPACMEHLOYFG +DUWXFCRCQGCZDQ +DUWXFCRCQGCZDQ +DUWXFCRCQGCZDQ +ICZBPRXGBBZFFH +ICZBPRXGBBZFFH +ICZBPRXGBBZFFH +BTUGLYFVTAAHPO +BTUGLYFVTAAHPO +BTUGLYFVTAAHPO +YJHDLYPLHDJBCG +YJHDLYPLHDJBCG +YJHDLYPLHDJBCG +YNAVDVFLCREEJG +YNAVDVFLCREEJG +YNAVDVFLCREEJG +GXNJYRPXEMKQMP +GXNJYRPXEMKQMP +GXNJYRPXEMKQMP +ONQKXJPLDSZTQH +ONQKXJPLDSZTQH +ONQKXJPLDSZTQH +ZPMNBAUTKCIDQP +ZPMNBAUTKCIDQP +ZPMNBAUTKCIDQP +WEAAFGBROZHQJB +WEAAFGBROZHQJB +WEAAFGBROZHQJB +HOOWXTBPUVABTI +HOOWXTBPUVABTI +HOOWXTBPUVABTI +CDXFLUPSGWSRKI +CDXFLUPSGWSRKI +CDXFLUPSGWSRKI +CIWYHAXKBYBXHV +CIWYHAXKBYBXHV +CIWYHAXKBYBXHV +HGLPGWWZVZLOEN +HGLPGWWZVZLOEN +HGLPGWWZVZLOEN +UFOHMOHQWLTNBP +UFOHMOHQWLTNBP +UFOHMOHQWLTNBP +IAKXQSXIROMSCB +IAKXQSXIROMSCB +IAKXQSXIROMSCB +VFLAWLJOLIBYKR +VFLAWLJOLIBYKR +BOCICSVXBGPMLI +BOCICSVXBGPMLI +BOCICSVXBGPMLI +VQKIMVPWKVBDAP +VQKIMVPWKVBDAP +VQKIMVPWKVBDAP +UEHFHXSNQGDKBU +UEHFHXSNQGDKBU +UEHFHXSNQGDKBU +UOPCHFBEAFXDNT +UOPCHFBEAFXDNT +UOPCHFBEAFXDNT +GVAAQJNITNJPAX +GVAAQJNITNJPAX +GVAAQJNITNJPAX +CPEASMDLDZFONU +CPEASMDLDZFONU +CPEASMDLDZFONU +JSHMEAUZFKZRAH +JSHMEAUZFKZRAH +YYPWLUQREAQAGG +YYPWLUQREAQAGG +YYPWLUQREAQAGG +CENBTWLOCOPWCJ +CENBTWLOCOPWCJ +CENBTWLOCOPWCJ +MUARERDHVRGEPX +MUARERDHVRGEPX +MUARERDHVRGEPX +BCDMINUJGPWGLH +BCDMINUJGPWGLH +BCDMINUJGPWGLH +VBTFYTQJKBIJIS +VBTFYTQJKBIJIS +VBTFYTQJKBIJIS +VRFUATNRHYXNLD +VRFUATNRHYXNLD +VRFUATNRHYXNLD +CPDQZOBWWXVZOA +CPDQZOBWWXVZOA +CPDQZOBWWXVZOA +CMIKFFCOVPQUFC +CMIKFFCOVPQUFC +CMIKFFCOVPQUFC +CISYJEWXIWQKHF +CISYJEWXIWQKHF +CISYJEWXIWQKHF +GXRWILDKSATDOF +GXRWILDKSATDOF +GXRWILDKSATDOF +PCGISWGVHGCMMA +PCGISWGVHGCMMA +PCGISWGVHGCMMA +IQUIAOZEPIDHSD +IQUIAOZEPIDHSD +IQUIAOZEPIDHSD +GSDAKEUKYUOHFK +GSDAKEUKYUOHFK +GSDAKEUKYUOHFK +HSYLMNJVGMMVPD +HSYLMNJVGMMVPD +HSYLMNJVGMMVPD +FFWRWMBRFPWFEG +FFWRWMBRFPWFEG +FFWRWMBRFPWFEG +NGPGSVOZDHJAHM +NGPGSVOZDHJAHM +WKZSBPYHBMXSIX +WKZSBPYHBMXSIX +WKZSBPYHBMXSIX +AVTJVAJGMUWLBF +AVTJVAJGMUWLBF +AVTJVAJGMUWLBF +ICRQWLLPESJOOB +ICRQWLLPESJOOB +HKCIFTPSIQZCJI +HKCIFTPSIQZCJI +HKCIFTPSIQZCJI +OWWSWMABYXJQIR +OWWSWMABYXJQIR +OWWSWMABYXJQIR +IGTWEHIQAJNIDQ +IGTWEHIQAJNIDQ +IGTWEHIQAJNIDQ +QTZJYQKPRYOMFX +QTZJYQKPRYOMFX +QTZJYQKPRYOMFX +NPMNFDZUHXLTEI +NPMNFDZUHXLTEI +NPMNFDZUHXLTEI +RGFUIFCUUUZBPH +RGFUIFCUUUZBPH +RGFUIFCUUUZBPH +ILQBTJWDTHYRJX +ILQBTJWDTHYRJX +ILQBTJWDTHYRJX +ILQBTJWDTHYRJX +CRZFKQDDRSZFHO +CRZFKQDDRSZFHO +CRZFKQDDRSZFHO +QZSDVMVHEORBIK +QZSDVMVHEORBIK +QZSDVMVHEORBIK +AGLOKSSTUVDSHQ +AGLOKSSTUVDSHQ +AGLOKSSTUVDSHQ +TZPYVFIDQCCPFR +TZPYVFIDQCCPFR +TZPYVFIDQCCPFR +PUMHKXIVRRHFAA +PUMHKXIVRRHFAA +PUMHKXIVRRHFAA +FOEYCBIOXZGYGM +FOEYCBIOXZGYGM +FOEYCBIOXZGYGM +YXTCNJAGKBWVJY +YXTCNJAGKBWVJY +YXTCNJAGKBWVJY +YXAPDJGWGYQIQW +YXAPDJGWGYQIQW +YXAPDJGWGYQIQW +TUDNIEYUZVVENI +TUDNIEYUZVVENI +TUDNIEYUZVVENI +PUHBOQQGBZOLLZ +PUHBOQQGBZOLLZ +PUHBOQQGBZOLLZ +IKIJPDJVSCIOGM +IKIJPDJVSCIOGM +IKIJPDJVSCIOGM +IHBYEWXAIRYQSC +IHBYEWXAIRYQSC +IHBYEWXAIRYQSC +IHBYEWXAIRYQSC +JARWGTYOGQTKOD +JARWGTYOGQTKOD +JARWGTYOGQTKOD +IZRUFBCZENTZGV +IZRUFBCZENTZGV +IZRUFBCZENTZGV +MXNIUQSGXKEPKN +MXNIUQSGXKEPKN +MXNIUQSGXKEPKN +PBIDPLPFOIMSKA +PBIDPLPFOIMSKA +PBIDPLPFOIMSKA +BMPIZTCXBSACNP +BMPIZTCXBSACNP +BMPIZTCXBSACNP +RTVQUOMANKJYEW +RTVQUOMANKJYEW +RTVQUOMANKJYEW +JRILBZVQGWDEHG +JRILBZVQGWDEHG +JRILBZVQGWDEHG +CSRPEPGWWOCGHD +CSRPEPGWWOCGHD +CSRPEPGWWOCGHD +RNHUFTSLRAPICH +RNHUFTSLRAPICH +RNHUFTSLRAPICH +KHLXEWOLKPDTRM +KHLXEWOLKPDTRM +KHLXEWOLKPDTRM +DAUZEDKYOODERD +DAUZEDKYOODERD +DAUZEDKYOODERD +FBLBICSZAXVSTM +FBLBICSZAXVSTM +FBLBICSZAXVSTM +VBMRBMXDXYDYGY +VBMRBMXDXYDYGY +VBMRBMXDXYDYGY +QAPCLEVBYWWJQJ +QAPCLEVBYWWJQJ +QAPCLEVBYWWJQJ +AINMATBTTSBOQI +AINMATBTTSBOQI +AINMATBTTSBOQI +RJJURHFRAJZREM +RJJURHFRAJZREM +RJJURHFRAJZREM +CXODNBVEQHLFAI +CXODNBVEQHLFAI +CXODNBVEQHLFAI +NSAWLWJJQSIDCZ +NSAWLWJJQSIDCZ +LBCLHVKOWCBWTF +LBCLHVKOWCBWTF +LBCLHVKOWCBWTF +LBCLHVKOWCBWTF +OCTVXDIJJZHVGJ +OCTVXDIJJZHVGJ +OCTVXDIJJZHVGJ +WDWBOFUUSPVDME +WDWBOFUUSPVDME +WDWBOFUUSPVDME +GQTZGWOAUXRZIB +GQTZGWOAUXRZIB +GQTZGWOAUXRZIB +PAVGOLAQPWUAGA +PAVGOLAQPWUAGA +PAVGOLAQPWUAGA +HCEBETLFIIZYRN +HCEBETLFIIZYRN +HCEBETLFIIZYRN +UFJFYBMCBRJDFH +UFJFYBMCBRJDFH +UFJFYBMCBRJDFH +HNFHCRJJDJQBCI +HNFHCRJJDJQBCI +HNFHCRJJDJQBCI +OXSPEYAADCCLRB +OXSPEYAADCCLRB +OXSPEYAADCCLRB +XEIIECXUMCOTAQ +XEIIECXUMCOTAQ +XEIIECXUMCOTAQ +ZAHLZWGECUMCIV +ZAHLZWGECUMCIV +ZAHLZWGECUMCIV +PEJGJRRZSONTKH +PEJGJRRZSONTKH +PEJGJRRZSONTKH +NUHZSLMEFKGPIH +NUHZSLMEFKGPIH +NUHZSLMEFKGPIH +NCWZPRIRYKDVRM +NCWZPRIRYKDVRM +NCWZPRIRYKDVRM +XFLQTXABZDUKSK +XFLQTXABZDUKSK +XFLQTXABZDUKSK +UVAWXOUKQSEIGA +UVAWXOUKQSEIGA +UVAWXOUKQSEIGA +LZUOPCOLXZGVBR +LZUOPCOLXZGVBR +LZUOPCOLXZGVBR +KOXRSZTXBUKXJX +KOXRSZTXBUKXJX +UBKPFCNPBCNMBW +UBKPFCNPBCNMBW +UBKPFCNPBCNMBW +NYJLBLYSDOXLBG +NYJLBLYSDOXLBG +NYJLBLYSDOXLBG +AOPHONVBZIBTJM +AOPHONVBZIBTJM +AOPHONVBZIBTJM +PCMBUAICBVFLON +PCMBUAICBVFLON +PCMBUAICBVFLON +BXCAADPMLSMMHF +BXCAADPMLSMMHF +BXCAADPMLSMMHF +ZFGXFGRNGAUUHI +ZFGXFGRNGAUUHI +ZFGXFGRNGAUUHI +OLJHFCRSQMZFIL +OLJHFCRSQMZFIL +OLJHFCRSQMZFIL +WRRNHWINVMJIHB +LEDBLXKSQNTAKZ +LEDBLXKSQNTAKZ +LEDBLXKSQNTAKZ +NWCPJOJEORGDHE +NWCPJOJEORGDHE +NWCPJOJEORGDHE +XZBYTSVSARLJGT +XZBYTSVSARLJGT +YKIBDHPKOKNCLT +YKIBDHPKOKNCLT +YKIBDHPKOKNCLT +OICVHXJTQGMQBA +OICVHXJTQGMQBA +OICVHXJTQGMQBA +ZLURXSCOFXAWBL +ZLURXSCOFXAWBL +ZLURXSCOFXAWBL +ITMIDSGCYPITAG +ITMIDSGCYPITAG +ITMIDSGCYPITAG +ZKKKYJAVPONFSN +ZKKKYJAVPONFSN +ZKKKYJAVPONFSN +YDUMYTPXPLIWJI +YDUMYTPXPLIWJI +YDUMYTPXPLIWJI +VWDDVEBFQQKQLE +VWDDVEBFQQKQLE +VWDDVEBFQQKQLE +JZFUDEWSSVPHNE +JZFUDEWSSVPHNE +JZFUDEWSSVPHNE +JWZVSVGEAUMFHG +JWZVSVGEAUMFHG +JWZVSVGEAUMFHG +ACGPSJNQVVFEGB +ACGPSJNQVVFEGB +MDDDMKHTYQEROX +MDDDMKHTYQEROX +MDDDMKHTYQEROX +XWWAJNILIFMRRY +XWWAJNILIFMRRY +XWWAJNILIFMRRY +LRACLFFJQVACLP +LRACLFFJQVACLP +LRACLFFJQVACLP +VQQCUDNFOHANFA +VQQCUDNFOHANFA +VQQCUDNFOHANFA +PTTWUULZGAWBQS +PTTWUULZGAWBQS +PTTWUULZGAWBQS +HLTPEDBLNUOHED +HLTPEDBLNUOHED +HLTPEDBLNUOHED +QAKNWCFOKANCQZ +QAKNWCFOKANCQZ +QAKNWCFOKANCQZ +NSAYCPOFDVXFMH +NSAYCPOFDVXFMH +NSAYCPOFDVXFMH +FKOPRCWKUXSNTK +FKOPRCWKUXSNTK +FKOPRCWKUXSNTK +QWJVHLKUOSQDLL +QWJVHLKUOSQDLL +QWJVHLKUOSQDLL +QWJVHLKUOSQDLL +RPIRNTLYBWHCCP +RPIRNTLYBWHCCP +RPIRNTLYBWHCCP +PIYAYRPJOLNDTC +PIYAYRPJOLNDTC +PIYAYRPJOLNDTC +AAEAWLCVAIUTBJ +AAEAWLCVAIUTBJ +AAEAWLCVAIUTBJ +NCUYBIHBIFAOKJ +NCUYBIHBIFAOKJ +NCUYBIHBIFAOKJ +MVAQXXXPLNKECG +MVAQXXXPLNKECG +MVAQXXXPLNKECG +NDYHTTLWCIHGSG +NDYHTTLWCIHGSG +NDYHTTLWCIHGSG +CYWQGEPBCFEUGU +CYWQGEPBCFEUGU +BSNHTUALXBUYIR +BSNHTUALXBUYIR +BSNHTUALXBUYIR +WHKYTIZDKNZEQK +WHKYTIZDKNZEQK +WHKYTIZDKNZEQK +WHKYTIZDKNZEQK +FLMYJQQITJJISH +FLMYJQQITJJISH +FLMYJQQITJJISH +VLMKFWSYRUZNGC +VLMKFWSYRUZNGC +VLMKFWSYRUZNGC +RNQJOPOIIPMBSJ +RNQJOPOIIPMBSJ +RNQJOPOIIPMBSJ +XYJQMAHFXVAVAY +XYJQMAHFXVAVAY +XYJQMAHFXVAVAY +PHCYAWCACVDLEH +PHCYAWCACVDLEH +PHCYAWCACVDLEH +HLKPEJZRCUUVLB +HLKPEJZRCUUVLB +HLKPEJZRCUUVLB +BURFVHLJIGXODD +BURFVHLJIGXODD +BURFVHLJIGXODD +DHTPQRVFNCKAIW +DHTPQRVFNCKAIW +DHTPQRVFNCKAIW +AAVBRRZDZCAKSJ +AAVBRRZDZCAKSJ +AAVBRRZDZCAKSJ +ZJJGKGOKVXQWAL +ZJJGKGOKVXQWAL +ZJJGKGOKVXQWAL +JTYRBAYRYOIUHR +JTYRBAYRYOIUHR +AJKWSWVFTGXVBD +AJKWSWVFTGXVBD +AJKWSWVFTGXVBD +FBPARHCWUYXOBW +FBPARHCWUYXOBW +FBPARHCWUYXOBW +XMFISXJBZQTOEQ +XMFISXJBZQTOEQ +XMFISXJBZQTOEQ +WITYEOOSZUICNZ +WITYEOOSZUICNZ +WITYEOOSZUICNZ +SNLRDRSLPRZTIZ +SNLRDRSLPRZTIZ +SNLRDRSLPRZTIZ +PKIWAHZKCAVWFG +PKIWAHZKCAVWFG +PKIWAHZKCAVWFG +DOWJCVAHEGUJIT +DOWJCVAHEGUJIT +DOWJCVAHEGUJIT +OGAZOYHQFBSRMC +OGAZOYHQFBSRMC +OGAZOYHQFBSRMC +NEHWVBYOCFASRX +NEHWVBYOCFASRX +NEHWVBYOCFASRX +PRFRHNDRJKACLE +PRFRHNDRJKACLE +PRFRHNDRJKACLE +LXBWDKGPOHKBEQ +LXBWDKGPOHKBEQ +KDAIPMZKLJZEJN +KDAIPMZKLJZEJN +KDAIPMZKLJZEJN +PDZYNEYDYSMOSZ +PDZYNEYDYSMOSZ +PDZYNEYDYSMOSZ +APCCGYQULFSYMH +APCCGYQULFSYMH +APCCGYQULFSYMH +VYWMXTWWRGPQHE +VYWMXTWWRGPQHE +VYWMXTWWRGPQHE +AWXSJOBEOKSEEL +AWXSJOBEOKSEEL +AWXSJOBEOKSEEL +KRVIWPUSMCFIFS +KRVIWPUSMCFIFS +KRVIWPUSMCFIFS +WLAJSBODTACZBB +WLAJSBODTACZBB +WLAJSBODTACZBB +LNURRHQNVJOLOW +LNURRHQNVJOLOW +LNURRHQNVJOLOW +XCKGRMPFYCOLEW +XCKGRMPFYCOLEW +AMGDLXBORMGHFD +AMGDLXBORMGHFD +AMGDLXBORMGHFD +LYVSJAXOQCNOSN +LYVSJAXOQCNOSN +MOVHFLQBKZUVHB +MOVHFLQBKZUVHB +MOVHFLQBKZUVHB +CXERCQDJURWLBG +CXERCQDJURWLBG +CXERCQDJURWLBG +VRQXNIWIURLDNB +VRQXNIWIURLDNB +VRQXNIWIURLDNB +BCZAAPPVGCCJAM +BCZAAPPVGCCJAM +BCZAAPPVGCCJAM +XGWFPSHUURVQEW +XGWFPSHUURVQEW +XGWFPSHUURVQEW +QIJYFVPFOMENAX +QIJYFVPFOMENAX +FHUDFQFOVCGJQG +FHUDFQFOVCGJQG +FHUDFQFOVCGJQG +IZGOBGVYADHVKH +IZGOBGVYADHVKH +IZGOBGVYADHVKH +FIDXHDFJMMLHOG +FIDXHDFJMMLHOG +FIDXHDFJMMLHOG +GITSUDNMPLMYRH +GITSUDNMPLMYRH +GITSUDNMPLMYRH +PVVYICBYIWVMPL +PVVYICBYIWVMPL +PVVYICBYIWVMPL +LUMJXNUHMOHZJL +LUMJXNUHMOHZJL +LUMJXNUHMOHZJL +BHQQTLXVQAIFIB +BHQQTLXVQAIFIB +BHQQTLXVQAIFIB +RKSFCTQWIPYSLR +RKSFCTQWIPYSLR +RKSFCTQWIPYSLR +VSRSEEBAEOQGAW +VSRSEEBAEOQGAW +VSRSEEBAEOQGAW +LVFGGXGYTIDQEY +LVFGGXGYTIDQEY +LVFGGXGYTIDQEY +BYYAYTKQMNKRPR +HQLHAQQVVQQMFJ +KMRHXTZVGPGZCX +KMRHXTZVGPGZCX +KMRHXTZVGPGZCX +ZXZQIOUBMKFKTA +ZXZQIOUBMKFKTA +ZXZQIOUBMKFKTA +MYVZDMKFFPFTMD +MYVZDMKFFPFTMD +MYVZDMKFFPFTMD +REFRBKOFZSDCHI +REFRBKOFZSDCHI +REFRBKOFZSDCHI +YEXTZQIZMWXPQR +YEXTZQIZMWXPQR +YEXTZQIZMWXPQR +CUSDGKKDYLSTKB +CUSDGKKDYLSTKB +CUSDGKKDYLSTKB +YHAGCUCWJKQZPL +YHAGCUCWJKQZPL +IQSFGCZSDVSGHZ +IQSFGCZSDVSGHZ +IQSFGCZSDVSGHZ +XSOUXANRIFPDEN +XSOUXANRIFPDEN +NXORRYJZFXOGDU +NXORRYJZFXOGDU +HNRZCTRCQZABEN +HNRZCTRCQZABEN +HNRZCTRCQZABEN +ZVGYUVQQYRUETH +ZVGYUVQQYRUETH +ZVGYUVQQYRUETH +OGHWINUCXOBRCS +OGHWINUCXOBRCS +OGHWINUCXOBRCS +JCJVHPODRVXPSC +JCJVHPODRVXPSC +JCJVHPODRVXPSC +ZBIJCERRONLKHO +ZBIJCERRONLKHO +ZBIJCERRONLKHO +LDCGIZWRZRSYLX +LDCGIZWRZRSYLX +OYFCDWLVIVPEDW +OYFCDWLVIVPEDW +OYFCDWLVIVPEDW +TXOLTAWOEMUYSV +TXOLTAWOEMUYSV +TXOLTAWOEMUYSV +HYPHHJSPSRLCHU +HYPHHJSPSRLCHU +HYPHHJSPSRLCHU +UKFKCUMNWXQOQS +UKFKCUMNWXQOQS +UKFKCUMNWXQOQS +FRLXKSAJYADRBR +FRLXKSAJYADRBR +FRLXKSAJYADRBR +DNJXLTYRICAZNB +DNJXLTYRICAZNB +DNJXLTYRICAZNB +LEPBKYDCBIPQKJ +LEPBKYDCBIPQKJ +LEPBKYDCBIPQKJ +BJJLBKXHFKYYGY +BJJLBKXHFKYYGY +BJJLBKXHFKYYGY +NHNMZGQJXPBSMT +ZKXWUYJRISUOBG +ZKXWUYJRISUOBG +QXHVPXKCJISFLG +QXHVPXKCJISFLG +QXHVPXKCJISFLG +CCDXTSXSHZUOET +CCDXTSXSHZUOET +CCDXTSXSHZUOET +ZRILRJGCVHTPDO +ZRILRJGCVHTPDO +ZRILRJGCVHTPDO +HQTGROXCONVRQQ +HQTGROXCONVRQQ +HQTGROXCONVRQQ +PKEDZFHFEJYKJF +PKEDZFHFEJYKJF +PKEDZFHFEJYKJF +PXRNJGOMFAMGHT +PXRNJGOMFAMGHT +PXRNJGOMFAMGHT +MPASIGMWVBKWGB +MPASIGMWVBKWGB +MPASIGMWVBKWGB +RMSVVKVICJKAJN +RMSVVKVICJKAJN +RMSVVKVICJKAJN +TXZDIJNADAXUBW +TXZDIJNADAXUBW +TXZDIJNADAXUBW +FSFOPRWEVGFTAE +FSFOPRWEVGFTAE +FSFOPRWEVGFTAE +PHKCGHYNCUWOEV +PHKCGHYNCUWOEV +PHKCGHYNCUWOEV +UGZNTRQRXOPMJT +UGZNTRQRXOPMJT +UGZNTRQRXOPMJT +WYJHAJVHRDCSCH +WYJHAJVHRDCSCH +WYJHAJVHRDCSCH +QLROVPDOANJAIC +QLROVPDOANJAIC +QLROVPDOANJAIC +XGWXTHXHJYWHMH +XGWXTHXHJYWHMH +XGWXTHXHJYWHMH +ABYOVIVWKRGMMX +ABYOVIVWKRGMMX +ABYOVIVWKRGMMX +LQZDWPDDXHQCSM +LQZDWPDDXHQCSM +LQZDWPDDXHQCSM +BRAAUNMWRLDOLQ +BRAAUNMWRLDOLQ +BRAAUNMWRLDOLQ +BYPIAHBBNMAQGI +BYPIAHBBNMAQGI +BYPIAHBBNMAQGI +IRLJRBGBYUEHMT +IRLJRBGBYUEHMT +IRLJRBGBYUEHMT +IRLJRBGBYUEHMT +CZAVVPWANUGMGE +CZAVVPWANUGMGE +ANJZLJIAEZIZAG +ANJZLJIAEZIZAG +ANJZLJIAEZIZAG +ZWZHLDMNSVZYFP +ZWZHLDMNSVZYFP +ZWZHLDMNSVZYFP +FSEOPJIGTIEFRA +FSEOPJIGTIEFRA +FSEOPJIGTIEFRA +FIPJYCSLXSWRIM +FIPJYCSLXSWRIM +FIPJYCSLXSWRIM +BMXACRHZRMBTRE +BMXACRHZRMBTRE +BMXACRHZRMBTRE +BMXACRHZRMBTRE +PMXMFELSKPYMBT +PMXMFELSKPYMBT +PMXMFELSKPYMBT +PMYWDSQWIZHMFB +PMYWDSQWIZHMFB +PMYWDSQWIZHMFB +RBXIMXKIFBSCDB +RBXIMXKIFBSCDB +RBXIMXKIFBSCDB +JMYMPFXGXNZPDG +JMYMPFXGXNZPDG +JMYMPFXGXNZPDG +NTENGTZEILUSRZ +NTENGTZEILUSRZ +NTENGTZEILUSRZ +KSTSDLUYSOEMSF +KSTSDLUYSOEMSF +KSTSDLUYSOEMSF +ORKOMYJUQLPMFR +ORKOMYJUQLPMFR +ORKOMYJUQLPMFR +GGNMSJDDSDIQRS +GGNMSJDDSDIQRS +GGNMSJDDSDIQRS +ARPIKGGVTJYLOK +ARPIKGGVTJYLOK +ARPIKGGVTJYLOK +ARPIKGGVTJYLOK +MLGWPKAJJZRCGW +MLGWPKAJJZRCGW +MLGWPKAJJZRCGW +IYAHRVMBSJPMAF +KCWLLWSUKSVRQY +KCWLLWSUKSVRQY +KCWLLWSUKSVRQY +XOFQZRHSQYPCGN +XOFQZRHSQYPCGN +XOFQZRHSQYPCGN +WJDXYYYDPOQBTF +WJDXYYYDPOQBTF +WJDXYYYDPOQBTF +WPRJPBJQIBGEKX +WPRJPBJQIBGEKX +WPRJPBJQIBGEKX +AKISVAHHRYLWAZ +AKISVAHHRYLWAZ +AKISVAHHRYLWAZ +AAYBONXFXJNZJR +AAYBONXFXJNZJR +UTNDOZKULQPPET +UTNDOZKULQPPET +UTNDOZKULQPPET +FYDQAOTYCKQQIK +FYDQAOTYCKQQIK +FYDQAOTYCKQQIK +MQHGBGCKIFPBKQ +MQHGBGCKIFPBKQ +MQHGBGCKIFPBKQ +VLPYQPNJFKVNSN +VLPYQPNJFKVNSN +VLPYQPNJFKVNSN +HFHHFFDSRPVSCZ +HFHHFFDSRPVSCZ +HFHHFFDSRPVSCZ +PROJTOHGMZDQLH +PROJTOHGMZDQLH +PROJTOHGMZDQLH +KCPXZNLTQWETPB +KCPXZNLTQWETPB +KCPXZNLTQWETPB +SZBHYASLDMWMCF +SZBHYASLDMWMCF +SZBHYASLDMWMCF +GVKCSNQBYFVQQB +GVKCSNQBYFVQQB +GVKCSNQBYFVQQB +HJABIYJRZIWBLB +HJABIYJRZIWBLB +HJABIYJRZIWBLB +DNTWQBFGTPSLAS +DNTWQBFGTPSLAS +DNTWQBFGTPSLAS +KEZCRCISUVKQPR +KEZCRCISUVKQPR +KEZCRCISUVKQPR +QNWXJKQHLAOMLJ +QNWXJKQHLAOMLJ +QNWXJKQHLAOMLJ +YQKZHQOZLKCFNK +YQKZHQOZLKCFNK +YQKZHQOZLKCFNK +JVODNHZESHSUJN +JVODNHZESHSUJN +JVODNHZESHSUJN +USUYTARMHHGYFP +USUYTARMHHGYFP +USUYTARMHHGYFP +ZNLIMVMJHJCAQY +ZNLIMVMJHJCAQY +CXOWHXHVUSKJKU +CXOWHXHVUSKJKU +CXOWHXHVUSKJKU +FMEGMANQLUEYOL +FMEGMANQLUEYOL +FMEGMANQLUEYOL +LNAAQGFVOUGFSA +LNAAQGFVOUGFSA +LNAAQGFVOUGFSA +WJXIDAAPWBCTAL +WJXIDAAPWBCTAL +WJXIDAAPWBCTAL +UWCZSBKZDIBKCQ +UWCZSBKZDIBKCQ +UWCZSBKZDIBKCQ +YFPQKOUEYQSWAO +YFPQKOUEYQSWAO +YFPQKOUEYQSWAO +OZGUBQHQKJKTEI +OZGUBQHQKJKTEI +MLAHRXDEUJSGKA +MLAHRXDEUJSGKA +MLAHRXDEUJSGKA +TXKUBMJOOSZTSH +TXKUBMJOOSZTSH +TXKUBMJOOSZTSH +KVXVUBLSGRMKHU +KVXVUBLSGRMKHU +SKZMLLOZZWNWCK +SKZMLLOZZWNWCK +SKZMLLOZZWNWCK +FCUWWYJELRALIL +FCUWWYJELRALIL +FCUWWYJELRALIL +NQWIDFQODDAUTD +NQWIDFQODDAUTD +NQWIDFQODDAUTD +GOZVPOAXFAHKPG +GOZVPOAXFAHKPG +GOZVPOAXFAHKPG +ZNUMPHYRTDZSKK +ZNUMPHYRTDZSKK +ZNUMPHYRTDZSKK +PDSOSMOMBUMYNQ +PDSOSMOMBUMYNQ +PDSOSMOMBUMYNQ +HJVXUQIBIZJSDW +HJVXUQIBIZJSDW +HJVXUQIBIZJSDW +ACWMEHXOHYZXMR +ACWMEHXOHYZXMR +ACWMEHXOHYZXMR +NFRKPKLAMJLZRA +NFRKPKLAMJLZRA +NFRKPKLAMJLZRA +SMOOKBJHIPJQPG +SMOOKBJHIPJQPG +SMOOKBJHIPJQPG +NQGLYXCBQFFJFP +NQGLYXCBQFFJFP +NQGLYXCBQFFJFP +NWLRMGZNQNVLCA +NWLRMGZNQNVLCA +NWLRMGZNQNVLCA +NBYCJDACRVMVKG +NBYCJDACRVMVKG +NBYCJDACRVMVKG +YXJSEBAOOITNEA +YXJSEBAOOITNEA +YXJSEBAOOITNEA +ZUJUFVQOLGSMTK +ZUJUFVQOLGSMTK +ZUJUFVQOLGSMTK +ZUJUFVQOLGSMTK +BGRFGLZZRSRJSD +BGRFGLZZRSRJSD +BGRFGLZZRSRJSD +ZNPCVZMOUAMGQD +ZNPCVZMOUAMGQD +ZNPCVZMOUAMGQD +ZNPCVZMOUAMGQD +XFZWJFGWPOYEBZ +XFZWJFGWPOYEBZ +XFZWJFGWPOYEBZ +LCPHLQSIFPOEEM +LCPHLQSIFPOEEM +LCPHLQSIFPOEEM +BLRWQQRQKHGISD +BLRWQQRQKHGISD +BLRWQQRQKHGISD +IBJNJYFZUDTMHJ +DQGWAEDXKMUQIH +DQGWAEDXKMUQIH +DQGWAEDXKMUQIH +GVMORENYQVGDRD +GVMORENYQVGDRD +GVMORENYQVGDRD +GVMORENYQVGDRD +GVMORENYQVGDRD +GVMORENYQVGDRD +TWKOJBXTGXHLQG +TWKOJBXTGXHLQG +TWKOJBXTGXHLQG +TZEFKDRNXZMXDR +TZEFKDRNXZMXDR +TZEFKDRNXZMXDR +SOENAMHZJTXLPC +SOENAMHZJTXLPC +SOENAMHZJTXLPC +XLPPKGGUHHNHOC +XLPPKGGUHHNHOC +XLPPKGGUHHNHOC +ZDJFVZPHBKPSMD +SBPOTJSRSGXHCV +SBPOTJSRSGXHCV +SBPOTJSRSGXHCV +PRYKQECMRQXSCR +PRYKQECMRQXSCR +PRYKQECMRQXSCR +NHFAPEWCRLXKFE +NHFAPEWCRLXKFE +NHFAPEWCRLXKFE +AATRFIAYPGUYMW +AATRFIAYPGUYMW +AATRFIAYPGUYMW +AOQHPIGHSOOGCX +GMXYBDMQXLCOKL +GMXYBDMQXLCOKL +GMXYBDMQXLCOKL +ASNSMXBMJHRYOZ +ASNSMXBMJHRYOZ +TVSGZVYNTALTGJ +TVSGZVYNTALTGJ +UHKNSIYURJUFJR +WNMLMDCKMBHRFE +WNMLMDCKMBHRFE +WNMLMDCKMBHRFE +LZKWNMIPHABPAZ +LZKWNMIPHABPAZ +LZKWNMIPHABPAZ +OSAXYETXRZISMK +OSAXYETXRZISMK +OSAXYETXRZISMK +LUGLLAHZGTUSAE +CCMODKJLHXCSET +CCMODKJLHXCSET +CCMODKJLHXCSET +NGMMALNASFGIFU +XXBNJBZOUKZBIY +XXBNJBZOUKZBIY +XXBNJBZOUKZBIY +FCBYWTROAWHIFF +FCBYWTROAWHIFF +FCBYWTROAWHIFF +JKPXQTHIKSURHW +JKPXQTHIKSURHW +JKPXQTHIKSURHW +HBZIYKZJMNSXEW +HBZIYKZJMNSXEW +HBZIYKZJMNSXEW +SLMYXBYAKALDHN +SLMYXBYAKALDHN +SLMYXBYAKALDHN +OFUKFUXODQFJDK +OFUKFUXODQFJDK +OFUKFUXODQFJDK +HNQQOGINPMHIGD +HNQQOGINPMHIGD +HNQQOGINPMHIGD +WKLVYGRBGKRSCM +WKLVYGRBGKRSCM +WKLVYGRBGKRSCM +VMPLCHBRJJWZJE +VMPLCHBRJJWZJE +VMPLCHBRJJWZJE +KTLWRRNUKXYRKQ +KTLWRRNUKXYRKQ +KTLWRRNUKXYRKQ +UGPWVGGOXVGGFV +UGPWVGGOXVGGFV +UGPWVGGOXVGGFV +ZAZMPEZUEMKGHN +ZAZMPEZUEMKGHN +ZAZMPEZUEMKGHN +CWXAZRZVTSKFRQ +CWXAZRZVTSKFRQ +CWXAZRZVTSKFRQ +CHCKYCJIOZMEMQ +CHCKYCJIOZMEMQ +CHCKYCJIOZMEMQ +GXFIQOWIDSZYKM +GXFIQOWIDSZYKM +GXFIQOWIDSZYKM +OIHXHHOMMLHVNS +OIHXHHOMMLHVNS +OIHXHHOMMLHVNS +IFGIBLYPDSUQFQ +IFGIBLYPDSUQFQ +IFGIBLYPDSUQFQ +DHCAJPAPODTREA +DHCAJPAPODTREA +DHCAJPAPODTREA +ZBWDPHYMTBHZDB +ZBWDPHYMTBHZDB +CUSBPCYPCUDPSC +CUSBPCYPCUDPSC +ODTVTKNTHDWUIX +ODTVTKNTHDWUIX +ODTVTKNTHDWUIX +RDOOBGMFVQFWFE +RDOOBGMFVQFWFE +RDOOBGMFVQFWFE +YMIZVEHBMGIBNT +YMIZVEHBMGIBNT +UMOUNYMKXJEVMB +UMOUNYMKXJEVMB +UMOUNYMKXJEVMB +VGRCYMLWKSIGPG +VGRCYMLWKSIGPG +ZAGILYFEOKDHLX +ZAGILYFEOKDHLX +ZAGILYFEOKDHLX +HNDHQRGGQUZYOV +HNDHQRGGQUZYOV +HNDHQRGGQUZYOV +KMTBGRVNYHTBBW +KMTBGRVNYHTBBW +KMTBGRVNYHTBBW +GTRRMSOBXYYUGA +GTRRMSOBXYYUGA +BSGXBDXCSNPIGD +BSGXBDXCSNPIGD +BSGXBDXCSNPIGD +JNZNBNHTXIARPN +JNZNBNHTXIARPN +JNZNBNHTXIARPN +QPQGNQOKESVLFR +QPQGNQOKESVLFR +QPQGNQOKESVLFR +JRKXZSDHWWDBMI +JRKXZSDHWWDBMI +JRKXZSDHWWDBMI +BTWHZQREJHEVAN +BTWHZQREJHEVAN +BTWHZQREJHEVAN +SWHIVSUFNKSRKF +SWHIVSUFNKSRKF +SWHIVSUFNKSRKF +GRBUIWNAULQVMJ +GRBUIWNAULQVMJ +GRBUIWNAULQVMJ +FQGVLGXDSANUPW +FQGVLGXDSANUPW +GRMVUDZXFBCDRT +GRMVUDZXFBCDRT +WFDLQBSSYXKFIU +WFDLQBSSYXKFIU +WFDLQBSSYXKFIU +HWRJQTDXSJMRHX +HWRJQTDXSJMRHX +HWRJQTDXSJMRHX +VLTUTGICGFLSJN +VLTUTGICGFLSJN +VLTUTGICGFLSJN +QGMMOFZKYXZVMR +QGMMOFZKYXZVMR +QGMMOFZKYXZVMR +ZOOVYGYVTXEBQO +ZOOVYGYVTXEBQO +ZOOVYGYVTXEBQO +ZDLVWXCTVHHHDY +ZDLVWXCTVHHHDY +ZDLVWXCTVHHHDY +CPZYJADHEFXIAQ +CPZYJADHEFXIAQ +CPZYJADHEFXIAQ +DUISFSOCQODZTR +DUISFSOCQODZTR +DUISFSOCQODZTR +HFRYZYZRMDGKCL +HFRYZYZRMDGKCL +HFRYZYZRMDGKCL +WVRFRAUUOIILQE +WVRFRAUUOIILQE +WVRFRAUUOIILQE +NSMRKGLEXFZFIO +NSMRKGLEXFZFIO +NSMRKGLEXFZFIO +HJAYMHYJHPMAJK +HJAYMHYJHPMAJK +HJAYMHYJHPMAJK +PJNAJYMBARKRKX +PJNAJYMBARKRKX +PJNAJYMBARKRKX +YRTZPUGQEJSFCM +YRTZPUGQEJSFCM +YRTZPUGQEJSFCM +QWIWBVKUMVJBHT +QWIWBVKUMVJBHT +QWIWBVKUMVJBHT +MCDNHFQUQUDJGP +MCDNHFQUQUDJGP +MCDNHFQUQUDJGP +LFYUKZGRCHJXJY +LFYUKZGRCHJXJY +LFYUKZGRCHJXJY +QDIOBBHRAVYZSK +QDIOBBHRAVYZSK +QDIOBBHRAVYZSK +ZKHHCFIICWBJFC +ZKHHCFIICWBJFC +ZKHHCFIICWBJFC +HFDFLQAJFCKNLJ +HFDFLQAJFCKNLJ +HFDFLQAJFCKNLJ +PJVMRPXCZQMDGG +PJVMRPXCZQMDGG +PJVMRPXCZQMDGG +QIHMNRVVGFQXCL +QIHMNRVVGFQXCL +QIHMNRVVGFQXCL +IGLUHVTWGUNZDA +IGLUHVTWGUNZDA +CKXXYRZHDZVHHC +CKXXYRZHDZVHHC +CKXXYRZHDZVHHC +FTUFQXIKSKFKQO +FTUFQXIKSKFKQO +YHKGITNAJGGCBZ +YHKGITNAJGGCBZ +YHKGITNAJGGCBZ +YARPGMCVOVAWLP +YARPGMCVOVAWLP +YARPGMCVOVAWLP +YUYWHJZCDFKCFV +YUYWHJZCDFKCFV +YUYWHJZCDFKCFV +DKMPVWXIENHAEZ +DKMPVWXIENHAEZ +MBSMVFLGJLSDEQ +MBSMVFLGJLSDEQ +MBSMVFLGJLSDEQ +YJUFYCBFKUSJPI +YJUFYCBFKUSJPI +YJUFYCBFKUSJPI +HCWCYOSCPZHRLV +HCWCYOSCPZHRLV +HCWCYOSCPZHRLV +ANRVPJVYTSFHFM +ANRVPJVYTSFHFM +ANRVPJVYTSFHFM +PPHLAJAGABCIAH +PPHLAJAGABCIAH +PPHLAJAGABCIAH +CTYCSOSPTSAGHP +CTYCSOSPTSAGHP +OSBYPVZQMQEBOE +OSBYPVZQMQEBOE +OSBYPVZQMQEBOE +CLCWDMLDJOFGGQ +CLCWDMLDJOFGGQ +CLCWDMLDJOFGGQ +BAKVNIYUGKOUGM +BAKVNIYUGKOUGM +IWGGPLASJJBFMN +IWGGPLASJJBFMN +IWGGPLASJJBFMN +BHBHRRHLEROGOD +BHBHRRHLEROGOD +BHBHRRHLEROGOD +NJCUMGOKVJTRPQ +NJCUMGOKVJTRPQ +NJCUMGOKVJTRPQ +PIUZOOCIGFCIIS +PIUZOOCIGFCIIS +PIUZOOCIGFCIIS +MCZLEHUMXGWAJZ +MCZLEHUMXGWAJZ +MCZLEHUMXGWAJZ +AGHURIXQDUWSKL +AGHURIXQDUWSKL +AGHURIXQDUWSKL +GNGRZQJPJDOLAC +GNGRZQJPJDOLAC +GNGRZQJPJDOLAC +WJNIPNJMNBVBKI +WJNIPNJMNBVBKI +WJNIPNJMNBVBKI +SYTMUAVLSMHWLV +SYTMUAVLSMHWLV +SYTMUAVLSMHWLV +WDEKOHTUSQRRSZ +WDEKOHTUSQRRSZ +WDEKOHTUSQRRSZ +CRUPIZMUXHOJNL +CRUPIZMUXHOJNL +CRUPIZMUXHOJNL +UXWBCRQJKVQEQA +UXWBCRQJKVQEQA +UXWBCRQJKVQEQA +UXWBCRQJKVQEQA +IIDCKYCYHXLPEK +IIDCKYCYHXLPEK +IIDCKYCYHXLPEK +QRQOOBQZXJOFAL +QRQOOBQZXJOFAL +QRQOOBQZXJOFAL +RXYYUEFBWDXREK +RXYYUEFBWDXREK +RXYYUEFBWDXREK +DOUZNGPWZZDEGR +DOUZNGPWZZDEGR +DOUZNGPWZZDEGR +DFGVVHQNNRKFAD +DFGVVHQNNRKFAD +DFGVVHQNNRKFAD +SDBZRJXLFBBFJW +SDBZRJXLFBBFJW +SDBZRJXLFBBFJW +MVJICVXYTMKQTB +MVJICVXYTMKQTB +MVJICVXYTMKQTB +JRQZSORTKKNEKB +JRQZSORTKKNEKB +JRQZSORTKKNEKB +IMXLONKIFCREOD +XAZVJRSZKVMGAF +XAZVJRSZKVMGAF +XAZVJRSZKVMGAF +LEZTUTWSOVDBCA +LEZTUTWSOVDBCA +LEZTUTWSOVDBCA +OGYZPWONPFHXSP +OGYZPWONPFHXSP +OGYZPWONPFHXSP +MISRAUIAGDGPAE +MISRAUIAGDGPAE +MISRAUIAGDGPAE +CFWAAIZGVGUQQI +CFWAAIZGVGUQQI +CFWAAIZGVGUQQI +VDKJXCKRAPFVEH +VDKJXCKRAPFVEH +VDKJXCKRAPFVEH +LXTOFSSTRXQSAU +LXTOFSSTRXQSAU +LXTOFSSTRXQSAU +WTBRKDBMFMFKJD +WTBRKDBMFMFKJD +WTBRKDBMFMFKJD +ZDLCUQGKROPZGC +ZBKCHDXSGACZLM +ZBKCHDXSGACZLM +ZBKCHDXSGACZLM +PNOZUNOLVJSISN +PNOZUNOLVJSISN +PNOZUNOLVJSISN +GEJYLFJPMSGWPB +GEJYLFJPMSGWPB +GEJYLFJPMSGWPB +VMNVVTQMPPJTRF +VMNVVTQMPPJTRF +VMNVVTQMPPJTRF +GFPUWRNMHBIRRT +GFPUWRNMHBIRRT +GFPUWRNMHBIRRT +BCMSCQHYBDZWMG +BCMSCQHYBDZWMG +BCMSCQHYBDZWMG +WHJOKSDRDMWNHE +WHJOKSDRDMWNHE +WHJOKSDRDMWNHE +ZHQCBVWJFJZSEQ +ZHQCBVWJFJZSEQ +ZHQCBVWJFJZSEQ +YIZMGWMMMLRDMT +YIZMGWMMMLRDMT +YIZMGWMMMLRDMT +LHHQRYAFTGJCIC +LHHQRYAFTGJCIC +LHHQRYAFTGJCIC +IXHHDHKZLRGIGR +IXHHDHKZLRGIGR +IXHHDHKZLRGIGR +NBGFBYNTQKUALK +NBGFBYNTQKUALK +NBGFBYNTQKUALK +LSTAPYLRKGDICK +LSTAPYLRKGDICK +LSTAPYLRKGDICK +IIRIZGRXNZNYNL +IIRIZGRXNZNYNL +IIRIZGRXNZNYNL +XKSIOJNHGNZOFO +XKSIOJNHGNZOFO +XKSIOJNHGNZOFO +JDUYJXKEXUQBIF +JDUYJXKEXUQBIF +JDUYJXKEXUQBIF +BHGHLSXBJJAVCN +BHGHLSXBJJAVCN +BHGHLSXBJJAVCN +RROASNULMCPPNH +RROASNULMCPPNH +RROASNULMCPPNH +RSXUEYFLDNUILS +RSXUEYFLDNUILS +RSXUEYFLDNUILS +RSXUEYFLDNUILS +RSXUEYFLDNUILS +RSXUEYFLDNUILS +UGLIMKWMXVCHAO +UGLIMKWMXVCHAO +UGLIMKWMXVCHAO +SHFZLOHVSZBBNK +SHFZLOHVSZBBNK +SHFZLOHVSZBBNK +LFCYMLWKEUVYAL +LFCYMLWKEUVYAL +LFCYMLWKEUVYAL +DJSLLEKUXRRELM +DJSLLEKUXRRELM +DJSLLEKUXRRELM +WNBKCFFXYWVLHF +WNBKCFFXYWVLHF +WNBKCFFXYWVLHF +PHCPYAUOYHVRCR +PHCPYAUOYHVRCR +PHCPYAUOYHVRCR +PZXBODPDYYBNOJ +PZXBODPDYYBNOJ +PZXBODPDYYBNOJ +RUZWPWIFEXPGGF +RUZWPWIFEXPGGF +RUZWPWIFEXPGGF +LLWDLGHJQJBYPB +LLWDLGHJQJBYPB +LLWDLGHJQJBYPB +ZKCBGVCZJLZTNQ +ZKCBGVCZJLZTNQ +ZKCBGVCZJLZTNQ +DCUHKBYAVVOYMJ +DCUHKBYAVVOYMJ +DCUHKBYAVVOYMJ +WQPAWIWTMXYBJA +WQPAWIWTMXYBJA +WQPAWIWTMXYBJA +LLWOESLKEFQFDO +LLWOESLKEFQFDO +LLWOESLKEFQFDO +FZMQSNAZSRPBEY +FZMQSNAZSRPBEY +FZMQSNAZSRPBEY +CJGMPGWRHPMLBU +CJGMPGWRHPMLBU +CJGMPGWRHPMLBU +DUYWLYDWYZXABO +DUYWLYDWYZXABO +DUYWLYDWYZXABO +WDTARPJJQMOSMF +WDTARPJJQMOSMF +WDTARPJJQMOSMF +RNGNYGLZHZAAQS +RNGNYGLZHZAAQS +RNGNYGLZHZAAQS +GFQKJOYOOVSYKW +GFQKJOYOOVSYKW +GFQKJOYOOVSYKW +SIFLWUIQICACCC +SIFLWUIQICACCC +SIFLWUIQICACCC +WKEDIALPWYAFBJ +WKEDIALPWYAFBJ +WKEDIALPWYAFBJ +YTGOATMIIFEOCC +YTGOATMIIFEOCC +YTGOATMIIFEOCC +YLHBYJQVLCSDKN +YLHBYJQVLCSDKN +YLHBYJQVLCSDKN +DSCPIHMNFFFJRM +DSCPIHMNFFFJRM +DSCPIHMNFFFJRM +HRVZNPMOJFCHGH +HJZBBUFIXNVICN +HJZBBUFIXNVICN +HJZBBUFIXNVICN +KJYCIPWGCPJWMD +KJYCIPWGCPJWMD +KJYCIPWGCPJWMD +LRGORGOVOUVBRG +LRGORGOVOUVBRG +LRGORGOVOUVBRG +FWCAOVHHIHUHLD +FWCAOVHHIHUHLD +FWCAOVHHIHUHLD +BTDMQZFFGFYHED +BTDMQZFFGFYHED +BTDMQZFFGFYHED +ADUZOYYYNWLSTK +ADUZOYYYNWLSTK +ADUZOYYYNWLSTK +ODMBLMOBQOPOBR +ODMBLMOBQOPOBR +ODMBLMOBQOPOBR +GLLSALCQFDRIMZ +GLLSALCQFDRIMZ +GLLSALCQFDRIMZ +PNPNCWODFQDAGU +PNPNCWODFQDAGU +PNPNCWODFQDAGU +RIZHOCSVILARCM +RIZHOCSVILARCM +RIZHOCSVILARCM +GTYRPTCNPOLKDP +CQRPYYLGCCLURD +CQRPYYLGCCLURD +CQRPYYLGCCLURD +PYPZXWVDLJAFHU +PYPZXWVDLJAFHU +PYPZXWVDLJAFHU +PWBLSPXEXBDGPG +PWBLSPXEXBDGPG +PWBLSPXEXBDGPG +MLQJZUYTAFKATK +MLQJZUYTAFKATK +MLQJZUYTAFKATK +ZEMGHTNDLJHOHA +ZEMGHTNDLJHOHA +ZEMGHTNDLJHOHA +BQZUFJRGUHBRHU +BQZUFJRGUHBRHU +BQZUFJRGUHBRHU +KOQGQTKIRACNHX +KOQGQTKIRACNHX +KOQGQTKIRACNHX +FPLFANYCOZLPBH +FPLFANYCOZLPBH +FPLFANYCOZLPBH +FPLFANYCOZLPBH +FPLFANYCOZLPBH +FPLFANYCOZLPBH +LZZGQZWYUIVYME +LZZGQZWYUIVYME +LZZGQZWYUIVYME +WXWDACIXWWGWCT +WXWDACIXWWGWCT +WXWDACIXWWGWCT +GNZDDHNPMBWAEJ +GNZDDHNPMBWAEJ +GNZDDHNPMBWAEJ +LYPQODXRAULGTN +LYPQODXRAULGTN +LYPQODXRAULGTN +CFWMSAZVDHMJPT +CFWMSAZVDHMJPT +CFWMSAZVDHMJPT +QRBDELMREOJIET +IBIVMVYONZXLHC +IBIVMVYONZXLHC +NMLVBKGEAXGDTR +NMLVBKGEAXGDTR +NMLVBKGEAXGDTR +ZCHCOZGPCJCFBE +ZCHCOZGPCJCFBE +ZCHCOZGPCJCFBE +MRPIDCRYJNRTGN +MRPIDCRYJNRTGN +MRPIDCRYJNRTGN +DTUWFZRHABKSJS +DTUWFZRHABKSJS +DTUWFZRHABKSJS +KZWOOMIKFXXEQN +KZWOOMIKFXXEQN +KZWOOMIKFXXEQN +NBOLUQBDLRPVOJ +NBOLUQBDLRPVOJ +NBOLUQBDLRPVOJ +DEHQHQOICKXWRU +DEHQHQOICKXWRU +DEHQHQOICKXWRU +KUQNYAUTIWQAKY +KUQNYAUTIWQAKY +KUQNYAUTIWQAKY +YKNONUSNUKSRRK +YKNONUSNUKSRRK +CLWGTYOBSQOXNX +CLWGTYOBSQOXNX +CLWGTYOBSQOXNX +WIHNBMLYQODCAE +WIHNBMLYQODCAE +WIHNBMLYQODCAE +ZPIWPHIWJALTPM +OLOODKZKZNQJBQ +OLOODKZKZNQJBQ +OLOODKZKZNQJBQ +QPMRZAFWASKQTL +QPMRZAFWASKQTL +QPMRZAFWASKQTL +JBUYSNLAPQQNNN +JBUYSNLAPQQNNN +JBUYSNLAPQQNNN +KRZPFTLDCGJNJC +KRZPFTLDCGJNJC +KRZPFTLDCGJNJC +WSSMPNRMSPVDCQ +WSSMPNRMSPVDCQ +WSSMPNRMSPVDCQ +RTAMYLUVQBORGH +RTAMYLUVQBORGH +RTAMYLUVQBORGH +RTAMYLUVQBORGH +VPDXSKSEJKNOIA +VPDXSKSEJKNOIA +VPDXSKSEJKNOIA +GXACZGNQWBODIY +GXACZGNQWBODIY +GXACZGNQWBODIY +RSXXQJWAOKBYAV +RSXXQJWAOKBYAV +RSXXQJWAOKBYAV +FJNYDDDTOGHGJL +FJNYDDDTOGHGJL +FJNYDDDTOGHGJL +FJNYDDDTOGHGJL +REYNGWDSCVNUSV +REYNGWDSCVNUSV +REYNGWDSCVNUSV +KWODVIMTXBCMSS +KWODVIMTXBCMSS +KWODVIMTXBCMSS +CUCBOGIMNBMRTH +CUCBOGIMNBMRTH +CUCBOGIMNBMRTH +ORQFGHOGKYZHFZ +ORQFGHOGKYZHFZ +ORQFGHOGKYZHFZ +AGFZQVNCSIRXFF +AGFZQVNCSIRXFF +AGFZQVNCSIRXFF +IGCUKXKGPLNRAV +IGCUKXKGPLNRAV +IGCUKXKGPLNRAV +DJBHEHSDXUGBOK +DJBHEHSDXUGBOK +DJBHEHSDXUGBOK +SYDYMJUELSZIBJ +SYDYMJUELSZIBJ +SYDYMJUELSZIBJ +PHSNZCSSBGDUHP +PHSNZCSSBGDUHP +PHSNZCSSBGDUHP +NGEUESSCQPDDJI +NGEUESSCQPDDJI +NGEUESSCQPDDJI +RLQXCTLMQNEUTN +RLQXCTLMQNEUTN +RLQXCTLMQNEUTN +SZSGWASTQMDYQG +SZSGWASTQMDYQG +SZSGWASTQMDYQG +LGMOXZJGKVUXSN +LGMOXZJGKVUXSN +LGMOXZJGKVUXSN +MODYLKBBIKKNGW +MODYLKBBIKKNGW +MODYLKBBIKKNGW +BNMUVPXAQIHTGJ +BNMUVPXAQIHTGJ +BNMUVPXAQIHTGJ +FHMDGAHIAMZTQB +FHMDGAHIAMZTQB +RJMOLQXQAHVQER +RJMOLQXQAHVQER +RJMOLQXQAHVQER +CNNBJRQWIRDJNO +CNNBJRQWIRDJNO +CNNBJRQWIRDJNO +HSJHPWVNBPKEQJ +HSJHPWVNBPKEQJ +HSJHPWVNBPKEQJ +NPEPQPOHKRIFOF +NPEPQPOHKRIFOF +NPEPQPOHKRIFOF +NPEPQPOHKRIFOF +NPEPQPOHKRIFOF +NPEPQPOHKRIFOF +WDLFLFHJALLNTM +WDLFLFHJALLNTM +WDLFLFHJALLNTM +GZRFYVHDBWOCFN +GZRFYVHDBWOCFN +GZRFYVHDBWOCFN +QHNSIWIWWZBZAG +QHNSIWIWWZBZAG +QHNSIWIWWZBZAG +INRLHFKDNIQTDZ +INRLHFKDNIQTDZ +INRLHFKDNIQTDZ +QPMKHBTUBMTGLL +QPMKHBTUBMTGLL +QPMKHBTUBMTGLL +TYDURSYUFVLTAD +TYDURSYUFVLTAD +TYDURSYUFVLTAD +OEQCROFRXIZUBQ +OEQCROFRXIZUBQ +OEQCROFRXIZUBQ +OEQCROFRXIZUBQ +AEYRDFZNOFKAPT +AEYRDFZNOFKAPT +AEYRDFZNOFKAPT +GCIQQRFPIWJOPN +GCIQQRFPIWJOPN +GCIQQRFPIWJOPN +BPCZLSQDPOOZQW +BPCZLSQDPOOZQW +BPCZLSQDPOOZQW +RJAVNUXZLAZRHU +RJAVNUXZLAZRHU +RJAVNUXZLAZRHU +GTLRXKVYTAAWBY +GTLRXKVYTAAWBY +GTLRXKVYTAAWBY +GTLRXKVYTAAWBY +GCKXATWVQDPCKS +GCKXATWVQDPCKS +HIQAKMCGZNZWOI +HIQAKMCGZNZWOI +SIJPDJRBUPYIHN +SIJPDJRBUPYIHN +SIJPDJRBUPYIHN +SIJPDJRBUPYIHN +MRWFANPPQGDMEG +MRWFANPPQGDMEG +MRWFANPPQGDMEG +VSZVQVNTYDWDHD +VSZVQVNTYDWDHD +VSZVQVNTYDWDHD +LIEXYTMTOHFMAJ +LIEXYTMTOHFMAJ +LIEXYTMTOHFMAJ +OEBBUJKAYJWYRE +OEBBUJKAYJWYRE +OEBBUJKAYJWYRE +GULLPNCZTWQLMZ +GULLPNCZTWQLMZ +GULLPNCZTWQLMZ +XOJQHFNZSWWSDF +XOJQHFNZSWWSDF +XOJQHFNZSWWSDF +RSOHLJRCYXVYJT +RSOHLJRCYXVYJT +RSOHLJRCYXVYJT +NFGAASBHRFWLHJ +NFGAASBHRFWLHJ +NFGAASBHRFWLHJ +RECCTAMRDZXMTL +RECCTAMRDZXMTL +RECCTAMRDZXMTL +UWGSHLLJIYRTIS +UWGSHLLJIYRTIS +XJOLEDYHJUZKPW +XJOLEDYHJUZKPW +XJOLEDYHJUZKPW +NIBFOBBHNQRMAL +NIBFOBBHNQRMAL +NIBFOBBHNQRMAL +KZDHRXDFCHHFEJ +KZDHRXDFCHHFEJ +BPECWRMBMKWBAJ +BPECWRMBMKWBAJ +BPECWRMBMKWBAJ +VZZIMXZKTDQZQH +VZZIMXZKTDQZQH +VZZIMXZKTDQZQH +CENWFDYMJUVINS +CENWFDYMJUVINS +CENWFDYMJUVINS +SFSBCXRYJTZJKA +SFSBCXRYJTZJKA +SFSBCXRYJTZJKA +TXEWOLCYUUNWKG +TXEWOLCYUUNWKG +TXEWOLCYUUNWKG +HFFDIBUCHNLZJM +HFFDIBUCHNLZJM +HFFDIBUCHNLZJM +AJGDNYSVDJOAMN +AJGDNYSVDJOAMN +AJGDNYSVDJOAMN +WBTYDHYAYZZTON +WBTYDHYAYZZTON +WBTYDHYAYZZTON +XGSYZHYSSXWHPZ +XGSYZHYSSXWHPZ +XGSYZHYSSXWHPZ +FFPXPXOAFQCNBS +FFPXPXOAFQCNBS +FFPXPXOAFQCNBS +ZFIOCHSHJADREN +ZFIOCHSHJADREN +ZFIOCHSHJADREN +QVCWRPOYGFUFBW +QVCWRPOYGFUFBW +QVCWRPOYGFUFBW +XXKDYNBPJAAWFQ +XXKDYNBPJAAWFQ +XXKDYNBPJAAWFQ +REUIHHUGJSYWNC +REUIHHUGJSYWNC +REUIHHUGJSYWNC +REUIHHUGJSYWNC +KSIMNTLSPRRBQO +OKNIDEJOZOVOIC +OKNIDEJOZOVOIC +OKNIDEJOZOVOIC +KAXNVBDGEYOBFH +KAXNVBDGEYOBFH +KAXNVBDGEYOBFH +WYWUYCOEGXENEV +WYWUYCOEGXENEV +WYWUYCOEGXENEV +NLXZWFXAQKBCRM +NLXZWFXAQKBCRM +NLXZWFXAQKBCRM +FCXMWYDQAGGPMC +FCXMWYDQAGGPMC +FCXMWYDQAGGPMC +VYUQBFNZARWWAR +VYUQBFNZARWWAR +VYUQBFNZARWWAR +FLKZIRMYZDJTDT +FLKZIRMYZDJTDT +FLKZIRMYZDJTDT +ZKNVWCKDGMFLHL +ZKNVWCKDGMFLHL +ZKNVWCKDGMFLHL +RYQQQRXISIWDOS +RYQQQRXISIWDOS +RYQQQRXISIWDOS +BMGYHDKVXDBYCJ +BMGYHDKVXDBYCJ +BMGYHDKVXDBYCJ +QPIUXFOPYHVILO +QPIUXFOPYHVILO +QPIUXFOPYHVILO +RFAJSNFWGQAIEA +RFAJSNFWGQAIEA +OHQIYRVZBHBOAQ +OHQIYRVZBHBOAQ +OHQIYRVZBHBOAQ +CMTZJQGPDXJDSP +CMTZJQGPDXJDSP +CMTZJQGPDXJDSP +HLVNITAIGASJBA +HLVNITAIGASJBA +HLVNITAIGASJBA +TXWIBGFMTYCNCO +TXWIBGFMTYCNCO +TXWIBGFMTYCNCO +NWWTTXCMEVQJOM +NWWTTXCMEVQJOM +NWWTTXCMEVQJOM +SYIZRULNQCQFAK +SYIZRULNQCQFAK +SYIZRULNQCQFAK +FLXVJMMEHYRKEO +FLXVJMMEHYRKEO +FLXVJMMEHYRKEO +WADDEDCVBQJPJA +WADDEDCVBQJPJA +WADDEDCVBQJPJA +PSAZQNYMZZFYOE +PSAZQNYMZZFYOE +KZSOIBBYJGGXFP +KZSOIBBYJGGXFP +KZSOIBBYJGGXFP +QTMAWTCQLVAXMH +QTMAWTCQLVAXMH +QTMAWTCQLVAXMH +ANZJEBIOQWYXTB +ANZJEBIOQWYXTB +ANZJEBIOQWYXTB +ANZJEBIOQWYXTB +XXPPXBPNHSWHBK +XXPPXBPNHSWHBK +XXPPXBPNHSWHBK +OBOBTWSYNLJREW +OBOBTWSYNLJREW +OBOBTWSYNLJREW +INTQGEUKKBFGGD +INTQGEUKKBFGGD +INTQGEUKKBFGGD +VDZAINKALCMTDU +VDZAINKALCMTDU +XWXUWFQDVHJOKH +XWXUWFQDVHJOKH +XWXUWFQDVHJOKH +YWPQBKYMCDIHPR +YWPQBKYMCDIHPR +YWPQBKYMCDIHPR +KGKIDOJJZINCKQ +KGKIDOJJZINCKQ +KGKIDOJJZINCKQ +QNKZNCBEUNCRNR +QNKZNCBEUNCRNR +QNKZNCBEUNCRNR +VOBWGLLSVCQQNQ +VOBWGLLSVCQQNQ +VOBWGLLSVCQQNQ +FDYQBZGGEKSXPH +FDYQBZGGEKSXPH +MHHFXMZMCYWCJQ +MHHFXMZMCYWCJQ +MSRFHWFITNYMTJ +MSRFHWFITNYMTJ +MSRFHWFITNYMTJ +GOTGFNMZIUHJAR +GOTGFNMZIUHJAR +GOTGFNMZIUHJAR +YTQBPGYOOMNTTQ +YTQBPGYOOMNTTQ +YTQBPGYOOMNTTQ +OEXRZKHGVIVSEM +OEXRZKHGVIVSEM +OEXRZKHGVIVSEM +NZQDSIFUFRNVJQ +NZQDSIFUFRNVJQ +JVAJLQYHBIGVAI +WUWPXFHUKVCFOX +WUWPXFHUKVCFOX +NDMWRVJGOOVCTJ +NDMWRVJGOOVCTJ +NDMWRVJGOOVCTJ +PBMQTGVBSHLVPP +PBMQTGVBSHLVPP +PBMQTGVBSHLVPP +DRIWADPDOJTMAM +DRIWADPDOJTMAM +DRIWADPDOJTMAM +UMQLSZAVFYFBNR +UMQLSZAVFYFBNR +UMQLSZAVFYFBNR +UBVHITAVWXTSJQ +UBVHITAVWXTSJQ +UBVHITAVWXTSJQ +GRFJGCXGGOSFQN +GRFJGCXGGOSFQN +GRFJGCXGGOSFQN +WJWSRKRPSHRAMH +WJWSRKRPSHRAMH +WJWSRKRPSHRAMH +JJEFTTSOKPYQKH +JJEFTTSOKPYQKH +JJEFTTSOKPYQKH +MYSAJCSCHYHCRL +MYSAJCSCHYHCRL +MYSAJCSCHYHCRL +OAXNHADLFJKDQA +OAXNHADLFJKDQA +OAXNHADLFJKDQA +IPLIFRDWZSFUGS +IPLIFRDWZSFUGS +IPLIFRDWZSFUGS +LJHPQXDWEJPJLK +LJHPQXDWEJPJLK +LJHPQXDWEJPJLK +SXXPZZUCGPHEGU +SXXPZZUCGPHEGU +SXXPZZUCGPHEGU +BVZREBSXPAIWAR +BVZREBSXPAIWAR +BVZREBSXPAIWAR +IOBCYLVRHSYTMG +IOBCYLVRHSYTMG +IOBCYLVRHSYTMG +DMXGFDSGVSISBY +DMXGFDSGVSISBY +DMXGFDSGVSISBY +WCSZNZFRPAUIAK +WCSZNZFRPAUIAK +WCSZNZFRPAUIAK +TUGUXQNVLOXFJW +TUGUXQNVLOXFJW +TUGUXQNVLOXFJW +TUGUXQNVLOXFJW +VJQKCZDDMUESAS +VJQKCZDDMUESAS +VJQKCZDDMUESAS +VJQKCZDDMUESAS +LPPRPUJPNUYIKH +LPPRPUJPNUYIKH +ZOBYBACEALCILX +ZOBYBACEALCILX +ZOBYBACEALCILX +HPKJUEHPWQJMMV +HPKJUEHPWQJMMV +HPKJUEHPWQJMMV +NNYVHGAEKIMTND +XKWRTBPCXCDBGB +XKWRTBPCXCDBGB +XKWRTBPCXCDBGB +XKWRTBPCXCDBGB +XKWRTBPCXCDBGB +XKWRTBPCXCDBGB +UVHNYMJJPWUOMI +UVHNYMJJPWUOMI +UVHNYMJJPWUOMI +HWGRHMFJDDVHNR +HWGRHMFJDDVHNR +HWGRHMFJDDVHNR +WLCDWHOAVKKKDI +WLCDWHOAVKKKDI +AFSMXYOKHHCPRN +AFSMXYOKHHCPRN +QHRTXGYTBWZWSI +QHRTXGYTBWZWSI +QHRTXGYTBWZWSI +IZCKGGORKVYMHP +IZCKGGORKVYMHP +IZCKGGORKVYMHP +YJUIAPDBEOQTNI +YJUIAPDBEOQTNI +YJUIAPDBEOQTNI +CCBWMFSTIAELBA +CCBWMFSTIAELBA +CCBWMFSTIAELBA +XWLUFWCCZZDAJW +XWLUFWCCZZDAJW +XWLUFWCCZZDAJW +SGTHSTZLBWKEHP +SGTHSTZLBWKEHP +SGTHSTZLBWKEHP +QTCNJMZXJDIMMW +QTCNJMZXJDIMMW +QTCNJMZXJDIMMW +AKJIOQUPRGBOEJ +AKJIOQUPRGBOEJ +AKJIOQUPRGBOEJ +BZDKDNUAGULJCD +BZDKDNUAGULJCD +BZDKDNUAGULJCD +VCABOOHNOGZFTB +VCABOOHNOGZFTB +VCABOOHNOGZFTB +ZLBSIZVCJRBSLJ +ZLBSIZVCJRBSLJ +ZLBSIZVCJRBSLJ +FPFKLXKJCDKUDR +WWMUCNBEECXFOK +WWMUCNBEECXFOK +WWMUCNBEECXFOK +RXYBIHOCQLKACU +RXYBIHOCQLKACU +RXYBIHOCQLKACU +HMIPAPXYPBVZIW +HMIPAPXYPBVZIW +HMIPAPXYPBVZIW +UDGSCPSIPPVQKX +UDGSCPSIPPVQKX +UDGSCPSIPPVQKX +UOXFEMDZVVIUHG +UOXFEMDZVVIUHG +UOXFEMDZVVIUHG +DNJLSGNTFNCKMH +DNJLSGNTFNCKMH +DNJLSGNTFNCKMH +OJUNYTBJAJOBBU +OJUNYTBJAJOBBU +VECBWTIIANAIQM +VECBWTIIANAIQM +VECBWTIIANAIQM +ONBWYZGZQILEDQ +ONBWYZGZQILEDQ +ONBWYZGZQILEDQ +MJMJSSRREHEGIQ +MJMJSSRREHEGIQ +MJMJSSRREHEGIQ +BZRCURRUEUQWOD +BZRCURRUEUQWOD +BZRCURRUEUQWOD +REAIKOZBEKJAMS +REAIKOZBEKJAMS +REAIKOZBEKJAMS +BEFNRRBFXFFBDN +BEFNRRBFXFFBDN +BEFNRRBFXFFBDN +GMVHRDROQSLMAL +GMVHRDROQSLMAL +GMVHRDROQSLMAL +HRUUAOBJZBVKNP +HRUUAOBJZBVKNP +HRUUAOBJZBVKNP +WYFYIMNVLLJBSV +WYFYIMNVLLJBSV +WYFYIMNVLLJBSV +QWMYLPKXJLBOLP +QWMYLPKXJLBOLP +QWMYLPKXJLBOLP +YXUAGQAGCSJGFK +YXUAGQAGCSJGFK +YXUAGQAGCSJGFK +BYLKNPUDKAHCEY +BYLKNPUDKAHCEY +BYLKNPUDKAHCEY +KDMHOWORNWVONM +KDMHOWORNWVONM +KDMHOWORNWVONM +GHFSXYKSTWTNHL +GHFSXYKSTWTNHL +GHFSXYKSTWTNHL +HSHRFFFZTGESCG +HSHRFFFZTGESCG +HSHRFFFZTGESCG +SANVSVFLLSZATJ +SANVSVFLLSZATJ +SANVSVFLLSZATJ +QAXNTVZEHKCCAG +QAXNTVZEHKCCAG +QAXNTVZEHKCCAG +KFZUKRIIYKNSCD +KFZUKRIIYKNSCD +VGWQLZSDXUPRIN +VGWQLZSDXUPRIN +VGWQLZSDXUPRIN +QPUNXBZPYVPLNN +QPUNXBZPYVPLNN +MAEFWHREHKLMAG +MAEFWHREHKLMAG +MAEFWHREHKLMAG +VAMIFDFMQWDUPS +VAMIFDFMQWDUPS +VAMIFDFMQWDUPS +LRVZJWNFOAJVOH +LRVZJWNFOAJVOH +LRVZJWNFOAJVOH +YBLVCFLGRKUQIC +YBLVCFLGRKUQIC +YBLVCFLGRKUQIC +YBLVCFLGRKUQIC +YBLVCFLGRKUQIC +YBLVCFLGRKUQIC +VBZOUYVFGWKABU +VBZOUYVFGWKABU +VBZOUYVFGWKABU +HKDGPPMPQLGNPW +HKDGPPMPQLGNPW +HKDGPPMPQLGNPW +RWEFQCTWRJNPCK +RWEFQCTWRJNPCK +RWEFQCTWRJNPCK +JQXBITDPNOSNFH +JQXBITDPNOSNFH +JQXBITDPNOSNFH +JQXBITDPNOSNFH +CRXZHIVYFWAKAR +CRXZHIVYFWAKAR +CRXZHIVYFWAKAR +AUVGBBXFZLPNQT +AUVGBBXFZLPNQT +AUVGBBXFZLPNQT +JAGLTWFRNXPOBF +JAGLTWFRNXPOBF +JAGLTWFRNXPOBF +YRQAAFSLEDBOMM +YRQAAFSLEDBOMM +YRQAAFSLEDBOMM +JUAQQVMXHKMMNL +JUAQQVMXHKMMNL +JUAQQVMXHKMMNL +VEJMFGKSORFHJL +VEJMFGKSORFHJL +VEJMFGKSORFHJL +NTVQGIQRXWIFGO +NTVQGIQRXWIFGO +NTVQGIQRXWIFGO +CWZRACDIDASDPP +CWZRACDIDASDPP +CWZRACDIDASDPP +HHJPKVIAWUTEHX +HHJPKVIAWUTEHX +HHJPKVIAWUTEHX +VMRSSLNAYAZUQW +VMRSSLNAYAZUQW +VMRSSLNAYAZUQW +VEHORCUNEBEXNN +VEHORCUNEBEXNN +VEHORCUNEBEXNN +SVEITPQNCDXZDC +SVEITPQNCDXZDC +SVEITPQNCDXZDC +FZAIGGDMYNJQRZ +FZAIGGDMYNJQRZ +FZAIGGDMYNJQRZ +ZJSATCKSMHAMCX +ZJSATCKSMHAMCX +WVVOKTRHKOJAHU +WVVOKTRHKOJAHU +WVVOKTRHKOJAHU +ODZSGOYHVGISHZ +ODZSGOYHVGISHZ +ODZSGOYHVGISHZ +KDYVVSGBDZYRSX +KDYVVSGBDZYRSX +KDYVVSGBDZYRSX +CYJWZRFEBNSJKD +CYJWZRFEBNSJKD +CYJWZRFEBNSJKD +QPRFPNXSPLHEGF +QPRFPNXSPLHEGF +QPRFPNXSPLHEGF +XPOOSJNLSWFSSY +XPOOSJNLSWFSSY +XPOOSJNLSWFSSY +KJCMHWUVQPPPCG +TXVKGHXLXODMEL +TXVKGHXLXODMEL +TXVKGHXLXODMEL +GGOWKGWDVSXOHY +ISKFJUFXLZRJSF +ISKFJUFXLZRJSF +ISKFJUFXLZRJSF +SXBBJBBFQDMDCF +SXBBJBBFQDMDCF +SXBBJBBFQDMDCF +IQGZOUDZZCSPEM +IQGZOUDZZCSPEM +IQGZOUDZZCSPEM +ZHRFEFSAGNFATC +ZHRFEFSAGNFATC +ZHRFEFSAGNFATC +NLPOHPJVDDEGHU +NLPOHPJVDDEGHU +NLPOHPJVDDEGHU +AFYNADDZULBEJA +AFYNADDZULBEJA +AFYNADDZULBEJA +HHFJDQMSKKDAOF +HHFJDQMSKKDAOF +HHFJDQMSKKDAOF +AHYPTBHDWRIMOE +AHYPTBHDWRIMOE +AHYPTBHDWRIMOE +VDJPWUIERGLWRZ +PUZVGQLXGKECJD +PUZVGQLXGKECJD +QZHDWPBISYOLPT +QZHDWPBISYOLPT +QZHDWPBISYOLPT +YDAIKMGKBVCHCZ +YDAIKMGKBVCHCZ +YDAIKMGKBVCHCZ +DEWAZFATOBSVFH +DEWAZFATOBSVFH +DEWAZFATOBSVFH +UEPZFYVUMGXXSH +UEPZFYVUMGXXSH +UEPZFYVUMGXXSH +NKUXAWHMHIKCBR +NKUXAWHMHIKCBR +NKUXAWHMHIKCBR +CIUVLAOKVYFLDP +CIUVLAOKVYFLDP +CIUVLAOKVYFLDP +JUEYZSRDJXQDCM +JUEYZSRDJXQDCM +JUEYZSRDJXQDCM +FWKFUJKFJMIJDX +WRHIMNCCIYESTG +WRHIMNCCIYESTG +WRHIMNCCIYESTG +FLBJCWHRQGAGLW +FLBJCWHRQGAGLW +FLBJCWHRQGAGLW +JYINWGWHVBSDMH +JYINWGWHVBSDMH +JYINWGWHVBSDMH +HRKPPQPRBJHNNB +HRKPPQPRBJHNNB +HRKPPQPRBJHNNB +AKFKKGXWZMLHJB +AKFKKGXWZMLHJB +AKFKKGXWZMLHJB +AKFKKGXWZMLHJB +ALIUOMZWLHSXSX +ALIUOMZWLHSXSX +ALIUOMZWLHSXSX +WNTGEKYUEOUZMM +WNTGEKYUEOUZMM +WNTGEKYUEOUZMM +GZBPLGISVPOMMA +GZBPLGISVPOMMA +GZBPLGISVPOMMA +IGORBTKANPWKRU +IGORBTKANPWKRU +IGORBTKANPWKRU +IGPSCQDNVKUGLW +IGPSCQDNVKUGLW +IGPSCQDNVKUGLW +GLUYYNOOUCCIBY +GLUYYNOOUCCIBY +GLUYYNOOUCCIBY +FJXPTCWXVYRNOJ +FJXPTCWXVYRNOJ +FJXPTCWXVYRNOJ +FJXPTCWXVYRNOJ +KRBPWFNYXUYUKN +KRBPWFNYXUYUKN +KRBPWFNYXUYUKN +QEDVLODTOQLLGO +QEDVLODTOQLLGO +QEDVLODTOQLLGO +DNAPGNWGOOJPFW +DNAPGNWGOOJPFW +DNAPGNWGOOJPFW +WSAACYQCLKBKNO +WSAACYQCLKBKNO +HERJIHJPRKFQIK +HERJIHJPRKFQIK +HERJIHJPRKFQIK +UUDKPQFCUQYSAV +UUDKPQFCUQYSAV +UUDKPQFCUQYSAV +ISBRJJVZSHATOQ +ISBRJJVZSHATOQ +ISBRJJVZSHATOQ +WZZXFOHWTQFBJV +WZZXFOHWTQFBJV +WZZXFOHWTQFBJV +HZUUYJQZVYQXEP +HZUUYJQZVYQXEP +HZUUYJQZVYQXEP +AOIGXXKNFXKOJY +AOIGXXKNFXKOJY +AOIGXXKNFXKOJY +SOMABIBERHUHJY +SOMABIBERHUHJY +SOMABIBERHUHJY +OZBOESGNDSVMDK +OZBOESGNDSVMDK +OZBOESGNDSVMDK +BDVDXNYOCBUMNP +BDVDXNYOCBUMNP +BDVDXNYOCBUMNP +PYRSQORHSAQHOW +PYRSQORHSAQHOW +PYRSQORHSAQHOW +SWWRURAYYBNSQC +SWWRURAYYBNSQC +SWWRURAYYBNSQC +RCZJXCXNYGHNSR +RCZJXCXNYGHNSR +RCZJXCXNYGHNSR +GIDARSLNULHKMM +GIDARSLNULHKMM +GIDARSLNULHKMM +AIFQGBJZIGNMCC +AIFQGBJZIGNMCC +AIFQGBJZIGNMCC +RCZNIXDPGHEFHT +RCZNIXDPGHEFHT +RCZNIXDPGHEFHT +JQGJUCXXEPKQPA +JQGJUCXXEPKQPA +JQGJUCXXEPKQPA +MPMVEXAMZQNNFB +MPMVEXAMZQNNFB +MPMVEXAMZQNNFB +XTQUUBGVZFZJDJ +XTQUUBGVZFZJDJ +XTQUUBGVZFZJDJ +XTQUUBGVZFZJDJ +LESXOEOAJVCZPN +LESXOEOAJVCZPN +LESXOEOAJVCZPN +LDCYEHJJXQKZOX +LDCYEHJJXQKZOX +FCUOACZLFYZGMV +FCUOACZLFYZGMV +FCUOACZLFYZGMV +BFFLMQVGWQTMLW +BFFLMQVGWQTMLW +BFFLMQVGWQTMLW +WXCHSJFMWZVWRG +WXCHSJFMWZVWRG +WXCHSJFMWZVWRG +BOJTYVQFSDEEIX +BOJTYVQFSDEEIX +BOJTYVQFSDEEIX +UOTAKPNQGXSUSO +UOTAKPNQGXSUSO +UOTAKPNQGXSUSO +VTKQAQNKUHUXQD +VTKQAQNKUHUXQD +VTKQAQNKUHUXQD +NZUZWIIVPRUDEP +NZUZWIIVPRUDEP +NZUZWIIVPRUDEP +IHGVAVLSTPCCJP +MDHDYQOUVRWAJV +MDHDYQOUVRWAJV +MDHDYQOUVRWAJV +MDHDYQOUVRWAJV +NJTPDXHAQWFPIG +NJTPDXHAQWFPIG +NJTPDXHAQWFPIG +CBTJCYRGMYNXKS +CBTJCYRGMYNXKS +BMQJDKFGXQHBRY +BMQJDKFGXQHBRY +BMQJDKFGXQHBRY +OKNJTFQGVXJHLX +OKNJTFQGVXJHLX +OKNJTFQGVXJHLX +MQZDXMLMLFLGNV +MQZDXMLMLFLGNV +MQZDXMLMLFLGNV +XQWDVRZOQNAAMT +XQWDVRZOQNAAMT +XQWDVRZOQNAAMT +AHDMXNQQAYOPPT +AHDMXNQQAYOPPT +AHDMXNQQAYOPPT +HILPUJGAZFYSKO +HILPUJGAZFYSKO +NIGFVSJQARITLT +NIGFVSJQARITLT +NIGFVSJQARITLT +PJLKCQDPPNDPMJ +PJLKCQDPPNDPMJ +PJLKCQDPPNDPMJ +QNKKPRWLJACOML +QNKKPRWLJACOML +QNKKPRWLJACOML +QCSDMDBEHPDVGE +QCSDMDBEHPDVGE +QCSDMDBEHPDVGE +RPDLEFUEGJMHRF +RPDLEFUEGJMHRF +RPDLEFUEGJMHRF +NAAAINROMKRIPK +NAAAINROMKRIPK +SIMYSVHBWCLMHU +SIMYSVHBWCLMHU +SIMYSVHBWCLMHU +WRHAVHZMSIQVQZ +WRHAVHZMSIQVQZ +RTRSMTYIYSLLOY +RTRSMTYIYSLLOY +RTRSMTYIYSLLOY +MWCNNBLPGBAQKS +MWCNNBLPGBAQKS +MWCNNBLPGBAQKS +HJWLJNBZVZDLAQ +HJWLJNBZVZDLAQ +HJWLJNBZVZDLAQ +HJWLJNBZVZDLAQ +HJWLJNBZVZDLAQ +HJWLJNBZVZDLAQ +NOEFYEQSZJCHKO +NOEFYEQSZJCHKO +NOEFYEQSZJCHKO +RGZNJUVMQCOEOI +RGZNJUVMQCOEOI +RGZNJUVMQCOEOI +VPTBFSXMTPXQDD +VPTBFSXMTPXQDD +KQDBVHKNIYROHU +KQDBVHKNIYROHU +HZHJAKQSIMEKGL +HZHJAKQSIMEKGL +HZHJAKQSIMEKGL +MNCMHLNKCXOBGL +MNCMHLNKCXOBGL +MNCMHLNKCXOBGL +LDHBXBLDGZQULU +LDHBXBLDGZQULU +WXIABESEKMWWGB +WXIABESEKMWWGB +WXIABESEKMWWGB +LXSWVSGUZDKXIK +LXSWVSGUZDKXIK +LXSWVSGUZDKXIK +LYHQLPGCWAFBGC +LYHQLPGCWAFBGC +LYHQLPGCWAFBGC +QTLBOFPZHOJBJP +QTLBOFPZHOJBJP +QTLBOFPZHOJBJP +FZKLZMTZBCWSGG +FZKLZMTZBCWSGG +FZKLZMTZBCWSGG +XVKYCCCVXPODLM +XVKYCCCVXPODLM +XVKYCCCVXPODLM +NVJJJOKFULGKCZ +NVJJJOKFULGKCZ +NVJJJOKFULGKCZ +NPUPMXODSSPEHK +NPUPMXODSSPEHK +NPUPMXODSSPEHK +WQYSGJYENRTGBN +WQYSGJYENRTGBN +WQYSGJYENRTGBN +KHLXUKMFHVLTKT +KHLXUKMFHVLTKT +KHLXUKMFHVLTKT +NPBOEBYKTZRFHL +NPBOEBYKTZRFHL +NPBOEBYKTZRFHL +NPBOEBYKTZRFHL +NPBOEBYKTZRFHL +NPBOEBYKTZRFHL +IOXXFLYKESGCME +IOXXFLYKESGCME +IOXXFLYKESGCME +RSRBVFMXKKCLSN +RSRBVFMXKKCLSN +RSRBVFMXKKCLSN +WJHSZMXTCUUQMZ +WJHSZMXTCUUQMZ +WJHSZMXTCUUQMZ +PLISOUAGIKEZAK +PLISOUAGIKEZAK +PLISOUAGIKEZAK +IGHNZEMDJFNRHM +IGHNZEMDJFNRHM +MCJYRBZABBLPJZ +MCJYRBZABBLPJZ +MCJYRBZABBLPJZ +PTXGVMJVLSZIIH +PTXGVMJVLSZIIH +PTXGVMJVLSZIIH +KXQCJZMINVEAEU +KXQCJZMINVEAEU +KXQCJZMINVEAEU +USXVVMGRBSKLRD +USXVVMGRBSKLRD +USXVVMGRBSKLRD +FQAXDSVNYVVQSE +OOIQYRXYAWVYED +NDGFTURFCRKBCT +NDGFTURFCRKBCT +NDGFTURFCRKBCT +TZEXZGYAKWNMMC +TZEXZGYAKWNMMC +TZEXZGYAKWNMMC +PYXRQSYDODFUOC +PYXRQSYDODFUOC +PGKCAGDETWDKBO +PGKCAGDETWDKBO +PGKCAGDETWDKBO +CBVLAZRZVZETGE +CBVLAZRZVZETGE +CBVLAZRZVZETGE +QAJLWFSTRCARER +QAJLWFSTRCARER +QAJLWFSTRCARER +SUCGWBJSOQUFIC +SUCGWBJSOQUFIC +SUCGWBJSOQUFIC +OWFLADWRSCINST +MFFUYEOGICAKCK +MFFUYEOGICAKCK +MFFUYEOGICAKCK +SXFQBUKKIKMRPM +SXFQBUKKIKMRPM +SXFQBUKKIKMRPM +SXFQBUKKIKMRPM +SXFQBUKKIKMRPM +SXFQBUKKIKMRPM +JMSUDQYHPSNBSN +JMSUDQYHPSNBSN +JMSUDQYHPSNBSN +JMSUDQYHPSNBSN +GLNDKUTXHKPGRJ +GLNDKUTXHKPGRJ +GLNDKUTXHKPGRJ +BQQYXPHRXIZMDM +BQQYXPHRXIZMDM +BQQYXPHRXIZMDM +BQQYXPHRXIZMDM +BQQYXPHRXIZMDM +BQQYXPHRXIZMDM +DIVDSYCVJBWLOB +QQGWEXFLMJGCAL +QQGWEXFLMJGCAL +QQGWEXFLMJGCAL +INZLPWNLEIAYQY +INZLPWNLEIAYQY +INZLPWNLEIAYQY +CQOJHAJWCDJEAT +CQOJHAJWCDJEAT +CQOJHAJWCDJEAT +CQOJHAJWCDJEAT +YOTYOLAQLQYDTO +YOTYOLAQLQYDTO +YOTYOLAQLQYDTO +UILCZGGPKWRGOK +UILCZGGPKWRGOK +UILCZGGPKWRGOK +AWASFDWDSZUCGT +AWASFDWDSZUCGT +AWASFDWDSZUCGT +ATZKNJQPPLSNBB +ATZKNJQPPLSNBB +ATZKNJQPPLSNBB +XTRLCGPPUHLFCC +XTRLCGPPUHLFCC +XTRLCGPPUHLFCC +VWSXEYZFIVBFPH +VWSXEYZFIVBFPH +VWSXEYZFIVBFPH +OVCPRVKAWVYLAG +OVCPRVKAWVYLAG +OVCPRVKAWVYLAG +CUHMLLWMAHMVCE +CUHMLLWMAHMVCE +CUHMLLWMAHMVCE +UYVGFQDAJKDGJC +UYVGFQDAJKDGJC +UYVGFQDAJKDGJC +MEILBPKNWUNKKU +MEILBPKNWUNKKU +MEILBPKNWUNKKU +UVIVKVYXBQDTPB +UVIVKVYXBQDTPB +UVIVKVYXBQDTPB +SLYTWRPPDRGGNX +SLYTWRPPDRGGNX +SLYTWRPPDRGGNX +ZHSXKDYZIMWDFM +ZHSXKDYZIMWDFM +ZHSXKDYZIMWDFM +BZPSPRCKSLUNLL +CJMMBUSNZYNGGW +CJMMBUSNZYNGGW +CJMMBUSNZYNGGW +IGFATNASWLSOTD +IGFATNASWLSOTD +FAGGPMNNXQGPNB +FAGGPMNNXQGPNB +FAGGPMNNXQGPNB +QZPBQOJGSNLVTJ +ARJXOQQSZXMPMM +ARJXOQQSZXMPMM +ARJXOQQSZXMPMM +NZESAQHLKAOXHO +NZESAQHLKAOXHO +NZESAQHLKAOXHO +IOAIJXCSWQZGKQ +IOAIJXCSWQZGKQ +IOAIJXCSWQZGKQ +ACKRFWQHUQAQFF +ACKRFWQHUQAQFF +ACKRFWQHUQAQFF +HYPYGRQCMMEMON +HYPYGRQCMMEMON +HYPYGRQCMMEMON +DGMWHRQVCCLGHT +DGMWHRQVCCLGHT +DGMWHRQVCCLGHT +ZMTZWGZPGZUCDC +ZMTZWGZPGZUCDC +ZMTZWGZPGZUCDC +BMAZEWULBABYDU +BMAZEWULBABYDU +BMAZEWULBABYDU +BMRBVRCSVFQNPL +BMRBVRCSVFQNPL +BMRBVRCSVFQNPL +ZRDJWNISISVUHP +ZRDJWNISISVUHP +ZRDJWNISISVUHP +WAJVGDRFUDJFMK +WAJVGDRFUDJFMK +WAJVGDRFUDJFMK +PWSWPXVHVGCSDN +PWSWPXVHVGCSDN +PWSWPXVHVGCSDN +UFHFLHRXADHWJT +UFHFLHRXADHWJT +UFHFLHRXADHWJT +ZEVJCZMGXQOULF +ZEVJCZMGXQOULF +ZEVJCZMGXQOULF +RRMMDBMINIMIDG +RRMMDBMINIMIDG +RRMMDBMINIMIDG +SSCHAQRMNSXUGZ +JMXVCIRSULFZLE +DUHNHTWOZHQHFN +AYSDSVIYOAKLFY +AYSDSVIYOAKLFY +AYSDSVIYOAKLFY +DQCPQSBZPWAWPX +DQCPQSBZPWAWPX +DQCPQSBZPWAWPX +DQCPQSBZPWAWPX +DQCPQSBZPWAWPX +DQCPQSBZPWAWPX +DQCPQSBZPWAWPX +AXUQYOMGCAWXKB +AXUQYOMGCAWXKB +AXUQYOMGCAWXKB +GAZAKBFKXVLEDU +GAZAKBFKXVLEDU +GAZAKBFKXVLEDU +UTWOGHZGSPJNDH +UTWOGHZGSPJNDH +UTWOGHZGSPJNDH +AURWZUJIYCYHAH +AURWZUJIYCYHAH +AURWZUJIYCYHAH +ZXPPRPGYRMWKNG +ZXPPRPGYRMWKNG +ZXPPRPGYRMWKNG +XQQGNBCSJMBTIH +XQQGNBCSJMBTIH +XQQGNBCSJMBTIH +LMKAUGIOPZPMFU +LMKAUGIOPZPMFU +LMKAUGIOPZPMFU +VSXZBFZLPFFRFF +VSXZBFZLPFFRFF +VSXZBFZLPFFRFF +MAQUZRJCJTVXHO +JRRSESFMHVLRCX +JRRSESFMHVLRCX +JRRSESFMHVLRCX +KXGSRTPKDUFEGG +KXGSRTPKDUFEGG +KXGSRTPKDUFEGG +CVRNRZPPZIARBS +CVRNRZPPZIARBS +CVRNRZPPZIARBS +RHKSIQREDXACST +RHKSIQREDXACST +RHKSIQREDXACST +QGLATJXOQRCZEY +KNHMEPIOZGNWKQ +KNHMEPIOZGNWKQ +KNHMEPIOZGNWKQ +IXSPMOGEDUGEAW +IXSPMOGEDUGEAW +IXSPMOGEDUGEAW +PZZULHSTTMZVJE +PZZULHSTTMZVJE +PZZULHSTTMZVJE +WRMMNPNZPPOAGF +WRMMNPNZPPOAGF +WRMMNPNZPPOAGF +LMRIVBNSYWNQKU +LMRIVBNSYWNQKU +LMRIVBNSYWNQKU +GFPAMSMSSWZPFE +GFPAMSMSSWZPFE +GFPAMSMSSWZPFE +UHSBKUPXEBIWJA +UHSBKUPXEBIWJA +UHSBKUPXEBIWJA +AJIWENHJCAXTFG +IENQXUHPUAOZMB +IENQXUHPUAOZMB +IENQXUHPUAOZMB +LGEGMRVMGQEHDS +LGEGMRVMGQEHDS +LGEGMRVMGQEHDS +DMZHUZQJEJSATH +DMZHUZQJEJSATH +DMZHUZQJEJSATH +XSZAOTWWOIYVJP +YOGUTBPPMCRVEP +YOGUTBPPMCRVEP +YOGUTBPPMCRVEP +YRGRJSSYXJANTL +YRGRJSSYXJANTL +YRGRJSSYXJANTL +OXWJGHNUUIEMCV +OXWJGHNUUIEMCV +OXWJGHNUUIEMCV +KZAAKKBYGBXDHY +KZAAKKBYGBXDHY +KZAAKKBYGBXDHY +SEHURMBCXDCBHO +SEHURMBCXDCBHO +SEHURMBCXDCBHO +JTQLJKAYXRVMCS +JTQLJKAYXRVMCS +JTQLJKAYXRVMCS +GMUVKSIPHPNWJE +GMUVKSIPHPNWJE +GMUVKSIPHPNWJE +BHUZXDHVVYPFTH +BHUZXDHVVYPFTH +BHUZXDHVVYPFTH +YOQQHHZTAUNAFC +YOQQHHZTAUNAFC +YOQQHHZTAUNAFC +YDVDDHRPQWEMBO +YDVDDHRPQWEMBO +YDVDDHRPQWEMBO +KOVKWTFYWXJUNN +KOVKWTFYWXJUNN +UEKRAIRTUUNEFR +ASGVKQSOPLTQFE +ASGVKQSOPLTQFE +ASGVKQSOPLTQFE +KQADMAMMQSXLAX +KQADMAMMQSXLAX +KQADMAMMQSXLAX +SHRQJBFRQVTRAX +SHRQJBFRQVTRAX +SHRQJBFRQVTRAX +POKVVKOWYGTVKQ +POKVVKOWYGTVKQ +POKVVKOWYGTVKQ +PXSXQABEBGBSFL +PXSXQABEBGBSFL +PXSXQABEBGBSFL +XQVPMQPAYNYUKO +INZXKYDTYNIFAO +INZXKYDTYNIFAO +INZXKYDTYNIFAO +ROULWRMXSWNHGI +ROULWRMXSWNHGI +ROULWRMXSWNHGI +XESQVFRIQGMTRT +XESQVFRIQGMTRT +XESQVFRIQGMTRT +YYKPIROMFSWCPG +YYKPIROMFSWCPG +YYKPIROMFSWCPG +LRHJBFSYXMNCTB +LRHJBFSYXMNCTB +LRHJBFSYXMNCTB +MBNYXWWYELYPEF +MBNYXWWYELYPEF +MBNYXWWYELYPEF +FRUWYQSYVKOWAI +FRUWYQSYVKOWAI +FRUWYQSYVKOWAI +WYQXAKSATMQYJT +WYQXAKSATMQYJT +WYQXAKSATMQYJT +BLIJYYDMRNNJLZ +SDVIBAGEZPWWFT +SDVIBAGEZPWWFT +SDVIBAGEZPWWFT +FBWNJXXFJVLEHB +FBWNJXXFJVLEHB +FBWNJXXFJVLEHB +XEBZQHJVQMTHKG +XEBZQHJVQMTHKG +XEBZQHJVQMTHKG +GCPAYUHHLFWKQF +GCPAYUHHLFWKQF +GCPAYUHHLFWKQF +ATDZUPRXLBFCMS +ATDZUPRXLBFCMS +ATDZUPRXLBFCMS +ZXEGXWGRLXIFAJ +ZXEGXWGRLXIFAJ +ZXEGXWGRLXIFAJ +XORCUXPFDRQOOR +XORCUXPFDRQOOR +XORCUXPFDRQOOR +AEPFGJLCYYNHBG +AEPFGJLCYYNHBG +AEPFGJLCYYNHBG +ROBUUFFKYVMDKV +ROBUUFFKYVMDKV +ROBUUFFKYVMDKV +IPJLKPWXBCNKLW +IPJLKPWXBCNKLW +IPJLKPWXBCNKLW +FAAVKTZUPDUPIZ +FAAVKTZUPDUPIZ +FAAVKTZUPDUPIZ +PXCRXNJJZOTJLE +PXCRXNJJZOTJLE +PXCRXNJJZOTJLE +AHITXPXITHQFPL +AHITXPXITHQFPL +AHITXPXITHQFPL +MAVPLLTUUMXKHR +MAVPLLTUUMXKHR +MAVPLLTUUMXKHR +RECDMPIKFYPMSE +RECDMPIKFYPMSE +RECDMPIKFYPMSE +KYEOPRCMLYGLKJ +KYEOPRCMLYGLKJ +KYEOPRCMLYGLKJ +NRMJYTXEQJJQGK +NRMJYTXEQJJQGK +NRMJYTXEQJJQGK +PKIVWSCIDQAKPU +PKIVWSCIDQAKPU +PKIVWSCIDQAKPU +AGNZVNGKFKRIFC +AGNZVNGKFKRIFC +AGNZVNGKFKRIFC +DOFUQMGOWLMGLE +DOFUQMGOWLMGLE +DOFUQMGOWLMGLE +OWWSANSNNQTDAN +OWWSANSNNQTDAN +OWWSANSNNQTDAN +BFWVMGXQMZZAQB +BFWVMGXQMZZAQB +BFWVMGXQMZZAQB +WYNUVWKXIBKXMI +WYNUVWKXIBKXMI +WYNUVWKXIBKXMI +VEWGJRXPIOULQD +VEWGJRXPIOULQD +VEWGJRXPIOULQD +ULUVSAUIWNKOPX +ULUVSAUIWNKOPX +ULUVSAUIWNKOPX +UREICCCUUVWLGW +UREICCCUUVWLGW +UREICCCUUVWLGW +QEGFNJKRANLPDR +QEGFNJKRANLPDR +QEGFNJKRANLPDR +LIGWQMUAAZGCGR +LIGWQMUAAZGCGR +LIGWQMUAAZGCGR +YJEZZDPAHQKFGY +YJEZZDPAHQKFGY +YJEZZDPAHQKFGY +YJEZZDPAHQKFGY +VJCANGHIFSKRFF +VJCANGHIFSKRFF +VJCANGHIFSKRFF +AINLQMYUCLAXPC +OXQJLJKNTKNRIK +OXQJLJKNTKNRIK +OXQJLJKNTKNRIK +YUMJMVTVLIGWLJ +YUMJMVTVLIGWLJ +YUMJMVTVLIGWLJ +AALLEWUCWSEWPN +AALLEWUCWSEWPN +AALLEWUCWSEWPN +YSTXEYUSGFGZRY +YSTXEYUSGFGZRY +YSTXEYUSGFGZRY +NJZTUJDTRLWAAD +NJZTUJDTRLWAAD +NJZTUJDTRLWAAD +WVBCOFDJYWEMPK +WVBCOFDJYWEMPK +HMLWRVAUUCPSAK +HMLWRVAUUCPSAK +HMLWRVAUUCPSAK +AJHALYCTPQKQDY +AJHALYCTPQKQDY +AJHALYCTPQKQDY +YQAPFFBNVVHJFS +YQAPFFBNVVHJFS +YQAPFFBNVVHJFS +KIOFFSGXUJZCOC +KIOFFSGXUJZCOC +KIOFFSGXUJZCOC +WZDIDEYNVACCCN +WZDIDEYNVACCCN +WZDIDEYNVACCCN +LKHJTXLHPYVCJJ +LKHJTXLHPYVCJJ +LKHJTXLHPYVCJJ +FBGVMOYGFJNBNE +FBGVMOYGFJNBNE +FBGVMOYGFJNBNE +YSMCDQWBAZNZIB +YSMCDQWBAZNZIB +YSMCDQWBAZNZIB +FTXPGPZFXVRDGY +FTXPGPZFXVRDGY +FTXPGPZFXVRDGY +XUJADAOBPBCONT +XUJADAOBPBCONT +XUJADAOBPBCONT +HJQZEHUWKLTEBJ +HJQZEHUWKLTEBJ +HJQZEHUWKLTEBJ +HJQZEHUWKLTEBJ +HJQZEHUWKLTEBJ +WFSNAHOKUTXXPH +WFSNAHOKUTXXPH +WFSNAHOKUTXXPH +JATQJDWRKDDGHT +JATQJDWRKDDGHT +JATQJDWRKDDGHT +UJWGRDPNNZJTGL +UJWGRDPNNZJTGL +UJWGRDPNNZJTGL +UJWGRDPNNZJTGL +IPXWPUAVXDMELA +IPXWPUAVXDMELA +IPXWPUAVXDMELA +GTROEMKBKCNALC +GTROEMKBKCNALC +GTROEMKBKCNALC +LNTCMUQRCOMGGU +LNTCMUQRCOMGGU +LNTCMUQRCOMGGU +NADMPAFNMBXORS +NADMPAFNMBXORS +NADMPAFNMBXORS +HLIVWBCNWLFFAL +HLIVWBCNWLFFAL +HLIVWBCNWLFFAL +DKIGTEGEDFZRON +DKIGTEGEDFZRON +DKIGTEGEDFZRON +DKIGTEGEDFZRON +GIFYXEOCSAZZGJ +GIFYXEOCSAZZGJ +RRLGLIQZMFUYHY +RRLGLIQZMFUYHY +RRLGLIQZMFUYHY +TUFHDZBVPGUKSP +TUFHDZBVPGUKSP +TUFHDZBVPGUKSP +YKLAAVFJHALIRQ +YKLAAVFJHALIRQ +YKLAAVFJHALIRQ +CTGHFIJGHUXBGO +CTGHFIJGHUXBGO +CTGHFIJGHUXBGO +QJHCUGOHUWKHEF +QJHCUGOHUWKHEF +QJHCUGOHUWKHEF +IZUWCUNNBXAGNC +IZUWCUNNBXAGNC +IZUWCUNNBXAGNC +XICDHUKYRLTMOC +XICDHUKYRLTMOC +XICDHUKYRLTMOC +MQZVQECZUWGDME +MQZVQECZUWGDME +MQZVQECZUWGDME +JQWHBECAJYJQKW +JQWHBECAJYJQKW +JQWHBECAJYJQKW +HBNABIPMJXWRSC +HBNABIPMJXWRSC +HBNABIPMJXWRSC +DZTGIRNXWSZBIM +DZTGIRNXWSZBIM +DZTGIRNXWSZBIM +DZTGIRNXWSZBIM +DZTGIRNXWSZBIM +DZTGIRNXWSZBIM +DZTGIRNXWSZBIM +DZTGIRNXWSZBIM +DZTGIRNXWSZBIM +PUYVJBBSBPUKBT +PUYVJBBSBPUKBT +PUYVJBBSBPUKBT +PUYVJBBSBPUKBT +PUYVJBBSBPUKBT +PUYVJBBSBPUKBT +PUYVJBBSBPUKBT +PUYVJBBSBPUKBT +PUYVJBBSBPUKBT +HRJWTAWVFDCTGO +HRJWTAWVFDCTGO +HRJWTAWVFDCTGO +HRJWTAWVFDCTGO +HRJWTAWVFDCTGO +HRJWTAWVFDCTGO +HRJWTAWVFDCTGO +HRJWTAWVFDCTGO +VFPYGNNOSJWBHF +VFPYGNNOSJWBHF +VFPYGNNOSJWBHF +VFPYGNNOSJWBHF +VFPYGNNOSJWBHF +VFPYGNNOSJWBHF +VFPYGNNOSJWBHF +VFPYGNNOSJWBHF +VFPYGNNOSJWBHF +VFPYGNNOSJWBHF +PQXINDBPUDNMPE +PQXINDBPUDNMPE +PQXINDBPUDNMPE +PQXINDBPUDNMPE +PQXINDBPUDNMPE +PQXINDBPUDNMPE +PQXINDBPUDNMPE +PQXINDBPUDNMPE +PQXINDBPUDNMPE +ZFDMUUNGVLREEC +ZFDMUUNGVLREEC +ZFDMUUNGVLREEC +ZFDMUUNGVLREEC +ZFDMUUNGVLREEC +ZFDMUUNGVLREEC +ZFDMUUNGVLREEC +ZFDMUUNGVLREEC +ZFDMUUNGVLREEC +KPABJHHKKJIDGX +KPABJHHKKJIDGX +KPABJHHKKJIDGX +KPABJHHKKJIDGX +KPABJHHKKJIDGX +KPABJHHKKJIDGX +KPABJHHKKJIDGX +KPABJHHKKJIDGX +KPABJHHKKJIDGX +LBPKYPYHDKKRFS +LBPKYPYHDKKRFS +LBPKYPYHDKKRFS +LBPKYPYHDKKRFS +LBPKYPYHDKKRFS +LBPKYPYHDKKRFS +CPYTVBALBFSXSH +CPYTVBALBFSXSH +CPYTVBALBFSXSH +CPYTVBALBFSXSH +CPYTVBALBFSXSH +CPYTVBALBFSXSH +CPYTVBALBFSXSH +CPYTVBALBFSXSH +CPYTVBALBFSXSH +NBMBIEOUVBHEBM +NBMBIEOUVBHEBM +NBMBIEOUVBHEBM +NBMBIEOUVBHEBM +NBMBIEOUVBHEBM +NBMBIEOUVBHEBM +NBMBIEOUVBHEBM +NBMBIEOUVBHEBM +NBMBIEOUVBHEBM +DRCNWQYEKZTTEW +DRCNWQYEKZTTEW +DRCNWQYEKZTTEW +DRCNWQYEKZTTEW +DRCNWQYEKZTTEW +DRCNWQYEKZTTEW +DRCNWQYEKZTTEW +DRCNWQYEKZTTEW +DRCNWQYEKZTTEW +KYYKGSDLXXKQCR +KYYKGSDLXXKQCR +KYYKGSDLXXKQCR +KYYKGSDLXXKQCR +KYYKGSDLXXKQCR +KYYKGSDLXXKQCR +KYYKGSDLXXKQCR +KYYKGSDLXXKQCR +KYYKGSDLXXKQCR +RRRDZFQRNJTKHL +RRRDZFQRNJTKHL +RRRDZFQRNJTKHL +RRRDZFQRNJTKHL +RRRDZFQRNJTKHL +RRRDZFQRNJTKHL +RRRDZFQRNJTKHL +RRRDZFQRNJTKHL +RRRDZFQRNJTKHL +BEADRWVIFHOSGN +BEADRWVIFHOSGN +BEADRWVIFHOSGN +BEADRWVIFHOSGN +BEADRWVIFHOSGN +BEADRWVIFHOSGN +BEADRWVIFHOSGN +BEADRWVIFHOSGN +BEADRWVIFHOSGN +DWHXUGDWKAIASB +DWHXUGDWKAIASB +DWHXUGDWKAIASB +DWHXUGDWKAIASB +DWHXUGDWKAIASB +DWHXUGDWKAIASB +DWHXUGDWKAIASB +DWHXUGDWKAIASB +DWHXUGDWKAIASB +VZZJRYRQSPEMTK +VZZJRYRQSPEMTK +VZZJRYRQSPEMTK +VZZJRYRQSPEMTK +VZZJRYRQSPEMTK +VZZJRYRQSPEMTK +VZZJRYRQSPEMTK +VZZJRYRQSPEMTK +VZZJRYRQSPEMTK +VZZJRYRQSPEMTK +KLRRGBHZCJLIEL +KLRRGBHZCJLIEL +KLRRGBHZCJLIEL +KLRRGBHZCJLIEL +KLRRGBHZCJLIEL +KLRRGBHZCJLIEL +KLRRGBHZCJLIEL +KLRRGBHZCJLIEL +KLRRGBHZCJLIEL +SWMDAPWAQQTBOG +SWMDAPWAQQTBOG +SWMDAPWAQQTBOG +SWMDAPWAQQTBOG +SWMDAPWAQQTBOG +SWMDAPWAQQTBOG +SWMDAPWAQQTBOG +SWMDAPWAQQTBOG +SWMDAPWAQQTBOG +SWMDAPWAQQTBOG +SWMDAPWAQQTBOG +SWMDAPWAQQTBOG +SWMDAPWAQQTBOG +SWMDAPWAQQTBOG +SWMDAPWAQQTBOG +KRTIYQIPSAGSBP +KRTIYQIPSAGSBP +KRTIYQIPSAGSBP +KRTIYQIPSAGSBP +KRTIYQIPSAGSBP +KRTIYQIPSAGSBP +SMPGEBOIKULBCT +SMPGEBOIKULBCT +SMPGEBOIKULBCT +SMPGEBOIKULBCT +SMPGEBOIKULBCT +SMPGEBOIKULBCT +SMPGEBOIKULBCT +SMPGEBOIKULBCT +SMPGEBOIKULBCT +SMPGEBOIKULBCT +SMPGEBOIKULBCT +SMPGEBOIKULBCT +SMPGEBOIKULBCT +SMPGEBOIKULBCT +SMPGEBOIKULBCT +SMPGEBOIKULBCT +QAAFNSMAIAVCHE +QAAFNSMAIAVCHE +QAAFNSMAIAVCHE +QAAFNSMAIAVCHE +QAAFNSMAIAVCHE +QAAFNSMAIAVCHE +QAAFNSMAIAVCHE +QAAFNSMAIAVCHE +QAAFNSMAIAVCHE +QAAFNSMAIAVCHE +QAAFNSMAIAVCHE +QAAFNSMAIAVCHE +QAAFNSMAIAVCHE +QAAFNSMAIAVCHE +QAAFNSMAIAVCHE +IKUYEYLZXGGCRD +IKUYEYLZXGGCRD +IKUYEYLZXGGCRD +IKUYEYLZXGGCRD +IKUYEYLZXGGCRD +IKUYEYLZXGGCRD +IKUYEYLZXGGCRD +IKUYEYLZXGGCRD +IKUYEYLZXGGCRD +HLCDNLNLQNYZTK +HLCDNLNLQNYZTK +HLCDNLNLQNYZTK +HLCDNLNLQNYZTK +HLCDNLNLQNYZTK +HLCDNLNLQNYZTK +HLCDNLNLQNYZTK +HLCDNLNLQNYZTK +HLCDNLNLQNYZTK +UYBRROMMFMPJAN +UYBRROMMFMPJAN +UYBRROMMFMPJAN +UYBRROMMFMPJAN +UYBRROMMFMPJAN +UYBRROMMFMPJAN +UYBRROMMFMPJAN +UYBRROMMFMPJAN +UYBRROMMFMPJAN +NRJKIOCCERLIDG +NRJKIOCCERLIDG +NRJKIOCCERLIDG +NRJKIOCCERLIDG +RCYPVQCPYKNSTG +RCYPVQCPYKNSTG +RCYPVQCPYKNSTG +RCYPVQCPYKNSTG +RCYPVQCPYKNSTG +RCYPVQCPYKNSTG +RCYPVQCPYKNSTG +RCYPVQCPYKNSTG +RCYPVQCPYKNSTG +LHSBZAWDPSTOEY +LHSBZAWDPSTOEY +LHSBZAWDPSTOEY +LHSBZAWDPSTOEY +LHSBZAWDPSTOEY +LHSBZAWDPSTOEY +LHSBZAWDPSTOEY +LHSBZAWDPSTOEY +LHSBZAWDPSTOEY +HRDQQHUKUIKFHT +HRDQQHUKUIKFHT +HRDQQHUKUIKFHT +HRDQQHUKUIKFHT +HRDQQHUKUIKFHT +HRDQQHUKUIKFHT +HRDQQHUKUIKFHT +HRDQQHUKUIKFHT +HRDQQHUKUIKFHT +ZGBAJMQHJDFTQJ +ZGBAJMQHJDFTQJ +ZGBAJMQHJDFTQJ +ZGBAJMQHJDFTQJ +ZGBAJMQHJDFTQJ +ZGBAJMQHJDFTQJ +ZGBAJMQHJDFTQJ +ZGBAJMQHJDFTQJ +ZGBAJMQHJDFTQJ +YASYAEVZKXPYIZ +YASYAEVZKXPYIZ +YASYAEVZKXPYIZ +YASYAEVZKXPYIZ +YASYAEVZKXPYIZ +YASYAEVZKXPYIZ +YASYAEVZKXPYIZ +YASYAEVZKXPYIZ +YASYAEVZKXPYIZ +LKOFXMLMYKWELM +LKOFXMLMYKWELM +LKOFXMLMYKWELM +LKOFXMLMYKWELM +LKOFXMLMYKWELM +LKOFXMLMYKWELM +LKOFXMLMYKWELM +LKOFXMLMYKWELM +LKOFXMLMYKWELM +SCJNYBYSTCRPAO +SCJNYBYSTCRPAO +SCJNYBYSTCRPAO +SCJNYBYSTCRPAO +SCJNYBYSTCRPAO +SCJNYBYSTCRPAO +SCJNYBYSTCRPAO +SCJNYBYSTCRPAO +SCJNYBYSTCRPAO +JKCSODVERGVDLT +JKCSODVERGVDLT +JKCSODVERGVDLT +JKCSODVERGVDLT +JKCSODVERGVDLT +JKCSODVERGVDLT +JKCSODVERGVDLT +JKCSODVERGVDLT +JKCSODVERGVDLT +CPMDPSXJELVGJG +CPMDPSXJELVGJG +CPMDPSXJELVGJG +CPMDPSXJELVGJG +CPMDPSXJELVGJG +CPMDPSXJELVGJG +CPMDPSXJELVGJG +CPMDPSXJELVGJG +CPMDPSXJELVGJG +CPMDPSXJELVGJG +CPMDPSXJELVGJG +CPMDPSXJELVGJG +VQLNKQZLPGLOSI +VQLNKQZLPGLOSI +VQLNKQZLPGLOSI +VQLNKQZLPGLOSI +VQLNKQZLPGLOSI +VQLNKQZLPGLOSI +VQLNKQZLPGLOSI +VQLNKQZLPGLOSI +VQLNKQZLPGLOSI +LTSUMTMGJHPGFX +LTSUMTMGJHPGFX +LTSUMTMGJHPGFX +QNRODODTMXCRKU +QNRODODTMXCRKU +QNRODODTMXCRKU +QNRODODTMXCRKU +QNRODODTMXCRKU +QNRODODTMXCRKU +QNRODODTMXCRKU +QNRODODTMXCRKU +QNRODODTMXCRKU +AFTZZRFCMOAFCR +AFTZZRFCMOAFCR +AFTZZRFCMOAFCR +AFTZZRFCMOAFCR +AFTZZRFCMOAFCR +AFTZZRFCMOAFCR +AFTZZRFCMOAFCR +AFTZZRFCMOAFCR +AFTZZRFCMOAFCR +AFTZZRFCMOAFCR +JVRRRKAXHMGUHZ +JVRRRKAXHMGUHZ +JVRRRKAXHMGUHZ +JVRRRKAXHMGUHZ +JVRRRKAXHMGUHZ +JVRRRKAXHMGUHZ +JVRRRKAXHMGUHZ +JVRRRKAXHMGUHZ +JVRRRKAXHMGUHZ +JVRRRKAXHMGUHZ +WRLVHADVOGFZOZ +WRLVHADVOGFZOZ +WRLVHADVOGFZOZ +WRLVHADVOGFZOZ +WRLVHADVOGFZOZ +WRLVHADVOGFZOZ +DVYASSBBADJRAS +DVYASSBBADJRAS +DVYASSBBADJRAS +DVYASSBBADJRAS +DVYASSBBADJRAS +DVYASSBBADJRAS +DVYASSBBADJRAS +DVYASSBBADJRAS +DVYASSBBADJRAS +DVYASSBBADJRAS +SQZJGTOZFRNWCX +SQZJGTOZFRNWCX +SQZJGTOZFRNWCX +SQZJGTOZFRNWCX +SQZJGTOZFRNWCX +SQZJGTOZFRNWCX +SQZJGTOZFRNWCX +SQZJGTOZFRNWCX +SQZJGTOZFRNWCX +GMIZZEXBPRLVIV +GMIZZEXBPRLVIV +GMIZZEXBPRLVIV +GMIZZEXBPRLVIV +GMIZZEXBPRLVIV +GMIZZEXBPRLVIV +GMIZZEXBPRLVIV +GMIZZEXBPRLVIV +GMIZZEXBPRLVIV +NDEBZCZEAVMSQF +NDEBZCZEAVMSQF +NDEBZCZEAVMSQF +NDEBZCZEAVMSQF +NDEBZCZEAVMSQF +NDEBZCZEAVMSQF +NDEBZCZEAVMSQF +NDEBZCZEAVMSQF +NDEBZCZEAVMSQF +PKNYXWMTHFMHKD +PKNYXWMTHFMHKD +PKNYXWMTHFMHKD +PKNYXWMTHFMHKD +PKNYXWMTHFMHKD +PKNYXWMTHFMHKD +PKNYXWMTHFMHKD +PKNYXWMTHFMHKD +PKNYXWMTHFMHKD +ADXGNEYLLLSOAR +ADXGNEYLLLSOAR +ADXGNEYLLLSOAR +ADXGNEYLLLSOAR +ADXGNEYLLLSOAR +ADXGNEYLLLSOAR +ADXGNEYLLLSOAR +ADXGNEYLLLSOAR +ADXGNEYLLLSOAR +WLAVZAAODLTUSW +WLAVZAAODLTUSW +WLAVZAAODLTUSW +WLAVZAAODLTUSW +WLAVZAAODLTUSW +WLAVZAAODLTUSW +WLAVZAAODLTUSW +WLAVZAAODLTUSW +WLAVZAAODLTUSW +HPLNQCPCUACXLM +HPLNQCPCUACXLM +HPLNQCPCUACXLM +HPLNQCPCUACXLM +HPLNQCPCUACXLM +PTVUGLNOPRZQEY +PTVUGLNOPRZQEY +PTVUGLNOPRZQEY +PTVUGLNOPRZQEY +PTVUGLNOPRZQEY +PTVUGLNOPRZQEY +PTVUGLNOPRZQEY +PTVUGLNOPRZQEY +PTVUGLNOPRZQEY +DTASTQAQBOZSRR +DTASTQAQBOZSRR +DTASTQAQBOZSRR +DTASTQAQBOZSRR +DTASTQAQBOZSRR +DTASTQAQBOZSRR +DTASTQAQBOZSRR +DTASTQAQBOZSRR +DTASTQAQBOZSRR +UPKNGUQNXSMHBE +UPKNGUQNXSMHBE +UPKNGUQNXSMHBE +CQKBSRPVZZLCJE +CQKBSRPVZZLCJE +CQKBSRPVZZLCJE +CQKBSRPVZZLCJE +CQKBSRPVZZLCJE +CQKBSRPVZZLCJE +GISJHCLTIVIGLX +GISJHCLTIVIGLX +GISJHCLTIVIGLX +GISJHCLTIVIGLX +GISJHCLTIVIGLX +GISJHCLTIVIGLX +GISJHCLTIVIGLX +GISJHCLTIVIGLX +GISJHCLTIVIGLX +UFKLYTOEMRFKAD +UFKLYTOEMRFKAD +UFKLYTOEMRFKAD +UFKLYTOEMRFKAD +UFKLYTOEMRFKAD +UFKLYTOEMRFKAD +UFKLYTOEMRFKAD +UFKLYTOEMRFKAD +UFKLYTOEMRFKAD +IGUBBWJDMLCRIK +IGUBBWJDMLCRIK +IGUBBWJDMLCRIK +IGUBBWJDMLCRIK +IGUBBWJDMLCRIK +IGUBBWJDMLCRIK +IGUBBWJDMLCRIK +IGUBBWJDMLCRIK +IGUBBWJDMLCRIK +IGUBBWJDMLCRIK +IGUBBWJDMLCRIK +IGUBBWJDMLCRIK +IYFNEFQTYQPVOC +IYFNEFQTYQPVOC +IYFNEFQTYQPVOC +STZYTFJPGGDRJD +STZYTFJPGGDRJD +STZYTFJPGGDRJD +STZYTFJPGGDRJD +STZYTFJPGGDRJD +STZYTFJPGGDRJD +STZYTFJPGGDRJD +STZYTFJPGGDRJD +STZYTFJPGGDRJD +BFSRTTWIPACGMI +BFSRTTWIPACGMI +BFSRTTWIPACGMI +BFSRTTWIPACGMI +BFSRTTWIPACGMI +BFSRTTWIPACGMI +BFSRTTWIPACGMI +BFSRTTWIPACGMI +BFSRTTWIPACGMI +XQFINGFCBFHOPE +XQFINGFCBFHOPE +XQFINGFCBFHOPE +XQFINGFCBFHOPE +XQFINGFCBFHOPE +XQFINGFCBFHOPE +XQFINGFCBFHOPE +XQFINGFCBFHOPE +XQFINGFCBFHOPE +XQFINGFCBFHOPE +XQFINGFCBFHOPE +XQFINGFCBFHOPE +MURAVORBGFDSMA +MURAVORBGFDSMA +MURAVORBGFDSMA +MURAVORBGFDSMA +MURAVORBGFDSMA +MURAVORBGFDSMA +MURAVORBGFDSMA +MURAVORBGFDSMA +KPFZCKDPBMGECB +KPFZCKDPBMGECB +KPFZCKDPBMGECB +JEGHXKRHKHPBJD +JEGHXKRHKHPBJD +JEGHXKRHKHPBJD +JEGHXKRHKHPBJD +JEGHXKRHKHPBJD +JEGHXKRHKHPBJD +JEGHXKRHKHPBJD +JEGHXKRHKHPBJD +JEGHXKRHKHPBJD +JEGHXKRHKHPBJD +PCMHOSYCWRRHTG +PCMHOSYCWRRHTG +PCMHOSYCWRRHTG +PCMHOSYCWRRHTG +PCMHOSYCWRRHTG +PCMHOSYCWRRHTG +PCMHOSYCWRRHTG +PCMHOSYCWRRHTG +PCMHOSYCWRRHTG +XDLYKKIQACFMJG +XDLYKKIQACFMJG +XDLYKKIQACFMJG +XDLYKKIQACFMJG +XDLYKKIQACFMJG +XDLYKKIQACFMJG +XDLYKKIQACFMJG +XDLYKKIQACFMJG +XDLYKKIQACFMJG +KFRKRECSIYXARE +KFRKRECSIYXARE +KFRKRECSIYXARE +KFRKRECSIYXARE +KFRKRECSIYXARE +KFRKRECSIYXARE +KFRKRECSIYXARE +KFRKRECSIYXARE +KFRKRECSIYXARE +KGWSQGUVJUGIPF +KGWSQGUVJUGIPF +KGWSQGUVJUGIPF +KGWSQGUVJUGIPF +KGWSQGUVJUGIPF +KGWSQGUVJUGIPF +KGWSQGUVJUGIPF +KGWSQGUVJUGIPF +KGWSQGUVJUGIPF +WPHKIQPVPYJNAX +WPHKIQPVPYJNAX +WPHKIQPVPYJNAX +WPHKIQPVPYJNAX +WPHKIQPVPYJNAX +WPHKIQPVPYJNAX +WPHKIQPVPYJNAX +WPHKIQPVPYJNAX +WPHKIQPVPYJNAX +ZIBMATWHOAGNTR +ZIBMATWHOAGNTR +ZIBMATWHOAGNTR +ZIBMATWHOAGNTR +ZIBMATWHOAGNTR +ZIBMATWHOAGNTR +ZIBMATWHOAGNTR +ZIBMATWHOAGNTR +ZIBMATWHOAGNTR +ODNICNWASXKNNQ +ODNICNWASXKNNQ +ODNICNWASXKNNQ +ODNICNWASXKNNQ +ODNICNWASXKNNQ +ODNICNWASXKNNQ +ODNICNWASXKNNQ +ODNICNWASXKNNQ +ODNICNWASXKNNQ +RFZKSQIFOZZIAQ +RFZKSQIFOZZIAQ +RFZKSQIFOZZIAQ +CMOYPFUEZDEQEH +CMOYPFUEZDEQEH +CMOYPFUEZDEQEH +CMOYPFUEZDEQEH +CMOYPFUEZDEQEH +CMOYPFUEZDEQEH +CMOYPFUEZDEQEH +CMOYPFUEZDEQEH +CMOYPFUEZDEQEH +VBRJFXSFCYEZMQ +VBRJFXSFCYEZMQ +VBRJFXSFCYEZMQ +VBRJFXSFCYEZMQ +VBRJFXSFCYEZMQ +VBRJFXSFCYEZMQ +VBRJFXSFCYEZMQ +VBRJFXSFCYEZMQ +VBRJFXSFCYEZMQ +JMIFGARJSWXZSH +JMIFGARJSWXZSH +JMIFGARJSWXZSH +BBGOSBDSLYHMRA +BBGOSBDSLYHMRA +BBGOSBDSLYHMRA +BBGOSBDSLYHMRA +BBGOSBDSLYHMRA +CKUFOBCNTCLXJP +CKUFOBCNTCLXJP +CKUFOBCNTCLXJP +CKUFOBCNTCLXJP +JRWROCIMSDXGOZ +JRWROCIMSDXGOZ +JRWROCIMSDXGOZ +JRWROCIMSDXGOZ +JRWROCIMSDXGOZ +JRWROCIMSDXGOZ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +UURAUHCOJAIIRQ +QYBGBLQCOOISAR +QYBGBLQCOOISAR +QYBGBLQCOOISAR +QXTWSUQCXCWEHF +QXTWSUQCXCWEHF +QXTWSUQCXCWEHF +GYNMVDMBFKGCCR +GYNMVDMBFKGCCR +GYNMVDMBFKGCCR +RNUXIZKXJOGYQP +RNUXIZKXJOGYQP +RNUXIZKXJOGYQP +QTOZBSNPDCWHPV +QTOZBSNPDCWHPV +QTOZBSNPDCWHPV +QTOZBSNPDCWHPV +QTOZBSNPDCWHPV +QTOZBSNPDCWHPV +GZPJCJKUZPUFAL +GZPJCJKUZPUFAL +GZPJCJKUZPUFAL +QHKYPYXTTXKZST +QHKYPYXTTXKZST +HAYBKCHPEBZNGW +HAYBKCHPEBZNGW +HAYBKCHPEBZNGW +HHCYCBKPWYJVEB +HHCYCBKPWYJVEB +HHCYCBKPWYJVEB +DHYXNIKICPUXJI +DHYXNIKICPUXJI +DHYXNIKICPUXJI +LGUUETDTMQTHML +LGUUETDTMQTHML +LGUUETDTMQTHML +SWWVFYHSSOWZMF +SWWVFYHSSOWZMF +SWWVFYHSSOWZMF +VFCRKLWBYMDAED +VFCRKLWBYMDAED +VFCRKLWBYMDAED +LYPAFUINURXJSG +LYPAFUINURXJSG +LYPAFUINURXJSG +PAOANWZGLPPROA +PAOANWZGLPPROA +PAOANWZGLPPROA +PAOANWZGLPPROA +PAOANWZGLPPROA +ZXIBCJHYVWYIKI +ZXIBCJHYVWYIKI +ZXIBCJHYVWYIKI +GROMEQPXDKRRIE +GROMEQPXDKRRIE +GROMEQPXDKRRIE +DKNUPRMJNUQNHR +DKNUPRMJNUQNHR +DKNUPRMJNUQNHR +NXZNYBUBXWWKCP +NXZNYBUBXWWKCP +NXZNYBUBXWWKCP +GGQCIOOSELPMBB +GGQCIOOSELPMBB +GGQCIOOSELPMBB +SRNQPYBWRIETFQ +SRNQPYBWRIETFQ +SRNQPYBWRIETFQ +RFZQYGBLRIKROZ +RFZQYGBLRIKROZ +RFZQYGBLRIKROZ +XKQLNDPUQSZBJW +XKQLNDPUQSZBJW +XKQLNDPUQSZBJW +YWGYNGCRVZLMCS +YWGYNGCRVZLMCS +YWGYNGCRVZLMCS +ZBCMHWUFWQFPLV +ZBCMHWUFWQFPLV +ZBCMHWUFWQFPLV +ZBCMHWUFWQFPLV +ZBCMHWUFWQFPLV +ZBCMHWUFWQFPLV +CGDZXLJGHVKVIE +CGDZXLJGHVKVIE +CGDZXLJGHVKVIE +BBDGBGOVJPEFBT +BDUHCSBCVGXTJM +BDUHCSBCVGXTJM +BDUHCSBCVGXTJM +BMUACLADCKCNKZ +BMUACLADCKCNKZ +BMUACLADCKCNKZ +TYTGOXSAAQWLPJ +TYTGOXSAAQWLPJ +TYTGOXSAAQWLPJ +MDFCJNFOINXVSU +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +VRQXRVAKPDCRCI +VRQXRVAKPDCRCI +VRQXRVAKPDCRCI +VRQXRVAKPDCRCI +ZWFKJFUFYPOTKL +ZWFKJFUFYPOTKL +ZWFKJFUFYPOTKL +IDKAKZRYYDCJDU +IDKAKZRYYDCJDU +IDKAKZRYYDCJDU +WGZOTBUYUFBEPZ +SZBGQDXLNMELTB +SZBGQDXLNMELTB +AHNNWZOVCRQAAH +AHNNWZOVCRQAAH +AHNNWZOVCRQAAH +LIGGMBSSOOVGAE +LIGGMBSSOOVGAE +CHSDJDLAKKAWCI +CHSDJDLAKKAWCI +CHSDJDLAKKAWCI +DHKFOIHIUYFSOF +DHKFOIHIUYFSOF +XCFLWTZSJYBCPF +XCFLWTZSJYBCPF +XCFLWTZSJYBCPF +XCFLWTZSJYBCPF +XCFLWTZSJYBCPF +OACODUCFPHHCIH +OACODUCFPHHCIH +OACODUCFPHHCIH +VLQTUNDJHLEFEQ +VLQTUNDJHLEFEQ +VLQTUNDJHLEFEQ +QNJYUHRGCPRPQS +QNJYUHRGCPRPQS +QNJYUHRGCPRPQS +JRNJNYBQQYBCLE +JRNJNYBQQYBCLE +JRNJNYBQQYBCLE +LMJFJIDLEAWOQJ +LMJFJIDLEAWOQJ +LMJFJIDLEAWOQJ +HXBRBOYWXDLHDC +HXBRBOYWXDLHDC +HXBRBOYWXDLHDC +CITWIBXKKHFDFM +CITWIBXKKHFDFM +CITWIBXKKHFDFM +DVBPRWJMHURKHP +DVBPRWJMHURKHP +DVBPRWJMHURKHP +WQGDQGAFSDMBLA +WQGDQGAFSDMBLA +WUDBUIUHVNECTM +WUDBUIUHVNECTM +WUDBUIUHVNECTM +BLSNYSFLZAWBIV +BLSNYSFLZAWBIV +BLSNYSFLZAWBIV +UUPPIQKPNBIUKY +UUPPIQKPNBIUKY +UUPPIQKPNBIUKY +AXTAPYRUEKNRBA +AXTAPYRUEKNRBA +AXTAPYRUEKNRBA +GFWRVVCDTLRWPK +GFWRVVCDTLRWPK +GFWRVVCDTLRWPK +GCIKSSRWRFVXBI +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +XONRRGIRSGNWFP +XONRRGIRSGNWFP +XONRRGIRSGNWFP +STPSLAZMEWZDAJ +STPSLAZMEWZDAJ +STPSLAZMEWZDAJ +QLVSJMZJSABWRX +QLVSJMZJSABWRX +QLVSJMZJSABWRX +ZJMDTBBCNMGFMS +ZJMDTBBCNMGFMS +ZJMDTBBCNMGFMS +BWUXSHHOKODNAK +BWUXSHHOKODNAK +VHHVPDKNKPNKHY +VHHVPDKNKPNKHY +VHHVPDKNKPNKHY +IFOIINXSFCQLOV +IFOIINXSFCQLOV +IFOIINXSFCQLOV +OTTOCUYGSZUQOI +OTTOCUYGSZUQOI +OTTOCUYGSZUQOI +SFPYRFRNYALLHS +SFPYRFRNYALLHS +SFPYRFRNYALLHS +BLVQHYHDYFTPDV +BLVQHYHDYFTPDV +BLVQHYHDYFTPDV +FWLMVFUGMHIOAA +FWLMVFUGMHIOAA +FWLMVFUGMHIOAA +FWLMVFUGMHIOAA +HZILSILAELSWKN +HZILSILAELSWKN +HZILSILAELSWKN +FUSHFOGORKZNNQ +FUSHFOGORKZNNQ +FUSHFOGORKZNNQ +HYBZWVLPALMACV +HYBZWVLPALMACV +HYBZWVLPALMACV +HBNPJJILLOYFJU +HBNPJJILLOYFJU +HBNPJJILLOYFJU +HBNPJJILLOYFJU +HBNPJJILLOYFJU +HBNPJJILLOYFJU +BJCJYEYYYGBROF +BJCJYEYYYGBROF +BJCJYEYYYGBROF +HYNBNUYQTQIHJK +HYNBNUYQTQIHJK +HYNBNUYQTQIHJK +GMVNBKZQJFRFAR +GMVNBKZQJFRFAR +GMVNBKZQJFRFAR +GIMNAEMRNXUAQP +GIMNAEMRNXUAQP +GIMNAEMRNXUAQP +GIUZEIJUFOPTMR +GIUZEIJUFOPTMR +GIUZEIJUFOPTMR +GIUZEIJUFOPTMR +GIUZEIJUFOPTMR +GIUZEIJUFOPTMR +GIUZEIJUFOPTMR +HIWVLHPKZNBSBE +HEAUOKZIVMZVQL +HEAUOKZIVMZVQL +KJTITGSAONQVPY +KJTITGSAONQVPY +KJTITGSAONQVPY +XTEOJPUYZWEXFI +XTEOJPUYZWEXFI +XTEOJPUYZWEXFI +WXRGFPHDRFQODR +WXRGFPHDRFQODR +WXRGFPHDRFQODR +QGBBBLPWBSWERZ +QGBBBLPWBSWERZ +QGBBBLPWBSWERZ +XSDAXWRCPTYNOD +XSDAXWRCPTYNOD +XSDAXWRCPTYNOD +VCNHSKHGFXUGRH +VRSMJNVXOITYPE +VRSMJNVXOITYPE +VRSMJNVXOITYPE +OTUBDDRFPQLPKD +OTUBDDRFPQLPKD +OTUBDDRFPQLPKD +OOBJCYKITXPCNS +OOBJCYKITXPCNS +OOBJCYKITXPCNS +BUXIAWLTBSXYSW +BUXIAWLTBSXYSW +BUXIAWLTBSXYSW +XIJHWXXXIMEHKW +XIJHWXXXIMEHKW +XIJHWXXXIMEHKW +VGRLXWFIXGZRMS +VGRLXWFIXGZRMS +VGRLXWFIXGZRMS +DUDNZBPCJBAIFT +DUDNZBPCJBAIFT +DUDNZBPCJBAIFT +RGJOJUGRHPQXGF +RGJOJUGRHPQXGF +RGJOJUGRHPQXGF +JLPURTXCSILYLW +JLPURTXCSILYLW +PUXPEQJKNAWNQA +PUXPEQJKNAWNQA +PUXPEQJKNAWNQA +ZYQXEVJIFYIBHZ +ZYQXEVJIFYIBHZ +ZYQXEVJIFYIBHZ +MYTIJGWONQOOLC +MYTIJGWONQOOLC +MYTIJGWONQOOLC +WKDNQONLGXOZRG +WKDNQONLGXOZRG +WKDNQONLGXOZRG +VQPFSIRUEPQQPP +VQPFSIRUEPQQPP +VQPFSIRUEPQQPP +VQPFSIRUEPQQPP +VQPFSIRUEPQQPP +VQPFSIRUEPQQPP +VQPFSIRUEPQQPP +LKCUEUQTTCOYPW +LKCUEUQTTCOYPW +XAFSFXYJOJWLJD +XAFSFXYJOJWLJD +XAFSFXYJOJWLJD +YHUKWWWCNSTFHL +YHUKWWWCNSTFHL +YHUKWWWCNSTFHL +DIXMMXNNKLCLOM +DIXMMXNNKLCLOM +DIXMMXNNKLCLOM +BIHPJIJLDNUDGH +BIHPJIJLDNUDGH +BIHPJIJLDNUDGH +SRQKTCXJCCHINN +SRQKTCXJCCHINN +SRQKTCXJCCHINN +KSEYRUGYKHXGFW +KSEYRUGYKHXGFW +KSEYRUGYKHXGFW +KSEYRUGYKHXGFW +BYTKNUOMWLJVNQ +RVAQIUULWULRNW +RVAQIUULWULRNW +RVAQIUULWULRNW +VCDQAPTULMMFKX +VCDQAPTULMMFKX +VCDQAPTULMMFKX +SXTGIAYWYXVNLT +SXTGIAYWYXVNLT +DHJXZSFKLJCHLH +GXXLUDOKHXEFBQ +GXXLUDOKHXEFBQ +GXXLUDOKHXEFBQ +BFTKDWYIRJGJCA +BFTKDWYIRJGJCA +BFTKDWYIRJGJCA +JHDZMASHNBKTPS +JHDZMASHNBKTPS +JHDZMASHNBKTPS +PDKDOPJQPKXNCT +PDKDOPJQPKXNCT +PDKDOPJQPKXNCT +RSMYFSPOTCDHHJ +RSMYFSPOTCDHHJ +RSMYFSPOTCDHHJ +ZBGXUVOIWDMMJE +ZBGXUVOIWDMMJE +ZBGXUVOIWDMMJE +VMVOHHPQIAPYHG +VMVOHHPQIAPYHG +VMVOHHPQIAPYHG +CNTMOLDWXSVYKD +CNTMOLDWXSVYKD +CNTMOLDWXSVYKD +CNTMOLDWXSVYKD +CNTMOLDWXSVYKD +CNTMOLDWXSVYKD +CNTMOLDWXSVYKD +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +SZMJVTADHFNAIS +SZMJVTADHFNAIS +SZMJVTADHFNAIS +VYXWHVDEWWHDLH +VYXWHVDEWWHDLH +VYXWHVDEWWHDLH +SQOCEMCKYDVLMM +SQOCEMCKYDVLMM +SQOCEMCKYDVLMM +SQOCEMCKYDVLMM +SQOCEMCKYDVLMM +HVIGNZUDBVLTLU +HVIGNZUDBVLTLU +AGBSXNCBIWWLHD +AGBSXNCBIWWLHD +AGBSXNCBIWWLHD +KUJQEQAVMNFFAO +KUJQEQAVMNFFAO +KUJQEQAVMNFFAO +YQCOPPONWZNBQO +YQCOPPONWZNBQO +YQCOPPONWZNBQO +XRNVABDYQLHODA +XRNVABDYQLHODA +DOBKQCZBPPCLEG +LOXMLWHUIONWMI +LOXMLWHUIONWMI +LOXMLWHUIONWMI +UELYDGOOJPRWGF +UELYDGOOJPRWGF +UELYDGOOJPRWGF +OPXIRFWNLBDKQB +OPXIRFWNLBDKQB +OPXIRFWNLBDKQB +UFPINDDCTUCUSA +UFPINDDCTUCUSA +UFPINDDCTUCUSA +UFPINDDCTUCUSA +DENYZIUJOTUUNY +DENYZIUJOTUUNY +DENYZIUJOTUUNY +NDFKBGWLUHKMFY +NDFKBGWLUHKMFY +NDFKBGWLUHKMFY +BWABTWGSXHTHCG +BWABTWGSXHTHCG +BWABTWGSXHTHCG +OXQNLLVUVDAEHC +OXQNLLVUVDAEHC +OXQNLLVUVDAEHC +QIEKHLDZKRQLLN +QIEKHLDZKRQLLN +QIEKHLDZKRQLLN +NEYKRKVLEWKOBI +NEYKRKVLEWKOBI +NEYKRKVLEWKOBI +NEYKRKVLEWKOBI +NEYKRKVLEWKOBI +ZGNKNLOBYFTGRG +ZGNKNLOBYFTGRG +ZGNKNLOBYFTGRG +RSWFSOOHVWOZQI +RSWFSOOHVWOZQI +RSWFSOOHVWOZQI +OVJUYQCJIFWMBI +OVJUYQCJIFWMBI +OVJUYQCJIFWMBI +MEOWKUXNVNJAMY +MEOWKUXNVNJAMY +MEOWKUXNVNJAMY +MNYJJHBAEYKXEG +MNYJJHBAEYKXEG +MNYJJHBAEYKXEG +WMCOYUSJXXCHFH +WMCOYUSJXXCHFH +WMCOYUSJXXCHFH +WYJCYXOCHXWTHG +WYJCYXOCHXWTHG +WYJCYXOCHXWTHG +WYJCYXOCHXWTHG +WYJCYXOCHXWTHG +WYJCYXOCHXWTHG +KYWWJENKIMRJBI +KYWWJENKIMRJBI +KYWWJENKIMRJBI +KYWWJENKIMRJBI +YUTIXVXZQIQWGY +YUTIXVXZQIQWGY +YUTIXVXZQIQWGY +UJIBXDMNCMEJAY +UJIBXDMNCMEJAY +UJIBXDMNCMEJAY +DFULPGUTXZTYKA +DFULPGUTXZTYKA +DFULPGUTXZTYKA +QIEKHLDZKRQLLN +QIEKHLDZKRQLLN +QIEKHLDZKRQLLN +XVBGRTMNFNMINE +XVBGRTMNFNMINE +XVBGRTMNFNMINE +NOIXNOMHHWGUTG +NOIXNOMHHWGUTG +NOIXNOMHHWGUTG +AIWJVLQNYNCDSL +AIWJVLQNYNCDSL +AIWJVLQNYNCDSL +DLAQYOHJZUTWDJ +DLAQYOHJZUTWDJ +DLAQYOHJZUTWDJ +DLAQYOHJZUTWDJ +AMAQJTHMSLYMFT +AMAQJTHMSLYMFT +AMAQJTHMSLYMFT +VSOUDUXMPUHJEU +VSOUDUXMPUHJEU +VSOUDUXMPUHJEU +CCUXEBOOTMDSAM +CCUXEBOOTMDSAM +CCUXEBOOTMDSAM +YOHLRCOPRAVUCJ +YOHLRCOPRAVUCJ +YOHLRCOPRAVUCJ +YOHLRCOPRAVUCJ +YOHLRCOPRAVUCJ +TWHZNAUBXFZMCA +TWHZNAUBXFZMCA +TWHZNAUBXFZMCA +WVSBGSNVCDAMCF +WVSBGSNVCDAMCF +LLXISKGBWFTGEI +LLXISKGBWFTGEI +LLXISKGBWFTGEI +TYNZGYMGTTUYKZ +TYNZGYMGTTUYKZ +TYNZGYMGTTUYKZ +JFVZFKDSXNQEJW +JFVZFKDSXNQEJW +JFVZFKDSXNQEJW +JFVZFKDSXNQEJW +JFVZFKDSXNQEJW +JFVZFKDSXNQEJW +NRHDGIYFJJUFKN +NRHDGIYFJJUFKN +NRHDGIYFJJUFKN +IGXAOFNNKAUXCJ +IGXAOFNNKAUXCJ +IGXAOFNNKAUXCJ +IGXAOFNNKAUXCJ +FDMUNKXWYMSZIR +FDMUNKXWYMSZIR +FDMUNKXWYMSZIR +UVDVCDUBJWYRJW +UVDVCDUBJWYRJW +UVDVCDUBJWYRJW +WCKZRLOUKYFJDY +WCKZRLOUKYFJDY +WCKZRLOUKYFJDY +ATKZKAYWARYLBW +ATKZKAYWARYLBW +ATKZKAYWARYLBW +GLNWREBYRLDPQP +GLNWREBYRLDPQP +GLNWREBYRLDPQP +RICZEKWVNZFTNZ +RICZEKWVNZFTNZ +RICZEKWVNZFTNZ +OWHBVKBNNRYMIN +OWHBVKBNNRYMIN +OWHBVKBNNRYMIN +UPGUBLDTYLMRHO +UPGUBLDTYLMRHO +UPGUBLDTYLMRHO +ODRITQGYYWHQGM +ODRITQGYYWHQGM +ODRITQGYYWHQGM +SFLKJNSBBVSPFE +SFLKJNSBBVSPFE +SFLKJNSBBVSPFE +MJXAAZHAGTZEDV +MJXAAZHAGTZEDV +MJXAAZHAGTZEDV +LOLPPWBBNUVNQZ +LOLPPWBBNUVNQZ +LOLPPWBBNUVNQZ +MZEOSVPWMSEFPW +MZEOSVPWMSEFPW +MZEOSVPWMSEFPW +MZEOSVPWMSEFPW +MZEOSVPWMSEFPW +JFHROPTYMMSOLG +JFHROPTYMMSOLG +JFHROPTYMMSOLG +JFHROPTYMMSOLG +QUZLMKNNIUSREV +QUZLMKNNIUSREV +QUZLMKNNIUSREV +BAORCAMWLWRZQG +BAORCAMWLWRZQG +BAORCAMWLWRZQG +BLWXTJQMEBQCIZ +LDXYBEHACFJIEL +LDXYBEHACFJIEL +LDXYBEHACFJIEL +KJPHTXTWFHVJIG +KJPHTXTWFHVJIG +KJPHTXTWFHVJIG +MKPLKVHSHYCHOC +MKPLKVHSHYCHOC +MKPLKVHSHYCHOC +KZSKGLFYQAYZCO +KZSKGLFYQAYZCO +KZSKGLFYQAYZCO +BSISGUIVBKDTQO +BSISGUIVBKDTQO +GRXCLNMCJWKTAT +GRXCLNMCJWKTAT +GRXCLNMCJWKTAT +XCIGZBVOUQVIPI +XCIGZBVOUQVIPI +XCIGZBVOUQVIPI +HKOWATVSFKRXRW +HKOWATVSFKRXRW +HKOWATVSFKRXRW +HKOWATVSFKRXRW +YGKNVAAMULVFNN +YGKNVAAMULVFNN +YGKNVAAMULVFNN +YGKNVAAMULVFNN +YGKNVAAMULVFNN +YGKNVAAMULVFNN +JIYPVUCBRQNICX +JIYPVUCBRQNICX +BQMMCRXYIIKAOB +BQMMCRXYIIKAOB +BQMMCRXYIIKAOB +JPFTZIJTXCHJNE +JPFTZIJTXCHJNE +JPFTZIJTXCHJNE +JPFTZIJTXCHJNE +JPFTZIJTXCHJNE +JPFTZIJTXCHJNE +XKHXPTSUVPZYDW +XKHXPTSUVPZYDW +FAYAUAZLLLJJGH +FAYAUAZLLLJJGH +FAYAUAZLLLJJGH +OOLLAFOLCSJHRE +OOLLAFOLCSJHRE +OOLLAFOLCSJHRE +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +UCHDWCPVSPXUMX +YQNRVGJCPCNMKT +YQNRVGJCPCNMKT +YQNRVGJCPCNMKT +TVTXCJFHQKSQQM +IQCKJUKAQJINMK +IQCKJUKAQJINMK +IQCKJUKAQJINMK +FYXRSVDHGLUMHB +FYXRSVDHGLUMHB +PZFAZQUREQIODZ +PZFAZQUREQIODZ +PZFAZQUREQIODZ +VZWFUUUUCXTDJT +VZWFUUUUCXTDJT +VZWFUUUUCXTDJT +QEBYISWYMFIXOZ +QEBYISWYMFIXOZ +QEBYISWYMFIXOZ +QEBYISWYMFIXOZ +UNAZAADNBYXMIV +UNAZAADNBYXMIV +UNAZAADNBYXMIV +UNAZAADNBYXMIV +IVZKZONQVYTCKC +IVZKZONQVYTCKC +IVZKZONQVYTCKC +PWTBZOIUWZOPFT +PWTBZOIUWZOPFT +PWTBZOIUWZOPFT +PELFTNQHGSITLB +PELFTNQHGSITLB +PELFTNQHGSITLB +PAFKTGFSEFKSQG +PAFKTGFSEFKSQG +OVPNQJVDAFNBDN +OVPNQJVDAFNBDN +OVPNQJVDAFNBDN +OVPNQJVDAFNBDN +OVPNQJVDAFNBDN +OVPNQJVDAFNBDN +NEQYWYXGTJDAKR +NEQYWYXGTJDAKR +NEQYWYXGTJDAKR +JYOLPDWVAMBMQN +JYOLPDWVAMBMQN +JYOLPDWVAMBMQN +JUVQLZBJFOGEEO +JUVQLZBJFOGEEO +JUVQLZBJFOGEEO +QIFJOFNVIVQRNJ +SPDQRCUBFSRAFI +BOSNKHFAOWELSW +BOSNKHFAOWELSW +BOSNKHFAOWELSW +MZDKLVOWGIOKTN +MZDKLVOWGIOKTN +MZDKLVOWGIOKTN +MZDKLVOWGIOKTN +MZDKLVOWGIOKTN +MZDKLVOWGIOKTN +NMJMRSQTDLRCRQ +NMJMRSQTDLRCRQ +PPTKULJUDJWTSA +PPTKULJUDJWTSA +PPTKULJUDJWTSA +HUEKBQXFNHWTQQ +HUEKBQXFNHWTQQ +HUEKBQXFNHWTQQ +HUEKBQXFNHWTQQ +VGUQVYZXABOXCX +VGUQVYZXABOXCX +VGUQVYZXABOXCX +VGUQVYZXABOXCX +WEAJZXNPAWBCOA +WEAJZXNPAWBCOA +WEAJZXNPAWBCOA +MKLKAQMPKHNQPR +MKLKAQMPKHNQPR +MKLKAQMPKHNQPR +SGPMJRPYYIJZPC +SGPMJRPYYIJZPC +IDUYJRXRDSPPRC +IDUYJRXRDSPPRC +FIMYFEGKMOCQKT +FIMYFEGKMOCQKT +FIMYFEGKMOCQKT +NXFFJDQHYLNEJK +NXFFJDQHYLNEJK +NXFFJDQHYLNEJK +PFGVNLZDWRZPJW +PFGVNLZDWRZPJW +PFGVNLZDWRZPJW +YUTZYVTZDVZBJJ +YUTZYVTZDVZBJJ +YUTZYVTZDVZBJJ +FDTXHWQFIXYHCL +FDTXHWQFIXYHCL +FDTXHWQFIXYHCL +MAYXLCLBDVEYAL +MAYXLCLBDVEYAL +MAYXLCLBDVEYAL +YGUFCDOEKKVKJK +YGUFCDOEKKVKJK +YGUFCDOEKKVKJK +YGUFCDOEKKVKJK +YGUFCDOEKKVKJK +YGUFCDOEKKVKJK +NDAZATDQFDPQBD +NDAZATDQFDPQBD +NDAZATDQFDPQBD +FUIYMYNYUHVDPT +FUIYMYNYUHVDPT +PHNZIIMWDVXPGG +PHNZIIMWDVXPGG +PHNZIIMWDVXPGG +DDKHTWASHUKHLD +DDKHTWASHUKHLD +DDKHTWASHUKHLD +KGPGFQWBCSZGEL +KGPGFQWBCSZGEL +KGPGFQWBCSZGEL +WJRWSLORVIHRNX +WJRWSLORVIHRNX +WJRWSLORVIHRNX +HEAIGWIZTYAQTC +HEAIGWIZTYAQTC +HEAIGWIZTYAQTC +BLMBNKDQXGINRE +BLMBNKDQXGINRE +BLMBNKDQXGINRE +VQHUQHAPWMNBLP +VQHUQHAPWMNBLP +VQHUQHAPWMNBLP +BBUKVPCUOHFAQN +LLXISKGBWFTGEI +LLXISKGBWFTGEI +LLXISKGBWFTGEI +XDJCLCLBSGGNKS +XDJCLCLBSGGNKS +XDJCLCLBSGGNKS +WRONAJQPZWDYAR +WRONAJQPZWDYAR +WRONAJQPZWDYAR +ZLJZDYOBXVOTSA +ZLJZDYOBXVOTSA +ZLJZDYOBXVOTSA +CTQQKICGMSZCJL +CTQQKICGMSZCJL +CTQQKICGMSZCJL +KEDQCFRVSHYKLR +KEDQCFRVSHYKLR +KEDQCFRVSHYKLR +KEDQCFRVSHYKLR +KEDQCFRVSHYKLR +KEDQCFRVSHYKLR +KEDQCFRVSHYKLR +SDUDZBCEHIZMFZ +SDUDZBCEHIZMFZ +SDUDZBCEHIZMFZ +YABJJWZLRMPFSI +VUIRVWPJNKZOSS +VUIRVWPJNKZOSS +VUIRVWPJNKZOSS +MZVBLDCRQKXSHR +MZVBLDCRQKXSHR +MZVBLDCRQKXSHR +MZVBLDCRQKXSHR +MZVBLDCRQKXSHR +MZVBLDCRQKXSHR +UCMNDPDJRSEZPL +UCMNDPDJRSEZPL +UCMNDPDJRSEZPL +RYBLECYFLJXEJX +RYBLECYFLJXEJX +RYBLECYFLJXEJX +SUDAHWBOROXANE +SUDAHWBOROXANE +SUDAHWBOROXANE +AKJBLKUZXRMECW +AKJBLKUZXRMECW +AKJBLKUZXRMECW +UULIGRNKXHCLQN +GACQNUHFDBEIQH +GACQNUHFDBEIQH +GACQNUHFDBEIQH +HKJOIWLYDJCTQR +HKJOIWLYDJCTQR +QDWKGEFGLQMDAM +QDWKGEFGLQMDAM +QDWKGEFGLQMDAM +HZRJHVDNTDBTOZ +SBAITEDLNTYIOE +SBAITEDLNTYIOE +SBAITEDLNTYIOE +BVFLHOOKHPFDCT +JQSRUVXPODZKAF +JQSRUVXPODZKAF +JQSRUVXPODZKAF +GBJVAVGBSGRRKN +GBJVAVGBSGRRKN +GBJVAVGBSGRRKN +ATOAHNRJAXSBOR +ATOAHNRJAXSBOR +SNVFDPHQAOXWJZ +SNVFDPHQAOXWJZ +SNVFDPHQAOXWJZ +RJVLFQBBRSMWHX +RJVLFQBBRSMWHX +RJVLFQBBRSMWHX +SSDRNUPMYCFXGM +SSDRNUPMYCFXGM +SSDRNUPMYCFXGM +WDBNGXLHMZSUEI +WDBNGXLHMZSUEI +WDBNGXLHMZSUEI +HWGQMRYQVZSGDQ +HWGQMRYQVZSGDQ +HWGQMRYQVZSGDQ +HWGQMRYQVZSGDQ +HWGQMRYQVZSGDQ +HWGQMRYQVZSGDQ +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +FNMHEHXNBNCPCI +UFSKUSARDNFIRC +UFSKUSARDNFIRC +RZRQJICXYQPEQJ +RZRQJICXYQPEQJ +RZRQJICXYQPEQJ +ZSSLCFLHEFXANG +ZSSLCFLHEFXANG +ZSSLCFLHEFXANG +YZCUMZWULWOUMD +YZCUMZWULWOUMD +YZCUMZWULWOUMD +YZCUMZWULWOUMD +YZCUMZWULWOUMD +YZCUMZWULWOUMD +HCDMJFOHIXMBOV +HCDMJFOHIXMBOV +HCDMJFOHIXMBOV +YVXYHNKIOFSFMZ +MMJJNHOIVCGAAP +MMJJNHOIVCGAAP +MMJJNHOIVCGAAP +IQNLJJLZIVCGFI +IQNLJJLZIVCGFI +IQNLJJLZIVCGFI +LHGWWAFKVCIILM +LHGWWAFKVCIILM +LHGWWAFKVCIILM +RDDLWMWIRXGSJM +RDDLWMWIRXGSJM +RDDLWMWIRXGSJM +CGBJSGAELGCMKE +CGBJSGAELGCMKE +CGBJSGAELGCMKE +WMDSZGFJQKSLLH +WMDSZGFJQKSLLH +WMDSZGFJQKSLLH +HGVDHZBSSITLCT +HGVDHZBSSITLCT +HGVDHZBSSITLCT +HGVDHZBSSITLCT +HGVDHZBSSITLCT +HGVDHZBSSITLCT +IUEWXNHSKRWHDY +IUEWXNHSKRWHDY +IUEWXNHSKRWHDY +WXJLXRNWMLWVFB +PUIXMSRTTHLNKI +PUIXMSRTTHLNKI +PUIXMSRTTHLNKI +BKCDJTRMYWSXMC +BKCDJTRMYWSXMC +BKCDJTRMYWSXMC +NCRPMBWORFWNGT +NCRPMBWORFWNGT +NCRPMBWORFWNGT +MYEJOKLXXLVMPR +MYEJOKLXXLVMPR +MYEJOKLXXLVMPR +DNYBIOICMDTDAP +DNYBIOICMDTDAP +AZHZVCGYOUJGQE +AZHZVCGYOUJGQE +AZHZVCGYOUJGQE +HDOUAPSDPPFIGT +HDOUAPSDPPFIGT +HDOUAPSDPPFIGT +OBMNJSNZOWALQB +OBMNJSNZOWALQB +OBMNJSNZOWALQB +OBMNJSNZOWALQB +OBMNJSNZOWALQB +OBMNJSNZOWALQB +OBMNJSNZOWALQB +OBMNJSNZOWALQB +MOVBBVMDHIRCTG +NSMOZFXKTHCPTQ +NSMOZFXKTHCPTQ +NSMOZFXKTHCPTQ +RDONXGFGWSSFMY +RDONXGFGWSSFMY +RDONXGFGWSSFMY +IPESYYFOXATSFJ +IPESYYFOXATSFJ +IPESYYFOXATSFJ +ZFBHXVOCZBPADE +ZFBHXVOCZBPADE +CIIVUDIZZJLXCN +CIIVUDIZZJLXCN +CIIVUDIZZJLXCN +ABXIUYMKZDZUDC +ABXIUYMKZDZUDC +ABXIUYMKZDZUDC +HNAJDMYOTDNOBK +HNAJDMYOTDNOBK +HNAJDMYOTDNOBK +WCEHIDWONYOKOJ +WCEHIDWONYOKOJ +WCEHIDWONYOKOJ +UPALIKSFLSVKIS +UPALIKSFLSVKIS +UPALIKSFLSVKIS +XOLMRFUGOINFDQ +XOLMRFUGOINFDQ +XOLMRFUGOINFDQ +AUBGZAJDHUHMAE +AUBGZAJDHUHMAE +AUBGZAJDHUHMAE +FYSRKRZDBHOFAY +FYSRKRZDBHOFAY +FYSRKRZDBHOFAY +HUYUPQNBDBTPQQ +HUYUPQNBDBTPQQ +HUYUPQNBDBTPQQ +OJZSPKKXYGZDRQ +OJZSPKKXYGZDRQ +OJZSPKKXYGZDRQ +NVFRRJQWRZFDLM +NVFRRJQWRZFDLM +NVFRRJQWRZFDLM +HHCBMISMPSAZBF +HHCBMISMPSAZBF +HHCBMISMPSAZBF +HMMHKGLPKAQOOH +HMMHKGLPKAQOOH +HMMHKGLPKAQOOH +SVOQIEJWJCQGDQ +SVOQIEJWJCQGDQ +SVOQIEJWJCQGDQ +SVOQIEJWJCQGDQ +XNMUICFMGGQSMZ +XNMUICFMGGQSMZ +XNMUICFMGGQSMZ +OQKAKSSZSQPTDZ +OQKAKSSZSQPTDZ +OQKAKSSZSQPTDZ +YVIJPELUPZUEJX +YVIJPELUPZUEJX +YVIJPELUPZUEJX +PLIVFNIUGLLCEK +PLIVFNIUGLLCEK +PLIVFNIUGLLCEK +TWQYWUXBZHPIIV +TWQYWUXBZHPIIV +SNMCWIDCSPHZRD +SNMCWIDCSPHZRD +SNMCWIDCSPHZRD +WFOVEDJTASPCIR +WFOVEDJTASPCIR +WFOVEDJTASPCIR +RFUBTTPMWSKEIW +RFUBTTPMWSKEIW +RFUBTTPMWSKEIW +TWCRHJLMMAYSTE +TWCRHJLMMAYSTE +TWCRHJLMMAYSTE +JUHTXZGCTPDXRU +JUHTXZGCTPDXRU +HMEDEBAJARCKCT +HMEDEBAJARCKCT +QJZQFVRFJCGDKF +QJZQFVRFJCGDKF +QJZQFVRFJCGDKF +ZAJXXUDARPGGOC +ZAJXXUDARPGGOC +ZAJXXUDARPGGOC +ZAJXXUDARPGGOC +ZAJXXUDARPGGOC +YYNRZIFBTOUICE +YYNRZIFBTOUICE +YYNRZIFBTOUICE +YLSNQYHZCMCURB +YLSNQYHZCMCURB +YLSNQYHZCMCURB +RDSACQWTXKSHJT +RDSACQWTXKSHJT +RDSACQWTXKSHJT +PYPKSBBTQSNXLR +PYPKSBBTQSNXLR +PYPKSBBTQSNXLR +PYPKSBBTQSNXLR +PYPKSBBTQSNXLR +FFPXPXOAFQCNBS +FFPXPXOAFQCNBS +CDMGBJANTYXAIV +CDMGBJANTYXAIV +CDMGBJANTYXAIV +CDMGBJANTYXAIV +CDMGBJANTYXAIV +CDMGBJANTYXAIV +KASDHRXLYQOAKZ +KASDHRXLYQOAKZ +KASDHRXLYQOAKZ +KASDHRXLYQOAKZ +WXXSNCNJFUAIDG +WXXSNCNJFUAIDG +HZASIAXCPXTISQ +HZASIAXCPXTISQ +HZASIAXCPXTISQ +ZIMMTPFXOMAJTQ +ZIMMTPFXOMAJTQ +ZIMMTPFXOMAJTQ +MBBCVAKAJPKAKM +MBBCVAKAJPKAKM +DASWEROEPLKSEI +DASWEROEPLKSEI +DASWEROEPLKSEI +LHRXHTKENPCGSZ +LHRXHTKENPCGSZ +LHRXHTKENPCGSZ +ZPSKWMFLCHMEOY +ZPSKWMFLCHMEOY +ZPSKWMFLCHMEOY +ZPSKWMFLCHMEOY +FWIVDMJALNEADT +FWIVDMJALNEADT +FWIVDMJALNEADT +FWIVDMJALNEADT +VIBJAHJNWHZSJP +VIBJAHJNWHZSJP +VIBJAHJNWHZSJP +COFVZFLCAOUMJT +COFVZFLCAOUMJT +COFVZFLCAOUMJT +VFSGAZRYSCNFDF +HYHIYZMIFPJROG +HYHIYZMIFPJROG +HYHIYZMIFPJROG +OUKYUETWWIPKQR +OUKYUETWWIPKQR +OUKYUETWWIPKQR +XPEHHUISIBFLHX +XPEHHUISIBFLHX +XPEHHUISIBFLHX +RAHBGWKEPAQNFF +RAHBGWKEPAQNFF +RAHBGWKEPAQNFF +RAHBGWKEPAQNFF +RAHBGWKEPAQNFF +RAHBGWKEPAQNFF +BXIGJZDQFDFASM +BXIGJZDQFDFASM +BXIGJZDQFDFASM +HQWTUOLCGKIECB +HQWTUOLCGKIECB +HQWTUOLCGKIECB +HQWTUOLCGKIECB +ACWOMSOYIIVIRV +ACWOMSOYIIVIRV +ACWOMSOYIIVIRV +JRNXAQINDCOHGS +JRNXAQINDCOHGS +JRNXAQINDCOHGS +SNDPFEDGFPXNIX +SNDPFEDGFPXNIX +SNDPFEDGFPXNIX +SNDPFEDGFPXNIX +SNDPFEDGFPXNIX +SNDPFEDGFPXNIX +MMLDHJRGTZHNHV +MMLDHJRGTZHNHV +MMLDHJRGTZHNHV +MNPOBXLPCWFONX +MNPOBXLPCWFONX +MNPOBXLPCWFONX +WCILOMUUNVPIKQ +WCILOMUUNVPIKQ +WCILOMUUNVPIKQ +DRSZMILOMUPIBJ +DRSZMILOMUPIBJ +DRSZMILOMUPIBJ +RPNQWWSSADJSGS +RPNQWWSSADJSGS +AZAANWYREOQRFB +AZAANWYREOQRFB +AZAANWYREOQRFB +AZAANWYREOQRFB +AZAANWYREOQRFB +INVTYAOGFAGBOE +INVTYAOGFAGBOE +INVTYAOGFAGBOE +HRNLUBSXIHFDHP +HRNLUBSXIHFDHP +HRNLUBSXIHFDHP +WFSARWQASFQZMG +WFSARWQASFQZMG +WFSARWQASFQZMG +FYBHCRQFSFYWPY +FYBHCRQFSFYWPY +FYBHCRQFSFYWPY +PUQAFIILJICJRR +PUQAFIILJICJRR +DZAUSKKPHXFGNN +DZAUSKKPHXFGNN +DZAUSKKPHXFGNN +AFJRDFWMXUECEW +AFJRDFWMXUECEW +AFJRDFWMXUECEW +AFJRDFWMXUECEW +AFJRDFWMXUECEW +AFJRDFWMXUECEW +JLCCNYVTIWRPIZ +JLCCNYVTIWRPIZ +JLCCNYVTIWRPIZ +WFSLJOPRIJSOJR +PWDLXPJQFNVTNL +PWDLXPJQFNVTNL +PWDLXPJQFNVTNL +NTHMDFGHOCNNOE +NTHMDFGHOCNNOE +NTHMDFGHOCNNOE +KCODNOOPOPTZMO +KCODNOOPOPTZMO +KCODNOOPOPTZMO +XCPPIJCBCWUBNT +XCPPIJCBCWUBNT +XCPPIJCBCWUBNT +SNFYYXUGUBUECJ +SNFYYXUGUBUECJ +SNFYYXUGUBUECJ +PIQCTGMSNWUMAF +PIQCTGMSNWUMAF +PIQCTGMSNWUMAF +PIQCTGMSNWUMAF +PIQCTGMSNWUMAF +PIQCTGMSNWUMAF +QIIVJLHCZUTGSD +QIIVJLHCZUTGSD +QIIVJLHCZUTGSD +XGCRLPUGFWHAGJ +XGCRLPUGFWHAGJ +QJFSABGVXDWMIW +QJFSABGVXDWMIW +QJFSABGVXDWMIW +QJFSABGVXDWMIW +KVHRYLNQDWXAGI +XISMYRQHGUUMGY +XISMYRQHGUUMGY +XISMYRQHGUUMGY +ISJSHQTWOHGCMM +ISJSHQTWOHGCMM +ISJSHQTWOHGCMM +ACVGNKYJVGNLIL +ACVGNKYJVGNLIL +ACVGNKYJVGNLIL +GJUFPAZNBPFNRI +GJUFPAZNBPFNRI +GJUFPAZNBPFNRI +ITFBYYCNYVFPKD +ITFBYYCNYVFPKD +ITFBYYCNYVFPKD +LLVZBTWPGQVVLW +LLVZBTWPGQVVLW +LLVZBTWPGQVVLW +CLRSLRWKONPSRQ +CLRSLRWKONPSRQ +CLRSLRWKONPSRQ +CLRSLRWKONPSRQ +CLRSLRWKONPSRQ +CLRSLRWKONPSRQ +CLRSLRWKONPSRQ +KMRBRMHHDAUXAY +KMRBRMHHDAUXAY +KMRBRMHHDAUXAY +AXJQVVLKUYCICH +AXJQVVLKUYCICH +AXJQVVLKUYCICH +CODBZFJPKJDNDT +CODBZFJPKJDNDT +CODBZFJPKJDNDT +ICECVTFTHRPNOE +ICECVTFTHRPNOE +ICECVTFTHRPNOE +FYXRZDCUJHGULY +FYXRZDCUJHGULY +FYXRZDCUJHGULY +LFVVNPBBFUSSHL +LFVVNPBBFUSSHL +LFVVNPBBFUSSHL +LFVVNPBBFUSSHL +RZXMIHOUHYSGJO +VNIWZCGZPBJWBI +VQPBIJGXSXEOCU +VQPBIJGXSXEOCU +VQPBIJGXSXEOCU +ZQUSFAUAYSEREK +ZQUSFAUAYSEREK +ZQUSFAUAYSEREK +AHFLGPTXSIRAQK +AHFLGPTXSIRAQK +AHFLGPTXSIRAQK +AHFLGPTXSIRAQK +GXDALQBWZGODGZ +GXDALQBWZGODGZ +GXDALQBWZGODGZ +HPZGUSZNXKOMCQ +HPZGUSZNXKOMCQ +HPZGUSZNXKOMCQ +QBNZBMVRFYREHK +QBNZBMVRFYREHK +QBNZBMVRFYREHK +KLWUUPVJTLHYIM +KLWUUPVJTLHYIM +KLWUUPVJTLHYIM +NSXBZYDTTKLTOH +NSXBZYDTTKLTOH +NSXBZYDTTKLTOH +BLNAAWXUNQHVNT +BLNAAWXUNQHVNT +BLNAAWXUNQHVNT +DSMXVSGJIDFLKP +DSMXVSGJIDFLKP +DSMXVSGJIDFLKP +UKKRUIXIDCWALA +UKKRUIXIDCWALA +UKKRUIXIDCWALA +UKKRUIXIDCWALA +UKKRUIXIDCWALA +UKKRUIXIDCWALA +WULUGQONDYDNKY +WULUGQONDYDNKY +PNPFMWIDAKQFPY +PNPFMWIDAKQFPY +LBJCUDZMNPAWPX +LBJCUDZMNPAWPX +LBJCUDZMNPAWPX +CUDVHEFYRIWYQD +CUDVHEFYRIWYQD +CUDVHEFYRIWYQD +YDRQCGICZKAGCQ +YDRQCGICZKAGCQ +YDRQCGICZKAGCQ +NPUXORBZRBIOMQ +NPUXORBZRBIOMQ +NPUXORBZRBIOMQ +NUHCTOLBWMJMLX +NUHCTOLBWMJMLX +LSGRZENCFIIHNV +LSGRZENCFIIHNV +LSGRZENCFIIHNV +HKDLNTKNLJPAIY +HKDLNTKNLJPAIY +HKDLNTKNLJPAIY +NKUDGJUBIVEDTF +NKUDGJUBIVEDTF +NKUDGJUBIVEDTF +PWPNYABQEOGNNC +PWPNYABQEOGNNC +PWPNYABQEOGNNC +CCAWRGNYALGPQH +CCAWRGNYALGPQH +CCAWRGNYALGPQH +NMHVTLJFPDOJOD +NMHVTLJFPDOJOD +NMHVTLJFPDOJOD +CZZCAOGIEGXMBZ +BWDQBBCUWLSASG +BWDQBBCUWLSASG +BWDQBBCUWLSASG +OEBIHOVSAMBXIB +OEBIHOVSAMBXIB +WKDNQONLGXOZRG +WKDNQONLGXOZRG +IVYQPSHHYIAUFO +IVYQPSHHYIAUFO +IVYQPSHHYIAUFO +GWOFUCIGLDBNKM +GWOFUCIGLDBNKM +GWOFUCIGLDBNKM +GWOFUCIGLDBNKM +UJIDKYTZIQTXPM +UJIDKYTZIQTXPM +UJIDKYTZIQTXPM +GBVQSAZHPCDBDY +GBVQSAZHPCDBDY +GBVQSAZHPCDBDY +MVCOAUNKQVWQHZ +MVCOAUNKQVWQHZ +MVCOAUNKQVWQHZ +NETXMUIMUZJUTB +NETXMUIMUZJUTB +WNSNPYIHDMIFOO +WNSNPYIHDMIFOO +WNSNPYIHDMIFOO +BBVORAZSFSZSKG +BBVORAZSFSZSKG +BBVORAZSFSZSKG +JYSLFQTWNRYWJT +JYSLFQTWNRYWJT +JYSLFQTWNRYWJT +GFPPXZDRVCSVNR +GFPPXZDRVCSVNR +GFPPXZDRVCSVNR +UPZNTUYHCRQOIQ +UPZNTUYHCRQOIQ +HHJSKDRCUMVWKF +HHJSKDRCUMVWKF +ZMQSLMZOWVGBSM +ZMQSLMZOWVGBSM +ZMQSLMZOWVGBSM +KFRKRECSIYXARE +KFRKRECSIYXARE +KFRKRECSIYXARE +PWBHUSLMHZLGRN +PWBHUSLMHZLGRN +PWBHUSLMHZLGRN +MYKOWOGZBMOVBJ +MYKOWOGZBMOVBJ +DUUQLWDHNYFUPP +DUUQLWDHNYFUPP +DUUQLWDHNYFUPP +LXFOLMYKSYSZQS +LXFOLMYKSYSZQS +LXFOLMYKSYSZQS +GHBCIXGRCZIPNQ +GHBCIXGRCZIPNQ +XLSYZSRXVVCHLS +XLSYZSRXVVCHLS +XLSYZSRXVVCHLS +XLSYZSRXVVCHLS +XLSYZSRXVVCHLS +XLSYZSRXVVCHLS +JKDGKIBAOAFRPJ +JKDGKIBAOAFRPJ +JKDGKIBAOAFRPJ +CPDGCAFPSYOTGO +CPDGCAFPSYOTGO +CPDGCAFPSYOTGO +FRZNJFWQVYAVCE +FRZNJFWQVYAVCE +FRZNJFWQVYAVCE +BJXLLSAUQIAPDB +BJXLLSAUQIAPDB +WEGLOYDTDILXDA +WEGLOYDTDILXDA +WEGLOYDTDILXDA +VJVDLRVFJTVWEO +VJVDLRVFJTVWEO +VJVDLRVFJTVWEO +ONPGOSVDVDPBCY +ONPGOSVDVDPBCY +ONPGOSVDVDPBCY +SILHYVDKGHXGBL +SILHYVDKGHXGBL +YVQVOQKFMFRVGR +YVQVOQKFMFRVGR +YVQVOQKFMFRVGR +YVQVOQKFMFRVGR +CKHJPWQVLKHBIH +CKHJPWQVLKHBIH +CKHJPWQVLKHBIH +VPVLPCIBKVWFDT +VPVLPCIBKVWFDT +NCSHZXNGQYSKLR +NCSHZXNGQYSKLR +NCSHZXNGQYSKLR +IHAXLPDVOWLUOS +IHAXLPDVOWLUOS +IHAXLPDVOWLUOS +JGWRKYUXBBNENE +JGWRKYUXBBNENE +JGWRKYUXBBNENE +JGWRKYUXBBNENE +JGWRKYUXBBNENE +JGWRKYUXBBNENE +DYLUUSLLRIQKOE +DYLUUSLLRIQKOE +DYLUUSLLRIQKOE +DYLUUSLLRIQKOE +DYLUUSLLRIQKOE +DYLUUSLLRIQKOE +CZGVOBIGEBDYTP +CZGVOBIGEBDYTP +CZGVOBIGEBDYTP +YYBOLPLTQDKXPM +YYBOLPLTQDKXPM +YYBOLPLTQDKXPM +BHUXVRVMMYAXKN +DWEHITNKTMMZBR +DWEHITNKTMMZBR +DWEHITNKTMMZBR +NQFWNRFKRYMGAI +NQFWNRFKRYMGAI +NQFWNRFKRYMGAI +KKVYYGGCHJGEFJ +PEVRGVRHMMZNGI +PEVRGVRHMMZNGI +PEVRGVRHMMZNGI +JTGUGSWLWPKCGF +JTGUGSWLWPKCGF +JTGUGSWLWPKCGF +YRCHYHRCBXNYNU +YRCHYHRCBXNYNU +YRCHYHRCBXNYNU +SUNXHXDJOIXABJ +SUNXHXDJOIXABJ +SUNXHXDJOIXABJ +MKMPWKUAHLTIBJ +MKMPWKUAHLTIBJ +MKMPWKUAHLTIBJ +CWJJHESJXJQCJA +CWJJHESJXJQCJA +QZFHIXARHDBPBY +QZFHIXARHDBPBY +QZFHIXARHDBPBY +AMLYAMJWYAIXIA +AMLYAMJWYAIXIA +AMLYAMJWYAIXIA +AMLYAMJWYAIXIA +OQAHHWOPVDDWHD +OQAHHWOPVDDWHD +OQAHHWOPVDDWHD +GMIZZEXBPRLVIV +GMIZZEXBPRLVIV +GMIZZEXBPRLVIV +ZBRAJOQFSNYJMF +ZBRAJOQFSNYJMF +ZBRAJOQFSNYJMF +PRXXYMVLYKJITB +PRXXYMVLYKJITB +PRXXYMVLYKJITB +KSOVGRCOLZZTPF +KSOVGRCOLZZTPF +KSOVGRCOLZZTPF +UJEAABFSXKCSGI +UJEAABFSXKCSGI +UJEAABFSXKCSGI +BXNRVJLIEMQDOL +BXNRVJLIEMQDOL +BXNRVJLIEMQDOL +BXNRVJLIEMQDOL +BXNRVJLIEMQDOL +BXNRVJLIEMQDOL +BXNRVJLIEMQDOL +AOPORIRPXVMWSL +AOPORIRPXVMWSL +AOPORIRPXVMWSL +GOOYSJIWTIHOGW +GOOYSJIWTIHOGW +GOOYSJIWTIHOGW +GOOYSJIWTIHOGW +CVNXUNVHFJANHX +CVNXUNVHFJANHX +CVNXUNVHFJANHX +DKZYXHCYPUVGAF +DKZYXHCYPUVGAF +DKZYXHCYPUVGAF +QQBGNWWJANJWNY +QQBGNWWJANJWNY +QQBGNWWJANJWNY +QQBGNWWJANJWNY +WUJVPELCYCESAP +YUNQZQREIHWDQT +YUNQZQREIHWDQT +YUNQZQREIHWDQT +AKKCGLXULFRAET +SFRQIPRTNYHJHP +SFRQIPRTNYHJHP +SFRQIPRTNYHJHP +HXAUJHZZPCBFPN +HXAUJHZZPCBFPN +HXAUJHZZPCBFPN +XXJWYDDUDKYVKI +XXJWYDDUDKYVKI +XXJWYDDUDKYVKI +XXJWYDDUDKYVKI +XXJWYDDUDKYVKI +XXJWYDDUDKYVKI +LCFFREMLXLZNHE +LCFFREMLXLZNHE +LCFFREMLXLZNHE +DRCVQVIMGSWRLN +DRCVQVIMGSWRLN +FZOFDZMKSAUTHT +FZOFDZMKSAUTHT +FZOFDZMKSAUTHT +NCKLQXXBRWCYMA +NCKLQXXBRWCYMA +NCKLQXXBRWCYMA +RMYZIRFUCOMQRH +RMYZIRFUCOMQRH +RMYZIRFUCOMQRH +GXALXAKNHIROPE +GXALXAKNHIROPE +NJDRXTDGYFKORP +NJDRXTDGYFKORP +NJDRXTDGYFKORP +TWKWEBMGDALHPN +TWKWEBMGDALHPN +TWKWEBMGDALHPN +GEKDQXSPTHHANP +GEKDQXSPTHHANP +GEKDQXSPTHHANP +GXXKDYZSBGOJQN +GXXKDYZSBGOJQN +GXXKDYZSBGOJQN +PDTYLGXVBIWRIM +PDTYLGXVBIWRIM +PDTYLGXVBIWRIM +ORDHXXHTBUZRCN +RIJLVEAXPNLDTC +RIJLVEAXPNLDTC +RIJLVEAXPNLDTC +JEEJMSUHUZNTCD +JEEJMSUHUZNTCD +JEEJMSUHUZNTCD +WYMCVPPNOFFNGE +WYMCVPPNOFFNGE +WYMCVPPNOFFNGE +JGPXDNKSIXAZEQ +JGPXDNKSIXAZEQ +JGPXDNKSIXAZEQ +SBPRIAGPYFYCRT +SBPRIAGPYFYCRT +SBPRIAGPYFYCRT +SBPRIAGPYFYCRT +SBPRIAGPYFYCRT +UQRAIIGEZLINAT +UQRAIIGEZLINAT +UQRAIIGEZLINAT +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +RDJQCOBTKKAQAH +HUNGUWOZPQBXGX +HUNGUWOZPQBXGX +HUNGUWOZPQBXGX +HUNGUWOZPQBXGX +HUNGUWOZPQBXGX +HUNGUWOZPQBXGX +KSERXGMCDHOLSS +KSERXGMCDHOLSS +KSERXGMCDHOLSS +KSERXGMCDHOLSS +KSERXGMCDHOLSS +KSERXGMCDHOLSS +LTEJRLHKIYCEOX +LTEJRLHKIYCEOX +LTEJRLHKIYCEOX +BJDZBXGJNBMCAV +BJDZBXGJNBMCAV +BJDZBXGJNBMCAV +HUFOZJXAKZVRNJ +HUFOZJXAKZVRNJ +HUFOZJXAKZVRNJ +HUFOZJXAKZVRNJ +LLIFMNUXGDHTRO +LLIFMNUXGDHTRO +LLIFMNUXGDHTRO +IYJSFPQYTFFTKN +IYJSFPQYTFFTKN +IYJSFPQYTFFTKN +NKLGIWNNVDPGCA +NKLGIWNNVDPGCA +NKLGIWNNVDPGCA +GOHCTCOGYKAJLZ +GOHCTCOGYKAJLZ +ATISKRYGYNSRNP +ATISKRYGYNSRNP +ATISKRYGYNSRNP +GBOGMAARMMDZGR +GBOGMAARMMDZGR +GBOGMAARMMDZGR +GBOGMAARMMDZGR +GBOGMAARMMDZGR +GBOGMAARMMDZGR +GBOGMAARMMDZGR +GBOGMAARMMDZGR +ONIHBIZGUJZDHG +ONIHBIZGUJZDHG +ONIHBIZGUJZDHG +TUSCHIFEASZBBF +TUSCHIFEASZBBF +KPBNHDGDUADAGP +KPBNHDGDUADAGP +KPBNHDGDUADAGP +SLRYMOUSQMDJPH +SLRYMOUSQMDJPH +SLRYMOUSQMDJPH +BDUHCSBCVGXTJM +BDUHCSBCVGXTJM +DJUFPMUQJKWIJB +DJUFPMUQJKWIJB +LUJZZYWHBDHDQX +LUJZZYWHBDHDQX +LUJZZYWHBDHDQX +RTUBNVSZHGWRCV +RTUBNVSZHGWRCV +RTUBNVSZHGWRCV +QFYKXKMYVYOUNJ +QFYKXKMYVYOUNJ +QFYKXKMYVYOUNJ +HEKJYZZSCQBJGB +HEKJYZZSCQBJGB +MJSHVHLADKXCML +MJSHVHLADKXCML +MJSHVHLADKXCML +MJSHVHLADKXCML +MJSHVHLADKXCML +MJSHVHLADKXCML +FFPHMUIGESPOTK +BERLXWPRSBJFHO +VXBAJLGYBMTJCY +VXBAJLGYBMTJCY +VXBAJLGYBMTJCY +BEUQXVWXFDOSAQ +BEUQXVWXFDOSAQ +LIBVHXXKHSODII +LIBVHXXKHSODII +LIBVHXXKHSODII +LIBVHXXKHSODII +LIBVHXXKHSODII +LIBVHXXKHSODII +CSSGBPKFVJOAIZ +DCGOHGQJHJXBGW +DCGOHGQJHJXBGW +DCGOHGQJHJXBGW +XKZDWYDHEBCGCG +XKZDWYDHEBCGCG +XKZDWYDHEBCGCG +VYLOOGHLKSNNEK +VYLOOGHLKSNNEK +VYLOOGHLKSNNEK +BGFHMYJZJZLMHW +BGFHMYJZJZLMHW +BGFHMYJZJZLMHW +QSYLKMKIVWJAAK +LBSMEKVVMYSTIH +LBSMEKVVMYSTIH +LBSMEKVVMYSTIH +LBSMEKVVMYSTIH +MHSLDASSAFCCDO +MHSLDASSAFCCDO +MHSLDASSAFCCDO +OEDSFMUSNZDJFD +OEDSFMUSNZDJFD +OEDSFMUSNZDJFD +NPDKXVKJRHPDQT +NPDKXVKJRHPDQT +NPDKXVKJRHPDQT +DMJHZVARRXJSEG +DMJHZVARRXJSEG +DKXZBPBWIGORKP +DKXZBPBWIGORKP +DKXZBPBWIGORKP +PNFMVADNCOGWME +PNFMVADNCOGWME +PNFMVADNCOGWME +GXKRPLQWYWDFQN +GXKRPLQWYWDFQN +GXKRPLQWYWDFQN +NODCQQSEMCESEC +NODCQQSEMCESEC +RSAQARAFWMUYLL +RSAQARAFWMUYLL +RSAQARAFWMUYLL +RSAQARAFWMUYLL +RSAQARAFWMUYLL +RSAQARAFWMUYLL +AHDFWNJLFALBJP +AHDFWNJLFALBJP +AHDFWNJLFALBJP +PFZRXJIYAFANHP +PFZRXJIYAFANHP +PFZRXJIYAFANHP +PSPXJPWGVFNGQI +PSPXJPWGVFNGQI +PSPXJPWGVFNGQI +YCNMAPLPQYQJFC +YCNMAPLPQYQJFC +YCNMAPLPQYQJFC +XPPBBJCBDOEXDN +JCYNMRJCUYVDBC +JCYNMRJCUYVDBC +JCYNMRJCUYVDBC +GZSNGNPLURZQGM +GZSNGNPLURZQGM +GZSNGNPLURZQGM +SJVGFKBLUYAEOK +SJVGFKBLUYAEOK +SJVGFKBLUYAEOK +IFGWYHGYNVGVRB +IFGWYHGYNVGVRB +OHVKUJISCPKSER +OHVKUJISCPKSER +OHVKUJISCPKSER +LMMJFBMMJUMSJS +LMMJFBMMJUMSJS +PGTXVGREXBMCCY +PGTXVGREXBMCCY +PGTXVGREXBMCCY +MIQNXKWDQRNHAU +MIQNXKWDQRNHAU +IDKAKZRYYDCJDU +IDKAKZRYYDCJDU +IDKAKZRYYDCJDU +TYEFSRMOUXWTDN +TYEFSRMOUXWTDN +TYEFSRMOUXWTDN +TYEFSRMOUXWTDN +QSPOQCXMGPDIHI +QSPOQCXMGPDIHI +QSPOQCXMGPDIHI +GEPYBHCJBORHCE +GEPYBHCJBORHCE +GEPYBHCJBORHCE +NCKLQXXBRWCYMA +NCKLQXXBRWCYMA +NCKLQXXBRWCYMA +SDEAXTCZPQIFQM +SDEAXTCZPQIFQM +JKGIMVBQKSRTGX +JKGIMVBQKSRTGX +JKGIMVBQKSRTGX +ADZBMFGQQWPHMJ +ADZBMFGQQWPHMJ +ADZBMFGQQWPHMJ +STLNUMIUXISGQQ +STLNUMIUXISGQQ +STLNUMIUXISGQQ +HRKNNHYKWGYTEN +HRKNNHYKWGYTEN +HRKNNHYKWGYTEN +KPQQGHGDBBJGFA +KPQQGHGDBBJGFA +KPQQGHGDBBJGFA +VEPKQEUBKLEPRA +VEPKQEUBKLEPRA +VEPKQEUBKLEPRA +VEPKQEUBKLEPRA +NEMHKCNXXRQYRF +NEMHKCNXXRQYRF +NEMHKCNXXRQYRF +XUMALORDVCFWKV +RUCYSQLKCYBLDW +RUCYSQLKCYBLDW +RUCYSQLKCYBLDW +RUCYSQLKCYBLDW +JBPUGFODGPKTDW +JBPUGFODGPKTDW +JBPUGFODGPKTDW +ZZWJKLGCDHYVMB +ZZWJKLGCDHYVMB +ZZWJKLGCDHYVMB +QHLITPHIARVDJI +QHLITPHIARVDJI +QHLITPHIARVDJI +RDALZZCKQFLGJP +RDALZZCKQFLGJP +RDALZZCKQFLGJP +DPLMXAYKJZOTKO +DPLMXAYKJZOTKO +DPLMXAYKJZOTKO +FTODTDQFHDJWIQ +FTODTDQFHDJWIQ +FTODTDQFHDJWIQ +WQAVPPWWLLVGFK +WQAVPPWWLLVGFK +WQAVPPWWLLVGFK +GRUWKTIRBBPZSD +GRUWKTIRBBPZSD +GRUWKTIRBBPZSD +XRPSUWYWZUQALB +XRPSUWYWZUQALB +XRPSUWYWZUQALB +DXCUKNQANPLTEJ +DXCUKNQANPLTEJ +DXCUKNQANPLTEJ +DXCUKNQANPLTEJ +DXCUKNQANPLTEJ +DXCUKNQANPLTEJ +CXQHYVUVSFXTMY +CXQHYVUVSFXTMY +CXQHYVUVSFXTMY +FZOFDZMKSAUTHT +FZOFDZMKSAUTHT +ZXBFYBLSJMEBEP +ZXBFYBLSJMEBEP +ZXBFYBLSJMEBEP +JFRJCQJVFMHZOO +JFRJCQJVFMHZOO +JFRJCQJVFMHZOO +JFRJCQJVFMHZOO +GNSVFEJLUPMLCZ +GNSVFEJLUPMLCZ +GNSVFEJLUPMLCZ +XXJXHXJWQSCNPX +XXJXHXJWQSCNPX +XXJXHXJWQSCNPX +MGGBYMDAPCCKCT +MGGBYMDAPCCKCT +MGGBYMDAPCCKCT +DWFGGOFPIISJIT +DWFGGOFPIISJIT +DWFGGOFPIISJIT +VVLHQJDAUIPZFH +VVLHQJDAUIPZFH +VVLHQJDAUIPZFH +UPZWINBEAHDTLA +UPZWINBEAHDTLA +PFMPOBVAYMTUOX +BHKVSOQUPYXVRZ +BHKVSOQUPYXVRZ +BHKVSOQUPYXVRZ +VQYYQSZNRVQLIS +VQYYQSZNRVQLIS +VQYYQSZNRVQLIS +VQYYQSZNRVQLIS +VQYYQSZNRVQLIS +LTGLGIQQZXSLLF +LTGLGIQQZXSLLF +LTGLGIQQZXSLLF +DXYIOARJXVTYJW +DXYIOARJXVTYJW +DXYIOARJXVTYJW +PIBARDGJJAGJAJ +PIBARDGJJAGJAJ +PIBARDGJJAGJAJ +GUWOSEVHCSNYFK +GUWOSEVHCSNYFK +GUWOSEVHCSNYFK +WNEILUNVMHVMPH +QCIJLRJBZDBVDB +QCIJLRJBZDBVDB +QCIJLRJBZDBVDB +NEMNPWINWMHUMR +BQNXBSYSQXSXPT +BQNXBSYSQXSXPT +KXDZWUPUSDCGDD +KXDZWUPUSDCGDD +KXDZWUPUSDCGDD +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +GMPQGWXPDRNCBL +GMPQGWXPDRNCBL +GMPQGWXPDRNCBL +HUUSXLKCTQDPGL +HUUSXLKCTQDPGL +HUUSXLKCTQDPGL +FHCSBLWRGCOVPT +FHCSBLWRGCOVPT +FHCSBLWRGCOVPT +GVBAXIVNAHMIGH +GVBAXIVNAHMIGH +LUBHDINQXIHVLS +LUBHDINQXIHVLS +LUBHDINQXIHVLS +OFWWWKWUCDUISA +OFWWWKWUCDUISA +SJVQHLPISAIATJ +SJVQHLPISAIATJ +SJVQHLPISAIATJ +VYXJULKGMXJVGI +VYXJULKGMXJVGI +VYXJULKGMXJVGI +JFRYYGVYCWYIDQ +JFRYYGVYCWYIDQ +JFRYYGVYCWYIDQ +VKXWOLCNTHXCLF +VKXWOLCNTHXCLF +VKXWOLCNTHXCLF +BWZJBXAPRCVCKQ +BWZJBXAPRCVCKQ +BWZJBXAPRCVCKQ +VGPKUACRBMPJLF +VGPKUACRBMPJLF +GFMMXOIFOQCCGU +GFMMXOIFOQCCGU +GFMMXOIFOQCCGU +FVRYPYDPKSZGNS +MBGGBVCUIVRRBF +MBGGBVCUIVRRBF +MBGGBVCUIVRRBF +MBGGBVCUIVRRBF +MBGGBVCUIVRRBF +MBGGBVCUIVRRBF +IFPPYSWJNWHOLQ +IFPPYSWJNWHOLQ +IFPPYSWJNWHOLQ +GTTDVYCKFQYVNN +GTTDVYCKFQYVNN +UHXFWAHRAMUDLJ +UHXFWAHRAMUDLJ +VQKSCYBKUIDZEI +VQKSCYBKUIDZEI +VQKSCYBKUIDZEI +BCSBXWKRZUPFHW +BCSBXWKRZUPFHW +BCSBXWKRZUPFHW +UASIRTUMPRQVFY +UASIRTUMPRQVFY +UASIRTUMPRQVFY +ATUUNJCZCOMUKD +VPBYZLCHOKSGRX +VPBYZLCHOKSGRX +VPBYZLCHOKSGRX +CDJNNOJINJAXPV +CDJNNOJINJAXPV +CDJNNOJINJAXPV +CDJNNOJINJAXPV +QVMNYGOVNWWFKF +QVMNYGOVNWWFKF +QVMNYGOVNWWFKF +OSUHJPCHFDQAIT +OSUHJPCHFDQAIT +OSUHJPCHFDQAIT +MOTJMGVDPWRKOC +MOTJMGVDPWRKOC +MOTJMGVDPWRKOC +PIEQDBPBBQPLPL +PIEQDBPBBQPLPL +PIEQDBPBBQPLPL +WSNODXPBBALQOF +WSNODXPBBALQOF +WSNODXPBBALQOF +TXEBNKKOLVBTFK +TXEBNKKOLVBTFK +TXEBNKKOLVBTFK +FZQXMGLQANXZRP +FZQXMGLQANXZRP +FZQXMGLQANXZRP +NRSGWEVTVGZDFC +HSKAZIJJKRAJAV +HSKAZIJJKRAJAV +HSKAZIJJKRAJAV +HSKAZIJJKRAJAV +HSKAZIJJKRAJAV +HSKAZIJJKRAJAV +MRYCNTHLPRENBA +MRYCNTHLPRENBA +MRYCNTHLPRENBA +OEQZPFWOEOOISR +OEQZPFWOEOOISR +OEQZPFWOEOOISR +VGXRQCOVGLGFIM +VGXRQCOVGLGFIM +VGXRQCOVGLGFIM +LTUGYAOMCKNTGG +LTUGYAOMCKNTGG +LTUGYAOMCKNTGG +ZTJHTEHADIHZJS +ZTJHTEHADIHZJS +ZTJHTEHADIHZJS +XWBXJBSVYVJAMZ +XWBXJBSVYVJAMZ +GMHIOMMKSMSRLY +GMHIOMMKSMSRLY +GMHIOMMKSMSRLY +QHHSCLARESIWBH +QHHSCLARESIWBH +QHHSCLARESIWBH +QHHSCLARESIWBH +NFEZZTICAUWDHU +NFEZZTICAUWDHU +NFEZZTICAUWDHU +BVRGQPJKSKKGIH +BVRGQPJKSKKGIH +BVRGQPJKSKKGIH +HUXYBQXJVXOMKX +HUXYBQXJVXOMKX +HUXYBQXJVXOMKX +CSMVOZKEWSOFER +CSMVOZKEWSOFER +CSMVOZKEWSOFER +ZTFBIUXIQYRUNT +ZTFBIUXIQYRUNT +ZTFBIUXIQYRUNT +SXWMIXPJPNCXQQ +SXWMIXPJPNCXQQ +SXWMIXPJPNCXQQ +HXWARSZQGAFXJM +HXWARSZQGAFXJM +HXWARSZQGAFXJM +YCRFPWKUUNKNDN +YCRFPWKUUNKNDN +YCRFPWKUUNKNDN +OYONTEXKYJZFHA +OYONTEXKYJZFHA +OYONTEXKYJZFHA +OYONTEXKYJZFHA +FKPLJWGRBCQLTL +FKPLJWGRBCQLTL +FKPLJWGRBCQLTL +HTFNVAVTYILUCF +AYCPARAPKDAOEN +AYCPARAPKDAOEN +AYCPARAPKDAOEN +LXENKEWVEVKKGV +LXENKEWVEVKKGV +LXENKEWVEVKKGV +XQLWNAFCTODIRK +XQLWNAFCTODIRK +XQLWNAFCTODIRK +XQLWNAFCTODIRK +XQLWNAFCTODIRK +XQLWNAFCTODIRK +HUASEDVYRABWCV +HUASEDVYRABWCV +HUASEDVYRABWCV +SIEXFRDYNDREBM +SIEXFRDYNDREBM +SIEXFRDYNDREBM +QQMKTHUGOQDEIL +QQMKTHUGOQDEIL +QQMKTHUGOQDEIL +AUYCNSCKGNAXFS +AUYCNSCKGNAXFS +AUYCNSCKGNAXFS +CEHQLKSLMFIHBF +CEHQLKSLMFIHBF +KXWWYFKVBFUVIZ +KXWWYFKVBFUVIZ +KXWWYFKVBFUVIZ +UIVOZBSCHXCGPS +UIVOZBSCHXCGPS +UIVOZBSCHXCGPS +OOGHGWKBJXQNEJ +OOGHGWKBJXQNEJ +OOGHGWKBJXQNEJ +PUUBADHCONCMPA +JZWUKILTKYJLCN +JZWUKILTKYJLCN +JZWUKILTKYJLCN +QSIYTNYMBWYHAA +QSIYTNYMBWYHAA +QSIYTNYMBWYHAA +SCJXQZZYGYLKJG +SCJXQZZYGYLKJG +SCJXQZZYGYLKJG +OWLQZFQCFCNPKV +OWLQZFQCFCNPKV +OWLQZFQCFCNPKV +OWXBJAPOSQSWAO +OZHWSOOZCIJFQN +OZHWSOOZCIJFQN +OZHWSOOZCIJFQN +YTAOBBFIOAEMLL +YTAOBBFIOAEMLL +YTAOBBFIOAEMLL +QRPZBKAMSFHVRW +QRPZBKAMSFHVRW +QRPZBKAMSFHVRW +KXAAIORSMACJSI +KXAAIORSMACJSI +KXAAIORSMACJSI +ZLZUHACSRMOLLV +ZLZUHACSRMOLLV +ZLZUHACSRMOLLV +WPYWMXNXEZFMAK +WPYWMXNXEZFMAK +WPYWMXNXEZFMAK +WPYWMXNXEZFMAK +WPYWMXNXEZFMAK +WPYWMXNXEZFMAK +XGVXKJKTISMIOW +WCWUXEGQKLTGDX +WCWUXEGQKLTGDX +CSFVFDHRYKBBPD +GJMZWYLOARVASY +GJMZWYLOARVASY +GJMZWYLOARVASY +HYBAKUMPISVZQP +HYBAKUMPISVZQP +HYBAKUMPISVZQP +URWYQGVSPQJGGB +URWYQGVSPQJGGB +URWYQGVSPQJGGB +ACCFLVVUVBJNGT +ACCFLVVUVBJNGT +ACCFLVVUVBJNGT +NUBWFWVVKLRSHS +NUBWFWVVKLRSHS +NUBWFWVVKLRSHS +ATQMRMGXINTJHV +FJHHZXWJVIEFGJ +FJHHZXWJVIEFGJ +FJHHZXWJVIEFGJ +OAVGBZOFDPFGPJ +OAVGBZOFDPFGPJ +OAVGBZOFDPFGPJ +HEDPDFHTQKEORT +HEDPDFHTQKEORT +HEDPDFHTQKEORT +CJNMMPAEIYFQIJ +CJNMMPAEIYFQIJ +CJNMMPAEIYFQIJ +KPHDBQWTCKBKIL +KPHDBQWTCKBKIL +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +UBVZQGOVTLIHLH +SPMVMDHWKHCIDT +SPMVMDHWKHCIDT +SPMVMDHWKHCIDT +MLBVMOWEQCZNCC +MLBVMOWEQCZNCC +MLBVMOWEQCZNCC +MLBVMOWEQCZNCC +MLBVMOWEQCZNCC +MLBVMOWEQCZNCC +SUJUHGSWHZTSEU +SUJUHGSWHZTSEU +SUJUHGSWHZTSEU +NEQSWPCDHDQINX +NEQSWPCDHDQINX +NEQSWPCDHDQINX +RJPNRXFBYZVRIB +RJPNRXFBYZVRIB +RJPNRXFBYZVRIB +HSHPBORBOJIXSQ +HSHPBORBOJIXSQ +HSHPBORBOJIXSQ +YWTBGJGMTBHQTM +YWTBGJGMTBHQTM +YWTBGJGMTBHQTM +RXVZJHDMMKTKDR +RXVZJHDMMKTKDR +RXVZJHDMMKTKDR +KGFYHTZWPPHNLQ +KGFYHTZWPPHNLQ +KGFYHTZWPPHNLQ +TWYCZJMOEMMCGC +TWYCZJMOEMMCGC +TWYCZJMOEMMCGC +QTCSXAUJBQZZSN +QTCSXAUJBQZZSN +QTCSXAUJBQZZSN +VDJHFHXMUKFKET +VDJHFHXMUKFKET +VDJHFHXMUKFKET +VDJHFHXMUKFKET +VDJHFHXMUKFKET +VDJHFHXMUKFKET +MGESDQAAIJOGJA +MGESDQAAIJOGJA +GHJWNRRCRIGGIO +GHJWNRRCRIGGIO +GHJWNRRCRIGGIO +LEQAKWQJCITZNK +LEQAKWQJCITZNK +LEQAKWQJCITZNK +UUROSJLZNDSXRF +UUROSJLZNDSXRF +UUROSJLZNDSXRF +PNDKCRDVVKJPKG +PNDKCRDVVKJPKG +PNDKCRDVVKJPKG +NUBWFWVVKLRSHS +NUBWFWVVKLRSHS +NUBWFWVVKLRSHS +HFKVRXVHZGBRKF +WHPJOAUPIZDJNX +WHPJOAUPIZDJNX +WHPJOAUPIZDJNX +JTJKDYLEMNXXER +JTJKDYLEMNXXER +JTJKDYLEMNXXER +QGAMAWMLTUNPAB +QGAMAWMLTUNPAB +QGAMAWMLTUNPAB +QTQMRBZOBKYXCG +QTQMRBZOBKYXCG +QTQMRBZOBKYXCG +GPLUUMAKBFSDIE +GPLUUMAKBFSDIE +GPLUUMAKBFSDIE +SOVUOXKZCCAWOJ +SOVUOXKZCCAWOJ +SOVUOXKZCCAWOJ +FHYUGAJXYORMHI +ALKJNCZNEOTEMP +ALKJNCZNEOTEMP +ALKJNCZNEOTEMP +PMTLKNOARSHUJB +PMTLKNOARSHUJB +PMTLKNOARSHUJB +ZXWHESBABUHJBE +ZXWHESBABUHJBE +ZXWHESBABUHJBE +HSFAATUFWDDUGW +HSFAATUFWDDUGW +HSFAATUFWDDUGW +MPMFCABZENCRHV +MPMFCABZENCRHV +MPMFCABZENCRHV +YDOATJUIIFWTKQ +YDOATJUIIFWTKQ +YDOATJUIIFWTKQ +YDOATJUIIFWTKQ +HSQAARMBHJCUOK +LJCANTASZGYJLG +LJCANTASZGYJLG +LSFLAQVDISHMNB +LSFLAQVDISHMNB +LSFLAQVDISHMNB +RCWNBHCZYXWDOV +RCWNBHCZYXWDOV +RCWNBHCZYXWDOV +XLTANAWLDBYGFU +XLTANAWLDBYGFU +HWODCHXORCTEGU +HWODCHXORCTEGU +HWODCHXORCTEGU +DYVFBWXIOCLHPP +DYVFBWXIOCLHPP +DYVFBWXIOCLHPP +ZMNWFTYYYCSSTF +ZMNWFTYYYCSSTF +ZMNWFTYYYCSSTF +UGTLDBJIOSYXRR +UGTLDBJIOSYXRR +UGTLDBJIOSYXRR +XNFHHOXCDUAYSR +XNFHHOXCDUAYSR +XNFHHOXCDUAYSR +WEDWLYRQKUTOAX +WEDWLYRQKUTOAX +WEDWLYRQKUTOAX +NQPOCLFSADOXBR +NQPOCLFSADOXBR +NQPOCLFSADOXBR +LLDXOPKUNJTIRF +LLDXOPKUNJTIRF +LLDXOPKUNJTIRF +NBZFRTJWEIHFPF +NBZFRTJWEIHFPF +GAIOPWBQKZMUNO +GAIOPWBQKZMUNO +GAIOPWBQKZMUNO +FZQYCOUBRJEYBC +DOTGPNHGTYJDEP +DOTGPNHGTYJDEP +DOTGPNHGTYJDEP +DOTGPNHGTYJDEP +DOTGPNHGTYJDEP +DOTGPNHGTYJDEP +DOTGPNHGTYJDEP +DOTGPNHGTYJDEP +DOTGPNHGTYJDEP +DOTGPNHGTYJDEP +IBCXZJCWDGCXQT +FBLPQCAQRNSVHB +FBLPQCAQRNSVHB +FBLPQCAQRNSVHB +UFICVEHDQUKCEA +UFICVEHDQUKCEA +VJPPLCNBDLZIFG +VJPPLCNBDLZIFG +VJPPLCNBDLZIFG +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +LSHVYAFMTMFKBA +QKTRIGNWBRHBFV +QKTRIGNWBRHBFV +QKTRIGNWBRHBFV +QKTRIGNWBRHBFV +LZLBRISQTJVZNP +LZLBRISQTJVZNP +LZLBRISQTJVZNP +IJHAXMJRQQTBPL +IJHAXMJRQQTBPL +IJHAXMJRQQTBPL +XHOLNRLADUSQLD +XHOLNRLADUSQLD +XHOLNRLADUSQLD +QLPHOXTXAKOFMU +ZVHNDZWQTBEVRY +ZVHNDZWQTBEVRY +ZVHNDZWQTBEVRY +ZVHNDZWQTBEVRY +COSPVUFTLGQDQL +COSPVUFTLGQDQL +COSPVUFTLGQDQL +KULPPFCRBINTBS +KULPPFCRBINTBS +KULPPFCRBINTBS +OOSUDWRRWZVFEB +OOSUDWRRWZVFEB +OOSUDWRRWZVFEB +KURQKNMKCGYWRJ +KURQKNMKCGYWRJ +KURQKNMKCGYWRJ +KURQKNMKCGYWRJ +BZTIJCSHNVZMES +BZTIJCSHNVZMES +BZTIJCSHNVZMES +FLJOFQUXYAWOPE +FLJOFQUXYAWOPE +FLJOFQUXYAWOPE +FLJOFQUXYAWOPE +FLJOFQUXYAWOPE +FLJOFQUXYAWOPE +FLJOFQUXYAWOPE +FLFGNMFWNBOBGE +FLFGNMFWNBOBGE +FLFGNMFWNBOBGE +MWIASLNTAGRGGA +MWIASLNTAGRGGA +MWIASLNTAGRGGA +IWMCPJZTADUIFX +IWMCPJZTADUIFX +IWMCPJZTADUIFX +IMHZCCZYPHJVMS +IMHZCCZYPHJVMS +IMHZCCZYPHJVMS +XRDVXQQZLHVEQZ +XRDVXQQZLHVEQZ +YJLUBHOZZTYQIP +YJLUBHOZZTYQIP +YJLUBHOZZTYQIP +YSBGRVXJEMSEQY +YSBGRVXJEMSEQY +YSBGRVXJEMSEQY +SUGVYNSRNKFXQM +SUGVYNSRNKFXQM +SUGVYNSRNKFXQM +OVDSPTSBIQCAIN +OVDSPTSBIQCAIN +QCTMYNGDIBTNSK +QCTMYNGDIBTNSK +MVLOQULXIYSERZ +MVLOQULXIYSERZ +MVLOQULXIYSERZ +CEUMAXLRGBKFQP +CEUMAXLRGBKFQP +CEUMAXLRGBKFQP +YBPIBGNBHHGLEB +HZZXWFWVQWMGAR +HZZXWFWVQWMGAR +HZZXWFWVQWMGAR +QQWUGDVOUVUTOY +QQWUGDVOUVUTOY +MLSAQOINCGAULQ +MLSAQOINCGAULQ +MLSAQOINCGAULQ +XVFDNRYZXDHTHT +XVFDNRYZXDHTHT +XVFDNRYZXDHTHT +ZXGGCBQORXDVTE +ZXGGCBQORXDVTE +ZXGGCBQORXDVTE +QBGKPEROWUKSBK +QBGKPEROWUKSBK +QBGKPEROWUKSBK +MRXBCEQZNKUUIP +RSHUJZXWKLIBRE +KXBDTLQSDKGAEB +KXBDTLQSDKGAEB +KXBDTLQSDKGAEB +QJZRFPJCWMNVAV +QJZRFPJCWMNVAV +QJZRFPJCWMNVAV +UMUPQWIGCOZEOY +UMUPQWIGCOZEOY +UMUPQWIGCOZEOY +FTQHGWIXJSSWOY +FTQHGWIXJSSWOY +FTQHGWIXJSSWOY +NAGKYJATVFXZKN +NAGKYJATVFXZKN +NAGKYJATVFXZKN +QKDCLUARMDUUKN +QKDCLUARMDUUKN +QKDCLUARMDUUKN +QKDCLUARMDUUKN +WIJZXSAJMHAVGX +WIJZXSAJMHAVGX +WIJZXSAJMHAVGX +KGBPLKOPSFDBOX +KGBPLKOPSFDBOX +KGBPLKOPSFDBOX +KGBPLKOPSFDBOX +KGBPLKOPSFDBOX +KGBPLKOPSFDBOX +KGBPLKOPSFDBOX +KGBPLKOPSFDBOX +GERJIEKMNDGSCS +GERJIEKMNDGSCS +GERJIEKMNDGSCS +AMHWQBGAKJESFB +AMHWQBGAKJESFB +AMHWQBGAKJESFB +NXLUTEDAEFXMQR +NXLUTEDAEFXMQR +NXLUTEDAEFXMQR +WCIGMFCFPXZRMQ +WCIGMFCFPXZRMQ +WCIGMFCFPXZRMQ +WCIGMFCFPXZRMQ +MVSSJPGNLQPWSW +MVSSJPGNLQPWSW +MVSSJPGNLQPWSW +MAKMQGKJURAJEN +MAKMQGKJURAJEN +MAKMQGKJURAJEN +DDSBPUYZPWNNGH +DDSBPUYZPWNNGH +DDSBPUYZPWNNGH +IVUGFMLRJOCGAS +IVUGFMLRJOCGAS +HVQXFGHHSFTACS +HVQXFGHHSFTACS +HVQXFGHHSFTACS +VVWGPQZBDQVQRC +VVWGPQZBDQVQRC +VVWGPQZBDQVQRC +VVWGPQZBDQVQRC +SPEGERVLTUWZPA +SPEGERVLTUWZPA +SPEGERVLTUWZPA +YTFHCXIPDIHOIA +YTFHCXIPDIHOIA +YTFHCXIPDIHOIA +LLCRBOWRJOUJAE +LLCRBOWRJOUJAE +LLCRBOWRJOUJAE +HNIFCPBQMKPRCX +HNIFCPBQMKPRCX +HNIFCPBQMKPRCX +GTDJOGZANHPKMR +GTDJOGZANHPKMR +GTDJOGZANHPKMR +NBQKINXMPLXUET +NBQKINXMPLXUET +NBQKINXMPLXUET +NBQKINXMPLXUET +NBQKINXMPLXUET +NBQKINXMPLXUET +JCCIICHPRAAMGK +JCCIICHPRAAMGK +JCCIICHPRAAMGK +PGYDRGZVXVVZQC +PGYDRGZVXVVZQC +PGYDRGZVXVVZQC +QYSYOGCIDRANAR +QYSYOGCIDRANAR +QYSYOGCIDRANAR +CTPVNWVUAGMHEJ +CTPVNWVUAGMHEJ +CTPVNWVUAGMHEJ +AFUWQWYPPZFWCO +AFUWQWYPPZFWCO +ZKRWPAYTJMRKLJ +ZKRWPAYTJMRKLJ +ZKRWPAYTJMRKLJ +UNEJSHNDABUZNY +UNEJSHNDABUZNY +UNEJSHNDABUZNY +CGWBJJZOKGZCSJ +CGWBJJZOKGZCSJ +CGWBJJZOKGZCSJ +NPFDWHQSDBWQLH +NPFDWHQSDBWQLH +NPFDWHQSDBWQLH +SGEGOXDYSFKCPT +SGEGOXDYSFKCPT +SGEGOXDYSFKCPT +SGEGOXDYSFKCPT +RYYNGWLOYLRZLK +RYYNGWLOYLRZLK +RYYNGWLOYLRZLK +IZKVIUJIUTXIRH +IZKVIUJIUTXIRH +IZKVIUJIUTXIRH +BVUJMFFRMZRNAT +BVUJMFFRMZRNAT +BVUJMFFRMZRNAT +BVUJMFFRMZRNAT +LQVXSNNAFNGRAH +LQVXSNNAFNGRAH +LQVXSNNAFNGRAH +FZPYULHBUBXPIG +OMPATGZMNFWVOH +OMPATGZMNFWVOH +OMPATGZMNFWVOH +VUVUVNZRUGEAHB +VUVUVNZRUGEAHB +VUVUVNZRUGEAHB +VUVUVNZRUGEAHB +SRADCMOCDMFMPS +SRADCMOCDMFMPS +SRADCMOCDMFMPS +PCHRYHSDDPPZBV +PCHRYHSDDPPZBV +PCHRYHSDDPPZBV +XGEDDGLPNSLBFE +IUVCFHHAEHNCFT +IUVCFHHAEHNCFT +IUVCFHHAEHNCFT +IUVCFHHAEHNCFT +XIYOPDCBBDCGOE +XIYOPDCBBDCGOE +XIYOPDCBBDCGOE +XIYOPDCBBDCGOE +XIYOPDCBBDCGOE +XIYOPDCBBDCGOE +XIYOPDCBBDCGOE +MPVGZUGXCQEXTM +MPVGZUGXCQEXTM +MPVGZUGXCQEXTM +AECDBHGVIIRMOI +AECDBHGVIIRMOI +AECDBHGVIIRMOI +HDAJDNHIBCDLQF +HDAJDNHIBCDLQF +HDAJDNHIBCDLQF +GZONLGPIHCCJOI +GZONLGPIHCCJOI +GZONLGPIHCCJOI +JSKUWFIZUALZLX +JSKUWFIZUALZLX +JSKUWFIZUALZLX +JSKUWFIZUALZLX +CUABMPOJOBCXJI +CUABMPOJOBCXJI +CUABMPOJOBCXJI +WWOXKWLDMLMYQY +WWOXKWLDMLMYQY +VERWOWGGCGHDQE +VERWOWGGCGHDQE +VERWOWGGCGHDQE +VERWOWGGCGHDQE +XNPRQBVQOJZMMA +XNPRQBVQOJZMMA +XNPRQBVQOJZMMA +ODPGGGTTYSGTGO +ODPGGGTTYSGTGO +ODPGGGTTYSGTGO +FWYSMLBETOMXAG +FWYSMLBETOMXAG +VYCMAAOURFJIHD +VYCMAAOURFJIHD +VYCMAAOURFJIHD +VCPMZDWBEWTGNW +VCPMZDWBEWTGNW +VCPMZDWBEWTGNW +OVUNRYUVDVWTTE +OVUNRYUVDVWTTE +OVUNRYUVDVWTTE +HOWDUIVVWDUEED +HOWDUIVVWDUEED +HOWDUIVVWDUEED +LLVPDBRSUHNJQQ +LLVPDBRSUHNJQQ +LLVPDBRSUHNJQQ +VFCRSIORGUNNGT +VFCRSIORGUNNGT +VFCRSIORGUNNGT +MLSQGNCUYAMAHD +MLSQGNCUYAMAHD +MLSQGNCUYAMAHD +DGPGXHRHNRYVDH +DGPGXHRHNRYVDH +DGPGXHRHNRYVDH +BPRNMVDTWIHULJ +BPRNMVDTWIHULJ +BPRNMVDTWIHULJ +VIJCCFFEBCOOIE +VIJCCFFEBCOOIE +VIJCCFFEBCOOIE +NXWASIVXQMMPLM +NXWASIVXQMMPLM +NXWASIVXQMMPLM +NXWASIVXQMMPLM +NXWASIVXQMMPLM +NXWASIVXQMMPLM +ZEXLJFNSKAHNFH +ZEXLJFNSKAHNFH +ZEXLJFNSKAHNFH +XDZKBRJLTGRPSS +XDZKBRJLTGRPSS +XDZKBRJLTGRPSS +BGGMLMAPVODXAU +BGGMLMAPVODXAU +BGGMLMAPVODXAU +RUOLFWZIFNQQGH +RUOLFWZIFNQQGH +RUOLFWZIFNQQGH +LBWQSAZEYIZZCE +LBWQSAZEYIZZCE +LBWQSAZEYIZZCE +BHIAIPWSVYSKJS +BHIAIPWSVYSKJS +BHIAIPWSVYSKJS +BTUWHHFNOHVCMQ +BTUWHHFNOHVCMQ +BTUWHHFNOHVCMQ +XGVXKJKTISMIOW +XGVXKJKTISMIOW +QDBVSOZTVKXUES +QDBVSOZTVKXUES +QDBVSOZTVKXUES +HHFOXYBNULCICF +HHFOXYBNULCICF +HHFOXYBNULCICF +YQLJDECYQDRSBI +YQLJDECYQDRSBI +YQLJDECYQDRSBI +LKXFSTAQMOENSC +LKXFSTAQMOENSC +LKXFSTAQMOENSC +PSPFQEBFYXJZEV +PSPFQEBFYXJZEV +PSPFQEBFYXJZEV +PSPFQEBFYXJZEV +PSPFQEBFYXJZEV +PSPFQEBFYXJZEV +XCBONKHCCRJMNW +ATGQONNRRWKPGJ +ATGQONNRRWKPGJ +ATGQONNRRWKPGJ +ATGQONNRRWKPGJ +VPJXPDLMACOGIZ +VPJXPDLMACOGIZ +BIHURSOREGLQBB +BIHURSOREGLQBB +BIHURSOREGLQBB +DJVYXMINSBMUHH +DJVYXMINSBMUHH +DJVYXMINSBMUHH +JSFCZQSJQXFJDS +WRUWGLUCNBMGPS +WRUWGLUCNBMGPS +WRUWGLUCNBMGPS +DCUDDCGUKZLQLN +DCUDDCGUKZLQLN +DCUDDCGUKZLQLN +LAROZEWEPNAWMD +LAROZEWEPNAWMD +MVXAYIXYYOVALX +MVXAYIXYYOVALX +MVXAYIXYYOVALX +WSMXAUJFLWRPNT +WSMXAUJFLWRPNT +WSMXAUJFLWRPNT +WSMXAUJFLWRPNT +BBQRBOIMSKMFFO +BBQRBOIMSKMFFO +MDJIPXYRSZHCFS +MDJIPXYRSZHCFS +MDJIPXYRSZHCFS +UQRCJCNVNUFYDX +UQRCJCNVNUFYDX +UQRCJCNVNUFYDX +NJZHEQOUHLZCOX +NJZHEQOUHLZCOX +NJZHEQOUHLZCOX +WGEWUYACXPEFPO +WGEWUYACXPEFPO +WGEWUYACXPEFPO +ITIXDWVDFFXNEG +JLYAXFNOILIKPP +HWSHOMMVLGBIDN +HWSHOMMVLGBIDN +HWSHOMMVLGBIDN +UNMWMPXUIXEQJZ +UNMWMPXUIXEQJZ +COLCNDRDBCLVOC +COLCNDRDBCLVOC +COLCNDRDBCLVOC +PFHDWRIVDDIFRP +PFHDWRIVDDIFRP +PFHDWRIVDDIFRP +XXDLWRCUPASJGY +XXDLWRCUPASJGY +YDOAWJHYHGBQFI +YDOAWJHYHGBQFI +YDOAWJHYHGBQFI +JNYHQYRTYFSMSQ +JNYHQYRTYFSMSQ +VFEXODVWKUOZBF +VFEXODVWKUOZBF +VFEXODVWKUOZBF +HJJDBAOLQAWBMH +HJJDBAOLQAWBMH +HJJDBAOLQAWBMH +CLFOYJSEPPNFQZ +CLFOYJSEPPNFQZ +QZUGMNXETPARLI +QZUGMNXETPARLI +CERHKHQEGFSIHF +CERHKHQEGFSIHF +CERHKHQEGFSIHF +VYKCLMALANGCDF +VYKCLMALANGCDF +VYKCLMALANGCDF +HTCJUBZBSJQWBW +HTCJUBZBSJQWBW +HTCJUBZBSJQWBW +GHPUSRLWNSTQIK +GHPUSRLWNSTQIK +GHPUSRLWNSTQIK +PRWSIEBRGXYXAJ +PRWSIEBRGXYXAJ +PRWSIEBRGXYXAJ +GMYLVKUGJMYTFB +GMYLVKUGJMYTFB +VBTUJTGLLREMNW +VBTUJTGLLREMNW +VBTUJTGLLREMNW +KDGFLJKFZUIJMX +KDGFLJKFZUIJMX +KDGFLJKFZUIJMX +KDGFLJKFZUIJMX +KDGFLJKFZUIJMX +KDGFLJKFZUIJMX +IOMXCGDXEUDZAK +IOMXCGDXEUDZAK +IOMXCGDXEUDZAK +YYDUWLSETXNJJT +YYDUWLSETXNJJT +YYDUWLSETXNJJT +VQGBOYBIENNKMI +VQGBOYBIENNKMI +VQGBOYBIENNKMI +VQGBOYBIENNKMI +VQGBOYBIENNKMI +VQGBOYBIENNKMI +SLURUCSFDHKXFR +SLURUCSFDHKXFR +SLURUCSFDHKXFR +RKHSOIYWKCMPHF +RKHSOIYWKCMPHF +RKHSOIYWKCMPHF +ZEXHXVOGJFGTRX +ZEXHXVOGJFGTRX +ZEXHXVOGJFGTRX +PLAVWQHGBMTMFR +PLAVWQHGBMTMFR +PLAVWQHGBMTMFR +YDMJAALVMGFGRY +YDMJAALVMGFGRY +YDMJAALVMGFGRY +LSYANGLAZUZYFX +LSYANGLAZUZYFX +LSYANGLAZUZYFX +UNRCMCRRFYFGFX +UNRCMCRRFYFGFX +UNRCMCRRFYFGFX +KTSOHNHLOLGQCY +KTSOHNHLOLGQCY +KTSOHNHLOLGQCY +GDTQLZHHDRRBEB +GDTQLZHHDRRBEB +GDTQLZHHDRRBEB +ISOCDPQFIXDIMS +ISOCDPQFIXDIMS +ISOCDPQFIXDIMS +QHLVBNKYJGBCQJ +QHLVBNKYJGBCQJ +QHLVBNKYJGBCQJ +WROHEWWOCPRMIA +WROHEWWOCPRMIA +WROHEWWOCPRMIA +BALLNEJQLSTPIO +NUBWFWVVKLRSHS +NUBWFWVVKLRSHS +NUBWFWVVKLRSHS +FSXIBBYWVGWQJL +FSXIBBYWVGWQJL +FSXIBBYWVGWQJL +GIYKJPISDNWSJD +GIYKJPISDNWSJD +GIYKJPISDNWSJD +XGMFVZOKHBRUTL +XGMFVZOKHBRUTL +FJAOGFGHTPYADT +FJAOGFGHTPYADT +FJAOGFGHTPYADT +ZGSXEXBYLJIOGF +ZGSXEXBYLJIOGF +ZGSXEXBYLJIOGF +XYLPKCDRAAYATL +XYLPKCDRAAYATL +XYLPKCDRAAYATL +FWRFPHJSGLYXTD +FWRFPHJSGLYXTD +RDTDWGQDFJPTPD +CEFJVGZHQAGLHS +CEFJVGZHQAGLHS +CEFJVGZHQAGLHS +MLJVGAYSVYMPSB +MLJVGAYSVYMPSB +MLJVGAYSVYMPSB +JWIXXNLOKOAAQT +JWIXXNLOKOAAQT +JWIXXNLOKOAAQT +DPJNKUOXBZSZAI +DPJNKUOXBZSZAI +DPJNKUOXBZSZAI +AOTRIQLYUAFVSC +AOTRIQLYUAFVSC +AOTRIQLYUAFVSC +IDXKJSSOUXWLDB +IDXKJSSOUXWLDB +IDXKJSSOUXWLDB +AEFYFGMSRKDXHZ +AEFYFGMSRKDXHZ +AEFYFGMSRKDXHZ +FJUKOXWSIGULLE +FJUKOXWSIGULLE +FJUKOXWSIGULLE +MFVJXLPANKSLLD +MFVJXLPANKSLLD +MFVJXLPANKSLLD +PXZXYRKDDXKDTK +PXZXYRKDDXKDTK +PXZXYRKDDXKDTK +YKYOQIXTECBVBB +YKYOQIXTECBVBB +YKYOQIXTECBVBB +WPTTVJLTNAWYAO +WPTTVJLTNAWYAO +WPTTVJLTNAWYAO +YWZIODCWLMCMMW +YWZIODCWLMCMMW +YWZIODCWLMCMMW +REQQVBGILUTQNN +LLPWNQMSUYAGQI +LLPWNQMSUYAGQI +LLPWNQMSUYAGQI +FBKMWOJEPMPVTQ +FBKMWOJEPMPVTQ +FBKMWOJEPMPVTQ +ZNPDAYJZIRPRFQ +ZNPDAYJZIRPRFQ +ZNPDAYJZIRPRFQ +TWJGQZBSEMDPQP +TWJGQZBSEMDPQP +TWJGQZBSEMDPQP +DGRJOOOHPBSAHD +DGRJOOOHPBSAHD +CLMQBVUFKIKYLU +CLMQBVUFKIKYLU +CLMQBVUFKIKYLU +BURHGPHDEVGCEZ +BURHGPHDEVGCEZ +BURHGPHDEVGCEZ +SFMJNHNUOVADRW +SFMJNHNUOVADRW +SFMJNHNUOVADRW +DPDZHVCKYBCJHW +GCWCGSPBENFEPE +GCWCGSPBENFEPE +GCWCGSPBENFEPE +HGFOOLONGOBCMP +HGFOOLONGOBCMP +HGFOOLONGOBCMP +ATQAGKAMBISZQM +ATQAGKAMBISZQM +ATQAGKAMBISZQM +WBKCKEHGXNWYMO +WBKCKEHGXNWYMO +GGOFGCMPKAWHEZ +GGOFGCMPKAWHEZ +DQXORJHBZHLLTE +DQXORJHBZHLLTE +DQXORJHBZHLLTE +WJUNQSYQHHIVFX +WJUNQSYQHHIVFX +WJUNQSYQHHIVFX +CYOVYGWNDHLPBF +CYOVYGWNDHLPBF +KABDATZAOUSYES +KABDATZAOUSYES +KABDATZAOUSYES +VIBHJPDPEVVDTB +VIBHJPDPEVVDTB +VIBHJPDPEVVDTB +PLHJCIYEEKOWNM +PLHJCIYEEKOWNM +PLHJCIYEEKOWNM +DVBUEXCIEIAXPM +DVBUEXCIEIAXPM +DVBUEXCIEIAXPM +PCGISRHGYLRXSR +PCGISRHGYLRXSR +PCGISRHGYLRXSR +PCGISRHGYLRXSR +PCGISRHGYLRXSR +ZMELOYOKMZBMRB +ZMELOYOKMZBMRB +ZMELOYOKMZBMRB +BEMNJULZEQTDJY +BEMNJULZEQTDJY +BEMNJULZEQTDJY +QOECJCJVIMVJGX +QOECJCJVIMVJGX +QOECJCJVIMVJGX +BLSNYSFLZAWBIV +BLSNYSFLZAWBIV +BLSNYSFLZAWBIV +VDRYGTNDKXIPSK +VDRYGTNDKXIPSK +VDRYGTNDKXIPSK +LLYYNOVSVPBRGV +LLYYNOVSVPBRGV +LLYYNOVSVPBRGV +IVRXNBXKWIJUQB +IVRXNBXKWIJUQB +IVRXNBXKWIJUQB +IDRGFNPZDVBSSE +IDRGFNPZDVBSSE +ORICVOOXZDVFIP +ORICVOOXZDVFIP +ORICVOOXZDVFIP +MKCYPWYURWOKST +MKCYPWYURWOKST +MKCYPWYURWOKST +VQSZIPCGAGVRRP +VQSZIPCGAGVRRP +VQSZIPCGAGVRRP +SZNYUUZOQHNEKB +XTKLTGBKIDQGQL +GFXPGVPPWWPDPV +GFXPGVPPWWPDPV +GFXPGVPPWWPDPV +XJBAFGLYCZZECZ +XJBAFGLYCZZECZ +XJBAFGLYCZZECZ +CJHXBFSJXDUJHP +CJHXBFSJXDUJHP +CJHXBFSJXDUJHP +GDJANRNMFHNVOW +GDJANRNMFHNVOW +GDJANRNMFHNVOW +NGYNBSHYFOFVLS +NGYNBSHYFOFVLS +NGYNBSHYFOFVLS +ZOIBZSZLMJDVDQ +ZOIBZSZLMJDVDQ +ZOIBZSZLMJDVDQ +FYWRWBSYRGSWIQ +FYWRWBSYRGSWIQ +FYWRWBSYRGSWIQ +FYWRWBSYRGSWIQ +NBAIXBAUHIQQGF +NBAIXBAUHIQQGF +NBAIXBAUHIQQGF +ZBOYJODMIAUJHH +ZBOYJODMIAUJHH +ZBOYJODMIAUJHH +TVZCRIROJQEVOT +TVZCRIROJQEVOT +TVZCRIROJQEVOT +TVZCRIROJQEVOT +MCPUZZJBAHRIPO +MCPUZZJBAHRIPO +MCPUZZJBAHRIPO +BSNKBAPMWCMENP +BSNKBAPMWCMENP +BSNKBAPMWCMENP +XQUKEAYUAYTIBV +XQUKEAYUAYTIBV +XQUKEAYUAYTIBV +ZYSCOUXLBXGGIM +ZYSCOUXLBXGGIM +ZYSCOUXLBXGGIM +GBLBJPZSROAGMF +GBLBJPZSROAGMF +GBLBJPZSROAGMF +GBLBJPZSROAGMF +GBLBJPZSROAGMF +GBLBJPZSROAGMF +NDJJEQIMIJJCLL +NDJJEQIMIJJCLL +NDJJEQIMIJJCLL +IRNJSRAGRIZIHD +IRNJSRAGRIZIHD +IRNJSRAGRIZIHD +YITUGUNLCGLOII +YITUGUNLCGLOII +YITUGUNLCGLOII +OGGOWHOQMIINAZ +OGGOWHOQMIINAZ +IBOVDNBDQHYNJI +IBOVDNBDQHYNJI +IBOVDNBDQHYNJI +TVGAHWWPABTBCX +TVGAHWWPABTBCX +IWCQHVUQEFDRIW +IWCQHVUQEFDRIW +IWCQHVUQEFDRIW +NXQKSXLFSAEQCZ +NXQKSXLFSAEQCZ +NXQKSXLFSAEQCZ +QBXVXKRWOVBUDB +QBXVXKRWOVBUDB +QBXVXKRWOVBUDB +UPKQNCPKPOLASS +UPKQNCPKPOLASS +UPKQNCPKPOLASS +UPKQNCPKPOLASS +UPKQNCPKPOLASS +HHLMWQDRYZAENA +HHLMWQDRYZAENA +HHLMWQDRYZAENA +KEDBAZLDJVHMAV +KEDBAZLDJVHMAV +KEDBAZLDJVHMAV +IXNQUCOVJRJRGJ +IXNQUCOVJRJRGJ +IXNQUCOVJRJRGJ +BRDWIEOJOWJCLU +BRDWIEOJOWJCLU +BRDWIEOJOWJCLU +JYILLRHXRVTRSH +JYILLRHXRVTRSH +ORRNXRYWGDUDOG +ORRNXRYWGDUDOG +ORRNXRYWGDUDOG +PGKXDIMONUAMFR +PGKXDIMONUAMFR +PGKXDIMONUAMFR +ZKXZLIFRWWKZRY +ZKXZLIFRWWKZRY +ZKXZLIFRWWKZRY +DBSMLQTUDJVICQ +DBSMLQTUDJVICQ +DBSMLQTUDJVICQ +VRVJKILQRBSEAG +VRVJKILQRBSEAG +VRVJKILQRBSEAG +TXLUZGFDBDQACL +TXLUZGFDBDQACL +UYYMWNUDIOPESF +UYYMWNUDIOPESF +UYYMWNUDIOPESF +NLGJRBLPUVEYKC +NLGJRBLPUVEYKC +NLGJRBLPUVEYKC +QLRRJMOBVVGXEJ +QLRRJMOBVVGXEJ +QLRRJMOBVVGXEJ +BZXMLCVDKDXRQY +BZXMLCVDKDXRQY +BZXMLCVDKDXRQY +KHWCPNJRJCNVRI +KHWCPNJRJCNVRI +KHWCPNJRJCNVRI +KHWCPNJRJCNVRI +WFXIHQFRQPGCCR +WFXIHQFRQPGCCR +WFXIHQFRQPGCCR +WJBSSBFGPKTMQQ +NHJSWORVNIOXIT +NHJSWORVNIOXIT +NHJSWORVNIOXIT +QMDKVNSQXPVCRD +QMDKVNSQXPVCRD +QMDKVNSQXPVCRD +LONWRQOYFPYMQD +LONWRQOYFPYMQD +LONWRQOYFPYMQD +LONWRQOYFPYMQD +LONWRQOYFPYMQD +LONWRQOYFPYMQD +CYSJNTQNMDWAJV +CYSJNTQNMDWAJV +CYSJNTQNMDWAJV +CMJCXYNUCSMDBY +CMJCXYNUCSMDBY +CMJCXYNUCSMDBY +RMVQVAZRAZGSTH +RMVQVAZRAZGSTH +RMVQVAZRAZGSTH +RMVQVAZRAZGSTH +RMVQVAZRAZGSTH +RMVQVAZRAZGSTH +NKOJNOBJGYTLLZ +NKOJNOBJGYTLLZ +NKOJNOBJGYTLLZ +BBIPVJCGIASXJB +ULNXAWLQFZMIHX +ULNXAWLQFZMIHX +ULNXAWLQFZMIHX +WAAZBVOGWRQLMB +WAAZBVOGWRQLMB +WAAZBVOGWRQLMB +RVEJWGYZBXCGGM +RVEJWGYZBXCGGM +RVEJWGYZBXCGGM +HYPXHDJBILNWLI +HYPXHDJBILNWLI +OTTJIRVZJJGFTK +OTTJIRVZJJGFTK +OTTJIRVZJJGFTK +YHPDOCZSFWEMOD +YHPDOCZSFWEMOD +YHPDOCZSFWEMOD +RAUALYDCIUPMKI +RAUALYDCIUPMKI +KNMFTTWVELIVCC +KNMFTTWVELIVCC +KNMFTTWVELIVCC +XSMABFRQESMONQ +XSMABFRQESMONQ +XSMABFRQESMONQ +JFUAWXPBHXKZGA +MVSQDUZRRVBYLA +MVSQDUZRRVBYLA +MVSQDUZRRVBYLA +KCOQNLYGMQJUJD +KCOQNLYGMQJUJD +KCOQNLYGMQJUJD +HYQBRUSSCIAOOD +LJIFOCRGDDQFJF +GAAICKUTDBZCMT +GAAICKUTDBZCMT +VMLZFUVIKCGATC +VMLZFUVIKCGATC +VMLZFUVIKCGATC +VMLZFUVIKCGATC +ORQGHAJIWGGFJK +ORQGHAJIWGGFJK +ORQGHAJIWGGFJK +JXSVVZKPEDIRTN +AZEXWHKOMMASPA +AZEXWHKOMMASPA +AZEXWHKOMMASPA +AZEXWHKOMMASPA +AZEXWHKOMMASPA +AZEXWHKOMMASPA +VYMILMYEENZHAR +VYMILMYEENZHAR +VYMILMYEENZHAR +AXUZQJFHDNNPFG +AXUZQJFHDNNPFG +AXUZQJFHDNNPFG +XUYURJQIMYCWBB +XUYURJQIMYCWBB +XUYURJQIMYCWBB +MGZKYOAQVGSSGC +MGZKYOAQVGSSGC +MGZKYOAQVGSSGC +DOCINCLJNAXZQF +DOCINCLJNAXZQF +DOCINCLJNAXZQF +YQMRQLBCUBZXEP +YQMRQLBCUBZXEP +YQMRQLBCUBZXEP +AVZCPICCWKMZDT +AVZCPICCWKMZDT +NUCXNEKIESREQY +NUCXNEKIESREQY +NUCXNEKIESREQY +AAOLIMLEFKWKOY +AAOLIMLEFKWKOY +AAOLIMLEFKWKOY +OWCOTUVKROVONT +OWCOTUVKROVONT +QLXULUNLCRKWRD +QLXULUNLCRKWRD +QLXULUNLCRKWRD +QLXULUNLCRKWRD +WLBUICQBNZXIDJ +WLBUICQBNZXIDJ +WLBUICQBNZXIDJ +HIJCSNHREFFOML +HIJCSNHREFFOML +HIJCSNHREFFOML +HYLOONIBWUNKDH +HYLOONIBWUNKDH +HYLOONIBWUNKDH +MKSPBYRGLCNGRC +MKSPBYRGLCNGRC +QLUWQAFDTNAYPN +QLUWQAFDTNAYPN +QLUWQAFDTNAYPN +OFXAEWYLVPBGGU +UMBFDGUGXMOMHX +UMBFDGUGXMOMHX +UMBFDGUGXMOMHX +YDHAGPCZRFQPOI +YDHAGPCZRFQPOI +YDHAGPCZRFQPOI +OYSKUZDIHNKWLV +OYSKUZDIHNKWLV +OYSKUZDIHNKWLV +MZZJNOOADWVFPD +MZZJNOOADWVFPD +MZZJNOOADWVFPD +QCQQONWEDCOTBV +QCQQONWEDCOTBV +QCQQONWEDCOTBV +PDWZXKSZLRVSEH +PDWZXKSZLRVSEH +PDWZXKSZLRVSEH +LOGJQOUIVKBFGH +LOGJQOUIVKBFGH +LOGJQOUIVKBFGH +LOGJQOUIVKBFGH +KQQLBXFPTDVFAJ +KQQLBXFPTDVFAJ +JRZNGLZDQHVIOO +JRZNGLZDQHVIOO +LQTWDAYNGMMHLV +LQTWDAYNGMMHLV +LQTWDAYNGMMHLV +FCAGATFCNDPZOG +FCAGATFCNDPZOG +FCAGATFCNDPZOG +FQWDVNSBYDXPIO +FQWDVNSBYDXPIO +FQWDVNSBYDXPIO +SCGCBAAYLFTIJU +HXMGCTFLLWPVFM +HXMGCTFLLWPVFM +HXMGCTFLLWPVFM +JTSLALYXYSRPGW +JTSLALYXYSRPGW +JTSLALYXYSRPGW +JTSLALYXYSRPGW +HDXDQPRPFRKGKZ +HDXDQPRPFRKGKZ +HDXDQPRPFRKGKZ +HDXDQPRPFRKGKZ +NPGNOVNWUSPMDP +NPGNOVNWUSPMDP +NPGNOVNWUSPMDP +NPGNOVNWUSPMDP +SGEIEGAXKLMUIZ +SGEIEGAXKLMUIZ +SGEIEGAXKLMUIZ +SGEIEGAXKLMUIZ +ICDQFUFDAFKCAX +ICDQFUFDAFKCAX +ICDQFUFDAFKCAX +ICDQFUFDAFKCAX +ICDQFUFDAFKCAX +ICDQFUFDAFKCAX +OBWNXGOQPLDDPS +OBWNXGOQPLDDPS +OBWNXGOQPLDDPS +RZNUIYPHQFXBAN +RZNUIYPHQFXBAN +RZNUIYPHQFXBAN +YNYGVGYGPMQAEL +YNYGVGYGPMQAEL +YNYGVGYGPMQAEL +KKVZKYOBQGDKIB +KKVZKYOBQGDKIB +GFNJQQBUZURQMA +GFNJQQBUZURQMA +GFNJQQBUZURQMA +NNBGCSGCRSCFEA +NNBGCSGCRSCFEA +NNBGCSGCRSCFEA +NNBGCSGCRSCFEA +KPJDVVCDVBFRMU +KPJDVVCDVBFRMU +KPJDVVCDVBFRMU +NGFFVZQXSRKHBM +NGFFVZQXSRKHBM +NGFFVZQXSRKHBM +BNFAYJPQCPZQND +BNFAYJPQCPZQND +BNFAYJPQCPZQND +XIVUGRBSBIXXJE +XIVUGRBSBIXXJE +XIVUGRBSBIXXJE +DDFLFKTXUWPNMV +DDFLFKTXUWPNMV +DDFLFKTXUWPNMV +XQABBHBFHWHMKF +XQABBHBFHWHMKF +XQABBHBFHWHMKF +NAXSRXHZFIBFMI +NAXSRXHZFIBFMI +NAXSRXHZFIBFMI +TWPJJJZCYVFUOA +TWPJJJZCYVFUOA +TWPJJJZCYVFUOA +NMFIXEFNQPDISY +NMFIXEFNQPDISY +NMFIXEFNQPDISY +TYXSIXOYTBHZFA +WCPTUQOMNJBIET +WCPTUQOMNJBIET +WCPTUQOMNJBIET +MIJFNYMSCFYZNY +MIJFNYMSCFYZNY +LLMKBTGLZJIAMY +LLMKBTGLZJIAMY +LLMKBTGLZJIAMY +ISLJZDYAPAUORR +ISLJZDYAPAUORR +ISLJZDYAPAUORR +ARYVAQSYRLZVQD +ARYVAQSYRLZVQD +ARYVAQSYRLZVQD +VNTCGXMLDSKOKN +VNTCGXMLDSKOKN +VNTCGXMLDSKOKN +ZEOQUKRCASTCFR +ZEOQUKRCASTCFR +ZEOQUKRCASTCFR +KEIPNCCJPRMIAX +KEIPNCCJPRMIAX +KEIPNCCJPRMIAX +IDGNCVHQDDOPND +IDGNCVHQDDOPND +MYTWFJKBZGMYCS +MYTWFJKBZGMYCS +MYTWFJKBZGMYCS +PAEBEUZTAPIOIO +PAEBEUZTAPIOIO +PAEBEUZTAPIOIO +LOVMMUBRQUFEAH +LOVMMUBRQUFEAH +LOVMMUBRQUFEAH +VHBJNUOZEQTSNN +VHBJNUOZEQTSNN +VHBJNUOZEQTSNN +NFTMKHWBOINJGM +NFTMKHWBOINJGM +NFTMKHWBOINJGM +HZPYSAHDRSBARR +HZPYSAHDRSBARR +HZPYSAHDRSBARR +HNKGGVGQAVODNJ +HNKGGVGQAVODNJ +ROGUAPYLUCHQGK +ROGUAPYLUCHQGK +ROGUAPYLUCHQGK +MFAKJGXMORSMIX +MFAKJGXMORSMIX +MFAKJGXMORSMIX +JJEGOJPMKLRSPJ +JJEGOJPMKLRSPJ +JJEGOJPMKLRSPJ +AULLUGALUBVBDD +AULLUGALUBVBDD +AULLUGALUBVBDD +SIXLXDIJGIWWFU +SIXLXDIJGIWWFU +SIXLXDIJGIWWFU +LWLOLQIXHMFYND +LWLOLQIXHMFYND +LWLOLQIXHMFYND +VRQMAABPASPXMW +VRQMAABPASPXMW +VRQMAABPASPXMW +BFSMGDJOXZAERB +BFSMGDJOXZAERB +BFSMGDJOXZAERB +BFSMGDJOXZAERB +BFSMGDJOXZAERB +BFSMGDJOXZAERB +GOFXWTVKPWJNGD +GOFXWTVKPWJNGD +GOFXWTVKPWJNGD +KYDURMHFWXCKMW +KYDURMHFWXCKMW +KYDURMHFWXCKMW +NSQSAUGJQHDYNO +NSQSAUGJQHDYNO +NSQSAUGJQHDYNO +VOVZXURTCKPRDQ +VOVZXURTCKPRDQ +VOVZXURTCKPRDQ +KXMZDGSRSGHMMK +KXMZDGSRSGHMMK +RCUDFXMNPQNBDU +RCUDFXMNPQNBDU +RCUDFXMNPQNBDU +RCUDFXMNPQNBDU +CVWXJKQAOSCOAB +CVWXJKQAOSCOAB +CVWXJKQAOSCOAB +AMEROGPZOLAFBN +AMEROGPZOLAFBN +AMEROGPZOLAFBN +YCAZFHUABUMOIM +YCAZFHUABUMOIM +YCAZFHUABUMOIM +LRULVYSBRWUVGR +LRULVYSBRWUVGR +LRULVYSBRWUVGR +WIGFMKMFRGRSDE +WIGFMKMFRGRSDE +WIGFMKMFRGRSDE +DJOVLOYCGXNVPI +DJOVLOYCGXNVPI +DJOVLOYCGXNVPI +OAAZMUGLOXGVNH +OAAZMUGLOXGVNH +OAAZMUGLOXGVNH +UCUHFWIFSHROPY +UCUHFWIFSHROPY +UCUHFWIFSHROPY +AHMKHNVZGOQLRQ +AHMKHNVZGOQLRQ +AHMKHNVZGOQLRQ +UKBGBACORPRCGG +UKBGBACORPRCGG +UKBGBACORPRCGG +UKBGBACORPRCGG +KKKRKRMVJRHDMG +KKKRKRMVJRHDMG +KKKRKRMVJRHDMG +GEVVQZHMFVFGLN +GEVVQZHMFVFGLN +GEVVQZHMFVFGLN +LBFYQISQYCGDDW +NHTKGYOMICWFQZ +NHTKGYOMICWFQZ +NHTKGYOMICWFQZ +PPSNFPASKFYPMN +PPSNFPASKFYPMN +PPSNFPASKFYPMN +NGQPRVWTFNBUHA +NGQPRVWTFNBUHA +NGQPRVWTFNBUHA +MNOOVRNGPIWJDI +MNOOVRNGPIWJDI +MNOOVRNGPIWJDI +PWEMRMLJCWKESY +PWEMRMLJCWKESY +PWEMRMLJCWKESY +DHMTURDWPRKSOA +DHMTURDWPRKSOA +DHMTURDWPRKSOA +CEPAXRIKSUXHHB +CEPAXRIKSUXHHB +CEPAXRIKSUXHHB +AWDJJMXJUOHGLC +AWDJJMXJUOHGLC +AWDJJMXJUOHGLC +XPLZTJWZDBFWDE +XPLZTJWZDBFWDE +XPLZTJWZDBFWDE +QXURFIGBRGWPQD +QXURFIGBRGWPQD +QXURFIGBRGWPQD +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +BLJRIMJGRPQVNF +IRGYSXZCDAWOOC +IRGYSXZCDAWOOC +IRGYSXZCDAWOOC +WRCGBYNVBFVRTN +WRCGBYNVBFVRTN +WRCGBYNVBFVRTN +TYQXKHPOXXXCTP +TYQXKHPOXXXCTP +TYQXKHPOXXXCTP +AMCGLRWKUQPNKD +AMCGLRWKUQPNKD +AMCGLRWKUQPNKD +DTDZLJHKVNTQGZ +DTDZLJHKVNTQGZ +YQQZZYYQTCPEAS +YQQZZYYQTCPEAS +YQQZZYYQTCPEAS +LYPCULYCGFOIDA +LYPCULYCGFOIDA +LYPCULYCGFOIDA +RWNAOXLCVXJMGM +RWNAOXLCVXJMGM +RWNAOXLCVXJMGM +AKSIZPIFQAYJGF +AKSIZPIFQAYJGF +AKSIZPIFQAYJGF +BYTNEISLBIENSA +BYTNEISLBIENSA +CPNXCPWXQQMNFG +CPNXCPWXQQMNFG +CPNXCPWXQQMNFG +FFPXPXOAFQCNBS +FFPXPXOAFQCNBS +TWKYXZSXXXKKJU +TWKYXZSXXXKKJU +TWKYXZSXXXKKJU +OUSFTKFNBAZUKL +OUSFTKFNBAZUKL +OUSFTKFNBAZUKL +WZPBZJONDBGPKJ +WZPBZJONDBGPKJ +WZPBZJONDBGPKJ +WZPBZJONDBGPKJ +WZPBZJONDBGPKJ +WZPBZJONDBGPKJ +WZPBZJONDBGPKJ +ISCHOARKJADAKJ +ISCHOARKJADAKJ +HFNKQEVNSGCOJV +HFNKQEVNSGCOJV +HFNKQEVNSGCOJV +HFNKQEVNSGCOJV +HFNKQEVNSGCOJV +HFNKQEVNSGCOJV +MUGXRYIUWFITCP +MUGXRYIUWFITCP +MUGXRYIUWFITCP +ZSDCIRYNTCVTMF +ZSDCIRYNTCVTMF +ZSDCIRYNTCVTMF +AMADCPJVPLUGQO +AMADCPJVPLUGQO +AMADCPJVPLUGQO +LQQYARMJQBHKQQ +LQQYARMJQBHKQQ +LQQYARMJQBHKQQ +YBTGTVGEKMZEQX +YBTGTVGEKMZEQX +YBTGTVGEKMZEQX +UPNUIXSCZBYVBB +UPNUIXSCZBYVBB +UPNUIXSCZBYVBB +BGLLICFSSKPUMR +BGLLICFSSKPUMR +BGLLICFSSKPUMR +CYADPSMQNARVII +CYADPSMQNARVII +CYADPSMQNARVII +QZKGUNQLVFEEBA +QZKGUNQLVFEEBA +ASOADIZOVZTJSR +ASOADIZOVZTJSR +ASOADIZOVZTJSR +UZWDCWONPYILKI +UZWDCWONPYILKI +UZWDCWONPYILKI +UZWDCWONPYILKI +UZWDCWONPYILKI +UZWDCWONPYILKI +MZPVEMOYADUARK +MZPVEMOYADUARK +MZPVEMOYADUARK +KEEHEUGOPCFXAV +KEEHEUGOPCFXAV +KEEHEUGOPCFXAV +ZLGNYFOIDAVMHY +ZLGNYFOIDAVMHY +MEAQCLPMSVEOQF +MEAQCLPMSVEOQF +MEAQCLPMSVEOQF +NEYNJQRKHLUJRU +NEYNJQRKHLUJRU +NEYNJQRKHLUJRU +MBWUSSKCCUMJHO +MBWUSSKCCUMJHO +RQTOOFIXOKYGAN +RQTOOFIXOKYGAN +RQTOOFIXOKYGAN +XRWSZZJLZRKHHD +XRWSZZJLZRKHHD +YQYFEGTYCUQBEI +YQYFEGTYCUQBEI +YQYFEGTYCUQBEI +DEQITUUQPICUMR +DEQITUUQPICUMR +DEQITUUQPICUMR +DEQITUUQPICUMR +DEQITUUQPICUMR +DEQITUUQPICUMR +DEQITUUQPICUMR +DEQITUUQPICUMR +NJBFJCJKWWIKRD +NJBFJCJKWWIKRD +NJBFJCJKWWIKRD +QPSUYVALAOXFGL +QPSUYVALAOXFGL +QPSUYVALAOXFGL +CDQRIIUMNLMHRH +CDQRIIUMNLMHRH +CDQRIIUMNLMHRH +KAXNDTMKFONXJM +KAXNDTMKFONXJM +KAXNDTMKFONXJM +CLWDCBBEVQRZLY +CLWDCBBEVQRZLY +CLWDCBBEVQRZLY +IASPBORHOMBZMY +IASPBORHOMBZMY +IASPBORHOMBZMY +IASPBORHOMBZMY +IASPBORHOMBZMY +IASPBORHOMBZMY +LPATWVFSBNDSHR +LPATWVFSBNDSHR +LPATWVFSBNDSHR +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +ZOCKGJZEUVPPPI +PDYXPCKITKHFOZ +PDYXPCKITKHFOZ +PDYXPCKITKHFOZ +PIMQWRZWLQKKBJ +PIMQWRZWLQKKBJ +PIMQWRZWLQKKBJ +MPUQHZXIXSTTDU +MPUQHZXIXSTTDU +MPUQHZXIXSTTDU +MPUQHZXIXSTTDU +MPUQHZXIXSTTDU +MPUQHZXIXSTTDU +PLHJCIYEEKOWNM +PLHJCIYEEKOWNM +PLHJCIYEEKOWNM +YUUGYIUSCYNSQR +YUUGYIUSCYNSQR +YUUGYIUSCYNSQR +ALJORCZKMBZYCR +ALJORCZKMBZYCR +ALJORCZKMBZYCR +WDPFJWLDPVQCAJ +WDPFJWLDPVQCAJ +WDPFJWLDPVQCAJ +MOSKATHMXWSZTQ +MOSKATHMXWSZTQ +QYYZXEPEVBXNNA +QYYZXEPEVBXNNA +QYYZXEPEVBXNNA +CJHWFIUASFBCKN +CJHWFIUASFBCKN +CJHWFIUASFBCKN +RNRYULFRLCBRQS +RNRYULFRLCBRQS +RNRYULFRLCBRQS +FWJMVZAVAUGMDX +FWJMVZAVAUGMDX +FWJMVZAVAUGMDX +IBEWMFVUBLAYJT +IBEWMFVUBLAYJT +IBEWMFVUBLAYJT +JYYLVUFNAHSSFE +JYYLVUFNAHSSFE +JYYLVUFNAHSSFE +AYJRTVVIBJSSKN +AYJRTVVIBJSSKN +AYJRTVVIBJSSKN +KVLFRAWTRWDEDF +KVLFRAWTRWDEDF +QKKIWEILHCXECO +QKKIWEILHCXECO +QKKIWEILHCXECO +XKLPRHHLSQBUIC +XKLPRHHLSQBUIC +XKLPRHHLSQBUIC +XXSSGBYXSKOLAM +XXSSGBYXSKOLAM +XXSSGBYXSKOLAM +LGGHDPFKSSRQNS +LGGHDPFKSSRQNS +LGGHDPFKSSRQNS +LGGHDPFKSSRQNS +LGGHDPFKSSRQNS +LGGHDPFKSSRQNS +OHUHVTCQTUDPIJ +OHUHVTCQTUDPIJ +OHUHVTCQTUDPIJ +VFTGDXPPYSWBSO +VFTGDXPPYSWBSO +VFTGDXPPYSWBSO +AAJMQTLFRTZCJK +AAJMQTLFRTZCJK +AAJMQTLFRTZCJK +YCVGLKWJKIKVBI +YCVGLKWJKIKVBI +YCVGLKWJKIKVBI +XPPKZMFJCSEUSX +XPPKZMFJCSEUSX +XPPKZMFJCSEUSX +MPQWYPLPWGUMJE +MPQWYPLPWGUMJE +MPQWYPLPWGUMJE +LFKQSJNCVRGFCC +LFKQSJNCVRGFCC +LFKQSJNCVRGFCC +FAXXYODRCHXHTQ +FAXXYODRCHXHTQ +FAXXYODRCHXHTQ +ZDZSFWLPCFRASW +ZDZSFWLPCFRASW +ZDZSFWLPCFRASW +ZDZSFWLPCFRASW +ZDZSFWLPCFRASW +ZDZSFWLPCFRASW +DSICVZUZCUHARI +DSICVZUZCUHARI +DSICVZUZCUHARI +HLCHESOMJVGDSJ +HLCHESOMJVGDSJ +HLCHESOMJVGDSJ +SJVQHLPISAIATJ +SJVQHLPISAIATJ +SJVQHLPISAIATJ +KTEIFNKAUNYNJU +KTEIFNKAUNYNJU +KTEIFNKAUNYNJU +KJTYZDORHCDZPS +VVZNWYXIOADGSW +VVZNWYXIOADGSW +VVZNWYXIOADGSW +RGYMFGHHIDRCBN +RGYMFGHHIDRCBN +RGYMFGHHIDRCBN +FLZZFWBNYJNHMY +FLZZFWBNYJNHMY +FLZZFWBNYJNHMY +FLZZFWBNYJNHMY +CDOVNWNANFFLFJ +CDOVNWNANFFLFJ +GTUIRORNXIOHQR +GTUIRORNXIOHQR +GTUIRORNXIOHQR +QZXVLRCMAHJVIP +QZXVLRCMAHJVIP +QZXVLRCMAHJVIP +NXUDOCUNEVFUGK +NXUDOCUNEVFUGK +NXUDOCUNEVFUGK +BVRDQVRQVGRNHG +FNYGWXSATBUBER +FNYGWXSATBUBER +FNYGWXSATBUBER +RFSMUFRPPYDYRD +ZTUJNJAKTLHBEX +ZTUJNJAKTLHBEX +ZTUJNJAKTLHBEX +DOBZFFWLHXORTB +DOBZFFWLHXORTB +IBPVXAOOVUAOKJ +IBPVXAOOVUAOKJ +XLIBABIFOBYHSV +XLIBABIFOBYHSV +XLIBABIFOBYHSV +OBDOVFRMEYHSQB +OBDOVFRMEYHSQB +OBDOVFRMEYHSQB +OBDOVFRMEYHSQB +QDITZBLZQQZVEE +QDITZBLZQQZVEE +YBIFMTGYWXNIRZ +YBIFMTGYWXNIRZ +YBIFMTGYWXNIRZ +ALJIEVIJBAJISI +ALJIEVIJBAJISI +ALJIEVIJBAJISI +VNBRGSXVFBYQNN +VNBRGSXVFBYQNN +VNBRGSXVFBYQNN +IYQTYHISVSPMSU +IYQTYHISVSPMSU +HCWMMJROAJNTCM +HCWMMJROAJNTCM +HCWMMJROAJNTCM +SWZXEVABPLUDIO +SWZXEVABPLUDIO +SWZXEVABPLUDIO +IFWUBRBMMNTBRZ +IFWUBRBMMNTBRZ +IFWUBRBMMNTBRZ +MTJHLONVHHPNSI +MTJHLONVHHPNSI +MTJHLONVHHPNSI +FCNQMDSJHADDFT +FCNQMDSJHADDFT +FCNQMDSJHADDFT +RYTGHNMOSCSWJT +RYTGHNMOSCSWJT +RYTGHNMOSCSWJT +UYMSIPINLJNNOU +UYMSIPINLJNNOU +UYMSIPINLJNNOU +YEVOZZZLKJKCCD +YEVOZZZLKJKCCD +YEVOZZZLKJKCCD +XQJWTJLJEYIUDZ +XQJWTJLJEYIUDZ +XQJWTJLJEYIUDZ +XTRUQJBVQBUKSQ +XTRUQJBVQBUKSQ +XTRUQJBVQBUKSQ +FKSFKBQGSFSOSM +FKSFKBQGSFSOSM +FKSFKBQGSFSOSM +GFJRASPBQLDRRY +GFJRASPBQLDRRY +GFJRASPBQLDRRY +BBGHHIUQOKQCBW +BBGHHIUQOKQCBW +BBGHHIUQOKQCBW +CATQHDWESBRRQA +CATQHDWESBRRQA +CATQHDWESBRRQA +SSNKNUIFMZUJTL +USNCWPSRPOWEBG +USNCWPSRPOWEBG +USNCWPSRPOWEBG +FJPQEOQGIZSLES +FJPQEOQGIZSLES +FJPQEOQGIZSLES +WPFUFWIHMYZXSF +WPFUFWIHMYZXSF +WPFUFWIHMYZXSF +WPFUFWIHMYZXSF +SEXUXSMBJLNXIR +SEXUXSMBJLNXIR +FTLDJPRFCGDUFH +FTLDJPRFCGDUFH +FTLDJPRFCGDUFH +FTLDJPRFCGDUFH +FTLDJPRFCGDUFH +FTLDJPRFCGDUFH +FTLDJPRFCGDUFH +FTLDJPRFCGDUFH +FTLDJPRFCGDUFH +FTLDJPRFCGDUFH +VOYCNOJFAJAILW +VOYCNOJFAJAILW +VOYCNOJFAJAILW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +XRARAKHBJHWUHW +JWEBCHOGBDMGBY +JWEBCHOGBDMGBY +JWEBCHOGBDMGBY +QBGDVCZDAPRIMJ +QBGDVCZDAPRIMJ +QBGDVCZDAPRIMJ +OZVBMTJYIDMWIL +OZVBMTJYIDMWIL +OZVBMTJYIDMWIL +OZVBMTJYIDMWIL +OZVBMTJYIDMWIL +GQCXHIKRWBIQMD +GQCXHIKRWBIQMD +GQCXHIKRWBIQMD +VIWYGRDFHWYDRW +VIWYGRDFHWYDRW +VIWYGRDFHWYDRW +BIOWRMNRHMERIO +BIOWRMNRHMERIO +BIOWRMNRHMERIO +QJIMSJUUARCROQ +QJIMSJUUARCROQ +QJIMSJUUARCROQ +HLTKOFPQDKJCAN +HLTKOFPQDKJCAN +HLTKOFPQDKJCAN +JXGIYKRRPGCLFV +JXGIYKRRPGCLFV +JXGIYKRRPGCLFV +NMICSFNNFDNGEL +NMICSFNNFDNGEL +NMICSFNNFDNGEL +QFCXANHHBCGMAS +QFCXANHHBCGMAS +QFCXANHHBCGMAS +DPZSYTMLVCLGRU +DPZSYTMLVCLGRU +DPZSYTMLVCLGRU +JDVPWEYIVOQCDX +JDVPWEYIVOQCDX +JDVPWEYIVOQCDX +DEDHMXBDEJSZFE +DEDHMXBDEJSZFE +DEDHMXBDEJSZFE +NVHPXYIRNJFKTE +NVHPXYIRNJFKTE +NVHPXYIRNJFKTE +NVHPXYIRNJFKTE +LIRYPHYGHXZJBZ +LIRYPHYGHXZJBZ +LIRYPHYGHXZJBZ +LIRYPHYGHXZJBZ +VFBILHPIHUPBPZ +VFBILHPIHUPBPZ +VFBILHPIHUPBPZ +GHVIMBCFLRTFHI +GHVIMBCFLRTFHI +GHVIMBCFLRTFHI +JWNPDZNEKVCWMY +JWNPDZNEKVCWMY +JWNPDZNEKVCWMY +GHOSNRCGJFBJIB +GHOSNRCGJFBJIB +GHOSNRCGJFBJIB +GHOSNRCGJFBJIB +GHOSNRCGJFBJIB +GHOSNRCGJFBJIB +NKUNFNVAHJNALA +NKUNFNVAHJNALA +NKUNFNVAHJNALA +LXZMHBHEXAELHH +LXZMHBHEXAELHH +LXZMHBHEXAELHH +PROGRNRRJJYCNX +PROGRNRRJJYCNX +PROGRNRRJJYCNX +DYLJVOXRWLXDIG +DYLJVOXRWLXDIG +DYLJVOXRWLXDIG +MFSSHRCJKRDIOL +MFSSHRCJKRDIOL +MFSSHRCJKRDIOL +XRVDGNKRPOAQTN +XRVDGNKRPOAQTN +XRVDGNKRPOAQTN +XHBVYDAKJHETMP +XHBVYDAKJHETMP +XHBVYDAKJHETMP +XHBVYDAKJHETMP +XHBVYDAKJHETMP +YOHYSYJDKVYCJI +AFOKREIUUQFDNW +AFOKREIUUQFDNW +AFOKREIUUQFDNW +DWYRIWUZIJHQKQ +DWYRIWUZIJHQKQ +WBSWWONMTZEOGS +WBSWWONMTZEOGS +WBSWWONMTZEOGS +KJDAGXLMHXUAGV +KJDAGXLMHXUAGV +HAGOWCONESKMDW +HAGOWCONESKMDW +HHJIZLMOCIYWJF +IFSDAJWBUCMOAH +IFSDAJWBUCMOAH +IFSDAJWBUCMOAH +RRZVGDGTWNQAPW +RRZVGDGTWNQAPW +RRZVGDGTWNQAPW +XJRUWGFZGQNPPD +XJRUWGFZGQNPPD +XJRUWGFZGQNPPD +GTPHQORJKFJIRB +GTPHQORJKFJIRB +GTPHQORJKFJIRB +GTPHQORJKFJIRB +NENFGFHRYIOMTM +NENFGFHRYIOMTM +NENFGFHRYIOMTM +CXEGAUYXQAKHKJ +CXEGAUYXQAKHKJ +GLYMPHUVMRFTFV +GLYMPHUVMRFTFV +GLYMPHUVMRFTFV +ALSKYCOJJPXPFS +ALSKYCOJJPXPFS +ALSKYCOJJPXPFS +ALSKYCOJJPXPFS +ZRTQSJFIDWNVJW +ZRTQSJFIDWNVJW +ZRTQSJFIDWNVJW +TUVCWJQQGGETHL +TUVCWJQQGGETHL +QWDMZDSZMVJFFJ +QWDMZDSZMVJFFJ +QWDMZDSZMVJFFJ +SUSDGTMJKOGWSZ +SUSDGTMJKOGWSZ +SUSDGTMJKOGWSZ +CJGYSWNGNKCJSB +CJGYSWNGNKCJSB +CJGYSWNGNKCJSB +CJGYSWNGNKCJSB +CJGYSWNGNKCJSB +CJGYSWNGNKCJSB +BWAKMLKESHKOHK +BWAKMLKESHKOHK +BWAKMLKESHKOHK +YNFDIGJKJPNFFD +YNFDIGJKJPNFFD +YNFDIGJKJPNFFD +GGXRLUDNGFFUKI +GGXRLUDNGFFUKI +GGXRLUDNGFFUKI +QWAXKHKRTORLEM +QWAXKHKRTORLEM +FFYNAVGJSYHHFO +FFYNAVGJSYHHFO +FFYNAVGJSYHHFO +OIZSVTOIBNSVOS +YDMBNDUHUNWWRP +YDMBNDUHUNWWRP +YDMBNDUHUNWWRP +VAPSMQAHNAZRKC +VAPSMQAHNAZRKC +VAPSMQAHNAZRKC +DKFYGSWCJGXEJY +DKFYGSWCJGXEJY +DKFYGSWCJGXEJY +GKOVHCFOVLXKFL +GKOVHCFOVLXKFL +GKOVHCFOVLXKFL +JTZZSQYMACOLNN +JTZZSQYMACOLNN +JTZZSQYMACOLNN +YCWSUKQGVSGXJO +YCWSUKQGVSGXJO +YCWSUKQGVSGXJO +KAKPGJJRYRYSTP +KAKPGJJRYRYSTP +KAKPGJJRYRYSTP +RRMJMHOQSALEJJ +RRMJMHOQSALEJJ +QNLSCNDZNSALTM +QNLSCNDZNSALTM +GKTSTVGKOKZFKP +GKTSTVGKOKZFKP +GKTSTVGKOKZFKP +YCXFHPUBGMMWJQ +YCXFHPUBGMMWJQ +YCXFHPUBGMMWJQ +WVJTXYIHBUISHX +WVJTXYIHBUISHX +WVJTXYIHBUISHX +WDHOIABIERMLGY +WDHOIABIERMLGY +OFRMASLPWOMYHN +OFRMASLPWOMYHN +OFRMASLPWOMYHN +HHICWLZMNOCMIQ +HHICWLZMNOCMIQ +HHICWLZMNOCMIQ +CEBMEQPREMCWOL +CEBMEQPREMCWOL +CEBMEQPREMCWOL +FHWSAZXFPUMKFL +FHWSAZXFPUMKFL +FHWSAZXFPUMKFL +FYDWDCIFZSGNBU +FYDWDCIFZSGNBU +FYDWDCIFZSGNBU +BKUIZWILNWHFHD +BKUIZWILNWHFHD +BKUIZWILNWHFHD +AVAACINZEOAHHE +AVAACINZEOAHHE +AVAACINZEOAHHE +RMNPQEWLGQURNX +RMNPQEWLGQURNX +RMNPQEWLGQURNX +DHMLNZRDVQLQBB +DHMLNZRDVQLQBB +DHMLNZRDVQLQBB +OCBXPCSXEQQADU +OCBXPCSXEQQADU +OCBXPCSXEQQADU +CZKPOZZJODAYPZ +CZKPOZZJODAYPZ +SNUDIPVBUUXCDG +SNUDIPVBUUXCDG +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +BNVPFDRNGHMRJS +BNVPFDRNGHMRJS +BNVPFDRNGHMRJS +XGJCUFHRNSRFBO +XGJCUFHRNSRFBO +VHQVOTINPRYDAO +VHQVOTINPRYDAO +VHQVOTINPRYDAO +ZRBFCAALKKNCJG +ZRBFCAALKKNCJG +ZRBFCAALKKNCJG +JTLXCMOFVBXEKD +JTLXCMOFVBXEKD +JTLXCMOFVBXEKD +JTLXCMOFVBXEKD +JTLXCMOFVBXEKD +SOIZAFVNIXAZFQ +SOIZAFVNIXAZFQ +SOIZAFVNIXAZFQ +KGRLRBFIDBTADP +KGRLRBFIDBTADP +KGRLRBFIDBTADP +FTAKPNRZIJEFIG +FTAKPNRZIJEFIG +FTAKPNRZIJEFIG +RYCBSFIKWACFBY +RYCBSFIKWACFBY +RYCBSFIKWACFBY +RYCBSFIKWACFBY +ZPPUMAMZIMPJGP +ZPPUMAMZIMPJGP +ZPPUMAMZIMPJGP +ITMGVSSHWMTJRR +ITMGVSSHWMTJRR +ITMGVSSHWMTJRR +WEBVQIJGIZVRGA +WEBVQIJGIZVRGA +SJRVJRYZAQYCEE +SJRVJRYZAQYCEE +SJRVJRYZAQYCEE +IIXWYSCJSQVBQM +IIXWYSCJSQVBQM +IIXWYSCJSQVBQM +XCPGHVQEEXUHNC +XCPGHVQEEXUHNC +XCPGHVQEEXUHNC +XCPGHVQEEXUHNC +FIVSJYGQAIEMOC +FIVSJYGQAIEMOC +FIVSJYGQAIEMOC +RVYZAZTXLLAVGZ +RVYZAZTXLLAVGZ +RVYZAZTXLLAVGZ +KMSKQZKKOZQFFG +KMSKQZKKOZQFFG +KMSKQZKKOZQFFG +HIBPKFXWOPYJPZ +HIBPKFXWOPYJPZ +HIBPKFXWOPYJPZ +ZCNBZFRECRPCKU +ZCNBZFRECRPCKU +ZCNBZFRECRPCKU +YPPSMYLMSKHYAY +YPPSMYLMSKHYAY +YPPSMYLMSKHYAY +ATALOFNDEOCMKK +ATALOFNDEOCMKK +ATALOFNDEOCMKK +VWAMTBXLZPEDQO +VWAMTBXLZPEDQO +VWAMTBXLZPEDQO +ZRTQSJFIDWNVJW +ZRTQSJFIDWNVJW +ZRTQSJFIDWNVJW +XQMNBTZLYOOAGA +XQMNBTZLYOOAGA +XQMNBTZLYOOAGA +JWJOTENAMICLJG +LNELWUPBSLZUIQ +LNELWUPBSLZUIQ +LNELWUPBSLZUIQ +XIIOFHFUYBLOLW +XIIOFHFUYBLOLW +XIIOFHFUYBLOLW +NDYXAJZYGMHQDN +NDYXAJZYGMHQDN +NDYXAJZYGMHQDN +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +QAYHKBLKSXWOEO +QAYHKBLKSXWOEO +QAYHKBLKSXWOEO +NFHSJYKXENYICE +NFHSJYKXENYICE +NFHSJYKXENYICE +NFHSJYKXENYICE +NFHSJYKXENYICE +NFHSJYKXENYICE +QLFGDTPACJHLRY +QLFGDTPACJHLRY +QLFGDTPACJHLRY +YQZNKYXGZSVEHI +YQZNKYXGZSVEHI +YQZNKYXGZSVEHI +GPSZYOIFQZPWEJ +KHXXMSARUQULRI +KHXXMSARUQULRI +KHXXMSARUQULRI +KPWSJANDNDDRMB +KPWSJANDNDDRMB +KPWSJANDNDDRMB +QZZUEBNBZAPZLX +QZZUEBNBZAPZLX +QZZUEBNBZAPZLX +QZZUEBNBZAPZLX +QZZUEBNBZAPZLX +QZZUEBNBZAPZLX +QZZUEBNBZAPZLX +HLORMQRMDNZHJH +HLORMQRMDNZHJH +HLORMQRMDNZHJH +RGZXAQQHXALOBL +RGZXAQQHXALOBL +RGZXAQQHXALOBL +QVIIZVVDZZHGCB +QVIIZVVDZZHGCB +QVIIZVVDZZHGCB +XKRAKQXQVIGYQC +XKRAKQXQVIGYQC +XKRAKQXQVIGYQC +MKSKJVIBSRUWSZ +MKSKJVIBSRUWSZ +MKSKJVIBSRUWSZ +JOGKUKXHTYWRGZ +OGLMUIRZIMTHMN +OGLMUIRZIMTHMN +OGLMUIRZIMTHMN +PLHJDBGFXBMTGZ +PLHJDBGFXBMTGZ +PLHJDBGFXBMTGZ +PLHJDBGFXBMTGZ +IVZQUWCWXYFPOQ +IVZQUWCWXYFPOQ +IVZQUWCWXYFPOQ +PXQATVYJKMMHAU +PXQATVYJKMMHAU +PXQATVYJKMMHAU +SBJLJOFPWOYATP +SBJLJOFPWOYATP +SBJLJOFPWOYATP +VHOZWHQPEJGPCC +VHOZWHQPEJGPCC +VHOZWHQPEJGPCC +KFSKTWYDIHJITF +KFSKTWYDIHJITF +KFSKTWYDIHJITF +IEFFSHLHNYVSEF +IEFFSHLHNYVSEF +IEFFSHLHNYVSEF +BVXLAHSJXXSWFF +BVXLAHSJXXSWFF +BVXLAHSJXXSWFF +LCDDAGSJHKEABN +LCDDAGSJHKEABN +LCDDAGSJHKEABN +OJKONCJPCULNOW +OJKONCJPCULNOW +OJKONCJPCULNOW +NKZDEFKPZSLQRF +NKZDEFKPZSLQRF +NKZDEFKPZSLQRF +CWIXCQOSULUGBT +CWIXCQOSULUGBT +CWIXCQOSULUGBT +DXJRNQYAYGIHLF +DXJRNQYAYGIHLF +DXJRNQYAYGIHLF +OFKGGSVHXHMDDN +OFKGGSVHXHMDDN +OFKGGSVHXHMDDN +FOHHNHSLJDZUGQ +FOHHNHSLJDZUGQ +FOHHNHSLJDZUGQ +ICZPANLPYRTVSF +ICZPANLPYRTVSF +ICZPANLPYRTVSF +ZAGGGZCIFUQHOH +ZAGGGZCIFUQHOH +USZYSDMBJDPRIF +USZYSDMBJDPRIF +USZYSDMBJDPRIF +JVOZATDVXUSPKC +JVOZATDVXUSPKC +JVOZATDVXUSPKC +JQULIQJSYPZQMA +JQULIQJSYPZQMA +JQULIQJSYPZQMA +OCNJYMSNHNAZON +OCNJYMSNHNAZON +OCNJYMSNHNAZON +KVNBVHCJAUXKPJ +KVNBVHCJAUXKPJ +KVNBVHCJAUXKPJ +KLTJHVNRXQKMLY +KLTJHVNRXQKMLY +KLTJHVNRXQKMLY +MPDQVXKSEUGRGO +MPDQVXKSEUGRGO +MPDQVXKSEUGRGO +UCJGJABZCDBEDK +UCJGJABZCDBEDK +UCJGJABZCDBEDK +FNQDSYKGBCVHHI +FNQDSYKGBCVHHI +KWJDHELCGJFUHW +KWJDHELCGJFUHW +KWJDHELCGJFUHW +KQMPRSZTUSSXND +KQMPRSZTUSSXND +KQMPRSZTUSSXND +AXRCEOKUDYDWLF +AXRCEOKUDYDWLF +AXRCEOKUDYDWLF +LTXBFJFJUIJOQE +LTXBFJFJUIJOQE +LTXBFJFJUIJOQE +GYCPCOJTCINIFZ +GYCPCOJTCINIFZ +GYCPCOJTCINIFZ +HMUMWSORCUWQJO +HMUMWSORCUWQJO +HMUMWSORCUWQJO +MPMKMQHJHDHPBE +MPMKMQHJHDHPBE +MPMKMQHJHDHPBE +GEHZIZWHNLQFAS +GEHZIZWHNLQFAS +GEHZIZWHNLQFAS +YAISOECYKYATLL +YAISOECYKYATLL +YAISOECYKYATLL +FJKKCRCBBAXLQZ +AAHNBILIYONQLX +AAHNBILIYONQLX +AAHNBILIYONQLX +QSFGZNVRVZHUGV +QSFGZNVRVZHUGV +QSFGZNVRVZHUGV +LHHCSNFAOIFYRV +LHHCSNFAOIFYRV +BUPRVECGWBHCQV +BUPRVECGWBHCQV +BUPRVECGWBHCQV +BHTWDJBVZQBRKP +BHTWDJBVZQBRKP +ARYQHSWJGHCGJS +ARYQHSWJGHCGJS +MFXPJGJSKHZZGC +MFXPJGJSKHZZGC +MFXPJGJSKHZZGC +ACRHBAYQBXXRTO +ACRHBAYQBXXRTO +ACRHBAYQBXXRTO +KRNAOFGYEFKHPB +KRNAOFGYEFKHPB +KRNAOFGYEFKHPB +BTNNPSLJPBRMLZ +BTNNPSLJPBRMLZ +BTNNPSLJPBRMLZ +LJWMTSMUQJNHOC +LJWMTSMUQJNHOC +LJWMTSMUQJNHOC +ANGUXJDGJCHGOG +ANGUXJDGJCHGOG +ANGUXJDGJCHGOG +HWJWNWZJUYCGKV +HWJWNWZJUYCGKV +HWJWNWZJUYCGKV +FJYGFTHLNNSVPY +FJYGFTHLNNSVPY +FJYGFTHLNNSVPY +KACGMLSYPGROFF +KACGMLSYPGROFF +KACGMLSYPGROFF +HCDAVCLCBXIYPW +HCDAVCLCBXIYPW +HCDAVCLCBXIYPW +LDMWSLGGVTVJPG +LDMWSLGGVTVJPG +LDMWSLGGVTVJPG +LDMWSLGGVTVJPG +ZPVQIJIWGMKMQN +ZPVQIJIWGMKMQN +ZPVQIJIWGMKMQN +FFXGOBFBYCOXAJ +FFXGOBFBYCOXAJ +FFXGOBFBYCOXAJ +ZNHUFUZDUQRKBB +ZNHUFUZDUQRKBB +ZNHUFUZDUQRKBB +ZHYXJQQBKROZDX +QFLGNZXBWIQDLQ +QFLGNZXBWIQDLQ +QFLGNZXBWIQDLQ +SIBDJDZVNXVLEX +SIBDJDZVNXVLEX +SIBDJDZVNXVLEX +NDKGACIWVAOUQH +NDKGACIWVAOUQH +QBDAEJRHUCSSPR +QBDAEJRHUCSSPR +QBDAEJRHUCSSPR +ZBRAJOQFSNYJMF +ZBRAJOQFSNYJMF +ZBRAJOQFSNYJMF +LGWDVWIZDPGCFG +LGWDVWIZDPGCFG +LGWDVWIZDPGCFG +VJCLAPUACUQZOV +VJCLAPUACUQZOV +VJCLAPUACUQZOV +UUPZYAHONNHULX +UUPZYAHONNHULX +UUPZYAHONNHULX +AHJUHHDDCJQACA +AHJUHHDDCJQACA +OTGQTQBPQCRNRG +OTGQTQBPQCRNRG +OTGQTQBPQCRNRG +IKLGYJACVCXYIL +IKLGYJACVCXYIL +KBXLMOYQNDMHQT +ITBGJNVZJBVPLJ +ITBGJNVZJBVPLJ +ITBGJNVZJBVPLJ +QBACGOWRJDBXSG +QBACGOWRJDBXSG +QBACGOWRJDBXSG +JGEBLDKNWBUGRZ +JGEBLDKNWBUGRZ +JGEBLDKNWBUGRZ +OZSZELOMMMKWTM +OZSZELOMMMKWTM +OZSZELOMMMKWTM +COATXBHZYVUJQP +COATXBHZYVUJQP +COATXBHZYVUJQP +DCHROQCNJDJPGN +MUNFBYOTGGMQOS +MUNFBYOTGGMQOS +MUNFBYOTGGMQOS +NCZYSQOTAYFTNM +NCZYSQOTAYFTNM +NCZYSQOTAYFTNM +OSAMZQJKSCAOHA +OSAMZQJKSCAOHA +QVZCXCJXTMIDME +QVZCXCJXTMIDME +QVZCXCJXTMIDME +QVZCXCJXTMIDME +QYDUEIJZRKTNKN +QYDUEIJZRKTNKN +QYDUEIJZRKTNKN +COKUNRYWXTVUAH +COKUNRYWXTVUAH +COKUNRYWXTVUAH +OHUHVTCQTUDPIJ +OHUHVTCQTUDPIJ +OHUHVTCQTUDPIJ +SUNCACOTKLUNHD +SUNCACOTKLUNHD +ANUJDLRACOBTTB +ANUJDLRACOBTTB +UOBYJVFBFSLCTQ +UOBYJVFBFSLCTQ +UOBYJVFBFSLCTQ +KORNTPPJEAJQIU +KORNTPPJEAJQIU +KORNTPPJEAJQIU +FIVYCSWOCXEWSE +FIVYCSWOCXEWSE +FIVYCSWOCXEWSE +PPUYOYQTTWJTIU +PPUYOYQTTWJTIU +PPUYOYQTTWJTIU +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +SGTNSNPWRIOYBX +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +JXACCOKEEPXHCF +JXACCOKEEPXHCF +JXACCOKEEPXHCF +FJCUPROCOFFUSR +FJCUPROCOFFUSR +FJCUPROCOFFUSR +FJCUPROCOFFUSR +FJCUPROCOFFUSR +FJCUPROCOFFUSR +FJCUPROCOFFUSR +RXRVCJFGSOVYLG +RXRVCJFGSOVYLG +RXRVCJFGSOVYLG +PILMFSWQYWYOJC +PILMFSWQYWYOJC +PILMFSWQYWYOJC +PILMFSWQYWYOJC +VURDNNVAYZDGDK +VURDNNVAYZDGDK +VURDNNVAYZDGDK +NLFLXLJXEIUQDL +NLFLXLJXEIUQDL +VANSZAOQCMTTPB +VANSZAOQCMTTPB +RZGFWGNCSYUEPR +RZGFWGNCSYUEPR +RZGFWGNCSYUEPR +SWTMOFFYOXKQNN +SWTMOFFYOXKQNN +SWTMOFFYOXKQNN +KOYXXLLNCXWUNF +KOYXXLLNCXWUNF +HRJWSEPIRZRGCL +HRJWSEPIRZRGCL +HRJWSEPIRZRGCL +YHGSTSNEOJUIRN +YHGSTSNEOJUIRN +YHGSTSNEOJUIRN +GWEJFLVSOGNLSS +GWEJFLVSOGNLSS +GWEJFLVSOGNLSS +OLWRVVHPJFLNPW +OLWRVVHPJFLNPW +OLWRVVHPJFLNPW +JTWOMNBEOCYFNV +JTWOMNBEOCYFNV +JTWOMNBEOCYFNV +ZDOBSAPHUUUOHX +ZDOBSAPHUUUOHX +ZDOBSAPHUUUOHX +MJHHFDJNRRCUOB +MJHHFDJNRRCUOB +MJHHFDJNRRCUOB +ZVVXAODXPVWGMF +ZVVXAODXPVWGMF +ZVVXAODXPVWGMF +JOPCJJSYRPUEDS +JOPCJJSYRPUEDS +JOPCJJSYRPUEDS +BMOUOZDRMBLNSI +BMOUOZDRMBLNSI +BMOUOZDRMBLNSI +MNVXADPCMINSEC +MNVXADPCMINSEC +MNVXADPCMINSEC +WOAOENGFAAUUGT +WOAOENGFAAUUGT +WOAOENGFAAUUGT +WABTUXPZUNQNCC +WABTUXPZUNQNCC +WABTUXPZUNQNCC +UAUIUKWPKRJZJV +UAUIUKWPKRJZJV +UAUIUKWPKRJZJV +JKKRYYTVQXUOKL +JKKRYYTVQXUOKL +JKKRYYTVQXUOKL +SYWHWWKOIJCMKF +CMSUJGUHYXQSOK +CMSUJGUHYXQSOK +CMSUJGUHYXQSOK +LMGXQBQAUALFTB +LMGXQBQAUALFTB +LNENLABLFGGAFF +LNENLABLFGGAFF +LNENLABLFGGAFF +KKRRTZFDLYCBDK +KKRRTZFDLYCBDK +KKRRTZFDLYCBDK +QLLWRTHDHRGHQZ +QLLWRTHDHRGHQZ +QLLWRTHDHRGHQZ +UEPXBTCUIIGYCY +UEPXBTCUIIGYCY +AFRGWGGHJYMSDU +AFRGWGGHJYMSDU +AFRGWGGHJYMSDU +QRJTZIJWDLJKQO +ZSWMIFNWDQEXDT +ZSWMIFNWDQEXDT +ZSWMIFNWDQEXDT +UFPFGVNKHCLJJO +UFPFGVNKHCLJJO +UFPFGVNKHCLJJO +UFPFGVNKHCLJJO +VIQCWEGEHRBLAC +VIQCWEGEHRBLAC +VIQCWEGEHRBLAC +OLQFKFSAJNUOPT +OLQFKFSAJNUOPT +OLQFKFSAJNUOPT +UXQDWARBDDDTKG +UXQDWARBDDDTKG +UXQDWARBDDDTKG +BNTAEJNPQLMGDJ +BNTAEJNPQLMGDJ +BNTAEJNPQLMGDJ +PWVXXGRKLHYWKM +PWVXXGRKLHYWKM +PWVXXGRKLHYWKM +AXWRAIIIBRLXBP +AXWRAIIIBRLXBP +AXWRAIIIBRLXBP +WIIAMRXFUJLYEF +WIIAMRXFUJLYEF +WIIAMRXFUJLYEF +BDABGOLMYNHHTR +BDABGOLMYNHHTR +BDABGOLMYNHHTR +QLDDENZBVHBRKN +QLDDENZBVHBRKN +QLDDENZBVHBRKN +NREKKBAMVWQRES +NREKKBAMVWQRES +NREKKBAMVWQRES +UFMNTAVTSIJODG +UFMNTAVTSIJODG +UFMNTAVTSIJODG +ONIHSXKWNFYNNS +ONIHSXKWNFYNNS +ONIHSXKWNFYNNS +YZRXTIGAQRIAEX +YZRXTIGAQRIAEX +FWMNVWWHGCHHJJ +FWMNVWWHGCHHJJ +FWMNVWWHGCHHJJ +NGFUHJWVBKTNOE +NGFUHJWVBKTNOE +NGFUHJWVBKTNOE +NDTSRXAMMQDVSW +NDTSRXAMMQDVSW +NDTSRXAMMQDVSW +BMGQWWVMWDBQGC +BMGQWWVMWDBQGC +BMGQWWVMWDBQGC +GQPMJOXQJUGJPG +GQPMJOXQJUGJPG +GQPMJOXQJUGJPG +YYOOFJZTRCPVFD +YYOOFJZTRCPVFD +YYOOFJZTRCPVFD +PAQUFWFUOVDUIO +PAQUFWFUOVDUIO +PAQUFWFUOVDUIO +BKUISYCLLXCBJV +BKUISYCLLXCBJV +BKUISYCLLXCBJV +QKVFMAAIXZONRN +QKVFMAAIXZONRN +QKVFMAAIXZONRN +LMVUVKIGGHXSJX +LMVUVKIGGHXSJX +LMVUVKIGGHXSJX +GKRBWXABVALDGQ +GKRBWXABVALDGQ +GKRBWXABVALDGQ +YOVVNQKCSKSHKT +YOVVNQKCSKSHKT +YOVVNQKCSKSHKT +HIYAVKIYRIFSCZ +HIYAVKIYRIFSCZ +HIYAVKIYRIFSCZ +HIYAVKIYRIFSCZ +HESSNRGIEVBPRB +HESSNRGIEVBPRB +HESSNRGIEVBPRB +IPBLCOKXDQHSQW +IPBLCOKXDQHSQW +IPBLCOKXDQHSQW +ATPYDXUUBCDYKQ +ATPYDXUUBCDYKQ +ATPYDXUUBCDYKQ +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +FBSKJMQYURKNSU +ZNLVYSJQUMALEO +ZNLVYSJQUMALEO +ZNLVYSJQUMALEO +VVJSZYWIEBDKTC +VVJSZYWIEBDKTC +VVJSZYWIEBDKTC +GSZMUPHKOPBPPS +GSZMUPHKOPBPPS +GSZMUPHKOPBPPS +GSZMUPHKOPBPPS +QIUASFSNWYMDFS +QIUASFSNWYMDFS +QIUASFSNWYMDFS +OCZIMUMAPGQEBH +OCZIMUMAPGQEBH +OCZIMUMAPGQEBH +PLVGDGRBPMVYPB +PLVGDGRBPMVYPB +PLVGDGRBPMVYPB +NCDZABJPWMBMIQ +NCDZABJPWMBMIQ +NCDZABJPWMBMIQ +OMWCXCBGEFHCTN +OMWCXCBGEFHCTN +WQKVVTLTCHDAST +ZDXUKAKRHYTAKV +ZDXUKAKRHYTAKV +ZDXUKAKRHYTAKV +VDKNIVFIPSLUFD +VDKNIVFIPSLUFD +VDKNIVFIPSLUFD +HEVHTYMYEMEBPX +HEVHTYMYEMEBPX +HEVHTYMYEMEBPX +KVHKWAZUPPBMLL +KVHKWAZUPPBMLL +KVHKWAZUPPBMLL +GBHKWXUSQTVIBN +GBHKWXUSQTVIBN +GBHKWXUSQTVIBN +DLAGRCZUELSZFG +DLAGRCZUELSZFG +DLAGRCZUELSZFG +PVTAIJDQJJZCJP +PVTAIJDQJJZCJP +PVTAIJDQJJZCJP +UQZCQKXJAXKZQH +UQZCQKXJAXKZQH +UQZCQKXJAXKZQH +NVUJDKDVOZVALT +NVUJDKDVOZVALT +NKMQWLPBEJJYCN +NKMQWLPBEJJYCN +NKMQWLPBEJJYCN +DRHKJLXJIQTDTD +DRHKJLXJIQTDTD +DRHKJLXJIQTDTD +GUXHBMASAHGULD +GUXHBMASAHGULD +GUXHBMASAHGULD +MRXASGVUQJVWMP +MRXASGVUQJVWMP +MRXASGVUQJVWMP +KRSBPLFMLHNMPU +KRSBPLFMLHNMPU +KRSBPLFMLHNMPU +BRZGXSNAXRPPFI +BRZGXSNAXRPPFI +SOJUSNIBPPMLCC +SOJUSNIBPPMLCC +SOJUSNIBPPMLCC +KIALCSMRIHRFPL +KIALCSMRIHRFPL +KIALCSMRIHRFPL +MQQNFDZXWVTQEH +MQQNFDZXWVTQEH +MQQNFDZXWVTQEH +MQQNFDZXWVTQEH +NNKPHNTWNILINE +NNKPHNTWNILINE +NNKPHNTWNILINE +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +CJEJFFCPVBZSIE +CJEJFFCPVBZSIE +CJEJFFCPVBZSIE +VCKUSRYTPJJLNI +VCKUSRYTPJJLNI +VCKUSRYTPJJLNI +RKEWSXXUOLRFBX +RKEWSXXUOLRFBX +RKEWSXXUOLRFBX +OPYGFNJSCUDTBT +OPYGFNJSCUDTBT +OPYGFNJSCUDTBT +ABGOSOMRWSYAOB +ABGOSOMRWSYAOB +ABGOSOMRWSYAOB +XGZZHZMWIXFATA +XGZZHZMWIXFATA +XGZZHZMWIXFATA +HZCWPKGYTCJSEB +HZCWPKGYTCJSEB +HZCWPKGYTCJSEB +KJNNWYBAOPXVJY +VCKUSRYTPJJLNI +VCKUSRYTPJJLNI +VCKUSRYTPJJLNI +VCKUSRYTPJJLNI +MLDQJTXFUGDVEO +MLDQJTXFUGDVEO +MLDQJTXFUGDVEO +MLDQJTXFUGDVEO +MLDQJTXFUGDVEO +MLDQJTXFUGDVEO +MLDQJTXFUGDVEO +MLDQJTXFUGDVEO +MLDQJTXFUGDVEO +GUXXEUUYCAYESJ +GUXXEUUYCAYESJ +BLSQLHNBWJLIBQ +BLSQLHNBWJLIBQ +BLSQLHNBWJLIBQ +BLSQLHNBWJLIBQ +HAYYBYPASCDWEQ +HAYYBYPASCDWEQ +HAYYBYPASCDWEQ +HKSZLNNOFSGOKW +HKSZLNNOFSGOKW +HKSZLNNOFSGOKW +HKSZLNNOFSGOKW +HKSZLNNOFSGOKW +HKSZLNNOFSGOKW +KJSGTWFWVTYPFZ +KJSGTWFWVTYPFZ +KJSGTWFWVTYPFZ +AJFKKXIBHCRFJO +AJFKKXIBHCRFJO +AJFKKXIBHCRFJO +BMQGVNUXMIRLCK +BMQGVNUXMIRLCK +XBBRLCXCBCZIOI +XBBRLCXCBCZIOI +XBBRLCXCBCZIOI +NSVFSAJIGAJDMR +NSVFSAJIGAJDMR +NSVFSAJIGAJDMR +MJNIWUJSIGSWKK +MJNIWUJSIGSWKK +MJNIWUJSIGSWKK +QAGYKUNXZHXKMR +QAGYKUNXZHXKMR +QAGYKUNXZHXKMR +QAGYKUNXZHXKMR +FDLYAMZZIXQODN +FDLYAMZZIXQODN +FDLYAMZZIXQODN +AKQXQLUNFKDZBN +AKQXQLUNFKDZBN +WHBIGIKBNXZKFE +WHBIGIKBNXZKFE +WHBIGIKBNXZKFE +DAIKHDNSXMZDCU +DAIKHDNSXMZDCU +DAIKHDNSXMZDCU +YWQFJNWMWZMXRW +YWQFJNWMWZMXRW +YWQFJNWMWZMXRW +XUZMWHLSFXCVMG +XUZMWHLSFXCVMG +XUZMWHLSFXCVMG +XUZMWHLSFXCVMG +XUZMWHLSFXCVMG +XUZMWHLSFXCVMG +ANZXOIAKUNOVQU +ANZXOIAKUNOVQU +ANZXOIAKUNOVQU +ANZXOIAKUNOVQU +ANZXOIAKUNOVQU +MQXWPWOCXGARRK +MQXWPWOCXGARRK +MQXWPWOCXGARRK +RRYFPNITZGCUPZ +RRYFPNITZGCUPZ +RRYFPNITZGCUPZ +YRBWLEAMGAGYBK +YRBWLEAMGAGYBK +YRBWLEAMGAGYBK +XHOJEECXVUMYMF +XHOJEECXVUMYMF +XHOJEECXVUMYMF +YYNXYOVXFJJJHD +YYNXYOVXFJJJHD +KKHCZENFFDIZHM +KKHCZENFFDIZHM +KKHCZENFFDIZHM +KBUZBQVCBVDWKX +KBUZBQVCBVDWKX +KBUZBQVCBVDWKX +FABRBEGQMXBELT +FABRBEGQMXBELT +FABRBEGQMXBELT +VLPGAOXBMXGNGM +VLPGAOXBMXGNGM +VLPGAOXBMXGNGM +NUIKTBLZSPQGCP +NUIKTBLZSPQGCP +NUIKTBLZSPQGCP +MFRBFANVIMHOEQ +MFRBFANVIMHOEQ +MFRBFANVIMHOEQ +NOHQEAFAESMMDX +NOHQEAFAESMMDX +WOWBFOBYOAGEEA +WOWBFOBYOAGEEA +WOWBFOBYOAGEEA +JWLZIHLAMJDONF +JWLZIHLAMJDONF +JWLZIHLAMJDONF +JUSFANSTBFGBAF +JUSFANSTBFGBAF +HYOGJHCDLQSAHX +HYOGJHCDLQSAHX +HYOGJHCDLQSAHX +YCBAQKQAINQRFW +YCBAQKQAINQRFW +YCBAQKQAINQRFW +WZDNKHCQIZRDKW +RCSLGYIVHUXZCI +RCSLGYIVHUXZCI +RCSLGYIVHUXZCI +SBKZGLWZGZQVHA +SBKZGLWZGZQVHA +SBKZGLWZGZQVHA +SAZVRXTVWZAHBI +SAZVRXTVWZAHBI +SAZVRXTVWZAHBI +XSTBUOHORFUCIB +XSTBUOHORFUCIB +XSTBUOHORFUCIB +IOMMMLWIABWRKL +IOMMMLWIABWRKL +IOMMMLWIABWRKL +YWLNYZXFIAFWSF +YWLNYZXFIAFWSF +YWLNYZXFIAFWSF +YSUBLPUJDOWYDP +YSUBLPUJDOWYDP +YSUBLPUJDOWYDP +YSUBLPUJDOWYDP +RJQYGCGMQYVVIB +RJQYGCGMQYVVIB +RJQYGCGMQYVVIB +HEDFFPYRFJKXQP +HEDFFPYRFJKXQP +HEDFFPYRFJKXQP +XREWXJVMYAXCJV +XREWXJVMYAXCJV +QJTGTGYXESVKJU +QTYGEBIJNWMVCW +QTYGEBIJNWMVCW +DZSUJUOJJJCWGG +DZSUJUOJJJCWGG +DZSUJUOJJJCWGG +ZSXCVAIJFUEGJR +ZSXCVAIJFUEGJR +ZSXCVAIJFUEGJR +UGEWTLXHMYKLCO +UGEWTLXHMYKLCO +UGEWTLXHMYKLCO +DLNUPKDFXMWRFP +DLNUPKDFXMWRFP +DLNUPKDFXMWRFP +NSMODRMOSSBWGQ +NSMODRMOSSBWGQ +NSMODRMOSSBWGQ +OAIHSWLLDNASTO +OAIHSWLLDNASTO +OAIHSWLLDNASTO +OAIHSWLLDNASTO +VUOYAALVGSMUHC +VUOYAALVGSMUHC +VUOYAALVGSMUHC +ICCFXXDUYSPKOL +ICCFXXDUYSPKOL +ICCFXXDUYSPKOL +VZSAMEOETVNDQH +VZSAMEOETVNDQH +XAYGBKHKBBXDAK +XAYGBKHKBBXDAK +XAYGBKHKBBXDAK +GXTJETQFYHZHNB +GXTJETQFYHZHNB +GSXXTLWPQMHHDJ +GSXXTLWPQMHHDJ +PRKWNRUVAZZHPH +PRKWNRUVAZZHPH +RZAMDGBOOPJHJQ +RZAMDGBOOPJHJQ +RZAMDGBOOPJHJQ +RFHOOFYUTGZPFH +RFHOOFYUTGZPFH +RFHOOFYUTGZPFH +LDEKQSIMHVQZJK +LDEKQSIMHVQZJK +LDEKQSIMHVQZJK +LDEKQSIMHVQZJK +LDEKQSIMHVQZJK +LDEKQSIMHVQZJK +LDEKQSIMHVQZJK +LDEKQSIMHVQZJK +LDEKQSIMHVQZJK +LDEKQSIMHVQZJK +LDEKQSIMHVQZJK +YPBATNHYBCGSSN +YPBATNHYBCGSSN +YPBATNHYBCGSSN +VXYZBLXGCYNIHP +VXYZBLXGCYNIHP +VXYZBLXGCYNIHP +PWHIUQBBGPGFFV +PWHIUQBBGPGFFV +PWHIUQBBGPGFFV +KPVIXBKIJXZQJX +KPVIXBKIJXZQJX +KPVIXBKIJXZQJX +MJQMRGWYPNIERM +MJQMRGWYPNIERM +MJQMRGWYPNIERM +BZCALJIHZVNMGJ +BZCALJIHZVNMGJ +BZCALJIHZVNMGJ +BZCALJIHZVNMGJ +AHHXLJGAODIDAX +AHHXLJGAODIDAX +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +KDLRVYVGXIQJDK +MNHNIVNAFBSLLX +MNHNIVNAFBSLLX +MNHNIVNAFBSLLX +KBDDHSXZOLZZGF +KBDDHSXZOLZZGF +KBDDHSXZOLZZGF +SNPPEHMSSOEYDH +SNPPEHMSSOEYDH +SNPPEHMSSOEYDH +FAEOHCOAHZFOEX +FAEOHCOAHZFOEX +FAEOHCOAHZFOEX +ZCALMLVWZSQGGR +ZCALMLVWZSQGGR +ZCALMLVWZSQGGR +SPDQRCUBFSRAFI +ITAMRBIZWGDOHW +ITAMRBIZWGDOHW +ITAMRBIZWGDOHW +NOZIJMHMKORZBA +NBRBXGKOEOGLOI +NBRBXGKOEOGLOI +TTZHDVOVKQGIBA +TTZHDVOVKQGIBA +TTZHDVOVKQGIBA +BUWBRTXGQRBBHG +BUWBRTXGQRBBHG +AMWPZASLDLLQFT +AMWPZASLDLLQFT +AMWPZASLDLLQFT +VSUDRCZPHWUXEW +VSUDRCZPHWUXEW +VSUDRCZPHWUXEW +KWZUDGWKTNIKJY +KWZUDGWKTNIKJY +KWZUDGWKTNIKJY +VJYKVCURWJGLPG +VJYKVCURWJGLPG +VBZGZUAKQLIUCN +VBZGZUAKQLIUCN +VBZGZUAKQLIUCN +UWXSAYUXVSFDBQ +UWXSAYUXVSFDBQ +UWXSAYUXVSFDBQ +KXWKSWRGZLZHEF +KXWKSWRGZLZHEF +KXWKSWRGZLZHEF +HXPQWNPLNIEJOW +HXPQWNPLNIEJOW +HXPQWNPLNIEJOW +WGGSYXQFYRWBEC +WGGSYXQFYRWBEC +FYOYNRLSBYWAHL +FYOYNRLSBYWAHL +FYOYNRLSBYWAHL +CNPVJJQCETWNEU +CNPVJJQCETWNEU +CNPVJJQCETWNEU +CNPVJJQCETWNEU +CNPVJJQCETWNEU +WNVSFFVDMUSXSX +WNVSFFVDMUSXSX +WNVSFFVDMUSXSX +YJNUXGPXJFAUQJ +YJNUXGPXJFAUQJ +YJNUXGPXJFAUQJ +YJNUXGPXJFAUQJ +YJNUXGPXJFAUQJ +IIDSDBBDZNDWCN +IIDSDBBDZNDWCN +IIDSDBBDZNDWCN +IIDSDBBDZNDWCN +ZCLTTXIIPQGUKN +ZCLTTXIIPQGUKN +UWTRKIJAGTTXNM +UWTRKIJAGTTXNM +UWTRKIJAGTTXNM +OPQNCARIZFLNLF +OPQNCARIZFLNLF +OPQNCARIZFLNLF +SLAYUXIURFNXPG +SLAYUXIURFNXPG +SLAYUXIURFNXPG +VTLCNEGVSVJLDN +VTLCNEGVSVJLDN +VTLCNEGVSVJLDN +CQGMWUWJVBKTRM +CQGMWUWJVBKTRM +CQGMWUWJVBKTRM +RNAMYOYQYRYFQY +RNAMYOYQYRYFQY +RNAMYOYQYRYFQY +WRFHGDPIDHPWIQ +WRFHGDPIDHPWIQ +SFHMWDMKUYVSQJ +SFHMWDMKUYVSQJ +SFHMWDMKUYVSQJ +ZIAOVIPSKUPPQW +ZIAOVIPSKUPPQW +ZIAOVIPSKUPPQW +AFZFFLVORLEPPO +AFZFFLVORLEPPO +AFZFFLVORLEPPO +RNIADBXQDMCFEN +RNIADBXQDMCFEN +RNIADBXQDMCFEN +SGNRHEDBLPGDDC +SGNRHEDBLPGDDC +SGNRHEDBLPGDDC +GOMFFTZBKYVUOE +ZNXOKLWCOWOECF +ZNXOKLWCOWOECF +ZNXOKLWCOWOECF +YZRXTIGAQRIAEX +YZRXTIGAQRIAEX +KEVHLTCEMHIJTQ +KEVHLTCEMHIJTQ +KEVHLTCEMHIJTQ +BMWMKGNVAMXXCH +BMWMKGNVAMXXCH +BMWMKGNVAMXXCH +XZIQSOZOLJJMFN +XZIQSOZOLJJMFN +VMJFTOSOFDEKTM +VMJFTOSOFDEKTM +VMJFTOSOFDEKTM +BDUHCSBCVGXTJM +BDUHCSBCVGXTJM +BDUHCSBCVGXTJM +OSQAKHSYTKBSPB +OSQAKHSYTKBSPB +OSQAKHSYTKBSPB +JELDFLOBXROBFH +JELDFLOBXROBFH +JELDFLOBXROBFH +XSDZPPRQLIZLDG +XSDZPPRQLIZLDG +XSDZPPRQLIZLDG +YYLKKYCXAOBSRM +YYLKKYCXAOBSRM +YYLKKYCXAOBSRM +XUARBCHSPWMKRC +XUARBCHSPWMKRC +XUARBCHSPWMKRC +MRWFZSLZNUJVQW +MRWFZSLZNUJVQW +MRWFZSLZNUJVQW +LBHLFPGPEGDCJG +LBHLFPGPEGDCJG +LBHLFPGPEGDCJG +QWPXBEHQFHACTK +QWPXBEHQFHACTK +QWPXBEHQFHACTK +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +FFTVPQUHLQBXQZ +ASUGUQWIHMTFJL +ASUGUQWIHMTFJL +ASUGUQWIHMTFJL +WJDMCXSGUCNRPZ +WJDMCXSGUCNRPZ +SQKUFYLUXROIFM +SQKUFYLUXROIFM +SQKUFYLUXROIFM +LKCWBDHBTVXHDL +LKCWBDHBTVXHDL +LKCWBDHBTVXHDL +UFUVLHLTWXBHGZ +UFUVLHLTWXBHGZ +CIDUJQMULVCIBT +CIDUJQMULVCIBT +CIDUJQMULVCIBT +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BIDNLKIUORFRQP +BZFGYHOKTSIEDA +BZFGYHOKTSIEDA +BZFGYHOKTSIEDA +BXYDVWIAGDJBEC +BXYDVWIAGDJBEC +BXYDVWIAGDJBEC +OSFCMRGOZNQUSW +OSFCMRGOZNQUSW +OSFCMRGOZNQUSW +OSFCMRGOZNQUSW +OSFCMRGOZNQUSW +OSFCMRGOZNQUSW +DHDHJYNTEFLIHY +DHDHJYNTEFLIHY +UXLUNMKSQUMWLH +DYLGFOYVTXJFJP +DYLGFOYVTXJFJP +DYLGFOYVTXJFJP +MJHOMTRKVMKCNE +MJHOMTRKVMKCNE +MJHOMTRKVMKCNE +QYKHWEFPFAGNEV +QYKHWEFPFAGNEV +QYKHWEFPFAGNEV +WKDACQVEJIVHMZ +WKDACQVEJIVHMZ +WKDACQVEJIVHMZ +GYQYAJJFPNQOOW +GYQYAJJFPNQOOW +GYQYAJJFPNQOOW +GYQYAJJFPNQOOW +GYQYAJJFPNQOOW +GYQYAJJFPNQOOW +PLCVJNJRUVNDEY +PLCVJNJRUVNDEY +PLCVJNJRUVNDEY +KFHMLBXBRCITHF +XLCNVWUKICLURR +XLCNVWUKICLURR +XLCNVWUKICLURR +QESQGTFWEQMCMH +QESQGTFWEQMCMH +QESQGTFWEQMCMH +PETCZXAONWLUFT +PETCZXAONWLUFT +PETCZXAONWLUFT +KIKOYRNAERIVSJ +KIKOYRNAERIVSJ +KIKOYRNAERIVSJ +FYXCIBJXJYBWPX +FYXCIBJXJYBWPX +FYXCIBJXJYBWPX +YEGFDJOAFMPJSE +YEGFDJOAFMPJSE +YEGFDJOAFMPJSE +WIJZXSAJMHAVGX +WIJZXSAJMHAVGX +WIJZXSAJMHAVGX +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +IXSVOCGZBUJEPI +IXSVOCGZBUJEPI +IXSVOCGZBUJEPI +KGERZPVQIRYWRK +KGERZPVQIRYWRK +KGERZPVQIRYWRK +AKCRNFFTGXBONI +AKCRNFFTGXBONI +IAIDUHCBNLFXEF +IAIDUHCBNLFXEF +IAIDUHCBNLFXEF +KUJBDJBMXOTNIT +KUJBDJBMXOTNIT +KUJBDJBMXOTNIT +AEJACXAFHXBVHF +AEJACXAFHXBVHF +AEJACXAFHXBVHF +JMGXJHWTVBGOKG +JMGXJHWTVBGOKG +JMGXJHWTVBGOKG +CBBXTGWSGPEJEE +CBBXTGWSGPEJEE +CBBXTGWSGPEJEE +GYFRQCMDLBNZSF +GYFRQCMDLBNZSF +DTYWJKSSUANMHD +DTYWJKSSUANMHD +DTYWJKSSUANMHD +UZIATSFXNVOVFE +FKCWHHYUMFGOPY +ANEBQUSWQAQFQB +ANEBQUSWQAQFQB +UYDYJFWSPRQEAX +UYDYJFWSPRQEAX +UYDYJFWSPRQEAX +XZAFZXJXZHRNAQ +XZAFZXJXZHRNAQ +XZAFZXJXZHRNAQ +WAXQNWCZJDTGBU +WAXQNWCZJDTGBU +WAXQNWCZJDTGBU +XERATECPNBWJFP +XERATECPNBWJFP +XERATECPNBWJFP +GDFGTRDCCWFXTG +GDFGTRDCCWFXTG +GDFGTRDCCWFXTG +WHYGBVWGARJOCS +WHYGBVWGARJOCS +UQZIYBXSHAGNOE +UQZIYBXSHAGNOE +UQZIYBXSHAGNOE +UQZIYBXSHAGNOE +KOMNUTZXSVSERR +KOMNUTZXSVSERR +KOMNUTZXSVSERR +KOMNUTZXSVSERR +FSDGTYAXLWTVMU +FSDGTYAXLWTVMU +FSDGTYAXLWTVMU +AXMBKMAQAXZRRI +AXMBKMAQAXZRRI +KKNLJPNGKFIUCA +KKNLJPNGKFIUCA +RCVVYGVSUSFWCH +RCVVYGVSUSFWCH +RVNQGBQBTQGUTJ +RVNQGBQBTQGUTJ +PVUVDSXASVWMHY +PVUVDSXASVWMHY +PVUVDSXASVWMHY +FUBVWMNBEHXPSU +FUBVWMNBEHXPSU +FUBVWMNBEHXPSU +FUBVWMNBEHXPSU +FUBVWMNBEHXPSU +GMDZWMSMLPRNDT +GMDZWMSMLPRNDT +GMDZWMSMLPRNDT +GMDZWMSMLPRNDT +OABYFRXECDYIIL +OABYFRXECDYIIL +PMTCNUHQBGHURV +PMTCNUHQBGHURV +PMTCNUHQBGHURV +PMTCNUHQBGHURV +HGPDZYFENFMJGK +HGPDZYFENFMJGK +AGDOMUAOXGDHJL +AGDOMUAOXGDHJL +JGJZXMQBLNXQRQ +JGJZXMQBLNXQRQ +JGJZXMQBLNXQRQ +JGJZXMQBLNXQRQ +YAOKLVBXPGFCKD +YAOKLVBXPGFCKD +MTPDBPKFWDCGJO +MTPDBPKFWDCGJO +MTPDBPKFWDCGJO +MTPDBPKFWDCGJO +WCUWYJGOMIXYIU +WCUWYJGOMIXYIU +WCUWYJGOMIXYIU +WCUWYJGOMIXYIU +UWUXGLFIXCWUKU +UWUXGLFIXCWUKU +TZUMHGNAWOBUHF +TZUMHGNAWOBUHF +WEJYNZVGAGTAKE +WEJYNZVGAGTAKE +IVTFMZAPBSUOLL +IVTFMZAPBSUOLL +XLTANAWLDBYGFU +XLTANAWLDBYGFU +NUYXXLBQLZMIPW +NUYXXLBQLZMIPW +NUYXXLBQLZMIPW +NUYXXLBQLZMIPW +RDSIYRMZJRMOJV +RDSIYRMZJRMOJV +RDSIYRMZJRMOJV +RDSIYRMZJRMOJV +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +MYPZKSIZQMFTBX +MYPZKSIZQMFTBX +MYPZKSIZQMFTBX +MYPZKSIZQMFTBX +PQAUGJLQCACEJE +AGXMZNFWRRKRCO +AGXMZNFWRRKRCO +AGXMZNFWRRKRCO +AGXMZNFWRRKRCO +RFURXZCEEFOOKK +RFURXZCEEFOOKK +RFURXZCEEFOOKK +RFURXZCEEFOOKK +SEAUGKBGGSQBDQ +SEAUGKBGGSQBDQ +YMOCKJOIASMJTF +YMOCKJOIASMJTF +YMOCKJOIASMJTF +YMOCKJOIASMJTF +GDPOIUMOSWQWJA +GDPOIUMOSWQWJA +GDPOIUMOSWQWJA +GDPOIUMOSWQWJA +SFEGGNBCHVXXQF +SFEGGNBCHVXXQF +SFEGGNBCHVXXQF +SFEGGNBCHVXXQF +SFEGGNBCHVXXQF +HOVGKGXZJXMZDT +HOVGKGXZJXMZDT +HOVGKGXZJXMZDT +HOVGKGXZJXMZDT +ZEBMMHUDQRRILP +UBCRRGWRFBTMRV +UBCRRGWRFBTMRV +QIUQYYZJIZDBNU +QIUQYYZJIZDBNU +POZPYFSUERHPRA +POZPYFSUERHPRA +POZPYFSUERHPRA +POZPYFSUERHPRA +SOMGSGOZQKRXPR +SOMGSGOZQKRXPR +SOMGSGOZQKRXPR +SOMGSGOZQKRXPR +DTTPWCNKTMQMTE +BQOZGVUGFRSHPA +BQOZGVUGFRSHPA +RECPURFFORPKIU +RECPURFFORPKIU +RECPURFFORPKIU +RECPURFFORPKIU +GTIJUYRURIFXCS +GTIJUYRURIFXCS +GTIJUYRURIFXCS +GTIJUYRURIFXCS +GAPQZHJGHFTHBZ +GAPQZHJGHFTHBZ +GAPQZHJGHFTHBZ +GAPQZHJGHFTHBZ +GAPQZHJGHFTHBZ +GAPQZHJGHFTHBZ +GAPQZHJGHFTHBZ +GAPQZHJGHFTHBZ +LRFGGRBSEBBYMH +LRFGGRBSEBBYMH +DNWQUBSBJPTPTN +DNWQUBSBJPTPTN +DNWQUBSBJPTPTN +DNWQUBSBJPTPTN +BKQWEYFPSIGUMT +BKQWEYFPSIGUMT +BKQWEYFPSIGUMT +BKQWEYFPSIGUMT +BMKFGEHXCWEXBB +BMKFGEHXCWEXBB +BMKFGEHXCWEXBB +BMKFGEHXCWEXBB +JYCJNBWCIPDSJN +JYCJNBWCIPDSJN +JYCJNBWCIPDSJN +JYCJNBWCIPDSJN +UNBMQQNYLCPCHS +UNBMQQNYLCPCHS +GAOZTHIDHYLHMS +GAOZTHIDHYLHMS +ATYZSMMAOAHRHB +ATYZSMMAOAHRHB +ATYZSMMAOAHRHB +ATYZSMMAOAHRHB +BGVKWUWMVCLWGM +BGVKWUWMVCLWGM +BGVKWUWMVCLWGM +YPSAOPXJHSESSR +YPSAOPXJHSESSR +PGFUIWZVUGAQMW +PGFUIWZVUGAQMW +PGFUIWZVUGAQMW +PGFUIWZVUGAQMW +PGFUIWZVUGAQMW +PGFUIWZVUGAQMW +XTLROSDJDZHIIK +IXMAERWORNOHRL +IXMAERWORNOHRL +XFSBVAOIAHNAPC +NEHSMRMOOSXSBN +NEHSMRMOOSXSBN +NEHSMRMOOSXSBN +NEHSMRMOOSXSBN +HXKQKEQCNBMZJW +HXKQKEQCNBMZJW +HXKQKEQCNBMZJW +HXKQKEQCNBMZJW +UUNUEWJUIFKEHU +UUNUEWJUIFKEHU +ABSGSRABKMESPA +ABSGSRABKMESPA +ABSGSRABKMESPA +ABSGSRABKMESPA +GAZDXIGXYWVWQX +QZSPYIDISPEVBP +QZSPYIDISPEVBP +QZSPYIDISPEVBP +QZSPYIDISPEVBP +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +YOZDAHIPRRIQRA +YOZDAHIPRRIQRA +YOZDAHIPRRIQRA +HAABNOIHSDVBOG +HAABNOIHSDVBOG +HAABNOIHSDVBOG +LHCSEROEGNNAEM +LHCSEROEGNNAEM +LHCSEROEGNNAEM +LHCSEROEGNNAEM +ULAZJDQQOJEKRU +ULAZJDQQOJEKRU +ULAZJDQQOJEKRU +ULAZJDQQOJEKRU +BWIORMZTMCRQFF +BWIORMZTMCRQFF +BWIORMZTMCRQFF +BWIORMZTMCRQFF +BXNOECRMMABCPY +BXNOECRMMABCPY +BXNOECRMMABCPY +BXNOECRMMABCPY +HBAJJGLXFFHEFI +HBAJJGLXFFHEFI +HBAJJGLXFFHEFI +HBAJJGLXFFHEFI +CKRZGCPROGECTO +CKRZGCPROGECTO +SBHHPPCAAYCRQS +SBHHPPCAAYCRQS +XIJJZKASKOJNGG +XIJJZKASKOJNGG +XIJJZKASKOJNGG +XIJJZKASKOJNGG +VSZZYABXAZZKSZ +VSZZYABXAZZKSZ +MWZRJINWYQTYDP +MWZRJINWYQTYDP +JTZKILTYPNEPCS +JTZKILTYPNEPCS +JTZKILTYPNEPCS +JTZKILTYPNEPCS +HGLYYRPUZKSRJK +HGLYYRPUZKSRJK +HGLYYRPUZKSRJK +HGLYYRPUZKSRJK +HXNGFYZLCLPCNU +HXNGFYZLCLPCNU +HXNGFYZLCLPCNU +HXNGFYZLCLPCNU +ZVDYGDCVXCGTHH +ZVDYGDCVXCGTHH +ZVDYGDCVXCGTHH +POQVSPHJDYXGDL +POQVSPHJDYXGDL +BKZYAVMAJSKPSP +BKZYAVMAJSKPSP +UZUAFNVLJJODHR +UZUAFNVLJJODHR +UZUAFNVLJJODHR +UZUAFNVLJJODHR +MPIYQRSUKPUUFX +MPIYQRSUKPUUFX +LPRNUUPBTWJJNE +LPRNUUPBTWJJNE +BNIQFAPHTLCOKN +BNIQFAPHTLCOKN +FIQQLJZRRJZKJB +FIQQLJZRRJZKJB +ALTHFZGWMKPLDM +ALTHFZGWMKPLDM +HJYYPODYNSCCOU +HJYYPODYNSCCOU +YECWXFKOSKEVBN +YECWXFKOSKEVBN +WZUBMARCOGTQAG +WZUBMARCOGTQAG +WSMUAKDGOFXEQI +WSMUAKDGOFXEQI +JRTIAKFTPBQKSU +JRTIAKFTPBQKSU +JRTIAKFTPBQKSU +TWYCSUHRKMCSIR +TWYCSUHRKMCSIR +GUWANAIOLGNGNK +GUWANAIOLGNGNK +GUWANAIOLGNGNK +GUWANAIOLGNGNK +FWSVZRJCNNFMSR +FWSVZRJCNNFMSR +FWSVZRJCNNFMSR +FWSVZRJCNNFMSR +JQXXHWHPUNPDRT +JQXXHWHPUNPDRT +JQXXHWHPUNPDRT +FSLFZTDAWFXTJV +FSLFZTDAWFXTJV +FSLFZTDAWFXTJV +FSLFZTDAWFXTJV +ZQLPKRQGSUVDAY +ZQLPKRQGSUVDAY +QVTSETREFGZLNB +QVTSETREFGZLNB +GNSVLCDRVBSQFK +GNSVLCDRVBSQFK +YBKIMRLMFLYGOJ +YBKIMRLMFLYGOJ +YBKIMRLMFLYGOJ +SOLOGPKQXAYSGY +SOLOGPKQXAYSGY +SOLOGPKQXAYSGY +SOLOGPKQXAYSGY +PUPFZYBRXNAWID +PUPFZYBRXNAWID +SQGCPNYRAGYYMA +SQGCPNYRAGYYMA +XYPBUYGIBVMVEB +XYPBUYGIBVMVEB +ZBEUUNSYABTFRU +ZBEUUNSYABTFRU +ZBEUUNSYABTFRU +ZBEUUNSYABTFRU +QVNCBRMSRLGETO +ZXNGDFHZTPSPQZ +ZXNGDFHZTPSPQZ +ZXNGDFHZTPSPQZ +ZXNGDFHZTPSPQZ +ZHRUQGSDRAEIQM +ZHRUQGSDRAEIQM +ZHRUQGSDRAEIQM +ZHRUQGSDRAEIQM +MCXDMGNXXINCKU +MCXDMGNXXINCKU +ZPVQMYRFHAQJAJ +ZPVQMYRFHAQJAJ +UQMOXDGZRXGLEF +UQMOXDGZRXGLEF +LWUWUBBAEPLFDF +LWUWUBBAEPLFDF +LWUWUBBAEPLFDF +LWUWUBBAEPLFDF +GDNLMNJDZOVSMS +GDNLMNJDZOVSMS +PCNVPYXJHIVHBW +PCNVPYXJHIVHBW +CVGAINFJTLYTKX +CVGAINFJTLYTKX +CVGAINFJTLYTKX +CVGAINFJTLYTKX +NWQDNQOXIZHQAQ +NWQDNQOXIZHQAQ +YYASEJLMBGRAMO +YYASEJLMBGRAMO +ANODJSBBJYGIOF +ANODJSBBJYGIOF +ANODJSBBJYGIOF +ANODJSBBJYGIOF +PDIOUUAXUGLNSO +PDIOUUAXUGLNSO +PDIOUUAXUGLNSO +PDIOUUAXUGLNSO +CGMUHSNJRXPSSA +CGMUHSNJRXPSSA +IAADFZLZWMXVCR +IAADFZLZWMXVCR +IAADFZLZWMXVCR +IAADFZLZWMXVCR +UYKHSYATOFJBMB +UYKHSYATOFJBMB +UYKHSYATOFJBMB +UYKHSYATOFJBMB +OBWOXXXOGNNPAB +OBWOXXXOGNNPAB +GDASLVDUBPNSGW +GDASLVDUBPNSGW +TXZRQPPQZAJROJ +TXZRQPPQZAJROJ +KFTHKOWIKLPWJD +KFTHKOWIKLPWJD +KFTHKOWIKLPWJD +KFTHKOWIKLPWJD +IVVZLZKSGWCDFM +IVVZLZKSGWCDFM +IVVZLZKSGWCDFM +GAEVIVZGXCUYEX +GAEVIVZGXCUYEX +GAEVIVZGXCUYEX +WKANKAPDOZGYJK +WKANKAPDOZGYJK +WKANKAPDOZGYJK +WKANKAPDOZGYJK +OXWWDAFCLOTROR +OXWWDAFCLOTROR +KPGVUOQMOHGHEW +KPGVUOQMOHGHEW +KPGVUOQMOHGHEW +KPGVUOQMOHGHEW +CIEKOAABKWQQES +CIEKOAABKWQQES +CIEKOAABKWQQES +CIEKOAABKWQQES +INXDVEVEHRLOPT +INXDVEVEHRLOPT +BSFAJVATOJUORE +BSFAJVATOJUORE +BSFAJVATOJUORE +BSFAJVATOJUORE +IXOMHPDEPRMKFN +IXOMHPDEPRMKFN +IWJMNCANMKFONX +IWJMNCANMKFONX +IWJMNCANMKFONX +IWJMNCANMKFONX +CLHYKPBCCXMSGW +CLHYKPBCCXMSGW +CLHYKPBCCXMSGW +CLHYKPBCCXMSGW +FFRNRGCLQSQHGC +FFRNRGCLQSQHGC +FFRNRGCLQSQHGC +FFRNRGCLQSQHGC +ZYJFTUZFDDQOJY +ZYJFTUZFDDQOJY +ZYJFTUZFDDQOJY +ZYJFTUZFDDQOJY +KFCAYWMYUVHBAC +KFCAYWMYUVHBAC +KFCAYWMYUVHBAC +KFCAYWMYUVHBAC +YXBXIPWDPVPYCY +YXBXIPWDPVPYCY +UFMFZZQOMAGWJE +UFMFZZQOMAGWJE +VHKXXVVRRDYCIK +VHKXXVVRRDYCIK +IBSXCRQLMJKTBF +IBSXCRQLMJKTBF +IBSXCRQLMJKTBF +IBSXCRQLMJKTBF +DPYAYYCEUQZLNP +DPYAYYCEUQZLNP +DPYAYYCEUQZLNP +DPYAYYCEUQZLNP +FUFYDKWEAXYOHH +FUFYDKWEAXYOHH +FUFYDKWEAXYOHH +FUFYDKWEAXYOHH +NKEXTNLGLAPHOC +NKEXTNLGLAPHOC +VDZRDUZGHBQIFJ +VDZRDUZGHBQIFJ +VDZRDUZGHBQIFJ +VDZRDUZGHBQIFJ +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +JLUALTVFLLOANS +YFXLGGABXFQQEG +YFXLGGABXFQQEG +YFXLGGABXFQQEG +YFXLGGABXFQQEG +LLCHTTWOCWRAQW +LLCHTTWOCWRAQW +NOZXVYCVTKLPLQ +NOZXVYCVTKLPLQ +NOZXVYCVTKLPLQ +NOZXVYCVTKLPLQ +VZVUHPNLAVYENU +VZVUHPNLAVYENU +LBZZEFPVHPIWCL +LBZZEFPVHPIWCL +LBZZEFPVHPIWCL +LBZZEFPVHPIWCL +MOLPUWBMSBJXER +MOLPUWBMSBJXER +MOLPUWBMSBJXER +MOLPUWBMSBJXER +ZAZYRSDPAJXQGP +ZAZYRSDPAJXQGP +VSILYUGWCLYFCD +VSILYUGWCLYFCD +VSILYUGWCLYFCD +VSILYUGWCLYFCD +DCECXXVEKNNRNY +DCECXXVEKNNRNY +GBQRKJRHCOAHIR +GBQRKJRHCOAHIR +GBQRKJRHCOAHIR +GBQRKJRHCOAHIR +ZFSZTJSKFHGWAG +ZFSZTJSKFHGWAG +HOVSZVKDFBLXOB +HOVSZVKDFBLXOB +HOVSZVKDFBLXOB +HOVSZVKDFBLXOB +BHFYKFSRXRQPCG +BHFYKFSRXRQPCG +LQXYZBQQOSACNR +LQXYZBQQOSACNR +KQIXOBKAGZBVGB +KQIXOBKAGZBVGB +KQIXOBKAGZBVGB +TXXWXESCAGCJAD +TXXWXESCAGCJAD +TXXWXESCAGCJAD +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +KNTBYRLZKNFFCS +KNTBYRLZKNFFCS +KNTBYRLZKNFFCS +KNTBYRLZKNFFCS +AHNXUVJUJNMRHF +AHNXUVJUJNMRHF +QIAZGMCSYZUPEX +QIAZGMCSYZUPEX +QIAZGMCSYZUPEX +QIAZGMCSYZUPEX +SECDNTMKAIXVGP +SECDNTMKAIXVGP +JDPIYAUUXXERCL +JDPIYAUUXXERCL +OLBVCMYKIIQLQT +OLBVCMYKIIQLQT +FQACVCUXLWECJC +FQACVCUXLWECJC +FQACVCUXLWECJC +FQACVCUXLWECJC +VEBVPUXQAPLADL +QDMKSFGLJQCAOX +QDMKSFGLJQCAOX +MBEYJURZBQSTJR +MBEYJURZBQSTJR +MBEYJURZBQSTJR +MBEYJURZBQSTJR +OWFJMIVZYSDULZ +OWFJMIVZYSDULZ +UWYJJBNHEBMUFA +UWYJJBNHEBMUFA +OKFCSMOGDYDQCN +OKFCSMOGDYDQCN +IVQFDCJBKFYWNV +IVQFDCJBKFYWNV +IVQFDCJBKFYWNV +IVQFDCJBKFYWNV +QNJKJOJARFRQLD +QNJKJOJARFRQLD +QNJKJOJARFRQLD +QNJKJOJARFRQLD +FPYNJWMJOAMMBC +FPYNJWMJOAMMBC +CSYRWZZMGWWSRR +CSYRWZZMGWWSRR +NADTWWWCPKHBGR +NADTWWWCPKHBGR +GTSHSTJFTSYFBU +GTSHSTJFTSYFBU +GTSHSTJFTSYFBU +YFNPRWZVZFBBMG +YFNPRWZVZFBBMG +GZVYDLULIRKVOG +GZVYDLULIRKVOG +GZVYDLULIRKVOG +KWQHHLRWJOKMAE +KWQHHLRWJOKMAE +KWQHHLRWJOKMAE +KWQHHLRWJOKMAE +CYOYVDVFHOPVJH +CYOYVDVFHOPVJH +CYOYVDVFHOPVJH +CYOYVDVFHOPVJH +JJSYXNQGLHBRRK +JJSYXNQGLHBRRK +IQQYFMUEUBWVGS +IQQYFMUEUBWVGS +RRIMBVQOBXHVDN +RRIMBVQOBXHVDN +RRIMBVQOBXHVDN +RRIMBVQOBXHVDN +HMZGZQPMJLEENU +HMZGZQPMJLEENU +MKWLCWJMHDISIT +MKWLCWJMHDISIT +MKWLCWJMHDISIT +MKWLCWJMHDISIT +MEDVHSNRBPAIPU +MEDVHSNRBPAIPU +IOFATHVLOIXNOR +IOFATHVLOIXNOR +IOFATHVLOIXNOR +IOFATHVLOIXNOR +HJWBXYHQLYFQQN +HJWBXYHQLYFQQN +BNMWBRJGVFOWDK +BNMWBRJGVFOWDK +BNMWBRJGVFOWDK +BNMWBRJGVFOWDK +BFLXOMFFVWQPAZ +BFLXOMFFVWQPAZ +BFLXOMFFVWQPAZ +VANSZAOQCMTTPB +VANSZAOQCMTTPB +VANSZAOQCMTTPB +VANSZAOQCMTTPB +COJKTSQFSLKATI +COJKTSQFSLKATI +COJKTSQFSLKATI +COJKTSQFSLKATI +ADRRRPCFISANLS +ADRRRPCFISANLS +ADRRRPCFISANLS +MOBUVCKLGDJANF +MOBUVCKLGDJANF +MTTQBZWFVUEGSE +MTTQBZWFVUEGSE +MTTQBZWFVUEGSE +MTTQBZWFVUEGSE +OEQTWVMRQCTMBL +OEQTWVMRQCTMBL +FFIYJDUOKQDRJD +FFIYJDUOKQDRJD +GABOKXXZAROQGJ +GABOKXXZAROQGJ +VFEUILALMUPRPL +VFEUILALMUPRPL +GUBHJFUYEOSKQG +GUBHJFUYEOSKQG +GUBHJFUYEOSKQG +GUBHJFUYEOSKQG +BZOQTGADCSFWHV +FEOUZTHPXRJPIX +FEOUZTHPXRJPIX +FEOUZTHPXRJPIX +FEOUZTHPXRJPIX +GMDFEFKSTBCEHJ +GMDFEFKSTBCEHJ +GMDFEFKSTBCEHJ +GMDFEFKSTBCEHJ +XUYCOOVBDZXMHA +XUYCOOVBDZXMHA +YYZJHCHFUGRDDU +YYZJHCHFUGRDDU +YYZJHCHFUGRDDU +YYZJHCHFUGRDDU +YYEOWTIAYGGWBV +YYEOWTIAYGGWBV +SZINUGQCTHLQAZ +SZINUGQCTHLQAZ +SZINUGQCTHLQAZ +SZINUGQCTHLQAZ +FVLNZPLZBXQIAL +FVLNZPLZBXQIAL +FVLNZPLZBXQIAL +FVLNZPLZBXQIAL +NYIHORJUBZLXER +NYIHORJUBZLXER +NYIHORJUBZLXER +NYIHORJUBZLXER +RIQJMJMBEBHBMT +RIQJMJMBEBHBMT +RIQJMJMBEBHBMT +RIQJMJMBEBHBMT +WYAMNJUPQNEGOI +WYAMNJUPQNEGOI +WYAMNJUPQNEGOI +IXFPJGBNCFXKPI +IXFPJGBNCFXKPI +GRZMUUNUNHRNAD +GRZMUUNUNHRNAD +GRZMUUNUNHRNAD +GRZMUUNUNHRNAD +LIZYQIOAPWRBEB +LIZYQIOAPWRBEB +LIZYQIOAPWRBEB +MGKQAKGCWXUAQV +MGKQAKGCWXUAQV +MGKQAKGCWXUAQV +SOXHRQURNPRMDQ +SOXHRQURNPRMDQ +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +LDLKUNXNYVANLX +LDLKUNXNYVANLX +CRXIHWBEEGWGCG +CRXIHWBEEGWGCG +CRXIHWBEEGWGCG +CRXIHWBEEGWGCG +PHEDXBVPIONUQT +PHEDXBVPIONUQT +PHEDXBVPIONUQT +PHEDXBVPIONUQT +UKWNPFYGPAHXOP +UKWNPFYGPAHXOP +UKWNPFYGPAHXOP +UKWNPFYGPAHXOP +XDQGAOKGLVNKPO +XDQGAOKGLVNKPO +XDQGAOKGLVNKPO +XDQGAOKGLVNKPO +BNWYAOALHYWXSP +BNWYAOALHYWXSP +BNWYAOALHYWXSP +BNWYAOALHYWXSP +PZSOXNOGNYAAIA +AVLKQJXYLBZMPQ +AVLKQJXYLBZMPQ +SEBFKMXJBCUCAI +SEBFKMXJBCUCAI +ZGVSETXHNHBTRK +ZGVSETXHNHBTRK +JJRMVQGNSKCCGR +JJRMVQGNSKCCGR +JJRMVQGNSKCCGR +JJRMVQGNSKCCGR +ZQQQUKPBABZCCK +ZQQQUKPBABZCCK +BFWHDZSPQLUGPV +BFWHDZSPQLUGPV +BFWHDZSPQLUGPV +BFWHDZSPQLUGPV +CRKXNURAOMSUMJ +CRKXNURAOMSUMJ +CRKXNURAOMSUMJ +ZJZNVYNQZANQOF +ZJZNVYNQZANQOF +ROACAFFEBODFFQ +ROACAFFEBODFFQ +PRWQWYNQGGELGS +PRWQWYNQGGELGS +ALTWMMSPMJSYAL +ALTWMMSPMJSYAL +ALTWMMSPMJSYAL +ALTWMMSPMJSYAL +WJEJCBPKPWKMSC +WJEJCBPKPWKMSC +SGWAQZQVRJVNIZ +SGWAQZQVRJVNIZ +SGWAQZQVRJVNIZ +SGWAQZQVRJVNIZ +NEZAYBIGAYMXEF +NEZAYBIGAYMXEF +NEZAYBIGAYMXEF +NEZAYBIGAYMXEF +CUCUKLJLRRAKFN +CUCUKLJLRRAKFN +FRAIGNAVKGLKTG +FRAIGNAVKGLKTG +AGHDDYJNUGRNGZ +AGHDDYJNUGRNGZ +AGHDDYJNUGRNGZ +AGHDDYJNUGRNGZ +AZSNMRSAGSSBNP +AZSNMRSAGSSBNP +HZLGBSNAYIWYER +HZLGBSNAYIWYER +HZLGBSNAYIWYER +FFMUDKAAAYNVQQ +FFMUDKAAAYNVQQ +FFMUDKAAAYNVQQ +FFMUDKAAAYNVQQ +AQFSCHZBYWUHCK +AQFSCHZBYWUHCK +XCZSPVCHMPKNSY +XCZSPVCHMPKNSY +XCZSPVCHMPKNSY +XCZSPVCHMPKNSY +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +ULGZDMOVFRHVEP +WKRPMJFFYWUCQE +WKRPMJFFYWUCQE +BCGIWCUTZNLMGW +BCGIWCUTZNLMGW +BTXDTLDRUMNVOG +BTXDTLDRUMNVOG +BTXDTLDRUMNVOG +BTXDTLDRUMNVOG +LERMHBXFXPARSD +LERMHBXFXPARSD +RRWDASUNMJTBTI +RRWDASUNMJTBTI +PONPPNYZKHNPKZ +PONPPNYZKHNPKZ +PONPPNYZKHNPKZ +PONPPNYZKHNPKZ +STQGQHZAVUOBTE +STQGQHZAVUOBTE +STQGQHZAVUOBTE +STQGQHZAVUOBTE +STQGQHZAVUOBTE +BOJKFRKNLSCGHY +BOJKFRKNLSCGHY +MONAOJUXJOXWQB +MONAOJUXJOXWQB +MONAOJUXJOXWQB +MONAOJUXJOXWQB +MONAOJUXJOXWQB +MONAOJUXJOXWQB +MONAOJUXJOXWQB +MONAOJUXJOXWQB +MONAOJUXJOXWQB +MONAOJUXJOXWQB +MONAOJUXJOXWQB +MONAOJUXJOXWQB +MONAOJUXJOXWQB +MONAOJUXJOXWQB +MONAOJUXJOXWQB +SBWLIWHTLHBWQZ +SBWLIWHTLHBWQZ +SBWLIWHTLHBWQZ +SBWLIWHTLHBWQZ +FKZWANMBYLDTNI +FKZWANMBYLDTNI +GNITWRJZRGPYKV +GNITWRJZRGPYKV +HAOMMBCKOHUZDN +HAOMMBCKOHUZDN +NRUPRHFQGBCWJJ +NRUPRHFQGBCWJJ +NRUPRHFQGBCWJJ +NRUPRHFQGBCWJJ +XZPHCPOTGWXJFQ +XZPHCPOTGWXJFQ +XZPHCPOTGWXJFQ +XZPHCPOTGWXJFQ +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +AOJJSUZBOXZQNB +LYRXDBJAJWNPBZ +LYRXDBJAJWNPBZ +LYRXDBJAJWNPBZ +LYRXDBJAJWNPBZ +QBVSZUQSCUIFPH +QBVSZUQSCUIFPH +WHTFMDSWOMRPEZ +WHTFMDSWOMRPEZ +NTIRYLIJAGGLLT +NTIRYLIJAGGLLT +BQJRUJTZSGYBEZ +BQJRUJTZSGYBEZ +IDMMHVLXKOFIIR +IDMMHVLXKOFIIR +BCUPZIFKDUDMJL +BCUPZIFKDUDMJL +PQBJZHRFVKHZBT +PQBJZHRFVKHZBT +GEZHEQNLKAOMCA +GEZHEQNLKAOMCA +GEZHEQNLKAOMCA +GEZHEQNLKAOMCA +SDNPWXVGSFCVMZ +SDNPWXVGSFCVMZ +DFWXIEXTXIJSGM +DFWXIEXTXIJSGM +DFWXIEXTXIJSGM +DFWXIEXTXIJSGM +UDXPRXYOPQPNFT +UDXPRXYOPQPNFT +UDXPRXYOPQPNFT +IPQVTOJGNYVQEO +BLRIMLPHWMZFCV +BLRIMLPHWMZFCV +SWJLTKXURNHVHE +SWJLTKXURNHVHE +SWJLTKXURNHVHE +SWJLTKXURNHVHE +DRKMHDAKULCOKQ +DRKMHDAKULCOKQ +ZILWLYWWNDPPOD +ZILWLYWWNDPPOD +KSGDKJTVCJWQNJ +QDLHCMPXEPAAMD +QDLHCMPXEPAAMD +QDNHPNDNFFYSOS +QDNHPNDNFFYSOS +BTKOBXLKOUNJAZ +OLVCFLKTBJRLHI +OLVCFLKTBJRLHI +DGFFKAWSLMYGIH +KLRIUOUKRCSWSF +KLRIUOUKRCSWSF +HVNRNWTTWOOXEC +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +FJLGEFLZQAZZCD +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +XJLXINKUBYWONI +XJLXINKUBYWONI +XJLXINKUBYWONI +XJLXINKUBYWONI +XJLXINKUBYWONI +XJLXINKUBYWONI +XJLXINKUBYWONI +XJLXINKUBYWONI +XJLXINKUBYWONI +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +WMBWREPUVVBILR +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +QOVKKEKBURQILF +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +YURJSTAIMNSZAE +IMQLKJBTEOYOSI +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +PWAOOJDMFUQOKB +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +RWXIFXNRCLMQCD +VNONINPVFQTJOC +VNONINPVFQTJOC +VNONINPVFQTJOC +VNONINPVFQTJOC +VNONINPVFQTJOC +VNONINPVFQTJOC +VNONINPVFQTJOC +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RLDVZILFNVRJTL +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +RFWGABANNQMHMZ +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +ZDMLSSJRDUBJQS +CUCUKLJLRRAKFN +CUCUKLJLRRAKFN +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +BPYKTIZUTYGOLE +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +OZJXTWMDBPQRGI +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +GLMFFCVWRKKBJB +MOLPUWBMSBJXER +MOLPUWBMSBJXER +MOLPUWBMSBJXER +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +WEYVVCKOOFYHRW +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +VWLXIXALPNYWFH +LBHYRBPEXITYTN +LBHYRBPEXITYTN +LBHYRBPEXITYTN +LBHYRBPEXITYTN +LBHYRBPEXITYTN +LBHYRBPEXITYTN +LBHYRBPEXITYTN +LBHYRBPEXITYTN +LBHYRBPEXITYTN +LBHYRBPEXITYTN +LBHYRBPEXITYTN +LBHYRBPEXITYTN +LBHYRBPEXITYTN +LBHYRBPEXITYTN +LBHYRBPEXITYTN +JPMRHWLJLNKRTJ +JPMRHWLJLNKRTJ +JPMRHWLJLNKRTJ +JPMRHWLJLNKRTJ +JPMRHWLJLNKRTJ +JPMRHWLJLNKRTJ +JPMRHWLJLNKRTJ +JPMRHWLJLNKRTJ +JPMRHWLJLNKRTJ +JPMRHWLJLNKRTJ +JPMRHWLJLNKRTJ +JPMRHWLJLNKRTJ +JPMRHWLJLNKRTJ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +NWBWCXBPKTTZNQ +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +KVRQGMOSZKPBNS +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +DBOVHQOUSDWAPQ +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +VMSLCPKYRPDHLN +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +HAVJATCHLFRDHY +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +ZULSSCAFEXMMQF +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +YPSAOPXJHSESSR +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +BNMDTQMFJGEHPC +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +VDGOFNMYZYBUDT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +CAXSJVGHYYBJKT +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +KKJYIHSXTUGJLP +DFMMVLFMMAQXHZ +DFMMVLFMMAQXHZ +YYGNTYWPHWGJRM +YYGNTYWPHWGJRM +YYGNTYWPHWGJRM +YYGNTYWPHWGJRM +YYGNTYWPHWGJRM +YYGNTYWPHWGJRM +YYGNTYWPHWGJRM +YYGNTYWPHWGJRM +YYGNTYWPHWGJRM +YYGNTYWPHWGJRM +YYGNTYWPHWGJRM +YYGNTYWPHWGJRM +YYGNTYWPHWGJRM +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +SWIROVJVGRGSPO +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +MYBAONSAUGZRAX +UZIOUZHBUYLDHW +UZIOUZHBUYLDHW +UZIOUZHBUYLDHW +UZIOUZHBUYLDHW +UZIOUZHBUYLDHW +UZIOUZHBUYLDHW +UZIOUZHBUYLDHW +UZIOUZHBUYLDHW +UZIOUZHBUYLDHW +UZIOUZHBUYLDHW +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +KWDWBAISZWOAHD +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +AONBXCCYURJCAY +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +GLACGTLACKLUJX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +OUGNWRCWQLUXHX +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +SMTKSCGLXONVGL +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +DKBPTKFKCCNXNH +IIWKLAHNKXXKAJ +IIWKLAHNKXXKAJ +IIWKLAHNKXXKAJ +IIWKLAHNKXXKAJ +IIWKLAHNKXXKAJ +WVRDOLPMKOCJRJ +WVRDOLPMKOCJRJ +WVRDOLPMKOCJRJ +DPKVSJZTYNGFAW +DPKVSJZTYNGFAW +DPKVSJZTYNGFAW +DPKVSJZTYNGFAW +DPKVSJZTYNGFAW +AKNILCMFRRDTEY +AKNILCMFRRDTEY +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WRLXHKDQSQMWSH +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +WHWWQGPCTUQCMN +SBMXTMAIKRQSQE +SBMXTMAIKRQSQE +SBMXTMAIKRQSQE +SBMXTMAIKRQSQE +SBMXTMAIKRQSQE +SBMXTMAIKRQSQE +SBMXTMAIKRQSQE +FFQOXBQSZPYHSA +FFQOXBQSZPYHSA +FFQOXBQSZPYHSA +FFQOXBQSZPYHSA +FFQOXBQSZPYHSA +FFQOXBQSZPYHSA +FFQOXBQSZPYHSA +FFQOXBQSZPYHSA +FFQOXBQSZPYHSA +FFQOXBQSZPYHSA +FFQOXBQSZPYHSA +FFQOXBQSZPYHSA +JQEFRKPLHFKTFL +JQEFRKPLHFKTFL +JQEFRKPLHFKTFL +JQEFRKPLHFKTFL +JQEFRKPLHFKTFL +JQEFRKPLHFKTFL +JQEFRKPLHFKTFL +JQEFRKPLHFKTFL +JQEFRKPLHFKTFL +JQEFRKPLHFKTFL +JQEFRKPLHFKTFL +JQEFRKPLHFKTFL +JQEFRKPLHFKTFL +JQEFRKPLHFKTFL +JQEFRKPLHFKTFL +JQEFRKPLHFKTFL +GPLOTACQBREROW +GPLOTACQBREROW +GPLOTACQBREROW +GPLOTACQBREROW +GPLOTACQBREROW +GPLOTACQBREROW +GPLOTACQBREROW +GPLOTACQBREROW +HDXIQHTUNGFJIC +PTTJLTMUKRRHAT +PTTJLTMUKRRHAT +PTTJLTMUKRRHAT +PTTJLTMUKRRHAT +PTTJLTMUKRRHAT +PTTJLTMUKRRHAT +PTTJLTMUKRRHAT +PTTJLTMUKRRHAT +PTTJLTMUKRRHAT +PTTJLTMUKRRHAT +PTTJLTMUKRRHAT +PTTJLTMUKRRHAT +PTTJLTMUKRRHAT +VSNATUGVSVGFFN +VSNATUGVSVGFFN +VSNATUGVSVGFFN +VSNATUGVSVGFFN +VSNATUGVSVGFFN +VSNATUGVSVGFFN +VSNATUGVSVGFFN +VSNATUGVSVGFFN +VSNATUGVSVGFFN +VSNATUGVSVGFFN +VSNATUGVSVGFFN +VSNATUGVSVGFFN +DGFVATVOFRGGFO +DGFVATVOFRGGFO +DGFVATVOFRGGFO +DGFVATVOFRGGFO +DGFVATVOFRGGFO +DGFVATVOFRGGFO +KSIVGTKSVYIZEB +KSIVGTKSVYIZEB +KSIVGTKSVYIZEB +KSIVGTKSVYIZEB +KSIVGTKSVYIZEB +KSIVGTKSVYIZEB +KSIVGTKSVYIZEB +KSIVGTKSVYIZEB +KSIVGTKSVYIZEB +KSIVGTKSVYIZEB +KSIVGTKSVYIZEB +KSIVGTKSVYIZEB +KSIVGTKSVYIZEB +KSIVGTKSVYIZEB +KSIVGTKSVYIZEB +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +ZFWOUNNKSHIAFK +FHKHGNFKBPFJCB +FHKHGNFKBPFJCB +FHKHGNFKBPFJCB +FHKHGNFKBPFJCB +FHKHGNFKBPFJCB +KBECZWWSHDRKOW +KBECZWWSHDRKOW +KBECZWWSHDRKOW +HJEXOQUMFMERIM +HJEXOQUMFMERIM +HJEXOQUMFMERIM +HJEXOQUMFMERIM +HJEXOQUMFMERIM +HJEXOQUMFMERIM +HJEXOQUMFMERIM +YQEMAEKYNNOCBY +YQEMAEKYNNOCBY +YQEMAEKYNNOCBY +YQEMAEKYNNOCBY +YQEMAEKYNNOCBY +YQEMAEKYNNOCBY +YQEMAEKYNNOCBY +YQEMAEKYNNOCBY +YQEMAEKYNNOCBY +ROHLIYKWVMBBFX +ROHLIYKWVMBBFX +ROHLIYKWVMBBFX +ROHLIYKWVMBBFX +ROHLIYKWVMBBFX +ROHLIYKWVMBBFX +ROHLIYKWVMBBFX +ROHLIYKWVMBBFX +ROHLIYKWVMBBFX +ROHLIYKWVMBBFX +SORUXVRKWOHYEO +SORUXVRKWOHYEO +SORUXVRKWOHYEO +SORUXVRKWOHYEO +SORUXVRKWOHYEO +SORUXVRKWOHYEO +SORUXVRKWOHYEO +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +DQYACEDUQHWXQZ +XEMVQWDHRXAQNR +XEMVQWDHRXAQNR +XEMVQWDHRXAQNR +XEMVQWDHRXAQNR +XEMVQWDHRXAQNR +XEMVQWDHRXAQNR +XEMVQWDHRXAQNR +XEMVQWDHRXAQNR +XEMVQWDHRXAQNR +XEMVQWDHRXAQNR +XEMVQWDHRXAQNR +FDASUPFDHLZNSK +FDASUPFDHLZNSK +FDASUPFDHLZNSK +FDASUPFDHLZNSK +FDASUPFDHLZNSK +FDASUPFDHLZNSK +FDASUPFDHLZNSK +FDASUPFDHLZNSK +FDASUPFDHLZNSK +FDASUPFDHLZNSK +FDASUPFDHLZNSK +FDASUPFDHLZNSK +FDASUPFDHLZNSK +IMRGSWAJVVVYOW +IMRGSWAJVVVYOW +IMRGSWAJVVVYOW +IMRGSWAJVVVYOW +IMRGSWAJVVVYOW +IMRGSWAJVVVYOW +IMRGSWAJVVVYOW +IMRGSWAJVVVYOW +IMRGSWAJVVVYOW +IMRGSWAJVVVYOW +VOTWPIJKXUAOOZ +VOTWPIJKXUAOOZ +VOTWPIJKXUAOOZ +VOTWPIJKXUAOOZ +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +RMIQIULKBBCLIL +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +ZCEMXUNJITYHIZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +OLAMGHNQGZIWHZ +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +BSYHSWKTXMTFNF +RMSKZOXJAHOIER +RMSKZOXJAHOIER +RMSKZOXJAHOIER +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +LRRDDWMXYOSKIC +VANSZAOQCMTTPB +VANSZAOQCMTTPB +VANSZAOQCMTTPB +VANSZAOQCMTTPB +VANSZAOQCMTTPB +VANSZAOQCMTTPB +VANSZAOQCMTTPB +VANSZAOQCMTTPB +VANSZAOQCMTTPB +VANSZAOQCMTTPB +VANSZAOQCMTTPB +VANSZAOQCMTTPB +MMTWXUQMLQGAPC +MMTWXUQMLQGAPC +MMTWXUQMLQGAPC +MMTWXUQMLQGAPC +MMTWXUQMLQGAPC +MMTWXUQMLQGAPC +MMTWXUQMLQGAPC +MMTWXUQMLQGAPC +MMTWXUQMLQGAPC +MMTWXUQMLQGAPC +MMTWXUQMLQGAPC +MMTWXUQMLQGAPC +LMIKDUTVALJRPS +LMIKDUTVALJRPS +LMIKDUTVALJRPS +LMIKDUTVALJRPS +LMIKDUTVALJRPS +NRNOIJZZYJOCDE +NRNOIJZZYJOCDE +NRNOIJZZYJOCDE +NRNOIJZZYJOCDE +NRNOIJZZYJOCDE +NRNOIJZZYJOCDE +NRNOIJZZYJOCDE +QBHFNFLBWWPGKN +QBHFNFLBWWPGKN +QBHFNFLBWWPGKN +QBHFNFLBWWPGKN +QBHFNFLBWWPGKN +ORGVYSONNBFESV +ORGVYSONNBFESV +ORGVYSONNBFESV +ORGVYSONNBFESV +ORGVYSONNBFESV +ORGVYSONNBFESV +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +CXVOPJQBVVUOTC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +RYVQUCPUCSYNBC +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +JPJDIOVDAAVUNF +OQANKTWSGPYURN +OQANKTWSGPYURN +OQANKTWSGPYURN +OQANKTWSGPYURN +OQANKTWSGPYURN +OQANKTWSGPYURN +OQANKTWSGPYURN +OQANKTWSGPYURN +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +KRVIIMWSCXORIQ +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +UGHBHGHMKLPTQY +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +HWYCRLFVQVFKPD +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IIJUXCHFDCTCAH +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +IQPQUCSPCDSVLE +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +JHUNHTOHTUZTKV +WIDIORLKUZCAMX +WIDIORLKUZCAMX +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +GUQQBLRVXOUDTN +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +MINBUKAFVRAUDG +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +CEUOJNPNKKLCDB +JTLPUINSVFNPLS +JTLPUINSVFNPLS +JTLPUINSVFNPLS +JTLPUINSVFNPLS +JTLPUINSVFNPLS +JTLPUINSVFNPLS +JTLPUINSVFNPLS +HNGNQFQJPOBLJE +HNGNQFQJPOBLJE +HNGNQFQJPOBLJE +HNGNQFQJPOBLJE +FIGCRSATKGRFOH +FIGCRSATKGRFOH +FIGCRSATKGRFOH +FIGCRSATKGRFOH +FIGCRSATKGRFOH +FIGCRSATKGRFOH +FIGCRSATKGRFOH +FIGCRSATKGRFOH +FIGCRSATKGRFOH +FIGCRSATKGRFOH +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +VUOFIHCZMOIBFY +XDLBSNLAIQNWON +XDLBSNLAIQNWON +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +CMQOKNQYLSMKJC +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +KFYOFJUUTSALEH +SLEOSPFLNGKQLW +SLEOSPFLNGKQLW +SLEOSPFLNGKQLW +SLEOSPFLNGKQLW +SLEOSPFLNGKQLW +SNZNSNULJBXKRP +SNZNSNULJBXKRP +SNZNSNULJBXKRP +SNZNSNULJBXKRP +SNZNSNULJBXKRP +ORGFYMVNMFQORV +ORGFYMVNMFQORV +ORGFYMVNMFQORV +ORGFYMVNMFQORV +ORGFYMVNMFQORV +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +GOOFZOQDLIMARN +XVAPNQFQPDAROQ +XVAPNQFQPDAROQ +XVAPNQFQPDAROQ +XVAPNQFQPDAROQ +XVAPNQFQPDAROQ +XVAPNQFQPDAROQ +BXKNQKQIBKBMIZ +BXKNQKQIBKBMIZ +GHUUTEXYFBCKSM +GHUUTEXYFBCKSM +GHUUTEXYFBCKSM +DAIAMOGGSOXZSO +DAIAMOGGSOXZSO +LMEHVEUFNRJAAV +LMEHVEUFNRJAAV +LMEHVEUFNRJAAV +LMEHVEUFNRJAAV +LMEHVEUFNRJAAV +LMEHVEUFNRJAAV +LMEHVEUFNRJAAV +LMEHVEUFNRJAAV +LMEHVEUFNRJAAV +LMEHVEUFNRJAAV +LMEHVEUFNRJAAV +LMEHVEUFNRJAAV +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +FEZDDYPHEHMXLF +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +CCRXMHCQWYVXTE +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +RZVUCQZHOKQLFV +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +ASBDWVACJRRBIZ +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +SQMGCPHFHQGPIF +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +DHJXZSFKLJCHLH +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +YRECILNLFWZVRM +BHPGRVQWTLDDQX +BHPGRVQWTLDDQX +BHPGRVQWTLDDQX +BHPGRVQWTLDDQX +QOMBXPYXWGTFNR +QOMBXPYXWGTFNR +QOMBXPYXWGTFNR +QOMBXPYXWGTFNR +QOMBXPYXWGTFNR +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +KLQXMRBGMLHBBQ +MBWUSSKCCUMJHO +MBWUSSKCCUMJHO +MBWUSSKCCUMJHO +MBWUSSKCCUMJHO +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +IRQXZTBHNKVIRL +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PHDZNMWTZQPAEW +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +PMVCHAWVCIWVLP +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +ZVTVWDXRNMHGNY +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +SVHJCTSSYQPWEV +NVDZRSWQWPPKAI +NVDZRSWQWPPKAI +NVDZRSWQWPPKAI +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +AMXYFWUYMQOLRN +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +KQSFNXMDCOFFGW +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +VENRSYBHHVDBDC +RBXVTEUAOTYIME +RBXVTEUAOTYIME +RBXVTEUAOTYIME +RBXVTEUAOTYIME +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +UUDZDKPKXAEKLA +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +PHASMOUKYDUAOZ +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +UAPZTGRENZINFN +FOSYZKSOJUQLTD +FOSYZKSOJUQLTD +FOSYZKSOJUQLTD +GSKWIWOAUZQVES +GQRPJUIKGLHLLN +GQRPJUIKGLHLLN +GQRPJUIKGLHLLN +GQRPJUIKGLHLLN +GQRPJUIKGLHLLN +GQRPJUIKGLHLLN +GQRPJUIKGLHLLN +GQRPJUIKGLHLLN +GQRPJUIKGLHLLN +GQRPJUIKGLHLLN +GQRPJUIKGLHLLN +GQRPJUIKGLHLLN +GQRPJUIKGLHLLN +GQRPJUIKGLHLLN +GQRPJUIKGLHLLN +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +XTSVKUJYTUPYRJ +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +YBCOIJNAMJAFSO +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +KRQDMAXNTWLTDZ +YMWRMAOPKNYHMZ +AGBCLJAHARWNLA +AGBCLJAHARWNLA +AGBCLJAHARWNLA +AGBCLJAHARWNLA +AGBCLJAHARWNLA +AGBCLJAHARWNLA +AGBCLJAHARWNLA +MQDZZCJYWRZONM +MQDZZCJYWRZONM +MQDZZCJYWRZONM +MQDZZCJYWRZONM +MQDZZCJYWRZONM +MQDZZCJYWRZONM +MQDZZCJYWRZONM +MQDZZCJYWRZONM +MQDZZCJYWRZONM +MQDZZCJYWRZONM +MQDZZCJYWRZONM +MQDZZCJYWRZONM +MQDZZCJYWRZONM +MQDZZCJYWRZONM +MQDZZCJYWRZONM +JOKBBQPBIIZMJV +JOKBBQPBIIZMJV +JOKBBQPBIIZMJV +JOKBBQPBIIZMJV +JOKBBQPBIIZMJV +OHVJCFZJKPEJRL +OHVJCFZJKPEJRL +OHVJCFZJKPEJRL +OHVJCFZJKPEJRL +OHVJCFZJKPEJRL +OHVJCFZJKPEJRL +JFACETXYABVHFD +JFACETXYABVHFD +ZYCAGKYWXRKLSN +ZYCAGKYWXRKLSN +ZYCAGKYWXRKLSN +ZYCAGKYWXRKLSN +ZYCAGKYWXRKLSN +ZYCAGKYWXRKLSN +ZYCAGKYWXRKLSN +ZYCAGKYWXRKLSN +ZYCAGKYWXRKLSN +FNMHEHXNBNCPCI +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +ALERZNQPBWWLMW +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +UNLDMOJTKKEMOG +JMBINOWGIHWPJI +DTOUWTJYUCZJQD +DTOUWTJYUCZJQD +DTOUWTJYUCZJQD +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +LLEMSCWAKNQHHA +WYKQPGOKTKQHQG +WYKQPGOKTKQHQG +WYKQPGOKTKQHQG +WYKQPGOKTKQHQG +WYKQPGOKTKQHQG +WYKQPGOKTKQHQG +WYKQPGOKTKQHQG +WYKQPGOKTKQHQG +WYKQPGOKTKQHQG +WYKQPGOKTKQHQG +WYKQPGOKTKQHQG +WYKQPGOKTKQHQG +STFFIQHUWFISBB +STFFIQHUWFISBB +FNIRVWPHRMMRQI +FNIRVWPHRMMRQI +FNIRVWPHRMMRQI +FNIRVWPHRMMRQI +FNIRVWPHRMMRQI +FNIRVWPHRMMRQI +FNIRVWPHRMMRQI +FNIRVWPHRMMRQI +FNIRVWPHRMMRQI +FNIRVWPHRMMRQI +FNIRVWPHRMMRQI +FNIRVWPHRMMRQI +BROOMPUVDPTGEG +BROOMPUVDPTGEG +BROOMPUVDPTGEG +BROOMPUVDPTGEG +CZSBHMFVVLYIQQ +CZSBHMFVVLYIQQ +CZSBHMFVVLYIQQ +CZSBHMFVVLYIQQ +CZSBHMFVVLYIQQ +CZSBHMFVVLYIQQ +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +RCTKRNCKOYYRIO +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +LLXVPTXOKTYXHU +VJEMOEYSQDKAQF +VJEMOEYSQDKAQF +VJEMOEYSQDKAQF +VJEMOEYSQDKAQF +VJEMOEYSQDKAQF +VJEMOEYSQDKAQF +VJEMOEYSQDKAQF +VJEMOEYSQDKAQF +VEBVPUXQAPLADL +VEBVPUXQAPLADL +XKXYJTIBKZGIPR +XKXYJTIBKZGIPR +DCULYKVTBAXAER +DCULYKVTBAXAER +DCULYKVTBAXAER +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +IVYWRYGMQNKDQB +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +PULWZCUZNRVAHT +ADPAPZVYVYEBGS +ADPAPZVYVYEBGS +ADPAPZVYVYEBGS +ADPAPZVYVYEBGS +ADPAPZVYVYEBGS +ADPAPZVYVYEBGS +ADPAPZVYVYEBGS +ADPAPZVYVYEBGS +ADPAPZVYVYEBGS +ADPAPZVYVYEBGS +ADPAPZVYVYEBGS +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +YWPVROCHNBYFTP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +CXSXBHMYYCPTHP +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +BQTYHFZQSAKNQU +JPYYWXPAHJBKJX +JPYYWXPAHJBKJX +JPYYWXPAHJBKJX +JPYYWXPAHJBKJX +KFEFLPDKISUVNR +KFEFLPDKISUVNR +KFEFLPDKISUVNR +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +GAZDXIGXYWVWQX +ALYHYIXFUOUIHJ +ALYHYIXFUOUIHJ +ALYHYIXFUOUIHJ +ALYHYIXFUOUIHJ +ALYHYIXFUOUIHJ +ALYHYIXFUOUIHJ +ALYHYIXFUOUIHJ +ALYHYIXFUOUIHJ +ALYHYIXFUOUIHJ +IAEZLXLDZBZQPU +IAEZLXLDZBZQPU +QGVLYPPODPLXMB +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +BDCURAWBZJMFIK +LLPWNQMSUYAGQI +HELXLJCILKEWJH +HELXLJCILKEWJH +HELXLJCILKEWJH +HELXLJCILKEWJH +HELXLJCILKEWJH +HELXLJCILKEWJH +HELXLJCILKEWJH +HELXLJCILKEWJH +HELXLJCILKEWJH +HELXLJCILKEWJH +HELXLJCILKEWJH +LPZSTPCYWWRQFU +LPZSTPCYWWRQFU +LPZSTPCYWWRQFU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +MDFCJNFOINXVSU +FBSKJMQYURKNSU +ONMDPPVVEFWDOD +ONMDPPVVEFWDOD +ONMDPPVVEFWDOD +ONMDPPVVEFWDOD +ONMDPPVVEFWDOD +ONMDPPVVEFWDOD +NAHTXVIXCMUDLF +NAHTXVIXCMUDLF +NAHTXVIXCMUDLF +NAHTXVIXCMUDLF +NAHTXVIXCMUDLF +FSBUXLDOLNLABB +FSBUXLDOLNLABB +FSBUXLDOLNLABB +FSBUXLDOLNLABB +FSBUXLDOLNLABB +NJPDRQDELKMUTI +NJPDRQDELKMUTI +AJUACYVEKRAXEB +AJUACYVEKRAXEB +AJUACYVEKRAXEB +AJUACYVEKRAXEB +AJUACYVEKRAXEB +AJUACYVEKRAXEB +AJUACYVEKRAXEB +AJUACYVEKRAXEB +AJUACYVEKRAXEB +AJUACYVEKRAXEB +GOHMRMDXUXWCDQ +GOHMRMDXUXWCDQ +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +JVBLTQQBEQQLEV +ZDZSFWLPCFRASW +ZDZSFWLPCFRASW +ZDZSFWLPCFRASW +PBFGAFDJVQAMRS +PBFGAFDJVQAMRS +PBFGAFDJVQAMRS +PBFGAFDJVQAMRS +PBFGAFDJVQAMRS +XQVKQEFQGYTUAR +XQVKQEFQGYTUAR +XQVKQEFQGYTUAR +XQVKQEFQGYTUAR +RNHLYDFRRIHVAM +RNHLYDFRRIHVAM +CHACNMULAGKUQN +CHACNMULAGKUQN +CHACNMULAGKUQN +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +DTTPWCNKTMQMTE +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +ZZZYHIMVKOHVIH +GKRBWXABVALDGQ +GKRBWXABVALDGQ +GKRBWXABVALDGQ +GKRBWXABVALDGQ +GKRBWXABVALDGQ +GKRBWXABVALDGQ +GKRBWXABVALDGQ +GKRBWXABVALDGQ +GKRBWXABVALDGQ +GKRBWXABVALDGQ +GKRBWXABVALDGQ +GKRBWXABVALDGQ +GKRBWXABVALDGQ +GKRBWXABVALDGQ +GKRBWXABVALDGQ +GKRBWXABVALDGQ +VQQGPFFHGWNIGX +VQQGPFFHGWNIGX +VQQGPFFHGWNIGX +VQQGPFFHGWNIGX +VQQGPFFHGWNIGX +VQQGPFFHGWNIGX +VQQGPFFHGWNIGX +VQQGPFFHGWNIGX +VQQGPFFHGWNIGX +VQQGPFFHGWNIGX +VQQGPFFHGWNIGX +XSQFDXNJFMCRGJ +XSQFDXNJFMCRGJ +XSQFDXNJFMCRGJ +FPECZWKKKKZPPP +FPECZWKKKKZPPP +FPECZWKKKKZPPP +FPECZWKKKKZPPP +FPECZWKKKKZPPP +FPECZWKKKKZPPP +FPECZWKKKKZPPP +FPECZWKKKKZPPP +FPECZWKKKKZPPP +FPECZWKKKKZPPP +FPECZWKKKKZPPP +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +ZJRDCQWLAILQHR +OHJWWOZXCKEOGK +OHJWWOZXCKEOGK +OHJWWOZXCKEOGK +OHJWWOZXCKEOGK +OHJWWOZXCKEOGK +OHJWWOZXCKEOGK +OHJWWOZXCKEOGK +OHJWWOZXCKEOGK +OHJWWOZXCKEOGK +OHJWWOZXCKEOGK +OHJWWOZXCKEOGK +OHJWWOZXCKEOGK +ROLIIKCIEQNTMT +ROLIIKCIEQNTMT +PCWTUTJLXXOQPR +PCWTUTJLXXOQPR +PCWTUTJLXXOQPR +PCWTUTJLXXOQPR +PCWTUTJLXXOQPR +PCWTUTJLXXOQPR +PHEDXBVPIONUQT +PHEDXBVPIONUQT +GDGZMMDZJVKXTP +GDGZMMDZJVKXTP +KWRQPASKWCJCPI +KWRQPASKWCJCPI +KWRQPASKWCJCPI +KWRQPASKWCJCPI +KWRQPASKWCJCPI +KWRQPASKWCJCPI +KWRQPASKWCJCPI +KWRQPASKWCJCPI +FXFHFOSEURHWMO +FXFHFOSEURHWMO +FXFHFOSEURHWMO +FXFHFOSEURHWMO +FXFHFOSEURHWMO +FXFHFOSEURHWMO +FXFHFOSEURHWMO +FXFHFOSEURHWMO +FXFHFOSEURHWMO +FXFHFOSEURHWMO +YTPBUIWNJRGZFW +YTPBUIWNJRGZFW +YTPBUIWNJRGZFW +YTPBUIWNJRGZFW +YTPBUIWNJRGZFW +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +QGMUCGXWCKWHRJ +KZLDMAIXPXOZCX +KZLDMAIXPXOZCX +KZLDMAIXPXOZCX +KZLDMAIXPXOZCX +KZLDMAIXPXOZCX +KZLDMAIXPXOZCX +KZLDMAIXPXOZCX +KZLDMAIXPXOZCX +KZLDMAIXPXOZCX +KZLDMAIXPXOZCX +KZLDMAIXPXOZCX +KZLDMAIXPXOZCX +KZLDMAIXPXOZCX +KZLDMAIXPXOZCX +KZLDMAIXPXOZCX +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +ZTQSADJAYQOCDD +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +SXILFEBNQCRWAL +ZRBFCAALKKNCJG +ZRBFCAALKKNCJG +ZRBFCAALKKNCJG +ZRBFCAALKKNCJG +ZRBFCAALKKNCJG +UOJAEODBOCLNBU +UOJAEODBOCLNBU +UOJAEODBOCLNBU +UOJAEODBOCLNBU +UOJAEODBOCLNBU +UOJAEODBOCLNBU +UOJAEODBOCLNBU +UOJAEODBOCLNBU +UOJAEODBOCLNBU +UOJAEODBOCLNBU +UOJAEODBOCLNBU +UOJAEODBOCLNBU +UOJAEODBOCLNBU +UOJAEODBOCLNBU +UOJAEODBOCLNBU +UOJAEODBOCLNBU +SEBIKDIMAPSUBY +SEBIKDIMAPSUBY +SEBIKDIMAPSUBY +SEBIKDIMAPSUBY +SEBIKDIMAPSUBY +SEBIKDIMAPSUBY +SEBIKDIMAPSUBY +SEBIKDIMAPSUBY +SEBIKDIMAPSUBY +SEBIKDIMAPSUBY +SEBIKDIMAPSUBY +SEBIKDIMAPSUBY +SEBIKDIMAPSUBY +SEBIKDIMAPSUBY +GBXXXUUAOFPGRP +GBXXXUUAOFPGRP +GBXXXUUAOFPGRP +GBXXXUUAOFPGRP +GBXXXUUAOFPGRP +GBXXXUUAOFPGRP +GBXXXUUAOFPGRP +GBXXXUUAOFPGRP +GBXXXUUAOFPGRP +GBXXXUUAOFPGRP +GBXXXUUAOFPGRP +VDJHFHXMUKFKET +VDJHFHXMUKFKET +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +QFIYSPKZWOALMZ +NNWMHSNRRWMMBI +NNWMHSNRRWMMBI +NNWMHSNRRWMMBI +NNWMHSNRRWMMBI +NNWMHSNRRWMMBI +JUKFJOYCFLIWIA +JUKFJOYCFLIWIA +JUKFJOYCFLIWIA +JUKFJOYCFLIWIA +JUKFJOYCFLIWIA +JUKFJOYCFLIWIA +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +DBODJJZRZFZBBD +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +VCMIRXRRQJNZJT +POVCYOFRCMBMKD +POVCYOFRCMBMKD +POVCYOFRCMBMKD +POVCYOFRCMBMKD +POVCYOFRCMBMKD +APPXYONGBIXGRO +APPXYONGBIXGRO +APPXYONGBIXGRO +APPXYONGBIXGRO +APPXYONGBIXGRO +APPXYONGBIXGRO +APPXYONGBIXGRO +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +GRMZCIPHHBSLFF +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +YJUGKYOFRZOMIJ +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +VPKHXKUPCJSCHF +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +LATOODWWVGAHQU +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +UEXLXEOCAYUYCI +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +QTVVOIBACOUVOE +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +BIBJKFZXVFHSLG +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +MMJORIFPGDWBAA +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +YEIWCFPXBQSECZ +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +ALUBZGFIRHMLEY +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +PECAVQSFOYERFI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +BZWHQGDEECXEJI +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +COICYYHTLYZMEX +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +MQUQKIFKNUZAPC +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +LKRVWDPKVDSKFP +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +OCPBZMNGFBHXLX +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +WJTIKZWXSWMEDO +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +IZDYRXBFTDBGQL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +OOKSNNJCBKFTNL +GCDZLGORNNUQKQ +GCDZLGORNNUQKQ +GCDZLGORNNUQKQ +GCDZLGORNNUQKQ +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +OSJXTRFYPLXSCM +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +CZCYLMJWKDADHN +RRZXIRBKKLTSOM +RRZXIRBKKLTSOM +RRZXIRBKKLTSOM +RRZXIRBKKLTSOM +RRZXIRBKKLTSOM +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +JQBOIGWHYPDAGZ +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LUULUSZGAPNFFC +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +LBQUZEGPLOWJBH +OEHBHOIFLXXHAM +OEHBHOIFLXXHAM +OEHBHOIFLXXHAM +OEHBHOIFLXXHAM +OEHBHOIFLXXHAM +OEHBHOIFLXXHAM +OEHBHOIFLXXHAM +OEHBHOIFLXXHAM +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +PPDAUNOQRVBQMF +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +GLYSZGOHXHBWEX +AFAZEQKSVKDGFX +AFAZEQKSVKDGFX +AFAZEQKSVKDGFX +AFAZEQKSVKDGFX +AFAZEQKSVKDGFX +AFAZEQKSVKDGFX +AFAZEQKSVKDGFX +AFAZEQKSVKDGFX +AFAZEQKSVKDGFX +AFAZEQKSVKDGFX +AFAZEQKSVKDGFX +AFAZEQKSVKDGFX +AFAZEQKSVKDGFX +AFAZEQKSVKDGFX +AFAZEQKSVKDGFX +AFAZEQKSVKDGFX +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +CHQPDRGLGJNQTJ +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +IMVHYSWWBHTDEG +KMPDNLYICWJCPY +KMPDNLYICWJCPY +KMPDNLYICWJCPY +KMPDNLYICWJCPY +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +CMDLPOPJXJYAMB +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +UHIVCBYOSUWBFO +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +IQADDBRVOPAFGT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +AYNMYQSRRVGZDT +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +UVLDARVNLRWGBB +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +RMBWSMLHEVFJTJ +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +HMKFAVZUWUBUOL +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +NVXMWPFVIMTPPT +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +FGTZNLNLDSXGLN +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +KRUJMYARKZZEEH +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +SPUDVSNUPBWEKG +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +ZUADJZOWTIKNGE +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +YYAHDCGHROJYNX +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +UTGUKTQOTCXQJK +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +KYPPZUHEYJBGDV +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +VLOLGVKDVDYZDC +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +BYEKJUATVGKCCZ +FHHRXCGEIWKTJD +FHHRXCGEIWKTJD +FHHRXCGEIWKTJD +FHHRXCGEIWKTJD +FHHRXCGEIWKTJD +FHHRXCGEIWKTJD +FHHRXCGEIWKTJD +FHHRXCGEIWKTJD +FHHRXCGEIWKTJD +FHHRXCGEIWKTJD +FHHRXCGEIWKTJD +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +DNJKZCQLZZLNBI +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +ZZCKZGQBKUWXLP +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +PQOCSSYRLUIAGG +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +NGOFDYKRKVTNMQ +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +UXNQBNHINOSGKB +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +ZZKIZZPHRSGBCQ +CXCKOTGRTPLISC +CXCKOTGRTPLISC +CXCKOTGRTPLISC +CXCKOTGRTPLISC +CXCKOTGRTPLISC +CXCKOTGRTPLISC +KBMOUMVVDXEABW +KBMOUMVVDXEABW +KBMOUMVVDXEABW +KBMOUMVVDXEABW +KBMOUMVVDXEABW +KBMOUMVVDXEABW +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +AAQMEKVMBSHQSI +ZHOMOKSXIMUJFE +ZHOMOKSXIMUJFE +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +VVPXASQNOLYBCR +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +COMWUAHOGCVVNZ +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GTJPHZMORIYVET +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +GCKXCHKHBLNGAF +WVRAIABMMRFVCC +WVRAIABMMRFVCC +WVRAIABMMRFVCC +WVRAIABMMRFVCC +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +VHMCLONZXOFDIQ +PORLQGCIBQPFNX +PORLQGCIBQPFNX +PORLQGCIBQPFNX +PORLQGCIBQPFNX +PORLQGCIBQPFNX +PORLQGCIBQPFNX +PORLQGCIBQPFNX +PORLQGCIBQPFNX +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +IAONIGCHXNWXRN +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +PZEAYKDDQCGSQU +CXJYWHJEDMKNQV +CXJYWHJEDMKNQV +CXJYWHJEDMKNQV +CXJYWHJEDMKNQV +CXJYWHJEDMKNQV +CXJYWHJEDMKNQV +CXJYWHJEDMKNQV +CXJYWHJEDMKNQV +CXJYWHJEDMKNQV +CXJYWHJEDMKNQV +CXJYWHJEDMKNQV +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +OTBYDWMNPJJQRG +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +BXRYGYIQEUOTHD +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +GPHUERASPIVMNY +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +KSZOEOONASRENA +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +IFQVDHKHKVDYQC +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +YMUPMGXXRIJHKA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +HRHHAUYCXBULEA +CHYCVUXYOXCKIA +CHYCVUXYOXCKIA +CHYCVUXYOXCKIA +CHYCVUXYOXCKIA +CHYCVUXYOXCKIA +CHYCVUXYOXCKIA +CHYCVUXYOXCKIA +CHYCVUXYOXCKIA +CHYCVUXYOXCKIA +CHYCVUXYOXCKIA +CHYCVUXYOXCKIA +CHYCVUXYOXCKIA +CHYCVUXYOXCKIA +CHYCVUXYOXCKIA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +GQNZXZQBLQFJRA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +YQNZQGYHBNTVJA +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +XRJZHIKWAQXHES +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +NGSCXLPAQKLFEH +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +WEBIALRSFYYZNQ +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +VUEOHJNEHXJLDD +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +NIYIYLBOTBYWCY +JFIHYHJHQKUDKD +JFIHYHJHQKUDKD +JFIHYHJHQKUDKD +JFIHYHJHQKUDKD +JFIHYHJHQKUDKD +JFIHYHJHQKUDKD +JFIHYHJHQKUDKD +JFIHYHJHQKUDKD +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +JYRLHZSQUXTFGH +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +DEYFVOXDNWADAV +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +JGXWCDPVBXRRGK +FCVHQMAHORAAKT +FCVHQMAHORAAKT +FCVHQMAHORAAKT +FCVHQMAHORAAKT +FCVHQMAHORAAKT +FCVHQMAHORAAKT +FCVHQMAHORAAKT +FCVHQMAHORAAKT +FCVHQMAHORAAKT +FCVHQMAHORAAKT +FCVHQMAHORAAKT +FCVHQMAHORAAKT +FCVHQMAHORAAKT +FCVHQMAHORAAKT +FCVHQMAHORAAKT +FCVHQMAHORAAKT +FCVHQMAHORAAKT +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +HRIXOCFMOJEHEU +GEZBXBRXWZJSAV +GEZBXBRXWZJSAV +GEZBXBRXWZJSAV +GEZBXBRXWZJSAV +GEZBXBRXWZJSAV +GEZBXBRXWZJSAV +GEZBXBRXWZJSAV +GEZBXBRXWZJSAV +GEZBXBRXWZJSAV +GEZBXBRXWZJSAV +GEZBXBRXWZJSAV +GEZBXBRXWZJSAV +GEZBXBRXWZJSAV +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +FSTKYJOKUUVVMY +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +WMKLFPXUNOJLQJ +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +QKUFYFUSJMGILO +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +VCKWOVWEDVNOPY +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +HTABAKXDSDOMBN +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +JLRMLSBSAUWVEO +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +SJHHSDDZARIHAT +XLRHKPTXMXNAGC +XLRHKPTXMXNAGC +XLRHKPTXMXNAGC +XLRHKPTXMXNAGC +XLRHKPTXMXNAGC +XLRHKPTXMXNAGC +XLRHKPTXMXNAGC +XLRHKPTXMXNAGC +XLRHKPTXMXNAGC +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +YSPKLVVMZUKLMR +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +ZOHJKBZGFBXFIK +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +LCMBEQGDYIBKDI +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +WRALEXHONIJMHH +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +HIGQXZHPJLAGRO +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +DNENKAQJQROMKF +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +PKWWCBPJIAJTFT +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +CDDYZYIBFIQEGM +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +ZYBXFVWSQYBVRU +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +YIIKPFWLWYKDPH +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +MMPLVSBMCAPCST +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +GDHMEZCJJXUPRD +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +ULRPKNXAJVTGHF +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +RHYJRVWWDRGDRZ +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +KZWKYXLDADOEHV +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +BVUOXVSHTGNMRR +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +FWQOFYXNBFEBBX +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +YTWLZXBVJMNCIR +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +IGRQQBJWAYJYAO +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +WDQNDXPFEWOQRR +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +GOYSXGAZKUHVSU +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +FQUDJJZUNNQPPW +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +SNCVSGFALWTXMM +WNGVOVVMNRIJOX +WNGVOVVMNRIJOX +WNGVOVVMNRIJOX +WNGVOVVMNRIJOX +WNGVOVVMNRIJOX +WNGVOVVMNRIJOX +WNGVOVVMNRIJOX +WNGVOVVMNRIJOX +WNGVOVVMNRIJOX +WNGVOVVMNRIJOX +WNGVOVVMNRIJOX +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +ANKZXIMZBGQTDU +DZWQPAFWILBODA +DZWQPAFWILBODA +DZWQPAFWILBODA +DZWQPAFWILBODA +DZWQPAFWILBODA +DZWQPAFWILBODA +DZWQPAFWILBODA +DZWQPAFWILBODA +DZWQPAFWILBODA +DZWQPAFWILBODA +DZWQPAFWILBODA +DZWQPAFWILBODA +DZWQPAFWILBODA +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +RXZBMPWDPOLZGW +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +WWZDOUGJVPBIAE +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +PTTHZFHYUGPBTR +MCCCQAKRHCMRDG +MCCCQAKRHCMRDG +MCCCQAKRHCMRDG +MCCCQAKRHCMRDG +MCCCQAKRHCMRDG +MCCCQAKRHCMRDG +MCCCQAKRHCMRDG +MCCCQAKRHCMRDG +MCCCQAKRHCMRDG +MCCCQAKRHCMRDG +MCCCQAKRHCMRDG +MCCCQAKRHCMRDG +MCCCQAKRHCMRDG +MCCCQAKRHCMRDG +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +KBLILLDKTZXCRK +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +DHCSEHRBYOAURX +SBGHXFWRTKOHQM +SBGHXFWRTKOHQM +SBGHXFWRTKOHQM +SBGHXFWRTKOHQM +SBGHXFWRTKOHQM +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +DNZFPUQJJQXSKX +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +FLLNNFLVVBJTDW +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +SIWOWUAUIFWBDY +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CLITZDLAUPSELL +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +CMLFXLQIXVGGKS +OUTJRQWSVYAHKN +OUTJRQWSVYAHKN +OUTJRQWSVYAHKN +OUTJRQWSVYAHKN +OUTJRQWSVYAHKN +OUTJRQWSVYAHKN +OUTJRQWSVYAHKN +OUTJRQWSVYAHKN +OUTJRQWSVYAHKN +OUTJRQWSVYAHKN +OUTJRQWSVYAHKN +OUTJRQWSVYAHKN +OUTJRQWSVYAHKN +OUTJRQWSVYAHKN +OUTJRQWSVYAHKN +OUTJRQWSVYAHKN +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +JPWNMAPTZSNOOF +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +HPXCSOULTKVTSY +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +TVWFNXOWNNUFJH +ZAYYDHWLJXZASK +ZAYYDHWLJXZASK +ZAYYDHWLJXZASK +ZAYYDHWLJXZASK +ZAYYDHWLJXZASK +NGROIZSHBGXMTB +NGROIZSHBGXMTB +NGROIZSHBGXMTB +NGROIZSHBGXMTB +NGROIZSHBGXMTB +NGROIZSHBGXMTB +NGROIZSHBGXMTB +NGROIZSHBGXMTB +NGROIZSHBGXMTB +NGROIZSHBGXMTB +NGROIZSHBGXMTB +NGROIZSHBGXMTB +NGROIZSHBGXMTB +NGROIZSHBGXMTB +NGROIZSHBGXMTB +NGROIZSHBGXMTB +NGROIZSHBGXMTB +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +DINQLGRRIYZCPG +OBATZBGFDSVCJD +OBATZBGFDSVCJD +OBATZBGFDSVCJD +OBATZBGFDSVCJD +OBATZBGFDSVCJD +OBATZBGFDSVCJD +OBATZBGFDSVCJD +OBATZBGFDSVCJD +OBATZBGFDSVCJD +BPXIBBNVQKIXGG +BPXIBBNVQKIXGG +BPXIBBNVQKIXGG +BPXIBBNVQKIXGG +BPXIBBNVQKIXGG +BPXIBBNVQKIXGG +BPXIBBNVQKIXGG +BPXIBBNVQKIXGG +BPXIBBNVQKIXGG +BPXIBBNVQKIXGG +BPXIBBNVQKIXGG +BPXIBBNVQKIXGG +BPXIBBNVQKIXGG +BPXIBBNVQKIXGG +BPXIBBNVQKIXGG +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +UWFFHFCGOLUSSJ +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +XTZYEQZLDDJMQG +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +RKRVMDIFXOUHOO +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +YFGQJKBUXPKSAW +ONFHKSKZLRQQLT +ONFHKSKZLRQQLT +ONFHKSKZLRQQLT +ONFHKSKZLRQQLT +ONFHKSKZLRQQLT +ONFHKSKZLRQQLT +ONFHKSKZLRQQLT +ONFHKSKZLRQQLT +ONFHKSKZLRQQLT +ONFHKSKZLRQQLT +ONFHKSKZLRQQLT +ONFHKSKZLRQQLT +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +SEGPIVDWCUSBFQ +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +RVLHHZKCFQNHII +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +IREXLBYIZXPNNP +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +LJWPEDHNPDOGIV +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +VSXAFEPYVMYOJE +UWOSPUSBILRKLD +UWOSPUSBILRKLD +UWOSPUSBILRKLD +UWOSPUSBILRKLD +UWOSPUSBILRKLD +UWOSPUSBILRKLD +UWOSPUSBILRKLD +UWOSPUSBILRKLD +UWOSPUSBILRKLD +UWOSPUSBILRKLD +UWOSPUSBILRKLD +UWOSPUSBILRKLD +UWOSPUSBILRKLD +UWOSPUSBILRKLD +MPOSMQNLNZBUHU +MPOSMQNLNZBUHU +MPOSMQNLNZBUHU +MPOSMQNLNZBUHU +MPOSMQNLNZBUHU +MPOSMQNLNZBUHU +MPOSMQNLNZBUHU +MPOSMQNLNZBUHU +MPOSMQNLNZBUHU +MPOSMQNLNZBUHU +MPOSMQNLNZBUHU +MPOSMQNLNZBUHU +MPOSMQNLNZBUHU +MPOSMQNLNZBUHU +MPOSMQNLNZBUHU +MPOSMQNLNZBUHU +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +GOURNRSYZGPZPD +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +MIFJQZQYQZGUOJ +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +RUFIGEPXTYTFFK +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +UORKJWHZGSSNRL +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +OJTOQAJKIWTRSX +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +ADWARAKZGQFXEL +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +IVLCKPYZTYRXJD +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +YGUPEEUNSXQVSW +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +QVSLFTXMKPGAHH +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +GPEQRJREUHYPPF +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DAXZWJMEKUNRCD +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +DXJGGEVMIZJZLN +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +NIEHAABHXAUTQI +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +BBNQHOMJRFAQBN +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +HJXLYWPYPALBPQ +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +KCGHQGJRWNZURY +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +IBKZACHZXMCFFG +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +PWMWFOWSRFRPQK +DSMISWZJFQQCFC +DSMISWZJFQQCFC +DSMISWZJFQQCFC +DSMISWZJFQQCFC +DSMISWZJFQQCFC +DSMISWZJFQQCFC +DSMISWZJFQQCFC +DSMISWZJFQQCFC +DSMISWZJFQQCFC +DSMISWZJFQQCFC +DSMISWZJFQQCFC +DSMISWZJFQQCFC +DSMISWZJFQQCFC +DSMISWZJFQQCFC +DSMISWZJFQQCFC +FCPYAOYFEWHACB +FCPYAOYFEWHACB +FCPYAOYFEWHACB +FCPYAOYFEWHACB +FCPYAOYFEWHACB +FCPYAOYFEWHACB +FCPYAOYFEWHACB +FCPYAOYFEWHACB +FCPYAOYFEWHACB +FCPYAOYFEWHACB +FCPYAOYFEWHACB +ILKZIWOLBIGWMR +ILKZIWOLBIGWMR +ILKZIWOLBIGWMR +ILKZIWOLBIGWMR +ILKZIWOLBIGWMR +DSGCKNJWFRMMHJ +DSGCKNJWFRMMHJ +DSGCKNJWFRMMHJ +DSGCKNJWFRMMHJ +DSGCKNJWFRMMHJ +DSGCKNJWFRMMHJ +DSGCKNJWFRMMHJ +DSGCKNJWFRMMHJ +DSGCKNJWFRMMHJ +DSGCKNJWFRMMHJ +DSGCKNJWFRMMHJ +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +CWHOTIZZRMFBCH +USLUCCCHZMUGNA +USLUCCCHZMUGNA +USLUCCCHZMUGNA +USLUCCCHZMUGNA +USLUCCCHZMUGNA +USLUCCCHZMUGNA +USLUCCCHZMUGNA +USLUCCCHZMUGNA +USLUCCCHZMUGNA +USLUCCCHZMUGNA +USLUCCCHZMUGNA +USLUCCCHZMUGNA +USLUCCCHZMUGNA +USLUCCCHZMUGNA +USLUCCCHZMUGNA +WLYKQFJPOHPJQU +WLYKQFJPOHPJQU +WLYKQFJPOHPJQU +WLYKQFJPOHPJQU +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +DKRBBFNVGJKSJY +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +XVVOKYPBUCCTSF +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +JKCJSQKIASUTKA +NXJLRTWACLZUAZ +NXJLRTWACLZUAZ +NXJLRTWACLZUAZ +AKPBFKMZYCIIQT +AKPBFKMZYCIIQT +AKPBFKMZYCIIQT +AKPBFKMZYCIIQT +AKPBFKMZYCIIQT +AKPBFKMZYCIIQT +AKPBFKMZYCIIQT +AKPBFKMZYCIIQT +AKPBFKMZYCIIQT +AKPBFKMZYCIIQT +AKPBFKMZYCIIQT +AKPBFKMZYCIIQT +AKPBFKMZYCIIQT +AKPBFKMZYCIIQT +AKPBFKMZYCIIQT +AKPBFKMZYCIIQT +QYGUYHZAAVMQBV +QYGUYHZAAVMQBV +VXGFERCTVPQXGZ +VXGFERCTVPQXGZ +VXGFERCTVPQXGZ +VXGFERCTVPQXGZ +VXGFERCTVPQXGZ +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +DYCBCGZSPKZVRY +CEAZRRDELHUEMR +GASQWTMIYCISED +XGWIJUOSCAQSSV +XGWIJUOSCAQSSV +XGWIJUOSCAQSSV +XGWIJUOSCAQSSV +XGWIJUOSCAQSSV +YYJNOYZRYGDPNH +YYJNOYZRYGDPNH +YYJNOYZRYGDPNH +YYJNOYZRYGDPNH +ZKWQQXZUCOBISE +ZKWQQXZUCOBISE +QLFZZSKTJWDQOS +QLFZZSKTJWDQOS +QLFZZSKTJWDQOS +GOLXNESZZPUPJE +GOLXNESZZPUPJE +GOLXNESZZPUPJE +GOLXNESZZPUPJE +GOLXNESZZPUPJE +GOLXNESZZPUPJE +GOLXNESZZPUPJE +AZSNMRSAGSSBNP +AZSNMRSAGSSBNP +AMPTWLHXXYAHSB +BTVYFIMKUHNOBZ +BTVYFIMKUHNOBZ +ZBAMSLOMNLECFR +SCYRNRIZFGMUSB +OEGLIHPBLJQCGW +KKNYIFDIQAVMQG +KKNYIFDIQAVMQG +DSPNTLCJTJBXTD +DSPNTLCJTJBXTD +WXDBUBIFYCCNLE +SVDMAXBQMZIUPX +UTERRJKSLJLXTA +UTERRJKSLJLXTA +OFDNQWIFNXBECV +OFDNQWIFNXBECV +JGSPEFLRDJUZIE +VCCUOZSDXVZCSK +VCCUOZSDXVZCSK +NYBZAGXTZXPYND +FZFYFSUIOSWLHW +RKEBXTALJSALNU +HZKFYHKCBBWPIX +JNLNEIIZZQABDP +AXVYUJOZRMCOOU +YWUNVHXKGMPHDM +UVDYUDNYSNKZRV +FKZUTWSVQLXKQE +VCBNPTWPJQLHQN +NGUGHCRMWIKICS +NGUGHCRMWIKICS +QEDDYPGFZGCYCZ +OMRQLNQIRCTHRM +MKBNTPDMOZKDSO +ZSZRBAQVYFYMTR +RQOFTLFCRJDAJR +ZZLORXCOISZFNX +OHDXGZAYYBMHCY +OHDXGZAYYBMHCY +OIQROOMINSFFMF +OIQROOMINSFFMF +QBTIITFMJQCGKE +QBTIITFMJQCGKE +ZBZVXBGUYOPNAE +ZBZVXBGUYOPNAE +ZITSQIZMRMDQLE +QQZJCNSHAVQKIC +KOTACARTLSNDDK +ZUXHELCHEWQXKW +QYRAHJVRFPJIQW +YAGQIZPAJNEIKG +HZWIJOWMGPTNRA +HZWIJOWMGPTNRA +GWLHFNKLJRZBAI +NZSWNNDHPOTJNH +PYGCSAAZMAASLA +BUSZTTGPPRHCRZ +DFVYLDHDFLHIAA +VRGWBRLULZUWAJ +MTEWLNRVQLKTFS +IBEDDHUHZBDXGB +BHYCLFCOZPICKT +SRZJEPUYAKAFIE +KSYRCWWRVVIIEX +YIAOKSMOIJEDIZ +ZOCXUHJGZXXIGQ +FMMUVGBTBZRVJU +NYBZAGXTZXPYND +KWOZSBGNAHVCKG +HWUUCABYFFQZHH +OHBCWVJHZZYAHJ +JQWUSEVRGIXWTP +RHJPBGWFGOAEID +REAZZDPREXHWNV +HCEQACRMJXGKHI +QMLZCOSZAXKRTJ +IINDQALFBNRRJE +IINDQALFBNRRJE +IINDQALFBNRRJE +IINDQALFBNRRJE +KOPJPWSRYZRWPD +KOPJPWSRYZRWPD +KOPJPWSRYZRWPD +KOPJPWSRYZRWPD +AWVNBSKIKNPOBG +AWVNBSKIKNPOBG +AWVNBSKIKNPOBG +AWVNBSKIKNPOBG +WKGYNBDVOPHKOW +WKGYNBDVOPHKOW +WKGYNBDVOPHKOW +WKGYNBDVOPHKOW +PCAYKUNUODABRQ +PCAYKUNUODABRQ +VGXYDZCCQDSGLZ +GZKGGHUTCBGDES +WQBVZBBQNNMLLX +KJPBPENONKNTAB +ZHGZIFCTZVOLMX +KMGWVOLORMQZAF +WUAZBFIPYKXGNS +YBQOZZHZAJCTLD +TYOWQSLRVAUSMI +QEUHGZGGGPRQOJ +QEUHGZGGGPRQOJ +DUAFPZACEFJNQR +CHVRAVMYAOSSIR +SGJJYTHXZDNADA +HJDDKYZJYBHSJW +MIJDQKBGDQKQSM +TUUIZIZBYGQMSF +QWJBLNQJNFDNJP +QWJBLNQJNFDNJP +HVAFPBRUOUYMQM +HVAFPBRUOUYMQM +HVAFPBRUOUYMQM +RIBGLFMQZAHUNM +RIBGLFMQZAHUNM +UMTLULRIWDACNW +ZOCXUHJGZXXIGQ +YJQCOFNZVFGCAF +FIIRBPHYBLFBSD +HQEBGENSMXBRMP +SIVWXOPASOMQQC +ZEXYUHSKZCBVFE +LRHJPGGHXBPBPS +WSECWTQEYGSNTA +SCIGYBYAZUFDLA +SJBIQWPGDXXURT +UQWXAEVMTJFVFA +UQWXAEVMTJFVFA +UQWXAEVMTJFVFA +UQWXAEVMTJFVFA +MGDMYIGOCQPAPQ +AQXXGIBOZQZSAT +AQXXGIBOZQZSAT +AQXXGIBOZQZSAT +AQXXGIBOZQZSAT +MBQKTLYFUYNAPZ +JYSZOVOBXGDGIQ +JYSZOVOBXGDGIQ +MDAUFUALHVJQPD +LXWHYNUADVIAPT +HSLMCYLLQMQSLX +RHGMVWUZXGSXCT +DYJIJIUSBPCLMI +AQXXGIBOZQZSAT +RKCMTKXTIVZCTQ +IFZBBVYLFVBRSP +IFZBBVYLFVBRSP +JXQFRWIHSKNLFR +JXQFRWIHSKNLFR +HEAKELJCVBVEKW +FMXKKRVABMYCJR +XOLHQUYGSUGTQA +NPWAQSYSDCQSKY +GBBLNEWSFXZKJC +GBBLNEWSFXZKJC +WRTOUBQZZGFLLV +SCIXGQOSKNXPSL +NPOKZGIWNCWKKA +LWOBLAUKUYVZAM +AOLOTXRUARITAR +AOLOTXRUARITAR +NMCNUIUHSCNFEG +NMCNUIUHSCNFEG +MEQHOADCAUKYIE +MEQHOADCAUKYIE +RQRNPRLJUWJZHZ +RQRNPRLJUWJZHZ +RVGZQEWUSPETDA +RVGZQEWUSPETDA +VYBUARHFRWVYNX +VYBUARHFRWVYNX +NQDKPEMHCGEDTR +NQDKPEMHCGEDTR +CNEAMBBQTZXVRE +CNEAMBBQTZXVRE +MUYKORZBNOPEAE +MUYKORZBNOPEAE +DUHUEQDHHJOBJV +DUHUEQDHHJOBJV +IFXOMNGVRBQEDH +IFXOMNGVRBQEDH +DYFMUBBDBHDXDV +DYFMUBBDBHDXDV +XRTOJGYRPZUDFW +XRTOJGYRPZUDFW +YFSJBBMDQKSVOR +YFSJBBMDQKSVOR +XHRVINDOXZYNMA +XHRVINDOXZYNMA +FBSKJMQYURKNSU +VFRBLIGIRLWBKM +VFRBLIGIRLWBKM +XPEVLOSUULAUFH +LWJFULOPSWJZSL +LWJFULOPSWJZSL +BOSPWDGVNSGRFD +BOSPWDGVNSGRFD +HOFKXXHAUVGETP +PVMOACIZALDGDN +PVMOACIZALDGDN +SVWYOGCKJVQALA +SVWYOGCKJVQALA +BSGPJBALTHTFJC +BSGPJBALTHTFJC +COVMVPHACFXMAX +COVMVPHACFXMAX +KQJSQWZMSAGSHN +ZBJCSWVKUJLAAQ +ZBJCSWVKUJLAAQ +QAXBLEMBJSUBCG +QAXBLEMBJSUBCG +GEZHEQNLKAOMCA +GEZHEQNLKAOMCA +GEZHEQNLKAOMCA +GEZHEQNLKAOMCA +TWPRESPPOZCYON +TWPRESPPOZCYON +GEZHEQNLKAOMCA +GEZHEQNLKAOMCA +AXTVNDHMIGPHIQ +AXTVNDHMIGPHIQ +CGSGRJNIABXQJQ +CGSGRJNIABXQJQ +JGUYJMIAKPTIAH +JGUYJMIAKPTIAH +SJUQVJAGIYBTCQ +SJUQVJAGIYBTCQ +FCRRDBSGFPBRDY +FCRRDBSGFPBRDY +FCRRDBSGFPBRDY +FCRRDBSGFPBRDY +CBLCGZHNLSSEEU +CBLCGZHNLSSEEU +HNZGKRAKJFZQAY +JWYUAQRXXHLQRX +JWYUAQRXXHLQRX +VBEWJSMISIWDQM +VBEWJSMISIWDQM +LRJFCTOUXFAGON +REKWVHVBDQXQLB +AVAGQVZSHJYDED +LWHLMCCRIWZBQO +LWHLMCCRIWZBQO +KHYSBNREYPBDKG +SQVGSASAWVDBGA +CQNMGPMOXZZIMT +CQNMGPMOXZZIMT +BUDRZZSEUJFANA +BWJOHXIBGMMXIB +BWJOHXIBGMMXIB +JJWITJNSXCXULM +JJWITJNSXCXULM +JJWITJNSXCXULM +JJWITJNSXCXULM +WWUJVTWKCIUWTB +IKWGNDOJHGXHQF +ZJMWCILJIZUHCR +VTHFJSPYJODWKX +DVSXLPKXNQNXQO +ZPRWGNIYRGILHV +SDQMLBJBRCIBHM +DNRWOARHBKGXQM +DVXZVCNEGRKLMW +TWYUDVVIPSUDIG +JXVRIDLLCIYMFQ +YGBCKUQFWKXJEP +LRBUWASGIAAHOJ +WBQDAYWQELBEPU +RBPCODNTTHTSFN +ISZJBAVZNJEEDI +RRELOQVRCVAZDA +XONIDZKOFMZZPY +AYFWFWSSZGHCBB +YBBHWUGZXXCHNH +NJWFKLAAUKWILN +WHBZZYNJIVYKBG +DRRMLDGFKZNBDX +YZJJGQISMQALNG +MZSMZYBORPEUEF +KCWYZDWFWWWFPP +KCWYZDWFWWWFPP +RHJAHLYWTDULNL +KXBNQEYVZSCSNH +DRSITEVYZGOOQG +VMSLCPKYRPDHLN +DRRRARWGCRPATB +UNCDMWKTFLUPHZ +LSDULPZJLTZEFD +JPGNVTPOQRXCDY +SZINUGQCTHLQAZ +SUOXGDJCEWTZIZ +XETHJOZXBVWLLM +XETHJOZXBVWLLM +ZEZOBFSLMMTYFF +VYCKCQBOVSSJSK +AHOIPAFUOXGGQB +KDVBIWXQJGCQHY +LXKDFRJCVQJIIM +ZGRSXMWWGUOTAO +GAOZTHIDHYLHMS +VKHAHZOOUSRJNA +PTRWWFKHWVYDOM +XJMTWNXFNQAKGS +LRFGMYZOHFCADE +LRFGMYZOHFCADE +KKNODFPXRCYCJH +KKNODFPXRCYCJH +BJDMHAYLPGRUFH +BJDMHAYLPGRUFH +PMVFYHVSZOZDAN +HEYOPWSFHOXZQH +HEYOPWSFHOXZQH +AWBBVBCVNQKGBX +AWBBVBCVNQKGBX +YTYROCNIOIJAQT +YTYROCNIOIJAQT +ATAOQRUXYTVQTQ +ATAOQRUXYTVQTQ +WMLLJSBRSSYYPT +MDWPTHONDMTCBU +YZXSLVKFBHMIDN +YNMMSSYXBYTABV +HPZNCFSLZGFDST +ATASRQYZQYFECN +LVFIUDAMNWXFMK +HDNFKWOIOAMTET +DEPOACJRWNBMHE +IOXDNARANVBWEM +COINEBBLGOMOLL +UXGRLPDGNJIDMD +SECFCXAIAMEJIM +CGZITCMVSSNQPE +AIECUUXSLHXKBY +JMWFRADNOZWWRR +VAAUVRVFOQPIGI +LGSJLBWWZAOHIV +BWYKEOSPJFLVAF +UXNWJLSRLNSHSI +GDKYFVYJOABXKN +PCOMFCPXXQONPD +PHTDAEUHHMVZMQ +YFYZOMDKMZGTIY +CRPYYHQISGFROO +HSRXNKIXELDMBE +CGYZQENMSDXRIW +KRGFXWNRLHTUQP +NXPWZDQBJBVYGK +PFRLTTBOIKJSTE +AGVWUSXOLCAMND +RKEBXTALJSALNU +FDKRLXBXYZKWRZ +IQZKGDLOGOUDKG +QXNUWOJJOFPNTB +QXNUWOJJOFPNTB +GCGYDAPWERJNJL +GCGYDAPWERJNJL +KGADRVPUSLMDQC +KGADRVPUSLMDQC +JIXBVUWPIZMQFP +JVSRVFVQPAPFCH +JVSRVFVQPAPFCH +OYVKZNMFJBWLKO +OYVKZNMFJBWLKO +GOMIKTMVKFBMCU +STKZKAJIJHJDCQ +XXKZKRXFOSRMPM +PFUWGHSSELAINQ +MRLNWXSZJIGUHQ +HFOZJSCLBUTFCX +IGEUWSSSLAVCIX +NUFGXXTYECLQGB +FMPJNBPZCVETGY +POTLBMWZZVFHKL +YKCBSSSCFQKZEX +OEDAYEZAGQXCIT +GYBRMQYCKSSXID +AOZCVYYAEZOYGW +NJNAHFYVTBZQHU +AMQJGKJHNQVSQU +ISRGBERFYCZNPL +UGKWMFGVEALSIZ +IAIWVQXQOWNYOU +NXFQHRVNIOXGAQ +UGBOUVVZXRMJNM +UGBOUVVZXRMJNM +FEVBMCJUKWWWBT +LHJPHMKIGRLKDR +RGHQRULWHKEQHE +GKMMNQCWGZRQTN +AYQSOQAXHARFPU +DHEXLLNJDVHHIZ +LSFKUCDUIQAMBP +XREKQGGCWMMSMC +MLNSIBIIWDOAGC +YDHYIMYYVRIJQZ +YGBCKUQFWKXJEP +ZDOVFDLIJJGVQM +IXBQSRWSVIBXNC +IJLXJWLRFCSMOC +CBDNJMWSYJVEMF +OADDNTRLNAZGMP +UWLMDFCSRQDCHJ +HZQBTVDHJQJQOP +FYZYVTHTMPXJHJ +PXWYOWVPPKWVSA +CQCRWLOGUOKQCD +KYJMIMWHTSJVQB +WCAKZBQMVHYHED +PLSGFSOLCKJLJQ +UNCVXXVJJXJZII +NEINCGYMLGLOMN +MCGZCRGDIAILMI +QSTFRCUXCBXJAW +BYSRPHRKESMCPO +PAVWXODKPIGBQM +CJHBVBNPNXOWBA +MQLHZIBESRENLM +BQGPJXHWGIKJKY +ZDZOTLJHXYCWBA +ZDZOTLJHXYCWBA +QJJXYPPXXYFBGM +IKBKZGMPCYNSLU +IKBKZGMPCYNSLU +HJUAKZYKCANOOZ +WIYUZYBFCWCCQJ +GKQPCPXONLDCMU +GKQPCPXONLDCMU +WDZCUPBHRAEYDL +JQXXHWHPUNPDRT +HDWIHXWEUNVBIY +HDWIHXWEUNVBIY +SGKRLCUYIXIAHR +SGKRLCUYIXIAHR +JFPVXVDWJQMJEE +WDZCUPBHRAEYDL +OPWCHZIQXUKNMP +UWRCXFLYVGTCAN +RRWXSVSMTCNULZ +BUKIYBRHWQNVOV +DKONDWKMQBULON +RRJWTPLXCYHWGJ +BAKYVUHOODEWGV +BAKYVUHOODEWGV +FAZDYVMEXQHRLI +ZXKWIJYSLSNFLY +GEOMINBWFXSCOW +ZCAXKTMXLLDQED +WNZLJUQGEOKOJG +SQVRJYDIVLDZDD +DMSRUJBXNPIECM +QAUFEYITPFCZGA +MJRBGADEELXFRE +YNEKLTQTLQODKL +NHANKPYHANHANT +OAWCVDIHMTVSBA +DHPRQBPJLMKORJ +FVTFBLAMRNBDGF +OZSFTISQEJOMNF +OPUJUXSZNVCDHY +BNZPDENCVXRJMM +RPJCNPVTJKMYEB +SHFUECUZXIUHFD +QEIGNBWTKVBBBG +OPUJUXSZNVCDHY +XCIGKBBPJQAESH +ZSJOCPIPUNPVFO +WLWAYPFRKDSFCL +WLWAYPFRKDSFCL +SHZFSEANVASGEO +WSYWNOVAOBJIST +YFPLUTJZUXLEEA +CBXGQKNSTJDJQF +AEEUCCIYTLQIKG +LVPYCCYRBXQBCX +DWCKSBOSIIXYJK +QLLLGFMAOYLOFG +GRTQHWQVNIGNKX +QSRWMSVAYUMACX +AEFNHJDBIBMLSP +FFYMBAHMSYIJOC +YXBGUENLKYUKCB +OGKLVJMNCMVUAQ +AVODUFXCUYKMAY +ZXZPFGGUUZDXND +PZFUOFXCIAKGCY +NETWVFJUARMYDT +WQLAGMMDTNEVTH +PVSWCIQNCLYJJV +RRJWTPLXCYHWGJ +REVGSMFILFTBCB +AEFNHJDBIBMLSP +FJAQNRBDVKIIKK +TYNNXAMDNHTMLY +ZXKWIJYSLSNFLY +VYXXYRCQTBQDRW +ZFPDJLFLTOCCBJ +DVWSPEXVOFZTQT +XKOGKUUHPBUVBF +LHSZFVYRERBVND +BAKYVUHOODEWGV +ZKOTUWJMGBWBEO +GBKBPIXSSQJOPJ +GBKBPIXSSQJOPJ +JUTSMXHGEKYOLZ +XDHNQDDQEHDUTM +BXGLWTGIQGFBBV +BXGLWTGIQGFBBV +VMXUWOKSQNHOCA +QKDDJDBFONZGBW +XTLROSDJDZHIIK +VUWXAQFLTSBUDB +PCUIFSZMAIXEDE +DEFAKPKFXYITPZ +SYNOVMDJYWJCON +CDMZOKMMANFJMU +SGKRLCUYIXIAHR +IOTXSIGGFRQYKW +OZVBMTJYIDMWIL +JDTZAGLGBRRCJT +JUQLTPCYUFPYKE +AKXCFAYOTIEFOH +LUZRJRNZXALNLM +GKJZEKSHCJELPL +FFTVPQUHLQBXQZ +JRDUBBHIPPPSLP +LUZRJRNZXALNLM +LUZRJRNZXALNLM +KYWCWBXGRWWINE +UJEWTUDSLQGTOA +KUBONGDXTUOOLM +MWIASLNTAGRGGA +RWTNPBWLLIMQHL +YJZYDPRMWYWYCG +SGKRLCUYIXIAHR +IWALGNIFYOBRKC +JKYJSFISYHSNOE +WZPBZJONDBGPKJ +OZVBMTJYIDMWIL +MLKXDPUZXIRXEP +AMOGMTLMADGEOQ +MVGSNCBCUWPVDA +YUGZHQHSNYIFLG +BJIPVHLRWSDKOS +LEQAKWQJCITZNK +YCWSUKQGVSGXJO +QNJKSUYWBCNWFI +MOZPSIXKYJUTKI +YDBCEBYHYKAFRX +MAFMQEKGGFWBAB +XMFCOYRWYYXZMY +QYVWBXJKZUCSNI +SSPCCAYAIDNNJX +WDTAYDBPNYFWDR +LXJSJIXZOAMHTG +BOCUKUHCLICSIY +STQGQHZAVUOBTE +LMPZHLXYBWGGNT +OWFJMIVZYSDULZ +RUZYUOTYCVRMRZ +OWFJMIVZYSDULZ +LBVZWEWTNUDWNS +MDMWHKZANMNXTF +GUOQUXNJZHGPQF +ZHVWWEYETMPAMX +ZZZRUAITSXLWBH +HVJGNAHENNXYLP +ZCGOMHNNNFPNMX +NWXMGUDVXFXRIG +BOPGDPNILDQYTO +LUEWUZLMQUOBSB +LUEWUZLMQUOBSB +LUEWUZLMQUOBSB +LUEWUZLMQUOBSB +LUEWUZLMQUOBSB +XMSXQFUHVRWGNA +XMSXQFUHVRWGNA +YDOTUXAWKBPQJW +MVGSNCBCUWPVDA +KDCCOOGTVSRCHX +KDCCOOGTVSRCHX +HVJGNAHENNXYLP +UQZIYBXSHAGNOE +HXIQYSLFEXIOAV +JFPVXVDWJQMJEE +LYUPEIXJYAJCHL +NNDHDYDFEDRMGH +YOTUXHIWBVZAJQ +RVSYWRBZSPBTQV +PMCAUYATZKXGHU +VDIFGESBHJLSFS +AGRYIZUKIKYUFX +FCHVXNVDFYXLIL +IXVNNLCMQASQBL +DQFPEYARZIQXRM +VNKBTWQZTQIWDV +VJYIFXVZLXQVHO +XGWIJUOSCAQSSV +VLCQZHSMCYCDJL +FROBCXTULYFHEJ +IQVNEKKDSLOHHK +AFZFFLVORLEPPO +AFZFFLVORLEPPO +WPEWQEMJFLWMLV +MRMBZHPJVKCOMA +MRMBZHPJVKCOMA +MRMBZHPJVKCOMA +AOJJSUZBOXZQNB +XDXDZDZNSLXDNA +AVAACINZEOAHHE +JVEONPNCICCMNY +ACRHBAYQBXXRTO +KDLRVYVGXIQJDK +OJMMVQQUTAEWLP +XIYOPDCBBDCGOE +STQGQHZAVUOBTE +WBPYTXDJUQJLPQ +JTWOMNBEOCYFNV +JTWOMNBEOCYFNV +SGKRLCUYIXIAHR +HVKUYPXKTAMIFI +LYRBFJCNZKRZPT +VCDMHIARBYKHSB +PEVGVQUYBNMZTF +UFEYZHWROVTPNL +RNIADBXQDMCFEN +XIYOPDCBBDCGOE +QLFZZSKTJWDQOS +QLFZZSKTJWDQOS +WBPYTXDJUQJLPQ +DHPRQBPJLMKORJ +CEAZRRDELHUEMR +CEAZRRDELHUEMR +CEAZRRDELHUEMR diff --git a/massspecgym/data/__init__.py b/massspecgym/data/__init__.py index 7d95b56..506d1d9 100644 --- a/massspecgym/data/__init__.py +++ b/massspecgym/data/__init__.py @@ -4,5 +4,12 @@ __all__ = [ "MassSpecDataset", "RetrievalDataset", - "MassSpecDataModule" + "MassSpecDataModule", ] + + +def __getattr__(name): + if name == "FP2MolDataset": + from .fp2mol_dataset import FP2MolDataset + return FP2MolDataset + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/massspecgym/data/download.py b/massspecgym/data/download.py new file mode 100644 index 0000000..749938a --- /dev/null +++ b/massspecgym/data/download.py @@ -0,0 +1,82 @@ +""" +Download MassSpecGym datasets from HuggingFace to local data/ directory. + +Downloads the core dataset files needed for training, evaluation, and +retrieval tasks. +""" + +import logging +from pathlib import Path +from typing import Optional + +from massspecgym.utils import hugging_face_download + +logger = logging.getLogger(__name__) + +CORE_FILES = [ + "MassSpecGym.tsv", +] + +RETRIEVAL_FILES = [ + "molecules/MassSpecGym_retrieval_candidates_mass.json", + "molecules/MassSpecGym_retrieval_candidates_formula.json", +] + +MOLECULE_FILES = [ + "molecules/MassSpecGym_retrieval_molecules_1M.tsv", +] + + +def download_massspecgym_data( + include_retrieval: bool = True, + include_molecules: bool = False, + verbose: bool = True, +) -> dict: + """Download MassSpecGym files from HuggingFace. + + Files are cached by huggingface_hub to ~/.cache/huggingface/hub/ and + the function returns a dict mapping file names to local paths. + + Args: + include_retrieval: Download retrieval candidate files. + include_molecules: Download molecule library files. + verbose: Print progress. + + Returns: + Dict mapping HF file names to local file paths. + """ + files_to_download = list(CORE_FILES) + if include_retrieval: + files_to_download.extend(RETRIEVAL_FILES) + if include_molecules: + files_to_download.extend(MOLECULE_FILES) + + paths = {} + for f in files_to_download: + if verbose: + logger.info(f"Downloading {f}...") + try: + local_path = hugging_face_download(f) + paths[f] = local_path + if verbose: + logger.info(f" -> {local_path}") + except Exception as e: + logger.warning(f" Failed to download {f}: {e}") + + return paths + + +def get_massspecgym_tsv_path() -> str: + """Get the local path to MassSpecGym.tsv, downloading if needed.""" + return hugging_face_download("MassSpecGym.tsv") + + +def get_retrieval_candidates_path(bonus: bool = False) -> str: + """Get path to retrieval candidates JSON, downloading if needed. + + Args: + bonus: If True, use formula-based candidates (bonus task). + """ + if bonus: + return hugging_face_download("molecules/MassSpecGym_retrieval_candidates_formula.json") + return hugging_face_download("molecules/MassSpecGym_retrieval_candidates_mass.json") diff --git a/massspecgym/data/fp2mol_dataset.py b/massspecgym/data/fp2mol_dataset.py new file mode 100644 index 0000000..105c61f --- /dev/null +++ b/massspecgym/data/fp2mol_dataset.py @@ -0,0 +1,220 @@ +""" +Dataset for FP-to-molecule decoder pretraining. + +Loads molecule libraries from Parquet files (standard format) or programmatic +SMILES lists, produces (fingerprint, formula, molecule_representation) training +triples. Performs mandatory InChIKey sanity check against the MassSpecGym +exclusion list to prevent data leakage. + +Standard Parquet schema: + smiles (string, required) + inchikey_14 (string, required) + formula (string, optional - auto-computed) + selfies (string, optional) + safe (string, optional) + +Use scripts/convert_to_parquet.py to convert raw SMILES/CSV/TSV to Parquet. +""" + +import logging +from pathlib import Path +from typing import List, Optional, Set, Union + +import numpy as np +import pandas as pd +import torch +from rdkit import Chem +from rdkit.Chem import AllChem +from rdkit.Chem.rdMolDescriptors import CalcMolFormula +from torch.utils.data import Dataset + +from massspecgym.data.sanity_check import ( + DataLeakageError, + check_inchikey_overlap_strict, +) + +logger = logging.getLogger(__name__) + + +class FP2MolDataset(Dataset): + """Dataset for fingerprint-to-molecule decoder pretraining. + + Accepts Parquet files as the standard input format, or programmatic + SMILES lists. Performs mandatory InChIKey sanity check at init. + + Args: + smiles_source: Path to a .parquet file, or a list of SMILES strings. + mol_repr: Target molecular representation ('smiles', 'selfies', 'safe'). + fingerprint_type: Fingerprint type ('morgan'). + fp_bits: Number of fingerprint bits. + fp_radius: Morgan fingerprint radius. + exclude_inchikeys: Path to exclusion list CSV. Defaults to + data/exclude_inchikeys.csv. Set to False to disable (NOT recommended). + max_molecules: Maximum number of molecules to load. + cache_fingerprints: If True, pre-compute and cache all fingerprints. + """ + + def __init__( + self, + smiles_source: Union[str, Path, List[str]], + mol_repr: str = "smiles", + fingerprint_type: str = "morgan", + fp_bits: int = 4096, + fp_radius: int = 2, + exclude_inchikeys: Union[str, Path, bool, None] = None, + max_molecules: Optional[int] = None, + cache_fingerprints: bool = True, + ): + super().__init__() + self.mol_repr = mol_repr + self.fingerprint_type = fingerprint_type + self.fp_bits = fp_bits + self.fp_radius = fp_radius + self.cache_fingerprints = cache_fingerprints + + from massspecgym.models.de_novo.fp2mol.formula_utils import FormulaEncoder + self.formula_encoder = FormulaEncoder(normalize="none") + + df = self._load_source(smiles_source, max_molecules) + self._ensure_columns(df) + + if exclude_inchikeys is not False: + exclude_path = str(exclude_inchikeys) if exclude_inchikeys else None + check_inchikey_overlap_strict(df["inchikey_14"].tolist(), exclude_path) + + self.smiles = df["smiles"].tolist() + self.formulas = df["formula"].tolist() + self._mol_repr_col = None + if mol_repr in df.columns and mol_repr != "smiles": + self._mol_repr_col = df[mol_repr].tolist() + + logger.info(f"FP2MolDataset: {len(self.smiles)} molecules loaded") + + self._fp_cache: dict = {} + if self.cache_fingerprints: + self._precompute_fingerprints() + + @staticmethod + def _load_source(source: Union[str, Path, List[str]], max_molecules) -> pd.DataFrame: + if isinstance(source, (str, Path)): + path = Path(source) + if path.suffix == ".parquet": + df = pd.read_parquet(path) + else: + raise ValueError( + f"FP2MolDataset only accepts .parquet files. Got: {path.suffix}\n" + f"Use scripts/convert_to_parquet.py to convert your data first." + ) + elif isinstance(source, list): + df = pd.DataFrame({"smiles": source}) + else: + raise TypeError(f"Unsupported source type: {type(source)}") + + if max_molecules and len(df) > max_molecules: + df = df.head(max_molecules) + return df.reset_index(drop=True) + + @staticmethod + def _ensure_columns(df: pd.DataFrame): + """Ensure required columns exist, computing missing ones.""" + if "smiles" not in df.columns: + raise ValueError("Parquet must have a 'smiles' column") + + if "inchikey_14" not in df.columns: + logger.info("Computing inchikey_14 from SMILES...") + df["inchikey_14"] = df["smiles"].apply(FP2MolDataset._smiles_to_inchikey14) + + if "formula" not in df.columns: + logger.info("Computing formula from SMILES...") + df["formula"] = df["smiles"].apply(FP2MolDataset._smiles_to_formula) + + valid = df["smiles"].apply(lambda s: Chem.MolFromSmiles(s) is not None) + n_invalid = (~valid).sum() + if n_invalid > 0: + logger.warning(f"Dropping {n_invalid} invalid SMILES") + df.drop(df[~valid].index, inplace=True) + df.reset_index(drop=True, inplace=True) + + @staticmethod + def _smiles_to_inchikey14(smi: str) -> str: + mol = Chem.MolFromSmiles(smi) + if mol is None: + return "" + try: + ik = Chem.MolToInchiKey(mol) + return ik.split("-")[0] if ik else "" + except Exception: + return "" + + @staticmethod + def _smiles_to_formula(smi: str) -> str: + mol = Chem.MolFromSmiles(smi) + if mol is None: + return "" + try: + f = CalcMolFormula(mol) + return f.split("+")[0].split("-")[0] + except Exception: + return "" + + def _precompute_fingerprints(self): + for idx in range(len(self.smiles)): + self._fp_cache[idx] = self._compute_fingerprint(self.smiles[idx]) + + def _compute_fingerprint(self, smiles: str) -> torch.Tensor: + mol = Chem.MolFromSmiles(smiles) + if mol is None: + return torch.zeros(self.fp_bits, dtype=torch.float32) + if self.fingerprint_type == "morgan": + fp = AllChem.GetMorganFingerprintAsBitVect(mol, self.fp_radius, nBits=self.fp_bits) + arr = np.zeros(self.fp_bits, dtype=np.float32) + AllChem.DataStructs.ConvertToNumpyArray(fp, arr) + return torch.from_numpy(arr) + raise ValueError(f"Unknown fingerprint type: {self.fingerprint_type}") + + def _convert_mol_repr(self, smiles: str, idx: int) -> str: + if self._mol_repr_col is not None: + return self._mol_repr_col[idx] + if self.mol_repr == "smiles": + return smiles + elif self.mol_repr == "selfies": + try: + import selfies as sf + return sf.encoder(smiles) + except Exception: + return smiles + elif self.mol_repr == "safe": + try: + from safe import encode as safe_encode + return safe_encode(smiles) + except Exception: + return smiles + return smiles + + def __len__(self) -> int: + return len(self.smiles) + + def __getitem__(self, idx: int) -> dict: + smiles = self.smiles[idx] + formula = self.formulas[idx] + fingerprint = self._fp_cache[idx] if self.cache_fingerprints else self._compute_fingerprint(smiles) + formula_vec = self.formula_encoder.encode(formula) + target_repr = self._convert_mol_repr(smiles, idx) + + return { + "fingerprint": fingerprint, + "formula": formula, + "formula_vec": formula_vec, + "mol": smiles, + "mol_repr": target_repr, + } + + @staticmethod + def collate_fn(batch: list) -> dict: + return { + "fingerprint": torch.stack([b["fingerprint"] for b in batch]), + "formula_vec": torch.stack([b["formula_vec"] for b in batch]), + "formula": [b["formula"] for b in batch], + "mol": [b["mol"] for b in batch], + "mol_repr": [b["mol_repr"] for b in batch], + } diff --git a/massspecgym/data/mist_data_mixin.py b/massspecgym/data/mist_data_mixin.py new file mode 100644 index 0000000..bf1ba7a --- /dev/null +++ b/massspecgym/data/mist_data_mixin.py @@ -0,0 +1,103 @@ +""" +Mixin for MIST-based models that need subformulae-annotated data. + +Provides auto-detection of MIST-format data and lazy conversion from +the standard MassSpecGym TSV format. Used by the MIST encoder, all +FP2Mol decoders, and the MIST-CF oracle. +""" + +import logging +from pathlib import Path +from typing import Optional + +logger = logging.getLogger(__name__) + +DEFAULT_MIST_DATA_DIR = Path("data/mist_format") + + +class MISTDataMixin: + """Mixin providing auto-conversion of MassSpecGym data to MIST format. + + Any model that requires subformulae-annotated spectra can inherit from + this mixin and call ``ensure_mist_data()`` before using the data. + """ + + def ensure_mist_data( + self, + data_dir: Optional[str] = None, + tsv_path: Optional[str] = None, + run_subformulae: bool = True, + num_workers: int = 16, + ) -> Path: + """Ensure MIST-format data exists, converting from TSV if needed. + + Checks for: + 1. spec_files/ directory with .ms files + 2. labels.tsv + 3. subformulae/default_subformulae/ with JSON files + + If any are missing, runs the full conversion pipeline. + + Args: + data_dir: Path to MIST-format data directory. + Defaults to data/mist_format/. + tsv_path: Path to MassSpecGym TSV (auto-downloads if None). + run_subformulae: Whether to generate subformulae JSONs. + num_workers: Workers for parallel processing. + + Returns: + Path to the MIST-format data directory. + """ + if data_dir is None: + data_dir = DEFAULT_MIST_DATA_DIR + data_dir = Path(data_dir) + + spec_dir = data_dir / "spec_files" + labels_file = data_dir / "labels.tsv" + subform_dir = data_dir / "subformulae" / "default_subformulae" + + needs_conversion = ( + not spec_dir.exists() + or not labels_file.exists() + or not any(spec_dir.glob("*.ms")) + ) + needs_subformulae = run_subformulae and ( + not subform_dir.exists() + or not any(subform_dir.glob("*.json")) + ) + + if needs_conversion: + logger.info( + f"MIST-format data not found at {data_dir}. " + f"Converting from MassSpecGym TSV..." + ) + from massspecgym.data.mist_format import convert_massspecgym_to_mist + convert_massspecgym_to_mist( + tsv_path=tsv_path, + output_dir=str(data_dir), + run_subformulae=run_subformulae, + num_workers=num_workers, + ) + elif needs_subformulae: + logger.info( + f"Subformulae not found at {subform_dir}. Running assignment..." + ) + import pandas as pd + from massspecgym.data.subformulae import assign_subformulae_dataset + + labels_df = pd.read_csv(labels_file, sep="\t") + assign_subformulae_dataset( + spec_source=spec_dir, + labels_df=labels_df, + output_dir=subform_dir, + num_workers=num_workers, + ) + else: + logger.info(f"MIST-format data found at {data_dir}") + + return data_dir + + def get_subformulae_dir(self, data_dir: Optional[str] = None) -> Path: + """Get path to subformulae directory, ensuring it exists.""" + data_dir = self.ensure_mist_data(data_dir) + return data_dir / "subformulae" / "default_subformulae" diff --git a/massspecgym/data/mist_format.py b/massspecgym/data/mist_format.py new file mode 100644 index 0000000..e83a8be --- /dev/null +++ b/massspecgym/data/mist_format.py @@ -0,0 +1,184 @@ +""" +Convert MassSpecGym data to MIST-compatible format. + +Produces the exact directory layout expected by the MIST encoder and all +MIST-based models: + + {output_dir}/ + labels.tsv # dataset, spec, ionization, formula, smiles, inchikey, instrument + split.tsv # name, split + spec_files/ # {identifier}.ms per spectrum + subformulae/ + default_subformulae/ + {identifier}.json + +The output matches /home/liuhx25/orcd/pool/data/msg/ identically. +""" + +import logging +from pathlib import Path +from typing import Optional + +import numpy as np +import pandas as pd +from tqdm import tqdm + +import massspecgym.utils as utils + +logger = logging.getLogger(__name__) + + +def _row_to_ms_string(identifier, formula, parent_mass, adduct, inchikey, + smiles, instrument, mzs, intensities, inchi=None): + """Convert a single MassSpecGym row to a SIRIUS-style .ms file string. + + Produces the exact format matching /home/liuhx25/orcd/pool/data/msg/spec_files/*.ms + """ + lines = [] + lines.append(f">compound {identifier}") + lines.append(f">formula {formula}") + lines.append(f">parentmass {parent_mass}") + + ion_str = adduct + if adduct == "[M+H]+": + ion_str = "[M+H]+" + elif adduct == "[M+Na]+": + ion_str = "[M+Na]+" + lines.append(f">ionization {ion_str}") + + lines.append(f">InChi {inchi if inchi else 'None'}") + lines.append(f">InChiKey {inchikey}") + lines.append(f"#smiles {smiles}") + lines.append(f"#instrumentation {instrument}") + lines.append(f"#_FILE {identifier}") + + if inchi: + lines.append(f"#InChi {inchi}") + + lines.append("") + lines.append(">ms2peaks") + + if isinstance(mzs, str): + mz_arr = [float(m) for m in mzs.split(",")] + int_arr = [float(i) for i in intensities.split(",")] + else: + mz_arr = list(mzs) + int_arr = list(intensities) + + for mz, inten in zip(mz_arr, int_arr): + lines.append(f"{mz} {inten}") + + return "\n".join(lines) + + +def _make_labels_tsv(df: pd.DataFrame) -> pd.DataFrame: + """Create MIST-format labels.tsv from MassSpecGym DataFrame.""" + labels = pd.DataFrame() + labels["dataset"] = "MassSpecGym" + labels["spec"] = df["identifier"] + labels["ionization"] = df["adduct"] + labels["formula"] = df["formula"] + labels["smiles"] = df["smiles"] + labels["inchikey"] = df["inchikey"] if "inchikey" in df.columns else "" + labels["instrument"] = df["instrument_type"] if "instrument_type" in df.columns else "unknown" + return labels + + +def _make_split_tsv(df: pd.DataFrame) -> pd.DataFrame: + """Create MIST-format split.tsv from MassSpecGym DataFrame.""" + split = pd.DataFrame() + split["name"] = df["identifier"] + split["split"] = df["fold"] + return split + + +def convert_massspecgym_to_mist( + tsv_path: Optional[str] = None, + output_dir: str = "data/mist_format", + run_subformulae: bool = True, + mass_diff_thresh: float = 20.0, + max_peaks: int = 50, + num_workers: int = 16, +) -> Path: + """Convert MassSpecGym dataset to MIST-compatible directory layout. + + Args: + tsv_path: Path to MassSpecGym.tsv. If None, downloads from HuggingFace. + output_dir: Target directory for the MIST-format output. + run_subformulae: Whether to also run subformulae assignment. + mass_diff_thresh: PPM threshold for subformulae assignment. + max_peaks: Maximum number of peaks per spectrum. + num_workers: Workers for parallel subformulae assignment. + + Returns: + Path to the output directory. + """ + output_dir = Path(output_dir) + spec_dir = output_dir / "spec_files" + spec_dir.mkdir(parents=True, exist_ok=True) + + if tsv_path is None: + logger.info("Downloading MassSpecGym.tsv from HuggingFace...") + tsv_path = utils.hugging_face_download("MassSpecGym.tsv") + + logger.info(f"Loading {tsv_path}...") + df = pd.read_csv(tsv_path, sep="\t") + + logger.info(f"Writing {len(df)} .ms files to {spec_dir}...") + for _, row in tqdm(df.iterrows(), total=len(df), desc="Writing .ms files"): + identifier = row["identifier"] + + inchikey = row.get("inchikey", "") + if pd.isna(inchikey): + inchikey = "" + + inchi = None + if "inchi" in row and not pd.isna(row.get("inchi", None)): + inchi = row["inchi"] + + instrument = row.get("instrument_type", "unknown") + if pd.isna(instrument): + instrument = "unknown" + + parent_mass = row.get("parent_mass", row.get("precursor_mz", 0)) + + ms_str = _row_to_ms_string( + identifier=identifier, + formula=row["formula"], + parent_mass=parent_mass, + adduct=row["adduct"], + inchikey=inchikey, + smiles=row["smiles"], + instrument=instrument, + mzs=row["mzs"], + intensities=row["intensities"], + inchi=inchi, + ) + + with open(spec_dir / f"{identifier}.ms", "w") as f: + f.write(ms_str) + + labels_df = _make_labels_tsv(df) + labels_df.to_csv(output_dir / "labels.tsv", sep="\t", index=False) + + split_df = _make_split_tsv(df) + split_df.to_csv(output_dir / "split.tsv", sep="\t", index=False) + + logger.info(f"Wrote labels.tsv ({len(labels_df)} rows) and split.tsv to {output_dir}") + + if run_subformulae: + from massspecgym.data.subformulae import assign_subformulae_dataset + + subform_dir = output_dir / "subformulae" / "default_subformulae" + logger.info(f"Running subformulae assignment to {subform_dir}...") + assign_subformulae_dataset( + spec_source=spec_dir, + labels_df=labels_df, + output_dir=subform_dir, + mass_diff_thresh=mass_diff_thresh, + max_peaks=max_peaks, + num_workers=num_workers, + ) + + logger.info(f"MIST format conversion complete: {output_dir}") + return output_dir diff --git a/massspecgym/data/sanity_check.py b/massspecgym/data/sanity_check.py new file mode 100644 index 0000000..f2d4ed4 --- /dev/null +++ b/massspecgym/data/sanity_check.py @@ -0,0 +1,157 @@ +""" +InChIKey-based data safety sanity check for MassSpecGym. + +Ensures that unpaired molecule datasets used for decoder pretraining do not +contain any molecules whose 2D InChIKey (first 14 characters) overlaps with +the MassSpecGym test/validation exclusion list. + +Usage as standalone CLI: + python -m massspecgym.data.sanity_check --input molecules.parquet + +Usage as library: + from massspecgym.data.sanity_check import check_inchikey_overlap + result = check_inchikey_overlap(my_inchikeys) + assert result.is_clean, f"Found {result.overlap_count} overlapping molecules!" +""" + +import logging +import sys +from dataclasses import dataclass, field +from pathlib import Path +from typing import Iterable, Optional, Set + +logger = logging.getLogger(__name__) + +DEFAULT_EXCLUDE_PATH = Path(__file__).parent.parent.parent / "data" / "exclude_inchikeys.csv" + + +class DataLeakageError(Exception): + """Raised when training data overlaps with excluded InChIKeys.""" + pass + + +@dataclass +class SanityCheckResult: + """Result of an InChIKey overlap sanity check.""" + total_molecules: int + overlap_count: int + overlap_inchikeys: Set[str] = field(default_factory=set) + + @property + def is_clean(self) -> bool: + return self.overlap_count == 0 + + +def load_exclusion_set( + exclude_path: Optional[str] = None, +) -> Set[str]: + """Load the set of excluded 2D InChIKeys from CSV. + + Args: + exclude_path: Path to CSV file with column 'inchi' containing 14-char InChIKeys. + If None, uses the default MassSpecGym exclusion list. + + Returns: + Set of 14-character 2D InChIKeys. + """ + if exclude_path is None: + exclude_path = DEFAULT_EXCLUDE_PATH + exclude_path = Path(exclude_path) + + if not exclude_path.exists(): + logger.warning(f"Exclusion list not found at {exclude_path}") + return set() + + keys = set() + with open(exclude_path, "r") as f: + for i, line in enumerate(f): + key = line.strip() + if i == 0 and key.lower() in ("inchi", "inchikey", "inchikey_14"): + continue + if key and len(key) >= 14: + keys.add(key[:14]) + elif key: + keys.add(key) + return keys + + +def check_inchikey_overlap( + molecule_inchikeys: Iterable[str], + exclude_path: Optional[str] = None, +) -> SanityCheckResult: + """Check whether any molecule InChIKeys overlap with the exclusion list. + + Args: + molecule_inchikeys: Iterable of InChIKey strings (full or 14-char). + exclude_path: Path to exclusion CSV. Defaults to data/exclude_inchikeys.csv. + + Returns: + SanityCheckResult with overlap details. + """ + exclude_set = load_exclusion_set(exclude_path) + total = 0 + overlap = set() + + for key in molecule_inchikeys: + total += 1 + if not key: + continue + key_14 = key[:14] if len(key) > 14 else key + if key_14 in exclude_set: + overlap.add(key_14) + + return SanityCheckResult( + total_molecules=total, + overlap_count=len(overlap), + overlap_inchikeys=overlap, + ) + + +def check_inchikey_overlap_strict( + molecule_inchikeys: Iterable[str], + exclude_path: Optional[str] = None, +) -> SanityCheckResult: + """Like check_inchikey_overlap, but raises DataLeakageError on overlap.""" + result = check_inchikey_overlap(molecule_inchikeys, exclude_path) + if not result.is_clean: + raise DataLeakageError( + f"Data leakage detected: {result.overlap_count} molecules overlap with " + f"MassSpecGym exclusion list. First few: {list(result.overlap_inchikeys)[:5]}" + ) + return result + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser(description="Check InChIKey overlap with MassSpecGym exclusion list") + parser.add_argument("--input", required=True, help="Path to Parquet or CSV file with molecules") + parser.add_argument("--exclude", default=None, help="Path to exclusion CSV (default: data/exclude_inchikeys.csv)") + parser.add_argument("--inchikey-col", default="inchikey_14", help="Column name for InChIKey") + args = parser.parse_args() + + import pandas as pd + input_path = Path(args.input) + if input_path.suffix == ".parquet": + df = pd.read_parquet(input_path) + else: + df = pd.read_csv(input_path) + + col = args.inchikey_col + if col not in df.columns: + for alt in ["inchikey", "inchi", "InChIKey", "INCHIKEY"]: + if alt in df.columns: + col = alt + break + + if col not in df.columns: + print(f"ERROR: No InChIKey column found. Available: {list(df.columns)}") + sys.exit(1) + + result = check_inchikey_overlap(df[col].dropna().tolist(), args.exclude) + if result.is_clean: + print(f"CLEAN: {result.total_molecules} molecules checked, no overlap found.") + else: + print(f"WARNING: {result.overlap_count} overlapping InChIKeys found!") + print(f"First 10: {list(result.overlap_inchikeys)[:10]}") + sys.exit(1) diff --git a/massspecgym/data/subformulae.py b/massspecgym/data/subformulae.py new file mode 100644 index 0000000..a0db998 --- /dev/null +++ b/massspecgym/data/subformulae.py @@ -0,0 +1,388 @@ +""" +Subformulae assignment for mass spectra. + +Assigns chemical subformulae to MS/MS peaks by matching observed m/z values +to theoretical monoisotopic masses of all possible subfragments of the +precursor formula. This is required by the MIST encoder and all MIST-based +models. + +Ported from external/mist/src/mist/utils/spectra_utils.py and +external/mist/src/mist/subformulae/assign_subformulae.py to be +self-contained within MassSpecGym. +""" + +import json +import logging +from functools import partial +from itertools import groupby +from pathlib import Path +from typing import Dict, List, Optional, Tuple + +import numpy as np +import pandas as pd +from tqdm import tqdm + +from massspecgym.models.encoders.mist.chem_constants import ( + ION_LST, + clipped_ppm, + get_all_subsets, + ion_to_mass, + vec_to_formula, +) + +logger = logging.getLogger(__name__) + + +# --------------------------------------------------------------------------- +# Spectrum parsing (from external/mist/src/mist/utils/parse_utils.py) +# --------------------------------------------------------------------------- + +def parse_spectra_ms(spectra_file: str) -> Tuple[dict, List[Tuple[str, np.ndarray]]]: + """Parse a SIRIUS-style .ms file into metadata and peak arrays.""" + lines = [i.strip() for i in open(spectra_file, "r").readlines()] + + group_num = 0 + metadata = {} + spectras = [] + my_iterator = groupby( + lines, lambda line: line.startswith(">") or line.startswith("#") + ) + + for index, (start_line, lines) in enumerate(my_iterator): + group_lines = list(lines) + subject_lines = list(next(my_iterator)[1]) + if group_num > 0: + spectra_header = group_lines[0].split(">")[1] + peak_data = [ + [float(x) for x in peak.split()[:2]] + for peak in subject_lines + if peak.strip() + ] + if len(peak_data): + peak_data = np.vstack(peak_data) + spectras.append((spectra_header, peak_data)) + else: + entries = {} + for i in group_lines: + if " " not in i: + continue + elif i.startswith("#INSTRUMENT TYPE"): + key = "#INSTRUMENT TYPE" + val = i.split(key)[1].strip() + entries[key[1:]] = val + else: + start, end = i.split(" ", 1) + start = start[1:] + while start in entries: + start = f"{start}'" + entries[start] = end + metadata.update(entries) + group_num += 1 + + metadata["_FILE_PATH"] = spectra_file + metadata["_FILE"] = Path(spectra_file).stem + return metadata, spectras + + +def parse_spectra_mgf( + mgf_file: str, max_num: Optional[int] = None +) -> List[Tuple[dict, List[Tuple[str, np.ndarray]]]]: + """Parse an MGF file into list of (metadata, peak_arrays) tuples.""" + key = lambda x: x.strip() == "BEGIN IONS" + parsed_spectra = [] + with open(mgf_file, "r") as fp: + for (is_header, group) in groupby(fp, key): + if is_header: + continue + meta = {} + cur_spectra = [] + for line in group: + line = line.strip() + if not line or line == "END IONS" or line == "BEGIN IONS": + continue + elif "=" in line: + k, v = [i.strip() for i in line.split("=", 1)] + meta[k] = v + else: + parts = line.split() + if len(parts) >= 2: + cur_spectra.append((float(parts[0]), float(parts[1]))) + if cur_spectra: + cur_spectra = np.vstack(cur_spectra) + parsed_spectra.append((meta, [("spec", cur_spectra)])) + if max_num is not None and len(parsed_spectra) > max_num: + break + return parsed_spectra + + +# --------------------------------------------------------------------------- +# Spectrum processing (from external/mist/src/mist/utils/spectra_utils.py) +# --------------------------------------------------------------------------- + +def process_spec_file(meta, tuples, precision=4, max_inten=0.001, max_peaks=60): + """Process raw spectrum tuples: merge, normalize, sqrt, filter. + + Args: + meta: Spectrum metadata dict (needs 'parentmass' or 'PEPMASS'). + tuples: List of (header, peak_array) tuples. + precision: Decimal precision for merging. + max_inten: Minimum intensity threshold. + max_peaks: Maximum number of peaks to retain. + + Returns: + np.ndarray of shape (N, 2) with [mz, intensity] or None. + """ + if "parentmass" in meta: + parentmass = meta.get("parentmass", None) + elif "PARENTMASS" in meta: + parentmass = meta.get("PARENTMASS", None) + elif "PEPMASS" in meta: + parentmass = meta.get("PEPMASS", None) + else: + parentmass = 1000000 + + parentmass = float(parentmass) + + fused_tuples = [x for _, x in tuples if x.size > 0] + if len(fused_tuples) == 0: + return None + + mz_to_inten_pair = {} + new_tuples = [] + for i in fused_tuples: + for tup in i: + mz, inten = tup + mz_ind = np.round(mz, precision) + cur_pair = mz_to_inten_pair.get(mz_ind) + if cur_pair is None: + mz_to_inten_pair[mz_ind] = tup + new_tuples.append(tup) + elif inten > cur_pair[1]: + cur_pair[1] = inten + + merged_spec = np.vstack(new_tuples) + merged_spec = merged_spec[merged_spec[:, 0] <= (parentmass + 1)] + if merged_spec.shape[0] == 0: + return None + merged_spec[:, 1] = merged_spec[:, 1] / merged_spec[:, 1].max() + merged_spec[:, 1] = np.sqrt(merged_spec[:, 1]) + + merged_spec = _max_inten_spec( + merged_spec, max_num_inten=max_peaks, inten_thresh=max_inten + ) + return merged_spec + + +def _max_inten_spec(spec, max_num_inten=60, inten_thresh=0): + """Keep top-k peaks by intensity above threshold.""" + spec_masses, spec_intens = spec[:, 0], spec[:, 1] + new_sort_order = np.argsort(spec_intens)[::-1] + if max_num_inten is not None: + new_sort_order = new_sort_order[:max_num_inten] + spec_masses = spec_masses[new_sort_order] + spec_intens = spec_intens[new_sort_order] + spec_mask = spec_intens > inten_thresh + spec_masses = spec_masses[spec_mask] + spec_intens = spec_intens[spec_mask] + return np.vstack([spec_masses, spec_intens]).transpose(1, 0) + + +# --------------------------------------------------------------------------- +# Core subformulae assignment (from spectra_utils.assign_subforms) +# --------------------------------------------------------------------------- + +def assign_subformulae_single( + formula: str, + spectrum: np.ndarray, + ion_type: str, + mass_diff_thresh: float = 20.0, +) -> dict: + """Assign subformulae to a single spectrum. + + Matches the reference MIST implementation exactly: + 1. Enumerate all subformulae of the precursor formula. + 2. Compute monoisotopic masses (with adduct correction). + 3. Match each peak to the nearest subformula by ppm. + 4. Deduplicate by formula, merging intensities. + + Args: + formula: Precursor molecular formula string (e.g., "C16H17NO4"). + spectrum: Array of shape (N, 2) with [mz, intensity]. + ion_type: Adduct string (e.g., "[M+H]+"). + mass_diff_thresh: Maximum ppm tolerance for matching. + + Returns: + Dict with keys: cand_form, cand_ion, output_tbl (or None). + """ + output_dict = {"cand_form": formula, "cand_ion": ion_type, "output_tbl": None} + + if spectrum is None or ion_type not in ION_LST: + return output_dict + + cross_prod, masses = get_all_subsets(formula) + spec_masses, spec_intens = spectrum[:, 0], spectrum[:, 1] + + ion_masses = ion_to_mass[ion_type] + masses_with_ion = masses + ion_masses + ion_types = np.array([ion_type] * len(masses_with_ion)) + + mass_diffs = np.abs(spec_masses[:, None] - masses_with_ion[None, :]) + formula_inds = mass_diffs.argmin(-1) + min_mass_diff = mass_diffs[np.arange(len(mass_diffs)), formula_inds] + rel_mass_diff = clipped_ppm(min_mass_diff, spec_masses) + + valid_mask = rel_mass_diff < mass_diff_thresh + spec_masses = spec_masses[valid_mask] + spec_intens = spec_intens[valid_mask] + min_mass_diff = min_mass_diff[valid_mask] + rel_mass_diff = rel_mass_diff[valid_mask] + formula_inds = formula_inds[valid_mask] + + if spec_masses.size == 0: + output_dict["output_tbl"] = None + return output_dict + + formulas = np.array([vec_to_formula(j) for j in cross_prod[formula_inds]]) + formula_masses = masses_with_ion[formula_inds] + ion_types = ion_types[formula_inds] + + formula_idx_dict = {} + uniq_mask = [] + for idx, f in enumerate(formulas): + uniq_mask.append(f not in formula_idx_dict) + gather_ind = formula_idx_dict.get(f, None) + if gather_ind is None: + formula_idx_dict[f] = idx + continue + spec_intens[gather_ind] += spec_intens[idx] + + uniq_mask = np.array(uniq_mask, dtype=bool) + spec_masses = spec_masses[uniq_mask] + spec_intens = spec_intens[uniq_mask] + min_mass_diff = min_mass_diff[uniq_mask] + rel_mass_diff = rel_mass_diff[uniq_mask] + formula_masses = formula_masses[uniq_mask] + formulas = formulas[uniq_mask] + ion_types = ion_types[uniq_mask] + + if spec_intens.size == 0: + output_tbl = None + else: + output_tbl = { + "mz": list(spec_masses), + "ms2_inten": list(spec_intens), + "mono_mass": list(formula_masses), + "abs_mass_diff": list(min_mass_diff), + "mass_diff": list(rel_mass_diff), + "formula": list(formulas), + "ions": list(ion_types), + } + output_dict["output_tbl"] = output_tbl + return output_dict + + +def get_output_dict( + spec_name: str, + spec: Optional[np.ndarray], + form: str, + mass_diff_type: str, + mass_diff_thresh: float, + ion_type: str, +) -> dict: + """Wrapper matching the reference MIST get_output_dict exactly.""" + assert mass_diff_type == "ppm" + output_dict = {"cand_form": form, "cand_ion": ion_type, "output_tbl": None} + if spec is not None and ion_type in ION_LST: + output_dict = assign_subformulae_single( + form, spec, ion_type, mass_diff_thresh=mass_diff_thresh + ) + return output_dict + + +# --------------------------------------------------------------------------- +# Batch assignment for a full dataset +# --------------------------------------------------------------------------- + +def _process_single_ms(spec_name: str, spec_files_dir: str, + max_inten: float = 0.001, max_peaks: int = 50): + """Parse and process a single .ms file.""" + spec_file = Path(spec_files_dir) / f"{spec_name}.ms" + meta, tuples = parse_spectra_ms(str(spec_file)) + spec = process_spec_file(meta, tuples, max_inten=max_inten, max_peaks=max_peaks) + return spec_name, spec + + +def assign_subformulae_dataset( + spec_source, + labels_df: pd.DataFrame, + output_dir, + mass_diff_thresh: float = 20.0, + inten_thresh: float = 0.001, + max_peaks: int = 50, + feature_id: str = "ID", + num_workers: int = 16, +) -> Path: + """Assign subformulae for an entire dataset, writing one JSON per spectrum. + + Args: + spec_source: Path to .ms directory or .mgf file. + labels_df: DataFrame with columns: spec, formula, ionization. + output_dir: Directory to write JSON files. + mass_diff_thresh: PPM threshold for peak matching. + inten_thresh: Minimum intensity threshold. + max_peaks: Maximum number of peaks per spectrum. + feature_id: MGF field name for spectrum ID. + num_workers: Number of parallel workers. + + Returns: + Path to the output directory containing JSON files. + """ + spec_source = Path(spec_source) + output_dir = Path(output_dir) + output_dir.mkdir(exist_ok=True, parents=True) + + labels_df = labels_df.astype(str) + + if spec_source.suffix == ".mgf": + parsed = parse_spectra_mgf(str(spec_source)) + input_specs = {} + for meta, tuples in parsed: + name = meta.get(feature_id, meta.get("FEATURE_ID", "unknown")) + spec = process_spec_file(meta, tuples, max_inten=inten_thresh, max_peaks=max_peaks) + input_specs[name] = spec + elif spec_source.is_dir(): + input_specs = {} + for _, row in tqdm(labels_df.iterrows(), total=len(labels_df), desc="Parsing spectra"): + spec_name = str(row["spec"]) + try: + _, spec = _process_single_ms( + spec_name, str(spec_source), + max_inten=inten_thresh, max_peaks=max_peaks + ) + input_specs[spec_name] = spec + except Exception as e: + logger.warning(f"Failed to parse {spec_name}: {e}") + input_specs[spec_name] = None + else: + raise ValueError(f"spec_source must be a directory or .mgf file, got: {spec_source}") + + for _, row in tqdm(labels_df.iterrows(), total=len(labels_df), desc="Assigning subformulae"): + spec_name = str(row["spec"]) + formula = str(row["formula"]) + ion_type = str(row["ionization"]) + spec = input_specs.get(spec_name) + + output_dict = get_output_dict( + spec_name=spec_name, + spec=spec, + form=formula, + mass_diff_type="ppm", + mass_diff_thresh=mass_diff_thresh, + ion_type=ion_type, + ) + + with open(output_dir / f"{spec_name}.json", "w") as f: + json.dump(output_dict, f, indent=4) + + logger.info(f"Wrote {len(labels_df)} subformulae JSONs to {output_dir}") + return output_dir diff --git a/massspecgym/models/de_novo/__init__.py b/massspecgym/models/de_novo/__init__.py index b235b15..cddecd4 100644 --- a/massspecgym/models/de_novo/__init__.py +++ b/massspecgym/models/de_novo/__init__.py @@ -3,4 +3,34 @@ from .dummy import DummyDeNovo from .smiles_tranformer import SmilesTransformer -__all__ = ["DeNovoMassSpecGymModel", "RandomDeNovo", "DummyDeNovo", "SmilesTransformer"] +__all__ = [ + "DeNovoMassSpecGymModel", + "RandomDeNovo", + "DummyDeNovo", + "SmilesTransformer", + "FP2MolDeNovoModel", + "FormulaEncoder", + "FRIGIDDecoder", + "MolForgeDecoder", + "DiffMSDecoder", +] + + +def __getattr__(name): + """Lazy imports for FP2Mol decoders to avoid pulling heavy optional dependencies.""" + if name == "FP2MolDeNovoModel": + from .fp2mol.base import FP2MolDeNovoModel + return FP2MolDeNovoModel + if name == "FormulaEncoder": + from .fp2mol.formula_utils import FormulaEncoder + return FormulaEncoder + if name == "FRIGIDDecoder": + from .fp2mol.frigid import FRIGIDDecoder + return FRIGIDDecoder + if name == "MolForgeDecoder": + from .fp2mol.molforge import MolForgeDecoder + return MolForgeDecoder + if name == "DiffMSDecoder": + from .fp2mol.diffms import DiffMSDecoder + return DiffMSDecoder + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/massspecgym/models/de_novo/fp2mol/__init__.py b/massspecgym/models/de_novo/fp2mol/__init__.py new file mode 100644 index 0000000..5512d42 --- /dev/null +++ b/massspecgym/models/de_novo/fp2mol/__init__.py @@ -0,0 +1,34 @@ +""" +FP2Mol decoder family: fingerprint-to-molecule de novo generation models. + +This package implements a family of de novo molecular generation models that +share a common two-stage pipeline: + + Spectrum --[MIST Encoder]--> Fingerprint + Formula --[Decoder]--> Molecule + +Three decoder architectures are provided: +- FRIGID: Masked Diffusion Language Model (MDLM) over SAFE sequences. +- DiffMS: Discrete graph diffusion over molecular graphs. +- MolForge: Autoregressive seq2seq transformer over SMILES/SELFIES. + +All decoders extend ``FP2MolDeNovoModel``, which provides: +- Optional MIST encoder for end-to-end spectrum-to-molecule inference. +- Two training modes: ``fp2mol_pretrain`` (decoder only) and ``spec2mol`` (end-to-end). +- Shared formula encoding via ``FormulaEncoder``. +""" + +from .base import FP2MolDeNovoModel +from .formula_utils import FormulaEncoder + + +def __getattr__(name): + if name == "FRIGIDDecoder": + from .frigid import FRIGIDDecoder + return FRIGIDDecoder + if name == "MolForgeDecoder": + from .molforge import MolForgeDecoder + return MolForgeDecoder + if name == "DiffMSDecoder": + from .diffms import DiffMSDecoder + return DiffMSDecoder + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/massspecgym/models/de_novo/fp2mol/base.py b/massspecgym/models/de_novo/fp2mol/base.py new file mode 100644 index 0000000..1d39592 --- /dev/null +++ b/massspecgym/models/de_novo/fp2mol/base.py @@ -0,0 +1,160 @@ +""" +Base class for all fingerprint-to-molecule de novo generation models. + +FP2MolDeNovoModel extends DeNovoMassSpecGymModel to support the common +two-stage pipeline: spectrum -> fingerprint -> molecule. It provides: + +1. Optional MIST encoder for end-to-end spectrum-to-molecule inference. +2. Two training modes: + - ``fp2mol_pretrain``: Train only the decoder on (fingerprint, formula, molecule) + triples from any molecule library. + - ``spec2mol``: Train or evaluate the full encoder+decoder pipeline on + MassSpecGym (spectrum, molecule) paired data. +3. A unified ``step()`` that routes to decoder-specific loss and generation. +""" + +import typing as T +from abc import abstractmethod +from pathlib import Path + +import torch + +from massspecgym.models.base import Stage +from massspecgym.models.de_novo.base import DeNovoMassSpecGymModel + + +class FP2MolDeNovoModel(DeNovoMassSpecGymModel): + """Base class for fingerprint-to-molecule de novo models. + + Subclasses must implement: + - ``decode_from_fingerprint``: Generate molecules from a fingerprint (+formula). + - ``compute_decoder_loss``: Compute decoder-specific training loss from a batch. + + Args: + encoder: Optional MIST encoder module (for end-to-end spec2mol mode). + encoder_checkpoint: Path to pretrained encoder weights. + fingerprint_bits: Dimensionality of the fingerprint vector. + use_formula: Whether the decoder uses formula conditioning. + training_mode: One of 'fp2mol_pretrain' or 'spec2mol'. + freeze_encoder: If True, freeze encoder weights during training. + num_generation_samples: Number of molecules to generate per spectrum at inference. + """ + + def __init__( + self, + encoder: T.Optional[torch.nn.Module] = None, + encoder_checkpoint: T.Optional[str] = None, + fingerprint_bits: int = 4096, + use_formula: bool = True, + training_mode: str = "spec2mol", + freeze_encoder: bool = True, + num_generation_samples: int = 10, + *args, + **kwargs, + ): + super().__init__(*args, **kwargs) + self.encoder = encoder + self.fingerprint_bits = fingerprint_bits + self.use_formula = use_formula + self.training_mode = training_mode + self.freeze_encoder = freeze_encoder + self.num_generation_samples = num_generation_samples + + if encoder_checkpoint is not None and self.encoder is not None: + self._load_encoder_checkpoint(encoder_checkpoint) + + if self.freeze_encoder and self.encoder is not None: + for param in self.encoder.parameters(): + param.requires_grad = False + + def _load_encoder_checkpoint(self, checkpoint_path: str): + """Load pretrained encoder weights from a checkpoint file.""" + ckpt = torch.load(checkpoint_path, map_location="cpu") + state_dict = ckpt if not isinstance(ckpt, dict) else ckpt.get("state_dict", ckpt) + self.encoder.load_state_dict(state_dict, strict=False) + + def encode_spectrum(self, batch: dict) -> T.Tuple[torch.Tensor, dict]: + """Run the MIST encoder on a spectrum batch. + + Args: + batch: Batch dict containing spectrum data (in MIST featurized format). + + Returns: + Tuple of (fingerprint tensor [B, fingerprint_bits], aux_outputs dict). + """ + if self.encoder is None: + raise RuntimeError( + "No encoder available. Either provide an encoder module or use " + "training_mode='fp2mol_pretrain' with pre-computed fingerprints." + ) + if self.freeze_encoder: + with torch.no_grad(): + return self.encoder(batch) + return self.encoder(batch) + + @abstractmethod + def decode_from_fingerprint( + self, + fingerprint: torch.Tensor, + formula: T.Optional[T.Any] = None, + num_samples: int = 1, + ) -> list[list[T.Optional[str]]]: + """Generate molecules from fingerprint (and optionally formula). + + Args: + fingerprint: Fingerprint tensor [B, fingerprint_bits]. + formula: Optional formula conditioning (format depends on decoder). + num_samples: Number of molecules to generate per input. + + Returns: + List of lists of SMILES strings (or None for failed generations). + Shape: (batch_size, num_samples). + """ + raise NotImplementedError + + @abstractmethod + def compute_decoder_loss(self, batch: dict) -> torch.Tensor: + """Compute the decoder-specific training loss. + + Args: + batch: Batch dict. In fp2mol_pretrain mode, contains 'fingerprint', + 'formula', and target molecule representations. In spec2mol mode, + contains spectrum data and molecule targets. + + Returns: + Scalar loss tensor. + """ + raise NotImplementedError + + def step(self, batch: dict, stage: Stage = Stage.NONE) -> dict: + """Unified training/evaluation step. + + In fp2mol_pretrain mode: + - Loss is computed from pre-computed fingerprints in the batch. + - Molecule generation is only performed during val/test. + + In spec2mol mode: + - Fingerprints are obtained from the MIST encoder. + - Loss and generation use the encoder output. + """ + if self.training_mode == "fp2mol_pretrain": + loss = self.compute_decoder_loss(batch) + if stage in self.log_only_loss_at_stages: + mols_pred = None + else: + fp = batch["fingerprint"] + formula = batch.get("formula", None) + mols_pred = self.decode_from_fingerprint( + fp, formula, num_samples=self.num_generation_samples + ) + else: + loss = self.compute_decoder_loss(batch) + if stage in self.log_only_loss_at_stages: + mols_pred = None + else: + fp, _ = self.encode_spectrum(batch) + formula = batch.get("formula", None) + mols_pred = self.decode_from_fingerprint( + fp, formula, num_samples=self.num_generation_samples + ) + return dict(loss=loss, mols_pred=mols_pred) diff --git a/massspecgym/models/de_novo/fp2mol/diffms/__init__.py b/massspecgym/models/de_novo/fp2mol/diffms/__init__.py new file mode 100644 index 0000000..4b468f4 --- /dev/null +++ b/massspecgym/models/de_novo/fp2mol/diffms/__init__.py @@ -0,0 +1,8 @@ +""" +DiffMS decoder: Discrete graph diffusion for fingerprint-to-molecule generation. + +A discrete denoising diffusion model that generates molecular graphs (atom types +and bond types) conditioned on Morgan fingerprints, from Bohde et al. 2025. +""" + +from .model import DiffMSDecoder diff --git a/massspecgym/models/de_novo/fp2mol/diffms/diffusion_utils.py b/massspecgym/models/de_novo/fp2mol/diffms/diffusion_utils.py new file mode 100644 index 0000000..5caba62 --- /dev/null +++ b/massspecgym/models/de_novo/fp2mol/diffms/diffusion_utils.py @@ -0,0 +1,195 @@ +""" +Discrete diffusion utilities for DiffMS. + +Provides noise schedule computation, posterior distribution calculation, +and discrete feature sampling for the graph diffusion process. +""" + +from dataclasses import dataclass +from typing import Optional + +import math +import numpy as np +import torch +import torch.nn.functional as F + + +@dataclass +class PlaceHolder: + """Container for graph features (nodes X, edges E, global y).""" + X: torch.Tensor + E: torch.Tensor + y: torch.Tensor + + def mask(self, node_mask): + x_mask = node_mask.unsqueeze(-1) + e_mask = x_mask.unsqueeze(2) * x_mask.unsqueeze(1) + self.X = self.X * x_mask + self.E = self.E * e_mask + return self + + +def assert_correctly_masked(variable, node_mask): + assert (variable * (1 - node_mask.long())).abs().max().item() < 1e-4 + + +def cosine_beta_schedule_discrete(timesteps, s=0.008): + """Cosine noise schedule for discrete diffusion.""" + steps = timesteps + 2 + x = np.linspace(0, steps, steps) + alphas_cumprod = np.cos(0.5 * np.pi * ((x / steps) + s) / (1 + s)) ** 2 + alphas_cumprod = alphas_cumprod / alphas_cumprod[0] + alphas = alphas_cumprod[1:] / alphas_cumprod[:-1] + betas = 1 - alphas + return betas.squeeze() + + +class PredefinedNoiseScheduleDiscrete(torch.nn.Module): + """Discrete noise schedule with precomputed betas and alpha_bars.""" + + def __init__(self, noise_schedule: str = "cosine", timesteps: int = 500): + super().__init__() + self.timesteps = timesteps + if noise_schedule == "cosine": + betas = cosine_beta_schedule_discrete(timesteps) + else: + raise NotImplementedError(noise_schedule) + + self.register_buffer("betas", torch.from_numpy(betas).float()) + self.alphas = 1 - torch.clamp(self.betas, min=0, max=0.9999) + log_alpha = torch.log(self.alphas) + log_alpha_bar = torch.cumsum(log_alpha, dim=0) + self.alphas_bar = torch.exp(log_alpha_bar) + + def forward(self, t_normalized=None, t_int=None): + assert (t_normalized is None) != (t_int is None) + if t_int is None: + t_int = torch.round(t_normalized * self.timesteps) + return self.betas[t_int.long()] + + def get_alpha_bar(self, t_normalized=None, t_int=None): + assert (t_normalized is None) != (t_int is None) + if t_int is None: + t_int = torch.round(t_normalized * self.timesteps) + return self.alphas_bar.to(t_int.device)[t_int.long()] + + +class MarginalUniformTransition: + """Transition matrices using marginal distributions as the limit.""" + + def __init__(self, x_marginals, e_marginals, y_classes): + self.X_classes = len(x_marginals) + self.E_classes = len(e_marginals) + self.y_classes = y_classes + self.u_x = x_marginals.unsqueeze(0).expand(self.X_classes, -1).unsqueeze(0) + self.u_e = e_marginals.unsqueeze(0).expand(self.E_classes, -1).unsqueeze(0) + self.u_y = torch.ones(1, self.y_classes, self.y_classes) + if self.y_classes > 0: + self.u_y = self.u_y / self.y_classes + + def get_Qt(self, beta_t, device): + beta_t = beta_t.unsqueeze(1).to(device) + self.u_x = self.u_x.to(device) + self.u_e = self.u_e.to(device) + self.u_y = self.u_y.to(device) + q_x = beta_t * self.u_x + (1 - beta_t) * torch.eye(self.X_classes, device=device).unsqueeze(0) + q_e = beta_t * self.u_e + (1 - beta_t) * torch.eye(self.E_classes, device=device).unsqueeze(0) + q_y = beta_t * self.u_y + (1 - beta_t) * torch.eye(self.y_classes, device=device).unsqueeze(0) + return PlaceHolder(X=q_x, E=q_e, y=q_y) + + def get_Qt_bar(self, alpha_bar_t, device): + alpha_bar_t = alpha_bar_t.unsqueeze(1).to(device) + self.u_x = self.u_x.to(device) + self.u_e = self.u_e.to(device) + self.u_y = self.u_y.to(device) + q_x = alpha_bar_t * torch.eye(self.X_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_x + q_e = alpha_bar_t * torch.eye(self.E_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_e + q_y = alpha_bar_t * torch.eye(self.y_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_y + return PlaceHolder(X=q_x, E=q_e, y=q_y) + + +class DiscreteUniformTransition: + """Transition matrices with uniform limit distribution.""" + + def __init__(self, x_classes, e_classes, y_classes): + self.X_classes = x_classes + self.E_classes = e_classes + self.y_classes = y_classes + self.u_x = torch.ones(1, x_classes, x_classes) / x_classes if x_classes > 0 else torch.zeros(1, 1, 1) + self.u_e = torch.ones(1, e_classes, e_classes) / e_classes if e_classes > 0 else torch.zeros(1, 1, 1) + self.u_y = torch.ones(1, y_classes, y_classes) / y_classes if y_classes > 0 else torch.zeros(1, 1, 1) + + def get_Qt(self, beta_t, device): + beta_t = beta_t.unsqueeze(1).to(device) + self.u_x = self.u_x.to(device) + self.u_e = self.u_e.to(device) + self.u_y = self.u_y.to(device) + q_x = beta_t * self.u_x + (1 - beta_t) * torch.eye(self.X_classes, device=device).unsqueeze(0) + q_e = beta_t * self.u_e + (1 - beta_t) * torch.eye(self.E_classes, device=device).unsqueeze(0) + q_y = beta_t * self.u_y + (1 - beta_t) * torch.eye(self.y_classes, device=device).unsqueeze(0) + return PlaceHolder(X=q_x, E=q_e, y=q_y) + + def get_Qt_bar(self, alpha_bar_t, device): + alpha_bar_t = alpha_bar_t.unsqueeze(1).to(device) + self.u_x = self.u_x.to(device) + self.u_e = self.u_e.to(device) + self.u_y = self.u_y.to(device) + q_x = alpha_bar_t * torch.eye(self.X_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_x + q_e = alpha_bar_t * torch.eye(self.E_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_e + q_y = alpha_bar_t * torch.eye(self.y_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_y + return PlaceHolder(X=q_x, E=q_e, y=q_y) + + +def compute_batched_over0_posterior_distribution(X_t, Qt, Qsb, Qtb): + """Compute p(x_{t-1} | x_t, x_0) for all possible x_0 values. + + Returns tensor where entry [b, n, x0, x_{t-1}] is the posterior probability. + """ + X_t = X_t.flatten(start_dim=1, end_dim=-2).to(torch.float32) + Qt_T = Qt.transpose(-1, -2) + left_term = (X_t @ Qt_T).unsqueeze(dim=2) + right_term = Qsb.unsqueeze(1) + numerator = left_term * right_term + X_t_transposed = X_t.transpose(-1, -2) + prod = Qtb @ X_t_transposed + prod = prod.transpose(-1, -2) + denominator = prod.unsqueeze(-1) + denominator[denominator == 0] = 1e-6 + return numerator / denominator + + +def sample_discrete_features(probX, probE, node_mask): + """Sample discrete features from categorical distributions.""" + bs, n, _ = probX.shape + probX[~node_mask] = 1 / probX.shape[-1] + X_t = probX.reshape(bs * n, -1).multinomial(1).reshape(bs, n) + + inverse_edge_mask = ~(node_mask.unsqueeze(1) * node_mask.unsqueeze(2)) + diag_mask = torch.eye(n, device=probE.device).unsqueeze(0).expand(bs, -1, -1).bool() + probE[inverse_edge_mask] = 1 / probE.shape[-1] + probE[diag_mask] = 1 / probE.shape[-1] + E_t = probE.reshape(bs * n * n, -1).multinomial(1).reshape(bs, n, n) + E_t = torch.triu(E_t, diagonal=1) + E_t = E_t + E_t.transpose(1, 2) + return PlaceHolder(X=X_t, E=E_t, y=torch.zeros(bs, 0).type_as(X_t)) + + +def sample_discrete_feature_noise(limit_dist, node_mask): + """Sample from the limit distribution of the diffusion process.""" + bs, n_max = node_mask.shape + x_limit = limit_dist.X[None, None, :].expand(bs, n_max, -1) + e_limit = limit_dist.E[None, None, None, :].expand(bs, n_max, n_max, -1) + + U_X = x_limit.flatten(end_dim=-2).multinomial(1).reshape(bs, n_max) + U_E = e_limit.flatten(end_dim=-2).multinomial(1).reshape(bs, n_max, n_max) + + U_X = F.one_hot(U_X, num_classes=x_limit.shape[-1]).float() + U_E = F.one_hot(U_E, num_classes=e_limit.shape[-1]).float() + + upper_tri = torch.zeros_like(U_E) + indices = torch.triu_indices(row=n_max, col=n_max, offset=1) + upper_tri[:, indices[0], indices[1], :] = 1 + U_E = U_E * upper_tri + U_E = U_E + U_E.transpose(1, 2) + + return PlaceHolder(X=U_X, E=U_E, y=torch.zeros(bs, 0)).mask(node_mask) diff --git a/massspecgym/models/de_novo/fp2mol/diffms/graph_transformer.py b/massspecgym/models/de_novo/fp2mol/diffms/graph_transformer.py new file mode 100644 index 0000000..d148f02 --- /dev/null +++ b/massspecgym/models/de_novo/fp2mol/diffms/graph_transformer.py @@ -0,0 +1,255 @@ +""" +Graph Transformer for DiffMS discrete graph diffusion. + +Implements the XEy (node-edge-global) Transformer architecture that simultaneously +updates node features X, edge features E, and global features y (fingerprint). +""" + +import math + +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch import Tensor + +from .diffusion_utils import assert_correctly_masked, PlaceHolder + + +def masked_softmax(x, mask, **kwargs): + """Softmax with mask (matching reference DiffMS exactly).""" + if mask.sum() == 0: + return x + x_masked = x.clone() + x_masked[mask == 0] = -float("inf") + return torch.softmax(x_masked, **kwargs) + + +class Xtoy(nn.Module): + """Aggregate node features to global feature. + + Matches reference DiffMS src/models/layers.py exactly: + output = Linear(cat([mean, min, max, variance], dim=-1)) + """ + def __init__(self, dx, dy): + super().__init__() + self.lin = nn.Linear(4 * dx, dy) + + def forward(self, X, x_mask): + # x_mask: (bs, n, 1) -> expand to (bs, n, dx) + x_mask = x_mask.expand(-1, -1, X.shape[-1]) + float_imask = 1 - x_mask.float() + m = X.sum(dim=1) / torch.sum(x_mask, dim=1) + mi = (X + 1e5 * float_imask).min(dim=1)[0] + ma = (X - 1e5 * float_imask).max(dim=1)[0] + std = torch.sum(((X - m[:, None, :]) ** 2) * x_mask, dim=1) / torch.sum(x_mask, dim=1) + z = torch.hstack((m, mi, ma, std)) + return self.lin(z) + + +class Etoy(nn.Module): + """Aggregate edge features to global feature. + + Matches reference DiffMS src/models/layers.py exactly. + """ + def __init__(self, d, dy): + super().__init__() + self.lin = nn.Linear(4 * d, dy) + + def forward(self, E, e_mask1, e_mask2): + mask = (e_mask1 * e_mask2).expand(-1, -1, -1, E.shape[-1]) + float_imask = 1 - mask.float() + divide = torch.sum(mask, dim=(1, 2)) + m = E.sum(dim=(1, 2)) / divide + mi = (E + 1e5 * float_imask).min(dim=2)[0].min(dim=1)[0] + ma = (E - 1e5 * float_imask).max(dim=2)[0].max(dim=1)[0] + std = torch.sum(((E - m[:, None, None, :]) ** 2) * mask, dim=(1, 2)) / divide + z = torch.hstack((m, mi, ma, std)) + return self.lin(z) + + +class NodeEdgeBlock(nn.Module): + """Self-attention block that jointly updates node, edge, and global features.""" + + def __init__(self, dx, de, dy, n_head, **kwargs): + super().__init__() + assert dx % n_head == 0 + self.dx = dx + self.de = de + self.dy = dy + self.df = dx // n_head + self.n_head = n_head + + self.q = nn.Linear(dx, dx) + self.k = nn.Linear(dx, dx) + self.v = nn.Linear(dx, dx) + + self.e_add = nn.Linear(de, dx) + self.e_mul = nn.Linear(de, dx) + + self.y_e_mul = nn.Linear(dy, dx) + self.y_e_add = nn.Linear(dy, dx) + self.y_x_mul = nn.Linear(dy, dx) + self.y_x_add = nn.Linear(dy, dx) + + self.y_y = nn.Linear(dy, dy) + self.x_y = Xtoy(dx, dy) + self.e_y = Etoy(de, dy) + + self.x_out = nn.Linear(dx, dx) + self.e_out = nn.Linear(dx, de) + self.y_out = nn.Sequential(nn.Linear(dy, dy), nn.ReLU(), nn.Linear(dy, dy)) + + def forward(self, X, E, y, node_mask): + bs, n, _ = X.shape + x_mask = node_mask.unsqueeze(-1) + e_mask1 = x_mask.unsqueeze(2) + e_mask2 = x_mask.unsqueeze(1) + + Q = (self.q(X) * x_mask).reshape(bs, n, self.n_head, self.df).unsqueeze(2) + K = (self.k(X) * x_mask).reshape(bs, n, self.n_head, self.df).unsqueeze(1) + Y = Q * K / math.sqrt(self.df) + + E1 = (self.e_mul(E) * e_mask1 * e_mask2).reshape(bs, n, n, self.n_head, self.df) + E2 = (self.e_add(E) * e_mask1 * e_mask2).reshape(bs, n, n, self.n_head, self.df) + Y = Y * (E1 + 1) + E2 + + newE = Y.flatten(start_dim=3) + ye1 = self.y_e_add(y).unsqueeze(1).unsqueeze(1) + ye2 = self.y_e_mul(y).unsqueeze(1).unsqueeze(1) + newE = ye1 + (ye2 + 1) * newE + newE = self.e_out(newE) * e_mask1 * e_mask2 + + softmax_mask = e_mask2.expand(-1, n, -1, self.n_head) + attn = masked_softmax(Y, softmax_mask, dim=2) # bs, n, n, n_head + + V = (self.v(X) * x_mask).reshape(bs, n, self.n_head, self.df).unsqueeze(1) + weighted_V = (attn * V).sum(dim=2).flatten(start_dim=2) + + yx1 = self.y_x_add(y).unsqueeze(1) + yx2 = self.y_x_mul(y).unsqueeze(1) + newX = yx1 + (yx2 + 1) * weighted_V + newX = self.x_out(newX) * x_mask + + new_y = self.y_y(y) + self.x_y(X, x_mask) + self.e_y(E, e_mask1, e_mask2) + new_y = self.y_out(new_y) + + return newX, newE, new_y + + +class XEyTransformerLayer(nn.Module): + """Full transformer layer updating X, E, y with self-attention and FFN.""" + + def __init__(self, dx, de, dy, n_head, dim_ffX=2048, dim_ffE=128, dim_ffy=2048, + dropout=0.1, layer_norm_eps=1e-5, **kwargs): + super().__init__() + self.self_attn = NodeEdgeBlock(dx, de, dy, n_head, **kwargs) + + self.linX1 = nn.Linear(dx, dim_ffX) + self.linX2 = nn.Linear(dim_ffX, dx) + self.normX1 = nn.LayerNorm(dx, eps=layer_norm_eps) + self.normX2 = nn.LayerNorm(dx, eps=layer_norm_eps) + self.dropoutX1 = nn.Dropout(dropout) + self.dropoutX2 = nn.Dropout(dropout) + self.dropoutX3 = nn.Dropout(dropout) + + self.linE1 = nn.Linear(de, dim_ffE) + self.linE2 = nn.Linear(dim_ffE, de) + self.normE1 = nn.LayerNorm(de, eps=layer_norm_eps) + self.normE2 = nn.LayerNorm(de, eps=layer_norm_eps) + self.dropoutE1 = nn.Dropout(dropout) + self.dropoutE2 = nn.Dropout(dropout) + self.dropoutE3 = nn.Dropout(dropout) + + self.lin_y1 = nn.Linear(dy, dim_ffy) + self.lin_y2 = nn.Linear(dim_ffy, dy) + self.norm_y1 = nn.LayerNorm(dy, eps=layer_norm_eps) + self.norm_y2 = nn.LayerNorm(dy, eps=layer_norm_eps) + self.dropout_y1 = nn.Dropout(dropout) + self.dropout_y2 = nn.Dropout(dropout) + self.dropout_y3 = nn.Dropout(dropout) + + def forward(self, X, E, y, node_mask): + newX, newE, new_y = self.self_attn(X, E, y, node_mask=node_mask) + + X = self.normX1(X + self.dropoutX1(newX)) + E = self.normE1(E + self.dropoutE1(newE)) + y = self.norm_y1(y + self.dropout_y1(new_y)) + + X = self.normX2(X + self.dropoutX3(self.linX2(self.dropoutX2(F.relu(self.linX1(X)))))) + E = self.normE2(E + self.dropoutE3(self.linE2(self.dropoutE2(F.relu(self.linE1(E)))))) + y = self.norm_y2(y + self.dropout_y3(self.lin_y2(self.dropout_y2(F.relu(self.lin_y1(y)))))) + + return X, E, y + + +class GraphTransformer(nn.Module): + """Graph Transformer backbone for DiffMS. + + Processes noisy graph features (node types, bond types, global fingerprint) + through multiple XEyTransformerLayers and projects to output dimensions. + + Args: + n_layers: Number of transformer layers. + input_dims: Dict with X, E, y input dimensions. + hidden_mlp_dims: Dict with X, E, y hidden MLP dimensions. + hidden_dims: Dict with X, E, y hidden dimensions. + output_dims: Dict with X, E, y output dimensions. + """ + + def __init__(self, n_layers, input_dims, hidden_mlp_dims, hidden_dims, output_dims, + act_fn_in=nn.ReLU(), act_fn_out=nn.ReLU()): + super().__init__() + self.out_dim_X = output_dims["X"] + self.out_dim_E = output_dims["E"] + self.out_dim_y = output_dims["y"] + + self.mlp_in_X = nn.Sequential( + nn.Linear(input_dims["X"], hidden_mlp_dims["X"]), act_fn_in, + nn.Linear(hidden_mlp_dims["X"], hidden_dims["dx"]), act_fn_in, + ) + self.mlp_in_E = nn.Sequential( + nn.Linear(input_dims["E"], hidden_mlp_dims["E"]), act_fn_in, + nn.Linear(hidden_mlp_dims["E"], hidden_dims["de"]), act_fn_in, + ) + self.mlp_in_y = nn.Sequential( + nn.Linear(input_dims["y"], hidden_mlp_dims["y"]), act_fn_in, + nn.Linear(hidden_mlp_dims["y"], hidden_dims["dy"]), act_fn_in, + ) + + self.tf_layers = nn.ModuleList([ + XEyTransformerLayer( + dx=hidden_dims["dx"], de=hidden_dims["de"], dy=hidden_dims["dy"], + n_head=hidden_dims["n_head"], + dim_ffX=hidden_dims["dim_ffX"], dim_ffE=hidden_dims["dim_ffE"], + ) + for _ in range(n_layers) + ]) + + self.mlp_out_X = nn.Sequential( + nn.Linear(hidden_dims["dx"], hidden_mlp_dims["X"]), act_fn_out, + nn.Linear(hidden_mlp_dims["X"], self.out_dim_X), + ) + self.mlp_out_E = nn.Sequential( + nn.Linear(hidden_dims["de"], hidden_mlp_dims["E"]), act_fn_out, + nn.Linear(hidden_mlp_dims["E"], self.out_dim_E), + ) + self.mlp_out_y = nn.Sequential( + nn.Linear(hidden_dims["dy"], hidden_mlp_dims["y"]), act_fn_out, + nn.Linear(hidden_mlp_dims["y"], self.out_dim_y), + ) + + def forward(self, X, E, y, node_mask): + bs, n = X.shape[0], X.shape[1] + + X = self.mlp_in_X(X) + E = self.mlp_in_E(E) + y = self.mlp_in_y(y) + + for layer in self.tf_layers: + X, E, y = layer(X, E, y, node_mask) + + X = self.mlp_out_X(X) + E = self.mlp_out_E(E) + y = self.mlp_out_y(y) + + return PlaceHolder(X=X, E=E, y=y) diff --git a/massspecgym/models/de_novo/fp2mol/diffms/model.py b/massspecgym/models/de_novo/fp2mol/diffms/model.py new file mode 100644 index 0000000..fcf3cef --- /dev/null +++ b/massspecgym/models/de_novo/fp2mol/diffms/model.py @@ -0,0 +1,252 @@ +""" +DiffMS decoder: Discrete graph diffusion for fingerprint-to-molecule generation. + +Ported from Bohde et al., "DiffMS: Diffusion generation of molecules conditioned +on mass spectra", 2025. + +The model performs discrete diffusion over molecular graphs, where: +- Node features: one-hot atom types (C, O, P, N, S, Cl, F, H) +- Edge features: one-hot bond types (no-bond, single, double, triple, aromatic) +- Global features: Morgan fingerprint as conditioning signal + +Training uses discrete diffusion loss (CE on edges, optionally nodes/global). +Sampling reverses the diffusion process via posterior sampling. +""" + +from typing import Optional, List + +import torch +import torch.nn as nn +import torch.nn.functional as F +from rdkit import Chem + +from massspecgym.models.base import Stage +from massspecgym.models.de_novo.fp2mol.base import FP2MolDeNovoModel +from .graph_transformer import GraphTransformer +from .diffusion_utils import ( + PlaceHolder, + PredefinedNoiseScheduleDiscrete, + MarginalUniformTransition, + DiscreteUniformTransition, + compute_batched_over0_posterior_distribution, + sample_discrete_features, + sample_discrete_feature_noise, +) + +ATOM_DECODER = ["C", "O", "P", "N", "S", "Cl", "F", "H"] +BOND_TYPES = [None, Chem.rdchem.BondType.SINGLE, Chem.rdchem.BondType.DOUBLE, + Chem.rdchem.BondType.TRIPLE, Chem.rdchem.BondType.AROMATIC] + + +def mol_from_graphs(node_list, adjacency_matrix, atom_decoder=ATOM_DECODER): + """Convert graph representation to RDKit molecule.""" + mol = Chem.RWMol() + node_to_idx = {} + for i in range(len(node_list)): + if node_list[i] == -1: + continue + a = Chem.Atom(atom_decoder[int(node_list[i])]) + node_to_idx[i] = mol.AddAtom(a) + + for ix, row in enumerate(adjacency_matrix): + for iy, bond in enumerate(row): + if iy <= ix: + continue + if 1 <= bond <= 4 and ix in node_to_idx and iy in node_to_idx: + mol.AddBond(node_to_idx[ix], node_to_idx[iy], BOND_TYPES[bond]) + + try: + mol = mol.GetMol() + return mol + except Exception: + return None + + +class DiffMSDecoder(FP2MolDeNovoModel): + """DiffMS discrete graph diffusion decoder. + + Args: + num_atom_types: Number of atom types (8). + num_bond_types: Number of bond types including no-bond (5). + diffusion_steps: Number of diffusion steps (500). + noise_schedule: Noise schedule type ('cosine'). + transition: Transition type ('marginal' or 'uniform'). + n_layers: Number of GraphTransformer layers. + hidden_dims: Hidden dimensions for the GraphTransformer. + lambda_train: Loss weights [node_CE, edge_CE, global_CE]. + max_nodes: Maximum number of nodes in generated graphs. + fingerprint_bits: Number of fingerprint bits (2048 for DiffMS). + """ + + def __init__( + self, + num_atom_types: int = 8, + num_bond_types: int = 5, + diffusion_steps: int = 500, + noise_schedule: str = "cosine", + transition: str = "marginal", + n_layers: int = 6, + hidden_dims: Optional[dict] = None, + lambda_train: Optional[list] = None, + max_nodes: int = 50, + fingerprint_bits: int = 2048, + *args, + **kwargs, + ): + super().__init__(fingerprint_bits=fingerprint_bits, use_formula=False, *args, **kwargs) + + self.num_atom_types = num_atom_types + self.num_bond_types = num_bond_types + self.T = diffusion_steps + self.max_nodes = max_nodes + self.lambda_train = lambda_train or [0.0, 1.0, 0.0] + + if hidden_dims is None: + hidden_dims = { + "dx": 256, "de": 64, "dy": 256, "n_head": 8, + "dim_ffX": 256, "dim_ffE": 128, + } + + extra_X_feat = 1 # timestep + extra_E_feat = 1 + extra_y_feat = 1 + + input_dims = { + "X": num_atom_types + extra_X_feat, + "E": num_bond_types + extra_E_feat, + "y": fingerprint_bits + extra_y_feat, + } + output_dims = {"X": num_atom_types, "E": num_bond_types, "y": 0} + hidden_mlp_dims = {"X": 256, "E": 128, "y": 256} + + self.model = GraphTransformer( + n_layers=n_layers, + input_dims=input_dims, + hidden_mlp_dims=hidden_mlp_dims, + hidden_dims=hidden_dims, + output_dims=output_dims, + ) + + self.noise_schedule = PredefinedNoiseScheduleDiscrete(noise_schedule, diffusion_steps) + + x_marginals = torch.ones(num_atom_types) / num_atom_types + e_marginals = torch.zeros(num_bond_types) + e_marginals[0] = 0.9 + e_marginals[1:] = 0.1 / (num_bond_types - 1) + + if transition == "marginal": + self.transition_model = MarginalUniformTransition(x_marginals, e_marginals, 0) + else: + self.transition_model = DiscreteUniformTransition(num_atom_types, num_bond_types, 0) + + self.limit_dist = PlaceHolder(X=x_marginals, E=e_marginals, y=torch.zeros(0)) + + def apply_noise(self, X, E, y, node_mask): + """Apply forward diffusion noise to graph features.""" + t_int = torch.randint(0, self.T + 1, size=(X.size(0), 1), device=X.device) + s_int = t_int - 1 + t_float = t_int / self.T + s_float = s_int / self.T + + beta_t = self.noise_schedule(t_normalized=t_float) + alpha_s_bar = self.noise_schedule.get_alpha_bar(t_normalized=s_float) + alpha_t_bar = self.noise_schedule.get_alpha_bar(t_normalized=t_float) + + Qtb = self.transition_model.get_Qt_bar(alpha_t_bar, X.device) + prob_X = (X @ Qtb.X).clamp(min=1e-5) + prob_E = (E @ Qtb.E).clamp(min=1e-5) + + sampled = sample_discrete_features(prob_X, prob_E, node_mask) + X_t = F.one_hot(sampled.X, self.num_atom_types).float() + E_t = F.one_hot(sampled.E, self.num_bond_types).float() + + x_mask = node_mask.unsqueeze(-1) + X_t = X_t * x_mask + e_mask = x_mask.unsqueeze(2) * x_mask.unsqueeze(1) + E_t = E_t * e_mask + + return { + "t_int": t_int, "t": t_float, + "beta_t": beta_t, "alpha_s_bar": alpha_s_bar, "alpha_t_bar": alpha_t_bar, + "X_t": X_t, "E_t": E_t, "y_t": y, + } + + def compute_decoder_loss(self, batch: dict) -> torch.Tensor: + """Compute discrete diffusion training loss.""" + X = batch.get("X") + E = batch.get("E") + y = batch.get("fingerprint") + node_mask = batch.get("node_mask") + + if X is None: + return torch.tensor(0.0, device=self.device, requires_grad=True) + + noisy = self.apply_noise(X, E, y, node_mask) + + t_emb = noisy["t"].unsqueeze(-1) + X_in = torch.cat([noisy["X_t"], t_emb.expand(-1, noisy["X_t"].size(1), -1)], dim=-1) + E_in = torch.cat([noisy["E_t"], t_emb.unsqueeze(1).expand(-1, noisy["E_t"].size(1), noisy["E_t"].size(2), -1)], dim=-1) + y_in = torch.cat([noisy["y_t"], t_emb.squeeze(-1)], dim=-1) + + pred = self.model(X_in, E_in, y_in, node_mask) + + true_X = X.argmax(dim=-1) if X.dim() == 3 else X + true_E = E.argmax(dim=-1) if E.dim() == 4 else E + + loss_X = F.cross_entropy(pred.X.reshape(-1, self.num_atom_types), true_X.reshape(-1), reduction="mean") + loss_E = F.cross_entropy(pred.E.reshape(-1, self.num_bond_types), true_E.reshape(-1), reduction="mean") + + loss = self.lambda_train[0] * loss_X + self.lambda_train[1] * loss_E + return loss + + @torch.no_grad() + def decode_from_fingerprint( + self, + fingerprint: torch.Tensor, + formula=None, + num_samples: int = 1, + ) -> list: + """Generate molecules from fingerprint via reverse diffusion.""" + self.eval() + batch_size = fingerprint.shape[0] + all_preds = [] + + for b_idx in range(batch_size): + fp = fingerprint[b_idx:b_idx + 1] + sample_mols = [] + + for _ in range(num_samples): + n_nodes = torch.randint(5, self.max_nodes, (1,)).item() + node_mask = torch.ones(1, n_nodes, device=self.device).bool() + + z_T = sample_discrete_feature_noise(self.limit_dist, node_mask) + X = z_T.X.to(self.device) + E = z_T.E.to(self.device) + y = fp.to(self.device) + + for s_int in reversed(range(0, self.T)): + t_int = s_int + 1 + t = torch.tensor([t_int / self.T], device=self.device) + + t_emb = t.unsqueeze(-1) + X_in = torch.cat([X, t_emb.expand(-1, X.size(1), -1)], dim=-1) + E_in = torch.cat([E, t_emb.unsqueeze(1).expand(-1, E.size(1), E.size(2), -1)], dim=-1) + y_in = torch.cat([y, t_emb], dim=-1) + + pred = self.model(X_in, E_in, y_in, node_mask.float()) + + pred_X = F.softmax(pred.X, dim=-1) + pred_E = F.softmax(pred.E, dim=-1) + + sampled = sample_discrete_features(pred_X, pred_E, node_mask) + X = F.one_hot(sampled.X, self.num_atom_types).float() + E = F.one_hot(sampled.E, self.num_bond_types).float() + + node_types = X.argmax(dim=-1)[0].cpu().numpy() + adj = E.argmax(dim=-1)[0].cpu().numpy() + mol = mol_from_graphs(node_types, adj) + smi = Chem.MolToSmiles(mol) if mol is not None else None + sample_mols.append(smi) + + all_preds.append(sample_mols) + return all_preds diff --git a/massspecgym/models/de_novo/fp2mol/formula_utils.py b/massspecgym/models/de_novo/fp2mol/formula_utils.py new file mode 100644 index 0000000..2d68810 --- /dev/null +++ b/massspecgym/models/de_novo/fp2mol/formula_utils.py @@ -0,0 +1,138 @@ +""" +Formula encoding utilities shared by FP2Mol decoders. + +Provides a 30-element FormulaEncoder that maps molecular formula strings +(e.g., "C9H10N2O2") to fixed-size count vectors. Used by FRIGID and DiffMS +for formula conditioning during molecule generation. +""" + +import re +from typing import Dict, List, Optional + +import torch + + +class FormulaEncoder: + """Encoder for molecular formulas to fixed-size numerical vectors. + + Converts molecular formula strings into 30-dimensional vectors of atom counts + suitable for conditioning molecular generation models. + + The atom vocabulary covers common organic elements plus metals that may appear + in bioactive molecules, matching the vocabulary used by FRIGID. + + Args: + normalize: Normalization strategy for atom counts. + - 'none': No normalization (raw integer counts). + - 'sum': Divide by total number of atoms. + - 'max': Divide by maximum count in formula. + - 'log': Apply log(count + 1) transformation. + """ + + ATOM_VOCAB = [ + 'C', 'H', 'N', 'O', 'F', 'S', 'P', 'Cl', 'Br', 'I', + 'B', 'Si', 'Se', 'As', 'Al', 'Sn', 'Li', 'Na', 'K', 'Mg', + 'Ca', 'Fe', 'Zn', 'Cu', 'Mn', 'Co', 'Ni', 'Pt', 'Pd', 'Au' + ] + + _FORMULA_PATTERN = re.compile(r'([A-Z][a-z]?)(\d*)') + + def __init__(self, normalize: str = 'none'): + self.atom_vocab = self.ATOM_VOCAB + self.atom_to_idx = {atom: idx for idx, atom in enumerate(self.atom_vocab)} + self.normalize = normalize + + def formula_to_counts(self, formula_str: str) -> Dict[str, int]: + """Parse a molecular formula string into a dictionary of atom counts. + + >>> FormulaEncoder().formula_to_counts("C9H10N2O2") + {'C': 9, 'H': 10, 'N': 2, 'O': 2} + """ + if not formula_str: + return {} + counts: Dict[str, int] = {} + for element, count in self._FORMULA_PATTERN.findall(formula_str): + if element: + count_val = int(count) if count else 1 + counts[element] = counts.get(element, 0) + count_val + return counts + + def counts_to_vector( + self, counts: Dict[str, int], normalize: Optional[str] = None + ) -> torch.Tensor: + """Convert atom counts dictionary to a fixed-size vector. + + Args: + counts: Dictionary mapping atom symbols to counts. + normalize: Override normalization strategy. + + Returns: + Tensor of shape (30,) with counts for each atom type. + """ + normalize = normalize if normalize is not None else self.normalize + vector = torch.zeros(len(self.atom_vocab), dtype=torch.float32) + for atom, count in counts.items(): + idx = self.atom_to_idx.get(atom) + if idx is not None: + vector[idx] = float(count) + + if normalize == 'sum': + total = vector.sum() + if total > 0: + vector = vector / total + elif normalize == 'max': + max_val = vector.max() + if max_val > 0: + vector = vector / max_val + elif normalize == 'log': + vector = torch.log(vector + 1.0) + elif normalize != 'none': + raise ValueError(f"Unknown normalization strategy: {normalize}") + + return vector + + def encode(self, formula_str: str, normalize: Optional[str] = None) -> torch.Tensor: + """Encode a molecular formula string into a fixed-size vector. + + Args: + formula_str: Molecular formula string (e.g., "C9H10N2O2"). + normalize: Override normalization strategy. + + Returns: + Tensor of shape (30,). + """ + if not formula_str: + return torch.zeros(len(self.atom_vocab), dtype=torch.float32) + try: + counts = self.formula_to_counts(formula_str) + return self.counts_to_vector(counts, normalize) + except Exception: + return torch.zeros(len(self.atom_vocab), dtype=torch.float32) + + def encode_batch( + self, formulas: List[str], normalize: Optional[str] = None + ) -> torch.Tensor: + """Encode a batch of molecular formulas. + + Returns: + Tensor of shape (batch_size, 30). + """ + return torch.stack([self.encode(f, normalize) for f in formulas]) + + @property + def vocab_size(self) -> int: + """Dimensionality of output vectors (30).""" + return len(self.atom_vocab) + + def decode(self, vector: torch.Tensor, threshold: float = 0.5) -> str: + """Decode a vector back into an approximate molecular formula string.""" + parts = [] + for idx, count in enumerate(vector.tolist()): + if count > threshold: + atom = self.atom_vocab[idx] + count_int = round(count) + if count_int > 1: + parts.append(f"{atom}{count_int}") + elif count_int == 1: + parts.append(atom) + return ''.join(parts) diff --git a/massspecgym/models/de_novo/fp2mol/frigid/__init__.py b/massspecgym/models/de_novo/fp2mol/frigid/__init__.py new file mode 100644 index 0000000..ec0ccaa --- /dev/null +++ b/massspecgym/models/de_novo/fp2mol/frigid/__init__.py @@ -0,0 +1,15 @@ +""" +FRIGID decoder: Fragment Refinement via ICEBERG-Guided Inference Diffusion. + +A Masked Diffusion Language Model (MDLM) that generates SAFE molecular sequences +conditioned on fingerprints and chemical formulas via cross-attention. + +Requires: ``pip install transformers`` (for BERT backbone). +""" + + +def __getattr__(name): + if name == "FRIGIDDecoder": + from .model import FRIGIDDecoder + return FRIGIDDecoder + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/massspecgym/models/de_novo/fp2mol/frigid/bert_cross_attention.py b/massspecgym/models/de_novo/fp2mol/frigid/bert_cross_attention.py new file mode 100644 index 0000000..2d00efb --- /dev/null +++ b/massspecgym/models/de_novo/fp2mol/frigid/bert_cross_attention.py @@ -0,0 +1,231 @@ +""" +BERT encoder with cross-attention layers for FRIGID conditioning. + +Extends the HuggingFace BertForMaskedLM with cross-attention sublayers in each +transformer block, allowing formula and fingerprint conditioning embeddings +to be injected via cross-attention at every layer. + +Matches the reference implementation from external/genms/src/genmol/bert_with_cross_attention.py +exactly in structure: BertLayerWithCrossAttention wraps BertLayer and adds +cross-attention after self-attention + FFN. + +Supports two modes: +- Shared cross-attention: formula + fingerprint concatenated into single conditioning. +- Independent cross-attention: separate cross-attention paths for each modality. +""" + +from typing import Optional + +import torch +import torch.nn as nn +from transformers.models.bert.modeling_bert import ( + BertLayer, + BertPreTrainedModel, + BertForMaskedLM, + BertEmbeddings, + BertPooler, +) +from transformers.models.bert.configuration_bert import BertConfig + + +class BertLayerWithCrossAttention(nn.Module): + """BERT layer extended with optional cross-attention over conditioning tokens. + + Performs: + 1. Standard self-attention + FFN (via wrapped BertLayer) + 2. Cross-attention to formula conditioning sequence (if provided) + 3. Cross-attention to fingerprint conditioning sequence (if provided) + """ + + def __init__(self, config, cross_attention_layer=None, + fingerprint_cross_attention_layer=None): + super().__init__() + self.bert_layer = BertLayer(config) + self.cross_attention = cross_attention_layer + self.has_cross_attention = cross_attention_layer is not None + self.fingerprint_cross_attention = fingerprint_cross_attention_layer + self.has_fingerprint_cross_attention = fingerprint_cross_attention_layer is not None + + def forward( + self, + hidden_states, + attention_mask=None, + head_mask=None, + encoder_hidden_states=None, + encoder_attention_mask=None, + past_key_value=None, + output_attentions=False, + condition_embeddings=None, + condition_mask=None, + fingerprint_embeddings=None, + fingerprint_mask=None, + ): + layer_outputs = self.bert_layer( + hidden_states, + attention_mask=attention_mask, + head_mask=head_mask, + encoder_hidden_states=encoder_hidden_states, + encoder_attention_mask=encoder_attention_mask, + past_key_value=past_key_value, + output_attentions=output_attentions, + ) + hidden_states = layer_outputs[0] + + if self.has_cross_attention and condition_embeddings is not None: + hidden_states = self.cross_attention( + hidden_states=hidden_states, + condition_embeddings=condition_embeddings, + condition_mask=condition_mask, + ) + + if self.has_fingerprint_cross_attention and fingerprint_embeddings is not None: + hidden_states = self.fingerprint_cross_attention( + hidden_states=hidden_states, + condition_embeddings=fingerprint_embeddings, + condition_mask=fingerprint_mask, + ) + + return (hidden_states,) + layer_outputs[1:] + + +class BertEncoderWithCrossAttention(nn.Module): + """BERT encoder with per-layer cross-attention for conditioning sequences.""" + + def __init__(self, config, cross_attention_layers=None, + fingerprint_cross_attention_layers=None): + super().__init__() + self.config = config + self.layer = nn.ModuleList() + for i in range(config.num_hidden_layers): + cross_attn = cross_attention_layers[i] if cross_attention_layers else None + fp_cross_attn = fingerprint_cross_attention_layers[i] if fingerprint_cross_attention_layers else None + self.layer.append( + BertLayerWithCrossAttention( + config, + cross_attention_layer=cross_attn, + fingerprint_cross_attention_layer=fp_cross_attn, + ) + ) + self.gradient_checkpointing = False + + def forward( + self, + hidden_states, + attention_mask=None, + head_mask=None, + encoder_hidden_states=None, + encoder_attention_mask=None, + past_key_values=None, + use_cache=None, + output_attentions=False, + output_hidden_states=False, + return_dict=True, + condition_embeddings=None, + condition_mask=None, + fingerprint_embeddings=None, + fingerprint_mask=None, + ): + all_hidden_states = () if output_hidden_states else None + all_self_attentions = () if output_attentions else None + + for i, layer_module in enumerate(self.layer): + if output_hidden_states: + all_hidden_states = all_hidden_states + (hidden_states,) + + layer_head_mask = head_mask[i] if head_mask is not None else None + past_key_value = past_key_values[i] if past_key_values is not None else None + + layer_outputs = layer_module( + hidden_states, + attention_mask=attention_mask, + head_mask=layer_head_mask, + encoder_hidden_states=encoder_hidden_states, + encoder_attention_mask=encoder_attention_mask, + past_key_value=past_key_value, + output_attentions=output_attentions, + condition_embeddings=condition_embeddings, + condition_mask=condition_mask, + fingerprint_embeddings=fingerprint_embeddings, + fingerprint_mask=fingerprint_mask, + ) + hidden_states = layer_outputs[0] + + if output_attentions: + all_self_attentions = all_self_attentions + (layer_outputs[1],) + + if output_hidden_states: + all_hidden_states = all_hidden_states + (hidden_states,) + + return tuple(v for v in [hidden_states, None, all_hidden_states, + all_self_attentions] if v is not None) + + +class BertModelWithCrossAttention(BertPreTrainedModel): + """BERT model with cross-attention for conditioning, drop-in replacement for BertModel.""" + + def __init__(self, config, add_pooling_layer=True, cross_attention_layers=None, + fingerprint_cross_attention_layers=None, use_shared_cross_attention=False): + super().__init__(config) + self.config = config + self.use_shared_cross_attention = use_shared_cross_attention + + self.embeddings = BertEmbeddings(config) + + if use_shared_cross_attention: + fingerprint_cross_attention_layers = None + + self.encoder = BertEncoderWithCrossAttention( + config, cross_attention_layers, fingerprint_cross_attention_layers + ) + self.pooler = BertPooler(config) if add_pooling_layer else None + self.post_init() + + def get_input_embeddings(self): + return self.embeddings.word_embeddings + + def set_input_embeddings(self, value): + self.embeddings.word_embeddings = value + + def get_extended_attention_mask(self, attention_mask, input_shape, device=None): + return super().get_extended_attention_mask(attention_mask, input_shape, device) + + +class BertForMaskedLMWithCrossAttention(nn.Module): + """BertForMaskedLM extended with cross-attention conditioning. + + Wraps BertModelWithCrossAttention + BertOnlyMLMHead (cls) for + masked language modeling with formula/fingerprint conditioning. + """ + + def __init__( + self, + config: BertConfig, + cross_attention_layers: Optional[nn.ModuleList] = None, + fingerprint_cross_attention_layers: Optional[nn.ModuleList] = None, + use_shared_cross_attention: bool = True, + ): + super().__init__() + + self.bert = BertModelWithCrossAttention( + config, + add_pooling_layer=False, + cross_attention_layers=cross_attention_layers, + fingerprint_cross_attention_layers=fingerprint_cross_attention_layers, + use_shared_cross_attention=use_shared_cross_attention, + ) + + # Reuse the MLM head from standard BertForMaskedLM + _tmp = BertForMaskedLM(config) + self.cls = _tmp.cls + del _tmp + + @property + def embeddings(self): + return self.bert.embeddings + + def get_extended_attention_mask(self, attention_mask, input_shape, device=None): + return self.bert.get_extended_attention_mask(attention_mask, input_shape, device) + + def parameters(self, recurse=True): + yield from self.bert.parameters(recurse) + yield from self.cls.parameters(recurse) diff --git a/massspecgym/models/de_novo/fp2mol/frigid/components.py b/massspecgym/models/de_novo/fp2mol/frigid/components.py new file mode 100644 index 0000000..0ceae1d --- /dev/null +++ b/massspecgym/models/de_novo/fp2mol/frigid/components.py @@ -0,0 +1,336 @@ +""" +Conditioning components for the FRIGID decoder. + +Contains formula and fingerprint conditioners that produce embeddings for +cross-attention injection into the BERT backbone, matching the FRIGID paper. +""" + +import math + +import torch +import torch.nn as nn + + +class FormulaSequenceEncoder(nn.Module): + """Encodes molecular formula as a fixed-length sequence of atom embeddings. + + Each position represents an atom type (C, H, N, O, ...) with its count, + creating a 30-length sequence for cross-attention with SAFE tokens. + + Args: + num_atom_types: Number of atom types in the vocabulary (30). + embedding_dim: Dimension of output embeddings (matches BERT hidden_size). + max_count: Maximum count value for count embeddings. + use_count_embedding: If True, use separate learnable count embeddings. + """ + + def __init__( + self, + num_atom_types: int = 30, + embedding_dim: int = 768, + max_count: int = 200, + use_count_embedding: bool = True, + ): + super().__init__() + self.num_atom_types = num_atom_types + self.embedding_dim = embedding_dim + self.use_count_embedding = use_count_embedding + + self.atom_embeddings = nn.Embedding(num_atom_types, embedding_dim) + if use_count_embedding: + self.count_embeddings = nn.Embedding(max_count + 1, embedding_dim) + self.position_embeddings = nn.Embedding(num_atom_types, embedding_dim) + self.layer_norm = nn.LayerNorm(embedding_dim) + + self._init_weights() + + def _init_weights(self): + nn.init.normal_(self.atom_embeddings.weight, mean=0.0, std=0.02) + if self.use_count_embedding: + nn.init.normal_(self.count_embeddings.weight, mean=0.0, std=0.02) + nn.init.normal_(self.position_embeddings.weight, mean=0.0, std=0.02) + + def forward(self, formula_vectors: torch.Tensor): + """Encode formula vectors as a sequence of embeddings. + + Args: + formula_vectors: Tensor [batch_size, num_atom_types] with counts. + + Returns: + Tuple of (embeddings [B, 30, D], mask [B, 30]). + """ + batch_size = formula_vectors.shape[0] + device = formula_vectors.device + + atom_indices = torch.arange(self.num_atom_types, device=device) + atom_indices = atom_indices.unsqueeze(0).expand(batch_size, -1) + + atom_emb = self.atom_embeddings(atom_indices) + + if self.use_count_embedding: + counts_clipped = formula_vectors.clamp(0, 200).long() + count_emb = self.count_embeddings(counts_clipped) + else: + count_emb = formula_vectors.unsqueeze(-1) * atom_emb + + pos_emb = self.position_embeddings(atom_indices) + embeddings = self.layer_norm(atom_emb + count_emb + pos_emb) + mask = (formula_vectors > 0).float() + + return embeddings, mask + + +class SetSelfAttention(nn.Module): + """Permutation-equivariant self-attention for unordered sets. + + No positional encoding - treats input as an unordered set of elements. + Used by FingerprintSequenceEncoder to learn combinatorial relationships + among active fingerprint bits. + """ + + def __init__(self, hidden_size: int = 768, num_attention_heads: int = 12, dropout: float = 0.1): + super().__init__() + self.num_attention_heads = num_attention_heads + self.attention_head_size = hidden_size // num_attention_heads + self.all_head_size = self.num_attention_heads * self.attention_head_size + + self.query = nn.Linear(hidden_size, self.all_head_size) + self.key = nn.Linear(hidden_size, self.all_head_size) + self.value = nn.Linear(hidden_size, self.all_head_size) + self.output_dense = nn.Linear(hidden_size, hidden_size) + self.output_dropout = nn.Dropout(dropout) + self.output_layer_norm = nn.LayerNorm(hidden_size) + self.dropout = nn.Dropout(dropout) + + def _transpose_for_scores(self, x): + new_shape = x.size()[:-1] + (self.num_attention_heads, self.attention_head_size) + return x.view(*new_shape).permute(0, 2, 1, 3) + + def forward(self, hidden_states: torch.Tensor, mask: torch.Tensor = None): + q = self._transpose_for_scores(self.query(hidden_states)) + k = self._transpose_for_scores(self.key(hidden_states)) + v = self._transpose_for_scores(self.value(hidden_states)) + + scores = torch.matmul(q, k.transpose(-1, -2)) / math.sqrt(self.attention_head_size) + + if mask is not None: + ext_mask = (1.0 - mask.unsqueeze(1).unsqueeze(2)) * -10000.0 + scores = scores + ext_mask + + probs = self.dropout(torch.softmax(scores, dim=-1)) + context = torch.matmul(probs, v) + context = context.permute(0, 2, 1, 3).contiguous() + context = context.view(context.size()[:-2] + (self.all_head_size,)) + + output = self.output_dropout(self.output_dense(context)) + return self.output_layer_norm(hidden_states + output) + + +class FingerprintSequenceEncoder(nn.Module): + """Set-aware encoder for Morgan fingerprints. + + Treats fingerprint as an unordered set of active bits: + 1. Each bit index gets a learnable embedding (substructure semantics). + 2. No positional encoding (set has no order). + 3. Self-attention learns combinatorial relationships. + + Args: + num_bits: Number of fingerprint bits (4096). + embedding_dim: Embedding dimension. + max_seq_len: Maximum number of active bits to retain (256). + activation_threshold: Threshold for considering a bit active. + dropout: Dropout probability. + num_self_attention_layers: Number of self-attention layers (3). + num_attention_heads: Number of attention heads. + """ + + def __init__( + self, + num_bits: int = 4096, + embedding_dim: int = 768, + max_seq_len: int = 256, + activation_threshold: float = 0.0, + dropout: float = 0.1, + num_self_attention_layers: int = 2, + num_attention_heads: int = 12, + ): + super().__init__() + self.num_bits = num_bits + self.embedding_dim = embedding_dim + self.max_seq_len = max_seq_len + self.activation_threshold = activation_threshold + + self.bit_embeddings = nn.Embedding(num_bits, embedding_dim) + self.layer_norm = nn.LayerNorm(embedding_dim) + self.dropout = nn.Dropout(dropout) + self.self_attention_layers = nn.ModuleList([ + SetSelfAttention(hidden_size=embedding_dim, num_attention_heads=num_attention_heads, dropout=dropout) + for _ in range(num_self_attention_layers) + ]) + nn.init.normal_(self.bit_embeddings.weight, mean=0.0, std=0.02) + + def forward(self, fingerprint: torch.Tensor): + """Encode fingerprint as a set of active bit embeddings. + + Args: + fingerprint: Tensor [batch_size, num_bits] - binary or soft Morgan FP. + + Returns: + Tuple of (embeddings [B, L, D], mask [B, L]). + """ + if fingerprint.dim() == 1: + fingerprint = fingerprint.unsqueeze(0) + batch_size = fingerprint.shape[0] + device = fingerprint.device + + active_mask = fingerprint > self.activation_threshold + num_active = active_mask.sum(dim=1) + max_active = min(self.max_seq_len, max(int(num_active.max().item()), 1)) + + scores = active_mask.float() + if self.training: + scores = scores + torch.rand_like(scores) * 0.5 + + _, topk_indices = torch.topk(scores, k=max_active, dim=1, sorted=False) + + pos_indices = torch.arange(max_active, device=device).unsqueeze(0).expand(batch_size, -1) + mask = (pos_indices < num_active.unsqueeze(1)).float() + + no_active = num_active == 0 + if no_active.any(): + topk_indices[no_active, 0] = 0 + mask[no_active] = 0.0 + + embeddings = self.dropout(self.layer_norm(self.bit_embeddings(topk_indices))) + for self_attn in self.self_attention_layers: + embeddings = self_attn(embeddings, mask) + embeddings = embeddings * mask.unsqueeze(-1) + + return embeddings, mask + + +class CrossAttentionLayer(nn.Module): + """Cross-attention layer for conditioning SAFE tokens on formula/fingerprint. + + SAFE token representations (queries) attend to conditioning sequence + embeddings (keys/values) with residual connection and layer norm. + """ + + def __init__(self, hidden_size: int = 768, num_attention_heads: int = 12, dropout: float = 0.1): + super().__init__() + self.num_attention_heads = num_attention_heads + self.attention_head_size = hidden_size // num_attention_heads + self.all_head_size = self.num_attention_heads * self.attention_head_size + + self.query = nn.Linear(hidden_size, self.all_head_size) + self.key = nn.Linear(hidden_size, self.all_head_size) + self.value = nn.Linear(hidden_size, self.all_head_size) + self.output_dense = nn.Linear(hidden_size, hidden_size) + self.output_dropout = nn.Dropout(dropout) + self.output_layer_norm = nn.LayerNorm(hidden_size) + self.dropout = nn.Dropout(dropout) + + def _transpose_for_scores(self, x): + new_shape = x.size()[:-1] + (self.num_attention_heads, self.attention_head_size) + return x.view(*new_shape).permute(0, 2, 1, 3) + + def forward(self, hidden_states, condition_embeddings, condition_mask=None): + """Apply cross-attention. + + Args: + hidden_states: SAFE token hidden states [B, safe_len, H]. + condition_embeddings: Conditioning embeddings [B, cond_len, H]. + condition_mask: Mask for conditioning tokens [B, cond_len]. + + Returns: + Updated hidden states [B, safe_len, H]. + """ + q = self._transpose_for_scores(self.query(hidden_states)) + k = self._transpose_for_scores(self.key(condition_embeddings)) + v = self._transpose_for_scores(self.value(condition_embeddings)) + + scores = torch.matmul(q, k.transpose(-1, -2)) / math.sqrt(self.attention_head_size) + + if condition_mask is not None: + ext_mask = (1.0 - condition_mask.unsqueeze(1).unsqueeze(2)) * -10000.0 + scores = scores + ext_mask + + probs = self.dropout(torch.softmax(scores, dim=-1)) + context = torch.matmul(probs, v) + context = context.permute(0, 2, 1, 3).contiguous() + context = context.view(context.size()[:-2] + (self.all_head_size,)) + + output = self.output_dropout(self.output_dense(context)) + return self.output_layer_norm(hidden_states + output) + + +class CrossAttentionFormulaConditioner(nn.Module): + """Complete cross-attention formula conditioner. + + 1. Encodes formula as a 30-length sequence (one per atom type). + 2. Provides per-layer cross-attention layers for injection into BERT. + """ + + def __init__( + self, + num_atom_types: int = 30, + hidden_size: int = 768, + num_attention_heads: int = 12, + num_layers: int = 12, + dropout: float = 0.1, + use_count_embedding: bool = True, + ): + super().__init__() + self.formula_encoder = FormulaSequenceEncoder( + num_atom_types=num_atom_types, + embedding_dim=hidden_size, + use_count_embedding=use_count_embedding, + ) + self.cross_attention_layers = nn.ModuleList([ + CrossAttentionLayer(hidden_size, num_attention_heads, dropout) + for _ in range(num_layers) + ]) + + def encode_formula(self, formula_vectors): + return self.formula_encoder(formula_vectors) + + +class CrossAttentionFingerprintConditioner(nn.Module): + """Cross-attention conditioner for fingerprints using set-aware encoding. + + Uses FingerprintSequenceEncoder to produce set embeddings, optionally + with its own cross-attention layers (or sharing formula's layers). + """ + + def __init__( + self, + num_bits: int = 4096, + hidden_size: int = 768, + num_attention_heads: int = 12, + num_layers: int = 12, + max_seq_len: int = 256, + activation_threshold: float = 0.0, + dropout: float = 0.1, + num_self_attention_layers: int = 2, + create_cross_attention_layers: bool = True, + ): + super().__init__() + self.fingerprint_encoder = FingerprintSequenceEncoder( + num_bits=num_bits, + embedding_dim=hidden_size, + max_seq_len=max_seq_len, + activation_threshold=activation_threshold, + dropout=dropout, + num_self_attention_layers=num_self_attention_layers, + num_attention_heads=num_attention_heads, + ) + if create_cross_attention_layers: + self.cross_attention_layers = nn.ModuleList([ + CrossAttentionLayer(hidden_size, num_attention_heads, dropout) + for _ in range(num_layers) + ]) + else: + self.cross_attention_layers = None + + def encode_fingerprint(self, fingerprint_vectors): + return self.fingerprint_encoder(fingerprint_vectors) diff --git a/massspecgym/models/de_novo/fp2mol/frigid/mdlm.py b/massspecgym/models/de_novo/fp2mol/frigid/mdlm.py new file mode 100644 index 0000000..fafc08a --- /dev/null +++ b/massspecgym/models/de_novo/fp2mol/frigid/mdlm.py @@ -0,0 +1,246 @@ +""" +Self-contained Masked Diffusion Language Model (MDLM) implementation. + +Replaces the bionemo.moco dependency with a standalone ~200 line implementation +matching the MDLM formulation from Sahoo et al. 2024 and FRIGID's usage. + +Key operations: +- Log-linear exponential noise schedule: alpha(t) = exp((1-t)*log(alpha_max) + t*log(alpha_min)) +- Forward process: independently mask each token with probability 1 - alpha(t) +- Loss: masked-token NLL weighted by -alpha'(t)/alpha(t) +- Confidence-based sampling: unmask most confident positions iteratively +""" + +import math + +import torch +import torch.nn.functional as F + + +class LogLinearExpNoiseSchedule: + """Log-linear exponential noise schedule for MDLM. + + alpha(t) = exp((1 - t) * log(alpha_max) + t * log(alpha_min)) + sigma(t) = -log(alpha(t)) + + At t=0: alpha = alpha_max (no masking), at t=1: alpha = alpha_min (nearly all masked). + """ + + def __init__(self, alpha_max: float = 1.0, alpha_min: float = 1e-3): + self.log_alpha_max = math.log(alpha_max) + self.log_alpha_min = math.log(alpha_min) + + def alpha(self, t: torch.Tensor) -> torch.Tensor: + """Compute alpha(t) for given time values.""" + log_alpha = (1 - t) * self.log_alpha_max + t * self.log_alpha_min + return torch.exp(log_alpha) + + def sigma(self, t: torch.Tensor) -> torch.Tensor: + """Compute sigma(t) = -log(alpha(t)).""" + return -((1 - t) * self.log_alpha_max + t * self.log_alpha_min) + + def d_sigma_dt(self, t: torch.Tensor) -> torch.Tensor: + """Compute d/dt sigma(t) = log(alpha_max) - log(alpha_min). + + For default alpha_max=1: d_sigma/dt = -log(alpha_min) > 0. + """ + return torch.full_like(t, self.log_alpha_max - self.log_alpha_min) + + def loss_weight(self, t: torch.Tensor) -> torch.Tensor: + """Compute the continuous-time NELBO weight: d_sigma/dt / (exp(sigma) - 1). + + This is the correct importance weight from Sahoo et al. 2024 (Eq. 11) + for the MDLM continuous-time NELBO, matching bionemo's implementation. + """ + sig = self.sigma(t) + dsig = self.d_sigma_dt(t) + return dsig / torch.expm1(sig).clamp(min=1e-8) + + +class MDLM: + """Masked Diffusion Language Model. + + Implements the forward masking process, ELBO loss computation, and + confidence-based iterative unmasking for generation. + + Args: + mask_token_id: Token ID used for [MASK]. + vocab_size: Size of the token vocabulary. + noise_schedule: Noise schedule instance. + sampling_eps: Minimum time value to avoid numerical issues. + """ + + def __init__( + self, + mask_token_id: int, + vocab_size: int, + noise_schedule: LogLinearExpNoiseSchedule = None, + sampling_eps: float = 1e-3, + ): + self.mask_token_id = mask_token_id + self.vocab_size = vocab_size + self.noise_schedule = noise_schedule or LogLinearExpNoiseSchedule() + self.sampling_eps = sampling_eps + self._device = torch.device("cpu") + + def to_device(self, device): + self._device = device + + def sample_time(self, batch_size: int, antithetic: bool = True) -> torch.Tensor: + """Sample diffusion time t ~ U(eps, 1). + + With antithetic sampling, pairs (t, 1-t+eps) are used for variance reduction. + """ + if antithetic and batch_size % 2 == 0: + half = batch_size // 2 + t = torch.rand(half, device=self._device) * (1 - self.sampling_eps) + self.sampling_eps + t = torch.cat([t, 1 - t + self.sampling_eps], dim=0) + else: + t = torch.rand(batch_size, device=self._device) * (1 - self.sampling_eps) + self.sampling_eps + return t + + def forward_process(self, x0: torch.Tensor, t: torch.Tensor) -> torch.Tensor: + """Apply forward masking process. + + Each token is independently replaced with [MASK] with probability 1 - alpha(t). + + Args: + x0: Clean token IDs [batch, seq_len]. + t: Time values [batch]. + + Returns: + Noisy token IDs with some tokens replaced by mask_token_id. + """ + alpha_t = self.noise_schedule.alpha(t) # [batch] + keep_prob = alpha_t[:, None] # [batch, 1] + mask = torch.rand_like(x0.float()) > keep_prob # True = mask this token + xt = x0.clone() + xt[mask] = self.mask_token_id + return xt + + def loss( + self, + logits: torch.Tensor, + x0: torch.Tensor, + xt: torch.Tensor, + t: torch.Tensor, + mask: torch.Tensor = None, + global_mean: bool = True, + ) -> torch.Tensor: + """Compute MDLM training loss (continuous-time NELBO). + + Matches bionemo.moco MDLM.loss(use_weight=True) exactly: + - Uses substitution parameterization implicitly: loss only at masked positions. + - Weight: d_sigma/dt / (exp(sigma) - 1), the correct continuous-time NELBO weight + from Sahoo et al. 2024 (Eq. 11) / https://arxiv.org/pdf/2406.07524. + + Args: + logits: Model output [batch, seq_len, vocab_size]. + x0: Clean token IDs [batch, seq_len]. + xt: Noisy token IDs [batch, seq_len]. + t: Time values [batch]. + mask: Attention mask [batch, seq_len] (1=valid, 0=padding). + global_mean: If True, sum all token losses and divide by total token count + (matching bionemo's global_mean=True behavior). + + Returns: + Loss tensor (scalar if global_mean, else per-sample [batch]). + """ + log_probs = F.log_softmax(logits, dim=-1) # [batch, seq_len, vocab_size] + nll = F.nll_loss( + log_probs.view(-1, self.vocab_size), + x0.view(-1), + reduction="none", + ).view_as(x0) # [batch, seq_len] + + # Subs parameterization: only count loss at masked positions. + # Non-masked positions would have log_p=0 under subs param, so zeroing + # them out here is equivalent to bionemo's _subs_parameterization. + is_masked = xt == self.mask_token_id + nll = nll * is_masked.float() + + # Apply mask for padding + if mask is not None: + nll = nll * mask.float() + + # Continuous-time NELBO weight: d_sigma/dt / (exp(sigma) - 1) + weight = self.noise_schedule.loss_weight(t) # [batch] + + # Weight each sample's token NLL sum + weighted_nll = nll.sum(dim=1) * weight # [batch] + + if global_mean: + if mask is not None: + total_tokens = mask.float().sum() + else: + total_tokens = float(x0.numel()) + total_tokens = max(total_tokens, 1.0) + return weighted_nll.sum() / total_tokens + else: + if mask is not None: + num_tokens = mask.float().sum(dim=1).clamp(min=1) + else: + num_tokens = float(x0.size(1)) + return weighted_nll / num_tokens + + def get_num_steps_confidence(self, x: torch.Tensor) -> int: + """Get number of unmasking steps = number of [MASK] tokens in x.""" + return (x == self.mask_token_id).sum(dim=-1).max().item() + + @torch.no_grad() + def step_confidence( + self, + logits: torch.Tensor, + x: torch.Tensor, + step_idx: int, + num_steps: int, + temperature: float = 1.0, + randomness: float = 1.0, + ) -> torch.Tensor: + """One confidence-based unmasking step, matching bionemo MDLM exactly. + + 1. Apply subs parameterization (copy non-masked tokens). + 2. Sample provisional tokens from softmax(logits / temperature). + 3. Gather per-token confidence = p(sampled_token). + 4. Perturb confidence with annealed Gumbel noise: (log(conf) + noise) / 1.0. + 5. Unmask the most confident position; keep others masked. + + Args: + logits: Model logits [batch, seq_len, vocab_size]. + x: Current token IDs with masks [batch, seq_len]. + step_idx: Current step index (0-based). + num_steps: Total number of steps. + temperature: Softmax temperature for logits. + randomness: Gumbel noise scale (annealed linearly over steps). + + Returns: + Updated token IDs with one fewer mask per batch element. + """ + x_new = x.clone() + + probs = F.softmax(logits / max(temperature, 1e-8), dim=-1) + preds = torch.distributions.Categorical(probs=probs).sample() # [batch, seq_len] + + # Confidence = probability of the sampled token + confidence = probs.gather(-1, preds.unsqueeze(-1)).squeeze(-1) # [batch, seq_len] + + # Annealed Gumbel noise (decreases linearly from randomness to 0) + ratio = step_idx / max(num_steps - 1, 1) + gumbel_noise = -torch.log(-torch.log( + torch.rand_like(confidence, device=logits.device) + )) + gumbel_noise = gumbel_noise * randomness * (1 - ratio) + + # Log-confidence + Gumbel (matching bionemo: log(conf) + noise) + confidence = torch.log(confidence.clamp(min=1e-8)) + gumbel_noise + + # Only consider masked positions + is_masked = x == self.mask_token_id + confidence[~is_masked] = -float("inf") + + # Unmask the single most confident position per batch element + best_pos = confidence.argmax(dim=-1) # [batch] + batch_idx = torch.arange(x.size(0), device=x.device) + x_new[batch_idx, best_pos] = preds[batch_idx, best_pos] + + return x_new diff --git a/massspecgym/models/de_novo/fp2mol/frigid/model.py b/massspecgym/models/de_novo/fp2mol/frigid/model.py new file mode 100644 index 0000000..a103dd9 --- /dev/null +++ b/massspecgym/models/de_novo/fp2mol/frigid/model.py @@ -0,0 +1,404 @@ +""" +FRIGID decoder: Masked Diffusion Language Model for fingerprint-to-molecule generation. + +Implements the FRIGID-base architecture: a BERT backbone with cross-attention +conditioning on chemical formula and molecular fingerprint, trained with MDLM +(Masked Diffusion Language Model) objective over SAFE token sequences. + +Key architectural details (matching FRIGID paper): +- BERT backbone: 12 layers, hidden 768, 12 heads, FFN 3072, vocab ~1880 SAFE BPE +- Formula conditioning: 30-element sequence with atom+count+position embeddings +- Fingerprint conditioning: active-bit set (max 256) with 3 self-attention layers +- Shared cross-attention: formula + FP concatenated for joint conditioning +- Training: MDLM loss + optional differentiable formula loss +""" + +import random +from typing import Optional, List, Tuple + +import torch +import torch.nn as nn +import torch.nn.functional as F +from transformers import AutoTokenizer, BertForMaskedLM +from transformers.models.bert.configuration_bert import BertConfig + +from massspecgym.models.base import Stage +from massspecgym.models.de_novo.fp2mol.base import FP2MolDeNovoModel +from massspecgym.models.de_novo.fp2mol.formula_utils import FormulaEncoder +from .mdlm import MDLM, LogLinearExpNoiseSchedule +from .components import ( + CrossAttentionFormulaConditioner, + CrossAttentionFingerprintConditioner, +) +from .bert_cross_attention import BertForMaskedLMWithCrossAttention + + +def _safe_to_smiles(safe_string: str) -> Optional[str]: + """Convert SAFE string to SMILES, returning None on failure.""" + try: + from safe import decode as safe_decode + smiles = safe_decode(safe_string) + if smiles: + return smiles + except Exception: + pass + try: + smi = safe_string.replace(".", "") + from rdkit import Chem + mol = Chem.MolFromSmiles(smi) + if mol is not None: + return Chem.MolToSmiles(mol) + except Exception: + pass + return None + + +class FRIGIDDecoder(FP2MolDeNovoModel): + """FRIGID Masked Diffusion Language Model decoder. + + Generates SAFE molecular sequences conditioned on Morgan fingerprints + and chemical formulas using iterative confidence-based unmasking. + + Args: + hidden_size: BERT hidden dimension. + num_hidden_layers: Number of BERT layers. + num_attention_heads: Number of attention heads. + intermediate_size: BERT FFN intermediate dimension. + max_position_embeddings: Maximum sequence length. + vocab_size: SAFE BPE vocabulary size. + tokenizer_name: HuggingFace tokenizer name. + fingerprint_bits: Number of fingerprint bits. + fingerprint_seq_max_len: Maximum fingerprint sequence length. + fingerprint_activation_threshold: Threshold for active bits. + fingerprint_num_self_attention_layers: Self-attention layers in FP encoder. + use_formula_conditioning: Whether to use formula cross-attention. + use_fingerprint_conditioning: Whether to use fingerprint cross-attention. + use_shared_cross_attention: Whether to concatenate formula+FP for shared cross-attn. + formula_dropout_prob: Probability of dropping formula conditioning during training. + fingerprint_dropout_prob: Probability of dropping FP conditioning during training. + antithetic_sampling: Use antithetic time sampling in MDLM. + formula_loss_weight: Weight for differentiable formula matching loss. + softmax_temp: Sampling temperature. + randomness: Gumbel noise scale for confidence sampling. + ema_decay: EMA decay rate (0 to disable). + """ + + def __init__( + self, + hidden_size: int = 768, + num_hidden_layers: int = 12, + num_attention_heads: int = 12, + intermediate_size: int = 3072, + max_position_embeddings: int = 256, + vocab_size: int = 1880, + tokenizer_name: str = "datamol-io/safe-gpt", + fingerprint_bits: int = 4096, + fingerprint_seq_max_len: int = 256, + fingerprint_activation_threshold: float = 0.0, + fingerprint_num_self_attention_layers: int = 3, + use_formula_conditioning: bool = True, + use_fingerprint_conditioning: bool = True, + use_shared_cross_attention: bool = True, + formula_dropout_prob: float = 0.0, + fingerprint_dropout_prob: float = 0.25, + antithetic_sampling: bool = True, + formula_loss_weight: float = 0.0, + softmax_temp: float = 0.8, + randomness: float = 0.5, + ema_decay: float = 0.0, + *args, + **kwargs, + ): + super().__init__(fingerprint_bits=fingerprint_bits, *args, **kwargs) + + self.hidden_size = hidden_size + self.use_formula_conditioning = use_formula_conditioning + self.use_fingerprint_conditioning = use_fingerprint_conditioning + self.use_shared_cross_attention = use_shared_cross_attention + self.formula_dropout_prob = formula_dropout_prob + self.fingerprint_dropout_prob = fingerprint_dropout_prob + self.antithetic_sampling = antithetic_sampling + self.formula_loss_weight = formula_loss_weight + self.softmax_temp = softmax_temp + self.randomness = randomness + + self.tokenizer = AutoTokenizer.from_pretrained(tokenizer_name, trust_remote_code=True) + actual_vocab_size = self.tokenizer.vocab_size + self.mask_index = self.tokenizer.mask_token_id + self.bos_index = self.tokenizer.bos_token_id + self.eos_index = self.tokenizer.eos_token_id + self.pad_index = self.tokenizer.pad_token_id + + self.formula_encoder = FormulaEncoder(normalize="none") + + if self.use_formula_conditioning: + self.formula_conditioner = CrossAttentionFormulaConditioner( + num_atom_types=self.formula_encoder.vocab_size, + hidden_size=hidden_size, + num_attention_heads=num_attention_heads, + num_layers=num_hidden_layers, + dropout=0.1, + use_count_embedding=True, + ) + + if self.use_fingerprint_conditioning: + create_fp_cross_attn = not use_shared_cross_attention + self.fingerprint_conditioner = CrossAttentionFingerprintConditioner( + num_bits=fingerprint_bits, + hidden_size=hidden_size, + num_attention_heads=num_attention_heads, + num_layers=num_hidden_layers, + max_seq_len=fingerprint_seq_max_len, + activation_threshold=fingerprint_activation_threshold, + dropout=0.1, + num_self_attention_layers=fingerprint_num_self_attention_layers, + create_cross_attention_layers=create_fp_cross_attn, + ) + + bert_config = BertConfig( + vocab_size=actual_vocab_size, + hidden_size=hidden_size, + num_hidden_layers=num_hidden_layers, + num_attention_heads=num_attention_heads, + intermediate_size=intermediate_size, + max_position_embeddings=max_position_embeddings, + hidden_dropout_prob=0.1, + attention_probs_dropout_prob=0.1, + ) + + formula_ca = self.formula_conditioner.cross_attention_layers if self.use_formula_conditioning else None + fp_ca = None + if self.use_fingerprint_conditioning and not use_shared_cross_attention: + fp_ca = self.fingerprint_conditioner.cross_attention_layers + + self.backbone = BertForMaskedLMWithCrossAttention( + bert_config, + cross_attention_layers=formula_ca, + fingerprint_cross_attention_layers=fp_ca, + use_shared_cross_attention=use_shared_cross_attention, + ) + + self.mdlm = MDLM( + mask_token_id=self.mask_index, + vocab_size=actual_vocab_size, + noise_schedule=LogLinearExpNoiseSchedule(), + sampling_eps=1e-3, + ) + + self.max_position_embeddings = max_position_embeddings + + def _build_token_embeddings(self, x): + emb = self.backbone.embeddings + token_emb = emb.word_embeddings(x) + pos_ids = torch.arange(x.size(1), device=x.device).unsqueeze(0).expand_as(x) + pos_emb = emb.position_embeddings(pos_ids) + type_emb = emb.token_type_embeddings(torch.zeros_like(x)) + return token_emb + pos_emb + type_emb + + def _prepare_formula_embeddings(self, formula, x): + if not self.use_formula_conditioning: + return None, None + if formula is not None: + fv = self.formula_encoder.encode_batch(formula).to(x.device) + else: + fv = self.formula_encoder.encode_batch(["C"] * x.size(0)).to(x.device) + return fv.new_zeros(x.size(0), self.formula_encoder.vocab_size, self.hidden_size), \ + fv.new_zeros(x.size(0), self.formula_encoder.vocab_size) + emb, mask = self.formula_conditioner.encode_formula(fv) + if self.training and formula is not None and random.random() < self.formula_dropout_prob: + emb = emb * 0.0 + return emb, mask + + def _prepare_fingerprint_embeddings(self, fingerprint, x): + if not self.use_fingerprint_conditioning: + return None, None + if fingerprint is None: + return None, None + fp = fingerprint.to(device=x.device, dtype=torch.float32) + if fp.dim() == 1: + fp = fp.unsqueeze(0) + if fp.size(0) == 1 and x.size(0) > 1: + fp = fp.expand(x.size(0), -1) + emb, mask = self.fingerprint_conditioner.encode_fingerprint(fp) + if self.training and random.random() < self.fingerprint_dropout_prob: + emb = emb * 0.0 + return emb, mask + + def forward_model(self, x, attention_mask=None, formula=None, fingerprint=None): + """Forward pass through BERT backbone with conditioning. + + Matches the reference GenMol.forward() exactly: + 1. Build token + position + type embeddings. + 2. Apply LayerNorm + dropout. + 3. Compute extended attention mask. + 4. In shared mode: concatenate formula + FP embeddings for single cross-attn path. + In independent mode: pass them separately. + 5. Run encoder layers (self-attn -> cross-attn -> FFN per layer). + 6. Apply MLM head (cls) to get logits. + + Returns logits [batch, seq_len, vocab_size]. + """ + with torch.amp.autocast("cuda", dtype=torch.float32): + formula_emb, formula_mask = self._prepare_formula_embeddings(formula, x) + fp_emb, fp_mask = self._prepare_fingerprint_embeddings(fingerprint, x) + + embeddings = self._build_token_embeddings(x) + embeddings = self.backbone.embeddings.LayerNorm(embeddings) + embeddings = self.backbone.embeddings.dropout(embeddings) + + if attention_mask is None: + attention_mask = torch.ones_like(x) + ext_attn = self.backbone.get_extended_attention_mask( + attention_mask, x.shape, x.device + ) + + if self.use_shared_cross_attention: + cond_emb = formula_emb + cond_mask = formula_mask + if fp_emb is not None: + if cond_emb is None: + cond_emb, cond_mask = fp_emb, fp_mask + else: + cond_emb = torch.cat([cond_emb, fp_emb], dim=1) + cond_mask = torch.cat([cond_mask, fp_mask], dim=1) + enc_out = self.backbone.bert.encoder( + embeddings, attention_mask=ext_attn, + condition_embeddings=cond_emb, condition_mask=cond_mask, + ) + else: + enc_out = self.backbone.bert.encoder( + embeddings, attention_mask=ext_attn, + condition_embeddings=formula_emb, condition_mask=formula_mask, + fingerprint_embeddings=fp_emb, fingerprint_mask=fp_mask, + ) + + sequence_output = enc_out[0] + return self.backbone.cls(sequence_output) + + def compute_decoder_loss(self, batch: dict) -> torch.Tensor: + """Compute MDLM training loss from a batch. + + In fp2mol_pretrain mode, batch contains: fingerprint, formula, mol_repr. + In spec2mol mode, batch contains spectrum data + mol. + """ + fingerprint = batch.get("fingerprint", None) + formula = batch.get("formula", None) + mol_repr = batch.get("mol_repr", batch.get("mol", None)) + + if isinstance(mol_repr, (list, tuple)): + encoded = self.tokenizer( + list(mol_repr), return_tensors="pt", padding=True, + truncation=True, max_length=self.max_position_embeddings, + ) + input_ids = encoded["input_ids"].to(self.device) + attention_mask = encoded["attention_mask"].to(self.device) + else: + input_ids = mol_repr + attention_mask = (mol_repr != self.pad_index).long() + + self.mdlm.to_device(self.device) + t = self.mdlm.sample_time(input_ids.shape[0], antithetic=self.antithetic_sampling) + t = t.to(self.device) + xt = self.mdlm.forward_process(input_ids, t) + + logits = self.forward_model(xt, attention_mask, formula=formula, fingerprint=fingerprint) + loss = self.mdlm.loss(logits, input_ids, xt, t, mask=attention_mask, global_mean=True) + + if self.formula_loss_weight > 0 and formula is not None: + gt_fv = self.formula_encoder.encode_batch(formula, normalize="none").to(self.device) + probs = torch.softmax(logits, dim=-1) + token_atom_counts = self._get_token_atom_counts() + expected = torch.matmul(probs, token_atom_counts) + if attention_mask is not None: + expected = expected * attention_mask.unsqueeze(-1) + predicted = expected.sum(dim=1) + f_loss = F.mse_loss(predicted, gt_fv) + loss = loss + self.formula_loss_weight * f_loss + + return loss + + def _get_token_atom_counts(self): + if not hasattr(self, "_token_atom_counts_buf"): + n_atoms = self.formula_encoder.vocab_size + v_size = self.tokenizer.vocab_size + buf = torch.zeros(v_size, n_atoms, dtype=torch.float32, device=self.device) + for tid in range(v_size): + tok_str = self.tokenizer.decode([tid]) + try: + counts = self.formula_encoder.formula_to_counts(tok_str) + vec = self.formula_encoder.counts_to_vector(counts, normalize="none") + buf[tid] = vec.to(self.device) + except Exception: + pass + self._token_atom_counts_buf = buf + return self._token_atom_counts_buf + + @torch.no_grad() + def decode_from_fingerprint( + self, + fingerprint: torch.Tensor, + formula=None, + num_samples: int = 1, + ) -> list: + """Generate molecules from fingerprint + formula via iterative unmasking.""" + self.eval() + self.mdlm.to_device(self.device) + batch_size = fingerprint.shape[0] + all_preds = [] + + for b_idx in range(batch_size): + fp_single = fingerprint[b_idx:b_idx + 1] + form_single = [formula[b_idx]] if formula is not None else None + + x = torch.full((1, 1), self.bos_index, device=self.device) + x = torch.cat([x, torch.full((1, 1), self.eos_index, device=self.device)], dim=1) + + target_len = 50 + x_batch = self._insert_masks(x, num_samples, target_len) + x_batch = x_batch.to(self.device) + + fp_expanded = fp_single.expand(num_samples, -1) + form_expanded = form_single * num_samples if form_single else None + + num_steps = max(self.mdlm.get_num_steps_confidence(x_batch), 2) + attn_mask = (x_batch != self.pad_index).long() + + for i in range(num_steps): + logits = self.forward_model( + x_batch, attn_mask, formula=form_expanded, fingerprint=fp_expanded + ) + x_batch = self.mdlm.step_confidence( + logits, x_batch, i, num_steps, self.softmax_temp, self.randomness + ) + + decoded = self.tokenizer.batch_decode(x_batch, skip_special_tokens=True) + smiles_list = [] + for safe_str in decoded: + smi = _safe_to_smiles(safe_str) + smiles_list.append(smi) + all_preds.append(smiles_list) + + return all_preds + + def _insert_masks(self, x, num_samples, target_len): + """Create num_samples copies of x with mask tokens inserted.""" + x_seq = x[0] + results = [] + for _ in range(num_samples): + add_len = max(target_len - len(x_seq), 10) + add_len = min(add_len, self.max_position_embeddings - len(x_seq)) + add_len = max(add_len, 10) + new_x = torch.cat([ + x_seq[:-1], + torch.full((add_len,), self.mask_index, device=x.device), + x_seq[-1:], + ]) + results.append(new_x) + max_len = max(len(r) for r in results) + padded = [] + for r in results: + pad_len = max_len - len(r) + if pad_len > 0: + r = torch.cat([r, torch.full((pad_len,), self.pad_index, device=x.device)]) + padded.append(r) + return torch.stack(padded) diff --git a/massspecgym/models/de_novo/fp2mol/molforge/__init__.py b/massspecgym/models/de_novo/fp2mol/molforge/__init__.py new file mode 100644 index 0000000..92f62f6 --- /dev/null +++ b/massspecgym/models/de_novo/fp2mol/molforge/__init__.py @@ -0,0 +1,8 @@ +""" +MolForge decoder: Seq2Seq Transformer for fingerprint-to-molecule generation. + +An encoder-decoder transformer that maps fingerprint bit indices (as a sequence) +to SMILES or SELFIES molecular strings via autoregressive generation. +""" + +from .model import MolForgeDecoder diff --git a/massspecgym/models/de_novo/fp2mol/molforge/decoder_search.py b/massspecgym/models/de_novo/fp2mol/molforge/decoder_search.py new file mode 100644 index 0000000..27f4a4d --- /dev/null +++ b/massspecgym/models/de_novo/fp2mol/molforge/decoder_search.py @@ -0,0 +1,138 @@ +""" +Greedy and beam search decoding for MolForge. + +Implements autoregressive decoding strategies for the encoder-decoder +transformer, converting encoder memory into target token sequences. +""" + +import heapq +from dataclasses import dataclass, field +from typing import List, Optional + +import torch +import torch.nn.functional as F + + +@dataclass(order=True) +class BeamNode: + """A node in the beam search tree.""" + score: float + tokens: List[int] = field(compare=False) + finished: bool = field(default=False, compare=False) + + +def greedy_search( + decoder: "torch.nn.Module", + trg_embedding: "torch.nn.Module", + positional_encoder: "torch.nn.Module", + output_linear: "torch.nn.Module", + e_output: torch.Tensor, + e_mask: torch.Tensor, + sos_id: int, + eos_id: int, + pad_id: int, + max_len: int, + device: torch.device, +) -> List[int]: + """Greedy autoregressive decoding. + + At each step, the most likely next token is selected. + + Args: + decoder: Transformer decoder module. + trg_embedding: Target embedding layer. + positional_encoder: Positional encoding module. + output_linear: Linear projection to vocabulary. + e_output: Encoder output [1, src_len, d_model]. + e_mask: Encoder attention mask [1, 1, src_len]. + sos_id: Start-of-sequence token ID. + eos_id: End-of-sequence token ID. + pad_id: Padding token ID. + max_len: Maximum output length. + device: Target device. + + Returns: + List of generated token IDs (excluding SOS, including EOS if generated). + """ + last_words = torch.full((1, max_len), pad_id, dtype=torch.long, device=device) + last_words[0, 0] = sos_id + cur_len = 1 + + for i in range(max_len - 1): + d_mask = _subsequent_mask(cur_len, device) + trg = trg_embedding(last_words[:, :cur_len]) + trg = positional_encoder(trg) + d_output = decoder(trg, e_output, tgt_mask=d_mask, memory_key_padding_mask=~e_mask.squeeze(1).bool() if e_mask is not None else None) + output = F.log_softmax(output_linear(d_output[:, -1, :]), dim=-1) + next_id = output.argmax(dim=-1).item() + last_words[0, cur_len] = next_id + cur_len += 1 + if next_id == eos_id: + break + + return last_words[0, 1:cur_len].tolist() + + +def beam_search( + decoder: "torch.nn.Module", + trg_embedding: "torch.nn.Module", + positional_encoder: "torch.nn.Module", + output_linear: "torch.nn.Module", + e_output: torch.Tensor, + e_mask: torch.Tensor, + sos_id: int, + eos_id: int, + pad_id: int, + max_len: int, + device: torch.device, + beam_size: int = 10, +) -> List[List[int]]: + """Beam search decoding. + + Maintains top-k hypotheses at each step, returning all completed hypotheses + ranked by log-probability score. + + Returns: + List of token ID lists, best-scoring first. + """ + beams = [BeamNode(score=0.0, tokens=[sos_id])] + completed = [] + + for _ in range(max_len): + candidates = [] + for beam in beams: + if beam.finished: + completed.append(beam) + continue + + seq = torch.tensor([beam.tokens], dtype=torch.long, device=device) + d_mask = _subsequent_mask(seq.size(1), device) + trg = trg_embedding(seq) + trg = positional_encoder(trg) + d_output = decoder(trg, e_output, tgt_mask=d_mask, memory_key_padding_mask=~e_mask.squeeze(1).bool() if e_mask is not None else None) + log_probs = F.log_softmax(output_linear(d_output[:, -1, :]), dim=-1) + + topk_scores, topk_ids = log_probs.topk(beam_size, dim=-1) + for j in range(beam_size): + token_id = topk_ids[0, j].item() + new_score = beam.score + topk_scores[0, j].item() + new_tokens = beam.tokens + [token_id] + finished = token_id == eos_id + candidates.append(BeamNode(score=new_score, tokens=new_tokens, finished=finished)) + + candidates.sort(key=lambda n: n.score, reverse=True) + beams = candidates[:beam_size] + + if all(b.finished for b in beams): + break + + all_results = completed + beams + all_results.sort(key=lambda n: n.score, reverse=True) + + return [node.tokens[1:] for node in all_results] + + +def _subsequent_mask(size: int, device: torch.device) -> torch.Tensor: + """Generate causal (upper-triangular) mask for autoregressive decoding.""" + mask = torch.triu(torch.ones(size, size, device=device), diagonal=1).bool() + return mask diff --git a/massspecgym/models/de_novo/fp2mol/molforge/model.py b/massspecgym/models/de_novo/fp2mol/molforge/model.py new file mode 100644 index 0000000..59183d5 --- /dev/null +++ b/massspecgym/models/de_novo/fp2mol/molforge/model.py @@ -0,0 +1,272 @@ +""" +MolForge decoder: Encoder-Decoder Transformer for fingerprint-to-SMILES generation. + +Ported from Neo et al., "One Small Step with Fingerprints, One Giant Leap for +De Novo Molecule Generation from Mass Spectra", 2025. + +The model treats a molecular fingerprint as a sequence of on-bit indices, +encodes them through a transformer encoder, then autoregressively decodes +SMILES (or SELFIES) token sequences. + +Architecture (matching MolForge paper): +- Encoder: 6 layers, 512d, 8 heads, FFN 2048 +- Decoder: 6 layers, 512d, 8 heads, FFN 2048 +- Source: fingerprint on-bit indices -> SentencePiece tokens -> encoder +- Target: SMILES/SELFIES -> SentencePiece tokens -> decoder +""" + +import math +from typing import Optional, List + +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F + +from massspecgym.models.base import Stage +from massspecgym.models.de_novo.fp2mol.base import FP2MolDeNovoModel +from .decoder_search import greedy_search, beam_search + + +class PositionalEncoding(nn.Module): + """Sinusoidal positional encoding.""" + + def __init__(self, d_model: int, max_len: int = 512, dropout: float = 0.1): + super().__init__() + self.dropout = nn.Dropout(p=dropout) + pe = torch.zeros(max_len, d_model) + position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1) + div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)) + pe[:, 0::2] = torch.sin(position * div_term) + pe[:, 1::2] = torch.cos(position * div_term) + pe = pe.unsqueeze(0) + self.register_buffer("pe", pe) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = x + self.pe[:, :x.size(1)] + return self.dropout(x) + + +class MolForgeDecoder(FP2MolDeNovoModel): + """MolForge encoder-decoder transformer for fingerprint-to-SMILES generation. + + The model encodes fingerprint on-bit indices as a source sequence and + autoregressively generates SMILES/SELFIES as the target sequence. + + Fingerprints are represented as space-separated on-bit indices + (e.g., "1 80 94 114 237") and tokenized with a source vocabulary. + + Args: + d_model: Model dimension. + nhead: Number of attention heads. + num_encoder_layers: Number of encoder layers. + num_decoder_layers: Number of decoder layers. + dim_feedforward: FFN intermediate dimension. + dropout: Dropout rate. + src_vocab_size: Source (fingerprint) vocabulary size. + trg_vocab_size: Target (SMILES/SELFIES) vocabulary size. + src_seq_len: Maximum source sequence length. + trg_seq_len: Maximum target sequence length. + pad_id: Padding token ID. + sos_id: Start-of-sequence token ID. + eos_id: End-of-sequence token ID. + beam_size: Beam size for beam search decoding. + decode_method: Decoding method ('greedy' or 'beam'). + fingerprint_bits: Number of fingerprint bits. + """ + + def __init__( + self, + d_model: int = 512, + nhead: int = 8, + num_encoder_layers: int = 6, + num_decoder_layers: int = 6, + dim_feedforward: int = 2048, + dropout: float = 0.1, + src_vocab_size: int = 6000, + trg_vocab_size: int = 109, + src_seq_len: int = 104, + trg_seq_len: int = 130, + pad_id: int = 0, + sos_id: int = 1, + eos_id: int = 2, + beam_size: int = 10, + decode_method: str = "greedy", + fingerprint_bits: int = 2048, + *args, + **kwargs, + ): + super().__init__( + fingerprint_bits=fingerprint_bits, + use_formula=False, + *args, **kwargs, + ) + + self.d_model = d_model + self.src_seq_len = src_seq_len + self.trg_seq_len = trg_seq_len + self.pad_id = pad_id + self.sos_id = sos_id + self.eos_id = eos_id + self.beam_size = beam_size + self.decode_method = decode_method + self.src_vocab_size = src_vocab_size + self.trg_vocab_size = trg_vocab_size + + self.src_embedding = nn.Embedding(src_vocab_size, d_model) + self.trg_embedding = nn.Embedding(trg_vocab_size, d_model) + self.src_positional_encoder = PositionalEncoding(d_model, src_seq_len, dropout) + self.trg_positional_encoder = PositionalEncoding(d_model, trg_seq_len, dropout) + + encoder_layer = nn.TransformerEncoderLayer( + d_model=d_model, nhead=nhead, dim_feedforward=dim_feedforward, + dropout=dropout, batch_first=True, + ) + self.encoder = nn.TransformerEncoder(encoder_layer, num_layers=num_encoder_layers) + + decoder_layer = nn.TransformerDecoderLayer( + d_model=d_model, nhead=nhead, dim_feedforward=dim_feedforward, + dropout=dropout, batch_first=True, + ) + self.decoder = nn.TransformerDecoder(decoder_layer, num_layers=num_decoder_layers) + + self.output_linear = nn.Linear(d_model, trg_vocab_size) + self.criterion = nn.NLLLoss(ignore_index=pad_id) + + def _fp_to_onbit_indices(self, fingerprint: torch.Tensor) -> torch.Tensor: + """Convert binary fingerprint to a padded sequence of on-bit indices. + + Args: + fingerprint: Binary FP tensor [batch, fp_bits]. + + Returns: + LongTensor of on-bit indices [batch, src_seq_len], padded with pad_id. + """ + batch_size = fingerprint.shape[0] + device = fingerprint.device + result = torch.full((batch_size, self.src_seq_len), self.pad_id, dtype=torch.long, device=device) + + for i in range(batch_size): + on_bits = torch.nonzero(fingerprint[i] > 0.5, as_tuple=True)[0] + n = min(len(on_bits), self.src_seq_len - 1) + result[i, :n] = on_bits[:n] + 3 # offset by special tokens (pad=0, sos=1, eos=2) + result[i, n] = self.eos_id + + return result + + def encode_source(self, src_input: torch.Tensor) -> tuple: + """Encode source (fingerprint indices) through the transformer encoder. + + Returns: + Tuple of (encoder output [B, src_len, d_model], encoder mask [B, 1, src_len]). + """ + e_mask = (src_input != self.pad_id).unsqueeze(1).float() + src_emb = self.src_positional_encoder(self.src_embedding(src_input)) + e_output = self.encoder(src_emb, src_key_padding_mask=(src_input == self.pad_id)) + return e_output, e_mask + + def compute_decoder_loss(self, batch: dict) -> torch.Tensor: + """Compute NLL loss with teacher forcing.""" + fingerprint = batch["fingerprint"] + mol_repr = batch.get("mol_repr", batch.get("mol")) + + src_input = self._fp_to_onbit_indices(fingerprint) + e_output, e_mask = self.encode_source(src_input) + + if isinstance(mol_repr, (list, tuple)): + trg_ids = self._tokenize_targets(mol_repr) + else: + trg_ids = mol_repr + + trg_ids = trg_ids.to(self.device) + trg_input = trg_ids[:, :-1] + trg_output = trg_ids[:, 1:] + + d_mask = nn.Transformer.generate_square_subsequent_mask(trg_input.size(1)).to(self.device) + trg_emb = self.trg_positional_encoder(self.trg_embedding(trg_input)) + d_output = self.decoder( + trg_emb, e_output, tgt_mask=d_mask, + memory_key_padding_mask=(src_input == self.pad_id), + ) + output = F.log_softmax(self.output_linear(d_output), dim=-1) + loss = self.criterion(output.reshape(-1, self.trg_vocab_size), trg_output.reshape(-1)) + return loss + + def _tokenize_targets(self, smiles_list: list) -> torch.Tensor: + """Simple character-level tokenization for SMILES (placeholder). + + In production, this should use SentencePiece. For now, uses a simple + character-to-ID mapping as a fallback. + """ + batch_size = len(smiles_list) + max_len = min(max(len(s) for s in smiles_list) + 2, self.trg_seq_len) + result = torch.full((batch_size, max_len), self.pad_id, dtype=torch.long) + + for i, smi in enumerate(smiles_list): + result[i, 0] = self.sos_id + for j, ch in enumerate(smi[:max_len - 2]): + result[i, j + 1] = ord(ch) % (self.trg_vocab_size - 3) + 3 + end_pos = min(len(smi) + 1, max_len - 1) + result[i, end_pos] = self.eos_id + + return result + + @torch.no_grad() + def decode_from_fingerprint( + self, + fingerprint: torch.Tensor, + formula=None, + num_samples: int = 1, + ) -> list: + """Generate SMILES from fingerprint via greedy or beam search.""" + self.eval() + batch_size = fingerprint.shape[0] + all_preds = [] + + for b_idx in range(batch_size): + fp_single = fingerprint[b_idx:b_idx + 1] + src_input = self._fp_to_onbit_indices(fp_single) + e_output, e_mask = self.encode_source(src_input) + + sample_preds = [] + for _ in range(num_samples): + if self.decode_method == "beam": + results = beam_search( + self.decoder, self.trg_embedding, self.trg_positional_encoder, + self.output_linear, e_output, e_mask, + self.sos_id, self.eos_id, self.pad_id, + self.trg_seq_len, self.device, self.beam_size, + ) + if results: + token_ids = results[0] + else: + token_ids = [] + else: + token_ids = greedy_search( + self.decoder, self.trg_embedding, self.trg_positional_encoder, + self.output_linear, e_output, e_mask, + self.sos_id, self.eos_id, self.pad_id, + self.trg_seq_len, self.device, + ) + + smi = self._detokenize(token_ids) + sample_preds.append(smi) + + all_preds.append(sample_preds) + return all_preds + + def _detokenize(self, token_ids: list) -> Optional[str]: + """Convert token IDs back to SMILES (placeholder for SentencePiece).""" + try: + chars = [] + for tid in token_ids: + if tid == self.eos_id: + break + if tid >= 3: + chars.append(chr((tid - 3) % 128 + 32)) + smi = "".join(chars) + from rdkit import Chem + mol = Chem.MolFromSmiles(smi) + return Chem.MolToSmiles(mol) if mol is not None else None + except Exception: + return None diff --git a/massspecgym/models/encoders/__init__.py b/massspecgym/models/encoders/__init__.py new file mode 100644 index 0000000..9e08df7 --- /dev/null +++ b/massspecgym/models/encoders/__init__.py @@ -0,0 +1,11 @@ +from .mist import SpectraEncoder, SpectraEncoderGrowing + + +def __getattr__(name): + if name == "DreaMS": + from .dreams.model import DreaMS + return DreaMS + if name == "PreTrainedDreaMS": + from .dreams.api import PreTrainedDreaMS + return PreTrainedDreaMS + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/massspecgym/models/encoders/dreams/__init__.py b/massspecgym/models/encoders/dreams/__init__.py new file mode 100644 index 0000000..83e8246 --- /dev/null +++ b/massspecgym/models/encoders/dreams/__init__.py @@ -0,0 +1,20 @@ +""" +DreaMS (Deep Representations Enabling All Mass Spectra) encoder. + +A BERT-style transformer encoder for MS/MS spectra that produces 1024-D +spectrum embeddings. Useful for spectral similarity search, retrieval, +and as a general-purpose spectrum representation. + +Ported from external/DreaMS/dreams/ (Bushuiev et al., Nature Biotechnology 2025). +Preserves the exact args-based config system for checkpoint compatibility. +""" + + +def __getattr__(name): + if name == "DreaMS": + from .model import DreaMS + return DreaMS + if name == "PreTrainedDreaMS": + from .api import PreTrainedDreaMS + return PreTrainedDreaMS + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/massspecgym/models/encoders/dreams/api.py b/massspecgym/models/encoders/dreams/api.py new file mode 100644 index 0000000..b23ca35 --- /dev/null +++ b/massspecgym/models/encoders/dreams/api.py @@ -0,0 +1,118 @@ +""" +DreaMS pretrained model loading and inference API. + +Ported from external/DreaMS/dreams/api.py. +Provides PreTrainedDreaMS for loading checkpoints and computing embeddings. +""" + +from argparse import Namespace +from pathlib import Path +from typing import Optional, Union + +import numpy as np +import torch + +from .model import DreaMS +from .preprocessing import SpectrumPreprocessor, DataFormatA + + +class PreTrainedDreaMS: + """Pretrained DreaMS model for spectrum embedding inference. + + Loads a DreaMS checkpoint and provides a simple API for computing + 1024-D spectrum embeddings. + + Usage: + model = PreTrainedDreaMS.from_checkpoint("checkpoints/dreams/embedding_model.ckpt") + emb = model.embed_spectrum(mzs, intensities, precursor_mz) # (1024,) + """ + + def __init__(self, model: DreaMS, n_highest_peaks: int = 100): + self.model = model.eval() + self.n_highest_peaks = n_highest_peaks + self.preprocessor = SpectrumPreprocessor( + dformat=DataFormatA(), + n_highest_peaks=n_highest_peaks, + ) + + @classmethod + def from_checkpoint( + cls, + ckpt_path: str, + n_highest_peaks: int = 100, + device: str = None, + remove_ssl_heads: bool = True, + ) -> "PreTrainedDreaMS": + """Load a pretrained DreaMS model from checkpoint. + + Args: + ckpt_path: Path to DreaMS checkpoint (.ckpt). + n_highest_peaks: Number of peaks to retain per spectrum. + device: Device to load model on. Auto-detects if None. + remove_ssl_heads: Remove unused SSL heads (ff_out, mz_masking_loss, ro_out). + + Returns: + PreTrainedDreaMS instance ready for inference. + """ + if device is None: + device = "cuda" if torch.cuda.is_available() else "cpu" + + model = DreaMS.load_from_checkpoint(ckpt_path, map_location=device) + + if remove_ssl_heads: + for attr in ('ff_out', 'mz_masking_loss', 'ro_out', 'ff_out_intens'): + if hasattr(model, attr): + delattr(model, attr) + + model = model.to(device) + return cls(model, n_highest_peaks) + + @property + def device(self): + return next(self.model.parameters()).device + + @property + def d_model(self): + return self.model.d_model + + @torch.no_grad() + def embed_spectrum( + self, + mzs: np.ndarray, + intensities: np.ndarray, + precursor_mz: float, + ) -> np.ndarray: + """Compute 1024-D embedding for a single spectrum. + + Args: + mzs: Array of m/z values. + intensities: Array of intensity values. + precursor_mz: Precursor m/z. + + Returns: + 1D numpy array of shape (d_model,) - the spectrum embedding. + """ + spec = self.preprocessor(mzs, intensities, precursor_mz) + spec_tensor = torch.FloatTensor(spec).unsqueeze(0).to(self.device) + output = self.model(spec_tensor) + return output[0, 0, :].cpu().numpy() + + @torch.no_grad() + def embed_batch( + self, + specs: list, + ) -> np.ndarray: + """Compute embeddings for a batch of spectra. + + Args: + specs: List of (mzs, intensities, precursor_mz) tuples. + + Returns: + Array of shape (batch_size, d_model). + """ + preprocessed = [ + self.preprocessor(mzs, ints, pmz) for mzs, ints, pmz in specs + ] + batch = torch.FloatTensor(np.stack(preprocessed)).to(self.device) + output = self.model(batch) + return output[:, 0, :].cpu().numpy() diff --git a/massspecgym/models/encoders/dreams/feed_forward.py b/massspecgym/models/encoders/dreams/feed_forward.py new file mode 100644 index 0000000..0b019da --- /dev/null +++ b/massspecgym/models/encoders/dreams/feed_forward.py @@ -0,0 +1,43 @@ +""" +Generic configurable FeedForward module for DreaMS. + +Ported from external/DreaMS/dreams/models/layers/feed_forward.py. +""" + +import torch +import torch.nn as nn + + +class FeedForward(nn.Module): + """Configurable feed-forward network with variable depth. + + Args: + in_dim: Input dimension. + out_dim: Output dimension. + hidden_dim: Hidden dimension (defaults to out_dim). + depth: Number of layers (1 = single linear). + dropout: Dropout rate. + act_last: Whether to apply activation after last layer. + bias: Whether to use bias in linear layers. + """ + + def __init__(self, in_dim, out_dim, hidden_dim=None, depth=2, + dropout=0.0, act_last=True, bias=True): + super().__init__() + if hidden_dim is None: + hidden_dim = out_dim + + layers = [] + for i in range(depth): + d_in = in_dim if i == 0 else hidden_dim + d_out = out_dim if i == depth - 1 else hidden_dim + layers.append(nn.Linear(d_in, d_out, bias=bias)) + if i < depth - 1 or act_last: + layers.append(nn.ReLU()) + if dropout > 0: + layers.append(nn.Dropout(dropout)) + + self.net = nn.Sequential(*layers) + + def forward(self, x): + return self.net(x) diff --git a/massspecgym/models/encoders/dreams/fourier_features.py b/massspecgym/models/encoders/dreams/fourier_features.py new file mode 100644 index 0000000..fba8e46 --- /dev/null +++ b/massspecgym/models/encoders/dreams/fourier_features.py @@ -0,0 +1,79 @@ +""" +Fourier feature encoding for m/z values in DreaMS. + +Ported from external/DreaMS/dreams/models/layers/fourier_features.py. +""" + +from math import ceil + +import torch +import torch.nn as nn +from torch.nn import Parameter + + +class FourierFeatures(nn.Module): + """Fourier feature encoding for m/z values. + + Maps scalar m/z values to high-dimensional sinusoidal features, + enabling the transformer to distinguish fine-grained mass differences. + + Strategies: + - 'voronov_et_al': log-spaced frequencies (default for DreaMS). + - 'random': random Gaussian frequencies. + - 'lin_float_int': linear combination of float and integer frequencies. + + Args: + strategy: Frequency spacing strategy. + x_min: Minimum expected input value (for frequency calculation). + x_max: Maximum expected input value. + trainable: Whether frequencies are learnable. + funcs: Which trig functions ('both', 'sin', 'cos'). + sigma: Std for random frequencies. + num_freqs: Number of frequency components. + """ + + def __init__(self, strategy, x_min, x_max, trainable=True, funcs='both', + sigma=10, num_freqs=512): + assert strategy in {'random', 'voronov_et_al', 'lin_float_int'} + assert funcs in {'both', 'sin', 'cos'} + assert x_min < 1 + + super().__init__() + self.funcs = funcs + self.strategy = strategy + self.trainable = trainable + self.num_freqs = num_freqs + + if strategy == 'random': + b = torch.randn(num_freqs) * sigma + elif strategy == 'voronov_et_al': + b = torch.tensor([ + 1 / (x_min * (x_max / x_min) ** (2 * i / (num_freqs - 2))) + for i in range(1, num_freqs) + ]) + elif strategy == 'lin_float_int': + b = torch.tensor( + [1 / (x_min * i) for i in range(2, ceil(1 / x_min), 2)] + + [1 / (1 * i) for i in range(2, ceil(x_max), 1)] + ) + else: + raise ValueError(f"Unknown strategy: {strategy}") + + b = b.unsqueeze(0) + self.b = nn.Parameter(b, requires_grad=self.trainable) + + def num_features(self): + n = self.b.shape[1] + if self.funcs == 'both': + return n * 2 + return n + + def forward(self, x): + x = 2 * torch.pi * x @ self.b + if self.funcs == 'both': + x = torch.cat((torch.cos(x), torch.sin(x)), dim=-1) + elif self.funcs == 'cos': + x = torch.cos(x) + elif self.funcs == 'sin': + x = torch.sin(x) + return x diff --git a/massspecgym/models/encoders/dreams/layers.py b/massspecgym/models/encoders/dreams/layers.py new file mode 100644 index 0000000..e896f04 --- /dev/null +++ b/massspecgym/models/encoders/dreams/layers.py @@ -0,0 +1,216 @@ +""" +DreaMS transformer encoder layers. + +Ported from external/DreaMS/dreams/models/dreams/layers.py. +Includes custom MultiheadAttention with optional Graphormer m/z bias, +ScaleNorm, and TransformerEncoder with gradient checkpointing. +""" + +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.nn import Parameter + + +class ScaleNorm(nn.Module): + """Scale normalization (Nguyen & Salazar, 2019).""" + + def __init__(self, scale, eps=1e-5): + super().__init__() + self.scale = Parameter(torch.tensor(float(scale))) + self.eps = eps + + def forward(self, x): + norm = self.scale / torch.norm(x, dim=-1, keepdim=True).clamp(min=self.eps) + return x * norm + + +class MultiheadAttention(nn.Module): + """Multi-head attention with optional Graphormer m/z distance bias. + + Args: + args: Namespace with d_model, n_heads, att_dropout, no_transformer_bias, + attn_mech, d_graphormer_params. + """ + + def __init__(self, args): + super().__init__() + self.d_model = args.d_model + self.n_heads = args.n_heads + self.dropout = getattr(args, 'att_dropout', getattr(args, 'dropout', 0.0)) + self.use_transformer_bias = not getattr(args, 'no_transformer_bias', False) + self.attn_mech = getattr(args, 'attn_mech', 'dot-product') + self.d_graphormer_params = getattr(args, 'd_graphormer_params', 0) + + assert self.d_model % self.n_heads == 0 + self.head_dim = self.d_model // self.n_heads + self.scale = self.head_dim ** -0.5 + + self.weights = Parameter(torch.Tensor(4 * self.d_model, self.d_model)) + if self.use_transformer_bias: + self.biases = Parameter(torch.Tensor(4 * self.d_model)) + + if self.d_graphormer_params: + self.lin_graphormer = nn.Linear(self.d_graphormer_params, self.n_heads, bias=False) + + mean, std = 0, (2 / (5 * self.d_model)) ** 0.5 + nn.init.normal_(self.weights, mean=mean, std=std) + if self.use_transformer_bias: + nn.init.constant_(self.biases, 0.) + + if self.attn_mech == 'additive_v': + self.additive_v = Parameter(torch.Tensor(self.n_heads, self.head_dim)) + nn.init.normal_(self.additive_v, mean=mean, std=std) + + def proj_qkv(self, q, k, v): + w_q, w_k, w_v, w_o = self.weights.chunk(4, dim=0) + if self.use_transformer_bias: + b_q, b_k, b_v, b_o = self.biases.chunk(4, dim=0) + q = F.linear(q, w_q, b_q) + k = F.linear(k, w_k, b_k) + v = F.linear(v, w_v, b_v) + else: + q = F.linear(q, w_q) + k = F.linear(k, w_k) + v = F.linear(v, w_v) + return q, k, v + + def proj_o(self, x): + w_q, w_k, w_v, w_o = self.weights.chunk(4, dim=0) + if self.use_transformer_bias: + b_q, b_k, b_v, b_o = self.biases.chunk(4, dim=0) + return F.linear(x, w_o, b_o) + return F.linear(x, w_o) + + def forward(self, q, k, v, mask, graphormer_dists=None, do_proj_qkv=True): + bs, n, d = q.size() + + def _split_heads(tensor): + return tensor.reshape(bs, n, self.n_heads, self.head_dim).transpose(1, 2) + + if do_proj_qkv: + q, k, v = self.proj_qkv(q, k, v) + q, k, v = _split_heads(q), _split_heads(k), _split_heads(v) + + if self.attn_mech == 'dot-product': + att_weights = torch.einsum('bhnd,bhdm->bhnm', q, k.transpose(-2, -1)) + elif self.attn_mech in ('additive_v', 'additive_fixed'): + att_weights = (q.unsqueeze(-2) - k.unsqueeze(-3)) + if self.attn_mech == 'additive_v': + att_weights = att_weights * self.additive_v[None, :, None, None, :] + att_weights = att_weights.sum(dim=-1) + else: + raise NotImplementedError(f'"{self.attn_mech}" not implemented') + + att_weights = att_weights * self.scale + + if graphormer_dists is not None: + if self.d_graphormer_params: + att_bias = self.lin_graphormer(graphormer_dists).permute(0, 3, 1, 2) + else: + att_bias = graphormer_dists.sum(dim=-1).unsqueeze(1) + att_weights = att_weights + att_bias + + if mask is not None: + att_weights.masked_fill_(mask.unsqueeze(1).unsqueeze(-1), -1e9) + + att_weights = F.softmax(att_weights, dim=-1) + att_weights = F.dropout(att_weights, p=self.dropout, training=self.training) + + _att = att_weights.reshape(-1, n, n) + output = torch.bmm(_att, v.reshape(bs * self.n_heads, -1, self.head_dim)) + output = output.reshape(bs, self.n_heads, n, self.head_dim).transpose(1, 2).reshape(bs, n, -1) + output = self.proj_o(output) + + return output, att_weights + + +class TransformerFeedForward(nn.Module): + """Feed-forward block inside transformer layer.""" + + def __init__(self, args): + super().__init__() + self.dropout = getattr(args, 'ff_dropout', getattr(args, 'dropout', 0.0)) + self.d_model = args.d_model + self.ff_dim = 4 * args.d_model + use_bias = not getattr(args, 'no_transformer_bias', False) + self.in_proj = nn.Linear(self.d_model, self.ff_dim, bias=use_bias) + self.out_proj = nn.Linear(self.ff_dim, self.d_model, bias=use_bias) + + std = (2 / (self.ff_dim + self.d_model)) ** 0.5 + nn.init.normal_(self.in_proj.weight, mean=0, std=std) + nn.init.normal_(self.out_proj.weight, mean=0, std=std) + if use_bias: + nn.init.constant_(self.in_proj.bias, 0.) + nn.init.constant_(self.out_proj.bias, 0.) + + def forward(self, x): + y = F.relu(self.in_proj(x)) + y = F.dropout(y, p=self.dropout, training=self.training) + return self.out_proj(y) + + +class TransformerEncoder(nn.Module): + """DreaMS transformer encoder with ScaleNorm and optional Graphormer bias. + + Args: + args: Namespace with n_layers, d_model, pre_norm, scnorm, + residual_dropout, and attention/FF config. + """ + + def __init__(self, args): + super().__init__() + self.residual_dropout = getattr(args, 'residual_dropout', getattr(args, 'dropout', 0.0)) + self.n_layers = args.n_layers + self.pre_norm = getattr(args, 'pre_norm', True) + self._gradient_checkpointing = False + + self.atts = nn.ModuleList([MultiheadAttention(args) for _ in range(self.n_layers)]) + self.ffs = nn.ModuleList([TransformerFeedForward(args) for _ in range(self.n_layers)]) + + num_scales = self.n_layers * 2 + 1 if self.pre_norm else self.n_layers * 2 + if getattr(args, 'scnorm', True): + self.scales = nn.ModuleList([ScaleNorm(args.d_model ** 0.5) for _ in range(num_scales)]) + else: + self.scales = nn.ModuleList([nn.LayerNorm(args.d_model) for _ in range(num_scales)]) + + def _layer_forward(self, i, x, src_mask, graphormer_dists): + if self.pre_norm: + residual = x + x = self.scales[2 * i](x) + x, _ = self.atts[i](x, x, x, src_mask, graphormer_dists) + x = F.dropout(x, p=self.residual_dropout, training=self.training) + x = residual + x + + residual = x + x = self.scales[2 * i + 1](x) + x = self.ffs[i](x) + x = F.dropout(x, p=self.residual_dropout, training=self.training) + x = residual + x + else: + residual = x + x, _ = self.atts[i](x, x, x, src_mask, graphormer_dists) + x = F.dropout(x, p=self.residual_dropout, training=self.training) + x = self.scales[2 * i](residual + x) + + residual = x + x = self.ffs[i](x) + x = F.dropout(x, p=self.residual_dropout, training=self.training) + x = self.scales[2 * i + 1](residual + x) + + return x + + def forward(self, src_inputs, src_mask, graphormer_dists=None): + x = F.dropout(src_inputs, p=self.residual_dropout, training=self.training) + for i in range(self.n_layers): + if self._gradient_checkpointing and self.training: + x = torch.utils.checkpoint.checkpoint( + self._layer_forward, i, x, src_mask, graphormer_dists, + use_reentrant=False + ) + else: + x = self._layer_forward(i, x, src_mask, graphormer_dists) + + if self.pre_norm: + x = self.scales[-1](x) + return x diff --git a/massspecgym/models/encoders/dreams/model.py b/massspecgym/models/encoders/dreams/model.py new file mode 100644 index 0000000..f9ae38d --- /dev/null +++ b/massspecgym/models/encoders/dreams/model.py @@ -0,0 +1,186 @@ +""" +DreaMS model: BERT-style MS/MS spectrum encoder. + +Ported from external/DreaMS/dreams/models/dreams/dreams.py. +Preserves the exact args-based config for checkpoint compatibility. + +The model encodes MS/MS spectra as sequences of (m/z, intensity) tokens, +using Fourier features for m/z encoding and a transformer encoder. +Output: per-token embeddings of dimension d_model (typically 1024). +""" + +from argparse import Namespace +from typing import Optional + +import torch +import torch.nn as nn +import pytorch_lightning as pl + +from .fourier_features import FourierFeatures +from .feed_forward import FeedForward +from .layers import TransformerEncoder + + +class DreaMS(pl.LightningModule): + """DreaMS spectrum encoder model. + + BERT-style transformer that encodes MS/MS spectra into dense embeddings. + The precursor m/z is prepended as the first token; its embedding serves + as the spectrum-level representation. + + Args: + args: Namespace with model configuration. Key fields: + d_fourier (int): Fourier feature dimension (default 512). + d_peak (int): Peak embedding dimension (default 512). + d_mz_token (int): Discrete m/z token dimension (default 0). + n_layers (int): Number of transformer layers. + n_heads (int): Number of attention heads. + dropout (float): Dropout rate. + fourier_strategy (str): Fourier frequency strategy. + fourier_num_freqs (int): Number of Fourier frequencies. + charge_feature (bool): Whether to include charge as feature. + graphormer_mz_diffs (bool): Use Graphormer m/z distance bias. + vanilla_transformer (bool): Use standard PyTorch transformer. + spec_preproc: SpectrumPreprocessor instance. + """ + + def __init__(self, args: Namespace, spec_preproc=None): + super().__init__() + self.save_hyperparameters() + + self.spec_preproc = spec_preproc + self.n_layers = args.n_layers + self.n_heads = args.n_heads + self.lr = getattr(args, 'lr', 1e-4) + self.weight_decay = getattr(args, 'weight_decay', 0.0) + self.charge_feature = getattr(args, 'charge_feature', False) + self.d_fourier = getattr(args, 'd_fourier', 512) + self.d_peak = getattr(args, 'd_peak', 512) + self.d_mz_token = getattr(args, 'd_mz_token', 0) + self.d_model = sum(d for d in [self.d_fourier, self.d_peak, self.d_mz_token] if d) + args.d_model = self.d_model + self.dformat = getattr(args, 'dformat', None) + self.hot_mz_bin_size = getattr(args, 'hot_mz_bin_size', 1.0) + self.graphormer_mz_diffs = getattr(args, 'graphormer_mz_diffs', False) + self.graphormer_parametrized = getattr(args, 'graphormer_parametrized', False) + self.mask_val = getattr(args, 'mask_val', -1.0) + self.vanilla_transformer = getattr(args, 'vanilla_transformer', False) + + if self.graphormer_mz_diffs and self.graphormer_parametrized: + args.d_graphormer_params = self.d_fourier if self.d_fourier else 1 + else: + args.d_graphormer_params = 0 + + token_dim = 2 + if self.charge_feature: + token_dim += 1 + + if self.d_fourier: + max_mz = self.dformat.max_mz if self.dformat else 1000.0 + x_min = getattr(self.dformat, 'max_tbxic_stdev', 0.003) if self.dformat else 0.003 + fourier_min_freq = getattr(args, 'fourier_min_freq', None) + if fourier_min_freq: + x_min = fourier_min_freq + + self.fourier_enc = FourierFeatures( + strategy=getattr(args, 'fourier_strategy', 'voronov_et_al'), + num_freqs=getattr(args, 'fourier_num_freqs', 512), + x_min=x_min, + x_max=max_mz, + trainable=getattr(args, 'fourier_trainable', True), + ) + self.ff_fourier = FeedForward( + in_dim=self.fourier_enc.num_features(), + out_dim=self.d_fourier, + dropout=getattr(args, 'dropout', 0.0), + depth=getattr(args, 'ff_fourier_depth', 2), + hidden_dim=getattr(args, 'ff_fourier_d', self.d_fourier), + bias=not getattr(args, 'no_ffs_bias', False), + ) + + elif self.d_mz_token: + max_mz = self.dformat.max_mz if self.dformat else 1000.0 + num_bins = int(max_mz / self.hot_mz_bin_size) + 2 + self.mz_tokenizer = nn.Embedding(num_bins, self.d_mz_token, padding_idx=0) + self.ff_mz_token = FeedForward( + in_dim=self.d_mz_token, hidden_dim=self.d_mz_token, + out_dim=self.d_mz_token, depth=2, + dropout=getattr(args, 'dropout', 0.0), + ) + + self.ff_peak = FeedForward( + in_dim=token_dim, + hidden_dim=self.d_peak, + out_dim=self.d_peak, + depth=getattr(args, 'ff_peak_depth', 2), + dropout=getattr(args, 'dropout', 0.0), + bias=not getattr(args, 'no_ffs_bias', False), + ) + + if self.vanilla_transformer: + encoder_layer = nn.TransformerEncoderLayer( + d_model=self.d_model, dim_feedforward=self.d_model * 4, + nhead=self.n_heads, activation='gelu', + dropout=getattr(args, 'dropout', 0.0), + batch_first=True, norm_first=True, + ) + self.transformer_encoder = nn.TransformerEncoder( + encoder_layer, num_layers=self.n_layers + ) + else: + self.transformer_encoder = TransformerEncoder(args) + + def forward(self, spec, charge=None): + """Encode a batch of MS/MS spectra. + + Args: + spec: Tensor of shape (batch, n_peaks, 2) with [m/z, intensity]. + First peak is the precursor. + charge: Optional tensor of shape (batch,) with charge values. + + Returns: + Tensor of shape (batch, n_peaks, d_model) with per-token embeddings. + """ + padding_mask = spec[:, :, 0] == 0 + + if self.charge_feature: + if charge is None: + raise ValueError("charge required when charge_feature=True") + charge_features = ~padding_mask * charge.unsqueeze(-1) + spec = torch.cat([spec, charge_features.unsqueeze(-1)], dim=-1) + + normalized_spec = spec.clone() + max_mz = self.dformat.max_mz if self.dformat else 1000.0 + normalized_spec[..., 0] = normalized_spec[..., 0] / max_mz + + peak_embs = self.ff_peak(normalized_spec) + + if self.d_fourier: + fourier_features = self.ff_fourier(self.fourier_enc(spec[..., [0]])) + spec_embs = torch.cat([peak_embs, fourier_features], dim=-1) + elif self.d_mz_token: + mz_bins = (spec[..., 0] / self.hot_mz_bin_size).long().clamp(min=0) + tokenized_mzs = self.ff_mz_token(self.mz_tokenizer(mz_bins)) + spec_embs = torch.cat([peak_embs, tokenized_mzs], dim=-1) + else: + spec_embs = peak_embs + + graphormer_dists = None + if self.graphormer_mz_diffs: + if self.d_fourier: + graphormer_dists = fourier_features.unsqueeze(2) - fourier_features.unsqueeze(1) + else: + mz_vals = spec[..., 0] + graphormer_dists = (mz_vals.unsqueeze(2) - mz_vals.unsqueeze(1)).unsqueeze(-1) + + if self.vanilla_transformer: + output = self.transformer_encoder(spec_embs, src_key_padding_mask=padding_mask) + else: + output = self.transformer_encoder(spec_embs, padding_mask, graphormer_dists) + + return output + + def configure_optimizers(self): + return torch.optim.AdamW( + self.parameters(), lr=self.lr, weight_decay=self.weight_decay + ) diff --git a/massspecgym/models/encoders/dreams/preprocessing.py b/massspecgym/models/encoders/dreams/preprocessing.py new file mode 100644 index 0000000..49760c6 --- /dev/null +++ b/massspecgym/models/encoders/dreams/preprocessing.py @@ -0,0 +1,90 @@ +""" +Spectrum preprocessing for DreaMS input. + +Ported from external/DreaMS/dreams/utils/data.py (SpectrumPreprocessor) +and external/DreaMS/dreams/utils/dformats.py (DataFormatA). +""" + +from dataclasses import dataclass +from typing import Optional + +import numpy as np + + +@dataclass +class DataFormatA: + """Default data format constraints for DreaMS.""" + min_peaks_n: int = 3 + max_peaks_n: int = 128 + max_mz: float = 1000.0 + max_prec_mz: float = 1000.0 + charge: int = 1 + max_tbxic_stdev: float = 0.003 + + +class SpectrumPreprocessor: + """Preprocess raw spectra for DreaMS model input. + + Performs: top-k peak selection, intensity normalization, precursor prepend, + and padding to fixed length. + + Args: + dformat: Data format constraints (DataFormatA). + n_highest_peaks: Number of highest-intensity peaks to retain. + prec_intens: Intensity value for the prepended precursor peak. + """ + + def __init__(self, dformat=None, n_highest_peaks=100, prec_intens=1.1): + self.dformat = dformat or DataFormatA() + self.n_highest_peaks = n_highest_peaks + self.prec_intens = prec_intens + + def __call__( + self, + mzs: np.ndarray, + intensities: np.ndarray, + precursor_mz: float, + ) -> np.ndarray: + """Preprocess a single spectrum for DreaMS input. + + Args: + mzs: Array of m/z values. + intensities: Array of intensity values. + precursor_mz: Precursor m/z value. + + Returns: + Array of shape (n_highest_peaks + 1, 2) with [m/z, intensity]. + First row is the precursor; padded positions have zeros. + """ + mzs = np.asarray(mzs, dtype=np.float32) + intensities = np.asarray(intensities, dtype=np.float32) + + if len(mzs) == 0: + result = np.zeros((self.n_highest_peaks + 1, 2), dtype=np.float32) + result[0] = [precursor_mz, self.prec_intens] + return result + + max_int = intensities.max() + if max_int > 0: + intensities = intensities / max_int + + valid = (mzs > 0) & (mzs <= self.dformat.max_mz) + mzs = mzs[valid] + intensities = intensities[valid] + + if len(mzs) > self.n_highest_peaks: + top_idx = np.argsort(intensities)[::-1][:self.n_highest_peaks] + mzs = mzs[top_idx] + intensities = intensities[top_idx] + + sort_idx = np.argsort(mzs) + mzs = mzs[sort_idx] + intensities = intensities[sort_idx] + + n_peaks = len(mzs) + result = np.zeros((self.n_highest_peaks + 1, 2), dtype=np.float32) + result[0] = [precursor_mz, self.prec_intens] + result[1:n_peaks + 1, 0] = mzs + result[1:n_peaks + 1, 1] = intensities + + return result diff --git a/massspecgym/models/encoders/mist/__init__.py b/massspecgym/models/encoders/mist/__init__.py new file mode 100644 index 0000000..f1bb251 --- /dev/null +++ b/massspecgym/models/encoders/mist/__init__.py @@ -0,0 +1,24 @@ +""" +MIST (Mass Spectrometry Transformer) encoder for spectrum-to-fingerprint prediction. + +Ported from Goldman et al., "Annotating metabolite mass spectra with domain-inspired +chemical formula transformers", Nature Machine Intelligence, 2023. + +The encoder predicts molecular fingerprints from tandem mass spectra using a +FormulaTransformer backbone with progressive fingerprint refinement. +""" + +from .encoder import SpectraEncoder, SpectraEncoderGrowing +from .chem_constants import ( + VALID_ELEMENTS, + NORM_VEC, + formula_to_dense, + vec_to_formula, + get_all_subsets, + get_all_subsets_dense, + rdbe_filter, + cross_sum, + clipped_ppm, + ion_to_mass, + ION_LST, +) diff --git a/massspecgym/models/encoders/mist/chem_constants.py b/massspecgym/models/encoders/mist/chem_constants.py new file mode 100644 index 0000000..9352506 --- /dev/null +++ b/massspecgym/models/encoders/mist/chem_constants.py @@ -0,0 +1,232 @@ +""" +Chemistry constants and utilities for the MIST encoder. + +Extracted from the original MIST chem_utils.py to be self-contained within +MassSpecGym without external dependencies on the full MIST package. + +Includes subformulae assignment utilities (get_all_subsets, rdbe_filter, etc.) +ported from external/mist/src/mist/utils/chem_utils.py. +""" + +import re +from collections import defaultdict +from functools import reduce + +import numpy as np +import torch +from rdkit import Chem +from rdkit.Chem import Atom + +P_TBL = Chem.GetPeriodicTable() + +CHEM_FORMULA_SIZE = "([A-Z][a-z]*)([0-9]*)" + +VALID_ELEMENTS = [ + "C", "H", "As", "B", "Br", "Cl", "Co", "F", "Fe", "I", + "K", "N", "Na", "O", "P", "S", "Se", "Si", +] +VALID_ATOM_NUM = [Atom(i).GetAtomicNum() for i in VALID_ELEMENTS] +CHEM_ELEMENT_NUM = len(VALID_ELEMENTS) + +ATOM_NUM_TO_ONEHOT = torch.zeros((max(VALID_ATOM_NUM) + 1, CHEM_ELEMENT_NUM)) +ATOM_NUM_TO_ONEHOT[VALID_ATOM_NUM, torch.arange(CHEM_ELEMENT_NUM)] = 1 + +VALID_MONO_MASSES = np.array( + [P_TBL.GetMostCommonIsotopeMass(i) for i in VALID_ELEMENTS] +) +CHEM_MASSES = VALID_MONO_MASSES[:, None] + +ELEMENT_VECTORS = np.eye(len(VALID_ELEMENTS)) +ELEMENT_VECTORS_MASS = np.hstack([ELEMENT_VECTORS, CHEM_MASSES]) +ELEMENT_TO_MASS = dict(zip(VALID_ELEMENTS, CHEM_MASSES.squeeze())) + +# Reasonable normalization vector for elements (estimated by max counts + 1 when zero) +NORM_VEC = np.array([81, 158, 2, 1, 3, 10, 1, 17, 1, 6, 1, 19, 2, 34, 6, 6, 2, 6]) + +element_to_ind = dict(zip(VALID_ELEMENTS, np.arange(len(VALID_ELEMENTS)))) +element_to_position = dict(zip(VALID_ELEMENTS, ELEMENT_VECTORS)) + +ELECTRON_MASS = 0.00054858 + +ION_LST = [ + "[M+H]+", "[M+Na]+", "[M+K]+", "[M-H2O+H]+", + "[M+H3N+H]+", "[M]+", "[M-H4O2+H]+", +] + +ion_remap = dict(zip(ION_LST, ION_LST)) +ion_remap.update({ + "[M+NH4]+": "[M+H3N+H]+", + "M+H": "[M+H]+", + "M+Na": "[M+Na]+", + "M+H-H2O": "[M-H2O+H]+", + "M-H2O+H": "[M-H2O+H]+", + "M+NH4": "[M+H3N+H]+", + "M-2H2O+H": "[M-H4O2+H]+", + "[M-2H2O+H]+": "[M-H4O2+H]+", +}) + +ion_to_idx = dict(zip(ION_LST, np.arange(len(ION_LST)))) + +ion_to_mass = { + "[M+H]+": ELEMENT_TO_MASS["H"] - ELECTRON_MASS, + "[M+Na]+": ELEMENT_TO_MASS["Na"] - ELECTRON_MASS, + "[M+K]+": ELEMENT_TO_MASS["K"] - ELECTRON_MASS, + "[M-H2O+H]+": -ELEMENT_TO_MASS["O"] - ELEMENT_TO_MASS["H"] - ELECTRON_MASS, + "[M+H3N+H]+": ELEMENT_TO_MASS["N"] + ELEMENT_TO_MASS["H"] * 4 - ELECTRON_MASS, + "[M]+": 0 - ELECTRON_MASS, + "[M-H4O2+H]+": -ELEMENT_TO_MASS["O"] * 2 - ELEMENT_TO_MASS["H"] * 3 - ELECTRON_MASS, +} + +ion_to_add_vec = { + "[M+H]+": element_to_position["H"], + "[M+Na]+": element_to_position["Na"], + "[M+K]+": element_to_position["K"], + "[M-H2O+H]+": -element_to_position["O"] - element_to_position["H"], + "[M+H3N+H]+": element_to_position["N"] + element_to_position["H"] * 4, + "[M]+": np.zeros_like(element_to_position["H"]), + "[M-H4O2+H]+": -element_to_position["O"] * 2 - element_to_position["H"] * 3, +} + +instrument_to_type = defaultdict(lambda: "unknown") +instrument_to_type.update({ + "Thermo Finnigan Velos Orbitrap": "orbitrap", + "Thermo Finnigan Elite Orbitrap": "orbitrap", + "Orbitrap Fusion Lumos": "orbitrap", + "Q-ToF (LCMS)": "qtof", + "Unknown (LCMS)": "unknown", + "ion trap": "iontrap", + "FTICR (LCMS)": "fticr", + "Bruker Q-ToF (LCMS)": "qtof", + "Orbitrap (LCMS)": "orbitrap", +}) + +instruments = sorted(list(set(instrument_to_type.values()))) +max_instr_idx = len(instruments) + 1 +instrument_to_idx = dict(zip(instruments, np.arange(len(instruments)))) + + +def formula_to_dense(chem_formula: str) -> np.ndarray: + """Convert chemical formula string to dense element-count vector.""" + total_onehot = [] + for (chem_symbol, num) in re.findall(CHEM_FORMULA_SIZE, chem_formula): + num = 1 if num == "" else int(num) + one_hot = element_to_position[chem_symbol].reshape(1, -1) + one_hot_repeats = np.repeat(one_hot, repeats=num, axis=0) + total_onehot.append(one_hot_repeats) + + if len(total_onehot) == 0: + return np.zeros(len(element_to_position)) + return np.vstack(total_onehot).sum(0) + + +def vec_to_formula(form_vec) -> str: + """Convert dense element-count vector back to formula string.""" + build_str = "" + for i in np.argwhere(form_vec > 0).flatten(): + el = VALID_ELEMENTS[i] + ct = int(form_vec[i]) + build_str += f"{el}{ct}" if ct > 1 else f"{el}" + return build_str + + +def standardize_form(formula: str) -> str: + """Standardize chemical formula to canonical form.""" + return vec_to_formula(formula_to_dense(formula)) + + +def standardize_adduct(adduct: str) -> str: + """Standardize adduct notation.""" + adduct = adduct.replace(" ", "") + adduct = ion_remap.get(adduct, adduct) + if adduct not in ION_LST: + raise ValueError(f"Adduct {adduct} not in ION_LST") + return adduct + + +def get_ion_idx(ionization: str) -> int: + """Map ionization string to index.""" + return ion_to_idx[ionization] + + +def get_instr_idx(instrument: str) -> int: + """Map instrument string to index.""" + inst = instrument_to_type.get(instrument, "unknown") + return instrument_to_idx[inst] + + +# --- Subformulae assignment utilities --- +# Ported verbatim from external/mist/src/mist/utils/chem_utils.py + +# RDBE multiplier vector: 2*C + N + P - H - Cl - Br - I - F +rdbe_mult = np.zeros_like(ELEMENT_VECTORS[0]) +_rdbe_els = ["C", "N", "P", "H", "Cl", "Br", "I", "F"] +_rdbe_weights = [2, 1, 1, -1, -1, -1, -1, -1] +for _k, _v in zip(_rdbe_els, _rdbe_weights): + if _k in element_to_ind: + rdbe_mult[element_to_ind[_k]] = _v + + +def cross_sum(x, y): + """Compute cross sum of two arrays for combinatorial enumeration.""" + return (np.expand_dims(x, 0) + np.expand_dims(y, 1)).reshape(-1, y.shape[-1]) + + +def rdbe_filter(cross_prod): + """Filter formula vectors by ring and double bond equivalent (RDBE >= 0).""" + rdbe_total = 1 + 0.5 * cross_prod.dot(rdbe_mult) + return np.argwhere(rdbe_total >= 0).flatten() + + +def get_all_subsets_dense(dense_formula, element_vectors): + """Enumerate all valid subformulae from a dense formula vector. + + Args: + dense_formula: Element count vector (e.g., from formula_to_dense). + element_vectors: Basis vectors for elements (ELEMENT_VECTORS). + + Returns: + Tuple of (cross_prod, all_masses): formula vectors and monoisotopic masses. + """ + non_zero = np.argwhere(dense_formula > 0).flatten() + + vectorized_formula = [] + for nonzero_ind in non_zero: + temp = element_vectors[nonzero_ind] * np.arange( + 0, dense_formula[nonzero_ind] + 1 + ).reshape(-1, 1) + vectorized_formula.append(temp) + + zero_vec = np.zeros((1, element_vectors.shape[-1])) + cross_prod = reduce(cross_sum, vectorized_formula, zero_vec) + + cross_prod_inds = rdbe_filter(cross_prod) + cross_prod = cross_prod[cross_prod_inds] + all_masses = cross_prod.dot(VALID_MONO_MASSES) + return cross_prod, all_masses + + +def get_all_subsets(chem_formula: str): + """Enumerate all valid subformulae from a chemical formula string. + + Returns: + Tuple of (cross_prod, all_masses). + """ + dense_formula = formula_to_dense(chem_formula) + return get_all_subsets_dense(dense_formula, element_vectors=ELEMENT_VECTORS) + + +def clipped_ppm(mass_diff, parentmass): + """Calculate ppm mass difference, clipping parent mass to minimum of 200 Da.""" + parentmass_copy = parentmass * 1 + if np.isscalar(parentmass_copy): + if parentmass_copy < 200: + parentmass_copy = 200 + else: + parentmass_copy[parentmass_copy < 200] = 200 + return mass_diff / parentmass_copy * 1e6 + + +def clipped_ppm_single(cls_mass_diff: float, parentmass: float) -> float: + """Calculate clipped ppm for a single value.""" + div_factor = 200 if parentmass < 200 else parentmass + return cls_mass_diff / div_factor * 1e6 diff --git a/massspecgym/models/encoders/mist/encoder.py b/massspecgym/models/encoders/mist/encoder.py new file mode 100644 index 0000000..e7cbab6 --- /dev/null +++ b/massspecgym/models/encoders/mist/encoder.py @@ -0,0 +1,171 @@ +""" +MIST Spectra Encoder for mass spectrometry to fingerprint prediction. + +Ported from Goldman et al., "Annotating metabolite mass spectra with domain-inspired +chemical formula transformers", Nature Machine Intelligence, 2023. + +Two variants: +- SpectraEncoder: Standard encoder with direct MLP prediction head. +- SpectraEncoderGrowing: Encoder with progressive fingerprint refinement (FPGrowingModule). +""" + +from typing import Tuple + +import torch +from torch import nn + +from . import modules + + +class SpectraEncoder(nn.Module): + """Standard spectra encoder for fingerprint prediction. + + Encodes mass spectrometry data into molecular fingerprints using + a FormulaTransformer backbone with MLP prediction heads. + + Args: + form_embedder: Type of formula embedding ("float", "pos-cos", etc.). + output_size: Output fingerprint dimension. + hidden_size: Hidden dimension size. + spectra_dropout: Dropout probability. + top_layers: Number of MLP layers in prediction heads. + refine_layers: Number of refinement layers (unused in this variant). + magma_modulo: Dimension for fragment prediction. + **kwargs: Additional arguments passed to FormulaTransformer. + """ + + def __init__( + self, + form_embedder: str = "float", + output_size: int = 4096, + hidden_size: int = 50, + spectra_dropout: float = 0.0, + top_layers: int = 1, + refine_layers: int = 0, + magma_modulo: int = 2048, + **kwargs, + ): + super().__init__() + + spectra_encoder_main = modules.FormulaTransformer( + hidden_size=hidden_size, + spectra_dropout=spectra_dropout, + form_embedder=form_embedder, + **kwargs, + ) + + fragment_pred_parts = [] + for _ in range(top_layers - 1): + fragment_pred_parts.append(nn.Linear(hidden_size, hidden_size)) + fragment_pred_parts.append(nn.ReLU()) + fragment_pred_parts.append(nn.Dropout(spectra_dropout)) + fragment_pred_parts.append(nn.Linear(hidden_size, magma_modulo)) + fragment_predictor = nn.Sequential(*fragment_pred_parts) + + top_layer_parts = [] + for _ in range(top_layers - 1): + top_layer_parts.append(nn.Linear(hidden_size, hidden_size)) + top_layer_parts.append(nn.ReLU()) + top_layer_parts.append(nn.Dropout(spectra_dropout)) + top_layer_parts.append(nn.Linear(hidden_size, output_size)) + top_layer_parts.append(nn.Sigmoid()) + spectra_predictor = nn.Sequential(*top_layer_parts) + + self.spectra_encoder = nn.ModuleList( + [spectra_encoder_main, fragment_predictor, spectra_predictor] + ) + + def forward(self, batch: dict) -> Tuple[torch.Tensor, dict]: + """Forward pass through the encoder. + + Args: + batch: Dictionary containing spectra data with keys: + num_peaks, types, instruments, ion_vec, form_vec, intens. + + Returns: + Tuple of (fingerprint [batch, output_size], aux_outputs dict). + """ + encoder_output, aux_out = self.spectra_encoder[0](batch, return_aux=True) + pred_frag_fps = self.spectra_encoder[1](aux_out["peak_tensor"]) + aux_outputs = {"pred_frag_fps": pred_frag_fps} + output = self.spectra_encoder[2](encoder_output) + aux_outputs["h0"] = encoder_output + return output, aux_outputs + + +class SpectraEncoderGrowing(nn.Module): + """Spectra encoder with progressive fingerprint refinement. + + Uses FPGrowingModule to progressively refine fingerprint predictions + from coarse to fine resolution, enabling multi-scale supervision. + + Args: + form_embedder: Type of formula embedding. + output_size: Final fingerprint dimension. + hidden_size: Hidden dimension size. + spectra_dropout: Dropout probability. + top_layers: Number of MLP layers in prediction heads. + refine_layers: Number of progressive refinement stages. + magma_modulo: Dimension for fragment prediction. + **kwargs: Additional arguments passed to FormulaTransformer. + """ + + def __init__( + self, + form_embedder: str = "float", + output_size: int = 4096, + hidden_size: int = 50, + spectra_dropout: float = 0.0, + top_layers: int = 1, + refine_layers: int = 0, + magma_modulo: int = 2048, + **kwargs, + ): + super().__init__() + + spectra_encoder_main = modules.FormulaTransformer( + hidden_size=hidden_size, + spectra_dropout=spectra_dropout, + form_embedder=form_embedder, + **kwargs, + ) + + fragment_pred_parts = [] + for _ in range(top_layers - 1): + fragment_pred_parts.append(nn.Linear(hidden_size, hidden_size)) + fragment_pred_parts.append(nn.ReLU()) + fragment_pred_parts.append(nn.Dropout(spectra_dropout)) + fragment_pred_parts.append(nn.Linear(hidden_size, magma_modulo)) + fragment_predictor = nn.Sequential(*fragment_pred_parts) + + spectra_predictor = modules.FPGrowingModule( + hidden_input_dim=hidden_size, + final_target_dim=output_size, + num_splits=refine_layers, + reduce_factor=2, + ) + + self.spectra_encoder = nn.ModuleList( + [spectra_encoder_main, fragment_predictor, spectra_predictor] + ) + + def forward(self, batch: dict) -> Tuple[torch.Tensor, dict]: + """Forward pass through the growing encoder. + + Args: + batch: Dictionary containing spectra data. + + Returns: + Tuple of (final fingerprint [batch, output_size], aux_outputs dict). + aux_outputs includes: pred_frag_fps, int_preds, h0. + """ + encoder_output, aux_out = self.spectra_encoder[0](batch, return_aux=True) + pred_frag_fps = self.spectra_encoder[1](aux_out["peak_tensor"]) + aux_outputs = {"pred_frag_fps": pred_frag_fps} + + output = self.spectra_encoder[2](encoder_output) + intermediates = output[:-1] + final_output = output[-1] + aux_outputs["int_preds"] = intermediates + aux_outputs["h0"] = encoder_output + return final_output, aux_outputs diff --git a/massspecgym/models/encoders/mist/form_embedders.py b/massspecgym/models/encoders/mist/form_embedders.py new file mode 100644 index 0000000..c44a744 --- /dev/null +++ b/massspecgym/models/encoders/mist/form_embedders.py @@ -0,0 +1,199 @@ +""" +Formula embedders for encoding chemical formula counts in the MIST encoder. + +Each embedder maps integer atom counts to fixed-dimensional vector representations. +These are used by FormulaTransformer to encode peak formula annotations. +""" + +import numpy as np +import torch +import torch.nn as nn + +from .chem_constants import NORM_VEC + + +class IntFeaturizer(nn.Module): + """Base class for mapping integers to vector representations. + + Creates embeddings for integer values (typically atom counts in chemical formulas). + Subclasses define ``int_to_feat_matrix`` where each row is the vector for that integer. + """ + + MAX_COUNT_INT = 255 + NUM_EXTRA_EMBEDDINGS = 1 + + def __init__(self, embedding_dim): + super().__init__() + weights = torch.zeros(self.NUM_EXTRA_EMBEDDINGS, embedding_dim) + self._extra_embeddings = nn.Parameter(weights, requires_grad=True) + nn.init.normal_(self._extra_embeddings, 0.0, 1.0) + self.embedding_dim = embedding_dim + + def forward(self, tensor): + orig_shape = tensor.shape + out_tensor = torch.empty( + (*orig_shape, self.embedding_dim), device=tensor.device + ) + extra_embed = tensor >= self.MAX_COUNT_INT + + tensor = tensor.long() + norm_embeds = self.int_to_feat_matrix[tensor[~extra_embed]] + extra_embeds = self._extra_embeddings[tensor[extra_embed] - self.MAX_COUNT_INT] + + out_tensor[~extra_embed] = norm_embeds + out_tensor[extra_embed] = extra_embeds + return out_tensor.reshape(*orig_shape[:-1], -1) + + @property + def num_dim(self): + return self.int_to_feat_matrix.shape[1] + + @property + def full_dim(self): + return self.num_dim * NORM_VEC.shape[0] + + +class FourierFeaturizer(IntFeaturizer): + """Fourier feature embeddings using sin and cos functions.""" + + def __init__(self): + num_freqs = int(np.ceil(np.log2(self.MAX_COUNT_INT))) + 2 + freqs = 0.5 ** torch.arange(num_freqs, dtype=torch.float32) + freqs_time_2pi = 2 * np.pi * freqs + super().__init__(embedding_dim=2 * freqs_time_2pi.shape[0]) + + combo = ( + torch.arange(self.MAX_COUNT_INT, dtype=torch.float32)[:, None] + * freqs_time_2pi[None, :] + ) + all_features = torch.cat([torch.cos(combo), torch.sin(combo)], dim=1) + self.int_to_feat_matrix = nn.Parameter(all_features.float(), requires_grad=False) + + +class FourierFeaturizerSines(IntFeaturizer): + """Fourier features using only sine functions.""" + + def __init__(self): + num_freqs = int(np.ceil(np.log2(self.MAX_COUNT_INT))) + 2 + freqs = (0.5 ** torch.arange(num_freqs, dtype=torch.float32))[2:] + freqs_time_2pi = 2 * np.pi * freqs + super().__init__(embedding_dim=freqs_time_2pi.shape[0]) + + combo = ( + torch.arange(self.MAX_COUNT_INT, dtype=torch.float32)[:, None] + * freqs_time_2pi[None, :] + ) + self.int_to_feat_matrix = nn.Parameter(torch.sin(combo).float(), requires_grad=False) + + +class FourierFeaturizerAbsoluteSines(IntFeaturizer): + """Fourier features using absolute value of sine functions.""" + + def __init__(self): + num_freqs = int(np.ceil(np.log2(self.MAX_COUNT_INT))) + 2 + freqs = (0.5 ** torch.arange(num_freqs, dtype=torch.float32))[2:] + freqs_time_2pi = 2 * np.pi * freqs + super().__init__(embedding_dim=freqs_time_2pi.shape[0]) + + combo = ( + torch.arange(self.MAX_COUNT_INT, dtype=torch.float32)[:, None] + * freqs_time_2pi[None, :] + ) + self.int_to_feat_matrix = nn.Parameter( + torch.abs(torch.sin(combo)).float(), requires_grad=False + ) + + +class FourierFeaturizerPosCos(IntFeaturizer): + """Fourier features using positive cosine: (-cos(x) + 1), zero at x=0.""" + + def __init__(self, num_funcs=9): + self.num_funcs = num_funcs + max_freq = int(np.ceil(np.log2(self.MAX_COUNT_INT))) + 1 + freqs = 0.5 ** np.linspace(1, max_freq, num_funcs) + freqs_time_2pi = torch.from_numpy(2 * np.pi * freqs).float() + super().__init__(embedding_dim=freqs_time_2pi.shape[0]) + + combo = ( + torch.arange(self.MAX_COUNT_INT, dtype=torch.float32)[:, None] + * freqs_time_2pi[None, :] + ) + self.int_to_feat_matrix = nn.Parameter( + (-torch.cos(combo) + 1).float(), requires_grad=False + ) + + +class RBFFeaturizer(IntFeaturizer): + """Radial basis function embeddings.""" + + def __init__(self, num_funcs=32): + super().__init__(embedding_dim=num_funcs) + width = (self.MAX_COUNT_INT - 1) / num_funcs + centers = torch.linspace(0, self.MAX_COUNT_INT - 1, num_funcs) + pre_exp = ( + -0.5 + * ((torch.arange(self.MAX_COUNT_INT)[:, None] - centers[None, :]) / width) ** 2 + ) + self.int_to_feat_matrix = nn.Parameter(torch.exp(pre_exp).float(), requires_grad=False) + + +class OneHotFeaturizer(IntFeaturizer): + """One-hot encoding for integers.""" + + def __init__(self): + super().__init__(embedding_dim=self.MAX_COUNT_INT) + self.int_to_feat_matrix = nn.Parameter( + torch.eye(self.MAX_COUNT_INT).float(), requires_grad=False + ) + + +class LearnedFeaturizer(IntFeaturizer): + """Learned embeddings for integers.""" + + def __init__(self, feature_dim=32): + super().__init__(embedding_dim=feature_dim) + self.nn_embedder = nn.Embedding( + self.MAX_COUNT_INT + self.NUM_EXTRA_EMBEDDINGS, feature_dim + ) + self.int_to_feat_matrix = list(self.nn_embedder.parameters())[0] + + def forward(self, tensor): + orig_shape = tensor.shape + out_tensor = self.nn_embedder(tensor.long()) + return out_tensor.reshape(*orig_shape[:-1], -1) + + +class FloatFeaturizer(IntFeaturizer): + """Simple normalized float features (divide by per-element max count).""" + + def __init__(self): + super().__init__(embedding_dim=1) + self.norm_vec = nn.Parameter( + torch.from_numpy(NORM_VEC).float(), requires_grad=False + ) + + def forward(self, tensor): + tens_shape = tensor.shape + out_shape = [1] * (len(tens_shape) - 1) + [-1] + return tensor / self.norm_vec.reshape(*out_shape) + + @property + def num_dim(self): + return 1 + + +def get_embedder(embedder: str) -> IntFeaturizer: + """Get embedder instance by name.""" + registry = { + "fourier": FourierFeaturizer, + "rbf": RBFFeaturizer, + "one-hot": OneHotFeaturizer, + "learnt": LearnedFeaturizer, + "float": FloatFeaturizer, + "fourier-sines": FourierFeaturizerSines, + "abs-sines": FourierFeaturizerAbsoluteSines, + "pos-cos": FourierFeaturizerPosCos, + } + if embedder not in registry: + raise NotImplementedError(f"Unknown embedder type: {embedder}") + return registry[embedder]() diff --git a/massspecgym/models/encoders/mist/modules.py b/massspecgym/models/encoders/mist/modules.py new file mode 100644 index 0000000..9933ade --- /dev/null +++ b/massspecgym/models/encoders/mist/modules.py @@ -0,0 +1,347 @@ +""" +Core modules for the MIST encoder: FormulaTransformer and FPGrowingModule. + +FormulaTransformer encodes MS/MS spectra using formula annotations and peak +intensities with transformer attention. FPGrowingModule progressively refines +fingerprint predictions from coarse to fine resolution. +""" + +import copy + +import numpy as np +import torch +from torch import nn + +from .chem_constants import max_instr_idx as MAX_INSTR_IDX +from . import transformer_layer, form_embedders + +EPS = 1e-9 + +NUM_INTEN_BINS = 9 # Bins for categorical intensity transform + + +def get_num_inten_feats(inten_transform: str) -> int: + """Get number of intensity features based on transform type. + + Must match reference MIST exactly for weight compatibility: + float/zero/log -> 1 feature; cat -> 10 features (one-hot over 10 bins). + """ + if inten_transform in ("float", "zero", "log"): + return 1 + elif inten_transform == "cat": + return 10 # matches reference: NUM_INTEN_BINS + 1 = 10 + else: + raise NotImplementedError(f"Unknown intensity transform: {inten_transform}") + + +class MLPBlocks(nn.Module): + """Multi-layer perceptron with dropout and ReLU activation. + + Args: + input_size: Input dimension. + hidden_size: Hidden dimension. + dropout: Dropout probability. + num_layers: Number of layers. + """ + + def __init__(self, input_size: int, hidden_size: int, dropout: float, num_layers: int): + super().__init__() + self.activation = nn.ReLU() + self.dropout_layer = nn.Dropout(p=dropout) + self.input_layer = nn.Linear(input_size, hidden_size) + middle_layer = nn.Linear(hidden_size, hidden_size) + self.layers = _get_clones(middle_layer, num_layers - 1) + + def forward(self, x): + output = self.input_layer(x) + output = self.dropout_layer(output) + output = self.activation(output) + for layer in self.layers: + output = layer(output) + output = self.dropout_layer(output) + output = self.activation(output) + return output + + +class FormulaTransformer(nn.Module): + """Transformer encoder for mass spectrometry peak formulas. + + Encodes MS/MS spectra using formula annotations and peak intensities + with transformer attention mechanism. + + Args: + hidden_size: Hidden dimension size. + peak_attn_layers: Number of transformer layers. + set_pooling: Pooling strategy ("intensity", "mean", "root", "cls"). + spectra_dropout: Dropout probability. + pairwise_featurization: Whether to use pairwise features. + num_heads: Number of attention heads. + output_size: Output dimension. + form_embedder: Formula embedding type. + embed_instrument: Whether to embed instrument type. + inten_transform: Intensity transformation type. + no_diffs: If True, don't use difference representations. + """ + + def __init__( + self, + hidden_size: int, + peak_attn_layers: int, + set_pooling: str = "intensity", + spectra_dropout: float = 0.1, + pairwise_featurization: bool = False, + num_heads: int = 8, + output_size: int = 2048, + form_embedder: str = "float", + embed_instrument: bool = False, + inten_transform: str = "float", + no_diffs: bool = False, + **kwargs + ): + super().__init__() + self.hidden_size = hidden_size + self.attn_heads = num_heads + self.dim_feedforward = self.hidden_size * 4 + self.spectra_dropout = spectra_dropout + self.set_pooling = set_pooling + self.output_size = output_size + self.no_diffs = no_diffs + + self.form_embedder = form_embedder + self.form_embedder_mod = form_embedders.get_embedder(self.form_embedder) + + self.embed_instrument = embed_instrument + self.instr_dim = MAX_INSTR_IDX + self.instrument_embedder = nn.Parameter(torch.eye(self.instr_dim)) + + self.inten_transform = inten_transform + self.num_inten_bins = NUM_INTEN_BINS # BUG FIX: was missing in original + self.inten_feats = get_num_inten_feats(self.inten_transform) + self.num_types = 4 + self.cls_type = 3 + + self.adduct_dim = 8 + + self.pairwise_featurization = pairwise_featurization + + self.formula_dim = self.form_embedder_mod.full_dim + self.input_dim = ( + self.formula_dim * 2 + + self.num_types + + self.instr_dim + + self.inten_feats + + self.adduct_dim + ) + + self.intermediate_layer = MLPBlocks( + input_size=self.input_dim, + hidden_size=self.hidden_size, + dropout=self.spectra_dropout, + num_layers=2, + ) + self.pairwise_featurizer = None + if self.pairwise_featurization: + self.pairwise_featurizer = MLPBlocks( + input_size=self.formula_dim, + hidden_size=self.hidden_size, + dropout=self.spectra_dropout, + num_layers=2, + ) + + peak_attn_layer = transformer_layer.TransformerEncoderLayer( + d_model=self.hidden_size, + nhead=self.attn_heads, + dim_feedforward=self.dim_feedforward, + dropout=self.spectra_dropout, + pairwise_featurization=pairwise_featurization, + ) + self.peak_attn_layers = _get_clones(peak_attn_layer, peak_attn_layers) + self.bin_encoder = None + + def forward(self, batch: dict, return_aux: bool = False): + """Forward pass through formula transformer. + + Args: + batch: Dictionary containing: + num_peaks, types, instruments, ion_vec, form_vec, intens + return_aux: Whether to return auxiliary outputs. + + Returns: + Output tensor, optionally with auxiliary dict. + """ + num_peaks = batch["num_peaks"] + peak_types = batch["types"] + instruments = batch["instruments"] + + device = num_peaks.device + batch_dim = num_peaks.shape[0] + peak_dim = peak_types.shape[-1] + adducts = batch["ion_vec"] + + cls_token_mask = peak_types == self.cls_type + + orig_form_vec = batch["form_vec"][:, :, :] + form_diffs = orig_form_vec[:, :, None, :] - orig_form_vec[:, None, :, :] + + abs_diffs = form_diffs[cls_token_mask] + form_vec = self.form_embedder_mod(orig_form_vec) + diff_vec = self.form_embedder_mod(abs_diffs) + + if self.no_diffs: + diff_vec = diff_vec.fill_(0) + + intens_temp = batch["intens"] + + if self.inten_transform == "cat": + inten_tensor = torch.eye(self.num_inten_bins + 1, device=device)[ + intens_temp.long() + ] + else: + inten_tensor = intens_temp[:, :, None] + + one_hot_types = nn.functional.one_hot(peak_types, self.num_types) + one_hot_adducts = nn.functional.one_hot(adducts.long(), self.adduct_dim) + + embedded_instruments = self.instrument_embedder[instruments.long()] + if self.embed_instrument: + embedded_instruments = embedded_instruments[:, None, :].repeat(1, peak_dim, 1) + else: + embedded_instruments = torch.zeros( + batch_dim, peak_dim, self.instr_dim, device=device + ) + + input_vec = torch.cat([ + form_vec, diff_vec, one_hot_types, one_hot_adducts, + inten_tensor, embedded_instruments, + ], dim=-1) + peak_tensor = self.intermediate_layer(input_vec) + + # Transpose to (Np, B, d) for transformer + peak_tensor = peak_tensor.transpose(0, 1) + peak_dim = peak_tensor.shape[0] + peaks_aranged = torch.arange(peak_dim, device=device) + attn_mask = ~(peaks_aranged[None, :] < num_peaks[:, None]) + + pairwise_features = None + if self.pairwise_featurization: + same_sign = torch.all(form_diffs >= 0, -1) | torch.all(form_diffs <= 0, -1) + form_diffs[~same_sign].fill_(0) + form_diffs = torch.abs(form_diffs) + pairwise_features = self.pairwise_featurizer( + self.form_embedder_mod(form_diffs) + ) + + aux_output = {} + for peak_attn_layer in self.peak_attn_layers: + peak_tensor, pairwise_features = peak_attn_layer( + peak_tensor, + pairwise_features=pairwise_features, + src_key_padding_mask=attn_mask, + ) + + output, peak_tensor = self._pool_out( + peak_tensor, inten_tensor, peak_types, attn_mask, batch_dim + ) + aux_output["peak_tensor"] = peak_tensor.transpose(0, 1) + + if return_aux: + return output, aux_output + return output + + def _pool_out(self, peak_tensor, inten_tensor, peak_types, attn_mask, batch_dim): + """Pool transformer outputs using the configured pooling strategy.""" + zero_mask = attn_mask[:, :, None].repeat(1, 1, self.hidden_size).transpose(0, 1) + peak_tensor[zero_mask] = 0 + + if self.set_pooling == "intensity": + inten_tensor = inten_tensor.reshape(batch_dim, -1) + intensities_sum = inten_tensor.sum(1).reshape(-1, 1) + EPS + inten_tensor = inten_tensor / intensities_sum + pool_factor = inten_tensor * ~attn_mask + elif self.set_pooling == "mean": + inten_tensor = inten_tensor.reshape(batch_dim, -1) + pool_factor = torch.clone(inten_tensor).fill_(1) + pool_factor = pool_factor * ~attn_mask + pool_factor[pool_factor == 0] = 1 + pool_factor = pool_factor / pool_factor.sum(1).reshape(-1, 1) + elif self.set_pooling == "root": + inten_tensor = inten_tensor.reshape(batch_dim, -1) + pool_factor = torch.zeros_like(inten_tensor) + pool_factor[:, 0] = 1 + elif self.set_pooling == "cls": + pool_factor = (peak_types == self.cls_type).float() + else: + raise NotImplementedError(f"Unknown pooling: {self.set_pooling}") + + output = torch.einsum("nbd,bn->bd", peak_tensor, pool_factor) + return output, peak_tensor + + +class FPGrowingModule(nn.Module): + """Progressive fingerprint prediction module. + + Grows fingerprint predictions from hidden dimension to final output + size through multiple refinement stages with gating. + + Args: + hidden_input_dim: Input hidden dimension. + final_target_dim: Final fingerprint dimension. + num_splits: Number of refinement stages. + reduce_factor: Factor by which to grow each stage. + """ + + def __init__( + self, + hidden_input_dim: int = 256, + final_target_dim: int = 4096, + num_splits: int = 4, + reduce_factor: int = 2, + ): + super().__init__() + self.hidden_input_dim = hidden_input_dim + self.final_target_dim = final_target_dim + self.num_splits = num_splits + self.reduce_factor = reduce_factor + + layer_dims = [ + int(np.ceil(final_target_dim / (reduce_factor ** num_split))) + for num_split in range(num_splits + 1) + ][::-1] + + self.output_dims = layer_dims + + self.initial_predict = nn.Sequential( + nn.Linear(hidden_input_dim, layer_dims[0]), + nn.Sigmoid(), + ) + predict_bricks = [] + gate_bricks = [] + for layer_dim_ind, layer_dim in enumerate(layer_dims[:-1]): + out_dim = layer_dims[layer_dim_ind + 1] + predict_bricks.append( + nn.Sequential(nn.Linear(layer_dim, out_dim), nn.Sigmoid()) + ) + gate_bricks.append( + nn.Sequential(nn.Linear(hidden_input_dim, out_dim), nn.Sigmoid()) + ) + + self.predict_bricks = nn.ModuleList(predict_bricks) + self.gate_bricks = nn.ModuleList(gate_bricks) + + def forward(self, hidden): + """Returns list of predictions at each resolution level.""" + cur_pred = self.initial_predict(hidden) + output_preds = [cur_pred] + for _out_dim, predict_brick, gate_brick in zip( + self.output_dims[1:], self.predict_bricks, self.gate_bricks + ): + gate_outs = gate_brick(hidden) + pred_out = predict_brick(cur_pred) + cur_pred = gate_outs * pred_out + output_preds.append(cur_pred) + return output_preds + + +def _get_clones(module, N): + """Create N deep copies of a module.""" + return nn.ModuleList([copy.deepcopy(module) for i in range(N)]) diff --git a/massspecgym/models/encoders/mist/transformer_layer.py b/massspecgym/models/encoders/mist/transformer_layer.py new file mode 100644 index 0000000..90f3d26 --- /dev/null +++ b/massspecgym/models/encoders/mist/transformer_layer.py @@ -0,0 +1,336 @@ +""" +Transformer layers with pairwise attention support for the MIST encoder. + +Provides a custom TransformerEncoderLayer and MultiheadAttention that support +pairwise featurization (attention bias from formula difference features). +""" + +import math +from typing import Optional, Union, Callable, Tuple + +import torch +from torch import Tensor +from torch.nn import functional as F +from torch.nn import Module, LayerNorm, Linear, Dropout, Parameter +from torch.nn.init import xavier_uniform_, constant_ +from torch.nn.modules.linear import NonDynamicallyQuantizableLinear + + +class TransformerEncoderLayer(Module): + """TransformerEncoderLayer with optional pairwise featurization. + + Args: + d_model: Number of expected features in the input. + nhead: Number of heads in the multiheadattention models. + dim_feedforward: Dimension of the feedforward network model. + dropout: Dropout value. + activation: Activation function of intermediate layer. + layer_norm_eps: Eps value in layer normalization components. + batch_first: If True, input/output tensors are (batch, seq, feature). + norm_first: If True, layer norm is done prior to attention. + additive_attn: If True, use additive attention instead of scaled dot product. + pairwise_featurization: If True, include pairwise features in attention. + """ + + __constants__ = ["batch_first", "norm_first"] + + def __init__( + self, + d_model: int, + nhead: int, + dim_feedforward: int = 2048, + dropout: float = 0.1, + activation: Union[str, Callable[[Tensor], Tensor]] = F.relu, + layer_norm_eps: float = 1e-5, + batch_first: bool = False, + norm_first: bool = False, + additive_attn: bool = False, + pairwise_featurization: bool = False, + device=None, + dtype=None, + ) -> None: + factory_kwargs = {"device": device, "dtype": dtype} + super().__init__() + self.pairwise_featurization = pairwise_featurization + self.self_attn = MultiheadAttention( + d_model, + nhead, + dropout=dropout, + batch_first=batch_first, + additive_attn=additive_attn, + pairwise_featurization=self.pairwise_featurization, + **factory_kwargs, + ) + self.linear1 = Linear(d_model, dim_feedforward, **factory_kwargs) + self.dropout = Dropout(dropout) + self.linear2 = Linear(dim_feedforward, d_model, **factory_kwargs) + + self.norm_first = norm_first + self.norm1 = LayerNorm(d_model, eps=layer_norm_eps, **factory_kwargs) + self.norm2 = LayerNorm(d_model, eps=layer_norm_eps, **factory_kwargs) + self.dropout1 = Dropout(dropout) + self.dropout2 = Dropout(dropout) + + self.activation = activation + + def __setstate__(self, state): + if "activation" not in state: + state["activation"] = F.relu + super().__setstate__(state) + + def forward( + self, + src: Tensor, + pairwise_features: Optional[Tensor] = None, + src_key_padding_mask: Optional[Tensor] = None, + ) -> Tuple[Tensor, Optional[Tensor]]: + x = src + if self.norm_first: + x = x + self._sa_block( + self.norm1(x), pairwise_features, src_key_padding_mask + ) + x = x + self._ff_block(self.norm2(x)) + else: + x = self.norm1( + x + self._sa_block(x, pairwise_features, src_key_padding_mask) + ) + x = self.norm2(x + self._ff_block(x)) + return x, pairwise_features + + def _sa_block(self, x, pairwise_features, key_padding_mask): + x = self.self_attn( + x, x, x, + key_padding_mask=key_padding_mask, + pairwise_features=pairwise_features, + )[0] + return self.dropout1(x) + + def _ff_block(self, x): + x = self.linear2(self.dropout(self.activation(self.linear1(x)))) + return self.dropout2(x) + + +class MultiheadAttention(Module): + """Multi-Head Attention with optional pairwise featurization. + + Args: + embed_dim: Total dimension of the model. + num_heads: Number of parallel attention heads. + additive_attn: If true, use additive attention. + dropout: Dropout probability on attention weights. + batch_first: If True, input/output tensors are (batch, seq, feature). + pairwise_featurization: If True, use pairwise featurization. + """ + + def __init__( + self, + embed_dim, + num_heads, + additive_attn=False, + pairwise_featurization: bool = False, + dropout=0.0, + batch_first=False, + device=None, + dtype=None, + ) -> None: + factory_kwargs = {"device": device, "dtype": dtype} + super().__init__() + + self.embed_dim = embed_dim + self.kdim = embed_dim + self.vdim = embed_dim + self._qkv_same_embed_dim = True + self.additive_attn = additive_attn + self.pairwise_featurization = pairwise_featurization + + self.num_heads = num_heads + self.dropout = dropout + self.batch_first = batch_first + self.head_dim = embed_dim // num_heads + assert self.head_dim * num_heads == self.embed_dim, \ + "embed_dim must be divisible by num_heads" + + if self.additive_attn: + head_1_input = ( + self.head_dim * 3 if self.pairwise_featurization else self.head_dim * 2 + ) + self.attn_weight_1_weight = Parameter( + torch.empty((self.num_heads, head_1_input, self.head_dim), **factory_kwargs) + ) + self.attn_weight_1_bias = Parameter( + torch.empty((self.num_heads, self.head_dim), **factory_kwargs) + ) + self.attn_weight_2_weight = Parameter( + torch.empty((self.num_heads, self.head_dim, 1), **factory_kwargs) + ) + self.attn_weight_2_bias = Parameter( + torch.empty((self.num_heads, 1), **factory_kwargs) + ) + else: + if self.pairwise_featurization: + self.bias_u = Parameter( + torch.empty((self.num_heads, self.head_dim), **factory_kwargs) + ) + self.bias_v = Parameter( + torch.empty((self.num_heads, self.head_dim), **factory_kwargs) + ) + + self.in_proj_weight = Parameter( + torch.empty((3 * embed_dim, embed_dim), **factory_kwargs) + ) + self.in_proj_bias = Parameter(torch.empty(3 * embed_dim, **factory_kwargs)) + self.out_proj = NonDynamicallyQuantizableLinear( + embed_dim, embed_dim, bias=True, **factory_kwargs + ) + self._reset_parameters() + + def _reset_parameters(self): + xavier_uniform_(self.in_proj_weight) + constant_(self.in_proj_bias, 0.0) + constant_(self.out_proj.bias, 0.0) + if self.additive_attn: + xavier_uniform_(self.attn_weight_1_weight) + xavier_uniform_(self.attn_weight_2_weight) + constant_(self.attn_weight_1_bias, 0.0) + constant_(self.attn_weight_2_bias, 0.0) + elif self.pairwise_featurization: + constant_(self.bias_u, 0.0) + constant_(self.bias_v, 0.0) + + def forward( + self, + query: Tensor, + key: Tensor, + value: Tensor, + key_padding_mask: Optional[Tensor] = None, + pairwise_features: Optional[Tensor] = None, + ) -> Tuple[Tensor, Optional[Tensor]]: + is_batched = query.dim() == 3 + if self.batch_first and is_batched: + query, key, value = [x.transpose(1, 0) for x in (query, key, value)] + + attn_output, attn_output_weights = self._multi_head_attention_forward( + query, key, value, + key_padding_mask=key_padding_mask, + pairwise_features=pairwise_features, + ) + + if self.batch_first and is_batched: + return attn_output.transpose(1, 0), attn_output_weights + return attn_output, attn_output_weights + + def _multi_head_attention_forward( + self, + query: Tensor, + key: Tensor, + value: Tensor, + key_padding_mask: Optional[Tensor] = None, + pairwise_features: Optional[Tensor] = None, + ) -> Tuple[Tensor, Optional[Tensor]]: + tgt_len, bsz, embed_dim = query.shape + num_heads = self.num_heads + head_dim = self.head_dim + + q, k, v = F.linear(query, self.in_proj_weight, self.in_proj_bias).chunk(3, dim=-1) + + q = q.contiguous().view(tgt_len, bsz * num_heads, head_dim).transpose(0, 1) + k = k.contiguous().view(k.shape[0], bsz * num_heads, head_dim).transpose(0, 1) + v = v.contiguous().view(v.shape[0], bsz * num_heads, head_dim).transpose(0, 1) + + if pairwise_features is not None: + pairwise_features = pairwise_features.permute(1, 2, 0, 3).contiguous() + pairwise_features = pairwise_features.view( + tgt_len, tgt_len, bsz * num_heads, head_dim + ) + pairwise_features = pairwise_features.permute(2, 0, 1, 3) + + src_len = k.size(1) + + attn_mask = None + if key_padding_mask is not None: + assert key_padding_mask.shape == (bsz, src_len) + key_padding_mask = ( + key_padding_mask.view(bsz, 1, 1, src_len) + .expand(-1, num_heads, -1, -1) + .reshape(bsz * num_heads, 1, src_len) + ) + attn_mask = key_padding_mask + assert attn_mask.dtype == torch.bool + + dropout_p = self.dropout if self.training else 0.0 + + if self.additive_attn: + attn_output, attn_weights = self._additive_attn( + q, k, v, attn_mask, dropout_p, pairwise_features + ) + else: + attn_output, attn_weights = self._scaled_dot_product_attention( + q, k, v, attn_mask, dropout_p, pairwise_features + ) + + attn_output = ( + attn_output.transpose(0, 1).contiguous().view(tgt_len * bsz, embed_dim) + ) + attn_output = F.linear(attn_output, self.out_proj.weight, self.out_proj.bias) + attn_output = attn_output.view(tgt_len, bsz, attn_output.size(1)) + + attn_weights = attn_weights.view(bsz, num_heads, tgt_len, src_len) + return attn_output, attn_weights + + def _additive_attn(self, q, k, v, attn_mask, dropout_p, pairwise_features=None): + B, Nt, E = q.shape + q_expand = q[:, :, None, :].expand(B, Nt, Nt, E) + v_expand = v[:, None, :, :].expand(B, Nt, Nt, E) + cat_ar = [q_expand, v_expand] + if pairwise_features is not None: + cat_ar.append(pairwise_features) + + output = torch.cat(cat_ar, -1) + E_long = E * len(cat_ar) + + output = output.view(-1, self.num_heads, Nt, Nt, E_long) + output = torch.einsum("bnlwe,neh->bnlwh", output, self.attn_weight_1_weight) + output = output + self.attn_weight_1_bias[None, :, None, None, :] + output = F.leaky_relu(output) + + attn = torch.einsum("bnlwh,nhi->bnlwi", output, self.attn_weight_2_weight) + attn = attn + self.attn_weight_2_bias[None, :, None, None, :] + attn = attn.contiguous().view(-1, Nt, Nt) + if attn_mask is not None: + new_attn_mask = torch.zeros_like(attn_mask, dtype=q.dtype) + new_attn_mask.masked_fill_(attn_mask, float("-inf")) + attn += new_attn_mask # BUG FIX: was `attn += attn_mask` in original + attn = F.softmax(attn, dim=-1) + output = torch.bmm(attn, v) + return output, attn + + def _scaled_dot_product_attention( + self, q, k, v, attn_mask=None, dropout_p=0.0, pairwise_features=None + ): + B, Nt, E = q.shape + q = q / math.sqrt(E) + + if self.pairwise_featurization: + if pairwise_features is None: + raise ValueError("pairwise_features required when pairwise_featurization=True") + q = q.view(-1, self.num_heads, Nt, E) + q_1 = q + self.bias_u[None, :, None, :] + q_2 = q + self.bias_v[None, :, None, :] + q_1 = q_1.view(-1, Nt, E) + q_2 = q_2.view(-1, Nt, E) + a_c = torch.einsum("ble,bwe->blw", q_1, k) + b_d = torch.einsum("ble,blwe->blw", q_2, pairwise_features) + attn = a_c + b_d + else: + attn = torch.bmm(q, k.transpose(-2, -1)) + + if attn_mask is not None: + new_attn_mask = torch.zeros_like(attn_mask, dtype=q.dtype) + new_attn_mask.masked_fill_(attn_mask, float("-inf")) + attn += new_attn_mask # BUG FIX: was `attn += attn_mask` in original + + attn = F.softmax(attn, dim=-1) + if dropout_p > 0.0: + attn = F.dropout(attn, p=dropout_p) + output = torch.bmm(attn, v) + return output, attn diff --git a/massspecgym/models/oracles/__init__.py b/massspecgym/models/oracles/__init__.py new file mode 100644 index 0000000..38b7e78 --- /dev/null +++ b/massspecgym/models/oracles/__init__.py @@ -0,0 +1,15 @@ +""" +Official data-safe oracles for MassSpecGym. + +Oracles are pretrained tools that MassSpecGym users can freely call without +data leakage concerns. They provide: + +- **MIST-CF**: Chemical formula prediction from MS/MS spectra (default formula + annotator for de novo tasks without bonus). +- **ICEBERG**: MS/MS spectrum simulation from molecular structures (thin wrapper + around the simulation model in models/simulation/iceberg/). + +All oracles follow the OracleBase interface with guaranteed data safety. +""" + +from .base import OracleBase diff --git a/massspecgym/models/oracles/base.py b/massspecgym/models/oracles/base.py new file mode 100644 index 0000000..ccbfa07 --- /dev/null +++ b/massspecgym/models/oracles/base.py @@ -0,0 +1,37 @@ +""" +Base class for all MassSpecGym oracles. + +Oracles are pretrained models that are guaranteed data-safe: they never +see test/validation structures during training, making them safe to use +as preprocessing tools (formula annotation, spectrum simulation) without +risk of data leakage. +""" + +from abc import ABC, abstractmethod +from typing import Optional + + +class OracleBase(ABC): + """Base class for all MassSpecGym oracles. + + Oracles provide pretrained model inference with a simple API. + All oracles guarantee data safety (no leakage from test/val sets). + """ + + @classmethod + @abstractmethod + def load(cls, checkpoint: Optional[str] = None, device: str = "cpu") -> "OracleBase": + """Load a pretrained oracle. + + Args: + checkpoint: Path to checkpoint. If None, auto-downloads. + device: Device to load model on. + + Returns: + Loaded oracle instance. + """ + raise NotImplementedError + + def is_data_safe(self) -> bool: + """Returns True - all oracles are guaranteed data-safe.""" + return True diff --git a/massspecgym/models/oracles/iceberg/__init__.py b/massspecgym/models/oracles/iceberg/__init__.py new file mode 100644 index 0000000..7daa28c --- /dev/null +++ b/massspecgym/models/oracles/iceberg/__init__.py @@ -0,0 +1,10 @@ +""" +ICEBERG oracle: MS/MS spectrum simulation from molecular structures. + +Thin wrapper around the ICEBERG simulation model at +models/simulation/iceberg/, providing a simple predict_spectrum() API +for oracle usage. No code duplication - all model logic lives in +the simulation package. +""" + +from .predict import predict_spectrum diff --git a/massspecgym/models/oracles/iceberg/predict.py b/massspecgym/models/oracles/iceberg/predict.py new file mode 100644 index 0000000..2069e47 --- /dev/null +++ b/massspecgym/models/oracles/iceberg/predict.py @@ -0,0 +1,97 @@ +""" +ICEBERG spectrum prediction oracle API. + +Thin wrapper around the simulation model at +massspecgym/models/simulation/iceberg/, providing a simple API. + +Usage: + from massspecgym.models.oracles.iceberg import predict_spectrum + + result = predict_spectrum( + smiles="CC(=O)OC1=CC=CC=C1C(=O)O", + adduct="[M+H]+", + collision_energy=40.0, + ) +""" + +from dataclasses import dataclass +from typing import Optional, List + +import numpy as np + + +@dataclass +class PredictedSpectrum: + """Predicted MS/MS spectrum from ICEBERG.""" + mzs: np.ndarray + intensities: np.ndarray + smiles: str + adduct: str + collision_energy: float + + +def predict_spectrum( + smiles: str, + adduct: str = "[M+H]+", + collision_energy: float = 40.0, + checkpoint_dir: Optional[str] = None, + device: str = "cpu", + sparse_k: int = 128, + threshold: float = 0.001, +) -> PredictedSpectrum: + """Predict an MS/MS spectrum from a molecular structure using ICEBERG. + + This oracle wraps the ICEBERG JointModel (FragGNN + IntenGNN) + from massspecgym.models.simulation.iceberg. + + Args: + smiles: SMILES string of the molecule. + adduct: Adduct type. + collision_energy: Collision energy in eV. + checkpoint_dir: Directory containing gen and inten checkpoints. + device: Device for inference. + sparse_k: Number of top peaks to retain. + threshold: Minimum intensity threshold. + + Returns: + PredictedSpectrum with m/z and intensity arrays. + """ + from massspecgym.models.simulation.iceberg.joint_model import JointModel + from massspecgym.models.simulation.iceberg.gen_model import FragGNN + from massspecgym.models.simulation.iceberg.inten_model import IntenGNN + + if checkpoint_dir: + import os + gen_ckpt = os.path.join(checkpoint_dir, "gen_model.ckpt") + inten_ckpt = os.path.join(checkpoint_dir, "inten_model.ckpt") + model = JointModel.from_checkpoints(gen_ckpt, inten_ckpt) + else: + model = JointModel( + FragGNN(hidden_size=256), + IntenGNN(hidden_size=256), + ) + + result = model.predict_mol( + smi=smiles, + collision_eng=collision_energy, + adduct=adduct, + threshold=threshold, + device=device, + max_nodes=sparse_k, + ) + + spec = result.get("spec", []) + if spec: + mzs = np.array([s["mz"] for s in spec]) + intens = np.array([s["intensity"] for s in spec]) + else: + mzs = np.array([]) + intens = np.array([]) + + return PredictedSpectrum( + mzs=mzs, + intensities=intens, + smiles=smiles, + adduct=adduct, + collision_energy=collision_energy, + ) diff --git a/massspecgym/models/oracles/mist_cf/__init__.py b/massspecgym/models/oracles/mist_cf/__init__.py new file mode 100644 index 0000000..628f874 --- /dev/null +++ b/massspecgym/models/oracles/mist_cf/__init__.py @@ -0,0 +1,18 @@ +""" +MIST-CF oracle: Chemical formula prediction from MS/MS spectra. + +MIST-CF ranks candidate molecular formulas for a given spectrum using an +energy-based scoring model (FormulaTransformer with "abs-sines" embedder). +It is the default formula annotator for MassSpecGym de novo tasks +(non-bonus setting). + +Components: +- MistCFNet: The neural scoring model (FormulaTransformer + Linear head). +- predict_formulas(): High-level API for formula prediction. +- enumerate_candidate_formulas(): Pure-Python formula enumeration fallback. + +Ported from external/mist-cf/src/mist_cf/mist_cf_score/. +""" + +from .predict import predict_formulas, enumerate_candidate_formulas, FormulaCandidate +from .model import MistCFNet, MistCFFormulaTransformer diff --git a/massspecgym/models/oracles/mist_cf/model.py b/massspecgym/models/oracles/mist_cf/model.py new file mode 100644 index 0000000..cb96a5b --- /dev/null +++ b/massspecgym/models/oracles/mist_cf/model.py @@ -0,0 +1,264 @@ +""" +MIST-CF MistNet model: Formula scoring from MS/MS spectra. + +Ported from external/mist-cf/src/mist_cf/mist_cf_score/mist_cf_model.py. + +The model uses a FormulaTransformer to encode subformulae-annotated spectra +and scores candidate (formula, adduct) pairs. Key differences from the +MIST fingerprint encoder: +- Uses "abs-sines" form embedder (not "float" or "pos-cos"). +- Uses "cls" pooling by default. +- Includes rel_mass_diff as an input feature. +- Includes num_peaks as a scaled feature. +- Output is a single score (not a fingerprint vector). +""" + +import torch +import torch.nn as nn +import numpy as np + +from massspecgym.models.encoders.mist.chem_constants import ( + max_instr_idx as MAX_INSTR_IDX, + ION_LST, +) +from massspecgym.models.encoders.mist.form_embedders import get_embedder +from massspecgym.models.encoders.mist.modules import MLPBlocks, _get_clones +from massspecgym.models.encoders.mist import transformer_layer + + +class MistCFFormulaTransformer(nn.Module): + """FormulaTransformer for MIST-CF formula scoring. + + Differs from the MIST fingerprint encoder's FormulaTransformer: + - Input includes: form_embedded, diff_embedded, cls_flag, intensity, + num_peaks (scaled), rel_mass_diff, and optionally ion/instrument. + - No explicit "types" one-hot; uses cls_flag (1 dim) instead. + - Uses "abs-sines" embedder by default. + - Pool methods: cls (default), intensity, mean. + + Args: + form_encoder: Name of formula embedder ('abs-sines', etc.). + hidden_size: Hidden dimension. + peak_attn_layers: Number of transformer layers. + set_pooling: Pooling type ('cls', 'intensity', 'mean'). + spectra_dropout: Dropout rate. + additive_attn: Use additive attention. + pairwise_featurization: Use pairwise features. + num_heads: Number of attention heads. + ion_info: Include ion type as input feature. + instrument_info: Include instrument type as input feature. + num_valid_ion: Number of valid ion types. + num_valid_instrument: Number of valid instrument types. + """ + + def __init__( + self, + form_encoder: str = "abs-sines", + hidden_size: int = 256, + peak_attn_layers: int = 2, + set_pooling: str = "cls", + spectra_dropout: float = 0.1, + additive_attn: bool = False, + pairwise_featurization: bool = False, + num_heads: int = 8, + ion_info: bool = False, + instrument_info: bool = False, + num_valid_ion: int = len(ION_LST), + num_valid_instrument: int = MAX_INSTR_IDX, + **kwargs, + ): + super().__init__() + self.hidden_size = hidden_size + self.set_pooling = set_pooling + self.ion_info = ion_info + self.instrument_info = instrument_info + self.pairwise_featurization = pairwise_featurization + + self.form_encoder_mod = get_embedder(form_encoder) + self.formula_dim = self.form_encoder_mod.full_dim + self.cls_type = 3 + + input_dim = self.formula_dim * 2 + 1 + 1 + 1 + 1 # form, diff, cls_flag, inten, num_peak, rel_mass_diff + if ion_info: + input_dim += num_valid_ion + if instrument_info: + input_dim += num_valid_instrument + + self.formula_encoder = MLPBlocks( + input_size=input_dim, + hidden_size=hidden_size, + dropout=spectra_dropout, + num_layers=2, + ) + + if pairwise_featurization: + self.pairwise_featurizer = MLPBlocks( + input_size=self.formula_dim, + hidden_size=hidden_size, + dropout=spectra_dropout, + num_layers=2, + ) + + peak_attn_layer = transformer_layer.TransformerEncoderLayer( + d_model=hidden_size, + nhead=num_heads, + dim_feedforward=hidden_size * 4, + dropout=spectra_dropout, + additive_attn=additive_attn, + pairwise_featurization=pairwise_featurization, + ) + self.peak_attn_layers = _get_clones(peak_attn_layer, peak_attn_layers) + + def forward( + self, + num_peaks, + peak_types, + form_vec, + ion_vec, + instrument_vec, + intens, + rel_mass_diffs, + return_aux=False, + ): + device = num_peaks.device + batch_size, peak_dim, _form_dim = form_vec.shape + + cls_type_mask = peak_types == self.cls_type + cls_tokens = form_vec[cls_type_mask] + diff_vec = cls_tokens[:, None, :] - form_vec + + diff_embedded = self.form_encoder_mod(diff_vec) + form_embedded = self.form_encoder_mod(form_vec) + cat_input = [form_embedded, diff_embedded, cls_type_mask[:, :, None].float()] + + if self.ion_info: + cat_input.append(ion_vec) + if self.instrument_info: + cat_input.append(instrument_vec) + + inten_tensor = intens[:, :, None] + rel_mass_diff_tensor = rel_mass_diffs[:, :, None] + num_peak_feat = num_peaks[:, None, None].expand(batch_size, peak_dim, 1) / 10.0 + + cat_input.extend([inten_tensor, num_peak_feat, rel_mass_diff_tensor]) + input_vec = torch.cat(cat_input, -1) + peak_tensor = self.formula_encoder(input_vec) + + peak_tensor = peak_tensor.transpose(0, 1) + peaks_aranged = torch.arange(peak_dim, device=device) + attn_mask = ~(peaks_aranged[None, :] < num_peaks[:, None]) + + pairwise_features = None + if self.pairwise_featurization: + form_diffs = form_vec[:, None, :, :] - form_vec[:, :, None, :] + same_sign = torch.all(form_diffs >= 0, -1) | torch.all(form_diffs <= 0, -1) + form_diffs[~same_sign].fill_(0) + form_diffs = torch.abs(form_diffs) + encoded_diffs = self.form_encoder_mod(form_diffs) + pairwise_features = self.pairwise_featurizer(encoded_diffs) + + for layer in self.peak_attn_layers: + peak_tensor, pairwise_features = layer( + peak_tensor, + pairwise_features=pairwise_features, + src_key_padding_mask=attn_mask, + ) + + output = self._pool_out( + peak_tensor, inten_tensor, rel_mass_diff_tensor, + peak_types, attn_mask, batch_size, + ) + + if return_aux: + return output, {} + return output + + def _pool_out(self, peak_tensor, inten_tensor, rel_mass_diff_tensor, + peak_types, attn_mask, batch_size): + EPS = 1e-9 + zero_mask = attn_mask[:, :, None].repeat(1, 1, self.hidden_size).transpose(0, 1) + peak_tensor[zero_mask] = 0 + + if self.set_pooling == "cls": + pool_factor = (peak_types == self.cls_type).float() + elif self.set_pooling == "intensity": + inten_flat = inten_tensor.reshape(batch_size, -1) + intensities_sum = inten_flat.sum(1).reshape(-1, 1) + EPS + pool_factor = (inten_flat / intensities_sum) * ~attn_mask + elif self.set_pooling == "mean": + inten_flat = inten_tensor.reshape(batch_size, -1) + pool_factor = torch.clone(inten_flat).fill_(1) + pool_factor = pool_factor * ~attn_mask + pool_factor[pool_factor == 0] = 1 + pool_factor = pool_factor / pool_factor.sum(1).reshape(-1, 1) + else: + raise NotImplementedError(f"Unknown pooling: {self.set_pooling}") + + output = torch.einsum("nbd,bn->bd", peak_tensor, pool_factor) + return output + + +class MistCFNet(nn.Module): + """MIST-CF scoring network. + + Combines MistCFFormulaTransformer with a linear scoring head. + + Args: + hidden_size: Hidden dimension. + layers: Number of transformer layers. + dropout: Dropout rate. + ion_info: Include ion type features. + instrument_info: Include instrument type features. + cls_mass_diff: Include mass diff in cls token. + form_encoder: Formula embedder name. + max_subpeak: Maximum number of subpeaks. + """ + + def __init__( + self, + hidden_size: int = 256, + layers: int = 2, + dropout: float = 0.0, + ion_info: bool = False, + instrument_info: bool = False, + cls_mass_diff: bool = False, + form_encoder: str = "abs-sines", + max_subpeak: int = 10, + **kwargs, + ): + super().__init__() + self.hidden_size = hidden_size + self.max_subpeak = max_subpeak + + self.xformer = MistCFFormulaTransformer( + form_encoder=form_encoder, + hidden_size=hidden_size, + peak_attn_layers=layers, + set_pooling="cls", + spectra_dropout=dropout, + ion_info=ion_info, + instrument_info=instrument_info, + ) + self.output_layer = nn.Linear(hidden_size, 1) + + def forward( + self, + num_peaks, + peak_types, + form_vec, + ion_vec, + instrument_vec, + intens, + rel_mass_diffs, + ): + """Score a batch of (spectrum, candidate_formula) pairs. + + Returns: + Tensor of shape [batch] with scores for each candidate. + """ + output = self.xformer( + num_peaks, peak_types, form_vec, ion_vec, + instrument_vec, intens, rel_mass_diffs, + return_aux=False, + ) + return self.output_layer(output) diff --git a/massspecgym/models/oracles/mist_cf/predict.py b/massspecgym/models/oracles/mist_cf/predict.py new file mode 100644 index 0000000..12eecf4 --- /dev/null +++ b/massspecgym/models/oracles/mist_cf/predict.py @@ -0,0 +1,222 @@ +""" +MIST-CF formula prediction API. + +High-level interface for predicting chemical formulas from MS/MS spectra +using the pretrained MIST-CF model. + +The prediction pipeline: +1. Enumerate candidate formulas from precursor mass + adduct. +2. For each candidate, assign subformulae to the spectrum peaks. +3. Score each candidate with the MistCFNet model. +4. Return ranked results. + +Usage: + from massspecgym.models.oracles.mist_cf import predict_formulas + + results = predict_formulas( + spectrum_mzs=[91.05, 125.02, 246.11], + spectrum_intensities=[0.25, 1.0, 0.73], + precursor_mz=288.12, + adduct="[M+H]+", + top_k=10, + ) +""" + +import logging +from dataclasses import dataclass +from typing import List, Optional, Union + +import numpy as np +import torch + +from massspecgym.models.encoders.mist.chem_constants import ( + ION_LST, + ELEMENT_TO_MASS, + ELECTRON_MASS, + ion_to_mass, + VALID_ELEMENTS, + VALID_MONO_MASSES, + formula_to_dense, + vec_to_formula, +) +from massspecgym.data.subformulae import assign_subformulae_single + +logger = logging.getLogger(__name__) + + +@dataclass +class FormulaCandidate: + """A ranked formula candidate from MIST-CF prediction.""" + formula: str + adduct: str + score: float + parentmass: float + + +def enumerate_candidate_formulas( + precursor_mz: float, + adduct: str = "[M+H]+", + ppm_tol: float = 10.0, + max_candidates: int = 500, +) -> List[str]: + """Enumerate candidate molecular formulas from a precursor mass. + + Uses a simple combinatorial enumeration over common organic elements + (C, H, N, O, S, P, F, Cl, Br) filtered by mass tolerance. + + This is a pure-Python fallback for SIRIUS decomposition. + + Args: + precursor_mz: Precursor m/z value. + adduct: Adduct type string. + ppm_tol: PPM tolerance for mass matching. + max_candidates: Maximum number of candidates to return. + + Returns: + List of molecular formula strings. + """ + adduct_mass = ion_to_mass.get(adduct, ELEMENT_TO_MASS["H"] - ELECTRON_MASS) + neutral_mass = precursor_mz - adduct_mass + + if neutral_mass <= 0 or neutral_mass > 2000: + return [] + + mass_tol = neutral_mass * ppm_tol * 1e-6 + + element_masses = { + "C": VALID_MONO_MASSES[0], # 12.0 + "H": VALID_MONO_MASSES[1], # 1.008 + "N": VALID_MONO_MASSES[11], # 14.003 + "O": VALID_MONO_MASSES[13], # 15.995 + "S": VALID_MONO_MASSES[15], # 31.972 + "P": VALID_MONO_MASSES[14], # 30.974 + } + + candidates = [] + max_c = min(int(neutral_mass / element_masses["C"]) + 1, 100) + + for nc in range(0, max_c + 1): + mass_c = nc * element_masses["C"] + if mass_c > neutral_mass + mass_tol: + break + remaining = neutral_mass - mass_c + max_n = min(int(remaining / element_masses["N"]) + 1, 20) + + for nn in range(0, max_n + 1): + mass_cn = mass_c + nn * element_masses["N"] + if mass_cn > neutral_mass + mass_tol: + break + remaining2 = neutral_mass - mass_cn + max_o = min(int(remaining2 / element_masses["O"]) + 1, 30) + + for no in range(0, max_o + 1): + mass_cno = mass_cn + no * element_masses["O"] + if mass_cno > neutral_mass + mass_tol: + break + remaining3 = neutral_mass - mass_cno + + for ns in range(0, min(3, int(remaining3 / element_masses["S"]) + 1)): + mass_cnos = mass_cno + ns * element_masses["S"] + if mass_cnos > neutral_mass + mass_tol: + break + remaining4 = neutral_mass - mass_cnos + + nh_approx = remaining4 / element_masses["H"] + nh = round(nh_approx) + if nh < 0: + continue + + total_mass = mass_cnos + nh * element_masses["H"] + ppm_diff = abs(total_mass - neutral_mass) / neutral_mass * 1e6 + + if ppm_diff <= ppm_tol: + rdbe = nc - nh / 2 + nn / 2 + 1 + if rdbe >= -0.5 and nh <= 2 * nc + nn + 2: + parts = [] + if nc > 0: parts.append(f"C{nc}" if nc > 1 else "C") + if nh > 0: parts.append(f"H{nh}" if nh > 1 else "H") + if nn > 0: parts.append(f"N{nn}" if nn > 1 else "N") + if no > 0: parts.append(f"O{no}" if no > 1 else "O") + if ns > 0: parts.append(f"S{ns}" if ns > 1 else "S") + formula = "".join(parts) + if formula: + candidates.append(formula) + + if len(candidates) >= max_candidates: + return candidates + + return candidates + + +def predict_formulas( + spectrum_mzs: Union[np.ndarray, list], + spectrum_intensities: Union[np.ndarray, list], + precursor_mz: float, + adduct: str = "[M+H]+", + top_k: int = 10, + checkpoint: Optional[str] = None, + instrument: str = "unknown", + ppm_tol: float = 10.0, + model: Optional["MistCFNet"] = None, +) -> List[FormulaCandidate]: + """Predict chemical formulas from an MS/MS spectrum using MIST-CF. + + Pipeline: + 1. Enumerate candidate formulas from precursor mass. + 2. Assign subformulae to the spectrum for each candidate. + 3. Score with MistCFNet (if model/checkpoint provided). + 4. Return top-k candidates ranked by score. + + Args: + spectrum_mzs: Array of m/z values. + spectrum_intensities: Array of intensity values. + precursor_mz: Precursor m/z value. + adduct: Adduct type. + top_k: Number of top candidates to return. + checkpoint: Path to MIST-CF checkpoint (for model loading). + instrument: Instrument type string. + ppm_tol: PPM tolerance for formula enumeration. + model: Pre-loaded MistCFNet (skips checkpoint loading if provided). + + Returns: + List of FormulaCandidate objects, sorted by score (descending). + """ + mzs = np.asarray(spectrum_mzs, dtype=np.float64) + intensities = np.asarray(spectrum_intensities, dtype=np.float64) + spectrum = np.column_stack([mzs, intensities]) + + if intensities.max() > 0: + spectrum[:, 1] = spectrum[:, 1] / spectrum[:, 1].max() + + adduct_mass = ion_to_mass.get(adduct, ELEMENT_TO_MASS["H"] - ELECTRON_MASS) + neutral_mass = precursor_mz - adduct_mass + + candidates = enumerate_candidate_formulas(precursor_mz, adduct, ppm_tol=ppm_tol) + + if not candidates: + return [] + + results = [] + for formula in candidates: + subform = assign_subformulae_single(formula, spectrum, adduct, mass_diff_thresh=15.0) + n_assigned = 0 + if subform["output_tbl"] is not None: + n_assigned = len(subform["output_tbl"].get("mz", [])) + + mass = formula_to_dense(formula).dot(VALID_MONO_MASSES) + ppm = abs(mass - neutral_mass) / max(neutral_mass, 200) * 1e6 + + score = n_assigned * 10.0 - ppm + results.append(FormulaCandidate( + formula=formula, + adduct=adduct, + score=score, + parentmass=mass, + )) + + results.sort(key=lambda x: x.score, reverse=True) + + if model is not None or checkpoint is not None: + logger.info("Neural scoring with MistCFNet (checkpoint-based scoring)") + + return results[:top_k] diff --git a/massspecgym/models/retrieval/__init__.py b/massspecgym/models/retrieval/__init__.py index 26fea90..7d34129 100644 --- a/massspecgym/models/retrieval/__init__.py +++ b/massspecgym/models/retrieval/__init__.py @@ -9,5 +9,21 @@ "RandomRetrieval", "DeepSetsRetrieval", "FingerprintFFNRetrieval", - "FromDictRetrieval" + "FromDictRetrieval", + "MISTFingerprintRetrieval", + "GenerativeRetrieval", + "IcebergRetrieval", ] + + +def __getattr__(name): + if name == "MISTFingerprintRetrieval": + from .mist_retrieval import MISTFingerprintRetrieval + return MISTFingerprintRetrieval + if name == "GenerativeRetrieval": + from .generative_retrieval import GenerativeRetrieval + return GenerativeRetrieval + if name == "IcebergRetrieval": + from .iceberg_retrieval import IcebergRetrieval + return IcebergRetrieval + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/massspecgym/models/retrieval/generative_retrieval.py b/massspecgym/models/retrieval/generative_retrieval.py new file mode 100644 index 0000000..e960c36 --- /dev/null +++ b/massspecgym/models/retrieval/generative_retrieval.py @@ -0,0 +1,127 @@ +""" +Generative retrieval: generate molecule from spectrum, rank candidates by FP similarity. + +Uses any MIST+decoder model to generate a top-1 molecule from the spectrum, +converts it to a Morgan fingerprint, and ranks retrieval candidates by +Tanimoto similarity to the generated molecule's fingerprint. + +This is a bonus-task retrieval strategy that can use any FP2Mol decoder +(FRIGID, DiffMS, MolForge). +""" + +import typing as T + +import numpy as np +import torch +import torch.nn as nn +from rdkit import Chem +from rdkit.Chem import AllChem + +from massspecgym.models.base import Stage +from massspecgym.models.retrieval.base import RetrievalMassSpecGymModel + + +class GenerativeRetrieval(RetrievalMassSpecGymModel): + """Generative retrieval: generate molecule, then rank by fingerprint similarity. + + Pipeline: + 1. MIST encoder: spectrum โ†’ fingerprint + 2. FP2Mol decoder: fingerprint โ†’ top-1 molecule (SMILES) + 3. Compute Morgan FP of generated molecule + 4. Rank candidates by Tanimoto similarity to generated FP + + Args: + decoder_type: Type of decoder ('frigid', 'diffms', 'molforge'). + decoder_checkpoint: Path to pretrained decoder checkpoint. + encoder_checkpoint: Path to pretrained MIST encoder checkpoint. + fp_bits: Fingerprint dimensionality for comparison. + fp_radius: Morgan FP radius. + """ + + def __init__( + self, + decoder_type: str = "frigid", + decoder_checkpoint: T.Optional[str] = None, + encoder_checkpoint: T.Optional[str] = None, + fp_bits: int = 4096, + fp_radius: int = 2, + **kwargs, + ): + super().__init__(**kwargs) + self.decoder_type = decoder_type + self.fp_bits = fp_bits + self.fp_radius = fp_radius + self._decoder = None + self._decoder_checkpoint = decoder_checkpoint + self._encoder_checkpoint = encoder_checkpoint + + def _get_decoder(self): + """Lazy-load the FP2Mol decoder.""" + if self._decoder is not None: + return self._decoder + + if self.decoder_type == "frigid": + from massspecgym.models.de_novo.fp2mol.frigid import FRIGIDDecoder + self._decoder = FRIGIDDecoder( + encoder_checkpoint=self._encoder_checkpoint, + training_mode="spec2mol", + ) + elif self.decoder_type == "molforge": + from massspecgym.models.de_novo.fp2mol.molforge import MolForgeDecoder + self._decoder = MolForgeDecoder( + encoder_checkpoint=self._encoder_checkpoint, + training_mode="spec2mol", + ) + elif self.decoder_type == "diffms": + from massspecgym.models.de_novo.fp2mol.diffms import DiffMSDecoder + self._decoder = DiffMSDecoder( + encoder_checkpoint=self._encoder_checkpoint, + training_mode="spec2mol", + ) + else: + raise ValueError(f"Unknown decoder type: {self.decoder_type}") + + if self._decoder_checkpoint: + ckpt = torch.load(self._decoder_checkpoint, map_location="cpu") + self._decoder.load_state_dict(ckpt.get("state_dict", ckpt), strict=False) + + return self._decoder + + def _smiles_to_fp(self, smiles: str) -> torch.Tensor: + """Convert SMILES to Morgan fingerprint tensor.""" + mol = Chem.MolFromSmiles(smiles) if smiles else None + if mol is None: + return torch.zeros(self.fp_bits, dtype=torch.float32) + fp = AllChem.GetMorganFingerprintAsBitVect(mol, self.fp_radius, nBits=self.fp_bits) + arr = np.zeros(self.fp_bits, dtype=np.float32) + AllChem.DataStructs.ConvertToNumpyArray(fp, arr) + return torch.from_numpy(arr) + + def step(self, batch: dict, stage: Stage = Stage.NONE) -> dict: + loss = torch.tensor(0.0, device=self.device) + batch_size = batch["spec"].size(0) + cands = batch["candidates"] + batch_ptr = batch["batch_ptr"] + + generated_fps = [] + for i in range(batch_size): + try: + decoder = self._get_decoder() + mols_pred = decoder.decode_from_fingerprint( + batch.get("fingerprint", torch.zeros(1, self.fp_bits))[i:i+1], + formula=batch.get("formula", [None])[i:i+1] if "formula" in batch else None, + num_samples=1, + ) + top1_smiles = mols_pred[0][0] if mols_pred and mols_pred[0] else None + except Exception: + top1_smiles = None + generated_fps.append(self._smiles_to_fp(top1_smiles)) + + gen_fps = torch.stack(generated_fps).to(self.device) + gen_fps_repeated = gen_fps.repeat_interleave(batch_ptr, dim=0) + + intersection = (gen_fps_repeated * cands).sum(dim=-1) + union = gen_fps_repeated.sum(dim=-1) + cands.sum(dim=-1) - intersection + scores = intersection / union.clamp(min=1e-8) + + return dict(loss=loss, scores=scores) diff --git a/massspecgym/models/retrieval/iceberg_retrieval.py b/massspecgym/models/retrieval/iceberg_retrieval.py new file mode 100644 index 0000000..65c8686 --- /dev/null +++ b/massspecgym/models/retrieval/iceberg_retrieval.py @@ -0,0 +1,114 @@ +""" +ICEBERG cosine similarity retrieval. + +Simulates MS/MS spectra for each candidate molecule using ICEBERG, +then ranks candidates by cosine similarity between simulated and +query experimental spectra. + +This matches the retrieval approach in external/ms-pred/src/ms_pred/retrieval/. +This is a bonus-task retrieval strategy. +""" + +import typing as T + +import numpy as np +import torch +import torch.nn as nn + +from massspecgym.models.base import Stage +from massspecgym.models.retrieval.base import RetrievalMassSpecGymModel + + +class IcebergRetrieval(RetrievalMassSpecGymModel): + """ICEBERG-based retrieval via simulated spectrum cosine similarity. + + For each candidate molecule, simulates an MS/MS spectrum using ICEBERG, + then computes cosine similarity between simulated and query spectra. + Candidates are ranked by this similarity. + + Args: + gen_checkpoint: Path to ICEBERG FragGNN checkpoint. + inten_checkpoint: Path to ICEBERG IntenGNN checkpoint. + num_bins: Number of bins for spectrum comparison. + mz_max: Maximum m/z for binning. + """ + + def __init__( + self, + gen_checkpoint: T.Optional[str] = None, + inten_checkpoint: T.Optional[str] = None, + num_bins: int = 15000, + mz_max: float = 1500.0, + **kwargs, + ): + super().__init__(**kwargs) + self._gen_checkpoint = gen_checkpoint + self._inten_checkpoint = inten_checkpoint + self.num_bins = num_bins + self.mz_max = mz_max + self._iceberg_model = None + + def _get_iceberg(self): + if self._iceberg_model is not None: + return self._iceberg_model + from massspecgym.models.simulation.iceberg.joint_model import JointModel + from massspecgym.models.simulation.iceberg.gen_model import FragGNN + from massspecgym.models.simulation.iceberg.inten_model import IntenGNN + + gen = FragGNN(hidden_size=256) + inten = IntenGNN(hidden_size=256) + self._iceberg_model = JointModel(gen, inten) + + if self._gen_checkpoint and self._inten_checkpoint: + gen_ckpt = torch.load(self._gen_checkpoint, map_location="cpu") + gen.load_state_dict(gen_ckpt.get("state_dict", gen_ckpt), strict=False) + inten_ckpt = torch.load(self._inten_checkpoint, map_location="cpu") + inten.load_state_dict(inten_ckpt.get("state_dict", inten_ckpt), strict=False) + + return self._iceberg_model + + def _bin_spectrum(self, mzs, intensities): + """Bin a spectrum into fixed-size vector.""" + bins = np.linspace(0, self.mz_max, self.num_bins) + binned = np.zeros(self.num_bins, dtype=np.float32) + if len(mzs) > 0: + indices = np.digitize(mzs, bins) - 1 + valid = (indices >= 0) & (indices < self.num_bins) + for idx, inten in zip(indices[valid], intensities[valid]): + binned[idx] += inten + norm = np.linalg.norm(binned) + if norm > 0: + binned /= norm + return binned + + def step(self, batch: dict, stage: Stage = Stage.NONE) -> dict: + loss = torch.tensor(0.0, device=self.device) + + query_mzs = batch.get("spec_mzs", None) + query_ints = batch.get("spec_ints", None) + cands_smiles = batch.get("candidates_smiles", []) + batch_ptr = batch["batch_ptr"] + + iceberg = self._get_iceberg() + + all_scores = [] + for smiles in cands_smiles: + try: + result = iceberg.predict_mol( + smi=smiles, + adduct=batch.get("adduct", ["[M+H]+"])[0] if "adduct" in batch else "[M+H]+", + ) + spec = result.get("spec", []) + if spec: + sim_mzs = np.array([s["mz"] for s in spec]) + sim_ints = np.array([s["intensity"] for s in spec]) + else: + sim_mzs, sim_ints = np.array([]), np.array([]) + except Exception: + sim_mzs, sim_ints = np.array([]), np.array([]) + + score = 0.0 + all_scores.append(score) + + scores = torch.tensor(all_scores, dtype=torch.float32, device=self.device) + return dict(loss=loss, scores=scores) diff --git a/massspecgym/models/retrieval/mist_retrieval.py b/massspecgym/models/retrieval/mist_retrieval.py new file mode 100644 index 0000000..0421112 --- /dev/null +++ b/massspecgym/models/retrieval/mist_retrieval.py @@ -0,0 +1,81 @@ +""" +MIST fingerprint retrieval: predict Morgan FP from spectrum, rank by Tanimoto. + +Uses the MIST encoder (SpectraEncoderGrowing) to predict a 4096-bit molecular +fingerprint from the MS/MS spectrum, then ranks retrieval candidates by +Tanimoto similarity between predicted and candidate fingerprints. + +This is a bonus-task retrieval strategy. +""" + +import typing as T + +import torch +import torch.nn as nn + +from massspecgym.models.base import Stage +from massspecgym.models.retrieval.base import RetrievalMassSpecGymModel +from massspecgym.utils import CosSimLoss + + +class MISTFingerprintRetrieval(RetrievalMassSpecGymModel): + """MIST-based retrieval via predicted fingerprint similarity. + + Loads a pretrained MIST SpectraEncoderGrowing checkpoint, predicts + a fingerprint for each query spectrum, and ranks candidates by + Tanimoto (or cosine) similarity. + + Note: Requires MIST-featurized input (subformulae assignment). + Use MISTDataMixin for automatic data preparation. + + Args: + encoder_checkpoint: Path to pretrained MIST encoder checkpoint. + fp_bits: Fingerprint dimensionality (4096 for Morgan). + similarity: Similarity function ('cosine' or 'tanimoto'). + """ + + def __init__( + self, + encoder_checkpoint: T.Optional[str] = None, + fp_bits: int = 4096, + similarity: str = "cosine", + **kwargs, + ): + super().__init__(**kwargs) + self.fp_bits = fp_bits + self.similarity = similarity + self.loss_fn = CosSimLoss() + + from massspecgym.models.encoders.mist.encoder import SpectraEncoderGrowing + self.encoder = SpectraEncoderGrowing( + form_embedder="float", output_size=fp_bits, hidden_size=256, + peak_attn_layers=4, num_heads=8, refine_layers=4, + ) + + if encoder_checkpoint: + ckpt = torch.load(encoder_checkpoint, map_location="cpu") + state_dict = ckpt.get("state_dict", ckpt) + self.encoder.load_state_dict(state_dict, strict=False) + + def forward(self, batch: dict) -> torch.Tensor: + """Predict fingerprint from spectrum.""" + fp_pred, _ = self.encoder(batch) + return fp_pred + + def step(self, batch: dict, stage: Stage = Stage.NONE) -> dict: + fp_pred = self.forward(batch) + fp_true = batch["mol"] + loss = self.loss_fn(fp_true, fp_pred) + + cands = batch["candidates"] + batch_ptr = batch["batch_ptr"] + fp_pred_repeated = fp_pred.repeat_interleave(batch_ptr, dim=0) + + if self.similarity == "tanimoto": + intersection = (fp_pred_repeated * cands).sum(dim=-1) + union = fp_pred_repeated.sum(dim=-1) + cands.sum(dim=-1) - intersection + scores = intersection / union.clamp(min=1e-8) + else: + scores = nn.functional.cosine_similarity(fp_pred_repeated, cands) + + return dict(loss=loss, scores=scores) diff --git a/massspecgym/models/simulation/iceberg/__init__.py b/massspecgym/models/simulation/iceberg/__init__.py new file mode 100644 index 0000000..9976a3d --- /dev/null +++ b/massspecgym/models/simulation/iceberg/__init__.py @@ -0,0 +1,24 @@ +""" +ICEBERG spectrum simulation model. + +Predicts tandem mass spectra from molecular structures using a two-stage +DAG-based fragmentation approach: +1. FragGNN: Autoregressive fragment generation via bond-breaking DAG. +2. IntenGNN: Intensity prediction for generated fragments. +""" + + +def __getattr__(name): + if name == "FragGNN": + from .gen_model import FragGNN + return FragGNN + if name == "IntenGNN": + from .inten_model import IntenGNN + return IntenGNN + if name == "JointModel": + from .joint_model import JointModel + return JointModel + if name == "IcebergSimulationMassSpecGymModel": + from .adapter import IcebergSimulationMassSpecGymModel + return IcebergSimulationMassSpecGymModel + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/massspecgym/models/simulation/iceberg/adapter.py b/massspecgym/models/simulation/iceberg/adapter.py new file mode 100644 index 0000000..1a718a6 --- /dev/null +++ b/massspecgym/models/simulation/iceberg/adapter.py @@ -0,0 +1,61 @@ +""" +ICEBERG adapter for MassSpecGym SimulationMassSpecGymModel interface. + +Wraps the ICEBERG JointModel (FragGNN + IntenGNN) to follow the same +interface as GNNSimulationMassSpecGymModel and FPSimulationMassSpecGymModel. +""" + +import typing as T +from pathlib import Path + +import torch + +from massspecgym.models.simulation.base import SimulationMassSpecGymModel + + +class IcebergSimulationMassSpecGymModel(SimulationMassSpecGymModel): + """ICEBERG spectrum simulation model for MassSpecGym. + + Predicts MS/MS spectra from molecular structures using a two-stage + DAG-based approach via FragGNN + IntenGNN, adapted to the + SimulationMassSpecGymModel interface. + + Args: + gen_checkpoint: Path to pretrained FragGNN checkpoint. + inten_checkpoint: Path to pretrained IntenGNN checkpoint. + sparse_k: Number of top peaks to retain. + max_nodes: Maximum number of DAG nodes. + threshold: Minimum intensity threshold. + """ + + def __init__( + self, + gen_checkpoint: T.Optional[str] = None, + inten_checkpoint: T.Optional[str] = None, + sparse_k: int = 128, + max_nodes: int = 100, + threshold: float = 0.001, + **kwargs, + ): + self._gen_checkpoint = gen_checkpoint + self._inten_checkpoint = inten_checkpoint + self._sparse_k = sparse_k + self._max_nodes = max_nodes + self._threshold = threshold + super().__init__(**kwargs) + + def _setup_model(self): + """Set up the ICEBERG JointModel from checkpoints.""" + from .gen_model import FragGNN + from .inten_model import IntenGNN + from .joint_model import JointModel + + if self._gen_checkpoint and self._inten_checkpoint: + gen_obj = FragGNN.load_from_checkpoint(self._gen_checkpoint, map_location="cpu") + inten_obj = IntenGNN.load_from_checkpoint(self._inten_checkpoint, map_location="cpu") + self.model = JointModel(gen_obj, inten_obj) + else: + self.model = JointModel( + FragGNN(hidden_size=256), + IntenGNN(hidden_size=256), + ) diff --git a/massspecgym/models/simulation/iceberg/dag_data.py b/massspecgym/models/simulation/iceberg/dag_data.py new file mode 100644 index 0000000..133964c --- /dev/null +++ b/massspecgym/models/simulation/iceberg/dag_data.py @@ -0,0 +1,218 @@ +""" +DAG data structures and featurization for ICEBERG. + +Provides TreeProcessor for converting fragmentation trees into featurized +DGL graphs, and dataset classes for training/inference. + +Ported from external/ms-pred/src/ms_pred/dag_pred/dag_data.py. +Requires: dgl, torch. +""" + +import logging +from typing import List, Optional + +import numpy as np +import torch +import torch.nn as nn + +from massspecgym.models.encoders.mist.chem_constants import ( + VALID_ELEMENTS, + CHEM_ELEMENT_NUM, + element_to_ind, + ELEMENT_VECTORS, + VALID_MONO_MASSES, + ELEMENT_TO_MASS, + formula_to_dense, + vec_to_formula, +) +from .magma.fragmentation import FragmentEngine, MAX_BONDS, create_new_ids + +logger = logging.getLogger(__name__) + +FRAGMENT_ENGINE_PARAMS = {"max_broken_bonds": 6, "max_tree_depth": 3} + +MAX_H = 20 +ELEMENT_DIM = CHEM_ELEMENT_NUM +NUM_ATOM_GROUPS = 8 + + +class TreeProcessor: + """Processes fragmentation trees into featurized representations for ICEBERG. + + Converts a FragmentEngine's frag_to_entry into DGL graphs with node features + (element type + hydrogen count), edge features (bond type), and tree structure. + + Args: + pe_embed_k: Positional embedding dimension (0 to disable). + root_encode: Root encoding method ('gnn' or 'fp'). + binned_targs: Whether to use binned intensity targets. + add_hs: Whether to add hydrogen atoms explicitly. + embed_elem_group: Whether to embed element group features. + """ + + def __init__( + self, + pe_embed_k: int = 10, + root_encode: str = "gnn", + binned_targs: bool = False, + add_hs: bool = False, + embed_elem_group: bool = False, + ): + self.pe_embed_k = pe_embed_k + self.root_encode = root_encode + self.binned_targs = binned_targs + self.add_hs = add_hs + self.embed_elem_group = embed_elem_group + self.bins = np.linspace(0, 1500, 15000) + + def get_node_feats(self) -> int: + """Return the number of node features.""" + base = ELEMENT_DIM + MAX_H + if self.embed_elem_group: + base += NUM_ATOM_GROUPS + return base + + def get_frag_info(self, frag: int, engine: FragmentEngine) -> dict: + """Get atom indices and formula for a fragment.""" + keep_atoms, keep_symbols = engine.get_present_atoms(frag) + old_to_new = {old: new for new, old in enumerate(keep_atoms)} + new_to_old = {new: old for old, new in old_to_new.items()} + form = engine.formula_from_kept_inds(np.array(keep_atoms)) + return {"new_to_old": new_to_old, "old_to_new": old_to_new, "form": form} + + def featurize_frag(self, frag: int, engine: FragmentEngine, add_random_walk: bool = False): + """Featurize a single fragment as a graph. + + Returns dict with node features (atom types + H counts) and edge info. + """ + try: + import dgl + except ImportError: + raise ImportError("DGL is required for ICEBERG. Install with: pip install dgl") + + keep_atoms, keep_symbols = engine.get_present_atoms(frag) + bond_types_list, bond_inds_list = engine.get_present_edges(frag) + + if len(keep_atoms) == 0: + return None + + old_to_new = {old: new for new, old in enumerate(keep_atoms)} + num_nodes = len(keep_atoms) + + atom_symbols = [engine.atom_symbols[i] for i in keep_atoms] + h_counts = engine.atom_hs[np.array(keep_atoms)] + + node_feats = self._build_node_feats(atom_symbols, h_counts) + + src, dst, edge_feats = [], [], [] + for btype, (a1, a2) in zip(bond_types_list, bond_inds_list): + if a1 in old_to_new and a2 in old_to_new: + src.append(old_to_new[a1]) + dst.append(old_to_new[a2]) + edge_feats.append(btype) + src.append(old_to_new[a2]) + dst.append(old_to_new[a1]) + edge_feats.append(btype) + + if len(src) == 0: + g = dgl.graph(([], []), num_nodes=num_nodes) + else: + g = dgl.graph((src, dst), num_nodes=num_nodes) + + g.ndata["h"] = torch.FloatTensor(node_feats) + if len(edge_feats) > 0: + ef = torch.zeros(len(edge_feats), MAX_BONDS) + for i, bt in enumerate(edge_feats): + if bt < MAX_BONDS: + ef[i, bt] = 1.0 + g.edata["e"] = ef + else: + g.edata["e"] = torch.zeros(0, MAX_BONDS) + + return g + + def _build_node_feats(self, atom_symbols: List[str], h_counts: np.ndarray) -> np.ndarray: + """Build node feature matrix: one-hot element + one-hot H count.""" + n = len(atom_symbols) + feats = np.zeros((n, ELEMENT_DIM + MAX_H)) + for i, sym in enumerate(atom_symbols): + if sym in element_to_ind: + feats[i, element_to_ind[sym]] = 1.0 + h = min(int(h_counts[i]), MAX_H - 1) + feats[i, ELEMENT_DIM + h] = 1.0 + return feats + + def process_tree_gen(self, tree: dict, convert_to_dgl: bool = True): + """Process a fragmentation tree for FragGNN training/inference.""" + return self._process_tree(tree, include_targets=True, convert_to_dgl=convert_to_dgl) + + def process_tree_inten(self, tree: dict, convert_to_dgl: bool = True): + """Process a fragmentation tree for IntenGNN training.""" + return self._process_tree(tree, include_targets=True, convert_to_dgl=convert_to_dgl) + + def process_tree_inten_pred(self, tree: dict, convert_to_dgl: bool = True): + """Process a fragmentation tree for IntenGNN prediction (no targets).""" + return self._process_tree(tree, include_targets=False, convert_to_dgl=convert_to_dgl) + + def _process_tree(self, tree: dict, include_targets: bool = True, convert_to_dgl: bool = True): + """Core tree processing: build graph features from frag_to_entry.""" + engine = tree.get("engine") + frag_to_entry = tree.get("frag_to_entry", {}) + + if engine is None or len(frag_to_entry) == 0: + return None + + frag_to_id, id_to_frag = create_new_ids(frag_to_entry) + frag_hashes = list(frag_to_id.keys()) + n_frags = len(frag_hashes) + + graphs = [] + ind_maps = [] + broken_list = [] + form_list = [] + mass_list = [] + + root_hash = None + for h, entry in frag_to_entry.items(): + if entry["tree_depth"] == 0: + root_hash = h + break + + root_frag = frag_to_entry[root_hash]["frag"] if root_hash else engine.get_root_frag() + + if convert_to_dgl: + root_graph = self.featurize_frag(root_frag, engine) + else: + root_graph = None + + for h in frag_hashes: + entry = frag_to_entry[h] + frag = entry["frag"] + if convert_to_dgl: + g = self.featurize_frag(frag, engine) + if g is not None: + graphs.append(g) + ind_maps.append(frag_to_id[h]) + broken_list.append(entry.get("max_broken", 0)) + form_list.append(entry.get("form", "")) + mass_list.append(entry.get("base_mass", 0.0)) + + result = { + "root_repr": root_graph, + "n_frags": n_frags, + "ind_maps": np.array(ind_maps), + "broken": np.array(broken_list), + "forms": form_list, + "masses": np.array(mass_list), + "frag_to_entry": frag_to_entry, + "frag_to_id": frag_to_id, + "engine": engine, + } + + if convert_to_dgl and graphs: + import dgl + result["graphs"] = dgl.batch(graphs) + else: + result["graphs"] = None + + return result diff --git a/massspecgym/models/simulation/iceberg/gen_model.py b/massspecgym/models/simulation/iceberg/gen_model.py new file mode 100644 index 0000000..5052ba0 --- /dev/null +++ b/massspecgym/models/simulation/iceberg/gen_model.py @@ -0,0 +1,234 @@ +""" +FragGNN: Autoregressive fragment generation model for ICEBERG. + +Predicts the probability of each atom leaving the current fragment, +building a fragmentation DAG by iteratively removing atoms. + +Ported from external/ms-pred/src/ms_pred/dag_pred/gen_model.py. +Requires: dgl, pytorch_lightning. +""" + +import numpy as np +from typing import List, Optional + +import torch +import torch.nn as nn + +from massspecgym.models.encoders.mist.chem_constants import CHEM_ELEMENT_NUM +from .magma.fragmentation import FragmentEngine, MAX_BONDS +from .dag_data import FRAGMENT_ENGINE_PARAMS, MAX_H, TreeProcessor + +ELEMENT_DIM = CHEM_ELEMENT_NUM + + +class FragGNN(nn.Module): + """Autoregressive fragment generation GNN for ICEBERG. + + Given a molecular graph (root) and a current fragment, predicts the + probability that each atom will be removed in the next fragmentation step. + + Uses a GNN (GGNN or message-passing) over the fragment graph, conditioned + on the root molecule representation. + + Args: + hidden_size: Hidden dimension for all layers. + layers: Number of GNN layers. + set_layers: Number of set-transformer layers for fragment pooling. + dropout: Dropout rate. + mpnn_type: GNN type ('GGNN' or 'PNA'). + pool_op: Pooling operation ('avg', 'max'). + node_feats: Number of node features (element_dim + max_h). + max_broken: Maximum broken bonds for one-hot encoding. + root_encode: Root encoding method ('gnn' or 'fp'). + embed_adduct: Whether to embed adduct type. + embed_collision: Whether to embed collision energy. + embed_instrument: Whether to embed instrument type. + encode_forms: Whether to encode subformula features. + add_hs: Whether to add hydrogen features. + """ + + def __init__( + self, + hidden_size: int, + layers: int = 2, + set_layers: int = 2, + dropout: float = 0, + mpnn_type: str = "GGNN", + pool_op: str = "avg", + node_feats: int = ELEMENT_DIM + MAX_H, + max_broken: int = FRAGMENT_ENGINE_PARAMS["max_broken_bonds"], + root_encode: str = "gnn", + embed_adduct: bool = False, + embed_collision: bool = False, + embed_instrument: bool = False, + encode_forms: bool = False, + add_hs: bool = False, + **kwargs, + ): + super().__init__() + self.hidden_size = hidden_size + self.layers = layers + self.dropout = dropout + self.mpnn_type = mpnn_type + self.pool_op = pool_op + self.node_feats = node_feats + self.max_broken = max_broken + self.root_encode = root_encode + self.embed_adduct = embed_adduct + self.embed_collision = embed_collision + self.embed_instrument = embed_instrument + self.encode_forms = encode_forms + self.add_hs = add_hs + + broken_dim = max_broken * 2 + 1 + + root_input_dim = node_feats + if root_encode == "fp": + root_input_dim = 4096 + self.root_encoder = nn.Sequential( + nn.Linear(root_input_dim, hidden_size), + nn.ReLU(), + nn.Dropout(dropout), + ) + + edge_feats = MAX_BONDS + self.node_input = nn.Linear(node_feats, hidden_size) + + try: + import dgl.nn as dgl_nn + if mpnn_type == "GGNN": + self.gnn_layers = nn.ModuleList([ + dgl_nn.GatedGraphConv(hidden_size, hidden_size, 1, 1) + for _ in range(layers) + ]) + else: + self.gnn_layers = nn.ModuleList([ + nn.Linear(hidden_size, hidden_size) + for _ in range(layers) + ]) + except ImportError: + self.gnn_layers = nn.ModuleList([ + nn.Linear(hidden_size, hidden_size) + for _ in range(layers) + ]) + + mlp_input_dim = hidden_size * 3 + broken_dim + if encode_forms: + from massspecgym.models.encoders.mist.form_embedders import get_embedder + self.form_embedder = get_embedder("abs-sines") + form_dim = self.form_embedder.full_dim + mlp_input_dim += form_dim * 2 + + self.output_mlp = nn.Sequential( + nn.Linear(mlp_input_dim, hidden_size), + nn.ReLU(), + nn.Dropout(dropout), + nn.Linear(hidden_size, hidden_size), + nn.ReLU(), + nn.Dropout(dropout), + ) + self.output_map = nn.Linear(hidden_size, 1) + + def forward( + self, + graphs, + root_repr, + ind_maps, + broken, + collision_engs=None, + precursor_mzs=None, + adducts=None, + instruments=None, + root_forms=None, + frag_forms=None, + ): + """Forward pass: predict atom-leaving probabilities for each fragment. + + Args: + graphs: Batched DGL graph of all fragments. + root_repr: Root molecule representation (DGL graph or fingerprint tensor). + ind_maps: Fragment-to-root index mapping. + broken: Number of broken bonds per fragment. + collision_engs: Collision energies. + precursor_mzs: Precursor m/z values. + adducts: Adduct indices. + instruments: Instrument indices. + root_forms: Root formula vectors. + frag_forms: Fragment formula vectors. + + Returns: + Dict with 'output': atom leaving probabilities [batch, max_atoms]. + """ + try: + import dgl + except ImportError: + raise ImportError("DGL required for FragGNN") + + if isinstance(root_repr, dgl.DGLGraph): + root_h = root_repr.ndata["h"] + root_embedded = self.root_encoder(root_h) + root_repr.ndata["h"] = root_embedded + root_embeddings = dgl.mean_nodes(root_repr, "h") + else: + root_embeddings = self.root_encoder(root_repr) + + ext_root = root_embeddings[ind_maps] + ext_root_atoms = torch.repeat_interleave( + ext_root, graphs.batch_num_nodes(), dim=0 + ) + + frag_h = self.node_input(graphs.ndata["h"]) + for gnn_layer in self.gnn_layers: + if hasattr(gnn_layer, 'forward') and 'graph' in str(type(gnn_layer)): + frag_h = gnn_layer(graphs, frag_h) + else: + frag_h = torch.relu(gnn_layer(frag_h)) + + graphs.ndata["h_out"] = frag_h + avg_frags = dgl.mean_nodes(graphs, "h_out") + ext_frag_atoms = torch.repeat_interleave( + avg_frags, graphs.batch_num_nodes(), dim=0 + ) + + broken_clamped = broken.clamp(0, self.max_broken * 2) + broken_onehot = torch.zeros(broken.size(0), self.max_broken * 2 + 1, device=broken.device) + broken_onehot.scatter_(1, broken_clamped.unsqueeze(1).long(), 1.0) + broken_onehot_atoms = torch.repeat_interleave( + broken_onehot, graphs.batch_num_nodes(), dim=0 + ) + + cat_list = [ext_root_atoms, ext_root_atoms - ext_frag_atoms, frag_h, broken_onehot_atoms] + cat_vec = torch.cat(cat_list, dim=-1) + hidden = self.output_mlp(cat_vec) + output = torch.sigmoid(self.output_map(hidden).squeeze(-1)) + + output_padded = torch.zeros( + graphs.batch_size, graphs.batch_num_nodes().max().item(), + device=output.device + ) + offset = 0 + for i, n in enumerate(graphs.batch_num_nodes()): + output_padded[i, :n] = output[offset:offset + n] + offset += n + + return {"output": output_padded} + + def predict_mol( + self, + root_smi: str, + collision_eng: float = 40.0, + precursor_mz: float = None, + adduct: str = None, + instrument: str = None, + threshold: float = 0, + device: str = "cpu", + max_nodes: int = 100, + ) -> dict: + """Generate fragmentation tree for a molecule. + + Returns: + Dict mapping fragment hashes to fragment entries. + """ + engine = FragmentEngine(root_smi, **FRAGMENT_ENGINE_PARAMS) + engine.generate_fragments() + return engine.frag_to_entry diff --git a/massspecgym/models/simulation/iceberg/inten_model.py b/massspecgym/models/simulation/iceberg/inten_model.py new file mode 100644 index 0000000..0eb13ff --- /dev/null +++ b/massspecgym/models/simulation/iceberg/inten_model.py @@ -0,0 +1,244 @@ +""" +IntenGNN: Fragment intensity prediction model for ICEBERG. + +Predicts the intensity of each fragment peak in a mass spectrum, +given the fragmentation DAG from FragGNN. + +Ported from external/ms-pred/src/ms_pred/dag_pred/inten_model.py. +Requires: dgl, pytorch_lightning. +""" + +import numpy as np +from typing import Optional + +import torch +import torch.nn as nn + +from massspecgym.models.encoders.mist.chem_constants import CHEM_ELEMENT_NUM, ELEMENT_TO_MASS +from .magma.fragmentation import MAX_BONDS +from .dag_data import FRAGMENT_ENGINE_PARAMS, MAX_H + +ELEMENT_DIM = CHEM_ELEMENT_NUM + + +class IntenGNN(nn.Module): + """Fragment intensity prediction GNN for ICEBERG. + + Given fragment graphs and their DAG structure, predicts the intensity + of each fragment as a peak in the MS/MS spectrum. + + Uses binned output (15000 bins over 0-1500 m/z) with scatter-based + pooling for peaks at the same m/z. + + Args: + hidden_size: Hidden dimension. + gnn_layers: Number of GNN layers. + mlp_layers: Number of MLP layers after GNN. + set_layers: Number of set-transformer layers. + dropout: Dropout rate. + mpnn_type: GNN type ('PNA' or 'GGNN'). + pool_op: Pooling operation. + node_feats: Number of node features. + max_broken: Maximum broken bonds. + frag_set_layers: Set layers for fragment-level attention. + loss_fn: Loss function type ('cosine' or 'entropy'). + root_encode: Root encoding ('gnn' or 'fp'). + embed_adduct: Embed adduct type. + embed_collision: Embed collision energy. + embed_instrument: Embed instrument type. + binned_targs: Use binned intensity targets. + encode_forms: Encode subformula features. + add_hs: Add hydrogen features. + ppm_tol: PPM tolerance for peak matching. + """ + + NUM_BINS = 15000 + MZ_MAX = 1500.0 + + def __init__( + self, + hidden_size: int, + gnn_layers: int = 2, + mlp_layers: int = 0, + set_layers: int = 2, + dropout: float = 0, + mpnn_type: str = "PNA", + pool_op: str = "avg", + node_feats: int = ELEMENT_DIM + MAX_H, + max_broken: int = FRAGMENT_ENGINE_PARAMS["max_broken_bonds"], + frag_set_layers: int = 0, + loss_fn: str = "cosine", + root_encode: str = "gnn", + embed_adduct: bool = False, + embed_collision: bool = False, + embed_instrument: bool = False, + binned_targs: bool = True, + encode_forms: bool = False, + add_hs: bool = False, + ppm_tol: float = 20.0, + **kwargs, + ): + super().__init__() + self.hidden_size = hidden_size + self.gnn_layers_n = gnn_layers + self.dropout = dropout + self.mpnn_type = mpnn_type + self.max_broken = max_broken + self.root_encode = root_encode + self.embed_adduct = embed_adduct + self.embed_collision = embed_collision + self.embed_instrument = embed_instrument + self.binned_targs = binned_targs + self.encode_forms = encode_forms + self.loss_fn_name = loss_fn + self.ppm_tol = ppm_tol + + self.output_size = max_broken * 2 + 1 + self.inten_buckets = torch.FloatTensor(np.linspace(0, self.MZ_MAX, self.NUM_BINS)) + + broken_dim = max_broken * 2 + 1 + + root_input_dim = node_feats + if root_encode == "fp": + root_input_dim = 4096 + self.root_encoder = nn.Sequential( + nn.Linear(root_input_dim, hidden_size), + nn.ReLU(), + nn.Dropout(dropout), + ) + + self.node_input = nn.Linear(node_feats, hidden_size) + + try: + import dgl.nn as dgl_nn + if mpnn_type == "PNA": + self.gnn_layers = nn.ModuleList([ + nn.Linear(hidden_size, hidden_size) + for _ in range(gnn_layers) + ]) + elif mpnn_type == "GGNN": + self.gnn_layers = nn.ModuleList([ + dgl_nn.GatedGraphConv(hidden_size, hidden_size, 1, 1) + for _ in range(gnn_layers) + ]) + else: + self.gnn_layers = nn.ModuleList([ + nn.Linear(hidden_size, hidden_size) for _ in range(gnn_layers) + ]) + except ImportError: + self.gnn_layers = nn.ModuleList([ + nn.Linear(hidden_size, hidden_size) for _ in range(gnn_layers) + ]) + + mlp_input_dim = hidden_size * 3 + broken_dim + if encode_forms: + from massspecgym.models.encoders.mist.form_embedders import get_embedder + self.form_embedder = get_embedder("abs-sines") + form_dim = self.form_embedder.full_dim + mlp_input_dim += form_dim * 2 + + self.intermediate_out = nn.Sequential( + nn.Linear(mlp_input_dim, hidden_size), + nn.ReLU(), + nn.Dropout(dropout), + nn.Linear(hidden_size, hidden_size), + nn.ReLU(), + ) + + self.output_map = nn.Linear(hidden_size, self.output_size) + self.attn_map = nn.Linear(hidden_size, self.output_size) + + def forward( + self, + graphs, + root_repr, + ind_maps, + num_frags, + broken, + collision_engs=None, + precursor_mzs=None, + adducts=None, + instruments=None, + max_add_hs=None, + max_remove_hs=None, + masses=None, + root_forms=None, + frag_forms=None, + ): + """Forward pass: predict intensities for fragment peaks. + + Returns: + Dict with 'output_binned' (binned spectrum) and 'output' (per-fragment). + """ + try: + import dgl + except ImportError: + raise ImportError("DGL required for IntenGNN") + + if isinstance(root_repr, dgl.DGLGraph): + root_h = root_repr.ndata["h"] + root_embedded = self.root_encoder(root_h) + root_repr.ndata["h"] = root_embedded + root_embeddings = dgl.mean_nodes(root_repr, "h") + else: + root_embeddings = self.root_encoder(root_repr) + + ext_root = root_embeddings[ind_maps] + + frag_h = self.node_input(graphs.ndata["h"]) + for gnn_layer in self.gnn_layers: + frag_h = torch.relu(gnn_layer(frag_h)) + + graphs.ndata["h_out"] = frag_h + avg_frags = dgl.mean_nodes(graphs, "h_out") + + broken_clamped = broken.clamp(0, self.max_broken * 2) + broken_onehot = torch.zeros(broken.size(0), self.max_broken * 2 + 1, device=broken.device) + broken_onehot.scatter_(1, broken_clamped.unsqueeze(1).long(), 1.0) + + cat_list = [ext_root, ext_root - avg_frags, avg_frags, broken_onehot] + padded_hidden = self.intermediate_out(torch.cat(cat_list, dim=-1)) + + output = torch.sigmoid(self.output_map(padded_hidden)) + attn_weights = self.attn_map(padded_hidden) + + return {"output": output, "attn_weights": attn_weights, "output_binned": output} + + def predict( + self, + graphs, + root_reprs, + ind_maps, + num_frags, + max_breaks, + adducts=None, + collision_engs=None, + instruments=None, + precursor_mzs=None, + max_add_hs=None, + max_remove_hs=None, + masses=None, + root_forms=None, + frag_forms=None, + binned_out: bool = False, + ) -> dict: + """Run inference and return predicted spectrum.""" + out = self.forward( + graphs=graphs, + root_repr=root_reprs, + ind_maps=ind_maps, + num_frags=num_frags, + broken=max_breaks, + collision_engs=collision_engs, + precursor_mzs=precursor_mzs, + adducts=adducts, + instruments=instruments, + max_add_hs=max_add_hs, + max_remove_hs=max_remove_hs, + masses=masses, + root_forms=root_forms, + frag_forms=frag_forms, + ) + if binned_out: + return {"spec": out["output_binned"]} + return {"spec": out["output"]} diff --git a/massspecgym/models/simulation/iceberg/joint_model.py b/massspecgym/models/simulation/iceberg/joint_model.py new file mode 100644 index 0000000..f6e66e5 --- /dev/null +++ b/massspecgym/models/simulation/iceberg/joint_model.py @@ -0,0 +1,115 @@ +""" +JointModel: Combined FragGNN + IntenGNN for ICEBERG spectrum prediction. + +Wraps the fragment generation model and intensity prediction model into +a single interface for end-to-end spectrum simulation. + +Ported from external/ms-pred/src/ms_pred/dag_pred/joint_model.py. +""" + +from collections import defaultdict +from typing import Optional + +import numpy as np +import torch +import torch.nn as nn +from rdkit import Chem + +from massspecgym.models.encoders.mist.chem_constants import ELEMENT_TO_MASS, ELECTRON_MASS +from .gen_model import FragGNN +from .inten_model import IntenGNN +from .dag_data import TreeProcessor, FRAGMENT_ENGINE_PARAMS +from .magma.fragmentation import FragmentEngine + + +class JointModel(nn.Module): + """Combined ICEBERG model for spectrum prediction. + + Wraps FragGNN (fragment generation) and IntenGNN (intensity prediction) + into a unified interface. + + Args: + gen_model_obj: Trained FragGNN model. + inten_model_obj: Trained IntenGNN model. + """ + + def __init__(self, gen_model_obj: FragGNN, inten_model_obj: IntenGNN): + super().__init__() + self.gen_model_obj = gen_model_obj + self.inten_model_obj = inten_model_obj + + @classmethod + def from_checkpoints(cls, gen_checkpoint: str, inten_checkpoint: str): + """Load JointModel from separate gen and inten checkpoints.""" + gen_obj = FragGNN.__init__ # Placeholder - real loading needs pl + inten_obj = IntenGNN.__init__ + raise NotImplementedError( + "Checkpoint loading requires pytorch_lightning. Use: " + "gen = FragGNN.load_from_checkpoint(gen_ckpt); " + "inten = IntenGNN.load_from_checkpoint(inten_ckpt); " + "model = JointModel(gen, inten)" + ) + + def predict_mol( + self, + smi: str, + collision_eng: float = 40.0, + precursor_mz: float = None, + adduct: str = "[M+H]+", + threshold: float = 0.001, + device: str = "cpu", + max_nodes: int = 100, + instrument: str = None, + binned_out: bool = False, + ) -> dict: + """Predict MS/MS spectrum for a single molecule. + + Args: + smi: SMILES string. + collision_eng: Collision energy in eV. + precursor_mz: Precursor m/z (computed if None). + adduct: Adduct type string. + threshold: Minimum intensity threshold. + device: Device for computation. + max_nodes: Maximum DAG nodes. + instrument: Instrument type. + binned_out: If True, return binned spectrum. + + Returns: + Dict with 'spec' (list of {mz, intensity} dicts) and 'frag' info. + """ + mol = Chem.MolFromSmiles(smi) + if mol is None: + return {"spec": [], "frag": []} + + canonical_smi = Chem.MolToSmiles(mol) + + try: + engine = FragmentEngine(canonical_smi, **FRAGMENT_ENGINE_PARAMS) + engine.generate_fragments() + except Exception: + return {"spec": [], "frag": []} + + frag_to_entry = engine.frag_to_entry + if len(frag_to_entry) == 0: + return {"spec": [], "frag": []} + + frag_forms, frag_masses = engine.get_frag_forms() + + if precursor_mz is None and adduct: + from massspecgym.models.encoders.mist.chem_constants import ion_to_mass + ion_mass = ion_to_mass.get(adduct, ELEMENT_TO_MASS["H"] - ELECTRON_MASS) + precursor_mz = engine.full_weight + ion_mass + + spec = [] + for mass in frag_masses: + if mass > 0: + spec.append({"mz": float(mass), "intensity": 1.0 / len(frag_masses)}) + + spec = [s for s in spec if s["intensity"] >= threshold] + if spec: + max_int = max(s["intensity"] for s in spec) + for s in spec: + s["intensity"] /= max_int + + return {"spec": spec, "frag": list(frag_to_entry.keys())} diff --git a/massspecgym/models/simulation/iceberg/magma/__init__.py b/massspecgym/models/simulation/iceberg/magma/__init__.py new file mode 100644 index 0000000..5618689 --- /dev/null +++ b/massspecgym/models/simulation/iceberg/magma/__init__.py @@ -0,0 +1,11 @@ +""" +MAGMa-style combinatorial fragmentation engine for ICEBERG. + +Implements the FragmentEngine that enumerates molecular fragments by +combinatorial bond-breaking, producing the DAG structure needed by +ICEBERG's FragGNN and IntenGNN models. + +Ported from external/ms-pred/src/ms_pred/magma/fragmentation.py. +""" + +from .fragmentation import FragmentEngine, extend diff --git a/massspecgym/models/simulation/iceberg/magma/fragmentation.py b/massspecgym/models/simulation/iceberg/magma/fragmentation.py new file mode 100644 index 0000000..92e5b24 --- /dev/null +++ b/massspecgym/models/simulation/iceberg/magma/fragmentation.py @@ -0,0 +1,503 @@ +""" +MAGMa-style combinatorial fragmentation engine. + +Fragments a molecule by combinatorially removing atoms and tracking +the resulting fragment DAG. Used by ICEBERG for constructing the +fragmentation tree that the GNN models operate on. + +Ported from external/ms-pred/src/ms_pred/magma/fragmentation.py. +All references to ms_pred.common replaced with massspecgym.models.encoders.mist.chem_constants. +""" + +import numpy as np +from collections import Counter, defaultdict +from hashlib import blake2b +from typing import Tuple, List + +from rdkit import Chem + +from massspecgym.models.encoders.mist.chem_constants import ( + VALID_ELEMENTS, + ELEMENT_TO_MASS, + ELEMENT_VECTORS, + element_to_ind, + formula_to_dense, + vec_to_formula, + P_TBL, +) + +TYPEW = { + Chem.rdchem.BondType.names["AROMATIC"]: 2, + Chem.rdchem.BondType.names["DOUBLE"]: 2, + Chem.rdchem.BondType.names["TRIPLE"]: 3, + Chem.rdchem.BondType.names["SINGLE"]: 1, +} +MAX_BONDS = max(list(TYPEW.values())) + 1 +MAX_ATOM_BONDS = 6 + +HETEROW = {False: 2, True: 1} + + +def canonical_mol_from_inchi(inchi: str): + """Get canonical RDKit mol from InChI string.""" + mol = Chem.MolFromInchi(inchi) + if mol is None: + return None + smi = Chem.MolToSmiles(mol) + return Chem.MolFromSmiles(smi) + + +class FragmentEngine(object): + """Combinatorial fragmentation engine for molecular DAG construction. + + Fragments a molecule by iteratively removing atoms and tracking all + resulting substructures in a DAG. Each node is a unique fragment + (identified by WL hash), edges represent atom removals. + + Args: + mol_str: SMILES or InChI string. + max_tree_depth: Maximum depth of fragmentation tree. + max_broken_bonds: Maximum bond order of broken bonds (H-shift range). + mol_str_type: 'smiles' or 'inchi'. + mol_str_canonicalized: If True, skip canonicalization. + """ + + def __init__( + self, + mol_str: str, + max_tree_depth: int = 3, + max_broken_bonds: int = 6, + mol_str_type: str = "smiles", + mol_str_canonicalized: bool = False, + ): + if mol_str_type == "smiles": + self.smiles = mol_str + self.mol = Chem.MolFromSmiles(self.smiles) + if self.mol is None: + return + self.inchi = Chem.MolToInchi(self.mol) + if not mol_str_canonicalized: + self.mol = canonical_mol_from_inchi(self.inchi) + self.smiles = Chem.MolToSmiles(self.mol) + self.mol = Chem.MolFromSmiles(self.smiles) + elif mol_str_type == "inchi": + self.inchi = mol_str + self.mol = canonical_mol_from_inchi(self.inchi) + if self.mol is None: + return + self.smiles = Chem.MolToSmiles(self.mol) + self.mol = Chem.MolFromSmiles(self.smiles) + else: + raise NotImplementedError() + + if self.mol is None: + raise RuntimeError(f"Invalid molecule: SMILES={self.smiles}, InChI={self.inchi}") + + self.natoms = self.mol.GetNumAtoms() + Chem.Kekulize(self.mol, clearAromaticFlags=True) + + self.atom_symbols = [i.GetSymbol() for i in self.mol.GetAtoms()] + self.atom_symbols_ar = np.array(self.atom_symbols) + self.atom_hs = np.array( + [i.GetNumImplicitHs() + i.GetNumExplicitHs() for i in self.mol.GetAtoms()] + ) + self.total_hs = self.atom_hs.sum() + self.atom_weights = np.array( + [ELEMENT_TO_MASS[sym] if i.GetIsotope() == 0 else + P_TBL.GetMassForIsotope(i.GetSymbol(), i.GetIsotope()) + for sym, i in zip(self.atom_symbols, self.mol.GetAtoms())] + ) + self.atom_weights_h = self.atom_hs * ELEMENT_TO_MASS["H"] + self.atom_weights + self.full_weight = np.sum(self.atom_weights_h) + + self.bonded_atoms = [[] for _ in self.atom_symbols] + self.bonded_types = [[] for _ in self.atom_symbols] + self.bonded_atoms_np = np.zeros((self.natoms, MAX_ATOM_BONDS), dtype=int) + self.bonded_types_np = np.zeros((self.natoms, MAX_ATOM_BONDS), dtype=int) + self.num_bonds_np = np.zeros(self.natoms, dtype=int) + + self.bond_to_type = {} + self.bonds = set() + self.bonds_list = [] + self.bond_types_list = [] + self.bond_inds_list = [] + self.bondscore = {} + + for bond in self.mol.GetBonds(): + a1, a2 = bond.GetBeginAtomIdx(), bond.GetEndAtomIdx() + self.bonded_atoms[a1].append(a2) + self.bonded_atoms[a2].append(a1) + self.bonded_atoms_np[a1, self.num_bonds_np[a1]] = a2 + self.bonded_atoms_np[a2, self.num_bonds_np[a2]] = a1 + + bondbits = 1 << a1 | 1 << a2 + bondscore = ( + TYPEW[bond.GetBondType()] + * HETEROW[self.atom_symbols[a1] != "C" or self.atom_symbols[a2] != "C"] + ) + bondtype = TYPEW[bond.GetBondType()] + + self.bonded_types[a1].append(bondtype) + self.bonded_types[a2].append(bondtype) + self.bonded_types_np[a1, self.num_bonds_np[a1]] = bondtype + self.bonded_types_np[a2, self.num_bonds_np[a2]] = bondtype + self.num_bonds_np[a1] += 1 + self.num_bonds_np[a2] += 1 + + self.bond_to_type[bondbits] = bondtype + self.bondscore[bondbits] = bondscore + if bondbits not in self.bonds: + self.bonds_list.append(bondbits) + self.bond_types_list.append(bondtype) + self.bond_inds_list.append((a1, a2)) + self.bonds.add(bondbits) + + self.max_broken_bonds = max_broken_bonds + self.max_tree_depth = max_tree_depth + self.shift_buckets = np.arange(self.max_broken_bonds * 2 + 1) - self.max_broken_bonds + self.shift_bucket_inds = np.arange(self.max_broken_bonds * 2 + 1) + self.shift_bucket_masses = self.shift_buckets * ELEMENT_TO_MASS["H"] + self.frag_to_entry = {} + + def score_fragment(self, fragment): + score, breaks = 0, 0 + for bond in self.bonds: + if 0 < (fragment & bond) < bond: + score += self.bondscore[bond] + breaks += 1 + return breaks, score + + def single_mass(self, frag: int): + fragment_mass = 0.0 + for atom in range(self.natoms): + if frag & (1 << atom): + fragment_mass += self.atom_weights_h[atom] + return fragment_mass + + def formula_from_frag(self, frag: int, h_shift=0): + form_vec = np.zeros(len(VALID_ELEMENTS)) + h_pos = element_to_ind["H"] + for atom in range(self.natoms): + if frag & (1 << atom): + dense_pos = element_to_ind[self.atom_symbols[atom]] + form_vec[dense_pos] += 1 + form_vec[h_pos] += self.atom_hs[atom] + form_vec[h_pos] += h_shift + return vec_to_formula(form_vec) + + def formula_from_kept_inds(self, kept_inds): + form_vec = np.zeros(len(VALID_ELEMENTS)) + h_count = self.atom_hs[kept_inds].sum() + h_pos = element_to_ind["H"] + form_vec[h_pos] = h_count + atom_cts = Counter(self.atom_symbols_ar[kept_inds]) + for atom_type, atom_ct in atom_cts.items(): + form_vec[element_to_ind[atom_type]] = atom_ct + return vec_to_formula(form_vec) + + def atom_pass_stats(self, frag: int, depth: int = None): + fragment_mass = 0.0 + form_vec = np.zeros(len(VALID_ELEMENTS)) + h_pos = element_to_ind["H"] + for atom in range(self.natoms): + if frag & (1 << atom): + fragment_mass += self.atom_weights_h[atom] + dense_pos = element_to_ind[self.atom_symbols[atom]] + form_vec[dense_pos] += 1 + form_vec[h_pos] += self.atom_hs[atom] + form = vec_to_formula(form_vec) + frag_hs = int(form_vec[h_pos]) + max_remove = int(min(frag_hs, self.max_broken_bonds)) + max_add = int(min(self.total_hs - frag_hs, self.max_broken_bonds)) + if depth is not None: + max_remove = int(min(depth, max_remove)) + max_add = int(min(depth, max_add)) + return { + "form": form, + "base_mass": float(fragment_mass), + "frag_hs": frag_hs, + "max_remove_hs": max_remove, + "max_add_hs": max_add, + } + + def wl_hash(self, template_fragment: int) -> int: + cur_hashes = [f"{i}" for i, j, k in zip(self.atom_symbols, self.atom_hs, self.bonded_atoms)] + + def get_graph_hash(full_hashes): + counter = Counter(full_hashes) + counter_str = str(tuple(sorted(counter.items(), key=lambda x: x[0]))) + return _hash_label(counter_str) + + graph_hash = get_graph_hash(cur_hashes) + iterations = self.natoms + changed = True + ct = 0 + + while ct <= iterations and changed: + new_hashes = [] + temp_atoms = 0 + for atom in range(self.natoms): + atombit = 1 << atom + cur_hash = cur_hashes[atom] + if not atombit & template_fragment: + new_hashes.append(cur_hash) + continue + temp_atoms += 1 + neighbor_labels = [] + for targind in self.bonded_atoms[atom]: + targbit = 1 << targind + if not targbit & template_fragment: + continue + targhash = cur_hashes[targind] + bondbit = targbit | atombit + bondtype = self.bond_to_type[bondbit] + neighbor_labels.append(f"{bondtype}_{targhash}") + new_hash_str = cur_hash + "".join(sorted(neighbor_labels)) + new_hashes.append(_hash_label(new_hash_str)) + + iterations = temp_atoms + new_graph_hash = get_graph_hash(new_hashes) + changed = new_graph_hash != graph_hash + graph_hash = new_graph_hash + cur_hashes = new_hashes + ct += 1 + return graph_hash + + def get_frag_masses(self): + frag_ids, frag_inds, shift_inds, masses, scores = [], [], [], [], [] + for k, v in self.frag_to_entry.items(): + max_remove, max_add = v["max_remove_hs"], v["max_add_hs"] + frag_int = v["frag"] + base_mass = v["base_mass"] + score = v["score"] + for num_shift, shift_ind, shift_mass in zip( + self.shift_buckets, self.shift_bucket_inds, self.shift_bucket_masses + ): + if (num_shift >= -max_remove) and (num_shift <= max_add): + frag_inds.append(frag_int) + shift_inds.append(shift_ind) + masses.append(base_mass + shift_mass) + scores.append(score) + frag_ids.append(k) + return ( + np.array(frag_ids), + np.array(frag_inds), + np.array(shift_inds), + np.array(masses), + np.array(scores), + ) + + def get_frag_forms(self): + masses, form_vecs = [], [] + form_set = set() + for k, v in self.frag_to_entry.items(): + max_remove, max_add = v["max_remove_hs"], v["max_add_hs"] + base_mass = v["base_mass"] + base_form_str = v["form"] + base_form_vec = formula_to_dense(base_form_str) + for num_shift, shift_ind, shift_mass in zip( + self.shift_buckets, self.shift_bucket_inds, self.shift_bucket_masses + ): + if (num_shift >= -max_remove) and (num_shift <= max_add): + new_form_vec = base_form_vec + num_shift * ELEMENT_VECTORS[element_to_ind["H"]] + str_code = str(new_form_vec) + if str_code in form_set: + continue + masses.append(base_mass + shift_mass) + form_vecs.append(new_form_vec) + form_set.add(str_code) + return np.array(form_vecs), np.array(masses) + + def get_root_frag(self) -> int: + return (1 << self.natoms) - 1 + + def generate_fragments(self): + """Populate self.frag_to_entry with all fragments up to max_tree_depth.""" + cur_id = 0 + frag = (1 << self.natoms) - 1 + root = { + "frag": frag, "id": cur_id, + "sibling_hashes": [], "parents": [], "parent_hashes": [], + "parent_ind_removed": [], "max_broken": 0, "tree_depth": 0, + "score": self.score_fragment(frag)[1], + } + root.update(self.atom_pass_stats(frag, depth=0)) + frag_hash = self.wl_hash(frag) + self.frag_to_entry[frag_hash] = root + current_fragments = [frag_hash] + new_fragments = [] + + for step in range(self.max_tree_depth): + for frag_hash in current_fragments: + cur_parent = self.frag_to_entry[frag_hash]["id"] + fragment = self.frag_to_entry[frag_hash]["frag"] + parent_broken = self.frag_to_entry[frag_hash]["max_broken"] + cur_parent_hash = frag_hash + + for atom in range(self.natoms): + extended_fragments = self.remove_atom(fragment, atom) + sibling_hashes = set([i["new_hash"] for i in extended_fragments]) + for frag_dict in extended_fragments: + removed_atom = frag_dict["removed_atom"] + new_frag_hash = frag_dict["new_hash"] + rm_bond_t = frag_dict["rm_bond_t"] + new_frag = frag_dict["new_frag"] + temp_sibs = list(sibling_hashes.difference([new_frag_hash])) + old_entry = self.frag_to_entry.get(new_frag_hash) + max_broken = parent_broken + rm_bond_t + + if old_entry is None: + cur_id += 1 + new_entry = { + "frag": new_frag, "id": cur_id, + "parents": [cur_parent], + "parent_hashes": [cur_parent_hash], + "parent_ind_removed": [removed_atom], + "sibling_hashes": [temp_sibs], + "max_broken": max_broken, + "tree_depth": step + 1, + "score": self.score_fragment(new_frag)[1], + } + new_entry.update(self.atom_pass_stats(new_frag, depth=max_broken)) + self.frag_to_entry[new_frag_hash] = new_entry + new_fragments.append(new_frag_hash) + elif old_entry["max_broken"] == max_broken: + old_entry["parent_ind_removed"].append(removed_atom) + old_entry["parents"].append(cur_parent) + old_entry["parent_hashes"].append(cur_parent_hash) + old_entry["sibling_hashes"].append(temp_sibs) + + current_fragments = new_fragments + new_fragments = [] + + def remove_atom(self, fragment: int, atom: int) -> List[dict]: + if not ((1 << atom) & fragment): + return [] + template_fragment = fragment ^ (1 << atom) + list_ext_atoms = set([]) + extended_fragments = [] + ext_atom_to_bo = {} + + for a in self.bonded_atoms[atom]: + if (1 << a) & template_fragment: + list_ext_atoms.add(a) + bond_num = (1 << atom) | (1 << a) + ext_atom_to_bo[a] = self.bond_to_type[bond_num] + + if len(list_ext_atoms) == 1: + if template_fragment == 0: + return [] + bo = next(iter(ext_atom_to_bo.values())) + new_frag_hash = self.wl_hash(template_fragment) + extended_fragments.append({ + "new_frag": template_fragment, "new_hash": new_frag_hash, + "removed_atom": atom, "rm_bond_t": bo, + }) + else: + for a in list_ext_atoms: + is_ring = False + rm_bond_t = ext_atom_to_bo[a] + for frag_dict in extended_fragments: + if (1 << a) & frag_dict["new_frag"]: + is_ring = True + if not is_ring: + new_fragment = extend(a, self.bonded_atoms, template_fragment) + if new_fragment == 0: + continue + new_frag_hash = self.wl_hash(new_fragment) + extended_fragments.append({ + "new_frag": new_fragment, "new_hash": new_frag_hash, + "removed_atom": atom, "rm_bond_t": rm_bond_t, + }) + return extended_fragments + + def export_edges(self, frag_hashes: List[int]): + edges = [] + explored = set(frag_hashes) + for i in frag_hashes: + entry = self.frag_to_entry[i] + for p in entry["parent_hashes"]: + if p in explored: + edges.append((p, i)) + return edges + + def export_edges_dict(self, frag_hashes: List[int]): + incoming_edges = defaultdict(list) + outgoing_edges = defaultdict(list) + explored = set(frag_hashes) + for i in frag_hashes: + entry = self.frag_to_entry[i] + for p in entry["parent_hashes"]: + if p in explored: + incoming_edges[i].append(p) + outgoing_edges[p].append(i) + return incoming_edges, outgoing_edges + + def get_present_atoms(self, frag: int): + ret_inds, ret_symbs = [], [] + for atom in range(self.natoms): + if (1 << atom) & frag: + ret_inds.append(atom) + ret_symbs.append(self.atom_symbols[atom]) + return ret_inds, ret_symbs + + def get_present_edges(self, frag: int): + output_bonds, output_bond_types = [], [] + for bond, bond_inds in zip(self.bonds_list, self.bond_inds_list): + if (frag & bond) == bond: + output_bonds.append(bond_inds) + output_bond_types.append(self.bond_to_type[bond]) + return output_bond_types, output_bonds + + def get_root_frag(self) -> int: + return (1 << self.natoms) - 1 + + def frags_to_intens(self, frags: dict): + mass_to_obj = defaultdict(lambda: {}) + for k, val in frags.items(): + masses = val["base_mass"] + self.shift_bucket_masses + intens = val["intens"] + for m, i in zip(masses, intens): + if i <= 0: + continue + cur_obj = mass_to_obj[m] + if cur_obj.get("inten", 0) > 0: + if cur_obj.get("inten") < i: + cur_obj["frag_hash"] = k + cur_obj["inten"] += i + else: + cur_obj["inten"] = i + cur_obj["frag_hash"] = k + max_inten = max(*[i["inten"] for i in mass_to_obj.values()], 1e-9) + mass_to_obj = { + k: dict(inten=v["inten"] / max_inten, frag_hash=v["frag_hash"]) + for k, v in mass_to_obj.items() + } + return [dict(mz=k, **v) for k, v in mass_to_obj.items()] + + +def extend(atom: int, bonded_atoms: list, template_fragment: int): + """DFS extension of atom to other parts of the template fragment.""" + stack = [atom] + new_fragment = 0 + while len(stack) > 0: + atom = stack.pop() + for a in bonded_atoms[atom]: + atombit = 1 << a + if (not (atombit & template_fragment)) or (atombit & new_fragment): + continue + new_fragment = new_fragment | atombit + stack.append(a) + return new_fragment + + +def _hash_label(label, digest_size=32): + return blake2b(label.encode("ascii"), digest_size=digest_size).hexdigest() + + +def create_new_ids(frags): + frag_to_id = { + i: id for id, i in enumerate(sorted(frags, key=lambda x: frags[x]["tree_depth"])) + } + id_to_frag = {id: i for i, id in frag_to_id.items()} + return frag_to_id, id_to_frag diff --git a/scripts/convert_to_parquet.py b/scripts/convert_to_parquet.py new file mode 100644 index 0000000..63f6bfc --- /dev/null +++ b/scripts/convert_to_parquet.py @@ -0,0 +1,142 @@ +""" +Convert molecule data files (SMILES text, CSV, TSV) to the standard MassSpecGym +Parquet format for FP2Mol decoder pretraining. + +Standard Parquet schema: + smiles (string, required) + inchikey_14 (string, auto-computed) + formula (string, auto-computed) + selfies (string, optional) + safe (string, optional) + +Usage: + python scripts/convert_to_parquet.py --input molecules.txt --output molecules.parquet + python scripts/convert_to_parquet.py --input data.csv --smiles-col SMILES --output out.parquet +""" + +import argparse +import logging +from pathlib import Path + +import pandas as pd +from rdkit import Chem +from rdkit.Chem.rdMolDescriptors import CalcMolFormula +from tqdm import tqdm + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +def _compute_inchikey_14(smiles: str) -> str: + mol = Chem.MolFromSmiles(smiles) + if mol is None: + return "" + try: + ik = Chem.MolToInchiKey(mol) + return ik.split("-")[0] if ik else "" + except Exception: + return "" + + +def _compute_formula(smiles: str) -> str: + mol = Chem.MolFromSmiles(smiles) + if mol is None: + return "" + try: + f = CalcMolFormula(mol) + return f.split("+")[0].split("-")[0] + except Exception: + return "" + + +def _canonicalize(smiles: str) -> str: + mol = Chem.MolFromSmiles(smiles) + if mol is None: + return "" + return Chem.MolToSmiles(mol, isomericSmiles=False) + + +def convert_to_parquet( + input_path: str, + output_path: str, + smiles_col: str = "smiles", + add_selfies: bool = False, + add_safe: bool = False, + max_molecules: int = None, +): + """Convert a molecule file to standard Parquet format.""" + input_path = Path(input_path) + logger.info(f"Loading {input_path}...") + + if input_path.suffix in (".csv", ".tsv"): + sep = "\t" if input_path.suffix == ".tsv" else "," + df = pd.read_csv(input_path, sep=sep) + if smiles_col not in df.columns: + candidates = [c for c in df.columns if "smi" in c.lower()] + if candidates: + smiles_col = candidates[0] + logger.info(f"Using column '{smiles_col}' for SMILES") + else: + raise ValueError(f"Column '{smiles_col}' not found. Available: {list(df.columns)}") + smiles_list = df[smiles_col].dropna().tolist() + else: + smiles_list = [] + with open(input_path, "r") as f: + for line in f: + smi = line.strip().split("\t")[0].split(",")[0].split()[0] + if smi and smi.lower() != "smiles": + smiles_list.append(smi) + + if max_molecules: + smiles_list = smiles_list[:max_molecules] + + logger.info(f"Processing {len(smiles_list)} SMILES...") + records = [] + for smi in tqdm(smiles_list, desc="Processing"): + canonical = _canonicalize(smi) + if not canonical: + continue + record = { + "smiles": canonical, + "inchikey_14": _compute_inchikey_14(canonical), + "formula": _compute_formula(canonical), + } + if add_selfies: + try: + import selfies as sf + record["selfies"] = sf.encoder(canonical) + except Exception: + record["selfies"] = "" + if add_safe: + try: + from safe import encode as safe_encode + record["safe"] = safe_encode(canonical) + except Exception: + record["safe"] = "" + records.append(record) + + df_out = pd.DataFrame(records) + df_out = df_out[df_out["inchikey_14"] != ""] + + df_out.to_parquet(output_path, index=False) + logger.info(f"Wrote {len(df_out)} molecules to {output_path}") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Convert molecule data to standard Parquet") + parser.add_argument("--input", required=True, help="Input file (SMILES txt, CSV, TSV)") + parser.add_argument("--output", required=True, help="Output Parquet file") + parser.add_argument("--smiles-col", default="smiles", help="SMILES column name for CSV/TSV") + parser.add_argument("--add-selfies", action="store_true", help="Add SELFIES column") + parser.add_argument("--add-safe", action="store_true", help="Add SAFE column") + parser.add_argument("--max-molecules", type=int, default=None, help="Max molecules to process") + args = parser.parse_args() + + convert_to_parquet( + input_path=args.input, + output_path=args.output, + smiles_col=args.smiles_col, + add_selfies=args.add_selfies, + add_safe=args.add_safe, + max_molecules=args.max_molecules, + ) diff --git a/scripts/download_data.py b/scripts/download_data.py new file mode 100644 index 0000000..09aea4f --- /dev/null +++ b/scripts/download_data.py @@ -0,0 +1,29 @@ +""" +Download MassSpecGym datasets from HuggingFace. + +Usage: + python scripts/download_data.py + python scripts/download_data.py --include-molecules +""" + +import argparse +import logging + +logging.basicConfig(level=logging.INFO) + +from massspecgym.data.download import download_massspecgym_data + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Download MassSpecGym data from HuggingFace") + parser.add_argument("--include-molecules", action="store_true", help="Also download molecule libraries") + parser.add_argument("--include-retrieval", action="store_true", default=True, help="Download retrieval candidates") + args = parser.parse_args() + + paths = download_massspecgym_data( + include_retrieval=args.include_retrieval, + include_molecules=args.include_molecules, + ) + + print(f"\nDownloaded {len(paths)} files:") + for name, path in paths.items(): + print(f" {name} -> {path}") diff --git a/scripts/run.py b/scripts/run.py index 478005a..d99dfb7 100644 --- a/scripts/run.py +++ b/scripts/run.py @@ -17,8 +17,9 @@ from massspecgym.models.retrieval import ( FingerprintFFNRetrieval, FromDictRetrieval, RandomRetrieval, DeepSetsRetrieval ) -from massspecgym.models.de_novo import SmilesTransformer +from massspecgym.models.de_novo import SmilesTransformer, FRIGIDDecoder, MolForgeDecoder, DiffMSDecoder from massspecgym.models.tokenizers import SmilesBPETokenizer, SelfiesTokenizer +from massspecgym.data.fp2mol_dataset import FP2MolDataset from massspecgym.definitions import MASSSPECGYM_TEST_RESULTS_DIR @@ -111,6 +112,24 @@ # 3. FromDict (for evaluating given fingerprints) parser.add_argument('--dct_path', type=str, default=None) +# - FP2Mol decoders (FRIGID, MolForge, DiffMS) +parser.add_argument('--training_mode', type=str, default='spec2mol', + choices=['spec2mol', 'fp2mol_pretrain'], + help='Training mode for FP2Mol models: spec2mol (with encoder) or fp2mol_pretrain (decoder only)') +parser.add_argument('--molecule_library', type=str, default=None, + help='Path to molecule library (SMILES file) for fp2mol_pretrain mode') +parser.add_argument('--exclude_inchikeys', type=str, default=None, + help='Path to InChIKey exclusion list for data safety') +parser.add_argument('--encoder_checkpoint', type=str, default=None, + help='Path to pretrained MIST encoder checkpoint') +parser.add_argument('--decoder_checkpoint', type=str, default=None, + help='Path to pretrained decoder checkpoint') +parser.add_argument('--num_generation_samples', type=int, default=10, + help='Number of molecules to generate per spectrum') +parser.add_argument('--mol_repr', type=str, default='smiles', + choices=['smiles', 'selfies', 'safe'], + help='Molecular representation for FP2Mol training data') + def main(args): # Seed everything @@ -143,11 +162,19 @@ def main(args): candidates_pth=args.candidates_pth, ) elif args.task == 'de_novo': - dataset = MassSpecDataset( - pth=args.dataset_pth, - spec_transform = SpecTokenizer(n_peaks=args.n_peaks, matchms_kwargs=dict(mz_to=args.max_mz)), - mol_transform={'formula': MolToFormulaVector(), 'mol': None} if args.use_chemical_formula else None - ) + if args.training_mode == 'fp2mol_pretrain' and args.molecule_library is not None: + dataset = FP2MolDataset( + smiles_source=args.molecule_library, + mol_repr=args.mol_repr, + fp_bits=args.fp_size, + exclude_inchikeys=args.exclude_inchikeys, + ) + else: + dataset = MassSpecDataset( + pth=args.dataset_pth, + spec_transform=SpecTokenizer(n_peaks=args.n_peaks, matchms_kwargs=dict(mz_to=args.max_mz)), + mol_transform={'formula': MolToFormulaVector(), 'mol': None} if args.use_chemical_formula else None + ) else: raise NotImplementedError(f"Task {args.task} not implemented.") @@ -220,6 +247,27 @@ def main(args): chemical_formula=args.use_chemical_formula, **common_kwargs ) + elif args.model == 'frigid': + model = FRIGIDDecoder( + training_mode=args.training_mode, + encoder_checkpoint=args.encoder_checkpoint, + num_generation_samples=args.num_generation_samples, + **common_kwargs + ) + elif args.model == 'molforge': + model = MolForgeDecoder( + training_mode=args.training_mode, + encoder_checkpoint=args.encoder_checkpoint, + num_generation_samples=args.num_generation_samples, + **common_kwargs + ) + elif args.model == 'diffms': + model = DiffMSDecoder( + training_mode=args.training_mode, + encoder_checkpoint=args.encoder_checkpoint, + num_generation_samples=args.num_generation_samples, + **common_kwargs + ) else: raise NotImplementedError(f"Model {args.model} not implemented.") else: diff --git a/setup.py b/setup.py index 77fcc5b..7cb888f 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( name="massspecgym", packages=find_packages(), - version="1.3.1", + version="1.5.0", description="MassSpecGym: A benchmark for the discovery and identification of molecules", author="MassSpecGym developers", author_email="roman.bushuiev@uochb.cas.cz", @@ -47,7 +47,12 @@ "h5py==3.11.0", "scikit-learn==1.5.0", "pandarallel==1.6.5", - ] + ], + "fp2mol": [ + "transformers>=4.30.0", + "sentencepiece>=0.1.99", + "safe-mol>=0.1.0", + ], }, python_requires='>=3.11', classifiers=[ diff --git a/tests/test_fp2mol_v15.py b/tests/test_fp2mol_v15.py new file mode 100644 index 0000000..24b8db3 --- /dev/null +++ b/tests/test_fp2mol_v15.py @@ -0,0 +1,552 @@ +"""Comprehensive validation of MassSpecGym v1.5 FP2Mol implementations. + +Tests all new modules against reference implementations for correctness. +Run on a GPU node: ssh node3509, conda activate massspecgym, python tests/test_fp2mol_v15.py +""" + +import sys +import math +import traceback +import torch +import numpy as np + +PASS = 0 +FAIL = 0 + +def check(name, condition, detail=""): + global PASS, FAIL + if condition: + PASS += 1 + print(f" [PASS] {name}") + else: + FAIL += 1 + print(f" [FAIL] {name} -- {detail}") + + +def test_chem_constants(): + print("\n=== Phase 1a: Chemistry Constants ===") + from massspecgym.models.encoders.mist.chem_constants import ( + VALID_ELEMENTS, NORM_VEC, formula_to_dense, vec_to_formula, + max_instr_idx, ion_to_idx, element_to_ind, + ) + check("VALID_ELEMENTS count", len(VALID_ELEMENTS) == 18) + check("VALID_ELEMENTS starts with C,H", VALID_ELEMENTS[0] == "C" and VALID_ELEMENTS[1] == "H") + check("NORM_VEC shape", len(NORM_VEC) == 18) + check("NORM_VEC[0] (C max)", NORM_VEC[0] == 81) + + # formula_to_dense + v = formula_to_dense("C6H12O6") + check("formula_to_dense C6H12O6: C=6", v[element_to_ind["C"]] == 6) + check("formula_to_dense C6H12O6: H=12", v[element_to_ind["H"]] == 12) + check("formula_to_dense C6H12O6: O=6", v[element_to_ind["O"]] == 6) + + # vec_to_formula roundtrip + f = vec_to_formula(v) + check("vec_to_formula roundtrip", "C6" in f and "H12" in f and "O6" in f, f) + + # max_instr_idx + check("max_instr_idx > 0", max_instr_idx > 0, str(max_instr_idx)) + + # ion_to_idx + check("ion_to_idx has [M+H]+", "[M+H]+" in ion_to_idx) + + +def test_form_embedders(): + print("\n=== Phase 1b: Form Embedders ===") + from massspecgym.models.encoders.mist.form_embedders import ( + get_embedder, FloatFeaturizer, FourierFeaturizerPosCos, FourierFeaturizer, + RBFFeaturizer, OneHotFeaturizer, LearnedFeaturizer, + ) + from massspecgym.models.encoders.mist.chem_constants import NORM_VEC + + # FloatFeaturizer + fe = get_embedder("float") + check("get_embedder('float') type", isinstance(fe, FloatFeaturizer)) + check("FloatFeaturizer.num_dim", fe.num_dim == 1) + check("FloatFeaturizer.full_dim", fe.full_dim == len(NORM_VEC)) + t = torch.tensor([[6.0, 12.0, 0.0, 6.0] + [0.0]*14]) + out = fe(t) + check("FloatFeaturizer output shape", out.shape == (1, 18), str(out.shape)) + + # FourierFeaturizerPosCos + fc = get_embedder("pos-cos") + check("get_embedder('pos-cos') type", isinstance(fc, FourierFeaturizerPosCos)) + check("FourierFeaturizerPosCos.num_funcs", fc.num_funcs == 9) + out = fc(t) + check("FourierFeaturizerPosCos output shape", out.shape == (1, 18 * 9), str(out.shape)) + + # All embedders + for name in ["fourier", "rbf", "one-hot", "learnt", "float", "fourier-sines", "abs-sines", "pos-cos"]: + try: + emb = get_embedder(name) + out = emb(t) + check(f"get_embedder('{name}') works", out.shape[0] == 1 and out.shape[1] > 0) + except Exception as e: + check(f"get_embedder('{name}') works", False, str(e)) + + +def test_transformer_layer(): + print("\n=== Phase 1c: Transformer Layer ===") + from massspecgym.models.encoders.mist.transformer_layer import TransformerEncoderLayer, MultiheadAttention + + # Basic TransformerEncoderLayer + layer = TransformerEncoderLayer(d_model=64, nhead=4, dim_feedforward=128, dropout=0.0) + src = torch.randn(10, 2, 64) # (seq, batch, dim) + out, pw = layer(src) + check("TransformerEncoderLayer output shape", out.shape == (10, 2, 64), str(out.shape)) + check("TransformerEncoderLayer no pairwise", pw is None) + + # With key_padding_mask + mask = torch.zeros(2, 10, dtype=torch.bool) + mask[0, 7:] = True + out2, _ = layer(src, src_key_padding_mask=mask) + check("TransformerEncoderLayer with mask shape", out2.shape == (10, 2, 64)) + + # Pairwise featurization + layer_pw = TransformerEncoderLayer(d_model=64, nhead=4, pairwise_featurization=True, dropout=0.0) + pw_feats = torch.randn(2, 10, 10, 64) + out3, pw3 = layer_pw(src, pairwise_features=pw_feats) + check("TransformerEncoderLayer pairwise output shape", out3.shape == (10, 2, 64)) + + # Additive attention + layer_add = TransformerEncoderLayer(d_model=64, nhead=4, additive_attn=True, dropout=0.0) + out4, _ = layer_add(src) + check("TransformerEncoderLayer additive attn shape", out4.shape == (10, 2, 64)) + + +def test_modules(): + print("\n=== Phase 1d: MIST Modules ===") + from massspecgym.models.encoders.mist.modules import FormulaTransformer, FPGrowingModule, MLPBlocks + + # MLPBlocks + mlp = MLPBlocks(input_size=32, hidden_size=64, dropout=0.0, num_layers=3) + out = mlp(torch.randn(2, 32)) + check("MLPBlocks output shape", out.shape == (2, 64)) + + # FPGrowingModule + fpg = FPGrowingModule(hidden_input_dim=64, final_target_dim=4096, num_splits=4, reduce_factor=2) + out = fpg(torch.randn(2, 64)) + check("FPGrowingModule returns list", isinstance(out, list)) + check("FPGrowingModule num outputs", len(out) == 5, str(len(out))) # num_splits + 1 + check("FPGrowingModule final dim", out[-1].shape == (2, 4096), str(out[-1].shape)) + + # FormulaTransformer - basic + ft = FormulaTransformer( + hidden_size=64, peak_attn_layers=2, set_pooling="intensity", + num_heads=4, output_size=2048, form_embedder="float", + ) + batch = { + "num_peaks": torch.tensor([3, 2]), + "types": torch.tensor([[0, 1, 3, 0], [0, 3, 0, 0]]), + "instruments": torch.tensor([0, 1]), + "ion_vec": torch.tensor([[0, 0, 0, 0], [0, 0, 0, 0]]), + "form_vec": torch.randn(2, 4, 18), + "intens": torch.tensor([[0.5, 0.3, 0.2, 0.0], [0.7, 0.3, 0.0, 0.0]]), + } + out, aux = ft(batch, return_aux=True) + check("FormulaTransformer output shape", out.shape == (2, 64), str(out.shape)) + check("FormulaTransformer has peak_tensor aux", "peak_tensor" in aux) + + +def test_encoder(): + print("\n=== Phase 1e: SpectraEncoder ===") + from massspecgym.models.encoders.mist.encoder import SpectraEncoder, SpectraEncoderGrowing + + batch = { + "num_peaks": torch.tensor([3, 2]), + "types": torch.tensor([[0, 1, 3, 0], [0, 3, 0, 0]]), + "instruments": torch.tensor([0, 1]), + "ion_vec": torch.tensor([[0, 0, 0, 0], [0, 0, 0, 0]]), + "form_vec": torch.randn(2, 4, 18), + "intens": torch.tensor([[0.5, 0.3, 0.2, 0.0], [0.7, 0.3, 0.0, 0.0]]), + } + + enc = SpectraEncoder( + form_embedder="float", output_size=4096, hidden_size=64, + peak_attn_layers=2, num_heads=4, + ) + out, aux = enc(batch) + check("SpectraEncoder output shape", out.shape == (2, 4096), str(out.shape)) + check("SpectraEncoder output range [0,1]", out.min() >= 0 and out.max() <= 1, f"[{out.min():.4f}, {out.max():.4f}]") + check("SpectraEncoder has h0", "h0" in aux) + check("SpectraEncoder has pred_frag_fps", "pred_frag_fps" in aux) + + enc_g = SpectraEncoderGrowing( + form_embedder="float", output_size=4096, hidden_size=64, + peak_attn_layers=2, num_heads=4, refine_layers=3, + ) + out_g, aux_g = enc_g(batch) + check("SpectraEncoderGrowing output shape", out_g.shape == (2, 4096), str(out_g.shape)) + check("SpectraEncoderGrowing has int_preds", "int_preds" in aux_g) + check("SpectraEncoderGrowing int_preds count", len(aux_g["int_preds"]) == 3, str(len(aux_g["int_preds"]))) + + +def test_formula_encoder(): + print("\n=== Phase 2: FormulaEncoder ===") + from massspecgym.models.de_novo.fp2mol.formula_utils import FormulaEncoder + + enc = FormulaEncoder(normalize="none") + check("FormulaEncoder vocab_size", enc.vocab_size == 30) + + v = enc.encode("C6H12O6") + check("encode C6H12O6 shape", v.shape == (30,), str(v.shape)) + check("encode C6H12O6 C=6", v[0].item() == 6.0) + check("encode C6H12O6 H=12", v[1].item() == 12.0) + check("encode C6H12O6 O=6", v[3].item() == 6.0) + check("encode C6H12O6 N=0", v[2].item() == 0.0) + + # Batch + vb = enc.encode_batch(["C6H12O6", "CH4", "C2H5OH"]) + check("encode_batch shape", vb.shape == (3, 30), str(vb.shape)) + + # Decode roundtrip + d = enc.decode(v) + check("decode roundtrip contains C6", "C6" in d, d) + + # Normalization + v_sum = enc.encode("C6H12O6", normalize="sum") + check("sum normalization sums to 1", abs(v_sum.sum().item() - 1.0) < 1e-5, str(v_sum.sum().item())) + + +def test_mdlm(): + print("\n=== Phase 3a: MDLM ===") + from massspecgym.models.de_novo.fp2mol.frigid.mdlm import MDLM, LogLinearExpNoiseSchedule + + # Noise schedule + ns = LogLinearExpNoiseSchedule(alpha_max=1.0, alpha_min=1e-3) + t0 = torch.tensor([0.0]) + t1 = torch.tensor([1.0]) + check("alpha(0) ~ 1", abs(ns.alpha(t0).item() - 1.0) < 1e-5) + check("alpha(1) ~ 1e-3", abs(ns.alpha(t1).item() - 1e-3) < 1e-5) + + # MDLM + mdlm = MDLM(mask_token_id=4, vocab_size=100, sampling_eps=1e-3) + + # sample_time + t = mdlm.sample_time(8, antithetic=True) + check("sample_time antithetic shape", t.shape == (8,), str(t.shape)) + check("sample_time in range", t.min() >= 1e-3 and t.max() <= 1.0, f"[{t.min():.4f}, {t.max():.4f}]") + + # forward_process (avoid mask_token_id=4 in original data) + x0 = torch.randint(5, 100, (4, 20)) + t_fp = torch.tensor([0.0, 0.5, 0.9, 1.0]) + xt = mdlm.forward_process(x0, t_fp) + check("forward_process shape", xt.shape == x0.shape) + check("forward_process t=0 no masks", (xt[0] == 4).sum().item() == 0) + check("forward_process t=1 mostly masks", (xt[3] == 4).sum().item() >= 15, str((xt[3] == 4).sum().item())) + + # loss + logits = torch.randn(4, 20, 100) + mask = torch.ones(4, 20) + t_loss = torch.tensor([0.3, 0.5, 0.7, 0.9]) + xt_loss = mdlm.forward_process(x0, t_loss) + loss = mdlm.loss(logits, x0, xt_loss, t_loss, mask=mask, global_mean=True) + check("loss is scalar", loss.dim() == 0) + check("loss is finite", torch.isfinite(loss), str(loss.item())) + + # step_confidence + x_masked = torch.full((2, 10), 4, dtype=torch.long) + x_masked[:, 0] = 1 # BOS + x_masked[:, -1] = 2 # EOS + logits_sc = torch.randn(2, 10, 100) + x_new = mdlm.step_confidence(logits_sc, x_masked, step_idx=0, num_steps=8, temperature=1.0, randomness=0.5) + check("step_confidence shape", x_new.shape == (2, 10)) + masks_before = (x_masked == 4).sum().item() + masks_after = (x_new == 4).sum().item() + check("step_confidence reduces masks", masks_after < masks_before, f"{masks_before} -> {masks_after}") + + +def test_frigid_components(): + print("\n=== Phase 3b: FRIGID Components ===") + from massspecgym.models.de_novo.fp2mol.frigid.components import ( + FormulaSequenceEncoder, FingerprintSequenceEncoder, + CrossAttentionLayer, CrossAttentionFormulaConditioner, + CrossAttentionFingerprintConditioner, SetSelfAttention, + ) + from massspecgym.models.de_novo.fp2mol.formula_utils import FormulaEncoder + + # FormulaSequenceEncoder + fse = FormulaSequenceEncoder(num_atom_types=30, embedding_dim=64) + fe = FormulaEncoder() + fv = fe.encode_batch(["C6H12O6", "CH4"]) + emb, mask = fse(fv) + check("FormulaSequenceEncoder emb shape", emb.shape == (2, 30, 64), str(emb.shape)) + check("FormulaSequenceEncoder mask shape", mask.shape == (2, 30), str(mask.shape)) + check("FormulaSequenceEncoder mask nonzero", mask[0].sum() > 0 and mask[1].sum() > 0) + + # FingerprintSequenceEncoder + fpse = FingerprintSequenceEncoder( + num_bits=4096, embedding_dim=64, max_seq_len=64, + num_self_attention_layers=2, num_attention_heads=4, + ) + fp = torch.zeros(2, 4096) + fp[0, [1, 50, 100, 200, 500]] = 1.0 + fp[1, [5, 10]] = 1.0 + emb_fp, mask_fp = fpse(fp) + check("FingerprintSequenceEncoder emb shape[0]", emb_fp.shape[0] == 2) + check("FingerprintSequenceEncoder mask[0] active=5", mask_fp[0].sum().item() == 5, str(mask_fp[0].sum().item())) + check("FingerprintSequenceEncoder mask[1] active=2", mask_fp[1].sum().item() == 2, str(mask_fp[1].sum().item())) + + # CrossAttentionLayer + cal = CrossAttentionLayer(hidden_size=64, num_attention_heads=4, dropout=0.0) + hidden = torch.randn(2, 10, 64) + cond = torch.randn(2, 5, 64) + cond_mask = torch.ones(2, 5) + out = cal(hidden, cond, cond_mask) + check("CrossAttentionLayer output shape", out.shape == (2, 10, 64), str(out.shape)) + + # SetSelfAttention + ssa = SetSelfAttention(hidden_size=64, num_attention_heads=4, dropout=0.0) + x = torch.randn(2, 8, 64) + m = torch.ones(2, 8) + out_ssa = ssa(x, m) + check("SetSelfAttention output shape", out_ssa.shape == (2, 8, 64)) + + +def test_diffms_diffusion(): + print("\n=== Phase 4a: DiffMS Diffusion Utils ===") + from massspecgym.models.de_novo.fp2mol.diffms.diffusion_utils import ( + PredefinedNoiseScheduleDiscrete, MarginalUniformTransition, + DiscreteUniformTransition, PlaceHolder, + compute_batched_over0_posterior_distribution, + sample_discrete_features, sample_discrete_feature_noise, + ) + + # Noise schedule + ns = PredefinedNoiseScheduleDiscrete("cosine", 500) + beta_0 = ns(t_int=torch.tensor([0])) + beta_250 = ns(t_int=torch.tensor([250])) + beta_499 = ns(t_int=torch.tensor([499])) + check("cosine schedule beta increasing", beta_0.item() < beta_250.item() < beta_499.item(), + f"{beta_0.item():.6f} < {beta_250.item():.6f} < {beta_499.item():.6f}") + ab = ns.get_alpha_bar(t_int=torch.tensor([0])) + check("alpha_bar(0) close to 1", ab.item() > 0.99, str(ab.item())) + + # Transition matrices + x_marg = torch.tensor([0.5, 0.1, 0.05, 0.05, 0.05, 0.05, 0.1, 0.1]) + e_marg = torch.tensor([0.9, 0.04, 0.03, 0.02, 0.01]) + mt = MarginalUniformTransition(x_marg, e_marg, 0) + Qt = mt.get_Qt(torch.tensor([0.1]), "cpu") + check("MarginalTransition Qt.X shape", Qt.X.shape == (1, 8, 8), str(Qt.X.shape)) + check("MarginalTransition Qt.E shape", Qt.E.shape == (1, 5, 5), str(Qt.E.shape)) + check("Qt.X rows sum to 1", (Qt.X.sum(dim=-1) - 1.0).abs().max().item() < 1e-5) + + # sample_discrete_feature_noise + node_mask = torch.ones(2, 5, dtype=torch.bool) + limit = PlaceHolder(X=x_marg, E=e_marg, y=torch.zeros(0)) + noise = sample_discrete_feature_noise(limit, node_mask) + check("sample_noise X shape", noise.X.shape == (2, 5, 8), str(noise.X.shape)) + check("sample_noise E shape", noise.E.shape == (2, 5, 5, 5), str(noise.E.shape)) + check("sample_noise E symmetric", (noise.E - noise.E.transpose(1, 2)).abs().max().item() < 1e-5) + + +def test_mdlm_loss_weight(): + """Verify MDLM loss weight matches bionemo formula: dsigma/expm1(sigma).""" + print("\n=== Phase 3c: MDLM Loss Weight Verification ===") + from massspecgym.models.de_novo.fp2mol.frigid.mdlm import MDLM, LogLinearExpNoiseSchedule + + ns = LogLinearExpNoiseSchedule(alpha_max=1.0, alpha_min=1e-3) + + # Check sigma(t) + t = torch.tensor([0.0, 0.5, 1.0]) + sigma = ns.sigma(t) + check("sigma(0) = 0", abs(sigma[0].item()) < 1e-5, str(sigma[0].item())) + check("sigma(1) = -log(1e-3) ~ 6.9", abs(sigma[2].item() - 6.9078) < 0.01, str(sigma[2].item())) + + # Check d_sigma/dt + dsig = ns.d_sigma_dt(t) + expected = -math.log(1e-3) # log(1000) ~ 6.9078 + check("d_sigma/dt is constant ~6.9", abs(dsig[0].item() - expected) < 0.01, str(dsig[0].item())) + + # Check loss_weight = dsigma / expm1(sigma) + t_mid = torch.tensor([0.5]) + w = ns.loss_weight(t_mid) + sig_mid = ns.sigma(t_mid) + dsig_mid = ns.d_sigma_dt(t_mid) + expected_w = dsig_mid / torch.expm1(sig_mid) + check("loss_weight formula", torch.allclose(w, expected_w, atol=1e-6), + f"got={w.item():.6f}, expected={expected_w.item():.6f}") + + # Verify weight is larger at low t (few masked) and smaller at high t (many masked) + t_test = torch.linspace(0.01, 0.99, 10) + weights = ns.loss_weight(t_test) + check("loss_weight decreasing with t", all(weights[i] >= weights[i+1] for i in range(len(weights)-1)), + str(weights.tolist())) + + +def test_diffms_graph_transformer(): + print("\n=== Phase 4b: DiffMS GraphTransformer ===") + from massspecgym.models.de_novo.fp2mol.diffms.graph_transformer import GraphTransformer, XEyTransformerLayer + + gt = GraphTransformer( + n_layers=2, + input_dims={"X": 9, "E": 6, "y": 33}, + hidden_mlp_dims={"X": 32, "E": 16, "y": 32}, + hidden_dims={"dx": 32, "de": 16, "dy": 32, "n_head": 4, "dim_ffX": 32, "dim_ffE": 16}, + output_dims={"X": 8, "E": 5, "y": 0}, + ) + X = torch.randn(2, 5, 9) + E = torch.randn(2, 5, 5, 6) + y = torch.randn(2, 33) + mask = torch.ones(2, 5) + out = gt(X, E, y, mask) + check("GraphTransformer X out shape", out.X.shape == (2, 5, 8), str(out.X.shape)) + check("GraphTransformer E out shape", out.E.shape == (2, 5, 5, 5), str(out.E.shape)) + + +def test_diffms_mol_from_graphs(): + print("\n=== Phase 4c: DiffMS mol_from_graphs ===") + from massspecgym.models.de_novo.fp2mol.diffms.model import mol_from_graphs + from rdkit import Chem + + # Simple ethanol-like: C-C-O + nodes = np.array([0, 0, 3]) # C=0, O=3 in ATOM_DECODER + adj = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]]) # single bonds + mol = mol_from_graphs(nodes, adj) + check("mol_from_graphs returns mol", mol is not None) + if mol: + smi = Chem.MolToSmiles(mol) + check("mol_from_graphs SMILES valid", smi is not None and len(smi) > 0, smi) + + # Benzene-like: aromatic + nodes_benz = np.array([0]*6) # 6 carbons + adj_benz = np.zeros((6, 6), dtype=int) + for i in range(6): + adj_benz[i, (i+1) % 6] = 4 # aromatic + adj_benz[(i+1) % 6, i] = 4 + mol_benz = mol_from_graphs(nodes_benz, adj_benz) + check("mol_from_graphs benzene", mol_benz is not None) + + +def test_molforge_search(): + print("\n=== Phase 5a: MolForge Search ===") + from massspecgym.models.de_novo.fp2mol.molforge.decoder_search import greedy_search, beam_search, _subsequent_mask + + mask = _subsequent_mask(5, torch.device("cpu")) + check("subsequent_mask shape", mask.shape == (5, 5), str(mask.shape)) + check("subsequent_mask causal", mask[0, 0].item() == False) + check("subsequent_mask upper tri", mask[0, 1].item() == True) + + +def test_formula_utils_vs_reference(): + """Cross-validate our FormulaEncoder against the reference FRIGID implementation.""" + print("\n=== Phase 6: Cross-validation vs Reference ===") + from massspecgym.models.de_novo.fp2mol.formula_utils import FormulaEncoder + sys.path.insert(0, "/home/liuhx25/MassSpecGym/external/genms/src") + try: + from genmol.utils.formula_encoder import FormulaEncoder as RefFormulaEncoder + ours = FormulaEncoder(normalize="none") + ref = RefFormulaEncoder(normalize="none") + + check("vocab_size match", ours.vocab_size == ref.vocab_size, f"{ours.vocab_size} vs {ref.vocab_size}") + check("ATOM_VOCAB match", ours.ATOM_VOCAB == ref.ATOM_VOCAB) + + test_formulas = ["C6H12O6", "CH4", "C2H5OH", "C9H10N2O2", "C20H30BrClN2O4S"] + for f in test_formulas: + v_ours = ours.encode(f) + v_ref = ref.encode(f) + match = torch.allclose(v_ours, v_ref) + check(f"FormulaEncoder '{f}' matches ref", match, + f"diff={torch.abs(v_ours - v_ref).max().item()}" if not match else "") + + # Batch + vb_ours = ours.encode_batch(test_formulas) + vb_ref = ref.encode_batch(test_formulas) + check("encode_batch matches ref", torch.allclose(vb_ours, vb_ref)) + except ImportError as e: + print(f" [SKIP] Reference FRIGID not importable: {e}") + finally: + if "/home/liuhx25/MassSpecGym/external/genms/src" in sys.path: + sys.path.remove("/home/liuhx25/MassSpecGym/external/genms/src") + + +def test_mist_encoder_vs_reference(): + """Cross-validate our MIST modules against the reference FRIGID implementation.""" + print("\n=== Phase 7: MIST Encoder Cross-validation ===") + from massspecgym.models.encoders.mist.modules import FormulaTransformer as OurFT, FPGrowingModule as OurFPG + from massspecgym.models.encoders.mist.form_embedders import get_embedder as our_get_embedder + from massspecgym.models.encoders.mist.chem_constants import NORM_VEC as OUR_NORM_VEC + + sys.path.insert(0, "/home/liuhx25/MassSpecGym/external/genms/src") + try: + from mist.models.modules import FormulaTransformer as RefFT, FPGrowingModule as RefFPG + from mist.models.form_embedders import get_embedder as ref_get_embedder + from mist.utils.chem_utils import NORM_VEC as REF_NORM_VEC + + # NORM_VEC + check("NORM_VEC matches ref", np.array_equal(OUR_NORM_VEC, REF_NORM_VEC)) + + # Float embedder output + our_fe = our_get_embedder("float") + ref_fe = ref_get_embedder("float") + test_in = torch.tensor([[6.0, 12.0, 0.0, 6.0] + [0.0]*14]) + our_out = our_fe(test_in) + ref_out = ref_fe(test_in) + check("FloatFeaturizer output matches ref", torch.allclose(our_out, ref_out, atol=1e-6), + f"max_diff={torch.abs(our_out - ref_out).max().item()}") + + # pos-cos embedder + our_pc = our_get_embedder("pos-cos") + ref_pc = ref_get_embedder("pos-cos") + our_out_pc = our_pc(test_in) + ref_out_pc = ref_pc(test_in) + check("PosCos embedder output matches ref", torch.allclose(our_out_pc, ref_out_pc, atol=1e-6)) + + # FormulaTransformer constructor compatibility (same kwargs) + our_ft = OurFT(hidden_size=64, peak_attn_layers=2, num_heads=4, form_embedder="float") + ref_ft = RefFT(hidden_size=64, peak_attn_layers=2, num_heads=4, form_embedder="float") + our_params = sum(p.numel() for p in our_ft.parameters()) + ref_params = sum(p.numel() for p in ref_ft.parameters()) + check("FormulaTransformer param count matches", our_params == ref_params, + f"ours={our_params}, ref={ref_params}") + + # FPGrowingModule constructor compatibility + our_fpg = OurFPG(hidden_input_dim=64, final_target_dim=4096, num_splits=4) + ref_fpg = RefFPG(hidden_input_dim=64, final_target_dim=4096, num_splits=4) + our_fp_params = sum(p.numel() for p in our_fpg.parameters()) + ref_fp_params = sum(p.numel() for p in ref_fpg.parameters()) + check("FPGrowingModule param count matches", our_fp_params == ref_fp_params, + f"ours={our_fp_params}, ref={ref_fp_params}") + + except ImportError as e: + print(f" [SKIP] Reference MIST not importable: {e}") + finally: + if "/home/liuhx25/MassSpecGym/external/genms/src" in sys.path: + sys.path.remove("/home/liuhx25/MassSpecGym/external/genms/src") + + +if __name__ == "__main__": + print("=" * 60) + print("MassSpecGym v1.5 FP2Mol Validation Suite") + print("=" * 60) + + tests = [ + test_chem_constants, + test_form_embedders, + test_transformer_layer, + test_modules, + test_encoder, + test_formula_encoder, + test_mdlm, + test_mdlm_loss_weight, + test_frigid_components, + test_diffms_diffusion, + test_diffms_graph_transformer, + test_diffms_mol_from_graphs, + test_molforge_search, + test_formula_utils_vs_reference, + test_mist_encoder_vs_reference, + ] + + for test_fn in tests: + try: + test_fn() + except Exception as e: + FAIL += 1 + print(f"\n [ERROR] {test_fn.__name__} crashed: {e}") + traceback.print_exc() + + print("\n" + "=" * 60) + print(f"Results: {PASS} passed, {FAIL} failed out of {PASS + FAIL} checks") + print("=" * 60) + sys.exit(1 if FAIL > 0 else 0) diff --git a/tests/test_v15_data_oracles.py b/tests/test_v15_data_oracles.py new file mode 100644 index 0000000..9492607 --- /dev/null +++ b/tests/test_v15_data_oracles.py @@ -0,0 +1,326 @@ +"""Validation test suite for MassSpecGym v1.5 data pipeline, subformulae, and oracles.""" + +import sys +import json +import traceback +import numpy as np + +PASS = 0 +FAIL = 0 + +def check(name, condition, detail=""): + global PASS, FAIL + if condition: + PASS += 1 + print(f" [PASS] {name}") + else: + FAIL += 1 + print(f" [FAIL] {name} -- {detail}") + + +def test_chem_constants_subformulae(): + print("\n=== Phase 1: chem_constants subformulae functions ===") + from massspecgym.models.encoders.mist.chem_constants import ( + get_all_subsets, rdbe_filter, cross_sum, clipped_ppm, + formula_to_dense, VALID_MONO_MASSES, ELEMENT_VECTORS, + ) + + v = formula_to_dense("CH4") + check("CH4 dense vec C=1", v[0] == 1) + check("CH4 dense vec H=4", v[1] == 4) + + cross_prod, masses = get_all_subsets("CH4") + check("CH4 subsets not empty", len(cross_prod) > 0, str(len(cross_prod))) + check("CH4 subsets includes full formula", any(np.allclose(r, v) for r in cross_prod)) + check("CH4 masses > 0", all(m >= 0 for m in masses)) + + cross_prod2, masses2 = get_all_subsets("C6H12O6") + check("C6H12O6 has many subsets", len(cross_prod2) > 50, str(len(cross_prod2))) + + ppm = clipped_ppm(np.array([0.001]), np.array([500.0])) + check("clipped_ppm scalar", abs(ppm[0] - 2.0) < 0.01, str(ppm[0])) + + ppm_small = clipped_ppm(np.array([0.001]), np.array([100.0])) + expected = 0.001 / 200 * 1e6 + check("clipped_ppm clips to 200", abs(ppm_small[0] - expected) < 0.01, str(ppm_small[0])) + + +def test_subformulae_engine(): + print("\n=== Phase 2: Subformulae assignment engine ===") + from massspecgym.data.subformulae import ( + assign_subformulae_single, get_output_dict, process_spec_file, + parse_spectra_ms, + ) + + spectrum = np.array([ + [91.0542, 0.245], + [125.0233, 1.0], + [155.0577, 0.355], + [246.1125, 0.735], + ]) + + result = assign_subformulae_single("C16H17NO4", spectrum, "[M+H]+", mass_diff_thresh=20.0) + check("assign result has cand_form", result["cand_form"] == "C16H17NO4") + check("assign result has cand_ion", result["cand_ion"] == "[M+H]+") + check("assign result has output_tbl", result["output_tbl"] is not None) + + if result["output_tbl"] is not None: + tbl = result["output_tbl"] + check("output_tbl has mz", "mz" in tbl) + check("output_tbl has formula", "formula" in tbl) + check("output_tbl has ms2_inten", "ms2_inten" in tbl) + check("output_tbl has ions", "ions" in tbl) + check("output_tbl has mono_mass", "mono_mass" in tbl) + check("peaks assigned > 0", len(tbl["mz"]) > 0, str(len(tbl["mz"]))) + + result_bad_ion = assign_subformulae_single("C16H17NO4", spectrum, "[M-H]-") + check("bad ion returns None output_tbl", result_bad_ion["output_tbl"] is None) + + +def test_subformulae_vs_reference(): + """Cross-validate against reference output at /home/liuhx25/orcd/pool/data/msg/.""" + print("\n=== Phase 3: Subformulae cross-validation vs MSG reference ===") + import json + from pathlib import Path + from massspecgym.data.subformulae import assign_subformulae_single, parse_spectra_ms, process_spec_file + + ref_dir = Path("/home/liuhx25/orcd/pool/data/msg") + spec_file = ref_dir / "spec_files" / "MassSpecGymID0000001.ms" + ref_json = ref_dir / "subformulae" / "default_subformulae" / "MassSpecGymID0000001.json" + + if not spec_file.exists() or not ref_json.exists(): + print(" [SKIP] Reference MSG data not found") + return + + meta, tuples = parse_spectra_ms(str(spec_file)) + spec = process_spec_file(meta, tuples) + check("parsed spec not None", spec is not None) + + if spec is None: + return + + with open(ref_json) as f: + ref = json.load(f) + + result = assign_subformulae_single( + ref["cand_form"], spec, ref["cand_ion"], mass_diff_thresh=20.0 + ) + + check("formula matches ref", result["cand_form"] == ref["cand_form"]) + check("ion matches ref", result["cand_ion"] == ref["cand_ion"]) + + if result["output_tbl"] is not None and ref["output_tbl"] is not None: + our_formulas = set(result["output_tbl"]["formula"]) + ref_formulas = set(ref["output_tbl"]["formula"]) + check("formula overlap > 50%", + len(our_formulas & ref_formulas) / max(len(ref_formulas), 1) > 0.5, + f"ours={len(our_formulas)}, ref={len(ref_formulas)}, overlap={len(our_formulas & ref_formulas)}") + + +def test_sanity_check(): + print("\n=== Phase 4: InChIKey sanity check ===") + from massspecgym.data.sanity_check import ( + check_inchikey_overlap, check_inchikey_overlap_strict, DataLeakageError, + load_exclusion_set, + ) + + exclude_set = load_exclusion_set() + check("exclusion set loaded", len(exclude_set) > 8000, str(len(exclude_set))) + + clean_keys = ["ABCDEFGHIJKLMN", "ZYXWVUTSRQPONM"] + result = check_inchikey_overlap(clean_keys) + check("clean data passes", result.is_clean) + check("clean count correct", result.total_molecules == 2) + + dirty_keys = list(exclude_set)[:3] + clean_keys + result2 = check_inchikey_overlap(dirty_keys) + check("dirty data detected", not result2.is_clean) + check("overlap count >= 3", result2.overlap_count >= 3, str(result2.overlap_count)) + + try: + check_inchikey_overlap_strict(dirty_keys) + check("strict raises on dirty", False, "should have raised") + except DataLeakageError: + check("strict raises on dirty", True) + + +def test_magma_fragmentation(): + print("\n=== Phase 5: MAGMa FragmentEngine ===") + from massspecgym.models.simulation.iceberg.magma import FragmentEngine + + engine = FragmentEngine("CCO", max_tree_depth=2, max_broken_bonds=3) + check("FragmentEngine created", engine.mol is not None) + check("FragmentEngine natoms=3", engine.natoms == 3) + + engine.generate_fragments() + n_frags = len(engine.frag_to_entry) + check("fragments generated", n_frags > 1, str(n_frags)) + + root = engine.get_root_frag() + check("root frag correct", root == (1 << 3) - 1) + + forms, masses = engine.get_frag_forms() + check("frag_forms not empty", len(forms) > 0, str(len(forms))) + check("frag_masses positive", all(m > 0 for m in masses)) + + engine2 = FragmentEngine("c1ccccc1", max_tree_depth=2) + engine2.generate_fragments() + check("benzene fragments", len(engine2.frag_to_entry) > 1, str(len(engine2.frag_to_entry))) + + +def test_fp2mol_dataset_parquet(): + print("\n=== Phase 6: FP2MolDataset Parquet ===") + import tempfile, os + import pandas as pd + + smiles_list = ["CCO", "CC(=O)O", "c1ccccc1", "CC(C)O"] + df = pd.DataFrame({ + "smiles": smiles_list, + "inchikey_14": ["LFQSCWFLJHTTHZ", "QTBSBXVTEAMEQO", "UHOVQNZJYSORNB", "KFZMGEQAYNKOFK"], + "formula": ["C2H6O", "C2H4O2", "C6H6", "C3H8O"], + }) + + with tempfile.NamedTemporaryFile(suffix=".parquet", delete=False) as f: + df.to_parquet(f.name) + tmp_path = f.name + + try: + from massspecgym.data.fp2mol_dataset import FP2MolDataset + ds = FP2MolDataset(tmp_path, exclude_inchikeys=False) + check("FP2MolDataset loads parquet", len(ds) == 4, str(len(ds))) + + item = ds[0] + check("item has fingerprint", "fingerprint" in item) + check("item has formula", "formula" in item) + check("item has mol", "mol" in item) + check("fingerprint shape", item["fingerprint"].shape[0] == 4096) + finally: + os.unlink(tmp_path) + + try: + from massspecgym.data.fp2mol_dataset import FP2MolDataset + ds2 = FP2MolDataset(smiles_list, exclude_inchikeys=False) + check("FP2MolDataset list input", len(ds2) == 4) + except Exception as e: + check("FP2MolDataset list input", False, str(e)) + + +def test_oracle_interfaces(): + print("\n=== Phase 7: Oracle interfaces ===") + from massspecgym.models.oracles import OracleBase + from massspecgym.models.oracles.mist_cf import predict_formulas, MistCFNet, enumerate_candidate_formulas, FormulaCandidate + from massspecgym.models.oracles.iceberg import predict_spectrum + + check("OracleBase importable", True) + check("predict_formulas importable", callable(predict_formulas)) + check("predict_spectrum importable", callable(predict_spectrum)) + check("MistCFNet importable", MistCFNet is not None) + check("FormulaCandidate importable", FormulaCandidate is not None) + + candidates = enumerate_candidate_formulas(180.0634, "[M+H]+", ppm_tol=10.0) + check("enumerate_candidates non-empty", len(candidates) > 0, str(len(candidates))) + has_glucose = any("C6" in c and "H12" in c and "O6" in c for c in candidates) + check("enumerate finds C6H12O6-like", has_glucose or len(candidates) > 0) + + results = predict_formulas( + spectrum_mzs=[91.05, 125.02, 155.06, 246.11], + spectrum_intensities=[0.25, 1.0, 0.36, 0.73], + precursor_mz=288.12, + adduct="[M+H]+", + top_k=5, + ) + check("predict_formulas returns results", len(results) > 0, str(len(results))) + if results: + check("results are FormulaCandidate", isinstance(results[0], FormulaCandidate)) + check("results have score", results[0].score != 0) + + +def test_iceberg_models(): + print("\n=== Phase 7b: ICEBERG model imports ===") + from massspecgym.models.simulation.iceberg.gen_model import FragGNN + from massspecgym.models.simulation.iceberg.inten_model import IntenGNN + from massspecgym.models.simulation.iceberg.joint_model import JointModel + from massspecgym.models.simulation.iceberg.dag_data import TreeProcessor, FRAGMENT_ENGINE_PARAMS + from massspecgym.models.simulation.iceberg.adapter import IcebergSimulationMassSpecGymModel + + check("FragGNN importable", FragGNN is not None) + check("IntenGNN importable", IntenGNN is not None) + check("JointModel importable", JointModel is not None) + check("TreeProcessor importable", TreeProcessor is not None) + check("FRAGMENT_ENGINE_PARAMS", FRAGMENT_ENGINE_PARAMS == {"max_broken_bonds": 6, "max_tree_depth": 3}) + + tp = TreeProcessor(pe_embed_k=0, root_encode="gnn") + nf = tp.get_node_feats() + check("TreeProcessor node_feats > 0", nf > 0, str(nf)) + + gen = FragGNN(hidden_size=64) + check("FragGNN instantiates", gen is not None) + + inten = IntenGNN(hidden_size=64) + check("IntenGNN instantiates", inten is not None) + + jm = JointModel(gen, inten) + check("JointModel instantiates", jm is not None) + + result = jm.predict_mol("CCO", collision_eng=40.0, adduct="[M+H]+") + check("JointModel predict_mol returns", "spec" in result) + check("JointModel predict_mol has peaks", len(result["spec"]) > 0, str(len(result["spec"]))) + + from massspecgym.models.oracles.mist_cf.model import MistCFNet + net = MistCFNet(hidden_size=64, layers=1) + check("MistCFNet instantiates", net is not None) + + import torch + num_peaks = torch.tensor([3, 2]) + peak_types = torch.tensor([[0, 1, 3, 0], [0, 3, 0, 0]]) + form_vec = torch.randn(2, 4, 18) + ion_vec = torch.zeros(2, 4, 7) + instrument_vec = torch.zeros(2, 4, 6) + intens = torch.tensor([[0.5, 0.3, 0.2, 0.0], [0.7, 0.3, 0.0, 0.0]]) + rel_mass_diffs = torch.zeros(2, 4) + scores = net(num_peaks, peak_types, form_vec, ion_vec, instrument_vec, intens, rel_mass_diffs) + check("MistCFNet forward shape", scores.shape == (2, 1), str(scores.shape)) + + +def test_mist_data_mixin(): + print("\n=== Phase 8: MISTDataMixin ===") + from massspecgym.data.mist_data_mixin import MISTDataMixin + check("MISTDataMixin importable", True) + + class TestModel(MISTDataMixin): + pass + + m = TestModel() + check("ensure_mist_data is callable", hasattr(m, "ensure_mist_data")) + check("get_subformulae_dir is callable", hasattr(m, "get_subformulae_dir")) + + +if __name__ == "__main__": + print("=" * 60) + print("MassSpecGym v1.5 Data/Oracles Validation Suite") + print("=" * 60) + + tests = [ + test_chem_constants_subformulae, + test_subformulae_engine, + test_subformulae_vs_reference, + test_sanity_check, + test_magma_fragmentation, + test_fp2mol_dataset_parquet, + test_oracle_interfaces, + test_iceberg_models, + test_mist_data_mixin, + ] + + for test_fn in tests: + try: + test_fn() + except Exception as e: + FAIL += 1 + print(f"\n [ERROR] {test_fn.__name__} crashed: {e}") + traceback.print_exc() + + print("\n" + "=" * 60) + print(f"Results: {PASS} passed, {FAIL} failed out of {PASS + FAIL} checks") + print("=" * 60) + sys.exit(1 if FAIL > 0 else 0) From ddd3cc4e8cd5cdb8fc47bf1673617ac0a6755f40 Mon Sep 17 00:00:00 2001 From: Magdalena Lederbauer <98785759+mlederbauer@users.noreply.github.com> Date: Sun, 10 May 2026 20:13:29 -0400 Subject: [PATCH 2/5] Feat/llm skills lv2 (#14) * adding MIST and SpecBridge Evals * Add DreaMS-MSG support. * feat: skill to build model with MSG ABCs * feat: skill for review for common issues * chore: cosmetic changes * chore: remove implementation script since we focus on review * chore: update review "skill" to be used as maintainer guide * feat: add submissions guide and model template card * feat: add submission review script * feat: update leaderboard GH action (to be triggered after manual approval) * feat: add "submissions" label to test workflow * chore: add pyarrow dependency * chore: move pyarrow to setup deps * tmp: add feature branch to github action sorkflow * Merge pull request #4 from mlederbauer/submission/diffms feat: level 1 model card impl * feat: add mist molforge submission * tmp chore: adaptations to review scripts * tmp feat: test out with diffms (v0 model card) * chore: update model card * fix: suibmission dir * cho9re: remove pubication field * chore: remove superfluous comments * chore: add .claude to gitignore * chore: update scripts in llm skills * feat: diffms implementation * feat: add mist molforge submission * tmp fix: remove model card for llm skills * chore: remocve mist molforge * choe: only model card for ttt-msms * Revert "choe: only model card for ttt-msms" This reverts commit dae836aa447734b9967d647b9774d6c7a1c86a63. * feat v: llm review w local repo * feat: update system pormpt to use unified SKILL.md * chore: remove emojis from review * feat: update results metrics in model card instead of csv * chore: remove reference section * chore: refine warning gravity and red/yellow labeling for revbiew * fix: detect mist bug * Delete checkpoints/README.md * chore: remove superfluous code for LLM review submission * chore: remover superfluous code for llm skills submission * chore: remove superfluous code * chore: move leaderboard update scripts * chore: keep llm skills as CI branch for testing * chore: update workflow to edit csvs during PR * chore: cosmetic changes * feat: create model cards for baselines * fix: update trigger to also include feature branch --------- Co-authored-by: harrylaucngd --- .github/workflows/prepare_submission.yml | 123 +++ .github/workflows/review_submission.yml | 176 ++++ .gitignore | 4 +- README.md | 74 -- checkpoints/README.md | 43 - massspecgym/data/__init__.py | 11 +- massspecgym/data/download.py | 82 -- massspecgym/data/fp2mol_dataset.py | 220 ----- massspecgym/data/mist_data_mixin.py | 103 -- massspecgym/data/mist_format.py | 184 ---- massspecgym/data/sanity_check.py | 157 --- massspecgym/data/subformulae.py | 388 -------- massspecgym/models/de_novo/__init__.py | 32 +- massspecgym/models/de_novo/fp2mol/__init__.py | 34 - massspecgym/models/de_novo/fp2mol/base.py | 160 --- .../models/de_novo/fp2mol/diffms/__init__.py | 8 - .../de_novo/fp2mol/diffms/diffusion_utils.py | 195 ---- .../fp2mol/diffms/graph_transformer.py | 255 ----- .../models/de_novo/fp2mol/diffms/model.py | 252 ----- .../models/de_novo/fp2mol/formula_utils.py | 138 --- .../models/de_novo/fp2mol/frigid/__init__.py | 15 - .../fp2mol/frigid/bert_cross_attention.py | 231 ----- .../de_novo/fp2mol/frigid/components.py | 336 ------- .../models/de_novo/fp2mol/frigid/mdlm.py | 246 ----- .../models/de_novo/fp2mol/frigid/model.py | 404 -------- .../de_novo/fp2mol/molforge/__init__.py | 8 - .../de_novo/fp2mol/molforge/decoder_search.py | 138 --- .../models/de_novo/fp2mol/molforge/model.py | 272 ------ massspecgym/models/encoders/__init__.py | 11 - .../models/encoders/dreams/__init__.py | 20 - massspecgym/models/encoders/dreams/api.py | 118 --- .../models/encoders/dreams/feed_forward.py | 43 - .../encoders/dreams/fourier_features.py | 79 -- massspecgym/models/encoders/dreams/layers.py | 216 ----- massspecgym/models/encoders/dreams/model.py | 186 ---- .../models/encoders/dreams/preprocessing.py | 90 -- massspecgym/models/encoders/mist/__init__.py | 24 - .../models/encoders/mist/chem_constants.py | 232 ----- massspecgym/models/encoders/mist/encoder.py | 171 ---- .../models/encoders/mist/form_embedders.py | 199 ---- massspecgym/models/encoders/mist/modules.py | 347 ------- .../models/encoders/mist/transformer_layer.py | 336 ------- massspecgym/models/oracles/__init__.py | 15 - massspecgym/models/oracles/base.py | 37 - .../models/oracles/iceberg/__init__.py | 10 - massspecgym/models/oracles/iceberg/predict.py | 97 -- .../models/oracles/mist_cf/__init__.py | 18 - massspecgym/models/oracles/mist_cf/model.py | 264 ----- massspecgym/models/oracles/mist_cf/predict.py | 222 ----- massspecgym/models/retrieval/__init__.py | 20 +- .../models/retrieval/generative_retrieval.py | 127 --- .../models/retrieval/iceberg_retrieval.py | 114 --- .../models/retrieval/mist_retrieval.py | 81 -- .../models/simulation/iceberg/__init__.py | 24 - .../models/simulation/iceberg/adapter.py | 61 -- .../models/simulation/iceberg/dag_data.py | 218 ----- .../models/simulation/iceberg/gen_model.py | 234 ----- .../models/simulation/iceberg/inten_model.py | 244 ----- .../models/simulation/iceberg/joint_model.py | 115 --- .../simulation/iceberg/magma/__init__.py | 11 - .../simulation/iceberg/magma/fragmentation.py | 503 ---------- results/de_novo.csv | 6 +- results/de_novo_bonus.csv | 22 +- results/retrieval.csv | 10 +- results/retrieval_bonus.csv | 10 +- results/simulation.csv | 6 +- results/simulation_bonus.csv | 10 +- scripts/convert_to_parquet.py | 142 --- scripts/download_data.py | 29 - scripts/leaderboard/generate_results_csvs.py | 170 ++++ .../massspecgym_leaderboard.py | 14 - scripts/leaderboard/review_submission.py | 916 ++++++++++++++++++ scripts/run.py | 61 +- setup.py | 8 +- skills/review/SKILL.md | 179 ++++ submissions/DeepSets/model_card.yaml | 64 ++ submissions/DeepSets_Fourier/model_card.yaml | 64 ++ submissions/DiffMS/model_card.yaml | 49 + submissions/ESP/model_card.yaml | 64 ++ submissions/FFN_Fingerprint/model_card.yaml | 70 ++ submissions/Fingerprint_FFN/model_card.yaml | 64 ++ submissions/FraGNNet/model_card.yaml | 70 ++ submissions/GNN/model_card.yaml | 70 ++ submissions/ICEBERG/model_card.yaml | 46 + submissions/JESTR/model_card.yaml | 64 ++ submissions/MADGEN/model_card.yaml | 49 + submissions/MARASON/model_card.yaml | 46 + submissions/MIST/model_card.yaml | 64 ++ submissions/MIST_MSNovelist/model_card.yaml | 49 + .../MIST_Neuraldecipher/model_card.yaml | 49 + submissions/MS-BART/model_card.yaml | 49 + submissions/OMG/model_card.yaml | 49 + submissions/OMG_ESP/model_card.yaml | 49 + submissions/Precursor_mz/model_card.yaml | 70 ++ submissions/Random/model_card.yaml | 64 ++ .../model_card.yaml | 76 ++ .../SELFIES_Transformer/model_card.yaml | 76 ++ .../SMILES_Transformer/model_card.yaml | 76 ++ submissions/SUBMISSION_GUIDE.md | 199 ++++ submissions/Spec2Mol/model_card.yaml | 49 + submissions/Spec2Mol_reeval/model_card.yaml | 49 + submissions/template/model_card.yaml | 131 +++ tests/test_fp2mol_v15.py | 552 ----------- tests/test_v15_data_oracles.py | 326 ------- 104 files changed, 3431 insertions(+), 9625 deletions(-) create mode 100644 .github/workflows/prepare_submission.yml create mode 100644 .github/workflows/review_submission.yml delete mode 100644 checkpoints/README.md delete mode 100644 massspecgym/data/download.py delete mode 100644 massspecgym/data/fp2mol_dataset.py delete mode 100644 massspecgym/data/mist_data_mixin.py delete mode 100644 massspecgym/data/mist_format.py delete mode 100644 massspecgym/data/sanity_check.py delete mode 100644 massspecgym/data/subformulae.py delete mode 100644 massspecgym/models/de_novo/fp2mol/__init__.py delete mode 100644 massspecgym/models/de_novo/fp2mol/base.py delete mode 100644 massspecgym/models/de_novo/fp2mol/diffms/__init__.py delete mode 100644 massspecgym/models/de_novo/fp2mol/diffms/diffusion_utils.py delete mode 100644 massspecgym/models/de_novo/fp2mol/diffms/graph_transformer.py delete mode 100644 massspecgym/models/de_novo/fp2mol/diffms/model.py delete mode 100644 massspecgym/models/de_novo/fp2mol/formula_utils.py delete mode 100644 massspecgym/models/de_novo/fp2mol/frigid/__init__.py delete mode 100644 massspecgym/models/de_novo/fp2mol/frigid/bert_cross_attention.py delete mode 100644 massspecgym/models/de_novo/fp2mol/frigid/components.py delete mode 100644 massspecgym/models/de_novo/fp2mol/frigid/mdlm.py delete mode 100644 massspecgym/models/de_novo/fp2mol/frigid/model.py delete mode 100644 massspecgym/models/de_novo/fp2mol/molforge/__init__.py delete mode 100644 massspecgym/models/de_novo/fp2mol/molforge/decoder_search.py delete mode 100644 massspecgym/models/de_novo/fp2mol/molforge/model.py delete mode 100644 massspecgym/models/encoders/__init__.py delete mode 100644 massspecgym/models/encoders/dreams/__init__.py delete mode 100644 massspecgym/models/encoders/dreams/api.py delete mode 100644 massspecgym/models/encoders/dreams/feed_forward.py delete mode 100644 massspecgym/models/encoders/dreams/fourier_features.py delete mode 100644 massspecgym/models/encoders/dreams/layers.py delete mode 100644 massspecgym/models/encoders/dreams/model.py delete mode 100644 massspecgym/models/encoders/dreams/preprocessing.py delete mode 100644 massspecgym/models/encoders/mist/__init__.py delete mode 100644 massspecgym/models/encoders/mist/chem_constants.py delete mode 100644 massspecgym/models/encoders/mist/encoder.py delete mode 100644 massspecgym/models/encoders/mist/form_embedders.py delete mode 100644 massspecgym/models/encoders/mist/modules.py delete mode 100644 massspecgym/models/encoders/mist/transformer_layer.py delete mode 100644 massspecgym/models/oracles/__init__.py delete mode 100644 massspecgym/models/oracles/base.py delete mode 100644 massspecgym/models/oracles/iceberg/__init__.py delete mode 100644 massspecgym/models/oracles/iceberg/predict.py delete mode 100644 massspecgym/models/oracles/mist_cf/__init__.py delete mode 100644 massspecgym/models/oracles/mist_cf/model.py delete mode 100644 massspecgym/models/oracles/mist_cf/predict.py delete mode 100644 massspecgym/models/retrieval/generative_retrieval.py delete mode 100644 massspecgym/models/retrieval/iceberg_retrieval.py delete mode 100644 massspecgym/models/retrieval/mist_retrieval.py delete mode 100644 massspecgym/models/simulation/iceberg/__init__.py delete mode 100644 massspecgym/models/simulation/iceberg/adapter.py delete mode 100644 massspecgym/models/simulation/iceberg/dag_data.py delete mode 100644 massspecgym/models/simulation/iceberg/gen_model.py delete mode 100644 massspecgym/models/simulation/iceberg/inten_model.py delete mode 100644 massspecgym/models/simulation/iceberg/joint_model.py delete mode 100644 massspecgym/models/simulation/iceberg/magma/__init__.py delete mode 100644 massspecgym/models/simulation/iceberg/magma/fragmentation.py delete mode 100644 scripts/convert_to_parquet.py delete mode 100644 scripts/download_data.py create mode 100644 scripts/leaderboard/generate_results_csvs.py rename scripts/{ => leaderboard}/massspecgym_leaderboard.py (98%) create mode 100644 scripts/leaderboard/review_submission.py create mode 100644 skills/review/SKILL.md create mode 100644 submissions/DeepSets/model_card.yaml create mode 100644 submissions/DeepSets_Fourier/model_card.yaml create mode 100644 submissions/DiffMS/model_card.yaml create mode 100644 submissions/ESP/model_card.yaml create mode 100644 submissions/FFN_Fingerprint/model_card.yaml create mode 100644 submissions/Fingerprint_FFN/model_card.yaml create mode 100644 submissions/FraGNNet/model_card.yaml create mode 100644 submissions/GNN/model_card.yaml create mode 100644 submissions/ICEBERG/model_card.yaml create mode 100644 submissions/JESTR/model_card.yaml create mode 100644 submissions/MADGEN/model_card.yaml create mode 100644 submissions/MARASON/model_card.yaml create mode 100644 submissions/MIST/model_card.yaml create mode 100644 submissions/MIST_MSNovelist/model_card.yaml create mode 100644 submissions/MIST_Neuraldecipher/model_card.yaml create mode 100644 submissions/MS-BART/model_card.yaml create mode 100644 submissions/OMG/model_card.yaml create mode 100644 submissions/OMG_ESP/model_card.yaml create mode 100644 submissions/Precursor_mz/model_card.yaml create mode 100644 submissions/Random/model_card.yaml create mode 100644 submissions/Random_chemical_generation/model_card.yaml create mode 100644 submissions/SELFIES_Transformer/model_card.yaml create mode 100644 submissions/SMILES_Transformer/model_card.yaml create mode 100644 submissions/SUBMISSION_GUIDE.md create mode 100644 submissions/Spec2Mol/model_card.yaml create mode 100644 submissions/Spec2Mol_reeval/model_card.yaml create mode 100644 submissions/template/model_card.yaml delete mode 100644 tests/test_fp2mol_v15.py delete mode 100644 tests/test_v15_data_oracles.py diff --git a/.github/workflows/prepare_submission.yml b/.github/workflows/prepare_submission.yml new file mode 100644 index 0000000..dc2e99c --- /dev/null +++ b/.github/workflows/prepare_submission.yml @@ -0,0 +1,123 @@ +name: Prepare Submission for Merge + +# pull_request_target runs in the BASE repo context (has secrets + write access) +# even when the PR comes from a fork. We never execute code from the fork โ€” +# only our own scripts run, on the sanitized model_card.yaml content. +on: + pull_request_target: + types: [labeled] + branches: [main, feat/llm-skills-lv2] + paths: + - "submissions/**" + +jobs: + prepare: + runs-on: ubuntu-latest + # Trigger: maintainer adds 'ready-to-merge' label after human review + approval + if: github.event.label.name == 'ready-to-merge' + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout base repo (our scripts) + uses: actions/checkout@v4 + with: + ref: main + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Fetch fork PR head (read-only, no code execution) + run: | + git fetch origin pull/${{ github.event.pull_request.number }}/head:pr-head + git checkout pr-head -- submissions/ + + - name: Strip source code โ€” keep only model_card.yaml per method dir + run: | + for method_dir in submissions/*/; do + method=$(basename "$method_dir") + if [ "$method" = "template" ]; then + continue + fi + echo "Cleaning $method_dir ..." + find "$method_dir" -mindepth 1 ! -name "model_card.yaml" -delete + done + + - name: Validate model cards present + run: | + MISSING=0 + for method_dir in submissions/*/; do + method=$(basename "$method_dir") + [ "$method" = "template" ] && continue + if [ ! -f "${method_dir}model_card.yaml" ]; then + echo "ERROR: missing model_card.yaml in $method_dir" + MISSING=1 + fi + done + if [ "$MISSING" != "0" ]; then + exit 1 + fi + echo "All model_card.yaml files present." + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pandas pyyaml + + - name: Regenerate results CSVs from model cards + run: python scripts/leaderboard/generate_results_csvs.py + + - name: Push clean branch to base repo + id: push + run: | + BRANCH="submissions/prepare-${{ github.event.pull_request.number }}" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git checkout -b "$BRANCH" + git add submissions/ results/*.csv + if git diff --cached --quiet; then + echo "Nothing changed after cleanup." + else + git commit -m "leaderboard: strip submission src code and regenerate CSVs (#${{ github.event.pull_request.number }}) [skip ci]" + fi + git push origin "$BRANCH" --force + echo "branch=$BRANCH" >> $GITHUB_OUTPUT + + - name: Comment on original PR + uses: actions/github-script@v7 + with: + script: | + const branch = '${{ steps.push.outputs.branch }}'; + const origPR = context.payload.pull_request.number; + const body = [ + '## Submission prepared for merge', + '', + `A clean branch \`${branch}\` has been created in the base repository with:`, + '- Source code removed (only `model_card.yaml` retained)', + '- `results/*.csv` regenerated from all model cards', + '', + `**Maintainer:** merge \`${branch}\` into \`main\` โ€” do not merge this PR directly.`, + ].join('\n'); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: origPR, + body, + }); + + - name: Close original fork PR + uses: actions/github-script@v7 + with: + script: | + await github.rest.pulls.update({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.pull_request.number, + state: 'closed', + }); diff --git a/.github/workflows/review_submission.yml b/.github/workflows/review_submission.yml new file mode 100644 index 0000000..f3f720e --- /dev/null +++ b/.github/workflows/review_submission.yml @@ -0,0 +1,176 @@ +name: Review Submission + +on: + pull_request: + branches: [main, feat/llm-skills-lv2] + types: [opened, synchronize, reopened, labeled] + paths: + - "submissions/**" + +jobs: + review: + runs-on: ubuntu-latest + # Only run when the PR carries the 'submission' label + if: contains(github.event.pull_request.labels.*.name, 'submission') + permissions: + pull-requests: write + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: false + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e ".[dev]" + pip install anthropic pyyaml pandas + + - name: Detect changed submission folders + id: detect + run: | + # Find all submissions/ directories that were added or modified in this PR + git diff --name-only origin/${{ github.base_ref }}...HEAD \ + | grep -E '^submissions/[^/]+/' \ + | sed 's|\(submissions/[^/]*\)/.*|\1|' \ + | sort -u \ + | grep -v '^submissions/template$' \ + > changed_submissions.txt || true + + echo "Changed submission dirs:" + cat changed_submissions.txt + + if [ ! -s changed_submissions.txt ]; then + echo "found=false" >> $GITHUB_OUTPUT + else + echo "found=true" >> $GITHUB_OUTPUT + fi + + - name: Run review for each changed submission + if: steps.detect.outputs.found == 'true' + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + run: | + mkdir -p review_outputs + EXIT_CODE=0 + + while IFS= read -r sub_dir; do + echo "Reviewing: $sub_dir" + method_slug=$(basename "$sub_dir") + + python scripts/leaderboard/review_submission.py \ + --submission "$sub_dir" \ + --output "review_outputs/${method_slug}_report.json" \ + --markdown "review_outputs/${method_slug}_summary.md" \ + || EXIT_CODE=$? + + echo "Exit code for $sub_dir: $?" + done < changed_submissions.txt + + # Store overall exit code for the comment step + echo "$EXIT_CODE" > review_outputs/exit_code.txt + + - name: Post review comment on PR + if: steps.detect.outputs.found == 'true' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const path = require('path'); + + const outputDir = 'review_outputs'; + let combinedBody = '## MassSpecGym Automated Submission Review\n\n'; + + const exitCodeFile = path.join(outputDir, 'exit_code.txt'); + const exitCode = fs.existsSync(exitCodeFile) + ? parseInt(fs.readFileSync(exitCodeFile, 'utf8').trim()) + : 0; + + if (exitCode !== 0) { + combinedBody += '> **BLOCKED: One or more hard failures detected. This PR cannot be merged until they are resolved.**\n\n'; + } else { + combinedBody += '> No hard failures. Maintainer review required for any warnings.\n\n'; + } + + const mdFiles = fs.readdirSync(outputDir).filter(f => f.endsWith('_summary.md')); + if (mdFiles.length === 0) { + combinedBody += '_No submission directories detected in changed files._\n'; + } + for (const f of mdFiles) { + combinedBody += fs.readFileSync(path.join(outputDir, f), 'utf8') + '\n\n---\n\n'; + } + + combinedBody += '_Generated by [review_submission.py](scripts/leaderboard/review_submission.py). '; + combinedBody += 'See [SUBMISSION_GUIDE.md](submissions/SUBMISSION_GUIDE.md) for requirements._'; + + // Find and update existing bot comment, or create new one + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + + const botComment = comments.find(c => + c.user.type === 'Bot' && + c.body.includes('MassSpecGym Automated Submission Review') + ); + + if (botComment) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + body: combinedBody, + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: combinedBody, + }); + } + + - name: Fail CI on hard failures + if: steps.detect.outputs.found == 'true' + run: | + EXIT_CODE=$(cat review_outputs/exit_code.txt 2>/dev/null || echo 0) + if [ "$EXIT_CODE" != "0" ]; then + echo "Hard failures detected in submission review. See PR comment for details." + exit 1 + fi + + - name: No submission changes detected + if: steps.detect.outputs.found == 'false' + run: | + echo "No changes in submissions/ directories detected. Skipping submission review." + echo "If you added results to results/*.csv without a model card, please also add" + echo "submissions//model_card.yaml (see submissions/SUBMISSION_GUIDE.md)." + + # Separate job: always required, never skipped, even if the review job passes. + # Enforces that a human maintainer must approve before merge. + require-human-approval: + runs-on: ubuntu-latest + if: contains(github.event.pull_request.labels.*.name, 'submission') + needs: review + # This job always requires a human PR review approval โ€” enforced via branch + # protection rules (Settings โ†’ Branches โ†’ main โ†’ Require approvals: 1). + # This step documents the requirement explicitly in CI output. + steps: + - name: Human sign-off required + run: | + echo "HUMAN REVIEW REQUIRED" + echo "The automated review has completed. A maintainer" + echo "must read the review report and approve this PR" + echo "before it can be merged." + echo "" + echo "Maintainers: see skills/review/SKILL.md for the" + echo "human review checklist." diff --git a/.gitignore b/.gitignore index 6fde53c..1f77f3b 100644 --- a/.gitignore +++ b/.gitignore @@ -141,4 +141,6 @@ dmypy.json wandb/ # External codebases -external/ \ No newline at end of file +external/ +.claude/ +checkpoints/ diff --git a/README.md b/README.md index c1d3499..fbbbfe8 100644 --- a/README.md +++ b/README.md @@ -217,80 +217,6 @@ trainer.fit(model, datamodule=data_module) trainer.test(model, datamodule=data_module) ``` -## ๐Ÿงช v1.5 Model Zoo - -MassSpecGym v1.5 extends the benchmark with a comprehensive suite of state-of-the-art models, data utilities, and official oracles. - -### Spectrum Encoders (`massspecgym/models/encoders/`) - -| Encoder | Description | Output | -|---------|-------------|--------| -| **MIST** | FormulaTransformer over subformulae-annotated peaks (Goldman et al., NMI 2023) | 4096-bit Morgan fingerprint | -| **DreaMS** | BERT-style transformer over (m/z, intensity) tokens (Bushuiev et al., Nat. Biotech. 2025) | 1024-D spectrum embedding | - -### De Novo Models (`massspecgym/models/de_novo/`) - -| Model | Type | Approach | -|-------|------|----------| -| **SmilesTransformer** | Autoregressive | Spectrum โ†’ SMILES (encoder-decoder transformer) | -| **FRIGID** | MIST + MDLM decoder | Fingerprint + formula โ†’ SAFE via masked diffusion | -| **DiffMS** | MIST + graph diffusion decoder | Fingerprint โ†’ molecular graph via discrete diffusion | -| **MolForge** | MIST + seq2seq decoder | Fingerprint bit IDs โ†’ SMILES via autoregressive transformer | - -### Retrieval Models (`massspecgym/models/retrieval/`) - -| Model | Strategy | Description | -|-------|----------|-------------| -| **FingerprintFFN** | Direct | FFN predicts fingerprint from binned spectrum | -| **DeepSets** | Direct | DeepSets predicts fingerprint from peak list | -| **MISTFingerprintRetrieval** | Bonus | MIST predicts FP, rank by Tanimoto similarity | -| **GenerativeRetrieval** | Bonus | Any FP2Mol decoder generates molecule, rank by FP similarity | -| **IcebergRetrieval** | Bonus | ICEBERG simulates spectra, rank by cosine similarity | - -### Simulation Models (`massspecgym/models/simulation/`) - -| Model | Description | -|-------|-------------| -| **FP** | Fingerprint + metadata โ†’ spectrum via FFN | -| **GNN** | Molecular graph + metadata โ†’ spectrum via GNN | -| **ICEBERG** | DAG-based fragmentation with FragGNN + IntenGNN | - -### Official Oracles (`massspecgym/models/oracles/`) - -| Oracle | Task | Data-Safe | -|--------|------|-----------| -| **MIST-CF** | Chemical formula prediction from MS/MS spectrum | Yes | -| **ICEBERG** | MS/MS spectrum simulation from molecular structure | Yes | - -### Data Utilities (`massspecgym/data/`) - -| Module | Function | -|--------|----------| -| `subformulae.py` | Subformulae assignment for MIST-based models | -| `mist_format.py` | Convert MassSpecGym TSV to MIST-compatible format | -| `sanity_check.py` | InChIKey-based data leakage prevention | -| `fp2mol_dataset.py` | Parquet-based dataset for FP2Mol decoder pretraining | -| `download.py` | Download MassSpecGym data from HuggingFace | - -### Quick Start with Checkpoints - -Place pretrained checkpoints in `checkpoints/` and load any model directly: - -```python -# DreaMS spectrum embedding -from massspecgym.models.encoders.dreams.api import PreTrainedDreaMS -model = PreTrainedDreaMS.from_checkpoint("checkpoints/dreams/embedding_model.ckpt") -embedding = model.embed_spectrum(mzs, intensities, precursor_mz) - -# MIST-CF formula prediction -from massspecgym.models.oracles.mist_cf import predict_formulas -candidates = predict_formulas(mzs, intensities, precursor_mz, adduct="[M+H]+") - -# FP2Mol decoder pretraining with data safety -from massspecgym.data.fp2mol_dataset import FP2MolDataset -dataset = FP2MolDataset("molecules.parquet") # auto InChIKey sanity check -``` - ## ๐Ÿ”— References If you use MassSpecGym in your work, please cite the following paper: diff --git a/checkpoints/README.md b/checkpoints/README.md deleted file mode 100644 index 4db47a6..0000000 --- a/checkpoints/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# MassSpecGym Checkpoints - -Place pretrained model checkpoints here for inference. - -## Directory Structure - -``` -checkpoints/ - mist/ # MIST spectrum encoder - mist_encoder.ckpt - mist_cf/ # MIST-CF formula prediction oracle - mist_cf.ckpt - iceberg/ # ICEBERG spectrum simulation - gen_model.ckpt - inten_model.ckpt - dreams/ # DreaMS spectrum encoder - embedding_model.ckpt - frigid/ # FRIGID MDLM decoder - frigid.ckpt - diffms/ # DiffMS graph diffusion decoder - diffms.ckpt - molforge/ # MolForge seq2seq decoder - molforge.ckpt -``` - -## Usage - -All models can be loaded from checkpoints using their respective classes: - -```python -# MIST encoder -from massspecgym.models.encoders.mist import SpectraEncoderGrowing -encoder = SpectraEncoderGrowing(...) -encoder.load_state_dict(torch.load("checkpoints/mist/mist_encoder.ckpt")) - -# DreaMS encoder -from massspecgym.models.encoders.dreams import PreTrainedDreaMS -model = PreTrainedDreaMS.from_checkpoint("checkpoints/dreams/embedding_model.ckpt") - -# FRIGID decoder -from massspecgym.models.de_novo import FRIGIDDecoder -model = FRIGIDDecoder.load_from_checkpoint("checkpoints/frigid/frigid.ckpt") -``` diff --git a/massspecgym/data/__init__.py b/massspecgym/data/__init__.py index 506d1d9..5d81972 100644 --- a/massspecgym/data/__init__.py +++ b/massspecgym/data/__init__.py @@ -4,12 +4,5 @@ __all__ = [ "MassSpecDataset", "RetrievalDataset", - "MassSpecDataModule", -] - - -def __getattr__(name): - if name == "FP2MolDataset": - from .fp2mol_dataset import FP2MolDataset - return FP2MolDataset - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + "MassSpecDataModule" +] \ No newline at end of file diff --git a/massspecgym/data/download.py b/massspecgym/data/download.py deleted file mode 100644 index 749938a..0000000 --- a/massspecgym/data/download.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -Download MassSpecGym datasets from HuggingFace to local data/ directory. - -Downloads the core dataset files needed for training, evaluation, and -retrieval tasks. -""" - -import logging -from pathlib import Path -from typing import Optional - -from massspecgym.utils import hugging_face_download - -logger = logging.getLogger(__name__) - -CORE_FILES = [ - "MassSpecGym.tsv", -] - -RETRIEVAL_FILES = [ - "molecules/MassSpecGym_retrieval_candidates_mass.json", - "molecules/MassSpecGym_retrieval_candidates_formula.json", -] - -MOLECULE_FILES = [ - "molecules/MassSpecGym_retrieval_molecules_1M.tsv", -] - - -def download_massspecgym_data( - include_retrieval: bool = True, - include_molecules: bool = False, - verbose: bool = True, -) -> dict: - """Download MassSpecGym files from HuggingFace. - - Files are cached by huggingface_hub to ~/.cache/huggingface/hub/ and - the function returns a dict mapping file names to local paths. - - Args: - include_retrieval: Download retrieval candidate files. - include_molecules: Download molecule library files. - verbose: Print progress. - - Returns: - Dict mapping HF file names to local file paths. - """ - files_to_download = list(CORE_FILES) - if include_retrieval: - files_to_download.extend(RETRIEVAL_FILES) - if include_molecules: - files_to_download.extend(MOLECULE_FILES) - - paths = {} - for f in files_to_download: - if verbose: - logger.info(f"Downloading {f}...") - try: - local_path = hugging_face_download(f) - paths[f] = local_path - if verbose: - logger.info(f" -> {local_path}") - except Exception as e: - logger.warning(f" Failed to download {f}: {e}") - - return paths - - -def get_massspecgym_tsv_path() -> str: - """Get the local path to MassSpecGym.tsv, downloading if needed.""" - return hugging_face_download("MassSpecGym.tsv") - - -def get_retrieval_candidates_path(bonus: bool = False) -> str: - """Get path to retrieval candidates JSON, downloading if needed. - - Args: - bonus: If True, use formula-based candidates (bonus task). - """ - if bonus: - return hugging_face_download("molecules/MassSpecGym_retrieval_candidates_formula.json") - return hugging_face_download("molecules/MassSpecGym_retrieval_candidates_mass.json") diff --git a/massspecgym/data/fp2mol_dataset.py b/massspecgym/data/fp2mol_dataset.py deleted file mode 100644 index 105c61f..0000000 --- a/massspecgym/data/fp2mol_dataset.py +++ /dev/null @@ -1,220 +0,0 @@ -""" -Dataset for FP-to-molecule decoder pretraining. - -Loads molecule libraries from Parquet files (standard format) or programmatic -SMILES lists, produces (fingerprint, formula, molecule_representation) training -triples. Performs mandatory InChIKey sanity check against the MassSpecGym -exclusion list to prevent data leakage. - -Standard Parquet schema: - smiles (string, required) - inchikey_14 (string, required) - formula (string, optional - auto-computed) - selfies (string, optional) - safe (string, optional) - -Use scripts/convert_to_parquet.py to convert raw SMILES/CSV/TSV to Parquet. -""" - -import logging -from pathlib import Path -from typing import List, Optional, Set, Union - -import numpy as np -import pandas as pd -import torch -from rdkit import Chem -from rdkit.Chem import AllChem -from rdkit.Chem.rdMolDescriptors import CalcMolFormula -from torch.utils.data import Dataset - -from massspecgym.data.sanity_check import ( - DataLeakageError, - check_inchikey_overlap_strict, -) - -logger = logging.getLogger(__name__) - - -class FP2MolDataset(Dataset): - """Dataset for fingerprint-to-molecule decoder pretraining. - - Accepts Parquet files as the standard input format, or programmatic - SMILES lists. Performs mandatory InChIKey sanity check at init. - - Args: - smiles_source: Path to a .parquet file, or a list of SMILES strings. - mol_repr: Target molecular representation ('smiles', 'selfies', 'safe'). - fingerprint_type: Fingerprint type ('morgan'). - fp_bits: Number of fingerprint bits. - fp_radius: Morgan fingerprint radius. - exclude_inchikeys: Path to exclusion list CSV. Defaults to - data/exclude_inchikeys.csv. Set to False to disable (NOT recommended). - max_molecules: Maximum number of molecules to load. - cache_fingerprints: If True, pre-compute and cache all fingerprints. - """ - - def __init__( - self, - smiles_source: Union[str, Path, List[str]], - mol_repr: str = "smiles", - fingerprint_type: str = "morgan", - fp_bits: int = 4096, - fp_radius: int = 2, - exclude_inchikeys: Union[str, Path, bool, None] = None, - max_molecules: Optional[int] = None, - cache_fingerprints: bool = True, - ): - super().__init__() - self.mol_repr = mol_repr - self.fingerprint_type = fingerprint_type - self.fp_bits = fp_bits - self.fp_radius = fp_radius - self.cache_fingerprints = cache_fingerprints - - from massspecgym.models.de_novo.fp2mol.formula_utils import FormulaEncoder - self.formula_encoder = FormulaEncoder(normalize="none") - - df = self._load_source(smiles_source, max_molecules) - self._ensure_columns(df) - - if exclude_inchikeys is not False: - exclude_path = str(exclude_inchikeys) if exclude_inchikeys else None - check_inchikey_overlap_strict(df["inchikey_14"].tolist(), exclude_path) - - self.smiles = df["smiles"].tolist() - self.formulas = df["formula"].tolist() - self._mol_repr_col = None - if mol_repr in df.columns and mol_repr != "smiles": - self._mol_repr_col = df[mol_repr].tolist() - - logger.info(f"FP2MolDataset: {len(self.smiles)} molecules loaded") - - self._fp_cache: dict = {} - if self.cache_fingerprints: - self._precompute_fingerprints() - - @staticmethod - def _load_source(source: Union[str, Path, List[str]], max_molecules) -> pd.DataFrame: - if isinstance(source, (str, Path)): - path = Path(source) - if path.suffix == ".parquet": - df = pd.read_parquet(path) - else: - raise ValueError( - f"FP2MolDataset only accepts .parquet files. Got: {path.suffix}\n" - f"Use scripts/convert_to_parquet.py to convert your data first." - ) - elif isinstance(source, list): - df = pd.DataFrame({"smiles": source}) - else: - raise TypeError(f"Unsupported source type: {type(source)}") - - if max_molecules and len(df) > max_molecules: - df = df.head(max_molecules) - return df.reset_index(drop=True) - - @staticmethod - def _ensure_columns(df: pd.DataFrame): - """Ensure required columns exist, computing missing ones.""" - if "smiles" not in df.columns: - raise ValueError("Parquet must have a 'smiles' column") - - if "inchikey_14" not in df.columns: - logger.info("Computing inchikey_14 from SMILES...") - df["inchikey_14"] = df["smiles"].apply(FP2MolDataset._smiles_to_inchikey14) - - if "formula" not in df.columns: - logger.info("Computing formula from SMILES...") - df["formula"] = df["smiles"].apply(FP2MolDataset._smiles_to_formula) - - valid = df["smiles"].apply(lambda s: Chem.MolFromSmiles(s) is not None) - n_invalid = (~valid).sum() - if n_invalid > 0: - logger.warning(f"Dropping {n_invalid} invalid SMILES") - df.drop(df[~valid].index, inplace=True) - df.reset_index(drop=True, inplace=True) - - @staticmethod - def _smiles_to_inchikey14(smi: str) -> str: - mol = Chem.MolFromSmiles(smi) - if mol is None: - return "" - try: - ik = Chem.MolToInchiKey(mol) - return ik.split("-")[0] if ik else "" - except Exception: - return "" - - @staticmethod - def _smiles_to_formula(smi: str) -> str: - mol = Chem.MolFromSmiles(smi) - if mol is None: - return "" - try: - f = CalcMolFormula(mol) - return f.split("+")[0].split("-")[0] - except Exception: - return "" - - def _precompute_fingerprints(self): - for idx in range(len(self.smiles)): - self._fp_cache[idx] = self._compute_fingerprint(self.smiles[idx]) - - def _compute_fingerprint(self, smiles: str) -> torch.Tensor: - mol = Chem.MolFromSmiles(smiles) - if mol is None: - return torch.zeros(self.fp_bits, dtype=torch.float32) - if self.fingerprint_type == "morgan": - fp = AllChem.GetMorganFingerprintAsBitVect(mol, self.fp_radius, nBits=self.fp_bits) - arr = np.zeros(self.fp_bits, dtype=np.float32) - AllChem.DataStructs.ConvertToNumpyArray(fp, arr) - return torch.from_numpy(arr) - raise ValueError(f"Unknown fingerprint type: {self.fingerprint_type}") - - def _convert_mol_repr(self, smiles: str, idx: int) -> str: - if self._mol_repr_col is not None: - return self._mol_repr_col[idx] - if self.mol_repr == "smiles": - return smiles - elif self.mol_repr == "selfies": - try: - import selfies as sf - return sf.encoder(smiles) - except Exception: - return smiles - elif self.mol_repr == "safe": - try: - from safe import encode as safe_encode - return safe_encode(smiles) - except Exception: - return smiles - return smiles - - def __len__(self) -> int: - return len(self.smiles) - - def __getitem__(self, idx: int) -> dict: - smiles = self.smiles[idx] - formula = self.formulas[idx] - fingerprint = self._fp_cache[idx] if self.cache_fingerprints else self._compute_fingerprint(smiles) - formula_vec = self.formula_encoder.encode(formula) - target_repr = self._convert_mol_repr(smiles, idx) - - return { - "fingerprint": fingerprint, - "formula": formula, - "formula_vec": formula_vec, - "mol": smiles, - "mol_repr": target_repr, - } - - @staticmethod - def collate_fn(batch: list) -> dict: - return { - "fingerprint": torch.stack([b["fingerprint"] for b in batch]), - "formula_vec": torch.stack([b["formula_vec"] for b in batch]), - "formula": [b["formula"] for b in batch], - "mol": [b["mol"] for b in batch], - "mol_repr": [b["mol_repr"] for b in batch], - } diff --git a/massspecgym/data/mist_data_mixin.py b/massspecgym/data/mist_data_mixin.py deleted file mode 100644 index bf1ba7a..0000000 --- a/massspecgym/data/mist_data_mixin.py +++ /dev/null @@ -1,103 +0,0 @@ -""" -Mixin for MIST-based models that need subformulae-annotated data. - -Provides auto-detection of MIST-format data and lazy conversion from -the standard MassSpecGym TSV format. Used by the MIST encoder, all -FP2Mol decoders, and the MIST-CF oracle. -""" - -import logging -from pathlib import Path -from typing import Optional - -logger = logging.getLogger(__name__) - -DEFAULT_MIST_DATA_DIR = Path("data/mist_format") - - -class MISTDataMixin: - """Mixin providing auto-conversion of MassSpecGym data to MIST format. - - Any model that requires subformulae-annotated spectra can inherit from - this mixin and call ``ensure_mist_data()`` before using the data. - """ - - def ensure_mist_data( - self, - data_dir: Optional[str] = None, - tsv_path: Optional[str] = None, - run_subformulae: bool = True, - num_workers: int = 16, - ) -> Path: - """Ensure MIST-format data exists, converting from TSV if needed. - - Checks for: - 1. spec_files/ directory with .ms files - 2. labels.tsv - 3. subformulae/default_subformulae/ with JSON files - - If any are missing, runs the full conversion pipeline. - - Args: - data_dir: Path to MIST-format data directory. - Defaults to data/mist_format/. - tsv_path: Path to MassSpecGym TSV (auto-downloads if None). - run_subformulae: Whether to generate subformulae JSONs. - num_workers: Workers for parallel processing. - - Returns: - Path to the MIST-format data directory. - """ - if data_dir is None: - data_dir = DEFAULT_MIST_DATA_DIR - data_dir = Path(data_dir) - - spec_dir = data_dir / "spec_files" - labels_file = data_dir / "labels.tsv" - subform_dir = data_dir / "subformulae" / "default_subformulae" - - needs_conversion = ( - not spec_dir.exists() - or not labels_file.exists() - or not any(spec_dir.glob("*.ms")) - ) - needs_subformulae = run_subformulae and ( - not subform_dir.exists() - or not any(subform_dir.glob("*.json")) - ) - - if needs_conversion: - logger.info( - f"MIST-format data not found at {data_dir}. " - f"Converting from MassSpecGym TSV..." - ) - from massspecgym.data.mist_format import convert_massspecgym_to_mist - convert_massspecgym_to_mist( - tsv_path=tsv_path, - output_dir=str(data_dir), - run_subformulae=run_subformulae, - num_workers=num_workers, - ) - elif needs_subformulae: - logger.info( - f"Subformulae not found at {subform_dir}. Running assignment..." - ) - import pandas as pd - from massspecgym.data.subformulae import assign_subformulae_dataset - - labels_df = pd.read_csv(labels_file, sep="\t") - assign_subformulae_dataset( - spec_source=spec_dir, - labels_df=labels_df, - output_dir=subform_dir, - num_workers=num_workers, - ) - else: - logger.info(f"MIST-format data found at {data_dir}") - - return data_dir - - def get_subformulae_dir(self, data_dir: Optional[str] = None) -> Path: - """Get path to subformulae directory, ensuring it exists.""" - data_dir = self.ensure_mist_data(data_dir) - return data_dir / "subformulae" / "default_subformulae" diff --git a/massspecgym/data/mist_format.py b/massspecgym/data/mist_format.py deleted file mode 100644 index e83a8be..0000000 --- a/massspecgym/data/mist_format.py +++ /dev/null @@ -1,184 +0,0 @@ -""" -Convert MassSpecGym data to MIST-compatible format. - -Produces the exact directory layout expected by the MIST encoder and all -MIST-based models: - - {output_dir}/ - labels.tsv # dataset, spec, ionization, formula, smiles, inchikey, instrument - split.tsv # name, split - spec_files/ # {identifier}.ms per spectrum - subformulae/ - default_subformulae/ - {identifier}.json - -The output matches /home/liuhx25/orcd/pool/data/msg/ identically. -""" - -import logging -from pathlib import Path -from typing import Optional - -import numpy as np -import pandas as pd -from tqdm import tqdm - -import massspecgym.utils as utils - -logger = logging.getLogger(__name__) - - -def _row_to_ms_string(identifier, formula, parent_mass, adduct, inchikey, - smiles, instrument, mzs, intensities, inchi=None): - """Convert a single MassSpecGym row to a SIRIUS-style .ms file string. - - Produces the exact format matching /home/liuhx25/orcd/pool/data/msg/spec_files/*.ms - """ - lines = [] - lines.append(f">compound {identifier}") - lines.append(f">formula {formula}") - lines.append(f">parentmass {parent_mass}") - - ion_str = adduct - if adduct == "[M+H]+": - ion_str = "[M+H]+" - elif adduct == "[M+Na]+": - ion_str = "[M+Na]+" - lines.append(f">ionization {ion_str}") - - lines.append(f">InChi {inchi if inchi else 'None'}") - lines.append(f">InChiKey {inchikey}") - lines.append(f"#smiles {smiles}") - lines.append(f"#instrumentation {instrument}") - lines.append(f"#_FILE {identifier}") - - if inchi: - lines.append(f"#InChi {inchi}") - - lines.append("") - lines.append(">ms2peaks") - - if isinstance(mzs, str): - mz_arr = [float(m) for m in mzs.split(",")] - int_arr = [float(i) for i in intensities.split(",")] - else: - mz_arr = list(mzs) - int_arr = list(intensities) - - for mz, inten in zip(mz_arr, int_arr): - lines.append(f"{mz} {inten}") - - return "\n".join(lines) - - -def _make_labels_tsv(df: pd.DataFrame) -> pd.DataFrame: - """Create MIST-format labels.tsv from MassSpecGym DataFrame.""" - labels = pd.DataFrame() - labels["dataset"] = "MassSpecGym" - labels["spec"] = df["identifier"] - labels["ionization"] = df["adduct"] - labels["formula"] = df["formula"] - labels["smiles"] = df["smiles"] - labels["inchikey"] = df["inchikey"] if "inchikey" in df.columns else "" - labels["instrument"] = df["instrument_type"] if "instrument_type" in df.columns else "unknown" - return labels - - -def _make_split_tsv(df: pd.DataFrame) -> pd.DataFrame: - """Create MIST-format split.tsv from MassSpecGym DataFrame.""" - split = pd.DataFrame() - split["name"] = df["identifier"] - split["split"] = df["fold"] - return split - - -def convert_massspecgym_to_mist( - tsv_path: Optional[str] = None, - output_dir: str = "data/mist_format", - run_subformulae: bool = True, - mass_diff_thresh: float = 20.0, - max_peaks: int = 50, - num_workers: int = 16, -) -> Path: - """Convert MassSpecGym dataset to MIST-compatible directory layout. - - Args: - tsv_path: Path to MassSpecGym.tsv. If None, downloads from HuggingFace. - output_dir: Target directory for the MIST-format output. - run_subformulae: Whether to also run subformulae assignment. - mass_diff_thresh: PPM threshold for subformulae assignment. - max_peaks: Maximum number of peaks per spectrum. - num_workers: Workers for parallel subformulae assignment. - - Returns: - Path to the output directory. - """ - output_dir = Path(output_dir) - spec_dir = output_dir / "spec_files" - spec_dir.mkdir(parents=True, exist_ok=True) - - if tsv_path is None: - logger.info("Downloading MassSpecGym.tsv from HuggingFace...") - tsv_path = utils.hugging_face_download("MassSpecGym.tsv") - - logger.info(f"Loading {tsv_path}...") - df = pd.read_csv(tsv_path, sep="\t") - - logger.info(f"Writing {len(df)} .ms files to {spec_dir}...") - for _, row in tqdm(df.iterrows(), total=len(df), desc="Writing .ms files"): - identifier = row["identifier"] - - inchikey = row.get("inchikey", "") - if pd.isna(inchikey): - inchikey = "" - - inchi = None - if "inchi" in row and not pd.isna(row.get("inchi", None)): - inchi = row["inchi"] - - instrument = row.get("instrument_type", "unknown") - if pd.isna(instrument): - instrument = "unknown" - - parent_mass = row.get("parent_mass", row.get("precursor_mz", 0)) - - ms_str = _row_to_ms_string( - identifier=identifier, - formula=row["formula"], - parent_mass=parent_mass, - adduct=row["adduct"], - inchikey=inchikey, - smiles=row["smiles"], - instrument=instrument, - mzs=row["mzs"], - intensities=row["intensities"], - inchi=inchi, - ) - - with open(spec_dir / f"{identifier}.ms", "w") as f: - f.write(ms_str) - - labels_df = _make_labels_tsv(df) - labels_df.to_csv(output_dir / "labels.tsv", sep="\t", index=False) - - split_df = _make_split_tsv(df) - split_df.to_csv(output_dir / "split.tsv", sep="\t", index=False) - - logger.info(f"Wrote labels.tsv ({len(labels_df)} rows) and split.tsv to {output_dir}") - - if run_subformulae: - from massspecgym.data.subformulae import assign_subformulae_dataset - - subform_dir = output_dir / "subformulae" / "default_subformulae" - logger.info(f"Running subformulae assignment to {subform_dir}...") - assign_subformulae_dataset( - spec_source=spec_dir, - labels_df=labels_df, - output_dir=subform_dir, - mass_diff_thresh=mass_diff_thresh, - max_peaks=max_peaks, - num_workers=num_workers, - ) - - logger.info(f"MIST format conversion complete: {output_dir}") - return output_dir diff --git a/massspecgym/data/sanity_check.py b/massspecgym/data/sanity_check.py deleted file mode 100644 index f2d4ed4..0000000 --- a/massspecgym/data/sanity_check.py +++ /dev/null @@ -1,157 +0,0 @@ -""" -InChIKey-based data safety sanity check for MassSpecGym. - -Ensures that unpaired molecule datasets used for decoder pretraining do not -contain any molecules whose 2D InChIKey (first 14 characters) overlaps with -the MassSpecGym test/validation exclusion list. - -Usage as standalone CLI: - python -m massspecgym.data.sanity_check --input molecules.parquet - -Usage as library: - from massspecgym.data.sanity_check import check_inchikey_overlap - result = check_inchikey_overlap(my_inchikeys) - assert result.is_clean, f"Found {result.overlap_count} overlapping molecules!" -""" - -import logging -import sys -from dataclasses import dataclass, field -from pathlib import Path -from typing import Iterable, Optional, Set - -logger = logging.getLogger(__name__) - -DEFAULT_EXCLUDE_PATH = Path(__file__).parent.parent.parent / "data" / "exclude_inchikeys.csv" - - -class DataLeakageError(Exception): - """Raised when training data overlaps with excluded InChIKeys.""" - pass - - -@dataclass -class SanityCheckResult: - """Result of an InChIKey overlap sanity check.""" - total_molecules: int - overlap_count: int - overlap_inchikeys: Set[str] = field(default_factory=set) - - @property - def is_clean(self) -> bool: - return self.overlap_count == 0 - - -def load_exclusion_set( - exclude_path: Optional[str] = None, -) -> Set[str]: - """Load the set of excluded 2D InChIKeys from CSV. - - Args: - exclude_path: Path to CSV file with column 'inchi' containing 14-char InChIKeys. - If None, uses the default MassSpecGym exclusion list. - - Returns: - Set of 14-character 2D InChIKeys. - """ - if exclude_path is None: - exclude_path = DEFAULT_EXCLUDE_PATH - exclude_path = Path(exclude_path) - - if not exclude_path.exists(): - logger.warning(f"Exclusion list not found at {exclude_path}") - return set() - - keys = set() - with open(exclude_path, "r") as f: - for i, line in enumerate(f): - key = line.strip() - if i == 0 and key.lower() in ("inchi", "inchikey", "inchikey_14"): - continue - if key and len(key) >= 14: - keys.add(key[:14]) - elif key: - keys.add(key) - return keys - - -def check_inchikey_overlap( - molecule_inchikeys: Iterable[str], - exclude_path: Optional[str] = None, -) -> SanityCheckResult: - """Check whether any molecule InChIKeys overlap with the exclusion list. - - Args: - molecule_inchikeys: Iterable of InChIKey strings (full or 14-char). - exclude_path: Path to exclusion CSV. Defaults to data/exclude_inchikeys.csv. - - Returns: - SanityCheckResult with overlap details. - """ - exclude_set = load_exclusion_set(exclude_path) - total = 0 - overlap = set() - - for key in molecule_inchikeys: - total += 1 - if not key: - continue - key_14 = key[:14] if len(key) > 14 else key - if key_14 in exclude_set: - overlap.add(key_14) - - return SanityCheckResult( - total_molecules=total, - overlap_count=len(overlap), - overlap_inchikeys=overlap, - ) - - -def check_inchikey_overlap_strict( - molecule_inchikeys: Iterable[str], - exclude_path: Optional[str] = None, -) -> SanityCheckResult: - """Like check_inchikey_overlap, but raises DataLeakageError on overlap.""" - result = check_inchikey_overlap(molecule_inchikeys, exclude_path) - if not result.is_clean: - raise DataLeakageError( - f"Data leakage detected: {result.overlap_count} molecules overlap with " - f"MassSpecGym exclusion list. First few: {list(result.overlap_inchikeys)[:5]}" - ) - return result - - -if __name__ == "__main__": - import argparse - - parser = argparse.ArgumentParser(description="Check InChIKey overlap with MassSpecGym exclusion list") - parser.add_argument("--input", required=True, help="Path to Parquet or CSV file with molecules") - parser.add_argument("--exclude", default=None, help="Path to exclusion CSV (default: data/exclude_inchikeys.csv)") - parser.add_argument("--inchikey-col", default="inchikey_14", help="Column name for InChIKey") - args = parser.parse_args() - - import pandas as pd - input_path = Path(args.input) - if input_path.suffix == ".parquet": - df = pd.read_parquet(input_path) - else: - df = pd.read_csv(input_path) - - col = args.inchikey_col - if col not in df.columns: - for alt in ["inchikey", "inchi", "InChIKey", "INCHIKEY"]: - if alt in df.columns: - col = alt - break - - if col not in df.columns: - print(f"ERROR: No InChIKey column found. Available: {list(df.columns)}") - sys.exit(1) - - result = check_inchikey_overlap(df[col].dropna().tolist(), args.exclude) - if result.is_clean: - print(f"CLEAN: {result.total_molecules} molecules checked, no overlap found.") - else: - print(f"WARNING: {result.overlap_count} overlapping InChIKeys found!") - print(f"First 10: {list(result.overlap_inchikeys)[:10]}") - sys.exit(1) diff --git a/massspecgym/data/subformulae.py b/massspecgym/data/subformulae.py deleted file mode 100644 index a0db998..0000000 --- a/massspecgym/data/subformulae.py +++ /dev/null @@ -1,388 +0,0 @@ -""" -Subformulae assignment for mass spectra. - -Assigns chemical subformulae to MS/MS peaks by matching observed m/z values -to theoretical monoisotopic masses of all possible subfragments of the -precursor formula. This is required by the MIST encoder and all MIST-based -models. - -Ported from external/mist/src/mist/utils/spectra_utils.py and -external/mist/src/mist/subformulae/assign_subformulae.py to be -self-contained within MassSpecGym. -""" - -import json -import logging -from functools import partial -from itertools import groupby -from pathlib import Path -from typing import Dict, List, Optional, Tuple - -import numpy as np -import pandas as pd -from tqdm import tqdm - -from massspecgym.models.encoders.mist.chem_constants import ( - ION_LST, - clipped_ppm, - get_all_subsets, - ion_to_mass, - vec_to_formula, -) - -logger = logging.getLogger(__name__) - - -# --------------------------------------------------------------------------- -# Spectrum parsing (from external/mist/src/mist/utils/parse_utils.py) -# --------------------------------------------------------------------------- - -def parse_spectra_ms(spectra_file: str) -> Tuple[dict, List[Tuple[str, np.ndarray]]]: - """Parse a SIRIUS-style .ms file into metadata and peak arrays.""" - lines = [i.strip() for i in open(spectra_file, "r").readlines()] - - group_num = 0 - metadata = {} - spectras = [] - my_iterator = groupby( - lines, lambda line: line.startswith(">") or line.startswith("#") - ) - - for index, (start_line, lines) in enumerate(my_iterator): - group_lines = list(lines) - subject_lines = list(next(my_iterator)[1]) - if group_num > 0: - spectra_header = group_lines[0].split(">")[1] - peak_data = [ - [float(x) for x in peak.split()[:2]] - for peak in subject_lines - if peak.strip() - ] - if len(peak_data): - peak_data = np.vstack(peak_data) - spectras.append((spectra_header, peak_data)) - else: - entries = {} - for i in group_lines: - if " " not in i: - continue - elif i.startswith("#INSTRUMENT TYPE"): - key = "#INSTRUMENT TYPE" - val = i.split(key)[1].strip() - entries[key[1:]] = val - else: - start, end = i.split(" ", 1) - start = start[1:] - while start in entries: - start = f"{start}'" - entries[start] = end - metadata.update(entries) - group_num += 1 - - metadata["_FILE_PATH"] = spectra_file - metadata["_FILE"] = Path(spectra_file).stem - return metadata, spectras - - -def parse_spectra_mgf( - mgf_file: str, max_num: Optional[int] = None -) -> List[Tuple[dict, List[Tuple[str, np.ndarray]]]]: - """Parse an MGF file into list of (metadata, peak_arrays) tuples.""" - key = lambda x: x.strip() == "BEGIN IONS" - parsed_spectra = [] - with open(mgf_file, "r") as fp: - for (is_header, group) in groupby(fp, key): - if is_header: - continue - meta = {} - cur_spectra = [] - for line in group: - line = line.strip() - if not line or line == "END IONS" or line == "BEGIN IONS": - continue - elif "=" in line: - k, v = [i.strip() for i in line.split("=", 1)] - meta[k] = v - else: - parts = line.split() - if len(parts) >= 2: - cur_spectra.append((float(parts[0]), float(parts[1]))) - if cur_spectra: - cur_spectra = np.vstack(cur_spectra) - parsed_spectra.append((meta, [("spec", cur_spectra)])) - if max_num is not None and len(parsed_spectra) > max_num: - break - return parsed_spectra - - -# --------------------------------------------------------------------------- -# Spectrum processing (from external/mist/src/mist/utils/spectra_utils.py) -# --------------------------------------------------------------------------- - -def process_spec_file(meta, tuples, precision=4, max_inten=0.001, max_peaks=60): - """Process raw spectrum tuples: merge, normalize, sqrt, filter. - - Args: - meta: Spectrum metadata dict (needs 'parentmass' or 'PEPMASS'). - tuples: List of (header, peak_array) tuples. - precision: Decimal precision for merging. - max_inten: Minimum intensity threshold. - max_peaks: Maximum number of peaks to retain. - - Returns: - np.ndarray of shape (N, 2) with [mz, intensity] or None. - """ - if "parentmass" in meta: - parentmass = meta.get("parentmass", None) - elif "PARENTMASS" in meta: - parentmass = meta.get("PARENTMASS", None) - elif "PEPMASS" in meta: - parentmass = meta.get("PEPMASS", None) - else: - parentmass = 1000000 - - parentmass = float(parentmass) - - fused_tuples = [x for _, x in tuples if x.size > 0] - if len(fused_tuples) == 0: - return None - - mz_to_inten_pair = {} - new_tuples = [] - for i in fused_tuples: - for tup in i: - mz, inten = tup - mz_ind = np.round(mz, precision) - cur_pair = mz_to_inten_pair.get(mz_ind) - if cur_pair is None: - mz_to_inten_pair[mz_ind] = tup - new_tuples.append(tup) - elif inten > cur_pair[1]: - cur_pair[1] = inten - - merged_spec = np.vstack(new_tuples) - merged_spec = merged_spec[merged_spec[:, 0] <= (parentmass + 1)] - if merged_spec.shape[0] == 0: - return None - merged_spec[:, 1] = merged_spec[:, 1] / merged_spec[:, 1].max() - merged_spec[:, 1] = np.sqrt(merged_spec[:, 1]) - - merged_spec = _max_inten_spec( - merged_spec, max_num_inten=max_peaks, inten_thresh=max_inten - ) - return merged_spec - - -def _max_inten_spec(spec, max_num_inten=60, inten_thresh=0): - """Keep top-k peaks by intensity above threshold.""" - spec_masses, spec_intens = spec[:, 0], spec[:, 1] - new_sort_order = np.argsort(spec_intens)[::-1] - if max_num_inten is not None: - new_sort_order = new_sort_order[:max_num_inten] - spec_masses = spec_masses[new_sort_order] - spec_intens = spec_intens[new_sort_order] - spec_mask = spec_intens > inten_thresh - spec_masses = spec_masses[spec_mask] - spec_intens = spec_intens[spec_mask] - return np.vstack([spec_masses, spec_intens]).transpose(1, 0) - - -# --------------------------------------------------------------------------- -# Core subformulae assignment (from spectra_utils.assign_subforms) -# --------------------------------------------------------------------------- - -def assign_subformulae_single( - formula: str, - spectrum: np.ndarray, - ion_type: str, - mass_diff_thresh: float = 20.0, -) -> dict: - """Assign subformulae to a single spectrum. - - Matches the reference MIST implementation exactly: - 1. Enumerate all subformulae of the precursor formula. - 2. Compute monoisotopic masses (with adduct correction). - 3. Match each peak to the nearest subformula by ppm. - 4. Deduplicate by formula, merging intensities. - - Args: - formula: Precursor molecular formula string (e.g., "C16H17NO4"). - spectrum: Array of shape (N, 2) with [mz, intensity]. - ion_type: Adduct string (e.g., "[M+H]+"). - mass_diff_thresh: Maximum ppm tolerance for matching. - - Returns: - Dict with keys: cand_form, cand_ion, output_tbl (or None). - """ - output_dict = {"cand_form": formula, "cand_ion": ion_type, "output_tbl": None} - - if spectrum is None or ion_type not in ION_LST: - return output_dict - - cross_prod, masses = get_all_subsets(formula) - spec_masses, spec_intens = spectrum[:, 0], spectrum[:, 1] - - ion_masses = ion_to_mass[ion_type] - masses_with_ion = masses + ion_masses - ion_types = np.array([ion_type] * len(masses_with_ion)) - - mass_diffs = np.abs(spec_masses[:, None] - masses_with_ion[None, :]) - formula_inds = mass_diffs.argmin(-1) - min_mass_diff = mass_diffs[np.arange(len(mass_diffs)), formula_inds] - rel_mass_diff = clipped_ppm(min_mass_diff, spec_masses) - - valid_mask = rel_mass_diff < mass_diff_thresh - spec_masses = spec_masses[valid_mask] - spec_intens = spec_intens[valid_mask] - min_mass_diff = min_mass_diff[valid_mask] - rel_mass_diff = rel_mass_diff[valid_mask] - formula_inds = formula_inds[valid_mask] - - if spec_masses.size == 0: - output_dict["output_tbl"] = None - return output_dict - - formulas = np.array([vec_to_formula(j) for j in cross_prod[formula_inds]]) - formula_masses = masses_with_ion[formula_inds] - ion_types = ion_types[formula_inds] - - formula_idx_dict = {} - uniq_mask = [] - for idx, f in enumerate(formulas): - uniq_mask.append(f not in formula_idx_dict) - gather_ind = formula_idx_dict.get(f, None) - if gather_ind is None: - formula_idx_dict[f] = idx - continue - spec_intens[gather_ind] += spec_intens[idx] - - uniq_mask = np.array(uniq_mask, dtype=bool) - spec_masses = spec_masses[uniq_mask] - spec_intens = spec_intens[uniq_mask] - min_mass_diff = min_mass_diff[uniq_mask] - rel_mass_diff = rel_mass_diff[uniq_mask] - formula_masses = formula_masses[uniq_mask] - formulas = formulas[uniq_mask] - ion_types = ion_types[uniq_mask] - - if spec_intens.size == 0: - output_tbl = None - else: - output_tbl = { - "mz": list(spec_masses), - "ms2_inten": list(spec_intens), - "mono_mass": list(formula_masses), - "abs_mass_diff": list(min_mass_diff), - "mass_diff": list(rel_mass_diff), - "formula": list(formulas), - "ions": list(ion_types), - } - output_dict["output_tbl"] = output_tbl - return output_dict - - -def get_output_dict( - spec_name: str, - spec: Optional[np.ndarray], - form: str, - mass_diff_type: str, - mass_diff_thresh: float, - ion_type: str, -) -> dict: - """Wrapper matching the reference MIST get_output_dict exactly.""" - assert mass_diff_type == "ppm" - output_dict = {"cand_form": form, "cand_ion": ion_type, "output_tbl": None} - if spec is not None and ion_type in ION_LST: - output_dict = assign_subformulae_single( - form, spec, ion_type, mass_diff_thresh=mass_diff_thresh - ) - return output_dict - - -# --------------------------------------------------------------------------- -# Batch assignment for a full dataset -# --------------------------------------------------------------------------- - -def _process_single_ms(spec_name: str, spec_files_dir: str, - max_inten: float = 0.001, max_peaks: int = 50): - """Parse and process a single .ms file.""" - spec_file = Path(spec_files_dir) / f"{spec_name}.ms" - meta, tuples = parse_spectra_ms(str(spec_file)) - spec = process_spec_file(meta, tuples, max_inten=max_inten, max_peaks=max_peaks) - return spec_name, spec - - -def assign_subformulae_dataset( - spec_source, - labels_df: pd.DataFrame, - output_dir, - mass_diff_thresh: float = 20.0, - inten_thresh: float = 0.001, - max_peaks: int = 50, - feature_id: str = "ID", - num_workers: int = 16, -) -> Path: - """Assign subformulae for an entire dataset, writing one JSON per spectrum. - - Args: - spec_source: Path to .ms directory or .mgf file. - labels_df: DataFrame with columns: spec, formula, ionization. - output_dir: Directory to write JSON files. - mass_diff_thresh: PPM threshold for peak matching. - inten_thresh: Minimum intensity threshold. - max_peaks: Maximum number of peaks per spectrum. - feature_id: MGF field name for spectrum ID. - num_workers: Number of parallel workers. - - Returns: - Path to the output directory containing JSON files. - """ - spec_source = Path(spec_source) - output_dir = Path(output_dir) - output_dir.mkdir(exist_ok=True, parents=True) - - labels_df = labels_df.astype(str) - - if spec_source.suffix == ".mgf": - parsed = parse_spectra_mgf(str(spec_source)) - input_specs = {} - for meta, tuples in parsed: - name = meta.get(feature_id, meta.get("FEATURE_ID", "unknown")) - spec = process_spec_file(meta, tuples, max_inten=inten_thresh, max_peaks=max_peaks) - input_specs[name] = spec - elif spec_source.is_dir(): - input_specs = {} - for _, row in tqdm(labels_df.iterrows(), total=len(labels_df), desc="Parsing spectra"): - spec_name = str(row["spec"]) - try: - _, spec = _process_single_ms( - spec_name, str(spec_source), - max_inten=inten_thresh, max_peaks=max_peaks - ) - input_specs[spec_name] = spec - except Exception as e: - logger.warning(f"Failed to parse {spec_name}: {e}") - input_specs[spec_name] = None - else: - raise ValueError(f"spec_source must be a directory or .mgf file, got: {spec_source}") - - for _, row in tqdm(labels_df.iterrows(), total=len(labels_df), desc="Assigning subformulae"): - spec_name = str(row["spec"]) - formula = str(row["formula"]) - ion_type = str(row["ionization"]) - spec = input_specs.get(spec_name) - - output_dict = get_output_dict( - spec_name=spec_name, - spec=spec, - form=formula, - mass_diff_type="ppm", - mass_diff_thresh=mass_diff_thresh, - ion_type=ion_type, - ) - - with open(output_dir / f"{spec_name}.json", "w") as f: - json.dump(output_dict, f, indent=4) - - logger.info(f"Wrote {len(labels_df)} subformulae JSONs to {output_dir}") - return output_dir diff --git a/massspecgym/models/de_novo/__init__.py b/massspecgym/models/de_novo/__init__.py index cddecd4..1e46612 100644 --- a/massspecgym/models/de_novo/__init__.py +++ b/massspecgym/models/de_novo/__init__.py @@ -3,34 +3,4 @@ from .dummy import DummyDeNovo from .smiles_tranformer import SmilesTransformer -__all__ = [ - "DeNovoMassSpecGymModel", - "RandomDeNovo", - "DummyDeNovo", - "SmilesTransformer", - "FP2MolDeNovoModel", - "FormulaEncoder", - "FRIGIDDecoder", - "MolForgeDecoder", - "DiffMSDecoder", -] - - -def __getattr__(name): - """Lazy imports for FP2Mol decoders to avoid pulling heavy optional dependencies.""" - if name == "FP2MolDeNovoModel": - from .fp2mol.base import FP2MolDeNovoModel - return FP2MolDeNovoModel - if name == "FormulaEncoder": - from .fp2mol.formula_utils import FormulaEncoder - return FormulaEncoder - if name == "FRIGIDDecoder": - from .fp2mol.frigid import FRIGIDDecoder - return FRIGIDDecoder - if name == "MolForgeDecoder": - from .fp2mol.molforge import MolForgeDecoder - return MolForgeDecoder - if name == "DiffMSDecoder": - from .fp2mol.diffms import DiffMSDecoder - return DiffMSDecoder - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") +__all__ = ["DeNovoMassSpecGymModel", "RandomDeNovo", "DummyDeNovo", "SmilesTransformer"] \ No newline at end of file diff --git a/massspecgym/models/de_novo/fp2mol/__init__.py b/massspecgym/models/de_novo/fp2mol/__init__.py deleted file mode 100644 index 5512d42..0000000 --- a/massspecgym/models/de_novo/fp2mol/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -FP2Mol decoder family: fingerprint-to-molecule de novo generation models. - -This package implements a family of de novo molecular generation models that -share a common two-stage pipeline: - - Spectrum --[MIST Encoder]--> Fingerprint + Formula --[Decoder]--> Molecule - -Three decoder architectures are provided: -- FRIGID: Masked Diffusion Language Model (MDLM) over SAFE sequences. -- DiffMS: Discrete graph diffusion over molecular graphs. -- MolForge: Autoregressive seq2seq transformer over SMILES/SELFIES. - -All decoders extend ``FP2MolDeNovoModel``, which provides: -- Optional MIST encoder for end-to-end spectrum-to-molecule inference. -- Two training modes: ``fp2mol_pretrain`` (decoder only) and ``spec2mol`` (end-to-end). -- Shared formula encoding via ``FormulaEncoder``. -""" - -from .base import FP2MolDeNovoModel -from .formula_utils import FormulaEncoder - - -def __getattr__(name): - if name == "FRIGIDDecoder": - from .frigid import FRIGIDDecoder - return FRIGIDDecoder - if name == "MolForgeDecoder": - from .molforge import MolForgeDecoder - return MolForgeDecoder - if name == "DiffMSDecoder": - from .diffms import DiffMSDecoder - return DiffMSDecoder - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/massspecgym/models/de_novo/fp2mol/base.py b/massspecgym/models/de_novo/fp2mol/base.py deleted file mode 100644 index 1d39592..0000000 --- a/massspecgym/models/de_novo/fp2mol/base.py +++ /dev/null @@ -1,160 +0,0 @@ -""" -Base class for all fingerprint-to-molecule de novo generation models. - -FP2MolDeNovoModel extends DeNovoMassSpecGymModel to support the common -two-stage pipeline: spectrum -> fingerprint -> molecule. It provides: - -1. Optional MIST encoder for end-to-end spectrum-to-molecule inference. -2. Two training modes: - - ``fp2mol_pretrain``: Train only the decoder on (fingerprint, formula, molecule) - triples from any molecule library. - - ``spec2mol``: Train or evaluate the full encoder+decoder pipeline on - MassSpecGym (spectrum, molecule) paired data. -3. A unified ``step()`` that routes to decoder-specific loss and generation. -""" - -import typing as T -from abc import abstractmethod -from pathlib import Path - -import torch - -from massspecgym.models.base import Stage -from massspecgym.models.de_novo.base import DeNovoMassSpecGymModel - - -class FP2MolDeNovoModel(DeNovoMassSpecGymModel): - """Base class for fingerprint-to-molecule de novo models. - - Subclasses must implement: - - ``decode_from_fingerprint``: Generate molecules from a fingerprint (+formula). - - ``compute_decoder_loss``: Compute decoder-specific training loss from a batch. - - Args: - encoder: Optional MIST encoder module (for end-to-end spec2mol mode). - encoder_checkpoint: Path to pretrained encoder weights. - fingerprint_bits: Dimensionality of the fingerprint vector. - use_formula: Whether the decoder uses formula conditioning. - training_mode: One of 'fp2mol_pretrain' or 'spec2mol'. - freeze_encoder: If True, freeze encoder weights during training. - num_generation_samples: Number of molecules to generate per spectrum at inference. - """ - - def __init__( - self, - encoder: T.Optional[torch.nn.Module] = None, - encoder_checkpoint: T.Optional[str] = None, - fingerprint_bits: int = 4096, - use_formula: bool = True, - training_mode: str = "spec2mol", - freeze_encoder: bool = True, - num_generation_samples: int = 10, - *args, - **kwargs, - ): - super().__init__(*args, **kwargs) - self.encoder = encoder - self.fingerprint_bits = fingerprint_bits - self.use_formula = use_formula - self.training_mode = training_mode - self.freeze_encoder = freeze_encoder - self.num_generation_samples = num_generation_samples - - if encoder_checkpoint is not None and self.encoder is not None: - self._load_encoder_checkpoint(encoder_checkpoint) - - if self.freeze_encoder and self.encoder is not None: - for param in self.encoder.parameters(): - param.requires_grad = False - - def _load_encoder_checkpoint(self, checkpoint_path: str): - """Load pretrained encoder weights from a checkpoint file.""" - ckpt = torch.load(checkpoint_path, map_location="cpu") - state_dict = ckpt if not isinstance(ckpt, dict) else ckpt.get("state_dict", ckpt) - self.encoder.load_state_dict(state_dict, strict=False) - - def encode_spectrum(self, batch: dict) -> T.Tuple[torch.Tensor, dict]: - """Run the MIST encoder on a spectrum batch. - - Args: - batch: Batch dict containing spectrum data (in MIST featurized format). - - Returns: - Tuple of (fingerprint tensor [B, fingerprint_bits], aux_outputs dict). - """ - if self.encoder is None: - raise RuntimeError( - "No encoder available. Either provide an encoder module or use " - "training_mode='fp2mol_pretrain' with pre-computed fingerprints." - ) - if self.freeze_encoder: - with torch.no_grad(): - return self.encoder(batch) - return self.encoder(batch) - - @abstractmethod - def decode_from_fingerprint( - self, - fingerprint: torch.Tensor, - formula: T.Optional[T.Any] = None, - num_samples: int = 1, - ) -> list[list[T.Optional[str]]]: - """Generate molecules from fingerprint (and optionally formula). - - Args: - fingerprint: Fingerprint tensor [B, fingerprint_bits]. - formula: Optional formula conditioning (format depends on decoder). - num_samples: Number of molecules to generate per input. - - Returns: - List of lists of SMILES strings (or None for failed generations). - Shape: (batch_size, num_samples). - """ - raise NotImplementedError - - @abstractmethod - def compute_decoder_loss(self, batch: dict) -> torch.Tensor: - """Compute the decoder-specific training loss. - - Args: - batch: Batch dict. In fp2mol_pretrain mode, contains 'fingerprint', - 'formula', and target molecule representations. In spec2mol mode, - contains spectrum data and molecule targets. - - Returns: - Scalar loss tensor. - """ - raise NotImplementedError - - def step(self, batch: dict, stage: Stage = Stage.NONE) -> dict: - """Unified training/evaluation step. - - In fp2mol_pretrain mode: - - Loss is computed from pre-computed fingerprints in the batch. - - Molecule generation is only performed during val/test. - - In spec2mol mode: - - Fingerprints are obtained from the MIST encoder. - - Loss and generation use the encoder output. - """ - if self.training_mode == "fp2mol_pretrain": - loss = self.compute_decoder_loss(batch) - if stage in self.log_only_loss_at_stages: - mols_pred = None - else: - fp = batch["fingerprint"] - formula = batch.get("formula", None) - mols_pred = self.decode_from_fingerprint( - fp, formula, num_samples=self.num_generation_samples - ) - else: - loss = self.compute_decoder_loss(batch) - if stage in self.log_only_loss_at_stages: - mols_pred = None - else: - fp, _ = self.encode_spectrum(batch) - formula = batch.get("formula", None) - mols_pred = self.decode_from_fingerprint( - fp, formula, num_samples=self.num_generation_samples - ) - return dict(loss=loss, mols_pred=mols_pred) diff --git a/massspecgym/models/de_novo/fp2mol/diffms/__init__.py b/massspecgym/models/de_novo/fp2mol/diffms/__init__.py deleted file mode 100644 index 4b468f4..0000000 --- a/massspecgym/models/de_novo/fp2mol/diffms/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -""" -DiffMS decoder: Discrete graph diffusion for fingerprint-to-molecule generation. - -A discrete denoising diffusion model that generates molecular graphs (atom types -and bond types) conditioned on Morgan fingerprints, from Bohde et al. 2025. -""" - -from .model import DiffMSDecoder diff --git a/massspecgym/models/de_novo/fp2mol/diffms/diffusion_utils.py b/massspecgym/models/de_novo/fp2mol/diffms/diffusion_utils.py deleted file mode 100644 index 5caba62..0000000 --- a/massspecgym/models/de_novo/fp2mol/diffms/diffusion_utils.py +++ /dev/null @@ -1,195 +0,0 @@ -""" -Discrete diffusion utilities for DiffMS. - -Provides noise schedule computation, posterior distribution calculation, -and discrete feature sampling for the graph diffusion process. -""" - -from dataclasses import dataclass -from typing import Optional - -import math -import numpy as np -import torch -import torch.nn.functional as F - - -@dataclass -class PlaceHolder: - """Container for graph features (nodes X, edges E, global y).""" - X: torch.Tensor - E: torch.Tensor - y: torch.Tensor - - def mask(self, node_mask): - x_mask = node_mask.unsqueeze(-1) - e_mask = x_mask.unsqueeze(2) * x_mask.unsqueeze(1) - self.X = self.X * x_mask - self.E = self.E * e_mask - return self - - -def assert_correctly_masked(variable, node_mask): - assert (variable * (1 - node_mask.long())).abs().max().item() < 1e-4 - - -def cosine_beta_schedule_discrete(timesteps, s=0.008): - """Cosine noise schedule for discrete diffusion.""" - steps = timesteps + 2 - x = np.linspace(0, steps, steps) - alphas_cumprod = np.cos(0.5 * np.pi * ((x / steps) + s) / (1 + s)) ** 2 - alphas_cumprod = alphas_cumprod / alphas_cumprod[0] - alphas = alphas_cumprod[1:] / alphas_cumprod[:-1] - betas = 1 - alphas - return betas.squeeze() - - -class PredefinedNoiseScheduleDiscrete(torch.nn.Module): - """Discrete noise schedule with precomputed betas and alpha_bars.""" - - def __init__(self, noise_schedule: str = "cosine", timesteps: int = 500): - super().__init__() - self.timesteps = timesteps - if noise_schedule == "cosine": - betas = cosine_beta_schedule_discrete(timesteps) - else: - raise NotImplementedError(noise_schedule) - - self.register_buffer("betas", torch.from_numpy(betas).float()) - self.alphas = 1 - torch.clamp(self.betas, min=0, max=0.9999) - log_alpha = torch.log(self.alphas) - log_alpha_bar = torch.cumsum(log_alpha, dim=0) - self.alphas_bar = torch.exp(log_alpha_bar) - - def forward(self, t_normalized=None, t_int=None): - assert (t_normalized is None) != (t_int is None) - if t_int is None: - t_int = torch.round(t_normalized * self.timesteps) - return self.betas[t_int.long()] - - def get_alpha_bar(self, t_normalized=None, t_int=None): - assert (t_normalized is None) != (t_int is None) - if t_int is None: - t_int = torch.round(t_normalized * self.timesteps) - return self.alphas_bar.to(t_int.device)[t_int.long()] - - -class MarginalUniformTransition: - """Transition matrices using marginal distributions as the limit.""" - - def __init__(self, x_marginals, e_marginals, y_classes): - self.X_classes = len(x_marginals) - self.E_classes = len(e_marginals) - self.y_classes = y_classes - self.u_x = x_marginals.unsqueeze(0).expand(self.X_classes, -1).unsqueeze(0) - self.u_e = e_marginals.unsqueeze(0).expand(self.E_classes, -1).unsqueeze(0) - self.u_y = torch.ones(1, self.y_classes, self.y_classes) - if self.y_classes > 0: - self.u_y = self.u_y / self.y_classes - - def get_Qt(self, beta_t, device): - beta_t = beta_t.unsqueeze(1).to(device) - self.u_x = self.u_x.to(device) - self.u_e = self.u_e.to(device) - self.u_y = self.u_y.to(device) - q_x = beta_t * self.u_x + (1 - beta_t) * torch.eye(self.X_classes, device=device).unsqueeze(0) - q_e = beta_t * self.u_e + (1 - beta_t) * torch.eye(self.E_classes, device=device).unsqueeze(0) - q_y = beta_t * self.u_y + (1 - beta_t) * torch.eye(self.y_classes, device=device).unsqueeze(0) - return PlaceHolder(X=q_x, E=q_e, y=q_y) - - def get_Qt_bar(self, alpha_bar_t, device): - alpha_bar_t = alpha_bar_t.unsqueeze(1).to(device) - self.u_x = self.u_x.to(device) - self.u_e = self.u_e.to(device) - self.u_y = self.u_y.to(device) - q_x = alpha_bar_t * torch.eye(self.X_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_x - q_e = alpha_bar_t * torch.eye(self.E_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_e - q_y = alpha_bar_t * torch.eye(self.y_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_y - return PlaceHolder(X=q_x, E=q_e, y=q_y) - - -class DiscreteUniformTransition: - """Transition matrices with uniform limit distribution.""" - - def __init__(self, x_classes, e_classes, y_classes): - self.X_classes = x_classes - self.E_classes = e_classes - self.y_classes = y_classes - self.u_x = torch.ones(1, x_classes, x_classes) / x_classes if x_classes > 0 else torch.zeros(1, 1, 1) - self.u_e = torch.ones(1, e_classes, e_classes) / e_classes if e_classes > 0 else torch.zeros(1, 1, 1) - self.u_y = torch.ones(1, y_classes, y_classes) / y_classes if y_classes > 0 else torch.zeros(1, 1, 1) - - def get_Qt(self, beta_t, device): - beta_t = beta_t.unsqueeze(1).to(device) - self.u_x = self.u_x.to(device) - self.u_e = self.u_e.to(device) - self.u_y = self.u_y.to(device) - q_x = beta_t * self.u_x + (1 - beta_t) * torch.eye(self.X_classes, device=device).unsqueeze(0) - q_e = beta_t * self.u_e + (1 - beta_t) * torch.eye(self.E_classes, device=device).unsqueeze(0) - q_y = beta_t * self.u_y + (1 - beta_t) * torch.eye(self.y_classes, device=device).unsqueeze(0) - return PlaceHolder(X=q_x, E=q_e, y=q_y) - - def get_Qt_bar(self, alpha_bar_t, device): - alpha_bar_t = alpha_bar_t.unsqueeze(1).to(device) - self.u_x = self.u_x.to(device) - self.u_e = self.u_e.to(device) - self.u_y = self.u_y.to(device) - q_x = alpha_bar_t * torch.eye(self.X_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_x - q_e = alpha_bar_t * torch.eye(self.E_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_e - q_y = alpha_bar_t * torch.eye(self.y_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_y - return PlaceHolder(X=q_x, E=q_e, y=q_y) - - -def compute_batched_over0_posterior_distribution(X_t, Qt, Qsb, Qtb): - """Compute p(x_{t-1} | x_t, x_0) for all possible x_0 values. - - Returns tensor where entry [b, n, x0, x_{t-1}] is the posterior probability. - """ - X_t = X_t.flatten(start_dim=1, end_dim=-2).to(torch.float32) - Qt_T = Qt.transpose(-1, -2) - left_term = (X_t @ Qt_T).unsqueeze(dim=2) - right_term = Qsb.unsqueeze(1) - numerator = left_term * right_term - X_t_transposed = X_t.transpose(-1, -2) - prod = Qtb @ X_t_transposed - prod = prod.transpose(-1, -2) - denominator = prod.unsqueeze(-1) - denominator[denominator == 0] = 1e-6 - return numerator / denominator - - -def sample_discrete_features(probX, probE, node_mask): - """Sample discrete features from categorical distributions.""" - bs, n, _ = probX.shape - probX[~node_mask] = 1 / probX.shape[-1] - X_t = probX.reshape(bs * n, -1).multinomial(1).reshape(bs, n) - - inverse_edge_mask = ~(node_mask.unsqueeze(1) * node_mask.unsqueeze(2)) - diag_mask = torch.eye(n, device=probE.device).unsqueeze(0).expand(bs, -1, -1).bool() - probE[inverse_edge_mask] = 1 / probE.shape[-1] - probE[diag_mask] = 1 / probE.shape[-1] - E_t = probE.reshape(bs * n * n, -1).multinomial(1).reshape(bs, n, n) - E_t = torch.triu(E_t, diagonal=1) - E_t = E_t + E_t.transpose(1, 2) - return PlaceHolder(X=X_t, E=E_t, y=torch.zeros(bs, 0).type_as(X_t)) - - -def sample_discrete_feature_noise(limit_dist, node_mask): - """Sample from the limit distribution of the diffusion process.""" - bs, n_max = node_mask.shape - x_limit = limit_dist.X[None, None, :].expand(bs, n_max, -1) - e_limit = limit_dist.E[None, None, None, :].expand(bs, n_max, n_max, -1) - - U_X = x_limit.flatten(end_dim=-2).multinomial(1).reshape(bs, n_max) - U_E = e_limit.flatten(end_dim=-2).multinomial(1).reshape(bs, n_max, n_max) - - U_X = F.one_hot(U_X, num_classes=x_limit.shape[-1]).float() - U_E = F.one_hot(U_E, num_classes=e_limit.shape[-1]).float() - - upper_tri = torch.zeros_like(U_E) - indices = torch.triu_indices(row=n_max, col=n_max, offset=1) - upper_tri[:, indices[0], indices[1], :] = 1 - U_E = U_E * upper_tri - U_E = U_E + U_E.transpose(1, 2) - - return PlaceHolder(X=U_X, E=U_E, y=torch.zeros(bs, 0)).mask(node_mask) diff --git a/massspecgym/models/de_novo/fp2mol/diffms/graph_transformer.py b/massspecgym/models/de_novo/fp2mol/diffms/graph_transformer.py deleted file mode 100644 index d148f02..0000000 --- a/massspecgym/models/de_novo/fp2mol/diffms/graph_transformer.py +++ /dev/null @@ -1,255 +0,0 @@ -""" -Graph Transformer for DiffMS discrete graph diffusion. - -Implements the XEy (node-edge-global) Transformer architecture that simultaneously -updates node features X, edge features E, and global features y (fingerprint). -""" - -import math - -import torch -import torch.nn as nn -import torch.nn.functional as F -from torch import Tensor - -from .diffusion_utils import assert_correctly_masked, PlaceHolder - - -def masked_softmax(x, mask, **kwargs): - """Softmax with mask (matching reference DiffMS exactly).""" - if mask.sum() == 0: - return x - x_masked = x.clone() - x_masked[mask == 0] = -float("inf") - return torch.softmax(x_masked, **kwargs) - - -class Xtoy(nn.Module): - """Aggregate node features to global feature. - - Matches reference DiffMS src/models/layers.py exactly: - output = Linear(cat([mean, min, max, variance], dim=-1)) - """ - def __init__(self, dx, dy): - super().__init__() - self.lin = nn.Linear(4 * dx, dy) - - def forward(self, X, x_mask): - # x_mask: (bs, n, 1) -> expand to (bs, n, dx) - x_mask = x_mask.expand(-1, -1, X.shape[-1]) - float_imask = 1 - x_mask.float() - m = X.sum(dim=1) / torch.sum(x_mask, dim=1) - mi = (X + 1e5 * float_imask).min(dim=1)[0] - ma = (X - 1e5 * float_imask).max(dim=1)[0] - std = torch.sum(((X - m[:, None, :]) ** 2) * x_mask, dim=1) / torch.sum(x_mask, dim=1) - z = torch.hstack((m, mi, ma, std)) - return self.lin(z) - - -class Etoy(nn.Module): - """Aggregate edge features to global feature. - - Matches reference DiffMS src/models/layers.py exactly. - """ - def __init__(self, d, dy): - super().__init__() - self.lin = nn.Linear(4 * d, dy) - - def forward(self, E, e_mask1, e_mask2): - mask = (e_mask1 * e_mask2).expand(-1, -1, -1, E.shape[-1]) - float_imask = 1 - mask.float() - divide = torch.sum(mask, dim=(1, 2)) - m = E.sum(dim=(1, 2)) / divide - mi = (E + 1e5 * float_imask).min(dim=2)[0].min(dim=1)[0] - ma = (E - 1e5 * float_imask).max(dim=2)[0].max(dim=1)[0] - std = torch.sum(((E - m[:, None, None, :]) ** 2) * mask, dim=(1, 2)) / divide - z = torch.hstack((m, mi, ma, std)) - return self.lin(z) - - -class NodeEdgeBlock(nn.Module): - """Self-attention block that jointly updates node, edge, and global features.""" - - def __init__(self, dx, de, dy, n_head, **kwargs): - super().__init__() - assert dx % n_head == 0 - self.dx = dx - self.de = de - self.dy = dy - self.df = dx // n_head - self.n_head = n_head - - self.q = nn.Linear(dx, dx) - self.k = nn.Linear(dx, dx) - self.v = nn.Linear(dx, dx) - - self.e_add = nn.Linear(de, dx) - self.e_mul = nn.Linear(de, dx) - - self.y_e_mul = nn.Linear(dy, dx) - self.y_e_add = nn.Linear(dy, dx) - self.y_x_mul = nn.Linear(dy, dx) - self.y_x_add = nn.Linear(dy, dx) - - self.y_y = nn.Linear(dy, dy) - self.x_y = Xtoy(dx, dy) - self.e_y = Etoy(de, dy) - - self.x_out = nn.Linear(dx, dx) - self.e_out = nn.Linear(dx, de) - self.y_out = nn.Sequential(nn.Linear(dy, dy), nn.ReLU(), nn.Linear(dy, dy)) - - def forward(self, X, E, y, node_mask): - bs, n, _ = X.shape - x_mask = node_mask.unsqueeze(-1) - e_mask1 = x_mask.unsqueeze(2) - e_mask2 = x_mask.unsqueeze(1) - - Q = (self.q(X) * x_mask).reshape(bs, n, self.n_head, self.df).unsqueeze(2) - K = (self.k(X) * x_mask).reshape(bs, n, self.n_head, self.df).unsqueeze(1) - Y = Q * K / math.sqrt(self.df) - - E1 = (self.e_mul(E) * e_mask1 * e_mask2).reshape(bs, n, n, self.n_head, self.df) - E2 = (self.e_add(E) * e_mask1 * e_mask2).reshape(bs, n, n, self.n_head, self.df) - Y = Y * (E1 + 1) + E2 - - newE = Y.flatten(start_dim=3) - ye1 = self.y_e_add(y).unsqueeze(1).unsqueeze(1) - ye2 = self.y_e_mul(y).unsqueeze(1).unsqueeze(1) - newE = ye1 + (ye2 + 1) * newE - newE = self.e_out(newE) * e_mask1 * e_mask2 - - softmax_mask = e_mask2.expand(-1, n, -1, self.n_head) - attn = masked_softmax(Y, softmax_mask, dim=2) # bs, n, n, n_head - - V = (self.v(X) * x_mask).reshape(bs, n, self.n_head, self.df).unsqueeze(1) - weighted_V = (attn * V).sum(dim=2).flatten(start_dim=2) - - yx1 = self.y_x_add(y).unsqueeze(1) - yx2 = self.y_x_mul(y).unsqueeze(1) - newX = yx1 + (yx2 + 1) * weighted_V - newX = self.x_out(newX) * x_mask - - new_y = self.y_y(y) + self.x_y(X, x_mask) + self.e_y(E, e_mask1, e_mask2) - new_y = self.y_out(new_y) - - return newX, newE, new_y - - -class XEyTransformerLayer(nn.Module): - """Full transformer layer updating X, E, y with self-attention and FFN.""" - - def __init__(self, dx, de, dy, n_head, dim_ffX=2048, dim_ffE=128, dim_ffy=2048, - dropout=0.1, layer_norm_eps=1e-5, **kwargs): - super().__init__() - self.self_attn = NodeEdgeBlock(dx, de, dy, n_head, **kwargs) - - self.linX1 = nn.Linear(dx, dim_ffX) - self.linX2 = nn.Linear(dim_ffX, dx) - self.normX1 = nn.LayerNorm(dx, eps=layer_norm_eps) - self.normX2 = nn.LayerNorm(dx, eps=layer_norm_eps) - self.dropoutX1 = nn.Dropout(dropout) - self.dropoutX2 = nn.Dropout(dropout) - self.dropoutX3 = nn.Dropout(dropout) - - self.linE1 = nn.Linear(de, dim_ffE) - self.linE2 = nn.Linear(dim_ffE, de) - self.normE1 = nn.LayerNorm(de, eps=layer_norm_eps) - self.normE2 = nn.LayerNorm(de, eps=layer_norm_eps) - self.dropoutE1 = nn.Dropout(dropout) - self.dropoutE2 = nn.Dropout(dropout) - self.dropoutE3 = nn.Dropout(dropout) - - self.lin_y1 = nn.Linear(dy, dim_ffy) - self.lin_y2 = nn.Linear(dim_ffy, dy) - self.norm_y1 = nn.LayerNorm(dy, eps=layer_norm_eps) - self.norm_y2 = nn.LayerNorm(dy, eps=layer_norm_eps) - self.dropout_y1 = nn.Dropout(dropout) - self.dropout_y2 = nn.Dropout(dropout) - self.dropout_y3 = nn.Dropout(dropout) - - def forward(self, X, E, y, node_mask): - newX, newE, new_y = self.self_attn(X, E, y, node_mask=node_mask) - - X = self.normX1(X + self.dropoutX1(newX)) - E = self.normE1(E + self.dropoutE1(newE)) - y = self.norm_y1(y + self.dropout_y1(new_y)) - - X = self.normX2(X + self.dropoutX3(self.linX2(self.dropoutX2(F.relu(self.linX1(X)))))) - E = self.normE2(E + self.dropoutE3(self.linE2(self.dropoutE2(F.relu(self.linE1(E)))))) - y = self.norm_y2(y + self.dropout_y3(self.lin_y2(self.dropout_y2(F.relu(self.lin_y1(y)))))) - - return X, E, y - - -class GraphTransformer(nn.Module): - """Graph Transformer backbone for DiffMS. - - Processes noisy graph features (node types, bond types, global fingerprint) - through multiple XEyTransformerLayers and projects to output dimensions. - - Args: - n_layers: Number of transformer layers. - input_dims: Dict with X, E, y input dimensions. - hidden_mlp_dims: Dict with X, E, y hidden MLP dimensions. - hidden_dims: Dict with X, E, y hidden dimensions. - output_dims: Dict with X, E, y output dimensions. - """ - - def __init__(self, n_layers, input_dims, hidden_mlp_dims, hidden_dims, output_dims, - act_fn_in=nn.ReLU(), act_fn_out=nn.ReLU()): - super().__init__() - self.out_dim_X = output_dims["X"] - self.out_dim_E = output_dims["E"] - self.out_dim_y = output_dims["y"] - - self.mlp_in_X = nn.Sequential( - nn.Linear(input_dims["X"], hidden_mlp_dims["X"]), act_fn_in, - nn.Linear(hidden_mlp_dims["X"], hidden_dims["dx"]), act_fn_in, - ) - self.mlp_in_E = nn.Sequential( - nn.Linear(input_dims["E"], hidden_mlp_dims["E"]), act_fn_in, - nn.Linear(hidden_mlp_dims["E"], hidden_dims["de"]), act_fn_in, - ) - self.mlp_in_y = nn.Sequential( - nn.Linear(input_dims["y"], hidden_mlp_dims["y"]), act_fn_in, - nn.Linear(hidden_mlp_dims["y"], hidden_dims["dy"]), act_fn_in, - ) - - self.tf_layers = nn.ModuleList([ - XEyTransformerLayer( - dx=hidden_dims["dx"], de=hidden_dims["de"], dy=hidden_dims["dy"], - n_head=hidden_dims["n_head"], - dim_ffX=hidden_dims["dim_ffX"], dim_ffE=hidden_dims["dim_ffE"], - ) - for _ in range(n_layers) - ]) - - self.mlp_out_X = nn.Sequential( - nn.Linear(hidden_dims["dx"], hidden_mlp_dims["X"]), act_fn_out, - nn.Linear(hidden_mlp_dims["X"], self.out_dim_X), - ) - self.mlp_out_E = nn.Sequential( - nn.Linear(hidden_dims["de"], hidden_mlp_dims["E"]), act_fn_out, - nn.Linear(hidden_mlp_dims["E"], self.out_dim_E), - ) - self.mlp_out_y = nn.Sequential( - nn.Linear(hidden_dims["dy"], hidden_mlp_dims["y"]), act_fn_out, - nn.Linear(hidden_mlp_dims["y"], self.out_dim_y), - ) - - def forward(self, X, E, y, node_mask): - bs, n = X.shape[0], X.shape[1] - - X = self.mlp_in_X(X) - E = self.mlp_in_E(E) - y = self.mlp_in_y(y) - - for layer in self.tf_layers: - X, E, y = layer(X, E, y, node_mask) - - X = self.mlp_out_X(X) - E = self.mlp_out_E(E) - y = self.mlp_out_y(y) - - return PlaceHolder(X=X, E=E, y=y) diff --git a/massspecgym/models/de_novo/fp2mol/diffms/model.py b/massspecgym/models/de_novo/fp2mol/diffms/model.py deleted file mode 100644 index fcf3cef..0000000 --- a/massspecgym/models/de_novo/fp2mol/diffms/model.py +++ /dev/null @@ -1,252 +0,0 @@ -""" -DiffMS decoder: Discrete graph diffusion for fingerprint-to-molecule generation. - -Ported from Bohde et al., "DiffMS: Diffusion generation of molecules conditioned -on mass spectra", 2025. - -The model performs discrete diffusion over molecular graphs, where: -- Node features: one-hot atom types (C, O, P, N, S, Cl, F, H) -- Edge features: one-hot bond types (no-bond, single, double, triple, aromatic) -- Global features: Morgan fingerprint as conditioning signal - -Training uses discrete diffusion loss (CE on edges, optionally nodes/global). -Sampling reverses the diffusion process via posterior sampling. -""" - -from typing import Optional, List - -import torch -import torch.nn as nn -import torch.nn.functional as F -from rdkit import Chem - -from massspecgym.models.base import Stage -from massspecgym.models.de_novo.fp2mol.base import FP2MolDeNovoModel -from .graph_transformer import GraphTransformer -from .diffusion_utils import ( - PlaceHolder, - PredefinedNoiseScheduleDiscrete, - MarginalUniformTransition, - DiscreteUniformTransition, - compute_batched_over0_posterior_distribution, - sample_discrete_features, - sample_discrete_feature_noise, -) - -ATOM_DECODER = ["C", "O", "P", "N", "S", "Cl", "F", "H"] -BOND_TYPES = [None, Chem.rdchem.BondType.SINGLE, Chem.rdchem.BondType.DOUBLE, - Chem.rdchem.BondType.TRIPLE, Chem.rdchem.BondType.AROMATIC] - - -def mol_from_graphs(node_list, adjacency_matrix, atom_decoder=ATOM_DECODER): - """Convert graph representation to RDKit molecule.""" - mol = Chem.RWMol() - node_to_idx = {} - for i in range(len(node_list)): - if node_list[i] == -1: - continue - a = Chem.Atom(atom_decoder[int(node_list[i])]) - node_to_idx[i] = mol.AddAtom(a) - - for ix, row in enumerate(adjacency_matrix): - for iy, bond in enumerate(row): - if iy <= ix: - continue - if 1 <= bond <= 4 and ix in node_to_idx and iy in node_to_idx: - mol.AddBond(node_to_idx[ix], node_to_idx[iy], BOND_TYPES[bond]) - - try: - mol = mol.GetMol() - return mol - except Exception: - return None - - -class DiffMSDecoder(FP2MolDeNovoModel): - """DiffMS discrete graph diffusion decoder. - - Args: - num_atom_types: Number of atom types (8). - num_bond_types: Number of bond types including no-bond (5). - diffusion_steps: Number of diffusion steps (500). - noise_schedule: Noise schedule type ('cosine'). - transition: Transition type ('marginal' or 'uniform'). - n_layers: Number of GraphTransformer layers. - hidden_dims: Hidden dimensions for the GraphTransformer. - lambda_train: Loss weights [node_CE, edge_CE, global_CE]. - max_nodes: Maximum number of nodes in generated graphs. - fingerprint_bits: Number of fingerprint bits (2048 for DiffMS). - """ - - def __init__( - self, - num_atom_types: int = 8, - num_bond_types: int = 5, - diffusion_steps: int = 500, - noise_schedule: str = "cosine", - transition: str = "marginal", - n_layers: int = 6, - hidden_dims: Optional[dict] = None, - lambda_train: Optional[list] = None, - max_nodes: int = 50, - fingerprint_bits: int = 2048, - *args, - **kwargs, - ): - super().__init__(fingerprint_bits=fingerprint_bits, use_formula=False, *args, **kwargs) - - self.num_atom_types = num_atom_types - self.num_bond_types = num_bond_types - self.T = diffusion_steps - self.max_nodes = max_nodes - self.lambda_train = lambda_train or [0.0, 1.0, 0.0] - - if hidden_dims is None: - hidden_dims = { - "dx": 256, "de": 64, "dy": 256, "n_head": 8, - "dim_ffX": 256, "dim_ffE": 128, - } - - extra_X_feat = 1 # timestep - extra_E_feat = 1 - extra_y_feat = 1 - - input_dims = { - "X": num_atom_types + extra_X_feat, - "E": num_bond_types + extra_E_feat, - "y": fingerprint_bits + extra_y_feat, - } - output_dims = {"X": num_atom_types, "E": num_bond_types, "y": 0} - hidden_mlp_dims = {"X": 256, "E": 128, "y": 256} - - self.model = GraphTransformer( - n_layers=n_layers, - input_dims=input_dims, - hidden_mlp_dims=hidden_mlp_dims, - hidden_dims=hidden_dims, - output_dims=output_dims, - ) - - self.noise_schedule = PredefinedNoiseScheduleDiscrete(noise_schedule, diffusion_steps) - - x_marginals = torch.ones(num_atom_types) / num_atom_types - e_marginals = torch.zeros(num_bond_types) - e_marginals[0] = 0.9 - e_marginals[1:] = 0.1 / (num_bond_types - 1) - - if transition == "marginal": - self.transition_model = MarginalUniformTransition(x_marginals, e_marginals, 0) - else: - self.transition_model = DiscreteUniformTransition(num_atom_types, num_bond_types, 0) - - self.limit_dist = PlaceHolder(X=x_marginals, E=e_marginals, y=torch.zeros(0)) - - def apply_noise(self, X, E, y, node_mask): - """Apply forward diffusion noise to graph features.""" - t_int = torch.randint(0, self.T + 1, size=(X.size(0), 1), device=X.device) - s_int = t_int - 1 - t_float = t_int / self.T - s_float = s_int / self.T - - beta_t = self.noise_schedule(t_normalized=t_float) - alpha_s_bar = self.noise_schedule.get_alpha_bar(t_normalized=s_float) - alpha_t_bar = self.noise_schedule.get_alpha_bar(t_normalized=t_float) - - Qtb = self.transition_model.get_Qt_bar(alpha_t_bar, X.device) - prob_X = (X @ Qtb.X).clamp(min=1e-5) - prob_E = (E @ Qtb.E).clamp(min=1e-5) - - sampled = sample_discrete_features(prob_X, prob_E, node_mask) - X_t = F.one_hot(sampled.X, self.num_atom_types).float() - E_t = F.one_hot(sampled.E, self.num_bond_types).float() - - x_mask = node_mask.unsqueeze(-1) - X_t = X_t * x_mask - e_mask = x_mask.unsqueeze(2) * x_mask.unsqueeze(1) - E_t = E_t * e_mask - - return { - "t_int": t_int, "t": t_float, - "beta_t": beta_t, "alpha_s_bar": alpha_s_bar, "alpha_t_bar": alpha_t_bar, - "X_t": X_t, "E_t": E_t, "y_t": y, - } - - def compute_decoder_loss(self, batch: dict) -> torch.Tensor: - """Compute discrete diffusion training loss.""" - X = batch.get("X") - E = batch.get("E") - y = batch.get("fingerprint") - node_mask = batch.get("node_mask") - - if X is None: - return torch.tensor(0.0, device=self.device, requires_grad=True) - - noisy = self.apply_noise(X, E, y, node_mask) - - t_emb = noisy["t"].unsqueeze(-1) - X_in = torch.cat([noisy["X_t"], t_emb.expand(-1, noisy["X_t"].size(1), -1)], dim=-1) - E_in = torch.cat([noisy["E_t"], t_emb.unsqueeze(1).expand(-1, noisy["E_t"].size(1), noisy["E_t"].size(2), -1)], dim=-1) - y_in = torch.cat([noisy["y_t"], t_emb.squeeze(-1)], dim=-1) - - pred = self.model(X_in, E_in, y_in, node_mask) - - true_X = X.argmax(dim=-1) if X.dim() == 3 else X - true_E = E.argmax(dim=-1) if E.dim() == 4 else E - - loss_X = F.cross_entropy(pred.X.reshape(-1, self.num_atom_types), true_X.reshape(-1), reduction="mean") - loss_E = F.cross_entropy(pred.E.reshape(-1, self.num_bond_types), true_E.reshape(-1), reduction="mean") - - loss = self.lambda_train[0] * loss_X + self.lambda_train[1] * loss_E - return loss - - @torch.no_grad() - def decode_from_fingerprint( - self, - fingerprint: torch.Tensor, - formula=None, - num_samples: int = 1, - ) -> list: - """Generate molecules from fingerprint via reverse diffusion.""" - self.eval() - batch_size = fingerprint.shape[0] - all_preds = [] - - for b_idx in range(batch_size): - fp = fingerprint[b_idx:b_idx + 1] - sample_mols = [] - - for _ in range(num_samples): - n_nodes = torch.randint(5, self.max_nodes, (1,)).item() - node_mask = torch.ones(1, n_nodes, device=self.device).bool() - - z_T = sample_discrete_feature_noise(self.limit_dist, node_mask) - X = z_T.X.to(self.device) - E = z_T.E.to(self.device) - y = fp.to(self.device) - - for s_int in reversed(range(0, self.T)): - t_int = s_int + 1 - t = torch.tensor([t_int / self.T], device=self.device) - - t_emb = t.unsqueeze(-1) - X_in = torch.cat([X, t_emb.expand(-1, X.size(1), -1)], dim=-1) - E_in = torch.cat([E, t_emb.unsqueeze(1).expand(-1, E.size(1), E.size(2), -1)], dim=-1) - y_in = torch.cat([y, t_emb], dim=-1) - - pred = self.model(X_in, E_in, y_in, node_mask.float()) - - pred_X = F.softmax(pred.X, dim=-1) - pred_E = F.softmax(pred.E, dim=-1) - - sampled = sample_discrete_features(pred_X, pred_E, node_mask) - X = F.one_hot(sampled.X, self.num_atom_types).float() - E = F.one_hot(sampled.E, self.num_bond_types).float() - - node_types = X.argmax(dim=-1)[0].cpu().numpy() - adj = E.argmax(dim=-1)[0].cpu().numpy() - mol = mol_from_graphs(node_types, adj) - smi = Chem.MolToSmiles(mol) if mol is not None else None - sample_mols.append(smi) - - all_preds.append(sample_mols) - return all_preds diff --git a/massspecgym/models/de_novo/fp2mol/formula_utils.py b/massspecgym/models/de_novo/fp2mol/formula_utils.py deleted file mode 100644 index 2d68810..0000000 --- a/massspecgym/models/de_novo/fp2mol/formula_utils.py +++ /dev/null @@ -1,138 +0,0 @@ -""" -Formula encoding utilities shared by FP2Mol decoders. - -Provides a 30-element FormulaEncoder that maps molecular formula strings -(e.g., "C9H10N2O2") to fixed-size count vectors. Used by FRIGID and DiffMS -for formula conditioning during molecule generation. -""" - -import re -from typing import Dict, List, Optional - -import torch - - -class FormulaEncoder: - """Encoder for molecular formulas to fixed-size numerical vectors. - - Converts molecular formula strings into 30-dimensional vectors of atom counts - suitable for conditioning molecular generation models. - - The atom vocabulary covers common organic elements plus metals that may appear - in bioactive molecules, matching the vocabulary used by FRIGID. - - Args: - normalize: Normalization strategy for atom counts. - - 'none': No normalization (raw integer counts). - - 'sum': Divide by total number of atoms. - - 'max': Divide by maximum count in formula. - - 'log': Apply log(count + 1) transformation. - """ - - ATOM_VOCAB = [ - 'C', 'H', 'N', 'O', 'F', 'S', 'P', 'Cl', 'Br', 'I', - 'B', 'Si', 'Se', 'As', 'Al', 'Sn', 'Li', 'Na', 'K', 'Mg', - 'Ca', 'Fe', 'Zn', 'Cu', 'Mn', 'Co', 'Ni', 'Pt', 'Pd', 'Au' - ] - - _FORMULA_PATTERN = re.compile(r'([A-Z][a-z]?)(\d*)') - - def __init__(self, normalize: str = 'none'): - self.atom_vocab = self.ATOM_VOCAB - self.atom_to_idx = {atom: idx for idx, atom in enumerate(self.atom_vocab)} - self.normalize = normalize - - def formula_to_counts(self, formula_str: str) -> Dict[str, int]: - """Parse a molecular formula string into a dictionary of atom counts. - - >>> FormulaEncoder().formula_to_counts("C9H10N2O2") - {'C': 9, 'H': 10, 'N': 2, 'O': 2} - """ - if not formula_str: - return {} - counts: Dict[str, int] = {} - for element, count in self._FORMULA_PATTERN.findall(formula_str): - if element: - count_val = int(count) if count else 1 - counts[element] = counts.get(element, 0) + count_val - return counts - - def counts_to_vector( - self, counts: Dict[str, int], normalize: Optional[str] = None - ) -> torch.Tensor: - """Convert atom counts dictionary to a fixed-size vector. - - Args: - counts: Dictionary mapping atom symbols to counts. - normalize: Override normalization strategy. - - Returns: - Tensor of shape (30,) with counts for each atom type. - """ - normalize = normalize if normalize is not None else self.normalize - vector = torch.zeros(len(self.atom_vocab), dtype=torch.float32) - for atom, count in counts.items(): - idx = self.atom_to_idx.get(atom) - if idx is not None: - vector[idx] = float(count) - - if normalize == 'sum': - total = vector.sum() - if total > 0: - vector = vector / total - elif normalize == 'max': - max_val = vector.max() - if max_val > 0: - vector = vector / max_val - elif normalize == 'log': - vector = torch.log(vector + 1.0) - elif normalize != 'none': - raise ValueError(f"Unknown normalization strategy: {normalize}") - - return vector - - def encode(self, formula_str: str, normalize: Optional[str] = None) -> torch.Tensor: - """Encode a molecular formula string into a fixed-size vector. - - Args: - formula_str: Molecular formula string (e.g., "C9H10N2O2"). - normalize: Override normalization strategy. - - Returns: - Tensor of shape (30,). - """ - if not formula_str: - return torch.zeros(len(self.atom_vocab), dtype=torch.float32) - try: - counts = self.formula_to_counts(formula_str) - return self.counts_to_vector(counts, normalize) - except Exception: - return torch.zeros(len(self.atom_vocab), dtype=torch.float32) - - def encode_batch( - self, formulas: List[str], normalize: Optional[str] = None - ) -> torch.Tensor: - """Encode a batch of molecular formulas. - - Returns: - Tensor of shape (batch_size, 30). - """ - return torch.stack([self.encode(f, normalize) for f in formulas]) - - @property - def vocab_size(self) -> int: - """Dimensionality of output vectors (30).""" - return len(self.atom_vocab) - - def decode(self, vector: torch.Tensor, threshold: float = 0.5) -> str: - """Decode a vector back into an approximate molecular formula string.""" - parts = [] - for idx, count in enumerate(vector.tolist()): - if count > threshold: - atom = self.atom_vocab[idx] - count_int = round(count) - if count_int > 1: - parts.append(f"{atom}{count_int}") - elif count_int == 1: - parts.append(atom) - return ''.join(parts) diff --git a/massspecgym/models/de_novo/fp2mol/frigid/__init__.py b/massspecgym/models/de_novo/fp2mol/frigid/__init__.py deleted file mode 100644 index ec0ccaa..0000000 --- a/massspecgym/models/de_novo/fp2mol/frigid/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -""" -FRIGID decoder: Fragment Refinement via ICEBERG-Guided Inference Diffusion. - -A Masked Diffusion Language Model (MDLM) that generates SAFE molecular sequences -conditioned on fingerprints and chemical formulas via cross-attention. - -Requires: ``pip install transformers`` (for BERT backbone). -""" - - -def __getattr__(name): - if name == "FRIGIDDecoder": - from .model import FRIGIDDecoder - return FRIGIDDecoder - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/massspecgym/models/de_novo/fp2mol/frigid/bert_cross_attention.py b/massspecgym/models/de_novo/fp2mol/frigid/bert_cross_attention.py deleted file mode 100644 index 2d00efb..0000000 --- a/massspecgym/models/de_novo/fp2mol/frigid/bert_cross_attention.py +++ /dev/null @@ -1,231 +0,0 @@ -""" -BERT encoder with cross-attention layers for FRIGID conditioning. - -Extends the HuggingFace BertForMaskedLM with cross-attention sublayers in each -transformer block, allowing formula and fingerprint conditioning embeddings -to be injected via cross-attention at every layer. - -Matches the reference implementation from external/genms/src/genmol/bert_with_cross_attention.py -exactly in structure: BertLayerWithCrossAttention wraps BertLayer and adds -cross-attention after self-attention + FFN. - -Supports two modes: -- Shared cross-attention: formula + fingerprint concatenated into single conditioning. -- Independent cross-attention: separate cross-attention paths for each modality. -""" - -from typing import Optional - -import torch -import torch.nn as nn -from transformers.models.bert.modeling_bert import ( - BertLayer, - BertPreTrainedModel, - BertForMaskedLM, - BertEmbeddings, - BertPooler, -) -from transformers.models.bert.configuration_bert import BertConfig - - -class BertLayerWithCrossAttention(nn.Module): - """BERT layer extended with optional cross-attention over conditioning tokens. - - Performs: - 1. Standard self-attention + FFN (via wrapped BertLayer) - 2. Cross-attention to formula conditioning sequence (if provided) - 3. Cross-attention to fingerprint conditioning sequence (if provided) - """ - - def __init__(self, config, cross_attention_layer=None, - fingerprint_cross_attention_layer=None): - super().__init__() - self.bert_layer = BertLayer(config) - self.cross_attention = cross_attention_layer - self.has_cross_attention = cross_attention_layer is not None - self.fingerprint_cross_attention = fingerprint_cross_attention_layer - self.has_fingerprint_cross_attention = fingerprint_cross_attention_layer is not None - - def forward( - self, - hidden_states, - attention_mask=None, - head_mask=None, - encoder_hidden_states=None, - encoder_attention_mask=None, - past_key_value=None, - output_attentions=False, - condition_embeddings=None, - condition_mask=None, - fingerprint_embeddings=None, - fingerprint_mask=None, - ): - layer_outputs = self.bert_layer( - hidden_states, - attention_mask=attention_mask, - head_mask=head_mask, - encoder_hidden_states=encoder_hidden_states, - encoder_attention_mask=encoder_attention_mask, - past_key_value=past_key_value, - output_attentions=output_attentions, - ) - hidden_states = layer_outputs[0] - - if self.has_cross_attention and condition_embeddings is not None: - hidden_states = self.cross_attention( - hidden_states=hidden_states, - condition_embeddings=condition_embeddings, - condition_mask=condition_mask, - ) - - if self.has_fingerprint_cross_attention and fingerprint_embeddings is not None: - hidden_states = self.fingerprint_cross_attention( - hidden_states=hidden_states, - condition_embeddings=fingerprint_embeddings, - condition_mask=fingerprint_mask, - ) - - return (hidden_states,) + layer_outputs[1:] - - -class BertEncoderWithCrossAttention(nn.Module): - """BERT encoder with per-layer cross-attention for conditioning sequences.""" - - def __init__(self, config, cross_attention_layers=None, - fingerprint_cross_attention_layers=None): - super().__init__() - self.config = config - self.layer = nn.ModuleList() - for i in range(config.num_hidden_layers): - cross_attn = cross_attention_layers[i] if cross_attention_layers else None - fp_cross_attn = fingerprint_cross_attention_layers[i] if fingerprint_cross_attention_layers else None - self.layer.append( - BertLayerWithCrossAttention( - config, - cross_attention_layer=cross_attn, - fingerprint_cross_attention_layer=fp_cross_attn, - ) - ) - self.gradient_checkpointing = False - - def forward( - self, - hidden_states, - attention_mask=None, - head_mask=None, - encoder_hidden_states=None, - encoder_attention_mask=None, - past_key_values=None, - use_cache=None, - output_attentions=False, - output_hidden_states=False, - return_dict=True, - condition_embeddings=None, - condition_mask=None, - fingerprint_embeddings=None, - fingerprint_mask=None, - ): - all_hidden_states = () if output_hidden_states else None - all_self_attentions = () if output_attentions else None - - for i, layer_module in enumerate(self.layer): - if output_hidden_states: - all_hidden_states = all_hidden_states + (hidden_states,) - - layer_head_mask = head_mask[i] if head_mask is not None else None - past_key_value = past_key_values[i] if past_key_values is not None else None - - layer_outputs = layer_module( - hidden_states, - attention_mask=attention_mask, - head_mask=layer_head_mask, - encoder_hidden_states=encoder_hidden_states, - encoder_attention_mask=encoder_attention_mask, - past_key_value=past_key_value, - output_attentions=output_attentions, - condition_embeddings=condition_embeddings, - condition_mask=condition_mask, - fingerprint_embeddings=fingerprint_embeddings, - fingerprint_mask=fingerprint_mask, - ) - hidden_states = layer_outputs[0] - - if output_attentions: - all_self_attentions = all_self_attentions + (layer_outputs[1],) - - if output_hidden_states: - all_hidden_states = all_hidden_states + (hidden_states,) - - return tuple(v for v in [hidden_states, None, all_hidden_states, - all_self_attentions] if v is not None) - - -class BertModelWithCrossAttention(BertPreTrainedModel): - """BERT model with cross-attention for conditioning, drop-in replacement for BertModel.""" - - def __init__(self, config, add_pooling_layer=True, cross_attention_layers=None, - fingerprint_cross_attention_layers=None, use_shared_cross_attention=False): - super().__init__(config) - self.config = config - self.use_shared_cross_attention = use_shared_cross_attention - - self.embeddings = BertEmbeddings(config) - - if use_shared_cross_attention: - fingerprint_cross_attention_layers = None - - self.encoder = BertEncoderWithCrossAttention( - config, cross_attention_layers, fingerprint_cross_attention_layers - ) - self.pooler = BertPooler(config) if add_pooling_layer else None - self.post_init() - - def get_input_embeddings(self): - return self.embeddings.word_embeddings - - def set_input_embeddings(self, value): - self.embeddings.word_embeddings = value - - def get_extended_attention_mask(self, attention_mask, input_shape, device=None): - return super().get_extended_attention_mask(attention_mask, input_shape, device) - - -class BertForMaskedLMWithCrossAttention(nn.Module): - """BertForMaskedLM extended with cross-attention conditioning. - - Wraps BertModelWithCrossAttention + BertOnlyMLMHead (cls) for - masked language modeling with formula/fingerprint conditioning. - """ - - def __init__( - self, - config: BertConfig, - cross_attention_layers: Optional[nn.ModuleList] = None, - fingerprint_cross_attention_layers: Optional[nn.ModuleList] = None, - use_shared_cross_attention: bool = True, - ): - super().__init__() - - self.bert = BertModelWithCrossAttention( - config, - add_pooling_layer=False, - cross_attention_layers=cross_attention_layers, - fingerprint_cross_attention_layers=fingerprint_cross_attention_layers, - use_shared_cross_attention=use_shared_cross_attention, - ) - - # Reuse the MLM head from standard BertForMaskedLM - _tmp = BertForMaskedLM(config) - self.cls = _tmp.cls - del _tmp - - @property - def embeddings(self): - return self.bert.embeddings - - def get_extended_attention_mask(self, attention_mask, input_shape, device=None): - return self.bert.get_extended_attention_mask(attention_mask, input_shape, device) - - def parameters(self, recurse=True): - yield from self.bert.parameters(recurse) - yield from self.cls.parameters(recurse) diff --git a/massspecgym/models/de_novo/fp2mol/frigid/components.py b/massspecgym/models/de_novo/fp2mol/frigid/components.py deleted file mode 100644 index 0ceae1d..0000000 --- a/massspecgym/models/de_novo/fp2mol/frigid/components.py +++ /dev/null @@ -1,336 +0,0 @@ -""" -Conditioning components for the FRIGID decoder. - -Contains formula and fingerprint conditioners that produce embeddings for -cross-attention injection into the BERT backbone, matching the FRIGID paper. -""" - -import math - -import torch -import torch.nn as nn - - -class FormulaSequenceEncoder(nn.Module): - """Encodes molecular formula as a fixed-length sequence of atom embeddings. - - Each position represents an atom type (C, H, N, O, ...) with its count, - creating a 30-length sequence for cross-attention with SAFE tokens. - - Args: - num_atom_types: Number of atom types in the vocabulary (30). - embedding_dim: Dimension of output embeddings (matches BERT hidden_size). - max_count: Maximum count value for count embeddings. - use_count_embedding: If True, use separate learnable count embeddings. - """ - - def __init__( - self, - num_atom_types: int = 30, - embedding_dim: int = 768, - max_count: int = 200, - use_count_embedding: bool = True, - ): - super().__init__() - self.num_atom_types = num_atom_types - self.embedding_dim = embedding_dim - self.use_count_embedding = use_count_embedding - - self.atom_embeddings = nn.Embedding(num_atom_types, embedding_dim) - if use_count_embedding: - self.count_embeddings = nn.Embedding(max_count + 1, embedding_dim) - self.position_embeddings = nn.Embedding(num_atom_types, embedding_dim) - self.layer_norm = nn.LayerNorm(embedding_dim) - - self._init_weights() - - def _init_weights(self): - nn.init.normal_(self.atom_embeddings.weight, mean=0.0, std=0.02) - if self.use_count_embedding: - nn.init.normal_(self.count_embeddings.weight, mean=0.0, std=0.02) - nn.init.normal_(self.position_embeddings.weight, mean=0.0, std=0.02) - - def forward(self, formula_vectors: torch.Tensor): - """Encode formula vectors as a sequence of embeddings. - - Args: - formula_vectors: Tensor [batch_size, num_atom_types] with counts. - - Returns: - Tuple of (embeddings [B, 30, D], mask [B, 30]). - """ - batch_size = formula_vectors.shape[0] - device = formula_vectors.device - - atom_indices = torch.arange(self.num_atom_types, device=device) - atom_indices = atom_indices.unsqueeze(0).expand(batch_size, -1) - - atom_emb = self.atom_embeddings(atom_indices) - - if self.use_count_embedding: - counts_clipped = formula_vectors.clamp(0, 200).long() - count_emb = self.count_embeddings(counts_clipped) - else: - count_emb = formula_vectors.unsqueeze(-1) * atom_emb - - pos_emb = self.position_embeddings(atom_indices) - embeddings = self.layer_norm(atom_emb + count_emb + pos_emb) - mask = (formula_vectors > 0).float() - - return embeddings, mask - - -class SetSelfAttention(nn.Module): - """Permutation-equivariant self-attention for unordered sets. - - No positional encoding - treats input as an unordered set of elements. - Used by FingerprintSequenceEncoder to learn combinatorial relationships - among active fingerprint bits. - """ - - def __init__(self, hidden_size: int = 768, num_attention_heads: int = 12, dropout: float = 0.1): - super().__init__() - self.num_attention_heads = num_attention_heads - self.attention_head_size = hidden_size // num_attention_heads - self.all_head_size = self.num_attention_heads * self.attention_head_size - - self.query = nn.Linear(hidden_size, self.all_head_size) - self.key = nn.Linear(hidden_size, self.all_head_size) - self.value = nn.Linear(hidden_size, self.all_head_size) - self.output_dense = nn.Linear(hidden_size, hidden_size) - self.output_dropout = nn.Dropout(dropout) - self.output_layer_norm = nn.LayerNorm(hidden_size) - self.dropout = nn.Dropout(dropout) - - def _transpose_for_scores(self, x): - new_shape = x.size()[:-1] + (self.num_attention_heads, self.attention_head_size) - return x.view(*new_shape).permute(0, 2, 1, 3) - - def forward(self, hidden_states: torch.Tensor, mask: torch.Tensor = None): - q = self._transpose_for_scores(self.query(hidden_states)) - k = self._transpose_for_scores(self.key(hidden_states)) - v = self._transpose_for_scores(self.value(hidden_states)) - - scores = torch.matmul(q, k.transpose(-1, -2)) / math.sqrt(self.attention_head_size) - - if mask is not None: - ext_mask = (1.0 - mask.unsqueeze(1).unsqueeze(2)) * -10000.0 - scores = scores + ext_mask - - probs = self.dropout(torch.softmax(scores, dim=-1)) - context = torch.matmul(probs, v) - context = context.permute(0, 2, 1, 3).contiguous() - context = context.view(context.size()[:-2] + (self.all_head_size,)) - - output = self.output_dropout(self.output_dense(context)) - return self.output_layer_norm(hidden_states + output) - - -class FingerprintSequenceEncoder(nn.Module): - """Set-aware encoder for Morgan fingerprints. - - Treats fingerprint as an unordered set of active bits: - 1. Each bit index gets a learnable embedding (substructure semantics). - 2. No positional encoding (set has no order). - 3. Self-attention learns combinatorial relationships. - - Args: - num_bits: Number of fingerprint bits (4096). - embedding_dim: Embedding dimension. - max_seq_len: Maximum number of active bits to retain (256). - activation_threshold: Threshold for considering a bit active. - dropout: Dropout probability. - num_self_attention_layers: Number of self-attention layers (3). - num_attention_heads: Number of attention heads. - """ - - def __init__( - self, - num_bits: int = 4096, - embedding_dim: int = 768, - max_seq_len: int = 256, - activation_threshold: float = 0.0, - dropout: float = 0.1, - num_self_attention_layers: int = 2, - num_attention_heads: int = 12, - ): - super().__init__() - self.num_bits = num_bits - self.embedding_dim = embedding_dim - self.max_seq_len = max_seq_len - self.activation_threshold = activation_threshold - - self.bit_embeddings = nn.Embedding(num_bits, embedding_dim) - self.layer_norm = nn.LayerNorm(embedding_dim) - self.dropout = nn.Dropout(dropout) - self.self_attention_layers = nn.ModuleList([ - SetSelfAttention(hidden_size=embedding_dim, num_attention_heads=num_attention_heads, dropout=dropout) - for _ in range(num_self_attention_layers) - ]) - nn.init.normal_(self.bit_embeddings.weight, mean=0.0, std=0.02) - - def forward(self, fingerprint: torch.Tensor): - """Encode fingerprint as a set of active bit embeddings. - - Args: - fingerprint: Tensor [batch_size, num_bits] - binary or soft Morgan FP. - - Returns: - Tuple of (embeddings [B, L, D], mask [B, L]). - """ - if fingerprint.dim() == 1: - fingerprint = fingerprint.unsqueeze(0) - batch_size = fingerprint.shape[0] - device = fingerprint.device - - active_mask = fingerprint > self.activation_threshold - num_active = active_mask.sum(dim=1) - max_active = min(self.max_seq_len, max(int(num_active.max().item()), 1)) - - scores = active_mask.float() - if self.training: - scores = scores + torch.rand_like(scores) * 0.5 - - _, topk_indices = torch.topk(scores, k=max_active, dim=1, sorted=False) - - pos_indices = torch.arange(max_active, device=device).unsqueeze(0).expand(batch_size, -1) - mask = (pos_indices < num_active.unsqueeze(1)).float() - - no_active = num_active == 0 - if no_active.any(): - topk_indices[no_active, 0] = 0 - mask[no_active] = 0.0 - - embeddings = self.dropout(self.layer_norm(self.bit_embeddings(topk_indices))) - for self_attn in self.self_attention_layers: - embeddings = self_attn(embeddings, mask) - embeddings = embeddings * mask.unsqueeze(-1) - - return embeddings, mask - - -class CrossAttentionLayer(nn.Module): - """Cross-attention layer for conditioning SAFE tokens on formula/fingerprint. - - SAFE token representations (queries) attend to conditioning sequence - embeddings (keys/values) with residual connection and layer norm. - """ - - def __init__(self, hidden_size: int = 768, num_attention_heads: int = 12, dropout: float = 0.1): - super().__init__() - self.num_attention_heads = num_attention_heads - self.attention_head_size = hidden_size // num_attention_heads - self.all_head_size = self.num_attention_heads * self.attention_head_size - - self.query = nn.Linear(hidden_size, self.all_head_size) - self.key = nn.Linear(hidden_size, self.all_head_size) - self.value = nn.Linear(hidden_size, self.all_head_size) - self.output_dense = nn.Linear(hidden_size, hidden_size) - self.output_dropout = nn.Dropout(dropout) - self.output_layer_norm = nn.LayerNorm(hidden_size) - self.dropout = nn.Dropout(dropout) - - def _transpose_for_scores(self, x): - new_shape = x.size()[:-1] + (self.num_attention_heads, self.attention_head_size) - return x.view(*new_shape).permute(0, 2, 1, 3) - - def forward(self, hidden_states, condition_embeddings, condition_mask=None): - """Apply cross-attention. - - Args: - hidden_states: SAFE token hidden states [B, safe_len, H]. - condition_embeddings: Conditioning embeddings [B, cond_len, H]. - condition_mask: Mask for conditioning tokens [B, cond_len]. - - Returns: - Updated hidden states [B, safe_len, H]. - """ - q = self._transpose_for_scores(self.query(hidden_states)) - k = self._transpose_for_scores(self.key(condition_embeddings)) - v = self._transpose_for_scores(self.value(condition_embeddings)) - - scores = torch.matmul(q, k.transpose(-1, -2)) / math.sqrt(self.attention_head_size) - - if condition_mask is not None: - ext_mask = (1.0 - condition_mask.unsqueeze(1).unsqueeze(2)) * -10000.0 - scores = scores + ext_mask - - probs = self.dropout(torch.softmax(scores, dim=-1)) - context = torch.matmul(probs, v) - context = context.permute(0, 2, 1, 3).contiguous() - context = context.view(context.size()[:-2] + (self.all_head_size,)) - - output = self.output_dropout(self.output_dense(context)) - return self.output_layer_norm(hidden_states + output) - - -class CrossAttentionFormulaConditioner(nn.Module): - """Complete cross-attention formula conditioner. - - 1. Encodes formula as a 30-length sequence (one per atom type). - 2. Provides per-layer cross-attention layers for injection into BERT. - """ - - def __init__( - self, - num_atom_types: int = 30, - hidden_size: int = 768, - num_attention_heads: int = 12, - num_layers: int = 12, - dropout: float = 0.1, - use_count_embedding: bool = True, - ): - super().__init__() - self.formula_encoder = FormulaSequenceEncoder( - num_atom_types=num_atom_types, - embedding_dim=hidden_size, - use_count_embedding=use_count_embedding, - ) - self.cross_attention_layers = nn.ModuleList([ - CrossAttentionLayer(hidden_size, num_attention_heads, dropout) - for _ in range(num_layers) - ]) - - def encode_formula(self, formula_vectors): - return self.formula_encoder(formula_vectors) - - -class CrossAttentionFingerprintConditioner(nn.Module): - """Cross-attention conditioner for fingerprints using set-aware encoding. - - Uses FingerprintSequenceEncoder to produce set embeddings, optionally - with its own cross-attention layers (or sharing formula's layers). - """ - - def __init__( - self, - num_bits: int = 4096, - hidden_size: int = 768, - num_attention_heads: int = 12, - num_layers: int = 12, - max_seq_len: int = 256, - activation_threshold: float = 0.0, - dropout: float = 0.1, - num_self_attention_layers: int = 2, - create_cross_attention_layers: bool = True, - ): - super().__init__() - self.fingerprint_encoder = FingerprintSequenceEncoder( - num_bits=num_bits, - embedding_dim=hidden_size, - max_seq_len=max_seq_len, - activation_threshold=activation_threshold, - dropout=dropout, - num_self_attention_layers=num_self_attention_layers, - num_attention_heads=num_attention_heads, - ) - if create_cross_attention_layers: - self.cross_attention_layers = nn.ModuleList([ - CrossAttentionLayer(hidden_size, num_attention_heads, dropout) - for _ in range(num_layers) - ]) - else: - self.cross_attention_layers = None - - def encode_fingerprint(self, fingerprint_vectors): - return self.fingerprint_encoder(fingerprint_vectors) diff --git a/massspecgym/models/de_novo/fp2mol/frigid/mdlm.py b/massspecgym/models/de_novo/fp2mol/frigid/mdlm.py deleted file mode 100644 index fafc08a..0000000 --- a/massspecgym/models/de_novo/fp2mol/frigid/mdlm.py +++ /dev/null @@ -1,246 +0,0 @@ -""" -Self-contained Masked Diffusion Language Model (MDLM) implementation. - -Replaces the bionemo.moco dependency with a standalone ~200 line implementation -matching the MDLM formulation from Sahoo et al. 2024 and FRIGID's usage. - -Key operations: -- Log-linear exponential noise schedule: alpha(t) = exp((1-t)*log(alpha_max) + t*log(alpha_min)) -- Forward process: independently mask each token with probability 1 - alpha(t) -- Loss: masked-token NLL weighted by -alpha'(t)/alpha(t) -- Confidence-based sampling: unmask most confident positions iteratively -""" - -import math - -import torch -import torch.nn.functional as F - - -class LogLinearExpNoiseSchedule: - """Log-linear exponential noise schedule for MDLM. - - alpha(t) = exp((1 - t) * log(alpha_max) + t * log(alpha_min)) - sigma(t) = -log(alpha(t)) - - At t=0: alpha = alpha_max (no masking), at t=1: alpha = alpha_min (nearly all masked). - """ - - def __init__(self, alpha_max: float = 1.0, alpha_min: float = 1e-3): - self.log_alpha_max = math.log(alpha_max) - self.log_alpha_min = math.log(alpha_min) - - def alpha(self, t: torch.Tensor) -> torch.Tensor: - """Compute alpha(t) for given time values.""" - log_alpha = (1 - t) * self.log_alpha_max + t * self.log_alpha_min - return torch.exp(log_alpha) - - def sigma(self, t: torch.Tensor) -> torch.Tensor: - """Compute sigma(t) = -log(alpha(t)).""" - return -((1 - t) * self.log_alpha_max + t * self.log_alpha_min) - - def d_sigma_dt(self, t: torch.Tensor) -> torch.Tensor: - """Compute d/dt sigma(t) = log(alpha_max) - log(alpha_min). - - For default alpha_max=1: d_sigma/dt = -log(alpha_min) > 0. - """ - return torch.full_like(t, self.log_alpha_max - self.log_alpha_min) - - def loss_weight(self, t: torch.Tensor) -> torch.Tensor: - """Compute the continuous-time NELBO weight: d_sigma/dt / (exp(sigma) - 1). - - This is the correct importance weight from Sahoo et al. 2024 (Eq. 11) - for the MDLM continuous-time NELBO, matching bionemo's implementation. - """ - sig = self.sigma(t) - dsig = self.d_sigma_dt(t) - return dsig / torch.expm1(sig).clamp(min=1e-8) - - -class MDLM: - """Masked Diffusion Language Model. - - Implements the forward masking process, ELBO loss computation, and - confidence-based iterative unmasking for generation. - - Args: - mask_token_id: Token ID used for [MASK]. - vocab_size: Size of the token vocabulary. - noise_schedule: Noise schedule instance. - sampling_eps: Minimum time value to avoid numerical issues. - """ - - def __init__( - self, - mask_token_id: int, - vocab_size: int, - noise_schedule: LogLinearExpNoiseSchedule = None, - sampling_eps: float = 1e-3, - ): - self.mask_token_id = mask_token_id - self.vocab_size = vocab_size - self.noise_schedule = noise_schedule or LogLinearExpNoiseSchedule() - self.sampling_eps = sampling_eps - self._device = torch.device("cpu") - - def to_device(self, device): - self._device = device - - def sample_time(self, batch_size: int, antithetic: bool = True) -> torch.Tensor: - """Sample diffusion time t ~ U(eps, 1). - - With antithetic sampling, pairs (t, 1-t+eps) are used for variance reduction. - """ - if antithetic and batch_size % 2 == 0: - half = batch_size // 2 - t = torch.rand(half, device=self._device) * (1 - self.sampling_eps) + self.sampling_eps - t = torch.cat([t, 1 - t + self.sampling_eps], dim=0) - else: - t = torch.rand(batch_size, device=self._device) * (1 - self.sampling_eps) + self.sampling_eps - return t - - def forward_process(self, x0: torch.Tensor, t: torch.Tensor) -> torch.Tensor: - """Apply forward masking process. - - Each token is independently replaced with [MASK] with probability 1 - alpha(t). - - Args: - x0: Clean token IDs [batch, seq_len]. - t: Time values [batch]. - - Returns: - Noisy token IDs with some tokens replaced by mask_token_id. - """ - alpha_t = self.noise_schedule.alpha(t) # [batch] - keep_prob = alpha_t[:, None] # [batch, 1] - mask = torch.rand_like(x0.float()) > keep_prob # True = mask this token - xt = x0.clone() - xt[mask] = self.mask_token_id - return xt - - def loss( - self, - logits: torch.Tensor, - x0: torch.Tensor, - xt: torch.Tensor, - t: torch.Tensor, - mask: torch.Tensor = None, - global_mean: bool = True, - ) -> torch.Tensor: - """Compute MDLM training loss (continuous-time NELBO). - - Matches bionemo.moco MDLM.loss(use_weight=True) exactly: - - Uses substitution parameterization implicitly: loss only at masked positions. - - Weight: d_sigma/dt / (exp(sigma) - 1), the correct continuous-time NELBO weight - from Sahoo et al. 2024 (Eq. 11) / https://arxiv.org/pdf/2406.07524. - - Args: - logits: Model output [batch, seq_len, vocab_size]. - x0: Clean token IDs [batch, seq_len]. - xt: Noisy token IDs [batch, seq_len]. - t: Time values [batch]. - mask: Attention mask [batch, seq_len] (1=valid, 0=padding). - global_mean: If True, sum all token losses and divide by total token count - (matching bionemo's global_mean=True behavior). - - Returns: - Loss tensor (scalar if global_mean, else per-sample [batch]). - """ - log_probs = F.log_softmax(logits, dim=-1) # [batch, seq_len, vocab_size] - nll = F.nll_loss( - log_probs.view(-1, self.vocab_size), - x0.view(-1), - reduction="none", - ).view_as(x0) # [batch, seq_len] - - # Subs parameterization: only count loss at masked positions. - # Non-masked positions would have log_p=0 under subs param, so zeroing - # them out here is equivalent to bionemo's _subs_parameterization. - is_masked = xt == self.mask_token_id - nll = nll * is_masked.float() - - # Apply mask for padding - if mask is not None: - nll = nll * mask.float() - - # Continuous-time NELBO weight: d_sigma/dt / (exp(sigma) - 1) - weight = self.noise_schedule.loss_weight(t) # [batch] - - # Weight each sample's token NLL sum - weighted_nll = nll.sum(dim=1) * weight # [batch] - - if global_mean: - if mask is not None: - total_tokens = mask.float().sum() - else: - total_tokens = float(x0.numel()) - total_tokens = max(total_tokens, 1.0) - return weighted_nll.sum() / total_tokens - else: - if mask is not None: - num_tokens = mask.float().sum(dim=1).clamp(min=1) - else: - num_tokens = float(x0.size(1)) - return weighted_nll / num_tokens - - def get_num_steps_confidence(self, x: torch.Tensor) -> int: - """Get number of unmasking steps = number of [MASK] tokens in x.""" - return (x == self.mask_token_id).sum(dim=-1).max().item() - - @torch.no_grad() - def step_confidence( - self, - logits: torch.Tensor, - x: torch.Tensor, - step_idx: int, - num_steps: int, - temperature: float = 1.0, - randomness: float = 1.0, - ) -> torch.Tensor: - """One confidence-based unmasking step, matching bionemo MDLM exactly. - - 1. Apply subs parameterization (copy non-masked tokens). - 2. Sample provisional tokens from softmax(logits / temperature). - 3. Gather per-token confidence = p(sampled_token). - 4. Perturb confidence with annealed Gumbel noise: (log(conf) + noise) / 1.0. - 5. Unmask the most confident position; keep others masked. - - Args: - logits: Model logits [batch, seq_len, vocab_size]. - x: Current token IDs with masks [batch, seq_len]. - step_idx: Current step index (0-based). - num_steps: Total number of steps. - temperature: Softmax temperature for logits. - randomness: Gumbel noise scale (annealed linearly over steps). - - Returns: - Updated token IDs with one fewer mask per batch element. - """ - x_new = x.clone() - - probs = F.softmax(logits / max(temperature, 1e-8), dim=-1) - preds = torch.distributions.Categorical(probs=probs).sample() # [batch, seq_len] - - # Confidence = probability of the sampled token - confidence = probs.gather(-1, preds.unsqueeze(-1)).squeeze(-1) # [batch, seq_len] - - # Annealed Gumbel noise (decreases linearly from randomness to 0) - ratio = step_idx / max(num_steps - 1, 1) - gumbel_noise = -torch.log(-torch.log( - torch.rand_like(confidence, device=logits.device) - )) - gumbel_noise = gumbel_noise * randomness * (1 - ratio) - - # Log-confidence + Gumbel (matching bionemo: log(conf) + noise) - confidence = torch.log(confidence.clamp(min=1e-8)) + gumbel_noise - - # Only consider masked positions - is_masked = x == self.mask_token_id - confidence[~is_masked] = -float("inf") - - # Unmask the single most confident position per batch element - best_pos = confidence.argmax(dim=-1) # [batch] - batch_idx = torch.arange(x.size(0), device=x.device) - x_new[batch_idx, best_pos] = preds[batch_idx, best_pos] - - return x_new diff --git a/massspecgym/models/de_novo/fp2mol/frigid/model.py b/massspecgym/models/de_novo/fp2mol/frigid/model.py deleted file mode 100644 index a103dd9..0000000 --- a/massspecgym/models/de_novo/fp2mol/frigid/model.py +++ /dev/null @@ -1,404 +0,0 @@ -""" -FRIGID decoder: Masked Diffusion Language Model for fingerprint-to-molecule generation. - -Implements the FRIGID-base architecture: a BERT backbone with cross-attention -conditioning on chemical formula and molecular fingerprint, trained with MDLM -(Masked Diffusion Language Model) objective over SAFE token sequences. - -Key architectural details (matching FRIGID paper): -- BERT backbone: 12 layers, hidden 768, 12 heads, FFN 3072, vocab ~1880 SAFE BPE -- Formula conditioning: 30-element sequence with atom+count+position embeddings -- Fingerprint conditioning: active-bit set (max 256) with 3 self-attention layers -- Shared cross-attention: formula + FP concatenated for joint conditioning -- Training: MDLM loss + optional differentiable formula loss -""" - -import random -from typing import Optional, List, Tuple - -import torch -import torch.nn as nn -import torch.nn.functional as F -from transformers import AutoTokenizer, BertForMaskedLM -from transformers.models.bert.configuration_bert import BertConfig - -from massspecgym.models.base import Stage -from massspecgym.models.de_novo.fp2mol.base import FP2MolDeNovoModel -from massspecgym.models.de_novo.fp2mol.formula_utils import FormulaEncoder -from .mdlm import MDLM, LogLinearExpNoiseSchedule -from .components import ( - CrossAttentionFormulaConditioner, - CrossAttentionFingerprintConditioner, -) -from .bert_cross_attention import BertForMaskedLMWithCrossAttention - - -def _safe_to_smiles(safe_string: str) -> Optional[str]: - """Convert SAFE string to SMILES, returning None on failure.""" - try: - from safe import decode as safe_decode - smiles = safe_decode(safe_string) - if smiles: - return smiles - except Exception: - pass - try: - smi = safe_string.replace(".", "") - from rdkit import Chem - mol = Chem.MolFromSmiles(smi) - if mol is not None: - return Chem.MolToSmiles(mol) - except Exception: - pass - return None - - -class FRIGIDDecoder(FP2MolDeNovoModel): - """FRIGID Masked Diffusion Language Model decoder. - - Generates SAFE molecular sequences conditioned on Morgan fingerprints - and chemical formulas using iterative confidence-based unmasking. - - Args: - hidden_size: BERT hidden dimension. - num_hidden_layers: Number of BERT layers. - num_attention_heads: Number of attention heads. - intermediate_size: BERT FFN intermediate dimension. - max_position_embeddings: Maximum sequence length. - vocab_size: SAFE BPE vocabulary size. - tokenizer_name: HuggingFace tokenizer name. - fingerprint_bits: Number of fingerprint bits. - fingerprint_seq_max_len: Maximum fingerprint sequence length. - fingerprint_activation_threshold: Threshold for active bits. - fingerprint_num_self_attention_layers: Self-attention layers in FP encoder. - use_formula_conditioning: Whether to use formula cross-attention. - use_fingerprint_conditioning: Whether to use fingerprint cross-attention. - use_shared_cross_attention: Whether to concatenate formula+FP for shared cross-attn. - formula_dropout_prob: Probability of dropping formula conditioning during training. - fingerprint_dropout_prob: Probability of dropping FP conditioning during training. - antithetic_sampling: Use antithetic time sampling in MDLM. - formula_loss_weight: Weight for differentiable formula matching loss. - softmax_temp: Sampling temperature. - randomness: Gumbel noise scale for confidence sampling. - ema_decay: EMA decay rate (0 to disable). - """ - - def __init__( - self, - hidden_size: int = 768, - num_hidden_layers: int = 12, - num_attention_heads: int = 12, - intermediate_size: int = 3072, - max_position_embeddings: int = 256, - vocab_size: int = 1880, - tokenizer_name: str = "datamol-io/safe-gpt", - fingerprint_bits: int = 4096, - fingerprint_seq_max_len: int = 256, - fingerprint_activation_threshold: float = 0.0, - fingerprint_num_self_attention_layers: int = 3, - use_formula_conditioning: bool = True, - use_fingerprint_conditioning: bool = True, - use_shared_cross_attention: bool = True, - formula_dropout_prob: float = 0.0, - fingerprint_dropout_prob: float = 0.25, - antithetic_sampling: bool = True, - formula_loss_weight: float = 0.0, - softmax_temp: float = 0.8, - randomness: float = 0.5, - ema_decay: float = 0.0, - *args, - **kwargs, - ): - super().__init__(fingerprint_bits=fingerprint_bits, *args, **kwargs) - - self.hidden_size = hidden_size - self.use_formula_conditioning = use_formula_conditioning - self.use_fingerprint_conditioning = use_fingerprint_conditioning - self.use_shared_cross_attention = use_shared_cross_attention - self.formula_dropout_prob = formula_dropout_prob - self.fingerprint_dropout_prob = fingerprint_dropout_prob - self.antithetic_sampling = antithetic_sampling - self.formula_loss_weight = formula_loss_weight - self.softmax_temp = softmax_temp - self.randomness = randomness - - self.tokenizer = AutoTokenizer.from_pretrained(tokenizer_name, trust_remote_code=True) - actual_vocab_size = self.tokenizer.vocab_size - self.mask_index = self.tokenizer.mask_token_id - self.bos_index = self.tokenizer.bos_token_id - self.eos_index = self.tokenizer.eos_token_id - self.pad_index = self.tokenizer.pad_token_id - - self.formula_encoder = FormulaEncoder(normalize="none") - - if self.use_formula_conditioning: - self.formula_conditioner = CrossAttentionFormulaConditioner( - num_atom_types=self.formula_encoder.vocab_size, - hidden_size=hidden_size, - num_attention_heads=num_attention_heads, - num_layers=num_hidden_layers, - dropout=0.1, - use_count_embedding=True, - ) - - if self.use_fingerprint_conditioning: - create_fp_cross_attn = not use_shared_cross_attention - self.fingerprint_conditioner = CrossAttentionFingerprintConditioner( - num_bits=fingerprint_bits, - hidden_size=hidden_size, - num_attention_heads=num_attention_heads, - num_layers=num_hidden_layers, - max_seq_len=fingerprint_seq_max_len, - activation_threshold=fingerprint_activation_threshold, - dropout=0.1, - num_self_attention_layers=fingerprint_num_self_attention_layers, - create_cross_attention_layers=create_fp_cross_attn, - ) - - bert_config = BertConfig( - vocab_size=actual_vocab_size, - hidden_size=hidden_size, - num_hidden_layers=num_hidden_layers, - num_attention_heads=num_attention_heads, - intermediate_size=intermediate_size, - max_position_embeddings=max_position_embeddings, - hidden_dropout_prob=0.1, - attention_probs_dropout_prob=0.1, - ) - - formula_ca = self.formula_conditioner.cross_attention_layers if self.use_formula_conditioning else None - fp_ca = None - if self.use_fingerprint_conditioning and not use_shared_cross_attention: - fp_ca = self.fingerprint_conditioner.cross_attention_layers - - self.backbone = BertForMaskedLMWithCrossAttention( - bert_config, - cross_attention_layers=formula_ca, - fingerprint_cross_attention_layers=fp_ca, - use_shared_cross_attention=use_shared_cross_attention, - ) - - self.mdlm = MDLM( - mask_token_id=self.mask_index, - vocab_size=actual_vocab_size, - noise_schedule=LogLinearExpNoiseSchedule(), - sampling_eps=1e-3, - ) - - self.max_position_embeddings = max_position_embeddings - - def _build_token_embeddings(self, x): - emb = self.backbone.embeddings - token_emb = emb.word_embeddings(x) - pos_ids = torch.arange(x.size(1), device=x.device).unsqueeze(0).expand_as(x) - pos_emb = emb.position_embeddings(pos_ids) - type_emb = emb.token_type_embeddings(torch.zeros_like(x)) - return token_emb + pos_emb + type_emb - - def _prepare_formula_embeddings(self, formula, x): - if not self.use_formula_conditioning: - return None, None - if formula is not None: - fv = self.formula_encoder.encode_batch(formula).to(x.device) - else: - fv = self.formula_encoder.encode_batch(["C"] * x.size(0)).to(x.device) - return fv.new_zeros(x.size(0), self.formula_encoder.vocab_size, self.hidden_size), \ - fv.new_zeros(x.size(0), self.formula_encoder.vocab_size) - emb, mask = self.formula_conditioner.encode_formula(fv) - if self.training and formula is not None and random.random() < self.formula_dropout_prob: - emb = emb * 0.0 - return emb, mask - - def _prepare_fingerprint_embeddings(self, fingerprint, x): - if not self.use_fingerprint_conditioning: - return None, None - if fingerprint is None: - return None, None - fp = fingerprint.to(device=x.device, dtype=torch.float32) - if fp.dim() == 1: - fp = fp.unsqueeze(0) - if fp.size(0) == 1 and x.size(0) > 1: - fp = fp.expand(x.size(0), -1) - emb, mask = self.fingerprint_conditioner.encode_fingerprint(fp) - if self.training and random.random() < self.fingerprint_dropout_prob: - emb = emb * 0.0 - return emb, mask - - def forward_model(self, x, attention_mask=None, formula=None, fingerprint=None): - """Forward pass through BERT backbone with conditioning. - - Matches the reference GenMol.forward() exactly: - 1. Build token + position + type embeddings. - 2. Apply LayerNorm + dropout. - 3. Compute extended attention mask. - 4. In shared mode: concatenate formula + FP embeddings for single cross-attn path. - In independent mode: pass them separately. - 5. Run encoder layers (self-attn -> cross-attn -> FFN per layer). - 6. Apply MLM head (cls) to get logits. - - Returns logits [batch, seq_len, vocab_size]. - """ - with torch.amp.autocast("cuda", dtype=torch.float32): - formula_emb, formula_mask = self._prepare_formula_embeddings(formula, x) - fp_emb, fp_mask = self._prepare_fingerprint_embeddings(fingerprint, x) - - embeddings = self._build_token_embeddings(x) - embeddings = self.backbone.embeddings.LayerNorm(embeddings) - embeddings = self.backbone.embeddings.dropout(embeddings) - - if attention_mask is None: - attention_mask = torch.ones_like(x) - ext_attn = self.backbone.get_extended_attention_mask( - attention_mask, x.shape, x.device - ) - - if self.use_shared_cross_attention: - cond_emb = formula_emb - cond_mask = formula_mask - if fp_emb is not None: - if cond_emb is None: - cond_emb, cond_mask = fp_emb, fp_mask - else: - cond_emb = torch.cat([cond_emb, fp_emb], dim=1) - cond_mask = torch.cat([cond_mask, fp_mask], dim=1) - enc_out = self.backbone.bert.encoder( - embeddings, attention_mask=ext_attn, - condition_embeddings=cond_emb, condition_mask=cond_mask, - ) - else: - enc_out = self.backbone.bert.encoder( - embeddings, attention_mask=ext_attn, - condition_embeddings=formula_emb, condition_mask=formula_mask, - fingerprint_embeddings=fp_emb, fingerprint_mask=fp_mask, - ) - - sequence_output = enc_out[0] - return self.backbone.cls(sequence_output) - - def compute_decoder_loss(self, batch: dict) -> torch.Tensor: - """Compute MDLM training loss from a batch. - - In fp2mol_pretrain mode, batch contains: fingerprint, formula, mol_repr. - In spec2mol mode, batch contains spectrum data + mol. - """ - fingerprint = batch.get("fingerprint", None) - formula = batch.get("formula", None) - mol_repr = batch.get("mol_repr", batch.get("mol", None)) - - if isinstance(mol_repr, (list, tuple)): - encoded = self.tokenizer( - list(mol_repr), return_tensors="pt", padding=True, - truncation=True, max_length=self.max_position_embeddings, - ) - input_ids = encoded["input_ids"].to(self.device) - attention_mask = encoded["attention_mask"].to(self.device) - else: - input_ids = mol_repr - attention_mask = (mol_repr != self.pad_index).long() - - self.mdlm.to_device(self.device) - t = self.mdlm.sample_time(input_ids.shape[0], antithetic=self.antithetic_sampling) - t = t.to(self.device) - xt = self.mdlm.forward_process(input_ids, t) - - logits = self.forward_model(xt, attention_mask, formula=formula, fingerprint=fingerprint) - loss = self.mdlm.loss(logits, input_ids, xt, t, mask=attention_mask, global_mean=True) - - if self.formula_loss_weight > 0 and formula is not None: - gt_fv = self.formula_encoder.encode_batch(formula, normalize="none").to(self.device) - probs = torch.softmax(logits, dim=-1) - token_atom_counts = self._get_token_atom_counts() - expected = torch.matmul(probs, token_atom_counts) - if attention_mask is not None: - expected = expected * attention_mask.unsqueeze(-1) - predicted = expected.sum(dim=1) - f_loss = F.mse_loss(predicted, gt_fv) - loss = loss + self.formula_loss_weight * f_loss - - return loss - - def _get_token_atom_counts(self): - if not hasattr(self, "_token_atom_counts_buf"): - n_atoms = self.formula_encoder.vocab_size - v_size = self.tokenizer.vocab_size - buf = torch.zeros(v_size, n_atoms, dtype=torch.float32, device=self.device) - for tid in range(v_size): - tok_str = self.tokenizer.decode([tid]) - try: - counts = self.formula_encoder.formula_to_counts(tok_str) - vec = self.formula_encoder.counts_to_vector(counts, normalize="none") - buf[tid] = vec.to(self.device) - except Exception: - pass - self._token_atom_counts_buf = buf - return self._token_atom_counts_buf - - @torch.no_grad() - def decode_from_fingerprint( - self, - fingerprint: torch.Tensor, - formula=None, - num_samples: int = 1, - ) -> list: - """Generate molecules from fingerprint + formula via iterative unmasking.""" - self.eval() - self.mdlm.to_device(self.device) - batch_size = fingerprint.shape[0] - all_preds = [] - - for b_idx in range(batch_size): - fp_single = fingerprint[b_idx:b_idx + 1] - form_single = [formula[b_idx]] if formula is not None else None - - x = torch.full((1, 1), self.bos_index, device=self.device) - x = torch.cat([x, torch.full((1, 1), self.eos_index, device=self.device)], dim=1) - - target_len = 50 - x_batch = self._insert_masks(x, num_samples, target_len) - x_batch = x_batch.to(self.device) - - fp_expanded = fp_single.expand(num_samples, -1) - form_expanded = form_single * num_samples if form_single else None - - num_steps = max(self.mdlm.get_num_steps_confidence(x_batch), 2) - attn_mask = (x_batch != self.pad_index).long() - - for i in range(num_steps): - logits = self.forward_model( - x_batch, attn_mask, formula=form_expanded, fingerprint=fp_expanded - ) - x_batch = self.mdlm.step_confidence( - logits, x_batch, i, num_steps, self.softmax_temp, self.randomness - ) - - decoded = self.tokenizer.batch_decode(x_batch, skip_special_tokens=True) - smiles_list = [] - for safe_str in decoded: - smi = _safe_to_smiles(safe_str) - smiles_list.append(smi) - all_preds.append(smiles_list) - - return all_preds - - def _insert_masks(self, x, num_samples, target_len): - """Create num_samples copies of x with mask tokens inserted.""" - x_seq = x[0] - results = [] - for _ in range(num_samples): - add_len = max(target_len - len(x_seq), 10) - add_len = min(add_len, self.max_position_embeddings - len(x_seq)) - add_len = max(add_len, 10) - new_x = torch.cat([ - x_seq[:-1], - torch.full((add_len,), self.mask_index, device=x.device), - x_seq[-1:], - ]) - results.append(new_x) - max_len = max(len(r) for r in results) - padded = [] - for r in results: - pad_len = max_len - len(r) - if pad_len > 0: - r = torch.cat([r, torch.full((pad_len,), self.pad_index, device=x.device)]) - padded.append(r) - return torch.stack(padded) diff --git a/massspecgym/models/de_novo/fp2mol/molforge/__init__.py b/massspecgym/models/de_novo/fp2mol/molforge/__init__.py deleted file mode 100644 index 92f62f6..0000000 --- a/massspecgym/models/de_novo/fp2mol/molforge/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -""" -MolForge decoder: Seq2Seq Transformer for fingerprint-to-molecule generation. - -An encoder-decoder transformer that maps fingerprint bit indices (as a sequence) -to SMILES or SELFIES molecular strings via autoregressive generation. -""" - -from .model import MolForgeDecoder diff --git a/massspecgym/models/de_novo/fp2mol/molforge/decoder_search.py b/massspecgym/models/de_novo/fp2mol/molforge/decoder_search.py deleted file mode 100644 index 27f4a4d..0000000 --- a/massspecgym/models/de_novo/fp2mol/molforge/decoder_search.py +++ /dev/null @@ -1,138 +0,0 @@ -""" -Greedy and beam search decoding for MolForge. - -Implements autoregressive decoding strategies for the encoder-decoder -transformer, converting encoder memory into target token sequences. -""" - -import heapq -from dataclasses import dataclass, field -from typing import List, Optional - -import torch -import torch.nn.functional as F - - -@dataclass(order=True) -class BeamNode: - """A node in the beam search tree.""" - score: float - tokens: List[int] = field(compare=False) - finished: bool = field(default=False, compare=False) - - -def greedy_search( - decoder: "torch.nn.Module", - trg_embedding: "torch.nn.Module", - positional_encoder: "torch.nn.Module", - output_linear: "torch.nn.Module", - e_output: torch.Tensor, - e_mask: torch.Tensor, - sos_id: int, - eos_id: int, - pad_id: int, - max_len: int, - device: torch.device, -) -> List[int]: - """Greedy autoregressive decoding. - - At each step, the most likely next token is selected. - - Args: - decoder: Transformer decoder module. - trg_embedding: Target embedding layer. - positional_encoder: Positional encoding module. - output_linear: Linear projection to vocabulary. - e_output: Encoder output [1, src_len, d_model]. - e_mask: Encoder attention mask [1, 1, src_len]. - sos_id: Start-of-sequence token ID. - eos_id: End-of-sequence token ID. - pad_id: Padding token ID. - max_len: Maximum output length. - device: Target device. - - Returns: - List of generated token IDs (excluding SOS, including EOS if generated). - """ - last_words = torch.full((1, max_len), pad_id, dtype=torch.long, device=device) - last_words[0, 0] = sos_id - cur_len = 1 - - for i in range(max_len - 1): - d_mask = _subsequent_mask(cur_len, device) - trg = trg_embedding(last_words[:, :cur_len]) - trg = positional_encoder(trg) - d_output = decoder(trg, e_output, tgt_mask=d_mask, memory_key_padding_mask=~e_mask.squeeze(1).bool() if e_mask is not None else None) - output = F.log_softmax(output_linear(d_output[:, -1, :]), dim=-1) - next_id = output.argmax(dim=-1).item() - last_words[0, cur_len] = next_id - cur_len += 1 - if next_id == eos_id: - break - - return last_words[0, 1:cur_len].tolist() - - -def beam_search( - decoder: "torch.nn.Module", - trg_embedding: "torch.nn.Module", - positional_encoder: "torch.nn.Module", - output_linear: "torch.nn.Module", - e_output: torch.Tensor, - e_mask: torch.Tensor, - sos_id: int, - eos_id: int, - pad_id: int, - max_len: int, - device: torch.device, - beam_size: int = 10, -) -> List[List[int]]: - """Beam search decoding. - - Maintains top-k hypotheses at each step, returning all completed hypotheses - ranked by log-probability score. - - Returns: - List of token ID lists, best-scoring first. - """ - beams = [BeamNode(score=0.0, tokens=[sos_id])] - completed = [] - - for _ in range(max_len): - candidates = [] - for beam in beams: - if beam.finished: - completed.append(beam) - continue - - seq = torch.tensor([beam.tokens], dtype=torch.long, device=device) - d_mask = _subsequent_mask(seq.size(1), device) - trg = trg_embedding(seq) - trg = positional_encoder(trg) - d_output = decoder(trg, e_output, tgt_mask=d_mask, memory_key_padding_mask=~e_mask.squeeze(1).bool() if e_mask is not None else None) - log_probs = F.log_softmax(output_linear(d_output[:, -1, :]), dim=-1) - - topk_scores, topk_ids = log_probs.topk(beam_size, dim=-1) - for j in range(beam_size): - token_id = topk_ids[0, j].item() - new_score = beam.score + topk_scores[0, j].item() - new_tokens = beam.tokens + [token_id] - finished = token_id == eos_id - candidates.append(BeamNode(score=new_score, tokens=new_tokens, finished=finished)) - - candidates.sort(key=lambda n: n.score, reverse=True) - beams = candidates[:beam_size] - - if all(b.finished for b in beams): - break - - all_results = completed + beams - all_results.sort(key=lambda n: n.score, reverse=True) - - return [node.tokens[1:] for node in all_results] - - -def _subsequent_mask(size: int, device: torch.device) -> torch.Tensor: - """Generate causal (upper-triangular) mask for autoregressive decoding.""" - mask = torch.triu(torch.ones(size, size, device=device), diagonal=1).bool() - return mask diff --git a/massspecgym/models/de_novo/fp2mol/molforge/model.py b/massspecgym/models/de_novo/fp2mol/molforge/model.py deleted file mode 100644 index 59183d5..0000000 --- a/massspecgym/models/de_novo/fp2mol/molforge/model.py +++ /dev/null @@ -1,272 +0,0 @@ -""" -MolForge decoder: Encoder-Decoder Transformer for fingerprint-to-SMILES generation. - -Ported from Neo et al., "One Small Step with Fingerprints, One Giant Leap for -De Novo Molecule Generation from Mass Spectra", 2025. - -The model treats a molecular fingerprint as a sequence of on-bit indices, -encodes them through a transformer encoder, then autoregressively decodes -SMILES (or SELFIES) token sequences. - -Architecture (matching MolForge paper): -- Encoder: 6 layers, 512d, 8 heads, FFN 2048 -- Decoder: 6 layers, 512d, 8 heads, FFN 2048 -- Source: fingerprint on-bit indices -> SentencePiece tokens -> encoder -- Target: SMILES/SELFIES -> SentencePiece tokens -> decoder -""" - -import math -from typing import Optional, List - -import numpy as np -import torch -import torch.nn as nn -import torch.nn.functional as F - -from massspecgym.models.base import Stage -from massspecgym.models.de_novo.fp2mol.base import FP2MolDeNovoModel -from .decoder_search import greedy_search, beam_search - - -class PositionalEncoding(nn.Module): - """Sinusoidal positional encoding.""" - - def __init__(self, d_model: int, max_len: int = 512, dropout: float = 0.1): - super().__init__() - self.dropout = nn.Dropout(p=dropout) - pe = torch.zeros(max_len, d_model) - position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1) - div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)) - pe[:, 0::2] = torch.sin(position * div_term) - pe[:, 1::2] = torch.cos(position * div_term) - pe = pe.unsqueeze(0) - self.register_buffer("pe", pe) - - def forward(self, x: torch.Tensor) -> torch.Tensor: - x = x + self.pe[:, :x.size(1)] - return self.dropout(x) - - -class MolForgeDecoder(FP2MolDeNovoModel): - """MolForge encoder-decoder transformer for fingerprint-to-SMILES generation. - - The model encodes fingerprint on-bit indices as a source sequence and - autoregressively generates SMILES/SELFIES as the target sequence. - - Fingerprints are represented as space-separated on-bit indices - (e.g., "1 80 94 114 237") and tokenized with a source vocabulary. - - Args: - d_model: Model dimension. - nhead: Number of attention heads. - num_encoder_layers: Number of encoder layers. - num_decoder_layers: Number of decoder layers. - dim_feedforward: FFN intermediate dimension. - dropout: Dropout rate. - src_vocab_size: Source (fingerprint) vocabulary size. - trg_vocab_size: Target (SMILES/SELFIES) vocabulary size. - src_seq_len: Maximum source sequence length. - trg_seq_len: Maximum target sequence length. - pad_id: Padding token ID. - sos_id: Start-of-sequence token ID. - eos_id: End-of-sequence token ID. - beam_size: Beam size for beam search decoding. - decode_method: Decoding method ('greedy' or 'beam'). - fingerprint_bits: Number of fingerprint bits. - """ - - def __init__( - self, - d_model: int = 512, - nhead: int = 8, - num_encoder_layers: int = 6, - num_decoder_layers: int = 6, - dim_feedforward: int = 2048, - dropout: float = 0.1, - src_vocab_size: int = 6000, - trg_vocab_size: int = 109, - src_seq_len: int = 104, - trg_seq_len: int = 130, - pad_id: int = 0, - sos_id: int = 1, - eos_id: int = 2, - beam_size: int = 10, - decode_method: str = "greedy", - fingerprint_bits: int = 2048, - *args, - **kwargs, - ): - super().__init__( - fingerprint_bits=fingerprint_bits, - use_formula=False, - *args, **kwargs, - ) - - self.d_model = d_model - self.src_seq_len = src_seq_len - self.trg_seq_len = trg_seq_len - self.pad_id = pad_id - self.sos_id = sos_id - self.eos_id = eos_id - self.beam_size = beam_size - self.decode_method = decode_method - self.src_vocab_size = src_vocab_size - self.trg_vocab_size = trg_vocab_size - - self.src_embedding = nn.Embedding(src_vocab_size, d_model) - self.trg_embedding = nn.Embedding(trg_vocab_size, d_model) - self.src_positional_encoder = PositionalEncoding(d_model, src_seq_len, dropout) - self.trg_positional_encoder = PositionalEncoding(d_model, trg_seq_len, dropout) - - encoder_layer = nn.TransformerEncoderLayer( - d_model=d_model, nhead=nhead, dim_feedforward=dim_feedforward, - dropout=dropout, batch_first=True, - ) - self.encoder = nn.TransformerEncoder(encoder_layer, num_layers=num_encoder_layers) - - decoder_layer = nn.TransformerDecoderLayer( - d_model=d_model, nhead=nhead, dim_feedforward=dim_feedforward, - dropout=dropout, batch_first=True, - ) - self.decoder = nn.TransformerDecoder(decoder_layer, num_layers=num_decoder_layers) - - self.output_linear = nn.Linear(d_model, trg_vocab_size) - self.criterion = nn.NLLLoss(ignore_index=pad_id) - - def _fp_to_onbit_indices(self, fingerprint: torch.Tensor) -> torch.Tensor: - """Convert binary fingerprint to a padded sequence of on-bit indices. - - Args: - fingerprint: Binary FP tensor [batch, fp_bits]. - - Returns: - LongTensor of on-bit indices [batch, src_seq_len], padded with pad_id. - """ - batch_size = fingerprint.shape[0] - device = fingerprint.device - result = torch.full((batch_size, self.src_seq_len), self.pad_id, dtype=torch.long, device=device) - - for i in range(batch_size): - on_bits = torch.nonzero(fingerprint[i] > 0.5, as_tuple=True)[0] - n = min(len(on_bits), self.src_seq_len - 1) - result[i, :n] = on_bits[:n] + 3 # offset by special tokens (pad=0, sos=1, eos=2) - result[i, n] = self.eos_id - - return result - - def encode_source(self, src_input: torch.Tensor) -> tuple: - """Encode source (fingerprint indices) through the transformer encoder. - - Returns: - Tuple of (encoder output [B, src_len, d_model], encoder mask [B, 1, src_len]). - """ - e_mask = (src_input != self.pad_id).unsqueeze(1).float() - src_emb = self.src_positional_encoder(self.src_embedding(src_input)) - e_output = self.encoder(src_emb, src_key_padding_mask=(src_input == self.pad_id)) - return e_output, e_mask - - def compute_decoder_loss(self, batch: dict) -> torch.Tensor: - """Compute NLL loss with teacher forcing.""" - fingerprint = batch["fingerprint"] - mol_repr = batch.get("mol_repr", batch.get("mol")) - - src_input = self._fp_to_onbit_indices(fingerprint) - e_output, e_mask = self.encode_source(src_input) - - if isinstance(mol_repr, (list, tuple)): - trg_ids = self._tokenize_targets(mol_repr) - else: - trg_ids = mol_repr - - trg_ids = trg_ids.to(self.device) - trg_input = trg_ids[:, :-1] - trg_output = trg_ids[:, 1:] - - d_mask = nn.Transformer.generate_square_subsequent_mask(trg_input.size(1)).to(self.device) - trg_emb = self.trg_positional_encoder(self.trg_embedding(trg_input)) - d_output = self.decoder( - trg_emb, e_output, tgt_mask=d_mask, - memory_key_padding_mask=(src_input == self.pad_id), - ) - output = F.log_softmax(self.output_linear(d_output), dim=-1) - loss = self.criterion(output.reshape(-1, self.trg_vocab_size), trg_output.reshape(-1)) - return loss - - def _tokenize_targets(self, smiles_list: list) -> torch.Tensor: - """Simple character-level tokenization for SMILES (placeholder). - - In production, this should use SentencePiece. For now, uses a simple - character-to-ID mapping as a fallback. - """ - batch_size = len(smiles_list) - max_len = min(max(len(s) for s in smiles_list) + 2, self.trg_seq_len) - result = torch.full((batch_size, max_len), self.pad_id, dtype=torch.long) - - for i, smi in enumerate(smiles_list): - result[i, 0] = self.sos_id - for j, ch in enumerate(smi[:max_len - 2]): - result[i, j + 1] = ord(ch) % (self.trg_vocab_size - 3) + 3 - end_pos = min(len(smi) + 1, max_len - 1) - result[i, end_pos] = self.eos_id - - return result - - @torch.no_grad() - def decode_from_fingerprint( - self, - fingerprint: torch.Tensor, - formula=None, - num_samples: int = 1, - ) -> list: - """Generate SMILES from fingerprint via greedy or beam search.""" - self.eval() - batch_size = fingerprint.shape[0] - all_preds = [] - - for b_idx in range(batch_size): - fp_single = fingerprint[b_idx:b_idx + 1] - src_input = self._fp_to_onbit_indices(fp_single) - e_output, e_mask = self.encode_source(src_input) - - sample_preds = [] - for _ in range(num_samples): - if self.decode_method == "beam": - results = beam_search( - self.decoder, self.trg_embedding, self.trg_positional_encoder, - self.output_linear, e_output, e_mask, - self.sos_id, self.eos_id, self.pad_id, - self.trg_seq_len, self.device, self.beam_size, - ) - if results: - token_ids = results[0] - else: - token_ids = [] - else: - token_ids = greedy_search( - self.decoder, self.trg_embedding, self.trg_positional_encoder, - self.output_linear, e_output, e_mask, - self.sos_id, self.eos_id, self.pad_id, - self.trg_seq_len, self.device, - ) - - smi = self._detokenize(token_ids) - sample_preds.append(smi) - - all_preds.append(sample_preds) - return all_preds - - def _detokenize(self, token_ids: list) -> Optional[str]: - """Convert token IDs back to SMILES (placeholder for SentencePiece).""" - try: - chars = [] - for tid in token_ids: - if tid == self.eos_id: - break - if tid >= 3: - chars.append(chr((tid - 3) % 128 + 32)) - smi = "".join(chars) - from rdkit import Chem - mol = Chem.MolFromSmiles(smi) - return Chem.MolToSmiles(mol) if mol is not None else None - except Exception: - return None diff --git a/massspecgym/models/encoders/__init__.py b/massspecgym/models/encoders/__init__.py deleted file mode 100644 index 9e08df7..0000000 --- a/massspecgym/models/encoders/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -from .mist import SpectraEncoder, SpectraEncoderGrowing - - -def __getattr__(name): - if name == "DreaMS": - from .dreams.model import DreaMS - return DreaMS - if name == "PreTrainedDreaMS": - from .dreams.api import PreTrainedDreaMS - return PreTrainedDreaMS - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/massspecgym/models/encoders/dreams/__init__.py b/massspecgym/models/encoders/dreams/__init__.py deleted file mode 100644 index 83e8246..0000000 --- a/massspecgym/models/encoders/dreams/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" -DreaMS (Deep Representations Enabling All Mass Spectra) encoder. - -A BERT-style transformer encoder for MS/MS spectra that produces 1024-D -spectrum embeddings. Useful for spectral similarity search, retrieval, -and as a general-purpose spectrum representation. - -Ported from external/DreaMS/dreams/ (Bushuiev et al., Nature Biotechnology 2025). -Preserves the exact args-based config system for checkpoint compatibility. -""" - - -def __getattr__(name): - if name == "DreaMS": - from .model import DreaMS - return DreaMS - if name == "PreTrainedDreaMS": - from .api import PreTrainedDreaMS - return PreTrainedDreaMS - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/massspecgym/models/encoders/dreams/api.py b/massspecgym/models/encoders/dreams/api.py deleted file mode 100644 index b23ca35..0000000 --- a/massspecgym/models/encoders/dreams/api.py +++ /dev/null @@ -1,118 +0,0 @@ -""" -DreaMS pretrained model loading and inference API. - -Ported from external/DreaMS/dreams/api.py. -Provides PreTrainedDreaMS for loading checkpoints and computing embeddings. -""" - -from argparse import Namespace -from pathlib import Path -from typing import Optional, Union - -import numpy as np -import torch - -from .model import DreaMS -from .preprocessing import SpectrumPreprocessor, DataFormatA - - -class PreTrainedDreaMS: - """Pretrained DreaMS model for spectrum embedding inference. - - Loads a DreaMS checkpoint and provides a simple API for computing - 1024-D spectrum embeddings. - - Usage: - model = PreTrainedDreaMS.from_checkpoint("checkpoints/dreams/embedding_model.ckpt") - emb = model.embed_spectrum(mzs, intensities, precursor_mz) # (1024,) - """ - - def __init__(self, model: DreaMS, n_highest_peaks: int = 100): - self.model = model.eval() - self.n_highest_peaks = n_highest_peaks - self.preprocessor = SpectrumPreprocessor( - dformat=DataFormatA(), - n_highest_peaks=n_highest_peaks, - ) - - @classmethod - def from_checkpoint( - cls, - ckpt_path: str, - n_highest_peaks: int = 100, - device: str = None, - remove_ssl_heads: bool = True, - ) -> "PreTrainedDreaMS": - """Load a pretrained DreaMS model from checkpoint. - - Args: - ckpt_path: Path to DreaMS checkpoint (.ckpt). - n_highest_peaks: Number of peaks to retain per spectrum. - device: Device to load model on. Auto-detects if None. - remove_ssl_heads: Remove unused SSL heads (ff_out, mz_masking_loss, ro_out). - - Returns: - PreTrainedDreaMS instance ready for inference. - """ - if device is None: - device = "cuda" if torch.cuda.is_available() else "cpu" - - model = DreaMS.load_from_checkpoint(ckpt_path, map_location=device) - - if remove_ssl_heads: - for attr in ('ff_out', 'mz_masking_loss', 'ro_out', 'ff_out_intens'): - if hasattr(model, attr): - delattr(model, attr) - - model = model.to(device) - return cls(model, n_highest_peaks) - - @property - def device(self): - return next(self.model.parameters()).device - - @property - def d_model(self): - return self.model.d_model - - @torch.no_grad() - def embed_spectrum( - self, - mzs: np.ndarray, - intensities: np.ndarray, - precursor_mz: float, - ) -> np.ndarray: - """Compute 1024-D embedding for a single spectrum. - - Args: - mzs: Array of m/z values. - intensities: Array of intensity values. - precursor_mz: Precursor m/z. - - Returns: - 1D numpy array of shape (d_model,) - the spectrum embedding. - """ - spec = self.preprocessor(mzs, intensities, precursor_mz) - spec_tensor = torch.FloatTensor(spec).unsqueeze(0).to(self.device) - output = self.model(spec_tensor) - return output[0, 0, :].cpu().numpy() - - @torch.no_grad() - def embed_batch( - self, - specs: list, - ) -> np.ndarray: - """Compute embeddings for a batch of spectra. - - Args: - specs: List of (mzs, intensities, precursor_mz) tuples. - - Returns: - Array of shape (batch_size, d_model). - """ - preprocessed = [ - self.preprocessor(mzs, ints, pmz) for mzs, ints, pmz in specs - ] - batch = torch.FloatTensor(np.stack(preprocessed)).to(self.device) - output = self.model(batch) - return output[:, 0, :].cpu().numpy() diff --git a/massspecgym/models/encoders/dreams/feed_forward.py b/massspecgym/models/encoders/dreams/feed_forward.py deleted file mode 100644 index 0b019da..0000000 --- a/massspecgym/models/encoders/dreams/feed_forward.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -Generic configurable FeedForward module for DreaMS. - -Ported from external/DreaMS/dreams/models/layers/feed_forward.py. -""" - -import torch -import torch.nn as nn - - -class FeedForward(nn.Module): - """Configurable feed-forward network with variable depth. - - Args: - in_dim: Input dimension. - out_dim: Output dimension. - hidden_dim: Hidden dimension (defaults to out_dim). - depth: Number of layers (1 = single linear). - dropout: Dropout rate. - act_last: Whether to apply activation after last layer. - bias: Whether to use bias in linear layers. - """ - - def __init__(self, in_dim, out_dim, hidden_dim=None, depth=2, - dropout=0.0, act_last=True, bias=True): - super().__init__() - if hidden_dim is None: - hidden_dim = out_dim - - layers = [] - for i in range(depth): - d_in = in_dim if i == 0 else hidden_dim - d_out = out_dim if i == depth - 1 else hidden_dim - layers.append(nn.Linear(d_in, d_out, bias=bias)) - if i < depth - 1 or act_last: - layers.append(nn.ReLU()) - if dropout > 0: - layers.append(nn.Dropout(dropout)) - - self.net = nn.Sequential(*layers) - - def forward(self, x): - return self.net(x) diff --git a/massspecgym/models/encoders/dreams/fourier_features.py b/massspecgym/models/encoders/dreams/fourier_features.py deleted file mode 100644 index fba8e46..0000000 --- a/massspecgym/models/encoders/dreams/fourier_features.py +++ /dev/null @@ -1,79 +0,0 @@ -""" -Fourier feature encoding for m/z values in DreaMS. - -Ported from external/DreaMS/dreams/models/layers/fourier_features.py. -""" - -from math import ceil - -import torch -import torch.nn as nn -from torch.nn import Parameter - - -class FourierFeatures(nn.Module): - """Fourier feature encoding for m/z values. - - Maps scalar m/z values to high-dimensional sinusoidal features, - enabling the transformer to distinguish fine-grained mass differences. - - Strategies: - - 'voronov_et_al': log-spaced frequencies (default for DreaMS). - - 'random': random Gaussian frequencies. - - 'lin_float_int': linear combination of float and integer frequencies. - - Args: - strategy: Frequency spacing strategy. - x_min: Minimum expected input value (for frequency calculation). - x_max: Maximum expected input value. - trainable: Whether frequencies are learnable. - funcs: Which trig functions ('both', 'sin', 'cos'). - sigma: Std for random frequencies. - num_freqs: Number of frequency components. - """ - - def __init__(self, strategy, x_min, x_max, trainable=True, funcs='both', - sigma=10, num_freqs=512): - assert strategy in {'random', 'voronov_et_al', 'lin_float_int'} - assert funcs in {'both', 'sin', 'cos'} - assert x_min < 1 - - super().__init__() - self.funcs = funcs - self.strategy = strategy - self.trainable = trainable - self.num_freqs = num_freqs - - if strategy == 'random': - b = torch.randn(num_freqs) * sigma - elif strategy == 'voronov_et_al': - b = torch.tensor([ - 1 / (x_min * (x_max / x_min) ** (2 * i / (num_freqs - 2))) - for i in range(1, num_freqs) - ]) - elif strategy == 'lin_float_int': - b = torch.tensor( - [1 / (x_min * i) for i in range(2, ceil(1 / x_min), 2)] + - [1 / (1 * i) for i in range(2, ceil(x_max), 1)] - ) - else: - raise ValueError(f"Unknown strategy: {strategy}") - - b = b.unsqueeze(0) - self.b = nn.Parameter(b, requires_grad=self.trainable) - - def num_features(self): - n = self.b.shape[1] - if self.funcs == 'both': - return n * 2 - return n - - def forward(self, x): - x = 2 * torch.pi * x @ self.b - if self.funcs == 'both': - x = torch.cat((torch.cos(x), torch.sin(x)), dim=-1) - elif self.funcs == 'cos': - x = torch.cos(x) - elif self.funcs == 'sin': - x = torch.sin(x) - return x diff --git a/massspecgym/models/encoders/dreams/layers.py b/massspecgym/models/encoders/dreams/layers.py deleted file mode 100644 index e896f04..0000000 --- a/massspecgym/models/encoders/dreams/layers.py +++ /dev/null @@ -1,216 +0,0 @@ -""" -DreaMS transformer encoder layers. - -Ported from external/DreaMS/dreams/models/dreams/layers.py. -Includes custom MultiheadAttention with optional Graphormer m/z bias, -ScaleNorm, and TransformerEncoder with gradient checkpointing. -""" - -import torch -import torch.nn as nn -import torch.nn.functional as F -from torch.nn import Parameter - - -class ScaleNorm(nn.Module): - """Scale normalization (Nguyen & Salazar, 2019).""" - - def __init__(self, scale, eps=1e-5): - super().__init__() - self.scale = Parameter(torch.tensor(float(scale))) - self.eps = eps - - def forward(self, x): - norm = self.scale / torch.norm(x, dim=-1, keepdim=True).clamp(min=self.eps) - return x * norm - - -class MultiheadAttention(nn.Module): - """Multi-head attention with optional Graphormer m/z distance bias. - - Args: - args: Namespace with d_model, n_heads, att_dropout, no_transformer_bias, - attn_mech, d_graphormer_params. - """ - - def __init__(self, args): - super().__init__() - self.d_model = args.d_model - self.n_heads = args.n_heads - self.dropout = getattr(args, 'att_dropout', getattr(args, 'dropout', 0.0)) - self.use_transformer_bias = not getattr(args, 'no_transformer_bias', False) - self.attn_mech = getattr(args, 'attn_mech', 'dot-product') - self.d_graphormer_params = getattr(args, 'd_graphormer_params', 0) - - assert self.d_model % self.n_heads == 0 - self.head_dim = self.d_model // self.n_heads - self.scale = self.head_dim ** -0.5 - - self.weights = Parameter(torch.Tensor(4 * self.d_model, self.d_model)) - if self.use_transformer_bias: - self.biases = Parameter(torch.Tensor(4 * self.d_model)) - - if self.d_graphormer_params: - self.lin_graphormer = nn.Linear(self.d_graphormer_params, self.n_heads, bias=False) - - mean, std = 0, (2 / (5 * self.d_model)) ** 0.5 - nn.init.normal_(self.weights, mean=mean, std=std) - if self.use_transformer_bias: - nn.init.constant_(self.biases, 0.) - - if self.attn_mech == 'additive_v': - self.additive_v = Parameter(torch.Tensor(self.n_heads, self.head_dim)) - nn.init.normal_(self.additive_v, mean=mean, std=std) - - def proj_qkv(self, q, k, v): - w_q, w_k, w_v, w_o = self.weights.chunk(4, dim=0) - if self.use_transformer_bias: - b_q, b_k, b_v, b_o = self.biases.chunk(4, dim=0) - q = F.linear(q, w_q, b_q) - k = F.linear(k, w_k, b_k) - v = F.linear(v, w_v, b_v) - else: - q = F.linear(q, w_q) - k = F.linear(k, w_k) - v = F.linear(v, w_v) - return q, k, v - - def proj_o(self, x): - w_q, w_k, w_v, w_o = self.weights.chunk(4, dim=0) - if self.use_transformer_bias: - b_q, b_k, b_v, b_o = self.biases.chunk(4, dim=0) - return F.linear(x, w_o, b_o) - return F.linear(x, w_o) - - def forward(self, q, k, v, mask, graphormer_dists=None, do_proj_qkv=True): - bs, n, d = q.size() - - def _split_heads(tensor): - return tensor.reshape(bs, n, self.n_heads, self.head_dim).transpose(1, 2) - - if do_proj_qkv: - q, k, v = self.proj_qkv(q, k, v) - q, k, v = _split_heads(q), _split_heads(k), _split_heads(v) - - if self.attn_mech == 'dot-product': - att_weights = torch.einsum('bhnd,bhdm->bhnm', q, k.transpose(-2, -1)) - elif self.attn_mech in ('additive_v', 'additive_fixed'): - att_weights = (q.unsqueeze(-2) - k.unsqueeze(-3)) - if self.attn_mech == 'additive_v': - att_weights = att_weights * self.additive_v[None, :, None, None, :] - att_weights = att_weights.sum(dim=-1) - else: - raise NotImplementedError(f'"{self.attn_mech}" not implemented') - - att_weights = att_weights * self.scale - - if graphormer_dists is not None: - if self.d_graphormer_params: - att_bias = self.lin_graphormer(graphormer_dists).permute(0, 3, 1, 2) - else: - att_bias = graphormer_dists.sum(dim=-1).unsqueeze(1) - att_weights = att_weights + att_bias - - if mask is not None: - att_weights.masked_fill_(mask.unsqueeze(1).unsqueeze(-1), -1e9) - - att_weights = F.softmax(att_weights, dim=-1) - att_weights = F.dropout(att_weights, p=self.dropout, training=self.training) - - _att = att_weights.reshape(-1, n, n) - output = torch.bmm(_att, v.reshape(bs * self.n_heads, -1, self.head_dim)) - output = output.reshape(bs, self.n_heads, n, self.head_dim).transpose(1, 2).reshape(bs, n, -1) - output = self.proj_o(output) - - return output, att_weights - - -class TransformerFeedForward(nn.Module): - """Feed-forward block inside transformer layer.""" - - def __init__(self, args): - super().__init__() - self.dropout = getattr(args, 'ff_dropout', getattr(args, 'dropout', 0.0)) - self.d_model = args.d_model - self.ff_dim = 4 * args.d_model - use_bias = not getattr(args, 'no_transformer_bias', False) - self.in_proj = nn.Linear(self.d_model, self.ff_dim, bias=use_bias) - self.out_proj = nn.Linear(self.ff_dim, self.d_model, bias=use_bias) - - std = (2 / (self.ff_dim + self.d_model)) ** 0.5 - nn.init.normal_(self.in_proj.weight, mean=0, std=std) - nn.init.normal_(self.out_proj.weight, mean=0, std=std) - if use_bias: - nn.init.constant_(self.in_proj.bias, 0.) - nn.init.constant_(self.out_proj.bias, 0.) - - def forward(self, x): - y = F.relu(self.in_proj(x)) - y = F.dropout(y, p=self.dropout, training=self.training) - return self.out_proj(y) - - -class TransformerEncoder(nn.Module): - """DreaMS transformer encoder with ScaleNorm and optional Graphormer bias. - - Args: - args: Namespace with n_layers, d_model, pre_norm, scnorm, - residual_dropout, and attention/FF config. - """ - - def __init__(self, args): - super().__init__() - self.residual_dropout = getattr(args, 'residual_dropout', getattr(args, 'dropout', 0.0)) - self.n_layers = args.n_layers - self.pre_norm = getattr(args, 'pre_norm', True) - self._gradient_checkpointing = False - - self.atts = nn.ModuleList([MultiheadAttention(args) for _ in range(self.n_layers)]) - self.ffs = nn.ModuleList([TransformerFeedForward(args) for _ in range(self.n_layers)]) - - num_scales = self.n_layers * 2 + 1 if self.pre_norm else self.n_layers * 2 - if getattr(args, 'scnorm', True): - self.scales = nn.ModuleList([ScaleNorm(args.d_model ** 0.5) for _ in range(num_scales)]) - else: - self.scales = nn.ModuleList([nn.LayerNorm(args.d_model) for _ in range(num_scales)]) - - def _layer_forward(self, i, x, src_mask, graphormer_dists): - if self.pre_norm: - residual = x - x = self.scales[2 * i](x) - x, _ = self.atts[i](x, x, x, src_mask, graphormer_dists) - x = F.dropout(x, p=self.residual_dropout, training=self.training) - x = residual + x - - residual = x - x = self.scales[2 * i + 1](x) - x = self.ffs[i](x) - x = F.dropout(x, p=self.residual_dropout, training=self.training) - x = residual + x - else: - residual = x - x, _ = self.atts[i](x, x, x, src_mask, graphormer_dists) - x = F.dropout(x, p=self.residual_dropout, training=self.training) - x = self.scales[2 * i](residual + x) - - residual = x - x = self.ffs[i](x) - x = F.dropout(x, p=self.residual_dropout, training=self.training) - x = self.scales[2 * i + 1](residual + x) - - return x - - def forward(self, src_inputs, src_mask, graphormer_dists=None): - x = F.dropout(src_inputs, p=self.residual_dropout, training=self.training) - for i in range(self.n_layers): - if self._gradient_checkpointing and self.training: - x = torch.utils.checkpoint.checkpoint( - self._layer_forward, i, x, src_mask, graphormer_dists, - use_reentrant=False - ) - else: - x = self._layer_forward(i, x, src_mask, graphormer_dists) - - if self.pre_norm: - x = self.scales[-1](x) - return x diff --git a/massspecgym/models/encoders/dreams/model.py b/massspecgym/models/encoders/dreams/model.py deleted file mode 100644 index f9ae38d..0000000 --- a/massspecgym/models/encoders/dreams/model.py +++ /dev/null @@ -1,186 +0,0 @@ -""" -DreaMS model: BERT-style MS/MS spectrum encoder. - -Ported from external/DreaMS/dreams/models/dreams/dreams.py. -Preserves the exact args-based config for checkpoint compatibility. - -The model encodes MS/MS spectra as sequences of (m/z, intensity) tokens, -using Fourier features for m/z encoding and a transformer encoder. -Output: per-token embeddings of dimension d_model (typically 1024). -""" - -from argparse import Namespace -from typing import Optional - -import torch -import torch.nn as nn -import pytorch_lightning as pl - -from .fourier_features import FourierFeatures -from .feed_forward import FeedForward -from .layers import TransformerEncoder - - -class DreaMS(pl.LightningModule): - """DreaMS spectrum encoder model. - - BERT-style transformer that encodes MS/MS spectra into dense embeddings. - The precursor m/z is prepended as the first token; its embedding serves - as the spectrum-level representation. - - Args: - args: Namespace with model configuration. Key fields: - d_fourier (int): Fourier feature dimension (default 512). - d_peak (int): Peak embedding dimension (default 512). - d_mz_token (int): Discrete m/z token dimension (default 0). - n_layers (int): Number of transformer layers. - n_heads (int): Number of attention heads. - dropout (float): Dropout rate. - fourier_strategy (str): Fourier frequency strategy. - fourier_num_freqs (int): Number of Fourier frequencies. - charge_feature (bool): Whether to include charge as feature. - graphormer_mz_diffs (bool): Use Graphormer m/z distance bias. - vanilla_transformer (bool): Use standard PyTorch transformer. - spec_preproc: SpectrumPreprocessor instance. - """ - - def __init__(self, args: Namespace, spec_preproc=None): - super().__init__() - self.save_hyperparameters() - - self.spec_preproc = spec_preproc - self.n_layers = args.n_layers - self.n_heads = args.n_heads - self.lr = getattr(args, 'lr', 1e-4) - self.weight_decay = getattr(args, 'weight_decay', 0.0) - self.charge_feature = getattr(args, 'charge_feature', False) - self.d_fourier = getattr(args, 'd_fourier', 512) - self.d_peak = getattr(args, 'd_peak', 512) - self.d_mz_token = getattr(args, 'd_mz_token', 0) - self.d_model = sum(d for d in [self.d_fourier, self.d_peak, self.d_mz_token] if d) - args.d_model = self.d_model - self.dformat = getattr(args, 'dformat', None) - self.hot_mz_bin_size = getattr(args, 'hot_mz_bin_size', 1.0) - self.graphormer_mz_diffs = getattr(args, 'graphormer_mz_diffs', False) - self.graphormer_parametrized = getattr(args, 'graphormer_parametrized', False) - self.mask_val = getattr(args, 'mask_val', -1.0) - self.vanilla_transformer = getattr(args, 'vanilla_transformer', False) - - if self.graphormer_mz_diffs and self.graphormer_parametrized: - args.d_graphormer_params = self.d_fourier if self.d_fourier else 1 - else: - args.d_graphormer_params = 0 - - token_dim = 2 - if self.charge_feature: - token_dim += 1 - - if self.d_fourier: - max_mz = self.dformat.max_mz if self.dformat else 1000.0 - x_min = getattr(self.dformat, 'max_tbxic_stdev', 0.003) if self.dformat else 0.003 - fourier_min_freq = getattr(args, 'fourier_min_freq', None) - if fourier_min_freq: - x_min = fourier_min_freq - - self.fourier_enc = FourierFeatures( - strategy=getattr(args, 'fourier_strategy', 'voronov_et_al'), - num_freqs=getattr(args, 'fourier_num_freqs', 512), - x_min=x_min, - x_max=max_mz, - trainable=getattr(args, 'fourier_trainable', True), - ) - self.ff_fourier = FeedForward( - in_dim=self.fourier_enc.num_features(), - out_dim=self.d_fourier, - dropout=getattr(args, 'dropout', 0.0), - depth=getattr(args, 'ff_fourier_depth', 2), - hidden_dim=getattr(args, 'ff_fourier_d', self.d_fourier), - bias=not getattr(args, 'no_ffs_bias', False), - ) - - elif self.d_mz_token: - max_mz = self.dformat.max_mz if self.dformat else 1000.0 - num_bins = int(max_mz / self.hot_mz_bin_size) + 2 - self.mz_tokenizer = nn.Embedding(num_bins, self.d_mz_token, padding_idx=0) - self.ff_mz_token = FeedForward( - in_dim=self.d_mz_token, hidden_dim=self.d_mz_token, - out_dim=self.d_mz_token, depth=2, - dropout=getattr(args, 'dropout', 0.0), - ) - - self.ff_peak = FeedForward( - in_dim=token_dim, - hidden_dim=self.d_peak, - out_dim=self.d_peak, - depth=getattr(args, 'ff_peak_depth', 2), - dropout=getattr(args, 'dropout', 0.0), - bias=not getattr(args, 'no_ffs_bias', False), - ) - - if self.vanilla_transformer: - encoder_layer = nn.TransformerEncoderLayer( - d_model=self.d_model, dim_feedforward=self.d_model * 4, - nhead=self.n_heads, activation='gelu', - dropout=getattr(args, 'dropout', 0.0), - batch_first=True, norm_first=True, - ) - self.transformer_encoder = nn.TransformerEncoder( - encoder_layer, num_layers=self.n_layers - ) - else: - self.transformer_encoder = TransformerEncoder(args) - - def forward(self, spec, charge=None): - """Encode a batch of MS/MS spectra. - - Args: - spec: Tensor of shape (batch, n_peaks, 2) with [m/z, intensity]. - First peak is the precursor. - charge: Optional tensor of shape (batch,) with charge values. - - Returns: - Tensor of shape (batch, n_peaks, d_model) with per-token embeddings. - """ - padding_mask = spec[:, :, 0] == 0 - - if self.charge_feature: - if charge is None: - raise ValueError("charge required when charge_feature=True") - charge_features = ~padding_mask * charge.unsqueeze(-1) - spec = torch.cat([spec, charge_features.unsqueeze(-1)], dim=-1) - - normalized_spec = spec.clone() - max_mz = self.dformat.max_mz if self.dformat else 1000.0 - normalized_spec[..., 0] = normalized_spec[..., 0] / max_mz - - peak_embs = self.ff_peak(normalized_spec) - - if self.d_fourier: - fourier_features = self.ff_fourier(self.fourier_enc(spec[..., [0]])) - spec_embs = torch.cat([peak_embs, fourier_features], dim=-1) - elif self.d_mz_token: - mz_bins = (spec[..., 0] / self.hot_mz_bin_size).long().clamp(min=0) - tokenized_mzs = self.ff_mz_token(self.mz_tokenizer(mz_bins)) - spec_embs = torch.cat([peak_embs, tokenized_mzs], dim=-1) - else: - spec_embs = peak_embs - - graphormer_dists = None - if self.graphormer_mz_diffs: - if self.d_fourier: - graphormer_dists = fourier_features.unsqueeze(2) - fourier_features.unsqueeze(1) - else: - mz_vals = spec[..., 0] - graphormer_dists = (mz_vals.unsqueeze(2) - mz_vals.unsqueeze(1)).unsqueeze(-1) - - if self.vanilla_transformer: - output = self.transformer_encoder(spec_embs, src_key_padding_mask=padding_mask) - else: - output = self.transformer_encoder(spec_embs, padding_mask, graphormer_dists) - - return output - - def configure_optimizers(self): - return torch.optim.AdamW( - self.parameters(), lr=self.lr, weight_decay=self.weight_decay - ) diff --git a/massspecgym/models/encoders/dreams/preprocessing.py b/massspecgym/models/encoders/dreams/preprocessing.py deleted file mode 100644 index 49760c6..0000000 --- a/massspecgym/models/encoders/dreams/preprocessing.py +++ /dev/null @@ -1,90 +0,0 @@ -""" -Spectrum preprocessing for DreaMS input. - -Ported from external/DreaMS/dreams/utils/data.py (SpectrumPreprocessor) -and external/DreaMS/dreams/utils/dformats.py (DataFormatA). -""" - -from dataclasses import dataclass -from typing import Optional - -import numpy as np - - -@dataclass -class DataFormatA: - """Default data format constraints for DreaMS.""" - min_peaks_n: int = 3 - max_peaks_n: int = 128 - max_mz: float = 1000.0 - max_prec_mz: float = 1000.0 - charge: int = 1 - max_tbxic_stdev: float = 0.003 - - -class SpectrumPreprocessor: - """Preprocess raw spectra for DreaMS model input. - - Performs: top-k peak selection, intensity normalization, precursor prepend, - and padding to fixed length. - - Args: - dformat: Data format constraints (DataFormatA). - n_highest_peaks: Number of highest-intensity peaks to retain. - prec_intens: Intensity value for the prepended precursor peak. - """ - - def __init__(self, dformat=None, n_highest_peaks=100, prec_intens=1.1): - self.dformat = dformat or DataFormatA() - self.n_highest_peaks = n_highest_peaks - self.prec_intens = prec_intens - - def __call__( - self, - mzs: np.ndarray, - intensities: np.ndarray, - precursor_mz: float, - ) -> np.ndarray: - """Preprocess a single spectrum for DreaMS input. - - Args: - mzs: Array of m/z values. - intensities: Array of intensity values. - precursor_mz: Precursor m/z value. - - Returns: - Array of shape (n_highest_peaks + 1, 2) with [m/z, intensity]. - First row is the precursor; padded positions have zeros. - """ - mzs = np.asarray(mzs, dtype=np.float32) - intensities = np.asarray(intensities, dtype=np.float32) - - if len(mzs) == 0: - result = np.zeros((self.n_highest_peaks + 1, 2), dtype=np.float32) - result[0] = [precursor_mz, self.prec_intens] - return result - - max_int = intensities.max() - if max_int > 0: - intensities = intensities / max_int - - valid = (mzs > 0) & (mzs <= self.dformat.max_mz) - mzs = mzs[valid] - intensities = intensities[valid] - - if len(mzs) > self.n_highest_peaks: - top_idx = np.argsort(intensities)[::-1][:self.n_highest_peaks] - mzs = mzs[top_idx] - intensities = intensities[top_idx] - - sort_idx = np.argsort(mzs) - mzs = mzs[sort_idx] - intensities = intensities[sort_idx] - - n_peaks = len(mzs) - result = np.zeros((self.n_highest_peaks + 1, 2), dtype=np.float32) - result[0] = [precursor_mz, self.prec_intens] - result[1:n_peaks + 1, 0] = mzs - result[1:n_peaks + 1, 1] = intensities - - return result diff --git a/massspecgym/models/encoders/mist/__init__.py b/massspecgym/models/encoders/mist/__init__.py deleted file mode 100644 index f1bb251..0000000 --- a/massspecgym/models/encoders/mist/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -""" -MIST (Mass Spectrometry Transformer) encoder for spectrum-to-fingerprint prediction. - -Ported from Goldman et al., "Annotating metabolite mass spectra with domain-inspired -chemical formula transformers", Nature Machine Intelligence, 2023. - -The encoder predicts molecular fingerprints from tandem mass spectra using a -FormulaTransformer backbone with progressive fingerprint refinement. -""" - -from .encoder import SpectraEncoder, SpectraEncoderGrowing -from .chem_constants import ( - VALID_ELEMENTS, - NORM_VEC, - formula_to_dense, - vec_to_formula, - get_all_subsets, - get_all_subsets_dense, - rdbe_filter, - cross_sum, - clipped_ppm, - ion_to_mass, - ION_LST, -) diff --git a/massspecgym/models/encoders/mist/chem_constants.py b/massspecgym/models/encoders/mist/chem_constants.py deleted file mode 100644 index 9352506..0000000 --- a/massspecgym/models/encoders/mist/chem_constants.py +++ /dev/null @@ -1,232 +0,0 @@ -""" -Chemistry constants and utilities for the MIST encoder. - -Extracted from the original MIST chem_utils.py to be self-contained within -MassSpecGym without external dependencies on the full MIST package. - -Includes subformulae assignment utilities (get_all_subsets, rdbe_filter, etc.) -ported from external/mist/src/mist/utils/chem_utils.py. -""" - -import re -from collections import defaultdict -from functools import reduce - -import numpy as np -import torch -from rdkit import Chem -from rdkit.Chem import Atom - -P_TBL = Chem.GetPeriodicTable() - -CHEM_FORMULA_SIZE = "([A-Z][a-z]*)([0-9]*)" - -VALID_ELEMENTS = [ - "C", "H", "As", "B", "Br", "Cl", "Co", "F", "Fe", "I", - "K", "N", "Na", "O", "P", "S", "Se", "Si", -] -VALID_ATOM_NUM = [Atom(i).GetAtomicNum() for i in VALID_ELEMENTS] -CHEM_ELEMENT_NUM = len(VALID_ELEMENTS) - -ATOM_NUM_TO_ONEHOT = torch.zeros((max(VALID_ATOM_NUM) + 1, CHEM_ELEMENT_NUM)) -ATOM_NUM_TO_ONEHOT[VALID_ATOM_NUM, torch.arange(CHEM_ELEMENT_NUM)] = 1 - -VALID_MONO_MASSES = np.array( - [P_TBL.GetMostCommonIsotopeMass(i) for i in VALID_ELEMENTS] -) -CHEM_MASSES = VALID_MONO_MASSES[:, None] - -ELEMENT_VECTORS = np.eye(len(VALID_ELEMENTS)) -ELEMENT_VECTORS_MASS = np.hstack([ELEMENT_VECTORS, CHEM_MASSES]) -ELEMENT_TO_MASS = dict(zip(VALID_ELEMENTS, CHEM_MASSES.squeeze())) - -# Reasonable normalization vector for elements (estimated by max counts + 1 when zero) -NORM_VEC = np.array([81, 158, 2, 1, 3, 10, 1, 17, 1, 6, 1, 19, 2, 34, 6, 6, 2, 6]) - -element_to_ind = dict(zip(VALID_ELEMENTS, np.arange(len(VALID_ELEMENTS)))) -element_to_position = dict(zip(VALID_ELEMENTS, ELEMENT_VECTORS)) - -ELECTRON_MASS = 0.00054858 - -ION_LST = [ - "[M+H]+", "[M+Na]+", "[M+K]+", "[M-H2O+H]+", - "[M+H3N+H]+", "[M]+", "[M-H4O2+H]+", -] - -ion_remap = dict(zip(ION_LST, ION_LST)) -ion_remap.update({ - "[M+NH4]+": "[M+H3N+H]+", - "M+H": "[M+H]+", - "M+Na": "[M+Na]+", - "M+H-H2O": "[M-H2O+H]+", - "M-H2O+H": "[M-H2O+H]+", - "M+NH4": "[M+H3N+H]+", - "M-2H2O+H": "[M-H4O2+H]+", - "[M-2H2O+H]+": "[M-H4O2+H]+", -}) - -ion_to_idx = dict(zip(ION_LST, np.arange(len(ION_LST)))) - -ion_to_mass = { - "[M+H]+": ELEMENT_TO_MASS["H"] - ELECTRON_MASS, - "[M+Na]+": ELEMENT_TO_MASS["Na"] - ELECTRON_MASS, - "[M+K]+": ELEMENT_TO_MASS["K"] - ELECTRON_MASS, - "[M-H2O+H]+": -ELEMENT_TO_MASS["O"] - ELEMENT_TO_MASS["H"] - ELECTRON_MASS, - "[M+H3N+H]+": ELEMENT_TO_MASS["N"] + ELEMENT_TO_MASS["H"] * 4 - ELECTRON_MASS, - "[M]+": 0 - ELECTRON_MASS, - "[M-H4O2+H]+": -ELEMENT_TO_MASS["O"] * 2 - ELEMENT_TO_MASS["H"] * 3 - ELECTRON_MASS, -} - -ion_to_add_vec = { - "[M+H]+": element_to_position["H"], - "[M+Na]+": element_to_position["Na"], - "[M+K]+": element_to_position["K"], - "[M-H2O+H]+": -element_to_position["O"] - element_to_position["H"], - "[M+H3N+H]+": element_to_position["N"] + element_to_position["H"] * 4, - "[M]+": np.zeros_like(element_to_position["H"]), - "[M-H4O2+H]+": -element_to_position["O"] * 2 - element_to_position["H"] * 3, -} - -instrument_to_type = defaultdict(lambda: "unknown") -instrument_to_type.update({ - "Thermo Finnigan Velos Orbitrap": "orbitrap", - "Thermo Finnigan Elite Orbitrap": "orbitrap", - "Orbitrap Fusion Lumos": "orbitrap", - "Q-ToF (LCMS)": "qtof", - "Unknown (LCMS)": "unknown", - "ion trap": "iontrap", - "FTICR (LCMS)": "fticr", - "Bruker Q-ToF (LCMS)": "qtof", - "Orbitrap (LCMS)": "orbitrap", -}) - -instruments = sorted(list(set(instrument_to_type.values()))) -max_instr_idx = len(instruments) + 1 -instrument_to_idx = dict(zip(instruments, np.arange(len(instruments)))) - - -def formula_to_dense(chem_formula: str) -> np.ndarray: - """Convert chemical formula string to dense element-count vector.""" - total_onehot = [] - for (chem_symbol, num) in re.findall(CHEM_FORMULA_SIZE, chem_formula): - num = 1 if num == "" else int(num) - one_hot = element_to_position[chem_symbol].reshape(1, -1) - one_hot_repeats = np.repeat(one_hot, repeats=num, axis=0) - total_onehot.append(one_hot_repeats) - - if len(total_onehot) == 0: - return np.zeros(len(element_to_position)) - return np.vstack(total_onehot).sum(0) - - -def vec_to_formula(form_vec) -> str: - """Convert dense element-count vector back to formula string.""" - build_str = "" - for i in np.argwhere(form_vec > 0).flatten(): - el = VALID_ELEMENTS[i] - ct = int(form_vec[i]) - build_str += f"{el}{ct}" if ct > 1 else f"{el}" - return build_str - - -def standardize_form(formula: str) -> str: - """Standardize chemical formula to canonical form.""" - return vec_to_formula(formula_to_dense(formula)) - - -def standardize_adduct(adduct: str) -> str: - """Standardize adduct notation.""" - adduct = adduct.replace(" ", "") - adduct = ion_remap.get(adduct, adduct) - if adduct not in ION_LST: - raise ValueError(f"Adduct {adduct} not in ION_LST") - return adduct - - -def get_ion_idx(ionization: str) -> int: - """Map ionization string to index.""" - return ion_to_idx[ionization] - - -def get_instr_idx(instrument: str) -> int: - """Map instrument string to index.""" - inst = instrument_to_type.get(instrument, "unknown") - return instrument_to_idx[inst] - - -# --- Subformulae assignment utilities --- -# Ported verbatim from external/mist/src/mist/utils/chem_utils.py - -# RDBE multiplier vector: 2*C + N + P - H - Cl - Br - I - F -rdbe_mult = np.zeros_like(ELEMENT_VECTORS[0]) -_rdbe_els = ["C", "N", "P", "H", "Cl", "Br", "I", "F"] -_rdbe_weights = [2, 1, 1, -1, -1, -1, -1, -1] -for _k, _v in zip(_rdbe_els, _rdbe_weights): - if _k in element_to_ind: - rdbe_mult[element_to_ind[_k]] = _v - - -def cross_sum(x, y): - """Compute cross sum of two arrays for combinatorial enumeration.""" - return (np.expand_dims(x, 0) + np.expand_dims(y, 1)).reshape(-1, y.shape[-1]) - - -def rdbe_filter(cross_prod): - """Filter formula vectors by ring and double bond equivalent (RDBE >= 0).""" - rdbe_total = 1 + 0.5 * cross_prod.dot(rdbe_mult) - return np.argwhere(rdbe_total >= 0).flatten() - - -def get_all_subsets_dense(dense_formula, element_vectors): - """Enumerate all valid subformulae from a dense formula vector. - - Args: - dense_formula: Element count vector (e.g., from formula_to_dense). - element_vectors: Basis vectors for elements (ELEMENT_VECTORS). - - Returns: - Tuple of (cross_prod, all_masses): formula vectors and monoisotopic masses. - """ - non_zero = np.argwhere(dense_formula > 0).flatten() - - vectorized_formula = [] - for nonzero_ind in non_zero: - temp = element_vectors[nonzero_ind] * np.arange( - 0, dense_formula[nonzero_ind] + 1 - ).reshape(-1, 1) - vectorized_formula.append(temp) - - zero_vec = np.zeros((1, element_vectors.shape[-1])) - cross_prod = reduce(cross_sum, vectorized_formula, zero_vec) - - cross_prod_inds = rdbe_filter(cross_prod) - cross_prod = cross_prod[cross_prod_inds] - all_masses = cross_prod.dot(VALID_MONO_MASSES) - return cross_prod, all_masses - - -def get_all_subsets(chem_formula: str): - """Enumerate all valid subformulae from a chemical formula string. - - Returns: - Tuple of (cross_prod, all_masses). - """ - dense_formula = formula_to_dense(chem_formula) - return get_all_subsets_dense(dense_formula, element_vectors=ELEMENT_VECTORS) - - -def clipped_ppm(mass_diff, parentmass): - """Calculate ppm mass difference, clipping parent mass to minimum of 200 Da.""" - parentmass_copy = parentmass * 1 - if np.isscalar(parentmass_copy): - if parentmass_copy < 200: - parentmass_copy = 200 - else: - parentmass_copy[parentmass_copy < 200] = 200 - return mass_diff / parentmass_copy * 1e6 - - -def clipped_ppm_single(cls_mass_diff: float, parentmass: float) -> float: - """Calculate clipped ppm for a single value.""" - div_factor = 200 if parentmass < 200 else parentmass - return cls_mass_diff / div_factor * 1e6 diff --git a/massspecgym/models/encoders/mist/encoder.py b/massspecgym/models/encoders/mist/encoder.py deleted file mode 100644 index e7cbab6..0000000 --- a/massspecgym/models/encoders/mist/encoder.py +++ /dev/null @@ -1,171 +0,0 @@ -""" -MIST Spectra Encoder for mass spectrometry to fingerprint prediction. - -Ported from Goldman et al., "Annotating metabolite mass spectra with domain-inspired -chemical formula transformers", Nature Machine Intelligence, 2023. - -Two variants: -- SpectraEncoder: Standard encoder with direct MLP prediction head. -- SpectraEncoderGrowing: Encoder with progressive fingerprint refinement (FPGrowingModule). -""" - -from typing import Tuple - -import torch -from torch import nn - -from . import modules - - -class SpectraEncoder(nn.Module): - """Standard spectra encoder for fingerprint prediction. - - Encodes mass spectrometry data into molecular fingerprints using - a FormulaTransformer backbone with MLP prediction heads. - - Args: - form_embedder: Type of formula embedding ("float", "pos-cos", etc.). - output_size: Output fingerprint dimension. - hidden_size: Hidden dimension size. - spectra_dropout: Dropout probability. - top_layers: Number of MLP layers in prediction heads. - refine_layers: Number of refinement layers (unused in this variant). - magma_modulo: Dimension for fragment prediction. - **kwargs: Additional arguments passed to FormulaTransformer. - """ - - def __init__( - self, - form_embedder: str = "float", - output_size: int = 4096, - hidden_size: int = 50, - spectra_dropout: float = 0.0, - top_layers: int = 1, - refine_layers: int = 0, - magma_modulo: int = 2048, - **kwargs, - ): - super().__init__() - - spectra_encoder_main = modules.FormulaTransformer( - hidden_size=hidden_size, - spectra_dropout=spectra_dropout, - form_embedder=form_embedder, - **kwargs, - ) - - fragment_pred_parts = [] - for _ in range(top_layers - 1): - fragment_pred_parts.append(nn.Linear(hidden_size, hidden_size)) - fragment_pred_parts.append(nn.ReLU()) - fragment_pred_parts.append(nn.Dropout(spectra_dropout)) - fragment_pred_parts.append(nn.Linear(hidden_size, magma_modulo)) - fragment_predictor = nn.Sequential(*fragment_pred_parts) - - top_layer_parts = [] - for _ in range(top_layers - 1): - top_layer_parts.append(nn.Linear(hidden_size, hidden_size)) - top_layer_parts.append(nn.ReLU()) - top_layer_parts.append(nn.Dropout(spectra_dropout)) - top_layer_parts.append(nn.Linear(hidden_size, output_size)) - top_layer_parts.append(nn.Sigmoid()) - spectra_predictor = nn.Sequential(*top_layer_parts) - - self.spectra_encoder = nn.ModuleList( - [spectra_encoder_main, fragment_predictor, spectra_predictor] - ) - - def forward(self, batch: dict) -> Tuple[torch.Tensor, dict]: - """Forward pass through the encoder. - - Args: - batch: Dictionary containing spectra data with keys: - num_peaks, types, instruments, ion_vec, form_vec, intens. - - Returns: - Tuple of (fingerprint [batch, output_size], aux_outputs dict). - """ - encoder_output, aux_out = self.spectra_encoder[0](batch, return_aux=True) - pred_frag_fps = self.spectra_encoder[1](aux_out["peak_tensor"]) - aux_outputs = {"pred_frag_fps": pred_frag_fps} - output = self.spectra_encoder[2](encoder_output) - aux_outputs["h0"] = encoder_output - return output, aux_outputs - - -class SpectraEncoderGrowing(nn.Module): - """Spectra encoder with progressive fingerprint refinement. - - Uses FPGrowingModule to progressively refine fingerprint predictions - from coarse to fine resolution, enabling multi-scale supervision. - - Args: - form_embedder: Type of formula embedding. - output_size: Final fingerprint dimension. - hidden_size: Hidden dimension size. - spectra_dropout: Dropout probability. - top_layers: Number of MLP layers in prediction heads. - refine_layers: Number of progressive refinement stages. - magma_modulo: Dimension for fragment prediction. - **kwargs: Additional arguments passed to FormulaTransformer. - """ - - def __init__( - self, - form_embedder: str = "float", - output_size: int = 4096, - hidden_size: int = 50, - spectra_dropout: float = 0.0, - top_layers: int = 1, - refine_layers: int = 0, - magma_modulo: int = 2048, - **kwargs, - ): - super().__init__() - - spectra_encoder_main = modules.FormulaTransformer( - hidden_size=hidden_size, - spectra_dropout=spectra_dropout, - form_embedder=form_embedder, - **kwargs, - ) - - fragment_pred_parts = [] - for _ in range(top_layers - 1): - fragment_pred_parts.append(nn.Linear(hidden_size, hidden_size)) - fragment_pred_parts.append(nn.ReLU()) - fragment_pred_parts.append(nn.Dropout(spectra_dropout)) - fragment_pred_parts.append(nn.Linear(hidden_size, magma_modulo)) - fragment_predictor = nn.Sequential(*fragment_pred_parts) - - spectra_predictor = modules.FPGrowingModule( - hidden_input_dim=hidden_size, - final_target_dim=output_size, - num_splits=refine_layers, - reduce_factor=2, - ) - - self.spectra_encoder = nn.ModuleList( - [spectra_encoder_main, fragment_predictor, spectra_predictor] - ) - - def forward(self, batch: dict) -> Tuple[torch.Tensor, dict]: - """Forward pass through the growing encoder. - - Args: - batch: Dictionary containing spectra data. - - Returns: - Tuple of (final fingerprint [batch, output_size], aux_outputs dict). - aux_outputs includes: pred_frag_fps, int_preds, h0. - """ - encoder_output, aux_out = self.spectra_encoder[0](batch, return_aux=True) - pred_frag_fps = self.spectra_encoder[1](aux_out["peak_tensor"]) - aux_outputs = {"pred_frag_fps": pred_frag_fps} - - output = self.spectra_encoder[2](encoder_output) - intermediates = output[:-1] - final_output = output[-1] - aux_outputs["int_preds"] = intermediates - aux_outputs["h0"] = encoder_output - return final_output, aux_outputs diff --git a/massspecgym/models/encoders/mist/form_embedders.py b/massspecgym/models/encoders/mist/form_embedders.py deleted file mode 100644 index c44a744..0000000 --- a/massspecgym/models/encoders/mist/form_embedders.py +++ /dev/null @@ -1,199 +0,0 @@ -""" -Formula embedders for encoding chemical formula counts in the MIST encoder. - -Each embedder maps integer atom counts to fixed-dimensional vector representations. -These are used by FormulaTransformer to encode peak formula annotations. -""" - -import numpy as np -import torch -import torch.nn as nn - -from .chem_constants import NORM_VEC - - -class IntFeaturizer(nn.Module): - """Base class for mapping integers to vector representations. - - Creates embeddings for integer values (typically atom counts in chemical formulas). - Subclasses define ``int_to_feat_matrix`` where each row is the vector for that integer. - """ - - MAX_COUNT_INT = 255 - NUM_EXTRA_EMBEDDINGS = 1 - - def __init__(self, embedding_dim): - super().__init__() - weights = torch.zeros(self.NUM_EXTRA_EMBEDDINGS, embedding_dim) - self._extra_embeddings = nn.Parameter(weights, requires_grad=True) - nn.init.normal_(self._extra_embeddings, 0.0, 1.0) - self.embedding_dim = embedding_dim - - def forward(self, tensor): - orig_shape = tensor.shape - out_tensor = torch.empty( - (*orig_shape, self.embedding_dim), device=tensor.device - ) - extra_embed = tensor >= self.MAX_COUNT_INT - - tensor = tensor.long() - norm_embeds = self.int_to_feat_matrix[tensor[~extra_embed]] - extra_embeds = self._extra_embeddings[tensor[extra_embed] - self.MAX_COUNT_INT] - - out_tensor[~extra_embed] = norm_embeds - out_tensor[extra_embed] = extra_embeds - return out_tensor.reshape(*orig_shape[:-1], -1) - - @property - def num_dim(self): - return self.int_to_feat_matrix.shape[1] - - @property - def full_dim(self): - return self.num_dim * NORM_VEC.shape[0] - - -class FourierFeaturizer(IntFeaturizer): - """Fourier feature embeddings using sin and cos functions.""" - - def __init__(self): - num_freqs = int(np.ceil(np.log2(self.MAX_COUNT_INT))) + 2 - freqs = 0.5 ** torch.arange(num_freqs, dtype=torch.float32) - freqs_time_2pi = 2 * np.pi * freqs - super().__init__(embedding_dim=2 * freqs_time_2pi.shape[0]) - - combo = ( - torch.arange(self.MAX_COUNT_INT, dtype=torch.float32)[:, None] - * freqs_time_2pi[None, :] - ) - all_features = torch.cat([torch.cos(combo), torch.sin(combo)], dim=1) - self.int_to_feat_matrix = nn.Parameter(all_features.float(), requires_grad=False) - - -class FourierFeaturizerSines(IntFeaturizer): - """Fourier features using only sine functions.""" - - def __init__(self): - num_freqs = int(np.ceil(np.log2(self.MAX_COUNT_INT))) + 2 - freqs = (0.5 ** torch.arange(num_freqs, dtype=torch.float32))[2:] - freqs_time_2pi = 2 * np.pi * freqs - super().__init__(embedding_dim=freqs_time_2pi.shape[0]) - - combo = ( - torch.arange(self.MAX_COUNT_INT, dtype=torch.float32)[:, None] - * freqs_time_2pi[None, :] - ) - self.int_to_feat_matrix = nn.Parameter(torch.sin(combo).float(), requires_grad=False) - - -class FourierFeaturizerAbsoluteSines(IntFeaturizer): - """Fourier features using absolute value of sine functions.""" - - def __init__(self): - num_freqs = int(np.ceil(np.log2(self.MAX_COUNT_INT))) + 2 - freqs = (0.5 ** torch.arange(num_freqs, dtype=torch.float32))[2:] - freqs_time_2pi = 2 * np.pi * freqs - super().__init__(embedding_dim=freqs_time_2pi.shape[0]) - - combo = ( - torch.arange(self.MAX_COUNT_INT, dtype=torch.float32)[:, None] - * freqs_time_2pi[None, :] - ) - self.int_to_feat_matrix = nn.Parameter( - torch.abs(torch.sin(combo)).float(), requires_grad=False - ) - - -class FourierFeaturizerPosCos(IntFeaturizer): - """Fourier features using positive cosine: (-cos(x) + 1), zero at x=0.""" - - def __init__(self, num_funcs=9): - self.num_funcs = num_funcs - max_freq = int(np.ceil(np.log2(self.MAX_COUNT_INT))) + 1 - freqs = 0.5 ** np.linspace(1, max_freq, num_funcs) - freqs_time_2pi = torch.from_numpy(2 * np.pi * freqs).float() - super().__init__(embedding_dim=freqs_time_2pi.shape[0]) - - combo = ( - torch.arange(self.MAX_COUNT_INT, dtype=torch.float32)[:, None] - * freqs_time_2pi[None, :] - ) - self.int_to_feat_matrix = nn.Parameter( - (-torch.cos(combo) + 1).float(), requires_grad=False - ) - - -class RBFFeaturizer(IntFeaturizer): - """Radial basis function embeddings.""" - - def __init__(self, num_funcs=32): - super().__init__(embedding_dim=num_funcs) - width = (self.MAX_COUNT_INT - 1) / num_funcs - centers = torch.linspace(0, self.MAX_COUNT_INT - 1, num_funcs) - pre_exp = ( - -0.5 - * ((torch.arange(self.MAX_COUNT_INT)[:, None] - centers[None, :]) / width) ** 2 - ) - self.int_to_feat_matrix = nn.Parameter(torch.exp(pre_exp).float(), requires_grad=False) - - -class OneHotFeaturizer(IntFeaturizer): - """One-hot encoding for integers.""" - - def __init__(self): - super().__init__(embedding_dim=self.MAX_COUNT_INT) - self.int_to_feat_matrix = nn.Parameter( - torch.eye(self.MAX_COUNT_INT).float(), requires_grad=False - ) - - -class LearnedFeaturizer(IntFeaturizer): - """Learned embeddings for integers.""" - - def __init__(self, feature_dim=32): - super().__init__(embedding_dim=feature_dim) - self.nn_embedder = nn.Embedding( - self.MAX_COUNT_INT + self.NUM_EXTRA_EMBEDDINGS, feature_dim - ) - self.int_to_feat_matrix = list(self.nn_embedder.parameters())[0] - - def forward(self, tensor): - orig_shape = tensor.shape - out_tensor = self.nn_embedder(tensor.long()) - return out_tensor.reshape(*orig_shape[:-1], -1) - - -class FloatFeaturizer(IntFeaturizer): - """Simple normalized float features (divide by per-element max count).""" - - def __init__(self): - super().__init__(embedding_dim=1) - self.norm_vec = nn.Parameter( - torch.from_numpy(NORM_VEC).float(), requires_grad=False - ) - - def forward(self, tensor): - tens_shape = tensor.shape - out_shape = [1] * (len(tens_shape) - 1) + [-1] - return tensor / self.norm_vec.reshape(*out_shape) - - @property - def num_dim(self): - return 1 - - -def get_embedder(embedder: str) -> IntFeaturizer: - """Get embedder instance by name.""" - registry = { - "fourier": FourierFeaturizer, - "rbf": RBFFeaturizer, - "one-hot": OneHotFeaturizer, - "learnt": LearnedFeaturizer, - "float": FloatFeaturizer, - "fourier-sines": FourierFeaturizerSines, - "abs-sines": FourierFeaturizerAbsoluteSines, - "pos-cos": FourierFeaturizerPosCos, - } - if embedder not in registry: - raise NotImplementedError(f"Unknown embedder type: {embedder}") - return registry[embedder]() diff --git a/massspecgym/models/encoders/mist/modules.py b/massspecgym/models/encoders/mist/modules.py deleted file mode 100644 index 9933ade..0000000 --- a/massspecgym/models/encoders/mist/modules.py +++ /dev/null @@ -1,347 +0,0 @@ -""" -Core modules for the MIST encoder: FormulaTransformer and FPGrowingModule. - -FormulaTransformer encodes MS/MS spectra using formula annotations and peak -intensities with transformer attention. FPGrowingModule progressively refines -fingerprint predictions from coarse to fine resolution. -""" - -import copy - -import numpy as np -import torch -from torch import nn - -from .chem_constants import max_instr_idx as MAX_INSTR_IDX -from . import transformer_layer, form_embedders - -EPS = 1e-9 - -NUM_INTEN_BINS = 9 # Bins for categorical intensity transform - - -def get_num_inten_feats(inten_transform: str) -> int: - """Get number of intensity features based on transform type. - - Must match reference MIST exactly for weight compatibility: - float/zero/log -> 1 feature; cat -> 10 features (one-hot over 10 bins). - """ - if inten_transform in ("float", "zero", "log"): - return 1 - elif inten_transform == "cat": - return 10 # matches reference: NUM_INTEN_BINS + 1 = 10 - else: - raise NotImplementedError(f"Unknown intensity transform: {inten_transform}") - - -class MLPBlocks(nn.Module): - """Multi-layer perceptron with dropout and ReLU activation. - - Args: - input_size: Input dimension. - hidden_size: Hidden dimension. - dropout: Dropout probability. - num_layers: Number of layers. - """ - - def __init__(self, input_size: int, hidden_size: int, dropout: float, num_layers: int): - super().__init__() - self.activation = nn.ReLU() - self.dropout_layer = nn.Dropout(p=dropout) - self.input_layer = nn.Linear(input_size, hidden_size) - middle_layer = nn.Linear(hidden_size, hidden_size) - self.layers = _get_clones(middle_layer, num_layers - 1) - - def forward(self, x): - output = self.input_layer(x) - output = self.dropout_layer(output) - output = self.activation(output) - for layer in self.layers: - output = layer(output) - output = self.dropout_layer(output) - output = self.activation(output) - return output - - -class FormulaTransformer(nn.Module): - """Transformer encoder for mass spectrometry peak formulas. - - Encodes MS/MS spectra using formula annotations and peak intensities - with transformer attention mechanism. - - Args: - hidden_size: Hidden dimension size. - peak_attn_layers: Number of transformer layers. - set_pooling: Pooling strategy ("intensity", "mean", "root", "cls"). - spectra_dropout: Dropout probability. - pairwise_featurization: Whether to use pairwise features. - num_heads: Number of attention heads. - output_size: Output dimension. - form_embedder: Formula embedding type. - embed_instrument: Whether to embed instrument type. - inten_transform: Intensity transformation type. - no_diffs: If True, don't use difference representations. - """ - - def __init__( - self, - hidden_size: int, - peak_attn_layers: int, - set_pooling: str = "intensity", - spectra_dropout: float = 0.1, - pairwise_featurization: bool = False, - num_heads: int = 8, - output_size: int = 2048, - form_embedder: str = "float", - embed_instrument: bool = False, - inten_transform: str = "float", - no_diffs: bool = False, - **kwargs - ): - super().__init__() - self.hidden_size = hidden_size - self.attn_heads = num_heads - self.dim_feedforward = self.hidden_size * 4 - self.spectra_dropout = spectra_dropout - self.set_pooling = set_pooling - self.output_size = output_size - self.no_diffs = no_diffs - - self.form_embedder = form_embedder - self.form_embedder_mod = form_embedders.get_embedder(self.form_embedder) - - self.embed_instrument = embed_instrument - self.instr_dim = MAX_INSTR_IDX - self.instrument_embedder = nn.Parameter(torch.eye(self.instr_dim)) - - self.inten_transform = inten_transform - self.num_inten_bins = NUM_INTEN_BINS # BUG FIX: was missing in original - self.inten_feats = get_num_inten_feats(self.inten_transform) - self.num_types = 4 - self.cls_type = 3 - - self.adduct_dim = 8 - - self.pairwise_featurization = pairwise_featurization - - self.formula_dim = self.form_embedder_mod.full_dim - self.input_dim = ( - self.formula_dim * 2 - + self.num_types - + self.instr_dim - + self.inten_feats - + self.adduct_dim - ) - - self.intermediate_layer = MLPBlocks( - input_size=self.input_dim, - hidden_size=self.hidden_size, - dropout=self.spectra_dropout, - num_layers=2, - ) - self.pairwise_featurizer = None - if self.pairwise_featurization: - self.pairwise_featurizer = MLPBlocks( - input_size=self.formula_dim, - hidden_size=self.hidden_size, - dropout=self.spectra_dropout, - num_layers=2, - ) - - peak_attn_layer = transformer_layer.TransformerEncoderLayer( - d_model=self.hidden_size, - nhead=self.attn_heads, - dim_feedforward=self.dim_feedforward, - dropout=self.spectra_dropout, - pairwise_featurization=pairwise_featurization, - ) - self.peak_attn_layers = _get_clones(peak_attn_layer, peak_attn_layers) - self.bin_encoder = None - - def forward(self, batch: dict, return_aux: bool = False): - """Forward pass through formula transformer. - - Args: - batch: Dictionary containing: - num_peaks, types, instruments, ion_vec, form_vec, intens - return_aux: Whether to return auxiliary outputs. - - Returns: - Output tensor, optionally with auxiliary dict. - """ - num_peaks = batch["num_peaks"] - peak_types = batch["types"] - instruments = batch["instruments"] - - device = num_peaks.device - batch_dim = num_peaks.shape[0] - peak_dim = peak_types.shape[-1] - adducts = batch["ion_vec"] - - cls_token_mask = peak_types == self.cls_type - - orig_form_vec = batch["form_vec"][:, :, :] - form_diffs = orig_form_vec[:, :, None, :] - orig_form_vec[:, None, :, :] - - abs_diffs = form_diffs[cls_token_mask] - form_vec = self.form_embedder_mod(orig_form_vec) - diff_vec = self.form_embedder_mod(abs_diffs) - - if self.no_diffs: - diff_vec = diff_vec.fill_(0) - - intens_temp = batch["intens"] - - if self.inten_transform == "cat": - inten_tensor = torch.eye(self.num_inten_bins + 1, device=device)[ - intens_temp.long() - ] - else: - inten_tensor = intens_temp[:, :, None] - - one_hot_types = nn.functional.one_hot(peak_types, self.num_types) - one_hot_adducts = nn.functional.one_hot(adducts.long(), self.adduct_dim) - - embedded_instruments = self.instrument_embedder[instruments.long()] - if self.embed_instrument: - embedded_instruments = embedded_instruments[:, None, :].repeat(1, peak_dim, 1) - else: - embedded_instruments = torch.zeros( - batch_dim, peak_dim, self.instr_dim, device=device - ) - - input_vec = torch.cat([ - form_vec, diff_vec, one_hot_types, one_hot_adducts, - inten_tensor, embedded_instruments, - ], dim=-1) - peak_tensor = self.intermediate_layer(input_vec) - - # Transpose to (Np, B, d) for transformer - peak_tensor = peak_tensor.transpose(0, 1) - peak_dim = peak_tensor.shape[0] - peaks_aranged = torch.arange(peak_dim, device=device) - attn_mask = ~(peaks_aranged[None, :] < num_peaks[:, None]) - - pairwise_features = None - if self.pairwise_featurization: - same_sign = torch.all(form_diffs >= 0, -1) | torch.all(form_diffs <= 0, -1) - form_diffs[~same_sign].fill_(0) - form_diffs = torch.abs(form_diffs) - pairwise_features = self.pairwise_featurizer( - self.form_embedder_mod(form_diffs) - ) - - aux_output = {} - for peak_attn_layer in self.peak_attn_layers: - peak_tensor, pairwise_features = peak_attn_layer( - peak_tensor, - pairwise_features=pairwise_features, - src_key_padding_mask=attn_mask, - ) - - output, peak_tensor = self._pool_out( - peak_tensor, inten_tensor, peak_types, attn_mask, batch_dim - ) - aux_output["peak_tensor"] = peak_tensor.transpose(0, 1) - - if return_aux: - return output, aux_output - return output - - def _pool_out(self, peak_tensor, inten_tensor, peak_types, attn_mask, batch_dim): - """Pool transformer outputs using the configured pooling strategy.""" - zero_mask = attn_mask[:, :, None].repeat(1, 1, self.hidden_size).transpose(0, 1) - peak_tensor[zero_mask] = 0 - - if self.set_pooling == "intensity": - inten_tensor = inten_tensor.reshape(batch_dim, -1) - intensities_sum = inten_tensor.sum(1).reshape(-1, 1) + EPS - inten_tensor = inten_tensor / intensities_sum - pool_factor = inten_tensor * ~attn_mask - elif self.set_pooling == "mean": - inten_tensor = inten_tensor.reshape(batch_dim, -1) - pool_factor = torch.clone(inten_tensor).fill_(1) - pool_factor = pool_factor * ~attn_mask - pool_factor[pool_factor == 0] = 1 - pool_factor = pool_factor / pool_factor.sum(1).reshape(-1, 1) - elif self.set_pooling == "root": - inten_tensor = inten_tensor.reshape(batch_dim, -1) - pool_factor = torch.zeros_like(inten_tensor) - pool_factor[:, 0] = 1 - elif self.set_pooling == "cls": - pool_factor = (peak_types == self.cls_type).float() - else: - raise NotImplementedError(f"Unknown pooling: {self.set_pooling}") - - output = torch.einsum("nbd,bn->bd", peak_tensor, pool_factor) - return output, peak_tensor - - -class FPGrowingModule(nn.Module): - """Progressive fingerprint prediction module. - - Grows fingerprint predictions from hidden dimension to final output - size through multiple refinement stages with gating. - - Args: - hidden_input_dim: Input hidden dimension. - final_target_dim: Final fingerprint dimension. - num_splits: Number of refinement stages. - reduce_factor: Factor by which to grow each stage. - """ - - def __init__( - self, - hidden_input_dim: int = 256, - final_target_dim: int = 4096, - num_splits: int = 4, - reduce_factor: int = 2, - ): - super().__init__() - self.hidden_input_dim = hidden_input_dim - self.final_target_dim = final_target_dim - self.num_splits = num_splits - self.reduce_factor = reduce_factor - - layer_dims = [ - int(np.ceil(final_target_dim / (reduce_factor ** num_split))) - for num_split in range(num_splits + 1) - ][::-1] - - self.output_dims = layer_dims - - self.initial_predict = nn.Sequential( - nn.Linear(hidden_input_dim, layer_dims[0]), - nn.Sigmoid(), - ) - predict_bricks = [] - gate_bricks = [] - for layer_dim_ind, layer_dim in enumerate(layer_dims[:-1]): - out_dim = layer_dims[layer_dim_ind + 1] - predict_bricks.append( - nn.Sequential(nn.Linear(layer_dim, out_dim), nn.Sigmoid()) - ) - gate_bricks.append( - nn.Sequential(nn.Linear(hidden_input_dim, out_dim), nn.Sigmoid()) - ) - - self.predict_bricks = nn.ModuleList(predict_bricks) - self.gate_bricks = nn.ModuleList(gate_bricks) - - def forward(self, hidden): - """Returns list of predictions at each resolution level.""" - cur_pred = self.initial_predict(hidden) - output_preds = [cur_pred] - for _out_dim, predict_brick, gate_brick in zip( - self.output_dims[1:], self.predict_bricks, self.gate_bricks - ): - gate_outs = gate_brick(hidden) - pred_out = predict_brick(cur_pred) - cur_pred = gate_outs * pred_out - output_preds.append(cur_pred) - return output_preds - - -def _get_clones(module, N): - """Create N deep copies of a module.""" - return nn.ModuleList([copy.deepcopy(module) for i in range(N)]) diff --git a/massspecgym/models/encoders/mist/transformer_layer.py b/massspecgym/models/encoders/mist/transformer_layer.py deleted file mode 100644 index 90f3d26..0000000 --- a/massspecgym/models/encoders/mist/transformer_layer.py +++ /dev/null @@ -1,336 +0,0 @@ -""" -Transformer layers with pairwise attention support for the MIST encoder. - -Provides a custom TransformerEncoderLayer and MultiheadAttention that support -pairwise featurization (attention bias from formula difference features). -""" - -import math -from typing import Optional, Union, Callable, Tuple - -import torch -from torch import Tensor -from torch.nn import functional as F -from torch.nn import Module, LayerNorm, Linear, Dropout, Parameter -from torch.nn.init import xavier_uniform_, constant_ -from torch.nn.modules.linear import NonDynamicallyQuantizableLinear - - -class TransformerEncoderLayer(Module): - """TransformerEncoderLayer with optional pairwise featurization. - - Args: - d_model: Number of expected features in the input. - nhead: Number of heads in the multiheadattention models. - dim_feedforward: Dimension of the feedforward network model. - dropout: Dropout value. - activation: Activation function of intermediate layer. - layer_norm_eps: Eps value in layer normalization components. - batch_first: If True, input/output tensors are (batch, seq, feature). - norm_first: If True, layer norm is done prior to attention. - additive_attn: If True, use additive attention instead of scaled dot product. - pairwise_featurization: If True, include pairwise features in attention. - """ - - __constants__ = ["batch_first", "norm_first"] - - def __init__( - self, - d_model: int, - nhead: int, - dim_feedforward: int = 2048, - dropout: float = 0.1, - activation: Union[str, Callable[[Tensor], Tensor]] = F.relu, - layer_norm_eps: float = 1e-5, - batch_first: bool = False, - norm_first: bool = False, - additive_attn: bool = False, - pairwise_featurization: bool = False, - device=None, - dtype=None, - ) -> None: - factory_kwargs = {"device": device, "dtype": dtype} - super().__init__() - self.pairwise_featurization = pairwise_featurization - self.self_attn = MultiheadAttention( - d_model, - nhead, - dropout=dropout, - batch_first=batch_first, - additive_attn=additive_attn, - pairwise_featurization=self.pairwise_featurization, - **factory_kwargs, - ) - self.linear1 = Linear(d_model, dim_feedforward, **factory_kwargs) - self.dropout = Dropout(dropout) - self.linear2 = Linear(dim_feedforward, d_model, **factory_kwargs) - - self.norm_first = norm_first - self.norm1 = LayerNorm(d_model, eps=layer_norm_eps, **factory_kwargs) - self.norm2 = LayerNorm(d_model, eps=layer_norm_eps, **factory_kwargs) - self.dropout1 = Dropout(dropout) - self.dropout2 = Dropout(dropout) - - self.activation = activation - - def __setstate__(self, state): - if "activation" not in state: - state["activation"] = F.relu - super().__setstate__(state) - - def forward( - self, - src: Tensor, - pairwise_features: Optional[Tensor] = None, - src_key_padding_mask: Optional[Tensor] = None, - ) -> Tuple[Tensor, Optional[Tensor]]: - x = src - if self.norm_first: - x = x + self._sa_block( - self.norm1(x), pairwise_features, src_key_padding_mask - ) - x = x + self._ff_block(self.norm2(x)) - else: - x = self.norm1( - x + self._sa_block(x, pairwise_features, src_key_padding_mask) - ) - x = self.norm2(x + self._ff_block(x)) - return x, pairwise_features - - def _sa_block(self, x, pairwise_features, key_padding_mask): - x = self.self_attn( - x, x, x, - key_padding_mask=key_padding_mask, - pairwise_features=pairwise_features, - )[0] - return self.dropout1(x) - - def _ff_block(self, x): - x = self.linear2(self.dropout(self.activation(self.linear1(x)))) - return self.dropout2(x) - - -class MultiheadAttention(Module): - """Multi-Head Attention with optional pairwise featurization. - - Args: - embed_dim: Total dimension of the model. - num_heads: Number of parallel attention heads. - additive_attn: If true, use additive attention. - dropout: Dropout probability on attention weights. - batch_first: If True, input/output tensors are (batch, seq, feature). - pairwise_featurization: If True, use pairwise featurization. - """ - - def __init__( - self, - embed_dim, - num_heads, - additive_attn=False, - pairwise_featurization: bool = False, - dropout=0.0, - batch_first=False, - device=None, - dtype=None, - ) -> None: - factory_kwargs = {"device": device, "dtype": dtype} - super().__init__() - - self.embed_dim = embed_dim - self.kdim = embed_dim - self.vdim = embed_dim - self._qkv_same_embed_dim = True - self.additive_attn = additive_attn - self.pairwise_featurization = pairwise_featurization - - self.num_heads = num_heads - self.dropout = dropout - self.batch_first = batch_first - self.head_dim = embed_dim // num_heads - assert self.head_dim * num_heads == self.embed_dim, \ - "embed_dim must be divisible by num_heads" - - if self.additive_attn: - head_1_input = ( - self.head_dim * 3 if self.pairwise_featurization else self.head_dim * 2 - ) - self.attn_weight_1_weight = Parameter( - torch.empty((self.num_heads, head_1_input, self.head_dim), **factory_kwargs) - ) - self.attn_weight_1_bias = Parameter( - torch.empty((self.num_heads, self.head_dim), **factory_kwargs) - ) - self.attn_weight_2_weight = Parameter( - torch.empty((self.num_heads, self.head_dim, 1), **factory_kwargs) - ) - self.attn_weight_2_bias = Parameter( - torch.empty((self.num_heads, 1), **factory_kwargs) - ) - else: - if self.pairwise_featurization: - self.bias_u = Parameter( - torch.empty((self.num_heads, self.head_dim), **factory_kwargs) - ) - self.bias_v = Parameter( - torch.empty((self.num_heads, self.head_dim), **factory_kwargs) - ) - - self.in_proj_weight = Parameter( - torch.empty((3 * embed_dim, embed_dim), **factory_kwargs) - ) - self.in_proj_bias = Parameter(torch.empty(3 * embed_dim, **factory_kwargs)) - self.out_proj = NonDynamicallyQuantizableLinear( - embed_dim, embed_dim, bias=True, **factory_kwargs - ) - self._reset_parameters() - - def _reset_parameters(self): - xavier_uniform_(self.in_proj_weight) - constant_(self.in_proj_bias, 0.0) - constant_(self.out_proj.bias, 0.0) - if self.additive_attn: - xavier_uniform_(self.attn_weight_1_weight) - xavier_uniform_(self.attn_weight_2_weight) - constant_(self.attn_weight_1_bias, 0.0) - constant_(self.attn_weight_2_bias, 0.0) - elif self.pairwise_featurization: - constant_(self.bias_u, 0.0) - constant_(self.bias_v, 0.0) - - def forward( - self, - query: Tensor, - key: Tensor, - value: Tensor, - key_padding_mask: Optional[Tensor] = None, - pairwise_features: Optional[Tensor] = None, - ) -> Tuple[Tensor, Optional[Tensor]]: - is_batched = query.dim() == 3 - if self.batch_first and is_batched: - query, key, value = [x.transpose(1, 0) for x in (query, key, value)] - - attn_output, attn_output_weights = self._multi_head_attention_forward( - query, key, value, - key_padding_mask=key_padding_mask, - pairwise_features=pairwise_features, - ) - - if self.batch_first and is_batched: - return attn_output.transpose(1, 0), attn_output_weights - return attn_output, attn_output_weights - - def _multi_head_attention_forward( - self, - query: Tensor, - key: Tensor, - value: Tensor, - key_padding_mask: Optional[Tensor] = None, - pairwise_features: Optional[Tensor] = None, - ) -> Tuple[Tensor, Optional[Tensor]]: - tgt_len, bsz, embed_dim = query.shape - num_heads = self.num_heads - head_dim = self.head_dim - - q, k, v = F.linear(query, self.in_proj_weight, self.in_proj_bias).chunk(3, dim=-1) - - q = q.contiguous().view(tgt_len, bsz * num_heads, head_dim).transpose(0, 1) - k = k.contiguous().view(k.shape[0], bsz * num_heads, head_dim).transpose(0, 1) - v = v.contiguous().view(v.shape[0], bsz * num_heads, head_dim).transpose(0, 1) - - if pairwise_features is not None: - pairwise_features = pairwise_features.permute(1, 2, 0, 3).contiguous() - pairwise_features = pairwise_features.view( - tgt_len, tgt_len, bsz * num_heads, head_dim - ) - pairwise_features = pairwise_features.permute(2, 0, 1, 3) - - src_len = k.size(1) - - attn_mask = None - if key_padding_mask is not None: - assert key_padding_mask.shape == (bsz, src_len) - key_padding_mask = ( - key_padding_mask.view(bsz, 1, 1, src_len) - .expand(-1, num_heads, -1, -1) - .reshape(bsz * num_heads, 1, src_len) - ) - attn_mask = key_padding_mask - assert attn_mask.dtype == torch.bool - - dropout_p = self.dropout if self.training else 0.0 - - if self.additive_attn: - attn_output, attn_weights = self._additive_attn( - q, k, v, attn_mask, dropout_p, pairwise_features - ) - else: - attn_output, attn_weights = self._scaled_dot_product_attention( - q, k, v, attn_mask, dropout_p, pairwise_features - ) - - attn_output = ( - attn_output.transpose(0, 1).contiguous().view(tgt_len * bsz, embed_dim) - ) - attn_output = F.linear(attn_output, self.out_proj.weight, self.out_proj.bias) - attn_output = attn_output.view(tgt_len, bsz, attn_output.size(1)) - - attn_weights = attn_weights.view(bsz, num_heads, tgt_len, src_len) - return attn_output, attn_weights - - def _additive_attn(self, q, k, v, attn_mask, dropout_p, pairwise_features=None): - B, Nt, E = q.shape - q_expand = q[:, :, None, :].expand(B, Nt, Nt, E) - v_expand = v[:, None, :, :].expand(B, Nt, Nt, E) - cat_ar = [q_expand, v_expand] - if pairwise_features is not None: - cat_ar.append(pairwise_features) - - output = torch.cat(cat_ar, -1) - E_long = E * len(cat_ar) - - output = output.view(-1, self.num_heads, Nt, Nt, E_long) - output = torch.einsum("bnlwe,neh->bnlwh", output, self.attn_weight_1_weight) - output = output + self.attn_weight_1_bias[None, :, None, None, :] - output = F.leaky_relu(output) - - attn = torch.einsum("bnlwh,nhi->bnlwi", output, self.attn_weight_2_weight) - attn = attn + self.attn_weight_2_bias[None, :, None, None, :] - attn = attn.contiguous().view(-1, Nt, Nt) - if attn_mask is not None: - new_attn_mask = torch.zeros_like(attn_mask, dtype=q.dtype) - new_attn_mask.masked_fill_(attn_mask, float("-inf")) - attn += new_attn_mask # BUG FIX: was `attn += attn_mask` in original - attn = F.softmax(attn, dim=-1) - output = torch.bmm(attn, v) - return output, attn - - def _scaled_dot_product_attention( - self, q, k, v, attn_mask=None, dropout_p=0.0, pairwise_features=None - ): - B, Nt, E = q.shape - q = q / math.sqrt(E) - - if self.pairwise_featurization: - if pairwise_features is None: - raise ValueError("pairwise_features required when pairwise_featurization=True") - q = q.view(-1, self.num_heads, Nt, E) - q_1 = q + self.bias_u[None, :, None, :] - q_2 = q + self.bias_v[None, :, None, :] - q_1 = q_1.view(-1, Nt, E) - q_2 = q_2.view(-1, Nt, E) - a_c = torch.einsum("ble,bwe->blw", q_1, k) - b_d = torch.einsum("ble,blwe->blw", q_2, pairwise_features) - attn = a_c + b_d - else: - attn = torch.bmm(q, k.transpose(-2, -1)) - - if attn_mask is not None: - new_attn_mask = torch.zeros_like(attn_mask, dtype=q.dtype) - new_attn_mask.masked_fill_(attn_mask, float("-inf")) - attn += new_attn_mask # BUG FIX: was `attn += attn_mask` in original - - attn = F.softmax(attn, dim=-1) - if dropout_p > 0.0: - attn = F.dropout(attn, p=dropout_p) - output = torch.bmm(attn, v) - return output, attn diff --git a/massspecgym/models/oracles/__init__.py b/massspecgym/models/oracles/__init__.py deleted file mode 100644 index 38b7e78..0000000 --- a/massspecgym/models/oracles/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -""" -Official data-safe oracles for MassSpecGym. - -Oracles are pretrained tools that MassSpecGym users can freely call without -data leakage concerns. They provide: - -- **MIST-CF**: Chemical formula prediction from MS/MS spectra (default formula - annotator for de novo tasks without bonus). -- **ICEBERG**: MS/MS spectrum simulation from molecular structures (thin wrapper - around the simulation model in models/simulation/iceberg/). - -All oracles follow the OracleBase interface with guaranteed data safety. -""" - -from .base import OracleBase diff --git a/massspecgym/models/oracles/base.py b/massspecgym/models/oracles/base.py deleted file mode 100644 index ccbfa07..0000000 --- a/massspecgym/models/oracles/base.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -Base class for all MassSpecGym oracles. - -Oracles are pretrained models that are guaranteed data-safe: they never -see test/validation structures during training, making them safe to use -as preprocessing tools (formula annotation, spectrum simulation) without -risk of data leakage. -""" - -from abc import ABC, abstractmethod -from typing import Optional - - -class OracleBase(ABC): - """Base class for all MassSpecGym oracles. - - Oracles provide pretrained model inference with a simple API. - All oracles guarantee data safety (no leakage from test/val sets). - """ - - @classmethod - @abstractmethod - def load(cls, checkpoint: Optional[str] = None, device: str = "cpu") -> "OracleBase": - """Load a pretrained oracle. - - Args: - checkpoint: Path to checkpoint. If None, auto-downloads. - device: Device to load model on. - - Returns: - Loaded oracle instance. - """ - raise NotImplementedError - - def is_data_safe(self) -> bool: - """Returns True - all oracles are guaranteed data-safe.""" - return True diff --git a/massspecgym/models/oracles/iceberg/__init__.py b/massspecgym/models/oracles/iceberg/__init__.py deleted file mode 100644 index 7daa28c..0000000 --- a/massspecgym/models/oracles/iceberg/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -""" -ICEBERG oracle: MS/MS spectrum simulation from molecular structures. - -Thin wrapper around the ICEBERG simulation model at -models/simulation/iceberg/, providing a simple predict_spectrum() API -for oracle usage. No code duplication - all model logic lives in -the simulation package. -""" - -from .predict import predict_spectrum diff --git a/massspecgym/models/oracles/iceberg/predict.py b/massspecgym/models/oracles/iceberg/predict.py deleted file mode 100644 index 2069e47..0000000 --- a/massspecgym/models/oracles/iceberg/predict.py +++ /dev/null @@ -1,97 +0,0 @@ -""" -ICEBERG spectrum prediction oracle API. - -Thin wrapper around the simulation model at -massspecgym/models/simulation/iceberg/, providing a simple API. - -Usage: - from massspecgym.models.oracles.iceberg import predict_spectrum - - result = predict_spectrum( - smiles="CC(=O)OC1=CC=CC=C1C(=O)O", - adduct="[M+H]+", - collision_energy=40.0, - ) -""" - -from dataclasses import dataclass -from typing import Optional, List - -import numpy as np - - -@dataclass -class PredictedSpectrum: - """Predicted MS/MS spectrum from ICEBERG.""" - mzs: np.ndarray - intensities: np.ndarray - smiles: str - adduct: str - collision_energy: float - - -def predict_spectrum( - smiles: str, - adduct: str = "[M+H]+", - collision_energy: float = 40.0, - checkpoint_dir: Optional[str] = None, - device: str = "cpu", - sparse_k: int = 128, - threshold: float = 0.001, -) -> PredictedSpectrum: - """Predict an MS/MS spectrum from a molecular structure using ICEBERG. - - This oracle wraps the ICEBERG JointModel (FragGNN + IntenGNN) - from massspecgym.models.simulation.iceberg. - - Args: - smiles: SMILES string of the molecule. - adduct: Adduct type. - collision_energy: Collision energy in eV. - checkpoint_dir: Directory containing gen and inten checkpoints. - device: Device for inference. - sparse_k: Number of top peaks to retain. - threshold: Minimum intensity threshold. - - Returns: - PredictedSpectrum with m/z and intensity arrays. - """ - from massspecgym.models.simulation.iceberg.joint_model import JointModel - from massspecgym.models.simulation.iceberg.gen_model import FragGNN - from massspecgym.models.simulation.iceberg.inten_model import IntenGNN - - if checkpoint_dir: - import os - gen_ckpt = os.path.join(checkpoint_dir, "gen_model.ckpt") - inten_ckpt = os.path.join(checkpoint_dir, "inten_model.ckpt") - model = JointModel.from_checkpoints(gen_ckpt, inten_ckpt) - else: - model = JointModel( - FragGNN(hidden_size=256), - IntenGNN(hidden_size=256), - ) - - result = model.predict_mol( - smi=smiles, - collision_eng=collision_energy, - adduct=adduct, - threshold=threshold, - device=device, - max_nodes=sparse_k, - ) - - spec = result.get("spec", []) - if spec: - mzs = np.array([s["mz"] for s in spec]) - intens = np.array([s["intensity"] for s in spec]) - else: - mzs = np.array([]) - intens = np.array([]) - - return PredictedSpectrum( - mzs=mzs, - intensities=intens, - smiles=smiles, - adduct=adduct, - collision_energy=collision_energy, - ) diff --git a/massspecgym/models/oracles/mist_cf/__init__.py b/massspecgym/models/oracles/mist_cf/__init__.py deleted file mode 100644 index 628f874..0000000 --- a/massspecgym/models/oracles/mist_cf/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -""" -MIST-CF oracle: Chemical formula prediction from MS/MS spectra. - -MIST-CF ranks candidate molecular formulas for a given spectrum using an -energy-based scoring model (FormulaTransformer with "abs-sines" embedder). -It is the default formula annotator for MassSpecGym de novo tasks -(non-bonus setting). - -Components: -- MistCFNet: The neural scoring model (FormulaTransformer + Linear head). -- predict_formulas(): High-level API for formula prediction. -- enumerate_candidate_formulas(): Pure-Python formula enumeration fallback. - -Ported from external/mist-cf/src/mist_cf/mist_cf_score/. -""" - -from .predict import predict_formulas, enumerate_candidate_formulas, FormulaCandidate -from .model import MistCFNet, MistCFFormulaTransformer diff --git a/massspecgym/models/oracles/mist_cf/model.py b/massspecgym/models/oracles/mist_cf/model.py deleted file mode 100644 index cb96a5b..0000000 --- a/massspecgym/models/oracles/mist_cf/model.py +++ /dev/null @@ -1,264 +0,0 @@ -""" -MIST-CF MistNet model: Formula scoring from MS/MS spectra. - -Ported from external/mist-cf/src/mist_cf/mist_cf_score/mist_cf_model.py. - -The model uses a FormulaTransformer to encode subformulae-annotated spectra -and scores candidate (formula, adduct) pairs. Key differences from the -MIST fingerprint encoder: -- Uses "abs-sines" form embedder (not "float" or "pos-cos"). -- Uses "cls" pooling by default. -- Includes rel_mass_diff as an input feature. -- Includes num_peaks as a scaled feature. -- Output is a single score (not a fingerprint vector). -""" - -import torch -import torch.nn as nn -import numpy as np - -from massspecgym.models.encoders.mist.chem_constants import ( - max_instr_idx as MAX_INSTR_IDX, - ION_LST, -) -from massspecgym.models.encoders.mist.form_embedders import get_embedder -from massspecgym.models.encoders.mist.modules import MLPBlocks, _get_clones -from massspecgym.models.encoders.mist import transformer_layer - - -class MistCFFormulaTransformer(nn.Module): - """FormulaTransformer for MIST-CF formula scoring. - - Differs from the MIST fingerprint encoder's FormulaTransformer: - - Input includes: form_embedded, diff_embedded, cls_flag, intensity, - num_peaks (scaled), rel_mass_diff, and optionally ion/instrument. - - No explicit "types" one-hot; uses cls_flag (1 dim) instead. - - Uses "abs-sines" embedder by default. - - Pool methods: cls (default), intensity, mean. - - Args: - form_encoder: Name of formula embedder ('abs-sines', etc.). - hidden_size: Hidden dimension. - peak_attn_layers: Number of transformer layers. - set_pooling: Pooling type ('cls', 'intensity', 'mean'). - spectra_dropout: Dropout rate. - additive_attn: Use additive attention. - pairwise_featurization: Use pairwise features. - num_heads: Number of attention heads. - ion_info: Include ion type as input feature. - instrument_info: Include instrument type as input feature. - num_valid_ion: Number of valid ion types. - num_valid_instrument: Number of valid instrument types. - """ - - def __init__( - self, - form_encoder: str = "abs-sines", - hidden_size: int = 256, - peak_attn_layers: int = 2, - set_pooling: str = "cls", - spectra_dropout: float = 0.1, - additive_attn: bool = False, - pairwise_featurization: bool = False, - num_heads: int = 8, - ion_info: bool = False, - instrument_info: bool = False, - num_valid_ion: int = len(ION_LST), - num_valid_instrument: int = MAX_INSTR_IDX, - **kwargs, - ): - super().__init__() - self.hidden_size = hidden_size - self.set_pooling = set_pooling - self.ion_info = ion_info - self.instrument_info = instrument_info - self.pairwise_featurization = pairwise_featurization - - self.form_encoder_mod = get_embedder(form_encoder) - self.formula_dim = self.form_encoder_mod.full_dim - self.cls_type = 3 - - input_dim = self.formula_dim * 2 + 1 + 1 + 1 + 1 # form, diff, cls_flag, inten, num_peak, rel_mass_diff - if ion_info: - input_dim += num_valid_ion - if instrument_info: - input_dim += num_valid_instrument - - self.formula_encoder = MLPBlocks( - input_size=input_dim, - hidden_size=hidden_size, - dropout=spectra_dropout, - num_layers=2, - ) - - if pairwise_featurization: - self.pairwise_featurizer = MLPBlocks( - input_size=self.formula_dim, - hidden_size=hidden_size, - dropout=spectra_dropout, - num_layers=2, - ) - - peak_attn_layer = transformer_layer.TransformerEncoderLayer( - d_model=hidden_size, - nhead=num_heads, - dim_feedforward=hidden_size * 4, - dropout=spectra_dropout, - additive_attn=additive_attn, - pairwise_featurization=pairwise_featurization, - ) - self.peak_attn_layers = _get_clones(peak_attn_layer, peak_attn_layers) - - def forward( - self, - num_peaks, - peak_types, - form_vec, - ion_vec, - instrument_vec, - intens, - rel_mass_diffs, - return_aux=False, - ): - device = num_peaks.device - batch_size, peak_dim, _form_dim = form_vec.shape - - cls_type_mask = peak_types == self.cls_type - cls_tokens = form_vec[cls_type_mask] - diff_vec = cls_tokens[:, None, :] - form_vec - - diff_embedded = self.form_encoder_mod(diff_vec) - form_embedded = self.form_encoder_mod(form_vec) - cat_input = [form_embedded, diff_embedded, cls_type_mask[:, :, None].float()] - - if self.ion_info: - cat_input.append(ion_vec) - if self.instrument_info: - cat_input.append(instrument_vec) - - inten_tensor = intens[:, :, None] - rel_mass_diff_tensor = rel_mass_diffs[:, :, None] - num_peak_feat = num_peaks[:, None, None].expand(batch_size, peak_dim, 1) / 10.0 - - cat_input.extend([inten_tensor, num_peak_feat, rel_mass_diff_tensor]) - input_vec = torch.cat(cat_input, -1) - peak_tensor = self.formula_encoder(input_vec) - - peak_tensor = peak_tensor.transpose(0, 1) - peaks_aranged = torch.arange(peak_dim, device=device) - attn_mask = ~(peaks_aranged[None, :] < num_peaks[:, None]) - - pairwise_features = None - if self.pairwise_featurization: - form_diffs = form_vec[:, None, :, :] - form_vec[:, :, None, :] - same_sign = torch.all(form_diffs >= 0, -1) | torch.all(form_diffs <= 0, -1) - form_diffs[~same_sign].fill_(0) - form_diffs = torch.abs(form_diffs) - encoded_diffs = self.form_encoder_mod(form_diffs) - pairwise_features = self.pairwise_featurizer(encoded_diffs) - - for layer in self.peak_attn_layers: - peak_tensor, pairwise_features = layer( - peak_tensor, - pairwise_features=pairwise_features, - src_key_padding_mask=attn_mask, - ) - - output = self._pool_out( - peak_tensor, inten_tensor, rel_mass_diff_tensor, - peak_types, attn_mask, batch_size, - ) - - if return_aux: - return output, {} - return output - - def _pool_out(self, peak_tensor, inten_tensor, rel_mass_diff_tensor, - peak_types, attn_mask, batch_size): - EPS = 1e-9 - zero_mask = attn_mask[:, :, None].repeat(1, 1, self.hidden_size).transpose(0, 1) - peak_tensor[zero_mask] = 0 - - if self.set_pooling == "cls": - pool_factor = (peak_types == self.cls_type).float() - elif self.set_pooling == "intensity": - inten_flat = inten_tensor.reshape(batch_size, -1) - intensities_sum = inten_flat.sum(1).reshape(-1, 1) + EPS - pool_factor = (inten_flat / intensities_sum) * ~attn_mask - elif self.set_pooling == "mean": - inten_flat = inten_tensor.reshape(batch_size, -1) - pool_factor = torch.clone(inten_flat).fill_(1) - pool_factor = pool_factor * ~attn_mask - pool_factor[pool_factor == 0] = 1 - pool_factor = pool_factor / pool_factor.sum(1).reshape(-1, 1) - else: - raise NotImplementedError(f"Unknown pooling: {self.set_pooling}") - - output = torch.einsum("nbd,bn->bd", peak_tensor, pool_factor) - return output - - -class MistCFNet(nn.Module): - """MIST-CF scoring network. - - Combines MistCFFormulaTransformer with a linear scoring head. - - Args: - hidden_size: Hidden dimension. - layers: Number of transformer layers. - dropout: Dropout rate. - ion_info: Include ion type features. - instrument_info: Include instrument type features. - cls_mass_diff: Include mass diff in cls token. - form_encoder: Formula embedder name. - max_subpeak: Maximum number of subpeaks. - """ - - def __init__( - self, - hidden_size: int = 256, - layers: int = 2, - dropout: float = 0.0, - ion_info: bool = False, - instrument_info: bool = False, - cls_mass_diff: bool = False, - form_encoder: str = "abs-sines", - max_subpeak: int = 10, - **kwargs, - ): - super().__init__() - self.hidden_size = hidden_size - self.max_subpeak = max_subpeak - - self.xformer = MistCFFormulaTransformer( - form_encoder=form_encoder, - hidden_size=hidden_size, - peak_attn_layers=layers, - set_pooling="cls", - spectra_dropout=dropout, - ion_info=ion_info, - instrument_info=instrument_info, - ) - self.output_layer = nn.Linear(hidden_size, 1) - - def forward( - self, - num_peaks, - peak_types, - form_vec, - ion_vec, - instrument_vec, - intens, - rel_mass_diffs, - ): - """Score a batch of (spectrum, candidate_formula) pairs. - - Returns: - Tensor of shape [batch] with scores for each candidate. - """ - output = self.xformer( - num_peaks, peak_types, form_vec, ion_vec, - instrument_vec, intens, rel_mass_diffs, - return_aux=False, - ) - return self.output_layer(output) diff --git a/massspecgym/models/oracles/mist_cf/predict.py b/massspecgym/models/oracles/mist_cf/predict.py deleted file mode 100644 index 12eecf4..0000000 --- a/massspecgym/models/oracles/mist_cf/predict.py +++ /dev/null @@ -1,222 +0,0 @@ -""" -MIST-CF formula prediction API. - -High-level interface for predicting chemical formulas from MS/MS spectra -using the pretrained MIST-CF model. - -The prediction pipeline: -1. Enumerate candidate formulas from precursor mass + adduct. -2. For each candidate, assign subformulae to the spectrum peaks. -3. Score each candidate with the MistCFNet model. -4. Return ranked results. - -Usage: - from massspecgym.models.oracles.mist_cf import predict_formulas - - results = predict_formulas( - spectrum_mzs=[91.05, 125.02, 246.11], - spectrum_intensities=[0.25, 1.0, 0.73], - precursor_mz=288.12, - adduct="[M+H]+", - top_k=10, - ) -""" - -import logging -from dataclasses import dataclass -from typing import List, Optional, Union - -import numpy as np -import torch - -from massspecgym.models.encoders.mist.chem_constants import ( - ION_LST, - ELEMENT_TO_MASS, - ELECTRON_MASS, - ion_to_mass, - VALID_ELEMENTS, - VALID_MONO_MASSES, - formula_to_dense, - vec_to_formula, -) -from massspecgym.data.subformulae import assign_subformulae_single - -logger = logging.getLogger(__name__) - - -@dataclass -class FormulaCandidate: - """A ranked formula candidate from MIST-CF prediction.""" - formula: str - adduct: str - score: float - parentmass: float - - -def enumerate_candidate_formulas( - precursor_mz: float, - adduct: str = "[M+H]+", - ppm_tol: float = 10.0, - max_candidates: int = 500, -) -> List[str]: - """Enumerate candidate molecular formulas from a precursor mass. - - Uses a simple combinatorial enumeration over common organic elements - (C, H, N, O, S, P, F, Cl, Br) filtered by mass tolerance. - - This is a pure-Python fallback for SIRIUS decomposition. - - Args: - precursor_mz: Precursor m/z value. - adduct: Adduct type string. - ppm_tol: PPM tolerance for mass matching. - max_candidates: Maximum number of candidates to return. - - Returns: - List of molecular formula strings. - """ - adduct_mass = ion_to_mass.get(adduct, ELEMENT_TO_MASS["H"] - ELECTRON_MASS) - neutral_mass = precursor_mz - adduct_mass - - if neutral_mass <= 0 or neutral_mass > 2000: - return [] - - mass_tol = neutral_mass * ppm_tol * 1e-6 - - element_masses = { - "C": VALID_MONO_MASSES[0], # 12.0 - "H": VALID_MONO_MASSES[1], # 1.008 - "N": VALID_MONO_MASSES[11], # 14.003 - "O": VALID_MONO_MASSES[13], # 15.995 - "S": VALID_MONO_MASSES[15], # 31.972 - "P": VALID_MONO_MASSES[14], # 30.974 - } - - candidates = [] - max_c = min(int(neutral_mass / element_masses["C"]) + 1, 100) - - for nc in range(0, max_c + 1): - mass_c = nc * element_masses["C"] - if mass_c > neutral_mass + mass_tol: - break - remaining = neutral_mass - mass_c - max_n = min(int(remaining / element_masses["N"]) + 1, 20) - - for nn in range(0, max_n + 1): - mass_cn = mass_c + nn * element_masses["N"] - if mass_cn > neutral_mass + mass_tol: - break - remaining2 = neutral_mass - mass_cn - max_o = min(int(remaining2 / element_masses["O"]) + 1, 30) - - for no in range(0, max_o + 1): - mass_cno = mass_cn + no * element_masses["O"] - if mass_cno > neutral_mass + mass_tol: - break - remaining3 = neutral_mass - mass_cno - - for ns in range(0, min(3, int(remaining3 / element_masses["S"]) + 1)): - mass_cnos = mass_cno + ns * element_masses["S"] - if mass_cnos > neutral_mass + mass_tol: - break - remaining4 = neutral_mass - mass_cnos - - nh_approx = remaining4 / element_masses["H"] - nh = round(nh_approx) - if nh < 0: - continue - - total_mass = mass_cnos + nh * element_masses["H"] - ppm_diff = abs(total_mass - neutral_mass) / neutral_mass * 1e6 - - if ppm_diff <= ppm_tol: - rdbe = nc - nh / 2 + nn / 2 + 1 - if rdbe >= -0.5 and nh <= 2 * nc + nn + 2: - parts = [] - if nc > 0: parts.append(f"C{nc}" if nc > 1 else "C") - if nh > 0: parts.append(f"H{nh}" if nh > 1 else "H") - if nn > 0: parts.append(f"N{nn}" if nn > 1 else "N") - if no > 0: parts.append(f"O{no}" if no > 1 else "O") - if ns > 0: parts.append(f"S{ns}" if ns > 1 else "S") - formula = "".join(parts) - if formula: - candidates.append(formula) - - if len(candidates) >= max_candidates: - return candidates - - return candidates - - -def predict_formulas( - spectrum_mzs: Union[np.ndarray, list], - spectrum_intensities: Union[np.ndarray, list], - precursor_mz: float, - adduct: str = "[M+H]+", - top_k: int = 10, - checkpoint: Optional[str] = None, - instrument: str = "unknown", - ppm_tol: float = 10.0, - model: Optional["MistCFNet"] = None, -) -> List[FormulaCandidate]: - """Predict chemical formulas from an MS/MS spectrum using MIST-CF. - - Pipeline: - 1. Enumerate candidate formulas from precursor mass. - 2. Assign subformulae to the spectrum for each candidate. - 3. Score with MistCFNet (if model/checkpoint provided). - 4. Return top-k candidates ranked by score. - - Args: - spectrum_mzs: Array of m/z values. - spectrum_intensities: Array of intensity values. - precursor_mz: Precursor m/z value. - adduct: Adduct type. - top_k: Number of top candidates to return. - checkpoint: Path to MIST-CF checkpoint (for model loading). - instrument: Instrument type string. - ppm_tol: PPM tolerance for formula enumeration. - model: Pre-loaded MistCFNet (skips checkpoint loading if provided). - - Returns: - List of FormulaCandidate objects, sorted by score (descending). - """ - mzs = np.asarray(spectrum_mzs, dtype=np.float64) - intensities = np.asarray(spectrum_intensities, dtype=np.float64) - spectrum = np.column_stack([mzs, intensities]) - - if intensities.max() > 0: - spectrum[:, 1] = spectrum[:, 1] / spectrum[:, 1].max() - - adduct_mass = ion_to_mass.get(adduct, ELEMENT_TO_MASS["H"] - ELECTRON_MASS) - neutral_mass = precursor_mz - adduct_mass - - candidates = enumerate_candidate_formulas(precursor_mz, adduct, ppm_tol=ppm_tol) - - if not candidates: - return [] - - results = [] - for formula in candidates: - subform = assign_subformulae_single(formula, spectrum, adduct, mass_diff_thresh=15.0) - n_assigned = 0 - if subform["output_tbl"] is not None: - n_assigned = len(subform["output_tbl"].get("mz", [])) - - mass = formula_to_dense(formula).dot(VALID_MONO_MASSES) - ppm = abs(mass - neutral_mass) / max(neutral_mass, 200) * 1e6 - - score = n_assigned * 10.0 - ppm - results.append(FormulaCandidate( - formula=formula, - adduct=adduct, - score=score, - parentmass=mass, - )) - - results.sort(key=lambda x: x.score, reverse=True) - - if model is not None or checkpoint is not None: - logger.info("Neural scoring with MistCFNet (checkpoint-based scoring)") - - return results[:top_k] diff --git a/massspecgym/models/retrieval/__init__.py b/massspecgym/models/retrieval/__init__.py index 7d34129..e24be5c 100644 --- a/massspecgym/models/retrieval/__init__.py +++ b/massspecgym/models/retrieval/__init__.py @@ -9,21 +9,5 @@ "RandomRetrieval", "DeepSetsRetrieval", "FingerprintFFNRetrieval", - "FromDictRetrieval", - "MISTFingerprintRetrieval", - "GenerativeRetrieval", - "IcebergRetrieval", -] - - -def __getattr__(name): - if name == "MISTFingerprintRetrieval": - from .mist_retrieval import MISTFingerprintRetrieval - return MISTFingerprintRetrieval - if name == "GenerativeRetrieval": - from .generative_retrieval import GenerativeRetrieval - return GenerativeRetrieval - if name == "IcebergRetrieval": - from .iceberg_retrieval import IcebergRetrieval - return IcebergRetrieval - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + "FromDictRetrieval" +] \ No newline at end of file diff --git a/massspecgym/models/retrieval/generative_retrieval.py b/massspecgym/models/retrieval/generative_retrieval.py deleted file mode 100644 index e960c36..0000000 --- a/massspecgym/models/retrieval/generative_retrieval.py +++ /dev/null @@ -1,127 +0,0 @@ -""" -Generative retrieval: generate molecule from spectrum, rank candidates by FP similarity. - -Uses any MIST+decoder model to generate a top-1 molecule from the spectrum, -converts it to a Morgan fingerprint, and ranks retrieval candidates by -Tanimoto similarity to the generated molecule's fingerprint. - -This is a bonus-task retrieval strategy that can use any FP2Mol decoder -(FRIGID, DiffMS, MolForge). -""" - -import typing as T - -import numpy as np -import torch -import torch.nn as nn -from rdkit import Chem -from rdkit.Chem import AllChem - -from massspecgym.models.base import Stage -from massspecgym.models.retrieval.base import RetrievalMassSpecGymModel - - -class GenerativeRetrieval(RetrievalMassSpecGymModel): - """Generative retrieval: generate molecule, then rank by fingerprint similarity. - - Pipeline: - 1. MIST encoder: spectrum โ†’ fingerprint - 2. FP2Mol decoder: fingerprint โ†’ top-1 molecule (SMILES) - 3. Compute Morgan FP of generated molecule - 4. Rank candidates by Tanimoto similarity to generated FP - - Args: - decoder_type: Type of decoder ('frigid', 'diffms', 'molforge'). - decoder_checkpoint: Path to pretrained decoder checkpoint. - encoder_checkpoint: Path to pretrained MIST encoder checkpoint. - fp_bits: Fingerprint dimensionality for comparison. - fp_radius: Morgan FP radius. - """ - - def __init__( - self, - decoder_type: str = "frigid", - decoder_checkpoint: T.Optional[str] = None, - encoder_checkpoint: T.Optional[str] = None, - fp_bits: int = 4096, - fp_radius: int = 2, - **kwargs, - ): - super().__init__(**kwargs) - self.decoder_type = decoder_type - self.fp_bits = fp_bits - self.fp_radius = fp_radius - self._decoder = None - self._decoder_checkpoint = decoder_checkpoint - self._encoder_checkpoint = encoder_checkpoint - - def _get_decoder(self): - """Lazy-load the FP2Mol decoder.""" - if self._decoder is not None: - return self._decoder - - if self.decoder_type == "frigid": - from massspecgym.models.de_novo.fp2mol.frigid import FRIGIDDecoder - self._decoder = FRIGIDDecoder( - encoder_checkpoint=self._encoder_checkpoint, - training_mode="spec2mol", - ) - elif self.decoder_type == "molforge": - from massspecgym.models.de_novo.fp2mol.molforge import MolForgeDecoder - self._decoder = MolForgeDecoder( - encoder_checkpoint=self._encoder_checkpoint, - training_mode="spec2mol", - ) - elif self.decoder_type == "diffms": - from massspecgym.models.de_novo.fp2mol.diffms import DiffMSDecoder - self._decoder = DiffMSDecoder( - encoder_checkpoint=self._encoder_checkpoint, - training_mode="spec2mol", - ) - else: - raise ValueError(f"Unknown decoder type: {self.decoder_type}") - - if self._decoder_checkpoint: - ckpt = torch.load(self._decoder_checkpoint, map_location="cpu") - self._decoder.load_state_dict(ckpt.get("state_dict", ckpt), strict=False) - - return self._decoder - - def _smiles_to_fp(self, smiles: str) -> torch.Tensor: - """Convert SMILES to Morgan fingerprint tensor.""" - mol = Chem.MolFromSmiles(smiles) if smiles else None - if mol is None: - return torch.zeros(self.fp_bits, dtype=torch.float32) - fp = AllChem.GetMorganFingerprintAsBitVect(mol, self.fp_radius, nBits=self.fp_bits) - arr = np.zeros(self.fp_bits, dtype=np.float32) - AllChem.DataStructs.ConvertToNumpyArray(fp, arr) - return torch.from_numpy(arr) - - def step(self, batch: dict, stage: Stage = Stage.NONE) -> dict: - loss = torch.tensor(0.0, device=self.device) - batch_size = batch["spec"].size(0) - cands = batch["candidates"] - batch_ptr = batch["batch_ptr"] - - generated_fps = [] - for i in range(batch_size): - try: - decoder = self._get_decoder() - mols_pred = decoder.decode_from_fingerprint( - batch.get("fingerprint", torch.zeros(1, self.fp_bits))[i:i+1], - formula=batch.get("formula", [None])[i:i+1] if "formula" in batch else None, - num_samples=1, - ) - top1_smiles = mols_pred[0][0] if mols_pred and mols_pred[0] else None - except Exception: - top1_smiles = None - generated_fps.append(self._smiles_to_fp(top1_smiles)) - - gen_fps = torch.stack(generated_fps).to(self.device) - gen_fps_repeated = gen_fps.repeat_interleave(batch_ptr, dim=0) - - intersection = (gen_fps_repeated * cands).sum(dim=-1) - union = gen_fps_repeated.sum(dim=-1) + cands.sum(dim=-1) - intersection - scores = intersection / union.clamp(min=1e-8) - - return dict(loss=loss, scores=scores) diff --git a/massspecgym/models/retrieval/iceberg_retrieval.py b/massspecgym/models/retrieval/iceberg_retrieval.py deleted file mode 100644 index 65c8686..0000000 --- a/massspecgym/models/retrieval/iceberg_retrieval.py +++ /dev/null @@ -1,114 +0,0 @@ -""" -ICEBERG cosine similarity retrieval. - -Simulates MS/MS spectra for each candidate molecule using ICEBERG, -then ranks candidates by cosine similarity between simulated and -query experimental spectra. - -This matches the retrieval approach in external/ms-pred/src/ms_pred/retrieval/. -This is a bonus-task retrieval strategy. -""" - -import typing as T - -import numpy as np -import torch -import torch.nn as nn - -from massspecgym.models.base import Stage -from massspecgym.models.retrieval.base import RetrievalMassSpecGymModel - - -class IcebergRetrieval(RetrievalMassSpecGymModel): - """ICEBERG-based retrieval via simulated spectrum cosine similarity. - - For each candidate molecule, simulates an MS/MS spectrum using ICEBERG, - then computes cosine similarity between simulated and query spectra. - Candidates are ranked by this similarity. - - Args: - gen_checkpoint: Path to ICEBERG FragGNN checkpoint. - inten_checkpoint: Path to ICEBERG IntenGNN checkpoint. - num_bins: Number of bins for spectrum comparison. - mz_max: Maximum m/z for binning. - """ - - def __init__( - self, - gen_checkpoint: T.Optional[str] = None, - inten_checkpoint: T.Optional[str] = None, - num_bins: int = 15000, - mz_max: float = 1500.0, - **kwargs, - ): - super().__init__(**kwargs) - self._gen_checkpoint = gen_checkpoint - self._inten_checkpoint = inten_checkpoint - self.num_bins = num_bins - self.mz_max = mz_max - self._iceberg_model = None - - def _get_iceberg(self): - if self._iceberg_model is not None: - return self._iceberg_model - from massspecgym.models.simulation.iceberg.joint_model import JointModel - from massspecgym.models.simulation.iceberg.gen_model import FragGNN - from massspecgym.models.simulation.iceberg.inten_model import IntenGNN - - gen = FragGNN(hidden_size=256) - inten = IntenGNN(hidden_size=256) - self._iceberg_model = JointModel(gen, inten) - - if self._gen_checkpoint and self._inten_checkpoint: - gen_ckpt = torch.load(self._gen_checkpoint, map_location="cpu") - gen.load_state_dict(gen_ckpt.get("state_dict", gen_ckpt), strict=False) - inten_ckpt = torch.load(self._inten_checkpoint, map_location="cpu") - inten.load_state_dict(inten_ckpt.get("state_dict", inten_ckpt), strict=False) - - return self._iceberg_model - - def _bin_spectrum(self, mzs, intensities): - """Bin a spectrum into fixed-size vector.""" - bins = np.linspace(0, self.mz_max, self.num_bins) - binned = np.zeros(self.num_bins, dtype=np.float32) - if len(mzs) > 0: - indices = np.digitize(mzs, bins) - 1 - valid = (indices >= 0) & (indices < self.num_bins) - for idx, inten in zip(indices[valid], intensities[valid]): - binned[idx] += inten - norm = np.linalg.norm(binned) - if norm > 0: - binned /= norm - return binned - - def step(self, batch: dict, stage: Stage = Stage.NONE) -> dict: - loss = torch.tensor(0.0, device=self.device) - - query_mzs = batch.get("spec_mzs", None) - query_ints = batch.get("spec_ints", None) - cands_smiles = batch.get("candidates_smiles", []) - batch_ptr = batch["batch_ptr"] - - iceberg = self._get_iceberg() - - all_scores = [] - for smiles in cands_smiles: - try: - result = iceberg.predict_mol( - smi=smiles, - adduct=batch.get("adduct", ["[M+H]+"])[0] if "adduct" in batch else "[M+H]+", - ) - spec = result.get("spec", []) - if spec: - sim_mzs = np.array([s["mz"] for s in spec]) - sim_ints = np.array([s["intensity"] for s in spec]) - else: - sim_mzs, sim_ints = np.array([]), np.array([]) - except Exception: - sim_mzs, sim_ints = np.array([]), np.array([]) - - score = 0.0 - all_scores.append(score) - - scores = torch.tensor(all_scores, dtype=torch.float32, device=self.device) - return dict(loss=loss, scores=scores) diff --git a/massspecgym/models/retrieval/mist_retrieval.py b/massspecgym/models/retrieval/mist_retrieval.py deleted file mode 100644 index 0421112..0000000 --- a/massspecgym/models/retrieval/mist_retrieval.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -MIST fingerprint retrieval: predict Morgan FP from spectrum, rank by Tanimoto. - -Uses the MIST encoder (SpectraEncoderGrowing) to predict a 4096-bit molecular -fingerprint from the MS/MS spectrum, then ranks retrieval candidates by -Tanimoto similarity between predicted and candidate fingerprints. - -This is a bonus-task retrieval strategy. -""" - -import typing as T - -import torch -import torch.nn as nn - -from massspecgym.models.base import Stage -from massspecgym.models.retrieval.base import RetrievalMassSpecGymModel -from massspecgym.utils import CosSimLoss - - -class MISTFingerprintRetrieval(RetrievalMassSpecGymModel): - """MIST-based retrieval via predicted fingerprint similarity. - - Loads a pretrained MIST SpectraEncoderGrowing checkpoint, predicts - a fingerprint for each query spectrum, and ranks candidates by - Tanimoto (or cosine) similarity. - - Note: Requires MIST-featurized input (subformulae assignment). - Use MISTDataMixin for automatic data preparation. - - Args: - encoder_checkpoint: Path to pretrained MIST encoder checkpoint. - fp_bits: Fingerprint dimensionality (4096 for Morgan). - similarity: Similarity function ('cosine' or 'tanimoto'). - """ - - def __init__( - self, - encoder_checkpoint: T.Optional[str] = None, - fp_bits: int = 4096, - similarity: str = "cosine", - **kwargs, - ): - super().__init__(**kwargs) - self.fp_bits = fp_bits - self.similarity = similarity - self.loss_fn = CosSimLoss() - - from massspecgym.models.encoders.mist.encoder import SpectraEncoderGrowing - self.encoder = SpectraEncoderGrowing( - form_embedder="float", output_size=fp_bits, hidden_size=256, - peak_attn_layers=4, num_heads=8, refine_layers=4, - ) - - if encoder_checkpoint: - ckpt = torch.load(encoder_checkpoint, map_location="cpu") - state_dict = ckpt.get("state_dict", ckpt) - self.encoder.load_state_dict(state_dict, strict=False) - - def forward(self, batch: dict) -> torch.Tensor: - """Predict fingerprint from spectrum.""" - fp_pred, _ = self.encoder(batch) - return fp_pred - - def step(self, batch: dict, stage: Stage = Stage.NONE) -> dict: - fp_pred = self.forward(batch) - fp_true = batch["mol"] - loss = self.loss_fn(fp_true, fp_pred) - - cands = batch["candidates"] - batch_ptr = batch["batch_ptr"] - fp_pred_repeated = fp_pred.repeat_interleave(batch_ptr, dim=0) - - if self.similarity == "tanimoto": - intersection = (fp_pred_repeated * cands).sum(dim=-1) - union = fp_pred_repeated.sum(dim=-1) + cands.sum(dim=-1) - intersection - scores = intersection / union.clamp(min=1e-8) - else: - scores = nn.functional.cosine_similarity(fp_pred_repeated, cands) - - return dict(loss=loss, scores=scores) diff --git a/massspecgym/models/simulation/iceberg/__init__.py b/massspecgym/models/simulation/iceberg/__init__.py deleted file mode 100644 index 9976a3d..0000000 --- a/massspecgym/models/simulation/iceberg/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -""" -ICEBERG spectrum simulation model. - -Predicts tandem mass spectra from molecular structures using a two-stage -DAG-based fragmentation approach: -1. FragGNN: Autoregressive fragment generation via bond-breaking DAG. -2. IntenGNN: Intensity prediction for generated fragments. -""" - - -def __getattr__(name): - if name == "FragGNN": - from .gen_model import FragGNN - return FragGNN - if name == "IntenGNN": - from .inten_model import IntenGNN - return IntenGNN - if name == "JointModel": - from .joint_model import JointModel - return JointModel - if name == "IcebergSimulationMassSpecGymModel": - from .adapter import IcebergSimulationMassSpecGymModel - return IcebergSimulationMassSpecGymModel - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/massspecgym/models/simulation/iceberg/adapter.py b/massspecgym/models/simulation/iceberg/adapter.py deleted file mode 100644 index 1a718a6..0000000 --- a/massspecgym/models/simulation/iceberg/adapter.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -ICEBERG adapter for MassSpecGym SimulationMassSpecGymModel interface. - -Wraps the ICEBERG JointModel (FragGNN + IntenGNN) to follow the same -interface as GNNSimulationMassSpecGymModel and FPSimulationMassSpecGymModel. -""" - -import typing as T -from pathlib import Path - -import torch - -from massspecgym.models.simulation.base import SimulationMassSpecGymModel - - -class IcebergSimulationMassSpecGymModel(SimulationMassSpecGymModel): - """ICEBERG spectrum simulation model for MassSpecGym. - - Predicts MS/MS spectra from molecular structures using a two-stage - DAG-based approach via FragGNN + IntenGNN, adapted to the - SimulationMassSpecGymModel interface. - - Args: - gen_checkpoint: Path to pretrained FragGNN checkpoint. - inten_checkpoint: Path to pretrained IntenGNN checkpoint. - sparse_k: Number of top peaks to retain. - max_nodes: Maximum number of DAG nodes. - threshold: Minimum intensity threshold. - """ - - def __init__( - self, - gen_checkpoint: T.Optional[str] = None, - inten_checkpoint: T.Optional[str] = None, - sparse_k: int = 128, - max_nodes: int = 100, - threshold: float = 0.001, - **kwargs, - ): - self._gen_checkpoint = gen_checkpoint - self._inten_checkpoint = inten_checkpoint - self._sparse_k = sparse_k - self._max_nodes = max_nodes - self._threshold = threshold - super().__init__(**kwargs) - - def _setup_model(self): - """Set up the ICEBERG JointModel from checkpoints.""" - from .gen_model import FragGNN - from .inten_model import IntenGNN - from .joint_model import JointModel - - if self._gen_checkpoint and self._inten_checkpoint: - gen_obj = FragGNN.load_from_checkpoint(self._gen_checkpoint, map_location="cpu") - inten_obj = IntenGNN.load_from_checkpoint(self._inten_checkpoint, map_location="cpu") - self.model = JointModel(gen_obj, inten_obj) - else: - self.model = JointModel( - FragGNN(hidden_size=256), - IntenGNN(hidden_size=256), - ) diff --git a/massspecgym/models/simulation/iceberg/dag_data.py b/massspecgym/models/simulation/iceberg/dag_data.py deleted file mode 100644 index 133964c..0000000 --- a/massspecgym/models/simulation/iceberg/dag_data.py +++ /dev/null @@ -1,218 +0,0 @@ -""" -DAG data structures and featurization for ICEBERG. - -Provides TreeProcessor for converting fragmentation trees into featurized -DGL graphs, and dataset classes for training/inference. - -Ported from external/ms-pred/src/ms_pred/dag_pred/dag_data.py. -Requires: dgl, torch. -""" - -import logging -from typing import List, Optional - -import numpy as np -import torch -import torch.nn as nn - -from massspecgym.models.encoders.mist.chem_constants import ( - VALID_ELEMENTS, - CHEM_ELEMENT_NUM, - element_to_ind, - ELEMENT_VECTORS, - VALID_MONO_MASSES, - ELEMENT_TO_MASS, - formula_to_dense, - vec_to_formula, -) -from .magma.fragmentation import FragmentEngine, MAX_BONDS, create_new_ids - -logger = logging.getLogger(__name__) - -FRAGMENT_ENGINE_PARAMS = {"max_broken_bonds": 6, "max_tree_depth": 3} - -MAX_H = 20 -ELEMENT_DIM = CHEM_ELEMENT_NUM -NUM_ATOM_GROUPS = 8 - - -class TreeProcessor: - """Processes fragmentation trees into featurized representations for ICEBERG. - - Converts a FragmentEngine's frag_to_entry into DGL graphs with node features - (element type + hydrogen count), edge features (bond type), and tree structure. - - Args: - pe_embed_k: Positional embedding dimension (0 to disable). - root_encode: Root encoding method ('gnn' or 'fp'). - binned_targs: Whether to use binned intensity targets. - add_hs: Whether to add hydrogen atoms explicitly. - embed_elem_group: Whether to embed element group features. - """ - - def __init__( - self, - pe_embed_k: int = 10, - root_encode: str = "gnn", - binned_targs: bool = False, - add_hs: bool = False, - embed_elem_group: bool = False, - ): - self.pe_embed_k = pe_embed_k - self.root_encode = root_encode - self.binned_targs = binned_targs - self.add_hs = add_hs - self.embed_elem_group = embed_elem_group - self.bins = np.linspace(0, 1500, 15000) - - def get_node_feats(self) -> int: - """Return the number of node features.""" - base = ELEMENT_DIM + MAX_H - if self.embed_elem_group: - base += NUM_ATOM_GROUPS - return base - - def get_frag_info(self, frag: int, engine: FragmentEngine) -> dict: - """Get atom indices and formula for a fragment.""" - keep_atoms, keep_symbols = engine.get_present_atoms(frag) - old_to_new = {old: new for new, old in enumerate(keep_atoms)} - new_to_old = {new: old for old, new in old_to_new.items()} - form = engine.formula_from_kept_inds(np.array(keep_atoms)) - return {"new_to_old": new_to_old, "old_to_new": old_to_new, "form": form} - - def featurize_frag(self, frag: int, engine: FragmentEngine, add_random_walk: bool = False): - """Featurize a single fragment as a graph. - - Returns dict with node features (atom types + H counts) and edge info. - """ - try: - import dgl - except ImportError: - raise ImportError("DGL is required for ICEBERG. Install with: pip install dgl") - - keep_atoms, keep_symbols = engine.get_present_atoms(frag) - bond_types_list, bond_inds_list = engine.get_present_edges(frag) - - if len(keep_atoms) == 0: - return None - - old_to_new = {old: new for new, old in enumerate(keep_atoms)} - num_nodes = len(keep_atoms) - - atom_symbols = [engine.atom_symbols[i] for i in keep_atoms] - h_counts = engine.atom_hs[np.array(keep_atoms)] - - node_feats = self._build_node_feats(atom_symbols, h_counts) - - src, dst, edge_feats = [], [], [] - for btype, (a1, a2) in zip(bond_types_list, bond_inds_list): - if a1 in old_to_new and a2 in old_to_new: - src.append(old_to_new[a1]) - dst.append(old_to_new[a2]) - edge_feats.append(btype) - src.append(old_to_new[a2]) - dst.append(old_to_new[a1]) - edge_feats.append(btype) - - if len(src) == 0: - g = dgl.graph(([], []), num_nodes=num_nodes) - else: - g = dgl.graph((src, dst), num_nodes=num_nodes) - - g.ndata["h"] = torch.FloatTensor(node_feats) - if len(edge_feats) > 0: - ef = torch.zeros(len(edge_feats), MAX_BONDS) - for i, bt in enumerate(edge_feats): - if bt < MAX_BONDS: - ef[i, bt] = 1.0 - g.edata["e"] = ef - else: - g.edata["e"] = torch.zeros(0, MAX_BONDS) - - return g - - def _build_node_feats(self, atom_symbols: List[str], h_counts: np.ndarray) -> np.ndarray: - """Build node feature matrix: one-hot element + one-hot H count.""" - n = len(atom_symbols) - feats = np.zeros((n, ELEMENT_DIM + MAX_H)) - for i, sym in enumerate(atom_symbols): - if sym in element_to_ind: - feats[i, element_to_ind[sym]] = 1.0 - h = min(int(h_counts[i]), MAX_H - 1) - feats[i, ELEMENT_DIM + h] = 1.0 - return feats - - def process_tree_gen(self, tree: dict, convert_to_dgl: bool = True): - """Process a fragmentation tree for FragGNN training/inference.""" - return self._process_tree(tree, include_targets=True, convert_to_dgl=convert_to_dgl) - - def process_tree_inten(self, tree: dict, convert_to_dgl: bool = True): - """Process a fragmentation tree for IntenGNN training.""" - return self._process_tree(tree, include_targets=True, convert_to_dgl=convert_to_dgl) - - def process_tree_inten_pred(self, tree: dict, convert_to_dgl: bool = True): - """Process a fragmentation tree for IntenGNN prediction (no targets).""" - return self._process_tree(tree, include_targets=False, convert_to_dgl=convert_to_dgl) - - def _process_tree(self, tree: dict, include_targets: bool = True, convert_to_dgl: bool = True): - """Core tree processing: build graph features from frag_to_entry.""" - engine = tree.get("engine") - frag_to_entry = tree.get("frag_to_entry", {}) - - if engine is None or len(frag_to_entry) == 0: - return None - - frag_to_id, id_to_frag = create_new_ids(frag_to_entry) - frag_hashes = list(frag_to_id.keys()) - n_frags = len(frag_hashes) - - graphs = [] - ind_maps = [] - broken_list = [] - form_list = [] - mass_list = [] - - root_hash = None - for h, entry in frag_to_entry.items(): - if entry["tree_depth"] == 0: - root_hash = h - break - - root_frag = frag_to_entry[root_hash]["frag"] if root_hash else engine.get_root_frag() - - if convert_to_dgl: - root_graph = self.featurize_frag(root_frag, engine) - else: - root_graph = None - - for h in frag_hashes: - entry = frag_to_entry[h] - frag = entry["frag"] - if convert_to_dgl: - g = self.featurize_frag(frag, engine) - if g is not None: - graphs.append(g) - ind_maps.append(frag_to_id[h]) - broken_list.append(entry.get("max_broken", 0)) - form_list.append(entry.get("form", "")) - mass_list.append(entry.get("base_mass", 0.0)) - - result = { - "root_repr": root_graph, - "n_frags": n_frags, - "ind_maps": np.array(ind_maps), - "broken": np.array(broken_list), - "forms": form_list, - "masses": np.array(mass_list), - "frag_to_entry": frag_to_entry, - "frag_to_id": frag_to_id, - "engine": engine, - } - - if convert_to_dgl and graphs: - import dgl - result["graphs"] = dgl.batch(graphs) - else: - result["graphs"] = None - - return result diff --git a/massspecgym/models/simulation/iceberg/gen_model.py b/massspecgym/models/simulation/iceberg/gen_model.py deleted file mode 100644 index 5052ba0..0000000 --- a/massspecgym/models/simulation/iceberg/gen_model.py +++ /dev/null @@ -1,234 +0,0 @@ -""" -FragGNN: Autoregressive fragment generation model for ICEBERG. - -Predicts the probability of each atom leaving the current fragment, -building a fragmentation DAG by iteratively removing atoms. - -Ported from external/ms-pred/src/ms_pred/dag_pred/gen_model.py. -Requires: dgl, pytorch_lightning. -""" - -import numpy as np -from typing import List, Optional - -import torch -import torch.nn as nn - -from massspecgym.models.encoders.mist.chem_constants import CHEM_ELEMENT_NUM -from .magma.fragmentation import FragmentEngine, MAX_BONDS -from .dag_data import FRAGMENT_ENGINE_PARAMS, MAX_H, TreeProcessor - -ELEMENT_DIM = CHEM_ELEMENT_NUM - - -class FragGNN(nn.Module): - """Autoregressive fragment generation GNN for ICEBERG. - - Given a molecular graph (root) and a current fragment, predicts the - probability that each atom will be removed in the next fragmentation step. - - Uses a GNN (GGNN or message-passing) over the fragment graph, conditioned - on the root molecule representation. - - Args: - hidden_size: Hidden dimension for all layers. - layers: Number of GNN layers. - set_layers: Number of set-transformer layers for fragment pooling. - dropout: Dropout rate. - mpnn_type: GNN type ('GGNN' or 'PNA'). - pool_op: Pooling operation ('avg', 'max'). - node_feats: Number of node features (element_dim + max_h). - max_broken: Maximum broken bonds for one-hot encoding. - root_encode: Root encoding method ('gnn' or 'fp'). - embed_adduct: Whether to embed adduct type. - embed_collision: Whether to embed collision energy. - embed_instrument: Whether to embed instrument type. - encode_forms: Whether to encode subformula features. - add_hs: Whether to add hydrogen features. - """ - - def __init__( - self, - hidden_size: int, - layers: int = 2, - set_layers: int = 2, - dropout: float = 0, - mpnn_type: str = "GGNN", - pool_op: str = "avg", - node_feats: int = ELEMENT_DIM + MAX_H, - max_broken: int = FRAGMENT_ENGINE_PARAMS["max_broken_bonds"], - root_encode: str = "gnn", - embed_adduct: bool = False, - embed_collision: bool = False, - embed_instrument: bool = False, - encode_forms: bool = False, - add_hs: bool = False, - **kwargs, - ): - super().__init__() - self.hidden_size = hidden_size - self.layers = layers - self.dropout = dropout - self.mpnn_type = mpnn_type - self.pool_op = pool_op - self.node_feats = node_feats - self.max_broken = max_broken - self.root_encode = root_encode - self.embed_adduct = embed_adduct - self.embed_collision = embed_collision - self.embed_instrument = embed_instrument - self.encode_forms = encode_forms - self.add_hs = add_hs - - broken_dim = max_broken * 2 + 1 - - root_input_dim = node_feats - if root_encode == "fp": - root_input_dim = 4096 - self.root_encoder = nn.Sequential( - nn.Linear(root_input_dim, hidden_size), - nn.ReLU(), - nn.Dropout(dropout), - ) - - edge_feats = MAX_BONDS - self.node_input = nn.Linear(node_feats, hidden_size) - - try: - import dgl.nn as dgl_nn - if mpnn_type == "GGNN": - self.gnn_layers = nn.ModuleList([ - dgl_nn.GatedGraphConv(hidden_size, hidden_size, 1, 1) - for _ in range(layers) - ]) - else: - self.gnn_layers = nn.ModuleList([ - nn.Linear(hidden_size, hidden_size) - for _ in range(layers) - ]) - except ImportError: - self.gnn_layers = nn.ModuleList([ - nn.Linear(hidden_size, hidden_size) - for _ in range(layers) - ]) - - mlp_input_dim = hidden_size * 3 + broken_dim - if encode_forms: - from massspecgym.models.encoders.mist.form_embedders import get_embedder - self.form_embedder = get_embedder("abs-sines") - form_dim = self.form_embedder.full_dim - mlp_input_dim += form_dim * 2 - - self.output_mlp = nn.Sequential( - nn.Linear(mlp_input_dim, hidden_size), - nn.ReLU(), - nn.Dropout(dropout), - nn.Linear(hidden_size, hidden_size), - nn.ReLU(), - nn.Dropout(dropout), - ) - self.output_map = nn.Linear(hidden_size, 1) - - def forward( - self, - graphs, - root_repr, - ind_maps, - broken, - collision_engs=None, - precursor_mzs=None, - adducts=None, - instruments=None, - root_forms=None, - frag_forms=None, - ): - """Forward pass: predict atom-leaving probabilities for each fragment. - - Args: - graphs: Batched DGL graph of all fragments. - root_repr: Root molecule representation (DGL graph or fingerprint tensor). - ind_maps: Fragment-to-root index mapping. - broken: Number of broken bonds per fragment. - collision_engs: Collision energies. - precursor_mzs: Precursor m/z values. - adducts: Adduct indices. - instruments: Instrument indices. - root_forms: Root formula vectors. - frag_forms: Fragment formula vectors. - - Returns: - Dict with 'output': atom leaving probabilities [batch, max_atoms]. - """ - try: - import dgl - except ImportError: - raise ImportError("DGL required for FragGNN") - - if isinstance(root_repr, dgl.DGLGraph): - root_h = root_repr.ndata["h"] - root_embedded = self.root_encoder(root_h) - root_repr.ndata["h"] = root_embedded - root_embeddings = dgl.mean_nodes(root_repr, "h") - else: - root_embeddings = self.root_encoder(root_repr) - - ext_root = root_embeddings[ind_maps] - ext_root_atoms = torch.repeat_interleave( - ext_root, graphs.batch_num_nodes(), dim=0 - ) - - frag_h = self.node_input(graphs.ndata["h"]) - for gnn_layer in self.gnn_layers: - if hasattr(gnn_layer, 'forward') and 'graph' in str(type(gnn_layer)): - frag_h = gnn_layer(graphs, frag_h) - else: - frag_h = torch.relu(gnn_layer(frag_h)) - - graphs.ndata["h_out"] = frag_h - avg_frags = dgl.mean_nodes(graphs, "h_out") - ext_frag_atoms = torch.repeat_interleave( - avg_frags, graphs.batch_num_nodes(), dim=0 - ) - - broken_clamped = broken.clamp(0, self.max_broken * 2) - broken_onehot = torch.zeros(broken.size(0), self.max_broken * 2 + 1, device=broken.device) - broken_onehot.scatter_(1, broken_clamped.unsqueeze(1).long(), 1.0) - broken_onehot_atoms = torch.repeat_interleave( - broken_onehot, graphs.batch_num_nodes(), dim=0 - ) - - cat_list = [ext_root_atoms, ext_root_atoms - ext_frag_atoms, frag_h, broken_onehot_atoms] - cat_vec = torch.cat(cat_list, dim=-1) - hidden = self.output_mlp(cat_vec) - output = torch.sigmoid(self.output_map(hidden).squeeze(-1)) - - output_padded = torch.zeros( - graphs.batch_size, graphs.batch_num_nodes().max().item(), - device=output.device - ) - offset = 0 - for i, n in enumerate(graphs.batch_num_nodes()): - output_padded[i, :n] = output[offset:offset + n] - offset += n - - return {"output": output_padded} - - def predict_mol( - self, - root_smi: str, - collision_eng: float = 40.0, - precursor_mz: float = None, - adduct: str = None, - instrument: str = None, - threshold: float = 0, - device: str = "cpu", - max_nodes: int = 100, - ) -> dict: - """Generate fragmentation tree for a molecule. - - Returns: - Dict mapping fragment hashes to fragment entries. - """ - engine = FragmentEngine(root_smi, **FRAGMENT_ENGINE_PARAMS) - engine.generate_fragments() - return engine.frag_to_entry diff --git a/massspecgym/models/simulation/iceberg/inten_model.py b/massspecgym/models/simulation/iceberg/inten_model.py deleted file mode 100644 index 0eb13ff..0000000 --- a/massspecgym/models/simulation/iceberg/inten_model.py +++ /dev/null @@ -1,244 +0,0 @@ -""" -IntenGNN: Fragment intensity prediction model for ICEBERG. - -Predicts the intensity of each fragment peak in a mass spectrum, -given the fragmentation DAG from FragGNN. - -Ported from external/ms-pred/src/ms_pred/dag_pred/inten_model.py. -Requires: dgl, pytorch_lightning. -""" - -import numpy as np -from typing import Optional - -import torch -import torch.nn as nn - -from massspecgym.models.encoders.mist.chem_constants import CHEM_ELEMENT_NUM, ELEMENT_TO_MASS -from .magma.fragmentation import MAX_BONDS -from .dag_data import FRAGMENT_ENGINE_PARAMS, MAX_H - -ELEMENT_DIM = CHEM_ELEMENT_NUM - - -class IntenGNN(nn.Module): - """Fragment intensity prediction GNN for ICEBERG. - - Given fragment graphs and their DAG structure, predicts the intensity - of each fragment as a peak in the MS/MS spectrum. - - Uses binned output (15000 bins over 0-1500 m/z) with scatter-based - pooling for peaks at the same m/z. - - Args: - hidden_size: Hidden dimension. - gnn_layers: Number of GNN layers. - mlp_layers: Number of MLP layers after GNN. - set_layers: Number of set-transformer layers. - dropout: Dropout rate. - mpnn_type: GNN type ('PNA' or 'GGNN'). - pool_op: Pooling operation. - node_feats: Number of node features. - max_broken: Maximum broken bonds. - frag_set_layers: Set layers for fragment-level attention. - loss_fn: Loss function type ('cosine' or 'entropy'). - root_encode: Root encoding ('gnn' or 'fp'). - embed_adduct: Embed adduct type. - embed_collision: Embed collision energy. - embed_instrument: Embed instrument type. - binned_targs: Use binned intensity targets. - encode_forms: Encode subformula features. - add_hs: Add hydrogen features. - ppm_tol: PPM tolerance for peak matching. - """ - - NUM_BINS = 15000 - MZ_MAX = 1500.0 - - def __init__( - self, - hidden_size: int, - gnn_layers: int = 2, - mlp_layers: int = 0, - set_layers: int = 2, - dropout: float = 0, - mpnn_type: str = "PNA", - pool_op: str = "avg", - node_feats: int = ELEMENT_DIM + MAX_H, - max_broken: int = FRAGMENT_ENGINE_PARAMS["max_broken_bonds"], - frag_set_layers: int = 0, - loss_fn: str = "cosine", - root_encode: str = "gnn", - embed_adduct: bool = False, - embed_collision: bool = False, - embed_instrument: bool = False, - binned_targs: bool = True, - encode_forms: bool = False, - add_hs: bool = False, - ppm_tol: float = 20.0, - **kwargs, - ): - super().__init__() - self.hidden_size = hidden_size - self.gnn_layers_n = gnn_layers - self.dropout = dropout - self.mpnn_type = mpnn_type - self.max_broken = max_broken - self.root_encode = root_encode - self.embed_adduct = embed_adduct - self.embed_collision = embed_collision - self.embed_instrument = embed_instrument - self.binned_targs = binned_targs - self.encode_forms = encode_forms - self.loss_fn_name = loss_fn - self.ppm_tol = ppm_tol - - self.output_size = max_broken * 2 + 1 - self.inten_buckets = torch.FloatTensor(np.linspace(0, self.MZ_MAX, self.NUM_BINS)) - - broken_dim = max_broken * 2 + 1 - - root_input_dim = node_feats - if root_encode == "fp": - root_input_dim = 4096 - self.root_encoder = nn.Sequential( - nn.Linear(root_input_dim, hidden_size), - nn.ReLU(), - nn.Dropout(dropout), - ) - - self.node_input = nn.Linear(node_feats, hidden_size) - - try: - import dgl.nn as dgl_nn - if mpnn_type == "PNA": - self.gnn_layers = nn.ModuleList([ - nn.Linear(hidden_size, hidden_size) - for _ in range(gnn_layers) - ]) - elif mpnn_type == "GGNN": - self.gnn_layers = nn.ModuleList([ - dgl_nn.GatedGraphConv(hidden_size, hidden_size, 1, 1) - for _ in range(gnn_layers) - ]) - else: - self.gnn_layers = nn.ModuleList([ - nn.Linear(hidden_size, hidden_size) for _ in range(gnn_layers) - ]) - except ImportError: - self.gnn_layers = nn.ModuleList([ - nn.Linear(hidden_size, hidden_size) for _ in range(gnn_layers) - ]) - - mlp_input_dim = hidden_size * 3 + broken_dim - if encode_forms: - from massspecgym.models.encoders.mist.form_embedders import get_embedder - self.form_embedder = get_embedder("abs-sines") - form_dim = self.form_embedder.full_dim - mlp_input_dim += form_dim * 2 - - self.intermediate_out = nn.Sequential( - nn.Linear(mlp_input_dim, hidden_size), - nn.ReLU(), - nn.Dropout(dropout), - nn.Linear(hidden_size, hidden_size), - nn.ReLU(), - ) - - self.output_map = nn.Linear(hidden_size, self.output_size) - self.attn_map = nn.Linear(hidden_size, self.output_size) - - def forward( - self, - graphs, - root_repr, - ind_maps, - num_frags, - broken, - collision_engs=None, - precursor_mzs=None, - adducts=None, - instruments=None, - max_add_hs=None, - max_remove_hs=None, - masses=None, - root_forms=None, - frag_forms=None, - ): - """Forward pass: predict intensities for fragment peaks. - - Returns: - Dict with 'output_binned' (binned spectrum) and 'output' (per-fragment). - """ - try: - import dgl - except ImportError: - raise ImportError("DGL required for IntenGNN") - - if isinstance(root_repr, dgl.DGLGraph): - root_h = root_repr.ndata["h"] - root_embedded = self.root_encoder(root_h) - root_repr.ndata["h"] = root_embedded - root_embeddings = dgl.mean_nodes(root_repr, "h") - else: - root_embeddings = self.root_encoder(root_repr) - - ext_root = root_embeddings[ind_maps] - - frag_h = self.node_input(graphs.ndata["h"]) - for gnn_layer in self.gnn_layers: - frag_h = torch.relu(gnn_layer(frag_h)) - - graphs.ndata["h_out"] = frag_h - avg_frags = dgl.mean_nodes(graphs, "h_out") - - broken_clamped = broken.clamp(0, self.max_broken * 2) - broken_onehot = torch.zeros(broken.size(0), self.max_broken * 2 + 1, device=broken.device) - broken_onehot.scatter_(1, broken_clamped.unsqueeze(1).long(), 1.0) - - cat_list = [ext_root, ext_root - avg_frags, avg_frags, broken_onehot] - padded_hidden = self.intermediate_out(torch.cat(cat_list, dim=-1)) - - output = torch.sigmoid(self.output_map(padded_hidden)) - attn_weights = self.attn_map(padded_hidden) - - return {"output": output, "attn_weights": attn_weights, "output_binned": output} - - def predict( - self, - graphs, - root_reprs, - ind_maps, - num_frags, - max_breaks, - adducts=None, - collision_engs=None, - instruments=None, - precursor_mzs=None, - max_add_hs=None, - max_remove_hs=None, - masses=None, - root_forms=None, - frag_forms=None, - binned_out: bool = False, - ) -> dict: - """Run inference and return predicted spectrum.""" - out = self.forward( - graphs=graphs, - root_repr=root_reprs, - ind_maps=ind_maps, - num_frags=num_frags, - broken=max_breaks, - collision_engs=collision_engs, - precursor_mzs=precursor_mzs, - adducts=adducts, - instruments=instruments, - max_add_hs=max_add_hs, - max_remove_hs=max_remove_hs, - masses=masses, - root_forms=root_forms, - frag_forms=frag_forms, - ) - if binned_out: - return {"spec": out["output_binned"]} - return {"spec": out["output"]} diff --git a/massspecgym/models/simulation/iceberg/joint_model.py b/massspecgym/models/simulation/iceberg/joint_model.py deleted file mode 100644 index f6e66e5..0000000 --- a/massspecgym/models/simulation/iceberg/joint_model.py +++ /dev/null @@ -1,115 +0,0 @@ -""" -JointModel: Combined FragGNN + IntenGNN for ICEBERG spectrum prediction. - -Wraps the fragment generation model and intensity prediction model into -a single interface for end-to-end spectrum simulation. - -Ported from external/ms-pred/src/ms_pred/dag_pred/joint_model.py. -""" - -from collections import defaultdict -from typing import Optional - -import numpy as np -import torch -import torch.nn as nn -from rdkit import Chem - -from massspecgym.models.encoders.mist.chem_constants import ELEMENT_TO_MASS, ELECTRON_MASS -from .gen_model import FragGNN -from .inten_model import IntenGNN -from .dag_data import TreeProcessor, FRAGMENT_ENGINE_PARAMS -from .magma.fragmentation import FragmentEngine - - -class JointModel(nn.Module): - """Combined ICEBERG model for spectrum prediction. - - Wraps FragGNN (fragment generation) and IntenGNN (intensity prediction) - into a unified interface. - - Args: - gen_model_obj: Trained FragGNN model. - inten_model_obj: Trained IntenGNN model. - """ - - def __init__(self, gen_model_obj: FragGNN, inten_model_obj: IntenGNN): - super().__init__() - self.gen_model_obj = gen_model_obj - self.inten_model_obj = inten_model_obj - - @classmethod - def from_checkpoints(cls, gen_checkpoint: str, inten_checkpoint: str): - """Load JointModel from separate gen and inten checkpoints.""" - gen_obj = FragGNN.__init__ # Placeholder - real loading needs pl - inten_obj = IntenGNN.__init__ - raise NotImplementedError( - "Checkpoint loading requires pytorch_lightning. Use: " - "gen = FragGNN.load_from_checkpoint(gen_ckpt); " - "inten = IntenGNN.load_from_checkpoint(inten_ckpt); " - "model = JointModel(gen, inten)" - ) - - def predict_mol( - self, - smi: str, - collision_eng: float = 40.0, - precursor_mz: float = None, - adduct: str = "[M+H]+", - threshold: float = 0.001, - device: str = "cpu", - max_nodes: int = 100, - instrument: str = None, - binned_out: bool = False, - ) -> dict: - """Predict MS/MS spectrum for a single molecule. - - Args: - smi: SMILES string. - collision_eng: Collision energy in eV. - precursor_mz: Precursor m/z (computed if None). - adduct: Adduct type string. - threshold: Minimum intensity threshold. - device: Device for computation. - max_nodes: Maximum DAG nodes. - instrument: Instrument type. - binned_out: If True, return binned spectrum. - - Returns: - Dict with 'spec' (list of {mz, intensity} dicts) and 'frag' info. - """ - mol = Chem.MolFromSmiles(smi) - if mol is None: - return {"spec": [], "frag": []} - - canonical_smi = Chem.MolToSmiles(mol) - - try: - engine = FragmentEngine(canonical_smi, **FRAGMENT_ENGINE_PARAMS) - engine.generate_fragments() - except Exception: - return {"spec": [], "frag": []} - - frag_to_entry = engine.frag_to_entry - if len(frag_to_entry) == 0: - return {"spec": [], "frag": []} - - frag_forms, frag_masses = engine.get_frag_forms() - - if precursor_mz is None and adduct: - from massspecgym.models.encoders.mist.chem_constants import ion_to_mass - ion_mass = ion_to_mass.get(adduct, ELEMENT_TO_MASS["H"] - ELECTRON_MASS) - precursor_mz = engine.full_weight + ion_mass - - spec = [] - for mass in frag_masses: - if mass > 0: - spec.append({"mz": float(mass), "intensity": 1.0 / len(frag_masses)}) - - spec = [s for s in spec if s["intensity"] >= threshold] - if spec: - max_int = max(s["intensity"] for s in spec) - for s in spec: - s["intensity"] /= max_int - - return {"spec": spec, "frag": list(frag_to_entry.keys())} diff --git a/massspecgym/models/simulation/iceberg/magma/__init__.py b/massspecgym/models/simulation/iceberg/magma/__init__.py deleted file mode 100644 index 5618689..0000000 --- a/massspecgym/models/simulation/iceberg/magma/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -""" -MAGMa-style combinatorial fragmentation engine for ICEBERG. - -Implements the FragmentEngine that enumerates molecular fragments by -combinatorial bond-breaking, producing the DAG structure needed by -ICEBERG's FragGNN and IntenGNN models. - -Ported from external/ms-pred/src/ms_pred/magma/fragmentation.py. -""" - -from .fragmentation import FragmentEngine, extend diff --git a/massspecgym/models/simulation/iceberg/magma/fragmentation.py b/massspecgym/models/simulation/iceberg/magma/fragmentation.py deleted file mode 100644 index 92e5b24..0000000 --- a/massspecgym/models/simulation/iceberg/magma/fragmentation.py +++ /dev/null @@ -1,503 +0,0 @@ -""" -MAGMa-style combinatorial fragmentation engine. - -Fragments a molecule by combinatorially removing atoms and tracking -the resulting fragment DAG. Used by ICEBERG for constructing the -fragmentation tree that the GNN models operate on. - -Ported from external/ms-pred/src/ms_pred/magma/fragmentation.py. -All references to ms_pred.common replaced with massspecgym.models.encoders.mist.chem_constants. -""" - -import numpy as np -from collections import Counter, defaultdict -from hashlib import blake2b -from typing import Tuple, List - -from rdkit import Chem - -from massspecgym.models.encoders.mist.chem_constants import ( - VALID_ELEMENTS, - ELEMENT_TO_MASS, - ELEMENT_VECTORS, - element_to_ind, - formula_to_dense, - vec_to_formula, - P_TBL, -) - -TYPEW = { - Chem.rdchem.BondType.names["AROMATIC"]: 2, - Chem.rdchem.BondType.names["DOUBLE"]: 2, - Chem.rdchem.BondType.names["TRIPLE"]: 3, - Chem.rdchem.BondType.names["SINGLE"]: 1, -} -MAX_BONDS = max(list(TYPEW.values())) + 1 -MAX_ATOM_BONDS = 6 - -HETEROW = {False: 2, True: 1} - - -def canonical_mol_from_inchi(inchi: str): - """Get canonical RDKit mol from InChI string.""" - mol = Chem.MolFromInchi(inchi) - if mol is None: - return None - smi = Chem.MolToSmiles(mol) - return Chem.MolFromSmiles(smi) - - -class FragmentEngine(object): - """Combinatorial fragmentation engine for molecular DAG construction. - - Fragments a molecule by iteratively removing atoms and tracking all - resulting substructures in a DAG. Each node is a unique fragment - (identified by WL hash), edges represent atom removals. - - Args: - mol_str: SMILES or InChI string. - max_tree_depth: Maximum depth of fragmentation tree. - max_broken_bonds: Maximum bond order of broken bonds (H-shift range). - mol_str_type: 'smiles' or 'inchi'. - mol_str_canonicalized: If True, skip canonicalization. - """ - - def __init__( - self, - mol_str: str, - max_tree_depth: int = 3, - max_broken_bonds: int = 6, - mol_str_type: str = "smiles", - mol_str_canonicalized: bool = False, - ): - if mol_str_type == "smiles": - self.smiles = mol_str - self.mol = Chem.MolFromSmiles(self.smiles) - if self.mol is None: - return - self.inchi = Chem.MolToInchi(self.mol) - if not mol_str_canonicalized: - self.mol = canonical_mol_from_inchi(self.inchi) - self.smiles = Chem.MolToSmiles(self.mol) - self.mol = Chem.MolFromSmiles(self.smiles) - elif mol_str_type == "inchi": - self.inchi = mol_str - self.mol = canonical_mol_from_inchi(self.inchi) - if self.mol is None: - return - self.smiles = Chem.MolToSmiles(self.mol) - self.mol = Chem.MolFromSmiles(self.smiles) - else: - raise NotImplementedError() - - if self.mol is None: - raise RuntimeError(f"Invalid molecule: SMILES={self.smiles}, InChI={self.inchi}") - - self.natoms = self.mol.GetNumAtoms() - Chem.Kekulize(self.mol, clearAromaticFlags=True) - - self.atom_symbols = [i.GetSymbol() for i in self.mol.GetAtoms()] - self.atom_symbols_ar = np.array(self.atom_symbols) - self.atom_hs = np.array( - [i.GetNumImplicitHs() + i.GetNumExplicitHs() for i in self.mol.GetAtoms()] - ) - self.total_hs = self.atom_hs.sum() - self.atom_weights = np.array( - [ELEMENT_TO_MASS[sym] if i.GetIsotope() == 0 else - P_TBL.GetMassForIsotope(i.GetSymbol(), i.GetIsotope()) - for sym, i in zip(self.atom_symbols, self.mol.GetAtoms())] - ) - self.atom_weights_h = self.atom_hs * ELEMENT_TO_MASS["H"] + self.atom_weights - self.full_weight = np.sum(self.atom_weights_h) - - self.bonded_atoms = [[] for _ in self.atom_symbols] - self.bonded_types = [[] for _ in self.atom_symbols] - self.bonded_atoms_np = np.zeros((self.natoms, MAX_ATOM_BONDS), dtype=int) - self.bonded_types_np = np.zeros((self.natoms, MAX_ATOM_BONDS), dtype=int) - self.num_bonds_np = np.zeros(self.natoms, dtype=int) - - self.bond_to_type = {} - self.bonds = set() - self.bonds_list = [] - self.bond_types_list = [] - self.bond_inds_list = [] - self.bondscore = {} - - for bond in self.mol.GetBonds(): - a1, a2 = bond.GetBeginAtomIdx(), bond.GetEndAtomIdx() - self.bonded_atoms[a1].append(a2) - self.bonded_atoms[a2].append(a1) - self.bonded_atoms_np[a1, self.num_bonds_np[a1]] = a2 - self.bonded_atoms_np[a2, self.num_bonds_np[a2]] = a1 - - bondbits = 1 << a1 | 1 << a2 - bondscore = ( - TYPEW[bond.GetBondType()] - * HETEROW[self.atom_symbols[a1] != "C" or self.atom_symbols[a2] != "C"] - ) - bondtype = TYPEW[bond.GetBondType()] - - self.bonded_types[a1].append(bondtype) - self.bonded_types[a2].append(bondtype) - self.bonded_types_np[a1, self.num_bonds_np[a1]] = bondtype - self.bonded_types_np[a2, self.num_bonds_np[a2]] = bondtype - self.num_bonds_np[a1] += 1 - self.num_bonds_np[a2] += 1 - - self.bond_to_type[bondbits] = bondtype - self.bondscore[bondbits] = bondscore - if bondbits not in self.bonds: - self.bonds_list.append(bondbits) - self.bond_types_list.append(bondtype) - self.bond_inds_list.append((a1, a2)) - self.bonds.add(bondbits) - - self.max_broken_bonds = max_broken_bonds - self.max_tree_depth = max_tree_depth - self.shift_buckets = np.arange(self.max_broken_bonds * 2 + 1) - self.max_broken_bonds - self.shift_bucket_inds = np.arange(self.max_broken_bonds * 2 + 1) - self.shift_bucket_masses = self.shift_buckets * ELEMENT_TO_MASS["H"] - self.frag_to_entry = {} - - def score_fragment(self, fragment): - score, breaks = 0, 0 - for bond in self.bonds: - if 0 < (fragment & bond) < bond: - score += self.bondscore[bond] - breaks += 1 - return breaks, score - - def single_mass(self, frag: int): - fragment_mass = 0.0 - for atom in range(self.natoms): - if frag & (1 << atom): - fragment_mass += self.atom_weights_h[atom] - return fragment_mass - - def formula_from_frag(self, frag: int, h_shift=0): - form_vec = np.zeros(len(VALID_ELEMENTS)) - h_pos = element_to_ind["H"] - for atom in range(self.natoms): - if frag & (1 << atom): - dense_pos = element_to_ind[self.atom_symbols[atom]] - form_vec[dense_pos] += 1 - form_vec[h_pos] += self.atom_hs[atom] - form_vec[h_pos] += h_shift - return vec_to_formula(form_vec) - - def formula_from_kept_inds(self, kept_inds): - form_vec = np.zeros(len(VALID_ELEMENTS)) - h_count = self.atom_hs[kept_inds].sum() - h_pos = element_to_ind["H"] - form_vec[h_pos] = h_count - atom_cts = Counter(self.atom_symbols_ar[kept_inds]) - for atom_type, atom_ct in atom_cts.items(): - form_vec[element_to_ind[atom_type]] = atom_ct - return vec_to_formula(form_vec) - - def atom_pass_stats(self, frag: int, depth: int = None): - fragment_mass = 0.0 - form_vec = np.zeros(len(VALID_ELEMENTS)) - h_pos = element_to_ind["H"] - for atom in range(self.natoms): - if frag & (1 << atom): - fragment_mass += self.atom_weights_h[atom] - dense_pos = element_to_ind[self.atom_symbols[atom]] - form_vec[dense_pos] += 1 - form_vec[h_pos] += self.atom_hs[atom] - form = vec_to_formula(form_vec) - frag_hs = int(form_vec[h_pos]) - max_remove = int(min(frag_hs, self.max_broken_bonds)) - max_add = int(min(self.total_hs - frag_hs, self.max_broken_bonds)) - if depth is not None: - max_remove = int(min(depth, max_remove)) - max_add = int(min(depth, max_add)) - return { - "form": form, - "base_mass": float(fragment_mass), - "frag_hs": frag_hs, - "max_remove_hs": max_remove, - "max_add_hs": max_add, - } - - def wl_hash(self, template_fragment: int) -> int: - cur_hashes = [f"{i}" for i, j, k in zip(self.atom_symbols, self.atom_hs, self.bonded_atoms)] - - def get_graph_hash(full_hashes): - counter = Counter(full_hashes) - counter_str = str(tuple(sorted(counter.items(), key=lambda x: x[0]))) - return _hash_label(counter_str) - - graph_hash = get_graph_hash(cur_hashes) - iterations = self.natoms - changed = True - ct = 0 - - while ct <= iterations and changed: - new_hashes = [] - temp_atoms = 0 - for atom in range(self.natoms): - atombit = 1 << atom - cur_hash = cur_hashes[atom] - if not atombit & template_fragment: - new_hashes.append(cur_hash) - continue - temp_atoms += 1 - neighbor_labels = [] - for targind in self.bonded_atoms[atom]: - targbit = 1 << targind - if not targbit & template_fragment: - continue - targhash = cur_hashes[targind] - bondbit = targbit | atombit - bondtype = self.bond_to_type[bondbit] - neighbor_labels.append(f"{bondtype}_{targhash}") - new_hash_str = cur_hash + "".join(sorted(neighbor_labels)) - new_hashes.append(_hash_label(new_hash_str)) - - iterations = temp_atoms - new_graph_hash = get_graph_hash(new_hashes) - changed = new_graph_hash != graph_hash - graph_hash = new_graph_hash - cur_hashes = new_hashes - ct += 1 - return graph_hash - - def get_frag_masses(self): - frag_ids, frag_inds, shift_inds, masses, scores = [], [], [], [], [] - for k, v in self.frag_to_entry.items(): - max_remove, max_add = v["max_remove_hs"], v["max_add_hs"] - frag_int = v["frag"] - base_mass = v["base_mass"] - score = v["score"] - for num_shift, shift_ind, shift_mass in zip( - self.shift_buckets, self.shift_bucket_inds, self.shift_bucket_masses - ): - if (num_shift >= -max_remove) and (num_shift <= max_add): - frag_inds.append(frag_int) - shift_inds.append(shift_ind) - masses.append(base_mass + shift_mass) - scores.append(score) - frag_ids.append(k) - return ( - np.array(frag_ids), - np.array(frag_inds), - np.array(shift_inds), - np.array(masses), - np.array(scores), - ) - - def get_frag_forms(self): - masses, form_vecs = [], [] - form_set = set() - for k, v in self.frag_to_entry.items(): - max_remove, max_add = v["max_remove_hs"], v["max_add_hs"] - base_mass = v["base_mass"] - base_form_str = v["form"] - base_form_vec = formula_to_dense(base_form_str) - for num_shift, shift_ind, shift_mass in zip( - self.shift_buckets, self.shift_bucket_inds, self.shift_bucket_masses - ): - if (num_shift >= -max_remove) and (num_shift <= max_add): - new_form_vec = base_form_vec + num_shift * ELEMENT_VECTORS[element_to_ind["H"]] - str_code = str(new_form_vec) - if str_code in form_set: - continue - masses.append(base_mass + shift_mass) - form_vecs.append(new_form_vec) - form_set.add(str_code) - return np.array(form_vecs), np.array(masses) - - def get_root_frag(self) -> int: - return (1 << self.natoms) - 1 - - def generate_fragments(self): - """Populate self.frag_to_entry with all fragments up to max_tree_depth.""" - cur_id = 0 - frag = (1 << self.natoms) - 1 - root = { - "frag": frag, "id": cur_id, - "sibling_hashes": [], "parents": [], "parent_hashes": [], - "parent_ind_removed": [], "max_broken": 0, "tree_depth": 0, - "score": self.score_fragment(frag)[1], - } - root.update(self.atom_pass_stats(frag, depth=0)) - frag_hash = self.wl_hash(frag) - self.frag_to_entry[frag_hash] = root - current_fragments = [frag_hash] - new_fragments = [] - - for step in range(self.max_tree_depth): - for frag_hash in current_fragments: - cur_parent = self.frag_to_entry[frag_hash]["id"] - fragment = self.frag_to_entry[frag_hash]["frag"] - parent_broken = self.frag_to_entry[frag_hash]["max_broken"] - cur_parent_hash = frag_hash - - for atom in range(self.natoms): - extended_fragments = self.remove_atom(fragment, atom) - sibling_hashes = set([i["new_hash"] for i in extended_fragments]) - for frag_dict in extended_fragments: - removed_atom = frag_dict["removed_atom"] - new_frag_hash = frag_dict["new_hash"] - rm_bond_t = frag_dict["rm_bond_t"] - new_frag = frag_dict["new_frag"] - temp_sibs = list(sibling_hashes.difference([new_frag_hash])) - old_entry = self.frag_to_entry.get(new_frag_hash) - max_broken = parent_broken + rm_bond_t - - if old_entry is None: - cur_id += 1 - new_entry = { - "frag": new_frag, "id": cur_id, - "parents": [cur_parent], - "parent_hashes": [cur_parent_hash], - "parent_ind_removed": [removed_atom], - "sibling_hashes": [temp_sibs], - "max_broken": max_broken, - "tree_depth": step + 1, - "score": self.score_fragment(new_frag)[1], - } - new_entry.update(self.atom_pass_stats(new_frag, depth=max_broken)) - self.frag_to_entry[new_frag_hash] = new_entry - new_fragments.append(new_frag_hash) - elif old_entry["max_broken"] == max_broken: - old_entry["parent_ind_removed"].append(removed_atom) - old_entry["parents"].append(cur_parent) - old_entry["parent_hashes"].append(cur_parent_hash) - old_entry["sibling_hashes"].append(temp_sibs) - - current_fragments = new_fragments - new_fragments = [] - - def remove_atom(self, fragment: int, atom: int) -> List[dict]: - if not ((1 << atom) & fragment): - return [] - template_fragment = fragment ^ (1 << atom) - list_ext_atoms = set([]) - extended_fragments = [] - ext_atom_to_bo = {} - - for a in self.bonded_atoms[atom]: - if (1 << a) & template_fragment: - list_ext_atoms.add(a) - bond_num = (1 << atom) | (1 << a) - ext_atom_to_bo[a] = self.bond_to_type[bond_num] - - if len(list_ext_atoms) == 1: - if template_fragment == 0: - return [] - bo = next(iter(ext_atom_to_bo.values())) - new_frag_hash = self.wl_hash(template_fragment) - extended_fragments.append({ - "new_frag": template_fragment, "new_hash": new_frag_hash, - "removed_atom": atom, "rm_bond_t": bo, - }) - else: - for a in list_ext_atoms: - is_ring = False - rm_bond_t = ext_atom_to_bo[a] - for frag_dict in extended_fragments: - if (1 << a) & frag_dict["new_frag"]: - is_ring = True - if not is_ring: - new_fragment = extend(a, self.bonded_atoms, template_fragment) - if new_fragment == 0: - continue - new_frag_hash = self.wl_hash(new_fragment) - extended_fragments.append({ - "new_frag": new_fragment, "new_hash": new_frag_hash, - "removed_atom": atom, "rm_bond_t": rm_bond_t, - }) - return extended_fragments - - def export_edges(self, frag_hashes: List[int]): - edges = [] - explored = set(frag_hashes) - for i in frag_hashes: - entry = self.frag_to_entry[i] - for p in entry["parent_hashes"]: - if p in explored: - edges.append((p, i)) - return edges - - def export_edges_dict(self, frag_hashes: List[int]): - incoming_edges = defaultdict(list) - outgoing_edges = defaultdict(list) - explored = set(frag_hashes) - for i in frag_hashes: - entry = self.frag_to_entry[i] - for p in entry["parent_hashes"]: - if p in explored: - incoming_edges[i].append(p) - outgoing_edges[p].append(i) - return incoming_edges, outgoing_edges - - def get_present_atoms(self, frag: int): - ret_inds, ret_symbs = [], [] - for atom in range(self.natoms): - if (1 << atom) & frag: - ret_inds.append(atom) - ret_symbs.append(self.atom_symbols[atom]) - return ret_inds, ret_symbs - - def get_present_edges(self, frag: int): - output_bonds, output_bond_types = [], [] - for bond, bond_inds in zip(self.bonds_list, self.bond_inds_list): - if (frag & bond) == bond: - output_bonds.append(bond_inds) - output_bond_types.append(self.bond_to_type[bond]) - return output_bond_types, output_bonds - - def get_root_frag(self) -> int: - return (1 << self.natoms) - 1 - - def frags_to_intens(self, frags: dict): - mass_to_obj = defaultdict(lambda: {}) - for k, val in frags.items(): - masses = val["base_mass"] + self.shift_bucket_masses - intens = val["intens"] - for m, i in zip(masses, intens): - if i <= 0: - continue - cur_obj = mass_to_obj[m] - if cur_obj.get("inten", 0) > 0: - if cur_obj.get("inten") < i: - cur_obj["frag_hash"] = k - cur_obj["inten"] += i - else: - cur_obj["inten"] = i - cur_obj["frag_hash"] = k - max_inten = max(*[i["inten"] for i in mass_to_obj.values()], 1e-9) - mass_to_obj = { - k: dict(inten=v["inten"] / max_inten, frag_hash=v["frag_hash"]) - for k, v in mass_to_obj.items() - } - return [dict(mz=k, **v) for k, v in mass_to_obj.items()] - - -def extend(atom: int, bonded_atoms: list, template_fragment: int): - """DFS extension of atom to other parts of the template fragment.""" - stack = [atom] - new_fragment = 0 - while len(stack) > 0: - atom = stack.pop() - for a in bonded_atoms[atom]: - atombit = 1 << a - if (not (atombit & template_fragment)) or (atombit & new_fragment): - continue - new_fragment = new_fragment | atombit - stack.append(a) - return new_fragment - - -def _hash_label(label, digest_size=32): - return blake2b(label.encode("ascii"), digest_size=digest_size).hexdigest() - - -def create_new_ids(frags): - frag_to_id = { - i: id for id, i in enumerate(sorted(frags, key=lambda x: frags[x]["tree_depth"])) - } - id_to_frag = {id: i for i, id in frag_to_id.items()} - return frag_to_id, id_to_frag diff --git a/results/de_novo.csv b/results/de_novo.csv index 85b81f4..506201e 100644 --- a/results/de_novo.csv +++ b/results/de_novo.csv @@ -1,5 +1,5 @@ Method,Top-1 Accuracy,Top-1 Accuracy CI Low,Top-1 Accuracy CI High,Top-1 MCES,Top-1 MCES CI Low,Top-1 MCES CI High,Top-1 Tanimoto,Top-1 Tanimoto CI Low,Top-1 Tanimoto CI High,Top-10 Accuracy,Top-10 Accuracy CI Low,Top-10 Accuracy CI High,Top-10 MCES,Top-10 MCES CI Low,Top-10 MCES CI High,Top-10 Tanimoto,Top-10 Tanimoto CI Low,Top-10 Tanimoto CI High,Paper,DOI,Comment,Publication date -SMILES Transformer,0.00,0.00,0.00,79.39,78.64,80.08,0.03,0.03,0.04,0.00,0.00,0.00,52.13,51.45,52.81,0.10,0.09,0.10,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -SELFIES Transformer,0.00,0.00,0.00,38.88,38.57,39.20,0.08,0.08,0.08,0.00,0.00,0.00,26.87,26.66,27.11,0.13,0.13,0.13,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -Random chemical generation,0.00,0.00,0.00,21.11,20.97,21.26,0.08,0.08,0.08,0.00,0.00,0.00,18.25,18.14,18.35,0.11,0.11,0.11,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 MS-BART,0.0107,,,16.47,,,0.23,,,0.0111,,,15.12,,,0.28,,,MS-BART: Unified Modeling of Mass Spectra and Molecules for Structure Elucidation,https://doi.org/10.48550/arXiv.2510.20615,,2025-10-23 +Random chemical generation,0.0,0.0,0.0,21.11,20.97,21.26,0.08,0.08,0.08,0.0,0.0,0.0,18.25,18.14,18.35,0.11,0.11,0.11,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 +SELFIES Transformer,0.0,0.0,0.0,38.88,38.57,39.2,0.08,0.08,0.08,0.0,0.0,0.0,26.87,26.66,27.11,0.13,0.13,0.13,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 +SMILES Transformer,0.0,0.0,0.0,79.39,78.64,80.08,0.03,0.03,0.04,0.0,0.0,0.0,52.13,51.45,52.81,0.1,0.09,0.1,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 diff --git a/results/de_novo_bonus.csv b/results/de_novo_bonus.csv index 9d2fbfa..ee0a143 100644 --- a/results/de_novo_bonus.csv +++ b/results/de_novo_bonus.csv @@ -1,12 +1,12 @@ Method,Top-1 Accuracy,Top-1 Accuracy CI Low,Top-1 Accuracy CI High,Top-1 MCES,Top-1 MCES CI Low,Top-1 MCES CI High,Top-1 Tanimoto,Top-1 Tanimoto CI Low,Top-1 Tanimoto CI High,Top-10 Accuracy,Top-10 Accuracy CI Low,Top-10 Accuracy CI High,Top-10 MCES,Top-10 MCES CI Low,Top-10 MCES CI High,Top-10 Tanimoto,Top-10 Tanimoto CI Low,Top-10 Tanimoto CI High,Paper,DOI,Comment,Publication date -SMILES Transformer,0.00,0.00,0.00,79.39,78.64,80.08,0.03,0.03,0.04,0.00,0.00,0.00,52.13,51.45,52.81,0.10,0.09,0.10,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -SELFIES Transformer,0.00,0.00,0.00,38.88,38.57,39.20,0.08,0.08,0.08,0.00,0.00,0.00,26.87,26.66,27.11,0.13,0.13,0.13,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -Random chemical generation,0.00,0.00,0.00,21.11,20.97,21.26,0.08,0.08,0.08,0.00,0.00,0.00,18.25,18.14,18.35,0.11,0.11,0.11,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -Spec2Mol,0.00,,,45.89,,,0.09,,,0.00,,,32.60,,,0.13,,,MADGEN: Mass-Spec attends to De Novo Molecular generation,https://doi.org/10.48550/arXiv.2501.01950,,2025-04-29 -MADGEN,0.0131,,,27.47,,,0.20,,,0.0154,,,16.84,,,0.26,,,MADGEN: Mass-Spec attends to De Novo Molecular generation,https://doi.org/10.48550/arXiv.2501.01950,,2025-04-29 -MIST + MSNovelist,0.00,,,45.55,,,0.06,,,0.00,,,30.13,,,0.15,,,DiffMS: Diffusion Generation of Molecules Conditioned on Mass Spectra,https://doi.org/10.48550/arXiv.2502.09571,,2025-05-27 -Spec2Mol*,0.00,,,37.76,,,0.12,,,0.00,,,29.40,,,0.16,,,DiffMS: Diffusion Generation of Molecules Conditioned on Mass Spectra,https://doi.org/10.48550/arXiv.2502.09571,,2025-05-27 -MIST + Neuraldecipher*,0.00,,,33.19,,,0.14,,,0.00,,,31.89,,,0.16,,,DiffMS: Diffusion Generation of Molecules Conditioned on Mass Spectra,https://doi.org/10.48550/arXiv.2502.09571,,2025-05-27 -DiffMS,0.0230,,,18.45,,,0.28,,,0.0425,,,14.73,,,0.39,,,DiffMS: Diffusion Generation of Molecules Conditioned on Mass Spectra,https://doi.org/10.48550/arXiv.2502.09571,,2025-05-27 -OMG_JESTR,0.0032,,,58.16,,,0.09,,,0.0255,,,56.99,,,0.14,,,Optimized De Novo Molecular Generation (OMG) for Mass Spectra Annotation Using Transfer and Reinforcement Learning,https://doi.org/10.1021/acs.analchem.5c01770,,2025-09-16 -OMG_ESP,0.0085,,,57.74,,,0.11,,,0.0282,,,56.77,,,0.15,,,Optimized De Novo Molecular Generation (OMG) for Mass Spectra Annotation Using Transfer and Reinforcement Learning,https://doi.org/10.1021/acs.analchem.5c01770,,2025-09-16 \ No newline at end of file +DiffMS,0.023,,,18.45,,,0.28,,,0.0425,,,14.73,,,0.39,,,DiffMS: Diffusion Generation of Molecules Conditioned on Mass Spectra,https://doi.org/10.48550/arXiv.2502.09571,,2025-05-27 +MADGEN,0.0131,,,27.47,,,0.2,,,0.0154,,,16.84,,,0.26,,,MADGEN: Mass-Spec attends to De Novo Molecular generation,https://doi.org/10.48550/arXiv.2501.01950,,2025-04-29 +MIST + MSNovelist,0.0,,,45.55,,,0.06,,,0.0,,,30.13,,,0.15,,,DiffMS: Diffusion Generation of Molecules Conditioned on Mass Spectra,https://doi.org/10.48550/arXiv.2502.09571,Baseline reported in DiffMS paper,2025-05-27 +MIST + Neuraldecipher,0.0,,,33.19,,,0.14,,,0.0,,,31.89,,,0.16,,,DiffMS: Diffusion Generation of Molecules Conditioned on Mass Spectra,https://doi.org/10.48550/arXiv.2502.09571,Re-evaluated baseline reported in DiffMS paper,2025-05-27 +OMG (JESTR),0.0032,,,58.16,,,0.09,,,0.0255,,,56.99,,,0.14,,,Optimized De Novo Molecular Generation (OMG) for Mass Spectra Annotation Using Transfer and Reinforcement Learning,https://doi.org/10.1021/acs.analchem.5c01770,JESTR-based candidate generation variant,2025-09-16 +OMG (ESP),0.0085,,,57.74,,,0.11,,,0.0282,,,56.77,,,0.15,,,Optimized De Novo Molecular Generation (OMG) for Mass Spectra Annotation Using Transfer and Reinforcement Learning,https://doi.org/10.1021/acs.analchem.5c01770,ESP-based candidate generation variant,2025-09-16 +Random chemical generation,0.0,0.0,0.0,21.11,20.97,21.26,0.08,0.08,0.08,0.0,0.0,0.0,18.25,18.14,18.35,0.11,0.11,0.11,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 +SELFIES Transformer,0.0,0.0,0.0,38.88,38.57,39.2,0.08,0.08,0.08,0.0,0.0,0.0,26.87,26.66,27.11,0.13,0.13,0.13,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 +SMILES Transformer,0.0,0.0,0.0,79.39,78.64,80.08,0.03,0.03,0.04,0.0,0.0,0.0,52.13,51.45,52.81,0.1,0.09,0.1,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 +Spec2Mol,0.0,,,45.89,,,0.09,,,0.0,,,32.6,,,0.13,,,MADGEN: Mass-Spec attends to De Novo Molecular generation,https://doi.org/10.48550/arXiv.2501.01950,,2025-04-29 +Spec2Mol (re-eval),0.0,,,37.76,,,0.12,,,0.0,,,29.4,,,0.16,,,DiffMS: Diffusion Generation of Molecules Conditioned on Mass Spectra,https://doi.org/10.48550/arXiv.2502.09571,Spec2Mol re-evaluated by DiffMS authors,2025-05-27 diff --git a/results/retrieval.csv b/results/retrieval.csv index 822330d..199c170 100644 --- a/results/retrieval.csv +++ b/results/retrieval.csv @@ -1,8 +1,8 @@ Method,Hit rate @ 1,Hit rate @ 1 CI Low,Hit rate @ 1 CI High,Hit rate @ 5,Hit rate @ 5 CI Low,Hit rate @ 5 CI High,Hit rate @ 20,Hit rate @ 20 CI Low,Hit rate @ 20 CI High,MCES @ 1,MCES @ 1 CI Low,MCES @ 1 CI High,Paper,DOI,Comment,Publication date -Random,0.37,0.24,0.54,2.01,1.68,2.39,8.22,7.53,8.89,30.81,30.40,31.21,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 DeepSets,1.47,1.18,1.77,6.21,5.64,6.82,19.23,18.24,20.26,25.11,24.84,25.39,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -Fingerprint FFN,2.54,2.17,2.99,7.59,6.96,8.28,20.80,19.01,20.98,24.66,24.38,24.94,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -DeepSets + Fourier features,5.24,4.71,5.83,12.58,11.80,13.42,28.21,27.10,29.36,22.13,21.85,22.43,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -MIST,14.64,13.82,15.54,34.87,33.69,36.10,59.15,57.89,60.39,15.37,15.12,15.62,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 +DeepSets + Fourier features,5.24,4.71,5.83,12.58,11.8,13.42,28.21,27.1,29.36,22.13,21.85,22.43,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 ESP,10.71,,,24.84,,,42.66,,,,,,JESTR: Joint Embedding Space Technique for Ranking Candidate Molecules for the Annotation of Untargeted Metabolomics Data,https://doi.org/10.48550/arXiv.2411.14464,,2025-06-10 -JESTR,15.13,,,36.75,,,60.32,,,,,,JESTR: Joint Embedding Space Technique for Ranking Candidate Molecules for the Annotation of Untargeted Metabolomics Data,https://doi.org/10.48550/arXiv.2411.14464,,2025-06-10 \ No newline at end of file +Fingerprint FFN,2.54,2.17,2.99,7.59,6.96,8.28,20.8,19.01,20.98,24.66,24.38,24.94,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 +JESTR,15.13,,,36.75,,,60.32,,,,,,JESTR: Joint Embedding Space Technique for Ranking Candidate Molecules for the Annotation of Untargeted Metabolomics Data,https://doi.org/10.48550/arXiv.2411.14464,,2025-06-10 +MIST,14.64,13.82,15.54,34.87,33.69,36.1,59.15,57.89,60.39,15.37,15.12,15.62,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 +Random,0.37,0.24,0.54,2.01,1.68,2.39,8.22,7.53,8.89,30.81,30.4,31.21,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 diff --git a/results/retrieval_bonus.csv b/results/retrieval_bonus.csv index 86dce5c..6fbe481 100644 --- a/results/retrieval_bonus.csv +++ b/results/retrieval_bonus.csv @@ -1,8 +1,8 @@ Method,Hit rate @ 1,Hit rate @ 1 CI Low,Hit rate @ 1 CI High,Hit rate @ 5,Hit rate @ 5 CI Low,Hit rate @ 5 CI High,Hit rate @ 20,Hit rate @ 20 CI Low,Hit rate @ 20 CI High,MCES @ 1,MCES @ 1 CI Low,MCES @ 1 CI High,Paper,DOI,Comment,Publication date -Random,3.06,2.64,3.52,11.35,10.60,12.12,27.74,26.52,28.84,13.87,13.70,14.03,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 DeepSets,4.42,3.92,4.97,14.46,13.58,15.36,30.76,29.67,31.93,15.04,14.89,15.19,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -Fingerprint FFN,5.09,4.57,5.66,16.03,15.38,15.56,31.97,30.86,33.20,14.94,14.79,15.09,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 DeepSets + Fourier features,6.56,5.95,7.16,16.46,15.58,17.35,33.46,32.39,34.59,14.14,13.98,14.31,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -MIST,9.57,8.88,10.30,22.11,21.10,23.13,41.12,39.98,42.34,12.75,12.59,12.91,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -ESP,11.05,,,27.42,,,52.20,,,,,,JESTR: Joint Embedding Space Technique for Ranking Candidate Molecules for the Annotation of Untargeted Metabolomics Data,https://doi.org/10.48550/arXiv.2411.14464,,2025-06-10 -JESTR,11.85,,,32.95,,,61.46,,,,,,JESTR: Joint Embedding Space Technique for Ranking Candidate Molecules for the Annotation of Untargeted Metabolomics Data,https://doi.org/10.48550/arXiv.2411.14464,,2025-06-10 \ No newline at end of file +ESP,11.05,,,27.42,,,52.2,,,,,,JESTR: Joint Embedding Space Technique for Ranking Candidate Molecules for the Annotation of Untargeted Metabolomics Data,https://doi.org/10.48550/arXiv.2411.14464,,2025-06-10 +Fingerprint FFN,5.09,4.57,5.66,16.03,15.38,15.56,31.97,30.86,33.2,14.94,14.79,15.09,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 +JESTR,11.85,,,32.95,,,61.46,,,,,,JESTR: Joint Embedding Space Technique for Ranking Candidate Molecules for the Annotation of Untargeted Metabolomics Data,https://doi.org/10.48550/arXiv.2411.14464,,2025-06-10 +MIST,9.57,8.88,10.3,22.11,21.1,23.13,41.12,39.98,42.34,12.75,12.59,12.91,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 +Random,3.06,2.64,3.52,11.35,10.6,12.12,27.74,26.52,28.84,13.87,13.7,14.03,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 diff --git a/results/simulation.csv b/results/simulation.csv index 819b15f..afa7158 100644 --- a/results/simulation.csv +++ b/results/simulation.csv @@ -1,5 +1,5 @@ Method,Cosine Similarity,Cosine Similarity CI Low,Cosine Similarity CI High,Jensen-Shannon Similarity,Jensen-Shannon Similarity CI Low,Jensen-Shannon Similarity CI High,Hit rate @ 1,Hit rate @ 1 CI Low,Hit rate @ 1 CI High,Hit rate @ 5,Hit rate @ 5 CI Low,Hit rate @ 5 CI High,Hit rate @ 20,Hit rate @ 20 CI Low,Hit rate @ 20 CI High,Paper,DOI,Comment,Publication date +FFN Fingerprint,0.25,0.24,0.26,0.24,0.23,0.25,8.44,7.56,9.34,21.43,20.1,22.79,38.57,36.99,40.23,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 +FraGNNet,0.52,0.51,0.53,0.47,0.46,0.48,46.64,44.98,48.26,72.56,71.18,74.0,83.58,82.34,84.75,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 +GNN,0.19,0.18,0.2,0.2,0.19,0.2,3.95,3.37,4.62,11.92,10.87,13.0,26.27,24.83,27.82,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 Precursor m/z,0.15,0.14,0.17,0.15,0.14,0.16,0.38,0.21,0.62,1.72,1.32,2.18,7.17,6.32,8.04,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -FFN Fingerprint,0.25,0.24,0.26,0.24,0.23,0.25,8.44,7.56,9.34,21.43,20.10,22.79,38.57,36.99,40.23,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -GNN,0.19,0.18,0.20,0.20,0.19,0.20,3.95,3.37,4.62,11.92,10.87,13.00,26.27,24.83,27.82,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -FraGNNet,0.52,0.51,0.53,0.47,0.46,0.48,46.64,44.98,48.26,72.56,71.18,74.00,83.58,82.34,84.75,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 \ No newline at end of file diff --git a/results/simulation_bonus.csv b/results/simulation_bonus.csv index 8472d9e..2739c47 100644 --- a/results/simulation_bonus.csv +++ b/results/simulation_bonus.csv @@ -1,7 +1,7 @@ Method,Cosine Similarity,Cosine Similarity CI Low,Cosine Similarity CI High,Jensen-Shannon Similarity,Jensen-Shannon Similarity CI Low,Jensen-Shannon Similarity CI High,Hit rate @ 1,Hit rate @ 1 CI Low,Hit rate @ 1 CI High,Hit rate @ 5,Hit rate @ 5 CI Low,Hit rate @ 5 CI High,Hit rate @ 20,Hit rate @ 20 CI Low,Hit rate @ 20 CI High,Paper,DOI,Comment,Publication date +FFN Fingerprint,0.25,0.24,0.26,0.24,0.23,0.25,7.62,6.77,8.54,22.7,21.32,24.12,44.12,42.51,45.75,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 +FraGNNet,0.52,0.51,0.53,0.47,0.46,0.48,31.93,30.4,33.5,63.2,61.64,64.76,82.7,81.45,83.93,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 +GNN,0.19,0.18,0.2,0.2,0.19,0.2,3.63,3.05,4.29,13.55,12.46,14.68,33.77,32.26,35.37,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 +ICEBERG,0.58,0.57,0.59,0.48,0.48,0.49,45.95,44.32,47.59,75.43,73.88,76.9,91.69,90.73,92.6,Neural Spectral Prediction for Structure Elucidation with Tandem Mass Spectrometry,https://doi.org/10.1101/2025.05.28.656653,,2025-06-01 +MARASON,,,,,,,34.03,32.86,35.2,64.04,62.77,65.19,85.39,84.48,86.24,Neural Graph Matching Improves Retrieval Augmented Generation in Molecular Machine Learning,https://doi.org/10.48550/arXiv.2502.17874,,2025-02-25 Precursor m/z,0.15,0.14,0.17,0.15,0.14,0.16,2.09,1.66,2.59,8.52,7.65,9.53,22.65,21.26,24.01,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -FFN Fingerprint,0.25,0.24,0.26,0.24,0.23,0.25,7.62,6.77,8.54,22.70,21.32,24.12,44.12,42.51,45.75,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -GNN,0.19,0.18,0.20,0.20,0.19,0.20,3.63,3.05,4.29,13.55,12.46,14.68,33.77,32.26,35.37,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -FraGNNet,0.52,0.51,0.53,0.47,0.46,0.48,31.93,30.40,33.50,63.20,61.64,64.76,82.70,81.45,83.93,MassSpecGym: A benchmark for the discovery and identification of molecules,https://doi.org/10.48550/arXiv.2410.23326,,2025-01-14 -MARASON,,,,,,,34.03,32.86,35.20,64.04,62.77,65.19,85.39,84.48,86.24,Neural Graph Matching Improves Retrieval Augmented Generation in Molecular Machine Learning,https://doi.org/10.48550/arXiv.2502.17874,,2025-02-25 -ICEBERG,0.58,0.57,0.59,0.48,0.48,0.49,45.95,44.32,47.59,75.43,73.88,76.90,91.69,90.73,92.60,Neural Spectral Prediction for Structure Elucidation with Tandem Mass Spectrometry,https://doi.org/10.1101/2025.05.28.656653,,2025-06-01 diff --git a/scripts/convert_to_parquet.py b/scripts/convert_to_parquet.py deleted file mode 100644 index 63f6bfc..0000000 --- a/scripts/convert_to_parquet.py +++ /dev/null @@ -1,142 +0,0 @@ -""" -Convert molecule data files (SMILES text, CSV, TSV) to the standard MassSpecGym -Parquet format for FP2Mol decoder pretraining. - -Standard Parquet schema: - smiles (string, required) - inchikey_14 (string, auto-computed) - formula (string, auto-computed) - selfies (string, optional) - safe (string, optional) - -Usage: - python scripts/convert_to_parquet.py --input molecules.txt --output molecules.parquet - python scripts/convert_to_parquet.py --input data.csv --smiles-col SMILES --output out.parquet -""" - -import argparse -import logging -from pathlib import Path - -import pandas as pd -from rdkit import Chem -from rdkit.Chem.rdMolDescriptors import CalcMolFormula -from tqdm import tqdm - -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) - - -def _compute_inchikey_14(smiles: str) -> str: - mol = Chem.MolFromSmiles(smiles) - if mol is None: - return "" - try: - ik = Chem.MolToInchiKey(mol) - return ik.split("-")[0] if ik else "" - except Exception: - return "" - - -def _compute_formula(smiles: str) -> str: - mol = Chem.MolFromSmiles(smiles) - if mol is None: - return "" - try: - f = CalcMolFormula(mol) - return f.split("+")[0].split("-")[0] - except Exception: - return "" - - -def _canonicalize(smiles: str) -> str: - mol = Chem.MolFromSmiles(smiles) - if mol is None: - return "" - return Chem.MolToSmiles(mol, isomericSmiles=False) - - -def convert_to_parquet( - input_path: str, - output_path: str, - smiles_col: str = "smiles", - add_selfies: bool = False, - add_safe: bool = False, - max_molecules: int = None, -): - """Convert a molecule file to standard Parquet format.""" - input_path = Path(input_path) - logger.info(f"Loading {input_path}...") - - if input_path.suffix in (".csv", ".tsv"): - sep = "\t" if input_path.suffix == ".tsv" else "," - df = pd.read_csv(input_path, sep=sep) - if smiles_col not in df.columns: - candidates = [c for c in df.columns if "smi" in c.lower()] - if candidates: - smiles_col = candidates[0] - logger.info(f"Using column '{smiles_col}' for SMILES") - else: - raise ValueError(f"Column '{smiles_col}' not found. Available: {list(df.columns)}") - smiles_list = df[smiles_col].dropna().tolist() - else: - smiles_list = [] - with open(input_path, "r") as f: - for line in f: - smi = line.strip().split("\t")[0].split(",")[0].split()[0] - if smi and smi.lower() != "smiles": - smiles_list.append(smi) - - if max_molecules: - smiles_list = smiles_list[:max_molecules] - - logger.info(f"Processing {len(smiles_list)} SMILES...") - records = [] - for smi in tqdm(smiles_list, desc="Processing"): - canonical = _canonicalize(smi) - if not canonical: - continue - record = { - "smiles": canonical, - "inchikey_14": _compute_inchikey_14(canonical), - "formula": _compute_formula(canonical), - } - if add_selfies: - try: - import selfies as sf - record["selfies"] = sf.encoder(canonical) - except Exception: - record["selfies"] = "" - if add_safe: - try: - from safe import encode as safe_encode - record["safe"] = safe_encode(canonical) - except Exception: - record["safe"] = "" - records.append(record) - - df_out = pd.DataFrame(records) - df_out = df_out[df_out["inchikey_14"] != ""] - - df_out.to_parquet(output_path, index=False) - logger.info(f"Wrote {len(df_out)} molecules to {output_path}") - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Convert molecule data to standard Parquet") - parser.add_argument("--input", required=True, help="Input file (SMILES txt, CSV, TSV)") - parser.add_argument("--output", required=True, help="Output Parquet file") - parser.add_argument("--smiles-col", default="smiles", help="SMILES column name for CSV/TSV") - parser.add_argument("--add-selfies", action="store_true", help="Add SELFIES column") - parser.add_argument("--add-safe", action="store_true", help="Add SAFE column") - parser.add_argument("--max-molecules", type=int, default=None, help="Max molecules to process") - args = parser.parse_args() - - convert_to_parquet( - input_path=args.input, - output_path=args.output, - smiles_col=args.smiles_col, - add_selfies=args.add_selfies, - add_safe=args.add_safe, - max_molecules=args.max_molecules, - ) diff --git a/scripts/download_data.py b/scripts/download_data.py deleted file mode 100644 index 09aea4f..0000000 --- a/scripts/download_data.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -Download MassSpecGym datasets from HuggingFace. - -Usage: - python scripts/download_data.py - python scripts/download_data.py --include-molecules -""" - -import argparse -import logging - -logging.basicConfig(level=logging.INFO) - -from massspecgym.data.download import download_massspecgym_data - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Download MassSpecGym data from HuggingFace") - parser.add_argument("--include-molecules", action="store_true", help="Also download molecule libraries") - parser.add_argument("--include-retrieval", action="store_true", default=True, help="Download retrieval candidates") - args = parser.parse_args() - - paths = download_massspecgym_data( - include_retrieval=args.include_retrieval, - include_molecules=args.include_molecules, - ) - - print(f"\nDownloaded {len(paths)} files:") - for name, path in paths.items(): - print(f" {name} -> {path}") diff --git a/scripts/leaderboard/generate_results_csvs.py b/scripts/leaderboard/generate_results_csvs.py new file mode 100644 index 0000000..d3a2c23 --- /dev/null +++ b/scripts/leaderboard/generate_results_csvs.py @@ -0,0 +1,170 @@ +""" +Regenerate results/*.csv from submissions/*/model_card.yaml. + +Baseline rows (those with no model card) are preserved unchanged. +Rows for methods that have a model card are replaced by the card's metrics. +Run on every merge to main via the update_leaderboard workflow. + +Usage: + python scripts/leaderboard/generate_results_csvs.py [--dry-run] +""" + +import argparse +import sys +import warnings +from pathlib import Path + +import pandas as pd +import yaml + +warnings.filterwarnings("ignore", category=FutureWarning, module="pandas") + +REPO_ROOT = Path(__file__).parent.parent.parent + +TASK_CSV_MAP = { + ("de_novo", "standard"): REPO_ROOT / "results" / "de_novo.csv", + ("de_novo", "bonus"): REPO_ROOT / "results" / "de_novo_bonus.csv", + ("retrieval", "standard"): REPO_ROOT / "results" / "retrieval.csv", + ("retrieval", "bonus"): REPO_ROOT / "results" / "retrieval_bonus.csv", + ("simulation", "standard"): REPO_ROOT / "results" / "simulation.csv", + ("simulation", "bonus"): REPO_ROOT / "results" / "simulation_bonus.csv", +} + +REQUIRED_COLUMNS = { + "de_novo": [ + "Method", + "Top-1 Accuracy", "Top-1 Accuracy CI Low", "Top-1 Accuracy CI High", + "Top-1 MCES", "Top-1 MCES CI Low", "Top-1 MCES CI High", + "Top-1 Tanimoto", "Top-1 Tanimoto CI Low", "Top-1 Tanimoto CI High", + "Top-10 Accuracy", "Top-10 Accuracy CI Low", "Top-10 Accuracy CI High", + "Top-10 MCES", "Top-10 MCES CI Low", "Top-10 MCES CI High", + "Top-10 Tanimoto", "Top-10 Tanimoto CI Low", "Top-10 Tanimoto CI High", + "Paper", "DOI", "Comment", "Publication date", + ], + "retrieval": [ + "Method", + "Hit rate @ 1", "Hit rate @ 1 CI Low", "Hit rate @ 1 CI High", + "Hit rate @ 5", "Hit rate @ 5 CI Low", "Hit rate @ 5 CI High", + "Hit rate @ 20", "Hit rate @ 20 CI Low", "Hit rate @ 20 CI High", + "MCES @ 1", "MCES @ 1 CI Low", "MCES @ 1 CI High", + "Paper", "DOI", "Comment", "Publication date", + ], + "simulation": [ + "Method", + "Cosine Similarity", "Cosine Similarity CI Low", "Cosine Similarity CI High", + "Jensen-Shannon Similarity", "Jensen-Shannon Similarity CI Low", "Jensen-Shannon Similarity CI High", + "Hit rate @ 1", "Hit rate @ 1 CI Low", "Hit rate @ 1 CI High", + "Hit rate @ 5", "Hit rate @ 5 CI Low", "Hit rate @ 5 CI High", + "Hit rate @ 20", "Hit rate @ 20 CI Low", "Hit rate @ 20 CI High", + "Paper", "DOI", "Comment", "Publication date", + ], +} + + +def load_model_cards() -> list[dict]: + """Return list of (card, card_path) for all non-template model cards.""" + cards = [] + submissions_dir = REPO_ROOT / "submissions" + for card_path in sorted(submissions_dir.rglob("model_card.yaml")): + if "template" in card_path.parts: + continue + try: + with open(card_path) as f: + card = yaml.safe_load(f) + if card and card.get("method_name") and card.get("results"): + cards.append((card, card_path)) + except Exception as e: + print(f"WARNING: could not parse {card_path}: {e}", file=sys.stderr) + return cards + + +def card_to_csv_row(method_name: str, entry: dict, task: str) -> dict: + """Build a CSV row dict from a model card result entry.""" + metrics = entry.get("metrics", {}) or {} + row = {"Method": method_name} + for col in REQUIRED_COLUMNS[task]: + if col == "Method": + continue + if col in ("Paper", "DOI", "Comment", "Publication date"): + key_map = { + "Paper": "paper", + "DOI": "doi", + "Comment": "comment", + "Publication date": "publication_date", + } + row[col] = entry.get(key_map[col], "") or "" + else: + row[col] = metrics.get(col, "") + return row + + +def generate(dry_run: bool = False) -> bool: + cards = load_model_cards() + + # Build index: (task, challenge) -> {method_name -> row_dict} + new_rows: dict[tuple, dict[str, dict]] = {k: {} for k in TASK_CSV_MAP} + errors = [] + + for card, card_path in cards: + method_name = card["method_name"] + for i, entry in enumerate(card.get("results", [])): + task = entry.get("task", "") + challenge = entry.get("challenge", "") + key = (task, challenge) + if key not in TASK_CSV_MAP: + errors.append(f"{card_path}: results[{i}] unknown task/challenge '{task}/{challenge}'") + continue + new_rows[key][method_name] = card_to_csv_row(method_name, entry, task) + + if errors: + for e in errors: + print(f"ERROR: {e}", file=sys.stderr) + return False + + ok = True + for (task, challenge), csv_path in TASK_CSV_MAP.items(): + if not csv_path.exists(): + print(f"WARNING: {csv_path} does not exist, skipping.", file=sys.stderr) + continue + + df = pd.read_csv(csv_path) + columns = REQUIRED_COLUMNS[task] + + # Ensure all required columns exist (add missing ones as empty) + for col in columns: + if col not in df.columns: + df[col] = "" + + # Rows with a model card are replaced; rows with no card are kept as-is. + carded_methods = set(new_rows[(task, challenge)].keys()) + df_uncarded = df[~df["Method"].apply(lambda m: str(m) in carded_methods)].copy() + + # Build new rows dataframe + new_rows_list = list(new_rows[(task, challenge)].values()) + if new_rows_list: + df_new = pd.DataFrame(new_rows_list, columns=columns) + else: + df_new = pd.DataFrame(columns=columns) + + df_out = pd.concat([df_uncarded[columns], df_new], ignore_index=True) + + if dry_run: + print(f"[dry-run] {csv_path.name}: {len(df_uncarded)} uncarded rows + {len(df_new)} card rows") + else: + df_out.to_csv(csv_path, index=False) + print(f"Written {csv_path.name}: {len(df_uncarded)} uncarded + {len(df_new)} card rows") + + return ok + + +def main() -> None: + parser = argparse.ArgumentParser(description="Regenerate results CSVs from model cards.") + parser.add_argument("--dry-run", action="store_true", + help="Print what would be written without modifying files.") + args = parser.parse_args() + success = generate(dry_run=args.dry_run) + sys.exit(0 if success else 1) + + +if __name__ == "__main__": + main() diff --git a/scripts/massspecgym_leaderboard.py b/scripts/leaderboard/massspecgym_leaderboard.py similarity index 98% rename from scripts/massspecgym_leaderboard.py rename to scripts/leaderboard/massspecgym_leaderboard.py index 060247f..a3b39db 100644 --- a/scripts/massspecgym_leaderboard.py +++ b/scripts/leaderboard/massspecgym_leaderboard.py @@ -7,9 +7,6 @@ import dash_ag_grid as dag import plotly.graph_objects as go -# --------------------------- -# 1) Load CSVs -# --------------------------- RESULTS_DIR = Path("results") DF_MAP: Dict[str, pd.DataFrame] = { @@ -36,9 +33,6 @@ def find_date_col(df: pd.DataFrame) -> str: DF_MAP[name] = df.copy() DF_MAP[name][date_col] = pd.to_datetime(DF_MAP[name][date_col], errors="coerce") -# --------------------------- -# 2) Metric discovery -# --------------------------- def list_metrics(df: pd.DataFrame) -> List[str]: """Return numeric metric columns (exclude Method, date, CI columns, and metadata).""" date_col = find_date_col(df) @@ -61,11 +55,6 @@ def has_ci(df_like: pd.DataFrame, metric: str) -> bool: bench: list_metrics(df) for bench, df in DF_MAP.items() } -# --------------------------- -# Sorting priorities per benchmark -# (col, ascending) โ€” ascending=True means smaller is better (e.g., MCES) -# Only columns that actually exist are applied. -# --------------------------- from typing import Optional SORT_SPECS: Dict[str, List[Tuple[str, bool]]] = { "De novo molecule generation": [ @@ -344,9 +333,6 @@ def format_doi_markdown(doi_url): return column_defs, data -# --------------------------- -# 3) Figure builder -# --------------------------- def build_figure(bench: str, metric: str) -> go.Figure: df = DF_MAP[bench] date_col = find_date_col(df) diff --git a/scripts/leaderboard/review_submission.py b/scripts/leaderboard/review_submission.py new file mode 100644 index 0000000..896efb9 --- /dev/null +++ b/scripts/leaderboard/review_submission.py @@ -0,0 +1,916 @@ +""" +MassSpecGym submission review script. + +Runs static analysis + LLM narrative review on a submissions// +folder and produces a structured JSON report plus a markdown summary. + +Usage: + python scripts/leaderboard/review_submission.py --submission submissions/MyModel + python scripts/leaderboard/review_submission.py --submission submissions/MyModel --output review_report.json + +Requires ANTHROPIC_API_KEY in environment for the LLM review step. +All other checks run without network access or GPU. +""" + +import argparse +import ast +import json +import os +import re +import subprocess +import sys +import tempfile +import textwrap +from dataclasses import dataclass, field, asdict +from enum import Enum +from pathlib import Path +from typing import Optional +from urllib.parse import urlparse + +import pandas as pd +import yaml + +REPO_ROOT = Path(__file__).parent.parent + +REQUIRED_COLUMNS = { + "de_novo": [ + "Method", + "Top-1 Accuracy", "Top-1 Accuracy CI Low", "Top-1 Accuracy CI High", + "Top-1 MCES", "Top-1 MCES CI Low", "Top-1 MCES CI High", + "Top-1 Tanimoto", "Top-1 Tanimoto CI Low", "Top-1 Tanimoto CI High", + "Top-10 Accuracy", "Top-10 Accuracy CI Low", "Top-10 Accuracy CI High", + "Top-10 MCES", "Top-10 MCES CI Low", "Top-10 MCES CI High", + "Top-10 Tanimoto", "Top-10 Tanimoto CI Low", "Top-10 Tanimoto CI High", + "Paper", "DOI", "Comment", "Publication date", + ], + "retrieval": [ + "Method", + "Hit rate @ 1", "Hit rate @ 1 CI Low", "Hit rate @ 1 CI High", + "Hit rate @ 5", "Hit rate @ 5 CI Low", "Hit rate @ 5 CI High", + "Hit rate @ 20", "Hit rate @ 20 CI Low", "Hit rate @ 20 CI High", + "MCES @ 1", "MCES @ 1 CI Low", "MCES @ 1 CI High", + "Paper", "DOI", "Comment", "Publication date", + ], + "simulation": [ + "Method", + "Cosine Similarity", "Cosine Similarity CI Low", "Cosine Similarity CI High", + "Jensen-Shannon Similarity", "Jensen-Shannon Similarity CI Low", "Jensen-Shannon Similarity CI High", + "Hit rate @ 1", "Hit rate @ 1 CI Low", "Hit rate @ 1 CI High", + "Hit rate @ 5", "Hit rate @ 5 CI Low", "Hit rate @ 5 CI High", + "Hit rate @ 20", "Hit rate @ 20 CI Low", "Hit rate @ 20 CI High", + "Paper", "DOI", "Comment", "Publication date", + ], +} + +METRIC_COLUMNS = { + task: [c for c in cols if not any(x in c for x in ["CI Low", "CI High", "Method", "Paper", "DOI", "Comment", "Publication date"])] + for task, cols in REQUIRED_COLUMNS.items() +} + +TASK_CSV_MAP = { + ("de_novo", "standard"): "results/de_novo.csv", + ("de_novo", "bonus"): "results/de_novo_bonus.csv", + ("retrieval", "standard"): "results/retrieval.csv", + ("retrieval", "bonus"): "results/retrieval_bonus.csv", + ("simulation", "standard"): "results/simulation.csv", + ("simulation", "bonus"): "results/simulation_bonus.csv", +} + +ORACLE_KEYWORDS = ["mist_cf", "mistcf", "mist-cf", "iceberg"] +MIST_ENCODER_KEYWORDS = ["mist", "MISTEncoder", "mist_retrieval", "MISTFingerprintRetrieval"] +MIST_BUG_PATTERN = re.compile(r"attn\s*\+=\s*attn_mask\b", re.IGNORECASE) +METRIC_OVERRIDE_PATTERN = re.compile( + r"def\s+(on_batch_end|evaluate_retrieval_step|evaluate_de_novo_step|evaluate_mces_at_1)\s*\(" +) +CUSTOM_SPLIT_PATTERN = re.compile(r"split_pth\s*=\s*['\"](?!None)[^'\"]+['\"]") +FORMULA_PREDICTOR_PATTERN = re.compile( + r"(mist.cf|mistcf|formula.*predict|predict.*formula|mist_cf|MistCF|MIST.CF)", re.IGNORECASE +) + + +class Status(str, Enum): + PASS = "PASS" + WARN = "WARN" + FAIL = "FAIL" + SKIP = "SKIP" + + +@dataclass +class CheckResult: + check_id: str + status: Status + message: str + details: str = "" + hard_fail: bool = False + + def is_blocking(self) -> bool: + return self.hard_fail and self.status == Status.FAIL + + +@dataclass +class ReviewReport: + submission_path: str + method_name: str + checks: list = field(default_factory=list) + llm_review: Optional[str] = None + llm_status: Optional[str] = None + + @property + def blocked(self) -> bool: + return any(c.is_blocking() for c in self.checks) + + @property + def warnings(self) -> list: + return [c for c in self.checks if c.status == Status.WARN] + + def to_dict(self) -> dict: + d = asdict(self) + d["blocked"] = self.blocked + d["warning_count"] = len(self.warnings) + return d + + def to_markdown(self) -> str: + lines = [] + status_icon = "**BLOCKED**" if self.blocked else ( + "**WARNINGS**" if self.warnings else "**PASSED**" + ) + lines.append(f"## MassSpecGym Submission Review: `{self.method_name}`") + lines.append(f"\n**Overall status:** {status_icon}\n") + + hard_fails = [c for c in self.checks if c.is_blocking()] + warnings = self.warnings + passes = [c for c in self.checks if c.status == Status.PASS] + skips = [c for c in self.checks if c.status == Status.SKIP] + + if hard_fails: + lines.append("### Hard failures (must be resolved before merge)\n") + for c in hard_fails: + lines.append(f"- ๐Ÿ”ด **{c.check_id}**: {c.message}") + if c.details: + lines.append(f" ```\n{textwrap.indent(c.details, ' ')}\n ```") + + if warnings: + lines.append("\n### Warnings (require maintainer sign-off)\n") + for c in warnings: + lines.append(f"- ๐ŸŸก **{c.check_id}**: {c.message}") + if c.details: + lines.append(f" ```\n{textwrap.indent(c.details, ' ')}\n ```") + + if passes: + lines.append("\n### Passed checks\n") + for c in passes: + lines.append(f"- **{c.check_id}**: {c.message}") + + if skips: + lines.append("\n### Skipped checks\n") + for c in skips: + lines.append(f"- **{c.check_id}**: {c.message}") + + if self.llm_review: + lines.append(f"\n### LLM Narrative Review ({self.llm_status})\n") + lines.append(self.llm_review) + + return "\n".join(lines) + + +def _check(report: ReviewReport, check_id: str, status: Status, message: str, + details: str = "", hard_fail: bool = False) -> None: + report.checks.append(CheckResult(check_id, status, message, details, hard_fail)) + + +# โ”€โ”€ Check implementations โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +def check_model_card_present(report: ReviewReport, submission_dir: Path) -> Optional[dict]: + card_path = submission_dir / "model_card.yaml" + if not card_path.exists(): + _check(report, "MC-PRESENT", Status.FAIL, + "model_card.yaml not found in submission directory.", + hard_fail=True) + return None + try: + with open(card_path) as f: + card = yaml.safe_load(f) + except yaml.YAMLError as e: + _check(report, "MC-PRESENT", Status.FAIL, + "model_card.yaml could not be parsed.", str(e), hard_fail=True) + return None + _check(report, "MC-PRESENT", Status.PASS, "model_card.yaml found and parseable.") + return card + + +def check_model_card_fields(report: ReviewReport, card: dict) -> None: + required_top = ["method_name", "paper_url", "code_url", "results"] + missing = [f for f in required_top if not card.get(f)] + if missing: + _check(report, "MC-FIELDS", Status.FAIL, + f"Required model_card fields missing or empty: {missing}", + hard_fail=True) + return + if not isinstance(card["results"], list) or len(card["results"]) == 0: + _check(report, "MC-FIELDS", Status.FAIL, + "model_card.yaml 'results' must be a non-empty list.", hard_fail=True) + return + for i, entry in enumerate(card["results"]): + for f in ["task", "challenge"]: + if not entry.get(f): + _check(report, "MC-FIELDS", Status.FAIL, + f"results[{i}] missing required field '{f}'.", hard_fail=True) + return + if entry["task"] not in ("de_novo", "retrieval", "simulation"): + _check(report, "MC-FIELDS", Status.FAIL, + f"results[{i}].task must be de_novo|retrieval|simulation, got '{entry['task']}'.", + hard_fail=True) + return + if entry["challenge"] not in ("standard", "bonus"): + _check(report, "MC-FIELDS", Status.FAIL, + f"results[{i}].challenge must be standard|bonus, got '{entry['challenge']}'.", + hard_fail=True) + return + if not isinstance(entry.get("metrics"), dict) or not entry["metrics"]: + _check(report, "MC-FIELDS", Status.FAIL, + f"results[{i}] missing required 'metrics' mapping.", hard_fail=True) + return + for required_meta in ["paper", "doi", "publication_date"]: + if not entry.get(required_meta): + _check(report, "MC-FIELDS", Status.FAIL, + f"results[{i}] missing required field '{required_meta}'.", hard_fail=True) + return + if card.get("random_seed") is None: + _check(report, "MC-SEED", Status.WARN, + "random_seed not specified in model_card.yaml. Document the seed used for reported results.") + else: + _check(report, "MC-SEED", Status.PASS, f"Random seed documented: {card['random_seed']}.") + _check(report, "MC-FIELDS", Status.PASS, "All required model_card fields present.") + + +def check_metrics_in_card(report: ReviewReport, card: dict) -> None: + method_name = card["method_name"] + for i, entry in enumerate(card.get("results", [])): + task = entry.get("task", "") + challenge = entry.get("challenge", "") + metrics = entry.get("metrics", {}) or {} + check_id = f"METRICS-{i}" + + metric_cols = METRIC_COLUMNS.get(task, []) + if not metric_cols: + _check(report, check_id, Status.FAIL, + f"results[{i}]: unknown task '{task}'.", hard_fail=True) + continue + + null_metrics = [c for c in metric_cols if metrics.get(c) is None] + if null_metrics: + _check(report, f"{check_id}-NULLS", Status.FAIL, + f"results[{i}]: missing or null metric values for Method='{method_name}': {null_metrics}", + hard_fail=True) + continue + + missing_cis = [] + for mc in metric_cols: + lo = metrics.get(f"{mc} CI Low") + hi = metrics.get(f"{mc} CI High") + if lo is None or hi is None: + missing_cis.append(mc) + if missing_cis: + _check(report, f"{check_id}-CI", Status.WARN, + f"results[{i}]: missing 95% bootstrap CI values for: {missing_cis}. " + "CIs are required for leaderboard merge.") + continue + + _check(report, check_id, Status.PASS, + f"Metrics valid: task={task}, challenge={challenge}, method='{method_name}'.") + + +def check_tier_integrity(report: ReviewReport, card: dict) -> None: + for i, entry in enumerate(card.get("results", [])): + uses_formula = entry.get("uses_formula_at_inference", False) + challenge = entry.get("challenge", "") + task = entry.get("task", "") + check_id = f"TIER-{i}" + if uses_formula and challenge == "standard": + _check(report, check_id, Status.FAIL, + f"results[{i}]: uses_formula_at_inference=true but challenge=standard. " + "Formula predictors used at inference must submit to the bonus tier.", + hard_fail=True) + elif not uses_formula and challenge == "bonus": + _check(report, check_id, Status.WARN, + f"results[{i}]: challenge=bonus but uses_formula_at_inference=false. " + "Confirm the bonus CSV is intentional.") + else: + _check(report, check_id, Status.PASS, + f"results[{i}]: tier integrity OK (task={task}, challenge={challenge}, " + f"uses_formula={uses_formula}).") + + +def check_pretraining(report: ReviewReport, card: dict) -> None: + pre = card.get("pretraining", {}) or {} + if not pre.get("used", False): + _check(report, "PRE-DECLARED", Status.PASS, "No external pretraining declared.") + return + + _check(report, "PRE-DECLARED", Status.PASS, "External pretraining declared.") + + criterion = pre.get("filtering_criterion", "") + if not criterion: + _check(report, "PRE-FILTER", Status.FAIL, + "Pretraining declared but filtering_criterion not specified. " + "Must be one of: exact_match | tanimoto_0.85 | tanimoto_0.70 | tanimoto_0.50 | none.", + hard_fail=True) + elif criterion == "none": + _check(report, "PRE-FILTER", Status.FAIL, + "Pretraining filtering_criterion=none. Results without any exclusion of test/val " + "molecules cannot be accepted.", hard_fail=True) + elif criterion == "exact_match": + _check(report, "PRE-FILTER", Status.WARN, + "Pretraining filtered by exact_match only. This is the minimum accepted criterion. " + "Consider Tanimoto โ‰ฅ 0.70 for stronger generalization claims (see MSG v1.5 paper ยง4).") + else: + _check(report, "PRE-FILTER", Status.PASS, + f"Pretraining filtering criterion: {criterion}.") + + inchikey_layer = pre.get("inchikey_layer_used", "") + if inchikey_layer == "27char": + _check(report, "PRE-INCHIKEY", Status.FAIL, + "inchikey_layer_used=27char uses full InChIKey matching. If stereochemistry is stripped " + "before InChI conversion (isomericSmiles=False), 27-char is functionally equivalent to " + "14-char connectivity matching. Maintainer must verify stereo stripping is applied " + "consistently in the pretraining pipeline.", + hard_fail=True) + elif inchikey_layer == "14char": + _check(report, "PRE-INCHIKEY", Status.PASS, "InChIKey matching uses 14-char connectivity layer.") + else: + _check(report, "PRE-INCHIKEY", Status.WARN, + "inchikey_layer_used not specified. Confirm 14-char (connectivity layer) was used.") + + parquet_url = pre.get("parquet_url", "") + if parquet_url: + _check(report, "PRE-SANITY", Status.WARN, + f"Pretraining parquet declared at: {parquet_url}. " + "Automated InChIKey overlap check requires local access; maintainer should run: " + "python -m massspecgym.data.sanity_check --input --inchikey-col inchikey_14") + else: + _check(report, "PRE-SANITY", Status.WARN, + "No pretraining parquet URL provided. Maintainer must verify data safety manually.") + + +def _clone_repo(url: str, tmpdir: str) -> Optional[Path]: + try: + result = subprocess.run( + ["git", "clone", "--depth=1", url, tmpdir], + capture_output=True, text=True, timeout=120 + ) + if result.returncode != 0: + return None + return Path(tmpdir) + except (subprocess.TimeoutExpired, FileNotFoundError): + return None + + +def _collect_python_files(root: Path) -> list: + return list(root.rglob("*.py")) + + +def _read_file_safe(p: Path) -> str: + try: + return p.read_text(errors="replace") + except Exception: + return "" + + +def _find_local_repo(submission_dir: Path) -> Optional[Path]: + """Return the first subdirectory of submission_dir that looks like a repo.""" + skip = {"__pycache__"} + for child in sorted(submission_dir.iterdir()): + if child.is_dir() and child.name not in skip and not child.name.startswith("."): + return child + return None + + +def check_code_repo(report: ReviewReport, card: dict, submission_dir: Path) -> Optional[Path]: + # Prefer a local repo directory submitted alongside the model card. + local_repo = _find_local_repo(submission_dir) + if local_repo is not None: + _check(report, "CODE-ACCESS", Status.PASS, + f"Local repository found in submission: {local_repo.name}/") + return local_repo + + code_url = card.get("code_url", "") + if not code_url: + _check(report, "CODE-ACCESS", Status.FAIL, + "code_url not provided in model_card.yaml and no local repo directory found.", + hard_fail=True) + return None + + parsed = urlparse(code_url) + if parsed.scheme not in ("http", "https") or not parsed.netloc: + _check(report, "CODE-ACCESS", Status.FAIL, + f"code_url '{code_url}' does not look like a valid URL.", hard_fail=True) + return None + + tmpdir = tempfile.mkdtemp(prefix="msgym_review_") + repo_path = _clone_repo(code_url, tmpdir) + if repo_path is None: + _check(report, "CODE-ACCESS", Status.WARN, + f"Could not clone code repository: {code_url}. " + "Code-level checks skipped; maintainer must review manually.") + return None + + _check(report, "CODE-ACCESS", Status.PASS, f"Code repository cloned: {code_url}.") + return repo_path + + +def check_mist_batching_bug(report: ReviewReport, card: dict, repo_path: Optional[Path]) -> None: + if not card.get("uses_mist_encoder", False): + _check(report, "I1-MIST-BUG", Status.SKIP, "uses_mist_encoder=false, check skipped.") + return + if repo_path is None: + _check(report, "I1-MIST-BUG", Status.FAIL, + "uses_mist_encoder=true but repository not accessible. " + "Cannot verify -inf attention mask fix. Provide accessible code repository.", + hard_fail=True) + return + + py_files = _collect_python_files(repo_path) + buggy_files = [] + for p in py_files: + src = _read_file_safe(p) + if MIST_BUG_PATTERN.search(src): + buggy_files.append(str(p.relative_to(repo_path))) + + if buggy_files: + _check(report, "I1-MIST-BUG", Status.FAIL, + "MIST batching bug detected: found 'attn += attn_mask' without -inf mask fill. " + "This inflates Tanimoto similarity from 0.37 to 0.52 and de novo Top-1 by ~17 pp.", + details="\n".join(buggy_files), + hard_fail=True) + else: + _check(report, "I1-MIST-BUG", Status.PASS, + "No MIST batching bug pattern found in repository.") + + +def check_metric_overrides(report: ReviewReport, repo_path: Optional[Path]) -> None: + if repo_path is None: + _check(report, "I2-METRIC-OVERRIDE", Status.SKIP, "Repository not accessible, check skipped.") + return + + py_files = _collect_python_files(repo_path) + flagged = [] + for p in py_files: + src = _read_file_safe(p) + for m in METRIC_OVERRIDE_PATTERN.finditer(src): + rel = str(p.relative_to(repo_path)) + line_no = src[:m.start()].count("\n") + 1 + flagged.append(f"{rel}:{line_no}: {m.group(0)}") + + if flagged: + _check(report, "I2-METRIC-OVERRIDE", Status.WARN, + "Custom metric method overrides found. Verify these delegate to MassSpecGym parent ABCs " + "and do not re-implement metric computation.", + details="\n".join(flagged)) + else: + _check(report, "I2-METRIC-OVERRIDE", Status.PASS, + "No metric override patterns found.") + + +def check_official_split(report: ReviewReport, card: dict, repo_path: Optional[Path]) -> None: + if not card.get("uses_official_split", True): + _check(report, "I3-SPLIT", Status.WARN, + "uses_official_split=false declared. Maintainer must verify custom split is scientifically justified.") + return + if repo_path is None: + _check(report, "I3-SPLIT", Status.SKIP, "Repository not accessible, check skipped.") + return + + py_files = _collect_python_files(repo_path) + flagged = [] + for p in py_files: + src = _read_file_safe(p) + for m in CUSTOM_SPLIT_PATTERN.finditer(src): + rel = str(p.relative_to(repo_path)) + line_no = src[:m.start()].count("\n") + 1 + flagged.append(f"{rel}:{line_no}: {m.group(0)}") + + if flagged: + _check(report, "I3-SPLIT", Status.WARN, + "Custom split_pth argument found. Confirm the official MassSpecGym split is used.", + details="\n".join(flagged)) + else: + _check(report, "I3-SPLIT", Status.PASS, "No custom split path detected.") + + +def check_smiles_canonicalization(report: ReviewReport) -> None: + try: + from rdkit import Chem + except ImportError: + _check(report, "S1-CANON", Status.SKIP, "RDKit not available, canonicalization check skipped.") + return + + candidate_files = list((REPO_ROOT / "data").rglob("*candidates*")) + \ + list((REPO_ROOT / "data").rglob("*retrieval*")) + candidate_files = [f for f in candidate_files if f.suffix in (".csv", ".parquet", ".tsv")] + + if not candidate_files: + _check(report, "S1-CANON", Status.SKIP, + "No local candidate set files found; canonicalization check skipped. " + "Maintainer should verify the submission uses the v1.5 pre-canonicalized candidate set.") + return + + non_canonical_total = 0 + checked_total = 0 + for cf in candidate_files[:2]: + try: + df = pd.read_parquet(cf) if cf.suffix == ".parquet" else pd.read_csv(cf, sep=None, engine="python") + except Exception: + continue + smiles_col = next((c for c in df.columns if "smiles" in c.lower()), None) + if smiles_col is None: + continue + smiles_list = df[smiles_col].dropna().tolist()[:5000] + for smi in smiles_list: + checked_total += 1 + try: + mol = Chem.MolFromSmiles(smi) + if mol is None: + continue + if smi != Chem.MolToSmiles(mol): + non_canonical_total += 1 + except Exception: + continue + + if checked_total == 0: + _check(report, "S1-CANON", Status.SKIP, + "Could not load candidate SMILES from local data files.") + return + + if non_canonical_total > 0: + _check(report, "S1-CANON", Status.FAIL, + f"{non_canonical_total}/{checked_total} non-canonical SMILES found in candidate set. " + "A spectrum-blind format classifier achieves >99% Recall@1 on non-canonicalized sets.", + hard_fail=True) + else: + _check(report, "S1-CANON", Status.PASS, + f"All {checked_total} sampled candidate SMILES are RDKit-canonical.") + + +def check_oracle_safety(report: ReviewReport, card: dict, repo_path: Optional[Path]) -> None: + uses_mist_cf = card.get("uses_mist_cf", False) + uses_iceberg = card.get("uses_iceberg", False) + + if not uses_mist_cf and not uses_iceberg: + _check(report, "L3-ORACLE", Status.PASS, "No MIST-CF or ICEBERG oracles declared.") + return + + issues = [] + if uses_mist_cf: + ver = card.get("mist_cf_version", "") + if "v1.5" not in str(ver) and "data_safe" not in str(ver): + issues.append( + f"uses_mist_cf=true but mist_cf_version='{ver}' does not confirm v1.5 data-safe version. " + "The public MIST-CF checkpoint overlaps with the MSG test set." + ) + if uses_iceberg: + ver = card.get("iceberg_version", "") + if "v1.5" not in str(ver) and "data_safe" not in str(ver): + issues.append( + f"uses_iceberg=true but iceberg_version='{ver}' does not confirm v1.5 data-safe version. " + "ICEBERG trained on test molecules inflates downstream metrics (see MSG v1.5 ยง4.2)." + ) + + if repo_path is not None: + py_files = _collect_python_files(repo_path) + for p in py_files: + src = _read_file_safe(p) + for kw in ORACLE_KEYWORDS: + if kw in src.lower(): + issues.append( + f"Oracle keyword '{kw}' found in {p.relative_to(repo_path)}. " + "Confirm data-safe v1.5 version is used." + ) + break + + if issues: + _check(report, "L3-ORACLE", Status.WARN, + "Oracle safety requires manual verification.", + details="\n".join(issues)) + else: + _check(report, "L3-ORACLE", Status.PASS, "Oracle versions declared as data-safe.") + + +def check_formula_leakage_in_code(report: ReviewReport, card: dict, repo_path: Optional[Path]) -> None: + for i, entry in enumerate(card.get("results", [])): + if entry.get("challenge") != "standard": + continue + if repo_path is None: + _check(report, f"L4-FORMULA-{i}", Status.SKIP, + "Repository not accessible; formula leakage check skipped.") + continue + py_files = _collect_python_files(repo_path) + flagged = [] + for p in py_files: + src = _read_file_safe(p) + if FORMULA_PREDICTOR_PATTERN.search(src): + rel = str(p.relative_to(repo_path)) + flagged.append(rel) + if flagged: + _check(report, f"L4-FORMULA-{i}", Status.WARN, + f"results[{i}] (challenge=standard): formula predictor references found in code. " + "If formula is used to pre-filter candidates at inference, this must be submitted " + "to the bonus tier.", + details="\n".join(flagged)) + else: + _check(report, f"L4-FORMULA-{i}", Status.PASS, + f"results[{i}]: no formula predictor usage detected for standard-tier submission.") + + +# โ”€โ”€ LLM review โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +def _fetch_arxiv_html(arxiv_url: str) -> Optional[str]: + import urllib.request + arxiv_id = None + patterns = [ + r"arxiv\.org/abs/([0-9]{4}\.[0-9]+)", + r"arxiv\.org/pdf/([0-9]{4}\.[0-9]+)", + ] + for pat in patterns: + m = re.search(pat, arxiv_url) + if m: + arxiv_id = m.group(1) + break + if arxiv_id is None: + return None + html_url = f"https://ar5iv.labs.arxiv.org/html/{arxiv_id}" + try: + req = urllib.request.Request(html_url, headers={"User-Agent": "MassSpecGym-review/1.0"}) + with urllib.request.urlopen(req, timeout=20) as resp: + content = resp.read().decode("utf-8", errors="replace") + # Strip HTML tags crudely but keep text + content = re.sub(r"<[^>]+>", " ", content) + content = re.sub(r"\s+", " ", content).strip() + return content[:60000] # cap at 60k chars + except Exception: + return None + + +def _fetch_url_text(url: str) -> Optional[str]: + import urllib.request + try: + req = urllib.request.Request(url, headers={"User-Agent": "MassSpecGym-review/1.0"}) + with urllib.request.urlopen(req, timeout=15) as resp: + ct = resp.headers.get("Content-Type", "") + if "pdf" in ct.lower(): + return None # can't parse PDF here + content = resp.read().decode("utf-8", errors="replace") + content = re.sub(r"<[^>]+>", " ", content) + content = re.sub(r"\s+", " ", content).strip() + return content[:40000] + except Exception: + return None + + +def _fetch_github_readme(code_url: str) -> Optional[str]: + import urllib.request + m = re.match(r"https?://github\.com/([^/]+/[^/]+)", code_url) + if not m: + return None + slug = m.group(1).rstrip("/") + for branch in ("main", "master"): + raw_url = f"https://raw.githubusercontent.com/{slug}/{branch}/README.md" + try: + req = urllib.request.Request(raw_url, headers={"User-Agent": "MassSpecGym-review/1.0"}) + with urllib.request.urlopen(req, timeout=10) as resp: + return resp.read().decode("utf-8", errors="replace")[:10000] + except Exception: + continue + return None + + +def _collect_repo_context(repo_path: Path, max_chars: int = 40000) -> str: + """Read Python/config files from repo_path and return concatenated text, capped at max_chars.""" + # Prioritize files likely to contain model/eval logic + PRIORITY_GLOBS = ["**/*.py", "**/*.yaml", "**/*.yml", "**/*.json", "**/*.sh", "**/*.md"] + SKIP_DIRS = {".git", "__pycache__", ".venv", "venv", "node_modules", ".mypy_cache"} + + seen: set = set() + files: list[tuple[int, Path]] = [] # (priority, path) + + for priority, glob in enumerate(PRIORITY_GLOBS): + for p in repo_path.rglob(glob): + if any(part in SKIP_DIRS for part in p.parts): + continue + if p in seen: + continue + seen.add(p) + files.append((priority, p)) + + files.sort(key=lambda x: (x[0], x[1])) + + parts = [] + total = 0 + for _, p in files: + try: + text = p.read_text(errors="replace") + except Exception: + continue + rel = p.relative_to(repo_path) + header = f"\n### {rel}\n" + chunk = header + text + if total + len(chunk) > max_chars: + remaining = max_chars - total - len(header) + if remaining > 200: + parts.append(header + text[:remaining] + "\n[truncated]") + break + parts.append(chunk) + total += len(chunk) + + return "".join(parts) + + +def run_llm_review(report: ReviewReport, card: dict, submission_dir: Path) -> None: + api_key = os.environ.get("ANTHROPIC_API_KEY") + if not api_key: + _check(report, "LLM-REVIEW", Status.SKIP, + "ANTHROPIC_API_KEY not set; LLM review skipped.") + return + + try: + import anthropic + except ImportError: + _check(report, "LLM-REVIEW", Status.SKIP, + "anthropic package not installed; LLM review skipped.") + return + + sections = [] + sections.append("## Model card\n```yaml\n" + yaml.dump(card, default_flow_style=False) + "\n```") + + paper_url = card.get("paper_url", "") + paper_text = None + if paper_url: + paper_text = _fetch_arxiv_html(paper_url) or _fetch_url_text(paper_url) + if paper_text: + sections.append(f"## Paper text (fetched from {paper_url}, truncated)\n{paper_text[:40000]}") + else: + sections.append(f"## Paper text\nCOULD NOT FETCH: {paper_url}") + _check(report, "LLM-PAPER-ACCESS", Status.WARN, + f"Paper URL not accessible: {paper_url}. LLM review will proceed without paper text.") + + code_url = card.get("code_url", "") + + # Prefer local repo dir over fetching README from remote + local_repo = _find_local_repo(submission_dir) + if local_repo is not None: + repo_context = _collect_repo_context(local_repo) + sections.append( + f"## Submitted repository code ({local_repo.name}/)\n{repo_context}" + ) + else: + readme_text = _fetch_github_readme(code_url) if code_url else None + if readme_text: + sections.append(f"## Code README (fetched from {code_url})\n{readme_text}") + elif code_url: + sections.append(f"## Code README\nCOULD NOT FETCH README from {code_url}") + _check(report, "LLM-CODE-ACCESS", Status.WARN, + f"Could not fetch README from code repository: {code_url}.") + + auto_report_summary = "\n".join( + f"- {c.check_id}: {c.status} โ€” {c.message}" for c in report.checks + ) + sections.append(f"## Automated check results so far\n{auto_report_summary}") + + context = "\n\n".join(sections) + + skill_md_path = REPO_ROOT / "skills" / "review" / "SKILL.md" + if skill_md_path.exists(): + skill_md = skill_md_path.read_text() + # Strip YAML frontmatter if present + if skill_md.startswith("---"): + end = skill_md.find("---", 3) + skill_md = skill_md[end + 3:].lstrip() if end != -1 else skill_md + system_prompt = ( + "You are an automated reviewer acting on behalf of the MassSpecGym maintainers. " + "The following is the maintainer review guide โ€” follow it as your instructions.\n\n" + + skill_md + + "\n\nYou have access to the submitted code (when provided). " + "For every metric the submission reports, trace the actual computation path in the code " + "and cite the specific file and line. If the code delegates to MassSpecGym parent ABCs " + "without overriding, say so explicitly โ€” that is the correct pattern. " + "Do not use emoji in your response. Use plain text only." + ) + else: + system_prompt = ( + "You are an expert reviewer for the MassSpecGym benchmark. " + "Identify data leakage, shortcut learning, metric implementation bugs, " + "and tier integrity issues. Be specific and cite file:line when code is available. " + "Do not use emoji in your response. Use plain text only." + ) + + user_prompt = f"""Review this MassSpecGym leaderboard submission for evaluation issues. + +{context} + +Provide a structured review with: +1. A one-sentence verdict (APPROVE / WARN / REJECT) +2. Metric implementation audit: for each reported metric, state whether the implementation matches the MassSpecGym spec (cite file:line if code is available), or flag the deviation +3. Other specific issues found, if any, with references to the paper/code evidence +4. Items that require human maintainer judgment +4. Items that look clean + +Be concise. Flag real issues only โ€” do not invent problems that are not evidenced. Do not use emoji.""" + + client = anthropic.Anthropic(api_key=api_key) + try: + response = client.messages.create( + model="claude-sonnet-4-6", + max_tokens=2000, + messages=[{"role": "user", "content": user_prompt}], + system=system_prompt, + ) + llm_text = response.content[0].text + verdict_line = llm_text.split("\n")[0].upper() + if "REJECT" in verdict_line: + llm_status = "REJECT" + elif "WARN" in verdict_line: + llm_status = "WARN" + else: + llm_status = "APPROVE" + report.llm_review = llm_text + report.llm_status = llm_status + except Exception as e: + _check(report, "LLM-REVIEW", Status.WARN, + f"LLM review call failed: {e}") + + +# โ”€โ”€ Main โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +def review(submission_dir: Path) -> ReviewReport: + method_name = submission_dir.name.replace("_", " ") + report = ReviewReport( + submission_path=str(submission_dir), + method_name=method_name, + ) + + card = check_model_card_present(report, submission_dir) + if card is None: + return report + + if card.get("method_name"): + report.method_name = card["method_name"] + + check_model_card_fields(report, card) + check_metrics_in_card(report, card) + check_tier_integrity(report, card) + check_pretraining(report, card) + check_smiles_canonicalization(report) + + repo_path = check_code_repo(report, card, submission_dir) + + check_mist_batching_bug(report, card, repo_path) + check_metric_overrides(report, repo_path) + check_official_split(report, card, repo_path) + check_oracle_safety(report, card, repo_path) + check_formula_leakage_in_code(report, card, repo_path) + + run_llm_review(report, card, submission_dir) + + return report + + +def main() -> None: + parser = argparse.ArgumentParser(description="Review a MassSpecGym leaderboard submission.") + parser.add_argument("--submission", required=True, + help="Path to submissions// directory") + parser.add_argument("--output", default="review_report.json", + help="Output path for JSON report (default: review_report.json)") + parser.add_argument("--markdown", default=None, + help="Output path for markdown summary (default: stdout)") + args = parser.parse_args() + + submission_dir = Path(args.submission) + if not submission_dir.exists(): + print(f"ERROR: submission directory not found: {submission_dir}", file=sys.stderr) + sys.exit(1) + + report = review(submission_dir) + + with open(args.output, "w") as f: + json.dump(report.to_dict(), f, indent=2, default=str) + + md = report.to_markdown() + if args.markdown: + Path(args.markdown).write_text(md) + else: + print(md) + + if report.blocked: + print(f"\nREVIEW BLOCKED: {sum(1 for c in report.checks if c.is_blocking())} hard failure(s).", + file=sys.stderr) + sys.exit(1) + elif report.warnings: + print(f"\nREVIEW PASSED WITH {len(report.warnings)} WARNING(S). Maintainer sign-off required.", + file=sys.stderr) + sys.exit(0) + else: + print("\nREVIEW PASSED.", file=sys.stderr) + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/scripts/run.py b/scripts/run.py index d99dfb7..b845a47 100644 --- a/scripts/run.py +++ b/scripts/run.py @@ -17,9 +17,8 @@ from massspecgym.models.retrieval import ( FingerprintFFNRetrieval, FromDictRetrieval, RandomRetrieval, DeepSetsRetrieval ) -from massspecgym.models.de_novo import SmilesTransformer, FRIGIDDecoder, MolForgeDecoder, DiffMSDecoder +from massspecgym.models.de_novo import SmilesTransformer from massspecgym.models.tokenizers import SmilesBPETokenizer, SelfiesTokenizer -from massspecgym.data.fp2mol_dataset import FP2MolDataset from massspecgym.definitions import MASSSPECGYM_TEST_RESULTS_DIR @@ -112,25 +111,6 @@ # 3. FromDict (for evaluating given fingerprints) parser.add_argument('--dct_path', type=str, default=None) -# - FP2Mol decoders (FRIGID, MolForge, DiffMS) -parser.add_argument('--training_mode', type=str, default='spec2mol', - choices=['spec2mol', 'fp2mol_pretrain'], - help='Training mode for FP2Mol models: spec2mol (with encoder) or fp2mol_pretrain (decoder only)') -parser.add_argument('--molecule_library', type=str, default=None, - help='Path to molecule library (SMILES file) for fp2mol_pretrain mode') -parser.add_argument('--exclude_inchikeys', type=str, default=None, - help='Path to InChIKey exclusion list for data safety') -parser.add_argument('--encoder_checkpoint', type=str, default=None, - help='Path to pretrained MIST encoder checkpoint') -parser.add_argument('--decoder_checkpoint', type=str, default=None, - help='Path to pretrained decoder checkpoint') -parser.add_argument('--num_generation_samples', type=int, default=10, - help='Number of molecules to generate per spectrum') -parser.add_argument('--mol_repr', type=str, default='smiles', - choices=['smiles', 'selfies', 'safe'], - help='Molecular representation for FP2Mol training data') - - def main(args): # Seed everything pl.seed_everything(args.seed) @@ -162,19 +142,11 @@ def main(args): candidates_pth=args.candidates_pth, ) elif args.task == 'de_novo': - if args.training_mode == 'fp2mol_pretrain' and args.molecule_library is not None: - dataset = FP2MolDataset( - smiles_source=args.molecule_library, - mol_repr=args.mol_repr, - fp_bits=args.fp_size, - exclude_inchikeys=args.exclude_inchikeys, - ) - else: - dataset = MassSpecDataset( - pth=args.dataset_pth, - spec_transform=SpecTokenizer(n_peaks=args.n_peaks, matchms_kwargs=dict(mz_to=args.max_mz)), - mol_transform={'formula': MolToFormulaVector(), 'mol': None} if args.use_chemical_formula else None - ) + dataset = MassSpecDataset( + pth=args.dataset_pth, + spec_transform = SpecTokenizer(n_peaks=args.n_peaks, matchms_kwargs=dict(mz_to=args.max_mz)), + mol_transform={'formula': MolToFormulaVector(), 'mol': None} if args.use_chemical_formula else None + ) else: raise NotImplementedError(f"Task {args.task} not implemented.") @@ -247,27 +219,6 @@ def main(args): chemical_formula=args.use_chemical_formula, **common_kwargs ) - elif args.model == 'frigid': - model = FRIGIDDecoder( - training_mode=args.training_mode, - encoder_checkpoint=args.encoder_checkpoint, - num_generation_samples=args.num_generation_samples, - **common_kwargs - ) - elif args.model == 'molforge': - model = MolForgeDecoder( - training_mode=args.training_mode, - encoder_checkpoint=args.encoder_checkpoint, - num_generation_samples=args.num_generation_samples, - **common_kwargs - ) - elif args.model == 'diffms': - model = DiffMSDecoder( - training_mode=args.training_mode, - encoder_checkpoint=args.encoder_checkpoint, - num_generation_samples=args.num_generation_samples, - **common_kwargs - ) else: raise NotImplementedError(f"Model {args.model} not implemented.") else: diff --git a/setup.py b/setup.py index 7cb888f..3212268 100644 --- a/setup.py +++ b/setup.py @@ -40,6 +40,7 @@ "black==24.4.2", "pytest==8.2.1", "pytest-cov==5.0.0", + "pyarrow" ], "notebooks": [ "jupyter==1.0.0", @@ -47,12 +48,7 @@ "h5py==3.11.0", "scikit-learn==1.5.0", "pandarallel==1.6.5", - ], - "fp2mol": [ - "transformers>=4.30.0", - "sentencepiece>=0.1.99", - "safe-mol>=0.1.0", - ], + ] }, python_requires='>=3.11', classifiers=[ diff --git a/skills/review/SKILL.md b/skills/review/SKILL.md new file mode 100644 index 0000000..39b40c3 --- /dev/null +++ b/skills/review/SKILL.md @@ -0,0 +1,179 @@ +--- +name: review +description: Maintainer guide for reviewing MassSpecGym leaderboard submissions. Covers interpreting the automated review report, performing judgment calls the automation cannot make, and approving or rejecting PRs. The automated review (scripts/leaderboard/review_submission.py, triggered by the review_submission GH Action) handles deterministic checks; this guide covers the residual human review. +--- + +# MassSpecGym Submission Review โ€” Maintainer Guide + +## Role of this guide + +Every leaderboard PR triggers `scripts/leaderboard/review_submission.py` automatically and posts a structured report as a PR comment. That report handles all deterministic checks (schema, CIs, tier integrity, MIST bug, pretraining filter, metric overrides). **Your job as maintainer is to:** + +1. Read the automated report and triage any WARNINGs that require judgment +2. Fetch and read the paper if the automated LLM review flagged concerns or couldn't access the paper +3. Check items the automation explicitly cannot verify (listed below) +4. Approve or request changes + +Hard failures in the automated report must be resolved by the author before you even look at the PR. Do not override hard failures without a documented reason. + +--- + +## Submission requirements (what a valid PR must contain) + +1. A new row in the correct `results/*.csv` with all required metrics and 95% bootstrap CIs +2. A `submissions//model_card.yaml` filled from the template + +The method name in the CSV `Method` column must exactly match `method_name` in `model_card.yaml` (underscored folder name, spaced method name). See `submissions/SUBMISSION_GUIDE.md`. + +--- + +## Step 1: Read the automated report + +The PR comment from the review bot contains: + +- **Hard failures** โ€” must be fixed; CI blocks merge +- **Warnings** โ€” require your sign-off; use a PR review comment to document your decision +- **LLM narrative review** โ€” treat as a second opinion; verify any specific issues it flags + +For warnings, document your reasoning inline on the PR before approving. + +--- + +## Step 2: Things the automation cannot check โ€” do these manually + +### 2a. Paper methods section vs. model card + +Read the paper's methods/data section and cross-check against `model_card.yaml`: + +- Does the paper describe using MIST-CF at inference to pre-filter candidates in the **mass-based** (standard) challenge? If yes and the model is submitted to `results/retrieval.csv` (not bonus), reject. +- Does the paper describe pretraining on data sources *not listed* in the model card? Flag the discrepancy. +- Does the paper use ICEBERG-generated spectra for pretraining? Check which ICEBERG version (data-safe v1.5 or upstream). If unclear, ask the author. +- Does the paper's reported number match the CSV entry? Values that differ from the paper by >0.5 pp on the primary metric need explanation. + +### 2b. Spectrum-blind shortcut check (S2) + +If the model is a retrieval model, mentally check: could a model that ignores the spectrum entirely (ranking purely by PubChem deposition frequency or SMILES format) achieve similar results? + +The PubChem frequency-prior baseline achieves >90% Recall@1 on non-corrected datasets. If the submission's Recall@1 is at or below this level, it may not be learning from spectra at all. Ask the author to compare against the frequency-prior baseline if not already included. + +**Spectrum-blind classifier test (run if suspicious):** A rule-based RDKit format check (`smiles != Chem.MolToSmiles(Chem.MolFromSmiles(smiles))`) achieves >99% Recall@1 on non-canonicalized datasets. If the candidate set for this submission is non-standard, ask the author to confirm the v1.5 pre-canonicalized candidate set is used. + +If you have access to compute: train or run a version of the model with the spectral input zeroed out or permuted. If performance stays substantially above random (~1/pool_size), the model likely exploits a spurious correlation and should be investigated further before acceptance. + +### 2c. Pretraining data โ€” if no parquet provided + +If `pretraining.used=true` but no parquet URL is given, ask the author to either: +- Provide a public parquet for the InChIKey overlap check, or +- Run `python -m massspecgym.data.sanity_check --input their_data.parquet --inchikey-col inchikey_14` themselves and share the output + +Do not accept claims of data safety without this check if pretraining is declared. + +### 2d. Reproducibility spot-check + +If the submission includes a checkpoint or inference script, spot-check one metric: + +```bash +# In the massspecgym conda environment (Python 3.11) +git clone +cd MassSpecGym +pip install -e ".[dev]" +python scripts/run.py \ + --job_key review_run \ + --run_name _review \ + --test_only \ + --no_wandb \ + --seed 42 +``` + +A discrepancy >0.5 pp on the primary metric requires explanation. If the author cannot provide a reproducible checkpoint, note this in your review but it is not grounds for automatic rejection โ€” reproducibility is aspirational for submissions without public checkpoints. + +--- + +## Step 3: Metric specifications (reference) + +All submitted metrics must match these pinned implementations: + +| Metric | Specification | +|--------|--------------| +| InChIKey hit rate | First 14 characters (connectivity layer) only โ€” **not** full 27-char | +| Tanimoto similarity | Morgan ECFP4, radius=2, 2048 bits | +| MCES distance | `threshold=15`, `always_stronger_bound=True` โ€” see `massspecgym/utils.py:MyopicMCES` | +| Cosine similarity | Standard MS/MS cosine as in `massspecgym` | +| Jensen-Shannon similarity | As in `massspecgym` | + +**Do not accept** metric implementations reimported from third-party codebases unless independently verified against the specifications above. + +--- + +## Step 4: Required metrics per task + +### De novo (standard and bonus) +`Top-1 Accuracy`, `Top-1 MCES`, `Top-1 Tanimoto`, `Top-10 Accuracy`, `Top-10 MCES`, `Top-10 Tanimoto` โ€” all required, all with CIs. + +### Retrieval (standard) +`Hit rate @ 1`, `Hit rate @ 5`, `Hit rate @ 20`, `MCES @ 1` โ€” all required, all with CIs. + +### Retrieval (bonus) +`Hit rate @ 1`, `Hit rate @ 5`, `Hit rate @ 20`, `MCES @ 1` โ€” all required, all with CIs. + +### Simulation (standard and bonus) +`Cosine Similarity`, `Jensen-Shannon Similarity`, `Hit rate @ 1`, `Hit rate @ 5`, `Hit rate @ 20` โ€” all required, all with CIs. + +Standard and bonus variants must not be compared in the same table row. A model submitted to both must have two separate CSV rows. + +--- + +## Step 5: MIST batching bug (I1) โ€” background + +If a submission uses the MIST encoder from an external codebase (not `massspecgym/models/encoders/mist/`), verify the attention masking in batched inference. The original MIST encoder added `attn += attn_mask` without first converting the boolean mask to `-inf`, which allows padding tokens to contribute to the softmax. The v1.5 MassSpecGym MIST encoder has this fixed. + +**Impact if not fixed:** Tanimoto similarity inflates from 0.37 to 0.52; de novo Top-1 inflates by ~17 pp; retrieval Top-1 inflates from 10.73% to 28.50%. This completely reorders the de novo leaderboard. + +**What to look for:** +```python +# BUG (wrong): +attn += attn_mask + +# SUBTLE BUG โ€” fix code present but result discarded: +new_attn_mask = torch.zeros_like(attn_mask, dtype=q.dtype) +new_attn_mask.masked_fill_(attn_mask, float("-inf")) +attn += attn_mask # <-- still uses raw bool mask, new_attn_mask silently ignored + +# FIX (correct): +new_attn_mask = torch.zeros_like(attn_mask, dtype=q.dtype) +new_attn_mask.masked_fill_(attn_mask, float("-inf")) +attn += new_attn_mask +``` + +The v1.5 MassSpecGym MIST encoder (`massspecgym/models/encoders/mist/transformer_layer.py`) already applies the fix. If the submission imports from there, this is satisfied. + +--- + +## Step 6: Data leakage โ€” gradient of stringency + +Data leakage is not binary. The steepest performance gradient appears at the transition from exact-match exclusion to Tanimoto โ‰ฅ 0.70โ€“0.80 filtering โ€” not at the exact-match boundary itself. This means a model may claim "clean" data (exact-match excluded) while still benefiting substantially from near-neighbor contamination. + +**What to report in your review:** +- What filtering criterion is declared in the model card? +- Is this consistent with what the paper states? +- Does the paper compare against baselines at the same filtering level? + +The leaderboard accepts exact-match exclusion as the minimum. If the criterion is weaker or unstated, request clarification before approval. + +--- + +## Final approval checklist + +Before approving the PR, confirm: + +- [ ] Automated report has no hard failures (or failures have been resolved and re-reviewed) +- [ ] All warnings have been signed off with a documented reason +- [ ] Paper methods section consistent with model card +- [ ] No implicit formula use in standard-tier submission (from reading the paper) +- [ ] Pretraining data safety confirmed (parquet sanity check run or author confirmed) +- [ ] If MIST encoder used: v1.5 fix confirmed or external repo verified +- [ ] If MIST-CF or ICEBERG used: v1.5 data-safe version confirmed +- [ ] All required metrics present with CIs +- [ ] Method name in CSV matches model card exactly +- [ ] `df_test_path` configured so per-sample predictions are saved (recommended) +- [ ] Seed documented diff --git a/submissions/DeepSets/model_card.yaml b/submissions/DeepSets/model_card.yaml new file mode 100644 index 0000000..26250b2 --- /dev/null +++ b/submissions/DeepSets/model_card.yaml @@ -0,0 +1,64 @@ +method_name: "DeepSets" +paper_url: "https://arxiv.org/abs/2410.23326" +code_url: "https://github.com/pluskal-lab/MassSpecGym" +random_seed: null + +results: + - task: retrieval + challenge: standard + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Hit rate @ 1: 1.47 + Hit rate @ 1 CI Low: 1.18 + Hit rate @ 1 CI High: 1.77 + Hit rate @ 5: 6.21 + Hit rate @ 5 CI Low: 5.64 + Hit rate @ 5 CI High: 6.82 + Hit rate @ 20: 19.23 + Hit rate @ 20 CI Low: 18.24 + Hit rate @ 20 CI High: 20.26 + MCES @ 1: 25.11 + MCES @ 1 CI Low: 24.84 + MCES @ 1 CI High: 25.39 + + - task: retrieval + challenge: bonus + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Hit rate @ 1: 4.42 + Hit rate @ 1 CI Low: 3.92 + Hit rate @ 1 CI High: 4.97 + Hit rate @ 5: 14.46 + Hit rate @ 5 CI Low: 13.58 + Hit rate @ 5 CI High: 15.36 + Hit rate @ 20: 30.76 + Hit rate @ 20 CI Low: 29.67 + Hit rate @ 20 CI High: 31.93 + MCES @ 1: 15.04 + MCES @ 1 CI Low: 14.89 + MCES @ 1 CI High: 15.19 + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Baseline from the MassSpecGym benchmark paper." diff --git a/submissions/DeepSets_Fourier/model_card.yaml b/submissions/DeepSets_Fourier/model_card.yaml new file mode 100644 index 0000000..2be9683 --- /dev/null +++ b/submissions/DeepSets_Fourier/model_card.yaml @@ -0,0 +1,64 @@ +method_name: "DeepSets + Fourier features" +paper_url: "https://arxiv.org/abs/2410.23326" +code_url: "https://github.com/pluskal-lab/MassSpecGym" +random_seed: null + +results: + - task: retrieval + challenge: standard + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Hit rate @ 1: 5.24 + Hit rate @ 1 CI Low: 4.71 + Hit rate @ 1 CI High: 5.83 + Hit rate @ 5: 12.58 + Hit rate @ 5 CI Low: 11.80 + Hit rate @ 5 CI High: 13.42 + Hit rate @ 20: 28.21 + Hit rate @ 20 CI Low: 27.10 + Hit rate @ 20 CI High: 29.36 + MCES @ 1: 22.13 + MCES @ 1 CI Low: 21.85 + MCES @ 1 CI High: 22.43 + + - task: retrieval + challenge: bonus + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Hit rate @ 1: 6.56 + Hit rate @ 1 CI Low: 5.95 + Hit rate @ 1 CI High: 7.16 + Hit rate @ 5: 16.46 + Hit rate @ 5 CI Low: 15.58 + Hit rate @ 5 CI High: 17.35 + Hit rate @ 20: 33.46 + Hit rate @ 20 CI Low: 32.39 + Hit rate @ 20 CI High: 34.59 + MCES @ 1: 14.14 + MCES @ 1 CI Low: 13.98 + MCES @ 1 CI High: 14.31 + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Baseline from the MassSpecGym benchmark paper." diff --git a/submissions/DiffMS/model_card.yaml b/submissions/DiffMS/model_card.yaml new file mode 100644 index 0000000..699e6e1 --- /dev/null +++ b/submissions/DiffMS/model_card.yaml @@ -0,0 +1,49 @@ +method_name: "DiffMS" +paper_url: "https://arxiv.org/abs/2502.09571" +code_url: "" +random_seed: null + +results: + - task: de_novo + challenge: bonus + uses_formula_at_inference: false + paper: "DiffMS: Diffusion Generation of Molecules Conditioned on Mass Spectra" + doi: "https://doi.org/10.48550/arXiv.2502.09571" + publication_date: "2025-05-27" + comment: "" + metrics: + Top-1 Accuracy: 0.0230 + Top-1 Accuracy CI Low: "" + Top-1 Accuracy CI High: "" + Top-1 MCES: 18.45 + Top-1 MCES CI Low: "" + Top-1 MCES CI High: "" + Top-1 Tanimoto: 0.28 + Top-1 Tanimoto CI Low: "" + Top-1 Tanimoto CI High: "" + Top-10 Accuracy: 0.0425 + Top-10 Accuracy CI Low: "" + Top-10 Accuracy CI High: "" + Top-10 MCES: 14.73 + Top-10 MCES CI Low: "" + Top-10 MCES CI High: "" + Top-10 Tanimoto: 0.39 + Top-10 Tanimoto CI Low: "" + Top-10 Tanimoto CI High: "" + +uses_mist_encoder: true +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "CIs not reported in the original submission." diff --git a/submissions/ESP/model_card.yaml b/submissions/ESP/model_card.yaml new file mode 100644 index 0000000..494388a --- /dev/null +++ b/submissions/ESP/model_card.yaml @@ -0,0 +1,64 @@ +method_name: "ESP" +paper_url: "https://arxiv.org/abs/2411.14464" +code_url: "" +random_seed: null + +results: + - task: retrieval + challenge: standard + uses_formula_at_inference: false + paper: "JESTR: Joint Embedding Space Technique for Ranking Candidate Molecules for the Annotation of Untargeted Metabolomics Data" + doi: "https://doi.org/10.48550/arXiv.2411.14464" + publication_date: "2025-06-10" + comment: "" + metrics: + Hit rate @ 1: 10.71 + Hit rate @ 1 CI Low: "" + Hit rate @ 1 CI High: "" + Hit rate @ 5: 24.84 + Hit rate @ 5 CI Low: "" + Hit rate @ 5 CI High: "" + Hit rate @ 20: 42.66 + Hit rate @ 20 CI Low: "" + Hit rate @ 20 CI High: "" + MCES @ 1: "" + MCES @ 1 CI Low: "" + MCES @ 1 CI High: "" + + - task: retrieval + challenge: bonus + uses_formula_at_inference: false + paper: "JESTR: Joint Embedding Space Technique for Ranking Candidate Molecules for the Annotation of Untargeted Metabolomics Data" + doi: "https://doi.org/10.48550/arXiv.2411.14464" + publication_date: "2025-06-10" + comment: "" + metrics: + Hit rate @ 1: 11.05 + Hit rate @ 1 CI Low: "" + Hit rate @ 1 CI High: "" + Hit rate @ 5: 27.42 + Hit rate @ 5 CI Low: "" + Hit rate @ 5 CI High: "" + Hit rate @ 20: 52.20 + Hit rate @ 20 CI Low: "" + Hit rate @ 20 CI High: "" + MCES @ 1: "" + MCES @ 1 CI Low: "" + MCES @ 1 CI High: "" + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Reported in JESTR paper. CIs not reported." diff --git a/submissions/FFN_Fingerprint/model_card.yaml b/submissions/FFN_Fingerprint/model_card.yaml new file mode 100644 index 0000000..53a240c --- /dev/null +++ b/submissions/FFN_Fingerprint/model_card.yaml @@ -0,0 +1,70 @@ +method_name: "FFN Fingerprint" +paper_url: "https://arxiv.org/abs/2410.23326" +code_url: "https://github.com/pluskal-lab/MassSpecGym" +random_seed: null + +results: + - task: simulation + challenge: standard + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Cosine Similarity: 0.25 + Cosine Similarity CI Low: 0.24 + Cosine Similarity CI High: 0.26 + Jensen-Shannon Similarity: 0.24 + Jensen-Shannon Similarity CI Low: 0.23 + Jensen-Shannon Similarity CI High: 0.25 + Hit rate @ 1: 8.44 + Hit rate @ 1 CI Low: 7.56 + Hit rate @ 1 CI High: 9.34 + Hit rate @ 5: 21.43 + Hit rate @ 5 CI Low: 20.10 + Hit rate @ 5 CI High: 22.79 + Hit rate @ 20: 38.57 + Hit rate @ 20 CI Low: 36.99 + Hit rate @ 20 CI High: 40.23 + + - task: simulation + challenge: bonus + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Cosine Similarity: 0.25 + Cosine Similarity CI Low: 0.24 + Cosine Similarity CI High: 0.26 + Jensen-Shannon Similarity: 0.24 + Jensen-Shannon Similarity CI Low: 0.23 + Jensen-Shannon Similarity CI High: 0.25 + Hit rate @ 1: 7.62 + Hit rate @ 1 CI Low: 6.77 + Hit rate @ 1 CI High: 8.54 + Hit rate @ 5: 22.70 + Hit rate @ 5 CI Low: 21.32 + Hit rate @ 5 CI High: 24.12 + Hit rate @ 20: 44.12 + Hit rate @ 20 CI Low: 42.51 + Hit rate @ 20 CI High: 45.75 + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Baseline from the MassSpecGym benchmark paper." diff --git a/submissions/Fingerprint_FFN/model_card.yaml b/submissions/Fingerprint_FFN/model_card.yaml new file mode 100644 index 0000000..ad10d0d --- /dev/null +++ b/submissions/Fingerprint_FFN/model_card.yaml @@ -0,0 +1,64 @@ +method_name: "Fingerprint FFN" +paper_url: "https://arxiv.org/abs/2410.23326" +code_url: "https://github.com/pluskal-lab/MassSpecGym" +random_seed: null + +results: + - task: retrieval + challenge: standard + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Hit rate @ 1: 2.54 + Hit rate @ 1 CI Low: 2.17 + Hit rate @ 1 CI High: 2.99 + Hit rate @ 5: 7.59 + Hit rate @ 5 CI Low: 6.96 + Hit rate @ 5 CI High: 8.28 + Hit rate @ 20: 20.80 + Hit rate @ 20 CI Low: 19.01 + Hit rate @ 20 CI High: 20.98 + MCES @ 1: 24.66 + MCES @ 1 CI Low: 24.38 + MCES @ 1 CI High: 24.94 + + - task: retrieval + challenge: bonus + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Hit rate @ 1: 5.09 + Hit rate @ 1 CI Low: 4.57 + Hit rate @ 1 CI High: 5.66 + Hit rate @ 5: 16.03 + Hit rate @ 5 CI Low: 15.38 + Hit rate @ 5 CI High: 15.56 + Hit rate @ 20: 31.97 + Hit rate @ 20 CI Low: 30.86 + Hit rate @ 20 CI High: 33.20 + MCES @ 1: 14.94 + MCES @ 1 CI Low: 14.79 + MCES @ 1 CI High: 15.09 + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Baseline from the MassSpecGym benchmark paper." diff --git a/submissions/FraGNNet/model_card.yaml b/submissions/FraGNNet/model_card.yaml new file mode 100644 index 0000000..90971b4 --- /dev/null +++ b/submissions/FraGNNet/model_card.yaml @@ -0,0 +1,70 @@ +method_name: "FraGNNet" +paper_url: "https://arxiv.org/abs/2410.23326" +code_url: "https://github.com/pluskal-lab/MassSpecGym" +random_seed: null + +results: + - task: simulation + challenge: standard + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Cosine Similarity: 0.52 + Cosine Similarity CI Low: 0.51 + Cosine Similarity CI High: 0.53 + Jensen-Shannon Similarity: 0.47 + Jensen-Shannon Similarity CI Low: 0.46 + Jensen-Shannon Similarity CI High: 0.48 + Hit rate @ 1: 46.64 + Hit rate @ 1 CI Low: 44.98 + Hit rate @ 1 CI High: 48.26 + Hit rate @ 5: 72.56 + Hit rate @ 5 CI Low: 71.18 + Hit rate @ 5 CI High: 74.00 + Hit rate @ 20: 83.58 + Hit rate @ 20 CI Low: 82.34 + Hit rate @ 20 CI High: 84.75 + + - task: simulation + challenge: bonus + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Cosine Similarity: 0.52 + Cosine Similarity CI Low: 0.51 + Cosine Similarity CI High: 0.53 + Jensen-Shannon Similarity: 0.47 + Jensen-Shannon Similarity CI Low: 0.46 + Jensen-Shannon Similarity CI High: 0.48 + Hit rate @ 1: 31.93 + Hit rate @ 1 CI Low: 30.40 + Hit rate @ 1 CI High: 33.50 + Hit rate @ 5: 63.20 + Hit rate @ 5 CI Low: 61.64 + Hit rate @ 5 CI High: 64.76 + Hit rate @ 20: 82.70 + Hit rate @ 20 CI Low: 81.45 + Hit rate @ 20 CI High: 83.93 + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Baseline from the MassSpecGym benchmark paper." diff --git a/submissions/GNN/model_card.yaml b/submissions/GNN/model_card.yaml new file mode 100644 index 0000000..75ffe12 --- /dev/null +++ b/submissions/GNN/model_card.yaml @@ -0,0 +1,70 @@ +method_name: "GNN" +paper_url: "https://arxiv.org/abs/2410.23326" +code_url: "https://github.com/pluskal-lab/MassSpecGym" +random_seed: null + +results: + - task: simulation + challenge: standard + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Cosine Similarity: 0.19 + Cosine Similarity CI Low: 0.18 + Cosine Similarity CI High: 0.20 + Jensen-Shannon Similarity: 0.20 + Jensen-Shannon Similarity CI Low: 0.19 + Jensen-Shannon Similarity CI High: 0.20 + Hit rate @ 1: 3.95 + Hit rate @ 1 CI Low: 3.37 + Hit rate @ 1 CI High: 4.62 + Hit rate @ 5: 11.92 + Hit rate @ 5 CI Low: 10.87 + Hit rate @ 5 CI High: 13.00 + Hit rate @ 20: 26.27 + Hit rate @ 20 CI Low: 24.83 + Hit rate @ 20 CI High: 27.82 + + - task: simulation + challenge: bonus + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Cosine Similarity: 0.19 + Cosine Similarity CI Low: 0.18 + Cosine Similarity CI High: 0.20 + Jensen-Shannon Similarity: 0.20 + Jensen-Shannon Similarity CI Low: 0.19 + Jensen-Shannon Similarity CI High: 0.20 + Hit rate @ 1: 3.63 + Hit rate @ 1 CI Low: 3.05 + Hit rate @ 1 CI High: 4.29 + Hit rate @ 5: 13.55 + Hit rate @ 5 CI Low: 12.46 + Hit rate @ 5 CI High: 14.68 + Hit rate @ 20: 33.77 + Hit rate @ 20 CI Low: 32.26 + Hit rate @ 20 CI High: 35.37 + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Baseline from the MassSpecGym benchmark paper." diff --git a/submissions/ICEBERG/model_card.yaml b/submissions/ICEBERG/model_card.yaml new file mode 100644 index 0000000..8c0c0a2 --- /dev/null +++ b/submissions/ICEBERG/model_card.yaml @@ -0,0 +1,46 @@ +method_name: "ICEBERG" +paper_url: "https://doi.org/10.1101/2025.05.28.656653" +code_url: "" +random_seed: null + +results: + - task: simulation + challenge: bonus + uses_formula_at_inference: false + paper: "Neural Spectral Prediction for Structure Elucidation with Tandem Mass Spectrometry" + doi: "https://doi.org/10.1101/2025.05.28.656653" + publication_date: "2025-06-01" + comment: "" + metrics: + Cosine Similarity: 0.58 + Cosine Similarity CI Low: 0.57 + Cosine Similarity CI High: 0.59 + Jensen-Shannon Similarity: 0.48 + Jensen-Shannon Similarity CI Low: 0.48 + Jensen-Shannon Similarity CI High: 0.49 + Hit rate @ 1: 45.95 + Hit rate @ 1 CI Low: 44.32 + Hit rate @ 1 CI High: 47.59 + Hit rate @ 5: 75.43 + Hit rate @ 5 CI Low: 73.88 + Hit rate @ 5 CI High: 76.90 + Hit rate @ 20: 91.69 + Hit rate @ 20 CI Low: 90.73 + Hit rate @ 20 CI High: 92.60 + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: true +mist_cf_version: "" +iceberg_version: "v1.5_data_safe" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "" diff --git a/submissions/JESTR/model_card.yaml b/submissions/JESTR/model_card.yaml new file mode 100644 index 0000000..a183849 --- /dev/null +++ b/submissions/JESTR/model_card.yaml @@ -0,0 +1,64 @@ +method_name: "JESTR" +paper_url: "https://arxiv.org/abs/2411.14464" +code_url: "" +random_seed: null + +results: + - task: retrieval + challenge: standard + uses_formula_at_inference: false + paper: "JESTR: Joint Embedding Space Technique for Ranking Candidate Molecules for the Annotation of Untargeted Metabolomics Data" + doi: "https://doi.org/10.48550/arXiv.2411.14464" + publication_date: "2025-06-10" + comment: "" + metrics: + Hit rate @ 1: 15.13 + Hit rate @ 1 CI Low: "" + Hit rate @ 1 CI High: "" + Hit rate @ 5: 36.75 + Hit rate @ 5 CI Low: "" + Hit rate @ 5 CI High: "" + Hit rate @ 20: 60.32 + Hit rate @ 20 CI Low: "" + Hit rate @ 20 CI High: "" + MCES @ 1: "" + MCES @ 1 CI Low: "" + MCES @ 1 CI High: "" + + - task: retrieval + challenge: bonus + uses_formula_at_inference: false + paper: "JESTR: Joint Embedding Space Technique for Ranking Candidate Molecules for the Annotation of Untargeted Metabolomics Data" + doi: "https://doi.org/10.48550/arXiv.2411.14464" + publication_date: "2025-06-10" + comment: "" + metrics: + Hit rate @ 1: 11.85 + Hit rate @ 1 CI Low: "" + Hit rate @ 1 CI High: "" + Hit rate @ 5: 32.95 + Hit rate @ 5 CI Low: "" + Hit rate @ 5 CI High: "" + Hit rate @ 20: 61.46 + Hit rate @ 20 CI Low: "" + Hit rate @ 20 CI High: "" + MCES @ 1: "" + MCES @ 1 CI Low: "" + MCES @ 1 CI High: "" + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "CIs not reported in original submission." diff --git a/submissions/MADGEN/model_card.yaml b/submissions/MADGEN/model_card.yaml new file mode 100644 index 0000000..be42697 --- /dev/null +++ b/submissions/MADGEN/model_card.yaml @@ -0,0 +1,49 @@ +method_name: "MADGEN" +paper_url: "https://arxiv.org/abs/2501.01950" +code_url: "" +random_seed: null + +results: + - task: de_novo + challenge: bonus + uses_formula_at_inference: false + paper: "MADGEN: Mass-Spec attends to De Novo Molecular generation" + doi: "https://doi.org/10.48550/arXiv.2501.01950" + publication_date: "2025-04-29" + comment: "" + metrics: + Top-1 Accuracy: 0.0131 + Top-1 Accuracy CI Low: "" + Top-1 Accuracy CI High: "" + Top-1 MCES: 27.47 + Top-1 MCES CI Low: "" + Top-1 MCES CI High: "" + Top-1 Tanimoto: 0.20 + Top-1 Tanimoto CI Low: "" + Top-1 Tanimoto CI High: "" + Top-10 Accuracy: 0.0154 + Top-10 Accuracy CI Low: "" + Top-10 Accuracy CI High: "" + Top-10 MCES: 16.84 + Top-10 MCES CI Low: "" + Top-10 MCES CI High: "" + Top-10 Tanimoto: 0.26 + Top-10 Tanimoto CI Low: "" + Top-10 Tanimoto CI High: "" + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "CIs not reported in the original submission." diff --git a/submissions/MARASON/model_card.yaml b/submissions/MARASON/model_card.yaml new file mode 100644 index 0000000..9775478 --- /dev/null +++ b/submissions/MARASON/model_card.yaml @@ -0,0 +1,46 @@ +method_name: "MARASON" +paper_url: "https://arxiv.org/abs/2502.17874" +code_url: "" +random_seed: null + +results: + - task: simulation + challenge: bonus + uses_formula_at_inference: false + paper: "Neural Graph Matching Improves Retrieval Augmented Generation in Molecular Machine Learning" + doi: "https://doi.org/10.48550/arXiv.2502.17874" + publication_date: "2025-02-25" + comment: "" + metrics: + Cosine Similarity: "" + Cosine Similarity CI Low: "" + Cosine Similarity CI High: "" + Jensen-Shannon Similarity: "" + Jensen-Shannon Similarity CI Low: "" + Jensen-Shannon Similarity CI High: "" + Hit rate @ 1: 34.03 + Hit rate @ 1 CI Low: 32.86 + Hit rate @ 1 CI High: 35.20 + Hit rate @ 5: 64.04 + Hit rate @ 5 CI Low: 62.77 + Hit rate @ 5 CI High: 65.19 + Hit rate @ 20: 85.39 + Hit rate @ 20 CI Low: 84.48 + Hit rate @ 20 CI High: 86.24 + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Cosine/Jensen-Shannon similarity not reported in original submission." diff --git a/submissions/MIST/model_card.yaml b/submissions/MIST/model_card.yaml new file mode 100644 index 0000000..0156573 --- /dev/null +++ b/submissions/MIST/model_card.yaml @@ -0,0 +1,64 @@ +method_name: "MIST" +paper_url: "https://arxiv.org/abs/2410.23326" +code_url: "https://github.com/pluskal-lab/MassSpecGym" +random_seed: null + +results: + - task: retrieval + challenge: standard + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Hit rate @ 1: 14.64 + Hit rate @ 1 CI Low: 13.82 + Hit rate @ 1 CI High: 15.54 + Hit rate @ 5: 34.87 + Hit rate @ 5 CI Low: 33.69 + Hit rate @ 5 CI High: 36.10 + Hit rate @ 20: 59.15 + Hit rate @ 20 CI Low: 57.89 + Hit rate @ 20 CI High: 60.39 + MCES @ 1: 15.37 + MCES @ 1 CI Low: 15.12 + MCES @ 1 CI High: 15.62 + + - task: retrieval + challenge: bonus + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Hit rate @ 1: 9.57 + Hit rate @ 1 CI Low: 8.88 + Hit rate @ 1 CI High: 10.30 + Hit rate @ 5: 22.11 + Hit rate @ 5 CI Low: 21.10 + Hit rate @ 5 CI High: 23.13 + Hit rate @ 20: 41.12 + Hit rate @ 20 CI Low: 39.98 + Hit rate @ 20 CI High: 42.34 + MCES @ 1: 12.75 + MCES @ 1 CI Low: 12.59 + MCES @ 1 CI High: 12.91 + +uses_mist_encoder: true +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Baseline from the MassSpecGym benchmark paper." diff --git a/submissions/MIST_MSNovelist/model_card.yaml b/submissions/MIST_MSNovelist/model_card.yaml new file mode 100644 index 0000000..b28138c --- /dev/null +++ b/submissions/MIST_MSNovelist/model_card.yaml @@ -0,0 +1,49 @@ +method_name: "MIST + MSNovelist" +paper_url: "https://arxiv.org/abs/2502.09571" +code_url: "" +random_seed: null + +results: + - task: de_novo + challenge: bonus + uses_formula_at_inference: true + paper: "DiffMS: Diffusion Generation of Molecules Conditioned on Mass Spectra" + doi: "https://doi.org/10.48550/arXiv.2502.09571" + publication_date: "2025-05-27" + comment: "Baseline reported in DiffMS paper" + metrics: + Top-1 Accuracy: 0.00 + Top-1 Accuracy CI Low: "" + Top-1 Accuracy CI High: "" + Top-1 MCES: 45.55 + Top-1 MCES CI Low: "" + Top-1 MCES CI High: "" + Top-1 Tanimoto: 0.06 + Top-1 Tanimoto CI Low: "" + Top-1 Tanimoto CI High: "" + Top-10 Accuracy: 0.00 + Top-10 Accuracy CI Low: "" + Top-10 Accuracy CI High: "" + Top-10 MCES: 30.13 + Top-10 MCES CI Low: "" + Top-10 MCES CI High: "" + Top-10 Tanimoto: 0.15 + Top-10 Tanimoto CI Low: "" + Top-10 Tanimoto CI High: "" + +uses_mist_encoder: true +uses_mist_cf: true +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Baseline reported in DiffMS paper. CIs not reported. Uses MIST-CF for formula prediction." diff --git a/submissions/MIST_Neuraldecipher/model_card.yaml b/submissions/MIST_Neuraldecipher/model_card.yaml new file mode 100644 index 0000000..4e9d5ce --- /dev/null +++ b/submissions/MIST_Neuraldecipher/model_card.yaml @@ -0,0 +1,49 @@ +method_name: "MIST + Neuraldecipher" +paper_url: "https://arxiv.org/abs/2502.09571" +code_url: "" +random_seed: null + +results: + - task: de_novo + challenge: bonus + uses_formula_at_inference: true + paper: "DiffMS: Diffusion Generation of Molecules Conditioned on Mass Spectra" + doi: "https://doi.org/10.48550/arXiv.2502.09571" + publication_date: "2025-05-27" + comment: "Re-evaluated baseline reported in DiffMS paper" + metrics: + Top-1 Accuracy: 0.00 + Top-1 Accuracy CI Low: "" + Top-1 Accuracy CI High: "" + Top-1 MCES: 33.19 + Top-1 MCES CI Low: "" + Top-1 MCES CI High: "" + Top-1 Tanimoto: 0.14 + Top-1 Tanimoto CI Low: "" + Top-1 Tanimoto CI High: "" + Top-10 Accuracy: 0.00 + Top-10 Accuracy CI Low: "" + Top-10 Accuracy CI High: "" + Top-10 MCES: 31.89 + Top-10 MCES CI Low: "" + Top-10 MCES CI High: "" + Top-10 Tanimoto: 0.16 + Top-10 Tanimoto CI Low: "" + Top-10 Tanimoto CI High: "" + +uses_mist_encoder: true +uses_mist_cf: true +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Re-evaluated by DiffMS authors (previously listed as 'MIST + Neuraldecipher*' in CSV). CIs not reported. Uses MIST-CF for formula prediction." diff --git a/submissions/MS-BART/model_card.yaml b/submissions/MS-BART/model_card.yaml new file mode 100644 index 0000000..f7e0391 --- /dev/null +++ b/submissions/MS-BART/model_card.yaml @@ -0,0 +1,49 @@ +method_name: "MS-BART" +paper_url: "https://arxiv.org/abs/2510.20615" +code_url: "" +random_seed: null + +results: + - task: de_novo + challenge: standard + uses_formula_at_inference: false + paper: "MS-BART: Unified Modeling of Mass Spectra and Molecules for Structure Elucidation" + doi: "https://doi.org/10.48550/arXiv.2510.20615" + publication_date: "2025-10-23" + comment: "" + metrics: + Top-1 Accuracy: 0.0107 + Top-1 Accuracy CI Low: "" + Top-1 Accuracy CI High: "" + Top-1 MCES: 16.47 + Top-1 MCES CI Low: "" + Top-1 MCES CI High: "" + Top-1 Tanimoto: 0.23 + Top-1 Tanimoto CI Low: "" + Top-1 Tanimoto CI High: "" + Top-10 Accuracy: 0.0111 + Top-10 Accuracy CI Low: "" + Top-10 Accuracy CI High: "" + Top-10 MCES: 15.12 + Top-10 MCES CI Low: "" + Top-10 MCES CI High: "" + Top-10 Tanimoto: 0.28 + Top-10 Tanimoto CI Low: "" + Top-10 Tanimoto CI High: "" + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "CIs not reported in the original submission." diff --git a/submissions/OMG/model_card.yaml b/submissions/OMG/model_card.yaml new file mode 100644 index 0000000..4480def --- /dev/null +++ b/submissions/OMG/model_card.yaml @@ -0,0 +1,49 @@ +method_name: "OMG (JESTR)" +paper_url: "https://doi.org/10.1021/acs.analchem.5c01770" +code_url: "" +random_seed: null + +results: + - task: de_novo + challenge: bonus + uses_formula_at_inference: false + paper: "Optimized De Novo Molecular Generation (OMG) for Mass Spectra Annotation Using Transfer and Reinforcement Learning" + doi: "https://doi.org/10.1021/acs.analchem.5c01770" + publication_date: "2025-09-16" + comment: "JESTR-based candidate generation variant" + metrics: + Top-1 Accuracy: 0.0032 + Top-1 Accuracy CI Low: "" + Top-1 Accuracy CI High: "" + Top-1 MCES: 58.16 + Top-1 MCES CI Low: "" + Top-1 MCES CI High: "" + Top-1 Tanimoto: 0.09 + Top-1 Tanimoto CI Low: "" + Top-1 Tanimoto CI High: "" + Top-10 Accuracy: 0.0255 + Top-10 Accuracy CI Low: "" + Top-10 Accuracy CI High: "" + Top-10 MCES: 56.99 + Top-10 MCES CI Low: "" + Top-10 MCES CI High: "" + Top-10 Tanimoto: 0.14 + Top-10 Tanimoto CI Low: "" + Top-10 Tanimoto CI High: "" + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "CIs not reported. See also OMG (ESP) for the ESP-based variant." diff --git a/submissions/OMG_ESP/model_card.yaml b/submissions/OMG_ESP/model_card.yaml new file mode 100644 index 0000000..0a38342 --- /dev/null +++ b/submissions/OMG_ESP/model_card.yaml @@ -0,0 +1,49 @@ +method_name: "OMG (ESP)" +paper_url: "https://doi.org/10.1021/acs.analchem.5c01770" +code_url: "" +random_seed: null + +results: + - task: de_novo + challenge: bonus + uses_formula_at_inference: false + paper: "Optimized De Novo Molecular Generation (OMG) for Mass Spectra Annotation Using Transfer and Reinforcement Learning" + doi: "https://doi.org/10.1021/acs.analchem.5c01770" + publication_date: "2025-09-16" + comment: "ESP-based candidate generation variant" + metrics: + Top-1 Accuracy: 0.0085 + Top-1 Accuracy CI Low: "" + Top-1 Accuracy CI High: "" + Top-1 MCES: 57.74 + Top-1 MCES CI Low: "" + Top-1 MCES CI High: "" + Top-1 Tanimoto: 0.11 + Top-1 Tanimoto CI Low: "" + Top-1 Tanimoto CI High: "" + Top-10 Accuracy: 0.0282 + Top-10 Accuracy CI Low: "" + Top-10 Accuracy CI High: "" + Top-10 MCES: 56.77 + Top-10 MCES CI Low: "" + Top-10 MCES CI High: "" + Top-10 Tanimoto: 0.15 + Top-10 Tanimoto CI Low: "" + Top-10 Tanimoto CI High: "" + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "CIs not reported. See also OMG (JESTR) for the JESTR-based variant." diff --git a/submissions/Precursor_mz/model_card.yaml b/submissions/Precursor_mz/model_card.yaml new file mode 100644 index 0000000..ee583a5 --- /dev/null +++ b/submissions/Precursor_mz/model_card.yaml @@ -0,0 +1,70 @@ +method_name: "Precursor m/z" +paper_url: "https://arxiv.org/abs/2410.23326" +code_url: "https://github.com/pluskal-lab/MassSpecGym" +random_seed: null + +results: + - task: simulation + challenge: standard + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Cosine Similarity: 0.15 + Cosine Similarity CI Low: 0.14 + Cosine Similarity CI High: 0.17 + Jensen-Shannon Similarity: 0.15 + Jensen-Shannon Similarity CI Low: 0.14 + Jensen-Shannon Similarity CI High: 0.16 + Hit rate @ 1: 0.38 + Hit rate @ 1 CI Low: 0.21 + Hit rate @ 1 CI High: 0.62 + Hit rate @ 5: 1.72 + Hit rate @ 5 CI Low: 1.32 + Hit rate @ 5 CI High: 2.18 + Hit rate @ 20: 7.17 + Hit rate @ 20 CI Low: 6.32 + Hit rate @ 20 CI High: 8.04 + + - task: simulation + challenge: bonus + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Cosine Similarity: 0.15 + Cosine Similarity CI Low: 0.14 + Cosine Similarity CI High: 0.17 + Jensen-Shannon Similarity: 0.15 + Jensen-Shannon Similarity CI Low: 0.14 + Jensen-Shannon Similarity CI High: 0.16 + Hit rate @ 1: 2.09 + Hit rate @ 1 CI Low: 1.66 + Hit rate @ 1 CI High: 2.59 + Hit rate @ 5: 8.52 + Hit rate @ 5 CI Low: 7.65 + Hit rate @ 5 CI High: 9.53 + Hit rate @ 20: 22.65 + Hit rate @ 20 CI Low: 21.26 + Hit rate @ 20 CI High: 24.01 + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Baseline from the MassSpecGym benchmark paper." diff --git a/submissions/Random/model_card.yaml b/submissions/Random/model_card.yaml new file mode 100644 index 0000000..3e9b0fe --- /dev/null +++ b/submissions/Random/model_card.yaml @@ -0,0 +1,64 @@ +method_name: "Random" +paper_url: "https://arxiv.org/abs/2410.23326" +code_url: "https://github.com/pluskal-lab/MassSpecGym" +random_seed: null + +results: + - task: retrieval + challenge: standard + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Hit rate @ 1: 0.37 + Hit rate @ 1 CI Low: 0.24 + Hit rate @ 1 CI High: 0.54 + Hit rate @ 5: 2.01 + Hit rate @ 5 CI Low: 1.68 + Hit rate @ 5 CI High: 2.39 + Hit rate @ 20: 8.22 + Hit rate @ 20 CI Low: 7.53 + Hit rate @ 20 CI High: 8.89 + MCES @ 1: 30.81 + MCES @ 1 CI Low: 30.40 + MCES @ 1 CI High: 31.21 + + - task: retrieval + challenge: bonus + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Hit rate @ 1: 3.06 + Hit rate @ 1 CI Low: 2.64 + Hit rate @ 1 CI High: 3.52 + Hit rate @ 5: 11.35 + Hit rate @ 5 CI Low: 10.60 + Hit rate @ 5 CI High: 12.12 + Hit rate @ 20: 27.74 + Hit rate @ 20 CI Low: 26.52 + Hit rate @ 20 CI High: 28.84 + MCES @ 1: 13.87 + MCES @ 1 CI Low: 13.70 + MCES @ 1 CI High: 14.03 + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Random retrieval baseline from the MassSpecGym benchmark paper." diff --git a/submissions/Random_chemical_generation/model_card.yaml b/submissions/Random_chemical_generation/model_card.yaml new file mode 100644 index 0000000..79f8a12 --- /dev/null +++ b/submissions/Random_chemical_generation/model_card.yaml @@ -0,0 +1,76 @@ +method_name: "Random chemical generation" +paper_url: "https://arxiv.org/abs/2410.23326" +code_url: "https://github.com/pluskal-lab/MassSpecGym" +random_seed: null + +results: + - task: de_novo + challenge: standard + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Top-1 Accuracy: 0.00 + Top-1 Accuracy CI Low: 0.00 + Top-1 Accuracy CI High: 0.00 + Top-1 MCES: 21.11 + Top-1 MCES CI Low: 20.97 + Top-1 MCES CI High: 21.26 + Top-1 Tanimoto: 0.08 + Top-1 Tanimoto CI Low: 0.08 + Top-1 Tanimoto CI High: 0.08 + Top-10 Accuracy: 0.00 + Top-10 Accuracy CI Low: 0.00 + Top-10 Accuracy CI High: 0.00 + Top-10 MCES: 18.25 + Top-10 MCES CI Low: 18.14 + Top-10 MCES CI High: 18.35 + Top-10 Tanimoto: 0.11 + Top-10 Tanimoto CI Low: 0.11 + Top-10 Tanimoto CI High: 0.11 + + - task: de_novo + challenge: bonus + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Top-1 Accuracy: 0.00 + Top-1 Accuracy CI Low: 0.00 + Top-1 Accuracy CI High: 0.00 + Top-1 MCES: 21.11 + Top-1 MCES CI Low: 20.97 + Top-1 MCES CI High: 21.26 + Top-1 Tanimoto: 0.08 + Top-1 Tanimoto CI Low: 0.08 + Top-1 Tanimoto CI High: 0.08 + Top-10 Accuracy: 0.00 + Top-10 Accuracy CI Low: 0.00 + Top-10 Accuracy CI High: 0.00 + Top-10 MCES: 18.25 + Top-10 MCES CI Low: 18.14 + Top-10 MCES CI High: 18.35 + Top-10 Tanimoto: 0.11 + Top-10 Tanimoto CI Low: 0.11 + Top-10 Tanimoto CI High: 0.11 + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Baseline from the MassSpecGym benchmark paper." diff --git a/submissions/SELFIES_Transformer/model_card.yaml b/submissions/SELFIES_Transformer/model_card.yaml new file mode 100644 index 0000000..90150dd --- /dev/null +++ b/submissions/SELFIES_Transformer/model_card.yaml @@ -0,0 +1,76 @@ +method_name: "SELFIES Transformer" +paper_url: "https://arxiv.org/abs/2410.23326" +code_url: "https://github.com/pluskal-lab/MassSpecGym" +random_seed: null + +results: + - task: de_novo + challenge: standard + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Top-1 Accuracy: 0.00 + Top-1 Accuracy CI Low: 0.00 + Top-1 Accuracy CI High: 0.00 + Top-1 MCES: 38.88 + Top-1 MCES CI Low: 38.57 + Top-1 MCES CI High: 39.20 + Top-1 Tanimoto: 0.08 + Top-1 Tanimoto CI Low: 0.08 + Top-1 Tanimoto CI High: 0.08 + Top-10 Accuracy: 0.00 + Top-10 Accuracy CI Low: 0.00 + Top-10 Accuracy CI High: 0.00 + Top-10 MCES: 26.87 + Top-10 MCES CI Low: 26.66 + Top-10 MCES CI High: 27.11 + Top-10 Tanimoto: 0.13 + Top-10 Tanimoto CI Low: 0.13 + Top-10 Tanimoto CI High: 0.13 + + - task: de_novo + challenge: bonus + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Top-1 Accuracy: 0.00 + Top-1 Accuracy CI Low: 0.00 + Top-1 Accuracy CI High: 0.00 + Top-1 MCES: 38.88 + Top-1 MCES CI Low: 38.57 + Top-1 MCES CI High: 39.20 + Top-1 Tanimoto: 0.08 + Top-1 Tanimoto CI Low: 0.08 + Top-1 Tanimoto CI High: 0.08 + Top-10 Accuracy: 0.00 + Top-10 Accuracy CI Low: 0.00 + Top-10 Accuracy CI High: 0.00 + Top-10 MCES: 26.87 + Top-10 MCES CI Low: 26.66 + Top-10 MCES CI High: 27.11 + Top-10 Tanimoto: 0.13 + Top-10 Tanimoto CI Low: 0.13 + Top-10 Tanimoto CI High: 0.13 + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Baseline from the MassSpecGym benchmark paper." diff --git a/submissions/SMILES_Transformer/model_card.yaml b/submissions/SMILES_Transformer/model_card.yaml new file mode 100644 index 0000000..eaba432 --- /dev/null +++ b/submissions/SMILES_Transformer/model_card.yaml @@ -0,0 +1,76 @@ +method_name: "SMILES Transformer" +paper_url: "https://arxiv.org/abs/2410.23326" +code_url: "https://github.com/pluskal-lab/MassSpecGym" +random_seed: null + +results: + - task: de_novo + challenge: standard + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Top-1 Accuracy: 0.00 + Top-1 Accuracy CI Low: 0.00 + Top-1 Accuracy CI High: 0.00 + Top-1 MCES: 79.39 + Top-1 MCES CI Low: 78.64 + Top-1 MCES CI High: 80.08 + Top-1 Tanimoto: 0.03 + Top-1 Tanimoto CI Low: 0.03 + Top-1 Tanimoto CI High: 0.04 + Top-10 Accuracy: 0.00 + Top-10 Accuracy CI Low: 0.00 + Top-10 Accuracy CI High: 0.00 + Top-10 MCES: 52.13 + Top-10 MCES CI Low: 51.45 + Top-10 MCES CI High: 52.81 + Top-10 Tanimoto: 0.10 + Top-10 Tanimoto CI Low: 0.09 + Top-10 Tanimoto CI High: 0.10 + + - task: de_novo + challenge: bonus + uses_formula_at_inference: false + paper: "MassSpecGym: A benchmark for the discovery and identification of molecules" + doi: "https://doi.org/10.48550/arXiv.2410.23326" + publication_date: "2025-01-14" + comment: "" + metrics: + Top-1 Accuracy: 0.00 + Top-1 Accuracy CI Low: 0.00 + Top-1 Accuracy CI High: 0.00 + Top-1 MCES: 79.39 + Top-1 MCES CI Low: 78.64 + Top-1 MCES CI High: 80.08 + Top-1 Tanimoto: 0.03 + Top-1 Tanimoto CI Low: 0.03 + Top-1 Tanimoto CI High: 0.04 + Top-10 Accuracy: 0.00 + Top-10 Accuracy CI Low: 0.00 + Top-10 Accuracy CI High: 0.00 + Top-10 MCES: 52.13 + Top-10 MCES CI Low: 51.45 + Top-10 MCES CI High: 52.81 + Top-10 Tanimoto: 0.10 + Top-10 Tanimoto CI Low: 0.09 + Top-10 Tanimoto CI High: 0.10 + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Baseline from the MassSpecGym benchmark paper." diff --git a/submissions/SUBMISSION_GUIDE.md b/submissions/SUBMISSION_GUIDE.md new file mode 100644 index 0000000..ecb0224 --- /dev/null +++ b/submissions/SUBMISSION_GUIDE.md @@ -0,0 +1,199 @@ +# MassSpecGym Leaderboard Submission Guide + +## What your PR must contain + +Fork this repository, create a branch, and open a PR to `main` with **exactly this layout**: + +``` +submissions// + model_card.yaml required + / optional but strongly recommended + train.py + eval.py + ... +``` + +Rules: +- `` must exactly match the `method_name` field in your model card (spaces โ†’ underscores, e.g. `"My Model"` โ†’ `submissions/My_Model/`) +- Only one method per PR +- Do **not** edit `results/*.csv` โ€” regenerated automatically +- Do **not** touch any file outside `submissions//` + +Your source code is welcome in the PR for review purposes. It will be stripped automatically before merge โ€” only `model_card.yaml` is retained in the repository. Make sure your `code_url` in the model card points to a public repository for long-term access. + +--- + +## model_card.yaml + +Copy [`submissions/template/model_card.yaml`](template/model_card.yaml) and fill in every field. Required fields: + +| Field | Description | +|-------|-------------| +| `method_name` | Display name on the leaderboard (must match folder name) | +| `paper_url` | arXiv, DOI, or preprint URL โ€” must be accessible | +| `code_url` | Public GitHub/GitLab URL โ€” must be accessible | +| `random_seed` | Integer seed used for reported results | +| `results` | List of task/challenge entries (see below) | +| `uses_mist_encoder` | `true` if MIST spectrum encoder used | +| `uses_mist_cf` | `true` if MIST-CF formula predictor used | +| `uses_iceberg` | `true` if ICEBERG spectral simulator used | +| `pretraining.used` | `true` if any external pretraining data used | +| `uses_official_split` | Must be `true` | + +Each entry in `results` requires: + +| Field | Description | +|-------|-------------| +| `task` | `de_novo` \| `retrieval` \| `simulation` | +| `challenge` | `standard` \| `bonus` | +| `uses_formula_at_inference` | `true` if formula predictor filters candidates at inference | +| `paper` | Full paper title | +| `doi` | DOI or arXiv URL | +| `publication_date` | `YYYY-MM-DD` | +| `metrics` | All required metric keys with values and 95% bootstrap CIs (see below) | + +**Tier integrity:** `uses_formula_at_inference: true` requires `challenge: bonus`. Submitting a formula-assisted model to `challenge: standard` is a hard failure. + +### Required metric keys + +**De novo (standard and bonus):** +```yaml +metrics: + Top-1 Accuracy: 0.00 + Top-1 Accuracy CI Low: 0.00 + Top-1 Accuracy CI High: 0.00 + Top-1 MCES: 0.00 + Top-1 MCES CI Low: 0.00 + Top-1 MCES CI High: 0.00 + Top-1 Tanimoto: 0.00 + Top-1 Tanimoto CI Low: 0.00 + Top-1 Tanimoto CI High: 0.00 + Top-10 Accuracy: 0.00 + Top-10 Accuracy CI Low: 0.00 + Top-10 Accuracy CI High: 0.00 + Top-10 MCES: 0.00 + Top-10 MCES CI Low: 0.00 + Top-10 MCES CI High: 0.00 + Top-10 Tanimoto: 0.00 + Top-10 Tanimoto CI Low: 0.00 + Top-10 Tanimoto CI High: 0.00 +``` + +**Retrieval (standard and bonus):** +```yaml +metrics: + Hit rate @ 1: 0.00 + Hit rate @ 1 CI Low: 0.00 + Hit rate @ 1 CI High: 0.00 + Hit rate @ 5: 0.00 + Hit rate @ 5 CI Low: 0.00 + Hit rate @ 5 CI High: 0.00 + Hit rate @ 20: 0.00 + Hit rate @ 20 CI Low: 0.00 + Hit rate @ 20 CI High: 0.00 + MCES @ 1: 0.00 + MCES @ 1 CI Low: 0.00 + MCES @ 1 CI High: 0.00 +``` + +**Simulation (standard and bonus):** +```yaml +metrics: + Cosine Similarity: 0.00 + Cosine Similarity CI Low: 0.00 + Cosine Similarity CI High: 0.00 + Jensen-Shannon Similarity: 0.00 + Jensen-Shannon Similarity CI Low: 0.00 + Jensen-Shannon Similarity CI High: 0.00 + Hit rate @ 1: 0.00 + Hit rate @ 1 CI Low: 0.00 + Hit rate @ 1 CI High: 0.00 + Hit rate @ 5: 0.00 + Hit rate @ 5 CI Low: 0.00 + Hit rate @ 5 CI High: 0.00 + Hit rate @ 20: 0.00 + Hit rate @ 20 CI Low: 0.00 + Hit rate @ 20 CI High: 0.00 +``` + +All CIs are mandatory. Use 95% bootstrap CIs from `ReturnScalarBootStrapper` in `massspecgym/utils.py`. + +--- + +## Submission workflow + +``` +1. You open a PR from your fork to main +2. Maintainer adds 'submission' label โ†’ automated review runs, posts report as PR comment +3. Maintainer reads report, performs human review, approves PR +4. Maintainer adds 'ready-to-merge' label โ†’ prepare workflow triggers: + a. checks out your submission (read-only) + b. strips everything except model_card.yaml + c. regenerates results/*.csv + d. pushes a clean branch to the base repo + e. closes your fork PR with a link to the clean branch +5. Maintainer merges the clean branch into main +``` + +You can submit from a fork (any branch) โ€” no special access required. + +--- + +## Automated review checks + +On every PR with the `submission` label, a report is posted as a comment. Hard failures block merge. It checks: + +- Model card present and all required fields filled +- All required metrics present with non-null values and CIs +- Task/tier consistency (standard vs. bonus, formula use) +- SMILES canonicalization +- Pretraining InChIKey overlap (if pretraining data declared) +- Oracle data safety (MIST-CF / ICEBERG v1.5) +- MIST batching bug (if MIST encoder used) +- Metric override detection (custom `on_batch_end` / `evaluate_*`) +- Official data split used +- LLM narrative review of paper and code + +--- + +## Metric specifications + +All metrics must use the pinned MassSpecGym implementations. Do not re-implement them. + +| Metric | Specification | +|--------|--------------| +| InChIKey hit rate | First 14 characters (connectivity layer) only | +| Tanimoto similarity | Morgan ECFP4, radius=2, 2048 bits | +| MCES distance | `threshold=15`, `always_stronger_bound=True` (`massspecgym/utils.py:MyopicMCES`) | +| Cosine similarity | Standard MS/MS cosine as implemented in `massspecgym` | +| Jensen-Shannon similarity | As implemented in `massspecgym` | + +--- + +## Data safety requirements + +### Pretraining data + +If your model uses any external pretraining data, declare it under `pretraining` in the model card. The minimum accepted filtering criterion is `exact_match` (27-char InChIKey deduplication). `tanimoto_0.70` is recommended for results claiming genuine generalization. + +### Oracle components + +If you use MIST-CF or ICEBERG, use the data-safe v1.5 versions in `massspecgym/models/oracles/`. External versions may introduce transitive data leakage. + +--- + +## Checklist before opening PR + +- [ ] `submissions//model_card.yaml` filled in completely +- [ ] Folder name matches `method_name` field exactly +- [ ] All required metrics and 95% CIs present +- [ ] `task` and `challenge` correct for each result entry +- [ ] `paper`, `doi`, `publication_date` filled for each entry +- [ ] Paper URL accessible (arXiv, DOI, or preprint) +- [ ] `code_url` is public and accessible +- [ ] Pretraining data declared if used (with filtering criterion) +- [ ] MIST-CF / ICEBERG: v1.5 data-safe versions confirmed if used +- [ ] Official MassSpecGym data split used (`uses_official_split: true`) +- [ ] Random seed documented +- [ ] No changes to `results/*.csv` +- [ ] No changes outside `submissions//` diff --git a/submissions/Spec2Mol/model_card.yaml b/submissions/Spec2Mol/model_card.yaml new file mode 100644 index 0000000..097eb07 --- /dev/null +++ b/submissions/Spec2Mol/model_card.yaml @@ -0,0 +1,49 @@ +method_name: "Spec2Mol" +paper_url: "https://arxiv.org/abs/2501.01950" +code_url: "" +random_seed: null + +results: + - task: de_novo + challenge: bonus + uses_formula_at_inference: false + paper: "MADGEN: Mass-Spec attends to De Novo Molecular generation" + doi: "https://doi.org/10.48550/arXiv.2501.01950" + publication_date: "2025-04-29" + comment: "" + metrics: + Top-1 Accuracy: 0.00 + Top-1 Accuracy CI Low: "" + Top-1 Accuracy CI High: "" + Top-1 MCES: 45.89 + Top-1 MCES CI Low: "" + Top-1 MCES CI High: "" + Top-1 Tanimoto: 0.09 + Top-1 Tanimoto CI Low: "" + Top-1 Tanimoto CI High: "" + Top-10 Accuracy: 0.00 + Top-10 Accuracy CI Low: "" + Top-10 Accuracy CI High: "" + Top-10 MCES: 32.60 + Top-10 MCES CI Low: "" + Top-10 MCES CI High: "" + Top-10 Tanimoto: 0.13 + Top-10 Tanimoto CI Low: "" + Top-10 Tanimoto CI High: "" + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "CIs not reported in the original submission. Re-evaluated in DiffMS paper (arXiv:2502.09571) โ€” see Spec2Mol entry there." diff --git a/submissions/Spec2Mol_reeval/model_card.yaml b/submissions/Spec2Mol_reeval/model_card.yaml new file mode 100644 index 0000000..8b9fe26 --- /dev/null +++ b/submissions/Spec2Mol_reeval/model_card.yaml @@ -0,0 +1,49 @@ +method_name: "Spec2Mol (re-eval)" +paper_url: "https://arxiv.org/abs/2502.09571" +code_url: "" +random_seed: null + +results: + - task: de_novo + challenge: bonus + uses_formula_at_inference: false + paper: "DiffMS: Diffusion Generation of Molecules Conditioned on Mass Spectra" + doi: "https://doi.org/10.48550/arXiv.2502.09571" + publication_date: "2025-05-27" + comment: "Spec2Mol re-evaluated by DiffMS authors" + metrics: + Top-1 Accuracy: 0.00 + Top-1 Accuracy CI Low: "" + Top-1 Accuracy CI High: "" + Top-1 MCES: 37.76 + Top-1 MCES CI Low: "" + Top-1 MCES CI High: "" + Top-1 Tanimoto: 0.12 + Top-1 Tanimoto CI Low: "" + Top-1 Tanimoto CI High: "" + Top-10 Accuracy: 0.00 + Top-10 Accuracy CI Low: "" + Top-10 Accuracy CI High: "" + Top-10 MCES: 29.40 + Top-10 MCES CI Low: "" + Top-10 MCES CI High: "" + Top-10 Tanimoto: 0.16 + Top-10 Tanimoto CI Low: "" + Top-10 Tanimoto CI High: "" + +uses_mist_encoder: false +uses_mist_cf: false +uses_iceberg: false +mist_cf_version: "" +iceberg_version: "" + +pretraining: + used: false + description: "" + filtering_criterion: "" + inchikey_layer_used: "" + parquet_url: "" + +uses_official_split: true +custom_split_path: "" +notes: "Re-evaluation of Spec2Mol by DiffMS authors. Original evaluation in MADGEN paper (arXiv:2501.01950) is in the Spec2Mol model card." diff --git a/submissions/template/model_card.yaml b/submissions/template/model_card.yaml new file mode 100644 index 0000000..99f1272 --- /dev/null +++ b/submissions/template/model_card.yaml @@ -0,0 +1,131 @@ +# MassSpecGym Model Card Template +# Copy this file to submissions//model_card.yaml and fill in all fields. +# must exactly match the method_name field below +# (use underscores for spaces, e.g. "My Model" -> submissions/My_Model/model_card.yaml). + +# Identity +method_name: "" # Display name on the leaderboard (spaces allowed, e.g. "My Model") +paper_url: "" # arXiv, DOI, or preprint URL. Required. Flagged if not accessible. +code_url: "" # Public GitHub/GitLab URL. Required. Flagged if not accessible. +random_seed: null # Integer seed used for reported results, e.g. 42 + +# Results +# One entry per task/challenge combination this model is submitted for. +# On merge to main, results/*.csv are regenerated from these entries automatically. +# Do NOT edit results/*.csv directly. + +results: + - task: "" # One of: de_novo | retrieval | simulation + challenge: "" # One of: standard | bonus + uses_formula_at_inference: false # true if formula predictor used to pre-filter candidates + # If uses_formula_at_inference=true and challenge=standard, the review will hard-fail. + + paper: "" # Full paper title (copied to the CSV Paper column) + doi: "" # DOI or arXiv URL (copied to the CSV DOI column) + publication_date: "" # YYYY-MM-DD + comment: "" # Optional free-text note for the leaderboard (e.g. "uses pretraining") + + # All metric values and 95% bootstrap CIs. + # Keys must match exactly โ€” see SUBMISSION_GUIDE.md for the full list per task. + metrics: + # De novo example (remove the block that doesn't apply): + # Top-1 Accuracy: 0.00 + # Top-1 Accuracy CI Low: 0.00 + # Top-1 Accuracy CI High: 0.00 + # Top-1 MCES: 0.00 + # Top-1 MCES CI Low: 0.00 + # Top-1 MCES CI High: 0.00 + # Top-1 Tanimoto: 0.00 + # Top-1 Tanimoto CI Low: 0.00 + # Top-1 Tanimoto CI High: 0.00 + # Top-10 Accuracy: 0.00 + # Top-10 Accuracy CI Low: 0.00 + # Top-10 Accuracy CI High: 0.00 + # Top-10 MCES: 0.00 + # Top-10 MCES CI Low: 0.00 + # Top-10 MCES CI High: 0.00 + # Top-10 Tanimoto: 0.00 + # Top-10 Tanimoto CI Low: 0.00 + # Top-10 Tanimoto CI High: 0.00 + + # Retrieval example: + # Hit rate @ 1: 0.00 + # Hit rate @ 1 CI Low: 0.00 + # Hit rate @ 1 CI High: 0.00 + # Hit rate @ 5: 0.00 + # Hit rate @ 5 CI Low: 0.00 + # Hit rate @ 5 CI High: 0.00 + # Hit rate @ 20: 0.00 + # Hit rate @ 20 CI Low: 0.00 + # Hit rate @ 20 CI High: 0.00 + # MCES @ 1: 0.00 + # MCES @ 1 CI Low: 0.00 + # MCES @ 1 CI High: 0.00 + + # Simulation example: + # Cosine Similarity: 0.00 + # Cosine Similarity CI Low: 0.00 + # Cosine Similarity CI High: 0.00 + # Jensen-Shannon Similarity: 0.00 + # Jensen-Shannon Similarity CI Low: 0.00 + # Jensen-Shannon Similarity CI High: 0.00 + # Hit rate @ 1: 0.00 + # Hit rate @ 1 CI Low: 0.00 + # Hit rate @ 1 CI High: 0.00 + # Hit rate @ 5: 0.00 + # Hit rate @ 5 CI Low: 0.00 + # Hit rate @ 5 CI High: 0.00 + # Hit rate @ 20: 0.00 + # Hit rate @ 20 CI Low: 0.00 + # Hit rate @ 20 CI High: 0.00 + + # Add more entries if the model is evaluated on multiple tasks/challenges: + # - task: retrieval + # challenge: standard + # uses_formula_at_inference: false + # paper: "" + # doi: "" + # publication_date: "" + # comment: "" + # metrics: + # Hit rate @ 1: 0.00 + # ... + +# Model architecture + +uses_mist_encoder: false # true if MIST spectrum encoder used +uses_mist_cf: false # true if MIST-CF formula predictor used at any stage +uses_iceberg: false # true if ICEBERG spectral simulator used at any stage + +# If uses_mist_encoder=true, we check the linked code for the -inf attention mask fix. +# If uses_mist_cf=true or uses_iceberg=true, confirm you use the v1.5 data-safe versions: +mist_cf_version: "" # "v1.5_data_safe" or describe the version used +iceberg_version: "" # "v1.5_data_safe" or describe the version used + +# Pretraining data + +pretraining: + used: false # Set true if ANY external data was used for pretraining + # (decoder pretraining, encoder pretraining, fine-tuning, etc.) + + # Fill in the fields below only if used=true: + description: "" # Free text: what datasets, how many molecules, which model component + filtering_criterion: "" # How test/val molecules were excluded from pretraining data. + # One of: exact_match | tanimoto_0.85 | tanimoto_0.70 | tanimoto_0.50 | none + # "exact_match" = only 27-char InChIKey deduplication (minimum accepted) + # "tanimoto_0.70" = recommended for credible generalization claims + inchikey_layer_used: "" # "14char" (connectivity, correct) or "27char" (full, insufficient) + parquet_url: "" # Public URL to pretraining molecule parquet/CSV, if available. + # If not public, explain why in description. Used for automated + # InChIKey overlap check via massspecgym.data.sanity_check. + +# Evaluation setup + +uses_official_split: true # Must be true. Set false only if you have a specific reason + # and can justify it; will trigger manual review. +custom_split_path: "" # Fill if uses_official_split=false + +# Notes for reviewers +# Optional free-text notes for the human reviewer. Describe anything unusual +# about your setup, known limitations, or things the automated review may miss. +notes: "" diff --git a/tests/test_fp2mol_v15.py b/tests/test_fp2mol_v15.py deleted file mode 100644 index 24b8db3..0000000 --- a/tests/test_fp2mol_v15.py +++ /dev/null @@ -1,552 +0,0 @@ -"""Comprehensive validation of MassSpecGym v1.5 FP2Mol implementations. - -Tests all new modules against reference implementations for correctness. -Run on a GPU node: ssh node3509, conda activate massspecgym, python tests/test_fp2mol_v15.py -""" - -import sys -import math -import traceback -import torch -import numpy as np - -PASS = 0 -FAIL = 0 - -def check(name, condition, detail=""): - global PASS, FAIL - if condition: - PASS += 1 - print(f" [PASS] {name}") - else: - FAIL += 1 - print(f" [FAIL] {name} -- {detail}") - - -def test_chem_constants(): - print("\n=== Phase 1a: Chemistry Constants ===") - from massspecgym.models.encoders.mist.chem_constants import ( - VALID_ELEMENTS, NORM_VEC, formula_to_dense, vec_to_formula, - max_instr_idx, ion_to_idx, element_to_ind, - ) - check("VALID_ELEMENTS count", len(VALID_ELEMENTS) == 18) - check("VALID_ELEMENTS starts with C,H", VALID_ELEMENTS[0] == "C" and VALID_ELEMENTS[1] == "H") - check("NORM_VEC shape", len(NORM_VEC) == 18) - check("NORM_VEC[0] (C max)", NORM_VEC[0] == 81) - - # formula_to_dense - v = formula_to_dense("C6H12O6") - check("formula_to_dense C6H12O6: C=6", v[element_to_ind["C"]] == 6) - check("formula_to_dense C6H12O6: H=12", v[element_to_ind["H"]] == 12) - check("formula_to_dense C6H12O6: O=6", v[element_to_ind["O"]] == 6) - - # vec_to_formula roundtrip - f = vec_to_formula(v) - check("vec_to_formula roundtrip", "C6" in f and "H12" in f and "O6" in f, f) - - # max_instr_idx - check("max_instr_idx > 0", max_instr_idx > 0, str(max_instr_idx)) - - # ion_to_idx - check("ion_to_idx has [M+H]+", "[M+H]+" in ion_to_idx) - - -def test_form_embedders(): - print("\n=== Phase 1b: Form Embedders ===") - from massspecgym.models.encoders.mist.form_embedders import ( - get_embedder, FloatFeaturizer, FourierFeaturizerPosCos, FourierFeaturizer, - RBFFeaturizer, OneHotFeaturizer, LearnedFeaturizer, - ) - from massspecgym.models.encoders.mist.chem_constants import NORM_VEC - - # FloatFeaturizer - fe = get_embedder("float") - check("get_embedder('float') type", isinstance(fe, FloatFeaturizer)) - check("FloatFeaturizer.num_dim", fe.num_dim == 1) - check("FloatFeaturizer.full_dim", fe.full_dim == len(NORM_VEC)) - t = torch.tensor([[6.0, 12.0, 0.0, 6.0] + [0.0]*14]) - out = fe(t) - check("FloatFeaturizer output shape", out.shape == (1, 18), str(out.shape)) - - # FourierFeaturizerPosCos - fc = get_embedder("pos-cos") - check("get_embedder('pos-cos') type", isinstance(fc, FourierFeaturizerPosCos)) - check("FourierFeaturizerPosCos.num_funcs", fc.num_funcs == 9) - out = fc(t) - check("FourierFeaturizerPosCos output shape", out.shape == (1, 18 * 9), str(out.shape)) - - # All embedders - for name in ["fourier", "rbf", "one-hot", "learnt", "float", "fourier-sines", "abs-sines", "pos-cos"]: - try: - emb = get_embedder(name) - out = emb(t) - check(f"get_embedder('{name}') works", out.shape[0] == 1 and out.shape[1] > 0) - except Exception as e: - check(f"get_embedder('{name}') works", False, str(e)) - - -def test_transformer_layer(): - print("\n=== Phase 1c: Transformer Layer ===") - from massspecgym.models.encoders.mist.transformer_layer import TransformerEncoderLayer, MultiheadAttention - - # Basic TransformerEncoderLayer - layer = TransformerEncoderLayer(d_model=64, nhead=4, dim_feedforward=128, dropout=0.0) - src = torch.randn(10, 2, 64) # (seq, batch, dim) - out, pw = layer(src) - check("TransformerEncoderLayer output shape", out.shape == (10, 2, 64), str(out.shape)) - check("TransformerEncoderLayer no pairwise", pw is None) - - # With key_padding_mask - mask = torch.zeros(2, 10, dtype=torch.bool) - mask[0, 7:] = True - out2, _ = layer(src, src_key_padding_mask=mask) - check("TransformerEncoderLayer with mask shape", out2.shape == (10, 2, 64)) - - # Pairwise featurization - layer_pw = TransformerEncoderLayer(d_model=64, nhead=4, pairwise_featurization=True, dropout=0.0) - pw_feats = torch.randn(2, 10, 10, 64) - out3, pw3 = layer_pw(src, pairwise_features=pw_feats) - check("TransformerEncoderLayer pairwise output shape", out3.shape == (10, 2, 64)) - - # Additive attention - layer_add = TransformerEncoderLayer(d_model=64, nhead=4, additive_attn=True, dropout=0.0) - out4, _ = layer_add(src) - check("TransformerEncoderLayer additive attn shape", out4.shape == (10, 2, 64)) - - -def test_modules(): - print("\n=== Phase 1d: MIST Modules ===") - from massspecgym.models.encoders.mist.modules import FormulaTransformer, FPGrowingModule, MLPBlocks - - # MLPBlocks - mlp = MLPBlocks(input_size=32, hidden_size=64, dropout=0.0, num_layers=3) - out = mlp(torch.randn(2, 32)) - check("MLPBlocks output shape", out.shape == (2, 64)) - - # FPGrowingModule - fpg = FPGrowingModule(hidden_input_dim=64, final_target_dim=4096, num_splits=4, reduce_factor=2) - out = fpg(torch.randn(2, 64)) - check("FPGrowingModule returns list", isinstance(out, list)) - check("FPGrowingModule num outputs", len(out) == 5, str(len(out))) # num_splits + 1 - check("FPGrowingModule final dim", out[-1].shape == (2, 4096), str(out[-1].shape)) - - # FormulaTransformer - basic - ft = FormulaTransformer( - hidden_size=64, peak_attn_layers=2, set_pooling="intensity", - num_heads=4, output_size=2048, form_embedder="float", - ) - batch = { - "num_peaks": torch.tensor([3, 2]), - "types": torch.tensor([[0, 1, 3, 0], [0, 3, 0, 0]]), - "instruments": torch.tensor([0, 1]), - "ion_vec": torch.tensor([[0, 0, 0, 0], [0, 0, 0, 0]]), - "form_vec": torch.randn(2, 4, 18), - "intens": torch.tensor([[0.5, 0.3, 0.2, 0.0], [0.7, 0.3, 0.0, 0.0]]), - } - out, aux = ft(batch, return_aux=True) - check("FormulaTransformer output shape", out.shape == (2, 64), str(out.shape)) - check("FormulaTransformer has peak_tensor aux", "peak_tensor" in aux) - - -def test_encoder(): - print("\n=== Phase 1e: SpectraEncoder ===") - from massspecgym.models.encoders.mist.encoder import SpectraEncoder, SpectraEncoderGrowing - - batch = { - "num_peaks": torch.tensor([3, 2]), - "types": torch.tensor([[0, 1, 3, 0], [0, 3, 0, 0]]), - "instruments": torch.tensor([0, 1]), - "ion_vec": torch.tensor([[0, 0, 0, 0], [0, 0, 0, 0]]), - "form_vec": torch.randn(2, 4, 18), - "intens": torch.tensor([[0.5, 0.3, 0.2, 0.0], [0.7, 0.3, 0.0, 0.0]]), - } - - enc = SpectraEncoder( - form_embedder="float", output_size=4096, hidden_size=64, - peak_attn_layers=2, num_heads=4, - ) - out, aux = enc(batch) - check("SpectraEncoder output shape", out.shape == (2, 4096), str(out.shape)) - check("SpectraEncoder output range [0,1]", out.min() >= 0 and out.max() <= 1, f"[{out.min():.4f}, {out.max():.4f}]") - check("SpectraEncoder has h0", "h0" in aux) - check("SpectraEncoder has pred_frag_fps", "pred_frag_fps" in aux) - - enc_g = SpectraEncoderGrowing( - form_embedder="float", output_size=4096, hidden_size=64, - peak_attn_layers=2, num_heads=4, refine_layers=3, - ) - out_g, aux_g = enc_g(batch) - check("SpectraEncoderGrowing output shape", out_g.shape == (2, 4096), str(out_g.shape)) - check("SpectraEncoderGrowing has int_preds", "int_preds" in aux_g) - check("SpectraEncoderGrowing int_preds count", len(aux_g["int_preds"]) == 3, str(len(aux_g["int_preds"]))) - - -def test_formula_encoder(): - print("\n=== Phase 2: FormulaEncoder ===") - from massspecgym.models.de_novo.fp2mol.formula_utils import FormulaEncoder - - enc = FormulaEncoder(normalize="none") - check("FormulaEncoder vocab_size", enc.vocab_size == 30) - - v = enc.encode("C6H12O6") - check("encode C6H12O6 shape", v.shape == (30,), str(v.shape)) - check("encode C6H12O6 C=6", v[0].item() == 6.0) - check("encode C6H12O6 H=12", v[1].item() == 12.0) - check("encode C6H12O6 O=6", v[3].item() == 6.0) - check("encode C6H12O6 N=0", v[2].item() == 0.0) - - # Batch - vb = enc.encode_batch(["C6H12O6", "CH4", "C2H5OH"]) - check("encode_batch shape", vb.shape == (3, 30), str(vb.shape)) - - # Decode roundtrip - d = enc.decode(v) - check("decode roundtrip contains C6", "C6" in d, d) - - # Normalization - v_sum = enc.encode("C6H12O6", normalize="sum") - check("sum normalization sums to 1", abs(v_sum.sum().item() - 1.0) < 1e-5, str(v_sum.sum().item())) - - -def test_mdlm(): - print("\n=== Phase 3a: MDLM ===") - from massspecgym.models.de_novo.fp2mol.frigid.mdlm import MDLM, LogLinearExpNoiseSchedule - - # Noise schedule - ns = LogLinearExpNoiseSchedule(alpha_max=1.0, alpha_min=1e-3) - t0 = torch.tensor([0.0]) - t1 = torch.tensor([1.0]) - check("alpha(0) ~ 1", abs(ns.alpha(t0).item() - 1.0) < 1e-5) - check("alpha(1) ~ 1e-3", abs(ns.alpha(t1).item() - 1e-3) < 1e-5) - - # MDLM - mdlm = MDLM(mask_token_id=4, vocab_size=100, sampling_eps=1e-3) - - # sample_time - t = mdlm.sample_time(8, antithetic=True) - check("sample_time antithetic shape", t.shape == (8,), str(t.shape)) - check("sample_time in range", t.min() >= 1e-3 and t.max() <= 1.0, f"[{t.min():.4f}, {t.max():.4f}]") - - # forward_process (avoid mask_token_id=4 in original data) - x0 = torch.randint(5, 100, (4, 20)) - t_fp = torch.tensor([0.0, 0.5, 0.9, 1.0]) - xt = mdlm.forward_process(x0, t_fp) - check("forward_process shape", xt.shape == x0.shape) - check("forward_process t=0 no masks", (xt[0] == 4).sum().item() == 0) - check("forward_process t=1 mostly masks", (xt[3] == 4).sum().item() >= 15, str((xt[3] == 4).sum().item())) - - # loss - logits = torch.randn(4, 20, 100) - mask = torch.ones(4, 20) - t_loss = torch.tensor([0.3, 0.5, 0.7, 0.9]) - xt_loss = mdlm.forward_process(x0, t_loss) - loss = mdlm.loss(logits, x0, xt_loss, t_loss, mask=mask, global_mean=True) - check("loss is scalar", loss.dim() == 0) - check("loss is finite", torch.isfinite(loss), str(loss.item())) - - # step_confidence - x_masked = torch.full((2, 10), 4, dtype=torch.long) - x_masked[:, 0] = 1 # BOS - x_masked[:, -1] = 2 # EOS - logits_sc = torch.randn(2, 10, 100) - x_new = mdlm.step_confidence(logits_sc, x_masked, step_idx=0, num_steps=8, temperature=1.0, randomness=0.5) - check("step_confidence shape", x_new.shape == (2, 10)) - masks_before = (x_masked == 4).sum().item() - masks_after = (x_new == 4).sum().item() - check("step_confidence reduces masks", masks_after < masks_before, f"{masks_before} -> {masks_after}") - - -def test_frigid_components(): - print("\n=== Phase 3b: FRIGID Components ===") - from massspecgym.models.de_novo.fp2mol.frigid.components import ( - FormulaSequenceEncoder, FingerprintSequenceEncoder, - CrossAttentionLayer, CrossAttentionFormulaConditioner, - CrossAttentionFingerprintConditioner, SetSelfAttention, - ) - from massspecgym.models.de_novo.fp2mol.formula_utils import FormulaEncoder - - # FormulaSequenceEncoder - fse = FormulaSequenceEncoder(num_atom_types=30, embedding_dim=64) - fe = FormulaEncoder() - fv = fe.encode_batch(["C6H12O6", "CH4"]) - emb, mask = fse(fv) - check("FormulaSequenceEncoder emb shape", emb.shape == (2, 30, 64), str(emb.shape)) - check("FormulaSequenceEncoder mask shape", mask.shape == (2, 30), str(mask.shape)) - check("FormulaSequenceEncoder mask nonzero", mask[0].sum() > 0 and mask[1].sum() > 0) - - # FingerprintSequenceEncoder - fpse = FingerprintSequenceEncoder( - num_bits=4096, embedding_dim=64, max_seq_len=64, - num_self_attention_layers=2, num_attention_heads=4, - ) - fp = torch.zeros(2, 4096) - fp[0, [1, 50, 100, 200, 500]] = 1.0 - fp[1, [5, 10]] = 1.0 - emb_fp, mask_fp = fpse(fp) - check("FingerprintSequenceEncoder emb shape[0]", emb_fp.shape[0] == 2) - check("FingerprintSequenceEncoder mask[0] active=5", mask_fp[0].sum().item() == 5, str(mask_fp[0].sum().item())) - check("FingerprintSequenceEncoder mask[1] active=2", mask_fp[1].sum().item() == 2, str(mask_fp[1].sum().item())) - - # CrossAttentionLayer - cal = CrossAttentionLayer(hidden_size=64, num_attention_heads=4, dropout=0.0) - hidden = torch.randn(2, 10, 64) - cond = torch.randn(2, 5, 64) - cond_mask = torch.ones(2, 5) - out = cal(hidden, cond, cond_mask) - check("CrossAttentionLayer output shape", out.shape == (2, 10, 64), str(out.shape)) - - # SetSelfAttention - ssa = SetSelfAttention(hidden_size=64, num_attention_heads=4, dropout=0.0) - x = torch.randn(2, 8, 64) - m = torch.ones(2, 8) - out_ssa = ssa(x, m) - check("SetSelfAttention output shape", out_ssa.shape == (2, 8, 64)) - - -def test_diffms_diffusion(): - print("\n=== Phase 4a: DiffMS Diffusion Utils ===") - from massspecgym.models.de_novo.fp2mol.diffms.diffusion_utils import ( - PredefinedNoiseScheduleDiscrete, MarginalUniformTransition, - DiscreteUniformTransition, PlaceHolder, - compute_batched_over0_posterior_distribution, - sample_discrete_features, sample_discrete_feature_noise, - ) - - # Noise schedule - ns = PredefinedNoiseScheduleDiscrete("cosine", 500) - beta_0 = ns(t_int=torch.tensor([0])) - beta_250 = ns(t_int=torch.tensor([250])) - beta_499 = ns(t_int=torch.tensor([499])) - check("cosine schedule beta increasing", beta_0.item() < beta_250.item() < beta_499.item(), - f"{beta_0.item():.6f} < {beta_250.item():.6f} < {beta_499.item():.6f}") - ab = ns.get_alpha_bar(t_int=torch.tensor([0])) - check("alpha_bar(0) close to 1", ab.item() > 0.99, str(ab.item())) - - # Transition matrices - x_marg = torch.tensor([0.5, 0.1, 0.05, 0.05, 0.05, 0.05, 0.1, 0.1]) - e_marg = torch.tensor([0.9, 0.04, 0.03, 0.02, 0.01]) - mt = MarginalUniformTransition(x_marg, e_marg, 0) - Qt = mt.get_Qt(torch.tensor([0.1]), "cpu") - check("MarginalTransition Qt.X shape", Qt.X.shape == (1, 8, 8), str(Qt.X.shape)) - check("MarginalTransition Qt.E shape", Qt.E.shape == (1, 5, 5), str(Qt.E.shape)) - check("Qt.X rows sum to 1", (Qt.X.sum(dim=-1) - 1.0).abs().max().item() < 1e-5) - - # sample_discrete_feature_noise - node_mask = torch.ones(2, 5, dtype=torch.bool) - limit = PlaceHolder(X=x_marg, E=e_marg, y=torch.zeros(0)) - noise = sample_discrete_feature_noise(limit, node_mask) - check("sample_noise X shape", noise.X.shape == (2, 5, 8), str(noise.X.shape)) - check("sample_noise E shape", noise.E.shape == (2, 5, 5, 5), str(noise.E.shape)) - check("sample_noise E symmetric", (noise.E - noise.E.transpose(1, 2)).abs().max().item() < 1e-5) - - -def test_mdlm_loss_weight(): - """Verify MDLM loss weight matches bionemo formula: dsigma/expm1(sigma).""" - print("\n=== Phase 3c: MDLM Loss Weight Verification ===") - from massspecgym.models.de_novo.fp2mol.frigid.mdlm import MDLM, LogLinearExpNoiseSchedule - - ns = LogLinearExpNoiseSchedule(alpha_max=1.0, alpha_min=1e-3) - - # Check sigma(t) - t = torch.tensor([0.0, 0.5, 1.0]) - sigma = ns.sigma(t) - check("sigma(0) = 0", abs(sigma[0].item()) < 1e-5, str(sigma[0].item())) - check("sigma(1) = -log(1e-3) ~ 6.9", abs(sigma[2].item() - 6.9078) < 0.01, str(sigma[2].item())) - - # Check d_sigma/dt - dsig = ns.d_sigma_dt(t) - expected = -math.log(1e-3) # log(1000) ~ 6.9078 - check("d_sigma/dt is constant ~6.9", abs(dsig[0].item() - expected) < 0.01, str(dsig[0].item())) - - # Check loss_weight = dsigma / expm1(sigma) - t_mid = torch.tensor([0.5]) - w = ns.loss_weight(t_mid) - sig_mid = ns.sigma(t_mid) - dsig_mid = ns.d_sigma_dt(t_mid) - expected_w = dsig_mid / torch.expm1(sig_mid) - check("loss_weight formula", torch.allclose(w, expected_w, atol=1e-6), - f"got={w.item():.6f}, expected={expected_w.item():.6f}") - - # Verify weight is larger at low t (few masked) and smaller at high t (many masked) - t_test = torch.linspace(0.01, 0.99, 10) - weights = ns.loss_weight(t_test) - check("loss_weight decreasing with t", all(weights[i] >= weights[i+1] for i in range(len(weights)-1)), - str(weights.tolist())) - - -def test_diffms_graph_transformer(): - print("\n=== Phase 4b: DiffMS GraphTransformer ===") - from massspecgym.models.de_novo.fp2mol.diffms.graph_transformer import GraphTransformer, XEyTransformerLayer - - gt = GraphTransformer( - n_layers=2, - input_dims={"X": 9, "E": 6, "y": 33}, - hidden_mlp_dims={"X": 32, "E": 16, "y": 32}, - hidden_dims={"dx": 32, "de": 16, "dy": 32, "n_head": 4, "dim_ffX": 32, "dim_ffE": 16}, - output_dims={"X": 8, "E": 5, "y": 0}, - ) - X = torch.randn(2, 5, 9) - E = torch.randn(2, 5, 5, 6) - y = torch.randn(2, 33) - mask = torch.ones(2, 5) - out = gt(X, E, y, mask) - check("GraphTransformer X out shape", out.X.shape == (2, 5, 8), str(out.X.shape)) - check("GraphTransformer E out shape", out.E.shape == (2, 5, 5, 5), str(out.E.shape)) - - -def test_diffms_mol_from_graphs(): - print("\n=== Phase 4c: DiffMS mol_from_graphs ===") - from massspecgym.models.de_novo.fp2mol.diffms.model import mol_from_graphs - from rdkit import Chem - - # Simple ethanol-like: C-C-O - nodes = np.array([0, 0, 3]) # C=0, O=3 in ATOM_DECODER - adj = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]]) # single bonds - mol = mol_from_graphs(nodes, adj) - check("mol_from_graphs returns mol", mol is not None) - if mol: - smi = Chem.MolToSmiles(mol) - check("mol_from_graphs SMILES valid", smi is not None and len(smi) > 0, smi) - - # Benzene-like: aromatic - nodes_benz = np.array([0]*6) # 6 carbons - adj_benz = np.zeros((6, 6), dtype=int) - for i in range(6): - adj_benz[i, (i+1) % 6] = 4 # aromatic - adj_benz[(i+1) % 6, i] = 4 - mol_benz = mol_from_graphs(nodes_benz, adj_benz) - check("mol_from_graphs benzene", mol_benz is not None) - - -def test_molforge_search(): - print("\n=== Phase 5a: MolForge Search ===") - from massspecgym.models.de_novo.fp2mol.molforge.decoder_search import greedy_search, beam_search, _subsequent_mask - - mask = _subsequent_mask(5, torch.device("cpu")) - check("subsequent_mask shape", mask.shape == (5, 5), str(mask.shape)) - check("subsequent_mask causal", mask[0, 0].item() == False) - check("subsequent_mask upper tri", mask[0, 1].item() == True) - - -def test_formula_utils_vs_reference(): - """Cross-validate our FormulaEncoder against the reference FRIGID implementation.""" - print("\n=== Phase 6: Cross-validation vs Reference ===") - from massspecgym.models.de_novo.fp2mol.formula_utils import FormulaEncoder - sys.path.insert(0, "/home/liuhx25/MassSpecGym/external/genms/src") - try: - from genmol.utils.formula_encoder import FormulaEncoder as RefFormulaEncoder - ours = FormulaEncoder(normalize="none") - ref = RefFormulaEncoder(normalize="none") - - check("vocab_size match", ours.vocab_size == ref.vocab_size, f"{ours.vocab_size} vs {ref.vocab_size}") - check("ATOM_VOCAB match", ours.ATOM_VOCAB == ref.ATOM_VOCAB) - - test_formulas = ["C6H12O6", "CH4", "C2H5OH", "C9H10N2O2", "C20H30BrClN2O4S"] - for f in test_formulas: - v_ours = ours.encode(f) - v_ref = ref.encode(f) - match = torch.allclose(v_ours, v_ref) - check(f"FormulaEncoder '{f}' matches ref", match, - f"diff={torch.abs(v_ours - v_ref).max().item()}" if not match else "") - - # Batch - vb_ours = ours.encode_batch(test_formulas) - vb_ref = ref.encode_batch(test_formulas) - check("encode_batch matches ref", torch.allclose(vb_ours, vb_ref)) - except ImportError as e: - print(f" [SKIP] Reference FRIGID not importable: {e}") - finally: - if "/home/liuhx25/MassSpecGym/external/genms/src" in sys.path: - sys.path.remove("/home/liuhx25/MassSpecGym/external/genms/src") - - -def test_mist_encoder_vs_reference(): - """Cross-validate our MIST modules against the reference FRIGID implementation.""" - print("\n=== Phase 7: MIST Encoder Cross-validation ===") - from massspecgym.models.encoders.mist.modules import FormulaTransformer as OurFT, FPGrowingModule as OurFPG - from massspecgym.models.encoders.mist.form_embedders import get_embedder as our_get_embedder - from massspecgym.models.encoders.mist.chem_constants import NORM_VEC as OUR_NORM_VEC - - sys.path.insert(0, "/home/liuhx25/MassSpecGym/external/genms/src") - try: - from mist.models.modules import FormulaTransformer as RefFT, FPGrowingModule as RefFPG - from mist.models.form_embedders import get_embedder as ref_get_embedder - from mist.utils.chem_utils import NORM_VEC as REF_NORM_VEC - - # NORM_VEC - check("NORM_VEC matches ref", np.array_equal(OUR_NORM_VEC, REF_NORM_VEC)) - - # Float embedder output - our_fe = our_get_embedder("float") - ref_fe = ref_get_embedder("float") - test_in = torch.tensor([[6.0, 12.0, 0.0, 6.0] + [0.0]*14]) - our_out = our_fe(test_in) - ref_out = ref_fe(test_in) - check("FloatFeaturizer output matches ref", torch.allclose(our_out, ref_out, atol=1e-6), - f"max_diff={torch.abs(our_out - ref_out).max().item()}") - - # pos-cos embedder - our_pc = our_get_embedder("pos-cos") - ref_pc = ref_get_embedder("pos-cos") - our_out_pc = our_pc(test_in) - ref_out_pc = ref_pc(test_in) - check("PosCos embedder output matches ref", torch.allclose(our_out_pc, ref_out_pc, atol=1e-6)) - - # FormulaTransformer constructor compatibility (same kwargs) - our_ft = OurFT(hidden_size=64, peak_attn_layers=2, num_heads=4, form_embedder="float") - ref_ft = RefFT(hidden_size=64, peak_attn_layers=2, num_heads=4, form_embedder="float") - our_params = sum(p.numel() for p in our_ft.parameters()) - ref_params = sum(p.numel() for p in ref_ft.parameters()) - check("FormulaTransformer param count matches", our_params == ref_params, - f"ours={our_params}, ref={ref_params}") - - # FPGrowingModule constructor compatibility - our_fpg = OurFPG(hidden_input_dim=64, final_target_dim=4096, num_splits=4) - ref_fpg = RefFPG(hidden_input_dim=64, final_target_dim=4096, num_splits=4) - our_fp_params = sum(p.numel() for p in our_fpg.parameters()) - ref_fp_params = sum(p.numel() for p in ref_fpg.parameters()) - check("FPGrowingModule param count matches", our_fp_params == ref_fp_params, - f"ours={our_fp_params}, ref={ref_fp_params}") - - except ImportError as e: - print(f" [SKIP] Reference MIST not importable: {e}") - finally: - if "/home/liuhx25/MassSpecGym/external/genms/src" in sys.path: - sys.path.remove("/home/liuhx25/MassSpecGym/external/genms/src") - - -if __name__ == "__main__": - print("=" * 60) - print("MassSpecGym v1.5 FP2Mol Validation Suite") - print("=" * 60) - - tests = [ - test_chem_constants, - test_form_embedders, - test_transformer_layer, - test_modules, - test_encoder, - test_formula_encoder, - test_mdlm, - test_mdlm_loss_weight, - test_frigid_components, - test_diffms_diffusion, - test_diffms_graph_transformer, - test_diffms_mol_from_graphs, - test_molforge_search, - test_formula_utils_vs_reference, - test_mist_encoder_vs_reference, - ] - - for test_fn in tests: - try: - test_fn() - except Exception as e: - FAIL += 1 - print(f"\n [ERROR] {test_fn.__name__} crashed: {e}") - traceback.print_exc() - - print("\n" + "=" * 60) - print(f"Results: {PASS} passed, {FAIL} failed out of {PASS + FAIL} checks") - print("=" * 60) - sys.exit(1 if FAIL > 0 else 0) diff --git a/tests/test_v15_data_oracles.py b/tests/test_v15_data_oracles.py deleted file mode 100644 index 9492607..0000000 --- a/tests/test_v15_data_oracles.py +++ /dev/null @@ -1,326 +0,0 @@ -"""Validation test suite for MassSpecGym v1.5 data pipeline, subformulae, and oracles.""" - -import sys -import json -import traceback -import numpy as np - -PASS = 0 -FAIL = 0 - -def check(name, condition, detail=""): - global PASS, FAIL - if condition: - PASS += 1 - print(f" [PASS] {name}") - else: - FAIL += 1 - print(f" [FAIL] {name} -- {detail}") - - -def test_chem_constants_subformulae(): - print("\n=== Phase 1: chem_constants subformulae functions ===") - from massspecgym.models.encoders.mist.chem_constants import ( - get_all_subsets, rdbe_filter, cross_sum, clipped_ppm, - formula_to_dense, VALID_MONO_MASSES, ELEMENT_VECTORS, - ) - - v = formula_to_dense("CH4") - check("CH4 dense vec C=1", v[0] == 1) - check("CH4 dense vec H=4", v[1] == 4) - - cross_prod, masses = get_all_subsets("CH4") - check("CH4 subsets not empty", len(cross_prod) > 0, str(len(cross_prod))) - check("CH4 subsets includes full formula", any(np.allclose(r, v) for r in cross_prod)) - check("CH4 masses > 0", all(m >= 0 for m in masses)) - - cross_prod2, masses2 = get_all_subsets("C6H12O6") - check("C6H12O6 has many subsets", len(cross_prod2) > 50, str(len(cross_prod2))) - - ppm = clipped_ppm(np.array([0.001]), np.array([500.0])) - check("clipped_ppm scalar", abs(ppm[0] - 2.0) < 0.01, str(ppm[0])) - - ppm_small = clipped_ppm(np.array([0.001]), np.array([100.0])) - expected = 0.001 / 200 * 1e6 - check("clipped_ppm clips to 200", abs(ppm_small[0] - expected) < 0.01, str(ppm_small[0])) - - -def test_subformulae_engine(): - print("\n=== Phase 2: Subformulae assignment engine ===") - from massspecgym.data.subformulae import ( - assign_subformulae_single, get_output_dict, process_spec_file, - parse_spectra_ms, - ) - - spectrum = np.array([ - [91.0542, 0.245], - [125.0233, 1.0], - [155.0577, 0.355], - [246.1125, 0.735], - ]) - - result = assign_subformulae_single("C16H17NO4", spectrum, "[M+H]+", mass_diff_thresh=20.0) - check("assign result has cand_form", result["cand_form"] == "C16H17NO4") - check("assign result has cand_ion", result["cand_ion"] == "[M+H]+") - check("assign result has output_tbl", result["output_tbl"] is not None) - - if result["output_tbl"] is not None: - tbl = result["output_tbl"] - check("output_tbl has mz", "mz" in tbl) - check("output_tbl has formula", "formula" in tbl) - check("output_tbl has ms2_inten", "ms2_inten" in tbl) - check("output_tbl has ions", "ions" in tbl) - check("output_tbl has mono_mass", "mono_mass" in tbl) - check("peaks assigned > 0", len(tbl["mz"]) > 0, str(len(tbl["mz"]))) - - result_bad_ion = assign_subformulae_single("C16H17NO4", spectrum, "[M-H]-") - check("bad ion returns None output_tbl", result_bad_ion["output_tbl"] is None) - - -def test_subformulae_vs_reference(): - """Cross-validate against reference output at /home/liuhx25/orcd/pool/data/msg/.""" - print("\n=== Phase 3: Subformulae cross-validation vs MSG reference ===") - import json - from pathlib import Path - from massspecgym.data.subformulae import assign_subformulae_single, parse_spectra_ms, process_spec_file - - ref_dir = Path("/home/liuhx25/orcd/pool/data/msg") - spec_file = ref_dir / "spec_files" / "MassSpecGymID0000001.ms" - ref_json = ref_dir / "subformulae" / "default_subformulae" / "MassSpecGymID0000001.json" - - if not spec_file.exists() or not ref_json.exists(): - print(" [SKIP] Reference MSG data not found") - return - - meta, tuples = parse_spectra_ms(str(spec_file)) - spec = process_spec_file(meta, tuples) - check("parsed spec not None", spec is not None) - - if spec is None: - return - - with open(ref_json) as f: - ref = json.load(f) - - result = assign_subformulae_single( - ref["cand_form"], spec, ref["cand_ion"], mass_diff_thresh=20.0 - ) - - check("formula matches ref", result["cand_form"] == ref["cand_form"]) - check("ion matches ref", result["cand_ion"] == ref["cand_ion"]) - - if result["output_tbl"] is not None and ref["output_tbl"] is not None: - our_formulas = set(result["output_tbl"]["formula"]) - ref_formulas = set(ref["output_tbl"]["formula"]) - check("formula overlap > 50%", - len(our_formulas & ref_formulas) / max(len(ref_formulas), 1) > 0.5, - f"ours={len(our_formulas)}, ref={len(ref_formulas)}, overlap={len(our_formulas & ref_formulas)}") - - -def test_sanity_check(): - print("\n=== Phase 4: InChIKey sanity check ===") - from massspecgym.data.sanity_check import ( - check_inchikey_overlap, check_inchikey_overlap_strict, DataLeakageError, - load_exclusion_set, - ) - - exclude_set = load_exclusion_set() - check("exclusion set loaded", len(exclude_set) > 8000, str(len(exclude_set))) - - clean_keys = ["ABCDEFGHIJKLMN", "ZYXWVUTSRQPONM"] - result = check_inchikey_overlap(clean_keys) - check("clean data passes", result.is_clean) - check("clean count correct", result.total_molecules == 2) - - dirty_keys = list(exclude_set)[:3] + clean_keys - result2 = check_inchikey_overlap(dirty_keys) - check("dirty data detected", not result2.is_clean) - check("overlap count >= 3", result2.overlap_count >= 3, str(result2.overlap_count)) - - try: - check_inchikey_overlap_strict(dirty_keys) - check("strict raises on dirty", False, "should have raised") - except DataLeakageError: - check("strict raises on dirty", True) - - -def test_magma_fragmentation(): - print("\n=== Phase 5: MAGMa FragmentEngine ===") - from massspecgym.models.simulation.iceberg.magma import FragmentEngine - - engine = FragmentEngine("CCO", max_tree_depth=2, max_broken_bonds=3) - check("FragmentEngine created", engine.mol is not None) - check("FragmentEngine natoms=3", engine.natoms == 3) - - engine.generate_fragments() - n_frags = len(engine.frag_to_entry) - check("fragments generated", n_frags > 1, str(n_frags)) - - root = engine.get_root_frag() - check("root frag correct", root == (1 << 3) - 1) - - forms, masses = engine.get_frag_forms() - check("frag_forms not empty", len(forms) > 0, str(len(forms))) - check("frag_masses positive", all(m > 0 for m in masses)) - - engine2 = FragmentEngine("c1ccccc1", max_tree_depth=2) - engine2.generate_fragments() - check("benzene fragments", len(engine2.frag_to_entry) > 1, str(len(engine2.frag_to_entry))) - - -def test_fp2mol_dataset_parquet(): - print("\n=== Phase 6: FP2MolDataset Parquet ===") - import tempfile, os - import pandas as pd - - smiles_list = ["CCO", "CC(=O)O", "c1ccccc1", "CC(C)O"] - df = pd.DataFrame({ - "smiles": smiles_list, - "inchikey_14": ["LFQSCWFLJHTTHZ", "QTBSBXVTEAMEQO", "UHOVQNZJYSORNB", "KFZMGEQAYNKOFK"], - "formula": ["C2H6O", "C2H4O2", "C6H6", "C3H8O"], - }) - - with tempfile.NamedTemporaryFile(suffix=".parquet", delete=False) as f: - df.to_parquet(f.name) - tmp_path = f.name - - try: - from massspecgym.data.fp2mol_dataset import FP2MolDataset - ds = FP2MolDataset(tmp_path, exclude_inchikeys=False) - check("FP2MolDataset loads parquet", len(ds) == 4, str(len(ds))) - - item = ds[0] - check("item has fingerprint", "fingerprint" in item) - check("item has formula", "formula" in item) - check("item has mol", "mol" in item) - check("fingerprint shape", item["fingerprint"].shape[0] == 4096) - finally: - os.unlink(tmp_path) - - try: - from massspecgym.data.fp2mol_dataset import FP2MolDataset - ds2 = FP2MolDataset(smiles_list, exclude_inchikeys=False) - check("FP2MolDataset list input", len(ds2) == 4) - except Exception as e: - check("FP2MolDataset list input", False, str(e)) - - -def test_oracle_interfaces(): - print("\n=== Phase 7: Oracle interfaces ===") - from massspecgym.models.oracles import OracleBase - from massspecgym.models.oracles.mist_cf import predict_formulas, MistCFNet, enumerate_candidate_formulas, FormulaCandidate - from massspecgym.models.oracles.iceberg import predict_spectrum - - check("OracleBase importable", True) - check("predict_formulas importable", callable(predict_formulas)) - check("predict_spectrum importable", callable(predict_spectrum)) - check("MistCFNet importable", MistCFNet is not None) - check("FormulaCandidate importable", FormulaCandidate is not None) - - candidates = enumerate_candidate_formulas(180.0634, "[M+H]+", ppm_tol=10.0) - check("enumerate_candidates non-empty", len(candidates) > 0, str(len(candidates))) - has_glucose = any("C6" in c and "H12" in c and "O6" in c for c in candidates) - check("enumerate finds C6H12O6-like", has_glucose or len(candidates) > 0) - - results = predict_formulas( - spectrum_mzs=[91.05, 125.02, 155.06, 246.11], - spectrum_intensities=[0.25, 1.0, 0.36, 0.73], - precursor_mz=288.12, - adduct="[M+H]+", - top_k=5, - ) - check("predict_formulas returns results", len(results) > 0, str(len(results))) - if results: - check("results are FormulaCandidate", isinstance(results[0], FormulaCandidate)) - check("results have score", results[0].score != 0) - - -def test_iceberg_models(): - print("\n=== Phase 7b: ICEBERG model imports ===") - from massspecgym.models.simulation.iceberg.gen_model import FragGNN - from massspecgym.models.simulation.iceberg.inten_model import IntenGNN - from massspecgym.models.simulation.iceberg.joint_model import JointModel - from massspecgym.models.simulation.iceberg.dag_data import TreeProcessor, FRAGMENT_ENGINE_PARAMS - from massspecgym.models.simulation.iceberg.adapter import IcebergSimulationMassSpecGymModel - - check("FragGNN importable", FragGNN is not None) - check("IntenGNN importable", IntenGNN is not None) - check("JointModel importable", JointModel is not None) - check("TreeProcessor importable", TreeProcessor is not None) - check("FRAGMENT_ENGINE_PARAMS", FRAGMENT_ENGINE_PARAMS == {"max_broken_bonds": 6, "max_tree_depth": 3}) - - tp = TreeProcessor(pe_embed_k=0, root_encode="gnn") - nf = tp.get_node_feats() - check("TreeProcessor node_feats > 0", nf > 0, str(nf)) - - gen = FragGNN(hidden_size=64) - check("FragGNN instantiates", gen is not None) - - inten = IntenGNN(hidden_size=64) - check("IntenGNN instantiates", inten is not None) - - jm = JointModel(gen, inten) - check("JointModel instantiates", jm is not None) - - result = jm.predict_mol("CCO", collision_eng=40.0, adduct="[M+H]+") - check("JointModel predict_mol returns", "spec" in result) - check("JointModel predict_mol has peaks", len(result["spec"]) > 0, str(len(result["spec"]))) - - from massspecgym.models.oracles.mist_cf.model import MistCFNet - net = MistCFNet(hidden_size=64, layers=1) - check("MistCFNet instantiates", net is not None) - - import torch - num_peaks = torch.tensor([3, 2]) - peak_types = torch.tensor([[0, 1, 3, 0], [0, 3, 0, 0]]) - form_vec = torch.randn(2, 4, 18) - ion_vec = torch.zeros(2, 4, 7) - instrument_vec = torch.zeros(2, 4, 6) - intens = torch.tensor([[0.5, 0.3, 0.2, 0.0], [0.7, 0.3, 0.0, 0.0]]) - rel_mass_diffs = torch.zeros(2, 4) - scores = net(num_peaks, peak_types, form_vec, ion_vec, instrument_vec, intens, rel_mass_diffs) - check("MistCFNet forward shape", scores.shape == (2, 1), str(scores.shape)) - - -def test_mist_data_mixin(): - print("\n=== Phase 8: MISTDataMixin ===") - from massspecgym.data.mist_data_mixin import MISTDataMixin - check("MISTDataMixin importable", True) - - class TestModel(MISTDataMixin): - pass - - m = TestModel() - check("ensure_mist_data is callable", hasattr(m, "ensure_mist_data")) - check("get_subformulae_dir is callable", hasattr(m, "get_subformulae_dir")) - - -if __name__ == "__main__": - print("=" * 60) - print("MassSpecGym v1.5 Data/Oracles Validation Suite") - print("=" * 60) - - tests = [ - test_chem_constants_subformulae, - test_subformulae_engine, - test_subformulae_vs_reference, - test_sanity_check, - test_magma_fragmentation, - test_fp2mol_dataset_parquet, - test_oracle_interfaces, - test_iceberg_models, - test_mist_data_mixin, - ] - - for test_fn in tests: - try: - test_fn() - except Exception as e: - FAIL += 1 - print(f"\n [ERROR] {test_fn.__name__} crashed: {e}") - traceback.print_exc() - - print("\n" + "=" * 60) - print(f"Results: {PASS} passed, {FAIL} failed out of {PASS + FAIL} checks") - print("=" * 60) - sys.exit(1 if FAIL > 0 else 0) From 356801d499dc6ca1c0d596a488e2563ad294b0dc Mon Sep 17 00:00:00 2001 From: Magdalena Lederbauer <98785759+mlederbauer@users.noreply.github.com> Date: Sun, 10 May 2026 20:18:06 -0400 Subject: [PATCH 3/5] Feat/llm skills lv2 (#19) * adding MIST and SpecBridge Evals * Add DreaMS-MSG support. * feat: skill to build model with MSG ABCs * feat: skill for review for common issues * chore: cosmetic changes * chore: remove implementation script since we focus on review * chore: update review "skill" to be used as maintainer guide * feat: add submissions guide and model template card * feat: add submission review script * feat: update leaderboard GH action (to be triggered after manual approval) * feat: add "submissions" label to test workflow * chore: add pyarrow dependency * chore: move pyarrow to setup deps * tmp: add feature branch to github action sorkflow * Merge pull request #4 from mlederbauer/submission/diffms feat: level 1 model card impl * feat: add mist molforge submission * tmp chore: adaptations to review scripts * tmp feat: test out with diffms (v0 model card) * chore: update model card * fix: suibmission dir * cho9re: remove pubication field * chore: remove superfluous comments * chore: add .claude to gitignore * chore: update scripts in llm skills * feat: diffms implementation * feat: add mist molforge submission * tmp fix: remove model card for llm skills * chore: remocve mist molforge * choe: only model card for ttt-msms * Revert "choe: only model card for ttt-msms" This reverts commit dae836aa447734b9967d647b9774d6c7a1c86a63. * feat v: llm review w local repo * feat: update system pormpt to use unified SKILL.md * chore: remove emojis from review * feat: update results metrics in model card instead of csv * chore: remove reference section * chore: refine warning gravity and red/yellow labeling for revbiew * fix: detect mist bug * Delete checkpoints/README.md * chore: remove superfluous code for LLM review submission * chore: remover superfluous code for llm skills submission * chore: remove superfluous code * chore: move leaderboard update scripts * chore: keep llm skills as CI branch for testing * chore: update workflow to edit csvs during PR * chore: cosmetic changes * feat: create model cards for baselines * fix: update trigger to also include feature branch * chore: create PR for leaderboard update --------- Co-authored-by: harrylaucngd --- .github/workflows/prepare_submission.yml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/prepare_submission.yml b/.github/workflows/prepare_submission.yml index dc2e99c..03b1720 100644 --- a/.github/workflows/prepare_submission.yml +++ b/.github/workflows/prepare_submission.yml @@ -88,20 +88,31 @@ jobs: git push origin "$BRANCH" --force echo "branch=$BRANCH" >> $GITHUB_OUTPUT - - name: Comment on original PR + - name: Create clean PR and comment on original uses: actions/github-script@v7 with: script: | const branch = '${{ steps.push.outputs.branch }}'; const origPR = context.payload.pull_request.number; + const origTitle = context.payload.pull_request.title; + + const cleanPR = await github.rest.pulls.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: `[prepared] ${origTitle}`, + head: branch, + base: context.payload.pull_request.base.ref, + body: `Automated clean branch from #${origPR}. Source code stripped, CSVs regenerated.`, + }); + const body = [ '## Submission prepared for merge', '', - `A clean branch \`${branch}\` has been created in the base repository with:`, + `A clean branch \`${branch}\` has been created with:`, '- Source code removed (only `model_card.yaml` retained)', '- `results/*.csv` regenerated from all model cards', '', - `**Maintainer:** merge \`${branch}\` into \`main\` โ€” do not merge this PR directly.`, + `**Maintainer:** review and merge the prepared PR: ${cleanPR.data.html_url}`, ].join('\n'); await github.rest.issues.createComment({ From 22b99867f172488b3f491903b1c434ce01c611e2 Mon Sep 17 00:00:00 2001 From: Magdalena Lederbauer <98785759+mlederbauer@users.noreply.github.com> Date: Sun, 10 May 2026 20:22:30 -0400 Subject: [PATCH 4/5] Update prepare_submission.yml --- .github/workflows/prepare_submission.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prepare_submission.yml b/.github/workflows/prepare_submission.yml index 03b1720..a0d4ec8 100644 --- a/.github/workflows/prepare_submission.yml +++ b/.github/workflows/prepare_submission.yml @@ -6,7 +6,7 @@ name: Prepare Submission for Merge on: pull_request_target: types: [labeled] - branches: [main, feat/llm-skills-lv2] + branches: [main] paths: - "submissions/**" From ba21f4d2c1111e85538d82a374b46b1ee22e62e9 Mon Sep 17 00:00:00 2001 From: Magdalena Lederbauer <98785759+mlederbauer@users.noreply.github.com> Date: Sun, 10 May 2026 20:22:41 -0400 Subject: [PATCH 5/5] Update branches for review submission workflow Restrict review submission workflow to main branch only. --- .github/workflows/review_submission.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/review_submission.yml b/.github/workflows/review_submission.yml index f3f720e..65ee83d 100644 --- a/.github/workflows/review_submission.yml +++ b/.github/workflows/review_submission.yml @@ -2,7 +2,7 @@ name: Review Submission on: pull_request: - branches: [main, feat/llm-skills-lv2] + branches: [main] types: [opened, synchronize, reopened, labeled] paths: - "submissions/**"