diff --git a/.secrets.baseline b/.secrets.baseline index 857d311a..bd9bdadc 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "^.secrets.baseline$|^.*pgsslrootcert.yml$", "lines": null }, - "generated_at": "2019-12-18T22:26:52Z", + "generated_at": "2020-01-09T16:55:07Z", "plugins_used": [ { "base64_limit": 4.5, @@ -25,15 +25,6 @@ } ], "results": { - "Pipfile.lock": [ - { - "hashed_secret": "526c14b5cd73155d72784fec39907f9b7d5ddcdd", - "is_secret": false, - "is_verified": false, - "line_number": 4, - "type": "Hex High Entropy String" - } - ], "README.md": [ { "hashed_secret": "d141ce86b0584abb29ee7c24af9afb1e3d871f04", @@ -111,15 +102,6 @@ "type": "Secret Keyword" } ], - "ssl/certificate-authority/ca.key": [ - { - "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", - "is_secret": false, - "is_verified": false, - "line_number": 1, - "type": "Private Key" - } - ], "ssl/client-certs/atat.mil.key": [ { "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", diff --git a/Pipfile b/Pipfile index ed87d000..0de14fa2 100644 --- a/Pipfile +++ b/Pipfile @@ -8,7 +8,9 @@ webassets = "*" Unipath = "*" pendulum = "*" redis = "*" -sqlalchemy = ">=1.3.0" +sqlalchemy = ">=1.3.12" +sqlalchemy-json = "*" +pydantic = "*" alembic = "*" "psycopg2-binary" = "*" flask = "*" @@ -30,6 +32,7 @@ msrestazure = "*" azure-mgmt-authorization = "*" azure-mgmt-managementgroups = "*" azure-mgmt-resource = "*" +transitions = "*" [dev-packages] bandit = "*" diff --git a/Pipfile.lock b/Pipfile.lock index d30bcbb2..ef6d0203 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c203c47b00f413fd40056ef6d2d8e51b37ad3ff5f7693db5eb170b7f8fd43234" + "sha256": "63b8f9d203f306a6f0ff20514b024909aa7e64917e1befcc9ea79931b5b4bd34" }, "pipfile-spec": 6, "requires": { @@ -39,10 +39,10 @@ }, "azure-common": { "hashes": [ - "sha256:53b1195b8f20943ccc0e71a17849258f7781bc6db1c72edc7d6c055f79bd54e3", - "sha256:99ef36e74b6395329aada288764ce80504da16ecc8206cb9a72f55fb02e8b484" + "sha256:184ad6a05a3089dfdc1ce07c1cbfa489bbc45b5f6f56e848cac0851e6443da21", + "sha256:3d64e9ab995300f42abd5bc0ef02f02bab661321e394d4dbacb4382ea1fb2f72" ], - "version": "==1.1.23" + "version": "==1.1.24" }, "azure-graphrbac": { "hashes": [ @@ -218,10 +218,11 @@ }, "flask-assets": { "hashes": [ - "sha256:6031527b89fb3509d1581d932affa5a79dd348cfffb58d0aef99a43461d47847" + "sha256:1dfdea35e40744d46aada72831f7613d67bf38e8b20ccaaa9e91fdc37aa3b8c2", + "sha256:2845bd3b479be9db8556801e7ebc2746ce2d9edb4e7b64a1c786ecbfc1e5867b" ], "index": "pypi", - "version": "==0.12" + "version": "==2.0" }, "flask-session": { "hashes": [ @@ -256,11 +257,11 @@ }, "importlib-metadata": { "hashes": [ - "sha256:073a852570f92da5f744a3472af1b61e28e9f78ccf0c9117658dc32b15de7b45", - "sha256:d95141fbfa7ef2ec65cfd945e2af7e5a6ddbd7c8d9a25e66ff3be8e3daf9f60f" + "sha256:bdd9b7c397c273bcc9a11d6629a38487cd07154fa255a467bf704cd2c258e359", + "sha256:f17c015735e1a88296994c0697ecea7e11db24290941983b08c9feb30921e6d8" ], "markers": "python_version < '3.8'", - "version": "==1.3.0" + "version": "==1.4.0" }, "isodate": { "hashes": [ @@ -339,10 +340,10 @@ }, "more-itertools": { "hashes": [ - "sha256:b84b238cce0d9adad5ed87e745778d20a3f8487d0f0cb8b8a586816c7496458d", - "sha256:c833ef592a0324bcc6a60e48440da07645063c453880c9477ceb22490aec1564" + "sha256:1a2a32c72400d365000412fe08eb4a24ebee89997c18d3d147544f70f5403b39", + "sha256:c468adec578380b6281a114cb8a5db34eb1116277da92d7c46f904f0b52d3288" ], - "version": "==8.0.2" + "version": "==8.1.0" }, "msrest": { "hashes": [ @@ -422,6 +423,26 @@ ], "version": "==2.19" }, + "pydantic": { + "hashes": [ + "sha256:176885123dfdd8f7ab6e7ba1b66d4197de75ba830bb44d921af88b3d977b8aa5", + "sha256:2b32a5f14558c36e39aeefda0c550bfc0f47fc32b4ce16d80dc4df2b33838ed8", + "sha256:2eab7d548b0e530bf65bee7855ad8164c2f6a889975d5e9c4eefd1e7c98245dc", + "sha256:479ca8dc7cc41418751bf10302ee0a1b1f8eedb2de6c4f4c0f3cf8372b204f9a", + "sha256:59235324dd7dc5363a654cd14271ea8631f1a43de5d4fc29c782318fcc498002", + "sha256:87673d1de790c8d5282153cab0b09271be77c49aabcedf3ac5ab1a1fd4dcbac0", + "sha256:8a8e089aec18c26561e09ee6daf15a3cc06df05bdc67de60a8684535ef54562f", + "sha256:b60f2b3b0e0dd74f1800a57d1bbd597839d16faf267e45fa4a5407b15d311085", + "sha256:c0da48978382c83f9488c6bbe4350e065ea5c83e85ca5cfb8fa14ac11de3c296", + "sha256:cbe284bd5ad67333d49ecc0dc27fa52c25b4c2fe72802a5c060b5f922db58bef", + "sha256:d03df07b7611004140b0fef91548878c2b5f48c520a8cb76d11d20e9887a495e", + "sha256:d4bb6a75abc2f04f6993124f1ed4221724c9dc3bd9df5cb54132e0b68775d375", + "sha256:dacb79144bb3fdb57cf9435e1bd16c35586bc44256215cfaa33bf21565d926ae", + "sha256:dd9359db7644317898816f6142f378aa48848dcc5cf14a481236235fde11a148" + ], + "index": "pypi", + "version": "==1.3" + }, "pyjwt": { "hashes": [ "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e", @@ -468,20 +489,20 @@ }, "pyyaml": { "hashes": [ - "sha256:0e7f69397d53155e55d10ff68fdfb2cf630a35e6daf65cf0bdeaf04f127c09dc", - "sha256:2e9f0b7c5914367b0916c3c104a024bb68f269a486b9d04a2e8ac6f6597b7803", - "sha256:35ace9b4147848cafac3db142795ee42deebe9d0dad885ce643928e88daebdcc", - "sha256:38a4f0d114101c58c0f3a88aeaa44d63efd588845c5a2df5290b73db8f246d15", - "sha256:483eb6a33b671408c8529106df3707270bfacb2447bf8ad856a4b4f57f6e3075", - "sha256:4b6be5edb9f6bb73680f5bf4ee08ff25416d1400fbd4535fe0069b2994da07cd", - "sha256:7f38e35c00e160db592091751d385cd7b3046d6d51f578b29943225178257b31", - "sha256:8100c896ecb361794d8bfdb9c11fce618c7cf83d624d73d5ab38aef3bc82d43f", - "sha256:c0ee8eca2c582d29c3c2ec6e2c4f703d1b7f1fb10bc72317355a746057e7346c", - "sha256:e4c015484ff0ff197564917b4b4246ca03f411b9bd7f16e02a2f586eb48b6d04", - "sha256:ebc4ed52dcc93eeebeae5cf5deb2ae4347b3a81c3fa12b0b8c976544829396a4" + "sha256:059b2ee3194d718896c0ad077dd8c043e5e909d9180f387ce42012662a4946d6", + "sha256:1cf708e2ac57f3aabc87405f04b86354f66799c8e62c28c5fc5f88b5521b2dbf", + "sha256:24521fa2890642614558b492b473bee0ac1f8057a7263156b02e8b14c88ce6f5", + "sha256:4fee71aa5bc6ed9d5f116327c04273e25ae31a3020386916905767ec4fc5317e", + "sha256:70024e02197337533eef7b85b068212420f950319cc8c580261963aefc75f811", + "sha256:74782fbd4d4f87ff04159e986886931456a1894c61229be9eaf4de6f6e44b99e", + "sha256:940532b111b1952befd7db542c370887a8611660d2b9becff75d39355303d82d", + "sha256:cb1f2f5e426dc9f07a7681419fe39cee823bb74f723f36f70399123f439e9b20", + "sha256:dbbb2379c19ed6042e8f11f2a2c66d39cceb8aeace421bfc29d085d93eda3689", + "sha256:e3a057b7a64f1222b56e47bcff5e4b94c4f61faac04c7c4ecb1985e18caa3994", + "sha256:e9f45bd5b92c7974e59bcd2dcc8631a6b6cc380a904725fce7bc08872e691615" ], "index": "pypi", - "version": "==5.2" + "version": "==5.3" }, "redis": { "hashes": [ @@ -520,6 +541,27 @@ "index": "pypi", "version": "==1.3.12" }, + "sqlalchemy-json": { + "hashes": [ + "sha256:d17952e771eecd9023c0f683d2a6aaa27ce1a6dbf57b0fe2bf4d5aef4c5dad1c" + ], + "index": "pypi", + "version": "==0.2.3" + }, + "sqlalchemy-utils": { + "hashes": [ + "sha256:4e637c88bf3ac5f99b7d72342092a1f636bea1287b2e3e17d441b0413771f86e" + ], + "version": "==0.36.1" + }, + "transitions": { + "hashes": [ + "sha256:011afaefa1244177cad3d960d836c0c4a201403252371bd4c555cf8c17ce7d3c", + "sha256:5566c9d32e438ee9eb1f046e3ac1a0b2689f32807b47859210162084d4c84ab7" + ], + "index": "pypi", + "version": "==0.7.2" + }, "unipath": { "hashes": [ "sha256:09839adcc72e8a24d4f76d63656f30b5a1f721fc40c9bcd79d8c67bdd8b47dae", @@ -544,10 +586,11 @@ }, "webassets": { "hashes": [ - "sha256:e7d9c8887343123fd5b32309b33167428cb1318cdda97ece12d0907fd69d38db" + "sha256:167132337677c8cedc9705090f6d48da3fb262c8e0b2773b29f3352f050181cd", + "sha256:a31a55147752ba1b3dc07dee0ad8c8efff274464e08bbdb88c1fd59ffd552724" ], "index": "pypi", - "version": "==0.12.1" + "version": "==2.0" }, "werkzeug": { "hashes": [ @@ -566,10 +609,10 @@ }, "zipp": { "hashes": [ - "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", - "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335" + "sha256:8dda78f06bd1674bd8720df8a50bb47b6e1233c503a4eed8e7810686bde37656", + "sha256:d38fbe01bbf7a3593a32bc35a9c4453c32bc42b98c377f9bff7e9f8da157786c" ], - "version": "==0.6.0" + "version": "==1.0.0" } }, "develop": { @@ -633,12 +676,12 @@ }, "beautifulsoup4": { "hashes": [ - "sha256:5279c36b4b2ec2cb4298d723791467e3000e5384a43ea0cdf5d45207c7e97169", - "sha256:6135db2ba678168c07950f9a16c4031822c6f4aec75a65e0a97bc5ca09789931", - "sha256:dcdef580e18a76d54002088602eba453eec38ebbcafafeaabd8cab12b6155d57" + "sha256:05fd825eb01c290877657a56df4c6e4c311b3965bda790c613a3d6fb01a5462a", + "sha256:9fbb4d6e48ecd30bcacc5b63b94088192dcda178513b2ae3c394229f8911b887", + "sha256:e1505eeed31b0f4ce2dbb3bc8eb256c04cc2b3b72af7d551a4ab6efd5cbe5dae" ], "index": "pypi", - "version": "==4.8.1" + "version": "==4.8.2" }, "black": { "hashes": [ @@ -685,39 +728,39 @@ }, "coverage": { "hashes": [ - "sha256:0cd13a6e98c37b510a2d34c8281d5e1a226aaf9b65b7d770ef03c63169965351", - "sha256:1a4b6b6a2a3a6612e6361130c2cc3dc4378d8c221752b96167ccbad94b47f3cd", - "sha256:2ee55e6dba516ddf6f484aa83ccabbb0adf45a18892204c23486938d12258cde", - "sha256:3be5338a2eb4ef03c57f20917e1d12a1fd10e3853fed060b6d6b677cb3745898", - "sha256:44b783b02db03c4777d8cf71bae19eadc171a6f2a96777d916b2c30a1eb3d070", - "sha256:475bf7c4252af0a56e1abba9606f1e54127cdf122063095c75ab04f6f99cf45e", - "sha256:47c81ee687eafc2f1db7f03fbe99aab81330565ebc62fb3b61edfc2216a550c8", - "sha256:4a7f8e72b18f2aca288ff02255ce32cc830bc04d993efbc87abf6beddc9e56c0", - "sha256:50197163a22fd17f79086e087a787883b3ec9280a509807daf158dfc2a7ded02", - "sha256:56b13000acf891f700f5067512b804d1ec8c301d627486c678b903859d07f798", - "sha256:79388ae29c896299b3567965dbcd93255f175c17c6c7bca38614d12718c47466", - "sha256:79fd5d3d62238c4f583b75d48d53cdae759fe04d4fb18fe8b371d88ad2b6f8be", - "sha256:7fe3e2fde2bf1d7ce25ebcd2d3de3650b8d60d9a73ce6dcef36e20191291613d", - "sha256:81042a24f67b96e4287774014fa27220d8a4d91af1043389e4d73892efc89ac6", - "sha256:81326f1095c53111f8afc95da281e1414185f4a538609a77ca50bdfa39a6c207", - "sha256:8873dc0d8f42142ea9f20c27bbdc485190fff93823c6795be661703369e5877d", - "sha256:88d2cbcb0a112f47eef71eb95460b6995da18e6f8ca50c264585abc2c473154b", - "sha256:91f2491aeab9599956c45a77c5666d323efdec790bfe23fcceafcd91105d585a", - "sha256:979daa8655ae5a51e8e7a24e7d34e250ae8309fd9719490df92cbb2fe2b0422b", - "sha256:9c871b006c878a890c6e44a5b2f3c6291335324b298c904dc0402ee92ee1f0be", - "sha256:a6d092545e5af53e960465f652e00efbf5357adad177b2630d63978d85e46a72", - "sha256:b5ed7837b923d1d71c4f587ae1539ccd96bfd6be9788f507dbe94dab5febbb5d", - "sha256:ba259f68250f16d2444cbbfaddaa0bb20e1560a4fdaad50bece25c199e6af864", - "sha256:be1d89614c6b6c36d7578496dc8625123bda2ff44f224cf8b1c45b810ee7383f", - "sha256:c1b030a79749aa8d1f1486885040114ee56933b15ccfc90049ba266e4aa2139f", - "sha256:c95bb147fab76f2ecde332d972d8f4138b8f2daee6c466af4ff3b4f29bd4c19e", - "sha256:d52c1c2d7e856cecc05aa0526453cb14574f821b7f413cc279b9514750d795c1", - "sha256:d609a6d564ad3d327e9509846c2c47f170456344521462b469e5cb39e48ba31c", - "sha256:e1bad043c12fb58e8c7d92b3d7f2f49977dcb80a08a6d1e7a5114a11bf819fca", - "sha256:e5a675f6829c53c87d79117a8eb656cc4a5f8918185a32fc93ba09778e90f6db", - "sha256:fec32646b98baf4a22fdceb08703965bd16dea09051fbeb31a04b5b6e72b846c" + "sha256:15cf13a6896048d6d947bf7d222f36e4809ab926894beb748fc9caa14605d9c3", + "sha256:1daa3eceed220f9fdb80d5ff950dd95112cd27f70d004c7918ca6dfc6c47054c", + "sha256:1e44a022500d944d42f94df76727ba3fc0a5c0b672c358b61067abb88caee7a0", + "sha256:25dbf1110d70bab68a74b4b9d74f30e99b177cde3388e07cc7272f2168bd1477", + "sha256:3230d1003eec018ad4a472d254991e34241e0bbd513e97a29727c7c2f637bd2a", + "sha256:3dbb72eaeea5763676a1a1efd9b427a048c97c39ed92e13336e726117d0b72bf", + "sha256:5012d3b8d5a500834783689a5d2292fe06ec75dc86ee1ccdad04b6f5bf231691", + "sha256:51bc7710b13a2ae0c726f69756cf7ffd4362f4ac36546e243136187cfcc8aa73", + "sha256:527b4f316e6bf7755082a783726da20671a0cc388b786a64417780b90565b987", + "sha256:722e4557c8039aad9592c6a4213db75da08c2cd9945320220634f637251c3894", + "sha256:76e2057e8ffba5472fd28a3a010431fd9e928885ff480cb278877c6e9943cc2e", + "sha256:77afca04240c40450c331fa796b3eab6f1e15c5ecf8bf2b8bee9706cd5452fef", + "sha256:7afad9835e7a651d3551eab18cbc0fdb888f0a6136169fbef0662d9cdc9987cf", + "sha256:9bea19ac2f08672636350f203db89382121c9c2ade85d945953ef3c8cf9d2a68", + "sha256:a8b8ac7876bc3598e43e2603f772d2353d9931709345ad6c1149009fd1bc81b8", + "sha256:b0840b45187699affd4c6588286d429cd79a99d509fe3de0f209594669bb0954", + "sha256:b26aaf69713e5674efbde4d728fb7124e429c9466aeaf5f4a7e9e699b12c9fe2", + "sha256:b63dd43f455ba878e5e9f80ba4f748c0a2156dde6e0e6e690310e24d6e8caf40", + "sha256:be18f4ae5a9e46edae3f329de2191747966a34a3d93046dbdf897319923923bc", + "sha256:c312e57847db2526bc92b9bfa78266bfbaabac3fdcd751df4d062cd4c23e46dc", + "sha256:c60097190fe9dc2b329a0eb03393e2e0829156a589bd732e70794c0dd804258e", + "sha256:c62a2143e1313944bf4a5ab34fd3b4be15367a02e9478b0ce800cb510e3bbb9d", + "sha256:cc1109f54a14d940b8512ee9f1c3975c181bbb200306c6d8b87d93376538782f", + "sha256:cd60f507c125ac0ad83f05803063bed27e50fa903b9c2cfee3f8a6867ca600fc", + "sha256:d513cc3db248e566e07a0da99c230aca3556d9b09ed02f420664e2da97eac301", + "sha256:d649dc0bcace6fcdb446ae02b98798a856593b19b637c1b9af8edadf2b150bea", + "sha256:d7008a6796095a79544f4da1ee49418901961c97ca9e9d44904205ff7d6aa8cb", + "sha256:da93027835164b8223e8e5af2cf902a4c80ed93cb0909417234f4a9df3bcd9af", + "sha256:e69215621707119c6baf99bda014a45b999d37602cb7043d943c76a59b05bf52", + "sha256:ea9525e0fef2de9208250d6c5aeeee0138921057cd67fcef90fbed49c4d62d37", + "sha256:fca1669d464f0c9831fd10be2eef6b86f5ebd76c724d1e0706ebdff86bb4adf0" ], - "version": "==5.0" + "version": "==5.0.3" }, "decorator": { "hashes": [ @@ -750,10 +793,10 @@ }, "faker": { "hashes": [ - "sha256:202ad3b2ec16ae7c51c02904fb838831f8d2899e61bf18db1e91a5a582feab11", - "sha256:92c84a10bec81217d9cb554ee12b3838c8986ce0b5d45f72f769da22e4bb5432" + "sha256:047d4d1791bfb3756264da670d99df13d799bb36e7d88774b1585a82d05dbaec", + "sha256:1b1a58961683b30c574520d0c739c4443e0ef6a185c04382e8cc888273dbebed" ], - "version": "==3.0.0" + "version": "==4.0.0" }, "flask": { "hashes": [ @@ -794,11 +837,11 @@ }, "importlib-metadata": { "hashes": [ - "sha256:073a852570f92da5f744a3472af1b61e28e9f78ccf0c9117658dc32b15de7b45", - "sha256:d95141fbfa7ef2ec65cfd945e2af7e5a6ddbd7c8d9a25e66ff3be8e3daf9f60f" + "sha256:bdd9b7c397c273bcc9a11d6629a38487cd07154fa255a467bf704cd2c258e359", + "sha256:f17c015735e1a88296994c0697ecea7e11db24290941983b08c9feb30921e6d8" ], "markers": "python_version < '3.8'", - "version": "==1.3.0" + "version": "==1.4.0" }, "ipdb": { "hashes": [ @@ -809,11 +852,11 @@ }, "ipython": { "hashes": [ - "sha256:190a279bd3d4fc585a611e9358a88f1048cc57fd688254a86f9461889ee152a6", - "sha256:762d79a62b6aa96b04971e920543f558dfbeedc0468b899303c080c8068d4ac2" + "sha256:0f4bcf18293fb666df8511feec0403bdb7e061a5842ea6e88a3177b0ceb34ead", + "sha256:387686dd7fc9caf29d2fddcf3116c4b07a11d9025701d220c589a430b0171d8a" ], "index": "pypi", - "version": "==7.10.2" + "version": "==7.11.1" }, "ipython-genutils": { "hashes": [ @@ -838,10 +881,10 @@ }, "jedi": { "hashes": [ - "sha256:786b6c3d80e2f06fd77162a07fed81b8baa22dde5d62896a790a331d6ac21a27", - "sha256:ba859c74fa3c966a22f2aeebe1b74ee27e2a462f56d3f5f7ca4a59af61bfe42e" + "sha256:1349c1e8c107095a55386628bb3b2a79422f3a2cab8381e34ce19909e0cf5064", + "sha256:e909527104a903606dd63bea6e8e888833f0ef087057829b89a18364a856f807" ], - "version": "==0.15.1" + "version": "==0.15.2" }, "jinja2": { "hashes": [ @@ -918,29 +961,30 @@ }, "more-itertools": { "hashes": [ - "sha256:b84b238cce0d9adad5ed87e745778d20a3f8487d0f0cb8b8a586816c7496458d", - "sha256:c833ef592a0324bcc6a60e48440da07645063c453880c9477ceb22490aec1564" + "sha256:1a2a32c72400d365000412fe08eb4a24ebee89997c18d3d147544f70f5403b39", + "sha256:c468adec578380b6281a114cb8a5db34eb1116277da92d7c46f904f0b52d3288" ], - "version": "==8.0.2" + "version": "==8.1.0" }, "mypy": { "hashes": [ - "sha256:0308c35fd16c96a81b8dfc4d09ec63b8fa607cfec087acf5aafb44c2c45197de", - "sha256:39f7be2f89668d21b2bbab45ce5aa15e69bf8d6f3b46f9e1cc1a88e4fcc84f3d", - "sha256:4223f576813c79a10d0fd14192c86f1b85e3bd235c93792f22ed811a20b5ee4e", - "sha256:4c8f812a2fbefa96185933fbe05aa035e9cf791cf3a23bbdb6a219c80b60e0b1", - "sha256:4ea9ee847ea5bb38ea275441f3aea7eeba1b96187a3f968ee359d33d9dcc0eda", - "sha256:573c68df69f0e399fa57866a0b72989acf0a56c4008eee59c789c2ca5ea9df03", - "sha256:588c0e38466306aa7dbe6522ceacf37dde8b13cfa5edde90be2ce382f078875f", - "sha256:6d1bd2e675823a19e6bf72149540ab9851bfe698b796aea698fb926ab2bedd02", - "sha256:aa8e3bd1540dd5c39ef580ec2146a9c99c45f7c62af890095fec9e87b5ca19fb", - "sha256:b978ba1ea90d0abe2fc720ec9a41824b7d3a1304569bd58c9038d8d61dc4dfdb", - "sha256:c85c5367c2e8247e06cc0aba84e3633e90f48e8a0677bc51b351e138b5ff80b1", - "sha256:ce69577b424058bfa177df27213869f37c1e964c3e1ebd3b3d54f1d10b234c4d", - "sha256:ec6eaf98a57624d96d9916352a5bad2d73959f6358fabf43838f7d1a4d2f8389" + "sha256:0a9a45157e532da06fe56adcfef8a74629566b607fa2c1ac0122d1ff995c748a", + "sha256:2c35cae79ceb20d47facfad51f952df16c2ae9f45db6cb38405a3da1cf8fc0a7", + "sha256:4b9365ade157794cef9685791032521233729cb00ce76b0ddc78749abea463d2", + "sha256:53ea810ae3f83f9c9b452582261ea859828a9ed666f2e1ca840300b69322c474", + "sha256:634aef60b4ff0f650d3e59d4374626ca6153fcaff96ec075b215b568e6ee3cb0", + "sha256:7e396ce53cacd5596ff6d191b47ab0ea18f8e0ec04e15d69728d530e86d4c217", + "sha256:7eadc91af8270455e0d73565b8964da1642fe226665dd5c9560067cd64d56749", + "sha256:7f672d02fffcbace4db2b05369142e0506cdcde20cea0e07c7c2171c4fd11dd6", + "sha256:85baab8d74ec601e86134afe2bcccd87820f79d2f8d5798c889507d1088287bf", + "sha256:87c556fb85d709dacd4b4cb6167eecc5bbb4f0a9864b69136a0d4640fdc76a36", + "sha256:a6bd44efee4dc8c3324c13785a9dc3519b3ee3a92cada42d2b57762b7053b49b", + "sha256:c6d27bd20c3ba60d5b02f20bd28e20091d6286a699174dfad515636cb09b5a72", + "sha256:e2bb577d10d09a2d8822a042a23b8d62bc3b269667c9eb8e60a6edfa000211b1", + "sha256:f97a605d7c8bc2c6d1172c2f0d5a65b24142e11a58de689046e62c2d632ca8c1" ], "index": "pypi", - "version": "==0.760" + "version": "==0.761" }, "mypy-extensions": { "hashes": [ @@ -958,9 +1002,10 @@ }, "pathspec": { "hashes": [ - "sha256:e285ccc8b0785beadd4c18e5708b12bb8fcf529a1e61215b3feff1d1e559ea5c" + "sha256:163b0632d4e31cef212976cf57b43d9fd6b0bac6e67c26015d611a647d5e7424", + "sha256:562aa70af2e0d434367d9790ad37aed893de47f1693e4201fd1d3dca15d19b96" ], - "version": "==0.6.0" + "version": "==0.7.0" }, "pathtools": { "hashes": [ @@ -1013,10 +1058,10 @@ }, "py": { "hashes": [ - "sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", - "sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53" + "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa", + "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0" ], - "version": "==1.8.0" + "version": "==1.8.1" }, "pygments": { "hashes": [ @@ -1066,11 +1111,11 @@ }, "pytest-mock": { "hashes": [ - "sha256:67e414b3caef7bff6fc6bd83b22b5bc39147e4493f483c2679bc9d4dc485a94d", - "sha256:e24a911ec96773022ebcc7030059b57cd3480b56d4f5d19b7c370ec635e6aed5" + "sha256:b35eb281e93aafed138db25c8772b95d3756108b601947f89af503f8c629413f", + "sha256:cb67402d87d5f53c579263d37971a164743dc33c159dfb4fb4a86f37c5552307" ], "index": "pypi", - "version": "==1.13.0" + "version": "==2.0.0" }, "pytest-watch": { "hashes": [ @@ -1088,46 +1133,46 @@ }, "pyyaml": { "hashes": [ - "sha256:0e7f69397d53155e55d10ff68fdfb2cf630a35e6daf65cf0bdeaf04f127c09dc", - "sha256:2e9f0b7c5914367b0916c3c104a024bb68f269a486b9d04a2e8ac6f6597b7803", - "sha256:35ace9b4147848cafac3db142795ee42deebe9d0dad885ce643928e88daebdcc", - "sha256:38a4f0d114101c58c0f3a88aeaa44d63efd588845c5a2df5290b73db8f246d15", - "sha256:483eb6a33b671408c8529106df3707270bfacb2447bf8ad856a4b4f57f6e3075", - "sha256:4b6be5edb9f6bb73680f5bf4ee08ff25416d1400fbd4535fe0069b2994da07cd", - "sha256:7f38e35c00e160db592091751d385cd7b3046d6d51f578b29943225178257b31", - "sha256:8100c896ecb361794d8bfdb9c11fce618c7cf83d624d73d5ab38aef3bc82d43f", - "sha256:c0ee8eca2c582d29c3c2ec6e2c4f703d1b7f1fb10bc72317355a746057e7346c", - "sha256:e4c015484ff0ff197564917b4b4246ca03f411b9bd7f16e02a2f586eb48b6d04", - "sha256:ebc4ed52dcc93eeebeae5cf5deb2ae4347b3a81c3fa12b0b8c976544829396a4" + "sha256:059b2ee3194d718896c0ad077dd8c043e5e909d9180f387ce42012662a4946d6", + "sha256:1cf708e2ac57f3aabc87405f04b86354f66799c8e62c28c5fc5f88b5521b2dbf", + "sha256:24521fa2890642614558b492b473bee0ac1f8057a7263156b02e8b14c88ce6f5", + "sha256:4fee71aa5bc6ed9d5f116327c04273e25ae31a3020386916905767ec4fc5317e", + "sha256:70024e02197337533eef7b85b068212420f950319cc8c580261963aefc75f811", + "sha256:74782fbd4d4f87ff04159e986886931456a1894c61229be9eaf4de6f6e44b99e", + "sha256:940532b111b1952befd7db542c370887a8611660d2b9becff75d39355303d82d", + "sha256:cb1f2f5e426dc9f07a7681419fe39cee823bb74f723f36f70399123f439e9b20", + "sha256:dbbb2379c19ed6042e8f11f2a2c66d39cceb8aeace421bfc29d085d93eda3689", + "sha256:e3a057b7a64f1222b56e47bcff5e4b94c4f61faac04c7c4ecb1985e18caa3994", + "sha256:e9f45bd5b92c7974e59bcd2dcc8631a6b6cc380a904725fce7bc08872e691615" ], "index": "pypi", - "version": "==5.2" + "version": "==5.3" }, "regex": { "hashes": [ - "sha256:0472acc4b6319801c1bc681d838c88ba1446f9ae199e01f6e41091c701fb3d42", - "sha256:16709434c4e2332ee8ba26ae339aceb8ab0b24b8398ebd0f52ebc943f45c4fc2", - "sha256:223fb63ec8dcab20b3318e93dcec4aee89e98b062934090bf29ffc374d2000a2", - "sha256:23c3ebf05d1cd3adb26723fd598e75724e0cdb7d6a35185ac0caf061cc6edb49", - "sha256:2404a50fb48badaf214b700f08822b68d93d79200e0aefd9569d0332d21fbfcb", - "sha256:2af3a7a16fed6eff85c25da106effa36f61cbbe801d00ade349b53ce7619eb15", - "sha256:37e018d3746baf159aedfc9773c3cafacbd10d354ba15484f5cfc8ed9da5748b", - "sha256:3c9c2988d02a9238a1975c70e87c6ce94e6f36dd8e372b66f468990cfe077434", - "sha256:47298bc8b89d1c747f0f5974aa528fc0b6b17396f1694136a224d51461279d83", - "sha256:4eeb0fe936797ae00a085f99802642bfc722b3b4ea557e9e7849cb621ea10c91", - "sha256:6881be0218b47ed76db033f252bab3f912dfe7ed1fe7baa9daebf51de08546a0", - "sha256:7ac08cee5055f548eed3889e9aaef15fd00172d037949496f1f0b34acb8a7c3e", - "sha256:7c5e2efcf079c35ff266c3f3a6708834f88f9fd04a3c16b855e036b2b7b1b543", - "sha256:8355eaa64724a0fdb010a1654b77cb3e375dc08b7f592cc4a1c05ac606aa481c", - "sha256:999a885f7f5194464238ad5d74b05982acee54002f3aa775d8e0e8c5fb74c06c", - "sha256:9fd2f4813eaa3e421e82819d38e5b634d900faff7ae5a80cd89ccff407175e69", - "sha256:a2e1e53df7dd27943da2b512895125b33fb20f81862c9fed7b3bab2a1de684d1", - "sha256:ab43bc0836820b7900dfffc025b996784aec26ec87dc1df4f95a40398760223f", - "sha256:ba449b56fa419fb19bf2a2438adbd2433f27087a6fe115917eaf9cfca684d5b6", - "sha256:d3f632cefad2cf247bd845794002585e3772288bfcb0dbac59fdecd32cd38b67", - "sha256:d51311496061863caae2cfe120cf1ef37900019b86c89c2d75f0918e0b4b8bf3" + "sha256:07b39bf943d3d2fe63d46281d8504f8df0ff3fe4c57e13d1656737950e53e525", + "sha256:0932941cdfb3afcbc26cc3bcf7c3f3d73d5a9b9c56955d432dbf8bbc147d4c5b", + "sha256:0e182d2f097ea8549a249040922fa2b92ae28be4be4895933e369a525ba36576", + "sha256:10671601ee06cf4dc1bc0b4805309040bb34c9af423c12c379c83d7895622bb5", + "sha256:23e2c2c0ff50f44877f64780b815b8fd2e003cda9ce817a7fd00dea5600c84a0", + "sha256:26ff99c980f53b3191d8931b199b29d6787c059f2e029b2b0c694343b1708c35", + "sha256:27429b8d74ba683484a06b260b7bb00f312e7c757792628ea251afdbf1434003", + "sha256:3e77409b678b21a056415da3a56abfd7c3ad03da71f3051bbcdb68cf44d3c34d", + "sha256:4e8f02d3d72ca94efc8396f8036c0d3bcc812aefc28ec70f35bb888c74a25161", + "sha256:4eae742636aec40cf7ab98171ab9400393360b97e8f9da67b1867a9ee0889b26", + "sha256:6a6ae17bf8f2d82d1e8858a47757ce389b880083c4ff2498dba17c56e6c103b9", + "sha256:6a6ba91b94427cd49cd27764679024b14a96874e0dc638ae6bdd4b1a3ce97be1", + "sha256:7bcd322935377abcc79bfe5b63c44abd0b29387f267791d566bbb566edfdd146", + "sha256:98b8ed7bb2155e2cbb8b76f627b2fd12cf4b22ab6e14873e8641f266e0fb6d8f", + "sha256:bd25bb7980917e4e70ccccd7e3b5740614f1c408a642c245019cff9d7d1b6149", + "sha256:d0f424328f9822b0323b3b6f2e4b9c90960b24743d220763c7f07071e0778351", + "sha256:d58e4606da2a41659c84baeb3cfa2e4c87a74cec89a1e7c56bee4b956f9d7461", + "sha256:e3cd21cc2840ca67de0bbe4071f79f031c81418deb544ceda93ad75ca1ee9f7b", + "sha256:e6c02171d62ed6972ca8631f6f34fa3281d51db8b326ee397b9c83093a6b7242", + "sha256:e7c7661f7276507bce416eaae22040fd91ca471b5b33c13f8ff21137ed6f248c", + "sha256:ecc6de77df3ef68fee966bb8cb4e067e84d4d1f397d0ef6fce46913663540d77" ], - "version": "==2019.12.19" + "version": "==2020.1.8" }, "requests": { "hashes": [ @@ -1139,12 +1184,12 @@ }, "rope": { "hashes": [ - "sha256:6b728fdc3e98a83446c27a91fc5d56808a004f8beab7a31ab1d7224cecc7d969", - "sha256:c5c5a6a87f7b1a2095fb311135e2a3d1f194f5ecb96900fdd0a9100881f48aaf", - "sha256:f0dcf719b63200d492b85535ebe5ea9b29e0d0b8aebeb87fe03fc1a65924fdaf" + "sha256:52423a7eebb5306a6d63bdc91a7c657db51ac9babfb8341c9a1440831ecf3203", + "sha256:ae1fa2fd56f64f4cc9be46493ce54bed0dd12dee03980c61a4393d89d84029ad", + "sha256:d2830142c2e046f5fc26a022fe680675b6f48f81c7fc1f03a950706e746e9dfe" ], "index": "pypi", - "version": "==0.14.0" + "version": "==0.16.0" }, "selenium": { "hashes": [ @@ -1205,29 +1250,30 @@ }, "typed-ast": { "hashes": [ - "sha256:1170afa46a3799e18b4c977777ce137bb53c7485379d9706af8a59f2ea1aa161", - "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", - "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", - "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", - "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", - "sha256:48e5b1e71f25cfdef98b013263a88d7145879fbb2d5185f2a0c79fa7ebbeae47", - "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", - "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", - "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", - "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", - "sha256:7954560051331d003b4e2b3eb822d9dd2e376fa4f6d98fee32f452f52dd6ebb2", - "sha256:838997f4310012cf2e1ad3803bce2f3402e9ffb71ded61b5ee22617b3a7f6b6e", - "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", - "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", - "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", - "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", - "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", - "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", - "sha256:fdc1c9bbf79510b76408840e009ed65958feba92a88833cdceecff93ae8fff66", - "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12" + "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355", + "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919", + "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa", + "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652", + "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75", + "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01", + "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d", + "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1", + "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907", + "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c", + "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3", + "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b", + "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614", + "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb", + "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b", + "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41", + "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6", + "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34", + "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe", + "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4", + "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7" ], "markers": "implementation_name == 'cpython' and python_version < '3.8'", - "version": "==1.4.0" + "version": "==1.4.1" }, "typing-extensions": { "hashes": [ @@ -1252,10 +1298,10 @@ }, "wcwidth": { "hashes": [ - "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", - "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" + "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603", + "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8" ], - "version": "==0.1.7" + "version": "==0.1.8" }, "werkzeug": { "hashes": [ @@ -1273,10 +1319,10 @@ }, "zipp": { "hashes": [ - "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", - "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335" + "sha256:8dda78f06bd1674bd8720df8a50bb47b6e1233c503a4eed8e7810686bde37656", + "sha256:d38fbe01bbf7a3593a32bc35a9c4453c32bc42b98c377f9bff7e9f8da157786c" ], - "version": "==0.6.0" + "version": "==1.0.0" } } } diff --git a/PortfolioProvision.md b/PortfolioProvision.md new file mode 100644 index 00000000..6ea8d3cc --- /dev/null +++ b/PortfolioProvision.md @@ -0,0 +1,70 @@ + +Each CSP will have a set of "stages" that are required to be completed before the provisioning process can be considered complete. + +Azure Stages: + tenant, + billing profile, + admin subscription + etc. + +`atst.models.mixins.state_machines` module contains: + + python Enum classes that define the stages for a CSP + + class AzureStages(Enum): + TENANT = "tenant" + BILLING_PROFILE = "billing profile" + ADMIN_SUBSCRIPTION = "admin subscription" + +there are two types of python dataclass subclasses defined in `atst.models.portoflio_state_machine` module. + +one holds the data that is submitted to the CSP + + @dataclass + class TenantCSPPayload(): + user_id: str + password: str + etc. + +the other holds the results of the call to the CSP + @dataclass + class TenantCSPResult(): + user_id: str + tenant_id: str + user_object_id: str + etc. + +A Finite State Machine `atst.models.portoflio_state_machine.PortfolioStateMachine` is created for each provisioning process and tied to an instance of Portfolio class. + +Aach time the FSM is created/accessed it will generate a list of States and Transitions between the states. + +There is a set of "system" states such as UNSTARTED, STARTING, STARTED, COMPLETED, FAILED etc + +There is a set of CSP specific states generated for each "stage" in the FSM. + TENANT_IN_PROGRESS + TENANT_IN_COMPLETED + TENANT_IN_FAILED + BILLING_PROFILE_IN_PROGRESS + BILLING_PROFILE_IN_COMPLETED + BILLING_PROFILE_IN_FAILED + etc. + +There is a set of callbacks defined that are triggered as the process transitions between stages. + + callback `PortfolioStateMachine.after_in_progress_callback` + The CSP api call is made as the process transitions into IN_PROGESS state for each state. + + callback `PortfolioStateMachine.is_csp_data_valid` + validates the collected data. + +A transition into the next state can be triggered using PortfolioStateMachine.trigger_next_transition` + + + + + + + + + + diff --git a/README.md b/README.md index 5fdbf6d3..1dfc1ad1 100644 --- a/README.md +++ b/README.md @@ -362,50 +362,3 @@ fi Also note that if the line number of a previously whitelisted secret changes, the whitelist file, `.secrets.baseline`, will be updated and needs to be committed. -## Local Kubernetes Setup - -A modified version of the Kubernetes cluster can be deployed locally for -testing and development purposes. - -It is strongly recommended that you backup your local K8s config (usually -`~/.kube/config`) before launching Minikube for the first time. - -Before beginning: - -- install the [Docker CLI](https://docs.docker.com/v17.12/install/) -- install [Minikube](https://kubernetes.io/docs/tasks/tools/install-minikube/) - (this will also require installing a Hypervisor, such as VirtualBox) - -### Setup - -Run - -``` -script/minikube_setup -``` - -Once the script exits successfully, run - -``` -minikube service list -``` - -### Access the site - -One of the two URLs given for the `atat-auth` service will load an HTTP version -of the application. - -For HTTP basic auth, the username and password are both `minikube`. - -### Differences from the main config - -As of the time of writing, this setup does not include the following: - -- SSL/TLS or the complete DoD PKI -- the cronjob for syncing CRLs and the peristent storage -- production configuration - -In order for the application to run, the K8s config for Minikube includes an -additional deployment resource called `datastores`. This includes Postgres -and Redis containers. It also includes hard-coded versions of the K8s secrets -used in the regular clusters. diff --git a/alembic/versions/59973fa17ded_portfolio_state_machine_table.py b/alembic/versions/59973fa17ded_portfolio_state_machine_table.py new file mode 100644 index 00000000..2d3d754c --- /dev/null +++ b/alembic/versions/59973fa17ded_portfolio_state_machine_table.py @@ -0,0 +1,113 @@ +"""portfolio state machine table. + +Revision ID: 59973fa17ded +Revises: 828d8c188dce +Create Date: 2020-01-08 10:37:32.924245 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql +import sqlalchemy_json + +# revision identifiers, used by Alembic. +revision = "59973fa17ded" # pragma: allowlist secret +down_revision = "828d8c188dce" # pragma: allowlist secret +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "portfolio_job_failures", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("task_id", sa.String(), nullable=False), + sa.Column("portfolio_id", postgresql.UUID(as_uuid=True), nullable=False), + sa.ForeignKeyConstraint(["portfolio_id"], ["portfolios.id"],), + sa.PrimaryKeyConstraint("id"), + ) + op.create_table( + "portfolio_state_machines", + sa.Column( + "time_created", + sa.TIMESTAMP(timezone=True), + server_default=sa.text("now()"), + nullable=False, + ), + sa.Column( + "time_updated", + sa.TIMESTAMP(timezone=True), + server_default=sa.text("now()"), + nullable=False, + ), + sa.Column( + "deleted", sa.Boolean(), server_default=sa.text("false"), nullable=False + ), + sa.Column( + "id", + postgresql.UUID(as_uuid=True), + server_default=sa.text("uuid_generate_v4()"), + nullable=False, + ), + sa.Column("portfolio_id", postgresql.UUID(as_uuid=True), nullable=True), + sa.Column( + "state", + sa.Enum( + "UNSTARTED", + "STARTING", + "STARTED", + "COMPLETED", + "FAILED", + "TENANT_CREATED", + "TENANT_IN_PROGRESS", + "TENANT_FAILED", + "BILLING_PROFILE_CREATED", + "BILLING_PROFILE_IN_PROGRESS", + "BILLING_PROFILE_FAILED", + "ADMIN_SUBSCRIPTION_CREATED", + "ADMIN_SUBSCRIPTION_IN_PROGRESS", + "ADMIN_SUBSCRIPTION_FAILED", + name="fsmstates", + native_enum=False, + ), + nullable=False, + ), + sa.ForeignKeyConstraint(["portfolio_id"], ["portfolios.id"],), + sa.PrimaryKeyConstraint("id"), + ) + op.add_column("portfolios", sa.Column("app_migration", sa.String(), nullable=True)) + op.add_column( + "portfolios", sa.Column("complexity", sa.ARRAY(sa.String()), nullable=True) + ) + op.add_column( + "portfolios", sa.Column("complexity_other", sa.String(), nullable=True) + ) + op.add_column( + "portfolios", + sa.Column("csp_data", sqlalchemy_json.NestedMutableJson(), nullable=True), + ) + op.add_column( + "portfolios", sa.Column("dev_team", sa.ARRAY(sa.String()), nullable=True) + ) + op.add_column("portfolios", sa.Column("dev_team_other", sa.String(), nullable=True)) + op.add_column("portfolios", sa.Column("native_apps", sa.String(), nullable=True)) + op.add_column( + "portfolios", sa.Column("team_experience", sa.String(), nullable=True) + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("portfolios", "team_experience") + op.drop_column("portfolios", "native_apps") + op.drop_column("portfolios", "dev_team_other") + op.drop_column("portfolios", "dev_team") + op.drop_column("portfolios", "csp_data") + op.drop_column("portfolios", "complexity_other") + op.drop_column("portfolios", "complexity") + op.drop_column("portfolios", "app_migration") + op.drop_table("portfolio_state_machines") + op.drop_table("portfolio_job_failures") + # ### end Alembic commands ### diff --git a/alembic/versions/5d7198d34b91_remove_users_provisional.py b/alembic/versions/5d7198d34b91_remove_users_provisional.py new file mode 100644 index 00000000..aeb80bdc --- /dev/null +++ b/alembic/versions/5d7198d34b91_remove_users_provisional.py @@ -0,0 +1,28 @@ +"""remove users.provisional + +Revision ID: 5d7198d34b91 +Revises: 02ac8bdcf16f +Create Date: 2020-01-09 08:42:34.512191 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '5d7198d34b91' # pragma: allowlist secret +down_revision = '02ac8bdcf16f' # pragma: allowlist secret +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('users', 'provisional') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('users', sa.Column('provisional', sa.BOOLEAN(), autoincrement=False, nullable=True)) + # ### end Alembic commands ### diff --git a/alembic/versions/828d8c188dce_update_environment_roles_enum_list.py b/alembic/versions/828d8c188dce_update_environment_roles_enum_list.py new file mode 100644 index 00000000..450ece6e --- /dev/null +++ b/alembic/versions/828d8c188dce_update_environment_roles_enum_list.py @@ -0,0 +1,58 @@ +"""update environment_roles enum list + +Revision ID: 828d8c188dce +Revises: 5d7198d34b91 +Create Date: 2020-01-08 16:08:03.879881 + +""" +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = '828d8c188dce' # pragma: allowlist secret +down_revision = '5d7198d34b91' # pragma: allowlist secret +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + conn = op.get_bind() + conn.execute( + """ + UPDATE environment_roles + SET role = NULL + """ + ) + + op.alter_column( + "environment_roles", + "role", + type_=sa.Enum( + "ADMIN", + "BILLING_READ", + "CONTRIBUTOR", + name="role", + native_enum=False, + ), + existing_type=sa.VARCHAR(), + nullable=True, + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column( + "environment_roles", + "status", + type_=sa.VARCHAR(), + existing_type=sa.Enum( + "ADMIN", + "BILLING_READ", + "CONTRIBUTOR", + name="status", + native_enum=False, + ), + ) + # ### end Alembic commands ### diff --git a/atst/app.py b/atst/app.py index e9daabd6..d73188cf 100644 --- a/atst/app.py +++ b/atst/app.py @@ -159,6 +159,7 @@ def map_config(config): "ENV": config["default"]["ENVIRONMENT"], "BROKER_URL": config["default"]["REDIS_URI"], "DEBUG": config["default"].getboolean("DEBUG"), + "DEBUG_MAILER": config["default"].getboolean("DEBUG_MAILER"), "SQLALCHEMY_ECHO": config["default"].getboolean("SQLALCHEMY_ECHO"), "PORT": int(config["default"]["PORT"]), "SQLALCHEMY_DATABASE_URI": config["default"]["DATABASE_URI"], @@ -289,7 +290,7 @@ def make_crl_validator(app): def make_mailer(app): - if app.config["DEBUG"]: + if app.config["DEBUG"] or app.config["DEBUG_MAILER"]: mailer_connection = mailer.RedisConnection(app.redis) else: mailer_connection = mailer.SMTPConnection( diff --git a/atst/domain/auth.py b/atst/domain/auth.py index 0f99af09..73bb1db1 100644 --- a/atst/domain/auth.py +++ b/atst/domain/auth.py @@ -1,4 +1,4 @@ -from flask import g, redirect, url_for, session, request +from flask import g, redirect, url_for, session, request, current_app as app from atst.domain.users import Users @@ -59,8 +59,10 @@ def get_last_login(): def logout(): if session.get("user_id"): # pragma: no branch + dod_id = g.current_user.dod_id del session["user_id"] del session["last_login"] + app.logger.info(f"user with EDIPI {dod_id} has logged out") def _unprotected_route(request): diff --git a/atst/domain/csp/__init__.py b/atst/domain/csp/__init__.py index d886f8a2..fc452935 100644 --- a/atst/domain/csp/__init__.py +++ b/atst/domain/csp/__init__.py @@ -1,3 +1,5 @@ +import importlib + from .cloud import MockCloudProvider from .file_uploads import AzureUploader, MockUploader from .reports import MockReportingProvider @@ -29,3 +31,22 @@ def make_csp_provider(app, csp=None): app.csp = MockCSP(app, test_mode=True) else: app.csp = MockCSP(app) + + +def _stage_to_classname(stage): + return "".join( + map(lambda word: word.capitalize(), stage.replace("_", " ").split(" ")) + ) + + +def get_stage_csp_class(stage, class_type): + """ + given a stage name and class_type return the class + class_type is either 'payload' or 'result' + + """ + cls_name = "".join([_stage_to_classname(stage), "CSP", class_type.capitalize()]) + try: + return getattr(importlib.import_module("atst.domain.csp.cloud"), cls_name) + except AttributeError: + print("could not import CSP Result class <%s>" % cls_name) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index 36c91c95..9f764da0 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -1,12 +1,12 @@ -from typing import Dict import re +from typing import Dict from uuid import uuid4 +from pydantic import BaseModel + from atst.models.user import User -from atst.models.application import Application from atst.models.environment import Environment from atst.models.environment_role import EnvironmentRole -from .policy import AzurePolicyManager class GeneralCSPException(Exception): @@ -142,6 +142,97 @@ class BaselineProvisionException(GeneralCSPException): ) +class BaseCSPPayload(BaseModel): + # {"username": "mock-cloud", "pass": "shh"} + creds: Dict + + +class TenantCSPPayload(BaseCSPPayload): + user_id: str + password: str + domain_name: str + first_name: str + last_name: str + country_code: str + password_recovery_email_address: str + + +class TenantCSPResult(BaseModel): + user_id: str + tenant_id: str + user_object_id: str + + +class BillingProfileAddress(BaseModel): + address: Dict + """ + "address": { + "firstName": "string", + "lastName": "string", + "companyName": "string", + "addressLine1": "string", + "addressLine2": "string", + "addressLine3": "string", + "city": "string", + "region": "string", + "country": "string", + "postalCode": "string" + }, + """ + + +class BillingProfileCLINBudget(BaseModel): + clinBudget: Dict + """ + "clinBudget": { + "amount": 0, + "startDate": "2019-12-18T16:47:40.909Z", + "endDate": "2019-12-18T16:47:40.909Z", + "externalReferenceId": "string" + } + """ + + +class BillingProfileCSPPayload( + BaseCSPPayload, BillingProfileAddress, BillingProfileCLINBudget +): + displayName: str + poNumber: str + invoiceEmailOptIn: str + + """ + { + "displayName": "string", + "poNumber": "string", + "address": { + "firstName": "string", + "lastName": "string", + "companyName": "string", + "addressLine1": "string", + "addressLine2": "string", + "addressLine3": "string", + "city": "string", + "region": "string", + "country": "string", + "postalCode": "string" + }, + "invoiceEmailOptIn": true, + Note: These last 2 are also the body for adding/updating new TOs/clins + "enabledAzurePlans": [ + { + "skuId": "string" + } + ], + "clinBudget": { + "amount": 0, + "startDate": "2019-12-18T16:47:40.909Z", + "endDate": "2019-12-18T16:47:40.909Z", + "externalReferenceId": "string" + } + } + """ + + class CloudProviderInterface: def root_creds(self) -> Dict: raise NotImplementedError() @@ -325,6 +416,68 @@ class MockCloudProvider(CloudProviderInterface): return {"id": self._id(), "credentials": self._auth_credentials} + def create_tenant(self, payload): + """ + payload is an instance of TenantCSPPayload data class + """ + + self._authorize(payload.creds) + + self._delay(1, 5) + + self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) + self._maybe_raise(self.SERVER_FAILURE_PCT, self.SERVER_EXCEPTION) + self._maybe_raise(self.UNAUTHORIZED_RATE, self.AUTHORIZATION_EXCEPTION) + # return tenant id, tenant owner id and tenant owner object id from: + response = {"tenantId": "string", "userId": "string", "objectId": "string"} + return { + "tenant_id": response["tenantId"], + "user_id": response["userId"], + "user_object_id": response["objectId"], + } + + def create_billing_profile(self, creds, tenant_admin_details, billing_owner_id): + # call billing profile creation endpoint, specifying owner + # Payload: + """ + { + "displayName": "string", + "poNumber": "string", + "address": { + "firstName": "string", + "lastName": "string", + "companyName": "string", + "addressLine1": "string", + "addressLine2": "string", + "addressLine3": "string", + "city": "string", + "region": "string", + "country": "string", + "postalCode": "string" + }, + "invoiceEmailOptIn": true, + Note: These last 2 are also the body for adding/updating new TOs/clins + "enabledAzurePlans": [ + { + "skuId": "string" + } + ], + "clinBudget": { + "amount": 0, + "startDate": "2019-12-18T16:47:40.909Z", + "endDate": "2019-12-18T16:47:40.909Z", + "externalReferenceId": "string" + } + } + """ + # response will be mostly the same as the body, but we only really care about the id + self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) + self._maybe_raise(self.SERVER_FAILURE_PCT, self.SERVER_EXCEPTION) + self._maybe_raise(self.UNAUTHORIZED_RATE, self.AUTHORIZATION_EXCEPTION) + + response = {"id": "string"} + return {"billing_profile_id": response["id"]} + def create_or_update_user(self, auth_credentials, user_info, csp_role_id): self._authorize(auth_credentials) @@ -401,18 +554,15 @@ REMOTE_ROOT_ROLE_DEF_ID = "/providers/Microsoft.Authorization/roleDefinitions/00 class AzureSDKProvider(object): def __init__(self): - from azure.mgmt import subscription, authorization, managementgroups - from azure.mgmt.resource import policy + from azure.mgmt import subscription, authorization import azure.graphrbac as graphrbac import azure.common.credentials as credentials from msrestazure.azure_cloud import AZURE_PUBLIC_CLOUD self.subscription = subscription self.authorization = authorization - self.managementgroups = managementgroups self.graphrbac = graphrbac self.credentials = credentials - self.policy = policy # may change to a JEDI cloud self.cloud = AZURE_PUBLIC_CLOUD @@ -430,28 +580,45 @@ class AzureCloudProvider(CloudProviderInterface): else: self.sdk = azure_sdk_provider - self.policy_manager = AzurePolicyManager(config["AZURE_POLICY_LOCATION"]) - def create_environment( self, auth_credentials: Dict, user: User, environment: Environment ): - # since this operation would only occur within a tenant, should we source the tenant - # via lookup from environment once we've created the portfolio csp data schema - # something like this: - # environment_tenant = environment.application.portfolio.csp_data.get('tenant_id', None) - # though we'd probably source the whole credentials for these calls from the portfolio csp - # data, as it would have to be where we store the creds for the at-at user within the portfolio tenant - # credentials = self._get_credential_obj(environment.application.portfolio.csp_data.get_creds()) credentials = self._get_credential_obj(self._root_creds) - display_name = f"{environment.application.name}_{environment.name}_{environment.id}" # proposed format - management_group_id = "?" # management group id chained from environment - parent_id = "?" # from environment.application + sub_client = self.sdk.subscription.SubscriptionClient(credentials) - management_group = self._create_management_group( - credentials, management_group_id, display_name, parent_id, + display_name = f"{environment.application.name}_{environment.name}_{environment.id}" # proposed format + + billing_profile_id = "?" # something chained from environment? + sku_id = AZURE_SKU_ID + # we want to set AT-AT as an owner here + # we could potentially associate subscriptions with "management groups" per DOD component + body = self.sdk.subscription.models.ModernSubscriptionCreationParameters( + display_name, + billing_profile_id, + sku_id, + # owner= ) - return management_group + # These 2 seem like something that might be worthwhile to allow tiebacks to + # TOs filed for the environment + billing_account_name = "?" + invoice_section_name = "?" + # We may also want to create billing sections in the enrollment account + sub_creation_operation = sub_client.subscription_factory.create_subscription( + billing_account_name, invoice_section_name, body + ) + + # the resulting object from this process is a link to the new subscription + # not a subscription model, so we'll have to unpack the ID + new_sub = sub_creation_operation.result() + + subscription_id = self._extract_subscription_id(new_sub.subscription_link) + if subscription_id: + return subscription_id + else: + # troublesome error, subscription should exist at this point + # but we just don't have a valid ID + pass def create_atat_admin_user( self, auth_credentials: Dict, csp_environment_id: str @@ -490,126 +657,135 @@ class AzureCloudProvider(CloudProviderInterface): "role_name": role_assignment_id, } - def _create_application(self, auth_credentials: Dict, application: Application): - management_group_name = str(uuid4()) # can be anything, not just uuid - display_name = application.name # Does this need to be unique? - credentials = self._get_credential_obj(auth_credentials) - parent_id = "?" # application.portfolio.csp_details.management_group_id + def create_tenant(self, payload): + # auth as SP that is allowed to create tenant? (tenant creation sp creds) + # create tenant with owner details (populated from portfolio point of contact, pw is generated) - return self._create_management_group( - credentials, management_group_name, display_name, parent_id, + # return tenant id, tenant owner id and tenant owner object id from: + response = {"tenantId": "string", "userId": "string", "objectId": "string"} + return self._ok( + { + "tenant_id": response["tenantId"], + "user_id": response["userId"], + "user_object_id": response["objectId"], + } ) - def _create_management_group( - self, credentials, management_group_id, display_name, parent_id=None, - ): - mgmgt_group_client = self.sdk.managementgroups.ManagementGroupsAPI(credentials) - create_parent_grp_info = self.sdk.managementgroups.models.CreateParentGroupInfo( - id=parent_id - ) - create_mgmt_grp_details = self.sdk.managementgroups.models.CreateManagementGroupDetails( - parent=create_parent_grp_info - ) - mgmt_grp_create = self.sdk.managementgroups.models.CreateManagementGroupRequest( - name=management_group_id, - display_name=display_name, - details=create_mgmt_grp_details, - ) - create_request = mgmgt_group_client.management_groups.create_or_update( - management_group_id, mgmt_grp_create - ) + def create_billing_owner(self, creds, tenant_admin_details): + # authenticate as tenant_admin + # create billing owner identity - # result is a synchronous wait, might need to do a poll instead to handle first mgmt group create - # since we were told it could take 10+ minutes to complete, unless this handles that polling internally - return create_request.result() + # TODO: Lookup response format + # Managed service identity? + response = {"id": "string"} + return self._ok({"billing_owner_id": response["id"]}) - def _create_subscription( - self, - credentials, - display_name, - billing_profile_id, - sku_id, - management_group_id, - billing_account_name, - invoice_section_name, - ): - sub_client = self.sdk.subscription.SubscriptionClient(credentials) - - billing_profile_id = "?" # where do we source this? - sku_id = AZURE_SKU_ID - # These 2 seem like something that might be worthwhile to allow tiebacks to - # TOs filed for the environment - billing_account_name = "?" # from TO? - invoice_section_name = "?" # from TO? - - body = self.sdk.subscription.models.ModernSubscriptionCreationParameters( - display_name=display_name, - billing_profile_id=billing_profile_id, - sku_id=sku_id, - management_group_id=management_group_id, - ) - - # We may also want to create billing sections in the enrollment account - sub_creation_operation = sub_client.subscription_factory.create_subscription( - billing_account_name, invoice_section_name, body - ) - - # the resulting object from this process is a link to the new subscription - # not a subscription model, so we'll have to unpack the ID - new_sub = sub_creation_operation.result() - - subscription_id = self._extract_subscription_id(new_sub.subscription_link) - if subscription_id: - return subscription_id - else: - # troublesome error, subscription should exist at this point - # but we just don't have a valid ID - pass - - AZURE_MANAGEMENT_API = "https://management.azure.com" - - def _create_policy_definition( - self, credentials, subscription_id, management_group_id, properties, - ): + def assign_billing_owner(self, creds, billing_owner_id, tenant_id): + # TODO: Do we source role definition ID from config, api or self-defined? + # TODO: If from api, """ - Requires credentials that have AZURE_MANAGEMENT_API - specified as the resource. The Service Principal - specified in the credentials must have the "Resource - Policy Contributor" role assigned with a scope at least - as high as the management group specified by - management_group_id. - - Arguments: - credentials -- ServicePrincipalCredentials - subscription_id -- str, ID of the subscription (just the UUID, not the path) - management_group_id -- str, ID of the management group (just the UUID, not the path) - properties -- dictionary, the "properties" section of a valid Azure policy definition document - - Returns: - azure.mgmt.resource.policy.[api version].models.PolicyDefinition: the PolicyDefinition object provided to Azure - - Raises: - TBD + { + "principalId": "string", + "principalTenantId": "string", + "billingRoleDefinitionId": "string" + } """ - # TODO: which subscription would this be? - client = self.sdk.policy.PolicyClient(credentials, subscription_id) - definition = client.policy_definitions.models.PolicyDefinition( - policy_type=properties.get("policyType"), - mode=properties.get("mode"), - display_name=properties.get("displayName"), - description=properties.get("description"), - policy_rule=properties.get("policyRule"), - parameters=properties.get("parameters"), + return self.ok() + + def create_billing_profile(self, creds, tenant_admin_details, billing_owner_id): + # call billing profile creation endpoint, specifying owner + # Payload: + """ + { + "displayName": "string", + "poNumber": "string", + "address": { + "firstName": "string", + "lastName": "string", + "companyName": "string", + "addressLine1": "string", + "addressLine2": "string", + "addressLine3": "string", + "city": "string", + "region": "string", + "country": "string", + "postalCode": "string" + }, + "invoiceEmailOptIn": true, + Note: These last 2 are also the body for adding/updating new TOs/clins + "enabledAzurePlans": [ + { + "skuId": "string" + } + ], + "clinBudget": { + "amount": 0, + "startDate": "2019-12-18T16:47:40.909Z", + "endDate": "2019-12-18T16:47:40.909Z", + "externalReferenceId": "string" + } + } + """ + + # response will be mostly the same as the body, but we only really care about the id + response = {"id": "string"} + return self._ok({"billing_profile_id": response["id"]}) + + def report_clin(self, creds, clin_id, clin_amount, clin_start, clin_end, clin_to): + # should consumer be responsible for reporting each clin or + # should this take a list and manage the sequential reporting? + """ Payload + { + "enabledAzurePlans": [ + { + "skuId": "string" + } + ], + "clinBudget": { + "amount": 0, + "startDate": "2019-12-18T16:47:40.909Z", + "endDate": "2019-12-18T16:47:40.909Z", + "externalReferenceId": "string" + } + } + """ + + # we don't need any of the returned info for this + return self._ok() + + def create_remote_admin(self, creds, tenant_details): + # create app/service principal within tenant, with name constructed from tenant details + # assign principal global admin + + # needs to call out to CLI with tenant owner username/password, prototyping for that underway + + # return identifier and creds to consumer for storage + response = {"clientId": "string", "secretKey": "string", "tenantId": "string"} + return self._ok( + { + "client_id": response["clientId"], + "secret_key": response["secret_key"], + "tenant_id": response["tenantId"], + } ) - name = properties.get("displayName") + def force_tenant_admin_pw_update(self, creds, tenant_owner_id): + # use creds to update to force password recovery? + # not sure what the endpoint/method for this is, yet - return client.policy_definitions.create_or_update_at_management_group( - policy_definition_name=name, - parameters=definition, - management_group_id=management_group_id, - ) + return self._ok() + + def create_billing_alerts(self, TBD): + # TODO: Add azure-mgmt-consumption for Budget and Notification entities/operations + # TODO: Determine how to auth against that API using the SDK, doesn't seeem possible at the moment + # TODO: billing alerts are registered as Notifications on Budget objects, which have start/end dates + # TODO: determine what the keys in the Notifications dict are supposed to be + # we may need to rotate budget objects when new TOs/CLINs are reported? + + # we likely only want the budget ID, can be updated or replaced? + response = {"id": "id"} + return self._ok({"budget_id": response["id"]}) def _get_management_service_principal(self): # we really should be using graph.microsoft.com, but i'm getting @@ -663,6 +839,7 @@ class AzureCloudProvider(CloudProviderInterface): return sub_id_match.group(1) def _get_credential_obj(self, creds, resource=None): + return self.sdk.credentials.ServicePrincipalCredentials( client_id=creds.get("client_id"), secret=creds.get("secret_key"), @@ -671,6 +848,27 @@ class AzureCloudProvider(CloudProviderInterface): cloud_environment=self.sdk.cloud, ) + def _make_tenant_admin_cred_obj(self, username, password): + return self.sdk.credentials.UserPassCredentials(username, password) + + def _ok(self, body=None): + return self._make_response("ok", body) + + def _error(self, body=None): + return self._make_response("error", body) + + def _make_response(self, status, body=dict()): + """Create body for responses from API + + Arguments: + status {string} -- "ok" or "error" + body {dict} -- dict containing details of response or error, if applicable + + Returns: + dict -- status of call with body containing details + """ + return {"status": status, "body": body} + @property def _root_creds(self): return { diff --git a/atst/domain/portfolios/__init__.py b/atst/domain/portfolios/__init__.py index dd1dd918..e3cb8c7b 100644 --- a/atst/domain/portfolios/__init__.py +++ b/atst/domain/portfolios/__init__.py @@ -2,4 +2,5 @@ from .portfolios import ( Portfolios, PortfolioError, PortfolioDeletionApplicationsExistError, + PortfolioStateMachines, ) diff --git a/atst/domain/portfolios/portfolios.py b/atst/domain/portfolios/portfolios.py index bb9e7aea..1254ac71 100644 --- a/atst/domain/portfolios/portfolios.py +++ b/atst/domain/portfolios/portfolios.py @@ -1,11 +1,23 @@ +from sqlalchemy import or_ +from typing import List +from uuid import UUID + from atst.database import db from atst.domain.permission_sets import PermissionSets from atst.domain.authz import Authorization from atst.domain.portfolio_roles import PortfolioRoles -from atst.domain.invitations import PortfolioInvitations -from atst.models import Permissions, PortfolioRole, PortfolioRoleStatus -from .query import PortfoliosQuery +from atst.domain.invitations import PortfolioInvitations +from atst.models import ( + Portfolio, + PortfolioStateMachine, + FSMStates, + Permissions, + PortfolioRole, + PortfolioRoleStatus, +) + +from .query import PortfoliosQuery, PortfolioStateMachinesQuery from .scopes import ScopedPortfolio @@ -17,7 +29,22 @@ class PortfolioDeletionApplicationsExistError(Exception): pass +class PortfolioStateMachines(object): + @classmethod + def create(cls, portfolio, **sm_attrs): + sm_attrs.update({"portfolio": portfolio}) + sm = PortfolioStateMachinesQuery.create(**sm_attrs) + return sm + + class Portfolios(object): + @classmethod + def get_or_create_state_machine(cls, portfolio): + """ + get or create Portfolio State Machine for a Portfolio + """ + return portfolio.state_machine or PortfolioStateMachines.create(portfolio) + @classmethod def create(cls, user, portfolio_attrs): portfolio = PortfoliosQuery.create(**portfolio_attrs) @@ -75,10 +102,10 @@ class Portfolios(object): permission_sets = PortfolioRoles._permission_sets_for_names( member_data.get("permission_sets", []) ) - role = PortfolioRole(portfolio_id=portfolio.id, permission_sets=permission_sets) + role = PortfolioRole(portfolio=portfolio, permission_sets=permission_sets) invitation = PortfolioInvitations.create( - inviter=inviter, role=role, member_data=member_data + inviter=inviter, role=role, member_data=member_data["user_data"] ) PortfoliosQuery.add_and_commit(role) @@ -111,3 +138,37 @@ class Portfolios(object): portfolio.description = new_data["description"] PortfoliosQuery.add_and_commit(portfolio) + + @classmethod + def base_provision_query(cls): + return db.session.query(Portfolio.id) + + @classmethod + def get_portfolios_pending_provisioning(cls) -> List[UUID]: + """ + Any portfolio with a corresponding State Machine that is either: + not started yet, + failed in creating a tenant + failed + """ + + results = ( + cls.base_provision_query() + .join(PortfolioStateMachine) + .filter( + or_( + PortfolioStateMachine.state == FSMStates.UNSTARTED, + PortfolioStateMachine.state == FSMStates.FAILED, + PortfolioStateMachine.state == FSMStates.TENANT_FAILED, + ) + ) + ) + return [id_ for id_, in results] + + # db.session.query(PortfolioStateMachine).\ + # filter( + # or_( + # PortfolioStateMachine.state==FSMStates.UNSTARTED, + # PortfolioStateMachine.state==FSMStates.UNSTARTED, + # ) + # ).all() diff --git a/atst/domain/portfolios/query.py b/atst/domain/portfolios/query.py index 18554017..0fa8f5ac 100644 --- a/atst/domain/portfolios/query.py +++ b/atst/domain/portfolios/query.py @@ -8,6 +8,13 @@ from atst.models.application_role import ( Status as ApplicationRoleStatus, ) from atst.models.application import Application +from atst.models.portfolio_state_machine import PortfolioStateMachine + +# from atst.models.application import Application + + +class PortfolioStateMachinesQuery(Query): + model = PortfolioStateMachine class PortfoliosQuery(Query): diff --git a/atst/domain/users.py b/atst/domain/users.py index 1db198cf..5e09ce22 100644 --- a/atst/domain/users.py +++ b/atst/domain/users.py @@ -117,12 +117,3 @@ class Users(object): user.last_session_id = session_id db.session.add(user) db.session.commit() - - @classmethod - def finalize(cls, user): - user.provisional = False - - db.session.add(user) - db.session.commit() - - return user diff --git a/atst/forms/data.py b/atst/forms/data.py index 5f1f9532..bb728686 100644 --- a/atst/forms/data.py +++ b/atst/forms/data.py @@ -14,7 +14,7 @@ SERVICE_BRANCHES = [ ] ENV_ROLE_NO_ACCESS = "No Access" -ENV_ROLES = [(role.value, role.value) for role in CSPRole] + [ +ENV_ROLES = [(role.name, role.value) for role in CSPRole] + [ (ENV_ROLE_NO_ACCESS, ENV_ROLE_NO_ACCESS) ] diff --git a/atst/forms/portfolio_member.py b/atst/forms/portfolio_member.py index 918d1112..9fff59c1 100644 --- a/atst/forms/portfolio_member.py +++ b/atst/forms/portfolio_member.py @@ -1,76 +1,59 @@ from wtforms.validators import Required -from wtforms.fields import StringField, FormField, FieldList, HiddenField +from wtforms.fields import BooleanField, FormField -from atst.domain.permission_sets import PermissionSets from .forms import BaseForm from .member import NewForm as BaseNewMemberForm +from atst.domain.permission_sets import PermissionSets from atst.forms.fields import SelectField from atst.utils.localization import translate class PermissionsForm(BaseForm): - member_name = StringField() - member_id = HiddenField() - perms_app_mgmt = SelectField( - translate("forms.new_member.app_mgmt"), - choices=[ - ( - PermissionSets.VIEW_PORTFOLIO_APPLICATION_MANAGEMENT, - translate("common.view"), - ), - ( - PermissionSets.EDIT_PORTFOLIO_APPLICATION_MANAGEMENT, - translate("common.edit"), - ), - ], + perms_app_mgmt = BooleanField( + translate("forms.new_member.app_mgmt.label"), + default=False, + description=translate("forms.new_member.app_mgmt.description"), ) - perms_funding = SelectField( - translate("forms.new_member.funding"), - choices=[ - (PermissionSets.VIEW_PORTFOLIO_FUNDING, translate("common.view")), - (PermissionSets.EDIT_PORTFOLIO_FUNDING, translate("common.edit")), - ], + perms_funding = BooleanField( + translate("forms.new_member.funding.label"), + default=False, + description=translate("forms.new_member.funding.description"), ) - perms_reporting = SelectField( - translate("forms.new_member.reporting"), - choices=[ - (PermissionSets.VIEW_PORTFOLIO_REPORTS, translate("common.view")), - (PermissionSets.EDIT_PORTFOLIO_REPORTS, translate("common.edit")), - ], + perms_reporting = BooleanField( + translate("forms.new_member.reporting.label"), + default=False, + description=translate("forms.new_member.reporting.description"), ) - perms_portfolio_mgmt = SelectField( - translate("forms.new_member.portfolio_mgmt"), - choices=[ - (PermissionSets.VIEW_PORTFOLIO_ADMIN, translate("common.view")), - (PermissionSets.EDIT_PORTFOLIO_ADMIN, translate("common.edit")), - ], + perms_portfolio_mgmt = BooleanField( + translate("forms.new_member.portfolio_mgmt.label"), + default=False, + description=translate("forms.new_member.portfolio_mgmt.description"), ) @property def data(self): _data = super().data - _data["permission_sets"] = [] - for field in _data: - if "perms" in field: - _data["permission_sets"].append(_data[field]) + _data.pop("csrf_token", None) + perm_sets = [] + if _data["perms_app_mgmt"]: + perm_sets.append(PermissionSets.EDIT_PORTFOLIO_APPLICATION_MANAGEMENT) + + if _data["perms_funding"]: + perm_sets.append(PermissionSets.EDIT_PORTFOLIO_FUNDING) + + if _data["perms_reporting"]: + perm_sets.append(PermissionSets.EDIT_PORTFOLIO_REPORTS) + + if _data["perms_portfolio_mgmt"]: + perm_sets.append(PermissionSets.EDIT_PORTFOLIO_ADMIN) + + _data["permission_sets"] = perm_sets return _data -class MembersPermissionsForm(BaseForm): - members_permissions = FieldList(FormField(PermissionsForm)) - - -class NewForm(BaseForm): +class NewForm(PermissionsForm): user_data = FormField(BaseNewMemberForm) - permission_sets = FormField(PermissionsForm) - - @property - def update_data(self): - return { - "permission_sets": self.data.get("permission_sets").get("permission_sets"), - **self.data.get("user_data"), - } class AssignPPOCForm(PermissionsForm): diff --git a/atst/forms/task_order.py b/atst/forms/task_order.py index 1c324736..fab3707c 100644 --- a/atst/forms/task_order.py +++ b/atst/forms/task_order.py @@ -7,7 +7,7 @@ from wtforms.fields import ( HiddenField, ) from wtforms.fields.html5 import DateField -from wtforms.validators import Required, Length, NumberRange, ValidationError +from wtforms.validators import Required, Length, NumberRange, ValidationError, Regexp from flask_wtf import FlaskForm from numbers import Number @@ -15,6 +15,7 @@ from .data import JEDI_CLIN_TYPES from .fields import SelectField from .forms import BaseForm, remove_empty_string from atst.utils.localization import translate +from .validators import REGEX_ALPHA_NUMERIC from flask import current_app as app MAX_CLIN_AMOUNT = 1000000000 @@ -116,7 +117,10 @@ class AttachmentForm(BaseForm): filename = HiddenField( id="attachment_filename", validators=[ - Length(max=100, message=translate("forms.attachment.filename.length_error")) + Length( + max=100, message=translate("forms.attachment.filename.length_error") + ), + Regexp(regex=REGEX_ALPHA_NUMERIC), ], ) object_name = HiddenField( @@ -124,7 +128,8 @@ class AttachmentForm(BaseForm): validators=[ Length( max=40, message=translate("forms.attachment.object_name.length_error") - ) + ), + Regexp(regex=REGEX_ALPHA_NUMERIC), ], ) accept = ".pdf,application/pdf" diff --git a/atst/forms/validators.py b/atst/forms/validators.py index a16bf4f5..ebf29a2a 100644 --- a/atst/forms/validators.py +++ b/atst/forms/validators.py @@ -8,6 +8,9 @@ import pendulum from atst.utils.localization import translate +REGEX_ALPHA_NUMERIC = "^[A-Za-z0-9\-_ \.]*$" + + def DateRange(lower_bound=None, upper_bound=None, message=None): def _date_range(form, field): if field.data is None: diff --git a/atst/jobs.py b/atst/jobs.py index 4ee67f51..f4611a9a 100644 --- a/atst/jobs.py +++ b/atst/jobs.py @@ -7,14 +7,27 @@ from atst.models import ( EnvironmentJobFailure, EnvironmentRoleJobFailure, EnvironmentRole, + PortfolioJobFailure, ) from atst.domain.csp.cloud import CloudProviderInterface, GeneralCSPException from atst.domain.environments import Environments +from atst.domain.portfolios import Portfolios + from atst.domain.environment_roles import EnvironmentRoles from atst.models.utils import claim_for_update from atst.utils.localization import translate +class RecordPortfolioFailure(celery.Task): + def on_failure(self, exc, task_id, args, kwargs, einfo): + if "portfolio_id" in kwargs: + failure = PortfolioJobFailure( + portfolio_id=kwargs["portfolio_id"], task_id=task_id + ) + db.session.add(failure) + db.session.commit() + + class RecordEnvironmentFailure(celery.Task): def on_failure(self, exc, task_id, args, kwargs, einfo): if "environment_id" in kwargs: @@ -125,6 +138,17 @@ def do_work(fn, task, csp, **kwargs): raise task.retry(exc=e) +def do_provision_portfolio(csp: CloudProviderInterface, portfolio_id=None): + portfolio = Portfolios.get_for_update(portfolio_id) + fsm = Portfolios.get_or_create_state_machine(portfolio) + fsm.trigger_next_transition() + + +@celery.task(bind=True, base=RecordPortfolioFailure) +def provision_portfolio(self, portfolio_id=None): + do_work(do_provision_portfolio, self, app.csp.cloud, portfolio_id=portfolio_id) + + @celery.task(bind=True, base=RecordEnvironmentFailure) def create_environment(self, environment_id=None): do_work(do_create_environment, self, app.csp.cloud, environment_id=environment_id) @@ -144,6 +168,15 @@ def provision_user(self, environment_role_id=None): ) +@celery.task(bind=True) +def dispatch_provision_portfolio(self): + """ + Iterate over portfolios with a corresponding State Machine that have not completed. + """ + for portfolio_id in Portfolios.get_portfolios_pending_provisioning(): + provision_portfolio.delay(portfolio_id=portfolio_id) + + @celery.task(bind=True) def dispatch_create_environment(self): for environment_id in Environments.get_environments_pending_creation( diff --git a/atst/models/__init__.py b/atst/models/__init__.py index dc7b2f8a..f6c48306 100644 --- a/atst/models/__init__.py +++ b/atst/models/__init__.py @@ -7,11 +7,16 @@ from .audit_event import AuditEvent from .clin import CLIN, JEDICLINType from .environment import Environment from .environment_role import EnvironmentRole, CSPRole -from .job_failure import EnvironmentJobFailure, EnvironmentRoleJobFailure +from .job_failure import ( + EnvironmentJobFailure, + EnvironmentRoleJobFailure, + PortfolioJobFailure, +) from .notification_recipient import NotificationRecipient from .permissions import Permissions from .permission_set import PermissionSet from .portfolio import Portfolio +from .portfolio_state_machine import PortfolioStateMachine, FSMStates from .portfolio_invitation import PortfolioInvitation from .portfolio_role import PortfolioRole, Status as PortfolioRoleStatus from .task_order import TaskOrder diff --git a/atst/models/environment_role.py b/atst/models/environment_role.py index 5b3a2c27..21f033e0 100644 --- a/atst/models/environment_role.py +++ b/atst/models/environment_role.py @@ -9,10 +9,9 @@ import atst.models.types as types class CSPRole(Enum): - BASIC_ACCESS = "Basic Access" - NETWORK_ADMIN = "Network Admin" - BUSINESS_READ = "Business Read-only" - TECHNICAL_READ = "Technical Read-only" + ADMIN = "Admin" + BILLING_READ = "Billing Read-only" + CONTRIBUTOR = "Contributor" class EnvironmentRole( @@ -26,7 +25,7 @@ class EnvironmentRole( ) environment = relationship("Environment") - role = Column(String()) + role = Column(SQLAEnum(CSPRole, native_enum=False), nullable=True) application_role_id = Column( UUID(as_uuid=True), ForeignKey("application_roles.id"), nullable=False diff --git a/atst/models/job_failure.py b/atst/models/job_failure.py index c7ca9482..7a7f010a 100644 --- a/atst/models/job_failure.py +++ b/atst/models/job_failure.py @@ -14,3 +14,9 @@ class EnvironmentRoleJobFailure(Base, mixins.JobFailureMixin): __tablename__ = "environment_role_job_failures" environment_role_id = Column(ForeignKey("environment_roles.id"), nullable=False) + + +class PortfolioJobFailure(Base, mixins.JobFailureMixin): + __tablename__ = "portfolio_job_failures" + + portfolio_id = Column(ForeignKey("portfolios.id"), nullable=False) diff --git a/atst/models/mixins/__init__.py b/atst/models/mixins/__init__.py index fbc5e448..955171ab 100644 --- a/atst/models/mixins/__init__.py +++ b/atst/models/mixins/__init__.py @@ -4,3 +4,4 @@ from .permissions import PermissionsMixin from .deletable import DeletableMixin from .invites import InvitesMixin from .job_failure import JobFailureMixin +from .state_machines import FSMMixin diff --git a/atst/models/mixins/state_machines.py b/atst/models/mixins/state_machines.py new file mode 100644 index 00000000..bc35209d --- /dev/null +++ b/atst/models/mixins/state_machines.py @@ -0,0 +1,137 @@ +from enum import Enum + + +class StageStates(Enum): + CREATED = "created" + IN_PROGRESS = "in progress" + FAILED = "failed" + + +class AzureStages(Enum): + TENANT = "tenant" + BILLING_PROFILE = "billing profile" + ADMIN_SUBSCRIPTION = "admin subscription" + + +def _build_csp_states(csp_stages): + states = { + "UNSTARTED": "unstarted", + "STARTING": "starting", + "STARTED": "started", + "COMPLETED": "completed", + "FAILED": "failed", + } + for csp_stage in csp_stages: + for state in StageStates: + states[csp_stage.name + "_" + state.name] = ( + csp_stage.value + " " + state.value + ) + return states + + +FSMStates = Enum("FSMStates", _build_csp_states(AzureStages)) + + +def _build_transitions(csp_stages): + transitions = [] + states = [] + compose_state = lambda csp_stage, state: getattr( + FSMStates, "_".join([csp_stage.name, state.name]) + ) + + for stage_i, csp_stage in enumerate(csp_stages): + for state in StageStates: + states.append( + dict( + name=compose_state(csp_stage, state), + tags=[csp_stage.name, state.name], + ) + ) + if state == StageStates.CREATED: + if stage_i > 0: + src = compose_state( + list(csp_stages)[stage_i - 1], StageStates.CREATED + ) + else: + src = FSMStates.STARTED + transitions.append( + dict( + trigger="create_" + csp_stage.name.lower(), + source=src, + dest=compose_state(csp_stage, StageStates.IN_PROGRESS), + after="after_in_progress_callback", + ) + ) + if state == StageStates.IN_PROGRESS: + transitions.append( + dict( + trigger="finish_" + csp_stage.name.lower(), + source=compose_state(csp_stage, state), + dest=compose_state(csp_stage, StageStates.CREATED), + conditions=["is_csp_data_valid"], + ) + ) + if state == StageStates.FAILED: + transitions.append( + dict( + trigger="fail_" + csp_stage.name.lower(), + source=compose_state(csp_stage, StageStates.IN_PROGRESS), + dest=compose_state(csp_stage, StageStates.FAILED), + ) + ) + return states, transitions + + +class FSMMixin: + + system_states = [ + {"name": FSMStates.UNSTARTED.name, "tags": ["system"]}, + {"name": FSMStates.STARTING.name, "tags": ["system"]}, + {"name": FSMStates.STARTED.name, "tags": ["system"]}, + {"name": FSMStates.FAILED.name, "tags": ["system"]}, + {"name": FSMStates.COMPLETED.name, "tags": ["system"]}, + ] + + system_transitions = [ + {"trigger": "init", "source": FSMStates.UNSTARTED, "dest": FSMStates.STARTING}, + {"trigger": "start", "source": FSMStates.STARTING, "dest": FSMStates.STARTED}, + {"trigger": "reset", "source": "*", "dest": FSMStates.UNSTARTED}, + {"trigger": "fail", "source": "*", "dest": FSMStates.FAILED,}, + ] + + def prepare_init(self, event): + pass + + def before_init(self, event): + pass + + def after_init(self, event): + pass + + def prepare_start(self, event): + pass + + def before_start(self, event): + pass + + def after_start(self, event): + pass + + def prepare_reset(self, event): + pass + + def before_reset(self, event): + pass + + def after_reset(self, event): + pass + + def fail_stage(self, stage): + fail_trigger = "fail" + stage + if fail_trigger in self.machine.get_triggers(self.current_state.name): + self.trigger(fail_trigger) + + def finish_stage(self, stage): + finish_trigger = "finish_" + stage + if finish_trigger in self.machine.get_triggers(self.current_state.name): + self.trigger(finish_trigger) diff --git a/atst/models/portfolio.py b/atst/models/portfolio.py index 0e48745b..f60ed8de 100644 --- a/atst/models/portfolio.py +++ b/atst/models/portfolio.py @@ -11,6 +11,8 @@ from atst.domain.permission_sets import PermissionSets from atst.utils import first_or_none from atst.database import db +from sqlalchemy_json import NestedMutableJson + class Portfolio( Base, mixins.TimestampsMixin, mixins.AuditableMixin, mixins.DeletableMixin @@ -19,16 +21,31 @@ class Portfolio( id = types.Id() name = Column(String, nullable=False) - description = Column(String) defense_component = Column( - ARRAY(String), nullable=False + String, nullable=False ) # Department of Defense Component + app_migration = Column(String) # App Migration + complexity = Column(ARRAY(String)) # Application Complexity + complexity_other = Column(String) + description = Column(String) + dev_team = Column(ARRAY(String)) # Development Team + dev_team_other = Column(String) + native_apps = Column(String) # Native Apps + team_experience = Column(String) # Team Experience + + csp_data = Column(NestedMutableJson, nullable=True) + applications = relationship( "Application", back_populates="portfolio", primaryjoin="and_(Application.portfolio_id == Portfolio.id, Application.deleted == False)", ) + + state_machine = relationship( + "PortfolioStateMachine", uselist=False, back_populates="portfolio" + ) + roles = relationship("PortfolioRole") task_orders = relationship("TaskOrder") @@ -77,7 +94,7 @@ class Portfolio( """ Return the earliest period of performance start date and latest period of performance end date for all active task orders in a portfolio. - @return: (datetime.date or None, datetime.date or None) + @return: (datetime.date or None, datetime.date or None) """ start_dates = ( task_order.start_date diff --git a/atst/models/portfolio_role.py b/atst/models/portfolio_role.py index 53204e82..6d34dd97 100644 --- a/atst/models/portfolio_role.py +++ b/atst/models/portfolio_role.py @@ -12,17 +12,6 @@ from atst.utils import first_or_none from atst.models.mixins.auditable import record_permission_sets_updates -MEMBER_STATUSES = { - "active": "Active", - "revoked": "Invite revoked", - "expired": "Invite expired", - "error": "Error on invite", - "pending": "Pending", - "unknown": "Unknown errors", - "disabled": "Disabled", -} - - class Status(Enum): ACTIVE = "active" DISABLED = "disabled" @@ -90,23 +79,23 @@ class PortfolioRole( @property def display_status(self): if self.status == Status.ACTIVE: - return MEMBER_STATUSES["active"] + return "active" elif self.status == Status.DISABLED: - return MEMBER_STATUSES["disabled"] + return "disabled" elif self.latest_invitation: if self.latest_invitation.is_revoked: - return MEMBER_STATUSES["revoked"] + return "invite_revoked" elif self.latest_invitation.is_rejected_wrong_user: - return MEMBER_STATUSES["error"] + return "invite_error" elif ( self.latest_invitation.is_rejected_expired or self.latest_invitation.is_expired ): - return MEMBER_STATUSES["expired"] + return "invite_expired" else: - return MEMBER_STATUSES["pending"] + return "invite_pending" else: - return MEMBER_STATUSES["unknown"] + return "unknown" def has_permission_set(self, perm_set_name): return first_or_none( diff --git a/atst/models/portfolio_state_machine.py b/atst/models/portfolio_state_machine.py new file mode 100644 index 00000000..3c934197 --- /dev/null +++ b/atst/models/portfolio_state_machine.py @@ -0,0 +1,181 @@ +from sqlalchemy import Column, ForeignKey, Enum as SQLAEnum +from sqlalchemy.orm import relationship, reconstructor +from sqlalchemy.dialects.postgresql import UUID + +from pydantic import ValidationError as PydanticValidationError +from transitions import Machine +from transitions.extensions.states import add_state_features, Tags + +from flask import current_app as app + +from atst.domain.csp.cloud import ConnectionException, UnknownServerException +from atst.domain.csp import MockCSP, AzureCSP, get_stage_csp_class +from atst.database import db +from atst.models.types import Id +from atst.models.base import Base +import atst.models.mixins as mixins +from atst.models.mixins.state_machines import FSMStates, AzureStages, _build_transitions + + +@add_state_features(Tags) +class StateMachineWithTags(Machine): + pass + + +class PortfolioStateMachine( + Base, + mixins.TimestampsMixin, + mixins.AuditableMixin, + mixins.DeletableMixin, + mixins.FSMMixin, +): + __tablename__ = "portfolio_state_machines" + + id = Id() + + portfolio_id = Column(UUID(as_uuid=True), ForeignKey("portfolios.id"),) + portfolio = relationship("Portfolio", back_populates="state_machine") + + state = Column( + SQLAEnum(FSMStates, native_enum=False, create_constraint=False), + default=FSMStates.UNSTARTED, + nullable=False, + ) + + def __init__(self, portfolio, csp=None, **kwargs): + self.portfolio = portfolio + self.attach_machine() + + def after_state_change(self, event): + db.session.add(self) + db.session.commit() + + @reconstructor + def attach_machine(self): + """ + This is called as a result of a sqlalchemy query. + Attach a machine depending on the current state. + """ + self.machine = StateMachineWithTags( + model=self, + send_event=True, + initial=self.current_state if self.state else FSMStates.UNSTARTED, + auto_transitions=False, + after_state_change="after_state_change", + ) + states, transitions = _build_transitions(AzureStages) + self.machine.add_states(self.system_states + states) + self.machine.add_transitions(self.system_transitions + transitions) + + @property + def current_state(self): + if isinstance(self.state, str): + return getattr(FSMStates, self.state) + return self.state + + def trigger_next_transition(self): + state_obj = self.machine.get_state(self.state) + + if state_obj.is_system: + if self.current_state in (FSMStates.UNSTARTED, FSMStates.STARTING): + # call the first trigger availabe for these two system states + trigger_name = self.machine.get_triggers(self.current_state.name)[0] + self.trigger(trigger_name) + + elif self.current_state == FSMStates.STARTED: + # get the first trigger that starts with 'create_' + create_trigger = list( + filter( + lambda trigger: trigger.startswith("create_"), + self.machine.get_triggers(FSMStates.STARTED.name), + ) + )[0] + self.trigger(create_trigger) + + elif state_obj.is_IN_PROGRESS: + pass + + # elif state_obj.is_TENANT: + # pass + # elif state_obj.is_BILLING_PROFILE: + # pass + + # @with_payload + def after_in_progress_callback(self, event): + stage = self.current_state.name.split("_IN_PROGRESS")[0].lower() + if stage == "tenant": + payload = dict( # nosec + creds={"username": "mock-cloud", "pass": "shh"}, + user_id="123", + password="123", + domain_name="123", + first_name="john", + last_name="doe", + country_code="US", + password_recovery_email_address="password@email.com", + ) + elif stage == "billing_profile": + payload = dict(creds={"username": "mock-cloud", "pass": "shh"},) + + payload_data_cls = get_stage_csp_class(stage, "payload") + if not payload_data_cls: + self.fail_stage(stage) + try: + payload_data = payload_data_cls(**payload) + except PydanticValidationError as exc: + print(exc.json()) + self.fail_stage(stage) + + csp = event.kwargs.get("csp") + if csp is not None: + self.csp = AzureCSP(app).cloud + else: + self.csp = MockCSP(app).cloud + + for attempt in range(5): + try: + response = getattr(self.csp, "create_" + stage)(payload_data) + except (ConnectionException, UnknownServerException) as exc: + print("caught exception. retry", attempt) + continue + else: + break + else: + # failed all attempts + self.fail_stage(stage) + + if self.portfolio.csp_data is None: + self.portfolio.csp_data = {} + self.portfolio.csp_data[stage + "_data"] = response + db.session.add(self.portfolio) + db.session.commit() + + self.finish_stage(stage) + + def is_csp_data_valid(self, event): + # check portfolio csp details json field for fields + + if self.portfolio.csp_data is None or not isinstance( + self.portfolio.csp_data, dict + ): + return False + + stage = self.current_state.name.split("_IN_PROGRESS")[0].lower() + stage_data = self.portfolio.csp_data.get(stage + "_data") + cls = get_stage_csp_class(stage, "result") + if not cls: + return False + + try: + cls(**stage_data) + except PydanticValidationError as exc: + print(exc.json()) + return False + + return True + + # print('failed condition', self.portfolio.csp_data) + + @property + def application_id(self): + return None diff --git a/atst/models/task_order.py b/atst/models/task_order.py index 36ba905e..789a7e3f 100644 --- a/atst/models/task_order.py +++ b/atst/models/task_order.py @@ -140,7 +140,10 @@ class TaskOrder(Base, mixins.TimestampsMixin): @property def invoiced_funds(self): # TODO: implement this using reporting data from the CSP - return self.total_obligated_funds * Decimal(0.75) + if self.is_active: + return self.total_obligated_funds * Decimal(0.75) + else: + return 0 @property def display_status(self): diff --git a/atst/models/user.py b/atst/models/user.py index 29b377d6..a45760d0 100644 --- a/atst/models/user.py +++ b/atst/models/user.py @@ -1,4 +1,4 @@ -from sqlalchemy import String, ForeignKey, Column, Date, Boolean, Table, TIMESTAMP +from sqlalchemy import String, ForeignKey, Column, Date, Table, TIMESTAMP from sqlalchemy.orm import relationship from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.event import listen @@ -67,8 +67,6 @@ class User( last_login = Column(TIMESTAMP(timezone=True), nullable=True) last_session_id = Column(UUID(as_uuid=True), nullable=True) - provisional = Column(Boolean) - cloud_id = Column(String) REQUIRED_FIELDS = [ diff --git a/atst/queue.py b/atst/queue.py index dfe9d894..1dce690c 100644 --- a/atst/queue.py +++ b/atst/queue.py @@ -7,6 +7,10 @@ celery = Celery(__name__) def update_celery(celery, app): celery.conf.update(app.config) celery.conf.CELERYBEAT_SCHEDULE = { + "beat-dispatch_provision_portfolio": { + "task": "atst.jobs.dispatch_provision_portfolio", + "schedule": 60, + }, "beat-dispatch_create_environment": { "task": "atst.jobs.dispatch_create_environment", "schedule": 60, diff --git a/atst/routes/__init__.py b/atst/routes/__init__.py index 9665ef9b..4e366a08 100644 --- a/atst/routes/__init__.py +++ b/atst/routes/__init__.py @@ -19,6 +19,7 @@ from werkzeug.exceptions import NotFound from atst.domain.users import Users from atst.domain.authnid import AuthenticationContext from atst.domain.auth import logout as _logout +from atst.domain.exceptions import UnauthenticatedError from atst.utils.flash import formatted_flash as flash @@ -64,11 +65,15 @@ def catch_all(path): raise NotFound() +def _client_s_dn(): + return request.environ.get("HTTP_X_SSL_CLIENT_S_DN") + + def _make_authentication_context(): return AuthenticationContext( crl_cache=app.crl_cache, auth_status=request.environ.get("HTTP_X_SSL_CLIENT_VERIFY"), - sdn=request.environ.get("HTTP_X_SSL_CLIENT_S_DN"), + sdn=_client_s_dn(), cert=request.environ.get("HTTP_X_SSL_CLIENT_CERT"), ) @@ -89,19 +94,24 @@ def current_user_setup(user): session["user_id"] = user.id session["last_login"] = user.last_login app.session_limiter.on_login(user) + app.logger.info(f"authentication succeeded for user with EDIPI {user.dod_id}") Users.update_last_login(user) @bp.route("/login-redirect") def login_redirect(): - auth_context = _make_authentication_context() - auth_context.authenticate() - user = auth_context.get_user() + try: + auth_context = _make_authentication_context() + auth_context.authenticate() - if user.provisional: - Users.finalize(user) + user = auth_context.get_user() + current_user_setup(user) + except UnauthenticatedError as err: + app.logger.info( + f"authentication failed for subject distinguished name {_client_s_dn()}" + ) + raise err - current_user_setup(user) return redirect(redirect_after_login_url()) diff --git a/atst/routes/applications/settings.py b/atst/routes/applications/settings.py index 92226e89..91676cfb 100644 --- a/atst/routes/applications/settings.py +++ b/atst/routes/applications/settings.py @@ -78,7 +78,7 @@ def filter_env_roles_data(roles): { "environment_id": str(role.environment.id), "environment_name": role.environment.name, - "role": role.role, + "role": (role.role.value if role.role else "None"), } for role in roles ], @@ -99,8 +99,9 @@ def filter_env_roles_form_data(member, environments): if len(env_roles_set) == 1: (env_role,) = env_roles_set - env_data["role"] = env_role.role env_data["disabled"] = env_role.disabled + if env_role.role: + env_data["role"] = env_role.role.name env_roles_form_data.append(env_data) diff --git a/atst/routes/portfolios/admin.py b/atst/routes/portfolios/admin.py index 1b4ac711..699bdfab 100644 --- a/atst/routes/portfolios/admin.py +++ b/atst/routes/portfolios/admin.py @@ -17,63 +17,51 @@ from atst.utils.flash import formatted_flash as flash from atst.domain.exceptions import UnauthorizedError -def permission_str(member, edit_perm_set, view_perm_set): - if member.has_permission_set(edit_perm_set): - return edit_perm_set - else: - return view_perm_set - - -def serialize_member_form_data(member): - return { - "member_name": member.full_name, - "member_id": member.id, - "perms_app_mgmt": permission_str( - member, - PermissionSets.EDIT_PORTFOLIO_APPLICATION_MANAGEMENT, - PermissionSets.VIEW_PORTFOLIO_APPLICATION_MANAGEMENT, +def filter_perm_sets_data(member): + perm_sets_data = { + "perms_portfolio_mgmt": bool( + member.has_permission_set(PermissionSets.EDIT_PORTFOLIO_ADMIN) ), - "perms_funding": permission_str( - member, - PermissionSets.EDIT_PORTFOLIO_FUNDING, - PermissionSets.VIEW_PORTFOLIO_FUNDING, + "perms_app_mgmt": bool( + member.has_permission_set( + PermissionSets.EDIT_PORTFOLIO_APPLICATION_MANAGEMENT + ) ), - "perms_reporting": permission_str( - member, - PermissionSets.EDIT_PORTFOLIO_REPORTS, - PermissionSets.VIEW_PORTFOLIO_REPORTS, + "perms_funding": bool( + member.has_permission_set(PermissionSets.EDIT_PORTFOLIO_FUNDING) ), - "perms_portfolio_mgmt": permission_str( - member, - PermissionSets.EDIT_PORTFOLIO_ADMIN, - PermissionSets.VIEW_PORTFOLIO_ADMIN, + "perms_reporting": bool( + member.has_permission_set(PermissionSets.EDIT_PORTFOLIO_REPORTS) ), } + return perm_sets_data -def get_members_data(portfolio): - members = sorted( - [serialize_member_form_data(member) for member in portfolio.members], - key=lambda member: member["member_name"], - ) - for member in members: - if member["member_id"] == portfolio.owner_role.id: - ppoc = member - members.remove(member) - members.insert(0, ppoc) - return members + +def filter_members_data(members_list, portfolio): + members_data = [] + for member in members_list: + members_data.append( + { + "role_id": member.id, + "user_name": member.user_name, + "permission_sets": filter_perm_sets_data(member), + "status": member.display_status, + "ppoc": PermissionSets.PORTFOLIO_POC in member.permission_sets, + # add in stuff here for forms + } + ) + + return sorted(members_data, key=lambda member: member["user_name"]) def render_admin_page(portfolio, form=None): pagination_opts = Paginator.get_pagination_opts(http_request) audit_events = AuditLog.get_portfolio_events(portfolio, pagination_opts) - members_data = get_members_data(portfolio) portfolio_form = PortfolioForm(obj=portfolio) - member_perms_form = member_forms.MembersPermissionsForm( - data={"members_permissions": members_data} - ) - + member_list = portfolio.members assign_ppoc_form = member_forms.AssignPPOCForm() + for pf_role in portfolio.roles: if pf_role.user != portfolio.owner and pf_role.is_active: assign_ppoc_form.role_id.choices += [(pf_role.id, pf_role.full_name)] @@ -87,13 +75,12 @@ def render_admin_page(portfolio, form=None): "portfolios/admin.html", form=form, portfolio_form=portfolio_form, - member_perms_form=member_perms_form, - member_form=member_forms.NewForm(), + members=filter_members_data(member_list, portfolio), + new_manager_form=member_forms.NewForm(), assign_ppoc_form=assign_ppoc_form, portfolio=portfolio, audit_events=audit_events, user=g.current_user, - ppoc_id=members_data[0].get("member_id"), current_member_id=current_member_id, applications_count=len(portfolio.applications), ) @@ -106,34 +93,6 @@ def admin(portfolio_id): return render_admin_page(portfolio) -@portfolios_bp.route("/portfolios//admin", methods=["POST"]) -@user_can(Permissions.EDIT_PORTFOLIO_USERS, message="view portfolio admin page") -def edit_members(portfolio_id): - portfolio = Portfolios.get_for_update(portfolio_id) - member_perms_form = member_forms.MembersPermissionsForm(http_request.form) - - if member_perms_form.validate(): - for subform in member_perms_form.members_permissions: - member_id = subform.member_id.data - member = PortfolioRoles.get_by_id(member_id) - if member is not portfolio.owner_role: - new_perm_set = subform.data["permission_sets"] - PortfolioRoles.update(member, new_perm_set) - - flash("update_portfolio_members", portfolio=portfolio) - - return redirect( - url_for( - "portfolios.admin", - portfolio_id=portfolio_id, - fragment="portfolio-members", - _anchor="portfolio-members", - ) - ) - else: - return render_admin_page(portfolio) - - @portfolios_bp.route("/portfolios//update_ppoc", methods=["POST"]) @user_can(Permissions.EDIT_PORTFOLIO_POC, message="update portfolio ppoc") def update_ppoc(portfolio_id): diff --git a/atst/routes/portfolios/invitations.py b/atst/routes/portfolios/invitations.py index 8f2e4701..09a22d1f 100644 --- a/atst/routes/portfolios/invitations.py +++ b/atst/routes/portfolios/invitations.py @@ -79,7 +79,7 @@ def invite_member(portfolio_id): if form.validate(): try: - invite = Portfolios.invite(portfolio, g.current_user, form.update_data) + invite = Portfolios.invite(portfolio, g.current_user, form.data) send_portfolio_invitation( invitee_email=invite.email, inviter_name=g.current_user.full_name, diff --git a/atst/utils/flash.py b/atst/utils/flash.py index f876330f..da2c9253 100644 --- a/atst/utils/flash.py +++ b/atst/utils/flash.py @@ -1,214 +1,171 @@ -from flask import flash, render_template_string +from flask import flash from atst.utils.localization import translate + MESSAGES = { - "portfolio_deleted": { - "title_template": "Portfolio has been deleted", - "message_template": "Portfolio '{{portfolio_name}}' has been deleted", - "category": "success", - }, "application_created": { - "title_template": translate("flash.application.created.title"), - "message_template": """ - {{ "flash.application.created.message" | translate({"application_name": application_name}) }} - """, + "title": "flash.application.created.title", + "message": "flash.application.created.message", "category": "success", }, "application_updated": { - "title_template": translate("flash.success"), - "message_template": """ - {{ "flash.application.updated" | translate({"application_name": application_name}) }} - """, - "category": "success", - }, - "application_deleted": { - "title_template": translate("flash.success"), - "message_template": """ - {{ "flash.application.deleted" | translate({"application_name": application_name}) }} - {{ "common.undo" | translate }} - """, + "title": "flash.success", + "message": "flash.application.updated", "category": "success", }, "application_environments_name_error": { - "title_template": "", - "message_template": """{{ 'flash.application.env_name_error.message' | translate({ 'name': name }) }}""", + "title": None, + "message": "flash.application.env_name_error.message", "category": "error", }, "application_environments_updated": { - "title_template": "Application environments updated", - "message_template": "Application environments have been updated", + "title": "flash.environment.updated.title", + "message": "flash.environment.updated.message", "category": "success", }, "application_invite_error": { - "title_template": "Application invitation error", - "message_template": "There was an error processing the invitation for {{ user_name }} from {{ application_name }}", + "title": "flash.application_invite.error.title", + "message": "flash.application_invite.error.message", "category": "error", }, "application_invite_resent": { - "title_template": "Application invitation resent", - "message_template": "You have successfully resent the invite for {{ user_name }} from {{ application_name }}", + "title": "flash.application_invite.resent.title", + "message": "flash.application_invite.resent.message", "category": "success", }, "application_invite_revoked": { - "title_template": "Application invitation revoked", - "message_template": "You have successfully revoked the invite for {{ user_name }} from {{ application_name }}", + "title": "flash.application_invite.revoked.title", + "message": "flash.application_invite.revoked.message", "category": "success", }, "application_member_removed": { - "title_template": "Team member removed from application", - "message_template": "You have successfully deleted {{ user_name }} from {{ application_name }}", + "title": "flash.application_member.removed.title", + "message": "flash.application_member.removed.message", "category": "success", }, "application_member_update_error": { - "title_template": "{{ user_name }} could not be updated", - "message_template": "An unexpected problem occurred with your request, please try again. If the problem persists, contact an administrator.", + "title": "flash.application_member.update_error.title", + "message": "flash.application_member.update_error.message", "category": "error", }, "application_member_updated": { - "title_template": "Team member updated", - "message_template": "You have successfully updated the permissions for {{ user_name }}", + "title": "flash.application_member.updated.title", + "message": "flash.application_member.updated.message", "category": "success", }, "application_name_error": { - "title_template": "", - "message_template": """{{ 'flash.application.name_error.message' | translate({ 'name': name }) }}""", + "title": None, + "message": "flash.application.name_error.message", "category": "error", }, "ccpo_user_added": { - "title_template": translate("flash.success"), - "message_template": "You have successfully given {{ user_name }} CCPO permissions.", + "title": "flash.success", + "message": "flash.ccpo_user.added.message", "category": "success", }, "ccpo_user_not_found": { - "title_template": translate("ccpo.form.user_not_found_title"), - "message_template": translate("ccpo.form.user_not_found_text"), + "title": "ccpo.form.user_not_found_title", + "message": "ccpo.form.user_not_found_text", "category": "info", }, "ccpo_user_removed": { - "title_template": translate("flash.success"), - "message_template": "You have successfully removed {{ user_name }}'s CCPO permissions.", + "title": "flash.success", + "message": "flash.ccpo_user.removed.message", "category": "success", }, "environment_added": { - "title_template": translate("flash.success"), - "message_template": """ - {{ "flash.environment_added" | translate({ "env_name": environment_name }) }} - """, + "title": "flash.success", + "message": "flash.environment_added", "category": "success", }, "environment_deleted": { - "title_template": "{{ environment_name }} deleted", - "message_template": 'The environment "{{ environment_name }}" has been deleted', + "title": "flash.environment.deleted.title", + "message": "flash.environment.deleted.message", "category": "success", }, "form_errors": { - "title_template": "There were some errors", - "message_template": "

Please see below.

", + "title": "flash.form.errors.title", + "message": "flash.form.errors.message", "category": "error", }, "insufficient_funds": { - "title_template": "Insufficient Funds", - "message_template": "", + "title": "flash.task_order.insufficient_funds.title", + "message": "", "category": "warning", }, "logged_out": { - "title_template": translate("flash.logged_out"), - "message_template": """ - You've been logged out. - """, + "title": "flash.logged_out.title", + "message": "flash.logged_out.message", "category": "info", }, "login_next": { - "title_template": translate("flash.login_required_title"), - "message_template": translate("flash.login_required_message"), + "title": "flash.login_required_title", + "message": "flash.login_required_message", "category": "warning", }, "new_application_member": { - "title_template": """{{ "flash.new_application_member.title" | translate({ "user_name": user_name }) }}""", - "message_template": """ -

{{ "flash.new_application_member.message" | translate({ "user_name": user_name }) }}

- """, + "title": "flash.new_application_member.title", + "message": "flash.new_application_member.message", "category": "success", }, "new_portfolio_member": { - "title_template": translate("flash.success"), - "message_template": """ -

{{ "flash.new_portfolio_member" | translate({ "user_name": user_name }) }}

- """, + "title": "flash.success", + "message": "flash.new_portfolio_member", "category": "success", }, "portfolio_member_removed": { - "title_template": translate("flash.deleted_member"), - "message_template": """ - {{ "flash.delete_member_success" | translate({ "member_name": member_name }) }} - """, + "title": "flash.deleted_member", + "message": "flash.delete_member_success", "category": "success", }, "primary_point_of_contact_changed": { - "title_template": translate("flash.new_ppoc_title"), - "message_template": """{{ "flash.new_ppoc_message" | translate({ "ppoc_name": ppoc_name }) }}""", + "title": "flash.new_ppoc_title", + "message": "flash.new_ppoc_message", "category": "success", }, "resend_portfolio_invitation": { - "title_template": "Invitation resent", - "message_template": """ -

Successfully sent a new invitation to {{ user_name }}.

- """, + "title": "flash.portfolio_invite.resent.title", + "message": "flash.portfolio_invite.resent.message", "category": "success", }, "revoked_portfolio_access": { - "title_template": "Removed portfolio access", - "message_template": """ -

Portfolio access successfully removed from {{ member_name }}.

- """, + "title": "flash.portfolio_member.revoked.title", + "message": "flash.portfolio_member.revoked.message", "category": "success", }, "session_expired": { - "title_template": "Session Expired", - "message_template": """ - Your session expired due to inactivity. Please log in again to continue. - """, + "title": "flash.session_expired.title", + "message": "flash.session_expired.message", "category": "error", }, "task_order_draft": { - "title_template": translate("task_orders.form.draft_alert_title"), - "message_template": translate("task_orders.form.draft_alert_message"), + "title": "task_orders.form.draft_alert_title", + "message": "task_orders.form.draft_alert_message", "category": "warning", }, "task_order_number_error": { - "title_template": "", - "message_template": """{{ 'flash.task_order_number_error.message' | translate({ 'to_number': to_number }) }}""", + "title": None, + "message": "flash.task_order_number_error.message", "category": "error", }, "task_order_submitted": { - "title_template": "Your Task Order has been uploaded successfully.", - "message_template": """ - Your task order form for {{ task_order.portfolio_name }} has been submitted. - """, - "category": "success", - }, - "update_portfolio_members": { - "title_template": "Success!", - "message_template": """ -

You have successfully updated access permissions for members of {{ portfolio.name }}.

- """, + "title": "flash.task_order.submitted.title", + "message": "flash.task_order.submitted.message", "category": "success", }, "updated_application_team_settings": { - "title_template": translate("flash.success"), - "message_template": """ -

{{ "flash.updated_application_team_settings" | translate({"application_name": application_name}) }}

- """, + "title": "flash.success", + "message": "flash.updated_application_team_settings", "category": "success", }, "user_must_complete_profile": { - "title_template": "You must complete your profile", - "message_template": "

Before continuing, you must complete your profile

", + "title": "flash.user.complete_profile.title", + "message": "flash.user.complete_profile.message", "category": "info", }, "user_updated": { - "title_template": "User information updated.", - "message_template": "", + "title": "flash.user.updated.title", + "message": None, "category": "success", }, } @@ -216,9 +173,11 @@ MESSAGES = { def formatted_flash(message_name, **message_args): config = MESSAGES[message_name] - title = render_template_string(config["title_template"], **message_args) - message = render_template_string(config["message_template"], **message_args) - actions = None - if "actions" in config: - actions = render_template_string(config["actions"], **message_args) + + title = translate(config["title"], message_args) if config["title"] else None + message = translate(config["message"], message_args) if config["message"] else None + actions = ( + translate(config["actions"], message_args) if config.get("actions") else None + ) + flash({"title": title, "message": message, "actions": actions}, config["category"]) diff --git a/atst/utils/logging.py b/atst/utils/logging.py index 94e7aab6..f0b16dff 100644 --- a/atst/utils/logging.py +++ b/atst/utils/logging.py @@ -2,16 +2,22 @@ import datetime import json import logging -from flask import g, request, has_request_context +from flask import g, request, has_request_context, session class RequestContextFilter(logging.Filter): def filter(self, record): if has_request_context(): if getattr(g, "current_user", None): - record.user_id = str(g.current_user.id) record.dod_edipi = g.current_user.dod_id + user_id = session.get("user_id") + if user_id: + record.user_id = str(user_id) + record.logged_in = True + else: + record.logged_in = False + if request.environ.get("HTTP_X_REQUEST_ID"): record.request_id = request.environ.get("HTTP_X_REQUEST_ID") @@ -30,6 +36,7 @@ class JsonFormatter(logging.Formatter): ("request_id", lambda r: r.__dict__.get("request_id")), ("user_id", lambda r: r.__dict__.get("user_id")), ("dod_edipi", lambda r: r.__dict__.get("dod_edipi")), + ("logged_in", lambda r: r.__dict__.get("logged_in")), ("severity", lambda r: r.levelname), ("tags", lambda r: r.__dict__.get("tags")), ("audit_event", lambda r: r.__dict__.get("audit_event")), @@ -44,7 +51,7 @@ class JsonFormatter(logging.Formatter): for field, func in self._DEFAULT_RECORD_FIELDS: result = func(record) - if result: + if result is not None: message_dict[field] = result if record.args: diff --git a/config/base.ini b/config/base.ini index 9233ef21..1df7f47a 100644 --- a/config/base.ini +++ b/config/base.ini @@ -15,6 +15,7 @@ CRL_FAIL_OPEN = false CRL_STORAGE_CONTAINER = crls CSP=mock DEBUG = true +DEBUG_MAILER = false DISABLE_CRL_CHECK = false ENVIRONMENT = dev LIMIT_CONCURRENT_SESSIONS = false diff --git a/deploy/azure/autoscaling.yml b/deploy/azure/autoscaling.yml new file mode 100644 index 00000000..e208d943 --- /dev/null +++ b/deploy/azure/autoscaling.yml @@ -0,0 +1,40 @@ +--- +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + labels: + app: atst + name: atst + namespace: atat +spec: + minReplicas: 2 + maxReplicas: 10 + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: atst + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: 60 +--- +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + labels: + app: atst + name: atst-worker + namespace: atat +spec: + minReplicas: 1 + maxReplicas: 10 + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: atst-worker + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: 60 diff --git a/deploy/azure/azure.yml b/deploy/azure/azure.yml index 8fe7fd87..1300ed34 100644 --- a/deploy/azure/azure.yml +++ b/deploy/azure/azure.yml @@ -15,7 +15,6 @@ spec: selector: matchLabels: role: web - replicas: 4 strategy: type: RollingUpdate template: @@ -49,6 +48,13 @@ spec: subPath: uwsgi.ini - name: flask-secret mountPath: "/config" + resources: + requests: + memory: 200Mi + cpu: 400m + limits: + memory: 200Mi + cpu: 400m - name: nginx image: nginx:alpine ports: @@ -77,6 +83,13 @@ spec: mountPath: "/etc/nginx/snippets/" - name: nginx-secret mountPath: "/etc/ssl/" + resources: + requests: + memory: 20Mi + cpu: 10m + limits: + memory: 20Mi + cpu: 10m volumes: - name: nginx-client-ca-bundle configMap: @@ -155,7 +168,6 @@ spec: selector: matchLabels: role: worker - replicas: 2 strategy: type: RollingUpdate template: @@ -190,6 +202,13 @@ spec: subPath: pgsslrootcert.crt - name: flask-secret mountPath: "/config" + resources: + requests: + memory: 280Mi + cpu: 400m + limits: + memory: 280Mi + cpu: 400m volumes: - name: pgsslrootcert configMap: @@ -255,6 +274,13 @@ spec: subPath: pgsslrootcert.crt - name: flask-secret mountPath: "/config" + resources: + requests: + memory: 80Mi + cpu: 10m + limits: + memory: 80Mi + cpu: 10m volumes: - name: pgsslrootcert configMap: diff --git a/deploy/azure/kustomization.yaml b/deploy/azure/kustomization.yaml index 9dee809c..d0162394 100644 --- a/deploy/azure/kustomization.yaml +++ b/deploy/azure/kustomization.yaml @@ -12,3 +12,4 @@ resources: - acme-challenges.yml - aadpodidentity.yml - nginx-snippets.yml + - autoscaling.yml diff --git a/deploy/minikube/atst-configmap.yml b/deploy/minikube/atst-configmap.yml deleted file mode 100644 index 79f9a61b..00000000 --- a/deploy/minikube/atst-configmap.yml +++ /dev/null @@ -1,35 +0,0 @@ ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: atst-config - namespace: atat -data: - uwsgi-config: |- - [uwsgi] - callable = app - module = app - socket = /var/run/uwsgi/uwsgi.socket - plugin = python3 - plugin = logfile - virtualenv = /opt/atat/atst/.venv - chmod-socket = 666 - - ; logger config - - ; application logs: log without modifying - logger = secondlogger stdio - log-route = secondlogger atst - log-encoder = format:secondlogger ${msg} - - ; default uWSGI messages (start, stop, etc.) - logger = default stdio - log-route = default ^((?!atst).)*$ - log-encoder = json:default {"timestamp":"${strftime:%%FT%%T}","source":"uwsgi","severity":"DEBUG","message":"${msg}"} - log-encoder = nl - - ; uWSGI request logs - logger-req = stdio - log-format = request_id=%(var.HTTP_X_REQUEST_ID), pid=%(pid), remote_add=%(addr), request=%(method) %(uri), status=%(status), body_bytes_sent=%(rsize), referer=%(referer), user_agent=%(uagent), http_x_forwarded_for=%(var.HTTP_X_FORWARDED_FOR) - log-req-encoder = json {"timestamp":"${strftime:%%FT%%T}","source":"req","severity":"INFO","message":"${msg}"} - log-req-encoder = nl diff --git a/deploy/minikube/atst-envvars-configmap.yml b/deploy/minikube/atst-envvars-configmap.yml deleted file mode 100644 index 997ce16a..00000000 --- a/deploy/minikube/atst-envvars-configmap.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: atst-envvars - namespace: atat -data: - TZ: UTC - FLASK_ENV: dev - OVERRIDE_CONFIG_FULLPATH: /opt/atat/atst/atst-overrides.ini - UWSGI_CONFIG_FULLPATH: /opt/atat/atst/uwsgi.ini - CRL_STORAGE_PROVIDER: CLOUDFILES - LOG_JSON: "true" - REDIS_URI: "redis://redis-svc:6379" - PGHOST: postgres-svc diff --git a/deploy/minikube/atst-nginx-configmap.yml b/deploy/minikube/atst-nginx-configmap.yml deleted file mode 100644 index 7c0d7506..00000000 --- a/deploy/minikube/atst-nginx-configmap.yml +++ /dev/null @@ -1,73 +0,0 @@ ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: atst-nginx - namespace: atat -data: - nginx-config: |- - server { - listen 8342; - server_name aws.atat.code.mil; - return 301 https://$host$request_uri; - } - server { - listen 8343; - server_name auth-aws.atat.code.mil; - return 301 https://$host$request_uri; - } - server { - server_name aws.atat.code.mil; - # access_log /var/log/nginx/access.log json; - listen 8442; - location /login-redirect { - return 301 https://auth-aws.atat.code.mil$request_uri; - } - location /login-dev { - try_files $uri @appbasicauth; - } - location / { - try_files $uri @app; - } - location @app { - include uwsgi_params; - uwsgi_pass unix:///var/run/uwsgi/uwsgi.socket; - uwsgi_param HTTP_X_REQUEST_ID $request_id; - } - location @appbasicauth { - include uwsgi_params; - uwsgi_pass unix:///var/run/uwsgi/uwsgi.socket; - auth_basic "Developer Access"; - auth_basic_user_file /etc/nginx/.htpasswd; - uwsgi_param HTTP_X_REQUEST_ID $request_id; - } - } - server { - # access_log /var/log/nginx/access.log json; - server_name auth-aws.atat.code.mil; - listen 8443; - listen [::]:8443 ipv6only=on; - # Request and validate client certificate - ssl_verify_client on; - ssl_verify_depth 10; - ssl_client_certificate /etc/ssl/client-ca-bundle.pem; - # Guard against HTTPS -> HTTP downgrade - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; always"; - location / { - return 301 https://aws.atat.code.mil$request_uri; - } - location /login-redirect { - try_files $uri @app; - } - location @app { - include uwsgi_params; - uwsgi_pass unix:///var/run/uwsgi/uwsgi.socket; - uwsgi_param HTTP_X_SSL_CLIENT_VERIFY $ssl_client_verify; - uwsgi_param HTTP_X_SSL_CLIENT_CERT $ssl_client_raw_cert; - uwsgi_param HTTP_X_SSL_CLIENT_S_DN $ssl_client_s_dn; - uwsgi_param HTTP_X_SSL_CLIENT_S_DN_LEGACY $ssl_client_s_dn_legacy; - uwsgi_param HTTP_X_SSL_CLIENT_I_DN $ssl_client_i_dn; - uwsgi_param HTTP_X_SSL_CLIENT_I_DN_LEGACY $ssl_client_i_dn_legacy; - uwsgi_param HTTP_X_REQUEST_ID $request_id; - } - } diff --git a/deploy/minikube/atst-worker-envvars-configmap.yml b/deploy/minikube/atst-worker-envvars-configmap.yml deleted file mode 100644 index 9d477597..00000000 --- a/deploy/minikube/atst-worker-envvars-configmap.yml +++ /dev/null @@ -1,12 +0,0 @@ ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: atst-worker-envvars - namespace: atat -data: - TZ: UTC - DISABLE_CRL_CHECK: "True" - CRL_STORAGE_PROVIDER: CLOUDFILES - REDIS_URI: "redis://redis-svc:6379" - PGHOST: postgres-svc diff --git a/deploy/minikube/datastores.yml b/deploy/minikube/datastores.yml deleted file mode 100644 index a3eeda7e..00000000 --- a/deploy/minikube/datastores.yml +++ /dev/null @@ -1,61 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: db-cache - name: datastores - namespace: atat -spec: - selector: - matchLabels: - app: db-cache - replicas: 1 - strategy: - type: RollingUpdate - template: - metadata: - labels: - app: db-cache - spec: - securityContext: - fsGroup: 101 - containers: - - name: postgres - image: postgres:11-alpine - imagePullPolicy: Never - ports: - - containerPort: 5432 - - name: redis - image: redis:5.0-alpine - imagePullPolicy: Never - ports: - - containerPort: 6379 ---- -apiVersion: v1 -kind: Service -metadata: - name: postgres-svc - namespace: atat -spec: - ports: - - name: db-port - protocol: "TCP" - port: 5432 - targetPort: 5432 - selector: - app: db-cache ---- -apiVersion: v1 -kind: Service -metadata: - name: redis-svc - namespace: atat -spec: - ports: - - name: cache-port - protocol: "TCP" - port: 6379 - targetPort: 6379 - selector: - app: db-cache diff --git a/deploy/minikube/minikube.yml b/deploy/minikube/minikube.yml deleted file mode 100644 index c78d663b..00000000 --- a/deploy/minikube/minikube.yml +++ /dev/null @@ -1,232 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: atst - name: atst - namespace: atat -spec: - selector: - matchLabels: - role: web - replicas: 1 - strategy: - type: RollingUpdate - template: - metadata: - labels: - app: atst - role: web - spec: - securityContext: - fsGroup: 101 - containers: - - name: atst - image: atat:latest - imagePullPolicy: Never - envFrom: - - configMapRef: - name: atst-envvars - volumeMounts: - - name: atst-config - mountPath: "/opt/atat/atst/atst-overrides.ini" - subPath: atst-overrides.ini - - name: nginx-client-ca-bundle - mountPath: "/opt/atat/atst/ssl/server-certs/ca-chain.pem" - subPath: client-ca-bundle.pem - - name: uwsgi-socket-dir - mountPath: "/var/run/uwsgi" - - name: nginx - image: nginx:alpine - imagePullPolicy: Never - ports: - - containerPort: 8342 - name: main-upgrade - - containerPort: 8442 - name: main - - containerPort: 8343 - name: auth-upgrade - - containerPort: 8443 - name: auth - volumeMounts: - - name: nginx-config - mountPath: "/etc/nginx/conf.d/atst.conf" - subPath: atst.conf - - name: uwsgi-socket-dir - mountPath: "/var/run/uwsgi" - - name: nginx-htpasswd - mountPath: "/etc/nginx/.htpasswd" - subPath: .htpasswd - - name: nginx-client-ca-bundle - mountPath: "/etc/ssl/" - volumes: - - name: atst-config - secret: - secretName: atst-config-ini - items: - - key: override.ini - path: atst-overrides.ini - mode: 0644 - - name: nginx-client-ca-bundle - configMap: - name: nginx-client-ca-bundle - defaultMode: 0666 - - name: nginx-config - configMap: - name: atst-nginx - items: - - key: nginx-config - path: atst.conf - - name: uwsgi-socket-dir - emptyDir: - medium: Memory - - name: nginx-htpasswd - secret: - secretName: atst-nginx-htpasswd - items: - - key: htpasswd - path: .htpasswd - mode: 0640 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: atst - name: atst-worker - namespace: atat -spec: - selector: - matchLabels: - role: worker - replicas: 1 - strategy: - type: RollingUpdate - template: - metadata: - labels: - app: atst - role: worker - spec: - securityContext: - fsGroup: 101 - containers: - - name: atst-worker - image: atat:latest - imagePullPolicy: Never - args: [ - "/opt/atat/atst/.venv/bin/python", - "/opt/atat/atst/.venv/bin/celery", - "-A", - "celery_worker.celery", - "worker", - "--loglevel=info" - ] - envFrom: - - configMapRef: - name: atst-envvars - - configMapRef: - name: atst-worker-envvars - volumeMounts: - - name: atst-config - mountPath: "/opt/atat/atst/atst-overrides.ini" - subPath: atst-overrides.ini - volumes: - - name: atst-config - secret: - secretName: atst-config-ini - items: - - key: override.ini - path: atst-overrides.ini - mode: 0644 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: atst - name: atst-beat - namespace: atat -spec: - selector: - matchLabels: - role: beat - replicas: 1 - strategy: - type: RollingUpdate - template: - metadata: - labels: - app: atst - role: beat - spec: - securityContext: - fsGroup: 101 - containers: - - name: atst-beat - image: atat:latest - imagePullPolicy: Never - args: [ - "/opt/atat/atst/.venv/bin/python", - "/opt/atat/atst/.venv/bin/celery", - "-A", - "celery_worker.celery", - "beat", - "--loglevel=info" - ] - envFrom: - - configMapRef: - name: atst-envvars - - configMapRef: - name: atst-worker-envvars - volumeMounts: - - name: atst-config - mountPath: "/opt/atat/atst/atst-overrides.ini" - subPath: atst-overrides.ini - volumes: - - name: atst-config - secret: - secretName: atst-config-ini - items: - - key: override.ini - path: atst-overrides.ini - mode: 0644 ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: atst - name: atst-main - namespace: atat -spec: - ports: - - port: 80 - targetPort: 8342 - name: http-main - - port: 443 - targetPort: 8442 - name: https-main - selector: - role: web - type: LoadBalancer ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: atst - name: atst-auth - namespace: atat -spec: - ports: - - port: 80 - targetPort: 8343 - name: http-auth - - port: 443 - targetPort: 8443 - name: https-auth - selector: - role: web - type: LoadBalancer diff --git a/deploy/minikube/nginx-client-ca-bundle.yml b/deploy/minikube/nginx-client-ca-bundle.yml deleted file mode 100644 index 40fac25f..00000000 --- a/deploy/minikube/nginx-client-ca-bundle.yml +++ /dev/null @@ -1,1359 +0,0 @@ -apiVersion: v1 -data: - client-ca-bundle.pem: |+ - -----BEGIN CERTIFICATE----- - MIIElTCCA32gAwIBAgIJAN5qDki+VlfPMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYD - VQQGEwJVUzEVMBMGA1UECBMMUGVubnN5bHZhbmlhMRUwEwYDVQQHEwxQaGlsYWRl - bHBoaWExEDAOBgNVBAoTB0ZhdXhEb0QxCzAJBgNVBAsTAlBXMREwDwYDVQQDEwhG - YXV4IERvRDEeMBwGCSqGSIb3DQEJARYPZmF1eGRvZEBkb2QuY29tMB4XDTE4MDYy - MDIwMzg0N1oXDTE5MDYyMDIwMzg0N1owgY0xCzAJBgNVBAYTAlVTMRUwEwYDVQQI - EwxQZW5uc3lsdmFuaWExFTATBgNVBAcTDFBoaWxhZGVscGhpYTEQMA4GA1UEChMH - RmF1eERvRDELMAkGA1UECxMCUFcxETAPBgNVBAMTCEZhdXggRG9EMR4wHAYJKoZI - hvcNAQkBFg9mYXV4ZG9kQGRvZC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw - ggEKAoIBAQDyQUFcuQ+YKOEJtv4XjKOTpOLp8IdbsaFwU8YgenMdvAc1ONZRL/2o - jaCZx+kB2QSCVH2jaLUQ/2i4uz4rE21Ngpx+EHa1hgDQANle3d5CWrn2Q10/pdPe - rJHYkMSiZ3cNWfFPBfHDtJrLlRUwJkgy+lUSLnOaipmBZMYXbV8/qUh69nWJQNXi - AvmSUw8jwUPfTrpQVzftkOYz+0HVJyvKijTsj1LaPZTR3D8OhbFnvZWIlhIUjJZO - jap/xQ3YEOcNF+gfx8hDQG2SnltWgecPsgiBRXmZK2IqDv39DE2DNiukEclZLhbN - SpTibNZwkVzcTSRV2mSOHKXqTcH0wTvpAgMBAAGjgfUwgfIwHQYDVR0OBBYEFAo/ - 6auHcKMK1ItTElg1Kk4MyoB5MIHCBgNVHSMEgbowgbeAFAo/6auHcKMK1ItTElg1 - Kk4MyoB5oYGTpIGQMIGNMQswCQYDVQQGEwJVUzEVMBMGA1UECBMMUGVubnN5bHZh - bmlhMRUwEwYDVQQHEwxQaGlsYWRlbHBoaWExEDAOBgNVBAoTB0ZhdXhEb0QxCzAJ - BgNVBAsTAlBXMREwDwYDVQQDEwhGYXV4IERvRDEeMBwGCSqGSIb3DQEJARYPZmF1 - eGRvZEBkb2QuY29tggkA3moOSL5WV88wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B - AQUFAAOCAQEAp4fVYeSKYJICBQt37NOF6qZ+dv8GBDI+oZy7vC+VcjiRaODkiz9w - IO5dBZxx/ldH5sD24Oc2SH+48S6UjE/D5kDpM/nIddfVfL2f222sE14RsqgrhmbG - qRaEB8NXWiSQyKOKX63v8scioUqb9hFY+gtwb8HDFiOZFx+67L/NaXSh6VA8BbLj - o55EafjTgr+Yad7SrZI5f6Q2iQ+uuHcJsf7fEe3Kts5Uwt5KXBBfMxeaSyQRxNX+ - JBBmy6MaxddPtus3MH+eIgI2Wp2rofH/PtGnSoizBj5IZXBkc18x1DG5pAJL4205 - EKQoicsafE27XBw45dK3cRBLXPWt8JrCBg== - -----END CERTIFICATE----- - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD SW CA-58 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 5 - -----BEGIN CERTIFICATE----- - MIIDHTCCAqOgAwIBAgIBETAKBggqhkjOPQQDAzBbMQswCQYDVQQGEwJVUzEYMBYG - A1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BL - STEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgNTAeFw0xNjEyMTMxNDQwNTJaFw0yMjEy - MTIxNDQwNTJaMFoxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1l - bnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRUwEwYDVQQDEwxET0QgU1cg - Q0EtNTgwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASi6z3lLSwaqQ6FPQrMxlIW2VBf - xYzA7f+z3pBb2AzNVnMVsRMbMe2f3LCLaAK3kVHbf2MFvd00UCQTaJNoBLrsL7pz - SA3jHtBglzOwI5755VNZydC2aK5Ozw+a2yMQrv+jggE6MIIBNjAfBgNVHSMEGDAW - gBSGwBVC+3F23D4tEVshEEQ1ysHcFDAdBgNVHQ4EFgQUJFUaC5AhLNYjqojSnum4 - raKAfdwwDgYDVR0PAQH/BAQDAgEGMD0GA1UdIAQ2MDQwCwYJYIZIAWUCAQsmMAsG - CWCGSAFlAgELKTALBglghkgBZQIBCywwCwYJYIZIAWUCAQs7MBIGA1UdEwEB/wQI - MAYBAf8CAQAwDAYDVR0kBAUwA4ABADA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8v - Y3JsLmRpc2EubWlsL2NybC9ET0RST09UQ0E1LmNybDBKBggrBgEFBQcBAQQ+MDww - OgYIKwYBBQUHMAKGLmh0dHA6Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9P - VENBNV9JVC5wN2MwCgYIKoZIzj0EAwMDaAAwZQIxAKil1qozXdz7E7kAOhaZ7rOG - 81/dVR5o2KGPFavrto3g9eBE1SboimiKKiiveNnhtQIwLNAaeZukpj9sDs2e16vu - s4rRqS3tuansdH1Fy8j9InJojBLaYeJR60j0AchyqvaG - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD SW CA-57 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 5 - -----BEGIN CERTIFICATE----- - MIIDHTCCAqOgAwIBAgIBEDAKBggqhkjOPQQDAzBbMQswCQYDVQQGEwJVUzEYMBYG - A1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BL - STEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgNTAeFw0xNjEyMTMxNDM5NDlaFw0yMjEy - MTIxNDM5NDlaMFoxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1l - bnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRUwEwYDVQQDEwxET0QgU1cg - Q0EtNTcwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARnTnlhX1XAyZxEwrGRe6CpxNu/ - /EDg3NjbHIEknhq5sh7gCEwtpy3+B37ss64mWq88JTWrtjdmmsuWDQgU6Y6x6QUM - 8NnU/iEILAdH+d8YC/OCoxxUdz13Hhkdlt1JB/6jggE6MIIBNjAfBgNVHSMEGDAW - gBSGwBVC+3F23D4tEVshEEQ1ysHcFDAdBgNVHQ4EFgQUWhIprDfUjj71jVO1IvA6 - BAnRo+swDgYDVR0PAQH/BAQDAgEGMD0GA1UdIAQ2MDQwCwYJYIZIAWUCAQsmMAsG - CWCGSAFlAgELKTALBglghkgBZQIBCywwCwYJYIZIAWUCAQs7MBIGA1UdEwEB/wQI - MAYBAf8CAQAwDAYDVR0kBAUwA4ABADA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8v - Y3JsLmRpc2EubWlsL2NybC9ET0RST09UQ0E1LmNybDBKBggrBgEFBQcBAQQ+MDww - OgYIKwYBBQUHMAKGLmh0dHA6Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9P - VENBNV9JVC5wN2MwCgYIKoZIzj0EAwMDaAAwZQIxAJ0s/tXCmJaEmNjh96qg3PQR - JidParsm6DRIOPgL2umoWx9QQP5mCHebRXk/KBOvpwIwUEw7/IxrYi5bF+kZNnw0 - qansI3GZB9080HFde2/owhIWZ5GMDV8mKKhoNVn3kY/D - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 5 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 5 - -----BEGIN CERTIFICATE----- - MIICJDCCAaqgAwIBAgIBDzAKBggqhkjOPQQDAzBbMQswCQYDVQQGEwJVUzEYMBYG - A1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BL - STEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgNTAeFw0xNjA2MTQxNzE3MjdaFw00MTA2 - MTQxNzE3MjdaMFsxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1l - bnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRYwFAYDVQQDEw1Eb0QgUm9v - dCBDQSA1MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAENmLeC07Ax9cpRTp/HJnmKiF2 - sQDdjEf/wLG0+s46TlL7p+02LRweHJCNl6orpuLTc3N8XBzQZ/QKKdOQhOtR5fFe - HMDShoTFbdEkSQ7sF4nkaMjeGlwaBtA4GTMpARqBo0IwQDAdBgNVHQ4EFgQUhsAV - Qvtxdtw+LRFbIRBENcrB3BQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB - Af8wCgYIKoZIzj0EAwMDaAAwZQIwQQbk3t5iNJ3fuKoW2W2iOB85IlfJcIQfkw9X - fgUvpUszzRXqV9XSKx+bjXzOarbMAjEAt4HS4TuTzxFk3AsvF9Jt1dgF5FByYmXc - pDzKYaUGmsn77cQwyXuJ4KW+Y1XmnBHj - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD SW CA-56 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 4 - -----BEGIN CERTIFICATE----- - MIIC4zCCAoigAwIBAgIBSTAMBggqhkjOPQQDAgUAMFsxCzAJBgNVBAYTAlVTMRgw - FgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMD - UEtJMRYwFAYDVQQDEw1Eb0QgUm9vdCBDQSA0MB4XDTE2MTEyMjE1NDgyMloXDTIy - MTEyMzE1NDgyMlowWjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1UuUy4gR292ZXJu - bWVudDEMMAoGA1UECwwDRG9EMQwwCgYDVQQLDANQS0kxFTATBgNVBAMMDERPRCBT - VyBDQS01NjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJ8P6wqfbu85tSo6iiVb - QpyTzVfDbEcUuojsnZxa2ZviI59J9fOB6LkSxvoaclcIDG2CQHb/cTFRlYnmny28 - qhajggE6MIIBNjAfBgNVHSMEGDAWgBS9wblrTfQd7DCQv2JzwIQz8nEkhTAdBgNV - HQ4EFgQUvPL0UZ0qy+OdEFZjBXZWyd261FswDgYDVR0PAQH/BAQDAgGGMD0GA1Ud - IAQ2MDQwCwYJYIZIAWUCAQslMAsGCWCGSAFlAgELKDALBglghkgBZQIBCyswCwYJ - YIZIAWUCAQs7MBIGA1UdEwEB/wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADA3BgNV - HR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9ET0RST09UQ0E0 - LmNybDBKBggrBgEFBQcBAQQ+MDwwOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcmwuZGlz - YS5taWwvaXNzdWVkdG8vRE9EUk9PVENBNF9JVC5wN2MwDAYIKoZIzj0EAwIFAANH - ADBEAiBjgR3FzwuqcKfmIAyyghC85+C4WZWLlLV/pnA+KF16igIgdT3W8YPHEMGh - WPpqVeBR1xJfFBl4H+a8OxmJ8RTZdUQ= - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD SW CA-55 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 4 - -----BEGIN CERTIFICATE----- - MIIC5TCCAoigAwIBAgIBSDAMBggqhkjOPQQDAgUAMFsxCzAJBgNVBAYTAlVTMRgw - FgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMD - UEtJMRYwFAYDVQQDEw1Eb0QgUm9vdCBDQSA0MB4XDTE2MTEyMjE1NDY0NloXDTIy - MTEyMzE1NDY0NlowWjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1UuUy4gR292ZXJu - bWVudDEMMAoGA1UECwwDRG9EMQwwCgYDVQQLDANQS0kxFTATBgNVBAMMDERPRCBT - VyBDQS01NTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDmzh2HFjUhGEaKxXU5E - jVU66fMJbN52tWk4QsBIU8rCcuKdzyoY3DTULRv5WdF4mjPHBTfycuWOmxztrU64 - N+ajggE6MIIBNjAfBgNVHSMEGDAWgBS9wblrTfQd7DCQv2JzwIQz8nEkhTAdBgNV - HQ4EFgQUpW9LHZK1y9132ba9SAa+BkgJNBgwDgYDVR0PAQH/BAQDAgGGMD0GA1Ud - IAQ2MDQwCwYJYIZIAWUCAQslMAsGCWCGSAFlAgELKDALBglghkgBZQIBCyswCwYJ - YIZIAWUCAQs7MBIGA1UdEwEB/wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADA3BgNV - HR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9ET0RST09UQ0E0 - LmNybDBKBggrBgEFBQcBAQQ+MDwwOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcmwuZGlz - YS5taWwvaXNzdWVkdG8vRE9EUk9PVENBNF9JVC5wN2MwDAYIKoZIzj0EAwIFAANJ - ADBGAiEA8zQA+T3anaM0b1QsYSEvu8Y95S03GGy8fG2Hoi661FICIQCDCbwQZD1Z - 8NhnjbOBDEonqzFEdiXgGiq26ss/1ejDaw== - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID SW CA-48 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 4 - -----BEGIN CERTIFICATE----- - MIIC2jCCAn6gAwIBAgIBCjAMBggqhkjOPQQDAgUAMFsxCzAJBgNVBAYTAlVTMRgw - FgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMD - UEtJMRYwFAYDVQQDEw1Eb0QgUm9vdCBDQSA0MB4XDTE2MDQxMjEzMTk0OVoXDTIy - MDQxMzEzMTk0OVowXTELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJu - bWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQLEwNQS0kxGDAWBgNVBAMTD0RPRCBJ - RCBTVyBDQS00ODBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHP3gMIrM5XHrtPg - Np7Bm42eqJiheI0fMNe9WDJkFdJbJeTrdxUtYQJfb4nYmLlnGG7Bw3RLHhLhS0vi - MO0inc2jggEtMIIBKTAfBgNVHSMEGDAWgBS9wblrTfQd7DCQv2JzwIQz8nEkhTAd - BgNVHQ4EFgQUtraXanDTuzYAuelFdC8nlSryWQkwDgYDVR0PAQH/BAQDAgGGMDAG - A1UdIAQpMCcwCwYJYIZIAWUCAQsoMAsGCWCGSAFlAgELKzALBglghkgBZQIBCyUw - EgYDVR0TAQH/BAgwBgEB/wIBADAMBgNVHSQEBTADgAEAMDcGA1UdHwQwMC4wLKAq - oCiGJmh0dHA6Ly9jcmwuZGlzYS5taWwvY3JsL0RPRFJPT1RDQTQuY3JsMEoGCCsG - AQUFBwEBBD4wPDA6BggrBgEFBQcwAoYuaHR0cDovL2NybC5kaXNhLm1pbC9pc3N1 - ZWR0by9ET0RST09UQ0E0X0lULnA3YzAMBggqhkjOPQQDAgUAA0gAMEUCIQC+iGG8 - kjbV/VNcKlxuuufzU0hVa3nbY+AH1G/019EVGgIgOBioOJjL2DEOswswow0z0Way - O+Dq52y9IIt1LNiEuQw= - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID SW CA-47 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 4 - -----BEGIN CERTIFICATE----- - MIIC2zCCAn6gAwIBAgIBCTAMBggqhkjOPQQDAgUAMFsxCzAJBgNVBAYTAlVTMRgw - FgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMD - UEtJMRYwFAYDVQQDEw1Eb0QgUm9vdCBDQSA0MB4XDTE2MDQxMjEzMTI0M1oXDTIy - MDQxMzEzMTI0M1owXTELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJu - bWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQLEwNQS0kxGDAWBgNVBAMTD0RPRCBJ - RCBTVyBDQS00NzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABIXYA5Gtzjuc8KIc - kgMu3+mgBPldfBkOr9i+4whQzY84FDKvzsc78BbuQicWDsbJDXN45N5ACoAkwrIz - MP1NRZyjggEtMIIBKTAfBgNVHSMEGDAWgBS9wblrTfQd7DCQv2JzwIQz8nEkhTAd - BgNVHQ4EFgQUowEMSwGcEB8madmOXGcnxdqsNnowDgYDVR0PAQH/BAQDAgGGMDAG - A1UdIAQpMCcwCwYJYIZIAWUCAQsoMAsGCWCGSAFlAgELKzALBglghkgBZQIBCyUw - EgYDVR0TAQH/BAgwBgEB/wIBADAMBgNVHSQEBTADgAEAMDcGA1UdHwQwMC4wLKAq - oCiGJmh0dHA6Ly9jcmwuZGlzYS5taWwvY3JsL0RPRFJPT1RDQTQuY3JsMEoGCCsG - AQUFBwEBBD4wPDA6BggrBgEFBQcwAoYuaHR0cDovL2NybC5kaXNhLm1pbC9pc3N1 - ZWR0by9ET0RST09UQ0E0X0lULnA3YzAMBggqhkjOPQQDAgUAA0kAMEYCIQCN7jJe - h0KGZ05OTCbxZKgvqR7N3hco4qTXcETpm1mPmAIhAPZWclBf54lOCDQku0UBz8gW - lYdeVXmiuKz7DveFthis - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 4 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 4 - -----BEGIN CERTIFICATE----- - MIIB6zCCAY+gAwIBAgIBATAMBggqhkjOPQQDAgUAMFsxCzAJBgNVBAYTAlVTMRgw - FgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMD - UEtJMRYwFAYDVQQDEw1Eb0QgUm9vdCBDQSA0MB4XDTEyMDczMDE5NDgyM1oXDTMy - MDcyNTE5NDgyM1owWzELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJu - bWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQLEwNQS0kxFjAUBgNVBAMTDURvRCBS - b290IENBIDQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR2yNhDyw8H0iwPKtA4 - 8YLNQlXn3B1agLcIkUtU1k+yZoU0lo0uPvTgSpF8zM2GnxHgUqFmgsbLkCPsX1/1 - 8DxFo0IwQDAdBgNVHQ4EFgQUvcG5a030HewwkL9ic8CEM/JxJIUwDgYDVR0PAQH/ - BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDAYIKoZIzj0EAwIFAANIADBFAiEA6GGK - 99yqCaUH0kSeggNaRFNHhCOZz1zT3kpe1rs1NUYCIHYPuMR8FjV/1BLtiD2AEWtk - B0xFZd9Trl8B7fFD0vW3 - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID SW CA-46 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIErjCCA5agAwIBAgIBZDANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEY - MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT - A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMzAeFw0xNjAzMDgxNDIyMjdaFw0y - MjAzMDkxNDIyMjdaMF0xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy - bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRgwFgYDVQQDEw9ET0Qg - SUQgU1cgQ0EtNDYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDB8t7O - izHtqCLUKXdNcAOYlJDNyNoqW22ZB75KiU3GJna5ww499SOnBaEU4OvRSMI3FcKS - lZRvJJIbNpcUbn6X/4cEH6g64lCGSXcm8nl/rU1W0onf7l/fk8tcaVRG0hP9iTbe - 7fjlJ7hEWwKEXSk7Xkr/3e09bvKIHVtiCsV6cOlNsK6H7JbEhRw4yPOkqdXtrpQX - mNh9Y6OGya91I1vzYO+zcexr2+MOoHFJyADBVF/+LrMWdRqVI0Fl8r8NXKnGXpC7 - yPns28gz1egmxJ5NsJtQ8p4WHMQnA6J3wPr+7na+5MKzLgCIoMxD2vIJ0FU28ODE - WrAb9clqWqv/Jte/AgMBAAGjggF5MIIBdTAfBgNVHSMEGDAWgBRsipSid7GAch2B - ehaq8tzOZu5FwDAdBgNVHQ4EFgQUW2dpXrVYC5wfCdw1fZvWJ+5iqpwwDgYDVR0P - AQH/BAQDAgGGMFoGA1UdIARTMFEwCwYJYIZIAWUCAQskMAsGCWCGSAFlAgELJzAL - BglghkgBZQIBCyowDAYKYIZIAWUDAgEDDTAMBgpghkgBZQMCAQMRMAwGCmCGSAFl - AwIBAycwEgYDVR0TAQH/BAgwBgEB/wIBADAMBgNVHSQEBTADgAEAMDcGA1UdHwQw - MC4wLKAqoCiGJmh0dHA6Ly9jcmwuZGlzYS5taWwvY3JsL0RPRFJPT1RDQTMuY3Js - MGwGCCsGAQUFBwEBBGAwXjA6BggrBgEFBQcwAoYuaHR0cDovL2NybC5kaXNhLm1p - bC9pc3N1ZWR0by9ET0RST09UQ0EzX0lULnA3YzAgBggrBgEFBQcwAYYUaHR0cDov - L29jc3AuZGlzYS5taWwwDQYJKoZIhvcNAQELBQADggEBAHrAmFSy86ZAscEU5KID - UdXtfC3+OV/I1BYnYiZHJKJj8zRuqvdWvsulKtCGKZo1wFv446n/14YRbI3TKno2 - Q/c4J6uz+MOsIGLyPvPmwO5Y6Gaqj5EDD6rgyYSRdHrmBlLE1aUmedc86UOMKAz6 - OwmUFRru8aXF/YSEWQmkeIWX4saImbv8Evb2vqjDPFERjH6BebYDRI7ZpMWg8jJt - LnQFoKOhCOTnHJz0vd/vnh4IC+7+KNgbg+RZ0O3H9dnBeULcLGeHtw2F2jBMrlyW - d0Iyn7vj9cOGkdrkggSpdGqqlXiNkVsYhyPXztL8jOqmyY7ndXubEQCsYxMIIXur - SEQ= - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID SW CA-45 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIErjCCA5agAwIBAgIBYzANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEY - MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT - A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMzAeFw0xNjAzMDgxMzI4NTZaFw0y - MjAzMDkxMzI4NTZaMF0xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy - bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRgwFgYDVQQDEw9ET0Qg - SUQgU1cgQ0EtNDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVVtcp - RJMdLbl4C4dfjcBCfAqUMLRbXiKiDRnAMXn3c5IrYEND7uJKJTCrQklQ8YC570Za - YXxhSaKiFbcR0MA7oHEF8HWglB53GSmFowqtAiERS/AWbMJoXlh/MBJweeSVUzat - CPO8V3q56Y/5OFglW5YV3tA3Kgv+BvlqjYCzWNeBwfyeglkB8EWi58llAiyjsGPd - QpN71LOyqHK16SCv22E6mIyrxfFgeaWIxIBeXzgVxDzZ2djbsqYyrJlAdUCbGzh/ - O9N0MhEC0mMRcgo7uER0olnWri1oOWtJl2Ok8ZvMqGQbdkxkkmxCthUWyxFoVq7P - xU7IYmBiBn27SyF7AgMBAAGjggF5MIIBdTAfBgNVHSMEGDAWgBRsipSid7GAch2B - ehaq8tzOZu5FwDAdBgNVHQ4EFgQUy/0Vpppg8S5OW5UcjD8djcKjIhswDgYDVR0P - AQH/BAQDAgGGMFoGA1UdIARTMFEwCwYJYIZIAWUCAQskMAsGCWCGSAFlAgELJzAL - BglghkgBZQIBCyowDAYKYIZIAWUDAgEDDTAMBgpghkgBZQMCAQMRMAwGCmCGSAFl - AwIBAycwEgYDVR0TAQH/BAgwBgEB/wIBADAMBgNVHSQEBTADgAEAMDcGA1UdHwQw - MC4wLKAqoCiGJmh0dHA6Ly9jcmwuZGlzYS5taWwvY3JsL0RPRFJPT1RDQTMuY3Js - MGwGCCsGAQUFBwEBBGAwXjA6BggrBgEFBQcwAoYuaHR0cDovL2NybC5kaXNhLm1p - bC9pc3N1ZWR0by9ET0RST09UQ0EzX0lULnA3YzAgBggrBgEFBQcwAYYUaHR0cDov - L29jc3AuZGlzYS5taWwwDQYJKoZIhvcNAQELBQADggEBADPubZ/kZNDB/hkuGuuK - OmiGZJC2C1dBGkuM0SXewWzGHEPKapa4rNDrgDSTQMOLeMUCmr4XbHbMo1mqIDBc - SioVFiq+CooCskj3D+gj1Y+dbfi+IW8/IlbHVDxlApDlJ11v3nvNJNHp7gA0hFVD - Da2Upj9wVsYr0ReXvHRz0Zb6a1/7R6to41c8wwg3hWCGCXsPvnILaQK5JmxNVX1i - HT95UKDxnysb+vw+GxxJgaIH87HkgxZtOc7WUnP+GFALfKQyLsR8J3vkIkI2DJfP - FjtBblgXWn9lCI5lYgeH3VbKjVvowcUWuw2F8PJaaNHpVpWwv+XfzLmUCdLGjZrB - zBQ= - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID CA-44 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEnTCCA4WgAwIBAgIBGzANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEY - MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT - A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMzAeFw0xNTExMDkxNjE4MTRaFw0y - MTExMDkxNjE4MTRaMFoxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy - bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRUwEwYDVQQDEwxET0Qg - SUQgQ0EtNDQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDG3+Tty+pD - oTJGbJvbL/uQUD5vXkR1G6vSxNSbFskImmrpLV2hr8uCGAFDL+Kb3dPaYLTEeaK9 - 34LqDC02+Cw4mLamoXKtfBGlFT1T3AHzpS4wJAhfrSGFGRBdY76jpTn1eiaWs+nb - CLiJjpxQOQhp7caytsZnGvLNOFUc+QZJFsyAf06cpWEmo/iAx7KXLMPV6sbGTLqm - kyqNxYPvqd1Ryyq2vi5Pqyw0swg2+wvkMhGIZ39ryJhgaU5vcAhd39z53tNU1ttp - xP506Z4uDG9TmBciUFfs4uZbz9aOzT9YYs6enlh172PU48WfCFIQSOXjRcB9/XkD - btghMxTcmzgRAgMBAAGjggFrMIIBZzAfBgNVHSMEGDAWgBRsipSid7GAch2Behaq - 8tzOZu5FwDAdBgNVHQ4EFgQUMPnNVHOQG4Lyco6N7lZGokQpv/owDgYDVR0PAQH/ - BAQDAgGGMEwGA1UdIARFMEMwCwYJYIZIAWUCAQskMAsGCWCGSAFlAgELJzALBglg - hkgBZQIBCyowDAYKYIZIAWUDAgEDDTAMBgpghkgBZQMCAQMRMBIGA1UdEwEB/wQI - MAYBAf8CAQAwDAYDVR0kBAUwA4ABADA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8v - Y3JsLmRpc2EubWlsL2NybC9ET0RST09UQ0EzLmNybDBsBggrBgEFBQcBAQRgMF4w - OgYIKwYBBQUHMAKGLmh0dHA6Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9P - VENBM19JVC5wN2MwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWlsMA0G - CSqGSIb3DQEBCwUAA4IBAQCnFaVDUuNpbT4YazfYL4qKc/e0Zqd1wM10uqo+ayjz - zP5HXLL2frAudguRVxFDC1WzjB16tc1GODUWY4OOxPCyUNKUJTU3G8qcXMabjEvC - y9wLu/5FTvE0iumpvdpSGJb2v/pBc+Tofe17SgCTpOW+METZM5fiV6e8VrYaZalg - YXrHg+DvdBpGSteccLFLORhZoq0ZpHh7QoHNVOi9sxLhEuhRTSGebRhTkYN99PzC - BdD6ljQ0uShqB3r8uX1pVpBskdovm2JWSX40/QahFVDMwJPImlJ7lXRNvRrkqLHH - PaTJ4R5spBJULmUEbqVfFXG5p/I9vNVF7YZCE5nzegTf - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID CA-43 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEnTCCA4WgAwIBAgIBGjANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEY - MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT - A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMzAeFw0xNTExMDkxNjE2MDFaFw0y - MTExMDkxNjE2MDFaMFoxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy - bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRUwEwYDVQQDEwxET0Qg - SUQgQ0EtNDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCib5WKgEkw - yV+HYIReCPRrFLoBoue/va3ODbll8dZITF5Dkj/Qpn/aE3cCVXkd1Oy38k+7MFGo - I93xCKkxq+gdkeLGXEZ8tuwpuqeVHW7rjgd+2DgDuNWsXkN8UqfJvaMccLSjLfTI - MS420x3sMtE5aOC+Zib6Ei7YlT5GUatw33BKSTZIsXqWa9tag6daktv1JonQOs9W - z+zCwZ806AmJhygNzv5scv0+Wtbns91UzwyTBSpYi8Go03YXU1znT/hciQC6uXRY - xUWbBRkuJyc4AsGb2mwfcfG7Tv3LoO1sv1VUV0FswWGP9dFRX3DqjIzs5ylk58oo - CXTCrwOYIXGPAgMBAAGjggFrMIIBZzAfBgNVHSMEGDAWgBRsipSid7GAch2Behaq - 8tzOZu5FwDAdBgNVHQ4EFgQUN6mSY1xcxJ27IUhTKKrUZFBmmkUwDgYDVR0PAQH/ - BAQDAgGGMEwGA1UdIARFMEMwCwYJYIZIAWUCAQskMAsGCWCGSAFlAgELJzALBglg - hkgBZQIBCyowDAYKYIZIAWUDAgEDDTAMBgpghkgBZQMCAQMRMBIGA1UdEwEB/wQI - MAYBAf8CAQAwDAYDVR0kBAUwA4ABADA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8v - Y3JsLmRpc2EubWlsL2NybC9ET0RST09UQ0EzLmNybDBsBggrBgEFBQcBAQRgMF4w - OgYIKwYBBQUHMAKGLmh0dHA6Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9P - VENBM19JVC5wN2MwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWlsMA0G - CSqGSIb3DQEBCwUAA4IBAQBqUrzdeqnC2ohoGUExkxayPe+h3TKunmYUBgFHOLtT - w89DiGAypywUHgjSOqb1DQD7Z2JohlU2rRRn0ajIAii5DtPgGN4mB9Z5HsmdfZ8L - +CMr/Jw7oYeaRLnyWoRW6cvGiM3opBewNo1192dqv7JYHaAGIVKSdLcESJNwp347 - nDD5MauXa8/2a20lsOOrcU8PgpBHhyRPDQoBaxjjSFtH+aA7KwvFaqsUpvgiTqNp - 5j41K0ayV0rdd/K3zRKcA2weMONqDXagcvDSCMOu3S6jS/M7oc3Sv4kKk8Vjhcom - hCvw6EHyLSiUMqNzlO71q5q3qMj9QOD6T4PK6/UxRD7D - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID CA-42 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEnTCCA4WgAwIBAgIBGTANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEY - MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT - A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMzAeFw0xNTExMDkxNjE1MDJaFw0y - MTExMDkxNjE1MDJaMFoxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy - bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRUwEwYDVQQDEwxET0Qg - SUQgQ0EtNDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCt4/+9beDb - 3g9kGg2MlznUY93COtiDLetMCks4aQ5/MYaSti6eoDw5L7EHlkNfnrO5XXKbQHZ7 - HqipwyE6uZ36WPEvU6ufin57Fr++aIYNk3xLAH4me6jT8qyrzn9FUBXh2UsnqCMo - 5jHl+6FJbsTq2/sSpIZl8SMUS4w6wNi/gRSrhdVfmJibhQgEj6QbvUr8aASzlyS9 - +zvMRTZq7JBDEPlbdsfE3mbGWvO0+PD8HMsNrj5rKL7wdoAzQDB/YisF/9ffJw8L - cFPsUisUdZsFTk9L7qMCcgSfCtGfw5AEw4lcmIAiHRX0Apd/iJM4kADuHUFPYzM2 - EN4ngjDxK6jVAgMBAAGjggFrMIIBZzAfBgNVHSMEGDAWgBRsipSid7GAch2Behaq - 8tzOZu5FwDAdBgNVHQ4EFgQUMqAAylmLxM58e9veGSoQioZB0eMwDgYDVR0PAQH/ - BAQDAgGGMEwGA1UdIARFMEMwCwYJYIZIAWUCAQskMAsGCWCGSAFlAgELJzALBglg - hkgBZQIBCyowDAYKYIZIAWUDAgEDDTAMBgpghkgBZQMCAQMRMBIGA1UdEwEB/wQI - MAYBAf8CAQAwDAYDVR0kBAUwA4ABADA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8v - Y3JsLmRpc2EubWlsL2NybC9ET0RST09UQ0EzLmNybDBsBggrBgEFBQcBAQRgMF4w - OgYIKwYBBQUHMAKGLmh0dHA6Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9P - VENBM19JVC5wN2MwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWlsMA0G - CSqGSIb3DQEBCwUAA4IBAQA5hIjoPl6je1176wDm7i4FNGehuKkrM6KOqEZLyze2 - bkSRZXV8wIve6CkMxL89PLEa9BPXF/PpF5Wn2to4YZgZmx0j+3M9kIuIzDxKHAHB - tfLoOXHiT/g9U9Scl09RiWVfhul13R7+Q6CQdKO1yu69bNtvL1Uxsz2LaGP3pFaS - QklM+Ns56N3a2YJ3qNyjGnMoksBDFSkitYJJrWteHSv1iBv9FVge/d3SE9+Pq/WD - Q22yK/0ph3gTEw61e9EYZ/TAeNb01Ju56bNo5lVHAz2UawrwGhRklJQhf/i9JRda - gykYg4Zkczl+ZXN+0bfJDZ+kpis0wlcPrVzNKNpAVnzf - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID CA-41 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEnTCCA4WgAwIBAgIBGDANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEY - MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT - A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMzAeFw0xNTExMDkxNjEzNTZaFw0y - MTExMDkxNjEzNTZaMFoxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy - bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRUwEwYDVQQDEwxET0Qg - SUQgQ0EtNDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3yXSI2Ca+ - LJHgzmhn2NH9Xk02+QoEPtO4K3oHa+XKeP2Mdk4ooFy3SLvizf84zDWzqVPoofEd - pF1NpDT89rm5JOjaI5PBm9ct4rV0ZqH34DlARMVjthW6ySUp2YDDK5dGkZTACqkn - E2AaL777RyPLRESDp1p/J2yInUMvCc3wsJmqteSW5dUDpl7+S9SV2D+urf7zB5oB - 06D9i4YknSh3nnthtqHSCvNF0QtpynTydycBrZZ2Cv4lF/iVPpi89WDTAjwWc3u7 - HVxHqCi9Z6zB7eIIXtIRcKBJrqL7oExvAGu0C/1D6/dQfOqHa4cPEgllXfy38Zxf - nUrFCih4TjD1AgMBAAGjggFrMIIBZzAfBgNVHSMEGDAWgBRsipSid7GAch2Behaq - 8tzOZu5FwDAdBgNVHQ4EFgQUW5HGRDbyKPL4z7LCyMpjSWGbIAowDgYDVR0PAQH/ - BAQDAgGGMEwGA1UdIARFMEMwCwYJYIZIAWUCAQskMAsGCWCGSAFlAgELJzALBglg - hkgBZQIBCyowDAYKYIZIAWUDAgEDDTAMBgpghkgBZQMCAQMRMBIGA1UdEwEB/wQI - MAYBAf8CAQAwDAYDVR0kBAUwA4ABADA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8v - Y3JsLmRpc2EubWlsL2NybC9ET0RST09UQ0EzLmNybDBsBggrBgEFBQcBAQRgMF4w - OgYIKwYBBQUHMAKGLmh0dHA6Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9P - VENBM19JVC5wN2MwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWlsMA0G - CSqGSIb3DQEBCwUAA4IBAQCh4rRiX98I1sgwJ/wFaLDtM3GlKTulDu7VGpGllllh - bUpZiaHQ8pMV2goFboAOPXxMnl2N2UM/U4/9S2uW4mosQo2gbcNT7rbi/QhlEk4Z - u6tZek3SvhFIq+fn/XhMqiMwIOUNqroh5BnvPGLQcMqfnLebTJmkcG4I6OmXP6en - jh/JcdNnxMhZ1ZUju61+Sw8g14fKV6kAUdrGhQPZAceZyLvUajDRXLdxFX7LWip0 - IIFPD4eM2pLx94MPpbwFo4/l+rO8LK5BLxG4YV7hIiyauwtcREoNwjRyE0TJ8qTf - mzXUzM7YyjBQytyeKHaEyDbULAe0vfUb9p1joxoGSOue - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD EMAIL CA-44 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEoDCCA4igAwIBAgIBFzANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEY - MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT - A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMzAeFw0xNTExMDkxNjEyMTZaFw0y - MTExMDkxNjEyMTZaMF0xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy - bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRgwFgYDVQQDEw9ET0Qg - RU1BSUwgQ0EtNDQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5wjjc - RPtz4s4DzWJURVpAl0MhxzRT1SHv3Sju/LkVaagrEfNxEZbnkTHKciFhScbCIco4 - 458+LtRXmwMZiXSPSVquEuhYjpmQggqVUs8eozfV4uMnI88FBEGUhwA8zfgwRMLF - RQnJ4SCB3oGbZHh4sV1MutprCDwd6qrG0k8b8/GF9h1vyPZbNNBHODlfdDraBD5/ - bdX5lQ4L6J7uT5vYtTQQIRM+fk1Nlmxr2okKH4wcwK5FQ9I/kYAs7QoF9My8nAOO - sAAYPBxq+V5UWwRqqdSSxX72YEHAyitxmwng3VMHu5pNCnmEsYSVH7C7FfQaXk/e - Q4+o36slG0x/jys7AgMBAAGjggFrMIIBZzAfBgNVHSMEGDAWgBRsipSid7GAch2B - ehaq8tzOZu5FwDAdBgNVHQ4EFgQUoItn0eFgZHWnOazJuDWNmJJ0c6UwDgYDVR0P - AQH/BAQDAgGGMEwGA1UdIARFMEMwCwYJYIZIAWUCAQskMAsGCWCGSAFlAgELJzAL - BglghkgBZQIBCyowDAYKYIZIAWUDAgEDDTAMBgpghkgBZQMCAQMRMBIGA1UdEwEB - /wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADA3BgNVHR8EMDAuMCygKqAohiZodHRw - Oi8vY3JsLmRpc2EubWlsL2NybC9ET0RST09UQ0EzLmNybDBsBggrBgEFBQcBAQRg - MF4wOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9E - Uk9PVENBM19JVC5wN2MwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWls - MA0GCSqGSIb3DQEBCwUAA4IBAQCSY9dTLozPHVTcrSBDSPRiAts6kmKFip1T2qP+ - zDqETUs7FpS/EkLka8n0qjmYMtNWD9zsWKi8FbZeZ1se5tSFxL9waupfibMFsJT4 - Mnvmk3ihhUfTZYpERBmgeX7cd80+WO9SB1P+dCLw/7MjTdN8j0aOcjh+I6KLWLjA - LfVNhpZ7/8LgsOl3sHgZ7537YsA6Ti+yezGD0jM7nKpfyg78nbK2imWutiuEyHui - OdwcJOQpsKuoyNa5yzyuXK5ygG/PMEzJr6rfJykd6UMpADgaCZmSWueJqzMxfrI2 - ZoXlZzmX0xG2CuhOEhcqwLLvKgqu+dUKwzE4VxQYgtRtzzJf - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD EMAIL CA-43 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEoDCCA4igAwIBAgIBFjANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEY - MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT - A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMzAeFw0xNTExMDkxNjExMDJaFw0y - MTExMDkxNjExMDJaMF0xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy - bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRgwFgYDVQQDEw9ET0Qg - RU1BSUwgQ0EtNDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCr3inR - YhAew1kjGebIpt5eR5BSz/xqDhz6KvPNiri3gbRar7lAu7XVGAn+LYB+NyuJt3Wu - 6tSmXvvqxLPKXr47tFAkjpX2My1IGM+Y59iMsuvK+T1xeFvbZFtnC8EgntEwR0Uo - UWtUZAdb5IdKGquolt89RTt6W1mgMhbuYEewydSknxxUI+yNvMQ6NGeaRzu9IRIm - AmtSHUpkE5vxto8lmxRtF09LcmLSiElx7InsL3olAQSjzw2AWbHEMr4WDVTugJXn - VLfmC8/fuTENvmLRDGnTA+li0fjORzMqmGIok5eoU3X24Qv3Ii7/XvGFyNGAKPy4 - oKAXEGn5eZtar4kvAgMBAAGjggFrMIIBZzAfBgNVHSMEGDAWgBRsipSid7GAch2B - ehaq8tzOZu5FwDAdBgNVHQ4EFgQU9x/xRjhVv7xxi7IGO44rGLJeu7QwDgYDVR0P - AQH/BAQDAgGGMEwGA1UdIARFMEMwCwYJYIZIAWUCAQskMAsGCWCGSAFlAgELJzAL - BglghkgBZQIBCyowDAYKYIZIAWUDAgEDDTAMBgpghkgBZQMCAQMRMBIGA1UdEwEB - /wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADA3BgNVHR8EMDAuMCygKqAohiZodHRw - Oi8vY3JsLmRpc2EubWlsL2NybC9ET0RST09UQ0EzLmNybDBsBggrBgEFBQcBAQRg - MF4wOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9E - Uk9PVENBM19JVC5wN2MwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWls - MA0GCSqGSIb3DQEBCwUAA4IBAQBb0OxJQPngXOTSzqqxRWBYjiK+4vEf/nwj7cj0 - OT07FIrRsRpyZwpENffCtMU5yv2GHqlS8JKiqw9oGNMtqoW4BtXEE0Oo7W0dnQGk - wLv55eRN1FDI0JgpTu4zixq7NMpYx7XVADi6+3E11efmOesF20po7+Gg2MGsJTNR - EMXh7yHcDqs6nMkPtcl1u4qivfohdRcKsIvwC1Z4cV+bjZ9A5KOBZeWsa86FzNBl - jKTdLxebUz091aA6tjUZ/k576OPKiR1k8awlDsz5j/S9xK1Ht5KV2x8Edvgreiw4 - Dt8Disz/fX0T330P2n6GbPOcgL/wiktRjCq2BnnlmDLFwxJe - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD EMAIL CA-42 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEoDCCA4igAwIBAgIBFTANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEY - MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT - A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMzAeFw0xNTExMDkxNjA5NDJaFw0y - MTExMDkxNjA5NDJaMF0xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy - bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRgwFgYDVQQDEw9ET0Qg - RU1BSUwgQ0EtNDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmnSX1 - j25X0lrlxl7FTi65DxzSaXlUQwPPILHxQh4pWMbA7Rff4r+duETma3mrPmaej45H - KYPF+1jFiV+jLiPFXzQKcsrrImratXcABFus0lA8xBtvhjZTE/vmGSXZpBPFAkyb - jof3OJBzzWwo+kPrK/je0Kbrlq4jekNcpXDeR4Qp2FXtwMgeS9RnMGUWbO7sv/iJ - ceUkXD9WG6IY2GW3EMsx5MJtxe6M7ACsMb0J3eN+2BAxAZZGjMRjPa2C+2kc922j - Bsr4mfQ9hEbWEu5wWLwiJLBH+9NaTBxlqcGS8yyX0xQktvLHlrmnIUpQksH3x/6F - UnzXQ1CKhaENi4lvAgMBAAGjggFrMIIBZzAfBgNVHSMEGDAWgBRsipSid7GAch2B - ehaq8tzOZu5FwDAdBgNVHQ4EFgQUbwWkXaLEr5VbQZHfC3gLFu8cCW4wDgYDVR0P - AQH/BAQDAgGGMEwGA1UdIARFMEMwCwYJYIZIAWUCAQskMAsGCWCGSAFlAgELJzAL - BglghkgBZQIBCyowDAYKYIZIAWUDAgEDDTAMBgpghkgBZQMCAQMRMBIGA1UdEwEB - /wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADA3BgNVHR8EMDAuMCygKqAohiZodHRw - Oi8vY3JsLmRpc2EubWlsL2NybC9ET0RST09UQ0EzLmNybDBsBggrBgEFBQcBAQRg - MF4wOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9E - Uk9PVENBM19JVC5wN2MwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWls - MA0GCSqGSIb3DQEBCwUAA4IBAQB+0vQGArx8bB3kLkQtlSq/JQdzYG9ZxTu1W+nv - eaBUzXyhUyBP1OEA0ZvyiAt7km95y3/H65mZqtBRQuz+jYf0Hxxd0fFw2cXrU8oN - pf9of8SIit3g7H/lPvCzQrixjBPJyIZiuF/1tGqS7OmQP/4jU3+R8uvVhUi3AX2D - XAm4VTcBpCsG3ozOCpJykAQZJxaOgqSJHFLNdPByr1fMvpsFOkSWwlGzmWObh4Xw - ud0+naP4pbqKYjue/MeAGqgmxMJTn4hFXS5bHMViscJpnZtJz1J6XsA8aSiZO/ul - iO/vQx3CzdEWCMB1ZCGP0xdzfDipKEMDPRpA3ucPj3dgb3Mr - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD EMAIL CA-41 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEoDCCA4igAwIBAgIBFDANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEY - MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT - A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMzAeFw0xNTExMDkxNjA1MjdaFw0y - MTExMDkxNjA1MjdaMF0xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy - bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRgwFgYDVQQDEw9ET0Qg - RU1BSUwgQ0EtNDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCUuycR - DCMw4iPGIbeq1Yuw/9S+tkQnTdtDE1RSp/AhVU+sIILIH0Ay5GiJYuZ1L4NdUGnJ - rsAeRJIFUZae/eMfzARtUtnHyPteXJB1DYh8eK5b5E7RFUz5lae4AdhuUtPSRDm0 - YdH8nXJ8Fgm0w+pMCltZJLIGhfgphXbcZleyFJrRk/k30PIfNdZSoxI0dn8tJRui - 8H50cXpDbCd5Ksi+jEsdYR3Mcza6VTZRmvepwAiF9fpEqlyVqltq2OWLg8ky628V - ODeDZ188HSx8rgpZfOxHQJpMnIyOKHH35WeXEMGC7spvrRP+d/BZsIRGmVx25FTi - jbCFfTQeD91cb6ifAgMBAAGjggFrMIIBZzAfBgNVHSMEGDAWgBRsipSid7GAch2B - ehaq8tzOZu5FwDAdBgNVHQ4EFgQUOSmoCGTij4OqgWFHEZEz+Fo3puQwDgYDVR0P - AQH/BAQDAgGGMEwGA1UdIARFMEMwCwYJYIZIAWUCAQskMAsGCWCGSAFlAgELJzAL - BglghkgBZQIBCyowDAYKYIZIAWUDAgEDDTAMBgpghkgBZQMCAQMRMBIGA1UdEwEB - /wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADA3BgNVHR8EMDAuMCygKqAohiZodHRw - Oi8vY3JsLmRpc2EubWlsL2NybC9ET0RST09UQ0EzLmNybDBsBggrBgEFBQcBAQRg - MF4wOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9E - Uk9PVENBM19JVC5wN2MwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWls - MA0GCSqGSIb3DQEBCwUAA4IBAQAhEvHTWyebz05Ox9hW+neUMYI1686yzQA3er3T - lmapTCnxNyNeGP0dcLuFqHZu7wiw6n362ygHDB4e2GQm/IFHsdPXBEQiDBtBOe24 - EOxXMEp4Ku0znOFgZEV/kng/ST4rsoyb4MVCzhCR/5lfzk0zWD5oUgnJ5YwWIITN - zCO10fxQYiCBFDGPcMGJ/biBdcXFtzvPmrzIHDgitll91kI4Rtq5Z8K7988yqqsM - Dm/Ec1t7aL+A+PH9CSLMLNYfllANDvpS2qGV9vh4RGjO4d8P8WAejNczrcuQ4GEA - 1aInA29sNdhLFOKAt3BDKvSjxJM/b3J3jkg6CDzmccXolN/y - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID SW CA-38 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEoDCCA4igAwIBAgIBEzANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEY - MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT - A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMzAeFw0xNTA5MjMxNTI0NTFaFw0y - MTA5MjMxNTI0NTFaMF0xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy - bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRgwFgYDVQQDEw9ET0Qg - SUQgU1cgQ0EtMzgwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMtw2M - Q24eg6nE7h/ZXMiN0GTHnybtceAlYm5NmOWZNzr1/s22At1aN3NSilt5T2MAq7IJ - OOPVqtQ4e8YjvwnZMl/vhk6Z4rwAePshr9HvlO8CXl257RP3uN8HgRBRyiBzJh08 - Q8W+Hrb77XMn0CzdQ7h+0+hJjdwRjSAgHfHBagAFIilYBUHtresJNB7zk/jedaIu - v6xoTkJttS+USSWJ91Rqn1hvAZfd4XbweSqCPNFXXWvudII7DZ9G3ViymCXqXJDZ - KXW+iEOFewY9K1BMnI+NOV/qOv335oitPYeRqnIOiQmV0J2ArCYoWfQputQuHD6Y - y3dzTEj6dFH9CbuXAgMBAAGjggFrMIIBZzAfBgNVHSMEGDAWgBRsipSid7GAch2B - ehaq8tzOZu5FwDAdBgNVHQ4EFgQUjsW5zPzOjlO0Ks7oESrPmylsZ8owDgYDVR0P - AQH/BAQDAgGGMEwGA1UdIARFMEMwCwYJYIZIAWUCAQskMAsGCWCGSAFlAgELJzAL - BglghkgBZQIBCyowDAYKYIZIAWUDAgEDDTAMBgpghkgBZQMCAQMRMBIGA1UdEwEB - /wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADA3BgNVHR8EMDAuMCygKqAohiZodHRw - Oi8vY3JsLmRpc2EubWlsL2NybC9ET0RST09UQ0EzLmNybDBsBggrBgEFBQcBAQRg - MF4wOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9E - Uk9PVENBM19JVC5wN2MwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWls - MA0GCSqGSIb3DQEBCwUAA4IBAQChLaZGtZEevrRh4hyMrywIePJ1h8t8K766TTUB - 8AY2y5/BolEoHxKTOis7BRolriRFsa4PVFUSIXUsGQxrA2h8pa0v2irrEE2ixZGN - h5rSXXhC+UtALDF8PlWUvD/M1WLOIW277YHQ4JNjMl5OEhsrVoxJZ3I32bTG8EZp - EDmBbVPsBINRf1kjBd69xb7kk67DfUEs4fUjTHRDOflV388bX2877//UaADPfjGK - 6g9AxY++pf/4can/DhxhJ40+oKiDN29apuwmeNrfAi+CqL9uFu6JSxSUGOy4ZDLA - vmAQHGI6r+mRBcu8U/9xuaYpkO8jAoDNn7yS4H0STEoDorrR - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID SW CA-37 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEoDCCA4igAwIBAgIBEjANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEY - MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT - A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMzAeFw0xNTA5MjMxNTIzMDVaFw0y - MTA5MjMxNTIzMDVaMF0xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy - bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRgwFgYDVQQDEw9ET0Qg - SUQgU1cgQ0EtMzcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsrnKi - qfWUYvBZ5poN5GMO6qotl7XJ4GGfg/lr8ipbPcgYScw8HLXrxakW0wA+uEk3Yka/ - /bfUgtiLCqr2/SMYVISjXisglAHUiK1pnXl6ANJ3FGX4eio9XdbvifXjcMu462T3 - XoZAcbbwkk7j5G2P4uJn88h2GmprYJzePNLC38yMgi4FMRsPchVYpX3Fxk2wXEOg - hyeSYvueXWOzEtEDCEyrumQxHfW3Oru0b6JrTZMpztOlaTd9ngKLrIcKaXEyGtrj - lCokBmTALc6xnyKmUNf4R9Imo+lVbwSIycGnePOTrJccRTUbZsfXsFeD0lIWGnHY - rws1w9xarvIN7Gm9AgMBAAGjggFrMIIBZzAfBgNVHSMEGDAWgBRsipSid7GAch2B - ehaq8tzOZu5FwDAdBgNVHQ4EFgQUFiR+9y3B75I/vkTnVF7p/he686EwDgYDVR0P - AQH/BAQDAgGGMEwGA1UdIARFMEMwCwYJYIZIAWUCAQskMAsGCWCGSAFlAgELJzAL - BglghkgBZQIBCyowDAYKYIZIAWUDAgEDDTAMBgpghkgBZQMCAQMRMBIGA1UdEwEB - /wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADA3BgNVHR8EMDAuMCygKqAohiZodHRw - Oi8vY3JsLmRpc2EubWlsL2NybC9ET0RST09UQ0EzLmNybDBsBggrBgEFBQcBAQRg - MF4wOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9E - Uk9PVENBM19JVC5wN2MwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWls - MA0GCSqGSIb3DQEBCwUAA4IBAQBZDRYy0oP+yD3OiDqM3liOggDDqJidDSkqmPMB - pxTL9iyXCAqS5OUhzKQ2/N8gRYzO1o7JNIqez7kuwj1HJ0LH94jbjyMnvrWV34mh - m1OzbG1y/88FvheQXLgld+tjojxYVhErbFGHnxMPw1X0VpbRTWrAcetlfMNKdwPU - AH1GDfFmczuSfqwqZcapgJal9BWMIJoCXH1sUOHXmg/6anXx1d30OH9iTYV0to76 - oHTg6PEw7nwxNDgGcVgLDVyDAyTpfQCfhV4fSLI9cDTs4nA0SUgUga01d2h1Sp4r - 0PtksjJINJlYvLggvRWucI/MokLw5F6m+w6BN+t+kEggLn6T - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIDczCCAlugAwIBAgIBATANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEY - MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT - A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMzAeFw0xMjAzMjAxODQ2NDFaFw0y - OTEyMzAxODQ2NDFaMFsxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy - bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRYwFAYDVQQDEw1Eb0Qg - Um9vdCBDQSAzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqewUcoro - S3Cj2hADhKb7pzYNKjpSFr8wFVKGBUcgz6qmzXXEZG7v8WAjywpmQK60yGgqAFFo - STfpWTJNlbxDJ+lAjToQzhS8Qxih+d7M54V2c14YGiNbvT8f8u2NGcwD0UCkj6cg - AkwnWnk29qM3IY4AWgYWytNVlm8xKbtyDsviSFHy1DekNdZv7hezsQarCxmG6CNt - MRsoeGXF3mJSvMF96+6gXVQE+7LLK7IjVJGCTPC/unRAOwwERYBnXMXrolfDGn8K - Lb1/udzBmbDIB+QMhjaUOiUv8n3mlzwblLSXWQbJOuQL2erp/DtzNG/955jk86HC - kF8c9T8u1xnTfwIDAQABo0IwQDAdBgNVHQ4EFgQUbIqUonexgHIdgXoWqvLczmbu - RcAwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL - BQADggEBAJ9xpMC2ltKAQ6BI6R92BPnFPK1mGFhjm8O26GiKhVpCZhK00uaLiH+H - 9Jj1qMYJyR/wLB/sgrj0pUc4wTMr30x+mr4LC7HLD3xQKBDPio2i6bqshtfUsZNf - Io+WBbRODHWRfdPy55TClBR2T48MqxCHWDKFB3WGEgte6lO0CshMhJIf6+hBhjy6 - 9E5BStFsWEdBw4Za8u7p8pgnguouNtb4Bl6C8aBSk0QJutKpGVpYo6hdIG1PZPgw - hxuQE0iBzcqQxw3B1Jg/jvIOV2gzEo6ZCbHw5PYQ9DbySb3qozjIVkEjg5rfoRs1 - fOs/QbP1b0s6Xq5vk3aY0vGZnUXEjnI= - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD SW CA-54 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEjzCCA3egAwIBAgICASwwDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDMwHhcNMTYxMTIyMTM1MTI4WhcN - MjIxMTIzMTM1MTI4WjBaMQswCQYDVQQGEwJVUzEYMBYGA1UECgwPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLDANEb0QxDDAKBgNVBAsMA1BLSTEVMBMGA1UEAwwMRE9E - IFNXIENBLTU0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq0wnaj/j - ZzXRnZnNDN5rMZW7OmPPcrG+8IQW6oHretQqvj/HCnAyX3sl5TvT6bLCG4UfLBAx - 4VRCvpsVW9fME/43E+N8pyUDjlhYe8BHO9e0RfbVjMgDh6tLagvjN3MfThg8E94C - 6TRisdifkP6WonplO1sbv8YD49GjmBWLs8KtU3xzw/StQrwNfymY8aW4lXJQa/Ca - +FXzz/tRh7Mclrlz6QCzgdHAliWK4s5tsXDxeZls2/tvTaZQCVCiyccDdc//lYzL - UIwg3lnPcoV6CPhhw+QW4q42Y4oSu48Z9g/fAvqhrK1U0S9mHl1vWLDTHI3hkwmd - T/O2WgKh8nvx8wIDAQABo4IBXDCCAVgwHwYDVR0jBBgwFoAUbIqUonexgHIdgXoW - qvLczmbuRcAwHQYDVR0OBBYEFLC3KL8sBImKdCavqhOMAhBVgXmxMA4GA1UdDwEB - /wQEAwIBhjA9BgNVHSAENjA0MAsGCWCGSAFlAgELJDALBglghkgBZQIBCycwCwYJ - YIZIAWUCAQsqMAsGCWCGSAFlAgELOzASBgNVHRMBAf8ECDAGAQH/AgEAMAwGA1Ud - JAQFMAOAAQAwNwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5kaXNhLm1pbC9j - cmwvRE9EUk9PVENBMy5jcmwwbAYIKwYBBQUHAQEEYDBeMDoGCCsGAQUFBzAChi5o - dHRwOi8vY3JsLmRpc2EubWlsL2lzc3VlZHRvL0RPRFJPT1RDQTNfSVQucDdjMCAG - CCsGAQUFBzABhhRodHRwOi8vb2NzcC5kaXNhLm1pbDANBgkqhkiG9w0BAQsFAAOC - AQEAZF047yS8bq8lkMpoxFrJjmbdD1TNpjnWRmImQ32uPwNkrDbspNJ4GdqAh3N6 - ueIMcPUSmrIEs9GRZGJzOeTQ6tcQKCyWy+npsI1DQ/k5Xz0H375Bw17gnq2Bpjdy - s8zeg8I+2lDOjSNr7RgVWWB+2sVWXdvILx4Wkh6vX57uEud046HBmc4NeDiHAer8 - NIac5A7e379NRyuusNGXkAm3g7GsE/Y7MrFsKKsMlHb+gFXVgD0DBhtF22YqmA/R - QvTz7Ij1AD++Gv5I4IIzJFMryN6ED6XduWcTtk9Cnf0uY0z+VY8RFw9nOkECFc2b - BA8L2LlruBOzMWbFy4kH7G/hrA== - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD SW CA-53 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEjzCCA3egAwIBAgICASswDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDMwHhcNMTYxMTIyMTM1MDM1WhcN - MjIxMTIzMTM1MDM1WjBaMQswCQYDVQQGEwJVUzEYMBYGA1UECgwPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLDANEb0QxDDAKBgNVBAsMA1BLSTEVMBMGA1UEAwwMRE9E - IFNXIENBLTUzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwTewS9iv - ChYtMvNBYEOjVcVqr+3VOAEgyjt7ieJUVPrFDgtL9Sz+eXX+uBXkJwYjS0gtex6L - RuNtdcLkukoJu34ZxnfUwc8rgTwNV8VtIyI2GJq/u/FjGwK8fHkzslOzwF8KoA6N - NTYvKy9XohBDrrYGpRq/RuDttVfiJ4Yvcii5J6+uZTvT9035EksqjV7A+sJkFVqI - 3MZ83kN9O0ZJf4dEj4h4DKqQYHTRrpy/BL4pTGxmSpnQHne63ToqsoZntTYCYhB5 - 6izOakbsUTYVauwYqlNVf0j20IwcZibztp7wqV2NgGzA81LndhYLQh+8KsDabTSV - sZMvLHfEAeLdhwIDAQABo4IBXDCCAVgwHwYDVR0jBBgwFoAUbIqUonexgHIdgXoW - qvLczmbuRcAwHQYDVR0OBBYEFFHEizOZlMB+uzYd4+I6Bb0ydJ1TMA4GA1UdDwEB - /wQEAwIBhjA9BgNVHSAENjA0MAsGCWCGSAFlAgELJDALBglghkgBZQIBCycwCwYJ - YIZIAWUCAQsqMAsGCWCGSAFlAgELOzASBgNVHRMBAf8ECDAGAQH/AgEAMAwGA1Ud - JAQFMAOAAQAwNwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5kaXNhLm1pbC9j - cmwvRE9EUk9PVENBMy5jcmwwbAYIKwYBBQUHAQEEYDBeMDoGCCsGAQUFBzAChi5o - dHRwOi8vY3JsLmRpc2EubWlsL2lzc3VlZHRvL0RPRFJPT1RDQTNfSVQucDdjMCAG - CCsGAQUFBzABhhRodHRwOi8vb2NzcC5kaXNhLm1pbDANBgkqhkiG9w0BAQsFAAOC - AQEACZtxX9lr6sye0RUSOLYzLCU4jVDNSQgz3qq8Kk7dJ97GdsuBzACcCIwFDpNd - tjMtD+mwNjgfeRY5ovyMEH3ZzVhIqGpQo4WLeE+bjy3fNcU3rsb2SHNaEpRddWQ3 - jnOc3jlyg/sHaR6Jg4JfQ1G9za46AReVa1nJLHjt/BO5m/3D4iJmpJvq2Qp6N4eF - a2VL6s8uAZKnLCocjZU2B3wYZMyaSgppaE4TOe/Hc5HJw245/cFLUL8I02iYfv9E - KQDuTGqNzGrBuKp9LMpRrBWb0boFrZaONcVXjtCqi05fo1Fd/JhuvfraTpgxmVXi - 1OvgVGwq5lsxW2pbjSpBFebaRw== - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID CA-52 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEuTCCA6GgAwIBAgICASowDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDMwHhcNMTYxMTIyMTM0OTU3WhcN - MjIxMTIzMTM0OTU3WjBaMQswCQYDVQQGEwJVUzEYMBYGA1UECgwPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLDANEb0QxDDAKBgNVBAsMA1BLSTEVMBMGA1UEAwwMRE9E - IElEIENBLTUyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAltzcMp2O - 02t+fwd7rTlugoKqYF8eo/3M+JVdppPAHTiJVaVt0JSeM4xyZsKNoPBoFW/yshnx - lRv/LyNx0VBbn+4mJ7Ea1U4FBPxCSZ68VYqKdV64UMhndawVBJM3Oy8Y3ZxPldTD - f9ApCg4dZXSEiSnShO8YuphrNbYAd6YrdUn1IhDAhw90VTU3GMLru4vx60vFHscW - eZHpHfET8AsClbAyqu65bsa1+o0XvGLQy2GTMzEVaR1NhYVWKRSwgqW57gbE8pV+ - 63WYNwi8XIr/2TaJ5GvgBVCbgJWAwsSfFTz21ZqOou0d5xYu79iIIue5DEoRW1bm - qserHNG7gsMvHwIDAQABo4IBhjCCAYIwHwYDVR0jBBgwFoAUbIqUonexgHIdgXoW - qvLczmbuRcAwHQYDVR0OBBYEFJroUayRVNeUmgRI+iJ5/8bV7oYrMA4GA1UdDwEB - /wQEAwIBhjBnBgNVHSAEYDBeMAsGCWCGSAFlAgELJDALBglghkgBZQIBCycwCwYJ - YIZIAWUCAQsqMAsGCWCGSAFlAgELOzAMBgpghkgBZQMCAQMNMAwGCmCGSAFlAwIB - AxEwDAYKYIZIAWUDAgEDJzASBgNVHRMBAf8ECDAGAQH/AgEAMAwGA1UdJAQFMAOA - AQAwNwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5kaXNhLm1pbC9jcmwvRE9E - Uk9PVENBMy5jcmwwbAYIKwYBBQUHAQEEYDBeMDoGCCsGAQUFBzAChi5odHRwOi8v - Y3JsLmRpc2EubWlsL2lzc3VlZHRvL0RPRFJPT1RDQTNfSVQucDdjMCAGCCsGAQUF - BzABhhRodHRwOi8vb2NzcC5kaXNhLm1pbDANBgkqhkiG9w0BAQsFAAOCAQEAkxvd - sbOh2zGZCsj3nu9fHEMClJVtK4kJzPJZPi44gdSn+U8X5lbtT0kxsRrqCAZntlgQ - mp+DxnQClr35fjao3wF79nQaIOP2789a9VWZgyJfPrV2KLsxAH4/oOd2ZYdUtHfC - lbfZwbpxFulBqPWxysKQOx3XC/3LszCR0YFqbV/c5hBRB1A4sWBlF8KRGQyKdAyc - K7PrLcSMnLq04ugd5MfYWuJjJx/USNNWlil/LzqyCFzxPp4nGBB8y8s2LcZyvofh - HIBN9qxl3+EXcJyeyqyNiVZcgJi+DLSmBCckb2J6lN9tbGWV02WK+8OiAiZ31CfJ - /sezZ58EZayGYS031Q== - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID CA-51 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEuTCCA6GgAwIBAgICASkwDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDMwHhcNMTYxMTIyMTM0OTI3WhcN - MjIxMTIzMTM0OTI3WjBaMQswCQYDVQQGEwJVUzEYMBYGA1UECgwPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLDANEb0QxDDAKBgNVBAsMA1BLSTEVMBMGA1UEAwwMRE9E - IElEIENBLTUxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjjtDs/iL - TIf25t9SGGMP49gCFIYXcEtvTtc/vh+Cghf7qVwiNvUYCaGMq5q7F/pgL5xsw6Bn - iCMau2bZtLfl5xnMk2VMl2GRwUayHQ/0lyteeKid6fa8sfnlyNLh8lvPuHqQFJZX - 5vpfAC24NDQCrr8YIkkNRyxJihCpj8HHYuzTplDRIpMljahhAWCsQkUqlq/5Lite - XHYA/+EnT2hspkitSU+FUIWo0FKK95oo+i2uXX8x3cXWEUCXoR23Slk5NrGTwAsf - TUd16xWA1acvksunx8eK3uOVCV02Q0sldVN19NaGm8lpoBfbtiNz3lo/j1VT558q - 35LmOYWI6KzSTwIDAQABo4IBhjCCAYIwHwYDVR0jBBgwFoAUbIqUonexgHIdgXoW - qvLczmbuRcAwHQYDVR0OBBYEFJ2kwVzT+WZxSaiEIwO24a8pdy2uMA4GA1UdDwEB - /wQEAwIBhjBnBgNVHSAEYDBeMAsGCWCGSAFlAgELJDALBglghkgBZQIBCycwCwYJ - YIZIAWUCAQsqMAsGCWCGSAFlAgELOzAMBgpghkgBZQMCAQMNMAwGCmCGSAFlAwIB - AxEwDAYKYIZIAWUDAgEDJzASBgNVHRMBAf8ECDAGAQH/AgEAMAwGA1UdJAQFMAOA - AQAwNwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5kaXNhLm1pbC9jcmwvRE9E - Uk9PVENBMy5jcmwwbAYIKwYBBQUHAQEEYDBeMDoGCCsGAQUFBzAChi5odHRwOi8v - Y3JsLmRpc2EubWlsL2lzc3VlZHRvL0RPRFJPT1RDQTNfSVQucDdjMCAGCCsGAQUF - BzABhhRodHRwOi8vb2NzcC5kaXNhLm1pbDANBgkqhkiG9w0BAQsFAAOCAQEAigQ4 - aOduTUCpDvC0ue0B0GV49B0aek8HXWKc10bPb1iUCQL2DT4aIf0u+yQqrzVpTw/x - 5mVPRn2Zi2iEV5A8PsN4dReF3lblQSrSVvKFw7cq66Z8ab2ijXjpAMTJCUIOir8w - KoOV03cnVcaW0VDTH+gOslXnm95kPqdfbxJMh06Q00XfvWfRjfnB9D8ZDXbytM5X - mkZRyuUvWY+DKyJUy1HAuardaFpgA5WowjeQm9sAvx72LzaS7zmv+hxOliGXYOn7 - gbJATcT+zt1Ffwa9M19FjoQDSzWihW8P5cFRt6xVEwZHeD8VG++jcQfAujwX0v7U - hFKu8gxm3wlNXOalzA== - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID CA-50 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEuTCCA6GgAwIBAgICASgwDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDMwHhcNMTYxMTIyMTM0ODQ3WhcN - MjIxMTIzMTM0ODQ3WjBaMQswCQYDVQQGEwJVUzEYMBYGA1UECgwPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLDANEb0QxDDAKBgNVBAsMA1BLSTEVMBMGA1UEAwwMRE9E - IElEIENBLTUwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy1ncM1bN - JJHiu1Bh5jQ8r+Y1L2pvw+6YDLGE71z5gquBqisOC6XLKffKdBSF2U55vvp0m5J8 - WdF5DSfyfdAJ7S1HlzFYVW+0KjGLELKV5tWZh/aXu8V85ZaaYkvJeeEU5cIYWLKK - RAr1iygwnslhy1Kb7xhYV7gLYc29Wm1EgZiJ2Xm9M11FIauo40EXmQFniz4FLE/S - 4JB1lbYiP1jGa4zJrdnec1k65tZk/K4hdi2diS+9mEUz3PWrzNqjrHKxFocnh9qS - NGqJfyfXxXgKTrZw2UG83IxHKvIpMPodX4SYUwRm5HRbrG6c1Fx12NC2go16w3dD - ilH+aUduTNpmFQIDAQABo4IBhjCCAYIwHwYDVR0jBBgwFoAUbIqUonexgHIdgXoW - qvLczmbuRcAwHQYDVR0OBBYEFDYuUt50qp7sux+T0b62ULXGaQv5MA4GA1UdDwEB - /wQEAwIBhjBnBgNVHSAEYDBeMAsGCWCGSAFlAgELJDALBglghkgBZQIBCycwCwYJ - YIZIAWUCAQsqMAsGCWCGSAFlAgELOzAMBgpghkgBZQMCAQMNMAwGCmCGSAFlAwIB - AxEwDAYKYIZIAWUDAgEDJzASBgNVHRMBAf8ECDAGAQH/AgEAMAwGA1UdJAQFMAOA - AQAwNwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5kaXNhLm1pbC9jcmwvRE9E - Uk9PVENBMy5jcmwwbAYIKwYBBQUHAQEEYDBeMDoGCCsGAQUFBzAChi5odHRwOi8v - Y3JsLmRpc2EubWlsL2lzc3VlZHRvL0RPRFJPT1RDQTNfSVQucDdjMCAGCCsGAQUF - BzABhhRodHRwOi8vb2NzcC5kaXNhLm1pbDANBgkqhkiG9w0BAQsFAAOCAQEAbAli - o7+gWX5YytmPMD9ic+aX2s0NaSdSauFYmb6khtN0CCocIqTI/TyfRJTjhI6wRNoa - ckcjVa5H3EOp4vOrtLN4TxbhNqdE+IHafWE4/btDstI5PrA2hlFZb1zvM5EQC8u0 - BZQ/DqyShOjypvxldvol6UGjys7wecPxt3cBJC7uroY+nqfxHnOIxRFoJGdC7pSm - f90/uDcX87oCbK/FrzJBO+/V2lGHiByC7ahcP59a4Xd69lHSMtRWquclAyBEy1Mx - p7Bx/v5kCpv14JE6SBlYEwhFrTt4aT49FQEQ9aJFKRv7j20sS/6wxPzGx24HE0Gb - XwusK9jo5skGLLUC3g== - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID CA-49 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEuTCCA6GgAwIBAgICAScwDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDMwHhcNMTYxMTIyMTM0ODE1WhcN - MjIxMTIzMTM0ODE1WjBaMQswCQYDVQQGEwJVUzEYMBYGA1UECgwPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLDANEb0QxDDAKBgNVBAsMA1BLSTEVMBMGA1UEAwwMRE9E - IElEIENBLTQ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2EngKIwP - Cl9+dsIByO2uONNLKhpnFypBAE+LM8+kekt4/HG6StaU/fmqFTRiVI0Uh+td9BWe - 8NXOYrhQRo6FVSxBkLtWZX8Px2IHxiqQ1lnrZK9UlCo8h3MPpiN8VEjH2bP/WSa0 - oZEWzEDKLB5tSKerddc+QL2uEHb+Gfym6i+5qPOLXjV00FY24FdNOyHaRjQTM/Lf - sjWoFItHTKp5B9QogdKnyg+WkAARYtbd1nqtDXv6Fph5HaT39SEnRhc+lkrRDpDY - c+HAU6Xywik+stgv2yFk1MhFpF5/rndEwMLIST0+lSpahJKGmYtg1VKcnDcq5CER - C31gl6Yr7ffjAwIDAQABo4IBhjCCAYIwHwYDVR0jBBgwFoAUbIqUonexgHIdgXoW - qvLczmbuRcAwHQYDVR0OBBYEFNhnk8pG3MmVppSzBBicziU6lhxNMA4GA1UdDwEB - /wQEAwIBhjBnBgNVHSAEYDBeMAsGCWCGSAFlAgELJDALBglghkgBZQIBCycwCwYJ - YIZIAWUCAQsqMAsGCWCGSAFlAgELOzAMBgpghkgBZQMCAQMNMAwGCmCGSAFlAwIB - AxEwDAYKYIZIAWUDAgEDJzASBgNVHRMBAf8ECDAGAQH/AgEAMAwGA1UdJAQFMAOA - AQAwNwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5kaXNhLm1pbC9jcmwvRE9E - Uk9PVENBMy5jcmwwbAYIKwYBBQUHAQEEYDBeMDoGCCsGAQUFBzAChi5odHRwOi8v - Y3JsLmRpc2EubWlsL2lzc3VlZHRvL0RPRFJPT1RDQTNfSVQucDdjMCAGCCsGAQUF - BzABhhRodHRwOi8vb2NzcC5kaXNhLm1pbDANBgkqhkiG9w0BAQsFAAOCAQEATmfP - QPkolF5PB0fS/9DrngX0tmdSwlidBtrkY6vL/V7IMKqJk7r+hHW6k9+nxijHFj6Y - J1+4ElpH/PwWPsqwVIshQxECvJKfo3OfN3a8Mn6Hog5kXJl5dMb0vJOpWQ9UhmG2 - m9UUZ9847wSlbW0vMHL0puuTso0365vilPO5JkapEXcFXdc3LDxXW8BR5NHyaN3V - mvfD/qAqe4BiBx2+WAxsolTJQ5IMjG5tIN7WE6VJdUAm6EIgbuFfvG1KiWQJLHkL - XdTvwdUTqX9JQYswfvoCwvHRh+I2mZX+/iH5HKLcaxqW8b9JnHCtfMSBZqLdI3nG - IBw48tRul8lbrg0mJw== - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD EMAIL CA-52 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEvDCCA6SgAwIBAgICASYwDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDMwHhcNMTYxMTIyMTM0NzI4WhcN - MjIxMTIzMTM0NzI4WjBdMQswCQYDVQQGEwJVUzEYMBYGA1UECgwPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLDANEb0QxDDAKBgNVBAsMA1BLSTEYMBYGA1UEAwwPRE9E - IEVNQUlMIENBLTUyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw4pb - qFZ5LPm9gcWT24lCj8yLQHYdzntTWgMqPVyveG88rA+bXiAWO6zWUsjPlYQHfxiN - qTZemKgK8OUkVQA4oiQ59EzcNiRsZp1hy7nvDpFcW/0WJzHY5M84ThI57zRH20Ac - iNw1DB7XmR5yJFKTFusipWgsqwWRTtpJlLGJXhTHyG6aNxP6HEXbTLAM4x/0LM9Z - Q2yYihUufgtJYGeLapNb1pPLsPVchhJOQjLFyp3Kx9W1xfjUFftE9FQAwCBJHyC7 - tFMk6DlITy4s7ptst1nNbPYdzGmiix/P7+I702Yn8H3YbmhFD3d+fkhCXqsjio0y - 0wWFDaa6vmm3RqF1GQIDAQABo4IBhjCCAYIwHwYDVR0jBBgwFoAUbIqUonexgHId - gXoWqvLczmbuRcAwHQYDVR0OBBYEFOlmDFyb4lpKsgM2NP18yab4qwc5MA4GA1Ud - DwEB/wQEAwIBhjBnBgNVHSAEYDBeMAsGCWCGSAFlAgELJDALBglghkgBZQIBCycw - CwYJYIZIAWUCAQsqMAsGCWCGSAFlAgELOzAMBgpghkgBZQMCAQMNMAwGCmCGSAFl - AwIBAxEwDAYKYIZIAWUDAgEDJzASBgNVHRMBAf8ECDAGAQH/AgEAMAwGA1UdJAQF - MAOAAQAwNwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5kaXNhLm1pbC9jcmwv - RE9EUk9PVENBMy5jcmwwbAYIKwYBBQUHAQEEYDBeMDoGCCsGAQUFBzAChi5odHRw - Oi8vY3JsLmRpc2EubWlsL2lzc3VlZHRvL0RPRFJPT1RDQTNfSVQucDdjMCAGCCsG - AQUFBzABhhRodHRwOi8vb2NzcC5kaXNhLm1pbDANBgkqhkiG9w0BAQsFAAOCAQEA - dYEfuTkBoJLwzyIZ/lrxB3ECCes2zWMLe1RsRrQ3QUhkeLcqxxwG1z+UbbmWkrSS - JS0Q1XeLRiT7P1x+ycs1Gvoy5V4CFOryb5eNaDpOclJdXOiRjOGvS0wSeSLGnT/d - lRPrQZcoEm+DFvtSMasu/zR8DnaepKpWLvyFXwvoimvsQVvz4tOS2o4u400KLPBo - MQbTwpDmk39wxf4Aq4m8hznf2BhAy20YH6jY08gXg0pNDVh4CZIxyF2gmE0TDXPv - sx77lxYKW3Bx0ZxHIcfBKifjSiTrGlLeEP9LfEQdpCjJqhG/3BFy6flzwJDEHqHH - swhN9DCJn+3xTeq25PUXPg== - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD EMAIL CA-51 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEvDCCA6SgAwIBAgICASUwDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDMwHhcNMTYxMTIyMTM0NjQ5WhcN - MjIxMTIzMTM0NjQ5WjBdMQswCQYDVQQGEwJVUzEYMBYGA1UECgwPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLDANEb0QxDDAKBgNVBAsMA1BLSTEYMBYGA1UEAwwPRE9E - IEVNQUlMIENBLTUxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnw7P - Taj5UGSMi8whxGpPsoChGMjVQRk1Fzp9J/mPjx/oXc2MwMahK3xpE3YB86q/SeH1 - Cv5hc9Pa99HtSF/RaHAo3frFoPnRNoPDLj6ihPGmEWwMKywUgOCnTQcGSlNqR0es - tYrMTxti9bKE3uc0hgWibZYlukiGYg0UygYPS4+afMtzaBljiUWeQFrmCaEgeG3B - UvX/zgNdSqtG9KX1LjqtNZB91hIDrRUNohX5xSLxPMpojC5d391u/0GfAEXeKyAy - bPN8BdVjqJ7FlyueVKUgIAB/t/k6NO3lKEiC+QsrhrwaFI3Yme9JfRsZU8/Yhv0L - wKeJhoz3552oT0e4PwIDAQABo4IBhjCCAYIwHwYDVR0jBBgwFoAUbIqUonexgHId - gXoWqvLczmbuRcAwHQYDVR0OBBYEFDXvECJsuhIPvcJNGeTOfY8FV1w0MA4GA1Ud - DwEB/wQEAwIBhjBnBgNVHSAEYDBeMAsGCWCGSAFlAgELJDALBglghkgBZQIBCycw - CwYJYIZIAWUCAQsqMAsGCWCGSAFlAgELOzAMBgpghkgBZQMCAQMNMAwGCmCGSAFl - AwIBAxEwDAYKYIZIAWUDAgEDJzASBgNVHRMBAf8ECDAGAQH/AgEAMAwGA1UdJAQF - MAOAAQAwNwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5kaXNhLm1pbC9jcmwv - RE9EUk9PVENBMy5jcmwwbAYIKwYBBQUHAQEEYDBeMDoGCCsGAQUFBzAChi5odHRw - Oi8vY3JsLmRpc2EubWlsL2lzc3VlZHRvL0RPRFJPT1RDQTNfSVQucDdjMCAGCCsG - AQUFBzABhhRodHRwOi8vb2NzcC5kaXNhLm1pbDANBgkqhkiG9w0BAQsFAAOCAQEA - Y2UKHMi98mslNJ9qUBT8ZNGKim+nYkfLfBgdP136smJYYDcwUOXwHt3b1aOy4sXI - 0BkNNS6tO5fdvZ7W4/zYFouIVnImaa8hjDiJNoAi5dYKDxkB8iOWYlAP8TZwpKNy - sbGh4EQHWWQ8wDuFcdA5/9ElnxpQ/JJzSgUOHhtGm8vrEQmmJKW0FvbGXhGydHx2 - I5GtDvGHqlpF8GFIAA5HNAaw1s5De2StEYCTS/y95naqZafCxYG62cGbHir8dp0U - KQOUQt88tTh0TAqzcLKz1OJIoIkbfpzV6XiXuL0VSob+W0peZeqTVq+w7nWP1cNr - 44ligwwVjeF04L3sZKA54w== - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD EMAIL CA-50 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEvDCCA6SgAwIBAgICASQwDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDMwHhcNMTYxMTIyMTM0NTAwWhcN - MjIxMTIzMTM0NTAwWjBdMQswCQYDVQQGEwJVUzEYMBYGA1UECgwPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLDANEb0QxDDAKBgNVBAsMA1BLSTEYMBYGA1UEAwwPRE9E - IEVNQUlMIENBLTUwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAorU5 - fwMKXKwK4SrttozvWb8Zx9g+7pGrzD+cbaZbISrTvNTi9MhDYASMo23nzG/ShHQM - c0qCc10AVUqpAfwRhm9FbphD3r30SWKQsrKeObBW63iMeB6gfhg/+zScvkJxlqj6 - x5cHglMCFQfdqjgmjtcuWIGr7cDf1WQJLGfCz6ilKH/H2no0a3AyoFEAglrUyhC5 - n0IVsmyrWY4Hy9A/0xe84hl+68cJfB4VD+8A+YrUqEgspiqzocvzcuN/GNdeD9Lw - XPqylqnF8SN0HYoHmjbimscIn86wCxARO0siWZ7hStrcbkb+cgFoY5aScdldUkni - YI2cmRy0C5jv+wAfXwIDAQABo4IBhjCCAYIwHwYDVR0jBBgwFoAUbIqUonexgHId - gXoWqvLczmbuRcAwHQYDVR0OBBYEFGUKe10mGzDKLdz81nPHHsF/BIzIMA4GA1Ud - DwEB/wQEAwIBhjBnBgNVHSAEYDBeMAsGCWCGSAFlAgELJDALBglghkgBZQIBCycw - CwYJYIZIAWUCAQsqMAsGCWCGSAFlAgELOzAMBgpghkgBZQMCAQMNMAwGCmCGSAFl - AwIBAxEwDAYKYIZIAWUDAgEDJzASBgNVHRMBAf8ECDAGAQH/AgEAMAwGA1UdJAQF - MAOAAQAwNwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5kaXNhLm1pbC9jcmwv - RE9EUk9PVENBMy5jcmwwbAYIKwYBBQUHAQEEYDBeMDoGCCsGAQUFBzAChi5odHRw - Oi8vY3JsLmRpc2EubWlsL2lzc3VlZHRvL0RPRFJPT1RDQTNfSVQucDdjMCAGCCsG - AQUFBzABhhRodHRwOi8vb2NzcC5kaXNhLm1pbDANBgkqhkiG9w0BAQsFAAOCAQEA - VnLKwRdYBaPnEONJnTpHoC4znIQMHBsEpQbR8P5j49IXtHRjCpl5PKRIwuAc+Ff3 - ixM3jv/G+LBi26G0ZNGZ4iI11rJ3TLxUqHT12/WXTuS91jePA/f3WIHkGBEFeRs+ - wiROXSAveyMAt1ThK9Bil7BYlLmpgfci7eiKHC6OlA7VZo4OrS03VZTlaaBaU5Te - +tX8XYQ7Kllh9LreXZ2Cks14oNBlS4vzOcZOpw1bamaEbIA13IsGyY/kF7LqSPW2 - b7Jy628ObLeU3a+0lm+nIkjH25FDvtfxD9+2qQHEpRaRclskwIGTmA/Tg/YrrS2Z - am9RD+6E/tsgIIlQE09NEA== - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD EMAIL CA-49 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 3 - -----BEGIN CERTIFICATE----- - MIIEvDCCA6SgAwIBAgICASMwDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDMwHhcNMTYxMTIyMTM0MzE0WhcN - MjIxMTIzMTM0MzE0WjBdMQswCQYDVQQGEwJVUzEYMBYGA1UECgwPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLDANEb0QxDDAKBgNVBAsMA1BLSTEYMBYGA1UEAwwPRE9E - IEVNQUlMIENBLTQ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAus23 - xtOAbfLxPh+OS8U3N/c7ZsnTNZGki6KjnEg4EVHnUKwBB1pWLeQbZTVp01dHWlxR - KyvANnk+8ozM8tucowx0q6fo5J/YteD9qHFAoWjJQpRB6Hvn2vvHvUbu7iAY5Pel - 0B6A0NN/lKW26tTlim6NkV1MuCcvpCGrwH0f2TOCzkDf7IPqQDvLWOjPQP9nmNMG - nS+qCvF5F0iGFXTH1NDeI8EPvKMBQE+LgJ4PAF8eFdDo0mDE6iLfPAIXBzfYUdFk - MS3eVpJOWPzOEYeRLcWQkORvczfxN0obxSH3TGoBLB3ubELOoiqgsTF7rLKE1Kyz - Wrao15uoYf29O9jatQIDAQABo4IBhjCCAYIwHwYDVR0jBBgwFoAUbIqUonexgHId - gXoWqvLczmbuRcAwHQYDVR0OBBYEFGlEHxqVTqUaf4g6zHsSOSwfzxoxMA4GA1Ud - DwEB/wQEAwIBhjBnBgNVHSAEYDBeMAsGCWCGSAFlAgELJDALBglghkgBZQIBCycw - CwYJYIZIAWUCAQsqMAsGCWCGSAFlAgELOzAMBgpghkgBZQMCAQMNMAwGCmCGSAFl - AwIBAxEwDAYKYIZIAWUDAgEDJzASBgNVHRMBAf8ECDAGAQH/AgEAMAwGA1UdJAQF - MAOAAQAwNwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5kaXNhLm1pbC9jcmwv - RE9EUk9PVENBMy5jcmwwbAYIKwYBBQUHAQEEYDBeMDoGCCsGAQUFBzAChi5odHRw - Oi8vY3JsLmRpc2EubWlsL2lzc3VlZHRvL0RPRFJPT1RDQTNfSVQucDdjMCAGCCsG - AQUFBzABhhRodHRwOi8vb2NzcC5kaXNhLm1pbDANBgkqhkiG9w0BAQsFAAOCAQEA - XDNkaD2Gwe4ZoWklwvAvveoOYK5s8fJbjZOjI2V1tZjIP5edw8YSvLDGTqsaDlao - 28hCVhoOU0+V234p0CAGKNKID6WCR46s7uAALaaWfd4aHDzf20qYsnMrl0eKCv6F - sUtKBkIYJBjxpoaIpudRCnSmQkxweKzCGCtjWCT2MGSJro2Q0eQWTDxnJX9/v8z7 - dZ8ddZO1zgoU1xnAx9LxdrVl6H2VcB17z6t2d5TqSLM/OnuSHT7LWqYbVJERf38D - U0WSQ7VOp2x1SkInJqpewvi+0rl/yh97UoDZuS/GUkVIMFbpJkbcadiEGBINErRl - R5vQZDesBpGqUxNYuIIJbA== - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID CA-40 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - -----BEGIN CERTIFICATE----- - MIIEuDCCA6CgAwIBAgICB8QwDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDIwHhcNMTUxMTA5MTQyMjU0WhcN - MjExMTA4MTQyMjU0WjBaMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BLSTEVMBMGA1UEAxMMRE9E - IElEIENBLTQwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsC0FbWsI - la6+NfHD63GReLt85F4jdzs5mlNrXkjVlXJzksaIkmlHfqAWyo6ea8ShhqwdNnXg - PlIb7ej4RoXFqXJIwsCrxQ7rev+sCdkL5UtxOxPq40wbjV+AcjF8Qmp9xoPyImxz - lLebWWJ8HDgJl2HSLrIFibrRFeD0t6GLsT8JhOdQmqE8wRNypZH6oDIhygX3lhBe - RDxuK/6zLMJ+srqG8DMJFJhz0kHh36ugbJJOPLyEGxwjyEicBqk44NFcmr8YWC24 - RM28QjruqwotlsI3woCaTHkVm37fc0xmbAPg4eggxrzXn3dFQE+cw40WBLpy0d0G - 05PMAC1LKPdccwIDAQABo4IBhTCCAYEwHQYDVR0OBBYEFM1bl5X91Ceq5yXxnIfW - 8gfX0Yc+MB8GA1UdIwQYMBaAFEl0uwxeunr+AlTve6DGlcYJgHCWMBIGA1UdEwEB - /wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADAOBgNVHQ8BAf8EBAMCAYYwZgYDVR0g - BF8wXTALBglghkgBZQIBCwUwCwYJYIZIAWUCAQsJMAsGCWCGSAFlAgELETALBglg - hkgBZQIBCxIwCwYJYIZIAWUCAQsTMAwGCmCGSAFlAwIBAxowDAYKYIZIAWUDAgED - GzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9ET0RS - T09UQ0EyLmNybDBsBggrBgEFBQcBAQRgMF4wOgYIKwYBBQUHMAKGLmh0dHA6Ly9j - cmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9PVENBMl9JVC5wN2MwIAYIKwYBBQUH - MAGGFGh0dHA6Ly9vY3NwLmRpc2EubWlsMA0GCSqGSIb3DQEBBQUAA4IBAQBFRhX2 - izaXm5Yu4omDw2mbNo59EYAaITQCcUKbK6pwkmRYICu8DsjLMVhciOgeK4fn4OFA - mYbLXWAtgSknNc+Hugb4WFoLWSb3EKZs8ocb/fR4eJLOKoY1PuRCuozS4yZFPet8 - RFInX8l7NQ41Zyu4O4QNzmcMz4pct0E+7nOisGEjh7/29Q0UmITPek60iVGEBIzz - skjlclPzu7+qJseMF+cIV+DU5hFtEjXZ5HPn4fS2B/Fa15vkbnA9MvkxjFYjgLa6 - Xb/3zH5yYN2b20FluCxWyWD29UKXS5vwnXVGn4d+LIt5LPXbkgYt7uxgGCIkX2ha - hR0L51Yz9q3/sVvm - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID CA-39 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - -----BEGIN CERTIFICATE----- - MIIEuDCCA6CgAwIBAgICB8MwDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDIwHhcNMTUxMTA5MTQyMTU3WhcN - MjExMTA4MTQyMTU3WjBaMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BLSTEVMBMGA1UEAxMMRE9E - IElEIENBLTM5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHukMtcV - I9MuUvhC55JlteAPugFH0iElnuOH1uST9FQVwCueIgZEXFQ1HtQyK/N/Dt2nM89Q - FT6lJ55kAPhJtqYpGZYdfrirxWRTNzisQI2GoDTzID9iMYxd4wTikDvuTpV4H0s1 - sU6r9UqdouRFMZ+PrClHyTji8P9PrHY6+YSSLXu76fJgfKNdDBtIGaUhTA9CMOXv - TJGJLiZTuViJobP9hAEWtgd/8C2GIdTwbQPb/R7fsM/joH94HX59A00Q6q2COz1J - G6LB/GqvfIGpIx2NmLx6beRDQ1OpCs3mzqUTXmfQpZD6vweTXkyIGqlEgav5yahv - vjm2Pp7O3VjbEwIDAQABo4IBhTCCAYEwHQYDVR0OBBYEFKrDk9xwD3lROQQd5f8p - 6BbIrpPGMB8GA1UdIwQYMBaAFEl0uwxeunr+AlTve6DGlcYJgHCWMBIGA1UdEwEB - /wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADAOBgNVHQ8BAf8EBAMCAYYwZgYDVR0g - BF8wXTALBglghkgBZQIBCwUwCwYJYIZIAWUCAQsJMAsGCWCGSAFlAgELETALBglg - hkgBZQIBCxIwCwYJYIZIAWUCAQsTMAwGCmCGSAFlAwIBAxowDAYKYIZIAWUDAgED - GzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9ET0RS - T09UQ0EyLmNybDBsBggrBgEFBQcBAQRgMF4wOgYIKwYBBQUHMAKGLmh0dHA6Ly9j - cmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9PVENBMl9JVC5wN2MwIAYIKwYBBQUH - MAGGFGh0dHA6Ly9vY3NwLmRpc2EubWlsMA0GCSqGSIb3DQEBBQUAA4IBAQCvxzdd - +7fyM+exiin8pLYIADkJ4pUEnO3xxayqEviFgD/kqy6VInSIWP+eajXsTAHQwsUi - aV9i8ba+ejpZpkU83XgyWR873P0Vycg4o2pUdx1jhXzoMqEq/iZBvV6SEKqHRmK3 - 8eZ0mzAevAE8vEfr8o1RtwoPO+4Uh6pZpBcj4NWYgL9l+CDotlKivAMIy0nN+NFJ - 4SqPWXODhmFlBsCtGY0sJWRWn9sGi0kaEU0sOyqfSnGwchTS34D7MuaDYk7Usgx3 - Sto/Cpp7scmHsVq56evon9YHVxclT3NoWKy9HHxsMIjVVAEGpXOZ05LYW6O02Eds - oZ/0UDsa8A8aV5aL - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD EMAIL CA-40 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - -----BEGIN CERTIFICATE----- - MIIEuzCCA6OgAwIBAgICB8IwDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDIwHhcNMTUxMTA5MTQxODQzWhcN - MjExMTA4MTQxODQzWjBdMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BLSTEYMBYGA1UEAxMPRE9E - IEVNQUlMIENBLTQwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzNjg - O6XMNXsXqOPEk9Q7ZmS8o3JNb1NhmvC5hpfRuA7GUDT0eFJYt0uWgMqFdSvMTrRs - JW86RfWnuAz9dnszgUPcfimp+6LNy3yEb/NUWQXiiYCKmuDLo8YWkkfzoMIAzVH+ - Dy++wzc7lOngm5ZgDzdVuGd/QRQ880HyJ9HYnJFkMT9vXvlbYDN7HopIWJntpeaa - tqudwm29Iz3wq6/wba8tDd6aWnOwfRfL9uCe8EGuw4xJh1uvpFfMq2N5GhUIb6kS - q4gai+t+b2cfNJ2OIwKQnysfcO5kJne1Za4oI7GP03IDtRyygvBANOTrBnxKUhMX - MjbCxRxNGm6/GJCz5QIDAQABo4IBhTCCAYEwHQYDVR0OBBYEFJuBtqJZi+3pgB/w - Jz1XBT6JL7bMMB8GA1UdIwQYMBaAFEl0uwxeunr+AlTve6DGlcYJgHCWMBIGA1Ud - EwEB/wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADAOBgNVHQ8BAf8EBAMCAYYwZgYD - VR0gBF8wXTALBglghkgBZQIBCwUwCwYJYIZIAWUCAQsJMAsGCWCGSAFlAgELETAL - BglghkgBZQIBCxIwCwYJYIZIAWUCAQsTMAwGCmCGSAFlAwIBAxowDAYKYIZIAWUD - AgEDGzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9E - T0RST09UQ0EyLmNybDBsBggrBgEFBQcBAQRgMF4wOgYIKwYBBQUHMAKGLmh0dHA6 - Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9PVENBMl9JVC5wN2MwIAYIKwYB - BQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWlsMA0GCSqGSIb3DQEBBQUAA4IBAQAv - ty5uG7qcbmzT2hU1riC3WUF7fYN6qCRBGRe1beziZqr7NWsJYUWDu9iIvHTRsXdI - SgYgtqseBl9zCmY49iyXWBOs26RF6CyVOOi9cDPMzzuXHfsrFRrlgotvgI/IxJkt - DH41GbkFmx/yZXkCd8wEM5Ud7Gy61zquEvD1qsYM8qUuDCcT0sB70njKQ+ETKQBW - uQdqRDyUSHbnFZaHS8/uGpCL93ie9vVRJEBuGl0fgJXblXDcJsM0YOVgLImGCxnk - lfWCaIA7QtkWmd249PPR+KgM0WW+QXHLEsULo5iUrZxOgPUoo4auLR/Alk4KFmql - 8AJej2z9iMmg6Jb1BbG1 - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD EMAIL CA-39 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - -----BEGIN CERTIFICATE----- - MIIEuzCCA6OgAwIBAgICB8EwDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDIwHhcNMTUxMTA5MTQxNDQ3WhcN - MjExMTA4MTQxNDQ3WjBdMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BLSTEYMBYGA1UEAxMPRE9E - IEVNQUlMIENBLTM5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/Gg - vdig7X8ajfgi1iqHWM3n+GGoqt9cQwGfORbowgjHwIDb7tNQqMPRG2pVYSlST5nl - Nkoe+XRTI/vhExMRYvTDkBmxcFpHAmi4lVFeYHfGYvYn7Ai9SndbTlK4G8tx9BPu - rYjrI7z+TYdlNfcxcqU9Zus3L7VSjo4Nz/oGu1QPdZ3e5W27mrBrGVodhYrGd9zb - vclzDGKpANfrrF6Wm0/t07/j2opYuXDrp3CSVPgHXRCLueDJ+xyIth8oZ/uq7l1u - O2a+4xixCQpuGnTjVfBkC19jSG8WylKn8crduVPLCmRTp65IXgTBAV6gpjta1veA - 8+hFLGswsSKzVTy2YwIDAQABo4IBhTCCAYEwHQYDVR0OBBYEFKyd+MRMc6BDXwgl - fUYPZRvLoLCAMB8GA1UdIwQYMBaAFEl0uwxeunr+AlTve6DGlcYJgHCWMBIGA1Ud - EwEB/wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADAOBgNVHQ8BAf8EBAMCAYYwZgYD - VR0gBF8wXTALBglghkgBZQIBCwUwCwYJYIZIAWUCAQsJMAsGCWCGSAFlAgELETAL - BglghkgBZQIBCxIwCwYJYIZIAWUCAQsTMAwGCmCGSAFlAwIBAxowDAYKYIZIAWUD - AgEDGzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9E - T0RST09UQ0EyLmNybDBsBggrBgEFBQcBAQRgMF4wOgYIKwYBBQUHMAKGLmh0dHA6 - Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9PVENBMl9JVC5wN2MwIAYIKwYB - BQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWlsMA0GCSqGSIb3DQEBBQUAA4IBAQCa - 8QoBL1IVhci+xe1rnO2hJlMnKKWwsRXmxC0qq+sSqdEcq0hmwDFlQeKyI7hByp60 - 9J+i5yhu5ebOHGsQuU71/ENMAMOczUYt+MYJocGcwe1g1b/XZtZshgo9N6Gwrlny - WFwbr5CnX6yswooBmUl0xdYvcd/ZZ6/5djuVUu4n6/bIwbWcqkkyEDPGGFNXxenT - DuS3BgRAaggyMcNhQNdH3gcc8DbQ57lB57uBNO0cHcaVa2Nk+TGt3eRoLTeqNHoS - 4ZQbg9v4OhAZJtwhKydCtxZAcHcxL2qFXMiT2ots/NmWZyS3sJqSgWcz77a2xREb - is7L2sM8/f9lDnpymyuz - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID SW CA-36 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - -----BEGIN CERTIFICATE----- - MIIEuzCCA6OgAwIBAgICB6EwDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDIwHhcNMTUwOTIzMTM0NDQyWhcN - MjEwOTIyMTM0NDQyWjBdMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BLSTEYMBYGA1UEAxMPRE9E - IElEIFNXIENBLTM2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtnkW - Y6AlD+M3jiVf9vhsodsLFGnoiYi3dQoseibOrPSU555Ft/5GHGmj+nCXW9twRmGp - AckwzWakNR6nyDh56c5OhJxWKEg594B2i9SBmTXicTzBPa3tZNoJh6Ml6/Ofch+G - XR9u/FFdDWs7ubEF2K7u82MQUsYif+tePRAssI0CToGPF5SPw3+CcijFwY73JFFy - my55gZtb9jiEEp1aWrIgJ9nJczyWbFOV15I5tZPQiWlaXq0BGFh1hJiTGhgGs3fZ - H+yqMmOL91Msb9u99TAr4R4A6yDV/s313JkV4kWIJ1CNSPZHsXOY5WXj6zq/CDhM - JqozUbreJREFadAfwwIDAQABo4IBhTCCAYEwHQYDVR0OBBYEFGcaNjy6u2+FA+cj - iK3FZ5ClTLqEMB8GA1UdIwQYMBaAFEl0uwxeunr+AlTve6DGlcYJgHCWMBIGA1Ud - EwEB/wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADAOBgNVHQ8BAf8EBAMCAYYwZgYD - VR0gBF8wXTALBglghkgBZQIBCwUwCwYJYIZIAWUCAQsJMAsGCWCGSAFlAgELETAL - BglghkgBZQIBCxIwCwYJYIZIAWUCAQsTMAwGCmCGSAFlAwIBAxowDAYKYIZIAWUD - AgEDGzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9E - T0RST09UQ0EyLmNybDBsBggrBgEFBQcBAQRgMF4wOgYIKwYBBQUHMAKGLmh0dHA6 - Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9PVENBMl9JVC5wN2MwIAYIKwYB - BQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWlsMA0GCSqGSIb3DQEBBQUAA4IBAQB7 - r4RGlVKvdqeCAoErpvW10WRPIn4mmMJbOwzwfgLPzGKvnNQR0CWPWgb8Y7QZYtIT - cbBcWE8awZwB+OWDgTOoxrD0+euOw2CvZg36Z0P7mbS4IF6ElxDd/tzw5Hqr8vkw - hH/F2f6k7+tRznt4+cMQwJmIDKGwoZ+3Atd7CKcouBzXZLcNEbbohJF5z54EYwRU - J5agPcnTZMBDkQfSs9ku1nPrGQfATEBybLTAe31untM6oMzMHw8PYn3Sh7xWTCDG - SFSnPYhzlNKdMb8BKi3spVOxt6t3VHzNXDo8FXRbNpBY/fS7RAmHPPrz5pa9KNtJ - cKENmIqQ5QbjB/P8UX3i - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD EMAIL CA-34 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - -----BEGIN CERTIFICATE----- - MIIEuzCCA6OgAwIBAgICB6AwDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDIwHhcNMTUwOTIzMTM0MTU0WhcN - MjEwOTIyMTM0MTU0WjBdMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BLSTEYMBYGA1UEAxMPRE9E - IEVNQUlMIENBLTM0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl9rP - JyF3FMlTkbUCbyRbHPGfd9K7RKdmnCE257ehsNm7nM7Q9zxc8SpbTSDbOaP3Wqov - S5bmsSE+leWR/MhTGV4VMKztZmkGea8WYd5zooz+OrmfuoxEoCy5Ciya+RT+wLOw - H0ApD4doIkrkZd2Q2ZJeL/8pDDj1hPAMLpTfJbekNsQ3hsWnKp7AWVsliY4lR8u0 - RYmX4LHYM5hN+qf6uiOLK6U/pcXcyRa3ymxiqq0gkVKqzybqKjlF4JucUU9zTc/R - cm2XSQEFl5niGI1YRRcrwGdl88TEYqcD8LfqAfKtVHvKy6nQ49L2S8qXQi7p9DmB - bGf0c9gZFxG2SAo19wIDAQABo4IBhTCCAYEwHQYDVR0OBBYEFA+GWX7j+ucT+zE7 - wTkMfGCLQMLdMB8GA1UdIwQYMBaAFEl0uwxeunr+AlTve6DGlcYJgHCWMBIGA1Ud - EwEB/wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADAOBgNVHQ8BAf8EBAMCAYYwZgYD - VR0gBF8wXTALBglghkgBZQIBCwUwCwYJYIZIAWUCAQsJMAsGCWCGSAFlAgELETAL - BglghkgBZQIBCxIwCwYJYIZIAWUCAQsTMAwGCmCGSAFlAwIBAxowDAYKYIZIAWUD - AgEDGzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9E - T0RST09UQ0EyLmNybDBsBggrBgEFBQcBAQRgMF4wOgYIKwYBBQUHMAKGLmh0dHA6 - Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9PVENBMl9JVC5wN2MwIAYIKwYB - BQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWlsMA0GCSqGSIb3DQEBBQUAA4IBAQBU - 9C9y03/5bT/I09cfBTJDhgP5zoFm45xTzfA47ENg9zj7VntEUG9KH4lkgnIxrD+p - hx5kGZgpxK218MWlQKWutYtrFeeS+RBisyVEGEtF2JjYEmQ4dUAOfVEy2iE/6jlg - 7JWB3nPNCVYjWsvYAwrtciclM/xdAbuBm1valn5TFGwp3UQNMfkbiYs6luVubPmO - 760ruzCJyDwcOopbraZJ3BNqMVbPHL68axpk8mKE83k6WgqMYIEsolA2F95OSPuB - +3jjC6U0fehSz5Ud4xmFdFV4AiW6mgCYy1RZxwPO7HovxjRs+tg8UtwcOjnVBPpM - 5Qh8+8BEUs7sjKlow1tH - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID CA-34 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - -----BEGIN CERTIFICATE----- - MIIEuDCCA6CgAwIBAgICB58wDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDIwHhcNMTUwOTIzMTM0MDMwWhcN - MjEwOTIyMTM0MDMwWjBaMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BLSTEVMBMGA1UEAxMMRE9E - IElEIENBLTM0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz7At/wMM - qpI56sRrQlphyt7hTUYitQma2jYHROcUqaROcqW7Q+sZQuH5lENLlRP6xd/mIYac - +w390E2kPbMQwA46yb399LTve7pJoeukdfNUhgLtBJ1R9Kg3IRJhgr8J9vnY5m5S - y+MsGKhwA5XHcGtJtC0NiKYuxnqZpHpa4pDHNFaRQFl+nka12K15qxPgyf6+ro4m - LHJcD2Mk/KE82ETlBgI5TRxxSVLeO9PnFPcNyLMxD2IKe/1zdoHTpDU6lIEjln2v - 22QN2Ibr1HBwOACwITWeMMr9tUg2fQtIBzLkybJbWxgo9J5kPpoqQih2Eo6ZKky5 - dSdcuOQrwr2OYwIDAQABo4IBhTCCAYEwHQYDVR0OBBYEFBgkTL1Wlo/EyOP9BWWL - mIjjiHDGMB8GA1UdIwQYMBaAFEl0uwxeunr+AlTve6DGlcYJgHCWMBIGA1UdEwEB - /wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADAOBgNVHQ8BAf8EBAMCAYYwZgYDVR0g - BF8wXTALBglghkgBZQIBCwUwCwYJYIZIAWUCAQsJMAsGCWCGSAFlAgELETALBglg - hkgBZQIBCxIwCwYJYIZIAWUCAQsTMAwGCmCGSAFlAwIBAxowDAYKYIZIAWUDAgED - GzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9ET0RS - T09UQ0EyLmNybDBsBggrBgEFBQcBAQRgMF4wOgYIKwYBBQUHMAKGLmh0dHA6Ly9j - cmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9PVENBMl9JVC5wN2MwIAYIKwYBBQUH - MAGGFGh0dHA6Ly9vY3NwLmRpc2EubWlsMA0GCSqGSIb3DQEBBQUAA4IBAQAGxypr - 9mbQvdY2thCJ3ANDuIn1MK8IhiX3We5joBshmTcfh71DFKsNvUps4BPdjfNGcHng - CTlgHwe4MEsNzUpSkD3e2nm7jPriXh4tRL5RJFEK6yxDL+k3LTL0c/gVjjhsnZoi - mr2a8JoWyDUVdUJmHly4M6GtDWw2l6CiEro3Lv3pEuURrgE+demq3WMhb5IZw7+N - Zi4GapdONX/a+e3028H9KVOC2IbfH9FZGhL96g5YtASd+twKydAen61NE49wYZqZ - rn0E2PywQSqZjiuiEM9F3QNzGVd9geux4TIYvzyQl0ywWkimZlCQPkQUe/hOUdZW - MFJfAy8EW8z4XsPc - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID SW CA-35 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - -----BEGIN CERTIFICATE----- - MIIEuzCCA6OgAwIBAgICB54wDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDIwHhcNMTUwOTIzMTMzNzUwWhcN - MjEwOTIyMTMzNzUwWjBdMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BLSTEYMBYGA1UEAxMPRE9E - IElEIFNXIENBLTM1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAivXY - eDP8GJB+ao4zla/UEtJDKEflwOSda8kGxkfbz9mMLQFB0iamHa+g/ldgulIUr/pr - upUb959Q2i26GrWHRozgWniOdLU6/X4ZQnic2cM8ejit9TK45jGmr9Krk7+Gvt+i - XtDHTVAQKyVJOKBZyexFE/zBeGjEv5d4tnLy2rjqrgfskXTAYTBJfOkJvHogmuP2 - hrMcEkC/b6LYAAFy7obVdmZcv7B9c4brzml6ZdW/Hjp/S9Z+qY+WnDr+hnbN0Oc+ - qxAaxZxY7kMBMBCEMXH9wBnGFEVQ0CFW918zYKXaIDizkcMCC7GlORKGnQh3gxKn - r7NOc5mSlVK6W5az9wIDAQABo4IBhTCCAYEwHQYDVR0OBBYEFN7CRmPJB/WsEhyq - mREdH+pT5lQyMB8GA1UdIwQYMBaAFEl0uwxeunr+AlTve6DGlcYJgHCWMBIGA1Ud - EwEB/wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADAOBgNVHQ8BAf8EBAMCAYYwZgYD - VR0gBF8wXTALBglghkgBZQIBCwUwCwYJYIZIAWUCAQsJMAsGCWCGSAFlAgELETAL - BglghkgBZQIBCxIwCwYJYIZIAWUCAQsTMAwGCmCGSAFlAwIBAxowDAYKYIZIAWUD - AgEDGzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9E - T0RST09UQ0EyLmNybDBsBggrBgEFBQcBAQRgMF4wOgYIKwYBBQUHMAKGLmh0dHA6 - Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9PVENBMl9JVC5wN2MwIAYIKwYB - BQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWlsMA0GCSqGSIb3DQEBBQUAA4IBAQCW - F8rvKyx7YtnMtonV/LyPXUHpCnFbGeg8drZ7qNKLVxxLraVBSs6rQz1XiKTcyzpu - zYfPyDIHvxaugkJg3cL/oruKJ3GZ/wxQdNzcljfhAcpuz0BCv3nGzHy2khAoFbds - ZbjTeeP189okGF8hV9Wv0jImfvgAyQJV4Sve7KBQvwwBJRRLA92WTPmkbSi/LtO7 - 2FyOiuoaRA68xmptPiL1xjap0fHJfovs6imAGl8DuVERDsuPiNoQzsDDkPaNQ9j+ - /sAFszlaatFIBKTmZ0hWk9PHnSLb5vlP1zyFJuUSK6Ab5s0jWUFed/YGCPalQSys - aBRL9SJlA8HhG84Ywl2q - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD EMAIL CA-33 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - -----BEGIN CERTIFICATE----- - MIIEuzCCA6OgAwIBAgICB50wDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDIwHhcNMTUwOTIzMTMzNDU3WhcN - MjEwOTIyMTMzNDU3WjBdMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BLSTEYMBYGA1UEAxMPRE9E - IEVNQUlMIENBLTMzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwSKS - bVjWCG5J6MNxhYf1FAiXnHuZFVMZ0b3XTV9rE944yOfKBGT76dCBIAvegMB2HqB2 - ijX/ME5JB6o/YKHHq1DfWTKKiBc++0Pu2L/5EGQfqMMEr7e44hmydzjVrIfM+1/s - wV8C+kTqDtK6CnQio/E4sKnALwcMKi6QhdNotGRuHPQzYFvu3CXWhekic6hD4rFK - jKKhi92f00nMGs2uKtkHZZ/zfqZqi0B1ngDMIO2nklz8MIlHtuyy6aVe1kjd7j/z - 7rYBISC0u7MtH7nDWXTS9H/jer7/NPH6Jv84euHwYZoiW+XJsV+n39N6fUz6A3DH - VEjdltOveeCBC1LI8QIDAQABo4IBhTCCAYEwHQYDVR0OBBYEFBVlzf0tkBZKr/w4 - lwDc6kOw3yCXMB8GA1UdIwQYMBaAFEl0uwxeunr+AlTve6DGlcYJgHCWMBIGA1Ud - EwEB/wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADAOBgNVHQ8BAf8EBAMCAYYwZgYD - VR0gBF8wXTALBglghkgBZQIBCwUwCwYJYIZIAWUCAQsJMAsGCWCGSAFlAgELETAL - BglghkgBZQIBCxIwCwYJYIZIAWUCAQsTMAwGCmCGSAFlAwIBAxowDAYKYIZIAWUD - AgEDGzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9E - T0RST09UQ0EyLmNybDBsBggrBgEFBQcBAQRgMF4wOgYIKwYBBQUHMAKGLmh0dHA6 - Ly9jcmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9PVENBMl9JVC5wN2MwIAYIKwYB - BQUHMAGGFGh0dHA6Ly9vY3NwLmRpc2EubWlsMA0GCSqGSIb3DQEBBQUAA4IBAQA0 - aN8RNdEAXOx0WqWKmJoBt2y8LJv1EYbhSWoUP+U0OLTPpkrz0nH4/vR/EYtpkbHV - KOAlXWzlyCigMI8spRUKuAtpyq4BFE4kppL8jBc977oLPTFu/Xw+Hw1U2W07fL8n - VbxxYQZltrMu6yYztK/GuNpXnSWD17ZgtypvkefzttygHUfyVTqMsYBpYWncSu9E - ju6VtYJVikCqDfevloX6tX+4pUPsyyxkUMe0xm8YvO4iN/OX3ABW0IGPtGxhIMWz - /aE9BFtgUY45gnpcAagoqN8I1FYq+zaeflPb0h3yevoypAzRqAt3FftEXDHlcEdj - P6LrZrEWHn3iSLihEODb - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD ID CA-33 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - -----BEGIN CERTIFICATE----- - MIIEuDCCA6CgAwIBAgICB5wwDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDIwHhcNMTUwOTIzMTMzMjMyWhcN - MjEwOTIyMTMzMjMyWjBaMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BLSTEVMBMGA1UEAxMMRE9E - IElEIENBLTMzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx3397Vyy - U8iwnti8z0835m6o5N6b9ZbPg2AwbGZsBHEA0aW9LrgWqVNdRrFN+L73IVfYhrpd - B9SO72ZGsBfekTPAK4/g0WPwoxDeO+jpBDDbrp/mOrxWlZseY6jpSvETmYdBHuql - dnh+HbnuM7/c863NrUHZvq9T5+wEJekvhJOkta92+WPQhTmoRGDz/C0k7EYVIxWB - XqNDSqbb4eT+9kavdZKMuALhV/Qvij1UC7EyxYGT5GPclNvCDtRxmo397vmiZMpr - LuXqy8DJNnQmQfRSEknYRG13+UAQsYs2GmBc2M7nUXhzmfmAjG3DQNs7F6D0mwym - PurM27FE6rQx8wIDAQABo4IBhTCCAYEwHQYDVR0OBBYEFC2O2dSD8uKQjEufb/lG - 52pLzbwnMB8GA1UdIwQYMBaAFEl0uwxeunr+AlTve6DGlcYJgHCWMBIGA1UdEwEB - /wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADAOBgNVHQ8BAf8EBAMCAYYwZgYDVR0g - BF8wXTALBglghkgBZQIBCwUwCwYJYIZIAWUCAQsJMAsGCWCGSAFlAgELETALBglg - hkgBZQIBCxIwCwYJYIZIAWUCAQsTMAwGCmCGSAFlAwIBAxowDAYKYIZIAWUDAgED - GzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9ET0RS - T09UQ0EyLmNybDBsBggrBgEFBQcBAQRgMF4wOgYIKwYBBQUHMAKGLmh0dHA6Ly9j - cmwuZGlzYS5taWwvaXNzdWVkdG8vRE9EUk9PVENBMl9JVC5wN2MwIAYIKwYBBQUH - MAGGFGh0dHA6Ly9vY3NwLmRpc2EubWlsMA0GCSqGSIb3DQEBBQUAA4IBAQCzqB2z - CqvPEhgEgFD9/ebtFDm6a3c5JtW+1GRgvw2Bm0rVQ3NNecr+C1YnwTv4fut+75rd - a2R77MDyszJYzM6i0nO6f30xm5dGKPgGS7HiPD3Ph47XLY/N+cuAj0mowXCOWK56 - n0uvXU5DKxrAeqlbaUOYakyCw67Pzz+FBNSWlTxrjEkG8rqzUIY7VXX8MtectJ65 - rahntartTt+gsOzECELWFwoRvPzV7pUrY9VSnKR8sjusnxK4J/b0cRk2RblXUe3G - Un9fXfDDnUQ3CgQtbScfDWOeAbPJdLYWW75YSzsyW03amrOi2aBJZU1E+7hvJkm7 - cw8ckAW5tJD5SRim - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - -----BEGIN CERTIFICATE----- - MIIDcDCCAligAwIBAgIBBTANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJVUzEY - MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT - A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMjAeFw0wNDEyMTMxNTAwMTBaFw0y - OTEyMDUxNTAwMTBaMFsxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy - bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRYwFAYDVQQDEw1Eb0Qg - Um9vdCBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwCzB9o07 - rP8/PNZxvrh0IgfscEEV/KtA4weqwcPYn/7aTDq/P8jYKHtLNgHArEUlw9IOCo+F - GGQQPRoTcCpvjtfcjZOzQQ84Ic2tq8I9KgXTVxE3Dc2MUfmT48xGSSGOFLTNyxQ+ - OM1yMe6rEvJl6jQuVl3/7mN1y226kTT8nvP0LRy+UMRC31mI/2qz+qhsPctWcXEF - lrufgOWARVlnQbDrw61gpIB1BhecDvRD4JkOG/t/9bPMsoGCsf0ywbi+QaRktWA6 - WlEwjM7eQSwZR1xJEGS5dKmHQa99brrBuKG/ZTE6BGf5tbuOkooAY7ix5ow4X4P/ - UNU7ol1rshDMYwIDAQABoz8wPTAdBgNVHQ4EFgQUSXS7DF66ev4CVO97oMaVxgmA - cJYwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD - ggEBAJiRjT+JyLv1wGlzKTs1rLqzCHY9cAmS6YREIQF9FHYb7lFsHY0VNy17MWn0 - mkS4r0bMNPojywMnGdKDIXUr5+AbmSbchECV6KjSzPZYXGbvP0qXEIIdugqi3VsG - K52nZE7rLgE1pLQ/E61V5NVzqGmbEfGY8jEeb0DU+HifjpGgb3AEkGaqBivO4XqS - tX3h4NGW56E6LcyxnR8FRO2HmdNNGnA5wQQM5X7Z8a/XIA7xInolpHOZzD+kByeW - qKKV7YK5FtOeC4fCwfKI9WLfaN/HvGlR7bFc3FRUKQ8JOZqsA8HbDE2ubwp6Fknx - v5HSOJTT9pUst2zJQraNypCNhdk= - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD EMAIL CA-32 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - -----BEGIN CERTIFICATE----- - MIIFUjCCBDqgAwIBAgICA6IwDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDIwHhcNMTMwMjA0MjA0ODEyWhcN - MTkwMjA0MjA0ODEyWjBdMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BLSTEYMBYGA1UEAxMPRE9E - IEVNQUlMIENBLTMyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo/qq - hsqKGhsDTnFtQbbZZZpu/zYqPwLTfJVliFqk969jt1LHGvu7lXMHQmGLSqZ76VYH - NhuqNwIgHKTO+7bQaav8OEzI20ZW96JefucxtO7B/81kv3mCQSt30vh9q0yP98Ye - PPiOLz0Ug9qSmAnY0MZaWTaLh6KJ3b5KXsvNtkd+QaYJVGxBlnRbBsPUwS5GfV42 - 342iRnGsSrrEsffJFwov3aPshCHPqAXqueMub59+fbsdFnVPkh0D5hE4mDZ6odQA - PK0QWK8VxzZL4zubTbW0kL6tq9PAhLP83BWICYwRUFAv5HDstwquSlPiNsQFboB1 - Eo03RvJLDDgcSR+sgwIDAQABo4ICHDCCAhgwHQYDVR0OBBYEFAqwqjhWR3sWfb6r - k5a8VN2F++0sMB8GA1UdIwQYMBaAFEl0uwxeunr+AlTve6DGlcYJgHCWMBIGA1Ud - EwEB/wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADAOBgNVHQ8BAf8EBAMCAYYwZgYD - VR0gBF8wXTALBglghkgBZQIBCwUwCwYJYIZIAWUCAQsJMAsGCWCGSAFlAgELETAL - BglghkgBZQIBCxIwCwYJYIZIAWUCAQsTMAwGCmCGSAFlAwIBAxowDAYKYIZIAWUD - AgEDGzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9E - T0RST09UQ0EyLmNybDCCAQEGCCsGAQUFBwEBBIH0MIHxMDoGCCsGAQUFBzAChi5o - dHRwOi8vY3JsLmRpc2EubWlsL2lzc3VlZHRvL0RPRFJPT1RDQTJfSVQucDdjMCAG - CCsGAQUFBzABhhRodHRwOi8vb2NzcC5kaXNhLm1pbDCBkAYIKwYBBQUHMAKGgYNs - ZGFwOi8vY3JsLmdkcy5kaXNhLm1pbC9jbiUzZERvRCUyMFJvb3QlMjBDQSUyMDIl - MmNvdSUzZFBLSSUyY291JTNkRG9EJTJjbyUzZFUuUy4lMjBHb3Zlcm5tZW50JTJj - YyUzZFVTP2Nyb3NzQ2VydGlmaWNhdGVQYWlyO2JpbmFyeTANBgkqhkiG9w0BAQUF - AAOCAQEAD72PR/+5yb1D5c6+tfM5y0UWWaPftlIkPAlVS9m/lXq9dtngMIfNSqmj - LZ7ZKATGlq4BFIDQJVbxWANV79KoIlKrge8A/q/HSdKMIC6kcYH3JssOpW3VQXd7 - LTO7m7N8nD89/8LuefKJChCMkHRdNGdwvgL+gEYZB859L5aoxBPQ758psTSpuYyl - iTSzjD5H+GaMkdHuq8HqcYXJX7Cp7tsA1DAqQs5XYxAiMKichkESXb5QfBP66yhz - X3IziV9/DWikPf0WJugKk/57H4aBgCe+Z3GGG33Hb7epcQHGY7NzfQFrMyLteYmK - DuZyAnM3P8sxge2k+wtqO1KEukz3jg== - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD CA-32 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - -----BEGIN CERTIFICATE----- - MIIFTDCCBDSgAwIBAgICA6EwDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDIwHhcNMTMwMjA0MjA0NDA1WhcN - MTkwMjA0MjA0NDA1WjBXMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BLSTESMBAGA1UEAxMJRE9E - IENBLTMyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs+KVHZM2LSWl - Dv146e/qk9E6ydhXvRnf0cei0ejZ/dKOFajdvT5k9Lb+nAPfS7Blt6sEGDIZbBMB - UtHmtchBEre+O8tNQBCIyp62/TV3bSb2ZK0RhwypJXpYn7C9mPaTXxvv77KXrfgV - 59zmoGp1DVHfVR1oQVJJLsecaFdWR4/e9lIugW9WvAaJEpSfI70/gceGAnUwXjOh - 3OETu/15VgE8Shn0LOuQZGTX6AovUYbVCJuE+/npi0LKZdKQBxyCl4xEI1cGLHVp - KHCy7T5M1eOWdxX9upXPW5ZpAnfWgNmPhynj5wV2r8qNEmA0cseznThuTJYynpA1 - rXWL0WJACQIDAQABo4ICHDCCAhgwHQYDVR0OBBYEFC/Kk1MDrG919Xb6vv6O6hCL - t+eQMB8GA1UdIwQYMBaAFEl0uwxeunr+AlTve6DGlcYJgHCWMBIGA1UdEwEB/wQI - MAYBAf8CAQAwDAYDVR0kBAUwA4ABADAOBgNVHQ8BAf8EBAMCAYYwZgYDVR0gBF8w - XTALBglghkgBZQIBCwUwCwYJYIZIAWUCAQsJMAsGCWCGSAFlAgELETALBglghkgB - ZQIBCxIwCwYJYIZIAWUCAQsTMAwGCmCGSAFlAwIBAxowDAYKYIZIAWUDAgEDGzA3 - BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9ET0RST09U - Q0EyLmNybDCCAQEGCCsGAQUFBwEBBIH0MIHxMDoGCCsGAQUFBzAChi5odHRwOi8v - Y3JsLmRpc2EubWlsL2lzc3VlZHRvL0RPRFJPT1RDQTJfSVQucDdjMCAGCCsGAQUF - BzABhhRodHRwOi8vb2NzcC5kaXNhLm1pbDCBkAYIKwYBBQUHMAKGgYNsZGFwOi8v - Y3JsLmdkcy5kaXNhLm1pbC9jbiUzZERvRCUyMFJvb3QlMjBDQSUyMDIlMmNvdSUz - ZFBLSSUyY291JTNkRG9EJTJjbyUzZFUuUy4lMjBHb3Zlcm5tZW50JTJjYyUzZFVT - P2Nyb3NzQ2VydGlmaWNhdGVQYWlyO2JpbmFyeTANBgkqhkiG9w0BAQUFAAOCAQEA - MI3VVmO9mQaLTbbSDgO5xoTSm3dBGojS/8Pa4uZnYb3Zeu04OV6rC1g0+droYnmv - OXLzSqfjTjkQzenSCOrUnpqnNTWTkwJZ4kwAHPP8ayFTSoxh52HL0EYL0T+cafXv - UIrwQLMrVloda2JZBbOPJxgFCkNbAu/dUl5bwKkcVuOVbJdPAYNWcl3XfVHjWlQu - uJj9ck4lj4sW0bDhM+OSfBBVMyRmrw8zBlNIA4eftGR0tdI9InK30Y43ERM5357n - 0AwLilkRMmX/9rlGvT82nqeUAFfwwBnhLNxM9y9MkB1D764I43OeOr+Z7CK5B1iu - 2TVSS1G7gTaPn24hCqaOhw== - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD EMAIL CA-31 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - -----BEGIN CERTIFICATE----- - MIIFUjCCBDqgAwIBAgICA58wDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDIwHhcNMTMwMTE2MTQ1MjQzWhcN - MTkwMTE2MTQ1MjQzWjBdMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BLSTEYMBYGA1UEAxMPRE9E - IEVNQUlMIENBLTMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6K4C - LEBMOlLoi3OStHfnOEvA8KpKGFzH9zXDSvDwlnell74n78REIYDqFjS3MNFEOH8q - zgTGkWWpblB8yE7+vcC1SxbkOFIV27O391M98rEH25FmXcG38ndmxFGaY5QRSwId - DUt8swBHB3kY+nizkx/Udm2ZBMUeNkb8BjQL42hvHnyfLM9huEv/tN8Gn6BflF7r - Nf8JXTVAB/Kd7ZYJ2Xbq/m4x/sv0ResweEhobKEpPoZ9k0FK6ucMTOWRUCqlQ2a8 - IsD8Gyzk8y9iHgTUIb+sHyZ3NdAdvOK7RsLy6+QUrviza7P6cTiwcSnt0Ysb1wIb - 3srsfu6h3Eil8T6UqQIDAQABo4ICHDCCAhgwHQYDVR0OBBYEFIbxW2hv3TDzlIJo - 1Ez3RB24ymiBMB8GA1UdIwQYMBaAFEl0uwxeunr+AlTve6DGlcYJgHCWMBIGA1Ud - EwEB/wQIMAYBAf8CAQAwDAYDVR0kBAUwA4ABADAOBgNVHQ8BAf8EBAMCAYYwZgYD - VR0gBF8wXTALBglghkgBZQIBCwUwCwYJYIZIAWUCAQsJMAsGCWCGSAFlAgELETAL - BglghkgBZQIBCxIwCwYJYIZIAWUCAQsTMAwGCmCGSAFlAwIBAxowDAYKYIZIAWUD - AgEDGzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9E - T0RST09UQ0EyLmNybDCCAQEGCCsGAQUFBwEBBIH0MIHxMDoGCCsGAQUFBzAChi5o - dHRwOi8vY3JsLmRpc2EubWlsL2lzc3VlZHRvL0RPRFJPT1RDQTJfSVQucDdjMCAG - CCsGAQUFBzABhhRodHRwOi8vb2NzcC5kaXNhLm1pbDCBkAYIKwYBBQUHMAKGgYNs - ZGFwOi8vY3JsLmdkcy5kaXNhLm1pbC9jbiUzZERvRCUyMFJvb3QlMjBDQSUyMDIl - MmNvdSUzZFBLSSUyY291JTNkRG9EJTJjbyUzZFUuUy4lMjBHb3Zlcm5tZW50JTJj - YyUzZFVTP2Nyb3NzQ2VydGlmaWNhdGVQYWlyO2JpbmFyeTANBgkqhkiG9w0BAQUF - AAOCAQEAWTKtqsP435xknHEJNMG9vGMAHi3b7anICOO5GOSvyq4Uwd27+XODg1eO - lMmgqgMHzmecteUXWT8ouBc22rqNw5YRAWpQ1gbaaKRK0guFfM2I3/9ed+b1pEiR - 0E6iZ2r4aO+qF0Xv2JYK3c/wPoe2v4g/01S+PhLOofkLbzLRVL+EWzWg2wdktavp - eR7i8qp0cueREvfHu27u5XSQECSLt+fNnIWQR+Tib38gvSy7g5YjTahM2H4uXhUp - uCV9VzULLRVUjKnc4OU3nahPIJWDK8USNj2oc+FOiEmlubv6CUooWjO55JJ5W3v4 - pU/zyTTNmYywumB+n4Q+5jz6flrr5g== - -----END CERTIFICATE----- - - subject=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DOD CA-31 - issuer=/C=US/O=U.S. Government/OU=DoD/OU=PKI/CN=DoD Root CA 2 - -----BEGIN CERTIFICATE----- - MIIFTDCCBDSgAwIBAgICA50wDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCVVMx - GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL - EwNQS0kxFjAUBgNVBAMTDURvRCBSb290IENBIDIwHhcNMTMwMTE2MTQ0OTMwWhcN - MTkwMTE2MTQ0OTMwWjBXMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zl - cm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BLSTESMBAGA1UEAxMJRE9E - IENBLTMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxicQL5CWONnf - 5l8/uon7ZoLrtqXt8FaQFkDnbKKweWZZ15hiMdEzIlPjHlykVmamTVb7w+JCEqv5 - wEpLQO+RE4Y5MFHWbo4nt0GJKQHuWEZzBHFEXGlDPjLmZN+za5kscKLQPk3YWBJt - RfA9k1S+3+L7zxH//IoBN++nLrpADGo+HOQKMoBpvSI57Et2ybFakzwhhDjdcxOC - +V0MgQqpslN02QuOwOiXuz1fE4y1uTvs9rudjiD2a7ydFDLcfrniY7BqwYC5FvyR - 76yyCZ9SR1gTXmJ+mhKGW8UgH+GOZgB2U+znIokhTF+56b6gUpMOpsjezLeCrSJt - i9AwUzZVVwIDAQABo4ICHDCCAhgwHQYDVR0OBBYEFETjRqNB7mCxXqeTJfSgU+63 - Sb67MB8GA1UdIwQYMBaAFEl0uwxeunr+AlTve6DGlcYJgHCWMBIGA1UdEwEB/wQI - MAYBAf8CAQAwDAYDVR0kBAUwA4ABADAOBgNVHQ8BAf8EBAMCAYYwZgYDVR0gBF8w - XTALBglghkgBZQIBCwUwCwYJYIZIAWUCAQsJMAsGCWCGSAFlAgELETALBglghkgB - ZQIBCxIwCwYJYIZIAWUCAQsTMAwGCmCGSAFlAwIBAxowDAYKYIZIAWUDAgEDGzA3 - BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmRpc2EubWlsL2NybC9ET0RST09U - Q0EyLmNybDCCAQEGCCsGAQUFBwEBBIH0MIHxMDoGCCsGAQUFBzAChi5odHRwOi8v - Y3JsLmRpc2EubWlsL2lzc3VlZHRvL0RPRFJPT1RDQTJfSVQucDdjMCAGCCsGAQUF - BzABhhRodHRwOi8vb2NzcC5kaXNhLm1pbDCBkAYIKwYBBQUHMAKGgYNsZGFwOi8v - Y3JsLmdkcy5kaXNhLm1pbC9jbiUzZERvRCUyMFJvb3QlMjBDQSUyMDIlMmNvdSUz - ZFBLSSUyY291JTNkRG9EJTJjbyUzZFUuUy4lMjBHb3Zlcm5tZW50JTJjYyUzZFVT - P2Nyb3NzQ2VydGlmaWNhdGVQYWlyO2JpbmFyeTANBgkqhkiG9w0BAQUFAAOCAQEA - R1FS3PSgc5pC5wvsI5GNJXW0RII0qvlGdVHD9g745+MvtCDD76FlNOCdh8HmLmLw - J+jrxc81ldJAgIuSCbamG9USZDHbtdQO3wqKtlb1vHaSkxl8v2V9coHYZHs5NIp2 - WMwdQ/cHzxyDA3O+OBfbdK1pCRF87djWAo1mPatryjPbx3pmxd6nJ0gPZhLuaCTA - 75HqBhkqUFgT4CL8DrEk++uOQgIPd4gVi+by9VO3fOBVmxPWtnDKc3DjUyXBKB57 - xCxJbpDbqstbAxvCh4f1q75RcXNtJmZ7mx0X4O3jwN4dJ7HtDTRGPt0uXvSCcNrR - kxt53dZK5875P3MfzormFg== - -----END CERTIFICATE----- - -kind: ConfigMap -metadata: - name: nginx-client-ca-bundle - namespace: atat diff --git a/deploy/minikube/secrets.yml b/deploy/minikube/secrets.yml deleted file mode 100644 index d5aa9807..00000000 --- a/deploy/minikube/secrets.yml +++ /dev/null @@ -1,26 +0,0 @@ -apiVersion: v1 -data: - override.ini: W2RlZmF1bHRdCkVOVklST05NRU5UID0gZGV2Cg== -kind: Secret -metadata: - name: atst-config-ini - namespace: atat -type: Opaque ---- -apiVersion: v1 -data: - htpasswd: bWluaWt1YmU6JGFwcjEkRFNrbXhtNGYkcEVjTzEyYUpWcTcyREFSL0I2cmlvLgo= -kind: Secret -metadata: - name: atst-nginx-htpasswd - namespace: atat -type: Opaque ---- -apiVersion: v1 -data: - client-ca-bundle.pem: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVsVENDQTMyZ0F3SUJBZ0lKQU41cURraStWbGZQTUEwR0NTcUdTSWIzRFFFQkJRVUFNSUdOTVFzd0NRWUQKVlFRR0V3SlZVekVWTUJNR0ExVUVDQk1NVUdWdWJuTjViSFpoYm1saE1SVXdFd1lEVlFRSEV3eFFhR2xzWVdSbApiSEJvYVdFeEVEQU9CZ05WQkFvVEIwWmhkWGhFYjBReEN6QUpCZ05WQkFzVEFsQlhNUkV3RHdZRFZRUURFd2hHCllYVjRJRVJ2UkRFZU1Cd0dDU3FHU0liM0RRRUpBUllQWm1GMWVHUnZaRUJrYjJRdVkyOXRNQjRYRFRFNE1EWXkKTURJd016ZzBOMW9YRFRFNU1EWXlNREl3TXpnME4xb3dnWTB4Q3pBSkJnTlZCQVlUQWxWVE1SVXdFd1lEVlFRSQpFd3hRWlc1dWMzbHNkbUZ1YVdFeEZUQVRCZ05WQkFjVERGQm9hV3hoWkdWc2NHaHBZVEVRTUE0R0ExVUVDaE1IClJtRjFlRVJ2UkRFTE1Ba0dBMVVFQ3hNQ1VGY3hFVEFQQmdOVkJBTVRDRVpoZFhnZ1JHOUVNUjR3SEFZSktvWkkKaHZjTkFRa0JGZzltWVhWNFpHOWtRR1J2WkM1amIyMHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBdwpnZ0VLQW9JQkFRRHlRVUZjdVErWUtPRUp0djRYaktPVHBPTHA4SWRic2FGd1U4WWdlbk1kdkFjMU9OWlJMLzJvCmphQ1p4K2tCMlFTQ1ZIMmphTFVRLzJpNHV6NHJFMjFOZ3B4K0VIYTFoZ0RRQU5sZTNkNUNXcm4yUTEwL3BkUGUKckpIWWtNU2laM2NOV2ZGUEJmSER0SnJMbFJVd0prZ3krbFVTTG5PYWlwbUJaTVlYYlY4L3FVaDY5bldKUU5YaQpBdm1TVXc4andVUGZUcnBRVnpmdGtPWXorMEhWSnl2S2lqVHNqMUxhUFpUUjNEOE9oYkZudlpXSWxoSVVqSlpPCmphcC94UTNZRU9jTkYrZ2Z4OGhEUUcyU25sdFdnZWNQc2dpQlJYbVpLMklxRHYzOURFMkROaXVrRWNsWkxoYk4KU3BUaWJOWndrVnpjVFNSVjJtU09IS1hxVGNIMHdUdnBBZ01CQUFHamdmVXdnZkl3SFFZRFZSME9CQllFRkFvLwo2YXVIY0tNSzFJdFRFbGcxS2s0TXlvQjVNSUhDQmdOVkhTTUVnYm93Z2JlQUZBby82YXVIY0tNSzFJdFRFbGcxCktrNE15b0I1b1lHVHBJR1FNSUdOTVFzd0NRWURWUVFHRXdKVlV6RVZNQk1HQTFVRUNCTU1VR1Z1Ym5ONWJIWmgKYm1saE1SVXdFd1lEVlFRSEV3eFFhR2xzWVdSbGJIQm9hV0V4RURBT0JnTlZCQW9UQjBaaGRYaEViMFF4Q3pBSgpCZ05WQkFzVEFsQlhNUkV3RHdZRFZRUURFd2hHWVhWNElFUnZSREVlTUJ3R0NTcUdTSWIzRFFFSkFSWVBabUYxCmVHUnZaRUJrYjJRdVkyOXRnZ2tBM21vT1NMNVdWODh3REFZRFZSMFRCQVV3QXdFQi96QU5CZ2txaGtpRzl3MEIKQVFVRkFBT0NBUUVBcDRmVlllU0tZSklDQlF0MzdOT0Y2cVorZHY4R0JESStvWnk3dkMrVmNqaVJhT0RraXo5dwpJTzVkQlp4eC9sZEg1c0QyNE9jMlNIKzQ4UzZVakUvRDVrRHBNL25JZGRmVmZMMmYyMjJzRTE0UnNxZ3JobWJHCnFSYUVCOE5YV2lTUXlLT0tYNjN2OHNjaW9VcWI5aEZZK2d0d2I4SERGaU9aRngrNjdML05hWFNoNlZBOEJiTGoKbzU1RWFmalRncitZYWQ3U3JaSTVmNlEyaVErdXVIY0pzZjdmRWUzS3RzNVV3dDVLWEJCZk14ZWFTeVFSeE5YKwpKQkJteTZNYXhkZFB0dXMzTUgrZUlnSTJXcDJyb2ZIL1B0R25Tb2l6Qmo1SVpYQmtjMTh4MURHNXBBSkw0MjA1CkVLUW9pY3NhZkUyN1hCdzQ1ZEszY1JCTFhQV3Q4SnJDQmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCnN1YmplY3Q9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1ET0QgU1cgQ0EtNTgKaXNzdWVyPS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RG9EIFJvb3QgQ0EgNQotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJREhUQ0NBcU9nQXdJQkFnSUJFVEFLQmdncWhrak9QUVFEQXpCYk1Rc3dDUVlEVlFRR0V3SlZVekVZTUJZRwpBMVVFQ2hNUFZTNVRMaUJIYjNabGNtNXRaVzUwTVF3d0NnWURWUVFMRXdORWIwUXhEREFLQmdOVkJBc1RBMUJMClNURVdNQlFHQTFVRUF4TU5SRzlFSUZKdmIzUWdRMEVnTlRBZUZ3MHhOakV5TVRNeE5EUXdOVEphRncweU1qRXkKTVRJeE5EUXdOVEphTUZveEN6QUpCZ05WQkFZVEFsVlRNUmd3RmdZRFZRUUtFdzlWTGxNdUlFZHZkbVZ5Ym0xbApiblF4RERBS0JnTlZCQXNUQTBSdlJERU1NQW9HQTFVRUN4TURVRXRKTVJVd0V3WURWUVFERXd4RVQwUWdVMWNnClEwRXROVGd3ZGpBUUJnY3Foa2pPUFFJQkJnVXJnUVFBSWdOaUFBU2k2ejNsTFN3YXFRNkZQUXJNeGxJVzJWQmYKeFl6QTdmK3ozcEJiMkF6TlZuTVZzUk1iTWUyZjNMQ0xhQUsza1ZIYmYyTUZ2ZDAwVUNRVGFKTm9CTHJzTDdwegpTQTNqSHRCZ2x6T3dJNTc1NVZOWnlkQzJhSzVPencrYTJ5TVFyditqZ2dFNk1JSUJOakFmQmdOVkhTTUVHREFXCmdCU0d3QlZDKzNGMjNENHRFVnNoRUVRMXlzSGNGREFkQmdOVkhRNEVGZ1FVSkZVYUM1QWhMTllqcW9qU251bTQKcmFLQWZkd3dEZ1lEVlIwUEFRSC9CQVFEQWdFR01EMEdBMVVkSUFRMk1EUXdDd1lKWUlaSUFXVUNBUXNtTUFzRwpDV0NHU0FGbEFnRUxLVEFMQmdsZ2hrZ0JaUUlCQ3l3d0N3WUpZSVpJQVdVQ0FRczdNQklHQTFVZEV3RUIvd1FJCk1BWUJBZjhDQVFBd0RBWURWUjBrQkFVd0E0QUJBREEzQmdOVkhSOEVNREF1TUN5Z0txQW9oaVpvZEhSd09pOHYKWTNKc0xtUnBjMkV1Yldsc0wyTnliQzlFVDBSU1QwOVVRMEUxTG1OeWJEQktCZ2dyQmdFRkJRY0JBUVErTUR3dwpPZ1lJS3dZQkJRVUhNQUtHTG1oMGRIQTZMeTlqY213dVpHbHpZUzV0YVd3dmFYTnpkV1ZrZEc4dlJFOUVVazlQClZFTkJOVjlKVkM1d04yTXdDZ1lJS29aSXpqMEVBd01EYUFBd1pRSXhBS2lsMXFvelhkejdFN2tBT2hhWjdyT0cKODEvZFZSNW8yS0dQRmF2cnRvM2c5ZUJFMVNib2ltaUtLaWl2ZU5uaHRRSXdMTkFhZVp1a3BqOXNEczJlMTZ2dQpzNHJScVMzdHVhbnNkSDFGeThqOUluSm9qQkxhWWVKUjYwajBBY2h5cXZhRwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIFNXIENBLTU3Cmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDUKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURIVENDQXFPZ0F3SUJBZ0lCRURBS0JnZ3Foa2pPUFFRREF6QmJNUXN3Q1FZRFZRUUdFd0pWVXpFWU1CWUcKQTFVRUNoTVBWUzVUTGlCSGIzWmxjbTV0Wlc1ME1Rd3dDZ1lEVlFRTEV3TkViMFF4RERBS0JnTlZCQXNUQTFCTApTVEVXTUJRR0ExVUVBeE1OUkc5RUlGSnZiM1FnUTBFZ05UQWVGdzB4TmpFeU1UTXhORE01TkRsYUZ3MHlNakV5Ck1USXhORE01TkRsYU1Gb3hDekFKQmdOVkJBWVRBbFZUTVJnd0ZnWURWUVFLRXc5VkxsTXVJRWR2ZG1WeWJtMWwKYm5ReEREQUtCZ05WQkFzVEEwUnZSREVNTUFvR0ExVUVDeE1EVUV0Sk1SVXdFd1lEVlFRREV3eEVUMFFnVTFjZwpRMEV0TlRjd2RqQVFCZ2NxaGtqT1BRSUJCZ1VyZ1FRQUlnTmlBQVJuVG5saFgxWEF5WnhFd3JHUmU2Q3B4TnUvCi9FRGczTmpiSElFa25ocTVzaDdnQ0V3dHB5MytCMzdzczY0bVdxODhKVFdydGpkbW1zdVdEUWdVNlk2eDZRVU0KOE5uVS9pRUlMQWRIK2Q4WUMvT0NveHhVZHoxM0hoa2RsdDFKQi82amdnRTZNSUlCTmpBZkJnTlZIU01FR0RBVwpnQlNHd0JWQyszRjIzRDR0RVZzaEVFUTF5c0hjRkRBZEJnTlZIUTRFRmdRVVdoSXByRGZVamo3MWpWTzFJdkE2CkJBblJvK3N3RGdZRFZSMFBBUUgvQkFRREFnRUdNRDBHQTFVZElBUTJNRFF3Q3dZSllJWklBV1VDQVFzbU1Bc0cKQ1dDR1NBRmxBZ0VMS1RBTEJnbGdoa2dCWlFJQkN5d3dDd1lKWUlaSUFXVUNBUXM3TUJJR0ExVWRFd0VCL3dRSQpNQVlCQWY4Q0FRQXdEQVlEVlIwa0JBVXdBNEFCQURBM0JnTlZIUjhFTURBdU1DeWdLcUFvaGlab2RIUndPaTh2ClkzSnNMbVJwYzJFdWJXbHNMMk55YkM5RVQwUlNUMDlVUTBFMUxtTnliREJLQmdnckJnRUZCUWNCQVFRK01Ed3cKT2dZSUt3WUJCUVVITUFLR0xtaDBkSEE2THk5amNtd3VaR2x6WVM1dGFXd3ZhWE56ZFdWa2RHOHZSRTlFVWs5UApWRU5CTlY5SlZDNXdOMk13Q2dZSUtvWkl6ajBFQXdNRGFBQXdaUUl4QUowcy90WENtSmFFbU5qaDk2cWczUFFSCkppZFBhcnNtNkRSSU9QZ0wydW1vV3g5UVFQNW1DSGViUlhrL0tCT3Zwd0l3VUV3Ny9JeHJZaTViRitrWk5udzAKcWFuc0kzR1pCOTA4MEhGZGUyL293aElXWjVHTURWOG1LS2hvTlZuM2tZL0QKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoKc3ViamVjdD0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDUKaXNzdWVyPS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RG9EIFJvb3QgQ0EgNQotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ0pEQ0NBYXFnQXdJQkFnSUJEekFLQmdncWhrak9QUVFEQXpCYk1Rc3dDUVlEVlFRR0V3SlZVekVZTUJZRwpBMVVFQ2hNUFZTNVRMaUJIYjNabGNtNXRaVzUwTVF3d0NnWURWUVFMRXdORWIwUXhEREFLQmdOVkJBc1RBMUJMClNURVdNQlFHQTFVRUF4TU5SRzlFSUZKdmIzUWdRMEVnTlRBZUZ3MHhOakEyTVRReE56RTNNamRhRncwME1UQTIKTVRReE56RTNNamRhTUZzeEN6QUpCZ05WQkFZVEFsVlRNUmd3RmdZRFZRUUtFdzlWTGxNdUlFZHZkbVZ5Ym0xbApiblF4RERBS0JnTlZCQXNUQTBSdlJERU1NQW9HQTFVRUN4TURVRXRKTVJZd0ZBWURWUVFERXcxRWIwUWdVbTl2CmRDQkRRU0ExTUhZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUNJRFlnQUVObUxlQzA3QXg5Y3BSVHAvSEpubUtpRjIKc1FEZGpFZi93TEcwK3M0NlRsTDdwKzAyTFJ3ZUhKQ05sNm9ycHVMVGMzTjhYQnpRWi9RS0tkT1FoT3RSNWZGZQpITURTaG9URmJkRWtTUTdzRjRua2FNamVHbHdhQnRBNEdUTXBBUnFCbzBJd1FEQWRCZ05WSFE0RUZnUVVoc0FWClF2dHhkdHcrTFJGYklSQkVOY3JCM0JRd0RnWURWUjBQQVFIL0JBUURBZ0VHTUE4R0ExVWRFd0VCL3dRRk1BTUIKQWY4d0NnWUlLb1pJemowRUF3TURhQUF3WlFJd1FRYmszdDVpTkozZnVLb1cyVzJpT0I4NUlsZkpjSVFma3c5WApmZ1V2cFVzenpSWHFWOVhTS3grYmpYek9hcmJNQWpFQXQ0SFM0VHVUenhGazNBc3ZGOUp0MWRnRjVGQnlZbVhjCnBEektZYVVHbXNuNzdjUXd5WHVKNEtXK1kxWG1uQkhqCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCnN1YmplY3Q9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1ET0QgU1cgQ0EtNTYKaXNzdWVyPS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RG9EIFJvb3QgQ0EgNAotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQzR6Q0NBb2lnQXdJQkFnSUJTVEFNQmdncWhrak9QUVFEQWdVQU1Gc3hDekFKQmdOVkJBWVRBbFZUTVJndwpGZ1lEVlFRS0V3OVZMbE11SUVkdmRtVnlibTFsYm5ReEREQUtCZ05WQkFzVEEwUnZSREVNTUFvR0ExVUVDeE1EClVFdEpNUll3RkFZRFZRUURFdzFFYjBRZ1VtOXZkQ0JEUVNBME1CNFhEVEUyTVRFeU1qRTFORGd5TWxvWERUSXkKTVRFeU16RTFORGd5TWxvd1dqRUxNQWtHQTFVRUJoTUNWVk14R0RBV0JnTlZCQW9NRDFVdVV5NGdSMjkyWlhKdQpiV1Z1ZERFTU1Bb0dBMVVFQ3d3RFJHOUVNUXd3Q2dZRFZRUUxEQU5RUzBreEZUQVRCZ05WQkFNTURFUlBSQ0JUClZ5QkRRUzAxTmpCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQko4UDZ3cWZidTg1dFNvNmlpVmIKUXB5VHpWZkRiRWNVdW9qc25aeGEyWnZpSTU5SjlmT0I2TGtTeHZvYWNsY0lERzJDUUhiL2NURlJsWW5tbnkyOApxaGFqZ2dFNk1JSUJOakFmQmdOVkhTTUVHREFXZ0JTOXdibHJUZlFkN0RDUXYySnp3SVF6OG5Fa2hUQWRCZ05WCkhRNEVGZ1FVdlBMMFVaMHF5K09kRUZaakJYWld5ZDI2MUZzd0RnWURWUjBQQVFIL0JBUURBZ0dHTUQwR0ExVWQKSUFRMk1EUXdDd1lKWUlaSUFXVUNBUXNsTUFzR0NXQ0dTQUZsQWdFTEtEQUxCZ2xnaGtnQlpRSUJDeXN3Q3dZSgpZSVpJQVdVQ0FRczdNQklHQTFVZEV3RUIvd1FJTUFZQkFmOENBUUF3REFZRFZSMGtCQVV3QTRBQkFEQTNCZ05WCkhSOEVNREF1TUN5Z0txQW9oaVpvZEhSd09pOHZZM0pzTG1ScGMyRXViV2xzTDJOeWJDOUVUMFJTVDA5VVEwRTAKTG1OeWJEQktCZ2dyQmdFRkJRY0JBUVErTUR3d09nWUlLd1lCQlFVSE1BS0dMbWgwZEhBNkx5OWpjbXd1WkdsegpZUzV0YVd3dmFYTnpkV1ZrZEc4dlJFOUVVazlQVkVOQk5GOUpWQzV3TjJNd0RBWUlLb1pJemowRUF3SUZBQU5ICkFEQkVBaUJqZ1IzRnp3dXFjS2ZtSUF5eWdoQzg1K0M0V1pXTGxMVi9wbkErS0YxNmlnSWdkVDNXOFlQSEVNR2gKV1BwcVZlQlIxeEpmRkJsNEgrYThPeG1KOFJUWmRVUT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoKc3ViamVjdD0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURPRCBTVyBDQS01NQppc3N1ZXI9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSA0Ci0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlDNVRDQ0FvaWdBd0lCQWdJQlNEQU1CZ2dxaGtqT1BRUURBZ1VBTUZzeEN6QUpCZ05WQkFZVEFsVlRNUmd3CkZnWURWUVFLRXc5VkxsTXVJRWR2ZG1WeWJtMWxiblF4RERBS0JnTlZCQXNUQTBSdlJERU1NQW9HQTFVRUN4TUQKVUV0Sk1SWXdGQVlEVlFRREV3MUViMFFnVW05dmRDQkRRU0EwTUI0WERURTJNVEV5TWpFMU5EWTBObG9YRFRJeQpNVEV5TXpFMU5EWTBObG93V2pFTE1Ba0dBMVVFQmhNQ1ZWTXhHREFXQmdOVkJBb01EMVV1VXk0Z1IyOTJaWEp1CmJXVnVkREVNTUFvR0ExVUVDd3dEUkc5RU1Rd3dDZ1lEVlFRTERBTlFTMGt4RlRBVEJnTlZCQU1NREVSUFJDQlQKVnlCRFFTMDFOVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCRG16aDJIRmpVaEdFYUt4WFU1RQpqVlU2NmZNSmJONTJ0V2s0UXNCSVU4ckNjdUtkenlvWTNEVFVMUnY1V2RGNG1qUEhCVGZ5Y3VXT214enRyVTY0Ck4rYWpnZ0U2TUlJQk5qQWZCZ05WSFNNRUdEQVdnQlM5d2JsclRmUWQ3RENRdjJKendJUXo4bkVraFRBZEJnTlYKSFE0RUZnUVVwVzlMSFpLMXk5MTMyYmE5U0FhK0JrZ0pOQmd3RGdZRFZSMFBBUUgvQkFRREFnR0dNRDBHQTFVZApJQVEyTURRd0N3WUpZSVpJQVdVQ0FRc2xNQXNHQ1dDR1NBRmxBZ0VMS0RBTEJnbGdoa2dCWlFJQkN5c3dDd1lKCllJWklBV1VDQVFzN01CSUdBMVVkRXdFQi93UUlNQVlCQWY4Q0FRQXdEQVlEVlIwa0JBVXdBNEFCQURBM0JnTlYKSFI4RU1EQXVNQ3lnS3FBb2hpWm9kSFJ3T2k4dlkzSnNMbVJwYzJFdWJXbHNMMk55YkM5RVQwUlNUMDlVUTBFMApMbU55YkRCS0JnZ3JCZ0VGQlFjQkFRUStNRHd3T2dZSUt3WUJCUVVITUFLR0xtaDBkSEE2THk5amNtd3VaR2x6CllTNXRhV3d2YVhOemRXVmtkRzh2UkU5RVVrOVBWRU5CTkY5SlZDNXdOMk13REFZSUtvWkl6ajBFQXdJRkFBTkoKQURCR0FpRUE4elFBK1QzYW5hTTBiMVFzWVNFdnU4WTk1UzAzR0d5OGZHMkhvaTY2MUZJQ0lRQ0RDYndRWkQxWgo4TmhuamJPQkRFb25xekZFZGlYZ0dpcTI2c3MvMWVqRGF3PT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoKc3ViamVjdD0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURPRCBJRCBTVyBDQS00OAppc3N1ZXI9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSA0Ci0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlDMmpDQ0FuNmdBd0lCQWdJQkNqQU1CZ2dxaGtqT1BRUURBZ1VBTUZzeEN6QUpCZ05WQkFZVEFsVlRNUmd3CkZnWURWUVFLRXc5VkxsTXVJRWR2ZG1WeWJtMWxiblF4RERBS0JnTlZCQXNUQTBSdlJERU1NQW9HQTFVRUN4TUQKVUV0Sk1SWXdGQVlEVlFRREV3MUViMFFnVW05dmRDQkRRU0EwTUI0WERURTJNRFF4TWpFek1UazBPVm9YRFRJeQpNRFF4TXpFek1UazBPVm93WFRFTE1Ba0dBMVVFQmhNQ1ZWTXhHREFXQmdOVkJBb1REMVV1VXk0Z1IyOTJaWEp1CmJXVnVkREVNTUFvR0ExVUVDeE1EUkc5RU1Rd3dDZ1lEVlFRTEV3TlFTMGt4R0RBV0JnTlZCQU1URDBSUFJDQkoKUkNCVFZ5QkRRUzAwT0RCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkhQM2dNSXJNNVhIcnRQZwpOcDdCbTQyZXFKaWhlSTBmTU5lOVdESmtGZEpiSmVUcmR4VXRZUUpmYjRuWW1MbG5HRzdCdzNSTEhoTGhTMHZpCk1PMGluYzJqZ2dFdE1JSUJLVEFmQmdOVkhTTUVHREFXZ0JTOXdibHJUZlFkN0RDUXYySnp3SVF6OG5Fa2hUQWQKQmdOVkhRNEVGZ1FVdHJhWGFuRFR1ellBdWVsRmRDOG5sU3J5V1Frd0RnWURWUjBQQVFIL0JBUURBZ0dHTURBRwpBMVVkSUFRcE1DY3dDd1lKWUlaSUFXVUNBUXNvTUFzR0NXQ0dTQUZsQWdFTEt6QUxCZ2xnaGtnQlpRSUJDeVV3CkVnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFEQU1CZ05WSFNRRUJUQURnQUVBTURjR0ExVWRId1F3TUM0d0xLQXEKb0NpR0ptaDBkSEE2THk5amNtd3VaR2x6WVM1dGFXd3ZZM0pzTDBSUFJGSlBUMVJEUVRRdVkzSnNNRW9HQ0NzRwpBUVVGQndFQkJENHdQREE2QmdnckJnRUZCUWN3QW9ZdWFIUjBjRG92TDJOeWJDNWthWE5oTG0xcGJDOXBjM04xClpXUjBieTlFVDBSU1QwOVVRMEUwWDBsVUxuQTNZekFNQmdncWhrak9QUVFEQWdVQUEwZ0FNRVVDSVFDK2lHRzgKa2piVi9WTmNLbHh1dXVmelUwaFZhM25iWStBSDFHLzAxOUVWR2dJZ09CaW9PSmpMMkRFT3N3c3dvdzB6MFdheQpPK0RxNTJ5OUlJdDFMTmlFdVF3PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIElEIFNXIENBLTQ3Cmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDQKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMyekNDQW42Z0F3SUJBZ0lCQ1RBTUJnZ3Foa2pPUFFRREFnVUFNRnN4Q3pBSkJnTlZCQVlUQWxWVE1SZ3cKRmdZRFZRUUtFdzlWTGxNdUlFZHZkbVZ5Ym0xbGJuUXhEREFLQmdOVkJBc1RBMFJ2UkRFTU1Bb0dBMVVFQ3hNRApVRXRKTVJZd0ZBWURWUVFERXcxRWIwUWdVbTl2ZENCRFFTQTBNQjRYRFRFMk1EUXhNakV6TVRJME0xb1hEVEl5Ck1EUXhNekV6TVRJME0xb3dYVEVMTUFrR0ExVUVCaE1DVlZNeEdEQVdCZ05WQkFvVEQxVXVVeTRnUjI5MlpYSnUKYldWdWRERU1NQW9HQTFVRUN4TURSRzlFTVF3d0NnWURWUVFMRXdOUVMwa3hHREFXQmdOVkJBTVREMFJQUkNCSgpSQ0JUVnlCRFFTMDBOekJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCSVhZQTVHdHpqdWM4S0ljCmtnTXUzK21nQlBsZGZCa09yOWkrNHdoUXpZODRGREt2enNjNzhCYnVRaWNXRHNiSkRYTjQ1TjVBQ29Ba3dySXoKTVAxTlJaeWpnZ0V0TUlJQktUQWZCZ05WSFNNRUdEQVdnQlM5d2JsclRmUWQ3RENRdjJKendJUXo4bkVraFRBZApCZ05WSFE0RUZnUVVvd0VNU3dHY0VCOG1hZG1PWEdjbnhkcXNObm93RGdZRFZSMFBBUUgvQkFRREFnR0dNREFHCkExVWRJQVFwTUNjd0N3WUpZSVpJQVdVQ0FRc29NQXNHQ1dDR1NBRmxBZ0VMS3pBTEJnbGdoa2dCWlFJQkN5VXcKRWdZRFZSMFRBUUgvQkFnd0JnRUIvd0lCQURBTUJnTlZIU1FFQlRBRGdBRUFNRGNHQTFVZEh3UXdNQzR3TEtBcQpvQ2lHSm1oMGRIQTZMeTlqY213dVpHbHpZUzV0YVd3dlkzSnNMMFJQUkZKUFQxUkRRVFF1WTNKc01Fb0dDQ3NHCkFRVUZCd0VCQkQ0d1BEQTZCZ2dyQmdFRkJRY3dBb1l1YUhSMGNEb3ZMMk55YkM1a2FYTmhMbTFwYkM5cGMzTjEKWldSMGJ5OUVUMFJTVDA5VVEwRTBYMGxVTG5BM1l6QU1CZ2dxaGtqT1BRUURBZ1VBQTBrQU1FWUNJUUNON2pKZQpoMEtHWjA1T1RDYnhaS2d2cVI3TjNoY280cVRYY0VUcG0xbVBtQUloQVBaV2NsQmY1NGxPQ0RRa3UwVUJ6OGdXCmxZZGVWWG1pdUt6N0R2ZUZ0aGlzCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCnN1YmplY3Q9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSA0Cmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDQKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUI2ekNDQVkrZ0F3SUJBZ0lCQVRBTUJnZ3Foa2pPUFFRREFnVUFNRnN4Q3pBSkJnTlZCQVlUQWxWVE1SZ3cKRmdZRFZRUUtFdzlWTGxNdUlFZHZkbVZ5Ym0xbGJuUXhEREFLQmdOVkJBc1RBMFJ2UkRFTU1Bb0dBMVVFQ3hNRApVRXRKTVJZd0ZBWURWUVFERXcxRWIwUWdVbTl2ZENCRFFTQTBNQjRYRFRFeU1EY3pNREU1TkRneU0xb1hEVE15Ck1EY3lOVEU1TkRneU0xb3dXekVMTUFrR0ExVUVCaE1DVlZNeEdEQVdCZ05WQkFvVEQxVXVVeTRnUjI5MlpYSnUKYldWdWRERU1NQW9HQTFVRUN4TURSRzlFTVF3d0NnWURWUVFMRXdOUVMwa3hGakFVQmdOVkJBTVREVVJ2UkNCUwpiMjkwSUVOQklEUXdXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CQndOQ0FBUjJ5TmhEeXc4SDBpd1BLdEE0CjhZTE5RbFhuM0IxYWdMY0lrVXRVMWsreVpvVTBsbzB1UHZUZ1NwRjh6TTJHbnhIZ1VxRm1nc2JMa0NQc1gxLzEKOER4Rm8wSXdRREFkQmdOVkhRNEVGZ1FVdmNHNWEwMzBIZXd3a0w5aWM4Q0VNL0p4SklVd0RnWURWUjBQQVFILwpCQVFEQWdHR01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RBWUlLb1pJemowRUF3SUZBQU5JQURCRkFpRUE2R0dLCjk5eXFDYVVIMGtTZWdnTmFSRk5IaENPWnoxelQza3BlMXJzMU5VWUNJSFlQdU1SOEZqVi8xQkx0aUQyQUVXdGsKQjB4RlpkOVRybDhCN2ZGRDB2VzMKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoKc3ViamVjdD0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURPRCBJRCBTVyBDQS00Ngppc3N1ZXI9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSAzCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFcmpDQ0E1YWdBd0lCQWdJQlpEQU5CZ2txaGtpRzl3MEJBUXNGQURCYk1Rc3dDUVlEVlFRR0V3SlZVekVZCk1CWUdBMVVFQ2hNUFZTNVRMaUJIYjNabGNtNXRaVzUwTVF3d0NnWURWUVFMRXdORWIwUXhEREFLQmdOVkJBc1QKQTFCTFNURVdNQlFHQTFVRUF4TU5SRzlFSUZKdmIzUWdRMEVnTXpBZUZ3MHhOakF6TURneE5ESXlNamRhRncweQpNakF6TURreE5ESXlNamRhTUYweEN6QUpCZ05WQkFZVEFsVlRNUmd3RmdZRFZRUUtFdzlWTGxNdUlFZHZkbVZ5CmJtMWxiblF4RERBS0JnTlZCQXNUQTBSdlJERU1NQW9HQTFVRUN4TURVRXRKTVJnd0ZnWURWUVFERXc5RVQwUWcKU1VRZ1UxY2dRMEV0TkRZd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURCOHQ3Twppekh0cUNMVUtYZE5jQU9ZbEpETnlOb3FXMjJaQjc1S2lVM0dKbmE1d3c0OTlTT25CYUVVNE92UlNNSTNGY0tTCmxaUnZKSkliTnBjVWJuNlgvNGNFSDZnNjRsQ0dTWGNtOG5sL3JVMVcwb25mN2wvZms4dGNhVlJHMGhQOWlUYmUKN2ZqbEo3aEVXd0tFWFNrN1hrci8zZTA5YnZLSUhWdGlDc1Y2Y09sTnNLNkg3SmJFaFJ3NHlQT2txZFh0cnBRWAptTmg5WTZPR3lhOTFJMXZ6WU8remNleHIyK01Pb0hGSnlBREJWRi8rTHJNV2RScVZJMEZsOHI4TlhLbkdYcEM3CnlQbnMyOGd6MWVnbXhKNU5zSnRROHA0V0hNUW5BNkozd1ByKzduYSs1TUt6TGdDSW9NeEQydklKMEZVMjhPREUKV3JBYjljbHFXcXYvSnRlL0FnTUJBQUdqZ2dGNU1JSUJkVEFmQmdOVkhTTUVHREFXZ0JSc2lwU2lkN0dBY2gyQgplaGFxOHR6T1p1NUZ3REFkQmdOVkhRNEVGZ1FVVzJkcFhyVllDNXdmQ2R3MWZadldKKzVpcXB3d0RnWURWUjBQCkFRSC9CQVFEQWdHR01Gb0dBMVVkSUFSVE1GRXdDd1lKWUlaSUFXVUNBUXNrTUFzR0NXQ0dTQUZsQWdFTEp6QUwKQmdsZ2hrZ0JaUUlCQ3lvd0RBWUtZSVpJQVdVREFnRUREVEFNQmdwZ2hrZ0JaUU1DQVFNUk1Bd0dDbUNHU0FGbApBd0lCQXljd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFEQU1CZ05WSFNRRUJUQURnQUVBTURjR0ExVWRId1F3Ck1DNHdMS0Fxb0NpR0ptaDBkSEE2THk5amNtd3VaR2x6WVM1dGFXd3ZZM0pzTDBSUFJGSlBUMVJEUVRNdVkzSnMKTUd3R0NDc0dBUVVGQndFQkJHQXdYakE2QmdnckJnRUZCUWN3QW9ZdWFIUjBjRG92TDJOeWJDNWthWE5oTG0xcApiQzlwYzNOMVpXUjBieTlFVDBSU1QwOVVRMEV6WDBsVUxuQTNZekFnQmdnckJnRUZCUWN3QVlZVWFIUjBjRG92CkwyOWpjM0F1WkdsellTNXRhV3d3RFFZSktvWklodmNOQVFFTEJRQURnZ0VCQUhyQW1GU3k4NlpBc2NFVTVLSUQKVWRYdGZDMytPVi9JMUJZbllpWkhKS0pqOHpSdXF2ZFd2c3VsS3RDR0tabzF3RnY0NDZuLzE0WVJiSTNUS25vMgpRL2M0SjZ1eitNT3NJR0x5UHZQbXdPNVk2R2FxajVFREQ2cmd5WVNSZEhybUJsTEUxYVVtZWRjODZVT01LQXo2Ck93bVVGUnJ1OGFYRi9ZU0VXUW1rZUlXWDRzYUltYnY4RXZiMnZxakRQRkVSakg2QmViWURSSTdacE1XZzhqSnQKTG5RRm9LT2hDT1RuSEp6MHZkL3ZuaDRJQys3K0tOZ2JnK1JaME8zSDlkbkJlVUxjTEdlSHR3MkYyakJNcmx5VwpkMEl5bjd2ajljT0drZHJrZ2dTcGRHcXFsWGlOa1ZzWWh5UFh6dEw4ak9xbXlZN25kWHViRVFDc1l4TUlJWHVyClNFUT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoKc3ViamVjdD0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURPRCBJRCBTVyBDQS00NQppc3N1ZXI9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSAzCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFcmpDQ0E1YWdBd0lCQWdJQll6QU5CZ2txaGtpRzl3MEJBUXNGQURCYk1Rc3dDUVlEVlFRR0V3SlZVekVZCk1CWUdBMVVFQ2hNUFZTNVRMaUJIYjNabGNtNXRaVzUwTVF3d0NnWURWUVFMRXdORWIwUXhEREFLQmdOVkJBc1QKQTFCTFNURVdNQlFHQTFVRUF4TU5SRzlFSUZKdmIzUWdRMEVnTXpBZUZ3MHhOakF6TURneE16STROVFphRncweQpNakF6TURreE16STROVFphTUYweEN6QUpCZ05WQkFZVEFsVlRNUmd3RmdZRFZRUUtFdzlWTGxNdUlFZHZkbVZ5CmJtMWxiblF4RERBS0JnTlZCQXNUQTBSdlJERU1NQW9HQTFVRUN4TURVRXRKTVJnd0ZnWURWUVFERXc5RVQwUWcKU1VRZ1UxY2dRMEV0TkRVd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUUNWVnRjcApSSk1kTGJsNEM0ZGZqY0JDZkFxVU1MUmJYaUtpRFJuQU1YbjNjNUlyWUVORDd1SktKVENyUWtsUThZQzU3MFphCllYeGhTYUtpRmJjUjBNQTdvSEVGOEhXZ2xCNTNHU21Gb3dxdEFpRVJTL0FXYk1Kb1hsaC9NQkp3ZWVTVlV6YXQKQ1BPOFYzcTU2WS81T0ZnbFc1WVYzdEEzS2d2K0J2bHFqWUN6V05lQndmeWVnbGtCOEVXaTU4bGxBaXlqc0dQZApRcE43MUxPeXFISzE2U0N2MjJFNm1JeXJ4ZkZnZWFXSXhJQmVYemdWeER6WjJkamJzcVl5ckpsQWRVQ2JHemgvCk85TjBNaEVDMG1NUmNnbzd1RVIwb2xuV3JpMW9PV3RKbDJPazhadk1xR1FiZGt4a2tteEN0aFVXeXhGb1ZxN1AKeFU3SVltQmlCbjI3U3lGN0FnTUJBQUdqZ2dGNU1JSUJkVEFmQmdOVkhTTUVHREFXZ0JSc2lwU2lkN0dBY2gyQgplaGFxOHR6T1p1NUZ3REFkQmdOVkhRNEVGZ1FVeS8wVnBwcGc4UzVPVzVVY2pEOGRqY0tqSWhzd0RnWURWUjBQCkFRSC9CQVFEQWdHR01Gb0dBMVVkSUFSVE1GRXdDd1lKWUlaSUFXVUNBUXNrTUFzR0NXQ0dTQUZsQWdFTEp6QUwKQmdsZ2hrZ0JaUUlCQ3lvd0RBWUtZSVpJQVdVREFnRUREVEFNQmdwZ2hrZ0JaUU1DQVFNUk1Bd0dDbUNHU0FGbApBd0lCQXljd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFEQU1CZ05WSFNRRUJUQURnQUVBTURjR0ExVWRId1F3Ck1DNHdMS0Fxb0NpR0ptaDBkSEE2THk5amNtd3VaR2x6WVM1dGFXd3ZZM0pzTDBSUFJGSlBUMVJEUVRNdVkzSnMKTUd3R0NDc0dBUVVGQndFQkJHQXdYakE2QmdnckJnRUZCUWN3QW9ZdWFIUjBjRG92TDJOeWJDNWthWE5oTG0xcApiQzlwYzNOMVpXUjBieTlFVDBSU1QwOVVRMEV6WDBsVUxuQTNZekFnQmdnckJnRUZCUWN3QVlZVWFIUjBjRG92CkwyOWpjM0F1WkdsellTNXRhV3d3RFFZSktvWklodmNOQVFFTEJRQURnZ0VCQURQdWJaL2taTkRCL2hrdUd1dUsKT21pR1pKQzJDMWRCR2t1TTBTWGV3V3pHSEVQS2FwYTRyTkRyZ0RTVFFNT0xlTVVDbXI0WGJIYk1vMW1xSURCYwpTaW9WRmlxK0Nvb0Nza2ozRCtnajFZK2RiZmkrSVc4L0lsYkhWRHhsQXBEbEoxMXYzbnZOSk5IcDdnQTBoRlZECkRhMlVwajl3VnNZcjBSZVh2SFJ6MFpiNmExLzdSNnRvNDFjOHd3ZzNoV0NHQ1hzUHZuSUxhUUs1Sm14TlZYMWkKSFQ5NVVLRHhueXNiK3Z3K0d4eEpnYUlIODdIa2d4WnRPYzdXVW5QK0dGQUxmS1F5THNSOEozdmtJa0kyREpmUApGanRCYmxnWFduOWxDSTVsWWdlSDNWYktqVnZvd2NVV3V3MkY4UEphYU5IcFZwV3d2K1hmekxtVUNkTEdqWnJCCnpCUT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoKc3ViamVjdD0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURPRCBJRCBDQS00NAppc3N1ZXI9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSAzCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFblRDQ0E0V2dBd0lCQWdJQkd6QU5CZ2txaGtpRzl3MEJBUXNGQURCYk1Rc3dDUVlEVlFRR0V3SlZVekVZCk1CWUdBMVVFQ2hNUFZTNVRMaUJIYjNabGNtNXRaVzUwTVF3d0NnWURWUVFMRXdORWIwUXhEREFLQmdOVkJBc1QKQTFCTFNURVdNQlFHQTFVRUF4TU5SRzlFSUZKdmIzUWdRMEVnTXpBZUZ3MHhOVEV4TURreE5qRTRNVFJhRncweQpNVEV4TURreE5qRTRNVFJhTUZveEN6QUpCZ05WQkFZVEFsVlRNUmd3RmdZRFZRUUtFdzlWTGxNdUlFZHZkbVZ5CmJtMWxiblF4RERBS0JnTlZCQXNUQTBSdlJERU1NQW9HQTFVRUN4TURVRXRKTVJVd0V3WURWUVFERXd4RVQwUWcKU1VRZ1EwRXRORFF3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRREczK1R0eStwRApvVEpHYkp2YkwvdVFVRDV2WGtSMUc2dlN4TlNiRnNrSW1tcnBMVjJocjh1Q0dBRkRMK0tiM2RQYVlMVEVlYUs5CjM0THFEQzAyK0N3NG1MYW1vWEt0ZkJHbEZUMVQzQUh6cFM0d0pBaGZyU0dGR1JCZFk3NmpwVG4xZWlhV3MrbmIKQ0xpSmpweFFPUWhwN2NheXRzWm5HdkxOT0ZVYytRWkpGc3lBZjA2Y3BXRW1vL2lBeDdLWExNUFY2c2JHVExxbQpreXFOeFlQdnFkMVJ5eXEydmk1UHF5dzBzd2cyK3d2a01oR0laMzlyeUpoZ2FVNXZjQWhkMzl6NTN0TlUxdHRwCnhQNTA2WjR1REc5VG1CY2lVRmZzNHVaYno5YU96VDlZWXM2ZW5saDE3MlBVNDhXZkNGSVFTT1hqUmNCOS9Ya0QKYnRnaE14VGNtemdSQWdNQkFBR2pnZ0ZyTUlJQlp6QWZCZ05WSFNNRUdEQVdnQlJzaXBTaWQ3R0FjaDJCZWhhcQo4dHpPWnU1RndEQWRCZ05WSFE0RUZnUVVNUG5OVkhPUUc0THljbzZON2xaR29rUXB2L293RGdZRFZSMFBBUUgvCkJBUURBZ0dHTUV3R0ExVWRJQVJGTUVNd0N3WUpZSVpJQVdVQ0FRc2tNQXNHQ1dDR1NBRmxBZ0VMSnpBTEJnbGcKaGtnQlpRSUJDeW93REFZS1lJWklBV1VEQWdFRERUQU1CZ3BnaGtnQlpRTUNBUU1STUJJR0ExVWRFd0VCL3dRSQpNQVlCQWY4Q0FRQXdEQVlEVlIwa0JBVXdBNEFCQURBM0JnTlZIUjhFTURBdU1DeWdLcUFvaGlab2RIUndPaTh2ClkzSnNMbVJwYzJFdWJXbHNMMk55YkM5RVQwUlNUMDlVUTBFekxtTnliREJzQmdnckJnRUZCUWNCQVFSZ01GNHcKT2dZSUt3WUJCUVVITUFLR0xtaDBkSEE2THk5amNtd3VaR2x6WVM1dGFXd3ZhWE56ZFdWa2RHOHZSRTlFVWs5UApWRU5CTTE5SlZDNXdOMk13SUFZSUt3WUJCUVVITUFHR0ZHaDBkSEE2THk5dlkzTndMbVJwYzJFdWJXbHNNQTBHCkNTcUdTSWIzRFFFQkN3VUFBNElCQVFDbkZhVkRVdU5wYlQ0WWF6ZllMNHFLYy9lMFpxZDF3TTEwdXFvK2F5anoKelA1SFhMTDJmckF1ZGd1UlZ4RkRDMVd6akIxNnRjMUdPRFVXWTRPT3hQQ3lVTktVSlRVM0c4cWNYTWFiakV2Qwp5OXdMdS81RlR2RTBpdW1wdmRwU0dKYjJ2L3BCYytUb2ZlMTdTZ0NUcE9XK01FVFpNNWZpVjZlOFZyWWFaYWxnCllYckhnK0R2ZEJwR1N0ZWNjTEZMT1JoWm9xMFpwSGg3UW9ITlZPaTlzeExoRXVoUlRTR2ViUmhUa1lOOTlQekMKQmRENmxqUTB1U2hxQjNyOHVYMXBWcEJza2Rvdm0ySldTWDQwL1FhaEZWRE13SlBJbWxKN2xYUk52UnJrcUxISApQYVRKNFI1c3BCSlVMbVVFYnFWZkZYRzVwL0k5dk5WRjdZWkNFNW56ZWdUZgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIElEIENBLTQzCmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDMKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVuVENDQTRXZ0F3SUJBZ0lCR2pBTkJna3Foa2lHOXcwQkFRc0ZBREJiTVFzd0NRWURWUVFHRXdKVlV6RVkKTUJZR0ExVUVDaE1QVlM1VExpQkhiM1psY201dFpXNTBNUXd3Q2dZRFZRUUxFd05FYjBReEREQUtCZ05WQkFzVApBMUJMU1RFV01CUUdBMVVFQXhNTlJHOUVJRkp2YjNRZ1EwRWdNekFlRncweE5URXhNRGt4TmpFMk1ERmFGdzB5Ck1URXhNRGt4TmpFMk1ERmFNRm94Q3pBSkJnTlZCQVlUQWxWVE1SZ3dGZ1lEVlFRS0V3OVZMbE11SUVkdmRtVnkKYm0xbGJuUXhEREFLQmdOVkJBc1RBMFJ2UkRFTU1Bb0dBMVVFQ3hNRFVFdEpNUlV3RXdZRFZRUURFd3hFVDBRZwpTVVFnUTBFdE5ETXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDaWI1V0tnRWt3CnlWK0hZSVJlQ1BSckZMb0JvdWUvdmEzT0RibGw4ZFpJVEY1RGtqL1Fwbi9hRTNjQ1ZYa2QxT3kzOGsrN01GR28KSTkzeENLa3hxK2dka2VMR1hFWjh0dXdwdXFlVkhXN3JqZ2QrMkRnRHVOV3NYa044VXFmSnZhTWNjTFNqTGZUSQpNUzQyMHgzc010RTVhT0MrWmliNkVpN1lsVDVHVWF0dzMzQktTVFpJc1hxV2E5dGFnNmRha3R2MUpvblFPczlXCnorekN3WjgwNkFtSmh5Z056djVzY3YwK1d0Ym5zOTFVend5VEJTcFlpOEdvMDNZWFUxem5UL2hjaVFDNnVYUlkKeFVXYkJSa3VKeWM0QXNHYjJtd2ZjZkc3VHYzTG9PMXN2MVZVVjBGc3dXR1A5ZEZSWDNEcWpJenM1eWxrNThvbwpDWFRDcndPWUlYR1BBZ01CQUFHamdnRnJNSUlCWnpBZkJnTlZIU01FR0RBV2dCUnNpcFNpZDdHQWNoMkJlaGFxCjh0ek9adTVGd0RBZEJnTlZIUTRFRmdRVU42bVNZMXhjeEoyN0lVaFRLS3JVWkZCbW1rVXdEZ1lEVlIwUEFRSC8KQkFRREFnR0dNRXdHQTFVZElBUkZNRU13Q3dZSllJWklBV1VDQVFza01Bc0dDV0NHU0FGbEFnRUxKekFMQmdsZwpoa2dCWlFJQkN5b3dEQVlLWUlaSUFXVURBZ0VERFRBTUJncGdoa2dCWlFNQ0FRTVJNQklHQTFVZEV3RUIvd1FJCk1BWUJBZjhDQVFBd0RBWURWUjBrQkFVd0E0QUJBREEzQmdOVkhSOEVNREF1TUN5Z0txQW9oaVpvZEhSd09pOHYKWTNKc0xtUnBjMkV1Yldsc0wyTnliQzlFVDBSU1QwOVVRMEV6TG1OeWJEQnNCZ2dyQmdFRkJRY0JBUVJnTUY0dwpPZ1lJS3dZQkJRVUhNQUtHTG1oMGRIQTZMeTlqY213dVpHbHpZUzV0YVd3dmFYTnpkV1ZrZEc4dlJFOUVVazlQClZFTkJNMTlKVkM1d04yTXdJQVlJS3dZQkJRVUhNQUdHRkdoMGRIQTZMeTl2WTNOd0xtUnBjMkV1Yldsc01BMEcKQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUJxVXJ6ZGVxbkMyb2hvR1VFeGt4YXlQZStoM1RLdW5tWVVCZ0ZIT0x0VAp3ODlEaUdBeXB5d1VIZ2pTT3FiMURRRDdaMkpvaGxVMnJSUm4wYWpJQWlpNUR0UGdHTjRtQjlaNUhzbWRmWjhMCitDTXIvSnc3b1llYVJMbnlXb1JXNmN2R2lNM29wQmV3Tm8xMTkyZHF2N0pZSGFBR0lWS1NkTGNFU0pOd3AzNDcKbkRENU1hdVhhOC8yYTIwbHNPT3JjVThQZ3BCSGh5UlBEUW9CYXhqalNGdEgrYUE3S3d2RmFxc1VwdmdpVHFOcAo1ajQxSzBheVYwcmRkL0szelJLY0Eyd2VNT05xRFhhZ2N2RFNDTU91M1M2alMvTTdvYzNTdjRrS2s4VmpoY29tCmhDdnc2RUh5TFNpVU1xTnpsTzcxcTVxM3FNajlRT0Q2VDRQSzYvVXhSRDdECi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCnN1YmplY3Q9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1ET0QgSUQgQ0EtNDIKaXNzdWVyPS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RG9EIFJvb3QgQ0EgMwotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRW5UQ0NBNFdnQXdJQkFnSUJHVEFOQmdrcWhraUc5dzBCQVFzRkFEQmJNUXN3Q1FZRFZRUUdFd0pWVXpFWQpNQllHQTFVRUNoTVBWUzVUTGlCSGIzWmxjbTV0Wlc1ME1Rd3dDZ1lEVlFRTEV3TkViMFF4RERBS0JnTlZCQXNUCkExQkxTVEVXTUJRR0ExVUVBeE1OUkc5RUlGSnZiM1FnUTBFZ016QWVGdzB4TlRFeE1Ea3hOakUxTURKYUZ3MHkKTVRFeE1Ea3hOakUxTURKYU1Gb3hDekFKQmdOVkJBWVRBbFZUTVJnd0ZnWURWUVFLRXc5VkxsTXVJRWR2ZG1WeQpibTFsYm5ReEREQUtCZ05WQkFzVEEwUnZSREVNTUFvR0ExVUVDeE1EVUV0Sk1SVXdFd1lEVlFRREV3eEVUMFFnClNVUWdRMEV0TkRJd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUUN0NC8rOWJlRGIKM2c5a0dnMk1sem5VWTkzQ090aURMZXRNQ2tzNGFRNS9NWWFTdGk2ZW9EdzVMN0VIbGtOZm5yTzVYWEtiUUhaNwpIcWlwd3lFNnVaMzZXUEV2VTZ1ZmluNTdGcisrYUlZTmszeExBSDRtZTZqVDhxeXJ6bjlGVUJYaDJVc25xQ01vCjVqSGwrNkZKYnNUcTIvc1NwSVpsOFNNVVM0dzZ3TmkvZ1JTcmhkVmZtSmliaFFnRWo2UWJ2VXI4YUFTemx5UzkKK3p2TVJUWnE3SkJERVBsYmRzZkUzbWJHV3ZPMCtQRDhITXNOcmo1cktMN3dkb0F6UURCL1lpc0YvOWZmSnc4TApjRlBzVWlzVWRac0ZUazlMN3FNQ2NnU2ZDdEdmdzVBRXc0bGNtSUFpSFJYMEFwZC9pSk00a0FEdUhVRlBZek0yCkVONG5nakR4SzZqVkFnTUJBQUdqZ2dGck1JSUJaekFmQmdOVkhTTUVHREFXZ0JSc2lwU2lkN0dBY2gyQmVoYXEKOHR6T1p1NUZ3REFkQmdOVkhRNEVGZ1FVTXFBQXlsbUx4TTU4ZTl2ZUdTb1Fpb1pCMGVNd0RnWURWUjBQQVFILwpCQVFEQWdHR01Fd0dBMVVkSUFSRk1FTXdDd1lKWUlaSUFXVUNBUXNrTUFzR0NXQ0dTQUZsQWdFTEp6QUxCZ2xnCmhrZ0JaUUlCQ3lvd0RBWUtZSVpJQVdVREFnRUREVEFNQmdwZ2hrZ0JaUU1DQVFNUk1CSUdBMVVkRXdFQi93UUkKTUFZQkFmOENBUUF3REFZRFZSMGtCQVV3QTRBQkFEQTNCZ05WSFI4RU1EQXVNQ3lnS3FBb2hpWm9kSFJ3T2k4dgpZM0pzTG1ScGMyRXViV2xzTDJOeWJDOUVUMFJTVDA5VVEwRXpMbU55YkRCc0JnZ3JCZ0VGQlFjQkFRUmdNRjR3Ck9nWUlLd1lCQlFVSE1BS0dMbWgwZEhBNkx5OWpjbXd1WkdsellTNXRhV3d2YVhOemRXVmtkRzh2UkU5RVVrOVAKVkVOQk0xOUpWQzV3TjJNd0lBWUlLd1lCQlFVSE1BR0dGR2gwZEhBNkx5OXZZM053TG1ScGMyRXViV2xzTUEwRwpDU3FHU0liM0RRRUJDd1VBQTRJQkFRQTVoSWpvUGw2amUxMTc2d0RtN2k0Rk5HZWh1S2tyTTZLT3FFWkx5emUyCmJrU1JaWFY4d0l2ZTZDa014TDg5UExFYTlCUFhGL1BwRjVXbjJ0bzRZWmdabXgwaiszTTlrSXVJekR4S0hBSEIKdGZMb09YSGlUL2c5VTlTY2wwOVJpV1ZmaHVsMTNSNytRNkNRZEtPMXl1NjliTnR2TDFVeHN6MkxhR1AzcEZhUwpRa2xNK05zNTZOM2EyWUozcU55akduTW9rc0JERlNraXRZSkpyV3RlSFN2MWlCdjlGVmdlL2QzU0U5K1BxL1dEClEyMnlLLzBwaDNnVEV3NjFlOUVZWi9UQWVOYjAxSnU1NmJObzVsVkhBejJVYXdyd0doUmtsSlFoZi9pOUpSZGEKZ3lrWWc0WmtjemwrWlhOKzBiZkpEWitrcGlzMHdsY1ByVnpOS05wQVZuemYKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoKc3ViamVjdD0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURPRCBJRCBDQS00MQppc3N1ZXI9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSAzCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFblRDQ0E0V2dBd0lCQWdJQkdEQU5CZ2txaGtpRzl3MEJBUXNGQURCYk1Rc3dDUVlEVlFRR0V3SlZVekVZCk1CWUdBMVVFQ2hNUFZTNVRMaUJIYjNabGNtNXRaVzUwTVF3d0NnWURWUVFMRXdORWIwUXhEREFLQmdOVkJBc1QKQTFCTFNURVdNQlFHQTFVRUF4TU5SRzlFSUZKdmIzUWdRMEVnTXpBZUZ3MHhOVEV4TURreE5qRXpOVFphRncweQpNVEV4TURreE5qRXpOVFphTUZveEN6QUpCZ05WQkFZVEFsVlRNUmd3RmdZRFZRUUtFdzlWTGxNdUlFZHZkbVZ5CmJtMWxiblF4RERBS0JnTlZCQXNUQTBSdlJERU1NQW9HQTFVRUN4TURVRXRKTVJVd0V3WURWUVFERXd4RVQwUWcKU1VRZ1EwRXROREV3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQzN5WFNJMkNhKwpMSkhnem1objJOSDlYazAyK1FvRVB0TzRLM29IYStYS2VQMk1kazRvb0Z5M1NMdml6Zjg0ekRXenFWUG9vZkVkCnBGMU5wRFQ4OXJtNUpPamFJNVBCbTljdDRyVjBacUgzNERsQVJNVmp0aFc2eVNVcDJZRERLNWRHa1pUQUNxa24KRTJBYUw3NzdSeVBMUkVTRHAxcC9KMnlJblVNdkNjM3dzSm1xdGVTVzVkVURwbDcrUzlTVjJEK3VyZjd6QjVvQgowNkQ5aTRZa25TaDNubnRodHFIU0N2TkYwUXRweW5UeWR5Y0JyWloyQ3Y0bEYvaVZQcGk4OVdEVEFqd1djM3U3CkhWeEhxQ2k5WjZ6QjdlSUlYdElSY0tCSnJxTDdvRXh2QUd1MEMvMUQ2L2RRZk9xSGE0Y1BFZ2xsWGZ5MzhaeGYKblVyRkNpaDRUakQxQWdNQkFBR2pnZ0ZyTUlJQlp6QWZCZ05WSFNNRUdEQVdnQlJzaXBTaWQ3R0FjaDJCZWhhcQo4dHpPWnU1RndEQWRCZ05WSFE0RUZnUVVXNUhHUkRieUtQTDR6N0xDeU1walNXR2JJQW93RGdZRFZSMFBBUUgvCkJBUURBZ0dHTUV3R0ExVWRJQVJGTUVNd0N3WUpZSVpJQVdVQ0FRc2tNQXNHQ1dDR1NBRmxBZ0VMSnpBTEJnbGcKaGtnQlpRSUJDeW93REFZS1lJWklBV1VEQWdFRERUQU1CZ3BnaGtnQlpRTUNBUU1STUJJR0ExVWRFd0VCL3dRSQpNQVlCQWY4Q0FRQXdEQVlEVlIwa0JBVXdBNEFCQURBM0JnTlZIUjhFTURBdU1DeWdLcUFvaGlab2RIUndPaTh2ClkzSnNMbVJwYzJFdWJXbHNMMk55YkM5RVQwUlNUMDlVUTBFekxtTnliREJzQmdnckJnRUZCUWNCQVFSZ01GNHcKT2dZSUt3WUJCUVVITUFLR0xtaDBkSEE2THk5amNtd3VaR2x6WVM1dGFXd3ZhWE56ZFdWa2RHOHZSRTlFVWs5UApWRU5CTTE5SlZDNXdOMk13SUFZSUt3WUJCUVVITUFHR0ZHaDBkSEE2THk5dlkzTndMbVJwYzJFdWJXbHNNQTBHCkNTcUdTSWIzRFFFQkN3VUFBNElCQVFDaDRyUmlYOThJMXNnd0ovd0ZhTER0TTNHbEtUdWxEdTdWR3BHbGxsbGgKYlVwWmlhSFE4cE1WMmdvRmJvQU9QWHhNbmwyTjJVTS9VNC85UzJ1VzRtb3NRbzJnYmNOVDdyYmkvUWhsRWs0Wgp1NnRaZWszU3ZoRklxK2ZuL1hoTXFpTXdJT1VOcXJvaDVCbnZQR0xRY01xZm5MZWJUSm1rY0c0STZPbVhQNmVuCmpoL0pjZE5ueE1oWjFaVWp1NjErU3c4ZzE0ZktWNmtBVWRyR2hRUFpBY2VaeUx2VWFqRFJYTGR4Rlg3TFdpcDAKSUlGUEQ0ZU0ycEx4OTRNUHBid0ZvNC9sK3JPOExLNUJMeEc0WVY3aElpeWF1d3RjUkVvTndqUnlFMFRKOHFUZgptelhVek03WXlqQlF5dHllS0hhRXlEYlVMQWUwdmZVYjlwMWpveG9HU091ZQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIEVNQUlMIENBLTQ0Cmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDMKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVvRENDQTRpZ0F3SUJBZ0lCRnpBTkJna3Foa2lHOXcwQkFRc0ZBREJiTVFzd0NRWURWUVFHRXdKVlV6RVkKTUJZR0ExVUVDaE1QVlM1VExpQkhiM1psY201dFpXNTBNUXd3Q2dZRFZRUUxFd05FYjBReEREQUtCZ05WQkFzVApBMUJMU1RFV01CUUdBMVVFQXhNTlJHOUVJRkp2YjNRZ1EwRWdNekFlRncweE5URXhNRGt4TmpFeU1UWmFGdzB5Ck1URXhNRGt4TmpFeU1UWmFNRjB4Q3pBSkJnTlZCQVlUQWxWVE1SZ3dGZ1lEVlFRS0V3OVZMbE11SUVkdmRtVnkKYm0xbGJuUXhEREFLQmdOVkJBc1RBMFJ2UkRFTU1Bb0dBMVVFQ3hNRFVFdEpNUmd3RmdZRFZRUURFdzlFVDBRZwpSVTFCU1V3Z1EwRXRORFF3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQzV3ampjClJQdHo0czREeldKVVJWcEFsME1oeHpSVDFTSHYzU2p1L0xrVmFhZ3JFZk54RVpibmtUSEtjaUZoU2NiQ0ljbzQKNDU4K0x0Ulhtd01aaVhTUFNWcXVFdWhZanBtUWdncVZVczhlb3pmVjR1TW5JODhGQkVHVWh3QTh6Zmd3Uk1MRgpSUW5KNFNDQjNvR2JaSGg0c1YxTXV0cHJDRHdkNnFyRzBrOGI4L0dGOWgxdnlQWmJOTkJIT0RsZmREcmFCRDUvCmJkWDVsUTRMNko3dVQ1dll0VFFRSVJNK2ZrMU5sbXhyMm9rS0g0d2N3SzVGUTlJL2tZQXM3UW9GOU15OG5BT08Kc0FBWVBCeHErVjVVV3dScXFkU1N4WDcyWUVIQXlpdHhtd25nM1ZNSHU1cE5Dbm1Fc1lTVkg3QzdGZlFhWGsvZQpRNCtvMzZzbEcweC9qeXM3QWdNQkFBR2pnZ0ZyTUlJQlp6QWZCZ05WSFNNRUdEQVdnQlJzaXBTaWQ3R0FjaDJCCmVoYXE4dHpPWnU1RndEQWRCZ05WSFE0RUZnUVVvSXRuMGVGZ1pIV25PYXpKdURXTm1KSjBjNlV3RGdZRFZSMFAKQVFIL0JBUURBZ0dHTUV3R0ExVWRJQVJGTUVNd0N3WUpZSVpJQVdVQ0FRc2tNQXNHQ1dDR1NBRmxBZ0VMSnpBTApCZ2xnaGtnQlpRSUJDeW93REFZS1lJWklBV1VEQWdFRERUQU1CZ3BnaGtnQlpRTUNBUU1STUJJR0ExVWRFd0VCCi93UUlNQVlCQWY4Q0FRQXdEQVlEVlIwa0JBVXdBNEFCQURBM0JnTlZIUjhFTURBdU1DeWdLcUFvaGlab2RIUncKT2k4dlkzSnNMbVJwYzJFdWJXbHNMMk55YkM5RVQwUlNUMDlVUTBFekxtTnliREJzQmdnckJnRUZCUWNCQVFSZwpNRjR3T2dZSUt3WUJCUVVITUFLR0xtaDBkSEE2THk5amNtd3VaR2x6WVM1dGFXd3ZhWE56ZFdWa2RHOHZSRTlFClVrOVBWRU5CTTE5SlZDNXdOMk13SUFZSUt3WUJCUVVITUFHR0ZHaDBkSEE2THk5dlkzTndMbVJwYzJFdWJXbHMKTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFDU1k5ZFRMb3pQSFZUY3JTQkRTUFJpQXRzNmttS0ZpcDFUMnFQKwp6RHFFVFVzN0ZwUy9Fa0xrYThuMHFqbVlNdE5XRDl6c1dLaThGYlplWjFzZTV0U0Z4TDl3YXVwZmliTUZzSlQ0Ck1udm1rM2loaFVmVFpZcEVSQm1nZVg3Y2Q4MCtXTzlTQjFQK2RDTHcvN01qVGROOGowYU9jamgrSTZLTFdMakEKTGZWTmhwWjcvOExnc09sM3NIZ1o3NTM3WXNBNlRpK3llekdEMGpNN25LcGZ5Zzc4bmJLMmltV3V0aXVFeUh1aQpPZHdjSk9RcHNLdW95TmE1eXp5dVhLNXlnRy9QTUV6SnI2cmZKeWtkNlVNcEFEZ2FDWm1TV3VlSnF6TXhmckkyClpvWGxaem1YMHhHMkN1aE9FaGNxd0xMdktncXUrZFVLd3pFNFZ4UVlndFJ0enpKZgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIEVNQUlMIENBLTQzCmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDMKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVvRENDQTRpZ0F3SUJBZ0lCRmpBTkJna3Foa2lHOXcwQkFRc0ZBREJiTVFzd0NRWURWUVFHRXdKVlV6RVkKTUJZR0ExVUVDaE1QVlM1VExpQkhiM1psY201dFpXNTBNUXd3Q2dZRFZRUUxFd05FYjBReEREQUtCZ05WQkFzVApBMUJMU1RFV01CUUdBMVVFQXhNTlJHOUVJRkp2YjNRZ1EwRWdNekFlRncweE5URXhNRGt4TmpFeE1ESmFGdzB5Ck1URXhNRGt4TmpFeE1ESmFNRjB4Q3pBSkJnTlZCQVlUQWxWVE1SZ3dGZ1lEVlFRS0V3OVZMbE11SUVkdmRtVnkKYm0xbGJuUXhEREFLQmdOVkJBc1RBMFJ2UkRFTU1Bb0dBMVVFQ3hNRFVFdEpNUmd3RmdZRFZRUURFdzlFVDBRZwpSVTFCU1V3Z1EwRXRORE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQ3IzaW5SClloQWV3MWtqR2ViSXB0NWVSNUJTei94cURoejZLdlBOaXJpM2diUmFyN2xBdTdYVkdBbitMWUIrTnl1SnQzV3UKNnRTbVh2dnF4TFBLWHI0N3RGQWtqcFgyTXkxSUdNK1k1OWlNc3V2SytUMXhlRnZiWkZ0bkM4RWdudEV3UjBVbwpVV3RVWkFkYjVJZEtHcXVvbHQ4OVJUdDZXMW1nTWhidVlFZXd5ZFNrbnh4VUkreU52TVE2TkdlYVJ6dTlJUkltCkFtdFNIVXBrRTV2eHRvOGxteFJ0RjA5TGNtTFNpRWx4N0luc0wzb2xBUVNqencyQVdiSEVNcjRXRFZUdWdKWG4KVkxmbUM4L2Z1VEVOdm1MUkRHblRBK2xpMGZqT1J6TXFtR0lvazVlb1UzWDI0UXYzSWk3L1h2R0Z5TkdBS1B5NApvS0FYRUduNWVadGFyNGt2QWdNQkFBR2pnZ0ZyTUlJQlp6QWZCZ05WSFNNRUdEQVdnQlJzaXBTaWQ3R0FjaDJCCmVoYXE4dHpPWnU1RndEQWRCZ05WSFE0RUZnUVU5eC94UmpoVnY3eHhpN0lHTzQ0ckdMSmV1N1F3RGdZRFZSMFAKQVFIL0JBUURBZ0dHTUV3R0ExVWRJQVJGTUVNd0N3WUpZSVpJQVdVQ0FRc2tNQXNHQ1dDR1NBRmxBZ0VMSnpBTApCZ2xnaGtnQlpRSUJDeW93REFZS1lJWklBV1VEQWdFRERUQU1CZ3BnaGtnQlpRTUNBUU1STUJJR0ExVWRFd0VCCi93UUlNQVlCQWY4Q0FRQXdEQVlEVlIwa0JBVXdBNEFCQURBM0JnTlZIUjhFTURBdU1DeWdLcUFvaGlab2RIUncKT2k4dlkzSnNMbVJwYzJFdWJXbHNMMk55YkM5RVQwUlNUMDlVUTBFekxtTnliREJzQmdnckJnRUZCUWNCQVFSZwpNRjR3T2dZSUt3WUJCUVVITUFLR0xtaDBkSEE2THk5amNtd3VaR2x6WVM1dGFXd3ZhWE56ZFdWa2RHOHZSRTlFClVrOVBWRU5CTTE5SlZDNXdOMk13SUFZSUt3WUJCUVVITUFHR0ZHaDBkSEE2THk5dlkzTndMbVJwYzJFdWJXbHMKTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCYjBPeEpRUG5nWE9UU3pxcXhSV0JZamlLKzR2RWYvbndqN2NqMApPVDA3RklyUnNScHlad3BFTmZmQ3RNVTV5djJHSHFsUzhKS2lxdzlvR05NdHFvVzRCdFhFRTBPbzdXMGRuUUdrCndMdjU1ZVJOMUZESTBKZ3BUdTR6aXhxN05NcFl4N1hWQURpNiszRTExZWZtT2VzRjIwcG83K0dnMk1Hc0pUTlIKRU1YaDd5SGNEcXM2bk1rUHRjbDF1NHFpdmZvaGRSY0tzSXZ3QzFaNGNWK2JqWjlBNUtPQlplV3NhODZGek5CbApqS1RkTHhlYlV6MDkxYUE2dGpVWi9rNTc2T1BLaVIxazhhd2xEc3o1ai9TOXhLMUh0NUtWMng4RWR2Z3JlaXc0CkR0OERpc3ovZlgwVDMzMFAybjZHYlBPY2dML3dpa3RSakNxMkJubmxtRExGd3hKZQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIEVNQUlMIENBLTQyCmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDMKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVvRENDQTRpZ0F3SUJBZ0lCRlRBTkJna3Foa2lHOXcwQkFRc0ZBREJiTVFzd0NRWURWUVFHRXdKVlV6RVkKTUJZR0ExVUVDaE1QVlM1VExpQkhiM1psY201dFpXNTBNUXd3Q2dZRFZRUUxFd05FYjBReEREQUtCZ05WQkFzVApBMUJMU1RFV01CUUdBMVVFQXhNTlJHOUVJRkp2YjNRZ1EwRWdNekFlRncweE5URXhNRGt4TmpBNU5ESmFGdzB5Ck1URXhNRGt4TmpBNU5ESmFNRjB4Q3pBSkJnTlZCQVlUQWxWVE1SZ3dGZ1lEVlFRS0V3OVZMbE11SUVkdmRtVnkKYm0xbGJuUXhEREFLQmdOVkJBc1RBMFJ2UkRFTU1Bb0dBMVVFQ3hNRFVFdEpNUmd3RmdZRFZRUURFdzlFVDBRZwpSVTFCU1V3Z1EwRXROREl3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQ21uU1gxCmoyNVgwbHJseGw3RlRpNjVEeHpTYVhsVVF3UFBJTEh4UWg0cFdNYkE3UmZmNHIrZHVFVG1hM21yUG1hZWo0NUgKS1lQRisxakZpVitqTGlQRlh6UUtjc3JySW1yYXRYY0FCRnVzMGxBOHhCdHZoalpURS92bUdTWFpwQlBGQWt5Ygpqb2YzT0pCenpXd28ra1BySy9qZTBLYnJscTRqZWtOY3BYRGVSNFFwMkZYdHdNZ2VTOVJuTUdVV2JPN3N2L2lKCmNlVWtYRDlXRzZJWTJHVzNFTXN4NU1KdHhlNk03QUNzTWIwSjNlTisyQkF4QVpaR2pNUmpQYTJDKzJrYzkyMmoKQnNyNG1mUTloRWJXRXU1d1dMd2lKTEJIKzlOYVRCeGxxY0dTOHl5WDB4UWt0dkxIbHJtbklVcFFrc0gzeC82RgpVbnpYUTFDS2hhRU5pNGx2QWdNQkFBR2pnZ0ZyTUlJQlp6QWZCZ05WSFNNRUdEQVdnQlJzaXBTaWQ3R0FjaDJCCmVoYXE4dHpPWnU1RndEQWRCZ05WSFE0RUZnUVVid1drWGFMRXI1VmJRWkhmQzNnTEZ1OGNDVzR3RGdZRFZSMFAKQVFIL0JBUURBZ0dHTUV3R0ExVWRJQVJGTUVNd0N3WUpZSVpJQVdVQ0FRc2tNQXNHQ1dDR1NBRmxBZ0VMSnpBTApCZ2xnaGtnQlpRSUJDeW93REFZS1lJWklBV1VEQWdFRERUQU1CZ3BnaGtnQlpRTUNBUU1STUJJR0ExVWRFd0VCCi93UUlNQVlCQWY4Q0FRQXdEQVlEVlIwa0JBVXdBNEFCQURBM0JnTlZIUjhFTURBdU1DeWdLcUFvaGlab2RIUncKT2k4dlkzSnNMbVJwYzJFdWJXbHNMMk55YkM5RVQwUlNUMDlVUTBFekxtTnliREJzQmdnckJnRUZCUWNCQVFSZwpNRjR3T2dZSUt3WUJCUVVITUFLR0xtaDBkSEE2THk5amNtd3VaR2x6WVM1dGFXd3ZhWE56ZFdWa2RHOHZSRTlFClVrOVBWRU5CTTE5SlZDNXdOMk13SUFZSUt3WUJCUVVITUFHR0ZHaDBkSEE2THk5dlkzTndMbVJwYzJFdWJXbHMKTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCKzB2UUdBcng4YkIza0xrUXRsU3EvSlFkellHOVp4VHUxVytudgplYUJVelh5aFV5QlAxT0VBMFp2eWlBdDdrbTk1eTMvSDY1bVpxdEJSUXV6K2pZZjBIeHhkMGZGdzJjWHJVOG9OCnBmOW9mOFNJaXQzZzdIL2xQdkN6UXJpeGpCUEp5SVppdUYvMXRHcVM3T21RUC80alUzK1I4dXZWaFVpM0FYMkQKWEFtNFZUY0JwQ3NHM296T0NwSnlrQVFaSnhhT2dxU0pIRkxOZFBCeXIxZk12cHNGT2tTV3dsR3ptV09iaDRYdwp1ZDArbmFQNHBicUtZanVlL01lQUdxZ214TUpUbjRoRlhTNWJITVZpc2NKcG5adEp6MUo2WHNBOGFTaVpPL3VsCmlPL3ZReDNDemRFV0NNQjFaQ0dQMHhkemZEaXBLRU1EUFJwQTN1Y1BqM2RnYjNNcgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIEVNQUlMIENBLTQxCmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDMKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVvRENDQTRpZ0F3SUJBZ0lCRkRBTkJna3Foa2lHOXcwQkFRc0ZBREJiTVFzd0NRWURWUVFHRXdKVlV6RVkKTUJZR0ExVUVDaE1QVlM1VExpQkhiM1psY201dFpXNTBNUXd3Q2dZRFZRUUxFd05FYjBReEREQUtCZ05WQkFzVApBMUJMU1RFV01CUUdBMVVFQXhNTlJHOUVJRkp2YjNRZ1EwRWdNekFlRncweE5URXhNRGt4TmpBMU1qZGFGdzB5Ck1URXhNRGt4TmpBMU1qZGFNRjB4Q3pBSkJnTlZCQVlUQWxWVE1SZ3dGZ1lEVlFRS0V3OVZMbE11SUVkdmRtVnkKYm0xbGJuUXhEREFLQmdOVkJBc1RBMFJ2UkRFTU1Bb0dBMVVFQ3hNRFVFdEpNUmd3RmdZRFZRUURFdzlFVDBRZwpSVTFCU1V3Z1EwRXROREV3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQ1V1eWNSCkRDTXc0aVBHSWJlcTFZdXcvOVMrdGtRblRkdERFMVJTcC9BaFZVK3NJSUxJSDBBeTVHaUpZdVoxTDROZFVHbkoKcnNBZVJKSUZVWmFlL2VNZnpBUnRVdG5IeVB0ZVhKQjFEWWg4ZUs1YjVFN1JGVXo1bGFlNEFkaHVVdFBTUkRtMApZZEg4blhKOEZnbTB3K3BNQ2x0WkpMSUdoZmdwaFhiY1psZXlGSnJSay9rMzBQSWZOZFpTb3hJMGRuOHRKUnVpCjhINTBjWHBEYkNkNUtzaStqRXNkWVIzTWN6YTZWVFpSbXZlcHdBaUY5ZnBFcWx5VnFsdHEyT1dMZzhreTYyOFYKT0RlRFoxODhIU3g4cmdwWmZPeEhRSnBNbkl5T0tISDM1V2VYRU1HQzdzcHZyUlArZC9CWnNJUkdtVngyNUZUaQpqYkNGZlRRZUQ5MWNiNmlmQWdNQkFBR2pnZ0ZyTUlJQlp6QWZCZ05WSFNNRUdEQVdnQlJzaXBTaWQ3R0FjaDJCCmVoYXE4dHpPWnU1RndEQWRCZ05WSFE0RUZnUVVPU21vQ0dUaWo0T3FnV0ZIRVpFeitGbzNwdVF3RGdZRFZSMFAKQVFIL0JBUURBZ0dHTUV3R0ExVWRJQVJGTUVNd0N3WUpZSVpJQVdVQ0FRc2tNQXNHQ1dDR1NBRmxBZ0VMSnpBTApCZ2xnaGtnQlpRSUJDeW93REFZS1lJWklBV1VEQWdFRERUQU1CZ3BnaGtnQlpRTUNBUU1STUJJR0ExVWRFd0VCCi93UUlNQVlCQWY4Q0FRQXdEQVlEVlIwa0JBVXdBNEFCQURBM0JnTlZIUjhFTURBdU1DeWdLcUFvaGlab2RIUncKT2k4dlkzSnNMbVJwYzJFdWJXbHNMMk55YkM5RVQwUlNUMDlVUTBFekxtTnliREJzQmdnckJnRUZCUWNCQVFSZwpNRjR3T2dZSUt3WUJCUVVITUFLR0xtaDBkSEE2THk5amNtd3VaR2x6WVM1dGFXd3ZhWE56ZFdWa2RHOHZSRTlFClVrOVBWRU5CTTE5SlZDNXdOMk13SUFZSUt3WUJCUVVITUFHR0ZHaDBkSEE2THk5dlkzTndMbVJwYzJFdWJXbHMKTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFBaEV2SFRXeWViejA1T3g5aFcrbmVVTVlJMTY4Nnl6UUEzZXIzVApsbWFwVENueE55TmVHUDBkY0x1RnFIWnU3d2l3Nm4zNjJ5Z0hEQjRlMkdRbS9JRkhzZFBYQkVRaURCdEJPZTI0CkVPeFhNRXA0S3Uwem5PRmdaRVYva25nL1NUNHJzb3liNE1WQ3poQ1IvNWxmemsweldENW9VZ25KNVl3V0lJVE4KekNPMTBmeFFZaUNCRkRHUGNNR0ovYmlCZGNYRnR6dlBtcnpJSERnaXRsbDkxa0k0UnRxNVo4Szc5ODh5cXFzTQpEbS9FYzF0N2FMK0ErUEg5Q1NMTUxOWWZsbEFORHZwUzJxR1Y5dmg0UkdqTzRkOFA4V0Flak5jenJjdVE0R0VBCjFhSW5BMjlzTmRoTEZPS0F0M0JES3ZTanhKTS9iM0ozamtnNkNEem1jY1hvbE4veQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIElEIFNXIENBLTM4Cmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDMKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVvRENDQTRpZ0F3SUJBZ0lCRXpBTkJna3Foa2lHOXcwQkFRc0ZBREJiTVFzd0NRWURWUVFHRXdKVlV6RVkKTUJZR0ExVUVDaE1QVlM1VExpQkhiM1psY201dFpXNTBNUXd3Q2dZRFZRUUxFd05FYjBReEREQUtCZ05WQkFzVApBMUJMU1RFV01CUUdBMVVFQXhNTlJHOUVJRkp2YjNRZ1EwRWdNekFlRncweE5UQTVNak14TlRJME5URmFGdzB5Ck1UQTVNak14TlRJME5URmFNRjB4Q3pBSkJnTlZCQVlUQWxWVE1SZ3dGZ1lEVlFRS0V3OVZMbE11SUVkdmRtVnkKYm0xbGJuUXhEREFLQmdOVkJBc1RBMFJ2UkRFTU1Bb0dBMVVFQ3hNRFVFdEpNUmd3RmdZRFZRUURFdzlFVDBRZwpTVVFnVTFjZ1EwRXRNemd3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRE10dzJNClEyNGVnNm5FN2gvWlhNaU4wR1RIbnlidGNlQWxZbTVObU9XWk56cjEvczIyQXQxYU4zTlNpbHQ1VDJNQXE3SUoKT09QVnF0UTRlOFlqdnduWk1sL3ZoazZaNHJ3QWVQc2hyOUh2bE84Q1hsMjU3UlAzdU44SGdSQlJ5aUJ6SmgwOApROFcrSHJiNzdYTW4wQ3pkUTdoKzAraEpqZHdSalNBZ0hmSEJhZ0FGSWlsWUJVSHRyZXNKTkI3emsvamVkYUl1CnY2eG9Ua0p0dFMrVVNTV0o5MVJxbjFodkFaZmQ0WGJ3ZVNxQ1BORlhYV3Z1ZElJN0RaOUczVml5bUNYcVhKRFoKS1hXK2lFT0Zld1k5SzFCTW5JK05PVi9xT3YzMzVvaXRQWWVScW5JT2lRbVYwSjJBckNZb1dmUXB1dFF1SEQ2WQp5M2R6VEVqNmRGSDlDYnVYQWdNQkFBR2pnZ0ZyTUlJQlp6QWZCZ05WSFNNRUdEQVdnQlJzaXBTaWQ3R0FjaDJCCmVoYXE4dHpPWnU1RndEQWRCZ05WSFE0RUZnUVVqc1c1elB6T2psTzBLczdvRVNyUG15bHNaOG93RGdZRFZSMFAKQVFIL0JBUURBZ0dHTUV3R0ExVWRJQVJGTUVNd0N3WUpZSVpJQVdVQ0FRc2tNQXNHQ1dDR1NBRmxBZ0VMSnpBTApCZ2xnaGtnQlpRSUJDeW93REFZS1lJWklBV1VEQWdFRERUQU1CZ3BnaGtnQlpRTUNBUU1STUJJR0ExVWRFd0VCCi93UUlNQVlCQWY4Q0FRQXdEQVlEVlIwa0JBVXdBNEFCQURBM0JnTlZIUjhFTURBdU1DeWdLcUFvaGlab2RIUncKT2k4dlkzSnNMbVJwYzJFdWJXbHNMMk55YkM5RVQwUlNUMDlVUTBFekxtTnliREJzQmdnckJnRUZCUWNCQVFSZwpNRjR3T2dZSUt3WUJCUVVITUFLR0xtaDBkSEE2THk5amNtd3VaR2x6WVM1dGFXd3ZhWE56ZFdWa2RHOHZSRTlFClVrOVBWRU5CTTE5SlZDNXdOMk13SUFZSUt3WUJCUVVITUFHR0ZHaDBkSEE2THk5dlkzTndMbVJwYzJFdWJXbHMKTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFDaExhWkd0WkVldnJSaDRoeU1yeXdJZVBKMWg4dDhLNzY2VFRVQgo4QVkyeTUvQm9sRW9IeEtUT2lzN0JSb2xyaVJGc2E0UFZGVVNJWFVzR1F4ckEyaDhwYTB2MmlyckVFMml4WkdOCmg1clNYWGhDK1V0QUxERjhQbFdVdkQvTTFXTE9JVzI3N1lIUTRKTmpNbDVPRWhzclZveEpaM0kzMmJURzhFWnAKRURtQmJWUHNCSU5SZjFrakJkNjl4YjdrazY3RGZVRXM0ZlVqVEhSRE9mbFYzODhiWDI4NzcvL1VhQURQZmpHSwo2ZzlBeFkrK3BmLzRjYW4vRGh4aEo0MCtvS2lETjI5YXB1d21lTnJmQWkrQ3FMOXVGdTZKU3hTVUdPeTRaRExBCnZtQVFIR0k2cittUkJjdThVLzl4dWFZcGtPOGpBb0RObjd5UzRIMFNURW9Eb3JyUgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIElEIFNXIENBLTM3Cmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDMKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVvRENDQTRpZ0F3SUJBZ0lCRWpBTkJna3Foa2lHOXcwQkFRc0ZBREJiTVFzd0NRWURWUVFHRXdKVlV6RVkKTUJZR0ExVUVDaE1QVlM1VExpQkhiM1psY201dFpXNTBNUXd3Q2dZRFZRUUxFd05FYjBReEREQUtCZ05WQkFzVApBMUJMU1RFV01CUUdBMVVFQXhNTlJHOUVJRkp2YjNRZ1EwRWdNekFlRncweE5UQTVNak14TlRJek1EVmFGdzB5Ck1UQTVNak14TlRJek1EVmFNRjB4Q3pBSkJnTlZCQVlUQWxWVE1SZ3dGZ1lEVlFRS0V3OVZMbE11SUVkdmRtVnkKYm0xbGJuUXhEREFLQmdOVkJBc1RBMFJ2UkRFTU1Bb0dBMVVFQ3hNRFVFdEpNUmd3RmdZRFZRUURFdzlFVDBRZwpTVVFnVTFjZ1EwRXRNemN3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQ3NybktpCnFmV1VZdkJaNXBvTjVHTU82cW90bDdYSjRHR2ZnL2xyOGlwYlBjZ1lTY3c4SExYcnhha1cwd0ErdUVrM1lrYS8KL2JmVWd0aUxDcXIyL1NNWVZJU2pYaXNnbEFIVWlLMXBuWGw2QU5KM0ZHWDRlaW85WGRidmlmWGpjTXU0NjJUMwpYb1pBY2Jid2trN2o1RzJQNHVKbjg4aDJHbXByWUp6ZVBOTEMzOHlNZ2k0Rk1Sc1BjaFZZcFgzRnhrMndYRU9nCmh5ZVNZdnVlWFdPekV0RURDRXlydW1ReEhmVzNPcnUwYjZKclRaTXB6dE9sYVRkOW5nS0xySWNLYVhFeUd0cmoKbENva0JtVEFMYzZ4bnlLbVVOZjRSOUltbytsVmJ3U0l5Y0duZVBPVHJKY2NSVFViWnNmWHNGZUQwbElXR25IWQpyd3Mxdzl4YXJ2SU43R205QWdNQkFBR2pnZ0ZyTUlJQlp6QWZCZ05WSFNNRUdEQVdnQlJzaXBTaWQ3R0FjaDJCCmVoYXE4dHpPWnU1RndEQWRCZ05WSFE0RUZnUVVGaVIrOXkzQjc1SS92a1RuVkY3cC9oZTY4NkV3RGdZRFZSMFAKQVFIL0JBUURBZ0dHTUV3R0ExVWRJQVJGTUVNd0N3WUpZSVpJQVdVQ0FRc2tNQXNHQ1dDR1NBRmxBZ0VMSnpBTApCZ2xnaGtnQlpRSUJDeW93REFZS1lJWklBV1VEQWdFRERUQU1CZ3BnaGtnQlpRTUNBUU1STUJJR0ExVWRFd0VCCi93UUlNQVlCQWY4Q0FRQXdEQVlEVlIwa0JBVXdBNEFCQURBM0JnTlZIUjhFTURBdU1DeWdLcUFvaGlab2RIUncKT2k4dlkzSnNMbVJwYzJFdWJXbHNMMk55YkM5RVQwUlNUMDlVUTBFekxtTnliREJzQmdnckJnRUZCUWNCQVFSZwpNRjR3T2dZSUt3WUJCUVVITUFLR0xtaDBkSEE2THk5amNtd3VaR2x6WVM1dGFXd3ZhWE56ZFdWa2RHOHZSRTlFClVrOVBWRU5CTTE5SlZDNXdOMk13SUFZSUt3WUJCUVVITUFHR0ZHaDBkSEE2THk5dlkzTndMbVJwYzJFdWJXbHMKTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCWkRSWXkwb1AreUQzT2lEcU0zbGlPZ2dERHFKaWREU2txbVBNQgpweFRMOWl5WENBcVM1T1VoektRMi9OOGdSWXpPMW83Sk5JcWV6N2t1d2oxSEowTEg5NGpianlNbnZyV1YzNG1oCm0xT3piRzF5Lzg4RnZoZVFYTGdsZCt0am9qeFlWaEVyYkZHSG54TVB3MVgwVnBiUlRXckFjZXRsZk1OS2R3UFUKQUgxR0RmRm1jenVTZnF3cVpjYXBnSmFsOUJXTUlKb0NYSDFzVU9IWG1nLzZhblh4MWQzME9IOWlUWVYwdG83NgpvSFRnNlBFdzdud3hORGdHY1ZnTERWeURBeVRwZlFDZmhWNGZTTEk5Y0RUczRuQTBTVWdVZ2EwMWQyaDFTcDRyCjBQdGtzakpJTkpsWXZMZ2d2Uld1Y0kvTW9rTHc1RjZtK3c2Qk4rdCtrRWdnTG42VAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RG9EIFJvb3QgQ0EgMwppc3N1ZXI9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSAzCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlEY3pDQ0FsdWdBd0lCQWdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURCYk1Rc3dDUVlEVlFRR0V3SlZVekVZCk1CWUdBMVVFQ2hNUFZTNVRMaUJIYjNabGNtNXRaVzUwTVF3d0NnWURWUVFMRXdORWIwUXhEREFLQmdOVkJBc1QKQTFCTFNURVdNQlFHQTFVRUF4TU5SRzlFSUZKdmIzUWdRMEVnTXpBZUZ3MHhNakF6TWpBeE9EUTJOREZhRncweQpPVEV5TXpBeE9EUTJOREZhTUZzeEN6QUpCZ05WQkFZVEFsVlRNUmd3RmdZRFZRUUtFdzlWTGxNdUlFZHZkbVZ5CmJtMWxiblF4RERBS0JnTlZCQXNUQTBSdlJERU1NQW9HQTFVRUN4TURVRXRKTVJZd0ZBWURWUVFERXcxRWIwUWcKVW05dmRDQkRRU0F6TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFxZXdVY29ybwpTM0NqMmhBRGhLYjdwellOS2pwU0ZyOHdGVktHQlVjZ3o2cW16WFhFWkc3djhXQWp5d3BtUUs2MHlHZ3FBRkZvClNUZnBXVEpObGJ4REorbEFqVG9RemhTOFF4aWgrZDdNNTRWMmMxNFlHaU5idlQ4Zjh1Mk5HY3dEMFVDa2o2Y2cKQWt3blduazI5cU0zSVk0QVdnWVd5dE5WbG04eEtidHlEc3ZpU0ZIeTFEZWtOZFp2N2hlenNRYXJDeG1HNkNOdApNUnNvZUdYRjNtSlN2TUY5Nis2Z1hWUUUrN0xMSzdJalZKR0NUUEMvdW5SQU93d0VSWUJuWE1Ycm9sZkRHbjhLCkxiMS91ZHpCbWJESUIrUU1oamFVT2lVdjhuM21sendibExTWFdRYkpPdVFMMmVycC9EdHpORy85NTVqazg2SEMKa0Y4YzlUOHUxeG5UZndJREFRQUJvMEl3UURBZEJnTlZIUTRFRmdRVWJJcVVvbmV4Z0hJZGdYb1dxdkxjem1idQpSY0F3RGdZRFZSMFBBUUgvQkFRREFnR0dNQThHQTFVZEV3RUIvd1FGTUFNQkFmOHdEUVlKS29aSWh2Y05BUUVMCkJRQURnZ0VCQUo5eHBNQzJsdEtBUTZCSTZSOTJCUG5GUEsxbUdGaGptOE8yNkdpS2hWcENaaEswMHVhTGlIK0gKOUpqMXFNWUp5Ui93TEIvc2dyajBwVWM0d1RNcjMweCttcjRMQzdITEQzeFFLQkRQaW8yaTZicXNodGZVc1pOZgpJbytXQmJST0RIV1JmZFB5NTVUQ2xCUjJUNDhNcXhDSFdES0ZCM1dHRWd0ZTZsTzBDc2hNaEpJZjYraEJoank2CjlFNUJTdEZzV0VkQnc0WmE4dTdwOHBnbmd1b3VOdGI0Qmw2QzhhQlNrMFFKdXRLcEdWcFlvNmhkSUcxUFpQZ3cKaHh1UUUwaUJ6Y3FReHczQjFKZy9qdklPVjJnekVvNlpDYkh3NVBZUTlEYnlTYjNxb3pqSVZrRWpnNXJmb1JzMQpmT3MvUWJQMWIwczZYcTV2azNhWTB2R1puVVhFam5JPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIFNXIENBLTU0Cmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDMKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVqekNDQTNlZ0F3SUJBZ0lDQVN3d0RRWUpLb1pJaHZjTkFRRUxCUUF3V3pFTE1Ba0dBMVVFQmhNQ1ZWTXgKR0RBV0JnTlZCQW9URDFVdVV5NGdSMjkyWlhKdWJXVnVkREVNTUFvR0ExVUVDeE1EUkc5RU1Rd3dDZ1lEVlFRTApFd05RUzBreEZqQVVCZ05WQkFNVERVUnZSQ0JTYjI5MElFTkJJRE13SGhjTk1UWXhNVEl5TVRNMU1USTRXaGNOCk1qSXhNVEl6TVRNMU1USTRXakJhTVFzd0NRWURWUVFHRXdKVlV6RVlNQllHQTFVRUNnd1BWUzVUTGlCSGIzWmwKY201dFpXNTBNUXd3Q2dZRFZRUUxEQU5FYjBReEREQUtCZ05WQkFzTUExQkxTVEVWTUJNR0ExVUVBd3dNUkU5RQpJRk5YSUVOQkxUVTBNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXEwd25hai9qClp6WFJuWm5ORE41ck1aVzdPbVBQY3JHKzhJUVc2b0hyZXRRcXZqL0hDbkF5WDNzbDVUdlQ2YkxDRzRVZkxCQXgKNFZSQ3Zwc1ZXOWZNRS80M0UrTjhweVVEamxoWWU4QkhPOWUwUmZiVmpNZ0RoNnRMYWd2ak4zTWZUaGc4RTk0Qwo2VFJpc2RpZmtQNldvbnBsTzFzYnY4WUQ0OUdqbUJXTHM4S3RVM3h6dy9TdFFyd05meW1ZOGFXNGxYSlFhL0NhCitGWHp6L3RSaDdNY2xybHo2UUN6Z2RIQWxpV0s0czV0c1hEeGVabHMyL3R2VGFaUUNWQ2l5Y2NEZGMvL2xZekwKVUl3ZzNsblBjb1Y2Q1BoaHcrUVc0cTQyWTRvU3U0OFo5Zy9mQXZxaHJLMVUwUzltSGwxdldMRFRISTNoa3dtZApUL08yV2dLaDhudng4d0lEQVFBQm80SUJYRENDQVZnd0h3WURWUjBqQkJnd0ZvQVViSXFVb25leGdISWRnWG9XCnF2TGN6bWJ1UmNBd0hRWURWUjBPQkJZRUZMQzNLTDhzQkltS2RDYXZxaE9NQWhCVmdYbXhNQTRHQTFVZER3RUIKL3dRRUF3SUJoakE5QmdOVkhTQUVOakEwTUFzR0NXQ0dTQUZsQWdFTEpEQUxCZ2xnaGtnQlpRSUJDeWN3Q3dZSgpZSVpJQVdVQ0FRc3FNQXNHQ1dDR1NBRmxBZ0VMT3pBU0JnTlZIUk1CQWY4RUNEQUdBUUgvQWdFQU1Bd0dBMVVkCkpBUUZNQU9BQVFBd053WURWUjBmQkRBd0xqQXNvQ3FnS0lZbWFIUjBjRG92TDJOeWJDNWthWE5oTG0xcGJDOWoKY213dlJFOUVVazlQVkVOQk15NWpjbXd3YkFZSUt3WUJCUVVIQVFFRVlEQmVNRG9HQ0NzR0FRVUZCekFDaGk1bwpkSFJ3T2k4dlkzSnNMbVJwYzJFdWJXbHNMMmx6YzNWbFpIUnZMMFJQUkZKUFQxUkRRVE5mU1ZRdWNEZGpNQ0FHCkNDc0dBUVVGQnpBQmhoUm9kSFJ3T2k4dmIyTnpjQzVrYVhOaExtMXBiREFOQmdrcWhraUc5dzBCQVFzRkFBT0MKQVFFQVpGMDQ3eVM4YnE4bGtNcG94RnJKam1iZEQxVE5wam5XUm1JbVEzMnVQd05rckRic3BOSjRHZHFBaDNONgp1ZUlNY1BVU21ySUVzOUdSWkdKek9lVFE2dGNRS0N5V3krbnBzSTFEUS9rNVh6MEgzNzVCdzE3Z25xMkJwamR5CnM4emVnOEkrMmxET2pTTnI3UmdWV1dCKzJzVldYZHZJTHg0V2toNnZYNTd1RXVkMDQ2SEJtYzROZURpSEFlcjgKTklhYzVBN2UzNzlOUnl1dXNOR1hrQW0zZzdHc0UvWTdNckZzS0tzTWxIYitnRlhWZ0QwREJodEYyMllxbUEvUgpRdlR6N0lqMUFEKytHdjVJNElJekpGTXJ5TjZFRDZYZHVXY1R0azlDbmYwdVkweitWWThSRnc5bk9rRUNGYzJiCkJBOEwyTGxydUJPek1XYkZ5NGtIN0cvaHJBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoKc3ViamVjdD0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURPRCBTVyBDQS01Mwppc3N1ZXI9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSAzCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFanpDQ0EzZWdBd0lCQWdJQ0FTc3dEUVlKS29aSWh2Y05BUUVMQlFBd1d6RUxNQWtHQTFVRUJoTUNWVk14CkdEQVdCZ05WQkFvVEQxVXVVeTRnUjI5MlpYSnViV1Z1ZERFTU1Bb0dBMVVFQ3hNRFJHOUVNUXd3Q2dZRFZRUUwKRXdOUVMwa3hGakFVQmdOVkJBTVREVVJ2UkNCU2IyOTBJRU5CSURNd0hoY05NVFl4TVRJeU1UTTFNRE0xV2hjTgpNakl4TVRJek1UTTFNRE0xV2pCYU1Rc3dDUVlEVlFRR0V3SlZVekVZTUJZR0ExVUVDZ3dQVlM1VExpQkhiM1psCmNtNXRaVzUwTVF3d0NnWURWUVFMREFORWIwUXhEREFLQmdOVkJBc01BMUJMU1RFVk1CTUdBMVVFQXd3TVJFOUUKSUZOWElFTkJMVFV6TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF3VGV3UzlpdgpDaFl0TXZOQllFT2pWY1ZxciszVk9BRWd5anQ3aWVKVVZQckZEZ3RMOVN6K2VYWCt1QlhrSndZalMwZ3RleDZMClJ1TnRkY0xrdWtvSnUzNFp4bmZVd2M4cmdUd05WOFZ0SXlJMkdKcS91L0ZqR3dLOGZIa3pzbE96d0Y4S29BNk4KTlRZdkt5OVhvaEJEcnJZR3BScS9SdUR0dFZmaUo0WXZjaWk1SjYrdVpUdlQ5MDM1RWtzcWpWN0Erc0prRlZxSQozTVo4M2tOOU8wWkpmNGRFajRoNERLcVFZSFRScnB5L0JMNHBUR3htU3BuUUhuZTYzVG9xc29abnRUWUNZaEI1CjZpek9ha2JzVVRZVmF1d1lxbE5WZjBqMjBJd2NaaWJ6dHA3d3FWMk5nR3pBODFMbmRoWUxRaCs4S3NEYWJUU1YKc1pNdkxIZkVBZUxkaHdJREFRQUJvNElCWERDQ0FWZ3dId1lEVlIwakJCZ3dGb0FVYklxVW9uZXhnSElkZ1hvVwpxdkxjem1idVJjQXdIUVlEVlIwT0JCWUVGRkhFaXpPWmxNQit1ellkNCtJNkJiMHlkSjFUTUE0R0ExVWREd0VCCi93UUVBd0lCaGpBOUJnTlZIU0FFTmpBME1Bc0dDV0NHU0FGbEFnRUxKREFMQmdsZ2hrZ0JaUUlCQ3ljd0N3WUoKWUlaSUFXVUNBUXNxTUFzR0NXQ0dTQUZsQWdFTE96QVNCZ05WSFJNQkFmOEVDREFHQVFIL0FnRUFNQXdHQTFVZApKQVFGTUFPQUFRQXdOd1lEVlIwZkJEQXdMakFzb0NxZ0tJWW1hSFIwY0RvdkwyTnliQzVrYVhOaExtMXBiQzlqCmNtd3ZSRTlFVWs5UFZFTkJNeTVqY213d2JBWUlLd1lCQlFVSEFRRUVZREJlTURvR0NDc0dBUVVGQnpBQ2hpNW8KZEhSd09pOHZZM0pzTG1ScGMyRXViV2xzTDJsemMzVmxaSFJ2TDBSUFJGSlBUMVJEUVROZlNWUXVjRGRqTUNBRwpDQ3NHQVFVRkJ6QUJoaFJvZEhSd09pOHZiMk56Y0M1a2FYTmhMbTFwYkRBTkJna3Foa2lHOXcwQkFRc0ZBQU9DCkFRRUFDWnR4WDlscjZzeWUwUlVTT0xZekxDVTRqVkROU1FnejNxcThLazdkSjk3R2RzdUJ6QUNjQ0l3RkRwTmQKdGpNdEQrbXdOamdmZVJZNW92eU1FSDNaelZoSXFHcFFvNFdMZUUrYmp5M2ZOY1UzcnNiMlNITmFFcFJkZFdRMwpqbk9jM2pseWcvc0hhUjZKZzRKZlExRzl6YTQ2QVJlVmExbkpMSGp0L0JPNW0vM0Q0aUptcEp2cTJRcDZONGVGCmEyVkw2czh1QVpLbkxDb2NqWlUyQjN3WVpNeWFTZ3BwYUU0VE9lL0hjNUhKdzI0NS9jRkxVTDhJMDJpWWZ2OUUKS1FEdVRHcU56R3JCdUtwOUxNcFJyQldiMGJvRnJaYU9OY1ZYanRDcWkwNWZvMUZkL0podXZmcmFUcGd4bVZYaQoxT3ZnVkd3cTVsc3hXMnBialNwQkZlYmFSdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCnN1YmplY3Q9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1ET0QgSUQgQ0EtNTIKaXNzdWVyPS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RG9EIFJvb3QgQ0EgMwotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRXVUQ0NBNkdnQXdJQkFnSUNBU293RFFZSktvWklodmNOQVFFTEJRQXdXekVMTUFrR0ExVUVCaE1DVlZNeApHREFXQmdOVkJBb1REMVV1VXk0Z1IyOTJaWEp1YldWdWRERU1NQW9HQTFVRUN4TURSRzlFTVF3d0NnWURWUVFMCkV3TlFTMGt4RmpBVUJnTlZCQU1URFVSdlJDQlNiMjkwSUVOQklETXdIaGNOTVRZeE1USXlNVE0wT1RVM1doY04KTWpJeE1USXpNVE0wT1RVM1dqQmFNUXN3Q1FZRFZRUUdFd0pWVXpFWU1CWUdBMVVFQ2d3UFZTNVRMaUJIYjNabApjbTV0Wlc1ME1Rd3dDZ1lEVlFRTERBTkViMFF4RERBS0JnTlZCQXNNQTFCTFNURVZNQk1HQTFVRUF3d01SRTlFCklFbEVJRU5CTFRVeU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBbHR6Y01wMk8KMDJ0K2Z3ZDdyVGx1Z29LcVlGOGVvLzNNK0pWZHBwUEFIVGlKVmFWdDBKU2VNNHh5WnNLTm9QQm9GVy95c2hueApsUnYvTHlOeDBWQmJuKzRtSjdFYTFVNEZCUHhDU1o2OFZZcUtkVjY0VU1obmRhd1ZCSk0zT3k4WTNaeFBsZFRECmY5QXBDZzRkWlhTRWlTblNoTzhZdXBock5iWUFkNllyZFVuMUloREFodzkwVlRVM0dNTHJ1NHZ4NjB2RkhzY1cKZVpIcEhmRVQ4QXNDbGJBeXF1NjVic2ExK28wWHZHTFF5MkdUTXpFVmFSMU5oWVZXS1JTd2dxVzU3Z2JFOHBWKwo2M1dZTndpOFhJci8yVGFKNUd2Z0JWQ2JnSldBd3NTZkZUejIxWnFPb3UwZDV4WXU3OWlJSXVlNURFb1JXMWJtCnFzZXJITkc3Z3NNdkh3SURBUUFCbzRJQmhqQ0NBWUl3SHdZRFZSMGpCQmd3Rm9BVWJJcVVvbmV4Z0hJZGdYb1cKcXZMY3ptYnVSY0F3SFFZRFZSME9CQllFRkpyb1VheVJWTmVVbWdSSStpSjUvOGJWN29Zck1BNEdBMVVkRHdFQgovd1FFQXdJQmhqQm5CZ05WSFNBRVlEQmVNQXNHQ1dDR1NBRmxBZ0VMSkRBTEJnbGdoa2dCWlFJQkN5Y3dDd1lKCllJWklBV1VDQVFzcU1Bc0dDV0NHU0FGbEFnRUxPekFNQmdwZ2hrZ0JaUU1DQVFNTk1Bd0dDbUNHU0FGbEF3SUIKQXhFd0RBWUtZSVpJQVdVREFnRURKekFTQmdOVkhSTUJBZjhFQ0RBR0FRSC9BZ0VBTUF3R0ExVWRKQVFGTUFPQQpBUUF3TndZRFZSMGZCREF3TGpBc29DcWdLSVltYUhSMGNEb3ZMMk55YkM1a2FYTmhMbTFwYkM5amNtd3ZSRTlFClVrOVBWRU5CTXk1amNtd3diQVlJS3dZQkJRVUhBUUVFWURCZU1Eb0dDQ3NHQVFVRkJ6QUNoaTVvZEhSd09pOHYKWTNKc0xtUnBjMkV1Yldsc0wybHpjM1ZsWkhSdkwwUlBSRkpQVDFSRFFUTmZTVlF1Y0Rkak1DQUdDQ3NHQVFVRgpCekFCaGhSb2RIUndPaTh2YjJOemNDNWthWE5oTG0xcGJEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFreHZkCnNiT2gyekdaQ3NqM251OWZIRU1DbEpWdEs0a0p6UEpaUGk0NGdkU24rVThYNWxidFQwa3hzUnJxQ0FabnRsZ1EKbXArRHhuUUNscjM1ZmphbzN3Rjc5blFhSU9QMjc4OWE5VldaZ3lKZlByVjJLTHN4QUg0L29PZDJaWWRVdEhmQwpsYmZad2JweEZ1bEJxUFd4eXNLUU94M1hDLzNMc3pDUjBZRnFiVi9jNWhCUkIxQTRzV0JsRjhLUkdReUtkQXljCks3UHJMY1NNbkxxMDR1Z2Q1TWZZV3VKakp4L1VTTk5XbGlsL0x6cXlDRnp4UHA0bkdCQjh5OHMyTGNaeXZvZmgKSElCTjlxeGwzK0VYY0p5ZXlxeU5pVlpjZ0ppK0RMU21CQ2NrYjJKNmxOOXRiR1dWMDJXSys4T2lBaVozMUNmSgovc2V6WjU4RVpheUdZUzAzMVE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIElEIENBLTUxCmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDMKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUV1VENDQTZHZ0F3SUJBZ0lDQVNrd0RRWUpLb1pJaHZjTkFRRUxCUUF3V3pFTE1Ba0dBMVVFQmhNQ1ZWTXgKR0RBV0JnTlZCQW9URDFVdVV5NGdSMjkyWlhKdWJXVnVkREVNTUFvR0ExVUVDeE1EUkc5RU1Rd3dDZ1lEVlFRTApFd05RUzBreEZqQVVCZ05WQkFNVERVUnZSQ0JTYjI5MElFTkJJRE13SGhjTk1UWXhNVEl5TVRNME9USTNXaGNOCk1qSXhNVEl6TVRNME9USTNXakJhTVFzd0NRWURWUVFHRXdKVlV6RVlNQllHQTFVRUNnd1BWUzVUTGlCSGIzWmwKY201dFpXNTBNUXd3Q2dZRFZRUUxEQU5FYjBReEREQUtCZ05WQkFzTUExQkxTVEVWTUJNR0ExVUVBd3dNUkU5RQpJRWxFSUVOQkxUVXhNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQWpqdERzL2lMClRJZjI1dDlTR0dNUDQ5Z0NGSVlYY0V0dlR0Yy92aCtDZ2hmN3FWd2lOdlVZQ2FHTXE1cTdGL3BnTDV4c3c2Qm4KaUNNYXUyYlp0TGZsNXhuTWsyVk1sMkdSd1VheUhRLzBseXRlZUtpZDZmYThzZm5seU5MaDhsdlB1SHFRRkpaWAo1dnBmQUMyNE5EUUNycjhZSWtrTlJ5eEppaENwajhISFl1elRwbERSSXBNbGphaGhBV0NzUWtVcWxxLzVMaXRlClhIWUEvK0VuVDJoc3BraXRTVStGVUlXbzBGS0s5NW9vK2kydVhYOHgzY1hXRVVDWG9SMjNTbGs1TnJHVHdBc2YKVFVkMTZ4V0ExYWN2a3N1bng4ZUszdU9WQ1YwMlEwc2xkVk4xOU5hR204bHBvQmZidGlOejNsby9qMVZUNTU4cQozNUxtT1lXSTZLelNUd0lEQVFBQm80SUJoakNDQVlJd0h3WURWUjBqQkJnd0ZvQVViSXFVb25leGdISWRnWG9XCnF2TGN6bWJ1UmNBd0hRWURWUjBPQkJZRUZKMmt3VnpUK1daeFNhaUVJd08yNGE4cGR5MnVNQTRHQTFVZER3RUIKL3dRRUF3SUJoakJuQmdOVkhTQUVZREJlTUFzR0NXQ0dTQUZsQWdFTEpEQUxCZ2xnaGtnQlpRSUJDeWN3Q3dZSgpZSVpJQVdVQ0FRc3FNQXNHQ1dDR1NBRmxBZ0VMT3pBTUJncGdoa2dCWlFNQ0FRTU5NQXdHQ21DR1NBRmxBd0lCCkF4RXdEQVlLWUlaSUFXVURBZ0VESnpBU0JnTlZIUk1CQWY4RUNEQUdBUUgvQWdFQU1Bd0dBMVVkSkFRRk1BT0EKQVFBd053WURWUjBmQkRBd0xqQXNvQ3FnS0lZbWFIUjBjRG92TDJOeWJDNWthWE5oTG0xcGJDOWpjbXd2UkU5RQpVazlQVkVOQk15NWpjbXd3YkFZSUt3WUJCUVVIQVFFRVlEQmVNRG9HQ0NzR0FRVUZCekFDaGk1b2RIUndPaTh2ClkzSnNMbVJwYzJFdWJXbHNMMmx6YzNWbFpIUnZMMFJQUkZKUFQxUkRRVE5mU1ZRdWNEZGpNQ0FHQ0NzR0FRVUYKQnpBQmhoUm9kSFJ3T2k4dmIyTnpjQzVrYVhOaExtMXBiREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBaWdRNAphT2R1VFVDcER2QzB1ZTBCMEdWNDlCMGFlazhIWFdLYzEwYlBiMWlVQ1FMMkRUNGFJZjB1K3lRcXJ6VnBUdy94CjVtVlBSbjJaaTJpRVY1QThQc040ZFJlRjNsYmxRU3JTVnZLRnc3Y3E2Nlo4YWIyaWpYanBBTVRKQ1VJT2lyOHcKS29PVjAzY25WY2FXMFZEVEgrZ09zbFhubTk1a1BxZGZieEpNaDA2UTAwWGZ2V2ZSamZuQjlEOFpEWGJ5dE01WApta1pSeXVVdldZK0RLeUpVeTFIQXVhcmRhRnBnQTVXb3dqZVFtOXNBdng3Mkx6YVM3em12K2h4T2xpR1hZT243CmdiSkFUY1QrenQxRmZ3YTlNMTlGam9RRFN6V2loVzhQNWNGUnQ2eFZFd1pIZUQ4VkcrK2pjUWZBdWp3WDB2N1UKaEZLdThneG0zd2xOWE9hbHpBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoKc3ViamVjdD0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURPRCBJRCBDQS01MAppc3N1ZXI9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSAzCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFdVRDQ0E2R2dBd0lCQWdJQ0FTZ3dEUVlKS29aSWh2Y05BUUVMQlFBd1d6RUxNQWtHQTFVRUJoTUNWVk14CkdEQVdCZ05WQkFvVEQxVXVVeTRnUjI5MlpYSnViV1Z1ZERFTU1Bb0dBMVVFQ3hNRFJHOUVNUXd3Q2dZRFZRUUwKRXdOUVMwa3hGakFVQmdOVkJBTVREVVJ2UkNCU2IyOTBJRU5CSURNd0hoY05NVFl4TVRJeU1UTTBPRFEzV2hjTgpNakl4TVRJek1UTTBPRFEzV2pCYU1Rc3dDUVlEVlFRR0V3SlZVekVZTUJZR0ExVUVDZ3dQVlM1VExpQkhiM1psCmNtNXRaVzUwTVF3d0NnWURWUVFMREFORWIwUXhEREFLQmdOVkJBc01BMUJMU1RFVk1CTUdBMVVFQXd3TVJFOUUKSUVsRUlFTkJMVFV3TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF5MW5jTTFiTgpKSkhpdTFCaDVqUThyK1kxTDJwdncrNllETEdFNzF6NWdxdUJxaXNPQzZYTEtmZktkQlNGMlU1NXZ2cDBtNUo4CldkRjVEU2Z5ZmRBSjdTMUhsekZZVlcrMEtqR0xFTEtWNXRXWmgvYVh1OFY4NVphYVlrdkplZUVVNWNJWVdMS0sKUkFyMWl5Z3duc2xoeTFLYjd4aFlWN2dMWWMyOVdtMUVnWmlKMlhtOU0xMUZJYXVvNDBFWG1RRm5pejRGTEUvUwo0SkIxbGJZaVAxakdhNHpKcmRuZWMxazY1dFprL0s0aGRpMmRpUys5bUVVejNQV3J6TnFqckhLeEZvY25oOXFTCk5HcUpmeWZYeFhnS1RyWncyVUc4M0l4SEt2SXBNUG9kWDRTWVV3Um01SFJickc2YzFGeDEyTkMyZ28xNnczZEQKaWxIK2FVZHVUTnBtRlFJREFRQUJvNElCaGpDQ0FZSXdId1lEVlIwakJCZ3dGb0FVYklxVW9uZXhnSElkZ1hvVwpxdkxjem1idVJjQXdIUVlEVlIwT0JCWUVGRFl1VXQ1MHFwN3N1eCtUMGI2MlVMWEdhUXY1TUE0R0ExVWREd0VCCi93UUVBd0lCaGpCbkJnTlZIU0FFWURCZU1Bc0dDV0NHU0FGbEFnRUxKREFMQmdsZ2hrZ0JaUUlCQ3ljd0N3WUoKWUlaSUFXVUNBUXNxTUFzR0NXQ0dTQUZsQWdFTE96QU1CZ3BnaGtnQlpRTUNBUU1OTUF3R0NtQ0dTQUZsQXdJQgpBeEV3REFZS1lJWklBV1VEQWdFREp6QVNCZ05WSFJNQkFmOEVDREFHQVFIL0FnRUFNQXdHQTFVZEpBUUZNQU9BCkFRQXdOd1lEVlIwZkJEQXdMakFzb0NxZ0tJWW1hSFIwY0RvdkwyTnliQzVrYVhOaExtMXBiQzlqY213dlJFOUUKVWs5UFZFTkJNeTVqY213d2JBWUlLd1lCQlFVSEFRRUVZREJlTURvR0NDc0dBUVVGQnpBQ2hpNW9kSFJ3T2k4dgpZM0pzTG1ScGMyRXViV2xzTDJsemMzVmxaSFJ2TDBSUFJGSlBUMVJEUVROZlNWUXVjRGRqTUNBR0NDc0dBUVVGCkJ6QUJoaFJvZEhSd09pOHZiMk56Y0M1a2FYTmhMbTFwYkRBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQWJBbGkKbzcrZ1dYNVl5dG1QTUQ5aWMrYVgyczBOYVNkU2F1RlltYjZraHROMENDb2NJcVRJL1R5ZlJKVGpoSTZ3Uk5vYQpja2NqVmE1SDNFT3A0dk9ydExONFR4YmhOcWRFK0lIYWZXRTQvYnREc3RJNVByQTJobEZaYjF6dk01RVFDOHUwCkJaUS9EcXlTaE9qeXB2eGxkdm9sNlVHanlzN3dlY1B4dDNjQkpDN3Vyb1krbnFmeEhuT0l4UkZvSkdkQzdwU20KZjkwL3VEY1g4N29DYksvRnJ6SkJPKy9WMmxHSGlCeUM3YWhjUDU5YTRYZDY5bEhTTXRSV3F1Y2xBeUJFeTFNeApwN0J4L3Y1a0NwdjE0SkU2U0JsWUV3aEZyVHQ0YVQ0OUZRRVE5YUpGS1J2N2oyMHNTLzZ3eFB6R3gyNEhFMEdiClh3dXNLOWpvNXNrR0xMVUMzZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCnN1YmplY3Q9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1ET0QgSUQgQ0EtNDkKaXNzdWVyPS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RG9EIFJvb3QgQ0EgMwotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRXVUQ0NBNkdnQXdJQkFnSUNBU2N3RFFZSktvWklodmNOQVFFTEJRQXdXekVMTUFrR0ExVUVCaE1DVlZNeApHREFXQmdOVkJBb1REMVV1VXk0Z1IyOTJaWEp1YldWdWRERU1NQW9HQTFVRUN4TURSRzlFTVF3d0NnWURWUVFMCkV3TlFTMGt4RmpBVUJnTlZCQU1URFVSdlJDQlNiMjkwSUVOQklETXdIaGNOTVRZeE1USXlNVE0wT0RFMVdoY04KTWpJeE1USXpNVE0wT0RFMVdqQmFNUXN3Q1FZRFZRUUdFd0pWVXpFWU1CWUdBMVVFQ2d3UFZTNVRMaUJIYjNabApjbTV0Wlc1ME1Rd3dDZ1lEVlFRTERBTkViMFF4RERBS0JnTlZCQXNNQTFCTFNURVZNQk1HQTFVRUF3d01SRTlFCklFbEVJRU5CTFRRNU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMkVuZ0tJd1AKQ2w5K2RzSUJ5TzJ1T05OTEtocG5GeXBCQUUrTE04K2tla3Q0L0hHNlN0YVUvZm1xRlRSaVZJMFVoK3RkOUJXZQo4TlhPWXJoUVJvNkZWU3hCa0x0V1pYOFB4MklIeGlxUTFsbnJaSzlVbENvOGgzTVBwaU44VkVqSDJiUC9XU2EwCm9aRVd6RURLTEI1dFNLZXJkZGMrUUwydUVIYitHZnltNmkrNXFQT0xYalYwMEZZMjRGZE5PeUhhUmpRVE0vTGYKc2pXb0ZJdEhUS3A1QjlRb2dkS255ZytXa0FBUll0YmQxbnF0RFh2NkZwaDVIYVQzOVNFblJoYytsa3JSRHBEWQpjK0hBVTZYeXdpaytzdGd2MnlGazFNaEZwRjUvcm5kRXdNTElTVDArbFNwYWhKS0dtWXRnMVZLY25EY3E1Q0VSCkMzMWdsNllyN2ZmakF3SURBUUFCbzRJQmhqQ0NBWUl3SHdZRFZSMGpCQmd3Rm9BVWJJcVVvbmV4Z0hJZGdYb1cKcXZMY3ptYnVSY0F3SFFZRFZSME9CQllFRk5obms4cEczTW1WcHBTekJCaWN6aVU2bGh4Tk1BNEdBMVVkRHdFQgovd1FFQXdJQmhqQm5CZ05WSFNBRVlEQmVNQXNHQ1dDR1NBRmxBZ0VMSkRBTEJnbGdoa2dCWlFJQkN5Y3dDd1lKCllJWklBV1VDQVFzcU1Bc0dDV0NHU0FGbEFnRUxPekFNQmdwZ2hrZ0JaUU1DQVFNTk1Bd0dDbUNHU0FGbEF3SUIKQXhFd0RBWUtZSVpJQVdVREFnRURKekFTQmdOVkhSTUJBZjhFQ0RBR0FRSC9BZ0VBTUF3R0ExVWRKQVFGTUFPQQpBUUF3TndZRFZSMGZCREF3TGpBc29DcWdLSVltYUhSMGNEb3ZMMk55YkM1a2FYTmhMbTFwYkM5amNtd3ZSRTlFClVrOVBWRU5CTXk1amNtd3diQVlJS3dZQkJRVUhBUUVFWURCZU1Eb0dDQ3NHQVFVRkJ6QUNoaTVvZEhSd09pOHYKWTNKc0xtUnBjMkV1Yldsc0wybHpjM1ZsWkhSdkwwUlBSRkpQVDFSRFFUTmZTVlF1Y0Rkak1DQUdDQ3NHQVFVRgpCekFCaGhSb2RIUndPaTh2YjJOemNDNWthWE5oTG0xcGJEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFUbWZQClFQa29sRjVQQjBmUy85RHJuZ1gwdG1kU3dsaWRCdHJrWTZ2TC9WN0lNS3FKazdyK2hIVzZrOStueGlqSEZqNlkKSjErNEVscEgvUHdXUHNxd1ZJc2hReEVDdkpLZm8zT2ZOM2E4TW42SG9nNWtYSmw1ZE1iMHZKT3BXUTlVaG1HMgptOVVVWjk4NDd3U2xiVzB2TUhMMHB1dVRzbzAzNjV2aWxQTzVKa2FwRVhjRlhkYzNMRHhYVzhCUjVOSHlhTjNWCm12ZkQvcUFxZTRCaUJ4MitXQXhzb2xUSlE1SU1qRzV0SU43V0U2VkpkVUFtNkVJZ2J1RmZ2RzFLaVdRSkxIa0wKWGRUdndkVVRxWDlKUVlzd2Z2b0N3dkhSaCtJMm1aWCsvaUg1SEtMY2F4cVc4YjlKbkhDdGZNU0JacUxkSTNuRwpJQnc0OHRSdWw4bGJyZzBtSnc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIEVNQUlMIENBLTUyCmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDMKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUV2RENDQTZTZ0F3SUJBZ0lDQVNZd0RRWUpLb1pJaHZjTkFRRUxCUUF3V3pFTE1Ba0dBMVVFQmhNQ1ZWTXgKR0RBV0JnTlZCQW9URDFVdVV5NGdSMjkyWlhKdWJXVnVkREVNTUFvR0ExVUVDeE1EUkc5RU1Rd3dDZ1lEVlFRTApFd05RUzBreEZqQVVCZ05WQkFNVERVUnZSQ0JTYjI5MElFTkJJRE13SGhjTk1UWXhNVEl5TVRNME56STRXaGNOCk1qSXhNVEl6TVRNME56STRXakJkTVFzd0NRWURWUVFHRXdKVlV6RVlNQllHQTFVRUNnd1BWUzVUTGlCSGIzWmwKY201dFpXNTBNUXd3Q2dZRFZRUUxEQU5FYjBReEREQUtCZ05WQkFzTUExQkxTVEVZTUJZR0ExVUVBd3dQUkU5RQpJRVZOUVVsTUlFTkJMVFV5TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF3NHBiCnFGWjVMUG05Z2NXVDI0bENqOHlMUUhZZHpudFRXZ01xUFZ5dmVHODhyQStiWGlBV082eldVc2pQbFlRSGZ4aU4KcVRaZW1LZ0s4T1VrVlFBNG9pUTU5RXpjTmlSc1pwMWh5N252RHBGY1cvMFdKekhZNU04NFRoSTU3elJIMjBBYwppTncxREI3WG1SNXlKRktURnVzaXBXZ3Nxd1dSVHRwSmxMR0pYaFRIeUc2YU54UDZIRVhiVExBTTR4LzBMTTlaClEyeVlpaFV1Zmd0SllHZUxhcE5iMXBQTHNQVmNoaEpPUWpMRnlwM0t4OVcxeGZqVUZmdEU5RlFBd0NCSkh5QzcKdEZNazZEbElUeTRzN3B0c3Qxbk5iUFlkekdtaWl4L1A3K0k3MDJZbjhIM1libWhGRDNkK2ZraENYcXNqaW8weQowd1dGRGFhNnZtbTNScUYxR1FJREFRQUJvNElCaGpDQ0FZSXdId1lEVlIwakJCZ3dGb0FVYklxVW9uZXhnSElkCmdYb1dxdkxjem1idVJjQXdIUVlEVlIwT0JCWUVGT2xtREZ5YjRscEtzZ00yTlAxOHlhYjRxd2M1TUE0R0ExVWQKRHdFQi93UUVBd0lCaGpCbkJnTlZIU0FFWURCZU1Bc0dDV0NHU0FGbEFnRUxKREFMQmdsZ2hrZ0JaUUlCQ3ljdwpDd1lKWUlaSUFXVUNBUXNxTUFzR0NXQ0dTQUZsQWdFTE96QU1CZ3BnaGtnQlpRTUNBUU1OTUF3R0NtQ0dTQUZsCkF3SUJBeEV3REFZS1lJWklBV1VEQWdFREp6QVNCZ05WSFJNQkFmOEVDREFHQVFIL0FnRUFNQXdHQTFVZEpBUUYKTUFPQUFRQXdOd1lEVlIwZkJEQXdMakFzb0NxZ0tJWW1hSFIwY0RvdkwyTnliQzVrYVhOaExtMXBiQzlqY213dgpSRTlFVWs5UFZFTkJNeTVqY213d2JBWUlLd1lCQlFVSEFRRUVZREJlTURvR0NDc0dBUVVGQnpBQ2hpNW9kSFJ3Ck9pOHZZM0pzTG1ScGMyRXViV2xzTDJsemMzVmxaSFJ2TDBSUFJGSlBUMVJEUVROZlNWUXVjRGRqTUNBR0NDc0cKQVFVRkJ6QUJoaFJvZEhSd09pOHZiMk56Y0M1a2FYTmhMbTFwYkRBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQQpkWUVmdVRrQm9KTHd6eUlaL2xyeEIzRUNDZXMyeldNTGUxUnNSclEzUVVoa2VMY3F4eHdHMXorVWJibVdrclNTCkpTMFExWGVMUmlUN1AxeCt5Y3MxR3ZveTVWNENGT3J5YjVlTmFEcE9jbEpkWE9pUmpPR3ZTMHdTZVNMR25UL2QKbFJQclFaY29FbStERnZ0U01hc3UvelI4RG5hZXBLcFdMdnlGWHd2b2ltdnNRVnZ6NHRPUzJvNHU0MDBLTFBCbwpNUWJUd3BEbWszOXd4ZjRBcTRtOGh6bmYyQmhBeTIwWUg2alkwOGdYZzBwTkRWaDRDWkl4eUYyZ21FMFREWFB2CnN4NzdseFlLVzNCeDBaeEhJY2ZCS2lmalNpVHJHbExlRVA5TGZFUWRwQ2pKcWhHLzNCRnk2Zmx6d0pERUhxSEgKc3doTjlEQ0puKzN4VGVxMjVQVVhQZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCnN1YmplY3Q9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1ET0QgRU1BSUwgQ0EtNTEKaXNzdWVyPS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RG9EIFJvb3QgQ0EgMwotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRXZEQ0NBNlNnQXdJQkFnSUNBU1V3RFFZSktvWklodmNOQVFFTEJRQXdXekVMTUFrR0ExVUVCaE1DVlZNeApHREFXQmdOVkJBb1REMVV1VXk0Z1IyOTJaWEp1YldWdWRERU1NQW9HQTFVRUN4TURSRzlFTVF3d0NnWURWUVFMCkV3TlFTMGt4RmpBVUJnTlZCQU1URFVSdlJDQlNiMjkwSUVOQklETXdIaGNOTVRZeE1USXlNVE0wTmpRNVdoY04KTWpJeE1USXpNVE0wTmpRNVdqQmRNUXN3Q1FZRFZRUUdFd0pWVXpFWU1CWUdBMVVFQ2d3UFZTNVRMaUJIYjNabApjbTV0Wlc1ME1Rd3dDZ1lEVlFRTERBTkViMFF4RERBS0JnTlZCQXNNQTFCTFNURVlNQllHQTFVRUF3d1BSRTlFCklFVk5RVWxNSUVOQkxUVXhNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQW53N1AKVGFqNVVHU01pOHdoeEdwUHNvQ2hHTWpWUVJrMUZ6cDlKL21Qangvb1hjMk13TWFoSzN4cEUzWUI4NnEvU2VIMQpDdjVoYzlQYTk5SHRTRi9SYUhBbzNmckZvUG5STm9QRExqNmloUEdtRVd3TUt5d1VnT0NuVFFjR1NsTnFSMGVzCnRZck1UeHRpOWJLRTN1YzBoZ1dpYlpZbHVraUdZZzBVeWdZUFM0K2FmTXR6YUJsamlVV2VRRnJtQ2FFZ2VHM0IKVXZYL3pnTmRTcXRHOUtYMUxqcXROWkI5MWhJRHJSVU5vaFg1eFNMeFBNcG9qQzVkMzkxdS8wR2ZBRVhlS3lBeQpiUE44QmRWanFKN0ZseXVlVktVZ0lBQi90L2s2Tk8zbEtFaUMrUXNyaHJ3YUZJM1ltZTlKZlJzWlU4L1lodjBMCndLZUpob3ozNTUyb1QwZTRQd0lEQVFBQm80SUJoakNDQVlJd0h3WURWUjBqQkJnd0ZvQVViSXFVb25leGdISWQKZ1hvV3F2TGN6bWJ1UmNBd0hRWURWUjBPQkJZRUZEWHZFQ0pzdWhJUHZjSk5HZVRPZlk4RlYxdzBNQTRHQTFVZApEd0VCL3dRRUF3SUJoakJuQmdOVkhTQUVZREJlTUFzR0NXQ0dTQUZsQWdFTEpEQUxCZ2xnaGtnQlpRSUJDeWN3CkN3WUpZSVpJQVdVQ0FRc3FNQXNHQ1dDR1NBRmxBZ0VMT3pBTUJncGdoa2dCWlFNQ0FRTU5NQXdHQ21DR1NBRmwKQXdJQkF4RXdEQVlLWUlaSUFXVURBZ0VESnpBU0JnTlZIUk1CQWY4RUNEQUdBUUgvQWdFQU1Bd0dBMVVkSkFRRgpNQU9BQVFBd053WURWUjBmQkRBd0xqQXNvQ3FnS0lZbWFIUjBjRG92TDJOeWJDNWthWE5oTG0xcGJDOWpjbXd2ClJFOUVVazlQVkVOQk15NWpjbXd3YkFZSUt3WUJCUVVIQVFFRVlEQmVNRG9HQ0NzR0FRVUZCekFDaGk1b2RIUncKT2k4dlkzSnNMbVJwYzJFdWJXbHNMMmx6YzNWbFpIUnZMMFJQUkZKUFQxUkRRVE5mU1ZRdWNEZGpNQ0FHQ0NzRwpBUVVGQnpBQmhoUm9kSFJ3T2k4dmIyTnpjQzVrYVhOaExtMXBiREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBClkyVUtITWk5OG1zbE5KOXFVQlQ4Wk5HS2ltK25Za2ZMZkJnZFAxMzZzbUpZWURjd1VPWHdIdDNiMWFPeTRzWEkKMEJrTk5TNnRPNWZkdlo3VzQvellGb3VJVm5JbWFhOGhqRGlKTm9BaTVkWUtEeGtCOGlPV1lsQVA4VFp3cEtOeQpzYkdoNEVRSFdXUTh3RHVGY2RBNS85RWxueHBRL0pKelNnVU9IaHRHbTh2ckVRbW1KS1cwRnZiR1hoR3lkSHgyCkk1R3REdkdIcWxwRjhHRklBQTVITkFhdzFzNURlMlN0RVlDVFMveTk1bmFxWmFmQ3hZRzYyY0diSGlyOGRwMFUKS1FPVVF0ODh0VGgwVEFxemNMS3oxT0pJb0lrYmZwelY2WGlYdUwwVlNvYitXMHBlWmVxVFZxK3c3bldQMWNOcgo0NGxpZ3d3VmplRjA0TDNzWktBNTR3PT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoKc3ViamVjdD0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURPRCBFTUFJTCBDQS01MAppc3N1ZXI9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSAzCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFdkRDQ0E2U2dBd0lCQWdJQ0FTUXdEUVlKS29aSWh2Y05BUUVMQlFBd1d6RUxNQWtHQTFVRUJoTUNWVk14CkdEQVdCZ05WQkFvVEQxVXVVeTRnUjI5MlpYSnViV1Z1ZERFTU1Bb0dBMVVFQ3hNRFJHOUVNUXd3Q2dZRFZRUUwKRXdOUVMwa3hGakFVQmdOVkJBTVREVVJ2UkNCU2IyOTBJRU5CSURNd0hoY05NVFl4TVRJeU1UTTBOVEF3V2hjTgpNakl4TVRJek1UTTBOVEF3V2pCZE1Rc3dDUVlEVlFRR0V3SlZVekVZTUJZR0ExVUVDZ3dQVlM1VExpQkhiM1psCmNtNXRaVzUwTVF3d0NnWURWUVFMREFORWIwUXhEREFLQmdOVkJBc01BMUJMU1RFWU1CWUdBMVVFQXd3UFJFOUUKSUVWTlFVbE1JRU5CTFRVd01JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBb3JVNQpmd01LWEt3SzRTcnR0b3p2V2I4Wng5Zys3cEdyekQrY2JhWmJJU3JUdk5UaTlNaERZQVNNbzIzbnpHL1NoSFFNCmMwcUNjMTBBVlVxcEFmd1JobTlGYnBoRDNyMzBTV0tRc3JLZU9iQlc2M2lNZUI2Z2ZoZy8relNjdmtKeGxxajYKeDVjSGdsTUNGUWZkcWpnbWp0Y3VXSUdyN2NEZjFXUUpMR2ZDejZpbEtIL0gybm8wYTNBeW9GRUFnbHJVeWhDNQpuMElWc215cldZNEh5OUEvMHhlODRobCs2OGNKZkI0VkQrOEErWXJVcUVnc3BpcXpvY3Z6Y3VOL0dOZGVEOUx3ClhQcXlscW5GOFNOMEhZb0htamJpbXNjSW44NndDeEFSTzBzaVdaN2hTdHJjYmtiK2NnRm9ZNWFTY2RsZFVrbmkKWUkyY21SeTBDNWp2K3dBZlh3SURBUUFCbzRJQmhqQ0NBWUl3SHdZRFZSMGpCQmd3Rm9BVWJJcVVvbmV4Z0hJZApnWG9XcXZMY3ptYnVSY0F3SFFZRFZSME9CQllFRkdVS2UxMG1HekRLTGR6ODFuUEhIc0YvQkl6SU1BNEdBMVVkCkR3RUIvd1FFQXdJQmhqQm5CZ05WSFNBRVlEQmVNQXNHQ1dDR1NBRmxBZ0VMSkRBTEJnbGdoa2dCWlFJQkN5Y3cKQ3dZSllJWklBV1VDQVFzcU1Bc0dDV0NHU0FGbEFnRUxPekFNQmdwZ2hrZ0JaUU1DQVFNTk1Bd0dDbUNHU0FGbApBd0lCQXhFd0RBWUtZSVpJQVdVREFnRURKekFTQmdOVkhSTUJBZjhFQ0RBR0FRSC9BZ0VBTUF3R0ExVWRKQVFGCk1BT0FBUUF3TndZRFZSMGZCREF3TGpBc29DcWdLSVltYUhSMGNEb3ZMMk55YkM1a2FYTmhMbTFwYkM5amNtd3YKUkU5RVVrOVBWRU5CTXk1amNtd3diQVlJS3dZQkJRVUhBUUVFWURCZU1Eb0dDQ3NHQVFVRkJ6QUNoaTVvZEhSdwpPaTh2WTNKc0xtUnBjMkV1Yldsc0wybHpjM1ZsWkhSdkwwUlBSRkpQVDFSRFFUTmZTVlF1Y0Rkak1DQUdDQ3NHCkFRVUZCekFCaGhSb2RIUndPaTh2YjJOemNDNWthWE5oTG0xcGJEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUEKVm5MS3dSZFlCYVBuRU9OSm5UcEhvQzR6bklRTUhCc0VwUWJSOFA1ajQ5SVh0SFJqQ3BsNVBLUkl3dUFjK0ZmMwppeE0zanYvRytMQmkyNkcwWk5HWjRpSTExckozVEx4VXFIVDEyL1dYVHVTOTFqZVBBL2YzV0lIa0dCRUZlUnMrCndpUk9YU0F2ZXlNQXQxVGhLOUJpbDdCWWxMbXBnZmNpN2VpS0hDNk9sQTdWWm80T3JTMDNWWlRsYWFCYVU1VGUKK3RYOFhZUTdLbGxoOUxyZVhaMkNrczE0b05CbFM0dnpPY1pPcHcxYmFtYUViSUExM0lzR3lZL2tGN0xxU1BXMgpiN0p5NjI4T2JMZVUzYSswbG0rbklrakgyNUZEdnRmeEQ5KzJxUUhFcFJhUmNsc2t3SUdUbUEvVGcvWXJyUzJaCmFtOVJEKzZFL3RzZ0lJbFFFMDlORUE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIEVNQUlMIENBLTQ5Cmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDMKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUV2RENDQTZTZ0F3SUJBZ0lDQVNNd0RRWUpLb1pJaHZjTkFRRUxCUUF3V3pFTE1Ba0dBMVVFQmhNQ1ZWTXgKR0RBV0JnTlZCQW9URDFVdVV5NGdSMjkyWlhKdWJXVnVkREVNTUFvR0ExVUVDeE1EUkc5RU1Rd3dDZ1lEVlFRTApFd05RUzBreEZqQVVCZ05WQkFNVERVUnZSQ0JTYjI5MElFTkJJRE13SGhjTk1UWXhNVEl5TVRNME16RTBXaGNOCk1qSXhNVEl6TVRNME16RTBXakJkTVFzd0NRWURWUVFHRXdKVlV6RVlNQllHQTFVRUNnd1BWUzVUTGlCSGIzWmwKY201dFpXNTBNUXd3Q2dZRFZRUUxEQU5FYjBReEREQUtCZ05WQkFzTUExQkxTVEVZTUJZR0ExVUVBd3dQUkU5RQpJRVZOUVVsTUlFTkJMVFE1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF1czIzCnh0T0FiZkx4UGgrT1M4VTNOL2M3WnNuVE5aR2tpNktqbkVnNEVWSG5VS3dCQjFwV0xlUWJaVFZwMDFkSFdseFIKS3l2QU5uays4b3pNOHR1Y293eDBxNmZvNUovWXRlRDlxSEZBb1dqSlFwUkI2SHZuMnZ2SHZVYnU3aUFZNVBlbAowQjZBME5OL2xLVzI2dFRsaW02TmtWMU11Q2N2cENHcndIMGYyVE9DemtEZjdJUHFRRHZMV09qUFFQOW5tTk1HCm5TK3FDdkY1RjBpR0ZYVEgxTkRlSThFUHZLTUJRRStMZ0o0UEFGOGVGZERvMG1ERTZpTGZQQUlYQnpmWVVkRmsKTVMzZVZwSk9XUHpPRVllUkxjV1FrT1J2Y3pmeE4wb2J4U0gzVEdvQkxCM3ViRUxPb2lxZ3NURjdyTEtFMUt5egpXcmFvMTV1b1lmMjlPOWphdFFJREFRQUJvNElCaGpDQ0FZSXdId1lEVlIwakJCZ3dGb0FVYklxVW9uZXhnSElkCmdYb1dxdkxjem1idVJjQXdIUVlEVlIwT0JCWUVGR2xFSHhxVlRxVWFmNGc2ekhzU09Td2Z6eG94TUE0R0ExVWQKRHdFQi93UUVBd0lCaGpCbkJnTlZIU0FFWURCZU1Bc0dDV0NHU0FGbEFnRUxKREFMQmdsZ2hrZ0JaUUlCQ3ljdwpDd1lKWUlaSUFXVUNBUXNxTUFzR0NXQ0dTQUZsQWdFTE96QU1CZ3BnaGtnQlpRTUNBUU1OTUF3R0NtQ0dTQUZsCkF3SUJBeEV3REFZS1lJWklBV1VEQWdFREp6QVNCZ05WSFJNQkFmOEVDREFHQVFIL0FnRUFNQXdHQTFVZEpBUUYKTUFPQUFRQXdOd1lEVlIwZkJEQXdMakFzb0NxZ0tJWW1hSFIwY0RvdkwyTnliQzVrYVhOaExtMXBiQzlqY213dgpSRTlFVWs5UFZFTkJNeTVqY213d2JBWUlLd1lCQlFVSEFRRUVZREJlTURvR0NDc0dBUVVGQnpBQ2hpNW9kSFJ3Ck9pOHZZM0pzTG1ScGMyRXViV2xzTDJsemMzVmxaSFJ2TDBSUFJGSlBUMVJEUVROZlNWUXVjRGRqTUNBR0NDc0cKQVFVRkJ6QUJoaFJvZEhSd09pOHZiMk56Y0M1a2FYTmhMbTFwYkRBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQQpYRE5rYUQyR3dlNFpvV2tsd3ZBdnZlb09ZSzVzOGZKYmpaT2pJMlYxdFpqSVA1ZWR3OFlTdkxER1Rxc2FEbGFvCjI4aENWaG9PVTArVjIzNHAwQ0FHS05LSUQ2V0NSNDZzN3VBQUxhYVdmZDRhSER6ZjIwcVlzbk1ybDBlS0N2NkYKc1V0S0JrSVlKQmp4cG9hSXB1ZFJDblNtUWt4d2VLekNHQ3RqV0NUMk1HU0pybzJRMGVRV1REeG5KWDkvdjh6NwpkWjhkZFpPMXpnb1UxeG5BeDlMeGRyVmw2SDJWY0IxN3o2dDJkNVRxU0xNL09udVNIVDdMV3FZYlZKRVJmMzhEClUwV1NRN1ZPcDJ4MVNrSW5KcXBld3ZpKzBybC95aDk3VW9EWnVTL0dVa1ZJTUZicEprYmNhZGlFR0JJTkVyUmwKUjV2UVpEZXNCcEdxVXhOWXVJSUpiQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCnN1YmplY3Q9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1ET0QgSUQgQ0EtNDAKaXNzdWVyPS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RG9EIFJvb3QgQ0EgMgotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRXVEQ0NBNkNnQXdJQkFnSUNCOFF3RFFZSktvWklodmNOQVFFRkJRQXdXekVMTUFrR0ExVUVCaE1DVlZNeApHREFXQmdOVkJBb1REMVV1VXk0Z1IyOTJaWEp1YldWdWRERU1NQW9HQTFVRUN4TURSRzlFTVF3d0NnWURWUVFMCkV3TlFTMGt4RmpBVUJnTlZCQU1URFVSdlJDQlNiMjkwSUVOQklESXdIaGNOTVRVeE1UQTVNVFF5TWpVMFdoY04KTWpFeE1UQTRNVFF5TWpVMFdqQmFNUXN3Q1FZRFZRUUdFd0pWVXpFWU1CWUdBMVVFQ2hNUFZTNVRMaUJIYjNabApjbTV0Wlc1ME1Rd3dDZ1lEVlFRTEV3TkViMFF4RERBS0JnTlZCQXNUQTFCTFNURVZNQk1HQTFVRUF4TU1SRTlFCklFbEVJRU5CTFRRd01JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBc0MwRmJXc0kKbGE2K05mSEQ2M0dSZUx0ODVGNGpkenM1bWxOclhralZsWEp6a3NhSWttbEhmcUFXeW82ZWE4U2hocXdkTm5YZwpQbEliN2VqNFJvWEZxWEpJd3NDcnhRN3JlditzQ2RrTDVVdHhPeFBxNDB3YmpWK0FjakY4UW1wOXhvUHlJbXh6CmxMZWJXV0o4SERnSmwySFNMcklGaWJyUkZlRDB0NkdMc1Q4SmhPZFFtcUU4d1JOeXBaSDZvREloeWdYM2xoQmUKUkR4dUsvNnpMTUorc3JxRzhETUpGSmh6MGtIaDM2dWdiSkpPUEx5RUd4d2p5RWljQnFrNDRORmNtcjhZV0MyNApSTTI4UWpydXF3b3Rsc0kzd29DYVRIa1ZtMzdmYzB4bWJBUGc0ZWdneHJ6WG4zZEZRRStjdzQwV0JMcHkwZDBHCjA1UE1BQzFMS1BkY2N3SURBUUFCbzRJQmhUQ0NBWUV3SFFZRFZSME9CQllFRk0xYmw1WDkxQ2VxNXlYeG5JZlcKOGdmWDBZYytNQjhHQTFVZEl3UVlNQmFBRkVsMHV3eGV1bnIrQWxUdmU2REdsY1lKZ0hDV01CSUdBMVVkRXdFQgovd1FJTUFZQkFmOENBUUF3REFZRFZSMGtCQVV3QTRBQkFEQU9CZ05WSFE4QkFmOEVCQU1DQVlZd1pnWURWUjBnCkJGOHdYVEFMQmdsZ2hrZ0JaUUlCQ3dVd0N3WUpZSVpJQVdVQ0FRc0pNQXNHQ1dDR1NBRmxBZ0VMRVRBTEJnbGcKaGtnQlpRSUJDeEl3Q3dZSllJWklBV1VDQVFzVE1Bd0dDbUNHU0FGbEF3SUJBeG93REFZS1lJWklBV1VEQWdFRApHekEzQmdOVkhSOEVNREF1TUN5Z0txQW9oaVpvZEhSd09pOHZZM0pzTG1ScGMyRXViV2xzTDJOeWJDOUVUMFJTClQwOVVRMEV5TG1OeWJEQnNCZ2dyQmdFRkJRY0JBUVJnTUY0d09nWUlLd1lCQlFVSE1BS0dMbWgwZEhBNkx5OWoKY213dVpHbHpZUzV0YVd3dmFYTnpkV1ZrZEc4dlJFOUVVazlQVkVOQk1sOUpWQzV3TjJNd0lBWUlLd1lCQlFVSApNQUdHRkdoMGRIQTZMeTl2WTNOd0xtUnBjMkV1Yldsc01BMEdDU3FHU0liM0RRRUJCUVVBQTRJQkFRQkZSaFgyCml6YVhtNVl1NG9tRHcybWJObzU5RVlBYUlUUUNjVUtiSzZwd2ttUllJQ3U4RHNqTE1WaGNpT2dlSzRmbjRPRkEKbVliTFhXQXRnU2tuTmMrSHVnYjRXRm9MV1NiM0VLWnM4b2NiL2ZSNGVKTE9Lb1kxUHVSQ3VvelM0eVpGUGV0OApSRkluWDhsN05RNDFaeXU0TzRRTnptY016NHBjdDBFKzduT2lzR0VqaDcvMjlRMFVtSVRQZWs2MGlWR0VCSXp6CnNramxjbFB6dTcrcUpzZU1GK2NJVitEVTVoRnRFalhaNUhQbjRmUzJCL0ZhMTV2a2JuQTlNdmt4akZZamdMYTYKWGIvM3pINXlZTjJiMjBGbHVDeFd5V0QyOVVLWFM1dnduWFZHbjRkK0xJdDVMUFhia2dZdDd1eGdHQ0lrWDJoYQpoUjBMNTFZejlxMy9zVnZtCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCnN1YmplY3Q9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1ET0QgSUQgQ0EtMzkKaXNzdWVyPS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RG9EIFJvb3QgQ0EgMgotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRXVEQ0NBNkNnQXdJQkFnSUNCOE13RFFZSktvWklodmNOQVFFRkJRQXdXekVMTUFrR0ExVUVCaE1DVlZNeApHREFXQmdOVkJBb1REMVV1VXk0Z1IyOTJaWEp1YldWdWRERU1NQW9HQTFVRUN4TURSRzlFTVF3d0NnWURWUVFMCkV3TlFTMGt4RmpBVUJnTlZCQU1URFVSdlJDQlNiMjkwSUVOQklESXdIaGNOTVRVeE1UQTVNVFF5TVRVM1doY04KTWpFeE1UQTRNVFF5TVRVM1dqQmFNUXN3Q1FZRFZRUUdFd0pWVXpFWU1CWUdBMVVFQ2hNUFZTNVRMaUJIYjNabApjbTV0Wlc1ME1Rd3dDZ1lEVlFRTEV3TkViMFF4RERBS0JnTlZCQXNUQTFCTFNURVZNQk1HQTFVRUF4TU1SRTlFCklFbEVJRU5CTFRNNU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBeUh1a010Y1YKSTlNdVV2aEM1NUpsdGVBUHVnRkgwaUVsbnVPSDF1U1Q5RlFWd0N1ZUlnWkVYRlExSHRReUsvTi9EdDJuTTg5UQpGVDZsSjU1a0FQaEp0cVlwR1pZZGZyaXJ4V1JUTnppc1FJMkdvRFR6SUQ5aU1ZeGQ0d1Rpa0R2dVRwVjRIMHMxCnNVNnI5VXFkb3VSRk1aK1ByQ2xIeVRqaThQOVBySFk2K1lTU0xYdTc2ZkpnZktOZERCdElHYVVoVEE5Q01PWHYKVEpHSkxpWlR1VmlKb2JQOWhBRVd0Z2QvOEMyR0lkVHdiUVBiL1I3ZnNNL2pvSDk0SFg1OUEwMFE2cTJDT3oxSgpHNkxCL0dxdmZJR3BJeDJObUx4NmJlUkRRMU9wQ3MzbXpxVVRYbWZRcFpENnZ3ZVRYa3lJR3FsRWdhdjV5YWh2CnZqbTJQcDdPM1ZqYkV3SURBUUFCbzRJQmhUQ0NBWUV3SFFZRFZSME9CQllFRktyRGs5eHdEM2xST1FRZDVmOHAKNkJiSXJwUEdNQjhHQTFVZEl3UVlNQmFBRkVsMHV3eGV1bnIrQWxUdmU2REdsY1lKZ0hDV01CSUdBMVVkRXdFQgovd1FJTUFZQkFmOENBUUF3REFZRFZSMGtCQVV3QTRBQkFEQU9CZ05WSFE4QkFmOEVCQU1DQVlZd1pnWURWUjBnCkJGOHdYVEFMQmdsZ2hrZ0JaUUlCQ3dVd0N3WUpZSVpJQVdVQ0FRc0pNQXNHQ1dDR1NBRmxBZ0VMRVRBTEJnbGcKaGtnQlpRSUJDeEl3Q3dZSllJWklBV1VDQVFzVE1Bd0dDbUNHU0FGbEF3SUJBeG93REFZS1lJWklBV1VEQWdFRApHekEzQmdOVkhSOEVNREF1TUN5Z0txQW9oaVpvZEhSd09pOHZZM0pzTG1ScGMyRXViV2xzTDJOeWJDOUVUMFJTClQwOVVRMEV5TG1OeWJEQnNCZ2dyQmdFRkJRY0JBUVJnTUY0d09nWUlLd1lCQlFVSE1BS0dMbWgwZEhBNkx5OWoKY213dVpHbHpZUzV0YVd3dmFYTnpkV1ZrZEc4dlJFOUVVazlQVkVOQk1sOUpWQzV3TjJNd0lBWUlLd1lCQlFVSApNQUdHRkdoMGRIQTZMeTl2WTNOd0xtUnBjMkV1Yldsc01BMEdDU3FHU0liM0RRRUJCUVVBQTRJQkFRQ3Z4emRkCis3ZnlNK2V4aWluOHBMWUlBRGtKNHBVRW5PM3h4YXlxRXZpRmdEL2txeTZWSW5TSVdQK2VhalhzVEFIUXdzVWkKYVY5aThiYStlanBacGtVODNYZ3lXUjg3M1AwVnljZzRvMnBVZHgxamhYem9NcUVxL2laQnZWNlNFS3FIUm1LMwo4ZVowbXpBZXZBRTh2RWZyOG8xUnR3b1BPKzRVaDZwWnBCY2o0TldZZ0w5bCtDRG90bEtpdkFNSXkwbk4rTkZKCjRTcVBXWE9EaG1GbEJzQ3RHWTBzSldSV245c0dpMGthRVUwc095cWZTbkd3Y2hUUzM0RDdNdWFEWWs3VXNneDMKU3RvL0NwcDdzY21Ic1ZxNTZldm9uOVlIVnhjbFQzTm9XS3k5SEh4c01JalZWQUVHcFhPWjA1TFlXNk8wMkVkcwpvWi8wVURzYThBOGFWNWFMCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCnN1YmplY3Q9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1ET0QgRU1BSUwgQ0EtNDAKaXNzdWVyPS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RG9EIFJvb3QgQ0EgMgotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRXV6Q0NBNk9nQXdJQkFnSUNCOEl3RFFZSktvWklodmNOQVFFRkJRQXdXekVMTUFrR0ExVUVCaE1DVlZNeApHREFXQmdOVkJBb1REMVV1VXk0Z1IyOTJaWEp1YldWdWRERU1NQW9HQTFVRUN4TURSRzlFTVF3d0NnWURWUVFMCkV3TlFTMGt4RmpBVUJnTlZCQU1URFVSdlJDQlNiMjkwSUVOQklESXdIaGNOTVRVeE1UQTVNVFF4T0RReldoY04KTWpFeE1UQTRNVFF4T0RReldqQmRNUXN3Q1FZRFZRUUdFd0pWVXpFWU1CWUdBMVVFQ2hNUFZTNVRMaUJIYjNabApjbTV0Wlc1ME1Rd3dDZ1lEVlFRTEV3TkViMFF4RERBS0JnTlZCQXNUQTFCTFNURVlNQllHQTFVRUF4TVBSRTlFCklFVk5RVWxNSUVOQkxUUXdNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXpOamcKTzZYTU5Yc1hxT1BFazlRN1ptUzhvM0pOYjFOaG12QzVocGZSdUE3R1VEVDBlRkpZdDB1V2dNcUZkU3ZNVHJScwpKVzg2UmZXbnVBejlkbnN6Z1VQY2ZpbXArNkxOeTN5RWIvTlVXUVhpaVlDS211RExvOFlXa2tmem9NSUF6VkgrCkR5Kyt3emM3bE9uZ201WmdEemRWdUdkL1FSUTg4MEh5SjlIWW5KRmtNVDl2WHZsYllETjdIb3BJV0pudHBlYWEKdHF1ZHdtMjlJejN3cTYvd2JhOHREZDZhV25Pd2ZSZkw5dUNlOEVHdXc0eEpoMXV2cEZmTXEyTjVHaFVJYjZrUwpxNGdhaSt0K2IyY2ZOSjJPSXdLUW55c2ZjTzVrSm5lMVphNG9JN0dQMDNJRHRSeXlndkJBTk9UckJueEtVaE1YCk1qYkN4UnhOR202L0dKQ3o1UUlEQVFBQm80SUJoVENDQVlFd0hRWURWUjBPQkJZRUZKdUJ0cUpaaSszcGdCL3cKSnoxWEJUNkpMN2JNTUI4R0ExVWRJd1FZTUJhQUZFbDB1d3hldW5yK0FsVHZlNkRHbGNZSmdIQ1dNQklHQTFVZApFd0VCL3dRSU1BWUJBZjhDQVFBd0RBWURWUjBrQkFVd0E0QUJBREFPQmdOVkhROEJBZjhFQkFNQ0FZWXdaZ1lEClZSMGdCRjh3WFRBTEJnbGdoa2dCWlFJQkN3VXdDd1lKWUlaSUFXVUNBUXNKTUFzR0NXQ0dTQUZsQWdFTEVUQUwKQmdsZ2hrZ0JaUUlCQ3hJd0N3WUpZSVpJQVdVQ0FRc1RNQXdHQ21DR1NBRmxBd0lCQXhvd0RBWUtZSVpJQVdVRApBZ0VER3pBM0JnTlZIUjhFTURBdU1DeWdLcUFvaGlab2RIUndPaTh2WTNKc0xtUnBjMkV1Yldsc0wyTnliQzlFClQwUlNUMDlVUTBFeUxtTnliREJzQmdnckJnRUZCUWNCQVFSZ01GNHdPZ1lJS3dZQkJRVUhNQUtHTG1oMGRIQTYKTHk5amNtd3VaR2x6WVM1dGFXd3ZhWE56ZFdWa2RHOHZSRTlFVWs5UFZFTkJNbDlKVkM1d04yTXdJQVlJS3dZQgpCUVVITUFHR0ZHaDBkSEE2THk5dlkzTndMbVJwYzJFdWJXbHNNQTBHQ1NxR1NJYjNEUUVCQlFVQUE0SUJBUUF2CnR5NXVHN3FjYm16VDJoVTFyaUMzV1VGN2ZZTjZxQ1JCR1JlMWJlemlacXI3TldzSllVV0R1OWlJdkhUUnNYZEkKU2dZZ3Rxc2VCbDl6Q21ZNDlpeVhXQk9zMjZSRjZDeVZPT2k5Y0RQTXp6dVhIZnNyRlJybGdvdHZnSS9JeEprdApESDQxR2JrRm14L3laWGtDZDh3RU01VWQ3R3k2MXpxdUV2RDFxc1lNOHFVdURDY1Qwc0I3MG5qS1ErRVRLUUJXCnVRZHFSRHlVU0hibkZaYUhTOC91R3BDTDkzaWU5dlZSSkVCdUdsMGZnSlhibFhEY0pzTTBZT1ZnTEltR0N4bmsKbGZXQ2FJQTdRdGtXbWQyNDlQUFIrS2dNMFdXK1FYSExFc1VMbzVpVXJaeE9nUFVvbzRhdUxSL0FsazRLRm1xbAo4QUplajJ6OWlNbWc2SmIxQmJHMQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIEVNQUlMIENBLTM5Cmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDIKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUV1ekNDQTZPZ0F3SUJBZ0lDQjhFd0RRWUpLb1pJaHZjTkFRRUZCUUF3V3pFTE1Ba0dBMVVFQmhNQ1ZWTXgKR0RBV0JnTlZCQW9URDFVdVV5NGdSMjkyWlhKdWJXVnVkREVNTUFvR0ExVUVDeE1EUkc5RU1Rd3dDZ1lEVlFRTApFd05RUzBreEZqQVVCZ05WQkFNVERVUnZSQ0JTYjI5MElFTkJJREl3SGhjTk1UVXhNVEE1TVRReE5EUTNXaGNOCk1qRXhNVEE0TVRReE5EUTNXakJkTVFzd0NRWURWUVFHRXdKVlV6RVlNQllHQTFVRUNoTVBWUzVUTGlCSGIzWmwKY201dFpXNTBNUXd3Q2dZRFZRUUxFd05FYjBReEREQUtCZ05WQkFzVEExQkxTVEVZTUJZR0ExVUVBeE1QUkU5RQpJRVZOUVVsTUlFTkJMVE01TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFzL0dnCnZkaWc3WDhhamZnaTFpcUhXTTNuK0dHb3F0OWNRd0dmT1Jib3dnakh3SURiN3ROUXFNUFJHMnBWWVNsU1Q1bmwKTmtvZStYUlRJL3ZoRXhNUll2VERrQm14Y0ZwSEFtaTRsVkZlWUhmR1l2WW43QWk5U25kYlRsSzRHOHR4OUJQdQpyWWpySTd6K1RZZGxOZmN4Y3FVOVp1czNMN1ZTam80Tnovb0d1MVFQZFozZTVXMjdtckJyR1ZvZGhZckdkOXpiCnZjbHpER0twQU5mcnJGNldtMC90MDcvajJvcFl1WERycDNDU1ZQZ0hYUkNMdWVESit4eUl0aDhvWi91cTdsMXUKTzJhKzR4aXhDUXB1R25UalZmQmtDMTlqU0c4V3lsS244Y3JkdVZQTENtUlRwNjVJWGdUQkFWNmdwanRhMXZlQQo4K2hGTEdzd3NTS3pWVHkyWXdJREFRQUJvNElCaFRDQ0FZRXdIUVlEVlIwT0JCWUVGS3lkK01STWM2QkRYd2dsCmZVWVBaUnZMb0xDQU1COEdBMVVkSXdRWU1CYUFGRWwwdXd4ZXVucitBbFR2ZTZER2xjWUpnSENXTUJJR0ExVWQKRXdFQi93UUlNQVlCQWY4Q0FRQXdEQVlEVlIwa0JBVXdBNEFCQURBT0JnTlZIUThCQWY4RUJBTUNBWVl3WmdZRApWUjBnQkY4d1hUQUxCZ2xnaGtnQlpRSUJDd1V3Q3dZSllJWklBV1VDQVFzSk1Bc0dDV0NHU0FGbEFnRUxFVEFMCkJnbGdoa2dCWlFJQkN4SXdDd1lKWUlaSUFXVUNBUXNUTUF3R0NtQ0dTQUZsQXdJQkF4b3dEQVlLWUlaSUFXVUQKQWdFREd6QTNCZ05WSFI4RU1EQXVNQ3lnS3FBb2hpWm9kSFJ3T2k4dlkzSnNMbVJwYzJFdWJXbHNMMk55YkM5RQpUMFJTVDA5VVEwRXlMbU55YkRCc0JnZ3JCZ0VGQlFjQkFRUmdNRjR3T2dZSUt3WUJCUVVITUFLR0xtaDBkSEE2Ckx5OWpjbXd1WkdsellTNXRhV3d2YVhOemRXVmtkRzh2UkU5RVVrOVBWRU5CTWw5SlZDNXdOMk13SUFZSUt3WUIKQlFVSE1BR0dGR2gwZEhBNkx5OXZZM053TG1ScGMyRXViV2xzTUEwR0NTcUdTSWIzRFFFQkJRVUFBNElCQVFDYQo4UW9CTDFJVmhjaSt4ZTFybk8yaEpsTW5LS1d3c1JYbXhDMHFxK3NTcWRFY3EwaG13REZsUWVLeUk3aEJ5cDYwCjlKK2k1eWh1NWViT0hHc1F1VTcxL0VOTUFNT2N6VVl0K01ZSm9jR2N3ZTFnMWIvWFp0WnNoZ285TjZHd3JsbnkKV0Z3YnI1Q25YNnlzd29vQm1VbDB4ZFl2Y2QvWlo2LzVkanVWVXU0bjYvYkl3YldjcWtreUVEUEdHRk5YeGVuVApEdVMzQmdSQWFnZ3lNY05oUU5kSDNnY2M4RGJRNTdsQjU3dUJOTzBjSGNhVmEyTmsrVEd0M2VSb0xUZXFOSG9TCjRaUWJnOXY0T2hBWkp0d2hLeWRDdHhaQWNIY3hMMnFGWE1pVDJvdHMvTm1XWnlTM3NKcVNnV2N6NzdhMnhSRWIKaXM3TDJzTTgvZjlsRG5weW15dXoKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoKc3ViamVjdD0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURPRCBJRCBTVyBDQS0zNgppc3N1ZXI9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSAyCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFdXpDQ0E2T2dBd0lCQWdJQ0I2RXdEUVlKS29aSWh2Y05BUUVGQlFBd1d6RUxNQWtHQTFVRUJoTUNWVk14CkdEQVdCZ05WQkFvVEQxVXVVeTRnUjI5MlpYSnViV1Z1ZERFTU1Bb0dBMVVFQ3hNRFJHOUVNUXd3Q2dZRFZRUUwKRXdOUVMwa3hGakFVQmdOVkJBTVREVVJ2UkNCU2IyOTBJRU5CSURJd0hoY05NVFV3T1RJek1UTTBORFF5V2hjTgpNakV3T1RJeU1UTTBORFF5V2pCZE1Rc3dDUVlEVlFRR0V3SlZVekVZTUJZR0ExVUVDaE1QVlM1VExpQkhiM1psCmNtNXRaVzUwTVF3d0NnWURWUVFMRXdORWIwUXhEREFLQmdOVkJBc1RBMUJMU1RFWU1CWUdBMVVFQXhNUFJFOUUKSUVsRUlGTlhJRU5CTFRNMk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBdG5rVwpZNkFsRCtNM2ppVmY5dmhzb2RzTEZHbm9pWWkzZFFvc2VpYk9yUFNVNTU1RnQvNUdIR21qK25DWFc5dHdSbUdwCkFja3d6V2FrTlI2bnlEaDU2YzVPaEp4V0tFZzU5NEIyaTlTQm1UWGljVHpCUGEzdFpOb0poNk1sNi9PZmNoK0cKWFI5dS9GRmREV3M3dWJFRjJLN3U4Mk1RVXNZaWYrdGVQUkFzc0kwQ1RvR1BGNVNQdzMrQ2NpakZ3WTczSkZGeQpteTU1Z1p0YjlqaUVFcDFhV3JJZ0o5bkpjenlXYkZPVjE1STV0WlBRaVdsYVhxMEJHRmgxaEppVEdoZ0dzM2ZaCkgreXFNbU9MOTFNc2I5dTk5VEFyNFI0QTZ5RFYvczMxM0prVjRrV0lKMUNOU1BaSHNYT1k1V1hqNnpxL0NEaE0KSnFvelVicmVKUkVGYWRBZnd3SURBUUFCbzRJQmhUQ0NBWUV3SFFZRFZSME9CQllFRkdjYU5qeTZ1MitGQStjagppSzNGWjVDbFRMcUVNQjhHQTFVZEl3UVlNQmFBRkVsMHV3eGV1bnIrQWxUdmU2REdsY1lKZ0hDV01CSUdBMVVkCkV3RUIvd1FJTUFZQkFmOENBUUF3REFZRFZSMGtCQVV3QTRBQkFEQU9CZ05WSFE4QkFmOEVCQU1DQVlZd1pnWUQKVlIwZ0JGOHdYVEFMQmdsZ2hrZ0JaUUlCQ3dVd0N3WUpZSVpJQVdVQ0FRc0pNQXNHQ1dDR1NBRmxBZ0VMRVRBTApCZ2xnaGtnQlpRSUJDeEl3Q3dZSllJWklBV1VDQVFzVE1Bd0dDbUNHU0FGbEF3SUJBeG93REFZS1lJWklBV1VECkFnRURHekEzQmdOVkhSOEVNREF1TUN5Z0txQW9oaVpvZEhSd09pOHZZM0pzTG1ScGMyRXViV2xzTDJOeWJDOUUKVDBSU1QwOVVRMEV5TG1OeWJEQnNCZ2dyQmdFRkJRY0JBUVJnTUY0d09nWUlLd1lCQlFVSE1BS0dMbWgwZEhBNgpMeTlqY213dVpHbHpZUzV0YVd3dmFYTnpkV1ZrZEc4dlJFOUVVazlQVkVOQk1sOUpWQzV3TjJNd0lBWUlLd1lCCkJRVUhNQUdHRkdoMGRIQTZMeTl2WTNOd0xtUnBjMkV1Yldsc01BMEdDU3FHU0liM0RRRUJCUVVBQTRJQkFRQjcKcjRSR2xWS3ZkcWVDQW9FcnB2VzEwV1JQSW40bW1NSmJPd3p3ZmdMUHpHS3ZuTlFSMENXUFdnYjhZN1FaWXRJVApjYkJjV0U4YXdad0IrT1dEZ1RPb3hyRDArZXVPdzJDdlpnMzZaMFA3bWJTNElGNkVseERkL3R6dzVIcXI4dmt3CmhIL0YyZjZrNyt0UnpudDQrY01Rd0ptSURLR3dvWiszQXRkN0NLY291QnpYWkxjTkViYm9oSkY1ejU0RVl3UlUKSjVhZ1BjblRaTUJEa1FmU3M5a3UxblByR1FmQVRFQnliTFRBZTMxdW50TTZvTXpNSHc4UFluM1NoN3hXVENERwpTRlNuUFloemxOS2RNYjhCS2kzc3BWT3h0NnQzVkh6TlhEbzhGWFJiTnBCWS9mUzdSQW1IUFByejVwYTlLTnRKCmNLRU5tSXFRNVFiakIvUDhVWDNpCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCnN1YmplY3Q9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1ET0QgRU1BSUwgQ0EtMzQKaXNzdWVyPS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RG9EIFJvb3QgQ0EgMgotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRXV6Q0NBNk9nQXdJQkFnSUNCNkF3RFFZSktvWklodmNOQVFFRkJRQXdXekVMTUFrR0ExVUVCaE1DVlZNeApHREFXQmdOVkJBb1REMVV1VXk0Z1IyOTJaWEp1YldWdWRERU1NQW9HQTFVRUN4TURSRzlFTVF3d0NnWURWUVFMCkV3TlFTMGt4RmpBVUJnTlZCQU1URFVSdlJDQlNiMjkwSUVOQklESXdIaGNOTVRVd09USXpNVE0wTVRVMFdoY04KTWpFd09USXlNVE0wTVRVMFdqQmRNUXN3Q1FZRFZRUUdFd0pWVXpFWU1CWUdBMVVFQ2hNUFZTNVRMaUJIYjNabApjbTV0Wlc1ME1Rd3dDZ1lEVlFRTEV3TkViMFF4RERBS0JnTlZCQXNUQTFCTFNURVlNQllHQTFVRUF4TVBSRTlFCklFVk5RVWxNSUVOQkxUTTBNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQWw5clAKSnlGM0ZNbFRrYlVDYnlSYkhQR2ZkOUs3UktkbW5DRTI1N2Voc05tN25NN1E5enhjOFNwYlRTRGJPYVAzV3FvdgpTNWJtc1NFK2xlV1IvTWhUR1Y0Vk1LenRabWtHZWE4V1lkNXpvb3orT3JtZnVveEVvQ3k1Q2l5YStSVCt3TE93CkgwQXBENGRvSWtya1pkMlEyWkplTC84cEREajFoUEFNTHBUZkpiZWtOc1EzaHNXbktwN0FXVnNsaVk0bFI4dTAKUlltWDRMSFlNNWhOK3FmNnVpT0xLNlUvcGNYY3lSYTN5bXhpcXEwZ2tWS3F6eWJxS2psRjRKdWNVVTl6VGMvUgpjbTJYU1FFRmw1bmlHSTFZUlJjcndHZGw4OFRFWXFjRDhMZnFBZkt0Vkh2S3k2blE0OUwyUzhxWFFpN3A5RG1CCmJHZjBjOWdaRnhHMlNBbzE5d0lEQVFBQm80SUJoVENDQVlFd0hRWURWUjBPQkJZRUZBK0dXWDdqK3VjVCt6RTcKd1RrTWZHQ0xRTUxkTUI4R0ExVWRJd1FZTUJhQUZFbDB1d3hldW5yK0FsVHZlNkRHbGNZSmdIQ1dNQklHQTFVZApFd0VCL3dRSU1BWUJBZjhDQVFBd0RBWURWUjBrQkFVd0E0QUJBREFPQmdOVkhROEJBZjhFQkFNQ0FZWXdaZ1lEClZSMGdCRjh3WFRBTEJnbGdoa2dCWlFJQkN3VXdDd1lKWUlaSUFXVUNBUXNKTUFzR0NXQ0dTQUZsQWdFTEVUQUwKQmdsZ2hrZ0JaUUlCQ3hJd0N3WUpZSVpJQVdVQ0FRc1RNQXdHQ21DR1NBRmxBd0lCQXhvd0RBWUtZSVpJQVdVRApBZ0VER3pBM0JnTlZIUjhFTURBdU1DeWdLcUFvaGlab2RIUndPaTh2WTNKc0xtUnBjMkV1Yldsc0wyTnliQzlFClQwUlNUMDlVUTBFeUxtTnliREJzQmdnckJnRUZCUWNCQVFSZ01GNHdPZ1lJS3dZQkJRVUhNQUtHTG1oMGRIQTYKTHk5amNtd3VaR2x6WVM1dGFXd3ZhWE56ZFdWa2RHOHZSRTlFVWs5UFZFTkJNbDlKVkM1d04yTXdJQVlJS3dZQgpCUVVITUFHR0ZHaDBkSEE2THk5dlkzTndMbVJwYzJFdWJXbHNNQTBHQ1NxR1NJYjNEUUVCQlFVQUE0SUJBUUJVCjlDOXkwMy81YlQvSTA5Y2ZCVEpEaGdQNXpvRm00NXhUemZBNDdFTmc5emo3Vm50RVVHOUtINGxrZ25JeHJEK3AKaHg1a0daZ3B4SzIxOE1XbFFLV3V0WXRyRmVlUytSQmlzeVZFR0V0RjJKallFbVE0ZFVBT2ZWRXkyaUUvNmpsZwo3SldCM25QTkNWWWpXc3ZZQXdydGNpY2xNL3hkQWJ1Qm0xdmFsbjVURkd3cDNVUU5NZmtiaVlzNmx1VnViUG1PCjc2MHJ1ekNKeUR3Y09vcGJyYVpKM0JOcU1WYlBITDY4YXhwazhtS0U4M2s2V2dxTVlJRXNvbEEyRjk1T1NQdUIKKzNqakM2VTBmZWhTejVVZDR4bUZkRlY0QWlXNm1nQ1l5MVJaeHdQTzdIb3Z4alJzK3RnOFV0d2NPam5WQlBwTQo1UWg4KzhCRVVzN3NqS2xvdzF0SAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIElEIENBLTM0Cmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDIKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUV1RENDQTZDZ0F3SUJBZ0lDQjU4d0RRWUpLb1pJaHZjTkFRRUZCUUF3V3pFTE1Ba0dBMVVFQmhNQ1ZWTXgKR0RBV0JnTlZCQW9URDFVdVV5NGdSMjkyWlhKdWJXVnVkREVNTUFvR0ExVUVDeE1EUkc5RU1Rd3dDZ1lEVlFRTApFd05RUzBreEZqQVVCZ05WQkFNVERVUnZSQ0JTYjI5MElFTkJJREl3SGhjTk1UVXdPVEl6TVRNME1ETXdXaGNOCk1qRXdPVEl5TVRNME1ETXdXakJhTVFzd0NRWURWUVFHRXdKVlV6RVlNQllHQTFVRUNoTVBWUzVUTGlCSGIzWmwKY201dFpXNTBNUXd3Q2dZRFZRUUxFd05FYjBReEREQUtCZ05WQkFzVEExQkxTVEVWTUJNR0ExVUVBeE1NUkU5RQpJRWxFSUVOQkxUTTBNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXo3QXQvd01NCnFwSTU2c1JyUWxwaHl0N2hUVVlpdFFtYTJqWUhST2NVcWFST2NxVzdRK3NaUXVINWxFTkxsUlA2eGQvbUlZYWMKK3czOTBFMmtQYk1Rd0E0NnliMzk5TFR2ZTdwSm9ldWtkZk5VaGdMdEJKMVI5S2czSVJKaGdyOEo5dm5ZNW01Uwp5K01zR0tod0E1WEhjR3RKdEMwTmlLWXV4bnFacEhwYTRwREhORmFSUUZsK25rYTEySzE1cXhQZ3lmNitybzRtCkxISmNEMk1rL0tFODJFVGxCZ0k1VFJ4eFNWTGVPOVBuRlBjTnlMTXhEMklLZS8xemRvSFRwRFU2bElFamxuMnYKMjJRTjJJYnIxSEJ3T0FDd0lUV2VNTXI5dFVnMmZRdElCekxreWJKYld4Z285SjVrUHBvcVFpaDJFbzZaS2t5NQpkU2RjdU9RcndyMk9Zd0lEQVFBQm80SUJoVENDQVlFd0hRWURWUjBPQkJZRUZCZ2tUTDFXbG8vRXlPUDlCV1dMCm1JamppSERHTUI4R0ExVWRJd1FZTUJhQUZFbDB1d3hldW5yK0FsVHZlNkRHbGNZSmdIQ1dNQklHQTFVZEV3RUIKL3dRSU1BWUJBZjhDQVFBd0RBWURWUjBrQkFVd0E0QUJBREFPQmdOVkhROEJBZjhFQkFNQ0FZWXdaZ1lEVlIwZwpCRjh3WFRBTEJnbGdoa2dCWlFJQkN3VXdDd1lKWUlaSUFXVUNBUXNKTUFzR0NXQ0dTQUZsQWdFTEVUQUxCZ2xnCmhrZ0JaUUlCQ3hJd0N3WUpZSVpJQVdVQ0FRc1RNQXdHQ21DR1NBRmxBd0lCQXhvd0RBWUtZSVpJQVdVREFnRUQKR3pBM0JnTlZIUjhFTURBdU1DeWdLcUFvaGlab2RIUndPaTh2WTNKc0xtUnBjMkV1Yldsc0wyTnliQzlFVDBSUwpUMDlVUTBFeUxtTnliREJzQmdnckJnRUZCUWNCQVFSZ01GNHdPZ1lJS3dZQkJRVUhNQUtHTG1oMGRIQTZMeTlqCmNtd3VaR2x6WVM1dGFXd3ZhWE56ZFdWa2RHOHZSRTlFVWs5UFZFTkJNbDlKVkM1d04yTXdJQVlJS3dZQkJRVUgKTUFHR0ZHaDBkSEE2THk5dlkzTndMbVJwYzJFdWJXbHNNQTBHQ1NxR1NJYjNEUUVCQlFVQUE0SUJBUUFHeHlwcgo5bWJRdmRZMnRoQ0ozQU5EdUluMU1LOEloaVgzV2U1am9Cc2htVGNmaDcxREZLc052VXBzNEJQZGpmTkdjSG5nCkNUbGdId2U0TUVzTnpVcFNrRDNlMm5tN2pQcmlYaDR0Ukw1UkpGRUs2eXhETCtrM0xUTDBjL2dWampoc25ab2kKbXIyYThKb1d5RFVWZFVKbUhseTRNNkd0RFd3Mmw2Q2lFcm8zTHYzcEV1VVJyZ0UrZGVtcTNXTWhiNUladzcrTgpaaTRHYXBkT05YL2ErZTMwMjhIOUtWT0MySWJmSDlGWkdoTDk2ZzVZdEFTZCt0d0t5ZEFlbjYxTkU0OXdZWnFaCnJuMEUyUHl3UVNxWmppdWlFTTlGM1FOekdWZDlnZXV4NFRJWXZ6eVFsMHl3V2tpbVpsQ1FQa1FVZS9oT1VkWlcKTUZKZkF5OEVXOHo0WHNQYwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgpzdWJqZWN0PS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RE9EIElEIFNXIENBLTM1Cmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDIKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUV1ekNDQTZPZ0F3SUJBZ0lDQjU0d0RRWUpLb1pJaHZjTkFRRUZCUUF3V3pFTE1Ba0dBMVVFQmhNQ1ZWTXgKR0RBV0JnTlZCQW9URDFVdVV5NGdSMjkyWlhKdWJXVnVkREVNTUFvR0ExVUVDeE1EUkc5RU1Rd3dDZ1lEVlFRTApFd05RUzBreEZqQVVCZ05WQkFNVERVUnZSQ0JTYjI5MElFTkJJREl3SGhjTk1UVXdPVEl6TVRNek56VXdXaGNOCk1qRXdPVEl5TVRNek56VXdXakJkTVFzd0NRWURWUVFHRXdKVlV6RVlNQllHQTFVRUNoTVBWUzVUTGlCSGIzWmwKY201dFpXNTBNUXd3Q2dZRFZRUUxFd05FYjBReEREQUtCZ05WQkFzVEExQkxTVEVZTUJZR0ExVUVBeE1QUkU5RQpJRWxFSUZOWElFTkJMVE0xTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFpdlhZCmVEUDhHSkIrYW80emxhL1VFdEpES0VmbHdPU2RhOGtHeGtmYno5bU1MUUZCMGlhbUhhK2cvbGRndWxJVXIvcHIKdXBVYjk1OVEyaTI2R3JXSFJvemdXbmlPZExVNi9YNFpRbmljMmNNOGVqaXQ5VEs0NWpHbXI5S3JrNytHdnQraQpYdERIVFZBUUt5VkpPS0JaeWV4RkUvekJlR2pFdjVkNHRuTHkycmpxcmdmc2tYVEFZVEJKZk9rSnZIb2dtdVAyCmhyTWNFa0MvYjZMWUFBRnk3b2JWZG1aY3Y3QjljNGJyem1sNlpkVy9IanAvUzlaK3FZK1duRHIraG5iTjBPYysKcXhBYXhaeFk3a01CTUJDRU1YSDl3Qm5HRkVWUTBDRlc5MTh6WUtYYUlEaXprY01DQzdHbE9SS0duUWgzZ3hLbgpyN05PYzVtU2xWSzZXNWF6OXdJREFRQUJvNElCaFRDQ0FZRXdIUVlEVlIwT0JCWUVGTjdDUm1QSkIvV3NFaHlxCm1SRWRIK3BUNWxReU1COEdBMVVkSXdRWU1CYUFGRWwwdXd4ZXVucitBbFR2ZTZER2xjWUpnSENXTUJJR0ExVWQKRXdFQi93UUlNQVlCQWY4Q0FRQXdEQVlEVlIwa0JBVXdBNEFCQURBT0JnTlZIUThCQWY4RUJBTUNBWVl3WmdZRApWUjBnQkY4d1hUQUxCZ2xnaGtnQlpRSUJDd1V3Q3dZSllJWklBV1VDQVFzSk1Bc0dDV0NHU0FGbEFnRUxFVEFMCkJnbGdoa2dCWlFJQkN4SXdDd1lKWUlaSUFXVUNBUXNUTUF3R0NtQ0dTQUZsQXdJQkF4b3dEQVlLWUlaSUFXVUQKQWdFREd6QTNCZ05WSFI4RU1EQXVNQ3lnS3FBb2hpWm9kSFJ3T2k4dlkzSnNMbVJwYzJFdWJXbHNMMk55YkM5RQpUMFJTVDA5VVEwRXlMbU55YkRCc0JnZ3JCZ0VGQlFjQkFRUmdNRjR3T2dZSUt3WUJCUVVITUFLR0xtaDBkSEE2Ckx5OWpjbXd1WkdsellTNXRhV3d2YVhOemRXVmtkRzh2UkU5RVVrOVBWRU5CTWw5SlZDNXdOMk13SUFZSUt3WUIKQlFVSE1BR0dGR2gwZEhBNkx5OXZZM053TG1ScGMyRXViV2xzTUEwR0NTcUdTSWIzRFFFQkJRVUFBNElCQVFDVwpGOHJ2S3l4N1l0bk10b25WL0x5UFhVSHBDbkZiR2VnOGRyWjdxTktMVnh4THJhVkJTczZyUXoxWGlLVGN5enB1CnpZZlB5RElIdnhhdWdrSmczY0wvb3J1S0ozR1ovd3hRZE56Y2xqZmhBY3B1ejBCQ3Yzbkd6SHkya2hBb0ZiZHMKWmJqVGVlUDE4OW9rR0Y4aFY5V3YwakltZnZnQXlRSlY0U3ZlN0tCUXZ3d0JKUlJMQTkyV1RQbWtiU2kvTHRPNwoyRnlPaXVvYVJBNjh4bXB0UGlMMXhqYXAwZkhKZm92czZpbUFHbDhEdVZFUkRzdVBpTm9RenNERGtQYU5ROWorCi9zQUZzemxhYXRGSUJLVG1aMGhXazlQSG5TTGI1dmxQMXp5Rkp1VVNLNkFiNXMwaldVRmVkL1lHQ1BhbFFTeXMKYUJSTDlTSmxBOEhoRzg0WXdsMnEKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoKc3ViamVjdD0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURPRCBFTUFJTCBDQS0zMwppc3N1ZXI9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSAyCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFdXpDQ0E2T2dBd0lCQWdJQ0I1MHdEUVlKS29aSWh2Y05BUUVGQlFBd1d6RUxNQWtHQTFVRUJoTUNWVk14CkdEQVdCZ05WQkFvVEQxVXVVeTRnUjI5MlpYSnViV1Z1ZERFTU1Bb0dBMVVFQ3hNRFJHOUVNUXd3Q2dZRFZRUUwKRXdOUVMwa3hGakFVQmdOVkJBTVREVVJ2UkNCU2IyOTBJRU5CSURJd0hoY05NVFV3T1RJek1UTXpORFUzV2hjTgpNakV3T1RJeU1UTXpORFUzV2pCZE1Rc3dDUVlEVlFRR0V3SlZVekVZTUJZR0ExVUVDaE1QVlM1VExpQkhiM1psCmNtNXRaVzUwTVF3d0NnWURWUVFMRXdORWIwUXhEREFLQmdOVkJBc1RBMUJMU1RFWU1CWUdBMVVFQXhNUFJFOUUKSUVWTlFVbE1JRU5CTFRNek1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBd1NLUwpiVmpXQ0c1SjZNTnhoWWYxRkFpWG5IdVpGVk1aMGIzWFRWOXJFOTQ0eU9mS0JHVDc2ZENCSUF2ZWdNQjJIcUIyCmlqWC9NRTVKQjZvL1lLSEhxMURmV1RLS2lCYysrMFB1MkwvNUVHUWZxTU1FcjdlNDRobXlkempWcklmTSsxL3MKd1Y4QytrVHFEdEs2Q25RaW8vRTRzS25BTHdjTUtpNlFoZE5vdEdSdUhQUXpZRnZ1M0NYV2hla2ljNmhENHJGSwpqS0toaTkyZjAwbk1HczJ1S3RrSFpaL3pmcVpxaTBCMW5nRE1JTzJua2x6OE1JbEh0dXl5NmFWZTFramQ3ai96CjdyWUJJU0MwdTdNdEg3bkRXWFRTOUgvamVyNy9OUEg2SnY4NGV1SHdZWm9pVytYSnNWK24zOU42ZlV6NkEzREgKVkVqZGx0T3ZlZUNCQzFMSThRSURBUUFCbzRJQmhUQ0NBWUV3SFFZRFZSME9CQllFRkJWbHpmMHRrQlpLci93NApsd0RjNmtPdzN5Q1hNQjhHQTFVZEl3UVlNQmFBRkVsMHV3eGV1bnIrQWxUdmU2REdsY1lKZ0hDV01CSUdBMVVkCkV3RUIvd1FJTUFZQkFmOENBUUF3REFZRFZSMGtCQVV3QTRBQkFEQU9CZ05WSFE4QkFmOEVCQU1DQVlZd1pnWUQKVlIwZ0JGOHdYVEFMQmdsZ2hrZ0JaUUlCQ3dVd0N3WUpZSVpJQVdVQ0FRc0pNQXNHQ1dDR1NBRmxBZ0VMRVRBTApCZ2xnaGtnQlpRSUJDeEl3Q3dZSllJWklBV1VDQVFzVE1Bd0dDbUNHU0FGbEF3SUJBeG93REFZS1lJWklBV1VECkFnRURHekEzQmdOVkhSOEVNREF1TUN5Z0txQW9oaVpvZEhSd09pOHZZM0pzTG1ScGMyRXViV2xzTDJOeWJDOUUKVDBSU1QwOVVRMEV5TG1OeWJEQnNCZ2dyQmdFRkJRY0JBUVJnTUY0d09nWUlLd1lCQlFVSE1BS0dMbWgwZEhBNgpMeTlqY213dVpHbHpZUzV0YVd3dmFYTnpkV1ZrZEc4dlJFOUVVazlQVkVOQk1sOUpWQzV3TjJNd0lBWUlLd1lCCkJRVUhNQUdHRkdoMGRIQTZMeTl2WTNOd0xtUnBjMkV1Yldsc01BMEdDU3FHU0liM0RRRUJCUVVBQTRJQkFRQTAKYU44Uk5kRUFYT3gwV3FXS21Kb0J0Mnk4TEp2MUVZYmhTV29VUCtVME9MVFBwa3J6MG5INC92Ui9FWXRwa2JIVgpLT0FsWFd6bHlDaWdNSThzcFJVS3VBdHB5cTRCRkU0a3BwTDhqQmM5NzdvTFBURnUvWHcrSHcxVTJXMDdmTDhuClZieHhZUVpsdHJNdTZ5WXp0Sy9HdU5wWG5TV0QxN1pndHlwdmtlZnp0dHlnSFVmeVZUcU1zWUJwWVduY1N1OUUKanU2VnRZSlZpa0NxRGZldmxvWDZ0WCs0cFVQc3l5eGtVTWUweG04WXZPNGlOL09YM0FCVzBJR1B0R3hoSU1XegovYUU5QkZ0Z1VZNDVnbnBjQWFnb3FOOEkxRllxK3phZWZsUGIwaDN5ZXZveXBBelJxQXQzRmZ0RVhESGxjRWRqClA2THJackVXSG4zaVNMaWhFT0RiCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCnN1YmplY3Q9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1ET0QgSUQgQ0EtMzMKaXNzdWVyPS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RG9EIFJvb3QgQ0EgMgotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRXVEQ0NBNkNnQXdJQkFnSUNCNXd3RFFZSktvWklodmNOQVFFRkJRQXdXekVMTUFrR0ExVUVCaE1DVlZNeApHREFXQmdOVkJBb1REMVV1VXk0Z1IyOTJaWEp1YldWdWRERU1NQW9HQTFVRUN4TURSRzlFTVF3d0NnWURWUVFMCkV3TlFTMGt4RmpBVUJnTlZCQU1URFVSdlJDQlNiMjkwSUVOQklESXdIaGNOTVRVd09USXpNVE16TWpNeVdoY04KTWpFd09USXlNVE16TWpNeVdqQmFNUXN3Q1FZRFZRUUdFd0pWVXpFWU1CWUdBMVVFQ2hNUFZTNVRMaUJIYjNabApjbTV0Wlc1ME1Rd3dDZ1lEVlFRTEV3TkViMFF4RERBS0JnTlZCQXNUQTFCTFNURVZNQk1HQTFVRUF4TU1SRTlFCklFbEVJRU5CTFRNek1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBeDMzOTdWeXkKVThpd250aTh6MDgzNW02bzVONmI5WmJQZzJBd2JHWnNCSEVBMGFXOUxyZ1dxVk5kUnJGTitMNzNJVmZZaHJwZApCOVNPNzJaR3NCZmVrVFBBSzQvZzBXUHdveERlTytqcEJERGJycC9tT3J4V2xac2VZNmpwU3ZFVG1ZZEJIdXFsCmRuaCtIYm51TTcvYzg2M05yVUhadnE5VDUrd0VKZWt2aEpPa3RhOTIrV1BRaFRtb1JHRHovQzBrN0VZVkl4V0IKWHFORFNxYmI0ZVQrOWthdmRaS011QUxoVi9RdmlqMVVDN0V5eFlHVDVHUGNsTnZDRHRSeG1vMzk3dm1pWk1wcgpMdVhxeThESk5uUW1RZlJTRWtuWVJHMTMrVUFRc1lzMkdtQmMyTTduVVhoem1mbUFqRzNEUU5zN0Y2RDBtd3ltClB1ck0yN0ZFNnJReDh3SURBUUFCbzRJQmhUQ0NBWUV3SFFZRFZSME9CQllFRkMyTzJkU0Q4dUtRakV1ZmIvbEcKNTJwTHpid25NQjhHQTFVZEl3UVlNQmFBRkVsMHV3eGV1bnIrQWxUdmU2REdsY1lKZ0hDV01CSUdBMVVkRXdFQgovd1FJTUFZQkFmOENBUUF3REFZRFZSMGtCQVV3QTRBQkFEQU9CZ05WSFE4QkFmOEVCQU1DQVlZd1pnWURWUjBnCkJGOHdYVEFMQmdsZ2hrZ0JaUUlCQ3dVd0N3WUpZSVpJQVdVQ0FRc0pNQXNHQ1dDR1NBRmxBZ0VMRVRBTEJnbGcKaGtnQlpRSUJDeEl3Q3dZSllJWklBV1VDQVFzVE1Bd0dDbUNHU0FGbEF3SUJBeG93REFZS1lJWklBV1VEQWdFRApHekEzQmdOVkhSOEVNREF1TUN5Z0txQW9oaVpvZEhSd09pOHZZM0pzTG1ScGMyRXViV2xzTDJOeWJDOUVUMFJTClQwOVVRMEV5TG1OeWJEQnNCZ2dyQmdFRkJRY0JBUVJnTUY0d09nWUlLd1lCQlFVSE1BS0dMbWgwZEhBNkx5OWoKY213dVpHbHpZUzV0YVd3dmFYTnpkV1ZrZEc4dlJFOUVVazlQVkVOQk1sOUpWQzV3TjJNd0lBWUlLd1lCQlFVSApNQUdHRkdoMGRIQTZMeTl2WTNOd0xtUnBjMkV1Yldsc01BMEdDU3FHU0liM0RRRUJCUVVBQTRJQkFRQ3pxQjJ6CkNxdlBFaGdFZ0ZEOS9lYnRGRG02YTNjNUp0VysxR1JndncyQm0wclZRM05OZWNyK0MxWW53VHY0ZnV0Kzc1cmQKYTJSNzdNRHlzekpZek02aTBuTzZmMzB4bTVkR0tQZ0dTN0hpUEQzUGg0N1hMWS9OK2N1QWowbW93WENPV0s1NgpuMHV2WFU1REt4ckFlcWxiYVVPWWFreUN3NjdQenorRkJOU1dsVHhyakVrRzhycXpVSVk3VlhYOE10ZWN0SjY1CnJhaG50YXJ0VHQrZ3NPekVDRUxXRndvUnZQelY3cFVyWTlWU25LUjhzanVzbnhLNEovYjBjUmsyUmJsWFVlM0cKVW45ZlhmRERuVVEzQ2dRdGJTY2ZEV09lQWJQSmRMWVdXNzVZU3pzeVcwM2Ftck9pMmFCSlpVMUUrN2h2SmttNwpjdzhja0FXNXRKRDVTUmltCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCnN1YmplY3Q9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSAyCmlzc3Vlcj0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURvRCBSb290IENBIDIKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURjRENDQWxpZ0F3SUJBZ0lCQlRBTkJna3Foa2lHOXcwQkFRVUZBREJiTVFzd0NRWURWUVFHRXdKVlV6RVkKTUJZR0ExVUVDaE1QVlM1VExpQkhiM1psY201dFpXNTBNUXd3Q2dZRFZRUUxFd05FYjBReEREQUtCZ05WQkFzVApBMUJMU1RFV01CUUdBMVVFQXhNTlJHOUVJRkp2YjNRZ1EwRWdNakFlRncwd05ERXlNVE14TlRBd01UQmFGdzB5Ck9URXlNRFV4TlRBd01UQmFNRnN4Q3pBSkJnTlZCQVlUQWxWVE1SZ3dGZ1lEVlFRS0V3OVZMbE11SUVkdmRtVnkKYm0xbGJuUXhEREFLQmdOVkJBc1RBMFJ2UkRFTU1Bb0dBMVVFQ3hNRFVFdEpNUll3RkFZRFZRUURFdzFFYjBRZwpVbTl2ZENCRFFTQXlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXdDekI5bzA3CnJQOC9QTlp4dnJoMElnZnNjRUVWL0t0QTR3ZXF3Y1BZbi83YVREcS9QOGpZS0h0TE5nSEFyRVVsdzlJT0NvK0YKR0dRUVBSb1RjQ3B2anRmY2paT3pRUTg0SWMydHE4STlLZ1hUVnhFM0RjMk1VZm1UNDh4R1NTR09GTFROeXhRKwpPTTF5TWU2ckV2Smw2alF1VmwzLzdtTjF5MjI2a1RUOG52UDBMUnkrVU1SQzMxbUkvMnF6K3Foc1BjdFdjWEVGCmxydWZnT1dBUlZsblFiRHJ3NjFncElCMUJoZWNEdlJENEprT0cvdC85YlBNc29HQ3NmMHl3YmkrUWFSa3RXQTYKV2xFd2pNN2VRU3daUjF4SkVHUzVkS21IUWE5OWJyckJ1S0cvWlRFNkJHZjV0YnVPa29vQVk3aXg1b3c0WDRQLwpVTlU3b2wxcnNoRE1Zd0lEQVFBQm96OHdQVEFkQmdOVkhRNEVGZ1FVU1hTN0RGNjZldjRDVk85N29NYVZ4Z21BCmNKWXdDd1lEVlIwUEJBUURBZ0dHTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3RFFZSktvWklodmNOQVFFRkJRQUQKZ2dFQkFKaVJqVCtKeUx2MXdHbHpLVHMxckxxekNIWTljQW1TNllSRUlRRjlGSFliN2xGc0hZMFZOeTE3TVduMApta1M0cjBiTU5Qb2p5d01uR2RLRElYVXI1K0FibVNiY2hFQ1Y2S2pTelBaWVhHYnZQMHFYRUlJZHVncWkzVnNHCks1Mm5aRTdyTGdFMXBMUS9FNjFWNU5WenFHbWJFZkdZOGpFZWIwRFUrSGlmanBHZ2IzQUVrR2FxQml2TzRYcVMKdFgzaDROR1c1NkU2TGN5eG5SOEZSTzJIbWROTkduQTV3UVFNNVg3WjhhL1hJQTd4SW5vbHBIT1p6RCtrQnllVwpxS0tWN1lLNUZ0T2VDNGZDd2ZLSTlXTGZhTi9IdkdsUjdiRmMzRlJVS1E4Sk9acXNBOEhiREUydWJ3cDZGa254CnY1SFNPSlRUOXBVc3QyekpRcmFOeXBDTmhkaz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoKc3ViamVjdD0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURPRCBFTUFJTCBDQS0zMgppc3N1ZXI9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSAyCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlGVWpDQ0JEcWdBd0lCQWdJQ0E2SXdEUVlKS29aSWh2Y05BUUVGQlFBd1d6RUxNQWtHQTFVRUJoTUNWVk14CkdEQVdCZ05WQkFvVEQxVXVVeTRnUjI5MlpYSnViV1Z1ZERFTU1Bb0dBMVVFQ3hNRFJHOUVNUXd3Q2dZRFZRUUwKRXdOUVMwa3hGakFVQmdOVkJBTVREVVJ2UkNCU2IyOTBJRU5CSURJd0hoY05NVE13TWpBME1qQTBPREV5V2hjTgpNVGt3TWpBME1qQTBPREV5V2pCZE1Rc3dDUVlEVlFRR0V3SlZVekVZTUJZR0ExVUVDaE1QVlM1VExpQkhiM1psCmNtNXRaVzUwTVF3d0NnWURWUVFMRXdORWIwUXhEREFLQmdOVkJBc1RBMUJMU1RFWU1CWUdBMVVFQXhNUFJFOUUKSUVWTlFVbE1JRU5CTFRNeU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBby9xcQpoc3FLR2hzRFRuRnRRYmJaWlpwdS96WXFQd0xUZkpWbGlGcWs5NjlqdDFMSEd2dTdsWE1IUW1HTFNxWjc2VllICk5odXFOd0lnSEtUTys3YlFhYXY4T0V6STIwWlc5NkplZnVjeHRPN0IvODFrdjNtQ1FTdDMwdmg5cTB5UDk4WWUKUFBpT0x6MFVnOXFTbUFuWTBNWmFXVGFMaDZLSjNiNUtYc3ZOdGtkK1FhWUpWR3hCbG5SYkJzUFV3UzVHZlY0MgozNDJpUm5Hc1NyckVzZmZKRndvdjNhUHNoQ0hQcUFYcXVlTXViNTkrZmJzZEZuVlBraDBENWhFNG1EWjZvZFFBClBLMFFXSzhWeHpaTDR6dWJUYlcwa0w2dHE5UEFoTFA4M0JXSUNZd1JVRkF2NUhEc3R3cXVTbFBpTnNRRmJvQjEKRW8wM1J2SkxERGdjU1Irc2d3SURBUUFCbzRJQ0hEQ0NBaGd3SFFZRFZSME9CQllFRkFxd3FqaFdSM3NXZmI2cgprNWE4Vk4yRisrMHNNQjhHQTFVZEl3UVlNQmFBRkVsMHV3eGV1bnIrQWxUdmU2REdsY1lKZ0hDV01CSUdBMVVkCkV3RUIvd1FJTUFZQkFmOENBUUF3REFZRFZSMGtCQVV3QTRBQkFEQU9CZ05WSFE4QkFmOEVCQU1DQVlZd1pnWUQKVlIwZ0JGOHdYVEFMQmdsZ2hrZ0JaUUlCQ3dVd0N3WUpZSVpJQVdVQ0FRc0pNQXNHQ1dDR1NBRmxBZ0VMRVRBTApCZ2xnaGtnQlpRSUJDeEl3Q3dZSllJWklBV1VDQVFzVE1Bd0dDbUNHU0FGbEF3SUJBeG93REFZS1lJWklBV1VECkFnRURHekEzQmdOVkhSOEVNREF1TUN5Z0txQW9oaVpvZEhSd09pOHZZM0pzTG1ScGMyRXViV2xzTDJOeWJDOUUKVDBSU1QwOVVRMEV5TG1OeWJEQ0NBUUVHQ0NzR0FRVUZCd0VCQklIME1JSHhNRG9HQ0NzR0FRVUZCekFDaGk1bwpkSFJ3T2k4dlkzSnNMbVJwYzJFdWJXbHNMMmx6YzNWbFpIUnZMMFJQUkZKUFQxUkRRVEpmU1ZRdWNEZGpNQ0FHCkNDc0dBUVVGQnpBQmhoUm9kSFJ3T2k4dmIyTnpjQzVrYVhOaExtMXBiRENCa0FZSUt3WUJCUVVITUFLR2dZTnMKWkdGd09pOHZZM0pzTG1ka2N5NWthWE5oTG0xcGJDOWpiaVV6WkVSdlJDVXlNRkp2YjNRbE1qQkRRU1V5TURJbApNbU52ZFNVelpGQkxTU1V5WTI5MUpUTmtSRzlFSlRKamJ5VXpaRlV1VXk0bE1qQkhiM1psY201dFpXNTBKVEpqCll5VXpaRlZUUDJOeWIzTnpRMlZ5ZEdsbWFXTmhkR1ZRWVdseU8ySnBibUZ5ZVRBTkJna3Foa2lHOXcwQkFRVUYKQUFPQ0FRRUFENzJQUi8rNXliMUQ1YzYrdGZNNXkwVVdXYVBmdGxJa1BBbFZTOW0vbFhxOWR0bmdNSWZOU3FtagpMWjdaS0FUR2xxNEJGSURRSlZieFdBTlY3OUtvSWxLcmdlOEEvcS9IU2RLTUlDNmtjWUgzSnNzT3BXM1ZRWGQ3CkxUTzdtN044bkQ4OS84THVlZktKQ2hDTWtIUmROR2R3dmdMK2dFWVpCODU5TDVhb3hCUFE3NThwc1RTcHVZeWwKaVRTempENUgrR2FNa2RIdXE4SHFjWVhKWDdDcDd0c0ExREFxUXM1WFl4QWlNS2ljaGtFU1hiNVFmQlA2NnloegpYM0l6aVY5L0RXaWtQZjBXSnVnS2svNTdINGFCZ0NlK1ozR0dHMzNIYjdlcGNRSEdZN056ZlFGck15THRlWW1LCkR1WnlBbk0zUDhzeGdlMmsrd3RxTzFLRXVrejNqZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCnN1YmplY3Q9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1ET0QgQ0EtMzIKaXNzdWVyPS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RG9EIFJvb3QgQ0EgMgotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRlREQ0NCRFNnQXdJQkFnSUNBNkV3RFFZSktvWklodmNOQVFFRkJRQXdXekVMTUFrR0ExVUVCaE1DVlZNeApHREFXQmdOVkJBb1REMVV1VXk0Z1IyOTJaWEp1YldWdWRERU1NQW9HQTFVRUN4TURSRzlFTVF3d0NnWURWUVFMCkV3TlFTMGt4RmpBVUJnTlZCQU1URFVSdlJDQlNiMjkwSUVOQklESXdIaGNOTVRNd01qQTBNakEwTkRBMVdoY04KTVRrd01qQTBNakEwTkRBMVdqQlhNUXN3Q1FZRFZRUUdFd0pWVXpFWU1CWUdBMVVFQ2hNUFZTNVRMaUJIYjNabApjbTV0Wlc1ME1Rd3dDZ1lEVlFRTEV3TkViMFF4RERBS0JnTlZCQXNUQTFCTFNURVNNQkFHQTFVRUF4TUpSRTlFCklFTkJMVE15TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFzK0tWSFpNMkxTV2wKRHYxNDZlL3FrOUU2eWRoWHZSbmYwY2VpMGVqWi9kS09GYWpkdlQ1azlMYituQVBmUzdCbHQ2c0VHRElaYkJNQgpVdEhtdGNoQkVyZStPOHROUUJDSXlwNjIvVFYzYlNiMlpLMFJod3lwSlhwWW43QzltUGFUWHh2djc3S1hyZmdWCjU5em1vR3AxRFZIZlZSMW9RVkpKTHNlY2FGZFdSNC9lOWxJdWdXOVd2QWFKRXBTZkk3MC9nY2VHQW5Vd1hqT2gKM09FVHUvMTVWZ0U4U2huMExPdVFaR1RYNkFvdlVZYlZDSnVFKy9ucGkwTEtaZEtRQnh5Q2w0eEVJMWNHTEhWcApLSEN5N1Q1TTFlT1dkeFg5dXBYUFc1WnBBbmZXZ05tUGh5bmo1d1YycjhxTkVtQTBjc2V6blRodVRKWXlucEExCnJYV0wwV0pBQ1FJREFRQUJvNElDSERDQ0FoZ3dIUVlEVlIwT0JCWUVGQy9LazFNRHJHOTE5WGI2dnY2TzZoQ0wKdCtlUU1COEdBMVVkSXdRWU1CYUFGRWwwdXd4ZXVucitBbFR2ZTZER2xjWUpnSENXTUJJR0ExVWRFd0VCL3dRSQpNQVlCQWY4Q0FRQXdEQVlEVlIwa0JBVXdBNEFCQURBT0JnTlZIUThCQWY4RUJBTUNBWVl3WmdZRFZSMGdCRjh3ClhUQUxCZ2xnaGtnQlpRSUJDd1V3Q3dZSllJWklBV1VDQVFzSk1Bc0dDV0NHU0FGbEFnRUxFVEFMQmdsZ2hrZ0IKWlFJQkN4SXdDd1lKWUlaSUFXVUNBUXNUTUF3R0NtQ0dTQUZsQXdJQkF4b3dEQVlLWUlaSUFXVURBZ0VER3pBMwpCZ05WSFI4RU1EQXVNQ3lnS3FBb2hpWm9kSFJ3T2k4dlkzSnNMbVJwYzJFdWJXbHNMMk55YkM5RVQwUlNUMDlVClEwRXlMbU55YkRDQ0FRRUdDQ3NHQVFVRkJ3RUJCSUgwTUlIeE1Eb0dDQ3NHQVFVRkJ6QUNoaTVvZEhSd09pOHYKWTNKc0xtUnBjMkV1Yldsc0wybHpjM1ZsWkhSdkwwUlBSRkpQVDFSRFFUSmZTVlF1Y0Rkak1DQUdDQ3NHQVFVRgpCekFCaGhSb2RIUndPaTh2YjJOemNDNWthWE5oTG0xcGJEQ0JrQVlJS3dZQkJRVUhNQUtHZ1lOc1pHRndPaTh2ClkzSnNMbWRrY3k1a2FYTmhMbTFwYkM5amJpVXpaRVJ2UkNVeU1GSnZiM1FsTWpCRFFTVXlNRElsTW1OdmRTVXoKWkZCTFNTVXlZMjkxSlROa1JHOUVKVEpqYnlVelpGVXVVeTRsTWpCSGIzWmxjbTV0Wlc1MEpUSmpZeVV6WkZWVApQMk55YjNOelEyVnlkR2xtYVdOaGRHVlFZV2x5TzJKcGJtRnllVEFOQmdrcWhraUc5dzBCQVFVRkFBT0NBUUVBCk1JM1ZWbU85bVFhTFRiYlNEZ081eG9UU20zZEJHb2pTLzhQYTR1Wm5ZYjNaZXUwNE9WNnJDMWcwK2Ryb1lubXYKT1hMelNxZmpUamtRemVuU0NPclVucHFuTlRXVGt3Slo0a3dBSFBQOGF5RlRTb3hoNTJITDBFWUwwVCtjYWZYdgpVSXJ3UUxNclZsb2RhMkpaQmJPUEp4Z0ZDa05iQXUvZFVsNWJ3S2tjVnVPVmJKZFBBWU5XY2wzWGZWSGpXbFF1CnVKajljazRsajRzVzBiRGhNK09TZkJCVk15Um1ydzh6QmxOSUE0ZWZ0R1IwdGRJOUluSzMwWTQzRVJNNTM1N24KMEF3TGlsa1JNbVgvOXJsR3ZUODJucWVVQUZmd3dCbmhMTnhNOXk5TWtCMUQ3NjRJNDNPZU9yK1o3Q0s1QjFpdQoyVFZTUzFHN2dUYVBuMjRoQ3FhT2h3PT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoKc3ViamVjdD0vQz1VUy9PPVUuUy4gR292ZXJubWVudC9PVT1Eb0QvT1U9UEtJL0NOPURPRCBFTUFJTCBDQS0zMQppc3N1ZXI9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1Eb0QgUm9vdCBDQSAyCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlGVWpDQ0JEcWdBd0lCQWdJQ0E1OHdEUVlKS29aSWh2Y05BUUVGQlFBd1d6RUxNQWtHQTFVRUJoTUNWVk14CkdEQVdCZ05WQkFvVEQxVXVVeTRnUjI5MlpYSnViV1Z1ZERFTU1Bb0dBMVVFQ3hNRFJHOUVNUXd3Q2dZRFZRUUwKRXdOUVMwa3hGakFVQmdOVkJBTVREVVJ2UkNCU2IyOTBJRU5CSURJd0hoY05NVE13TVRFMk1UUTFNalF6V2hjTgpNVGt3TVRFMk1UUTFNalF6V2pCZE1Rc3dDUVlEVlFRR0V3SlZVekVZTUJZR0ExVUVDaE1QVlM1VExpQkhiM1psCmNtNXRaVzUwTVF3d0NnWURWUVFMRXdORWIwUXhEREFLQmdOVkJBc1RBMUJMU1RFWU1CWUdBMVVFQXhNUFJFOUUKSUVWTlFVbE1JRU5CTFRNeE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBNks0QwpMRUJNT2xMb2kzT1N0SGZuT0V2QThLcEtHRnpIOXpYRFN2RHdsbmVsbDc0bjc4UkVJWURxRmpTM01ORkVPSDhxCnpnVEdrV1dwYmxCOHlFNyt2Y0MxU3hia09GSVYyN08zOTFNOThyRUgyNUZtWGNHMzhuZG14RkdhWTVRUlN3SWQKRFV0OHN3QkhCM2tZK25pemt4L1VkbTJaQk1VZU5rYjhCalFMNDJodkhueWZMTTlodUV2L3ROOEduNkJmbEY3cgpOZjhKWFRWQUIvS2Q3WllKMlhicS9tNHgvc3YwUmVzd2VFaG9iS0VwUG9aOWswRks2dWNNVE9XUlVDcWxRMmE4CklzRDhHeXprOHk5aUhnVFVJYitzSHlaM05kQWR2T0s3UnNMeTYrUVVydml6YTdQNmNUaXdjU250MFlzYjF3SWIKM3Nyc2Z1NmgzRWlsOFQ2VXFRSURBUUFCbzRJQ0hEQ0NBaGd3SFFZRFZSME9CQllFRklieFcyaHYzVER6bElKbwoxRXozUkIyNHltaUJNQjhHQTFVZEl3UVlNQmFBRkVsMHV3eGV1bnIrQWxUdmU2REdsY1lKZ0hDV01CSUdBMVVkCkV3RUIvd1FJTUFZQkFmOENBUUF3REFZRFZSMGtCQVV3QTRBQkFEQU9CZ05WSFE4QkFmOEVCQU1DQVlZd1pnWUQKVlIwZ0JGOHdYVEFMQmdsZ2hrZ0JaUUlCQ3dVd0N3WUpZSVpJQVdVQ0FRc0pNQXNHQ1dDR1NBRmxBZ0VMRVRBTApCZ2xnaGtnQlpRSUJDeEl3Q3dZSllJWklBV1VDQVFzVE1Bd0dDbUNHU0FGbEF3SUJBeG93REFZS1lJWklBV1VECkFnRURHekEzQmdOVkhSOEVNREF1TUN5Z0txQW9oaVpvZEhSd09pOHZZM0pzTG1ScGMyRXViV2xzTDJOeWJDOUUKVDBSU1QwOVVRMEV5TG1OeWJEQ0NBUUVHQ0NzR0FRVUZCd0VCQklIME1JSHhNRG9HQ0NzR0FRVUZCekFDaGk1bwpkSFJ3T2k4dlkzSnNMbVJwYzJFdWJXbHNMMmx6YzNWbFpIUnZMMFJQUkZKUFQxUkRRVEpmU1ZRdWNEZGpNQ0FHCkNDc0dBUVVGQnpBQmhoUm9kSFJ3T2k4dmIyTnpjQzVrYVhOaExtMXBiRENCa0FZSUt3WUJCUVVITUFLR2dZTnMKWkdGd09pOHZZM0pzTG1ka2N5NWthWE5oTG0xcGJDOWpiaVV6WkVSdlJDVXlNRkp2YjNRbE1qQkRRU1V5TURJbApNbU52ZFNVelpGQkxTU1V5WTI5MUpUTmtSRzlFSlRKamJ5VXpaRlV1VXk0bE1qQkhiM1psY201dFpXNTBKVEpqCll5VXpaRlZUUDJOeWIzTnpRMlZ5ZEdsbWFXTmhkR1ZRWVdseU8ySnBibUZ5ZVRBTkJna3Foa2lHOXcwQkFRVUYKQUFPQ0FRRUFXVEt0cXNQNDM1eGtuSEVKTk1HOXZHTUFIaTNiN2FuSUNPTzVHT1N2eXE0VXdkMjcrWE9EZzFlTwpsTW1ncWdNSHptZWN0ZVVYV1Q4b3VCYzIycnFOdzVZUkFXcFExZ2JhYUtSSzBndUZmTTJJMy85ZWQrYjFwRWlSCjBFNmlaMnI0YU8rcUYwWHYySllLM2Mvd1BvZTJ2NGcvMDFTK1BoTE9vZmtMYnpMUlZMK0VXeldnMndka3RhdnAKZVI3aThxcDBjdWVSRXZmSHUyN3U1WFNRRUNTTHQrZk5uSVdRUitUaWIzOGd2U3k3ZzVZalRhaE0ySDR1WGhVcAp1Q1Y5VnpVTExSVlVqS25jNE9VM25haFBJSldESzhVU05qMm9jK0ZPaUVtbHVidjZDVW9vV2pPNTVKSjVXM3Y0CnBVL3p5VFRObVl5d3VtQituNFErNWp6NmZscnI1Zz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCnN1YmplY3Q9L0M9VVMvTz1VLlMuIEdvdmVybm1lbnQvT1U9RG9EL09VPVBLSS9DTj1ET0QgQ0EtMzEKaXNzdWVyPS9DPVVTL089VS5TLiBHb3Zlcm5tZW50L09VPURvRC9PVT1QS0kvQ049RG9EIFJvb3QgQ0EgMgotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRlREQ0NCRFNnQXdJQkFnSUNBNTB3RFFZSktvWklodmNOQVFFRkJRQXdXekVMTUFrR0ExVUVCaE1DVlZNeApHREFXQmdOVkJBb1REMVV1VXk0Z1IyOTJaWEp1YldWdWRERU1NQW9HQTFVRUN4TURSRzlFTVF3d0NnWURWUVFMCkV3TlFTMGt4RmpBVUJnTlZCQU1URFVSdlJDQlNiMjkwSUVOQklESXdIaGNOTVRNd01URTJNVFEwT1RNd1doY04KTVRrd01URTJNVFEwT1RNd1dqQlhNUXN3Q1FZRFZRUUdFd0pWVXpFWU1CWUdBMVVFQ2hNUFZTNVRMaUJIYjNabApjbTV0Wlc1ME1Rd3dDZ1lEVlFRTEV3TkViMFF4RERBS0JnTlZCQXNUQTFCTFNURVNNQkFHQTFVRUF4TUpSRTlFCklFTkJMVE14TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF4aWNRTDVDV09ObmYKNWw4L3Vvbjdab0xydHFYdDhGYVFGa0RuYktLd2VXWloxNWhpTWRFeklsUGpIbHlrVm1hbVRWYjd3K0pDRXF2NQp3RXBMUU8rUkU0WTVNRkhXYm80bnQwR0pLUUh1V0VaekJIRkVYR2xEUGpMbVpOK3phNWtzY0tMUVBrM1lXQkp0ClJmQTlrMVMrMytMN3p4SC8vSW9CTisrbkxycEFER28rSE9RS01vQnB2U0k1N0V0MnliRmFrendoaERqZGN4T0MKK1YwTWdRcXBzbE4wMlF1T3dPaVh1ejFmRTR5MXVUdnM5cnVkamlEMmE3eWRGRExjZnJuaVk3QnF3WUM1RnZ5Ugo3Nnl5Q1o5U1IxZ1RYbUorbWhLR1c4VWdIK0dPWmdCMlUrem5Jb2toVEYrNTZiNmdVcE1PcHNqZXpMZUNyU0p0Cmk5QXdVelpWVndJREFRQUJvNElDSERDQ0FoZ3dIUVlEVlIwT0JCWUVGRVRqUnFOQjdtQ3hYcWVUSmZTZ1UrNjMKU2I2N01COEdBMVVkSXdRWU1CYUFGRWwwdXd4ZXVucitBbFR2ZTZER2xjWUpnSENXTUJJR0ExVWRFd0VCL3dRSQpNQVlCQWY4Q0FRQXdEQVlEVlIwa0JBVXdBNEFCQURBT0JnTlZIUThCQWY4RUJBTUNBWVl3WmdZRFZSMGdCRjh3ClhUQUxCZ2xnaGtnQlpRSUJDd1V3Q3dZSllJWklBV1VDQVFzSk1Bc0dDV0NHU0FGbEFnRUxFVEFMQmdsZ2hrZ0IKWlFJQkN4SXdDd1lKWUlaSUFXVUNBUXNUTUF3R0NtQ0dTQUZsQXdJQkF4b3dEQVlLWUlaSUFXVURBZ0VER3pBMwpCZ05WSFI4RU1EQXVNQ3lnS3FBb2hpWm9kSFJ3T2k4dlkzSnNMbVJwYzJFdWJXbHNMMk55YkM5RVQwUlNUMDlVClEwRXlMbU55YkRDQ0FRRUdDQ3NHQVFVRkJ3RUJCSUgwTUlIeE1Eb0dDQ3NHQVFVRkJ6QUNoaTVvZEhSd09pOHYKWTNKc0xtUnBjMkV1Yldsc0wybHpjM1ZsWkhSdkwwUlBSRkpQVDFSRFFUSmZTVlF1Y0Rkak1DQUdDQ3NHQVFVRgpCekFCaGhSb2RIUndPaTh2YjJOemNDNWthWE5oTG0xcGJEQ0JrQVlJS3dZQkJRVUhNQUtHZ1lOc1pHRndPaTh2ClkzSnNMbWRrY3k1a2FYTmhMbTFwYkM5amJpVXpaRVJ2UkNVeU1GSnZiM1FsTWpCRFFTVXlNRElsTW1OdmRTVXoKWkZCTFNTVXlZMjkxSlROa1JHOUVKVEpqYnlVelpGVXVVeTRsTWpCSGIzWmxjbTV0Wlc1MEpUSmpZeVV6WkZWVApQMk55YjNOelEyVnlkR2xtYVdOaGRHVlFZV2x5TzJKcGJtRnllVEFOQmdrcWhraUc5dzBCQVFVRkFBT0NBUUVBClIxRlMzUFNnYzVwQzV3dnNJNUdOSlhXMFJJSTBxdmxHZFZIRDlnNzQ1K012dENERDc2RmxOT0NkaDhIbUxtTHcKSitqcnhjODFsZEpBZ0l1U0NiYW1HOVVTWkRIYnRkUU8zd3FLdGxiMXZIYVNreGw4djJWOWNvSFlaSHM1TklwMgpXTXdkUS9jSHp4eURBM08rT0JmYmRLMXBDUkY4N2RqV0FvMW1QYXRyeWpQYngzcG14ZDZuSjBnUFpoTHVhQ1RBCjc1SHFCaGtxVUZnVDRDTDhEckVrKyt1T1FnSVBkNGdWaStieTlWTzNmT0JWbXhQV3RuREtjM0RqVXlYQktCNTcKeEN4SmJwRGJxc3RiQXh2Q2g0ZjFxNzVSY1hOdEptWjdteDBYNE8zandONGRKN0h0RFRSR1B0MHVYdlNDY05yUgpreHQ1M2RaSzU4NzVQM01mem9ybUZnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoK -kind: Secret -metadata: - name: nginx-client-ca-bundle - namespace: atat -type: Opaque diff --git a/deploy/overlays/cloudzero-dev/kustomization.yaml b/deploy/overlays/cloudzero-dev/kustomization.yaml index ee6f3a0c..24705531 100644 --- a/deploy/overlays/cloudzero-dev/kustomization.yaml +++ b/deploy/overlays/cloudzero-dev/kustomization.yaml @@ -5,7 +5,6 @@ resources: - namespace.yml - reset-cron-job.yml patchesStrategicMerge: - - replica_count.yml - ports.yml - envvars.yml - flex_vol.yml diff --git a/deploy/overlays/cloudzero-dev/replica_count.yml b/deploy/overlays/cloudzero-dev/replica_count.yml deleted file mode 100644 index 272286f7..00000000 --- a/deploy/overlays/cloudzero-dev/replica_count.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: atst -spec: - replicas: 2 ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: atst-worker -spec: - replicas: 1 diff --git a/deploy/overlays/staging/kustomization.yaml b/deploy/overlays/staging/kustomization.yaml index ee6f3a0c..24705531 100644 --- a/deploy/overlays/staging/kustomization.yaml +++ b/deploy/overlays/staging/kustomization.yaml @@ -5,7 +5,6 @@ resources: - namespace.yml - reset-cron-job.yml patchesStrategicMerge: - - replica_count.yml - ports.yml - envvars.yml - flex_vol.yml diff --git a/deploy/overlays/staging/replica_count.yml b/deploy/overlays/staging/replica_count.yml deleted file mode 100644 index 272286f7..00000000 --- a/deploy/overlays/staging/replica_count.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: atst -spec: - replicas: 2 ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: atst-worker -spec: - replicas: 1 diff --git a/docs/ATATArchitecture.md b/docs/ATATArchitecture.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/EdgeControls.md b/docs/EdgeControls.md new file mode 100644 index 00000000..b9b409f6 --- /dev/null +++ b/docs/EdgeControls.md @@ -0,0 +1,32 @@ +# Edge Control +This document describes the expected connections and listening services. + +## Transient Connections +| Service | Direction | Ports | Protocol | Encrypted? | Ciphers | +| --------|-----------|-------|----------|------------|--------------| +| Azure Container Registry | Egress | 443 | HTTP | Yes | MSFT Managed | +| DOD CRL Service | Egress | 443 | HTTP | Yes | DOD Managed | +| Azure Storage | Egress | 443 | HTTP | Yes | MSFT Managed| +| Redis | Egress | 6380 | HTTP | Yes | MSFT Managed| +| Postgres | Egress | 5432 | HTTP | Yes | MSFT Managed| + +# Listening Ports / Services +| Service/App | Port | Protocol| Encrypted? | Accessible | +|-------------|---------|---------|------------|--------| +| ATAT App | 80, 443 | HTTP | Both | Load Balancer Only +| ATAT Auth | 80, 443 | HTTP | Both | Load Balancer Only + +# Host List +## Dev +| Service| Host | +|--------|------| +| Redis | cloudzero-dev-redis.redis.cache.windows.net | +| Postgres| cloudzero-dev-sql.postgres.database.azure.com | +| Docker Container Registry | cloudzerodevregistry.azurecr.io | + +## Production +| Service | Host | +|---------|------| +| Redis | | +| Postgres| | +| Docker Container Registry | | \ No newline at end of file diff --git a/ipython_setup.py b/ipython_setup.py index 125a3d2b..ce44a907 100644 --- a/ipython_setup.py +++ b/ipython_setup.py @@ -6,4 +6,6 @@ app = make_app(make_config()) ctx = app.app_context() ctx.push() -print("\nWelcome to atst. This shell has all models in scope, and a SQLAlchemy session called db.") +print( + "\nWelcome to atst. This shell has all models in scope, and a SQLAlchemy session called db." +) diff --git a/js/components/__tests__/upload_input.test.js b/js/components/__tests__/upload_input.test.js index 43ae48a8..5d613b14 100644 --- a/js/components/__tests__/upload_input.test.js +++ b/js/components/__tests__/upload_input.test.js @@ -70,7 +70,7 @@ describe('UploadInput Test', () => { }) const component = wrapper.find(uploadinput) - const event = { target: { value: '', files: [{ name: '' }] } } + const event = { target: { value: '', files: [{ name: 'sample.pdf' }] } } component.setMethods({ getUploader: async () => new MockUploader('token', 'objectName'), diff --git a/js/components/clin_fields.js b/js/components/clin_fields.js index 59d6c8c9..327bedf0 100644 --- a/js/components/clin_fields.js +++ b/js/components/clin_fields.js @@ -1,5 +1,4 @@ import { emitFieldChange } from '../lib/emitters' -import escape from '../lib/escape' import optionsinput from './options_input' import textinput from './text_input' import clindollaramount from './clin_dollar_amount' @@ -100,7 +99,7 @@ export default { computed: { clinTitle: function() { if (!!this.clinNumber) { - return escape(`CLIN ${this.clinNumber}`) + return `CLIN ${this.clinNumber}` } else { return `CLIN` } diff --git a/js/components/upload_input.js b/js/components/upload_input.js index cdd9b15e..d7c90bf5 100644 --- a/js/components/upload_input.js +++ b/js/components/upload_input.js @@ -1,5 +1,6 @@ import { buildUploader } from '../lib/upload' import { emitFieldChange } from '../lib/emitters' +import inputValidations from '../lib/input_validations' export default { name: 'uploadinput', @@ -28,6 +29,7 @@ export default { changed: false, uploadError: false, sizeError: false, + filenameError: false, downloadLink: '', } }, @@ -50,6 +52,10 @@ export default { this.sizeError = true return } + if (!this.validateFileName(file.name)) { + this.filenameError = true + return + } const uploader = await this.getUploader() const response = await uploader.upload(file) @@ -71,6 +77,10 @@ export default { this.uploadError = true } }, + validateFileName: function(name) { + const regex = inputValidations.restrictedFileName.match + return regex.test(name) + }, removeAttachment: function(e) { e.preventDefault() this.attachment = null @@ -118,7 +128,8 @@ export default { return ( (!this.changed && this.initialErrors) || this.uploadError || - this.sizeError + this.sizeError || + this.filenameError ) }, valid: function() { diff --git a/js/lib/input_validations.js b/js/lib/input_validations.js index af74f211..80c16a7e 100644 --- a/js/lib/input_validations.js +++ b/js/lib/input_validations.js @@ -104,4 +104,11 @@ export default { unmask: ['(', ')', '-', ' '], validationError: 'Please enter a 10-digit phone number', }, + restrictedFileName: { + mask: false, + match: /^[A-Za-z0-9\-_ \.]+$/, + unmask: [], + validationError: + 'File names can only contain the characters A-Z, 0-9, space, hyphen, underscore, and period.', + }, } diff --git a/load-test/locustfile.py b/load-test/locustfile.py index 15b89db6..4fe678bf 100644 --- a/load-test/locustfile.py +++ b/load-test/locustfile.py @@ -15,7 +15,7 @@ PASSWORD = os.getenv("ATAT_BA_PASSWORD", "") DISABLE_VERIFY = os.getenv("DISABLE_VERIFY", "true").lower() == "true" # Alpha numerics for random entity names -LETTERS = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890" #pragma: allowlist secret +LETTERS = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890" # pragma: allowlist secret NEW_PORTFOLIO_CHANCE = 10 NEW_APPLICATION_CHANCE = 10 @@ -29,10 +29,6 @@ def logout(l): l.client.get("/logout") -def get_index(l): - l.client.get("/") - - def get_csrf_token(response): d = pq(response.text) return d("#csrf_token").val() @@ -52,14 +48,9 @@ def extract_id(path): def get_portfolios(l): - response = l.client.get("/portfolios") + response = l.client.get("/home") d = pq(response.text) - portfolio_links = [ - p.attr("href") - for p in d( - ".global-panel-container .atat-table tbody tr td:first-child a" - ).items() - ] + portfolio_links = [p.attr("href") for p in d(".sidenav__link").items()] force_new_portfolio = randrange(0, 100) < NEW_PORTFOLIO_CHANCE if len(portfolio_links) == 0 or force_new_portfolio: portfolio_links += [create_portfolio(l)] @@ -73,7 +64,7 @@ def get_portfolio(l): d = pq(response.text) application_links = [ p.attr("href") - for p in d(".application-list .accordion__actions a:first-child").items() + for p in d(".portfolio-applications .accordion__header-text a").items() ] if len(application_links) > 0: portfolio_id = extract_id(portfolio_link) @@ -161,18 +152,14 @@ class UserBehavior(TaskSequence): login(self) @seq_task(1) - def home(l): - get_index(l) - - @seq_task(2) def portfolios(l): get_portfolios(l) - @seq_task(3) + @seq_task(2) def pick_a_portfolio(l): get_portfolio(l) - @seq_task(4) + @seq_task(3) def pick_an_app(l): get_app(l) @@ -189,4 +176,3 @@ class WebsiteUser(HttpLocust): if __name__ == "__main__": # if run as the main file, will spin up a single locust WebsiteUser().run() - diff --git a/script/minikube_setup b/script/minikube_setup deleted file mode 100755 index 6a1e9760..00000000 --- a/script/minikube_setup +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -# script/minikube_setup: Set up local AT-AT cluster on Minikube - -source "$(dirname "${0}")"/../script/include/global_header.inc.sh - -output_divider "Start Minikube" -minikube start - -output_divider "Use Minikube Docker environment" -eval $(minikube docker-env) - -output_divider "Build AT-AT Docker image for Minikube registry" -docker build . -t atat:latest - -output_divider "Pull images for AT-AT cluster" -docker pull redis:5.0-alpine -docker pull postgres:11-alpine -docker pull nginx:alpine - -output_divider "Apply AT-AT Kubernetes config to Minikube cluster" -kubectl --context=minikube create namespace atat -kubectl --context=minikube apply -f deploy/minikube/ - -output_divider "Create database and apply migrations" -# wait for the datastore deployment to become available -kubectl --context=minikube -n atat wait --for=condition=Available deployment/datastores -# postgres isn't necessarily running as soon as the pod is available, so wait a few -sleep 3 -DB_POD=$(kubectl --context=minikube -n atat get pods -l app=db-cache -o custom-columns=NAME:.metadata.name --no-headers | sed -n 1p) -ATST_POD=$(kubectl --context=minikube -n atat get pods -l app=atst -o custom-columns=NAME:.metadata.name --no-headers | sed -n 1p) -kubectl --context=minikube -n atat exec -it $DB_POD -c postgres -- createdb -U postgres atat -kubectl --context=minikube -n atat exec -it $ATST_POD -c atst -- .venv/bin/python .venv/bin/alembic upgrade head diff --git a/script/seed_sample.py b/script/seed_sample.py index 47b7efb9..72c16c6c 100644 --- a/script/seed_sample.py +++ b/script/seed_sample.py @@ -159,7 +159,7 @@ def get_users(): def add_members_to_portfolio(portfolio): for user_data in PORTFOLIO_USERS: - invite = Portfolios.invite(portfolio, portfolio.owner, user_data) + invite = Portfolios.invite(portfolio, portfolio.owner, {"user_data": user_data}) profile = { k: user_data[k] for k in user_data if k not in ["dod_id", "permission_sets"] } diff --git a/ssl/certificate-authority/ca.crt b/ssl/certificate-authority/ca.crt deleted file mode 100644 index 60ed3ff2..00000000 --- a/ssl/certificate-authority/ca.crt +++ /dev/null @@ -1,25 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEJDCCAwygAwIBAgIJAK4JGo3BBGhVMA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNV -BAYTAlVTMRUwEwYDVQQIEwxQZW5uc3lsdmFuaWExFTATBgNVBAcTDFBoaWxhZGVs -cGhpYTEMMAoGA1UEChMDRG9EMQwwCgYDVQQLEwNERFMxEDAOBgNVBAMTB0FUQVQg -Q0EwHhcNMTgwNjAxMTk0NjIyWhcNMzgwNTI3MTk0NjIyWjBpMQswCQYDVQQGEwJV -UzEVMBMGA1UECBMMUGVubnN5bHZhbmlhMRUwEwYDVQQHEwxQaGlsYWRlbHBoaWEx -DDAKBgNVBAoTA0RvRDEMMAoGA1UECxMDRERTMRAwDgYDVQQDEwdBVEFUIENBMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzYU7UbstArnnVliaC/TB6Vir -kVWMnAEYMUZA1BKP8DZaNEKbzFH2+mMw7O0BY7Ph9x0hEZ1kXLr6U93xcKyUWNPo -13i5EwUUCSh2MdPfS8ZZt8DUIIKC7XzFnKyKSKQmr0Mt9dC44rryPKTBvmI60rQ8 -VZkFEgvs8FCP0M4Ar6/gtJ24ZLEtilu5dQBSlru4nPGXg07r2C2JgEZWshtMBtbH -LkOM2gtp/pkYCCG0zqeU+0s3H8IqDq0uYkONOfVeCumbg1/AtjgrZu7aOVPKyibk -aI6sTTooXE5aSZkfkx0z6+fKM2nPSe30HgiBODtb7G+44ln08d0isjpQ67OvGQID -AQABo4HOMIHLMB0GA1UdDgQWBBSl7CUAWPbx8XqotKKKAufPh0wn4DCBmwYDVR0j -BIGTMIGQgBSl7CUAWPbx8XqotKKKAufPh0wn4KFtpGswaTELMAkGA1UEBhMCVVMx -FTATBgNVBAgTDFBlbm5zeWx2YW5pYTEVMBMGA1UEBxMMUGhpbGFkZWxwaGlhMQww -CgYDVQQKEwNEb0QxDDAKBgNVBAsTA0REUzEQMA4GA1UEAxMHQVRBVCBDQYIJAK4J -Go3BBGhVMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBABguwdFk42YP -8U6Du5HQ6Is1jfc1KEOowdh0d2MCH8q0KNktqiu6kWzjH1gRjRwc07bAkAWqXPB6 -6gkRGYe/FRgi2Rn+Uo5UC5ahI4cXkE8OitCIEP3Br9fUw+vj/3Iiov0QZ6Hv81Kl -ZTZhLiZbjAg5maL/vufnUp+n15qzm67APh3/2hcgO93UlE9o9vXohWy1lHs8u12o -hPLxghSmGc9eKalEWEs61OrohpOtCHUEd1isq76WhaiXSwSUrBxgy89Z517A7ffC -BjzLo5AVo6a9ou+ONVeZk8qw6YR6X9J7axy8YuTWt+Z82WFvOF0ubkqjm72d001M -7R9zCOQ3O+g= ------END CERTIFICATE----- diff --git a/ssl/certificate-authority/ca.key b/ssl/certificate-authority/ca.key deleted file mode 100644 index 529761e9..00000000 --- a/ssl/certificate-authority/ca.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAzYU7UbstArnnVliaC/TB6VirkVWMnAEYMUZA1BKP8DZaNEKb -zFH2+mMw7O0BY7Ph9x0hEZ1kXLr6U93xcKyUWNPo13i5EwUUCSh2MdPfS8ZZt8DU -IIKC7XzFnKyKSKQmr0Mt9dC44rryPKTBvmI60rQ8VZkFEgvs8FCP0M4Ar6/gtJ24 -ZLEtilu5dQBSlru4nPGXg07r2C2JgEZWshtMBtbHLkOM2gtp/pkYCCG0zqeU+0s3 -H8IqDq0uYkONOfVeCumbg1/AtjgrZu7aOVPKyibkaI6sTTooXE5aSZkfkx0z6+fK -M2nPSe30HgiBODtb7G+44ln08d0isjpQ67OvGQIDAQABAoIBAHR4EInc3UEyQVu5 -knM8Hbgzu+b86FZweFlUSuDkNBYZdz0ukkRUHvb+x3c9SRBLnL8CDv+AhqPWgo6M -tIr6Aofkb4vMqnWQ5y3ZdEIApAa5PZbY/F4AGFql3wdO8H8CJ7ojBCTOSDiVYTnk -1Lcjy9okshyAP1Ne1sPJo/bdB56HtXs+wqok1NntIQwiXjjD9xUuc1EZk0J4M97L -vBUjUGNX942UjtRiey5zwhRp3bTPasTduHcA01NaIbOVYlRFwc2W+cflz0l6ml2p -14TNEEvIMMMCNKnlPrpGI23n0psAvE4nbuxZQGVYAFvXrWn+Gyvz0Yag2EoMUCEs -ziLED9ECgYEA6IByu+xqIuIAhj/PwIIxV4+lkuV4TXIlfAFLR4JuokOVfbRsmu2e -9EfeOUD9LfQ4KsG5mu4Abpja0k/VKRKRGRjV6Oe2C6VK942HFP6Kpn0hgIuomZkD -eVv8naDezZjAvVace38zjRWB2GXTpapwBAgf/YflPPsDZ8bi/weqZCMCgYEA4kqx -Ka489Rr7+cSXpMeS5lLufhlaE5OVQc5HVFREDAI5vXU8BM2sLiHTC/BHjis2JvLm -aRJ0UsxUoIUURl2KjTbx3zns4HDVkzBrSpoDXWxBjAo0oEg7JVc+6+qEqbDHHS1L -/UJ6mlUegsE42MkFWG3YJQuHxyLZqPXIwNAyhZMCgYEA5cxnGnSt5rJoAEi7xzMn -H7s71Hf3stw6TlldFV3GiZyw+aDFo09vR1RtQTuJwczbYu88yvOn+6gax7neHo1a -WmrgqiWzGcmS0iDRPZ/kXG/bGBlxV/cTpvSTNx0UejMbdUhQvANaaXyzbLYgPWK6 -+lEphUW2/tG+aOj73UOvVu8CgYA5L8sJz4CUKJeZDTeNauoSzs56i4mZ/OfxU2Hv -S8ROjJlu6ZubUya6Gc4t7DEJGp56xVO5JfLDoeOZFUiEZ8tF2KbTVN4p8hnnMotK -tRU4nM0LyOB3yQk5bIz4LbIM+CG5m+LiQ9Sb//rP7GijUFnLeSbwZbOQfZwn+MUd -BQBfhQKBgQDmuX8tJdPkjE133IhQhZHbHHt6AEQA3aXkFdvPvbYD9VbGTZ8wnpFO -VJrDDWnIKAgO2FerIX9oq+H9a5fggYtTMeAX1cOA6b9SnLmFjt0utxrQKxf7p5I+ -n+EsmcAWfb+KRQwoB0L/mE9Ool14AeJ15kHyNIrCrMPv0J4zoC0Jdg== ------END RSA PRIVATE KEY----- diff --git a/ssl/certificate-authority/ca.srl b/ssl/certificate-authority/ca.srl deleted file mode 100644 index a23185d3..00000000 --- a/ssl/certificate-authority/ca.srl +++ /dev/null @@ -1 +0,0 @@ -F4D74F1607DD3C83 diff --git a/ssl/make-certs.sh b/ssl/make-certs.sh deleted file mode 100755 index 8f1afd19..00000000 --- a/ssl/make-certs.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# Generate the root (GIVE IT A PASSWORD IF YOU'RE NOT AUTOMATING SIGNING!): -echo 'MAKING CA' -openssl genrsa -out certificate-authority/ca.key 2048 -openssl req -new -x509 -days 7300 -key certificate-authority/ca.key -sha256 -extensions v3_ca -out certificate-authority/ca.crt - -# Generate the domain key: -openssl genrsa -out server-certs/dev.cac.atat.codes.key 2048 - -echo 'MAKING CSR' -# Generate the certificate signing request -openssl req -nodes -sha256 -new -key server-certs/dev.cac.atat.codes.key -out server-certs/dev.cac.atat.codes.csr -reqexts SAN -config <(cat req.cnf <(printf "[SAN]\nsubjectAltName=DNS.1:dev.cac.atat.codes,DNS.2:cac.atat.codes,DNS.3:backend")) - -# Sign the request with your root key -openssl x509 -sha256 -req -in server-certs/dev.cac.atat.codes.csr -CA certificate-authority/ca.crt -CAkey certificate-authority/ca.key -CAcreateserial -out server-certs/dev.cac.atat.codes.crt -days 7300 -extfile <(cat req.cnf <(printf "[SAN]\nsubjectAltName=DNS.1:dev.cac.atat.codes,DNS.2:cac.atat.codes,DNS.3:backend")) -extensions SAN - -# Check your homework: -openssl verify -CAfile certificate-authority/ca.crt server-certs/dev.cac.atat.codes.crt diff --git a/styles/atat.scss b/styles/atat.scss index 4c8aa263..0134dd89 100644 --- a/styles/atat.scss +++ b/styles/atat.scss @@ -38,6 +38,7 @@ @import "components/dod_login_notice.scss"; @import "components/sticky_cta.scss"; @import "components/error_page.scss"; +@import "components/member_form.scss"; @import "sections/login"; @import "sections/home"; diff --git a/styles/components/_empty_state.scss b/styles/components/_empty_state.scss index 12405e05..b0b73b16 100644 --- a/styles/components/_empty_state.scss +++ b/styles/components/_empty_state.scss @@ -4,6 +4,20 @@ background-color: $color-gray-lightest; margin-top: $gap * 5; + &--white { + background-color: $color-white; + } + + &--centered { + text-align: center; + } + + &__message { + display: inline-block; + font-weight: bold; + margin-top: 3rem; + } + hr { margin-left: -$gap * 3; margin-right: -$gap * 3; diff --git a/styles/components/_member_form.scss b/styles/components/_member_form.scss new file mode 100644 index 00000000..5cbeaf87 --- /dev/null +++ b/styles/components/_member_form.scss @@ -0,0 +1,61 @@ +.member-form { + text-align: left; + + input[type="checkbox"] + label::before { + margin-left: 0; + } + + .input__inline-fields { + text-align: left; + + .usa-input__choices label { + font-weight: $font-bold; + } + } + + .input__inline-fields { + padding: $gap * 2; + border: 1px solid $color-gray-lighter; + + &.checked { + border: 1px solid $color-blue; + } + + label { + font-weight: $font-bold; + } + + p.usa-input__help { + margin-bottom: 0; + padding-left: 3rem; + } + } + + .user-info { + .usa-input { + width: 45rem; + + input, + label, + .usa-input__message { + max-width: unset; + } + + label .icon-validation { + left: unset; + right: -$gap * 4; + } + + &--validation--phoneExt { + width: 18rem; + } + } + } +} + +#modal--add-app-mem, +#modal--add-portfolio-manager { + .modal__body { + min-width: 75rem; + } +} diff --git a/styles/components/_portfolio_layout.scss b/styles/components/_portfolio_layout.scss index d7583b80..fffc468f 100644 --- a/styles/components/_portfolio_layout.scss +++ b/styles/components/_portfolio_layout.scss @@ -5,13 +5,6 @@ } margin-left: 2 * $gap; - - .line { - box-sizing: border-box; - height: 2px; - width: 100%; - border: 1px solid $color-gray-lightest; - } } .portfolio-header { @@ -40,36 +33,6 @@ } } - &__budget { - font-size: $small-font-size; - align-items: center; - - .icon-tooltip { - margin-left: -$gap / 2; - } - - button { - margin: 0; - padding: 0; - } - - &--dollars { - font-size: $h2-font-size; - font-weight: bold; - } - - &--amount { - white-space: nowrap; - } - - &--cents { - font-size: 2rem; - margin-top: 0.75rem; - margin-left: -0.7rem; - font-weight: bold; - } - } - .links { justify-content: center; font-size: $small-font-size; @@ -109,22 +72,6 @@ } } } - - .column-left { - width: 12.5rem; - float: left; - } - - .column-right { - margin-left: -0.4rem; - } - - .unfunded { - color: $color-red; - .icon { - @include icon-color($color-red); - } - } } @mixin subheading { @@ -138,6 +85,10 @@ .portfolio-content { margin: (4 * $gap) $gap 0 $gap; + .panel { + padding-bottom: 2rem; + } + a.add-new-button { display: inherit; margin-left: auto; @@ -157,44 +108,6 @@ } } - input.usa-button.usa-button-primary { - width: 9rem; - height: 4rem; - } - - select { - padding-left: 1.2rem; - } - - .members-table-ppoc { - select::-ms-expand { - display: none; - color: $color-gray; - } - - select { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - display: block; - width: 100%; - float: right; - margin: 5px 0px; - padding: 0px 24px; - background-image: none; - -ms-word-break: normal; - word-break: normal; - padding-right: 3rem; - padding-left: 1.2rem; - color: $color-gray; - } - - select:hover { - box-shadow: none; - color: $color-gray; - } - } - a.modal-link.icon-link { float: right; diff --git a/styles/core/_variables.scss b/styles/core/_variables.scss index 44fc53c8..122739c4 100644 --- a/styles/core/_variables.scss +++ b/styles/core/_variables.scss @@ -33,7 +33,7 @@ $title-font-size: 5.2rem; $h1-font-size: 4rem; $h2-font-size: 3rem; $h3-font-size: 2.3rem; -$h4-font-size: 1.7rem; +$h4-font-size: 1.9rem; $h5-font-size: 1.5rem; $h6-font-size: 1.3rem; $base-line-height: 1.5; @@ -44,6 +44,7 @@ $font-sans: "Source Sans Pro", sans-serif; $font-serif: "Merriweather", serif; $font-normal: 400; +$font-semibold: 600; $font-bold: 700; // Color diff --git a/styles/elements/_action_group.scss b/styles/elements/_action_group.scss index 73cad181..fe375f67 100644 --- a/styles/elements/_action_group.scss +++ b/styles/elements/_action_group.scss @@ -12,6 +12,7 @@ .usa-button, a { margin: 0 0 0 $gap; + cursor: pointer; @include media($medium-screen) { margin: 0 0 0 ($gap * 2); diff --git a/styles/elements/_tables.scss b/styles/elements/_tables.scss index 5f65830c..2a742929 100644 --- a/styles/elements/_tables.scss +++ b/styles/elements/_tables.scss @@ -21,24 +21,8 @@ table.atat-table { text-align: right; } - &--align-center { - text-align: center; - } - - &--shrink { - width: 1%; - } - - &--expand { - width: 100%; - } - - &--hide-small { - display: none; - - @include media($medium-screen) { - display: table-cell; - } + &--third { + width: 33%; } } } @@ -83,28 +67,6 @@ table.atat-table { @include panel-margin; - &__header { - @include panel-base; - @include panel-theme-default; - - border-top: none; - border-bottom: 0; - display: flex; - flex-direction: row; - flex-wrap: wrap; - justify-content: space-between; - align-items: center; - padding: $gap * 2; - - &__title { - @include h4; - - font-size: $lead-font-size; - justify-content: space-between; - flex: 2; - } - } - table { margin-bottom: 0; } diff --git a/styles/sections/_application_edit.scss b/styles/sections/_application_edit.scss index 8ff79b7b..8282cb64 100644 --- a/styles/sections/_application_edit.scss +++ b/styles/sections/_application_edit.scss @@ -23,66 +23,6 @@ } } -#modal--add-app-mem, -.form-content--app-mem { - text-align: left; - - .modal__body { - min-width: 75rem; - } - - input[type="checkbox"] + label::before { - margin-left: 0; - } - - .input__inline-fields { - text-align: left; - - .usa-input__choices label { - font-weight: $font-bold; - } - } - - .input__inline-fields { - padding: $gap * 2; - border: 1px solid $color-gray-lighter; - - &.checked { - border: 1px solid $color-blue; - } - - label { - font-weight: $font-bold; - } - - p.usa-input__help { - margin-bottom: 0; - padding-left: 3rem; - } - } - - .application-member__user-info { - .usa-input { - width: 45rem; - - input, - label, - .usa-input__message { - max-width: unset; - } - - label .icon-validation { - left: unset; - right: -$gap * 4; - } - - &--validation--phoneExt { - width: 18rem; - } - } - } -} - .environment-roles { padding: 0 ($gap * 3) ($gap * 3); diff --git a/styles/sections/_task_order.scss b/styles/sections/_task_order.scss index 79f391e0..05b90595 100644 --- a/styles/sections/_task_order.scss +++ b/styles/sections/_task_order.scss @@ -1,5 +1,6 @@ .task-order { margin-top: $gap * 4; + margin-bottom: $footer-height; width: 900px; &__amount { diff --git a/templates/applications/fragments/member_form_fields.html b/templates/applications/fragments/member_form_fields.html index 3aa97687..707653fa 100644 --- a/templates/applications/fragments/member_form_fields.html +++ b/templates/applications/fragments/member_form_fields.html @@ -118,7 +118,7 @@ {% endmacro %} {% macro InfoFields(member_form) %} -