text:
gwas = Dict(
    # Psychiatric
    "asd" => (url = "https://figshare.com/ndownloader/files/28169292",
        pmid = "30804558",
        title = "Autism (Grove et al. 2019)",
        file = "iPSYCH-PGC_ASD_Nov2017.gz"),
    "scz" => (url = "https://figshare.com/ndownloader/files/28169757",
        pmid = "35396580",
        title = "Schizophrenia (PGC3)",
        file = "PGC3_SCZ_wave3_public.v2.tsv.gz"),
    "bd" => (url = "https://figshare.com/ndownloader/files/26603681",
        pmid = "34002096",
        title = "Bipolar (Mullins et al. 2021)",
        file = "pgc-bip2021-all.vcf.tsv.gz"),
    "sczvsbd" => (url = "https://figshare.com/ndownloader/files/28169358",
        pmid = "29906448",
        title = "SCZ vs BD (Ruderfer et al. 2018)",
        file = "SCZvsBD.sumstats.gz"),
    "adhd" => (url = "https://figshare.com/ndownloader/files/28169253",
        pmid = "30478444",
        title = "ADHD (Demontis et al. 2019)",
        file = "daner_adhd_meta_filtered_NA_iPSYCH23_PGC11_sigPCs_woSEX_2ell6sd_EUR_Neff_70.meta.gz"),
    "anorexia" => (url = "https://figshare.com/ndownloader/files/28169271",
        pmid = "31308545",
        title = "Anorexia (Watson et al. 2019)",
        file = "pgcAN2.2019-07.vcf.tsv.gz"),
    "cross" => (url = "https://figshare.com/ndownloader/files/28169382",
        pmid = "31835028",
        title = "Cross disorder (PGC 2019)",
        file = "pgc_cdg2_meta_no23andMe_oct2019_v2.txt.daner.txt.gz"),
    "mdd" => (url = "https://datashare.ed.ac.uk/bitstream/handle/10283/3203/PGC_UKB_depression_genome-wide.txt",
        pmid = "30718901",
        title = "Major depression (Howard et al. 2019)",
        file = "PGC_UKB_depression_genome-wide.txt"),
    # Neurologic
    "alz" => (url = "https://ctg.cncr.nl/documents/p1651/AD_sumstats_Jansenetal_2019sept.txt.gz",
        pmid = "30617256",
        title = "Alzheimer disease (Jansen et al. 2019)",
        file = "AD_sumstats_Jansenetal_2019sept.txt.gz"),
    "als" => (url = "https://surfdrive.surf.nl/files/index.php/s/E5RetKw10hC3jXy/download?path=%2F&files=ALS_GWAS_RVB_SMR_sumstats.tar.gz",
        pmid = "34873335",
        title = "ALS (van Rheenen et al. 2021)",
        file = "ALS_sumstats_EUR_only.txt.gz"),
    "parkinson" => (url = "https://drive.google.com/file/d/1FZ9UL99LAqyWnyNBxxlx6qOUlfAnublN",
        pmid = "31701892",
        title = "Parkinson's disease (Nalls et al. 2019)",
        file = "nallsEtAl2019_excluding23andMe_allVariants.tab"),
    "stroke" => (url = "https://www.kp4cd.org/datasets/stroke",
        pmid = "29531354",
        title = "Stroke (Malik et al. 2018)",
        file = "metastroke.all.chr.bp"),
    # Neurocognitive
    "left-hand" => (url = "https://evansgroup.di.uq.edu.au/GWAS_RESULTS/HANDEDNESS/LeftHandedness_MetaAnalysis_UKBB_IHC.txt.gz",
        pmid = "32989287",
        title = "Left-handedness (Cuellar-Partida et al. 2020)",
        file = "LeftHandedness_MetaAnalysis_UKBB_IHC.txt.gz"),
    "cp" => (url = "https://thessgac.com/papers/",
        pmid = "30038396",
        title = "Cognitive performance (Lee et al. 2018)",
        file = "GWAS_CP_all.txt"),
    "ea" => (url = "https://thessgac.com/papers/",
        pmid = "35361970",
        title = "Educational attainment (Okbay et al. 2022)",
        file = "EA4_additive_excl_23andMe.txt.gz"),
    "birth" => (url = "https://thessgac.com/papers/",
        pmid = "27798627",
        title = "Age at first birth (Barban et al. 2016)",
        file = "AgeFirstBirth_Pooled.txt"),
    "children" => (url = "https://thessgac.com/papers/",
        pmid = "27798627",
        title = "Number of children (Barban et al. 2016)",
        file = "NumberChildrenEverBorn_Pooled.txt"),
    "risk" => (url = "https://thessgac.com/papers/",
        pmid = "30643258",
        title = "Risk tolerance (Linner et al. 2019)",
        file = "RISK_GWAS_MA_UKB+replication.txt"),
    "neuroticism" => (url = "https://ctg.cncr.nl/documents/p1651/sumstats_neuroticism_ctg_format.txt.gz",
        pmid = "29942085",
        title = "Neuroticism (Nagel et al. 2018)",
        file = "sumstats_neuroticism_ctg_format.txt.gz"),
    "smoking" => (url = "https://conservancy.umn.edu/bitstream/handle/11299/201564/CigarettesPerDay.txt.gz",
        pmid = "30643251",
        title = "Cigarettes per day (Liu et al. 2019)",
        file = "CigarettesPerDay.txt.gz"),
    "alcohol" => (url = "https://conservancy.umn.edu/bitstream/handle/11299/201564/DrinksPerWeek.txt.gz",
        pmid = "30643251",
        title = "Drinks per week (Liu et al. 2019)",
        file = "DrinksPerWeek.txt.gz"),
    "intelligence" => (url = "https://ctg.cncr.nl/documents/p1651/SavageJansen_IntMeta_sumstats.zip",
        pmid = "29942086",
        title = "Intelligence (Savage et al. 2018)",
        file = "SavageJansen_2018_intelligence_metaanalysis.txt"),
    "insomnia" => (url = "https://ctg.cncr.nl/documents/p1651/Insomnia_sumstats_Jansenetal.txt.gz",
        pmid = "30804565",
        title = "Insomnia (Jansen et al. 2019)",
        file = "Insomnia_sumstats_Jansenetal.txt.gz"),
    "icv" => (url = "https://ctg.cncr.nl/documents/p1651/meta_analysis_BV_Jansenetal_2020.sumstats.txt.gz",
        pmid = "33154357",
        title = "Intracranial volume (Jansen et al. 2020)",
        file = "meta_analysis_BV_Jansenetal_2020.sumstats.txt.gz"),
    # Ophtho
    "amd" => (url = "http://csg.sph.umich.edu/abecasis/public/amd2015/Fritsche_2015_AdvancedAMD.txt.gz",
        pmid = "26691988",
        title = "AMD (Fritsche et al. 2016)",
        file = "Fritsche_2015_AdvancedAMD.txt.gz"),
    "cataract" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST90014001-GCST90015000/GCST90014268/GCST90014268_buildGRCh37.tsv",
        pmid = "34127677",
        title = "Cataract (Choquet et al. 2021)",
        file = "GCST90014268_buildGRCh37.tsv"),
    "glaucoma" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST009001-GCST010000/GCST009722/MTAG_glaucoma_four_traits_summary_statistics.txt",
        pmid = "31959993",
        title = "Galucoma (Craig et al. 2020)",
        file = "MTAG_glaucoma_four_traits_summary_statistics.txt"),
    # Gyn
    "menarche" => (url = "https://www.reprogen.org/Menarche_1KG_NatGen2017_WebsiteUpload.zip",
        pmid = "28436984",
        title = "Age at menarche (Day et al. 2017)",
        file = "Menarche_1KG_NatGen2017_WebsiteUpload.txt"),
    "menopause" => (url = "https://www.reprogen.org/reprogen_ANM_201K_170621.txt.gz",
        pmid = "34349265",
        title = "Age at menoapuse (Ruth et al. 2021)",
        file = "reprogen_ANM_201K_170621.txt.gz"),
    "pcos" => (url = "https://www.repository.cam.ac.uk/bitstream/handle/1810/283491/PCOS_summary_data_19092018.tar.gz",
        pmid = "30566500",
        title = "PCOS (Day et al. 2018)",
        file = "PCOS_summary_data_19092018.txt"),
    # Autoimmune
    "lupus" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST003001-GCST004000/GCST003156/bentham_2015_26502338_sle_efo0002690_1_gwas.sumstats.tsv.gz",
        pmid = "26502338",
        title = "Lupus (Bentham et al. 2015)",
        file = "bentham_2015_26502338_sle_efo0002690_1_gwas.sumstats.tsv.gz"),
    "ra" => (url = "http://plaza.umin.ac.jp/~yokada/datasource/files/GWASMetaResults/RA_GWASmeta_European_v2.txt.gz",
        pmid = "24390342",
        title = "Rheumatoid arthritis (Okada et al. 2014)",
        file = "RA_GWASmeta_European_v2.txt.gz"),
    "t1d" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST90000001-GCST90001000/GCST90000529/harmonised/33830302-GCST90000529-EFO_0001359-Build37.f.tsv.gz",
        pmid = "33830302",
        title = "Type I diabetes (Inshaw et al. 2021)",
        file = "33830302-GCST90000529-EFO_0001359-Build37.f.tsv.gz"),
    "celiac" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST005001-GCST006000/GCST005523/harmonised/22057235-GCST005523-EFO_0001060-Build37.f.tsv.gz",
        pmid = "22057235",
        title = "Celiac disease (Trynka et al. 2011)",
        file = "22057235-GCST005523-EFO_0001060-Build37.f.tsv.gz"),
    "uc" => (url = "ftp://ftp.sanger.ac.uk/pub/project/humgen/summary_statistics/human/2016-11-07/",
        pmid = "28067908",
        title = "Ulcerative colitis (de Lange et al. 2017)",
        file = "uc_build37_45975_20161107.txt.gz"),
    "crohns" => (url = "ftp://ftp.sanger.ac.uk/pub/project/humgen/summary_statistics/human/2016-11-07/",
        pmid = "28067908",
        title = "Crohn's disease (de Lange et al. 2017)",
        file = "cd_build37_40266_20161107.txt.gz"),
    "ibd" => (url = "ftp://ftp.sanger.ac.uk/pub/project/humgen/summary_statistics/human/2016-11-07/",
        pmid = "28067908",
        title = "IBD (de Lange et al. 2017)",
        file = "ibd_build37_59957_20161107.txt.gz"),
    "as" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST005001-GCST006000/GCST005529/harmonised/23749187-GCST005529-EFO_0003898-Build37.f.tsv.gz",
        pmid = "23749187",
        title = "Ankylosing spondylitis (Cortes et al. 2013)",
        file = "23749187-GCST005529-EFO_0003898-Build37.f.tsv.gz"),
    "pbc" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST003001-GCST004000/GCST003129/harmonised/26394269-GCST003129-EFO_1001486-Build37.f.tsv.gz",
        pmid = "26394269",
        title = "Primary biliary cirrhosis (Cordell et al. 2015)",
        file = "26394269-GCST003129-EFO_1001486-Build37.f.tsv.gz"),
    # Respiratory
    "asthma" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST010001-GCST011000/GCST010042/HanY_prePMID_asthma_UKBB.txt.gz",
        pmid = "32296059",
        title = "Asthma (Han et al. 2020)",
        file = "HanY_prePMID_asthma_UKBB.txt.gz"),
    # MSK
    "oa" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST005001-GCST006000/GCST005811/Zengini_29559693_SR.txt.gz",
        pmid = "29559693",
        title = "Osteoarthritis (Zengini et al. 2018)",
        file = "Zengini_29559693_SR.txt.gz"),
    # Digestive
    "gerd" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST90000001-GCST90001000/GCST90000514/GCST90000514_buildGRCh37.tsv.gz",
        pmid = "34187846",
        title = "GERD (Ong et al. 2022)",
        file = "GCST90000514_buildGRCh37.tsv.gz"),
    "barrett" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST90000001-GCST90001000/GCST90000515/GCST90000515_buildGRCh37.tsv.gz",
        pmid = "34187846",
        title = "Barrett's esophagus (Ong et al. 2022)",
        file = "GCST90000515_buildGRCh37.tsv.gz"),
    # Anthropometric
    "height" => (url = "https://portals.broadinstitute.org/collaboration/giant/images/6/63/Meta-analysis_Wood_et_al%2BUKBiobank_2018.txt.gz",
        pmid = "30124842",
        title = "Height (Yengo et al. 2018)",
        file = "Meta-analysis_Wood_et_al%2BUKBiobank_2018.txt.gz"),
    "weight" => (url = "https://portals.broadinstitute.org/collaboration/giant/images/c/c8/Meta-analysis_Locke_et_al%2BUKBiobank_2018_UPDATED.txt.gz",
        pmid = "30124842",
        title = "Weight (Yengo et al. 2018)",
        file = "Meta-analysis_Locke_et_al%2BUKBiobank_2018_UPDATED.txt.gz"),
    # Hormone
    "tsh" => (url = "http://csg.sph.umich.edu/willer/public/TSH2020/2020_Zhou_et_al_TSH_meta_HUNT-MGI-ThyroidOmics.txt",
        pmid = "32769997",
        title = "TSH level (Zhou et al. 2020)",
        file = "2020_Zhou_et_al_TSH_meta_HUNT-MGI-ThyroidOmics.txt"),
    # Cardiovascular
    "cad" => (url = "http://www.cardiogramplusc4d.org/data-downloads/",
        pmid = "26343387",
        title = "CAD (Nikpay et al. 2015)",
        file = "cad.add.160614.website.txt"),
    "afib" => (url = "https://personal.broadinstitute.org/ryank/AF_HRC_GWAS_ALLv11.zip",
        pmid = "29892015",
        title = "Atrial fibrillation (Roselli et al. 2018)",
        file = "AF_HRC_GWAS_ALLv11.txt"),
    "dbp" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST006001-GCST007000/GCST006630/Evangelou_30224653_DBP.txt.gz",
        pmid = "30224653",
        title = "DBP (Evangelou et al. 2018)",
        file = "Evangelou_30224653_DBP.txt.gz"),
    "sbp" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST006001-GCST007000/GCST006624/Evangelou_30224653_SBP.txt.gz",
        pmid = "30224653",
        title = "SBP (Evangelou et al. 2018)",
        file = "Evangelou_30224653_SBP.txt.gz"),
    # Kidney
    "ckd" => (url = "http://ckdgen.imbi.uni-freiburg.de/files/Wuttke2019/CKD_overall_EA_JW_20180223_nstud23.dbgap.txt.gz",
        pmid = "31152163",
        title = "CKD (Wuttke et al. 2019)",
        file = "CKD_overall_EA_JW_20180223_nstud23.dbgap.txt.gz"),
    # Endocrine
    "t2d" => (url = "https://diagram-consortium.org/downloads.html",
        pmid = "30297969",
        title = "Type II diabetes (Mahajan et al. 2018)",
        file = "Mahajan.NatGenet2018b.T2D.European.txt"),
    # Respiratory
    "covid" => (url = "https://storage.googleapis.com/covid19-hg-public/20210415/results/20210607/COVID19_HGI_A2_ALL_leave_23andme_20210607.b37.txt.gz",
        pmid = "34237774",
        title = "COVID-19 (2021)",
        file = "COVID19_HGI_A2_ALL_leave_23andme_20210607.b37.txt.gz"),
    # Derm
    "acne" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST90091001-GCST90092000/GCST90092000/GCST90092000_buildGRCh37.tsv",
        pmid = "35132056",
        title = "Acne (Mitchell et al. 2022)",
        file = "GCST90092000_buildGRCh37.tsv.gz"),
    "bald" => (url = "http://www.psy.ed.ac.uk/ccace/downloads/Hagenaars2017_UKB_MPB_summary_results.zip",
        pmid = "28196072",
        title = "Male-pattern baldness (Hagenaars et al. 2017)",
        file = "Hagenaars2017_UKB_MPB_summary_results_10Feb2016.txt"),
    "ad" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST003001-GCST004000/GCST003184/EAGLE_AD_no23andme_results_29072015.txt",
        pmid = "26482879",
        title = "Atopic dermatitis (Paternoster et al. 2015)",
        file = "EAGLE_AD_no23andme_results_29072015.txt"),
    "vitiligo" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST004001-GCST005000/GCST004785/",
        pmid = "27723757",
        title = "Vitiligo (Jin et al. 2016)",
        file = "GWAS123.txt.gz"),
    "psoriasis" => (url = "https://gwas.mrcieu.ac.uk/files/ukb-b-10537/ukb-b-10537.vcf.gz",
        pmid = "",
        title = "Psoriasis (UK Biobank)",
        file = "ukb-b-10537.vcf.gz"),
    "bcc" => (url = "https://gwas.mrcieu.ac.uk/files/ukb-b-8837/ukb-b-8837.vcf.gz",
        pmid = "",
        title = "Basal cell carcinoma (UK Biobank)",
        file = "ukb-b-8837.vcf.gz"),
    "melanoma" => (url = "https://gwas.mrcieu.ac.uk/files/ukb-b-12915/ukb-b-12915.vcf.gz",
        pmid = "",
        title = "Melanoma (UK Biobank)",
        file = "ukb-b-12915.vcf.gz"),
    # Cancer
    "breast" => (url = "https://bcac.ccge.medschl.cam.ac.uk/bcacdata/oncoarray/oncoarray-and-combined-summary-result/gwas-summary-associations-breast-cancer-risk-2020/",
        pmid = "32424353",
        title = "Breast cancer (Zhang et al. 2020)",
        file = "icogs_onco_gwas_meta_overall_breast_cancer_summary_level_statistics.txt"),
    "prostate" => (url = "https://bcac.ccge.medschl.cam.ac.uk/bcacdata/oncoarray/oncoarray-and-combined-summary-result/gwas-summary-associations-breast-cancer-risk-2020/",
        pmid = "23065704",
        title = "Prostate cancer (Schumacher et al. 2018)",
        file = "meta_v3_onco_euro_overall_ChrAll_1_release.txt"),
    "ec" => (url = "http://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/GCST006001-GCST007000/GCST006464/GCST006464_GRCh37.tsv.gz",
        pmid = "30093612",
        title = "Endometrial cancer (O'Mara et al. 2018)",
        file = "GCST006464_GRCh37.tsv.gz"),
    # CBC
    "rbc" => (url = "http://www.mhi-humangenetics.org/dataset/BCX2_RBC_EA_GWAMA.out.gz",
        pmid = "32888493",
        title = "Red blood cell count (Chen et al. 2020)",
        file = "BCX2_RBC_EA_GWAMA.out.gz"),
    "hgb" => (url = "http://www.mhi-humangenetics.org/dataset/BCX2_HGB_EA_GWAMA.out.gz",
        pmid = "32888493",
        title = "Hemoglobin concentration (Chen et al. 2020)",
        file = "BCX2_HGB_EA_GWAMA.out.gz"),
    "hct" => (url = "http://www.mhi-humangenetics.org/dataset/BCX2_HCT_EA_GWAMA.out.gz",
        pmid = "32888493",
        title = "Hematocrit (Chen et al. 2020)",
        file = "BCX2_HCT_EA_GWAMA.out.gz"),
    "mch" => (url = "http://www.mhi-humangenetics.org/dataset/BCX2_MCH_EA_GWAMA.out.gz",
        pmid = "32888493",
        title = "Mean corpuscular hemoglobin (Chen et al. 2020)",
        file = "BCX2_MCH_EA_GWAMA.out.gz"),
    "mcv" => (url = "http://www.mhi-humangenetics.org/dataset/BCX2_MCV_EA_GWAMA.out.gz",
        pmid = "32888493",
        title = "Mean corpuscular volume (Chen et al. 2020)",
        file = "BCX2_MCV_EA_GWAMA.out.gz"),
    "mchc" => (url = "http://www.mhi-humangenetics.org/dataset/BCX2_MCHC_EA_GWAMA.out.gz",
        pmid = "32888493",
        title = "Mean corpuscular hemoglobin concentration (Chen et al. 2020)",
        file = "BCX2_MCHC_EA_GWAMA.out.gz"),
    "rdw" => (url = "http://www.mhi-humangenetics.org/dataset/BCX2_RDW_EA_GWAMA.out.gz",
        pmid = "32888493",
        title = "RBC distribution width (Chen et al. 2020)",
        file = "BCX2_RDW_EA_GWAMA.out.gz"),
    "wbc" => (url = "http://www.mhi-humangenetics.org/dataset/BCX2_WBC_EA_GWAMA.out.gz",
        pmid = "32888493",
        title = "White blood cell count (Chen et al. 2020)",
        file = "BCX2_WBC_EA_GWAMA.out.gz"),
    "neu" => (url = "http://www.mhi-humangenetics.org/dataset/BCX2_NEU_EA_GWAMA.out.gz",
        pmid = "32888493",
        title = "Neutrophil count (Chen et al. 2020)",
        file = "BCX2_NEU_EA_GWAMA.out.gz"),
    "lymph" => (url = "http://www.mhi-humangenetics.org/dataset/BCX2_LYM_EA_GWAMA.out.gz",
        pmid = "32888493",
        title = "Lymphocyte count (Chen et al. 2020)",
        file = "BCX2_LYM_EA_GWAMA.out.gz"),
    "mono" => (url = "http://www.mhi-humangenetics.org/dataset/BCX2_MON_EA_GWAMA.out.gz",
        pmid = "32888493",
        title = "Monocyte count (Chen et al. 2020)",
        file = "BCX2_MON_EA_GWAMA.out.gz"),
    "baso" => (url = "http://www.mhi-humangenetics.org/dataset/BCX2_BAS_EA_GWAMA.out.gz",
        pmid = "32888493",
        title = "Basophil count (Chen et al. 2020)",
        file = "BCX2_BAS_EA_GWAMA.out.gz"),
    "eos" => (url = "http://www.mhi-humangenetics.org/dataset/BCX2_EOS_EA_GWAMA.out.gz",
        pmid = "32888493",
        title = "Eosinophil count (Chen et al. 2020)",
        file = "BCX2_EOS_EA_GWAMA.out.gz"),
    "plt" => (url = "http://www.mhi-humangenetics.org/dataset/BCX2_PLT_EA_GWAMA.out.gz",
        pmid = "32888493",
        title = "Platelet count (Chen et al. 2020)",
        file = "BCX2_PLT_EA_GWAMA.out.gz"),
    "mpv" => (url = "http://www.mhi-humangenetics.org/dataset/BCX2_MPV_EA_GWAMA.out.gz",
        pmid = "32888493",
        title = "Mean platelet volume (Chen et al. 2020)",
        file = "BCX2_MPV_EA_GWAMA.out.gz"),
    # Serum/urine biomarker
    "alt" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "ALT (Sinnott-Armstrong et al. 2021)",
        file = "Alanine_aminotransferase.imp.gz"),
    "ast" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "AST (Sinnott-Armstrong et al. 2021)",
        file = "Aspartate_aminotransferase.imp.gz"),
    "astalt" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "AST / ALT (Sinnott-Armstrong et al. 2021)",
        file = "AST_ALT_ratio.imp.gz"),
    "ap" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Alkaline phosphatase (Sinnott-Armstrong et al. 2021)",
        file = "Alkaline_phosphatase.imp.gz"),
    "apoa" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "APOA (Sinnott-Armstrong et al. 2021)",
        file = "Apolipoprotein_A.imp.gz"),
    "apob" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "APOB (Sinnott-Armstrong et al. 2021)",
        file = "Apolipoprotein_B_adjstatins.imp.gz"),
    "crp" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "CRP (Sinnott-Armstrong et al. 2021)",
        file = "C_reactive_protein.imp.gz"),
    "calcium" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Ca²⁺ (Sinnott-Armstrong et al. 2021)",
        file = "Calcium.imp.gz"),
    "cholesterol" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Cholesterol (Sinnott-Armstrong et al. 2021)",
        file = "Cholesterol_adjstatins.imp.gz"),
    "creatinine" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Creatinine (Sinnott-Armstrong et al. 2021)",
        file = "Creatinine.imp.gz"),
    "ucreatinine" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Urine creatinine (Sinnott-Armstrong et al. 2021)",
        file = "Creatinine_in_urine.imp.gz"),
    "cystatinc" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Cystatin C (Sinnott-Armstrong et al. 2021)",
        file = "Cystatin_C.imp.gz"),
    "albumin" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Albumin (Sinnott-Armstrong et al. 2021)",
        file = "Albumin.imp.gz"),
    "dirbilirubin" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Direct bilirubin (Sinnott-Armstrong et al. 2021)",
        file = "Direct_bilirubin.imp.gz"),
    "egfr" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "eGFR (Sinnott-Armstrong et al. 2021)",
        file = "eGFR.imp.gz"),
    "ggt" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "GGT (Sinnott-Armstrong et al. 2021)",
        file = "Gamma_glutamyltransferase.imp.gz"),
    "glucose" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Glucose (Sinnott-Armstrong et al. 2021)",
        file = "Glucose.imp.gz"),
    "hba1c" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "HbA1c (Sinnott-Armstrong et al. 2021)",
        file = "Glycated_haemoglobin_HbA1c.imp.gz"),
    "hdl" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "HDL cholesterol (Sinnott-Armstrong et al. 2021)",
        file = "HDL_cholesterol.imp.gz"),
    "igf1" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "IGF-1 (Sinnott-Armstrong et al. 2021)",
        file = "IGF_1.imp.gz"),
    "ldl" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "LDL cholesterol (Sinnott-Armstrong et al. 2021)",
        file = "LDL_direct_adjstatins.imp.gz"),
    "lpa" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "LPA (Sinnott-Armstrong et al. 2021)",
        file = "Lipoprotein_A.imp.gz"),
    "ualbumin" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Urine microalbumin (Sinnott-Armstrong et al. 2021)",
        file = "Microalbumin_in_urine.imp.gz"),
    "nap" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Non-albumin protein (Sinnott-Armstrong et al. 2021)",
        file = "Non_albumin_protein.imp.gz"),
    "phosphate" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Phosphate (Sinnott-Armstrong et al. 2021)",
        file = "Phosphate.imp.gz"),
    "upotassium" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Urine K⁺ (Sinnott-Armstrong et al. 2021)",
        file = "Potassium_in_urine.imp.gz"),
    "shbg" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "SHBG (Sinnott-Armstrong et al. 2021)",
        file = "SHBG.imp.gz"),
    "usodium" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Urine Na⁺ (Sinnott-Armstrong et al. 2021)",
        file = "Sodium_in_urine.imp.gz"),
    "testosterone" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Testosterone (Sinnott-Armstrong et al. 2021)",
        file = "Testosterone.imp.gz"),
    "totbilirubin" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Total bilirubin (Sinnott-Armstrong et al. 2021)",
        file = "Total_bilirubin.imp.gz"),
    "totprotein" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Total protein (Sinnott-Armstrong et al. 2021)",
        file = "Total_protein.imp.gz"),
    "triglyceride" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Triglyceride (Sinnott-Armstrong et al. 2021)",
        file = "Triglycerides.imp.gz"),
    "urate" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Urate (Sinnott-Armstrong et al. 2021)",
        file = "Urate.imp.gz"),
    "bun" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "BUN (Sinnott-Armstrong et al. 2021)",
        file = "Urea.imp.gz"),
    "vitamind" => (url = "https://github.com/rivas-lab/biomarkers/tree/master/meta_flipfix/figshare_submission",
        pmid = "33462484",
        title = "Vitamin D (Sinnott-Armstrong et al. 2021)",
        file = "Vitamin_D.imp.gz")
    )


