From 8bc2bc01f38937abbcfbf13e536ce02d543a7864 Mon Sep 17 00:00:00 2001 From: Simon Sarasova Date: Tue, 13 Aug 2024 13:25:47 +0000 Subject: [PATCH] Implemented neural network prediction for polygenic diseases to replace old method. Added autism and homosexualness to genetic analyses. --- Changelog.md | 1 + Contributors.md | 2 +- documentation/Future-Plans.md | 32 +- gui/helpGui.go | 63 +- gui/viewAnalysisGui_Couple.go | 834 ++++++------- gui/viewAnalysisGui_Person.go | 1080 ++++++++--------- gui/viewGeneticReferencesGui.go | 214 ---- gui/viewProfileGui.go | 962 +++++---------- internal/generate/generate.go | 4 +- .../createCoupleGeneticAnalysis.go | 368 ++---- .../createPersonGeneticAnalysis.go | 265 ++-- .../geneticAnalysis/geneticAnalysis.go | 70 +- .../geneticPrediction/geneticPrediction.go | 262 ++-- .../readGeneticAnalysis.go | 238 +--- .../SampleCoupleAnalysis.messagepack | Bin 15184 -> 14148 bytes .../SamplePerson1Analysis.messagepack | Bin 28842 -> 33840 bytes .../SamplePerson2Analysis.messagepack | Bin 14134 -> 19952 bytes internal/helpers/helpers.go | 38 +- .../calculatedAttributes.go | 16 +- .../myProfileExports/myProfileExports.go | 6 +- .../profiles/profileFormat/profileFormat.go | 6 +- .../profileFormat/profileFormat_test.go | 4 +- .../geneticPredictionModels.go | 34 +- .../geneticPredictionModels_test.go | 20 +- .../AutismModelAccuracy.gob | Bin 0 -> 120256 bytes .../EyeColorModelAccuracy.gob | Bin 53755 -> 59203 bytes .../HeightModelAccuracy.gob | Bin 45555 -> 45559 bytes .../HomosexualnessModelAccuracy.gob | Bin 0 -> 1633 bytes .../LactoseToleranceModelAccuracy.gob | Bin 573 -> 573 bytes .../predictionModels/AutismModel.gob | Bin 0 -> 25480 bytes .../predictionModels/EyeColorModel.gob | Bin 196422 -> 196413 bytes .../predictionModels/HomosexualnessModel.gob | Bin 0 -> 1271 bytes .../attributeLoci/attributeLoci.go | 8 + .../geneticReferences/attributeLoci/autism.go | 605 +++++++++ .../geneticReferences_test.go | 97 +- .../locusMetadata/LocusMetadata.gob | Bin 200405 -> 209801 bytes .../modifyLocusMetadata.go | 3 +- .../polygenicDiseases/autism.go | 51 + .../polygenicDiseases/breastCancer.go | 785 +----------- .../polygenicDiseases/polygenicDiseases.go | 89 +- .../geneticReferences/traits/eyeColor.go | 1 + .../traits/facialStructure.go | 1 + .../geneticReferences/traits/hairColor.go | 1 + .../geneticReferences/traits/hairTexture.go | 1 + resources/geneticReferences/traits/height.go | 37 + .../traits/homosexualness.go | 59 + .../traits/lactoseTolerance.go | 1 + .../geneticReferences/traits/skinColor.go | 1 + resources/geneticReferences/traits/traits.go | 17 +- .../createGeneticModels.go | 353 +++--- 50 files changed, 2716 insertions(+), 3913 deletions(-) create mode 100644 resources/geneticPredictionModels/predictionModelAccuracies/AutismModelAccuracy.gob create mode 100644 resources/geneticPredictionModels/predictionModelAccuracies/HomosexualnessModelAccuracy.gob create mode 100644 resources/geneticPredictionModels/predictionModels/AutismModel.gob create mode 100644 resources/geneticPredictionModels/predictionModels/HomosexualnessModel.gob create mode 100644 resources/geneticReferences/attributeLoci/attributeLoci.go create mode 100644 resources/geneticReferences/attributeLoci/autism.go create mode 100644 resources/geneticReferences/polygenicDiseases/autism.go create mode 100644 resources/geneticReferences/traits/homosexualness.go diff --git a/Changelog.md b/Changelog.md index 7404b78..58988ca 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,7 @@ Small and insignificant changes may not be included in this log. ## Unversioned Changes +* Implemented neural network prediction for polygenic diseases to replace old method. Added autism and homosexualness to genetic analyses. - *Simon Sarasova* * Increased the quantity of attributes that are extracted from the OpenSNP biobank data archive. - *Simon Sarasova* * Added numeric traits to genetic analyses. - *Simon Sarasova* * Improved Documentation.md and Future-Plans.md. - *Simon Sarasova* diff --git a/Contributors.md b/Contributors.md index d72e5f6..4630e50 100644 --- a/Contributors.md +++ b/Contributors.md @@ -9,4 +9,4 @@ Many other people have written code for modules which are imported by Seekia. Th Name | Date Of First Commit | Number Of Commits --- | --- | --- -Simon Sarasova | June 13, 2023 | 277 \ No newline at end of file +Simon Sarasova | June 13, 2023 | 278 \ No newline at end of file diff --git a/documentation/Future-Plans.md b/documentation/Future-Plans.md index 99b56c6..8ec2093 100644 --- a/documentation/Future-Plans.md +++ b/documentation/Future-Plans.md @@ -289,9 +289,9 @@ There could be several analysis methods. These analysis methods will serve as an Providing an open source ancestral analysis method is essential for race aware mate discovery technology to be credibly neutral. There already exist multiple open source ancestral analysis packages. -### Add Custom Type Illnesses +### Add Complex Disease Diagnosis -Many genetic illnesses are not able to be detected using the methods implemented in the `monogenicDiseases` or the `polygenicDiseases` packages. +Many genetic diseases are not able to be detected using the methods implemented in the `monogenicDiseases` or the `polygenicDiseases` packages. Examples include diseases such as Fragile X and Turner's Syndrome. @@ -299,11 +299,7 @@ A new format called `complexDiseases` could be created. Each disease can have a function that takes in a genome map and returns a diagnosis. -Many of these diseases may require additional data from the raw genome files that is not included in the genome map. - -The `ReadRawGenomeFile` function should be able to read this relevant data. - -The GUI would also have an accompanying set of pages to display these Custom illnesses. +The GUI would also have an accompanying set of pages to display complex diseases. ### Add Polygenic Disease Probability Risk @@ -313,23 +309,17 @@ Meaning, we want to tell the user the estimated probability that they will get a Example: Normal risk = 5%, Your risk = 10% -We should be able to calculate this risk. We know the polygenic disease odds ratio of a base pair `(odds of disease with base pair)/(odds of disease with standard (common) base pair)`. We know the average probability of disease for the general population for each age period. We know the probability of each base pair for the general population. - This will be the most useful statistic for users trying to understand their polygenic disease risk. -Knowing that the probability of a particular type of cancer has increased by 10x is very different depending on the probability of getting the cancer. +Knowing that your risk score for a particular type of cancer is 10/10 is much less useful than understanding your probability of getting the cancer. If the general population probability of getting cancer X is 5%, and the user's adjusted risk is 50%, that is a significant increase. However, if the general population risk is 0.1%, and the user's adjusted risk is 1%, then the user does not need to change their behavior or worry much. -### Add Neural Network Genetic Predictions +### Get Genetic Training Data -The current method for predicting polygenic disease risks and traits is not as informative and accurate as using neural nets. +We use neural networks to predict traits and polygenic diseases. We have to train these networks using example training data. This training data is a collection of people's genomes and the trait/polygenic disease information for each person. -Our current model adds and subtracts the likelihood values of various SNPs that are reported to have an effect on polygenic diseases and traits. - -A much better method is to train a neural net to predict traits and polygenic diseases on a large number of genes. There are methods that exist to find the set of genes that have an effect on each trait/disease. For example, height is said to be effected by ~10,000 SNPs. Many GWAS studies exist which report which genes are responsible for certain traits and diseases. These are the genes to feed into the neural net for each trait/disease. These are also the genes that users will share in their profiles. I have already started to try to build this system. See `geneticPrediction.go` for an implementation of trait prediction using neural networks, and `createCoupleGeneticAnalysis.go` for information on how offspring predictions would work. - -This method requires training data, which is largely unavailable for public use. We need fully open training data, not data that requires registration or permission to download. +Good training data is largely unavailable for public use. We need fully open training data, not data that requires registration or permission to download. [OpenSNP.org](https://opensnp.org) is a free genomic data repository. OpenSNP relies on user submitted data, which can be falsified. OpenSNP should add a verification system so data provided by trustworthy people can be prioritized. @@ -339,10 +329,10 @@ Whoever collects the data needs to choose what data to collect from each person. Some examples of data to collect: -* Collecting polygenic disease information would enable prediction of polygenic disease risk. +* Collecting polygenic disease information enables prediction of polygenic disease risk. * Pictures and scans of participants faces would enable a genetic test for facial structure * Personality tests would enable prediction of personality -* Measuring height would enable prediction of height +* Measuring height enables prediction of height These kinds of genetic tests would allow parents to choose what their offspring will look like, their personality, and their intelligence. @@ -356,10 +346,12 @@ All of this is already possible, but will become easier with the proliferation o ### Add more diseases and traits -This task entails entering disease/trait SNP data from SNPedia.com and other sources. The bases have to be flipped if the orientation on SNPedia is minus. This requires flipping G/C and A/T. At least 3 people should check any added disease SNPs to ensure accuracy. +Adding monogenic diseases entails entering disease SNP data from SNPedia.com and other sources. The bases have to be flipped if the orientation on SNPedia is minus. This requires flipping G/C and A/T. At least 3 people should check any added disease SNPs to ensure accuracy. This is a tedious data entry process with negative consequences if mistakes are made. Many users could falsely believe they have monogenic diseases, which could trigger mental health crises. +Adding polygenic diseases/traits requires training data and access to genome wide association studies. Seekia should also have the ability to perform genome wide association studies to find causal genes for traits. + ### Interactive Map Seekia should have an interactive world map. It would be similar to OpenStreetMaps, but with much less detail. It would only need to contain borders of countries and states as lines. It would be able to display latitude/longitude coordinates on the map as points. diff --git a/gui/helpGui.go b/gui/helpGui.go index 369275e..cf0ef11 100644 --- a/gui/helpGui.go +++ b/gui/helpGui.go @@ -569,7 +569,7 @@ func setPolygenicDiseaseLociExplainerPage(window fyne.Window, previousPage func( description1 := getLabelCentered("Each polygenic disease has a set of associated genome loci.") description2 := getLabelCentered("These are locations on the genome that can be tested to determine disease risk.") - description3 := getLabelCentered("The more loci that your genome contains, the more accurate your disease risk score will be.") + description3 := getLabelCentered("The more loci that your genome sequence contains, the more accurate your disease risk score will be.") page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3) @@ -615,65 +615,6 @@ func setOffspringPolygenicDiseaseNumberOfLociTestedExplainerPage(window fyne.Win } -func setPolygenicDiseaseLocusRiskWeightExplainerPage(window fyne.Window, previousPage func()){ - - title := getPageTitleCentered("Help - Locus Risk Weight") - - backButton := getBackButtonCentered(previousPage) - - subtitle := getPageSubtitleCentered("Locus Risk Weight") - - description1 := getLabelCentered("A polygenic disease risk score is calculated by testing many locations on a genome.") - description2 := getLabelCentered("A genome will have a risk weight for each locus.") - description3 := getLabelCentered("A negative weight reduces the risk of the disease.") - description4 := getLabelCentered("A positive weight increases the risk of the disease.") - description5 := getLabelCentered("A 0 weight has no effect on the risk.") - - page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5) - - setPageContent(page, window) -} - -func setOffspringPolygenicDiseaseLocusRiskWeightExplainerPage(window fyne.Window, previousPage func()){ - - title := getPageTitleCentered("Help - Locus Risk Weight") - - backButton := getBackButtonCentered(previousPage) - - subtitle := getPageSubtitleCentered("Offspring Locus Risk Weight") - - description1 := getLabelCentered("A polygenic disease risk score is calculated by testing many locations on a genome.") - description2 := getLabelCentered("A genome will have a risk weight for each locus.") - description3 := getLabelCentered("A negative weight reduces the risk of the disease.") - description4 := getLabelCentered("A positive weight increases the risk of the disease.") - description5 := getLabelCentered("A 0 weight has no effect on the risk.") - description6 := getLabelCentered("An offspring's locus risk weight represents the average risk weight for all 4 possible locus outcomes.") - - page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5, description6) - - setPageContent(page, window) -} - -func setPolygenicDiseaseLocusRiskWeightProbabilityExplainerPage(window fyne.Window, previousPage func()){ - - title := getPageTitleCentered("Help - Risk Weight Probability") - - backButton := getBackButtonCentered(previousPage) - - subtitle := getPageSubtitleCentered("Locus Risk Weight Probability") - - description1 := getLabelCentered("A polygenic disease risk score is calculated by testing many locations on a genome.") - description2 := getLabelCentered("A genome will have a risk weight for each locus.") - description3 := getLabelCentered("A risk weight probability describes the probability of having that risk weight.") - description4 := getLabelCentered("For example, lets suppose a risk weight of 2 has a probability of 5%") - description5 := getLabelCentered("This means that 5% of people will have a risk weight of 2 at this locus.") - - page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5) - - setPageContent(page, window) -} - - func setDiscreteTraitNeuralNetworkPredictionExplainerPage(window fyne.Window, previousPage func()){ title := getPageTitleCentered("Help - Neural Network Prediction") @@ -768,7 +709,7 @@ func setDiscreteTraitRulesExplainerPage(window fyne.Window, previousPage func()) backButton := getBackButtonCentered(previousPage) - subtitle := getPageSubtitleCentered("Trait Rules") + subtitle := getPageSubtitleCentered("Discrete Trait Rules") description1 := getLabelCentered("Person genetic analyses contain discrete trait analyses.") description2 := getLabelCentered("Discrete traits has multiple outcomes, and each outcome has an associated score.") diff --git a/gui/viewAnalysisGui_Couple.go b/gui/viewAnalysisGui_Couple.go index daa2142..2763983 100644 --- a/gui/viewAnalysisGui_Couple.go +++ b/gui/viewAnalysisGui_Couple.go @@ -815,7 +815,6 @@ func setViewCoupleMonogenicDiseaseVariantsPage(window fyne.Window, person1Name s } - // This function provides a page to view the details of a specific variant from a genetic analysis // It will show the variant details for all of the couple's genome pairs func setViewCoupleGeneticAnalysisMonogenicDiseaseVariantDetailsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, variantIdentifier [3]byte, previousPage func()){ @@ -994,59 +993,115 @@ func setViewCoupleGeneticAnalysisPolygenicDiseasesPage(window fyne.Window, perso pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier, secondGenomePairExists, _, _, _, _, _, _, _, _, err := readGeneticAnalysis.GetMetadataFromCoupleGeneticAnalysis(coupleAnalysisObject) if (err != nil){ return nil, err } + mainGenomePairIdentifier := helpers.JoinTwo16ByteArrays(pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier) + diseaseNameLabel := getItalicLabelCentered("Disease Name") offspringRiskScoreLabel := getItalicLabelCentered("Offspring Risk Score") + confidenceRangeLabel := getItalicLabelCentered("Confidence Range") + conflictExistsLabel := getItalicLabelCentered("Conflict Exists?") - emptyLabel := widget.NewLabel("") + emptyLabel4 := widget.NewLabel("") diseaseNameColumn := container.NewVBox(diseaseNameLabel, widget.NewSeparator()) offspringRiskScoreColumn := container.NewVBox(offspringRiskScoreLabel, widget.NewSeparator()) + confidenceRangeColumn := container.NewVBox(confidenceRangeLabel, widget.NewSeparator()) conflictExistsColumn := container.NewVBox(conflictExistsLabel, widget.NewSeparator()) - viewButtonsColumn := container.NewVBox(emptyLabel, widget.NewSeparator()) + viewButtonsColumn := container.NewVBox(emptyLabel4, widget.NewSeparator()) - diseaseNamesList, err := polygenicDiseases.GetPolygenicDiseaseNamesList() + diseaseObjectsList, err := polygenicDiseases.GetPolygenicDiseaseObjectsList() if (err != nil) { return nil, err } - for _, diseaseName := range diseaseNamesList{ + for _, diseaseObject := range diseaseObjectsList{ - mainGenomePairIdentifier := helpers.JoinTwo16ByteArrays(pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier) + diseaseName := diseaseObject.DiseaseName - offspringRiskScoreKnown, _, offspringRiskScoreFormatted, _, _, conflictExists, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, mainGenomePairIdentifier) + neuralNetworkExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(diseaseName) + if (neuralNetworkExists == false){ + // We cannot analyze this disease + continue + } + + diseaseNameText := getBoldLabelCentered(diseaseName) + + analysisExists, offspringRiskScore, predictionConfidenceRangesMap, _, _, _, conflictExists, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, mainGenomePairIdentifier) if (err != nil) { return nil, err } - getRiskScoreLabelText := func()string{ + getRiskScoreLabel := func()fyne.Widget{ - if (offspringRiskScoreKnown == false){ - result := translate("Unknown") + if (analysisExists == false){ + result := widget.NewLabel(translate("Unknown")) return result } - return offspringRiskScoreFormatted + offspringRiskScoreString := helpers.ConvertIntToString(offspringRiskScore) + offspringRiskScoreFormatted := offspringRiskScoreString + "/10" + + riskScoreLabel := getBoldLabel(offspringRiskScoreFormatted) + + return riskScoreLabel } - offspringRiskScoreLabelText := getRiskScoreLabelText() + riskScoreLabel := getRiskScoreLabel() - diseaseNameText := getBoldLabelCentered(diseaseName) - diseaseNameColumn.Add(diseaseNameText) + riskScoreLabelCentered := getWidgetCentered(riskScoreLabel) - offspringRiskScoreText := getBoldLabelCentered(offspringRiskScoreLabelText) - offspringRiskScoreColumn.Add(offspringRiskScoreText) + getConfidenceRangeLabel := func()(fyne.Widget, error){ + + if (analysisExists == false){ + unknownLabel := widget.NewLabel("Unknown") + return unknownLabel, nil + } + + // This is a list of the percentage accuracies in the map + // For example: 80% == The distance from the prediction you must travel for 80% of the predictions to be + // accurate within that range + confidenceRangePercentagesList := helpers.GetListOfMapKeys(predictionConfidenceRangesMap) + + // We sort the list so the percentage is always the same upon refreshing the page + slices.Sort(confidenceRangePercentagesList) + + closestToEightyPercentage, err := helpers.GetClosestIntInList(confidenceRangePercentagesList, 80) + if (err != nil) { return nil, err } + + closestToEightyPercentageConfidenceDistance, exists := predictionConfidenceRangesMap[closestToEightyPercentage] + if (exists == false){ + return nil, errors.New("GetListOfMapKeys returning list of elements which contains element which is not in the map.") + } + + closestConfidenceDistanceString := helpers.ConvertFloat64ToStringRounded(closestToEightyPercentageConfidenceDistance, 2) + + closestToEightyPercentageString := helpers.ConvertIntToString(closestToEightyPercentage) + + confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)" + + confidenceRangeLabel := getBoldLabel(confidenceRangeLabelValueFormatted) + + return confidenceRangeLabel, nil + } + + confidenceRangeLabel, err := getConfidenceRangeLabel() + if (err != nil) { return nil, err } conflictExistsString := helpers.ConvertBoolToYesOrNoString(conflictExists) conflictExistsLabel := getBoldLabelCentered(conflictExistsString) - conflictExistsColumn.Add(conflictExistsLabel) viewDetailsButton := getWidgetCentered(widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ setViewCoupleGeneticAnalysisPolygenicDiseaseDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, currentPage) })) + + diseaseNameColumn.Add(diseaseNameText) + offspringRiskScoreColumn.Add(riskScoreLabelCentered) + confidenceRangeColumn.Add(confidenceRangeLabel) + conflictExistsColumn.Add(conflictExistsLabel) viewButtonsColumn.Add(viewDetailsButton) - + diseaseNameColumn.Add(widget.NewSeparator()) offspringRiskScoreColumn.Add(widget.NewSeparator()) + confidenceRangeColumn.Add(widget.NewSeparator()) conflictExistsColumn.Add(widget.NewSeparator()) viewButtonsColumn.Add(widget.NewSeparator()) } @@ -1055,8 +1110,14 @@ func setViewCoupleGeneticAnalysisPolygenicDiseasesPage(window fyne.Window, perso setOffspringPolygenicDiseaseRiskScoreExplainerPage(window, currentPage) }) offspringRiskScoreColumn.Add(offspringRiskScoreHelpButton) - - diseasesGrid := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, offspringRiskScoreColumn) + + confidenceRangeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ + //TODO + showUnderConstructionDialog(window) + }) + confidenceRangeColumn.Add(confidenceRangeHelpButton) + + diseasesGrid := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, offspringRiskScoreColumn, confidenceRangeColumn) if (secondGenomePairExists == true){ @@ -1089,10 +1150,25 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window, currentPage := func(){setViewCoupleGeneticAnalysisPolygenicDiseaseDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, previousPage)} + neuralNetworkExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(diseaseName) + if (neuralNetworkExists == false){ + // We cannot analyze this disease + setErrorEncounteredPage(window, errors.New("setViewCoupleGeneticAnalysisPolygenicDiseaseDetailsPage called non-analyzable trait: " + diseaseName), previousPage) + return + } + + diseaseObject, err := polygenicDiseases.GetPolygenicDiseaseObject(diseaseName) + if (err != nil){ + setErrorEncounteredPage(window, err, previousPage) + return + } + + diseaseLociList := diseaseObject.LociList + title := getPageTitleCentered("Viewing Couple Analysis - " + diseaseName) backButton := getBackButtonCentered(previousPage) - + pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier, secondGenomePairExists, pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier, _, _, _, _, _, _, err := readGeneticAnalysis.GetMetadataFromCoupleGeneticAnalysis(coupleAnalysisObject) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) @@ -1127,59 +1203,121 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window, emptyLabel1 := widget.NewLabel("") emptyLabel2 := widget.NewLabel("") - offspringRiskScoreLabel := getItalicLabelCentered("Offspring Risk Score") - emptyLabel3 := widget.NewLabel("") emptyLabel4 := widget.NewLabel("") - emptyLabel5 := widget.NewLabel("") - viewGenomePairButtonsColumn := container.NewVBox(emptyLabel1, widget.NewSeparator()) - pairNameColumn := container.NewVBox(emptyLabel2, widget.NewSeparator()) - offspringRiskScoreColumn := container.NewVBox(offspringRiskScoreLabel, widget.NewSeparator()) - viewSampleOffspringsChartButtonsColumn := container.NewVBox(emptyLabel3, widget.NewSeparator()) - viewLifetimeRiskButtonsColumn := container.NewVBox(emptyLabel4, widget.NewSeparator()) - viewOffspringLociButtonsColumn := container.NewVBox(emptyLabel5, widget.NewSeparator()) + offspringLabel := getItalicLabelCentered("Offspring") + riskScoreLabel := getItalicLabelCentered("Risk Score") + + emptyLabel5 := widget.NewLabel("") + confidenceRangeLabel := getItalicLabelCentered("Confidence Range") + + quantityOfLabel := getItalicLabelCentered("Quantity Of") + lociKnownLabel := getItalicLabelCentered("Loci Known") + + emptyLabel6 := widget.NewLabel("") + emptyLabel7 := widget.NewLabel("") + + emptyLabel8 := widget.NewLabel("") + emptyLabel9 := widget.NewLabel("") + + emptyLabel10 := widget.NewLabel("") + emptyLabel11 := widget.NewLabel("") + + viewGenomePairButtonsColumn := container.NewVBox(emptyLabel1, emptyLabel2, widget.NewSeparator()) + pairNameColumn := container.NewVBox(emptyLabel3, emptyLabel4, widget.NewSeparator()) + offspringRiskScoreColumn := container.NewVBox(offspringLabel, riskScoreLabel, widget.NewSeparator()) + confidenceRangeColumn := container.NewVBox(emptyLabel5, confidenceRangeLabel, widget.NewSeparator()) + quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel, lociKnownLabel, widget.NewSeparator()) + viewSampleOffspringsChartButtonsColumn := container.NewVBox(emptyLabel6, emptyLabel7, widget.NewSeparator()) + viewLifetimeRiskButtonsColumn := container.NewVBox(emptyLabel8, emptyLabel9, widget.NewSeparator()) + viewDetailsButtonsColumn := container.NewVBox(emptyLabel10, emptyLabel11, widget.NewSeparator()) addGenomePairRow := func(genomePairName string, person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{ + genomePairNameLabel := getBoldLabelCentered(genomePairName) + genomePairIdentifier := helpers.JoinTwo16ByteArrays(person1GenomeIdentifier, person2GenomeIdentifier) - offspringRiskScoreKnown, _, offspringRiskScoreFormatted, sampleOffspringRiskScoresList, numberOfLociTested, _, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, genomePairIdentifier) + analysisExists, offspringRiskScore, predictionConfidenceRangesMap, quantityOfLociKnown, _, sampleOffspringRiskScoresList, _, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, genomePairIdentifier) if (err != nil) { return err } - getRiskScoreLabelText := func()string{ + getRiskScoreLabel := func()fyne.Widget{ - if (offspringRiskScoreKnown == false){ - result := translate("Unknown") + if (analysisExists == false){ + result := widget.NewLabel(translate("Unknown")) return result } - return offspringRiskScoreFormatted + offspringRiskScoreString := helpers.ConvertIntToString(offspringRiskScore) + offspringRiskScoreFormatted := offspringRiskScoreString + "/10" + + offspringRiskScoreLabel := getBoldLabel(offspringRiskScoreFormatted) + + return offspringRiskScoreLabel } - riskScoreLabelText := getRiskScoreLabelText() + riskScoreLabel := getRiskScoreLabel() - genomePairNameLabel := getBoldLabelCentered(genomePairName) + riskScoreLabelCentered := getWidgetCentered(riskScoreLabel) - offspringRiskScoreLabel := getBoldLabelCentered(riskScoreLabelText) + getConfidenceRangeLabel := func()(fyne.Widget, error){ + + if (analysisExists == false){ + unknownLabel := widget.NewLabel("Unknown") + return unknownLabel, nil + } + + // This is a list of the percentage accuracies in the map + // For example: 80% == The distance from the prediction you must travel for 80% of the predictions to be + // accurate within that range + confidenceRangePercentagesList := helpers.GetListOfMapKeys(predictionConfidenceRangesMap) + + // We sort the list so the percentage is always the same upon refreshing the page + slices.Sort(confidenceRangePercentagesList) + + closestToEightyPercentage, err := helpers.GetClosestIntInList(confidenceRangePercentagesList, 80) + if (err != nil) { return nil, err } + + closestToEightyPercentageConfidenceDistance, exists := predictionConfidenceRangesMap[closestToEightyPercentage] + if (exists == false){ + return nil, errors.New("GetListOfMapKeys returning list of elements which contains element which is not in the map.") + } + + closestConfidenceDistanceString := helpers.ConvertFloat64ToStringRounded(closestToEightyPercentageConfidenceDistance, 2) + + closestToEightyPercentageString := helpers.ConvertIntToString(closestToEightyPercentage) + + confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)" + + confidenceRangeLabel := getBoldLabel(confidenceRangeLabelValueFormatted) + + return confidenceRangeLabel, nil + } + + confidenceRangeLabel, err := getConfidenceRangeLabel() + if (err != nil) { return err } + + totalQuantityOfLoci := len(diseaseLociList) + + quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown) + totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci) + + quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString + + quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted) viewGenomePairButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, currentPage) }) viewSampleOffspringsChartButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ - setViewPolygenicDiseaseSampleOffspringRiskScoresChart(window, diseaseName, sampleOffspringRiskScoresList, numberOfLociTested, currentPage) + setViewPolygenicDiseaseSampleOffspringRiskScoresChart(window, diseaseName, sampleOffspringRiskScoresList, quantityOfLociKnown, currentPage) }) viewOffspringLifetimeRiskButton := widget.NewButtonWithIcon("", theme.HistoryIcon(), func(){ - diseaseObject, err := polygenicDiseases.GetPolygenicDiseaseObject(diseaseName) - if (err != nil){ - setErrorEncounteredPage(window, err, currentPage) - return - } - getPageMaleOrFemale := func()string{ //TODO: Get user sex from myLocalProfiles @@ -1197,23 +1335,28 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window, setViewPersonPolygenicDiseaseLifetimeProbabilitiesPage(window, diseaseName, genomePairName, pageMaleOrFemale, currentPage) }) - viewOffspringLociButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ - setViewCouplePolygenicDiseaseLociPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, currentPage) + viewOffspringDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ + //TODO + showUnderConstructionDialog(window) }) viewGenomePairButtonsColumn.Add(viewGenomePairButton) pairNameColumn.Add(genomePairNameLabel) - offspringRiskScoreColumn.Add(offspringRiskScoreLabel) + offspringRiskScoreColumn.Add(riskScoreLabelCentered) + confidenceRangeColumn.Add(confidenceRangeLabel) + quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel) viewSampleOffspringsChartButtonsColumn.Add(viewSampleOffspringsChartButton) viewLifetimeRiskButtonsColumn.Add(viewOffspringLifetimeRiskButton) - viewOffspringLociButtonsColumn.Add(viewOffspringLociButton) + viewDetailsButtonsColumn.Add(viewOffspringDetailsButton) viewGenomePairButtonsColumn.Add(widget.NewSeparator()) pairNameColumn.Add(widget.NewSeparator()) offspringRiskScoreColumn.Add(widget.NewSeparator()) + confidenceRangeColumn.Add(widget.NewSeparator()) + quantityOfLociKnownColumn.Add(widget.NewSeparator()) viewSampleOffspringsChartButtonsColumn.Add(widget.NewSeparator()) viewLifetimeRiskButtonsColumn.Add(widget.NewSeparator()) - viewOffspringLociButtonsColumn.Add(widget.NewSeparator()) + viewDetailsButtonsColumn.Add(widget.NewSeparator()) return nil } @@ -1238,14 +1381,27 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window, offspringRiskScoreColumn.Add(offspringRiskScoreHelpButton) - genomesContainer := container.NewHBox(layout.NewSpacer(), viewGenomePairButtonsColumn, pairNameColumn, offspringRiskScoreColumn, viewSampleOffspringsChartButtonsColumn, viewLifetimeRiskButtonsColumn, viewOffspringLociButtonsColumn, layout.NewSpacer()) + confidenceRangeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ + showUnderConstructionDialog(window) + //TODO + }) + + confidenceRangeColumn.Add(confidenceRangeHelpButton) + + offspringQuantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ + + setOffspringPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage) + }) + + quantityOfLociKnownColumn.Add(offspringQuantityOfLociKnownHelpButton) + + genomesContainer := container.NewHBox(layout.NewSpacer(), viewGenomePairButtonsColumn, pairNameColumn, offspringRiskScoreColumn, confidenceRangeColumn, quantityOfLociKnownColumn, viewSampleOffspringsChartButtonsColumn, viewLifetimeRiskButtonsColumn, viewDetailsButtonsColumn, layout.NewSpacer()) page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), genomesContainer) - + setPageContent(page, window) } - func setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, genomePairIdentifier [32]byte, genomePairName string, previousPage func()){ currentPage := func(){setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, previousPage)} @@ -1256,6 +1412,14 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window fy description := getLabelCentered("Below is the disease information for both genomes in the genome pair.") + diseaseObject, err := polygenicDiseases.GetPolygenicDiseaseObject(diseaseName) + if (err != nil){ + setErrorEncounteredPage(window, err, previousPage) + return + } + + diseaseLociList := diseaseObject.LociList + diseaseNameLabel := widget.NewLabel("Disease:") diseaseNameText := getBoldLabel(diseaseName) diseaseNameInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ @@ -1279,7 +1443,7 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window fy emptyLabelC := widget.NewLabel("") riskScoreLabel := getItalicLabelCentered("Risk Score") - numberOfLabel := getItalicLabelCentered("Number Of") + quantityOfLabel := getItalicLabelCentered("Quantity Of") lociTestedLabel := getItalicLabelCentered("Loci Tested") emptyLabelD := widget.NewLabel("") @@ -1288,7 +1452,7 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window fy personNameColumn := container.NewVBox(emptyLabelA, personNameLabel, widget.NewSeparator()) genomeNameColumn := container.NewVBox(emptyLabelB, genomeNameLabel, widget.NewSeparator()) riskScoreColumn := container.NewVBox(emptyLabelC, riskScoreLabel, widget.NewSeparator()) - numberOfLociTestedColumn := container.NewVBox(numberOfLabel, lociTestedLabel, widget.NewSeparator()) + quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel, lociTestedLabel, widget.NewSeparator()) viewGenomeButtonsColumn := container.NewVBox(emptyLabelD, emptyLabelE, widget.NewSeparator()) addGenomeRow := func(isPerson1 bool, personName string, inputGenomeIdentifier [16]byte)error{ @@ -1331,38 +1495,52 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window fy genomeNameLabel := getBoldLabelCentered(genomeName) - personRiskScoreKnown, _, personRiskScoreFormatted, numberOfLociTested, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, personAnalysisGenomeIdentifier) + analysisExists, personRiskScore, _, quantityOfLociKnown, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, personAnalysisGenomeIdentifier) if (err != nil) { return err } - getPersonRiskScoreLabelText := func()string{ - if (personRiskScoreKnown == false){ - result := translate("Unknown") + getPersonRiskScoreLabel := func()fyne.Widget{ + + if (analysisExists == false){ + + result := widget.NewLabel(translate("Unknown")) return result } - return personRiskScoreFormatted + + personRiskScoreString := helpers.ConvertIntToString(personRiskScore) + personRiskScoreFormatted := personRiskScoreString + "/10" + personRiskScoreLabel := getBoldLabel(personRiskScoreFormatted) + + return personRiskScoreLabel } - personRiskScoreLabelText := getPersonRiskScoreLabelText() + personRiskScoreLabel := getPersonRiskScoreLabel() - genomeRiskScoreLabel := getBoldLabelCentered(personRiskScoreLabelText) + genomeRiskScoreLabelCentered := getWidgetCentered(personRiskScoreLabel) - numberOfLociTestedString := helpers.ConvertIntToString(numberOfLociTested) - numberOfLociTestedText := getBoldLabelCentered(numberOfLociTestedString) + totalQuantityOfLoci := len(diseaseLociList) + + quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown) + totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci) + + quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString + + quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted) viewGenomeButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ - setViewPersonGenomePolygenicDiseaseLociPage(window, personAnalysisObject, diseaseName, personAnalysisGenomeIdentifier, genomeName, currentPage) + //TODO + showUnderConstructionDialog(window) }) personNameColumn.Add(personNameLabel) genomeNameColumn.Add(genomeNameLabel) - riskScoreColumn.Add(genomeRiskScoreLabel) - numberOfLociTestedColumn.Add(numberOfLociTestedText) + riskScoreColumn.Add(genomeRiskScoreLabelCentered) + quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel) viewGenomeButtonsColumn.Add(viewGenomeButton) personNameColumn.Add(widget.NewSeparator()) genomeNameColumn.Add(widget.NewSeparator()) riskScoreColumn.Add(widget.NewSeparator()) - numberOfLociTestedColumn.Add(widget.NewSeparator()) + quantityOfLociKnownColumn.Add(widget.NewSeparator()) viewGenomeButtonsColumn.Add(widget.NewSeparator()) return nil @@ -1370,7 +1548,7 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window fy person1GenomeIdentifier, person2GenomeIdentifier := helpers.Split32ByteArrayInHalf(genomePairIdentifier) - err := addGenomeRow(true, person1Name, person1GenomeIdentifier) + err = addGenomeRow(true, person1Name, person1GenomeIdentifier) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return @@ -1387,355 +1565,18 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window fy riskScoreColumn.Add(riskScoreHelpButton) - numberOfLociTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ + quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage) }) - numberOfLociTestedColumn.Add(numberOfLociTestedHelpButton) + quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton) - genomesGrid := container.NewHBox(layout.NewSpacer(), personNameColumn, genomeNameColumn, riskScoreColumn, numberOfLociTestedColumn, viewGenomeButtonsColumn, layout.NewSpacer()) + genomesGrid := container.NewHBox(layout.NewSpacer(), personNameColumn, genomeNameColumn, riskScoreColumn, quantityOfLociKnownColumn, viewGenomeButtonsColumn, layout.NewSpacer()) page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), genomePairRow, widget.NewSeparator(), genomesGrid) setPageContent(page, window) } - -// This function provides a page to view the couple offspring locus probabilities for a particular genome pair -func setViewCouplePolygenicDiseaseLociPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, genomePairIdentifier [32]byte, genomePairName string, previousPage func()){ - - setLoadingScreen(window, "Loading Polygenic Disease Loci", "Loading disease loci...") - - currentPage := func(){setViewCouplePolygenicDiseaseLociPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, previousPage)} - - title := getPageTitleCentered("View Offspring Disease Loci - " + diseaseName) - - backButton := getBackButtonCentered(previousPage) - - description1 := widget.NewLabel("Below are the disease loci probabilities for offspring from this genome pair.") - diseaseLociHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setPolygenicDiseaseLociExplainerPage(window, currentPage) - }) - description1Row := container.NewHBox(layout.NewSpacer(), description1, diseaseLociHelpButton, layout.NewSpacer()) - - genomePairLabel := widget.NewLabel("Genome Pair:") - genomePairNameLabel := getBoldLabel(genomePairName) - viewGenomePairInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ - setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, currentPage) - }) - - genomePairRow := container.NewHBox(layout.NewSpacer(), genomePairLabel, genomePairNameLabel, viewGenomePairInfoButton, layout.NewSpacer()) - - _, _, _, _, numberOfLociTested, _, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, genomePairIdentifier) - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return - } - - numberOfLociTestedString := helpers.ConvertIntToString(numberOfLociTested) - - diseaseLociMap, err := polygenicDiseases.GetPolygenicDiseaseLociMap(diseaseName) - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return - } - - totalNumberOfLoci := len(diseaseLociMap) - totalNumberOfLociString := helpers.ConvertIntToString(totalNumberOfLoci) - - lociTestedLabel := widget.NewLabel("Loci Tested:") - lociTestedText := getBoldLabel(numberOfLociTestedString + "/" + totalNumberOfLociString) - lociTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setOffspringPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage) - }) - - lociTestedRow := container.NewHBox(layout.NewSpacer(), lociTestedLabel, lociTestedText, lociTestedHelpButton, layout.NewSpacer()) - - getLociGrid := func()(*fyne.Container, error){ - - locusNameLabel := getItalicLabelCentered("Locus Name") - - offspringRiskWeightLabel := getItalicLabelCentered("Offspring Risk Weight") - - offspringOddsRatioLabel := getItalicLabelCentered("Offspring Odds Ratio") - - emptyLabel := widget.NewLabel("") - - locusNameColumn := container.NewVBox(locusNameLabel, widget.NewSeparator()) - offspringRiskWeightColumn := container.NewVBox(offspringRiskWeightLabel, widget.NewSeparator()) - offspringOddsRatioColumn := container.NewVBox(offspringOddsRatioLabel, widget.NewSeparator()) - lociInfoButtonsColumn := container.NewVBox(emptyLabel, widget.NewSeparator()) - - addLocusRow := func(locusIdentifierHex string)error{ - - locusObject, exists := diseaseLociMap[locusIdentifierHex] - if (exists == false) { - return errors.New("Cannot add locus row: Locus not found in diseaseLociMap: " + locusIdentifierHex) - } - - locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex) - if (err != nil) { return err } - - locusRSID := locusObject.LocusRSID - locusRSIDString := helpers.ConvertInt64ToString(locusRSID) - locusName := "rs" + locusRSIDString - - offspringRiskWeightKnown, offspringRiskWeight, offspringOddsRatioKnown, _, offspringOddsRatioFormatted, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseLocusInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, locusIdentifier, genomePairIdentifier) - if (err != nil) { return err } - - getOffspringRiskWeightText := func()string{ - - if (offspringRiskWeightKnown == false){ - - unknownTextTranslated := translate("Unknown") - return unknownTextTranslated - } - - offspringRiskWeightString := helpers.ConvertIntToString(offspringRiskWeight) - - return offspringRiskWeightString - } - - offspringRiskWeightText := getOffspringRiskWeightText() - - getOffspringOddsRatioText := func()string{ - - if (offspringOddsRatioKnown == false){ - - unknownTextTranslated := translate("Unknown") - return unknownTextTranslated - } - - return offspringOddsRatioFormatted - } - - offspringOddsRatioText := getOffspringOddsRatioText() - - locusNameLabel := getBoldLabelCentered(locusName) - - locusRiskWeightLabel := getBoldLabelCentered(offspringRiskWeightText) - locusOddsRatioLabel := getBoldLabelCentered(offspringOddsRatioText) - - viewLocusDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ - setViewCoupleGeneticAnalysisPolygenicDiseaseLocusDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, locusIdentifier, currentPage) - }) - - locusNameColumn.Add(locusNameLabel) - offspringRiskWeightColumn.Add(locusRiskWeightLabel) - offspringOddsRatioColumn.Add(locusOddsRatioLabel) - lociInfoButtonsColumn.Add(viewLocusDetailsButton) - - locusNameColumn.Add(widget.NewSeparator()) - offspringRiskWeightColumn.Add(widget.NewSeparator()) - offspringOddsRatioColumn.Add(widget.NewSeparator()) - lociInfoButtonsColumn.Add(widget.NewSeparator()) - - return nil - } - - lociWithKnownRiskWeightList := make([]string, 0) - lociWithUnknownRiskWeightList := make([]string, 0) - - for locusIdentifierHex, _ := range diseaseLociMap{ - - locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex) - if (err != nil) { return nil, err } - - offspringRiskWeightKnown, _, _, _, _, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseLocusInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, locusIdentifier, genomePairIdentifier) - if (err != nil) { return nil, err } - - if (offspringRiskWeightKnown == true){ - lociWithKnownRiskWeightList = append(lociWithKnownRiskWeightList, locusIdentifierHex) - } else { - lociWithUnknownRiskWeightList = append(lociWithUnknownRiskWeightList, locusIdentifierHex) - } - } - - // We sort the lists so loci show up in the same order whenever page is refreshed - - helpers.SortStringListToUnicodeOrder(lociWithKnownRiskWeightList) - helpers.SortStringListToUnicodeOrder(lociWithUnknownRiskWeightList) - - for _, locusIdentifier := range lociWithKnownRiskWeightList{ - - err = addLocusRow(locusIdentifier) - if (err != nil) { return nil, err } - } - - for _, locusIdentifier := range lociWithUnknownRiskWeightList{ - - err = addLocusRow(locusIdentifier) - if (err != nil) { return nil, err } - } - - offspringRiskWeightHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setOffspringPolygenicDiseaseLocusRiskWeightExplainerPage(window, currentPage) - }) - offspringRiskWeightColumn.Add(offspringRiskWeightHelpButton) - - offspringOddsRatioHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - //TODO - showUnderConstructionDialog(window) - }) - offspringOddsRatioColumn.Add(offspringOddsRatioHelpButton) - - lociGrid := container.NewHBox(layout.NewSpacer(), locusNameColumn, offspringRiskWeightColumn, offspringOddsRatioColumn, lociInfoButtonsColumn, layout.NewSpacer()) - - return lociGrid, nil - } - - lociGrid, err := getLociGrid() - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return - } - - page := container.NewVBox(title, backButton, widget.NewSeparator(), description1Row, widget.NewSeparator(), genomePairRow, widget.NewSeparator(), lociTestedRow, widget.NewSeparator(), lociGrid) - - setPageContent(page, window) -} - - -// This function provides a page to view the details of a specific locus from a genetic analysis -// It will show the locus details for all of the couple's genome pairs -func setViewCoupleGeneticAnalysisPolygenicDiseaseLocusDetailsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, locusIdentifier [3]byte, previousPage func()){ - - currentPage := func(){setViewCoupleGeneticAnalysisPolygenicDiseaseLocusDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, locusIdentifier, previousPage)} - - title := getPageTitleCentered("Disease Locus Details - " + diseaseName) - - backButton := getBackButtonCentered(previousPage) - - locusIdentifierHex := encoding.EncodeBytesToHexString(locusIdentifier[:]) - - locusObject, err := polygenicDiseases.GetPolygenicDiseaseLocusObject(diseaseName, locusIdentifierHex) - if (err != nil) { - setErrorEncounteredPage(window, err, previousPage) - return - } - - locusRSID := locusObject.LocusRSID - locusRSIDString := helpers.ConvertInt64ToString(locusRSID) - locusName := "rs" + locusRSIDString - - description := getLabelCentered("Below is the locus analysis for the couple.") - - locusNameLabel := widget.NewLabel("Locus Name:") - locusNameText := getBoldLabel(locusName) - locusInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ - setViewPolygenicDiseaseLocusDetailsPage(window, diseaseName, locusIdentifierHex, currentPage) - }) - locusNameRow := container.NewHBox(layout.NewSpacer(), locusNameLabel, locusNameText, locusInfoButton, layout.NewSpacer()) - - getGenomePairsLocusInfoGrid := func()(*fyne.Container, error){ - - emptyLabel := widget.NewLabel("") - - genomePairLabel := getItalicLabelCentered("Genome Pair") - - offspringRiskWeightLabel := getItalicLabelCentered("Offspring Risk Weight") - - offspringOddsRatioLabel := getItalicLabelCentered("Offspring Odds Ratio") - - viewGenomePairInfoButtonsColumn := container.NewVBox(emptyLabel, widget.NewSeparator()) - genomePairNameColumn := container.NewVBox(genomePairLabel, widget.NewSeparator()) - offspringRiskWeightColumn := container.NewVBox(offspringRiskWeightLabel, widget.NewSeparator()) - offspringOddsRatioColumn := container.NewVBox(offspringOddsRatioLabel, widget.NewSeparator()) - - addGenomePairRow := func(genomePairName string, genomePairIdentifier [32]byte)error{ - - offspringRiskWeightKnown, offspringRiskWeight, offspringOddsRatioKnown, _, offspringOddsRatioFormatted, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseLocusInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, locusIdentifier, genomePairIdentifier) - if (err != nil) { return err } - - getOffspringRiskWeightText := func()string{ - - if (offspringRiskWeightKnown == false){ - result := translate("Unknown") - return result - } - - offspringRiskWeightString := helpers.ConvertIntToString(offspringRiskWeight) - - return offspringRiskWeightString - } - - offspringRiskWeightText := getOffspringRiskWeightText() - - getOffspringOddsRatioText := func()string{ - if (offspringOddsRatioKnown == false){ - result := translate("Unknown") - return result - } - return offspringOddsRatioFormatted - } - - offspringOddsRatioText := getOffspringOddsRatioText() - - viewGenomePairInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ - setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, currentPage) - }) - - genomePairNameLabel := getBoldLabelCentered(genomePairName) - - offspringRiskWeightLabel := getBoldLabelCentered(offspringRiskWeightText) - offspringOddsRatioLabel := getBoldLabelCentered(offspringOddsRatioText) - - viewGenomePairInfoButtonsColumn.Add(viewGenomePairInfoButton) - genomePairNameColumn.Add(genomePairNameLabel) - offspringRiskWeightColumn.Add(offspringRiskWeightLabel) - offspringOddsRatioColumn.Add(offspringOddsRatioLabel) - - viewGenomePairInfoButtonsColumn.Add(widget.NewSeparator()) - genomePairNameColumn.Add(widget.NewSeparator()) - offspringRiskWeightColumn.Add(widget.NewSeparator()) - offspringOddsRatioColumn.Add(widget.NewSeparator()) - - return nil - } - - pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier, secondGenomePairExists, pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier, _, _, _, _, _, _, err := readGeneticAnalysis.GetMetadataFromCoupleGeneticAnalysis(coupleAnalysisObject) - if (err != nil){ return nil, err } - - genomePair1Identifier := helpers.JoinTwo16ByteArrays(pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier) - - err = addGenomePairRow("Pair 1", genomePair1Identifier) - if (err != nil) { return nil, err } - - if (secondGenomePairExists == true){ - - genomePair2Identifier := helpers.JoinTwo16ByteArrays(pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier) - - err := addGenomePairRow("Pair 2", genomePair2Identifier) - if (err != nil) { return nil, err } - } - - offspringRiskWeightHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setOffspringPolygenicDiseaseLocusRiskWeightExplainerPage(window, currentPage) - }) - - offspringOddsRatioHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - //TODO - showUnderConstructionDialog(window) - }) - - offspringRiskWeightColumn.Add(offspringRiskWeightHelpButton) - offspringOddsRatioColumn.Add(offspringOddsRatioHelpButton) - - genomesContainer := container.NewHBox(layout.NewSpacer(), viewGenomePairInfoButtonsColumn, genomePairNameColumn, offspringRiskWeightColumn, offspringOddsRatioColumn, layout.NewSpacer()) - - return genomesContainer, nil - } - - genomePairsLocusInfoGrid, err := getGenomePairsLocusInfoGrid() - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return - } - - page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), locusNameRow, widget.NewSeparator(), genomePairsLocusInfoGrid) - - setPageContent(page, window) -} - // This is a page that shows the user 100 sample offspring polygenic disease risk scores on a bar chart // This helps users to visualize the standard deviation of their offspring's disease risk with this user func setViewPolygenicDiseaseSampleOffspringRiskScoresChart(window fyne.Window, diseaseName string, sampleOffspringRiskScoresList []int, numberOfLociTested int, previousPage func()){ @@ -1767,13 +1608,15 @@ func setViewPolygenicDiseaseSampleOffspringRiskScoresChart(window fyne.Window, d return } - diseaseLociMap, err := polygenicDiseases.GetPolygenicDiseaseLociMap(diseaseName) + diseaseLocusObject, err := polygenicDiseases.GetPolygenicDiseaseObject(diseaseName) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } - totalNumberOfLoci := len(diseaseLociMap) + diseaseLociList := diseaseLocusObject.LociList + + totalNumberOfLoci := len(diseaseLociList) totalNumberOfLociString := helpers.ConvertIntToString(totalNumberOfLoci) numberOfLociTestedTitle := widget.NewLabel("Number Of Loci Tested:") @@ -1810,14 +1653,11 @@ func setViewPolygenicDiseaseSampleOffspringRiskScoresChart(window fyne.Window, d chartTitle := diseaseName + ": 100 Prospective Offspring Risk Scores" - formatYAxisValuesFunction := func(inputRiskScore float64)(string, error){ + formatYAxisValuesFunction := func(inputOffspringCount float64)(string, error){ - inputRiskScoreInt, err := helpers.FloorFloat64ToInt(inputRiskScore) - if (err != nil){ return "", err } + offspringCountString := helpers.ConvertIntToString(int(inputOffspringCount)) - inputRiskScoreString := helpers.ConvertIntToString(inputRiskScoreInt) - - return inputRiskScoreString, nil + return offspringCountString, nil } offspringsChart, err := createCharts.CreateBarChart(chartTitle, offspringStatisticsDatumsList, formatYAxisValuesFunction, true, " Offspring") @@ -2140,9 +1980,12 @@ func setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe predictionLabel := getItalicLabelCentered("Prediction") confidenceLabel := getItalicLabelCentered("Confidence") - quantityOfLabel := getItalicLabelCentered("Quantity Of") + quantityOfLabel1 := getItalicLabelCentered("Quantity Of") rulesTestedLabel := getItalicLabelCentered("Rules Tested") + quantityOfLabel2 := getItalicLabelCentered("Quantity Of") + lociKnownLabel := getItalicLabelCentered("Loci Known") + emptyLabel5 := widget.NewLabel("") emptyLabel6 := widget.NewLabel("") @@ -2150,7 +1993,8 @@ func setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe pairNameColumn := container.NewVBox(emptyLabel3, genomePairLabel, widget.NewSeparator()) predictedProbabilitiesColumn := container.NewVBox(emptyLabel4, predictedProbabilitiesLabel, widget.NewSeparator()) neuralNetworkPredictionConfidenceColumn := container.NewVBox(predictionLabel, confidenceLabel, widget.NewSeparator()) - quantityOfRulesTestedColumn := container.NewVBox(quantityOfLabel, rulesTestedLabel, widget.NewSeparator()) + quantityOfRulesTestedColumn := container.NewVBox(quantityOfLabel1, rulesTestedLabel, widget.NewSeparator()) + quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel2, lociKnownLabel, widget.NewSeparator()) viewDetailsButtonsColumn := container.NewVBox(emptyLabel5, emptyLabel6, widget.NewSeparator()) addGenomePairRow := func(genomePairName string, person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{ @@ -2176,7 +2020,7 @@ func setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe pairNameColumn.Add(genomePairNameLabel) viewDetailsButtonsColumn.Add(viewAnalysisDetailsButton) - neuralNetworkExists, neuralNetworkAnalysisExists, offspringOutcomeProbabilitiesMap_NeuralNetwork, neuralNetworkPredictionConfidence, _, _, anyRulesExist, rulesAnalysisExists, offspringOutcomeProbabilitiesMap_Rules, _, quantityOfRulesTested, _, _, err := readGeneticAnalysis.GetOffspringDiscreteTraitInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, genomePairIdentifier) + neuralNetworkExists, neuralNetworkAnalysisExists, offspringOutcomeProbabilitiesMap_NeuralNetwork, neuralNetworkPredictionConfidence, quantityOfLociKnown_NeuralNetwork, _, anyRulesExist, rulesAnalysisExists, offspringOutcomeProbabilitiesMap_Rules, _, quantityOfRulesTested, _, _, err := readGeneticAnalysis.GetOffspringDiscreteTraitInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, genomePairIdentifier) if (err != nil) { return err } if (neuralNetworkExists == false && anyRulesExist == false){ return errors.New("setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage called with trait that is not analyzable.") @@ -2198,6 +2042,19 @@ func setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe neuralNetworkPredictionConfidenceColumn.Add(predictionConfidenceLabel) } + traitLociList := traitObject.LociList + + totalQuantityOfLoci := len(traitLociList) + + quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown_NeuralNetwork) + totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci) + + quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString + + quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted) + + quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel) + } else { if (anyRulesExist == false){ return errors.New("setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage called with analysis which is missing ") @@ -2278,6 +2135,7 @@ func setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe pairNameColumn.Add(widget.NewLabel("")) neuralNetworkPredictionConfidenceColumn.Add(widget.NewLabel("")) quantityOfRulesTestedColumn.Add(widget.NewLabel("")) + quantityOfLociKnownColumn.Add(widget.NewLabel("")) viewDetailsButtonsColumn.Add(widget.NewLabel("")) } } @@ -2288,6 +2146,7 @@ func setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe predictedProbabilitiesColumn.Add(widget.NewSeparator()) neuralNetworkPredictionConfidenceColumn.Add(widget.NewSeparator()) quantityOfRulesTestedColumn.Add(widget.NewSeparator()) + quantityOfLociKnownColumn.Add(widget.NewSeparator()) viewDetailsButtonsColumn.Add(widget.NewSeparator()) return nil @@ -2321,6 +2180,13 @@ func setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe }) neuralNetworkPredictionConfidenceColumn.Add(neuralNetworkPredictionConfidenceHelpButton) + + quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ + showUnderConstructionDialog(window) + //TODO + }) + + quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton) } else { quantityOfRulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setOffspringDiscreteTraitQuantityOfRulesTestedExplainerPage(window, currentPage) @@ -2334,6 +2200,7 @@ func setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe if (neuralNetworkExists == true){ genomesContainer.Add(neuralNetworkPredictionConfidenceColumn) + genomesContainer.Add(quantityOfLociKnownColumn) } else { genomesContainer.Add(quantityOfRulesTestedColumn) } @@ -2830,7 +2697,6 @@ func setViewCoupleDiscreteTraitRulesPage(window fyne.Window, person1Name string, } - // This function implements a page to view the details of a specific rule from a genetic analysis // It will show the rule details for all of the couple's genome pairs func setViewCoupleGeneticAnalysisDiscreteTraitRuleDetailsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, traitName string, ruleIdentifier [3]byte, previousPage func()){ @@ -2953,30 +2819,21 @@ func setViewCoupleGeneticAnalysisNumericTraitsPage(window fyne.Window, person1Na mainGenomePairIdentifier := helpers.JoinTwo16ByteArrays(pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier) - emptyLabel1 := widget.NewLabel("") traitNameLabel := getItalicLabelCentered("Trait Name") - emptyLabel2 := widget.NewLabel("") predictedOutcomeLabel := getItalicLabelCentered("Predicted Outcome") - quantityOfLabel := getItalicLabelCentered("Quantity Of") - lociKnownLabel := getItalicLabelCentered("Loci Known") - - emptyLabel3 := widget.NewLabel("") confidenceRangeLabel := getItalicLabelCentered("Confidence Range") - emptyLabel4 := widget.NewLabel("") conflictExistsLabel := getItalicLabelCentered("Conflict Exists?") emptyLabel5 := widget.NewLabel("") - emptyLabel6 := widget.NewLabel("") - traitNameColumn := container.NewVBox(emptyLabel1, traitNameLabel, widget.NewSeparator()) - predictedOutcomeColumn := container.NewVBox(emptyLabel2, predictedOutcomeLabel, widget.NewSeparator()) - confidenceRangeColumn := container.NewVBox(emptyLabel3, confidenceRangeLabel, widget.NewSeparator()) - quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel, lociKnownLabel, widget.NewSeparator()) - conflictExistsColumn := container.NewVBox(emptyLabel4, conflictExistsLabel, widget.NewSeparator()) - viewDetailsButtonsColumn := container.NewVBox(emptyLabel5, emptyLabel6, widget.NewSeparator()) + traitNameColumn := container.NewVBox(traitNameLabel, widget.NewSeparator()) + predictedOutcomeColumn := container.NewVBox(predictedOutcomeLabel, widget.NewSeparator()) + confidenceRangeColumn := container.NewVBox(confidenceRangeLabel, widget.NewSeparator()) + conflictExistsColumn := container.NewVBox(conflictExistsLabel, widget.NewSeparator()) + viewDetailsButtonsColumn := container.NewVBox(emptyLabel5, widget.NewSeparator()) traitObjectsList, err := traits.GetTraitObjectsList() if (err != nil) { return nil, err } @@ -3006,25 +2863,28 @@ func setViewCoupleGeneticAnalysisNumericTraitsPage(window fyne.Window, person1Na traitNameLabel := getBoldLabelCentered(traitName) - analysisExists, offspringAverageOutcome, predictionConfidenceRangesMap, quantityOfLociKnown, _, _, conflictExists, err := readGeneticAnalysis.GetOffspringNumericTraitInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, mainGenomePairIdentifier) + analysisExists, offspringAverageOutcome, predictionConfidenceRangesMap, _, _, _, conflictExists, err := readGeneticAnalysis.GetOffspringNumericTraitInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, mainGenomePairIdentifier) if (err != nil) { return nil, err } - getPredictedOutcomeLabel := func()fyne.Widget{ + outcomeFormatter := traitObject.NumericValueFormatter + + getPredictedOutcomeLabel := func()(fyne.Widget, error){ + if (analysisExists == false){ result := widget.NewLabel("Unknown") - return result + return result, nil } - predictedOutcomeString := helpers.ConvertFloat64ToStringRounded(offspringAverageOutcome, 2) - - predictedOutcomeFormatted := predictedOutcomeString + " centimeters" + predictedOutcomeFormatted, err := outcomeFormatter(offspringAverageOutcome, true) + if (err != nil) { return nil, err } outcomeLabel := getBoldLabel(predictedOutcomeFormatted) - return outcomeLabel + return outcomeLabel, nil } - predictedOutcomeLabel := getPredictedOutcomeLabel() + predictedOutcomeLabel, err := getPredictedOutcomeLabel() + if (err != nil) { return nil, err } predictedOutcomeLabelCentered := getWidgetCentered(predictedOutcomeLabel) @@ -3051,11 +2911,12 @@ func setViewCoupleGeneticAnalysisNumericTraitsPage(window fyne.Window, person1Na return nil, errors.New("GetListOfMapKeys returning list of elements which contains element which is not in the map.") } - closestConfidenceDistanceString := helpers.ConvertFloat64ToStringRounded(closestToEightyPercentageConfidenceDistance, 2) + closestConfidenceDistanceString, err := outcomeFormatter(closestToEightyPercentageConfidenceDistance, false) + if (err != nil) { return nil, err } closestToEightyPercentageString := helpers.ConvertIntToString(closestToEightyPercentage) - confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "% Confidence)" + confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)" confidenceRangeLabel := getBoldLabel(confidenceRangeLabelValueFormatted) @@ -3067,15 +2928,6 @@ func setViewCoupleGeneticAnalysisNumericTraitsPage(window fyne.Window, person1Na confidenceRangeLabelCentered := getWidgetCentered(confidenceRangeLabel) - totalQuantityOfLoci := len(traitLociList) - - quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown) - totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci) - - quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString - - quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted) - conflictExistsString := helpers.ConvertBoolToYesOrNoString(conflictExists) conflictExistsLabel := getBoldLabelCentered(conflictExistsString) @@ -3086,14 +2938,12 @@ func setViewCoupleGeneticAnalysisNumericTraitsPage(window fyne.Window, person1Na traitNameColumn.Add(traitNameLabel) predictedOutcomeColumn.Add(predictedOutcomeLabelCentered) confidenceRangeColumn.Add(confidenceRangeLabelCentered) - quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel) conflictExistsColumn.Add(conflictExistsLabel) viewDetailsButtonsColumn.Add(viewDetailsButton) traitNameColumn.Add(widget.NewSeparator()) predictedOutcomeColumn.Add(widget.NewSeparator()) confidenceRangeColumn.Add(widget.NewSeparator()) - quantityOfLociKnownColumn.Add(widget.NewSeparator()) conflictExistsColumn.Add(widget.NewSeparator()) viewDetailsButtonsColumn.Add(widget.NewSeparator()) } @@ -3111,13 +2961,7 @@ func setViewCoupleGeneticAnalysisNumericTraitsPage(window fyne.Window, person1Na confidenceRangeColumn.Add(confidenceRangeHelpButton) - quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - //TODO - showUnderConstructionDialog(window) - }) - quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton) - - traitsGrid := container.NewHBox(layout.NewSpacer(), traitNameColumn, predictedOutcomeColumn, confidenceRangeColumn, quantityOfLociKnownColumn) + traitsGrid := container.NewHBox(layout.NewSpacer(), traitNameColumn, predictedOutcomeColumn, confidenceRangeColumn) if (secondGenomePairExists == true){ @@ -3250,22 +3094,25 @@ func setViewCoupleGeneticAnalysisNumericTraitDetailsPage(window fyne.Window, per analysisExists, offspringAverageOutcome, predictionConfidenceRangesMap, quantityOfLociKnown, _, sampleOffspringOutcomesList, _, err := readGeneticAnalysis.GetOffspringNumericTraitInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, genomePairIdentifier) if (err != nil) { return err } - getPredictedOutcomeLabel := func()fyne.Widget{ + outcomeFormatter := traitObject.NumericValueFormatter + + getPredictedOutcomeLabel := func()(fyne.Widget, error){ + if (analysisExists == false){ unknownLabel := widget.NewLabel("Unknown") - return unknownLabel + return unknownLabel, nil } - offspringAverageOutcomeString := helpers.ConvertFloat64ToStringRounded(offspringAverageOutcome, 2) - - offspringAverageOutcomeFormatted := offspringAverageOutcomeString + " centimeters" + offspringAverageOutcomeFormatted, err := outcomeFormatter(offspringAverageOutcome, true) + if (err != nil) { return nil, err } predictedOutcomeLabel := getBoldLabel(offspringAverageOutcomeFormatted) - return predictedOutcomeLabel + return predictedOutcomeLabel, nil } - predictedOutcomeLabel := getPredictedOutcomeLabel() + predictedOutcomeLabel, err := getPredictedOutcomeLabel() + if (err != nil) { return err } predictedOutcomeLabelCentered := getWidgetCentered(predictedOutcomeLabel) @@ -3292,11 +3139,12 @@ func setViewCoupleGeneticAnalysisNumericTraitDetailsPage(window fyne.Window, per return nil, errors.New("GetListOfMapKeys returning list of elements which contains element which is not in the map.") } - closestConfidenceDistanceString := helpers.ConvertFloat64ToStringRounded(closestToEightyPercentageConfidenceDistance, 2) + closestConfidenceDistanceString, err := outcomeFormatter(closestToEightyPercentageConfidenceDistance, false) + if (err != nil) { return nil, err } closestToEightyPercentageString := helpers.ConvertIntToString(closestToEightyPercentage) - confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "% Confidence)" + confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)" confidenceRangeLabel := getBoldLabel(confidenceRangeLabelValueFormatted) @@ -3318,7 +3166,7 @@ func setViewCoupleGeneticAnalysisNumericTraitDetailsPage(window fyne.Window, per quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted) viewSampleOffspringsButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ - setViewNumericTraitSampleOffspringRiskScoresChart(window, traitName, sampleOffspringOutcomesList, quantityOfLociKnown, currentPage) + setViewNumericTraitSampleOffspringOutcomesChart(window, traitName, sampleOffspringOutcomesList, quantityOfLociKnown, currentPage) }) viewAnalysisDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ @@ -3388,9 +3236,9 @@ func setViewCoupleGeneticAnalysisNumericTraitDetailsPage(window fyne.Window, per // This is a page that shows the user 100 sample offspring trait outcomes on a bar chart // This helps users to visualize the standard deviation of their offspring's trait outcomes with this user -func setViewNumericTraitSampleOffspringRiskScoresChart(window fyne.Window, traitName string, sampleOffspringOutcomesList []float64, quantityOfLociKnown int, previousPage func()){ +func setViewNumericTraitSampleOffspringOutcomesChart(window fyne.Window, traitName string, sampleOffspringOutcomesList []float64, quantityOfLociKnown int, previousPage func()){ - currentPage := func(){setViewNumericTraitSampleOffspringRiskScoresChart(window, traitName, sampleOffspringOutcomesList, quantityOfLociKnown, previousPage)} + currentPage := func(){setViewNumericTraitSampleOffspringOutcomesChart(window, traitName, sampleOffspringOutcomesList, quantityOfLociKnown, previousPage)} title := getPageTitleCentered("Viewing Sample Offspring Outcomes Chart") @@ -3442,13 +3290,15 @@ func setViewNumericTraitSampleOffspringRiskScoresChart(window fyne.Window, trait getOffspringSampleOutcomesChartImage := func()(image.Image, error){ if (len(sampleOffspringOutcomesList) != 100){ - return nil, errors.New("setViewNumericTraitSampleOffspringRiskScoresChart called with offspringOutcomesList that is not 100 items in length.") + return nil, errors.New("setViewNumericTraitSampleOffspringOutcomesChart called with offspringOutcomesList that is not 100 items in length.") } // We sort the list in ascending order slices.Sort(sampleOffspringOutcomesList) - getOffspringStatisticsDatumsList := func()([]statisticsDatum.StatisticsDatum){ + outcomeFormatter := traitObject.NumericValueFormatter + + getOffspringStatisticsDatumsList := func()([]statisticsDatum.StatisticsDatum, error){ offspringStatisticsDatumsList := make([]statisticsDatum.StatisticsDatum, 0) @@ -3460,12 +3310,13 @@ func setViewNumericTraitSampleOffspringRiskScoresChart(window fyne.Window, trait // We can't split the values into groups // Every offspring has the same value - onlyValueString := helpers.ConvertFloat64ToStringRounded(smallestItem, 2) - - onlyValueFormatted := onlyValueString + " centimeters" + onlyValue := helpers.ConvertFloat64ToString(smallestItem) + + onlyValueFormatted, err := outcomeFormatter(smallestItem, true) + if (err != nil) { return nil, err } newStatisticsDatum := statisticsDatum.StatisticsDatum{ - Label: onlyValueString, + Label: onlyValue, LabelFormatted: onlyValueFormatted, Value: float64(100), ValueFormatted: "100", @@ -3473,14 +3324,14 @@ func setViewNumericTraitSampleOffspringRiskScoresChart(window fyne.Window, trait offspringStatisticsDatumsList = append(offspringStatisticsDatumsList, newStatisticsDatum) - return offspringStatisticsDatumsList + return offspringStatisticsDatumsList, nil } // We split all outcomes into ten groups sizeOfEachGroup := (largestItem-smallestItem)/10 - index := float64(0) + index := float64(smallestItem) for { @@ -3507,10 +3358,12 @@ func setViewNumericTraitSampleOffspringRiskScoresChart(window fyne.Window, trait } } - groupLowerBoundString := helpers.ConvertFloat64ToStringRounded(index, 1) - groupUpperBoundString := helpers.ConvertFloat64ToStringRounded(groupUpperBound, 1) + groupLowerBoundString, err := outcomeFormatter(index, true) + if (err != nil) { return nil, err } + groupUpperBoundString, err := outcomeFormatter(groupUpperBound, true) + if (err != nil) { return nil, err } - groupDescription := groupLowerBoundString + "-" + groupUpperBoundString + " centimeters" + groupDescription := groupLowerBoundString + "-" + groupUpperBoundString offspringCountString := helpers.ConvertIntToString(offspringInGroupCount) @@ -3530,16 +3383,17 @@ func setViewNumericTraitSampleOffspringRiskScoresChart(window fyne.Window, trait index += sizeOfEachGroup } - return offspringStatisticsDatumsList + return offspringStatisticsDatumsList, nil } - offspringStatisticsDatumsList := getOffspringStatisticsDatumsList() + offspringStatisticsDatumsList, err := getOffspringStatisticsDatumsList() + if (err != nil) { return nil, err } chartTitle := traitName + ": 100 Prospective Offspring Values" - formatYAxisValuesFunction := func(inputTraitValue float64)(string, error){ + formatYAxisValuesFunction := func(inputOffspringCount float64)(string, error){ - result := helpers.ConvertFloat64ToStringRounded(inputTraitValue, 2) + result := helpers.ConvertIntToString(int(inputOffspringCount)) return result, nil } diff --git a/gui/viewAnalysisGui_Person.go b/gui/viewAnalysisGui_Person.go index cf1af7c..3426b48 100644 --- a/gui/viewAnalysisGui_Person.go +++ b/gui/viewAnalysisGui_Person.go @@ -918,44 +918,96 @@ func setViewPersonGeneticAnalysisPolygenicDiseasesPage(window fyne.Window, perso mainGenomeIdentifier, err := getMainGenomeIdentifier() if (err != nil){ return nil, err } - + diseaseNameLabel := getItalicLabelCentered("Disease Name") riskScoreLabel := getItalicLabelCentered("Risk Score") + confidenceRangeLabel := getItalicLabelCentered("Confidence Range") + conflictExistsLabel := getItalicLabelCentered("Conflict Exists?") - emptyLabel := widget.NewLabel("") + emptyLabel5 := widget.NewLabel("") diseaseNameColumn := container.NewVBox(diseaseNameLabel, widget.NewSeparator()) riskScoreColumn := container.NewVBox(riskScoreLabel, widget.NewSeparator()) + confidenceRangeColumn := container.NewVBox(confidenceRangeLabel, widget.NewSeparator()) conflictExistsColumn := container.NewVBox(conflictExistsLabel, widget.NewSeparator()) - viewButtonsColumn := container.NewVBox(emptyLabel, widget.NewSeparator()) + viewButtonsColumn := container.NewVBox(emptyLabel5, widget.NewSeparator()) - polygenicDiseaseNamesList, err := polygenicDiseases.GetPolygenicDiseaseNamesList() + polygenicDiseasesList, err := polygenicDiseases.GetPolygenicDiseaseObjectsList() if (err != nil) { return nil, err } - for _, diseaseName := range polygenicDiseaseNamesList{ + for _, diseaseObject := range polygenicDiseasesList{ - diseaseNameText := getBoldLabelCentered(diseaseName) + diseaseName := diseaseObject.DiseaseName - personRiskScoreKnown, _, personRiskScoreFormatted, _, conflictExists, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(analysisObject, diseaseName, mainGenomeIdentifier) + neuralNetworkExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(diseaseName) + if (neuralNetworkExists == false){ + // We can't analyze this trait + continue + } + + diseaseNameLabel := getBoldLabelCentered(diseaseName) + + analysisExists, personRiskScore, predictionConfidenceRangesMap, _, _, conflictExists, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(analysisObject, diseaseName, mainGenomeIdentifier) if (err != nil) { return nil, err } - getPersonRiskScoreLabelText := func()string{ + getPersonRiskScoreLabel := func()fyne.Widget{ - if (personRiskScoreKnown == false){ - result := translate("Unknown") + if (analysisExists == false){ + result := widget.NewLabel(translate("Unknown")) return result } - return personRiskScoreFormatted + riskScoreString := helpers.ConvertIntToString(personRiskScore) + riskScoreFormatted := riskScoreString + "/10" + + riskScoreLabel := getBoldLabel(riskScoreFormatted) + + return riskScoreLabel } - personRiskScoreLabelText := getPersonRiskScoreLabelText() + personRiskScoreLabel := getPersonRiskScoreLabel() + personRiskScoreLabelCentered := getWidgetCentered(personRiskScoreLabel) - riskScoreText := getBoldLabelCentered(personRiskScoreLabelText) + getConfidenceRangeLabel := func()(fyne.Widget, error){ + + if (analysisExists == false){ + unknownLabel := widget.NewLabel("Unknown") + return unknownLabel, nil + } + + // This is a list of the percentage accuracies in the map + // For example: 80% == The distance from the prediction you must travel for 80% of the predictions to be + // accurate within that range + confidenceRangePercentagesList := helpers.GetListOfMapKeys(predictionConfidenceRangesMap) + + // We sort the list so the percentage is always the same upon refreshing the page + slices.Sort(confidenceRangePercentagesList) + + closestToEightyPercentage, err := helpers.GetClosestIntInList(confidenceRangePercentagesList, 80) + if (err != nil) { return nil, err } + + closestToEightyPercentageConfidenceDistance, exists := predictionConfidenceRangesMap[closestToEightyPercentage] + if (exists == false){ + return nil, errors.New("GetListOfMapKeys returning list of elements which contains element which is not in the map.") + } + + closestConfidenceDistanceString := helpers.ConvertFloat64ToStringRounded(closestToEightyPercentageConfidenceDistance, 2) + + closestToEightyPercentageString := helpers.ConvertIntToString(closestToEightyPercentage) + + confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)" + + confidenceRangeLabel := getBoldLabel(confidenceRangeLabelValueFormatted) + + return confidenceRangeLabel, nil + } + + confidenceRangeLabel, err := getConfidenceRangeLabel() + if (err != nil) { return nil, err } conflictExistsString := helpers.ConvertBoolToYesOrNoString(conflictExists) conflictExistsLabel := getBoldLabelCentered(conflictExistsString) @@ -964,13 +1016,15 @@ func setViewPersonGeneticAnalysisPolygenicDiseasesPage(window fyne.Window, perso setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window, personIdentifier, analysisObject, diseaseName, currentPage) })) - diseaseNameColumn.Add(diseaseNameText) - riskScoreColumn.Add(riskScoreText) + diseaseNameColumn.Add(diseaseNameLabel) + riskScoreColumn.Add(personRiskScoreLabelCentered) + confidenceRangeColumn.Add(confidenceRangeLabel) conflictExistsColumn.Add(conflictExistsLabel) viewButtonsColumn.Add(viewDetailsButton) diseaseNameColumn.Add(widget.NewSeparator()) riskScoreColumn.Add(widget.NewSeparator()) + confidenceRangeColumn.Add(widget.NewSeparator()) conflictExistsColumn.Add(widget.NewSeparator()) viewButtonsColumn.Add(widget.NewSeparator()) } @@ -980,7 +1034,13 @@ func setViewPersonGeneticAnalysisPolygenicDiseasesPage(window fyne.Window, perso }) riskScoreColumn.Add(riskScoreHelpButton) - diseasesContainer := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, riskScoreColumn) + confidenceRangeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ + //TODO + showUnderConstructionDialog(window) + }) + confidenceRangeColumn.Add(confidenceRangeHelpButton) + + diseasesContainer := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, riskScoreColumn, confidenceRangeColumn) if (multipleGenomesExist == true){ @@ -1010,7 +1070,6 @@ func setViewPersonGeneticAnalysisPolygenicDiseasesPage(window fyne.Window, perso } - func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window, personIdentifier string, analysisObject geneticAnalysis.PersonAnalysis, diseaseName string, previousPage func()){ currentPage := func(){setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window, personIdentifier, analysisObject, diseaseName, previousPage)} @@ -1018,7 +1077,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window, title := getPageTitleCentered("Viewing Genetic Analysis - " + diseaseName) backButton := getBackButtonCentered(previousPage) - + allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject) if (err != nil) { setErrorEncounteredPage(window, err, previousPage) @@ -1035,7 +1094,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window, description1 := getLabelCentered("Below is the disease information for this person's genomes.") description2 := getLabelCentered("The first two genomes are created by combining multiple genomes.") - + descriptionsSection := container.NewVBox(description1, description2) return descriptionsSection @@ -1052,32 +1111,38 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window, getGenomesContainer := func()(*fyne.Container, error){ - diseaseLociMap, err := polygenicDiseases.GetPolygenicDiseaseLociMap(diseaseName) + diseaseObject, err := polygenicDiseases.GetPolygenicDiseaseObject(diseaseName) if (err != nil){ return nil, err } - totalNumberOfLoci := len(diseaseLociMap) - totalNumberOfLociString := helpers.ConvertIntToString(totalNumberOfLoci) + diseaseLociList := diseaseObject.LociList - emptyLabelA := widget.NewLabel("") + totalQuantityOfLoci := len(diseaseLociList) + totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci) + + emptyLabel1 := widget.NewLabel("") genomeNameLabel := getItalicLabelCentered("Genome Name") - emptyLabelB := widget.NewLabel("") + emptyLabel2 := widget.NewLabel("") riskScoreLabel := getItalicLabelCentered("Risk Score") - numberOfLabel := getItalicLabelCentered("Number of") - lociTestedLabel := getItalicLabelCentered("Loci Tested") + emptyLabel3 := widget.NewLabel("") + predictionConfidenceLabel := getItalicLabelCentered("Confidence Range") - emptyLabelD := widget.NewLabel("") - emptyLabelE := widget.NewLabel("") + quantityOfLabel := getItalicLabelCentered("Quantity of") + lociKnownLabel := getItalicLabelCentered("Loci Known") - emptyLabelF := widget.NewLabel("") - emptyLabelG := widget.NewLabel("") + emptyLabel4 := widget.NewLabel("") + emptyLabel5 := widget.NewLabel("") - genomeNameColumn := container.NewVBox(emptyLabelA, genomeNameLabel, widget.NewSeparator()) - riskScoreColumn := container.NewVBox(emptyLabelB, riskScoreLabel, widget.NewSeparator()) - numberOfLociTestedColumn := container.NewVBox(numberOfLabel, lociTestedLabel, widget.NewSeparator()) - viewLifetimeRiskButtonsColumn := container.NewVBox(emptyLabelD, emptyLabelE, widget.NewSeparator()) - viewLociButtonsColumn := container.NewVBox(emptyLabelF, emptyLabelG, widget.NewSeparator()) + emptyLabel6 := widget.NewLabel("") + emptyLabel7 := widget.NewLabel("") + + genomeNameColumn := container.NewVBox(emptyLabel1, genomeNameLabel, widget.NewSeparator()) + riskScoreColumn := container.NewVBox(emptyLabel2, riskScoreLabel, widget.NewSeparator()) + predictionConfidenceColumn := container.NewVBox(emptyLabel3, predictionConfidenceLabel, widget.NewSeparator()) + quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel, lociKnownLabel, widget.NewSeparator()) + viewLifetimeRiskButtonsColumn := container.NewVBox(emptyLabel4, emptyLabel5, widget.NewSeparator()) + viewDetailsButtonsColumn := container.NewVBox(emptyLabel6, emptyLabel7, widget.NewSeparator()) addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{ @@ -1094,30 +1159,75 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window, genomeNameLabel := getBoldLabel(genomeName) genomeNameCell := container.NewHBox(layout.NewSpacer(), viewHelpButton, genomeNameLabel, layout.NewSpacer()) - return genomeNameCell + return genomeNameCell } genomeNameCell := getGenomeNameCell() - diseaseRiskScoreKnown, _, diseaseRiskScoreFormatted, numberOfLociTested, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(analysisObject, diseaseName, genomeIdentifier) + analysisExists, predictedRiskScore, predictionConfidenceRangesMap, quantityOfLociKnown, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(analysisObject, diseaseName, genomeIdentifier) if (err != nil) { return err } - getRiskScoreLabelText := func()string{ - if (diseaseRiskScoreKnown == false){ - result := translate("Unknown") + getRiskScoreLabel := func()fyne.Widget{ + + if (analysisExists == false){ + + result := widget.NewLabel(translate("Unknown")) return result } - return diseaseRiskScoreFormatted + riskScoreString := helpers.ConvertIntToString(predictedRiskScore) + riskScoreFormatted := riskScoreString + "/10" + + riskScoreLabel := getBoldLabel(riskScoreFormatted) + + return riskScoreLabel } - genomeRiskScoreLabelText := getRiskScoreLabelText() + genomeRiskScoreLabel := getRiskScoreLabel() + genomeRiskScoreLabelCentered := getWidgetCentered(genomeRiskScoreLabel) - riskScoreLabel := getBoldLabelCentered(genomeRiskScoreLabelText) + getConfidenceRangeLabel := func()(fyne.Widget, error){ - genomeNumberOfLociTestedString := helpers.ConvertIntToString(numberOfLociTested) - numberOfLociTestedLabel := getBoldLabelCentered(genomeNumberOfLociTestedString + "/" + totalNumberOfLociString) + if (analysisExists == false){ + unknownLabel := widget.NewLabel("Unknown") + return unknownLabel, nil + } + + // This is a list of the percentage accuracies in the map + // For example: 80% == The distance from the prediction you must travel for 80% of the predictions to be + // accurate within that range + confidenceRangePercentagesList := helpers.GetListOfMapKeys(predictionConfidenceRangesMap) + + // We sort the list so the percentage is always the same upon refreshing the page + slices.Sort(confidenceRangePercentagesList) + + closestToEightyPercentage, err := helpers.GetClosestIntInList(confidenceRangePercentagesList, 80) + if (err != nil) { return nil, err } + + closestToEightyPercentageConfidenceDistance, exists := predictionConfidenceRangesMap[closestToEightyPercentage] + if (exists == false){ + return nil, errors.New("GetListOfMapKeys returning list of elements which contains element which is not in the map.") + } + + closestConfidenceDistanceString := helpers.ConvertFloat64ToStringRounded(closestToEightyPercentageConfidenceDistance, 2) + + closestToEightyPercentageString := helpers.ConvertIntToString(closestToEightyPercentage) + + confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)" + + confidenceRangeLabel := getBoldLabel(confidenceRangeLabelValueFormatted) + + return confidenceRangeLabel, nil + } + + confidenceRangeLabel, err := getConfidenceRangeLabel() + if (err != nil) { return err } + + confidenceRangeLabelCentered := getWidgetCentered(confidenceRangeLabel) + + genomeQuantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown) + quantityOfLociKnownLabel := getBoldLabelCentered(genomeQuantityOfLociKnownString + "/" + totalQuantityOfLociString) viewLifetimeRiskButton := widget.NewButtonWithIcon("", theme.HistoryIcon(), func(){ @@ -1142,21 +1252,24 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window, setViewPersonPolygenicDiseaseLifetimeProbabilitiesPage(window, diseaseName, genomeName, sexToDisplay, currentPage) }) - viewLociButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ - setViewPersonGenomePolygenicDiseaseLociPage(window, analysisObject, diseaseName, genomeIdentifier, genomeName, currentPage) + viewDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ + //TODO + showUnderConstructionDialog(window) }) genomeNameColumn.Add(genomeNameCell) - riskScoreColumn.Add(riskScoreLabel) - numberOfLociTestedColumn.Add(numberOfLociTestedLabel) + riskScoreColumn.Add(genomeRiskScoreLabelCentered) + predictionConfidenceColumn.Add(confidenceRangeLabelCentered) + quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel) viewLifetimeRiskButtonsColumn.Add(viewLifetimeRiskButton) - viewLociButtonsColumn.Add(viewLociButton) - + viewDetailsButtonsColumn.Add(viewDetailsButton) + genomeNameColumn.Add(widget.NewSeparator()) riskScoreColumn.Add(widget.NewSeparator()) - numberOfLociTestedColumn.Add(widget.NewSeparator()) + predictionConfidenceColumn.Add(widget.NewSeparator()) + quantityOfLociKnownColumn.Add(widget.NewSeparator()) viewLifetimeRiskButtonsColumn.Add(widget.NewSeparator()) - viewLociButtonsColumn.Add(widget.NewSeparator()) + viewDetailsButtonsColumn.Add(widget.NewSeparator()) return nil } @@ -1184,7 +1297,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window, } // We show the date the genome was exported - + exportTimeAgo, err := helpers.ConvertUnixTimeToTimeAgoTranslated(timeGenomeWasExported, false) if (err != nil){ return "", err } @@ -1205,12 +1318,17 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window, }) riskScoreColumn.Add(riskScoreHelpButton) - numberOfLociTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ + predictionConfidenceHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ + showUnderConstructionDialog(window) + }) + predictionConfidenceColumn.Add(predictionConfidenceHelpButton) + + quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage) }) - numberOfLociTestedColumn.Add(numberOfLociTestedHelpButton) + quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton) - genomesContainer := container.NewHBox(layout.NewSpacer(), genomeNameColumn, riskScoreColumn, numberOfLociTestedColumn, viewLifetimeRiskButtonsColumn, viewLociButtonsColumn, layout.NewSpacer()) + genomesContainer := container.NewHBox(layout.NewSpacer(), genomeNameColumn, riskScoreColumn, predictionConfidenceColumn, quantityOfLociKnownColumn, viewLifetimeRiskButtonsColumn, viewDetailsButtonsColumn, layout.NewSpacer()) return genomesContainer, nil } @@ -1222,7 +1340,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window, } page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), genomesContainer) - + setPageContent(page, window) } @@ -1311,7 +1429,9 @@ func setViewPersonPolygenicDiseaseLifetimeProbabilitiesPage(window fyne.Window, startAgeString := helpers.ConvertIntToString(rowInitialAge) endAgeString := helpers.ConvertIntToString(age) - averageRiskString := helpers.ConvertFloat64ToStringRounded(averageRisk, 2) + averageRiskPercentage := averageRisk * 100 + + averageRiskString := helpers.ConvertFloat64ToStringRounded(averageRiskPercentage, 2) ageRangeLabel := getBoldLabel(startAgeString + " - " + endAgeString) averageRiskLabel := getBoldLabelCentered(averageRiskString + "%") @@ -1347,7 +1467,7 @@ func setViewPersonPolygenicDiseaseLifetimeProbabilitiesPage(window fyne.Window, setErrorEncounteredPage(window, err, previousPage) return } - + ageProbabilityTabs := container.NewAppTabs(maleTab, femaleTab) if (maleOrFemale == "Male"){ @@ -1364,410 +1484,6 @@ func setViewPersonPolygenicDiseaseLifetimeProbabilitiesPage(window fyne.Window, } - -// This function provides a page to view the polygenic disease loci for a particular genome from a genetic analysis -func setViewPersonGenomePolygenicDiseaseLociPage(window fyne.Window, geneticAnalysisObject geneticAnalysis.PersonAnalysis, diseaseName string, genomeIdentifier [16]byte, genomeName string, previousPage func()){ - - setLoadingScreen(window, "Loading Polygenic Disease Loci", "Loading disease loci...") - - currentPage := func(){setViewPersonGenomePolygenicDiseaseLociPage(window, geneticAnalysisObject, diseaseName, genomeIdentifier, genomeName, previousPage)} - - title := getPageTitleCentered("View Disease Loci - " + diseaseName) - - backButton := getBackButtonCentered(previousPage) - - description1 := widget.NewLabel("Below are the disease loci results for this genome.") - lociHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setPolygenicDiseaseLociExplainerPage(window, currentPage) - }) - description1Row := container.NewHBox(layout.NewSpacer(), description1, lociHelpButton, layout.NewSpacer()) - - getGenomeNameRow := func()*fyne.Container{ - - genomeLabel := widget.NewLabel("Genome:") - genomeNameLabel := getBoldLabel(genomeName) - - if (genomeName == "Only Exclude Conflicts" || genomeName == "Only Include Shared"){ - genomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setCombinedGenomesExplainerPage(window, currentPage) - }) - genomeNameRow := container.NewHBox(layout.NewSpacer(), genomeLabel, genomeNameLabel, genomeHelpButton, layout.NewSpacer()) - return genomeNameRow - } - genomeNameRow := container.NewHBox(layout.NewSpacer(), genomeLabel, genomeNameLabel, layout.NewSpacer()) - return genomeNameRow - } - - genomeNameRow := getGenomeNameRow() - - diseaseLociMap, err := polygenicDiseases.GetPolygenicDiseaseLociMap(diseaseName) - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return - } - - numberOfLociTested := 0 - - lociList_PositiveWeight := make([]string, 0) - lociList_ZeroWeight := make([]string, 0) - lociList_NegativeWeight := make([]string, 0) - lociList_UnknownWeight := make([]string, 0) - - for locusIdentifierHex, _ := range diseaseLociMap{ - - locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex) - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return - } - - locusRiskWeightIsKnown, genomeLocusRiskWeight, _, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(geneticAnalysisObject, diseaseName, locusIdentifier, genomeIdentifier) - if (err != nil) { - setErrorEncounteredPage(window, err, previousPage) - return - } - if (locusRiskWeightIsKnown == false){ - lociList_UnknownWeight = append(lociList_UnknownWeight, locusIdentifierHex) - continue - } - numberOfLociTested += 1 - - if (genomeLocusRiskWeight > 0){ - - lociList_PositiveWeight = append(lociList_PositiveWeight, locusIdentifierHex) - - } else if (genomeLocusRiskWeight == 0) { - - lociList_ZeroWeight = append(lociList_ZeroWeight, locusIdentifierHex) - - } else { - // genomeLocusRiskWeight < 0 - lociList_NegativeWeight = append(lociList_NegativeWeight, locusIdentifierHex) - } - } - - numberOfLociTestedString := helpers.ConvertIntToString(numberOfLociTested) - - totalNumberOfLoci := len(diseaseLociMap) - totalNumberOfLociString := helpers.ConvertIntToString(totalNumberOfLoci) - - lociTestedLabel := widget.NewLabel("Loci Tested:") - lociTestedText := getBoldLabel(numberOfLociTestedString + "/" + totalNumberOfLociString) - lociTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage) - }) - - lociTestedRow := container.NewHBox(layout.NewSpacer(), lociTestedLabel, lociTestedText, lociTestedHelpButton, layout.NewSpacer()) - - getDiseaseLociGrid := func()(*fyne.Container, error){ - - locusNameLabel := getItalicLabelCentered("Locus Name") - riskWeightLabel := getItalicLabelCentered("Risk Weight") - oddsRatioLabel := getItalicLabelCentered("Odds Ratio") - emptyLabel := widget.NewLabel("") - - locusNameColumn := container.NewVBox(locusNameLabel, widget.NewSeparator()) - riskWeightColumn := container.NewVBox(riskWeightLabel, widget.NewSeparator()) - oddsRatioColumn := container.NewVBox(oddsRatioLabel, widget.NewSeparator()) - viewButtonsColumn := container.NewVBox(emptyLabel, widget.NewSeparator()) - - addLocusRow := func(locusIdentifierHex string)error{ - - diseaseLocusObject, exists := diseaseLociMap[locusIdentifierHex] - if (exists == false) { - return errors.New("Cannot add locusRow: diseaseLociMap missing locus: " + locusIdentifierHex) - } - - locusRSID := diseaseLocusObject.LocusRSID - locusRSIDString := helpers.ConvertInt64ToString(locusRSID) - locusName := "rs" + locusRSIDString - - locusNameLabel := getBoldLabelCentered(locusName) - - locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex) - if (err != nil) { return err } - - locusRiskWeightIsKnown, genomeLocusRiskWeight, locusOddsRatioIsKnown, _, locusOddsRatioFormatted, err := readGeneticAnalysis.GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(geneticAnalysisObject, diseaseName, locusIdentifier, genomeIdentifier) - if (err != nil) { return err } - - getGenomeLocusRiskWeightText := func()string{ - if (locusRiskWeightIsKnown == false){ - - result := translate("Unknown") - return result - } - locusRiskWeightString := helpers.ConvertIntToString(genomeLocusRiskWeight) - - return locusRiskWeightString - } - - locusRiskWeightText := getGenomeLocusRiskWeightText() - locusRiskWeightLabel := getBoldLabelCentered(locusRiskWeightText) - - getOddsRatioText := func()string{ - - if (locusOddsRatioIsKnown == false){ - result := translate("Unknown") - return result - } - - return locusOddsRatioFormatted - } - - locusOddsRatioText := getOddsRatioText() - genomeLocusOddsRatioLabel := getBoldLabelCentered(locusOddsRatioText) - - viewLocusButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ - setViewPersonGeneticAnalysisPolygenicDiseaseLocusDetailsPage(window, geneticAnalysisObject, diseaseName, locusIdentifier, currentPage) - }) - - locusNameColumn.Add(locusNameLabel) - riskWeightColumn.Add(locusRiskWeightLabel) - oddsRatioColumn.Add(genomeLocusOddsRatioLabel) - viewButtonsColumn.Add(viewLocusButton) - - locusNameColumn.Add(widget.NewSeparator()) - riskWeightColumn.Add(widget.NewSeparator()) - oddsRatioColumn.Add(widget.NewSeparator()) - viewButtonsColumn.Add(widget.NewSeparator()) - - return nil - } - - // Items within each group are sorted so they will display the same way whenever user refreshes page - - helpers.SortStringListToUnicodeOrder(lociList_PositiveWeight) - helpers.SortStringListToUnicodeOrder(lociList_NegativeWeight) - helpers.SortStringListToUnicodeOrder(lociList_ZeroWeight) - helpers.SortStringListToUnicodeOrder(lociList_UnknownWeight) - - for _, locusIdentifier := range lociList_PositiveWeight{ - - err = addLocusRow(locusIdentifier) - if (err != nil) { return nil, err } - } - for _, locusIdentifier := range lociList_NegativeWeight{ - - err = addLocusRow(locusIdentifier) - if (err != nil) { return nil, err } - } - for _, locusIdentifier := range lociList_ZeroWeight{ - - err = addLocusRow(locusIdentifier) - if (err != nil) { return nil, err } - } - for _, locusIdentifier := range lociList_UnknownWeight{ - - err = addLocusRow(locusIdentifier) - if (err != nil) { return nil, err } - } - - - riskWeightHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setPolygenicDiseaseLocusRiskWeightExplainerPage(window, currentPage) - }) - riskWeightColumn.Add(riskWeightHelpButton) - - oddsRatioHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - //TODO - showUnderConstructionDialog(window) - }) - - oddsRatioColumn.Add(oddsRatioHelpButton) - - diseaseLociGrid := container.NewHBox(layout.NewSpacer(), locusNameColumn, riskWeightColumn, oddsRatioColumn, viewButtonsColumn, layout.NewSpacer()) - - return diseaseLociGrid, nil - } - - diseaseLociGrid, err := getDiseaseLociGrid() - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return - } - - page := container.NewVBox(title, backButton, widget.NewSeparator(), description1Row, widget.NewSeparator(), genomeNameRow, widget.NewSeparator(), lociTestedRow, widget.NewSeparator(), diseaseLociGrid) - - setPageContent(page, window) -} - - -// This function provides a page to view the details of a specific locus from a person genetic analysis -// It will show the locus details for all of the person's genomes -func setViewPersonGeneticAnalysisPolygenicDiseaseLocusDetailsPage(window fyne.Window, geneticAnalysisObject geneticAnalysis.PersonAnalysis, diseaseName string, locusIdentifier [3]byte, previousPage func()){ - - currentPage := func(){setViewPersonGeneticAnalysisPolygenicDiseaseLocusDetailsPage(window, geneticAnalysisObject, diseaseName, locusIdentifier, previousPage)} - - title := getPageTitleCentered("Disease Locus Details - " + diseaseName) - - backButton := getBackButtonCentered(previousPage) - - locusIdentifierHex := encoding.EncodeBytesToHexString(locusIdentifier[:]) - - locusObject, err := polygenicDiseases.GetPolygenicDiseaseLocusObject(diseaseName, locusIdentifierHex) - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return - } - - locusRSID := locusObject.LocusRSID - locusRSIDString := helpers.ConvertInt64ToString(locusRSID) - locusName := "rs" + locusRSIDString - - description := getLabelCentered("Below is the locus result for the person's genomes.") - - locusNameLabel := widget.NewLabel("Locus Name:") - locusNameText := getBoldLabel(locusName) - locusInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ - setViewPolygenicDiseaseLocusDetailsPage(window, diseaseName, locusIdentifierHex, currentPage) - }) - locusNameRow := container.NewHBox(layout.NewSpacer(), locusNameLabel, locusNameText, locusInfoButton, layout.NewSpacer()) - - getGenomesLocusInfoGrid := func()(*fyne.Container, error){ - - allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(geneticAnalysisObject) - if (err != nil) { return nil, err } - - genomeNameLabel := getItalicLabelCentered("Genome Name") - riskWeightLabel := getItalicLabelCentered("Risk Weight") - oddsRatioLabel := getItalicLabelCentered("Odds Ratio") - - genomeNameColumn := container.NewVBox(genomeNameLabel, widget.NewSeparator()) - riskWeightColumn := container.NewVBox(riskWeightLabel, widget.NewSeparator()) - oddsRatioColumn := container.NewVBox(oddsRatioLabel, widget.NewSeparator()) - - addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{ - - genomeRiskWeightKnown, genomeRiskWeight, genomeOddsRatioIsKnown, _, genomeOddsRatioFormatted, err := readGeneticAnalysis.GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(geneticAnalysisObject, diseaseName, locusIdentifier, genomeIdentifier) - if (err != nil) { return err } - - getGenomeRiskWeightText := func()string{ - - if (genomeRiskWeightKnown == false){ - result := translate("Unknown") - - return result - } - - genomeRiskWeightString := helpers.ConvertIntToString(genomeRiskWeight) - return genomeRiskWeightString - } - - genomeRiskWeightText := getGenomeRiskWeightText() - - getGenomeOddsRatioText := func()string{ - - if (genomeOddsRatioIsKnown == false){ - result := translate("Unknown") - - return result - } - - return genomeOddsRatioFormatted - } - - genomeOddsRatioText := getGenomeOddsRatioText() - - getGenomeNameCell := func()*fyne.Container{ - if (isACombinedGenome == false){ - - genomeNameLabel := getBoldLabelCentered(genomeName) - return genomeNameLabel - } - viewHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setCombinedGenomesExplainerPage(window, currentPage) - }) - - genomeNameLabel := getBoldLabel(genomeName) - genomeNameCell := container.NewHBox(layout.NewSpacer(), viewHelpButton, genomeNameLabel, layout.NewSpacer()) - - return genomeNameCell - } - - genomeNameCell := getGenomeNameCell() - genomeNameColumn.Add(genomeNameCell) - - riskWeightLabel := getBoldLabelCentered(genomeRiskWeightText) - riskWeightColumn.Add(riskWeightLabel) - - oddsRatioLabel := getBoldLabelCentered(genomeOddsRatioText) - oddsRatioColumn.Add(oddsRatioLabel) - - genomeNameColumn.Add(widget.NewSeparator()) - riskWeightColumn.Add(widget.NewSeparator()) - oddsRatioColumn.Add(widget.NewSeparator()) - - return nil - } - - if (multipleGenomesExist == true){ - - err := addGenomeRow("Only Exclude Conflicts", onlyExcludeConflictsGenomeIdentifier, true) - if (err != nil){ return nil, err } - - err = addGenomeRow("Only Include Shared", onlyIncludeSharedGenomeIdentifier, true) - if (err != nil){ return nil, err } - } - - for _, genomeIdentifier := range allRawGenomeIdentifiersList{ - - getGenomeName := func()(string, error){ - - genomeFound, _, timeGenomeWasExported, _, _, _, companyName, _, _, err := myGenomes.GetMyRawGenomeMetadata(genomeIdentifier) - if (err != nil) { return "", err } - if (genomeFound == false){ - return "", errors.New("MyGenomeInfo for genome from analysisObject not found.") - } - - if (multipleGenomesExist == false){ - return companyName, nil - } - - // We show the date that the genome was exported - - exportTimeAgo, err := helpers.ConvertUnixTimeToTimeAgoTranslated(timeGenomeWasExported, false) - if (err != nil){ return "", err } - - genomeName := companyName + " (Exported " + exportTimeAgo + ")" - - return genomeName, nil - } - - genomeName, err := getGenomeName() - if (err != nil) { return nil, err } - - err = addGenomeRow(genomeName, genomeIdentifier, false) - if (err != nil){ return nil, err } - } - - riskWeightHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setPolygenicDiseaseLocusRiskWeightExplainerPage(window, currentPage) - }) - riskWeightColumn.Add(riskWeightHelpButton) - - oddsRatioHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - //TODO - showUnderConstructionDialog(window) - }) - oddsRatioColumn.Add(oddsRatioHelpButton) - - genomesContainer := container.NewHBox(layout.NewSpacer(), genomeNameColumn, riskWeightColumn, oddsRatioColumn, layout.NewSpacer()) - - return genomesContainer, nil - } - - genomesLocusInfoGrid, err := getGenomesLocusInfoGrid() - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return - } - - page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), locusNameRow, widget.NewSeparator(), genomesLocusInfoGrid) - - setPageContent(page, window) -} - - func setViewPersonGeneticAnalysisDiscreteTraitsPage(window fyne.Window, personIdentifier string, analysisObject geneticAnalysis.PersonAnalysis, previousPage func()){ currentPage := func(){setViewPersonGeneticAnalysisDiscreteTraitsPage(window, personIdentifier, analysisObject, previousPage)} @@ -1985,7 +1701,7 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe title := getPageTitleCentered("Viewing Genetic Analysis - " + traitName) backButton := getBackButtonCentered(previousPage) - + allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject) if (err != nil) { setErrorEncounteredPage(window, err, previousPage) @@ -2017,10 +1733,11 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe }) traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameLabel, traitNameText, traitInfoButton, layout.NewSpacer()) - neuralNetworkExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName) - getGenomesContainer := func()(*fyne.Container, error){ + traitObject, err := traits.GetTraitObject(traitName) + if (err != nil) { return nil, err } + emptyLabel1 := widget.NewLabel("") genomeNameLabel := getItalicLabelCentered("Genome Name") @@ -2030,35 +1747,21 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe emptyLabel3 := widget.NewLabel("") predictionConfidenceLabel := getItalicLabelCentered("Prediction Confidence") - quantityOfLabel := getItalicLabelCentered("Quantity Of") + quantityOfLabel1 := getItalicLabelCentered("Quantity Of") + lociKnownLabel := getItalicLabelCentered("Loci Known") + + quantityOfLabel2 := getItalicLabelCentered("Quantity Of") rulesTestedLabel := getItalicLabelCentered("Rules Tested") emptyLabel4 := widget.NewLabel("") emptyLabel5 := widget.NewLabel("") - genomeNameColumn := container.NewVBox() - predictedOutcomeColumn := container.NewVBox() - neuralNetworkPredictionConfidenceColumn := container.NewVBox() - numberOfRulesTestedColumn := container.NewVBox(quantityOfLabel, rulesTestedLabel, widget.NewSeparator()) - viewDetailsButtonsColumn := container.NewVBox() - - if (neuralNetworkExists == false){ - // We only need an extra header row if the numberOfRulesTested column is shown - genomeNameColumn.Add(emptyLabel1) - predictedOutcomeColumn.Add(emptyLabel2) - neuralNetworkPredictionConfidenceColumn.Add(emptyLabel3) - viewDetailsButtonsColumn.Add(emptyLabel4) - } - - genomeNameColumn.Add(genomeNameLabel) - predictedOutcomeColumn.Add(predictedOutcomeLabel) - neuralNetworkPredictionConfidenceColumn.Add(predictionConfidenceLabel) - viewDetailsButtonsColumn.Add(emptyLabel5) - - genomeNameColumn.Add(widget.NewSeparator()) - predictedOutcomeColumn.Add(widget.NewSeparator()) - neuralNetworkPredictionConfidenceColumn.Add(widget.NewSeparator()) - viewDetailsButtonsColumn.Add(widget.NewSeparator()) + genomeNameColumn := container.NewVBox(emptyLabel1, genomeNameLabel, widget.NewSeparator()) + predictedOutcomeColumn := container.NewVBox(emptyLabel2, predictedOutcomeLabel, widget.NewSeparator()) + neuralNetworkPredictionConfidenceColumn := container.NewVBox(emptyLabel3, predictionConfidenceLabel, widget.NewSeparator()) + quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel1, lociKnownLabel, widget.NewSeparator()) + numberOfRulesTestedColumn := container.NewVBox(quantityOfLabel2, rulesTestedLabel, widget.NewSeparator()) + viewDetailsButtonsColumn := container.NewVBox(emptyLabel4, emptyLabel5, widget.NewSeparator()) addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{ @@ -2080,7 +1783,7 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe genomeNameCell := getGenomeNameCell() - neuralNetworkExists, neuralNetworkAnalysisExists, neuralNetworkPredictedOutcome, neuralNetworkPredictionConfidence, _, _, anyRulesExist, rulesAnalysisExists, _, rulesPredictedOutcomeExists, rulesPredictedOutcome, quantityOfRulesTested, _, _, err := readGeneticAnalysis.GetPersonDiscreteTraitInfoFromGeneticAnalysis(analysisObject, traitName, genomeIdentifier) + neuralNetworkExists, neuralNetworkAnalysisExists, neuralNetworkPredictedOutcome, neuralNetworkPredictionConfidence, quantityOfLociKnown_NeuralNetwork, _, anyRulesExist, rulesAnalysisExists, _, rulesPredictedOutcomeExists, rulesPredictedOutcome, quantityOfRulesTested, _, _, err := readGeneticAnalysis.GetPersonDiscreteTraitInfoFromGeneticAnalysis(analysisObject, traitName, genomeIdentifier) if (err != nil) { return err } if (neuralNetworkExists == false && anyRulesExist == false){ @@ -2120,61 +1823,48 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe predictedOutcomeLabelCentered := getWidgetCentered(predictedOutcomeLabel) - getNeuralNetworkConfidenceLabel := func()fyne.Widget{ + if (neuralNetworkExists == true){ - if (neuralNetworkExists == false){ - - emptyLabel := widget.NewLabel("") - - return emptyLabel - } if (neuralNetworkAnalysisExists == false){ - predictedOutcomeConfidenceLabel := getItalicLabel("Unknown") + predictedOutcomeConfidenceLabel := getItalicLabelCentered("Unknown") - return predictedOutcomeConfidenceLabel + neuralNetworkPredictionConfidenceColumn.Add(predictedOutcomeConfidenceLabel) + } else { + + neuralNetworkPredictionConfidenceString := helpers.ConvertIntToString(neuralNetworkPredictionConfidence) + predictedOutcomeConfidenceLabel := getBoldLabelCentered(neuralNetworkPredictionConfidenceString + "%") + + neuralNetworkPredictionConfidenceColumn.Add(predictedOutcomeConfidenceLabel) } - neuralNetworkPredictionConfidenceString := helpers.ConvertIntToString(neuralNetworkPredictionConfidence) - predictedOutcomeConfidenceLabel := getBoldLabel(neuralNetworkPredictionConfidenceString + "%") + traitLociList := traitObject.LociList + totalQuantityOfLoci := len(traitLociList) - return predictedOutcomeConfidenceLabel - } + quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown_NeuralNetwork) + totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci) - predictedOutcomeConfidenceLabel := getNeuralNetworkConfidenceLabel() - predictedOutcomeConfidenceLabelCentered := getWidgetCentered(predictedOutcomeConfidenceLabel) + quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString - getQuantityOfRulesTestedLabel := func()(fyne.Widget, error){ + quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted) - if (anyRulesExist == false){ + quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel) - emptyLabel := widget.NewLabel("") - return emptyLabel, nil - } + } else { traitRulesMap, err := traits.GetTraitRulesMap(traitName) - if (err != nil){ return nil, err } + if (err != nil){ return err } totalNumberOfRules := len(traitRulesMap) totalNumberOfRulesString := helpers.ConvertIntToString(totalNumberOfRules) - if (rulesAnalysisExists == false){ - quantityOfRulesTestedLabel := getItalicLabel("0/" + totalNumberOfRulesString) - return quantityOfRulesTestedLabel, nil - } - quantityOfRulesTestedString := helpers.ConvertIntToString(quantityOfRulesTested) - quantityOfRulesTestedLabel := getBoldLabel(quantityOfRulesTestedString + "/" + totalNumberOfRulesString) + quantityOfRulesTestedLabel := getBoldLabelCentered(quantityOfRulesTestedString + "/" + totalNumberOfRulesString) - return quantityOfRulesTestedLabel, nil + numberOfRulesTestedColumn.Add(quantityOfRulesTestedLabel) } - quantityOfRulesTestedLabel, err := getQuantityOfRulesTestedLabel() - if (err != nil) { return err } - - quantityOfRulesTestedLabelCentered := getWidgetCentered(quantityOfRulesTestedLabel) - viewDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ if (neuralNetworkExists == true){ //TODO @@ -2186,13 +1876,12 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe genomeNameColumn.Add(genomeNameCell) predictedOutcomeColumn.Add(predictedOutcomeLabelCentered) - neuralNetworkPredictionConfidenceColumn.Add(predictedOutcomeConfidenceLabelCentered) - numberOfRulesTestedColumn.Add(quantityOfRulesTestedLabelCentered) - viewDetailsButtonsColumn.Add(viewDetailsButton) + viewDetailsButtonsColumn.Add(viewDetailsButton) genomeNameColumn.Add(widget.NewSeparator()) predictedOutcomeColumn.Add(widget.NewSeparator()) neuralNetworkPredictionConfidenceColumn.Add(widget.NewSeparator()) + quantityOfLociKnownColumn.Add(widget.NewSeparator()) numberOfRulesTestedColumn.Add(widget.NewSeparator()) viewDetailsButtonsColumn.Add(widget.NewSeparator()) @@ -2239,6 +1928,8 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe if (err != nil){ return nil, err } } + neuralNetworkExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName) + if (neuralNetworkExists == true){ neuralNetworksHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ @@ -2264,14 +1955,21 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe }) numberOfRulesTestedColumn.Add(numberOfRulesTestedHelpButton) + quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ + //TODO + showUnderConstructionDialog(window) + }) + quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton) + genomesContainer := container.NewHBox(layout.NewSpacer(), genomeNameColumn, predictedOutcomeColumn) if (neuralNetworkExists == true){ genomesContainer.Add(neuralNetworkPredictionConfidenceColumn) + genomesContainer.Add(quantityOfLociKnownColumn) } else { genomesContainer.Add(numberOfRulesTestedColumn) } - + genomesContainer.Add(viewDetailsButtonsColumn) genomesContainer.Add(layout.NewSpacer()) @@ -2290,7 +1988,6 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe } - // Ths function provides a page to view the discrete trait rules for a particular genome from a genetic analysis func setViewPersonGenomeDiscreteTraitRulesPage(window fyne.Window, geneticAnalysisObject geneticAnalysis.PersonAnalysis, traitName string, genomeIdentifier [16]byte, genomeName string, previousPage func()){ @@ -2706,30 +2403,21 @@ func setViewPersonGeneticAnalysisNumericTraitsPage(window fyne.Window, personIde mainGenomeIdentifier, err := getMainGenomeIdentifier() if (err != nil){ return nil, err } - emptyLabel1 := widget.NewLabel("") traitNameLabel := getItalicLabelCentered("Trait Name") - emptyLabel2 := widget.NewLabel("") predictedOutcomeLabel := getItalicLabelCentered("Predicted Outcome") - quantityOfLabel := getItalicLabelCentered("Quantity Of") - lociKnownLabel := getItalicLabelCentered("Loci Known") - - emptyLabel3 := widget.NewLabel("") confidenceRangeLabel := getItalicLabelCentered("Confidence Range") - emptyLabel4 := widget.NewLabel("") conflictExistsLabel := getItalicLabelCentered("Conflict Exists?") emptyLabel5 := widget.NewLabel("") - emptyLabel6 := widget.NewLabel("") - traitNameColumn := container.NewVBox(emptyLabel1, traitNameLabel, widget.NewSeparator()) - predictedOutcomeColumn := container.NewVBox(emptyLabel2, predictedOutcomeLabel, widget.NewSeparator()) - confidenceRangeColumn := container.NewVBox(emptyLabel3, confidenceRangeLabel, widget.NewSeparator()) - quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel, lociKnownLabel, widget.NewSeparator()) - conflictExistsColumn := container.NewVBox(emptyLabel4, conflictExistsLabel, widget.NewSeparator()) - viewButtonsColumn := container.NewVBox(emptyLabel5, emptyLabel6, widget.NewSeparator()) + traitNameColumn := container.NewVBox(traitNameLabel, widget.NewSeparator()) + predictedOutcomeColumn := container.NewVBox(predictedOutcomeLabel, widget.NewSeparator()) + confidenceRangeColumn := container.NewVBox(confidenceRangeLabel, widget.NewSeparator()) + conflictExistsColumn := container.NewVBox(conflictExistsLabel, widget.NewSeparator()) + viewButtonsColumn := container.NewVBox(emptyLabel5, widget.NewSeparator()) traitObjectsList, err := traits.GetTraitObjectsList() if (err != nil) { return nil, err } @@ -2759,25 +2447,28 @@ func setViewPersonGeneticAnalysisNumericTraitsPage(window fyne.Window, personIde continue } - analysisExists, predictedOutcome, confidenceRangesMap, quantityOfLociKnown, _, conflictExists, err := readGeneticAnalysis.GetPersonNumericTraitInfoFromGeneticAnalysis(analysisObject, traitName, mainGenomeIdentifier) + analysisExists, predictedOutcome, confidenceRangesMap, _, _, conflictExists, err := readGeneticAnalysis.GetPersonNumericTraitInfoFromGeneticAnalysis(analysisObject, traitName, mainGenomeIdentifier) if (err != nil) { return nil, err } - getPredictionLabel := func()fyne.Widget{ + outcomeFormatter := traitObject.NumericValueFormatter + + getPredictionLabel := func()(fyne.Widget, error){ if (analysisExists == false){ result := getItalicLabel("Unknown") - return result + return result, nil } - predictedOutcomeString := helpers.ConvertFloat64ToStringRounded(predictedOutcome, 2) + predictedOutcomeString, err := outcomeFormatter(predictedOutcome, true) + if (err != nil) { return nil, err } - //TODO: Fix units - result := getBoldLabel(predictedOutcomeString + " centimeters") + result := getBoldLabel(predictedOutcomeString) - return result + return result, nil } - predictionLabel := getPredictionLabel() + predictionLabel, err := getPredictionLabel() + if (err != nil) { return nil, err } predictionLabelCentered := getWidgetCentered(predictionLabel) @@ -2804,11 +2495,12 @@ func setViewPersonGeneticAnalysisNumericTraitsPage(window fyne.Window, personIde return nil, errors.New("GetListOfMapKeys returning list of elements which contains element which is not in the map.") } - closestConfidenceDistanceString := helpers.ConvertFloat64ToStringRounded(closestToEightyPercentageConfidenceDistance, 2) + closestConfidenceDistanceString, err := outcomeFormatter(closestToEightyPercentageConfidenceDistance, false) + if (err != nil) { return nil, err } closestToEightyPercentageString := helpers.ConvertIntToString(closestToEightyPercentage) - confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "% Confidence)" + confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)" confidenceRangeLabel := getBoldLabel(confidenceRangeLabelValueFormatted) @@ -2820,34 +2512,22 @@ func setViewPersonGeneticAnalysisNumericTraitsPage(window fyne.Window, personIde confidenceRangeLabelCentered := getWidgetCentered(confidenceRangeLabel) - totalQuantityOfLoci := len(traitLociList) - - quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown) - totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci) - - quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString - - quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted) - conflictExistsString := helpers.ConvertBoolToYesOrNoString(conflictExists) conflictExistsLabel := getBoldLabelCentered(conflictExistsString) viewDetailsButton := getWidgetCentered(widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ - showUnderConstructionDialog(window) - //TODO + setViewPersonGeneticAnalysisNumericTraitDetailsPage(window, personIdentifier, analysisObject, traitName, currentPage) })) traitNameColumn.Add(traitNameText) predictedOutcomeColumn.Add(predictionLabelCentered) confidenceRangeColumn.Add(confidenceRangeLabelCentered) - quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel) conflictExistsColumn.Add(conflictExistsLabel) viewButtonsColumn.Add(viewDetailsButton) traitNameColumn.Add(widget.NewSeparator()) predictedOutcomeColumn.Add(widget.NewSeparator()) confidenceRangeColumn.Add(widget.NewSeparator()) - quantityOfLociKnownColumn.Add(widget.NewSeparator()) conflictExistsColumn.Add(widget.NewSeparator()) viewButtonsColumn.Add(widget.NewSeparator()) } @@ -2864,13 +2544,7 @@ func setViewPersonGeneticAnalysisNumericTraitsPage(window fyne.Window, personIde }) confidenceRangeColumn.Add(confidenceRangeHelpButton) - quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - //TODO - showUnderConstructionDialog(window) - }) - quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton) - - traitsContainer := container.NewHBox(layout.NewSpacer(), traitNameColumn, predictedOutcomeColumn, confidenceRangeColumn, quantityOfLociKnownColumn) + traitsContainer := container.NewHBox(layout.NewSpacer(), traitNameColumn, predictedOutcomeColumn, confidenceRangeColumn) if (multipleGenomesExist == true){ @@ -2900,3 +2574,261 @@ func setViewPersonGeneticAnalysisNumericTraitsPage(window fyne.Window, personIde } + +func setViewPersonGeneticAnalysisNumericTraitDetailsPage(window fyne.Window, personIdentifier string, analysisObject geneticAnalysis.PersonAnalysis, traitName string, previousPage func()){ + + currentPage := func(){setViewPersonGeneticAnalysisNumericTraitDetailsPage(window, personIdentifier, analysisObject, traitName, previousPage)} + + title := getPageTitleCentered("Viewing Genetic Analysis - " + traitName) + + backButton := getBackButtonCentered(previousPage) + + allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject) + if (err != nil) { + setErrorEncounteredPage(window, err, previousPage) + return + } + + getDescriptionSection := func()*fyne.Container{ + + if (multipleGenomesExist == false){ + description := getLabelCentered("Below is the trait information for this person's genome.") + + return description + } + + description1 := getLabelCentered("Below is the trait information for this person's genomes.") + description2 := getLabelCentered("The first two genomes are created by combining multiple genomes.") + + descriptionsSection := container.NewVBox(description1, description2) + + return descriptionsSection + } + + descriptionSection := getDescriptionSection() + + traitNameLabel := widget.NewLabel("Trait:") + traitNameText := getBoldLabel(traitName) + traitInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ + setViewTraitDetailsPage(window, traitName, currentPage) + }) + traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameLabel, traitNameText, traitInfoButton, layout.NewSpacer()) + + getGenomesContainer := func()(*fyne.Container, error){ + + traitObject, err := traits.GetTraitObject(traitName) + if (err != nil){ return nil, err } + + traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric + if (traitIsDiscreteOrNumeric != "Numeric"){ + return nil, errors.New("setViewPersonGeneticAnalysisNumericTraitDetailsPage called with non-numeric trait: " + traitName) + } + + traitLociList := traitObject.LociList + + totalQuantityOfLoci := len(traitLociList) + totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci) + + emptyLabel1 := widget.NewLabel("") + genomeNameLabel := getItalicLabelCentered("Genome Name") + + emptyLabel2 := widget.NewLabel("") + predictedOutcomeLabel := getItalicLabelCentered("Predicted Outcome") + + emptyLabel3 := widget.NewLabel("") + predictionConfidenceLabel := getItalicLabelCentered("Confidence Range") + + quantityOfLabel := getItalicLabelCentered("Quantity of") + lociKnownLabel := getItalicLabelCentered("Loci Known") + + emptyLabel4 := widget.NewLabel("") + emptyLabel5 := widget.NewLabel("") + + genomeNameColumn := container.NewVBox(emptyLabel1, genomeNameLabel, widget.NewSeparator()) + predictedOutcomeColumn := container.NewVBox(emptyLabel2, predictedOutcomeLabel, widget.NewSeparator()) + predictionConfidenceColumn := container.NewVBox(emptyLabel3, predictionConfidenceLabel, widget.NewSeparator()) + quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel, lociKnownLabel, widget.NewSeparator()) + viewDetailsButtonsColumn := container.NewVBox(emptyLabel4, emptyLabel5, widget.NewSeparator()) + + addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{ + + getGenomeNameCell := func()*fyne.Container{ + if (isACombinedGenome == false){ + + genomeNameLabel := getBoldLabelCentered(genomeName) + return genomeNameLabel + } + viewHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ + setCombinedGenomesExplainerPage(window, currentPage) + }) + + genomeNameLabel := getBoldLabel(genomeName) + genomeNameCell := container.NewHBox(layout.NewSpacer(), viewHelpButton, genomeNameLabel, layout.NewSpacer()) + + return genomeNameCell + } + + genomeNameCell := getGenomeNameCell() + + analysisExists, predictedOutcome, predictionConfidenceRangesMap, quantityOfLociKnown, _, _, err := readGeneticAnalysis.GetPersonNumericTraitInfoFromGeneticAnalysis(analysisObject, traitName, genomeIdentifier) + if (err != nil) { return err } + + outcomeFormatter := traitObject.NumericValueFormatter + + getPredictedOutcomeLabel := func()(fyne.Widget, error){ + + if (analysisExists == false){ + + result := widget.NewLabel(translate("Unknown")) + + return result, nil + } + + outcomeFormatted, err := outcomeFormatter(predictedOutcome, true) + if (err != nil) { return nil, err } + + outcomeLabel := getBoldLabel(outcomeFormatted) + + return outcomeLabel, nil + } + + predictedOutcomeLabel, err := getPredictedOutcomeLabel() + if (err != nil) { return err } + predictedOutcomeLabelCentered := getWidgetCentered(predictedOutcomeLabel) + + getConfidenceRangeLabel := func()(fyne.Widget, error){ + + if (analysisExists == false){ + unknownLabel := widget.NewLabel("Unknown") + return unknownLabel, nil + } + + // This is a list of the percentage accuracies in the map + // For example: 80% == The distance from the prediction you must travel for 80% of the predictions to be + // accurate within that range + confidenceRangePercentagesList := helpers.GetListOfMapKeys(predictionConfidenceRangesMap) + + // We sort the list so the percentage is always the same upon refreshing the page + slices.Sort(confidenceRangePercentagesList) + + closestToEightyPercentage, err := helpers.GetClosestIntInList(confidenceRangePercentagesList, 80) + if (err != nil) { return nil, err } + + closestToEightyPercentageConfidenceDistance, exists := predictionConfidenceRangesMap[closestToEightyPercentage] + if (exists == false){ + return nil, errors.New("GetListOfMapKeys returning list of elements which contains element which is not in the map.") + } + + closestConfidenceDistanceString, err := outcomeFormatter(closestToEightyPercentageConfidenceDistance, false) + if (err != nil) { return nil, err } + + closestToEightyPercentageString := helpers.ConvertIntToString(closestToEightyPercentage) + + confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)" + + confidenceRangeLabel := getBoldLabel(confidenceRangeLabelValueFormatted) + + return confidenceRangeLabel, nil + } + + confidenceRangeLabel, err := getConfidenceRangeLabel() + if (err != nil) { return err } + + confidenceRangeLabelCentered := getWidgetCentered(confidenceRangeLabel) + + genomeQuantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown) + quantityOfLociKnownLabel := getBoldLabelCentered(genomeQuantityOfLociKnownString + "/" + totalQuantityOfLociString) + + viewDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ + //TODO + showUnderConstructionDialog(window) + }) + + genomeNameColumn.Add(genomeNameCell) + predictedOutcomeColumn.Add(predictedOutcomeLabelCentered) + predictionConfidenceColumn.Add(confidenceRangeLabelCentered) + quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel) + viewDetailsButtonsColumn.Add(viewDetailsButton) + + genomeNameColumn.Add(widget.NewSeparator()) + predictedOutcomeColumn.Add(widget.NewSeparator()) + predictionConfidenceColumn.Add(widget.NewSeparator()) + quantityOfLociKnownColumn.Add(widget.NewSeparator()) + viewDetailsButtonsColumn.Add(widget.NewSeparator()) + + return nil + } + + if (multipleGenomesExist == true){ + + err := addGenomeRow("Only Exclude Conflicts", onlyExcludeConflictsGenomeIdentifier, true) + if (err != nil){ return nil, err } + + err = addGenomeRow("Only Include Shared", onlyIncludeSharedGenomeIdentifier, true) + if (err != nil){ return nil, err } + } + + for _, genomeIdentifier := range allRawGenomeIdentifiersList{ + + getGenomeName := func()(string, error){ + genomeFound, _, timeGenomeWasExported, _, _, _, companyName, _, _, err := myGenomes.GetMyRawGenomeMetadata(genomeIdentifier) + if (err != nil) { return "", err } + if (genomeFound == false){ + return "", errors.New("MyGenomeInfo for genome from analysisObject not found.") + } + + if (multipleGenomesExist == false){ + return companyName, nil + } + + // We show the date the genome was exported + + exportTimeAgo, err := helpers.ConvertUnixTimeToTimeAgoTranslated(timeGenomeWasExported, false) + if (err != nil){ return "", err } + + genomeName := companyName + " (Exported " + exportTimeAgo + ")" + + return genomeName, nil + } + + genomeName, err := getGenomeName() + if (err != nil) { return nil, err } + + err = addGenomeRow(genomeName, genomeIdentifier, false) + if (err != nil){ return nil, err } + } + + predictedOutcomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ + showUnderConstructionDialog(window) + //TODO + }) + predictedOutcomeColumn.Add(predictedOutcomeHelpButton) + + predictionConfidenceHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ + showUnderConstructionDialog(window) + }) + predictionConfidenceColumn.Add(predictionConfidenceHelpButton) + + quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ + //TODO + showUnderConstructionDialog(window) + }) + quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton) + + genomesContainer := container.NewHBox(layout.NewSpacer(), genomeNameColumn, predictedOutcomeColumn, predictionConfidenceColumn, quantityOfLociKnownColumn, viewDetailsButtonsColumn, layout.NewSpacer()) + + return genomesContainer, nil + } + + genomesContainer, err := getGenomesContainer() + if (err != nil){ + setErrorEncounteredPage(window, err, previousPage) + return + } + + page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), traitNameRow, widget.NewSeparator(), genomesContainer) + + setPageContent(page, window) +} + + diff --git a/gui/viewGeneticReferencesGui.go b/gui/viewGeneticReferencesGui.go index 8fa57fa..e6452b2 100644 --- a/gui/viewGeneticReferencesGui.go +++ b/gui/viewGeneticReferencesGui.go @@ -1,4 +1,3 @@ - package gui // viewGeneticReferencesGui.go implements pages to display information about genetic diseases and traits @@ -245,217 +244,6 @@ func setViewPolygenicDiseaseDetailsPage(window fyne.Window, diseaseName string, } -func setViewPolygenicDiseaseLocusDetailsPage(window fyne.Window, diseaseName string, locusIdentifier string, previousPage func()){ - - currentPage := func(){setViewPolygenicDiseaseLocusDetailsPage(window, diseaseName, locusIdentifier, previousPage)} - - title := getPageTitleCentered("Viewing Locus Details") - - backButton := getBackButtonCentered(previousPage) - - locusObject, err := polygenicDiseases.GetPolygenicDiseaseLocusObject(diseaseName, locusIdentifier) - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return - } - - locusRSID := locusObject.LocusRSID - locusReferencesMap := locusObject.References - - locusRSIDsList := []int64{locusRSID} - - // We add aliases to locusRSIDsList - - anyAliasesExist, rsidAliasesList, err := locusMetadata.GetRSIDAliases(locusRSID) - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return - } - if (anyAliasesExist == true){ - locusRSIDsList = append(locusRSIDsList, rsidAliasesList...) - } - - metadataExists, locusMetadataObject, err := locusMetadata.GetLocusMetadata(locusRSID) - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return - } - if (metadataExists == false){ - setErrorEncounteredPage(window, errors.New("setViewPolygenicDiseaseLocusDetailsPage called with locusRSID missing from locusMetadata."), previousPage) - return - } - - diseaseNameLabel := widget.NewLabel("Disease Name:") - diseaseNameText := getBoldLabel(diseaseName) - diseaseNameRow := container.NewHBox(layout.NewSpacer(), diseaseNameLabel, diseaseNameText, layout.NewSpacer()) - - getLocusNamesLabelText := func()string{ - - if(len(locusRSIDsList) == 1){ - return "Locus Name:" - } - return "Locus Names:" - } - - locusNamesLabelText := getLocusNamesLabelText() - - locusRSIDStringsList := make([]string, 0, len(locusRSIDsList)) - - for _, locusRSID := range locusRSIDsList{ - - locusRSIDString := helpers.ConvertInt64ToString(locusRSID) - - locusRSIDName := "rs" + locusRSIDString - - locusRSIDStringsList = append(locusRSIDStringsList, locusRSIDName) - } - - locusNamesListString := strings.Join(locusRSIDStringsList, ", ") - locusNamesLabel := widget.NewLabel(locusNamesLabelText) - locusNamesText := getBoldLabel(locusNamesListString) - locusNamesRow := container.NewHBox(layout.NewSpacer(), locusNamesLabel, locusNamesText, layout.NewSpacer()) - - getLocusGeneNameLabelValue := func()string{ - - locusGeneInfoIsKnown := locusMetadataObject.GeneInfoIsKnown - if (locusGeneInfoIsKnown == false){ - return "Unknown" - } - - locusGeneExists := locusMetadataObject.GeneExists - if (locusGeneExists == false){ - return "None" - } - - locusGeneName := locusMetadataObject.GeneNamesList[0] - - return locusGeneName - } - - locusGeneNameLabelValue := getLocusGeneNameLabelValue() - - geneNameLabel := widget.NewLabel("Gene Name:") - geneNameText := getBoldLabel(locusGeneNameLabelValue) - geneNameRow := container.NewHBox(layout.NewSpacer(), geneNameLabel, geneNameText, layout.NewSpacer()) - - viewReferencesButton := getWidgetCentered(widget.NewButtonWithIcon("View References", theme.ListIcon(), func(){ - setViewGeneticAnalysisReferencesPage(window, "Locus", locusReferencesMap, currentPage) - })) - - getBasePairsGrid := func()(*fyne.Container, error){ - - locusRiskWeightsMap := locusObject.RiskWeightsMap - locusBasePairProbabilitiesMap := locusObject.BasePairProbabilitiesMap - - riskWeightLabel := getItalicLabelCentered("Risk Weight") - probabilityLabel := getItalicLabelCentered("Probability Of Weight") - - riskWeightColumn := container.NewVBox(riskWeightLabel, widget.NewSeparator()) - riskWeightProbabilityColumn := container.NewVBox(probabilityLabel, widget.NewSeparator()) - - // We create a new map with duplicates removed - - locusBasePairProbabilitiesMap_DuplicatesRemoved := make(map[string]float64) - - for basePair, basePairProbability := range locusBasePairProbabilitiesMap{ - - baseA, baseB, semicolonFound := strings.Cut(basePair, ";") - if (semicolonFound == false) { - return nil, errors.New("Invalid base pair found in locusBasePairProbabilitiesMap: " + basePair) - } - basePairDuplicate := baseB + ";" + baseA - - existingProbabilityValue, exists := locusBasePairProbabilitiesMap_DuplicatesRemoved[basePairDuplicate] - if (exists == true){ - - // The duplicate has already been added. - // We make sure the probability values match - if (existingProbabilityValue != basePairProbability){ - return nil, errors.New("locusBasePairProbabilitiesMap contains duplicate base pair with different value") - } - continue - } - locusBasePairProbabilitiesMap_DuplicatesRemoved[basePair] = basePairProbability - } - - // All probabilities are mutually exclusive (you can only have 1 base pair for each genome locus) - // Thus, we can add them together to get a total probability for each risk weight - - // Map structure: Risk Weight -> Probability of having weight - riskWeightProbabilitiesMap := make(map[int]float64) - - for basePair, basePairProbability := range locusBasePairProbabilitiesMap_DuplicatesRemoved{ - - getBasePairRiskWeight := func()int{ - - basePairRiskWeight, exists := locusRiskWeightsMap[basePair] - if (exists == false){ - // This base pair has no known weight. We treat it as a 0 weight. - return 0 - } - return basePairRiskWeight - } - - basePairRiskWeight := getBasePairRiskWeight() - - riskWeightProbabilitiesMap[basePairRiskWeight] += basePairProbability - } - - // Now we sort risk weights in order of least to greatest - allRiskWeightsList := helpers.GetListOfMapKeys(riskWeightProbabilitiesMap) - - slices.Sort(allRiskWeightsList) - - for _, riskWeight := range allRiskWeightsList{ - - riskWeightProbability, exists := riskWeightProbabilitiesMap[riskWeight] - if (exists == false){ - return nil, errors.New("Risk weight probability not found in riskWeightProbabilitiesMap") - } - - riskWeightString := helpers.ConvertIntToString(riskWeight) - - riskWeightPercentageProbability := riskWeightProbability * 100 - riskWeightProbabilityString := helpers.ConvertFloat64ToStringRounded(riskWeightPercentageProbability, 2) - riskWeightProbabilityFormatted := "~" + riskWeightProbabilityString + "%" - - riskWeightText := getBoldLabelCentered(riskWeightString) - riskWeightProbabilityText := getBoldLabelCentered(riskWeightProbabilityFormatted) - - riskWeightColumn.Add(riskWeightText) - riskWeightProbabilityColumn.Add(riskWeightProbabilityText) - - riskWeightColumn.Add(widget.NewSeparator()) - riskWeightProbabilityColumn.Add(widget.NewSeparator()) - } - - riskWeightHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setPolygenicDiseaseLocusRiskWeightExplainerPage(window, currentPage) - }) - riskWeightColumn.Add(riskWeightHelpButton) - - probabilityHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setPolygenicDiseaseLocusRiskWeightProbabilityExplainerPage(window, currentPage) - }) - riskWeightProbabilityColumn.Add(probabilityHelpButton) - - basePairsGrid := container.NewHBox(layout.NewSpacer(), riskWeightColumn, riskWeightProbabilityColumn, layout.NewSpacer()) - - return basePairsGrid, nil - } - - basePairsGrid, err := getBasePairsGrid() - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return - } - - page := container.NewVBox(title, backButton, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), locusNamesRow, widget.NewSeparator(), geneNameRow, widget.NewSeparator(), viewReferencesButton, widget.NewSeparator(), basePairsGrid) - - setPageContent(page, window) -} - - func setViewGeneticAnalysisReferencesPage(window fyne.Window, referencesTopic string, referencesMap map[string]string, previousPage func()){ currentPage := func(){setViewGeneticAnalysisReferencesPage(window, referencesTopic, referencesMap, previousPage)} @@ -644,5 +432,3 @@ func setViewDiscreteTraitRuleDetailsPage(window fyne.Window, traitName string, r - - diff --git a/gui/viewProfileGui.go b/gui/viewProfileGui.go index 849591c..89ece49 100644 --- a/gui/viewProfileGui.go +++ b/gui/viewProfileGui.go @@ -2370,6 +2370,8 @@ func setViewMateProfilePage_AncestryComposition(window fyne.Window, userOrOffspr // This is a page to view the total monogenic disease risk for a user's offspring func setViewMateProfilePage_TotalDiseaseRisk(window fyne.Window, getAnyUserProfileAttributeFunction func(string)(bool, int, string, error), previousPage func()){ + setLoadingScreen(window, "View Profile - Physical", "Computing Genetic Analysis...") + title := getPageTitleCentered(translate("View Profile - Physical")) backButton := getBackButtonCentered(previousPage) @@ -2499,7 +2501,15 @@ func setViewMateProfilePage_TotalDiseaseRisk(window fyne.Window, getAnyUserProfi return } - totalNumberOfPolygenicDiseases := len(allPolygenicDiseaseNamesList) + // We count up every disease that has a prediction model + totalNumberOfPolygenicDiseases := 0 + + for _, diseaseName := range allPolygenicDiseaseNamesList{ + predictionModelExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(diseaseName) + if (predictionModelExists == true){ + totalNumberOfPolygenicDiseases += 1 + } + } totalNumberOfPolygenicDiseasesString := helpers.ConvertIntToString(totalNumberOfPolygenicDiseases) @@ -2891,6 +2901,10 @@ func setViewMateProfilePage_MonogenicDiseases(window fyne.Window, userOrOffsprin func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffspring string, getAnyUserProfileAttributeFunction func(string)(bool, int, string, error), previousPage func()){ + if (userOrOffspring == "Offspring"){ + setLoadingScreen(window, "View Profile - Physical", "Computing Genetic Analysis...") + } + currentPage := func(){setViewMateProfilePage_PolygenicDiseases(window, userOrOffspring, getAnyUserProfileAttributeFunction, previousPage)} title := getPageTitleCentered(translate("View Profile - Physical")) @@ -2917,38 +2931,92 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin getDiseaseInfoGrid := func()(*fyne.Container, error){ - emptyLabel1 := widget.NewLabel("") diseaseNameLabel := getItalicLabelCentered("Disease Name") - emptyLabel2 := widget.NewLabel("") userRiskScoreLabel := getItalicLabelCentered("User Risk Score") - emptyLabel3 := widget.NewLabel("") offspringRiskScoreLabel := getItalicLabelCentered("Offspring Risk Score") - userNumberOfLabel := getItalicLabelCentered("User Number Of") - lociTestedLabelA := getItalicLabelCentered("Loci Tested") + confidenceRangeLabel := getItalicLabelCentered("Confidence Range") - offspringNumberOfLabel := getItalicLabelCentered("Offspring Number Of") - lociTestedLabelB := getItalicLabelCentered("Loci Tested") + emptyLabel1 := widget.NewLabel("") - emptyLabel4 := widget.NewLabel("") - emptyLabel5 := widget.NewLabel("") + emptyLabel2 := widget.NewLabel("") - emptyLabel6 := widget.NewLabel("") - emptyLabel7 := widget.NewLabel("") + diseaseNameColumn := container.NewVBox(diseaseNameLabel, widget.NewSeparator()) + userRiskScoreColumn := container.NewVBox(userRiskScoreLabel, widget.NewSeparator()) + offspringRiskScoreColumn := container.NewVBox(offspringRiskScoreLabel, widget.NewSeparator()) + confidenceRangeColumn := container.NewVBox(confidenceRangeLabel, widget.NewSeparator()) + viewSampleOffspringsChartButtonsColumn := container.NewVBox(emptyLabel1, widget.NewSeparator()) + viewDiseaseInfoButtonsColumn := container.NewVBox(emptyLabel2, widget.NewSeparator()) - diseaseNameColumn := container.NewVBox(emptyLabel1, diseaseNameLabel, widget.NewSeparator()) - userRiskScoreColumn := container.NewVBox(emptyLabel2, userRiskScoreLabel, widget.NewSeparator()) - offspringRiskScoreColumn := container.NewVBox(emptyLabel3, offspringRiskScoreLabel, widget.NewSeparator()) - userNumberOfLociTestedColumn := container.NewVBox(userNumberOfLabel, lociTestedLabelA, widget.NewSeparator()) - offspringNumberOfLociTestedColumn := container.NewVBox(offspringNumberOfLabel, lociTestedLabelB, widget.NewSeparator()) - viewSampleOffspringsChartButtonsColumn := container.NewVBox(emptyLabel4, emptyLabel5, widget.NewSeparator()) - viewDiseaseInfoButtonsColumn := container.NewVBox(emptyLabel6, emptyLabel7, widget.NewSeparator()) + //Outputs: + // -map[int64]locusValue.LocusValue + // -error + getMyGenomeLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){ - myPersonChosen, myGenomesExist, myAnalysisIsReady, myAnalysisObject, myGenomeIdentifier, _, err := myChosenAnalysis.GetMyChosenMateGeneticAnalysis() + if (userOrOffspring == "User"){ + // We don't need to retrieve our locus values map + emptyMap := make(map[int64]locusValue.LocusValue) + return emptyMap, nil + } + + myPersonChosen, myGenomesExist, myAnalysisIsReady, myAnalysisObject, myGenomeIdentifier, _, err := myChosenAnalysis.GetMyChosenMateGeneticAnalysis() + if (err != nil) { return nil, err } + + if (myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false){ + emptyMap := make(map[int64]locusValue.LocusValue) + return emptyMap, nil + } + + _, _, _, _, myGenomesMap, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myAnalysisObject) + if (err != nil) { return nil, err } + + myGenomeLocusValuesMap, exists := myGenomesMap[myGenomeIdentifier] + if (exists == false){ + return nil, errors.New("GetMyChosenMateGeneticAnalysis returning analysis which is missing genome with myGenomeIdentifier.") + } + + return myGenomeLocusValuesMap, nil + } + + myGenomeLocusValuesMap, err := getMyGenomeLocusValuesMap() if (err != nil) { return nil, err } + getConfidenceRangeLabel := func(analysisExists bool, predictionConfidenceRangesMap map[int]float64)(fyne.Widget, error){ + if (analysisExists == false){ + + result := widget.NewLabel("Unknown") + return result, nil + } + + // This is a list of the percentage accuracies in the map + // For example: 80% == The distance from the prediction you must travel for 80% of the predictions to be + // accurate within that range + confidenceRangePercentagesList := helpers.GetListOfMapKeys(predictionConfidenceRangesMap) + + // We sort the list so the percentage is always the same upon refreshing the page + slices.Sort(confidenceRangePercentagesList) + + closestToEightyPercentage, err := helpers.GetClosestIntInList(confidenceRangePercentagesList, 80) + if (err != nil) { return nil, err } + + closestToEightyPercentageConfidenceDistance, exists := predictionConfidenceRangesMap[closestToEightyPercentage] + if (exists == false){ + return nil, errors.New("GetListOfMapKeys returning list of elements which contains element which is not in the map.") + } + + closestConfidenceDistanceString := helpers.ConvertFloat64ToStringRounded(closestToEightyPercentageConfidenceDistance, 2) + + closestToEightyPercentageString := helpers.ConvertIntToString(closestToEightyPercentage) + + confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)" + + confidenceRangeLabel := getBoldLabel(confidenceRangeLabelValueFormatted) + + return confidenceRangeLabel, nil + } + diseaseObjectsList, err := polygenicDiseases.GetPolygenicDiseaseObjectsList() if (err != nil) { return nil, err } @@ -2957,36 +3025,18 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin diseaseName := diseaseObject.DiseaseName diseaseLociList := diseaseObject.LociList - //Outputs: - // -map[int64]locusValue.LocusValue - // -error - getMyGenomeLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){ - - if (myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false){ - emptyMap := make(map[int64]locusValue.LocusValue) - return emptyMap, nil - } - - _, _, _, _, myGenomesMap, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myAnalysisObject) - if (err != nil) { return nil, err } - - myGenomeLocusValuesMap, exists := myGenomesMap[myGenomeIdentifier] - if (exists == false){ - return nil, errors.New("GetMyChosenMateGeneticAnalysis returning analysis which is missing genome with myGenomeIdentifier.") - } - - return myGenomeLocusValuesMap, nil + predictionModelExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(diseaseName) + if (predictionModelExists == false){ + // Prediction is not possible for this disease + continue } - myGenomeLocusValuesMap, err := getMyGenomeLocusValuesMap() - if (err != nil) { return nil, err } + diseaseNameLabel := getBoldLabelCentered(diseaseName) // Map Structure: Locus rsID -> Locus Value userDiseaseLocusValuesMap := make(map[int64]locusValue.LocusValue) - for _, locusObject := range diseaseLociList{ - - locusRSID := locusObject.LocusRSID + for _, locusRSID := range diseaseLociList{ locusRSIDString := helpers.ConvertInt64ToString(locusRSID) @@ -3023,81 +3073,100 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin userDiseaseLocusValuesMap[locusRSID] = userLocusValueObject } - userDiseaseInfoIsKnown, userDiseaseRiskScore, userNumberOfLociTested, _, err := createPersonGeneticAnalysis.GetPersonGenomePolygenicDiseaseInfo(diseaseLociList, userDiseaseLocusValuesMap, true) - if (err != nil) { return nil, err } + if (userOrOffspring == "User"){ - getUserDiseaseRiskScoreString := func()(string, error){ - - if (userDiseaseInfoIsKnown == false){ - result := translate("Unknown") - - return result, nil - } - - userRiskScoreString := helpers.ConvertIntToString(userDiseaseRiskScore) - resultFormatted := userRiskScoreString + "/10" - - return resultFormatted, nil - } - - userDiseaseRiskScoreString, err := getUserDiseaseRiskScoreString() - if (err != nil) { return nil, err } - - anyOffspringLociTested, offspringDiseaseRiskScore, offspringNumberOfLociTested, _, offspringSampleRiskScoresList, err := createCoupleGeneticAnalysis.GetOffspringPolygenicDiseaseInfo(diseaseLociList, myGenomeLocusValuesMap, userDiseaseLocusValuesMap) - if (err != nil) { return nil, err } - - getOffspringDiseaseRiskScoreFormatted := func()(string, error){ - - if (anyOffspringLociTested == false){ - result := translate("Unknown") - - return result, nil + neuralNetworkExists, analysisExists, userDiseaseRiskScore, predictionConfidenceRangesMap, _, _, err := createPersonGeneticAnalysis.GetPersonGenomePolygenicDiseaseAnalysis(diseaseObject, userDiseaseLocusValuesMap, true) + if (err != nil) { return nil, err } + if (neuralNetworkExists == false){ + return nil, errors.New("GetPersonGenomePolygenicDiseaseAnalysis claims model doesn't exist when we already checked.") } - offspringRiskScoreString := helpers.ConvertIntToString(offspringDiseaseRiskScore) - resultFormatted := offspringRiskScoreString + "/10" - return resultFormatted, nil + getUserDiseaseRiskScoreLabel := func()fyne.Widget{ + + if (analysisExists == false){ + + result := widget.NewLabel(translate("Unknown")) + + return result + } + + userRiskScoreString := helpers.ConvertIntToString(userDiseaseRiskScore) + riskScoreFormatted := userRiskScoreString + "/10" + + riskScoreLabel := getBoldLabel(riskScoreFormatted) + + return riskScoreLabel + } + + userDiseaseRiskScoreLabel := getUserDiseaseRiskScoreLabel() + userDiseaseRiskScoreLabelCentered := getWidgetCentered(userDiseaseRiskScoreLabel) + userRiskScoreColumn.Add(userDiseaseRiskScoreLabelCentered) + + confidenceRangeLabel, err := getConfidenceRangeLabel(analysisExists, predictionConfidenceRangesMap) + if (err != nil) { return nil, err } + + confidenceRangeLabelCentered := getWidgetCentered(confidenceRangeLabel) + + confidenceRangeColumn.Add(confidenceRangeLabelCentered) + + } else if (userOrOffspring == "Offspring"){ + + neuralNetworkExists, anyOffspringLociKnown, offspringDiseaseRiskScore, predictionConfidenceRangesMap, offspringSampleRiskScoresList, offspringQuantityOfLociKnown, _, err := createCoupleGeneticAnalysis.GetOffspringPolygenicDiseaseAnalysis(diseaseObject, myGenomeLocusValuesMap, userDiseaseLocusValuesMap) + if (err != nil) { return nil, err } + if (neuralNetworkExists == false){ + return nil, errors.New("GetOffspringPolygenicDiseaseAnalysis claims that neural network doesn't exist when we already checked.") + } + + getOffspringDiseaseRiskScoreLabel := func()fyne.Widget{ + + if (anyOffspringLociKnown == false){ + + result := widget.NewLabel(translate("Unknown")) + + return result + } + + offspringRiskScoreString := helpers.ConvertIntToString(offspringDiseaseRiskScore) + riskScoreFormatted := offspringRiskScoreString + "/10" + + riskScoreLabel := getBoldLabel(riskScoreFormatted) + + return riskScoreLabel + } + + offspringDiseaseRiskScoreLabel := getOffspringDiseaseRiskScoreLabel() + offspringDiseaseRiskScoreLabelCentered := getWidgetCentered(offspringDiseaseRiskScoreLabel) + + offspringRiskScoreColumn.Add(offspringDiseaseRiskScoreLabelCentered) + + confidenceRangeLabel, err := getConfidenceRangeLabel(anyOffspringLociKnown, predictionConfidenceRangesMap) + if (err != nil) { return nil, err } + + confidenceRangeLabelCentered := getWidgetCentered(confidenceRangeLabel) + + confidenceRangeColumn.Add(confidenceRangeLabelCentered) + + viewSampleOffspringsChartButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ + + setViewPolygenicDiseaseSampleOffspringRiskScoresChart(window, diseaseName, offspringSampleRiskScoresList, offspringQuantityOfLociKnown, currentPage) + }) + + viewSampleOffspringsChartButtonsColumn.Add(viewSampleOffspringsChartButton) } - offspringDiseaseRiskScoreFormatted, err := getOffspringDiseaseRiskScoreFormatted() - if (err != nil) { return nil, err } - - totalNumberOfDiseaseLoci := len(diseaseLociList) - totalNumberOfDiseaseLociString := helpers.ConvertIntToString(totalNumberOfDiseaseLoci) - - userNumberOfLociTestedString := helpers.ConvertIntToString(userNumberOfLociTested) - userNumberOfLociTestedFormatted := userNumberOfLociTestedString + "/" + totalNumberOfDiseaseLociString - offspringNumberOfLociTestedString := helpers.ConvertIntToString(offspringNumberOfLociTested) - offspringNumberOfLociTestedFormatted := offspringNumberOfLociTestedString + "/" + totalNumberOfDiseaseLociString - - diseaseNameText := getBoldLabelCentered(diseaseName) - userRiskScoreLabel := getBoldLabelCentered(userDiseaseRiskScoreString) - offspringRiskScoreLabel := getBoldLabelCentered(offspringDiseaseRiskScoreFormatted) - userNumberOfLociTestedLabel := getBoldLabelCentered(userNumberOfLociTestedFormatted) - offspringNumberOfLociTestedLabel := getBoldLabelCentered(offspringNumberOfLociTestedFormatted) - - viewSampleOffspringsChartButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ - - setViewPolygenicDiseaseSampleOffspringRiskScoresChart(window, diseaseName, offspringSampleRiskScoresList, offspringNumberOfLociTested, currentPage) - }) - viewDiseaseDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ - setViewMateProfilePage_PolygenicDiseaseLoci(window, diseaseName, userOrOffspring, getAnyUserProfileAttributeFunction, currentPage) + //TODO + showUnderConstructionDialog(window) }) - diseaseNameColumn.Add(diseaseNameText) - userRiskScoreColumn.Add(userRiskScoreLabel) - offspringRiskScoreColumn.Add(offspringRiskScoreLabel) - userNumberOfLociTestedColumn.Add(userNumberOfLociTestedLabel) - offspringNumberOfLociTestedColumn.Add(offspringNumberOfLociTestedLabel) - viewSampleOffspringsChartButtonsColumn.Add(viewSampleOffspringsChartButton) + diseaseNameColumn.Add(diseaseNameLabel) + viewDiseaseInfoButtonsColumn.Add(viewDiseaseDetailsButton) diseaseNameColumn.Add(widget.NewSeparator()) userRiskScoreColumn.Add(widget.NewSeparator()) offspringRiskScoreColumn.Add(widget.NewSeparator()) - userNumberOfLociTestedColumn.Add(widget.NewSeparator()) - offspringNumberOfLociTestedColumn.Add(widget.NewSeparator()) + confidenceRangeColumn.Add(widget.NewSeparator()) viewSampleOffspringsChartButtonsColumn.Add(widget.NewSeparator()) viewDiseaseInfoButtonsColumn.Add(widget.NewSeparator()) } @@ -3105,30 +3174,27 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin userRiskScoreHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setPolygenicDiseaseRiskScoreExplainerPage(window, currentPage) }) + userRiskScoreColumn.Add(userRiskScoreHelpButton) offspringRiskScoreHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setOffspringPolygenicDiseaseRiskScoreExplainerPage(window, currentPage) }) - userNumberOfLociTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage) - }) - - offspringNumberOfLociTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setOffspringPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage) - }) - - userRiskScoreColumn.Add(userRiskScoreHelpButton) offspringRiskScoreColumn.Add(offspringRiskScoreHelpButton) - userNumberOfLociTestedColumn.Add(userNumberOfLociTestedHelpButton) - offspringNumberOfLociTestedColumn.Add(offspringNumberOfLociTestedHelpButton) + + confidenceRangeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ + showUnderConstructionDialog(window) + //TODO + }) + + confidenceRangeColumn.Add(confidenceRangeHelpButton) if (userOrOffspring == "User"){ - diseaseInfoGrid := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, userRiskScoreColumn, userNumberOfLociTestedColumn, viewDiseaseInfoButtonsColumn, layout.NewSpacer()) + diseaseInfoGrid := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, userRiskScoreColumn, confidenceRangeColumn, viewDiseaseInfoButtonsColumn, layout.NewSpacer()) return diseaseInfoGrid, nil } - diseaseInfoGrid := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, offspringRiskScoreColumn, offspringNumberOfLociTestedColumn, viewSampleOffspringsChartButtonsColumn, viewDiseaseInfoButtonsColumn, layout.NewSpacer()) + diseaseInfoGrid := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, offspringRiskScoreColumn, confidenceRangeColumn, viewSampleOffspringsChartButtonsColumn, viewDiseaseInfoButtonsColumn, layout.NewSpacer()) return diseaseInfoGrid, nil } @@ -3138,403 +3204,12 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin setErrorEncounteredPage(window, err, previousPage) return } - + page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), userOrOffspringSelectorCentered, widget.NewSeparator(), diseaseInfoGrid) setPageContent(page, window) } -func setViewMateProfilePage_PolygenicDiseaseLoci(window fyne.Window, diseaseName string, userOrOffspring string, getAnyUserProfileAttributeFunction func(string)(bool, int, string, error), previousPage func()){ - - setLoadingScreen(window, translate("View Profile - Physical"), "Loading " + userOrOffspring + " Disease Loci Info") - - if (userOrOffspring != "User" && userOrOffspring != "Offspring"){ - setErrorEncounteredPage(window, errors.New("setViewMateProfilePage_DiseaseLoci called with invalid userOrOffspring: " + userOrOffspring), previousPage) - return - } - - currentPage := func(){setViewMateProfilePage_PolygenicDiseaseLoci(window, diseaseName, userOrOffspring, getAnyUserProfileAttributeFunction, previousPage)} - - title := getPageTitleCentered(translate("View Profile - Physical")) - - backButton := getBackButtonCentered(previousPage) - - subtitle := getPageSubtitleCentered(translate(userOrOffspring + " Disease Loci Info")) - - diseaseNameLabel := widget.NewLabel(translate("Disease Name:")) - - diseaseNameText := getBoldLabel(translate(diseaseName)) - - viewDiseaseInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ - setViewPolygenicDiseaseDetailsPage(window, diseaseName, currentPage) - }) - - diseaseNameRow := container.NewHBox(layout.NewSpacer(), diseaseNameLabel, diseaseNameText, viewDiseaseInfoButton, layout.NewSpacer()) - - diseaseObject, err := polygenicDiseases.GetPolygenicDiseaseObject(diseaseName) - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return - } - - diseaseLocusObjectsList := diseaseObject.LociList - - numberOfDiseaseLoci := len(diseaseLocusObjectsList) - - // Outputs: - // -map[int64]locusValue.LocusValue: Map Structure: Locus rsID -> Locus Value - // -error - getMyGenomeLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){ - - myPersonChosen, myGenomesExist, myAnalysisIsReady, myAnalysisObject, myGenomeIdentifier, _, err := myChosenAnalysis.GetMyChosenMateGeneticAnalysis() - if (err != nil) { return nil, err } - - if (myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false){ - - emptyMap := make(map[int64]locusValue.LocusValue) - return emptyMap, nil - } - - _, _, _, _, myGenomesMap, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myAnalysisObject) - if (err != nil) { return nil, err } - - myGenomeLocusValuesMap, exists := myGenomesMap[myGenomeIdentifier] - if (exists == false){ - return nil, errors.New("GetMyChosenMateGeneticAnalysis returning analysis which is missing genome with myGenomeIdentifier.") - } - - return myGenomeLocusValuesMap, nil - } - - myGenomeLocusValuesMap, err := getMyGenomeLocusValuesMap() - if (err != nil) { - setErrorEncounteredPage(window, err, previousPage) - return - } - - getUserLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){ - - // Map Structure: Locus rsID -> Locus Value - userDiseaseLocusValuesMap := make(map[int64]locusValue.LocusValue) - - for _, locusObject := range diseaseLocusObjectsList{ - - locusRSID := locusObject.LocusRSID - - locusRSIDString := helpers.ConvertInt64ToString(locusRSID) - - locusValueAttributeName := "LocusValue_rs" + locusRSIDString - - userLocusValueExists, _, userLocusValue, err := getAnyUserProfileAttributeFunction(locusValueAttributeName) - if (err != nil) { return nil, err } - if (userLocusValueExists == false){ - continue - } - - userLocusBase1, userLocusBase2, semicolonFound := strings.Cut(userLocusValue, ";") - if (semicolonFound == false){ - return nil, errors.New("Database corrupt: Contains profile with invalid " + locusValueAttributeName + " value: " + userLocusValue) - } - - userLocusIsPhasedAttributeName := "LocusIsPhased_rs" + locusRSIDString - - userLocusIsPhasedExists, _, userLocusIsPhasedString, err := getAnyUserProfileAttributeFunction(userLocusIsPhasedAttributeName) - if (err != nil) { return nil, err } - if (userLocusIsPhasedExists == false){ - return nil, errors.New("Database corrupt: Contains profile with locusValue but not locusIsPhased status for locus: " + locusRSIDString) - } - - userLocusIsPhased, err := helpers.ConvertYesOrNoStringToBool(userLocusIsPhasedString) - if (err != nil) { return nil, err } - - userLocusValueObject := locusValue.LocusValue{ - Base1Value: userLocusBase1, - Base2Value: userLocusBase2, - LocusIsPhased: userLocusIsPhased, - } - - userDiseaseLocusValuesMap[locusRSID] = userLocusValueObject - } - - return userDiseaseLocusValuesMap, nil - } - - userDiseaseLocusValuesMap, err := getUserLocusValuesMap() - if (err != nil) { - setErrorEncounteredPage(window, err, previousPage) - return - } - - anyUserLociTested, _, userNumberOfLociTested, userDiseaseLocusInfoMap, err := createPersonGeneticAnalysis.GetPersonGenomePolygenicDiseaseInfo(diseaseLocusObjectsList, userDiseaseLocusValuesMap, true) - if (err != nil) { - setErrorEncounteredPage(window, err, previousPage) - return - } - - anyOffspringLociTested, _, offspringNumberOfLociTested, offspringLociInfoMap, _, err := createCoupleGeneticAnalysis.GetOffspringPolygenicDiseaseInfo(diseaseLocusObjectsList, myGenomeLocusValuesMap, userDiseaseLocusValuesMap) - if (err != nil) { - setErrorEncounteredPage(window, err, previousPage) - return - } - - getNumberOfLociTested := func()int{ - - if (userOrOffspring == "Offspring"){ - - if (anyOffspringLociTested == false){ - return 0 - } - - return offspringNumberOfLociTested - } - - return userNumberOfLociTested - } - - numberOfLociTested := getNumberOfLociTested() - - numberOfLociTestedString := helpers.ConvertIntToString(numberOfLociTested) - totalNumberOfDiseaseLociString := helpers.ConvertIntToString(numberOfDiseaseLoci) - lociTestedString := numberOfLociTestedString + "/" + totalNumberOfDiseaseLociString - - lociTestedLabel := widget.NewLabel("Loci Tested:") - - lociTestedText := getBoldLabel(lociTestedString) - - lociTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - if (userOrOffspring == "User"){ - setPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage) - } else { - setOffspringPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage) - } - }) - - lociTestedRow := container.NewHBox(layout.NewSpacer(), lociTestedLabel, lociTestedText, lociTestedHelpButton, layout.NewSpacer()) - - //TODO: Navigation buttons and multiple pages - - getDiseaseLociGrid := func()(*fyne.Container, error){ - - //TODO: Sort loci - - locusNameLabel := getItalicLabelCentered("Locus Name") - - userRiskWeightLabel := getItalicLabelCentered("User Risk Weight") - offspringRiskWeightLabel := getItalicLabelCentered("Offspring Risk Weight") - - userOddsRatioLabel := getItalicLabelCentered("User Odds Ratio") - offspringOddsRatioLabel := getItalicLabelCentered("Offspring Odds Ratio") - - emptyLabel := widget.NewLabel("") - - locusNameColumn := container.NewVBox(locusNameLabel, widget.NewSeparator()) - userRiskWeightColumn := container.NewVBox(userRiskWeightLabel, widget.NewSeparator()) - offspringRiskWeightColumn := container.NewVBox(offspringRiskWeightLabel, widget.NewSeparator()) - userOddsRatioColumn := container.NewVBox(userOddsRatioLabel, widget.NewSeparator()) - offspringOddsRatioColumn := container.NewVBox(offspringOddsRatioLabel, widget.NewSeparator()) - locusInfoButtonsColumn := container.NewVBox(emptyLabel, widget.NewSeparator()) - - for _, locusObject := range diseaseLocusObjectsList{ - - locusIdentifierHex := locusObject.LocusIdentifier - - locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex) - if (err != nil) { return nil, err } - - locusRSID := locusObject.LocusRSID - locusRSIDString := helpers.ConvertInt64ToString(locusRSID) - locusName := "rs" + locusRSIDString - - //Outputs: - // -bool: User locus Info is known - // -int: User locus Risk weight - // -bool: User locus odds ratio known - // -string: User locus odds ratio formatted - // -error - getUserLocusInfo := func()(bool, int, bool, string, error){ - - if (anyUserLociTested == false){ - return false, 0, false, "", nil - } - - locusInfoObject, exists := userDiseaseLocusInfoMap[locusIdentifier] - if (exists == false){ - return false, 0, false, "", nil - } - - userLocusRiskWeight := locusInfoObject.RiskWeight - - oddsRatioIsKnown := locusInfoObject.OddsRatioIsKnown - - if (oddsRatioIsKnown == false){ - return true, userLocusRiskWeight, false, "", nil - } - - userLocusOddsRatio := locusInfoObject.OddsRatio - - locusOddsRatioString := helpers.ConvertFloat64ToStringRounded(userLocusOddsRatio, 2) - - locusOddsRatioFormatted := locusOddsRatioString + "x" - - return true, userLocusRiskWeight, true, locusOddsRatioFormatted, nil - } - - userLocusInfoIsKnown, userLocusRiskWeight, userLocusOddsRatioIsKnown, userLocusOddsRatioFormatted, err := getUserLocusInfo() - if (err != nil) { return nil, err } - - getUserRiskWeightString := func()string{ - - if (userLocusInfoIsKnown == false){ - result := translate("Unknown") - return result - } - - userRiskWeightString := helpers.ConvertIntToString(userLocusRiskWeight) - return userRiskWeightString - } - - userRiskWeightString := getUserRiskWeightString() - - getUserOddsRatioString := func()string{ - if (userLocusOddsRatioIsKnown == false){ - result := translate("Unknown") - return result - } - return userLocusOddsRatioFormatted - } - - userOddsRatioString := getUserOddsRatioString() - - //Outputs: - // -bool: Offspring disease locus info known - // -int: Offspring risk weight - // -bool: Offspring odds ratio known - // -string: Offspring odds ratio formatted - // -error - getOffspringDiseaseLocusInfo := func()(bool, int, bool, string, error){ - - if (anyOffspringLociTested == false){ - return false, 0, false, "", nil - } - - offspringLocusInfoObject, exists := offspringLociInfoMap[locusIdentifier] - if (exists == false){ - return false, 0, false, "", nil - } - - offspringLocusRiskWeight := offspringLocusInfoObject.OffspringAverageRiskWeight - offspringOddsRatioIsKnown := offspringLocusInfoObject.OffspringOddsRatioIsKnown - - if (offspringOddsRatioIsKnown == false){ - return true, offspringLocusRiskWeight, false, "", nil - } - - offspringOddsRatio := offspringLocusInfoObject.OffspringAverageOddsRatio - unknownOddsRatiosWeightSum := offspringLocusInfoObject.OffspringAverageUnknownOddsRatiosWeightSum - - getOddsRatioFormatted := func()string{ - - offspringOddsRatioString := helpers.ConvertFloat64ToStringRounded(offspringOddsRatio, 2) - - if (unknownOddsRatiosWeightSum > 0){ - result := offspringOddsRatioString + "x+" - return result - } - if (unknownOddsRatiosWeightSum < 0){ - result := "<" + offspringOddsRatioString + "x" - return result - } - result := offspringOddsRatioString + "x" - return result - } - - oddsRatioFormatted := getOddsRatioFormatted() - return true, offspringLocusRiskWeight, true, oddsRatioFormatted, nil - } - - offspringDiseaseLocusKnown, offspringRiskWeight, offspringOddsRatioKnown, offspringOddsRatioFormatted, err := getOffspringDiseaseLocusInfo() - if (err != nil) { return nil, err } - - getOffspringRiskWeightString := func()string{ - - if (offspringDiseaseLocusKnown == false){ - result := translate("Unknown") - return result - } - - offspringRiskWeightString := helpers.ConvertIntToString(offspringRiskWeight) - return offspringRiskWeightString - } - - offspringRiskWeightString := getOffspringRiskWeightString() - - getOffspringOddsRatioString := func()string{ - - if (offspringDiseaseLocusKnown == false || offspringOddsRatioKnown == false){ - result := translate("Unknown") - return result - } - return offspringOddsRatioFormatted - } - - offspringOddsRatioString := getOffspringOddsRatioString() - - locusNameLabel := getBoldLabelCentered(locusName) - userRiskWeightLabel := getBoldLabelCentered(userRiskWeightString) - offspringRiskWeightLabel := getBoldLabelCentered(offspringRiskWeightString) - userOddsRatioLabel := getBoldLabelCentered(userOddsRatioString) - offspringOddsRatioLabel := getBoldLabelCentered(offspringOddsRatioString) - locusInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ - setViewPolygenicDiseaseLocusDetailsPage(window, diseaseName, locusIdentifierHex, currentPage) - }) - - locusNameColumn.Add(locusNameLabel) - userRiskWeightColumn.Add(userRiskWeightLabel) - offspringRiskWeightColumn.Add(offspringRiskWeightLabel) - userOddsRatioColumn.Add(userOddsRatioLabel) - offspringOddsRatioColumn.Add(offspringOddsRatioLabel) - locusInfoButtonsColumn.Add(locusInfoButton) - - locusNameColumn.Add(widget.NewSeparator()) - userRiskWeightColumn.Add(widget.NewSeparator()) - offspringRiskWeightColumn.Add(widget.NewSeparator()) - userOddsRatioColumn.Add(widget.NewSeparator()) - offspringOddsRatioColumn.Add(widget.NewSeparator()) - locusInfoButtonsColumn.Add(widget.NewSeparator()) - } - - userRiskWeightHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setPolygenicDiseaseLocusRiskWeightExplainerPage(window, currentPage) - }) - offspringRiskWeightHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - setOffspringPolygenicDiseaseLocusRiskWeightExplainerPage(window, currentPage) - }) - - userRiskWeightColumn.Add(userRiskWeightHelpButton) - offspringRiskWeightColumn.Add(offspringRiskWeightHelpButton) - - if (userOrOffspring == "User"){ - - diseaseLociGrid := container.NewHBox(layout.NewSpacer(), locusNameColumn, userRiskWeightColumn, userOddsRatioColumn, locusInfoButtonsColumn, layout.NewSpacer()) - - return diseaseLociGrid, nil - } - - diseaseLociGrid := container.NewHBox(layout.NewSpacer(), locusNameColumn, offspringRiskWeightColumn, offspringOddsRatioColumn, locusInfoButtonsColumn, layout.NewSpacer()) - - return diseaseLociGrid, nil - } - - diseaseLociGrid, err := getDiseaseLociGrid() - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return - } - - page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), lociTestedRow, widget.NewSeparator(), diseaseLociGrid) - - setPageContent(page, window) -} func setViewMateProfilePage_GeneticTraits(window fyne.Window, getAnyUserProfileAttributeFunction func(string)(bool, int, string, error), previousPage func()){ @@ -3801,10 +3476,10 @@ func setViewMateProfilePage_DiscreteGeneticTraits(window fyne.Window, userOrOffs if (traitNeuralNetworkExists == true){ - neuralNetworkExists, anyLociKnown, outcomeProbabilitiesMap, _, quantityOfLociKnown, _, err := createCoupleGeneticAnalysis.GetOffspringDiscreteTraitInfo_NeuralNetwork(traitObject, userTraitLocusValuesMap, myGenomeLocusValuesMap) + neuralNetworkExists, anyLociKnown, outcomeProbabilitiesMap, _, quantityOfLociKnown, _, err := createCoupleGeneticAnalysis.GetOffspringDiscreteTraitAnalysis_NeuralNetwork(traitObject, userTraitLocusValuesMap, myGenomeLocusValuesMap) if (err != nil) { return nil, err } if (neuralNetworkExists == false){ - return nil, errors.New("GetOffspringTraitInfo_NeuralNetwork claiming that neural network doesn't exist when we already checked.") + return nil, errors.New("GetOffspringDiscreteTraitAnalysis_NeuralNetwork claiming that neural network doesn't exist when we already checked.") } totalNumberOfLociString := helpers.ConvertIntToString(numberOfTraitLoci) @@ -3862,10 +3537,10 @@ func setViewMateProfilePage_DiscreteGeneticTraits(window fyne.Window, userOrOffs // We use the rules-based analysis - anyRulesExist, rulesAnalysisExists, _, offspringQuantityOfLociKnown, _, outcomeProbabilitiesMap, err := createCoupleGeneticAnalysis.GetOffspringDiscreteTraitInfo_Rules(traitObject, myGenomeLocusValuesMap, userTraitLocusValuesMap) + anyRulesExist, rulesAnalysisExists, _, offspringQuantityOfLociKnown, _, outcomeProbabilitiesMap, err := createCoupleGeneticAnalysis.GetOffspringDiscreteTraitAnalysis_Rules(traitObject, myGenomeLocusValuesMap, userTraitLocusValuesMap) if (err != nil) { return nil, err } if (anyRulesExist == false){ - return nil, errors.New("GetOffspringDiscreteTraitInfo_Rules claiming that no rules exist when we already checked.") + return nil, errors.New("GetOffspringDiscreteTraitAnalysis_Rules claiming that no rules exist when we already checked.") } lociList_Rules := traitObject.LociList_Rules @@ -4125,10 +3800,10 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str return false, nil, nil } - anyRulesExist, anyOffspringRulesTested, _, _, offspringProbabilityOfPassingRulesMap, _, err := createCoupleGeneticAnalysis.GetOffspringDiscreteTraitInfo_Rules(traitObject, myLocusValuesMap, userTraitLocusValuesMap) + anyRulesExist, anyOffspringRulesTested, _, _, offspringProbabilityOfPassingRulesMap, _, err := createCoupleGeneticAnalysis.GetOffspringDiscreteTraitAnalysis_Rules(traitObject, myLocusValuesMap, userTraitLocusValuesMap) if (err != nil) { return false, nil, err } if (anyRulesExist == false){ - return false, nil, errors.New("GetOffspringDiscreteTraitInfo claiming no trait rules exist when we already checked.") + return false, nil, errors.New("GetOffspringDiscreteTraitAnalysis_Rules claiming no trait rules exist when we already checked.") } if (anyOffspringRulesTested == false){ return false, nil, nil @@ -4411,7 +4086,7 @@ func setViewMateProfilePage_NumericGeneticTraits(window fyne.Window, userOrOffsp setLoadingScreen(window, "View Profile - Physical", "Computing Genetic Analysis...") } - //currentPage := func(){setViewMateProfilePage_NumericGeneticTraits(window, userOrOffspring, getAnyUserProfileAttributeFunction, previousPage)} + currentPage := func(){setViewMateProfilePage_NumericGeneticTraits(window, userOrOffspring, getAnyUserProfileAttributeFunction, previousPage)} title := getPageTitleCentered(translate("View Profile - Physical")) @@ -4437,14 +4112,20 @@ func setViewMateProfilePage_NumericGeneticTraits(window fyne.Window, userOrOffsp getTraitsInfoGrid := func()(*fyne.Container, error){ - myPersonChosen, myGenomesExist, myAnalysisIsReady, myAnalysisObject, myGenomeIdentifier, _, err := myChosenAnalysis.GetMyChosenMateGeneticAnalysis() - if (err != nil) { return nil, err } - //Outputs: // -map[int64]locusValue.LocusValue // -error getMyGenomeLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){ + if (userOrOffspring == "User"){ + // We don't need to retrieve our locus values map + emptyMap := make(map[int64]locusValue.LocusValue) + return emptyMap, nil + } + + myPersonChosen, myGenomesExist, myAnalysisIsReady, myAnalysisObject, myGenomeIdentifier, _, err := myChosenAnalysis.GetMyChosenMateGeneticAnalysis() + if (err != nil) { return nil, err } + if (myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false){ emptyMap := make(map[int64]locusValue.LocusValue) return emptyMap, nil @@ -4465,32 +4146,64 @@ func setViewMateProfilePage_NumericGeneticTraits(window fyne.Window, userOrOffsp if (err != nil) { return nil, err } - emptyLabel1 := widget.NewLabel("") traitNameLabel := getItalicLabelCentered("Trait Name") - emptyLabel2 := widget.NewLabel("") userPredictedOutcomeTitle := getItalicLabelCentered("User Predicted Outcome") - emptyLabel3 := widget.NewLabel("") offspringPredictedOutcomeTitle := getItalicLabelCentered("Offspring Predicted Outcome") - predictionTitle := getItalicLabelCentered("Prediction") confidenceRangeTitle := getItalicLabelCentered("Confidence Range") - quantityOfLabel1 := getItalicLabelCentered("Quantity Of") - lociKnownLabel := getItalicLabelCentered("Loci Known") + emptyLabel1 := widget.NewLabel("") - emptyLabel4 := widget.NewLabel("") - emptyLabel5 := widget.NewLabel("") + emptyLabel2 := widget.NewLabel("") - traitNameColumn := container.NewVBox(emptyLabel1, traitNameLabel, widget.NewSeparator()) - userPredictedOutcomeColumn := container.NewVBox(emptyLabel2, userPredictedOutcomeTitle, widget.NewSeparator()) - offspringPredictedOutcomeColumn := container.NewVBox(emptyLabel3, offspringPredictedOutcomeTitle, widget.NewSeparator()) + traitNameColumn := container.NewVBox(traitNameLabel, widget.NewSeparator()) - predictionConfidenceRangeColumn := container.NewVBox(predictionTitle, confidenceRangeTitle, widget.NewSeparator()) - quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel1, lociKnownLabel, widget.NewSeparator()) - viewTraitDetailsButtonsColumn := container.NewVBox(emptyLabel4, emptyLabel5, widget.NewSeparator()) + userPredictedOutcomeColumn := container.NewVBox(userPredictedOutcomeTitle, widget.NewSeparator()) + offspringPredictedOutcomeColumn := container.NewVBox(offspringPredictedOutcomeTitle, widget.NewSeparator()) + + predictionConfidenceRangeColumn := container.NewVBox(confidenceRangeTitle, widget.NewSeparator()) + viewSampleOffspringsButtonsColumn := container.NewVBox(emptyLabel1, widget.NewSeparator()) + viewTraitDetailsButtonsColumn := container.NewVBox(emptyLabel2, widget.NewSeparator()) + + getConfidenceRangeLabel := func(traitObject traits.Trait, analysisExists bool, predictionConfidenceRangesMap map[int]float64)(fyne.Widget, error){ + if (analysisExists == false){ + + result := widget.NewLabel("Unknown") + return result, nil + } + + // This is a list of the percentage accuracies in the map + // For example: 80% == The distance from the prediction you must travel for 80% of the predictions to be + // accurate within that range + confidenceRangePercentagesList := helpers.GetListOfMapKeys(predictionConfidenceRangesMap) + + // We sort the list so the percentage is always the same upon refreshing the page + slices.Sort(confidenceRangePercentagesList) + + closestToEightyPercentage, err := helpers.GetClosestIntInList(confidenceRangePercentagesList, 80) + if (err != nil) { return nil, err } + + closestToEightyPercentageConfidenceDistance, exists := predictionConfidenceRangesMap[closestToEightyPercentage] + if (exists == false){ + return nil, errors.New("GetListOfMapKeys returning list of elements which contains element which is not in the map.") + } + + outcomeFormatter := traitObject.NumericValueFormatter + + closestConfidenceDistanceString, err := outcomeFormatter(closestToEightyPercentageConfidenceDistance, false) + if (err != nil) { return nil, err } + + closestToEightyPercentageString := helpers.ConvertIntToString(closestToEightyPercentage) + + confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)" + + confidenceRangeLabel := getBoldLabel(confidenceRangeLabelValueFormatted) + + return confidenceRangeLabel, nil + } traitObjectsList, err := traits.GetTraitObjectsList() if (err != nil) { return nil, err } @@ -4498,6 +4211,7 @@ func setViewMateProfilePage_NumericGeneticTraits(window fyne.Window, userOrOffsp for _, traitObject := range traitObjectsList{ traitName := traitObject.TraitName + traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric if (traitIsDiscreteOrNumeric != "Numeric"){ continue @@ -4561,108 +4275,74 @@ func setViewMateProfilePage_NumericGeneticTraits(window fyne.Window, userOrOffsp userTraitLocusValuesMap[rsID] = userLocusValueObject } - //Outputs: - // -bool: Analysis results exist - // -float64: Predicted outcome - // -map[int]float64: Prediction confidence ranges map - // -int: Quantity of known loci - // -error - getAnalysisResults := func()(bool, float64, map[int]float64, int, error){ - - if (userOrOffspring == "User"){ - - traitNeuralNetworkExists, anyLocusValuesAreKnown, predictedOutcome, predictionAccuracyRangesMap, quantityOfLociKnown, _, err := createPersonGeneticAnalysis.GetGenomeNumericTraitAnalysis(traitObject, userTraitLocusValuesMap, true) - if (err != nil) { return false, 0, nil, 0, err } - if (traitNeuralNetworkExists == false){ - return false, 0, nil, 0, errors.New("GetGenomeNumericTraitAnalysis claims neural network doesn't exist for trait, but we already checked.") - } - - return anyLocusValuesAreKnown, predictedOutcome, predictionAccuracyRangesMap, quantityOfLociKnown, nil - } else { - - // userOrOffspring == "Offspring" - - neuralNetworkExists, anyLociKnown, predictedOutcome, predictionAccuracyRangesMap, _, quantityOfLociKnown, _, err := createCoupleGeneticAnalysis.GetOffspringNumericTraitInfo(traitObject, userTraitLocusValuesMap, myGenomeLocusValuesMap) - if (err != nil) { return false, 0, nil, 0, err } - if (neuralNetworkExists == false){ - return false, 0, nil, 0, errors.New("GetOffspringTraitInfo_NeuralNetwork claiming that neural network doesn't exist when we already checked.") - } - - return anyLociKnown, predictedOutcome, predictionAccuracyRangesMap, quantityOfLociKnown, nil - } - } - - analysisExists, predictedOutcome, predictionConfidenceRangesMap, quantityOfLociKnown, err := getAnalysisResults() - if (err != nil) { return nil, err } - - getPredictedOutcomeLabel := func()fyne.Widget{ + getPredictedOutcomeLabel := func(analysisExists bool, predictedOutcome float64)(fyne.Widget, error){ if (analysisExists == false){ unknownLabel := widget.NewLabel("Unknown") - return unknownLabel + return unknownLabel, nil } - predictedOutcomeString := helpers.ConvertFloat64ToStringRounded(predictedOutcome, 2) + outcomeFormatter := traitObject.NumericValueFormatter - //TODO: Retrieve units from traits package - predictedOutcomeFormatted := predictedOutcomeString + " centimeters" + predictedOutcomeFormatted, err := outcomeFormatter(predictedOutcome, true) + if (err != nil) { return nil, err } predictedOutcomeLabel := getBoldLabel(predictedOutcomeFormatted) - return predictedOutcomeLabel + return predictedOutcomeLabel, nil } - predictedOutcomeLabel := getPredictedOutcomeLabel() + if (userOrOffspring == "User"){ - predictedOutcomeLabelCentered := getWidgetCentered(predictedOutcomeLabel) - - getConfidenceRangeLabel := func()(fyne.Widget, error){ - if (analysisExists == false){ - - result := widget.NewLabel("Unknown") - return result, nil + traitNeuralNetworkExists, anyLocusValuesAreKnown, predictedOutcome, predictionAccuracyRangesMap, _, _, err := createPersonGeneticAnalysis.GetGenomeNumericTraitAnalysis(traitObject, userTraitLocusValuesMap, true) + if (err != nil) { return nil, err } + if (traitNeuralNetworkExists == false){ + return nil, errors.New("GetGenomeNumericTraitAnalysis claims neural network doesn't exist for trait, but we already checked.") } - // This is a list of the percentage accuracies in the map - // For example: 80% == The distance from the prediction you must travel for 80% of the predictions to be - // accurate within that range - confidenceRangePercentagesList := helpers.GetListOfMapKeys(predictionConfidenceRangesMap) + predictedOutcomeLabel, err := getPredictedOutcomeLabel(anyLocusValuesAreKnown, predictedOutcome) + if (err != nil) { return nil, err } + predictedOutcomeLabelCentered := getWidgetCentered(predictedOutcomeLabel) - // We sort the list so the percentage is always the same upon refreshing the page - slices.Sort(confidenceRangePercentagesList) + userPredictedOutcomeColumn.Add(predictedOutcomeLabelCentered) - closestToEightyPercentage, err := helpers.GetClosestIntInList(confidenceRangePercentagesList, 80) + confidenceRangeLabel, err := getConfidenceRangeLabel(traitObject, anyLocusValuesAreKnown, predictionAccuracyRangesMap) if (err != nil) { return nil, err } - closestToEightyPercentageConfidenceDistance, exists := predictionConfidenceRangesMap[closestToEightyPercentage] - if (exists == false){ - return nil, errors.New("GetListOfMapKeys returning list of elements which contains element which is not in the map.") + confidenceRangeLabelCentered := getWidgetCentered(confidenceRangeLabel) + + predictionConfidenceRangeColumn.Add(confidenceRangeLabelCentered) + + } else { + + // userOrOffspring == "Offspring" + + neuralNetworkExists, anyLociKnown, predictedOutcome, predictionAccuracyRangesMap, sampleOffspringOutcomesList, quantityOfLociKnown, _, err := createCoupleGeneticAnalysis.GetOffspringNumericTraitAnalysis(traitObject, userTraitLocusValuesMap, myGenomeLocusValuesMap) + if (err != nil) { return nil, err } + if (neuralNetworkExists == false){ + return nil, errors.New("GetOffspringNumericTraitAnalysis claiming that neural network doesn't exist when we already checked.") } - closestConfidenceDistanceString := helpers.ConvertFloat64ToStringRounded(closestToEightyPercentageConfidenceDistance, 2) + predictedOutcomeLabel, err := getPredictedOutcomeLabel(anyLociKnown, predictedOutcome) + if (err != nil) { return nil, err } + predictedOutcomeLabelCentered := getWidgetCentered(predictedOutcomeLabel) - closestToEightyPercentageString := helpers.ConvertIntToString(closestToEightyPercentage) + offspringPredictedOutcomeColumn.Add(predictedOutcomeLabelCentered) - confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "% Confidence)" + confidenceRangeLabel, err := getConfidenceRangeLabel(traitObject, anyLociKnown, predictionAccuracyRangesMap) + if (err != nil) { return nil, err } - confidenceRangeLabel := getBoldLabel(confidenceRangeLabelValueFormatted) + confidenceRangeLabelCentered := getWidgetCentered(confidenceRangeLabel) - return confidenceRangeLabel, nil + predictionConfidenceRangeColumn.Add(confidenceRangeLabelCentered) + + viewSampleOffspringsButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ + setViewNumericTraitSampleOffspringOutcomesChart(window, traitName, sampleOffspringOutcomesList, quantityOfLociKnown, currentPage) + }) + + viewSampleOffspringsButtonsColumn.Add(viewSampleOffspringsButton) } - confidenceRangeLabel, err := getConfidenceRangeLabel() - if (err != nil) { return nil, err } - - confidenceRangeLabelCentered := getWidgetCentered(confidenceRangeLabel) - - totalNumberOfLociString := helpers.ConvertIntToString(numberOfTraitLoci) - - quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown) - - quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalNumberOfLociString - - quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted) - viewTraitDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ //TODO showUnderConstructionDialog(window) @@ -4670,76 +4350,46 @@ func setViewMateProfilePage_NumericGeneticTraits(window fyne.Window, userOrOffsp traitNameColumn.Add(traitNameText) - if (userOrOffspring == "User"){ - userPredictedOutcomeColumn.Add(predictedOutcomeLabelCentered) - } else { - offspringPredictedOutcomeColumn.Add(predictedOutcomeLabelCentered) - } - - predictionConfidenceRangeColumn.Add(confidenceRangeLabelCentered) - quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel) viewTraitDetailsButtonsColumn.Add(viewTraitDetailsButton) traitNameColumn.Add(widget.NewSeparator()) userPredictedOutcomeColumn.Add(widget.NewSeparator()) offspringPredictedOutcomeColumn.Add(widget.NewSeparator()) predictionConfidenceRangeColumn.Add(widget.NewSeparator()) - quantityOfLociKnownColumn.Add(widget.NewSeparator()) + viewSampleOffspringsButtonsColumn.Add(widget.NewSeparator()) viewTraitDetailsButtonsColumn.Add(widget.NewSeparator()) } - if (userOrOffspring == "User"){ + predictedOutcomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - predictedOutcomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - - //TODO - showUnderConstructionDialog(window) - }) - - userPredictedOutcomeColumn.Add(predictedOutcomeHelpButton) - - } else { - // userOrOffspring == "Offspring" - - predictedOutcomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - - //TODO - showUnderConstructionDialog(window) - }) - - offspringPredictedOutcomeColumn.Add(predictedOutcomeHelpButton) - } - - predictionConfidenceRangeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ - - //TODO - showUnderConstructionDialog(window) - }) - - predictionConfidenceRangeColumn.Add(predictionConfidenceRangeHelpButton) - - quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ //TODO showUnderConstructionDialog(window) }) - quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton) + predictionConfidenceRangeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ + //TODO + showUnderConstructionDialog(window) + }) + + predictionConfidenceRangeColumn.Add(predictionConfidenceRangeHelpButton) traitsInfoGrid := container.NewHBox(layout.NewSpacer(), traitNameColumn) if (userOrOffspring == "User"){ - + userPredictedOutcomeColumn.Add(predictedOutcomeHelpButton) traitsInfoGrid.Add(userPredictedOutcomeColumn) - } else { - // userOrOffspring == "Offspring" - + offspringPredictedOutcomeColumn.Add(predictedOutcomeHelpButton) traitsInfoGrid.Add(offspringPredictedOutcomeColumn) } traitsInfoGrid.Add(predictionConfidenceRangeColumn) - traitsInfoGrid.Add(quantityOfLociKnownColumn) + + if (userOrOffspring == "Offspring"){ + traitsInfoGrid.Add(viewSampleOffspringsButtonsColumn) + } + traitsInfoGrid.Add(viewTraitDetailsButtonsColumn) traitsInfoGrid.Add(layout.NewSpacer()) diff --git a/internal/generate/generate.go b/internal/generate/generate.go index 141d4c8..068c292 100644 --- a/internal/generate/generate.go +++ b/internal/generate/generate.go @@ -945,9 +945,7 @@ func GetFakeProfile(profileType string, identityPublicKey [32]byte, identityPriv diseaseLociList := diseaseObject.LociList - for _, locusObject := range diseaseLociList{ - - locusRSID := locusObject.LocusRSID + for _, locusRSID := range diseaseLociList{ shareableRSIDsMap[locusRSID] = struct{}{} } diff --git a/internal/genetics/createCoupleGeneticAnalysis/createCoupleGeneticAnalysis.go b/internal/genetics/createCoupleGeneticAnalysis/createCoupleGeneticAnalysis.go index 7dfbd75..da8cfb0 100644 --- a/internal/genetics/createCoupleGeneticAnalysis/createCoupleGeneticAnalysis.go +++ b/internal/genetics/createCoupleGeneticAnalysis/createCoupleGeneticAnalysis.go @@ -27,7 +27,6 @@ import "seekia/internal/helpers" import "errors" import mathRand "math/rand/v2" -import "slices" import "maps" import "reflect" @@ -512,7 +511,6 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom for _, diseaseObject := range polygenicDiseaseObjectsList{ diseaseName := diseaseObject.DiseaseName - diseaseLociList := diseaseObject.LociList // This map stores the polygenic disease info for each genome pair // Map Structure: Genome Pair Identifier -> OffspringGenomePairPolygenicDiseaseInfo @@ -532,9 +530,13 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom return errors.New("addGenomePairDiseaseInfoToDiseaseMap called with unknown person2GenomeIdentifier.") } - anyOffspringLocusTested, genomePairOffspringAverageRiskScore, quantityOfLociTested, genomePairOffspringDiseaseLociInfoMap, genomePairSampleOffspringRiskScoresList, err := GetOffspringPolygenicDiseaseInfo(diseaseLociList, person1LocusValuesMap, person2LocusValuesMap) + neuralNetworkExists, anyOffspringLocusKnown, offspringAverageRiskScore, accuracyRangesMap, predictedRiskScoresList, quantityOfLociKnown, quantityOfParentalPhasedLoci, err := GetOffspringPolygenicDiseaseAnalysis(diseaseObject, person1LocusValuesMap, person2LocusValuesMap) if (err != nil) { return err } - if (anyOffspringLocusTested == false){ + if (neuralNetworkExists == false){ + // We cannot analyze this disease + return nil + } + if (anyOffspringLocusKnown == false){ // We have no information about this genome pair's disease risk // We don't add this genome pair's disease info to the diseaseInfoMap return nil @@ -542,10 +544,11 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom newOffspringGenomePairPolygenicDiseaseInfo := geneticAnalysis.OffspringGenomePairPolygenicDiseaseInfo{ - QuantityOfLociTested: quantityOfLociTested, - OffspringAverageRiskScore: genomePairOffspringAverageRiskScore, - LociInfoMap: genomePairOffspringDiseaseLociInfoMap, - SampleOffspringRiskScoresList: genomePairSampleOffspringRiskScoresList, + OffspringAverageRiskScore: offspringAverageRiskScore, + PredictionConfidenceRangesMap: accuracyRangesMap, + QuantityOfLociKnown: quantityOfLociKnown, + QuantityOfParentalPhasedLoci: quantityOfParentalPhasedLoci, + SampleOffspringRiskScoresList: predictedRiskScoresList, } genomePairIdentifier := helpers.JoinTwo16ByteArrays(person1GenomeIdentifier, person2GenomeIdentifier) @@ -564,6 +567,11 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom if (err != nil) { return false, "", err } } + if (len(offspringPolygenicDiseaseInfoMap) == 0){ + // No disease analysis was performed + continue + } + newOffspringPolygenicDiseaseInfoObject := geneticAnalysis.OffspringPolygenicDiseaseInfo{ PolygenicDiseaseInfoMap: offspringPolygenicDiseaseInfoMap, } @@ -644,7 +652,7 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom newOffspringGenomePairTraitInfo := geneticAnalysis.OffspringGenomePairDiscreteTraitInfo{} - neuralNetworkExists, neuralNetworkAnalysisExists, outcomeProbabilitiesMap, averagePredictionConfidence, quantityOfLociTested, quantityOfParentalPhasedLoci, err := GetOffspringDiscreteTraitInfo_NeuralNetwork(traitObject, person1LocusValuesMap, person2LocusValuesMap) + neuralNetworkExists, neuralNetworkAnalysisExists, outcomeProbabilitiesMap, averagePredictionConfidence, quantityOfLociTested, quantityOfParentalPhasedLoci, err := GetOffspringDiscreteTraitAnalysis_NeuralNetwork(traitObject, person1LocusValuesMap, person2LocusValuesMap) if (err != nil) { return err } if (neuralNetworkExists == true){ @@ -665,7 +673,7 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom } } - anyRulesExist, rulesAnalysisExists, quantityOfRulesTested, quantityOfLociKnown, offspringProbabilityOfPassingRulesMap, offspringOutcomeProbabilitiesMap, err := GetOffspringDiscreteTraitInfo_Rules(traitObject, person1LocusValuesMap, person2LocusValuesMap) + anyRulesExist, rulesAnalysisExists, quantityOfRulesTested, quantityOfLociKnown, offspringProbabilityOfPassingRulesMap, offspringOutcomeProbabilitiesMap, err := GetOffspringDiscreteTraitAnalysis_Rules(traitObject, person1LocusValuesMap, person2LocusValuesMap) if (err != nil) { return err } if (anyRulesExist == true){ @@ -764,7 +772,7 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom return errors.New("addGenomePairTraitInfoToOffspringMap called with unknown person2GenomeIdentifier.") } - neuralNetworkExists, neuralNetworkAnalysisExists, averageOutcome, predictionConfidenceRangesMap, sampleOffspringOutcomesList, quantityOfLociTested, quantityOfParentalPhasedLoci, err := GetOffspringNumericTraitInfo(traitObject, person1LocusValuesMap, person2LocusValuesMap) + neuralNetworkExists, neuralNetworkAnalysisExists, averageOutcome, predictionConfidenceRangesMap, sampleOffspringOutcomesList, quantityOfLociTested, quantityOfParentalPhasedLoci, err := GetOffspringNumericTraitAnalysis(traitObject, person1LocusValuesMap, person2LocusValuesMap) if (err != nil) { return err } if (neuralNetworkExists == false){ // Predictions are not possible for this trait @@ -951,288 +959,109 @@ func GetOffspringMonogenicDiseaseProbabilities(dominantOrRecessive string, perso return true, percentageProbabilityOffspringHasDiseaseInt, true, percentageProbabilityOffspringHasVariantInt, nil } - -// This is used to calculate user polygenic disease info for users -// It is faster to do it this way, because we don't create 100 prospective offspring -// We instead create 4 outcomes for each locus -// We can do this because testing each locus's risk score is independent of every other locus -// This is not true for traits, because trait rules are effected by multiple different loci -// When using the fast method for polygenic diseases, we don't get a sample of 100 offspring disease risk scores. -// The average risk score should still be the same for the fast and normal methods -// This function is also faster because we don't calculate odds ratio information or information about each locus //Outputs: -// -bool: Any loci tested (if false, no offspring polygenic disease information is known) -// -int: Offspring Risk Score (Value between 0-10) -// -int: Number of loci tested -// -error -func GetOffspringPolygenicDiseaseInfo_Fast(diseaseLociList []polygenicDiseases.DiseaseLocus, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, int, int, error){ - - if (len(person1LocusValuesMap) == 0){ - return false, 0, 0, nil - } - if (len(person2LocusValuesMap) == 0){ - return false, 0, 0, nil - } - - // I = Insertion - // D = Deletion - - validAllelesList := []string{"C", "A", "T", "G", "I", "D"} - - numberOfLociTested := 0 - - offspringSummedRiskWeights := 0 - offspringMinimumPossibleRiskWeightSum := 0 - offspringMaximumPossibleRiskWeightSum := 0 - - for _, locusObject := range diseaseLociList{ - - locusRSID := locusObject.LocusRSID - locusRiskWeightsMap := locusObject.RiskWeightsMap - locusMinimumWeight := locusObject.MinimumRiskWeight - locusMaximumWeight := locusObject.MaximumRiskWeight - - person1LocusValueFound, person1LocusBase1Value, person1LocusBase2Value, _, _, err := createPersonGeneticAnalysis.GetLocusValueFromGenomeMap(true, person1LocusValuesMap, locusRSID) - if (err != nil) { return false, 0, 0, err } - if (person1LocusValueFound == false){ - // None of the offspring will have a value for this locus - continue - } - - person2LocusValueFound, person2LocusBase1Value, person2LocusBase2Value, _, _, err := createPersonGeneticAnalysis.GetLocusValueFromGenomeMap(true, person2LocusValuesMap, locusRSID) - if (err != nil) { return false, 0, 0, err } - if (person2LocusValueFound == false){ - // None of the offspring will have a value for this locus - continue - } - - baseIsValid := slices.Contains(validAllelesList, person1LocusBase1Value) - if (baseIsValid == false){ - return false, 0, 0, errors.New("GetOffspringPolygenicDiseaseInfo_Fast called with genomeMap containing invalid locus value base: " + person1LocusBase1Value) - } - baseIsValid = slices.Contains(validAllelesList, person1LocusBase2Value) - if (baseIsValid == false){ - return false, 0, 0, errors.New("GetOffspringPolygenicDiseaseInfo_Fast called with genomeMap containing invalid locus value base: " + person1LocusBase2Value) - } - baseIsValid = slices.Contains(validAllelesList, person2LocusBase1Value) - if (baseIsValid == false){ - return false, 0, 0, errors.New("GetOffspringPolygenicDiseaseInfo_Fast called with genomeMap containing invalid locus value base: " + person2LocusBase1Value) - } - baseIsValid = slices.Contains(validAllelesList, person2LocusBase2Value) - if (baseIsValid == false){ - return false, 0, 0, errors.New("GetOffspringPolygenicDiseaseInfo_Fast called with genomeMap containing invalid locus value base: " + person2LocusBase2Value) - } - - numberOfLociTested += 1 - - offspringBasePairOutcome1 := person1LocusBase1Value + ";" + person2LocusBase1Value - offspringBasePairOutcome2 := person1LocusBase2Value + ";" + person2LocusBase2Value - offspringBasePairOutcome3 := person1LocusBase1Value + ";" + person2LocusBase2Value - offspringBasePairOutcome4 := person1LocusBase2Value + ";" + person2LocusBase1Value - - baseOutcomesList := []string{offspringBasePairOutcome1, offspringBasePairOutcome2, offspringBasePairOutcome3, offspringBasePairOutcome4} - - outcomesSummedRiskWeight := 0 - - for _, outcomeBasePair := range baseOutcomesList{ - - offspringOutcomeRiskWeight, exists := locusRiskWeightsMap[outcomeBasePair] - if (exists == false){ - // We do not know the risk weight for this base pair - // We treat this as a 0 risk weight - continue - } - - outcomesSummedRiskWeight += offspringOutcomeRiskWeight - } - - locusAverageRiskWeight := outcomesSummedRiskWeight/4 - - offspringSummedRiskWeights += locusAverageRiskWeight - - offspringMinimumPossibleRiskWeightSum += locusMinimumWeight - offspringMaximumPossibleRiskWeightSum += locusMaximumWeight - } - - offspringAverageDiseaseRiskScore, err := helpers.ScaleIntProportionally(true, offspringSummedRiskWeights, offspringMinimumPossibleRiskWeightSum, offspringMaximumPossibleRiskWeightSum, 0, 10) - if (err != nil) { return false, 0, 0, err } - - if (numberOfLociTested == 0){ - // No locations were tested - return false, 0, 0, nil - } - - return true, offspringAverageDiseaseRiskScore, numberOfLociTested, nil -} - - -//Outputs: -// -bool: Any loci tested (if false, no offspring polygenic disease information is known) -// -int: Offspring Risk Score (Value between 0-10) -// -int: Number of loci tested -// -map[[3]byte]geneticAnalysis.OffspringPolygenicDiseaseLocusInfo: Offspring Locus information map -// Map Structure: Locus identifier -> OffspringPolygenicDiseaseLocusInfo +// -bool: A neural network exists for this trait +// -bool: Any loci tested (if false, no offspring polygenic disease analysis is known) +// -int: Offspring Average Risk Score (Value between 0-10) +// -map[int]float64: Prediction accuracy ranges map +// -Map Structure: Probability prediction is accurate (X) -> Distance from prediction that must be travelled in both directions to +// create a range in which the true value will fall into, X% of the time // -[]int: Sample offspring risks scores list +// -int: Quantity of loci known +// -int: Quantity of parental phased loci // -error -func GetOffspringPolygenicDiseaseInfo(diseaseLociList []polygenicDiseases.DiseaseLocus, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, int, int, map[[3]byte]geneticAnalysis.OffspringPolygenicDiseaseLocusInfo, []int, error){ +func GetOffspringPolygenicDiseaseAnalysis(diseaseObject polygenicDiseases.PolygenicDisease, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, int, map[int]float64, []int, int, int, error){ + + diseaseName := diseaseObject.DiseaseName + + modelExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(diseaseName) + if (modelExists == false){ + // Prediction is not possible for this trait + return false, false, 0, nil, nil, 0, 0, nil + } if (len(person1LocusValuesMap) == 0){ - return false, 0, 0, nil, nil, nil + return true, false, 0, nil, nil, 0, 0, nil } if (len(person2LocusValuesMap) == 0){ - return false, 0, 0, nil, nil, nil + return true, false, 0, nil, nil, 0, 0, nil } - // First, we create 100 prospective offspring genomes. + diseaseLociList := diseaseObject.LociList - diseaseLociRSIDsList := make([]int64, 0) + // First we count up the quantity of parental phased loci + // We only count the quantity of phased loci for loci which are known for both parents - for _, diseaseLocusObject := range diseaseLociList{ + quantityOfParentalPhasedLoci := 0 - locusRSID := diseaseLocusObject.LocusRSID - diseaseLociRSIDsList = append(diseaseLociRSIDsList, locusRSID) + for _, rsID := range diseaseLociList{ + + person1LocusValue, exists := person1LocusValuesMap[rsID] + if (exists == false){ + continue + } + + person2LocusValue, exists := person2LocusValuesMap[rsID] + if (exists == false){ + continue + } + + person1LocusIsPhased := person1LocusValue.LocusIsPhased + if (person1LocusIsPhased == true){ + quantityOfParentalPhasedLoci += 1 + } + + person2LocusIsPhased := person2LocusValue.LocusIsPhased + if (person2LocusIsPhased == true){ + quantityOfParentalPhasedLoci += 1 + } } - anyLocusValueExists, prospectiveOffspringGenomesList, err := getProspectiveOffspringGenomesList(diseaseLociRSIDsList, person1LocusValuesMap, person2LocusValuesMap) - if (err != nil) { return false, 0, 0, nil, nil, err } + // We create 100 prospective offspring genomes. + + anyLocusValueExists, prospectiveOffspringGenomesList, err := getProspectiveOffspringGenomesList(diseaseLociList, person1LocusValuesMap, person2LocusValuesMap) + if (err != nil) { return false, false, 0, nil, nil, 0, 0, err } if (anyLocusValueExists == false){ - return false, 0, 0, nil, nil, nil + return true, false, 0, nil, nil, 0, 0, nil } - // This will sum every offspring's average disease risk score - offspringAverageRiskScoreSum := 0 + // A list of predicted risk scores for each offspring + predictedRiskScoresList := make([]int, 0) - // This stores a list of every prospective offspring's risk score - sampleOffspringRiskScoresList := make([]int, 0) + accuracyRangesMap := make(map[int]float64) + quantityOfLociTested := 0 - type offspringSummedLocusInfoObject struct{ + for index, offspringGenomeMap := range prospectiveOffspringGenomesList{ - SummedLocusRiskWeights int - - SummedOddsRatios float64 - - NumberOfSummedOddsRatios int - - // This is the number of unknown-odds-ratio-weight sums that we summed up - NumberOfUnknownOddsRatioWeightSums int - - // This is the sum of every unknown-odds-ratio-weight-sum for each prospective offspring for this genome - UnknownOddsRatioWeightSumsSummed int - } - - // Map Structure: Locus Identifier -> offspringSummedLocusInfoObject - offspringLocusInfoSumsMap := make(map[[3]byte]offspringSummedLocusInfoObject) - - for offspringIndex, offspringGenomeMap := range prospectiveOffspringGenomesList{ - - offspringSummedRiskWeights := 0 - offspringMinimumPossibleRiskWeightSum := 0 - offspringMaximumPossibleRiskWeightSum := 0 - - for _, locusObject := range diseaseLociList{ - - locusIdentifierHex := locusObject.LocusIdentifier - - locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex) - if (err != nil) { return false, 0, 0, nil, nil, err } - - offspringLocusInfoSumsObject, exists := offspringLocusInfoSumsMap[locusIdentifier] - if (exists == false){ - - if (offspringIndex != 0){ - // We already checked a previous offspring for this locus, and it's value doesn't exist - continue - } - } - - locusRSID := locusObject.LocusRSID - locusRiskWeightsMap := locusObject.RiskWeightsMap - locusOddsRatiosMap := locusObject.OddsRatiosMap - locusMinimumWeight := locusObject.MinimumRiskWeight - locusMaximumWeight := locusObject.MaximumRiskWeight - - basePairValueFound, locusBase1Value, locusBase2Value, _, _, err := createPersonGeneticAnalysis.GetLocusValueFromGenomeMap(true, offspringGenomeMap, locusRSID) - if (err != nil) { return false, 0, 0, nil, nil, err } - if (basePairValueFound == false){ - // None of the offspring will have a value for this locus - continue - } - - locusRiskWeight, locusOddsRatioIsKnown, locusOddsRatio, err := createPersonGeneticAnalysis.GetGenomePolygenicDiseaseLocusRiskInfo(locusRiskWeightsMap, locusOddsRatiosMap, locusBase1Value, locusBase2Value) - if (err != nil) { return false, 0, 0, nil, nil, err } - - offspringLocusInfoSumsObject.SummedLocusRiskWeights += locusRiskWeight - - if (locusOddsRatioIsKnown == true){ - offspringLocusInfoSumsObject.SummedOddsRatios += locusOddsRatio - offspringLocusInfoSumsObject.NumberOfSummedOddsRatios += 1 - } else { - offspringLocusInfoSumsObject.UnknownOddsRatioWeightSumsSummed += locusRiskWeight - offspringLocusInfoSumsObject.NumberOfUnknownOddsRatioWeightSums += 1 - } - - offspringLocusInfoSumsMap[locusIdentifier] = offspringLocusInfoSumsObject - - offspringSummedRiskWeights += locusRiskWeight - - offspringMinimumPossibleRiskWeightSum += locusMinimumWeight - offspringMaximumPossibleRiskWeightSum += locusMaximumWeight + neuralNetworkExists, predictionIsKnown, predictedRiskScore, predictionAccuracyRangesMap, currentQuantityOfLociTested, _, err := createPersonGeneticAnalysis.GetPersonGenomePolygenicDiseaseAnalysis(diseaseObject, offspringGenomeMap, false) + if (err != nil){ return false, false, 0, nil, nil, 0, 0, err } + if (neuralNetworkExists == false){ + return false, false, 0, nil, nil, 0, 0, errors.New("GetGenomeNumericTraitAnalysis claiming that neural network doesn't exist when we already checked.") + } + if (predictionIsKnown == false){ + return false, false, 0, nil, nil, 0, 0, errors.New("GetGenomeNumericTraitAnalysis claiming that prediction is impossible when we already know at least 1 locus value exists for trait.") } - offspringAverageDiseaseRiskScore, err := helpers.ScaleIntProportionally(true, offspringSummedRiskWeights, offspringMinimumPossibleRiskWeightSum, offspringMaximumPossibleRiskWeightSum, 0, 10) - if (err != nil) { return false, 0, 0, nil, nil, err } + predictedRiskScoresList = append(predictedRiskScoresList, predictedRiskScore) - sampleOffspringRiskScoresList = append(sampleOffspringRiskScoresList, offspringAverageDiseaseRiskScore) - - offspringAverageRiskScoreSum += offspringAverageDiseaseRiskScore + if (index == 0){ + // These values should be the same for each predicted offspring + accuracyRangesMap = predictionAccuracyRangesMap + quantityOfLociTested = currentQuantityOfLociTested + } } - numberOfLociTested := len(offspringLocusInfoSumsMap) + // We calculate the average predicted risk score - if (numberOfLociTested == 0){ - // No locations were tested - return false, 0, 0, nil, nil, nil + outcomesSum := 0 + + for _, predictedRiskScore := range predictedRiskScoresList{ + outcomesSum += predictedRiskScore } - offspringAverageRiskScore := offspringAverageRiskScoreSum/100 + averageRiskScore := outcomesSum/100 - // Map Structure: Locus Identifier -> OffspringPolygenicDiseaseLocusInfo - offspringDiseaseLociInfoMap := make(map[[3]byte]geneticAnalysis.OffspringPolygenicDiseaseLocusInfo) - - for locusIdentifier, summedLocusInfoObject := range offspringLocusInfoSumsMap{ - - summedLocusRiskWeights := summedLocusInfoObject.SummedLocusRiskWeights - summedOddsRatios := summedLocusInfoObject.SummedOddsRatios - numberOfSummedOddsRatios := summedLocusInfoObject.NumberOfSummedOddsRatios - numberOfUnknownOddsRatioWeightSums := summedLocusInfoObject.NumberOfUnknownOddsRatioWeightSums - unknownOddsRatioWeightSumsSummed := summedLocusInfoObject.UnknownOddsRatioWeightSumsSummed - - // There are 100 prospective offspring, so we divide by 100 - locusAverageRiskWeight := summedLocusRiskWeights/100 - - newLocusInfoObject := geneticAnalysis.OffspringPolygenicDiseaseLocusInfo{ - OffspringAverageRiskWeight: locusAverageRiskWeight, - } - - if (numberOfSummedOddsRatios != 0){ - newLocusInfoObject.OffspringOddsRatioIsKnown = true - - offspringAverageOddsRatio := summedOddsRatios/float64(numberOfSummedOddsRatios) - - newLocusInfoObject.OffspringAverageOddsRatio = offspringAverageOddsRatio - } - - if (numberOfUnknownOddsRatioWeightSums != 0){ - - offspringAverageUnknownOddsRatiosWeightSum := unknownOddsRatioWeightSumsSummed/numberOfUnknownOddsRatioWeightSums - - newLocusInfoObject.OffspringAverageUnknownOddsRatiosWeightSum = offspringAverageUnknownOddsRatiosWeightSum - } - - offspringDiseaseLociInfoMap[locusIdentifier] = newLocusInfoObject - } - - return true, offspringAverageRiskScore, numberOfLociTested, offspringDiseaseLociInfoMap, sampleOffspringRiskScoresList, nil + return true, true, averageRiskScore, accuracyRangesMap, predictedRiskScoresList, quantityOfLociTested, quantityOfParentalPhasedLoci, nil } @@ -1245,13 +1074,13 @@ func GetOffspringPolygenicDiseaseInfo(diseaseLociList []polygenicDiseases.Diseas // -int: Quantity of loci tested // -int: Quantity of parental phased loci // -error -func GetOffspringDiscreteTraitInfo_NeuralNetwork(traitObject traits.Trait, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, map[string]int, int, int, int, error){ +func GetOffspringDiscreteTraitAnalysis_NeuralNetwork(traitObject traits.Trait, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, map[string]int, int, int, int, error){ traitName := traitObject.TraitName traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric if (traitIsDiscreteOrNumeric != "Discrete"){ - return false, false, nil, 0, 0, 0, errors.New("GetOffspringDiscreteTraitInfo_NeuralNetwork called with non-discrete trait.") + return false, false, nil, 0, 0, 0, errors.New("GetOffspringDiscreteTraitAnalysis_NeuralNetwork called with non-discrete trait.") } modelExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName) @@ -1343,7 +1172,7 @@ func GetOffspringDiscreteTraitInfo_NeuralNetwork(traitObject traits.Trait, perso // -map[string]int: Offspring outcome probabilities map // Map Structure: Outcome Name -> Offspring probability of outcome (0-100) // -error -func GetOffspringDiscreteTraitInfo_Rules(traitObject traits.Trait, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, int, int, map[[3]byte]int, map[string]int, error){ +func GetOffspringDiscreteTraitAnalysis_Rules(traitObject traits.Trait, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, int, int, map[[3]byte]int, map[string]int, error){ traitRulesList := traitObject.RulesList @@ -1421,7 +1250,6 @@ func GetOffspringDiscreteTraitInfo_Rules(traitObject traits.Trait, person1LocusV } - //Outputs: // -bool: A neural network exists for this trait // -bool: Analysis exists (at least 1 locus exists for this analysis from both people's genomes @@ -1433,13 +1261,13 @@ func GetOffspringDiscreteTraitInfo_Rules(traitObject traits.Trait, person1LocusV // -int: Quantity of loci known // -int: Quantity of parental phased loci // -error -func GetOffspringNumericTraitInfo(traitObject traits.Trait, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, float64, map[int]float64, []float64, int, int, error){ +func GetOffspringNumericTraitAnalysis(traitObject traits.Trait, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, float64, map[int]float64, []float64, int, int, error){ traitName := traitObject.TraitName traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric if (traitIsDiscreteOrNumeric != "Numeric"){ - return false, false, 0, nil, nil, 0, 0, errors.New("GetOffspringNumericTraitInfo called with non-numeric trait.") + return false, false, 0, nil, nil, 0, 0, errors.New("GetOffspringNumericTraitAnalysis called with non-numeric trait.") } modelExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName) diff --git a/internal/genetics/createPersonGeneticAnalysis/createPersonGeneticAnalysis.go b/internal/genetics/createPersonGeneticAnalysis/createPersonGeneticAnalysis.go index 43cf8fd..7e4a318 100644 --- a/internal/genetics/createPersonGeneticAnalysis/createPersonGeneticAnalysis.go +++ b/internal/genetics/createPersonGeneticAnalysis/createPersonGeneticAnalysis.go @@ -8,10 +8,6 @@ package createPersonGeneticAnalysis // Disclaimer: I am a novice in the ways of genetics. This package could be flawed in numerous ways. -// TODO: We want to eventually use neural nets for both trait and polygenic disease analysis (see geneticPrediction.go) -// These will be trained on a set of genomes and will output a probability analysis for each trait/disease -// This is only possible once we get access to the necessary training data - // TODO: Add the ability to weight different genome files based on their reliability. // Some files are much more accurate because they record each location many times. @@ -667,80 +663,6 @@ func GetPersonMonogenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw return personMonogenicDiseaseInfoObject, nil } - -//Outputs: -// -bool: Any loci tested -// -int: Person genome risk score (value between 0-10) -// -int: Person Genome Number of loci tested -// -map[[3]byte]geneticAnalysis.PersonGenomePolygenicDiseaseLocusInfo: Person disease locus info map -// Map Structure: Locus Identifier -> PersonGenomePolygenicDiseaseLocusInfo -// -error -func GetPersonGenomePolygenicDiseaseInfo(diseaseLociList []polygenicDiseases.DiseaseLocus, personLocusValuesMap map[int64]locusValue.LocusValue, lookForLocusAliases bool)(bool, int, int, map[[3]byte]geneticAnalysis.PersonGenomePolygenicDiseaseLocusInfo, error){ - - if (len(personLocusValuesMap) == 0){ - return false, 0, 0, nil, nil - } - - // Map Structure: Locus Identifier -> PersonGenomePolygenicDiseaseLocusInfo - genomeLociInfoMap := make(map[[3]byte]geneticAnalysis.PersonGenomePolygenicDiseaseLocusInfo) - - summedDiseaseRiskWeight := 0 - - minimumPossibleRiskWeightSum := 0 - maximumPossibleRiskWeightSum := 0 - - for _, locusObject := range diseaseLociList{ - - locusRSID := locusObject.LocusRSID - locusRiskWeightsMap := locusObject.RiskWeightsMap - locusOddsRatiosMap := locusObject.OddsRatiosMap - locusMinimumWeight := locusObject.MinimumRiskWeight - locusMaximumWeight := locusObject.MaximumRiskWeight - - locusValueFound, locusBase1Value, locusBase2Value, _, _, err := GetLocusValueFromGenomeMap(lookForLocusAliases, personLocusValuesMap, locusRSID) - if (err != nil) { return false, 0, 0, nil, err } - if (locusValueFound == false){ - continue - } - - locusRiskWeight, locusOddsRatioIsKnown, locusOddsRatio, err := GetGenomePolygenicDiseaseLocusRiskInfo(locusRiskWeightsMap, locusOddsRatiosMap, locusBase1Value, locusBase2Value) - if (err != nil) { return false, 0, 0, nil, err } - - newLocusInfoObject := geneticAnalysis.PersonGenomePolygenicDiseaseLocusInfo{ - RiskWeight: locusRiskWeight, - OddsRatioIsKnown: locusOddsRatioIsKnown, - } - - if (locusOddsRatioIsKnown == true){ - newLocusInfoObject.OddsRatio = locusOddsRatio - } - - locusIdentifierHex := locusObject.LocusIdentifier - - locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex) - if (err != nil) { return false, 0, 0, nil, err } - - genomeLociInfoMap[locusIdentifier] = newLocusInfoObject - - minimumPossibleRiskWeightSum += locusMinimumWeight - maximumPossibleRiskWeightSum += locusMaximumWeight - - summedDiseaseRiskWeight += locusRiskWeight - } - - numberOfLociTested := len(genomeLociInfoMap) - if (numberOfLociTested == 0){ - // We have no information about this disease for this genome - return false, 0, 0, nil, nil - } - - diseaseRiskScore, err := helpers.ScaleIntProportionally(true, summedDiseaseRiskWeight, minimumPossibleRiskWeightSum, maximumPossibleRiskWeightSum, 0, 10) - if (err != nil) { return false, 0, 0, nil, err } - - return true, diseaseRiskScore, numberOfLociTested, genomeLociInfoMap, nil -} - - //Outputs: // -geneticAnalysis.PersonPolygenicDiseaseInfo // -error @@ -749,8 +671,6 @@ func GetPersonPolygenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw // We use this when returning errors emptyDiseaseInfoObject := geneticAnalysis.PersonPolygenicDiseaseInfo{} - diseaseLociList := diseaseObject.LociList - // This map stores the polygenic disease for each of the person's genomes // Map Structure: Genome Identifier -> PersonGenomePolygenicDiseaseInfo personPolygenicDiseaseInfoMap := make(map[[16]byte]geneticAnalysis.PersonGenomePolygenicDiseaseInfo) @@ -762,33 +682,17 @@ func GetPersonPolygenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw genomeIdentifier := genomeWithMetadataObject.GenomeIdentifier genomeMap := genomeWithMetadataObject.GenomeMap - // This map stores the loci for this disease and does not contain loci which do not belong to this disease - // Map Structure: rsID -> Locus Value - genomeLocusValuesMap := make(map[int64]locusValue.LocusValue) - - for _, locusObject := range diseaseLociList{ - - locusRSID := locusObject.LocusRSID - - locusValueFound, _, _, _, locusValueObject, err := GetLocusValueFromGenomeMap(true, genomeMap, locusRSID) - if (err != nil) { return emptyDiseaseInfoObject, err } - if (locusValueFound == false){ - continue - } - - genomeLocusValuesMap[locusRSID] = locusValueObject - } - - anyLociTested, personDiseaseRiskScore, genomeNumberOfLociTested, genomeLociInfoMap, err := GetPersonGenomePolygenicDiseaseInfo(diseaseLociList, genomeLocusValuesMap, true) + neuralNetworkExists, anyLociTested, personDiseaseRiskScore, predictionAccuracyRangesMap, genomeQuantityOfLociKnown, genomeQuantityOfPhasedLoci, err := GetPersonGenomePolygenicDiseaseAnalysis(diseaseObject, genomeMap, true) if (err != nil) { return emptyDiseaseInfoObject, err } - if (anyLociTested == false){ + if (neuralNetworkExists == false || anyLociTested == false){ continue } newDiseaseInfoObject := geneticAnalysis.PersonGenomePolygenicDiseaseInfo{ - QuantityOfLociTested: genomeNumberOfLociTested, RiskScore: personDiseaseRiskScore, - LociInfoMap: genomeLociInfoMap, + ConfidenceRangesMap: predictionAccuracyRangesMap, + QuantityOfLociKnown: genomeQuantityOfLociKnown, + QuantityOfPhasedLoci: genomeQuantityOfPhasedLoci, } personPolygenicDiseaseInfoMap[genomeIdentifier] = newDiseaseInfoObject @@ -810,75 +714,20 @@ func GetPersonPolygenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw // First we check to see if any of the genomes have different risk scores or NumberOfLociTested - genomeRiskScore := 0 - genomeNumberOfLociTested := 0 + personGenomePolygenicDiseaseInfoObject := geneticAnalysis.PersonGenomePolygenicDiseaseInfo{} firstItemReached := false for _, personGenomeDiseaseInfoObject := range personPolygenicDiseaseInfoMap{ - currentGenomeRiskScore := personGenomeDiseaseInfoObject.RiskScore - currentGenomeNumberOfLociTested := personGenomeDiseaseInfoObject.QuantityOfLociTested - if (firstItemReached == false){ - genomeRiskScore = currentGenomeRiskScore - genomeNumberOfLociTested = currentGenomeNumberOfLociTested + personGenomePolygenicDiseaseInfoObject = personGenomeDiseaseInfoObject firstItemReached = true continue } - if (genomeRiskScore != currentGenomeRiskScore){ - return true, nil - } - if (genomeNumberOfLociTested != currentGenomeNumberOfLociTested){ - return true, nil - } - } - - // Now we check for conflicts between the different locus values - // We consider a conflict any time the same locus has different weights/odds ratios - // We don't care if the loci have different base pair values, so long as those base pairs have the same risk weights/odds ratios - - for _, locusObject := range diseaseLociList{ - - locusIdentifierHex := locusObject.LocusIdentifier - - locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex) - if (err != nil) { return false, err } - - locusRiskWeight := 0 - locusOddsRatio := float64(0) - - firstItemReached := false - - for _, personGenomeDiseaseInfoObject := range personPolygenicDiseaseInfoMap{ - - genomeLociInfoMap := personGenomeDiseaseInfoObject.LociInfoMap - - genomeLocusObject, exists := genomeLociInfoMap[locusIdentifier] - if (exists == false){ - if (firstItemReached == true){ - // A previous genome has information for this locus, and the current one does not - return true, nil - } - continue - } - - genomeLocusRiskWeight := genomeLocusObject.RiskWeight - genomeLocusOddsRatio := genomeLocusObject.OddsRatio - - if (firstItemReached == false){ - locusRiskWeight = genomeLocusRiskWeight - locusOddsRatio = genomeLocusOddsRatio - firstItemReached = true - continue - } - if (locusRiskWeight == genomeLocusRiskWeight && locusOddsRatio == genomeLocusOddsRatio){ - // No conflict exists for this locus on the genomes we have already checked - continue - } - - // Conflict exists + areEqual := reflect.DeepEqual(personGenomeDiseaseInfoObject, personGenomePolygenicDiseaseInfoObject) + if (areEqual == false){ return true, nil } } @@ -895,6 +744,67 @@ func GetPersonPolygenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw } +//Outputs: +// -bool: Neural network exists for disease +// -bool: Any loci tested +// -int: Person genome risk score (value between 0-10) +// -map[int]float64: Confidence ranges map +// -If we want to know how accurate the prediction is with a X% accuracy, how far would we have to expand the +// risk score's range to be accurate, X% of the time? +// -Map Structure: Percentage -> Distance to travel in both directions of prediction +// -int: Person Genome quantity of loci known +// -int: Person genome quantity of phased loci +// -error +func GetPersonGenomePolygenicDiseaseAnalysis(diseaseObject polygenicDiseases.PolygenicDisease, personGenomeMap map[int64]locusValue.LocusValue, checkForAliases bool)(bool, bool, int, map[int]float64, int, int, error){ + + diseaseLociList := diseaseObject.LociList + + getGenomeLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){ + + if (checkForAliases == false){ + // We don't need to check for rsID aliases. + return personGenomeMap, nil + } + + // This map contains the locus values for the genome + // If a locus's entry doesn't exist, its value is unknown + // Map Structure: Locus rsID -> Locus Value + genomeLocusValuesMap := make(map[int64]locusValue.LocusValue) + + for _, locusRSID := range diseaseLociList{ + + locusBasePairKnown, _, _, _, locusValueObject, err := GetLocusValueFromGenomeMap(checkForAliases, personGenomeMap, locusRSID) + if (err != nil) { return nil, err } + if (locusBasePairKnown == false){ + continue + } + + genomeLocusValuesMap[locusRSID] = locusValueObject + } + + return genomeLocusValuesMap, nil + } + + genomeLocusValuesMap, err := getGenomeLocusValuesMap() + if (err != nil) { return false, false, 0, nil, 0, 0, err } + + diseaseName := diseaseObject.DiseaseName + + neuralNetworkModelExists, riskScorePredictionIsPossible, predictedRiskScore, predictionAccuracyRangesMap, quantityOfLociKnown, quantityOfPhasedLoci, err := geneticPrediction.GetNeuralNetworkNumericAttributePredictionFromGenomeMap(diseaseName, diseaseLociList, genomeLocusValuesMap) + if (err != nil) { return false, false, 0, nil, 0, 0, err } + if (neuralNetworkModelExists == false){ + return false, false, 0, nil, 0, 0, nil + } + if (riskScorePredictionIsPossible == false){ + return true, false, 0, nil, 0, 0, nil + } + + predictedRiskScoreInt := int(predictedRiskScore) + + return true, true, predictedRiskScoreInt, predictionAccuracyRangesMap, quantityOfLociKnown, quantityOfPhasedLoci, nil +} + + //Outputs: // -geneticAnalysis.PersonDiscreteTraitInfo: Trait analysis object // -error @@ -1073,35 +983,6 @@ func GetPersonNumericTraitAnalysis(inputGenomesWithMetadataList []prepareRawGeno return newPersonTraitInfoObject, nil } - -//Outputs: -// -int: Base pair disease locus risk weight -// -bool: Base pair disease locus odds ratio known -// -float64: Base pair disease locus odds ratio -// -error -func GetGenomePolygenicDiseaseLocusRiskInfo(locusRiskWeightsMap map[string]int, locusOddsRatiosMap map[string]float64, locusBase1Value string, locusBase2Value string)(int, bool, float64, error){ - - locusBasePairJoined := locusBase1Value + ";" + locusBase2Value - - riskWeight, exists := locusRiskWeightsMap[locusBasePairJoined] - if (exists == false){ - // This is an unknown base combination - // We will treat it as a 0 risk weight - return 0, true, 1, nil - } - - if (riskWeight == 0){ - return 0, true, 1, nil - } - - oddsRatio, exists := locusOddsRatiosMap[locusBasePairJoined] - if (exists == false){ - return riskWeight, false, 0, nil - } - - return riskWeight, true, oddsRatio, nil -} - // We use this to generate discrete trait predictions using a neural network // The alternative prediction method is to use Rules (see GetGenomeTraitAnalysis_Rules) //Outputs: @@ -1357,6 +1238,8 @@ func GetGenomePassesDiscreteTraitRuleStatus(ruleLociList []traits.RuleLocus, gen // -error func GetGenomeNumericTraitAnalysis(traitObject traits.Trait, genomeMap map[int64]locusValue.LocusValue, checkForAliases bool)(bool, bool, float64, map[int]float64, int, int, error){ + traitLociList := traitObject.LociList + getGenomeLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){ if (checkForAliases == false){ @@ -1364,8 +1247,6 @@ func GetGenomeNumericTraitAnalysis(traitObject traits.Trait, genomeMap map[int64 return genomeMap, nil } - traitLociList := traitObject.LociList - // This map contains the locus values for the genome // If a locus's entry doesn't exist, its value is unknown // Map Structure: Locus rsID -> Locus Value @@ -1390,7 +1271,7 @@ func GetGenomeNumericTraitAnalysis(traitObject traits.Trait, genomeMap map[int64 traitName := traitObject.TraitName - neuralNetworkModelExists, traitPredictionIsPossible, predictedOutcome, predictionAccuracyRangesMap, quantityOfLociKnown, quantityOfPhasedLoci, err := geneticPrediction.GetNeuralNetworkNumericTraitPredictionFromGenomeMap(traitName, genomeLocusValuesMap) + neuralNetworkModelExists, traitPredictionIsPossible, predictedOutcome, predictionAccuracyRangesMap, quantityOfLociKnown, quantityOfPhasedLoci, err := geneticPrediction.GetNeuralNetworkNumericAttributePredictionFromGenomeMap(traitName, traitLociList, genomeLocusValuesMap) if (err != nil) { return false, false, 0, nil, 0, 0, err } if (neuralNetworkModelExists == false){ return false, false, 0, nil, 0, 0, nil diff --git a/internal/genetics/geneticAnalysis/geneticAnalysis.go b/internal/genetics/geneticAnalysis/geneticAnalysis.go index 9677c8e..220a389 100644 --- a/internal/genetics/geneticAnalysis/geneticAnalysis.go +++ b/internal/genetics/geneticAnalysis/geneticAnalysis.go @@ -107,32 +107,21 @@ type PersonPolygenicDiseaseInfo struct{ type PersonGenomePolygenicDiseaseInfo struct{ - // This describes the quantity of loci tested for this disease - // This should be len(LociInfoMap) - QuantityOfLociTested int - // This is total risk score for this disease for the person's genome // This is a number between 1-10 RiskScore int - // This map contains info about all tested polygenic disease loci for this genome - // If a locus does not exist in the map, its values are unknown - // Map Structure: Locus Identifier -> PersonGenomePolygenicDiseaseLocusInfo - LociInfoMap map[[3]byte]PersonGenomePolygenicDiseaseLocusInfo -} + // This map stores the confidence ranges for the predicted risk score + // If we want to know how accurate the prediction is with a X% accuracy, how far would we have to expand the + // risk score's range to be accurate, X% of the time? + // For example: 50% accuracy requires a +/-2 point range, 80% accuracy requires a +-5 point range + // Map Structure: Accuracy probability (0-100) -> Amount to add to value in both +/- directions so prediction is that accurate + ConfidenceRangesMap map[int]float64 -type PersonGenomePolygenicDiseaseLocusInfo struct{ + // This describes the quantity of loci tested for this disease + QuantityOfLociKnown int - // This is the risk weight that this person's genome has for this variant - // A higher risk weight means more risk of getting the disease - RiskWeight int - - // This is valse if the odds ratio is not known - OddsRatioIsKnown bool - - // This is the person's genome odds ratio value for this variant's locus - // A ratio >1 means their risk is increased, a ratio <1 means their risk is decreased - OddsRatio float64 + QuantityOfPhasedLoci int } @@ -325,7 +314,6 @@ type OffspringMonogenicDiseaseVariantInfo struct{ ProbabilityOf2MutationsUpperBound int } - type OffspringPolygenicDiseaseInfo struct{ // This map stores the polygenic disease info for each genome pair @@ -339,16 +327,23 @@ type OffspringPolygenicDiseaseInfo struct{ type OffspringGenomePairPolygenicDiseaseInfo struct{ - // This should be len(LociInfoMap) - QuantityOfLociTested int - // A number between 1-10 representing the offspring's average risk score // 1 == lowest risk, 10 == highest risk OffspringAverageRiskScore int - // A map of the offspring's locus information - // Map Structure: Locus Identifier -> OffspringPolygenicDiseaseLocusInfo - LociInfoMap map[[3]byte]OffspringPolygenicDiseaseLocusInfo + // This map stores the confidence ranges for the predicted risk score + // If we want to know how accurate the prediction is with a X% accuracy, how far would we have to expand the + // risk score's range to be accurate, X% of the time? + // For example: 50% accuracy requires a +/-2 point range, 80% accuracy requires a +-3 point range + // Map Structure: Accuracy probability (0-100) -> Amount to add to value in both +/- directions so prediction is that accurate + PredictionConfidenceRangesMap map[int]float64 + + QuantityOfLociKnown int + + // This describes the quantity of loci from both parents that are phased + // For example, if there are 10 loci for this trait, and one parent has 10 phased loci and the other has 5, + // this variable will have a value of 15 + QuantityOfParentalPhasedLoci int // This is a list of prospective offspring risk scores // This is useful for plotting on a graph to understand the standard deviation of risk @@ -356,27 +351,6 @@ type OffspringGenomePairPolygenicDiseaseInfo struct{ } -type OffspringPolygenicDiseaseLocusInfo struct{ - - // This is the offspring's average risk weight for this locus value - // A higher weight means a higher risk of the disease - OffspringAverageRiskWeight int - - // This is true if any of the 100 prospective offspring had a known odds ratio for this locus - OffspringOddsRatioIsKnown bool - - // This value represent's the offspring's average odds ratio for the disease locus - // A value <1 denotes a lesser risk, a value >1 denotes an increased risk - OffspringAverageOddsRatio float64 - - // This is the average of the sum of weights for the loci which have no odds ratios for each prospective offspring - // We do this to understand what effect those loci are having on the odds ratio - // If the sum is <0, we say the ratio is probably lower - // If the sum is >0, we say the ratio is probably higher - OffspringAverageUnknownOddsRatiosWeightSum int -} - - type OffspringDiscreteTraitInfo struct{ // This map stores the trait info for each genome pair diff --git a/internal/genetics/geneticPrediction/geneticPrediction.go b/internal/genetics/geneticPrediction/geneticPrediction.go index 720b2d1..858657a 100644 --- a/internal/genetics/geneticPrediction/geneticPrediction.go +++ b/internal/genetics/geneticPrediction/geneticPrediction.go @@ -1,6 +1,6 @@ // geneticPrediction provides functions to train and query neural network models -// These models are currently used to predict traits such as eye color from user genome files +// These models are used to predict attributes such as eye color and autism from user genome files package geneticPrediction @@ -10,6 +10,7 @@ package geneticPrediction // Sorting matches by offspring total polygenic disease score will require inference on dozens of models for each match // We could create slower models that provide more accurate predictions +import "seekia/resources/geneticReferences/polygenicDiseases" import "seekia/resources/geneticReferences/traits" import "seekia/resources/geneticPredictionModels" @@ -48,7 +49,7 @@ type NeuralNetwork struct{ // and the OutputLayer is a column representing their phenotype, such as eye color type TrainingData struct{ - // InputLayer stores relevant rsID values for each trait from the user's genomes + // InputLayer stores relevant rsID values for each attribute from the user's genomes // It also stores if each rsID is phased and if each rsID exists InputLayer []float32 @@ -282,9 +283,9 @@ func DecodeBytesToDiscreteTraitPredictionAccuracyInfoMap(inputBytes []byte)(Disc return newDiscreteTraitPredictionAccuracyInfoMap, nil } -type NumericTraitPredictionAccuracyInfoMap map[NumericTraitPredictionInfo]NumericTraitPredictionAccuracyRangesMap +type NumericAttributePredictionAccuracyInfoMap map[NumericAttributePredictionInfo]NumericAttributePredictionAccuracyRangesMap -type NumericTraitPredictionInfo struct{ +type NumericAttributePredictionInfo struct{ // This is a value between 0-100 which describes the percentage of the loci which were tested for the input for the prediction PercentageOfLociTested int @@ -302,10 +303,10 @@ type NumericTraitPredictionInfo struct{ // the true height value will fall into this range 90% of the time. // -50%+: 20 centimeters // -10%+: 10 centimeters -type NumericTraitPredictionAccuracyRangesMap map[int]float64 +type NumericAttributePredictionAccuracyRangesMap map[int]float64 -func EncodeNumericTraitPredictionAccuracyInfoMapToBytes(inputMap NumericTraitPredictionAccuracyInfoMap)([]byte, error){ +func EncodeNumericAttributePredictionAccuracyInfoMapToBytes(inputMap NumericAttributePredictionAccuracyInfoMap)([]byte, error){ buffer := new(bytes.Buffer) @@ -319,22 +320,22 @@ func EncodeNumericTraitPredictionAccuracyInfoMapToBytes(inputMap NumericTraitPre return inputMapBytes, nil } -func DecodeBytesToNumericTraitPredictionAccuracyInfoMap(inputBytes []byte)(NumericTraitPredictionAccuracyInfoMap, error){ +func DecodeBytesToNumericAttributePredictionAccuracyInfoMap(inputBytes []byte)(NumericAttributePredictionAccuracyInfoMap, error){ if (inputBytes == nil){ - return nil, errors.New("DecodeBytesToNumericTraitPredictionAccuracyInfoMap called with nil inputBytes.") + return nil, errors.New("DecodeBytesToNumericAttributePredictionAccuracyInfoMap called with nil inputBytes.") } buffer := bytes.NewBuffer(inputBytes) decoder := gob.NewDecoder(buffer) - var newNumericTraitPredictionAccuracyInfoMap NumericTraitPredictionAccuracyInfoMap + var newNumericAttributePredictionAccuracyInfoMap NumericAttributePredictionAccuracyInfoMap - err := decoder.Decode(&newNumericTraitPredictionAccuracyInfoMap) + err := decoder.Decode(&newNumericAttributePredictionAccuracyInfoMap) if (err != nil){ return nil, err } - return newNumericTraitPredictionAccuracyInfoMap, nil + return newNumericAttributePredictionAccuracyInfoMap, nil } //Outputs: @@ -471,48 +472,37 @@ func GetNeuralNetworkDiscreteTraitPredictionFromGenomeMap(traitName string, geno return true, true, predictedOutcomeName, predictionAccuracy, quantityOfLociKnown, quantityOfPhasedLoci, nil } +// This function is used to predict numeric traits and polygenic disease risk scores //Outputs: -// -bool: Neural network model exists for this trait (trait prediction is possible for this trait) -// -bool: Trait prediction is possible for this user (User has at least 1 known trait locus value) -// -float64: Predicted trait outcome (Example: Height in centimeters) +// -bool: Neural network model exists for this attribute (neural network prediction is possible for this attribute) +// -bool: Attribute prediction is possible for this user (User has at least 1 known attribute locus value) +// -float64: Predicted attribute outcome (Example: Height in centimeters) // -map[int]float64: Accuracy ranges map // -Map Structure: Probability prediction is accurate (X) -> Distance from prediction that must be travelled in both directions to // create a range in which the true value will fall into, X% of the time // -int: Quantity of loci known // -int: Quantity of phased loci // -error -func GetNeuralNetworkNumericTraitPredictionFromGenomeMap(traitName string, genomeMap map[int64]locusValue.LocusValue)(bool, bool, float64, map[int]float64, int, int, error){ +func GetNeuralNetworkNumericAttributePredictionFromGenomeMap(attributeName string, attributeLociList []int64, genomeMap map[int64]locusValue.LocusValue)(bool, bool, float64, map[int]float64, int, int, error){ - traitObject, err := traits.GetTraitObject(traitName) - if (err != nil) { return false, false, 0, nil, 0, 0, err } - - traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric - if (traitIsDiscreteOrNumeric != "Numeric"){ - return false, false, 0, nil, 0, 0, errors.New("GetNeuralNetworkNumericTraitPredictionFromGenomeMap called with non-discrete trait: " + traitName) - } - - // This is a map of rsIDs which influence this trait - traitRSIDsList := traitObject.LociList - - if (len(traitRSIDsList) == 0){ - // Prediction is not possible for this trait - return false, false, 0, nil, 0, 0, nil - } - - predictionModelExists, predictionModelBytes := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName) + predictionModelExists, predictionModelBytes := geneticPredictionModels.GetGeneticPredictionModelBytes(attributeName) if (predictionModelExists == false){ - // Prediction is not possible for this trait + // Prediction is not possible for this attribute return false, false, 0, nil, 0, 0, nil } - traitRSIDsListCopy := slices.Clone(traitRSIDsList) - slices.Sort(traitRSIDsListCopy) + if (len(attributeLociList) == 0){ + return false, false, 0, nil, 0, 0, errors.New("GetNeuralNetworkNumericAttributePredictionFromGenomeMap called with empty attributeLociList for attribute with an existing neural network.") + } - neuralNetworkInput, quantityOfLociKnown, quantityOfPhasedLoci, err := createInputNeuralNetworkLayerFromGenomeMap(traitRSIDsListCopy, genomeMap) + attributeLociListCopy := slices.Clone(attributeLociList) + slices.Sort(attributeLociListCopy) + + neuralNetworkInput, quantityOfLociKnown, quantityOfPhasedLoci, err := createInputNeuralNetworkLayerFromGenomeMap(attributeLociListCopy, genomeMap) if (err != nil) { return false, false, 0, nil, 0, 0, err } if (quantityOfLociKnown == 0){ - // We can't predict anything about this trait for this genome + // We can't predict anything about this attribute for this genome return true, false, 0, nil, 0, 0, nil } @@ -522,25 +512,25 @@ func GetNeuralNetworkNumericTraitPredictionFromGenomeMap(traitName string, genom outputLayer, err := GetNeuralNetworkRawPrediction(&neuralNetworkObject, true, neuralNetworkInput) if (err != nil) { return false, false, 0, nil, 0, 0, err } - predictedOutcomeValue, err := GetNumericOutcomeValueFromOutputLayer(traitName, outputLayer) + predictedOutcomeValue, err := GetNumericOutcomeValueFromOutputLayer(attributeName, outputLayer) if (err != nil) { return false, false, 0, nil, 0, 0, err } - modelTraitAccuracyInfoFile, err := geneticPredictionModels.GetPredictionModelNumericTraitAccuracyInfoBytes(traitName) + modelAccuracyInfoFile, err := geneticPredictionModels.GetPredictionModelNumericAttributeAccuracyInfoBytes(attributeName) if (err != nil) { return false, false, 0, nil, 0, 0, err } - modelTraitAccuracyInfoMap, err := DecodeBytesToNumericTraitPredictionAccuracyInfoMap(modelTraitAccuracyInfoFile) + modelAccuracyInfoMap, err := DecodeBytesToNumericAttributePredictionAccuracyInfoMap(modelAccuracyInfoFile) if (err != nil) { return false, false, 0, nil, 0, 0, err } // We create a prediction confidence ranges map for our prediction getPredictionConfidenceRangesMap := func()map[int]float64{ - totalNumberOfTraitLoci := len(traitRSIDsList) + totalNumberOfAttributeLoci := len(attributeLociListCopy) - proportionOfLociTested := float64(quantityOfLociKnown)/float64(totalNumberOfTraitLoci) + proportionOfLociTested := float64(quantityOfLociKnown)/float64(totalNumberOfAttributeLoci) percentageOfLociTested := int(proportionOfLociTested * 100) - proportionOfPhasedLoci := float64(quantityOfPhasedLoci)/float64(totalNumberOfTraitLoci) + proportionOfPhasedLoci := float64(quantityOfPhasedLoci)/float64(totalNumberOfAttributeLoci) percentageOfPhasedLoci := int(proportionOfPhasedLoci * 100) // This is a value between 0 and 100 that represents the most similar confidence ranges map for this prediction @@ -552,10 +542,10 @@ func GetNeuralNetworkNumericTraitPredictionFromGenomeMap(traitName string, genom // Y = Number of phased loci closestPredictionConfidenceRangesMapDistance := float64(0) - for traitOutcomeInfo, traitPredictionConfidenceRangesMap := range modelTraitAccuracyInfoMap{ + for attributeOutcomeInfo, attributePredictionConfidenceRangesMap := range modelAccuracyInfoMap{ - currentPercentageOfLociTested := traitOutcomeInfo.PercentageOfLociTested - currentPercentageOfPhasedLoci := traitOutcomeInfo.PercentageOfPhasedLoci + currentPercentageOfLociTested := attributeOutcomeInfo.PercentageOfLociTested + currentPercentageOfPhasedLoci := attributeOutcomeInfo.PercentageOfPhasedLoci // Distance Formula for 2 coordinates (x1, y1) and (x2, y2): // distance = √((x2 - x1)^2 + (y2 - y1)^2) @@ -567,12 +557,12 @@ func GetNeuralNetworkNumericTraitPredictionFromGenomeMap(traitName string, genom if (distance == 0){ // We found the exact prediction confidence ranges map - return traitPredictionConfidenceRangesMap + return attributePredictionConfidenceRangesMap } if (closestPredictionConfidenceRangesMap == nil || distance < closestPredictionConfidenceRangesMapDistance){ closestPredictionConfidenceRangesMapDistance = distance - closestPredictionConfidenceRangesMap = traitPredictionConfidenceRangesMap + closestPredictionConfidenceRangesMap = attributePredictionConfidenceRangesMap } } @@ -789,11 +779,11 @@ func GetDiscreteOutcomeNameFromOutputLayer(traitName string, verifyOutputLayer b // This function returns which outcome is being described from a neural network's final output layer -// This is only used for discrete traits +// This is only used for numeric traits and polygenic diseases // Outputs: // -float64: Output Value (example: 150 centimeters) // -error -func GetNumericOutcomeValueFromOutputLayer(traitName string, outputLayer []float32)(float64, error){ +func GetNumericOutcomeValueFromOutputLayer(attributeName string, outputLayer []float32)(float64, error){ if (len(outputLayer) != 1){ return 0, errors.New("GetNumericOutcomeValueFromOutputLayer called with output layer which is not length of 1") @@ -807,15 +797,19 @@ func GetNumericOutcomeValueFromOutputLayer(traitName string, outputLayer []float getOutcomeMinAndMax := func()(float64, float64, error){ - switch traitName{ + switch attributeName{ case "Height":{ // Shortest person of all time: 54 cm // Tallest person of all time: 272 cm return 54, 272, nil } + case "Autism", + "Homosexualness":{ + return 0, 10, nil + } } - return 0, 0, errors.New("GetNumericOutcomeValueFromOutputLayer called with unknown traitName: " + traitName) + return 0, 0, errors.New("GetNumericOutcomeValueFromOutputLayer called with unknown attributeName: " + attributeName) } outcomeMin, outcomeMax, err := getOutcomeMinAndMax() @@ -833,9 +827,9 @@ func GetNumericOutcomeValueFromOutputLayer(traitName string, outputLayer []float // -int: Layer 3 neuron count // -int: Layer 4 neuron count (output layer) // -error -func getNeuralNetworkLayerSizes(traitName string)(int, int, int, int, error){ +func getNeuralNetworkLayerSizes(attributeName string)(int, int, int, int, error){ - switch traitName{ + switch attributeName{ case "Eye Color":{ @@ -856,9 +850,19 @@ func getNeuralNetworkLayerSizes(traitName string)(int, int, int, int, error){ // There is 1 output neuron, representing a height value return 3000, 3, 2, 1, nil } + case "Autism":{ + // There are 1428 input neurons + // There is 1 output neuron, representing an autism value + return 1428, 3, 2, 1, nil + } + case "Homosexualness":{ + // There are 12 input neurons + // There is 1 output neuron, representing a homosexualness value + return 12, 10, 5, 1, nil + } } - return 0, 0, 0, 0, errors.New("getNeuralNetworkLayerSizes called with unknown traitName: " + traitName) + return 0, 0, 0, 0, errors.New("getNeuralNetworkLayerSizes called with unknown attributeName: " + attributeName) } //This function converts a genome allele to a neuron to use in a tensor @@ -903,22 +907,50 @@ func convertAlleleToNeuron(allele string)(float32, error){ // -[]TrainingData: List of TrainingData for the user which we will use to train the model // -error func CreateGeneticPredictionTrainingData_OpenSNP( - traitName string, + attributeName string, userPhenotypeDataObject readBiobankData.PhenotypeData_OpenSNP, userLocusValuesMap map[int64]locusValue.LocusValue)(bool, []TrainingData, error){ - if (traitName != "Eye Color" && traitName != "Lactose Tolerance" && traitName != "Height"){ - return false, nil, errors.New("CreateGeneticPredictionTrainingData_OpenSNP called with unknown traitName: " + traitName) + //Outputs: + // -[]int64: Attribute rsIDs list + // -error + getAttributeLociList := func()([]int64, error){ + + switch attributeName{ + + case "Eye Color", + "Lactose Tolerance", + "Height", + "Homosexualness":{ + + traitObject, err := traits.GetTraitObject(attributeName) + if (err != nil) { return nil, err } + + // This is a list of rsIDs which influence this trait + traitLociList := traitObject.LociList + + return traitLociList, nil + } + case "Autism":{ + + diseaseObject, err := polygenicDiseases.GetPolygenicDiseaseObject(attributeName) + if (err != nil) { return nil, err } + + // This is a list of rsIDs which influence this disease + diseaseLociList := diseaseObject.LociList + + return diseaseLociList, nil + } + } + + return nil, errors.New("CreateGeneticPredictionTrainingData_OpenSNP called with unknown attributeName: " + attributeName) } - traitObject, err := traits.GetTraitObject(traitName) + attributeLociList, err := getAttributeLociList() if (err != nil) { return false, nil, err } - // This is a list of rsIDs which influence this trait - traitRSIDsList := traitObject.LociList - - if (len(traitRSIDsList) == 0){ - return false, nil, errors.New("traitObject contains no rsIDs.") + if (len(attributeLociList) == 0){ + return false, nil, errors.New("getAttributeLociList returning empty attributeLociList.") } // Each layer is represented as a []float32 @@ -927,7 +959,7 @@ func CreateGeneticPredictionTrainingData_OpenSNP( // Each TrainingData holds a variation of the user's genome rsID values // We add many rows with withheld data to improve training data - numberOfInputLayerRows, _, _, numberOfOutputLayerRows, err := getNeuralNetworkLayerSizes(traitName) + numberOfInputLayerRows, _, _, numberOfOutputLayerRows, err := getNeuralNetworkLayerSizes(attributeName) if (err != nil) { return false, nil, err } // Each rsID is represented by 3 neurons: LocusExists/LocusIsPhased, Allele1 Value, Allele2 Value @@ -935,7 +967,7 @@ func CreateGeneticPredictionTrainingData_OpenSNP( // -0 = Locus value is unknown // -0.5 = Locus Is known, phase is unknown // -1 = Locus Is Known, phase is known - expectedNumberOfInputLayerRows := len(traitRSIDsList) * 3 + expectedNumberOfInputLayerRows := len(attributeLociList) * 3 if (numberOfInputLayerRows != expectedNumberOfInputLayerRows){ @@ -944,9 +976,9 @@ func CreateGeneticPredictionTrainingData_OpenSNP( return false, nil, errors.New("numberOfInputLayerRows is not expected: " + expectedNumberOfInputLayerRowsString) } - checkIfAnyTraitLocusValuesExist := func()bool{ + checkIfAnyAttributeLocusValuesExist := func()bool{ - for _, rsID := range traitRSIDsList{ + for _, rsID := range attributeLociList{ _, exists := userLocusValuesMap[rsID] if (exists == true){ @@ -957,29 +989,29 @@ func CreateGeneticPredictionTrainingData_OpenSNP( return false } - anyTraitLocusValuesExist := checkIfAnyTraitLocusValuesExist() - if (anyTraitLocusValuesExist == false){ - // The user's genome does not contain any of this trait's locus values + anyAttributeLocusValuesExist := checkIfAnyAttributeLocusValuesExist() + if (anyAttributeLocusValuesExist == false){ + // The user's genome does not contain any of this attribute's locus values // We will not train on their data return false, nil, nil } // We sort rsIDs in ascending order - traitRSIDsListCopy := slices.Clone(traitRSIDsList) - slices.Sort(traitRSIDsListCopy) + attributeLociListCopy := slices.Clone(attributeLociList) + slices.Sort(attributeLociListCopy) // This function returns the outputLayer for all trainingDatas for this user - // Each outputLayer represents the user's trait value (Example: "Blue" for Eye Color) + // Each outputLayer represents the user's attribute value (Example: "Blue" for Eye Color) // Each outputLayer is identical, because each TrainingData example belongs to the same user // // Outputs: - // -bool: User trait value is known + // -bool: User attribute value is known // -[]float32: Neuron values for layer // -error - getUserTraitValueNeurons := func()(bool, []float32, error){ + getUserAttributeValueNeurons := func()(bool, []float32, error){ - switch traitName{ + switch attributeName{ case "Eye Color":{ @@ -1044,23 +1076,53 @@ func CreateGeneticPredictionTrainingData_OpenSNP( outputLayer := []float32{outputValueFloat32} + return true, outputLayer, nil + } + case "Autism":{ + + userAutismIsKnown := userPhenotypeDataObject.AutismIsKnown + if (userAutismIsKnown == false){ + return false, nil, nil + } + + userAutism := userPhenotypeDataObject.Autism + + outputValueFloat32 := float32(userAutism) + + outputLayer := []float32{outputValueFloat32} + + return true, outputLayer, nil + } + case "Homosexualness":{ + + userHomosexualnessIsKnown := userPhenotypeDataObject.HomosexualnessIsKnown + if (userHomosexualnessIsKnown == false){ + return false, nil, nil + } + + userHomosexualness := userPhenotypeDataObject.Homosexualness + + outputValueFloat32 := float32(userHomosexualness) + + outputLayer := []float32{outputValueFloat32} + return true, outputLayer, nil } } - return false, nil, errors.New("Unknown traitName: " + traitName) + return false, nil, errors.New("Unknown attributeName: " + attributeName) } - userTraitValueExists, userTraitValueNeurons, err := getUserTraitValueNeurons() + userAttributeValueExists, userAttributeValueNeurons, err := getUserAttributeValueNeurons() if (err != nil) { return false, nil, err } - if (userTraitValueExists == false){ + if (userAttributeValueExists == false){ // User cannot be used to train the model. - // They do not have a value for this trait. + // They do not have a value for this attribute. return false, nil, nil } - if (len(userTraitValueNeurons) != numberOfOutputLayerRows){ - return false, nil, errors.New("getUserTraitValueNeurons returning invalid length layer slice.") + if (len(userAttributeValueNeurons) != numberOfOutputLayerRows){ + return false, nil, errors.New("getUserAttributeValueNeurons returning invalid length layer slice.") } // We want the initial training data to be the same for each call of this function that has the same input parameters @@ -1134,11 +1196,11 @@ func CreateGeneticPredictionTrainingData_OpenSNP( anyLocusExists := false - inputLayerLength := len(traitRSIDsListCopy) * 3 + inputLayerLength := len(attributeLociListCopy) * 3 inputLayer := make([]float32, 0, inputLayerLength) - for _, rsID := range traitRSIDsListCopy{ + for _, rsID := range attributeLociListCopy{ randomFloat := pseudorandomNumberGenerator.Float64() if (randomFloat > probabilityOfUsingLoci){ @@ -1209,11 +1271,11 @@ func CreateGeneticPredictionTrainingData_OpenSNP( continue } - userTraitValueNeuronsCopy := slices.Clone(userTraitValueNeurons) + userAttributeValueNeuronsCopy := slices.Clone(userAttributeValueNeurons) newTrainingData := TrainingData{ InputLayer: inputLayer, - OutputLayer: userTraitValueNeuronsCopy, + OutputLayer: userAttributeValueNeuronsCopy, } trainingDataList = append(trainingDataList, newTrainingData) @@ -1222,9 +1284,9 @@ func CreateGeneticPredictionTrainingData_OpenSNP( return true, trainingDataList, nil } -func GetNewUntrainedNeuralNetworkObject(traitName string)(*NeuralNetwork, error){ +func GetNewUntrainedNeuralNetworkObject(attributeName string)(*NeuralNetwork, error){ - layer1NeuronCount, layer2NeuronCount, layer3NeuronCount, layer4NeuronCount, err := getNeuralNetworkLayerSizes(traitName) + layer1NeuronCount, layer2NeuronCount, layer3NeuronCount, layer4NeuronCount, err := getNeuralNetworkLayerSizes(attributeName) if (err != nil) { return nil, err } // This is the graph object we add each layer to @@ -1304,10 +1366,10 @@ func (inputNetwork *NeuralNetwork)getLearnables()gorgonia.Nodes{ // This function will train the neural network // The function is passed a batch of TrainingData examples to train on // Inputs: -// -string: Trait Name -// -bool: Trait is Numeric -// -An example of a numeric trait is Height -// -An example of a discrete trait is Eye Color, which has discrete outcomes (colors) +// -string: Attribute Name +// -bool: Attribute is Numeric +// -An example of a numeric attribute is Height +// -An example of a discrete attribute is Eye Color, which has discrete outcomes (colors) // -*NeuralNetwork // -func()(bool, bool, TrainingData, error): Function to get the next training data. // -Outputs: @@ -1318,9 +1380,9 @@ func (inputNetwork *NeuralNetwork)getLearnables()gorgonia.Nodes{ // Outputs: // -bool: Process completed (was not stopped mid-way) // -error -func TrainNeuralNetwork(traitName string, traitIsNumeric bool, neuralNetworkObject *NeuralNetwork, getNextTrainingData func()(bool, bool, TrainingData, error))(bool, error){ +func TrainNeuralNetwork(attributeName string, attributeIsNumeric bool, neuralNetworkObject *NeuralNetwork, getNextTrainingData func()(bool, bool, TrainingData, error))(bool, error){ - layer1NeuronCount, _, _, layer4NeuronCount, err := getNeuralNetworkLayerSizes(traitName) + layer1NeuronCount, _, _, layer4NeuronCount, err := getNeuralNetworkLayerSizes(attributeName) if (err != nil) { return false, err } neuralNetworkGraph := neuralNetworkObject.graph @@ -1340,7 +1402,7 @@ func TrainNeuralNetwork(traitName string, traitIsNumeric bool, neuralNetworkObje gorgonia.WithShape(1, layer4NeuronCount), ) - err = neuralNetworkObject.buildNeuralNetwork(trainingDataInputNode, traitIsNumeric) + err = neuralNetworkObject.buildNeuralNetwork(trainingDataInputNode, attributeIsNumeric) if (err != nil) { return false, err } // This computes the loss (how accurate was our prediction) @@ -1431,7 +1493,7 @@ func TrainNeuralNetwork(traitName string, traitIsNumeric bool, neuralNetworkObje // Outputs: // -[]float32: Output neurons // -error -func GetNeuralNetworkRawPrediction(inputNeuralNetwork *NeuralNetwork, traitIsNumeric bool, inputLayer []float32)([]float32, error){ +func GetNeuralNetworkRawPrediction(inputNeuralNetwork *NeuralNetwork, attributeIsNumeric bool, inputLayer []float32)([]float32, error){ neuralNetworkGraph := inputNeuralNetwork.graph @@ -1455,7 +1517,7 @@ func GetNeuralNetworkRawPrediction(inputNeuralNetwork *NeuralNetwork, traitIsNum if (err != nil) { return nil, err } - err = inputNeuralNetwork.buildNeuralNetwork(inputNode, traitIsNumeric) + err = inputNeuralNetwork.buildNeuralNetwork(inputNode, attributeIsNumeric) if (err != nil){ return nil, err } // Now we create a virtual machine to compute the prediction @@ -1479,7 +1541,7 @@ func GetNeuralNetworkRawPrediction(inputNeuralNetwork *NeuralNetwork, traitIsNum // This function will take a neural network and input layer and build the network to be able to compute a prediction // We need to run a virtual machine after calling this function in order for the prediction to be generated -func (inputNetwork *NeuralNetwork)buildNeuralNetwork(inputLayer *gorgonia.Node, traitIsNumeric bool)error{ +func (inputNetwork *NeuralNetwork)buildNeuralNetwork(inputLayer *gorgonia.Node, predictionIsNumeric bool)error{ // We copy node pointer (says to do this in a resource i'm reading) @@ -1518,7 +1580,7 @@ func (inputNetwork *NeuralNetwork)buildNeuralNetwork(inputLayer *gorgonia.Node, return errors.New("Layer 3 multiplication failed: " + err.Error()) } - if (traitIsNumeric == false){ + if (predictionIsNumeric == false){ // We SoftMax the output to get the prediction diff --git a/internal/genetics/readGeneticAnalysis/readGeneticAnalysis.go b/internal/genetics/readGeneticAnalysis/readGeneticAnalysis.go index 1039c3a..bae6a1b 100644 --- a/internal/genetics/readGeneticAnalysis/readGeneticAnalysis.go +++ b/internal/genetics/readGeneticAnalysis/readGeneticAnalysis.go @@ -483,193 +483,74 @@ func GetOffspringMonogenicDiseaseVariantInfoFromGeneticAnalysis(coupleAnalysisOb return true, probabilityOf0MutationsLowerBound, probabilityOf0MutationsUpperBound, probabilityOf0MutationsFormatted, probabilityOf1MutationLowerBound, probabilityOf1MutationUpperBound, probabilityOf1MutationFormatted, probabilityOf2MutationsLowerBound, probabilityOf2MutationsUpperBound, probabilityOf2MutationsFormatted, nil } - //Outputs: -// -bool: Polygenic Disease Risk Score known (any loci values exist) -// -int: Person Disease risk score -// -string: Person Disease risk score formatted (has "/10" suffix) -// -int: Quantity of loci tested -// -bool: Conflict exists +// -bool: Any analysis exists +// -int: Predicted risk score (0-10) +// -map[int]float64: Prediction confidence ranges map +// -Map Structure: Percentage probability of accurate prediction -> distance of range in both directions from prediction +// -int: Quantity of loci known +// -int: Quantity of phased loci +// -bool: Conflict exists (between any of these results for each genome) // -error -func GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis, diseaseName string, genomeIdentifier [16]byte)(bool, int, string, int, bool, error){ +func GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis, diseaseName string, genomeIdentifier [16]byte)(bool, int, map[int]float64, int, int, bool, error){ personPolygenicDiseasesMap := personAnalysisObject.PolygenicDiseasesMap - personPolygenicDiseaseInfo, exists := personPolygenicDiseasesMap[diseaseName] + personDiseaseInfoObject, exists := personPolygenicDiseasesMap[diseaseName] if (exists == false){ - return false, 0, "", 0, false, nil + return false, 0, nil, 0, 0, false, nil } - personPolygenicDiseaseInfoMap := personPolygenicDiseaseInfo.PolygenicDiseaseInfoMap + personDiseaseInfoMap := personDiseaseInfoObject.PolygenicDiseaseInfoMap + conflictExists := personDiseaseInfoObject.ConflictExists - genomePolygenicDiseaseInfo, exists := personPolygenicDiseaseInfoMap[genomeIdentifier] + personGenomeDiseaseInfoObject, exists := personDiseaseInfoMap[genomeIdentifier] if (exists == false){ - return false, 0, "", 0, false, nil + return false, 0, nil, 0, 0, false, nil } - conflictExists := personPolygenicDiseaseInfo.ConflictExists + predictedRiskScore := personGenomeDiseaseInfoObject.RiskScore + confidenceRangesMap := personGenomeDiseaseInfoObject.ConfidenceRangesMap + quantityOfLociKnown := personGenomeDiseaseInfoObject.QuantityOfLociKnown + quantityOfPhasedLoci := personGenomeDiseaseInfoObject.QuantityOfPhasedLoci - personDiseaseRiskScore := genomePolygenicDiseaseInfo.RiskScore - - personDiseaseRiskScoreString := helpers.ConvertIntToString(personDiseaseRiskScore) - - personDiseaseRiskScoreFormatted := personDiseaseRiskScoreString + "/10" - - quantityOfLociTested := genomePolygenicDiseaseInfo.QuantityOfLociTested - - return true, personDiseaseRiskScore, personDiseaseRiskScoreFormatted, quantityOfLociTested, conflictExists, nil + return true, predictedRiskScore, confidenceRangesMap, quantityOfLociKnown, quantityOfPhasedLoci, conflictExists, nil } //Outputs: -// -bool: Offspring Disease Risk Score known -// -int: Offspring average disease risk score -// -string: Offspring Disease average risk score formatted (has "/10" suffix) -// -[]int: Sample Offspring Risk Scores List -// -int: Quantity of loci tested -// -bool: Conflict exists +// -bool: Analysis exists +// -int: Average offspring risk score (0-10) +// -map[int]float64: Prediction confidence ranges map +// -int: Quantity of loci known +// -int: Quantity of Parental phased loci +// -[]int: 100 Sample offspring risk scores +// -bool: Conflict exists (Between this genome pair and other genome pairs) // -error -func GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, genomePairIdentifier [32]byte)(bool, int, string, []int, int, bool, error){ +func GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, genomePairIdentifier [32]byte)(bool, int, map[int]float64, int, int, []int, bool, error){ - couplePolygenicDiseasesMap := coupleAnalysisObject.PolygenicDiseasesMap + offspringDiseasesMap := coupleAnalysisObject.PolygenicDiseasesMap - couplePolygenicDiseaseInfo, exists := couplePolygenicDiseasesMap[diseaseName] + diseaseInfoObject, exists := offspringDiseasesMap[diseaseName] if (exists == false){ - return false, 0, "", nil, 0, false, nil + return false, 0, nil, 0, 0, nil, false, nil } - polygenicDiseaseInfoMap := couplePolygenicDiseaseInfo.PolygenicDiseaseInfoMap + diseaseInfoMap := diseaseInfoObject.PolygenicDiseaseInfoMap + conflictExists := diseaseInfoObject.ConflictExists - genomePairPolygenicDiseaseInfo, exists := polygenicDiseaseInfoMap[genomePairIdentifier] + genomePairDiseaseInfoObject, exists := diseaseInfoMap[genomePairIdentifier] if (exists == false){ - return false, 0, "", nil, 0, false, nil + return false, 0, nil, 0, 0, nil, false, nil } - conflictExists := couplePolygenicDiseaseInfo.ConflictExists + offspringAverageRiskScore := genomePairDiseaseInfoObject.OffspringAverageRiskScore + predictionConfidenceRangesMap := genomePairDiseaseInfoObject.PredictionConfidenceRangesMap + quantityOfLociKnown := genomePairDiseaseInfoObject.QuantityOfLociKnown + quantityOfParentalPhasedLoci := genomePairDiseaseInfoObject.QuantityOfParentalPhasedLoci + sampleOffspringRiskScoresList := genomePairDiseaseInfoObject.SampleOffspringRiskScoresList - quantityOfLociTested := genomePairPolygenicDiseaseInfo.QuantityOfLociTested - - offspringAverageRiskScore := genomePairPolygenicDiseaseInfo.OffspringAverageRiskScore - - offspringAverageRiskScoreString := helpers.ConvertIntToString(offspringAverageRiskScore) - - offspringAverageRiskScoreFormatted := offspringAverageRiskScoreString + "/10" - - sampleOffspringRiskScoresList := genomePairPolygenicDiseaseInfo.SampleOffspringRiskScoresList - - return true, offspringAverageRiskScore, offspringAverageRiskScoreFormatted, sampleOffspringRiskScoresList, quantityOfLociTested, conflictExists, nil -} - -//Outputs: -// -bool: Risk Weight and base pair known -// -int: Locus risk weight -// -bool: Locus odds ratio known -// -float64: Locus odds ratio -// -string: Locus odds ratio formatted (with x suffix) -// -error -func GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(personAnalyisObject geneticAnalysis.PersonAnalysis, diseaseName string, locusIdentifier [3]byte, genomeIdentifier [16]byte)(bool, int, bool, float64, string, error){ - - personPolygenicDiseasesMap := personAnalyisObject.PolygenicDiseasesMap - - personPolygenicDiseaseMap, exists := personPolygenicDiseasesMap[diseaseName] - if (exists == false){ - return false, 0, false, 0, "", nil - } - - personPolygenicDiseaseInfoMap := personPolygenicDiseaseMap.PolygenicDiseaseInfoMap - - personGenomePolygenicDiseaseInfo, exists := personPolygenicDiseaseInfoMap[genomeIdentifier] - if (exists == false){ - return false, 0, false, 0, "", nil - } - - genomeLociInfoMap := personGenomePolygenicDiseaseInfo.LociInfoMap - - locusInfoObject, exists := genomeLociInfoMap[locusIdentifier] - if (exists == false){ - return false, 0, false, 0, "", nil - } - - locusRiskWeight := locusInfoObject.RiskWeight - - locusOddsRatioIsKnown := locusInfoObject.OddsRatioIsKnown - if (locusOddsRatioIsKnown == false){ - return true, locusRiskWeight, false, 0, "", nil - } - - locusOddsRatio := locusInfoObject.OddsRatio - - genomeLocusOddsRatioString := helpers.ConvertFloat64ToStringRounded(locusOddsRatio, 2) - - locusOddsRatioFormatted := genomeLocusOddsRatioString + "x" - - return true, locusRiskWeight, true, locusOddsRatio, locusOddsRatioFormatted, nil -} - -//Outputs: -// -bool: Offspring risk weight known -// -int: Offspring risk weight -// -bool: Offspring odds ratio known -// -float64: Offspring odds ratio -// -string: Offspring odds ratio formatted (with + and < from unknownFactors weight sum and x suffix) -// -error -func GetOffspringPolygenicDiseaseLocusInfoFromGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, locusIdentifier [3]byte, genomePairIdentifier [32]byte)(bool, int, bool, float64, string, error){ - - offspringPolygenicDiseasesMap := coupleAnalysisObject.PolygenicDiseasesMap - - offspringPolygenicDiseaseInfo, exists := offspringPolygenicDiseasesMap[diseaseName] - if (exists == false){ - return false, 0, false, 0, "", nil - } - - offspringPolygenicDiseaseMap := offspringPolygenicDiseaseInfo.PolygenicDiseaseInfoMap - - genomePairPolygenicDiseaseInfo, exists := offspringPolygenicDiseaseMap[genomePairIdentifier] - if (exists == false){ - return false, 0, false, 0, "", nil - } - - genomePairLociInfoMap := genomePairPolygenicDiseaseInfo.LociInfoMap - - locusInfoObject, exists := genomePairLociInfoMap[locusIdentifier] - if (exists == false){ - return false, 0, false, 0, "", nil - } - - offspringAverageRiskWeight := locusInfoObject.OffspringAverageRiskWeight - offspringOddsRatioIsKnown := locusInfoObject.OffspringOddsRatioIsKnown - - if (offspringOddsRatioIsKnown == false){ - return true, offspringAverageRiskWeight, false, 0, "", nil - } - - offspringAverageOddsRatio := locusInfoObject.OffspringAverageOddsRatio - - getOddsRatioFormatted := func()string{ - - offspringAverageUnknownOddsRatiosWeightSum := locusInfoObject.OffspringAverageUnknownOddsRatiosWeightSum - - offspringAverageOddsRatioString := helpers.ConvertFloat64ToStringRounded(offspringAverageOddsRatio, 2) - - if (offspringAverageUnknownOddsRatiosWeightSum == 0){ - result := offspringAverageOddsRatioString + "x" - - return result - } - if (offspringAverageUnknownOddsRatiosWeightSum < 0){ - result := "<" + offspringAverageOddsRatioString + "x" - - return result - } - // offspringAverageUnknownOddsRatiosWeightSum > 0 - result := offspringAverageOddsRatioString + "x+" - - return result - } - - oddsRatioFormatted := getOddsRatioFormatted() - - return true, offspringAverageRiskWeight, true, offspringAverageOddsRatio, oddsRatioFormatted, nil + return true, offspringAverageRiskScore, predictionConfidenceRangesMap, quantityOfLociKnown, quantityOfParentalPhasedLoci, sampleOffspringRiskScoresList, conflictExists, nil } //Outputs: @@ -892,7 +773,6 @@ func GetOffspringDiscreteTraitRuleInfoFromGeneticAnalysis(coupleAnalysisObject g } - //Outputs: // -bool: Any analysis exists // -float64: Predicted outcome (Example: Height in centimeters) @@ -964,6 +844,8 @@ func GetOffspringNumericTraitInfoFromGeneticAnalysis(coupleAnalysisObject geneti return true, offspringAverageOutcome, predictionConfidenceRangesMap, quantityOfLociKnown, quantityOfParentalPhasedLoci, sampleOffspringOutcomesList, conflictExists, nil } + + // We use this function to verify a person genetic analysis is well formed //TODO: Perform sanity checks on data func VerifyPersonGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis)error{ @@ -1015,25 +897,9 @@ func VerifyPersonGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnal for _, genomeIdentifier := range allGenomeIdentifiersList{ - _, _, _, _, _, err := GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, genomeIdentifier) + _, _, _, _, _, _, err := GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, genomeIdentifier) if (err != nil) { return err } } - - diseaseLocusObjectsList := diseaseObject.LociList - - for _, diseaseLocusObject := range diseaseLocusObjectsList{ - - locusIdentifierHex := diseaseLocusObject.LocusIdentifier - - locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex) - if (err != nil) { return err } - - for _, genomeIdentifier := range allGenomeIdentifiersList{ - - _, _, _, _, _, err := GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, locusIdentifier, genomeIdentifier) - if (err != nil) { return err } - } - } } traitObjectsList, err := traits.GetTraitObjectsList() @@ -1138,25 +1004,9 @@ func VerifyCoupleGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnal for _, genomePairIdentifier := range allGenomePairIdentifiersList{ - _, _, _, _, _, _, err := GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, genomePairIdentifier) + _, _, _, _, _, _, _, err := GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, genomePairIdentifier) if (err != nil) { return err } } - - diseaseLocusObjectsList := diseaseObject.LociList - - for _, diseaseLocusObject := range diseaseLocusObjectsList{ - - locusIdentifierHex := diseaseLocusObject.LocusIdentifier - - locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex) - if (err != nil) { return err } - - for _, genomePairIdentifier := range allGenomePairIdentifiersList{ - - _, _, _, _, _, err := GetOffspringPolygenicDiseaseLocusInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, locusIdentifier, genomePairIdentifier) - if (err != nil) { return err } - } - } } traitObjectsList, err := traits.GetTraitObjectsList() diff --git a/internal/genetics/sampleAnalyses/SampleCoupleAnalysis.messagepack b/internal/genetics/sampleAnalyses/SampleCoupleAnalysis.messagepack index f85b8108393fb5d4aff124e7f7cc1674931dbddc..52b1029a28a84b1b215e8b2cf52baa27bbf458a8 100644 GIT binary patch literal 14148 zcmeHNU2GIp6rN>h5k)Dq{uR(g1hKTxZUIrK-L|x}^l#}FP=3Ve?A{?Gu9i1QJeXE5AgJ`I{^R|hVn#8R1+m^v2q z8!7r#k;6dLvp`iV=U88U1I@}Fl*e;kmZ2q4@1%Cpp812+i@1=wdn+X%PZYZ9)Q;gz z9a4{R>f@z6$5$hcp;s~@qC_N?Qguy-^L(Pj(DnkRO5kyxyw|Ztrf@n)zH;w6N?=hDuxZ2;1%lxhO5Rw zRE;hYi#fiY>po=;b3`0Rb?Q#zs4&mrfkjY#=p|+a$i?>4%{{Y+Sdd;SOO%9nm{`Ks zBO#ZUIgckIW^G*^VC+N2$ru)WE{HPQH{&4O^=hO@vEDdA$uNp1EIBPT1i#Yf|tcE-{3O}mQ2@aMEW##*p^=)!HZ&}~`J9b&tx1A+@mi6syTDoO@t0$T*>)W2G(=6-T$sFs} zT&4Un%f@Zzr&lfOTkp|dE$f@_>~hQcwsiOAXnb>MzG4`?zd7#wZW<91e#6zyG>rGR zx!)g;#<%4Rb~Q(DziBgM7;*di?b4S_g-=D7I)u*>B``K zHjOGMt~%7>+~!f7NrZd=w{f3VoKtV#zJ)1=;!M2R7vvQOrJ?6oxbs=U(@dz(nAaI* zx^Rn^lPK1;6*o^kK}h9EH&u&!&R`nYB$nXr_s@hU?jAhaJ$eMUN@)Q}s8XO9DcI$0 zK3Ir5^7cy9Ajtx1Iv5f}zxK_?%8)EjY#Ea3d7(x<3Oa@`2YzRu3QrgcxAoXzsmf)E z#y>s?H$RzBw7QO{;SEQUFbWJ|8W^IbLS~T|GN$`jh#qQS_ZLH$Q5e>^FHaU&pQkfy zF>aB&C{e`y>Cj+!p?3txeFa}G3y_ZA>XQQGA%~P2AZyN?TM;0?V^276=lJ3e`0vf% z*eum^ycQ3g)c>YOUhT?2%hB&&caU)4T1Ua!~u zu<9i|k0{OwpWnjC5d6qMPTK3iR1Q#YD$ZwGh&`D1B;Xc;6n~&lb*BSWsW{^*ZBDFF z1-gZx@jT#O1zwzzedEA{53mLW8uI|R5^z~SZNj*B(!RwS3xM}9Xe0r(0;JP`mkT_X z;+%MW<41TDd?>4aOaaQKWdFG3uk%>C6f_nCHBrg_r?0ILOH+Yo2i*jqR)e$%s63#O z0rw(MYrv{4up0QPP$NUaymLWgIY?&%?+sX?`M`S=r~=TSVUEq9u>_>qKs^h(&j5u# zMX6Td>rGw1Wx$Jvs6GYK4fx|#e>OP*mkHEsSlS=ea#(|@po=d_b+(s)N(bt3z^#Y; zn*+QO7;l1-{ZrN)95x~Ybn!KkVDv;ZV8EEDn~3gC9R}2^0|$thz@TM9=m!Kai1b8E7(Ey` iCWL;{XgK--^;&=d5pYZh00W^1n}`4m7?sc#6#oO>0t!O_ literal 15184 zcmeHOYitx%6rM7n#ApOl5)vNC8m(d}2tzd(HTD68+Sk%8G$Hty&fG1RPG_2VSe8H9 zT3U=6e+dcxK?92ARoarKwrJT-gixcRCS(Z~5G4FC2#QD$qjzU#XSTPq%WStxhN1iG z?##L8eBV9y-Z^v6nGs^f!2+J<0uq$g0#SkjpE2O2p}540{t5h&m4Fu-KnV+Y8Tug* z)fpYwFIJoyE8dU&I(>i7XOXUhD!$uB7 zKuSUV7G-fOv_S7x$#a1fn;1@EL6N}wImpP;SdzHW(EOP0CA`+%w}BP`Yoo7jno7;I z);&qnJ>>!~)Bzqc%b^5l2}tF1W6Qy!fFwi4Qw(cG0nL-Q`&TP8nhtWH(!Z7#A!M_+2p*SL@76P+GMYY7Bi7ykQMqU?G-!RDC`u&YM-R;e5Mdr z#5|e6Ev2we{{8VHJKXNcXTZ+skGPiGAIsl&Ew|#|&)eaKM+;W#&2eXVfm6@h;dW21 zx0=jOJKXH}E$*SQdG;FDwdOvFk75e@WS-}!9d5YA^vy|p6jR`qwWG_W+zv$ZVtP8S z%Lkcy4tRGe#K>$QTh5lrbXkj8U^ndN0@9C-bAnD{uik$=JNV zP(%qw*;7RG3=ms-aUuKp!PXu#Jy|9&Fp`>_)mQ1)Gld0j0FkZ(RZyz;F@gw)yyoYadZ3(Z@)8AD?DrK^!NaVQ5@y@sz3XDkg- zDPqT`G!QD8ed4xrz`Q&y*EwJooqN(bVAlP0!8u@Vc4a#U%(Ur`I|s~9wL&_;T+7O@ z*tKUU$)){4-Q0A58Q(rby?53*U{2f;odf3G2d6j(%q?c*bx6M@Mv;{@ZWZzqJfIj#_*;3%62%zxtq^V{b0D-XmvJz_5u7ij4_qOn<21I4g3?RBkzffw` zrNn@F(TfUud70+C8&JtC8-AH2I;s>7NE(=-Zmm5U;L!e27i|D*-d&`KT!0-g5eF*$ zURsh+@vEi`4RpIoQWu(Ls^oXvVM-+rP;#zH)}K86f=cFH`T+!!Gn` zjv4h;(R`g25w@=x&R-f*I#KA%4(I1Bym1`09v;r0vvF>?HFr3FanP5GS~*7RIn+9R u^dWR@rO~otot4nBPxNEay&kegV|xStWMhyZCI?}15F*R@Zq5XJ+xj2qv+M)_ diff --git a/internal/genetics/sampleAnalyses/SamplePerson1Analysis.messagepack b/internal/genetics/sampleAnalyses/SamplePerson1Analysis.messagepack index 8d0f514451a9e5cae4a961c578c29f5c434c3360..f4135b664ae6ef79185cafd4628305b8237c4553 100644 GIT binary patch delta 5248 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 delta 4597 zcmbVO3sh8P9-o=-@=!qr0Y`)ZhPQ&u-1}V`@ii9^5kx`cVT$qwM-32WMbR1*QQOK# z|5cZAQ!5L>45iZCwtPTpcU`q?J)0#DHFZ0y;H#I>{_p2GWv4QgbMBen_xSza|NlqJ zYE4s@dfj=Ax*2-HV_;(@g?FL_j$7qPVJc^W>$wz!X_UP8j0<$Rnut$zjq(c@9VwZ3 z`8;AHq?L-WoKVv4vIX*I6vEmZO5T;vGJZ)qg}-D|(s*$hTaQDz+4&SgBLzD*TUIBMv(yB&LX`17=>-g0;l5jzOX=N zg44+q+GYrF-bn-##^Ev%;Kpzf>M4b{5j!P|MB8x&45db*O3^`ns2;X*o=`lE!oR&x z(3UM9G7|-V5l&5}q-yM4_3J}XV4wgON1|5i2#_p}(34MzeByCtQDG(}1N51SVCd{G z!sl*OvnB}w)I8KW2r$k=BtDDIDbax1kpfgCicqH!h}y9Vx?FhhQ&Zyl=HF zZwj8{C~!U$V%^cFFbetE0$2u#aBvm{jh@1WECJd>L{Lwq#2VGhxCL1hT1R49H2JQu zyT6feM-8xkm>w$Bp0F;Qk|COHioMUL3veMugu!D_@0Qn@3%b!1f(j^X45YBwBEZ_2 z81WDO?97Z#)1W~EC|Q$K!!B#xD71{GWZ&A2iel27Jzv?^SU18pZxe7sMQ9JDa0heH zIS%d7e$oI2wTZOIIn2;Ao&ro5CxXtI676GFIHfni;h9*c0hDCF+77)Y9ufxfFvvoI zOcBY!x1!)wnh`uPwoa1-C>tz-BbJPR357rt)wDFg`WzlwoGILhpwJjk!NY|DpCLT& zCqg==zXrou7mdfWDLMQK^NK9(nWO4fCP&Oqm!|_M~`Rx zRYlmSduthQ;#f@A01BTBp-|}|z_-~VbYLmu2T@29u^f#2A|+L%pY0$zWrR7YB8eEk zodqe=MBzoOOPf2@OuPcU1uRBzXc#4JbT!kJ9Yx{g!4x*9M#HyZJjBOQaP+2RWKRSW z_qWL+Ii~Ai;$~nPn_{tac5B~M%0W|qjm3J_-c{`U$8<{ebStqn!opY)t{Jfn);Y7Y zz1U7KIwmun#8;`>MJ&HX8OnrfWOsV=sAkW9;FK?>O(zmByFa^bnLuGrj1o!%^cM1( zp>HTmGRI_P60TyFj{6DVFNkF0cY2oP1G5FfwT}Wr2@jctl(=1PVsjuGv-&cQy5mzR zJcm`cA?YYn5vRopS&o^)S>Zc}g1dy3DN2Ky1_2Z#S~t{Zq#Ck++!)3pZPUQ zQHei=LpfNE)=eKPevmi++s!P?LjP-)yJOdzpbn*8kED<{ox(~1W4M1MQKXWFDixcP zg*eK*ag+rVQz+93@HCEd0muAB2PE(!Bw`Wh@eR=o^sa_jPad`>3gB0YYJ)>Tz1^B{MB)r~(Sv=vZM3#Z?vncWJ zcY^H&I>$4yTZd4x^pH2hD@w6)4BHr*~xdHXG<((uEl>~1BN%866~Zst&qTg-(rVFsSU6b{=yq>ruT z015{p1jq{(i96rGOi?v#*u`=dhE)-KtBXBw)vh9RVgGga!?5>Dk46l--eHY1$y#k#;+dCG~x zlgb z#b-uC*E|tURG6W&%nYOP+ksy`uE#DgL+%r0P&eNUHpE`|+l;?c%FWQdAR4aCkAdS) zm?0d$;dtK>&u-vZCGyYBGs9nTPlxOG@Z)f=9)I`GkA}XvS_rH3QZIv>m0>We(!*Z& z*3>`cm)Weg#i=DJ<%QOa;woElk@t>tYt_7Ih2@pSs%B+7sjQ@Ya(=}*m3JG7>I|!E zQqHrBt)+8ps+QEEqN?A~uYMl%D7;Tps~&~+ z(RY=Y9mf=!4Jz* zXe*jteH7Z!b2UHH><`{QYfF89<~=y=nE{&n(Cok4uEMh&_u>66?PUGnhoNEomA^J} z=IKZB?#9+l_o`Fhe>mKz_uDu1tNJ$5df|n;H2cHNu)Kdg(&(FU>-@b|-ZP7Q?$dUy zzEu;{KK~rsbGVHxtGIfojikrrBA%2Jjre9~Wb2c*dbQz)3l6vxzx)`FB3_$`c;2bc z5DVw45ucdD5wfRcY+mh_3&oe_z$$5JW|? zH0o^4%ZLWbl1e(Z6%mmw=Z?LCK$Rm)LP}L4q7*dHyr3IVv@8Xf8A55Z5)rt zUzP@T?okX3LqAhrP>_c#X|6uef+$y(MCs-cMBcLGC^(wH{-n;HfvO89Dyntp>G$?L zMDEB5Xs$ryhEC1-F%3~a*>Y?13kXyNvh-N+W<_EiN?gysk4P#z?42#Cls!@Ez$CCcI+jfzV&MQaroaA6{Y0%|f!jX6C{ zHO+StjZKvvckNM>5R#KWG=gnBQx{CtXst2TqBULgG|fqDZTh|YX1+hlIlTM3-}1ZP zcJF-9^!OL@oA(si4*$*?#iZ4lP^&uOQj`N;uyA-JYj7Y*XDPSa;7hw3B2#o`_l<*7 z(QZ{*+xk-zlwRCqf{nf_g?T%g{bp@C4oJU2rk){`_pO|DUDzHbWqBRtgiq~=gk0Ifk^|WotA`Ek zx+o49AE$v+(V3KM5nMUxD^2pZc9sZ1=k|IcIUjRGM95t_+_h<{G+w$Y1p6I2JWx4{ zd+8(@UpP4@gp;7lszXh@1_u*$R)1~@Y_)peYC4A>D@al@yxA;J+QqNPdz$5+BBvA4 z8u$}*HvbRFM%*yb&e`aXU&LJ8ur^hP>IBZZ3q~8ZOc`+niHhJA*~+G;{Y~Uq{h>e1 z31gG-w94{bVF7DC`He7IdTX>u;}9Nnq1!A_=IaNAE_3HpvajBK!;Ez3qT!;N>EFF0 zjLzQzLC~%0jHT@{qEpq^9UMJ9tf%}v6cj;~&C2p${ebWWZI^KVWM-ErIjfyx^vlDh zJlrFWu}&!79XdNnmF2TDgtjy7Ib(&-(m41NHJBK~A=;s{;*M6NcEU5e9sX#wvX{SK zhU(fU_Kq#%XFqu;GE=^pBk;R;fHvR5H2dH)f(6d$$WgqyJ~7 zU{}KiLjW_G1{-3zDvf;h1YONbu_2CwOU5x+_;a-OKo?GK(UU)$o*yL_V7hJ?m&D;l zk`A@9rmA~)Z4otS|H&S))?Cj-YtcgJm35`HEkvHAG8pMGbkXBKlkiVI6>rR%heU&P zFeisAnH;`|;cR0^0&=;bN73O@7H4&v|0?#rWSznMMuS7Km0-WJ;Busc6=l?jZX7<> z8=}Lq^bQy|*K9zAQ-k{vI?TYkXgj)D7;mZzmoT+;T1@2*-NeS;0^EwA-nXRtSJ_*+0yEo~^7}D=c$Gf$ASOOkpUciag9#Wo+ z(g0s6cHqcID09QF@S$8WV~ZJ9TfcZQVR?2L+_gloqpRkNx*m?l>3ZKe$6%D_!X|YT zbf$6ExoWFXe%NT!;5v@IJ`*0hhGm`9#T(y+8R zAuYF$i9Vf<;4p~UA72u_a1N+S;l3Vk2~XLZ4SVa%$}_8Bq3vkWVAFb*l0T~i7M z+qn0Pu>Li6)>ZzM2s6>nAr-H|>FPi@F1UlT>&9EO#%WBn8%|p=4|k3TGPAYahz$~B zbT+ynRS;U!G-z<@@TVwr%51w6W@1uou3^9`S-Dt`zWaqZRmtK??lm|SWz0>Is;=9) zK_{^Du4A)Zdk$7mPDsZ;7ZoQ}ws9HMo+2wO(2Iycp)mwo-uXLEr^m=*scJ={zqy z&GkaV5HIY=_rj(;FB`<}=H}|)Lb)CFeYnm?-Ff`qhj#ODe;wBc=>G=dRmhcty7D1j z){Zl7`2Gd`{)4j53r4`c0&ll{=oneLV*w*N8@t-?Xy}qT< zzqX@ymTyfvoXH*bxi6+megRCa{Rw%5zP!%so&PUhbWq4S%gND z?<7JPm1VA6g&xHuiy;p?p&#LC0rR-I^7HPLf=|y(>StIf|Z|-%|oR$kz_x_DwrPA4Ud56>@Xr6 zMTRdB;VeQbg<48>WrUVcfh$QCPt1$x-~y6G1_R+St09*tQhP|2NU|4cQfwr{3mWSC zVhW*nNG_^Fgw9i~I-3L1~t1KH2 LS%Uok@8$mhkQh+{ delta 2570 zcmbW1c}x^{6vub=x9kEUu)4UYtB723xx4clTu?bgYC$O$rJ8C}y1*(#1%xFO(qs!r zEcUSaO{&5_8ZC)O6-#Svlh%W+7_rtXCANwOYBh~i>XFu}>DxgG)&pdcnctiDexG;# zW^OhJdkR18R4VGRIw%&KMo7^3i@0HuaLQjotzd>;BeA%vJFsb#N%@0-ZleiD$4Yo* zD2Lvi;}<^>`y(XWAJ17uT|IVtnxOUOEGQuknJN>04CV0gQRSJFeW-Qm6*mv_D zxH4ct)n>}fL>X1c?63z@0abl!|k0Uu2kL9>U>u@g)^+-{r+VE4D%a_tT2APbq7j&%kw;QfP5x_aq znm0U-3%f5@sSXF4~H%}5w-w{O)U z14@T+WJ)3eM2RW#bL8Tje@>u)MpRM}88mQ*nlr!TLyr#(^SQQ7p3k)y>goG-c?MW% z7SX8XxHCb5M1vCOUO!I6yonOq{fWC=M_N_4h>&`X|eR- zk$vYB3leCJCR+pDnQ<0Y(LP1C?;!ng;tf+RD5rh<$VVCJ?$SD!bU9>8BK?7>G5CPq zy%Kzz)$x&nPt_O6B{plRecW_wVXmzN%M+p;HD6_xSqtq2_KMky(u;BnvTUVxTb}>c zIR&Ll=H?ca*o5sabz0$~qSvg&9SVOZJDpQhv(06nZ!1`wZx@P9}bI{%Nj%tm|yh05C^S;%$k& z;qK4cJ^=11?AFG0gTWjtwrv><_u&xbV6c!Q_n*WZy_0&@?0TEBqM`LkZeZBN3t|0W zj=o2wH{9P}hV;Wd6Pu}tdRfe&P&iq8o#ACU7dGuc-e9oRi~B@#*tV7PrD>Y$SyjlbFAWL3poB+p6CCVAFd zF$b}8y1sc;(lSB%dFj`r+bP<~{`ri3Bu6$bBzf;yPkKJM>_*QeCw?Wp*jY}pboHc6 zV^z|y=B(sbm2RolO54)rjVayCy{a)){zIcHDG&{5Ivh(i;9;t$d!sFhpDAmi#^<#q RNzr!?lZ1 Locus Value userDiseaseLocusValuesMap := make(map[int64]locusValue.LocusValue) - for _, locusObject := range diseaseLociList{ - - locusRSID := locusObject.LocusRSID + for _, locusRSID := range diseaseLociList{ locusRSIDString := helpers.ConvertInt64ToString(locusRSID) @@ -842,9 +838,9 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA userDiseaseLocusValuesMap[locusRSID] = newLocusValueObject } - anyLocusValuesTested, offspringAverageRiskScore, _, err := createCoupleGeneticAnalysis.GetOffspringPolygenicDiseaseInfo_Fast(diseaseLociList, myGenomeLocusValuesMap, userDiseaseLocusValuesMap) + neuralNetworkExists, anyLocusValuesTested, offspringAverageRiskScore, _, _, _, _, err := createCoupleGeneticAnalysis.GetOffspringPolygenicDiseaseAnalysis(diseaseObject, myGenomeLocusValuesMap, userDiseaseLocusValuesMap) if (err != nil) { return false, 0, "", err } - if (anyLocusValuesTested == false){ + if (neuralNetworkExists == false || anyLocusValuesTested == false){ continue } diff --git a/internal/profiles/myProfileExports/myProfileExports.go b/internal/profiles/myProfileExports/myProfileExports.go index 0569c50..339c78f 100644 --- a/internal/profiles/myProfileExports/myProfileExports.go +++ b/internal/profiles/myProfileExports/myProfileExports.go @@ -214,11 +214,9 @@ func UpdateMyExportedProfile(myProfileType string, networkType byte)error{ lociList := diseaseObject.LociList - for _, locusObject := range lociList{ + for _, rsID := range lociList{ - locusRSID := locusObject.LocusRSID - - myLociToShareMap[locusRSID] = struct{}{} + myLociToShareMap[rsID] = struct{}{} } } diff --git a/internal/profiles/profileFormat/profileFormat.go b/internal/profiles/profileFormat/profileFormat.go index a736596..6ea1a16 100644 --- a/internal/profiles/profileFormat/profileFormat.go +++ b/internal/profiles/profileFormat/profileFormat.go @@ -2267,11 +2267,9 @@ func initializeProfileAttributeObjectsList()error{ diseaseLociList := diseaseObject.LociList - for _, locusObject := range diseaseLociList{ + for _, rsID := range diseaseLociList{ - locusRSID := locusObject.LocusRSID - - shareableRSIDsMap[locusRSID] = struct{}{} + shareableRSIDsMap[rsID] = struct{}{} } } diff --git a/internal/profiles/profileFormat/profileFormat_test.go b/internal/profiles/profileFormat/profileFormat_test.go index 6411b43..a47f024 100644 --- a/internal/profiles/profileFormat/profileFormat_test.go +++ b/internal/profiles/profileFormat/profileFormat_test.go @@ -210,9 +210,7 @@ func TestProfileGeneticReferences(t *testing.T){ diseaseLociList := diseaseObject.LociList - for _, locusObject := range diseaseLociList{ - - locusRSID := locusObject.LocusRSID + for _, locusRSID := range diseaseLociList{ locusRSIDString := helpers.ConvertInt64ToString(locusRSID) diff --git a/resources/geneticPredictionModels/geneticPredictionModels.go b/resources/geneticPredictionModels/geneticPredictionModels.go index 3562906..d2fdf03 100644 --- a/resources/geneticPredictionModels/geneticPredictionModels.go +++ b/resources/geneticPredictionModels/geneticPredictionModels.go @@ -21,6 +21,12 @@ var predictionModel_LactoseTolerance []byte //go:embed predictionModels/HeightModel.gob var predictionModel_Height []byte +//go:embed predictionModels/AutismModel.gob +var predictionModel_Autism []byte + +//go:embed predictionModels/HomosexualnessModel.gob +var predictionModel_Homosexualness []byte + //Outputs: // -bool: Model exists @@ -38,6 +44,12 @@ func GetGeneticPredictionModelBytes(traitName string)(bool, []byte){ case "Height":{ return true, predictionModel_Height } + case "Autism":{ + return true, predictionModel_Autism + } + case "Homosexualness":{ + return true, predictionModel_Homosexualness + } } return false, nil @@ -65,19 +77,33 @@ func GetPredictionModelDiscreteTraitAccuracyInfoBytes(traitName string)([]byte, return nil, errors.New("GetPredictionModelDiscreteTraitAccuracyInfoBytes called with unknown traitName: " + traitName) } + //go:embed predictionModelAccuracies/HeightModelAccuracy.gob var predictionAccuracy_Height []byte -// The files returned by this function are .gob encoded geneticPrediction.NumericTraitPredictionAccuracyInfoMap objects -func GetPredictionModelNumericTraitAccuracyInfoBytes(traitName string)([]byte, error){ +//go:embed predictionModelAccuracies/AutismModelAccuracy.gob +var predictionAccuracy_Autism []byte - switch traitName{ +//go:embed predictionModelAccuracies/HomosexualnessModelAccuracy.gob +var predictionAccuracy_Homosexualness []byte + + +// The files returned by this function are .gob encoded geneticPrediction.NumericAttributePredictionAccuracyInfoMap objects +func GetPredictionModelNumericAttributeAccuracyInfoBytes(attributeName string)([]byte, error){ + + switch attributeName{ case "Height":{ return predictionAccuracy_Height, nil } + case "Autism":{ + return predictionAccuracy_Autism, nil + } + case "Homosexualness":{ + return predictionAccuracy_Homosexualness, nil + } } - return nil, errors.New("GetPredictionModelNumericTraitAccuracyInfoBytes called with unknown traitName: " + traitName) + return nil, errors.New("GetPredictionModelNumericAttributeAccuracyInfoBytes called with unknown attributeName: " + attributeName) } diff --git a/resources/geneticPredictionModels/geneticPredictionModels_test.go b/resources/geneticPredictionModels/geneticPredictionModels_test.go index da206d7..bccc1f8 100644 --- a/resources/geneticPredictionModels/geneticPredictionModels_test.go +++ b/resources/geneticPredictionModels/geneticPredictionModels_test.go @@ -9,13 +9,13 @@ import "seekia/internal/genetics/geneticPrediction" func TestGeneticPredictionModels(t *testing.T){ - traitNamesList := []string{"Eye Color", "Lactose Tolerance", "Height"} + attributeNamesList := []string{"Eye Color", "Lactose Tolerance", "Height", "Autism"} - for _, traitName := range traitNamesList{ + for _, attributeName := range attributeNamesList{ - modelFound, modelBytes := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName) + modelFound, modelBytes := geneticPredictionModels.GetGeneticPredictionModelBytes(attributeName) if (modelFound == false){ - t.Fatalf("GetGeneticPredictionModelBytes failed to find model for trait: " + traitName) + t.Fatalf("GetGeneticPredictionModelBytes failed to find model for trait: " + attributeName) } _, err := geneticPrediction.DecodeBytesToNeuralNetworkObject(modelBytes) @@ -43,18 +43,18 @@ func TestGeneticPredictionModelAccuracies(t *testing.T){ } } - numericTraitNamesList := []string{"Height"} + numericAttributeNamesList := []string{"Height", "Autism", "Homosexualness"} - for _, traitName := range numericTraitNamesList{ + for _, attributeName := range numericAttributeNamesList{ - accuracyInfoBytes, err := geneticPredictionModels.GetPredictionModelNumericTraitAccuracyInfoBytes(traitName) + accuracyInfoBytes, err := geneticPredictionModels.GetPredictionModelNumericAttributeAccuracyInfoBytes(attributeName) if (err != nil){ - t.Fatalf("GetPredictionModelNumericTraitAccuracyInfoBytes failed: " + err.Error()) + t.Fatalf("GetPredictionModelNumericAttributeAccuracyInfoBytes failed: " + err.Error()) } - _, err = geneticPrediction.DecodeBytesToNumericTraitPredictionAccuracyInfoMap(accuracyInfoBytes) + _, err = geneticPrediction.DecodeBytesToNumericAttributePredictionAccuracyInfoMap(accuracyInfoBytes) if (err != nil){ - t.Fatalf("DecodeBytesToNumericTraitPredictionAccuracyInfoMap failed: " + err.Error()) + t.Fatalf("DecodeBytesToNumericAttributePredictionAccuracyInfoMap failed: " + err.Error()) } } } diff --git a/resources/geneticPredictionModels/predictionModelAccuracies/AutismModelAccuracy.gob b/resources/geneticPredictionModels/predictionModelAccuracies/AutismModelAccuracy.gob new file mode 100644 index 0000000000000000000000000000000000000000..a44dca65591e55e23668bc8539dd9aec475396b8 GIT binary patch literal 120256 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 z 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 Iw({Wr2Zlsl`v3p{ diff --git a/resources/geneticPredictionModels/predictionModelAccuracies/HeightModelAccuracy.gob b/resources/geneticPredictionModels/predictionModelAccuracies/HeightModelAccuracy.gob index b2e886afcd48d06f837ea019291c885c21043dfe..7f707ec7d1bb1f5f3ba2132dd3d29c66d7fcf112 100644 GIT binary patch literal 45559 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%0Al6WN8xT{U;0z!? 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 z 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 literal 45555 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

;nz;jWjt*bpd)XAOEc1kCGc3z^ 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

-u!{pRvgr%1M6PLsPdbmZFPHQM zWBb+#t(EPA0gSPg>Q8ZRu#!w~+6gw5TgL%hi%4pVs04&_@+rntDW_lej)j#`K{1J6 z<623xMIPM$A!jD;?WS)LuF#%M=mD(}etahQMWNr!$ff8*J2DOr zO(XMvS)=D*G&kTLA!I~zxe{JOzL9y{uo~WTT`y=LZSOt(Aee4D1agGhbh0C!QAkw> z&OilJQBw^7)_Rk&dR<-ZjR$uj7&O=@^^-5TAcP$Jo@4Dmm9bwWV}*&NKfHuzQcODEIgm{}qY563sy!KnYp2{UoDhBa7wmg9Hv=&9K#`U>i|dF(=Js zW^uNVebEy=vGL`!c%3g)Qy#@QwO~V3hTq^klji@411X_#>x%qAt*T8&xdK`D%`)!M ztcgWgHJGiq?E=14OYRqk!h*s;@o0WXCF!3@gIIsKVJ^Z-vcKZPA%VQj=eVb&wagg1 ziA+;bPhT*o;>4DoU;}F%+B6X?o$JdESzKu!ca9qVaMT1Ro%Ie@dOWQ(DZ`3UIF$Ss z7_*vsy7or42%`ArQN){2*;}~cKagItGPN7n+4lkgC!5$zdN z)G`()RtB;e^3a5}YsZ^2FhtU*Lh?#5=!A_2r5H9h7Y1t^4y1}SgD;GRnNjOEofVv{ zcoCOY3Evz=)tj9d&q#LQI-^Czjp4`+&=Kmz!8L@uiV9@U6MOonE6w-Hl4|dYhkE=}?AxgSg`yLGgk*m24NJ&e+ zea@mwcn}!1A}W(-G$^h|K0}mVH*Pbiw}`|?{`Lo#Wx4I;nk?ZWLv2P9w@udnc@mU@ z0?3E`L7nO3Slk4qUqHE!;DREi!B4{RZI!HoB+$`*&zoaGpy7TPgw@Pi(ZIEuE3Jwa5?_l&?jfO#x&1%soob;noOP!;)I*pBvdVYO&aUjLqHws!Ft zYv$qSK1Z+{85C`K9+X`|>Aw~rMxpn+cn$nsv-*%ZWP;ZnWRBu#&dXFRcQ=IcEIb}q zY&Ly_9h#L=F%B+<`~-qaC|h`#%{E8lBcI;j@*1NS*2C#H!?6tobm*bK1Y%Vzdx&E~ zP9e_|G3&p9hO+wiuFgbx|ugP(jWwA7jCV^uIlf!*`epKIJK)012uI;`pG_ z)P~0b%3r6MK#(MSinfXM^z!9EaBVqNUg!gtvWn~j`;CImX^uX~T^@=7)$ECfm%roQ zk}MxJbQTgwzutuWQ&W=+fI#n^eH+7WTqp-4q;X@W1p0(1j1*;8P5Mx+zeAmJ=x*mx6X#B0c^{NXjK7{pxo`ko! z8@>YUV^~x!2@6M`9B=z*!#lwzyu;wF!oND8ON%M`7nDGXga>*ETNh}!b86Q%Z}0lH zD#P|d`wDx88ZUmVz3@Zm>y16F!NX&nwXOl6kesg9sSJDje}6q^YybcN diff --git a/resources/geneticPredictionModels/predictionModelAccuracies/HomosexualnessModelAccuracy.gob b/resources/geneticPredictionModels/predictionModelAccuracies/HomosexualnessModelAccuracy.gob new file mode 100644 index 0000000000000000000000000000000000000000..b8542be2ac883273c290574a3d67b88a6375800e GIT binary patch literal 1633 zcmY+@Uq}>D6vy$IaWxSU5m`h;%tTBq#6-l*9Yw^#Y>`Ez#MGTJS8SDaS4_mVO)Mfr zL`+0NLPAtRB-#v3@?(Svv(536=nV+I}m-)J-Tbh;P99$~?=_!C_P*2eZ$&d~ikOPI#04>lBVNl!7qjyzjO?7Y_eU@$H zn?+LJqMpR^B2-Fq&dE7EN;TvE4}2-^%aAN`Q)$r?^{e(jq_O-Xx3d@Un)v6^x{bVz7gd@JD{bTPA7x-oIqDL6cGnQEOA qan=Nf&T)xOEtm( literal 0 HcmV?d00001 diff --git a/resources/geneticPredictionModels/predictionModelAccuracies/LactoseToleranceModelAccuracy.gob b/resources/geneticPredictionModels/predictionModelAccuracies/LactoseToleranceModelAccuracy.gob index 1ec8a15351c3663b1f701751d419070e1fc1e379..c16c60917b64640fea28a31d7915d6860f5a7383 100644 GIT binary patch delta 51 zcmV-30L=fr1ib{XG64tw$N&NU1G1AH0w9y#0WFh80UVPF0v4030U?uO0Uwi=0V0z! J0TPqV0TIFz5Dx$V delta 51 zcmV-30L=fr1ib{XG69ns0uqyi0Undt0Urnd$N&NU1G1Cq0Wg!q0Tq)h0uhs00WFiH J0Th!v0UpP{5UT(H diff --git a/resources/geneticPredictionModels/predictionModels/AutismModel.gob b/resources/geneticPredictionModels/predictionModels/AutismModel.gob new file mode 100644 index 0000000000000000000000000000000000000000..51059e72a6b0b49c240d0597ffbcfbc194c3a762 GIT binary patch literal 25480 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 Du~=B9 literal 0 HcmV?d00001 diff --git a/resources/geneticPredictionModels/predictionModels/EyeColorModel.gob b/resources/geneticPredictionModels/predictionModels/EyeColorModel.gob index 42434f55859f2542d79c3412a3f42f8976fb4c6d..2d9ff8f478f928934efa1b34031bcbd9ce3d971d 100644 GIT binary patch literal 196413 zcmZs@b#&EE)c1?KyA%9}yUPjg?jEdAv^W$?1?p~8prJ}z3T>&;LQg2}?iSqL=>gu) zu-@n1b)R+rnU(JB+55Y7CX<~0&Dl~gfBtGq=dE5bYw?JAtJW@Cv1q`u75$gaSvJ>t z>HPeE)qMGj=Px#Kp7s0%t5&wn|JOd>|MOS7|Ic6T|NT|!e>lf1Te~uUp?vwv{tuz= zvc;>HEd59OAEtKyo2lLZ4^#X9&D8$?Wy+VY>R-D8`STZ_I^AmVvRSLz|6fS?^8GIG zXVzae|DUD*<>{#x_nRzJoa0S-#^w?UraWc(#uQVY++ba*DNlWrqna#71Gv=e5AHYT zsqd}ROqSCnQn^emVQ0?MZN2uHEUQZ=oARXlQORb@xGJ{hJh}dQZ>Egem&|o!k$7{S zcCA9R$+BwjHdCJds@E2Cp0cV4Qk78e6oiagxz1!!>{r28bsE~W_$%UOUN6mL@pux8eNT8nA0)UnVgr+6}B)Vse<-^1f9t1WTKB z%(RJ#G+9y#$D+CW8?+h8b0N6909y8K6~UCb?ua$=U2w;MZ%y|AtHZb^&`%B7jFc}W zlbBk4g)p_R1EXdtum{ebtD=xTzxO`qUMVqVORH1ZD36Sjl_&z_|YtB>Zwj~5gR;eARtKHcjffa3-uSrJ{Ze-_M552la4D@1+ zperHCeyFp|u?4W_fMk=U=vNIDJ2IUSc6QfprdG;_NF%%zNcG5psFv-X1wpCp%w0Jv zG#UZ-I{Gqhlhe$3a`$r)(2K{R#Ax51V9BrF19kbL?Fj49AQ}XtYTIK$sV-!t{A)-m zl*B)qz;w)m9FynF#LaTyYjG&Nv1%ur#{v@&R_!M7*JhjvCySR(<>u3$B5=pjNJHgQ zVIPxa@VG!`ZuW(&&tHgiEh-#fhO>e`rG=NEG|a;gW!&)?j`s8E!$+ad~U!bdD9+Gux^Z&3&wkk@a(6xDyT=$rQV~x?zqRp0hZRs4!0_Qzu%g|)OH!z0O zQ({~RgLY|?sJKGo1k2}8%1lZqAjW*Jg;}$H2Xg)657)~6_QC<3tnrlU-6sKD_YAtE z`t~T;rKBk$C|lNo!0>-j>Z}|lc(zBV^rB4W8{x;pqkVCt z2N<=wV6@!m4T7Z&4R)C=3+*ULHPH_id2%E2R(fhJ>^+!;?aH|d>jYydPm`rjMSEB} zNZw}4j&Pwt`$fCdw+x~wsN-%&A!X|hktL1nP$t67YlJ!Z#P!o$s;qk^ys+*>F)|Ta$V$$2zy>m z7W0>^5d~3gHnwXmU)q^1O- z8mdFDumf|o(yg;GX67YIS*bQU#GEH@@F&@|MHlHb%Dah4W=mE)nW;T$7Y1X?qwb*n zuUkBfxhu%YeqlKfBG2PSy|~L{SUT4YXFPt0q|nscbZ2Rkx9HKYUBIF5J>d_fe=6ol zr@Cy$Jf}*D;L8fwj>xZ*Fjc+ZKEPyg`{D%qY?ahjl0G>KNHIXwItLSdv8j03V zS2JPxGz*2s<=ZM#Z`_Fo$EW`PlDt7Eoa3vyLT|(BX4#N}v!uAbm?MV|$MI^Bg5;0t zpFYNvCy)8Mle_nqiB7WQyUN}FYR95>Oe9%vcsy7SzB8+Fms+qg0g!IKpfYr~hse~I z-hopt-Hxfvd5=Fa_Q z%b+a@W=n%DP^Ct@7UBBq(?U&_omFYVI|`(NG43HDQb#nOi_XJ^35fc!I9`&LUKTaH z%{`Utu?w+4>1maYl)NOIrN#6@c4h$@j52CAi7EXaj6XFSX96OX{g8&>XDtYY^1CWZ zq|Vm^xcf7759Xzu5=D_41w`$$8NrfL4fB*9DI(XtFCvkp!40P{*S*zhpyf5j1xER0 z!HgyE;W)KzH?(M$XmWesbK$pZxf!t6pYMl&@|OvtJ|hVw>XUu~{jI0iBWGXrfOGd_ zvQ>T8G8�#aPOGobgYaMo_ih#fXGdyq?IEy1xEGmN!b3b2ovl)L1HD-@3z0ZBO_nArv0GX7Bm@xpOS>#HR=FWy|x8^=u*D`ta(}% zuSi|W<4|d2AJKMpxW$?Bv}6`1%bSYqoX4insf>xr9;mh2kag125+s3q=CdDCau@Ao zrj$u=^^AtjjNkvz&3fd-f${lET&s>q#CEmMIh1NA%Q)bN2iZ7Yo&G|IoEJ~cXeY`! zm@Vebqakz+#(9eWEGkdCox)9{_FUG*0Wr%_x^u3#$ucL?6^;|7XpGX?l0-(EFbm=G z{E0+QDe2EP?A}un!kDrn3Ua}LB2Ne8QYz0Y;y@$e1%Q;}^#YNdI~0mivk?|)iysMz zLE8?%v*9XsDf>bZto? zdoIQi?p2U4qcgEhn8vB zx_bkrLpf4fpOccs^}g+be{DnItLt}#BO3ge#N2OLBCnnl%Y-tpMmBO*KB5^YDd{Z# z9TwwksYFE)uD0n8jAuUMCG~)I0G7esiMkdpb^)@3H=a~_Mfd`6!bZf)ug+qz(qoJr zYCkn5uyWtWC{e042ZB+2O|Z$b$WN>_1AZb>w#^r7vNUZ^v8%x~2)F#@F+I*Gu_DoA zQMMpToqThq*)q45r#VkTnkUQacuZ<^A;Xj>m6oV9 zW!MWUOKEOJF&IrAQSwU5x=CCIk7SgrYa>8%DZL)(QC<9@7kkQF&Aq~Apl?w8n0w1t z7_%h-PipTk1~A$$2!p4@q}?V<);(5YTL+Od72VPRR%evx2amG^>H+n=;cMzJ7ahS} z&?k3#m0`AgPY^eCSAn6BNKWSvp#A8&2{3mr;Rmg3J+ez)B831T{<0f% z_xo__InBuwdCXED)c%dfS8B%{oA5_clXdWKtV&85b8Ljns==5qhx~iE%ov^lXTm^Y zpua1<&77xs<J5KU&4=rTm@Pfy5F?-L!IOo{Th-#xJ{I`1>UKnk}27NlN{hCuOW%F1-ZY-nrC_KI#LJRg?E(lv?FS z5L4%NivU$j31QWOo66PBnRAGoVtttTq*?;I8Jg=Z$>>D8NX zrZj33S!A@1uwmBaTg2LE{hny(!v+O#*YXoiy{3kLm6Wn{B)wrXG0yVbjRhLLMW&Mg!7!UYS`FfjrBADIgq#^QAd3Wd! zTTtP0O9yM{-nWq;Pn7MUAKVoK&+AeiW=njbL@sUZ$OhS=IcU@)ds9(Wf3#2)|AFGx z(~pSE7}O@3an?x2 z_a~KbvS8YefttN}(L>}Cf0%WMPaWzJ1-WpmO#;5XVWKKuMk{g$`$;kuKf{bvTQGz0>GRYP{~Vo(`?kR*CLm?o)LNV zr2!P>eHnPvlZA-HmgeiZ=^IY|C|biLRQxPK?kc--co3^N4{h>m1@n!5+qo$R+ks!I za$JHK{I@E|( zL{`qbvx$?RAmMV4c_LghUX##jq3wjixH^^)N#`%(XSL)?;klh<5U9$_CYde!2Z%{c zzY!rlsyxosUN3{)STaaBy+_&2;BQ4|D;~y?)1asH3O##L6jRoZ7aockPiAV%8>3B6 zb|T>vQ?@IHyBpDna^2+t&*Y#m)9>;`PdU64?fRqtC_JTkFA7Ba{(@|lGuDGm&nzlh zVZmoml*41vFw4`xb4uNCOq2#5W38=JDFAH$^<%2>dVCa{(9NQTV#MKwbf-7v|GY~e z0=uTM&73kH+?Df1n=FZ$^fjq_6h|Vq196GEut<=}a^bcQtk#^pS#rV|P7HFyt`+C7 zMOk-;2pgRqim0^9iNuP<@gnm+4iTs$!Wi}A-3g9Sd!RKuKTdjsx9AQqrgZUze5$;N zi|*>j_2SZ0f&5sUpC~!Un4~xEh)C^`BM~&FSBzzh8i?_7<)_?L-#L2YJfkf9YBC3e zmN@})O_p$RK4!exCR~zw)D43pn~G%YEat1;-wCO<^2ua0EgXYf=}|nvl3vsnp|Q9K zqZ0N7n(`FuqDVJ}_R{E;g-FkkBM!{$(^>R@jH$FCIk8$Q=H<5)5_?vnuWP;jBQd3U z_tC8fdq$&UX%|9fyvc`L8UtHY5Z;?um}2XgmS*QFXHQ6B#QFPZ~?)4i!*BL-p4>CK7mGWIP4}Z_2e;h2qVGW zmh0mZ6xm8V=r!(~26^=QAXA><`h;?qFPZS99GL5FvREb&Ira1BO|blm!vxt|=B9Rk zqi|odRFT04A8$pI`z#^mZ$E+K&8i{LpEwAY>3hfqb$Q+v_|Ns=u%foN69NjBB|X$J zFJO_n#?OQ0zzHwJSe}#M#?dp0fP8)%RZ`(SK~PSSka_ad3Y?Eo}XfaHTvE z)N9{yGxLNyip-EVgyU~@^c?`I7u@^6ucqQ-y>|}Ttv+ANnk7Z=r#b14bBTbm{wopJ zTFntLIU&|j<=#2WGH$jEGg*?Za;cs#9l%XTD^X*g`^6!kRtHklcydsT%|_#Ot@i*%c?5V6NXg1M)5+sC=eA0lduoB&?wY=FPn(mo&tj)!AiAcTv5>rS-4!0&x#Hbc@cfG*C(*5T^cdfcs2q1^tPK>ZwA!l!ONk6Cmf3$nWI)~LKZ0F z?h+d1NSbJpC-=reU$zA+m9SW(%k__f&bYIIeke@~0k8VOT|i0>#lLc|Vk{&NqD9O% z^cBw9-GMHv%p4_lO6i9PhgN1rTNr;A6b*INJ?aT_B?Lz(?`H*Yx3ee_W78N+ zlcI}~h|(kTa)MR05KT=jG((v4+b#mhmJn8Lx#=7sx!MOonZHgH)BM3KG_qGy;THQw z;<`f{Op%ubQ9AefSt0(~S$0Q53hsp?X8dZT7s_I$F~6{ovUmNVUOXX9L7(<2UKjz6EqjV_lG_>#bUE$L-Gz%tXSL67c;r6Q6A{_U4b@V`xtOE$ zwuYjFUl4UwS)8M5{uU}*8ToJ_chi@6At%+JB9lHn(xGbug?BqgV6t{K;h+g8T&5q$ z|3!o{{#r_wcqDD+X4Q3~7meE?swJ-7HiVUl6cxCyHr5*fFMJUEqZK`0Dk#$WyD!g; zbw?vsnVkVtsrdx~RoQ^Yj1!z@=P9*+Cqr4=)0^vxcUgnC#Iuhd^`1GL`bJ@7-!Lz< z)v!rsy!u{6L%o6`%{zKi%gWD3cu&b`Z4JHH@&ruE+j0bB+K70@wQHybBVqAmg$%z z_x~x}=2(%4swb|kH(6RO*kiKnYSkMo2bZLA@7<@(TsvQ+}EINZya_V%x8LUJ!uX+LwKxMBG7&@gob}isw7w;3r4%o8q=mG|t~c z;nY6#0jfT8B4qJuQTUQjQ25idt?e$)Rp@4TJ8i;~6c$8uRo8Q$*7EdlDecu}Bsm zOa4T%`ZWkVN`a+#Pb)Iag)!(7zE;+^oeh0_H*3ZK9>MaY^}k5x-j!1T^7k#?Q}eB* z%=BZw)?$6ZzU-iXwjuDU$G+u|Z!{x4wX(egR+}{1#1h>Eu=oFZ%edSS$Tw2}qYkel zQo+?eiK)vUkP6!QX9Cit2kafq6S%3)-Y6{CGKT$=^pt0ZN-qE*`-j-Uw($rPXo z@abWfiKTXJ5We1f5liF=4Lu-~o`(RX)Cn?8AMx8C0qNR)#NXzjIZt`%7{M6v28z~t z7x`*@ct}9i(__d$s(w={t0f)=WiUGeMbOL z?{iZCY%exA+VMW=W{c97oKl{@0fM?UR;-N|lMcY*P-7P`KkI7{@OB7oeWNGy70=Sb zVSAS_-?%4U@2P*QflR8pfY?h_kI~!o%3nkZ*1w@bpFUOKtJICTl2n$yDBZMTt{xhR zCDP~Xyq##?UaXdLV%PG9_S;^RejL-1Is4ZMAC#L;2A0d=Npv00mw8H`rD>q3vKgl; ziLpxoS1wIBJ2{ISQ~#ExQD_Z55@vPxzt2~!-2F|K^IreN&ch{gn>@7X_iX^Jepn&Q z$X>Gv*KT`>^W=B`HXM8JAVv+g!SV9n@KEmV8B8qoYE#xD_{|08>e=U!saNVr&d6~E zM2IHyNNBN>Tp;wBH610px^O=D*i3>dukYbsWnf2EP33->8H^5lX*$_AgkO5hO$D`o z{Z#hDrI9Li9lDiq_B(bJL1R*pl#fp{@{}&e;gfD$6g_L!d&*h*nkk|@dMp(E!e6?Z z+$jTZsN368RNpTOSr3{Az#cP@d{qmGH&)unR-#NJuZzMdkm!d8Vm9)Hh~HcCMw=%N zVAT6R`yg@4zk@~Re`mzCD^s$1T}c%F{_b2Geg7dC^;KZ%6+k?U1(7`3R`eZ%T(1e# zgj)5HNQCa8EM|sX$!#zWKZ+l;S3MDoM-u(*~rOd8hM&*ehPY8PyKOIV17^WQE8=$|i1B$;OwG-E2FP<>VD~OL}=6 zt!xbo1kKZrbCES|Dpo1|hN4wHe8JkBXE+&xv$d@=<3fAU%WBR*t6px?E_e!vvo^WH z7y761trlAK!?)?5H&+8*K5=V{nN#T5Y=>&!6dd_W<4`rPCcaUcB@jogX*PK)r#}%o zo&@edZoJsF>+2HTkRI3pea4`!_*Gh`(r7i$iXux_M%IS^Z#y!n?`B-7Z2h*^Y$?$< zi8+%OgUd+%Bob^~jR5pDIpo8bxWk6KtA6mj|Ktg4fl=XrEi)fJ6wY%xF%KB?iVM^Y zcdkTHo8dS`DN{^jPl3IJNJ`HZPHh}Rn>8BGgsy~~VF&*zP}F(%RV1!zbKeGG+wqCz zTs;a*n)RPZ)+G~oxz;0(1zOu8F&fj~;6delsWfKpzm4tcZgsyYPc9q35fx3RdZOav zLWI}1=TZyofn$sf-9fD_JI7RM_ErKX4Rdg1>K-#w)&Fv7cxrN(%C$=Z&Q?x~PY$#~ z`GtckR1@jar?@En{o=S=-q(WI7`89B19BwtDl>P1nvE!#lUzXQO)|F>UK!WtBf>lX61Fvz4DcnvSKk}qfZPK z&T_xD77J$O+XPFWEm$U1TR?Ic4{qBrz8r|3q?dIDA@c4u#K=`bJ(;^se5WHvx{5?J zhmlgsQ#N3hj(r90|7@siBd7=-H(RPUMxVCfQUvq=vji~b^G{zW$&FpW zVbzG-lh-WtMnI8=K2SX3$HFu9E2b$Sy8}V6b;mO3P98DL@+vNL=ML@-|J^_&>(%Xv zqq<@pkP}9zTy9k`+^P=yei_vgUAFI5X2#IIxX4jFAqf z?F7DTjRd*>LSafs7D3UkEEhSjJx&D3qh%=CLr*eSpVppDMfqO{Gm2lOzc-i>$;|nu z(Q2HH;a=r{J?1>A-*fJD4-^^qdb-e7q+t?M`do^KJK(OfIZs}FORQh(4~as(G4>EV zZlzKgKTdChW$$8mZrmhxSH{Q(fK%dn16QvxhWwC*&)tYq^4!T1^}h)=+cS|8T-V;wKLkgt9Q#L)5xzQ~sbGb~vv7p`l zO62`E@wtf>6GR~8^pm8Uex&MXBs*2}Vpavs2P+)c6I3Tw&2p%2IlBUM0pBcOu{P&DK zdosb4tQ8z7&wD7$wYXxJG@_U*%!W*(u zX&-|3{pFnT?|q6??pP}XTupjYaOwkVa!{GtKL}w}r)MyAP+3w@dDan!Ns&JAtJz1= zpe)J6P0~y8u&#M*K%`P|B(s$B`~O8w9PcP!Itj=PlYyyLtSk6!?GIpaF_B^V%VbeB zpC;0s^+q$nAj{9`M%q1F6}`6(V~|$LRv5bCwSYfwkXVcNwh(@K6`+E!@cuXqx;zP8 zQon3AD%m?XLztCE^XlCfKBZA8MJBCrSPA!pS;B@!nK(h(y(-vjd0I4-%RLwP7Ed|D znyNIuL1t>(#WRVlhiS}d^N7+_e($E~NbNH1xL#R^1W-!%WW!s=iI}P9N5QB~8H_At zc_T4tYM7}j1zr!V(O;NghbojWC-7$$_`0weS*!1dUxydYR# z1i^aLQlWO^U{2*vzGLIdrW-G@FdG*S$zKhiX;AY@=oK^k&+ZG^tW0U z4?Wxpb~S4h2J82S3p1<+5DER+O*Y2>;7ktBKixj#d86Dz z;v!woABhUjh)gWI`+6OdeshY(_h8o6T=$d?0_M+yDEMzn08qmh`NP@8N<_9DP`FJ5*u8s;up?amwemE01aaSKGUV*8B;;RpNREOnAPV5a`aVbMJ z$s7GLFfe||5o~bZmxHv0XU;+?ADYWuhf2cJ)!z|sqxoVXt>CmnRPP{fLGCvf@|(;< zkiYEXM4&k(2YFMOc_b&o>t?a z$+AK|#iS~4!K<%+<4UCF&m{En#X>yX&C2Izwgk^UW8!m7U!gO0&;p=$Dh_DLNC;yb zS_w0>)b1$NCRR*F^`CWn;ZM0KR22R|foS)OuH@RQrtnp*qv=TKv->1-t2mI=Qbxoc zu2a64;jFg^iAjWz%%h$*9pi8}buALbVJo zO&gT;CPY#_Y;rL1{ehmw{LB7ydHwY+Cy>p5$P;YGpTZBL#HL=W@G=qh&1Zq61m*{x zQm&pz+|4GuXI#9+f|M7;f>%qF`OKpD}w;7QeoVxI6O{;9N_89xOEl>vLBlX!kyK? z&}SStZn9Jn-@IzWpCeES^<$L&+$Q0*BXx73EZRT<8%J}tGpW$I7{;6OWs@apj60X* z%O0Y0T9fUx={j(d3i%A{`V`J@In~ZH0z$y6w{A7&^{5!_33#2ilO_BH5c+ z%c2FYN@WwdUV8etnT4)Q5R$ueie=WQ0vAnr#;)hYKrdSXYqV}+ZPFu;a94gmkj9{$ zh}Y58unNg9HLnHT_|o7QJTu<}m@Vn|Pav{ka02A{pSNPq>sW3o-hs5@kf!IjIkNx; zN{9co!)>dHymZVLd{U!Et-Ubk z{&|sJ&BjF{|5xc<@EcV@uUye`IsCr23zl#0s8!GZCITA2CPA?0pHKvhy-G6al}<%4 zDWZXBFAq(e*+jp(g2WboF;kl%Uae@EwF!@0@G-%YpS1?JQf=KKCOth91+tdy2$-_{ z3LT_YwIs-s-{CSjWCnhgFHRuKlvm z+`tg6peI|E5m(s~b-3qd=DkulE2+`;CNWc!-tWV4?$s|M(PbbY6~{xwRreW9#z=3T z;2^zi2iCtyOVd%;AYv_J>3k?s`v2nOKWyJBG`#%4wtH54lqt1h;Zv($$34avYhm5k zS*(qQ#Ww?b$^O|;JWikBI^l2_Dz<-SmhP?y1GZGe4|+@yUx1~J+>GF!l>}#2mE~m{3h9cE^hp#l#jScX0yB&>$VrvMfK8jttWke&wBrTnRT5Zka zEHSp;gz`pV0F$pIFiF|uxEo;|vv{%l%0$~zzef48V+#@CICWbXQ|ley=5$^_`WU4e zI3fE%zgbL4^e2Yuyo);!RYfePx~Z3FZ@-nD@Z9Z;EPd$eSVlXiV35WngqSRs4~xPp zn*}aCdW;LWNB?10R2heK_+o_u^_L(Tx`+SRBF9u;<7gY#S&uszuNH!LzsCI{4#SlOD#;_i59dCG zZ7Dmrd*O^1vkq4lvsOA{kK%ltaOm!Rj$+SOt03&WHo<|r*IhS2X|Wj|?M+Y!oTdK# zRA=l;=IXJDeHVSw-R^kEID46wX$98 zL6vBT{$Jd=d3_~wM3RB}D;XgtJ;$A>RmYPqM4I z?L}gC+p3xPUFkH@BBG0k086n@bg3Q`-F>YH{P;;Ehg7pe1e~4si!cN%!_&Icckaqv z7GbC|tB**xULW~=!LD6N*nBJ9k(*nO5C+L4@6W*>yciTi!)#H{4 z*IFuUMa=Zd`x$+g5f**o;&4p7Hq@ z&ivDSf-vCD9M%rQqcRz5yuU#?sS6u`MGM_P4e2)GhkaUl6$-={JU0M(LOCKY)hZ?W zXubKfkZ`#eboD_?5&y!TVoa$oY+9a5@he^@fn-R0DQx+fh=Da$XY9luiBtjCG1Sp?3aJp4g=?*NBBSYs^}%FMUblZr>dw zsM>TUag_2hg~G43BcbTefvMIJ3#`#Ssyh;945u$C^;-#_-F*OEbNJE~?T6NpgnFwf zXjJ#rc7$hIP2fwD9`d`Oo)@#QGwm8cneUzi-?}pd zL!Xd;JE|vV(eBz_ax_`m$s%0s=Kxx_EuPH1AA|6le7hb^L9LPuUxiW{q6;_mL}gV^ z9`7>NlB!1Af)1#e@j+zv)2(o8%g$1SB~;2<`JF?6^xqRuX_PwZgYc8bMNkfieTp&S zod=U9{2{DT^N%rbn%nbA|7q+>GjE-{;4bOtCS0nvtqDc4{!N6{(~ctVyCn;eNzJUV zsQ-WL?t65=MaJx1QH;Yo3*Xyy3dB*)55OTex1t#+2Z!5neg0@7V#=(tNB1v_DDTN} zWVIIc@5fScA1E=ScOf3BB$Y7eTR&|?_kl-g2>a^HR&Tf+Jzi^p&$VS!nXXu8k{Rm7 z5$;^O1*dVHPrPF^>UUs{rkQ1ex$t6)l-hKq`lW)hlfa&Mo z6cg6B$BF8lJq~;?ejC5(Z;t_99nfeap{9( zX3R#QJai_JlNDEq%Y5MF{ zEL(EimKE^q6(=?7FY(iT>HK((ft~jsfDk*1wqhL5=M0!18%YDD{lC|8a#K=8IeisO z%0j*qu(Yel17JJxX{-ACNdN{MD-g?=H-pTRUZsjM&Iy37{v6J8;LaPMkh{0VFlFK@BbCJh;>CSQ%zLX=dZ-dh;)cE z^A*=R_~mjrh?HA3^hWEB&-0;I<3DNeGU)OybPsS4HBs~`j?nIO7JHs4*0@H!U0I~O z`)c8Sds8Gl{i9sbQtT%Qq|`|yrPQL;(4|bDjN_y)WBeIMeFm+x^PCq5!*0xC?vbt} znKo=#1oHpn?*pYyHE)w;{l8xmzpn2LV~HQ4mVBmU0RQ$i#H*_kL~8%G=UUz|0UrJG zo82h1-j{^4e=6k+obukzimU^NQ?52qMa(Z6=20wN=6+l-m4g~$pHse2x-2cosYNLC*aB{VJlbJKNRq+TMY7lfa zzYE8$C(4R+i{zQvvMF~9lQUL~L|mcsC{}(Xtc0&v(e)@kIw_TJP>#AH+3qv(R2mN@ zN?O32!vJqL6c-s;9=!e?{eaeBoU0Opwi7{Et{ji!xWC@Fbj0pEPPRzfr+D)w^*voi zZMO|Ssa{^GXg*n*i05g~ERQZx9n59Cq+#+zs z!PCq!JiJ+1cpStyy;=grp?q=$w4A$=_YyzE57CXKKSkx`JltxscscC=O3c|6aQwYO zLCH@3O@KIEeBh*4y2}Pt+cRr9qemV5r_XCdnoFI|QcFv$Y*Cti1&ApE*{AWAJ_|$vf^!+w$B%{ z)E51iE>*lNTp@ufM0+MPduA9ijGG(5srrh~TJ;m*!u@@+ zHkd3IO<1BfYbBuFx=8r-f%$v!yw?jP>WewaXlq#`j_Y2}_JC^U08z?C0m~0&B8i!N z#)|AzzF7+ktB-dy^S3E3M=&T;+e~+ae(M5$G+erqr!Y}X!jDl7>9?@ z(&xgAsKdNen_wtqqMRWgcJ9Qm(@nnGNCE)HQw&m-46Sz zyX@rQaVCe==e{vTjwnRF%C~*7QGNGsfwuHp!v6H)856m<^@LX#%2T#;-%9&59!!Aphl&V)PICik>u<6Q3!|2<&WSJ=}eO&&~v6HL2tU8Op#VUrl%>- zLL=Zgw+@B6@{Kc$@A(~J^qmiCW0CkoNRFLJAe1GCah?<^nw%W8ks9MmCxR_4%jeJN zc$f6<_JU@jRGOBB^ns1Y7WMl=kSXz{$uTW?D&`nR8qzh?F_rx=wp0c@N~Aci=Y;7kKLDO`<6Nq;gLX|w* z4HIs)ry9-q%qEL6h)le&b}?#B4Fj!S(~svq&qJY1*gH_zZ)>v~YcsR0e zG(xJfs_FrgC4S>h@Na2AxYVk54?sTF+!qCv+LCe7+5E^>um1bFbEzd$5YuUaYT~!7 z1)>>$=lF5=@mV`i{JOA~>xMRztK#fPYtmNC2r^sF&msMc;tl#TwfhaalKS_E5bx3e zOV!Nlag1w+i)h~Et9rf<3qr7#Q-jo1=EMi!jT=s);JwzfWCU7ay41EPDXLEt2N8zV zWRgNpZcj8d&t>fDJm!*{x=Z#N7+t5NLZ1ABiqNgwc>%JKc#S2+<%My5W6@gB?6g6c zQC6I(NX;67#&~hb2{h00i72Kuh(>&sE9^_^inozUz6RMQizHrMDP}+6!!rN=E7E}M z05ER4EUJLtJ)1ZX{H&tGe<{VQAMp@js#}7B)9a;^v+@}Qck7k%Gb%eANg!!m7Cz9L zG{;ustcbAQwZ8Dp;=fd%{Ae2zjNK7nRYN_|tL=M19JQW7;8TuN@C5yzHe73ebC4h{ z7=Z+NX5o0~zaLM7(lTAd!9^T3$+vq5gfVOJv3fQC8b)Pd4E(lcf5sYP1fEM32&CM4 zVIVSRh_8Y5&=jg$=_?Mdq_kk9$wjJ?TzkKgrgDi^ct>@dL=XMibX+?G=uzWvwQ?$jR509{(qW}}wF&KjTHsc@H;9BWqs(T=?nl?bVm|}{YQZmC zc|@qNgG=*v0<8335(vAtV?O%cd2y7jxH_TKrgS1IhX3(r=G^;2>Gg7?hHQ61VZ}Qo z^miOZ@U*}t2h4oZ5GhjbdL4clv%K6&$WrWbX8PQwQ5bgOv`1MnZnueV?C#TsoC;%+ z)_d(76D=l(Tsu7~7(khscwb(572(FvgWgCnaUNxPcAt)>4gKt7;#>1Yd-&Y%$x);p z8^HomJL0~XkEGW;;J5DIU14jmgnQDs&=^ym+-`!7_4)jS4|?&XrlogL0&5(4%(ohA z7x00=#pg5l`%yE3B0VrJpzwt_50$%CqXL!6lYp&$cgRLm#*x#g{QXSyG#{JesBmtP z!*%Nmcv9Qb&x7k5BNija7zcc5P}*~Nc8XT2FL&Ft9#hLOX9nSqWhZ#RU1(@9D zU~dZT5Ob;B2#iz{OCM&=bB)4K zhffuS)YY<cq=Pqj7(8?xa%$lta2H*l0{Leb5$MQQ=RucZ zV&S%1NH!}&v|L14zbA|2>hZ^5^oYk1dTzGJ_(!?I;XTzGP!9Mc0cO2dCISwh2!Nhf zo8F)pIa#P$8ATqbAs%yhd+UuE<)v8EjhjfDQJjyQF_E3o#{lEza}xUPPd?DU_q+w& z&x`0OF;*A(ucPjd5#Di~H9k7@FVkv{K5OPDyhC(+vh*RI()PDSnAFYQ7h&D&MF4oy zHOy3O$6cinc%-(p2_;or|XFZWOm3c1V=?>?+9GJHIesro~eK(z`%Hqvm{p zQ3`AURJA~6AfNc=Uk*!+emcK*5??!MJ!g1e_3?Hane(P89?)uUN;g?LZ()j3<2jk6 z$8UZK*~MQ}S?N)J%>T7YW&G)pj*7__cA>(sXT|dLqYEkZZR{XK58V&Y&K+24n_tcV zXRW+6RIHpM3ZnPDQ~-Uyg`^6*Q9o@5m>Oa^ z#DTO2NpHBc5lXLaL!=TCPf19fYi9#5?*`&klQ<%jiyXBvSq}B~1AFItnUI6T=T>Ud z(?r17B$|^va^x8(^|ydSu^C0kjX|UFrZF~)HBWANj>?j&EpT9*{XpfvcWr{8tnZIG zT9Y4~aXhi1CiMf2P_6ENf>Oh6BhAJ0$`PjLx4MZjW$ZvFk5^B?GUDV7*k>&TjGXw5 zV}lR86sr1Qsz{HEJ)Gg5Z?^#~lY&KsI62_}<@{u9 zQPudv@HEdR<&>Ux7}XgkA{nz55n!#Zc9gNmDzc*2ZeIFDi&IHSnE)Vp&0FrtG5;RW zyVl3|`Y`^z1N~b33kzwa_dm49t`H9|gzm*xDChc}Gw{KB$QafGcJaC#O9W`10mOo_T z&corSoH*&gP>f>%&JJKv%JXn~)k_aX<49SKP|zcY?&!Y`1LZ1!QUAsaCH-c zA;9?nE|LEXN2H;IV1(@rU_5=wiaEhHK$TXEp@emRKQdGL5KTrIYyYm|qrVpzW^_6e z&CSif5ui145y6YP<;2v3D+E-xJ$O-Fo5b!RGW3*nUz+R@W9Jd+D%8%)A*KSIXjk|4VS$fUEJ;3{G4yg6jb*V3-*kI79of--- z1zJ%hdgfCH#xdf>q53Km=c(4e7?ok=j=^(#3i9PWW>JsTFZ#pT>xf8=oMGF|EboJ2 z;cT!|WNQ0Zyr(CvL$Y%A5%E)stj2E{cf1gDdYrJkRu&bb&RlvFkuj5!%_QyKgC=Ui zI0gOt6zWD9+8tq%?|b@)CY?jAJhma5pYn$&82w~Xk@e>*h9L4nV7&Ra0}eBsh7u*I z_mVYci&7IdE%apql4_oGhuL-+y+~?)HUi3;q0yLOn}^v_?K+(J*H}-iHO(5o84G$j z1F_L87vB5_QMFo)jS!51X6ixSJcN=|x|P?Md9yKfqMTWR6s^Ed5$u(If$;38hZyzA zTimZ_&7uR3Z12HM+vSJMypoI-1|2Ck4*)+mQIg8UpOZ1J;RoQ!y{EA4Xqm%n6}?0V z_dIWq;@Z!djR&VeDuWzgk3M&>8VD7uHpvi425;twh zr7cV?I2Dn~*Iz_K@~yQE`uBau8Sl^9fq^A+qfk;>{EskYd|sHzQls>45R_^}fQ>UR z$$`fo*1_#iiVwubh+{nE#z_(UBhSbcwY)gVP`0dL%ctMDmC0y7376~JKa%VEi@#v3 zIV%`Zac&@0CT?2{`D6WkOf9{e^plEJ$1us%lcG>3mP+T^b7c~o7sQ(xIeE7NB~5(L zEtg*k-56hqERYUW5Z%~smp5bd2An9pxi8YH#zS$ppm-&#Z13-F;yl3#U2>a&2_{SR zGB7GvqZy6hCOZ)6cXm2Jy4KqTW7z8@Or3uvoG;lI@E&lxI4)5eCy3OWv^4|nF<(Ue zmVOd!;)F8frz2Z(Bc>2a8} zX&k}QY&YU5E%7d%)$9EXMctJPJu&sWnTl6_+#&{AOq;!C%NHFpq}SE`xmoMqH`%)~ z_L%dGBK5X1emF$N%O6&f!RqA%jMqAdO`hU2kfxxn`sl{o!lHS~wJ#DN`N-nk(397R zu(~}LCWIx4PF3bF4M1&`1Z+EBu*!v=5`gc(2n{RBG4Ok>cCohGchshKC7qu$|X&3%;U9YHNgR;|foqF@y7$8IREt&jZu^GtfJJ$^<-R5}%rfw@yEpz_TeAJAiyO4Wg+X`kq6aS4t zX>f{0qC2}DmuQkud~!f{$>Y)_Vo+lNtqxl1~1Q1k+3X`PI@rV0 z;R2OwIOh>meU~%!tE^p&WT{-ZKi9@Ie6Md8FW{61OMSThb1Q=%wfnMOsG-|ok!!di zOulfGo5tpDC^wdg&pD*(b~gWqqqB^UTIu32?iY8t1TGFQ?zX|*-GjTk2P#-w>ZPSE z0ZNt9mKwe(?(Q1g-RT1FbNXd|vy+*l|8p{#OlIlcuVy4ymxfB1yszyGtD|Y8ZYAn3 zb+us^-OirB88e`kmX)9|)y46&|B|O;V{SnVW7yk5O>K18?lvB&3!${OH%7{4 zd=2by{3=Gr$}Wd#&`P*Mp!##sVamRR41HM@SXg-%Zli3yKMs4nPk@!Clp`xCG1~&tRozkpmrT%>ij@@cMnI=2d$eQZ8JviPEER60&A8`yfY27f`OnlwHNp z#-+fj-YFWRX`SEir{{(%?6b;}B-&SLKNskDn}V*B`rtLa^qEa;ICzu@saAZ^P5Mfbps4v1$LgNj$>8TUi6OHc2I|_GY0{h= z$%=jDzLF#6{{YPT_3S9EDA$r(VH*SlK zkK%{*fQn){KI)z@xD z-<2w{t)+T13)?su{>rLnJQa)@$~C2q3GCHL1=rgh<>yJYgMn=7mA)n?*T^}b+9aW#ZN(Awf2M)E_3NqOBB0(_!6=R3ARTKr4p84k?@yl9A5$#Si?A1v%h<&|AH_}o3 z3Sz`)TudPNfDJB=l-aY;X^<@bn(aS?K=x@}iNK|2g+-(OV9$6q?GRMl-lf_cgIt1a zzds(dk%baTm-f0oP~I#=wbXl*N}IP_IaqyG3E{M(sIt*OTP})i7L~p47k@vJitC`$`snwN-D@U z-)0iTRr<4)`roox$-1U_bG3`p7Dm-iA_mMh{y{9JZw1cQjh);`@_dT0vn2Kog{(bC zft@iYdj!*>Vka5+-yJbXrxSozNm`3sMzuTS4!w0xZ(6(>VQizKY<4&QcZ@!I@P90g zR_`WOUiownrM7mVopqB~0IoeB8jN(c&Qdo%`igWzs)`wVZfB?wW5QcGehjsZM(=&8 zSC*Nbxuf?4L@m8mJU`^(3Yd3sq)={RAEu+yE12lrRpt}c9|vTterXs&35Y~Kt4vQ! zYxsU5#`V8`5Z2tom>TZ8nE`-pheEW3c_V?UhHsf^QMrhjMrA?r7Tn9!$R^0M)1;5t!t%nL$G zotEX0jiU;F1+sniw~TlFNG`D6wqzm^nHz&^RX=efQihZMd+NONdQ^QPgu3^~?dpQ9 zgs!STB4ezWjh5>1jiO*92{9|~dN>zXxSGhl+861yzD_<|E%KcfL9HKX>X51!rpCQxVm;`wFwD zCBMhPugr5-%0W&w_A7CYIF<@dfGwqy1F@;i1S&V+hZ~H{b?@{1U z%_18i)P-A*An@~ylabCviJdFVI7rLEDbAEh7Z6AJw~s({_C9>1EZc}U=8^VOX_=W1 z3VQYX*iYNib0a-_zF3YV!DqRL1gX+7c^2zZ`c2@jDR-hNLr;QIrL*k8HcI`FF5SLy zd#v67jA-Lak&jyrMn83b)DHUX*5F|H=bXsJPH6aUW z%z@;(x{n)$RlNkeXFcjop&|Ep1k?)Lhm0Au8(W$#jdnt8?==K8N91sa)u#ahTjWThBE(wzj3tSY9#95E?66;;4iC*Z1*&(cl4o*3iPMt%3M@3 z|F^k6{YUNTjdb=%?uKU7ESO2@kxGAS(McF;6Xl$Jt-YM*sb0B`dyG9NaHRfY6y{Ss z<>^PS`GM^~`?C@+>WQDoWKDdEN6c$3^I_O7@_Mx_%f}J@4T`t-2?Kt+5}2 zZRy&JRJjk`+04XZeiYP|cEvHa>f*VHW?Rmalwn^`(_H(*mF`L{+LfY?y|ni&PYdht z*xd4aN*{Hot4#7L9K$2Vmsjz$)Tyx&LE;V!U~I+FVwducg;4N5DLUV-ATfBZ4c<{( zDolkcX6%j%YUpd{o1~}2zxL=<81=Z_7*pHiYC?X}V+d=9YH?@KBE!59JX>MRnTiRW`dWyf1b3FYZK@k_Slk=Ld6V%4M zLKwm5aF(RXN1&97P0sKz|Ncp_5q?Dgh_)jW7}ToNiKS2Mw-5;2)&sdZ?O8Nj>ng;J zQM#=}$y;~&n|a@MhUQb*e_~v37fQ>>#Uux-)A3Z=|NSUlDwz){&AZ|8v*tpYFROzrvRr;D57MNS7qwzZ%K4? zJ3u1(;~GP?nJ)m=k~=5T<$fm7yLCm;yIrQ8@VMlJMCQ8#k#O?Q?g@c!U9g`~VKzLB z2@g-w-?)wh%B&{bid0AQFs|NsA`}|;UI&Fk-9WGv6mf*ox92Q7FWfsp*@&4XIs`4{ z5xxBk3}JRzDC(p*1gZZfVMH@B%MMJrp>itS{oY~}W!EZkRr&0g#=4sKGVKeGBC-|Z zg!pR167(@ zVpbn4tS;&&c_sGYF8F=<9EvoXWtBo-RGI*@Dthgqect7rkUScE)aICEfEcSwDMCm) zDvGF2H-d3BM=tc%M|{~uIr2;jSCe`iM5YN9cxY?lnq=eIQ@&O;=E&z(*6!afbcxP^ z_G$z30QG=EDRxK46^H3EC6>TaohyMUy>xMsiFvFLhS2A40q90k>|+(oA5O>r%{x!W zQ3KPsI9xU(7=u~>N^5%D8HTzq6$|eXs~YE`NzUr7jKjDJ?pthUnQdkeS6huod!@$g ziCo>?PIUEXhw%Cs`O?}L+6nhso}&f6VU01Lrrq}8>dr#&QugHl4%XJrdzjtd@nnA0 zM1pRd zEo!(O$K95R~NzoJ-JeK`CWSF5fKk6gHz zpi8(swFqf#Pw#ECS3L?3vuMrr)SEx&K}Knkf&p5~+aRsulBI|j`t}Tis_i0ASz`)= zdvj!e1}Uz8k8s$E90{yn+KNuriTx*Rj$iMSsWyElFt(SIJip+1G~>IDb7JJ`^zGFD zR<$!IBIA4IPva5B$U2$3u<2de$Hu<-jO`^2_9CkJE;@-(zXn57^S3a(a7wrsKfphJ$g+jz^nUDoa9EYIgyS-o}tqRla5Ja(}@z|XvGX+0jcEk3+y$~1~C8)R| z=bvi*e}yorB#)_l>Ke-fX()+_#pYhiAoF>WKZDM>U_0$WJ;`SE8*gRMt={5VpL$}= zi354|4_Fcn#ly08roS9Ghus|V<(VGhyBaFmUCA^1I+C@t{xzlJkBv|?%2sDxvaJ)? z((*k9gWAuyV9MZY0mwM!_GUYq=oW0IrRgeEHT!>wXVBLb$u_`+;V__qp0t?B;)wU#=EF9ngs`15WD)HJMv)?{$ZMh0wE%=tN@?7t+u9wiS+hP% zvr@enDwu5o(M+wusktn3WgJ90V*DWv;qS59&JO-~nvF(D08P7BF@ctjZZXK(#1~G= zqkkx^AJ4;S9~cQZlm-*`vYP$^?3)$6aEMu{n90RiZP()52C|@L%o`a@`>ZKJsIWU3 z3!7<==R*F|5WKEM?b-v$HbD{yX%#V-xh_)>W9QsPK|Q`2{xYi_A<5`|+GIA@PXR_& zz!)KRTsCT&gN6(Elk}_W^aPIZA zjB;^f)Z7gK&-hVNGz=Lo+3rxr%X-IgKPY^ANxPO zdG!pJ7%#GorOVw0I8wRY0OM#K3Q|`KC!`?kD?2S}tBz5$k8Ci4dcs$XtPJrc-n3{r znZ|k{pRedMQhB=DCZAzx-E(lSx#x}>j0r(l!ty$V7|PzO8yWL4Gq>u~Z;;o>Dw_-S zGM^K$$95k=QEd{QMEe{$$6D!Kn2uAw^UQmyK9B4j=5a~8S`NvrKT)%gjYutDa(WxRii__A@DshSPaHVfJza$*CQ?z}WgM zJLq#11rPerv4p1C<1cl!|G&6FX%faG@2e9?sjibhOHrmjW}e_NNw{DA18$6~ZSb^F zXq+#yP3kFmuI&`Gx8k0xw>w^Bl~8>te`TVqUyTXO2JHjU_~~_To8wy9&X7Hk#e63=KFk6}rwD?;*dO2lRT6UR#j*Y6+lXjNIfy zpDefOV=nDV)EI-a(V{FYPhCB7-~jb<+sT(oy%15PdW19e!OQ(A2l$J`$Gz~b+2_S! zC~T0ohw7x$nC44g2I-62NSF5MEIv$^Ppi$BJq4gQXG2}PFu@PK2ll~Y+JoY}n^~3! zs;v(hY3ZgHFi=nNFZ+s&>y5wgcG?MpXv{%?S&4XKUywdMW9n;m3-khMqN515TKB2CR1h&T04 zW(-U}32oMK3=_Orjs)6$ zc_=dTP2L2x4LQUdTPiV1&7HQDo{0s>iuy7>!*x8A`>Wd4Yv7lFh-6^Cc1y^J;b+U#}7oW-a(8 z<@f$LKq)5cI%@N}z(@UGZg}c@ZPbl99K+-2Blmx+W_}h7oADacp>_uu>bYRduRATp zaOTU5jT#L~h=7MW0e>@a3#H-O;E>(XRhA1?y~;Woew9aK^TQ0>V(#tCjY7%SdmVpo z&=h87&wd1p(ci>Y>ZaVOTs&S)sGkmHn`4VrY%09=L6ZG&R~%<(Zv-5V&i18sy!@+^ zvFirvsg2*RqdfW$<&{s*7-RH03Z%>x4m_=;B%*_9n}$qE)HkA8Kj%)}a+F15Rh#3) zs6I6eq{;ukU3MPl-iTG+-Xf-r;8=;G@1DCDo4w6iTIK{0b;^I<(m&6Z5a_(k?G1$` z87C*5Yq8zNCTk~LZ05TmT-I(TXKFVtiPcKYfU7TLVu)L7mb|&)#1Y7tewQ$#HnZ$7 zMEFyH&Cdz(JK_3n2r_B5Y3%*m=rMb@c5t=R76@x`)ky;SqBGRhrFBv$-825OJ9Szx zGUk&{n2gd{Fok)?4s_IB)ja@F$7XyNF(rwJ z)tAo0DrS5!Zv=QhN{2wcG>P8Y@)ru)>E0oHVt-gb^5=&?6ek@5kVdKJ=xS{^#4Sh} zUt|m&cMqFS*+zDF=sypULzUf|N$A~z!`PzqdaKPb>JEI=fP&m^oh>xfozCNJv%GvE zbRro{YsWVtq1rIxL-R)d5fF;#B=O+32K;INYdsbTmu4Xi8@1cRURjwA0*p9$uuzVT z$6V@jn-_#@zQq`7L_!LEy7pvY{a^@*Rf%5-1_B0oL95I?+%#?pFyD>SZ28q`(~cVb-g9-c5P zx0?l{_6r2Omt~e{e#oIisA@^>>c85tS!w!*L$og29!8HPAMmF7pBc{Z%kN_7r}`72 z+SoM7S)ZP)rO&??5X#KFXRnP{8HxzyT>*PoF%huS_BRtR)rx6^5~Bu5%YrwDDeu_n zuQ}qOubiB^-RAi6&=>PXUBI>05CfCx^Clyt+G;X+*!;0K5i(hu;1}ckn}f8()nAWj zXCH2)XFwkkk5Vs9M)g}l>WeMZ6Pd>Ma;G88fwiqyCx|DjZ63%NC2J5$=F*w)*8e-U z55mjC_cF3@F^~s0D%>T&ND$U6U$eF1&)8;5# z8H)PBeStIDriFuj#Ilz`Ep=jfvJ%)N*GGaCwKm%x9lQFUpkt@FSO$&CNk?_qH2|*_K6;Q{ zsBz-nh4XQV?kWpN`db~l>eY+}SfR`kKd5YpmqFk6^NbkT2{&jS$C7N0t3M>*?zK&# zUzCF*9=FU}6C^wK6BY3|%;&%?R+nC4~E=xJ_e`}%8v?lh@ zw(Mi9@}t6W4qY4vLvz`4>}C~u>;bW3lU;@F3|OhV!gevJRA#dE%&g2D^ae)(k=9J! zBUyXo>ECdD@5b>W770M9uz)efwUPqX3T`+~{rx)z!ESUSRVZ<*8Kk*w3}Wc;4wr1{ z+U-A*kDpiB!`P$FCmDNV6i@W)JA^@?d)yS(TYo@H&+f+T#HxM4hvp4OF^ZAd*l2U) zRM5pdwjaA$`zrWB$|v9~bLuYK%XVyGW}3hL5ypk`@h}UKPEgX)1~R+SzE|2r%a3De zl-a9*J1wH#9{5zL2xOJB^0;7a4M%fpUZS+$YVT=hQ?@+Ws&flqUhTXKrnb72ASJ8S zmLY(aFHrK^6WO7x?zwx6QSPsSm-??i?$+~sNT7e_E7(UbP>W~lA7eKo`^rnl`5&oU zCjF+DBYxH&0}s}zQiAz7IbB%Y7Y*FBiuE93bUh2M%(1t1}7_KgLUwtsZF_h=_Wh^8Vnhsd!XH){Id)O0cAv3Yu8gOHQJL|9c_FSJ&m^*E(Hb## z2!y*G#%^Zp4Q!&+so+7q$^7le-gRLBgu?>yft9{yo6RwN+eT#i(6JQd-o}KEK46{; z@}2RveRIBuAF8d# zEXLyc6Cs(eGjV6kRF@DU8GmHZehysCZVecu#I)QYa{Mb;dzB~-o0A4EG?leuN9JZ? zo6)aPLBD%}4FHY#1j#Y6$2>T!%tUAXT3g}Yvp_7QRvZDOdSCxl5IJ{wo1KrMZeSE8 zZ*xCbWS4hjm3$>E!;U2}D0X}@<%BnckeMTOI9--_@pijHZlJ4mTPzXOx+HYXlMDP2 zcTHC`(xXq2)qe-b_#|SUy(3Lwq4fde*)ZU#KRe3u{BG#vdcq4fjPij{yVI;Ly#A*iRYSEUu`#(ttd3T&> zqvRJwTu<>X?v;FzU{sd>>o%{y!_;mWPgpa1OBS9k4?M=JSE#DoEY0j@NoX*fpFf0; zy0ktJ*SDXGW#sw?tl{Px5JmHZ0eIHjSj@x5gI7arZnInO}BI7U&akl9hvcw*o6jIbHG|eHj57rWq2un7+He~ z^WZnG8gg2`ck#C|wh^l?Sq&@D|o{o(tLCpMeSp;q{ z8)D|Y#XGtBVU#}%JFZ^OprJpV5oA$kY3^b(=|VFoBp94gw4&1#U!gn<5c6xUa_ow z@obx;+tF0S$R0{UGjr76VQ24}LqNSOJc901<0IkM{c1;~$thbA)KVtc{Mrb}s-G(X z?d5Hd(X@Z$nzA>~I-6tL1p?WMe`7GjVM12>-vYQ`dLqm8IVdu34ucu_%pcGgU zZ{yVbB?Q7ucOt_Y)d=gF&SgNq`D2(w^NW?}VlEvCMdM9wkfle-Rut3P6KZE4#|W+( zE!;g>)5|zp=^4jpu|jcX8)EcIup`FAcihI6){TYCpxvt=Ims~&@?jHvDc$ljZ$2}~ z*z zw`6OONyY24%F3emv5& zIeL(ey@z30{xxC?LhY2#LyQ5HRGX9Cq+JN2l|7yWiuO7iO`IAyC zSheiN-EC(EX!=LOSobWO%#b|G>1>{ui8J+kt#{B;;T^a9t)2X!+F##=4DDV6Nzl|g**d1NwuZG~yjj8(|$~Q;v6vfs~g{da!0DuCVbu z+@v}!W`7M=x}U??Mz;^xPyZ|n63T$F22xq8C~igV)l7)uMgut7GjKcG_sG4H?Tuj(WTd@wKhkHY;IOp z?3+&6T2^w5W!1z}#rHU~Bf>wBeg`jMDa-g*n7M{tpPmsf^)%le>GSc~&GwphQ`WyR?q(bF{ zKUrK`ET6M;|W zr;pk!vvBI*N{V)p?4fOo-vY&&t!B}j|D$Phc+13J{Sm?K?q_Fjq&*R|i3XR?ix^(w zIudDH@&g;ajl7sm?!tsei9NBLE`I;`a4cpDP*LWbOrwW$A}CSbkJ-q@EzyXp^>2@g zTBdv=O4ZVMz?yXclvv$bN_@=BCOk%T{U2()iVxrpC4c8^o*F0e=kpRjZm)msIbEa>bDhl1{IXQ zAJ(QenQC*Cm$|L>XG?#^UkLy^R{ztiFDUEwF)*yeVtT*1i5PmjKysatKVy9~K)z+w z2gNO=(R8sY4|S$J)_E=ZHF}#& z_dhx3Ak6stDF`#}1LjcQ&f>oRt&7lFBByC6WxZC}9DXAbxpv?!BaN~3@vnJ#Ea^_W zUlVc7y9>!ZdVC^bsrG%fnxRE&p@6l%#Q@rSt`D>E&SebG1plpMs9yhw3+!C0kh*5c z=V4aksVPV?vprH+MOZL#jFS`W%s(FM5juJ-H#Kuh95&U%FYTixa}ROK?GK<&A5nKR zGIm^q1=Y-6tc<4TTtJtGm3?Wb+X3mcxLvVyzfw-8UQu2iC_|fUwK<-*MMu@=K2|rj z_m774Tlth*D?59!EnU<90ADqK#w`A!^>t z=&P3=kA0O-k8!ZR?|*Q$7LOLoJo?{aPJ3*65YI#`gVvq;2(5Y-ApW(@C19-{854#Y z^92IR@;s=m$2MS6Q{;X)GUjT}l2)v@WQ**}m{UxhIE~JkGj>&-naFUhP#H9juzNE4 z@Jig}{!8+7w*^V`8(N$Y&P zq?G?>)ODi;Fy80))7~yzr+l<#7O%Es*P*hl1ldt(-4&E+TiQ!Rzjgp{ zGrzTt`p`aW7`pLgyxs9OFI1EU0pMPn-j!LTS$fJio1@tsLYAYOaj*H`DV(pq`Lc++ z*F6cUVwo_#8RG}w47aiv-TE>*l9o{`p`s>@#K}gLslM9Zhn z+C^99&wiu0sQn#x5Q+NAqMiEk4u&vBHiEqRw4abK){yY=ktZ&5*hlPR9^%`1M^v47 z8m{jA-r6zRXD`*uqZ1hNI#qgv4&g4Tov1&G_LbM%kgod>auH`j;7oJWlXWmX)*5+@ z95b1~k1WQta^PbzS6_dD=Zf*jsiq$hA*N>sYRZ=&9{yT}NKj9lO-FOcQo3ko@^jHj zdA*Z*sY0~qL9-=Oojr-Gv||-V!lF*!2wJvPl@uP`1u@K5OZ@3s&%&u{I62CZe|iGd zaz8M#(r=irjZZ0e0aEp9CCKQ%v!j`EWtiBs!|t7wH=d)V5l~8_PwVB7(cAPUy{N}G z!AkM|z6+ryWgPD8IZWLDyBJZV$IkXdaE~?EKpXXY1Lg2FxL8e(kT5J$!q3Ke=R=^T z@i)P=%u2x_x<_AR(}(;NrORIqL&Ef0z{tqaPVPPLWs{-Sa29=(MIGp4RIAmOda6#W z8lwk;qmEy~&^a+Q3Rc%Lb0gHg2MF7SF)V)7X}_0?S*nwWrl){fvqDv2I%k(FJr;Qi z*^kqA(51>yFUpB$wm|k^46f5$C+wl;x#=!8-a##Qquyr^c2z>1JQ(XS2vAsG7u#u> z$Jc_6L}wC#ar6qXQPl)NiD!*Sy4>`XY&G~X%(V%Z_Szi1+KBno6$5yllyxU%WGPr^ zKVl^+ZGRUbz+)d&vPO}#9i1Zr7;gWDMrPLF8C+a5R&xB#W02KWWM-c2lZU&W?H%UQ z?RBCNqD`Q<_2ya-p^tT;ZvM`-2~jpYGNIMF=P}q_O-DPU(?O_Mk7fZ3t^R04w1WS^ zf@X&$0Nm^u2L&x?DRYMYXE2WzI2RA7j~5bmdcAp}5Y94&5VFQD#B6HIT=+`)kxH;x zlaeI$m#csrc{AZoD|=;lYXQ#5(EStd2Z5m#U0BlC&l1UR#VRpx`+2muR`yC0g>&15?|LKYdXBBGB7%gG6(DIu{ zySbEq=W&#j+-~0bi80h0-y|Kl<-vjKfvv%`AGt;@)Cc>xQ;!-4mbGt+4@?UU*-E{R zECA>|R4oaxS3R=(Vfq})1t+VM9QC95mlQGw(g2@%>(Ufj(rmue6BCZor%z$Y zbG?H@?2Zm{`l9-!SQ0XYXG`T`v%9FL?zukE&bIMCYQDTSS|FpPhom3M~%AR{LL(5|ofyBI)yJ-WOg;PO>}rH(hwmab8dBn|31S_zTEv z)EYvL&^Pr*M{W8lo@=k&3qj0_6H#5wDjyoEv#&0vOTwJJkhOvjQvX$f#jc$-(-5j; zM@jvDQ5aE4>_k9ox#shP(IhjT(bo0bj+in1w{b3Xk1%8lt9-!5W5S0RntvYPhHD5< z=3K{SQQvgk$L7c}582EO*SJ8G9W${kTQcWDDMPDI;ukz}V|dg+ff z(-W3K`;4|288R)zf<_%#Y_q1E6icK>B81|7gqM|5TL2^D$yG96lk8+HRWC1q{W_!v z&A;T-N3%gf6un1JgNpj#8l^t4)O`A!X}llaL2^$uON5hvjmjN$j5DzUda3;s0&Ubv z;z12bBx$NOZ#PH(&GN@@6D@jZmF5Fjy}+3bP!H;z%=lX23!#2Wg`XN=@s|F9q%6%W zib|T}9VXJUHvnkbp}IiNa=I^92VMdc+QHJtAvU}igq8chB$TH2YD;^O1q75?K{lUQ z`(n2tc5++l+Jd<}de*qNk3mCc?qqXVmk?eGiCwg7`?)VzVYgwSwrYaYtV8$3X_Hqc zAYDa2G&L_qtfS`GpOW_)74 zl6#7|rvV5zyyT2;Ej@zI7SlYdtx#k&zozXIQk5C9qsOM%x^@e;~NED}|eb<-D0dvZj7o z%a|s&S7G!?cYux2nH_R0g?%SyS?2L+w6yNPD5KL5Y-ufspO0Nr3*b#NpKMbzN8v|a zMV=*$jWYMPpmxtwk(8M}h9l~}4k=)Be}IkehjMzNU0P0qdSl)-IvUE~#2A0%pW!U; ztzJ+Z^iw?B=^k1eDGPzAS$48cJ<-jZdV6P)etofRjJkgg(!`#$*lS(M&hb3JOxL;ZgPMqP?`V^$MY^6yQcV&Vj6IwLz$3wR-}vtWW1Lx>9K! zebn!}$WLkud7QJhtX)DqB#}k9-boV4rEAe$368`DO1){2H$QrBwL3bM!clrQUlNDb zYk`4$bJy0PY}Ajbcg@3CSidn9kZ9wI2JpAeeS}DzZ3%Eoo6AzLkKAI+8n?)I?H&i% z*_F0lOucj$CegmIkHArVny6dt4g*bNIg@p#d*Xm%%kaL^ddOJ%^?raiZ9z1c?bDpt z@x0OM4=Zb)_x#Gh5&Ar+iTi z$LNI`inUtL0l!+F8Y#%t=av&a>s{tHWX>Lsyvm*F0qpj<>}7W(eet1p`#BMIzE>EE zRpjPKi~l+3D*k=B$L!d!1tPJh5J^8GlXgAs&Q^##JByBL*UOPMhjMrx{6i~)YNJp| z{H=7U98S6OL$r;X;R6t^9`hvCJ+sqAD|o_(=9ix-^&cUA3_1`_peV^%lQ>?W%t0Hk ziDM;p59G&c+HgPO!3fUS*PdK>BkfI|F@-)+fy7{Bnz0+=FY`i0ACMi~Dh*SBf)ck; z0CBM}N~_%m6ZXb={jb)Wn4j;5&-wlPQN%L5-Z30oK*{$w5XY>5bl z%z1>k`t(1P=BPHQ3@TE%4*XkpMqjN+*I0-*kgvkk2~Ij?d_{7#{{CAG^#SKa>Rrd9 zxu4aSm@R6!bFoQYM2|eX1FmmMU`D<4Ko_W2EiRh=Qw#5CPGxcdzg0`m;5o3A&34v8_11OvKe_>C(g3B7rGTjE~l-uL0 z!K>ADOrgfg9(behZNkSK%qh~2N=1?(7FQh4scVlngIMRO#IM!pGJ+_<*RYClxFUk6 z*>`QGPt#;{F!Y0vv8JurMbG2u*wX0JdJAt7TgD^PlN?|~U6cbUjRPYws9COPDoHR< z{L;H5Dr<4woEblBT_P8!<@2Kaa%};F5;M+`J?xY!|L(F6*?R;N(Q1=iVuQgg7cexo zF?qqd^Bj2Uqwaugv)p1r$QUB;;q`TaOrJ(-`x)x_#vh6oZpCpiSF-rK+eq<3j$OQG zo#+$8$aWcTRr9O{jb_~+*hk5F0J`S)=N{N|h2EDzb;oU`=j}}pu;%5O4%hwfv7V7H zuM6b!=LZx@vhz;bw@(3DM)pimw5L7_h0e&mZhS^;0~u=6MqH%-E<{JGT8WLw6p=ZS zq0U*wX%G4)Q|?<#;#zeZ8>)vYETzmNA6KeJpGtBa&`<1fcpLCjC%445+N6fqL%n?? zh5F#0$f3uscZTHOdJwZpI%8bDc@Jb&e)K{zWvG0wZbpCSs(P=|1_a674GbxJord)dN8lHv%&2)k(Z) z1^tKeN|T%d!6sjqvZJ5?jy6`!B4ZlA(!Cg7Vm9>NhlbH3tqCE`0i&2oTQsvbLTEvP zG@rB%wA6`2VZGICCq${_icz#Dc2rUuOJG|6$}U`UX_^n>My80#7Y!4x&N&DOeS4m8 zj!3zNU`ER{s#Rr+lyayc*Ho(_6Y-FySk}7nR_r^sQay-=-u6e0FO?vxw(TZ2+B^-D zX_>cbBlWnlOX=UWDh5z{E(cOp!QF=tpw>YwZa$nh914N`M9bs^N#ZV7O(?HXNd)H1 zIxA?8{|%CjXH{k+$YlbX&UdE|gGGODLpXt^8>*=)4uVbkDR}dLqc^Xh|HxK0NH`;|$1{UH5`u;tlsm-e|WN76pxJbL6jQxx&O%TM| zYa~Jb!_n0;XrmZlR^2s_Dfwy|qcVB%tmokb{XVOHu_-fhcWJZL#RAYDlW}kmnbr zla8g;iB}|rOxOfIjh##b9fexJPK)|MRG3+MVjA;B7yNC$eND=5ep0O0MD~~IA0C5d z<9-6F8qV_SNAGhN_v({stP_hZILOcmmj%-vX;ay}Tp|=r|IFlusFxiAJM;EU3Hbb; zYdHAO+JcS^;FCGnQ?P$X?QZxh5bS6s`` z3*}sBUe<9DvL6m*sb)e8H#^_7$wXP3m%P+vGO28y3*uVv(KRzn=)GEYN_H~%i9 zd%+86q;!jCs`%s`AXonRGMzGpzlmZe&kDwvmqu5p-y%-^*dEP{aCxt-Mz0Ix zxkrxA*J~FO%S^1u{4V>1_4KQi%bWEEjy7YBnmd}KYaw4mY$<<{qxH-_8O`gl2Zn#H zNkMe$#WFw2_D^`SIn!4tRlW-PjjfZYt5aemT<0}i4T0BZ5Xj6a>sAjFk;nS_mdI6d zmjmUd(^qC~!%h;u#>!%Q?4*;W2(G`L>4C_@PNgE}`utu{|B#!|Hx6ADtQMK>N4?CA z4RFfSW(ijtp4*Lb5BCB}YkL)3U^zHL-!U_FEQCEc*$}~2p}!HAB(devnJlAxTPsl* zR3B8C^&6v;-s+Q(@8gdk#-=leAbD^Hw?v~L+E{Zx1MsucSzEB1&I~Mn)SbyRr(`(B zJP1Ldrw=fcQs@&#V-Xfe>1(p>frQy`B`y3XC2aP#1SDp`Hb`r1l~s3ZdR5Yu^7aJ+ znUD7|8*j5Ck*$C^mvgOFU;0@ut{|XM?>UJ_`R`5y0;YW7c|2#?U3UI$C{MJVEqReE z?fjp@K?26Q)C)#RtJTRi$29jvP#rN;Y_sdjcAF!3$|ic$kf$PLXwPjlm*aJ@W7THt zX7-d#6MFx0XkoN>2CvpsFG{VVM)pyLeU!9%p)m665j*D79sMmx}YgOy!)@1Xv+;E+qijP z75}PTm?gzw?2HG&|CMxQ z(9W@&(7(tc3F)`ZM{)IDWD<-tZefm_yaC4uTm2xAa}Gk>(n*r$PY+)hHIMB>~ zm8<6cp&;VRB%H2o3_=cb$15(XO@b(`8?xuk$h;8Lsu8lqMXC8)luYTjmHOsyWVyud zn93*}z(uoSJL+nu&tOlR-;9grNaT+3afFGoD8iSrWs@dcdpIbZ^GknYId$MGsvi~_ z@1>FL679vmJqOFKp zhzvU)d2u!T>N48j$ZI~uXVE;azCMCf=DRyPs1H7dEwq|)Q&SQzt+lbvd<6TN{odma zweWKthWnagP1D~GVCnr6H_+ZM1*mJ6DghR)o<}@dw~R&xv)5$&S+@Opx=+sdzxSd4 zhC_Z*7lKNiA@6qdgC`Kv2%N*c!AO%WUq+U!gsHx11wHl5SHQaV-!5FH^}dY7t&sE7 zl~L0WQ+fM9SUtNWV4p7Ek!eQ_O6BnXF|5$EkEzo5F|5I^|o1)$?oofDPiF^tDk96xZ6796!$C2E!4rJ$oXd%=t#x-ZHbPVQtE?Lup&gRwgOtaO2gawY)# z7+0@)(`EgzU9_AE4~F8M{XUG(`h&VLXpm0nm(CrvtBGLx_qAAD+o2+o;nr9HI^~BL z?BaeA_~iciysICXOvkLh1=XLo!$VKZIR4^7$WS`ADb7%(NEH!m`UY;mXPN}j&|tK$ z-EpiLe$#%m+sc?mbws*lyQJLkmpo)`3>V)9R&_)7MpJ;WwQ?4;blbZD(lduIR;sm- zv6kmMsH>G_QA@9Pnsi~t?uE_%Jo>77n@0t5x>$+(@V}C|N-;AosC_Us2IsJP; zS-NZ-G|HB4@L%$fdCcB3PSPDrRG0@G;=p1_BFNx12O*%{Or=kgAnp}wG6^hFk2pbV zeV%#ns~5YM?R8JZz;*p25N68_vaL2POAO<4UBXOiuN6?y+{R!@EhOC^PH)e{PyJDv z@a~fpsrA__A-0&OA}VcT0>6XRAIR7r3O+@@W%Jv6TNsAjOx=V9!im z#8pkbDmeKx)`0BJGMy2(>T0prmNzL}y%#o}tNG>GVy2N1aacGW~p4%HZ}6w~?oYFbAABeZtc1ZL{_@36CKzd4FVNpkX( z*{MVrOjq<1>tru-7^7wJT7zLcVDt#utRX68P%5-Jrsl92VX z8PAsgP1r}hULeRc`mKuOZ{02;kiNUULBo@@$uN2{ilJ89v{oDI;@avrH6V($cO0UMuF>LCVuR0HsmBH|bj$+QXzC!^=uX`0*jgJMVKi zB5jw?&8#O*Y4CF?fS0XUo*5mzGxnM9+IfJED~{4^3|I&!BllybiuIO}{#%3v@Vn$h zN;R??@oC=p22_n*a~II^Cj#4P@47_Me%%`#_3k_5YLhWUnVI_pQ-Bx4_9D9T1s2BE zzrrrcm!iu!rTDA2oluu|VfwK}K#D_r#g);A0f63d!y#IHnu-JK`w|DHc^|);=f0zb zYBd0>dTVwC@<#9lf>{eEPoz)PLN!bB zR*5#WsJDBg>A;F|7kPGV0^&W-HJ0zhf5KYXzlzY-9{F(hHv69Upv9vX`s&X9h^>5z zm)lVAzc^B@^Aw6o^-s)arhmo(%FRQ`80LVi8LOKDc@A?w3Poe0&5MT7ow;Mo&hCsr z^Kzi~eFptD*Zcx@_&aAI;N>?SzH9Z8vn? z*~ZL{&T1@Vy_zcQinR0MPjWJj7U?l21)e^Y-H`m<8;O{c6@Za`U!KFX4F#jot4>dB zq@BvB-%b--)V1LxqvrS!`sd#x$e1wbFp3p1p+{@+1wAR06*4iDaoY-ajc|{N?ug4Ji ze*>37@$dX3Zi2hX=Gw!XylPVfW?J1_dns?tT+WbhebGiOGacEDB^z;=TI)mz^>!`c zrW7vbjMTNyi#ChX{p>uo8l&OaA|Qg6PLc=J1E-SUbiM&J&3v*YNgehVJZOEU5_Cp` zWnu&8GZ@r*a@@(rPJ&;+QtN!pgEJkAZ-e~vK`5!W4we|*`2b?Z>65N>yvQG4@DEOx zF|l>7v6#37J1^w0fa!=nf7?IRdS50-CGwB=!ZF7Y{CaM>~|1PrUU8)b`| zSXJLFa~Abg(cxU(Hb$I$(^;ZHozHB2)BE+%8dRCrf`=kpV6-R{vYN+TVWe%u62`y< zVe~%8+en99PK`7IoRQABcOPRJW#7_bX}gh>|C+)O`qEe9Xg5ph)PMdj6{$ydkUky( z<88c2U+rOIyXdqrl*MCaQFeTmjNUD)Bes6yGl6FwasW^*t|!JdVt=8%c3j!6Y zLY_AEMg)2C4_UG`Ld{(U{>nA^mjLy?GsCsJbwG_8&cB0!rYh?w^W-K_jRhwS8xb8% z$!3IY)O$+&D1XyMJ@?)?MDH=n8-a&6+Q!#*{#1?TJH@uupW{kx;cbFTIkHm}j+!e{ zw;O|n&8;nXT{Wexm@`P`SmvDU7}eT-8CZet@ie z;aCNZ2#TbSmS4wW#<|x)4Aqj?LNR?Yx?0N{u0m|voS7sz`I9(ft;}VuY3X=aU$U8S z)7G!VeAdjzC|`GV8|b!cB(&nfh(A5B4B#;O_7fg@?>+Et=Yuv{&)&qbeqz#c%2KUJ zg89;uxcH{_Y%XdGFt$3NlvuBZKAnvYdFLU;yg|O`alJepm0%7?ah#lph}x}J%n|&H zi?qWZkf~IUQ)CAvNWOv6Zr)!)?_~#FX<2f6GkqqX#%k);p`Pr#Lj!ZYFh-yUmQbL6jb&5m%iUiUR6^F0_~xisKIT@0yL&!%8lI{J-C0QMl7! zsF@e5(%;JI1RZNi7#UA}7R7u-+fat&Vy)SiRh>eYUDQSHp8QAfh#V8*!q6VLdT)()CS&PHNYYdF)MZa!bd zB*3~^l9}GLX|qtRkq#tH|JH!fiti~IeSUN3S~Fcigq0K<2vuFtqWL0!?BMuR0s!f^JLBsm&Sm7T z?}%aD&iEwoanr4cw7D=rXlPyipuV+43ZqI45y!T2;?C0O2%c8TcZYy=a2AsbJx&z( z+z@~0#ZIq4fO9VZKnqzjF#3jyvm8xGlWHcrD|z!9o-{po2@1Ubgdt1yg@M%n*7u>~ zwOc!>=R1k1_;e@{ib`kl@$Kq}sBWtajFinS!)y+FXF}BoUC#@sSvI-$x&J1FoxIGS z=H?xiVci>Fi9kO3fw*ED(3%fcSGsU^r*wTIH(lX3M~c1c*=DMv_KG<2v9Qiq(J`CaXq7%tn3i3mPo^IXP%oi3^TMA03LZ!fQqvV4J3A2!9pjNG5N?5n)DD0+o^hKodcY&?(-%oGG zlsf_^ZN&3vTEg2B=;~BMV7GLYq>Y?g$&F^Wie3o3yd^$Rx=%%MQyYwLte^e()MkJA zO$a&9Ay~URo~8ejX-D93W%m-s$6XAgzL;Yi$fUC2&zjhM8Jzx4(piRAtvn5!|Gl`o zOK^AB6Wl5865Op6Es`oN6{-{|kQPdTmQqRuD<>3pcen)Z#og@y?{E5k*=NsWc6=tu z?q*M$z^U+FaC8wk+4x|O{{>qf2TrMvXlX^iA_$_&5*1p}(WJh5_BtVBb-9N_)pr3& zOfNx9at%kU3XLEmIw!F#9*)OvMBte|=#kkN4A zb}s&xU&4R!FLYEp^k0VnUoNjjM@IxhjroCiPrXqT`>NL(al=#Y=N)8sWIMYL7S&D4 z<2Dbds9%arevlw`+z#T^y8tJ$^L647aoWXrT(7U0 z5CNO%7t#=JU~o8a=Y@!9zI{upCe85&@<0}lbv+zsDl4y0gOvQTq0ZP`I-aYorXE1( zDbs=IA@WkKl^Y;jB3JdtUQ;WQms+6~i7Z&WrCLsrXDKc8Hkr4XsVB$o66nyDzaV9* zFC8td#N`K=i9eH0w@MNTXH@7Z*${dWPbiP&10pp&X&Jm+My`QUGDD4EnVK_Ob{}GAscjqXvyRpzbG6>H5Xd@{b`WB-&yd#n zqXPkSox@P=XG#JDX4FaM;(+>)(LXdnlhJ*oeEii;Lg&9_semI7fo@FkBfqTvr|Iiq z6;?6G?`EpqQReg^z)n60pl&_HG=BPH%xak_26ENC=E2A;uRR$vw0b-!`A*lM-)jbR zjkv^g{+ihzzZm_SM$pFk&!crql@gWz_ILznIyi~`@(*rU=D~1O(zhI3VxxU}fIrvC zJmvoRb&|{~(>aC%DyEC6&Q>6lG`H~quo%47g~LwyyD#3S$`A&c>y=QX3#)S!vKRlP zaEEi}_5DD|97z8=kUC&&?vGilcMoEq`bFE0T~98c8ki-^l8eg40R*QqWGUfdwTsvY zq`Rv>bOUoI!Fu13BVZP|8;po&7D$kVw;@*IRnWve5;BpMld1|P>_{tp8m95zF{b(skH!6 z7fxHiSGsOQir#pJ0q3iW>{w|1_MP+xhEaCv$yPL_z#m+t^*c^sG4KAj2#S|ah1eZ6 zN&ry*vZQv7K8$oqgRN8}(|rt~YSvq@9$GJZAf)y~!z238hAa>kNup~ut|1ZlN#>2T z-~UU2;+_NW&^sz&NWIP-skOwx@sRY)hc?!>ll|?Eoq4y@T|1PLp#D=E{~1YM@K7S( zOMyukVWi%#sZ^0g^7O9c8MdDBtG>`TwoQw){WKP}OoB(hT+**DN9J2yw(UXTYOfE_ z4qJ*oG_ajxAYGV@382Y$e3JrAj#5Vjr^ibZyxl~~ODI~V5Ai>;81{4z{q3iAP0 z9@c6x;%zL8rrPufUL5;Qq6k?r#X^wcmtO|`rLumjohSew)BhwER7br-GjrM`ETFp< zAe4+E-y{;My$FX)Yq>A!VYZ1j$D`t&5O8>jkq_MBK|r1S2&P3JB%)W+{lko$Q-MC; z5{rYAWD~N^k^jJ#WNwEUu@$=3)^>!k)udQ~+#m0zXe0w_=>^(Afr)`&m^{x1z6h_v0w2u#V zZcu!zgSi14A6JiMWOM~)tV@g#Zmzw#YpONat>tiU8i~V>e%OU!rfo$5V@d|YpUA#B zz3O7TtTe2G(bblTRDDCeAVSROJQ4K8Q_{G4Cu28^u1+MLw0-u&;0#=Hgns$w0m#zK zWCHAe*MlHdV7u^0*y#-c^{OOLy*-#mf98del?gwQR4Hc%$BL~>2{C(To{3REv!t0u zFccQeWq#myUP;C!ZeD2c+Z79Fd*l!g^;_ocG}0YY8O7p|Mn8N+a_4d`iM*O}=z(b; zkM_pu@55nUt)T?U*u$<|P0T=XEo3fHs26KQ>3&=;5osRhp*07*PP01-H%frVlu!}x z<;^g7ycrzJBcunxYMeW(Gw@?xTxk6>ei>t`$);(oQ7Z|t!VdyyOC06a9gv%9tnZB{ zYqV~!i3DZlq!<`|xqysTu3t!@zPlmH`@aw6A4D%|P;V;V&*<**5svlr1V&W~N+jsR zWNWC_tTRcec@!W=46kLVWYh>70M6xH$gYmJlWtxashva!CfxC?d9GA|rrW@~m7qmRULSAE_o8Om12g%Djd zk-l=s10B>t{{zMNb~gn|7gfScsVG}jtlOG9RKC|r1KzYjD42OhN}^uf7zh6Ta|E=V&0de;v!4*0sM8QO%&nI6S+;PhVObe#$?Ny(sbYv74Qn+{0i{ z>PPxQt6e`lXqI_~2h7t$k;xj`4!0}rPa&gSi*`^7hysM)kQb0aAW0s}*naCL-igJHyTQ9BAbz)ZP;vZxm$OLvI+1(g{8WZ1Q&{ zj;yb4WT!fUIdX2B0Wl!DJVs&lQ91f%pFZ5R)N{imSj%kkqW|Hx)TeIMBu_fdz`y#v zF$VpC?&6#c^8BXkS+RtEDHd5Bx29l8ZRR?BpwE5D{a6{jnrKxj6<)=PuM5Vv>dS^c z>oh|Q=UH;C^+6O+#w~`FQP@svP1+A!efxPOI5$FIZPvakQGIAQUNIF}JW~|;J0!JT zE-Hq}se$l|DvV{d=NvQX80x$p^u)tLX8Hm`$I2yZuiD{nGIVo4p7Ec?68I)_QAqG{ znGUVB`DekY-ak80^6i&h5a@MX29#xM!y^G2V|#wPp|IHDQw?VT|@u)N|Mpa5*7sWA-*tCGH%U< zaQc6wwz2Q=W~h~!LwV0u8?I)04p8*m_t4V1CVx6&mAD)a%EMi>nrG&xX4h&@Li*W< zq^x-Ks*SQWqa}r(5848g;ZkL-zSWpSyHuEZqSQ}D$N~+-O!ZFZgUYkD68-Pht>C@u z3s-f=IT`s|^8r#U9i_CZ@`0T?d9;+J(q9Jv-)|+`9A}<$<1l*IgCW+oZxGKH%fhM4%}F=T~u?Hm^E$`Aj!2^HI|~_pIJ~- zCpb}8vW=MnxZOGO*Zb-`y5-n$>o~O|86w5+Q=F?Bax;pS*?h@vn@yKY7kOwkTT(cN2G*)qbP3+O_x~#Eq^% z0I6+;09SfP!_`_KYkEfd-aWvV-y~|RmU0x3@}xZstu6oavU9TEBrL3*4kFLBf%9Of ze0n|<%GpA=b!mZPf)MRn&KPde9^}Ts2U0&a`I3s(+Y$td5_k^3nV;A02D`~3@w~5d z3M!~o!nwMp7r}1M?xiDT{KE(=QE@P?&@x|?t!qBpkgxrW*+3SL4S~X%>ENhK5|LhS zy+7X04gDo>Wf^}I;qa2T6RS^RD1e#^DLvNIZrfmWM>hYdt#2Z{@u1yqi1l?PQLKh{ z2oG&nP9SFW26$SXo>!Q^{eWmz%TCx{8`%T#^~>||x3-4E;~h^|ip|b1khZ=PM%R4V zx$oGxWjZ`wRKn+)u@SKGu04iRc4k`(*KMZ}Qr{87F1ze)7-Y_(t9Rx5K6R5n9x#COIQN|~c#F^Y#(A+vfNls%J{dkUqrbu;kP zqMvp#8{v#DX28g`NPhA=F*e?7iOo^&dmnJub8wO4MmTd8CCa-Ze2)rJ{HsaPHdB0& zTm4#<`=K7z8B3^2PaLMX48Z96Y|eb(^X`dKN^-uTHPw52?3`a9Gxerj#`v1*h`p+YTjP-zka2&0TR!ZKckua%K5D~OrSyrOO*YX|= z((6D*DZCseYP4(@PW%GHJ8UoxES zJXFdQk>xrZT}_{91f-I8t^`O*4UDUu@?=WNHjfZ6XP-%93&Q4;_uKkc1Kb5jPn7KO?6avFuTo51s-$v5Y)Ss7X=cZVpZe* zZ%Vw;^Ix9z%+xmfz$~!Hz-}cyaG)CZ0OidhC00TC`#R*a3e_@cTX>1Z(uM>>zwG%4 zo`yKF$kUh4A*M&K&jIe@s#v4c00x515eTG zY7n?acz8cP`*=_h5l3fV31H~C#SD))Le8l-?>R%TULpF%$xTtTKex>XQs+3PRoYxa zRrTWm45@W&M1e3SPJ*QJ?`c$0H#U|asP}d(I8&zp*WQOBm{MvC0i@pWImOjuhx}|m zjkLLa4Z6UW@;Z^jiIl_24+Ips)8dpkTe8hE(dOJQ&Ehag!CY{L>KD%9Up(fNzUD z=$l~_5bb3$k2+)jTf#`Umv*~j(yL@xydHRf;hm~boz#ig>ZkdohZ|dz+V7_uc1n2W z=2UFQ_N+&24xjHl^}Be6Gj3X6Ues%iO@>Q){#`${i&)v@ONh zlw1Dheh@2LB(Q#wPha>ums{~j_FMi;Ozmt1aCP+X88+_jn~pSPq+@>eV0jK7m0|=uvN{mL*3Ckoc7hJ(>T2c9;&p7lyoi>Xz`fmNc09g)nm&(+{ zA9lvM&qR#=X9cd%p1Be-*87VDm|3Rh7zFrh5DwA(zJ}3Wdm`@5SB@+&DrO*<^?5SJ z(hpZ81dO7Ou!MCwG6tG!N0}J$-!lkhcF%{z`n`t8dL>lSqWl|g8?)HAf*2GrMm#;E zl<2Tw2@0BzCxrkhwKg3~R6J@xV9Gwsrw2VHs;u-uR4nz>tYofMo#|n7Y`IG`=zT_F zdGp{D^8Lb!BM6YC>QF5FLqmJ*;s#OSp@()45u3<0|{2`@AWPad$N}`zIGj8WG?)jYI8goyaqM0#9;xoQd5HT*sw$fHV!BM zX0v$eXp_0x{K^cZ1ZX(L{E^!VR%S%VN||y>TP4$lbhTx@J6O?Vw{p zvczl`8!4h>k!Z>CJP|9#Nygoh7cX;VTahQ%P@G^^T7zrVzaOvSM4Ojb-rRabF0PZu zdGp}2we-`&gD~K#e^8OnP$?4DkzA;vHvCN98QZ%NbH*6u5CU}C$iA{O!4mIBKVy5P zgOd;#Bl|D(nuBq#QmkP(kY0sBH@eC3j#||m?vZI{4^446DG!? zWzq$ht9L3(rD$4-{8RQd^#tcdMO>ry>Liev$5{7r9*;TnQ&wdgTUu3#`eJ(^Y4*>Y z+J84R5v^MPO_+?2-N2Z>-LZk%nxh;X%iD4GMHxRkZj>L_6tW7HNdhl^KN0{$j4o;{i_~zOubTypvpqcq!ZzjKYdWHZ_-M9k6 zmyd)YSVBLC+ zK4!yH*i~!ePa2u+LU5h(yoN;SuJ*jT8~MTj)Xe;tNSW;qm8G()*$SSz5`nwPE;RM= zcdTya@tMnu$_YGTZfYy{Pxr}KQ9Z#CCp=2LCdbSvX@Pb}OrHw{=0_;F{+5v)LM48l918{V-vb0QrzRxZ zn5_CuVi=sbd??W&S-j4_Tzl^L)=#Edf@BVA6Sq- zf0k18JA>A`?dQjOv^?~f)y5K_W-VF5SH9h%HFn7|xxRX?82o(Mb#SfMdpql<8)7+C zA~FqVwZ&M}a$DxkwWnJoz_)}UixxCTr1+GExWOgxsX8Sa`m6qR5KB+Jg+ylaLOiD! z5d&w@2D=cYYMq-%XVl(;z4TZ8LLe~dMVQUetI2#WUiUMgyIS++;)xpgR4q_1fMqaO zgA=q?U>xnrFv`gkU495ZElN~tnyHC}DJ4}@If zNM!Bm_6TT1e_I5v{%+`?SAPj#J>?hHwrW&C9JODGDF{C5ncQ#8v(z4=sBGgjzJwBn z(>IIzlE;XiEqf7GW=5$nti3lYj~8K|?O;#tHv>-dT2MrkPI*PRH{(GuCjQ3HzuHMX z@yRVFpV?f-=bP;bQRf~JLp z&h!bvFu7cP0XU29Q(LSiqcEVk_Tn=7Te9v0ZdMZf8^03l?3QoMR74M1?$EyGL}6zh~V}yL@B=G5toLNJJ>;1~K*D{OJhQ`W(jA z|H}e%wOt0fnp-Y9A;{7yNzfdUM)(>v%17B9?U&&X>&I#Fje7>MXtg`fAYGMuX*7KY zc`aXqsdgTxWop9Q#b3}+LH|dPsmo7MS(V0d!m87iwLnhJ#|lOt-z~ISnP@xD?D7$- zn*S>Sue55<>;2fhAezd5)LNs%;6R4f_>3`)zFBdrRopj(_R=VHvvQW+i8!aDSTia; z6JJ`(Z{T7hMjJ1K7NW9tSx$P^N5rI}V6w82s}H`5OVhqBgXDw8qT6M4COUM_{A;D( zF_1Sxwj!DOR=!fxe&5E;+Q!5r;AiCV%ozJ@5&ftQ-k5acZgBLK@#v%5ir@&%=_@iQ zjmA8ixO3$_mw(8r-UhDzQ-VIuj zO~XK3A#2w9$PMVAJ>LVm*2oPHXnEr(3?2C-&!MN2dWKWSMf^Q<8|-5&2wV)aLp^8G zx67iZdLH|5NX^M)78uwr!@qJ@BbtfLT&A9F~f1#< zQXpeqo)QGVW7V;mb?m4!6h^m5V@}8trklN^8FX+9VWBqc&QN9AdUQ1=Rl)WvvQK1; z|K_7Mmb;_Y!|#jNR%lKCACs>qFA}xNwFxMoWt3WH<8Hl{j5H$TBrC1dUW8OemS1Rd z4Cyd}kpoA;La*wx3r6iFShQ^mkXq@}RpRm^e=qNN_ZxAQf$|h&{W^s2j4dX<(#DjX z1%bw;Lui}i#B7Rx5-DfJ%OTQc)4LKq-HM=%8oCJsX+7e^XaD<-Hfr%6B1f@bts9Xh8*K{DR!{f(P^Y056WDKdho`dcS`d0^EMwOK;GB3>{I25nzVwu%9qrjPdA3JD&4U=%Wy1<2g zj}G9NdshoiYHiA#*6JQHZG0QQ4UYe|*~wJ??HP2Pnh|f>`UL@?M~idxO0GNj*Om6- zvu{~&-{S>X&HVZy5K_6`MX;yk81m{}T|8(9PhAD=dDC6l4>(86W7>!cb533aGE0P@ zbx3}a&ZsYc0L;;e;db_e%dud}jaR&8jQN_1_+Ngz(YACVl_$HRgE3*L2W{^@qSf;; zlGh94ctla-Hxd)(jTchS{!S&Ml;1KZt~Lqgsx`f%8}O-da@$_NBL(TS`@nTK6P=BT z2^$daay}%m@@^69ghvCV#pVql2E;g3o=Hd(G zzuF?#zu6aa^~RM=K)QU0fcn9vv0$#hNsg*dE;4`Nl+P8CXl5P)nfImv zfp?GMfNYc_t<}<%H-LE|2VT2=!V8pEv2?%I(ZM+OItWo?Wb3UK-;a>fW^ zQft)`RqL^9pBnB&Xc#$`;8iv3&T8-n{FOkv<^yB(eGPGq6{qt!vSA-OZfiiwmb>n6 zV|RURiHT}I*MQ)V$wzgRJi6(pchWbiJw$0O_ZqTAS?WW?o5gMc*CSO-qSUA##MSG| z5zIXQ*@t5a#^P#iS`pl#_wIs9+S_NmYFf2Kh$r%eg`sU?ypnSy#X+z2(4GFpB}^=| z>(6bs(Q7zsaUB@0K5R(k z`VK$p!F@qDE8fO}V`IrbBfH5v&Y+m(40&Er0xq;U7)sNniOk&&+78vLkD#h%&pg4< zr#Q6DkB5;$@eY8vxiAm4!1}Zj>9oV$1L+UmO~e+hNlaUfA&M$7Q&~>?=^t4?wdXSdyP<)=9OVHR#4M!-oBE&nHJusb&Ze`!0lsSIlU1m~NcPeQr6HgmrH z?O@1go)=+lrnnP6deK7kjeQXbP@7s(JP{nf5uElbu#XabYZv`N-4I)kiAmwFX)1}W zufG#{4|WNGe1beGs3)89Za3mB89E~#6KYvy?|}B-zhcN*vY*9z{S}AZn2#OJxr4=; z&-=jN%Cjs4+8@gD7_nTQQM4W2-f-}}L|T~o55lW|8MMcS8_scedqgeZDo4Rjj+fPy~N zop3RV-GQyyH6M|ukEzP7u;EOUQooPmqPnc5Hzem|Nr6DkO|$4X+C;5*93!=2aAFwX zpC6<$`^i`5+SEL&px!KP3+5hPV3ML(^6A1a0!P#h;{rLdQJ* zIRHAxa#8M8KaPQ8k>Cw6t+(|?c+06ZA!1b+#ND@N2BtJFm63orFq6KTYxG<$W+{iP z%Ew$NVr@^FL3=Yjlm*HH^WZwIH2kcDKSJHdmC9@6I*&AJ!DaF!@XZt7Th-?fym~zq z93^m)ug$TclEmcva62Q$29 z6{1G_Q$udjW!DqwTH1U1Y8A}|xJ@?38|`=RU=+Lj8I`byB5SnWM=EQN#fjc5roq zJUC^vgn+U@lc6;#k!e$8B3LiBbq~jP|CIQCJRVYNwP~@;rN&9^-C2s!y8m+qnrDBy zGw`?*7ZdsrU5bZ1c$>}o_}Q6Tt0vL>&V!1kI$F}2yYlt~a`X?DRQvX$tXLJwAe`E7 z19emHDmy9k5^}nNkja>dJp1WXdg^iX~i7iS;4gsPaB;N zGidXABAzl!CIhw9*+hggXFo;U%4oU@$isXnXuX^Tm4&Z^VG;2%-sT7_=mDSC0V3Dy z?Ep?EBm!7%`arOU?1nKm%4hS|&kty-&D<$hKNOk_WLle0#Jb8mpTkd6TB73%u3gG~8QIm!;AF_w!pWqDE=S-lAls*5(mw3&PnZGFE(mg=>4 zk#Lb+Af>6Z#Zt4I1|iYoF0pntQ5+}YG?%MwK^*Z|Ae|E=F;=ZaN!@SnM#y|P#iUQs ztbPnVyCfW@_4*6D9ic-&KVyNSJby~PGIDMu!i$`wT$!I_3yw0*m*mmjj6+_dYbZmt z4w>tG2UJn=RiOYovnn?wl(ed%Q^30b@Yl&XRL0o%c+XsLhf-&Ko`QXhVa{U1logD% zicj)Hz8+1)=N>NH*Iea;C1Z>$rd3)Tr*s+PZttN#x{k1lNPvufWmpW5Rk;oTS;vx$ zr;1UAk5jT3{~%3P2=k9 z^ZRM1RD!TsUiM0>!7SbJP0#3!w2AB7xH_p_Dx;o{$v~!UwT0Et8_R$n4CE$ldY6)L z$fq+_i{31eRI4hE)YB+Kj#$}Dtls$G#hTu+eehUQWf&t@{u1|&e@wt=U(;NW=EE1P ztv&e;C;e$(;!UtlWr8-)Tt-!Tk2MM@Kv)>Gak9cypxg@A8C{Hkm7 zvAi1nzc4QLeos`g33v-vw--(ZeyTSl)iH^vU=}_BM2Ve<=`FPxl|?U>Zy)OP8UzJv zbVb(T4tegkIo`+?WOcxEDxuN05GrU_lMdJ&Rd1uUx$ox*w8?N2t;4-G*(nCq#m;lr zpte=)%QS|1OmKy1*%iBOzb0*i&8iBNQ2k~cyAc{*;9Vj;bDHX~H$JiYN3TIBZ>I!w zcK#%ZH~hs>;HPfy;0ty)(Nkq(Du+5f6L}^(5n;-{^S($`ZZM8i1AZ}CYg>q2jm_6v z1NM~z6_klPp<<@qCbrD+az?7L`t@mWuF1{Q?ED!+8I}F6Kww(m5Jrt1iJ_Dof2Kfw z>oIq9X=*XbY$&HBnH>%yh&HG;@oF`fvupJFwFpV=M%N%91sm)Fr^mRHP-_zmB1cKs}CEoSiB2$M=4+5A4%Sx*^16>vtexY^9^y+^sJ`M zF<|L&z@z06!P+XP!WfA@!L;woQuqv0&Y81XmtvlIm=}3%rQL_35m5aUbnD&6L`I$} z_{@574Q=(fO5wnpJ{FQKru(5o=K1;7g0lpNdb!#>4*y8iVV!fGJRQ`&ja${b`$ABB z_EQPud}mC^Y+FqQP)oeN2u@@tL{)D*O9LMB>kK>8&x^lZh7(pw_)%_|*}o;hF0s&g zz}a~BafH^!4r={p$Ju;(=_K5$<$;5`WH2{}g7Mf|D_2_dkGX=al>*hUteUNCD0*FV zhN@Qo(>iE>KX4dQl=R%nM1htu>=KXab)qoErZbQ- zw&cKm)~@BE&ux{Gqep%H{tcW9`OQvCf$VdKj8bGIk}3nE$!6vD0v^qj zPPL9Rr?ZC4(*}moT4NU>lMyeQ3H5{ogx4b%orBD!Tgi4u=!FRgknTq6YK1H8g_d4e zf`93hVem-(6b^x69riG&=zHNbUOp1kZtF>qbV@)PLuqdZp6)FWpJLQRC08q$C|mqg zC|}MXdo}$wI9B;u;Fww4?y@@`+#^}^_-_Grro%GuyWtuPdA)gMe5S8IfC$RRbp)68 z?-bOz@IPW-?IQ*ZB&*Zv3Ltt>vmiLozW#$LAl>xq&LscOo4vr ztytRP{bn&XIzsZGV!S(cNgBHZ_=)9WH4Yhv&i89nW3|${JIg6w$uI2!(&!(C!BxMtUuxy`#feb--`s^j zvefcMg5_t>M{&*ECG_8l@r?4>NcJtOIg@|p_~QZ7Y&U)EKdqw7E%D`4BdluWuR--s zQ==hnoL>pqjL(p@EP4E}4y=tsjgPWB%3O4p8{FbvWR|jF0OPgRpQZm-3&5%Uz|c#U zkdaN&D8ovd8nk-a9mcDDs)48t8IlY~= zS&4)(tAr!4`S(A>xb;6t1KrPnzB0PNIR4J3ujE4V-^7SHWfowq^gG_eN;bk6YMrAj z^3SWqz0MqTVw>%!RoX&c)hX9v`U&k3RXy@Ch%s$9rXawDu~M{acOgcUomV3fY})<} zoET7mp~mt&&M;EHQ*(`{M_m~D&6bK3orWT*?yDL=Mm1RgvFQgkL4J@cqtx{_vFDg9 z1cA}%nIBiT2E{U}tqEJT$0RC8mFU&T=UFNc#BWi^VP2Ssu{58|6kc+bC^hp|-i-*o zN+Gcp+6@sDm&+2p-r*veSrNUBB_GKj>qC^_QxT(x-<;H2d&x(d~1 zg^)RlFK1=3C!=F9QZB27CPtH9@Kbx8r#2Ytdtyty$phXrzs^7~rJE=IQ=BaPZPuA4 z2|uC}>7cZeO_6%b&p5_tvJzo}+&7`k04el(yT6gf3@$0rUoa1GuZ|tW9YuY%9PO>t z8UgTV@M9S8-Yr*g_})<+@VpX;t<95Ze7zG{sWm8tX4dM@WRLaJ54qH%CXDJX*$CiV z2~47oYJ@UIDJOsWe|M6kD0x{-uy8x7s;-5IOl!R>-yx0L=?l0j6OfMLxrj^i(Pi>8 zubGBLX6(XyJls)+)q5Lh4O@5ARsQn8C;D_|Y8-RrfDhfXA11YK-CPH$%?H-;s$D;V z?!Lj417(DK{bkj9!g&3`WFoqX{B@D>qdZ#at!pH5aYeZx2!6i=as9T-bmk8mKvwP3 z+ys!(beEk~?7E(I$NtsWS=rhqm5Z(2<{+)vX*&J5#O-)t=g%5Q@w7F8VJ2>2(%>H- zaZAi)SQrDB${p)yF>I#%94Gyi@xZkgauAnw%MG&_Cz(Tc)N#UddbTzA*t+@-NlnAy zZs(s*N=fmam?7b4uRQ_{s#tK+o-@w|&SP=uo3;`YW#cI7>hWbe!OwXc=PLtxNtF2P zP6ofmXjp0GWjab7<}Hy_@;R;X<1DSVXt9j?Jw{~k8v?$Owv6}RK_`e3<@{lWDvoc& zfcf+^(pymvLqN29Fv!|bX%1IsWNvo4=s66b?hdbo61AsGgyruEzM;Fo*1G)_!If-L z(6QQeMr6zH4DqMLjUe2NQR6&m(>ASvLhl(9;5EIdh}Q3X6m*6JE}-w`Pc$nd|H87=z09DH|!XJTqAx`-ptQsxkD?%NLw%A~YJBI|EIOsLHICye$TpZPetM^L}4&WFXmg&J=L zWt!Xo^|vhp_-G;ulV}s>fntVK#Eg1dsry#$_A>t4EJ@+f;maA+>!UwB+Iwz5q_}rr zs+HvH8Y}){IFJi+^psUJWj642%`v|INT`_ubAh8r2jVzoZi5-%+%b^V{4B@M8V^=U zcwCg%5beW07w81JA&GKmI~KO8IK*(j;&Ht?zXkGWyWfb-uVgM3wGE50JAA#oVc75} zGg($+37!6Pu6k7u0rN&FOrejLKcmr_5107K~K#&751rRl!>lSH_5%eLj#|2{PmN?T;3iGIBwO0IYS4P$QqU66ho zic*$G<_q%u8e-*3bwO17FB}WJi2+%4%)=PIU95`n&B$VCbxb~p59;m!ijv~; zK8X)&3(Z86kFw%o=5K*Zln+Y~!kTpo9jxc+6d&t%#b7kad61&K{8BT<-|_6so}hAw zV(xlKzz zI*Mp}ccX$;;4zeyZd0V%x3Aj|Y8#3ow>A7T!s-|P0m$gQ4TNmT_Vx%cHJhllaW<>-KC+u(9d*gE(xA#}0^`o8Zitb+6Vlen^BkYUk&u^f6oJK|Zf6Dq1bV zFrWEs7P=bG=4}OY&?_DQmW_tGw)-?DGtZ|- z7C~c8687Z66pj$d51sQuzSjkJrWPdiIpU;(@HW_&r$zr^LO;tsTg` z8b9n_%#~bSclWa_}pQ2hCWvdCdcB`n{3%mAXNY8iJ+sOYG#>)L`1cQ1m zgwm${dqooOLLn40aD&Q&Qf@?3vl3)0Q~DlhL|TWAhf>a)t8WFb*CUiM z-h3t4tcTt~jNf}+s@#QdNTe^zfkn*+o*2`bb$yMU+wT$}y8g!>$j6yb(9314My5h% zlYy7NHPy~T2Z5pt=q|BaZUg31Z+-}8kS!ZoqLk~m z0K^0D{Mnk)TQ0gKkoS7RU8K?cPS+BMhP9M$viDXQ(-!@$uJcJ@KX^i^>S8K;~ zWKw(PrEi{!1;?z&p0}S`p3$(?pTF78sOQtyL-}duhh|;N2Q#+*XCE*dZv#fhz_uR)NWb}4XKdJDC=*+f{U_QLkGABm#R z>m3igS;=I$Y^f_wygvn(8AIM;3`?7u2%YraT-AGWK)2)gWCGB7(v|?STkSHS+SkeFy}77zGmIw z!SsvX7H<#bC@v;~4q`9upmPB5Iv;_nL;I$)Q1jsc7wgI$(%7M31wAb5bO=m4cnrcN z0tsd1t}IWgL*l&{n)PXd&2eriRZ1(ZNAUF2P*|7`M5G_J#BDQMgrH7Dtz}?aS+S+H z`!V9_;Zwt*($(5Vdxrmca+EAg&Z%v-g@V#mOS7{CT_F^@9w|twPrHP!#xIWnklZat z2w2O?5qkR8LKs@B9wcOTG!Z@A0ua)8yhfZlWg^;Jjg=^pF^3e<+6nmADm{}zXvG%U zVRKYiHXa_|t1!~I9h^#A^m`Nvmnann%9*y@Mz0Q!f%u|x2SId{O`!j(C0j?n)uE_s z!`kqWvwACjHtl_}i;?Rawadzpx$!Z$DbMHLDQmdc)S&#_&KrV&-aUByuXbGweZGDo zLN#9J4ABzKd+d%x*^+BLyh<4BkBVR|b^TA`#wgt%xN*3%z+b+?IOfZ~B(1eQn!e@X zjXp~8Zx~S7WJ}@d@4g;3<}ubGx#AKamfkuK6KNG5B_ZQUKkAk8xW!)EO>0z@rY0(@=AV(hiFn^@}iA1YnNnaE^%kMV?7;&#k1=Y6D| zgZkv0BlBT`FKzKzgn%`wxQCtnPz^ATp7+641lY2Y+}E@DjDyzC9*Ao0x8{R?X$w|2 zN}B1gGbXKq^~DE=7~3%O@bEteNfoR079vC&@?3Id-&1^T-Y&Y2QFD*5Y?o3TEtLVQ z(9-&A@OsFnwAuq=>dd*ItW3i4#gC$lal)9%MUSbNPp!yqZpYlwD5m|&i5<*`H&H|_ znR)E@w>CJ+I^7d%>&|z?hKI&)f_nB(K(tv*9dW*3EyOnCH^{B?Xu);hEKJ_csNG{yefIr+-QnmvH0 zp8c{*M4K{@u+e(`iGWyECvsJb$cGWsnL~CVPL-A->#QyWRcG0RXu4DlvhfMBJGr0~ zxfB6<1=%@jY`jQCRtI<7h(T^&#e@2xfvI3N@h8{}WtDg>Z7|WGE^-h7+T0+_qRxs9 z20q&fO#RmeT6MQf-syR+i|>B^o5~^o#ZcdxtW#Z-=Cb&s<@-R=&l&ypFz-DjqS#pL z3OmL3q*MzpYZ>jeED}w5zJ`N+FAb-gtY-cdId1C|{0bf+3q*!wYq}v_CvZ7_neQq|# z=vfl0#Y;oTe4wqfIVN8qJB`b&6EKN=9sW>Dx2%jggDSW{^oh>A!Z=>F9f4QH$jiS{ zl*|t&v4E0zClC=?f647-x~Isq#B(o2yl*2 z^2YML0$r{5_dpvD4?!rarXTSa^hFH8Og_MbB|IoUs*V6DmzN5^%-|XCCa2 z4UIyg{_R7!N4_lcOXV=5pqwxcWn*r8d=>{PA~SOJtd2a z`d_aQOn)<&d6z@Qy+Ju$bqB)4Ey5g@YwbCZ*>%y4HgyQfTSr{Q1Qq3<1(YV;_uJTj z)SUD&9tC4)>*N~LF&cUJ1HVy|zFN{Nn!_9FjsyMDJP50$?by@Iz5&V9-e1G*j#(8= zy7rVcC|vF!V5`A4_*oUFNkkM{3MVU%MOl>Y#0WQmLIj-{uQ5TN*#LqK;Hup`ox?U+Vi`>)isF|J^1 zqh#4x4fn!KYQ=2M(A|@P#_IBRJcsDD(-uI%KLt9aZPSBRi0j$>Esp9@4bI@A< zet#Pf*JpFlNDm-Q)tuLpk>%Egtv1KU-iIN0w5nKe`Gis!U{(XFism$)ShQ+1o(F*} zyT}!N?MTdKmCJ>nmGPZXOv(2&2r``yi6_n%S_}DEa-f6R^fV^0e0d*rJnfsn(9rl3 zXm@Y~j~co;9(3hV$`aagpGgYUnPXHOjg1tjJYBSg@hvY=#WvrXfi}&5=&&g0d>qz# zKheE$=49<7S%%`A;nSdB_n5#{|Cb169^EG4`QUmgoQ6#lYex1C1)gVl82!K?zSVL> z;sT|^XlD>z&Ii-Fl{1)Pnu7_<={h#ay#Zt+Pm6K3pW4ZvKIoD=b80l{U-DMJVKY!> z(eL9n$5h99NY(GpaNngAA+_=#tfq!G!3ygA%PzD}wi0qmEp`ey?)XVX9;ClGH^#H(6cBHGPs{-FvCwfo2imfS zfjtH>#q#5SV&vaLi4vpGi%_tgI&;UVvg|xvug{6F^zKS)#rz2ZQSTwKHl&3(yv_Ba zKvG&vLBgTIxZP?iIig=(#Dj%7x}^kBnYYwGGygOo`m-z0F*dd!h>V%C^U+j%DK=Ki z#;Bn!DtrX-+C+*Vt?H9y#-5Xu67$G5W=j9-MBrF;bH{)(#g8mgZ)~Jh?z}ik`#Nep z8hd2N4W`cv;>vQB5~?`IpquI0CLUt%5<-AqycZ9vtc#+!dUhKk=(Q`j+ws*>S8)F4 zfpSWrk?CM+SAzI^yp?gF-^;@tNbi$?_q4y82hmohg z4e)xIjW;*9Q=piA+PQ(gF%=Q4*t}t^>$>{Fd-Fd8QuSp7u-5O&7BC{mix}1K(AQo^ zMxy(Tx4RgV;Is=!zXDP^>eNLf&1c7A+DBJn?fm=M5wY{Jq+R?2WkZGacM=A? zW2{7(AB|QTftKzQ?~|q&g>`08L(0+dHTu^iIpD%1ip8+@V#m$$Lh#i zuTlF6ab$L@wGG6!)p%L${S2MdAFQZ39&Sef<@B#@45|4_hj{yg{ppYEPZFq?=fhel zET3F&-hMrdRlQV!attd_E>+aHCXwt#XdE5~Z zSgL#}iL=*TgrNB-fUDNL03eU{3Z%vqWVz84Ira3G08B6Wi%RuCWEB0HIpAj$mi-at zjf)=0c;oIiJG&s8L)hHhfo#)`tjf%)D!9+A@5ke6ikywFpKlFUW1qyO<`M&n-n0r& zE#}DPSjws#2}$FXZ0TG&6am6!g);n4s*8!D79eKu$=Oo#Pc3{I8j zP|-`ip!+^3*6j9+x}dDMgz)OXKyH;DV>a5E#`;&H_UI~%qMcma0s_y@ z5PIg^_7Xoy{tYl$^#=3l&nY++`0I~Iuh*&r8LRLis(`+;FGbT_=SD17-k^8vjrQvKUN}lmejY+Uw}g%QBw!QLv_B0KZE7u%KDe+%t_a0dkMP+7 zVXY`CD_6cypp4G^p&);{cpqEpZ=2%{X0griw}Hgwc6CkPR>V~HTHy8IR` za-@kJJMlkfjzj}={r7$>qSY`FN_{ZLo!0v}5OeVG9SB=^_;MR-7%zlL)X)@$p0{mc z)T*#V{<{5x=r*+cb{h*Xa+bIDv>!$DT^Njvk<6Mp{5#HLVCSJ*0n}ZQ!oZSesYlwu zxFkqz>55!N7X@}o>EpOTSusJv_3=C~t)WlBQTwHdlll}epwRgb8mn6ti1vOD#7WaK zcYwUCxC@-e<|=P|$71Ha24aV`oE^=7uyjBq{i?r^ z+}IA~V<)YHZbB*IR7sZQd$r!{x%|(R9R;kMTM29JntUK;N_i+JW?X?{*>Ls(Su{)d>qLXpp zdKx^+U< zLT9nylb2+G)&DFR5HsfhfY;Sx1ur-5Q(No^g-@B!$YoA{h3ynqIr>(Om$eJ!T3-sc zSw~*swA&*gX4t$kkR{_bH@~7?R{(GvM@KdP|8aEIaaCk(9JgCnT~}RQb?mjf%qbDsD;F*9e*IoBzU z;X=Ii5eH6%;!Fd@wX}^X(%0xGmx8AVjzGLA??A3~@B(dJRz*d{% zugmL^;L!$7+N%Z(l(-DSI`v}C%BBUEuvh<9NxU($rXbLAKsYV?_@>H3Yf-tGnw6zJ zm+#(%w zyE8~Op)SAm%$Ydfn$R!R&Oero^0PZy`r#HMkG3#3 z8E5?X1)!BpzvCxud?eLYot;d>ygS8ZAM3k3l8d1#{&Kst%Rtt%8fduG?Grr zuyi3waz?1uqd_b%3~$s27@U3*9qNLP3+YXFghyp^;PiJZSVi8}hJ>KV`%P7=sAH-UrIy*b`8PQ1hk#v&UJBT5Gcv7lCz zR98pjr$wuwNaVOrCU^8K$9}ZE)-)W0y2yrc=G~nHw~-LbqyL7Zcv1VaL@JE?$^Rbf zi*AF6^)~l3NE#|z=<0M9)Xi4Edc*jgtYotWb`?{)JjX<{ibcdIgYM`UG`>@~%~5;} zEREqSi8XWb0um@)2B3Ax1(s3nC5@B;!5FK|`f`}##`{cO3eE*`>W;3lT(ryjT65tF zV#3@M;fs1R8pm)9eM>Ycd2fN1J|}{6?NCQ1q?J_APHXHUZpgEY2S6)vC~#=2lhIB; z*pI8$+eDr_MwZ53+NrzXqYu9ecm2TQG&Jq|D@poFUR(8_8RGk)1ISG6XfzRgDnFjK zKC-<42DrxB9SQ4G!KIr_yf+_);1tDiMyP*JzyPIoSJX1zi~~*c;X;ft^6jC{A8ba{ zC_lSLK+@1P36i(+fm<0f8=>lTmbkHmwW0*vU753~e@+GgJ)g@CDB}v^H?~I)NpK{h(TA9~jj?g&3zo3YM8@%ypBa*%A+dZyku&i*Mec77lI^*$-2jOp+dNXD#K zk2Yu95M74#b~0R?8{ir}H!1 zS+IB*2DV_>8@aEfaDFi}n)B85kD^D1!`zUQI;Yd{Jm+ok!0#Akp6yOtnl+x1K6>*V z-pET!;7iA(K!ei(ACP2T-Yu?d*3So$qEUkR|JI?lbuv4Ou0ys;t`sz~xf;Ct0LQGg zFxFq4^MkVB`Mow=H(MO|F4bUB!n@;kc3^XMf@J@8qRUj8kSmr}Cxi2oZiDULv;wPe zi!$XTI;qDWrDMo?3ubETqv)y^esh@fCp^!5v)0s0;9u^~k(Fj!Ayl`Y=I*xP0MTTw z^hpJ#BF+ctKmFQ4rm;OEq|^nyC_&o8oaeo;GNTb%wxPW1tf)k0s0Z^+N4-{TP7B1HLeI4AIcIU+REy3vs)UuhDFfz$Q`}aHX4-2{!39k_fn8mUwq-#-E1_) z$@+1Mr;Gk)flFz4Cyry&qoL?fr~uwq!yRMkUsl$MXzh==(4Lw`0Bf-_K}%_RgN)IN z?eK%+>#hK!)cnD7Pe>cdwE=7y_RR{+&ADFTW}uy2AG0AhzupXhaByou@N8p*n6>s$ ziq!9I0Ykek??37vvQAjfjyM3#a@o(?XjX`J)87r4trVX`xV9_bW9`-9)-(Gq);N_S-id3XNKes=je=>&0!(O{>60 zOk!KznU^OAMX4s0XxnF$Gt2pqM!H(;B*zc^vDA2eBoxZu6+~Le#^O^i z8IjcQ-vR=?MRmFGO~Wga7=~A2w7k-F72M}tTnXQbZ$+Dm+b2WaCJ?aIpyspSczO6Hxc7}D zOVz7YcH11~3K2Hb$-PTe?7H@&06;ug@^%Jis zNmkI6jr4UMx(J$P@5R3N!^E6PF1|MQi95%wYSL3r$Y;y$bmpZAz+@EK#LMTDkxDInBXCH;WM>BL)YX<_Eo_w0z z(Ee&lixRkCBfWn9jHK6(Ff7pna=sP3`fo113ib?u@|d3=M>pp!v~&tfK%Gio09W(A zD4tz14Cu|!a))RsnGgie9;s03b3cXBvgH?7`Wh2<&{8gqcfFFQajzMCity2y&dK@C z=|rwt=mP2(Q}d+5Y)*evR_1IBLe!tN8MAy)^ehcuE{DNAw!nNkrOVsC(Z((zdbAgD zrrlj;!t&u{QpFfl0llrq`fA!2yHh!gHI)Kk+@KM0Y$eAm;~7S_Hqcj$@P?%Mdv`95 ze>ltLSmF*s#)(DykaXZ7>RHKrr*|~2PM|C89wb8-a?cqB`d&p-Rhb4uW%-0OuI|d2 z4bpbTVjEM*a{lajP|9pX2VU6@n<^K%MP6@p*6wgsl7Yk)8ib&A-AM@TL+ibmA={TZ z>dI#z<}`D6P@1@gb6&e6L8^SM9>(0`Gg29HmqN1kD04q@mer3!i=GFGX>(64bku@( zPlJ4r7p~Ffx&ebZP;}I@lX-%8Q45UJ-i?u=Y;A(K4bQruqihVxhCHp&0h^=$N8acP z)`CK7(Hn@Yj0;fcUhOxd?wJTu#jyKM=GgVS9WLFTaFa4m4c&t>r<>wsWxpeWzRkw$ zLQ;4CSo+pEE3PfKMJ(%AnKGk~|8fMHEGIHSEvOQ=%B5%lqUdD|QSUs7gMRp@6t240 z2U>kwgcF>f$n;C~!q8n%mYD-jtBDLbsE#V=qwM|cYa=2?PNi@Bi$g*)csEz~jaknz zV1Pipd9w%S{Fx!guWm6M-|Xh9kx`GQTIC4IWF7n;iYR57`tLYbnU~h|oYB38>0HzI zv?BPG_+0zwlDi0B{jQGjK+e@MI8@DlAkM}k?7CQ56!~8|tHw2M&U$u9uIg_Y_;KXh zFpuVCT>(hHaXHrJ=ro3EqV@gC-Ds^WRxynpj8P`Afbg5{oik%^c+7mXe7Yxwj-It} zq;mPY6ohB;MZlO}mLM=4cgPFP)7c9xR`ikjv>}Y_Py+Y+((7_*xLJug-}fs11T|&R zW^X9_p3tGZgg_SXRp$Y4=?bZ&PseaeKh}@<*LU-=%W?J%>1|XD6u2)p6%pmxHj;G~ zr*Vu`ZUW+r>qUT7GwOwM^*`qz8?cUC%yEo7r>R>$q_P!=cuG%mmb&2|@5ym-t0{N+!Z=+v`9S$&{rO=Clg9Ni7l0&Br?H zg@RTA*>GG-eg>sgRQ{34+SQU!GJgN*2ZwWqBjJ!GwWHbx&Be~3b)kK93 zL2yvA8VT$!y9q>Ndl917xWuG-$C$?PoQ?^{aO3PVvcd4SQDv+*Z{lF~?_kc=3)2C| zthk#hp`TXhYPQSS$>^S~rj2_=40&TV8yiWl(vuKw-Od{Zw`vm&gl~Dam*cXJp0w;J zOzN1n53@PX8jJ8et=F*)z&baiI^QGYtZ)Aj1KRiD8A#fFBFfIA`biw7wk(p)@nALp zT1gHQb6yWYSABtep0s}bm%y~fO~n$k$MXen_<0VO=#Gv8&M;>*P#)Te4dr?}D3y>N zl9?6SWODwYue1#R8@YOu!#bKA+Ko~HABBB;nN_BL596ptE@n(-XIDQca3xePC9X9`BYsdAU)rW;1QJrMEo_NQs(zh zqf_dyc+2{*G=W~)IVm3fs={2I{eeKYLf27WMkcO6^7b}pZeY!?=v`=QR(&2m@Lri5hkzzFWje+F}CkgKDlW14Ro$%r6jSWKX{%Q?SlzJM3 zz}dec%BWTZmR5{xsHgwjLNVTZnZPn5OUCmpPj>&&FE%9n^;+r6;5C26M!47LFUs#= zT-ouieF%8ITT9lNyBA`O9xyf3#(<#&ySBiM8aLrOr@S5$KiYvEm}IVhyB1y}JBz`~ ziiwMsd6NT*C0oYmrME2QYP1a9oBul~%Ji)+ahO~jhbw2+u%TY<(-P|Y4-v3tmHL4+ zC$vqV)5(00sBb2Nyg9uXUN;WP{>w_6FTR{ldk(5v%Ky0U&RiunU3?LaZ1X2l%}@O( zLRx``awkcWkW>y8PNQoJPnapEh9Jc1eUWI$7ba;kv=pJDX9WP8>K(|r+39DJokz9j zQ)$WFn+VX$72XS*m`S9Dws~{_8uT0?>Fp^?qqO-`=%tQ6$L-2_8op7!U51&}u4*89 zJgz1TqE6Gvj7SG!B|~nSdSaOr*c8&muUcCPi9^HDUh|!WJxazm{Gv^n0HS8nJN&Aa z8_bx=O!@p|?z_!{O~2g0p)YMQ)5fMMeq@wh`pzhN9`DZ^OUsoKhixZIJm>kbkfZCJ zDTodXK{4aBTR05=okr3t+Z!W7PkxDulsUF-D041LT(s{17Hik?0j2q&c^JL2HZw12 z=iQ008FY9L%|7|(()Gj>SehH-uu>acSrFcycLZ!^e__r+sm*oqq(F@2D>*zqJm4xExXl-jpMCd^>&)=Hyj4(2K zERUtrC%Yd*D6-mHd6kLk+RWH3FmQd_f-$Nu&M5Rn_OerK|9Yc;>m>w%F)R?M^#-nh zY^{mHhgL{GF(#^IDm3qNHZ49FjC#hkTA>^(J-`Apa3&ngZ6jCF*Ka=MR#|>y2Uo}W z!&9p!A3_!1Ur<5G)d_A^<`s#K>g(vMpY$V2+sY~e_4)|`;%w775GD->MTJ7Yf}VBy z)e@MEnQO4NYD5wjJDrwDyLpJ`o$K#V*hp>bf&yJPC)ykZ^9QmjsU8K$dNdp!TK!R+ z8y6Z9e*bJtMaon4(}bbBn<0x%aTfQui^2=@cEqbd80+{FA^QbXIM? zEBG2DOX;jku?joL2B&nlN5Ek9j~8={r(jag+&1{4=08`l!WCsVK8o zBT;Ya9n3y44rUSj`e7_91N-9_wU@Qa?zm9`?UXqa;jG*(g_TCbZB#zZ3pp=nC6>g!2R|K`6Jb&j4)hS%5i=wOt6 zDhb@@8^~DMuHf$Ta|80HRt(@`zq%-(uh`U@i{sWXc-DL27No^3zy>|6)N;i2Xug_@ zT~3hPYDy$k--vo7P8}N+1Ld1Wa-6f1M7QeBPG#R&S$Lwv%NlYcqYg)X$M5c3EY*?x z*9J`kKI4y%C}aL;z>v=R)fl6EkY(o9Uy|I~&H^ByPW2QlXBWeE^Fw8l!tlB)SB-xO z8g={^JZ~-UM@`csdW+pteTgnTEuM38doBsX0pDmb{>nudsu!Q_y8kE?w7%v8O>6RB#Dj7#XQQ-He-M6;uSiX-ehSd^ z1Ur5+TF77HnxCE0m|K^IY|BNq)Kc8rq@h!r4DKFP(-5tW--9wr>F#T3j-0s+LB($o zJ<}#~QJ?b%(#)IJlOb6&g?jX=Az+&!WsqjJ>Ocr7*$Yrw9X5p;dVD)lO#>)(MUcdEx z{Ii(jMMqp~{p~FQyH38(tKa$wm>#lwl`-UZ&b4VPIO_55nCjT}INBO5Uj@VPyF7Yn zyW;#H=`r0Cal<}iu3;wOJ)=?iFvMNEz81>U@>XP~b(O2DYm*_`jabRw$MV-i*8XKF zOdQIYX#3+zB7~poh1nd7iZdYb*UU5|A6`e*n9h_WChxW*#+6)ck!jAJh%e1`X_8Yt zi)^RGUXCbHzD|JBy!9rW_O=e_%`ZblesK=~Q?lEmg_6JNR1k1Zqi(5}7mL4Z3@578 zRuh(T_43Rj)<}Y)(f`<~aO^#ADCaV*ZTktL%R$~BeC@=Y%^X+M+llPXr-0jf5(@`CWGNA%{yjSw zo<~0NMY;gnRXR33Ky`i9*f5lN+M42Jy0sI?oz8Joo0bzUhXRNO{dv1hc53$qG%zds zBURsdhbIiH!D0Z?%K1Q}-g1^+(LISy<5?(`BSqHOo0%)ZQEB{iz&4h|0g!PwdKC=X z57(h#z+96_$PUJ3rjf2jyp-#s}9<+ve| znQ7g4o$q!W{Io+ACHiLNd?Req5g(f_!^G}09ZqmHDFH-H+keS6rldIG9V3I8dkmJy z=K$ljDGDC6@P?JY%tp?AD}s)CoNuZ;#qZfo%jrFfIlif%X?Ns(vmQ2?&IaUdRo%{j z$9AbUH)S=cIjAi_skuW<&hr-Z;B~MfsjV$^!8D`O8S&}pzy)?kObrlHd#3M)%S?|& z>^D@EF3O3!#H}%-G*1LhM-i+Z$Qi>N5z4ta+yzIQH3xGvX3hw)JEAS1(jLquYz=cy z0BT)O0LJ>}L!DFCq`=&Ka5IUnJ41j_%MMtB(0*HhR*RcV)*72s)UeLv53@U7zKyW+ z0G9}OR`3LTqxS!REyjJBo~+H28P>db9iV+o+;onQ!azXlE`R8zxyUoPe(%rPaA;iw zmU^*0V4^(wn~=~NG+c}#_SS+@@@AA(l3hrJ{z1b2`Y`HyxO^4R7u}~08+Z06*tn_H zk&3wZ!8Y1!{>9AUiPsYlx;fezWg7M*fXtU(MB1w90A^PEBM_~hmy}{~thvO=vZ36s z)H>HBWwZ|jhw`!zExOj6YJTr3C@H~N0I9kfm|=7sx1D>!(lF$gYJec4(G3vSdW<>< z_wA4NLB6iEq;;>e;G>+p;%;NR?6uHa@%3ppYr6uodT!TjXetCz;gojG*K$5!D}1aY zlQnQqcc6iBeWV9RYP+Up5UNYoYzjrm7jPtJ$t1%K<^ z_6?}qwu?J_#$Bj2us|>E2<2xs&6LXASK^AJBd7t4<&XN@$aRP5~3bA zW-!6$5mBk$i3L)lwuYYkR}`+Y4!O}sd-buWolg(N2tVUuX`ogT(DfpVz^3ujw|!PC_%R=Wv&{t?6g}K$CC)GME2tNsoz$(-Fb@_^kzG==zE@J4vw`gmcs0hvy*J3 z{sMv6!{p)Q=wc_R-wu%A4}Jq&YO&^oxwepf;l3%KR9B8queRi0*?iZa-Ul1HYh6CC zgS=NCL>sHV0;&0E25wOt;W$bQeoSs?pIZT@+PLx_+6Ok~)@1fg1UuzoU=SSI)0A-YmKhr!3+1QMiKL^6?^DDGfR=gzRjgrFZZ={H>H9$MeA$Vz#N3!qxw&cv(M z?mE6#ANjybzw{x3M~0z`V7q@&1jlkSA`!YW4=O2H_XriE%-d+XzF$eZu_bss?R&*~ z-RCnwXl2E^p|F-bovTa=wDD1Xlz4NPDYY~CaXRfqa{dLgpPz_5afn_@sakkndBjfr z-}GrK9(8p1OSGy}uV(Opzb}&X7T4BdL9IqScP3Jz*{tfrZad#6x6Op%r|+1jr52k_ zdr)l;gk~{SuLId_pE6f9LuazcU0{`@(%g4qjX#QT1oBNB262X(2VU_VnR3`1fpl4cnLTI0VAod*QNx)I= zlRN9H{@9NNuB!y>X)@;EkZirZJ`(jM2JtJWYsfjTz$5-5t_jATgS*JmQEpWNxK zUE^Yr;LUVn$GA@WAlX)XHv5Xm_id%tAn`-=KOxXr%K_4;`40hM?HC-+)$9#`ubrzv zxG4=wc-b6(+Yw>@Z!XcI7Miph`A-{5!mP;6jY0pVXdG8P+;omrpN@k~j#%d(d12I?%Yt4LZoAA3&UWFvLOWX2uHPlf zPcI?(%#^iYtN6*kZmCI~;%F&37;ucrB(Tjd9n|>Nu4n^3E_cPt=9%pUtFvgUSIf@jHb5<>spm4c`(&6rB>X~ovk;yE}4F>x-~W@>GK zb>0Qu!dIzbSaU*=Bw9Dxo#PXCY}I_n6InjlM1g*<4&kqy%}IsW&x}xdq>HfmUgCvO zvMfQpHAvDb?_?N$O56&Q3GVX|KU?MrTiM0ILG4)^&kY<%Jg9*KA<^H(Re`N3k0HvY z)7<3M=ER@*&&8E;ajzFW2h9O1t=?M#NA2o`Th)SX1*@v{(a7?8hNAj|CSa&;_xGaZ zZT3DsIqgFu^W`$^w0ix4KlS4wkubZ=uq-Q@I?&Z97Pc6gb~DLYWko7}*1Ww*5Pj+6 zu6Dk2Z6(x=%3nR8(HDnszNUOKir7Ln*}1(W68!oIrqMavyY!;D0Lw4GDc>^*VB@7c zD;l#;ZKq~S$yNS0AMVQdMo3kYw=WQ>m*J&+JWY#MEHjo)$IDVvjB(=)TB?r%8{?OD z2keYV`AfvsNF)NS8dkjB!Lo51L+=B9Aa6MdHH@#-(^=jS!NZncg8+UH+ja^;rF~#- z{8?NWI*J2<`rF)e&W}IY!ugo9K%@SBQ)s47Mqjh@bkfKCRmWRu*-?{FFQ_FUtzUah zm^}JHNNTaWc{7Moq?UxV@uO#x7sQ5E^Q9jxmjf_EJ1xXj>u1&Pz>PLX>mvu~-nsyqDFd!^(HNie8ROayXZkPiO)MxgWj+8~&j6w|RAvYm zRg2PYHkaF}dMi4P<3ATTS6U}vr=~f>NBzZmm$ow*zDx-EYrBC&6f<)aH>&w>6w+_Q_$NoSXu6`u4G}re4s;>`00sX`=-e|TA z2W_ooJZ@E5AKJ~R`TyeVj)O1I)6A@ZR$6RU222Xw<)))dPY&fN%ZJHLccw3*wd9sq zHYSjD6I!=qac>cBWlTO_9%g5kraviqW{ISoTrHlJf@=TMMUyDm&Q9rGK$7uhY$(01 zzZRfZ*T7gaaT`V`QA4DrcE}q*-v-W67=8B`uG2dY030PDnQEzwAI!P_BM+rVANP@u zl1uYZxz3kKW5Kh0)Un1+B5BOmZzJhmalkG+gOHK5>m$9nljwJ{r67Ih3zTE<1_I2? zJcaI>|16?P8CQxTVZ}T`BkKDGI=O}dwBcHO5!+&>Q8~5ky}76lDxLxP>?6#00q1%kn~TMgu-Nre6~|pefPkXWwFW(?y`k0ug4yQ$$+zTG=9B^ zRqBAmKrBqpfSirKKuUL($scB{AJ~~aCo{!${~vTUp4~}8m-Dp_)Ah%GRM*n;1CI7w zzA9J`W&^Aq90>y@VgmLm8Rt=^lzcli?dO3<$-9^#yVmm6#JC{y49wwoFjRTcasop4 z58upr%FIlz_J{*$?c8K>-i?N&iurUJwrh?5ll-t|z|44>bC2%3i8^3Z_QfUFMvuba zT{(Nt-**$;+lA@|9>8w*Kcp2!QecQ8|BZyQoVL&IGry2 z4KwTODT2{h?YoLVxgnBT)dgGi_Fth8o-RO(x#rOf`!_B64&=*B7vP+ox-+igQ%>z$%VH?s|C;X>5$Y#p$P1xM+n(5UI-JAEcI5g?ZGDP6r~OSUD?@ z=H4!%dqvr2)GFOpvaCP@0zg*}6R*ZHwoP$tkmb1gl5idQx3Wknz0+clv5J=m8ST^J zR0z)`LZgn#BqX#qbHGrKa3v=iPhN_QBNtFWtJXD~=J$V!0p%kkd6vzkgqpj*Y^Q7G zjC~m6dWh)N-*&<Ei(}PzzH$$`ATo?+=&g>Z>x~{RvU!kx z=wIMgBU4Bky}*S;WcwGyMP}ew092h9rqQe4TuGSVOyJUjo#sK4wP-B#`SaGcJBsgI z#mCn(1f?Fn)f2vph%?&6 z1%r^wHo<$%(6zR2)|C4T;jr-@;cJzjzRu>*WfGT}o3}F-1AGag>%t5|R`HcrI&Jy3 ziCmqX=n1o2NAR_^r6Z=9zg&=B19B#DD*phPI(rRIrW0zy*Zi#*MPDB-uWU-!zeJnv z^2JmAo=qq1*9oxEw#-k3<&|1e9H#4w&~HSv;`boPYrhq%&Ry8c{zXnb;nhzzM~LtgmzMRUqqVx~E)D9UnKJAWCR)4sBI zJ35EpY->wzL3G#xm|MSGAQ6=J%5a4YQ^^&Mmj@29v0YgY%82^2^GIwdlJgC!KCcO^i&j^2T%VN$ z-?Tu|M*lJ~hvyWJt6&0Y7U?}$sQXs?ncIz63CFDtmJuy1(|XK9Up z@WAce9wYT^50X;9Sw#SDbW*~y$$uQp=Cc9bI2@5k%c%#e5$n-qDaWSyLDdM1C3MYo zyn{J9vNIwdX!l{O`Nbd!jC5bo;DCHVS1a&_$~3G*x|%n0Zm*&L_@hCe8hF<@cqy3n zhwQH4Sh-I^-`hl<_5OjFd}}lpjb^8jt^btWJ=C$I2q5!9UIglCEp^!3GQ{NDCe_bs z?t}_fX}L|9c>|^b&fQChGJdTkR^8Z3X8u`3Jgo+~vPYvI7Hj*jFJX(czk$F?9V|EP zY#$WRwoS$#wRVNtn12^V)+sa7Md^Rbp_dZ94Od##_a}4gea6M^=wuMT>PmLKX1dR} zR0v1PELnYFG9+q)i}7&3wr(k^R5<6wv4MO!Q*6I%Vm?*Q$j5W}9~t9n7k?O3Os9CL zfxYOeZB@{~d?0`Dqzv3c*ehp`?}28+5-imQe}V{z5)gYb9<;#Gh(3n)7z@ z@MosXgHr8N*@GLiQ#Ly3{VAbphulXXDcbG;j58{MiBTa@qrJjT>Ga=6azlIV>yF+l z&n0p-;}$lkw(Ve}|1I0kSW`mruK9C%ChW_uMu^eza5(2(<^L@8a_fUQ|C#d+Jnr|+ z$cl6)PSv_jnOw~+AG7q$!t zq%CNgy>gzZ_dG=}!@qVC8l?;Y0(IZ!EcB|A5Qa%NX0AYu9}Zwrixwe-^t(X^IF2ou z&hgIE03diejR-JX_2Dh@y$8&!g$Y#QmD9Rv_-zhP?NN;aq<~$`L{0ru`vK z=~VV8$MO+0>(8f7M~lCM=FzFyv~W9}h$}~*(SV~ri#&<2h?Pm~5Lsg(6yuhXH^z#S zq`y9<@(Rvhx5Qz_qZ7QiR^CJPzPJYXwSE`2pr3Kfjt$|zF=wi`&n)f|t$>!*rzcRS zL1%8_=G#qti>eZ|99^&8+E14o^8awkp{^*ROqW-G!`D}Q>y-1j`TW@`7*@^%VDtKv zVA@-(S7e{n_?q!Wb=O0 zslOEbV&O!~+qZ%A87mvMo1gAc&8^-=1?wsYAh)_V#kc12OIWThIuwFpp6@qf&4LzN zk`y&fx4 zld)7Edk)nNzh{`Cz0wF*v(_8D@P(rgPPG=0@6mN=wS6pFU)BGf=4pQdoVf5GPjN8e1do9-PShp#g0g>>% z{LZanx)Gl9_UQeFvtvcH&GFFOI zf5SMAXO%*=(`kwOm66CQE2i@-_hJsb+MH!jCApCs8jU&cjfkc%!C6aKE^+unc04fh zzt84)_7-ZG9#V{S_tznG%|C(6ul*yHP8CaVG=ClIM5j1;!?zaK*X?}Ut>c1@TV#7i z%YH{9sMbs1u;v4m<5IskNLqdc8Ef@oZ>IFVB{2DNhv$4N(p`&d11lw%wT6y$@?2px zDivYlYk3svYRwnnC^c$NFzplLNd0l0L(%PjZHQ}Q*A%>9?F_)T+Sm)kh8`s^!FpIO zW?R4du#cY8Wyr~_x)c(&aN|z$n~V}@SK`o0Z?KDo(F^>!wsi^3M&r+OQP!mlBS}Zc zE~lY^e0JB;+Yz_M%rO|K9aw=JW&9{w%<*R^g}d(JC#zx{z^NS~=%hPE5Ri(Gm)J5} z=6tH}`$41qwVOxT&r8HXF-9UBbM~jv3s%_5RMsXqM49#(J=Ly<216b51g~n7E=i`B z_-h(`M^r``WBD>NQZ4Z^jFvAo4?}aWor;YmVnS`a2zRBND5X-u(cn@L_2I_fNi;Wp z4F2k$>?Gj0T9f|D?`zQ1Y%5>BtuH$zCLfe1v6W>L7@^77&*b~sjrSwX`#OqKMRiRM<6$LF3LEAY;jN-$SHL!owqFXPYMq8-r@DabQ$IJyPv+tu zbktl*iJ?QQ(_Pd37h}Zg`7w6x`*+D-GxBBzlpEIXpjYD-_(*v-7yz_{2k}sbwV>T_ zUL+y5Zar1fNL;K#-{A_LF-G)}3iS5U2CiQI8}QWLLqJ(OylfHeE!0WSjNVGS-mw%C zjhF@SG28pEvGEvH2D#P~`9z}c9goiDglG?rC*!Cg#+^gZn_)*&xSBVVUdsAiX|%g% zVTl!&3B#Y)^{Jd5;!7Z6)D=NE^P`!^W)Ub1*Pc{te>l z-ErVytx4LzRp*-c!TM`_H0`Q0xoi~i4nw7Z`RS{yTd)fL_l61vW#Y;10y2X)N_=r2nKuxU=Nz1ZC3Zz4p$IurZ#u*boW%vjE2 z#Lv69OZzRHK6+}?2=pEQ!;7idhw-tp><(qc$mmaj>Xy12Ju600opt{&Xlo2EEw|(v za?@owDwe9{yHHEC2{quN*EyGAcbqvY#ub-Q8vWg{|b)uMeUCQEv4W`2TA^)!)9<&@@ zIu6m<+$5CQT z$7BeV;oAXITfAN(b*ubixG_OC*s?U4uc7^ORc;^!2OL1Q+i;LIF1!e)uWOA&jz!9V zxG_JLh*9oDNLGfN3gy_*RSfL>nNjLy7bKse^5Rc(jQru4)-h-Q!lJR18LdEUJktVN zuHd36I~QBIN|Rew>;@^ha}R=wIr~I7GL{yEjpddPUCo|B;-=)$AYmBHaA0Vu6xn8_ zMG&)AQW`+3-KS@A-uwoJTYi_&+g!DQTH3zMTrSSKE&(x8UZc!v#Zgs#wiPJMGIK}q zajTZZ(v`*1?9zTM7#ye*!o}}r_Sx9XUe+8NRsR)$@~wsJ!4bQS`Cx0dVNLzH``K(KT@vL&C&`@rxd7YDIupqGkyv!ms)k~W(keep ztb%)V+AD@OWYX@V9W<0UE}lqj9>H;*?6RU(8OS5-hbfV~mEED9=$^VS2K^RIEz+(o zqPv>A)gs#aE#W!MSYe`CE+>KXtiOa(-O|YrddRK`R+A9|e%FRLLc6n#`;Aq!`vN-) z8>=25I;$OmOO1S?Fu3!P8%?EY66Ys(1B+UAf*;4WGF-0RX}tlGvmdDlCuN|^^5}Mm zixpoJB}&ppkTW07#dPID9{go|HxJq!Ypzk^5`zg}<%nx0|5{cj73ou4MDa0giD9+X z7V=-)UN9b#?y@G$^4&0p?xh}bt_5ZwLLYoO!_EuegO${HCxdO0HYOsh;WBp{B|4o9 zwerepJ*)mPZd_XWk7XP`R$6aoVuq}JFfzIUpp`xyEX@09YvFY$504b%mxHr1^_UlT ziX+gOPs>P%IeK_PQEWAVY33P2Wa~b6g>PsYfu=opM2q6*JkZ7)as5D!{o6#aYGR3j zGD@~&)uB~F9#j-utQ*xZz^vr9mvgU|0I2ru5C+R-K3ROCks0yYp50!^-m|nUm{co@ zrCK##LQj7@3YJ!5|HH^Dzi1+wd6oBs{a`m3o2|+$usPz6hd^F+f`HmURwI~O=1}#l zMT^2<86*!WYFLSrFdMgHqwTv48|fSN!`7S>c8p_`{I8H{ey1jx1#hOq{OX1i^ckA7 z2+|t#rkCQ$mXSPK6?W&m!=_bm{LPO7U30WAB$KNirc&Z3mT3t#MmirPd(v!~9ss;h5uit4?)iq`EIZ3Mz&6;9O4MZD=)XExDk*fmJB zv*iF-aopQwceI-o2z3GfRq%5CbcFNU@~=Efn@c%q;3vlkmtr`^7ZlA~#`wWNKP}ik z2s((=3yG38_1cQLEn5jJwi4iJ3@MHf!!--7)pJbd`=)N%%S+|XZxk7QawO?#mAU4F z!1EtLQ5{#f2134+LsxB!R~B8B5v0R;Y6^4w15!A~$mD~lHyEt;{RQUMZ%N#04Zmrk zaNBbG;G6m>oSqHiLr`qQe#zkl*N6yhbIxD%)=0(>J+WV~ohh4j{6r<$8(w#K8+JC> z$tUJ(vINLHx{hSqpo@19=C9n}gZoKa+-6wE;qTWhao;lf~EAc++9?K*#LfcABfs5UiR^ zC6cUHUV9*S%#}R(CtoDT76v(M?K>XCao%ES4=HvW%9iqJKsme=qfF)U2^-^$;KW<$ z(W7ht`zOp4bEG?ro4YMTZKGQvUV&M>-t#~*~BesbPc_*gx?IC^)d#5UN3$?Dm7 za>+b721U%xuQTZMPelnu-A(eidG1B1Q~U`>Yvh6%bnU%$E9{5QT8Hpc=eb4bZO)Pf z>fWM)Xs9I^-;&WR&A1Q@&6N@0|wHmRLz$3KR3PD^ItL ze$rdnULP&Ae}7A6hVaW!RPjr2g5s}+o`_jdGYpbre-J_X;6^yas4xwC4X<5}oz0}tm1H=mZatQC_ld!vV z3xKVcGAL*`A2(+3z+HB`5{h`g!caRPIt=@S#R~uHr-->o{ zBf7565Xw`soJpxRimWrI9^+^f_VZC~=W5Xl#N268oR5W1Kpi?|^F zZK*V9qJL0qG`E5N*pyHwm6lN13sk-MlKAJYW9Mb2IS?rGhEL<-XKP98ZPESdSF4}s?GcVI$pZ0+oqCeV+HKr@;^&D;o1>lYMFhfh- zzLbB?;Um1`(_U^N*7p`LG4g#1v$L|Xu(;YJrC4-j`Ui3WrG4e=p9<&8gOM@#6U?yJJysfSvEe&){Nib|$~gU5B`6`X?^5 zI~G6N4#Qb94%r>sQbp&yh4E!#RlZQX3=yRYy$OO=Exgk1FjoM!a^xjpZ!PIUQr7uv z1)SZ!Z$N`b3>_w5u&rua)abh;q*W~=-cqt>V+s92MapuN@lLnzw6>0-QcgwkTya zE#r0@`tGL7>#L!7!bE}^6_Uivo93JaV#iK!1=w-3Tm zKXA6;6Ajqf&_AVX=~-gd&qy)~#c?FGsiTjs~nCwLRm)Ueg5oV$+5v=ht2fkKZCIs})RGI3RD zF+g|~ns&Ie7~P5Z2l zo^V^g&zpI>QX$ndDL!m>w^4r`J1xq7P#-5CYcXpv* zS0{XJ%$7~P%`YWRp@R1XSNd+QdY=Kj1*w3l}dho+7piPJkDcMD@nMZ#jy57DylE66Rc zP2rrkdlYDMEdQ7I^}X#3^P5lcv)=3kapJZF1+Ye z&&%MswmP0`5yMFtqflHh6#CX3FzmDhYUB2A*kBF0v4@tW#VP()pal8N$<@z0AHY$;_t{(Y} zP3od@yxFZg>JInQlTp|_b-6tx6$TNZYTz~<28*+ZVr7dNN=x}Q6cg)n5+SGGTEeus z^0H%vI;7%$7*vbrE}-=IPG*}cYXPVA_p4A`^ZU_Ne3qIe)gi;agMSZkTSA{rjI236 zMUyA`oQvX}ax+{Y4#=78ou@r2TE5E?@kUk^&@g+YuYvMzUm`=j@E!>DUGI-#{IyG% zp_k}N99lISGjpr$sg1CS92tQb8&%#XyTpR2(d>vpLvP`(Jvo32RoAAduJuh5*v zfWOfq_Aq@*v?CbI-)F!o*AdsL0^;L|dbIUTJ> zuHjmxeIRJ=%SA!ZrVjvR<5NF7npa&eG23ER5bKL_{>|F6Eewr8*8x@^ScrJkKgwcW zt4SW@>;4{qWKAh0kl2cmbIO#Qe`4vC7b}$hQJAHlHG^R}Odds*=NtSve=}(Ys%~2V zPo@4Ez*Dj+N80(`5vZeDv3x{}7CT3R*|jd^MR)JC*~Y&L4TFzaaU{qXsnfWs>+OWY z>j!vLb!~|zX2XBOY024V+z1aLrj65M_P`;JQ!3`R7!XTKlpjFp9X2^}+&XEwja$Gx zfYLAhf$3WRt(|FayNf3iyEDF2ySWpvO4&*hUssC+a$Nlo?38((31Ox2Sc!wG^;4ic z>b?N8Zsa23thxs>5Evz+IO<*t-zyUiPvLt+6H>!!vgia6ufoL`wlC4n7qD`~i}JiU ziK_1`kE;4HeHk2UzaWB?w0xP+l<7Uk<_Kzzrbb0sk)b*d6~e){|3d4$#>P+$QLwU0|#wJz9sVgBp^+=3u9TC_E!!~#{3adulvNuTn4F~*4g4E|P#U@5n!3+32a#E57hvwQ7aZE}AMNf&n&n;f>(v>P^J|7JV%EN<`q5r!JDWJ4zL4N3G z&JhDt-Ne>jLl(Ey&tIj4iNiIdMD3`tLa1N==^` zN$eKwkxbW{|45=bZmqPjz^XNjm6yej!?@5zVNi6dxN1+~<2J{{-ehI)o2@qXK)%bv zsH~L1$&x7px31Y&0-hxVD%wLGz>e}bH&OH7LF15BaMRz?WIT**zSct>b zi`OI~+w_#!cP(#nwZFq3O}}3NA*<^ybk|(JfQR;R2pkl@l`+u2y#i0|B!3j>=(m^gc^okkj zw78c8J>4@u@n&?$3(VT2I-B7TRKJgnkGqpja`kKTY&7}IbYIq;RTJcwUg2ntpOyuO zT{6>GS#k+bv|eH8p#7ZcO|Rku2x`st`$mqZ{dJ~??EoMxVx|wmgM5xK87p@Nr!PN> z52nn>gx8PKi9j@V78Tw6<-Nc)WD`$+|FlK{YecfRV1396o5O9_VkjC_CX`gqO+o15 z)x`;!mYXl_PwJ5g)`?M(@SWKw9<9d|Cr`}&o3L1|d@%;f61KHmjjznpi1N=aFJv2s zz|y#%P23w*{h?7y#Dj|RqWvbgZC*43JHD2s7O5XM^I+!^gm>%hrLO6XA0f#oIviA$ z+i{8XZ(I!|m0wsh$bD;K0Oz0Yx^Q*uV;inG%{GA6t2HQ)`W-25{*8{-)i06-gXuj^o*|Ja=;~+PSrL=c;|z zB(DCio+(1Z)`BjJ+QV*2KyU1t z$neWsnytPc4Vy!`8-cn}W%tmhSP9+$%gMf8#!4o2IEwtAqqB~yBKrck-MX&bj%(}M zop02&yIaQ&EJSQ{5CH=bq(lV=q%1%Mk@Ah*-92`%^;1`U>hF8_=YHV8pUE7mJ{!T|Ys5=osPL zejeBr<3R+MAeJZktP*1a!Tb9=D~bIzxUl{$9|JEVd*D?1oUcis>iCuyqPo#%15bw( zhj(k-0XOPRWN}P&=3fmR2VWwL8O8}bX8-zUQGI}lOwa-I9V@&OgQmi_OqzL6{1#GCr)<+$>vwXjruiM1%E%9Iv4T1GAi<#}+ z9J^!eB-Cjw`hxdpvBOZCvFcqi^;`Q8L_6;y@3{w~mhpAujeb?nhV<0BHxEY2j=rL@ zu1ClT>ar*Ed3ryb7*i@OKr-__H}mny8!zU5FaH>598BZuzO&qkto0tYl`Y;Ic2XVh zw30Gm+G;RfennjA)5b)?#=0})JL`BECSNOasUlO!Hj;;t+9{5DpA&So?k-qK%c4iT zPMkh00?UkXiD0Sy#{_sOKb{uz^(&m+8qQqJ4=r1G1l;Ae$WUq%nG3Nt|H49ArxSCL zV48(ylwwcBjZetl7xMx~>m5a!KwBv*OSalF5B$e)Yr2Trzh%o&o4#MrPgUZ zEguh{^6V$Y{0(E0Y(MmFC-E@dJp+3hGrYFZ^|73_v@+VFX6uJ6XKS|}N~nzeJA&_D zJp`tU$dV^TF|kr)OZ-}GHZ`56?pgn#s+Z{x28TNg8VkCCSqo>O zmFp<-VJ-d6H=IuG`iCFALKi?wZ8(ouG1`5Tm&d}am z?--Hc{a10BArF^=_s1n*+FyW>{+1Gc}Qs6#w8 zCYHwe)%ni`@wDnWo?4B5!mIx4x46oq=BU@KdRDZi%YQ;BP7dI;%~@;uP9NdH_$l+% z#@icE(Hlq}(5Lvs!{#1wjDHGGMW}jS+hMbO3zCr*-WK%Ar#e{J+jb*a9pFsYtF@CkNj(cDjiLENZI1j|2U6=7 zO9V^YIW(ys9F|P|UN9-tqZUhnG4ijAM*T_PQ<4IqqvZ<_9cJ(31-04PMSJqg8V;w*m78Q=y-{2EPlGWEw1jA$m^bO*!mI;%LJ@b^RzY)wc4yl(eBloMxeK?faNKxWmii7ky47a*c^ zI}}3KRb5cI@=m5jjrpU9IK99NY^*4)JZKsDx)myh2wMdM&( zy+&+WzHR{^(B1uP%*p%%gXXyee8Mc+ny=~O?NF{(@|HxX-i8dKm2K$Hf18(pVe7Tr zZm*~PMXI&V$bX1h=T-{241b)*T+RoVlucBK4=G@jLC|ZlZYQ!3BUg zr!Y`-_C-A9=oxX_d&_`OpN$HI+=(Gufv!10aE0F?As97sLPPseR-A8m26*)j+~xJd zaJ`7K%)(0$Tdm}d*{$v}4X5nOy2<2CRS%vX569=UOB)cO@Nve?mq*V6&MpIKmFJdF`g_Re|-t(9Z?T8|2FW1i0whz$SS zCdl;Z?UI4-Sk3_Puaz-&l#(PI*ZnfZ&gkqq99z}pZ*i?M6_da=IdlMcT#nC%Zm< z*cbd9aHUHA6@cuK|LZdRitt)9^0X$+=ghqavRYw=KQc7?j_%csZPC5a#wiFQ z7fhrzs@zHfX3zA4Xy;(RG&VtP7j9zb;!oBc2S*NiD=f(Uj&oZf0iG3%g*%WVKfUQtR%XafY<$qHIy}t(`ldG z6C%1_eHmtTg(Wkat7xv=ncaYYx&Q*@y&UJV63_eFNmVn52IWOp;ptho0Gp#g27#fw z-Jz>m$X^`#`khTSN6H0;GurG?xQ2Oi2>dFJ5;MVAC=SNddh>n271T0-`X3cQU^bFD zGwo6U`Zt$%I{-_$`ppOB%N2fg`2a2D0oj!@c=Qv1QV zYCo}QgdI3&a}1i70-6I^pPRojY1VQ!AfEWE9Xc7l%O=8F_Hu$?em^W_R;wU&TbES` zd)HT3CLL41k)K851NY!VYvD-@t2ZygpHj6OUo-D3Z?rjXwSgDCT=h6E%$3uv`n=kR zt(>@lOX*MlL^JyJ1~YAB%?Ydnl#fA=rt3NMs1;gez{Il!e9JtkH_FcZ#&da36qF56 zTHZ3?GLmdqN!`4J{A`@)E!b1b;4@k#({GOIDoNBBvsg&1uj|c6(_k3X^EQ#Vj1OR% za{*TuaA+R`>isJ0hpVVGdaEayPjFlu1a;#}JnItC(b8kJp2D+QvZ!Ju-y2V#Sr;H+ zhMdRT%DaSA;jjZA`-e}ka+YU_C-}xaJ7YhE*?r|Y~L6= zw`T3)`!};IYPRy0wNoy8j+wZIgpe>FYdfhQa)y-kS2dkZU2jHn{Z!cv2+#)~)K5PN z0q(1~lXYS#@~V6GI>ThS+-SgBR1X(Ye3BQU*TT^Vrk+?H49x$=A)a3LTr$08l(y5- zFl8`;6c3Mwz57$)!2H&Q2r!PmW%1GV7Yvv=foWXX!Oz!Uh(XU(nTRmi1@m8U5x%du%B(zIE^lj$k}X z38dxHPwH0xjT%G_4-z78Ws+UD>wdKSIfCKlPJcj@3>}fJ$&q5*z@Ln@at}viW{cFR zFi_(MPHJ_SI)N5XH?U|WuSe0|;RBLcE$U0T`{5ciu{Ibq#u%CWHD{)SLH|5{DUic| zgIL>@^_QeCb1}G3S2_p<Ec74~w&*U5a&{}gc7|eYN(91k~3J%SMqo8FZ*TaYD$kb_Nk;3M%=s?L zTDMlB$=J#S5!&q1U@TY$?&W);a4HO`dAdq$pODZpqxOo{oHi$;kpY=Uz;%BOF{oCn zO1p7ZhWu6oxspS9noTloM1YJK_P^n&Ry`SI7~V<-EeZbU&KT(=#=G|^8u$(Of>71+ zc3$jCsW=-_uijjHlnI(AP8!-#vE$T2=SIU74+)PWf`<=--qG!UGnj2mT8Tc zmR)W@w2W5}u||G^DRW@oLtJqY4QEBT><`E%Xf90lnwQ?}Z9pQ?)wL&%Q zlpl+dF0HA3p{ur7z7b51PT?iyEB|=Pssm{^hpk$Mpnk=V0Dr>92ksdKyO=|4grXY$ zYZwogY*>q+Pb*1arz?o7WTuBgYDx)z5KPJ>4;w?=#m^e*IF#|f^ug3aJ0#HSi^JQ_ zgmE3*S3S3oSDI^1(C}x4;uM$vJ`T!JM*!4Aw&2xT(PsN;ujDt??(iGu4j%(w9soA=;=e7sVob7 z+OPHzfV5i)xU%Z&I1r5ah45PCUwEZ@<7f~H%HMQ15`3>bg{P+q;Fa3Du8`IA3B-x= zx+YUXJ-dio^y}RLFY4PEdm2GK@V;@&8DbbeWjWDGc_5a#yD*48pR#V^S-N`x7(=h% ziu$}+aG;$Z$PHSx3!nq*!g~T$tHKDB4X|>|O^uz-{*gsnP}ngK+|Nk*Nok$u?qSE0 z?(Sfn@<2z>*Tvx9Jn_~aB*V7s0c1qsXefMaw8zd)o2&yvzN4dnS1OFLbJypc-SnC{ zQ4ASf`Y7$wx4YZ9$J3j3y+nfy7${wdkxiTI%i5|x zw$Sot&J{LpQZh)(LwllXv+pv}kXovf2vsf?^y-dO6L6nEhMTK$u<6D2X&s`PWw!F{ zs)@x_9~HHmZ}TS5zHm3>wD0q&>t$qOLYq^KHOnhSL|67W1WQ(XXpU30Sz{8u^K(|5!`t`JMXx28y!_n`V2xIn_ zWi;c@#{N9Lo`DLC;Bi<^`;QY#juPLAD}Bjyx?1&1OJaX@aswc9YT||J0Z%y9{oLW* zcz%Z2{4dLJpGR3Q**I5uHohXBudI~4M%whOQDMP0c%@bA&1M_h%eX7e@$E<)2ropX z0J2GPsoF6TCsKP9oDX2%v?Kt}JQWYgFLm|i1z_~RCCJNBI#gmL7F>!>-44^P)#{Jo z^fP}_zN!7z5{{8V7x9gU}N?%xMsXVe1>XEyKT35NYMgw5a2$%)pWcWJbbW#b{c z>*8Qp_qO3*x<@~G7oS&yn6Hcspt`-G8_mVy57Si>O&A9^?uB^A8924R`w?B$1*Bsl z(KngW?^ueRRhdc>P%Rg_!p^@NGa=P&FMZ8j-zl}w59ASj`_d)U6Eql9N|c9+c||t0 z>T7NL>09TU`0SCxybF}Q?f7KabtA~mCM3CX&Zr{a<@$**h7d-%5XO<3{?Wi3EQ@cO{ky@8dY8j^OmxVt^=7+8gaSum@j3J3YHXrZbVh&b=3o{z z%k3unO{g`T-%0tPVGUSCf4wq$r5zhiz_e+XOMcCVuOO`t+UJ8X*GEr*fuWZIAr$c6 zD%uyzW-p`CzvA3GLQ8|JeJR9N!n1Oar|b*YUuA{*-K^D_$9JO9>iVS^-@4rdN3fDR zB97j12QSz+2SBDikjqSrYb_w6_q&d=wdBQK@a`QJO8sRwUOraXRmIZ4Ikn0#Sg@vL3WnOX5W;9PzXzCGO{YcMS%H1))4srg-q2Y>aLW~Jp#;mc zwpHCuG^j62pg#TN98{)rh!1&kdkOJ(vS;MQL@xk)|A?^jKKoxf7_S!#rhFRD``!FK z)|)bQbv#|)55)tD?n3AK zIS%-8A&1XySn~TN9^`jr2c2>R;91JGH<3Vkts|I>pt)EhkH5O(R{fCPH4Q#8O1$liLhrhYEJO0w-3O!_Pw~6 zsA(U>(VlGILHpMa=-lw0izAsgd-HlyyeiO3pSPU+Kjs9%Xl!qS=Jgzni6g6Y4!lV( z-%A59Xbm!%hr;Qk@T;o}qye%&Z!pWUdy=H#T%_G`rywKe z3Rx>gr&a}nY1J=c%e)v)s?a0L5z)#)!^h5=)%O*&tnWAl3In_2wgG!}JC~+?09@}q z1dCgaaTy>`Dxzh}S5^ts@SI+BD$IF?AIgDF_=$cYz#n7*E0QUjwS_NZ)_p`vv`Ir^&E+!_90eG!Lpw zNb>JDTLA13gDH&7j|h0}WIah}uDcjTo~aN(&u{UFuXPH=8?6=<_rufKAW_J&yDRvQ z^#>?asXd=)vr5YssC91CK^{Kr4SQBG4~fMIa*K}Mq%6p+fRhq)DaDc7+}|Bds6TqL zZOH8lPO6^H&scqE4l#N0$pZ1$PFFbcYJr)RzT9o)*m4%7>JNTGNLeL2Ev>MN5%e6> zc`*Wn%ObjRtTDLEIwi5cp>>Ib_vN?OK(xbJoYc6?xWnOcU1EFCvSa|Wv%SpWR*Ag% zd9M?{r`M*7IpSv!$R`(Oq@(9gfr$>O5?HggF+({j5Y$?wH{V_8vk1lx+}eR zLhGNAc&1YCR2nTGW&fUKJSA_dhlk^5R@43Q@V{ms{98U%h~P`j17RwpELluhze&{H zP`0^h-f|k%$Z-~R>vhBXLL})*2rbJd!-o3DRX&rH3dm!w-^9DN_E~JECiD?oHY<&} zjpOn3*PIu?fEngI71j;8)XivBIf-K`i4e7V#rGpN9*D=T8{uJhRE)q_x})L|#9!(U zLM^mp3J<&2mkdC4}he$yj&FI zXGi-X&yiVi$UWzmgarReM}5&Q%&dpUi~p@_3vKmuuN}bmDv}A}nnjC)VRK{9Ti>o? z60_NXM0S|C!IM5U18}Y44Y)BUo)>~^B6%&Cbqf0Nb<+`OtH(=9{o;@)uw3#L@G&{P z;iFvLm0+~hz$L7`3nl#&;+hv5Iq4YaAf z7*FU}YE#_E7{5IRP6K!D1=qK+Nj!bYfhNYYKZSRngVSIm_l-^94d?@mSzneV)RVFR zu8i@}>3e4zrQWD30~V!}e4(1JMjxUj?8iRJ*chUBa@}P3c(r{krBh8TVJ#|-cc=&C z@Q!l7GfFjzACConkQ~cYa~5H;-%ZxqwDN9fIoz8_GWv`Hi&Cc-&F0O0iLmtjf1yAx z%lZebi!p=1==qWtyt>0}9W+{8LE z3em+it1{Q}3^9N$xs*}4*n>eZsMXWtz5P()dpjr?QWUn`DK*1ncw{c*f+ ztR3QOhPebl>)#J}sp%&RcbacOcepAr#lz4vKFj2gnz)lH|fE|ZlAde%c}X3e7r!XHPV6XoXv^sOvE%qw17S`=Z8-mhR# zojDj%N_s0_yW{c24dCjw8;t7o+e_fdSMJ(VYX1)h)~XFfSmoxQyJ#O#48E;_mykqv zG)S_OLL2Oci22Eh@Y=DrMjey7i7;JCZ(zC3C0Q>rWNLG|yiI&`3=XZo0^Hm(l${NeLN8#BA+iMXwuv z<0q;a$rp&Wt0bmUZ=@lWGPXY4Yqq?DXu17S6mn^FJRA?rS^)`azJ?a>wTVEwR22AH z^1+~N`x~j$jDaC=wNloe)o)9;Q@;5y%jOt7QN~c)%M;$((idAmFuW-0G7^^H*;=lv zJLojtfGKVKm05NUvHrpdlx-6NK<62?2p`k7%K1%vW53Za!3`x0n*`4=!|t94-D zJ~_fo*)OM_Rp@QxdIP=Y5a5;OH8(Rgg5n& zs|=CtJeLyKLmZU1G05LG^`5U(1*Ud{Y-jBm&6#_8re6X z)^x@EmX^;64hl7#%hS~XxTJp2OQL9N{|JyBiXH{xmU|i6Y&JK*{Ohjb8^>ZLyeIW= z0dPtZIm_yQOT^4IM?&xCdi>SuTFMp9s#f!YxcS!2&evrvjA}UhBc_(SD2CT3Wv&Oq z4p&bwzgrOiJ9*s^Q#rQ@29@sdyTNITNU%9xnw}tAk}?urt@QN(j%X1Bn$j=DA9l#6 zrZqfKf@r|hMG$E_5_ZfurV$;jE)l?{(`OW|rM2D%;I94gfV_JQua^HF=ow=Rz>}HK zdL<}3ZpY-B|2-0lHhsFE5R3!8d8j;QFq5Aob7iG3f~fn}#L{(-EXeAgT%xGA>>=DV zx<z`QerW477I&@8SfTd3EqK`SjzG~kCF5|vW%oZ8Hp2_NAvvy zr8xN`qBFUWLthdrq1dr0l$7~9!DW>5f|6chm#{tbUwlz3wTLC9uEp_XtxASSc0C9X z^>!NAm7?{qh~7;m!nM@>M5S7;UIce|wMV9(w+J11A zaPa=>=uTBHo*RuT`8F}WDf`hMDYkD+qWQ!*BFAjHA8O_>FPKAI@`OIMy~tH&+;%X| zE`I=yPAy5Np415s(pnB%z|(?$l8su87M+B26CV47iK=p(@9yK^Ar+$&L_`ZdfKkm7w&iP5V) zacnG!k@l=VF4y{8hDoD|Yy~i0)IiJn0lBZrw4$M{H}^ylMnu+9XRF^Sh!%Atkd}X| zECj|3L*rEwgzE}Lv7Y(i!Y&XuoI=Xc@^Tj6k>l8EyW_e7Ipf_27Mv<4;CSkkI_psH z;r8g>`Z;1UU7Wg7Hy--)BCF4*lq2mJ(=g4FB55p_3*XacJtPv$uC=JEuAd^nU$HS* zwXJNBcIeR>)rqMYfZK-ZfV3YYhVdwjNi;{r49I^`ofGz6bq%($@xBL|GoMtChEhf$;VB^6h4wx#_JO@>OE!>x<x=rmz zS!b+BcA+==QzN$Rhv5S`#kYLZFo{;AILXtDtid8H46bR#xqA95%~b1$L2;Ykw) znv{_Q_4|-0$lQb+%0vg5MPH<#ezi=dR4Nk(Oz7g9Jnd#73&dKrHhESXJ-;ZRcT*ywmNDpUYk0&HF2o zYEfH+6Q3QTUVR`^DC4h&(EoelCSdA}C9KrJqZd&h84X9KCR6Bohp%GcXL35%x+P!T z`q2~HfXO9yKIn%-1Hto+n`|9lvu=nVn~71>3tuJDD>T8;8ayZYX}z*;7%CNohZqCK zM{}w1it&)>lvk`jya}k3XL3S8FDnPulx`y-tu}or%BXdEE1h~=!ylCSgJDu%`p;$< zxZD?&nkVA?X&HL}q4YSJ8ZoCm0>)Us99Gp)k{itnjgrBTUSN^k5jzZit?3ouNv~FU z8OK8{ub0I19fyhA zp1d0hQ&B%Lsa0Yn&{h$Pp@8YR3`HwWqu|GSQ!kw|<}RjIbM}O~WyWuTaz!VwXkGpVyD_t~H&~8;2F8lYvyZ1qza;WzqPIg_pZxQ|HM#HAZ)AF`af)#V^Y(i(?(v*z^x{VR1V z;$X_m7OUvgRjwx0R?lKHS-wk22)RQp>d->Qui<*SxnqHIDZ3L{+AU^a@Z?)8&%S>X zu{!!7x>`ccI%}2o5nq~b-$~HCVy-~tRhnn;C!RA8(C|4Uo`)xUp-jukH-)Y)N82Dp z=>y23mb!}l&8ay-qxYGKAL#}2^KQI4IS{t48998;cx%zNwkmbNBGo}b0AuMw|Q{ZJ5L5^+z!m3 z<#r7WXD-=^Ac|QD1F1R3pq?XV|qZZ%$Zgr@;I4xwHfDGroZt_x9O8Ziy%-wV># zb(xdW;x3SWl_jH*TPu0e4<@^%P6kcS9gtT47+`{+Ty@cQMqSKh8EwhyX7wSfDZf<} zZ8`soH=5_WVI#dq00uWF`1*s*^b$L|UrYz**mQD;o-iU3p)Sas4Qk!2v&fy#%%Q!= z37MP7Xd&1O?nY^IlLZN3_ai~nIB)1{!#pOVR zI(*SV_^aTN290Tv@S%*!8q`JA#mY+a(#PmEAZZEQD6W#DhW^&sz`Y$GR&rV5H~l7} zExopi{&gka8qjq5M5!G4Dgw4BLO#*g=Zr?cg%3R7X3)<$keyK$|1aPR0;OPjEDwwA zI77W!=2`e_KN>!?^?k|VdceKolvBDK0@;?1z*|2!6v9T_rSm{`|I=2Gd924Ttz&B_ zm3&iiX{EXx%26M0gsfugmiVAF=*tM3u#5VfyCJ}wYl9xmxE5iQD;G#!yBET%!gA)?HTFgnJ4t&p zIq1XTkt5Vsgf;}`W>->Ta~0Ro{(F0X|8qPh5I;7P^|h6S$%32A4qgPv@Y@I8ugWTgCgU7H>;^T|k zpbo2AYY>_(KjN0kzsF-}Z~WJ0+I=sZHdem=loU124RvToYNdeeqH_vQKfMLsxN`Nd zox3JBx&xWnj+ii$3mgZ-<4*{z=JZ9m`jqM>6Stkvk`-S>Y;k=CfveZ8l}Wv=+`p>W z8$`o`Z^kalCt+goE(dWLqsR{!F^NKn~rt#-tt{!`SpNJ z>p$*?WFEOKZ0atukzScFKN*-`>9lJn3P~EcP}CXaG_Fa^>Fr*hf|ko3#!R2)pl)T* z5r%%TuZU%{%ZQ}}hTL{)9v$Rw;}rUKv5i|nVRG|0gZAehaiCiJJCHK&jknz~xG0ph zldqF#*kv4~-1?2KR-Q|6q58anYpp?Jyh(d>o0!s_e{ThGzt#A!{&Jx(aP435%K4ry zsPFaOZR`PF3JoQ_J+5p_|Gf{CgKN=M*?v$0&hH+|QeMq70B>;QB9lyoJgIj7DlA10 zz<|oeV5B>6%LUTSJ^G=5Y${Ht_WyVoHu5KvNQD$(~24R(YKWVCCJ%==AJu5amo+88Sm)uaDnE^Y*kii^u_h&GR{uMM zCAC!UnB*peN(7Zvy(5#Om*-3M=DKb4FZu@~v9LLWnz?b3M8I|p^BBFHl6g4fiEx-d zn2c|pnuU_}J&SQ&Epa$rp$=S#SZej2&{M{}Mj6_&-rm4Gc*7g!zI-t1B@`xHO1*MM z6}vYD0$r!?0I;WYVhdP>qOLSFPG`WSR5}@J<1ZPSBEI%wzMz^^0YYk%B@0oDHX#be z#>%T%@Ao!|UVcM#VEV-nLE282Eui#ogEUr)HuAQKX$}Ufa~Q%a^^>reUhq}`@UO?N zLXeDc>`yB9AF-`8i$gNC_TMw<^sWrrQ+Cajq}48QF^J8PAX6qBBaGBXRoB}cJ@Sbi z8ZJOJMtze3!OrHvz)jk;9*9>Xd||c2_effN&%% zVdj?RPp|)SlE7TM3u)&ySi)H*P?h~Z=JKpi65p7aw}&E2ubM$NQp-P4l=0Jg!$s&Q zc+m>Wu|l=dj}D-nK17)L^8*<}dAm^jv6%;^u?8zZs-ade&W1aG$% zw*s;GaDFf-lkein*7t)R{F}^9G_JY*LU&ppK8}9qr5IW`suV^eR?Phk^jY6y9({Tp z<)M;ze-CU-$skblDifXUEaJ#qr&eWv7_MU*Z`%D-v|-+n9SiEmqr3ynL!}5Kt^Wt$ zP1TE$|EkKHXijT^!u3NYr1ZE>NT53svApp#L0AnKvk?}SIpKQRjvpif>v3_Gx}qlw ztCen|Yo#2U03EB3!&7934#w&A5;VsCHb;i%IM9k)SeahY|^T*bBU0 zu^$7wwWu}TVZ>J;IF-dR`Jn8$4fjUBU!wFqIemcXWeM5e+)hB^J^~)=MGtv8>7y%F z8<%Y71WK)SklN?9z|O`*nD5lPr$evdF8HS`3Ru#2VsX+dTk4y_1Y}%#U(L!^pdv7BhAzb-mo107xG^ zI-B;kQ3z@IaiN*xT+0yT8hs;<=Hfr#NF8~Q52$Nd|15C(Ji($mMPYgM#{jHl94L=p zn7PxKi*Nai;f`8S?nkkF{}R#nmOwk!%%((${zy)HT9w4(l?)GD)vTKj%ja$;Y9Hyd z8u06N*8-A%E7`k<7))RA4?>%NC5T=cuM9#X9r6RN6>wlBef=_dX=~V8yDM{|+RkOZ zAom@T3`ajdLqazf8Q>id2m~>+VF2eNL=nr^PHv-HG9pFXtLRk+|vvq^2k-U}9 z(*)VFW)5lT4xv9HoxzxIJ$#*?gIs3dj(D0|&0uYAP#np-(L$XScxx1$-&JD9uvEDi zJNpyY;33KfIpJ=eDTbZQE#FsB?%kl#`+Qz;>TNY>R~Hlpt1`N}IBfZ~bLbnQ;}KeN z*lzl+R#3N6?P?%G#FgDkuTn|E=Uv&}t2|ppEE(VXdLwR`&lx}_RG&z>YoRyTK1KNR zG%P|aaONyQX7rj#Wa^(;?c*lIS70#4mRw28JGq)f{r4O^XlWD4AL@)*R zY90XoN>x`hmU{{6G_DO1=PEDrBiePj`&Dnyi!7%X_=C_iPizLidZ*23xn;B={NmtjsRB-qwf_2;WW7QcQ>o{ul1kTJDPoLkJwd78F!sa1QnyIj3(Mc%XkQ)^s(ORt^T3eN z3r5TbGOeV!ZR4q#kF^s=-2DI>IeaG`QGe|QF3i2a9tC2p&3>Fl`7n>K*`w-gCLNuV;5%!DNK+Rw{nDwjCji!4-ndq~ z7lV2DTkfSaN}rRo)Vurw+GoE3x#2c+0g!R!AYtx0#9pw&{cs!Wbl%N4`W>QAeenZ{ z)ZvSny#03|0$Kfjrq(QhnFGjhz-2jt-zDf zh(GZX9;vxMg@iJ=!8#7AwGBXsCPOyRFl6jf%8YMlWl^7G`ZQ_hK|_m=gXwc5U?5UB zWPQ&pESntlj+r=z(OV|8%(pvm3-zB0XhB;&UxcjgChl^wGp?iR&e34#@(+x4Dus>D z1@e)d7IBdOv?v}3Y?aA6{kGjF>a6UF@Y(Anv7zOtfwk4UvKz^YeiTI6s|_z><#v+9 zLheP-SCnoWp_9b^fBs3MEZixbp9RC$k>+ShRosavdVJ51Ic%{^{BRmY52$I~Y*2ubDE!Nv5d{RD&SBO0Vow%pCx zyJ6FzYS}Mspd8W=cQ>odae=d1Q_-^3RaVrEuJvMV+&XcA7&L1+5e&*Bk1!xNb=t-4 zSe<%7Y1XDKP%7DWDLmEp2BmTP(gDi0Svy@CF6U*Zhx9?&O5Wjqps&6aMVZ;WSa`ZA zAAqXwXCCT553NFfBMhl8te*i&=bPwE50)({*1?Tl@bqyAs?fKX#Ju71Xb3!wi4lSg z$B12Bdy6y89YU#1tw?6p>h+rgsb(%%Ln|=KhxUrK7lHrfFt!plJiij+;itxf{%ksA zjlN;1UO9URFV|iC5782P9tW@v9YG%RM4>pIPV9g}^ocE!LHx%FqEXAu-VruD-rT~| z6|-0KwA?jPTfsz6&@bI9etW;e7;eR5){PfIFn#oMFQce$&rjM~JV*FiGzI-ztuou8xOxuA68KQs5Tj%26#(~_)8Xpm70ge zhr{Dy!09s>cQhAE>d==x4S;V~_Xz5HWIL=eNB$wnc>G$Fa%8|H;In@t&(4oT1|?V4 z)p(8HiyOpb&BiRwTo1^SUn14kad^01vowrb`G3Kn(Paec(-$rj3q8)d)G5M+z&6v? z@xrkF9gQ0GlL`W1&hr>2`aIPY)ABvyQ^pY4aTpaM~#Wyo5gYSki4^{aJo5#_2gd0U&) zk{OH&RlVtyZ6roAughj8^H2qdXc_wN{$qP4nh2!D}sK8fZJ zB@GZnxzkDMcrh4|-a)&ldzHbWR!Y|W!-Ia|%c}Pl)N19Zj_NJfL}mcSMhIsEn~jIw zohHdV%-b48SYf-!8`cfE*u~8IQ$ppioHx{O{SPiR*9k~v_;3$0mq0GW=^IZFA1NnW zbIg6!kY4Q~`&Y~ba?7%DXqzO@*k1=IJuBiFYQ3#|nb;45R~_FG57K_7dQn$p$DQ)3 zG}yHTk)TxW)k#2*l9Pm+4*fQPpkx{Hoe?U#Qq;ejk}%b#=V>vg=0&4sjxD~l{CRUD zeSNd8&MlmPa?}tF8yTlM!;U%oITGp@-w`ls<2tnK8~@d9>@hyI1X>Hkjm>t<)i66z z9yJ;r2Vq$yXE71w{N4TF_Z;SIz>Y zcHpm-Hm0TeparGi2P|M@6cY43eaW2Gp9e+I$*bixSkD`UD?zgB)uh;#oBp;6>H2=oT08ND5T zL$iA0petpMzG%x>wv@O~3#i1S?!1s3YiW@6 zRt}iey2rtSab=ndL~fs-4ZMDjp@TK#+B}Jm;8t9wr_nr( zbfMmv-W|pcmO__io80iB|2JhX^=7+qE30e1wP1WE+t7@@vO1v+9>Y_-Hu7j zw{PU((plo8jz5sts&J65OpVTh?UJGBNwZB_Vq>LZ8f49Ozk;bRe!$9E=gp$ZR?=W~ zyb5jO>2sW1zaEEz%$1*mK>RrqV_1%y(%zs&9Oa287)<>=coBW|ZAfL@zAifW_Y}db zd${>S*8RtRE>!#^Aht;&Nb0`*EM6D$qv7G_(RN26c1AMe&29URF*PI*clAJ0WqmR9 zt2Xmu5Zp2(&CYuMgp(+v{#K$z$>WQKmHm;3Zf_=``r0iD=-z$0QXen-*~}_i>2Gzq zN?o~8fx2FxM<%7~6m+dS*M(2BLw~&7cy~dZZ_%DWAU}BUp>8vvp+4V5Wa|}&uCzHq zm%xR7khEddE+;EI&A22ra-Okj@K$fEQXoBEmLid2S3(A|LFn@ zqV&6(OwayVf2#73!`0fd3iy<$r|_mfTeH#T*v{L?@t_#Aw7bjEg!aeiqdfao zpXP%e#ERbbM>t}}W-aJkZ7CkC&&N>8=(#2=zh4Ur=7B+Yf>!RoHE7%A6}p{V023S5 zWz4U2ea{V&^?8R1EXj@6l=clDpZ{8GT zTNiVL19(X;DYgC{upj!5d!a~WdKr8{NzjR5>y2M5Ob=X#`mEuz;7D!I*R(l;W{N(; zzViCfhlLR-YI<{j>a7_SIeJ{vBsFnmi=kicc*Hzs}%jAm8 z@{Xz~!JHhn6Ecs^LQ?J8{;hKoz|$25uuBBByfq25Cw?))7UpIbd~=lx-!Lepd~o|2Xc3<>-D2idF1`!|Yt) zcm&amJg@L3>&LKYo=!Zq!tUrc4m%j8hL@N>XCR2uexD018Et7-E_Xw5`bQ09>cVF` zYz%9XBO%hV!yxK6?l0%*TKTRrg2VA<^(~%mo;!@hdWtNIXlL4F@^I+Ico2L$g>#sb z@(zWA?6Zf1rjg6;~e2Ipy!td@ET1Us;4#tO-Ly*q6a%}?49d51K z9C|B;7)Eg;iK%;yk&!-0(zKqv3v#M$h%LThUWTHy!Yy0?Tq_fkW~r>SHK!6o(#5iw zK(9agC^u-eWgTbMe`3anI_TLdmB$Ap_jaNnD?@gB>%&Il@OnhwrSNlqoG8xQSzhbs zhKDevP#QW`%tX{=zH|?AlF@?N-;?&8UchTrADmq;9;OK|CwJs-pGD_xIa*RX$fkT!Pz$%^y)0TK%;PRG27-X z!oi!`^Jtk^RWx4gG^EteS!ha|mw2ryS2|3dt#0 zD>z>QJmq125rsBP=4qD=5wu_G;RH{O=0Mi^yTe*w#y6y|QuDko?O(Q|dZmzjFzRg{ zX3{e55Ns;Nk|l=zj5$I3fv2ZvpDla*jQfgMAmt9$(6*k%%<6w##q~lPk*@T-mE7%I zGU642D91v!!oOEOoZie{1_w4ymfl9M5LGnjavBBb?{a4XUo-zocrF== zs)r42S)mmG)bdq^C1oia^nW%Ki!A*U{g^TRgP?!-3ED6x+&spmunxRe-?kn1FgreH zR%C8)IP5#+WvJAwBJ=2x2M9=`aj0NUN}->T<^oe{k5njXH%f)jUTNN9@Vzd%k(S^| zB1!0$Wa_5|oQ4ONO;|%4*-bD+%RIVSK+fyvM>Fk=%+}yb`j{d60BPSB!Oe;NMDW%_tIYLlRvm-WrS3>hpJ+u$ikjAnKdN ztLd|9D4(&e$ymq;iHHMhTv2h5Q}M#X+s~q$N$(kMZQgs3{%eb1TeTy*));$a-5Sw% zEUCu)(H?N4(b)4aSE?u|Nnd!5cC%|+;?A5u9!Pzt*IKszayrBDrZC1d21Fl4*06Y>tz)Ukm$zFW zyhN54t}FaT9oEKnIJWj&J}=Dz^4_p^$>+avVlD2dmrq6?TIb4Xw79fnbU9OYmYPl9 z5dq4tnUI+Cj+en{nHy3b#YZw1I2pZIYgZqjq1L0F9LPKFX8)ng_$8=IZ^Da}MXEPf z<>@-Ty{aCCle%o~a^(AhpDFKTONmx;$SImLWJkI>Z{{K!b7#j>xmA7G8F)%rA4AXN z3M3b0VmFbbd#t?gpUI^as&_LyQtP=J-C6_dpcLiv!yRz+t%X1JNd-h9IbsZ8UY~^} z<5xJwH~x%9X6;g?D0;1|D`7YM9+9CR8P1x)T6g9vrw{O>PyGX=B&}=R9Z(uHZ5<2; zoPv^;^fQ%~Y_4e6oEhyZc(<&9-jCi4W_EiC1AkT}4hQ(Gvh)8Yn5U^h3|PhGkggIemnta6cHoUy!HEzlmp9tZzR)ehC||FMhu>D;0>JS7 z{sy?N?u9nYb~3BNJzUf|gNMPboRJ$T@3d!z;YEc|I*l9xi0-$IDAFRIFj7gKL$sK8 z1~GP5h84i>M}0zg_H&T<@rDAyAoR}=6R2rI!ue4G*C(08hgnGzX`B|#g`;vq;ldnK zBoS)+dh%LzyM&SSd{bc2?4?jQW3Li0R*LLqGT(xQKOgJ17QEYJrq%3qEDA~$$Ar-< zc&B(<@(uQ5^T+JyYWNPA)(%g_ZhD#Hgqd;f_dJlz)x+VStSk+hqp~^iwDL$=%rbHY z$5=dRFJ-mn=s{h7isWIPZ%B(0E3-?=s79j0vOBxj9ifH+n&~y+K${%488m0#LeSb) z9mQ+y%FPFG&%}7TuGx*F88asc;$t8DY~1Yqhyn1Pmn%V#GKgkXe<7Z7;XIku`Y6{i zs7veZpE>1Tgjardbi?4i}AYcMtY@ejf8iniXu%&RpFrB1TvA; z>xrk0eI<4l6N_i!RBEdtym++5m6PfE^Y>Qj%|?JgOFIf5R%UL*QCkMe3+WC0HAA*R zSaqC*?c=#blkxo-AUVljgPEQ3?4jA%#w#>O3iP%96LBN!)I3j`t4`VkN26?fE##ew z0Q%^cfjoS11(&p@dAPu6;qiEy>U@N+`|+M$Hug`-CGl2pS3w?J19^>}KQ>Ul+Zcen zD^#S@8|2xAME@HB>sI~4aHr<$ju&W~&-CMI>9ujdZ`%uP&HJ_={HFK8OI2SvQL8R> zCq3x>W%1D}KMR4i9$A-4&;JNrwcadBWA;p_utR4PkiQ$ENqx-KK$7DfF>$HZ7)LK$ z3&e^sKZr7JyfEA4W-Q1y&yD75uqw3Gegk-CUOb1pS-0;Yz2Y$zb?Tvw#Z{NyMF;x8 zQsfOSe<5Pg2!8}2rC0R?+K)!pf$cGGc7pexB%$Ya13bDlm%i$ZWqf?ztwDp)>IfdM z#6K6!=k-S`YR&|FQaN9b2;qcoHa?E20(Lh0veZ*=vx{R$g8d;vkTT$$N~$xiHK{Nv3C zyTDf>!>D^r6xrhfS-^0rA*Q+N9|ncFf0uT(zFcmgS9u|Fw2$8gPwQ6%^2fsG z$nmyBjBP!25el;|dQ;AOuhaAIq7c#>+}zDEoNy$yf>$Dj@kb-fsrjTMfYD_?FV$b^ zgqku>t~*p4y28KpB|lQ@hnI&y=Y=+nPQ_b-S1S;Ya~U(7z-tXp!EUNg&gsaQtA8Tx zQM>&qD{R3W=Ia~iQ$2Pc4EpAOlF&eALu{jb-OUKX`;vgi?+^r2{?F1`hgYpUeH?f9 zd$C{_DeiuPyE{dKdx1hJPAFAcs2fE>TcB85N=xw*+%E1?2zqh19~|KQOrQ6kJUN@$ z(eF$)o6Vjp7;LWb4dZxR){7ejWi+pjEk`C;32SE9*p0Im8Y^nbTvRLVO#yNB+REwV z9AMFmcmugI=r}`!1HBm^8k_cEtCBnyEbk6YxAPTo${von>JLYk_N9Z-_h24+8e4l~ ztFola9?o-(O5?oQWH+pw-A1ZK&rM!z5|u?<@S%t}X#cie99=4zb~fc&PS#i(gT=g0 z8FYe9dSj)ya5XYk$3JNMQU&FAm$>bueLjizZ{9ob5EnNV(@lJ zz=6l&IFIjl0BVmyM8XJ?b&`7Xrs!o(DkXxB-y$=OJYx@Ib;lcsC=h~V{l=wGjzd=v z8YM16?u>2~0hINzHj`vuzJoq>Y5A4(?B~7C?noYy#IbSb~u&z>Zh(W}J{#?@T|Ab)iOrPTODihw!fG`XqlvZuk|{4+{Y`V&dP z<4yr~N9l_?9S7W*gsK(&#QgR;h%mGMJH_T0caFNfqb*FI2B4efc#2~mFBKyy92-l& zB2~RO-YnJwc7@g;ODX;ZDaO~`VoHtmQ0fo#MR3i!6=;|l2X~{ms}DLj_wvQg$NwYD zitXNd6f}y9C3SwRqif!Wp86voF?J7Ax_8oXv-|mxJM!d{VSih^{A8W}cI4e`9?dCT4X%(Ha$*yBccnNGU zdSBSgxzho#r+nCU5HEY}LxcHY^f!OU&$T%=lp_M_)?&-Cc*0fE^PGbRj6PGaQ7>54 zo7wx;R4n6$+zOSqlYMC3P-7K5YRC#Xwf_zVo@46+Tz&IfOfj#$lk!{SilDvM3tVDt zT)U2Q?Jvp2zj6t_W_|#7R@!i8_5B9}N;ULnJe?+-#9!tTSy8I(YAnDA{(=!^9(m=f z9<49OAbeZ?TC=`DLu5{;5cV;xd~r?e{T0t2;>a9LZSXr!ss7si;?zg|24B6L{Y6C@eK? zb`SJYE}cWN<~Mrtl_I#8S}Ga9RO z=c#C=C6~i*%7Hl`+T3VkaJG8>5*y3lUMJ9y;2aLiDQ_@ByIYHMwQ8UQ`e=7>q0Wo} zLF(ZBwh_=+J8xpHx_K?`HAj3DH@@k&koH1NljvJb zMx|!nd#GtVijClyFa(!amA;eR>VXN+>o+#zHY0zXV5GF1$6d&jbuHTL9>FM^cc+N@ z@jecgmyaUEN(J6E_Jj)ni#&US{umg91BE-@lj&f zcgJR~W*NB;%H6UUOjlB9(JZGB*zZr^fiSzwmg+;^k!i}0-9a4tuaY>tU%CtO4YJ7C z{8E4jXpcrS7E#7s789DsP)(HN*(;&+emI-+{AX~Bek>Pajf~;A)M`Ih;!`J{Vr2$g zCmMZ*35Y*Thq3jRgmVl{5oeuWOCNJzPfCaJr0-HlD!fHWJ)tFqL8-l&g+ea|;uQ17 z9@y%xNojUI75qWit%mufrGz{cnAhV0o$|F>7@Zb}%%SC}4wQ_8_ldrdJvXBn{g4N6 zGq-%D!WaqH(Zej#5Z9}Je*j$S(bq&=UH2C+TlKbhUSIb82=*QJWC%1zp0&;LqcBFX zcV~*`Q@9iodz)>r>Xw~kv_^!^L{Nu{U{<@_Y9l>gRftEW4PRice|w8!T58Q6(El&j zLFng>fl@tPkYK7#?eMVvbdbcm-ZqR-+74&*f6H==-88;fVX)d%0teRCg5sg85tO|T z=RuSCU(PUkK3sspM$yjPo5D_Rr#a)x9`ri;eKV})uEzq+>klwcTm1!O&AFAaRk@y5 zymdEG+S77zM>7kyWZq$0X+IllXp4&Rp%JV@i|ZW<#n&B4aA|THLHgBWpwaxR5J%&c zd~mJzU%%Mq$km0&D;K8|GpoY5Ikum=D!4Zt4Jma!-FSu{c5@t7MN9+(%G|vYV{IFw;f8cTmedB{WvMXg}z?^On=GIy{2r06WulpUUGqGxu9@*wD8@ z91mO`%`)EusdTAk1K4`n3)ItZwPw^%EzT3a>~~H@!j?%qv8XrLyHBUwWDoz}R=6Wkx{iC!=o(o%7cDes) zjb9COt2bY0J2D1|6G|5#n3kD)mYsK)36SVn%kY}dYz$kgltp$K{d7F1_PVzTg^CqB z#<8R9rl6MZu>l)X*rml@2Q5)en7&Md@B~z7XcSA{FhXKl!Qu zngkHE;}?Q$%<-SbFr!My2DUsbwGIaRrmd#aDo<*pb-3?r$cMG$Npap5Yp8mY>Ojs`amB4ZK(rG9% zqdE31osG+l%Du(q;hnHm-FJitn}t(%p!b;*EZL}Y6E`bOu8Z@|{D&h9mjW1Ul%JPw zqr9(}&G~)rBS>265{lGqQX`FjFWNa~$!_QB^|sUwH9_X%P47D)Q0jBVt=onNVN`ed zQr}c+!dX?LrJRhb%(-=CHBi+yN2hZ2%tsfF_xqrlrOJyV{YLqD@N~*>rG0gAaYc(! zTj8)kcEHn9GS`Hp7owF^<|`^1=)G&Ca(r1U zk*h=FCvrSDMDj8^?`CLTyQ8#J zCV^)SNUG(c0JHP_0epW_)|@LJya1L~=qfI<#{A^IZ>rH)r%kzy&PJ!M?Ksvdz#ZVg zE#jd5Y=v3o(zd&8;AeqE^RFu_Ac=~W5Js26Jx0-9;LsW?U$kqdw}2n>S}lp>c0TEG zRGWhz^{g&{OQ}}_?-*t3d7?+^f?ya-dAAGA20bBE`rbQ|CWi*oqKrBZ0F?vF#qZ89 zU~H}N;wCh)-w;TgPU*-S=eHL9&P~I~*1AOMq3QApv}iBJQTMeQKdAC|+xSCLdjC#j z=>8(RT`5-x8@xq5Gi(4iV5Rw@V7@W^L{GEE5I3yp6a)sQ3|WZe9V<*b54f4PhWkt& zJ0=g2BCzKaKGEKOWA#?}f=IX~Mgw`X_6I3rv16I^dC*$?b!jP@=wB+NL#?zXdzDol zIA6(rNFsZ)b|}&=T!K=Y{#*)Mi5JkATj~odiNrjmbT+@kNz&4 z)X@(syW#UdimE;$BmpTidH_rP)dg>^7CN*Sv(L5)vOAVn2i!`}2vSEck&ARzUmxYR ztDpWNm<`k;>AHCa3E_5tyOR4Yue#fTr}?ApQag)z(lE*zdSoqK3$%h>D^(e{n2|o>{fx}- z#pZdUhjOdHNcu+45uaxm`%$EFHwNfxQ!r+}?{t{sJPX9LC6p`Yx89(F5|{Z#BDn=v zFv}?MT{W8yvUM9E0LqFslYq9P4a=1;ujr;;PUcrOgosi z$L25t=g|Dm1wmqtw;YuMvv7lzJ|FQ~{h2PDf0ijavsF1yt|ra}r{;+b1j5Mq#*bc! zEC=JCv~RF5iN6ZQF++npLO5^DI4*Y1BGGeKL6PoR+Kc0uzkOkleG@TMgVquz{ddGs zn57jngr=@wAu7Lz?Wb{T5l3a*;7w32kzL`;mP2Ep8E_PQsY8Zur&rlS5{mH;(ok^z zU5vG=HY1|uwmM02ypW6$9kM{FWsGpAZTismMML#$u zmLwCbp_%VFa*e-acdV%`$+FOfQ&8p`?mWrlU9s#PuAcjZ+w>a8ZrB{d@*IOrmno-kNmT7v6mSYY zfe^11R70cmMu}&kqT-|rt5fMzc^hJ^gn3kfjYUC-=`r9UTc;Fy2$$wXLhQ`{%l~sI z#U>+D|0A>b#;u|+xjLZ8Qn){o`5UXtWccb|{Enf_xV8sjb2R1@SN)G)rKQ*G)6id) z1t!+wv5#nfGkgiX>P^a^{mY(H%w>(jM78Zw)V3}*zRC-~M`!InwM(vEjpO zkl#;(v3~jKbS^fLe>F3%48VKV%xMDt+w2A6cw129-T!!vivctCLZ~$7q8i;)5-%w{ z&Cb{T3Bq7!C%MCxmqDB5G+nYpnJTp=p$%dDCl6S%)_hq3d0GPbYX($twmWnmn$^(Z zBID)qWG=eBd}(LY*%YAa-yXx=>Qq|JSN5kQsMX?TVDW;_yd$s0Utc@=wmSnwTX~2! z&c8axv0#oJ2s+b1dgh8}n;$2>ns#K{L1AkslUwG@Uj$#dW37YHiJ)M*%!ysjdBchq zQTa?u0YdAA1k6%Kg7B4>R`P28fn?9@`)6ofdV3zMQ*)(3x4$^yRR(^M%CdP3h8xAJ z!`<@S3-=v+;dy@4&nvn+p8d$ zxzEN5b3!#=)YD6u_~__gmu!yuZFuk*wdV${>&tSxG(9gJ;(U$IbyRxLjT)idcU)&H zNmr?a-yWP{F+_?1U09V{@cv&og+g7_=Mv`LitK`-^OlBleyr&Nj$;N=-<869<87=? zcg8St!#O)X?=5>6==WxWFLULCbSO_QMYfUg-yE(^%_g#!J_JbC;ekO&>GO$rDYYu< zw4A-aAIhD-u|`W6M1rfuXWWMW=$;*I+%q~Xv^%~>4}#=IBx#=i*dBB$euo@2k1RL@ zb^72f$jd*18fa#OgAZ%it&8+OG#Rj(gXZ8!)$e#3Gy`8=qy2urL%blIHU-5d=Kx4* z!7}sgj?sdCwf!6PvYPHaV&`%EAmOkotl!TueG!Y z>t*(pGN~IG>&C_Ko$3cgsypCE( z^|7w{9z&;$-^cg{uq|NHIxg4%gBlaX1zVzTqu;moig1pe@@a{=`#JPlhUa=aUlZnn zUVYjhJ)ZWjcDnU$0e}b8ExQSQ}30wF>%KJqV+<;FGASD?aS-S5;!1l21Ch z#Q|AE{jvbNADzVWdfa@T3r4R%ZL4CCI4Hs-j8@N|IMi@k2N&~y7gk_Hz5*fe&EA7Y zu-DNbVpfkO3;r*O6ZPCTv;aVIpo|At*QrvJKdRT*<{GslDh0`SLg!r}1sg*SQ)e1LX} z?|(rEDZMM0mfc@{;TAeP6nec=vYn5!f5KB~Up5Ab&dtK$pX2sQ_>|9%=T+SkKU)p^ z;#GarPxLXY!?;F&^cd^Sy5VSL#>-$&uNF)!^s13@Y>jdQ-0EZ7tcAht7O0?ilwAtU zC-NyD zcS!+$TfwOyi%s}<*&Pp=lVMmfAG~Oa9%|>$$@Yt&>RKen+p>IEpY7FyPRtAqYCb#rQRv3#-Iie zDowsKDp`^fTp1H?_T^Z8j|W_A4|dud?zKhC|6*WkjpCFHBD= zDJoVuyOmwhs)oSu)F0?~SxSSStaU>4d#{ ze_IkQ>%IKAnl+YOwf3ICy4aT6=;{;~fxh>v#tMT{2Ir1i*r6y1YakrgDu9-=C$U4h z?C6i!ds|RXjn2=VO36q8AB@g-a&!(7xAhJre=P5-%eh)C$P@apC%rkg={N_+r{-YX zwD6<^b;$%EU~ux8>SpyNz+V3n^))k4FVF)x z13T&;r{Y_4@`drhq;9Y|^2fACt(U`A6L7zpB(yd35=xt89^iaqhv$6SmoD?c8%-2L|U1*p{K?Lsi%Vvc2S@9c@$+JIXGNDutMRjug{=&jBh1z~54yU z*6{uS$yzXz;c<%=xIp{4JqczD*@TL9uqW`U5hrsE`m>oZ&#}gyN{U=^f9^d6gqa+s*-yLqqt-nVDLS&qiFCmroF4A0g zZzwD`esqP+fNk7vjHgaq)xU4U$@-L!VW{vTo8VwUH`LLWu?w{0awE~^R}>8NC3!)H zv7IL<$H8am@EUOh$LV2%aH~=zJ&>01i^%ay5=Ewe)SWx2ab*NVXUqRsR((Y!F&f*P;zr1lU4os#v z8PDD2+;u7lQoJ36&-!4YpMLPTaDQGE6ewFRp*I_y6KJdaMPg>0qnNRY7&}|A1an@b zosR`PNi=o+&J$eL+ z)o-H#X@$IpVWcCni}AnK(;!~wF$ul5oM(diUO%k2JPI=oRR@ogJZXPd9PN>jKzoxT zk_63vhr{L1BysxwuB&N}NDj9-vKRND`RJxd_*N}E5pf%?6HIfq{Ev}UZaU}c$?M{w zyX;-Y160Qev^VGjzSKDpghUzg5m4xUnTxzGbxO7K?y1o>_TJq;hSR$xeK>ZI5B!yd zr^Us;zpbECRVcwpU27_B= zfx6!BHtojlD}i*~dmO(iEf!#jdLpYNzQXr;6eG_)2q_>N&{*U8AVeuI9}ybeopG#s zCI|;^-USMcRqqyaam!G;DpQ-T=1(k}k;lfkAB4ng@^=8|Pc9K+YhW_6m9PZrk9tGy z%xcw@pwNuGffLM~dp2^u@V*`W^1gzxRmL53StBa8rq_eYW8rge%mEB+mP=gc*%N?h z8OzhSTKpOOjWZocHf4!yxud!yOO!74+CZ=J2XLAe(_|C$F~NJ``Scr{l^+EUbL?0H zCmY(TK)ww-!#tpO%6vQfnSPrJbqX{LinQ;jZFZ1}OWnUYp3pl1Ja%x!+ot@zxCz&BdKhJvb=ugAbF%Wu&)U*5eO z7fofTegE2YI)yJgDE>cjgLP^uAkh179YecI{49>g(_>+59p$Q?>m-@lapzpS zqs-QCZOQw;4`Arz&n)Af{vUFbX-E9%p8YC?)$||I&+ahN_t_k4Zo1f+j&BNLj0-am zW(3#3SS7N&7wx6Lord+roJ7mox`r{1TKLyS`oGRji&m@%?ly1T#v@jt97FA_c|Nz& z&eF}Jn|bVa3AZ~YT#VrNV);H)%U+TAn|Jc1qs4Fenn}s)iY~hC@P7Dieupp3Fxe_b zX);mre{o^)m(xBfl5$y~wn@gs+P7Z^QSy8R$>fc>Nf*7RJ5G;%HXB{KOdC)0@ujOM zXj|}>T5Uaj%$u3Bhb@}`TfOiQK&O2Fhq#(mPN1IE%t;_wvmc|E6S7Z&F+55nH>xiP zsxG*X}@|&FqP8|rmT`0p;CXJA*0OSzCozh&YSwJBovlgR_RZO(w`=- zginQ&5$pk_ZsL8^ze}LImU}03f1Uv{t5|ta>0=(Mp_YyR&Tt&*CMD!QeYu@44)23< zZPX6jqeYFtYW;4~7K9d(#RJCizr0~!8b0S zccG?$Lod{s2DR9eAUZAW1pf40Z*Zq|E<0UKwL&Q7?0ZbK)xQqGUY)RltBO}PFrv0P zA&l!bqj-(I3l`PAEByHQsH%Xo(AzL5GHf%1Zz#}H=Kj42j&*iYUd*Q3F~q1jog0r{ zy!I@1lc`L!&0)6|(dpywP}#1HaiW>H9kf}``>cX4PhDoP+O|g6wgh$CE99jIB}ry|THD=0Bv^kIy4VGwaOv&vM8{z#I*3^@w?^&?Bg&gi0<5nZ2# zK6eWP607dn;rRPh=GGqn6esKTzd}K8mG^{1-`*KK8ci1n%THw~2G(7>!JcFC#g8({ z7w$%_Q@GyD+laszJI?Ln+&!lkU59!_Vcd@E8excDY#`~%9s>r+k5SmD*$Zv7SM88z z9y%;u-*F{~_EYkyr_#7mx(z<(5U#i|tIJBi5T5fAlf~!FEUPm=$)%k3BeFX+Ico`k=K0#k75q!na4Z={K%@JjfJM{c2+E z0nx}I-}sn!T=sI@E$@8IwF?odmhp$VesBk>n(kdNNoj7NlJVxs4ElN>#%t>E6iS0O z{Kg6>>!*c7na7u!_q-aBRIa=XgXGm=%Bp_%I`zdYQ=VFA?G6*9c}K0Z@pmkLsG6d3hin7{RfR|CU|g*>p5%$lIoA>)`8O~5R<&I_ zm^gP&MXSBO0NwC#2y6~)jG=vZHTNh9LRV158r4F~P3j(G0m>-dW5>>F+L5xRpLc18Yt#^t+VmgJojoF+8vGKPmIR}p+ro1_~~alp`w`@6pcmmHX+#<`WK$E zuGL1S_V+7*WL!R-g6;dNCZlh;HW;RNE(o5~3-jby>nL&Cw~PuIG~JhL&EqIi#)JL_ zeHt!VVt3RT&qJttFY$l6j)i*1Cm>t%%_-*x_aoUj5XHHY+#aQkS6eo~rS;wkXi?Fe z#PL9RIGSO;;-jY)!^Np*=VQzEVT`lBbiu9Gn4;iIz4Tn5nRP#06#qe3XARwl>&=Lq z0*pev<#;!c*cmsjF#$MutdM{Bn~G-aIDmy zc9t;Chuw1H*wYSQz2`bAeAkZjx8|8+XdcscC0smLO1>_i3Kp#m*_kd}7A3XjRGu^h z{g)9ANzxxsV2;0=M5o`KrLw*^`pcA_K}cSLoCkq$kKag zxz!KQSes9W+8mG8c+xO*isb06k8|xTnl6J3z3m_ns4Q~!#;30?@5Qk0D^}6T^8m{P z4)LF`j=Bk0WbAI6gm-@RCvIl!hIF)ec#=pe{bHPNvxhp1(5`G-KZN>?q{aMJQ-&v7pTklwHXTG6XVOv9`m~ynT~qlV zI_t~vr5x{$+6XWAYlrFDIUeMwQ>{q4sxjo0*={+xpHyiRLU(O*LE*Zc1vsNW-~p|S zY^0^_zp@8~ZT^z5#p5X$X1lYfZPnSEitOR_G0pg|6DF7y+DlU1?1w+KaY;NlPP`w% zMV}S~UW-UT4`X;~m}!*`b0<}{EJu`nU@oEz_wZ1J<4|Er z6i;52Y+}f{XaU;Ei#SpBl9$8UAy+gr%5RlU_0#Wd^9?h;6|Nuy1WWRcH5^gN5nQR~SE0%N-VD?XmKJqQ)9 zbctrWgsEwEo~t|JMZNtObXDKg74L?(#6I<98L*`#?30*Yyn}zt5uVT}`&Zy(Wr^I# z)B{W;I)<*pDb{7X1Y^oJ(o^l<9e*ghup}Z z(IX!kYxTRP(rbBFoM5I*?gO`%vhvpoEh#OzV>lXT;#R{gJP9?mK^3Xtul9mMb*+5t zr98hC0(nX_`sthM!%RPzbvG;rvrQzMC5`XPY-Kv+dj8!wRQt1A{4{a^o->y=Sqyj6 zhfdn3JL39=J{WGLd}ZyUe+GG{&fOOQFKu5uE3v1Ds(A?yYRwovFqOQKcq-49NM6l6$GP6TA~MXQh5c-d%TM%x!7Kk*j#;+Q zSHF5D81}WYpn>|mq_|42!5v0hAB2;v)}xlta!$Sx)N>9ALf7f8n`!?Z&0w$J9*Sn) z?%U`&e;F0Z`s)Qz)ji~~PM@EQW6jp#*koNbvDNa=B~k6MG#SdRN8HhAFn^QItCk++ zk(cha3mNv?g2T6u@Urr4C>)gi4M}ZdSmu636-S1%tg}Ahuxfh9ZNj+^Pr|DNSLz5m z)Yi9GVnLVpXrNVcW)`=m>>s6{9)K}M#43*FjN?-viT{Av*0PEiV|1FFifdALbF^GE zN`rOi8%HC08?ZGF{`7|ZF&7k5Z?;E>-m4geTNx??D&u&;Ewnp1>rkrQK)?3)wIn27 zT0=-oD@j7K*5YQSyxQxEnGY+{qOR;Kc``H`YN~GgFr0PhKuv8`5P+DY{w3np(H3IL z{5a}_cJ4dUl~MupRgwn4U%6Q;6#lC|fePjNaCERL%Nl#*F!vY!UQqtp*f{O97S6$I zk!7CW;}6f41(Bs%KIG)>m#p;P`Fb_ic4SU+rpTV=#;)co;5haHp;CRDuZ2sHABEtZ z0|ku76F`g>HgYAbPTr%O_8uzyZr4~&pVJ@ku5$Mz+8JKUW~1Ggi{RJjSq8r9+BsNe zrB_+VaeoZ8!WcbyJTzBE3CspHllbJ`-T-ax+PL{B)BC3(YSsJo^c~n0Kj|i)c(6t( z3-!*b(~rpLKVDG4lwqr(G-k;BiZW6DB2Q~m4+V{YnUWxbD+$DWWdXRJ!3~%qH(6p{ zzvx`(j~ABWvf?rATIg>OWd*kuZoaLlwpO=wa8qlq!0Xngek6tYc8v!#zY5D$kKXXn z|CYb8*4hRVE3G9faUB^o!fBp4kSTVTBJjhv z+=0+rtE4t;4@DDWRwOjalXp(MGOi~EoekRziTWtn=D7JJ2<;yhC1KTdMx>4T5|+WU zd7KQ5l$sTgt=*S(cFOQC61jzS;b_&8|3B1H(}<{EE)Jc{cVCj>^Wn?_t~SZBi@sZ$ zgInX(UGhj@o3fqr9w*?h7HTJW{>n(i(LdjA7`wY7(D1HFfXvYc7_>(_BhT<&2ZF6T z1DA318Y!_lvpLqrn~PW^nIp2|Z>?8nUmG}@HqXvNg7fI7RUa*pPrM68jIG7F)9b$O zMB6mBETh-aKs;g1;s(vl;yp*b>q5c8)AOs~Q&OtGp0W|!%&vK*SN*5LXUX;i`c^5- zx!P%hjB0bjSZU+|aJ8bjBVajV0V?wa!F&wwc$7r5+~;DlSuX!L7%bQEx;~PZQjXCj zIaQ|K3E;TBtv4J!7UK`CZWNOc0Y?d}^7Y9IdVcy6%Z$_JFeKMpBl-rsM83IyEs<9K zIYL|%w~OejhNKcZt!x=WYI-=OaV&o_1bWAVzNk?zNFumGw#wG|W{&eurdW9@zkqGR z#5M5A^|djStrEemQu!dUvno1K%L}AnpXzg+^wCcH!CqT4igdR8i*KUS33t>{CYLAa z^qW;-sg0EH5!Lwev%~5z)sNL~-VjQeG^&y~oTK1tBS@R|^_CG|$d^%aM^ye`n1nmhUV#h{b+^)M-MzB^sFGa_^U)PE5 zIlQq&`RgpAm2y^y&GGt7Bzk__De;-kY7I7*^u$DE!yGcHo1dh{VWxEC&%<$}S){C} zc+?Gan$642wzEBcWe-%0ot=sTZ3Y55V_!v7G;7P&QC8z3L{%GEU=@0FkS+hLi}@s> z>bw_t1`a{ES|OTQ(0^q8gVuOHSYl5h0;#SZ!tliUDhYFA6;jQocX%M09TseNG!6hU z=D|=`de`nNs?YO*!uq!wanbYb0fg2_AMkFu%f3=tYPtY5-!%`o44z2@?*70rW??4r zSSk8cE^aG_lMK~kGk=XMV=iUYsUS#Fzl7j{klPSi&t-E`y{Kyho69;0vNr0>KNL7I z4GBj_l5~2Lj^bCpA9zX`=(>XTlX4qUOHXD9k+@%l)hk&TrWZREjlCD`QtC6EOs5VsE45Q88)j4zmKt|YOQ~)Uy^_5y-{3Usu^SjanT1?X z_Y{P=R>c=B)Urjz3(fm`a;|I4qO{2Hp<{{qLQ;5JA`H9U-N}UNv~U`Z858lg+j`Nz z`XOQKRG3?|SzT_?W_DQvreDZ>=RKg+HYoir1mU$c?ZAX~D@GD2phg-i;;+Qo9LEc6 zNAg_$B+8LzX{NLRTQFjMYHi3$AEcP-tLqENsnJUj)ZPU^8kL_RNWJz#!dO9`OO$tU zs9|1Q63ltd{j``Pj*tRM(-u@lZDkJf#ymJyD%~4_xA8}&xAcY+g+tGkNYwXMpdeke zI5ld_;tuJX4LWuI+c+A|%i1Qj#CeQV^03J;ulQ%sQ+xeDGO?w6QDp_S1*PhHSoQz*qIL|FNvm;~ z=HE3QT^9YI2J|W;itgRP3}r?`^fb!sA*M>PMSxxV(0&&^C-+X|J*RBVY1J+SVnUoc z(tG+B)T(h4>|N`KBdoBPjp!34LkPWZIYvo~H{)S#%{BmRxJfLn5_d%GXAb~ujmZLB zqBg_d`rTM^e5w3XlUij857nu5De@&}Qbvr^{}DdzlZ@4j+qERN;UzFl&AU93uH_x1 zg!bbWcii)DxM);9I}=_D{vxc}siOlSOif!2-z)hClJ@^D#+(o3uvl%_G79o_GeDQM zHj$yqcFUE9YMz8ZUvgNi54eWvYR1Xo^#43lywa$T#??1Y{>Zo^d!*_^{w0*=ytx8i zqhJK=CpchlJ~q601N98h-Os$k{d_}zv&lB%q?K6$wXxQTo=R}ja1>~Jj&v~Jl)*{5 z`=ClJ@-p$1Rj-++&2hsdZffre$;hu&OTg0VI#9H(jKwi#itOoO9Ddw?O6d!ACG@oNkIvWGwe|yL(Z6fh@oIXm%XuIT{h50@! zbjpW9!BEdF9LUiYHJg?qf5BbLKBOM!4LnorjytS@bkrS1F;y4+i$S{od6YFKoIslH zJP5cb!36=M+U#Hm?X`Y;B4hHv3CJik6t@^Hhm$92;8*-_PQMLytOxI)*RoUrnM(ax zvGBRHEzIV~+XKeRovtfk)1aDE2j@R{RP~7=fa>sj2sGZe--eOXI^t9QEDIB~>aXWR zliDB@6N(N8aau;^4YWvaT%)(U&fWFTZ4xl_Xb8Vwty_ZvgG&=qt<(tIt8V(0oAX`) zVaN_zF_V97cb^Aya~2}ZCV%E2bla+M21r(Rb2<7h^S=?Q;CR~*J<~Fp;)=X#O z#}S8eb#sAlv$0Kl64oCjth!Al!LC1si`8qAFXzjD2XM99G!#&JCo(L^b)ACV;)Ix$ zTAo~0-pJc7b(p_+@USALtUV*uW&AsC(b_buP{+OECS0wT7cv)(97V(SWik9+XCIVM zp2vfqnBRVwX8Qz|jR7$NgY@&DM(w_gbMqHp0y~!FT>?qt$+0xAd`ysy-gl_$cm4sE zYK#Bz5bN=L5~pX4Fz7Zm;~6;W;39ha4uFUCbQxIE|2G8vlua*yub!B>N!qBE$;=Fg zV2HLyAM89G5L5v~+bN5^jG;wlVkj z37gHky*O8LeGek9dU9$uSqzD?TSZT0!8g+1sI(Qgs7(Xq>Yj6ASINf`xx!^h5z}?y zRL*M`CDW`$HBegblM%uB;4JBO$F-zA$Zp=hHg6$kVGgCp=n}TIiw9>xsQq(mq}VjLa8;O8zfXvDC9So>s5Ka|?MqITSA4 z?*wDs>}dL{F$=fY9PdAhpsh8-x!6CDDmZNa1iQoY79KI*$k)8e`EGL&HsJ~J*Wd0H zg)TagEXqQEe6H=td<|(WA%JT2C1kr*X)z)ckE7c;mK6jTb8~=hwb_+Ogj&JywBB|0 zfv3-MLap|8mY58SjNt2|H)M-hRUQeI+mW2>g;`4ASpS|=by`1Pnqw;yb)}0t##miG zN(MBPZ!454mjqv>=F(L=?vlpUYH!xs9r2xUgSkPref}9ntGYbY59%heeURB`2`JUx z9$AMjeJ67dHvJx~z@|`H9in`X^M{MqWe}@<6K_M)aDzwNzeOM%1>-@f4jq;6Z^FGg%}+wCCqeGs@0R8#+ujMdsJI5 zQSbAp@f?#X08yht7?kEg*&)YV;|bjKF0!Ui=@=1=khGE^cK)kOmeH!N%kaN4NpN6( zx-$oXd%D3>&%crwYcoRdy_NScxKTUFOFU~+>)o8k9pZUs>$e~nq{kuLa*=m_s&7}$ zje$pa7dosDbXtjfi{R2|RwNupU-hG9#?lnX&*nh3e)_~tbgj2zy^YjxPe9`}7J4Xc zU7^vNB!LpWK<2Gimj#@9>s&-!{k)#)SmkvDj1M=5P-)p7Gp*32z|=f^oco66`h&qx zq9PSBdt^rxn^7u)XgF$1+_fU>eWnpPvNfg;d3T;7Nx68{p z?mHx&dz^@$jOGD^TKjx6Or{qhG}^KRfG^-Qq^b-42XeLVi+ShM@$Oc7Zb+f7HMk%q z^|((gb=MK3k9FnGDyX|}m9P}{lxoy@o<@8B(UUk1{|=_q6@1>~_|i;}tQ{5%=RdI7 z#(!SEL>D7AkLa>>EdDXoRpO<_fuhWa%%a?<+fw^aD`x5>CYUcvD4X7QhVKjcr%pX^ z9)@Y(WQ~yd<|2t{ydDBd`<2;)8b7DW*z)3SBxw`6&0)hbNh|a1Td1{=-upP;I+k&? zk249PjrdGuSEFk+r8#aE1=FbanUbc~kBjEp(Q4=);T6d5sE*)939c(OV{l1&TKTTg zVlE8BY39CWF$@}p;tQ);w=@`LuZlGNOhK~DJpLa`wDZ1&t5WqY&Na6sgL?JVYl&c? z)q>x;g}JjD?_@QbX|=#R`oAJW{(2Wl?mmLzsL*A|_OHf^S^J9^7(5FANP7D@g5N)~ z^RdyUSPET>uS$dbhpY@Tce%4pWLvfEwx8N286Id+6S&!Kx`O|V;7KBG>{E$s$B*v( z(W^zXIxZ*S)!b9LsCT}+6(%2R<3LOOI~a1$*+fm-oMQp)B~ygvRb6aS&gDs@(l7nRHzgg_Dh3iQ8FOS6%21Ulq~&&H{EdbQX8=@UJ0u$LUt>Z2WJR z3`(^QE5~wv*4qo-!%Wa&y{jWdtX7ff^sgUYlJ@SsaIb!#ri_*geB=4&@2`|pWzjjz z(9378v+4JA7q13qi(LhOlFQaQmXR_%>hBGSyFL+)B~w!2IHFV&I5zV@b<4esgwV5@ z#43FdRju}ZQciV!y&1(EGf_|7atX&6cTVVbR#`M7*5-|&h}Q5Z|t-O<<`<^uu~Yvw0X2x!%O33>*P|jG}in> zIE`<~p0KgnCv$$`@0F+%eT0lsqLxBw)JgI|sqb~=>eM3KU5vr1 zMLw@zfDpFB21dQDNSeI^iKUUb^S-)Awir~?WYLh;Dcf`yJdLHrP>iQuR=EXAqS$NoO zMjVm)e40B4OMb?+MRlY3Ks=*uxD$(_87Cx<+r2}EKKniaF@uWZ2i3d27?49&9vNL_ zdnToE=Bz`65lef$ufDW|?ZH?2j+9MsJMfSKqmFrmC(Z4$XkK5kS1bN+B34n-35ieOg2u_B_m-o~oi_i8i}E zwNEM3oO_YBVJlg0O(>emdGK>$Y;}LpmtG??{|_pvD!$Xa%90*F^4+NxIvZxj_6`E4 z*Y)ta?p1>Xu!g!*tjs0ZV57d%Tv7R(EW$QckAYI#^mYd=-)~Az)EFBYO> z;nQ69htpqn6Nh)~J{3M`PXg?}nnxo#@&;Tqul0n=?BGj(W7bs)k6NTZ!8cpUm1B^Crf#(sqaA-F!fU7fhp`Xz;%UozG_2t~!nZkmDUrWU+ ztv@rEyV#MZ6tjcVY;2k_1bJGgEJ(7xT#n^@Rf5K`(4=srzW5(teaeie#X20xGCM>F?z zJZ|NbSz2xME&8gZGT+31K7$_CxUYEJIME-@WZapw#lny9Z-Kvo!W^FGviG_Xov}uFEJ4%9n9l zA?fu1yUllZIM-6jb~S z;$mdf2tg^Gb;T^@vI)1RXF;+S_DhoV_g}m=IF}7k%B8hrzco`{SXe#V0S4vkM_ue3 z!oBEhcezDPO$y_9NUDu`wIhV)30VSYb#ao!)D{PE{AU-~QOk6|9@VL`o2PCITCT~yR(i^QBu`~MMmq?zR(YvBtSLYsbJQL?H$ZZk~ zwa;+z{cF{gUNL``L)q_pIF!D!s>8?;hP#v-8L3?DRRKq-vkC_xrH2bGmU?|PbL&IX zu;G0re5P)arTo_JQpDG6%-w`_(WMvAUeqg$W1$7X2ybIbWa^Z`AS=x0^p51?hp zSp01ogHg(y_J=WEvr%ZH2L3}x%%D&?roV^8xZ;8h*5P?#x$j6IrWbh`!*Q@F#h_`a zZO~lz6`C2#R>6K1U+l6dJHKSxxCkjs{>xBPX*!0h=F-yKC3dy-rD0G<3^YUEVVbht z1>wr?`PiU&7iNsKJnK&TPixCG3{i$Z)d9(XtV_m5+J+` zM1AcOhIzTNO4$D{ju~2`W;}(=a>FjGLfJt!N2^8DhEbVYI@&(@!KCmTY*V^U+X`Fv z8e5RoB2;RIdvCm^+8Z+cS=osk(B8|&U)q&bZs>oSfsf-+3282I&!3(>Em37^2;)jC z%8uuZO#`^9|2JVMs{GRvPb+Wslip@4*>2uSe#so=q3#}N>r zPAqc`a9R`IY^3|HH{MXh$rG^|GZW|P#RdUXrAigDQW+mKjbn*mjM2|Om2mmV8f$C* z7_ORmosu~JxD>xw^LpVmE$2WL%3=#sF)vrFCoY(HZWHah-wS9z1V~K?{2RHZ_kCh* zj66F9p37^2RQ<`r1Z1ff;bt`bK_s;HiQVX1@fe(S$1vQi>c8cVo3;#;o9$)wk@nHC zj=l%(W0nuwcFI~4OtHQu0dj3pWBjc9<=ugTHD7yi+{d;Pj?P(;p}k*-J=)lt&Tw4s zBLNAn&SQt3{f;nLkP!s47GwQc^_w~KGNA$LX*bpq1Q1xCeP7$=X>X978^2 zuIf6pSBmn0-r|seUmh40;0s(V?=Do(QZscrZA~#mv7y+ZE2V@m)(hF@vKyS653|s2 zG?$FF?&n67^5_oJP|?4LYt;1(_{Xe)C#^cM;9V=W1#8UvEb4J&m#KF>aTbOd$pdhe zvOa<|(49-8sa4hkFl*tnalGDVs^n*x{yYK|8Av)SVe+u1A59~%jGTqh!noa;JE+-O zTglaFzZc=38~I5xCqw)&HXgN%p}rt^&H~V-9KR;9{X1eH{p+0+s9*5lUSY%y;R@vVA(P+pT4 zBT$Z@#W{1b>hz4Aw5+&~GZioPqjYqtKi}rquv<{KYT;^ljbAHnO5acD)fe(g$8viv zEkEa@suEB|D78o#{M?kSWsFgIw%S>YID;Fd@xXfne6ODNqNS(HbR@aH4ZyGKbM%8x ztNS|qQ;Jg%wDJd1Y5DS+`MR246JdNd$b;ri#pl5$+btlZnFf!G>V`=CXT8X`7@E?< zB|Ez>LX_E7zIEhV`yH?xJ~rIuDDw-KX^RB{TD9Gxy=Nst{d`^meTKYc< z@Md*MAwuTjmsD~kNOm>Sm-Yci#@RZc)ZG4L8!Zj{p`w2Dh`6fAKy*>w$gG^@QGqo3 z@7^v7LVNU4Q?~#e?QnkszD2H+h}za@47EDGA?C(E!+40*7!LAHe0%(2`3@(jR{z$X zFih;iNVQ=UZnVaZBeZIp6;tVB4x#yZE>zJ6C2=$cCX+{_i=eYUI6K}lFAPLy)A7v* zl8fWfLYvf5Y-u){cJ-zV5Y4+zz|v??T#|C#71$^{`v4*{yeayc>zwhcQuiF;G=BA_ z8mc>&?tt<@C{CI<9cP%kKa&TF&wDW=;hEH&@?TNGa_J(%6MjhE{9AhkLQb)A*s;GX z5iy-BlLl?~3Y}j7Q80t1b2L6zAv$U`d4s9C$#a|0RK;LzT*_=H&Fm|Y6eEK_HGlo( zu$eg%M=GV{kEHab;hxavwDW$eWVAaLe<~;{Wj(tclIx3B^G>rAJ&nMq5RT5W$BZ%P zr5HB42ad4H$dsNH_)uJPQ5K4*&NCyq+We$E3{8<+uzGa`SCz5Pp*JeZ4kGHRHN5G$ z)fNm`x$LBY`M-ZxanT${i&?TbgnH=-FtfsnNTs=dVG|5a4&%NGnJQqtB)q}IP5K)dZdKr{-)f;Gcy75>mJH00Gpv(d95ANB|#+CTFEl2T;^cPVY< z5n4>Q>XF!&o&~Qck2m3YQ~fuA^SLc0B6Tn4rti2QF~_49l|$_;``uc_w&D--)>Sb` z%_oYq9%JwyRIOLjJgyDe>l1!RsMU4op({?Q=#=sy1pS&E=ANMZA4g{$S4H*(aJ$y- zHOKDmd}DWaGIn<-gNmX^Nu%O`gkS(tBIp~%?(Uz?itQS!uK9F--{U{`bKjkFPoFb) zZoTK%A*DQ>h!bknx1d&SbCVgoTD~#d)BCPRMP|U7g*K*rbS$Nw{(b&G_x9z`{`yR0 zaG4^?{gsX@>Z3|B%CI(#T5RK3xrWDB*CY*VmFA&dbwVaw>T6_C%gTL~1a3^eIFz!< zrU2UyHNidz_{$sjvfn0xH+YV3$gNjA97{Q)+d8mhD-=#SES~5$W*+qyp|+D1^(486 z)_7gY4;no>i$A^mMl_9^WgtzGTvwr;|HmB=FIT#1hswBs;C=ZZTHc4jlG&#ax>34} z#pSHMm3%-`d#bzv(&enEeyrhg*sFOP5v+zU5Lw&zG8&jKH3=kbmfS+B_+^HH)29*( znB8t-9sOPVa5%eCO6OtLka$Q%YPg2_^!;Jl%WOtgeQ@J+S~_^7fM&E8!DCGGAO@{p z7jZrHZS`c@+a@zhb)shq{MCNT8_`%g4~6Ov27+F#<$`jwN)5528d(%m>9NVQsHdLN zRf#Myho^gA*QaGcZJb5z=n$o^meZWtt*S_3++NAhe96D)e7&6C)GN9Z;L88VjE*}g zD9ajIMfAVn5DQ0h>!gXU4iThU(K2vh1k2inRj?9KXR4(zh4Jk7(T!uWYG6zXIt)!W zXZSL9za%7njJe=t6%XZ706LDUHgK>R!fO{y-v zFpE($Q?mNN!jwi>wUuqsS z;|fOcO&H$DHw3g=v6-=UN3B#qbPuk&;MV);qSyTo(24f7oLIwsc`EHb14dBR>WyFN z2UzB0ed08h)EmhW32oXg+}v1j1aH(1HA30e^$-@L%gSx`<{t(70MdQoHUucshPZC+ zdWhz_>8`-tNCLaz)I5ov!MCuDaquxdYP!$xfnI;7k+h$`xB~=>Dr}%k`n}pUdg&@? z_iTc~%m)$T56*SPisR)Zx9Q~X50^0oC2~S#*QM3|=M?JWtDzS2i%xRVojXgfsITkj zRYBG<^)6SDLEkM0lJsVk)2Q!dd4%_*?>?wpZpDm#k*{tvR|^ZX%O6E!MP>Lr2E{4A zz-Sd3UVB5XWQ@eacyVkb)@U4Z62%)7>1}`sd<22}5 zBO|uZK155l;cJcYY^BFdq*5H4{dxNDD~XvIdtIn+y^YqadLgUq46%!f1?qQz9W`5s zP@lFOc(uoe1ekp~v@Z3q17pEi|MXDGf3A3eGwU&OnyJTy*1kWy!5opBy1u$3-0B^_ zry%o}a|ysqIYUruUCU!3wb?U2D2}XvmW{>NnaR4V^PO3zI+7UvH&-KP<_w(6%)hif z{I%VLoXW2WqUn5H7sJQPX92W-8?^$M@O?O=61xHW=>PnnuKzC=G8h55QL^G$b^|Tt zR^h^0wyndU>f#}x(j|>WgIqHEXytymp5`lUGi*%L$aN*AQwdaI1_m&Yy_CDQjUelS z1M2To-R{VIf=H@UNnFgVP#(c_x5D21-|xA_G?ZVR!mhFE;`EpH`f@eNW%?Pp9$^Dx z;$~ubO*g7$IdvPrxHfR-KO})~=ORkYLoRkP-DM%qOmCD#+4a{@ggbphOcUB%3~?;O zh5Zw?10X#6&K{aqcLk-A@QzN(jpl^AlCl%aSWd0!q?hRH2l~ic{?zYOJw!P&j=Vg* z7l}*t__Y!6?B!NazIujQtZuV#d8_G9-gj15(;>oqmkc`}3IoJl+`|Ypef%n>e^-2u zrTN}zV#)k@2XE9@^oDJx>o0i>wZUvdSo6?9mg_z1k*`}nQ%#*^? zcG*#dd!A6^na_4GxQwc1f98Y1Fsf6`h!GKOWF9N zg$(qet(*_-%kE-5qj(W~I@j;NyzLQr8Zuw!4~PAVt0yDd z-mi-RG3FA~X6@3)=+v-d7|0F`MN!J={X41uxlhn^Xc7t0eUbVHBaS#5z3{|yt+w( zouGU(48Y{#pfNkcD04X5Bz-TGDKG1^Gb07Fn4Ediyninx_@5P@Ydasol%DchHm1&u zKsl-@Ze>o4eT?l4r$3zi*I#V}$E(`?Y zfUhXRSn~%<9BB_-!8LW{4m9vfHZf>LOT&?Nqdo(RqJJKO^;IRq=|5UNl~vDRn*Fv% zG5=ZC4-vDzU=!`qeIM!>GC6DX%Ii-#GH@e3d*|Oz8U3jrJ(oX$M+T#(VhY{!t>lU+0}#rb z(ai@0^Rh3btMgZoX`xsBX0A3!B%5qcrun+<9%SlpC6i=D#m~n)VBpt>U-ECzeGZuJtLOc%S|pmFS-D zJYn$fyTnpak>3c7#}8yB48TzmKSs_*k`^N8q=KeIbNRONN{y#$9#e>4e}hhy(`&^2 zDj$ZFo)Cz0>UXxmj;7WMhg6p#2Vi_!QL*hyH}ET)!efCSoeRBNV|^`|kJp8E!!^eVqLfj+;C;jK!yaYlV%ellr+ zv(VFSv=n*v2hd-sTMV^m&n9~FUzdN70?VB8gJ$Ie%nLPT(ea1&E-wP8Cp8nW@)H+> z&vT#$^-mwsysrO^EzDrW7npGsaCdFJ$3|LqcXS8Mtx>!q)YCNrc$!d<(%d5(WUNP3 zBjK^T6V_C7UqWmxXWQ+xzy6!J)q-VN(ioXjlFPK;*I2xaL162GngDzyrZF80l9uss z%#rn6T4Y-YbeHTvn6a6t-)N8r$F@cfL^0~PSm9~RV$^TWU53%j_6@o<5CT z2dUFf1>2K3V*Beex7Zym|Dmhu;>^IdcujoGTK-TPmMs&{8ZR^RR?8ydM>~drORri$ zQs~&3h29+`>SjOu}8uR@Ys%k!3cgAXyXLJWyo5tW$<;aalcslZY)V@WY6Ng+Ux5)nit4! z6l=shAzoCbs2!F=R;IWj? zM&bNglP@4sJD(x)toh#=`I!5wNt~qyGd|Fl4{+saw>KjB-qJ{DbyIsT7^Gb_y0t2EAdkjEw>H@P%4dqS8YQukzUb| zaBU)9txua3L_H*Hht2UTAY zDD~r2(YAj5j%0yM7Z>`kAMHhpm+Y~%oR`9YS?(GdGUr~O#?y5VU`+Mvz!J>ldhx_~ zt$1(+Z(@K{xhv$=Oc&fwxe|@?v}r!RJWOaobSwAcNj?)9ih8}U>JJ(!i{$hb8#4!2Q!V};1alcXB;_=5nx|LruGt>xf{a^6m}IXei+ z)Ts?;0J5Q>@P0IOnaz)Qb4S#%-ez?j4uB=BgkYfWp&i_as$ikgZPye z_m>ZVjw8%e?9a#WRPnhCA?0(^l{Pj}#&3mzKja?8EKc+B2M`4ys+`J+yy`n67=-VC zK-3JDB@1O&9NN&YJ&3TeSQ$&+Q~C@M1J8SpCe@RRyrx)#OSHpo`X*+$5 zH-qV`zDYL_C;l)hQ^t1^)f}D`#nURoNqqXG)4AOp!Dek$Hvff z$uxOFh+t#acXyC&2?DYC?)Ms3u^l$hEd4KzUM{;tH%{B5?T)k!p784VQaJwd6MFiK zX*i$yAcjyyTqDox7)VzxB>?X1=>2buLb zZvq@iRcF|?7tC&_fRtjX+ zgYwkPvcp${zD^d7sy~?y8fAn@V4JNEkS5g9=Mb4o_JZMi=U~Y*S1$6=Fti2kXXfH| z07vUNn_=}+Q(Vc~k`x0QYY&RVucl&0eOD5tQf`^ho}EN)G78BF8Kq7c(MOY^IDMZ( z2@ri0Gl7T8SCbU9&-ob@|6+T&!%MEcSBL#RW!qxgCYxjCgN=4>dul~**2g4 zTiqS^!lXefk8+evGSR5CmV4WkD$~}%Rhg3espkrVhW4v7s!&5@-;R3Q9hBC>Xw;}b z@4?32Sqf6!EDlZeb^FQetLOuB=54u1OrJOa=B$z>1E{wgjj-0IH2hcX+z+EE$K`qk zb>;*d*tmU~P&CFKM$!6>x;TP5`Z1y^y-Nwv#QTCX|8AaI&l_P!D|{XAAw{nz>ezi~ z9#3EF_k_x53;b)_>Gy*10yMED~J!pz14C- z^HxxvYKu8drtbe}#I zD#520*c~}q3)!R>f^3poHygxbA!YTvO;@W?2{dBO=qTKuJc)$Hrn60{A2;!W5XRGv zrm_*yjFA(XN_XFNh%SQ2gt_0qrTHhf!q3$=AIn5yp zAfX%_PnZ}%4<#tNd={ck*+6CuNfqCiFRL1Q;(glnT%BrDy7rXz6|zfGvA8P8QQ-3| zI>o+U!wI-QC({~mU9{Ep6cF0aj_A+oOC&hH$>>&Tbsu50({Vy*MtgLoR{Wc2Gi%8o zn`pN#V`XdoXmn;KkHfFEV}2XxwV(>_J~(|Y4H@#cf=Z5wATY``!^&#z-TV35vOg&5 z%n`e`E)Wlr0)Gmh_RkR@KkboBOQE;!@ZaJW>amX6U`CrHhvn6!DGbbt$z~x(59|j%Jn+ z4lZo~M!UidGz`{0iW|)RkD0k53yB3~?m5O3KXQtx%5)%HwC)|ksBg$AQTwbnUsXob zM%+Vt?@QF`4`amJ`@Ht$>BV;eU>`adXSoNeJ) z34H-K`uQHhO=LfKRVsf&H%eT#W%Ql#6CG-qnW$N_A~2;gEex*oY33@*sgpN>x$Zj` z>Z{k_7e?e0G_Ov0!=PolYdF=pi%1SeAh!o{lC+jESYs&ysRQlKARg9B*gWys2c|B5 z)9qY^WrGD{Qmh9oe15rx_C+2T!}R5@bVp2XY*FhcyI1CW4WO~X({N~38jB|Mrr&%Z zQN1>PrP`)YYA3V7fL>Qd$%fybaH{2!uNL*hiFr21js`42<}F1OYokKZq1m+tj4E%6 zh|Z6^-vE|94kAeH^BNYllmrnb#}eS#fC+Y`vqJ`(-69Z4JK?n3j;Gw6%|R$psu~fr z5&pfp2U71M-l1IDOGB+Mdl2aO3tu~9&?ey0oBPb5f5XyiXmPGZSM78GL6q3Xj4f~!%Rl#cFvouQIJDRtRWZ+ z-UERWS=SqoxN1`RO^kr{OYuyz#w0Xjn8Bn1wcallc>aze)^znXerTGq)@EL+0d1?^ zUeK7Y2I8u!V{r@!^`q$Yq7W}dZ9xBV)I0Rw zO4qk<0Jr>K$J_aqOqxf%^h%VaHyWJ+f}pn%)H`xA&@rr!WP~aMMdF8zw;|47Mdkv2 zw}?MymoE|^JysD8#+!6ThDv55QSI{^;;wU!gaZ9+B~GsR*F~LH^htEUE~cOTZ(7KfoHI9hK7sk5}Hxhd{0p-H4pQRZ3N2T zq2DR|Lw}k-jZ$+bCe0w(UTZ#;EBCDVjhWi?yCB|t?H>eJ4lWnN_Nt1*SY>ueS?vCJ z8=oZ830|X7%l)AIcph2IH><=oP8Sy^JT?>b#>M=|rB3jVhL1y%;;aQ#&_bh1_@Gre zWEbc^58aC9R5>zXW<9ps`8&XV>9n`mB#G+OVeGC}ejw`%m2yB(i5$X2pRXL{R`S$c zN<)1752Q}gM_JD`kg{h%cp`}-q|BW!)`9Q@iH5GXE)h{qB?~0S8%&~)$ zsT+&^IX+tf)oFvzErG}=XAEOiX|)iL6MwTE`;H8{Ie|RR#;W8I36&8iP=$Gm8x0+i z8a`w#`j!CO4f3VhxnxmntmNi+ren?x52`UPzCb@r@dD5`W4g@|Ad{zRUO5<`C1pp! z=JDSH@3_`*VFrF&&Uor+w2jqu2R1MQ&hkDUTzMG{gA{Sld#8M0;=jY9j5?Y-^=cJ$ zHgZ42=6bxk2*C6UQ05;4k=$svVi|zNud_Zq=p%-=&V@_{ZPU#d!rYVwh&J&xSxH?w z0#7p&?_mNZS!PyMqd^k&_^OGN$1})>y=pTHnY<7_trt#`WuhmeXe;};xs%u9u2VW5`^JN+kk(?#tYR&nmQdxaqJ3Ys>2bb32#U8}S zzHtlmcaD`{nA~D5Wt7}>r{293Pv21@7Rm>5_G7FaIbjg2EhtFpzxQ^l} z+1~USg&8~bT?bc(oMFP)IA1U=k_};oy;vY1KYld=yjpG|Qpq`fBUhN&JZwMv;#>OT zRPnGAYg1ui%@BZ%-1U;79)A-av`5cFp?M?%8H|P%i9xMKsxN9ea$*CeA=~kd4<6{! znzm{Y2P!+m#{C@B=B#>Tl$8*0t3Vx;&}`3FXKG ztf;0J2cfkg3@Ma~8G+nTTNY-ozx4xdQc0AmuPnrXJu4OEnN8%XR%1liW}D;nY;VXG zl)oW18xIuwxSm=KYtfYnIb(J!tfzRq;w_+6XgwX6jF?2I)m^cer_1bHf%I7EW8>x) znLRaXYZy-b@N6#is;4BOKMX><`n~n2M_Y9)7;MwhlW8ga8BHr4RwJBI&O097n^=+o zU9Tm&0@p=4p2)(WdH!}1LGSGhkNfKo zdd90}D9dRS=(HYHK&?#M3Ss?^nRu(2);Y|U{Z|P${_e6OU^{lD!%g|_hwYqTE8<7* z`9F`64=Mwztbe?aheg+*RL$Xg)Xucd0oTyJ@>k;wIPHE%%8Zaj z;9B1kEcq&?Aa)yt7`8_IFzt>WU65CA|92*GoGE=0YFlnVS&vCghFsf{X@Jkru0q0| zoXXRg(@0Co)=9MMF1ruVGPTBG`uh3?Q1|pOq4)7moJjdp3C7H{eWWgZp&xqEQ(|D! z7@mz%IY(GH9?RsO6`OPn_IkSefM%6L)co=gZk0FtAmCPSx6^R=3Zg290}p^JBZ$aV zw^SH}3OcVKNtjbxi124KSd^U7LcF+jJl<{UFX(FK?*SXikBAdCroBHQz3z5`Ftl<+ zq=TlrH?gONE{#DS3r>(zlqeP^99QDS^8b!RRx36CD7v1OL8jGh?-83LVF9W!MrMhl zOn-BXhs8%6wL99o#zDGTe%=&|e+Wa%$0CtFt6?N6>}yN5Gjab2BwAycB{QA7?%@x- z2B9x4Jb($jvhTu~8P-6j9cqc6TGul0clAn80%f?zA&BiMiZzV^UD3CGq24Jb;Ccww z6Jw6h95WHgIVO!f+O93!pb|NdhgNcln>L4cAGB(<)h|MKO5iCF&V5QM)OIVUXwO#r zIQ{z-JJ^GMc5lQk%D!CZz}sM=D5U@C(>87#4aaYiGT93CuY6CaHJ_x~ z9KGc~F}3b>X2a0a!V^(SeZN3D#($8EaG_@~$g{11b8F>oiKqKrc-fCsa62VORE&)y z+`q?~6@Q?~rvJdAGPwj2_MI69-5L3|vvo}N)hI8`Ya;B5AgJxjE$r7ny#zY>)0T2O z-3oM?JBW{#yo2t7;&>t4L)~8pZ&%|E;0HzlabGp$;WoPW64jc!+8w8Tyf+FqSIe@T zKIE;wPQ)Ly%9Hq@Gf3kta2px1)F2{YnZcYxezSpZ;C`GifjgVi%C~di+Ot& zEuJH&EA^TYXU2aCnbd#&f>EV&7i8Cl{p^RC2^r9bN@Z-gn#2{THwH=Jgss%ny0x6IoTbB z6rxpGT?MUc-p~2;o|B*O*8;oZ4o2_Er)-Y@1{~%C_jn?|6KjOSR=ycW0KR%J0=QN( zf22N0 zT7{YfqZalH-qnS3#bchyRZ?2zTR5?51^Lr*>Fa4IU7h9$e55yniqB>68*5E36sh%? zFN%EfUI533M?xuM?J@S-?IOZ7C+B$Z=4&tEGHb5~o&Kwb%b1siceBPPrXAhnPpgcJ zQvf%5%sl~k`$SP(ynNSL2RBE7{o71f((7JIw>iFV^rL5`(Wu=mShaDKWz7cQjw^+KXz$HP%kg>uskF@R4fpRyVIN~b z=i}fi`V8#mDqmb9Va+crRAT~2J?xJ#=6h!2m;#r7G_o>B(4xJ%fcmZCMesST$M3w=PPQzY9eN;+ zTEbNjXS)hh#)`31XrGfRNnmwxFP?T9ifYXNWgWIV+}ff;CHmDV(5!MwusQC_SH0PK zXD>UOKcBCo`N^csu&2#MS$d_3V(wyc_p>so8$qJB+$WiHVr_}-Fa0CnukKWwK?ypD z5{x6scDutPDap>~QVFD2H}4d{gO~R6a6${h-Mrs5g?8svV)b)*(4YBNLn+6~?m4ym zlrT`%wBx3VYtm{&e&>a+o8PD6Yf8m@KHw?*82jjF8jF8~$yLDL=oo6X0;o0ZS&5SZW2BN&a0 zr-*Cx@xsP|;leVPHFOnxOCQhaUA$dqZIDfJ_7G)s{=J zr4^3g%=&^bs{M=MW9G+47*)%gh1=FBMOISol|)7Q2KlpNby6|ZV)iLB4UDd`D@N`3 zjsCB4;&WH8;fhwhd#Fj9#Qqqzv^zF|aCFHHU^z5Hf~kQl7@A$n_6KHp6`WZs|LP1a zJ1%FSl;v@ZbLVV8GwN`E#?vKMtV6hN)5SzB^4n>))ky`e*j55YIl>iKjxi;6vJ3v+ zH5Ah3`bqFzOqA?5E?DwWbrn>`nYlQOGKg#7*>^r&sBO#IheWmS;V@?C-@<9hJiN~I zN^U4qpY>XN)A%xNqbbDoCq(c(BxpRZ0s@^PVO9#BH;g9w*`bwuP~nSzwP+8Hanj$^#v#Br1pPCkeY6v_*&iY`+Mt2 z#6cQ{l|&!f*>36l{aOa^q0ybthM87TT;=jVIG9zHQxlG7>~>wgEIP%2GX%%zf5qG{e!a|iY=as0 z5Rs&EonJ^bE+8BW|uB z#n+XIL(OG2omg;2w~FZrYvvGHBGz&@1zgWr013_A>3u=)_2xDt?BXYkUpqt+F~0O; zG@$8FKRvv;@24T^u$Gl#LhSp2P&;=qY{K)^ z-4g-{e~B^JqF$C~TUiakCyM?XrZdU%o1Zx;Tm^{I%|X8Ktnzx@{NR+lWK z(>rew-9B##V$Jpf!HnS-$!FT@Y@oNg$yNo${d&BeRP;|A`1K{!jYgj_nz?n5X#Ssl znczvPh0fK0LimUIr(y@g+gcLVsTUB$Xf~7dWLEV&1WaZQK4H2A!U!j2FpD;RH7Lyj zL+}8rS!;>G0vFfNUW`dG{+6LJPGyxILA$ZDHo8$<+JaI^eFJfIX!JquqAG>7+5kxf z>WUxK^&2xtghtN#ObZtn3>Mx0_kbpNiW~I@g?TM#ZARe?O0m6RbSl*V6`R%i?BdGR z3FKj=bIIde*Vcv{=cUzzTHg#KrGq8!a_htvnu#dXcP)z(oS>$mtn@>tp>@&=oO+oLFd0^E5uIkp%$2$B6N)vb zb;d2VPCdj91Ir`5XI zul2(as#`Xi)q92EQt#9>1#Ub7NWNNA*#>Lmaq#A=JkXhk_iB-3jEQSVwdS1mN1=Dy zNyea4PXK-RKd>0vdxJ&0Sqjgy!h1tQt(6}iwQAm(42}LNg8j=uBsPXzLK-V9UHGWt zigGQ#T#RZ@#js1bU|AtdLE>Rgxi_^5oWhK$Ox+ zfV3VP2911`#Yt-X&R3o}fw8L2kn}NPn=7T$R6N>vxc4%&hvYm3%r{@bZ?29dfdng4C^Omt1yP^=ST^Zue{53Ne@V+u{Z`Mx4I_C7! z2%+yP$vD%;Fwd3o?ugw{UR*+}vsX-7eLe`a4MzzVYtwvp>a~;bZLQik z&{|WfNO@j{ltzI%GJuHtc@Z`;Y^1QDh5^uN(ta1^m{+2LOS1_G>)$|BW=1?EkgelW z;nWD+O1s&$<^~Y-ntd2#uaBV`(>J^ne}L{4#{!rs_K3U4Yx$O^&ag540A&6hdxrAt z6!01U_KQR>J8po(xGuZ8&HB9%!<;nxBuqbYB1FySCC1yh$0ZJ2s{2+xULWShkk-s= zfatBpoCQI)dugzH=Buzy^6s!P%T8SVq0&1B_DdA3MmJjXOcz`zCzrL9+EvAKf|un2(*| zST$Ep183u=!dlDON5M9-zX8m!USjk8$6-es*$q6}h~4zk(?)_pJ-uZL@V2qXsJH+9 z1>K-{6us`P2m-TK90Mw8uds!YlQl;KbpyWBkf-SDm_%OeK&xJ%G*PeioE-`SKeI=(fE|gz+(jV{6D_Y_rThn?)tn|-P?^N_HI8EA z&x3o`X@(H`XZf!qv)>V@Sv{)~Eb7DIk~PMZ2&7YiIv`U@IKhQc)K4-?^rs*wt@c3e z*0kw@vS02Nh~2vgb-i}c?RNfusu4VCd#aF{!jj@?Xww|u(R?Md>H$4SFXlM88CfY9 zg+bIgThOGsdHQk?Z0jwVWmsjg!nk$#owcYBQD|+JGvwyg>}Xi)yHx^X0LUsBim-b+jA5#K=ECGgjNTIuRnHzTnW>VRtldw0lHIsAqQJpl0Q9IF@m=IPqo1 zw55~QUV(e#kS_skcwRbz6#YHnq*r*|G5 z%C7RKB1Y=;2)n~mX7ZFT_4a^Z+G3HYa1JONabq`7Zzw56-93{GYP5WaPP9hBqQlvh z?CgVY5)JM8i}4mS$JBu|Kb*=3_1VNtH1w<*Lc{+i7?3;I28%1x($KZCW(aO;zMFOg z?EiUhgX;Y{;wN?A?Eu+=i<|6@F`fOmd_=>gRbvA}d)CJXtX3BSX_f7_E_>41Mtt2F z(N+Y=qsOk`xB7GqLgd%`U7<4JH7YlUz9({wxb27Rj`aGNNlCuvMe~@_khO~LLW@d_ zJDSrf&J^#r%k8+z&bF|om+HEe@_#E$o(7!(jgqfGq}@?*{z{s=<`IMTYP*~H?o2dk zX2qiv_2uj|nge~ns9bBYgZ6*Zy=jTtngAACDoWJ%&-a0Y8ZzWp7CykGtZg+->H}H6 zbezhK=9TyP*8upg^*Yexm2F`9hO7wW`1KLSGd7Ct8#Oma{f;oS-I?w=Uy*BJoI*5_6iU}9wsoL+B}k9DP`3W_l26x!!RC;t_0Hl^&AkN_1 z0VdT+9WOGs{t<&}U;Xd`Hr2p@zRZ&W`PJ7u?c7ik$*1`>yAP+nwhlJe2&`O#|JS`_>kDI>Ub3GEY?1j;+pem?R ztI;QvmgmKIml+=wKgtOHrGk&qw{Z~hsX&tWz6wCS=|LPr9dE*c=5<_D9~&ozjhX}p zyWXP*>(=rNdVYN94){iYp{ERld9%MvBU)wy@TyHJ9AQ7gc_gr+E}&)o%8x#Fj^a&@ z1EfkNR8TY>3CxNQQI9fa)-E_I@>ncWvy317R`MgF{u?SFe;i|QV;Rd?d90X6l53%p z#GJW#+hO|b`&-IvZ^Ug^E=Yq!i{h#1AvTp3Wliifo)&FG%2VohCIJ_hTV(Ws(IK$d z^Y@maV_#%Y(De|AwKBbK)2UH&Y@=L$dIOlRH+F&YC)b!b+LgY7GIBcb3ib4WXK+wx z8y45x(tIh`Mc~v%ipyQgZ}--HIR>Vx@>c(vUFn%JBP;^6)OpgQ;wenq{W+Sa4~z)E$S~` zTt;@c+RssJ&xUYe%`n8`dz}79eU3kd)CZNvZfY3^Ix+tF6D?^qO2N$e5};JSb_bbW z_WlDNsuM%u0}@U*aT zlKuntZ=^ZoBY3ScP4M~a%dv*~@GD9-bI1uVHP`X&fPb3ePkZG@1in?fzi8vabV_TN zCtj@XnU0qAj$ep9y|rf$Y_#nLRpWaivnYM$Cs4iVeFQc#9!Pd8P(6}*{kdYR!*>W_ zbA@jvEq(dyad>tCi}u$CUpr?z?gj#~5+ThtQVzFyL}0iHB(g&)Xb!xrkfect!l?`n!oxTQYSi^#^_^R<95!${#xqCpK%h z2Z83YWfS$61MCRa=D{AG+IG@cO$zsB?et$j^w;d5{h?JYpGf`U0uxFj_id$Kv*s{i zsUh}Pw0ZDhJ$}W2&|3c;73hz1K+3A^mP)BM65CdIMl@)*WZuMR_Ke8Z@24TX(S03( zXcStFm`WGf^{y6>l}Y`QEWH}l=8A3?El8rCuW5hEcXA1blBa0~*cvYLq1VJBM74gi zHB{6M*TrgI(s2^SYdx{3XRL!yWo%8ToA)ZDP|mE!E5sV-9u5!rnmU0$c94~>1!;@qg(TdgN-Z4S9wW4vHhnK z@TfHT3ciH zqv$lN6+&C1VwUxgs zHaDylPg+x+9IAeo1wzH`Vj8>1u0T~k&;g#zsSj8Qy8ZhCJL{^b=-sUocE^l`%RqR2 z80yykixwAoUN{hh6>|CWeeqtrqT5fDYi0i4jParHLc3#g(=9fKDoc;bnDKn{Jxky< zpho6Mh03~Vsgf-jS=4w;-u(0p4>U{9#&}wES3J`i8j9~Jc|J%gzVT=(#9Lh=-qfHA z%*3APBgvrS&7*K#^k@Q_+?gvHGI`tKjFxs~CCIi8#fj8e@?J99Ey2DsOESJ~GoH`w znkz7k{^$de&-oQX_2FjN8?ZPSbS+9Vp2&-s)iRIKXOWU{ zs=QhzZ@Ni)(2JJT0q@YiR5*n2bAzJjX@14U&8O2Kp(io6a!itg8cMw#XvTV18*nqd zCOTKM`bk{O<=;RYzHy@Nv&|(eW|d2#=O?+pLuq?D$mZB48)CIJ=RHu&U(e!c4!g3! z&US_qb~{H$VqNNHUVe1a1F9BkHhpgjQ?Z-VgSIHGxt8;$Q^V zl-$5`w15UUmzk~8PEh(tqSkh`gm-nL0+VL?bur(_zAbULQekx3-CPVbrQ<;!wnE{K zX4%BC6Fw6$YU0{cfLxZt7Zwdce1G@ok2k3F1)FnNqc05OueSqOO!tJ9uiW1%a_^EIz3Ic~|_qSULP# z>oEcU4mc{jUH*Uz>V8)OsDB!Oj?G9P&|AHB!@p{0;nMM1riQH@r^Sr>YzV3)RmIeL zyD4I%e^XNJKh&$|33Yv!9Me|X@|n#CS0J>lI1hBBB=0eKy0Rf0>xD89O)J%N1NB5Z z1eNdHP3dskJ)G*OBoddBJC87YatjWw^&S*$<2r!hATa%&dC?v}A)L6JFFr7QDb_S5 zenp$=lLGF5cYYi|eb{#Rvqn`G6Be#Rp3O2O;H;i}lty|fH}C`PSOlke+o`N#*Bdny59PH8S~(zqjL)B4#=nA)B$&T{P) z460K{qDCb?hQV`=>vU53|3X47v~MO|YdUR&-qB8gn4WUofmX_(ZZzmFapFE*GT!|5 zIKGi_9@AQ(i{MYIatf)GEhAIF6R@c(Ek8$L)X*DZ{n69c*&N-2;oYczKN{XAR6EJC zYA=9|I}O4>;yZ*KWe?<2G3rDdg#T;}Qsv48gtL}^ghi8?9@uJA423D#xRHP@A&psa zsq2YxNrGt8?6C&F)m{}P*v*$NpjDm>0MMK#e;#VC%O%ofD}ogImmcH~Yr$c$fmb-% z*B%6|amMkxRqvq`}EBY4v-9F3hJ7 z(Tm}CX%ER*;WPXD1Ef{elc-)f6X|8=T#EBz=scVNMrH6(=|3q557f4E-iTA$7rY42J20iDMvLF$_21WH@iAg)=We?|ojn zT5Z}QwQ+w%FfE7LkzbVHe3GdCO2_zG<-pURQDsw}wKRcuZ=_O!hc}m#K#e*X$ZqD6 zd#;Qg(ST@!f|EeGu{Bmv-_JTi*K#_{>sdV|vy2+M4?zx&J`Vgb;Zk`yK^*nQ^8m`P z(-BZ@ms=cXO<9bidjI~ojh%udYT)lpMLYeZJ#NHFsK3o0MX$R*wj%BI7{Wq_V*(OR>t6XgtWw476JwrSY z-xzmAbea2xSa!`%m^VvHepc@n!C-32EYbbRx%4%Tf5!*(8&wbUw*&>rL|T6hV`#27 zwoneAasV_JuLGi7%0eI7tk}&k>HC_gp9UKekn-SIa)BPdk^F8>xEqNkO6>z&Ynp32 zfOpRxq};F>rCS&5f$&jqF8-{o_$e>l=d~x&cialdTD^x(1w-8Mg>c`tk}JBIwGyK$ z-c{+VcRv^a--`~2B-gw#xxS>RB#g3y!+>o2j+jhgGujXBM+l=hV|^KvtN5)U8nr=( z(m*+P5DulcIU|X<*bWJ!exBkp+9jAZ-IKQi6XFc}=8KIP)Wanx)eap7Qg)v0NlV#g zV79Wm2|H(2?SlocY^T{WHQmd@fj+t#{;NNBAxMnPb`qPFv0t8M`kbJ==1%^Ixl)fKe-AyAPDp+U=%O%+h_pEL*}z%y6?WrRA^mRq#^sKOM;Q14m)t zc_GZN2ZEBL413^I`(LB^!0&mF5!B!=JLr|`$wunm%VhvF%>(~72JeF%GfD=1>i9## zVBb6*)LkN_*ACeaWYv7^2Db7?X;-}0!h^PdaWH&#E{C3!5#yOm-j)t}^;|E$Q-&-+ zW9nH+C+5idLBjD(_)~BFg$!2mQ7mM{JjLS;eKJ~AH?551sZ%_Wr?xFlY4qK{4oa6B zqgFNVIr4z^<$eTx`}h&pTA{$>wC4{cGni_9xL0qO=NPUfC&KEY2=PJ3DRQ+rd-`g? z6L*5rTwfo3>+P5FRI}w@N8NQ|1pj@y9G|kbl!@bxlhzj@oiqbNM(bINfg3twf{h89 zRQfCXTdm-1&P4o0vHGKD^ZtLw0BJA=uQ4j^Lt<;v1KQOuRg+-AITe}o0qkINwESj( z_tOr^6!~s41?e;@81j<}o}#>R)S3TM0?pH z3Y^MLUN}nUnvzP4EbMOdy^1l^6erwAnX(nbE6NfHo|hlxHGg*>?Of!-TTst`P83#c zaxC~?-r<9`Z3#wnoNGr0WkWX){^9o2Zu*QF441|u*;8g}uJEn5I!x*@E7c}-DAWB{ z*&JIsU~nVp8G=})(y)ec`3@gOhqq!3Ges68v<*8$P~o1Rgpgj#CX}-;%%mJ&4(`nD zjgiLiT9QmX<|gS;z4@MOVSFxT!ods!H`AZBLM!UWA`mf7MdED6fH^2SbSZA4+*&^w zuK!#V4Vw4+h=Sg($Lx-l88B^C`2oAe$d7A)OQ{=S<6mJW5e1qdJJHms>-SKvUPYYZ zRW29c&o|ftu1QPJ!K%|ZRA9DqgJE;<>u}(6cFCaSU;u0@b;F1V%PW;q`67FQt#~;J zYfQV0AnLuBtVe{m^M`oRk|Y5$s1;q6!J)J5e6p=W+4_!_27nzFEJMB(wRITDA4i6M zc@xjox3*pny>Hpz)hfzLBxeXtpbk@U_oM6hA8@buH-j_vk737Xv0o$~m~ZM}N~10o zwmu$9sDnh(TS9UoPS z{bU6HqJZ?7_fkT*+8Ye7)SihNwMNlk)Jm@0O3!X`_k#AHLUibDpJO-kp=`A_X7!@Q zNSH!Y>iZ7uxAA8nU+86QT+RDqXEBVb#%fa$1cs^_- zpL2qP%rnHQac!+9GR+9`2g|aY!iU+>9|W)aCDGE!`!HzcdJ}{Co{G#B|MZx^+#>S{ z4pqj~N=!Xxfd6&#hO&$N-KuuanRKA{^_B2^*^tSajS2Wci|3%zyt_kEYdsb7SUU>} zTLnBrX$dKch}Msr+hL_pB{H2H^Z%#R3IA0Li-|xnQKuTPh$$=ntE^SvGJ#Tk(+J*#eJ;Kb`+*= z*o`6uN{<#BU_NIPu|d{OAa&#S+0Qi_X|YCB_kr=%i?Fl)yiX>5UvGm!wMYVx z>b4(I++=p|0P=hb#pc>Y8|Zc2jWI~v*HOUvJE10H|7=1^&7ahdveZ)E24*STLMe9w zk5mgS!w}{<$rDOB89=M2f8t7}UsKGaO?MD4>Wg?>UCYMqFUP$CkTAE(6_x6a06s7O zb}{Hvgww^mXCn?Ez^KKn6lPV&Ze0&9ht8c{rznq=bhkU43t`ta*#p7<$18$GYkwWO z>cCN84(LPXP>#s_pEmCu5*us35NFo(E9k(=mkI%6^C9FhFP}-aGg$MYtMRLZ=%e#h z3~80OiDk@dc0_TG29Fsm%j@RS_Ly8d*hnwSAcvc*klHB9{E=@D;tqNNuUc?zUM5DJrD;IE zX@oy0-p&NJwdXEW^|?>!Wu!!Hre#QCx}BSOwuMvf_+Kb8Urfgw)~7H$&1#>OYR81FUMP3-DzJrdyC z^En?4{^wAi;Vb_!rw^{!>J8-(k8?4wBC{Gp4Ku@Hb_< zsqy4+Uts>Iy&YCte3xF=o&#eTKTx!_+7u`E{u2S!P7U_Z>yLvW;J>&4r5W?&``BzA zz5@(n{zTDAiWhUeoBOW>Fnc{LsQcl&JjLa|Ts9nRujiAQQtH*G?=4Z#m8_ zIYwR+Lg8KFVI%GlLlZ*@aAECs8qkWZP7J*K7!aKWr^i1+CtB|{ z7i^9~dGR{)wfr-R9)AQUHrB5ttjx{F$q-h{i@2bb-66@Uc9S!3p84)DrL*jd&~}N8 zX7!KaaAPl^PwmE)Ba|zehtQta86zsK#=G&<*O`gT>s5DxEcm+4AD9(p&fYBn@r})A zNLl8X6Je0MEAy?&#vDt4Yjp`*t<5|sH~0{~@nsQK>rfiHhEG4Z(he^@1z6Wk`|P}{ zn?TFT;mWH|JGKK4P^^(+sR@H(1pc@<rnRzxut=D9xBK51i_rtv6U3#J7^F7qlu8D3>h3K(y%mqt*6_Ai zrffHu(*7xcWa`ZpBBilSVyJf!l&$ZIy^KosWJk@K!}%0X-<;(I>ogONmBMSo;WBQz zowsUWAP{$l<1mJ=n+THh5GEDxt6}i_A%Ue%I6+tM zqp+bgj0~Xc`5gZ>3vm^hV}vK~Q*B}n@?M=~VLbbo?JRvR$0D7UyR4s`KV13~Q|U7g zplxkV31l?p&tS=;)3IG3$sJ4FE6;nP2CIRS7$N18B*j^>$y+Vxx(t{FITwH+=-mp? z@5jv@V``BgjL?itaGFE*38>0(6rd)gM{qhdJ%fiC<3yrTDvH(P_CnO0HbTl4Q$i{4 zr48q4Y6k@9uq7JOMP=z%zwAY(%>OAGgw_9N*c?w~;Hw^ah(=7OE(Z`a>Jt879J=cd zEAigq?JWjjDPzCyCCc*hzk}9<+$j)!RhATF-ptJyvQthJW6atT%)`JO$q@SA@15;; z4wKi(&Jr42%zqbrr z2-aa{MX_#_7hcLMqTEkXn2~cV3RnMEN76|2NpzxHCkN4f_LjKrjTL0V1qV=xUb@|3 zx>lLu40~TbqIPRSJIPondy!IW<9C9VMSo19ekE*&&Cx7B54G28#BUa4dPC#&N4!e? z&_j6LUBn$^k1|k=mBqnr?hTV0wv~*|=)fwy4`kZ&^Co{ET(dt23SaWH@n(F0vGfZz z5i?#^X;sfUgXmOZ8!Hjx8euW(R|p2S9J20U-ni?@!(9Ip Yp4_(JjPous5x)5~M z{Gc%ZVW&6nN6YPpUcu5ac1Ip|SvbDs4dZuF`HLoNeHGkC8~J+|vDFXrTm5IA1n<){ zQNgE?2|S%2h85J{rKBdM?nIPj%sI3S$k%<*r&%K>^L9O(6EsIp?f|ZkEC8#kyNcfb z{YX-Jo_G?5KHotl=D$9e#(FnpCpUb12)BdM2^4L$Lo7CJHq?~ovT~)~Ep>+WS3htf z)A}<44dz&bW{m;aLaFIyra-I>yBV!*sUr3YG43;#Z+ zmg~lL>XY6QFiOwg|BHLN7Tl=ioVRmMB_39_^0UEfoK7>~;LrT&v{V>?cj^E7;jqSL zmckuZ=fSmFWSXRwmBaj?5#1HZv^B0o!;UXOz(wUhh&m>%ATpFH*HDD<&1o)#>TU|M zvA=&^5*Uk4m8T12!9;83?*y_2fh;FP$e-AoFV6kHqw|2O;^^YIy!^S@{(dZ4wa-F?TJ3M9Gse#M=eCUxl}xujD64twCu6jW1wmUKSauikhxVaq*S1MN zZ0#9zhNS?>V5`Ju0Kb0OKZR)>U4p;*bi8HdmDT*}@tu5XZu*#r(qGQO@xHC$s`ift zNMq$NJl3~U1V)9)eqQD5OyX6ENB|#JD ziv62@X3%1cl9>j}TqAC%BcI!pxAoA``gtei>ei)1uKvMwo!w#dCQh}crNlcg`zND7 zM1Th+*Vi!&Po4=c&iAJIGu`I;^Wv6u7Ul&r7g0RyI$@@^FNp{vJqYIN?>oh#y@F^> zEKN35YMnlyozgdc4-CpQCUn$Pc^lDg%THCC^WT8GW~0&N_gz0AN(t`^R@RG9Nr25V zl+?eqO0_xa_awOWaifV0_3@=JJ|%ykrqy}fdMFlOBZBmvo&=2X*OG&999K0I%~sBk zJihHr1{>|p1A#F_mNgkQPvBMaN>7^Jv9&i+Fz^XEX627bK-DVpwr>@B2{V0?oT#Y1 zd(VioU2{*0^^&pJ@$wTSs@?*Nl?#d3YD~G41mWPYWUjYrNPbQEKoseRGq77NR8e&5 z(q@kRt5&%(F=l1gpu{L7o2irvvzQWC983@>!{w+Lb3zU7^(Z->M{Cd*mPU(lyKKxN z|0=+}izeTcm!rrOW%&g_F#CGTYee=H!c(s>G8EP3ml0={yaFG!%SWKF#vMa(wS6B1 z>f5HrGE|iHw&tRL7r<2T0#erh#>QvlPG^Czo-|T#=Y*cLYlg2vrs^Htk}%8Kq(p->*-XgTGi!O z<;(=v6VSIijl$Zs2ryIQsz@gPDQ{s~>jt978C{UR=3<&3iV-p96PvToeDU7tfpOuVk`y7+3 zZkYh5yN4L?di@PRP5tCTJ1gT_iYw+f*~ru2+%<~bjb!R}D4${@THivcU-idsW7uab z(EI%Wbj?R7t$s2kY-G<}ij`&t`K;eBjtXj`%vkFY9gwSase<0tF1u(vAP%dP9l5i| z?sZ5cZTmW|>YE&KaQaPbGs~Dsa62IL#!8EQ@K-P9c10J*!c$eRjG>mb9b3%GNt?Nk zJc;J&=n2$S?tT(4)v#^h{(VrQoxNjns*v@@oJ)Dn-Ymd!S_tg=JvI|Lj^7~C_3r8J zJS%=gbnSlupDLG+`q}xhjac;7&Oe2_b&Rc0yyxU_)t~;>3wiY<(DeWH5*yARV)7|* z#wOGb-zR47aFHe@E+~XbAC`zySJoql)S*MqL7uK|qkObXdn>gfX@a!ClsG&4+*f#V z;!8pTCrQa>% zFg`OuML)G_0Vt)6Jr45_g&xV6f&+~L_28wiwZ+5WaFJcy*LcC(uGfO)JZvsQMJ>++RJoPIwlMKFdRJo|>`qD1s{%M`ykKoptDc z`~5ubr>k*TJ9$zDG>3dQ*c{uEPExggh9AXW&IJQP{VcKKLm}R7ew~(%5|^&g**h&` z7*YPRcx&P)4{EP+!6^N2-&M$I@q^~ZB`}iOdlkA0>)Y^Dil;sFLLql2k~iVYF$%V? z3&)}B8!e>%5(kHA?hcQhp0N}pXeN8M^0s9(;@PR%x>Akm-JlIXAbhsfygWUKwFW{)AvL)MT=djIQO ztu-bVm@c`yfZo5s5z1uwxjS{k);;`yOPv4+m%n1Vw(ff3LW!zG%c@HjOnoZIw>euILlrY8V;&WUs+3#ifG|qDe<8)^4cUM!`EsOn9R?@E z``Q}rQ%(jUu|((*N(THJ1g|HKP_FAjC64#|AYK`8Wijge6yJhD9hwrO#<8{n)Uj!J zNH0<-1R1vbhbdWg40!dCc`4VLuRqQ;w$O5}OB0hA;_j3LGi;wqdWOFm!OJqT|^MOjJJPCHSzZA|@4EeoHbBhca zjXr1PsgF2XTU9rn@^iicXmR!f*`-dcMXRB>?Z7PS!AJ?z>8m{1XpnotQkATWC_U~V zEcN=^BDo*dAAHpw&5?buo@DCde}GZ>vRR@|b7BUhR!?*`Pi11i){tXH9ZRkTQe|0Y zJQDUL62JP)QGuK{-5&GxULV&{z0rz;Ose%Gp43Ci9;n|=qoCOz;I39UM8~{x%VvPc z-;toq4Csc~*4OZ)9?ddZUexC!Tn(Io_sogKq%+U^MEo{*5YeLj`|LDa!e#xFxzH66 zy7K`6XVyqcl#$thV=VQC#_V|}jQh6h*TdoC=U}9qy8~$E)zuO&Aq#PfmRcL5trTZT zxSUc*)Mgg%{gobb_z>$AF}$cQkSyOrlx)UJWC) zhbJiDgbm@*bu8Z1FSf=c>(=Zeu=2E}@O0o%nkemq?Bmx1ERx0SQGusMjib0!eO;MX z%JXh(AnY;YJe3;VA{g}B(h!^O^6F`n%vy;q&sRtwPfnncu{{NW+N}nsY;2THrHlDm zo}e@f4Dn@RCz6cQi#5206%|hs2YliNS=}~e6LtJPfv?`uwu_SN{#R^d>-h{gW)&3m zZq$@8cW$zqlCRx_X8SErR(dzV2b$Ar8XJ9jh~r9@|K*0`(=95(n($>KBh` z>Wz|@?d*5FiQbk=cWS9W4B*l;%0a2dpP?C3E41GLXO9Lt8h$PzsWNLK-a5K|IhmIw z*7rY79czB`Bsd=Ik7kDV#ud=5XMExq_mQyE_jLqMHLJ6v$i0g}nA7?2X3pX4A$I)Q zh1jqPrv=y@dt~Lmes30j*XmZ-iR!6snHk+t8hq3nPq5v3J|2|JVJS#f?q1o8oLjSF zDX$QK6Sd6RtI=gietJ!#W*UfBI!)%P$B#sy#hTy5|Ahl#V=kI}l=Ay?V<2DDgW0@7 zYb2KSm(lQQJQ}`ARs&ElT70AH3FcSm9dB3CLYsFzk!G&-7BBaou^F~sCKL1Kzz9J- zQqH$A=l@Pkt@$wWNHGs@g;l+s^^}A+?ElefDlHlVk}+fc zMri)GBaxCBW)w=s)3!T`%#MJ;_A-KCOk6nXU7UniYs(O#Sqo{p1~zfglxWej4FqQX ziV3=F2x=N$MRnNZDF`U)?CPYu>g_Idzvs@KcKaD4tZnkHWwo!3BF4>hIycMjcVwA9 zWuF%#eu^@OLU?*sACixS{!l`KMFDd!8*Ul#s|TdfJTkMIk0(=cDJKOE0nS7sR8 z{|Exa24lCu-1j!>DNi0@j?$^E7i&cWpip8?u0&4tI%4+iwP>o8lqA-QHwZv-NH(3w zZyw38D)pMcDXrU?D5lQIg8U~Jh%)8dnnX%+ ze`LY>eW*Zx>!;b!|FI+lMe+~CSgle1MQ|HkA&gqhTv5mD(_Dfur!ZZw`ydL8*AEe* zU5df$YL>YLLilRw84y3Yt;xt zkDiItG*X+obB!1UmTFbmTws)21Q#vN$ql|GyPlgtL6MdrO`{w(MylGL{*!|9vhP{i|~Wm=uW(i3CXUk zn&@6_6|$R{(%e=pOSWjwYH#IXkgRz#`{i!s@fs=3jrx#J9Ww?9;fugTx^UUEr4?5; z!O(3OSM8XIrdrJUEtHg9M%)++a^HGKRuZ&-FTD#jMy26Kqwuo++UEpQ~3|oq*c|T&{c6tD@ue5SK2A=^9g>#P`a_?4&=r%g^M{n!1Lu$n+ zn=!LnFotXAcdxLqYe?RD)uUD88K-`QrBUepSx6j~s6Vw3?ox^iV{3337RAn-%e&!h z4^%R422je*ZLX@Lwm_T2p)8K3HX%;Ea+qn0ZQ>5UBW5*u@s%wBhEE+@6>D)p+^5|eFI}YD zYHyq4C+Nq}(V-65FQYevTCMdeF}UgOsz(A|7P%o!(+ z(x7UE#{q&>Y$>C#7VU^-!@DaF^;1s;`?h1lYz&8AhjM@CAuU;@fIZx%rbz>LrL81- zPF21Q6kC@}ae=vb(`w0K7#wVW`4snlvL`|bpDQJ!mhOOiv*&3xUNwu*Z(Z!fLv6A* zMq6==5Ls9dh%?n*91rX8k923rRy3hzTuTNJ<#70BJKrX{#&Q32uw?VD7{IY2H*U8( zivKIfb$cl7U`AcOAv-liyte3`VB_&F3@%=>71+3Qc`Y@gPNI-?sqTg%8M3edZ7OBEihYG)DLD+V~L}~Kai)rj}AiKvQn{VIX?+2%~gpa zX;L||&`7U-l=3n&0M-0s22RZy2ch--6nSZeO{dtHl!Keii*16qzUU!tu5)!X3bgx7 zlWoLxPleK3*2`%A&zEx@GjTBhJ4Mk)C!9y2w$46ShV~P;rSP=uMpU!Z{lV1DjFgOd_2GTdK}$N;HRaid)|xSH=@d> zQ(XDW5x7K#ky=L4dl+e{%`c+CDdzx6t~TIn!US1*X{7eLYvc2|oc^FZc}DP=Q!brn zQG9>#O_6>St9jk)HvFe2{~x#tN45I%a)c4%=Jarx03fgP6Mg-WHhebmyUK6GB1H z-!F{o{e!1r()}Q=HC?vYMZ22Exc527d*-D#lJvJy!Nl6+wi{jzw@aLK`i}%w4osbo z7L!waC@(d9AM(1L14t{WkUv-V+_hnTS?ldg4t3_KR(AJ#^l**RVZSS_KIJ?1rckSB zuWfMnc>z6TW7$SvPL@_ueH135S{?-}ZSRN^pm8_ai}Hz13($L319C%oAxqGWQ(cHD z^WYuYHY0ffVXMaew+R)BX49ovX`FwB3awZ1YfZcmIcjF%KQr;&eoXjyl~~YU?b;9B zQx!?d33;>8iw6c%a=MdfP^&)Js@75lVm$p+GOOYb8^4x z+l!!`R^h@r^lDcGhQ=9QlN~-Ck})RLjOAh4SQ2S#3~jWL?-0z*aWQs^zkO$b@zZKN zsgBP*`r&y1z*v=C31(xh=PJy~UuOqwPtTJ8ZdeH)ny*HlM3*6jlVFh2egl+Gs_cd3 za9c1X?;A^CUG9Uk^w*7uVCBtE0H9u9aD?*X)hHP*8a62uZ zZH&*kD}3|)gcH;jZD=TKcp8wz)<&SR_b47UFKT4A;WcbEm0I81#Zw;{d+4QP=1PmM z3S%wNPgIDhC`y&T!uacpMs}F98XSO4QG@0{-I5#)n~ICjQa^h|u=^xyCe?XSe5Y=> zc@nq&?trGvi>FPn$~rINI_DT9R*AyllsCEzbn1(1=%lWa!LCwk5(cU+)tIYpH&ghA z#URgk5DR8nv)23UD7g+v>d-O6ksa5)JNHjHyXC8T^%dc0x%>qi{r>AS)OFD@T;C#} zGu27~yU_mRT=?ieLJ0!(^vmOv3^|8qjF8^or#vfQuu&y|0_ELi+^i>@m7FZm5Jzey zY7>6?@FYPiR?eigDs7Z5^Oo!1u$grMMU0^9)KdFq1CI5gKKL13W)Xl&@EWYr3TEM2 z-S?tI;1agCF?ZO9)=W=1Ee<}}>=5b?%KdhJ`e`UUzw8nER&PN{-zFOk)W54Td)wn9 zw?^I!0r0l0pwn_>gOgUfEkg7YFGxgdl6iq}>tQ+@* z(*Bl4L*F%ybT#tL425UrAVO5>KY+wA)mkWKgs)HL=%FfTsypY)K#`-3lVMqZE#pv^ z{X4kL&+Z4N7TO8=mt|e2+9WcCn#pWxhfr2ct0@+P2DQV3L^O!F9?vx<+py8+M$YHH zUIdfU6IKyO>X$)~sMX~#3blBpBdFBTYaMK|=N=N1=MaNd&Q_k90c$sLeI;{mYFJ`8 z_Z?R3g{A8k`V>vMM}k_v9p-Ab`H!4ezJzXoChFe<+|M~0g|ZuEH;A5-um{SLnaioQ z)Ll&`Q=QY_>|~C7+C-`V0a`|1M3(mg+Dt;-dDTY-CYXQ<4LD zxZz|XyxvU(bhb#7k80>Caa(_8R=--w`DwpPECCg>#mNyYG4H~yQm-qqqYUo~h)P~( z>@!|ja8WJ>g1m9FFs{=|IpZ{KXccj3)jQy1l#?R~jIvX>ng@Rd1HE;bbZnYicQ@s> zv2);g>$MJL+PX8GCz&H`_Mak))TWb&9;HTA4A#B}u7GgHL?1gl(GCNa){L!pyrJ~G z0ON9X7x6UeR{?8K8;nvXeBI7{TP4&+Uo{P$%5N@*xxd^};_Qd)PtncsnK%1bqc&T5Hjlf1o6?eXJeWE-gpYWr&?mH zzUO}oF|?e12IdTOfs3l}k(3W}fqR$-=}!=vdx}A#EE~8Kk|SP=xjvq@gDIj+097W3 zGk$5_W*-u^*SJJGe;C)8*E48Y)M2fVqkL;dZm2^R5Nc)_xRPBmPiMuuqn0i|k?4pV zfMMQq*u|2b z?XzjoRHy6|th_T1#jOTak#HjUBnL8hj{&NMA!34hhiFzWwWc{XCS{TX$`~C7Y3ZF; zQ-4lb0k{B5*}iJ7Gm;Q-!)GzP23Vrv%+fwwJ?`yB-nj90toYyG3(%-Y7h?F?MOZSl z3+7?(E~uoId`o64?IzQt8m{e0F*Qo!!tf7DrRwsJOF3Zn9R=n$`Ce`9IYd}!8L!cL z<_MD3D(ptgm~DT6x$e?wCkmIl$$M=>*SQF~Q8kF^;A)Z3-JXtNN|qetsOBAmT54a9 zaOxCH2WYEBxiE}L595vWdVP_0cJNM$Q(~~x_^H1;RreNvTsgCpFjg<9XY6#La(1+J z<1etXUj8ROwic1C=6`b3nBGBNwet+J+0LIQ0P-ili8}hIuebLmNR+UxHga}vqx^Gb9#Op5}WDAb#+Ig*}V4T2qZ0E z#X|B#x*t6~AJMN?k)ez>-+^$w%5pwGk4Te9?pRz%=D0{GZ8=F*y-1!g7(~cuK(P!e z=@W8iSe}+nq~w^4wUoBvD06);T2?J0!V8-G?^jT3$_p%1kN%Hz(fphRm;C=R#OzT4 z%@nmq48^0G67+^W z+-+eoyTfdQ>#Y*21=c>zu+N|3 znnCNsaDrGhD~o~iS094@RWUz~6#dPB@kTjYM5%fXFQ}Ddz^(0do<#Y!XRz0k_HAMh z?BqbW*IK!YQ+4r{$NK2zVn!SHCuphu%?P(iXJZl7puDtd({tzZUu;Q$-?VXu5bl$590`e$V51jYDtZ?y zjZFQo`DmiKWI?0$V2aR@lnQWWIpPP1E zxxj4GJUQpXaA|bN=E&PQlIP?8T+C!|laq+ekX061?28jzKb(YkM%+TQjOvA7w5_3F zsWr+#pykqaC^dc4NfT?3Kf$Gx`4q(UzOO$ena|MMxRA|LtztPC8&gW-H*K~J1=UYy z@s&32*g@#M<%d|zk&ZPOvFd_&X=b~usDke|az=Xa3X=$!3FdM6vq!hA}qQ1lI$9#lO@bXrg zK&Ee$$yM!npEyd!J7UkT|;q$?*B;w`1)3|M)7R`d`3>)L$H6DCik(wB%#Q~ zk}=SD{Q?8?#va(KCwdZ0dXLc?QFih6 zsv5s+5qoA#5JYc$lqPHWLo8Qf`E1~*a7Ns6Z0Q0jbr~#hN35m0T=dEVmAV%qZ2law z3MP#^M^i9;`zh{U%l>1%ZNCF7+{`0J7I-Y#-{a^`9%eV9L{}J@z1EqmED(j}%0IcwADYXiN-KD+LCK$Y z1=_gXySTo%38;$hj(TeSABWLnk%A<{xj?L)g@3Y&#OU5}C6r^G*YfmoJTz9f(xTtp zvNV(G_(9NH{_PnmbeDHpKFLM#Bfq=1q5B{AB-S4m1zB^=mD7|IqltI4x)#Q5+J!i~ zqpZ!aaSYH|_*oTd1D)BI-@|4mC@GwVVt6o?dTE5DT1`Hhvc-uc(eyM*l+U%nQCl7l zVET?|ab&RvB$6JnaTy9NKfi|G+>pgvTK+lQ4wU5;R=Luoqq#I1XX-6kOW??t>`|X5QHd22yR% zg?^B~-y+Nw=f2Lh>Hs2^YXv(DHag)StFjYGqQ7M0n4^k|G=cR7&{FElwWKAqQOjj5it#K1!<5eb z077dctGLY-M;Ai=*@L80^WK$E8j(+;X#8grso&%aNaw)^P;3&P>Ug8L1LXRf5E>Ni z%Vj*LMco1cV_*-#=lXc?QM+Xd@}u_&hNY5%L1tQ2iT6)6PQtS2JuxksWtff^Rf4G$ zxo;v5XMcmS;ymCic(km6N7ZLr31MqsLZF>p6Jee+ceoq?^S#XfLio zUVQwH^iDw<@N^|&@r=yw}lf_}35O*oXjf{9k*Lz;P(Z{Dyu z&XgCM_diEXWx~rO1_1Jt5c-X_XrMK1OtPuo$pny+=Ryj6NBI$H)~eab$crw{y%FCO z&8&XME+Xlm?|EvyTL{KliMe;MrwpqG9Okmlc88xVc(s-k08qW;z*Md^ib%A)m+fN{ zvqX@a{6eACbDG5N=>X!=tXJVUgafNG`FH#NCHM_tUcm8Mjsn#Oy-2q+gM8Jpvm1O3 z-N*p@1F9@9iOa2@3(@lEpC*b~h1aE_dG~L))hJgr5kcd%tCYVyw9CeVb|S)Y=MKs$ z^H<-rIX<5MhiC8pAzG|AJEVB>Lh)X5le?6Z-HnBcZQ4OZKm8pPRQ(JorM#Oc5$Y+^ zZranI;Gn*^a{~GzpOB<^$s~X_Dv}V_k7UQ%9XDsEF(hq$p3)|{@0WM{$TWTAt1K*d zbP}&wwknFlwMZZ6)l7b=lc|O7r;#1pi6}AO8GvdG<%B}$ zr${7?+LeTsJ6%WC!$AojSN!GGr0-lU(}ushmY z+kZ~uCo6{w^TX$9jvq<)McV7}R7n*BwuGQ$F@S7^@`<2mEK?2XwUmSUrSmj`5(_;kv#tg*JcSe literal 196422 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�+(irRtRYCOvoE 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%0A>n#sk#-gfL_ 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

    PlIm&H(4k`sZVl)XS3^ILxuvvSE2Q2l&4 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 literal 0 HcmV?d00001 diff --git a/resources/geneticReferences/attributeLoci/attributeLoci.go b/resources/geneticReferences/attributeLoci/attributeLoci.go new file mode 100644 index 0000000..b173474 --- /dev/null +++ b/resources/geneticReferences/attributeLoci/attributeLoci.go @@ -0,0 +1,8 @@ + +// attributeLoci provides loci associated with various bodily attributes +// For example, this package stores all loci associated with the brain +// We can then use this same set of loci to predict all attributes pertaining to the brain, such as autism, depression, anxiety, etc. +// We need this package because we can't have packages that import from polygenicDiseases->traits and traits->polygenicDiseases + +package attributeLoci + diff --git a/resources/geneticReferences/attributeLoci/autism.go b/resources/geneticReferences/attributeLoci/autism.go new file mode 100644 index 0000000..94e2bbe --- /dev/null +++ b/resources/geneticReferences/attributeLoci/autism.go @@ -0,0 +1,605 @@ +package attributeLoci + +import "maps" + +// Outputs: +// -map[int64]map[string]string +// -Map Structure: rsID -> map[ReferenceName]ReferenceLink +func GetAutismLoci()map[int64]map[string]string{ + + // Map Structure: rsID -> (map[Reference Name]Reference Link) + locusReferencesMap := make(map[int64]map[string]string) + + locus1_ReferencesMap := make(map[string]string) + locus1_ReferencesMap["SNPedia.com - rs10513025"] = "https://www.snpedia.com/index.php/Rs10513025" + + locusReferencesMap[10513025] = locus1_ReferencesMap + + locus2_ReferencesMap := make(map[string]string) + locus2_ReferencesMap["SNPedia.com - rs2710102"] = "https://www.snpedia.com/index.php/Rs2710102" + + locusReferencesMap[2710102] = locus2_ReferencesMap + + locus3_ReferencesMap := make(map[string]string) + locus3_ReferencesMap["SNPedia.com - rs7794745"] = "https://www.snpedia.com/index.php/Rs7794745" + + locusReferencesMap[7794745] = locus3_ReferencesMap + + locus4_ReferencesMap := make(map[string]string) + locus4_ReferencesMap["SNPedia.com - rs1858830"] = "https://www.snpedia.com/index.php/Rs1858830" + + locusReferencesMap[1858830] = locus4_ReferencesMap + + locus5_ReferencesMap := make(map[string]string) + locus5_ReferencesMap["SNPedia.com - rs1322784"] = "https://www.snpedia.com/index.php/Rs1322784" + + locusReferencesMap[1322784] = locus5_ReferencesMap + + locus6_ReferencesMap := make(map[string]string) + locus6_ReferencesMap["SNPedia.com - rs1804197"] = "https://www.snpedia.com/index.php/Rs1804197" + + locusReferencesMap[1804197] = locus6_ReferencesMap + + locus7_ReferencesMap := make(map[string]string) + locus7_ReferencesMap["SNPedia.com - rs265981"] = "https://www.snpedia.com/index.php/Rs265981" + + locusReferencesMap[265981] = locus7_ReferencesMap + + locus8_ReferencesMap := make(map[string]string) + locus8_ReferencesMap["SNPedia.com - rs4532"] = "https://www.snpedia.com/index.php/Rs4532" + + locusReferencesMap[4532] = locus8_ReferencesMap + + locus9_ReferencesMap := make(map[string]string) + locus9_ReferencesMap["SNPedia.com - rs686"] = "https://www.snpedia.com/index.php/Rs686" + + locusReferencesMap[686] = locus9_ReferencesMap + + locus10_ReferencesMap := make(map[string]string) + locus10_ReferencesMap["SNPedia.com - rs6766410"] = "https://www.snpedia.com/index.php/Rs6766410" + + locusReferencesMap[6766410] = locus10_ReferencesMap + + locus11_ReferencesMap := make(map[string]string) + locus11_ReferencesMap["SNPedia.com - rs6807362"] = "https://www.snpedia.com/index.php/Rs6807362" + + locusReferencesMap[6807362] = locus11_ReferencesMap + + locus12_ReferencesMap := make(map[string]string) + locus12_ReferencesMap["SNPedia.com - rs1143674"] = "https://www.snpedia.com/index.php/Rs1143674" + + locusReferencesMap[1143674] = locus12_ReferencesMap + + locus13_ReferencesMap := make(map[string]string) + locus13_ReferencesMap["SNPedia.com - rs2745557"] = "https://www.snpedia.com/index.php/Rs2745557" + + locusReferencesMap[2745557] = locus13_ReferencesMap + + locus14_ReferencesMap := make(map[string]string) + locus14_ReferencesMap["SNPedia.com - rs2217262"] = "https://www.snpedia.com/index.php/Rs2217262" + + locusReferencesMap[2217262] = locus14_ReferencesMap + + locus15_ReferencesMap := make(map[string]string) + locus15_ReferencesMap["SNPedia.com - rs373126732"] = "https://www.snpedia.com/index.php/Rs373126732" + + locusReferencesMap[373126732] = locus15_ReferencesMap + + locus16_ReferencesMap := make(map[string]string) + locus16_ReferencesMap["SNPedia.com - rs184718561"] = "https://www.snpedia.com/index.php/Rs184718561" + + locusReferencesMap[184718561] = locus16_ReferencesMap + + locus17_ReferencesMap := make(map[string]string) + locus17_ReferencesMap["SNPedia.com - rs1445442"] = "https://www.snpedia.com/index.php/Rs1445442" + + locusReferencesMap[1445442] = locus17_ReferencesMap + + locus18_ReferencesMap := make(map[string]string) + locus18_ReferencesMap["SNPedia.com - rs2421826"] = "https://www.snpedia.com/index.php/Rs2421826" + + locusReferencesMap[2421826] = locus18_ReferencesMap + + locus19_ReferencesMap := make(map[string]string) + locus19_ReferencesMap["SNPedia.com - rs1358054"] = "https://www.snpedia.com/index.php/Rs1358054" + + locusReferencesMap[1358054] = locus19_ReferencesMap + + locus20_ReferencesMap := make(map[string]string) + locus20_ReferencesMap["SNPedia.com - rs722628"] = "https://www.snpedia.com/index.php/Rs722628" + + locusReferencesMap[722628] = locus20_ReferencesMap + + locus21_ReferencesMap := make(map[string]string) + locus21_ReferencesMap["SNPedia.com - rs536861"] = "https://www.snpedia.com/index.php/Rs536861" + + locusReferencesMap[536861] = locus21_ReferencesMap + + locus22_ReferencesMap := make(map[string]string) + locus22_ReferencesMap["SNPedia.com - rs757972971"] = "https://www.snpedia.com/index.php/Rs757972971" + + locusReferencesMap[757972971] = locus22_ReferencesMap + + + referencesMap_LocusList1 := make(map[string]string) + referencesMap_LocusList1["Understanding the impact of SNPs associated with autism spectrum disorder on biological pathways in the human fetal and adult cortex"] = "https://www.nature.com/articles/s41598-021-95447-z" + + lociList1 := []int64{ + 13217619, + 115329265, + 116137698, + 141342723, + 75782365, + 151267808, + 7746199, + 114115252, + 4298967, + 1782810, + 6921919, + 9467711, + 115707823, + 116633139, + 115123779, + 116326873, + 9834970, + 144762289, + 9348739, + 4481150, + 12129573, + 116408368, + 11191419, + 115242751, + 116385615, + 114882497, + 114867672, + 12658451, + 202906, + 13212562, + 7085104, + 1702294, + 114276265, + 116427960, + 59574136, + 114041423, + 7531118, + 114964506, + 111639056, + 6939532, + 6940116, + 116663187, + 114904464, + 145547914, + 9269271, + 114963521, + 140502984, + 61867293, + 115035678, + 9274390, + 11688767, + 78110044, + 150680405, + 10883832, + 7752195, + 115497191, + 116676919, + 11191582, + 115344853, + 144911693, + 71395455, + 5758265, + 2007044, + 149979052, + 115682897, + 3001723, + 1024582, + 115625073, + 9273177, + 61472021, + 12668848, + 184153866, + 115558405, + 150430679, + 115687605, + 35324223, + 9274299, + 138984909, + 145076523, + 55661361, + 911186, + 144304366, + 10149470, + 144660248, + 13218591, + 114455101, + 185717927, + 144649399, + 114086406, + 11682175, + 142972412, + 138748649, + 7405404, + 11693528, + 12958048, + 35225200, + 114950038, + 140865314, + 4129585, + 12887734, + 36057735, + 115052633, + 186129480, + 2507989, + 2021722, + 140505938, + 2388334, + 3617, + 114274203, + 281768, + 115937317, + 144018888, + 2535629, + 4906364, + 180778602, + 707939, + 8084351, + 80318442, + 186229361, + 9461856, + 113397282, + 28681284, + 113205291, + 2851447, + 4380187, + 115960997, + 1793889, + 142790902, + 111312615, + 144532965, + 75968099, + 115661163, + 1518367, + 193267147, + 41293179, + 200986, + 34787248, + 140364877, + 13240464, + 1625579, + 4702, + 2514218, + 778353, + 325506, + 182908437, + 149721896, + 6434928, + 4713071, + 11753207, + 191843781, + 116182620, + 2760981, + 116067082, + 142601889, + 147976543, + 116254153, + 8054556, + 114204022, + 115165987, + 9636107, + 41563, + 35828350, + 764284, + 115325719, + 7193263, + 149915948, + 17843707, + 79879286, + 631399, + 732381, + 1150688, + 189600472, + 3798869, + 5757717, + 145501595, + 4642619, + 117616320, + 12704290, + 2176546, + 149787317, + 11570190, + 4391122, + 7071123, + 12712388, + 4307059, + 369637, + 114291394, + 11740474, + 12925872, + 116460775, + 114838832, + 10791097, + 35610290, + 114812317, + 9469174, + 7801375, + 114508985, + 6704768, + 4580973, + 147875011, + 7893279, + 12966547, + 9922678, + 111294930, + 6047287, + 34215985, + 2693698, + 12826178, + 2237234, + 11210892, + 67756423, + 9787523, + 10108980, + 2057884, + 1498232, + 8042374, + 142520578, + 114771361, + 114810457, + 17194490, + 145470632, + 36063234, + 2332700, + 1615350, + 3735025, + 115283957, + 75059851, + 1730054, + 116593970, + 4523957, + 169738, + 35346733, + 12954356, + 7907645, + 2910032, + 9270074, + 1899546, + 6071524, + 11874716, + 72761442, + 3132556, + 116139966, + 139547629, + 28724212, + 6855246, + 72934570, + 147793969, + 115487448, + 4619651, + 7521492, + 2103655, + 880090, + 1806153, + 11787216, + 115915654, + 11223651, + 62378245, + 8009147, + 7191183, + 77502336, + 3849046, + 1131275, + 61747867, + 116047537, + 41293330, + 61789073, + 7914558, + 10043984, + 10514301, + 117956829, + 4647903, + 4916723, + 28669119, + 35774874, + 4244354, + 1452075, + 56223946, + 2434529, + 115641444, + 149998036, + 184123737, + 10994359, + 9360557, + 80256351, + 6125656, + 247910, + 3812984, + 915057, + 17659437, + 11641947, + 139099016, + 72687362, + 57709857, + 11210195, + 3020736, + 12592967, + 5995756, + 385492, + 115443066, + 9371601, + 59979824, + 6694545, + 1484144, + 832190, + 9267057, + 4309187, + 149544854, + 116502302, + 191269336, + 1006737, + 10265001, + 6969410, + 1080500, + 171748, + 139480376, + 17292804, + 174592, + 1620977, + 184538485, + 191239160, + 301798, + 10211550, + 10994397, + 9677504, + 144158419, + 2098651, + 8321, + 11231640, + 77135925, + 12474906, + 2300861, + 2391769, + 10520163, + 9607782, + 55648125, + 10099100, + 16854048, + 35131895, + 1977199, + 145607970, + 115569272, + 116552815, + 6803008, + 35998080, + 10791111, + 2944591, + 1353545, + 115437294, + 133047, + 9274657, + 11191580, + 11191454, + 7618871, + 10745841, + 61882743, + 116755193, + 142462188, + 7200826, + 27419, + 2414718, + 2842198, + 12552, + 395138, + 760648, + 1002656, + 2898883, + 13072940, + 12443170, + 114441450, + 146201420, + 184981897, + 138850297, + 8032315, + 7184114, + 115136442, + 2767713, + 2828478, + 9879311, + 114142645, + 111977918, + 7819570, + 12522290, + 112209031, + 10491964, + 11658257, + 62526783, + 6471814, + 11866581, + 12894153, + 2391734, + 2522831, + 2003490, + 301799, + 1226412, + 1950829, + 8453, + 926938, + 6537825, + 111931861, + 115963308, + 149961934, + 61847307, + 146827975, + 1339227, + 36350, + 7432375, + 9656169, + 28758902, + 427691, + 2293751, + 182087722, + 73416724, + 61884307, + 188190243, + 41294271, + 114830752, + 7004633, + 7785663, + 8066384, + 188099135, + 4730387, + 11887562, + 2801578, + 4242470, + 746839, + 3827735, + 11582563, + 11102807, + 7511633, + 11102800, + 11585926, + 6661053, + 11589568, + 4141463, + 201910565, + 71190156, + 353547, + 880446, + 2115780, + 114277634, + 140849564, + 76994193, + 114875775, + 7122181, + 221902, + 12576775, + 10503253, + 2799573, + 4495234, + 4526442, + 4682973, + 12898460, + 2047568, + 2910032, + 1501361, + } + + for _, rsID := range lociList1{ + + existingMap, exists := locusReferencesMap[rsID] + if (exists == false){ + locusReferencesMap[rsID] = maps.Clone(referencesMap_LocusList1) + } else { + + // We merge the maps + + for key, value := range referencesMap_LocusList1{ + existingMap[key] = value + } + + locusReferencesMap[rsID] = existingMap + } + } + + return locusReferencesMap +} + + diff --git a/resources/geneticReferences/geneticReferences_test.go b/resources/geneticReferences/geneticReferences_test.go index 57b5a27..4ca39d3 100644 --- a/resources/geneticReferences/geneticReferences_test.go +++ b/resources/geneticReferences/geneticReferences_test.go @@ -199,6 +199,7 @@ func TestGeneticReferences(t *testing.T){ diseaseName := diseaseObject.DiseaseName diseaseDescription := diseaseObject.DiseaseDescription diseaseEffectedSex := diseaseObject.EffectedSex + diseaseLocusReferencesMap := diseaseObject.LocusReferencesMap diseaseLociList := diseaseObject.LociList diseaseReferencesMap := diseaseObject.References @@ -218,81 +219,33 @@ func TestGeneticReferences(t *testing.T){ t.Fatalf("PolygenicDisease effected sex is invalid: " + diseaseEffectedSex) } + for rsID, referencesMap := range diseaseLocusReferencesMap{ + + containsItem := slices.Contains(diseaseLociList, rsID) + if (containsItem == false){ + t.Fatalf("Polygenic disease diseaseLocusReferencesMap contains disease locus that is not inside of the disease's loci list.") + } + + allRSIDsMap[rsID] = struct{}{} + + referencesAreValid := verifyReferencesMap(referencesMap) + if (referencesAreValid == false){ + t.Fatalf("PolygenicDisease references map is invalid for disease locus.") + } + } + + containsDuplicates, _ := helpers.CheckIfListContainsDuplicates(diseaseLociList) + if (containsDuplicates == true){ + t.Fatalf("Polygenic disease object contains diseaseLociList with duplicate rsIDs.") + } + + if (len(diseaseLocusReferencesMap) > len(diseaseLociList)){ + t.Fatalf("Polygenic disease contains locus references map that is longer than the diseaseLociList") + } + referencesAreValid := verifyReferencesMap(diseaseReferencesMap) if (referencesAreValid == false){ t.Fatalf("PolygenicDisease references map is invalid for disease: " + diseaseName) - } - - // We use this map to make sure each disease locus references a unique rsid - allPolygenicDiseaseRSIDsMap := make(map[int64]struct{}) - - for _, locusObject := range diseaseLociList{ - - locusIdentifier := locusObject.LocusIdentifier - locusRSID := locusObject.LocusRSID - riskWeightsMap := locusObject.RiskWeightsMap - oddsRatiosMap := locusObject.OddsRatiosMap - minimumWeight := locusObject.MinimumRiskWeight - maximumWeight := locusObject.MaximumRiskWeight - - allRSIDsMap[locusRSID] = struct{}{} - - identifierIsValid := verifyIdentifier(locusIdentifier) - if (identifierIsValid == false){ - t.Fatalf(diseaseName + " Invalid locus identifier found: " + locusIdentifier) - } - - _, exists := allIdentifiersMap[locusIdentifier] - if (exists == true){ - t.Fatalf(diseaseName + " Duplicate locus identifier found: " + locusIdentifier) - } - allIdentifiersMap[locusIdentifier] = struct{}{} - - _, exists = allPolygenicDiseaseRSIDsMap[locusRSID] - if (exists == true){ - rsidString := helpers.ConvertInt64ToString(locusRSID) - t.Fatalf(diseaseName + " RSID Collision found: " + rsidString) - } - - allPolygenicDiseaseRSIDsMap[locusRSID] = struct{}{} - - if (len(riskWeightsMap) == 0){ - t.Fatalf("Empty base weights map found: " + locusIdentifier) - } - - trueMinimumWeight := 100000 - trueMaximumWeight := -100000 - - for basePair, basePairWeight := range riskWeightsMap{ - - isValid := verifyBasePair(basePair) - if (isValid == false){ - t.Fatalf("Base pair weights map contains invalid base pair: " + locusIdentifier) - } - - if (basePairWeight < trueMinimumWeight){ - trueMinimumWeight = basePairWeight - } - if (basePairWeight > trueMaximumWeight){ - trueMaximumWeight = basePairWeight - } - } - - if (trueMinimumWeight != minimumWeight){ - t.Fatalf(diseaseName + ": Invalid minimum base pair weight found: " + locusIdentifier) - } - if (trueMaximumWeight != maximumWeight){ - t.Fatalf(diseaseName + ": Invalid maximum base pair weight found: " + locusIdentifier) - } - - for basePair, _ := range oddsRatiosMap{ - isValid := verifyBasePair(basePair) - if (isValid == false){ - t.Fatalf("Odds ratio weights map contains invalid base pair: " + locusIdentifier) - } - } - - //TODO: Make sure that duplicate base pairs have same weight, odds ratios and probabilities } } diff --git a/resources/geneticReferences/locusMetadata/LocusMetadata.gob b/resources/geneticReferences/locusMetadata/LocusMetadata.gob index d510079624832d4d5be40ebccdaa734be0c8ac8c..c81c03b2e2f7064ec6fd3a75eaad139674c1fb06 100644 GIT binary patch delta 9607 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 delta 122 zcmV-=0EPdF=M2@I46r-_2o0D2iU9ru{j)>?u?mv{3@QNwvmgwA0h2Be3X`@CG7SO& z3RXujH&Ze>HZnMqkP8%({0&i)S`Hxr1CwtKhm$-HLX-9mMzekoe*}{k6djZO6C0C} c3loz_6u6TO6)FJ(gDVw>D-{8^D-{B&`EgGs4gdfE diff --git a/resources/geneticReferences/modifyLocusMetadata/modifyLocusMetadata.go b/resources/geneticReferences/modifyLocusMetadata/modifyLocusMetadata.go index 012e1ee..962b9cc 100644 --- a/resources/geneticReferences/modifyLocusMetadata/modifyLocusMetadata.go +++ b/resources/geneticReferences/modifyLocusMetadata/modifyLocusMetadata.go @@ -43,7 +43,8 @@ func AddLocusMetadata(inputLociToAddList []locusMetadata.LocusMetadata)(int, []b _, exists := newLocusMetadataRSIDsMap[rsID] if (exists == true){ - return 0, nil, errors.New("inputLociToAddList contains multiple locus metadatas with a duplicate rsID.") + rsIDString := helpers.ConvertInt64ToString(rsID) + return 0, nil, errors.New("inputLociToAddList contains multiple locus metadatas with a duplicate rsID: " + rsIDString) } newLocusMetadataRSIDsMap[rsID] = struct{}{} diff --git a/resources/geneticReferences/polygenicDiseases/autism.go b/resources/geneticReferences/polygenicDiseases/autism.go new file mode 100644 index 0000000..d36c6e5 --- /dev/null +++ b/resources/geneticReferences/polygenicDiseases/autism.go @@ -0,0 +1,51 @@ +package polygenicDiseases + +import "errors" + +import "seekia/resources/geneticReferences/attributeLoci" + +import "seekia/internal/helpers" + + +func getAutismDiseaseObject()PolygenicDisease{ + + autismLocusReferencesMap := attributeLoci.GetAutismLoci() + + autismLociList := helpers.GetListOfMapKeys(autismLocusReferencesMap) + + referencesMap := make(map[string]string) + referencesMap["SNPedia.com - Autism"] = "https://www.snpedia.com/index.php/Autism" + + // https://www.cdc.gov/mmwr/volumes/72/ss/ss7202a1.htm + // For 2020, one in 36 children aged 8 years (approximately 4% of boys and 1% of girls) was estimated to have ASD. + + getAverageRiskProbabilitiesFunction := func(maleOrFemale string, inputAge int)(float64, error){ + + if (maleOrFemale == "Male"){ + return 0.04, nil + } + + if (maleOrFemale != "Female"){ + return 0, errors.New("Trying to get breast cancer risk probability for invalid maleOrFemale: " + maleOrFemale) + } + + //TODO: Add different probabilities per age + + return 0.01, nil + } + + autismObject := PolygenicDisease{ + + DiseaseName: "Autism", + EffectedSex: "Both", + DiseaseDescription: "A mental disorder characterized by inability to engage in normal social interactions and intense self-absorption, and usually accompanied by other symptoms such as language dysfunctions and repetitive behavior.", + // Taken from: The American Heritage® Dictionary of the English Language, 5th Edition + LocusReferencesMap: autismLocusReferencesMap, + LociList: autismLociList, + GetAverageRiskProbabilitiesFunction: getAverageRiskProbabilitiesFunction, + References: referencesMap, + } + + return autismObject +} + diff --git a/resources/geneticReferences/polygenicDiseases/breastCancer.go b/resources/geneticReferences/polygenicDiseases/breastCancer.go index 1a4d4c1..e011d2a 100644 --- a/resources/geneticReferences/polygenicDiseases/breastCancer.go +++ b/resources/geneticReferences/polygenicDiseases/breastCancer.go @@ -2,863 +2,143 @@ package polygenicDiseases import "errors" +import "seekia/internal/helpers" + func getBreastCancerDiseaseObject()PolygenicDisease{ + // Map Structure: rsID -> (map[Reference Name]Reference Link) + locusReferencesMap := make(map[int64]map[string]string) + locus1_ReferencesMap := make(map[string]string) locus1_ReferencesMap["SNPedia.com - rs16942"] = "https://www.snpedia.com/index.php/Rs16942" - locus1_RiskWeightsMap := make(map[string]int) - locus1_RiskWeightsMap["T;T"] = 0 - locus1_RiskWeightsMap["T;C"] = 1 - locus1_RiskWeightsMap["C;T"] = 1 - locus1_RiskWeightsMap["C;C"] = 1 - - locus1_OddsRatiosMap := make(map[string]float64) - locus1_OddsRatiosMap["T;T"] = 1 - locus1_OddsRatiosMap["T;C"] = 1.14 - locus1_OddsRatiosMap["C;T"] = 1.14 - locus1_OddsRatiosMap["C;C"] = 1.28 - - locus1_BasePairProbabilitiesMap := make(map[string]float64) - locus1_BasePairProbabilitiesMap["T;T"] = .45 - locus1_BasePairProbabilitiesMap["T;C"] = .45 - locus1_BasePairProbabilitiesMap["C;T"] = .45 - locus1_BasePairProbabilitiesMap["C;C"] = .10 - - locus1_Object := DiseaseLocus{ - - LocusIdentifier: "d7891c", - LocusRSID: 16942, - RiskWeightsMap: locus1_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 1, - OddsRatiosMap: locus1_OddsRatiosMap, - BasePairProbabilitiesMap: locus1_BasePairProbabilitiesMap, - References: locus1_ReferencesMap, - } + locusReferencesMap[16942] = locus1_ReferencesMap locus2_ReferencesMap := make(map[string]string) locus2_ReferencesMap["SNPedia.com - rs1045485"] = "https://www.snpedia.com/index.php/Rs1045485" - - locus2_RiskWeightsMap := make(map[string]int) - locus2_RiskWeightsMap["C;C"] = -2 - locus2_RiskWeightsMap["C;G"] = -1 - locus2_RiskWeightsMap["G;C"] = -1 - locus2_RiskWeightsMap["G;G"] = 0 - locus2_OddsRatiosMap := make(map[string]float64) - - locus2_OddsRatiosMap["C;C"] = 0.74 - locus2_OddsRatiosMap["C;G"] = 0.89 - locus2_OddsRatiosMap["G;C"] = 0.89 - locus2_OddsRatiosMap["G;G"] = 1 - - locus2_BasePairProbabilitiesMap := make(map[string]float64) - locus2_BasePairProbabilitiesMap["C;C"] = .01 - locus2_BasePairProbabilitiesMap["C;G"] = .04 - locus2_BasePairProbabilitiesMap["G;C"] = .04 - locus2_BasePairProbabilitiesMap["G;G"] = .95 - - locus2_Object := DiseaseLocus{ - - LocusIdentifier: "41c164", - LocusRSID: 1045485, - RiskWeightsMap: locus2_RiskWeightsMap, - MinimumRiskWeight: -2, - MaximumRiskWeight: 0, - OddsRatiosMap: locus2_OddsRatiosMap, - BasePairProbabilitiesMap: locus2_BasePairProbabilitiesMap, - References: locus2_ReferencesMap, - } + locusReferencesMap[1045485] = locus2_ReferencesMap locus3_ReferencesMap := make(map[string]string) locus3_ReferencesMap["SNPedia.com - rs34330"] = "https://www.snpedia.com/index.php/Rs34330" - - locus3_RiskWeightsMap := make(map[string]int) - locus3_RiskWeightsMap["C;C"] = 0 - locus3_RiskWeightsMap["T;T"] = 1 - locus3_OddsRatiosMap := make(map[string]float64) - locus3_OddsRatiosMap["C;C"] = 0 - locus3_OddsRatiosMap["T;T"] = 1.22 - - locus3_BasePairProbabilitiesMap := make(map[string]float64) - locus3_BasePairProbabilitiesMap["C;C"] = .40 - locus3_BasePairProbabilitiesMap["C;T"] = .45 - locus3_BasePairProbabilitiesMap["T;C"] = .45 - locus3_BasePairProbabilitiesMap["T;T"] = .15 - - locus3_Object := DiseaseLocus{ - - LocusIdentifier: "f3a097", - LocusRSID: 34330, - RiskWeightsMap: locus3_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 1, - OddsRatiosMap: locus3_OddsRatiosMap, - BasePairProbabilitiesMap: locus3_BasePairProbabilitiesMap, - References: locus3_ReferencesMap, - } + locusReferencesMap[34330] = locus3_ReferencesMap locus4_ReferencesMap := make(map[string]string) locus4_ReferencesMap["SNPedia.com - rs144848"] = "https://www.snpedia.com/index.php/Rs144848" - - locus4_RiskWeightsMap := make(map[string]int) - locus4_RiskWeightsMap["A;A"] = 0 - locus4_RiskWeightsMap["C;A"] = 1 - locus4_RiskWeightsMap["A;C"] = 1 - locus4_RiskWeightsMap["C;C"] = 2 - locus4_OddsRatiosMap := make(map[string]float64) - locus4_OddsRatiosMap["A;A"] = 1 - locus4_OddsRatiosMap["A;C"] = 1.14 - locus4_OddsRatiosMap["C;A"] = 1.14 - locus4_OddsRatiosMap["C;C"] = 1.31 - - locus4_BasePairProbabilitiesMap := make(map[string]float64) - locus4_BasePairProbabilitiesMap["A;A"] = .55 - locus4_BasePairProbabilitiesMap["C;A"] = .36 - locus4_BasePairProbabilitiesMap["A;C"] = .36 - locus4_BasePairProbabilitiesMap["C;C"] = .09 - - locus4_Object := DiseaseLocus{ - - LocusIdentifier: "d4626f", - LocusRSID: 144848, - RiskWeightsMap: locus4_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus4_OddsRatiosMap, - BasePairProbabilitiesMap: locus4_BasePairProbabilitiesMap, - References: locus4_ReferencesMap, - } + locusReferencesMap[144848] = locus4_ReferencesMap locus5_ReferencesMap := make(map[string]string) locus5_ReferencesMap["SNPedia.com - rs766173"] = "https://www.snpedia.com/index.php/Rs766173" - - locus5_RiskWeightsMap := make(map[string]int) - locus5_RiskWeightsMap["A;A"] = 0 - locus5_RiskWeightsMap["A;C"] = 1 - locus5_RiskWeightsMap["C;A"] = 1 - locus5_RiskWeightsMap["C;C"] = 2 - locus5_OddsRatiosMap := make(map[string]float64) - locus5_OddsRatiosMap["A;A"] = 1 - locus5_OddsRatiosMap["A;C"] = 1.14 - locus5_OddsRatiosMap["C;A"] = 1.14 - locus5_OddsRatiosMap["C;C"] = 1.28 - - locus5_BasePairProbabilitiesMap := make(map[string]float64) - locus5_BasePairProbabilitiesMap["A;A"] = .85 - locus5_BasePairProbabilitiesMap["A;C"] = .13 - locus5_BasePairProbabilitiesMap["C;A"] = .13 - locus5_BasePairProbabilitiesMap["C;C"] = .02 - - locus5_Object := DiseaseLocus{ - - LocusIdentifier: "84aaa4", - LocusRSID: 766173, - RiskWeightsMap: locus5_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus5_OddsRatiosMap, - BasePairProbabilitiesMap: locus5_BasePairProbabilitiesMap, - References: locus5_ReferencesMap, - } + locusReferencesMap[766173] = locus5_ReferencesMap locus6_ReferencesMap := make(map[string]string) locus6_ReferencesMap["SNPedia.com - rs1799950"] = "https://www.snpedia.com/index.php/Rs1799950" - locus6_RiskWeightsMap := make(map[string]int) - locus6_RiskWeightsMap["T;T"] = 0 - locus6_RiskWeightsMap["T;C"] = 1 - locus6_RiskWeightsMap["C;T"] = 1 - locus6_RiskWeightsMap["C;C"] = 2 - - locus6_OddsRatiosMap := make(map[string]float64) - locus6_OddsRatiosMap["T;T"] = 1 - locus6_OddsRatiosMap["T;C"] = 1.5 - locus6_OddsRatiosMap["C;T"] = 1.5 - locus6_OddsRatiosMap["C;C"] = 1.72 - - locus6_BasePairProbabilitiesMap := make(map[string]float64) - locus6_BasePairProbabilitiesMap["T;T"] = .98 - locus6_BasePairProbabilitiesMap["T;C"] = .02 - locus6_BasePairProbabilitiesMap["C;T"] = .02 - locus6_BasePairProbabilitiesMap["C;C"] = .001 - - locus6_Object := DiseaseLocus{ - - LocusIdentifier: "c8de7a", - LocusRSID: 1799950, - RiskWeightsMap: locus6_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus6_OddsRatiosMap, - BasePairProbabilitiesMap: locus6_BasePairProbabilitiesMap, - References: locus6_ReferencesMap, - } + locusReferencesMap[1799950] = locus6_ReferencesMap locus7_ReferencesMap := make(map[string]string) locus7_ReferencesMap["SNPedia.com - rs4986850"] = "https://www.snpedia.com/index.php/Rs4986850" - - locus7_RiskWeightsMap := make(map[string]int) - locus7_RiskWeightsMap["C;C"] = 0 - locus7_RiskWeightsMap["T;C"] = 1 - locus7_RiskWeightsMap["C;T"] = 1 - locus7_RiskWeightsMap["T;T"] = 2 - locus7_OddsRatiosMap := make(map[string]float64) - locus7_OddsRatiosMap["C;C"] = 1 - locus7_OddsRatiosMap["T;C"] = 1.14 - locus7_OddsRatiosMap["C;T"] = 1.14 - locus7_OddsRatiosMap["T;T"] = 1.28 - - locus7_BasePairProbabilitiesMap := make(map[string]float64) - locus7_BasePairProbabilitiesMap["C;C"] = .92 - locus7_BasePairProbabilitiesMap["T;C"] = .07 - locus7_BasePairProbabilitiesMap["C;T"] = .07 - locus7_BasePairProbabilitiesMap["T;T"] = .01 - - locus7_Object := DiseaseLocus{ - - LocusIdentifier: "d30087", - LocusRSID: 4986850, - RiskWeightsMap: locus7_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus7_OddsRatiosMap, - BasePairProbabilitiesMap: locus7_BasePairProbabilitiesMap, - References: locus7_ReferencesMap, - } + locusReferencesMap[4986850] = locus7_ReferencesMap locus8_ReferencesMap := make(map[string]string) locus8_ReferencesMap["SNPedia.com - rs2227945"] = "https://www.snpedia.com/index.php/Rs2227945" - - locus8_RiskWeightsMap := make(map[string]int) - locus8_RiskWeightsMap["T;T"] = 0 - locus8_RiskWeightsMap["T;C"] = 1 - locus8_RiskWeightsMap["C;T"] = 1 - locus8_RiskWeightsMap["C;C"] = 2 - locus8_OddsRatiosMap := make(map[string]float64) - locus8_OddsRatiosMap["T;T"] = 1 - locus8_OddsRatiosMap["T;C"] = 1.14 - locus8_OddsRatiosMap["C;T"] = 1.14 - locus8_OddsRatiosMap["C;C"] = 1.28 - - locus8_BasePairProbabilitiesMap := make(map[string]float64) - locus8_BasePairProbabilitiesMap["T;T"] = .97 - locus8_BasePairProbabilitiesMap["T;C"] = .03 - locus8_BasePairProbabilitiesMap["C;T"] = .03 - locus8_BasePairProbabilitiesMap["C;C"] = .001 - - locus8_Object := DiseaseLocus{ - - LocusIdentifier: "cafa72", - LocusRSID: 2227945, - RiskWeightsMap: locus8_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus8_OddsRatiosMap, - BasePairProbabilitiesMap: locus8_BasePairProbabilitiesMap, - References: locus8_ReferencesMap, - } + locusReferencesMap[2227945] = locus8_ReferencesMap locus9_ReferencesMap := make(map[string]string) locus9_ReferencesMap["SNPedia.com - rs1799966"] = "https://www.snpedia.com/index.php/Rs1799966" - - locus9_RiskWeightsMap := make(map[string]int) - locus9_RiskWeightsMap["T;T"] = 0 - locus9_RiskWeightsMap["T;C"] = 1 - locus9_RiskWeightsMap["C;T"] = 1 - locus9_RiskWeightsMap["C;C"] = 2 - locus9_OddsRatiosMap := make(map[string]float64) - locus9_OddsRatiosMap["T;T"] = 1 - locus9_OddsRatiosMap["T;C"] = 1.14 - locus9_OddsRatiosMap["C;T"] = 1.14 - locus9_OddsRatiosMap["C;C"] = 1.28 - - locus9_BasePairProbabilitiesMap := make(map[string]float64) - locus9_BasePairProbabilitiesMap["T;T"] = .45 - locus9_BasePairProbabilitiesMap["T;C"] = .45 - locus9_BasePairProbabilitiesMap["C;T"] = .45 - locus9_BasePairProbabilitiesMap["C;C"] = .10 - - locus9_Object := DiseaseLocus{ - - LocusIdentifier: "8f671c", - LocusRSID: 1799966, - RiskWeightsMap: locus9_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus9_OddsRatiosMap, - BasePairProbabilitiesMap: locus9_BasePairProbabilitiesMap, - References: locus9_ReferencesMap, - } + locusReferencesMap[1799966] = locus9_ReferencesMap locus10_ReferencesMap := make(map[string]string) locus10_ReferencesMap["SNPedia.com - rs4987117"] = "https://www.snpedia.com/index.php/Rs4987117" - - locus10_RiskWeightsMap := make(map[string]int) - locus10_RiskWeightsMap["C;C"] = 0 - locus10_RiskWeightsMap["T;C"] = 1 - locus10_RiskWeightsMap["C;T"] = 1 - locus10_RiskWeightsMap["T;T"] = 2 - locus10_OddsRatiosMap := make(map[string]float64) - locus10_OddsRatiosMap["C;C"] = 1 - locus10_OddsRatiosMap["T;C"] = 1.14 - locus10_OddsRatiosMap["C;T"] = 1.14 - locus10_OddsRatiosMap["T;T"] = 1.28 - - locus10_BasePairProbabilitiesMap := make(map[string]float64) - locus10_BasePairProbabilitiesMap["C;C"] = .98 - locus10_BasePairProbabilitiesMap["T;C"] = .02 - locus10_BasePairProbabilitiesMap["C;T"] = .02 - locus10_BasePairProbabilitiesMap["T;T"] = .001 - - locus10_Object := DiseaseLocus{ - - LocusIdentifier: "b3e49a", - LocusRSID: 4987117, - RiskWeightsMap: locus10_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus10_OddsRatiosMap, - BasePairProbabilitiesMap: locus10_BasePairProbabilitiesMap, - References: locus10_ReferencesMap, - } + locusReferencesMap[4987117] = locus10_ReferencesMap locus11_ReferencesMap := make(map[string]string) locus11_ReferencesMap["SNPedia.com - rs1799954"] = "https://www.snpedia.com/index.php/Rs1799954" - - locus11_RiskWeightsMap := make(map[string]int) - locus11_RiskWeightsMap["C;C"] = 0 - locus11_RiskWeightsMap["T;C"] = 1 - locus11_RiskWeightsMap["C;T"] = 1 - locus11_RiskWeightsMap["T;T"] = 2 - locus11_OddsRatiosMap := make(map[string]float64) - locus11_OddsRatiosMap["C;C"] = 1 - locus11_OddsRatiosMap["T;C"] = 1.14 - locus11_OddsRatiosMap["C;T"] = 1.14 - locus11_OddsRatiosMap["T;T"] = 1.28 - - locus11_BasePairProbabilitiesMap := make(map[string]float64) - locus11_BasePairProbabilitiesMap["C;C"] = .97 - locus11_BasePairProbabilitiesMap["T;C"] = .03 - locus11_BasePairProbabilitiesMap["C;T"] = .03 - locus11_BasePairProbabilitiesMap["T;T"] = .001 - - locus11_Object := DiseaseLocus{ - - LocusIdentifier: "8b0b02", - LocusRSID: 1799954, - RiskWeightsMap: locus11_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus11_OddsRatiosMap, - BasePairProbabilitiesMap: locus11_BasePairProbabilitiesMap, - References: locus11_ReferencesMap, - } + locusReferencesMap[1799954] = locus11_ReferencesMap locus12_ReferencesMap := make(map[string]string) locus12_ReferencesMap["SNPedia.com - rs11571746"] = "https://www.snpedia.com/index.php/Rs11571746" - locus12_RiskWeightsMap := make(map[string]int) - locus12_RiskWeightsMap["T;T"] = 0 - locus12_RiskWeightsMap["T;C"] = 1 - locus12_RiskWeightsMap["C;T"] = 1 - locus12_RiskWeightsMap["C;C"] = 2 - - locus12_OddsRatiosMap := make(map[string]float64) - locus12_OddsRatiosMap["T;T"] = 1 - locus12_OddsRatiosMap["T;C"] = 1.14 - locus12_OddsRatiosMap["C;T"] = 1.14 - locus12_OddsRatiosMap["C;C"] = 1.28 - - locus12_BasePairProbabilitiesMap := make(map[string]float64) - locus12_BasePairProbabilitiesMap["T;T"] = .98 - locus12_BasePairProbabilitiesMap["T;C"] = .02 - locus12_BasePairProbabilitiesMap["C;T"] = .02 - locus12_BasePairProbabilitiesMap["C;C"] = .001 - - locus12_Object := DiseaseLocus{ - - LocusIdentifier: "25cafc", - LocusRSID: 11571746, - RiskWeightsMap: locus12_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus12_OddsRatiosMap, - BasePairProbabilitiesMap: locus12_BasePairProbabilitiesMap, - References: locus12_ReferencesMap, - } + locusReferencesMap[11571746] = locus12_ReferencesMap locus13_ReferencesMap := make(map[string]string) locus13_ReferencesMap["SNPedia.com - rs11571747"] = "https://www.snpedia.com/index.php/Rs11571747" - locus13_RiskWeightsMap := make(map[string]int) - locus13_RiskWeightsMap["A;A"] = 0 - locus13_RiskWeightsMap["A;C"] = 1 - locus13_RiskWeightsMap["C;A"] = 1 - locus13_RiskWeightsMap["C;C"] = 2 - - locus13_OddsRatiosMap := make(map[string]float64) - locus13_OddsRatiosMap["A;A"] = 1 - locus13_OddsRatiosMap["A;C"] = 1.14 - locus13_OddsRatiosMap["C;A"] = 1.14 - locus13_OddsRatiosMap["C;C"] = 1.28 - - locus13_BasePairProbabilitiesMap := make(map[string]float64) - locus13_BasePairProbabilitiesMap["A;A"] = .99 - locus13_BasePairProbabilitiesMap["A;C"] = .001 - locus13_BasePairProbabilitiesMap["C;A"] = .001 - locus13_BasePairProbabilitiesMap["C;C"] = .001 - - locus13_Object := DiseaseLocus{ - - LocusIdentifier: "34c7e5", - LocusRSID: 11571747, - RiskWeightsMap: locus13_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus13_OddsRatiosMap, - BasePairProbabilitiesMap: locus13_BasePairProbabilitiesMap, - References: locus13_ReferencesMap, - } + locusReferencesMap[11571747] = locus13_ReferencesMap locus14_ReferencesMap := make(map[string]string) locus14_ReferencesMap["SNPedia.com - rs4987047"] = "https://www.snpedia.com/index.php/Rs4987047" - locus14_RiskWeightsMap := make(map[string]int) - locus14_RiskWeightsMap["A;A"] = 0 - locus14_RiskWeightsMap["A;T"] = 1 - locus14_RiskWeightsMap["T;A"] = 1 - locus14_RiskWeightsMap["T;T"] = 2 - - locus14_OddsRatiosMap := make(map[string]float64) - locus14_OddsRatiosMap["A;A"] = 1 - locus14_OddsRatiosMap["A;T"] = 1.14 - locus14_OddsRatiosMap["T;A"] = 1.14 - locus14_OddsRatiosMap["T;T"] = 1.28 - - locus14_BasePairProbabilitiesMap := make(map[string]float64) - locus14_BasePairProbabilitiesMap["A;A"] = .94 - locus14_BasePairProbabilitiesMap["A;T"] = .94 - locus14_BasePairProbabilitiesMap["T;A"] = .05 - locus14_BasePairProbabilitiesMap["T;T"] = .01 - - locus14_Object := DiseaseLocus{ - - LocusIdentifier: "60ce27", - LocusRSID: 4987047, - RiskWeightsMap: locus14_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus14_OddsRatiosMap, - BasePairProbabilitiesMap: locus14_BasePairProbabilitiesMap, - References: locus14_ReferencesMap, - } + locusReferencesMap[4987047] = locus14_ReferencesMap locus15_ReferencesMap := make(map[string]string) locus15_ReferencesMap["SNPedia.com - rs11571833"] = "https://www.snpedia.com/index.php/Rs11571833" - locus15_RiskWeightsMap := make(map[string]int) - locus15_RiskWeightsMap["A;A"] = 0 - locus15_RiskWeightsMap["T;A"] = 1 - locus15_RiskWeightsMap["A;T"] = 1 - locus15_RiskWeightsMap["T;T"] = 2 + locusReferencesMap[11571833] = locus15_ReferencesMap - locus15_OddsRatiosMap := make(map[string]float64) - locus15_OddsRatiosMap["A;A"] = 1 - locus15_OddsRatiosMap["T;A"] = 1.14 - locus15_OddsRatiosMap["A;T"] = 1.14 - locus15_OddsRatiosMap["T;T"] = 1.28 - - locus15_BasePairProbabilitiesMap := make(map[string]float64) - locus15_BasePairProbabilitiesMap["A;A"] = .99 - locus15_BasePairProbabilitiesMap["T;A"] = .01 - locus15_BasePairProbabilitiesMap["A;T"] = .01 - locus15_BasePairProbabilitiesMap["T;T"] = .001 - - locus15_Object := DiseaseLocus{ - - LocusIdentifier: "328cdf", - LocusRSID: 11571833, - RiskWeightsMap: locus15_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus15_OddsRatiosMap, - BasePairProbabilitiesMap: locus15_BasePairProbabilitiesMap, - References: locus15_ReferencesMap, - } - locus16_ReferencesMap := make(map[string]string) locus16_ReferencesMap["SNPedia.com - rs1801426"] = "https://www.snpedia.com/index.php/Rs1801426" - locus16_RiskWeightsMap := make(map[string]int) - locus16_RiskWeightsMap["A;A"] = 0 - locus16_RiskWeightsMap["G;A"] = 1 - locus16_RiskWeightsMap["A;G"] = 1 - locus16_RiskWeightsMap["G;G"] = 2 - - locus16_OddsRatiosMap := make(map[string]float64) - locus16_OddsRatiosMap["A;A"] = 1 - locus16_OddsRatiosMap["G;A"] = 1.14 - locus16_OddsRatiosMap["A;G"] = 1.14 - locus16_OddsRatiosMap["G;G"] = 1.28 - - locus16_BasePairProbabilitiesMap := make(map[string]float64) - locus16_BasePairProbabilitiesMap["A;A"] = .90 - locus16_BasePairProbabilitiesMap["G;A"] = .09 - locus16_BasePairProbabilitiesMap["A;G"] = .09 - locus16_BasePairProbabilitiesMap["G;G"] = .01 - - locus16_Object := DiseaseLocus{ - - LocusIdentifier: "849bc7", - LocusRSID: 1801426, - RiskWeightsMap: locus16_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus16_OddsRatiosMap, - BasePairProbabilitiesMap: locus16_BasePairProbabilitiesMap, - References: locus16_ReferencesMap, - } + locusReferencesMap[1801426] = locus16_ReferencesMap locus17_ReferencesMap := make(map[string]string) locus17_ReferencesMap["SNPedia.com - rs3218707"] = "https://www.snpedia.com/index.php/Rs3218707" - locus17_RiskWeightsMap := make(map[string]int) - locus17_RiskWeightsMap["G;G"] = 0 - locus17_RiskWeightsMap["G;C"] = 1 - locus17_RiskWeightsMap["C;G"] = 1 - locus17_RiskWeightsMap["C;C"] = 2 - - locus17_OddsRatiosMap := make(map[string]float64) - locus17_OddsRatiosMap["G;G"] = 1 - locus17_OddsRatiosMap["G;C"] = 1.14 - locus17_OddsRatiosMap["C;G"] = 1.14 - locus17_OddsRatiosMap["C;C"] = 1.28 - - locus17_BasePairProbabilitiesMap := make(map[string]float64) - locus17_BasePairProbabilitiesMap["G;G"] = .96 - locus17_BasePairProbabilitiesMap["G;C"] = .04 - locus17_BasePairProbabilitiesMap["C;G"] = .04 - locus17_BasePairProbabilitiesMap["C;C"] = .001 - - locus17_Object := DiseaseLocus{ - - LocusIdentifier: "5af5e3", - LocusRSID: 3218707, - RiskWeightsMap: locus17_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus17_OddsRatiosMap, - BasePairProbabilitiesMap: locus17_BasePairProbabilitiesMap, - References: locus17_ReferencesMap, - } + locusReferencesMap[3218707] = locus17_ReferencesMap locus18_ReferencesMap := make(map[string]string) locus18_ReferencesMap["SNPedia.com - rs4987945"] = "https://www.snpedia.com/index.php/Rs4987945" - locus18_RiskWeightsMap := make(map[string]int) - locus18_RiskWeightsMap["C;C"] = 0 - locus18_RiskWeightsMap["C;G"] = 1 - locus18_RiskWeightsMap["G;C"] = 1 - locus18_RiskWeightsMap["G;G"] = 2 - - locus18_OddsRatiosMap := make(map[string]float64) - locus18_OddsRatiosMap["C;C"] = 1 - locus18_OddsRatiosMap["C;G"] = 1.14 - locus18_OddsRatiosMap["G;C"] = 1.14 - locus18_OddsRatiosMap["G;G"] = 1.28 - - locus18_BasePairProbabilitiesMap := make(map[string]float64) - locus18_BasePairProbabilitiesMap["C;C"] = .95 - locus18_BasePairProbabilitiesMap["C;G"] = .04 - locus18_BasePairProbabilitiesMap["G;C"] = .04 - locus18_BasePairProbabilitiesMap["G;G"] = .01 - - locus18_Object := DiseaseLocus{ - - LocusIdentifier: "c354fa", - LocusRSID: 4987945, - RiskWeightsMap: locus18_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus18_OddsRatiosMap, - BasePairProbabilitiesMap: locus18_BasePairProbabilitiesMap, - References: locus18_ReferencesMap, - } + locusReferencesMap[4987945] = locus18_ReferencesMap locus19_ReferencesMap := make(map[string]string) locus19_ReferencesMap["SNPedia.com - rs4986761"] = "https://www.snpedia.com/index.php/Rs4986761" - locus19_RiskWeightsMap := make(map[string]int) - locus19_RiskWeightsMap["T;T"] = 0 - locus19_RiskWeightsMap["C;T"] = 1 - locus19_RiskWeightsMap["T;C"] = 1 - locus19_RiskWeightsMap["C;C"] = 2 - - locus19_OddsRatiosMap := make(map[string]float64) - locus19_OddsRatiosMap["T;T"] = 1 - locus19_OddsRatiosMap["C;T"] = 1.05 - locus19_OddsRatiosMap["T;C"] = 1.05 - locus19_OddsRatiosMap["C;C"] = 1.51 - - locus19_BasePairProbabilitiesMap := make(map[string]float64) - locus19_BasePairProbabilitiesMap["T;T"] = .99 - locus19_BasePairProbabilitiesMap["C;T"] = .01 - locus19_BasePairProbabilitiesMap["T;C"] = .01 - locus19_BasePairProbabilitiesMap["C;C"] = .001 - - locus19_Object := DiseaseLocus{ - - LocusIdentifier: "eedc23", - LocusRSID: 4986761, - RiskWeightsMap: locus19_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus19_OddsRatiosMap, - BasePairProbabilitiesMap: locus19_BasePairProbabilitiesMap, - References: locus19_ReferencesMap, - } + locusReferencesMap[4986761] = locus19_ReferencesMap locus20_ReferencesMap := make(map[string]string) locus20_ReferencesMap["SNPedia.com - rs3218695"] = "https://www.snpedia.com/index.php/Rs3218695" - locus20_RiskWeightsMap := make(map[string]int) - locus20_RiskWeightsMap["C;C"] = 0 - locus20_RiskWeightsMap["C;A"] = 1 - locus20_RiskWeightsMap["A;C"] = 1 - locus20_RiskWeightsMap["A;A"] = 2 - - locus20_OddsRatiosMap := make(map[string]float64) - locus20_OddsRatiosMap["C;C"] = 1 - locus20_OddsRatiosMap["C;A"] = 1.14 - locus20_OddsRatiosMap["A;C"] = 1.14 - locus20_OddsRatiosMap["A;A"] = 1.28 - - locus20_BasePairProbabilitiesMap := make(map[string]float64) - locus20_BasePairProbabilitiesMap["C;C"] = .98 - locus20_BasePairProbabilitiesMap["C;A"] = .02 - locus20_BasePairProbabilitiesMap["A;C"] = .02 - locus20_BasePairProbabilitiesMap["A;A"] = .001 - - locus20_Object := DiseaseLocus{ - - LocusIdentifier: "2ee027", - LocusRSID: 3218695, - RiskWeightsMap: locus20_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus20_OddsRatiosMap, - BasePairProbabilitiesMap: locus20_BasePairProbabilitiesMap, - References: locus20_ReferencesMap, - } + locusReferencesMap[3218695] = locus20_ReferencesMap locus21_ReferencesMap := make(map[string]string) locus21_ReferencesMap["SNPedia.com - rs1800056"] = "https://www.snpedia.com/index.php/Rs1800056" - locus21_RiskWeightsMap := make(map[string]int) - locus21_RiskWeightsMap["T;T"] = 0 - locus21_RiskWeightsMap["C;T"] = 1 - locus21_RiskWeightsMap["T;C"] = 1 - locus21_RiskWeightsMap["C;C"] = 2 - - locus21_OddsRatiosMap := make(map[string]float64) - locus21_OddsRatiosMap["T;T"] = 1 - locus21_OddsRatiosMap["C;T"] = 1.05 - locus21_OddsRatiosMap["T;C"] = 1.05 - locus21_OddsRatiosMap["C;C"] = 1.51 - - locus21_BasePairProbabilitiesMap := make(map[string]float64) - locus21_BasePairProbabilitiesMap["T;T"] = .97 - locus21_BasePairProbabilitiesMap["C;T"] = .03 - locus21_BasePairProbabilitiesMap["T;C"] = .03 - locus21_BasePairProbabilitiesMap["C;C"] = .001 - - locus21_Object := DiseaseLocus{ - - LocusIdentifier: "fc4bab", - LocusRSID: 1800056, - RiskWeightsMap: locus21_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus21_OddsRatiosMap, - BasePairProbabilitiesMap: locus21_BasePairProbabilitiesMap, - References: locus21_ReferencesMap, - } + locusReferencesMap[1800056] = locus21_ReferencesMap locus22_ReferencesMap := make(map[string]string) locus22_ReferencesMap["SNPedia.com - rs1800057"] = "https://www.snpedia.com/index.php/Rs1800057" - locus22_RiskWeightsMap := make(map[string]int) - locus22_RiskWeightsMap["C;C"] = 0 - locus22_RiskWeightsMap["C;G"] = 1 - locus22_RiskWeightsMap["G;C"] = 1 - locus22_RiskWeightsMap["G;G"] = 2 - - locus22_OddsRatiosMap := make(map[string]float64) - locus22_OddsRatiosMap["C;C"] = 1 - locus22_OddsRatiosMap["C;G"] = 1.05 - locus22_OddsRatiosMap["G;C"] = 1.05 - locus22_OddsRatiosMap["G;G"] = 1.51 - - locus22_BasePairProbabilitiesMap := make(map[string]float64) - locus22_BasePairProbabilitiesMap["C;C"] = .97 - locus22_BasePairProbabilitiesMap["C;G"] = .03 - locus22_BasePairProbabilitiesMap["G;C"] = .03 - locus22_BasePairProbabilitiesMap["G;G"] = .001 - - locus22_Object := DiseaseLocus{ - - LocusIdentifier: "f8b225", - LocusRSID: 1800057, - RiskWeightsMap: locus22_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus22_OddsRatiosMap, - BasePairProbabilitiesMap: locus22_BasePairProbabilitiesMap, - References: locus22_ReferencesMap, - } + locusReferencesMap[1800057] = locus22_ReferencesMap locus23_ReferencesMap := make(map[string]string) locus23_ReferencesMap["SNPedia.com - rs3092856"] = "https://www.snpedia.com/index.php/Rs3092856" - locus23_RiskWeightsMap := make(map[string]int) - locus23_RiskWeightsMap["C;C"] = 0 - locus23_RiskWeightsMap["C;T"] = 1 - locus23_RiskWeightsMap["T;C"] = 1 - locus23_RiskWeightsMap["T;T"] = 2 - - locus23_OddsRatiosMap := make(map[string]float64) - locus23_OddsRatiosMap["C;C"] = 1 - locus23_OddsRatiosMap["C;T"] = 1.14 - locus23_OddsRatiosMap["T;C"] = 1.14 - locus23_OddsRatiosMap["T;T"] = 1.28 - - locus23_BasePairProbabilitiesMap := make(map[string]float64) - locus23_BasePairProbabilitiesMap["C;C"] = .95 - locus23_BasePairProbabilitiesMap["C;T"] = .05 - locus23_BasePairProbabilitiesMap["T;C"] = .05 - locus23_BasePairProbabilitiesMap["T;T"] = .001 - - locus23_Object := DiseaseLocus{ - - LocusIdentifier: "4a072c", - LocusRSID: 3092856, - RiskWeightsMap: locus23_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus23_OddsRatiosMap, - BasePairProbabilitiesMap: locus23_BasePairProbabilitiesMap, - References: locus23_ReferencesMap, - } + locusReferencesMap[3092856] = locus23_ReferencesMap locus24_ReferencesMap := make(map[string]string) locus24_ReferencesMap["SNPedia.com - rs1800058"] = "https://www.snpedia.com/index.php/Rs1800058" - locus24_RiskWeightsMap := make(map[string]int) - locus24_RiskWeightsMap["C;C"] = 0 - locus24_RiskWeightsMap["C;T"] = 1 - locus24_RiskWeightsMap["T;C"] = 1 - locus24_RiskWeightsMap["T;T"] = 2 - - locus24_OddsRatiosMap := make(map[string]float64) - locus24_OddsRatiosMap["C;C"] = 1 - locus24_OddsRatiosMap["C;T"] = 1.05 - locus24_OddsRatiosMap["T;C"] = 1.05 - locus24_OddsRatiosMap["T;T"] = 1.51 - - locus24_BasePairProbabilitiesMap := make(map[string]float64) - locus24_BasePairProbabilitiesMap["C;C"] = .95 - locus24_BasePairProbabilitiesMap["C;T"] = .04 - locus24_BasePairProbabilitiesMap["T;C"] = .04 - locus24_BasePairProbabilitiesMap["T;T"] = .01 - - locus24_Object := DiseaseLocus{ - - LocusIdentifier: "070f24", - LocusRSID: 1800058, - RiskWeightsMap: locus24_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus24_OddsRatiosMap, - BasePairProbabilitiesMap: locus24_BasePairProbabilitiesMap, - References: locus24_ReferencesMap, - } + locusReferencesMap[1800058] = locus24_ReferencesMap locus25_ReferencesMap := make(map[string]string) locus25_ReferencesMap["SNPedia.com - rs1801673"] = "https://www.snpedia.com/index.php/Rs1801673" - locus25_RiskWeightsMap := make(map[string]int) - locus25_RiskWeightsMap["A;A"] = 0 - locus25_RiskWeightsMap["A;T"] = 1 - locus25_RiskWeightsMap["T;A"] = 1 - locus25_RiskWeightsMap["T;T"] = 2 - - locus25_OddsRatiosMap := make(map[string]float64) - locus25_OddsRatiosMap["A;A"] = 1 - locus25_OddsRatiosMap["A;T"] = 1.14 - locus25_OddsRatiosMap["T;A"] = 1.14 - locus25_OddsRatiosMap["T;T"] = 1.28 - - locus25_BasePairProbabilitiesMap := make(map[string]float64) - locus25_BasePairProbabilitiesMap["A;A"] = .99 - locus25_BasePairProbabilitiesMap["A;T"] = .01 - locus25_BasePairProbabilitiesMap["T;A"] = .01 - locus25_BasePairProbabilitiesMap["T;T"] = .001 - - locus25_Object := DiseaseLocus{ - - LocusIdentifier: "d08516", - LocusRSID: 1801673, - RiskWeightsMap: locus25_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus25_OddsRatiosMap, - BasePairProbabilitiesMap: locus25_BasePairProbabilitiesMap, - References: locus25_ReferencesMap, - } + locusReferencesMap[1801673] = locus25_ReferencesMap locus26_ReferencesMap := make(map[string]string) locus26_ReferencesMap["SNPedia.com - rs17879961"] = "https://www.snpedia.com/index.php/Rs17879961" - locus26_RiskWeightsMap := make(map[string]int) - locus26_RiskWeightsMap["A;A"] = 0 - locus26_RiskWeightsMap["A;G"] = 1 - locus26_RiskWeightsMap["G;A"] = 1 - locus26_RiskWeightsMap["G;G"] = 2 - - locus26_OddsRatiosMap := make(map[string]float64) - locus26_OddsRatiosMap["A;A"] = 1 - locus26_OddsRatiosMap["A;G"] = 1.14 - locus26_OddsRatiosMap["G;A"] = 1.14 - locus26_OddsRatiosMap["G;G"] = 1.28 - - locus26_BasePairProbabilitiesMap := make(map[string]float64) - locus26_BasePairProbabilitiesMap["A;A"] = .98 - locus26_BasePairProbabilitiesMap["A;G"] = .02 - locus26_BasePairProbabilitiesMap["G;A"] = .02 - locus26_BasePairProbabilitiesMap["G;G"] = .001 - - locus26_Object := DiseaseLocus{ - - LocusIdentifier: "047b84", - LocusRSID: 17879961, - RiskWeightsMap: locus26_RiskWeightsMap, - MinimumRiskWeight: 0, - MaximumRiskWeight: 2, - OddsRatiosMap: locus26_OddsRatiosMap, - BasePairProbabilitiesMap: locus26_BasePairProbabilitiesMap, - References: locus26_ReferencesMap, - } + locusReferencesMap[17879961] = locus26_ReferencesMap // TODO: //-https://www.snpedia.com/index.php/Rs1042522 @@ -883,7 +163,7 @@ func getBreastCancerDiseaseObject()PolygenicDisease{ //-https://www.snpedia.com/index.php/Rs7895676 //-https://www.snpedia.com/index.php/Rs140068132 - breastCancerLociList := []DiseaseLocus{locus1_Object, locus2_Object, locus3_Object, locus4_Object, locus5_Object, locus6_Object, locus7_Object, locus8_Object, locus9_Object, locus10_Object, locus11_Object, locus12_Object, locus13_Object, locus14_Object, locus15_Object, locus16_Object, locus17_Object, locus18_Object, locus19_Object, locus20_Object, locus21_Object, locus22_Object, locus23_Object, locus24_Object, locus25_Object, locus26_Object} + breastCancerLociList := helpers.GetListOfMapKeys(locusReferencesMap) referencesMap := make(map[string]string) referencesMap["SNPedia.com - Breast Cancer"] = "https://www.snpedia.com/index.php/Breast_cancer" @@ -948,6 +228,7 @@ func getBreastCancerDiseaseObject()PolygenicDisease{ DiseaseName: "Breast Cancer", EffectedSex: "Both", DiseaseDescription: "Cancer growth in the tissue of a person's chest breast.", + LocusReferencesMap: locusReferencesMap, LociList: breastCancerLociList, GetAverageRiskProbabilitiesFunction: getAverageRiskProbabilitiesFunction, References: referencesMap, diff --git a/resources/geneticReferences/polygenicDiseases/polygenicDiseases.go b/resources/geneticReferences/polygenicDiseases/polygenicDiseases.go index 24014b0..bef6697 100644 --- a/resources/geneticReferences/polygenicDiseases/polygenicDiseases.go +++ b/resources/geneticReferences/polygenicDiseases/polygenicDiseases.go @@ -1,5 +1,5 @@ -// polygenicDiseases provides information about polygenic diseases and the SNP base changes that effect a person's risk of becoming victim to them. +// polygenicDiseases provides information about polygenic diseases and the loci that influence them package polygenicDiseases @@ -8,42 +8,8 @@ package polygenicDiseases // Polygenic disease probabilities are less accurate, because individual base pair changes only cause comparatively small changes in the disease risk. // Polygenic diseases are also more influenced by environmental factors, further decreasing risk accuracy. -//TODO: Eventually we want to use neural networks for polygenic disease prediction. -// This package is currently a less accurate solution until we get access to the necessary training data. - import "errors" -// DiseaseLocus is a location on a human genome that has an effect on the disease -type DiseaseLocus struct{ - - // 3 byte identifier, encoded in Hex. - LocusIdentifier string - - // RSID that represents this locus - // If multiple RSIDs represent the same locus, use the first rsID for the locus in the locusMetadata package - LocusRSID int64 - - // Map Structure: Base pair -> Effect weight (Positive number = increased risk, negative number = decreased risk) - // The number only indicates a general effect of the base, for bases for which we do not have risk probability statistics - // 0 indicates that the base has no effect - RiskWeightsMap map[string]int - - // Minimum and maximum values in above map - MinimumRiskWeight int - MaximumRiskWeight int - - // Map Structure: Base Pair -> Odds ratio of BasePair/Normal (common) Base pair - // Number is greater than 1 = Increases risk, Number is less than 1 = decreases risk - // 1 indicates that the base has no impact - OddsRatiosMap map[string]float64 - - // Map Structure: Base Pair -> Probability that a person will have that base pair for the general population - BasePairProbabilitiesMap map[string]float64 - - // Map Structure: Reference name -> Reference link - References map[string]string -} - type PolygenicDisease struct{ @@ -54,7 +20,14 @@ type PolygenicDisease struct{ // Is either "Mate"/"Female"/"Both" EffectedSex string - LociList []DiseaseLocus + // This is a list of rsIDs which are known to have an effect on this disease + // We use these loci to predict trait outcomes with neural networks. + // Map Structure: rsID -> (map[Reference Name]Reference Link) + LocusReferencesMap map[int64]map[string]string + + // This is a list of all loci used to predict this disease's risk + // This should be a list of the keys in LocusReferencesMap + LociList []int64 // Inputs: // -string: "Mate"/"Female" @@ -64,10 +37,12 @@ type PolygenicDisease struct{ // -error GetAverageRiskProbabilitiesFunction func(string, int)(float64, error) + // This map contains scientific resources about this disease // Map Structure: Reference name -> Reference link References map[string]string } + var polygenicDiseaseNamesList []string var polygenicDiseaseObjectsList []PolygenicDisease @@ -75,8 +50,9 @@ var polygenicDiseaseObjectsList []PolygenicDisease func InitializePolygenicDiseaseVariables(){ breastCancerObject := getBreastCancerDiseaseObject() + autismObject := getAutismDiseaseObject() - polygenicDiseaseObjectsList = []PolygenicDisease{breastCancerObject} + polygenicDiseaseObjectsList = []PolygenicDisease{breastCancerObject, autismObject} polygenicDiseaseNamesList = make([]string, 0, len(polygenicDiseaseObjectsList)) @@ -94,7 +70,7 @@ func InitializePolygenicDiseaseVariables(){ func GetPolygenicDiseaseNamesList()([]string, error){ if (polygenicDiseaseNamesList == nil){ - return nil, errors.New("GetDiseaseNamesList called when list is not initialized.") + return nil, errors.New("GetPolygenicDiseaseNamesList called when list is not initialized.") } return polygenicDiseaseNamesList, nil @@ -127,40 +103,3 @@ func GetPolygenicDiseaseObject(diseaseName string)(PolygenicDisease, error){ return PolygenicDisease{}, errors.New("GetPolygenicDiseaseObject called with unknown disease name: " + diseaseName) } - -//Outputs: -// -map[string]DiseaseLocus: Map of LocusIdentifier -> LocusObject -// -error (will return err if diseaseName is not found) -func GetPolygenicDiseaseLociMap(diseaseName string)(map[string]DiseaseLocus, error){ - - diseaseObject, err := GetPolygenicDiseaseObject(diseaseName) - if (err != nil) { return nil, err } - - diseaseLociList := diseaseObject.LociList - - diseaseLociMap := make(map[string]DiseaseLocus) - - for _, locusObject := range diseaseLociList{ - - locusIdentifier := locusObject.LocusIdentifier - diseaseLociMap[locusIdentifier] = locusObject - } - - return diseaseLociMap, nil -} - -func GetPolygenicDiseaseLocusObject(diseaseName string, locusIdentifier string)(DiseaseLocus, error){ - - diseaseLociMap, err := GetPolygenicDiseaseLociMap(diseaseName) - if (err != nil){ return DiseaseLocus{}, err } - - locusObject, exists := diseaseLociMap[locusIdentifier] - if (exists == false){ - return DiseaseLocus{}, errors.New("GetDiseaseLocusObject called with unknown locus identifier: " + locusIdentifier) - } - - return locusObject, nil -} - - - diff --git a/resources/geneticReferences/traits/eyeColor.go b/resources/geneticReferences/traits/eyeColor.go index e24439b..f490003 100644 --- a/resources/geneticReferences/traits/eyeColor.go +++ b/resources/geneticReferences/traits/eyeColor.go @@ -164,6 +164,7 @@ func getEyeColorTraitObject()Trait{ LociList_Rules: []int64{}, RulesList: []TraitRule{}, OutcomesList: []string{"Blue", "Green", "Hazel", "Brown"}, + NumericValueFormatter: nil, ReferencesMap: referencesMap, } diff --git a/resources/geneticReferences/traits/facialStructure.go b/resources/geneticReferences/traits/facialStructure.go index b5c2086..b054ad7 100644 --- a/resources/geneticReferences/traits/facialStructure.go +++ b/resources/geneticReferences/traits/facialStructure.go @@ -142,6 +142,7 @@ func getFacialStructureTraitObject()Trait{ LociList_Rules: []int64{}, RulesList: []TraitRule{}, OutcomesList: []string{}, + NumericValueFormatter: nil, ReferencesMap: referencesMap, } diff --git a/resources/geneticReferences/traits/hairColor.go b/resources/geneticReferences/traits/hairColor.go index 6e71b10..fab291d 100644 --- a/resources/geneticReferences/traits/hairColor.go +++ b/resources/geneticReferences/traits/hairColor.go @@ -62,6 +62,7 @@ func getHairColorTraitObject()Trait{ LociList_Rules: []int64{}, RulesList: []TraitRule{}, OutcomesList: []string{}, + NumericValueFormatter: nil, ReferencesMap: referencesMap, } diff --git a/resources/geneticReferences/traits/hairTexture.go b/resources/geneticReferences/traits/hairTexture.go index b731eda..46fd4e6 100644 --- a/resources/geneticReferences/traits/hairTexture.go +++ b/resources/geneticReferences/traits/hairTexture.go @@ -245,6 +245,7 @@ func getHairTextureTraitObject()Trait{ LociList_Rules: lociList_Rules, RulesList: hairTextureRulesList, OutcomesList: outcomesList, + NumericValueFormatter: nil, ReferencesMap: referencesMap, } diff --git a/resources/geneticReferences/traits/height.go b/resources/geneticReferences/traits/height.go index b0152bb..09ef4c0 100644 --- a/resources/geneticReferences/traits/height.go +++ b/resources/geneticReferences/traits/height.go @@ -1,11 +1,13 @@ package traits +import "seekia/internal/globalSettings" import "seekia/internal/helpers" import "maps" import _ "embed" +import "errors" import "encoding/gob" import "bytes" @@ -50,6 +52,40 @@ func getHeightTraitObject()(Trait, error){ referencesMap := make(map[string]string) referencesMap["GIANT consortium - Meta-analyses of Genome-Wide Association Studies - 2022 - Height"] = "https://portals.broadinstitute.org/collaboration/giant/index.php/GIANT_consortium_data_files" + numericValueFormatter := func(inputHeight float64, _ bool)(string, error){ + + getMyMetricOrImperial := func()(string, error){ + + exists, metricOrImperial, err := globalSettings.GetSetting("MetricOrImperial") + if (err != nil) { return "", err } + if (exists == false){ + return "Metric", nil + } + if (metricOrImperial != "Metric" && metricOrImperial != "Imperial"){ + return "", errors.New("Malformed globalSettings: Invalid metricOrImperial: " + metricOrImperial) + } + + return metricOrImperial, nil + } + + myMetricOrImperial, err := getMyMetricOrImperial() + if (err != nil){ return "", err } + if (myMetricOrImperial == "Metric"){ + centimetersString := helpers.ConvertFloat64ToStringRounded(inputHeight, 2) + + //TODO: Translate units + + centimetersWithUnits := centimetersString + " centimeters" + + return centimetersWithUnits, nil + } + + feetInchesString, err := helpers.ConvertCentimetersToFeetInchesTranslatedString(inputHeight) + if (err != nil) { return "", err } + + return feetInchesString, nil + } + heightObject := Trait{ TraitName: "Height", TraitDescription: "The distance between the top of a standing person head and the floor.", @@ -59,6 +95,7 @@ func getHeightTraitObject()(Trait, error){ LociList_Rules: []int64{}, RulesList: []TraitRule{}, OutcomesList: []string{}, + NumericValueFormatter: numericValueFormatter, ReferencesMap: referencesMap, } diff --git a/resources/geneticReferences/traits/homosexualness.go b/resources/geneticReferences/traits/homosexualness.go new file mode 100644 index 0000000..b4e9618 --- /dev/null +++ b/resources/geneticReferences/traits/homosexualness.go @@ -0,0 +1,59 @@ +package traits + +import "seekia/internal/helpers" + +import "maps" + +func getHomosexualnessTraitObject()Trait{ + + // Map Structure: rsID -> References Map + locusReferencesMap := make(map[int64]map[string]string) + + referencesMap_List1 := make(map[string]string) + referencesMap_List1["Large-scale GWAS reveals insights into the genetic architecture of same-sex sexual behavior"] = "https://www.science.org/doi/10.1126/science.aat7693" + + lociList_1 := []int64{ + 10261857, + 28371400, + 34730029, + 11114975, + } + + for _, rsID := range lociList_1{ + locusReferencesMap[rsID] = maps.Clone(referencesMap_List1) + } + + homosexualnessLociList := helpers.GetListOfMapKeys(locusReferencesMap) + + referencesMap := make(map[string]string) + referencesMap["Large-scale GWAS reveals insights into the genetic architecture of same-sex sexual behavior"] = "https://www.science.org/doi/10.1126/science.aat7693" + + valueFormatter := func(inputHomosexualness float64, showUnits bool)(string, error){ + + inputHomosexualnessString := helpers.ConvertIntToString(int(inputHomosexualness)) + + if (showUnits == false){ + return inputHomosexualnessString, nil + } + + formattedValue := inputHomosexualnessString + "/10" + + return formattedValue, nil + } + + homosexualnessObject := Trait{ + TraitName: "Homosexualness", + TraitDescription: "Feelings of sexual attraction towards people who belong to a person's own sex.", + DiscreteOrNumeric: "Numeric", + LocusReferencesMap: locusReferencesMap, + LociList: homosexualnessLociList, + LociList_Rules: []int64{}, + RulesList: []TraitRule{}, + OutcomesList: []string{}, + NumericValueFormatter: valueFormatter, + ReferencesMap: referencesMap, + } + + return homosexualnessObject +} + diff --git a/resources/geneticReferences/traits/lactoseTolerance.go b/resources/geneticReferences/traits/lactoseTolerance.go index 807a93b..ed3f7d6 100644 --- a/resources/geneticReferences/traits/lactoseTolerance.go +++ b/resources/geneticReferences/traits/lactoseTolerance.go @@ -140,6 +140,7 @@ func getLactoseToleranceTraitObject()Trait{ LociList_Rules: lociList_Rules, RulesList: lactoseToleranceRulesList, OutcomesList: outcomesList, + NumericValueFormatter: nil, ReferencesMap: referencesMap, } diff --git a/resources/geneticReferences/traits/skinColor.go b/resources/geneticReferences/traits/skinColor.go index 699b4b5..5a6869f 100644 --- a/resources/geneticReferences/traits/skinColor.go +++ b/resources/geneticReferences/traits/skinColor.go @@ -82,6 +82,7 @@ func getSkinColorTraitObject()Trait{ LociList_Rules: []int64{}, RulesList: []TraitRule{}, OutcomesList: []string{}, + NumericValueFormatter: nil, ReferencesMap: referencesMap, } diff --git a/resources/geneticReferences/traits/traits.go b/resources/geneticReferences/traits/traits.go index d636499..ea849ae 100644 --- a/resources/geneticReferences/traits/traits.go +++ b/resources/geneticReferences/traits/traits.go @@ -22,7 +22,7 @@ type Trait struct{ // These loci may not have any associated rules // We use these loci to predict trait outcomes with neural networks. // We also use these loci to calculate Racial Similarity. - // Map Structure: rsID -> (map[ReferenceName]Reference Link) + // Map Structure: rsID -> (map[Reference Name]Reference Link) LocusReferencesMap map[int64]map[string]string // This is a list of all loci used to predict this trait @@ -43,6 +43,17 @@ type Trait struct{ // If the trait is Numeric, or their or no rules nor a neural network, then this list will be empty. OutcomesList []string + // This function returns a formatted, translated representation of a numeric value for this trait + // For example, "150 centimeters", "5 foot 10 inches", "4/10" + // Inputs: + // -float64: The value to format + // -bool: Show "/10" units + // -The "/10" units are used for certain traits, where the unit value is not a real-world measurement (such as length, weight, etc.) + // -An example of an "/10" trait is Homosexuality, which is represented by a value between 0 and 10. + // -We don't want to "/10" if we are displaying a confidence range (Example: +/- 5.2) + // -If we did, then people would get confused by thinking the unit represents a fraction + NumericValueFormatter func(float64, bool)(string, error) + // This map contains scientific resources about this trait // Map structure: Reference name -> Reference link ReferencesMap map[string]string @@ -99,11 +110,13 @@ func InitializeTraitVariables()error{ eyeColorObject := getEyeColorTraitObject() hairColorObject := getHairColorTraitObject() skinColorObject := getSkinColorTraitObject() + homosexualnessObject := getHomosexualnessTraitObject() heightObject, err := getHeightTraitObject() if (err != nil){ return err } - traitObjectsList = []Trait{lactoseToleranceObject, hairTextureObject, facialStructureObject, eyeColorObject, hairColorObject, skinColorObject, heightObject} + + traitObjectsList = []Trait{lactoseToleranceObject, hairTextureObject, facialStructureObject, eyeColorObject, hairColorObject, skinColorObject, heightObject, homosexualnessObject} traitNamesList = make([]string, 0, len(traitObjectsList)) locusRSIDsMap = make(map[string]int64) diff --git a/utilities/createGeneticModels/createGeneticModels.go b/utilities/createGeneticModels/createGeneticModels.go index 09cb691..b93f3b8 100644 --- a/utilities/createGeneticModels/createGeneticModels.go +++ b/utilities/createGeneticModels/createGeneticModels.go @@ -1,6 +1,6 @@ // createGeneticModels.go provides an interface to create genetic prediction models -// These are neural networks which predict traits such as eye color from raw genome files +// These are neural networks which predict attributes such as eye color and autism from raw genome files // The OpenSNP.org dataset is used, and more datasets will be added in the future. // You must download the dataset and extract it. The instructions are described in the utility. // The trained models are saved in the /resources/geneticPredictionModels package for use in the Seekia app. @@ -16,6 +16,7 @@ import "fyne.io/fyne/v2/layout" import "fyne.io/fyne/v2/dialog" import "fyne.io/fyne/v2/data/binding" +import "seekia/resources/geneticReferences/polygenicDiseases" import "seekia/resources/geneticReferences/traits" import "seekia/resources/geneticReferences/locusMetadata" @@ -24,6 +25,7 @@ import "seekia/internal/genetics/locusValue" import "seekia/internal/genetics/prepareRawGenomes" import "seekia/internal/genetics/readRawGenomes" import "seekia/internal/genetics/geneticPrediction" +import "seekia/internal/globalSettings" import "seekia/internal/helpers" import "seekia/internal/imagery" import "seekia/internal/localFilesystem" @@ -46,12 +48,20 @@ import "time" func main(){ + polygenicDiseases.InitializePolygenicDiseaseVariables() + err := traits.InitializeTraitVariables() if (err != nil){ panic(err) return } + err = globalSettings.InitializeGlobalSettingsDatastore() + if (err != nil){ + panic(err) + return + } + app := app.New() customTheme := getCustomFyneTheme() @@ -209,7 +219,7 @@ func setHomePage(window fyne.Window){ title := getBoldLabelCentered("Create Genetic Models Utility") description1 := getLabelCentered("This utility is used to create the genetic prediction models.") - description2 := getLabelCentered("These models are used to predict traits such as eye color from raw genome files.") + description2 := getLabelCentered("These models are used to predict attributes such as eye color and autism from raw genome files.") description3 := getLabelCentered("Seekia aims to have open source and reproducible genetic prediction technology.") step1Label := getLabelCentered("Step 1:") @@ -722,16 +732,16 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f _, err = localFilesystem.CreateFolder("./TrainingData") if (err != nil) { return false, false, err } - //TODO: Add more traits - traitNamesList := []string{"Eye Color", "Lactose Tolerance", "Height"} + //TODO: Add more attributes + attributeNamesList := []string{"Eye Color", "Lactose Tolerance", "Height", "Autism", "Homosexualness"} - // We create the folders for each trait's training data + // We create the folders for each attribute's training data - for _, traitName := range traitNamesList{ + for _, attributeName := range attributeNamesList{ - traitNameWithoutWhitespace := strings.ReplaceAll(traitName, " ", "") + attributeNameWithoutWhitespace := strings.ReplaceAll(attributeName, " ", "") - folderpath := goFilepath.Join("./TrainingData/", traitNameWithoutWhitespace) + folderpath := goFilepath.Join("./TrainingData/", attributeNameWithoutWhitespace) _, err = localFilesystem.CreateFolder(folderpath) if (err != nil) { return false, false, err } @@ -891,13 +901,13 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f continue } - for _, traitName := range traitNamesList{ + for _, attributeName := range attributeNamesList{ - traitNameWithoutWhitespace := strings.ReplaceAll(traitName, " ", "") + attributeNameWithoutWhitespace := strings.ReplaceAll(attributeName, " ", "") - trainingDataFolderpath := goFilepath.Join("./TrainingData", traitNameWithoutWhitespace) + trainingDataFolderpath := goFilepath.Join("./TrainingData", attributeNameWithoutWhitespace) - userDataExists, userTrainingDataList, err := geneticPrediction.CreateGeneticPredictionTrainingData_OpenSNP(traitName, userPhenotypeDataObject, userLociValuesMap) + userDataExists, userTrainingDataList, err := geneticPrediction.CreateGeneticPredictionTrainingData_OpenSNP(attributeName, userPhenotypeDataObject, userLociValuesMap) if (err != nil) { return false, false, err } if (userDataExists == false){ // User cannot be used for training @@ -991,35 +1001,35 @@ func setTrainModelsPage(window fyne.Window, previousPage func()){ description1 := getLabelCentered("Press the button below to begin training a genetic model.") description2 := getLabelCentered("This will train a neural network using the user training data.") description3 := getLabelCentered("This will take a while.") - description4 := getLabelCentered("You must select a trait model to train.") + description4 := getLabelCentered("You must select a model to train.") - traitNamesList := []string{"Eye Color", "Lactose Tolerance", "Height"} + attributeNamesList := []string{"Eye Color", "Lactose Tolerance", "Height", "Autism", "Homosexualness"} - traitNameSelector := widget.NewSelect(traitNamesList, nil) + attributeNameSelector := widget.NewSelect(attributeNamesList, nil) beginTrainingButton := getWidgetCentered(widget.NewButtonWithIcon("Begin Training Model", theme.MediaPlayIcon(), func(){ - selectedTraitIndex := traitNameSelector.SelectedIndex() - if (selectedTraitIndex < 0){ - title := "No Trait Selected" - dialogMessage1 := getLabelCentered("You must select a trait model to train.") + selectedAttributeIndex := attributeNameSelector.SelectedIndex() + if (selectedAttributeIndex < 0){ + title := "No Attribute Selected" + dialogMessage1 := getLabelCentered("You must select an attribute model to train.") dialogContent := container.NewVBox(dialogMessage1) dialog.ShowCustom(title, "Close", dialogContent, window) return } - traitName := traitNameSelector.Selected - setStartAndMonitorTrainModelPage(window, traitName, currentPage) + attributeName := attributeNameSelector.Selected + setStartAndMonitorTrainModelPage(window, attributeName, currentPage) })) - traitNameSelectorCentered := getWidgetCentered(traitNameSelector) + attributeNameSelectorCentered := getWidgetCentered(attributeNameSelector) - page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), traitNameSelectorCentered, widget.NewSeparator(), beginTrainingButton) + page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), attributeNameSelectorCentered, widget.NewSeparator(), beginTrainingButton) window.SetContent(page) } -func setStartAndMonitorTrainModelPage(window fyne.Window, traitName string, previousPage func()){ +func setStartAndMonitorTrainModelPage(window fyne.Window, attributeName string, previousPage func()){ title := getBoldLabelCentered("Train Model") @@ -1154,7 +1164,7 @@ func setStartAndMonitorTrainModelPage(window fyne.Window, traitName string, prev _, err := localFilesystem.CreateFolder("./TrainedModels") if (err != nil) { return false, err } - trainingSetFilepathsList, _, err := getTrainingAndTestingDataFilepathLists(traitName) + trainingSetFilepathsList, _, err := getTrainingAndTestingDataFilepathLists(attributeName) if (err != nil) { return false, err } // Now we deterministically randomize the order of the trainingSetFilepathsList @@ -1165,7 +1175,7 @@ func setStartAndMonitorTrainModelPage(window fyne.Window, traitName string, prev }) // We create a new neural network object to train - neuralNetworkObject, err := geneticPrediction.GetNewUntrainedNeuralNetworkObject(traitName) + neuralNetworkObject, err := geneticPrediction.GetNewUntrainedNeuralNetworkObject(attributeName) if (err != nil) { return false, err } // The number of rounds of training for the training data set @@ -1253,21 +1263,28 @@ func setStartAndMonitorTrainModelPage(window fyne.Window, traitName string, prev return false, true, trainingDataObject, nil } - traitObject, err := traits.GetTraitObject(traitName) - if (err != nil) { return false, err } + getAttributeIsNumericBool := func()(bool, error){ - getTraitIsNumericBool := func()bool{ + switch attributeName{ - traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric - if (traitIsDiscreteOrNumeric == "Numeric"){ - return true + case "Height", + "Autism", + "Homosexualness":{ + return true, nil + } + case "Lactose Tolerance", + "Eye Color":{ + return false, nil + } } - return false + + return false, errors.New("setStartAndMonitorTrainModelPage called with unknown attributeName: " + attributeName) } - traitIsNumeric := getTraitIsNumericBool() + attributeIsNumeric, err := getAttributeIsNumericBool() + if (err != nil) { return false, err } - processCompleted, err := geneticPrediction.TrainNeuralNetwork(traitName, traitIsNumeric, neuralNetworkObject, getNextTrainingDataFunction) + processCompleted, err := geneticPrediction.TrainNeuralNetwork(attributeName, attributeIsNumeric, neuralNetworkObject, getNextTrainingDataFunction) if (err != nil) { return false, err } if (processCompleted == false){ return false, nil @@ -1279,9 +1296,9 @@ func setStartAndMonitorTrainModelPage(window fyne.Window, traitName string, prev neuralNetworkBytes, err := geneticPrediction.EncodeNeuralNetworkObjectToBytes(*neuralNetworkObject) if (err != nil) { return false, err } - traitNameWithoutWhitespaces := strings.ReplaceAll(traitName, " ", "") + attributeNameWithoutWhitespaces := strings.ReplaceAll(attributeName, " ", "") - neuralNetworkFilename := traitNameWithoutWhitespaces + "Model.gob" + neuralNetworkFilename := attributeNameWithoutWhitespaces + "Model.gob" err = localFilesystem.CreateOrOverwriteFile(neuralNetworkBytes, "./TrainedModels/", neuralNetworkFilename) if (err != nil) { return false, err } @@ -1343,36 +1360,36 @@ func setTestModelsPage(window fyne.Window, previousPage func()){ description3 := getLabelCentered("The testing data is not used to train the models.") description4 := getLabelCentered("The results of the testing will be displayed at the end.") description5 := getLabelCentered("The results will also be saved in the ModelAccuracies folder.") - description6 := getLabelCentered("You must select a trait model to test.") + description6 := getLabelCentered("You must select a model to test.") - traitNamesList := []string{"Eye Color", "Lactose Tolerance", "Height"} + attributeNamesList := []string{"Eye Color", "Lactose Tolerance", "Height", "Autism", "Homosexualness"} - traitNameSelector := widget.NewSelect(traitNamesList, nil) + attributeNameSelector := widget.NewSelect(attributeNamesList, nil) beginTestingButton := getWidgetCentered(widget.NewButtonWithIcon("Begin Testing Model", theme.MediaPlayIcon(), func(){ - selectedTraitIndex := traitNameSelector.SelectedIndex() - if (selectedTraitIndex < 0){ - title := "No Trait Selected" - dialogMessage1 := getLabelCentered("You must select a trait model to test.") + selectedAttributeIndex := attributeNameSelector.SelectedIndex() + if (selectedAttributeIndex < 0){ + title := "No Attribute Selected" + dialogMessage1 := getLabelCentered("You must select a model to test.") dialogContent := container.NewVBox(dialogMessage1) dialog.ShowCustom(title, "Close", dialogContent, window) return } - traitName := traitNameSelector.Selected + attributeName := attributeNameSelector.Selected - setStartAndMonitorTestModelPage(window, traitName, currentPage) + setStartAndMonitorTestModelPage(window, attributeName, currentPage) })) - traitNameSelectorCentered := getWidgetCentered(traitNameSelector) + attributeNameSelectorCentered := getWidgetCentered(attributeNameSelector) - page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, description5, description6, widget.NewSeparator(), traitNameSelectorCentered, widget.NewSeparator(), beginTestingButton) + page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, description5, description6, widget.NewSeparator(), attributeNameSelectorCentered, widget.NewSeparator(), beginTestingButton) window.SetContent(page) } -func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previousPage func()){ +func setStartAndMonitorTestModelPage(window fyne.Window, attributeName string, previousPage func()){ title := getBoldLabelCentered("Testing Model") @@ -1409,17 +1426,35 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ window.SetContent(page) - testModelFunction := func(){ + getAttributeIsNumericBool := func()(bool, error){ - traitObject, err := traits.GetTraitObject(traitName) - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return + switch attributeName{ + + case "Height", + "Autism", + "Homosexualness":{ + return true, nil + } + case "Lactose Tolerance", + "Eye Color":{ + return false, nil + } } - traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric + return false, errors.New("setStartAndMonitorTrainModelPage called with unknown attributeName: " + attributeName) + } - if (traitIsDiscreteOrNumeric == "Discrete"){ + attributeIsNumeric, err := getAttributeIsNumericBool() + if (err != nil) { + setErrorEncounteredPage(window, errors.New("setStartAndMonitorTestModelPage called with unknown attributeName: " + attributeName), previousPage) + return + } + + if (attributeIsNumeric == false){ + + // attribute is a Discrete trait + + testModelFunction := func(){ //Outputs: // -bool: Process completed (true == was not stopped mid-way) @@ -1448,10 +1483,10 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ traitPredictionInfoMap := make(map[geneticPrediction.DiscreteTraitOutcomeInfo]TraitAccuracyStatisticsValue) - _, testingSetFilepathsList, err := getTrainingAndTestingDataFilepathLists(traitName) + _, testingSetFilepathsList, err := getTrainingAndTestingDataFilepathLists(attributeName) if (err != nil) { return false, nil, err } - traitNameWithoutWhitespaces := strings.ReplaceAll(traitName, " ", "") + traitNameWithoutWhitespaces := strings.ReplaceAll(attributeName, " ", "") // We read the trained model for this trait modelFilename := traitNameWithoutWhitespaces + "Model.gob" @@ -1504,10 +1539,10 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ return false, nil, errors.New("Neural network prediction output length does not match expected output length.") } - correctOutcomeName, err := geneticPrediction.GetDiscreteOutcomeNameFromOutputLayer(traitName, true, trainingDataExpectedOutputLayer) + correctOutcomeName, err := geneticPrediction.GetDiscreteOutcomeNameFromOutputLayer(attributeName, true, trainingDataExpectedOutputLayer) if (err != nil) { return false, nil, err } - predictedOutcomeName, err := geneticPrediction.GetDiscreteOutcomeNameFromOutputLayer(traitName, true, predictionLayer) + predictedOutcomeName, err := geneticPrediction.GetDiscreteOutcomeNameFromOutputLayer(attributeName, true, predictionLayer) if (err != nil) { return false, nil, err } getPredictionIsCorrectBool := func()bool{ @@ -1674,30 +1709,37 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ return } - setViewModelTestingDiscreteTraitResultsPage(window, traitName, traitPredictionAccuracyInfoMap, previousPage) + setViewModelTestingDiscreteTraitResultsPage(window, attributeName, traitPredictionAccuracyInfoMap, previousPage) + } - } else { + go testModelFunction() + + return - // traitIsDiscreteOrNumeric == "Numeric" + } else { + + // attribute is Numeric + + testModelFunction := func(){ //Outputs: // -bool: Process completed (true == was not stopped mid-way) - // -geneticPrediction.NumericTraitPredictionAccuracyInfoMap + // -geneticPrediction.NumericAttributePredictionAccuracyInfoMap // -error - testModel := func()(bool, geneticPrediction.NumericTraitPredictionAccuracyInfoMap, error){ + testModel := func()(bool, geneticPrediction.NumericAttributePredictionAccuracyInfoMap, error){ // We use this map to count up the information about predictions // We use information from this map to construct the final accuracy information map - // Map Structure: NumericTraitPredictionInfo -> []float64 (List of distances for each prediction) - traitPredictionInfoMap := make(map[geneticPrediction.NumericTraitPredictionInfo][]float64) + // Map Structure: NumericAttributePredictionInfo -> []float64 (List of distances for each prediction) + attributePredictionInfoMap := make(map[geneticPrediction.NumericAttributePredictionInfo][]float64) - _, testingSetFilepathsList, err := getTrainingAndTestingDataFilepathLists(traitName) + _, testingSetFilepathsList, err := getTrainingAndTestingDataFilepathLists(attributeName) if (err != nil) { return false, nil, err } - traitNameWithoutWhitespaces := strings.ReplaceAll(traitName, " ", "") + attributeNameWithoutWhitespaces := strings.ReplaceAll(attributeName, " ", "") - // We read the trained model for this trait - modelFilename := traitNameWithoutWhitespaces + "Model.gob" + // We read the trained model for this attribute + modelFilename := attributeNameWithoutWhitespaces + "Model.gob" trainedModelFilepath := goFilepath.Join("./TrainedModels/", modelFilename) @@ -1749,10 +1791,10 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ return false, nil, errors.New("Neural network numeric prediction output layer length is not 1.") } - correctOutcomeValue, err := geneticPrediction.GetNumericOutcomeValueFromOutputLayer(traitName, trainingDataExpectedOutputLayer) + correctOutcomeValue, err := geneticPrediction.GetNumericOutcomeValueFromOutputLayer(attributeName, trainingDataExpectedOutputLayer) if (err != nil) { return false, nil, err } - predictedOutcomeValue, err := geneticPrediction.GetNumericOutcomeValueFromOutputLayer(traitName, predictionLayer) + predictedOutcomeValue, err := geneticPrediction.GetNumericOutcomeValueFromOutputLayer(attributeName, predictionLayer) if (err != nil) { return false, nil, err } numberOfKnownLoci, numberOfKnownAndPhasedLoci, numberOfLoci, err := geneticPrediction.GetLociInfoFromNetworkInputLayer(trainingDataInputLayer) @@ -1764,19 +1806,19 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ proportionOfPhasedLoci := float64(numberOfKnownAndPhasedLoci)/float64(numberOfKnownLoci) percentageOfPhasedLoci := int(100*proportionOfPhasedLoci) - newNumericTraitPredictionInfo := geneticPrediction.NumericTraitPredictionInfo{ + newNumericAttributePredictionInfo := geneticPrediction.NumericAttributePredictionInfo{ PercentageOfLociTested: percentageOfLociTested, PercentageOfPhasedLoci: percentageOfPhasedLoci, } distanceFromCorrectValue := math.Abs(predictedOutcomeValue - correctOutcomeValue) - existingList, exists := traitPredictionInfoMap[newNumericTraitPredictionInfo] + existingList, exists := attributePredictionInfoMap[newNumericAttributePredictionInfo] if (exists == false){ - traitPredictionInfoMap[newNumericTraitPredictionInfo] = []float64{distanceFromCorrectValue} + attributePredictionInfoMap[newNumericAttributePredictionInfo] = []float64{distanceFromCorrectValue} } else { existingList = append(existingList, distanceFromCorrectValue) - traitPredictionInfoMap[newNumericTraitPredictionInfo] = existingList + attributePredictionInfoMap[newNumericAttributePredictionInfo] = existingList } exampleIndexString := helpers.ConvertIntToString(index+1) @@ -1789,20 +1831,20 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ progressPercentageBinding.Set(newProgressFloat64) } - // Now we construct the TraitAccuracyInfoMap + // Now we construct the AttributeAccuracyInfoMap // This map stores the accuracy for each QuantityOfKnownLoci/QuantityOfPhasedLoci - traitPredictionAccuracyInfoMap := make(map[geneticPrediction.NumericTraitPredictionInfo]geneticPrediction.NumericTraitPredictionAccuracyRangesMap) + attributePredictionAccuracyInfoMap := make(map[geneticPrediction.NumericAttributePredictionInfo]geneticPrediction.NumericAttributePredictionAccuracyRangesMap) - for traitPredictionInfo, predictionDistancesList := range traitPredictionInfoMap{ + for attributePredictionInfo, predictionDistancesList := range attributePredictionInfoMap{ if (len(predictionDistancesList) == 0){ - return false, nil, errors.New("traitPredictionInfoMap contains empty predictionDistancesList.") + return false, nil, errors.New("attributePredictionInfoMap contains empty predictionDistancesList.") } // Map Structure: Accuracy Percentage (AP) -> Amount needed to deviate from prediction // for the value to be accurate (AP)% of the time - newNumericTraitPredictionAccuracyRangesMap := make(map[int]float64) + newNumericAttributePredictionAccuracyRangesMap := make(map[int]float64) if (len(predictionDistancesList) < 5){ // We don't have enough data to create an accuracyRanges map. @@ -1825,7 +1867,7 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ continue } - _, exists := newNumericTraitPredictionAccuracyRangesMap[percentageOfPredictionsWithinDistance] + _, exists := newNumericAttributePredictionAccuracyRangesMap[percentageOfPredictionsWithinDistance] if (exists == true){ // There exists a value for this percentage already // This happens because we convert a float64 to an int @@ -1835,33 +1877,33 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ continue } - newNumericTraitPredictionAccuracyRangesMap[percentageOfPredictionsWithinDistance] = distance + newNumericAttributePredictionAccuracyRangesMap[percentageOfPredictionsWithinDistance] = distance } - traitPredictionAccuracyInfoMap[traitPredictionInfo] = newNumericTraitPredictionAccuracyRangesMap + attributePredictionAccuracyInfoMap[attributePredictionInfo] = newNumericAttributePredictionAccuracyRangesMap } // Testing is complete. // We save the info map as a file in the ModelAccuracies folder - fileBytes, err := geneticPrediction.EncodeNumericTraitPredictionAccuracyInfoMapToBytes(traitPredictionAccuracyInfoMap) + fileBytes, err := geneticPrediction.EncodeNumericAttributePredictionAccuracyInfoMapToBytes(attributePredictionAccuracyInfoMap) if (err != nil) { return false, nil, err } _, err = localFilesystem.CreateFolder("./ModelAccuracies") if (err != nil) { return false, nil, err } - modelAccuracyFilename := traitNameWithoutWhitespaces + "ModelAccuracy.gob" + modelAccuracyFilename := attributeNameWithoutWhitespaces + "ModelAccuracy.gob" err = localFilesystem.CreateOrOverwriteFile(fileBytes, "./ModelAccuracies/", modelAccuracyFilename) if (err != nil) { return false, nil, err } progressPercentageBinding.Set(1) - return true, traitPredictionAccuracyInfoMap, nil + return true, attributePredictionAccuracyInfoMap, nil } - processIsComplete, traitPredictionAccuracyInfoMap, err := testModel() + processIsComplete, attributePredictionAccuracyInfoMap, err := testModel() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return @@ -1871,11 +1913,12 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ return } - setViewModelTestingNumericTraitResultsPage(window, traitName, traitPredictionAccuracyInfoMap, previousPage) + setViewModelTestingNumericAttributeResultsPage(window, attributeName, attributePredictionAccuracyInfoMap, previousPage) + return } - } - go testModelFunction() + go testModelFunction() + } } // This is a page to view the details of testing for a specific trait's model @@ -2043,18 +2086,18 @@ func setViewModelTestingDiscreteTraitResultsPage(window fyne.Window, traitName s } -// This is a page to view the details of testing for a specific trait's model -func setViewModelTestingNumericTraitResultsPage(window fyne.Window, traitName string, traitAccuracyInfoMap geneticPrediction.NumericTraitPredictionAccuracyInfoMap, exitPage func()){ +// This is a page to view the details of testing for a numeric attribute's model +func setViewModelTestingNumericAttributeResultsPage(window fyne.Window, attributeName string, attributeAccuracyInfoMap geneticPrediction.NumericAttributePredictionAccuracyInfoMap, exitPage func()){ - title := getBoldLabelCentered("Numeric Trait Prediction Accuracy Details") + title := getBoldLabelCentered("Numeric Attribute Prediction Accuracy Details") exitButton := getWidgetCentered(widget.NewButtonWithIcon("Exit", theme.CancelIcon(), exitPage)) - description1 := getLabelCentered("The results of the prediction accuracy for this trait are below.") + description1 := getLabelCentered("The results of the prediction accuracy for this attribute are below.") - traitNameTitle := widget.NewLabel("Trait Name:") - traitNameLabel := getBoldLabel(traitName) - traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameTitle, traitNameLabel, layout.NewSpacer()) + attributeNameTitle := widget.NewLabel("Attribute Name:") + attributeNameLabel := getBoldLabel(attributeName) + attributeNameRow := container.NewHBox(layout.NewSpacer(), attributeNameTitle, attributeNameLabel, layout.NewSpacer()) description2 := getLabelCentered("Each value is a range that the prediction must be widened by to be accurate X% of the time.") description3 := getLabelCentered("For example, for a height prediction to be accurate 90% of the time, allow a +/-10 cm range.") @@ -2078,14 +2121,41 @@ func setViewModelTestingNumericTraitResultsPage(window fyne.Window, traitName st accuracyRangeColumn_34to66 := container.NewVBox(accuracyRangeTitle2, knownLociLabel_34to66, widget.NewSeparator()) accuracyRangeColumn_67to100 := container.NewVBox(accuracyRangeTitle3, knownLociLabel_67to100, widget.NewSeparator()) - traitObject, err := traits.GetTraitObject(traitName) - if (err != nil) { return nil, err } + // We get the formatter for the distance values + // This converts raw predictions to formatted values + // Example: 100 -> "100 centimeters" - traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric - if (traitIsDiscreteOrNumeric != "Numeric"){ - return nil, errors.New("setViewModelTestingNumericTraitResultsPage called with non-discrete trait: " + traitName) + getAttributeValueFormatter := func()(func(float64, bool)(string, error), error){ + switch attributeName{ + case "Homosexuality", + "Height":{ + + traitObject, err := traits.GetTraitObject(attributeName) + if (err != nil) { return nil, err } + + numericValueFormatter := traitObject.NumericValueFormatter + + return numericValueFormatter, nil + } + } + + // attribute is a polygenic disease + + result := func(inputValue float64, _ bool)(string, error){ + + // Input value is a value between 0 and 10 + + inputValueFormatted := helpers.ConvertIntToString(int(inputValue)) + + return inputValueFormatted, nil + } + + return result, nil } + attributeValueFormatter, err := getAttributeValueFormatter() + if (err != nil){ return nil, err } + probabilityMinimumRange := 1 for { @@ -2125,11 +2195,11 @@ func setViewModelTestingNumericTraitResultsPage(window fyne.Window, traitName st predictionAccuracyDistancesSum_67to100 := float64(0) distancesCount_67to100 := 0 - for traitOutcomeInfo, traitPredictionAccuracyRangesMap := range traitAccuracyInfoMap{ + for attributeOutcomeInfo, attributePredictionAccuracyRangesMap := range attributeAccuracyInfoMap{ - percentageOfLociTested := traitOutcomeInfo.PercentageOfLociTested + percentageOfLociTested := attributeOutcomeInfo.PercentageOfLociTested - for percentageCorrect, distance := range traitPredictionAccuracyRangesMap{ + for percentageCorrect, distance := range attributePredictionAccuracyRangesMap{ if (percentageCorrect < probabilityMinimumRange || percentageCorrect > probabilityMaximumRange){ continue @@ -2153,24 +2223,27 @@ func setViewModelTestingNumericTraitResultsPage(window fyne.Window, traitName st } } - getAverageAccuracyText := func(distancesSum float64, distancesCount int)string{ + getAverageAccuracyText := func(distancesSum float64, distancesCount int)(string, error){ if (distancesCount == 0){ - return "Unknown" + return "Unknown", nil } averageDistance := distancesSum/float64(distancesCount) - averageDistanceString := helpers.ConvertFloat64ToStringRounded(averageDistance, 1) + averageDistanceFormatted, err := attributeValueFormatter(averageDistance, false) + if (err != nil) { return "", err } - //TODO: Retrieve units from traits package? - result := "+/- " + averageDistanceString + " centimeters" + result := "+/- " + averageDistanceFormatted - return result + return result, nil } - averageDistanceText_0to33 := getAverageAccuracyText(predictionAccuracyDistancesSum_0to33, distancesCount_0to33) - averageDistanceText_34to66 := getAverageAccuracyText(predictionAccuracyDistancesSum_34to66, distancesCount_34to66) - averageDistanceText_67to100 := getAverageAccuracyText(predictionAccuracyDistancesSum_67to100, distancesCount_67to100) + averageDistanceText_0to33, err := getAverageAccuracyText(predictionAccuracyDistancesSum_0to33, distancesCount_0to33) + if (err != nil){ return nil, err } + averageDistanceText_34to66, err := getAverageAccuracyText(predictionAccuracyDistancesSum_34to66, distancesCount_34to66) + if (err != nil){ return nil, err } + averageDistanceText_67to100, err := getAverageAccuracyText(predictionAccuracyDistancesSum_67to100, distancesCount_67to100) + if (err != nil){ return nil, err } averageDistanceLabel_0to33 := getBoldLabelCentered(averageDistanceText_0to33) averageDistanceLabel_34to66 := getBoldLabelCentered(averageDistanceText_34to66) @@ -2204,7 +2277,7 @@ func setViewModelTestingNumericTraitResultsPage(window fyne.Window, traitName st return } - page := container.NewVBox(title, exitButton, widget.NewSeparator(), description1, widget.NewSeparator(), traitNameRow, widget.NewSeparator(), description2, description3, widget.NewSeparator(), resultsGrid) + page := container.NewVBox(title, exitButton, widget.NewSeparator(), description1, widget.NewSeparator(), attributeNameRow, widget.NewSeparator(), description2, description3, widget.NewSeparator(), resultsGrid) pageScrollable := container.NewVScroll(page) @@ -2212,20 +2285,16 @@ func setViewModelTestingNumericTraitResultsPage(window fyne.Window, traitName st } -// This function returns a list of training data and testing data filepaths for a trait. +// This function returns a list of training data and testing data filepaths for an attribute. //Outputs: // -[]string: Sorted list of training data filepaths // -[]string: Unsorted list of testing data filepaths // -error -func getTrainingAndTestingDataFilepathLists(traitName string)([]string, []string, error){ +func getTrainingAndTestingDataFilepathLists(attributeName string)([]string, []string, error){ - if (traitName != "Eye Color" && traitName != "Lactose Tolerance" && traitName != "Height"){ - return nil, nil, errors.New("getTrainingAndTestingDataFilepathLists called with invalid traitName: " + traitName) - } + attributeNameWithoutWhitespaces := strings.ReplaceAll(attributeName, " ", "") - traitNameWithoutWhitespaces := strings.ReplaceAll(traitName, " ", "") - - trainingDataFolderpath := goFilepath.Join("./TrainingData/", traitNameWithoutWhitespaces) + trainingDataFolderpath := goFilepath.Join("./TrainingData/", attributeNameWithoutWhitespaces) filesList, err := os.ReadDir(trainingDataFolderpath) if (err != nil) { return nil, nil, err } @@ -2238,7 +2307,7 @@ func getTrainingAndTestingDataFilepathLists(traitName string)([]string, []string filepathIsFolder := filesystemObject.IsDir() if (filepathIsFolder == true){ // Folder is corrupt - return nil, nil, errors.New("Training data is corrupt for trait: " + traitName) + return nil, nil, errors.New("Training data is corrupt for attribute: " + attributeName) } fileName := filesystemObject.Name() @@ -2249,24 +2318,32 @@ func getTrainingAndTestingDataFilepathLists(traitName string)([]string, []string numberOfTrainingDataFiles := len(trainingDataFilenamesMap) if (numberOfTrainingDataFiles == 0){ - return nil, nil, errors.New("No training data exists for trait: " + traitName) + return nil, nil, errors.New("No training data exists for attribute: " + attributeName) } getNumberOfExpectedTrainingDatas := func()(int, error){ - if (traitName == "Eye Color"){ + switch attributeName{ - return 113648, nil + case "Eye Color":{ + return 149894, nil - } else if (traitName == "Lactose Tolerance"){ - - return 24872, nil - } else if (traitName == "Height"){ - - return 92281, nil + } + case "Lactose Tolerance":{ + return 24872, nil + } + case "Height":{ + return 92281, nil + } + case "Autism":{ + return 32118, nil + } + case "Homosexualness":{ + return 14500, nil + } } - return 0, errors.New("Unknown traitName: " + traitName) + return 0, errors.New("Unknown attributeName: " + attributeName) } numberOfExpectedTrainingDatas, err := getNumberOfExpectedTrainingDatas() @@ -2276,7 +2353,7 @@ func getTrainingAndTestingDataFilepathLists(traitName string)([]string, []string numberOfTrainingDataFilesString := helpers.ConvertIntToString(numberOfTrainingDataFiles) - return nil, nil, errors.New(traitName + " quantity of training datas is unexpected: " + numberOfTrainingDataFilesString) + return nil, nil, errors.New(attributeName + " quantity of training datas is unexpected: " + numberOfTrainingDataFilesString) } // We sort the training data to be in a deterministically random order @@ -2331,7 +2408,7 @@ func getTrainingAndTestingDataFilepathLists(traitName string)([]string, []string numberOfUsers := len(userIdentifiersList) if (numberOfUsers < 250){ - return nil, nil, errors.New("Too few training data examples for trait: " + traitName) + return nil, nil, errors.New("Too few training data examples for attribute: " + attributeName) } // We use 200 users for testing (validation), so we don't train using them