diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f932e74e..ced235c44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Changed license to Apache +### Docs + +- Added federated learning showcase code + ## [0.229.0-rc.0] - 2023-09-22 ### Authors diff --git a/doc/source/tutorials/federated_learning/assets/architecture.png b/doc/source/tutorials/federated_learning/assets/architecture.png new file mode 100644 index 000000000..652623d58 Binary files /dev/null and b/doc/source/tutorials/federated_learning/assets/architecture.png differ diff --git a/doc/source/tutorials/federated_learning/assets/evaluation.png b/doc/source/tutorials/federated_learning/assets/evaluation.png new file mode 100644 index 000000000..70da27c92 Binary files /dev/null and b/doc/source/tutorials/federated_learning/assets/evaluation.png differ diff --git a/doc/source/tutorials/federated_learning/assets/feature_visualization.png b/doc/source/tutorials/federated_learning/assets/feature_visualization.png new file mode 100644 index 000000000..4078071aa Binary files /dev/null and b/doc/source/tutorials/federated_learning/assets/feature_visualization.png differ diff --git a/doc/source/tutorials/federated_learning/assets/federated_test_accuracies.csv b/doc/source/tutorials/federated_learning/assets/federated_test_accuracies.csv new file mode 100644 index 000000000..7c08818fd --- /dev/null +++ b/doc/source/tutorials/federated_learning/assets/federated_test_accuracies.csv @@ -0,0 +1,151 @@ +,round,dataset,test_accuracy,batch_size,image_dimension,method +0,1,"('keremberke/chest-xray-classification', 'full')",0.8848797250859106,32,64,federated +1,1,"('mmenendezg/raw_pneumonia_x_ray',)",0.8782051282051282,32,64,federated +2,1,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.3733138136568023,32,64,federated +3,2,"('keremberke/chest-xray-classification', 'full')",0.8419243986254296,32,64,federated +4,2,"('mmenendezg/raw_pneumonia_x_ray',)",0.907051282051282,32,64,federated +5,2,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.4181742131130398,32,64,federated +6,3,"('keremberke/chest-xray-classification', 'full')",0.9192439862542955,32,64,federated +7,3,"('mmenendezg/raw_pneumonia_x_ray',)",0.9198717948717948,32,64,federated +8,3,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.6758339433232249,32,64,federated +9,4,"('keremberke/chest-xray-classification', 'full')",0.8762886597938144,32,64,federated +10,4,"('mmenendezg/raw_pneumonia_x_ray',)",0.907051282051282,32,64,federated +11,4,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.6138241137718289,32,64,federated +12,5,"('keremberke/chest-xray-classification', 'full')",0.8969072164948454,32,64,federated +13,5,"('mmenendezg/raw_pneumonia_x_ray',)",0.9230769230769231,32,64,federated +14,5,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7138973125588205,32,64,federated +15,6,"('keremberke/chest-xray-classification', 'full')",0.9243986254295533,32,64,federated +16,6,"('mmenendezg/raw_pneumonia_x_ray',)",0.8990384615384616,32,64,federated +17,6,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7370072153090035,32,64,federated +18,7,"('keremberke/chest-xray-classification', 'full')",0.9501718213058419,32,64,federated +19,7,"('mmenendezg/raw_pneumonia_x_ray',)",0.8910256410256411,32,64,federated +20,7,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7719334936735334,32,64,federated +21,8,"('keremberke/chest-xray-classification', 'full')",0.9501718213058419,32,64,federated +22,8,"('mmenendezg/raw_pneumonia_x_ray',)",0.9278846153846154,32,64,federated +23,8,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.811774547736066,32,64,federated +24,9,"('keremberke/chest-xray-classification', 'full')",0.915807560137457,32,64,federated +25,9,"('mmenendezg/raw_pneumonia_x_ray',)",0.9198717948717948,32,64,federated +26,9,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8927114922095577,32,64,federated +27,10,"('keremberke/chest-xray-classification', 'full')",0.9347079037800687,32,64,federated +28,10,"('mmenendezg/raw_pneumonia_x_ray',)",0.9246794871794872,32,64,federated +29,10,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8557983896266862,32,64,federated +30,11,"('keremberke/chest-xray-classification', 'full')",0.9450171821305842,32,64,federated +31,11,"('mmenendezg/raw_pneumonia_x_ray',)",0.9198717948717948,32,64,federated +32,11,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8679284743281397,32,64,federated +33,12,"('keremberke/chest-xray-classification', 'full')",0.9570446735395189,32,64,federated +34,12,"('mmenendezg/raw_pneumonia_x_ray',)",0.9455128205128205,32,64,federated +35,12,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8829865105092544,32,64,federated +36,13,"('keremberke/chest-xray-classification', 'full')",0.9621993127147767,32,64,federated +37,13,"('mmenendezg/raw_pneumonia_x_ray',)",0.9342948717948718,32,64,federated +38,13,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8907246679912162,32,64,federated +39,14,"('keremberke/chest-xray-classification', 'full')",0.9604810996563574,32,64,federated +40,14,"('mmenendezg/raw_pneumonia_x_ray',)",0.8862179487179487,32,64,federated +41,14,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8907246679912162,32,64,federated +42,15,"('keremberke/chest-xray-classification', 'full')",0.9536082474226805,32,64,federated +43,15,"('mmenendezg/raw_pneumonia_x_ray',)",0.9342948717948718,32,64,federated +44,15,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8928160619052599,32,64,federated +45,16,"('keremberke/chest-xray-classification', 'full')",0.9587628865979382,32,64,federated +46,16,"('mmenendezg/raw_pneumonia_x_ray',)",0.9407051282051282,32,64,federated +47,16,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.864163965282861,32,64,federated +48,17,"('keremberke/chest-xray-classification', 'full')",0.9621993127147767,32,64,federated +49,17,"('mmenendezg/raw_pneumonia_x_ray',)",0.9455128205128205,32,64,federated +50,17,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8933389103837708,32,64,federated +51,18,"('keremberke/chest-xray-classification', 'full')",0.9518900343642611,32,64,federated +52,18,"('mmenendezg/raw_pneumonia_x_ray',)",0.9391025641025641,32,64,federated +53,18,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8797448499424867,32,64,federated +54,19,"('keremberke/chest-xray-classification', 'full')",0.9690721649484536,32,64,federated +55,19,"('mmenendezg/raw_pneumonia_x_ray',)",0.9503205128205128,32,64,federated +56,19,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8587263411063474,32,64,federated +57,20,"('keremberke/chest-xray-classification', 'full')",0.9690721649484536,32,64,federated +58,20,"('mmenendezg/raw_pneumonia_x_ray',)",0.9439102564102564,32,64,federated +59,20,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.9088152253476942,32,64,federated +60,21,"('keremberke/chest-xray-classification', 'full')",0.9621993127147767,32,64,federated +61,21,"('mmenendezg/raw_pneumonia_x_ray',)",0.9503205128205128,32,64,federated +62,21,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8916657952525359,32,64,federated +63,22,"('keremberke/chest-xray-classification', 'full')",0.9690721649484536,32,64,federated +64,22,"('mmenendezg/raw_pneumonia_x_ray',)",0.9535256410256411,32,64,federated +65,22,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.9015999163442434,32,64,federated +66,23,"('keremberke/chest-xray-classification', 'full')",0.9484536082474226,32,64,federated +67,23,"('mmenendezg/raw_pneumonia_x_ray',)",0.9711538461538461,32,64,federated +68,23,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.9011816375614347,32,64,federated +69,24,"('keremberke/chest-xray-classification', 'full')",0.9656357388316151,32,64,federated +70,24,"('mmenendezg/raw_pneumonia_x_ray',)",0.9583333333333334,32,64,federated +71,24,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8956394436892189,32,64,federated +72,25,"('keremberke/chest-xray-classification', 'full')",0.9725085910652921,32,64,federated +73,25,"('mmenendezg/raw_pneumonia_x_ray',)",0.9599358974358975,32,64,federated +74,25,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8602948865418801,32,64,federated +75,26,"('keremberke/chest-xray-classification', 'full')",0.9776632302405498,32,64,federated +76,26,"('mmenendezg/raw_pneumonia_x_ray',)",0.9599358974358975,32,64,federated +77,26,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8663599288926069,32,64,federated +78,27,"('keremberke/chest-xray-classification', 'full')",0.9742268041237113,32,64,federated +79,27,"('mmenendezg/raw_pneumonia_x_ray',)",0.9663461538461539,32,64,federated +80,27,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8456551291435742,32,64,federated +81,28,"('keremberke/chest-xray-classification', 'full')",0.9776632302405498,32,64,federated +82,28,"('mmenendezg/raw_pneumonia_x_ray',)",0.9615384615384616,32,64,federated +83,28,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8428317473596152,32,64,federated +84,29,"('keremberke/chest-xray-classification', 'full')",0.9810996563573883,32,64,federated +85,29,"('mmenendezg/raw_pneumonia_x_ray',)",0.9583333333333334,32,64,federated +86,29,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8285056990484158,32,64,federated +87,30,"('keremberke/chest-xray-classification', 'full')",0.979381443298969,32,64,federated +88,30,"('mmenendezg/raw_pneumonia_x_ray',)",0.9663461538461539,32,64,federated +89,30,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.9231412736588936,32,64,federated +90,31,"('keremberke/chest-xray-classification', 'full')",0.9450171821305842,32,64,federated +91,31,"('mmenendezg/raw_pneumonia_x_ray',)",0.9647435897435898,32,64,federated +92,31,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.9117431768273554,32,64,federated +93,32,"('keremberke/chest-xray-classification', 'full')",0.9776632302405498,32,64,federated +94,32,"('mmenendezg/raw_pneumonia_x_ray',)",0.969551282051282,32,64,federated +95,32,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8210812506535606,32,64,federated +96,33,"('keremberke/chest-xray-classification', 'full')",0.9759450171821306,32,64,federated +97,33,"('mmenendezg/raw_pneumonia_x_ray',)",0.9727564102564102,32,64,federated +98,33,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8800585590295932,32,64,federated +99,34,"('keremberke/chest-xray-classification', 'full')",0.9673539518900344,32,64,federated +100,34,"('mmenendezg/raw_pneumonia_x_ray',)",0.9743589743589743,32,64,federated +101,34,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8766077590714211,32,64,federated +102,35,"('keremberke/chest-xray-classification', 'full')",0.9776632302405498,32,64,federated +103,35,"('mmenendezg/raw_pneumonia_x_ray',)",0.9567307692307693,32,64,federated +104,35,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8547526926696644,32,64,federated +105,36,"('keremberke/chest-xray-classification', 'full')",0.9828178694158075,32,64,federated +106,36,"('mmenendezg/raw_pneumonia_x_ray',)",0.9631410256410257,32,64,federated +107,36,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.852870438147025,32,64,federated +108,37,"('keremberke/chest-xray-classification', 'full')",0.9759450171821306,32,64,federated +109,37,"('mmenendezg/raw_pneumonia_x_ray',)",0.969551282051282,32,64,federated +110,37,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.9165533828296559,32,64,federated +111,38,"('keremberke/chest-xray-classification', 'full')",0.9862542955326461,32,64,federated +112,38,"('mmenendezg/raw_pneumonia_x_ray',)",0.9775641025641025,32,64,federated +113,38,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8313290808323748,32,64,federated +114,39,"('keremberke/chest-xray-classification', 'full')",0.9759450171821306,32,64,federated +115,39,"('mmenendezg/raw_pneumonia_x_ray',)",0.9599358974358975,32,64,federated +116,39,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8735752378960577,32,64,federated +117,40,"('keremberke/chest-xray-classification', 'full')",0.9810996563573883,32,64,federated +118,40,"('mmenendezg/raw_pneumonia_x_ray',)",0.969551282051282,32,64,federated +119,40,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8805814075081041,32,64,federated +120,41,"('keremberke/chest-xray-classification', 'full')",0.9776632302405498,32,64,federated +121,41,"('mmenendezg/raw_pneumonia_x_ray',)",0.9631410256410257,32,64,federated +122,41,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8599811774547736,32,64,federated +123,42,"('keremberke/chest-xray-classification', 'full')",0.9587628865979382,32,64,federated +124,42,"('mmenendezg/raw_pneumonia_x_ray',)",0.967948717948718,32,64,federated +125,42,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8126111053016836,32,64,federated +126,43,"('keremberke/chest-xray-classification', 'full')",0.9810996563573883,32,64,federated +127,43,"('mmenendezg/raw_pneumonia_x_ray',)",0.9711538461538461,32,64,federated +128,43,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8344661717034404,32,64,federated +129,44,"('keremberke/chest-xray-classification', 'full')",0.9759450171821306,32,64,federated +130,44,"('mmenendezg/raw_pneumonia_x_ray',)",0.9711538461538461,32,64,federated +131,44,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7816584753738367,32,64,federated +132,45,"('keremberke/chest-xray-classification', 'full')",0.9828178694158075,32,64,federated +133,45,"('mmenendezg/raw_pneumonia_x_ray',)",0.9535256410256411,32,64,federated +134,45,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.9151939767855276,32,64,federated +135,46,"('keremberke/chest-xray-classification', 'full')",0.9776632302405498,32,64,federated +136,46,"('mmenendezg/raw_pneumonia_x_ray',)",0.967948717948718,32,64,federated +137,46,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7864686813761372,32,64,federated +138,47,"('keremberke/chest-xray-classification', 'full')",0.9845360824742269,32,64,federated +139,47,"('mmenendezg/raw_pneumonia_x_ray',)",0.9711538461538461,32,64,federated +140,47,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8778625954198473,32,64,federated +141,48,"('keremberke/chest-xray-classification', 'full')",0.9810996563573883,32,64,federated +142,48,"('mmenendezg/raw_pneumonia_x_ray',)",0.9631410256410257,32,64,federated +143,48,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8426226079682108,32,64,federated +144,49,"('keremberke/chest-xray-classification', 'full')",0.979381443298969,32,64,federated +145,49,"('mmenendezg/raw_pneumonia_x_ray',)",0.9759615384615384,32,64,federated +146,49,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8819408135522325,32,64,federated +147,50,"('keremberke/chest-xray-classification', 'full')",0.9845360824742269,32,64,federated +148,50,"('mmenendezg/raw_pneumonia_x_ray',)",0.9727564102564102,32,64,federated +149,50,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8752483530272926,32,64,federated diff --git a/doc/source/tutorials/federated_learning/assets/hero.png b/doc/source/tutorials/federated_learning/assets/hero.png new file mode 100644 index 000000000..30d48d98e Binary files /dev/null and b/doc/source/tutorials/federated_learning/assets/hero.png differ diff --git a/doc/source/tutorials/federated_learning/assets/individual_test_accuracies.csv b/doc/source/tutorials/federated_learning/assets/individual_test_accuracies.csv new file mode 100644 index 000000000..72c59dc18 --- /dev/null +++ b/doc/source/tutorials/federated_learning/assets/individual_test_accuracies.csv @@ -0,0 +1,151 @@ +,round,dataset,test_accuracy,batch_size,image_dimension,method +0,1,"('keremberke/chest-xray-classification', 'full')",0.852233676975945,32,64,individual +1,2,"('keremberke/chest-xray-classification', 'full')",0.8676975945017182,32,64,individual +2,3,"('keremberke/chest-xray-classification', 'full')",0.8900343642611683,32,64,individual +3,4,"('keremberke/chest-xray-classification', 'full')",0.8883161512027491,32,64,individual +4,5,"('keremberke/chest-xray-classification', 'full')",0.8969072164948454,32,64,individual +5,6,"('keremberke/chest-xray-classification', 'full')",0.9054982817869416,32,64,individual +6,7,"('keremberke/chest-xray-classification', 'full')",0.9072164948453608,32,64,individual +7,8,"('keremberke/chest-xray-classification', 'full')",0.9037800687285223,32,64,individual +8,9,"('keremberke/chest-xray-classification', 'full')",0.8969072164948454,32,64,individual +9,10,"('keremberke/chest-xray-classification', 'full')",0.9003436426116839,32,64,individual +10,11,"('keremberke/chest-xray-classification', 'full')",0.9072164948453608,32,64,individual +11,12,"('keremberke/chest-xray-classification', 'full')",0.9106529209621993,32,64,individual +12,13,"('keremberke/chest-xray-classification', 'full')",0.9037800687285223,32,64,individual +13,14,"('keremberke/chest-xray-classification', 'full')",0.915807560137457,32,64,individual +14,15,"('keremberke/chest-xray-classification', 'full')",0.915807560137457,32,64,individual +15,16,"('keremberke/chest-xray-classification', 'full')",0.9054982817869416,32,64,individual +16,17,"('keremberke/chest-xray-classification', 'full')",0.9106529209621993,32,64,individual +17,18,"('keremberke/chest-xray-classification', 'full')",0.9192439862542955,32,64,individual +18,19,"('keremberke/chest-xray-classification', 'full')",0.9089347079037801,32,64,individual +19,20,"('keremberke/chest-xray-classification', 'full')",0.9123711340206185,32,64,individual +20,21,"('keremberke/chest-xray-classification', 'full')",0.9192439862542955,32,64,individual +21,22,"('keremberke/chest-xray-classification', 'full')",0.9140893470790378,32,64,individual +22,23,"('keremberke/chest-xray-classification', 'full')",0.9175257731958762,32,64,individual +23,24,"('keremberke/chest-xray-classification', 'full')",0.915807560137457,32,64,individual +24,25,"('keremberke/chest-xray-classification', 'full')",0.9209621993127147,32,64,individual +25,26,"('keremberke/chest-xray-classification', 'full')",0.9209621993127147,32,64,individual +26,27,"('keremberke/chest-xray-classification', 'full')",0.929553264604811,32,64,individual +27,28,"('keremberke/chest-xray-classification', 'full')",0.9243986254295533,32,64,individual +28,29,"('keremberke/chest-xray-classification', 'full')",0.9261168384879725,32,64,individual +29,30,"('keremberke/chest-xray-classification', 'full')",0.9054982817869416,32,64,individual +30,31,"('keremberke/chest-xray-classification', 'full')",0.9312714776632303,32,64,individual +31,32,"('keremberke/chest-xray-classification', 'full')",0.9072164948453608,32,64,individual +32,33,"('keremberke/chest-xray-classification', 'full')",0.9243986254295533,32,64,individual +33,34,"('keremberke/chest-xray-classification', 'full')",0.929553264604811,32,64,individual +34,35,"('keremberke/chest-xray-classification', 'full')",0.929553264604811,32,64,individual +35,36,"('keremberke/chest-xray-classification', 'full')",0.9106529209621993,32,64,individual +36,37,"('keremberke/chest-xray-classification', 'full')",0.9243986254295533,32,64,individual +37,38,"('keremberke/chest-xray-classification', 'full')",0.9123711340206185,32,64,individual +38,39,"('keremberke/chest-xray-classification', 'full')",0.915807560137457,32,64,individual +39,40,"('keremberke/chest-xray-classification', 'full')",0.9226804123711341,32,64,individual +40,41,"('keremberke/chest-xray-classification', 'full')",0.9192439862542955,32,64,individual +41,42,"('keremberke/chest-xray-classification', 'full')",0.9140893470790378,32,64,individual +42,43,"('keremberke/chest-xray-classification', 'full')",0.9467353951890034,32,64,individual +43,44,"('keremberke/chest-xray-classification', 'full')",0.9278350515463918,32,64,individual +44,45,"('keremberke/chest-xray-classification', 'full')",0.9175257731958762,32,64,individual +45,46,"('keremberke/chest-xray-classification', 'full')",0.9278350515463918,32,64,individual +46,47,"('keremberke/chest-xray-classification', 'full')",0.929553264604811,32,64,individual +47,48,"('keremberke/chest-xray-classification', 'full')",0.9450171821305842,32,64,individual +48,49,"('keremberke/chest-xray-classification', 'full')",0.9484536082474226,32,64,individual +49,50,"('keremberke/chest-xray-classification', 'full')",0.936426116838488,32,64,individual +50,1,"('mmenendezg/raw_pneumonia_x_ray',)",0.8894230769230769,32,64,individual +51,2,"('mmenendezg/raw_pneumonia_x_ray',)",0.8846153846153846,32,64,individual +52,3,"('mmenendezg/raw_pneumonia_x_ray',)",0.8846153846153846,32,64,individual +53,4,"('mmenendezg/raw_pneumonia_x_ray',)",0.8766025641025641,32,64,individual +54,5,"('mmenendezg/raw_pneumonia_x_ray',)",0.8782051282051282,32,64,individual +55,6,"('mmenendezg/raw_pneumonia_x_ray',)",0.8766025641025641,32,64,individual +56,7,"('mmenendezg/raw_pneumonia_x_ray',)",0.8782051282051282,32,64,individual +57,8,"('mmenendezg/raw_pneumonia_x_ray',)",0.875,32,64,individual +58,9,"('mmenendezg/raw_pneumonia_x_ray',)",0.8621794871794872,32,64,individual +59,10,"('mmenendezg/raw_pneumonia_x_ray',)",0.8669871794871795,32,64,individual +60,11,"('mmenendezg/raw_pneumonia_x_ray',)",0.8782051282051282,32,64,individual +61,12,"('mmenendezg/raw_pneumonia_x_ray',)",0.8685897435897436,32,64,individual +62,13,"('mmenendezg/raw_pneumonia_x_ray',)",0.8862179487179487,32,64,individual +63,14,"('mmenendezg/raw_pneumonia_x_ray',)",0.875,32,64,individual +64,15,"('mmenendezg/raw_pneumonia_x_ray',)",0.8830128205128205,32,64,individual +65,16,"('mmenendezg/raw_pneumonia_x_ray',)",0.8782051282051282,32,64,individual +66,17,"('mmenendezg/raw_pneumonia_x_ray',)",0.875,32,64,individual +67,18,"('mmenendezg/raw_pneumonia_x_ray',)",0.8782051282051282,32,64,individual +68,19,"('mmenendezg/raw_pneumonia_x_ray',)",0.8798076923076923,32,64,individual +69,20,"('mmenendezg/raw_pneumonia_x_ray',)",0.8862179487179487,32,64,individual +70,21,"('mmenendezg/raw_pneumonia_x_ray',)",0.8846153846153846,32,64,individual +71,22,"('mmenendezg/raw_pneumonia_x_ray',)",0.8974358974358975,32,64,individual +72,23,"('mmenendezg/raw_pneumonia_x_ray',)",0.8862179487179487,32,64,individual +73,24,"('mmenendezg/raw_pneumonia_x_ray',)",0.8846153846153846,32,64,individual +74,25,"('mmenendezg/raw_pneumonia_x_ray',)",0.8894230769230769,32,64,individual +75,26,"('mmenendezg/raw_pneumonia_x_ray',)",0.8894230769230769,32,64,individual +76,27,"('mmenendezg/raw_pneumonia_x_ray',)",0.8878205128205128,32,64,individual +77,28,"('mmenendezg/raw_pneumonia_x_ray',)",0.8878205128205128,32,64,individual +78,29,"('mmenendezg/raw_pneumonia_x_ray',)",0.8814102564102564,32,64,individual +79,30,"('mmenendezg/raw_pneumonia_x_ray',)",0.8862179487179487,32,64,individual +80,31,"('mmenendezg/raw_pneumonia_x_ray',)",0.875,32,64,individual +81,32,"('mmenendezg/raw_pneumonia_x_ray',)",0.8894230769230769,32,64,individual +82,33,"('mmenendezg/raw_pneumonia_x_ray',)",0.8926282051282052,32,64,individual +83,34,"('mmenendezg/raw_pneumonia_x_ray',)",0.8862179487179487,32,64,individual +84,35,"('mmenendezg/raw_pneumonia_x_ray',)",0.8974358974358975,32,64,individual +85,36,"('mmenendezg/raw_pneumonia_x_ray',)",0.8669871794871795,32,64,individual +86,37,"('mmenendezg/raw_pneumonia_x_ray',)",0.8942307692307693,32,64,individual +87,38,"('mmenendezg/raw_pneumonia_x_ray',)",0.8878205128205128,32,64,individual +88,39,"('mmenendezg/raw_pneumonia_x_ray',)",0.8846153846153846,32,64,individual +89,40,"('mmenendezg/raw_pneumonia_x_ray',)",0.8974358974358975,32,64,individual +90,41,"('mmenendezg/raw_pneumonia_x_ray',)",0.8942307692307693,32,64,individual +91,42,"('mmenendezg/raw_pneumonia_x_ray',)",0.8798076923076923,32,64,individual +92,43,"('mmenendezg/raw_pneumonia_x_ray',)",0.8830128205128205,32,64,individual +93,44,"('mmenendezg/raw_pneumonia_x_ray',)",0.8701923076923077,32,64,individual +94,45,"('mmenendezg/raw_pneumonia_x_ray',)",0.8798076923076923,32,64,individual +95,46,"('mmenendezg/raw_pneumonia_x_ray',)",0.8894230769230769,32,64,individual +96,47,"('mmenendezg/raw_pneumonia_x_ray',)",0.8910256410256411,32,64,individual +97,48,"('mmenendezg/raw_pneumonia_x_ray',)",0.8846153846153846,32,64,individual +98,49,"('mmenendezg/raw_pneumonia_x_ray',)",0.875,32,64,individual +99,50,"('mmenendezg/raw_pneumonia_x_ray',)",0.8798076923076923,32,64,individual +100,1,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.5013071211962773,32,64,individual +101,2,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.47725609118477463,32,64,individual +102,3,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.4527867823904632,32,64,individual +103,4,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.5092544180696434,32,64,individual +104,5,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.5657220537488236,32,64,individual +105,6,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.5395796298232772,32,64,individual +106,7,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.589041095890411,32,64,individual +107,8,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.6123601380319983,32,64,individual +108,9,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.5680225870542717,32,64,individual +109,10,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.5976158109379902,32,64,individual +110,11,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.5791069747987033,32,64,individual +111,12,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.573878490013594,32,64,individual +112,13,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.5963609745895639,32,64,individual +113,14,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.6389208407403535,32,64,individual +114,15,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.6652724040573041,32,64,individual +115,16,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.6517829133117222,32,64,individual +116,17,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.684304088675102,32,64,individual +117,18,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.6702917494510091,32,64,individual +118,19,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.6813761371954408,32,64,individual +119,20,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7042769005542194,32,64,individual +120,21,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.6540834466171703,32,64,individual +121,22,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7262365366516783,32,64,individual +122,23,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7122241974275855,32,64,individual +123,24,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.6767750705845446,32,64,individual +124,25,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.6932970825054899,32,64,individual +125,26,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.6905782704172331,32,64,individual +126,27,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.702917494510091,32,64,individual +127,28,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7245634215204434,32,64,individual +128,29,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7372163547004078,32,64,individual +129,30,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7394123183101537,32,64,individual +130,31,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7283279305657221,32,64,individual +131,32,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.747987033357733,32,64,individual +132,33,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7424448394855171,32,64,individual +133,34,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7507058454459897,32,64,individual +134,35,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7796716511554951,32,64,individual +135,36,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7783122451113668,32,64,individual +136,37,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7572937362752274,32,64,individual +137,38,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7781031057199623,32,64,individual +138,39,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7924291540311618,32,64,individual +139,40,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7747568754574924,32,64,individual +140,41,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.784063578374987,32,64,individual +141,42,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7534246575342466,32,64,individual +142,43,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7929520025096727,32,64,individual +143,44,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7798807905468995,32,64,individual +144,45,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7781031057199623,32,64,individual +145,46,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7960890933807383,32,64,individual +146,47,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7838544389835825,32,64,individual +147,48,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7676461361497438,32,64,individual +148,49,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.8017358569486562,32,64,individual +149,50,"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')",0.7971347903377601,32,64,individual diff --git a/doc/source/tutorials/federated_learning/assets/workflow.gif b/doc/source/tutorials/federated_learning/assets/workflow.gif new file mode 100644 index 000000000..2c75b8260 Binary files /dev/null and b/doc/source/tutorials/federated_learning/assets/workflow.gif differ diff --git a/doc/source/tutorials/federated_learning/requirements.txt b/doc/source/tutorials/federated_learning/requirements.txt new file mode 100644 index 000000000..8ff861d3d --- /dev/null +++ b/doc/source/tutorials/federated_learning/requirements.txt @@ -0,0 +1,9 @@ +covalent==0.220.0 +covalent-awsbatch-plugin==0.26.0 +covalent-azurebatch-plugin==0.12.0 +covalent-gcpbatch-plugin==0.9.0 +datasets==2.14.0 +pandas +plotly +torch==2.0.1 +torchvision==0.15.2 diff --git a/doc/source/tutorials/federated_learning/source.ipynb b/doc/source/tutorials/federated_learning/source.ipynb new file mode 100644 index 000000000..bc0e6d042 --- /dev/null +++ b/doc/source/tutorials/federated_learning/source.ipynb @@ -0,0 +1,2614 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "146d846a-594c-4024-bb43-b04575880e67", + "metadata": {}, + "source": [ + "# Improving Chest X-ray Pneumonia Detection with Federated Learning and Covalent\n", + "\n", + "![alt text](assets/hero.png \"Covalent\")\n", + "\n", + "In this tutorial, we will provide a comprehensive guide on federated learning, dive into the technical aspects required for building Covalent workflows, and showcase how the two can be combined to build powerful experiments. The exemplar case we will employ involves the identification of pneumonia from chest X-rays." + ] + }, + { + "cell_type": "markdown", + "id": "400f9bb8-498d-4915-ab45-d70511ef3c52", + "metadata": {}, + "source": [ + "This tutorial requires PyTorch, Hugging Face Transformers and Covalent plugins. To install all of them, simply use the requirements.txt file to replicate this notebook" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "c1f42d9a-f340-42f3-a7fe-fd8c11d9d65d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "covalent==0.220.0\n", + "covalent-awsbatch-plugin==0.26.0\n", + "covalent-azurebatch-plugin==0.12.0\n", + "covalent-gcpbatch-plugin==0.9.0\n", + "datasets==2.14.0\n", + "torch==2.0.1\n", + "torchvision==0.15.2\n", + "pandas\n", + "plotly\n" + ] + } + ], + "source": [ + "with open(\"./requirements.txt\", \"r\") as file:\n", + " for line in file:\n", + " print(line.rstrip())" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "167485a1-d709-4f27-b4f4-6b2e6c98947e", + "metadata": {}, + "outputs": [], + "source": [ + "# Uncomment below line to install necessary libraries\n", + "# !pip install -r requirements.txt" + ] + }, + { + "cell_type": "markdown", + "id": "2872e864-d3a9-4265-bece-001baa88829a", + "metadata": {}, + "source": [ + "# Federated Learning on Pneumonia Chest X-rays\n", + "In our demonstration of federated learning, we will train three separate Convolutional Neural Networks (CNNs) using distinct Pneumonia Chest X-ray datasets. Subsequently, the trained models and their corresponding weights will be transmitted back to a central node. On this central node, we will perform weight aggregation using a simple weighted arithmetic mean:\n", + "\n", + "$$\n", + "\\begin{equation}\n", + "w_{j} = \\sum_{k=1}^{K} \\frac{w_{jk} d_k}{\\sum_{i=1}^{K}d_i}\n", + "\\tag{1}\n", + "\\end{equation}\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "25b99a4c-2d63-4363-9035-9a0679110901", + "metadata": {}, + "source": [ + "Here, $w_j$ represents the set of weights in CNN layer $j$, $K$ is the number of models/datasets, which in our case is three, and $d_k$ represents the size of the dataset $k$." + ] + }, + { + "cell_type": "markdown", + "id": "a6886368-315d-4725-b24e-6bbc01b87eab", + "metadata": {}, + "source": [ + "This federated learning variant is commonly called [centralized federated learning](https://en.wikipedia.org/wiki/Federated_learning#Centralized_federated_learning), where a single central node oversees the entire learning process. Utilizing weight averaging represents just one approach among several options available in federated learning. Other alternatives include exchanging gradients instead of weights or implementing techniques such as dynamic regularization.\n", + "\n", + "Broadly speaking, our federated learning workflow encompasses the subsequent stages:\n", + "\n", + "1. Training autonomous CNN models in isolation.\n", + "2. Consolidating the distinct CNN models into a singular aggregated model.\n", + "3. Iteratively revisiting steps 1-2, this time refining the autonomous models by fine-tuning the aggregated model. \n", + "\n", + "We execute the workflow for a predefined number of rounds. Each round entails training separate CNN models on isolated nodes without sharing any data. Subsequently, we aggregate the models, and evaluation is performed on each individual test set. Throughout the process, the centralized node solely possesses information about the model weights, dataset size, and accuracy scores.\n", + "\n", + "For datasets, we will utilize three datasets currently available in the 🤗 Hugging Face Datasets repository:\n", + "\n", + "- [chest-xray-classification](https://huggingface.co/datasets/keremberke/chest-xray-classification)\n", + "- [raw_pneumonia_x_ray](https://huggingface.co/datasets/mmenendezg/raw_pneumonia_x_ray)\n", + "- [NIH-Chest-X-ray-dataset](https://huggingface.co/datasets/alkzar90/NIH-Chest-X-ray-dataset)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "b3aab487-706e-4790-a5a5-41504678addf", + "metadata": {}, + "outputs": [], + "source": [ + "import covalent as ct\n", + "\n", + "import os\n", + "from datasets import load_dataset\n", + "from torch.utils.data import Dataset, DataLoader\n", + "from torchvision import transforms\n", + "import torch.optim as optim\n", + "from tqdm import tqdm\n", + "from torch import nn\n", + "import numpy as np\n", + "import pandas as pd\n", + "import torch\n", + "from dataclasses import dataclass\n", + "from typing import Tuple, Callable, Dict\n", + "import pickle\n", + "\n", + "from collections import Counter\n", + "\n", + "\n", + "@dataclass\n", + "class HFDataset:\n", + " \"\"\"\n", + " A class to represent a dataset available\n", + " in the Hugging Face repository.\n", + " \"\"\"\n", + " name: Tuple[str, str]\n", + " cloud_provider: str\n", + " filter_func: Callable[[Dict[str, str]], bool] = None\n", + " transform_label_func: Callable[[Dict[str, str]], int] = None" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "b0bec015-9ee9-4791-b5c4-abcc47522e1f", + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install covalent-awsbatch-plugin covalent-gcpbatch-plugin covalent-azurebatch-plugin" + ] + }, + { + "cell_type": "markdown", + "id": "1edab435-2cb3-40cd-945a-bef817bbf33c", + "metadata": {}, + "source": [ + "We define parameters for three different executor types, one for each cloud. Each respective cloud instance will handle a single data source, ensuring data isolation as our approach to data separation. The association between a cloud and a dataset will be defined at runtime. " + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "2b8ee937-06d6-425f-99d3-6522ef6dfe92", + "metadata": {}, + "outputs": [], + "source": [ + "AWS_EXECUTOR_DEFAULT_PARAMS = {\n", + " \"vcpu\": 2,\n", + " \"memory\": 4,\n", + " \"num_gpus\": 0,\n", + " \"retry_attempts\": 1,\n", + " \"time_limit\": 3000,\n", + " \"poll_freq\": 3\n", + "}\n", + "GCP_EXECUTOR_DEFAULT_PARAMS = {\n", + " \"vcpus\": 4,\n", + " \"memory\": 4096,\n", + " \"time_limit\": 3000,\n", + " \"poll_freq\": 3,\n", + " \"retries\": 1\n", + "}\n", + "AZURE_EXECUTOR_DEFAULT_PARAMS = {\n", + " \"pool_id\": \"default\",\n", + " \"retries\": 1,\n", + " \"time_limit\": 3000,\n", + " \"cache_dir\": \"/tmp/covalent\",\n", + " \"poll_freq\": 3\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "cc84143b-0c55-4921-850c-5d2b90fe4530", + "metadata": {}, + "source": [ + "Our stub workflow signature suggests we run federated learning for a specified number of rounds on specified datasets. " + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "cc9dca6d-4957-4c55-b57c-d0918f73fc4c", + "metadata": {}, + "outputs": [], + "source": [ + "@ct.lattice\n", + "def federated_learning_workflow(\n", + " datasets: HFDataset, round_number, epoch_per_round, batch_size,\n", + " model_agg=None, image_dimension=64,\n", + "):\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "id": "8d47047d-da1f-4a6f-93b5-6bd9e426e91a", + "metadata": {}, + "source": [ + "Once a lattice is defined, you must dispatch a workflow to run it. You can dispatch a lattice workflow using Covalent by calling `ct.dispatch` and providing a workflow name and parameters." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "3ef04f3c-a888-41fb-bba8-ff8868f7fac5", + "metadata": {}, + "outputs": [], + "source": [ + "def filter_by_label(example, sample_size=1000):\n", + " if 0 not in example['labels'] and 7 not in example['labels']:\n", + " return False\n", + " else:\n", + " label = 0 if 0 in example['labels'] else 1\n", + "\n", + " if filter_by_label.label_freq[label] >= sample_size:\n", + " return False\n", + " else:\n", + " filter_by_label.label_freq[label] += 1\n", + "\n", + " return True\n", + "\n", + "\n", + "def map_labels_to_single_label(labels):\n", + " if 0 in labels:\n", + " return 0\n", + " else:\n", + " return 1\n", + "\n", + "\n", + "hf_datasets = [\n", + " HFDataset(\n", + " name=(\"keremberke/chest-xray-classification\", 'full'),\n", + " cloud_provider='aws',\n", + " ),\n", + " HFDataset(\n", + " name=(\"mmenendezg/raw_pneumonia_x_ray\", ),\n", + " cloud_provider=\"gcp\",\n", + " ),\n", + " HFDataset(\n", + " name=(\n", + " \"alkzar90/NIH-Chest-X-ray-dataset\",\n", + " \"image-classification\"\n", + " ),\n", + " cloud_provider='azure',\n", + " filter_func=filter_by_label,\n", + " transform_label_func=map_labels_to_single_label\n", + " )\n", + "]\n", + "\n", + "dispatch_id = ct.dispatch(federated_learning_workflow)(\n", + " hf_datasets, round_number=50,\n", + " epoch_per_round=1, batch_size=32\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9e481604-549f-4415-a865-53f9669c9b1e", + "metadata": {}, + "source": [ + "The diagram below portrays the overarching design of a Covalent workflow example that spans AWS, GCP, and Azure environments.\n", + "\n", + "![alt text](assets/architecture.png \"Covalent\")" + ] + }, + { + "cell_type": "markdown", + "id": "5ec5328c-686c-443b-9936-0bb24ef2cdcd", + "metadata": {}, + "source": [ + "# Pneumonia Chest X-ray Federated Learning using Covalent\n", + "\n", + "We now demonstrate how to utilize Covalent to run and perform federated learning across several cloud providers. To achieve this, we establish a dynamic [sublattice](https://docs.covalent.xyz/docs/user-documentation/concepts/covalent-basics/#sublattice), which creates an executor at runtime. This approach allows us to allocate cloud resources on the fly, based on the workflow's input parameters." + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "aba6784d-5782-42aa-8a18-43929b06da90", + "metadata": {}, + "outputs": [], + "source": [ + "@ct.electron\n", + "@ct.lattice\n", + "def cloud_pnemonia_classifier(cloud_provider, use_gpu=False, **kwargs):\n", + " # Match provider to an executor.\n", + " cloud_service_executor_mapping = {\n", + " \"aws\": ct.executor.AWSBatchExecutor(**AWS_EXECUTOR_DEFAULT_PARAMS),\n", + " \"gcp\": ct.executor.GCPBatchExecutor(**GCP_EXECUTOR_DEFAULT_PARAMS),\n", + " \"azure\": ct.executor.AzureBatchExecutor(**AZURE_EXECUTOR_DEFAULT_PARAMS),\n", + " }\n", + "\n", + " # Create a new electron (task) that uses this executor.\n", + " electron = ct.electron(\n", + " build_pneumonia_classifier,\n", + " executor=cloud_service_executor_mapping.get(cloud_provider),\n", + " deps_pip=ct.DepsPip(\n", + " packages=[\n", + " \"torch==2.0.1\", \"torchvision==0.15.2\",\"datasets==2.14.0\"\n", + " ]\n", + " )\n", + " )\n", + " return electron(**kwargs)" + ] + }, + { + "cell_type": "markdown", + "id": "5f612917-b1eb-4e83-b1dc-10e02e7d3481", + "metadata": {}, + "source": [ + "It is important to observe that in this case `build_pneumonia_classifier` is built as an `ct.electron` object dynamically at runtime, which is also when an executor is assigned." + ] + }, + { + "cell_type": "markdown", + "id": "a2eb2256-9283-4116-9229-24df99a3c014", + "metadata": {}, + "source": [ + "Executor default configuration parameters are available in the Covalent config (typically located at `$HOME/.config/covalent/covalent.conf`). More information on running batch executors is available in the Covalent docs for [AWSBatch](https://docs.covalent.xyz/docs/user-documentation/api-reference/executors/awsbatch/), [AzureBatch](https://docs.covalent.xyz/docs/user-documentation/api-reference/executors/azurebatch/), and [GCPBatch](https://docs.covalent.xyz/docs/user-documentation/gcp/). Python framework prerequisite dependencies installed on cloud resources are specified using `ct.DepsPip`.\n", + "With the main `@ct.lattice` defined, let's delve into the specifics of the `build_pneumonia_classifier method`. Its primary tasks include:\n", + "1. Loading and preprocessing the dataset,\n", + "2. Creating a new model or continuing the training of a previously trained supervised model, and\n", + "3. Evaluating the performance of the model on the loaded test dataset." + ] + }, + { + "cell_type": "markdown", + "id": "26725c76-c1de-45e7-9de8-4e0cb67d5080", + "metadata": {}, + "source": [ + "First, we define the convolutional neural network architecture. " + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "c9cc6425-7ed1-47f3-adec-92617083a6bd", + "metadata": {}, + "outputs": [], + "source": [ + "class PneumoniaDataset(Dataset):\n", + " def __init__(self, data):\n", + " self.data = data\n", + "\n", + " def __len__(self):\n", + " return len(self.data)\n", + "\n", + " def __getitem__(self, index):\n", + " item = self.data[index]\n", + " return item['image'], item['label']\n", + "\n", + "\n", + "class PneumoniaNet(nn.Module):\n", + " \"\"\"\n", + " Simple CNN for pneumonia detection.\n", + " \"\"\"\n", + " def __init__(self, image_dim=64):\n", + " super(PneumoniaNet, self).__init__()\n", + " # channel number is 1 for grayscale images\n", + " # use 3 for RGB images\n", + " channel_number = 1\n", + " self.image_dim = image_dim\n", + "\n", + " self.conv1 = nn.Conv2d(\n", + " in_channels=channel_number, out_channels=16, kernel_size=3,\n", + " stride=1, padding=1\n", + " )\n", + " self.relu1 = nn.ReLU()\n", + " self.conv2 = nn.Conv2d(\n", + " in_channels=16, out_channels=32, kernel_size=3,\n", + " stride=1, padding=1\n", + " )\n", + " self.relu2 = nn.ReLU()\n", + " self.maxpool1 = nn.MaxPool2d(\n", + " kernel_size=2, stride=2\n", + " )\n", + "\n", + " self.conv3 = nn.Conv2d(\n", + " in_channels=32, out_channels=64, kernel_size=3,\n", + " stride=1, padding=1\n", + " )\n", + " self.relu3 = nn.ReLU()\n", + " self.conv4 = nn.Conv2d(\n", + " in_channels=64, out_channels=128, kernel_size=3,\n", + " stride=1, padding=1\n", + " )\n", + " self.relu4 = nn.ReLU()\n", + " self.batchnorm1 = nn.BatchNorm2d(128)\n", + " self.maxpool2 = nn.MaxPool2d(\n", + " kernel_size=2, stride=2\n", + " )\n", + " mapping = {\n", + " 64: 32768,\n", + " 128: 131072\n", + " }\n", + " self.fc1 = nn.Linear(mapping[self.image_dim], 128)\n", + " self.batchnorm2 = nn.BatchNorm1d(128)\n", + " self.dropout1 = nn.Dropout(0.5)\n", + "\n", + " self.fc2 = nn.Linear(128, 1)\n", + " self.sigmoid = nn.Sigmoid()\n", + "\n", + " def forward(self, x):\n", + " x = self.conv1(x)\n", + " x = self.relu1(x)\n", + " x = self.conv2(x)\n", + " x = self.relu2(x)\n", + " x = self.maxpool1(x)\n", + "\n", + " x = self.conv3(x)\n", + " x = self.relu3(x)\n", + " x = self.conv4(x)\n", + " x = self.relu4(x)\n", + " x = self.batchnorm1(x)\n", + " x = self.maxpool2(x)\n", + "\n", + " x = x.view(x.size(0), -1)\n", + "\n", + " x = self.fc1(x)\n", + " x = self.batchnorm2(x)\n", + " x = self.dropout1(x)\n", + " x = self.fc2(x)\n", + " output = self.sigmoid(x)\n", + " return output\n", + "\n", + "\n", + "@ct.electron\n", + "def create_pneumonia_network(\n", + " image_dimension\n", + "):\n", + " return PneumoniaNet(image_dimension)" + ] + }, + { + "cell_type": "markdown", + "id": "a18c0a3f-b92e-471e-96f9-b6383618231b", + "metadata": {}, + "source": [ + "Next, we write the methods to prepare the dataset, train, and evaluate the models. " + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "25a46a04-2c09-4b4d-aabb-06bb2a4c92d1", + "metadata": {}, + "outputs": [], + "source": [ + "@ct.electron\n", + "def prepare_dataset(\n", + " dataset_name, filter_func=None, transform_label=None,\n", + " image_dimension=64, client=None\n", + "):\n", + " ds_name_path = dataset_name[0].replace('/', '-')\n", + " save_path = f'preprocessed-obj-{ds_name_path}'\n", + "\n", + " exists_on_cloud = client.check_file_exists(\n", + " save_path\n", + " ) if client is not None else False\n", + "\n", + " if os.path.exists(save_path):\n", + " print('Loading preprocessed data from local')\n", + " with open(save_path, 'rb') as f:\n", + " preprocessed_train, preprocesed_test, maj_test_acc = pickle.load(f)\n", + " elif not os.path.exists(save_path) and exists_on_cloud:\n", + " print('Loading preprocessed data from cloud')\n", + " client.download_file(\n", + " save_path, save_path\n", + " )\n", + " with open(save_path, 'rb') as f:\n", + " preprocessed_train, preprocesed_test, maj_test_acc = pickle.load(f)\n", + " else:\n", + " print('Preprocessing data')\n", + " dataset = load_dataset(\n", + " *dataset_name,\n", + " )\n", + " image_mean = [0.5]\n", + " image_std = [0.5]\n", + " image_transformation = transforms.Compose([\n", + " transforms.Resize(\n", + " size=(image_dimension, image_dimension)\n", + " ),\n", + " transforms.Grayscale(),\n", + " transforms.ToTensor(),\n", + " transforms.Normalize(\n", + " mean=image_mean, std=image_std\n", + " )\n", + " ])\n", + " preprocessed_train, label_column = preprocess(\n", + " dataset['train'], image_transformation,\n", + " transform_label_func=transform_label,\n", + " filter_func=filter_func\n", + " )\n", + " preprocesed_test, label_column = preprocess(\n", + " dataset['test'], image_transformation,\n", + " transform_label_func=transform_label,\n", + " filter_func=filter_func\n", + " )\n", + "\n", + " labels = np.array(\n", + " [x['label'] for x in preprocesed_test]\n", + " )\n", + " maj_test_acc = get_majority_class_accuracy(labels)\n", + " preprocessed_data = (\n", + " preprocessed_train, preprocesed_test, maj_test_acc\n", + " )\n", + " with open(save_path, \"wb\") as f:\n", + " pickle.dump(preprocessed_data, f)\n", + "\n", + " # upload to cloud\n", + " if client is not None:\n", + " client.upload_file(save_path, save_path)\n", + "\n", + " train_ds = PneumoniaDataset(preprocessed_train)\n", + " test_ds = PneumoniaDataset(preprocesed_test)\n", + "\n", + " return train_ds, test_ds, maj_test_acc\n", + "\n", + "\n", + "@ct.electron\n", + "def train_model(\n", + " model, epoch_count, train_dataloader, use_gpu=False\n", + "):\n", + " print(\"Training model\")\n", + " ds_size = len(train_dataloader.dataset)\n", + " losses = []\n", + " optimizer = optim.SGD(model.parameters(), lr=0.00005, momentum=0.9)\n", + " criterion = nn.BCELoss()\n", + "\n", + " for epoch in range(epoch_count):\n", + " if use_gpu:\n", + " model = model.cuda()\n", + " model.train()\n", + " running_loss = 0\n", + " train_correct = 0\n", + "\n", + " for images, labels in train_dataloader:\n", + " labels = labels.float()\n", + " if use_gpu:\n", + " images = images.cuda()\n", + " labels = labels.cuda()\n", + "\n", + " optimizer.zero_grad()\n", + " output = model(images).flatten()\n", + " loss = criterion(output, labels)\n", + " loss.backward()\n", + " optimizer.step()\n", + " losses.append(loss)\n", + " running_loss += loss.item()\n", + "\n", + " # Calculate training accuracy\n", + " predicted = (output > 0.5).long()\n", + " train_correct += (predicted == labels).sum().item()\n", + "\n", + " train_acc = train_correct / ds_size\n", + " print(\"Epoch {} - Training loss: {:.4f} - Accuracy: {:.4f}\".format(\n", + " epoch + 1, running_loss / len(train_dataloader), train_acc)\n", + " )\n", + " if use_gpu:\n", + " # detach from GPU after finishing training\n", + " model = model.cpu()\n", + "\n", + " return losses, ds_size\n", + "\n", + "\n", + "@ct.electron\n", + "def evaluate(\n", + " model, test_dataloader, use_gpu=False\n", + "):\n", + " if use_gpu:\n", + " model = model.cuda()\n", + "\n", + " criterion = nn.BCELoss()\n", + " model.eval()\n", + " test_loss = 0\n", + " test_correct = 0\n", + "\n", + " with torch.no_grad():\n", + " for images, labels in test_dataloader:\n", + " labels = labels.float()\n", + " if use_gpu:\n", + " images = images.cuda()\n", + " labels = labels.cuda()\n", + "\n", + " output = model(images).flatten()\n", + " loss = criterion(output, labels)\n", + " test_loss += loss.item()\n", + "\n", + " predicted = (output > 0.5).long()\n", + " test_correct += (predicted == labels).sum().item()\n", + "\n", + " test_acc = test_correct / len(test_dataloader.dataset)\n", + " print(\n", + " \"Test loss: {:.4f} - Test accuracy: {:.4f}\".format(\n", + " test_loss / len(test_dataloader), test_acc\n", + " )\n", + " )\n", + "\n", + " # detach from GPU after evaluation\n", + " if use_gpu:\n", + " model = model.cpu()\n", + "\n", + " return test_acc, test_loss" + ] + }, + { + "cell_type": "markdown", + "id": "b2ba5dbc-6d40-45d2-b30f-ae4d513b6b1c", + "metadata": {}, + "source": [ + "We put everything together in a single method that encompasses all the past steps and builds a pnemonia classifier. " + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "83933d2d-925a-4282-a441-fab7a61007e1", + "metadata": {}, + "outputs": [], + "source": [ + "def build_pneumonia_classifier(\n", + " dataset_name=None, filter_func=None, transform_label=None,\n", + " model=None, epoch_number=2, batch_size=64,\n", + " image_dimension=64\n", + "):\n", + " train_ds, test_ds, maj_test_acc = prepare_dataset(\n", + " dataset_name, filter_func, transform_label,\n", + " image_dimension=image_dimension\n", + " )\n", + " train_dataloader, test_dataloader = create_dataloaders(\n", + " train_ds, test_ds, batch_size\n", + " )\n", + "\n", + " if not model:\n", + " model = create_pneumonia_network(image_dimension)\n", + "\n", + " train_losses, ds_size = train_model(\n", + " model, epoch_number, train_dataloader\n", + " )\n", + " test_acc, test_loss = evaluate(model, test_dataloader)\n", + " return model, ds_size, test_acc" + ] + }, + { + "cell_type": "markdown", + "id": "a169694b-e913-403f-8b05-08c80f70da89", + "metadata": {}, + "source": [ + "Lastly, to finalize our federated learning workflow, we showcase the process of constructing an aggregated model from the individual models through weighted averaging, as defined in equation $(1)$." + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "4fa36948-de7a-45db-9c8c-291af26d51e6", + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "\n", + "@ct.electron\n", + "def create_aggregated_network(\n", + " model_list, ds_sizes, image_dimension=64\n", + "):\n", + " \"\"\"\n", + " Simple aggregation mechanism where weights of a network\n", + "\t are aggregated using a weighted average, where the value of the\n", + " weight is the size of the dataset\n", + " \"\"\"\n", + " dataset_weights = np.array(ds_sizes) / sum(ds_sizes)\n", + " whole_aggregator = []\n", + "\n", + " # compute a weighted average\n", + " for p_index, layer in enumerate(model_list[0].parameters()):\n", + " params_aggregator = torch.zeros(layer.size())\n", + "\n", + " for model_index, model in enumerate(model_list):\n", + " params_aggregator = params_aggregator + dataset_weights[\n", + " model_index\n", + " ] * list(model.parameters())[p_index].data\n", + " whole_aggregator.append(params_aggregator)\n", + "\n", + " net_avg = create_pneumonia_network(image_dimension)\n", + "\n", + " for param_index, layer in enumerate(net_avg.parameters()):\n", + " layer.data = whole_aggregator[param_index]\n", + " return net_avg" + ] + }, + { + "cell_type": "markdown", + "id": "cf48a3aa-32dd-48ba-838c-88325b423769", + "metadata": {}, + "source": [ + "Now we expand on the previously introduced `federated_learning_workflow`, which interconnects all the tasks (electrons) into a main workflow (lattice). This workflow facilitates the creation of a pnemonia classifier for each dataset, ensuring seamless development within isolated cloud environments. After the models are crafted, they are transmitted back to the central node. Here, the resulting models are aggregated as described in `create_aggregated_network`, thereby producing a refined model for the isolated cloud environments to further enhance and improve upon." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "be37830c-e65b-4cce-8810-0c0a2cf8e91e", + "metadata": {}, + "outputs": [], + "source": [ + "@ct.lattice\n", + "def federated_learning_workflow(\n", + " datasets: HFDataset, round_number, epoch_per_round, batch_size,\n", + " model_agg=None, image_dimension=64, use_gpu=False\n", + "):\n", + " test_accuracies = []\n", + " model_showcases = []\n", + " for round_idx in range(round_number):\n", + " print(f\"Round {round_idx + 1}\")\n", + " models = []\n", + " dataset_sizes = []\n", + " for ds in datasets:\n", + " trained_model, ds_size, test_accuracy = cloud_pnemonia_classifier(\n", + " ds.cloud_provider,\n", + " dataset_name=ds.name, model=model_agg,\n", + " image_dimension=image_dimension,\n", + " epoch_number=epoch_per_round,\n", + " transform_label=ds.transform_label_func,\n", + " filter_func=ds.filter_func, use_gpu=use_gpu\n", + " )\n", + " models.append(trained_model)\n", + " dataset_sizes.append(ds_size)\n", + " test_accuracies.append(\n", + " (round_idx + 1, ds.name, test_accuracy)\n", + " )\n", + " if round_idx == round_number - 1:\n", + " model_showcases.append((trained_model, ds.name))\n", + "\n", + " model_agg = create_aggregated_network(\n", + " models, dataset_sizes, image_dimension=image_dimension,\n", + " )\n", + " if round_idx == round_number - 1:\n", + " model_showcases.append((model_agg, \"aggregated\"))\n", + "\n", + " return test_accuracies, model_showcases" + ] + }, + { + "cell_type": "markdown", + "id": "e24ff9ba-4964-48cd-991c-1fbedcc52be8", + "metadata": {}, + "source": [ + "The iterative process of centralized federated learning continues for a duration determined by the `round_number` hyper-parameter. The illustration below provides a visual depiction of how the Covalent UI presents the aforementioned workflow when `round_number` is set to 2, and the workflow encompasses the processing of three distinct datasets across three different cloud providers." + ] + }, + { + "cell_type": "markdown", + "id": "27d1f68d-65e4-4a8b-84e4-cc79b74340fb", + "metadata": {}, + "source": [ + "![alt text](assets/workflow.gif \"Covalent\")" + ] + }, + { + "cell_type": "markdown", + "id": "772f30f0-eb1c-4eb8-b355-074cb90c92c6", + "metadata": {}, + "source": [ + "# Evaluation of applying Federated Learning to X-ray data\n", + "In this evaluation, we aim to shed further light on the intrinsic advantages of federated learning, particularly its emphasis on preserving data privacy and fostering seamless collaboration across diverse healthcare institutions. To achieve this, we compare the test accuracies of a federated learning setup against a classically trained setup, where a model is trained on a single dataset, while employing identical CNN model architectures. The following illustration illustrates the consistent superiority of a federated learning model over a standard machine learning arrangement. Three distinct models are individually developed and subsequently contrasted with a model trained through federated learning. This evaluation is performed across three distinct test datasets." + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "5665b5f1-9178-455d-bdd4-8cfda50aae15", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "method=Standard ML
dataset=chest-xray-classification
round=%{x}
test_accuracy=%{y}", + "legendgroup": "Standard ML", + "line": { + "color": "#636efa", + "dash": "solid" + }, + "marker": { + "symbol": "circle" + }, + "mode": "lines", + "name": "Standard ML", + "orientation": "v", + "showlegend": true, + "type": "scatter", + "x": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50 + ], + "xaxis": "x", + "y": [ + 0.852233676975945, + 0.8676975945017182, + 0.8900343642611683, + 0.8883161512027491, + 0.8969072164948454, + 0.9054982817869416, + 0.9072164948453608, + 0.9037800687285223, + 0.8969072164948454, + 0.9003436426116839, + 0.9072164948453608, + 0.9106529209621992, + 0.9037800687285223, + 0.915807560137457, + 0.915807560137457, + 0.9054982817869416, + 0.9106529209621992, + 0.9192439862542956, + 0.90893470790378, + 0.9123711340206184, + 0.9192439862542956, + 0.9140893470790378, + 0.9175257731958762, + 0.915807560137457, + 0.9209621993127148, + 0.9209621993127148, + 0.929553264604811, + 0.9243986254295532, + 0.9261168384879724, + 0.9054982817869416, + 0.9312714776632304, + 0.9072164948453608, + 0.9243986254295532, + 0.929553264604811, + 0.929553264604811, + 0.9106529209621992, + 0.9243986254295532, + 0.9123711340206184, + 0.915807560137457, + 0.922680412371134, + 0.9192439862542956, + 0.9140893470790378, + 0.9467353951890034, + 0.9278350515463918, + 0.9175257731958762, + 0.9278350515463918, + 0.929553264604811, + 0.9450171821305842, + 0.9484536082474226, + 0.936426116838488 + ], + "yaxis": "y" + }, + { + "hovertemplate": "method=Standard ML
dataset=raw_pneumonia_x_ray
round=%{x}
test_accuracy=%{y}", + "legendgroup": "Standard ML", + "line": { + "color": "#636efa", + "dash": "solid" + }, + "marker": { + "symbol": "circle" + }, + "mode": "lines", + "name": "Standard ML", + "orientation": "v", + "showlegend": false, + "type": "scatter", + "x": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50 + ], + "xaxis": "x2", + "y": [ + 0.8894230769230769, + 0.8846153846153846, + 0.8846153846153846, + 0.8766025641025641, + 0.8782051282051282, + 0.8766025641025641, + 0.8782051282051282, + 0.875, + 0.8621794871794872, + 0.8669871794871795, + 0.8782051282051282, + 0.8685897435897436, + 0.8862179487179487, + 0.875, + 0.8830128205128205, + 0.8782051282051282, + 0.875, + 0.8782051282051282, + 0.8798076923076923, + 0.8862179487179487, + 0.8846153846153846, + 0.8974358974358975, + 0.8862179487179487, + 0.8846153846153846, + 0.8894230769230769, + 0.8894230769230769, + 0.8878205128205128, + 0.8878205128205128, + 0.8814102564102564, + 0.8862179487179487, + 0.875, + 0.8894230769230769, + 0.8926282051282052, + 0.8862179487179487, + 0.8974358974358975, + 0.8669871794871795, + 0.8942307692307693, + 0.8878205128205128, + 0.8846153846153846, + 0.8974358974358975, + 0.8942307692307693, + 0.8798076923076923, + 0.8830128205128205, + 0.8701923076923077, + 0.8798076923076923, + 0.8894230769230769, + 0.8910256410256411, + 0.8846153846153846, + 0.875, + 0.8798076923076923 + ], + "yaxis": "y2" + }, + { + "hovertemplate": "method=Standard ML
dataset=NIH-Chest-X-ray-dataset
round=%{x}
test_accuracy=%{y}", + "legendgroup": "Standard ML", + "line": { + "color": "#636efa", + "dash": "solid" + }, + "marker": { + "symbol": "circle" + }, + "mode": "lines", + "name": "Standard ML", + "orientation": "v", + "showlegend": false, + "type": "scatter", + "x": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50 + ], + "xaxis": "x3", + "y": [ + 0.5013071211962773, + 0.4772560911847746, + 0.4527867823904632, + 0.5092544180696434, + 0.5657220537488236, + 0.5395796298232772, + 0.589041095890411, + 0.6123601380319983, + 0.5680225870542717, + 0.5976158109379902, + 0.5791069747987033, + 0.573878490013594, + 0.5963609745895639, + 0.6389208407403535, + 0.6652724040573041, + 0.6517829133117222, + 0.684304088675102, + 0.6702917494510091, + 0.6813761371954408, + 0.7042769005542194, + 0.6540834466171703, + 0.7262365366516783, + 0.7122241974275855, + 0.6767750705845446, + 0.6932970825054899, + 0.6905782704172331, + 0.702917494510091, + 0.7245634215204434, + 0.7372163547004078, + 0.7394123183101537, + 0.7283279305657221, + 0.747987033357733, + 0.7424448394855171, + 0.7507058454459897, + 0.7796716511554951, + 0.7783122451113668, + 0.7572937362752274, + 0.7781031057199623, + 0.7924291540311618, + 0.7747568754574924, + 0.784063578374987, + 0.7534246575342466, + 0.7929520025096727, + 0.7798807905468995, + 0.7781031057199623, + 0.7960890933807383, + 0.7838544389835825, + 0.7676461361497438, + 0.8017358569486562, + 0.7971347903377601 + ], + "yaxis": "y3" + }, + { + "hovertemplate": "method=Federated Learning
dataset=chest-xray-classification
round=%{x}
test_accuracy=%{y}", + "legendgroup": "Federated Learning", + "line": { + "color": "#EF553B", + "dash": "solid" + }, + "marker": { + "symbol": "circle" + }, + "mode": "lines", + "name": "Federated Learning", + "orientation": "v", + "showlegend": true, + "type": "scatter", + "x": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50 + ], + "xaxis": "x", + "y": [ + 0.8848797250859106, + 0.8419243986254296, + 0.9192439862542956, + 0.8762886597938144, + 0.8969072164948454, + 0.9243986254295532, + 0.950171821305842, + 0.950171821305842, + 0.915807560137457, + 0.9347079037800688, + 0.9450171821305842, + 0.9570446735395188, + 0.9621993127147768, + 0.9604810996563574, + 0.9536082474226804, + 0.9587628865979382, + 0.9621993127147768, + 0.9518900343642612, + 0.9690721649484536, + 0.9690721649484536, + 0.9621993127147768, + 0.9690721649484536, + 0.9484536082474226, + 0.9656357388316152, + 0.972508591065292, + 0.9776632302405498, + 0.9742268041237112, + 0.9776632302405498, + 0.9810996563573884, + 0.979381443298969, + 0.9450171821305842, + 0.9776632302405498, + 0.9759450171821306, + 0.9673539518900344, + 0.9776632302405498, + 0.9828178694158076, + 0.9759450171821306, + 0.986254295532646, + 0.9759450171821306, + 0.9810996563573884, + 0.9776632302405498, + 0.9587628865979382, + 0.9810996563573884, + 0.9759450171821306, + 0.9828178694158076, + 0.9776632302405498, + 0.9845360824742267, + 0.9810996563573884, + 0.979381443298969, + 0.9845360824742267 + ], + "yaxis": "y" + }, + { + "hovertemplate": "method=Federated Learning
dataset=raw_pneumonia_x_ray
round=%{x}
test_accuracy=%{y}", + "legendgroup": "Federated Learning", + "line": { + "color": "#EF553B", + "dash": "solid" + }, + "marker": { + "symbol": "circle" + }, + "mode": "lines", + "name": "Federated Learning", + "orientation": "v", + "showlegend": false, + "type": "scatter", + "x": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50 + ], + "xaxis": "x2", + "y": [ + 0.8782051282051282, + 0.907051282051282, + 0.9198717948717948, + 0.907051282051282, + 0.9230769230769232, + 0.8990384615384616, + 0.8910256410256411, + 0.9278846153846154, + 0.9198717948717948, + 0.9246794871794872, + 0.9198717948717948, + 0.9455128205128204, + 0.9342948717948718, + 0.8862179487179487, + 0.9342948717948718, + 0.9407051282051282, + 0.9455128205128204, + 0.939102564102564, + 0.9503205128205128, + 0.9439102564102564, + 0.9503205128205128, + 0.9535256410256412, + 0.971153846153846, + 0.9583333333333334, + 0.9599358974358976, + 0.9599358974358976, + 0.966346153846154, + 0.9615384615384616, + 0.9583333333333334, + 0.966346153846154, + 0.9647435897435898, + 0.969551282051282, + 0.9727564102564102, + 0.9743589743589745, + 0.9567307692307692, + 0.9631410256410255, + 0.969551282051282, + 0.9775641025641024, + 0.9599358974358976, + 0.969551282051282, + 0.9631410256410255, + 0.967948717948718, + 0.971153846153846, + 0.971153846153846, + 0.9535256410256412, + 0.967948717948718, + 0.971153846153846, + 0.9631410256410255, + 0.9759615384615384, + 0.9727564102564102 + ], + "yaxis": "y2" + }, + { + "hovertemplate": "method=Federated Learning
dataset=NIH-Chest-X-ray-dataset
round=%{x}
test_accuracy=%{y}", + "legendgroup": "Federated Learning", + "line": { + "color": "#EF553B", + "dash": "solid" + }, + "marker": { + "symbol": "circle" + }, + "mode": "lines", + "name": "Federated Learning", + "orientation": "v", + "showlegend": false, + "type": "scatter", + "x": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50 + ], + "xaxis": "x3", + "y": [ + 0.3733138136568023, + 0.4181742131130398, + 0.6758339433232249, + 0.6138241137718289, + 0.7138973125588205, + 0.7370072153090035, + 0.7719334936735334, + 0.811774547736066, + 0.8927114922095577, + 0.8557983896266862, + 0.8679284743281397, + 0.8829865105092544, + 0.8907246679912162, + 0.8907246679912162, + 0.8928160619052599, + 0.864163965282861, + 0.8933389103837708, + 0.8797448499424867, + 0.8587263411063474, + 0.9088152253476942, + 0.8916657952525359, + 0.9015999163442434, + 0.9011816375614348, + 0.8956394436892189, + 0.8602948865418801, + 0.8663599288926069, + 0.8456551291435742, + 0.8428317473596152, + 0.8285056990484158, + 0.9231412736588936, + 0.9117431768273554, + 0.8210812506535606, + 0.8800585590295932, + 0.8766077590714211, + 0.8547526926696644, + 0.852870438147025, + 0.916553382829656, + 0.8313290808323748, + 0.8735752378960577, + 0.8805814075081041, + 0.8599811774547736, + 0.8126111053016836, + 0.8344661717034404, + 0.7816584753738367, + 0.9151939767855276, + 0.7864686813761372, + 0.8778625954198473, + 0.8426226079682108, + 0.8819408135522325, + 0.8752483530272926 + ], + "yaxis": "y3" + } + ], + "layout": { + "annotations": [ + { + "font": {}, + "showarrow": false, + "text": "dataset=chest-xray-classification", + "x": 0.15999999999999998, + "xanchor": "center", + "xref": "paper", + "y": 1, + "yanchor": "bottom", + "yref": "paper" + }, + { + "font": {}, + "showarrow": false, + "text": "dataset=raw_pneumonia_x_ray", + "x": 0.49999999999999994, + "xanchor": "center", + "xref": "paper", + "y": 1, + "yanchor": "bottom", + "yref": "paper" + }, + { + "font": {}, + "showarrow": false, + "text": "dataset=NIH-Chest-X-ray-dataset", + "x": 0.8399999999999999, + "xanchor": "center", + "xref": "paper", + "y": 1, + "yanchor": "bottom", + "yref": "paper" + } + ], + "autosize": true, + "font": { + "color": "RebeccaPurple", + "family": "Courier New, monospace", + "size": 12 + }, + "legend": { + "title": { + "text": "Training method" + }, + "tracegroupgap": 0 + }, + "margin": { + "t": 60 + }, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Average test accuracy over 50 rounds" + }, + "xaxis": { + "anchor": "y", + "domain": [ + 0, + 0.31999999999999995 + ], + "range": [ + 1, + 50 + ], + "title": { + "text": "Round number" + }, + "type": "linear" + }, + "xaxis2": { + "anchor": "y2", + "domain": [ + 0.33999999999999997, + 0.6599999999999999 + ], + "matches": "x", + "title": { + "text": "Round number" + }, + "type": "linear" + }, + "xaxis3": { + "anchor": "y3", + "domain": [ + 0.6799999999999999, + 0.9999999999999999 + ], + "matches": "x", + "title": { + "text": "Round number" + }, + "type": "linear" + }, + "yaxis": { + "anchor": "x", + "domain": [ + 0, + 1 + ], + "range": [ + 0, + 1 + ], + "title": { + "text": "Test dataset accuracy" + }, + "type": "linear" + }, + "yaxis2": { + "anchor": "x2", + "domain": [ + 0, + 1 + ], + "matches": "y", + "showticklabels": false, + "type": "linear" + }, + "yaxis3": { + "anchor": "x3", + "domain": [ + 0, + 1 + ], + "matches": "y", + "showticklabels": false, + "type": "linear" + } + } + }, + "image/png": "iVBORw0KGgoAAAANSUhEUgAABE8AAAFoCAYAAACmM9U+AAAAAXNSR0IArs4c6QAAIABJREFUeF7sXQeUFMUWvT2zs4G85JwzSEZyEiVJElCCAUVFvzkHxBwwIOYAKioZBERAJIPknHNOS85pw+xM/3Nr7GFmd/IOy7L73jkedae7uupWdXXVrfve03Rd1yEmCAgCgoAgIAgIAoKAICAICAKCgCAgCAgCgoAg4BEBTcgTGRmCgCAgCAgCgoAgIAgIAoKAICAICAKCgCAgCHhHQMgTGR2CgCAgCAgCgoAgIAgIAoKAICAICAKCgCAgCPhAQMgTGR6CgCAgCAgCgoAgIAgIAoKAICAICAKCgCAgCAh5ImNAEBAEBAFBQBAQBAQBQUAQEAQEAUFAEBAEBIHQEBDlSWi4yV2CgCAgCAgCgoAgIAgIAoKAICAICAKCgCCQRRAQ8iSLdLQ0UxAQBAQBQUAQEAQEAUFAEBAEBAFBQBAQBEJDQMiT0HCTuwQBQUAQEAQEAUFAEBAEBAFBQBAQBAQBQSCLICDkSRbpaGmmICAICAKCgCAgCAgCgoAgIAgIAoKAICAIhIaAkCeh4SZ3CQKCgCAgCAgCgoAgIAgIAoKAICAICAKCQBZBQMiTLNLR0kxBQBAQBAQBQUAQEAQEAUFAEBAEBAFBQBAIDQEhT0LDTe4SBAQBQUAQEAQEAUFAEBAEBAFBQBAQBASBLIKAkCdZpKOlmYKAICAICAKCgCAgCAgCgoAgIAgIAoKAIBAaAkKehIab3CUICAKCgCAgCAgCgoAgIAgIAoKAICAICAJZBAEhT7JIR0szBQFBQBAQBAQBQUAQEAQEAUFAEBAEBAFBIDQEhDwJDTe5SxAQBAQBQUAQEAQEAUFAEBAEBAFBQBAQBLIIAkKeZJGOlmYKAoKAICAICAKCgCAgCAgCgoAgIAgIAoJAaAgIeRIabnKXICAICAKCgCAgCAgCgoAgIAgIAoKAICAIZBEEhDzJIh0tzRQEBAFB4EYg8Fb38ShRMT8eHdT6RjxenikICAKCgCAgCAgCgoAgIAiEBYEsRZ58/cw/2LrsMO566la0e7BWWADMaoW83HYk/je4LcreUjBdm/7vxG3YsPAAnv22Q7o+Vx4mCLgiMOTx6di55mgqUGJyROLLhQ+6/Z3jdcYv6xC39xwskWZUqlcUPZ5riALFc2UpUIU8yVLdLY0VBAQBQUAQEAQEAUEg0yKQZciT8yev4LWOY5A9VxSy547Ce5N63rBOtdt0aBqgmbQbVodQHnzy0AW82W08Xv21a7qTJ78MnI/L5xOyPHliS7bDZDap8SMWGgK6DthtdpgjTEEX8OF9k5EzbwzuevJWt3tNZg3Fyud1/m3L0sP45tl/0KhjRfVP4lUrpg1bi4tnruKdP+4ByZZwWFraEo7nB1KGkCeBoCTXCAKCgCAgCAgCgoAgIAhkdASyDHky45f1+Pvntej7dktwI/7q8C4oW6OQ6p+khGS80m6UOhn+3+A2bn2WGJ8Mqi2qNSqOxz65Q/1G8uOfX9dj+fRdOHv8siJjarcqg25PN0B0dovzfoNseOrLdmqzNPHLFYjbc1Y9r9fLTdCqZzXntUv/2on547eA90REmlGycn70eLYhSlTK51afg9tPY9ynS3Box2m1ibvjvhqwJtow9cc1+H7FI85rL51LwORvVmLzkkO4ejER+YrkQIse1XD7vbeENCZ/fGUO1s/fn+pe1vONUd3c/n545xn8+e1K7N10AslWO4pXyIvOj9dXGLrapbPxmPzNKmxbcVgRI7nyZUO9NuXQ5X/1EWFxbGyJ13u9Jnqs85NftEONZiWDbg/rNPXH1VgzZx8unLqC7LmjUbVhcXR/tiFyxka7lXdk91n89cNq7F53DCQuCpbIhVY9q6Np18pu17H+U75fjU2LDqq25CmYHfXblMOdj9RBZHSEunbf5pP45KEpeObr9qjWuITzfo4LKmu+WdLP+bfFf27H6EFL8MX8vlgzZy9mj9yE03EX1dh7a1wP50Y9nG3hWH/tztGoc1sZ3D+wuVv7+NwBncegTPWCzvcgUOCJ298/r8OKGbtBEpPvQvUmJdT7kjt/NlUM36cp363GwNHdU4356cPWKuLh7fF3o2i5WHV9oGOM7/qJg+fx8s9d8Oe3q7B23j5VB76zQ+b1DbQJzusGdB6L6o1LoM9rTX3e+/GDUxTBRaLRsHMnrigMSby0eaBm0M8OtC2B4M2HP9noZ7Tuc4vqB8M2LT6E756fiQEj7kKpqgXUn6m2yZYrCre2LY/pP63FycMXkKdAdjW2SQy52rKpO/H3L+vAtvJd6frkrQr34hXyubntBPLuBw2Q3CAICAKCgCAgCAgCgoAgIAhcRwSyBHnC09k37xqHImVj8find+ClNiNTbRDHfroUiydvxyf/3Oe2gV4yZQdGfrAIz//QEZXrF1VdMeqjxeAmgRL8Gs1K4dj+cxj14SIULhOL57+/09ldfO4zzYbj1nblsfHfA2hzf01UqFNEnULnK5rTKd83Tqk79a+rrk1KtGHKd6sUQfLBlF7OzTfve6PLWEUycPMWnc2iNpXcHJ45dtm5+eaG+qP7J6tN/H0DmqFoubzYsuwQJny+HB0frYsOD9cOekidP3UVW5YeUlg8+lFrFK/oIHUsURGKmDHs5OGL+KDPRPX73c83Uhvl+eO2YNHk7Xjhh46oWLeI89qvnpqBhCtJuOfFxmoTzXtHvLcQNZqXUuQSjW0hafDT63MRnT3SbVMfWygHomIcxEQwNunrlapO/d5rpUgqbqZ/f+9ftTF/4vO219py6AI+uHcSSlcriA79aiNHnmisX3BAbSDZNoOISk6y4aMH/kT85SQ1JgqXzqM29+M+W6r6+8khjjKDIU/2bzkJbsBb974FG/49gC7/q4eCJXLjyoVElKtZyKlcCHdbSADNG7MZH/99ryIYDKMLyg8vzcbLP3dG+VqFg4Ebw99aoIi33q80QcW6RdXmm+8LSaWBY3ooouzimXhF3LToURU9X2p87R2yk7QZi7yFc6hn04IZY7N+34gp369C825V1XtKspFkGfsqJZkXSKOea/kbWt5TDV2fqO/1cr6nzzT/1aN7IPuU70Qo7meBtiUQvFn5QMkTvqckMUtVyY97X2+miBTOJUv+2oF3/7gHhUrlVliQYBzcfxoad6qEtn1rIuGKVRG4h3eeRtWGJdzIk0De/UD6Q64RBAQBQUAQEAQEAUFAEBAE0guBLEGeMEYBT0/7f3w76t5eFqM+XIzVs/fgs1n3O4kJQ+HguilmJ3Czc/VSotPNhyTCax1GqRNbXmsY1QE/vT7PTdHC30h2nI67hIc/uE0RI56MGzme1BYpk8fpymNsRFxdZNbO3Ydhr83FSz91RoXajg0sVSfcdFLNYigX1szei58GzFObdhIRho35eAlW/rMbn895QKlbgjXGi2HcGF9uO6MHLVaKnI+m9kGufDHqESSR3r1nAkh2uG4an246XJ1eu8afOXXkIjRNQ/5iOd2ql5ZNZ8p2Xjh9FVRZ8GTcMBIiM3/bgG8W93P2AYki9usnM+5zUxTxJJ3G2Dk0Yjr8zQV4cWgnN3Jo5Yzd2LLssNpwUpEUDHlCRdPrHceofuIGNSUeRr3D3RaSGK93GoMuj9dzU0dws3vlQgIGjHRXGfkbQxz7fAdIDHbsX9d5+cZ/D+L7F2cpFUud1mXU3398eTZ2rz+uCExDebR1+RF8/fQMt/cnmDG24u/d+PXtBYoYo6olFFcdo9Icx/+7dRhqtiitiMnDu84oApNkEseCEcvEmEsYILVMtYKK/KH66s2xPdR7eWj7Kbz/Zy9/0KX6PZC2BIN3MOTJrnXH8MmMexWBSON7OrDrODz4Tkun+uS3dxZi/YL9GDz7AViiHPOLob6rd0c5N/IkmHc/aKDkBkFAEBAEBAFBQBAQBAQBQeA6IJAlyBOexNKdgmQJF/UGMdHv/VZo0L6CE1Zu0ElC0C2CdmzfObxzzx+454VGiiyhUXnATR5JALp6GEbXmOdv+x3dn2ngtul8v/dEXLmYiEHT7/Uap4KbsuXTd4KbozPHLqmNPWMyUGXg6poybehapXr4enE/N8XFz2/MAzejBnkyfvAyLBi/Bd8sedi5iXGt++u/34XS1RyS/GAsEPKELjZR2SyKRHI11okqHtbdiNfBmBC71h5TLjB0haBKw3BxSVmvcJInJKuoriCxcf7UFaVuYb9TMfD1oodU/Wlv95iAPAWyKdWRL+Nmnm5X3y1/xGcskmDIk6uXkvB8q9/U+OQ49WbhbgufQ3Jx6/LD+PCv3mAsD2OjnPJ9CWTsrJq5R7nJuRJ+vM9oH91X+M7QDKKE6rDatzkIlaGvzlFjxJVQCWaMGYoZuiGldLUKpP6u1xDrl+4YoVQwbfvWQpEysUpFQ5e5hKtWvDW2B2ILZceBracwqO+fSsVE0sSVPPn93X+VmxrbE6wF0pZg8A6GPCFJZ8yLrLehrqHSimoeGuPBcH595Rf3d5/zYtUGxd3Ik2De/WBxkusFAUFAEBAEBAFBQBAQBASB64FApidPuOFhPBMqTlzjOHBDU7hUbreN8bJpO8HNDU/XKVGnNH3R5G349J/7lFSdZlzDE+yUQTu5Cacrh6siheQJY5M89901d56UHTl75EZM+mqlOp1nzA/K+hlrgyfuruTJH18sx9zRmzF0TX+3IiYMWa5cjgzyhCfAVH8Yp/fGxSRpGA8hpSIl0IEVCHlCtcS5E5dTnfDb7bqK1/HVvw85VRwkLOaM2oR18/fjyK4z6p6aLUop/LhBdbVwkiffPjcTezYcR+9Xm6B8zcJK3cGYI4zL4Uqe0L2rYp0iSrHky6g42rE6Dp/PfcDndaGQJ3QPad/Pu5tVuNvCBpw4eAFv9xiPxz5tg9qtSqtYPdyUD5reJ2jlBnGl4umdCXcrtzlXe7z+MDTrVkUpc2gcn1SpFC0bC8YJorqD7y4354bKh9cFM8YMwoEbero7XQ87uvcc3u35h3KJ6/RYXSfpSuVJ3dvLISneqtRMJAY5Vg7tPI33JwcfsDqQtgSDdzDkCefR1367Fr/FIE+6P9tAuSPSGEyaaq6nv2rvBjPnWipwXFMVB/PuX48+kzIFAUFAEBAEBAFBQBAQBASBYBHI9OTJokkMvLnYKy7cEBobdSNwLE/7736hEV5tP0rFNOn7dgvn/Ya7Ad1wGC8jpWXLGeV0V+FvJE8Y38Q1lkbKe3iSTnLmpWGdnD8ZRIUrecLApQx8++1Sd0UJyRK69BjkCcmUhRO2KjcBT1lZGOzRNbBtoIMmEPKEMUKYlpWBeT0Z43ZQzZDSuFGm2oFBQ0keuZ5y89pwkSdU87zQ+nfnRteoB2MzMKZESuUJY7G88KN/5QlVNd9TeeIjg5IRxyRlwFiSCyS7XAPGGsoMV9VTSsyuR1uMZzC+CTfM3Ai/2mEU7ri3hk8Sx9sYWj1rL6iMSqU8+U+pRZctV2Lkn+Hr8dePa5SLCAmbSV+twAdTeru5LQUzxgzCwVMg2kDHfSDXPdn4FzTuVFERQZxHGOuoC4mvh9yJL6oz6M6WkmAI5BmBtCUYvFnn1r2ruwWMNVwDXQPG0mUrEPKE/UKCKKXyhFjc0rSUG3ni2l5/734g2Mg1goAgIAgIAoKAICAICAKCwPVGINOTJwzkycwOdAVwNcaUYAaZzo/XU3E3DBv7yVKVkeOBN1uorBMpXVxY1ivtR6n7XDdGVHQw3oARPNEoLxDy5NUOo1GuRiE3hYOhHnElT4yYBzwBZtYTGtUub3Qeo9wgjM03g3Oyba4ZhXgtNymsp5HhJNjBtW3FEXAj5StoKIOkctPLmCeuBA0D2ubIHeV0iaGb0/ZVcajVsrSbmmHhH1uV4ocEkSvJ8km/vxAZZfbrQuOvTYYLCgPuMjgpjZjQPYvxGVzJkxHv/wvGj6GLhWtqWf6d44B9Q2NsE7qGuQYV5t+pAmCg3Oe+7aDUR0b8B0/uYoyTESx5cj3aYuC3b9MJEHOSG/PGOgLIGvEu/GHs+jv7fUCnMeod4ztj2Lp5+5VLDhUmtzS9ljGJ7iGM4cOgsQzKTNxSEg2BjjE+KxDCIdD2kPxigF66GRnvH+813HRcM2gNfnSqejdd1RoMdPtWt3EqQPJtvaoH+ljndYG0JRi8qeoh9q6KPINEDIU8oXvWpsUH3WKeGISha8yTYN/9oIGSGwQBQUAQEAQEAUFAEBAEBIHrgECmJk+MwI0pCRIDR8YlIKHAk21DoWHcY6hKUqbh5b1G/A66l1RpUEylAp41YqNSTrw7saeKk2FYIOQJg8CSSCDZQVUICQRmBiFZwjSibe6voRQNrCs3oiUq5VeZS8wWM6YNXYPjB86ruBTG5ptkgBHolhs6ukGcOHRBbfzoGvP6b119KiS8jTNjs84An63uqa7ispw+ekmpc4zgsGeOXsL7fZihpoBKOZwzNga71x8DXY6YhYMxEmjcJNNFg38jiUHFDsua8PkyjyfzDPpJUui+N5orpRCxYGBZuvkEY8SGbh9UAz39ZTulEvjjyxUwm00q8Cs3u6WrFlD4EFcqBcreUlApVZilhQFk6d5DhUHz7lXUo5lt54P7Jiv3DG6MC5XKg4PbTmHsp0tQvUlJlZ1IXcfN9J2jVX/QFYiZiuaP2wyqo9ieYMmT69EWVyw/e2Sqcm9irJCUqYuDwZx9R7KEhBXdoI7uO6fUYBzrVCmkVCJR9UJyk9mmPKWjDnSMhZs84Vihew7dz+hOVaBEbhzffw5Th65R7xXVLQbJxiDVXzzxNxrdWRFNulRS5CbTdzPAM1VV3mL7+MI1EPKE9weKN3Het/mECnTMYLdUlv353SrQDSkU8sRQpjEwNrNEcUwTG77rdI8z3HaCffeDGWtyrSAgCAgCgoAgIAgIAoKAIHC9EMjU5AkVDAsmbFGn5p7UFkb8kpRZUkg88MTUW5BJ3a4rsoSuGtzkccPEjBvcUKWM6xAIecIyqGbYu/GEKqtx50ro/Fg9xyZo/n4071bFmb51x6o4jP98mYpLQRKBygD+99KpOzBkXl/nOKFLBzdCTJHM/2b7mXmHhEa2nJEhjycGWp0zepNKLUtlCdPyPvJha7cYJSSgmJGGpAkJA27MmnSuhNv73OJG2nBjzlTL3CQzhgLrSDKEbTdizBgV5Yk60xgzboiu62rjzTJ9xQPx1kgGDGZqahJK+YvmVKoIBqxlmlUGAGUGEZ6U01g3BgRlXa2JySodNV1YGt55LdAwr7t0LkGll+bJO/EmgdagQwXc+XAdt8xG3FTTrYrEDJU4ze6qovqcJ/4MOGtYIG47vPZ6tMWog+Hy5ileSTADiGNg+rC1ipxigF4qWKg4uuupBh7HohE4luP7o6m9PRJ9gY6xQAmHQNvDd5WBmxn0lX2eMzZauaSQoDUIRKMspiAnecC60pWtWqMSijxkUNlQLNC2BIo33ymmjN676QRMJk2pUDgeP39smltGrUDddtimBeO3gjGcSJBwbiDBzCDXxOnxz9o4mx3Mux8KVnKPICAICAKCgCAgCAgCgoAgEG4EMjV5Em6wMkJ5DKrJTbzryTXdH5Rcf8RdGaGKUodMggBdTzjOnvmmQyZpkTRDEBAEBAFBQBAQBAQBQUAQEAQEgdAQEPIkNNxu2F1DHp+uXHT6vtUCeYvkxM41cSqbCd1zjBgeN6xy8uCbHgEGBqVbzIIJW1UQW7qtFSuf96ZvlzRAEBAEBAFBQBAQBAQBQUAQEAQEgbQgIORJWtC7AffSXYbxQxi8NeGqVbmd0K2HASh9ZXq5AVWVR96ECDDbyvA356t4Hsz0U7Vh8ZuwFVJlQUAQEAQEAUFAEBAEBAFBQBAQBMKLgJAn4cVTShMEBAFBQBAQBAQBQUAQEAQEAUFAEBAEBIFMhoCQJ5msQ6U5goAgIAgIAoKAICAICAKCgCAgCAgCgoAgEF4EhDwJL55SmiAgCAgCgoAgIAgIAoKAICAICAKCgCAgCGQyBIQ8yWQdKs0RBAQBQUAQEAQEAUFAEBAEBAFBQBAQBASB8CIg5El48ZTSBAFBQBAQBAQBQUAQEAQEAUFAEBAEBAFBIJMhIORJJutQaY4gIAgIAoKAICAICAKCgCAgCAgCgoAgIAiEFwEhT8KLp5QmCAgCgoAgIAgIAoKAICAICAKCgCAgCAgCmQwBIU8yWYdKcwQBQUAQEAQEAUFAEBAEBAFBQBAQBAQBQSC8CAh5El48pTRBQBAQBAQBQUAQEAQEAUFAEBAEBAFBQBDIZAgIeZLJOlSaIwgIAoKAICAICAKCgCAgCAgCgoAgIAgIAuFFQMiT8OIppQkCgoAgIAgIAoKAICAICAKCgCAgCAgCgkAmQ0DIk0zWodIcQUAQEAQEAUFAEBAEBAFBQBAQBAQBQUAQCC8CQp6EF8+QSnuu5W94e/zdiC2U3e/9p45cxJTvVuPRQa39XhuuC5ZM2QFbsh0telQNS5Fxe87i66dn4JN/7gtLea6F3Ah8wt4IPwUu/nM7/vphDa5eTET/j29HrZal06UKVy8l4flWv+Hjv+9NNVbZp7+9sxDH9p+DOcKEu59vhKZdKzvrNX7wMiTGW/HAmy3CVteP7p+MASO7eS3v/d4T0eb+mmjQoULYnikFORDIanOW9HtgCPiaIwIrQa7KDAhkxvlh4pcrsHz6Lnwy415ERJqxfWUc/v5lHV4a1gnGuHftuwp1iqjfEq9a8UzzX/HFggeRLWekuuT1jmPw4DstUaleUb/d/e/Ebfjn1/W4ciFRXd/37ZbIGRuNBeO3Yt/mE3j4g9v8lhHsBaGs+Qb3n4aazUvhjvtqqMftXHMUvwycj/cm9UR0dkuwVUjX6w/vPIOhr87BB1N6BfTcUPAJqGAfFw1/cwE6PFwbhUvnSWtRcr8gIAikEQEhT9IIYDhuD2ahsfHfg1g1c0+6kicThixHoZK5bwryJD3w0XVA08LR82kr44v/TUerntXTjTyx23Qc2HYKJSvnR4TF5Fb5UR8tht1mx72vN1PkSUo7c+yy+r1A8Vxpa/R/d8dfTsJb3cfjs1n3ey2PhE7u/NmQI090WJ4phVxDIKvMWRnlXb9Zxp6vOeJGt0G369BMGWDivtFApMPzM+P8QPJk0aRt6htHQt6VPDEg3bf5JL5/cRYGz772XUoLebJj9VF8/8JMPDGkHcpUK4Bxg5fh4pmrePqr9teVPAllzcfv7eBHp+KdP+5R31weXrR/qHZIhxfpPe8GS56Egk9aX7sP7p2ERz5sLeRJWoGU+wWBMCAg5EkYQAy2iF1rj2HkB/+qhdytbctj7pjNTuXJpXMJGP7mfJw8fAGapqHrE/VRr0059QiSJqMHLUay1Y6YHI4TjBd+6Iii5WLBheG4z5Zh89JD6r/r3VEO3Z9t4Kzaunn7MXXoGvUbTwHuG9AcJSrlU7+fOHgBIz9chAunryI6mwX3vNAIPDWhjf1kKZb8tUNtli1REeq570/uGVCT54zapBYbSQnJKF2tIPq+1QLZckWBH9lvn5uplAlL/9qhcHjwnVaoULuw3/pwITL8rQVK4cC21GpVBt2ebqDIDF/4+KowFyijP1qEN8f2QGR0BNg/I97/V/1/VEwEpg9bC7tdhyXSjHnjtijFBzHIVzQnvPUXlTo8XXrqy3aKbKARh5fbjlR9nbdwDp8YcmE28cvluHw+AXkKZlcLNqMc40ZP5Imv8cP7/vphNdbM2afwIiH20Hu3OU/DfI0RPitu7zlcOhvvpjw5uvcchvxvOkhmGGOEz3n0o9bqlGzrssP49Z2Fqu317iibSnnibYywDJ7uzPp9g1I9FS2XV52wcfydOXoJHz3wJ65cSECO2BgFR5f/1UOzu6qo/5764xosmrwd8ZcS1fNclSes59hPl2LfphMwmTU06lhRLfBo88ZuxpHdZ5GcZMPpuIuw2XQ88Xlb5CmQLaDxnpkvygpzFscZN31vjOqGX99egOMHzqN2qzLqhNjXePzwvsm458XGzvnLeNep0vp6cT+PZKIxVjjm9m48oebA8yevqDH56Ee3I1e+GL/jcfOSQ/jz21WwJtmQv2hONdYN9eILrX/Ha7/dhYIlHGTlS21G4pVfuigCc+QHi9Q7T0KTczBPtm/rVV2R49y0zPhlHVbM2A3+T9kahdDn1aaIymbxWx9vcwSfz03lmI8Xq3kiW84odXpevEJev68M32WqCY3Tdc7Fxw6cV/OLP/v8sWlo+0AtLJu2E9tXxak2f/hXb3Wbt/pwPuN9n868z9lvu9cfx+/vLgz4VNpfvTLj71lhfiB5cv7UFZw9flm9S+lBnlDNycOI+wc2V8OG65+1c/ehcedKijzZvf4YdF1X3zOuKR7/rI06MKD5mh84zrnG4fvItUCHh+vg1nbl1X1pWfNRYUqFDNeWGxYewMs/dw5ouN+INda8MZsxZ/QmZM8VhTqtyypVkaE88TVf+cInLetwX/1F4uTIrjPInjtafSuqNy7h/C4FBLBcJAgIAmFFQMiTsMIZWGFv3jVObfhr31YGiydvB0/tDVeIcZ8tVZtFbpb3bzkJLki/XPiQWlTTuNDlQiWl2876+fsxbdhatfDnRvXNbuPx5JC2KFO9oLrvxdtHKDKAG0HKKfmxbd/PsWnk4r9Jl0poeXc1HNx2Ct8+PxMfTe0DS5RZ/f7T6/NQsW6RVMqTzx6ZqoiQlDZkXl9sXX4Yk75eiZd/6qwWrSRndDvQ9+0W6h66XPR8qQmad6+ChRO2Ys3cfUri6q8+88dtAT/8973RDDzlJF5tH6ipiAxf+PjrGZZjiYxA58frgR8qLlbK13KQOSRluIgnGdDr5SZKskvjosNXf03+ZqUiukhG0bjoIZn0/A8dfVaHBMjbPcbjhR87qQ0GP+rTf1qLD6b0dlO8eCJPfNWHuP/0+lw1DrggI5ZUgtzStKTfMWJU2NuJorcxYtzHhUrc3rNu5AkXC97GCDF4rcMo1WaSR9+Ri3mjAAAgAElEQVQ9P1P1R7sHa6kiubGlTNj1hC8lqDwBrNu6rBt5YizuHnqvFRKuJKlx2PvVpqjasLhajJJcemtcD7UQ5SaTC1GOiaxuWWHO4hzLdnKB2vOlxmruNNQKvsYjpelVbi2mNjQXz8Qje+4oHNt/Xr1r7068x+fQ4ZjjPEFpO4mPCZ8vV5shPt/XeORzqLx6cWgntVGZO3ozdqyOU2QtzRt5wt8MxdYvA+ehVJUC6v1nHbgh5IaHhMxrv3VFdPZI1YaCJXKj65P1A34/PM0R7/WaiA79aquDgFm/b8TONXF45psOfl8rfgs/fnCKegfzF8uFb56ZgTdGdVcY+zO+v7vWHkW7B2ujcaeKjjn7P+WJr/rweSRUa7Yope4Z8/ESNQ/c+Ugdf4/Msr9nhfmB7wjHAb/HJPP4DhpuO0bHh1t5wkOCxh0rouU91VKNLWN+MOaAYa/NRZEysej0WF1VN1/zw48vz1aEAQkTHtDwu9jv/duc6wt/33NvA51kDNeeSfFWNZ8Ur+g4oPNn6b3GIgH2zj1/4J0JdJfPgV/fWqBcoAzyxN985Q2fUNfh/vqL+JEA5xpZ3Hb8jSb5XRC4/ggIeXL9MXZ7AtUdVCR8u/RhRYjwlPvJxr84yRMuFvkPFRC0Jxr+jI+m9XGefnsjT3hiyA8WTwhpXz01Q52qG6cJA7uOQ+NOlRRJYpxM8Lrzp65iQKdr9eHfPun3Fzo/Vg9VGhRTZYXyIeXCNX+xnM5TfWuiTW0K2C5u4rlA5aksCQhDiTJoeh+/9Vk5YzdmjdioNrxlbymY6lTXGz7+upmEEzfShUrlQaFSuRW5ZRg3+dxEfDb7AaVEcTVf/UVFD08xSYyxr7lgqdWyDBre6TsGx8p/dmPF37vx7LeOzQU3cPFXrE6FiPF8T+SJr/rwpJlSWhJDPLkwxopRnrcx4trecJInvsYIn8mFmKGwos/36bhLzhO4UMmTN7qMxUPvtnISY8bJPQkuLka3rTiMJ79wbEBJ6u3felJdn5Utq8xZ7GNuVmo0LYmO/eum6nJv45HEJknSJp0rqQV5v/cc44Ubgv8NbuNz6HDMbVi430mobltxRJEXJMF9jUeWTdWeQcRy/uK7yTmVCjBf5Mnn/aeqeFMkfUgalqtRCN+9MEsRPb+/9y8KFMulfOtprA83jQNHdw/4/fA0R7B+ERazmgdJ3FPZ8/6fgcUXIFn+w0uzFKnV8dG6qN6kRECv46SvVuLAtpOKYEppvurDAw0qVRhPigT9qx1GKRVPviK+1YIBVSoTXpRV5gcqT6gI4xqGY5KqtGDIE6puDXdfqlf57vqLefLO3RMU+edpzcD5gUrjZ75ur0YV/5/jnd8rf/MDVScJV6zo1L8uipSNTTUqQ1nzGYX8+MocpZKgOjdQN7n0XmOtnrUXjB33wo+OgyzOcyRJDfLE33zlDZ9Q1+H++ot1FPIkE06e0qSbFgEhT9K5647tO4fPHp0KqjMMe6rJL3h/ci918ki1CVUOVy4mwmTScGDrSQyafi1ApzdygMw1P+7HD5yDyWxSJ/O9X2niPHXnRp6L/C1LD6FAidxK2VKqSn7Q1/PD+ycjtuC1YLX8cFBhUb+tw10olA8p3XJ4cme4UrjCnDJgLOtKIoAL+kDqQ8UET3/oWtG0axV0e/pW50faF3lCXBf+sVVVpWKdIkri6mo8vaWrDMkOqh0Mo+sJNxBUbKQ0f/1FdQ4lsdygcONOgsggxrzVZ/bIjQoHf4HgPJEn/uqzdfkRzBm1UW1gqjQorsgIIyaItzHi2uZwkie+xgg3LVSBcBPDBSfHN8k8I+BsqOTJ002H480x3VGwZG7VLLoNHdpxWmGdMgAfx9KeDcf99kM6TyHp/risMmcRWJK6VDelDMLsazyumbMX6+cfQLmahRTBx8DI+YrkVApAKjZ8mSG950adxpNrKkLoXuJrPFLJNeX71W7xfKikemucI/C4L/KEwbq5SSB5UqNZKZSqWgDfPvePUr+kfCf5blD1xbk50PfD0xxB0nvhxG3KbYi4kEwPNDgjcSG5c+Lgebw7sWfA8aY4Z/M5VPGkNF/1IUk2oPNYfDS1t/oez/xtg3OTle4v303wwKwyPxjkCdc0b/eYgD6vNVUu14Zi1nh/vcU8ocqBai41zzw0RZGsBnnCb/nhXWfUb1Q9GUFXOR/xAIxudSktLfMDiZNpw9aArro0uoe7urf6WvP5WkfxfflpwDylaK1zWxk3tTIJip/fmKeexzWqq2r0eq2xvD2T60C6az/+6R2qPqw350NjTvI3X3nDJ9R1uL/5nHUU8uQmmAylilkGASFP0rmrUyo9uFDjYtNw2+HpPz+c9D+nKoVR2rmQNnzZvZEDPEngorTfe7ep0z0G7uJHPmWmEW4C6APOTSNPGnlqxGcaKhBPcITitkM3HdcTTH6sL52LVx9VX+RJIPUx6njuxBX88PJstLmvhjMujC/yhHXgxobG+CU8CTKMsTwG9f1TSVlJyrgSK/yw0yWKUvaU5q+/lk3dqT7S3PjT3YpuS4Z5qw9VJ8v/3oXnv79TXUrlydF951C0bKzbSY4n8sRffYxn03eaQc84VkikuVrKMeL6WzjJk5Sn3K5jhIsXnuq99mtX1U9csNHfPK3kiSflCdU6PZ5rGPDmMJ2njBv+uKwyZ/Fd4GaFp7HVGrurG3yNR56yMhYVx+n9bzQHT14Zh6pinaJ+VWbcAG1cdADPfed413kCO23oGpVFytfmiCeny6fv9Or68tIdI/DST52dEm9FGv5H/voiT1K+kyRbp3x3TQnjmt3DG7mYco6g4o1uHVTTFCufV7mNUnUWKHmyY1UcJn61QhFS3Gx62kh6eklIntBcVYT8/0DqQ2VMhdpFVDwauqxSxSnmGYGsMj9wPFF5wgxuHL/8bpw+eilg8sRXth26zrA8GgkWQ+HKeYXrOkP9yG8z13pU3nJt4e199Dc/uPYkiQPOCQz0aqiSfZEn3tYtXKdwDdW2by0Vo4yqWxJGxuEM17M8FKQxnh+xNOx6rbG8PZNKD8ZUM5QnTDTwxxfL1ZwUyPzgDZ9Q1+GB9JeQJzIDCwIZBwEhT9K5Lyjre6PzGNz1VAOl7OCpFk/YGWOEBAkXnvQFp0sK3QY4oXPRa/g50qVj9shNGDDiLnWqxkCmjCnC046ytxRSp6bqY/jMP+o0gSQMCQkGWWUMFKoeDm4/rYLSGv74nzw0BY06VlLxR8icTxiyTG2oDZcJLhQoue79ahMVIJVBZY14KN7g4yaAJzWvDu+iymFcF7rtcPPrizxheb7qQ/UMF9FczPJjTfKEQXeNoLre8PHXzT+8NBuV6xdTvsUknpp3u0Y8+fqw++uvxPhktXFg/1FyzoW4PyORY/gr02eYGzeSNyk3G57IE1/1YZ8wFg1VRTQSaAxMzL72N0aMOoeTPPE1RngSs2XZYeW6xIXlF0/8jcKl8jhj/TC45uudxijSkXJ+BofNmffaYoz19RTzhITR5XMJ6Pd+KxXY7qMHJjuDFQd6su6v/zLb71llzmK/eSNPfI1Hbm54Es35m37+PMGkYoMny1R1+DKOuT+/dajaSCxzns6ROxr3vOhwI/O2OeI7wWdS+s+4SJzzqcbjaTiNcZs69a+n1H+bFh3E9y/NVsoSmi/yhJsIbhJf//0utYEb+tpclKiYT8X7CPT9SDlHUEVnqC3NZg2/vbsQJGV8xSsyMOPhAmNyUZmTp0B2pZJkkHS6Vvozb+RJIPXZve6YUvacOXZJqV1Sumv6e3ZW+j2rzA+G8oTkCddQ/P7y+xyo8iSUVMV8DtcjHP8kDjkmj+49q8jWtMwPVJh1f7YhipTJo9x33r57gnrnjeDooaz56AbDgx8jSCzjqDCY9X0D3A9nPL0b6b3GokLw3Z5/OBM1MF4M16VcYwUyP3jDJ9R1uL/5nJjxYOyup25Vih6u11zV0VlpvpG2CgIZAQEhT25AL1BKSDLBZrWhde9blPTz1V+7Kp9quqTwH7LyzITAiO4Ht5/Cm2N6KMKCvrLfPPuPygrCrDk9X2ysiANmBBjx3kLF8pepXggFS+bC3z+vU9lCGPhwxi/rlZqBrkCMdcH7KDOnMZvBqA8X4VTcJZVhgScHJF0MM6SY3NTzZII+tobbgy/4Zo/YqPxKubmoWLeo+ojy2f7IE1/1OXnogvLL58eGZAxdT9gWI6CuN3x81ZMffNaTJ7V0EeEzGIyUiwluiHx92P31F5/LDy3dT6ggCjTFMTcXk75aoeJ+EHMGc2PmDG7KSIzR2FaSYQxg2/Luqoqc8VUf4sW60BWMslkG2WUGJOO0ydsY4aaMgV1pHAMcY/RlZn8a7g3eTmIYeO3i2Xg1BijZ56kas/wYCyxvY4QkHgMX0+hSxvFIOfBdT96qSD4aT3nWzN6r4t406VJZqUdOHr6ITx/+S/1OQoUZoogPybbuzzRQC0We5nFM8z6Wa5xkB7o5vAFTxg1/ZFaZs7yRJ/7GI+NGcR6myoHvC7NkfL3ooVRxhVJ2JMccA73y3eCczjhR/QfdrohAf+ORfcI5gqe5JBB7vdTYmSWNhAmJdwZDpIKCrkWMv8L33hd5wvrxu2Fk26lUr5gicjjP+KqPrzmiZovSiqynWwLnDpL6xIeZfIz4MN4GOOd6zk+8h0YiecGErYqkMuZ8b/d6I0+42Q+kPiS9y9UsLFktAph9ssL84EqeEBKSelzPkDzhd/r5235XSBlBpukaTGVDWlIVszyqEqZ8v0odbJFAYaaqnLHRaZ4fSMRQ7cJv+e19blHrzVDXfFyL8MDn6a87KHdwY33Cv/EwMGWmwJRD6kassXhwybU3D/da964OrkUYXzCQ+cHbmjgt63Bf8znxYiymyd+uUn1WrFys2jOICQKCwI1BQMiTG4O7PDULITBt6FpoJihyQ0wQEAQEAQMBEhJciFMJJZaxECCB3uXxek5CKmPVTmojCAgCBgKyxpKxIAgIAumJgJAnAaLN0wOmYLvvjeao0cyR2lVMEPCHAFPiMWgs3ZdEZukPLfldEMhcCDBLFJV0nqzObWXVb66uOZmr9f5b4w8fb5l1mO1k7phNHh9ARVnKOE7+a+J+BU/CqbZj2nIxQUAQyLgIyBor4/aN1EwQyKwICHnip2cZoIty43GfLlFBOx/+oLWQJ5n1bQhzuxhThJlzuj/T0G/gyDA/WooTBASBmwCBlK4wN0GVM30VmVKerqX9P74DJSrly/TtlQYKAjcrArLGull7TuotCNzcCAh54qf/GJWbEzSDhP07aZv6tyhPbu5BL7UXBAQBQUAQEAQEAUFAEBAEBAFBQBAQBIJBQMiTINCiD7SQJ0EAJpcKAoKAICAICAKCgCAgCAgCgoAgIAgIApkAASFPguhEIU+CAEsuFQQEAUFAEBAEBAFBQBAQBAQBQUAQEAQyCQJCngTRkZ7Ik6Nn4oMoIWNdGh1pRrYoM85eSspYFUtjbfLnisLFeCuSrPY0lpRxbreYNeTJEYlTFxIzTqXCUJPYnJFISLQhPskWhtIyThF5sluQLToi5ApZk+03dV/njIkA83JfumoNGYOMeGORvDE4fjYeekasXIh14jiNNGs4fyVz9VWh2GicvpAImz0z9RZQIHcULBGmEHsbuJqQfFP3dd6ckaoNCZno+x5h1pA3ZxROnk8IuV8z4o1csyRZbbiamHm+75oGFI6NwbGzN+/a39tYKZovJiMOI6mTIJDhEBDyJIguEfIkCLBu4KVCntxA8IN8tJAnngET8iTIgZROlwt5kk5Ah+ExQp54BlHIkzAMrjAXIeRJmAG9jsUJeXIdwZWiBYGbBAEhT4LoKCFPggDrBl4q5En4wdcSr0I7EQd7yQo+C49YOQ/mpTOgnT8De5P2sDZpBz1Hbq/3pCd5Yjq0G3rB4tCjvZ+uaInxMO3eBNOxQ9DzFYQ9f1HoBYpBj8kWEKimI/tgOrwXOZu2REyeXAHd4+kiIU9Chu663ijkyXWFN6yFC3ki5ElYB9R1LEzIk+sIbpiLFvIkzIBKcYLATYiAkCd+Om3TooP47d2F6qr4y0mIjI6AOcKE3q80Rf225SBuOxlv1N9s5Inp1FFoxj+nj8F0/DBgs0KPigEsUdCjomGKikZMbCzOt+7lF3DT6WPQEhNhz5kbeq5Yv9d7uoDkgenAdmj7tsG8bztMR/ery1gne4UasFetC1vlurAXKal+i1j8N8wr50KLv5KquORaTWBveieSq9VXv5lOHFb3aIf2IurkQdhMFljzFYKWvwjs+YpAz18I9gLF/NbbdOEMLF+/Cs1khq10FehlKkMvXQW2oqX+e84RmLavhXn7Wph2bYCW4JDZ2oqWhr1sVehlq8NepjK0+Msw7VwP07a1MO/e5PG5evYcsBcvr9qe0jT22eG9MMXtc/4U+fEIZCtb1m8bvF0g5EnI0F3XG4U8ua7w+i1cu3IJ0O0+CVmjECFPPMMpyhO/wyzdLxDyJN0hD/mBQp6EDJ3cKAhkGgSEPEljVwp5kkYAr8PtN4I8UYqDPZth2rXRsQHXtP9UC4WhU71QkOqF7DCdioN2kmRJHLRTx0CiIxiz3nE3rN36e73FdPEsot7vD+3yBec1evZc0EmkxBaAvVYzJNdvpeqSigS4fAERS/5BxOJp0M6eDKhaekQktORrMXPsJcrD1qIz9Gw5YV42E+YtK13qkRNITHS73ttDWL+kB1+FrUYjj5eQgIn8+jWYPNRTj4wGIqPcMAioMQDsuWJhq9EYiMnmILROxsF06hg0a2CxZuyxBaAXK4voh19E9mJFA31squuEPAkZuut6o5AnvuHVzhyD6ewp4PxpkNxMbtQOevacaeoT84GdMG1bDdPmlTAf2AF7rrxI6v8m7OWq+yz3ZiZPOL9FzBil2qfnJ6FcDPYChYH8RZCvVDGJeSIxT9L0TqXXzRLzJL2QDs9zJOZJeHCUUjI/AkKepLGPhTxJI4BpvN28a2OqEnJnt+BK/pJIjMrht3QqLKieCNaoMlDuHTsdZIl25WKwRTivt+ctqBbI9vxFgDz5AGipyjLBDvOMMervCS8Ogb38LR6fFzX4eZj3bvFbl+RaTWFrcDtstZrAtHcLIhZORcSaBdfqFJMN9jLVoFeoDnu5arBVqKl+IzlDhYZpxzqHWuP8GeUGk1y/NWwtO8NetIzbs3m9eckMmBdPV9eqzUDeguo6W7HSiMkWjeRkHclWK7QzJxRhoQgmnjADsN7WDda7/+de5qHdiKLi5MolkKywNWoLxF+F6cgemI7ug3blsuM52XPBVrk29Iq1YLulgbqWZt6/Hab926Ht3QbTvq1AVDSSazaGXrMpbGWreMSOdefGEPFXQNceJCY4/w1LJOwly8NevILTvUcCxkrA2JQDSbt4DhFTf4WtURu/G3+/L3AYLwg0YCwJRCqstLMnoJ07DZw9Ce38qf/IklMwXTyXqlb2PPlgffRN2MpWC7jGfH/N21fDtGUlzFvXeCVBrZ36wtrhPq/lFrx8FGdjCiDZbAno2SScTccOwnT8EHD0ILSTR6BZUwfR1fMVgrXnUz7d/4wHKlXh6eMwnTkOUBF4+jhgMsF+a2skV7819Tx//gzM03+HZek/XuucffgsWHKkJr8DaiQkYGygOKXndaI8SU+00/YsUZ6kDT+5WxDIDAgIeZLGXhTyJI0Ahni76eQRWIa+C/PRA15LsBcvC1uVurBXra820TS6i5h3boBpx3pFftDNJLlhGyT1fdlnTahwMG9YopQl2q4NMMVfdbveVqQU9DJVYK9wC/S8hRy/6Tq0cydVrBC6diD+MkAVSiHG0SgOe77CARM3zLaTY8FEJI79UZ28Jr7za6o4HJaZY2H5a7hSlVgfeQNUhbiadvwQzKvmeyVXdEskkuvfBnvrHk7XF3/dw80GNxNK7eHHTId2QS9UHHrUtfgh3mKeWGaNg2XKL6pEW+lKsP7vPdVu886NiPx+ILSkBNgLFEUSiaTcJJyumencKYDESvHQ3Wb8tcXf70KeCHniOkbM29YicvhHTpLVVrEmkrs87JWs8ze+jN/5/pn3bYOebIVeuBT0IiXUexKoafFXEbN9JcznTyFBszhcBaOiHf/mfHlkr3KvU2TxySOBFpvquuSujyCpbU+v9zMekXnrKpi2rIaZhGYKs1WqBb1KPTUXmDYug2XBn465oUINJD0y0OmeyPmc7oN0IzRcDYm1nd+ByrVhK10ZpvOnodEt8fhBRZKQLCGOwRDger7CSHzivVRksVFty7yJiJg+wukq6KnhjAVlq9cStltbw16wBCJmjUHEgr+cyrzk2s2hk9i32xzEMt0DT8Yhxw9TYIl2n9uD6Rhx2wkGrfS5VsiT9ME5HE8R8iQcKEoZgsDNjYCQJ2nsv6xInjAmh2n/Dmj7tqpTSOTMAz1nHiBXXrWI1XPng71URY+uId7gVnEw4vZBO7wPpmMHYK9UE8mN27lttI17Ixb+BcukYWqRyQ20nsehKHD+rluh79nm9jcSA4iweIzJ4VyEP/YuGNsipVkWT0cEn0fFwX9GhYK9bDWlAOE/aZWm+xuGRqrii288ppQTXFhTum4Y5exRnzyt/jfp6Y+QXNURX8STKSJozUKYV81TmJN8sLXsguRmHa97O1LWx1fAWJJckT+9q5Qk3Ggk33YXLFN/U0UwcG3i0x9DzxF6UFZ/mKfldyFPhDwxxo9l0lBY5k5U/0uSlQoNY6Nuq1IHyR0fdCNRtEvnoV0861RfuY5DznnagZ3Q9m5V84CnGEMkT6mm0wuVhF6kFOyFS0AvXFLNlTSlBtu0AqZ1i1Q8oGDMTvKzEAmaWOC/uR45OefHQs+V16Ge+89IcEb88SMsS/5Wf+GcZO33uppjFMmxbQ1MW1fCvGU12GZXY9wie5V6sFet5yCkLVFuv5s3LIVlxKeKxKbCLLl1N+ViF7FiTjDNSXUtSRGSrvZiZdU3DNHugaK1S+dgGf+ds77We5+HtWkHZznm7etgGf8NTCccRBPnLXtBkuVFoccWUqoTPTkJEZuWO2JbeTAqUpI7PwS6QHoySVUsqYrTNMjT8WZx20lHsMPwqJvZbefjB6egeMV8uG9As5CRCEcZIT88HW78++d12L4qDi8N6xS2p104fRWvtBuFj6b2Rr6iaXPRDVul0qEgIU/SCHJWIE+YaSVi2UyYtq2Daf82j4t6TzDaqMSoVh/2KnWcsm0G7TQd3g0tbj+0w3Sz2A9T3AGPMSXsMdlga9wBttbdlMuFdvkiLL8OQsS2NY7FeIsuSOr1VKpHM+bJpQuXYNu6ARqDhe5YC/PRg47FbL5CSK5UGzoDnlaqAy3+EqK+elWd7PG3xKcGqc0Gja4aESMHX3se3VyatHO6sKRx6AR1u0GenNl/GFHvP6JONBP7vQ5b/dugXb2MqPcfVSeqntxcfD2Ip8n2gsWDqks4L/aXbYf9EvXDW27BWHmSnPTE+87T8XDWJ1xlCXki5AldNiKHvuscu9YuD8Parpd6dyPmjEfE3ElKQUUjKaFczy6eDWoIUpFhL1MVuHQO5uOHQXWZNwUFlWiMe0S3OMNIPGgNWsGcIxcSLl5y1Ee5pcVDsyXDXrg0UKw07EVLg/N5KBaxZRUsv3+q3G8UmVCoRCr1G8l3W+U6DnXILQ0dZLwfIwkcOfQdULXiaiRp7E3bId9tbXDmxDlg21poDAbNb8F/MaaolGObSJToxctBJ2HCf/+nuPH1aLaDKiISJeo7VL8VkjvcD8ufP8G8abnjOxMVA1v7e32rbajmWTUPljULVYwp4pvc439+1UhCngh54u/dyCi/C3mSUXoisHqEkzx5/NafoNt1jw/u+3YLNO5UKbBKBXjV+gUHkCNPNCrULhzgHakvC0cZIT88TDdO/2ktsueKRqueqV1lhTwJE8gMrqDruufRHb5nZOqSMjN5ok4o505ExOLpbvJjnmzamK2kRAV1kua0+KvgyZx2+igY5M/VuJjkiaOnAJ+8jieWOhezRUsDJrNyq3GVb1NpYd690bEAz5YDSX1f8RpM1FPAWHWae/WSWrinNCobIr97A+b929Si1/rIQOX2wRNEnpBywZ90/4ten5ceA9wgT05dSETEqvmI/HWQ8rlPfPNnRIz5EhFbV8NWqiISX/suPaoTtmf4I0+MB0X+/AEi1v4LxmpJeuztsD3/ehUk5MnNTZ4wvgc3tCnnC18BYzmP0DXNFLcX+uULsMyfokhhkrJJD7+RinzgXGaZPgIR/051nytJMJA8UCm+U8Q/0uDY5Ferp1xWUioyWBDLVS56KnaHwz1Fo7Lvv+DKvMdWqzHst96u4m4EGvMkLe8Kie/IEZ/BvHmFg1yIiISd8ZToikOXmjS42EX8+RMi1i+FrXFb2BreAXue/OoZngLGKvLEZnOQVWk0y4LJsEz4IVUpdH1knKZACCDj5mBibwl5IuRJGoduut0u5Em6QR2WB4WTPDl15CI915W933siuj5ZH7c0dWRCzJU3BtHZPceiIuGimVLH/QtLA7NAIT+8NBuV6xfzSp7sWB2HF4eK8iStQ0HIkzQieCPJk6ghLylCwZMZqgRfzYuONCNblBlnL13LlsLrKTmOmD1eqU0MS27Q+j83lepe/bxdn0U1hHnnOnXiF7F9HTQGzDNS3aqTzLLQS/x34lesrMcTP5UCd85E5WJiZHSxlasO66MDU8W5cH12qNl2LCM/h8WlzSyTpI21z7M33D3ElTxhvSKHvYuI9UvUAp3EEAmthDeGqo3azWSBkidsE091U2bfWbvOhOLFdRQqmH4c8PkLGk6d0nDiJP/REREBtGimI0/ua3UQ8iRw8oQKLwYWzQimVCELpyBi7kSl4GAwZ3ul2qB7jb1yHRQuVQTHz8ZDO3HEEQ/k8B5oTFN9ZK9H1UhynRawPvCCR/dDo72cGxl7BDlz+1eg+IMAACAASURBVJzX0ooPVSXa8cP/xR1yxDShpQd5YjyLQan1bLn+c8UJPW5HIFikR7YdKhotw95R30y6ZCWTZA9RoRNIm3iNkCdCngQ6Vm70dUKe3OgeCO754SRPXJ/8dNPheODNFqjftpxbhab+uAbHD5xH+4dqY+SHi3Bk1xnkjI3GJ/84AoGTfJny3Sosn74LVy8lomi5vOj9ShOUqV7QWQ6JmSO7HYrNZt2qpHLbGfzoVNRoVgoHt5/G/q0nlRqmx3MNUff2azHxfJXBOjxefxge/6wN5o7ehNNxF5EzbwweercVipV3xBfjNX99vxpLp+5Q/93l8XpYMWM36rQug9a9PSd3cAVi06KDmDd2MyKjI7B30wk8+HZLzBqxEScOXcDTX7VHqSqOA4G9G09gwpBliNtzFrnzZ0OjOyuifb/aMEc4DrGJc1JCshvGriofKk92rTuGqg2KY/ZIx96xRY+q6Px4Pec9xGnC58twZDf7IgYN76yADv3qwGR2EFpXLyXh93cXKvef3PlicOcjdfHr2wvEbSe4V02uvlHkSdR3A93SwKbsCUOVwMW/N0tJnjBzjZmkydbVjgnBEoXkJu1ha9srzZsb5d9t0kJyEWFWFQYAZOA8a4d7/Q66UMkTFsxAf5aJQzOE2sS1oSnJE262ot55yLlh8xfnxC9oN+iCYMiTlFWMO6ph6M9mRV507WxHjer269aKI0c0zJprwrFjGpJSJ+BQz61V046WzXTkzatDyJPAyBPOOVFfvASSorb2fZBczXusnlA6l8SEig2yz5FhiSoMO90JK9d1ECL/xZVQZO/scYhYNC1VMGjX55oKF4ft9Emv6baZRcpevAz04uVVzAy6mGV0S0/yJD2xSA/yhO3RrEkwbViiXCjTw4Q8EfIkPcZZOJ4h5Ek4UEy/MtKbPFkzey+mfL8aMTki0bZvTVSoXQSJ8ckoWMIRy27F37sx/vNleOWXLshXJAemDVuLdfP24cO/ejtBSbbaFSHy+3sLEZ09MhV58sX/piNu7zknCfHvxG3489tVGDznAURYHKSDvzLoglSmWgE8MaSdcg36ecA8xF9JwjNft1f3r5q5B6M+XIRnv70TRcvFYsLny7Hh3wPo/Fg9jwqQlD26ddlhfPfCLLz8c2esm78f//6xFe9N6ok/v1ulsOn1chPEX07CgM5j0fWJ+mjSpTLOHL2Eb5+fiZY9qqJ1HwdBk5xkwyf9/kLDDhXQvHtV9TcSKwbxQfJk/rgtaNq1Mto9WAt7NhzHt8/NxICR3RRBc/VionoGf7utV3WcPHwRXz89A63uqaZIGtqYj5dg/5aTzraTONm6/IiQJ+n3mmaOJ90I8iRyxKeIWD5HSZ+ZbYQZCFzN+J0nYImvfO0VaIM8ubhwDiJmT1CScxrdaxhPJPm27h4DqGb0nksLeaImm50bHNL47Bkn+FFK8kTVc/dGUH0UbJyTjNR/oZInCQkavvnBhEuXrsk769axo0vH8BIoiUka5szVsGqN4yObPbuOfHmhCJLcuXQw8j5JnN17rrmv1axhR5/uZuTLExEy1NZkO+iidbNazhj/5Ald+yKHvOgW74juG8nt+iC5bougm05lhengTpj37YDG2EwkSzykz3UtmDE/SHaY9u90xh/hvGm7owf07LlV4FbT3q0w7dvmFluDShmq53gvipWDnQFOi7ufqgXdgBt0g5AnNwj4EB8r5ImQJyEOnXS/TciTdIc8TQ9Mb/Jkx+qjILlBVUqTLqljoJAMiL9iVWoUGpUp7/eZhC8WPIhsOd2Vi78MnI+obBaP5EmegtmVUoRmBDj9YEovFCjunnDAWxkkTx4Y2ByNOzvqSLJk8jcr8fHfjsPc4W8tUMRF/49vV/9/+XyCCqJ69/ONAiZPhr42F18vegiL/9yOuaM3492J94BkB1UmLHfx5O1Y+MdWvDm2h7OPSQQtmrTN7W8f3jdZxZPxFvOE97DeBqEysOs4pfwh/ix/5m8bMGj6vWptS2MMldWz9qr60F5uOxJ3PXmrE4vtK+Pw5ZN/C3mSpjcvC96c3uQJ07cyjSuN2UZsVeumQp1ZYaLefRhM2eorRWTMxsUw/TEU+pkTqgyVdeWOu5HcvKNHX/qbpXvTSp5kxHZ6Ik9UPRf8A7RysN83o4VKnowYbcKevSaULK6jWlUd/8x2kBdFCuno3cvu5kITKi5bt5vw9z8aLl/WYLEAt7XU0aSRzWNxVKbMma9h/wFHPZ55TEONqkKeXLrqWaZDd4fIwc+qmEIq6GnxcjCvnu8kO5gZJrlTX5U6259Fjv3aoSo5vCfVpVTP2UtXhr18deiM0xQZBe3yeWjb18HMdOX/BRDljaxHcvt71b89GeOXFLh0DKej88OeLXVWLn/1zKi/C3mSUXvGc72EPBHy5GYZsUKe3Cw95ahnepMnVD589shUfD73AaXoSGlUW1AlsnPNUeWOYku2K/Lj05n3KbcVV/NFnpSrWdjpmkK3k+db/Ya3xvVwut0Y5fgiT57//k5UqufIWLdh4QGMeP9fDJnXV/3/kMeno1TVAuj+TANnlajguOPeGgGTJ6M+WoxB0/tg2bSdWDRpO177rasiMvZtPoEnPm+LSV+vxOwRqcM0UJny5cIHnc/1R55sW3FEKVwMo8tS065VVD0nfrkCh3edAdtqGNVBJIe+X/GIwv+Jhj/jhR87OrE4HXcJb3QZK+TJzfWq3/japid54hqgLqnf6z43Fua9WxA1+HkFUMIbP6Y6FY0c/y2Y8pfG4HnJbfsgudEdNx7QMNQgI5In+/abcPo0VHyOokWCj8/hiTw5ddqEn3/V0L6NrlxGgjGrFTgSZ1KqCau7i6QqJnduHXWCLDOY5xvXhkKeLF1uwqw5JkRF63j6cTty5dIRF6dh1DgTrlzREBWlo9fdOsqVDQyT+HgNl69ouHpVh27XwADxS5fDqSapUN6OTh105Mnjv98OHtYwa7YJT/c3ZTrliYrLAT2gFOS+lCckLJhWm4FNbZVrI/HZT51DhwRKxIK/VPBmNXe9PdyZ/crT+GKw1chx3zh/YnBnG4mS8tVhpytQ6co+hyWDwkZsWw1biQqO1LR+zFfAWH/3ZtTfhTzJqD3juV5Cngh5crOMWCFPbpaectTzRpAng/tPw4+rHvUI1MgPFikXEcb9iC2UHcf2ncM79/wRNHlSvlYRdHrMcdB8PciTzx+bBhI0dKkx7K3u49HqnuphI09IIu3deBwv/XSN+PAEmj/yJGWqYlfy5I8vlqv4Ma7kCVUnowctVgSNJ/LkxMELYFslVfHN9a7f8NqmF3nCTUXU8EGqvUm9nkZyC98vEK8zVCokRxIZTNQSqdLZWoa9p+IAqGt6PoYLLa/JwG44oGGoQEYhT0hMbNqiYfMWh3rBMMboKFZER4kSdpQopsGm67hymRt4XW3+L18F8uXV0fb2a5v1lOTJ2bMahv1iwtV4R7nduth9EiiJCRq279Rw6Ahw+LAj2Kk/q1TRju536YiO8k4abN6qoURxhKz0CJY8MeKcsO7397GDxIZhJEDGjjfh8BENkZE6qlTWcWtd4py6/uyPNetMWLMWuOji+uOKSY4cOu5sZ1fKlmAto8Y80S6eg54rNtjmqOsjRwxGxPJZUKlg6zaHrWZTj259zByS7cgOUPd5tVgl2IuUdD6PwWEjP31aqeLoHpP0/GA1L6U0y6ShsMydiORaTZD02Dte6xv9Wi+YLpyBtW0v2Bq18ZhNK6TGerlJyJNwonl9y0qvmCfXtxWpSxfyRMiT9B5zoT4v9551sFarj6uJnhWboZZ7I++jO0Ph2BgcOxt/I6txXZ6d0ciTd+6eoNxD2tzviB22Zs5e/PT6vAxHnvw0YB4skWY8+E5LVc/Eq1Y8f9vvQbnt+FOeLJu6ExO/WoFPZ97vjNVy6VyCCjIbRTfp/+yj+yejUUfvbju+yBO69MwYvl659RhuO9OGrsXmJQdVXBTai7ePwF1P3ariptCowmGGHyFPrssrmXkLTQ/yxLxtLaK+eU2BaG1/L6ydr0m0/CEb9f6jMB89gOTmnWCr1wKRQ98BU2rq2XMAT76PmBp1UmXb8Vfmjfid6gCbDeCG1p95Ik+4sWYZBfIHpkbw94zTZ0w4dQo4ecqhVHA1q9WO7dtNOHP2GkHBTCx58gBXrkJlagnEypezo+fdOqIidbiSJyROfvrVobIoWULHocOO8jrfaUe9uqnbt3efCZOmuBM4JBcKF4JSwURHuzfAbgdWrjYhMVFDbG4dvXraUaSw+zVH4jRMnW7C8ROOZ9erY0fLFjpy5fTfP4xTsnefhl17NOzfr0Ez6cibB4jNqyM2D2OKaMiXT0fxYu5lucY5aXirHR3aee7LGTNNWLHqWgySwoV0NG6oo3o1Ow4eMmHNOg1bt13rA0sEkCO7Dr4SjGmSPTuQN1ZDg3p2pW4JxdKLPKGLnnn9YgeREeMuY3WtNwOnRo4cDNOhPUh8cQjsxa5Fmg+kfebt6xD19aupLmXQVVvNJmBQZ23vVpgPbAeDr7oaU4uTKNHLVkPE0hmOFMAlKyLxhc+8ZqFhmvSoN+5XgVmZRcpTKltmxYkc/x3ssQWQ8NGYQJqR5muEPEkzhOlWgJAnnqG+mpCM81e8RL1Ot94J/UF5cwp5Ejp66XenlngVMc91gZ63IKx33ANbk/YeifL0q1F4niTkSfA4esu2Q7cdX8oTxtKgO88jH7bGyUMXMO6zpSo4qeFyQyWE3eZYozFgbFSMRQVXpUVEmhUBwJgqvpQngZTBmCe+3HaWTNmBSV+twOu/34W8RXLijyHLsWrWnqACxvojT0jI0BWoQYcK6PK/+rhyIQHDXpuL8rUKq+xBhn3z7D+IsJgVDsxQxPaVrOzI1sMYKr7IE6pyBnQao2KgMGDssf3nVEBZKmqMeC90Vzqw9RSeHNJWBdod88kS7FgVJ+RJ8K9F1r4jEPLEdOwgzPMmAWYzrL2fDQowFVTx8xfUJoJuNUkPvBLU/aYThxH1weNu2SEYYNb62LuILFjQY6rioB6Q4mKSFBs2mGD1cNBAAqF2EK4gzGqyY6cJmzYDu3Y7NsNVKpEggJviIGV9SZ6cvmjFrt3Anr3A3v2O1LK0mBjHprxkSQ0liumKFGCdz54Fzp6D899MNxZpASKjgMhIwGLRwc07yYKTJzXQ7cWfkaC4pbqOmtWB0qWvbfRJ4lAdceiwjqPHNERHaWrTzrop06EClFJVUqCgjgd625E/L0AJ7K5DSRj2s4M4KV1KR7++NjA2x/g/HPgwYCoDp9LojjNzlgmr1zp+K1GcMTtImjgywvgypuMdO86EY/+RI53utKN+XTtI3MyaQxWLo8ycOXW3oK0N6tvRormuyAgaiZJz55koScO+/To2b9Nw5sw1YsNXHZRCp6iOkiXsKF1Kw4JFGhhbhPV/4jHfJ1ns0zVrTVi1Bm6qH+N5JKRq19LRqKGDsAm3pQd5wswwlukjHKmqs+dA8h09kdyqK/RId99hy8wxiPh7tHMOUJm4nh+sCIxAjIvgqHcfccRQqt8KeoFi0E7Gwbxxqco0ktK4WDYVKApogO30Cbe4IryWREjiC0P8uv9YJv4Iy7xJSunCbFKuxudGDbxPxUhJeuAlJDdqG0hT0nyNkCdphjDdChDyxDPUQp6k2xAM+EERZg15c0bh5PmEgO/J6BfSHTLymwHOatKlMvn2HuogT4/JntGr77V+Qp4E33WhkieHdpwG45Aw9gnTAvd9qwV+e3ehChxL9xWmA/5n+HqPFRo4ujtKVMrnlzxhth9/ZfgjT0hQTCBhMnMPorNZ0Kl/XZV6mKmTW95dzS9gzLbjjzxhIXRhYhrhQzvPqCw89duUU3FWSBQZxnTGJJIYiyRbrig06VxJKUVo/sgTXrN73THVFgaqJXHFVMYdHq7jVKIwGC4z7Oxae0y5UvV8qYnKyPP+5J4oWDK337Zmlgs0Xec2USxUBAIhTyx//ADL/MnqEYlPD4Kt6rWc2r6e6xZUsXoDJD75QUjVZGwTxjihWVt1g/We/6n/Tpmq2Ffhp05q4PfO2BSnvJZuEP8udrhCUCHizUgQ1Kqho2ED75tWupUsX2XCzp2e43GwbMa5qFPLjpo1AFsylMqD5EeSVcOl8yas2XD9hrWxqS9ezK4CiXqyggWA6tVCrwPJi99HOtQrxKzvvTpKFbVg0BfJys2kUEEd/R+2OZ/vSqDQ1aRIER0T/zTh/HkHadSimQ2tWwVfn+n/mLBq9TXyhaQPjeRDs6ZA44Y2RSotXuogK0jYEJ+8sTrOnfPcf2YzULoUXW6AimUjQKXO1UQ7LlwATp3RcfachhPH2Z+pFTp87hOP24MiPOhatGKlw52H9eLYq1Pbrsix62XXkzyJWL8EEZOHOUkJe8HiMJ08oprC7DHWjg8guWUXmPZsRuSoITCdcPyW3LgdcP40IratUQRL0rOfwFbWkc7Ol1lGfwHLkhmK9KAKxDCH6mUJTJuWQc9XWClL7OWqwp4rL1xjnjAorHnfNmgHdkA7ehDWPs8GlMlKu3wR0a/3VqRP4qvfuMUv4XzKedWerwgSPhjhrwlh+13Ik7BBed0LEvLEM8RCnlz3oRf0AyxXLyKPloBTMQWDvjej3hDx50+InD0BqFIbNks0zJuWO75RUTGwtugEW8e+N0SJEvXlyyqjorVLP1jbXUt5GyiO6UmeWBZPB86fUd9uPV+hQKsY8nXXy20n5ArdxDe+2n4Uer3SFLVblb6JWyFV94aAkCdpHBuBkCfRr/YEZeg0ZpFIeO93v081nT2JqEFPOIIqVqiJ/b0/V2qDpCQdiVYN1kQgKUlDRISOYsUcQUi5afVmUd8NRHKzO2Gr0ch5iTfy5Nx5DXFHgbg4pmE14egxx7NoBQroKFdGR/lyQJnSduUKw40z3TwMo7KDLieulmwDtm41gWUbRjXGLdWAixd1HD+u4fhJDRcuuLtTlK9gR7UqQMUKOpKtcMSpWMd7/Lu+FCygK4VK+XKaM3goSYkjR6BcXQ4d0UBSKGcuXW2q88YC2bJ5JxiyZXOoVYh3ehjjlIweb8KBg4625srFdkO5Hj38oJ6qrnRFGT/xGgPNe6j2uae7XQWqDdVIzEyeYnKqbegy06qFi1Lmv4KvXNWwdBldfszOa7PF6IiNBWLzML2vHaVKaajgMjZ8xTxJSHQoTeKO8d+6Cm7LwK1VKofmekUiirFk0sOuB3nCVOKRo79yphS3lakKa/dHVWBU094tsPz1K8y7N6Vqnr1wCVgfeFm5ztAihw9CxOr5auGa+MzHsJe/xSskLDfaCDz91s+wFykVEHyBpCoOpCBjAW6rVBOJzw1Wt1B1Ev16L+UqlPTga0hu0DqQosJyjZAnYYExXQoR8sQzzEKepMvwC+ohUdN/h/nvUbDe+xysTa9lugiqkAx2cfSgJ1R6d+2FT3ClQh1F4kfMGImIVfNVTXkYaKt+LTtJelRfO3MMMQMfUI+yla2GxJe/DPqx6UmexDzfGVpCPJLuf9Fx+HGdTciT0AA+f/IK3uw2XqVDrtmiFFbO2K1cjD6c2seZZjm0kuWujIqAkCdp7Bl/5InpyF5Ef/i421PoumNt3tHrkynDj/rkGZjOHMPFPOUwtPA3OHEhxm9NqUbgxr54MYe7Q8o4FSkLIHmSlGjG9t3JOHzE4ULCWBZUEqQ0bsIZC4IbWG/G7CbNmgBly3jf3DL+xtr1GrZs9VwO21CqpI6yZUiY2L0SQrv3mLByNXDggAm5c9tVPBGSH3nzQik08hdMRmRU5ghSNmGS2YkXFTePPWxX7jKezFWBwgw8HdvbldtRWo3Ew5JlGpo301UcFF929aqGS5eB2Fjdr7oj2ICxaW1Het0fbvKEQVijPn4SWlICbKUqwtb5QeXOktKYfjdi2q8w73MEhLZ2ehDWDvemus4I/sofmO2GWW9SGt11ot97VMUosXZ5GNZ2vQKGL1zkCVUrDArLdie+8DlsFWrAMvcPWCYNS3fVCRsv5EnAQ+CGXyjkiecuEPLkhg9NtwpwcxwzoDcQf0X9nQdcSQ+87FWdR/dJ7dTR1I0wm1VWRSo7brQxM1vMC11UNbQfZ+CKfk3mGTlrPCKm/Oymgk6v+lqm/Q7LjFHOx8UPmRK0C1F6kSfamROIGXifqmtyiy5I6vXUdYdJyJPQIWZA179/WadSKRcskRvdnm6A6k1KhF6g3JmhERDyJI3d4488MSZra+vu6oQ3aug7YADFhA9GewzwaL0Yj4hBzyD7+QM4Yy6Cr/P/gCum3CqoJwN8erL4eHjMnkL3CBIoJFJIqNDOnNWVKwg3tyaNcShSkxh8FtUjxXlfcU39t6HIoNJkxy7GvAD27nWoEZiVpWVzx3MCNcbzWLfehMNxOooXYcYWHcWK28HgnWm1jJJtJ63tcL1/0WIzlq/U0P8Rm1+XlY2bTIiOdvRLRjchTzz3kDXZjlMXEh2Lz8sXEP3xU2DQV8qMKTf2Z+bNK6AXKg669HgzI6YIfyfBYq92q5sbD1MAMxVwSncdf8/m7+EiT1iWZepvsPwzGozVlPTCkGuqk0cGIrlui0CqE7ZrAiVPqLA7eFALOoV42CoaREHplao4KQkq/hLToFcPIYNVEE0CVWt7d0XCBity5XYEpCbxnBlMsu1kroCxBpmg5ckH/fwZNUTp+mjt9zpslWo5h2zEllUwL57udH/xNpbtRcvAXtKRet1etqr67/Q284alaq2rVbwF+mtfuWXboTtp9OcvqCxsCW/9kq5Vix7QR8XuIsFEt9OkRwciuU5w35D0Ik/o5hT1w1uO8VCuOhJe+uK6YyXkyXWHWB6QSRBIF/KEQWoYtCZPwZs3SJS3/vZHnkS/3x+mo/vVxMcJMGrIi0pab73jbli79XcWu2evCVtXXUatVR+iSsIqXDDlwy/Fv0Ph6gVQvSpSucGkrA9JDLo3HD3qUI/Q5cbVRcZb/Rn3oTAJlmL6fy4pdLEIfJHJuBR0eclIlhnJE2bbiTRH4kqSY0OdWUzIE8896UqeRH36LMz7t/lN2xvKmCApQXLCMHvufLCRkMiZB5a/hqs/J7w5DFyQB2PhJE+YvSdq4L0wxV9VChmqa2xFSyHxzZ+DqVJYrvVHnjAe0fyFDmKYRrc1BnBu1CCwTGFhqWSQhYRKnpCEZ1yj8+cBmx0oVxbIny81Ycug0ctWQMVESkzSFEH+eH+7z8xndN+cMVtDkUKaIuWLFtWR3YdLpdHk5GSH2+CiJVAupSmN3yqmLmca+EAytwUJZbpcLuRJ2skTKtnAb2liPEwJ/O94+iYzx6jaVGv8jX9LTICtwR0qo5cvo3uKectKJN9xT1BxPDRrIqIH3KsI8pgBX+CcPRKRv3wE06k49Ti6JDKeVMSKOUoBSLPnyQ+dAblT2pWLKrNiSkuuVh9JT7kH3L7eA9Uy4XtYFvwJc9e+sHXumypVccxznRXOCR+PA7856WFGxjjGDklucDssM0YjuWEbJPV9OajHpxd5QoUMD19pJHviv5waVD1DuVjIk1BQk3uyIgLpQp58eN9kHN51Brc0KYFm3aqieuMSMJn9x6y4GTrEF3liyO7sMTkxvMEUMAVsoaSD6LLCcXI8q/1oXIosjM1bNGS/eASPnH0ZeW0nkBCZG0fuH4Ki9UqmCQLGzDhMIoWkSpwOc4SG2Dx25MunqZO4QoVMKFbQdFOkKg4GiMxKnjDbjqFGCAaPjHytkCeeeyfJasfQEVa03/k28h9Yok7pEl//HrolKuzdyYxc5uWzEbFmAThnuZq1U19YOzikw8FYOMkTPpcLXcu0ayRP0mNvI7lW02CqFJZrvZEnzO707yL32E/58tndMktRbdGwgV2lF/dmJLyPxEGpVk6e5qo59XeSca6iIh1ZwFQmsEgdUVEmR0pziyOYsyVSU2rFooUdf/NlgZInJEtmztJUBi5vMaeoKilXWkf58jpy5iJhooFKuJRGEoMZszy5FNLt78efrwW7Nu6lqyJjexUrqql/k1BxDWC+dr0J8xZcS8lesCAU4cIg1mfPQGUvM4wEDuM2NW1yfVw7t+8wYcNG4MIlDdYkXQUy596cscPYP1Wq6KhaBW7xnwIdoFmFPCGxa/53mnJjYZBpw0JJVUySwrR1DcwbljiyhCXEBwq3IzvYy1+lymJmFGA6fxqRjO9x8ZwiNpLvehTJt94WUPnOdOulKiLXx7+obDuM6RQx+SdYFk5xK8NWsSZsLboguU4zr2XTXca8dwu0PZthYur4PZvVtSQISBSkl0W99wjMxw7CMvAbWMtWS0WeRH3/JqiOTOr7CpIb3vF/9s4DOoqqi+P/mW3ZhN470pSmKPWTIr2oSJEOojQBQVARBBQBAUXBQhGRjiAdEQSk9w7SO4j0GkoCadtmvnPfsCmwSXazu7Oz4d1zOED2zXtv/vdtkvntLapsyzh9FPQHt7GC6lKpijCN7QspU1bEfbfYo/XVgifGKcOhP7Irfm9UK5FqJvrTODzxp7p87vSkgCrwhAS7ceEB9qw6h31rzrOWR9WalmR/sufNENR63rx8C9SCzZUZNi2FYekUHMz4OhZkSGgx3CpyLKrE/I0jIbXwe9ZhKGY9gq4RX8DoiGE5q9beX0PK4n8a70m3nWByEocnweMtDk9c+8pilbDsg9/w+qMZiBKzYEqBX5HpuZwsSkzUJX0YFUWle1HhFB7K3T0RVCBWt28T9Ie2Qs6ULc1h1d7AEyo8/Mef9LApgIoTU9cq+pTSNLgtiz6R8hdF3JCErj+379ADKZDFg4g5d/VgP7tuCvjvPxHnL8i4fl0EtSCn+k8UuZAhA+tAj2PHRVDUAxm1U69XVyns/N9FEXv2AWfPJfiMWoyT6XSUDknzAA8jgctXEx78PdlfamMJNBCwoT8FCygfuN8KB27dAmu7fueuAFEAqlRWg7K+DwAAIABJREFUOpi5Ahpbd+iweUtSkJMpo8xqTdH5I7t9x3W0B71WvKiEV/8HFC4kYfI0kUGlF0pI6NAuaaQKRVDOmK1jmlP9q5LPS7h9V4modAVsyAf588rsPh48LjZONZlq15LRsJYRdyMtcEiK3hT1QoXC165PaF1PEOf1hvJTKY70wcPd+2B7SKkQe2LtCaARwDnwj3sFzelaUwjdo4zSJcGKm7uz1rMCT6jTFoEJ5rvH9Y7o357AE/2edRAPbQelvDxp1N5dNoWSE5Q6IS7AtHjzslK0v1xVWHp+9dQcFMFiGvsRxGv/sQdb8XEtEmoDb2vzIRxFlSLdyZnzHu29RyJL9VpJWhVTRxjD3B/hKPUKpFrN4cjvedcO/Z4NMM4Zw+7PMmxGqhE0qX0vced1FkUzoCUD/aaZ62G1OZ6CJ05oRJDJ2nmwO9N6NYaiF82fNmdzxH49D3K2XOz/9PW4L35lv3e7a2rBk5ChnVgEEhV8F29dhdWHaap0Tl2BGA5P3D0FfNyzroBq8MQptOSQcXrfNexedQ7Hd1xG8ZfzoHqzUni51nNBGY3y4N36sHX7EhQa+dQP568/Qdi1E5iR9Vs8LFY5/lOmkLj7qLWqI/QOC2493wB5zq1nl9pfeQ22zgM9Cvv05gBzeOKNeupeS2k7PPJEXc29Wc3bgrHWOBti3q3NtjA1/y84J6X8SziNo0/ZS5Z0/Yk2tRJ/FA1YLBSZAFbIV4laAEJMriMhqEMY5d6nxZKDJ/fvC8iWQsejM2dF/PmXkCTlgh6QK1cCqoXsRuitM5BerIILKI1TZ4AzZwVQBy0yirDImUNG9uwycuUSkCu7jBw5FYiRnFE0wv37gN2WFAzQ8/Y/hwiaJI1YSEkLKnTdsL7EakQ9aeF3RdaJ6tCRp6MwEo+laBGq/1SokBJdYUjaPIsNpUgKC0UzWBOiGQi2WS0U5QDWjY26slHqy51wzyI8KSqi/Csyqv5PZrVJLl0RsGKlEB9BQ/f4ekOJ7c2V3bqt1NG68B91axPYeaS5qPOZ0yi65pcpIiwWAQ3qJo3+mPmbjnUXo7V7dJOSRJZQRAoVLGd/rsu4dkNgHeicRueEam9Vrqj4O6WCsVR7ZdNmIT4ahe6L3j+0twcRiC+aTnPWq620Nk/OSKMDB0RQS/TEe6nwioRiRZ7Wn1KcLvwn49RpMUk7doqGIYBSurQCVBJDLAJzrCPdbQGv1zHAoE/5HKV0ToOhYKx49V+EfPNB/G1IOfLCMnQaeyB3B56wNu1zfohPf6GJKP3F/kp1SOVfi+88ltr3NvH6f6C0SYIktoZtYWvWNcklpl+HQXd0NwiWWPr/BOHGJdZCnaI/yOwVasHeqqfL1BT97rUwzv2BpUTah09DtoymJPAktb25+zp1WqSUIkep8rD0/c7dy9I8jiIYKfXIUaoCzJ//6BKeULRjyPAukDNmQeyYJcmuZZg3ToFbOfNBzlsYcq4CafpgUb91BYyLfmY1ZCwfj2XrGWd+A/2BLR61LCboQFqar57Fozffg5w9b5p1SulCKtZu/rgpZL0R9gatWZFbV+cvLYvrTx2AceLnDJ44XqrKfp46a+tweJIWRfk1z6ICqsMTEvn84VugysSHt1xEkbK5cO/mIwiCgJ5jGyBvkSxB5YeI1tVdth8+dSAKFWc2h1UwYkbVNWjfNmkxVMPaBfE1BeiGKZTQ9mZHVe+dwxNV5fZqMQ5PvJJP9Yu9hSe22DhEv1cvPtyaHr4pnePBA9cPrdTS+d//Eh6o6CGYogKiowH6RDw1o0+8jQYlHYSAipISkuj/j2FLxoxAhfJyssDFuU5ieELFO6neBXXHogd6qmFRsbyMF8smRDlQVMDK1QKL4CCjiJM8eYDde5ICAIqeCL+bfIRDcvdJtTgIpFC6YuRD5QH53l0lGiE1o7olLzyvpKI8l9eE+w+tIC8QYHn0iPQFcuQAi6Rwx6gGCF1DfomOUv42h8goVEBGzly+rR9FERRXrgu4ekVmrdkJPISFUsqmjDx5BOTJLSNLRh2rW7Juk5TkYZ7SYijigywsTIEmL5X1zf4oImf2XMXXXd6VQG3rf18g4tx5EWazAk7cqaVF0Sh0T+SHV15J+jM2tW475HuKptmzL3UQQS3O69WRUOZxoVurDThyVMS+f5R2906jCJtKFeF2O3WKmqIUn5Onni76XryYhBATpUnJSdK/JnyrQ6g59T0ndxaDAZ446z04XvwfhJuXId69GV8nLiV4Qt259MumwrDzb3b7BF2ohpOj/GtpLpxK6SWUZkKWOM3EsHwGDOsWstQP6+eTkwAS/eHt0P8xnXVMJEBg7TWKFbxObM7IAipaikq1/AZPxMh7MH3VFaSNGq2QCXgYdq6Grfn7CHv7HZfwhHRwFm+lKEKKJnzSqFYg1Qx80gigSQWLw9bxUxaV4Y452yZbuwyGvZKSUqXftwnG2d/CUawsA1+ujKCZ7twxiCf2QzxzkLVbdhpFLlk/GMmu97Xp/jsJ09iPWWc9+xvvsMKx1F3P2sd17RqCLYY/ZwAP78P23gAlosqFUUqY6atu7FwmNjnEDHqv5Rgw0te3wufjCqRLBVSDJxHhMdiz6iyDJjGPrKjW9AXUbFEa2fNlhCwDyybsw5kD1/HF728HldD3+7ZTQura9YX9tbfY3rfv1OHRqr/RKvJ7/JezJvKMGOLynuiHh/AoErbOg1LMY/WXIBye+EtZ38/L4YnvNfXnjF7DE7uE+3t2w1G6gtvbpIfw48cFHDmq1KXwl9HDbc0aFFGQPCwgeBJ+T8T6LXYcPSqyaIknjSJFXiwjIXs2AXv2AxQdYzLJeLupnOThk9qR79qbNPWFYEjJF2SUfAHxNUQI0twNB+7co79lFnURHk6gJHktaA85slEaDtUJUaCRUk+EUnIEFC1CXc4SgEFqBWP9pbk/501c8+TkKQHbd4hJzg/5uU4t37Q8T3wfO3frsH6jwGBJ8WIyjp9QUqK6dpJYlzhvLTV44pyfarlQBFPWLEp7dWp3T/CRjNKHVq0RQXCSjM5CjuzAuX+V+iVkVHfl5ZclVKkIFjGTVqO0o5MnRRZR5Vwv8VwUQZU7l4Ae7+lhDknf8CRkdG+IV87B2n0Y5MxZ2YMkWdygSchStiwIAMXZkn7/oQgQw/xxrPYIWVrrNbnynzMFm15jESbhN2H8bQwbahk4EY7nSrp0Oz30UtcUNo665zgf3A9uhXH615ByF0Dc8FnQ6wS/wRNaW39gM4wzR7O6LXFDp4OKpvrLQr58l8Eu8lWmMmWThSeGuT/AsHstbC26w1av1dM/H+aPh2HHKkg58wOZsgIP7kB8XDSXBjN40fubVKOIxGsXEPJ1T0jmUFi+WxIf2e1ML6K5kmtZHDKsM8Q7iYBJ9txwlKmMEFsM7Hs2sT1bOw1kBWh9afrtK2FcMAG2aq8zeGL+okOKUTqJAR9dY3unn8vtUBF4+uCWzp2tWTfoTh9kkTRUjFg2GJF13mZf3gafiyuQbhVQBZ5M/GgNTu65xqJMarUqjQp1i0JvTBqPHPPQggGNfsek3UnDIrWu/O1tW0FhkdR+OGrYPGzcF4Zde3Toen8gSln2w9r1c9grKuH3Txr9sKfcS6LogTAOTwKhetrW5PAkbboF6ipfwBNvigNTpIrDQQU13evy4ixmyRpO2JTGEzarAAsrcqnUyaCHxSPHKPJDeXCj1q91a8t4pZzyEEOQglILwu8KeBgpYP/BBPUpzaNGdRllSkmgB/SDhwVQh7HERukubVpKyT6A0vxnzwt4oYTsUUcwWoNgUng41RYRQYVHKaohazblwdcTS+/wxKnF+Qsijh0HatZw3UHHE81SGrt4qQ4nTiXAra6dHT6p3UNrugtP3LkX2uOGDWJ8XRW6pshzFGXin7bLBBJPnRFYel2uXEqhXKel95onYsQ91o6cLPanv0CfijvbqlOXrbAxc5LAE0qt0W/+E5QGQ+YoUgq2dwe4HZXgjv9pjPNh39nmlr7mzoOzYdGk+OKvztQL08j3WWcca6dBrKOOv+EJ7dUJchwlysHS7/v42yb9dOeOQDh/EvamnSDldi+aw5VuVKOG6rgQqIj7cQVLNXZV84SupeKtVMSV0nssfb9NMh0V9A0Z2JqlS8UNm5nEl/RhpWHheOjOHmUP/Nb3v2RRE8mZs/OP7bXGsLVLKDzMNPm2N3SXz7lsWWzYuASGP6ZCylUAjtfehKN0JUh5C7OajXmymhG+bAGMiyaxZX2VUuO8B8OC8TBsXwVrm96w12oWX5+FUpwokulJc96j8+uWD0awQsuJTbx5BSEjlOcryyffgwoQO0134zKEW5eQq34jd98OQTvOZnFg/rc7cWrvVTjsEvIVy4b3htWKr78Zfu0hlk86gPdH1/XbPf7y6Tr2HFzlDd+1Eb969h6mDNyAUcuV750pWY+KU1G3/Yto3U85I990XMa64fb6oSEe3I7GoDfn4Ze93aDzIj00tT0E++uqwJN5o3egZssyKFAi+fx5ij6JehCLjNnMQaUpddsx/dgfuvNHsStrG/wZ0hNG2YJvbinfhGJ/XAHZ7DqELtA3yuFJoD3g/vocnrivlRZGBhqe+FMDSjOgribOehpUoJOKvFIqw5P2fAkJNarJoJoSTxq19T18RMThI0CZ0hLq1/UMZPjzHpOb+1mBJ2pqO3mKjsGt9m0omsi91Cd39udLeOJcb+cuHSIfyqj6qucAz509uzMmvcMTSvmg1A976Yqw9hnNJKFuOaaR3VlBVn2LrrC+3h62E4egW78I+lP/sDGsPkSzLrDVbeGOjGkaYxo3AFTIlcxWtyVsLXu4NY9hyzIYFk9mY6k4KUVDUA2W2FFz2dfUgCcUaREyvDOE6Eesvh4gQ3fuMATKHXxssjkM1t6j0pyKot+7HsbfxrIHd3qATwmeCFEPYR7QggGQ2Amrk+io3/YXjAsnsgd8etB3ZVRXheqrkFk7fgp7VdcP/vGFYQdNglT4+SRTUStgShF7smWx8PABQoa+xwqVU6clR9HS8dclLhirO/UPjFNHsHH2V2o8rlnofUc86gSk++90fKFk00/9oTt3FJY+37qMRjWN7AYCIAQOdRdPsyYWccNmJGlmQdFblA5EsI6gnSt7FmqerJl1GP8euYWeYxowOLDo+92sdMSH45Tzc3TbZexf+69m4Qk9K9MZfNI8gSd9a8xE5pxhGPFHG9y/+QjfvPsnipXLzeGJW9/NlUGqwBMP9hN0Q89eisOuJZfx9gGF6P5cfAGalDqFQitHJvnhr8Ub4/BEi15xvScOT4LHV7TT9AxPnJ44/68CUSi1gYxSX6g7Sa6cQOECIooVFRESag0ux6WyWw5PfO9OirI496/AOv340vwBT3y5v7TOld7hibPAqbVtH9hrNomXyVkHgr4gFywG4eoF9hqDJq81hqNhmzQXuHbXF9SdxfRdH5b28mS0RGpzUPoORVpQ3QkySq2gFAsyNeAJW+fwThinJu0aRJ0dHWWrgIr0UhQGWVo7u1Aqk37vBljbfAh7raYpwhNax5meRUVcnUVL6etOGGDt/uVj0JPM70V/TIFh41JFTxd1A6n2jHHqSEh5C7nsHEeAwlXLYupQRJ2KqD4K1UlJbE922yFoYZz0OUt9oQgYSy/v64aY+zZmwNCZTkRFiA2bl7E6MrYGrZPshwq7hwxsw75GH9aafvqU+dIJsJjfHxcnJjgW99Vsl9ErNO5ZgCe/jdiGrLnC0KRnRaYZZT08vB+LPM9lYdCEPuy32ySYMxjZ6/0mN0a+YlnZv3cuP4N1vx2Jj1jpOqpO/LiPa81Gi75VcGjzRVD0Ss2WpVH/nZfYdRF3ojHt8014cCcahUvlQFy0Df97owSLPJElGQvH7sbxXVfYvyvWL4YWH1Vh11FkDM1L5SxmDduCW5ci8ErtIug0vBZ7fdP849gw7xjCMplQvm5R1tHWnciTT2rPRpEXc+PNruUZSLp06g5bi0eepPZdPOF1VeAJOWX5LwdQslJ+lHm1AFt9x7LTuHvjETvAwRwa1GuAlYWzt304BhWj1zD6DFEH/cGtqhTnct/VT4/k8MQb9dS9lsMTdfX2drVnAZ44NaKil5kygtWucJo3rYq91d6f13N44k91fTs3hyeu9dRywVhK0zB/pNSOi/tm/lOtdZ3pO/Q6pc/YajWBo16rJJ+w+/YUPT0btY+VwzKzVG1PTXfpLIyTvoCsNyBu9IL4y9WCJ7Qg1T4R7t1WuqyUrRzfppegjmH2GOgPbWP7cvWgntr9hgxqCypQS3VVKMUlpcgTmstZdNfasA3szbqx6cULJxDy/SesEG/cd4tTWxKGLX+C0lbIpEIllLbTj024c53tx9bqA9jquK6n+GTLYvKR6bsPWUSMZcRvkLLkSLIHV62KWVQPFeWNikRc/58geVFElqKrKOpFypqTvQfICEgRmKKIIQJKiU2/fzOMs0bDmY5FRW1No3pAsFtZgWPycciwTqwtM6UtUfpScuYPeEIt7CMi1Y8qzZNbQOZMT9/pwY3/Yc7IbQwcvPRaYQZNEtu2padw7uDNpyJPHj2Iw6A3fseo5e1YisukT9aybrGNOr3MLu9X9zf8783nWSrM/VtR+PLtRRi3pRMMJh3mjtrO/m47oBpuXHiAUR3+wHtDazJ4cnjzRaycepABEmucnV3X+8eGrMwF2ZfNFyIscwja9K/KvkaARRAFtsbw1kswfHErZM2dAbOGbsF/x2+7BU8IyLzdpwruXI3EhWO3UaN5SRzZeonDk1S/2yQMUAWeLP5xD07suoJuX9dFoZLKNyLquEMHmFoUE60LVvtosBWFCstoUv0BcozuwGix02LH/gE5g4t3r0ZulsMTjTjCjW1weOKGSBoa8izBE1eyc3iiocOYylYSF4wNnl2nvlMOT1xrpGV4QtEZVJuDUlvivvj1qRugB/zQ8Z9CevFVxL3WFPRJerCZcO8WdFfOJYmoUBOepKaXE2jQOFv1N9mHgO4YQSXqIJS4/XBq8ITqlpjG9Wd1/+I+V9KanOk4tjc6wPZWJ3eWZh9WUgHe5Cx27NJkAduTLYuddVBsTTrB9nqHp8/g45onN+/HJnnNmZpF4IQASlrNGR2UOIqF6tKEjOrBiufGjZidZGpnlIytaWfYGrVnrzmBEoEkqcRLSqvq50qy4sYpmT/gyZxFDmzf7duoQne07dhGh5pVXRfWPrX3GgiS0N85C2TCu1/WxHNlcrJpk4Mn9FpslDU+0oTSf+5ef4SOQygFToEnH096M/4Z99N6czD4t+bIkT8jhrZYhI5DaqLEK3nY2O86L0etVmWUyBMZsMbaYAo1sNfGf/g3Xm38PCo3UmphUkrNS9ULoXH3pM0DDqy7gB1/nka/XxUYRvdCtVzciTwheDLyz7b4/v2/kCFLCBq/XwFbFp/g8MSdg/V4jCrwpH+Dufh0yltPtSG+eTECP/RYie/Xq9ui1wN9Uh3679U4hIYqVNXZXo/+7ShSGpbPxqd6fSAHcHgSSPU9W5vDE8/0CvRoDk/0LDH3UYyLQiiBdo4X6/PIEy/EU/lSDk9cC65leBLfgSWFB+eUWhWrfMR8tpyW4AndFKWs0EM5+102b2EgQ2blXkMzQMqYFchbCPYajeM717Dff7evAhU6tVeqDWuXz9nw1OAJjYlPURm7FPQkaf5M6bxDkTlPRn2kJjhFmSD6IaieihAVAUQ9BLVRs7/aMNlL41sWFy0DR403WM0WKVsuWIbPSnJ/zglcRZ44X3NG3iRXmyS1/TMd/5oNw5p5sDVqB1vTLvGXhH5Qn/07dtxfSaJrqEAvFep9suuTs06KcwKCkQQlUzJ/wJN1myUcO6k+PGlQR4dyZVLuOkiRHn/POIw9q8/h29UdWC2R5OCJ5JCxYvIBnN5/nY17eC8WparkZ+CFjODJoNnNkaug8oE5Pfd+NqMp+z+BFIIc+YsrdT8n9F2DKo2KM3hC8ywdtxe3Lj2AqBNZak67z6rFF5P9ttNyFt1CgQaJbeuSkzhz4AZ6jlHOxcUTdzBjyGa34cm4rZ3w0werULZaIRQokZ3DE3fenInGqAJPer86HWPWdkRY5qSFlIji9a8/B5P2KOF6wWhUMDb+myr1UKc2bRQm+HZ32Oo/3X5NS/fI4YmWvJHyXjg8CR5f0U45POHwJFhOLI88CRZPKftMzzVP6MFZeBSBuMG/sBQMV8bhiTrnVfz3OEy/fAkhNtrlgpRWYm/ZA/byysMj1XOhDjqJa7m4A0+MEz+H/tQBWLt9AeHuLZbKY3+5Gqw9hqtyo4lbFlPUDJ0/6/tDYS9fw+X6KcETZ7FjqdDziBusdOJxZYIlBrLJdSMJ0pxaDz9Zdybkmw9YLRPLgHFwFC3DphVvX0XI8C7x3Y0Sr0VtnU0jurFitpSyRKlLqZk/4Elqa6r9OsGRCvWKsogLMnoOpUiMn7Z0QmhGY7LwZN/f57F6xiEMmtUMoZlM+OvXfxARHu0WPKHUG4IsJcrnZWtS2k79Di8xQEIZGARxuoyoA1EnsGiQGs1LJYEnb3WvgDJVk3bBovosVIPFGXlChW6X/LTHI3hCnYdoTUpT4pEnnp1EVeDJd11WoGzVgnija/n4KsGUt7V6+iGc3HsNA2c29WzXGhqdGJ6wb2Z3b7KaJ0SutW4cnmjdQwn74/AkeHxFO+XwhMOTYDmxHJ4Ei6eUfaZXeEJdQkxj+rKir3HfLUrWKRyeqHteWTTHowgIDyMgPHoA4cEd6Df+ASH6IdsIdcSxte0D0w/92NdiR82BnF15SHQHnhg2/cFaUVPHG9Yy+f4dWPp+B0ep8qrdKNU4oVon7H6KlYUlhbSblOAJXW8e0hGUmmXp+RUc5ao+dQ/0mmn8QFi7K+lpT5p5yDusJk3c8FmQcis1IsmcUVnOYrz0Nf3WFTAu+jlZ2KTftxH65dNhGT4zWViTeP1nAZ781Gs1cuTLyGqIGIw6bF54AhTFQWksZPvWnMf6ucfw+ZzmILggSTKDKlSc9cTuq/jo5zcQFREHmidP4SzxtVFSijyZPXwrq3nSYXANVrJiXO/VeHfIawyQUNvioi/mZtElFD1CUSnNelViBWfJKPLEFTyhlKGv2izBsEVU8yQMUwdtxPV/73sET5y+P73vOocnHn63UQWe0IGY+NEamMwG5CqUmYXm3bocCZvFjj7jX48vjOPh3jUx/El4oolNubkJDk/cFEoDwzg80YATPNgChyccnnhwXAI6lMOTgMrv8eLpFZ4YVsyCYe18VtCSClsmZxyeeHxkfH4BRaPoV81hHWASm5wtF2K/nhf/JXfgiXjzMkJGJESfu6rr4fMbeGJCZ8ti+nLckCmQ8hdNdsnU4AkBC+Ps7+DI9xwsX05LMg/VLiFwQtEt9gq1WLRNYiNdzf2asQ5SsRNdt2+mDk0U3UNmnPIV9Ed2wtquL+yvKYWWnzRaM6X7STz+WYAnkXdjWG2Q84dvslsv+EIOtPm0anxHHeq+Q8+r187fR0iYgb1WsUExll7z8ydr2TXUrYfgBnXQad67Ml5rUSrFtJ17N6MwbfBG3L3+EC9UzA9ZlvFi9UKstgmr/zliK4uEKVI2N3IVysQCC6jzDRWITQ6e0D7Wzj6CjfOPszosdduVxfo5R/HNSqXuTUpGkTaUtuM0V/CEitI6LSTUkGR8avM/C6+rAk/YN6RoGw6s+xe3r0QyXXMVzIxKDYvFF98JVrE5PNGe53JkMuFhrA1Wm/p5lv5Sg8MTfynrn3k5POHwxD8ny/ezcnjie039OWN6hSchI7tDvHER1t5fw162crIScnjiz9Pl2dzinWswLPmVFSQls1dtBGvHT+MncQee0GBnrRD6t61lT9jqtvBsI16OpvvQ7dsEOVd+2KvUS3G21OAJu5+vukC8dRXWrp/DXrE2m093/hiMvwyBEJeQ6h83cg6kHEqUjnOM6cdP4Sj8PCyDkqb9OFt1J34tpF9TiLExrIgsQSdv7VmAJ95qxK/nCpACqsGT9Co3hyfa8yyHJ9rzSXI7yprRiDiLA7FWR/Bs2o2dcnjC4Ykbx0QTQzg80YQb3N5EeoQnlKph/qIDZGMIYsevTFELDk/cPiqqDdSfPAD9okmwv/Uu7JXqxK/rLjxxdoyhiIu4bxdBDvO8DbRaN+sOPKF2z8ZpoyDlKoC4r2ZBf2gHjNNGsC06ylZhBV+pQ5C9ZhNY2/aJ37ozDSdxdInzRaqTYv5YKXEQM3kDSzOidCMqERCXKNrHGx04PPFGPX7ts6RAQOEJVS+mwjlDF7ZURfN1vx3Fht+PwmGXUKF+MbQfWJ0Vy0nNqC/4yin/wG6TWH/vjl+8htyFlerjHJ6kpp76r3N4or7maV2RwxPXytnsEsIjE9qep1XfQF3HWxUHSnnP1+XwxHPNAnlFeoQnqdVuSKw3hyeBPH0pr/1kIVR34QnVu9FtXwU5Zz5Qi2ItmzvwhPZPrYUpZcbx0qugFtxklFpDKTYU6RIyrDP7WuI2yobff4Rh1xrYWveCrXbzp2SgVtDUEppSi3TH98OwYgZcgZa06sfhSVqV49c9awqoAk8oV+zPSftx5XQ4bIk+YabcMoNJj9GrUs/R8tYxVE141rAtGDC9CcIymTDx47UoX6cI6rQtm+LUEeExGN5qMb74/W3WD3zTguP4Z8N/8UVuOTzx1jO+v57DE99r6q8ZOTzh8MRfZ8sf8/JWxf5Q1T9z8lbFrnXVYqti04SB0J0+BOt7A1jh0JSMwxP/vF/8Mau78MQfa/trTnfhCaUymSYNid/Gkx04jVOGQ39kF2yN2sPWVAEppm97Q3f5HCz9foCjxEtP3YJx6kjoD2+H9b3PoNu7HrqzR57qyuPNfXN44o16/NpnSQFV4MmkfutgibGhXM3CWDXtEJp+UJFVBaZCslQUJ1se/4foLRy7CxmzmvGWJsL4AAAgAElEQVRmN6WC97Htl7FuzlEGU1Iygi7zv92B4Utas2G07x97rsIPG99l/+fwRHtvFw5PtOeT5HbE4QmHJ8FzWgEOT4LHWxyeBAc8ER+EwzS6FyuimfhT+OROGocnwfMefJbhCYMhj7v4uGp9rPvvFExjP4IcmgFx38xj3XDMfd6EYLci9sflkM1hTznasHYBDCtmsqLKhu2r2OuxY/+AnCGTTw4Fhyc+kZFP8gwooAo8+ajmLHzzV3uEZTZhcOP58ZEmhzdfxOn919F+UHW/Sz2hz9+o2uQFVKyvtAa7dSmC9dP+foMCQZIz6gE+tMUifPhTIxQunZNVQb59ORJdRipFoDg88bvrPF6AwxOPJQvYBRyecHgSsMOXhoU5PEmDaAG6hMOT4IAnzo4htnotYWvRI9XTwuFJqhJpZsCzDk+oSCx0BjiKlnLpE2rNTSlLtlYfwFGmMkKGd4aUNSfivpnvcrz+xH4YJ33BaqYIllhIBYsj7vPJHvt7334R2bIDuXPJyJRRjr+ewxOPpeQXPKMKqAJPqC0S9dDOmDUEXzRdgOGLW7Oe12SJYYo/fUCgpP475XB81xVcO3cP74+ux9JxJu7skuqyB9ZdwMyhm1lnIGq33H/qW8ieLyO77lGsPdXrtTpArxNg0InprlhnqEkHi02CQ0r4oaBVH7i7LyrNQ62loy3pq7Cq2aiD3SHB5kg/viKfUnck8ldazW6XEBvE3aJMehEQwN6H6cmolktUrB3p6bQa9CLo+0tcOvNVhhA9Yix2pKMfA+ytZDaI0NP7K40WZ3Vo5/vtsX1w/DAQyJwN+jG/Qw4JTfWu6GcG1YSypyPHUldQs0mP6Ljg/X3SlePoZ6Ajnf18pyqJGcx6n/zuLx/cCWnCECBLdohtP4D06ygI5V6F2G+06/fBg7twfJxQI1J4vS3Etj1Tfc8kHrB6nYyNWxK+Yg4B8uYB8uUDOrUxeDQXH8wVeFYVUAWe/PrZBjy6H4sPxzVidUdCQo2sL/aNCw+watpBjFn7jt/1n9B3Dao0Kg6dXsSDO9EoVaUAxvValWrkCe2Ren5/MrkxchXMhH82XMDKKQcxbFErVmz2UYzN73v31wJ6nQiDXkBsOnsgDzXpYbE74EhHD+SiqDyMU756erIQkw52u8wASnoyeiD1Cp44pKB+XxoN9HAnwGpLX7Avg9mAqNjg/Z7v6j3G4IkogB6q05OFmfWIiXNAltMT6gIIHngNT+wa+H5rtcIxuCNw7w50vYYBlWu5dfzMpsfwJJ39fCe/pkt4IskMdgWj3b0nIPKRjGLPJdq9AGQISfvPgegYYMMWGfVqCcgQBjgGdgRuXwNy5QPu3IDQuD3Elu8nK1ds96YwWh+y18Pf+wF5aiulCNyxC5eAn6coI+me7j6QERmZ0DRj+ngOT9zRkY/hCqgCT6Ii4vDHhH1o82lVBi4mfbIW4dcewhiixzuf10CVN0r43ROLf9gDo1mPZr0qsbUommT7slP4dMpbKa69eeEJ/HvkFrp/m9D7vdf/pmPU8rasVgtP2/G76zxegKfteCxZwC7gaTuupefddgJ2JFNcmKftaNMvrnbF03Zc+0orBWOpdgPVcHA8Xw6WT753+2DxtB23pQr4wGBN27HagC3bBOzarUSPvlbdgXp1FAjrbsHY5MRfvkLEoaMUPQZUe9WBevIqmJeMix9u7TYE9go1n7r8QYSARUtEND7RH89bD7HX++fdguJFJdSpJaNAgZQhcVycgJ8ni3j4SMCr/5PwegMFaMVZBNy4ISDiIdC4jingZ4ZvgCsQDAqoAk9cCfHoQRxCMxpZJIgaduHobUwdvBEDpjVBaCYTxn+4GtWblUSN5gm5iAR4bly4jz7jX4/f0tl/bmDm0C0Y8vvbyJjNjJN7rmHml5sxdl1HFnnC4Yka3vNsDQ5PPNMrkKM5POHwJJDnz9O1OTzxVLHAjefwRLvwRLx9jdV3YA9vw2dCyl3Q7YPC4YnbUgV8YDDCkyNHRazfKCAqOiEig4TMn19G65YSsmWRkSerGTfvx8bre+++gMNHaIyAUi8kH2Vz5ZqA6TOTpvNmMlkw6FYbGOMik30/0J5W/S2CoM7bll9R9f4i3MtbAePNYxETq+yzRHEJdWvLyJfXNURZsETE6dMi8uSW0auH6yhDXvMk4G8ZvoEgUSBg8CQQ+mycdxxrZx+G3Sah6lsvoFW/VxlFdtrv3+xg9VAGzW6WZHsbfj+G7X+cAkX/EvBp/WlVFH85DxvD4UkgPJnymhyeaM8nye2IwxMOT4LntPJuO8HkKw5PtAtPTD/1h+7cUdgatYOtaep15xLfCYcnwfMuVBOe7NytgyDIMBgAowEwGJW/s2eTkS1b6ql7128IWLVGxPXrykNBoYIymjSWEBsLLP5DxKNHApu7WRMHGtQIwaVbcTh+QsChIwKuXVOuodd793Aku97EX0SE3xXxekMJ2bIB6zcJCL8joP6juWgYNROSzogz/dckcfA/h4BjJ5QPmV8qK6FZjTswPbgOOWsOxGXOj917ddi1F7DEKXugaJY6tWUY9AnTHDoiYvlfSrRLrx4ScmR3DXieBXiy7+/z7APxxJazQCaWTeCJXT17D1MGbvD4Ok/WoLGUpbF80gG8P7qup5cmGU+1R6ncRNbcT3dxSjzwwe1oDHpzHn7Z20214AZ3buzI1ktYOm6v3/V2Zy80xu/wRJZkdlDf7lMlVae5u2ktjePwREveUPbC4Yn2fJLcjjg8ca0MT9vR5hnmkSfa9IurXXF44tpXgU7b0e/fDOOs0ayriOWrWZANnqUKcHgSPO9BteDJnytEHD7qOoqdgEHbVhKeL5F8RMi+AyJWr1GuDzXLaNhAxivlEsbHxgpYtlzA2fPKmIL5BVy97hrI5Mwlo2dXBwMpiY3gDkW0UIeb3j0TIj8oqmT3hocoHr4ZtwxF8K/xlaccbDLJaNpYQtkyrteklJzNWwXs3a/sL0tmGc2ayChaRML9+wIm/Up1gsDmqFA+eR2eFXiyY/kZ1vjDG/MWntCH8Yk/vE9uL0e3Xcb+tf+mO3ji7v07dYl5aMG9m1Eo+EJ2b9zms2v9D09koGelqawobOYcqVdS99mdqTQRhycqCe3BMhyeeCBWgIdyeMLhSYCPoEfLc3jikVwBHczhifbgiXj3Jkzf9YEQFQlLz6/gKFfV4zPC4YnHkgXsAjXgya49OqzbIMBslpErZ9JbtdmAGzeViIymb0mo8MrT4ICupTnIKleSUK+2jJAQ15Bi914Ra9cnQJqMGRXIUqE8YDQCk6coNUVeLCuh1dsJa1FR1nE/U+choHsXh8v6JARwIiJk2GxUaB2wWsD+puiZN15P2lI4OYdeviqAQBIBE7Lyr0i4eUPAzdtKOlG7NikX7uXwBFgz8zD2rD7H9HuhYj5Wq1P/uHPipvnHsWHeMYRlMqF83aLYs+pcfCTE7cuRmPv1dkTejUFIqAGt+72KEuXzsnnOHbyJv349gNc7v4J53+5kDVTaDazGMiAowGDh2N2sEyz9u2L9YmjxURV2HUGTeaN3sGwJ6vZK1m9yY+QrlpX9+/jOK/jz5/2wWR3IkS8j3v2yZnyQAq05d9Q2CKKAyg2LY+P84z6JPElJn53Lz2Ddb0fgsEvIVywbuo6qE7/vVVMPQpJkGIw6bFp4AgRDRi5rwzrXTu6/HoVL5cSFY7dAkS95i2RFt6/rsL3HRlnx5duLIDkkhGY0JYk82bTgOK6dvw+71YG71x+yJiG9fmiILDkV1kA1SylzhEp11G5dBismH2AlN3xhfocntElqR9zt67ooVi63L/asqTk4PNGUO9hmODzRnk+S2xGHJ66V4ZEn2jzDHJ5o0y+udsXhiWtfBTLyxDTmI+gunoK9TCVYP/wmTYeJw5M0yRaQi/wNTygSZN4CBWYkByW27dRh02YFJtSs4WB1QZy2cLGIU2dEBijatJZQoljqXYFu3RFw6B8DSjxvZ3VGEhuBmmkzFUjS+A0JlSsqr9Meaa8EM5q9lfoa3jprw2YBO3Ym1FYhyPNhT4kBppTMH/BEunEF0oO73t6Sx9fr8hWCkDXHU9dR2k5ykSfHtl/G0vF7MWhWM4SEGVlaDj23NuhYDvdvRWF46yUYvphSXzJg1tAt+O/47fiH+a/fWYZqTV9ArVZlcPlUOH7+ZC2++as9DCYdIsJjMLzVYjYXAQ4KJCBQQnDg8OaLWDn1IL74/W1Y4+wMFPT+sSGKlM3F9r5t6SkGX55M23l4LxZDWyxiTU8oGoPKUpw5cJ11tSX7svlClvHxSp0i2LHsNKgsxberO6SaAZJS2k5K+lAd00Fv/I5Ry9shS64w1hiGyls06vQy2w+BoL9+/YcBqbYDqsUDKYq+oY68keHR7F5IkxFtl6LdwOooWSlfvP9cRfpsWXSSAZGhC1uyBi5zR21n2jbpWZFpThqQv+i1KYM24uLx2/hujW+6+6oCT0i09XOPovvoeshVKLPHbwItX8Dhifa8w+GJ9nyS3I44PHGtDIcn2jzDHJ5o0y+udsXhiWtfBQqeGNYuhGHFDMghZliGz4KUOW3h1xyeBM970J/w5E64gKnTdUoR1aYSXk6UZvOkQsdPCljyhwITypeT0KC+jLkLlPomGcJkvNdRYuk07lhq3XZOnBSw+PFaPd934OFDAfMXiTCFyPi0r5RsVIs7a3sy5vYdumcRpFPXTg4ULpT6/fkDnsRMHQPrxr882bpPxoZ2HwBjvaYewRN6+KYH7Te7Ke2fT+29hlXTDuKzGU1Zh9Ydf55Gv18bx782/9udDJ7Qg/rnb83Hz7u6skYiZN91WYEmPSqiVJX8DIr0qT6TwYHnKyjRKE6j9BVrrA2mUCXPa/yHf+PVxs+jcqPi7P/JwRN6rt614gw+mazsh9aguiYTdnRBdGQcC1pw7ociM3pXneE1PElJH9oDRYk4I2TWzDqMu9cfoeOQ19j+KEpm2uCNGLv+XZjMiQryQIEnxV7KjfrvvMTGErR6sVohVG3yQrxOycGTU3uvovdPCjDauvgkLp68g85f1QbVSNk47xj6T2vCXju5+yrmjNwWXPBk65KTOLTpIs4duok8z2VB5uzmJIfH6XyfvGNUnoTDE5UFd2M5Dk/cEEkjQzg8ce0IDk80ckCf2AaHJ9r0i6tdcXji2leBgCfi9f8QMqqH8kv++0NgL/90K1Z3TxaHJ+4qFfhx/oIn1Ann12kiAxP/qyzhjUapR3NcuiRi3kIBFmtCl4icOWW8946ETBlTBwtONVODJzTu77Uiqz9C80oyEBUloFkTCeVfTn2fvvbavxdEFHcjoobW9Qc8saxcANvB3b6+rVTnM73VFoYK1Z4a56pgbOn/FcBHP7+BXz5dh3+P3ILJrIAMWZZZis6XC1qCnmPPHLiBnmPqs9cunriDGUM2M3hCD/Zfd1yGrLkSirESzKAIi0oNi8FmceDDajPw05ZOrOlIYqMIEiqEeuvSA4g6EbcuRaDdZ9VQ5Y0SbFhy8IRSiJb/cgAZsoTETxcXbcXQha1Af499/y/8uOm9+Ndo/ZHL2noVeZKSPpJDZlEgp/dfZ7Vc6L4IHFGkDRnBi2UT9zEtnzSCJ2WrFmQdcMmmDd7ErnX+n76WHDyh6B9KD3JqRf6j/+9acRbHdlzGB983YK9RM5iJH60JLnjy/ft/IW/RrMiY1eyyeq+T8qX6btDgAA5PtOcUDk+055PkdsThiWtlODzR5hnm8ESbfnG1Kw5PXPsqEPCE2hJTe2J7lbqwdhrk1SHi8MQr+VS92B/wxG4Hps/W4cYNgRVE7dTRfSBBnW1+m6fUJXnuOQkdWsssIsQTcwee0HwzZutw+YoCagoUkFlakdbNH/BEa/ecUtoOpbZQ7RBnqknivVOkB9X0cEaeUCHXJT/tYfCE6pwMabaQRX24KgLrhCcUCUJpPImNoiEItHQZUYdFrdDzco3mpVKFJxQJs2fVWfSd+MZTEj8ZCUMRIRSV4m3aTkr6kK6rZxxiKU9UY4RSdCLCo5PAE0pPerKbLW3eH/Dk4Mb/GHhy+osiX37/entwwROtvXl8uR8OT3yppm/m4vDENzqqMQuHJxyeqHHOfLUGhye+UtL/83B4og14Ylg6BYZNS5XuOl9Oh2z2rnEAhyf+f+/4agV34QkVVF23UUS+vGBAJF/ep4HGzVsCTp0CTp0VER4uIGtmGR/08DwNhqJAdu8FGtTzDJo4NXEXnsTECPhlqhIdQ9113E0L8pX2aZnnWYcnJ/dcw5Ifd7M0HXNGE3YuPw1BEFgEBKWgfNVmSXzR1amDNuL6v/fja55813k5Xm38Al5rUYpFXSz+cTc6DK7B0lhSgicUzVH0xdwM2FA0y4S+a9CsVyXUbFmauXDfmvNYP/cYPp/TnM1DRVcpeiUqIg7DWi5maTsFSmRj11IB2/aDqoNSgb5oMh/NP6zCIl/Wzj7CokKoBos3rYpT0ociYU7svsoieGhvP/VajTyFs8TXaqHIEzXhCflrRLulrCgtBW7MGrYF5w7e4PAkLd8Y/HENhyf+UNW7OTk88U4/Na/m8ITDEzXPm7drcXjirYLqXc/hSeDhie6/kzCN/ZhtxDJgAhxFS3l9ADg88VpC1SZwB55cuSawgqrUDthp1O2mSGEZhQtTyouMEydFREQmvJ45s4x3O8jImcP9qBNf3bS78ITWu3VbwImTQL06aQM1vtqzu/M86/CEdKL6nDv+PANLjI1BCUo7oQKoZAQhqGsNAZG67cpi/Zyj+GZle/Za+LWHLLIh/PojyvdBw/dejgcgKcGT84dvYc6IrSz9pkjZ3MhVKBNWTz/EusZQ0VjqSkPpJtRVJiTMwLr/VGxQjK1JNVn+GL8X0Q8tCMscgrb9q8Z3+KHXKFLEYXOgbrsX2b4HzmqG7HkzpHgcnAVjqXBr/Psx1IBxWzux/yanDwEjKpJLRulLBH+mfb4JzXtXZkAprfCE7oHql1C3nZhH1vg0pWGLWuGf9RdY0V5XaTu0D9KR6tRkyRnGivmumnYI3/3dwd23Q4rjVCkYSxVxkzMSpG77F31yM4GYhMOTQKie8pocnmjPJ8ntiMMT18rwtB1tnmEOT7TpF1e74vDEta/UStsRLLEwjegG8f4dWBu2gb1ZN58cHg5PfCKjzyehmiKRD4HoGCA6WmZ1PiwWEdmyyKhcRUKWzE8DhENHRSxfoXTLoUiSsIzArVsCKDXnScuQQUbZ0jLKlpVRqEDgYIQn8MTnIvt5wmcBnvhZQj69RhW4dDIcs7/ayrrv+MJUgScj2y1NslcKKaJcKOoFTWTt40lv+uJeAjIHhycBkT3FRTk80Z5PODzxzCccnniml1qjOTxRS2nv1+HwJLDwxLBoEgxbl0MqUBRxX0zx3qGPZ+DwxGdS+mSi06dFrN8M3LunQJDkrEwpCdWrycifTwEfa9aL2LNXuaZ0SQktmkswKHU6QS1/r16jP4BeD7xSTnarW4xPbiiVSTg8UUNlvgZXwHsFvu++ErValmaROn9M2IeoB3F4b1jai5Un3pEq8MSVBNTjevOiEwygUA/tYDUOT7TnOQ5PtOeT5HbEI09cK8PhiTbPMIcn2vSLq11xeOLaV2pEnhhnfwf9vo2QzKGwDpwEKXcBnx2cZx2exMUJqrW7TclpFGmydqPACreSUeHVokVkZMwAhJoVQBJi1OHiZRlnzyekABQsIMNuA27eVr5Wv46MGtW1X0zVqQWHJz57K/OJuAJ+VYC6Iy0csxM2q4MVAqYWxs4ULG8XDhg8cW58eKvFGL6ktbf3EbDrOTwJmPTJLszhifZ8wuGJZz7h8MQzvdQazeGJWkp7vw6HJ4GBJ6bJQ6E7tgdyWEZYPv0JUt7C3jsz0QzPOjyhLi5UE+SNRjKyZlE/feVOuIA16wRc+E+JGqHIkCqVHXitGmB+DE2c7nLWPLl4VcLWbQJOnk6ITjEZZbRuKaNEcfXrlnhzIDk88UY9fi1XIH0oEFB4Qu2dRrRdih82vhu0anJ4oj3XcXiiPZ9weOKZTzg88UwvtUZzeKKW0t6vw+GJuvBEsFlgnDQEurNHIGfIDMuAcZBy+S7ixHk3zzI8oToiY35MaHVa9X8SateSQSBCDfv3gogFi0XYbIBOB/yvsgM1qidEmjy5hycLxj6IELB7j4D/LgJtWyMgBV+91YnDE28V5NdzBYJfAVXgCeUdPWl2q4O1eapQryg6Da8VtEpyeKI913F4oj2fcHjimU84PPFML7VGc3iiltLer8PhiXrwRIiNgXHiIOgunoaUOTssA36CnD2v9050McOzDE/27Rexem3S2iKUIlO3joxKFfwbwXHwkIgVq5S1Xy4noUFdGVTENSVzp9uOXw6JHyfl8MSP4vKpuQJBooAq8ITaBT1pxhA9chfOgherFUTilkhBolv8Njk80Z7HODzRnk84PPHMJxyeeKaXWqM5PFFLae/X4fBEPXgSMro3xCvnIGfPg7h+P0DOlst7ByYzw7MMT6bP1IFa+7Zp6UCOHMDylSKuX1dqh1Db3g7tZGTL6vsolHUbBOzao0S81K0to2YN92qUcHjit7eBXybm3Xb8IiufNB0qoAo8SYe6cXiiYadyeKJh5zyxNV4w1rWvODzR5hnm8ESbfnG1Kw5P1IEnwr3bMA95R0nV+eJXSFly+PWQpFd4EhVpREgGS7LaPXwo4PtxOhj0wODP7KzWCBlFhKzdQG2BBdbJpkc398CGu05atESMr1XS7C0J5V9xP8KFwxN3VdbGOA5PtOEHvgvtK6AqPKHOOjq9EvZnjbODok+C3XjkifY8yOGJ9nyS3I44POHwJHhOK8DhSfB4i8MTdeAJddWh7jr2l6vB2mO43w9IeoQne/bpWBHWjz50IHs215Eje/aJWLNORNnSVGg1KSCJjBQwcbIIq1XwWfeaqGgBy/8ScO688jt7u1YSSpVyH5zQNRye+P3t4NMFODzxqZx8snSsgCrwJOJONCYPWI86bcuiyuslmJyUynN85xV88H0DZM4RGrQSc3iiPddxeKI9n3B44plPeOSJZ3qpNZrDE7WU9n4dDk/UgSfGuT9Av3stbK0/gK322947LpUZ0hs8WbNexJ69CqB4pZyE5k1dA4qpM3S4dl1A21YSSruAGEeOili2Qpmnd08HcudKW/pOTIyAHbuAvft1cDgAo1HGO21lPPecZ+CEwxO/vxV8vgCHJz6XlE+YThVQBZ5M7r8eVGSp7WfVkSWnAkru34rCou93s0iU7t/WC1p5OTzRnus4PNGeTzg88cwnHJ54ppdaozk8UUtp79fh8EQdeBIytBPE8OuI+3wypILFvXfcMwRPlvyhw/GTSs0Sp/Xr60CWJ1oQR0QI+HGCDgYDMHhAQsrOk1LNXyzizBkROXPJ6NPTdfrOfxdF3LoNhIUCGTIAYWEyMoQpLYd37QZ279OxbjpkZUpJqFM77V1xeOSJ398OPl2AwxOfysknS8cKqAJPPqo5CyOXtUWm7OYkUj66H4svmi7AhB1dglZiDk+05zoOT7TnEw5PPPMJhyee6aXWaA5P1FLa+3U4PPE/PBEj7yFkUFvIJjNix/3lvdPcmCE9RJ4QnJi/SMSF/0RWw6RTRwnnz+uwdaeMihUkNHkzaZQHFWuloq1ly8ho3SL5miaxsQIm/CIiOlpA9WoO1hHHaVYbWNoP1UhJzcq9JOG16mmHJs75OTxJTWltvc7hibb8wXejXQVUgSd9X5uFr5a0RtbcYUmUiAiPwbCWizB+W2ftKpTKzjg80Z7rODzRnk84PPHMJxyeeKaXWqM5PFFLae/X4fDE//BEf3ArjNO/hr1sZVh7f+2909yYQYvw5MZNAecviKhZPfVirQQ4fvtdBF1DKTEETp4rBIiSCYO+sjMFBnziQMaMCeDj1+k63LghoF1rCaVKppw+Q/uYO08BJO93dqBgQZlBmuUrBVBtlJSsYnkJNarLyPpE5IsbbnE5hMOTtCoXmOs4PAmM7nzV4FNAFXgyddBGULHYlh//DznyZ2IqhV+NxOIf98Bg0qHHd/WDT7nHO+bwRHuu4/BEez7h8MQzn3B44pleao3m8EQtpb1fh8MT/8MT44IJ0G9fCVvz92Fr0Np7p7kxg9bgSVycgF+miIiIFFi6TYO6EosQcWWXLolYt1HA9RsCzGYZnd6VkDe3DL1OQLaMJkyda8WhwyL+V1nCG40USPIgQsBPE3QwGoBBKaTsJF5v1d8i9v8jIixURtGiMo6fUGDKc4VlvN1MQpbMaauH4oZ7kgzh8MRTxQI7nsOTwOrPVw8eBVSBJ5F3YzBr2Bac3nc9vtsOwZRSVfKj81e1ecHYAJ2XEKMOoSYd7j+yBmgH/lmWwxP/6OqPWXm3Hdeqcnjij9Pm/ZwcnnivoVozcHjif3hiGtENupuXYflsAhxFSqniWq3Bk3kLRJw9LyJDBhlRUUpkR+FCMt54XQEjZKfPiNi2U2DRI2RUZ6TLezJy5lAAiROenL1kYaCE6o/0/8SBULOMHTt12LBZwEtlJbR8272irTY7MOlXHe7fT4g0IRhDUEZN4/BETbW9X4vDE+815DM8GwqoAk+cUt6+HInbVyLZf3MXyozchTMHvco88kR7LuTwRHs+SW5HHJ5weBI8p5W3Kg4mX3F44h08MSz+Bfp/tsD+ejuXXXSE6Ecw938bsjEEseNXqnY0tARPdu7WYf1GgYGTDz+QcP26gFWrBTx4nB5DECUqCrj3GGJQJEiVKkCVihKLPHGaE57ciYjDH8tFHD0mxtcs+WWKDrduu5eyk9gJFN0yZbqOAZyWLRJAjWqO4q2K1ZTaJ2txeOITGfkkz4ACqsKT9Kgnhyfa8yqHJ9rzCYcnnvmER554ppdao3nkiVpKe78OhyfewZOQbz6AePVfSDnzI27E7Kcm0x3ZBdOU4XCUfAWWjxI55iMAACAASURBVMZ47zA3Z1ATnpw4qRRpdWWXrwqYMUvHXuraycGiTZy2dYcOm7ckRH1kzSyjWlUZlSu5jvxIDE/u3RMwfpLSWafLew4GQChlZ8hgpR6KJ0addYoWUTfaJPH+eOSJJ94K/FgOTwLvA76D4FBAFXhCKTrLfzmAkpXyo8yrBZgyO5adxt0bj9CkZ8X4VJ7gkCzpLjk80Z7XODzRnk+S2xGPPHGtDIcn2jzDHJ5o0y+udsXhiWtfxcTZERH9uBdtCu6kLjrUTYfMMmAcHEXLJBltWDwZhi3LYGvSCbbXO6h2MNSCJytXizhwUASBj7p1ZLz0YgKEiI4R8PNkpatNrRoO1Kn9NGChWiVbtgko+TxQulTKACMxPCEhFy3V4eQpgdUsobU8SdlRzRFuLMThiRsiaWgIhycacgbfiqYVUAWeUGHYE7uuoNvXdVGoZA4myPnDtzBn5Da8XOs5tOhbRdMipbQ5Dk+05zoOT7TnEw5PPPMJhyee6aXWaA5P1FLa+3U4PPEOnoR+kFDI3/5qfVjf/SzJhM7IFEu/H+Ao8ZL3DnNzBjXgyZr1IvbsTdrSN09uGfXryihRXMLsuSIoqqNwQRldO6feYSe1W3sSnty5I+DnX5WoFrJ2bSSUeiFwESSp7T+51zk8SatygbmOw5PA6M5XDT4FVIEn/RvMxadT3kLeIlmSKHTzYgR+6LES36/vGHzKPd4xhyfacx2HJ9rzCYcnnvmEwxPP9FJrNIcnaint/TocnqQdnghRkTAPaBk/gaw3Im7MYsjmMPY1ITYG5n5N2b9jJ6yGbDB67zA3Z/A3PHGm3FAb4W6dJdbtZu06gf2d2EJCZHzYU0KmTN53rnkSntA68xeJOHNWTHPKjpty+nUYhyd+ldfnk3N44nNJ+YTpVAFV4EnvV6djzNqOCMtsSiJjbJQV/evPwaQ93YJWXg5PtOc6Dk+05xMOTzzzCYcnnuml1mgOT9RS2vt1ODxJOzwRb1xEyMjucOQrDGTKBt2Zw7C27QN7zSZsUv2J/TBO+gKO4i/C8umP3jvLgxn8CU8o2oSiTsgoooQiS5xGxWG3bhNgfZzx9E47Cc+X8E00iCt4cidcwImTQPZsAsq95Jt1PJDZJ0M5PPGJjKpNwuGJalLzhYJcAVXgyXddVqBs1YJ4o2t5CI/hvSzJWD39EE7uvYaBM5VPMILRODzRntc4PNGeTzg88cwnHJ54ppdaozk8UUtp79fh8CTt8ER36iBMEwexYrCOGm/COG0UHPmeg+XLaQo8+XMajOsXw9aoPWxNO3vvLA9m8Bc8OXhIxIpVCjh5t4OE4sWeBhYxsQI2bhJYK2Fq/esrcwVPfDV3IOfh8CSQ6nu+NocnnmvGr3g2FVAFnlw8cQcTP1oDk9mAXIUyA7KMW5cjYbPY0Wf86yhSNlfQqs/hifZcx+GJ9nzC4YlnPuHwxDO91BrN4YlaSnu/DocnaYcn+r0bYPxtDOyV68DaeTDM/VtAiH4Iy8CJcDxXEqYxfaG7eBqWvt/BUaq8987yYAZ/wJNjJwQsXabUGGnVwoEXk+mw48E2PRrK4YlHcgV0MH0AnCerGTfvxwZ0H/5YnMMTf6jK50yPCqgCT0i4uGgbDqz7F7evRDIdcxXMjEoNi8GcQb1cWX84kMMTf6jq3Zwcnninn5pX8247rtXm8ETNU+j+WhyeuK9VoEdyeJJ2eGJYvxiGP6fBVq8lbC16wLBsKgwblsBWtRHsbfvA3PdNNrna9U5oTV/DE+pm89MEEVargLfelFCpgu8iStx9D3B44q5SgR/H4UngfcB3wBUItAKqwZNA36i/1ufwxF/Kpn1eDk/Srp3aV3J4wuGJ2mfOm/U4PPFGPXWv5fDEC3iyZDIMm5fB1rIHbHVbQrxzDSHDOkM2hsDa9XOYJg9lESgUiaK2+RqeOFsSUzedXj2875yTFj04PEmLaoG5hsOTwOjOV+UKaEmBgMITySFjVIc/MHRhQlV3LYnjzl44PHFHJXXHcHiirt7erMbhCYcn3pwfta/l8ERtxdO+HocnaYcnxhnfQP/PFli6DIajUh02kemn/tCdOwope16I927C2qA17M3fT7uD0nilL+EJFWX9ebKSrtO9qwMF8nvfOSctt8XhSVpUC8w1HJ4ERne+KldASwqoAk8e3ovFn5P248rpcNisCWQ/5qEFBpMeo1e115ImHu2FwxOP5FJlMIcnqsjsk0U4POHwxCcHSaVJODxRSWgfLMPhSdrhienH/tCdPwrLx2PheOFlNpH+wGYYZ46On9TSexQcZav4wFOeTeFLeDJjtg6XrwisxgnVOgmUcXgSKOU9X5fDE88141dwBdKbAqrAk0n91sESY0O5moWxatohNP2gIq7/ex9USLbXDw2RLU8GVXRd99tRbPj9KBx2CRXqF0P7gdUh6h63/0lhB5F3YzBr2BZcOhnO9tppeC0UKpmDXcHhiSqu82gRDk88kiuggzk84fAkoAfQw8U5PPFQsAAO5/Ak7fAkZHhniLevIW7odEh5C8dPFNKvKcTYGPb/2HErIJtCfeZhi1WAyZh65Iev4MnZ8yLmLRCh0wEff+hA5sypr+2zm31iIg5P/KWs7+fl8MT3mvIZuQLBpoAq8OSjmrPwzV/tEZbZhMGN58dHmhzefBGn919H+0HV/a7buYM3GQAZML0JwjKZMPHjtShfpwjqtC2b6toT+vyN4i/nRaNOL7OitwfWX8CH4xpxeJKqcoEZwOFJYHRPy6ocnnB4kpZzE6hrODwJlPKer8vhSdrhifnT5hBiohD7w5+QQxM+3DI8roUiFSyOuM8ne+6UZK7YuUuHU2eB7l1Sj/7wFTwZN1GH+w8E1KrhQJ3agQMnJAmHJz47Sn6fiMMTv0vMF+AKaF4BVeDJx7VmY+SfbZExawi+aLoAwxe3hsGk5Jkmhin+VGvh2F3ImNWMN7spbfWObb+MdXOOMpiSkkWEx2Bku6UYs/Yd6PTiU0N55Ik/vZa2uTk8SZtugbiKwxMOTwJx7tK6JocnaVVO/es4PEkbPBFs1vhuOjGTNySZRIh6CPHGRcgZsySJSPHGu+s2Cti1W/l9sH0bCSVfSLnbjS/gyZ69ItasFxEWJqPfRw4Y9N7cgffXcnjivYZqzcDhiVpK83W4AtpVQBV48utnG/DofiyL1qDoj5BQI15rUQo3LjzAqmkHGZjwt1H0SNUmL6Bi/WJsqVuXIvD9+3/h+w3vprj0yd1XsXrGIRQokR3Hd15B9rwZ0H5QDeQrlpVdx+GJvz3n+fwcnniuWaCu4PCEw5NAnb20rMvhSVpUC8w1HJ6kEZ7cuw3zkHcgZcuFuK/n+dV5y1eKOHQ44UOpbNlklkKTknkLT2JildbEFouAFs0klHtJ/dbET94fhyd+PWY+nZzDE5/KySfjCgSlAqrAk6iIOPwxYR/afFoVD+5EY9InaxF+7SGMIXq883kNVHmjhN/FI1BS/51yOL7rCq6du4f3R9fD8FaLMXFnlxTXPrDuAgM+nb+qjQr1imLzwhPY8edpDF/SGvRN9FGs3e9799cC9APboBMRm6iIr7/WUnPeUJMOFpsEhxTYUFxf3jOV5gkx6hBtST2s2Zfr+nsus1EHu0OCzZF+fEWaGXQC81dazW6XEGsL/C/1ad2/iaL0BLD3YXqyjGY9omLtSE+n1aAXQd9f4tKZrzKE6BFjsSMd/RhgbyWzQYTeRRSsu++zOKsj5e+3F07BMaIXULQkdMN+dXdaj8fNni/j6DHlsp5dBaxYLePmLaBlUwHVXk1+uh27RJQtDWTNmrbvLUuXy9i1FyhYAOj3Yeo17zy+sTRcIAqA2aRHdFzw/j7p6rbpZ6Ajnf18pxOTwawP6t/9kzui9PONG1eAK5C6AqrAE1fbePQgDqEZjS5TYVLftucjJvRdgyqNirP1COCUqlIA43qtcivyZMGYXRi1vC1bVJZkfFh9Jr5e3hZZcoXhUYzN881o5Aq9ToRBLyA2nT2Qh5r0sNgdcKSjB3JRVB7GY9LbL1cmHex2mQGU9GT0QOoVPHFIQf2+NBro02QBVlv6gn0ZzAZExQbv93xX7zEGT0QB9FCdnizMrEdMnAOynJ5QF0DA2Wt4Yk/++618cCekiV9CeKUqxI++9vmRsFmBGb/LOHtegMEAdO8koHhRGecvCPhluoywUODLgYDJ+PTSew8Ai5YBRiPQoglQuYJn2/vnMDBvsXLNJ72AQgU9u95fo+nnO/k1XcITSYYthfPmL039Nq8AZAhJfz8HSK+MoQa/ycYn5gqkJwUCBk/UFnHxD3tgNOvRrFcltjRFlGxfdgqfTnkrxa3cuRKJMV1XYOy6jhBEIR6ejF7ZHpmym3najtqOdGM9nrbjhkgaGcLTdlw7gn7ZDI+0aMRLnm+DfYIlCEENl13dNU/b8fwsBOoKnrbjWnkC8BHRyQNAw/ZVMCwYD1v1N2Hr8LFP3WezAbPn6nD1mgJOOnZw4LlCCXBrzjwR/14QUaO6A/XrJIVel68KmDEraTTfS2UlNGksMZiSmu3bL2L1WiVFqEolCW++rh1gz9N2UvOedl7naTva8QXfCVcgUAo8M/DkwtHbmDp4IwZMa4LQTCaM/3A1qjcriRrNS8VrT6lFNy7cR5/xryfxx7edlqNyo+Ko3aYstiw6gV0rzuDLBS3ZGF7zJFBHN/l1OTzRnk+S2xGHJxyeBM9pBTg8CR5vcXiSRniy8jcY/v4dtjfege2t93zq8J27dVi/UYDRKOPddyQUKpAUkNy+I2DSrwog6f+xA5kyKa9HRAiYNFWEJU5Aw7pA4UIyfl8IUP2SLFlktGsjIW/u5COMNm8VsHW7Mm+1Vx1oWF9b0Ugcnvj0mPl1Mg5P/Covn5wrEBQKPDPwhLyxcd5xrJ19GHabhKpvvYBW/V5ldUuc9vs3O1g9lEGzmyVxHhWXpbonty9HIm+RLHh3aC32N4cn2jzjHJ5o0y+udsXhCYcnwXNaOTwJJl9xeJJGeDJvHAw7V8PW7iPYXmvsM5fb7MAPP+kY8Hi3g4TixVxHfixfIeLQUZEVcqWCrlYbMHW6DnfCBZQqJaF3F0rHsuPOfRkLF4u4dl35Ja5hfQmFC8oo8ASQWb1GxL4DSsQJRZtQ1InWjMMTrXkk+f1weBI8vuI75Qr4S4FnCp74Q0QeeeIPVb2bk8MT7/RT82oOTzg8UfO8ebsWjzzxVkH1rufwJG3wxDR5KHTH9sDS8ys4ylX1mcOc7YEJbnTvknx9nUePBPw4gQqNAj3fd2DrdgFnzorIm0dGty4O5M5qZPDEWeA4MRxxbrZgARmFC0u4e0/AmTMKOGnT0oEypbUVceLcL4cnPjtmfp+IwxO/S8wX4ApoXgEOT7x0EYcnXgroh8s5PPGDqH6aksMTDk/8dLT8Mi2HJ36R1S+TcniSRnjyXR/oLp2B5bMJcBRJSGtOyUkUHWJModYkRZ38NF6HqOiUo06ca2zaLGDbTiqMC9jtQIYMMnq+LyFTRhmuWhWfPiPiyDHg1k0BDyKTdtAxGWV0aCfhucLaBCd0zxye+OVbgF8m5fDEL7LySbkCQaUAhydeuovDEy8F9MPlHJ74QVQ/TcnhCYcnfjpafpmWwxO/yOqXSTk8SRs8CfmiA8T7dxA76nfI2XO75ZtlK0TW+rdSBdcpMXv3i/h7rYh8eQmCpN7ViWAMwZboGIEBlG6dHexaMlfwJPEmY2MFXL8h4PpNATeuy6hTW0buXNoFJxyeuHXENDOIwxPNuIJvhCsQMAU4PPFSeg5PvBTQD5dzeOIHUf00JYcnHJ746Wj5ZVoOT/wiq18m5fAkbfAk9IP67MKYyRvc8gvVMPl2rFKMtWVzCS+9+DRAGfOjDlFRAt5pJ+H5Eu7VHNn/j4hVf4to10pitU6clho8cWvTGhvEI0805pAUtsPhSfD4iu+UK+AvBTg88VJZDk+8FNAPl3N44gdR/TQlhyccnvjpaPllWg5P/CKrXybl8MRzeCJER8Hcvznk0AyI/eFPt/xC6TWUZuO0dq0llCqZADucLYKpG84HPVKPOkm86MHDIiq8khS2cHjills0MShLBiOsNgdiLJ75XRObT2YTHJ5o2Tt8b1wBdRTg8MRLnTk88VJAP1zO4YkfRPXTlByecHjip6Pll2k5PPGLrH6ZlMMTz+GJePMKQkZ0hZSnIOKGzXTLL2N+UGqZJLb33pFQrKgCPZxRJ09CFbcmdzGIw5O0Kqf+dRyeqK+5Nyvmy2725nJ+LVfgmVEgoPAk5pEVURFxyFUwU9AKzuGJ9lzH4Yn2fJLcjjg84fAkeE4rb1UcTL7i8MRzeKI7exSmcf3heL4cLJ98n6q7j50QsHSZDlmyyOjX1wGqfXLkqAidDuj6ngM3bgks9SZnDgl9ermXrpPaohyepKaQdl7n8EQ7vnBnJxyeuKMSH8MVAFSBJ4Mbz8fIZW2gNyp5sU47f+gmFozZhaELWwatLzg80Z7rODzRnk84PPHMJza7hPBIi2cXaWh0RrMeEAQ8irFpaFfeb4VHnnivoVozcHiSBnhyYDNMM0fDXrE2rF0/T9VVv0zR4dZtAU3elFDxcbHYBUtEnD6tABRqN0zWuqUDZX3UJpjDk1TdopkBHJ5oxhVubYTDE7dk4oO4AurAkx4Vp+LnXV1hMCWFJ/duRmF4q8WYuLNL0LqCwxPtuY7DE+35hMMTz3zC4Ylneqk1msMTtZT2fh0OTzyHJ4ZNS2FYOgW2ui1ga9kzRSdcuy5g6gwdzGYZ/T92wJCoVfHc+SLO/yuy67Nnl/BRb99EndB8HJ54/95QawYOT9RS2jfrcHjiGx35LOlfAVUiT5KDJ2f2X8fkAesxflvnoFWawxPtuY7DE+35hMMTz3zC4Ylneqk1msMTtZT2fh0OT9IAT5ZNhWHDEtje7g5b/VYpOmHxHzqcOCmgejUHGtRN2grYbgfmzNPh0mUBLd+W8FJZDk9SEpN32/H+/a7WDLxgrFpK83W4AtpVwK/wZODrv8NmdSA60oKwzKanVIh5aEG1piXRcchr2lUolZ1xeKI913F4oj2fcHjimU84PPFML7VGc3iiltLer8PhiefwxDj7W+j3bYK100DYq9RL1glUIJYKxZJR1EmmTEnhCX3dZgOWLldaDfvSeOSJL9X071w88sS/+vp6dh554mtF+XzpVQG/whOHXcKNCw8wqsMf6Dm2AXR6JYyTjOhtxqxmFC6dk/07WI3DE+15jsMT7fmEwxPPfMLhiWd6qTWawxO1lPZ+HQ5PPIcnpgkDoTt9CJa+38FRqnyyTtiwScCOXTqULSOjdQt129ByeOL9e0OtGTg8UUtp36zD4YlvdOSzpH8F/ApPnPKtn3sU9dq/BFEXxJQkmbPA4Yn23iQcnmjPJxyeeOYTDk8800ut0RyeqKW09+tweJIGeDLyfehuXIJlyDQ48j+XrBNGj9UhNlZA964OFMj/dNSJ995LfgYOT/yprm/n5vDEt3r6ezYOT/ytMJ8/vSigCjxJL2K5ug8OT7TnXQ5PtOcTDk888wmHJ57ppdZoDk/UUtr7dTg88RyemPu3gBD9ELFjl0LOkNnlBAcPi1ixUkSe3DJ69VA36oQ2xOGJ9+8NtWbg8EQtpX2zDocnvtGRz5L+FVAVnlCNE+qwU/CF7OlGWQ5PtOdKDk+05xMOTzzzCYcnnuml1mgOT9RS2vt1ODzxHJ6EflCfXRQzeUOyDpj4i4jwuyJL16G0HbWNwxO1FU/7ehyepF27QFzJ4UkgVOdrBqMCqsCTqIg4zBm5DUe3XWYaTfmnOyLvxuDnj9ei948NkSVXWDBqx/bM4Yn2XMfhifZ8wuGJZz7h8MQzvdQazeGJWkp7vw6HJ57BEzHiLkIGt4OUJTviRi90efGlSyJmzhGRIYOMz/qpH3VCm+LwxPv3hlozcHiiltK+WYfDE9/oyGdJ/wqoAk9mDNkMa5wdzXpXxvBWixk8sVsdWDBmF6Ij41gx2WA1Dk+05zkOT7TnEw5PPPMJhyee6aXWaA5P1FLa+3U4PPEQnlw5h5DRvSEVeh5xgye5vHjBYhGnz4ioX0dGjeocnnh/SpUZeKtiXynp/3l4q2L/a8xX4ApoXQFV4En/BnMx4o82CM1oRI+KUxk8IYuNsmJw4/kYt7WT1nVKdn8cnmjPdRyeaM8nHJ545hMOTzzTS63RHJ6opbT363B44lrDiId2TJ7lQPs2EgyGhDG6E/tgmjQEjrJVYOk96qmLHz4U8P04pT3x4AEOmM3qp+zQ2jzyxPv3hloz8MgTtZT2zTo88sQ3OvJZ0r8CqsCTPtVnYszad2DOkBSeUOrOl28vwoTtnYNWaQ5PtOc6Dk+05xMOTzzzCYcnnuml1mgOT9RS2vt1ODxxreGV647/t3cm4DZV7x//3tk1U4SoZEoaFBKZEqWMFZJMpZRCKENUlKJBJUPJlEQkVJIhYzJkDhUVicwyu+587/95l/85P67LPfvss/bZ69zvfp6e3w97v2vtz7v22md/9lpr4/V30nBtiXS0a5PqFSiRq+Yj+vP3kFy9AZLbvnDRwQsWhWHlqghUvDUNDzVNs58gPyNQnvgJLgiHUZ4EAbqNIilPbMDjodmKgCPyZFTPBcidPwdadL8TPep+ho9+fhJ7/zqG6e+tQt4rYvH02+cWKTNxozxxX9YoT9yXE8oTazmhPLHGy6m9KU+cIm2/HMqTzBmejkvBgCFpOHU6DNeUSEf7/xcoUfOmIGr2RCQ3aI3kphe/0HrzrQgkJoWhc6dUFC0SnFEnckaUJ/avDaciUJ44RTow5VCeBIYjo4Q+AUfkyYnDcZjw6lL8sX6/IipzBtPTgQrVS+DxgXWQp2CssaQpT9yXOsoT9+WE8sRaTihPrPFyam/KE6dI2y+H8iRzhmcTUrBrfwrGTwi/QKDkmjkCkT/ORlKrrkip3eSCgz2fJy5ePB2dngjOWieeClGe2L82nIpAeeIU6cCUQ3kSGI6MEvoEHJEnHoyHdp/Ekb2nEBYehsIl8qJQ8bzGE6Y8cV8KKU/clxPKE2s5oTyxxsupvSlPnCJtvxzKk0vLkxNxyTh+MgxjxoUjLu7cCJTOia8iavMKJHUagJTbalxwsOfzxM0fSsUtNwVv1IlUivLE/rXhVATKE6dIB6YcypPAcGSU0CfgqDwJRZyUJ+7LKuWJ+3JCeWItJ5Qn1ng5tTfliVOk7ZdDeXJ5eSL/euxYGMZ+ek6g9DzdBcXO/IbEXsOQen0F78H/7A7DhM8ikDtXOnq/ENxRJ5Qn9q8LJyNQnjhJ235ZlCf2GTJC9iDgiDxJTUnD2vk7UK1RWUV1y/Ld+HHm7yhWqiAad6qE6ByRxtKmPHFf6ihP3JcTyhNrOaE8scbLqb0pT5wibb8cypOs5cn5AqXbrsdwReoBnBkwCeFFinoPnvpVOLZtC8fdddJxdy3KE/st8+II/FSxDqp6YvJTxXq4MioJmETAEXky7d2V2L3tP/SZ0BQydef1Vl+h3mO3YN+OY8hfKBfa9K9pErML6kp54r7UUZ64LyeUJ9ZyQnlijZdTe1OeOEXafjmUJ77JE49AKd6/njpgVLXFaNs6DZGRwPmfJ5ZRJzL6JNgbp+0EOwO+l8+RJ76zcsOeHHnihiywDiYQcESevFBvEgZOb6EWhp09ej12bzuCrh/ej7iTiRjYcjreXdDWBFaZ1pHyxH2pozxxX04oT6zlhPLEGi+n9qY8cYq0/XIoT3yXJ2EJ8Yjt0QQJ4Tnx8lXfo+R1aUqgLF527vPEN1dIR4uHgz/qRM6I8sT+teFUBMoTp0gHphzKk8BwZJTQJ+CIPOlaYwKGLeuAiMhwDGn/Nao3LofazW9UX9zpVnMCRqx4wljSlCfuSx3liftyQnliLSeUJ9Z4ObU35YlTpO2XQ3niuzwJP7wXOQY8juQrimNQvkk4Gx+Ga4qnY8/eMBXkqcdTUaJE8EedUJ7Yvy6cjEB54iRt+2VRnthnyAjZg4Aj8mRwu69Rp8WNaorOiOfnYch3rZG/cC41lWfCK0vw2oyWxtKmPHFf6ihP3JcTyhNrOaE8scbLqb0pT5wibb8cyhML8mTHVuR4rydSS9+Mve2HYfynYUqgyFb0qnR0ftodo04oT+xfF05GoDxxkrb9sihP7DNkhOxBwBF5suOXgxjTdxHiTiWqBWIbdKiIhLhk9G04BS17VkP1JuWMpU154r7UUZ64LyeUJ9ZyQnlijZdTe1OeOEXafjmUJ77Lk8iNPyJ67BtIqVQbSU++jMOHwzBuYjgSEsLwUNM0VLw1zX5CAhSB03YCBNKBMJQnDkAOYBGUJwGEyVAhTcAReeIhKF/dkak7nu3A38dR9PoCRgOmPHFf+ihP3JcTyhNrOaE8scbLqb0pT5wibb8cyhML8mTZN4j+chSS734QyS2fVQceOhyGqV+Go3tX94w6kXpRnti/NpyKQHniFOnAlEN5EhiOjBL6BByVJ6GIk/LEfVmlPHFfTihPrOWE8sQaL6f2pjxxirT9cihPfJcnUd+MR9SCaUhu1hHJ97XyHpiUDERH2c9FICNQngSSpt5YlCd6+QY6OuVJoIkyXqgSCKo8SUtNxxuPzcSr05oby5fyxH2pozxxX04oT6zlhPLEGi+n9qY8cYq0/XIoT3yXJ9GfvYvIn39AUvteSLnzXvvwNUagPNEIN8ChKU8CDFRzOMoTzYAZPmQIOCJPTh2Nx9ej1mLPtiNITvrfENCzpxIRFROJIXNaGwuU8sR9qaM8cV9OKE+s5YTyxBovp/amPHGKtP1yKE8syJMR/RD5+zokdh2C1Bsr24evMQLliUa4AQ5NeRJgoJrDUZ5oBszwIUPAEXkyqucCJJ5Nxq21r8WcsRvRtHNl7NtxDLt+PYxn37sPBYvkNhYo5Yn7Ukd54r6cUJ5YywnliTVeTu1NeeIUWJWQ3wAAIABJREFUafvlUJ74Lk9yvPkMwvfuREL/T5BW/Hr78DVGoDzRCDfAoSlPAgxUczjKE82AGT5kCDgiT56v/SkGz26NXPli8FKjL7wjTTYt2YVta/ehdd8axgKlPHFf6ihP3JcTyhNrOaE8scbLqb0pT5wibb8cyhML8qTPIwg/dQzxb09Hel53L+JPeWL/2nAqAuWJU6QDUw7lSWA4MkroE3BEnnSvMxGDvm6FPAVyoH/TqRg4vSWiYiIU3fNlim7cCz7bjIWTN0O++lOpfim07lMD4RFhPhcrn1x+98nZ6DWuCUpXLKKOozzxGZ9jO1KeOIbadkEF8kQjITEV8edN57Md1AUB8ueKQs4ckX7XhPLEb3RaD6Q80Yo3oMEpT3yXJzk711c7n/14YUBzoCMY5YkOqnpiUp7o4aorKuWJLrKMG2oEHJEno3svxOlj8egyrAE+HbAUOXJGo9bD5bF/53HMGbsB78xvo53rnxsOqLJFfOTKG4MR3efj9rolUbfVTT6VLcJFxMnRA6fx9Nv1KU98ohacnShPgsPdn1IpTzKnRnniT2vSfwzliX7GgSqB8sQ3eRK16CtEzRyD1JLlkdh7eKDwa4tDeaINbcADU54EHKnWgJQnWvEyeAgRcESenDmRgJnD1+CRF6rj+OE4jOoxH0f2nkJ0jki06VcTVR8oox3ptHdXIk+BWDR88nZV1pblu7Fg0mYlU3zZfpi0GQgD1sz9C4/2qUF54gu0IO1DeRIk8H4US3lCeeJHswnaIZQnQUNvuWDKk6zlSVj8WeTo1wphCfFI7DUMqddXsMzZ6QMoT5wm7n95lCf+swvGkZQnwaDOMk0k4Ig8yQzM6eMJyJknGhGR4Y5wG951Lqo3KYfK9Uup8g7+cwJDn5qNoQvbZVn+sYNnMLbfYrw4pjEGt51FeZIlseDuQHkSXP5WSqc8oTyx0l6CvS/lSbAz4Hv5lCdZy5Oob8YjasE0pN5UFYnPveE73CDuSXkSRPgWi6Y8sQgsyLtTngQ5ASzeGAJBkydOExJRUr/Nrdi6cg/2/nkUTw2ph4EtpmPEiieyrMroXj/g3nYVcf3NhTHo0RkXyJPT8SlZHu/WHSIjwhAVER5y603kjIlAYnIaUtPS3Yrecr1kaZ4c0RGIS/zfp74tB3HhAbHREUhJTUNyaujkSjBHRYSpfPm7paSkIT45zd/Dg35cjEjxMKjrMJS2PLGROBOfglBqrVGR4ZD+JSHEcpU7RyTOJqYghG4D6lKKjQpHpI2XTglJqef625PHkPpCKyA5CRFvfQ4ULWHEpSr3DJnWmBJCiQ0PA2JjIhGXYO7vycwaj9wDU0Ps/i6rJOaOjYTJv/0vdaHL/Y0bCZBA1gQckSdH959GwaJ5EJZhbVaZuvPvH0dx+z0ls66pzT2Gd5uHqg1Kq5EuMnWofNXiGPbsnCxHnmxdsQfyn+eLQBfJk7PJNmsWvMMjI8IRFRmG+BB7IM8ZE4nElFSkhtADeXj4uYfxs6H24yomAikp6UqghNImD6S25ElqmtHXZXSUjCgMQ1JyaMm+3LFROBNvbp+f2TWm5El4GOShOpS2XLGROJuQivT0UFJdgMgD2/IkJQ2pn30ALJ2NsFoPIPyJXsakPjbm/+VJiN3fJa8hKU/S0pXsCpktDMidI/TuA5KfPDmjQiZNPBES0EnAEXnydOUxGLmyo/cLO54T2vXrYTUdZvDsR3Weo4o9/b3ViI6NRLNnq6g/r1uwE8tn/Y4XPml82bInDfoRm3/cjTB5NQAg7mQCcuSKRvtXa6Ninev4tR3tmbNeAKftWGcWrCM4bSdz8lwwNlgt8vLlctqOO/OSWa04bSfzXImAP7lnD2Jfbof0yGgkDJ6C9Dz5jUksp+0Ykypw2o45uZKactqOWflibYNHIKjy5PihOLzcbCpGrX5SO4Gdmw9hzEuL0GtsE+TMG4MPu3yPGs1uQM0Hy3vLlkVt9+88hq4f3n/J+mQcecJPFWtPneUCKE8sIwvaAZQnlCdBa3x+FEx54ge0IB1CeXJpeXL2wwGI3PAjkhu0RnLTx4OUIf+KpTzxj1swjqI8CQZ1/8ukPPGfHY/MXgS0ypN9O44pmq+3moH+kx+6aHHYLT/txpJpv+LdBW0dob5oylbMn7gJKclpqN64HFr0rHbBVKLJg39S66H0ndiM8sSRjOgphPJED1cdUSlPKE90tCtdMSlPdJENfFzKk0vIk9NnkdTxXqTnyo2EN79Aekxs4OFrjEh5ohFugENTngQYqOZwlCeaATN8yBDQKk/ef2YO/v3jP5w9nZQpMPlUccue1VDzof+N/jCNLEeeuC9jlCfuy8mlakR5QnliTmsFKE/MyRblSea5itu7D8k9H0HSI12QUqepOQn9/5pSnpiTMsoTc3IlNaU8MStfrG3wCGiVJ57TkjVP3lvUDlHnf30iLAwiTzIuIhs8FP6VTHniHzedR1Ge6KQb2NiUJ5QngW1ReqNRnujlG8jolCeXkCf/7kXikB5IGDQpkLgdi0V54hhq2wVRnthG6GgAyhNHcbMwgwk4Ik92/34E15QvZLwoySzPlCfua/2UJ+7LyaVqRHlCeWJOa+XIE5NyRXmSebbUgrEHDiM9bwGT0umtK+WJOWmjPDEnV1JTyhOz8sXaBo+AI/Lkcqd38J8TKHKdOSu9ZzwXypPgNd5LlUx54r6cUJ5Yywm/tmONl1N7c+SJU6Ttl0N5cml5ciLO3M9tU57YvzacikB54hTpwJRDeRIYjowS+gQclSey9klyYoqX6pkTCfig8xwMXdjOWNKUJ+5LHeWJ+3JCeWItJ5Qn1ng5tTfliVOk7ZdDeUJ5Yr8VORMhMiIMBfPE4PCJBGcKdKgUyhOHQAeoGMqTAIFkmJAn4Ig82fXrYYzrvxj/7Tt9EdDyVa9G91ENjQVNeeK+1FGeuC8nlCfWckJ5Yo2XU3tTnjhF2n45lCeUJ/ZbkTMRKE+c4RyIUmSdxiIFYnHgWHwgwrkqBuWJq9LByriYgCPyZHDbWShX5WpUbVAaw7vNQ4+PGkI+Y7xy9h9o/2pt5C+cy8WILl81yhP3pY7yxH05oTyxlhPKE2u8nNqb8sQp0vbLoTyhPLHfipyJQHniDOdAlEJ5EgiKjEECZhNwRJ50uWs83l/cXn1d56VGX2DInNaKmqx38uXQVXh+5APGUqQ8cV/qKE/clxPKE2s5oTyxxsupvSlPnCJtvxzKE8oT+63ImQiUJ85wDkQplCeBoMgYJGA2AUfkSa/7PkfP0Y1RtGR+vPrwl3jhk8bId2VORa53g8l4Z34bYylSnrgvdZQn7ssJ5Ym1nFCeWOPl1N6UJ06Rtl8O5Qnlif1W5EwEyhNnOAeiFMqTQFBkDBIwm4Aj8mTWiDX46evtGDTrEcwevR47fjmIyvVLYd/OY2r6zsDpLYylSHnivtRRnrgvJ5Qn1nJCeWKNl1N7U544Rdp+OZQnlCf2W5EzEShPnOEciFIoTwJBkTFIwGwCjsiT9LR0rJm3A5XrX4+kxFTMGLYaf285hAJX5caDXe7ANTdcaSxFyhP3pY7yxH05oTyxlhPKE2u8nNqb8sQp0vbLoTyhPLHfipyJQHniDOdAlEJ5EgiKjEECZhNwRJ6Yjejytac8cV92KU/clxPKE2s5oTyxxsupvSlPnCJtvxzKE8oT+63ImQiUJ85wDkQplCeBoMgYJGA2AcoTm/mjPLEJUMPhlCcaoGoKWSBPNBISUxGflKqphOCEzZ8rCjlzRPpdOOWJ3+i0Hkh5ohVvQINTnlCeBLRBaQxGeaIRboBDU54EGCjDkYCBBLTJE/mqji9bakoaF4z1BZSGfXJERyBnTASOnU7SED14ISlPgsfeasmUJ5kTozyx2pKc2Z/yxBnOgSiF8oTyJBDtyIkYlCdOUA5MGZQngeHIKCRgMgFt8mTdgp1eLkcPnMaKb7ajyn2lUOjqvBBhsv/v49i6Yg8adKiIGs1uMJYhR564L3WUJ+7LyaVqRHlCeWJOawUoT8zJFuUJ5YkprZXyxJRMAZQn5uSKNSUBXQS0yZPzK/xOx2/x2Es1cXXpghecx/Z1+zF3/Eb0HN1I1/lpj0t5oh2x5QIoTywjC9oBlCeUJ0FrfH4UTHniB7QgHUJ5QnkSpKZnuVjKE8vIgnYA5UnQ0LNgEnANAUfkSZe7xuP9xe0RnWENgDMnEtC34RSMXNnRNUCsVoTyxCox/ftTnuhnHKgSKE8oTwLVlpyIQ3niBOXAlEF5QnkSmJakPwrliX7GgSqB8iRQJBmHBMwl4Ig8ebPNLFx7YyHc36EiChbJjfR0QKbyfD9uI/btOIb+kx8yliDliftSR3nivpxcqkaUJ5Qn5rRWTtsxKVeUJ5QnprRXyhNTMsVpO+ZkijUlAX0EHJEne/86hrEvLcLBf05ccCaFS+TFU0Pq4ZobrtR3hpojU55oBuxHeMoTP6AF6RDKE8qTIDU9v4rlyBO/sAXlIMoTypOgNDw/CqU88QNakA7hyJMggWexJOAiAo7IE8/5ijw5cThOjTzJXygnipQsoBZfMnmjPHFf9ihP3JeTS9WI8oTyxJzWypEnJuWK8oTyxJT2SnliSqY48sScTLGmJKCPgKPyRN9pBC8y5Unw2F+qZMoT9+WE8sRaTvipYmu8nNqbI0+cIm2/HMoTyhP7rciZCJQnznAORCkceRIIioxBAmYToDyxmT/KE5sANRxOeaIBqqaQHHmSOVjKE00NzmZYyhObAB08nPKE8sTB5marKMoTW/gcPZjyxFHcLIwEXEmA8sRmWihPbALUcDjliQaomkJSnlCeaGpaWsJSnmjBqiUo5QnliZaGpSEo5YkGqJpCUp5oAsuwJGAQAcoTm8miPLEJUMPhlCcaoGoKSXlCeaKpaWkJS3miBauWoJQnlCdaGpaGoJQnGqBqCkl5ogksw5KAQQQoT2wmi/LEJkANh1OeaICqKSTlCeWJpqalJSzliRasWoJSnlCeaGlYGoJSnmiAqikk5YkmsAxLAgYRoDyxmSzKE5sANRxOeaIBqqaQlCeUJ5qalpawlCdasGoJSnlCeaKlYWkISnmiAaqmkJQnmsAyLAkYRIDyxGayKE9sAtRwOOWJBqiaQlKeUJ5oalpawlKeaMGqJSjlCeWJloalISjliQaomkJSnmgCy7AkYBAByhObyaI8sQlQw+GUJxqgagpJeUJ5oqlpaQlLeaIFq5aglCeUJ1oaloaglCcaoGoKSXmiCSzDkoBBBChPbCaL8sQmQA2HU55ogKopJOUJ5YmmpqUlLOWJFqxaglKeUJ5oaVgaglKeaICqKSTliSawDEsCBhGgPLGZLMoTmwA1HE55ogGqppCUJ5QnmpqWlrCUJ1qwaglKeUJ5oqVhaQhKeaIBqqaQlCeawDIsCRhEwBF5MnHgMrR9uRYiIsMvQPPH+v2YO34jenzcyCBkF1aV8sR9qaM8cV9OLlUjyhPKE3NaK0B5Yk62KE8oT0xprZQnpmQKoDwxJ1esKQnoIuCIPHm68hiMXNkRUTERF5zHod0nMaT91xi2rIOu89Mel/JEO2LLBVCeWEYWtAMoTyhPgtb4/CiY8sQPaEE6hPKE8iRITc9ysZQnlpEF7QDKk6ChZ8Ek4BoCQZUnB/85gUGtZ2LUqo6uAWK1IpQnVonp35/yRD/jQJVAeUJ5Eqi25EQcyhMnKAemDMoTypPAtCT9UShP9DMOVAmUJ4EiyTgkYC4BrfJkdO+FisymJbtQsc51CAsPu4DUnu3/oWCR3HhxTGNjCVKeuC91lCfuy8mlakR5QnliTmvltB2TckV5QnliSnulPDElU5y2Y06mWFMS0EdAqzz5a9NB7Nl2BNPfX417Hr0Z4REXypO8BWNRvUk55M6fQ98Zao5MeaIZsB/hKU/8gBakQyhPKE+C1PT8KpYjT/zCFpSDKE8oT4LS8PwolPLED2hBOoQjT4IEnsWSgIsIaJUnnvMc2X0+Og+996IFY53msOCzzVg4eTNSU9JQqX4ptO5T4yKhk1mdtvy0BzOGrcapo/G4unRBtOlfC0VL5le7Up44ncWsy6M8yZqRW/agPKE8cUtb9KUelCe+UHLHPpQnlCfuaIlZ14LyJGtGbtmD8sQtmWA9SCB4BByRJ8E7vf+V/OeGA/h0wFL0GtcEufLGYET3+bi9bknUbXXTZat35kQC+jediq4f3o9StxbB/E83YevKPeg9vinliRsSm0kdKE9cmphMqkV5QnliTmvltB2TckV5QnliSnulPDElU5y2Y06mWFMS0Ecg28iTae+uRJ4CsWj45O2K5pblu7Fg0mYlUy63HT8Uh19X7UHNB8ur3WSR27ef+BYfLGlPeaKvXdqKTHliC5+jB1OeUJ442uBsFsaRJzYBOng45QnliYPNzVZRlCe28Dl6MEeeOIqbhZGAKwk4Ik9kmsza+TtQrVFZr7j4cebvKFaqIBp3qoToHJHa4QzvOletr1K5fimvBBn61GwMXdjOUtk/TNqMPzceQJdhDShPLJFzbmfKE+dY2y2J8oTyxG4bcvJ4yhMnadsri/KE8sReC3LuaMoT51jbLYnyxC5BHk8C5hNwRJ7IqI/d2/5DnwlNcWj3Sbze6ivUe+wW7NtxDPkL5UKb/jW1kxRRUr/NrWrKzd4/j+KpIfUwsMV0jFjxhM9lb1+7D2P7LVajVYpcd27Nk9PxKT4f77Yd5YYdFRGO+KRUt1XNVn1yxkQgMTkNqWnptuK46WBZazlHdATiEkMrV7HREUhJTUNyaujkStpNVESYype/W0pKGuKT0/w9POjHxUSGA2FQ12EobXliI3EmPgWh1FqjIsMh/UtCiOUqd45InE1MQQjdBtSlFBsVjki5vvzcEpJSje5v5Z6RnJKGlBBKrHyIMjYmEnEJ5v6ezKw5yj0wNcTu7/LZi9yxkUb/9r9U1yH3N24kQAJZE3BEnrxQbxIGTm+BPAVjMXv0euzedkStIRJ3MhEDW07HuwvaZl1Tm3sM7zYPVRuUVovWHj8ch/JVi2PYs3N8Hnny68p/8dnry/D02/VRumIRb21On022WbPgHR4ZEY6oyDDEh9gDec6YSCSmpCI1hB7Iw8PPPYyfDbUfVzERSElJVwIllDZ5ILUlT1LTjL4uo6Pk4S4MScmhJftyx0bhTLy5fX5m15iSJ+FhkIfqUNpyxUbibEIq0tNDSXUBIg9sy5MUc/vb2Jj/lychdn+XvIakPElLV7IrZLYwIHeO0LsPSH7y5IwKmTTxREhAJwFH5EnXGhMwbFkHJS6GtP8a1RuXQ+3mN0J+03SrOcHS6A9/YUx/bzWiYyPR7NkqKsS6BTuxfNbveOGTxlmG/GP9fkx4dSm6DmuA4mWvuGB/fm0nS3yO78BpO44j97tATtvJHJ382DxyMtFvrsE+UL3BCguDyXI5M4acthPsluV7+Zy2kzkrEfAn4swVgAXzRKuXCKE0UorTdny/roO9J6ftBDsDLJ8Egk/AEXkyuN3XqNPiRjVFZ8Tz8zDku9bIXziXmsoz4ZUleG1GS+0kdm4+hDEvLUKvsU2QM28MPuzyPWo0u8G7EKxUYObwNdi/85gaFePZZHTMgBbT0WlIPZStVPSielKeaE+d5QIoTywjC9oBlCeUJ0FrfH4UTHniB7QgHUJ5QnkSpKZnuVjKE8vIgnYA5UnQ0LNgEnANAUfkyY5fDmJM30WIO5WoFoht0KEiEuKS0bfhFLTsWU0t5OrEtmjKVsyfuAkpyWlq9EuLntXk5ah3mzz4J7UeSt+Jzbx/t+Kb7Zj85nIlXM7fBnzZAvmuzAnKEycyZ60MyhNrvIK5N+UJ5Ukw25/VsilPrBIL3v6UJ5QnwWt91kqmPLHGK5h7U54Ekz7LJgF3EHBEnnhOVb66I1N3PNuBv4+j6PUF3EHCz1pQnvgJTuNhlCca4QY4NOUJ5UmAm5TWcJQnWvEGNDjlCeVJQBuUxmCUJxrhBjg05UmAgTIcCRhIwFF5YiCfLKtMeZIlIsd3oDxxHLnfBVKeUJ743XiCcCDlSRCg+1kk5QnliZ9Nx/HDKE8cR+53gZQnfqPjgSQQMgQckyd7tv+H1XP+xNEDp/Hse/chLTUdv676F7fUvMZomJQn7ksf5Yn7cnKpGlGeUJ6Y01oByhNzskV5QnliSmulPDElU2oddBQpEIsDx+LNqbSPNS12RayPe3I3EsjeBByRJxsW/a2+VnNrrWsh//+T9Z1w7OAZvNlmFh7scodauNXUjfLEfZmjPHFfTihPrOWEX9uxxsupvSlPnCJtvxzKE8oT+63ImQiUJ85wDkQplCeBoMgYJGA2AUfkyWuPfIWWPaujfNWr8XTlMUqeyCYLyX72+o8YNOsRYylSnrgvdZQn7ssJ5Ym1nFCeWOPl1N6UJ06Rtl8O5Qnlif1W5EwEyhNnOAeiFMqTQFBkDBIwm4Aj8qTLXeMxfPkTCI8Iu0CeyAKy3Wp9ilGrOhpLkfLEfamjPHFfTihPrOWE8sQaL6f2pjxxirT9cihPKE/styJnIlCeOMM5EKVQngSCImOQgNkEHJEn/ZpMRcdBdVHq1qsukCdr5v2FOWM2YNDXrYylSHnivtRRnrgvJ5Qn1nJCeWKNl1N7U544Rdp+OZQnlCf2W5EzEShPnOEciFIoTwJBkTFIwGwCjsiTn2Ztw8zha1CtUVksmfYrGj55O2QBWVkwtsOAOrizYRljKVKeuC91lCfuywnlibWcUJ5Y4+XU3pQnTpG2Xw7lCeWJ/VbkTATKE2c4B6IUypNAUGQMEjCbgCPyRBD9ueEAls/6HUf2nkJYWBiuujYf6rSogJI3FTaaIOWJ+9JHeeK+nFCeWMsJ5Yk1Xk7tTXniFGn75VCeUJ7Yb0XORKA8cYZzIEqhPAkERcYgAbMJOCZPzMZ06dpTnrgvs5Qn7ssJ5Ym1nFCeWOPl1N6UJ06Rtl8O5Qnlif1W5EwEyhNnOAeiFMqTQFBkDBIwm4BWeTJx4DI83K0q8hQM3W+HU5647wKgPHFfTihPrOWE8sQaL6f2pjxxirT9cihPKE/styJnIlCeOMM5EKVQngSCImOQgNkEtMoT+SyxLAZbuEResyldpvaUJ+5LLeWJ+3JCeWItJ5Qn1ng5tTfliVOk7ZdDeUJ5Yr8VOROB8sQZzoEohfIkEBQZgwTMJkB5YjN/lCc2AWo4nPJEA1RNIQvkiUZCYirik1I1lRCcsPlzRSFnjki/C6c88Rud1gMpT7TiDWhwyhPKk4A2KI3BKE80wg1waMqTAANlOBIwkIB2eVLlvlLIkSv6smja9KtpILpzVaY8cV/qKE/cl5NL1YjyJHMylCfubMOUJ+7MS2a1ojyhPDGltVKemJIpgPLEnFyxpiSgi4B2eVKucjFEZ/EGtsuwBrrOT3tcyhPtiC0XQHliGVnQDqA8oTwJWuPzo2DKEz+gBekQyhPKkyA1PcvFUp5YRha0AyhPgoaeBZOAawholydc88Q1ub6oIjmiI5AzJgLHTie5t5J+1IzyxA9oQTqE8oTyJEhNz69iKU/8whaUgyhPKE+C0vD8KJTyxA9oQTqE8iRI4FksCbiIAOWJzWRw5IlNgBoOpzzRAFVTSMoTyhNNTUtLWMoTLVi1BKU8oTzR0rA0BKU80QBVU0jKE01gGZYEDCKgVZ580HkOHn+9LvIXymkQEmtVpTyxxsuJvSlPnKAcmDIoTyhPAtOSnIlCeeIM50CUQnlCeRKIduREDMoTJygHpgzKk8BwZBQSMJmAVnliMhhf60554isp5/ajPHGOtd2SKE8oT+y2ISePpzxxkra9sihPKE/stSDnjqY8cY613ZIoT+wS5PEkYD4ByhObOaQ8sQlQw+GUJxqgagpJeUJ5oqlpaQlLeaIFq5aglCeUJ1oaloaglCcaoGoKSXmiCSzDkoBBBChPbCaL8sQmQA2HU55ogKopJOUJ5YmmpqUlLOWJFqxaglKeUJ5oaVgaglKeaICqKSTliSawDEsCBhGgPLGZLMoTmwA1HE55ogGqppCUJ5QnmpqWlrCUJ1qwaglKeUJ5oqVhaQhKeaIBqqaQlCeawDIsCRhEgPLEZrIoT2wC1HA45YkGqJpCUp5QnmhqWlrCUp5owaolKOUJ5YmWhqUhKOWJBqiaQlKeaALLsCRgEAHKE5vJojyxCVDD4ZQnGqBqCkl5QnmiqWlpCUt5ogWrlqCUJ5QnWhqWhqCUJxqgagpJeaIJLMOSgEEEKE9sJovyxCZADYdTnmiAqikk5QnliaampSUs5YkWrFqCUp5QnmhpWBqCUp5ogKopJOWJJrAMSwIGEaA8sZksyhObADUcTnmiAaqmkJQnlCeampaWsJQnWrBqCUp5QnmipWFpCEp5ogGqppCUJ5rAMiwJGESA8sRmsihPbALUcDjliQaomkJSnlCeaGpaWsJSnmjBqiUo5QnliZaGpSEo5YkGqJpCUp5oAsuwJGAQAcoTm8miPLEJUMPhlCcaoGoKSXlCeaKpaWkJS3miBauWoJQnlCdaGpaGoJQnGqBqCkl5ogksw5KAQQQoT2wmi/LEJkANh1OeaICqKSTlCeWJpqalJSzliRasWoJSnlCeaGlYGoJSnmiAqikk5YkmsAxLAgYRoDyxmSzKE5sANRxOeaIBqqaQlCeUJ5qalpawlCdasGoJSnlCeaKlYWkISnmiAaqmkJQnmsAyLAkYRIDyxGayKE9sAtRwOOWJBqiaQlKeUJ5oalpawlKeaMGqJSjlCeWJloalISjliQaomkJSnmgCy7AkYBAByhObyaI8sQlQw+GUJxqgagpJeUJ5oqlpaQlLeaIFq5aglCeUJ1oaloaglCcaoGoKSXmiCSzDkoBBBChPbCaL8sQmQA2HU55ogKopJOUJ5YmmpqUlLOWJFqxaglKeUJ5oaVgaglKeaICqKSTliSawDEsCBhGgPLGZLMoTmwA1HE4mCCD7AAAgAElEQVR5ogGqppCUJ5QnmpqWlrCUJ1qwaglKeUJ5oqVhaQhKeaIBqqaQlCeawDIsCRhEgPLEZrIoT2wC1HA45YkGqJpCUp5QnmhqWlrCUp5owaolKOUJ5YmWhqUhKOWJBqiaQlKeaALLsCRgEAHKEx+S9dvqvZj69gqcOhaPkhUK4YlBdZHvypzqSMoTHwA6vAvlicPAbRRHeUJ5YqP5OH4o5YnjyP0ukPKE8sTvxuPwgZQnDgO3URzliQ14PJQEQoQA5UkWiYw/k4T+Taei05B6KHN7UXz78Toc2n0SnYfeS3ni0ouA8sSlicmkWpQnlCfmtFaA8sScbFGeUJ6Y0lopT0zJFEB5Yk6uWFMS0EWA8iQLspuW7MKyr35Dj48bqT1FprxYfxI+WNoB0TkiOfJEV8u0EZfyxAY8hw+lPKE8cbjJ2SqO8sQWPkcPpjyhPHG0wdkojPLEBjyHD6U8cRg4iyMBFxKgPMkiKfMn/oJjB8+gdd8a3j173fc5eo5ujKIl81OeuLBRU564MCmXqBLlCeWJOa2VI09MyhXlCeWJKe2V8sSUTHHkiTmZYk1JQB8BypMs2M4evR4JZ5NRskJhjOu/GCNXdsSA5l+i01v1cV2FQvoyw8gkQALGEkhKTkV0VITf9U9JTUNkRLjfx/NAEiCB0CSQkpKGyEj/+4ak5DRER/l/fGhS5VmRAAmQAAmQgG8EKE+y4LTgs804tOcE6rSogJXf/oGWL1RT03Z6T2imRp5wIwESIAESIAESIAESIAESIAESIAESCG0ClCdZ5PeXZf/gh883o/f4pmrPk/+dVQvIDlvaAZHR/r9ZDu1mxbMjARIgARIgARIgARIgARIgARIggdAhQHmSRS4TzyajX5OpeOL1u1GuytX46v3VOHs6ER3fqBs6rYBnQgIkQAIkQAIkQAIkQAIkQAIkQAIkcEkClCc+NI7t6/ZjyuDlOHHkLMpWKorHX7sbufPn8OFI7kICJEACJEACJEACJEACJEACJEACJGA6AcoT0zNosf6jei7AVdfkQ/Pud3qPTE5MxedvLseW5bvV55cbPnk7aje/0WLk4Ow+d/wm9Snp1JQ0lK96Ndr2r4WYnFGqMr+t3oupb6/AqWPxKFmhEJ4YVBf5rswZnIpaKPXA38cxefBP2LfjGPIUjMVDXavitruvUxFMzpUHwY5fDuLdJ2ej17gmKF2xiNG5+uajdVj8xVZExfxvCl/PjxuheNkr1HnJmkkLJ29W7bNS/VJo3acGwiPCLLQGM3aVEXqvPPQl2vSvhVtqXuOt9H/7TuPTAUvx759HUaBwLrR9uZY3524+MzkfuQZ/W/0vIqMiVH8o/aJnMzWvl+tbTM3V+e1I7gezP1mP0Wuf8v61qfeBdzp+i/07j3v7i5jYKAyZ0zpk7gO+Xv+7t/2HwW1nYfjyx733dpPv75frW0y+v8sU95nD1+D0sXgUK1UAbfrVUv8rWyj0LcOe+x7paeno8XEjo+8D8lvk2TvHIVe+GO95VKhWwjuaPhRy5Wvfwv1IwF8ClCf+kjPsOPnc8ndjNmDTkl2o0eyGC+TJnDEb8M/vR9DprXpqTRf50fb8iAe8D4BuPdWtK/Zg6jsr0WdCU8TmjsaYvotUnZs9WwXxZ5LU2jSdhtRDmduL4tuP1+HQ7pPoPPRet56Ot16vPfKVeliTRYr/2ngAw7vNw9vz2iBnnmiYmivPycmNW8TJ0QOn8fTb9dWDtMm5kvZ3ZbE8qN/mlova1Z8bDihxIJIoV94YjOg+H7fXLYm6rW5yfRv0tYJpqelKjEx7ZwX2/30cHd+45wJ58t7T36H8HcXRoENF/LpyjxISg2c/6vr1omZ+uEYtFP7U4HqIO5WItx//Bu1eqa0Ercl5vVzfYmquPG1VfvR/9MIC1Q498sTkvkVyJaNcr7nhyosuR9PvA770LyIStq3Zqx7ID/5z4gJ5YnJeL9e3mJpXGZX9WsvpeH5kQ1x7YyHMm7AJW37ajb4Tm6lUm963rFuwU/2GvKJobq88MfU+cOZEglqKQGRkZpvpufKlb+E+JGCXAOWJXYIGHC/i5P1n5uDOhmWQkpSGlOTUC+TJ661moHXfGt43wl99sFqNQGnauYqrz+7vLYfUg3eF6iVUPZfP3Ibff/4Xz7x7r5JEMiLF85ZA9pOvJH2wtIM6N7duIhcWT92K+o/dgrDwcyMUuteZqB7Ary5dEKbmysP7h0mbgTBgzdy/8Gifc23O1FzJOU14ZSluqFIM1ZuUu6hJTXt3JfIUiPWOWJCRXQsmbVa5DJVt7fwdWDh5C+5teyt+nPm7+l/PyBP5kfZSoy8wbFkHRPz/p1XfbDMLD3erihvuuNrVCOTHcvEyBVH0+nNvTsf2W4xSt1ylxJepeb1c3yIj8kzNlachjeoxH3Va3oQRz8/zyhOT+5Y+D0xBr7FNcOXVeS66Vky/D/hy8ct1Ji88mj13x0UjT0zO6+X6FlPzKuJy5+aDqPpAGZXaf/84ig+enYP3F7eHyfcBORf57Si/n6Xv//n7P72/KU29DxzZe0qdj2cU2/nXoum58qVf4T4kEAgClCeBoGhQjO8+2YDE+OQL5Mlz1cfjrTmt1RQRj4TYvm6fGoli0jay+3y1Jo08wM2f+AtEGokU8my97vscPUc3NuYT00kJKfhp1jas+HY7Xp7ysHoANTlXkg95CH1xTGP1Y9gjT0zOlTywpSSnQX6QpKen464mN+CBjrepJje861wlVSrXL6X+LG9Phz41G0MXtjPpsvK5rkM7fXeBPNn162FMHLgMr81o6Y0h+S97e1FjpgVKxRPiZErSNHT5oIF6qxoKec3Yt+zZ/p/RuZKH6W1r96kH7Z73fOaVJyb3Ld1qfYob7yyOXVsPqTXWmj57h1dMmnwf8LlDOW/HpyuPuWDkicl5Pf/8M/YtoZBXeQAXsZAjVzTa9KsJ0+8Dci5lbiuqfn8t/fJXrzwx9T4gfb0I5mKlCkKmcRYtmV/9FityXX7jc+VP38JjSMAfApQn/lAz+JiM8iQ9HXimyhj1dnhI+69Rsc51KFqyANYv3ImuH95vzJl+P24jNi7+G30nPqjWn5g9ej0SziajZIXCGNd/MUau7IgBzb9Ep7fq47oKhVx/Xn+s348POs9B3ityqqlGJW8qDNNzNbrXD7i3XUVcf3NhDHp0hleemJwraXeyJsbdj1RQC0oPe3YOHuxSFVXuK6VESf02t2Lryj3Y++dRPDWkHga2mI4RK55wffvzp4IZ5Ym0YRnFJv1I7waT0W34/Vj3w04Uu74A7m13qz9FOH6MiLGPX1yAAoVzo03/mqp80/OaWd9icq4S41Pw/jPfofuohqqPPF+emNy3yH2r0j3X45Za12L72n34pM9CDPiyBQoWzRMS92wrF3NGeWJyXj3nnbFvMf3+Lucl045kerj8XukyrIGSfib3LSIavvtkPZ77oAFkTZfz5Ymp94EDu05g3qeb1OhmWZNGpljJfXngVy3x5wbz79lW+hXuSwL+EqA88ZecocdlNvKky13jMWhWK6z67g8UL3OFWo9CFvU0ZeSJ3LA3LP4bPT5qhLxXnBs9Iws6ypoFsm7Iym//QMsXqqlpO70nNDNm5InM+f79572YMuQnNdWjUPG8MDVXsj6N/OcZCXS+PAmFXHm6A/lRIkPNOwyso9aqqdqgtHpjdfxwHMpXLa7kSnYaeTL+5SVq1NTXI9eiTssK+GbUWvU23YQFqWV0xujeC9V6SvKpes/Uo1DIa8a+Rd4Wm5qrGcN+VkJcRnidPZ10gTwJpb7lwy5zcUeD0qjWqKyx9wF/fzZllCem5/VSfYup9/fz8yrX4PKZv+PnuX/hlS8ehggIE/sWWRz2/c5z0P7VOmrqXEZ5Egr3AcmbrFvWrdYEvDbjEZw6etbIXPnbr/A4EvCXAOWJv+QMPS4zeTKo9Uw0f/5OtRiibLKoY/4rc6JRp0quP0ux5puX71ZvtXPm/d/q4XKj++Hzzeg9vqk6B1kIVxaQHba0g6sXqzx9PAGrZv+B+9r/7828TA25tfZ1aqFfU3M1adCP2Pzjbu86LnEnE9Sw3vav1lb5MTFXUm8RQjINxfOFJxF5/+0/reTJ9PdWIzo2Ui1gLJvMdV8+63e88Elj119X/lQw48iTs6cS0avBZDXvPSb23DpDrz78pfoKg0yvc/Mm64PIl8lkgUD5QpJn/SGps6l5vVzfIgsZm5or+cqTrEugtvR0yHnKFFQZpSHrMJjYt8h0DnmBcdNd59bzkk0WcqzeuJySJ6beB/y95jPKE1Pv73L+l+tbTM3r7t+P4PC/p9SIS88m085EnOfOF2Nk3yJTcd94bCaiYs7du1KSUiHSS0bVyMssU+8DRw+cUZJEzsPTHrvWmIBBX7dCbK4oI3Plb7/C40jAXwKUJ/6SM/S4zOSJCIg/Nx7AM+/Uh3Ss8iPtxbFNXD9CQ75EM+alRepHsgwPPX+TzwHKiuLyxrhclavx1furcfZ0ovdzbG5Nn9ygZaHAVr3uUj9EZJ0M+TqNDBuV6S6m5ioj7/NHnpiaKzknWXhNvoYhn5MWaSLXzqO971LT33ZuPqTapyz6KGLvwy7fKwFW88Hybm1+tuqVUZ5IMPm84/U3X6UWzd2w6G81AuWNb1p5R3HYKlDjwTIdS4Ywd/+oEcIyfFna1Lxm1beYmqvzm0HGkSem9i0yFanP/ZOVhJW+5NeV/2JM34V4fVYr5C+UM2TuA75ewhnlial5lfO9XN9i6v1d5MmHXefixTFN1FSQjYt3QV6YDP2hrXpZFQp9S8aRJ6beB/7adFBNAew9ThajzovvxqyHLGb/ytTm6nIMhVz52q9wPxLwlwDlib/kDDou7mSiWvBQNjHnsskXZ6rcV1o96Mnc28lvLsempbsQExuFB7vcod5uuX2TL51sWLTT+9Zf6is3g36THlRV375uP6YMXq7WopA33fLZx4ySxY3nKF8RmjZ0FQ7vOammDMhncD2ftzU1V5eTJybnSmSjXDuyKJ6Mrqj32C0XfLZ40ZStmD9xk7rG5K1xi57VLnoYd2Mb9LVO8qNr4mvL1O7y9l/6FZne8mjvGkr+ySLBE15Zgt3b/lPTztoPqINry1/86VVfy3NqPxGY8acTLxilducDZdX0P9lMzevl+hZTc3U5eWJy3yL3r+nvrVLTaAsWyY3m3auhQrXi6nRD5T5wuet51og1WPHNdrWL/IbJle/cyFIZzSA8TL2/X65vMTmvMj167oSNKlcyYq9Fj2rer6qFQt+SUZ6YfB9YMu1XNSJP7tnX3VgIbfrXUvdn2UIhV079TmA52ZcA5Un2zT3PnARIgARIgARIgARIgARIgARIgARIwAcClCc+QOIuJEACJEACJEACJEACJEACJEACJEAC2ZcA5Un2zT3PnARIgARIgARIgARIgARIgARIgARIwAcClCc+QOIuJEACJEACJEACJEACJEACJEACJEAC2ZcA5Un2zT3PnARIgARIgARIgARIgARIgARIgARIwAcClCc+QOIuJEACJEACJEACJEACJEACJEACJEAC2ZcA5Un2zT3PnARIgARIgARIgARIgARIgARIgARIwAcClCc+QOIuJEACJEACJEACJEACJEACJEACJEAC2ZcA5Un2zT3PnARIgARIgARIgARIgARIgARIgARIwAcClCc+QOIuJEACJEACJEACJEACJEACJEACJEAC2ZcA5Un2zT3PnARIgARIgARIgARIgARIgARIgARIwAcClCc+QOIuJEACJEACJEACJEACJEACJEACJEAC2ZcA5Un2zT3PnARIgARIgARIgARIgARIgARIgARIwAcClCc+QOIuJEACJEACJEACJEACJEACJEACJEAC2ZcA5Un2zT3PnARIgARIgARIgARIgARIgARIgARIwAcClCc+QOIuJEACJEACJEACJEACJEACJEACJEAC2ZcA5Un2zT3PnARIgARIgARIgARIgARIgARIgARIwAcClCc+QOIu2ZfA5ME/ISUpFR0G1nENhB2/HMS7T87GJ+s7uaZOrAgJkIA1Aq8+/CUadKiI6o3LWTtQ497fj9uIbWv34cUxjTWWwtAkQAK6CJz87yx6N5iMwbMfxRXF8ugqxnLcDzrPQemKRdH46UqWj+UBJEAC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", + "text/html": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import plotly.express as px\n", + "\n", + "# obtained from executing using Covalent and federated learning for 50 rounds\n", + "df_ind = pd.read_csv(\"assets/individual_test_accuracies.csv\")\n", + "\n", + "# obtained from executing without federated learning for 50 rounds independently\n", + "df_fed = pd.read_csv(\"assets/federated_test_accuracies.csv\")\n", + "\n", + "df = pd.concat([df_ind, df_fed], axis=0)\n", + "\n", + "\n", + "ds_mapping = {\n", + " \"('keremberke/chest-xray-classification', 'full')\":\n", + " \"chest-xray-classification\",\n", + " \"('mmenendezg/raw_pneumonia_x_ray',)\": \"raw_pneumonia_x_ray\",\n", + " \"('alkzar90/NIH-Chest-X-ray-dataset', 'image-classification')\":\n", + " \"NIH-Chest-X-ray-dataset\",\n", + "}\n", + "df['dataset'] = df['dataset'].apply(\n", + " lambda x: ds_mapping[x]\n", + ")\n", + "method_mapping = {\n", + " \"individual\": \"Standard ML\",\n", + " \"federated\": \"Federated Learning\",\n", + "}\n", + "df['method'] = df['method'].apply(\n", + " lambda x: method_mapping[x]\n", + ")\n", + "\n", + "fig = px.line(\n", + " df, x=\"round\", y=\"test_accuracy\",\n", + " facet_col=\"dataset\", color=\"method\",\n", + ")\n", + "\n", + "fig.update_layout(\n", + " title=\"Average test accuracy over 50 rounds\",\n", + " xaxis_title=\"Round number\",\n", + " xaxis_range=[1, 50],\n", + " yaxis_range=[0, 1],\n", + " xaxis2_title=\"Round number\",\n", + " xaxis3_title=\"Round number\",\n", + " yaxis_title=\"Test dataset accuracy\",\n", + " legend_title=\"Training method\",\n", + " font=dict(\n", + " family=\"Courier New, monospace\",\n", + " size=12,\n", + " color=\"RebeccaPurple\"\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "09d56bc7-3cfc-4a00-8ef4-ed86442a0647", + "metadata": {}, + "source": [ + "In an attempt to comprehend the reasons behind the federated model performance, we generate feature maps using the convolutional layer for separate models (upper row) and the federated learning model (lower row). The visual representations offer insights into the evolution of specialized and distinct filters by individual classifiers, whereas the federated model illustrates traits that span across all individual models.\n", + "\n", + "![alt text](assets/feature_visualization.png)" + ] + }, + { + "cell_type": "markdown", + "id": "00229014-f194-44ed-a9f5-2ab5a30df439", + "metadata": {}, + "source": [ + "# Conclusion\n", + "Leveraging Covalent, we established a federated learning framework across three cloud computing resources while maintaining strict data isolation protocols. This allowed us to build an X-ray pneumonia classifier seamlessly by utilizing dynamic sublattices for on-the-fly allocation of compute resources, even with heterogeneous datasets.\n", + "\n", + "The Covalent-enabled design of the federated learning experiment simplifies adding datasets, adjusting training hyperparameters, and altering aggregation technique. The workflow ensures reproducibility with secure metadata storage in a scalable database.\n", + "This blog post aims to showcase the remarkable potential of Covalent in conjunction with various resources such as AWS Batch, Azure Batch, and GCP Batch. \n", + "\n", + "[Covalent](https://github.com/AgnostiqHQ/covalent/) is free and [open source](https://www.covalent.xyz/open-source/). Please visit the Covalent documentation for more information and many more tutorials. " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/doc/source/tutorials/tutorials.rst b/doc/source/tutorials/tutorials.rst index afecaa3a3..e426f1cca 100644 --- a/doc/source/tutorials/tutorials.rst +++ b/doc/source/tutorials/tutorials.rst @@ -73,6 +73,8 @@ Advanced - :doc:`Classifying discrete spacetimes by dimension<./4_QuantumGravity/spacetime_classification/source>` * - Generative AI/LLM - :doc:`Scalable API backends for LLM and generative AI <./0_ClassicalMachineLearning/genai/source>` + * - Federated learning + - :doc:`Federated learning <./federated_learning/source>` ---------------------------------