text:
@doc raw"""
# Lotka-Volterra model in 2D with symmetric Lagrangian

```math
\begin{aligned}
L (q, \dot{q}) &= \frac{1}{2} \frac{\log q_2}{q_1} \, \dot{q_1} - \frac{1}{2} \frac{\log q_1}{q_2} \, \dot{q_2} - H(q) , \\
H(q) &= a_1 \, q_1 + a_2 \, q_2 + b_1 \, \log q_1 + b_2 \, \log q_2
\end{aligned}
```

This Lagrangian is a slight generalization of Equation (5) in José Fernández-Núñez,
Lagrangian Structure of the Two-Dimensional Lotka-Volterra System, International
Journal of Theoretical Physics, Vol. 37, No. 9, pp. 2457-2462, 1998.

"""
module LotkaVolterra2dSymmetric

    ϑ₁(t, q) = + log(q[2]) / q[1] / 2
    ϑ₂(t, q) = - log(q[1]) / q[2] / 2

    dϑ₁dx₁(t, q) = - log(q[2]) / q[1]^2 / 2
    dϑ₁dx₂(t, q) = + 1 / (q[1] * q[2]) / 2

    dϑ₂dx₁(t, q) = - 1 / (q[2] * q[1]) / 2
    dϑ₂dx₂(t, q) = + log(q[1]) / q[2]^2 / 2

    include("lotka_volterra_2d_common.jl")
    include("lotka_volterra_2d_equations.jl")

end

ext: jl


text:
"""
# Differencing
```julia
diff(ts::TS, periods::Int = 1)
```

Return the discrete difference of successive row elements.
Default is the element in the next row. `periods` defines the number
of rows to be shifted over. The skipped rows are rendered as `missing`.

`diff` returns an error if column type does not have the method `-`.

# Examples
```jldoctest; setup = :(using TSx, DataFrames, Dates, Random, Statistics)
julia> using Random, Statistics;

julia> random(x) = rand(MersenneTwister(123), x);

julia> dates = collect(Date(2017,1,1):Day(1):Date(2018,3,10));

julia> ts = TS(random(length(dates)), dates);
julia> ts[1:10]
(10 x 1) TS with Date Index

 Index       x1
 Date        Float64
───────────────────────
 2017-01-01  0.768448
 2017-01-02  0.940515
 2017-01-03  0.673959
 2017-01-04  0.395453
 2017-01-05  0.313244
 2017-01-06  0.662555
 2017-01-07  0.586022
 2017-01-08  0.0521332
 2017-01-09  0.26864
 2017-01-10  0.108871

julia> diff(ts)[1:10]        # difference over successive rows
(10 x 1) TS with Date Index

 Index       x1
 Date        Float64?
─────────────────────────────
 2017-01-01  missing
 2017-01-02        0.172067
 2017-01-03       -0.266556
 2017-01-04       -0.278506
 2017-01-05       -0.0822092
 2017-01-06        0.349311
 2017-01-07       -0.0765327
 2017-01-08       -0.533889
 2017-01-09        0.216506
 2017-01-10       -0.159769

julia> diff(ts, 3)[1:10]     # difference over the third row
(10 x 1) TS with Date Index

 Index       x1
 Date        Float64?
─────────────────────────────
 2017-01-01  missing
 2017-01-02  missing
 2017-01-03  missing
 2017-01-04       -0.372995
 2017-01-05       -0.627271
 2017-01-06       -0.0114039
 2017-01-07        0.190569
 2017-01-08       -0.261111
 2017-01-09       -0.393915
 2017-01-10       -0.477151

```
"""

# Diff
function diff(ts::TS, periods::Int = 1)
    if periods <= 0
        error("periods must be a postive int")
    end
    ddf = ts.coredata[:, Not(:Index)] .- TSx.lag(ts, periods).coredata[:, Not(:Index)]
    insertcols!(ddf, 1, "Index" => ts.coredata[:, :Index])
    TS(ddf, :Index)
end


text:
## Code for removing warnings

export scrub_stderr, scrub_redefinition_warnings, no_warnings, sinclude

# O nameless stranger, please improve my ailing regexes.
redefinition_regexes =
    [r"WARNING: Method definition .* in module .* at .* overwritten at .*\n",
     r"WARNING: Method definition .* in module .* overwritten.\n",
     r"WARNING: replacing docs for .*\n",
     # 0.6 updated its doc warnings with color. Looks like this:
     # \e[1m\e[33mWARNING: \e[39m\e[22m\e[33mreplacing
     r".*WARNING: .*replacing docs for .*\n",
     r"WARNING: redefining constant .*\n"]

""" `scrub_stderr(body::Function, pats::Regex...)` executes `body` without
outputting any warning that matches one of the `pats`.

Pattern example: r"WARNING: redefining constant .*\n" """
function scrub_stderr(body::Function, pats::Regex...)
    mktemp() do _, f
        old_stderr = STDERR
        redirect_stderr(f)
        try
            res = body()
            flush(f)
            seekstart(f)
            text = readstring(f)
            for pat in pats
                text = replace(text, pat, "")
            end
            write(old_stderr, text)
            res
        finally
            redirect_stderr(old_stderr)
        end
    end
end

""" `scrub_redefinition_warnings(body::Function)` executes `body` without
outputting any redefinition warnings """
function scrub_redefinition_warnings(body::Function)
    scrub_stderr(redefinition_regexes...) do
        body()
    end
end

""" `no_warnings(body::Function)` executes `body` without outputting any
warnings (no STDERR output) """
function no_warnings(body::Function)
    scrub_stderr(r".*\n") do
        body()
    end
end

""" `sinclude(filename)` calls `include(filename)`, but doesn't show any
redefinition warnings (it's a _silent_ `include`) """
function sinclude(filename)
    scrub_redefinition_warnings() do
        include(filename)
    end
end


text:
# MIT License

# Copyright (c) Microsoft Corporation.

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE

"""
    RigidBodyTransform{S<:Real}

Transform encapsulating rotation and translation in 3D space. Translation happens **after** rotation.

```julia
RigidBodyTransform{S}(θ::T, ϕ::T, ψ::T, x::T, y::T, z::T)
RigidBodyTransform(rotation::SMatrix{3,3,S}, translation::SVector{3,S})
RigidBodyTransform(rotation::AbstractArray{S,2}, translation::AbstractArray{S,1})
```
`θ`, `ϕ` and `ψ` in first constructor are in **radians**.
"""
struct RigidBodyTransform{T<:Real}
    rotation::SMatrix{3,3,T,9}
    translation::SVector{3,T}

    RigidBodyTransform{S}(θ::T, ϕ::T, ψ::T, x::T, y::T, z::T) where {T<:Number,S<:Real} = new{S}(rotmat(S, θ, ϕ, ψ), SVector{3,S}(x, y, z))
    RigidBodyTransform(rotation::SMatrix{3,3,T}, translation::SVector{3,T}) where {T<:Real} = new{T}(rotation, translation)
    function RigidBodyTransform(rotation::AbstractArray{T,2}, translation::AbstractArray{T,1}) where {T<:Real}
        @assert size(rotation)[1] == size(rotation)[2] == length(translation) == 3
        return new{T}(SMatrix{3,3,T}(rotation), SVector{3,T}(translation))
    end
end
export RigidBodyTransform

"""
    identitytransform([S::Type]) -> RigidBodyTransform{S}

Returns the [`RigidBodyTransform`](@ref) of type `S` (default `Float64`) representing the identity transform.
"""
identitytransform(::Type{T} = Float64) where {T<:Real} = RigidBodyTransform(SMatrix{3,3,T,9}(I), zeros(SVector{3,T}))
export identitytransform

"""
    rotmatbetween([S::Type], a::SVector{3,T}, b::SVector{3,T}) -> SMatrix{3,3,S}

Returns the rotation matrix of type `S` (default `Float64`) representing the rotation between vetors `a` and `b`.
"""
rotmatbetween(a::SVector{3,T}, b::SVector{3,T}) where {T<:Number} = rotmatbetween(Float64, a, b)
function rotmatbetween(::Type{S}, a::SVector{3,T}, b::SVector{3,T}) where {T<:Number,S<:Real}
    v = cross(a, b)
    c = dot(a, b)
    V = SMatrix{3,3,S,9}(0, v[3], -v[2], -v[3], 0, v[1], v[2], -v[1], 0)
    R = I + V + V^2 * one(T) / (one(T) + c)
    return SMatrix{3,3,S,9}(R)
end

"""
    rotmatd([S::Type], θ::T, ϕ::T, ψ::T) -> SMatrix{3,3,S}

Returns the rotation matrix of type `S` (default `Float64`) representing the rotation by `θ`, `ϕ` and `ψ` around the *x*, *y* and *z* axes respectively **in degrees**.
"""
rotmatd(θ::T, ϕ::T, ψ::T) where {T<:Number} = rotmat(Float64, θ * π / 180, ϕ * π / 180, ψ * π / 180)
rotmatd(::Type{S}, θ::T, ϕ::T, ψ::T) where {T<:Number,S<:Real} = rotmat(S, θ * π / 180, ϕ * π / 180, ψ * π / 180)
"""
    rotmat([S::Type], θ::T, ϕ::T, ψ::T) -> SMatrix{3,3,S}

Returns the rotation matrix of type `S` (default `Float64`) representing the rotation by `θ`, `ϕ` and `ψ` around the *x*, *y* and *z* axes respectively **in radians**.
"""
rotmat(θ::T, ϕ::T, ψ::T) where {T<:Number} = rotmat(Float64, θ, ϕ, ψ)
function rotmat(::Type{S}, θ::T, ϕ::T, ψ::T) where {T<:Number,S<:Real}
    sinψ = sin(ψ)
    sinϕ = sin(ϕ)
    sinθ = sin(θ)
    cosψ = cos(ψ)
    cosϕ = cos(ϕ)
    cosθ = cos(θ)
    return SMatrix{3,3,S,9}(cosψ * cosϕ, sinψ * cosϕ, -sinϕ, cosψ * sinϕ * sinθ - sinψ * cosθ, sinψ * sinϕ * sinθ + cosψ * cosθ, cosϕ * sinθ, cosψ * sinϕ * cosθ + sinψ * sinθ, sinψ * sinϕ * cosθ - cosψ * sinθ, cosϕ * cosθ)
end
"""
    translation([S::Type], x::T, y::T, z::T) -> RigidBodyTransform{S}

Returns the [`RigidBodyTransform`](@ref) of type `S` (default `Float64`) representing the translation by `x`, `y` and `z`.
"""
translation(x::T, y::T, z::T) where {T<:Number} = translation(Float64, x, y, z)
translation(::Type{S}, x::T, y::T, z::T) where {T<:Number,S<:Real} = RigidBodyTransform(SMatrix{3,3,S,9}(I), SVector{3,S}(x, y, z))
"""
    rotation([S::Type], θ::T, ϕ::T, ψ::T) -> RigidBodyTransform{S}

Returns the [`RigidBodyTransform`](@ref) of type `S` (default `Float64`) representing the rotation by `θ`, `ϕ` and `ψ` around the *x*, *y* and *z* axes respectively **in radians**.
"""
rotation(θ::T, ϕ::T, ψ::T) where {T<:Number} = rotation(Float64, θ, ϕ, ψ)
rotation(::Type{S}, θ::T, ϕ::T, ψ::T) where {T<:Number,S<:Real} = RigidBodyTransform(rotmat(S, θ, ϕ, ψ), zeros(SVector{3,S}))
"""
    rotationd([S::Type], θ::T, ϕ::T, ψ::T) -> RigidBodyTransform{S}

Returns the [`RigidBodyTransform`](@ref) of type `S` (default `Float64`) representing the rotation by `θ`, `ϕ` and `ψ` around the *x*, *y* and *z* axes respectively **in degrees**.
"""
rotationd(θ::T, ϕ::T, ψ::T) where {T<:Number} = rotationd(Float64, θ, ϕ, ψ)
rotationd(::Type{S}, θ::T, ϕ::T, ψ::T) where {T<:Number,S<:Real} = RigidBodyTransform(rotmatd(S, θ, ϕ, ψ), zeros(SVector{3,S}))
export translation, rotation, rotationd

function Base.:*(a::RigidBodyTransform{T}, r::Ray{T,3})::Ray{T,3} where {T}
    return Ray(a * origin(r), rotate(a, direction(r)))
end

function Base.:*(a::RigidBodyTransform{T}, intsct::Intersection{T,3})::Intersection{T,3} where {T<:Real}
    u, v = uv(intsct)
    i = interface(intsct)
    if VERSION < v"1.6.0-DEV"
        # TODO REMOVE
        return @unionsplit OpticalInterface T i Intersection(α(intsct), a * point(intsct), rotate(a, normal(intsct)), u, v, i, flippednormal = flippednormal(intsct))
    else
        return Intersection(α(intsct), a * point(intsct), rotate(a, normal(intsct)), u, v, interface(intsct), flippednormal = flippednormal(intsct))
    end
end

function Base.:*(transformation::RigidBodyTransform{T}, a::Interval{T}) where {T<:Real}
    # looks ridiculous but necessary to dissambiguate the elements of the interval
    u = upper(a)
    l = lower(a)
    if l isa RayOrigin{T}
        if u isa Infinity{T}
            return Interval(l, u)
        else
            u = transformation * u
            return Interval(l, u)
        end
    else
        l = transformation * l
        if u isa Infinity{T}
            return Interval(l, u)
        else
            u = transformation * u
            return Interval(l, u)
        end
    end
end

function Base.:*(a::RigidBodyTransform{T}, tmesh::TriangleMesh{T})::TriangleMesh{T} where {T<:Real}
    newT = Vector{Triangle{T}}(undef, length(tmesh.triangles))
    @inbounds @simd for i in 1:length(tmesh.triangles)
        newT[i] = a * tmesh.triangles[i]
    end
    return TriangleMesh(newT)
end

Base.:*(a::RigidBodyTransform{T}, t::Triangle{T}) where {T<:Real} = Triangle(a * vertex(t, 1), a * vertex(t, 2), a * vertex(t, 3))

function Base.:*(a::RigidBodyTransform{T}, vector::SVector{3,T}) where {T<:Real}
    if a.rotation === SMatrix{3,3,T,9}(I)
        return vector + a.translation
    else
        # in julia 0 * Inf = NaN, so if the vector has any infinite value in it then the rotation breaks
        # have to manually test and correct this - this can still fail when summing Infs of different signs (e.g. Inf + -Inf = NaN)
        # this happens when the rotation isn't axis aligned so the result becomes less meaningful anyway
        # in this case we fall back to infinite bounding boxes anyway which are usually clipped later in the csg
        # TODO better way to do this?
        if any(isinf.(vector))
            x = zero(T)
            y = zero(T)
            z = zero(T)
            @inbounds begin
                x += abs(a.rotation[1, 1]) <= eps(T) ? zero(T) : a.rotation[1, 1] * vector[1]
                x += abs(a.rotation[1, 2]) <= eps(T) ? zero(T) : a.rotation[1, 2] * vector[2]
                x += abs(a.rotation[1, 3]) <= eps(T) ? zero(T) : a.rotation[1, 3] * vector[3]
                y += abs(a.rotation[2, 1]) <= eps(T) ? zero(T) : a.rotation[2, 1] * vector[1]
                y += abs(a.rotation[2, 2]) <= eps(T) ? zero(T) : a.rotation[2, 2] * vector[2]
                y += abs(a.rotation[2, 3]) <= eps(T) ? zero(T) : a.rotation[2, 3] * vector[3]
                z += abs(a.rotation[3, 1]) <= eps(T) ? zero(T) : a.rotation[3, 1] * vector[1]
                z += abs(a.rotation[3, 2]) <= eps(T) ? zero(T) : a.rotation[3, 2] * vector[2]
                z += abs(a.rotation[3, 3]) <= eps(T) ? zero(T) : a.rotation[3, 3] * vector[3]
            end
            return SVector(x, y, z) + a.translation
        else
            return a.rotation * vector + a.translation
        end
    end
end
Base.:*(a::RigidBodyTransform{T}, b::RigidBodyTransform{T}) where {T<:Real} = RigidBodyTransform(a.rotation * b.rotation, a.translation + a.rotation * b.translation)
rotate(a::RigidBodyTransform{T}, vector::SVector{3,T}) where {T<:Real} = a.rotation * vector
Base.inv(a::RigidBodyTransform{T}) where {T<:Real} = RigidBodyTransform(a.rotation', -a.rotation' * a.translation)
Base.print(io::IO, a::RigidBodyTransform) = print(io, hcat(a.rotation, a.translation))
Base.collect(a::RigidBodyTransform) = hcat(a.rotation, a.translation)


text:
# If a matrix is `Diagonal` or if it is a `Cholesky` object,
# we generally don't need to wrap it in a `Symmetric`, because
# it's already symmetric. This is used in a couple of places to avoid precisely this and
# having to add specialised methods of e.g. `_cholesky` for complicated wrapped types.
_symmetric(X) = Symmetric(X)
_symmetric(X::Diagonal) = X
_symmetric(X::Cholesky) = X
_symmetric(X::AbstractPDMat) = X

# Small bit of indirection to work around a cholesky-related bug whereby the interaction
# between `FillArrays` and `Diagonal` and `Cholesky` causes problems.
_cholesky(X) = cholesky(X)
function _cholesky(X::Diagonal{<:Real,<:FillArrays.AbstractFill})
    return cholesky(Diagonal(collect(diag(X))))
end

"""
     update_chol(chol::Cholesky, C12::AbstractMatrix, C22::AbstractMatrix)

Let `C` be the positive definite matrix comprising blocks
```julia
C = [C11 C12;
     C21 C22]
```
with upper-triangular cholesky factorisation comprising blocks
```julia
U = [U11 U12;
     0   U22]
```
where `U11` and `U22` are themselves upper-triangular, and `U11 = cholesky(C11).U`.
update_chol computes the updated Cholesky given original `chol`, `C12`, and `C22`.

# Arguments
     - chol::Cholesky: The original cholesky decomposition
     - C12::AbstractMatrix: matrix of size (size(chol.U, 1), size(C22, 1))
     - C22::AbstractMatrix: positive-definite matrix
"""
function update_chol(chol::Cholesky, C12::AbstractMatrix, C22::AbstractMatrix)
    U12 = chol.U' \ C12
    U22 = cholesky(Symmetric(C22 - U12'U12)).U
    return Cholesky([chol.U U12; zero(U12') U22], 'U', 0)
end

# Various specialised operations using the Cholesky factorisation.

Xt_A_X(A::Cholesky, x::AbstractVector) = sum(abs2, A.U * x)
function Xt_A_X(A::Cholesky, X::AbstractMatrix)
    V = A.U * X
    return Symmetric(V'V)
end

Xt_A_Y(X::AbstractVecOrMat, A::Cholesky, Y::AbstractVecOrMat) = (A.U * X)' * (A.U * Y)

Xt_invA_X(A::Cholesky, x::AbstractVector) = sum(abs2, A.U' \ x)
function Xt_invA_X(A::Cholesky, X::AbstractVecOrMat)
    V = A.U' \ X
    return Symmetric(V'V)
end

Xt_invA_Y(X::AbstractVecOrMat, A::Cholesky, Y::AbstractVecOrMat) = (A.U' \ X)' * (A.U' \ Y)

At_A(A::AbstractVecOrMat) = A'A

diag_At_A(A::AbstractMatrix) = vec(sum(abs2, A; dims=1))
diag_At_A(A::AbstractVector) = [sum(abs2, A)]

tr_At_A(A::AbstractVecOrMat) = sum(abs2, A)

function diag_At_B(A::AbstractMatrix, B::AbstractMatrix)
    size(A) == size(B) || throw(
        DimensionMismatch(
            "A ($(size(A))) and B ($(size(B))) do not have the same dimensions "
        ),
    )
    return vec(sum(A .* B; dims=1))
end
diag_At_B(x::AbstractVector, y::AbstractVector) = [dot(x, y)]

diag_Xt_A_X(A::Cholesky, X::AbstractVecOrMat) = diag_At_A(A.U * X)

function diag_Xt_A_Y(X::AbstractVecOrMat, A::Cholesky, Y::AbstractVecOrMat)
    size(X) == size(Y) || throw(
        DimensionMismatch(
            "X ($(size(X))) and Y ($(size(Y))) do not have the same dimensions "
        ),
    )
    return diag_At_B(A.U * X, A.U * Y)
end

diag_Xt_invA_X(A::Cholesky, X::AbstractVecOrMat) = diag_At_A(A.U' \ X)

function diag_Xt_invA_Y(X::AbstractMatrix, A::Cholesky, Y::AbstractMatrix)
    size(X) == size(Y) || throw(
        DimensionMismatch(
            "X ($(size(X))) and Y ($(size(Y))) do not have the same dimensions "
        ),
    )
    return diag_At_B(A.U' \ X, A.U' \ Y)
end

tr_Xt_invA_X(A::Cholesky, X::AbstractVecOrMat) = tr_At_A(A.U' \ X)

function Xtinv_A_Xinv(A::Cholesky, X::Cholesky)
    size(A) == size(X) || throw(
        DimensionMismatch(
            "A ($(size(A))) and X ($(size(X))) do not have the same dimensions "
        ),
    )
    C = A.U \ (X.U' \ A.U')
    return Symmetric(C * C')
end

max_stars_repo_name: JuliaGaussianProcesses/AbstractGP

max_issues_repo_name: JuliaGaussianProcesses/AbstractGP

max_forks_repo_name: JuliaGaussianProcesses/AbstractGP


text:
#greet() = print("Hello world!")

function aI_generate_00()
    return rand(Float64, 4, 2)
end


text:
include("./octahedron_test.jl")
include("./tetramihexahedron_test.jl")
include("./octahemioctahedron_test.jl")
include("./cubohemioctahedron_prototype.jl")


text:
# Base Function Test

struct Euclidean <: Metric end

MLK.base_aggregate(::Euclidean, s::T, x::T, y::T) where {T} = s + (x-y)^2
MLK.base_return(::Euclidean, s::T) where {T} = sqrt(s)

# Base Function References

const base_functions = (
    SquaredEuclidean,
    ScalarProduct,
    Euclidean
)

const base_functions_initiate = Dict(
    SquaredEuclidean => 0,
    ScalarProduct    => 0,
    Euclidean        => 0
)

const base_functions_aggregate = Dict(
    SquaredEuclidean => (s,x,y) -> s + (x-y)^2,
    ScalarProduct    => (s,x,y) -> s + x*y,
    Euclidean        => (s,x,y) -> s + (x-y)^2
)

const base_functions_return = Dict(
    SquaredEuclidean => s -> s,
    ScalarProduct    => s -> s,
    Euclidean        => s -> sqrt(s)
)

const base_functions_properties = Dict(
                       #|stnry |isotrop
    ScalarProduct    => (false, false),
    SquaredEuclidean => (true,  true),
    Euclidean        => (false, false) # just default values test
)

# Kernel Function References

const kernel_functions = (
    ExponentialKernel,
    SquaredExponentialKernel,
    GammaExponentialKernel,
    RationalQuadraticKernel,
    GammaRationalQuadraticKernel,
    MaternKernel,
    PolynomialKernel,
    ExponentiatedKernel,
    PowerKernel,
    LogKernel,
    SigmoidKernel
)

const kernel_functions_arguments = Dict(
    ExponentialKernel            => ((1.0,),        (2.0,)),
    SquaredExponentialKernel     => ((1.0,),        (2.0,)),
    GammaExponentialKernel       => ((1.0,1.0),     (2.0,0.5)),
    RationalQuadraticKernel      => ((1.0,1.0),     (2.0,2.0)),
    GammaRationalQuadraticKernel => ((1.0,1.0,1.0), (2.0,2.0,0.5)),
    MaternKernel                 => ((1.0,1.0),     (2.0,2.0)),
    PolynomialKernel             => ((1.0,1.0,3),   (2.0,2.0,2)),
    ExponentiatedKernel          => ((1.0,),        (2.0,)),
    PowerKernel                  => ((1.0,),        (0.5,)),
    LogKernel                    => ((1.0,1.0),     (2.0,0.5)),
    SigmoidKernel                => ((1.0,1.0),     (2.0,2.0))
)

const kernel_functions_kappa = Dict(
    ExponentialKernel            => (z,α)     -> exp(-α*sqrt(z)),
    SquaredExponentialKernel     => (z,α)     -> exp(-α*z),
    GammaExponentialKernel       => (z,α,γ)   -> exp(-α*z^γ),
    RationalQuadraticKernel      => (z,α,β)   -> (1 + α*z)^(-β),
    GammaRationalQuadraticKernel => (z,α,β,γ) -> (1 + α*z^γ)^(-β),
    MaternKernel                 => (z,ν,ρ)   -> begin
                                                   d = √(z)
                                                   T = typeof(z)
                                                   d = d < eps(T) ? eps(T) : d
                                                   tmp1 = √(2*ν)*d/ρ
                                                   tmp2 = 2^(1 - ν)
                                                   tmp2*(tmp1^ν)*besselk(ν, tmp1)/gamma(ν)
                                                end,
    PolynomialKernel             => (z,a,c,d) -> (a*z+c)^d,
    ExponentiatedKernel          => (z,a)     -> exp(a*z),
    PowerKernel                  => (z,γ)     -> z^γ,
    LogKernel                    => (z,α,γ)   -> log(α*z^γ+1),
    SigmoidKernel                => (z,a,c)   -> tanh(a*z+c)
)

const kernel_functions_base = Dict(
    PolynomialKernel         => ScalarProduct,
    ExponentiatedKernel      => ScalarProduct,
    SigmoidKernel            => ScalarProduct
)


text:
using FastTransforms, LinearAlgebra, Test

import FastTransforms: pochhammer, sqrtpi, SpecialFunctions.gamma
import FastTransforms: Cnλ, Λ, lambertw, Cnαβ, Anαβ
import FastTransforms: chebyshevmoments1, chebyshevmoments2, chebyshevjacobimoments1, chebyshevjacobimoments2, chebyshevlogmoments1, chebyshevlogmoments2

@testset "Special functions" begin
    @test pochhammer(2,3) == 24
    @test pochhammer(0.5,3) == 0.5*1.5*2.5
    @test pochhammer(0.5,0.5) == 1/sqrtpi
    @test pochhammer(0,1) == 0
    @test pochhammer(-1,2) == 0
    @test pochhammer(-5,3) == -60
    @test pochhammer(-1,-0.5) == 0
    @test 1.0/pochhammer(-0.5,-0.5) == 0
    @test pochhammer(-1+0im,-1) == -0.5
    @test pochhammer(2,1) == pochhammer(2,1.0) == pochhammer(2.0,1) == 2
    @test pochhammer(1.1,2.2) ≈ gamma(3.3)/gamma(1.1)
    @test pochhammer(-2,1) == pochhammer(-2,1.0) == pochhammer(-2.0,1) == -2

    n = 0:1000
    λ = 0.125
    @test norm(Cnλ.(n, λ) ./ Cnλ.(n, big(λ)) .- 1, Inf) < 3eps()

    x = range(0, stop=20, length=81)
    @test norm((Λ.(x) .- Λ.(big.(x)))./Λ.(x), Inf) < 2eps()
    @test norm((lambertw.(x) .- lambertw.(big.(x)))./max.(lambertw.(x), 1), Inf) < 2eps()

    x = 0:0.5:1000
    λ₁, λ₂ = 0.125, 0.875
    @test norm((Λ.(x,λ₁,λ₂) .- Λ.(big.(x),big(λ₁),big(λ₂)))./Λ.(big.(x),big(λ₁),big(λ₂)), Inf) < 4eps()
    λ₁, λ₂ = 1//3, 2//3
    @test norm((Λ.(x,Float64(λ₁),Float64(λ₂)) .- Λ.(big.(x),big(λ₁),big(λ₂))) ./ Λ.(big.(x),big(λ₁),big(λ₂)), Inf) < 4eps()

    α, β = 0.125, 0.375

    @test norm(Cnαβ.(n,α,β) ./ Cnαβ.(n,big(α),big(β)) .- 1, Inf) < 3eps()
    @test norm(Anαβ.(n,α,β) ./ Anαβ.(n,big(α),big(β)) .- 1, Inf) < 4eps()
end


text:
# `info_dict` returns a dictionary of model trait values suitable, after
# encoding, to serializing to TOML file. Not intended to be exposed to
# user.

info_dict(model::Model) = info_dict(typeof(model))

function info_dict(M::Type{<:Model})
    message = "$M has a bad trait declaration.\n"
    is_pure_julia(M) isa Bool ||
        error(message * "`is_pure_julia($M)` must return true or false")
    supports_weights(M) isa Bool ||
        error(message * "`supports_weights($M)` must return true, "*
              "false or missing. ")
    is_wrapper(M) isa Bool ||
        error(message * "`is_wrapper($M)` must return true, false. ")

    return LittleDict{Symbol,Any}(trait => eval(:($trait))(M)
                                  for trait in MLJModelInterface.MODEL_TRAITS)
end


text:
using Revise
using AdFem
using LinearAlgebra

σ1 = rand(10, 3)
σ2 = zeros(10, 3)
ε1 = rand(10, 3)
ε2 = rand(10, 3)
μ = rand(10)
η = rand(10)
λ = rand(10)
Δt = rand()
for i = 1:10
    s = μ[i]*η[i]*Δt
    S = [
        1 + 2/3*s -1/3*s 0
        -1/3*s 1+2/3*s 0
        0 0 1+s
    ]
    S = inv(S)
    H = S * [
        2*μ[i]+λ[i] λ[i] 0
        λ[i] 2*μ[i]+λ[i] 0
        0 0 μ[i]
    ]
    σ2[i,:] = H * (ε2[i,:] - ε1[i,:]) + S*σ1[i,:]
end
σ22 = update_stress_viscosity(ε2, ε1, σ1, η, μ, λ, Δt)

@show norm(σ2 - σ22)


text:
module TestConversions

using Base.Test
using DataArrays
using DataFrames
using TimeSeries
using TimeData
using Dates

## using TimeData

println("Running conversion tests")

###########
## asArr ##
###########

## DataArray
##----------

da = @data([NA, 3, 4, NA])
expOut = Float64[NaN, 3.0, 4.0, NaN]
@test isequal(expOut, TimeData.asArr(da, Float64, NaN))

da = @data([NA, true, true, false])
expOut = Bool[true, true, true, false]
@test isequal(expOut, TimeData.asArr(da, Bool, true))

da = @data([true, true, "hello", NA])
expOut = Any[true, true, "hello", NaN]
@test isequal(expOut, TimeData.asArr(da, Any, NaN))

da = @data(["dog", "house", "hello", NA])
expOut = UTF8String["dog", "house", "hello", ""]
@test isequal(expOut, TimeData.asArr(da, UTF8String, ""))

## should throw error

da = @data([true, true, "hello", NA])
@test_throws Exception TimeData.asArr(da, Float64, true)

da = @data(["dog", "house", "hello", NA])
@test_throws Exception TimeData.asArr(da, UTF8String, 4.3)

## DataFrames
##-----------

df = DataFrame(a = @data([3.4, NA]),
               b = @data([3.4, NA]))

expOut = [3.4 3.4; NaN NaN]
@test isequal(expOut, TimeData.asArr(df, Float64, NaN))
@test_throws Exception TimeData.asArr(df, Float64)

df = DataFrame(a = ["hello", "world"],
               b = @data(["what", NA]))

expOut = ["hello" "what"; "world" "is"]
@test isequal(expOut, TimeData.asArr(df, String, "is"))

df = DataFrame(a = true, b = false, c = NA)
@test isequal([true false true], TimeData.asArr(df, Bool, true))

## TimeData
##---------

tn = TimeData.testcase(TimeData.Timenum, 2)[1:2,:]
expOut = [NaN 110; 120 120.0]
@test isequal(expOut, TimeData.asArr(tn, Float64, NaN))

expOut = [0 110; 120 120]
@test isequal(expOut, TimeData.asArr(tn, Float64, 0))

## NaN not allowed in Int
@test_throws InexactError TimeData.asArr(tn, Int, NaN)

expOut = Any[NA 110; 120 120]
@test isequal(expOut, TimeData.asArr(tn))

## DataFrameRow
##-------------

df = DataFrame(a = @data([3, NA]),
               b = @data([3, NA]))

rowIter = eachrow(df)
expOut = Float64[3.0 3.0]
@test isequal(expOut, TimeData.asArr(next(rowIter, 1)[1], Float64))

expOut = Float64[NaN NaN]
@test isequal(expOut, TimeData.asArr(next(rowIter, 2)[1], Float64, NaN))

##############
## TimeData ##
##############

df = DataFrame()
df[:a] = @data([4, NA])
df[:b] = @data([3, 8])
dats1 = [Date(2014,1,1):Date(2014,1,2)]
tn = TimeData.Timenum(df, dats1)

## convert Timenum
@test isequal(TimeData.convert(TimeData.Timedata, tn), TimeData.Timedata(df, dats1))
@test_throws ArgumentError TimeData.convert(TimeData.Timematr, tn)
@test TimeData.convert(TimeData.Timematr, tn, true) == TimeData.Timematr(df[1, :], [dats1[1]])

## convert Timematr
vals = rand(2, 4)
tm = TimeData.Timematr(vals, dats1)
@test TimeData.convert(TimeData.Timedata, tm) == TimeData.Timedata(vals, dats1)
@test TimeData.convert(TimeData.Timenum, tm) == TimeData.Timenum(vals, dats1)

## convert Timedata
vals = rand(2, 4)
tm = TimeData.Timedata(vals, dats1)
@test TimeData.convert(TimeData.Timematr, tm) == TimeData.Timematr(vals, dats1)
@test TimeData.convert(TimeData.Timenum, tm) == TimeData.Timenum(vals, dats1)

## non-convertible objects: NAs included
df = DataFrame()
df[:a] = @data([4, NA])
df[:b] = @data([3, 8])
dats1 = [Date(2014,1,1):Date(2014,1,2)]
tn = TimeData.Timedata(df, dats1)

TimeData.convert(TimeData.Timenum, tn)
@test_throws ArgumentError TimeData.convert(TimeData.Timematr, tn)

## non-convertible objects: strings included
df = DataFrame()
df[:a] = @data(["hello", NA])
df[:b] = @data([3, 8])
dats1 = [Date(2014,1,1):Date(2014,1,2)]
tn = TimeData.Timedata(df, dats1)

@test_throws ArgumentError TimeData.convert(TimeData.Timenum, tn)
@test_throws ArgumentError TimeData.convert(TimeData.Timematr, tn)

################
## TimeArrays ##
################

## TimeArray to TimeData
##----------------------

d = [Date(1980,1,1):Date(2015,1,1)];
t = TimeArray(d,rand(length(d)),["test"])
tm = convert(AbstractTimedata, t)

@test all(t.values .== asArr(tm, Float64))
@test names(tm) == [:test]
@test t.timestamp == idx(tm)

## TimeData to TimeArray
##----------------------

t2 = convert(TimeArray, tm)

@test all(t2.values .== asArr(tm, Float64))
@test t2.colnames == ["test"]
@test t2.timestamp == idx(tm)

end


text:
# Don't build docs on version 0.4 since they will fail.
VERSION < v"0.5.0-dev" && exit()

using Documenter, DocStringExtensions

makedocs(
    sitename = "DocStringExtensions.jl",
    modules = [DocStringExtensions],
    format = Documenter.Formats.HTML,
    clean = false,
    pages = Any["Home" => "index.md"],
)

deploydocs(
    target = "build",
    deps = nothing,
    make = nothing,
    repo = "github.com/JuliaDocs/DocStringExtensions.jl.git",
)


text:
module Calculus
    import Base.ctranspose
    export check_derivative,
           check_gradient,
           check_hessian,
           check_second_derivative,
           deparse,
           derivative,
           differentiate,
           gradient,
           hessian,
           integrate,
           jacobian,
           second_derivative

    # TODO: Debate type system more carefully
    # abstract BundledFunction
    # abstract ScalarFunction
    # abstract VectorFunction
    # abstract ForwardDifference
    # abstract CentralDifference
    # abstract ComplexDifference
    # abstract GradientEstimator
    # abstract HessianEstimator

    # typealias NonDifferentiableFunction Function
    # type DifferentiableFunction
    #   f::Function
    #   g::Function
    # end
    # type TwiceDifferentiableFunction
    #   f::Function
    #   g::Function
    #   h::Function
    # end
    # type NonDifferentiableBundledFunction <: BundledFunction
    #   f::Function
    #   fstorage::Any
    # end
    # type DifferentiableBundledFunction <: BundledFunction
    #   f::Function
    #   g::Function
    #   fstorage::Any
    #   gstorage::Any
    # end
    # type TwiceDifferentiableBundledFunction <: BundledFunction
    #   f::Function
    #   g::Function
    #   h::Function
    #   fstorage::Any
    #   gstorage::Any
    #   hstorage::Any
    # end

    include(joinpath(julia_pkgdir(), "Calculus", "src", "finite_difference.jl"))
    include(joinpath(julia_pkgdir(), "Calculus", "src", "derivative.jl"))
    include(joinpath(julia_pkgdir(), "Calculus", "src", "check_derivative.jl"))
    include(joinpath(julia_pkgdir(), "Calculus", "src", "integrate.jl"))
    include(joinpath(julia_pkgdir(), "Calculus", "src", "symbolic.jl"))
    include(joinpath(julia_pkgdir(), "Calculus", "src", "deparse.jl"))
end


text:
"""
Struct for Double Barrier Option

		dbOption=DoubleBarrierOption(T::num1,K::num2,D::num3,U::num4,isCall::Bool=true) where {num1 <: Number,num2 <: Number,num3 <: Number,num4 <: Number}

Where:\n
		T	=	Time to maturity of the Option.
		K	=	Strike Price of the Option.
		D	=	Low Barrier of the Option.
		U	=	Up Barrier of the Option.
		isCall  = true for CALL, false for PUT.
"""
struct DoubleBarrierOption{num1 <: Number, num2 <: Number, num3 <: Number, num4 <: Number, numtype <: Number} <: BarrierPayoff{numtype}
    T::num1
    K::num2
    D::num3
    U::num4
    isCall::Bool
    function DoubleBarrierOption(T::num1, K::num2, D::num3, U::num4, isCall::Bool = true) where {num1 <: Number, num2 <: Number, num3 <: Number, num4 <: Number}
        if T <= 0.0
            error("Time to Maturity must be positive")
        elseif K <= 0.0
            error("Strike Price must be positive")
        elseif D <= 0.0
            error("Low Barrier must be positive")
        elseif U <= D
            error("High Barrier must be positive and greater then Low barrier")
        else
            zero_typed = zero(num1) + zero(num2) + zero(num3) + zero(num4)
            return new{num1, num2, num3, num4, typeof(zero_typed)}(T, K, D, U, isCall)
        end
    end
end

export DoubleBarrierOption;

function payout(S::abstractArray, barrierPayoff::DoubleBarrierOption) where {abstractArray <: AbstractArray{num_}} where {num_ <: Number}
    iscall = barrierPayoff.isCall ? 1 : -1
    zero_typed = zero(eltype(S)) * barrierPayoff.K * barrierPayoff.U * barrierPayoff.D
    return max(iscall * (S[end] - barrierPayoff.K), zero_typed) * (findfirst(x -> x < barrierPayoff.D, S) == nothing) * (findfirst(x -> x > barrierPayoff.U, S) == nothing)
end


text:
module AffineArithmetic

using IntervalArithmetic

import Base: +, -, *, /, ^, ==,
            zero, one, range,
            show

export Affine, reset_affine_index

include("AF1.jl")
include("AF.jl")
include("AFF.jl")
export AF1, AF, AFF

const affine_index = [1]  # which affine vector index to use

reset_affine_index() = affine_index[1] = 1

@doc """
An affine quantity for affine arithmetic.
The usual way to create an affine quantity is from an interval `X`, via `Affine(X)`.
"""
struct Affine{T<:AbstractFloat}
    c::T   # mid-point
    γ::Vector{T}  # error terms
end

function show(io::IO, C::Affine)
    print(io, "⟨", C.c, "; ", C.γ, "⟩")
end

==(C::Affine, D::Affine) = C.c == D.c && C.γ == D.γ

@doc """
    Affine(X::Interval)

Construct a new `Affine` quantity from an `Interval`.
"""
function Affine(X::Interval)
    c = mid(X)
    r = radius(X)

    index = affine_index[1]
    affine_index[1] += 1

    γ = zeros(index)
    γ[end] = r

    return Affine(c, γ)
end

# conversion of numerical constant to affine:
Affine(c::Real) = Affine(c, Float64[])

range(C::Affine) = C.c + sum(abs.(C.γ))*(-1..1)

range(X::Interval) = X

# morally:
# +(C::Affine, D::Afine) = Affine(C.c + D.c, C.γ + D.γ)

for op in (:+, :-)
    @eval function $op(C::Affine, D::Affine)
        k = length(C.γ)
        l = length(D.γ)

        # account for unequal lengths:
        m = min(k, l)
        common_γ = $op(C.γ[1:m], D.γ[1:m])

        if l >= k
            γ = [ common_γ; D.γ[m+1:l] ]
        else
            γ = [ common_γ; C.γ[m+1:k] ]
        end

        Affine($op(C.c, D.c), γ)
    end
end

+(C::Affine, α::Real) = Affine(C.c + α, C.γ)
+(α::Real, C::Affine) = C + α

-(C::Affine, α::Real) = Affine(C.c - α, C.γ)
-(α::Real, C::Affine) = Affine(α - C.c, [-x for x in C.γ])

function *(C::Affine, D::Affine)

    c = C.c
    d = D.c

    k = length(C.γ)
    l = length(D.γ)

    # account for unequal lengths:
    m = min(k, l)
    common_γ = d * C.γ[1:m] + c * D.γ[1:m]

    error_bound = sum(abs.(C.γ)) * sum(abs.(D.γ))

    if l >= k
        γ = [ common_γ; c*D.γ[m+1:l]; error_bound ]
    else
        γ = [ common_γ; d*C.γ[m+1:k]; error_bound ]
    end

    # |γ|₁ = sum(abs.(γ))

    Affine(C.c * D.c, γ)
end

*(α::Real, C::Affine) = Affine(α*C.c, α*C.γ)
*(C::Affine, α::Real) = α * C

^(x::Affine, n::Integer) = Base.power_by_squaring(x, n)

Base.literal_pow(::typeof(^), x::Affine{T}, ::Val{p}) where {T,p} = x^p

eltype(C::Affine{T}) where T = T
zero(C::Affine{T}) where T = Affine(zero(T))
zero(::Type{Affine{T}}) where T = Affine(zero(T))

one(C::Affine{T}) where T = Affine(one(T))
one(::Type{Affine{T}}) where T = Affine(one(T))

#one(C::Affine)

end


text:
function DiffEqBase.solve(prob::OptimizationProblem, opt, args...;kwargs...)
	__solve(prob, opt, args...; kwargs...)
end

decompose_trace(trace::Optim.OptimizationTrace) = last(trace)
decompose_trace(trace) = trace

function __solve(prob::OptimizationProblem, opt::Optim.AbstractOptimizer;cb = (args...) -> (false), maxiters = 1000, kwargs...)
  	local x

	function _cb(trace)
		cb_call = opt == NelderMead() ? cb(decompose_trace(trace).metadata["centroid"],x...) : cb(decompose_trace(trace).metadata["x"],x...)
		if !(typeof(cb_call) <: Bool)
			error("The callback should return a boolean `halt` for whether to stop the optimization process.")
		end
		cb_call
  	end

	if prob.f isa OptimizationFunction
		_loss = function(θ)
			x = prob.f.f(θ, prob.p)
			return x[1]
		end
		fg! = let res = DiffResults.GradientResult(prob.x)
			function (G,θ)
				if G !== nothing
					prob.f.grad(res, θ)
					G .= DiffResults.gradient(res)
				end

				return _loss(θ)
			end
		end
		if opt isa Optim.KrylovTrustRegion
			optim_f = Optim.TwiceDifferentiableHV(_loss, fg!, prob.f.hv, prob.x)
		else
			optim_f = TwiceDifferentiable(_loss, prob.f.grad, fg!, prob.f.hess, prob.x)
		end
	else
		!(opt isa Optim.ZerothOrderOptimizer) && error("Use OptimizationFunction to pass the derivatives or automatically generate them with one of the autodiff backends")
		_loss = function(θ)
			x = prob.f(θ, prob.p)
			return x[1]
		end
		optim_f = _loss
	end

  	Optim.optimize(optim_f, prob.x, opt, Optim.Options(;extended_trace = true, callback = _cb, iterations = maxiters, kwargs...))
end

function __solve(prob::OptimizationProblem, opt::Union{Optim.Fminbox,Optim.SAMIN};cb = (args...) -> (false), maxiters = 1000, kwargs...)
	local x

  	function _cb(trace)
	  	cb_call = !(opt isa Optim.SAMIN) && opt.method == NelderMead() ? cb(decompose_trace(trace).metadata["centroid"],x...) : cb(decompose_trace(trace).metadata["x"],x...)
	  	if !(typeof(cb_call) <: Bool)
			error("The callback should return a boolean `halt` for whether to stop the optimization process.")
	  	end
	  	cb_call
	end

  	if prob.f isa OptimizationFunction && !(opt isa Optim.SAMIN)
	  	_loss = function(θ)
			x = prob.f.f(θ, prob.p)
			return x[1]
	  	end
	  	fg! = let res = DiffResults.GradientResult(prob.x)
		  	function (G,θ)
			  	if G !== nothing
				  	prob.f.grad(res, θ)
				  	G .= DiffResults.gradient(res)
			  	end

			  	return _loss(θ)
		  	end
	  	end
		optim_f = OnceDifferentiable(_loss, prob.f.grad, fg!, prob.x)
  	else
	  	!(opt isa Optim.ZerothOrderOptimizer) && error("Use OptimizationFunction to pass the derivatives or automatically generate them with one of the autodiff backends")
		_loss = function(θ)
			x = prob.f isa OptimizationFunction ? prob.f.f(θ, prob.p) : prob.f(θ, prob.p)
			return x[1]
	  	end
	  	optim_f = _loss
  	end

	Optim.optimize(optim_f, prob.lb, prob.ub, prob.x, opt, Optim.Options(;extended_trace = true, callback = _cb, iterations = maxiters, kwargs...))
end

function __init__()
	@require BlackBoxOptim="a134a8b2-14d6-55f6-9291-3336d3ab0209" begin
		decompose_trace(opt::BlackBoxOptim.OptRunController) = BlackBoxOptim.best_candidate(opt)

		struct BBO
			method::Symbol
		end

		BBO() = BBO(:adaptive_de_rand_1_bin)

		function __solve(prob::OptimizationProblem, opt::BBO; cb = (args...) -> (false), maxiters = 1000, kwargs...)
			local x, _loss

			function _cb(trace)
			  cb_call = cb(decompose_trace(trace),x...)
			  if !(typeof(cb_call) <: Bool)
				error("The callback should return a boolean `halt` for whether to stop the optimization process.")
			  end
			  if cb_call == true
				BlackBoxOptim.shutdown_optimizer!(trace) #doesn't work
			  end
			  cb_call
			end

			if prob.f isa OptimizationFunction
				_loss = function(θ)
					x = prob.f.f(θ, prob.p)
					return x[1]
				end
			else
				_loss = function(θ)
					x = prob.f(θ, prob.p)
					return x[1]
				end
			end

			bboptre = BlackBoxOptim.bboptimize(_loss;Method = opt.method, SearchRange = [(prob.lb[i], prob.ub[i]) for i in 1:length(prob.lb)], MaxSteps = maxiters, CallbackFunction = _cb, CallbackInterval = 0.0, kwargs...)

			Optim.MultivariateOptimizationResults(opt.method,
												  [NaN],# initial_x,
												  BlackBoxOptim.best_candidate(bboptre), #pick_best_x(f_incr_pick, state),
												  BlackBoxOptim.best_fitness(bboptre), # pick_best_f(f_incr_pick, state, d),
												  bboptre.iterations, #iteration,
												  bboptre.iterations >= maxiters, #iteration == options.iterations,
												  false, # x_converged,
												  0.0,#T(options.x_tol),
												  0.0,#T(options.x_tol),
												  NaN,# x_abschange(state),
												  NaN,# x_abschange(state),
												  false,# f_converged,
												  0.0,#T(options.f_tol),
												  0.0,#T(options.f_tol),
												  NaN,#f_abschange(d, state),
												  NaN,#f_abschange(d, state),
												  false,#g_converged,
												  0.0,#T(options.g_tol),
												  NaN,#g_residual(d),
												  false, #f_increased,
												  nothing,
												  maxiters,
												  maxiters,
												  0,
												  true,
												  NaN,
												  bboptre.elapsed_time)
		end
	end

	@require NLopt="76087f3c-5699-56af-9a33-bf431cd00edd" begin
		function __solve(prob::OptimizationProblem, opt::NLopt.Opt; maxiters = 1000, nstart = 1, local_method = nothing, kwargs...)
			local x

			if prob.f isa OptimizationFunction
				_loss = function(θ)
					x = prob.f.f(θ, prob.p)
					return x[1]
				end
				fg! = let res = DiffResults.GradientResult(prob.x)
					function (θ,G)
						if length(G) > 0
							prob.f.grad(res, θ)
							G .= DiffResults.gradient(res)
						end

						return _loss(θ)
					end
				end
				NLopt.min_objective!(opt, fg!)
			else
				_loss = function(θ,G)
					x = prob.f(θ, prob.p)
					return x[1]
				end
				NLopt.min_objective!(opt, _loss)
			end

			if prob.ub !== nothing
				NLopt.upper_bounds!(opt, prob.ub)
			end
			if prob.lb !== nothing
				NLopt.lower_bounds!(opt, prob.lb)
			end

			if nstart > 1 && local_method !== nothing
				NLopt.local_optimizer!(opt, local_method)
				NLopt.maxeval!(opt, nstart * maxiters)
			end

            NLopt.maxeval!(opt, maxiters)

            t0= time()
            (minf,minx,ret) = NLopt.optimize(opt, prob.x)
            _time = time()

            Optim.MultivariateOptimizationResults(opt,
                                                    prob.x,# initial_x,
                                                    minx, #pick_best_x(f_incr_pick, state),
                                                    minf, # pick_best_f(f_incr_pick, state, d),
                                                    maxiters, #iteration,
													maxiters >= opt.numevals, #iteration == options.iterations,
                                                    false, # x_converged,
                                                    0.0,#T(options.x_tol),
                                                    0.0,#T(options.x_tol),
                                                    NaN,# x_abschange(state),
                                                    NaN,# x_abschange(state),
                                                    false,# f_converged,
                                                    0.0,#T(options.f_tol),
                                                    0.0,#T(options.f_tol),
                                                    NaN,#f_abschange(d, state),
                                                    NaN,#f_abschange(d, state),
                                                    false,#g_converged,
                                                    0.0,#T(options.g_tol),
                                                    NaN,#g_residual(d),
                                                    false, #f_increased,
                                                    nothing,
                                                    maxiters,
                                                    maxiters,
                                                    0,
                                                    ret,
                                                    NaN,
													_time-t0,)
		end
	end

	@require MultistartOptimization = "3933049c-43be-478e-a8bb-6e0f7fd53575" begin
		function __solve(prob::OptimizationProblem, opt::MultistartOptimization.TikTak; local_method, local_maxiters = 1000, kwargs...)
			local x, _loss

			if prob.f isa OptimizationFunction
				_loss = function(θ)
					x = prob.f.f(θ, prob.p)
					return x[1]
				end
			else
				_loss = function(θ)
					x = prob.f(θ, prob.p)
					return x[1]
				end
			end

			t0 = time()

			P = MultistartOptimization.MinimizationProblem(_loss, prob.lb, prob.ub)
			multistart_method = opt
			local_method = MultistartOptimization.NLoptLocalMethod(local_method, maxeval = local_maxiters)
			p = MultistartOptimization.multistart_minimization(multistart_method, local_method, P)

			t1 = time()

			Optim.MultivariateOptimizationResults(opt,
                                                [NaN],# initial_x,
                                                p.location, #pick_best_x(f_incr_pick, state),
                                                p.value, # pick_best_f(f_incr_pick, state, d),
                                                0, #iteration,
                                                false, #iteration == options.iterations,
                                                false, # x_converged,
                                                0.0,#T(options.x_tol),
                                                0.0,#T(options.x_tol),
                                                NaN,# x_abschange(state),
                                                NaN,# x_abschange(state),
                                                false,# f_converged,
                                                0.0,#T(options.f_tol),
                                                0.0,#T(options.f_tol),
                                                NaN,#f_abschange(d, state),
                                                NaN,#f_abschange(d, state),
                                                false,#g_converged,
                                                0.0,#T(options.g_tol),
                                                NaN,#g_residual(d),
                                                false, #f_increased,
                                                nothing,
                                                local_maxiters,
                                                local_maxiters,
                                                0,
                                                true,
                                                NaN,
                                                t1 - t0)
		end
	end

	@require QuadDIRECT = "dae52e8d-d666-5120-a592-9e15c33b8d7a" begin
		export QuadDirect

        struct QuadDirect
		end

		function __solve(prob::OptimizationProblem, opt::QuadDirect; splits, maxiters = 1000, kwargs...)
			local x, _loss

			if prob.f isa OptimizationFunction
				_loss = function(θ)
					x = prob.f.f(θ, prob.p)
					return x[1]
				end
			else
				_loss = function(θ)
					x = prob.f(θ, prob.p)
					return x[1]
				end
			end

			t0 = time()

			root, x0 = QuadDIRECT.analyze(_loss, splits, prob.lb, prob.ub; maxevals = maxiters, kwargs...)
			box = minimum(root)
           	t1 = time()

           	Optim.MultivariateOptimizationResults(opt,
                                                [NaN],# initial_x,
                                                QuadDIRECT.position(box, x0), #pick_best_x(f_incr_pick, state),
                                                QuadDIRECT.value(box), # pick_best_f(f_incr_pick, state, d),
                                                0, #iteration,
                                                false, #iteration == options.iterations,
                                                false, # x_converged,
                                                0.0,#T(options.x_tol),
                                                0.0,#T(options.x_tol),
                                                NaN,# x_abschange(state),
                                                NaN,# x_abschange(state),
                                                false,# f_converged,
                                                0.0,#T(options.f_tol),
                                                0.0,#T(options.f_tol),
                                                NaN,#f_abschange(d, state),
                                                NaN,#f_abschange(d, state),
                                                false,#g_converged,
                                                0.0,#T(options.g_tol),
                                                NaN,#g_residual(d),
                                                false, #f_increased,
                                                nothing,
                                                maxiters,
                                                maxiters,
                                                0,
                                                true,
                                                NaN,
                                                t1 - t0)
		end
	end

	@require Evolutionary="86b6b26d-c046-49b6-aa0b-5f0f74682bd6" begin
		decompose_trace(trace::Evolutionary.OptimizationTrace) = last(trace)

		function Evolutionary.trace!(record::Dict{String,Any}, objfun, state, population, method::Evolutionary.AbstractOptimizer, options)
			record["x"] = population
		end

		function __solve(prob::OptimizationProblem, opt::Evolutionary.AbstractOptimizer; cb = (args...) -> (false), maxiters = 1000, kwargs...)
			local x, _loss

			function _cb(trace)
				cb_call = cb(decompose_trace(trace).metadata["x"],trace.value...)
				if !(typeof(cb_call) <: Bool)
					error("The callback should return a boolean `halt` for whether to stop the optimization process.")
				end
				cb_call
			end

			if prob.f isa OptimizationFunction
				_loss = function(θ)
					x = prob.f.f(θ, prob.p)
					return x[1]
				end
			else
				_loss = function(θ)
					x = prob.f(θ, prob.p)
					return x[1]
				end
			end

			Evolutionary.optimize(_loss, prob.x, opt, Evolutionary.Options(;iterations = maxiters, callback = _cb, kwargs...))
		end
	end
end


text:
"""
Function that returns Utility for given prices and coordinates.
Functional version. Computes values each time it's called. Requires little RAM and lots of time.
# Arguments
- `mdl::Model`: mutable struct Model.
- `method::String="Function"`: the method for the utils cube. Try "CPU", "GPU","Mmap","Function".
"""

function cube_function(ind_vec::Vector{<:Integer},mdl::Model,additional_args=nothing)

    mdl.HAutility( mdl.HAconstraint( Tuple(ind_vec) , mdl )... )

end


text:
using DashBootstrapComponents, DashHtmlComponents

dropdown = html_div([
    dbc_dropdownmenu(
        [
            dbc_dropdownmenuitem("A button", id="dropdown-button", n_clicks=0),
            dbc_dropdownmenuitem("Internal link", href="/docs/components/dropdown_menu"),
            dbc_dropdownmenuitem("External Link", href="https://github.com"),
            dbc_dropdownmenuitem(
                "External relative",
                href="/docs/components/dropdown_menu",
                external_link=true,
            ),
        ],
        label="Menu",
    ),
    html_p(id="item-clicks", className="mt-3"),
]);

callback!(app, Output("item-clicks", "children"), Input("dropdown-button", "n_clicks")) do n
    return n > 0 ? "Button clicked $n times." : "Button not clicked yet."
end;

max_stars_repo_name: harisbal/dash-bootstrap-components

max_issues_repo_name: harisbal/dash-bootstrap-components

max_forks_repo_name: harisbal/dash-bootstrap-components


text: abstract type Group end


text:
## ExoplanetsSysSim/examples/run_abc.jl
## (c) 2015 Eric B. Ford

include(joinpath(Pkg.dir(),"ExoplanetsSysSim","examples","multiplanet_systems", "model.jl"))
include("abc_setup.jl")

using SysSimABC
using JLD

start_ind = 1
final_ind = 1

for n in start_ind:final_ind
  abc_plan = setup_abc()

  param_names = make_vector_of_active_param_keys(EvalSysSimModel.sim_param_closure)
  println("# Param Names = ", param_names)
  @time output = SysSimABC.run_abc(abc_plan)

  println("")
  println("Test ", n)
  println("")
  println("Mean = ")
  println(reshape(mean(output.theta,2), (1, size(output.theta,1))))
  println("")
  println("Standard deviation = ")
  println(reshape(std(output.theta,2), (1, size(output.theta,1))))
  println("")
  #println(EvalSysSimModel.get_ss_obs())
  println("-----------------------------")
  println("# Param Names = ", param_names)
  save(string("test-",n,"-out.jld"), "output", output, "ss_true", EvalSysSimModel.get_ss_obs())
  sample = SysSimABC.run_abc_largegen(output,EvalSysSimModel.get_ss_obs(),output.accept_log.epsilon[end])
  save(string("test-",n,"-sample.jld"), "output", output, "ss_true", EvalSysSimModel.get_ss_obs(), "sample", sample)
end


text:
using Documenter, OnlineStats, OnlineStatsBase

makedocs(
    format = Documenter.HTML(
        assets = ["assets/style.css", "assets/favicon.ico"],
        sidebar_sitename=false,
        analytics="UA-72795550-5"
    ),
    sitename = "OnlineStats Docs",
    modules = [OnlineStats, OnlineStatsBase],
    authors = "Josh Day",
    clean = true,
    debug = true,
    pages = [
        "index.md",
        "stats_and_models.md",
        "bigdata.md",
        "dataviz.md",
        "collections.md",
        "howfitworks.md",
        "weights.md",
        "api.md",
    ]
)

deploydocs(
    repo   = "github.com/joshday/OnlineStats.jl.git"
)


text:
struct SolverState

    iteration::Integer
    xdist::Float64
    fdist::Float64

end

struct SolverTrace

    trace::Array{SolverState,1}

end

struct SolverResults

    solution_method::Symbol
    initial::Array{Float64,1}
    zero::Array{Float64,1}
    fzero::Array{Float64,1}
    xdist::Float64
    fdist::Float64
    iters::Integer
    trace::SolverTrace

end


text:
# Note that this script can accept some limited command-line arguments, run
# `julia build_tarballs.jl --help` to see a usage message.
using BinaryBuilder, Pkg

name = "KaHyPar"
version = v"1.0.0"

# Collection of sources required to complete build
sources = [
    GitSource("https://github.com/arbenson/kahypar.git", "d64498068ab745a09a94391e746d35853fc3eef3"),
    DirectorySource("./bundled"),
]

# Bash recipe for building across all platforms
script = raw"""
cd $WORKSPACE/srcdir/kahypar/
git submodule update --init --recursive
atomic_patch -p1 ../patches/disable-tests.patch
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=${prefix} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TARGET_TOOLCHAIN} -DCMAKE_BUILD_TYPE=Release
make -j${nproc}
make install
"""

# These are the platforms we will build for by default, unless further
# platforms are passed in on the command line
platforms = [
    Linux(:i686, libc=:glibc),
    Linux(:x86_64, libc=:glibc),
    Linux(:i686, libc=:musl),
    Linux(:x86_64, libc=:musl),
    MacOS(:x86_64),
    FreeBSD(:x86_64),
    Windows(:i686),
]
platforms = expand_cxxstring_abis(platforms)

# The products that we will ensure are always built
products = [
    LibraryProduct("libkahypar", :libkahypar)
]

# Dependencies that must be installed before this package can be built
dependencies = Dependency[
]

# Build the tarballs, and possibly a `build.jl` as well.
build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies; preferred_gcc_version = v"6.1.0")


text:
include("../../testcases.jl")
using PyCall
using DFTK
using Unitful: Å
using UnitfulAtomic

# Note: This is not exactly the minimum-energy structure
a = austrip(1.228Å)
b = austrip(2.12695839Å)
c = austrip(7Å)
lattice = [[a a 0]; [-b b 0]; [0 0 c]]
C = ElementPsp(:C, psp=load_psp("hgh/lda/c-q4"))
atoms = [C => [[0, 0, 1/4], [0, 0, 3/4], [1/3, 2/3, 1/4], [2/3, 1/3, 3/4]]]

model = model_DFT(lattice, atoms, :lda_xc_teter93, temperature=0.01,
                  smearing=Smearing.MethfesselPaxton2())
abinitpseudos = [joinpath(pyimport("abipy.data").__path__[end], "hgh_pseudos/6c.4.hgh")]
DFTK.run_abinit_scf(model, @__DIR__; abinitpseudos=abinitpseudos,
                    Ecut=20, kgrid=[8, 8, 8], n_bands=12, tol=1e-10,
                    iscf=3) # Use Anderson mixing instead of minimization


text:
export κ, κ_norm, μ_norm, kappa, kappa_norm, mu_norm

"""
    κ(H, z, t, cfg)

Computes the condition number of H at (z, t) (with config cfg). See Condition^[1] for details

Proposition 16.10: κ(f,z) := ‖f‖ ‖ Df(z)^† diag(‖ z ‖^{d_i-1}) ‖

[1]: Condition, Bürgisser and Cucker
"""

function κ(H::AbstractHomotopy, z::Vector, t::Float64, cfg=PolynomialHomotopyConfig(H))
    weyl_norm=weylnorm(H)
    f = weyl_norm(t)
    D = jacobian(H,z,t,cfg)
    norm_z = norm(z)

    M = diagm(map(d_i -> norm_z ^ (1-d_i), FP.degree.(H.start)))

    try
        _, s, _ = svd(M*D)
        σ = s[end]

        return real(f * inv(σ))
    catch
        Inf
    end
end

kappa(H::AbstractHomotopy, z::Vector, t::Float64, cfg=PolynomialHomotopyConfig(H))=κ(H, z, t, cfg)

"""
    κ_norm(H, z, t, cfg)

Computes the condition number of H at (z, t) (with config cfg). See Condition^[1] for details

Eq. (16.11): κ_norm(f,z) := ‖f‖ ‖ Df(z)^† diag(√{d_i}‖ z ‖^{d_i-1}) ‖

[1]: Condition, Bürgisser and Cucker
"""

function κ_norm(H::AbstractHomotopy, z::Vector, t::Float64, cfg=PolynomialHomotopyConfig(H))
    weyl_norm=weylnorm(H)
    f = weyl_norm(t)
    D = jacobian(H,z,t,cfg)
    norm_z = norm(z)

    M = diagm(map(d_i -> inv(sqrt(d_i)) * norm_z ^ (1-d_i), FP.degree.(H.start)))

    _, s, _ = svd(M*D)
    σ = s[end]

    real(f * inv(σ))
end

kappa_norm(H::AbstractHomotopy, z::Vector, t::Float64, cfg=PolynomialHomotopyConfig(H))=κ_norm(H, z, t, cfg)

"""
    μ_norm(H, z, t, cfg)

Computes the condition number of H at (z, t) (with config cfg). See Condition^[1] for details

Definition 16.43: μ_norm(f,z) := ‖f‖ ‖ (Df(z)-(T_z))^{-1} diag(√{d_i}‖ z ‖^{d_i-1}) ‖

[1]: Condition, Bürgisser and Cucker
"""

function μ_norm(H::AbstractHomotopy, z::Vector, t::Float64, cfg=PolynomialHomotopyConfig(H))
    if ishomogenized(H) || ishomogenous(H)

        weyl_norm=weylnorm(H)
        f = weyl_norm(t)
        D = jacobian(H,z,t,cfg)
        n=length(z)
        norm_z = norm(z)
        P = qrfact(reshape(z,n,1))
        Q = P[:Q][:,2:end]

        M = diagm(map(d_i -> inv(sqrt(d_i)) * norm_z ^ (1-d_i), FP.degree.(H.start)))

        _, s, _ = svd(M*D*Q)
        σ = last(s)

        real(f * inv(σ))
    else
        κ_norm(H, z, t, cfg)
    end
end

mu_norm(H::AbstractHomotopy, z::Vector, t::Float64, cfg=PolynomialHomotopyConfig(H))=μ_norm(H, z, t, cfg)


text:
# basic test that parsing works correctly

testdir = dirname(@__FILE__)

@test_throws Gumbo.InvalidHTMLException parsehtml("", strict=true)

let
    page = open("$testdir/fixtures/example.html") do example
        read(example, String) |> parsehtml
    end
    @test page.doctype == "html"
    root = page.root
    @test tag(root[1][1]) == :meta
    @test root[2][1][1].text == "A simple test page."
    @test root[2][1][1].parent === root[2][1]
end

# test that nonexistant tags are parsed as their actual name and not "unknown"

let
    page = parsehtml("<weird></weird")
    @test tag(page.root[2][1]) == :weird
end

# test that non-standard tags, with attributes, are parsed correctly

let
    page = Gumbo.parsehtml("<my-element cool></my-element>")
    @test tag(page.root[2][1]) == Symbol("my-element")
    @test Gumbo.attrs(page.root[2][1]) == Dict("cool" => "")
end


text:
using BioformatsLoader
using JavaCall
using Test
using Downloads
using AxisArrays

# Test initialization
@test length(JavaCall.opts) >= 3
@test sum(startswith.(JavaCall.opts, "-Xmx")) == 1
@test BioformatsLoader.set_memory(1025) === nothing
@test sum(startswith.(JavaCall.opts, "-Xmx")) == 1
@test BioformatsLoader.ensure_init() === nothing
@test_logs (:warn, "BioformatsLoader already initialized") BioformatsLoader.init()
@test BioformatsLoader.ensure_init() === nothing
@test endswith(JavaCall.getClassPath(), "bioformats_package.jar")

oxr = OMEXMLReader()
@test !JavaCall.isnull(oxr.reader)
@test !JavaCall.isnull(oxr.meta)

openjpeg_imgs_url = "https://github.com/uclouvain/openjpeg-data/raw/master/input/conformance"

mktempdir() do path
    for file in ("file2.jp2",)
        imgpath = joinpath(path, file)
        Downloads.download(join((openjpeg_imgs_url, file), "/"), imgpath)
        md = metadata(imgpath)
        @test md["SizeC"] == 3
        @test md["Type"] == "uint8"
        img = bf_import(imgpath)
        @test size(img[1])[1:3] == (3, md["SizeY"], md["SizeX"])
    end
end

ome_imgs_url = "https://downloads.openmicroscopy.org/images"

ome_paths =
    Dict(
        "ND2" => [
            "maxime/BF007.nd2",
            "aryeh/MeOh_high_fluo_003.nd2"
        ],
    )

test_slice = (Axis{:T}(1), Axis{:Z}(1), Axis{:C}(1), Axis{:X}(1), Axis{:Y}(:))
for (fmt, paths) in ome_paths
    for p in paths
        url = "$(ome_imgs_url)/$(fmt)/$(p)"
        imgs = bf_import(url)
        @test length(imgs) > 0

        filename = basename(p)

        mktempdir() do path
            imgpath = joinpath(path, filename)
            Downloads.download(url, imgpath)
            for (order, import_order) in [("TZYXC", (:T, :Z, :Y, :X, :C)),
                                          ("XYCZT", (:X, :Y, :C, :Z, :T))]
                img = bf_import(imgpath; order)[1]
                @test img.ImportOrder == import_order
                @test arraydata(img[test_slice...]) == arraydata(imgs[1][test_slice...])
            end
            @test metadata(imgpath) isa Dict{String,Any}
        end
    end
end