From 61fb678a18ed3b5a418adc1579da68d21bf26f8b Mon Sep 17 00:00:00 2001 From: "Brian C. Lane" Date: Thu, 1 Oct 2020 16:15:31 -0700 Subject: [PATCH] Add lorax 32.12 documentation in f32-branch --- f32-branch/.buildinfo | 4 + f32-branch/.doctrees/composer-cli.doctree | Bin 0 -> 69135 bytes f32-branch/.doctrees/composer.cli.doctree | Bin 0 -> 376510 bytes f32-branch/.doctrees/composer.doctree | Bin 0 -> 63434 bytes f32-branch/.doctrees/environment.pickle | Bin 0 -> 2488913 bytes f32-branch/.doctrees/index.doctree | Bin 0 -> 8310 bytes f32-branch/.doctrees/intro.doctree | Bin 0 -> 9092 bytes f32-branch/.doctrees/lifted.doctree | Bin 0 -> 117005 bytes .../.doctrees/livemedia-creator.doctree | Bin 0 -> 171368 bytes f32-branch/.doctrees/lorax-composer.doctree | Bin 0 -> 120079 bytes f32-branch/.doctrees/lorax.doctree | Bin 0 -> 81951 bytes f32-branch/.doctrees/mkksiso.doctree | Bin 0 -> 28045 bytes f32-branch/.doctrees/modules.doctree | Bin 0 -> 2521 bytes f32-branch/.doctrees/product-images.doctree | Bin 0 -> 7155 bytes f32-branch/.doctrees/pylorax.api.doctree | Bin 0 -> 960449 bytes f32-branch/.doctrees/pylorax.doctree | Bin 0 -> 538713 bytes f32-branch/README | 5 + f32-branch/_modules/composer/cli.html | 259 + .../_modules/composer/cli/blueprints.html | 779 ++ f32-branch/_modules/composer/cli/cmdline.html | 251 + f32-branch/_modules/composer/cli/compose.html | 889 ++ f32-branch/_modules/composer/cli/modules.html | 249 + .../_modules/composer/cli/projects.html | 311 + .../_modules/composer/cli/providers.html | 523 + f32-branch/_modules/composer/cli/sources.html | 353 + f32-branch/_modules/composer/cli/status.html | 257 + f32-branch/_modules/composer/cli/upload.html | 478 + .../_modules/composer/cli/utilities.html | 296 + f32-branch/_modules/composer/http_client.html | 459 + f32-branch/_modules/composer/unix_socket.html | 262 + f32-branch/_modules/index.html | 250 + f32-branch/_modules/lifted/config.html | 234 + f32-branch/_modules/lifted/providers.html | 444 + f32-branch/_modules/lifted/queue.html | 468 + f32-branch/_modules/lifted/upload.html | 411 + f32-branch/_modules/pylorax.html | 653 + f32-branch/_modules/pylorax/api/bisect.html | 250 + .../_modules/pylorax/api/checkparams.html | 245 + f32-branch/_modules/pylorax/api/cmdline.html | 264 + f32-branch/_modules/pylorax/api/compose.html | 1468 +++ f32-branch/_modules/pylorax/api/config.html | 341 + .../_modules/pylorax/api/crossdomain.html | 264 + f32-branch/_modules/pylorax/api/dnfbase.html | 387 + .../_modules/pylorax/api/flask_blueprint.html | 255 + f32-branch/_modules/pylorax/api/gitrpm.html | 423 + f32-branch/_modules/pylorax/api/projects.html | 898 ++ f32-branch/_modules/pylorax/api/queue.html | 1064 ++ f32-branch/_modules/pylorax/api/recipes.html | 1477 +++ f32-branch/_modules/pylorax/api/server.html | 304 + .../_modules/pylorax/api/timestamp.html | 252 + f32-branch/_modules/pylorax/api/toml.html | 243 + f32-branch/_modules/pylorax/api/utils.html | 250 + f32-branch/_modules/pylorax/api/v0.html | 2187 ++++ f32-branch/_modules/pylorax/api/v1.html | 1243 ++ .../_modules/pylorax/api/workspace.html | 300 + f32-branch/_modules/pylorax/base.html | 268 + f32-branch/_modules/pylorax/buildstamp.html | 267 + f32-branch/_modules/pylorax/cmdline.html | 522 + f32-branch/_modules/pylorax/creator.html | 952 ++ f32-branch/_modules/pylorax/decorators.html | 231 + f32-branch/_modules/pylorax/discinfo.html | 246 + f32-branch/_modules/pylorax/dnfbase.html | 388 + f32-branch/_modules/pylorax/dnfhelper.html | 311 + f32-branch/_modules/pylorax/executils.html | 550 + f32-branch/_modules/pylorax/imgutils.html | 755 ++ f32-branch/_modules/pylorax/installer.html | 879 ++ f32-branch/_modules/pylorax/ltmpl.html | 1085 ++ f32-branch/_modules/pylorax/monitor.html | 404 + f32-branch/_modules/pylorax/mount.html | 305 + f32-branch/_modules/pylorax/sysutils.html | 361 + f32-branch/_modules/pylorax/treebuilder.html | 625 + f32-branch/_modules/pylorax/treeinfo.html | 264 + f32-branch/_sources/composer-cli.rst.txt | 178 + f32-branch/_sources/composer.cli.rst.txt | 102 + f32-branch/_sources/composer.rst.txt | 37 + f32-branch/_sources/index.rst.txt | 39 + f32-branch/_sources/intro.rst.txt | 67 + f32-branch/_sources/lifted.rst.txt | 46 + f32-branch/_sources/livemedia-creator.rst.txt | 670 + f32-branch/_sources/lorax-composer.rst.txt | 535 + f32-branch/_sources/lorax.rst.txt | 200 + f32-branch/_sources/mkksiso.rst.txt | 128 + f32-branch/_sources/modules.rst.txt | 9 + f32-branch/_sources/product-images.rst.txt | 27 + f32-branch/_sources/pylorax.api.rst.txt | 174 + f32-branch/_sources/pylorax.rst.txt | 165 + f32-branch/_static/ajax-loader.gif | Bin 0 -> 673 bytes f32-branch/_static/basic.css | 764 ++ f32-branch/_static/comment-bright.png | Bin 0 -> 756 bytes f32-branch/_static/comment-close.png | Bin 0 -> 829 bytes f32-branch/_static/comment.png | Bin 0 -> 641 bytes f32-branch/_static/css/badge_only.css | 1 + f32-branch/_static/css/theme.css | 6 + f32-branch/_static/doctools.js | 314 + f32-branch/_static/documentation_options.js | 10 + f32-branch/_static/down-pressed.png | Bin 0 -> 222 bytes f32-branch/_static/down.png | Bin 0 -> 202 bytes f32-branch/_static/file.png | Bin 0 -> 286 bytes f32-branch/_static/fonts/Inconsolata-Bold.ttf | Bin 0 -> 108360 bytes .../_static/fonts/Inconsolata-Regular.ttf | Bin 0 -> 95960 bytes f32-branch/_static/fonts/Lato-Bold.ttf | Bin 0 -> 657188 bytes f32-branch/_static/fonts/Lato-BoldItalic.ttf | Bin 0 -> 699008 bytes f32-branch/_static/fonts/Lato-Italic.ttf | Bin 0 -> 723544 bytes f32-branch/_static/fonts/Lato-Regular.ttf | Bin 0 -> 657212 bytes f32-branch/_static/fonts/Lato/lato-bold.eot | Bin 0 -> 256056 bytes f32-branch/_static/fonts/Lato/lato-bold.ttf | Bin 0 -> 657188 bytes f32-branch/_static/fonts/Lato/lato-bold.woff | Bin 0 -> 309728 bytes f32-branch/_static/fonts/Lato/lato-bold.woff2 | Bin 0 -> 184912 bytes .../_static/fonts/Lato/lato-bolditalic.eot | Bin 0 -> 266158 bytes .../_static/fonts/Lato/lato-bolditalic.ttf | Bin 0 -> 699008 bytes .../_static/fonts/Lato/lato-bolditalic.woff | Bin 0 -> 323344 bytes .../_static/fonts/Lato/lato-bolditalic.woff2 | Bin 0 -> 193308 bytes f32-branch/_static/fonts/Lato/lato-italic.eot | Bin 0 -> 268604 bytes f32-branch/_static/fonts/Lato/lato-italic.ttf | Bin 0 -> 723544 bytes .../_static/fonts/Lato/lato-italic.woff | Bin 0 -> 328412 bytes .../_static/fonts/Lato/lato-italic.woff2 | Bin 0 -> 195704 bytes .../_static/fonts/Lato/lato-regular.eot | Bin 0 -> 253461 bytes .../_static/fonts/Lato/lato-regular.ttf | Bin 0 -> 657212 bytes .../_static/fonts/Lato/lato-regular.woff | Bin 0 -> 309192 bytes .../_static/fonts/Lato/lato-regular.woff2 | Bin 0 -> 182708 bytes f32-branch/_static/fonts/RobotoSlab-Bold.ttf | Bin 0 -> 170616 bytes .../_static/fonts/RobotoSlab-Regular.ttf | Bin 0 -> 169064 bytes .../fonts/RobotoSlab/roboto-slab-v7-bold.eot | Bin 0 -> 79520 bytes .../fonts/RobotoSlab/roboto-slab-v7-bold.ttf | Bin 0 -> 170616 bytes .../fonts/RobotoSlab/roboto-slab-v7-bold.woff | Bin 0 -> 87624 bytes .../RobotoSlab/roboto-slab-v7-bold.woff2 | Bin 0 -> 67312 bytes .../RobotoSlab/roboto-slab-v7-regular.eot | Bin 0 -> 78331 bytes .../RobotoSlab/roboto-slab-v7-regular.ttf | Bin 0 -> 169064 bytes .../RobotoSlab/roboto-slab-v7-regular.woff | Bin 0 -> 86288 bytes .../RobotoSlab/roboto-slab-v7-regular.woff2 | Bin 0 -> 66444 bytes .../_static/fonts/fontawesome-webfont.eot | Bin 0 -> 165742 bytes .../_static/fonts/fontawesome-webfont.svg | 2671 ++++ .../_static/fonts/fontawesome-webfont.ttf | Bin 0 -> 165548 bytes .../_static/fonts/fontawesome-webfont.woff | Bin 0 -> 98024 bytes .../_static/fonts/fontawesome-webfont.woff2 | Bin 0 -> 77160 bytes f32-branch/_static/jquery-3.4.1.js | 10598 ++++++++++++++++ f32-branch/_static/jquery.js | 2 + f32-branch/_static/js/modernizr.min.js | 4 + f32-branch/_static/js/theme.js | 3 + f32-branch/_static/language_data.js | 297 + f32-branch/_static/minus.png | Bin 0 -> 90 bytes f32-branch/_static/plus.png | Bin 0 -> 90 bytes f32-branch/_static/pygments.css | 69 + f32-branch/_static/searchtools.js | 506 + f32-branch/_static/underscore-1.3.1.js | 999 ++ f32-branch/_static/underscore.js | 31 + f32-branch/_static/up-pressed.png | Bin 0 -> 214 bytes f32-branch/_static/up.png | Bin 0 -> 203 bytes f32-branch/_static/websupport.js | 808 ++ f32-branch/composer-cli.html | 523 + f32-branch/composer.cli.html | 1448 +++ f32-branch/composer.html | 506 + f32-branch/genindex.html | 1606 +++ f32-branch/index.html | 244 + f32-branch/intro.html | 261 + f32-branch/lifted.html | 716 ++ f32-branch/livemedia-creator.html | 1102 ++ f32-branch/lorax-composer.html | 781 ++ f32-branch/lorax.html | 581 + f32-branch/mkksiso.html | 355 + f32-branch/modules.html | 309 + f32-branch/objects.inv | Bin 0 -> 4594 bytes f32-branch/product-images.html | 234 + f32-branch/py-modindex.html | 522 + f32-branch/pylorax.api.html | 5164 ++++++++ f32-branch/pylorax.html | 2240 ++++ f32-branch/search.html | 219 + f32-branch/searchindex.js | 1 + 168 files changed, 64635 insertions(+) create mode 100644 f32-branch/.buildinfo create mode 100644 f32-branch/.doctrees/composer-cli.doctree create mode 100644 f32-branch/.doctrees/composer.cli.doctree create mode 100644 f32-branch/.doctrees/composer.doctree create mode 100644 f32-branch/.doctrees/environment.pickle create mode 100644 f32-branch/.doctrees/index.doctree create mode 100644 f32-branch/.doctrees/intro.doctree create mode 100644 f32-branch/.doctrees/lifted.doctree create mode 100644 f32-branch/.doctrees/livemedia-creator.doctree create mode 100644 f32-branch/.doctrees/lorax-composer.doctree create mode 100644 f32-branch/.doctrees/lorax.doctree create mode 100644 f32-branch/.doctrees/mkksiso.doctree create mode 100644 f32-branch/.doctrees/modules.doctree create mode 100644 f32-branch/.doctrees/product-images.doctree create mode 100644 f32-branch/.doctrees/pylorax.api.doctree create mode 100644 f32-branch/.doctrees/pylorax.doctree create mode 100644 f32-branch/README create mode 100644 f32-branch/_modules/composer/cli.html create mode 100644 f32-branch/_modules/composer/cli/blueprints.html create mode 100644 f32-branch/_modules/composer/cli/cmdline.html create mode 100644 f32-branch/_modules/composer/cli/compose.html create mode 100644 f32-branch/_modules/composer/cli/modules.html create mode 100644 f32-branch/_modules/composer/cli/projects.html create mode 100644 f32-branch/_modules/composer/cli/providers.html create mode 100644 f32-branch/_modules/composer/cli/sources.html create mode 100644 f32-branch/_modules/composer/cli/status.html create mode 100644 f32-branch/_modules/composer/cli/upload.html create mode 100644 f32-branch/_modules/composer/cli/utilities.html create mode 100644 f32-branch/_modules/composer/http_client.html create mode 100644 f32-branch/_modules/composer/unix_socket.html create mode 100644 f32-branch/_modules/index.html create mode 100644 f32-branch/_modules/lifted/config.html create mode 100644 f32-branch/_modules/lifted/providers.html create mode 100644 f32-branch/_modules/lifted/queue.html create mode 100644 f32-branch/_modules/lifted/upload.html create mode 100644 f32-branch/_modules/pylorax.html create mode 100644 f32-branch/_modules/pylorax/api/bisect.html create mode 100644 f32-branch/_modules/pylorax/api/checkparams.html create mode 100644 f32-branch/_modules/pylorax/api/cmdline.html create mode 100644 f32-branch/_modules/pylorax/api/compose.html create mode 100644 f32-branch/_modules/pylorax/api/config.html create mode 100644 f32-branch/_modules/pylorax/api/crossdomain.html create mode 100644 f32-branch/_modules/pylorax/api/dnfbase.html create mode 100644 f32-branch/_modules/pylorax/api/flask_blueprint.html create mode 100644 f32-branch/_modules/pylorax/api/gitrpm.html create mode 100644 f32-branch/_modules/pylorax/api/projects.html create mode 100644 f32-branch/_modules/pylorax/api/queue.html create mode 100644 f32-branch/_modules/pylorax/api/recipes.html create mode 100644 f32-branch/_modules/pylorax/api/server.html create mode 100644 f32-branch/_modules/pylorax/api/timestamp.html create mode 100644 f32-branch/_modules/pylorax/api/toml.html create mode 100644 f32-branch/_modules/pylorax/api/utils.html create mode 100644 f32-branch/_modules/pylorax/api/v0.html create mode 100644 f32-branch/_modules/pylorax/api/v1.html create mode 100644 f32-branch/_modules/pylorax/api/workspace.html create mode 100644 f32-branch/_modules/pylorax/base.html create mode 100644 f32-branch/_modules/pylorax/buildstamp.html create mode 100644 f32-branch/_modules/pylorax/cmdline.html create mode 100644 f32-branch/_modules/pylorax/creator.html create mode 100644 f32-branch/_modules/pylorax/decorators.html create mode 100644 f32-branch/_modules/pylorax/discinfo.html create mode 100644 f32-branch/_modules/pylorax/dnfbase.html create mode 100644 f32-branch/_modules/pylorax/dnfhelper.html create mode 100644 f32-branch/_modules/pylorax/executils.html create mode 100644 f32-branch/_modules/pylorax/imgutils.html create mode 100644 f32-branch/_modules/pylorax/installer.html create mode 100644 f32-branch/_modules/pylorax/ltmpl.html create mode 100644 f32-branch/_modules/pylorax/monitor.html create mode 100644 f32-branch/_modules/pylorax/mount.html create mode 100644 f32-branch/_modules/pylorax/sysutils.html create mode 100644 f32-branch/_modules/pylorax/treebuilder.html create mode 100644 f32-branch/_modules/pylorax/treeinfo.html create mode 100644 f32-branch/_sources/composer-cli.rst.txt create mode 100644 f32-branch/_sources/composer.cli.rst.txt create mode 100644 f32-branch/_sources/composer.rst.txt create mode 100644 f32-branch/_sources/index.rst.txt create mode 100644 f32-branch/_sources/intro.rst.txt create mode 100644 f32-branch/_sources/lifted.rst.txt create mode 100644 f32-branch/_sources/livemedia-creator.rst.txt create mode 100644 f32-branch/_sources/lorax-composer.rst.txt create mode 100644 f32-branch/_sources/lorax.rst.txt create mode 100644 f32-branch/_sources/mkksiso.rst.txt create mode 100644 f32-branch/_sources/modules.rst.txt create mode 100644 f32-branch/_sources/product-images.rst.txt create mode 100644 f32-branch/_sources/pylorax.api.rst.txt create mode 100644 f32-branch/_sources/pylorax.rst.txt create mode 100644 f32-branch/_static/ajax-loader.gif create mode 100644 f32-branch/_static/basic.css create mode 100644 f32-branch/_static/comment-bright.png create mode 100644 f32-branch/_static/comment-close.png create mode 100644 f32-branch/_static/comment.png create mode 100644 f32-branch/_static/css/badge_only.css create mode 100644 f32-branch/_static/css/theme.css create mode 100644 f32-branch/_static/doctools.js create mode 100644 f32-branch/_static/documentation_options.js create mode 100644 f32-branch/_static/down-pressed.png create mode 100644 f32-branch/_static/down.png create mode 100644 f32-branch/_static/file.png create mode 100644 f32-branch/_static/fonts/Inconsolata-Bold.ttf create mode 100644 f32-branch/_static/fonts/Inconsolata-Regular.ttf create mode 100644 f32-branch/_static/fonts/Lato-Bold.ttf create mode 100644 f32-branch/_static/fonts/Lato-BoldItalic.ttf create mode 100644 f32-branch/_static/fonts/Lato-Italic.ttf create mode 100644 f32-branch/_static/fonts/Lato-Regular.ttf create mode 100644 f32-branch/_static/fonts/Lato/lato-bold.eot create mode 100644 f32-branch/_static/fonts/Lato/lato-bold.ttf create mode 100644 f32-branch/_static/fonts/Lato/lato-bold.woff create mode 100644 f32-branch/_static/fonts/Lato/lato-bold.woff2 create mode 100644 f32-branch/_static/fonts/Lato/lato-bolditalic.eot create mode 100644 f32-branch/_static/fonts/Lato/lato-bolditalic.ttf create mode 100644 f32-branch/_static/fonts/Lato/lato-bolditalic.woff create mode 100644 f32-branch/_static/fonts/Lato/lato-bolditalic.woff2 create mode 100644 f32-branch/_static/fonts/Lato/lato-italic.eot create mode 100644 f32-branch/_static/fonts/Lato/lato-italic.ttf create mode 100644 f32-branch/_static/fonts/Lato/lato-italic.woff create mode 100644 f32-branch/_static/fonts/Lato/lato-italic.woff2 create mode 100644 f32-branch/_static/fonts/Lato/lato-regular.eot create mode 100644 f32-branch/_static/fonts/Lato/lato-regular.ttf create mode 100644 f32-branch/_static/fonts/Lato/lato-regular.woff create mode 100644 f32-branch/_static/fonts/Lato/lato-regular.woff2 create mode 100644 f32-branch/_static/fonts/RobotoSlab-Bold.ttf create mode 100644 f32-branch/_static/fonts/RobotoSlab-Regular.ttf create mode 100644 f32-branch/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot create mode 100644 f32-branch/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf create mode 100644 f32-branch/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff create mode 100644 f32-branch/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 create mode 100644 f32-branch/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot create mode 100644 f32-branch/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf create mode 100644 f32-branch/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff create mode 100644 f32-branch/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 create mode 100644 f32-branch/_static/fonts/fontawesome-webfont.eot create mode 100644 f32-branch/_static/fonts/fontawesome-webfont.svg create mode 100644 f32-branch/_static/fonts/fontawesome-webfont.ttf create mode 100644 f32-branch/_static/fonts/fontawesome-webfont.woff create mode 100644 f32-branch/_static/fonts/fontawesome-webfont.woff2 create mode 100644 f32-branch/_static/jquery-3.4.1.js create mode 100644 f32-branch/_static/jquery.js create mode 100644 f32-branch/_static/js/modernizr.min.js create mode 100644 f32-branch/_static/js/theme.js create mode 100644 f32-branch/_static/language_data.js create mode 100644 f32-branch/_static/minus.png create mode 100644 f32-branch/_static/plus.png create mode 100644 f32-branch/_static/pygments.css create mode 100644 f32-branch/_static/searchtools.js create mode 100644 f32-branch/_static/underscore-1.3.1.js create mode 100644 f32-branch/_static/underscore.js create mode 100644 f32-branch/_static/up-pressed.png create mode 100644 f32-branch/_static/up.png create mode 100644 f32-branch/_static/websupport.js create mode 100644 f32-branch/composer-cli.html create mode 100644 f32-branch/composer.cli.html create mode 100644 f32-branch/composer.html create mode 100644 f32-branch/genindex.html create mode 100644 f32-branch/index.html create mode 100644 f32-branch/intro.html create mode 100644 f32-branch/lifted.html create mode 100644 f32-branch/livemedia-creator.html create mode 100644 f32-branch/lorax-composer.html create mode 100644 f32-branch/lorax.html create mode 100644 f32-branch/mkksiso.html create mode 100644 f32-branch/modules.html create mode 100644 f32-branch/objects.inv create mode 100644 f32-branch/product-images.html create mode 100644 f32-branch/py-modindex.html create mode 100644 f32-branch/pylorax.api.html create mode 100644 f32-branch/pylorax.html create mode 100644 f32-branch/search.html create mode 100644 f32-branch/searchindex.js diff --git a/f32-branch/.buildinfo b/f32-branch/.buildinfo new file mode 100644 index 00000000..d39c0cf9 --- /dev/null +++ b/f32-branch/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: c4915faa43645ef53e2c72f589eb92b8 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/f32-branch/.doctrees/composer-cli.doctree b/f32-branch/.doctrees/composer-cli.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a2ae315627a16fa0a2f722385ddc2c482c3848ca GIT binary patch literal 69135 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

Us1NzUEw*|B&c7t6 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 literal 0 HcmV?d00001 diff --git a/f32-branch/.doctrees/composer.doctree b/f32-branch/.doctrees/composer.doctree new file mode 100644 index 0000000000000000000000000000000000000000..43b5c8c754dfb6987cdd1de5897189f88ed16354 GIT binary patch literal 63434 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

  • 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%0DeouJJRLWN9T~(?FeX+E7GGwZks*p*o8tOngo%L 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

    H4`SaxTp-@!; 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

    NN?ig9| zAe>U=$9BXiCWO3h$tt8f|B$N?adVfn_vMhGwM}_r@wCk?op)r+uCfqRSnzP}{A1ZZljw`F16qgUgAr^kTx(Zx>1B+a z6KR%U-3PF5cE$sW-F*4Lj|NAq6bw$khxn^*b1zAGSonQkA}p|`nC`;5{%L3qdZQk4a!u14 z+&LKV{rh(E;WS)O-NkkPC(pki^Ejj^WGS!^Q4du5jMGxrC{aKLF#-LqbjN%Ga zOYIceMP9e$6w;lCNz33M7#5h}cpE)Hr?#err%U&Z6m~$T z|CYJTR-i1PCw3Y~HV6rKHQ{bEl7>J{2j;L+7*T4vIU-@eyQMB7GV}WW-{cd zR5I>8nC<)l`<2z#IL)Mu%LcYc9V~@l^^+4>tyQ~Q%~`Hn9VRjyh`Fzxb@st7;%g*W zP0_x=b5Y-9}kC@yHV??;}gFG=EO9Q?7dSl&;5Bx*wOv1JOc!^UW6S7r@`W!GZPY z{d@DlIAIbiCA#8SDY^H*rw_#sL|0r&Jb{P3-jU4Tin8IY$QA_ym|=R_oX?v5jrJD* zM5#M5qe)$SK}LoLol?5sDeQ~M10}FJP8G?NscV{i3dzh(e2=V@by<$>4RdUZS7yV* z8`})p^T`wyDvrH(%kg_w6t_QND`z9{gauUg!cd?&)`ui@hV_4IE-{gbdNmV&N2wN~ zqn%liUfM2f@kBAaJUIm~l?_MeLj2MaY^DERdAgJQVZBCBrtOSVOrOajOut~QW^m=; zc7=nT{ub>ywq(yCGF5hwoMH)JX~FyTBU9e{=+p3D(B`LPl1^q;jK=@Jn5~+qf!S!H z>eeGnRGjX=-lDk4azOnlHfAU2a3axC67KgK9mG#E!NSLt57`#jc=X+)Cz~=;AAPsE z`fQEt8#!<5_5#CXJHQaDtK@o$gQUswNci#CDojdsQyV_YNAssRuE;Y$z&aV!HJVVy z?qX}tF1e?0jh--EywPX@-u;d@7)6_lWaHRKYr67q!BpKX7>e!CAXwqtbc<^D@A6O? zwYA<{ZB;udp!?zoBna4Cd>4xIF;O`5y?iil;sopsI(n#$iyG2hcIF`8?1_MoC=83| ze#JTqU+Td&m4ZOz_4k{b>)usD@?7QR^S8{)=RZ&6h21uyCy19>>}g&@+WlH!_{an! zg+Af8eUDfqh1R|xYV!zeIBa!y;WMIq^-^L~#`&8&)GtH2D~}?9;`S4y#1DB(H^bBq zIP#)&4O?dTPa+-g+=a&qji$a!#H^<>6R~ju5u6yld!O;76GsD_#Siv7BRW#I@fjHx zLnKlYL52$c22)iJh7763+v5?kcR35hh)CviAW|#Gzmx&p`zzxiTG#!FHnxFY;pw5t zi{VR(bC&R5+qW50I=oSnP7qiL5233U@9Wp7EETAMjjMr;Ve4pE8|>Xc{l7juSRS@t zBPWVVnd#i|oos;JO$wC?+zg*=Nb=+!RW<@YmlJ+8YCKhH4GxS>U`A0TXe)AJ`Iu{u zF)r=h+8$}3MTX;}_Skns3CYdff4;@*j1PtvH8O6!8ep>363oQ^soJsxEfi9co^SD2 znwdi+r`zLQQj-)tU?s1K&!65E>s=jbDVk2T3rwSY?wv`14b4I1szhcIECDFw#rAk# z!ZOXYJ!?)(07Fj9c%Nc35l|DuK4TCeuemeG%ELhiau|2Yjmqd-ZB&RkJ%rClo0sCb zX(ZnD0z41WkGRki;qcJO$ELxVWEG{CW?`f-?&=fh*de87wbSoG?_Cb5GK9{kR$cP({AR)Qc!T?IL&gG58Ii;4CrdrFu=31P^emAE zI4AeK7}}Y%%CK@&R~--J-v3tapTQ+2qZf$ngQb{cB7o$qJXzcQnUz;18oGVZ-&vOZ zvLAh>7y#X@XCYCp3!W$+8(|YtGGa2SL+MhIIBrT~jZ_753!Ww)KnVe~^`bn90z0OM z8%$gjd*CFSlpw*luRNg*U-!qSQT^wC{9N!&I-l}C?ZKdZ{3#+P4|{`SzO5nlJlV;d zA(^hK4Hh(Mi)F|oxkb;_1M+**u3S?vFX64-Eh@ZZ7nqE$Oogno!xb=-m}kP{LQb%0 z=0TOyKu~r=NT8L|c;ZFpH5-wZW=4(aD9gK{jS_R&jR1cefhhH9f76fPj@!dbqB825wYVOL2f zkZ$T*`cw!3G;who@o7h`ZOOaEZAqL;lun9Fl~om((mbt0gg)}Ay?+VWN|%K;DV3nN zQp%a>k)v$z+%$#%rS{%cp$eaDw~s#Zl$&;Tj&K>$T_GcX)f4hOkX+4s7D520q28d` zF~rkPA@1_{?ax^2kR3Kc>MfT3kmL)}?+IyaE;%n+486KOXt3R>8}@o&cY}HY$|FR? z!n%}|iTY!~Gc`UqsAHu;aAqwl2^@U8!~niY$a?vsCFX6)pTTp}n}AQ{4^y0G94~BU z+%qOePU-{*^GgSu2(p!a-p^`7C6jkOfr`xApP@DV4EE&)NNduH3)AaURA>IQz}VAh zUhrhC0?X*^oZ1wUSmq{_2ACpZx|dCr$Cr~Gk&;A1FZ$V&KpZf5plUYZ!e_e32UtV8}9 zjwdEk2oX@9_0(bPR8qk*!(WpMRswR@JxS5D9xo z4V@Q?$cgdWHbXJv-Za_iklEf#OkVFfs9?JPDzsrZ;@%rhXb(y0eE!rMkNV>ghuUCk ze2BCm*w0c;_u!bsVMZ|Pv`S{vGO1e>2AW0sBt4(L$VuE(&dKyeMtKE=^7*o_#}*;n z5-kGo+aTn2rJ#BNzQ~-YWuGr@C}p+-!M$*YDMUYm;<#H(jyifpX#U|3FgN^tZM+0s z(N|l&qn3{?GxRgoWu)(4)Y&Cz?QTw>yEXB&E%^)Yrt_$whSP}o-}t@~QIp@^n7QyobdOS(#CsK(+N z#PNteMyehP{(Y=iJe7$2sCa;<_)Gy=&MW|P{4(rNT55(PYZGL&s;)BpRvVt#ly*de zSwM8j&RrpVdXjn>I#s^rEK^IhfuBQfX)9Bu@7Wenq7VIbaZD6?14L1%hP@1V3IspARVcTxD%s%hvg{!sl&;qR z)hXr^Q+KyxRd0i`N_a)cr5Ns($kQEJ`=03uUxB25RM_Q~?%;R{SNBl9LT_*Ms$DXB zG81R7{r9rRy#~xJ{{Ww_EQ#GAVqgZl|Ae|ND6NTDPE_zXLVDf-;%1MaHIex7--)ST z?)>RbMzGPeQGfW&ojY`??6RyX%e}$=oqKnJVClgSy{r3&U+%QG4N#`wivk@Eai+5E zI}@+Fsg?WRrc?g<4ypxr_D22enZc8jS*|-Xn27C`R*3Aw&GnkIgUb{V8tMnMu;SRl zUm2r9n;qlxwCNQ@xA^n`$GF7{)JAM^L@b$9G+?ttpDs$P*(qe~hPYuXotu~7kVB08 zPFYsiVd3ka78|Aeb}(X6?=o;VX;CSyh|Kd9g$h# zV!JDK8wAI_OEh_1o8xa7tsA>Pu zFErJxu>;b}DKhyvosTD!P7*R&xcoU*UQi*z~^S`koGIA=Vx z1dJN+%px!u+~X+xH0=b~F^Lt+pl4Xu?oZ}bisDa!utlVMJZSb_CMr7|XDXMRm6Ua6 zAyrz8;4SPLG` z4-_}29@Kq+W0ydKLPCVI?>!4*Q!s$aQ#$W5N^^2oD3JSbgYJyMS~x6L{S7bdD|$dX zKD3{R&q|k|ZaTRS?CNl$$Bo}jJ0ZZhUrRgn3#RMq%-gz8Qv{+cr)@uZ&Blw7xI(Bb ze-tlYAEItD8i(75CktJJ)R_cuxxMZ4%#$xCP;novglpi3p%8mTHZNcSsS0A|Kr$-c z`m^VN2P;OQWxx*);dPVUz7_k-VTzbZ@)FfF(~dV-?mAI|$L}d?!;;r~5gegHW_QT` zNL0W78~!p{CevCK_kMThWiSEj@Z2JJ@MI*1jmhxZ5`M7F&M2JN$yNI~LBkr5d;+a` zZtLjY=Ucugt7+$x$?8ShNtHeimK8;d%7$LYWmfk-*KdDz|00ijTFYxv2=*J)-lbRw z3JfPx?Wo|#)FtopLwOk{?t!SgEKJJ7K7#%#Hc3W8CU0^QEbJ}gCsqoNyGMNKCpzt- zP$kWjDuT>;NJ3K!ZO1Oc<{C(@B^0Fxb_=3Mf1{)*Hki*Tg@!LQM4?iYZ)eMFf%rI} zdn{|urWWyoInxSnp^YqQM0<3LQmOSAG_vxij%mEu1RX6uq3-hN zg>89e=cFA?FX3-X&_lV|KvuBP(U>5i+?J80jA~L^$*Yl`FWrTsXd=d+M%Xa;$Um}? zpbz{pWvxDFuxf=WWPz+4dj>qx2A+oYFj2;md9>G+y3+N^D6=z5S{*O~{qRj>f!dF+ zsp7SryK~@Th|3|uqYX7iWFQ)97RbFvfq!I~!6VDZNFbAT0G0$jT1tsFP=+|Tgz*{L z>(8g)NC<%F-zC7~%yjgo{#8x*;7x$0pG?B$$wX9n6JWdgs(%TwaeLmsfzSve=NUh_ zcDSa~)q}Y?6wHL#f&&bm`{F*|t3e0;v<;+7_lOXk zEn$(OebI4mJP1Jp5+^`2fMk!}XdO!RVABzZ!}WSp;7A3>IC5p#jOPO*4{w<1oXqYm z>|sM7gN1QdH_106909uUo;EZbn|E$F?o|xOTItNpG(D^^G@kT+n4J1WFeGlQ2o)To zqmn+n{lio#{HDsoR=)?YDGI+M0B=j&h^90CGTGv8%ob`E1{y6-LwB3B+``Bn+o_sa zlH$T&jUWqH?wXDRK}Q3JCdM^-O3wS?$v_HE&5=aLCxjcIlK!v3ad*D!NTd!_=YUd@ zQi3#N<;0IC?yz&PM@-S;Ot*wqtk*_{Udm?x`Jr;ci4Kyfd zcS!jcl9Ysgg42v@O41Gv1B|Zfz3he~ax=9v>yr*C4f?V`1fe&0?z}%HCt^@>{Nvx+ zXEwPKf$8X_H}X)|J0#u#53^ zRgz-v5z1W(#CR~Vo$yp@+mvxH#6_cGJd_b9v=Cj13$8G$0A+2KOe1B5#2fmu3UmVH zE7at|#+>95!5C?A1(f zXRN`KTdII4)u*(5Bq;~0;n3e3!B=+%Jv#M-!v_kqHr6$>P0lbsf*)3F)<9mKf$C?qaPvkFgKWYC3(pb~9#_65mk8)5~KDuhKHO9N1Pzo|(TZl(| zmb9J0r==4>+yxCuler24dxs-|sKA=0Brxt*4{!q)_HE)Fi*bbo+#4`G zuvK7P{D&RR1@KikNM(fh(-y_tAY2~xByeSFIp*eHPc|e4+V}J+$hcq2&9Ed}fg6bc z5^f6S26O%Q74A7Ad594sy#>Cx4Hf2_9Ck6o6PTY&#eE!km!~N4o_UcLDC;xII)%B~ zVbA!W!?4$ICqV8T2hQ@~UNbaw`(}w{R@)PaMMQT+sInF3w~5TcZ#@f0ImNBz9b7gF z2a7*@qhmA*euqQKD9z0?iPlLJIP(?-r-%nyE8|ffGwu0+P~Gq>Q-~JTHHb69aG5zG z&vaZ3C=TmAr6}#B8LlUMn2BlF$OOrpz=p+yy#y}Ilp`j7HHisUzO*a1PL~EXxCGJ6 zEb0}*PJ)g&|1x8r@>X1kgU5Rld8C`bTD@0D0N@}aM5K(`HF1;eGYMRk=?pn{x6%qZ zoMpEkSoHfqsvX>p`B_WaG*O?y{xu?y@dD;VpbQD09)A_f6OjO@4)KiC-tBlc9a2Vw zt5fI)8X&*mpPDdo4Sc}@V8kr}!xc)V!$0)&a9tinh@gNb0;rKR*4@Sxr{(K98Wahs zp*|7XU4Q7yDF{_$$}3g$gsKBLjXNlEI6*6&O&wG*-2zMoqGNT^P3<0^dm`24dDx6d zX3WiuNa|vrqPi;@1WYcGQBP>0KW;@4{GyJhf~=zB5YCBo9AMoY zsy0C-CsfW;zfOaK?KPuz0s;5IW8t9i98ft5s!5?7K(cfc73v?L113Vd>&jo94$yI= ztB$A_gQb=B+u6pk0_nb57b=BPDQ@=$-(auJwDGU*BT(=rt{Get(QER0{xXi1jBZdS z5aGTq#}I5^Uh#5;lm79buChTUCn7`5z`5yXj2@TePdrsB6V}~3rlFwJYTN_98~yK9 zt@y*4?2HCP+<)B&oN&!8 z!wK|Cs#KS|@M7&&;cUxY6*FN(Hq3E5pnJ^l693d{A7F8$Wv4}HaxL6vR;rhOwmoJO zDthMT?KND;F+eIIh4`jwAanMX5&VedE^Y)|C`DC0Bu8YO*Pe2nP4!eD-TWpME=j2* z1`xRik;m~?4WKHfTX-&XtN~Q`d4l6xK9@!L>7U3wQa@LooN2;O#&$RKJXq+K=FB{z zcOV86dZvj$@cZ6YE@QciYKgJto%Y14F6Kv)`?1bL~_lOrz89RgyN)4_CwV!C?mSLP0-lx zy-xG*u6pwD4dXJN+Vhi)&pAx|D)kben-y1c+H_A_x=0rit8_92b4#=D?ud}S%4^D-v2NS=>ifdWhGcuayuKB7-f!s&mYNI@~05)OHs^KbjmC)*zx zh1h_h0O@|KjL?M8uVrRX;3H1E5x6E-l+1X3IBV2$lQ{q}+~|y;^2w5YiUW`tVWD`8 zYPFIt33Ve+V6GygVqiT%nWfnfs~-ytl*hzTj~@hT`{UmJGogj9hYI2f&lLD#ulLQI zFhx0x@1_mr5SKnmzx($3C=ZU)Lom5I&V4ug`}B+yW{3v|&K+7Y5LKi%$@`Yb?R->1 zjZ3`SZ%O&_LgNLXcJ?&1$eQQ-B(J4ChEDn1_@u%@JYjsEw#vx}v=lLE2z_R*Vwq6wxiAurk+G*e#wA zrId-lS?wgvEDJiMHDz{{rvS+lrL&2iO-aWwuJrlY$5{G%n*K>?T@F0aFVJSAwi)CG zu{nxR>gkB*7Q){t=_p?G^H05_w;z}&2$ z)>5ofwwWQ7u$6jx3RN#cmv=jek3RX|xSXiE=Jt@U0|7#0{atyU5Yp1~3_7RSoQc4f+|Ct12 zMya6KXh}L6jGTYj(h(%L_z(_Z3fL;xw@KA%WxWnv31hfh&f+@j;3<|n4^x^^(YR~c zI0Vwk(HGezb`CUHwrX2hf-L2rgf{9;UZ=DrYe^~=?ri59!PxoEJD;b1eR+hob86VU+X7XLg(QZRxl5T;&i;`R!-rnur1G#Z`v zP&M$@E5t|G(QF{IKSAvTfwf4g(tf$y*)vlvqbQ?IOl*;yr74XBgqh$^7R%K_ZsF(l z80Gd(j>>Ita72DN9}pellk)`Jdk=(xNkO_d^nI!M58Z#z+rf2B&8yqWdM&SOuS=V& zknV5)svf>VPE&b!LOEtBrr#$Bb(OOPKDOvhsrvqcCnF z20mu}J6jS9WdtRoo5ewZD<)8x(DsDKao0l_8wm;tM&W+~RhTb0WT$2ybzaq+bY|Q{ zSjyyHlRJ2o_fT6p(E=l7XvEridP!6)Z@IoP(~;O3{68ikJI`B&3F*LpjJU{!tZsaX@gBx=vXg26+Cx2(nOU&v427P zs$9;9YdQAebH&`KrZ#0fPT9=>S@~sL_x=OE43fTw$JNvG>36)C-b@&>ipUOmhAW*+ zW$hLiD&x{FMSm=;l4G8HCn4&2fat~_N$n%3(a1wa_@e}3tCso%rKM$5xA+Jo*w7HJ z=mBN}aw0n?u%Y|A)Y8bviQg)Q_f^SM@JLSd%XE(l3tYdp1^1rk?9GQ$mCTWfrv%>yYQ*l#8m;@1u$xVL?%)FQCNc|1*wY&6A$DJl)G^U z=y&Kl>`Wv)^l2>g^$wjqm^LuwScV8+0Rd zMF+3zuo);sK9Ft2_);5?*uOyQC<5*5T+8JCY5&21g)&r19>bk~(s@PZDM3#Yv}Qk> zshknOXe3jT7RB>L5&_G7{2+mr@&>gl`sI`bjBdFkbH;c}-@LmuT z7lL3tdXvC7^{mxKtp=X2DD;cLvT7%DH+?|3Q}umL2B#Vz*t?5%r7{shnv-Ffv-bjS zi~E}lF|-N_5*N0nGpZ45a0BA3nA#QlN}62-SBd8#l85j*oxIyV$yhgmcZ?6Jy6)nd z5op3P>43_$L6|`C+hUWKcHFVE&v#=$U+M@|r6eP+;kB}eNQ(r^efnUsd=$4IclO&m z$Ayo2;*hzI0xkwa2T(V5bmnD`LNXN?0#HtFCed(9iTL;}U-5vbV|u?Ipi>^jQnN#t zx#m4!G-OZV-Q|R{4OsgmHekw(W4Y3A#>W`>$cYmFhL+#wOZ9@p(Teau<%hVq9^ep5 zMM2S+R&Dy%OsOZ6SBda`RW^hO%K;<04?^Sl?p$1y zzEjXI-J>wS;w;~)HAxzAqHmUGxPFiAY~Vz@fTiNnF2zz(*n<_!j6lS7Xp*xgLb^+| zvT|4jlba`U)PXI>noHhYeO~`QO}=TD_GoqY(s@3P`PyRPlLEIj}bVi0^<5)kFTW^ z7nCrMZG~zRD^NJMR3n)Bxsx;6p$T1& z=&pL|lnMn2*8K%qUFHD^2$&G2?Qh6~M+`i`#|#QN9tPv1qqob0M+`hXV+tt`b2=7v z>(yCDU$NZWs;q+P=m!xGF_3RZ#1lAojeRTkxtji}26xIGB{yP&eNn>Nv+Rr!niar~ zmO2cms5}No&wu{M{~mHsLa2qP70B4nb6vS2$%QUZ^TBpa1Lf{=jB_PjTX^eeaaX2tq6s5HZG|cctekt zMA}>#z0|-1St|u)OtWMiYc*gmh_98HVXxgsth-_BtP-PGIQ;jh=!Y;V^em)eikx*)7(h4u+#h18 zK{Brcpyv&yjZKdKWl~uM5y0F9exjPb5`x|BG439~j&-6T@% ztf5ZjL)}{OYLN9*Av*yUaXnAh9+4X=kW9Op)!7lIdMzJkQD+9sO_Lf)31ZbeY|%3l zHQ8C_Rt3<_6XD0umML)-th(vc;OMW?;fmufKa~?qvXw^g38BM-T=l!P9eWnJN}zB# zWT@szE>XH`8|HD^R32Cgq^+fYmVq^3?iSmGRAY1H!Trtq8|0~|%Ll8}-{p2$ejnZFnY9tGq(>#|H;M3>u^k8lh@W*H($<2GdMO z;L7f3S5u2>d1(+)LP9re<8lZ|nex2U;KB*I`Jgtj%Gbr%!_~%AAIsQ^8KWV_QiSa+ z#qVmgSQ*uQ^oWj1sqQ?afCE;w9!8*yA(~6ebd*IR<4KD?Qb{Y-bJV2h2cfxNKj1TJ zs!}{GzU_=&bvj3UB?*`0k_=QfYp-?aSd3!Jj&@P7_s8yjHN>WYH4`rgnSkf6tqLJ# zAR&a#I8X1C!#OjR4dvD`|B{G;BDi@X11u)<=)o#C@`KJEyz*U0C&FT>Uh) zE^IBu6J;g_T^5UY7R{gblogt4uTe)@X!n5KFSs?9G~!_odN?psyuv-qRH!&GgD2=R zSwX@py?q$moq@PTyvcy$>Vq-Xsro$O=aY|B(s|v%EbT0NME;xO*CvuErVnfQ;x|W2-giSSZ%0eCp}=8c`K65 zLqrQ&AmKh*$47E0@SO}txI%0j@#XCNQ8vKijg-f~Q;qRjdC#0hH=lmYq^03z{!E+E zRF1Bs9O0VOiYCig7O&ui9pY&3&gaWtdo?D)%A^&{efYeO({`ljW5vU@9^VwJiAdjF zzDI*+rX0P_!44BHxO#h2u8xwsvI+X%QshkOh%W7_*It1d;mRD+pK{y+yqo_k>UEK- zF8uX`)Lpj>D~AUpViP*+-`<)Qz$7ivaSNDx>r6Y9sgKIsVQQ4#Of~5L{Z=`w(sEac zOMGADbir^+cQ~2xeDd}_i`YT* z=n&4zM8-7{CA~iFBLcdss~#LVFSsdsz{WTW#^vx-3%BSFD2~`jNM?tm>Y8tmRaw+V zM6^g;h685{^al0)67~sH1`C_S-T|oBF7yo*Ol8kH2^;$(ruxhiO||kgUK$)r%|AO1 z4UWIy4nvV_^vW_02-*}p=Y=)Jbkm@Y7;3Hs$RqG>r{CMLI`!_!I+fD;Jv_gzkvcO# zn-EB!$!gT0OatjHkXv5e-S6;x;_5lY=AgTer1lU~f198GB<;=F&R~G!5-nC@j*5xwXB$0H0KwBv)bRkWsh+)rnL4R{4wEHz$%zdgh+?wue`^}gfvMaQ9xGBrU4xR z&Rt&B??e!Z23mM2zG^x&( zrY&NkpmG`9DDdduK0o^2>dDM{rQ_E>W)v058bB1T5(;!N3z9T7V+tN5p6Zwn^cJfZ zOTK}Qt0C`!uu>6j!5_(21i|%JE6#X|GKEZEH_&8tBt4S7wTh`Q`C8SI8P>_2YvFtw zS6O`q`Q=`n2X$C%2)6lKkMn~~Gc&H^C{hy)kuokb!KA2kai>svkT7C`lKnB%2>0%f zZN5mxWf++l^>FlrEHk(su_7NqP{R~1K|{9(YB)+EYG7e1vS5WPV+%#<$;&~)eS?q* zI28%{MGFk@J;0{38|mI!N`hq?CSRdpP!|2caCA7b&C00U*enT?NoyTMFdk0d#;EMM zeOH2o+zPSgrllFXD!gzffM}0G`$!4y5DgC}pr*as7vwx<4|?C%itH8IfJZtxsRL9&m8? z6mHxIyFw$anJWC@{X5~+vb2_f-Hp{SWHMav|4BE|=v>_M=NyeCHqO?1Jsbhu4Q!XG z04ONR5eO799i~Y>?hTy3#3JB74#|ZJpC}$My^%S~t3AM(jOzZFp50K^V`qSkX{Xrs z2WomJr{B>lI}%*`YX%#G+yGNfs$NqYrHyYgAo zMQU4BU3@-yhe!?J7exHx`|!UXBdF}Ccu1wy(N_n@#r@$+h`^u6i1<|FiUlg#2s>r8r1I%HM_BQbZ{JG z)lQYn9jMevl>^2+vim<-MtOW`u!aZi;fvdMKG7JAFh`izqPK@;=%G+?*l8a{_7NaY zdH!6p6BUHu`0!`Ur|DsHEKRIWMs=Tt9>zo9%L{_%pOVN2ud zUR($v3u&_(q(`S!Xak13@K9qf(5xkDEB0)B6D(bb3lHG1TpKWBS!?@9o`ZBo& z(M=J9-%F4S$=_o7a}d;YG%`krc2Qkf;#yo>2^7hvuAWQ$cy;HKaYDysf8x$30d<#% za@_6A@o!-?tOjimG&X!e>6?DW0XYsVwmZn!q=d2_oIn(}MWlvBLJR#qMPEuea!Wg7 z5o>oRuSNzG%S}I|hKivhn=N{td={2agGfBp<9;IKSnk8*W*sTVPD4#xFiCEsXM%3vg%SOFG)DQwRE{&|9ulfXy*s|Oyv}T6tqDQ^ zItJA(%U$x)5fpk=KuW3ZVn9?XYFMMJge$I_;Ox-r7}VG+bckDHwUd?8K7?$EF7|x*)C(b>4af zlahE9cRiK|cC~ClZz3?oHZkM+l*mDAqY4svjTy+#U|;dat&I$A@r$ zmJ%B?1*lYTg2H2%R)Epv=$Dv1rUNs6@z{a2;sGEL4M0Zc9!<)5eDji{S+!7X+HaXv zRr(DsX5AZ-?$j5n26rl~o8Hdt~NSm=V8!RK?^|X62oE|MY`v%1$ zla|9heI>k(Z7bfY6gg|K;R+BH4g#WE+Jw{Op|-T(;C-fr9`Li8cvkh9>XHV1V2v%M z63}#7gF7=AbGkcYMBr2>89aa}GQR(!Hy%l) zF{GKK0aP=4cQ&VTto{tNw=wlm{?5A$!l4X+j@(JB|}>nu~ivYi-8|Y?E-qwD7XK&E6HIXvwV;r;UsTpx3g>VmAz44 z18!7<$>9_prX1H%TdVkG_0B`|Q;Y_6w7W@$^#_g1zC zgLY$ESjD8gp|@ZiR1 zfrV7ZdjwM=!hhvl;Een;jzZ6I*GR?qvqU7;H6TG#GBUgato=3^^^C(SKni|=+feTP zCR4!Q9-s=0M3Z1jz$0tmpA{G|3M}2h2UkWS&)6LTq~P2gmBfk6!XA}i?Y6{s68yFg z{hw4spY{}bjy11RP^*hFP8Gkc^RQkQ`A-4M%?G;4zV4>d#EBVO2q;}cZtil*UB;Cx zhDF4&^lNb4#Yce#)-9fv(h2F(*W%e=Rz~n;AmJ{;vEoSAC)^-#H3mor+8* zFI0LKFG`bA1h?>A2ld2A=F=`+z%%k~ZTXZ;7*K3kCE%%w>23zBan>&a25X(fC$gGckyYRld z`2^vbKBz!qICg0}tG7p;+dt@Smkt!psLMQ(?11D$)Mq3J^YSH~W9+qX4Y?KVjCERR z9rK*vxDUSLujrft2M}X_e63fVv(R4v_2Cdj@=c#+_Ko_ypGx{Rrjq`NHeK2OsoTf? z6-py4CWb%*%|#HNNDY`dYBAfcMLTA=$txObrSPOfE2^c2?4Vh`DP8IRBq3x~+j*HoCzL3Mw!Hv`|nqWAR0I|ApMyJs}J;c>x(k@B$xlz!yimY18bCwD`w;pVr{GE8okvyf8fW z=%70L;$`QU^o~zINNuu=)>OGMv(6&9`S1T_^d zrIhb*u8{U*#^TiGQK61y!SKUagJ~0~mdM}`bcJF_`xw*~-r0;`djlR3eulfiu?;gduUfLZET&s0{!Fpi#9&semU-10;l7`7X z`8vP1+ucXp>EwQTLQf69xpN0)d9hARkW8oDCewa^icJ)RSF4KN zWZGANW!gXU^lJ3b9Csm9GUa+BI@okrW-ZWBq}P|_^+Y8mc)Ik6z|iJqOtDAhh`$CQ zWlSonT?6G7XasoMF&<(!K=8b7gS{=D+gnFR_U^m}^Ya94L5SMCYs4K4gd?d%6DClq z&>I}|a2wMg?Fq2%8nqWTgQu6u*cEyQp>@1BsXO#(w9ZmsaS|+EhbhWoO(>-tu#Q6Z z8B+a*^~a+P^h0e|R6yM#b;L7ID`kSG+EAxh?SQ<&RI36DCmS_$?49o2KU&$#>^^m3 z(K|Au_-(qM5k6(9*+wC59H>n)eyO`#8$OKwRvkf15zS8PM#1 zp<4zsI1Tn*^fKm@A0LC{W*)8GU;jdV{3LyzR-M*78!bgrT8YIyN0CLbAg|rMHc6RboI&HZh7p2BT#zJhQM@{Hid<()KZAf1QLC(muwT}NXSAsTpd zwjl}k+rS@qk=(n$ODRENo-qFrY4H_Yca^vzQV>a-7Jm*8mpAAc8Hw|tdK%=BCdZIa zgF%Z9_V~=g%1WanTS3riP(pJg97JHyIY?^W72$kDCqF$zo|sf1zML!&-hs>5DQSXm z3qq4dd(FomLnNVLhzLZfDUndm@80sgln6n%I}+s;K#R5%BL(eb?$Mei+>jEu9G+IC zWBWU!?Q{kNgc3s$&^jp=!V3s2s8%z~SjVCDp_*Y8%3a0XoS}|k_?_B1EuSPs!}NF~ zS(dlcMtUR(P?nzy{~gG^k8cL3YPH)M!sU2?jR5itM!2vWxz5%>-@sUgGq!`O$dt>G zg>}Dr7AT(2R+3>_!KX0F>GOXcgmFkq)SkRkk zgS_WZ7t~Y(txwiKIw7f4E7c>T1F+6OM=Fj&3EkaDdTYH>Dsqa>HGS=VGie$v+Y=0- z1kz2>*{2e~ya7QJfx-T=oMw}mrSbHPDn8>yZFNL)ANv!+M--(KwiV=zj>l=D5{Z5n zHQ{J^U`9;4Gb%C1h6Qxj9(e*)2Ijc~Fn3?n^+Ki!PmX*Fhk#hBaXF#o;_0j-ea4ns zK)2|}p+bI^+8sy6bb985C$>5cdV=CUu><}oGN3utiFcKfd$$=6ix&eESgb>`P&xxM zCWx>C%LN%mC1z4I48FFMEP|CZ0}1r|n*s@=&q@Ojp2fErwP4`4)6Z z%{18oOWGCse6O{~_ot;o(ZJ7C+Yx0j8n~Nk zIjMlUyXb~NkGr146jf6X+S|wj5?ca0DBQ#A8S(eI(P&{7%V^1&s^KkT+hs?}L%D0u zP(Z%h`H|R>@7VuIWM=}|QG4g5p_*AY@>ChgT_ukVwx68=+ynSOd0s&wrCAN;Ix9^< zf<;O3TRasIIZWmi(Zj+(2Ue(LL4RO4Ofxf`>mN@Gvs9qmwPgD&@WJnPwfr=~OAoE@ zDC0kGKwa?M?;;ESC1&9p-XaspVu&jWK^dL#euXCt&tCU+3&BV>aw=n4HeoG=b)QY* z5Orl=7q@9r$n&04PNVy9600~YN4}liab?QJoPt|LcK0SR{DaV*#B+7Xks@OczTR-i z881KN^hh$~3*3)fcb=A01Y4L1kcn!U)N=;Q{hCY4lX6+5(pXdlaQIEJ+3m|rM9tY9 zxusJ&M=Z@2lG$;;2o50(GiT_W3ZDDbW7Mi9?<8viCPLeHc`z1CkbX&Cx2&9@UksMJ z74I8gNv&nBCBvHOGLMXZYbdFO>GGI~5SuhK7R+6fgvGk%UlHPC1k2#Eu^P>ovDhY3 zw`lIl3V(sTK~}s$Gs0YhN=CFui$$sCqS%aeGKqK@&RzZ(*4v}{6rLXPv$a|l^$wYZh<(CtmGWRI=(Nj2WR*Z>w?1h&>LA^fbx){B z2!RW+O@^KJ0GFoHX47cHGuS36lq0Wcckh@~v+N%EYUvH8R?ucPipdZ@Yzbx_+hWyc z5EFyt7B>`{?UBFrwhNFz+eIu?HfvST8N{N3=WcFz@h^Cx;zi++C?sM-h5%Q9wO`ik zP|h#}DU|zQlYnUiR1gscb%fiZ3)u~U0eEh}G`Ttt?F`MR|5#=fu*gid`di|h%+=D-%#}|K_ zIhhejIk@&Vq#X^5=RQc-qDUan!d1qvj!=7qYO7F>@DfR^{C(W*)N+zpA~T#AI2>NZ z{!vDrKO*{U9uR%0wg<&slFrPI`D9T@LEW4m$1VSDDu(C{KbEOsbh2rJ_iDrm`r>-JHn7qMZ8%A(m}RC>n5@l#1(_GI*<$HH#>h+JKvc~l;a zS6O|~FTOOqzwGvHaU5Vyii8U7LtR!m#KgPqlP9RJjM_>xUrBa&Fn!!J9bX>8l@qUU z`bF1H)651V&Y9|wB@zV}B`j)m%%%+NA8fD4g&SxM_By~Yk zvkkG6)88QOz6VM0ksd<91^&-46{#)rN}zV?WhBL)r+7?DEMP&uDbXa%=L*pr^`HwT zoEKzteGn0ah?L8Sh@SEfg%Za+d<&60LXNxT1l!DXKasfNNoO-d#WPQXI{R-BA=(j= z4NB27W>gzEgXw)~a0MxMHX(G8meN0NjmSCwhICUT4fmaWX>SNhRa%3VrI$LDklgIQ zFm$S|ulW$g78N1e!cjFmYZz?Pu8i>7gvJyLn^MKnmR$(pkZGGTViG5O{qi61+=YKh zA}wcMqTugXa#~hugbt(_?2-Vjjqyf6RzH$Ii=_RuyL&5xcCS ziWSM=UpUZWXz7?VFjVwCnML{u?h$VYYLT^KgBDZDAjG@{HI&vstp(FtnT5J$KN29^ zdx4aI@Y@Q6Q%%)J4(g+JAroi%OGpB4DIej`5o{skd8k_Eegc3 zLzLNLDII!~Ui3X!furL$qyf`v-8(>rH6FzRDtGCf<2!FG$xJsY$&eL9flVI5%|7n! zBk*=#aw55L=ly&$U6*N6l)Czfs&H=papyH`j04yo?StbXObkfHtY@z-1|l<)#Kf{q z>TVAZK&(LSBlVwi^L#VmwnI_;$MPuApHcd!@*!xS@=JaUJ$dg#c#lppy^ID|Qa#o~OGxgfR3WD=md{{9 zhy^^JJ>0>{l1gWP$nDc^P8*t$5+z+114JyOkZ$g=e3K5|G@g1{OEu#{R;p5V0~5@P zNeTry!N-);B{UXs*gHr`F`7M7RY?h1H5*~v!sFgPEOS7nl+Mxf&6oK}R0u-WCwO*} zjSs|x;9IzNwO_VY8}wSaF)5V0iU#3}`vRR(z2V;j*&oTpx7)%g7V15eYMo?alj@c% zS(R!qkznEJ6vPrOVVg=10((ul!5JD-Dr#BDoJM9?DFM1`oNZpq#ARi|A0M~-HqA4$ zx|GLU5LAx2y?z~U5h~{n#mG^+6aBEn2GvKTmwgJORgKS2_M3P(+k<)`2K7&2CVwLB&f(*GzPQxYaFx*9AyfyIA# zH}YPy_u-0(ULm@a`A2sIQ&<_F-<6r8=pLyrZ944jFqeS48 zqtUBnDx*OcTo`VeYIvw1dAqFDJSMh7Ua?d43?_r|3OY5p2{<)IGH(2gQcu7f;;nW% zd_p;t8|rq8UAY3o3ovy-7#Yd5k!#zzPQU4kHyoKNIA`nONTYz$y?4L_*<0=JGLaX2 zgyszRrR^jxtUD?h_L)=0XaG;x*BDS(!}6Ka^jKZe(o1BwIQQmgcesT}UEGp@v``lKV|^(tLk6 zYdv9 zo|%223SV%39b%6n@?i1Y)iwM=M(-NY@u%E8{Xn^Uu-$u&%1hhFcGhKjTq*mPm1c_M z-u;#lX@(gZe#2-wwZROVOiBUWG*euYLKnR9DB;>VRvF!&ZC?PhxuJ7PjQ&O87}LOv z+doT7vE2DJkBa`hR-&XGkcw#omFZFJ;CX@y>1I9Mq*tc{dB}}vWyZmnZzTb_cMji3Z>?|6jcMb!|YG9iPM%EUzs+|d?gC7A)sh(xr=#JmerKyJu` zENpEt=+^QU18;3nhhD&<+ug&th@q2N0}_`mhaA&qrR9;_uQtHA4}PUs4B8p+y>;}k z)Kwq?nQMCj4*}6#U-JzN)e|JJke5MBy}ph^s%bKZcj8utk&x6#Pf*+f zHbo;0p0&fyjAV$;i+`p81XzogwO2rwlC%fwDVMEPfbL}9x!Gn_)m)H5w3xf@FG z>Gt1{U|DSFDG2xBxx@D0Whrnu)3T^o=q+s;BS3Bxc^4)NeMfDinu6@P>mf?RYc(YA zBR&$}wm1mhbZcfpYPa(1fp!VYU4HLZ(bB$PTG1-a6uhE55^r`N$@eIj0>nNTdi3WOKS&9XV zCP4xJe7GdF7Rnt5wsgUp1b-$7kSD8)Tg}M)4dY4D@pq#ldc+ z62DDdiD#-2W|^)`+#TxpNa+cd`XLp=nKs0#~L;$slz5!eJMD zQKEEhCp75)0N^>R;6c^lJ4wct^_thrxkFTm*hRJ>qWxO<*Nl4uT}NlLcx~CkD0PeJ z-uFLqKhRS1;OQDApGyWDIv}u7w|>4U8;a?sh-}jMcMiKlYe+Y!8%XbHGx4^&wuUcI zjHrFo>7j~g8k4nn*nQ0h2Nb1MJF*#9s?IFB24TG0#RUFQ$<~0n#WkW;JU~eSAw zcbVqDU}}sCQJePEQ0}2)V_GwvKarTA$Q7WgQVMMoxGBL|Ptad`VA_|_rV~jjj=Mq) z^q*3K+MmO}Q{;)Ecb5M2FhWi~+)K%6`(6$AQI6Sq6VB2;#Sw!3Q%Z1AIuwV0RPf7N zRi>F4SGi836eAU%5~{nkD%Xd|)ghE4zQ$sPNNSaE2Xb6SS$Ir zRCAmcrmf0oaDRw@EhU2p&-%iFS766?$kW}Pa1nK8U6vy`T(ze4Qb7n}=)LTA)WElR)T2Zo?a`UTVHbzQIA20=i`~9tEbkygLloTe zHBl{)TX>+LDY;AZ6xY$VW0=uAlW2JqcaDqdv*~c2(D%nSDkZZModit~ZtA<|kF-`X zNjbC5mem`x?osIOTm(}cB8?1(`2I_lgW-=mD56Q{JBTkd6FcJ|iLIfxy{ua#HwB*$ zVHS_>Je9RT9$>$hA(T;E8A5{N<{r`s`_n#U(ZIIm!I?f3QaxB(_Uz$oqy)#!Jte$g zyE3Vz!y)o(TjZ2PacR0^(?_MJs;PkuXOeU$VY>I%Hne0wA?`$+V5LUa%|kLJT79fk z9i*wIHn-{W3`aG}axx}-74b&|${K=@udB=t>XyQ9LgBSF6%8^K%}v-rDd?dd*o9~^ z3dbbYKpS^@CbYrTW&K5O=O~@=XO^@^Ecx6wpt{d+(#;`u;HQlnW{&p34~cF;cQ8j5 z<166rL*XxY`4Ge>se%&0VwJ*QCfkEy_Hai8I6q(QmlYar4m)y6Q1sWWv$)@=a7NeD zAYaDv)S$X$31|XO0o`4pdnu?Ux?~a-OcQ-|y#%B-ie;!lG)W1ko}meDrH@K4BW`4f zC;>#1P?bAyZMpgDTN<(|6-1dTW!`SCcg@Xo)EU>J-t&R%d?t-`%rS#c*<&J{f z?<1cJTV#6-(BNX65>)+wrTFgJdZboh<%L^_<9pCMw@PTF8D1Z6sfCzo^Ub$3dQ2f$ zU~UG?y*^GYm;QgJr(vEL5H~q0h;(=C0+89XM-M&_7$AKHpeS#eGpkxSQLgPoh~jXF z*jelyH-$EO@2XP;=II1rv?aj>#3ZhKeD$RBy~upkB)FFV%>_|zu>-DC?ex9EEmMc_(3AE%Aqw^!?^q{q7FK3M6H@__c{EC zJ)r5c%+TbiKr@|qDFJ%XpVX(zN26YZk_^>RbjUoGyYNI|(Qj9dMlD{@u)5WriD&k& zY6ba)v2-S02kaJ}Y_9%@4a4K!esVZIeKbblD`;IpuU3HE!u zlvqWRi4={BCj8~Q7T^KQ%{+Pj_;InW;OOIXa{G=EoD(A&B>{nh*@S&JLUTA-V2%CctR*3nOcG)_v@x0u9EZcvZn_esNbdUg z0Hj3-{(n!S;D20N~q7KkwmLM)ky12zxFW&t5Ac=vMBWux}7goNDrp2bFaZ z&QMvev1{eBVKg}B5Pl9&Wo-$EA?MY3xX}rW`w6LSJ8K=?QSi zu75(Iji;1{?{zZM%&brJVI+Cql zX(FJzs6@G;?@5rb6s2uJFZtm|6+}zC!PO?Xj62q-$>F-`r<_q3@6RAM*r`M=Ynu9y z{T9^@q|={N>Kj;Q3Z+9o8Q5K>05w_|a4(rs!}PnM5Ggm+#VK=nK@>xwKA9JR#Z~o@ zlb{Q)1U|Nrz_mZ6r*4M>^`nA`sFt`@Our{2@ErskaQT7m&~vJQS5zHCz)S;BPHNDQZwZc>zY@G zJG9v^Wiw=~?Gx0AqPg=c9v9v5t4IvV{kXn#G;D3dmED0EB2&id_6FxeidfR85RwV_ zlDp5e3s2imS01tJ3fO`v&zl6Yws7EYhAVS+d{V!ZP;ps>|AuR~dRpi!7+-#1P?e#L zV_aMoK*q7*qk+k%Fr^MEfx20E1&N9`!AW>O(pRM}1TDfls{ip56rACuL0Jj~tn$JR z$qKx?8GM!Ppz-}^5r=VEMsoy07_+@}_GP&O>*fPTN(p>K^&Wg8B+opUrjO2UtkeLz z%c~l!O?@KNz)cikQR}pIY2h+aYcii*gv+RI?mJ#Sct_22jPS5Si&#L33Q`5NGyUws zGZEf>$gVE3<~-%%Hr;;kNjlwcX~*%kFe=_S(1)OR?3TR2Mn}O)@{MD+Ald;M9uQp9 z5-4KbKy0m0Mfd$$p_s4uft`cHR!ziPgTrBksbNol^6tk#!M#UZ>aU26CFkU@@btmx zP5sReYbz=BkecZYb_+K)ugy?;i=eH2`#V^wSj*nbgr3$XV(T5SU2w(S@C+2 zmk{jLz2@eSvf5osCN%4W1;k>y83|WQ_9|uab&&*bN?tLQynZ$UK?;fHeYA+)jzCm# z-NL%ives9W&3>=%U4C_|`PpT&itDbf2U?{SJxn8noxsgRUE^;7@$M}nrVXO2RL)8h zW)ix)vF_>OxZYEyf}3E37Sn{ivE0dn+O&}C)~JVqiscx~H(+l9x?5V8Ukco#3A(7Y z=;?yFPqnSMn4~kHyM-vKpc_UNKa-N+HPD)B|9)~Hk7Aelu?Z#j>7PA6943+SRG`}L zz^^q3wr3j>E%{ifwFd1j&ks?iI0_4kgb{>|GdCbZz`g%WsC!k86FmrpDohfGXhj59 z5`{vef^a&E&u&GOQQh3L&R%Cg9nr-Q{xIcyG%|(cS{?3i<3xL>J<7Q zjAZ%ss%PlQnFp~R+g&X)7JNik6SgSxK$ZqGY8iLs39Aok(MCu&Pbbm*mG2i4oW(#N zF)4@LqaF@Mt+%wnai(IFreuofrZy9N5MI!i>dRSXj^$2hbf}K$E~GUye-r4z3x_it zk`z)*_?iut8VP-VW--W;aPL1)IZ&mO7zNQbq97GD!Rb832*%lMqYA9M`U5DjSt}hf zqzZZeoh0P9q2u_ies72vF4Xorh^9h?vjzdsidvGHJPr4&z-Htlnh}BLcYtnpm7h%> zOCmXh3;E9H%RZBi--fjW(Kzh>Zy3YuGd8VJ}b^S|iX{`$k@{*vR<;jx~JA*BAM97=%gLT-U7p5x9( z$caR@UF_l36690&EscAVX@of*h$w)&$=M|jI#MVc1>QYvpJ*~gv=Gcs2O(y*WTK$z zs40ZIO7!FgCOziz&6@V45Yk%m^fWl;?J0jm@@fW(6lCBS@={f_ZAk457JMBZ;-x+bO>45~qEizmFcv)OvQj6m} zs8z0{ynCu~<=0(N%39{T#E>H^XUNbu)V51RO>!p8&}PoxYZ|5qlz_!WTM$o?R@)#6 zqG!4wZpfTYf&xUOgMAN17Rw@!)RJaW!(%rwA-lu5YL%l4QE``U_DU^5YvVO(ji0|38_ z&?jz4z;nNoJ@?u@C?EIrwJAb(1Gfyng3pk~ zSb9LiY0~XkCM>5eWQkj)IBs48Akr9&S=<*2ZG%cl1HQE~rIxXFZm#Ol$N)>eQk2*cC$nhjct^1iTT=inVC*a7lEE z&tbky zT-%jOUd9d4fTtAI{oY>&mhuLZVG?ui5p!f*w}(4jq@rVv?&5BT?PD0*W~>_I+>Hk) z?6$qk%~cth42~PDywmgk#>%5d#j21lzGc!-3v&P(Ay%R`Y^#Cg&%t6;c`oo`&;ov{ z9^UDB|HdE6Ja_ecD23PeOwzkegn|R8RZxJQ3R3vs3*P7BKUP*L8us(C_qH zpWXZ7o{`7QI+YjzK940JxR2IX*9%~MQ;^R5&;R&ebZ0NBLD>QFB)_sj4rd?<1otJA z{0boqtFMvXu><$;vknFD{)n;ztWc4?OnKIAnB7n#6243eqi5sm&)&4ZTlbJn2SID?CuH|fBeP=;%Z3* zbU&%(P26Hm(bH6x3i^&OS;feor)J#y%yN+N4kRM)JvIv93TEIlFtDPLM~FXzC{o%y z7AsyXJ-t7f7N3FMpMG|~5qf`uoQeJpt6_1!Px8;+qcGa{?tb=$GR6pA#sEgcEjJX^ zM?mxF;vE}bb!y3G1b2%Y3$Skx@rpw+q@ZCMtKpe6^6neX;d^(1ppCqXNgQsmXoWC= zWGmwvdG{<6Dbbmriixx&jl7GQM2j=LFW4#iJIj>N8)`}rf~LIT2|-mpK>#aivVay} zYMAzo@@)kJ)Ye!Wvw)E;b;Ed~@P2ArSi{zs(-;Z_CUcNpc`Dtt6ZkBBgBkpxXAM*M z{x;lZ@WU6l1*=o69Ke(jrAP#XI-H#xd$M zbAdRe{>IJy9L>GysiV2vKzM_&Q6){BsK&e2<#Bq|2mp6aC?P0x%@^_HH9&94^jl(G z5QoK&cbD%blK;gUD@q`^-+CrUQF7vJ@qHK5d9d^1n7Mhv*=gK#-_2j1o^DC*f#A)c zyI+FtvyR@xj%{J_bc09t(Nn}p`KVa+VlhlefR{otqmriFwQ%eJV`lix2f6U|j1-kn=s=Ifg z;6{UEY;38E?;zR`Aqs5iN$-APSBf)`#6ls8;|r`4q|$s;9gLiZh(yKJt7!|ZF@FYf z2oG;&%S-#deAD&;z}@C9{Sxg9t1p)OA+@%(!8uonhV*pbw4q<3p`I=_EzfDMUcheq zsk4Q{N#yxp0UMu+r&&kgbc+53==pCC?&mc|zgrr<4K4zfyUf#7 zq6tVlBe|NCmrfh35eP{w6=gZwvJ*+<+*`?IP{m&(;*j&8_1jweKnC?6XvZRR5kPYnowf zKnm}osY)urfy?^o`aMW6XJyjh2_1E5pR!36I*Q}zB<(p*$7g7xX-bn7E*xbm0L5uD z6kX}=Z3a9`>KgL}ON3DC-M#&tWB%TX(s0tm6R!9Ec^4COu!IKx#bev>b zo0$p;?Rz?G+{Oe7$9=xtzR^qoWZxyScB*I290DoRv54E^Zf%9KwTVmZMvSj(p)S%f zjyV0{pJ`v_5PAQA;!p<1+O`ljNO17OE1VvD%o4@dQpl@ZoipQn3iF%Zj1 zRSH26nb|&jj%&4C6Z41P_D!`&?tG%+X0Urf00MF%hV4B&B{NZQ5@kWJc?t%^z5gxU zR~=#x9#u*!Pl2kBinn5vp{erQMXFYy8bI8YjSi=GP>G4~E&6eeK0|P^9`8_P9y4$a z>>o%arrpy8MBZMi`zmLmyQWp4z@UtF9Bw|xsmXcO8+PhHfxMX z>mzOXcgPc4aEK(%?>LI)DxMu7ik^-kaKNXFP`a2kI9nEB4BcJ>2o=eM)`d{ITwern z)E1#&(3EUOWrQKD1_ehfcM-HaE>9Q9#)rvx85kD+LHLoyS{lOt*HP>Vl7 zmkG^0Kx<)DIIj7()IDwbQ4o!SU4wa!4UgF^WL)H(#^(B6Y^&7PI$v$i+Ib5rpW zKQ?xup{2cKgk-zLs=0o<&`31 zjaL^#1t6X1|K<(pCeF+V7)_o9nf)#73CBA$>rGo51$fq#j3!JC!}#i+|aI?PZl$gH_Q-whcPSsSI|d zHjV++W}gpq{KHKLTqjnRlwvBig@oD=Lo~GV)g)F~V)p7=1_y+ID!uEV_xc#lC%7hC zZMyeBGU~0B{N&_phY78$$0p+kWN`%D-JuH>*gF9$I@ws?5XN@9s2q)~-$|S`4`M8L z2so<)cONio518%*-bnQDdRnok8o+s>K(~(Fa$G+ zsEO-IJ#1N6_az;s>k&G|GSX3g;`IBvps-QT5`~s_5Uax`4mxEAb`c6Mb+NB38|@h{ zV6*{D#D5vhy}yDh+rSQmi<2V`N6`r}$iyNzIM^QGf*I^rYYl)VrZi*d;MCx`8997O z7K9~Fn1jI4@><#%D@d1PfibizkoB1+7y8GC@MZOEx#LWPl$e(i2&M!*g49e`K&mc* zvg`;@BCRslKURk?-;ZJBFtbhKhwp@!m7>K$jD>Z#ehyzD#yQI0J>ub9pZ&~+bf%@T zbICicl<98@He@Jd&!EJ}Ax_`*t}>8;JhMBSq+M>WPIoPtwkknF46dv)mYesav2}=- zV^4dULsW*czJ>;;c!>*3s0oTH6vYO)QetXmR>VaC-4M1oX(u94n(*9BiNHC~^?|#v<08TFvuX|n<eXG^yJLR|h3(x2W(BhxIyb_2I%%iAOO;^k)+TfQ5f`s&T8;oYz9^Ufws{|O0~{y! z4%HWL+tk1-BCkuM%2006d*dZ@{u%CK#BJi#jZ1^}E4T;uy5fMY_uV$wD5n_8Lp`ut zde(jgM<+Ou zW~>P@>*IT&rHbP&frNfQ8=-%3Up5ua9NB6cnS&iMlK4f%j~MQHjh6cU=?|MvsY@^5 zEnJ#aiivBWdt+(*fZ&$3yam_l!4>HwE_`4qBhAr_ke|fB#*j)fq--_ql9QRQ=ur{7 zJLw*^42A$b$#0~MG4{YQ=aSkEovHhs?eV@Po$-;;v)aw(ecbZh!Dbt6rnFMT=K&LB zra`8DRnM3)s+j5BL>VPOZu%L1OSLlk5@r=VpmmEt1N*biEn9}9LU&9gC5#sSeT-{1 zxIl=R84b)&89!L^QfYnnV7!2*fo0O-M5&3UT-R9Rv(T3AK8y2K_}WK+q<+68tR!Idv| z4*TSVu@knDt|-M<7%<(IUmhILi5DGf!E?n{vKiF|Eu_q9FT_Fms+r{Wa7ED44VCgX}D{LOGZhT<*^+pqn(CVaq^EAKKf z`pP!WHJ1URn|&FwDk}DkgF$cLyUL6nKdd=(wK9`20xN8c4i7%AM|6uD_x~DFo>CST zhUEXnAw&K0)<9$#z_-1EQ&zY>@2<7gE zTNc{I5OsM`rHkmu0a@<|_sZbJi=T%|VVjy4gkgvBI!*ulX7b^zJpKRi_NL2m97(!p zkF_L{Sh+9r*PzfrQogjJzJf0}Ub!#R%D_Mh zk|K!lTVYs?*%T4c83Ew-_ zj3Dscm|oSE`}=#g=@kNFc+&$ccbWVCBXs)~)Jiy>oex|ubI&M0Zi+p~C7!6T;f8Yy zj->gZ>=SBlER%i8`kJ}yOiE^cbvu_y;ZJfCcbT)yB+uYCFQK)G zFvh3Fl|r6*59mrETko}=%V~neM!S6px4oAzJ~ysVzRx!||3p_P`Dzeu{$XR*!&%Jv z%YN+34(2NMjf&A%BwW#zf6{vA>jSU@k?%~ltz<4dvh%~`m3DstG`+2z zp~IjjIyA+hAi1v42^p@fk;8!2LCI93F%OkqR_0I*zJ`Mvc;8)kSs81b5t0wCEJLMR z7sSPpW?>zEj}(h$WmTw5*{Bz;$Ph|8g_|9u)^=L;Q=VND_`0lJ6=yZNdgZ=K06-dT zKdd?i%)JxRIC=F7r(mWT72APJ@%tM7=k{xH1Ll#^&tNSLy1hXUdWd6zCY0r;23?k) z8tP|%&?$2?RGbiz_Rng>J?BCo`(4*?fR=vp0>%ooJ~j|gl|hFtdu2Wc-k53nN-bay z(e2FV=8T}15T0rk7-$qFe@wKfzAi%|Y4 z7sz0<@H(099pQdTsRN)wi^$r9!rG(|Cv~{tnz`nfC^7<#D@h|8F;WZ>@>#TWnvSGt z%K8Mlw|hr4*YUgpZg#yQ;6JO<(U)6kfqXiw5;gMmQ%rOtpJ0D$ zxUHRaKGmYSMwTG`L!o-^w1H}{LsdX!Z%Jio?j!Gg`FyYNPFGZ~0GVFaufpznAT@w6 z@6#=LtVIOg<3;Fxt#JUS4JFp#rHMxn$N=TJ9EzR#Se*Vi$@rO1dZJ}0_ZN3oKJ!1hWm5PT`qy4 zO4^NWXT@b>ZKqsKaiz6u$?cHGg&xhd_-S=zb7S7=QlVVE%OM>JHSFCx!PnPut9Xjr$$8BmPq0vq}41<-6SxM?S;tF5@NiamXmj83~T9)$Y z*`OcC;nkgfLTZRg#ZIS8osl)B>YZyVA;A>m4_KI*>{|{7@V8He63KPpx0Ew291h?^ z7(){F%!_e)hI@VlN%}x4ir;;W<5D?NqktJ-o6-Ze%bXQhyvTG&72A8dD6+G!0#bUD z{X(b%oUh1!9L51mv+tr*iK(zDMBgVThs+!Lr$<)Ow~-G(u>5y zsF(+6O1obpGZl%YEKkL&OC|Prb01E%t6M;GnHoJLNUj-@l1mR2s#pnC8JcSd+uPg_ zu)a;dvrVcPolHLG?R-W_FYW9wo_i@^s(0M)l#0EGFbOJ~36Bs6cIE2!M(B-lL}kZz z5$9#)r=47NMTDsdMme!_#uZhl%#yCx5Wit!b z^;FN@^C(80MRYAE>Csuk9~=xd(IqKDe4(7~shoT*;Fo$xN(*s@k98@l9?n7r_C@guy>_@9qa)}H4$oS;FC;l;A~f8=?l1J_ zvz4DQ)2P4CPEToch=lDyDCdCO+(k-T_6bZ$ON;SP6&*dQoe~LkT`64(&@2>c7Wakm zj8P4dQ9Ya++jdr%n{JJYSb!=S-tovortgBi{*qRy6hLPS9s2oB@2_}fuknBs(i1t? z)g>1$-ijM~elGa{S=~cMYge%lElAtP-QUuBr9x+5*a!+5j3@a3&+6!KxLgnCe zIiGF_xvXkPNs#fPpKkif!A}W&zO0WbMy$GzEMz(}&tHUnb5-eGLgIq;U$Gb~sROul z!iTKzinyhePGNTzOFmFLV)rT?g*;~Z;VNIgP4u>)Gj%a3VTVelt!rALZu@m<|3@5) zl~yLiOD8wmufv|7R#tb65>CMwNmRBb91={UzfjtCKJ#|*;n`8mzSD~VXaw4KaSt4`V{yA-sC z)oo0r7}sma72>2H_{|z$*AySIKcwD?fCo2@vGEQ>1Y3o?09FDhZeUI&J}F;XvU6uP_O^TyPxa&?8q^K>(mmLPzU0~H znF9eFGFON)*X*pEZ#uUm`yM85#;sA0O#ZGm8!rmdJ?`LJEcLsqfnSJ$Bko4)6( z^1^W@^BE~7*9@uzPZ>FXkOIjnnh_r2k|(}$fawP=kFrz2aL&ko=c&$wsKaIc3diE` zdy-$=dU7gux=MA7+7)7^f1FF^SC*4{_PCF$3!T&}vFnk2c$Khpnn<-^<$p!km(EM1 z1@}=q}=qiAgFTXGQ!nTS`Ui| zi%V+4--lhHgW>92s$h*b7&$;4jAA$3K{wzO_!t*X`(1iEy;0k39MxYnk+~rhju9sf z@SimZK!xK_-1Lu1iileB_9`_#K2>t85Sl0um81oexI8K52U#2Ln$GM*oEKA;`W<-v zTS!>%H;xkQ^!+WSM5=jA7i12%)Tq;ytWIk4uWF|`Q5V43kn2d&H!XAxI+Y#rQtBH2wBj3Fou7CbU; z3=oq_VeX^{U2uF>B3JZv+~6a2>|NoaS;((?>c}&#G?Nay@ALr(})f?>M`Yr?tQVZb!*VH--`6?!}6C7EB<6&?xjVw`U24134 z#ei(87^M$tk9`-rDia`p{20tL(~8)v}D&?P#dy~{w~0U@3{Cn1@ELzgTh6c75qpQ z+D<0Nis6U`4~m}oj5T}_jC{q}EZzvq(JS^xeBDY>(i(ZH(ei=Ing`9fhr33!PjY08 z+@$ubEJg;n=+iwdU11SoBux0w%R#}sao@nabZZ?Q8|qdQSZ3IvalUEqImN7OUs9)o zM}l$b|ELe7(GGP-7B#JdJtPBz!yjv%@9dcVub7N(!5!`ilBd?|+j-dZ6I4b1n9PH- zxtIJ<@9x5@jR4A4a9w}4hqTUZJWthV^!Dnw;1f!oh;cAVZVoD)3EUPGpMuVqK?-Zw zC*BMR>Bcv0EGB0BX>X-{7??J*poKZ--I=DD6%*feyidEGM?qvW<7R7}+BgLxQ_nE1 z(2MXCqHGooYk=(TI7xqVv)gh+IPMA@iUWJZ%^O_3z>nmC7#=w0!}_NIH@!CwpW>u5 z&mCgY?DcTs1-vwX0-ykWruS#LWM0Q zSFCh)yWXYiM4>z)#wJ8nsW2Ra(O@wn3Br(Zrr&6t3^{3!Fc4g6^tO{kIk0qQo6*Cd z1trve2>WzwLIv}L>sc(p74qKjxO??7DCB?4D25(~5Zq1{u#YN#XHD#f+2;194&c*rDaFEuFSc#p%dM5wG@K|01! zhjL|T>E!m}*7nZE=Hk-wPt+<5VXwc3&}To?;Uql^A!}p>v~*&dR54;;;fhs(6o3P$ zW~GD?tHQU?6I!@*=7(;3&>=OLxn%4RTghj~wA0xADq?AbN(P5%22c=hWH9pqu>(i9 zUZ7v$8j=~li1}&VvG&dW|2u5^#mA{YCphr z7!!!u-+S3ZX4<0~?2f~MU5phn)%nMRY)hqJE_upR zJSGHQNs)ia$`G9N;x_)3EW4Lr&^B^FBgTc^kHl#}m+tU~%c5en=MCagtn~eDrbv)b z1dhBdN1=~((}>v@W0HaPf;|Zey8hGb6Rp?Jn$#igETc z%-%iCfno1-oe}Jv@5ygC2nV+vbQB6bP!VD=qz6hN(~qPM9GL?`KPI1VZ)N>($5pHJ zv6-+>wuifZwNJ=-TlSt!1p}l2chu0=Y+P9@+$tV%EAJpU9=~=x=mV$#?0_TJfqOU6 z9hf?25l!EhG(T>!Z+?$X@oUX}@`>Z zQbEso4YzrP-w--^y9CJyNWn7X5eJe2B4g@mkV8yASasM5zgLoMzoc}BZT#0Y7mLu> zg^jBtve5H)kH)QwMNFsJP8Kf?tFO1TA8=up{Ec#f$I9FYH&SU&1&;z)Z6LyVsAXjYLL`d9WOs*iNIa(iRFdtN5PnhPcZ|$vSF|y63=e$) zDZ_-8r}#L~)OV7c($R5;0ws4dD%@CZS2ITgxI4h73j&nR{Nr!`8?Te|cmMd?|8cFv zlT(d?dQou%;TIGYl>YP>=}nD>hyQuc1{qy~?EtF$=#4`~7{kWx3e%8^UTUybsE(#( z1Q4{&;9-xVrqFllX%QPwzb>`$Di&upb#fP8vc{+ms;4|}{ws^BB1ojHnb`Hi^6>1v%%Fi zBAMv-U-tT^6y$6cTFf5hWaC{R$WUcaF!=i~p~*R5@Ju0xL8~4~*qz^YK`#X0>aXs&P*ySq)y&F(3lKed}cg=ONo${T4Q)7x|UIq^@Z(jx-A z(q>#8kocaD>dnNdSmC|`yr(*4K4>q!!vAF(jDFTUfn;K{jE|CCbVQ@o z!=YNMj+?6dqQ*+Q-QhY-yE-)+2Yn>6Gxe&_6;Q}6!NTw$BGe(Je|$>+PPPF{j#4rY zQ7aBO#nn_iaSAzyPPuF<(0^_7aaTAOb9D&ENGm~T>D|%wU_aRgf-aL~@nvB0LfhTL zlL~04>6IA4ge8-EHHI1)0H*J|=Q|~YzmA&=2yXR!=$3>_@RLsHGprx7W1$jcX>CGN zX=AuE!FLmfIe6zi)u##_?@rO5c~-e+T#*m+$1tbPHD5zqT&3uad@NZ^PnB0H08DSW zdMtR3Bzyc}(pLeF7XaZ0*h z%Fnt0Jm`?5q~KUbK-5Gk(*;7n^!75@!tl!c+NRuz{D>jxJZ!<-;h7X9&_^PiL*&}b zJE$tcAAC>bWukF)WU$^N;V$ayCYtTpR1Os&IT_Bmm~D&qY`OvW%IjjzGN)m3D0q=%>G+x|=62^?0MKUS>p z-uO-^YK<-zH({mklEUvoR-3=FJ{(5pT&L+tHRm3qJ6Gcf+x)~V0H&80NOPf)P!2Sk z1wDS-kOVVuGg)aHGb2m54PH76YD`6Jb_qGMva!Zp8N5v2svX!H9x*-cNCV9vz)C+_ zaKOn@tBnqaVBBb9-9Upzt|e(t3GI9CFb<^u?15InBIb9CiqNuXX}!C z0G1dAUL>~>15sN~nNaj-=^dTsr~o!_^njX6%zeRe+uMCH-A?nWY_;z$m-MS^C}{|qPA!BVF}|*m$mkWykqRr<^SRrofh?o6VDNTe8RK8L z37~yRvxsf5{q`Pug?2bY7PERv)&Br5y|K{VUb`d!)mh!~+)-s%7_y(PCJ$TZ{%1Sh*ZWr^N4HfCUl z64PA?y2?dTj`kS3NyHM5Y0zetKnKk(B3;Pv$#F+XTURa^<`6BtHHU@*9w(yhmr1=( z<~Z|!oaFF|x3Hh%-DaDOk!)Itt@umn>y}Ls#>TdVm~ABwNl* z4qqed3LR1vf{|9d^g4z3H+rOJlYW}82qTf@Ld+*FUNua`f-4(k;oT}pSR0}q#8E!Qo0!UvBEgtRd#M!~2Ku+jhGd@7RYlJ-3Cn{`t2RBa}@P9 zMItiB2MVEm3 zO;m@>+ib*rmCcAp*9?mj2${6@HG2iayR=7S=uwK|&+B`1LCbK*Y*cy0i)jPAbe1~> z-@p^c3}`Xy(frG^o4c-9Sz|kYPd_Hhgb7`DIL~gsha3|=X*zW|D_=nBT1R}0JfV4q z(F`DfI0ac(TQMr)uuxf)5S3=*N_$q8oB)3KQs51YdkSKsd@HR zmg*l(95i4i(Yz+@(rF&V!rQ*PWCl~lG%!Y=Es76X3s@`AXD==Le}m{EE#m*|Vcmox zD&`EQv_Xu7tK7Irk2UJ8`Td0KY!~&zKLIm~<(G}qU8L*Bk8LBP7ir#G83Lw%+^+Ak zTM7>bl2%21tTIF72z9pBY<#Vccdu-Z$8Z)LV*wTdj|r1sgEoho{zRGQG?gItttEdGXK;p? zUL!8?LmuH3I*d8@GYcpBon?(_GK(U4={nmA99H@^@i7BSe*U&r@73UkrVC%;imFH? z;Wyx6zNkEIdcz$9GJAqkKwL5L7tFAn{qLbNAdLR}>mj&>dca~MJ}fC#L?j5*@W-gK z#c9?)JR~`vUck*q{ue0RWX6GXbHCZn-Me@bk3JGZDkRnseSjp}ZtNYMG%>E+Iu;l( zM33;G5*)s^hht_{evc2a(#h2T84cxV5a&`+?Jt~JF`9H?Kd^A=jB~4mVKzL1;;lUM z2o}7Y3Y1=e_J~I*xf}U-LjD4u2ERID`!Yr@4CBfW)AtwgRxh+e45a*;R*e$s4seXq z8?kLngJbrhQky6Qgy)J5hvuEsro)5R@TZUv20cqg`ZcdyLmtxu!{kPWm`*c0wm_B{ ze$%60NRJrS7^|qH-!rguRtZ=hvACNLAdXZ}y)m2ZI*OKFSQA{djCBYn7fici zH19&Y1SkD)F2Np->?pf!sHSW5p0-m^vpcA)IJWn5p5=;5VSbw{vJy% zqiO70#Z5+5*9&p}F>^F8XAM|-XWhMT0@Zxs_L?y!s{tcMm<3Yj5>r)cI%iM$3>CHOK1P$7<9k$&Ft2jl=#UsGe%P7y_<@YUfpzvIo~F0{K%`EyImP& zJC_+&4l2D)-VpwG?xdEbJ*INKo71<)8bbw2XEtH7V!mt&vI@l>9zbfyWg*j-F`G+a z${4itgDnDgl9(kwv^J@K`#smEqpOMpjRI86ZZ}FGz;~E4@k6$tg&PUZOYDAQwP_K4z(m zTRXOgWA?mZ+8~3aZ{gk#H;iSUOWI%4l(c3l#Y9h(I@0o>$ifKs9pXR{J=gHLX{nK} z4ieofJ!R@Jmi&bj=Wt;KL?RmvAa;Gt?dKIs0w0$a4Ck2BNs#FNwGD{_IdS;s9Np^a zBa4>ZYhpqk^1B{B6HNN2MLL$$lgmwd?#?A)Vtq=^YhlE4W(xI^vt8*zOGLjh{Sc$u zl==WIBwa105N?WKk(@h_ozC8*Ilx+h6u}CE{)I;h=q=s+HZhJ?Fbo$t<6MQX+=wxO z$?X_XBbgb+kee9cTJA4$^?;PS;COikI?>|88_(SNLl=4m$>DKz>V1i!q#kFrx_64B z=3m^lYM5h0j4PHICI*Z$R1vm2!_HbNIb`y~8Y4stDs+HFSwJ|4G6AD?yuA1#k`6a%LNqDIaCP>FwuA=Y7hVanAuj zxU|t766_Sy8TmoZ!KJsJ1K$N1A_~bKEwlQ?uko6>6{CKYZYd5*uRru5P-LfOgDpFp z;a&3;-t#rI6_@sW$5WwfLNi4A(T`0?ZrolD&br*-hxQY1Vy|(f2B{bi(BrUd?97YV z#0oP!517ur00k65Poa|P^-;Zl(td4P9HVtgxvbF&lwNuP$Yibk`hU>eCNaggc3_9^ zH*D6Rn7xuqd6p0fw<5EV+!hw1yg_$tYd)QZb5`0;t=OIPl4&lRPbs8c^_+5yEGI2d z#kO2_ADCGLCY_@2^U$d}O*Ffwedv1Kx{c4TSR2|POcE-u!J`H$y+ZkI88#%mq=eCp zswN{pjY}9DL>*iu60#+c14ka2G_$e7q#Vwc!%J_>I|6Lg{EQ_(yT`lBWuixTvR+2E zO|9tHA>(JDY$Aq>L`BE4rhOGoui@=ulypW9W3%SW5XUjxvfa~H&4yjq6`SR7rT{CQ zT4mtmM<9zD47Rdkg$kjW^_wi~0HQeO-=_B1F{$VGnM4SLv_V{!@-&YrT=>Ovxi6X!r8Naldck-%+_+sx7NSQWjeNa?3I z03ghu_b`x{mK10DHD|j(`v0sm%NF=}ovBFad-E>Dku6OAH%>rkVUqfTQJmlf+lH=Y zg=K}4sG{W#C%x`&bv+$4TL@h|$%G~gW`srCtauf2rht54xC6=f1`bTi5`2 zx0juZXy`0A6ooiBQ7(|C!kVhCfr6!XaINYX2Y0?ca%dr;4ZQbK!{Ng|9=Jz|!r465 z-kZZiK$K!<)nI{01MNf-)qwiPY>eZHBo7tDSMVOs)hcUbg<(FTmlX~2$aP*x19?Mc zZa3y(_l_stsf7+JeFq+1dX5ntnep%xGd(#zkHbpeai%Nrygi`jsSJF@qRckrLN0cP zlYaJ`pS!~SE4cv2A_2)OUN@0F0KVklsWNcm{*mFXcy>z%j|(|n!&N}wM$Nr*8je*(BVF1^DXK&vPCETuk~#bLXRpZ5&u(Hn{V6MF2(zzo^+ZX% zbsg@_H>Cn%9>M9!X@^YbR@k1d7J^}_kO#z#Keuu6z;4l-*Lq9MO%M3QKf& z1r#W~qaCpB4xZg+gW*NY4QBEmKn(vK;@J>VM)|a>^1?;D;;C@HH!8vXP3)39+cY_} zFqF0YeeeqZOE%{nK%p)I2ZJcsfHUP2-E!NLALD)|U4kt;Dtb0N`NN1h>~{7~XlqB*o*%du_aTWMyx~Im?J~ z$bqIvO^)zKJXawssKHyPfpytbJaZq={o?!n7bN9*4v-|vU#jl{xfZ^J^XWw2JSfe| zwHh(gx_AqB_imT2@aqfGgOhS-st^A~vgd^|@z$V&m%=HYn9}F*V~~&yxvc&XJ&rJ7 zE-c+J1Qb3{{R{RvM+fCwu15^GO}h511svnPD(jLQq<3ElS8>y;FnndxV@SE|ZeY@H zd9O>B8aNwqcL3_xI5bFz{0dh@H{%DRhuj8^LrQW7sZ&3uPHj}P+(Pdqc z43Uf63;fj~2J$YR;$b#2#Gq2M%=d{bFS{S&IpDqH;+q~7R*++qLP1y80w_G9?35e4 z(RRWYuQECuS|GENolIlWDHN{HXE%G2EN>M0G~=b)jJRxW*3y`~3Wdy3K{MT+npK2` z^p5Xkc3M%GUTKch3h`dm-$l^$$}&0Hh=|0y-X@sx^*GMmva9f!I%X8ejWR)`?>*;r zB@+yDte&jWYg_$xkAp#OWQ^F{OB-Eb=R4~1Np>9Kr8idbvC(SPPa5q3624_^p7u2; zC=?Z0FB~(K$hDe5(hr~Kn$3C!68`roM3BYU70)X#{o1)+VHP{?@>Y8+-9NLL{Tj=^ z4cB<6u8y49QYhC*g`$&El3LmDz7P^j>g%q7aFf;c4x2Tn(Hiy$v5k@;cMc53GV|l> z1iuumnO2naF8!XepuWtx>MEx5?%+_4p|bibgpMomNt^kyITDjP4lvIQ`g_BIYAZtC z&29+AuKjWs|0iv?h`8A9FYqUnKf5O{wLRaSPd@))b^D9tRkKbnogOp~2hK%7eR2u+ z1P~mV&m~jgN)$U*i)n2XCB5`q|3vsxg8}l`tEm)DvkD5YjG(OGhbZ=mmsgZzw#Hsb zGm$D(LB+?E#oHN1A*WJ0xRq92Y{^s{qzkC6Ue-h#NuU*Y)8RQv3p zgrFs_H>0hqCHX6aimue&X0`%XVmm8V7Ix;myQ!*VVQ+ybWe|(hc;NSLho=B zNK1Jhhv8Cu{Rl{0T|7KWRvNF61qtavu~=z3(HUW>)m7o{(nf|44H}$uiVg@v!|JNY zOz3x|FSu9iKgy<3*EO&NFTMJr^u_k1_*=SV7kJ9T!QC7^3A2*J>XO4xFG|gvF0b{0 zK~G_$X1Yd*Ybh=QG!K@3u#TzFb(${8P)uje^M%wlbn;BnQ_IL#Ve>1t#Oi?%EEkmV z!VN@^q85epiYN7HIzrxvH6;MKc4w}u^xE7jcuzPI*Ekqwl^QPt4OA)L| zcM{-KZ&7{&M?zJ6AtOVz@clxbApG%sCZdATBWVn4IIq8^P)WQKg82e3JDjd~BEb-^ zj9!4=o^{3jj3_}Sp}=2bCN{*vrM6=_zG@)k3a=@tyEvSV6*^nC3^dJU5h}g%0`NNo zpObH|VCd z5an!5z-9#6-XSvzTy9cokSSL|SlQ_`8kkhQ_rwQLPnYY`~C&jC-N ztf|l&v}{SwhG@#=gbOW8y0wHI&vb3fR4uMLMM^K|ztFJ(QKM6P_~7hPtb|CA(%T!0 z8woJK&qCbi;RJOlc5}=R@1I8#i5W=gN6h^2{`W{_bD$x-P=*m6CwZ2w80~PuN9R_B zM}JQrxGFqC)^W)l?NS3m8=V(vF2S60Ej(Q3vilTA5|S!=w8W;zcI ziB3I9IfIhyF4a-;)j1?PSc4Z^Z^e_DR8qMoWAs>Fvber~f+rhX<(?$9WDbjq9JciI zn7=3CGVkdCiXN{5olzcrGe&*#8=)elf8zQ)`UcZiPA2FKm7OSjbV0_QyBaL_&r5pf zkrj$#u3Va(KuZ6+tI>n+ac0tKHTRnRd?!gT=y&ADD%S7YbL%}IrT@;o_bv4v9?0(PVL&;} zwOaiMss4X(+_BrBdw4wD2X!Q~?NT;u1XNIVKZ=wm=~hIo@$-kKwsczgKScce_@3uSPgH@ocIB^bmwz>ckG3Uj7_^r!}@L=;J^qpUiE%!3@CC ziQt2oKE1&%2AvbQhBjavV}4EtU|`IU!I({6E@bHvBbDt8E$UYyr3tsGy6gPa~%9dKMe59SUrmj?8X z6DyH6b`NoV?_w40+co^2dS*yN%-I~MZ+T%LBHT%igOZ%PGxwIa(L-2SpLw? z_xcIW$my*Qd9#2vNAEdAA(+7rA6rEx&U0Ag7pU}0R<#~Oli9$T8-*c5`^{(8P1eb~ zR#uxQ-Guklz5d1mv8mqxoU{&Z_Zm(s6)F|Hzg34to3w z{8p`m9`2&Bb>u8YD30%{LM_g3GJOZNSZaaEgacog4CKb5hz?9C#Q#uuBkRSvT0Hub zH6GreF9<5VfLjenyS;~*@|H&+sH>nPwoP7dNBUs#}*15im z@*(%8zE?U_#5}rh-F0tNFZk=e;cmJQe_hs1U1Z}-8Wf%7#0&*O<0VG%372-(`OTyI zm`91L6q(_4cz6UumZC+ScU9dF`T2AI{FV)%WG>$)N1;nLL~Z~LR)*b{y$)X7l^)$c zH$g&BI!F*C;--=CPKqtW`5Ff61b0Gcl4F>jZ!guJln&DQEwKA)aX-4B`Hr+wZ1B5P z7FDkY=eN=Tm43pL=K)rlnLLR7Mi@<)v)!Abv{ABBTB72|nW80IWC#cc$ZGpWi62`l|%VVevb zc67KDxZCv(30^$Pfae>s2#IhxBgi6Ok#XgmK;cmhhly^^6r^u8qyQQcCI>sVP4nXv zB)LYYD$|2fSQE66O}*^5lwa16$4$NA8tI+RlJ|v?VRrMDRWL!c9SG`O8Q1MfZ8QBfZF9VjqGB2yyWNmKL4U@ zL>`S}TMp?1*p`!Y_l~Vc=bg`Y`Q!7OhJZ@H<1T-UX$VI+vUNJa&z>45ndQ<5ZxpQP zY3`Y_zIc3o^8rxlBUd@hhe9BPdjN~{D#$Y2I!wH_UOG)4kE5NJ4-%l#uU*A3O*Y!S zey2^Z)Gua=IZjyShAE^?B%I8(Y;rj2bVs!lYWOpR{3c;(2nq zo7!&i<%QBAJU;=0^KR`a2$(Hg;lXC)_H&4Q31=oVbZ6(d-aOgaDXq`>Ew9J4yu<~_ zmnWfgc)u>RgThW9=hrQpCQuphtO0J(9ZS#<&&pu4-{Etn+ep{W{cZ<-^=4~_N8+S3Z(y8$m-ETi z7#1#2&Xb|(2vyO7rx}rVc>apw;^NP>G-Mq27CEcO-Q)J2TszAFrZaf74k8pH$uXeG zZ@)gmDXZz~ilv?<+#xq^8wqcAdi~?R#>g|2yQIOe_CfRse23F;O4)AsD(=)}d`KCF zu#nac5-he(d(Dhd5z}{Hcz6ogc-?56prtPngG-C{?&~AGDNsMDAvaeIx72I+C!T@8 zJquDhDasjNWLbnv1%DcTY2cv#*L(1h0!Bkh&%}~`^Wx|fK^!LthwdlKxCKb|4jur~ zijnNW7g@zP?de5o3=T)F)?bmVsH~b?KK+3zaEu^61iSpd^c8A??xULQ6D3XYlBppsD6fWOj^LH02>8ZtT z8-c$xsuziIA0aS?ts#S;$DD+b-Vn7NVI42r04Gaxe<3cKF79`Omc6cDF@P0KM4E{fx^EjnF7!`KSsZV- z=mrqTXz-ZqWN_H97dXy5cma;G?^ZvwIX-CCOaIL=5)2W*KPOO2Ym|s!k!Y$p|>bX#k92|GBlI$r8^2C zxgq7y7m8PKZ}MPBC+MphPS)d}HPOA&Kk=o)#sj7Q`kVy-!&0_NbTY@6e$B$JhaJ3g zq=yp}PgShf6kn0*(!)JD!BjEkS~K{H`MgKo_BBwrhk>wC#B42_!%dlN{3mQ=_(9=4 zs)`fj5yT!23FgsSt$_cUmlmkub>l=*(UMqsDLzg{!N8=S5f{1oka+<)Zt*ksfG2f2 z6$+=^%rE=hVRvpTCZE;;rSVT!iyTrq;q%)$1)2U%lO6fx^(IxMpLG~p4lSM8VEFI? z+I3=esrHBPRve!X<1OH&mt8zMW>|0+?DxMMTj`8`>UVnI-@At_hduZ{DDw;nzk3hv zd8%W{j7(+In?J3t(19++6VZS=dzicP8h%iFHE2=FmR-$C5cX$dz*=3I&nXST)aLt(c7oZM$7Js z74~elQ}jr(HbTq80XfTq|7|UgOZ*)v(Pmq!m|GcHrh1EJnqj3^ex?Ql+BwhZ*Q2fU3Gk0GZ0i*TgKTw0!zo24u>M2qNK5!vi z6n--*8D+&=AUggI%nf`sa8)A8St%;jv>g?(SC-VmL)m<5SA@w4t3qy&iWstr76)MI zglM^vE#xENbI(Ma^5%#{HoQ5*y@V~=OvH%vpCxUr08j6@jEKZs_E7vaz|mo=P6y83 z6^h-6?L;8_Bq-pG8hS2Jwue@%%V0RDxFuJtboM`*ohAG^6ns}vU+4Bwp=ak?#hF<^ z>JU6_9?;G@>SgzfA;P}G^D&AuKuklPu*tN(aM`9^s;G?7$p(u%c^T*dE>Qr{j=D7)a%t7QU6OXUj|5hH0GfaNQ+f%5hUTR_C@imw(z>eZI22ypbFH zh-AV;nw3XYR&Ckp`oi;-^>b>OfGNkUwydm45%%1$CMlfqToRu3P1BAFMQp@e0FYu& z3HHYNi$x0`A$^84z+owaj>P79&M^VYb8J0-x;1Z`G5$OjFy+wE#@E}MbMtn!j6d2Q zPI<1%h-_~@Un~;=5j)b5aS0KXO{L{exyd!Yv?L@&zxMR`^2)-_{QBC~_RgOdf8JT0 z+c0x@9C=m(seBWTZ)JJQ4$nBPVH!qK^eY+q&hxd6x%oevwv4k=dJ+Xxu1k(9-(Tab zdFCJ>#lGyZmGz8zWnq3Ph2kmGojeok7d!LV{Y}?ZWXu>U%5t0mva(AbZY|o$Fm@jj zkYY<8;wx?Qx%6Rxr%aQs54Tp9=dCUfVSbell!H?IDZ$6?y!L|`m2q|e9+fSJr3})7 z?dKaS=hOlRrTAA}3;4^j(HKW!ayty7vb|qq3+7%p3)V(^;mQXndW|Ca*AB_euF;XZwY<>BbpfS4DbXvpRp@8<@~GoWu^cklc-xANRh(J|Js z!BU2c_;zP`J71l9b{zZws)(O+#l8uC;ETP!ETqPB8mdK0XV>pbF||cA`qvV7Y{liUVX`lWrYyJg z`@HKkY+6O^>?pcCtn&KSmAGWzpmjN)>}B6N^`eH&8pEn6;Awj%^e;I@VGLb7KvMK+ z{jTVk9YcayFy-(gQsSC@gAvL3X8nkGPv<#}h{x0RT+?QTj?R#5j9sP-Qu!wJk9p_m z8%Q96`mYm-Z8fejCW8f2jw${c`qGQJO>4W3q0|{H zWw_4YE-&pY&8=*~gx%cP$XN(u2-H$cWxS?;+|OM7z$6~1v7EJ4Z0jE6$wR;Tri^3@G z@7HnyyW)wjVQL~lDBdM(06R~SHNhUFjnU5;kYZ2JSBpQ*FK)c?+6<5seUiRACnrt_ zrTACqOWkUCzcd17jHAXPpmJRf|3o{bp&CQ-7x0wn0{!J2+=2?DxDy*VyV}NRZ&*uq z3`rRvDf;y0+%oi)ALlmVP_WzL7}}QwQ;w<4#qH;tYvfb8Bns+jDfrWyf`l^;HB^ zuFLYL^7y(j)>i>fnWo)e%H+}*Gu47A$AtU35GOdsS__aA{Q|x_kDW_l6nA24n`0dF zs`EIt&X5#+(xDeswK4Ra5K8f-_622a?AjY`ZOT!WsB2^B$p$M||AIm_cKwY;CG{^k z&lE`0xpEuT_)tXMM7^+ch0itqEIj;G+t;Ka~fmMi{Q9OdC9M^dwy`t$bU ze4el3BG^d202oM zXLD-{E4kQ$H(198Q~9J1pUrJO+ge<--rzUrLyxCC6K<@Yt>=P;Dio7ZYz3;;{Le3z*A~`aY%Oh-68~lR z0q>|54ujWP+%Bob*7m}(4Qr~1i#}5Y9I|qY+;<5}&HnNRa$nGt%frva&bkau@R6 zU}ZCw;>-TBvAMpqyt25=!7ON!ZO|L+FGXNw7M)<@=lQw$XN$DQEZgAUH_!}$KQhb?pa2h;a&o$!>W}U(* zi}V(b?bonzS~2?uz2)(QXMne!aB-N^wXtRNPJO44uAw4qs3Kj%A#&2=v0bFqLn^ph zopZeTGorWgpx5DvnFAG_r>9QtB?fmZIS0>h+Ibg|k)ha(3aJ<0jFWxa5T>H6IHoP< zMa96{s&^%WePbUPA~jDPC*v^O|JQK!CTnIflSi&UU5-*bDxFc)DC3|X!Hf0o;m!%3 z9Wdk-A|qlDyLfq-5VghA;22Pvz?~MJ;W9)UF|9155Xm)C&})pYq?2ed9_J}`Y(=t& zGjuG2+pfHk^)b&{%GQHdIKvpHicE+Z_o(LjNyAfEShU%*K_z&gL;9_l-X1xpGJZ3Y zW;jRb4iaz``+PfwxGaHLZlvi=3VPDpcKoz3<3&a!S2P_S)#7MkAqe^!_1U2eX2m8y zKhGv}rZ&^tZ{gL{W7E_My)1ri5vVqArmoMU6a_>?j-v`GueerBOnE-k*EB6^$&Ok! zN=o3`#CPk1LlR8?zsO>x8Y+w5Ms3<1)AFc2d*q5`SZ(tqu=F938&(pp#?03UCV^JA z34UX8jT%yVzB9Lv<8h1q=3&#eEozr3&yZ^ckVp5;!#9+b=rEU&XfviaBN-Jx zTx#oY2{msuH6 zTS`<96SFcX?$t#FO}kN5Y>U|v93j=13AkAwQky7m zscBS&_wkHWgsf!K+$w!r-VjC!(U`V*bS0f2(t5Yq%W2E!u}1{ZO2=*Vxz|k_qgFRT z`r?vY%Wf0;3oA#N*FS`1c+abEGjwh2O`m}m$=|clG3-Cb2=T1!kS0r_-+HUeEJ54x zF44)rWt}wa6@L6|B9Gd(6yEkYCf3O-yoQ)J!_IAY4)C?ZC-xhAx?_j7*ST>9_{w<+ z-{DmwB$75gdro3D16Mw3qvPut!l-Gii-Q%I(zz6%E8`S)EQknr74mX0s$XL`1AJw@ zxZh|M^{gn#J8HrL+0NCg^z1HP%n07fGkqInPmWlmL{YO8+SDngN7jx`tA1*Tqh?VI zv4Sh*+eJk^O5(?8R}Na4F7ZdqA8QswNuFpnh7TC=s$IYN%KFtR4zks+hNRHsE-dqo z?l%=vX)gP(cG`G~CVu}s3tLT~mGnlQwCEnFSd?QhTQ|X#JiV1c6{_qQ)IF~mP42hp z8R24Eqh?Wr0AhIC)aizMgL?-?ZNu6j6^;RI=5Pm$z#^Y6!RokP!keM3b`Q_EoAn5%h=WYU%K%1j zT0j4ltlZ8?8w%OJX>OF8AcGi1EezVpVXJ=|Z+liXt1e6(4AbVLS{yU44$2hyiw97M z=pl8}%jdR$4$w+Q*B-ub(5UzGA}PwCAEkjQurf^?P%`?We2>_(hf7+|4i15 z-i`~0Oq2KqFU#yu)_61b&##S4P-B9ujr@RCPO&?`<)-M$cj2Jq5G`uUi0IPX@!3V< zD)jTQ+$xAURSr=c4SJk-~(*t%$yU*q~=wV3iLO)i2J$@#0C!r1j)stGx?7 ztFSknOQRjQZS?G6w>_XY#LEnl3b{R6;wW(59JzSZ_@!t`p4$@f=sJ-m@Xc@P;0f@R zbF#V5k7<$z?Y9v=&3!lqoQuxubQi&j7sGN^^SSjbC>^@Ca-z8pRlbQm)9xZs>SN3< z65uQ6g(fL9$5u5zCxO=_Z3fWFHPJk-AC~Nr=hwarUpXh;0~*CPo{I#K_d850r`W0l zVL?lbct~KlCdH`ePoo`P#FHBIn5OkuRUDeBn4ztQpQS7Fvv|;~6HoB)YqMWJ$vwS# zPPTtDfLG27Wilpe(4tm?oLMW|6=Gv$;8mG!`afefsz|FmV9FWimtHnbcknp+zy`LQ zhXVr0HHWM%p7CTwdo^lUGs~>hX!MNMT%E%AuiM>yI?%Jtj2hd~qy%1LaBb;Tq3rEw z9G>-YFR!)DdTi`lCIVVO(dJlY%Z)^a|9ORc?~ zRs+65yNN~ZDOej_Ja*5bsZ27p_G$vHy*ougk2~sG4-cHqV?GghO~IA&f(A>3Z0B+E zt++~rwvkYRo9_r0K0~&1^Kl46jTw~pQmcJ($N?aRG)gMO2;U4|8K?bMg{DT$)-$o1 zwr0!)fpq@NMl4NGn@hBWbJKIx9RK2R{M3MyR%DS z3uaEAiwq|0n#0z{zH?j*`Kvgx$UHM6dHJ0$S0n;b#6FkXW<_d@sYoq#0;jO_lg|F%5&7ygJ zZUWpeXlpN?wEH`J=^~sM72bzz$VSXR0P{1=zGG)#&%rdjk9Kv(+19)`ho4_|@CH!VVwE@0zUTUB0z){yeumOD$&i{%7 z`}RoWZMU+CP8%Yrc#3~++G>EW zoq8Q3-Xt#-w(ZQW4!5-PI6%lqN{si}?5{>w53RVJt-I)OKV=4~EEhUmIDWfUN}Pu%R$L{T>U1f#dIz@|a(>DvX*{ay z7`*1dm2#q6Z}v(K)uQZ*QLB)#?J}J0Hd=KGtJ^8j{G(1{N0JIbEoTB;={67=x!2%( ztbD9*CTCO(b&Q!F(9|4__VpwlJ|A>XiXty+bVs+Fz-@0&_8R5BrKsT@F`s~4a4k*r zj+zJkqUjhV)JO3Vv{jNo*Y5UY91Ao%+d ze^1n^jqdE+0nu#0TIlYm-Sdph#<>=<7drg6U^hMf79|%jLh6koei%(>(qte`48^&~ zA_s0|(FAWiMJ421L<4P@R{s#XLc)UcqchnGE>P?8QFZ5`BPgy8+;vjjyL8_fxi$1) z$c$jryc{KK9Z3x&HBX{dxT;miKuiUq{LWd~($hDgU~!+zkT9k6g%ue!cO!|-O7xV4 z>2#iyWbQ=evfnGJMLR!{2dbX`_}V&9u8)K)n?7Q z{Up1Xd}iw_YX9J~DU=yAmI5tGEN7NtCBJVwEtk^1K6?m`}P8CE)^polz)*~6y+pjE|5>dl z>IgJuPa{$XuOoT!m$DO|s10VsW(Hup>LyP40!tw=)OnaJ3|(VrZP{f)fj$|2=EFa}d(=N} z{XM-gMea}|4HXPTM5{8>|f|9K7{wJ<9_mY+RDSYUlxhw@*6j@NXeSB{ukuN7y zAI`})XpfS$PpG?+XN`J?D6a`+r&-^H7r2<(;r>Y0u&8h2#&QB%HJN+5oc!oe$ruOW zB_ZtE3vZu~r0E_C_@^6nR1;0|M>tHiJ7~7{>1#e~=V6<0T)XYIy{PrYC^9M`Y_m`C z??(MZJCNEiCAfowgWQqIS0j2Vyj+0 zisx5>h_a`gt%s+9L_PwA5jbHW}><+OLY-9_va!RwPNXav7cBD2CjkJKS z44Vo?W&U&z&i>?wdUv;e*huEvtrn$KiB^R9Ak`Yo}pzL++baa_lYdcrx6@G$kX4n~Mnc z2OF#*+?!A4ppR`fpsgTrNF!OTpA71(ZOB}uD_^D!Bjpj55SA~N@$V+I=3iN7{W@7{ zBEZIfA~kUP2pKl_xn&~esXX1lJZM@yaHNtW`gfiTnRCa zjp$Pp5w@x2;7Uob+~HfW(KVyH5G4fk$}-){fJ`;2pe#v3roWjwk6e;kN*FGChCm?7 z=ob!AMpm6lXn(BW-{HbgP+UeZH69I$5&}AlPNrzp5La}a<9df~LmTLkx{egmzF2h_ zrn5bKw|9iK5grXhz;hvizm46qo*+PpfY_E)i3f2cV&k}R+|C6sjT9TMjF4PeWdvHv zka>J8mF>~)m#>t^}`v{{sxQuYjIH?*!%M3-N`x!TADj~45+c2Wn@L7O^ZYjBtJhIBJjADxp zUSbwv5O#}JC(2dtp1zncTw8DL!?{7`t62on>29da+!@&dS4LZ~&XdJp%L2piu>YNL zfk`1j|3J{ObGme1EaDT<2xuf^lR;Om-J)n)-jL66xKuZbql`TOrqax}NV#f^lNc9K>1b1?)VdTGT zvo5SL?2VDzEEf^f=`9K&30JMmO$ZEFa;CB)=cX$o$RBSpLNeFsfWl3kr_fknE6}df zJwQw%%^|UOV1VQLC=#8V(OSsL3GZ!K*vIg`$>fE#sJI~0VK}ucqle*CoiTUTaYBUF zKp);Z?IBVjdERg06uOCugFr^5KfsbPoi}n+xQLF*HkA)YMPzB=h;8ISQfLJ9;G|h_{EUQ_LIQo~xx>(kv$fBT8}4v1cVMT>AcRW+5Y+

    QinBz2d%dljGvW-)HE*mr0D!7(gkdE{)w?1-Z(y9trelT;0bPfVPc}?Pgi7R z4XbXvkQdsjh&8WgsamvdJPvg_TERadP+CPz@p-jA{0WmnAFi7RXGT8rDh0;mYuS4G zs#rPRK0ZFt#h#Gg5?K=5)q?2^97#p&x~1{tjXO_6*Ep>VE)xlUV5v zwr3)D+lrD0cmGUo`a(! z{l9^Jmce`f!JWfL_8vUIU#d2yc-FN4;9Yz6?w7Xk+H@W}dh`+OW9~mVI(%&G$Zr17 zZegKQYkEgU4)y_0NLYwsw3wN@z7N(=wH-f({*%Ar-r)5|>C z-u8AMJ2E;vcIUx^N2K|E`;1g0FZ#7>@8Nx8dq;-vQr+YGO?kuLoNOzyJ%=44E}56U zrIOOSeZL6pWQCMcM}|kyM10t&1wMq;G{5TML;HvC+`XSaFCS`G9`N(nt(>ZR%;?zR zz0cY`HoSlDT?hJ$Rf=~`Hlc&e=aG94Ni%7Ef#l{rWB15CR$uNfHfFZ*m-%0FDEc-K zJJn5eV;g>|xAWl0A#~(ntvmW1*Qa0FuL9X3mf=H(GKiAMwa$4|L@OLKPH$OJ>5b9U zR-xvN>>fEdDzKR@HoI-_=*~m;9PTf{>3Y#SdSIv2+$xrVqMdj1FKh+Z{i^8RzTKk- zcJH?hYE0KA^St?e@aV{%u|va0qzp~)@?C$j(*L8d1jnaq{1uuv=UebOp1JqP-D9H% z?&7DVRsrEgd2Crvdb>u4ciwYk48Y&xzN5ZXuh<&&?K`rI2+C=6poOGt-u}HucaMz% zOVCDAHm=#FI!-VlQhw7YR+yQ}ly`9FUgl-*UH#igMc_|$DzJ}KX7ru|NA@ZcsmyM^ z=64FELZ{#z9lmRH_`s2|k=;jzcMTsI?q9Vk&Pt$48a;sh3}`tB7WC=6cOGHxTUd1| zwEbzU*^chszkB%b?xVZK`b;;fm6CV#;Qqb4`hT*0f49&sLwd&eQ^OkFjz^6;cn^Q* zDE3Zi|8&D+BPaZV$41T*#)>^Qawa*7(2~bSPK>ILjhv5-oP-hJ;iq%tG&5i<6=07j zWj@u%8(rUAh_eC4S_C@xvE}JQ!qabO<0<$}BEN3miP+@Nl4acFS)zTAi^frUq3UN9g6sg{t|vs&~GBq5^q!3Y~6S6Rqm4D)|%L zDSU4IOrb@~#h}0%VGU2#V#T89Q=?{I-CJL&H@lrN#NIbb1i#+eZf7$8WK62?@5{n3 z$NW~S(HbiwvKc|(kTbDb#7T*BF~tbivWjb&?Oi_S&73NNuR}+A>!n`HgD!np_{E&U zz4NFIZ3wCi5mnj9o>MKI)YW*_y=s6eUCDRpbjF{5}8EI&X17-rx=6skFwpFq0x zHg&&!)NK3RQezB*0jSRNPc$2Cf6Oh(T2kzcO;_3#QPFe9usB3N;P&=dQa%k*bDjRp=TRs7B* zf2Q22Rq=_n2;m0=N}clTzBRqep-{CkgDu1Un2e#X>0Qj+U|-%x0Dhwmy(JlypvdcR zuF3oa@Xl+WL?r!*v2taqj5Vt=ALwb2hM(Q8A$))A{x0C#M#&5LxBMKVRYxVk%Zp{4 zgejtb1y<-WvOi-eeH=sCYxuYoABj?Me+`rbZc%*_U9Itd0a=80cOp!8o?n~rOMv7_ ze5>puB>gqL4aI7saD2?ClPP0`63%4tiKkch9_QDmXE7%C)`%ql^q@tRy6oPMNlZKU z`T6(|w4%f32B0B04D|xos?bwfF676kZPNUpgE4g03glupJp7qE)W10LEO>?UsJG79+Ry`k=$RSy*{wbJxb$s6 zp<{F^!tzLKNo@KK(GP- zy>B*nJpR03Hn>#&JVE|kE`P3+KTqU8WDSC=<;k`3X8?at#dY#$tNa<1KR3vqZSv=4 z{MmPUa0~r8Ex1*FJxSg@MgBY$e+~q<(SLy~X))BFgqGZJ2U((S{Ye*(tn~_6YMW5& z=iJ9e9~oc2jW(nOk0^XSlz~*?>o=G*1z(qFe6gS4oJ`Z4Cli=91pgCX0;c{bowq2a zK22p~Fh!Lu22)=Vp1z!or{D`jE|?OIg1_LB$@*e3MP(gK(a#l$DQPht^(Y(MiVDg=c2Q)p;366|T-<(iB{6Rk%XjnTZdOja@nhdTeCB z3iFlq12y-aUm?@hU@JHR{;o@JLll3Tsca1XsItZ2?{?wowro5FPbPA~pKugBg-a&u zmc<{Hb?`?&S0w(V#lRm4ExF+i{zMh~lP(^AdfBZ|t7zo8kBlBN=DOT%eNz=O>Dv*HGCQ{7_|!!Ow%j(=TV^DR?W9 z3x0&7;B8zoSvM?xsH}q@`ne+UBP|AgNNC9ockm->)t_|f@PmoD)<=yWdSvvF@$(nl zZJF@%`3$5AKYz-kDfro>eL--g&x}#@g_E^F^Ph#(v@7^Nz7BkSFP+~gzP?LkWAH_l zEe2m_tYV%{!=Dt_n|KO-M4uCU2}i+yach!w$Ks31I{2cWD-vJQV&IE}mfUa$U!r#X zNf(c=bCrJxwdGhgt)!9XMk5(%Pf723JyPA8fm9*wCMHcm+U7Y(E8xhCNgxulypfsS zv@jS2AHdw9bk3ug8=n4`)TgSnFMG?9&`;JHLDm=lhIF)o>`PZo1j*1;V8T#=ZQ z76Wr6wB&|6m=gu;Pr7uN)8Wf=F=w6|jbzNdjXN;Y==KX4NEPPZ%%mxpyINz8_hG>w zpOyA>h+NoT%tmb57JL{S0Bs*k=Q)bD4^Y_{v{7Y?LEC49r%z?$Dfl>%3)+OE;1gUj zS(7Z) zAaX!>x;7h6!6qUXL<&d2Ra`Pz+bklftb<7UxgrrMEe0YWn-{Ll`RHquN9tNosFm93MfHPJ}_$hr+ZX_%gl)RDCg>yC|yuoXWBgqGZJ2UVhE{Ye*(DxHo;!anC_>tPICMJH+dryJHQ zBwhwmg`vxtGzLSCVh)*dYkX4{lnMBZG z+w)Hp{ibA$qT|Jcg{>aqh$krd04Fk%wo-^5rT0PDH2({!7&N^W!Nc@5Bi-N)kOBJq zb?H)zg6n6fYy?~bT$v-mxq<7c@$Byso*vA`Q}9bfE@PQ+6ug~FCTp+-IF)q(PCr*9 zz@^0)%SdR+4R^*eQU3mk53*AN4VFVHUGuQXmbtOyH zg5k&XO*`7r&lL%VpRnvQj&`CR%Z&q->Q7v{Ie7qC_w#Eqdvw=jAXU1*nMwQW{?+@; zr2wq*2u81P)*?z3q?|lSz=a$_*@&$+?*RkQ=3VJ5N40sF%0{)B>dK|ZiP|qETpDg!CUclsP-?U^BYy|H&fY&Y7cN_&agCZ z&*}Zb)BCdV6ug_r#d8vlg7$gFmWlG5A}*mU%iGe^LxK@f55fa>1W) z6s+Zv$+~6nM`a!S(a#l$KWQ=WM?y<(xPw1Y%>JZ{$KP2hcbXpF%x|NCjJ@65VVSUZ zX9iM*y{9p04E7x5^dz<0J)`?+O+l}@IZm7AJe|-qDR?eE3{X8Moz*C)?xnI3P;p(! z^05jX&^N8WMn6}iLLX<@rNCd0CDPH$t;^Vu(Ked$!f3^q``D-fYxXa4JCb{j5UG5& zw`3qyn*Amw?XTH~hf5{CvkTWIfL+erNjl!d&4Tn-x5XP!DG)h*^OiyH5D_#e<0CCU z`vs(5)8%!Wm!)naxZs0m9`N&9=>m!3=QpWr6hBl~axYl?e2l(n@k2jXB!2#Y+L3j> zBkHu=_&Epov57IYD$RLnlz`Fm58R66esj?CoeZQ3J>O!|{^)rY4FM*Jry3fN54vur zKRoSeGf0r+bE{Vw^arocFTn*7c=4QSF26v?B zO#6Jl1+G4zJsbm51F7Yy+{i9?2rUF~-k&a$C~)3OWh1~D;L4n--X$g@*r2@vdl0hF zotjKw`TV%>`LS$#1|K1ES(^|pgO75_WR10erm_y8>F0_Bw6qv&6C||ch7&T>+MuX= zf6~RTO`K1trhCzKq9=2+LChPY0gUn=a3^L$`M+i$RVe=_CXGS4qr{k<;UZ=Dqqrsy zH#3?X@Pu}`vs48Jq!XGZ1?R0}@U6$6dHaa#sB8p$0o9c(AFJe-(Kqd=ML$=hl3z~k z$U16CM=!U2Bjyda0BGZ;ewj{ZJ>JJ$C-;*xTHT$2RO#_E~+TRKS5<95a+s*`^N(7bM#F+ zO3}|139LV3*`=gNULi?3+Ftw9BmbjuFJ+za4nI`NGALQo4I7NMp?j7SqE_R zb43D9T8xp5gqGZJXCxDK>`%HRBbm9^N#hP9nSEw@osn1Mj_VI6wTm^Lfm9*yJ|;~; zp0}&vA@Q_Yrtk`kGKv~y0Aldc?57i&HU-bemw~MZ(s_+yYlh0kV2dhqur=?fqt^*f zy=*)MuO@Oqmv9ukhD#=Ejzt%hbX?koE^mnu4^uchlW&X0KN^iA#J%G|cJ*l2t!ewrT zR4a#OF+w+X=_)ib3jPW$0dl{R-u5VRzeHtYkV}<0$X#bf#Z8-ZQ$o)yH{Ta-zL$-g z;5$Svm=#`v?{djxeYBXRvJPhH=ZeIvv>2Erp(Qum!K^56f6~Qc7G9^irA+s^^ThNx zV|4R5nf=hKGmt8bK9NaNFnY7eZ4Q5v*8J{JSE}8CIh+eo$)Yc*&2)nnR@k&XxC0yl zd$*^zDT=+PQrQ^nQDqMH&a>Ftk6pkM27u8QmakFa>rghng8f7;C={-O5iXgmVHSl{ z)qHATo@L!6gF)S-USYU#Rt>d6vg7(scZ}usWJzPb{@Ftrfmj@bDmm`J}ex4 zFdIj~Lqskp6n=saaLHs1vnZsp4hre#ibSEb7$_v6B{$qbp(tj5(#4|?QM!Bwrv{+; zZF-xr_g(I=OxXK&22zE+Z!l>L_8iq*3-%Du=;5LowcX`BF-!($u4j;(fj=qhMp2Ob z1Z+e>5>Q>qEw(Cp9(~iU7}C!bsiNnz>{6tsR}7`=mRmcK_fluI9q)J<#!lW_U>aHH%fKVo^Tp*kfPMYT3NjuA)9L=%R)x0L^V*Uk9 zn}cKE3?szR^tMEm|1gz}86l`L2Zr-r;|PSOayFiV5|PUoAshuhmrT|$3qUIC0FZvJ zNB~NUF-DNkk{j-f5u%d)Nf$pxV0NS~Th{nKx zdOHh75cd%mHM+RyNsiXbo6rT^BMW0S{dk{rn^~#|Bd-g?jdLF_~#6yN`wEA zN&9Q?we50ahRz-#e7v@~?cuugHswvhrHd1!&e*`E`w%tjS;P{#J6Yp`SDwK9Ye{q2a$t3;N%WxOpEq^>Edx3j;|*!O8Lj293IIMrL}`!r%+w z14{n+bk3tn{-;znqT~Zynd64ed!F=d;pv;%cnZEw3zE#FdQNaGBi$@!dWlgrjSaTm4J!GU^c^+AdOh~&d1F1sVrA*p? z+_^I{?##V0(LEpEcl23`s*G5ICxdyw^Vam{M&WrAm5soY>q?ffg~l%WrX7Rm=Zb{J zZkAn|UMWzBTK`w+ zjfiUfUsBnq)>B={lCxU>_w-Gx_4IQ^YW+V@JF;rMsK9b-y*N-slD3XW}ORs zvu?|Li<$NYH-jsv`?mCUMAdzW%0|?EfGcz6G8fti9nH9j4Tybbx!WV$?aIboa0ijg ztVVbXhPh<2c3JRISqFUdb47wrT8vo@2`#zdq{GU86UFRLy7*ZQu4NMctzCJ*&ljqd zDKiC+du4Qh5%~h{#!QHOAOopF8z;MIW7 zN|O$GOyVhkI$fxCDVM7^Qn}NNOiNdxkx}p#v;-)gO>cV?#Xm=7V^B<$IVjE<6yKn& zj{C^+^6SFOyR-2Uyo<;Mv%*R6D_k;JA1!97tbbY0Lw60dZIsgCteyt0$Gd1WP zM(!B>%gg7>eznQoW4qhLiN%h@#?}g*w!!HV)@Xzj{2w$0K>hdh#z%qrFH|-HRIV#o z;ub7tUJwEc{ale?Sw-#0>RpQJEH_TzO0sS_IsV*7ru!KqH!=UoJw_;3QAIaoAXOO2 zGieM)T<@|xtg`y?Ne!LWPs5^b9zWzGEBhx+3K*ollxXtd{rkNl0wuUcQ9UJL>@F%Bf!F|7<`^4$w&U5@CY3C~p=Xwx=L$E^$;M4^jL2m)6kdXR zxn!~iTYytpXEdarD-z(+VvL3)wB&|6qoF8&f6~Q|hKOmszu1`BrhDA{HoeXGelvGi zCVam!1F6FI>zOnK-*>4&kl9q@AO$k1RM503*2cZs2rXn++~e$oSU(AG8rvao$?7u_ z3LZi`fX?@)w>*l@_fpvybW&vwI_JH2_Hp6qW7&8LK0@SzQQ;`~D3?suKZ{W+>tK|A zu1JhZi-A!RT5`i3jEVyHCtW;7aUz+O-%Yn0dS*0{vHAnqe4;kzC za_42j`q2!e3hRfNGzII=*=c$8a626(uA==vy>&6@op@lYSAC#{e7{o$L7Gnf&rpqXb=^B-d!8BFoVA?q`cH#lE zRy^ma<>=+Y(Mz*&6ugkg1=qq)@FFgmtg{x^RMx>Y{alf_mKFooB(&s)JGd4_?@zjT zTq8BU#^_rH9BI#iW(cr zdbv+0UD3uTBeiKif`|r{>t-jOG z6{+w4joOiQ&qlg`x%FKcZi>y+me74{U1~|qS6CgnFCOp8h?|4nOLQPr>50ZqI+;Gy^x5}vo zQN#YEq4A|Zsq!Gn0SkGM19-3`9^`u3W{f(Ia~~TmVgw&zMd*uQ_8Uh)x8!~!GO6P% zt~N93SD3%4bpG^6TFOAGEKGq(Q!LEjh+k8ApRtkKC{nZ&txnk^@Q7fl`BR07lQ{ow z?9F_Onf3-RCK+!GUYOpFsP%asm5s4JRGDLa>{`*b8*YBGmi(NjmZLWcM{mf+QP3lD zu`|L?@UvVp85q{iP+7;$(9acVXQaijGbFU+hC6mfl(9dlvNO+RaW2S@rOZRcX4m9t zFuzT2vpx79{Dr>uK;!K*8Aui0J}G?n^<1AowXvg}fv3q4Xw_b#^vV|}tKIRsbq**(F^{70%oy`9ea#3rxD_G* zqHazXS`<+?QrRe?sIKImvWU8qzG)FfKUXB8c2YaC&h+K9W)MoEc}{q1xDU4B8&KaH(z%MNZ=T9V)OUa@b6iQ!oG98f)NQwh+GQ{} z)>fzGFgu-%&4pbGy1tAVJ0ocOrC_6 z+;GxWwPGj=*q?OqGkM@@y3*?8yZ&TF>uu2=21^SI+OVeLc)QiZiHlcr!TPuW^S zIAb>s*I)1)=jaHX0px3+YK@Y?;53P}p(Qum!JQ~$f6~R{ZVlb)ls`Ug z7Od?9ql1jNuX2}VLfn@#kSfIe1(T*A?#9E%D^0K4rjrZcR1W0wa+*Kw;|L(`j+aBZ z(}fC7{X5%a3n*z?9sE0Z1M>bgy){wf{S%dqK^|4M804+Fgn3$xKPj#T@f4gvtNmI~w&FF!<5Pv*fK@b=16g^}2$UWXby-}B+^@az6ExHLAsZHyG zW8eWOJDSdQ6lI60Yz)e%G6!WBJH96xG9*csjK`Vu+VU6(kL7GU1|=dF)Cq@y&n1&J z%A$_SI;f+cD-w0mVxW$MmfUa$b)t;@NkgdXPpWpNX^S_sGd+q2OR_V4d8t(>b~|=& zdb>BE!t}R$1`jDzM#mWC?_)LTi*nw#eh=uDeBT;tJJKQqW!EP)p65Ib^ZSW(e)Z18 z$1;#AtMpMOjj>7&q>FmOi%cEd4THoq$H?f|Fy}0!bArNlm!t{cSGI zvavP~%eRbRgD+F(ZVbMdF0iOU{BtTBF^F7OvQ}B+^G*7uT}z^$E7JIUi)9A~>CJCG z?ex>=|H@Bz!R$c!avb1}=DgMuUD3P#Rz(@0-{TJ~Xv-QIH5AO81OnlQMiuNp&Unt%c@x`lf{@{algId@8jg>oTt>={ykGpH#U7G**r;jYt)O;-eUPAYXs>4CBkojZpmE$uSw@z+o@M(AXRqiWlS1lr`+Z5t%oT$7ZPz1 zd~dXY?ZjenKS3Mgut}9U*qrxb`NhK1McH@?&LeWcsBjdV&n1)f&tjCy zIvAy&D-xs9VqlbnmfUa$qoSbwNkbUzPpUix8e~JBLI)3)#8Wuu;Lg2K4`I$zqt}e= zqpSvfksj@>;Od8`2H~`%wcUunz zZ3KFdnB{l3C7~bg8K5krrdh!&Nw6D(m#4EEH7+lqvXOzG>q_oX3+y-2H?8+iKUXBM z-^8*@G0l41mCo)DRE6mh*Snx`7YkgZ+3IRdJr>P*YLtMH_zC`6a=(#XQZw?8Wgu0$ z{ZVN{bc}U$`zn0{Xa?oZL~9xrd>NmIc7HLQ;iz{1IhBoSH`SFaC9B=vq;Fd7rk^WP zyT3*4$U3)`?w*Hs_a{{&78(E0h;U)~gJ^^$~K5}8=IxU>%YksFdXM{E5aj(Lh-;&O`M*6l4qzdUnOxk}GdqSg0k&3vx zO>->+nmc^;r7;Z&4v<(k2K&<)j3Rq4m5m~s>PqfUi|l97H!ZU1=ZZx3v#A|fkuBZZ zAFgWL+RF7Vblg&U?WzREE%&KW0> zaSx459v);Knd~QeSJBEr%`a67dA?(*(aINVrD~;)iw4Y+tEo7K+*9Pv{HrkM3e@sC zD9z)_1LZB4ieKNIDEGMmHTR5erFa|{NVm*2yY3^a$KOYTp~v52K_qLR9u2=so#XBU~e|=WiEn7{U}4D5Rk<3 zd>ZI=<1oiR?A+qoyRY3X$@+Pyhmpjc)8|#%4evRKlEL2{L;eZuHVxsQL)31*?-7R< z+B*h^N{wQBXwok=S_NLv=DG%to0a%w{)*{xwz}&sBgIed?_dG~2#WX*+22uGa}+rZ zhvejR{!{O5bdiUL&13+IKZNHf^N-C?uSc5-S<^@h`|280mV3b@*&)T0sCSLYmBw~huLn{(FHx`egnH7^>j$+? zHYVDB3tMQisSMLvt;*t!#DL=D=%9Cm)qJWgS?c*3^clLGg^rYZGlg~z=T6&xeJd8D zy^{(rICqMxUD{2*SedNI=~HjwByVlg9(JW82U^F+`A{w$Y~Ai0Y#krxjvFX%=)LL` z;nacRDZ>(a_f}So;2OkUm=WvJ{!)cdH^fTaX<`BaKKQg0T_nqTHMlXnS$`rXAjH_5 zrzdIZ8;(%i0{(xu-Gy?VgjP*88YK@w3vbL%9` zdVR{Ap+5B(Ge#pgicW$+kEHjN>41??2iQ*Q>xruw*a7vJ5O z@%A1*sIF1RI`T}TW!;CQ*S4t*X=*J)Q)%HNAad*Kjk>Phv6n$_VeF6@n6d+J^I#64 zP<%y)KGZ1Bpm-H%MYGi?b&F6rb%_-z5>iL09dX_X&lRA&9R%KVJI!uK5)hN-kspQi z2DsKv%ehimPUtX5WG7vfuhda|Fn6HQsxb=4&dxNtIL}O;$wZ@5Hr$f-N|b)Hfi%wK zq(bf6okr7>`?^tiPMy(|LeTh=D(Ig~2Y)!&pkF!yy;&d*6xx&2%;6TZN@+pJi zTmiB`+;XGa213P2F1Z(bIi{b!Kv#arXU4~A)SzejZf3{!|K!L|cV{>T`KMkK!0z)H zX5ubhR@CNZY z&r$0yEI@o`66T#s<#z&$>tl=qx&V^`Z84mh+^4AT{qtqcj(h!_l_RKH4!6zq1M{rV*C$bgkn>+RRg3EVNBu92tnP?dd)R;0+ph6fW z$rL*t4h$uX=ru6-9az*h=BRY`p6^TabB0dbD9Mpj>|#Wy$wiCi$Ua`_!Am~T#_iZ} z@lWD=g-)*6ZM6_)2e-ab&zoA?Ua28o5&7%Se1Q2NdKJG1h9W=_8G^RorI| z-|7J>_@CL8SH1=5qi-I8zBk_3BlLYE?QHOURswvF{Ve>y=rVmC#RU1pEt(UfWm*Dtp_-QsaR zS_-e2n}J5;G^;$}qVHghK%wNZjv>o^N_C8ZeDF<}DFEtk)2)@6YmOxVu=fEP$7HIc zS6I<-jWzre^9(HhS7>yDdXgt1)1*P~IK4Q*Yqb+T%}Gi!+3(UmI!06fM4^U_3z`|R zR*T9?m4aV6>`bUqNE!6@()_>f5tMSMmBw&<)*O%4`nmG>w%zxy(tZCtkM5gH>c02H zj{PK2+f$p{-jMA?((7WQS%Fk5b=bTDt;XQGSco|{cPgzW-6(+?>)gd2X2;TDm>rYN zl+}1z(Ge%iIzf{hB`ez#dhlH_{Mzn1<8nsZY53D`r^8*&4-&fT*cr0ifi(*Xevst` z>JQ%I;vt5`xz+Jnb*gMEYScX^y9^T!(bzeZqtOdpPCwLs35{tJeibV{q6@T#LeE0O z8M*m$mhs2OdDP6=ue!sh^`%D&$Fb(;*D&lL$FA~V`J&=>1O6-TUg-g{ohy`RXu~MT zU$dU;Ymb2IQ$rSxKX@u}1w~rViWi=PZ;0(W4YKni-RiV1<|RJz_;l^oQ*z-4p0Dgv zEVHT@96mgsGxE;n*Ve;8KdpBr7O?%C}uG-ay18JO{EEIXt z3cSF$ieX?3>uunt<_OV}<83Q!0!}5CWWBU~f49&sPf9X%D*6jX2CNZ(HX%eHE|NDO6a?B-TJjn2lA3OLnE0Y-mqd_)Ka z?fh{doSn7m`V_|)jyqU^QX{%7jwcncDqRpi%;BL8d#Mb$lf7r2Bw^C+&mf40!zTv4yY*TgS$8DRZnnL>GTWvq8g<}8R_*q1*q?W7&(7Vv zC7|`=)Z)pC{p}+5x6MQBFAaRUv7|yG97&S@$9J$!Wc{^k%Gr z8L9KScikRLPkG%Jay>DLWm5xdWiXDnCxv8=7aDw!I7j6ec;{1#Z8}%5G5GL2n*Itj z{kPKTgNKN>jlplwA7gDXt^^;z6Fu|j-H5!=-UB|OCMQ}REF{G*lp6KT9bOS8O_L=e z%pmZu0v3el%HV&{2Sf%7sLYCj>)9CmFI1Ox1?81!-)Gb5Gm7Fu5=F7<7h1Gri6wl5 zQ_OAb*KA{B$!&9(a%1rIboR{h>#NY5ze=ai*qjTfIqjK3)2`~xZOspCYvQPFW0-Jb z@E_^SnZ~>tjrq59`izY^pXQ;}MxjJwHDcU-6=-fIgu(hNj2gxe+omwx#^5}VXH~P; zpebjk(`RhT<=ijjZl^>Z1WY%9%vhYcU386YR!TwJL@u*2*qqL?>8;nIiC3l5XKdp4 zsEKvILp~^QM16<7f=**csa$Llu&@n2O-q7kz5O@DpvvTU&x<`+jso0si7lU5PeMUN| zk=W}|^?`KyU_Uie3%BolI-|*XkRVr(>_=n(U_46O3CENVsX4=cYJN^zn0{6%r~RSa zTyG%9JB?}>qUCe!iDNdt1HMy^M_Czf^PDzn$1OK*%Xw{O=%YqrLoCM{c^AdKb-FtK zJw$pkUHYcCeh&0qrVk$`c}ZAk87z5DxsbUz{u8es#|w;|EcQbD-ozsxZ!)r83U&YSUWo%E6M;p1uU%|ansbAUJdR;fEAZ@QaB?sW58A`4v~$>1 zr0{)NP(VO*-J`W6o@3HXm39KK9MRzTZ(ha6T$5Hg3IH5Y@vIg5`YmiZV9kOi5PCyG ze4A^qukTmAsaB)gq$viI@o^;?;gP(Y3eksn03YPhm$@u?c?41e!QSoO5alhdcdOO7 z5%(*PW_f5ZJh~fca2C8v28RbzpyuwSzYXa6C9z~9_@k${k-_$1?Y$0++v&-YPxt{&qU4G3D<-)eoi9>w#BfwG@`<TV;}VL@`r9O~}`7xs49Yw=b?m8m)`1#^T{G zNd-3sUrO&@qYm!`{hu?vx>}sPx#9wk<#9*Zo$dsGriuayo;yB5C>UV%N`2 zwYn4A^0+@LSMzIh{_@GUUY~=1h}00>6JqHcd+?zZ*a(ff70J6*;2Q+VgXs!sjNE&n zz}KbICn|6<{(Ea^^Q3dK>Cg677g~jhN)i9S!NJMOiP`dM?fodoV{ZL5!4?p-ty~v45%iv=4=q+%rUS2h%0No6Y-)+-!gB`(S8~ z?!zkNiS}7#YuN1Uy8Q7%ql!Hy?}cYFZEt{Xe!ioKts(j=q6Dx=VHj*9$LZip^g9O^WNgmUmit?HR)t!Az5oWgv`BhI}u@Sg(AKqK#C ztq85C^=?|IjIpUVG|%2~1TycUV1F`QskM6~EltL>J30C=s@6CN#g$x2({>3e@k@DE z!>fXOBI@Tt3kcc|4kftbSz4ofo=+8`toSbOkl0{F(@ zmFc2md+;(MxAx%w3E6`mA4C8N#@?9;gkjK{hZqGuC&=OL7|O8^+QcG+#J8KF+@zgh zAk#e$xlRQkjz!uHCElM<$)n5L88Bvs;o=B>ndr;#J)fkO;*<|x_qpc$4)l=Ras2CH0e z5#^fApjAmSP(6;H<(n*b1^Kn%Du5^06ZlNV>qU0QRws$X7 zoln>4oj{m3>V3tD5yf~85qDI+Prh~R)|-bK?IG;9 z^5_r-!WXDD0)%HS({~-*EZZj_;4h|kh=$qc(@9O=eHvB&X*zudm>qjJA~XqUCYGNz z0&p0w+k~Gh4zFbDkuV~T<;U0~uW{U#HnxT*oobWCJZatz(sCcbOR=MamBx@?A41p`X2C;-B+u{4om%xO#ML!BaDTSh z6Z1&!UV||xwevVfFRFU`_!uo_kVUqLAM|jt384by@6+Iov@L3Vk|I!9^>Nx?RfbWU z2YB{uJX#VE&w`7Bn4Vi|o@+p~6!tmc=SX@bs*!~Y@82G_!<3&ggq1iPLZ9WuDLx2~ zb9kvlcXR@v{_ysf1C@vS%TV)wW;HKAQ||%vUi1j-kM?FSFj}ZpqwPp4?k!sLpDCcl zSt6*&Y%jL>J9<+O6HI1lzH!t_|6NAquZ*? z24{P`~R?UobT{Y6upuf(I@{V zt?8)Ta0)#ede>?t?Qg%FuVpQf(3UmY6zayDNtV&6Uw)(XO$%tw<+?es2G;pX3Sk2C z>l_oU`9Dh;ZKrbc2-V!RfL2^T5A*MQc3#Cy3$raQd=~WDE1#Rn_BX6Ac4&0($nfaB z`O)2n4(9I}-LGAM9fw8_9=n&GAP@n0T5%UU?AeY@^y9`&_(_>I$cfyucl7X)c@^L0 z7C*du=fMNJxcpe`=XI~GD4vZ!&#@_m6pc!ZP5I+cAKHHJUBU|>`GQPR)n(o2nYLp{ zg@!Uf%w5GX=9C79wfKfUD4~{zu=wJ9%ceteYY#u|bC`*a5%pPXve{15d3u#E2DfFT zJ<5>-UzgU&krxqhJRo4_oENg-#nWAFG$7)vlgdt0YS6lrT~{JM^yY=M(XnF-D-X%P zfqN)CcAgUwo`(NgBT(nN&O=o8i|O61M^pJOTK3!I*(hjMF1Pz2w!F+!&vd@^ULEkT3EB|Z4j;6=H4{dTtsi1FP4jV7HNBzQOK91V+D*y#%Lq#-2+C{@-q4QGZX zQcrp0HBd%4jJjB37TDSd*g`#5n1r3+6Dd`sVdn)c-U+6?q9_7?^wTU24ac8uAy{mF zUaMN5a4l=fS`?k{EdU z_;~s~HpbV+JfCk8iMg;QcE2b0MChUH_v~4k&p6)xQq>62oDDuRF1)QtCpF#vt&r4% zZH{}}`?3U8s97Pof@(sUl%i4Mm{d+6KI{#DQT+3Gg-V&sP&pcG2L-$)nDo)# z)D4g7CR)RDEx~zXaP>SO@Ey>5>GXlht`i=e$Q2EN=Dowvxk(QhG}@G(`=%QPpX43h zy`T1@d7l$U3fc$(0GM{yq1;8D*3p=z$03}1pn&Lh4ujm38gxoNoKIW=kLa9k3mz&C zKu~Tb%+oMRsnrzy5oB^fas>`5Li$BcBSVQzX%)0Zr=l=nERZi7!N5x6d_!*qacnj8 zcG1w=(lyQ)>F+~BpPWvgsG-&&>s_H8B6W3wTD8+lf6ihoG)%cxNz0sb7iB}2!qAdr zpGDN%@W@_oZ;cWZX-CR^WW{x#i0j$u&F6*DV?=Hyiu?Y}^&O9GI{mcMhHHfffXm%G zx9KGqiar29WH8~3NU}mo4xk#mkXIPzaVvC95aA95Fl%fznym`3YS)$d@B+dTY`g)d zEueujoQj{?P3t!k28-23 zw`5}w+QteYw=vHru@)pZ$}nFXB^in0Q+8p)W75hdEvu@>MO7;qR8@!g{Q$_;D(k9h zFX~(?CpG%QGH_BDn3)FyKT2Ytkmhw0COD7Y4ii;wGJN*C%`fj4x8e54SZDlI)BthD zQ*M=9{*r$-zo( ziVYRbk;&?iEg;vzOm?*e=qkW= zC`1buk(wo=7TY)&`$2CH;-xtlTPz?fJ|e}iBIldtE^)24?Y}8)|BZRH{fuzioe?|- z)tA9Lw7E%ukUa&A;e9qYX+-QZE?+R*Y+}EHZhY8DNy6d7>hU@5m2Kl^q>Z1-&_>$8 z`~;Dkae8F+=^^X)Cy`N!edju|3BZq~n#Hqq!xzsX6=pD01KPAxxi5&_$|Qx67_c6CvUxpUUL%}~+Vs@v5NM%&S^I3*Z% zMzvFfA$0K9SR=w4<_NvcBw9%JivEO7lhY`{%ipDIryhxgZEJV?>=BQgov6q!+SMo` znPgpdXVuRA9Q9QjK57~=i49rIFk}mNoE0618~q$dDI-XkqmFS#5UHc&GK4nAzS{t0 zgiZJ-1}QEX0mp2+NkMO493zgH7h4m$;m6z!PF(Hq(liw9Tx%reuE*X6O_7^xIlg=H7)F&#vu^Xo9}dgje(X%XyG>6DSf zLjcb=Ufst3ooj6OFXi_fHCftvp=n!L)54~Y)05MvlF&ftFp`hQ5jdPCQQ(`mq-eJj zpeyWU>-`H8d;cctjmbt8cfZh}IbFb_2<}S5DkByqX(%OsT+%mblV!G$7F5>y9Q)B$ zH2LZ2P1cj9k&DCah&fb8*?rF~;lMib)WZ9XPXP>?i{{Wok^%qS_&9HEAoI*HPI6&G z1Mr|HV->9Ysz4n&-^mXLbGzxE7%C8TLs31QkXVscxK%;MO1~``B?)e**rS-%5cYW6 zMdm)FVVnSqHc<+=H8SUI!ZD~#{0t}1ipSgC+87AkDR>~aRuN&4tOc}w}a zk!wj8Cb$fEM|OAJ=T1sz731aXhmI_1XX?q-64z=m@+xZY#^4p{qA?h`l;rYKE)a_k zyKS~*d|WAFnjVTH66*gR!t|xI7J?i=F}$mR7|gsioqMeVZ(&kc(I@6od9q*1Knymd z?raA0G7{pOgc&O^++}RQ$XJY%3&ucAq$RUj9ykEePw*&I^b=Gl zRN2~jWo$b!%4vI{4a_EGU*cMPeuP{%{G3oVPW$J)0M}p0E{4x(F|5rQwyY$ahp1L) zvk7BUtS|;`>tIh)&1sx~&UUNNvRR{LmD? zw$TIQ>jw;L#Kf1XX8EOw%Z_Yzh_JjFymrdYL ziWT_PbU>NU`XElsmAU&gPVBe?FhT;!ddae*-VOxwX|d9FH~Xq zV}b)~ZMd=cI@^8hFd2RhHm{y9o7p;IyX}a+1+-hK_od>}1KmPPUOHY#)>_n3W~HX0 z?D(o{wech;F3qCX0!y1N2!IJ4r;w_Qd%yl%P=_ET}|V%(!y!FDJ#yjq|SG5$*yCLo#)iOc==*$8*hA36|l4Xp39Y< zclf*%nFZ`T`uWK=zoTpcP1-3z;A<%KecO$LPnLZ?xtxQ;WhRip%H!Mv2&B#Fqa_Gs z#fA~qN7MmIs_ak;M<*NIHif++Y!y2qd}yRFU8q#$JT`R~(7P0t;op8LD>0@^p$Djhd7s%YPpm$YdMTSbBJP$9Z({YoOj z@Igl^=u8w+78fRPy^}fv=nO(UbWpj;cAjZeKa;_~D#It8{>elRf#j~C*>cz<^W>IW z!b|p{$*q0td<>IY=Q(PLID46dredKXB5m*jw^et6 z^ELM=>f1cuMrO08qhSkU3-vCws-oo0UX6HkS7HtDiTBOAL@GAiAxaLI9$}BFkK1?t zk>OE~T)#-bbj%xTV)sHwkkwu3vf^`1yNKMnc}GKT-m%rEpLQCpNf?&_7uy0@Ds8Ba zvzp`b73lg~9nHZvqggQ`)67W zCUQ}9h=RNOG>@Gx<3u7;2A^IKmy*vWNaiZsmk4){mKO*P#>Jr|62-MoEo{WERdO zc{n;MzajB^SmI$|v$pf-!-CU(mOi_ThfYoIQ`Gm|^d8iZmQRDZSDX@E8bHQG^_HwkBQ9&RV+KCskQ^gJuMJ+vaXyS0rtt+_ZxQx`oDIAAqugptbgPvb z_K7(LG0wlXGsiW$a;J0bGqChvjOAFWS=xKEce$_uEAo_ux7l{`A}TQ=$=0p+C3fpM zdm;;=Xx`cGQ>RbD&%wke(`9FLYb?w}__Eqg;_QG%%Ehkq@zR}2OTq{7Q0d@_2egHF zWIk>bffwOEmmG15Cin;yD8GpOK{&Na_gH-hJ3T$e}){h<_SMfTIP6X zp@W+3`@2Y8hI{a2!i3yL9o*ePfz?!sFR;y7Hw^{=Cq>lW6T5e`rGRhn?b3tZt_qTl z;btszBM#*%Q%6Hp)x4(1b@LauBL8Nqj!BsMg>QF|c}%#WiJFe#CdZLJB)7(ODeW0@ zp3&#Y5Ho!iZ|px<#$j*lLgU6-Y3bfOS54RT8^um#{iD>tWOgr}fa6S*~WjgXl;cH!J9C^9&;{Qky{EQLyZ z%1IQl#vcQHHY#eKr;?n)_9$W8jn5#du+C9t9YB(MyUPhX5G{wKI@PL}D4Ck7;_3|& zn&K8#lMmw^Z?EA@NYaAJ=a%g+Kab;!yK9T*eXOO+l@9{!XTipqB@+2Pn zf8j4m53rVH?aJ%;azPYA-%fI6l%mbkCJNRD4DAp2XncDoc3O^$(ln2 zu>*pjbRUWRZyda7@Mi8=G+`@T$!ayk2ycYAtc$lvmCyh|x4F-)9J~HANFXkoFlY~Z zu5<@G=HR7#z1=L#)YUCM;F_*^<5d*74UR6Z#HuH*k!-3YB z5(`+>smO70L5ud5=sv|Es_;695PLq7>;_gOce2sd1D8GP_`a3Xz3f=iuFkVe1tI-o&oSyv#T!J_s5p9ee8TY{2aA@G99Vf-xmhZ{7vb2az2@bI-z+N5s>G? zQaACuxv!jWM&IEJf3bk3ZkxXmaM)N#X(I|de)n5}cqv)W-{qFs$eCkLgxNg!m?_F+ ziZ=9y7cDBM&zGPw^yoh=3)p{{9Rb1s!2Xg)d<1fYdkQeKY@M@ybLK^8(>Yg)2az}$ zJEBV^O=uW`9$Xk{>zlI=osYOrQQxKoH0gpEpTYQ-y|}lA@oX0JmDXbREuixxYu7X` zknO^Qk{pv0(TmGv4)DajGc5^rK{nw0&U6u(UCG`YPdW9Lsf$i_akG=UcrJgEo!H1t zOc%xw>0XX~XWMYEwBecaXv6EM4TsYU=xaj`(I?F8EOMpKopiZ#f!tB-C`tMt_SC0Z zxHFEP5Hx58t8cavPuj;NS$tuY--^g%c+pjA=`BG`R@V26tQ+Z~Gy3udlJ)WQ0@-AJ z>~frZQM2>{CM`4Gkl!f|kwAyk{+?{oQbLuI4$o85 z&yw!2cIR3)O_aoUNs=g@M{K9OM)*J3PaMPh_Omz3G;fRv#&G}0=KH)I-e#@$cW_4o zoO!vTOwY>moo+?u^_!*6t3)M`J5=^Rr*Kzz9V#?bM*7zwr7lD2?NF4BX0?mt`(wn~ z=KG$#c>*c+#%gqN8na1{kUO`%`MyCMIPvSHfq~7jHE-U!*?eU4mMyv5-btS8Qlc!` z|Axra5+!Li()8m}HYE9=Tc+e@I4mvf!KLH~1jm$1W%tK*P>``W)4ZFjE{o;EL(~hj zmw}9Mv<<8~gGx`)H3XRHVP6ENj6_7(cUCu)GuTA_>V~NS>xTAT`pBz`#^OsJaaNpR z@)TeOmf=60{C=vPYsPuYIGJyaHforo9?ec2Ac^uh8PZshQ_KK zJBDT*eL1SOUGZ`0ijU2sE8b3Bp~Zp4@KhK7&d~~{xj~K@Ukk_ z9ix)bM&Z14Mr1!sGVijhR;pC$BK~j}J$xydK?H_}*&rIrRI~z^*%XO{+ z8z$X`rWBi=lRKS*S$I!u=sKKJAB@qP+ZR`#QIpI1)#Hf1KOIE%pD`Vc4C84H)7^eW ze?o_oG)nMt=0N7P9$`D1O8g3`#1EECCF+dOHeb_@2wd8aEVT;7Zb$Etaq?bF1<1Nw z(<~H^(?w0#@F`N1C)4ZwGiXq^RrTaZs-CGA8!ZYv<(Wr}2Gt(c&l`o?w}hW{v|>rC zMK@o?DipR`Q0Fu$8+Gna=rDdo3MF{inq8fR?QH7&Zc^tfGt`~U!aZp(qLi&C02>d7 zz{?}Foaf5OjyF@r#(e(7lW!fn^=1m>2YrlQ-ny`QjDoEXmv=-x_YIoAFQ%I*(_bdm zb!T6lh1}sI8$Gx?lA&`{rWR>PwvK-dw~j6*Gj`z)u@oC4OPLNQ)RBVe1Bm zl)5;1T81coV<<*d$`99*#Qrj;6}rY1R@{hDJX> zg9a+?7Wrh;?)Q^+H!{?nO}oFV{Ai_*6r!wGNm;e~S-9}tI!vAlMat)6LYi#2)^m9A z6XdcOiaEp%Glf86`uvS}g?mZq1d4q@w{Z{gTlw!G9w5UJt>%KfM!8}r>WMCe^8`>4 zpy?Fyc6M@6T;sJ$T^RGyQIgo#=$f~sca51ke}MY(=LH<0%ut_BQ|ASXeo3UBQQ%sV zkCN7ysX4E1y)UJo6IZu>+je?i#Or;P$jmFbRG;;d-YOhVXmw`yorzgs@LpMp(Mts? z7xjaom6K!Z5e71Gnuy}!$m50yy?{5U?1aD%o-Sv=^rJhd{w-4{8$ zfEB<;M`LVHe@}Y)?=$qYUV8r+!9{m@=rl@f_=w6+75mQe@gw2mhx6d$55s(Ki!GGnUIVx_9<$^y7U5iSYAV)Fi86;4lUUtvfi97IwR}PkgTstFOW^v z$2L4VLQCY72$|c*LP{PBDWT~v-@LYL!BEa*_S6U|d0M(fFec=W$b>wV3xq>Tz8s3_ zm|t*L2!W?=D9NL_iN+7%N%nyhjYyni|1YZ^WxL+9aw0O6tG03&HvJYn7kvh7J}0H? z+-cwcw!M|SxIya{YE3iZdnK3Zvn1jyglHdHErfh3JZ)NzI1kmq%TcxMiWAZm)AQ(x zKclYD;&?2CBq{jC89NsnLh>`*JK?R^r41pOP49mlLL$s0!^uVM7f4lJm7#8h+Lwd0 z&y49&A42k>n2vs=LP&l;L$|5TDPcRCN_>e_;sY7#&ZZKNg^(;ZaK^DyOC3V;m+|V{ zKiPF{4;7jS?#Nw;5DUsk5-1O`X3&>iicO>dvOlD>8)Sao5orT6lOmbwWta zX72i~@adsV8j`K!|C&1fCrj4xkA;xvTtpHs<5;DvAtcwwsNthNgyiPz+AZ?QrrlpB z?cSWB?rdhwhA9o#3s`+A;Y=AKng(g(b`gP6rjEq;s3{Yzw7efS;ZfJmdpo6`G_ z=$WoC2{8}OvwMtI&by=$O|q$VHTYk`8f**ouAUR;M=IPe$WQ1cRGotSSmmu!N>ph7 z_&yGj>l5F1$w4ICINZSjHFe_y2lmm$UuqL4nZO7%_`1OSYw5knX+^(E)RvR$oYYTdz8exi7z9&aE>m^qtuY3eRAhyv4~5(=qEmF zsz9V4(icnyph#CUv3n)zD*9`Ga&7(}qI64ny&kN3%jWvU+s4 z)96$AnPzahbzyKYI_H4Nk>fh|F+RKQ`u>5Iy))@zqS;=!+&g;LWP;}`4IM{q>)vHr zH;@(J(jI*yW^Wx#L0;Jc=S~fJOje0ZgdH<_t6TnLw^f-9E~93Gmv_<)L6)Blz0(J+ zaDpj0Tp{4HLtDQ*oIj-6w9R)tx?@{l>W{$Isl?^>SUqm6mxHGb3TVK3p* z@fFtXYGtb2!M)ZV%Ath|F81Qu!%|67Vic>5Zi&yZ@<9su z+3i%S?L3lT%+OF{GZ#BH-Iz>R?G6nelt_(iHD6XPw%gXtvEjM6%H>!Feab100c27g z!sYy27?Lm!@le;UJm8BBFK>8EX!8=9by9AHenSy&PC>Kl$(?pag68&aQs*BE-u=bK z%(jpQkVe?kwABidkaTdGz+^vMP+8lKUDA#_=h2Q;;db=DTDm=CEeV?50*^kKFb$ zCp)ii?&ul1UovxWvFFM|$JPpE@{9NMmHjjEjzL=~2u-;!>&J}Ko&D(`pDxQM?6NwS zR+G-!U4C;pH9dB|5`Kt zB0A^9w^sLJ4u;E%$-K%TO&WpiR8Zz}^wyc-=s9rD7J%^;ZZC%k+1a?(wi z`{^TF$dHMXk^XjLtB*g7A9Xb7Vf`$+=%HE_FIcVDe5_ zZ;{6p?dP9bOc_Y>zQOxbB%io%us+-k4p4@XOHjO$nF5;-SqLfPjt!c8I|7Dbw%7c^ zr=>*ze znAM9DT5NhHk;1ejo9R10+&{KZ?-HY?$`fLk(2`q0Poo?fRhW9eZpHKn&3MSIK=Snbh-07-#3WduJdg;!=3!~ zK7J2Q%~s(oK z!h%AjG#h-KE~Zs$8^myL4My!ob=oh@@(sirde47Ed(Wu#Bg}{CPirEy87MnY*TI_uQ_2Ay~>4H(RdP*dDy|_d~v2)KGh-sO7 z?pRdq4$u}^5juTax(xMjH<(Up{JG0W+}EcU(DOpAduCqfxE@yyi;1k$&L|!5#5SzC z(yh`l8kS0D73cu<#l~QNI)kP~SIkF&keiH`7nF_=-}#D{hw)db@1P{!5Hi*eQFCI| zWsF!9b-8{Xbvep0uVRo!Azd0;74AzXHG=a=bQ{k)xevf%ASewzw1dYJp{wdbJ6#_R>GM!uT5dt>m*bUCpX^fDs1UeMKHFX*q2 z(1dm8URv9ht0US?zgU^9!0u3{P~JVnJNPx6C5Yy{bO$QjqDI{=qrj7+1jcYxkiQt7 z5EhaPo!mHiE6F0kG#IxU_+Drqk(^UA+iLS(BJCi0dT@FRh}qjBuJZH^XGNf5K%Q3`?M$S&8B~DoMUf>03`xc+ z*aFJcvio5V{onSkJw~poj6%-x;2 zoqaHmwu>}C(75P?NZg=8VkHs@36VdHN&+zo;s zJ9qAM*rf}yf1KI5bMAS3=X;;;e20MY_QUk(=QcO@N(|n5_1=cXK*wu4sf)|V(hUp3 zQJ09f=IPFk^^pPuVFo3EJy0G@TX(t+!c?tJ8ew}g;zFg+K<}EvN-!C%v>#JMEeTW2G zYP?z4Gufl}3u;iZ96eJ&@#y)?jREBSTB}6ro0{b^#5X^7@jVE1sDvT@F@YS6)alg9 z@#bL%;NEkiZxy@Zu zODL8zO?AT-_qvlsnK;(g3|z=8m0LysbXE_KWSE%`j%qSCZAxN!a0sz&YT#-h(;XhHi{gQMsktIvwexnAqONjzr@eM3@7VN>js&UJwYtv5F6&@g z&fAwC#AR~z7~gr^&lc3-W-K>WeN*zPi`lq=)t%Y6DQY&}eb5XiV!RzzV{D9y6o$lA z*0mMp%6KbwWwN<2yX9SWW^jMD9-D{x_7NbkBLMd_pj|2VQy{v~P)`*at>%kCr3PQPaH@>1OE#d*1^U1l&rTu2 zAa)5`XB2x%zk?l_I)WNS|JJXYvo2$LcLBS}5V}s7UJ^5852<6T01qEhRO`6S_3v}8 z25mmw0tRn9lYYWD9!*$G!<8n#d%U^IaHr(Ou-r<|+i|PRX{~7s_nI^+x0T%Hr%BxG z$rf&=2RFC5XF4#)QqlA@Z;`4yZn!m$825iphbL3PGst9k8#GecsAfp=C_T0L3gVNs zX{*F6Z`p&ZX((TTs}|`l$5Ps!RY{}E1M(ORjOJ@Rs$$;eeGk~mhA)@KF@qt}3;<4( z69{>x^zBfUv20r38_6cfCcKgA5p$Fb!1Jx{h!-HGSOU(+^~2>nluh4=xN2i~kEFe3 zH~_6dIP#xG^7m*=s;;m_TtHK_F8WDEBbjkfp8(E&0dHa64dC4 znYeh~RA=V+VitA2zo;I%xIoFdZe6|Kz4^veK!?BWVRdhtdTe(rYZ@B2aP5v^-4MsH zn#VzlU>hJ)`0mW1ihbH{aUto7aY>v2x5jzMz&PGyy9rDNyE>zC6}Db49;T}*wLqAX z<_|E)g916#o;^F#h~qmHjEQcM$L{G7zBACMqs@mh>riOcL(ga=n(KDh9V`jK4!x zLIMFDx1QT}1U@CUuK*CdDn zCd=I&HHjWiuefpN?maxK%gL{Fn}4J}&fE)Nl$xSX@uZr9mTIM@l|F3EgF9DnYI$^| zRx9^cf|QGY6zICwr8WJ!cG>LSx2q4jOLgc7PfE~?FSpRG+Hz2ztHam0W+}U7 zvL9y`Y}(p)@Ytr{apP&gV{be>ayYYSJOPZAntV!3dfwbA?v{!PKLAR_NmuhN{Uwexb4qLce?e{^-DApxb%?mw|cJ-EOR*nVH1JN{km?0;|_T9OdwT`ghR zVx4z)MZxDe@4hUl)wJb~pi~mS)4EADWZL?eFeNHu$`M-#!dL?`ae5ql1=#B{x5|;d zxD!ctPh%$@)=g_SK-h;9z)#=0VbAwOAs$8871Vw`AmU6=O^%i>21pkJKj}N!dez#s zhOE1PA&M~HN*Hl0!rU7jzK1Y-cUNg7!EJ+62b>2THOek?cte(HQ$UK8(e5Rpmp-jf zbhx9fECxo**3Em%Y9C<vuqpKufhBwGctd9;|E94tU6Ov5{6bw2+;ts<% z<@hT+;~>jYP#J}@iUSk7Zn%(!jV9AG>Mn*^Ms%9E#Uf+E0U9)-pkVC00Y1V?FmfA9 zA)X!vX7j+CnmGrGiKH|#S*==KQpthT>tpK#B6Q{9@T&k-8>Px+haCXTr9VcDj}fC* z4~Dcamx$pw(7zQ2`d1em$mm=lS-D|F5tF#7x14GXhIL9LsxU+4%)AmeoWfU(*O3XTSa^tCF1COFoH^mX3<>#vi< zntYyGf}}EFh64kspin~cya2cB(!pIRrmlpjFzV)XG;K*iOuq})bap<+YVwUJNIXsc zVc;Kdm63?#`kLtzRr>?b!IAtJ8M+o~5I0)P9O9v#%r*2CvaZPJ(Q1d-AFP!Ov5c6@A$~WQe@4gP;QBQM*GEnRu3wLZ>k9{T5U5I> zZc_Qtlcj`b?NC{z#FPtil+6u6OjI-~J>{y+-vv}QshqQExGRmsmUuR9A{`2XQMKEx zI^cI|TKTG+OUnr)FxF z*d}`8W4~1&FcWC?$ztI%-26r4vvn+M8gF3Hr z2*UlAFECqqrCclFB?O&<=SfqfyMqVw`WCB<)|o+7OtUmv&!%rc%)&srPtsnb*KG#T z>I<*RwbW3fQZM8D8}kfk!vjP}Kbzk-Iwo(Wzl#*l%);2+z)A#15izd3kyOM}+E-@D zy-{mGf0xrvzh;|5=Y91f2RU4N$aCvPB=e?t$adH~9aj|$d$ z!1?IR=>tKV_j*8^cB#x2p>@Z#AB%Er_fqrXqS+ndv0$}3(gN~ zYW5BUAAv6#qO;$v5DOQr6@_{sK9VwTU5Eu+!0K+>>50g;Q}ajLu)R_l8I`nn;;k|v zPj#MFK=>Sv;$j~}Hskf4kAzEczRWnU!rzpiD`hzZuG9%CIHv?gKa@w5FeDzosLBUX zTOXpfha9~FHdSo(2wx1UYosfja}sdSYf?J{3DO8p$F4?uWM;(M#II?%*|5>juyIdQ*rXne>Ul`VXcL# z^k9{HwtGahl1|*Z-M?qiraL-*DoV%hrRMCCmcee`-lGoT_LQw&I~Q4ZQbzn1BUO(< zwf(WB?Q@*mz8Ou&XOw7uvWAPM3c*BaCE429;ja))k_%sz@&wB8*DU6o!>4mm-ZK$i zf{$Yp;e7RRseCjqLJA)7N4n$+sLHId`C7P8Rb3<>E5h$#xx*(=l%6j=S2|hxP3fJ| z+u@s+;^`?CgO{NwvKT`W`0y}`2h#k?;-N(-jwPTdvG^>Dy;q>Poy9L$yu{*} zr6`_ev3N0xMJ#SWF52)q7N=M+HEnpsG8C7ym|*cZi{Il`%?8!Rp% zjOMU-oW)}-cC)yJ#W5E5qiBRzctFjSo*yrr951~yF3`*gBy$4AoIo%q(8~$rasst+ zfmlwUl@mzi1WMxqp`1V`Cy>brRB{55oIoQdkjM!X#sva7nSD-XJ}$E!ml@||w&OC> zahYXKW|))N@gZES_+~Cax3O5!KK?FCLDOKSH6R;`Vc){YvKlz{F#s-TUcUjzc zivJ02Fi1|}2E#EFZcwjKxY1{DBdiO8ELFs}Ont1t2MBYO`dF<#vg%{4`dF_%Hsa&v zv%{yK_Dx#Z< zqRhh~#0cHP`3erMF;HuyT4bC@X5E(b;*E>bEA;pD#+63QzMm$nSdgv$mk5*&98v8& zF9=^usMq{Ng{BHJS2t(LZ6D29J9B-zCp?bYoW-jnCcuGl;P_`~4}yl6;+XTUAK<3L z@aOpH!vVb46M$lX_q&98lYkeV#2X2qGgrWR_Ynu-HG+`g7x0k_uVqQ-Hu|&w1H=kp Av;Y7A literal 0 HcmV?d00001 diff --git a/f32-branch/.doctrees/lorax-composer.doctree b/f32-branch/.doctrees/lorax-composer.doctree new file mode 100644 index 0000000000000000000000000000000000000000..308d27ce4aeb949817833a6602ac50bc076de127 GIT binary patch literal 120079 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�{6GkU!&`Aqc~ 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 literal 0 HcmV?d00001 diff --git a/f32-branch/.doctrees/lorax.doctree b/f32-branch/.doctrees/lorax.doctree new file mode 100644 index 0000000000000000000000000000000000000000..13f54d4d3b3806afc4057c21cffad9efb33c19bd GIT binary patch literal 81951 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 O?mka{3Cpi+}repa;r literal 0 HcmV?d00001 diff --git a/f32-branch/.doctrees/mkksiso.doctree b/f32-branch/.doctrees/mkksiso.doctree new file mode 100644 index 0000000000000000000000000000000000000000..1e6abd11e620ce3ae8dda58e991a2db8c61756f3 GIT binary patch literal 28045 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 a29+f%6dzK>Ob{y$8CPM4XwJ`?wf_TI4k{V| literal 0 HcmV?d00001 diff --git a/f32-branch/.doctrees/modules.doctree b/f32-branch/.doctrees/modules.doctree new file mode 100644 index 0000000000000000000000000000000000000000..79e48e0ef5e4189008f62d74f27c617b5e2134b8 GIT binary patch literal 2521 zcmZ8jOK%%D5O!kgWm~f2G(99S+M)<*x3JX$JrunZMUMt_DjFa_K~PIdB)m&*`LLuz zfb`HJ26!v`xB8px39-Nu)8}5hRzyFQ)s$ZBeop~p7d#yC%Hilsm6kNIZ zPrUpyzK<7SWa!FjZ!#Xk9yBr`b7r`Tzelkb29{?|YSrnBp6H9g@9_egJttkxx3$Q;gC9KP%$E;~In8bjUnCtL297S%RumKQQXGjVVn6iT)Lu?=ZRq;S=qYMor-f!d=l0rI z7sEj=6^}Ph{T$~WX1XY~S8OY>I_Gd=OCi zJYV8@gXd)!G{KQ0%3x%b*~P4hY`KYl$64s-a^X0u-UsETIzARW97~nup7Di50?7PA z{3L!Bzwj_D=$i4;iFk8>^3k&D+$nOYB&PlZdKc01j zSs1Mx2M9v{H=27Cx@C-*%))5N6*tsrgGP-Q1$G@RN-U1*Fa*ADu{>;+-sD(~Q7Muz zn|2Ydm)gIH;cTI`Q`+&Z&6_7-oXCg9ko7{FB0@5;fJ;e$&_rSjm#=CG&v_*wE9nGj znS+RpK|>`ZZ+NMVBRRk0IUpYn1CRdjB9QE%!{5b&>FN%Gaf~oNQZG5Xl_5lUCOFJRwY4I?q!g%_#>h8^mQe zMlu%or_Hn&H)^DvFJV&hk{~C{2bER%9w*71B6I?F_*^(w+8?LW)oOKJZk*8STASsR z@w+KB?KFlL$s&177R2!aRd%TA5b~=x-+qs>Ow1yC6edX?!n|(7IIVG~N$wU^7~zT> zAx4hQfq$0f-!Pm5O$F(Q)g7PMGPUT#4NhtUI+E<>;CS zxfD5`>c-Fs-p96}Ak!Zn+_kWLUajjT$#q8S2_4QeK|vGrx8@W&mWB_3^{p>)m~>ND zQ@7zdMl>W+Ezs(g{AXz#SU=y@JLMSM41C-mmf+mM+lwsM^p@~~%ADY`GQ7G-KZbp- z?jpu-7}jF|yaS4)ViLG^#8I>47%RAOpCJ%X;qdu@+TgNDmvcDVk=FMx#PGK07X5^N zT;Y%plCXXk@5EahMoHi{C5rVvigzdgQE literal 0 HcmV?d00001 diff --git a/f32-branch/.doctrees/product-images.doctree b/f32-branch/.doctrees/product-images.doctree new file mode 100644 index 0000000000000000000000000000000000000000..2025b6c84d60976af7814d7ecdcb41059d3dc907 GIT binary patch literal 7155 zcmeHM&5s*N6`y=~CgaICUkoeqA!mE~|FAyX-2ayQ`_H z&e(^Q-~b|0NgQa-To4DunZJNDmzDN!;L4o?zgN|5dnTW|%3-z2XguS7_3FJ>@4H_A zruXOnT-ypievs+3b}F}{QfI<8{u}`cQM%?&&8^=ypEfuBuHi>k*CrK>-vUM|Rh}79 zHlH+d%kNl`I;G1MzU;|ux${YL6N^2kTrM`2{MC<)&g#@LUS{kURmPpL?8Ac3!JKws z)7eL2LF`|O`@1Fx2WFT3cEur%Yvjdx%6*?ZXVkO?;UNAQm05`Dcha0&3n0GtN?yco z=d!w5KTLUgXvBnTpP3nBU3@Jeo|3|NAt zx+usnM^dGd9jQF;JANnveyTyBgm7TSS*8r^uFW#Y6yy~EgFt1#9Gtj;qdXC8W^}=n zBXLB3y{)LNV^grCqXK=pWV#gHNh%nEe1f%7286z;OQ#AkY=I*Ov6(isw}NfyWRuCT zTdof0mi-Wa$%sFiOqkOw7>#k)ks2`)i!JWmz0ImB4S(+5$#E2DfzuK0-dU-~GUy8= z^dXyR(;wH?jID(4MPKNAU>r6-v)bBiyi%PC$0ObL+XJyw8m%3vA0k92XstCq%CuQsbB_ExuVIuA5R*~5@{cXH)~;rT||_19jKCSn;n@bA1Jk*uxuViYjHhgu}B zp?=C6sA}KF=Usfhi_d!~F7kWwZY$xz;|~y6ZaXw1 zoAQ?Y{)4k!Glb~69a}`%^Z!N}McHYKJ}M2&$=6SW3B8BYRo5AWI=8fFSy0B=l*%Rb1k7q+0mo`&&oT-!v=2-Hx>i7x@Tg{P zy7s;DT>CznOrGgtTYEjvNaJeR1$k$`_R2MmY9Ce0$t3FggD!E%D%|=G{6}w^)kd9u z^R%Ha^D5<1fiGW$)J51k&$YmRV~da5O?w@pEXh^b-QhZGbU8I9JIcK!@}er!yw2z< z7O#nY+}uiS3Iu5;Dp6*lOz9HRrA*3@wi2nDsdUZqNI4lo_C(J#nIKKa>muTq@@E@} z;oe2J-2xXoLwWmt@Pqr4Y8kE~Bf7qXyQ(mwkK>*0CvzpWQgoi3O1S!7Z)@ixx!_mf(^>CXn?{po6nxmvXx zhB#@&^R5biJGpxk$!|jmm_s#w(58fT5Y=FMM=J%AMkD{}cktwv6()JT$jk2mA{JGy zQstVb0pW<75?^<#<^2M~It=h0l5|n8_)a7pH*-CX@9ENK3 zbiKh}?c~P*X4s~+?kv2!My;^Iq@_!Kadgq}%}drUn4F=>T`M7GaWB4=t)_eO7M<#p zAEdRR$zsw@{T}-B9VCqQpcX5fgBN0QdTBLE#l(wx*{t!~zvOw1L1Q;dl>=yRE=n{? zn4OU-!vNHwr@_NsWRrmQAs+kfV{LLg?K_<&G@qnZu(1oK0gqkh~TlA`S;_LYY2kOEz(AH?(6@93G7`#*;~oPA|t? z)AuFMSC2h^Nh}m}<+!VDht%`E47q*|dIRz+idfJUyZ~g^8T8?FsOArTph~o932Kt2 zxQ6G}ZZ^C(v&PLc})J(H*@My?lh?T%CF1uBidabo2J3Hd)ih(y-{ zbX%_<^BpLrrKo5X6=O%wo%h(I3v`d zvINu9nOZb*+Yfl{bg~Bd(+VE7pVdW`th^3d4FCm)Gnf#PSuX?#R9jlI{TftRQD-_? z6y#4A5%d@oCYw8hi=-}jqO6Mkc_GP^< zNIQ~lSWOvIRKxdva0hA`m|1#)4MEmyu6Jyl)_B{YgqsC6(iJ&a>^eS$|7T7%56<}; z@TMYJ1=dRZ#G(-sNR8hN(xBfFhQ{=8TGCMlFW$q;lGP)k?xJ0yV_PIr&1H^HcrBpG zz0cbMqxnF{WTKNyu#td5_FT%`; zVX$JV^Of}j>NidRSJ=D9DDHM#!=}r}=p!u}M|t?*B&~L3%b!EAuh0hQpb;Z@O=ZK& cF^G0~71PJSdn<4-Nk5}B(?%qfzIr literal 0 HcmV?d00001 diff --git a/f32-branch/.doctrees/pylorax.api.doctree b/f32-branch/.doctrees/pylorax.api.doctree new file mode 100644 index 0000000000000000000000000000000000000000..1d999b391eea354cd24411bf6dbd6dc99e04ed81 GIT binary patch literal 960449 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

    dDvj&K!l|3SJ^H%EH9)lK46lEXK^ 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

    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for composer.cli

    +#
    +# composer-cli
    +#
    +# Copyright (C) 2018  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("composer-cli")
    +
    +from composer.cli.blueprints import blueprints_cmd
    +from composer.cli.modules import modules_cmd
    +from composer.cli.projects import projects_cmd
    +from composer.cli.compose import compose_cmd
    +from composer.cli.sources import sources_cmd
    +from composer.cli.status import status_cmd
    +from composer.cli.upload import upload_cmd
    +from composer.cli.providers import providers_cmd
    +
    +command_map = {
    +    "blueprints": blueprints_cmd,
    +    "modules":    modules_cmd,
    +    "projects":   projects_cmd,
    +    "compose":    compose_cmd,
    +    "sources":    sources_cmd,
    +    "status":     status_cmd,
    +    "upload":     upload_cmd,
    +    "providers":  providers_cmd
    +    }
    +
    +
    +
    [docs]def main(opts): + """ Main program execution + + :param opts: Cmdline arguments + :type opts: argparse.Namespace + """ + + # Making sure opts.args is not empty (thus, has a command and subcommand) + # is already handled in src/bin/composer-cli. + if opts.args[0] not in command_map: + log.error("Unknown command %s", opts.args[0]) + return 1 + else: + try: + return command_map[opts.args[0]](opts) + except Exception as e: + log.error(str(e)) + return 1
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/composer/cli/blueprints.html b/f32-branch/_modules/composer/cli/blueprints.html new file mode 100644 index 00000000..390a0422 --- /dev/null +++ b/f32-branch/_modules/composer/cli/blueprints.html @@ -0,0 +1,779 @@ + + + + + + + + + + + composer.cli.blueprints — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for composer.cli.blueprints

    +#
    +# Copyright (C) 2018  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("composer-cli")
    +
    +import os
    +
    +from composer import http_client as client
    +from composer.cli.help import blueprints_help
    +from composer.cli.utilities import argify, frozen_toml_filename, toml_filename, handle_api_result
    +from composer.cli.utilities import packageNEVRA
    +
    +
    [docs]def blueprints_cmd(opts): + """Process blueprints commands + + :param opts: Cmdline arguments + :type opts: argparse.Namespace + :returns: Value to return from sys.exit() + :rtype: int + + This dispatches the blueprints commands to a function + """ + cmd_map = { + "list": blueprints_list, + "show": blueprints_show, + "changes": blueprints_changes, + "diff": blueprints_diff, + "save": blueprints_save, + "delete": blueprints_delete, + "depsolve": blueprints_depsolve, + "push": blueprints_push, + "freeze": blueprints_freeze, + "tag": blueprints_tag, + "undo": blueprints_undo, + "workspace": blueprints_workspace + } + if opts.args[1] == "help" or opts.args[1] == "--help": + print(blueprints_help) + return 0 + elif opts.args[1] not in cmd_map: + log.error("Unknown blueprints command: %s", opts.args[1]) + return 1 + + return cmd_map[opts.args[1]](opts.socket, opts.api_version, opts.args[2:], opts.json)
    + +
    [docs]def blueprints_list(socket_path, api_version, args, show_json=False): + """Output the list of available blueprints + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + blueprints list + """ + api_route = client.api_url(api_version, "/blueprints/list") + result = client.get_url_json_unlimited(socket_path, api_route) + (rc, exit_now) = handle_api_result(result, show_json) + if exit_now: + return rc + + # "list" should output a plain list of identifiers, one per line. + print("\n".join(result["blueprints"])) + + return rc
    + +
    [docs]def blueprints_show(socket_path, api_version, args, show_json=False): + """Show the blueprints, in TOML format + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + blueprints show <blueprint,...> Display the blueprint in TOML format. + + Multiple blueprints will be separated by \n\n + """ + for blueprint in argify(args): + api_route = client.api_url(api_version, "/blueprints/info/%s?format=toml" % blueprint) + print(client.get_url_raw(socket_path, api_route) + "\n\n") + + return 0
    + +
    [docs]def blueprints_changes(socket_path, api_version, args, show_json=False): + """Display the changes for each of the blueprints + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + blueprints changes <blueprint,...> Display the changes for each blueprint. + """ + def changes_total_fn(data): + """Return the maximum number of possible changes""" + + # Each blueprint can have a different total, return the largest one + return max([c["total"] for c in data["blueprints"]]) + + api_route = client.api_url(api_version, "/blueprints/changes/%s" % (",".join(argify(args)))) + result = client.get_url_json_unlimited(socket_path, api_route, total_fn=changes_total_fn) + (rc, exit_now) = handle_api_result(result, show_json) + if exit_now: + return rc + + for blueprint in result["blueprints"]: + print(blueprint["name"]) + for change in blueprint["changes"]: + prettyCommitDetails(change) + + return rc
    + +
    [docs]def prettyCommitDetails(change, indent=4): + """Print the blueprint's change in a nice way + + :param change: The individual blueprint change dict + :type change: dict + :param indent: Number of spaces to indent + :type indent: int + """ + def revision(): + if change["revision"]: + return " revision %d" % change["revision"] + else: + return "" + + print(" " * indent + change["timestamp"] + " " + change["commit"] + revision()) + print(" " * indent + change["message"] + "\n")
    + +
    [docs]def blueprints_diff(socket_path, api_version, args, show_json=False): + """Display the differences between 2 versions of a blueprint + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + blueprints diff <blueprint-name> Display the differences between 2 versions of a blueprint. + <from-commit> Commit hash or NEWEST + <to-commit> Commit hash, NEWEST, or WORKSPACE + """ + if len(args) == 0: + log.error("blueprints diff is missing the blueprint name, from commit, and to commit") + return 1 + elif len(args) == 1: + log.error("blueprints diff is missing the from commit, and the to commit") + return 1 + elif len(args) == 2: + log.error("blueprints diff is missing the to commit") + return 1 + + api_route = client.api_url(api_version, "/blueprints/diff/%s/%s/%s" % (args[0], args[1], args[2])) + result = client.get_url_json(socket_path, api_route) + (rc, exit_now) = handle_api_result(result, show_json) + if exit_now: + return rc + + for diff in result["diff"]: + print(pretty_diff_entry(diff)) + + return rc
    + +
    [docs]def pretty_dict(d): + """Return the dict as a human readable single line + + :param d: key/values + :type d: dict + :returns: String of the dict's keys and values + :rtype: str + + key="str", key="str1,str2", ... + """ + result = [] + for k in d: + if type(d[k]) == type(""): + result.append('%s="%s"' % (k, d[k])) + elif type(d[k]) == type([]) and type(d[k][0]) == type(""): + result.append('%s="%s"' % (k, ", ".join(d[k]))) + elif type(d[k]) == type([]) and type(d[k][0]) == type({}): + result.append('%s="%s"' % (k, pretty_dict(d[k]))) + return " ".join(result)
    + +
    [docs]def dict_names(lst): + """Return comma-separated list of the dict's name/user fields + + :param d: key/values + :type d: dict + :returns: String of the dict's keys and values + :rtype: str + + root, norm + """ + if "user" in lst[0]: + field_name = "user" + elif "name" in lst[0]: + field_name = "name" + else: + # Use first fields in sorted keys + field_name = sorted(lst[0].keys())[0] + + return ", ".join(d[field_name] for d in lst)
    + +
    [docs]def pretty_diff_entry(diff): + """Generate nice diff entry string. + + :param diff: Difference entry dict + :type diff: dict + :returns: Nice string + """ + if diff["old"] and diff["new"]: + change = "Changed" + elif diff["new"] and not diff["old"]: + change = "Added" + elif diff["old"] and not diff["new"]: + change = "Removed" + else: + change = "Unknown" + + if diff["old"]: + name = list(diff["old"].keys())[0] + elif diff["new"]: + name = list(diff["new"].keys())[0] + else: + name = "Unknown" + + def details(diff): + if change == "Changed": + if type(diff["old"][name]) == type(""): + if name == "Description" or " " in diff["old"][name]: + return '"%s" -> "%s"' % (diff["old"][name], diff["new"][name]) + else: + return "%s -> %s" % (diff["old"][name], diff["new"][name]) + elif name in ["Module", "Package"]: + return "%s %s -> %s" % (diff["old"][name]["name"], diff["old"][name]["version"], + diff["new"][name]["version"]) + elif type(diff["old"][name]) == type([]): + if type(diff["old"][name][0]) == type(""): + return "%s -> %s" % (" ".join(diff["old"][name]), " ".join(diff["new"][name])) + elif type(diff["old"][name][0]) == type({}): + # Lists of dicts are too long to display in detail, just show their names + return "%s -> %s" % (dict_names(diff["old"][name]), dict_names(diff["new"][name])) + elif type(diff["old"][name]) == type({}): + return "%s -> %s" % (pretty_dict(diff["old"][name]), pretty_dict(diff["new"][name])) + else: + return "Unknown" + elif change == "Added": + if name in ["Module", "Package"]: + return "%s %s" % (diff["new"][name]["name"], diff["new"][name]["version"]) + elif name in ["Group"]: + return diff["new"][name]["name"] + elif type(diff["new"][name]) == type(""): + return diff["new"][name] + elif type(diff["new"][name]) == type([]): + if type(diff["new"][name][0]) == type(""): + return " ".join(diff["new"][name]) + elif type(diff["new"][name][0]) == type({}): + # Lists of dicts are too long to display in detail, just show their names + return dict_names(diff["new"][name]) + elif type(diff["new"][name]) == type({}): + return pretty_dict(diff["new"][name]) + else: + return "unknown/todo: %s" % type(diff["new"][name]) + elif change == "Removed": + if name in ["Module", "Package"]: + return "%s %s" % (diff["old"][name]["name"], diff["old"][name]["version"]) + elif name in ["Group"]: + return diff["old"][name]["name"] + elif type(diff["old"][name]) == type(""): + return diff["old"][name] + elif type(diff["old"][name]) == type([]): + if type(diff["old"][name][0]) == type(""): + return " ".join(diff["old"][name]) + elif type(diff["old"][name][0]) == type({}): + # Lists of dicts are too long to display in detail, just show their names + return dict_names(diff["old"][name]) + elif type(diff["old"][name]) == type({}): + return pretty_dict(diff["old"][name]) + else: + return "unknown/todo: %s" % type(diff["new"][name]) + + return change + " " + name + " " + details(diff)
    + +
    [docs]def blueprints_save(socket_path, api_version, args, show_json=False): + """Save the blueprint to a TOML file + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + blueprints save <blueprint,...> Save the blueprint to a file, <blueprint-name>.toml + """ + for blueprint in argify(args): + api_route = client.api_url(api_version, "/blueprints/info/%s?format=toml" % blueprint) + blueprint_toml = client.get_url_raw(socket_path, api_route) + open(toml_filename(blueprint), "w").write(blueprint_toml) + + return 0
    + +
    [docs]def blueprints_delete(socket_path, api_version, args, show_json=False): + """Delete a blueprint from the server + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + delete <blueprint> Delete a blueprint from the server + """ + api_route = client.api_url(api_version, "/blueprints/delete/%s" % args[0]) + result = client.delete_url_json(socket_path, api_route) + + return handle_api_result(result, show_json)[0]
    + +
    [docs]def blueprints_depsolve(socket_path, api_version, args, show_json=False): + """Display the packages needed to install the blueprint + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + blueprints depsolve <blueprint,...> Display the packages needed to install the blueprint. + """ + api_route = client.api_url(api_version, "/blueprints/depsolve/%s" % (",".join(argify(args)))) + result = client.get_url_json(socket_path, api_route) + (rc, exit_now) = handle_api_result(result, show_json) + if exit_now: + return rc + + for blueprint in result["blueprints"]: + if blueprint["blueprint"].get("version", ""): + print("blueprint: %s v%s" % (blueprint["blueprint"]["name"], blueprint["blueprint"]["version"])) + else: + print("blueprint: %s" % (blueprint["blueprint"]["name"])) + for dep in blueprint["dependencies"]: + print(" " + packageNEVRA(dep)) + + return rc
    + +
    [docs]def blueprints_push(socket_path, api_version, args, show_json=False): + """Push a blueprint TOML file to the server, updating the blueprint + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + push <blueprint> Push a blueprint TOML file to the server. + """ + api_route = client.api_url(api_version, "/blueprints/new") + rval = 0 + for blueprint in argify(args): + if not os.path.exists(blueprint): + log.error("Missing blueprint file: %s", blueprint) + continue + blueprint_toml = open(blueprint, "r").read() + + result = client.post_url_toml(socket_path, api_route, blueprint_toml) + if handle_api_result(result, show_json)[0]: + rval = 1 + + return rval
    + +
    [docs]def blueprints_freeze(socket_path, api_version, args, show_json=False): + """Handle the blueprints freeze commands + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + blueprints freeze <blueprint,...> Display the frozen blueprint's modules and packages. + blueprints freeze show <blueprint,...> Display the frozen blueprint in TOML format. + blueprints freeze save <blueprint,...> Save the frozen blueprint to a file, <blueprint-name>.frozen.toml. + """ + if args[0] == "show": + return blueprints_freeze_show(socket_path, api_version, args[1:], show_json) + elif args[0] == "save": + return blueprints_freeze_save(socket_path, api_version, args[1:], show_json) + + if len(args) == 0: + log.error("freeze is missing the blueprint name") + return 1 + + api_route = client.api_url(api_version, "/blueprints/freeze/%s" % (",".join(argify(args)))) + result = client.get_url_json(socket_path, api_route) + (rc, exit_now) = handle_api_result(result, show_json) + if exit_now: + return rc + + for entry in result["blueprints"]: + blueprint = entry["blueprint"] + if blueprint.get("version", ""): + print("blueprint: %s v%s" % (blueprint["name"], blueprint["version"])) + else: + print("blueprint: %s" % (blueprint["name"])) + + for m in blueprint["modules"]: + print(" %s-%s" % (m["name"], m["version"])) + + for p in blueprint["packages"]: + print(" %s-%s" % (p["name"], p["version"])) + + return rc
    + +
    [docs]def blueprints_freeze_show(socket_path, api_version, args, show_json=False): + """Show the frozen blueprint in TOML format + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + blueprints freeze show <blueprint,...> Display the frozen blueprint in TOML format. + """ + if len(args) == 0: + log.error("freeze show is missing the blueprint name") + return 1 + + for blueprint in argify(args): + api_route = client.api_url(api_version, "/blueprints/freeze/%s?format=toml" % blueprint) + print(client.get_url_raw(socket_path, api_route)) + + return 0
    + +
    [docs]def blueprints_freeze_save(socket_path, api_version, args, show_json=False): + """Save the frozen blueprint to a TOML file + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + blueprints freeze save <blueprint,...> Save the frozen blueprint to a file, <blueprint-name>.frozen.toml. + """ + if len(args) == 0: + log.error("freeze save is missing the blueprint name") + return 1 + + for blueprint in argify(args): + api_route = client.api_url(api_version, "/blueprints/freeze/%s?format=toml" % blueprint) + blueprint_toml = client.get_url_raw(socket_path, api_route) + open(frozen_toml_filename(blueprint), "w").write(blueprint_toml) + + return 0
    + +
    [docs]def blueprints_tag(socket_path, api_version, args, show_json=False): + """Tag the most recent blueprint commit as a release + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + blueprints tag <blueprint> Tag the most recent blueprint commit as a release. + """ + api_route = client.api_url(api_version, "/blueprints/tag/%s" % args[0]) + result = client.post_url(socket_path, api_route, "") + + return handle_api_result(result, show_json)[0]
    + +
    [docs]def blueprints_undo(socket_path, api_version, args, show_json=False): + """Undo changes to a blueprint + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + blueprints undo <blueprint> <commit> Undo changes to a blueprint by reverting to the selected commit. + """ + if len(args) == 0: + log.error("undo is missing the blueprint name and commit hash") + return 1 + elif len(args) == 1: + log.error("undo is missing commit hash") + return 1 + + api_route = client.api_url(api_version, "/blueprints/undo/%s/%s" % (args[0], args[1])) + result = client.post_url(socket_path, api_route, "") + + return handle_api_result(result, show_json)[0]
    + +
    [docs]def blueprints_workspace(socket_path, api_version, args, show_json=False): + """Push the blueprint TOML to the temporary workspace storage + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + blueprints workspace <blueprint> Push the blueprint TOML to the temporary workspace storage. + """ + api_route = client.api_url(api_version, "/blueprints/workspace") + rval = 0 + for blueprint in argify(args): + if not os.path.exists(blueprint): + log.error("Missing blueprint file: %s", blueprint) + continue + blueprint_toml = open(blueprint, "r").read() + + result = client.post_url_toml(socket_path, api_route, blueprint_toml) + if handle_api_result(result, show_json)[0]: + rval = 1 + + return rval
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/composer/cli/cmdline.html b/f32-branch/_modules/composer/cli/cmdline.html new file mode 100644 index 00000000..8d36728b --- /dev/null +++ b/f32-branch/_modules/composer/cli/cmdline.html @@ -0,0 +1,251 @@ + + + + + + + + + + + composer.cli.cmdline — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for composer.cli.cmdline

    +#
    +# Copyright (C) 2018 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import os
    +import sys
    +import argparse
    +
    +from composer import vernum
    +from composer.cli.help import epilog
    +
    +VERSION = "{0}-{1}".format(os.path.basename(sys.argv[0]), vernum)
    +
    +
    [docs]def composer_cli_parser(): + """ Return the ArgumentParser for composer-cli""" + + parser = argparse.ArgumentParser(description="Lorax Composer commandline tool", + epilog=epilog, + formatter_class=argparse.RawDescriptionHelpFormatter, + fromfile_prefix_chars="@") + + parser.add_argument("-j", "--json", action="store_true", default=False, + help="Output the raw JSON response instead of the normal output.") + parser.add_argument("-s", "--socket", default="/run/weldr/api.socket", metavar="SOCKET", + help="Path to the socket file to listen on") + parser.add_argument("--log", dest="logfile", default=None, metavar="LOG", + help="Path to logfile (./composer-cli.log)") + parser.add_argument("-a", "--api", dest="api_version", default="1", metavar="APIVER", + help="API Version to use") + parser.add_argument("--test", dest="testmode", default=0, type=int, metavar="TESTMODE", + help="Pass test mode to compose. 1=Mock compose with fail. 2=Mock compose with finished.") + parser.add_argument("-V", action="store_true", dest="showver", + help="show program's version number and exit") + + # Commands are implemented by parsing the remaining arguments outside of argparse + parser.add_argument('args', nargs=argparse.REMAINDER) + + return parser
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/composer/cli/compose.html b/f32-branch/_modules/composer/cli/compose.html new file mode 100644 index 00000000..bf5618a9 --- /dev/null +++ b/f32-branch/_modules/composer/cli/compose.html @@ -0,0 +1,889 @@ + + + + + + + + + + + composer.cli.compose — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for composer.cli.compose

    +#
    +# Copyright (C) 2018  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("composer-cli")
    +
    +from datetime import datetime
    +import sys
    +import json
    +import toml
    +
    +from composer import http_client as client
    +from composer.cli.help import compose_help
    +from composer.cli.utilities import argify, handle_api_result, packageNEVRA
    +
    +
    [docs]def compose_cmd(opts): + """Process compose commands + + :param opts: Cmdline arguments + :type opts: argparse.Namespace + :returns: Value to return from sys.exit() + :rtype: int + + This dispatches the compose commands to a function + + compose_cmd expects api to be passed. eg. + + {"version": 1, "backend": "lorax-composer"} + + """ + result = client.get_url_json(opts.socket, "/api/status") + # Get the api version and fall back to 0 if it fails. + api_version = result.get("api", "0") + backend = result.get("backend", "unknown") + api = {"version": api_version, "backend": backend} + + cmd_map = { + "list": compose_list, + "status": compose_status, + "types": compose_types, + "start": compose_start, + "log": compose_log, + "cancel": compose_cancel, + "delete": compose_delete, + "info": compose_info, + "metadata": compose_metadata, + "results": compose_results, + "logs": compose_logs, + "image": compose_image, + "start-ostree": compose_ostree, + } + if opts.args[1] == "help" or opts.args[1] == "--help": + print(compose_help) + return 0 + elif opts.args[1] not in cmd_map: + log.error("Unknown compose command: %s", opts.args[1]) + return 1 + + return cmd_map[opts.args[1]](opts.socket, opts.api_version, opts.args[2:], opts.json, opts.testmode, api=api)
    + +
    [docs]def get_size(args): + """Return optional size argument, and remaining args + + :param api: Details about the API server, "version" and "backend" + :type api: dict + :returns: (args, size) + :rtype: tuple + + - check size argument for int + - check other args for --size in wrong place + - raise error? Or just return 0? + - no size returns 0 in size + - multiply by 1024**2 to make it easier on users to specify large sizes + + """ + if len(args) == 0: + return (args, 0) + + if args[0] != "--size" and "--size" in args[1:]: + raise RuntimeError("--size must be first argument after the command") + if args[0] != "--size": + return (args, 0) + + if len(args) < 2: + raise RuntimeError("--size is missing the value, in MiB") + + # Let this raise an error for non-digit input + size = int(args[1]) + return (args[2:], size * 1024**2)
    + +
    [docs]def compose_list(socket_path, api_version, args, show_json=False, testmode=0, api=None): + """Return a simple list of compose identifiers""" + + states = ("running", "waiting", "finished", "failed") + + which = set() + + if any(a not in states for a in args): + # TODO: error about unknown state + return 1 + elif not args: + which.update(states) + else: + which.update(args) + + results = [] + + if "running" in which or "waiting" in which: + api_route = client.api_url(api_version, "/compose/queue") + r = client.get_url_json(socket_path, api_route) + if "running" in which: + results += r["run"] + if "waiting" in which: + results += r["new"] + + if "finished" in which: + api_route = client.api_url(api_version, "/compose/finished") + r = client.get_url_json(socket_path, api_route) + results += r["finished"] + + if "failed" in which: + api_route = client.api_url(api_version, "/compose/failed") + r = client.get_url_json(socket_path, api_route) + results += r["failed"] + + if results: + if show_json: + print(json.dumps(results, indent=4)) + else: + list_fmt = "{id} {queue_status} {blueprint} {version} {compose_type}" + print("\n".join(list_fmt.format(**c) for c in results)) + + return 0
    + +
    [docs]def compose_status(socket_path, api_version, args, show_json=False, testmode=0, api=None): + """Return the status of all known composes + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + This doesn't map directly to an API command, it combines the results from queue, finished, + and failed so raw JSON output is not available. + """ + def get_status(compose): + return {"id": compose["id"], + "blueprint": compose["blueprint"], + "version": compose["version"], + "compose_type": compose["compose_type"], + "image_size": compose["image_size"], + "status": compose["queue_status"], + "created": compose.get("job_created"), + "started": compose.get("job_started"), + "finished": compose.get("job_finished")} + + # Sort the status in a specific order + def sort_status(a): + order = ["RUNNING", "WAITING", "FINISHED", "FAILED"] + return (order.index(a["status"]), a["blueprint"], a["version"], a["compose_type"]) + + status = [] + + # Get the composes currently in the queue + api_route = client.api_url(api_version, "/compose/queue") + result = client.get_url_json(socket_path, api_route) + status.extend(list(map(get_status, result["run"] + result["new"]))) + + # Get the list of finished composes + api_route = client.api_url(api_version, "/compose/finished") + result = client.get_url_json(socket_path, api_route) + status.extend(list(map(get_status, result["finished"]))) + + # Get the list of failed composes + api_route = client.api_url(api_version, "/compose/failed") + result = client.get_url_json(socket_path, api_route) + status.extend(list(map(get_status, result["failed"]))) + + # Sort them by status (running, waiting, finished, failed) and then by name and version. + status.sort(key=sort_status) + + if show_json: + print(json.dumps(status, indent=4)) + return 0 + + # Print them as UUID blueprint STATUS + for c in status: + if c["image_size"] > 0: + image_size = str(c["image_size"]) + else: + image_size = "" + + dt = datetime.fromtimestamp(c.get("finished") or c.get("started") or c.get("created")) + + print("%s %-8s %s %-15s %s %-16s %s" % (c["id"], c["status"], dt.strftime("%c"), c["blueprint"], + c["version"], c["compose_type"], image_size))
    + + +
    [docs]def compose_types(socket_path, api_version, args, show_json=False, testmode=0, api=None): + """Return information about the supported compose types + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + Add additional details to types that are known to composer-cli. Raw JSON output does not + include this extra information. + """ + api_route = client.api_url(api_version, "/compose/types") + result = client.get_url_json(socket_path, api_route) + if show_json: + print(json.dumps(result, indent=4)) + return 0 + + # output a plain list of identifiers, one per line + print("\n".join(t["name"] for t in result["types"] if t["enabled"]))
    + +
    [docs]def compose_start(socket_path, api_version, args, show_json=False, testmode=0, api=None): + """Start a new compose using the selected blueprint and type + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: Set to 1 to simulate a failed compose, set to 2 to simulate a finished one. + :type testmode: int + :param api: Details about the API server, "version" and "backend" + :type api: dict + + compose start [--size XXX] <blueprint-name> <compose-type> [<image-name> <provider> <profile> | <image-name> <profile.toml>] + """ + if api == None: + log.error("Missing api version/backend") + return 1 + + # Get the optional size before checking other parameters + try: + args, size = get_size(args) + except (RuntimeError, ValueError) as e: + log.error(str(e)) + return 1 + + if len(args) == 0: + log.error("start is missing the blueprint name and output type") + return 1 + if len(args) == 1: + log.error("start is missing the output type") + return 1 + if len(args) == 3: + log.error("start is missing the provider and profile details") + return 1 + + config = { + "blueprint_name": args[0], + "compose_type": args[1], + "branch": "master" + } + if size > 0: + if api["backend"] == "lorax-composer": + log.warning("lorax-composer does not support --size, it will be ignored.") + else: + config["size"] = size + + if len(args) == 4: + config["upload"] = {"image_name": args[2]} + # profile TOML file (maybe) + try: + config["upload"].update(toml.load(args[3])) + except toml.TomlDecodeError as e: + log.error(str(e)) + return 1 + elif len(args) == 5: + config["upload"] = { + "image_name": args[2], + "provider": args[3], + "profile": args[4] + } + + if testmode: + test_url = "?test=%d" % testmode + else: + test_url = "" + api_route = client.api_url(api_version, "/compose" + test_url) + result = client.post_url_json(socket_path, api_route, json.dumps(config)) + (rc, exit_now) = handle_api_result(result, show_json) + if exit_now: + return rc + + print("Compose %s added to the queue" % result["build_id"]) + + if "upload_id" in result and result["upload_id"]: + print ("Upload %s added to the upload queue" % result["upload_id"]) + + return rc
    + +
    [docs]def compose_ostree(socket_path, api_version, args, show_json=False, testmode=0, api=None): + """Start a new compose using the selected blueprint and type + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: Set to 1 to simulate a failed compose, set to 2 to simulate a finished one. + :type testmode: int + :param api: Details about the API server, "version" and "backend" + :type api: dict + + compose start [--size XXX] <blueprint-name> <compose-type> <ostree-ref> <ostree-parent> [<image-name> <provider> <profile> | <image-name> <profile.toml>] + """ + if api == None: + log.error("Missing api version/backend") + return 1 + + if api["backend"] == "lorax-composer": + log.warning("lorax-composer doesn not support start-ostree.") + return 1 + + # Get the optional size before checking other parameters + try: + args, size = get_size(args) + except (RuntimeError, ValueError) as e: + log.error(str(e)) + return 1 + + if len(args) == 0: + log.error("start-ostree is missing the blueprint name, output type, and ostree details") + return 1 + if len(args) == 1: + log.error("start-ostree is missing the output type") + return 1 + if len(args) == 2: + log.error("start-ostree is missing the ostree reference") + return 1 + if len(args) == 3: + log.error("start-ostree is missing the ostree parent") + return 1 + if len(args) == 5: + log.error("start-ostree is missing the provider and profile details") + return 1 + + config = { + "blueprint_name": args[0], + "compose_type": args[1], + "branch": "master", + "ostree": {"ref": args[2], "parent": args[3]}, + } + if size > 0: + config["size"] = size + + if len(args) == 6: + config["upload"] = {"image_name": args[4]} + # profile TOML file (maybe) + try: + config["upload"].update(toml.load(args[5])) + except toml.TomlDecodeError as e: + log.error(str(e)) + return 1 + elif len(args) == 7: + config["upload"] = { + "image_name": args[4], + "provider": args[5], + "profile": args[6] + } + + if testmode: + test_url = "?test=%d" % testmode + else: + test_url = "" + api_route = client.api_url(api_version, "/compose" + test_url) + result = client.post_url_json(socket_path, api_route, json.dumps(config)) + (rc, exit_now) = handle_api_result(result, show_json) + if exit_now: + return rc + + print("Compose %s added to the queue" % result["build_id"]) + + if "upload_id" in result and result["upload_id"]: + print ("Upload %s added to the upload queue" % result["upload_id"]) + + return rc
    + +
    [docs]def compose_log(socket_path, api_version, args, show_json=False, testmode=0, api=None): + """Show the last part of the compose log + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + compose log <uuid> [<size>kB] + + This will display the last 1kB of the compose's log file. Can be used to follow progress + during the build. + """ + if len(args) == 0: + log.error("log is missing the compose build id") + return 1 + if len(args) == 2: + try: + log_size = int(args[1]) + except ValueError: + log.error("Log size must be an integer.") + return 1 + else: + log_size = 1024 + + api_route = client.api_url(api_version, "/compose/log/%s?size=%d" % (args[0], log_size)) + try: + result = client.get_url_raw(socket_path, api_route) + except RuntimeError as e: + print(str(e)) + return 1 + + print(result) + return 0
    + +
    [docs]def compose_cancel(socket_path, api_version, args, show_json=False, testmode=0, api=None): + """Cancel a running compose + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + compose cancel <uuid> + + This will cancel a running compose. It does nothing if the compose has finished. + """ + if len(args) == 0: + log.error("cancel is missing the compose build id") + return 1 + + api_route = client.api_url(api_version, "/compose/cancel/%s" % args[0]) + result = client.delete_url_json(socket_path, api_route) + return handle_api_result(result, show_json)[0]
    + +
    [docs]def compose_delete(socket_path, api_version, args, show_json=False, testmode=0, api=None): + """Delete a finished compose's results + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + compose delete <uuid,...> + + Delete the listed compose results. It will only delete results for composes that have finished + or failed, not a running compose. + """ + if len(args) == 0: + log.error("delete is missing the compose build id") + return 1 + + api_route = client.api_url(api_version, "/compose/delete/%s" % (",".join(argify(args)))) + result = client.delete_url_json(socket_path, api_route) + return handle_api_result(result, show_json)[0]
    + +
    [docs]def compose_info(socket_path, api_version, args, show_json=False, testmode=0, api=None): + """Return detailed information about the compose + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + compose info <uuid> + + This returns information about the compose, including the blueprint and the dependencies. + """ + if len(args) == 0: + log.error("info is missing the compose build id") + return 1 + + api_route = client.api_url(api_version, "/compose/info/%s" % args[0]) + result = client.get_url_json(socket_path, api_route) + (rc, exit_now) = handle_api_result(result, show_json) + if exit_now: + return rc + + if result["image_size"] > 0: + image_size = str(result["image_size"]) + else: + image_size = "" + + + print("%s %-8s %-15s %s %-16s %s" % (result["id"], + result["queue_status"], + result["blueprint"]["name"], + result["blueprint"]["version"], + result["compose_type"], + image_size)) + print("Packages:") + for p in result["blueprint"]["packages"]: + print(" %s-%s" % (p["name"], p["version"])) + + print("Modules:") + for m in result["blueprint"]["modules"]: + print(" %s-%s" % (m["name"], m["version"])) + + print("Dependencies:") + for d in result["deps"]["packages"]: + print(" " + packageNEVRA(d)) + + return rc
    + +
    [docs]def compose_metadata(socket_path, api_version, args, show_json=False, testmode=0, api=None): + """Download a tar file of the compose's metadata + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + compose metadata <uuid> + + Saves the metadata as uuid-metadata.tar + """ + if len(args) == 0: + log.error("metadata is missing the compose build id") + return 1 + + api_route = client.api_url(api_version, "/compose/metadata/%s" % args[0]) + try: + rc = client.download_file(socket_path, api_route) + except RuntimeError as e: + print(str(e)) + rc = 1 + + return rc
    + +
    [docs]def compose_results(socket_path, api_version, args, show_json=False, testmode=0, api=None): + """Download a tar file of the compose's results + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + compose results <uuid> + + The results includes the metadata, output image, and logs. + It is saved as uuid.tar + """ + if len(args) == 0: + log.error("results is missing the compose build id") + return 1 + + api_route = client.api_url(api_version, "/compose/results/%s" % args[0]) + try: + rc = client.download_file(socket_path, api_route, sys.stdout.isatty()) + except RuntimeError as e: + print(str(e)) + rc = 1 + + return rc
    + +
    [docs]def compose_logs(socket_path, api_version, args, show_json=False, testmode=0, api=None): + """Download a tar of the compose's logs + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + compose logs <uuid> + + Saves the logs as uuid-logs.tar + """ + if len(args) == 0: + log.error("logs is missing the compose build id") + return 1 + + api_route = client.api_url(api_version, "/compose/logs/%s" % args[0]) + try: + rc = client.download_file(socket_path, api_route, sys.stdout.isatty()) + except RuntimeError as e: + print(str(e)) + rc = 1 + + return rc
    + +
    [docs]def compose_image(socket_path, api_version, args, show_json=False, testmode=0, api=None): + """Download the compose's output image + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + compose image <uuid> + + This downloads only the result image, saving it as the image name, which depends on the type + of compose that was selected. + """ + if len(args) == 0: + log.error("logs is missing the compose build id") + return 1 + + api_route = client.api_url(api_version, "/compose/image/%s" % args[0]) + try: + rc = client.download_file(socket_path, api_route, sys.stdout.isatty()) + except RuntimeError as e: + print(str(e)) + rc = 1 + + return rc
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/composer/cli/modules.html b/f32-branch/_modules/composer/cli/modules.html new file mode 100644 index 00000000..f3e33a48 --- /dev/null +++ b/f32-branch/_modules/composer/cli/modules.html @@ -0,0 +1,249 @@ + + + + + + + + + + + composer.cli.modules — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for composer.cli.modules

    +#
    +# Copyright (C) 2018  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("composer-cli")
    +
    +from composer import http_client as client
    +from composer.cli.help import modules_help
    +from composer.cli.utilities import handle_api_result
    +
    +
    [docs]def modules_cmd(opts): + """Process modules commands + + :param opts: Cmdline arguments + :type opts: argparse.Namespace + :returns: Value to return from sys.exit() + :rtype: int + """ + if opts.args[1] == "help" or opts.args[1] == "--help": + print(modules_help) + return 0 + elif opts.args[1] != "list": + log.error("Unknown modules command: %s", opts.args[1]) + return 1 + + api_route = client.api_url(opts.api_version, "/modules/list") + result = client.get_url_json_unlimited(opts.socket, api_route) + (rc, exit_now) = handle_api_result(result, opts.json) + if exit_now: + return rc + + # "list" should output a plain list of identifiers, one per line. + print("\n".join(r["name"] for r in result["modules"])) + + return rc
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/composer/cli/projects.html b/f32-branch/_modules/composer/cli/projects.html new file mode 100644 index 00000000..7c57f1e8 --- /dev/null +++ b/f32-branch/_modules/composer/cli/projects.html @@ -0,0 +1,311 @@ + + + + + + + + + + + composer.cli.projects — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for composer.cli.projects

    +#
    +# Copyright (C) 2018  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("composer-cli")
    +
    +import textwrap
    +
    +from composer import http_client as client
    +from composer.cli.help import projects_help
    +from composer.cli.utilities import handle_api_result
    +
    +
    [docs]def projects_cmd(opts): + """Process projects commands + + :param opts: Cmdline arguments + :type opts: argparse.Namespace + :returns: Value to return from sys.exit() + :rtype: int + """ + cmd_map = { + "list": projects_list, + "info": projects_info, + } + if opts.args[1] == "help" or opts.args[1] == "--help": + print(projects_help) + return 0 + elif opts.args[1] not in cmd_map: + log.error("Unknown projects command: %s", opts.args[1]) + return 1 + + return cmd_map[opts.args[1]](opts.socket, opts.api_version, opts.args[2:], opts.json)
    + +
    [docs]def projects_list(socket_path, api_version, args, show_json=False): + """Output the list of available projects + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + projects list + """ + api_route = client.api_url(api_version, "/projects/list") + result = client.get_url_json_unlimited(socket_path, api_route) + (rc, exit_now) = handle_api_result(result, show_json) + if exit_now: + return rc + + for proj in result["projects"]: + for k in [field for field in ("name", "summary", "homepage", "description") if proj[field]]: + print("%s: %s" % (k.title(), textwrap.fill(proj[k], subsequent_indent=" " * (len(k)+2)))) + print("\n\n") + + return rc
    + +
    [docs]def projects_info(socket_path, api_version, args, show_json=False): + """Output info on a list of projects + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + projects info <project,...> + """ + if len(args) == 0: + log.error("projects info is missing the packages") + return 1 + + api_route = client.api_url(api_version, "/projects/info/%s" % ",".join(args)) + result = client.get_url_json(socket_path, api_route) + (rc, exit_now) = handle_api_result(result, show_json) + if exit_now: + return rc + + for proj in result["projects"]: + for k in [field for field in ("name", "summary", "homepage", "description") if proj[field]]: + print("%s: %s" % (k.title(), textwrap.fill(proj[k], subsequent_indent=" " * (len(k)+2)))) + print("Builds: ") + for build in proj["builds"]: + print(" %s%s-%s.%s at %s for %s" % ("" if not build["epoch"] else str(build["epoch"]) + ":", + build["source"]["version"], + build["release"], + build["arch"], + build["build_time"], + build["changelog"])) + print("") + return rc
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/composer/cli/providers.html b/f32-branch/_modules/composer/cli/providers.html new file mode 100644 index 00000000..c7edc494 --- /dev/null +++ b/f32-branch/_modules/composer/cli/providers.html @@ -0,0 +1,523 @@ + + + + + + + + + + + composer.cli.providers — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for composer.cli.providers

    +#
    +# Copyright (C) 2019  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("composer-cli")
    +
    +import json
    +import toml
    +import os
    +
    +from composer import http_client as client
    +from composer.cli.help import providers_help
    +from composer.cli.utilities import handle_api_result, toml_filename
    +
    +
    [docs]def providers_cmd(opts): + """Process providers commands + + :param opts: Cmdline arguments + :type opts: argparse.Namespace + :returns: Value to return from sys.exit() + :rtype: int + + This dispatches the providers commands to a function + """ + cmd_map = { + "list": providers_list, + "info": providers_info, + "show": providers_show, + "push": providers_push, + "save": providers_save, + "delete": providers_delete, + "template": providers_template + } + if opts.args[1] == "help" or opts.args[1] == "--help": + print(providers_help) + return 0 + elif opts.args[1] not in cmd_map: + log.error("Unknown providers command: %s", opts.args[1]) + return 1 + + return cmd_map[opts.args[1]](opts.socket, opts.api_version, opts.args[2:], opts.json, opts.testmode)
    + +
    [docs]def providers_list(socket_path, api_version, args, show_json=False, testmode=0): + """Return the list of providers + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + providers list + """ + api_route = client.api_url(api_version, "/upload/providers") + r = client.get_url_json(socket_path, api_route) + results = r["providers"] + if not results: + return 0 + + if show_json: + print(json.dumps(results, indent=4)) + else: + if len(args) == 1: + if args[0] not in results: + log.error("%s is not a valid provider", args[0]) + return 1 + print("\n".join(sorted(results[args[0]]["profiles"].keys()))) + else: + print("\n".join(sorted(results.keys()))) + + return 0
    + +
    [docs]def providers_info(socket_path, api_version, args, show_json=False, testmode=0): + """Show information about each provider + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + providers info <PROVIDER> + """ + if len(args) == 0: + log.error("info is missing the provider name") + return 1 + + api_route = client.api_url(api_version, "/upload/providers") + r = client.get_url_json(socket_path, api_route) + results = r["providers"] + if not results: + return 0 + + if show_json: + print(json.dumps(results, indent=4)) + else: + if args[0] not in results: + log.error("%s is not a valid provider", args[0]) + return 1 + p = results[args[0]] + print("%s supports these image types: %s" % (p["display"], ", ".join(p["supported_types"]))) + print("Settings:") + for k in p["settings-info"]: + f = p["settings-info"][k] + print(" %-20s: %s is a %s" % (k, f["display"], f["type"])) + + return 0
    + +
    [docs]def providers_show(socket_path, api_version, args, show_json=False, testmode=0): + """Return details about a provider + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + providers show <provider> <profile> + """ + if len(args) == 0: + log.error("show is missing the provider name") + return 1 + if len(args) == 1: + log.error("show is missing the profile name") + return 1 + + api_route = client.api_url(api_version, "/upload/providers") + r = client.get_url_json(socket_path, api_route) + results = r["providers"] + if not results: + return 0 + + if show_json: + print(json.dumps(results, indent=4)) + else: + if args[0] not in results: + log.error("%s is not a valid provider", args[0]) + return 1 + if args[1] not in results[args[0]]["profiles"]: + log.error("%s is not a valid %s profile", args[1], args[0]) + return 1 + + # Print the details for this profile + # fields are different for each provider, so we just print out the key:values + for k in results[args[0]]["profiles"][args[1]]: + print("%s: %s" % (k, results[args[0]]["profiles"][args[1]][k])) + return 0
    + +
    [docs]def providers_push(socket_path, api_version, args, show_json=False, testmode=0): + """Add a new provider profile or overwrite an existing one + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + providers push <profile.toml> + + """ + if len(args) == 0: + log.error("push is missing the profile TOML file") + return 1 + if not os.path.exists(args[0]): + log.error("Missing profile TOML file: %s", args[0]) + return 1 + + api_route = client.api_url(api_version, "/upload/providers/save") + profile = toml.load(args[0]) + result = client.post_url_json(socket_path, api_route, json.dumps(profile)) + return handle_api_result(result, show_json)[0]
    + +
    [docs]def providers_save(socket_path, api_version, args, show_json=False, testmode=0): + """Save a provider's profile to a TOML file + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + providers save <provider> <profile> + + """ + if len(args) == 0: + log.error("save is missing the provider name") + return 1 + if len(args) == 1: + log.error("save is missing the profile name") + return 1 + + api_route = client.api_url(api_version, "/upload/providers") + r = client.get_url_json(socket_path, api_route) + results = r["providers"] + if not results: + return 0 + + if show_json: + print(json.dumps(results, indent=4)) + else: + if args[0] not in results: + log.error("%s is not a valid provider", args[0]) + return 1 + if args[1] not in results[args[0]]["profiles"]: + log.error("%s is not a valid %s profile", args[1], args[0]) + return 1 + + profile = { + "provider": args[0], + "profile": args[1], + "settings": results[args[0]]["profiles"][args[1]] + } + open(toml_filename(args[1]), "w").write(toml.dumps(profile)) + + return 0
    + +
    [docs]def providers_delete(socket_path, api_version, args, show_json=False, testmode=0): + """Delete a profile from a provider + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + providers delete <provider> <profile> + + """ + if len(args) == 0: + log.error("delete is missing the provider name") + return 1 + if len(args) == 1: + log.error("delete is missing the profile name") + return 1 + + api_route = client.api_url(api_version, "/upload/providers/delete/%s/%s" % (args[0], args[1])) + result = client.delete_url_json(socket_path, api_route) + return handle_api_result(result, show_json)[0]
    + +
    [docs]def providers_template(socket_path, api_version, args, show_json=False, testmode=0): + """Return a TOML template for setting the provider's fields + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + providers template <provider> + """ + if len(args) == 0: + log.error("template is missing the provider name") + return 1 + + api_route = client.api_url(api_version, "/upload/providers") + r = client.get_url_json(socket_path, api_route) + results = r["providers"] + if not results: + return 0 + + if show_json: + print(json.dumps(results, indent=4)) + return 0 + + if args[0] not in results: + log.error("%s is not a valid provider", args[0]) + return 1 + + template = {"provider": args[0]} + settings = results[args[0]]["settings-info"] + template["settings"] = dict([(k, settings[k]["display"]) for k in settings]) + print(toml.dumps(template)) + + return 0
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/composer/cli/sources.html b/f32-branch/_modules/composer/cli/sources.html new file mode 100644 index 00000000..6d1065a9 --- /dev/null +++ b/f32-branch/_modules/composer/cli/sources.html @@ -0,0 +1,353 @@ + + + + + + + + + + + composer.cli.sources — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for composer.cli.sources

    +#
    +# Copyright (C) 2018  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("composer-cli")
    +
    +import os
    +
    +from composer import http_client as client
    +from composer.cli.help import sources_help
    +from composer.cli.utilities import argify, handle_api_result
    +
    +
    [docs]def sources_cmd(opts): + """Process sources commands + + :param opts: Cmdline arguments + :type opts: argparse.Namespace + :returns: Value to return from sys.exit() + :rtype: int + """ + cmd_map = { + "list": sources_list, + "info": sources_info, + "add": sources_add, + "change": sources_add, + "delete": sources_delete, + } + if opts.args[1] == "help" or opts.args[1] == "--help": + print(sources_help) + return 0 + elif opts.args[1] not in cmd_map: + log.error("Unknown sources command: %s", opts.args[1]) + return 1 + + return cmd_map[opts.args[1]](opts.socket, opts.api_version, opts.args[2:], opts.json)
    + +
    [docs]def sources_list(socket_path, api_version, args, show_json=False): + """Output the list of available sources + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + sources list + """ + api_route = client.api_url(api_version, "/projects/source/list") + result = client.get_url_json(socket_path, api_route) + (rc, exit_now) = handle_api_result(result, show_json) + if exit_now: + return rc + + # "list" should output a plain list of identifiers, one per line. + print("\n".join(result["sources"])) + return rc
    + +
    [docs]def sources_info(socket_path, api_version, args, show_json=False): + """Output info on a list of projects + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + sources info <source-name> + """ + if len(args) == 0: + log.error("sources info is missing the name of the source") + return 1 + + if show_json: + api_route = client.api_url(api_version, "/projects/source/info/%s" % ",".join(args)) + result = client.get_url_json(socket_path, api_route) + rc = handle_api_result(result, show_json)[0] + else: + api_route = client.api_url(api_version, "/projects/source/info/%s?format=toml" % ",".join(args)) + try: + result = client.get_url_raw(socket_path, api_route) + print(result) + rc = 0 + except RuntimeError as e: + print(str(e)) + rc = 1 + + return rc
    + +
    [docs]def sources_add(socket_path, api_version, args, show_json=False): + """Add or change a source + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + sources add <source.toml> + """ + api_route = client.api_url(api_version, "/projects/source/new") + rval = 0 + for source in argify(args): + if not os.path.exists(source): + log.error("Missing source file: %s", source) + continue + source_toml = open(source, "r").read() + + result = client.post_url_toml(socket_path, api_route, source_toml) + if handle_api_result(result, show_json)[0]: + rval = 1 + return rval
    + +
    [docs]def sources_delete(socket_path, api_version, args, show_json=False): + """Delete a source + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + + sources delete <source-name> + """ + api_route = client.api_url(api_version, "/projects/source/delete/%s" % args[0]) + result = client.delete_url_json(socket_path, api_route) + + return handle_api_result(result, show_json)[0]
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/composer/cli/status.html b/f32-branch/_modules/composer/cli/status.html new file mode 100644 index 00000000..f7c57edb --- /dev/null +++ b/f32-branch/_modules/composer/cli/status.html @@ -0,0 +1,257 @@ + + + + + + + + + + + composer.cli.status — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for composer.cli.status

    +#
    +# Copyright (C) 2018  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("composer-cli")
    +
    +from composer import http_client as client
    +from composer.cli.help import status_help
    +from composer.cli.utilities import handle_api_result
    +
    +
    [docs]def status_cmd(opts): + """Process status commands + + :param opts: Cmdline arguments + :type opts: argparse.Namespace + :returns: Value to return from sys.exit() + :rtype: int + """ + if opts.args[1] == "help" or opts.args[1] == "--help": + print(status_help) + return 0 + elif opts.args[1] != "show": + log.error("Unknown status command: %s", opts.args[1]) + return 1 + + result = client.get_url_json(opts.socket, "/api/status") + (rc, exit_now) = handle_api_result(result, opts.json) + if exit_now: + return rc + + print("API server status:") + print(" Database version: " + result["db_version"]) + print(" Database supported: %s" % result["db_supported"]) + print(" Schema version: " + result["schema_version"]) + print(" API version: " + result["api"]) + print(" Backend: " + result["backend"]) + print(" Build: " + result["build"]) + + if result["msgs"]: + print("Error messages:") + print("\n".join([" " + r for r in result["msgs"]])) + + return rc
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/composer/cli/upload.html b/f32-branch/_modules/composer/cli/upload.html new file mode 100644 index 00000000..93088b68 --- /dev/null +++ b/f32-branch/_modules/composer/cli/upload.html @@ -0,0 +1,478 @@ + + + + + + + + + + + composer.cli.upload — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for composer.cli.upload

    +#
    +# Copyright (C) 2019  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("composer-cli")
    +
    +import json
    +import toml
    +import os
    +
    +from composer import http_client as client
    +from composer.cli.help import upload_help
    +from composer.cli.utilities import handle_api_result
    +
    +
    [docs]def upload_cmd(opts): + """Process upload commands + + :param opts: Cmdline arguments + :type opts: argparse.Namespace + :returns: Value to return from sys.exit() + :rtype: int + + This dispatches the upload commands to a function + """ + cmd_map = { + "list": upload_list, + "info": upload_info, + "start": upload_start, + "log": upload_log, + "cancel": upload_cancel, + "delete": upload_delete, + "reset": upload_reset, + } + if opts.args[1] == "help" or opts.args[1] == "--help": + print(upload_help) + return 0 + elif opts.args[1] not in cmd_map: + log.error("Unknown upload command: %s", opts.args[1]) + return 1 + + return cmd_map[opts.args[1]](opts.socket, opts.api_version, opts.args[2:], opts.json, opts.testmode)
    + +
    [docs]def upload_list(socket_path, api_version, args, show_json=False, testmode=0): + """Return the composes and their associated upload uuids and status + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + upload list + """ + api_route = client.api_url(api_version, "/compose/finished") + r = client.get_url_json(socket_path, api_route) + results = r["finished"] + if not results: + return 0 + + if show_json: + print(json.dumps(results, indent=4)) + else: + compose_fmt = "{id} {queue_status} {blueprint} {version} {compose_type}" + upload_fmt = ' {uuid} "{image_name}" {provider_name} {status}' + for c in results: + print(compose_fmt.format(**c)) + print("\n".join(upload_fmt.format(**u) for u in c["uploads"])) + print() + + return 0
    + +
    [docs]def upload_info(socket_path, api_version, args, show_json=False, testmode=0): + """Return detailed information about the upload + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + upload info <uuid> + + This returns information about the upload, including uuid, name, status, service, and image. + """ + if len(args) == 0: + log.error("info is missing the upload uuid") + return 1 + + api_route = client.api_url(api_version, "/upload/info/%s" % args[0]) + result = client.get_url_json(socket_path, api_route) + (rc, exit_now) = handle_api_result(result, show_json) + if exit_now: + return rc + + image_path = result["upload"]["image_path"] + print("%s %-8s %-15s %-8s %s" % (result["upload"]["uuid"], + result["upload"]["status"], + result["upload"]["image_name"], + result["upload"]["provider_name"], + os.path.basename(image_path) if image_path else "UNFINISHED")) + + return rc
    + +
    [docs]def upload_start(socket_path, api_version, args, show_json=False, testmode=0): + """Start upload up a build uuid image + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + upload start <build-uuid> <image-name> [<provider> <profile> | <profile.toml>] + """ + if len(args) == 0: + log.error("start is missing the compose build id") + return 1 + if len(args) == 1: + log.error("start is missing the image name") + return 1 + if len(args) == 2: + log.error("start is missing the provider and profile details") + return 1 + + body = {"image_name": args[1]} + if len(args) == 3: + try: + body.update(toml.load(args[2])) + except toml.TomlDecodeError as e: + log.error(str(e)) + return 1 + elif len(args) == 4: + body["provider"] = args[2] + body["profile"] = args[3] + else: + log.error("start has incorrect number of arguments") + return 1 + + api_route = client.api_url(api_version, "/compose/uploads/schedule/%s" % args[0]) + result = client.post_url_json(socket_path, api_route, json.dumps(body)) + (rc, exit_now) = handle_api_result(result, show_json) + if exit_now: + return rc + + print("Upload %s added to the queue" % result["upload_id"]) + return rc
    + +
    [docs]def upload_log(socket_path, api_version, args, show_json=False, testmode=0): + """Return the upload log + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + upload log <build-uuid> + """ + if len(args) == 0: + log.error("log is missing the upload uuid") + return 1 + + api_route = client.api_url(api_version, "/upload/log/%s" % args[0]) + result = client.get_url_json(socket_path, api_route) + (rc, exit_now) = handle_api_result(result, show_json) + if exit_now: + return rc + + print("Upload log for %s:\n" % result["upload_id"]) + print(result["log"]) + + return 0
    + +
    [docs]def upload_cancel(socket_path, api_version, args, show_json=False, testmode=0): + """Cancel the queued or running upload + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + upload cancel <build-uuid> + """ + if len(args) == 0: + log.error("cancel is missing the upload uuid") + return 1 + + api_route = client.api_url(api_version, "/upload/cancel/%s" % args[0]) + result = client.delete_url_json(socket_path, api_route) + return handle_api_result(result, show_json)[0]
    + +
    [docs]def upload_delete(socket_path, api_version, args, show_json=False, testmode=0): + """Delete an upload and remove it from the build + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + upload delete <build-uuid> + """ + if len(args) == 0: + log.error("delete is missing the upload uuid") + return 1 + + api_route = client.api_url(api_version, "/upload/delete/%s" % args[0]) + result = client.delete_url_json(socket_path, api_route) + return handle_api_result(result, show_json)[0]
    + +
    [docs]def upload_reset(socket_path, api_version, args, show_json=False, testmode=0): + """Reset the upload and execute it again + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param api_version: Version of the API to talk to. eg. "0" + :type api_version: str + :param args: List of remaining arguments from the cmdline + :type args: list of str + :param show_json: Set to True to show the JSON output instead of the human readable output + :type show_json: bool + :param testmode: unused in this function + :type testmode: int + + upload reset <build-uuid> + """ + if len(args) == 0: + log.error("reset is missing the upload uuid") + return 1 + + api_route = client.api_url(api_version, "/upload/reset/%s" % args[0]) + result = client.post_url_json(socket_path, api_route, json.dumps({})) + return handle_api_result(result, show_json)[0]
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/composer/cli/utilities.html b/f32-branch/_modules/composer/cli/utilities.html new file mode 100644 index 00000000..8ff39ae8 --- /dev/null +++ b/f32-branch/_modules/composer/cli/utilities.html @@ -0,0 +1,296 @@ + + + + + + + + + + + composer.cli.utilities — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for composer.cli.utilities

    +#
    +# Copyright (C) 2018  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("composer-cli")
    +
    +import json
    +
    +
    [docs]def argify(args): + """Take a list of human args and return a list with each item + + :param args: list of strings with possible commas and spaces + :type args: list of str + :returns: List of all the items + :rtype: list of str + + Examples: + + ["one,two", "three", ",four", ",five,"] returns ["one", "two", "three", "four", "five"] + """ + return [i for i in [arg for entry in args for arg in entry.split(",")] if i]
    + +
    [docs]def toml_filename(blueprint_name): + """Convert a blueprint name into a filename.toml + + :param blueprint_name: The blueprint's name + :type blueprint_name: str + :returns: The blueprint name with ' ' converted to - and .toml appended + :rtype: str + """ + return blueprint_name.replace(" ", "-") + ".toml"
    + +
    [docs]def frozen_toml_filename(blueprint_name): + """Convert a blueprint name into a filename.toml + + :param blueprint_name: The blueprint's name + :type blueprint_name: str + :returns: The blueprint name with ' ' converted to - and .toml appended + :rtype: str + """ + return blueprint_name.replace(" ", "-") + ".frozen.toml"
    + +
    [docs]def handle_api_result(result, show_json=False): + """Log any errors, return the correct value + + :param result: JSON result from the http query + :type result: dict + :rtype: tuple + :returns: (rc, should_exit_now) + + Return the correct rc for the program (0 or 1), and whether or + not to continue processing the results. + """ + if show_json: + print(json.dumps(result, indent=4)) + else: + for err in result.get("errors", []): + log.error(err["msg"]) + + # What's the rc? If status is present, use that + # If not, use length of errors + if "status" in result: + rc = int(not result["status"]) + else: + rc = int(len(result.get("errors", [])) > 0) + + # Caller should return if showing json, or status was present and False + exit_now = show_json or ("status" in result and rc) + return (rc, exit_now)
    + +
    [docs]def packageNEVRA(pkg): + """Return the package info as a NEVRA + + :param pkg: The package details + :type pkg: dict + :returns: name-[epoch:]version-release-arch + :rtype: str + """ + if pkg["epoch"]: + return "%s-%s:%s-%s.%s" % (pkg["name"], pkg["epoch"], pkg["version"], pkg["release"], pkg["arch"]) + else: + return "%s-%s-%s.%s" % (pkg["name"], pkg["version"], pkg["release"], pkg["arch"])
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/composer/http_client.html b/f32-branch/_modules/composer/http_client.html new file mode 100644 index 00000000..4edd84ea --- /dev/null +++ b/f32-branch/_modules/composer/http_client.html @@ -0,0 +1,459 @@ + + + + + + + + + + + composer.http_client — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for composer.http_client

    +#
    +# Copyright (C) 2018  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("composer-cli")
    +
    +import os
    +import sys
    +import json
    +from urllib.parse import urlparse, urlunparse
    +
    +from composer.unix_socket import UnixHTTPConnectionPool
    +
    +
    [docs]def api_url(api_version, url): + """Return the versioned path to the API route + + :param api_version: The version of the API to talk to. eg. "0" + :type api_version: str + :param url: The API route to talk to + :type url: str + :returns: The full url to use for the route and API version + :rtype: str + """ + return os.path.normpath("/api/v%s/%s" % (api_version, url))
    + +
    [docs]def append_query(url, query): + """Add a query argument to a URL + + The query should be of the form "param1=what&param2=ever", i.e., no + leading '?'. The new query data will be appended to any existing + query string. + + :param url: The original URL + :type url: str + :param query: The query to append + :type query: str + :returns: The new URL with the query argument included + :rtype: str + """ + + url_parts = urlparse(url) + if url_parts.query: + new_query = url_parts.query + "&" + query + else: + new_query = query + return urlunparse([url_parts[0], url_parts[1], url_parts[2], + url_parts[3], new_query, url_parts[5]])
    + +
    [docs]def get_url_raw(socket_path, url): + """Return the raw results of a GET request + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param url: URL to request + :type url: str + :returns: The raw response from the server + :rtype: str + """ + http = UnixHTTPConnectionPool(socket_path) + r = http.request("GET", url) + if r.status == 400: + err = json.loads(r.data.decode("utf-8")) + if "status" in err and err["status"] == False: + msgs = [e["msg"] for e in err["errors"]] + raise RuntimeError(", ".join(msgs)) + + return r.data.decode('utf-8')
    + +
    [docs]def get_url_json(socket_path, url): + """Return the JSON results of a GET request + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param url: URL to request + :type url: str + :returns: The json response from the server + :rtype: dict + """ + http = UnixHTTPConnectionPool(socket_path) + r = http.request("GET", url) + return json.loads(r.data.decode('utf-8'))
    + +
    [docs]def get_url_json_unlimited(socket_path, url, total_fn=None): + """Return the JSON results of a GET request + + For URLs that use offset/limit arguments, this command will + fetch all results for the given request. + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param url: URL to request + :type url: str + :returns: The json response from the server + :rtype: dict + """ + def default_total_fn(data): + """Return the total number of available results""" + return data["total"] + + http = UnixHTTPConnectionPool(socket_path) + + # Start with limit=0 to just get the number of objects + total_url = append_query(url, "limit=0") + r_total = http.request("GET", total_url) + json_total = json.loads(r_total.data.decode('utf-8')) + + # Where to get the total from + if not total_fn: + total_fn = default_total_fn + + # Add the "total" returned by limit=0 as the new limit + unlimited_url = append_query(url, "limit=%d" % total_fn(json_total)) + r_unlimited = http.request("GET", unlimited_url) + return json.loads(r_unlimited.data.decode('utf-8'))
    + +
    [docs]def delete_url_json(socket_path, url): + """Send a DELETE request to the url and return JSON response + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param url: URL to send DELETE to + :type url: str + :returns: The json response from the server + :rtype: dict + """ + http = UnixHTTPConnectionPool(socket_path) + r = http.request("DELETE", url) + return json.loads(r.data.decode("utf-8"))
    + +
    [docs]def post_url(socket_path, url, body): + """POST raw data to the URL + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param url: URL to send POST to + :type url: str + :param body: The data for the body of the POST + :type body: str + :returns: The json response from the server + :rtype: dict + """ + http = UnixHTTPConnectionPool(socket_path) + r = http.request("POST", url, + body=body.encode("utf-8")) + return json.loads(r.data.decode("utf-8"))
    + +
    [docs]def post_url_toml(socket_path, url, body): + """POST a TOML string to the URL + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param url: URL to send POST to + :type url: str + :param body: The data for the body of the POST + :type body: str + :returns: The json response from the server + :rtype: dict + """ + http = UnixHTTPConnectionPool(socket_path) + r = http.request("POST", url, + body=body.encode("utf-8"), + headers={"Content-Type": "text/x-toml"}) + return json.loads(r.data.decode("utf-8"))
    + +
    [docs]def post_url_json(socket_path, url, body): + """POST some JSON data to the URL + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param url: URL to send POST to + :type url: str + :param body: The data for the body of the POST + :type body: str + :returns: The json response from the server + :rtype: dict + """ + http = UnixHTTPConnectionPool(socket_path) + r = http.request("POST", url, + body=body.encode("utf-8"), + headers={"Content-Type": "application/json"}) + return json.loads(r.data.decode("utf-8"))
    + +
    [docs]def get_filename(headers): + """Get the filename from the response header + + :param response: The urllib3 response object + :type response: Response + :raises: RuntimeError if it cannot find a filename in the header + :returns: Filename from content-disposition header + :rtype: str + """ + log.debug("Headers = %s", headers) + if "content-disposition" not in headers: + raise RuntimeError("No Content-Disposition header; cannot get filename") + + try: + k, _, v = headers["content-disposition"].split(";")[1].strip().partition("=") + if k != "filename": + raise RuntimeError("No filename= found in content-disposition header") + except RuntimeError: + raise + except Exception as e: + raise RuntimeError("Error parsing filename from content-disposition header: %s" % str(e)) + + return os.path.basename(v)
    + +
    [docs]def download_file(socket_path, url, progress=True): + """Download a file, saving it to the CWD with the included filename + + :param socket_path: Path to the Unix socket to use for API communication + :type socket_path: str + :param url: URL to send POST to + :type url: str + """ + http = UnixHTTPConnectionPool(socket_path) + r = http.request("GET", url, preload_content=False) + if r.status == 400: + err = json.loads(r.data.decode("utf-8")) + if not err["status"]: + msgs = [e["msg"] for e in err["errors"]] + raise RuntimeError(", ".join(msgs)) + + filename = get_filename(r.headers) + if os.path.exists(filename): + msg = "%s exists, skipping download" % filename + log.error(msg) + raise RuntimeError(msg) + + with open(filename, "wb") as f: + while True: + data = r.read(10 * 1024**2) + if not data: + break + f.write(data) + + if progress: + data_written = f.tell() + if data_written > 5 * 1024**2: + sys.stdout.write("%s: %0.2f MB \r" % (filename, data_written / 1024**2)) + else: + sys.stdout.write("%s: %0.2f kB\r" % (filename, data_written / 1024)) + sys.stdout.flush() + + print("") + r.release_conn() + + return 0
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/composer/unix_socket.html b/f32-branch/_modules/composer/unix_socket.html new file mode 100644 index 00000000..6124ea5b --- /dev/null +++ b/f32-branch/_modules/composer/unix_socket.html @@ -0,0 +1,262 @@ + + + + + + + + + + + composer.unix_socket — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for composer.unix_socket

    +#
    +# Copyright (C) 2018  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import http.client
    +import socket
    +import urllib3
    +
    +
    +# These 2 classes were adapted and simplified for use with just urllib3.
    +# Originally from https://github.com/msabramo/requests-unixsocket/blob/master/requests_unixsocket/adapters.py
    +
    +# The following was adapted from some code from docker-py
    +# https://github.com/docker/docker-py/blob/master/docker/transport/unixconn.py
    +
    [docs]class UnixHTTPConnection(http.client.HTTPConnection, object): + + def __init__(self, socket_path, timeout=60*5): + """Create an HTTP connection to a unix domain socket + + :param socket_path: The path to the Unix domain socket + :param timeout: Number of seconds to timeout the connection + """ + super(UnixHTTPConnection, self).__init__('localhost', timeout=timeout) + self.socket_path = socket_path + self.sock = None + + def __del__(self): # base class does not have d'tor + if self.sock: + self.sock.close() + +
    [docs] def connect(self): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.settimeout(self.timeout) + sock.connect(self.socket_path) + self.sock = sock
    + +
    [docs]class UnixHTTPConnectionPool(urllib3.connectionpool.HTTPConnectionPool): + + def __init__(self, socket_path, timeout=60*5): + """Create a connection pool using a Unix domain socket + + :param socket_path: The path to the Unix domain socket + :param timeout: Number of seconds to timeout the connection + + NOTE: retries are disabled for these connections, they are never useful + """ + super(UnixHTTPConnectionPool, self).__init__('localhost', timeout=timeout, retries=False) + self.socket_path = socket_path + + def _new_conn(self): + return UnixHTTPConnection(self.socket_path, self.timeout)
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/index.html b/f32-branch/_modules/index.html new file mode 100644 index 00000000..66c2e0d1 --- /dev/null +++ b/f32-branch/_modules/index.html @@ -0,0 +1,250 @@ + + + + + + + + + + + Overview: module code — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + + + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/lifted/config.html b/f32-branch/_modules/lifted/config.html new file mode 100644 index 00000000..5a1a748f --- /dev/null +++ b/f32-branch/_modules/lifted/config.html @@ -0,0 +1,234 @@ + + + + + + + + + + + lifted.config — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for lifted.config

    +#
    +# Copyright (C) 2019  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +from pylorax.sysutils import joinpaths
    +
    +
    [docs]def configure(conf): + """Add lifted settings to the configuration + + :param conf: configuration object + :type conf: ComposerConfig + :returns: None + + This uses the composer.share_dir and composer.lib_dir as the base + directories for the settings. + """ + share_dir = conf.get("composer", "share_dir") + lib_dir = conf.get("composer", "lib_dir") + + conf.add_section("upload") + conf.set("upload", "providers_dir", joinpaths(share_dir, "/lifted/providers/")) + conf.set("upload", "queue_dir", joinpaths(lib_dir, "/upload/queue/")) + conf.set("upload", "settings_dir", joinpaths(lib_dir, "/upload/settings/"))
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/lifted/providers.html b/f32-branch/_modules/lifted/providers.html new file mode 100644 index 00000000..afd04f10 --- /dev/null +++ b/f32-branch/_modules/lifted/providers.html @@ -0,0 +1,444 @@ + + + + + + + + + + + lifted.providers — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for lifted.providers

    +#
    +# Copyright (C) 2019 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from glob import glob
    +import os
    +import re
    +import stat
    +
    +import pylorax.api.toml as toml
    +
    +
    +def _get_profile_path(ucfg, provider_name, profile, exists=True):
    +    """Helper to return the directory and path for a provider's profile file
    +
    +    :param ucfg: upload config
    +    :type ucfg: object
    +    :param provider_name: the name of the cloud provider, e.g. "azure"
    +    :type provider_name: str
    +    :param profile: the name of the profile to save
    +    :type profile: str != ""
    +    :returns: Full path of the profile .toml file
    +    :rtype: str
    +    :raises: ValueError when passed invalid settings or an invalid profile name
    +    :raises: RuntimeError when the provider or profile couldn't be found
    +    """
    +    # Make sure no path elements are present
    +    profile = os.path.basename(profile)
    +    provider_name = os.path.basename(provider_name)
    +    if not profile:
    +        raise ValueError("Profile name cannot be empty!")
    +    if not provider_name:
    +        raise ValueError("Provider name cannot be empty!")
    +
    +    directory = os.path.join(ucfg["settings_dir"], provider_name)
    +    # create the settings directory if it doesn't exist
    +    os.makedirs(directory, exist_ok=True)
    +
    +    path = os.path.join(directory, f"{profile}.toml")
    +    if exists and not os.path.isfile(path):
    +        raise RuntimeError(f'Couldn\'t find profile "{profile}"!')
    +
    +    return os.path.abspath(path)
    +
    +
    [docs]def resolve_provider(ucfg, provider_name): + """Get information about the specified provider as defined in that + provider's `provider.toml`, including the provider's display name and expected + settings. + + At a minimum, each setting has a display name (that likely differs from its + snake_case name) and a type. Currently, there are two types of settings: + string and boolean. String settings can optionally have a "placeholder" + value for use on the front end and a "regex" for making sure that a value + follows an expected pattern. + + :param ucfg: upload config + :type ucfg: object + :param provider_name: the name of the provider to look for + :type provider_name: str + :raises: RuntimeError when the provider couldn't be found + :returns: the provider + :rtype: dict + """ + # Make sure no path elements are present + provider_name = os.path.basename(provider_name) + path = os.path.join(ucfg["providers_dir"], provider_name, "provider.toml") + try: + with open(path) as provider_file: + provider = toml.load(provider_file) + except OSError as error: + raise RuntimeError(f'Couldn\'t find provider "{provider_name}"!') from error + + return provider
    + + +
    [docs]def load_profiles(ucfg, provider_name): + """Return all settings profiles associated with a provider + + :param ucfg: upload config + :type ucfg: object + :param provider_name: name a provider to find profiles for + :type provider_name: str + :returns: a dict of settings dicts, keyed by profile name + :rtype: dict + """ + # Make sure no path elements are present + provider_name = os.path.basename(provider_name) + + def load_path(path): + with open(path) as file: + return toml.load(file) + + def get_name(path): + return os.path.splitext(os.path.basename(path))[0] + + paths = glob(os.path.join(ucfg["settings_dir"], provider_name, "*")) + return {get_name(path): load_path(path) for path in paths}
    + + +
    [docs]def resolve_playbook_path(ucfg, provider_name): + """Given a provider's name, return the path to its playbook + + :param ucfg: upload config + :type ucfg: object + :param provider_name: the name of the provider to find the playbook for + :type provider_name: str + :raises: RuntimeError when the provider couldn't be found + :returns: the path to the playbook + :rtype: str + """ + # Make sure no path elements are present + provider_name = os.path.basename(provider_name) + + path = os.path.join(ucfg["providers_dir"], provider_name, "playbook.yaml") + if not os.path.isfile(path): + raise RuntimeError(f'Couldn\'t find playbook for "{provider_name}"!') + return path
    + + +
    [docs]def list_providers(ucfg): + """List the names of the available upload providers + + :param ucfg: upload config + :type ucfg: object + :returns: a list of all available provider_names + :rtype: list of str + """ + paths = glob(os.path.join(ucfg["providers_dir"], "*")) + return sorted(os.path.basename(path) for path in paths)
    + + +
    [docs]def validate_settings(ucfg, provider_name, settings, image_name=None): + """Raise a ValueError if any settings are invalid + + :param ucfg: upload config + :type ucfg: object + :param provider_name: the name of the provider to validate the settings against + :type provider_name: str + :param settings: the settings to validate + :type settings: dict + :param image_name: optionally check whether an image_name is valid + :type image_name: str + :raises: ValueError when the passed settings are invalid + :raises: RuntimeError when provider_name can't be found + """ + if image_name == "": + raise ValueError("Image name cannot be empty!") + type_map = {"string": str, "boolean": bool} + settings_info = resolve_provider(ucfg, provider_name)["settings-info"] + for key, value in settings.items(): + if key not in settings_info: + raise ValueError(f'Received unexpected setting: "{key}"!') + setting_type = settings_info[key]["type"] + correct_type = type_map[setting_type] + if not isinstance(value, correct_type): + raise ValueError( + f'Expected a {correct_type} for "{key}", received a {type(value)}!' + ) + if setting_type == "string" and "regex" in settings_info[key]: + if not re.match(settings_info[key]["regex"], value): + raise ValueError(f'Value "{value}" is invalid for setting "{key}"!')
    + + +
    [docs]def save_settings(ucfg, provider_name, profile, settings): + """Save (and overwrite) settings for a given provider + + :param ucfg: upload config + :type ucfg: object + :param provider_name: the name of the cloud provider, e.g. "azure" + :type provider_name: str + :param profile: the name of the profile to save + :type profile: str != "" + :param settings: settings to save for that provider + :type settings: dict + :raises: ValueError when passed invalid settings or an invalid profile name + """ + path = _get_profile_path(ucfg, provider_name, profile, exists=False) + validate_settings(ucfg, provider_name, settings, image_name=None) + + # touch the TOML file if it doesn't exist + if not os.path.isfile(path): + open(path, "a").close() + + # make sure settings files aren't readable by others, as they will contain + # sensitive credentials + current = stat.S_IMODE(os.lstat(path).st_mode) + os.chmod(path, current & ~stat.S_IROTH) + + with open(path, "w") as settings_file: + toml.dump(settings, settings_file)
    + +
    [docs]def load_settings(ucfg, provider_name, profile): + """Load settings for a provider's profile + + :param ucfg: upload config + :type ucfg: object + :param provider_name: the name of the cloud provider, e.g. "azure" + :type provider_name: str + :param profile: the name of the profile to save + :type profile: str != "" + :returns: The profile settings for the selected provider + :rtype: dict + :raises: ValueError when passed invalid settings or an invalid profile name + :raises: RuntimeError when the provider or profile couldn't be found + :raises: ValueError when the passed settings are invalid + + This also calls validate_settings on the loaded settings, potentially + raising an error if the saved settings are invalid. + """ + path = _get_profile_path(ucfg, provider_name, profile) + + with open(path) as file: + settings = toml.load(file) + validate_settings(ucfg, provider_name, settings) + return settings
    + +
    [docs]def delete_profile(ucfg, provider_name, profile): + """Delete a provider's profile settings file + + :param ucfg: upload config + :type ucfg: object + :param provider_name: the name of the cloud provider, e.g. "azure" + :type provider_name: str + :param profile: the name of the profile to save + :type profile: str != "" + :raises: ValueError when passed invalid settings or an invalid profile name + :raises: RuntimeError when the provider or profile couldn't be found + """ + path = _get_profile_path(ucfg, provider_name, profile) + + if os.path.exists(path): + os.unlink(path)
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/lifted/queue.html b/f32-branch/_modules/lifted/queue.html new file mode 100644 index 00000000..3ef32a37 --- /dev/null +++ b/f32-branch/_modules/lifted/queue.html @@ -0,0 +1,468 @@ + + + + + + + + + + + lifted.queue — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for lifted.queue

    +#
    +# Copyright (C) 2019 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from functools import partial
    +from glob import glob
    +import logging
    +import multiprocessing
    +
    +# We use a multiprocessing Pool for uploads so that we can cancel them with a
    +# simple SIGINT, which should bubble down to subprocesses.
    +from multiprocessing import Pool
    +
    +# multiprocessing.dummy is to threads as multiprocessing is to processes.
    +# Since daemonic processes can't have children, we use a thread to monitor the
    +# upload pool.
    +from multiprocessing.dummy import Process
    +
    +from operator import attrgetter
    +import os
    +import stat
    +import time
    +
    +import pylorax.api.toml as toml
    +
    +from lifted.upload import Upload
    +from lifted.providers import resolve_playbook_path, validate_settings
    +
    +# the maximum number of simultaneous uploads
    +SIMULTANEOUS_UPLOADS = 1
    +
    +log = logging.getLogger("lifted")
    +multiprocessing.log_to_stderr().setLevel(logging.INFO)
    +
    +
    +def _get_queue_path(ucfg):
    +    path = ucfg["queue_dir"]
    +
    +    # create the upload_queue directory if it doesn't exist
    +    os.makedirs(path, exist_ok=True)
    +
    +    return path
    +
    +
    +def _get_upload_path(ucfg, uuid, write=False):
    +    # Make sure no path elements are present
    +    uuid = os.path.basename(uuid)
    +
    +    path = os.path.join(_get_queue_path(ucfg), f"{uuid}.toml")
    +    if write and not os.path.exists(path):
    +        open(path, "a").close()
    +    if os.path.exists(path):
    +        # make sure uploads aren't readable by others, as they will contain
    +        # sensitive credentials
    +        current = stat.S_IMODE(os.lstat(path).st_mode)
    +        os.chmod(path, current & ~stat.S_IROTH)
    +    return path
    +
    +
    +def _list_upload_uuids(ucfg):
    +    paths = glob(os.path.join(_get_queue_path(ucfg), "*"))
    +    return [os.path.splitext(os.path.basename(path))[0] for path in paths]
    +
    +
    +def _write_upload(ucfg, upload):
    +    with open(_get_upload_path(ucfg, upload.uuid, write=True), "w") as upload_file:
    +        toml.dump(upload.serializable(), upload_file)
    +
    +
    +def _write_callback(ucfg):
    +    return partial(_write_upload, ucfg)
    +
    +
    +
    [docs]def get_upload(ucfg, uuid, ignore_missing=False, ignore_corrupt=False): + """Get an Upload object by UUID + + :param ucfg: upload config + :type ucfg: object + :param uuid: UUID of the upload to get + :type uuid: str + :param ignore_missing: if True, don't raise a RuntimeError when the specified upload is missing, instead just return None + :type ignore_missing: bool + :param ignore_corrupt: if True, don't raise a RuntimeError when the specified upload could not be deserialized, instead just return None + :type ignore_corrupt: bool + :returns: the upload object or None + :rtype: Upload or None + :raises: RuntimeError + """ + try: + with open(_get_upload_path(ucfg, uuid), "r") as upload_file: + return Upload(**toml.load(upload_file)) + except FileNotFoundError as error: + if not ignore_missing: + raise RuntimeError(f"Could not find upload {uuid}!") from error + except toml.TomlError as error: + if not ignore_corrupt: + raise RuntimeError(f"Could not parse upload {uuid}!") from error
    + + +
    [docs]def get_uploads(ucfg, uuids): + """Gets a list of Upload objects from a list of upload UUIDs, ignoring + missing or corrupt uploads + + :param ucfg: upload config + :type ucfg: object + :param uuids: list of upload UUIDs to get + :type uuids: list of str + :returns: a list of the uploads that were successfully deserialized + :rtype: list of Upload + """ + uploads = ( + get_upload(ucfg, uuid, ignore_missing=True, ignore_corrupt=True) + for uuid in uuids + ) + return list(filter(None, uploads))
    + + +
    [docs]def get_all_uploads(ucfg): + """Get a list of all stored Upload objects + + :param ucfg: upload config + :type ucfg: object + :returns: a list of all stored upload objects + :rtype: list of Upload + """ + return get_uploads(ucfg, _list_upload_uuids(ucfg))
    + + +
    [docs]def create_upload(ucfg, provider_name, image_name, settings): + """Creates a new upload + + :param ucfg: upload config + :type ucfg: object + :param provider_name: the name of the cloud provider to upload to, e.g. "azure" + :type provider_name: str + :param image_name: what to name the image in the cloud + :type image_name: str + :param settings: settings to pass to the upload, specific to the cloud provider + :type settings: dict + :returns: the created upload object + :rtype: Upload + """ + validate_settings(ucfg, provider_name, settings, image_name) + return Upload( + provider_name=provider_name, + playbook_path=resolve_playbook_path(ucfg, provider_name), + image_name=image_name, + settings=settings, + status_callback=_write_callback(ucfg), + )
    + + +
    [docs]def ready_upload(ucfg, uuid, image_path): + """Pass an image_path to an upload and mark it ready to execute + + :param ucfg: upload config + :type ucfg: object + :param uuid: the UUID of the upload to mark ready + :type uuid: str + :param image_path: the path of the image to pass to the upload + :type image_path: str + """ + get_upload(ucfg, uuid).ready(image_path, _write_callback(ucfg))
    + + +
    [docs]def reset_upload(ucfg, uuid, new_image_name=None, new_settings=None): + """Reset an upload so it can be attempted again + + :param ucfg: upload config + :type ucfg: object + :param uuid: the UUID of the upload to reset + :type uuid: str + :param new_image_name: optionally update the upload's image_name + :type new_image_name: str + :param new_settings: optionally update the upload's settings + :type new_settings: dict + """ + upload = get_upload(ucfg, uuid) + validate_settings( + ucfg, + upload.provider_name, + new_settings or upload.settings, + new_image_name or upload.image_name, + ) + if new_image_name: + upload.image_name = new_image_name + if new_settings: + upload.settings = new_settings + upload.reset(_write_callback(ucfg))
    + + +
    [docs]def cancel_upload(ucfg, uuid): + """Cancel an upload + + :param ucfg: the compose config + :type ucfg: ComposerConfig + :param uuid: the UUID of the upload to cancel + :type uuid: str + """ + get_upload(ucfg, uuid).cancel(_write_callback(ucfg))
    + + +
    [docs]def delete_upload(ucfg, uuid): + """Delete an upload + + :param ucfg: the compose config + :type ucfg: ComposerConfig + :param uuid: the UUID of the upload to delete + :type uuid: str + """ + upload = get_upload(ucfg, uuid) + if upload and upload.is_cancellable(): + upload.cancel() + os.remove(_get_upload_path(ucfg, uuid))
    + + +
    [docs]def start_upload_monitor(ucfg): + """Start a thread that manages the upload queue + + :param ucfg: the compose config + :type ucfg: ComposerConfig + """ + process = Process(target=_monitor, args=(ucfg,)) + process.daemon = True + process.start()
    + + +def _monitor(ucfg): + log.info("Started upload monitor.") + for upload in get_all_uploads(ucfg): + # Set abandoned uploads to FAILED + if upload.status == "RUNNING": + upload.set_status("FAILED", _write_callback(ucfg)) + pool = Pool(processes=SIMULTANEOUS_UPLOADS) + pool_uuids = set() + + def remover(uuid): + return lambda _: pool_uuids.remove(uuid) + + while True: + # Every second, scoop up READY uploads from the filesystem and throw + # them in the pool + all_uploads = get_all_uploads(ucfg) + for upload in sorted(all_uploads, key=attrgetter("creation_time")): + ready = upload.status == "READY" + if ready and upload.uuid not in pool_uuids: + log.info("Starting upload %s...", upload.uuid) + pool_uuids.add(upload.uuid) + callback = remover(upload.uuid) + pool.apply_async( + upload.execute, + (_write_callback(ucfg),), + callback=callback, + error_callback=callback, + ) + time.sleep(1) +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/lifted/upload.html b/f32-branch/_modules/lifted/upload.html new file mode 100644 index 00000000..7adb05e2 --- /dev/null +++ b/f32-branch/_modules/lifted/upload.html @@ -0,0 +1,411 @@ + + + + + + + + + + + lifted.upload — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for lifted.upload

    +#
    +# Copyright (C) 2019 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from datetime import datetime
    +import logging
    +from multiprocessing import current_process
    +import os
    +import signal
    +from uuid import uuid4
    +
    +from ansible_runner.interface import run as ansible_run
    +from ansible_runner.exceptions import AnsibleRunnerException
    +
    +log = logging.getLogger("lifted")
    +
    +
    +
    [docs]class Upload: + """Represents an upload of an image to a cloud provider. Instances of this + class are serialized as TOML and stored in the upload queue directory, + which is /var/lib/lorax/upload/queue/ by default""" + + def __init__( + self, + uuid=None, + provider_name=None, + playbook_path=None, + image_name=None, + settings=None, + creation_time=None, + upload_log=None, + upload_pid=None, + image_path=None, + status_callback=None, + status=None, + ): + self.uuid = uuid or str(uuid4()) + self.provider_name = provider_name + self.playbook_path = playbook_path + self.image_name = image_name + self.settings = settings + self.creation_time = creation_time or datetime.now().timestamp() + self.upload_log = upload_log or "" + self.upload_pid = upload_pid + self.image_path = image_path + if status: + self.status = status + else: + self.set_status("WAITING", status_callback) + + def _log(self, message, callback=None): + """Logs something to the upload log with an optional callback + + :param message: the object to log + :type message: object + :param callback: a function of the form callback(self) + :type callback: function + """ + if message: + messages = str(message).splitlines() + + # Log multi-line messages as individual log lines + for m in messages: + log.info(m) + self.upload_log += f"{message}\n" + if callback: + callback(self) + +
    [docs] def serializable(self): + """Returns a representation of the object as a dict for serialization + + :returns: the object's __dict__ + :rtype: dict + """ + return self.__dict__
    + +
    [docs] def summary(self): + """Return a dict with useful information about the upload + + :returns: upload information + :rtype: dict + """ + + return { + "uuid": self.uuid, + "status": self.status, + "provider_name": self.provider_name, + "image_name": self.image_name, + "image_path": self.image_path, + "creation_time": self.creation_time, + "settings": self.settings, + }
    + +
    [docs] def set_status(self, status, status_callback=None): + """Sets the status of the upload with an optional callback + + :param status: the new status + :type status: str + :param status_callback: a function of the form callback(self) + :type status_callback: function + """ + self._log("Setting status to %s" % status) + self.status = status + if status_callback: + status_callback(self)
    + +
    [docs] def ready(self, image_path, status_callback): + """Provide an image_path and mark the upload as ready to execute + + :param image_path: path of the image to upload + :type image_path: str + :param status_callback: a function of the form callback(self) + :type status_callback: function + """ + self._log("Setting image_path to %s" % image_path) + self.image_path = image_path + if self.status == "WAITING": + self.set_status("READY", status_callback)
    + +
    [docs] def reset(self, status_callback): + """Reset the upload so it can be attempted again + + :param status_callback: a function of the form callback(self) + :type status_callback: function + """ + if self.is_cancellable(): + raise RuntimeError(f"Can't reset, status is {self.status}!") + if not self.image_path: + raise RuntimeError("Can't reset, no image supplied yet!") + # self.error = None + self._log("Resetting state") + self.set_status("READY", status_callback)
    + +
    [docs] def is_cancellable(self): + """Is the upload in a cancellable state? + + :returns: whether the upload is cancellable + :rtype: bool + """ + return self.status in ("WAITING", "READY", "RUNNING")
    + +
    [docs] def cancel(self, status_callback=None): + """Cancel the upload. Sends a SIGINT to self.upload_pid. + + :param status_callback: a function of the form callback(self) + :type status_callback: function + """ + if not self.is_cancellable(): + raise RuntimeError(f"Can't cancel, status is already {self.status}!") + if self.upload_pid: + os.kill(self.upload_pid, signal.SIGINT) + self.set_status("CANCELLED", status_callback)
    + +
    [docs] def execute(self, status_callback=None): + """Execute the upload. Meant to be called from a dedicated process so + that the upload can be cancelled by sending a SIGINT to + self.upload_pid. + + :param status_callback: a function of the form callback(self) + :type status_callback: function + """ + if self.status != "READY": + raise RuntimeError("This upload is not ready!") + + try: + self.upload_pid = current_process().pid + self.set_status("RUNNING", status_callback) + self._log("Executing playbook.yml") + + # NOTE: event_handler doesn't seem to be called for playbook errors + logger = lambda e: self._log(e["stdout"], status_callback) + + runner = ansible_run( + playbook=self.playbook_path, + extravars={ + **self.settings, + "image_name": self.image_name, + "image_path": self.image_path, + }, + event_handler=logger, + verbosity=2, + ) + + # Try logging events and stats -- but they may not exist, so catch the error + try: + for e in runner.events: + self._log("%s" % dir(e), status_callback) + + self._log("%s" % runner.stats, status_callback) + except AnsibleRunnerException: + self._log("%s" % runner.stdout.read(), status_callback) + + if runner.status == "successful": + self.set_status("FINISHED", status_callback) + else: + self.set_status("FAILED", status_callback) + except Exception: + import traceback + log.error(traceback.format_exc(limit=2))
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax.html b/f32-branch/_modules/pylorax.html new file mode 100644 index 00000000..b226901d --- /dev/null +++ b/f32-branch/_modules/pylorax.html @@ -0,0 +1,653 @@ + + + + + + + + + + + pylorax — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax

    +#
    +# __init__.py
    +#
    +# Copyright (C) 2010-2015  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Red Hat Author(s):  Martin Gracik <mgracik@redhat.com>
    +#                     David Cantrell <dcantrell@redhat.com>
    +#                     Will Woods <wwoods@redhat.com>
    +
    +# set up logging
    +import logging
    +logger = logging.getLogger("pylorax")
    +logger.addHandler(logging.NullHandler())
    +
    +program_log = logging.getLogger("program")
    +
    +import sys
    +import os
    +import configparser
    +import tempfile
    +import locale
    +from subprocess import CalledProcessError
    +import selinux
    +from glob import glob
    +
    +from pylorax.base import BaseLoraxClass, DataHolder
    +import pylorax.output as output
    +
    +import dnf
    +
    +from pylorax.sysutils import joinpaths, remove, linktree
    +
    +from pylorax.treebuilder import RuntimeBuilder, TreeBuilder
    +from pylorax.buildstamp import BuildStamp
    +from pylorax.treeinfo import TreeInfo
    +from pylorax.discinfo import DiscInfo
    +from pylorax.executils import runcmd, runcmd_output
    +
    +
    +# get lorax version
    +try:
    +    import pylorax.version
    +except ImportError:
    +    vernum = "devel"
    +else:
    +    vernum = pylorax.version.num
    +
    +DRACUT_DEFAULT = ["--xz", "--install", "/.buildstamp", "--no-early-microcode", "--add", "fips"]
    +
    +# Used for DNF conf.module_platform_id
    +DEFAULT_PLATFORM_ID = "platform:f32"
    +
    +
    [docs]class ArchData(DataHolder): + lib64_arches = ("x86_64", "ppc64le", "s390x", "ia64", "aarch64") + bcj_arch = dict(i386="x86", x86_64="x86", + ppc64le="powerpc", + arm="arm", armhfp="arm") + + def __init__(self, buildarch): + super(ArchData, self).__init__() + self.buildarch = buildarch + self.basearch = dnf.rpm.basearch(buildarch) + self.libdir = "lib64" if self.basearch in self.lib64_arches else "lib" + self.bcj = self.bcj_arch.get(self.basearch)
    + +
    [docs]class Lorax(BaseLoraxClass): + + def __init__(self): + BaseLoraxClass.__init__(self) + self._configured = False + self.product = None + self.workdir = None + self.arch = None + self.conf = None + self.inroot = None + self.debug = False + self.outputdir = None + self._templatedir = None + + # set locale to C + locale.setlocale(locale.LC_ALL, 'C') + +
    [docs] def configure(self, conf_file="/etc/lorax/lorax.conf"): + self.conf = configparser.SafeConfigParser() + + # set defaults + self.conf.add_section("lorax") + self.conf.set("lorax", "debug", "1") + self.conf.set("lorax", "sharedir", "/usr/share/lorax") + self.conf.set("lorax", "logdir", "/var/log/lorax") + + self.conf.add_section("output") + self.conf.set("output", "colors", "1") + self.conf.set("output", "encoding", "utf-8") + self.conf.set("output", "ignorelist", "/usr/share/lorax/ignorelist") + + self.conf.add_section("templates") + self.conf.set("templates", "ramdisk", "ramdisk.ltmpl") + + self.conf.add_section("compression") + self.conf.set("compression", "type", "xz") + self.conf.set("compression", "args", "") + self.conf.set("compression", "bcj", "on") + + # read the config file + if os.path.isfile(conf_file): + self.conf.read(conf_file) + + # set up the output + self.debug = self.conf.getboolean("lorax", "debug") + output_level = output.DEBUG if self.debug else output.INFO + + if sys.stdout.isatty(): + colors = self.conf.getboolean("output", "colors") + else: + colors = False + encoding = self.conf.get("output", "encoding") + + self.output.basic_config(output_level=output_level, + colors=colors, encoding=encoding) + + ignorelist = self.conf.get("output", "ignorelist") + if os.path.isfile(ignorelist): + with open(ignorelist, "r") as fobj: + for line in fobj: + line = line.strip() + if line and not line.startswith("#"): + self.output.ignore(line) + + # cron does not have sbin in PATH, + # so we have to add it ourselves + os.environ["PATH"] = "{0}:/sbin:/usr/sbin".format(os.environ["PATH"]) + + # remove some environmental variables that can cause problems with package scripts + env_remove = ('DISPLAY', 'DBUS_SESSION_BUS_ADDRESS') + list(os.environ.pop(k) for k in env_remove if k in os.environ) + + self._configured = True
    + + @property + def templatedir(self): + """Find the template directory. + + Pick the first directory under sharedir/templates.d/ if it exists. + Otherwise use the sharedir + """ + if not self._templatedir: + self._templatedir = find_templates(self.conf.get("lorax", "sharedir")) + logger.info("Using templatedir %s", self._templatedir) + return self._templatedir + +
    [docs] def init_stream_logging(self): + sh = logging.StreamHandler() + sh.setLevel(logging.INFO) + logger.addHandler(sh)
    + +
    [docs] def init_file_logging(self, logdir, logname="pylorax.log"): + fh = logging.FileHandler(filename=joinpaths(logdir, logname), mode="w") + fh.setLevel(logging.DEBUG) + logger.addHandler(fh)
    + +
    [docs] def run(self, dbo, product, version, release, variant="", bugurl="", + isfinal=False, workdir=None, outputdir=None, buildarch=None, volid=None, + domacboot=True, doupgrade=True, remove_temp=False, + installpkgs=None, excludepkgs=None, + size=2, + add_templates=None, + add_template_vars=None, + add_arch_templates=None, + add_arch_template_vars=None, + verify=True, + user_dracut_args=None, + squashfs_only=False, + skip_branding=False): + + assert self._configured + + installpkgs = installpkgs or [] + excludepkgs = excludepkgs or [] + + if domacboot: + try: + runcmd(["rpm", "-q", "hfsplus-tools"]) + except CalledProcessError: + logger.critical("you need to install hfsplus-tools to create mac images") + sys.exit(1) + + # set up work directory + self.workdir = workdir or tempfile.mkdtemp(prefix="pylorax.work.") + if not os.path.isdir(self.workdir): + os.makedirs(self.workdir) + + # set up log directory + logdir = self.conf.get("lorax", "logdir") + if not os.path.isdir(logdir): + os.makedirs(logdir) + + self.init_stream_logging() + self.init_file_logging(logdir) + + logger.debug("version is %s", vernum) + log_selinux_state() + + logger.debug("using work directory %s", self.workdir) + logger.debug("using log directory %s", logdir) + + # set up output directory + self.outputdir = outputdir or tempfile.mkdtemp(prefix="pylorax.out.") + if not os.path.isdir(self.outputdir): + os.makedirs(self.outputdir) + logger.debug("using output directory %s", self.outputdir) + + # do we have root privileges? + logger.info("checking for root privileges") + if not os.geteuid() == 0: + logger.critical("no root privileges") + sys.exit(1) + + # do we have a proper dnf base object? + logger.info("checking dnf base object") + if not isinstance(dbo, dnf.Base): + logger.critical("no dnf base object") + sys.exit(1) + self.inroot = dbo.conf.installroot + logger.debug("using install root: %s", self.inroot) + + if not buildarch: + buildarch = get_buildarch(dbo) + + logger.info("setting up build architecture") + self.arch = ArchData(buildarch) + for attr in ('buildarch', 'basearch', 'libdir'): + logger.debug("self.arch.%s = %s", attr, getattr(self.arch,attr)) + + logger.info("setting up build parameters") + self.product = DataHolder(name=product, version=version, release=release, + variant=variant, bugurl=bugurl, isfinal=isfinal) + logger.debug("product data: %s", self.product) + + # NOTE: if you change isolabel, you need to change pungi to match, or + # the pungi images won't boot. + isolabel = volid or "%s-%s-%s" % (self.product.name, self.product.version, self.arch.basearch) + + if len(isolabel) > 32: + logger.fatal("the volume id cannot be longer than 32 characters") + sys.exit(1) + + # NOTE: rb.root = dbo.conf.installroot (== self.inroot) + rb = RuntimeBuilder(product=self.product, arch=self.arch, + dbo=dbo, templatedir=self.templatedir, + installpkgs=installpkgs, + excludepkgs=excludepkgs, + add_templates=add_templates, + add_template_vars=add_template_vars, + skip_branding=skip_branding) + + logger.info("installing runtime packages") + rb.install() + + # write .buildstamp + buildstamp = BuildStamp(self.product.name, self.product.version, + self.product.bugurl, self.product.isfinal, + self.arch.buildarch, self.product.variant) + + buildstamp.write(joinpaths(self.inroot, ".buildstamp")) + + if self.debug: + rb.writepkglists(joinpaths(logdir, "pkglists")) + rb.writepkgsizes(joinpaths(logdir, "original-pkgsizes.txt")) + + logger.info("doing post-install configuration") + rb.postinstall() + + # write .discinfo + discinfo = DiscInfo(self.product.release, self.arch.basearch) + discinfo.write(joinpaths(self.outputdir, ".discinfo")) + + logger.info("backing up installroot") + installroot = joinpaths(self.workdir, "installroot") + linktree(self.inroot, installroot) + + logger.info("generating kernel module metadata") + rb.generate_module_data() + + logger.info("cleaning unneeded files") + rb.cleanup() + + if verify: + logger.info("verifying the installroot") + if not rb.verify(): + sys.exit(1) + else: + logger.info("Skipping verify") + + if self.debug: + rb.writepkgsizes(joinpaths(logdir, "final-pkgsizes.txt")) + + logger.info("creating the runtime image") + runtime = "images/install.img" + compression = self.conf.get("compression", "type") + compressargs = self.conf.get("compression", "args").split() # pylint: disable=no-member + if self.conf.getboolean("compression", "bcj"): + if self.arch.bcj: + compressargs += ["-Xbcj", self.arch.bcj] + else: + logger.info("no BCJ filter for arch %s", self.arch.basearch) + if squashfs_only: + # Create an ext4 rootfs.img and compress it with squashfs + rb.create_squashfs_runtime(joinpaths(installroot,runtime), + compression=compression, compressargs=compressargs, + size=size) + else: + # Create an ext4 rootfs.img and compress it with squashfs + rb.create_ext4_runtime(joinpaths(installroot,runtime), + compression=compression, compressargs=compressargs, + size=size) + rb.finished() + + logger.info("preparing to build output tree and boot images") + treebuilder = TreeBuilder(product=self.product, arch=self.arch, + inroot=installroot, outroot=self.outputdir, + runtime=runtime, isolabel=isolabel, + domacboot=domacboot, doupgrade=doupgrade, + templatedir=self.templatedir, + add_templates=add_arch_templates, + add_template_vars=add_arch_template_vars, + workdir=self.workdir) + + logger.info("rebuilding initramfs images") + if not user_dracut_args: + dracut_args = DRACUT_DEFAULT + else: + dracut_args = [] + for arg in user_dracut_args: + dracut_args += arg.split(" ", 1) + + anaconda_args = dracut_args + ["--add", "anaconda pollcdrom qemu qemu-net"] + + logger.info("dracut args = %s", dracut_args) + logger.info("anaconda args = %s", anaconda_args) + treebuilder.rebuild_initrds(add_args=anaconda_args) + + logger.info("populating output tree and building boot images") + treebuilder.build() + + # write .treeinfo file and we're done + treeinfo = TreeInfo(self.product.name, self.product.version, + self.product.variant, self.arch.basearch) + for section, data in treebuilder.treeinfo_data.items(): + treeinfo.add_section(section, data) + treeinfo.write(joinpaths(self.outputdir, ".treeinfo")) + + # cleanup + if remove_temp: + remove(self.workdir)
    + + +
    [docs]def get_buildarch(dbo): + # get architecture of the available anaconda package + buildarch = None + q = dbo.sack.query() + a = q.available() + for anaconda in a.filter(name="anaconda-core"): + if anaconda.arch != "src": + buildarch = anaconda.arch + break + if not buildarch: + logger.critical("no anaconda-core package in the repository") + sys.exit(1) + + return buildarch
    + + +
    [docs]def setup_logging(logfile, theLogger): + """ + Setup the various logs + + :param logfile: filename to write the log to + :type logfile: string + :param theLogger: top-level logger + :type theLogger: logging.Logger + """ + if not os.path.isdir(os.path.abspath(os.path.dirname(logfile))): + os.makedirs(os.path.abspath(os.path.dirname(logfile))) + + # Setup logging to console and to logfile + logger.setLevel(logging.DEBUG) + theLogger.setLevel(logging.DEBUG) + + sh = logging.StreamHandler() + sh.setLevel(logging.INFO) + fmt = logging.Formatter("%(asctime)s: %(message)s") + sh.setFormatter(fmt) + logger.addHandler(sh) + theLogger.addHandler(sh) + + fh = logging.FileHandler(filename=logfile, mode="w") + fh.setLevel(logging.DEBUG) + fmt = logging.Formatter("%(asctime)s %(levelname)s %(name)s: %(message)s") + fh.setFormatter(fmt) + logger.addHandler(fh) + theLogger.addHandler(fh) + + # External program output log + program_log.setLevel(logging.DEBUG) + f = os.path.abspath(os.path.dirname(logfile))+"/program.log" + fh = logging.FileHandler(filename=f, mode="w") + fh.setLevel(logging.DEBUG) + fmt = logging.Formatter("%(asctime)s %(levelname)s: %(message)s") + fh.setFormatter(fmt) + program_log.addHandler(fh)
    + + +
    [docs]def find_templates(templatedir="/usr/share/lorax"): + """ Find the templates to use. + + :param str templatedir: Top directory to search for templates + :returns: Path to templates + :rtype: str + + If there is a templates.d directory under templatedir the + lowest numbered directory entry is returned. + + eg. /usr/share/lorax/templates.d/99-generic/ + """ + if os.path.isdir(joinpaths(templatedir, "templates.d")): + try: + templatedir = sorted(glob(joinpaths(templatedir, "templates.d", "*")))[0] + except IndexError: + pass + return templatedir
    + +
    [docs]def log_selinux_state(): + """Log the current state of selinux""" + if selinux.is_selinux_enabled(): + if selinux.security_getenforce(): + logger.info("selinux is enabled and in Enforcing mode") + else: + logger.info("selinux is enabled and in Permissive mode") + else: + logger.info("selinux is Disabled")
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/bisect.html b/f32-branch/_modules/pylorax/api/bisect.html new file mode 100644 index 00000000..806781f3 --- /dev/null +++ b/f32-branch/_modules/pylorax/api/bisect.html @@ -0,0 +1,250 @@ + + + + + + + + + + + pylorax.api.bisect — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.bisect

    +#
    +# Copyright (C) 2018 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    [docs]def insort_left(a, x, key=None, lo=0, hi=None): + """Insert item x in list a, and keep it sorted assuming a is sorted. + + :param a: sorted list + :type a: list + :param x: item to insert into the list + :type x: object + :param key: Function to use to compare items in the list + :type key: function + :returns: index where the item was inserted + :rtype: int + + If x is already in a, insert it to the left of the leftmost x. + Optional args lo (default 0) and hi (default len(a)) bound the + slice of a to be searched. + + This is a modified version of bisect.insort_left that can use a + function for the compare, and returns the index position where it + was inserted. + """ + if key is None: + key = lambda i: i + + if lo < 0: + raise ValueError('lo must be non-negative') + if hi is None: + hi = len(a) + while lo < hi: + mid = (lo+hi)//2 + if key(a[mid]) < key(x): lo = mid+1 + else: hi = mid + a.insert(lo, x) + return lo
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/checkparams.html b/f32-branch/_modules/pylorax/api/checkparams.html new file mode 100644 index 00000000..e6b5aea4 --- /dev/null +++ b/f32-branch/_modules/pylorax/api/checkparams.html @@ -0,0 +1,245 @@ + + + + + + + + + + + pylorax.api.checkparams — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.checkparams

    +#
    +# Copyright (C) 2018  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +import logging
    +log = logging.getLogger("lorax-composer")
    +
    +from flask import jsonify
    +from functools import update_wrapper
    +
    +# A decorator for checking the parameters provided to the API route implementing
    +# functions.  The tuples parameter is a list of tuples.  Each tuple is the string
    +# name of a parameter ("blueprint_name", not blueprint_name), the value it's set
    +# to by flask if the caller did not provide it, and a message to be returned to
    +# the user.
    +#
    +# If the parameter is set to its default, the error message is returned.  Otherwise,
    +# the decorated function is called and its return value is returned.
    +
    [docs]def checkparams(tuples): + def decorator(f): + def wrapped_function(*args, **kwargs): + for tup in tuples: + if kwargs[tup[0]] == tup[1]: + log.error("(%s) %s", f.__name__, tup[2]) + return jsonify(status=False, errors=[tup[2]]), 400 + + return f(*args, **kwargs) + + return update_wrapper(wrapped_function, f) + + return decorator
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/cmdline.html b/f32-branch/_modules/pylorax/api/cmdline.html new file mode 100644 index 00000000..e06ac911 --- /dev/null +++ b/f32-branch/_modules/pylorax/api/cmdline.html @@ -0,0 +1,264 @@ + + + + + + + + + + + pylorax.api.cmdline — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.cmdline

    +#
    +# cmdline.py
    +#
    +# Copyright (C) 2018 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import os
    +import sys
    +import argparse
    +
    +from pylorax import vernum
    +
    +DEFAULT_USER  = "root"
    +DEFAULT_GROUP = "weldr"
    +
    +version = "{0}-{1}".format(os.path.basename(sys.argv[0]), vernum)
    +
    +
    [docs]def lorax_composer_parser(): + """ Return the ArgumentParser for lorax-composer""" + + parser = argparse.ArgumentParser(description="Lorax Composer API Server", + fromfile_prefix_chars="@") + + parser.add_argument("--socket", default="/run/weldr/api.socket", metavar="SOCKET", + help="Path to the socket file to listen on") + parser.add_argument("--user", default=DEFAULT_USER, metavar="USER", + help="User to use for reduced permissions") + parser.add_argument("--group", default=DEFAULT_GROUP, metavar="GROUP", + help="Group to set ownership of the socket to") + parser.add_argument("--log", dest="logfile", default="/var/log/lorax-composer/composer.log", metavar="LOG", + help="Path to logfile (/var/log/lorax-composer/composer.log)") + parser.add_argument("--mockfiles", default="/var/tmp/bdcs-mockfiles/", metavar="MOCKFILES", + help="Path to JSON files used for /api/mock/ paths (/var/tmp/bdcs-mockfiles/)") + parser.add_argument("--sharedir", type=os.path.abspath, metavar="SHAREDIR", + help="Directory containing all the templates. Overrides config file sharedir") + parser.add_argument("-V", action="store_true", dest="showver", + help="show program's version number and exit") + parser.add_argument("-c", "--config", default="/etc/lorax/composer.conf", metavar="CONFIG", + help="Path to lorax-composer configuration file.") + parser.add_argument("--releasever", default=None, metavar="STRING", + help="Release version to use for $releasever in dnf repository urls") + parser.add_argument("--tmp", default="/var/tmp", + help="Top level temporary directory") + parser.add_argument("--proxy", default=None, metavar="PROXY", + help="Set proxy for DNF, overrides configuration file setting.") + parser.add_argument("--no-system-repos", action="store_true", default=False, + help="Do not copy over system repos from /etc/yum.repos.d/ at startup") + parser.add_argument("BLUEPRINTS", metavar="BLUEPRINTS", + help="Path to the blueprints") + + return parser
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/compose.html b/f32-branch/_modules/pylorax/api/compose.html new file mode 100644 index 00000000..d0d148d1 --- /dev/null +++ b/f32-branch/_modules/pylorax/api/compose.html @@ -0,0 +1,1468 @@ + + + + + + + + + + + pylorax.api.compose — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.compose

    +# Copyright (C) 2018-2019 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +""" Setup for composing an image
    +
    +Adding New Output Types
    +-----------------------
    +
    +The new output type must add a kickstart template to ./share/composer/ where the
    +name of the kickstart (without the trailing .ks) matches the entry in compose_args.
    +
    +The kickstart should not have any url or repo entries, these will be added at build
    +time. The %packages section should be the last thing, and while it can contain mandatory
    +packages required by the output type, it should not have the trailing %end because the
    +package NEVRAs will be appended to it at build time.
    +
    +compose_args should have a name matching the kickstart, and it should set the novirt_install
    +parameters needed to generate the desired output. Other types should be set to False.
    +
    +"""
    +import logging
    +log = logging.getLogger("lorax-composer")
    +
    +import os
    +from glob import glob
    +from io import StringIO
    +from math import ceil
    +import shutil
    +from uuid import uuid4
    +
    +# Use pykickstart to calculate disk image size
    +from pykickstart.parser import KickstartParser
    +from pykickstart.version import makeVersion
    +
    +from pylorax import ArchData, find_templates, get_buildarch
    +from pylorax.api.gitrpm import create_gitrpm_repo
    +from pylorax.api.projects import projects_depsolve, projects_depsolve_with_size, dep_nevra
    +from pylorax.api.projects import ProjectsError
    +from pylorax.api.recipes import read_recipe_and_id
    +from pylorax.api.timestamp import TS_CREATED, write_timestamp
    +import pylorax.api.toml as toml
    +from pylorax.base import DataHolder
    +from pylorax.imgutils import default_image_name
    +from pylorax.ltmpl import LiveTemplateRunner
    +from pylorax.sysutils import joinpaths, flatconfig
    +
    +
    +
    [docs]def test_templates(dbo, share_dir): + """ Try depsolving each of the the templates and report any errors + + :param dbo: dnf base object + :type dbo: dnf.Base + :returns: List of template types and errors + :rtype: List of errors + + Return a list of templates and errors encountered or an empty list + """ + template_errors = [] + for compose_type, enabled in compose_types(share_dir): + if not enabled: + continue + + # Read the kickstart template for this type + ks_template_path = joinpaths(share_dir, "composer", compose_type) + ".ks" + ks_template = open(ks_template_path, "r").read() + + # How much space will the packages in the default template take? + ks_version = makeVersion() + ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False) + ks.readKickstartFromString(ks_template+"\n%end\n") + pkgs = [(name, "*") for name in ks.handler.packages.packageList] + grps = [grp.name for grp in ks.handler.packages.groupList] + try: + projects_depsolve(dbo, pkgs, grps) + except ProjectsError as e: + template_errors.append("Error depsolving %s: %s" % (compose_type, str(e))) + + return template_errors
    + + +
    [docs]def repo_to_ks(r, url="url"): + """ Return a kickstart line with the correct args. + :param r: DNF repository information + :type r: dnf.Repo + :param url: "url" or "baseurl" to use for the baseurl parameter + :type url: str + :returns: kickstart command arguments for url/repo command + :rtype: str + + Set url to "baseurl" if it is a repo, leave it as "url" for the installation url. + """ + cmd = "" + # url uses --url not --baseurl + if r.baseurl: + cmd += '--%s="%s" ' % (url, r.baseurl[0]) + elif r.metalink: + cmd += '--metalink="%s" ' % r.metalink + elif r.mirrorlist: + cmd += '--mirrorlist="%s" ' % r.mirrorlist + else: + raise RuntimeError("Repo has no baseurl, metalink, or mirrorlist") + + if r.proxy: + cmd += '--proxy="%s" ' % r.proxy + + if not r.sslverify: + cmd += '--noverifyssl' + + if r.sslcacert: + cmd += ' --sslcacert="%s"' % r.sslcacert + if r.sslclientcert: + cmd += ' --sslclientcert="%s"' % r.sslclientcert + if r.sslclientkey: + cmd += ' --sslclientkey="%s"' % r.sslclientkey + + return cmd
    + + +
    [docs]def bootloader_append(line, kernel_append): + """ Insert the kernel_append string into the --append argument + + :param line: The bootloader ... line + :type line: str + :param kernel_append: The arguments to append to the --append section + :type kernel_append: str + + Using pykickstart to process the line is the best way to make sure it + is parsed correctly, and re-assembled for inclusion into the final kickstart + """ + ks_version = makeVersion() + ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False) + ks.readKickstartFromString(line) + + if ks.handler.bootloader.appendLine: + ks.handler.bootloader.appendLine += " %s" % kernel_append + else: + ks.handler.bootloader.appendLine = kernel_append + + # Converting back to a string includes a comment, return just the bootloader line + return str(ks.handler.bootloader).splitlines()[-1]
    + + +
    [docs]def get_kernel_append(recipe): + """Return the customizations.kernel append value + + :param recipe: + :type recipe: Recipe object + :returns: append value or empty string + :rtype: str + """ + if "customizations" not in recipe or \ + "kernel" not in recipe["customizations"] or \ + "append" not in recipe["customizations"]["kernel"]: + return "" + return recipe["customizations"]["kernel"]["append"]
    + + +
    [docs]def timezone_cmd(line, settings): + """ Update the timezone line with the settings + + :param line: The timezone ... line + :type line: str + :param settings: A dict with timezone and/or ntpservers list + :type settings: dict + + Using pykickstart to process the line is the best way to make sure it + is parsed correctly, and re-assembled for inclusion into the final kickstart + """ + ks_version = makeVersion() + ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False) + ks.readKickstartFromString(line) + + if "timezone" in settings: + ks.handler.timezone.timezone = settings["timezone"] + if "ntpservers" in settings: + ks.handler.timezone.ntpservers = settings["ntpservers"] + + # Converting back to a string includes a comment, return just the timezone line + return str(ks.handler.timezone).splitlines()[-1]
    + + +
    [docs]def get_timezone_settings(recipe): + """Return the customizations.timezone dict + + :param recipe: + :type recipe: Recipe object + :returns: append value or empty string + :rtype: dict + """ + if "customizations" not in recipe or \ + "timezone" not in recipe["customizations"]: + return {} + return recipe["customizations"]["timezone"]
    + + +
    [docs]def lang_cmd(line, languages): + """ Update the lang line with the languages + + :param line: The lang ... line + :type line: str + :param settings: The list of languages + :type settings: list + + Using pykickstart to process the line is the best way to make sure it + is parsed correctly, and re-assembled for inclusion into the final kickstart + """ + ks_version = makeVersion() + ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False) + ks.readKickstartFromString(line) + + if languages: + ks.handler.lang.lang = languages[0] + + if len(languages) > 1: + ks.handler.lang.addsupport = languages[1:] + + # Converting back to a string includes a comment, return just the lang line + return str(ks.handler.lang).splitlines()[-1]
    + + +
    [docs]def get_languages(recipe): + """Return the customizations.locale.languages list + + :param recipe: The recipe + :type recipe: Recipe object + :returns: list of language strings + :rtype: list + """ + if "customizations" not in recipe or \ + "locale" not in recipe["customizations"] or \ + "languages" not in recipe["customizations"]["locale"]: + return [] + return recipe["customizations"]["locale"]["languages"]
    + + +
    [docs]def keyboard_cmd(line, layout): + """ Update the keyboard line with the layout + + :param line: The keyboard ... line + :type line: str + :param settings: The keyboard layout + :type settings: str + + Using pykickstart to process the line is the best way to make sure it + is parsed correctly, and re-assembled for inclusion into the final kickstart + """ + ks_version = makeVersion() + ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False) + ks.readKickstartFromString(line) + + if layout: + ks.handler.keyboard.keyboard = layout + ks.handler.keyboard.vc_keymap = "" + ks.handler.keyboard.x_layouts = [] + + # Converting back to a string includes a comment, return just the keyboard line + return str(ks.handler.keyboard).splitlines()[-1]
    + + +
    [docs]def get_keyboard_layout(recipe): + """Return the customizations.locale.keyboard list + + :param recipe: The recipe + :type recipe: Recipe object + :returns: The keyboard layout string + :rtype: str + """ + if "customizations" not in recipe or \ + "locale" not in recipe["customizations"] or \ + "keyboard" not in recipe["customizations"]["locale"]: + return [] + return recipe["customizations"]["locale"]["keyboard"]
    + + +
    [docs]def firewall_cmd(line, settings): + """ Update the firewall line with the new ports and services + + :param line: The firewall ... line + :type line: str + :param settings: A dict with the list of services and ports to enable and disable + :type settings: dict + + Using pykickstart to process the line is the best way to make sure it + is parsed correctly, and re-assembled for inclusion into the final kickstart + """ + ks_version = makeVersion() + ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False) + ks.readKickstartFromString(line) + + # Do not override firewall --disabled + if ks.handler.firewall.enabled != False and settings: + ks.handler.firewall.ports = sorted(set(settings["ports"] + ks.handler.firewall.ports)) + ks.handler.firewall.services = sorted(set(settings["enabled"] + ks.handler.firewall.services)) + ks.handler.firewall.remove_services = sorted(set(settings["disabled"] + ks.handler.firewall.remove_services)) + + # Converting back to a string includes a comment, return just the keyboard line + return str(ks.handler.firewall).splitlines()[-1]
    + + +
    [docs]def get_firewall_settings(recipe): + """Return the customizations.firewall settings + + :param recipe: The recipe + :type recipe: Recipe object + :returns: A dict of settings + :rtype: dict + """ + settings = {"ports": [], "enabled": [], "disabled": []} + + if "customizations" not in recipe or \ + "firewall" not in recipe["customizations"]: + return settings + + settings["ports"] = recipe["customizations"]["firewall"].get("ports", []) + + if "services" in recipe["customizations"]["firewall"]: + settings["enabled"] = recipe["customizations"]["firewall"]["services"].get("enabled", []) + settings["disabled"] = recipe["customizations"]["firewall"]["services"].get("disabled", []) + return settings
    + + +
    [docs]def services_cmd(line, settings): + """ Update the services line with additional services to enable/disable + + :param line: The services ... line + :type line: str + :param settings: A dict with the list of services to enable and disable + :type settings: dict + + Using pykickstart to process the line is the best way to make sure it + is parsed correctly, and re-assembled for inclusion into the final kickstart + """ + # Empty services and no additional settings, return an empty string + if not line and not settings["enabled"] and not settings["disabled"]: + return "" + + ks_version = makeVersion() + ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False) + + # Allow passing in a 'default' so that the enable/disable may be applied to it, without + # parsing it and emitting a kickstart error message + if line != "services": + ks.readKickstartFromString(line) + + # Add to any existing services, removing any duplicates + ks.handler.services.enabled = sorted(set(settings["enabled"] + ks.handler.services.enabled)) + ks.handler.services.disabled = sorted(set(settings["disabled"] + ks.handler.services.disabled)) + + # Converting back to a string includes a comment, return just the keyboard line + return str(ks.handler.services).splitlines()[-1]
    + + +
    [docs]def get_services(recipe): + """Return the customizations.services settings + + :param recipe: The recipe + :type recipe: Recipe object + :returns: A dict of settings + :rtype: dict + """ + settings = {"enabled": [], "disabled": []} + + if "customizations" not in recipe or \ + "services" not in recipe["customizations"]: + return settings + + settings["enabled"] = sorted(recipe["customizations"]["services"].get("enabled", [])) + settings["disabled"] = sorted(recipe["customizations"]["services"].get("disabled", [])) + return settings
    + + +
    [docs]def get_default_services(recipe): + """Get the default string for services, based on recipe + :param recipe: The recipe + + :type recipe: Recipe object + :returns: string with "services" or "" + :rtype: str + + When no services have been selected we don't need to add anything to the kickstart + so return an empty string. Otherwise return "services" which will be updated with + the settings. + """ + services = get_services(recipe) + + if services["enabled"] or services["disabled"]: + return "services" + else: + return ""
    + + +
    [docs]def customize_ks_template(ks_template, recipe): + """ Customize the kickstart template and return it + + :param ks_template: The kickstart template + :type ks_template: str + :param recipe: + :type recipe: Recipe object + + Apply customizations to existing template commands, or add defaults for ones that are + missing and required. + + Apply customizations.kernel.append to the bootloader argument in the template. + Add bootloader line if it is missing. + + Add default timezone if needed. It does NOT replace an existing timezone entry + """ + # Commands to be modified [NEW-COMMAND-FUNC, NEW-VALUE, DEFAULT, REPLACE] + # The function is called with a kickstart command string and the value to replace + # The value is specific to the command, and is understood by the function + # The default is a complete kickstart command string, suitable for writing to the template + # If REPLACE is False it will not change an existing entry only add a missing one + commands = {"bootloader": [bootloader_append, + get_kernel_append(recipe), + 'bootloader --location=none', True], + "timezone": [timezone_cmd, + get_timezone_settings(recipe), + 'timezone UTC', False], + "lang": [lang_cmd, + get_languages(recipe), + 'lang en_US.UTF-8', True], + "keyboard": [keyboard_cmd, + get_keyboard_layout(recipe), + 'keyboard --xlayouts us --vckeymap us', True], + "firewall": [firewall_cmd, + get_firewall_settings(recipe), + 'firewall --enabled', True], + "services": [services_cmd, + get_services(recipe), + get_default_services(recipe), True] + } + found = {} + + output = StringIO() + for line in ks_template.splitlines(): + for cmd in commands: + (new_command, value, default, replace) = commands[cmd] + if line.startswith(cmd): + found[cmd] = True + if value and replace: + log.debug("Replacing %s with %s", cmd, value) + print(new_command(line, value), file=output) + else: + log.debug("Skipping %s", cmd) + print(line, file=output) + break + else: + # No matches, write the line as-is + print(line, file=output) + + # Write out defaults for the ones not found + # These must go FIRST because the template still needs to have the packages added + defaults = StringIO() + for cmd in commands: + if cmd in found: + continue + (new_command, value, default, _) = commands[cmd] + if value and default: + log.debug("Setting %s to use %s", cmd, value) + print(new_command(default, value), file=defaults) + elif default: + log.debug("Setting %s to %s", cmd, default) + print(default, file=defaults) + + return defaults.getvalue() + output.getvalue()
    + + +
    [docs]def write_ks_root(f, user): + """ Write kickstart root password and sshkey entry + + :param f: kickstart file object + :type f: open file object + :param user: A blueprint user dictionary + :type user: dict + :returns: True if it wrote a rootpw command to the kickstart + :rtype: bool + + If the entry contains a ssh key, use sshkey to write it + If it contains password, use rootpw to set it + + root cannot be used with the user command. So only key and password are supported + for root. + """ + wrote_rootpw = False + + # ssh key uses the sshkey kickstart command + if "key" in user: + f.write('sshkey --user %s "%s"\n' % (user["name"], user["key"])) + + if "password" in user: + if any(user["password"].startswith(prefix) for prefix in ["$2b$", "$6$", "$5$"]): + log.debug("Detected pre-crypted password") + f.write('rootpw --iscrypted "%s"\n' % user["password"]) + wrote_rootpw = True + else: + log.debug("Detected plaintext password") + f.write('rootpw --plaintext "%s"\n' % user["password"]) + wrote_rootpw = True + + return wrote_rootpw
    + +
    [docs]def write_ks_user(f, user): + """ Write kickstart user and sshkey entry + + :param f: kickstart file object + :type f: open file object + :param user: A blueprint user dictionary + :type user: dict + + If the entry contains a ssh key, use sshkey to write it + All of the user fields are optional, except name, write out a kickstart user entry + with whatever options are relevant. + """ + # ssh key uses the sshkey kickstart command + if "key" in user: + f.write('sshkey --user %s "%s"\n' % (user["name"], user["key"])) + + # Write out the user kickstart command, much of it is optional + f.write("user --name %s" % user["name"]) + if "home" in user: + f.write(" --homedir %s" % user["home"]) + + if "password" in user: + if any(user["password"].startswith(prefix) for prefix in ["$2b$", "$6$", "$5$"]): + log.debug("Detected pre-crypted password") + f.write(" --iscrypted") + else: + log.debug("Detected plaintext password") + f.write(" --plaintext") + + f.write(" --password \"%s\"" % user["password"]) + + if "shell" in user: + f.write(" --shell %s" % user["shell"]) + + if "uid" in user: + f.write(" --uid %d" % int(user["uid"])) + + if "gid" in user: + f.write(" --gid %d" % int(user["gid"])) + + if "description" in user: + f.write(" --gecos \"%s\"" % user["description"]) + + if "groups" in user: + f.write(" --groups %s" % ",".join(user["groups"])) + + f.write("\n")
    + + +
    [docs]def write_ks_group(f, group): + """ Write kickstart group entry + + :param f: kickstart file object + :type f: open file object + :param group: A blueprint group dictionary + :type user: dict + + gid is optional + """ + if "name" not in group: + raise RuntimeError("group entry requires a name") + + f.write("group --name %s" % group["name"]) + if "gid" in group: + f.write(" --gid %d" % int(group["gid"])) + + f.write("\n")
    + + +
    [docs]def add_customizations(f, recipe): + """ Add customizations to the kickstart file + + :param f: kickstart file object + :type f: open file object + :param recipe: + :type recipe: Recipe object + :returns: None + :raises: RuntimeError if there was a problem writing to the kickstart + """ + if "customizations" not in recipe: + f.write('rootpw --lock\n') + return + customizations = recipe["customizations"] + + # allow customizations to be incorrectly specified as [[customizations]] instead of [customizations] + if isinstance(customizations, list): + customizations = customizations[0] + + if "hostname" in customizations: + f.write("network --hostname=%s\n" % customizations["hostname"]) + + # TODO - remove this, should use user section to define this + if "sshkey" in customizations: + # This is a list of entries + for sshkey in customizations["sshkey"]: + if "user" not in sshkey or "key" not in sshkey: + log.error("%s is incorrect, skipping", sshkey) + continue + f.write('sshkey --user %s "%s"\n' % (sshkey["user"], sshkey["key"])) + + # Creating a user also creates a group. Make a list of the names for later + user_groups = [] + # kickstart requires a rootpw line + wrote_rootpw = False + if "user" in customizations: + # only name is required, everything else is optional + for user in customizations["user"]: + if "name" not in user: + raise RuntimeError("user entry requires a name") + + # root is special, cannot use normal user command for it + if user["name"] == "root": + wrote_rootpw = write_ks_root(f, user) + continue + + write_ks_user(f, user) + user_groups.append(user["name"]) + + if "group" in customizations: + for group in customizations["group"]: + if group["name"] not in user_groups: + write_ks_group(f, group) + else: + log.warning("Skipping group %s, already created by user", group["name"]) + + # Lock the root account if no root user password has been specified + if not wrote_rootpw: + f.write('rootpw --lock\n')
    + + +
    [docs]def get_extra_pkgs(dbo, share_dir, compose_type): + """Return extra packages needed for the output type + + :param dbo: dnf base object + :type dbo: dnf.Base + :param share_dir: Path to the top level share directory + :type share_dir: str + :param compose_type: The type of output to create from the recipe + :type compose_type: str + :returns: List of package names (name only, not NEVRA) + :rtype: list + + Currently this is only needed by live-iso, it reads ./live/live-install.tmpl and + processes only the installpkg lines. It lists the packages needed to complete creation of the + iso using the templates such as x86.tmpl + + Keep in mind that the live-install.tmpl is shared between livemedia-creator and lorax-composer, + even though the results are applied differently. + """ + if compose_type != "live-iso": + return [] + + # get the arch information to pass to the runner + arch = ArchData(get_buildarch(dbo)) + defaults = DataHolder(basearch=arch.basearch) + templatedir = joinpaths(find_templates(share_dir), "live") + runner = LiveTemplateRunner(dbo, templatedir=templatedir, defaults=defaults) + runner.run("live-install.tmpl") + log.debug("extra pkgs = %s", runner.pkgs) + + return runner.pkgnames
    + + +
    [docs]def start_build(cfg, dnflock, gitlock, branch, recipe_name, compose_type, test_mode=0): + """ Start the build + + :param cfg: Configuration object + :type cfg: ComposerConfig + :param dnflock: Lock and YumBase for depsolving + :type dnflock: YumLock + :param recipe: The recipe to build + :type recipe: str + :param compose_type: The type of output to create from the recipe + :type compose_type: str + :returns: Unique ID for the build that can be used to track its status + :rtype: str + """ + share_dir = cfg.get("composer", "share_dir") + lib_dir = cfg.get("composer", "lib_dir") + + # Make sure compose_type is valid, only allow enabled types + type_enabled = dict(compose_types(share_dir)).get(compose_type) + if type_enabled is None: + raise RuntimeError("Invalid compose type (%s), must be one of %s" % (compose_type, [t for t, e in compose_types(share_dir)])) + if not type_enabled: + raise RuntimeError("Compose type '%s' is disabled on this architecture" % compose_type) + + # Some image types (live-iso) need extra packages for composer to execute the output template + with dnflock.lock: + extra_pkgs = get_extra_pkgs(dnflock.dbo, share_dir, compose_type) + log.debug("Extra packages needed for %s: %s", compose_type, extra_pkgs) + + with gitlock.lock: + (commit_id, recipe) = read_recipe_and_id(gitlock.repo, branch, recipe_name) + + # Combine modules and packages and depsolve the list + module_nver = recipe.module_nver + package_nver = recipe.package_nver + package_nver.extend([(name, '*') for name in extra_pkgs]) + + projects = sorted(set(module_nver+package_nver), key=lambda p: p[0].lower()) + deps = [] + log.info("depsolving %s", recipe["name"]) + try: + # This can possibly update repodata and reset the YumBase object. + with dnflock.lock_check: + (installed_size, deps) = projects_depsolve_with_size(dnflock.dbo, projects, recipe.group_names, with_core=False) + except ProjectsError as e: + log.error("start_build depsolve: %s", str(e)) + raise RuntimeError("Problem depsolving %s: %s" % (recipe["name"], str(e))) + + # Read the kickstart template for this type + ks_template_path = joinpaths(share_dir, "composer", compose_type) + ".ks" + ks_template = open(ks_template_path, "r").read() + + # How much space will the packages in the default template take? + ks_version = makeVersion() + ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False) + ks.readKickstartFromString(ks_template+"\n%end\n") + pkgs = [(name, "*") for name in ks.handler.packages.packageList] + grps = [grp.name for grp in ks.handler.packages.groupList] + try: + with dnflock.lock: + (template_size, _) = projects_depsolve_with_size(dnflock.dbo, pkgs, grps, with_core=not ks.handler.packages.nocore) + except ProjectsError as e: + log.error("start_build depsolve: %s", str(e)) + raise RuntimeError("Problem depsolving %s: %s" % (recipe["name"], str(e))) + log.debug("installed_size = %d, template_size=%d", installed_size, template_size) + + # Minimum LMC disk size is 1GiB, and anaconda bumps the estimated size up by 10% (which doesn't always work). + installed_size = int((installed_size+template_size)) * 1.2 + log.debug("/ partition size = %d", installed_size) + + # Create the results directory + build_id = str(uuid4()) + results_dir = joinpaths(lib_dir, "results", build_id) + os.makedirs(results_dir) + + # Write the recipe commit hash + commit_path = joinpaths(results_dir, "COMMIT") + with open(commit_path, "w") as f: + f.write(commit_id) + + # Write the original recipe + recipe_path = joinpaths(results_dir, "blueprint.toml") + with open(recipe_path, "w") as f: + f.write(recipe.toml()) + + # Write the frozen recipe + frozen_recipe = recipe.freeze(deps) + recipe_path = joinpaths(results_dir, "frozen.toml") + with open(recipe_path, "w") as f: + f.write(frozen_recipe.toml()) + + # Write out the dependencies to the results dir + deps_path = joinpaths(results_dir, "deps.toml") + with open(deps_path, "w") as f: + f.write(toml.dumps({"packages":deps})) + + # Save a copy of the original kickstart + shutil.copy(ks_template_path, results_dir) + + with dnflock.lock: + repos = list(dnflock.dbo.repos.iter_enabled()) + if not repos: + raise RuntimeError("No enabled repos, canceling build.") + + # Create the git rpms, if any, and return the path to the repo under results_dir + gitrpm_repo = create_gitrpm_repo(results_dir, recipe) + + # Create the final kickstart with repos and package list + ks_path = joinpaths(results_dir, "final-kickstart.ks") + with open(ks_path, "w") as f: + ks_url = repo_to_ks(repos[0], "url") + log.debug("url = %s", ks_url) + f.write('url %s\n' % ks_url) + for idx, r in enumerate(repos[1:]): + ks_repo = repo_to_ks(r, "baseurl") + log.debug("repo composer-%s = %s", idx, ks_repo) + f.write('repo --name="composer-%s" %s\n' % (idx, ks_repo)) + + if gitrpm_repo: + log.debug("repo gitrpms = %s", gitrpm_repo) + f.write('repo --name="gitrpms" --baseurl="file://%s"\n' % gitrpm_repo) + + # Setup the disk for booting + # TODO Add GPT and UEFI boot support + f.write('clearpart --all --initlabel\n') + + # Write the root partition and it's size in MB (rounded up) + f.write('part / --size=%d\n' % ceil(installed_size / 1024**2)) + + # Some customizations modify the template before writing it + f.write(customize_ks_template(ks_template, recipe)) + + for d in deps: + f.write(dep_nevra(d)+"\n") + + # Include the rpms from the gitrpm repo directory + if gitrpm_repo: + for rpm in glob(os.path.join(gitrpm_repo, "*.rpm")): + f.write(os.path.basename(rpm)[:-4]+"\n") + + f.write("%end\n") + + # Other customizations can be appended to the kickstart + add_customizations(f, recipe) + + # Setup the config to pass to novirt_install + log_dir = joinpaths(results_dir, "logs/") + cfg_args = compose_args(compose_type) + + # Get the title, project, and release version from the host + if not os.path.exists("/etc/os-release"): + log.error("/etc/os-release is missing, cannot determine product or release version") + os_release = flatconfig("/etc/os-release") + + log.debug("os_release = %s", dict(os_release.items())) + + cfg_args["title"] = os_release.get("PRETTY_NAME", "") + cfg_args["project"] = os_release.get("NAME", "") + cfg_args["releasever"] = os_release.get("VERSION_ID", "") + cfg_args["volid"] = "" + cfg_args["extra_boot_args"] = get_kernel_append(recipe) + + if "compression" not in cfg_args: + cfg_args["compression"] = "xz" + + if "compress_args" not in cfg_args: + cfg_args["compress_args"] = [] + + cfg_args.update({ + "ks": [ks_path], + "logfile": log_dir, + "timeout": 60, # 60 minute timeout + }) + with open(joinpaths(results_dir, "config.toml"), "w") as f: + f.write(toml.dumps(cfg_args)) + + # Set the initial status + open(joinpaths(results_dir, "STATUS"), "w").write("WAITING") + + # Set the test mode, if requested + if test_mode > 0: + open(joinpaths(results_dir, "TEST"), "w").write("%s" % test_mode) + + write_timestamp(results_dir, TS_CREATED) + log.info("Adding %s (%s %s) to compose queue", build_id, recipe["name"], compose_type) + os.symlink(results_dir, joinpaths(lib_dir, "queue/new/", build_id)) + + return build_id
    + +# Supported output types +
    [docs]def compose_types(share_dir): + r""" Returns a list of tuples of the supported output types, and their state + + The output types come from the kickstart names in /usr/share/lorax/composer/\*ks + + If they are disabled on the current arch their state is False. If enabled, it is True. + eg. [("alibaba", False), ("ext4-filesystem", True), ...] + """ + # These are compose types that are not supported on an architecture. eg. hyper-v on s390 + # If it is not listed, it is allowed + disable_map = { + "arm": ["alibaba", "ami", "google", "hyper-v", "vhd", "vmdk"], + "armhfp": ["alibaba", "ami", "google", "hyper-v", "vhd", "vmdk"], + "aarch64": ["alibaba", "google", "hyper-v", "vhd", "vmdk"], + "ppc": ["alibaba", "ami", "google", "hyper-v", "vhd", "vmdk"], + "ppc64": ["alibaba", "ami", "google", "hyper-v", "vhd", "vmdk"], + "ppc64le": ["alibaba", "ami", "google", "hyper-v", "vhd", "vmdk"], + "s390": ["alibaba", "ami", "google", "hyper-v", "vhd", "vmdk"], + "s390x": ["alibaba", "ami", "google", "hyper-v", "vhd", "vmdk"], + } + + all_types = sorted([os.path.basename(ks)[:-3] for ks in glob(joinpaths(share_dir, "composer/*.ks"))]) + arch_disabled = disable_map.get(os.uname().machine, []) + + return [(t, t not in arch_disabled) for t in all_types]
    + +
    [docs]def compose_args(compose_type): + """ Returns the settings to pass to novirt_install for the compose type + + :param compose_type: The type of compose to create, from `compose_types()` + :type compose_type: str + + This will return a dict of options that match the ArgumentParser options for livemedia-creator. + These are the ones the define the type of output, it's filename, etc. + Other options will be filled in by `make_compose()` + """ + _MAP = {"tar": {"make_iso": False, + "make_disk": False, + "make_fsimage": False, + "make_appliance": False, + "make_ami": False, + "make_tar": True, + "make_tar_disk": False, + "make_pxe_live": False, + "make_ostree_live": False, + "make_oci": False, + "make_vagrant": False, + "ostree": False, + "live_rootfs_keep_size": False, + "live_rootfs_size": 0, + "image_size_align": 0, + "image_type": False, # False instead of None because of TOML + "qemu_args": [], + "image_name": default_image_name("xz", "root.tar"), + "tar_disk_name": None, + "image_only": True, + "app_name": None, + "app_template": None, + "app_file": None, + "squashfs_only": False, + }, + "liveimg-tar": {"make_iso": False, + "make_disk": False, + "make_fsimage": False, + "make_appliance": False, + "make_ami": False, + "make_tar": True, + "make_tar_disk": False, + "make_pxe_live": False, + "make_ostree_live": False, + "make_oci": False, + "make_vagrant": False, + "ostree": False, + "live_rootfs_keep_size": False, + "live_rootfs_size": 0, + "image_size_align": 0, + "image_type": False, # False instead of None because of TOML + "qemu_args": [], + "image_name": default_image_name("xz", "root.tar"), + "tar_disk_name": None, + "image_only": True, + "app_name": None, + "app_template": None, + "app_file": None, + "squashfs_only": False, + }, + "live-iso": {"make_iso": True, + "make_disk": False, + "make_fsimage": False, + "make_appliance": False, + "make_ami": False, + "make_tar": False, + "make_tar_disk": False, + "make_pxe_live": False, + "make_ostree_live": False, + "make_oci": False, + "make_vagrant": False, + "ostree": False, + "live_rootfs_keep_size": False, + "live_rootfs_size": 0, + "image_size_align": 0, + "image_type": False, # False instead of None because of TOML + "qemu_args": [], + "image_name": "live.iso", + "tar_disk_name": None, + "fs_label": "Anaconda", # Live booting may expect this to be 'Anaconda' + "image_only": False, + "app_name": None, + "app_template": None, + "app_file": None, + "iso_only": True, + "iso_name": "live.iso", + "squashfs_only": False, + }, + "partitioned-disk": {"make_iso": False, + "make_disk": True, + "make_fsimage": False, + "make_appliance": False, + "make_ami": False, + "make_tar": False, + "make_tar_disk": False, + "make_pxe_live": False, + "make_ostree_live": False, + "make_oci": False, + "make_vagrant": False, + "ostree": False, + "live_rootfs_keep_size": False, + "live_rootfs_size": 0, + "image_size_align": 0, + "image_type": False, # False instead of None because of TOML + "qemu_args": [], + "image_name": "disk.img", + "tar_disk_name": None, + "fs_label": "", + "image_only": True, + "app_name": None, + "app_template": None, + "app_file": None, + "squashfs_only": False, + }, + "qcow2": {"make_iso": False, + "make_disk": True, + "make_fsimage": False, + "make_appliance": False, + "make_ami": False, + "make_tar": False, + "make_tar_disk": False, + "make_pxe_live": False, + "make_ostree_live": False, + "make_oci": False, + "make_vagrant": False, + "ostree": False, + "live_rootfs_keep_size": False, + "live_rootfs_size": 0, + "image_size_align": 0, + "image_type": "qcow2", + "qemu_args": [], + "image_name": "disk.qcow2", + "tar_disk_name": None, + "fs_label": "", + "image_only": True, + "app_name": None, + "app_template": None, + "app_file": None, + "squashfs_only": False, + }, + "ext4-filesystem": {"make_iso": False, + "make_disk": False, + "make_fsimage": True, + "make_appliance": False, + "make_ami": False, + "make_tar": False, + "make_tar_disk": False, + "make_pxe_live": False, + "make_ostree_live": False, + "make_oci": False, + "make_vagrant": False, + "ostree": False, + "live_rootfs_keep_size": False, + "live_rootfs_size": 0, + "image_size_align": 0, + "image_type": False, # False instead of None because of TOML + "qemu_args": [], + "image_name": "filesystem.img", + "tar_disk_name": None, + "fs_label": "", + "image_only": True, + "app_name": None, + "app_template": None, + "app_file": None, + "squashfs_only": False, + }, + "ami": {"make_iso": False, + "make_disk": True, + "make_fsimage": False, + "make_appliance": False, + "make_ami": False, + "make_tar": False, + "make_tar_disk": False, + "make_pxe_live": False, + "make_ostree_live": False, + "make_oci": False, + "make_vagrant": False, + "ostree": False, + "live_rootfs_keep_size": False, + "live_rootfs_size": 0, + "image_size_align": 0, + "image_type": False, + "qemu_args": [], + "image_name": "disk.ami", + "tar_disk_name": None, + "fs_label": "", + "image_only": True, + "app_name": None, + "app_template": None, + "app_file": None, + "squashfs_only": False, + }, + "vhd": {"make_iso": False, + "make_disk": True, + "make_fsimage": False, + "make_appliance": False, + "make_ami": False, + "make_tar": False, + "make_tar_disk": False, + "make_pxe_live": False, + "make_ostree_live": False, + "make_oci": False, + "make_vagrant": False, + "ostree": False, + "live_rootfs_keep_size": False, + "live_rootfs_size": 0, + "image_size_align": 0, + "image_type": "vpc", + "qemu_args": ["-o", "subformat=fixed,force_size"], + "image_name": "disk.vhd", + "tar_disk_name": None, + "fs_label": "", + "image_only": True, + "app_name": None, + "app_template": None, + "app_file": None, + "squashfs_only": False, + }, + "vmdk": {"make_iso": False, + "make_disk": True, + "make_fsimage": False, + "make_appliance": False, + "make_ami": False, + "make_tar": False, + "make_tar_disk": False, + "make_pxe_live": False, + "make_ostree_live": False, + "make_oci": False, + "make_vagrant": False, + "ostree": False, + "live_rootfs_keep_size": False, + "live_rootfs_size": 0, + "image_size_align": 0, + "image_type": "vmdk", + "qemu_args": [], + "image_name": "disk.vmdk", + "tar_disk_name": None, + "fs_label": "", + "image_only": True, + "app_name": None, + "app_template": None, + "app_file": None, + "squashfs_only": False, + }, + "openstack": {"make_iso": False, + "make_disk": True, + "make_fsimage": False, + "make_appliance": False, + "make_ami": False, + "make_tar": False, + "make_tar_disk": False, + "make_pxe_live": False, + "make_ostree_live": False, + "make_oci": False, + "make_vagrant": False, + "ostree": False, + "live_rootfs_keep_size": False, + "live_rootfs_size": 0, + "image_size_align": 0, + "image_type": "qcow2", + "qemu_args": [], + "image_name": "disk.qcow2", + "tar_disk_name": None, + "fs_label": "", + "image_only": True, + "app_name": None, + "app_template": None, + "app_file": None, + "squashfs_only": False, + }, + "google": {"make_iso": False, + "make_disk": True, + "make_fsimage": False, + "make_appliance": False, + "make_ami": False, + "make_tar": False, + "make_tar_disk": True, + "make_pxe_live": False, + "make_ostree_live": False, + "make_oci": False, + "make_vagrant": False, + "ostree": False, + "live_rootfs_keep_size": False, + "live_rootfs_size": 0, + "image_size_align": 1024, + "image_type": False, # False instead of None because of TOML + "qemu_args": [], + "image_name": "disk.tar.gz", + "tar_disk_name": "disk.raw", + "compression": "gzip", + "compress_args": ["-9"], + "fs_label": "", + "image_only": True, + "app_name": None, + "app_template": None, + "app_file": None, + "squashfs_only": False, + }, + "hyper-v": {"make_iso": False, + "make_disk": True, + "make_fsimage": False, + "make_appliance": False, + "make_ami": False, + "make_tar": False, + "make_tar_disk": False, + "make_pxe_live": False, + "make_ostree_live": False, + "make_oci": False, + "make_vagrant": False, + "ostree": False, + "live_rootfs_keep_size": False, + "live_rootfs_size": 0, + "image_size_align": 0, + "image_type": "vhdx", + "qemu_args": [], + "image_name": "disk.vhdx", + "tar_disk_name": None, + "fs_label": "", + "image_only": True, + "app_name": None, + "app_template": None, + "app_file": None, + "squashfs_only": False, + }, + "alibaba": {"make_iso": False, + "make_disk": True, + "make_fsimage": False, + "make_appliance": False, + "make_ami": False, + "make_tar": False, + "make_tar_disk": False, + "make_pxe_live": False, + "make_ostree_live": False, + "make_oci": False, + "make_vagrant": False, + "ostree": False, + "live_rootfs_keep_size": False, + "live_rootfs_size": 0, + "image_size_align": 0, + "image_type": "qcow2", + "qemu_args": [], + "image_name": "disk.qcow2", + "tar_disk_name": None, + "fs_label": "", + "image_only": True, + "app_name": None, + "app_template": None, + "app_file": None, + "squashfs_only": False, + }, + } + return _MAP[compose_type]
    + +
    [docs]def move_compose_results(cfg, results_dir): + """Move the final image to the results_dir and cleanup the unneeded compose files + + :param cfg: Build configuration + :type cfg: DataHolder + :param results_dir: Directory to put the results into + :type results_dir: str + """ + if cfg["make_tar"]: + shutil.move(joinpaths(cfg["result_dir"], cfg["image_name"]), results_dir) + elif cfg["make_iso"]: + # Output from live iso is always a boot.iso under images/, move and rename it + shutil.move(joinpaths(cfg["result_dir"], cfg["iso_name"]), joinpaths(results_dir, cfg["image_name"])) + elif cfg["make_disk"] or cfg["make_fsimage"]: + shutil.move(joinpaths(cfg["result_dir"], cfg["image_name"]), joinpaths(results_dir, cfg["image_name"])) + + + # Cleanup the compose directory, but only if it looks like a compose directory + if os.path.basename(cfg["result_dir"]) == "compose": + shutil.rmtree(cfg["result_dir"]) + else: + log.error("Incorrect compose directory, not cleaning up")
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/config.html b/f32-branch/_modules/pylorax/api/config.html new file mode 100644 index 00000000..4964426a --- /dev/null +++ b/f32-branch/_modules/pylorax/api/config.html @@ -0,0 +1,341 @@ + + + + + + + + + + + pylorax.api.config — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.config

    +#
    +# Copyright (C) 2017  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import configparser
    +import grp
    +import os
    +import pwd
    +
    +from pylorax.sysutils import joinpaths
    +
    +
    [docs]class ComposerConfig(configparser.ConfigParser): +
    [docs] def get_default(self, section, option, default): + try: + return self.get(section, option) + except configparser.Error: + return default
    + + +
    [docs]def configure(conf_file="/etc/lorax/composer.conf", root_dir="/", test_config=False): + """lorax-composer configuration + + :param conf_file: Path to the config file overriding the default settings + :type conf_file: str + :param root_dir: Directory to prepend to paths, defaults to / + :type root_dir: str + :param test_config: Set to True to skip reading conf_file + :type test_config: bool + :returns: Configuration + :rtype: ComposerConfig + """ + conf = ComposerConfig() + + # set defaults + conf.add_section("composer") + conf.set("composer", "share_dir", os.path.realpath(joinpaths(root_dir, "/usr/share/lorax/"))) + conf.set("composer", "lib_dir", os.path.realpath(joinpaths(root_dir, "/var/lib/lorax/composer/"))) + conf.set("composer", "repo_dir", os.path.realpath(joinpaths(root_dir, "/var/lib/lorax/composer/repos.d/"))) + conf.set("composer", "dnf_conf", os.path.realpath(joinpaths(root_dir, "/var/tmp/composer/dnf.conf"))) + conf.set("composer", "dnf_root", os.path.realpath(joinpaths(root_dir, "/var/tmp/composer/dnf/root/"))) + conf.set("composer", "cache_dir", os.path.realpath(joinpaths(root_dir, "/var/tmp/composer/cache/"))) + conf.set("composer", "tmp", os.path.realpath(joinpaths(root_dir, "/var/tmp/"))) + + conf.add_section("users") + conf.set("users", "root", "1") + + # Enable all available repo files by default + conf.add_section("repos") + conf.set("repos", "use_system_repos", "1") + conf.set("repos", "enabled", "*") + + conf.add_section("dnf") + + if not test_config: + # read the config file + if os.path.isfile(conf_file): + conf.read(conf_file) + + return conf
    + +
    [docs]def make_owned_dir(p_dir, uid, gid): + """Make a directory and its parents, setting owner and group + + :param p_dir: path to directory to create + :type p_dir: string + :param uid: uid of owner + :type uid: int + :param gid: gid of owner + :type gid: int + :returns: list of errors + :rtype: list of str + + Check to make sure it does not have o+rw permissions and that it is owned by uid:gid + """ + errors = [] + if not os.path.isdir(p_dir): + # Make sure no o+rw permissions are set + orig_umask = os.umask(0o006) + os.makedirs(p_dir, 0o771) + os.chown(p_dir, uid, gid) + os.umask(orig_umask) + else: + p_stat = os.stat(p_dir) + if p_stat.st_mode & 0o006 != 0: + errors.append("Incorrect permissions on %s, no o+rw permissions are allowed." % p_dir) + + if p_stat.st_gid != gid or p_stat.st_uid != 0: + gr_name = grp.getgrgid(gid).gr_name + u_name = pwd.getpwuid(uid) + errors.append("%s should be owned by %s:%s" % (p_dir, u_name, gr_name)) + + return errors
    + +
    [docs]def make_dnf_dirs(conf, uid, gid): + """Make any missing dnf directories owned by user:group + + :param conf: The configuration to use + :type conf: ComposerConfig + :param uid: uid of owner + :type uid: int + :param gid: gid of owner + :type gid: int + :returns: list of errors + :rtype: list of str + """ + errors = [] + for p in ["dnf_conf", "repo_dir", "cache_dir", "dnf_root"]: + p_dir = os.path.abspath(conf.get("composer", p)) + if p == "dnf_conf": + p_dir = os.path.dirname(p_dir) + errors.extend(make_owned_dir(p_dir, uid, gid))
    + +
    [docs]def make_queue_dirs(conf, gid): + """Make any missing queue directories + + :param conf: The configuration to use + :type conf: ComposerConfig + :param gid: Group ID that has access to the queue directories + :type gid: int + :returns: list of errors + :rtype: list of str + """ + errors = [] + lib_dir = conf.get("composer", "lib_dir") + for p in ["queue/run", "queue/new", "results"]: + p_dir = joinpaths(lib_dir, p) + errors.extend(make_owned_dir(p_dir, 0, gid)) + return errors
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/crossdomain.html b/f32-branch/_modules/pylorax/api/crossdomain.html new file mode 100644 index 00000000..d8f653fe --- /dev/null +++ b/f32-branch/_modules/pylorax/api/crossdomain.html @@ -0,0 +1,264 @@ + + + + + + + + + + + pylorax.api.crossdomain — Lorax 31.7 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.crossdomain

    +#
    +# Copyright (C) 2017  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +# crossdomain decorator from - http://flask.pocoo.org/snippets/56/
    +from datetime import timedelta
    +from flask import make_response, request, current_app
    +from functools import update_wrapper
    +
    +
    +
    [docs]def crossdomain(origin, methods=None, headers=None, + max_age=21600, attach_to_all=True, + automatic_options=True): + if methods is not None: + methods = ', '.join(sorted(x.upper() for x in methods)) + if headers is not None and not isinstance(headers, str): + headers = ', '.join(x.upper() for x in headers) + if not isinstance(origin, list): + origin = [origin] + if isinstance(max_age, timedelta): + max_age = int(max_age.total_seconds()) + + def get_methods(): + if methods is not None: + return methods + + options_resp = current_app.make_default_options_response() + return options_resp.headers['allow'] + + def decorator(f): + def wrapped_function(*args, **kwargs): + if automatic_options and request.method == 'OPTIONS': + resp = current_app.make_default_options_response() + else: + resp = make_response(f(*args, **kwargs)) + if not attach_to_all and request.method != 'OPTIONS': + return resp + + h = resp.headers + + h.extend([("Access-Control-Allow-Origin", orig) for orig in origin]) + h['Access-Control-Allow-Methods'] = get_methods() + h['Access-Control-Max-Age'] = str(max_age) + if headers is not None: + h['Access-Control-Allow-Headers'] = headers + return resp + + f.provide_automatic_options = False + f.required_methods = ['OPTIONS'] + return update_wrapper(wrapped_function, f) + return decorator
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/dnfbase.html b/f32-branch/_modules/pylorax/api/dnfbase.html new file mode 100644 index 00000000..dda95ebe --- /dev/null +++ b/f32-branch/_modules/pylorax/api/dnfbase.html @@ -0,0 +1,387 @@ + + + + + + + + + + + pylorax.api.dnfbase — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.dnfbase

    +#
    +# Copyright (C) 2017-2018 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# pylint: disable=bad-preconf-access
    +
    +import logging
    +log = logging.getLogger("lorax-composer")
    +
    +import dnf
    +import dnf.logging
    +from glob import glob
    +import os
    +import shutil
    +from threading import Lock
    +import time
    +
    +from pylorax import DEFAULT_PLATFORM_ID
    +from pylorax.sysutils import flatconfig
    +
    +
    [docs]class DNFLock(object): + """Hold the dnf.Base object and a Lock to control access to it. + + self.dbo is a property that returns the dnf.Base object, but it *may* change + from one call to the next if the upstream repositories have changed. + """ + def __init__(self, conf, expire_secs=6*60*60): + self._conf = conf + self._lock = Lock() + self.dbo = get_base_object(self._conf) + self._expire_secs = expire_secs + self._expire_time = time.time() + self._expire_secs + + @property + def lock(self): + """Check for repo updates (using expiration time) and return the lock + + If the repository has been updated, tear down the old dnf.Base and + create a new one. This is the only way to force dnf to use the new + metadata. + """ + if time.time() > self._expire_time: + return self.lock_check + return self._lock + + @property + def lock_check(self): + """Force a check for repo updates and return the lock + + Use this method sparingly, it removes the repodata and downloads a new copy every time. + """ + self._expire_time = time.time() + self._expire_secs + self.dbo.update_cache() + return self._lock
    + +
    [docs]def get_base_object(conf): + """Get the DNF object with settings from the config file + + :param conf: configuration object + :type conf: ComposerParser + :returns: A DNF Base object + :rtype: dnf.Base + """ + cachedir = os.path.abspath(conf.get("composer", "cache_dir")) + dnfconf = os.path.abspath(conf.get("composer", "dnf_conf")) + dnfroot = os.path.abspath(conf.get("composer", "dnf_root")) + repodir = os.path.abspath(conf.get("composer", "repo_dir")) + + # Setup the config for the DNF Base object + dbo = dnf.Base() + dbc = dbo.conf +# TODO - Handle this +# dbc.logdir = logdir + dbc.installroot = dnfroot + if not os.path.isdir(dnfroot): + os.makedirs(dnfroot) + if not os.path.isdir(repodir): + os.makedirs(repodir) + + dbc.cachedir = cachedir + dbc.reposdir = [repodir] + dbc.install_weak_deps = False + dbc.prepend_installroot('persistdir') + # this is a weird 'AppendOption' thing that, when you set it, + # actually appends. Doing this adds 'nodocs' to the existing list + # of values, over in libdnf, it does not replace the existing values. + dbc.tsflags = ['nodocs'] + + if conf.get_default("dnf", "proxy", None): + dbc.proxy = conf.get("dnf", "proxy") + + if conf.has_option("dnf", "sslverify") and not conf.getboolean("dnf", "sslverify"): + dbc.sslverify = False + + # If the system repos are enabled read the dnf vars from /etc/dnf/vars/ + if not conf.has_option("repos", "use_system_repos") or conf.getboolean("repos", "use_system_repos"): + dbc.substitutions.update_from_etc("/") + log.info("dnf vars: %s", dbc.substitutions) + + _releasever = conf.get_default("composer", "releasever", None) + if not _releasever: + # Use the releasever of the host system + _releasever = dnf.rpm.detect_releasever("/") + log.info("releasever = %s", _releasever) + dbc.releasever = _releasever + + # DNF 3.2 needs to have module_platform_id set, otherwise depsolve won't work correctly + if not os.path.exists("/etc/os-release"): + log.warning("/etc/os-release is missing, cannot determine platform id, falling back to %s", DEFAULT_PLATFORM_ID) + platform_id = DEFAULT_PLATFORM_ID + else: + os_release = flatconfig("/etc/os-release") + platform_id = os_release.get("PLATFORM_ID", DEFAULT_PLATFORM_ID) + log.info("Using %s for module_platform_id", platform_id) + dbc.module_platform_id = platform_id + + # Make sure metadata is always current + dbc.metadata_expire = 0 + dbc.metadata_expire_filter = "never" + + # write the dnf configuration file + with open(dnfconf, "w") as f: + f.write(dbc.dump()) + + # dnf needs the repos all in one directory, composer uses repodir for this + # if system repos are supposed to be used, copy them into repodir, overwriting any previous copies + if not conf.has_option("repos", "use_system_repos") or conf.getboolean("repos", "use_system_repos"): + for repo_file in glob("/etc/yum.repos.d/*.repo"): + shutil.copy2(repo_file, repodir) + dbo.read_all_repos() + + # Remove any duplicate repo entries. These can cause problems with Anaconda, which will fail + # with space problems. + repos = sorted(list(r.id for r in dbo.repos.iter_enabled())) + seen = {"baseurl": [], "mirrorlist": [], "metalink": []} + for source_name in repos: + remove = False + repo = dbo.repos.get(source_name, None) + if repo is None: + log.warning("repo %s vanished while removing duplicates", source_name) + continue + if repo.baseurl: + if repo.baseurl[0] in seen["baseurl"]: + log.info("Removing duplicate repo: %s baseurl=%s", source_name, repo.baseurl[0]) + remove = True + else: + seen["baseurl"].append(repo.baseurl[0]) + elif repo.mirrorlist: + if repo.mirrorlist in seen["mirrorlist"]: + log.info("Removing duplicate repo: %s mirrorlist=%s", source_name, repo.mirrorlist) + remove = True + else: + seen["mirrorlist"].append(repo.mirrorlist) + elif repo.metalink: + if repo.metalink in seen["metalink"]: + log.info("Removing duplicate repo: %s metalink=%s", source_name, repo.metalink) + remove = True + else: + seen["metalink"].append(repo.metalink) + + if remove: + del dbo.repos[source_name] + + # Update the metadata from the enabled repos to speed up later operations + log.info("Updating repository metadata") + try: + dbo.fill_sack(load_system_repo=False) + dbo.read_comps() + dbo.update_cache() + except dnf.exceptions.Error as e: + log.error("Failed to update metadata: %s", str(e)) + raise RuntimeError("Fetching metadata failed: %s" % str(e)) + + return dbo
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/flask_blueprint.html b/f32-branch/_modules/pylorax/api/flask_blueprint.html new file mode 100644 index 00000000..e8391df0 --- /dev/null +++ b/f32-branch/_modules/pylorax/api/flask_blueprint.html @@ -0,0 +1,255 @@ + + + + + + + + + + + pylorax.api.flask_blueprint — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.flask_blueprint

    +#
    +# Copyright (C) 2019 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +""" Flask Blueprints that support skipping routes
    +
    +When using Blueprints for API versioning you will usually want to fall back
    +to the previous version's rules for routes that have no new behavior. To do
    +this we add a 'skip_rule' list to the Blueprint's options dictionary. It lists
    +all of the routes that you do not want to register.
    +
    +For example:
    +    from pylorax.api.v0 import v0
    +    from pylorax.api.v1 import v1
    +
    +    server.register_blueprint(v0, url_prefix="/api/v0/")
    +    server.register_blueprint(v0, url_prefix="/api/v1/", skip_rules=["/blueprints/list"]
    +    server.register_blueprint(v1, url_prefix="/api/v1/")
    +
    +This will register all of v0's routes under `/api/v0`, and all but `/blueprints/list` under /api/v1,
    +and then register v1's version of `/blueprints/list` under `/api/v1`
    +
    +"""
    +from flask import Blueprint
    +from flask.blueprints import BlueprintSetupState
    +
    +
    [docs]class BlueprintSetupStateSkip(BlueprintSetupState): + def __init__(self, blueprint, app, options, first_registration, skip_rules): + self._skip_rules = skip_rules + super(BlueprintSetupStateSkip, self).__init__(blueprint, app, options, first_registration) + +
    [docs] def add_url_rule(self, rule, endpoint=None, view_func=None, **options): + if rule not in self._skip_rules: + super(BlueprintSetupStateSkip, self).add_url_rule(rule, endpoint, view_func, **options)
    + +
    [docs]class BlueprintSkip(Blueprint): + def __init__(self, *args, **kwargs): + super(BlueprintSkip, self).__init__(*args, **kwargs) + +
    [docs] def make_setup_state(self, app, options, first_registration=False): + skip_rules = options.pop("skip_rules", []) + return BlueprintSetupStateSkip(self, app, options, first_registration, skip_rules)
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/gitrpm.html b/f32-branch/_modules/pylorax/api/gitrpm.html new file mode 100644 index 00000000..a0dfb21c --- /dev/null +++ b/f32-branch/_modules/pylorax/api/gitrpm.html @@ -0,0 +1,423 @@ + + + + + + + + + + + pylorax.api.gitrpm — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.gitrpm

    +# Copyright (C) 2019 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +""" Clone a git repository and package it as an rpm
    +
    +This module contains functions for cloning a git repo, creating a tar archive of
    +the selected commit, branch, or tag, and packaging the files into an rpm that will
    +be installed by anaconda when creating the image.
    +"""
    +import logging
    +log = logging.getLogger("lorax-composer")
    +
    +import os
    +from rpmfluff import SimpleRpmBuild
    +import shutil
    +import subprocess
    +import tempfile
    +import time
    +
    +from pylorax.sysutils import joinpaths
    +
    +
    [docs]def get_repo_description(gitRepo): + """ Return a description including the git repo and reference + + :param gitRepo: A dict with the repository details + :type gitRepo: dict + :returns: A string with the git repo url and reference + :rtype: str + """ + return "Created from %s, reference '%s', on %s" % (gitRepo["repo"], gitRepo["ref"], time.ctime())
    + +
    [docs]class GitArchiveTarball: + """Create a git archive of the selected git repo and reference""" + def __init__(self, gitRepo): + self._gitRepo = gitRepo + self.sourceName = self._gitRepo["rpmname"]+".tar.xz" + +
    [docs] def write_file(self, sourcesDir): + """ Create the tar archive + + :param sourcesDir: Path to use for creating the archive + :type sourcesDir: str + + This clones the git repository and creates a git archive from the specified reference. + The result is in RPMNAME.tar.xz under the sourcesDir + """ + # Clone the repository into a temporary location + cmd = ["git", "clone", self._gitRepo["repo"], joinpaths(sourcesDir, "gitrepo")] + log.debug(cmd) + try: + subprocess.check_output(cmd, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + log.error("Failed to clone %s: %s", self._gitRepo["repo"], e.output) + raise RuntimeError("Failed to clone %s" % self._gitRepo["repo"]) + + oldcwd = os.getcwd() + try: + os.chdir(joinpaths(sourcesDir, "gitrepo")) + + # Configure archive to create a .tar.xz + cmd = ["git", "config", "tar.tar.xz.command", "xz -c"] + log.debug(cmd) + subprocess.check_call(cmd) + + cmd = ["git", "archive", "--prefix", self._gitRepo["rpmname"] + "/", "-o", joinpaths(sourcesDir, self.sourceName), self._gitRepo["ref"]] + log.debug(cmd) + try: + subprocess.check_output(cmd, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + log.error("Failed to archive %s: %s", self._gitRepo["repo"], e.output) + raise RuntimeError('Failed to archive %s from ref "%s"' % (self._gitRepo["repo"], + self._gitRepo["ref"])) + finally: + # Cleanup even if there was an error + os.chdir(oldcwd) + shutil.rmtree(joinpaths(sourcesDir, "gitrepo"))
    + +
    [docs]class GitRpmBuild(SimpleRpmBuild): + """Build an rpm containing files from a git repository""" + def __init__(self, *args, **kwargs): + self._base_dir = None + super().__init__(*args, **kwargs) + +
    [docs] def check(self): + raise NotImplementedError
    + +
    [docs] def get_base_dir(self): + """Place all the files under a temporary directory + rpmbuild/ + """ + if not self._base_dir: + self._base_dir = tempfile.mkdtemp(prefix="lorax-git-rpm.") + return joinpaths(self._base_dir, "rpmbuild")
    + +
    [docs] def cleanup_tmpdir(self): + """Remove the temporary directory and all of its contents + """ + if len(self._base_dir) < 5: + raise RuntimeError("Invalid base_dir: %s" % self.get_base_dir()) + + shutil.rmtree(self._base_dir)
    + +
    [docs] def clean(self): + """Remove the base directory from inside the tmpdir""" + if len(self.get_base_dir()) < 5: + raise RuntimeError("Invalid base_dir: %s" % self.get_base_dir()) + shutil.rmtree(self.get_base_dir(), ignore_errors=True)
    + +
    [docs] def add_git_tarball(self, gitRepo): + """Add a tar archive of a git repository to the rpm + + :param gitRepo: A dict with the repository details + :type gitRepo: dict + + This populates the rpm with the URL of the git repository, the summary + describing the repo, the description of the repository and reference used, + and sets up the rpm to install the archive contents into the destination + path. + """ + self.addUrl(gitRepo["repo"]) + self.add_summary(gitRepo["summary"]) + self.add_description(get_repo_description(gitRepo)) + self.addLicense("Unknown") + sourceIndex = self.add_source(GitArchiveTarball(gitRepo)) + self.section_build += "tar -xvf %s\n" % self.sources[sourceIndex].sourceName + dest = os.path.normpath(gitRepo["destination"]) + # Prevent double slash root + if dest == "/": + dest = "" + self.create_parent_dirs(dest) + self.section_install += "cp -r %s/. $RPM_BUILD_ROOT/%s\n" % (gitRepo["rpmname"], dest) + sub = self.get_subpackage(None) + if not dest: + # / is special, we don't want to include / itself, just what's under it + sub.section_files += "/*\n" + else: + sub.section_files += "%s/\n" % dest
    + +
    [docs]def make_git_rpm(gitRepo, dest): + """ Create an rpm from the specified git repo + + :param gitRepo: A dict with the repository details + :type gitRepo: dict + + This will clone the git repository, create an archive of the selected reference, + and build an rpm that will install the files from the repository under the destination + directory. The gitRepo dict should have the following fields:: + + rpmname: "server-config" + rpmversion: "1.0" + rpmrelease: "1" + summary: "Setup files for server deployment" + repo: "PATH OF GIT REPO TO CLONE" + ref: "v1.0" + destination: "/opt/server/" + + * rpmname: Name of the rpm to create, also used as the prefix name in the tar archive + * rpmversion: Version of the rpm, eg. "1.0.0" + * rpmrelease: Release of the rpm, eg. "1" + * summary: Summary string for the rpm + * repo: URL of the get repo to clone and create the archive from + * ref: Git reference to check out. eg. origin/branch-name, git tag, or git commit hash + * destination: Path to install the / of the git repo at when installing the rpm + """ + gitRpm = GitRpmBuild(gitRepo["rpmname"], gitRepo["rpmversion"], gitRepo["rpmrelease"], ["noarch"]) + try: + gitRpm.add_git_tarball(gitRepo) + gitRpm.do_make() + rpmfile = gitRpm.get_built_rpm("noarch") + shutil.move(rpmfile, dest) + except Exception as e: + log.error("Creating git repo rpm: %s", e) + raise RuntimeError("Creating git repo rpm: %s" % e) + finally: + gitRpm.cleanup_tmpdir() + + return os.path.basename(rpmfile)
    + +# Create the git rpms, if any, and return the path to the repo under results_dir +
    [docs]def create_gitrpm_repo(results_dir, recipe): + """Create a dnf repository with the rpms from the recipe + + :param results_dir: Path to create the repository under + :type results_dir: str + :param recipe: The recipe to get the repos.git entries from + :type recipe: Recipe + :returns: Path to the dnf repository or "" + :rtype: str + + This function creates a dnf repository directory at results_dir+"repo/", + creates rpms for all of the repos.git entries in the recipe, runs createrepo_c + on the dnf repository so that Anaconda can use it, and returns the path to the + repository to the caller. + """ + if "repos" not in recipe or "git" not in recipe["repos"]: + return "" + + gitrepo = joinpaths(results_dir, "repo/") + if not os.path.exists(gitrepo): + os.makedirs(gitrepo) + for r in recipe["repos"]["git"]: + make_git_rpm(r, gitrepo) + cmd = ["createrepo_c", gitrepo] + log.debug(cmd) + try: + subprocess.check_output(cmd, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + log.error("Failed to create repo at %s: %s", gitrepo, e.output) + raise RuntimeError("Failed to create repo at %s" % gitrepo) + + return gitrepo
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/projects.html b/f32-branch/_modules/pylorax/api/projects.html new file mode 100644 index 00000000..f5a9647a --- /dev/null +++ b/f32-branch/_modules/pylorax/api/projects.html @@ -0,0 +1,898 @@ + + + + + + + + + + + pylorax.api.projects — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.projects

    +#
    +# Copyright (C) 2017  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("lorax-composer")
    +
    +from configparser import ConfigParser
    +import dnf
    +from glob import glob
    +import os
    +import time
    +
    +from pylorax.api.bisect import insort_left
    +from pylorax.sysutils import joinpaths
    +
    +TIME_FORMAT = "%Y-%m-%dT%H:%M:%S"
    +
    +
    +
    [docs]class ProjectsError(Exception): + pass
    + + +
    [docs]def api_time(t): + """Convert time since epoch to a string + + :param t: Seconds since epoch + :type t: int + :returns: Time string + :rtype: str + """ + return time.strftime(TIME_FORMAT, time.localtime(t))
    + + +
    [docs]def api_changelog(changelog): + """Convert the changelog to a string + + :param changelog: A list of time, author, string tuples. + :type changelog: tuple + :returns: The most recent changelog text or "" + :rtype: str + + This returns only the most recent changelog entry. + """ + try: + entry = changelog[0][2] + except IndexError: + entry = "" + return entry
    + + +
    [docs]def pkg_to_project(pkg): + """Extract the details from a hawkey.Package object + + :param pkgs: hawkey.Package object with package details + :type pkgs: hawkey.Package + :returns: A dict with the name, summary, description, and url. + :rtype: dict + + upstream_vcs is hard-coded to UPSTREAM_VCS + """ + return {"name": pkg.name, + "summary": pkg.summary, + "description": pkg.description, + "homepage": pkg.url, + "upstream_vcs": "UPSTREAM_VCS"}
    + + +
    [docs]def pkg_to_build(pkg): + """Extract the build details from a hawkey.Package object + + :param pkg: hawkey.Package object with package details + :type pkg: hawkey.Package + :returns: A dict with the build details, epoch, release, arch, build_time, changelog, ... + :rtype: dict + + metadata entries are hard-coded to {} + + Note that this only returns the build dict, it does not include the name, description, etc. + """ + return {"epoch": pkg.epoch, + "release": pkg.release, + "arch": pkg.arch, + "build_time": api_time(pkg.buildtime), + "changelog": "CHANGELOG_NEEDED", # XXX Not in hawkey.Package + "build_config_ref": "BUILD_CONFIG_REF", + "build_env_ref": "BUILD_ENV_REF", + "metadata": {}, + "source": {"license": pkg.license, + "version": pkg.version, + "source_ref": "SOURCE_REF", + "metadata": {}}}
    + + +
    [docs]def pkg_to_project_info(pkg): + """Extract the details from a hawkey.Package object + + :param pkg: hawkey.Package object with package details + :type pkg: hawkey.Package + :returns: A dict with the project details, as well as epoch, release, arch, build_time, changelog, ... + :rtype: dict + + metadata entries are hard-coded to {} + """ + return {"name": pkg.name, + "summary": pkg.summary, + "description": pkg.description, + "homepage": pkg.url, + "upstream_vcs": "UPSTREAM_VCS", + "builds": [pkg_to_build(pkg)]}
    + + +
    [docs]def pkg_to_dep(pkg): + """Extract the info from a hawkey.Package object + + :param pkg: A hawkey.Package object + :type pkg: hawkey.Package + :returns: A dict with name, epoch, version, release, arch + :rtype: dict + """ + return {"name": pkg.name, + "epoch": pkg.epoch, + "version": pkg.version, + "release": pkg.release, + "arch": pkg.arch}
    + + +
    [docs]def proj_to_module(proj): + """Extract the name from a project_info dict + + :param pkg: dict with package details + :type pkg: dict + :returns: A dict with name, and group_type + :rtype: dict + + group_type is hard-coded to "rpm" + """ + return {"name": proj["name"], + "group_type": "rpm"}
    + + +
    [docs]def dep_evra(dep): + """Return the epoch:version-release.arch for the dep + + :param dep: dependency dict + :type dep: dict + :returns: epoch:version-release.arch + :rtype: str + """ + if dep["epoch"] == 0: + return dep["version"]+"-"+dep["release"]+"."+dep["arch"] + else: + return str(dep["epoch"])+":"+dep["version"]+"-"+dep["release"]+"."+dep["arch"]
    + +
    [docs]def dep_nevra(dep): + """Return the name-epoch:version-release.arch""" + return dep["name"]+"-"+dep_evra(dep)
    + + +
    [docs]def projects_list(dbo): + """Return a list of projects + + :param dbo: dnf base object + :type dbo: dnf.Base + :returns: List of project info dicts with name, summary, description, homepage, upstream_vcs + :rtype: list of dicts + """ + return projects_info(dbo, None)
    + + +
    [docs]def projects_info(dbo, project_names): + """Return details about specific projects + + :param dbo: dnf base object + :type dbo: dnf.Base + :param project_names: List of names of projects to get info about + :type project_names: str + :returns: List of project info dicts with pkg_to_project as well as epoch, version, release, etc. + :rtype: list of dicts + + If project_names is None it will return the full list of available packages + """ + if project_names: + pkgs = dbo.sack.query().available().filter(name__glob=project_names) + else: + pkgs = dbo.sack.query().available() + + # iterate over pkgs + # - if pkg.name isn't in the results yet, add pkg_to_project_info in sorted position + # - if pkg.name is already in results, get its builds. If the build for pkg is different + # in any way (version, arch, etc.) add it to the entry's builds list. If it is the same, + # skip it. + results = [] + results_names = {} + for p in pkgs: + if p.name.lower() not in results_names: + idx = insort_left(results, pkg_to_project_info(p), key=lambda p: p["name"].lower()) + results_names[p.name.lower()] = idx + else: + build = pkg_to_build(p) + if build not in results[results_names[p.name.lower()]]["builds"]: + results[results_names[p.name.lower()]]["builds"].append(build) + + return results
    + +def _depsolve(dbo, projects, groups): + """Add projects to a new transaction + + :param dbo: dnf base object + :type dbo: dnf.Base + :param projects: The projects and version globs to find the dependencies for + :type projects: List of tuples + :param groups: The groups to include in dependency solving + :type groups: List of str + :returns: None + :rtype: None + :raises: ProjectsError if there was a problem installing something + """ + # This resets the transaction and updates the cache. + # It is important that the cache always be synchronized because Anaconda will grab its own copy + # and if that is different the NEVRAs will not match and the build will fail. + dbo.reset(goal=True) + install_errors = [] + for name in groups: + try: + dbo.group_install(name, ["mandatory", "default"]) + except dnf.exceptions.MarkingError as e: + install_errors.append(("Group %s" % (name), str(e))) + + for name, version in projects: + # Find the best package matching the name + version glob + # dnf can return multiple packages if it is in more than 1 repository + query = dbo.sack.query().filterm(provides__glob=name) + if version: + query.filterm(version__glob=version) + + query.filterm(latest=1) + if not query: + install_errors.append(("%s-%s" % (name, version), "No match")) + continue + sltr = dnf.selector.Selector(dbo.sack).set(pkg=query) + + # NOTE: dnf says in near future there will be a "goal" attribute of Base class + # so yes, we're using a 'private' attribute here on purpose and with permission. + dbo._goal.install(select=sltr, optional=False) + + if install_errors: + raise ProjectsError("The following package(s) had problems: %s" % ",".join(["%s (%s)" % (pattern, err) for pattern, err in install_errors])) + +
    [docs]def projects_depsolve(dbo, projects, groups): + """Return the dependencies for a list of projects + + :param dbo: dnf base object + :type dbo: dnf.Base + :param projects: The projects to find the dependencies for + :type projects: List of Strings + :param groups: The groups to include in dependency solving + :type groups: List of str + :returns: NEVRA's of the project and its dependencies + :rtype: list of dicts + :raises: ProjectsError if there was a problem installing something + """ + _depsolve(dbo, projects, groups) + + try: + dbo.resolve() + except dnf.exceptions.DepsolveError as e: + raise ProjectsError("There was a problem depsolving %s: %s" % (projects, str(e))) + + if len(dbo.transaction) == 0: + return [] + + return sorted(map(pkg_to_dep, dbo.transaction.install_set), key=lambda p: p["name"].lower())
    + + +
    [docs]def estimate_size(packages, block_size=6144): + """Estimate the installed size of a package list + + :param packages: The packages to be installed + :type packages: list of hawkey.Package objects + :param block_size: The block size to use for rounding up file sizes. + :type block_size: int + :returns: The estimated size of installed packages + :rtype: int + + Estimating actual requirements is difficult without the actual file sizes, which + dnf doesn't provide access to. So use the file count and block size to estimate + a minimum size for each package. + """ + installed_size = 0 + for p in packages: + installed_size += len(p.files) * block_size + installed_size += p.installsize + return installed_size
    + + +
    [docs]def projects_depsolve_with_size(dbo, projects, groups, with_core=True): + """Return the dependencies and installed size for a list of projects + + :param dbo: dnf base object + :type dbo: dnf.Base + :param project_names: The projects to find the dependencies for + :type project_names: List of Strings + :param groups: The groups to include in dependency solving + :type groups: List of str + :returns: installed size and a list of NEVRA's of the project and its dependencies + :rtype: tuple of (int, list of dicts) + :raises: ProjectsError if there was a problem installing something + """ + _depsolve(dbo, projects, groups) + + if with_core: + dbo.group_install("core", ['mandatory', 'default', 'optional']) + + try: + dbo.resolve() + except dnf.exceptions.DepsolveError as e: + raise ProjectsError("There was a problem depsolving %s: %s" % (projects, str(e))) + + if len(dbo.transaction) == 0: + return (0, []) + + installed_size = estimate_size(dbo.transaction.install_set) + deps = sorted(map(pkg_to_dep, dbo.transaction.install_set), key=lambda p: p["name"].lower()) + return (installed_size, deps)
    + + +
    [docs]def modules_list(dbo, module_names): + """Return a list of modules + + :param dbo: dnf base object + :type dbo: dnf.Base + :param offset: Number of modules to skip + :type limit: int + :param limit: Maximum number of modules to return + :type limit: int + :returns: List of module information and total count + :rtype: tuple of a list of dicts and an Int + + Modules don't exist in RHEL7 so this only returns projects + and sets the type to "rpm" + + """ + # TODO - Figure out what to do with this for Fedora 'modules' + return list(map(proj_to_module, projects_info(dbo, module_names)))
    + +
    [docs]def modules_info(dbo, module_names): + """Return details about a module, including dependencies + + :param dbo: dnf base object + :type dbo: dnf.Base + :param module_names: Names of the modules to get info about + :type module_names: str + :returns: List of dicts with module details and dependencies. + :rtype: list of dicts + """ + modules = projects_info(dbo, module_names) + + # Add the dependency info to each one + for module in modules: + module["dependencies"] = projects_depsolve(dbo, [(module["name"], "*.*")], []) + + return modules
    + +
    [docs]def dnf_repo_to_file_repo(repo): + """Return a string representation of a DNF Repo object suitable for writing to a .repo file + + :param repo: DNF Repository + :type repo: dnf.RepoDict + :returns: A string + :rtype: str + + The DNF Repo.dump() function does not produce a string that can be used as a dnf .repo file, + it ouputs baseurl and gpgkey as python lists which DNF cannot read. So do this manually with + only the attributes we care about. + """ + repo_str = "[%s]\nname = %s\n" % (repo.id, repo.name) + if repo.metalink: + repo_str += "metalink = %s\n" % repo.metalink + elif repo.mirrorlist: + repo_str += "mirrorlist = %s\n" % repo.mirrorlist + elif repo.baseurl: + repo_str += "baseurl = %s\n" % repo.baseurl[0] + else: + raise RuntimeError("Repo has no baseurl, metalink, or mirrorlist") + + # proxy is optional + if repo.proxy: + repo_str += "proxy = %s\n" % repo.proxy + + repo_str += "sslverify = %s\n" % repo.sslverify + repo_str += "gpgcheck = %s\n" % repo.gpgcheck + if repo.gpgkey: + repo_str += "gpgkey = %s\n" % ",".join(repo.gpgkey) + + if repo.skip_if_unavailable: + repo_str += "skip_if_unavailable=1\n" + + return repo_str
    + +
    [docs]def repo_to_source(repo, system_source, api=1): + """Return a Weldr Source dict created from the DNF Repository + + :param repo: DNF Repository + :type repo: dnf.RepoDict + :param system_source: True if this source is an immutable system source + :type system_source: bool + :param api: Select which api version of the dict to return (default 1) + :type api: int + :returns: A dict with Weldr Source fields filled in + :rtype: dict + + Example:: + + { + "check_gpg": true, + "check_ssl": true, + "gpgkey_url": [ + "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-28-x86_64" + ], + "id": "fedora", + "name": "Fedora $releasever - $basearch", + "proxy": "http://proxy.brianlane.com:8123", + "system": true + "type": "yum-metalink", + "url": "https://mirrors.fedoraproject.org/metalink?repo=fedora-28&arch=x86_64" + } + + The ``name`` field has changed in v1 of the API. + In v0 of the API ``name`` is the repo.id, in v1 it is the repo.name and a new field, + ``id`` has been added for the repo.id + + """ + if api==0: + source = {"name": repo.id, "system": system_source} + else: + source = {"id": repo.id, "name": repo.name, "system": system_source} + if repo.baseurl: + source["url"] = repo.baseurl[0] + source["type"] = "yum-baseurl" + elif repo.metalink: + source["url"] = repo.metalink + source["type"] = "yum-metalink" + elif repo.mirrorlist: + source["url"] = repo.mirrorlist + source["type"] = "yum-mirrorlist" + else: + raise RuntimeError("Repo has no baseurl, metalink, or mirrorlist") + + # proxy is optional + if repo.proxy: + source["proxy"] = repo.proxy + + if not repo.sslverify: + source["check_ssl"] = False + else: + source["check_ssl"] = True + + if not repo.gpgcheck: + source["check_gpg"] = False + else: + source["check_gpg"] = True + + if repo.gpgkey: + source["gpgkey_urls"] = list(repo.gpgkey) + + return source
    + +
    [docs]def source_to_repodict(source): + """Return a tuple suitable for use with dnf.add_new_repo + + :param source: A Weldr source dict + :type source: dict + :returns: A tuple of dnf.Repo attributes + :rtype: (str, list, dict) + + Return a tuple with (id, baseurl|(), kwargs) that can be used + with dnf.repos.add_new_repo + """ + kwargs = {} + if "id" in source: + # This is an API v1 source definition + repoid = source["id"] + if "name" in source: + kwargs["name"] = source["name"] + else: + repoid = source["name"] + + # This will allow errors to be raised so we can catch them + # without this they are logged, but the repo is silently disabled + kwargs["skip_if_unavailable"] = False + + if source["type"] == "yum-baseurl": + baseurl = [source["url"]] + elif source["type"] == "yum-metalink": + kwargs["metalink"] = source["url"] + baseurl = () + elif source["type"] == "yum-mirrorlist": + kwargs["mirrorlist"] = source["url"] + baseurl = () + + if "proxy" in source: + kwargs["proxy"] = source["proxy"] + + if source["check_ssl"]: + kwargs["sslverify"] = True + else: + kwargs["sslverify"] = False + + if source["check_gpg"]: + kwargs["gpgcheck"] = True + else: + kwargs["gpgcheck"] = False + + if "gpgkey_urls" in source: + kwargs["gpgkey"] = tuple(source["gpgkey_urls"]) + + return (repoid, baseurl, kwargs)
    + + +
    [docs]def source_to_repo(source, dnf_conf): + """Return a dnf Repo object created from a source dict + + :param source: A Weldr source dict + :type source: dict + :param dnf_conf: The dnf Config object + :type dnf_conf: dnf.conf + :returns: A dnf Repo object + :rtype: dnf.Repo + + Example:: + + { + "check_gpg": True, + "check_ssl": True, + "gpgkey_urls": [ + "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-28-x86_64" + ], + "id": "fedora", + "name": "Fedora $releasever - $basearch", + "proxy": "http://proxy.brianlane.com:8123", + "system": True + "type": "yum-metalink", + "url": "https://mirrors.fedoraproject.org/metalink?repo=fedora-28&arch=x86_64" + } + + If the ``id`` field is included it is used for the repo id, otherwise ``name`` is used. + v0 of the API only used ``name``, v1 added the distinction between ``id`` and ``name``. + """ + repoid, baseurl, kwargs = source_to_repodict(source) + repo = dnf.repo.Repo(repoid, dnf_conf) + if baseurl: + repo.baseurl = baseurl + + # Apply the rest of the kwargs to the Repo object + for k, v in kwargs.items(): + setattr(repo, k, v) + + repo.enable() + + return repo
    + +
    [docs]def get_source_ids(source_path): + """Return a list of the source ids in a file + + :param source_path: Full path and filename of the source (yum repo) file + :type source_path: str + :returns: A list of source id strings + :rtype: list of str + """ + if not os.path.exists(source_path): + return [] + + cfg = ConfigParser() + cfg.read(source_path) + return cfg.sections()
    + +
    [docs]def get_repo_sources(source_glob): + """Return a list of sources from a directory of yum repositories + + :param source_glob: A glob to use to match the source files, including full path + :type source_glob: str + :returns: A list of the source ids in all of the matching files + :rtype: list of str + """ + sources = [] + for f in glob(source_glob): + sources.extend(get_source_ids(f)) + return sources
    + +
    [docs]def delete_repo_source(source_glob, source_id): + """Delete a source from a repo file + + :param source_glob: A glob of the repo sources to search + :type source_glob: str + :param source_id: The repo id to delete + :type source_id: str + :returns: None + :raises: ProjectsError if there was a problem + + A repo file may have multiple sources in it, delete only the selected source. + If it is the last one in the file, delete the file. + + WARNING: This will delete ANY source, the caller needs to ensure that a system + source_id isn't passed to it. + """ + found = False + for f in glob(source_glob): + try: + cfg = ConfigParser() + cfg.read(f) + if source_id in cfg.sections(): + found = True + cfg.remove_section(source_id) + # If there are other sections, rewrite the file without the deleted one + if len(cfg.sections()) > 0: + with open(f, "w") as cfg_file: + cfg.write(cfg_file) + else: + # No sections left, just delete the file + os.unlink(f) + except Exception as e: + raise ProjectsError("Problem deleting repo source %s: %s" % (source_id, str(e))) + if not found: + raise ProjectsError("source %s not found" % source_id)
    + +
    [docs]def new_repo_source(dbo, repoid, source, repo_dir): + """Add a new repo source from a Weldr source dict + + :param dbo: dnf base object + :type dbo: dnf.Base + :param id: The repo id (API v0 uses the name, v1 uses the id) + :type id: str + :param source: A Weldr source dict + :type source: dict + :returns: None + :raises: ... + + Make sure access to the dbo has been locked before calling this. + The `id` parameter will the the 'name' field for API v0, and the 'id' field for API v1 + + DNF variables will be substituted at load time, and on restart. + """ + try: + # Remove it from the RepoDict (NOTE that this isn't explicitly supported by the DNF API) + # If this repo already exists, delete it and replace it with the new one + repos = list(r.id for r in dbo.repos.iter_enabled()) + if repoid in repos: + del dbo.repos[repoid] + + # Add the repo and substitute any dnf variables + _, baseurl, kwargs = source_to_repodict(source) + log.debug("repoid=%s, baseurl=%s, kwargs=%s", repoid, baseurl, kwargs) + r = dbo.repos.add_new_repo(repoid, dbo.conf, baseurl, **kwargs) + r.enable() + + log.info("Updating repository metadata after adding %s", repoid) + dbo.fill_sack(load_system_repo=False) + dbo.read_comps() + + # Remove any previous sources with this id, ignore it if it isn't found + try: + delete_repo_source(joinpaths(repo_dir, "*.repo"), repoid) + except ProjectsError: + pass + + # Make sure the source id can't contain a path traversal by taking the basename + source_path = joinpaths(repo_dir, os.path.basename("%s.repo" % repoid)) + # Write the un-substituted version of the repo to disk + with open(source_path, "w") as f: + repo = source_to_repo(source, dbo.conf) + f.write(dnf_repo_to_file_repo(repo)) + except Exception as e: + log.error("(new_repo_source) adding %s failed: %s", repoid, str(e)) + + # Cleanup the mess, if loading it failed we don't want to leave it in memory + repos = list(r.id for r in dbo.repos.iter_enabled()) + if repoid in repos: + del dbo.repos[repoid] + + log.info("Updating repository metadata after adding %s failed", repoid) + dbo.fill_sack(load_system_repo=False) + dbo.read_comps() + + raise
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/queue.html b/f32-branch/_modules/pylorax/api/queue.html new file mode 100644 index 00000000..f72ac4b1 --- /dev/null +++ b/f32-branch/_modules/pylorax/api/queue.html @@ -0,0 +1,1064 @@ + + + + + + + + + + + pylorax.api.queue — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.queue

    +# Copyright (C) 2018 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +""" Functions to monitor compose queue and run anaconda"""
    +import logging
    +log = logging.getLogger("pylorax")
    +program_log = logging.getLogger("program")
    +dnf_log = logging.getLogger("dnf")
    +
    +import os
    +import grp
    +from glob import glob
    +import multiprocessing as mp
    +import pwd
    +import shutil
    +import subprocess
    +from subprocess import Popen, PIPE
    +import time
    +
    +from pylorax import find_templates
    +from pylorax.api.compose import move_compose_results
    +from pylorax.api.recipes import recipe_from_file
    +from pylorax.api.timestamp import TS_CREATED, TS_STARTED, TS_FINISHED, write_timestamp, timestamp_dict
    +import pylorax.api.toml as toml
    +from pylorax.base import DataHolder
    +from pylorax.creator import run_creator
    +from pylorax.sysutils import joinpaths, read_tail
    +
    +from lifted.queue import create_upload, get_uploads, ready_upload, delete_upload
    +
    +
    [docs]def check_queues(cfg): + """Check to make sure the new and run queue symlinks are correct + + :param cfg: Configuration settings + :type cfg: DataHolder + + Also check all of the existing results and make sure any with WAITING + set in STATUS have a symlink in queue/new/ + """ + # Remove broken symlinks from the new and run queues + queue_symlinks = glob(joinpaths(cfg.composer_dir, "queue/new/*")) + \ + glob(joinpaths(cfg.composer_dir, "queue/run/*")) + for link in queue_symlinks: + if not os.path.isdir(os.path.realpath(link)): + log.info("Removing broken symlink %s", link) + os.unlink(link) + + # Write FAILED to the STATUS of any run queue symlinks and remove them + for link in glob(joinpaths(cfg.composer_dir, "queue/run/*")): + log.info("Setting build %s to FAILED, and removing symlink from queue/run/", os.path.basename(link)) + open(joinpaths(link, "STATUS"), "w").write("FAILED\n") + os.unlink(link) + + # Check results STATUS messages + # - If STATUS is missing, set it to FAILED + # - RUNNING should be changed to FAILED + # - WAITING should have a symlink in the new queue + for link in glob(joinpaths(cfg.composer_dir, "results/*")): + if not os.path.exists(joinpaths(link, "STATUS")): + open(joinpaths(link, "STATUS"), "w").write("FAILED\n") + continue + + status = open(joinpaths(link, "STATUS")).read().strip() + if status == "RUNNING": + log.info("Setting build %s to FAILED", os.path.basename(link)) + open(joinpaths(link, "STATUS"), "w").write("FAILED\n") + elif status == "WAITING": + if not os.path.islink(joinpaths(cfg.composer_dir, "queue/new/", os.path.basename(link))): + log.info("Creating missing symlink to new build %s", os.path.basename(link)) + os.symlink(link, joinpaths(cfg.composer_dir, "queue/new/", os.path.basename(link)))
    + +
    [docs]def start_queue_monitor(cfg, uid, gid): + """Start the queue monitor as a mp process + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param uid: User ID that owns the queue + :type uid: int + :param gid: Group ID that owns the queue + :type gid: int + :returns: None + """ + lib_dir = cfg.get("composer", "lib_dir") + share_dir = cfg.get("composer", "share_dir") + tmp = cfg.get("composer", "tmp") + monitor_cfg = DataHolder(cfg=cfg, composer_dir=lib_dir, share_dir=share_dir, uid=uid, gid=gid, tmp=tmp) + p = mp.Process(target=monitor, args=(monitor_cfg,)) + p.daemon = True + p.start()
    + +
    [docs]def monitor(cfg): + """Monitor the queue for new compose requests + + :param cfg: Configuration settings + :type cfg: DataHolder + :returns: Does not return + + The queue has 2 subdirectories, new and run. When a compose is ready to be run + a symlink to the uniquely named results directory should be placed in ./queue/new/ + + When the it is ready to be run (it is checked every 30 seconds or after a previous + compose is finished) the symlink will be moved into ./queue/run/ and a STATUS file + will be created in the results directory. + + STATUS can contain one of: WAITING, RUNNING, FINISHED, FAILED + + If the system is restarted while a compose is running it will move any old symlinks + from ./queue/run/ to ./queue/new/ and rerun them. + """ + def queue_sort(uuid): + """Sort the queue entries by their mtime, not their names""" + return os.stat(joinpaths(cfg.composer_dir, "queue/new", uuid)).st_mtime + + check_queues(cfg) + while True: + uuids = sorted(os.listdir(joinpaths(cfg.composer_dir, "queue/new")), key=queue_sort) + + # Pick the oldest and move it into ./run/ + if not uuids: + # No composes left to process, sleep for a bit + time.sleep(5) + else: + src = joinpaths(cfg.composer_dir, "queue/new", uuids[0]) + dst = joinpaths(cfg.composer_dir, "queue/run", uuids[0]) + try: + os.rename(src, dst) + except OSError: + # The symlink may vanish if uuid_cancel() has been called + continue + + # The anaconda logs are also copied into ./anaconda/ in this directory + os.makedirs(joinpaths(dst, "logs"), exist_ok=True) + + def open_handler(loggers, file_name): + handler = logging.FileHandler(joinpaths(dst, "logs", file_name)) + handler.setLevel(logging.DEBUG) + handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s: %(message)s")) + for logger in loggers: + logger.addHandler(handler) + return (handler, loggers) + + loggers = (((log, program_log, dnf_log), "combined.log"), + ((log,), "composer.log"), + ((program_log,), "program.log"), + ((dnf_log,), "dnf.log")) + handlers = [open_handler(loggers, file_name) for loggers, file_name in loggers] + + log.info("Starting new compose: %s", dst) + open(joinpaths(dst, "STATUS"), "w").write("RUNNING\n") + + try: + make_compose(cfg, os.path.realpath(dst)) + log.info("Finished building %s, results are in %s", dst, os.path.realpath(dst)) + open(joinpaths(dst, "STATUS"), "w").write("FINISHED\n") + write_timestamp(dst, TS_FINISHED) + + upload_cfg = cfg.cfg["upload"] + for upload in get_uploads(upload_cfg, uuid_get_uploads(cfg.cfg, uuids[0])): + log.info("Readying upload %s", upload.uuid) + uuid_ready_upload(cfg.cfg, uuids[0], upload.uuid) + except Exception: + import traceback + log.error("traceback: %s", traceback.format_exc()) + +# TODO - Write the error message to an ERROR-LOG file to include with the status +# log.error("Error running compose: %s", e) + open(joinpaths(dst, "STATUS"), "w").write("FAILED\n") + write_timestamp(dst, TS_FINISHED) + finally: + for handler, loggers in handlers: + for logger in loggers: + logger.removeHandler(handler) + handler.close() + + os.unlink(dst)
    + +
    [docs]def make_compose(cfg, results_dir): + """Run anaconda with the final-kickstart.ks from results_dir + + :param cfg: Configuration settings + :type cfg: DataHolder + :param results_dir: The directory containing the metadata and results for the build + :type results_dir: str + :returns: Nothing + :raises: May raise various exceptions + + This takes the final-kickstart.ks, and the settings in config.toml and runs Anaconda + in no-virt mode (directly on the host operating system). Exceptions should be caught + at the higer level. + + If there is a failure, the build artifacts will be cleaned up, and any logs will be + moved into logs/anaconda/ and their ownership will be set to the user from the cfg + object. + """ + + # Check on the ks's presence + ks_path = joinpaths(results_dir, "final-kickstart.ks") + if not os.path.exists(ks_path): + raise RuntimeError("Missing kickstart file at %s" % ks_path) + + # Load the compose configuration + cfg_path = joinpaths(results_dir, "config.toml") + if not os.path.exists(cfg_path): + raise RuntimeError("Missing config.toml for %s" % results_dir) + cfg_dict = toml.loads(open(cfg_path, "r").read()) + + # The keys in cfg_dict correspond to the arguments setup in livemedia-creator + # keys that define what to build should be setup in compose_args, and keys with + # defaults should be setup here. + + # Make sure that image_name contains no path components + cfg_dict["image_name"] = os.path.basename(cfg_dict["image_name"]) + + # Only support novirt installation, set some other defaults + cfg_dict["no_virt"] = True + cfg_dict["disk_image"] = None + cfg_dict["fs_image"] = None + cfg_dict["keep_image"] = False + cfg_dict["domacboot"] = False + cfg_dict["anaconda_args"] = "" + cfg_dict["proxy"] = "" + cfg_dict["armplatform"] = "" + cfg_dict["squashfs_args"] = None + + cfg_dict["lorax_templates"] = find_templates(cfg.share_dir) + cfg_dict["tmp"] = cfg.tmp + # Use default args for dracut + cfg_dict["dracut_conf"] = None + cfg_dict["dracut_args"] = None + + # TODO How to support other arches? + cfg_dict["arch"] = None + + # Compose things in a temporary directory inside the results directory + cfg_dict["result_dir"] = joinpaths(results_dir, "compose") + os.makedirs(cfg_dict["result_dir"]) + + install_cfg = DataHolder(**cfg_dict) + + # Some kludges for the 99-copy-logs %post, failure in it will crash the build + for f in ["/tmp/NOSAVE_INPUT_KS", "/tmp/NOSAVE_LOGS"]: + open(f, "w") + + # Placing a CANCEL file in the results directory will make execWithRedirect send anaconda a SIGTERM + def cancel_build(): + return os.path.exists(joinpaths(results_dir, "CANCEL")) + + log.debug("cfg = %s", install_cfg) + try: + test_path = joinpaths(results_dir, "TEST") + write_timestamp(results_dir, TS_STARTED) + if os.path.exists(test_path): + # Pretend to run the compose + time.sleep(5) + try: + test_mode = int(open(test_path, "r").read()) + except Exception: + test_mode = 1 + if test_mode == 1: + raise RuntimeError("TESTING FAILED compose") + else: + open(joinpaths(results_dir, install_cfg.image_name), "w").write("TEST IMAGE") + else: + run_creator(install_cfg, cancel_func=cancel_build) + + # Extract the results of the compose into results_dir and cleanup the compose directory + move_compose_results(install_cfg, results_dir) + finally: + # Make sure any remaining temporary directories are removed (eg. if there was an exception) + for d in glob(joinpaths(cfg.tmp, "lmc-*")): + if os.path.isdir(d): + shutil.rmtree(d) + elif os.path.isfile(d): + os.unlink(d) + + # Make sure that everything under the results directory is owned by the user + user = pwd.getpwuid(cfg.uid).pw_name + group = grp.getgrgid(cfg.gid).gr_name + log.debug("Install finished, chowning results to %s:%s", user, group) + subprocess.call(["chown", "-R", "%s:%s" % (user, group), results_dir])
    + +
    [docs]def get_compose_type(results_dir): + """Return the type of composition. + + :param results_dir: The directory containing the metadata and results for the build + :type results_dir: str + :returns: The type of compose (eg. 'tar') + :rtype: str + :raises: RuntimeError if no kickstart template can be found. + """ + # Should only be 2 kickstarts, the final-kickstart.ks and the template + t = [os.path.basename(ks)[:-3] for ks in glob(joinpaths(results_dir, "*.ks")) + if "final-kickstart" not in ks] + if len(t) != 1: + raise RuntimeError("Cannot find ks template for build %s" % os.path.basename(results_dir)) + return t[0]
    + +
    [docs]def compose_detail(cfg, results_dir, api=1): + """Return details about the build. + + :param cfg: Configuration settings (required for api=1) + :type cfg: ComposerConfig + :param results_dir: The directory containing the metadata and results for the build + :type results_dir: str + :param api: Select which api version of the dict to return (default 1) + :type api: int + :returns: A dictionary with details about the compose + :rtype: dict + :raises: IOError if it cannot read the directory, STATUS, or blueprint file. + + The following details are included in the dict: + + * id - The uuid of the comoposition + * queue_status - The final status of the composition (FINISHED or FAILED) + * compose_type - The type of output generated (tar, iso, etc.) + * blueprint - Blueprint name + * version - Blueprint version + * image_size - Size of the image, if finished. 0 otherwise. + * uploads - For API v1 details about uploading the image are included + + Various timestamps are also included in the dict. These are all Unix UTC timestamps. + It is possible for these timestamps to not always exist, in which case they will be + None in Python (or null in JSON). The following timestamps are included: + + * job_created - When the user submitted the compose + * job_started - Anaconda started running + * job_finished - Job entered FINISHED or FAILED state + """ + build_id = os.path.basename(os.path.abspath(results_dir)) + status = open(joinpaths(results_dir, "STATUS")).read().strip() + blueprint = recipe_from_file(joinpaths(results_dir, "blueprint.toml")) + + compose_type = get_compose_type(results_dir) + + image_path = get_image_name(results_dir)[1] + if status == "FINISHED" and os.path.exists(image_path): + image_size = os.stat(image_path).st_size + else: + image_size = 0 + + times = timestamp_dict(results_dir) + + detail = {"id": build_id, + "queue_status": status, + "job_created": times.get(TS_CREATED), + "job_started": times.get(TS_STARTED), + "job_finished": times.get(TS_FINISHED), + "compose_type": compose_type, + "blueprint": blueprint["name"], + "version": blueprint["version"], + "image_size": image_size, + } + + if api == 1: + # Get uploads for this build_id + upload_uuids = uuid_get_uploads(cfg, build_id) + summaries = [upload.summary() for upload in get_uploads(cfg["upload"], upload_uuids)] + detail["uploads"] = summaries + return detail
    + +
    [docs]def queue_status(cfg, api=1): + """Return details about what is in the queue. + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param api: Select which api version of the dict to return (default 1) + :type api: int + :returns: A list of the new composes, and a list of the running composes + :rtype: dict + + This returns a dict with 2 lists. "new" is the list of uuids that are waiting to be built, + and "run" has the uuids that are being built (currently limited to 1 at a time). + """ + queue_dir = joinpaths(cfg.get("composer", "lib_dir"), "queue") + new_queue = [os.path.realpath(p) for p in glob(joinpaths(queue_dir, "new/*"))] + run_queue = [os.path.realpath(p) for p in glob(joinpaths(queue_dir, "run/*"))] + + new_details = [] + for n in new_queue: + try: + d = compose_detail(cfg, n, api) + except IOError: + continue + new_details.append(d) + + run_details = [] + for r in run_queue: + try: + d = compose_detail(cfg, r, api) + except IOError: + continue + run_details.append(d) + + return { + "new": new_details, + "run": run_details + }
    + +
    [docs]def uuid_status(cfg, uuid, api=1): + """Return the details of a specific UUID compose + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param uuid: The UUID of the build + :type uuid: str + :param api: Select which api version of the dict to return (default 1) + :type api: int + :returns: Details about the build + :rtype: dict or None + + Returns the same dict as `compose_detail()` + """ + uuid_dir = joinpaths(cfg.get("composer", "lib_dir"), "results", uuid) + try: + return compose_detail(cfg, uuid_dir, api) + except IOError: + return None
    + +
    [docs]def build_status(cfg, status_filter=None, api=1): + """Return the details of finished or failed builds + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param status_filter: What builds to return. None == all, "FINISHED", or "FAILED" + :type status_filter: str + :param api: Select which api version of the dict to return (default 1) + :type api: int + :returns: A list of the build details (from compose_detail) + :rtype: list of dicts + + This returns a list of build details for each of the matching builds on the + system. It does not return the status of builds that have not been finished. + Use queue_status() for those. + """ + if status_filter: + status_filter = [status_filter] + else: + status_filter = ["FINISHED", "FAILED"] + + results = [] + result_dir = joinpaths(cfg.get("composer", "lib_dir"), "results") + for build in glob(result_dir + "/*"): + log.debug("Checking status of build %s", build) + + try: + status = open(joinpaths(build, "STATUS"), "r").read().strip() + if status in status_filter: + results.append(compose_detail(cfg, build, api)) + except IOError: + pass + return results
    + +def _upload_list_path(cfg, uuid): + """Return the path to the UPLOADS file + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param uuid: The UUID of the build + :type uuid: str + :returns: Path to the UPLOADS file listing the build's associated uploads + :rtype: str + :raises: RuntimeError if the uuid is not found + """ + results_dir = joinpaths(cfg.get("composer", "lib_dir"), "results", uuid) + if not os.path.isdir(results_dir): + raise RuntimeError(f'"{uuid}" is not a valid build uuid!') + return joinpaths(results_dir, "UPLOADS") + +
    [docs]def uuid_schedule_upload(cfg, uuid, provider_name, image_name, settings): + """Schedule an upload of an image + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param uuid: The UUID of the build + :type uuid: str + :param provider_name: The name of the cloud provider, e.g. "azure" + :type provider_name: str + :param image_name: Path of the image to upload + :type image_name: str + :param settings: Settings to use for the selected provider + :type settings: dict + :returns: uuid of the upload + :rtype: str + :raises: RuntimeError if the uuid is not a valid build uuid + """ + status = uuid_status(cfg, uuid) + if status is None: + raise RuntimeError(f'"{uuid}" is not a valid build uuid!') + + upload = create_upload(cfg["upload"], provider_name, image_name, settings) + uuid_add_upload(cfg, uuid, upload.uuid) + return upload.uuid
    + +
    [docs]def uuid_get_uploads(cfg, uuid): + """Return the list of uploads for a build uuid + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param uuid: The UUID of the build + :type uuid: str + :returns: The upload UUIDs associated with the build UUID + :rtype: frozenset + """ + try: + with open(_upload_list_path(cfg, uuid)) as uploads_file: + return frozenset(uploads_file.read().split()) + except FileNotFoundError: + return frozenset()
    + +
    [docs]def uuid_add_upload(cfg, uuid, upload_uuid): + """Add an upload UUID to a build + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param uuid: The UUID of the build + :type uuid: str + :param upload_uuid: The UUID of the upload + :type upload_uuid: str + :returns: None + :rtype: None + """ + if upload_uuid not in uuid_get_uploads(cfg, uuid): + with open(_upload_list_path(cfg, uuid), "a") as uploads_file: + print(upload_uuid, file=uploads_file) + status = uuid_status(cfg, uuid) + if status and status["queue_status"] == "FINISHED": + uuid_ready_upload(cfg, uuid, upload_uuid)
    + +
    [docs]def uuid_remove_upload(cfg, upload_uuid): + """Remove an upload UUID from the build + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param upload_uuid: The UUID of the upload + :type upload_uuid: str + :returns: None + :rtype: None + :raises: RuntimeError if the upload_uuid is not found + """ + for build_uuid in (os.path.basename(b) for b in glob(joinpaths(cfg.get("composer", "lib_dir"), "results/*"))): + uploads = uuid_get_uploads(cfg, build_uuid) + if upload_uuid not in uploads: + continue + + uploads = uploads - frozenset((upload_uuid,)) + with open(_upload_list_path(cfg, build_uuid), "w") as uploads_file: + for upload in uploads: + print(upload, file=uploads_file) + return + + raise RuntimeError(f"{upload_uuid} is not a valid upload id!")
    + +
    [docs]def uuid_ready_upload(cfg, uuid, upload_uuid): + """Set an upload to READY if the build is in FINISHED state + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param uuid: The UUID of the build + :type uuid: str + :param upload_uuid: The UUID of the upload + :type upload_uuid: str + :returns: None + :rtype: None + :raises: RuntimeError if the build uuid is invalid or not in FINISHED state. + """ + status = uuid_status(cfg, uuid) + if not status: + raise RuntimeError(f"{uuid} is not a valid build id!") + if status["queue_status"] != "FINISHED": + raise RuntimeError(f"Build {uuid} is not finished!") + _, image_path = uuid_image(cfg, uuid) + ready_upload(cfg["upload"], upload_uuid, image_path)
    + +
    [docs]def uuid_cancel(cfg, uuid): + """Cancel a build and delete its results + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param uuid: The UUID of the build + :type uuid: str + :returns: True if it was canceled and deleted + :rtype: bool + + Only call this if the build status is WAITING or RUNNING + """ + cancel_path = joinpaths(cfg.get("composer", "lib_dir"), "results", uuid, "CANCEL") + if os.path.exists(cancel_path): + log.info("Cancel has already been requested for %s", uuid) + return False + + # This status can change (and probably will) while it is in the middle of doing this: + # It can move from WAITING -> RUNNING or it can move from RUNNING -> FINISHED|FAILED + + # If it is in WAITING remove the symlink and then check to make sure it didn't show up + # in the run queue + queue_dir = joinpaths(cfg.get("composer", "lib_dir"), "queue") + uuid_new = joinpaths(queue_dir, "new", uuid) + if os.path.exists(uuid_new): + try: + os.unlink(uuid_new) + except OSError: + # The symlink may vanish if the queue monitor started the build + pass + uuid_run = joinpaths(queue_dir, "run", uuid) + if not os.path.exists(uuid_run): + # Make sure the build is still in the waiting state + status = uuid_status(cfg, uuid) + if status is None or status["queue_status"] == "WAITING": + # Successfully removed it before the build started + return uuid_delete(cfg, uuid) + + # At this point the build has probably started. Write to the CANCEL file. + open(cancel_path, "w").write("\n") + + # Wait for status to move to FAILED or FINISHED + started = time.time() + while True: + status = uuid_status(cfg, uuid) + if status is None or status["queue_status"] == "FAILED": + break + elif status is not None and status["queue_status"] == "FINISHED": + # The build finished successfully, no point in deleting it now + return False + + # Is this taking too long? Exit anyway and try to cleanup. + if time.time() > started + (10 * 60): + log.error("Failed to cancel the build of %s", uuid) + break + + time.sleep(5) + + # Remove the partial results + uuid_delete(cfg, uuid)
    + +
    [docs]def uuid_delete(cfg, uuid): + """Delete all of the results from a compose + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param uuid: The UUID of the build + :type uuid: str + :returns: True if it was deleted + :rtype: bool + :raises: This will raise an error if the delete failed + """ + uuid_dir = joinpaths(cfg.get("composer", "lib_dir"), "results", uuid) + if not uuid_dir or len(uuid_dir) < 10: + raise RuntimeError("Directory length is too short: %s" % uuid_dir) + + for upload in get_uploads(cfg["upload"], uuid_get_uploads(cfg, uuid)): + delete_upload(cfg["upload"], upload.uuid) + + shutil.rmtree(uuid_dir) + return True
    + +
    [docs]def uuid_info(cfg, uuid, api=1): + """Return information about the composition + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param uuid: The UUID of the build + :type uuid: str + :returns: dictionary of information about the composition or None + :rtype: dict + :raises: RuntimeError if there was a problem + + This will return a dict with the following fields populated: + + * id - The uuid of the comoposition + * config - containing the configuration settings used to run Anaconda + * blueprint - The depsolved blueprint used to generate the kickstart + * commit - The (local) git commit hash for the blueprint used + * deps - The NEVRA of all of the dependencies used in the composition + * compose_type - The type of output generated (tar, iso, etc.) + * queue_status - The final status of the composition (FINISHED or FAILED) + """ + uuid_dir = joinpaths(cfg.get("composer", "lib_dir"), "results", uuid) + if not os.path.exists(uuid_dir): + return None + + # Load the compose configuration + cfg_path = joinpaths(uuid_dir, "config.toml") + if not os.path.exists(cfg_path): + raise RuntimeError("Missing config.toml for %s" % uuid) + cfg_dict = toml.loads(open(cfg_path, "r").read()) + + frozen_path = joinpaths(uuid_dir, "frozen.toml") + if not os.path.exists(frozen_path): + raise RuntimeError("Missing frozen.toml for %s" % uuid) + frozen_dict = toml.loads(open(frozen_path, "r").read()) + + deps_path = joinpaths(uuid_dir, "deps.toml") + if not os.path.exists(deps_path): + raise RuntimeError("Missing deps.toml for %s" % uuid) + deps_dict = toml.loads(open(deps_path, "r").read()) + + details = compose_detail(cfg, uuid_dir, api) + + commit_path = joinpaths(uuid_dir, "COMMIT") + if not os.path.exists(commit_path): + raise RuntimeError("Missing commit hash for %s" % uuid) + commit_id = open(commit_path, "r").read().strip() + + info = {"id": uuid, + "config": cfg_dict, + "blueprint": frozen_dict, + "commit": commit_id, + "deps": deps_dict, + "compose_type": details["compose_type"], + "queue_status": details["queue_status"], + "image_size": details["image_size"], + } + if api == 1: + upload_uuids = uuid_get_uploads(cfg, uuid) + summaries = [upload.summary() for upload in get_uploads(cfg["upload"], upload_uuids)] + info["uploads"] = summaries + return info
    + +
    [docs]def uuid_tar(cfg, uuid, metadata=False, image=False, logs=False): + """Return a tar of the build data + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param uuid: The UUID of the build + :type uuid: str + :param metadata: Set to true to include all the metadata needed to reproduce the build + :type metadata: bool + :param image: Set to true to include the output image + :type image: bool + :param logs: Set to true to include the logs from the build + :type logs: bool + :returns: A stream of bytes from tar + :rtype: A generator + :raises: RuntimeError if there was a problem (eg. missing config file) + + This yields an uncompressed tar's data to the caller. It includes + the selected data to the caller by returning the Popen stdout from the tar process. + """ + uuid_dir = joinpaths(cfg.get("composer", "lib_dir"), "results", uuid) + if not os.path.exists(uuid_dir): + raise RuntimeError("%s is not a valid build_id" % uuid) + + # Load the compose configuration + cfg_path = joinpaths(uuid_dir, "config.toml") + if not os.path.exists(cfg_path): + raise RuntimeError("Missing config.toml for %s" % uuid) + cfg_dict = toml.loads(open(cfg_path, "r").read()) + image_name = cfg_dict["image_name"] + + def include_file(f): + if f.endswith("/logs"): + return logs + if f.endswith(image_name): + return image + return metadata + filenames = [os.path.basename(f) for f in glob(joinpaths(uuid_dir, "*")) if include_file(f)] + + tar = Popen(["tar", "-C", uuid_dir, "-cf-"] + filenames, stdout=PIPE) + return tar.stdout
    + +
    [docs]def uuid_image(cfg, uuid): + """Return the filename and full path of the build's image file + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param uuid: The UUID of the build + :type uuid: str + :returns: The image filename and full path + :rtype: tuple of strings + :raises: RuntimeError if there was a problem (eg. invalid uuid, missing config file) + """ + uuid_dir = joinpaths(cfg.get("composer", "lib_dir"), "results", uuid) + return get_image_name(uuid_dir)
    + +
    [docs]def get_image_name(uuid_dir): + """Return the filename and full path of the build's image file + + :param uuid: The UUID of the build + :type uuid: str + :returns: The image filename and full path + :rtype: tuple of strings + :raises: RuntimeError if there was a problem (eg. invalid uuid, missing config file) + """ + uuid = os.path.basename(os.path.abspath(uuid_dir)) + if not os.path.exists(uuid_dir): + raise RuntimeError("%s is not a valid build_id" % uuid) + + # Load the compose configuration + cfg_path = joinpaths(uuid_dir, "config.toml") + if not os.path.exists(cfg_path): + raise RuntimeError("Missing config.toml for %s" % uuid) + cfg_dict = toml.loads(open(cfg_path, "r").read()) + image_name = cfg_dict["image_name"] + + return (image_name, joinpaths(uuid_dir, image_name))
    + +
    [docs]def uuid_log(cfg, uuid, size=1024): + """Return `size` KiB from the end of the most currently relevant log for a + given compose + + :param cfg: Configuration settings + :type cfg: ComposerConfig + :param uuid: The UUID of the build + :type uuid: str + :param size: Number of KiB to read. Default is 1024 + :type size: int + :returns: Up to `size` KiB from the end of the log + :rtype: str + :raises: RuntimeError if there was a problem (eg. no log file available) + + This function will return the end of either the anaconda log, the packaging + log, or the combined composer logs, depending on the progress of the + compose. It tries to return lines from the end of the log, it will attempt + to start on a line boundary, and it may return less than `size` kbytes. + """ + uuid_dir = joinpaths(cfg.get("composer", "lib_dir"), "results", uuid) + if not os.path.exists(uuid_dir): + raise RuntimeError("%s is not a valid build_id" % uuid) + + # While a build is running the logs will be in /tmp/anaconda.log and when it + # has finished they will be in the results directory + status = uuid_status(cfg, uuid) + if status is None: + raise RuntimeError("Status is missing for %s" % uuid) + + def get_log_path(): + # Try to return the most relevant log at any given time during the + # compose. If the compose is not running, return the composer log. + anaconda_log = "/tmp/anaconda.log" + packaging_log = "/tmp/packaging.log" + combined_log = joinpaths(uuid_dir, "logs", "combined.log") + if status["queue_status"] != "RUNNING" or not os.path.isfile(anaconda_log): + return combined_log + if not os.path.isfile(packaging_log): + return anaconda_log + try: + anaconda_mtime = os.stat(anaconda_log).st_mtime + packaging_mtime = os.stat(packaging_log).st_mtime + # If the packaging log exists and its last message is at least 15 + # seconds newer than the anaconda log, return the packaging log. + if packaging_mtime > anaconda_mtime + 15: + return packaging_log + return anaconda_log + except OSError: + # Return the combined log if anaconda_log or packaging_log disappear + return combined_log + try: + tail = read_tail(get_log_path(), size) + except OSError as e: + raise RuntimeError("No log available.") from e + return tail
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/recipes.html b/f32-branch/_modules/pylorax/api/recipes.html new file mode 100644 index 00000000..266d2158 --- /dev/null +++ b/f32-branch/_modules/pylorax/api/recipes.html @@ -0,0 +1,1477 @@ + + + + + + + + + + + pylorax.api.recipes — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.recipes

    +#
    +# Copyright (C) 2017-2019  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +import gi
    +gi.require_version("Ggit", "1.0")
    +from gi.repository import Ggit as Git
    +from gi.repository import Gio
    +from gi.repository import GLib
    +
    +import os
    +import semantic_version as semver
    +
    +from pylorax.api.projects import dep_evra
    +from pylorax.base import DataHolder
    +from pylorax.sysutils import joinpaths
    +import pylorax.api.toml as toml
    +
    +
    +
    [docs]class CommitTimeValError(Exception): + pass
    + +
    [docs]class RecipeFileError(Exception): + pass
    + +
    [docs]class RecipeError(Exception): + pass
    + + +
    [docs]class Recipe(dict): + """A Recipe of package and modules + + This is a subclass of dict that enforces the constructor arguments + and adds a .filename property to return the recipe's filename, + and a .toml() function to return the recipe as a TOML string. + """ + def __init__(self, name, description, version, modules, packages, groups, customizations=None, gitrepos=None): + # Check that version is empty or semver compatible + if version: + semver.Version(version) + + # Make sure modules, packages, and groups are listed by their case-insensitive names + if modules is not None: + modules = sorted(modules, key=lambda m: m["name"].lower()) + if packages is not None: + packages = sorted(packages, key=lambda p: p["name"].lower()) + if groups is not None: + groups = sorted(groups, key=lambda g: g["name"].lower()) + + # Only support [[repos.git]] for now + if gitrepos is not None: + repos = {"git": sorted(gitrepos, key=lambda g: g["repo"].lower())} + else: + repos = None + dict.__init__(self, name=name, + description=description, + version=version, + modules=modules, + packages=packages, + groups=groups, + customizations=customizations, + repos=repos) + + # We don't want customizations=None to show up in the TOML so remove it + if customizations is None: + del self["customizations"] + + # Don't include empty repos or repos.git + if repos is None or not repos["git"]: + del self["repos"] + + @property + def package_names(self): + """Return the names of the packages""" + return [p["name"] for p in self["packages"] or []] + + @property + def package_nver(self): + """Return the names and version globs of the packages""" + return [(p["name"], p["version"]) for p in self["packages"] or []] + + @property + def module_names(self): + """Return the names of the modules""" + return [m["name"] for m in self["modules"] or []] + + @property + def module_nver(self): + """Return the names and version globs of the modules""" + return [(m["name"], m["version"]) for m in self["modules"] or []] + + @property + def group_names(self): + """Return the names of the groups. Groups do not have versions.""" + return map(lambda g: g["name"], self["groups"] or []) + + @property + def filename(self): + """Return the Recipe's filename + + Replaces spaces in the name with '-' and appends .toml + """ + return recipe_filename(self.get("name")) + +
    [docs] def toml(self): + """Return the Recipe in TOML format""" + return toml.dumps(self)
    + +
    [docs] def bump_version(self, old_version=None): + """semver recipe version number bump + + :param old_version: An optional old version number + :type old_version: str + :returns: The new version number or None + :rtype: str + :raises: ValueError + + If neither have a version, 0.0.1 is returned + If there is no old version the new version is checked and returned + If there is no new version, but there is a old one, bump its patch level + If the old and new versions are the same, bump the patch level + If they are different, check and return the new version + """ + new_version = self.get("version") + if not new_version and not old_version: + self["version"] = "0.0.1" + + elif new_version and not old_version: + semver.Version(new_version) + self["version"] = new_version + + elif not new_version or new_version == old_version: + new_version = str(semver.Version(old_version).next_patch()) + self["version"] = new_version + + else: + semver.Version(new_version) + self["version"] = new_version + + # Return the new version + return str(semver.Version(self["version"]))
    + +
    [docs] def freeze(self, deps): + """ Return a new Recipe with full module and package NEVRA + + :param deps: A list of dependency NEVRA to use to fill in the modules and packages + :type deps: list( + :returns: A new Recipe object + :rtype: Recipe + """ + module_names = self.module_names + package_names = self.package_names + group_names = self.group_names + + new_modules = [] + new_packages = [] + new_groups = [] + for dep in deps: + if dep["name"] in package_names: + new_packages.append(RecipePackage(dep["name"], dep_evra(dep))) + elif dep["name"] in module_names: + new_modules.append(RecipeModule(dep["name"], dep_evra(dep))) + elif dep["name"] in group_names: + new_groups.append(RecipeGroup(dep["name"])) + if "customizations" in self: + customizations = self["customizations"] + else: + customizations = None + if "repos" in self and "git" in self["repos"]: + gitrepos = self["repos"]["git"] + else: + gitrepos = None + + return Recipe(self["name"], self["description"], self["version"], + new_modules, new_packages, new_groups, customizations, gitrepos)
    + +
    [docs]class RecipeModule(dict): + def __init__(self, name, version): + dict.__init__(self, name=name, version=version)
    + +
    [docs]class RecipePackage(RecipeModule): + pass
    + +
    [docs]class RecipeGroup(dict): + def __init__(self, name): + dict.__init__(self, name=name)
    + +
    [docs]def NewRecipeGit(toml_dict): + """Create a RecipeGit object from fields in a TOML dict + + :param rpmname: Name of the rpm to create, also used as the prefix name in the tar archive + :type rpmname: str + :param rpmversion: Version of the rpm, eg. "1.0.0" + :type rpmversion: str + :param rpmrelease: Release of the rpm, eg. "1" + :type rpmrelease: str + :param summary: Summary string for the rpm + :type summary: str + :param repo: URL of the get repo to clone and create the archive from + :type repo: str + :param ref: Git reference to check out. eg. origin/branch-name, git tag, or git commit hash + :type ref: str + :param destination: Path to install the / of the git repo at when installing the rpm + :type destination: str + :returns: A populated RecipeGit object + :rtype: RecipeGit + + The TOML should look like this:: + + [[repos.git]] + rpmname="server-config" + rpmversion="1.0" + rpmrelease="1" + summary="Setup files for server deployment" + repo="PATH OF GIT REPO TO CLONE" + ref="v1.0" + destination="/opt/server/" + + Note that the repo path supports anything that git supports, file://, https://, http:// + + Currently there is no support for authentication + """ + return RecipeGit(toml_dict.get("rpmname"), + toml_dict.get("rpmversion"), + toml_dict.get("rpmrelease"), + toml_dict.get("summary", ""), + toml_dict.get("repo"), + toml_dict.get("ref"), + toml_dict.get("destination"))
    + +
    [docs]class RecipeGit(dict): + def __init__(self, rpmname, rpmversion, rpmrelease, summary, repo, ref, destination): + dict.__init__(self, rpmname=rpmname, rpmversion=rpmversion, rpmrelease=rpmrelease, + summary=summary, repo=repo, ref=ref, destination=destination)
    + +
    [docs]def recipe_from_file(recipe_path): + """Return a recipe file as a Recipe object + + :param recipe_path: Path to the recipe fila + :type recipe_path: str + :returns: A Recipe object + :rtype: Recipe + """ + with open(recipe_path, 'rb') as f: + return recipe_from_toml(f.read())
    + +
    [docs]def recipe_from_toml(recipe_str): + """Create a Recipe object from a toml string. + + :param recipe_str: The Recipe TOML string + :type recipe_str: str + :returns: A Recipe object + :rtype: Recipe + :raises: TomlError + """ + recipe_dict = toml.loads(recipe_str) + return recipe_from_dict(recipe_dict)
    + +
    [docs]def check_required_list(lst, fields): + """Check a list of dicts for required fields + + :param lst: A list of dicts with fields + :type lst: list of dict + :param fields: A list of field name strings + :type fields: list of str + :returns: A list of error strings + :rtype: list of str + """ + errors = [] + for i, m in enumerate(lst): + m_errs = [] + errors.extend(check_list_case(fields, m.keys(), prefix="%d " % (i+1))) + for f in fields: + if f not in m: + m_errs.append("'%s'" % f) + if m_errs: + errors.append("%d is missing %s" % (i+1, ", ".join(m_errs))) + return errors
    + +
    [docs]def check_list_case(expected_keys, recipe_keys, prefix=""): + """Check the case of the recipe keys + + :param expected_keys: A list of expected key strings + :type expected_keys: list of str + :param recipe_keys: A list of the recipe's key strings + :type recipe_keys: list of str + :returns: list of errors + :rtype: list of str + """ + errors = [] + for k in recipe_keys: + if k in expected_keys: + continue + if k.lower() in expected_keys: + errors.append(prefix + "%s should be %s" % (k, k.lower())) + return errors
    + +
    [docs]def check_recipe_dict(recipe_dict): + """Check a dict before using it to create a new Recipe + + :param recipe_dict: A plain dict of the recipe + :type recipe_dict: dict + :returns: True if dict is ok + :rtype: bool + :raises: RecipeError + + This checks a dict to make sure required fields are present, + that optional fields are correct, and that other optional fields + are of the correct format, when included. + + This collects all of the errors and returns a single RecipeError with + a string that can be presented to users. + """ + errors = [] + + # Check for wrong case of top level keys + top_keys = ["name", "description", "version", "modules", "packages", "groups", "repos", "customizations"] + errors.extend(check_list_case(recipe_dict.keys(), top_keys)) + + if "name" not in recipe_dict: + errors.append("Missing 'name'") + if "description" not in recipe_dict: + errors.append("Missing 'description'") + if "version" in recipe_dict: + try: + semver.Version(recipe_dict["version"]) + except ValueError: + errors.append("Invalid 'version', must use Semantic Versioning") + + # Examine all the modules + if recipe_dict.get("modules"): + module_errors = check_required_list(recipe_dict["modules"], ["name", "version"]) + if module_errors: + errors.append("'modules' errors:\n%s" % "\n".join(module_errors)) + + # Examine all the packages + if recipe_dict.get("packages"): + package_errors = check_required_list(recipe_dict["packages"], ["name", "version"]) + if package_errors: + errors.append("'packages' errors:\n%s" % "\n".join(package_errors)) + + if recipe_dict.get("groups"): + groups_errors = check_required_list(recipe_dict["groups"], ["name"]) + if groups_errors: + errors.append("'groups' errors:\n%s" % "\n".join(groups_errors)) + + if recipe_dict.get("repos") and recipe_dict.get("repos").get("git"): + repos_errors = check_required_list(recipe_dict.get("repos").get("git"), + ["rpmname", "rpmversion", "rpmrelease", "summary", "repo", "ref", "destination"]) + if repos_errors: + errors.append("'repos.git' errors:\n%s" % "\n".join(repos_errors)) + + # No customizations to check, exit now + c = recipe_dict.get("customizations") + if not c: + return errors + + # Make sure to catch empty sections by testing for keywords, not just looking at .get() result. + if "kernel" in c: + errors.extend(check_list_case(["append"], c["kernel"].keys(), prefix="kernel ")) + if "append" not in c.get("kernel", []): + errors.append("'customizations.kernel': missing append field.") + + if "sshkey" in c: + sshkey_errors = check_required_list(c.get("sshkey"), ["user", "key"]) + if sshkey_errors: + errors.append("'customizations.sshkey' errors:\n%s" % "\n".join(sshkey_errors)) + + if "user" in c: + user_errors = check_required_list(c.get("user"), ["name"]) + if user_errors: + errors.append("'customizations.user' errors:\n%s" % "\n".join(user_errors)) + + if "group" in c: + group_errors = check_required_list(c.get("group"), ["name"]) + if group_errors: + errors.append("'customizations.group' errors:\n%s" % "\n".join(group_errors)) + + if "timezone" in c: + errors.extend(check_list_case(["timezone", "ntpservers"], c["timezone"].keys(), prefix="timezone ")) + if not c.get("timezone"): + errors.append("'customizations.timezone': missing timezone or ntpservers fields.") + + if "locale" in c: + errors.extend(check_list_case(["languages", "keyboard"], c["locale"].keys(), prefix="locale ")) + if not c.get("locale"): + errors.append("'customizations.locale': missing languages or keyboard fields.") + + if "firewall" in c: + errors.extend(check_list_case(["ports"], c["firewall"].keys(), prefix="firewall ")) + if not c.get("firewall"): + errors.append("'customizations.firewall': missing ports field or services section.") + + if "services" in c.get("firewall", []): + errors.extend(check_list_case(["enabled", "disabled"], c["firewall"]["services"].keys(), prefix="firewall.services ")) + if not c.get("firewall").get("services"): + errors.append("'customizations.firewall.services': missing enabled or disabled fields.") + + if "services" in c: + errors.extend(check_list_case(["enabled", "disabled"], c["services"].keys(), prefix="services ")) + if not c.get("services"): + errors.append("'customizations.services': missing enabled or disabled fields.") + + return errors
    + +
    [docs]def recipe_from_dict(recipe_dict): + """Create a Recipe object from a plain dict. + + :param recipe_dict: A plain dict of the recipe + :type recipe_dict: dict + :returns: A Recipe object + :rtype: Recipe + :raises: RecipeError + """ + errors = check_recipe_dict(recipe_dict) + if errors: + msg = "\n".join(errors) + raise RecipeError(msg) + + # Make RecipeModule objects from the toml + # The TOML may not have modules or packages in it. Set them to None in this case + try: + if recipe_dict.get("modules"): + modules = [RecipeModule(m.get("name"), m.get("version")) for m in recipe_dict["modules"]] + else: + modules = [] + if recipe_dict.get("packages"): + packages = [RecipePackage(p.get("name"), p.get("version")) for p in recipe_dict["packages"]] + else: + packages = [] + if recipe_dict.get("groups"): + groups = [RecipeGroup(g.get("name")) for g in recipe_dict["groups"]] + else: + groups = [] + if recipe_dict.get("repos") and recipe_dict.get("repos").get("git"): + gitrepos = [NewRecipeGit(r) for r in recipe_dict["repos"]["git"]] + else: + gitrepos = [] + name = recipe_dict["name"] + description = recipe_dict["description"] + version = recipe_dict.get("version", None) + customizations = recipe_dict.get("customizations", None) + + # [customizations] was incorrectly documented at first, so we have to support using it + # as [[customizations]] by grabbing the first element. + if isinstance(customizations, list): + customizations = customizations[0] + + except KeyError as e: + raise RecipeError("There was a problem parsing the recipe: %s" % str(e)) + + return Recipe(name, description, version, modules, packages, groups, customizations, gitrepos)
    + +
    [docs]def gfile(path): + """Convert a string path to GFile for use with Git""" + return Gio.file_new_for_path(path)
    + +
    [docs]def recipe_filename(name): + """Return the toml filename for a recipe + + Replaces spaces with '-' and appends '.toml' + """ + # XXX Raise and error if this is empty? + return name.replace(" ", "-") + ".toml"
    + +
    [docs]def head_commit(repo, branch): + """Get the branch's HEAD Commit Object + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :returns: Branch's head commit + :rtype: Git.Commit + :raises: Can raise errors from Ggit + """ + branch_obj = repo.lookup_branch(branch, Git.BranchType.LOCAL) + commit_id = branch_obj.get_target() + return repo.lookup(commit_id, Git.Commit)
    + +
    [docs]def prepare_commit(repo, branch, builder): + """Prepare for a commit + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param builder: instance of TreeBuilder + :type builder: TreeBuilder + :returns: (Tree, Sig, Ref) + :rtype: tuple + :raises: Can raise errors from Ggit + """ + tree_id = builder.write() + tree = repo.lookup(tree_id, Git.Tree) + sig = Git.Signature.new_now("bdcs-api-server", "user-email") + ref = "refs/heads/%s" % branch + return (tree, sig, ref)
    + +
    [docs]def open_or_create_repo(path): + """Open an existing repo, or create a new one + + :param path: path to recipe directory + :type path: string + :returns: A repository object + :rtype: Git.Repository + :raises: Can raise errors from Ggit + + A bare git repo will be created in the git directory of the specified path. + If a repo already exists it will be opened and returned instead of + creating a new one. + """ + Git.init() + git_path = joinpaths(path, "git") + if os.path.exists(joinpaths(git_path, "HEAD")): + return Git.Repository.open(gfile(git_path)) + + repo = Git.Repository.init_repository(gfile(git_path), True) + + # Make an initial empty commit + sig = Git.Signature.new_now("bdcs-api-server", "user-email") + tree_id = repo.get_index().write_tree() + tree = repo.lookup(tree_id, Git.Tree) + repo.create_commit("HEAD", sig, sig, "UTF-8", "Initial Recipe repository commit", tree, []) + return repo
    + +
    [docs]def write_commit(repo, branch, filename, message, content): + """Make a new commit to a repository's branch + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param filename: full path of the file to add + :type filename: str + :param message: The commit message + :type message: str + :param content: The data to write + :type content: str + :returns: OId of the new commit + :rtype: Git.OId + :raises: Can raise errors from Ggit + """ + try: + parent_commit = head_commit(repo, branch) + except GLib.GError: + # Branch doesn't exist, make a new one based on master + master_head = head_commit(repo, "master") + repo.create_branch(branch, master_head, 0) + parent_commit = head_commit(repo, branch) + + parent_commit = head_commit(repo, branch) + blob_id = repo.create_blob_from_buffer(content.encode("UTF-8")) + + # Use treebuilder to make a new entry for this filename and blob + parent_tree = parent_commit.get_tree() + builder = repo.create_tree_builder_from_tree(parent_tree) + builder.insert(filename, blob_id, Git.FileMode.BLOB) + (tree, sig, ref) = prepare_commit(repo, branch, builder) + return repo.create_commit(ref, sig, sig, "UTF-8", message, tree, [parent_commit])
    + +
    [docs]def read_commit_spec(repo, spec): + """Return the raw content of the blob specified by the spec + + :param repo: Open repository + :type repo: Git.Repository + :param spec: Git revparse spec + :type spec: str + :returns: Contents of the commit + :rtype: str + :raises: Can raise errors from Ggit + + eg. To read the README file from master the spec is "master:README" + """ + commit_id = repo.revparse(spec).get_id() + blob = repo.lookup(commit_id, Git.Blob) + return blob.get_raw_content()
    + +
    [docs]def read_commit(repo, branch, filename, commit=None): + """Return the contents of a file on a specific branch or commit. + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param filename: filename to read + :type filename: str + :param commit: Optional commit hash + :type commit: str + :returns: The commit id, and the contents of the commit + :rtype: tuple(str, str) + :raises: Can raise errors from Ggit + + If no commit is passed the master:filename is returned, otherwise it will be + commit:filename + """ + if not commit: + # Find the most recent commit for filename on the selected branch + commits = list_commits(repo, branch, filename, 1) + if not commits: + raise RecipeError("No commits for %s on the %s branch." % (filename, branch)) + commit = commits[0].commit + return (commit, read_commit_spec(repo, "%s:%s" % (commit, filename)))
    + +
    [docs]def read_recipe_commit(repo, branch, recipe_name, commit=None): + """Read a recipe commit from git and return a Recipe object + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param recipe_name: Recipe name to read + :type recipe_name: str + :param commit: Optional commit hash + :type commit: str + :returns: A Recipe object + :rtype: Recipe + :raises: Can raise errors from Ggit + + If no commit is passed the master:filename is returned, otherwise it will be + commit:filename + """ + if not repo_file_exists(repo, branch, recipe_filename(recipe_name)): + raise RecipeFileError("Unknown blueprint") + + (_, recipe_toml) = read_commit(repo, branch, recipe_filename(recipe_name), commit) + return recipe_from_toml(recipe_toml)
    + +
    [docs]def read_recipe_and_id(repo, branch, recipe_name, commit=None): + """Read a recipe commit and its id from git + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param recipe_name: Recipe name to read + :type recipe_name: str + :param commit: Optional commit hash + :type commit: str + :returns: The commit id, and a Recipe object + :rtype: tuple(str, Recipe) + :raises: Can raise errors from Ggit + + If no commit is passed the master:filename is returned, otherwise it will be + commit:filename + """ + (commit_id, recipe_toml) = read_commit(repo, branch, recipe_filename(recipe_name), commit) + return (commit_id, recipe_from_toml(recipe_toml))
    + +
    [docs]def list_branch_files(repo, branch): + """Return a sorted list of the files on the branch HEAD + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :returns: A sorted list of the filenames + :rtype: list(str) + :raises: Can raise errors from Ggit + """ + commit = head_commit(repo, branch).get_id().to_string() + return list_commit_files(repo, commit)
    + +
    [docs]def list_commit_files(repo, commit): + """Return a sorted list of the files on a commit + + :param repo: Open repository + :type repo: Git.Repository + :param commit: The commit hash to list + :type commit: str + :returns: A sorted list of the filenames + :rtype: list(str) + :raises: Can raise errors from Ggit + """ + commit_id = Git.OId.new_from_string(commit) + commit_obj = repo.lookup(commit_id, Git.Commit) + tree = commit_obj.get_tree() + return sorted([tree.get(i).get_name() for i in range(0, tree.size())])
    + +
    [docs]def delete_recipe(repo, branch, recipe_name): + """Delete a recipe from a branch. + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param recipe_name: Recipe name to delete + :type recipe_name: str + :returns: OId of the new commit + :rtype: Git.OId + :raises: Can raise errors from Ggit + """ + return delete_file(repo, branch, recipe_filename(recipe_name))
    + +
    [docs]def delete_file(repo, branch, filename): + """Delete a file from a branch. + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param filename: filename to delete + :type filename: str + :returns: OId of the new commit + :rtype: Git.OId + :raises: Can raise errors from Ggit + """ + parent_commit = head_commit(repo, branch) + parent_tree = parent_commit.get_tree() + builder = repo.create_tree_builder_from_tree(parent_tree) + builder.remove(filename) + (tree, sig, ref) = prepare_commit(repo, branch, builder) + message = "Recipe %s deleted" % filename + return repo.create_commit(ref, sig, sig, "UTF-8", message, tree, [parent_commit])
    + +
    [docs]def revert_recipe(repo, branch, recipe_name, commit): + """Revert the contents of a recipe to that of a previous commit + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param recipe_name: Recipe name to revert + :type recipe_name: str + :param commit: Commit hash + :type commit: str + :returns: OId of the new commit + :rtype: Git.OId + :raises: Can raise errors from Ggit + """ + return revert_file(repo, branch, recipe_filename(recipe_name), commit)
    + +
    [docs]def revert_file(repo, branch, filename, commit): + """Revert the contents of a file to that of a previous commit + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param filename: filename to revert + :type filename: str + :param commit: Commit hash + :type commit: str + :returns: OId of the new commit + :rtype: Git.OId + :raises: Can raise errors from Ggit + """ + commit_id = Git.OId.new_from_string(commit) + commit_obj = repo.lookup(commit_id, Git.Commit) + revert_tree = commit_obj.get_tree() + entry = revert_tree.get_by_name(filename) + blob_id = entry.get_id() + parent_commit = head_commit(repo, branch) + + # Use treebuilder to modify the tree + parent_tree = parent_commit.get_tree() + builder = repo.create_tree_builder_from_tree(parent_tree) + builder.insert(filename, blob_id, Git.FileMode.BLOB) + (tree, sig, ref) = prepare_commit(repo, branch, builder) + commit_hash = commit_id.to_string() + message = "%s reverted to commit %s" % (filename, commit_hash) + return repo.create_commit(ref, sig, sig, "UTF-8", message, tree, [parent_commit])
    + +
    [docs]def commit_recipe(repo, branch, recipe): + """Commit a recipe to a branch + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param recipe: Recipe to commit + :type recipe: Recipe + :returns: OId of the new commit + :rtype: Git.OId + :raises: Can raise errors from Ggit + """ + try: + old_recipe = read_recipe_commit(repo, branch, recipe["name"]) + old_version = old_recipe["version"] + except Exception: + old_version = None + + recipe.bump_version(old_version) + recipe_toml = recipe.toml() + message = "Recipe %s, version %s saved." % (recipe["name"], recipe["version"]) + return write_commit(repo, branch, recipe.filename, message, recipe_toml)
    + +
    [docs]def commit_recipe_file(repo, branch, filename): + """Commit a recipe file to a branch + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param filename: Path to the recipe file to commit + :type filename: str + :returns: OId of the new commit + :rtype: Git.OId + :raises: Can raise errors from Ggit or RecipeFileError + """ + try: + recipe = recipe_from_file(filename) + except IOError: + raise RecipeFileError + + return commit_recipe(repo, branch, recipe)
    + +
    [docs]def commit_recipe_directory(repo, branch, directory): + r"""Commit all \*.toml files from a directory, if they aren't already in git. + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param directory: The directory of \*.toml recipes to commit + :type directory: str + :returns: None + :raises: Can raise errors from Ggit or RecipeFileError + + Files with Toml or RecipeFileErrors will be skipped, and the remainder will + be tried. + """ + dir_files = set([e for e in os.listdir(directory) if e.endswith(".toml")]) + branch_files = set(list_branch_files(repo, branch)) + new_files = dir_files.difference(branch_files) + + for f in new_files: + # Skip files with errors, but try the others + try: + commit_recipe_file(repo, branch, joinpaths(directory, f)) + except (RecipeError, RecipeFileError, toml.TomlError): + pass
    + +
    [docs]def tag_recipe_commit(repo, branch, recipe_name): + """Tag a file's most recent commit + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param recipe_name: Recipe name to tag + :type recipe_name: str + :returns: Tag id or None if it failed. + :rtype: Git.OId + :raises: Can raise errors from Ggit + + Uses tag_file_commit() + """ + if not repo_file_exists(repo, branch, recipe_filename(recipe_name)): + raise RecipeFileError("Unknown blueprint") + + return tag_file_commit(repo, branch, recipe_filename(recipe_name))
    + +
    [docs]def tag_file_commit(repo, branch, filename): + """Tag a file's most recent commit + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param filename: Filename to tag + :type filename: str + :returns: Tag id or None if it failed. + :rtype: Git.OId + :raises: Can raise errors from Ggit + + This uses git tags, of the form `refs/tags/<branch>/<filename>/r<revision>` + Only the most recent recipe commit can be tagged to prevent out of order tagging. + Revisions start at 1 and increment for each new commit that is tagged. + If the commit has already been tagged it will return false. + """ + file_commits = list_commits(repo, branch, filename) + if not file_commits: + return None + + # Find the most recently tagged version (may not be one) and add 1 to it. + for details in file_commits: + if details.revision is not None: + new_revision = details.revision + 1 + break + else: + new_revision = 1 + + name = "%s/%s/r%d" % (branch, filename, new_revision) + sig = Git.Signature.new_now("bdcs-api-server", "user-email") + commit_id = Git.OId.new_from_string(file_commits[0].commit) + commit = repo.lookup(commit_id, Git.Commit) + return repo.create_tag(name, commit, sig, name, Git.CreateFlags.NONE)
    + +
    [docs]def find_commit_tag(repo, branch, filename, commit_id): + """Find the tag that matches the commit_id + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param filename: filename to revert + :type filename: str + :param commit_id: The commit id to check + :type commit_id: Git.OId + :returns: The tag or None if there isn't one + :rtype: str or None + + There should be only 1 tag pointing to a commit, but there may not + be a tag at all. + + The tag will look like: 'refs/tags/<branch>/<filename>/r<revision>' + """ + pattern = "%s/%s/r*" % (branch, filename) + tags = [t for t in repo.list_tags_match(pattern) if is_commit_tag(repo, commit_id, t)] + if len(tags) != 1: + return None + else: + return tags[0]
    + +
    [docs]def is_commit_tag(repo, commit_id, tag): + """Check to see if a tag points to a specific commit. + + :param repo: Open repository + :type repo: Git.Repository + :param commit_id: The commit id to check + :type commit_id: Git.OId + :param tag: The tag to check + :type tag: str + :returns: True if the tag points to the commit, False otherwise + :rtype: bool + """ + ref = repo.lookup_reference("refs/tags/" + tag) + tag_id = ref.get_target() + tag = repo.lookup(tag_id, Git.Tag) + target_id = tag.get_target_id() + return commit_id.compare(target_id) == 0
    + +
    [docs]def get_revision_from_tag(tag): + """Return the revision number from a tag + + :param tag: The tag to exract the revision from + :type tag: str + :returns: The integer revision or None + :rtype: int or None + + The revision is the part after the r in 'branch/filename/rXXX' + """ + if tag is None: + return None + try: + return int(tag.rsplit('r', 2)[-1]) + except (ValueError, IndexError): + return None
    + +
    [docs]class CommitDetails(DataHolder): + def __init__(self, commit, timestamp, message, revision=None): + DataHolder.__init__(self, + commit = commit, + timestamp = timestamp, + message = message, + revision = revision)
    + +
    [docs]def list_commits(repo, branch, filename, limit=0): + """List the commit history of a file on a branch. + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param filename: filename to revert + :type filename: str + :param limit: Number of commits to return (0=all) + :type limit: int + :returns: A list of commit details + :rtype: list(CommitDetails) + :raises: Can raise errors from Ggit + """ + revwalk = Git.RevisionWalker.new(repo) + branch_ref = "refs/heads/%s" % branch + revwalk.push_ref(branch_ref) + + commits = [] + while True: + commit_id = revwalk.next() + if not commit_id: + break + commit = repo.lookup(commit_id, Git.Commit) + + parents = commit.get_parents() + # No parents? Must be the first commit. + if parents.get_size() == 0: + continue + + tree = commit.get_tree() + # Is the filename in this tree? If not, move on. + if not tree.get_by_name(filename): + continue + + # Is filename different in all of the parent commits? + parent_commits = list(map(parents.get, range(0, parents.get_size()))) + is_diff = all([is_parent_diff(repo, filename, tree, pc) for pc in parent_commits]) + # No changes from parents, skip it. + if not is_diff: + continue + + tag = find_commit_tag(repo, branch, filename, commit.get_id()) + try: + commits.append(get_commit_details(commit, get_revision_from_tag(tag))) + if limit and len(commits) > limit: + break + except CommitTimeValError: + # Skip any commits that have trouble converting the time + # TODO - log details about this failure + pass + + # These will be in reverse time sort order thanks to revwalk + return commits
    + +
    [docs]def get_commit_details(commit, revision=None): + """Return the details about a specific commit. + + :param commit: The commit to get details from + :type commit: Git.Commit + :param revision: Optional commit revision + :type revision: int + :returns: Details about the commit + :rtype: CommitDetails + :raises: CommitTimeValError or Ggit exceptions + + """ + message = commit.get_message() + commit_str = commit.get_id().to_string() + sig = commit.get_committer() + + datetime = sig.get_time() + # XXX What do we do with timezone? + _timezone = sig.get_time_zone() + time_str = datetime.format_iso8601() + if not time_str: + raise CommitTimeValError + + return CommitDetails(commit_str, time_str, message, revision)
    + +
    [docs]def is_parent_diff(repo, filename, tree, parent): + """Check to see if the commit is different from its parents + + :param repo: Open repository + :type repo: Git.Repository + :param filename: filename to revert + :type filename: str + :param tree: The commit's tree + :type tree: Git.Tree + :param parent: The commit's parent commit + :type parent: Git.Commit + :retuns: True if filename in the commit is different from its parents + :rtype: bool + """ + diff_opts = Git.DiffOptions.new() + diff_opts.set_pathspec([filename]) + diff = Git.Diff.new_tree_to_tree(repo, parent.get_tree(), tree, diff_opts) + return diff.get_num_deltas() > 0
    + +
    [docs]def find_field_value(field, value, lst): + """Find a field matching value in the list of dicts. + + :param field: field to search for + :type field: str + :param value: value to match in the field + :type value: str + :param lst: List of dict's with field + :type lst: list of dict + :returns: First dict with matching field:value, or None + :rtype: dict or None + + Used to return a specific entry from a list that looks like this: + + [{"name": "one", "attr": "green"}, ...] + + find_field_value("name", "one", lst) will return the matching dict. + """ + for d in lst: + if d.get(field) and d.get(field) == value: + return d + return None
    + +
    [docs]def find_name(name, lst): + """Find the dict matching the name in a list and return it. + + :param name: Name to search for + :type name: str + :param lst: List of dict's with "name" field + :type lst: list of dict + :returns: First dict with matching name, or None + :rtype: dict or None + + This is just a wrapper for find_field_value with field set to "name" + """ + return find_field_value("name", name, lst)
    + +
    [docs]def find_recipe_obj(path, recipe, default=None): + """Find a recipe object + + :param path: A list of dict field names + :type path: list of str + :param recipe: The recipe to search + :type recipe: Recipe + :param default: The value to return if it is not found + :type default: Any + + Return the object found by applying the path to the dicts in the recipe, or + return the default if it doesn't exist. + + eg. {"customizations": {"hostname": "foo", "users": [...]}} + + find_recipe_obj(["customizations", "hostname"], recipe, "") + """ + o = recipe + try: + for p in path: + if not o.get(p): + return default + o = o.get(p) + except AttributeError: + return default + + return o
    + +
    [docs]def diff_lists(title, field, old_items, new_items): + """Return the differences between two lists of dicts. + + :param title: Title of the entry + :type title: str + :param field: Field to use as the key for comparisons + :type field: str + :param old_items: List of item dicts with "name" field + :type old_items: list(dict) + :param new_items: List of item dicts with "name" field + :type new_items: list(dict) + :returns: List of diff dicts with old/new entries + :rtype: list(dict) + """ + diffs = [] + old_fields= set(m[field] for m in old_items) + new_fields= set(m[field] for m in new_items) + + added_items = new_fields.difference(old_fields) + added_items = sorted(added_items, key=lambda n: n.lower()) + + removed_items = old_fields.difference(new_fields) + removed_items = sorted(removed_items, key=lambda n: n.lower()) + + same_items = old_fields.intersection(new_fields) + same_items = sorted(same_items, key=lambda n: n.lower()) + + for v in added_items: + diffs.append({"old":None, + "new":{title:find_field_value(field, v, new_items)}}) + + for v in removed_items: + diffs.append({"old":{title:find_field_value(field, v, old_items)}, + "new":None}) + + for v in same_items: + old_item = find_field_value(field, v, old_items) + new_item = find_field_value(field, v, new_items) + if old_item != new_item: + diffs.append({"old":{title:old_item}, + "new":{title:new_item}}) + + return diffs
    + +
    [docs]def customizations_diff(old_recipe, new_recipe): + """Diff the customizations sections from two versions of a recipe + """ + diffs = [] + old_keys = set(old_recipe.get("customizations", {}).keys()) + new_keys = set(new_recipe.get("customizations", {}).keys()) + + added_keys = new_keys.difference(old_keys) + added_keys = sorted(added_keys, key=lambda n: n.lower()) + + removed_keys = old_keys.difference(new_keys) + removed_keys = sorted(removed_keys, key=lambda n: n.lower()) + + same_keys = old_keys.intersection(new_keys) + same_keys = sorted(same_keys, key=lambda n: n.lower()) + + for v in added_keys: + diffs.append({"old": None, + "new": {"Customizations."+v: new_recipe["customizations"][v]}}) + + for v in removed_keys: + diffs.append({"old": {"Customizations."+v: old_recipe["customizations"][v]}, + "new": None}) + + for v in same_keys: + if new_recipe["customizations"][v] == old_recipe["customizations"][v]: + continue + + if type(new_recipe["customizations"][v]) == type([]): + # Lists of dicts need to use diff_lists + # sshkey uses 'user', user and group use 'name' + if "user" in new_recipe["customizations"][v][0]: + field_name = "user" + elif "name" in new_recipe["customizations"][v][0]: + field_name = "name" + else: + raise RuntimeError("%s list has unrecognized key, not 'name' or 'user'" % "customizations."+v) + + diffs.extend(diff_lists("Customizations."+v, field_name, old_recipe["customizations"][v], new_recipe["customizations"][v])) + else: + diffs.append({"old": {"Customizations."+v: old_recipe["customizations"][v]}, + "new": {"Customizations."+v: new_recipe["customizations"][v]}}) + + return diffs
    + + +
    [docs]def recipe_diff(old_recipe, new_recipe): + """Diff two versions of a recipe + + :param old_recipe: The old version of the recipe + :type old_recipe: Recipe + :param new_recipe: The new version of the recipe + :type new_recipe: Recipe + :returns: A list of diff dict entries with old/new + :rtype: list(dict) + """ + + diffs = [] + # These cannot be added or removed, just different + for element in ["name", "description", "version"]: + if old_recipe[element] != new_recipe[element]: + diffs.append({"old":{element.title():old_recipe[element]}, + "new":{element.title():new_recipe[element]}}) + + # These lists always exist + diffs.extend(diff_lists("Module", "name", old_recipe["modules"], new_recipe["modules"])) + diffs.extend(diff_lists("Package", "name", old_recipe["packages"], new_recipe["packages"])) + diffs.extend(diff_lists("Group", "name", old_recipe["groups"], new_recipe["groups"])) + + # The customizations section can contain a number of different types + diffs.extend(customizations_diff(old_recipe, new_recipe)) + + # repos contains keys that are lists (eg. [[repos.git]]) + diffs.extend(diff_lists("Repos.git", "rpmname", + find_recipe_obj(["repos", "git"], old_recipe, []), + find_recipe_obj(["repos", "git"], new_recipe, []))) + + return diffs
    + +
    [docs]def repo_file_exists(repo, branch, filename): + """Return True if the filename exists on the branch + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param filename: Filename to check + :type filename: str + :returns: True if the filename exists on the HEAD of the branch, False otherwise. + :rtype: bool + """ + commit = head_commit(repo, branch).get_id().to_string() + commit_id = Git.OId.new_from_string(commit) + commit_obj = repo.lookup(commit_id, Git.Commit) + tree = commit_obj.get_tree() + return tree.get_by_name(filename) is not None
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/server.html b/f32-branch/_modules/pylorax/api/server.html new file mode 100644 index 00000000..34cb9aea --- /dev/null +++ b/f32-branch/_modules/pylorax/api/server.html @@ -0,0 +1,304 @@ + + + + + + + + + + + pylorax.api.server — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.server

    +#
    +# Copyright (C) 2017-2019 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("lorax-composer")
    +
    +from collections import namedtuple
    +from flask import Flask, jsonify, redirect, send_from_directory
    +from glob import glob
    +import os
    +import werkzeug
    +
    +from pylorax import vernum
    +from pylorax.api.errors import HTTP_ERROR
    +from pylorax.api.v0 import v0_api
    +from pylorax.api.v1 import v1_api
    +from pylorax.sysutils import joinpaths
    +
    +GitLock = namedtuple("GitLock", ["repo", "lock", "dir"])
    +
    +server = Flask(__name__)
    +
    +__all__ = ["server", "GitLock"]
    +
    +@server.route('/')
    +def server_root():
    +    redirect("/api/docs/")
    +
    +@server.route("/api/docs/")
    +@server.route("/api/docs/<path:path>")
    +def api_docs(path=None):
    +    # Find the html docs
    +    try:
    +        # This assumes it is running from the source tree
    +        docs_path = os.path.abspath(joinpaths(os.path.dirname(__file__), "../../../docs/html"))
    +    except IndexError:
    +        docs_path = glob("/usr/share/doc/lorax-*/html/")[0]
    +
    +    if not path:
    +        path="index.html"
    +    return send_from_directory(docs_path, path)
    +
    +@server.route("/api/status")
    +def api_status():
    +    """
    +    `/api/status`
    +    ^^^^^^^^^^^^^^^^
    +    Return the status of the API Server::
    +
    +          { "api": "0",
    +            "build": "devel",
    +            "db_supported": true,
    +            "db_version": "0",
    +            "schema_version": "0",
    +            "backend": "lorax-composer",
    +            "msgs": []}
    +
    +    The 'msgs' field can be a list of strings describing startup problems or status that
    +    should be displayed to the user. eg. if the compose templates are not depsolving properly
    +    the errors will be in 'msgs'.
    +    """
    +    return jsonify(backend="lorax-composer",
    +                   build=vernum,
    +                   api="1",
    +                   db_version="0",
    +                   schema_version="0",
    +                   db_supported=True,
    +                   msgs=server.config["TEMPLATE_ERRORS"])
    +
    +@server.errorhandler(werkzeug.exceptions.HTTPException)
    +def bad_request(error):
    +    return jsonify(status=False, errors=[{ "id": HTTP_ERROR, "code": error.code, "msg": error.name }]), error.code
    +
    +# Register the v0 API on /api/v0/
    +server.register_blueprint(v0_api, url_prefix="/api/v0/")
    +
    +# Register the v1 API on /api/v1/
    +# Use v0 routes by default
    +skip_rules = [
    +    "/compose",
    +    "/compose/queue",
    +    "/compose/finished",
    +    "/compose/failed",
    +    "/compose/status/<uuids>",
    +    "/compose/info/<uuid>",
    +    "/projects/source/info/<source_names>",
    +    "/projects/source/new",
    +]
    +server.register_blueprint(v0_api, url_prefix="/api/v1/", skip_rules=skip_rules)
    +server.register_blueprint(v1_api, url_prefix="/api/v1/")
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/timestamp.html b/f32-branch/_modules/pylorax/api/timestamp.html new file mode 100644 index 00000000..3c321d9e --- /dev/null +++ b/f32-branch/_modules/pylorax/api/timestamp.html @@ -0,0 +1,252 @@ + + + + + + + + + + + pylorax.api.timestamp — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.timestamp

    +#
    +# Copyright (C) 2018  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +import time
    +
    +from pylorax.sysutils import joinpaths
    +import pylorax.api.toml as toml
    +
    +TS_CREATED  = "created"
    +TS_STARTED  = "started"
    +TS_FINISHED = "finished"
    +
    +
    [docs]def write_timestamp(destdir, ty): + path = joinpaths(destdir, "times.toml") + + try: + contents = toml.loads(open(path, "r").read()) + except IOError: + contents = toml.loads("") + + if ty == TS_CREATED: + contents[TS_CREATED] = time.time() + elif ty == TS_STARTED: + contents[TS_STARTED] = time.time() + elif ty == TS_FINISHED: + contents[TS_FINISHED] = time.time() + + with open(path, "w") as f: + f.write(toml.dumps(contents))
    + +
    [docs]def timestamp_dict(destdir): + path = joinpaths(destdir, "times.toml") + + try: + return toml.loads(open(path, "r").read()) + except IOError: + return toml.loads("")
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/toml.html b/f32-branch/_modules/pylorax/api/toml.html new file mode 100644 index 00000000..c39ba1db --- /dev/null +++ b/f32-branch/_modules/pylorax/api/toml.html @@ -0,0 +1,243 @@ + + + + + + + + + + + pylorax.api.toml — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.toml

    +#
    +# Copyright (C) 2019  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +import toml
    +
    +
    [docs]class TomlError(toml.TomlDecodeError): + pass
    + +
    [docs]def loads(s): + if isinstance(s, bytes): + s = s.decode('utf-8') + try: + return toml.loads(s) + except toml.TomlDecodeError as e: + raise TomlError(e.msg, e.doc, e.pos)
    + +
    [docs]def dumps(o): + # strip the result, because `toml.dumps` adds a lot of newlines + return toml.dumps(o, encoder=toml.TomlEncoder(dict)).strip()
    + +
    [docs]def load(file): + try: + return toml.load(file) + except toml.TomlDecodeError as e: + raise TomlError(e.msg, e.doc, e.pos)
    + +
    [docs]def dump(o, file): + return toml.dump(o, file)
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/utils.html b/f32-branch/_modules/pylorax/api/utils.html new file mode 100644 index 00000000..006df2b1 --- /dev/null +++ b/f32-branch/_modules/pylorax/api/utils.html @@ -0,0 +1,250 @@ + + + + + + + + + + + pylorax.api.utils — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.utils

    +#
    +# Copyright (C) 2019  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +""" API utility functions
    +"""
    +from pylorax.api.recipes import RecipeError, RecipeFileError, read_recipe_commit
    +
    +
    [docs]def take_limits(iterable, offset, limit): + """ Apply offset and limit to an iterable object + + :param iterable: The object to limit + :type iterable: iter + :param offset: The number of items to skip + :type offset: int + :param limit: The total number of items to return + :type limit: int + :returns: A subset of the iterable + """ + return iterable[offset:][:limit]
    + +
    [docs]def blueprint_exists(api, branch, blueprint_name): + """Return True if the blueprint exists + + :param api: flask object + :type api: Flask + :param branch: Branch name + :type branch: str + :param recipe_name: Recipe name to read + :type recipe_name: str + """ + try: + with api.config["GITLOCK"].lock: + read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) + + return True + except (RecipeError, RecipeFileError): + return False
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/v0.html b/f32-branch/_modules/pylorax/api/v0.html new file mode 100644 index 00000000..a1579042 --- /dev/null +++ b/f32-branch/_modules/pylorax/api/v0.html @@ -0,0 +1,2187 @@ + + + + + + + + + + + pylorax.api.v0 — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.v0

    +#
    +# Copyright (C) 2017-2019  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +""" Setup v0 of the API server
    +
    +v0_api() must be called to setup the API routes for Flask
    +
    +Status Responses
    +----------------
    +
    +Some requests only return a status/error response.
    +
    +  The response will be a status response with `status` set to true, or an
    +  error response with it set to false and an error message included.
    +
    +  Example response::
    +
    +      {
    +        "status": true
    +      }
    +
    +  Error response::
    +
    +      {
    +        "errors": ["ggit-error: Failed to remove entry. File isn't in the tree - jboss.toml (-1)"]
    +        "status": false
    +      }
    +
    +API Routes
    +----------
    +
    +All of the blueprints routes support the optional `branch` argument. If it is not
    +used then the API will use the `master` branch for blueprints. If you want to create
    +a new branch use the `new` or `workspace` routes with ?branch=<branch-name> to
    +store the new blueprint on the new branch.
    +"""
    +
    +import logging
    +log = logging.getLogger("lorax-composer")
    +
    +import os
    +from flask import jsonify, request, Response, send_file
    +from flask import current_app as api
    +
    +from pylorax.sysutils import joinpaths
    +from pylorax.api.checkparams import checkparams
    +from pylorax.api.compose import start_build, compose_types
    +from pylorax.api.errors import *                               # pylint: disable=wildcard-import,unused-wildcard-import
    +from pylorax.api.flask_blueprint import BlueprintSkip
    +from pylorax.api.projects import projects_list, projects_info, projects_depsolve
    +from pylorax.api.projects import modules_list, modules_info, ProjectsError, repo_to_source
    +from pylorax.api.projects import get_repo_sources, delete_repo_source, new_repo_source
    +from pylorax.api.queue import queue_status, build_status, uuid_delete, uuid_status, uuid_info
    +from pylorax.api.queue import uuid_tar, uuid_image, uuid_cancel, uuid_log
    +from pylorax.api.recipes import list_branch_files, read_recipe_commit, recipe_filename, list_commits
    +from pylorax.api.recipes import recipe_from_dict, recipe_from_toml, commit_recipe, delete_recipe, revert_recipe
    +from pylorax.api.recipes import tag_recipe_commit, recipe_diff, RecipeFileError
    +from pylorax.api.regexes import VALID_API_STRING, VALID_BLUEPRINT_NAME
    +import pylorax.api.toml as toml
    +from pylorax.api.utils import take_limits, blueprint_exists
    +from pylorax.api.workspace import workspace_read, workspace_write, workspace_delete
    +
    +# The API functions don't actually get called by any code here
    +# pylint: disable=unused-variable
    +
    +# Create the v0 routes Blueprint with skip_routes support
    +v0_api = BlueprintSkip("v0_routes", __name__)
    +
    +
    [docs]@v0_api.route("/blueprints/list") +def v0_blueprints_list(): + """List the available blueprints on a branch. + + **/api/v0/blueprints/list** + + List the available blueprints:: + + { "limit": 20, + "offset": 0, + "blueprints": [ + "atlas", + "development", + "glusterfs", + "http-server", + "jboss", + "kubernetes" ], + "total": 6 } + """ + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + try: + limit = int(request.args.get("limit", "20")) + offset = int(request.args.get("offset", "0")) + except ValueError as e: + return jsonify(status=False, errors=[{"id": BAD_LIMIT_OR_OFFSET, "msg": str(e)}]), 400 + + with api.config["GITLOCK"].lock: + blueprints = [f[:-5] for f in list_branch_files(api.config["GITLOCK"].repo, branch)] + limited_blueprints = take_limits(blueprints, offset, limit) + return jsonify(blueprints=limited_blueprints, limit=limit, offset=offset, total=len(blueprints))
    + +
    [docs]@v0_api.route("/blueprints/info", defaults={'blueprint_names': ""}) +@v0_api.route("/blueprints/info/<blueprint_names>") +@checkparams([("blueprint_names", "", "no blueprint names given")]) +def v0_blueprints_info(blueprint_names): + """Return the contents of the blueprint, or a list of blueprints + + **/api/v0/blueprints/info/<blueprint_names>[?format=<json|toml>]** + + Return the JSON representation of the blueprint. This includes 3 top level + objects. `changes` which lists whether or not the workspace is different from + the most recent commit. `blueprints` which lists the JSON representation of the + blueprint, and `errors` which will list any errors, like non-existant blueprints. + + By default the response is JSON, but if `?format=toml` is included in the URL's + arguments it will return the response as the blueprint's raw TOML content. + *Unless* there is an error which will only return a 400 and a standard error + `Status Responses`_. + + If there is an error when JSON is requested the successful blueprints and the + errors will both be returned. + + Example of json response:: + + { + "changes": [ + { + "changed": false, + "name": "glusterfs" + } + ], + "errors": [], + "blueprints": [ + { + "description": "An example GlusterFS server with samba", + "modules": [ + { + "name": "glusterfs", + "version": "3.7.*" + }, + { + "name": "glusterfs-cli", + "version": "3.7.*" + } + ], + "name": "glusterfs", + "packages": [ + { + "name": "2ping", + "version": "3.2.1" + }, + { + "name": "samba", + "version": "4.2.*" + } + ], + "version": "0.0.6" + } + ] + } + + Error example:: + + { + "changes": [], + "errors": ["ggit-error: the path 'missing.toml' does not exist in the given tree (-3)"] + "blueprints": [] + } + """ + if any(VALID_BLUEPRINT_NAME.match(blueprint_name) is None for blueprint_name in blueprint_names.split(',')): + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + out_fmt = request.args.get("format", "json") + if VALID_API_STRING.match(out_fmt) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in format argument"}]), 400 + + blueprints = [] + changes = [] + errors = [] + for blueprint_name in [n.strip() for n in blueprint_names.split(",")]: + exceptions = [] + # Get the workspace version (if it exists) + try: + with api.config["GITLOCK"].lock: + ws_blueprint = workspace_read(api.config["GITLOCK"].repo, branch, blueprint_name) + except Exception as e: + ws_blueprint = None + exceptions.append(str(e)) + log.error("(v0_blueprints_info) %s", str(e)) + + # Get the git version (if it exists) + try: + with api.config["GITLOCK"].lock: + git_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) + except RecipeFileError as e: + # Adding an exception would be redundant, skip it + git_blueprint = None + log.error("(v0_blueprints_info) %s", str(e)) + except Exception as e: + git_blueprint = None + exceptions.append(str(e)) + log.error("(v0_blueprints_info) %s", str(e)) + + if not ws_blueprint and not git_blueprint: + # Neither blueprint, return an error + errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "%s: %s" % (blueprint_name, ", ".join(exceptions))}) + elif ws_blueprint and not git_blueprint: + # No git blueprint, return the workspace blueprint + changes.append({"name":blueprint_name, "changed":True}) + blueprints.append(ws_blueprint) + elif not ws_blueprint and git_blueprint: + # No workspace blueprint, no change, return the git blueprint + changes.append({"name":blueprint_name, "changed":False}) + blueprints.append(git_blueprint) + else: + # Both exist, maybe changed, return the workspace blueprint + changes.append({"name":blueprint_name, "changed":ws_blueprint != git_blueprint}) + blueprints.append(ws_blueprint) + + # Sort all the results by case-insensitive blueprint name + changes = sorted(changes, key=lambda c: c["name"].lower()) + blueprints = sorted(blueprints, key=lambda r: r["name"].lower()) + + if out_fmt == "toml": + if errors: + # If there are errors they need to be reported, use JSON and 400 for this + return jsonify(status=False, errors=errors), 400 + else: + # With TOML output we just want to dump the raw blueprint, skipping the rest. + return "\n\n".join([r.toml() for r in blueprints]) + else: + return jsonify(changes=changes, blueprints=blueprints, errors=errors)
    + +
    [docs]@v0_api.route("/blueprints/changes", defaults={'blueprint_names': ""}) +@v0_api.route("/blueprints/changes/<blueprint_names>") +@checkparams([("blueprint_names", "", "no blueprint names given")]) +def v0_blueprints_changes(blueprint_names): + """Return the changes to a blueprint or list of blueprints + + **/api/v0/blueprints/changes/<blueprint_names>[?offset=0&limit=20]** + + Return the commits to a blueprint. By default it returns the first 20 commits, this + can be changed by passing `offset` and/or `limit`. The response will include the + commit hash, summary, timestamp, and optionally the revision number. The commit + hash can be passed to `/api/v0/blueprints/diff/` to retrieve the exact changes. + + Example:: + + { + "errors": [], + "limit": 20, + "offset": 0, + "blueprints": [ + { + "changes": [ + { + "commit": "e083921a7ed1cf2eec91ad12b9ad1e70ef3470be", + "message": "blueprint glusterfs, version 0.0.6 saved.", + "revision": null, + "timestamp": "2017-11-23T00:18:13Z" + }, + { + "commit": "cee5f4c20fc33ea4d54bfecf56f4ad41ad15f4f3", + "message": "blueprint glusterfs, version 0.0.5 saved.", + "revision": null, + "timestamp": "2017-11-11T01:00:28Z" + }, + { + "commit": "29b492f26ed35d80800b536623bafc51e2f0eff2", + "message": "blueprint glusterfs, version 0.0.4 saved.", + "revision": null, + "timestamp": "2017-11-11T00:28:30Z" + }, + { + "commit": "03374adbf080fe34f5c6c29f2e49cc2b86958bf2", + "message": "blueprint glusterfs, version 0.0.3 saved.", + "revision": null, + "timestamp": "2017-11-10T23:15:52Z" + }, + { + "commit": "0e08ecbb708675bfabc82952599a1712a843779d", + "message": "blueprint glusterfs, version 0.0.2 saved.", + "revision": null, + "timestamp": "2017-11-10T23:14:56Z" + }, + { + "commit": "3e11eb87a63d289662cba4b1804a0947a6843379", + "message": "blueprint glusterfs, version 0.0.1 saved.", + "revision": null, + "timestamp": "2017-11-08T00:02:47Z" + } + ], + "name": "glusterfs", + "total": 6 + } + ] + } + """ + if any(VALID_BLUEPRINT_NAME.match(blueprint_name) is None for blueprint_name in blueprint_names.split(',')): + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + try: + limit = int(request.args.get("limit", "20")) + offset = int(request.args.get("offset", "0")) + except ValueError as e: + return jsonify(status=False, errors=[{"id": BAD_LIMIT_OR_OFFSET, "msg": str(e)}]), 400 + + blueprints = [] + errors = [] + for blueprint_name in [n.strip() for n in blueprint_names.split(",")]: + filename = recipe_filename(blueprint_name) + try: + with api.config["GITLOCK"].lock: + commits = list_commits(api.config["GITLOCK"].repo, branch, filename) + except Exception as e: + errors.append({"id": BLUEPRINTS_ERROR, "msg": "%s: %s" % (blueprint_name, str(e))}) + log.error("(v0_blueprints_changes) %s", str(e)) + else: + if commits: + limited_commits = take_limits(commits, offset, limit) + blueprints.append({"name":blueprint_name, "changes":limited_commits, "total":len(commits)}) + else: + # no commits means there is no blueprint in the branch + errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "%s" % blueprint_name}) + + blueprints = sorted(blueprints, key=lambda r: r["name"].lower()) + + return jsonify(blueprints=blueprints, errors=errors, offset=offset, limit=limit)
    + +
    [docs]@v0_api.route("/blueprints/new", methods=["POST"]) +def v0_blueprints_new(): + """Commit a new blueprint + + **POST /api/v0/blueprints/new** + + Create a new blueprint, or update an existing blueprint. This supports both JSON and TOML + for the blueprint format. The blueprint should be in the body of the request with the + `Content-Type` header set to either `application/json` or `text/x-toml`. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + try: + if request.headers['Content-Type'] == "text/x-toml": + blueprint = recipe_from_toml(request.data) + else: + blueprint = recipe_from_dict(request.get_json(cache=False)) + + if VALID_BLUEPRINT_NAME.match(blueprint["name"]) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + with api.config["GITLOCK"].lock: + commit_recipe(api.config["GITLOCK"].repo, branch, blueprint) + + # Read the blueprint with new version and write it to the workspace + blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint["name"]) + workspace_write(api.config["GITLOCK"].repo, branch, blueprint) + except Exception as e: + log.error("(v0_blueprints_new) %s", str(e)) + return jsonify(status=False, errors=[{"id": BLUEPRINTS_ERROR, "msg": str(e)}]), 400 + else: + return jsonify(status=True)
    + +
    [docs]@v0_api.route("/blueprints/delete", defaults={'blueprint_name': ""}, methods=["DELETE"]) +@v0_api.route("/blueprints/delete/<blueprint_name>", methods=["DELETE"]) +@checkparams([("blueprint_name", "", "no blueprint name given")]) +def v0_blueprints_delete(blueprint_name): + """Delete a blueprint from git + + **DELETE /api/v0/blueprints/delete/<blueprint_name>** + + Delete a blueprint. The blueprint is deleted from the branch, and will no longer + be listed by the `list` route. A blueprint can be undeleted using the `undo` route + to revert to a previous commit. This will also delete the workspace copy of the + blueprint. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ + if VALID_BLUEPRINT_NAME.match(blueprint_name) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + try: + with api.config["GITLOCK"].lock: + workspace_delete(api.config["GITLOCK"].repo, branch, blueprint_name) + delete_recipe(api.config["GITLOCK"].repo, branch, blueprint_name) + except Exception as e: + log.error("(v0_blueprints_delete) %s", str(e)) + return jsonify(status=False, errors=[{"id": BLUEPRINTS_ERROR, "msg": str(e)}]), 400 + else: + return jsonify(status=True)
    + +
    [docs]@v0_api.route("/blueprints/workspace", methods=["POST"]) +def v0_blueprints_workspace(): + """Write a blueprint to the workspace + + **POST /api/v0/blueprints/workspace** + + Write a blueprint to the temporary workspace. This works exactly the same as `new` except + that it does not create a commit. JSON and TOML bodies are supported. + + The workspace is meant to be used as a temporary blueprint storage for clients. + It will be read by the `info` and `diff` routes if it is different from the + most recent commit. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + try: + if request.headers['Content-Type'] == "text/x-toml": + blueprint = recipe_from_toml(request.data) + else: + blueprint = recipe_from_dict(request.get_json(cache=False)) + + if VALID_BLUEPRINT_NAME.match(blueprint["name"]) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + with api.config["GITLOCK"].lock: + workspace_write(api.config["GITLOCK"].repo, branch, blueprint) + except Exception as e: + log.error("(v0_blueprints_workspace) %s", str(e)) + return jsonify(status=False, errors=[{"id": BLUEPRINTS_ERROR, "msg": str(e)}]), 400 + else: + return jsonify(status=True)
    + +
    [docs]@v0_api.route("/blueprints/workspace", defaults={'blueprint_name': ""}, methods=["DELETE"]) +@v0_api.route("/blueprints/workspace/<blueprint_name>", methods=["DELETE"]) +@checkparams([("blueprint_name", "", "no blueprint name given")]) +def v0_blueprints_delete_workspace(blueprint_name): + """Delete a blueprint from the workspace + + **DELETE /api/v0/blueprints/workspace/<blueprint_name>** + + Remove the temporary workspace copy of a blueprint. The `info` route will now + return the most recent commit of the blueprint. Any changes that were in the + workspace will be lost. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ + if VALID_BLUEPRINT_NAME.match(blueprint_name) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + try: + with api.config["GITLOCK"].lock: + workspace_delete(api.config["GITLOCK"].repo, branch, blueprint_name) + except Exception as e: + log.error("(v0_blueprints_delete_workspace) %s", str(e)) + return jsonify(status=False, errors=[{"id": BLUEPRINTS_ERROR, "msg": str(e)}]), 400 + else: + return jsonify(status=True)
    + +
    [docs]@v0_api.route("/blueprints/undo", defaults={'blueprint_name': "", 'commit': ""}, methods=["POST"]) +@v0_api.route("/blueprints/undo/<blueprint_name>", defaults={'commit': ""}, methods=["POST"]) +@v0_api.route("/blueprints/undo/<blueprint_name>/<commit>", methods=["POST"]) +@checkparams([("blueprint_name", "", "no blueprint name given"), + ("commit", "", "no commit ID given")]) +def v0_blueprints_undo(blueprint_name, commit): + """Undo changes to a blueprint by reverting to a previous commit. + + **POST /api/v0/blueprints/undo/<blueprint_name>/<commit>** + + This will revert the blueprint to a previous commit. The commit hash from the `changes` + route can be used in this request. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ + if VALID_BLUEPRINT_NAME.match(blueprint_name) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + try: + with api.config["GITLOCK"].lock: + revert_recipe(api.config["GITLOCK"].repo, branch, blueprint_name, commit) + + # Read the new recipe and write it to the workspace + blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) + workspace_write(api.config["GITLOCK"].repo, branch, blueprint) + except Exception as e: + log.error("(v0_blueprints_undo) %s", str(e)) + return jsonify(status=False, errors=[{"id": UNKNOWN_COMMIT, "msg": str(e)}]), 400 + else: + return jsonify(status=True)
    + +
    [docs]@v0_api.route("/blueprints/tag", defaults={'blueprint_name': ""}, methods=["POST"]) +@v0_api.route("/blueprints/tag/<blueprint_name>", methods=["POST"]) +@checkparams([("blueprint_name", "", "no blueprint name given")]) +def v0_blueprints_tag(blueprint_name): + """Tag a blueprint's latest blueprint commit as a 'revision' + + **POST /api/v0/blueprints/tag/<blueprint_name>** + + Tag a blueprint as a new release. This uses git tags with a special format. + `refs/tags/<branch>/<filename>/r<revision>`. Only the most recent blueprint commit + can be tagged. Revisions start at 1 and increment for each new tag + (per-blueprint). If the commit has already been tagged it will return false. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ + if VALID_BLUEPRINT_NAME.match(blueprint_name) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + try: + with api.config["GITLOCK"].lock: + tag_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) + except RecipeFileError as e: + log.error("(v0_blueprints_tag) %s", str(e)) + return jsonify(status=False, errors=[{"id": UNKNOWN_BLUEPRINT, "msg": str(e)}]), 400 + except Exception as e: + log.error("(v0_blueprints_tag) %s", str(e)) + return jsonify(status=False, errors=[{"id": BLUEPRINTS_ERROR, "msg": str(e)}]), 400 + else: + return jsonify(status=True)
    + +
    [docs]@v0_api.route("/blueprints/diff", defaults={'blueprint_name': "", 'from_commit': "", 'to_commit': ""}) +@v0_api.route("/blueprints/diff/<blueprint_name>", defaults={'from_commit': "", 'to_commit': ""}) +@v0_api.route("/blueprints/diff/<blueprint_name>/<from_commit>", defaults={'to_commit': ""}) +@v0_api.route("/blueprints/diff/<blueprint_name>/<from_commit>/<to_commit>") +@checkparams([("blueprint_name", "", "no blueprint name given"), + ("from_commit", "", "no from commit ID given"), + ("to_commit", "", "no to commit ID given")]) +def v0_blueprints_diff(blueprint_name, from_commit, to_commit): + """Return the differences between two commits of a blueprint + + **/api/v0/blueprints/diff/<blueprint_name>/<from_commit>/<to_commit>** + + Return the differences between two commits, or the workspace. The commit hash + from the `changes` response can be used here, or several special strings: + + - NEWEST will select the newest git commit. This works for `from_commit` or `to_commit` + - WORKSPACE will select the workspace copy. This can only be used in `to_commit` + + eg. `/api/v0/blueprints/diff/glusterfs/NEWEST/WORKSPACE` will return the differences + between the most recent git commit and the contents of the workspace. + + Each entry in the response's diff object contains the old blueprint value and the new one. + If old is null and new is set, then it was added. + If new is null and old is set, then it was removed. + If both are set, then it was changed. + + The old/new entries will have the name of the blueprint field that was changed. This + can be one of: Name, Description, Version, Module, or Package. + The contents for these will be the old/new values for them. + + In the example below the version was changed and the ping package was added. + + Example:: + + { + "diff": [ + { + "new": { + "Version": "0.0.6" + }, + "old": { + "Version": "0.0.5" + } + }, + { + "new": { + "Package": { + "name": "ping", + "version": "3.2.1" + } + }, + "old": null + } + ] + } + """ + for s in [blueprint_name, from_commit, to_commit]: + if VALID_API_STRING.match(s) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + if not blueprint_exists(api, branch, blueprint_name): + return jsonify(status=False, errors=[{"id": UNKNOWN_BLUEPRINT, "msg": "Unknown blueprint name: %s" % blueprint_name}]) + + try: + if from_commit == "NEWEST": + with api.config["GITLOCK"].lock: + old_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) + else: + with api.config["GITLOCK"].lock: + old_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name, from_commit) + except Exception as e: + log.error("(v0_blueprints_diff) %s", str(e)) + return jsonify(status=False, errors=[{"id": UNKNOWN_COMMIT, "msg": str(e)}]), 400 + + try: + if to_commit == "WORKSPACE": + with api.config["GITLOCK"].lock: + new_blueprint = workspace_read(api.config["GITLOCK"].repo, branch, blueprint_name) + # If there is no workspace, use the newest commit instead + if not new_blueprint: + with api.config["GITLOCK"].lock: + new_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) + elif to_commit == "NEWEST": + with api.config["GITLOCK"].lock: + new_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) + else: + with api.config["GITLOCK"].lock: + new_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name, to_commit) + except Exception as e: + log.error("(v0_blueprints_diff) %s", str(e)) + return jsonify(status=False, errors=[{"id": UNKNOWN_COMMIT, "msg": str(e)}]), 400 + + diff = recipe_diff(old_blueprint, new_blueprint) + return jsonify(diff=diff)
    + +
    [docs]@v0_api.route("/blueprints/freeze", defaults={'blueprint_names': ""}) +@v0_api.route("/blueprints/freeze/<blueprint_names>") +@checkparams([("blueprint_names", "", "no blueprint names given")]) +def v0_blueprints_freeze(blueprint_names): + """Return the blueprint with the exact modules and packages selected by depsolve + + **/api/v0/blueprints/freeze/<blueprint_names>** + + Return a JSON representation of the blueprint with the package and module versions set + to the exact versions chosen by depsolving the blueprint. + + Example:: + + { + "errors": [], + "blueprints": [ + { + "blueprint": { + "description": "An example GlusterFS server with samba", + "modules": [ + { + "name": "glusterfs", + "version": "3.8.4-18.4.el7.x86_64" + }, + { + "name": "glusterfs-cli", + "version": "3.8.4-18.4.el7.x86_64" + } + ], + "name": "glusterfs", + "packages": [ + { + "name": "ping", + "version": "2:3.2.1-2.el7.noarch" + }, + { + "name": "samba", + "version": "4.6.2-8.el7.x86_64" + } + ], + "version": "0.0.6" + } + } + ] + } + """ + if any(VALID_BLUEPRINT_NAME.match(blueprint_name) is None for blueprint_name in blueprint_names.split(',')): + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + out_fmt = request.args.get("format", "json") + if VALID_API_STRING.match(out_fmt) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in format argument"}]), 400 + + blueprints = [] + errors = [] + for blueprint_name in [n.strip() for n in sorted(blueprint_names.split(","), key=lambda n: n.lower())]: + # get the blueprint + # Get the workspace version (if it exists) + blueprint = None + try: + with api.config["GITLOCK"].lock: + blueprint = workspace_read(api.config["GITLOCK"].repo, branch, blueprint_name) + except Exception: + pass + + if not blueprint: + # No workspace version, get the git version (if it exists) + try: + with api.config["GITLOCK"].lock: + blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) + except RecipeFileError as e: + # adding an error here would be redundant, skip it + log.error("(v0_blueprints_freeze) %s", str(e)) + except Exception as e: + errors.append({"id": BLUEPRINTS_ERROR, "msg": "%s: %s" % (blueprint_name, str(e))}) + log.error("(v0_blueprints_freeze) %s", str(e)) + + # No blueprint found, skip it. + if not blueprint: + errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "%s: blueprint_not_found" % blueprint_name}) + continue + + # Combine modules and packages and depsolve the list + # TODO include the version/glob in the depsolving + module_nver = blueprint.module_nver + package_nver = blueprint.package_nver + projects = sorted(set(module_nver+package_nver), key=lambda p: p[0].lower()) + deps = [] + try: + with api.config["DNFLOCK"].lock: + deps = projects_depsolve(api.config["DNFLOCK"].dbo, projects, blueprint.group_names) + except ProjectsError as e: + errors.append({"id": BLUEPRINTS_ERROR, "msg": "%s: %s" % (blueprint_name, str(e))}) + log.error("(v0_blueprints_freeze) %s", str(e)) + + blueprints.append({"blueprint": blueprint.freeze(deps)}) + + if out_fmt == "toml": + # With TOML output we just want to dump the raw blueprint, skipping the rest. + return "\n\n".join([e["blueprint"].toml() for e in blueprints]) + else: + return jsonify(blueprints=blueprints, errors=errors)
    + +
    [docs]@v0_api.route("/blueprints/depsolve", defaults={'blueprint_names': ""}) +@v0_api.route("/blueprints/depsolve/<blueprint_names>") +@checkparams([("blueprint_names", "", "no blueprint names given")]) +def v0_blueprints_depsolve(blueprint_names): + """Return the dependencies for a blueprint + + **/api/v0/blueprints/depsolve/<blueprint_names>** + + Depsolve the blueprint using yum, return the blueprint used, and the NEVRAs of the packages + chosen to satisfy the blueprint's requirements. The response will include a list of results, + with the full dependency list in `dependencies`, the NEVRAs for the blueprint's direct modules + and packages in `modules`, and any error will be in `errors`. + + Example:: + + { + "errors": [], + "blueprints": [ + { + "dependencies": [ + { + "arch": "noarch", + "epoch": "0", + "name": "2ping", + "release": "2.el7", + "version": "3.2.1" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "acl", + "release": "12.el7", + "version": "2.2.51" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "audit-libs", + "release": "3.el7", + "version": "2.7.6" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "avahi-libs", + "release": "17.el7", + "version": "0.6.31" + }, + ... + ], + "modules": [ + { + "arch": "noarch", + "epoch": "0", + "name": "2ping", + "release": "2.el7", + "version": "3.2.1" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "glusterfs", + "release": "18.4.el7", + "version": "3.8.4" + }, + ... + ], + "blueprint": { + "description": "An example GlusterFS server with samba", + "modules": [ + { + "name": "glusterfs", + "version": "3.7.*" + }, + ... + } + } + ] + } + """ + if any(VALID_BLUEPRINT_NAME.match(blueprint_name) is None for blueprint_name in blueprint_names.split(',')): + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + blueprints = [] + errors = [] + for blueprint_name in [n.strip() for n in sorted(blueprint_names.split(","), key=lambda n: n.lower())]: + # get the blueprint + # Get the workspace version (if it exists) + blueprint = None + try: + with api.config["GITLOCK"].lock: + blueprint = workspace_read(api.config["GITLOCK"].repo, branch, blueprint_name) + except Exception: + pass + + if not blueprint: + # No workspace version, get the git version (if it exists) + try: + with api.config["GITLOCK"].lock: + blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) + except RecipeFileError as e: + # adding an error here would be redundant, skip it + log.error("(v0_blueprints_depsolve) %s", str(e)) + except Exception as e: + errors.append({"id": BLUEPRINTS_ERROR, "msg": "%s: %s" % (blueprint_name, str(e))}) + log.error("(v0_blueprints_depsolve) %s", str(e)) + + # No blueprint found, skip it. + if not blueprint: + errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "%s: blueprint not found" % blueprint_name}) + continue + + # Combine modules and packages and depsolve the list + # TODO include the version/glob in the depsolving + module_nver = blueprint.module_nver + package_nver = blueprint.package_nver + projects = sorted(set(module_nver+package_nver), key=lambda p: p[0].lower()) + deps = [] + try: + with api.config["DNFLOCK"].lock: + deps = projects_depsolve(api.config["DNFLOCK"].dbo, projects, blueprint.group_names) + except ProjectsError as e: + errors.append({"id": BLUEPRINTS_ERROR, "msg": "%s: %s" % (blueprint_name, str(e))}) + log.error("(v0_blueprints_depsolve) %s", str(e)) + + # Get the NEVRA's of the modules and projects, add as "modules" + modules = [] + for dep in deps: + if dep["name"] in projects: + modules.append(dep) + modules = sorted(modules, key=lambda m: m["name"].lower()) + + blueprints.append({"blueprint":blueprint, "dependencies":deps, "modules":modules}) + + return jsonify(blueprints=blueprints, errors=errors)
    + +
    [docs]@v0_api.route("/projects/list") +def v0_projects_list(): + """List all of the available projects/packages + + **/api/v0/projects/list[?offset=0&limit=20]** + + List all of the available projects. By default this returns the first 20 items, + but this can be changed by setting the `offset` and `limit` arguments. + + Example:: + + { + "limit": 20, + "offset": 0, + "projects": [ + { + "description": "0 A.D. (pronounced \"zero ey-dee\") is a ...", + "homepage": "http://play0ad.com", + "name": "0ad", + "summary": "Cross-Platform RTS Game of Ancient Warfare", + "upstream_vcs": "UPSTREAM_VCS" + }, + ... + ], + "total": 21770 + } + """ + try: + limit = int(request.args.get("limit", "20")) + offset = int(request.args.get("offset", "0")) + except ValueError as e: + return jsonify(status=False, errors=[{"id": BAD_LIMIT_OR_OFFSET, "msg": str(e)}]), 400 + + try: + with api.config["DNFLOCK"].lock: + available = projects_list(api.config["DNFLOCK"].dbo) + except ProjectsError as e: + log.error("(v0_projects_list) %s", str(e)) + return jsonify(status=False, errors=[{"id": PROJECTS_ERROR, "msg": str(e)}]), 400 + + projects = take_limits(available, offset, limit) + return jsonify(projects=projects, offset=offset, limit=limit, total=len(available))
    + +
    [docs]@v0_api.route("/projects/info", defaults={'project_names': ""}) +@v0_api.route("/projects/info/<project_names>") +@checkparams([("project_names", "", "no project names given")]) +def v0_projects_info(project_names): + """Return detailed information about the listed projects + + **/api/v0/projects/info/<project_names>** + + Return information about the comma-separated list of projects. It includes the description + of the package along with the list of available builds. + + Example:: + + { + "projects": [ + { + "builds": [ + { + "arch": "x86_64", + "build_config_ref": "BUILD_CONFIG_REF", + "build_env_ref": "BUILD_ENV_REF", + "build_time": "2017-03-01T08:39:23", + "changelog": "- restore incremental backups correctly, files ...", + "epoch": "2", + "metadata": {}, + "release": "32.el7", + "source": { + "license": "GPLv3+", + "metadata": {}, + "source_ref": "SOURCE_REF", + "version": "1.26" + } + } + ], + "description": "The GNU tar program saves many ...", + "homepage": "http://www.gnu.org/software/tar/", + "name": "tar", + "summary": "A GNU file archiving program", + "upstream_vcs": "UPSTREAM_VCS" + } + ] + } + """ + if VALID_API_STRING.match(project_names) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + try: + with api.config["DNFLOCK"].lock: + projects = projects_info(api.config["DNFLOCK"].dbo, project_names.split(",")) + except ProjectsError as e: + log.error("(v0_projects_info) %s", str(e)) + return jsonify(status=False, errors=[{"id": PROJECTS_ERROR, "msg": str(e)}]), 400 + + if not projects: + msg = "one of the requested projects does not exist: %s" % project_names + log.error("(v0_projects_info) %s", msg) + return jsonify(status=False, errors=[{"id": UNKNOWN_PROJECT, "msg": msg}]), 400 + + return jsonify(projects=projects)
    + +
    [docs]@v0_api.route("/projects/depsolve", defaults={'project_names': ""}) +@v0_api.route("/projects/depsolve/<project_names>") +@checkparams([("project_names", "", "no project names given")]) +def v0_projects_depsolve(project_names): + """Return detailed information about the listed projects + + **/api/v0/projects/depsolve/<project_names>** + + Depsolve the comma-separated list of projects and return the list of NEVRAs needed + to satisfy the request. + + Example:: + + { + "projects": [ + { + "arch": "noarch", + "epoch": "0", + "name": "basesystem", + "release": "7.el7", + "version": "10.0" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "bash", + "release": "28.el7", + "version": "4.2.46" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "filesystem", + "release": "21.el7", + "version": "3.2" + }, + ... + ] + } + """ + if VALID_API_STRING.match(project_names) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + try: + with api.config["DNFLOCK"].lock: + deps = projects_depsolve(api.config["DNFLOCK"].dbo, [(n, "*") for n in project_names.split(",")], []) + except ProjectsError as e: + log.error("(v0_projects_depsolve) %s", str(e)) + return jsonify(status=False, errors=[{"id": PROJECTS_ERROR, "msg": str(e)}]), 400 + + if not deps: + msg = "one of the requested projects does not exist: %s" % project_names + log.error("(v0_projects_depsolve) %s", msg) + return jsonify(status=False, errors=[{"id": UNKNOWN_PROJECT, "msg": msg}]), 400 + + return jsonify(projects=deps)
    + +
    [docs]@v0_api.route("/projects/source/list") +def v0_projects_source_list(): + """Return the list of source names + + **/api/v0/projects/source/list** + + Return the list of repositories used for depsolving and installing packages. + + Example:: + + { + "sources": [ + "fedora", + "fedora-cisco-openh264", + "fedora-updates-testing", + "fedora-updates" + ] + } + """ + with api.config["DNFLOCK"].lock: + repos = list(api.config["DNFLOCK"].dbo.repos.iter_enabled()) + sources = sorted([r.id for r in repos]) + return jsonify(sources=sources)
    + +
    [docs]@v0_api.route("/projects/source/info", defaults={'source_names': ""}) +@v0_api.route("/projects/source/info/<source_names>") +@checkparams([("source_names", "", "no source names given")]) +def v0_projects_source_info(source_names): + """Return detailed info about the list of sources + + **/api/v0/projects/source/info/<source-names>** + + Return information about the comma-separated list of source names. Or all of the + sources if '*' is passed. Note that general globbing is not supported, only '*'. + + immutable system sources will have the "system" field set to true. User added sources + will have it set to false. System sources cannot be changed or deleted. + + Example:: + + { + "errors": [], + "sources": { + "fedora": { + "check_gpg": true, + "check_ssl": true, + "gpgkey_urls": [ + "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-28-x86_64" + ], + "name": "fedora", + "proxy": "http://proxy.brianlane.com:8123", + "system": true, + "type": "yum-metalink", + "url": "https://mirrors.fedoraproject.org/metalink?repo=fedora-28&arch=x86_64" + } + } + } + """ + if VALID_API_STRING.match(source_names) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + out_fmt = request.args.get("format", "json") + if VALID_API_STRING.match(out_fmt) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in format argument"}]), 400 + + # Return info on all of the sources + if source_names == "*": + with api.config["DNFLOCK"].lock: + source_names = ",".join(r.id for r in api.config["DNFLOCK"].dbo.repos.iter_enabled()) + + sources = {} + errors = [] + system_sources = get_repo_sources("/etc/yum.repos.d/*.repo") + for source in source_names.split(","): + with api.config["DNFLOCK"].lock: + repo = api.config["DNFLOCK"].dbo.repos.get(source, None) + if not repo: + errors.append({"id": UNKNOWN_SOURCE, "msg": "%s is not a valid source" % source}) + continue + sources[repo.id] = repo_to_source(repo, repo.id in system_sources, api=0) + + if out_fmt == "toml" and not errors: + # With TOML output we just want to dump the raw sources, skipping the errors + return toml.dumps(sources) + elif out_fmt == "toml" and errors: + # TOML requested, but there was an error + return jsonify(status=False, errors=errors), 400 + else: + return jsonify(sources=sources, errors=errors)
    + +
    [docs]@v0_api.route("/projects/source/new", methods=["POST"]) +def v0_projects_source_new(): + """Add a new package source. Or change an existing one + + **POST /api/v0/projects/source/new** + + Add (or change) a source for use when depsolving blueprints and composing images. + + The ``proxy`` and ``gpgkey_urls`` entries are optional. All of the others are required. The supported + types for the urls are: + + * ``yum-baseurl`` is a URL to a yum repository. + * ``yum-mirrorlist`` is a URL for a mirrorlist. + * ``yum-metalink`` is a URL for a metalink. + + If ``check_ssl`` is true the https certificates must be valid. If they are self-signed you can either set + this to false, or add your Certificate Authority to the host system. + + If ``check_gpg`` is true the GPG key must either be installed on the host system, or ``gpgkey_urls`` + should point to it. + + You can edit an existing source (other than system sources), by doing a POST + of the new version of the source. It will overwrite the previous one. + + Example:: + + { + "name": "custom-source-1", + "url": "https://url/path/to/repository/", + "type": "yum-baseurl", + "check_ssl": true, + "check_gpg": true, + "gpgkey_urls": [ + "https://url/path/to/gpg-key" + ] + } + + + """ + if request.headers['Content-Type'] == "text/x-toml": + source = toml.loads(request.data) + else: + source = request.get_json(cache=False) + + system_sources = get_repo_sources("/etc/yum.repos.d/*.repo") + if source["name"] in system_sources: + return jsonify(status=False, errors=[{"id": SYSTEM_SOURCE, "msg": "%s is a system source, it cannot be changed." % source["name"]}]), 400 + + try: + # Remove it from the RepoDict (NOTE that this isn't explicitly supported by the DNF API) + with api.config["DNFLOCK"].lock: + repo_dir = api.config["COMPOSER_CFG"].get("composer", "repo_dir") + new_repo_source(api.config["DNFLOCK"].dbo, source["name"], source, repo_dir) + except Exception as e: + return jsonify(status=False, errors=[{"id": PROJECTS_ERROR, "msg": str(e)}]), 400 + + return jsonify(status=True)
    + +
    [docs]@v0_api.route("/projects/source/delete", defaults={'source_name': ""}, methods=["DELETE"]) +@v0_api.route("/projects/source/delete/<source_name>", methods=["DELETE"]) +@checkparams([("source_name", "", "no source name given")]) +def v0_projects_source_delete(source_name): + """Delete the named source and return a status response + + **DELETE /api/v0/projects/source/delete/<source-name>** + + Delete a user added source. This will fail if a system source is passed to + it. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ + if VALID_API_STRING.match(source_name) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + system_sources = get_repo_sources("/etc/yum.repos.d/*.repo") + if source_name in system_sources: + return jsonify(status=False, errors=[{"id": SYSTEM_SOURCE, "msg": "%s is a system source, it cannot be deleted." % source_name}]), 400 + share_dir = api.config["COMPOSER_CFG"].get("composer", "repo_dir") + try: + # Remove the file entry for the source + delete_repo_source(joinpaths(share_dir, "*.repo"), source_name) + + # Remove it from the RepoDict (NOTE that this isn't explicitly supported by the DNF API) + with api.config["DNFLOCK"].lock: + if source_name in api.config["DNFLOCK"].dbo.repos: + del api.config["DNFLOCK"].dbo.repos[source_name] + log.info("Updating repository metadata after removing %s", source_name) + api.config["DNFLOCK"].dbo.fill_sack(load_system_repo=False) + api.config["DNFLOCK"].dbo.read_comps() + + except ProjectsError as e: + log.error("(v0_projects_source_delete) %s", str(e)) + return jsonify(status=False, errors=[{"id": UNKNOWN_SOURCE, "msg": str(e)}]), 400 + + return jsonify(status=True)
    + +
    [docs]@v0_api.route("/modules/list") +@v0_api.route("/modules/list/<module_names>") +def v0_modules_list(module_names=None): + """List available modules, filtering by module_names + + **/api/v0/modules/list[?offset=0&limit=20]** + + Return a list of all of the available modules. This includes the name and the + group_type, which is always "rpm" for lorax-composer. By default this returns + the first 20 items. This can be changed by setting the `offset` and `limit` + arguments. + + Example:: + + { + "limit": 20, + "modules": [ + { + "group_type": "rpm", + "name": "0ad" + }, + { + "group_type": "rpm", + "name": "0ad-data" + }, + { + "group_type": "rpm", + "name": "0install" + }, + { + "group_type": "rpm", + "name": "2048-cli" + }, + ... + ] + "total": 21770 + } + + **/api/v0/modules/list/<module_names>[?offset=0&limit=20]** + + Return the list of comma-separated modules. Output is the same as `/modules/list` + + Example:: + + { + "limit": 20, + "modules": [ + { + "group_type": "rpm", + "name": "tar" + } + ], + "offset": 0, + "total": 1 + } + """ + if module_names and VALID_API_STRING.match(module_names) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + try: + limit = int(request.args.get("limit", "20")) + offset = int(request.args.get("offset", "0")) + except ValueError as e: + return jsonify(status=False, errors=[{"id": BAD_LIMIT_OR_OFFSET, "msg": str(e)}]), 400 + + if module_names: + module_names = module_names.split(",") + + try: + with api.config["DNFLOCK"].lock: + available = modules_list(api.config["DNFLOCK"].dbo, module_names) + except ProjectsError as e: + log.error("(v0_modules_list) %s", str(e)) + return jsonify(status=False, errors=[{"id": MODULES_ERROR, "msg": str(e)}]), 400 + + if module_names and not available: + msg = "one of the requested modules does not exist: %s" % module_names + log.error("(v0_modules_list) %s", msg) + return jsonify(status=False, errors=[{"id": UNKNOWN_MODULE, "msg": msg}]), 400 + + modules = take_limits(available, offset, limit) + return jsonify(modules=modules, offset=offset, limit=limit, total=len(available))
    + +
    [docs]@v0_api.route("/modules/info", defaults={'module_names': ""}) +@v0_api.route("/modules/info/<module_names>") +@checkparams([("module_names", "", "no module names given")]) +def v0_modules_info(module_names): + """Return detailed information about the listed modules + + **/api/v0/modules/info/<module_names>** + + Return the module's dependencies, and the information about the module. + + Example:: + + { + "modules": [ + { + "dependencies": [ + { + "arch": "noarch", + "epoch": "0", + "name": "basesystem", + "release": "7.el7", + "version": "10.0" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "bash", + "release": "28.el7", + "version": "4.2.46" + }, + ... + ], + "description": "The GNU tar program saves ...", + "homepage": "http://www.gnu.org/software/tar/", + "name": "tar", + "summary": "A GNU file archiving program", + "upstream_vcs": "UPSTREAM_VCS" + } + ] + } + """ + if VALID_API_STRING.match(module_names) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + try: + with api.config["DNFLOCK"].lock: + modules = modules_info(api.config["DNFLOCK"].dbo, module_names.split(",")) + except ProjectsError as e: + log.error("(v0_modules_info) %s", str(e)) + return jsonify(status=False, errors=[{"id": MODULES_ERROR, "msg": str(e)}]), 400 + + if not modules: + msg = "one of the requested modules does not exist: %s" % module_names + log.error("(v0_modules_info) %s", msg) + return jsonify(status=False, errors=[{"id": UNKNOWN_MODULE, "msg": msg}]), 400 + + return jsonify(modules=modules)
    + +
    [docs]@v0_api.route("/compose", methods=["POST"]) +def v0_compose_start(): + """Start a compose + + The body of the post should have these fields: + blueprint_name - The blueprint name from /blueprints/list/ + compose_type - The type of output to create, from /compose/types + branch - Optional, defaults to master, selects the git branch to use for the blueprint. + + **POST /api/v0/compose** + + Start a compose. The content type should be 'application/json' and the body of the POST + should look like this + + Example:: + + { + "blueprint_name": "http-server", + "compose_type": "tar", + "branch": "master" + } + + Pass it the name of the blueprint, the type of output (from '/api/v0/compose/types'), and the + blueprint branch to use. 'branch' is optional and will default to master. It will create a new + build and add it to the queue. It returns the build uuid and a status if it succeeds + + Example:: + + { + "build_id": "e6fa6db4-9c81-4b70-870f-a697ca405cdf", + "status": true + } + """ + # Passing ?test=1 will generate a fake FAILED compose. + # Passing ?test=2 will generate a fake FINISHED compose. + try: + test_mode = int(request.args.get("test", "0")) + except ValueError: + test_mode = 0 + + compose = request.get_json(cache=False) + + errors = [] + if not compose: + return jsonify(status=False, errors=[{"id": MISSING_POST, "msg": "Missing POST body"}]), 400 + + if "blueprint_name" not in compose: + errors.append({"id": UNKNOWN_BLUEPRINT,"msg": "No 'blueprint_name' in the JSON request"}) + else: + blueprint_name = compose["blueprint_name"] + + if "branch" not in compose or not compose["branch"]: + branch = "master" + else: + branch = compose["branch"] + + if "compose_type" not in compose: + errors.append({"id": BAD_COMPOSE_TYPE, "msg": "No 'compose_type' in the JSON request"}) + else: + compose_type = compose["compose_type"] + + if VALID_BLUEPRINT_NAME.match(blueprint_name) is None: + errors.append({"id": INVALID_CHARS, "msg": "Invalid characters in API path"}) + + if not blueprint_exists(api, branch, blueprint_name): + errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "Unknown blueprint name: %s" % blueprint_name}) + + if errors: + return jsonify(status=False, errors=errors), 400 + + try: + build_id = start_build(api.config["COMPOSER_CFG"], api.config["DNFLOCK"], api.config["GITLOCK"], + branch, blueprint_name, compose_type, test_mode) + except Exception as e: + if "Invalid compose type" in str(e): + return jsonify(status=False, errors=[{"id": BAD_COMPOSE_TYPE, "msg": str(e)}]), 400 + else: + return jsonify(status=False, errors=[{"id": BUILD_FAILED, "msg": str(e)}]), 400 + + return jsonify(status=True, build_id=build_id)
    + +
    [docs]@v0_api.route("/compose/types") +def v0_compose_types(): + """Return the list of enabled output types + + (only enabled types are returned) + + **/api/v0/compose/types** + + Returns the list of supported output types that are valid for use with 'POST /api/v0/compose' + + Example:: + + { + "types": [ + { + "enabled": true, + "name": "tar" + } + ] + } + """ + share_dir = api.config["COMPOSER_CFG"].get("composer", "share_dir") + return jsonify(types=[{"name": t, "enabled": e} for t, e in compose_types(share_dir)])
    + +
    [docs]@v0_api.route("/compose/queue") +def v0_compose_queue(): + """Return the status of the new and running queues + + **/api/v0/compose/queue** + + Return the status of the build queue. It includes information about the builds waiting, + and the build that is running. + + Example:: + + { + "new": [ + { + "id": "45502a6d-06e8-48a5-a215-2b4174b3614b", + "blueprint": "glusterfs", + "queue_status": "WAITING", + "job_created": 1517362647.4570868, + "version": "0.0.6" + }, + { + "id": "6d292bd0-bec7-4825-8d7d-41ef9c3e4b73", + "blueprint": "kubernetes", + "queue_status": "WAITING", + "job_created": 1517362659.0034983, + "version": "0.0.1" + } + ], + "run": [ + { + "id": "745712b2-96db-44c0-8014-fe925c35e795", + "blueprint": "glusterfs", + "queue_status": "RUNNING", + "job_created": 1517362633.7965999, + "job_started": 1517362633.8001345, + "version": "0.0.6" + } + ] + } + """ + return jsonify(queue_status(api.config["COMPOSER_CFG"], api=0))
    + +
    [docs]@v0_api.route("/compose/finished") +def v0_compose_finished(): + """Return the list of finished composes + + **/api/v0/compose/finished** + + Return the details on all of the finished composes on the system. + + Example:: + + { + "finished": [ + { + "id": "70b84195-9817-4b8a-af92-45e380f39894", + "blueprint": "glusterfs", + "queue_status": "FINISHED", + "job_created": 1517351003.8210032, + "job_started": 1517351003.8230415, + "job_finished": 1517359234.1003145, + "version": "0.0.6" + }, + { + "id": "e695affd-397f-4af9-9022-add2636e7459", + "blueprint": "glusterfs", + "queue_status": "FINISHED", + "job_created": 1517362289.7193348, + "job_started": 1517362289.9751132, + "job_finished": 1517363500.1234567, + "version": "0.0.6" + } + ] + } + """ + return jsonify(finished=build_status(api.config["COMPOSER_CFG"], "FINISHED", api=0))
    + +
    [docs]@v0_api.route("/compose/failed") +def v0_compose_failed(): + """Return the list of failed composes + + **/api/v0/compose/failed** + + Return the details on all of the failed composes on the system. + + Example:: + + { + "failed": [ + { + "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a", + "blueprint": "http-server", + "queue_status": "FAILED", + "job_created": 1517523249.9301329, + "job_started": 1517523249.9314211, + "job_finished": 1517523255.5623411, + "version": "0.0.2" + } + ] + } + """ + return jsonify(failed=build_status(api.config["COMPOSER_CFG"], "FAILED", api=0))
    + +
    [docs]@v0_api.route("/compose/status", defaults={'uuids': ""}) +@v0_api.route("/compose/status/<uuids>") +@checkparams([("uuids", "", "no UUIDs given")]) +def v0_compose_status(uuids): + """Return the status of the listed uuids + + **/api/v0/compose/status/<uuids>[?blueprint=<blueprint_name>&status=<compose_status>&type=<compose_type>]** + + Return the details for each of the comma-separated list of uuids. A uuid of '*' will return + details for all composes. + + Example:: + + { + "uuids": [ + { + "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a", + "blueprint": "http-server", + "queue_status": "FINISHED", + "job_created": 1517523644.2384307, + "job_started": 1517523644.2551234, + "job_finished": 1517523689.9864314, + "version": "0.0.2" + }, + { + "id": "45502a6d-06e8-48a5-a215-2b4174b3614b", + "blueprint": "glusterfs", + "queue_status": "FINISHED", + "job_created": 1517363442.188399, + "job_started": 1517363442.325324, + "job_finished": 1517363451.653621, + "version": "0.0.6" + } + ] + } + """ + if VALID_API_STRING.match(uuids) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + blueprint = request.args.get("blueprint", None) + status = request.args.get("status", None) + compose_type = request.args.get("type", None) + + results = [] + errors = [] + + if uuids.strip() == '*': + queue_status_dict = queue_status(api.config["COMPOSER_CFG"], api=0) + queue_new = queue_status_dict["new"] + queue_running = queue_status_dict["run"] + candidates = queue_new + queue_running + build_status(api.config["COMPOSER_CFG"], api=0) + else: + candidates = [] + for uuid in [n.strip().lower() for n in uuids.split(",")]: + details = uuid_status(api.config["COMPOSER_CFG"], uuid, api=0) + if details is None: + errors.append({"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}) + else: + candidates.append(details) + + for details in candidates: + if blueprint is not None and details['blueprint'] != blueprint: + continue + + if status is not None and details['queue_status'] != status: + continue + + if compose_type is not None and details['compose_type'] != compose_type: + continue + + results.append(details) + + return jsonify(uuids=results, errors=errors)
    + +
    [docs]@v0_api.route("/compose/cancel", defaults={'uuid': ""}, methods=["DELETE"]) +@v0_api.route("/compose/cancel/<uuid>", methods=["DELETE"]) +@checkparams([("uuid", "", "no UUID given")]) +def v0_compose_cancel(uuid): + """Cancel a running compose and delete its results directory + + **DELETE /api/v0/compose/cancel/<uuid>** + + Cancel the build, if it is not finished, and delete the results. It will return a + status of True if it is successful. + + Example:: + + { + "status": true, + "uuid": "03397f8d-acff-4cdb-bd31-f629b7a948f5" + } + """ + if VALID_API_STRING.match(uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + status = uuid_status(api.config["COMPOSER_CFG"], uuid, api=0) + if status is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + + if status["queue_status"] not in ["WAITING", "RUNNING"]: + return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s is not in WAITING or RUNNING." % uuid}]) + + try: + uuid_cancel(api.config["COMPOSER_CFG"], uuid) + except Exception as e: + return jsonify(status=False, errors=[{"id": COMPOSE_ERROR, "msg": "%s: %s" % (uuid, str(e))}]),400 + else: + return jsonify(status=True, uuid=uuid)
    + +
    [docs]@v0_api.route("/compose/delete", defaults={'uuids': ""}, methods=["DELETE"]) +@v0_api.route("/compose/delete/<uuids>", methods=["DELETE"]) +@checkparams([("uuids", "", "no UUIDs given")]) +def v0_compose_delete(uuids): + """Delete the compose results for the listed uuids + + **DELETE /api/v0/compose/delete/<uuids>** + + Delete the list of comma-separated uuids from the compose results. + + Example:: + + { + "errors": [], + "uuids": [ + { + "status": true, + "uuid": "ae1bf7e3-7f16-4c9f-b36e-3726a1093fd0" + } + ] + } + """ + if VALID_API_STRING.match(uuids) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + results = [] + errors = [] + for uuid in [n.strip().lower() for n in uuids.split(",")]: + status = uuid_status(api.config["COMPOSER_CFG"], uuid, api=0) + if status is None: + errors.append({"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}) + elif status["queue_status"] not in ["FINISHED", "FAILED"]: + errors.append({"id": BUILD_IN_WRONG_STATE, "msg": "Build %s is not in FINISHED or FAILED." % uuid}) + else: + try: + uuid_delete(api.config["COMPOSER_CFG"], uuid) + except Exception as e: + errors.append({"id": COMPOSE_ERROR, "msg": "%s: %s" % (uuid, str(e))}) + else: + results.append({"uuid":uuid, "status":True}) + return jsonify(uuids=results, errors=errors)
    + +
    [docs]@v0_api.route("/compose/info", defaults={'uuid': ""}) +@v0_api.route("/compose/info/<uuid>") +@checkparams([("uuid", "", "no UUID given")]) +def v0_compose_info(uuid): + """Return detailed info about a compose + + **/api/v0/compose/info/<uuid>** + + Get detailed information about the compose. The returned JSON string will + contain the following information: + + * id - The uuid of the comoposition + * config - containing the configuration settings used to run Anaconda + * blueprint - The depsolved blueprint used to generate the kickstart + * commit - The (local) git commit hash for the blueprint used + * deps - The NEVRA of all of the dependencies used in the composition + * compose_type - The type of output generated (tar, iso, etc.) + * queue_status - The final status of the composition (FINISHED or FAILED) + + Example:: + + { + "commit": "7078e521a54b12eae31c3fd028680da7a0815a4d", + "compose_type": "tar", + "config": { + "anaconda_args": "", + "armplatform": "", + "compress_args": [], + "compression": "xz", + "image_name": "root.tar.xz", + ... + }, + "deps": { + "packages": [ + { + "arch": "x86_64", + "epoch": "0", + "name": "acl", + "release": "14.el7", + "version": "2.2.51" + } + ] + }, + "id": "c30b7d80-523b-4a23-ad52-61b799739ce8", + "queue_status": "FINISHED", + "blueprint": { + "description": "An example kubernetes master", + ... + } + } + """ + if VALID_API_STRING.match(uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + try: + info = uuid_info(api.config["COMPOSER_CFG"], uuid, api=0) + except Exception as e: + return jsonify(status=False, errors=[{"id": COMPOSE_ERROR, "msg": str(e)}]), 400 + + if info is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + else: + return jsonify(**info)
    + +
    [docs]@v0_api.route("/compose/metadata", defaults={'uuid': ""}) +@v0_api.route("/compose/metadata/<uuid>") +@checkparams([("uuid","", "no UUID given")]) +def v0_compose_metadata(uuid): + """Return a tar of the metadata for the build + + **/api/v0/compose/metadata/<uuid>** + + Returns a .tar of the metadata used for the build. This includes all the + information needed to reproduce the build, including the final kickstart + populated with repository and package NEVRA. + + The mime type is set to 'application/x-tar' and the filename is set to + UUID-metadata.tar + + The .tar is uncompressed, but is not large. + """ + if VALID_API_STRING.match(uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + status = uuid_status(api.config["COMPOSER_CFG"], uuid, api=0) + if status is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + if status["queue_status"] not in ["FINISHED", "FAILED"]: + return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 + else: + return Response(uuid_tar(api.config["COMPOSER_CFG"], uuid, metadata=True, image=False, logs=False), + mimetype="application/x-tar", + headers=[("Content-Disposition", "attachment; filename=%s-metadata.tar;" % uuid)], + direct_passthrough=True)
    + +
    [docs]@v0_api.route("/compose/results", defaults={'uuid': ""}) +@v0_api.route("/compose/results/<uuid>") +@checkparams([("uuid","", "no UUID given")]) +def v0_compose_results(uuid): + """Return a tar of the metadata and the results for the build + + **/api/v0/compose/results/<uuid>** + + Returns a .tar of the metadata, logs, and output image of the build. This + includes all the information needed to reproduce the build, including the + final kickstart populated with repository and package NEVRA. The output image + is already in compressed form so the returned tar is not compressed. + + The mime type is set to 'application/x-tar' and the filename is set to + UUID.tar + """ + if VALID_API_STRING.match(uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + status = uuid_status(api.config["COMPOSER_CFG"], uuid, api=0) + if status is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + elif status["queue_status"] not in ["FINISHED", "FAILED"]: + return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 + else: + return Response(uuid_tar(api.config["COMPOSER_CFG"], uuid, metadata=True, image=True, logs=True), + mimetype="application/x-tar", + headers=[("Content-Disposition", "attachment; filename=%s.tar;" % uuid)], + direct_passthrough=True)
    + +
    [docs]@v0_api.route("/compose/logs", defaults={'uuid': ""}) +@v0_api.route("/compose/logs/<uuid>") +@checkparams([("uuid","", "no UUID given")]) +def v0_compose_logs(uuid): + """Return a tar of the metadata for the build + + **/api/v0/compose/logs/<uuid>** + + Returns a .tar of the anaconda build logs. The tar is not compressed, but is + not large. + + The mime type is set to 'application/x-tar' and the filename is set to + UUID-logs.tar + """ + if VALID_API_STRING.match(uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + status = uuid_status(api.config["COMPOSER_CFG"], uuid, api=0) + if status is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + elif status["queue_status"] not in ["FINISHED", "FAILED"]: + return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 + else: + return Response(uuid_tar(api.config["COMPOSER_CFG"], uuid, metadata=False, image=False, logs=True), + mimetype="application/x-tar", + headers=[("Content-Disposition", "attachment; filename=%s-logs.tar;" % uuid)], + direct_passthrough=True)
    + +
    [docs]@v0_api.route("/compose/image", defaults={'uuid': ""}) +@v0_api.route("/compose/image/<uuid>") +@checkparams([("uuid","", "no UUID given")]) +def v0_compose_image(uuid): + """Return the output image for the build + + **/api/v0/compose/image/<uuid>** + + Returns the output image from the build. The filename is set to the filename + from the build with the UUID as a prefix. eg. UUID-root.tar.xz or UUID-boot.iso. + """ + if VALID_API_STRING.match(uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + status = uuid_status(api.config["COMPOSER_CFG"], uuid, api=0) + if status is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + elif status["queue_status"] not in ["FINISHED", "FAILED"]: + return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 + else: + image_name, image_path = uuid_image(api.config["COMPOSER_CFG"], uuid) + + # Make sure it really exists + if not os.path.exists(image_path): + return jsonify(status=False, errors=[{"id": BUILD_MISSING_FILE, "msg": "Build %s is missing image file %s" % (uuid, image_name)}]), 400 + + # Make the image name unique + image_name = uuid + "-" + image_name + # XXX - Will mime type guessing work for all our output? + return send_file(image_path, as_attachment=True, attachment_filename=image_name, add_etags=False)
    + +
    [docs]@v0_api.route("/compose/log", defaults={'uuid': ""}) +@v0_api.route("/compose/log/<uuid>") +@checkparams([("uuid","", "no UUID given")]) +def v0_compose_log_tail(uuid): + """Return the tail of the most currently relevant log + + **/api/v0/compose/log/<uuid>[?size=KiB]** + + Returns the end of either the anaconda log, the packaging log, or the + composer logs, depending on the progress of the compose. The size + parameter is optional and defaults to 1 MiB if it is not included. The + returned data is raw text from the end of the log file, starting on a + line boundary. + + Example:: + + 12:59:24,222 INFO anaconda: Running Thread: AnaConfigurationThread (140629395244800) + 12:59:24,223 INFO anaconda: Configuring installed system + 12:59:24,912 INFO anaconda: Configuring installed system + 12:59:24,912 INFO anaconda: Creating users + 12:59:24,913 INFO anaconda: Clearing libuser.conf at /tmp/libuser.Dyy8Gj + 12:59:25,154 INFO anaconda: Creating users + 12:59:25,155 INFO anaconda: Configuring addons + 12:59:25,155 INFO anaconda: Configuring addons + 12:59:25,155 INFO anaconda: Generating initramfs + 12:59:49,467 INFO anaconda: Generating initramfs + 12:59:49,467 INFO anaconda: Running post-installation scripts + 12:59:49,467 INFO anaconda: Running kickstart %%post script(s) + 12:59:50,782 INFO anaconda: All kickstart %%post script(s) have been run + 12:59:50,782 INFO anaconda: Running post-installation scripts + 12:59:50,784 INFO anaconda: Thread Done: AnaConfigurationThread (140629395244800) + """ + if VALID_API_STRING.match(uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + try: + size = int(request.args.get("size", "1024")) + except ValueError as e: + return jsonify(status=False, errors=[{"id": COMPOSE_ERROR, "msg": str(e)}]), 400 + + status = uuid_status(api.config["COMPOSER_CFG"], uuid, api=0) + if status is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + elif status["queue_status"] == "WAITING": + return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s has not started yet. No logs to view" % uuid}]) + try: + return Response(uuid_log(api.config["COMPOSER_CFG"], uuid, size), direct_passthrough=True) + except RuntimeError as e: + return jsonify(status=False, errors=[{"id": COMPOSE_ERROR, "msg": str(e)}]), 400
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/v1.html b/f32-branch/_modules/pylorax/api/v1.html new file mode 100644 index 00000000..9c04cdf4 --- /dev/null +++ b/f32-branch/_modules/pylorax/api/v1.html @@ -0,0 +1,1243 @@ + + + + + + + + + + + pylorax.api.v1 — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.v1

    +#
    +# Copyright (C) 2019  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +""" Setup v1 of the API server
    +
    +"""
    +import logging
    +log = logging.getLogger("lorax-composer")
    +
    +from flask import jsonify, request
    +from flask import current_app as api
    +
    +from lifted.queue import get_upload, reset_upload, cancel_upload, delete_upload
    +from lifted.providers import list_providers, resolve_provider, load_profiles, validate_settings, save_settings
    +from lifted.providers import load_settings, delete_profile
    +from pylorax.api.checkparams import checkparams
    +from pylorax.api.compose import start_build
    +from pylorax.api.errors import BAD_COMPOSE_TYPE, BUILD_FAILED, INVALID_CHARS, MISSING_POST, PROJECTS_ERROR
    +from pylorax.api.errors import SYSTEM_SOURCE, UNKNOWN_BLUEPRINT, UNKNOWN_SOURCE, UNKNOWN_UUID, UPLOAD_ERROR
    +from pylorax.api.errors import COMPOSE_ERROR
    +from pylorax.api.flask_blueprint import BlueprintSkip
    +from pylorax.api.queue import queue_status, build_status, uuid_status, uuid_schedule_upload, uuid_remove_upload
    +from pylorax.api.queue import uuid_info
    +from pylorax.api.projects import get_repo_sources, repo_to_source
    +from pylorax.api.projects import new_repo_source
    +from pylorax.api.regexes import VALID_API_STRING, VALID_BLUEPRINT_NAME
    +import pylorax.api.toml as toml
    +from pylorax.api.utils import blueprint_exists
    +
    +
    +# Create the v1 routes Blueprint with skip_routes support
    +v1_api = BlueprintSkip("v1_routes", __name__)
    +
    +
    [docs]@v1_api.route("/projects/source/info", defaults={'source_ids': ""}) +@v1_api.route("/projects/source/info/<source_ids>") +@checkparams([("source_ids", "", "no source names given")]) +def v1_projects_source_info(source_ids): + """Return detailed info about the list of sources + + **/api/v1/projects/source/info/<source-ids>** + + Return information about the comma-separated list of source ids. Or all of the + sources if '*' is passed. Note that general globbing is not supported, only '*'. + + Immutable system sources will have the "system" field set to true. User added sources + will have it set to false. System sources cannot be changed or deleted. + + Example:: + + { + "errors": [], + "sources": { + "fedora": { + "check_gpg": true, + "check_ssl": true, + "gpgkey_urls": [ + "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-28-x86_64" + ], + "id": "fedora", + "name": "Fedora $releasever - $basearch", + "proxy": "http://proxy.brianlane.com:8123", + "system": true, + "type": "yum-metalink", + "url": "https://mirrors.fedoraproject.org/metalink?repo=fedora-28&arch=x86_64" + } + } + } + + In v0 the ``name`` field was used for the id (a short name for the repo). In v1 ``name`` changed + to ``id`` and ``name`` is now used for the longer descriptive name of the repository. + """ + if VALID_API_STRING.match(source_ids) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + out_fmt = request.args.get("format", "json") + if VALID_API_STRING.match(out_fmt) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in format argument"}]), 400 + + # Return info on all of the sources + if source_ids == "*": + with api.config["DNFLOCK"].lock: + source_ids = ",".join(r.id for r in api.config["DNFLOCK"].dbo.repos.iter_enabled()) + + sources = {} + errors = [] + system_sources = get_repo_sources("/etc/yum.repos.d/*.repo") + for source in source_ids.split(","): + with api.config["DNFLOCK"].lock: + repo = api.config["DNFLOCK"].dbo.repos.get(source, None) + if not repo: + errors.append({"id": UNKNOWN_SOURCE, "msg": "%s is not a valid source" % source}) + continue + sources[repo.id] = repo_to_source(repo, repo.id in system_sources, api=1) + + if out_fmt == "toml" and not errors: + # With TOML output we just want to dump the raw sources, skipping the errors + return toml.dumps(sources) + elif out_fmt == "toml" and errors: + # TOML requested, but there was an error + return jsonify(status=False, errors=errors), 400 + else: + return jsonify(sources=sources, errors=errors)
    + +
    [docs]@v1_api.route("/projects/source/new", methods=["POST"]) +def v1_projects_source_new(): + """Add a new package source. Or change an existing one + + **POST /api/v1/projects/source/new** + + Add (or change) a source for use when depsolving blueprints and composing images. + + The ``proxy`` and ``gpgkey_urls`` entries are optional. All of the others are required. The supported + types for the urls are: + + * ``yum-baseurl`` is a URL to a yum repository. + * ``yum-mirrorlist`` is a URL for a mirrorlist. + * ``yum-metalink`` is a URL for a metalink. + + If ``check_ssl`` is true the https certificates must be valid. If they are self-signed you can either set + this to false, or add your Certificate Authority to the host system. + + If ``check_gpg`` is true the GPG key must either be installed on the host system, or ``gpgkey_urls`` + should point to it. + + You can edit an existing source (other than system sources), by doing a POST + of the new version of the source. It will overwrite the previous one. + + Example:: + + { + "id": "custom-source-1", + "name": "Custom Package Source #1", + "url": "https://url/path/to/repository/", + "type": "yum-baseurl", + "check_ssl": true, + "check_gpg": true, + "gpgkey_urls": [ + "https://url/path/to/gpg-key" + ] + } + + In v0 the ``name`` field was used for the id (a short name for the repo). In v1 ``name`` changed + to ``id`` and ``name`` is now used for the longer descriptive name of the repository. + """ + if request.headers['Content-Type'] == "text/x-toml": + source = toml.loads(request.data) + else: + source = request.get_json(cache=False) + + # Check for id in source, return error if not + if "id" not in source: + return jsonify(status=False, errors=[{"id": UNKNOWN_SOURCE, "msg": "'id' field is missing from API v1 request."}]), 400 + + system_sources = get_repo_sources("/etc/yum.repos.d/*.repo") + if source["id"] in system_sources: + return jsonify(status=False, errors=[{"id": SYSTEM_SOURCE, "msg": "%s is a system source, it cannot be changed." % source["id"]}]), 400 + + try: + # Remove it from the RepoDict (NOTE that this isn't explicitly supported by the DNF API) + with api.config["DNFLOCK"].lock: + repo_dir = api.config["COMPOSER_CFG"].get("composer", "repo_dir") + new_repo_source(api.config["DNFLOCK"].dbo, source["id"], source, repo_dir) + except Exception as e: + return jsonify(status=False, errors=[{"id": PROJECTS_ERROR, "msg": str(e)}]), 400 + + return jsonify(status=True)
    + +
    [docs]@v1_api.route("/compose", methods=["POST"]) +def v1_compose_start(): + """Start a compose + + The body of the post should have these fields: + blueprint_name - The blueprint name from /blueprints/list/ + compose_type - The type of output to create, from /compose/types + branch - Optional, defaults to master, selects the git branch to use for the blueprint. + + **POST /api/v1/compose** + + Start a compose. The content type should be 'application/json' and the body of the POST + should look like this. The "upload" object is optional. + + The upload object can specify either a pre-existing profile to use (as returned by + `/uploads/providers`) or one-time use settings for the provider. + + Example with upload profile:: + + { + "blueprint_name": "http-server", + "compose_type": "tar", + "branch": "master", + "upload": { + "image_name": "My Image", + "provider": "azure", + "profile": "production-azure-settings" + } + } + + Example with upload settings:: + + { + "blueprint_name": "http-server", + "compose_type": "tar", + "branch": "master", + "upload": { + "image_name": "My Image", + "provider": "azure", + "settings": { + "resource_group": "SOMEBODY", + "storage_account_name": "ONCE", + "storage_container": "TOLD", + "location": "ME", + "subscription_id": "THE", + "client_id": "WORLD", + "secret": "IS", + "tenant": "GONNA" + } + } + } + + Pass it the name of the blueprint, the type of output (from + '/api/v1/compose/types'), and the blueprint branch to use. 'branch' is + optional and will default to master. It will create a new build and add + it to the queue. It returns the build uuid and a status if it succeeds. + If an "upload" is given, it will schedule an upload to run when the build + finishes. + + Example response:: + + { + "build_id": "e6fa6db4-9c81-4b70-870f-a697ca405cdf", + "upload_id": "572eb0d0-5348-4600-9666-14526ba628bb", + "status": true + } + """ + # Passing ?test=1 will generate a fake FAILED compose. + # Passing ?test=2 will generate a fake FINISHED compose. + try: + test_mode = int(request.args.get("test", "0")) + except ValueError: + test_mode = 0 + + compose = request.get_json(cache=False) + + errors = [] + if not compose: + return jsonify(status=False, errors=[{"id": MISSING_POST, "msg": "Missing POST body"}]), 400 + + if "blueprint_name" not in compose: + errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "No 'blueprint_name' in the JSON request"}) + else: + blueprint_name = compose["blueprint_name"] + + if "branch" not in compose or not compose["branch"]: + branch = "master" + else: + branch = compose["branch"] + + if "compose_type" not in compose: + errors.append({"id": BAD_COMPOSE_TYPE, "msg": "No 'compose_type' in the JSON request"}) + else: + compose_type = compose["compose_type"] + + if VALID_BLUEPRINT_NAME.match(blueprint_name) is None: + errors.append({"id": INVALID_CHARS, "msg": "Invalid characters in API path"}) + + if not blueprint_exists(api, branch, blueprint_name): + errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "Unknown blueprint name: %s" % blueprint_name}) + + if "upload" in compose: + try: + image_name = compose["upload"]["image_name"] + + if "profile" in compose["upload"]: + # Load a specific profile for this provider + profile = compose["upload"]["profile"] + provider_name = compose["upload"]["provider"] + settings = load_settings(api.config["COMPOSER_CFG"]["upload"], provider_name, profile) + else: + provider_name = compose["upload"]["provider"] + settings = compose["upload"]["settings"] + except KeyError as e: + errors.append({"id": UPLOAD_ERROR, "msg": f'Missing parameter {str(e)}!'}) + try: + provider = resolve_provider(api.config["COMPOSER_CFG"]["upload"], provider_name) + if "supported_types" in provider and compose_type not in provider["supported_types"]: + raise RuntimeError(f'Type "{compose_type}" is not supported by provider "{provider_name}"!') + validate_settings(api.config["COMPOSER_CFG"]["upload"], provider_name, settings, image_name) + except Exception as e: + errors.append({"id": UPLOAD_ERROR, "msg": str(e)}) + + if errors: + return jsonify(status=False, errors=errors), 400 + + try: + build_id = start_build(api.config["COMPOSER_CFG"], api.config["DNFLOCK"], api.config["GITLOCK"], + branch, blueprint_name, compose_type, test_mode) + except Exception as e: + if "Invalid compose type" in str(e): + return jsonify(status=False, errors=[{"id": BAD_COMPOSE_TYPE, "msg": str(e)}]), 400 + else: + return jsonify(status=False, errors=[{"id": BUILD_FAILED, "msg": str(e)}]), 400 + + if "upload" in compose: + upload_id = uuid_schedule_upload( + api.config["COMPOSER_CFG"], + build_id, + provider_name, + image_name, + settings + ) + else: + upload_id = "" + + return jsonify(status=True, build_id=build_id, upload_id=upload_id)
    + +
    [docs]@v1_api.route("/compose/queue") +def v1_compose_queue(): + """Return the status of the new and running queues + + **/api/v1/compose/queue** + + Return the status of the build queue. It includes information about the builds waiting, + and the build that is running. + + Example:: + + { + "new": [ + { + "id": "45502a6d-06e8-48a5-a215-2b4174b3614b", + "blueprint": "glusterfs", + "queue_status": "WAITING", + "job_created": 1517362647.4570868, + "version": "0.0.6" + }, + { + "id": "6d292bd0-bec7-4825-8d7d-41ef9c3e4b73", + "blueprint": "kubernetes", + "queue_status": "WAITING", + "job_created": 1517362659.0034983, + "version": "0.0.1" + } + ], + "run": [ + { + "id": "745712b2-96db-44c0-8014-fe925c35e795", + "blueprint": "glusterfs", + "queue_status": "RUNNING", + "job_created": 1517362633.7965999, + "job_started": 1517362633.8001345, + "version": "0.0.6", + "uploads": [ + { + "creation_time": 1568150660.524401, + "image_name": "glusterfs server", + "image_path": null, + "provider_name": "azure", + "settings": { + "client_id": "need", + "location": "need", + "resource_group": "group", + "secret": "need", + "storage_account_name": "need", + "storage_container": "need", + "subscription_id": "need", + "tenant": "need" + }, + "status": "WAITING", + "uuid": "21898dfd-9ac9-4e22-bb1d-7f12d0129e65" + } + ] + } + ] + } + """ + return jsonify(queue_status(api.config["COMPOSER_CFG"], api=1))
    + +
    [docs]@v1_api.route("/compose/finished") +def v1_compose_finished(): + """Return the list of finished composes + + **/api/v1/compose/finished** + + Return the details on all of the finished composes on the system. + + Example:: + + { + "finished": [ + { + "id": "70b84195-9817-4b8a-af92-45e380f39894", + "blueprint": "glusterfs", + "queue_status": "FINISHED", + "job_created": 1517351003.8210032, + "job_started": 1517351003.8230415, + "job_finished": 1517359234.1003145, + "version": "0.0.6" + }, + { + "id": "e695affd-397f-4af9-9022-add2636e7459", + "blueprint": "glusterfs", + "queue_status": "FINISHED", + "job_created": 1517362289.7193348, + "job_started": 1517362289.9751132, + "job_finished": 1517363500.1234567, + "version": "0.0.6", + "uploads": [ + { + "creation_time": 1568150660.524401, + "image_name": "glusterfs server", + "image_path": "/var/lib/lorax/composer/results/e695affd-397f-4af9-9022-add2636e7459/disk.vhd", + "provider_name": "azure", + "settings": { + "client_id": "need", + "location": "need", + "resource_group": "group", + "secret": "need", + "storage_account_name": "need", + "storage_container": "need", + "subscription_id": "need", + "tenant": "need" + }, + "status": "WAITING", + "uuid": "21898dfd-9ac9-4e22-bb1d-7f12d0129e65" + } + ] + } + ] + } + """ + return jsonify(finished=build_status(api.config["COMPOSER_CFG"], "FINISHED", api=1))
    + +
    [docs]@v1_api.route("/compose/failed") +def v1_compose_failed(): + """Return the list of failed composes + + **/api/v1/compose/failed** + + Return the details on all of the failed composes on the system. + + Example:: + + { + "failed": [ + { + "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a", + "blueprint": "http-server", + "queue_status": "FAILED", + "job_created": 1517523249.9301329, + "job_started": 1517523249.9314211, + "job_finished": 1517523255.5623411, + "version": "0.0.2", + "uploads": [ + { + "creation_time": 1568150660.524401, + "image_name": "http-server", + "image_path": null, + "provider_name": "azure", + "settings": { + "client_id": "need", + "location": "need", + "resource_group": "group", + "secret": "need", + "storage_account_name": "need", + "storage_container": "need", + "subscription_id": "need", + "tenant": "need" + }, + "status": "WAITING", + "uuid": "21898dfd-9ac9-4e22-bb1d-7f12d0129e65" + } + ] + } + ] + } + """ + return jsonify(failed=build_status(api.config["COMPOSER_CFG"], "FAILED", api=1))
    + +
    [docs]@v1_api.route("/compose/status", defaults={'uuids': ""}) +@v1_api.route("/compose/status/<uuids>") +@checkparams([("uuids", "", "no UUIDs given")]) +def v1_compose_status(uuids): + """Return the status of the listed uuids + + **/api/v1/compose/status/<uuids>[?blueprint=<blueprint_name>&status=<compose_status>&type=<compose_type>]** + + Return the details for each of the comma-separated list of uuids. A uuid of '*' will return + details for all composes. + + Example:: + + { + "uuids": [ + { + "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a", + "blueprint": "http-server", + "queue_status": "FINISHED", + "job_created": 1517523644.2384307, + "job_started": 1517523644.2551234, + "job_finished": 1517523689.9864314, + "version": "0.0.2" + }, + { + "id": "45502a6d-06e8-48a5-a215-2b4174b3614b", + "blueprint": "glusterfs", + "queue_status": "FINISHED", + "job_created": 1517363442.188399, + "job_started": 1517363442.325324, + "job_finished": 1517363451.653621, + "version": "0.0.6", + "uploads": [ + { + "creation_time": 1568150660.524401, + "image_name": "glusterfs server", + "image_path": null, + "provider_name": "azure", + "settings": { + "client_id": "need", + "location": "need", + "resource_group": "group", + "secret": "need", + "storage_account_name": "need", + "storage_container": "need", + "subscription_id": "need", + "tenant": "need" + }, + "status": "WAITING", + "uuid": "21898dfd-9ac9-4e22-bb1d-7f12d0129e65" + } + ] + } + ] + } + """ + if VALID_API_STRING.match(uuids) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + blueprint = request.args.get("blueprint", None) + status = request.args.get("status", None) + compose_type = request.args.get("type", None) + + results = [] + errors = [] + + if uuids.strip() == '*': + queue_status_dict = queue_status(api.config["COMPOSER_CFG"], api=1) + queue_new = queue_status_dict["new"] + queue_running = queue_status_dict["run"] + candidates = queue_new + queue_running + build_status(api.config["COMPOSER_CFG"], api=1) + else: + candidates = [] + for uuid in [n.strip().lower() for n in uuids.split(",")]: + details = uuid_status(api.config["COMPOSER_CFG"], uuid, api=1) + if details is None: + errors.append({"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}) + else: + candidates.append(details) + + for details in candidates: + if blueprint is not None and details['blueprint'] != blueprint: + continue + + if status is not None and details['queue_status'] != status: + continue + + if compose_type is not None and details['compose_type'] != compose_type: + continue + + results.append(details) + + return jsonify(uuids=results, errors=errors)
    + +
    [docs]@v1_api.route("/compose/info", defaults={'uuid': ""}) +@v1_api.route("/compose/info/<uuid>") +@checkparams([("uuid", "", "no UUID given")]) +def v1_compose_info(uuid): + """Return detailed info about a compose + + **/api/v1/compose/info/<uuid>** + + Get detailed information about the compose. The returned JSON string will + contain the following information: + + * id - The uuid of the comoposition + * config - containing the configuration settings used to run Anaconda + * blueprint - The depsolved blueprint used to generate the kickstart + * commit - The (local) git commit hash for the blueprint used + * deps - The NEVRA of all of the dependencies used in the composition + * compose_type - The type of output generated (tar, iso, etc.) + * queue_status - The final status of the composition (FINISHED or FAILED) + + Example:: + + { + "commit": "7078e521a54b12eae31c3fd028680da7a0815a4d", + "compose_type": "tar", + "config": { + "anaconda_args": "", + "armplatform": "", + "compress_args": [], + "compression": "xz", + "image_name": "root.tar.xz", + ... + }, + "deps": { + "packages": [ + { + "arch": "x86_64", + "epoch": "0", + "name": "acl", + "release": "14.el7", + "version": "2.2.51" + } + ] + }, + "id": "c30b7d80-523b-4a23-ad52-61b799739ce8", + "queue_status": "FINISHED", + "blueprint": { + "description": "An example kubernetes master", + ... + }, + "uploads": [ + { + "creation_time": 1568150660.524401, + "image_name": "glusterfs server", + "image_path": "/var/lib/lorax/composer/results/c30b7d80-523b-4a23-ad52-61b799739ce8/disk.vhd", + "provider_name": "azure", + "settings": { + "client_id": "need", + "location": "need", + "resource_group": "group", + "secret": "need", + "storage_account_name": "need", + "storage_container": "need", + "subscription_id": "need", + "tenant": "need" + }, + "status": "FAILED", + "uuid": "21898dfd-9ac9-4e22-bb1d-7f12d0129e65" + } + ] + } + """ + if VALID_API_STRING.match(uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + try: + info = uuid_info(api.config["COMPOSER_CFG"], uuid, api=1) + except Exception as e: + return jsonify(status=False, errors=[{"id": COMPOSE_ERROR, "msg": str(e)}]), 400 + + if info is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + else: + return jsonify(**info)
    + +
    [docs]@v1_api.route("/compose/uploads/schedule", defaults={'compose_uuid': ""}, methods=["POST"]) +@v1_api.route("/compose/uploads/schedule/<compose_uuid>", methods=["POST"]) +@checkparams([("compose_uuid", "", "no compose UUID given")]) +def v1_compose_uploads_schedule(compose_uuid): + """Schedule an upload of a compose to a given cloud provider + + **POST /api/v1/uploads/schedule/<compose_uuid>** + + The body can specify either a pre-existing profile to use (as returned by + `/uploads/providers`) or one-time use settings for the provider. + + Example with upload profile:: + + { + "image_name": "My Image", + "provider": "azure", + "profile": "production-azure-settings" + } + + Example with upload settings:: + + { + "image_name": "My Image", + "provider": "azure", + "settings": { + "resource_group": "SOMEBODY", + "storage_account_name": "ONCE", + "storage_container": "TOLD", + "location": "ME", + "subscription_id": "THE", + "client_id": "WORLD", + "secret": "IS", + "tenant": "GONNA" + } + } + + Example response:: + + { + "status": true, + "upload_id": "572eb0d0-5348-4600-9666-14526ba628bb" + } + """ + if VALID_API_STRING.match(compose_uuid) is None: + error = {"id": INVALID_CHARS, "msg": "Invalid characters in API path"} + return jsonify(status=False, errors=[error]), 400 + + parsed = request.get_json(cache=False) + if not parsed: + return jsonify(status=False, errors=[{"id": MISSING_POST, "msg": "Missing POST body"}]), 400 + + try: + image_name = parsed["image_name"] + provider_name = parsed["provider"] + if "profile" in parsed: + # Load a specific profile for this provider + profile = parsed["profile"] + settings = load_settings(api.config["COMPOSER_CFG"]["upload"], provider_name, profile) + else: + settings = parsed["settings"] + except KeyError as e: + error = {"id": UPLOAD_ERROR, "msg": f'Missing parameter {str(e)}!'} + return jsonify(status=False, errors=[error]), 400 + try: + compose_type = uuid_status(api.config["COMPOSER_CFG"], compose_uuid)["compose_type"] + provider = resolve_provider(api.config["COMPOSER_CFG"]["upload"], provider_name) + if "supported_types" in provider and compose_type not in provider["supported_types"]: + raise RuntimeError( + f'Type "{compose_type}" is not supported by provider "{provider_name}"!' + ) + except Exception as e: + return jsonify(status=False, errors=[{"id": UPLOAD_ERROR, "msg": str(e)}]), 400 + + try: + upload_id = uuid_schedule_upload( + api.config["COMPOSER_CFG"], + compose_uuid, + provider_name, + image_name, + settings + ) + except RuntimeError as e: + return jsonify(status=False, errors=[{"id": UPLOAD_ERROR, "msg": str(e)}]), 400 + return jsonify(status=True, upload_id=upload_id)
    + +
    [docs]@v1_api.route("/upload/delete", defaults={"upload_uuid": ""}, methods=["DELETE"]) +@v1_api.route("/upload/delete/<upload_uuid>", methods=["DELETE"]) +@checkparams([("upload_uuid", "", "no upload UUID given")]) +def v1_compose_uploads_delete(upload_uuid): + """Delete an upload and disassociate it from its compose + + **DELETE /api/v1/upload/delete/<upload_uuid>** + + Example response:: + + { + "status": true, + "upload_id": "572eb0d0-5348-4600-9666-14526ba628bb" + } + """ + if VALID_API_STRING.match(upload_uuid) is None: + error = {"id": INVALID_CHARS, "msg": "Invalid characters in API path"} + return jsonify(status=False, errors=[error]), 400 + + try: + uuid_remove_upload(api.config["COMPOSER_CFG"], upload_uuid) + delete_upload(api.config["COMPOSER_CFG"]["upload"], upload_uuid) + except RuntimeError as error: + return jsonify(status=False, errors=[{"id": UPLOAD_ERROR, "msg": str(error)}]) + return jsonify(status=True, upload_id=upload_uuid)
    + +
    [docs]@v1_api.route("/upload/info", defaults={"upload_uuid": ""}) +@v1_api.route("/upload/info/<upload_uuid>") +@checkparams([("upload_uuid", "", "no UUID given")]) +def v1_upload_info(upload_uuid): + """Returns information about a given upload + + **GET /api/v1/upload/info/<upload_uuid>** + + Example response:: + + { + "status": true, + "upload": { + "creation_time": 1565620940.069004, + "image_name": "My Image", + "image_path": "/var/lib/lorax/composer/results/b6218e8f-0fa2-48ec-9394-f5c2918544c4/disk.vhd", + "provider_name": "azure", + "settings": { + "resource_group": "SOMEBODY", + "storage_account_name": "ONCE", + "storage_container": "TOLD", + "location": "ME", + "subscription_id": "THE", + "client_id": "WORLD", + "secret": "IS", + "tenant": "GONNA" + }, + "status": "FAILED", + "uuid": "b637c411-9d9d-4279-b067-6c8d38e3b211" + } + } + """ + if VALID_API_STRING.match(upload_uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + try: + upload = get_upload(api.config["COMPOSER_CFG"]["upload"], upload_uuid).summary() + except RuntimeError as error: + return jsonify(status=False, errors=[{"id": UPLOAD_ERROR, "msg": str(error)}]) + return jsonify(status=True, upload=upload)
    + +
    [docs]@v1_api.route("/upload/log", defaults={"upload_uuid": ""}) +@v1_api.route("/upload/log/<upload_uuid>") +@checkparams([("upload_uuid", "", "no UUID given")]) +def v1_upload_log(upload_uuid): + """Returns an upload's log + + **GET /api/v1/upload/log/<upload_uuid>** + + Example response:: + + { + "status": true, + "upload_id": "b637c411-9d9d-4279-b067-6c8d38e3b211", + "log": "< PLAY [localhost] >..." + } + """ + if VALID_API_STRING.match(upload_uuid) is None: + error = {"id": INVALID_CHARS, "msg": "Invalid characters in API path"} + return jsonify(status=False, errors=[error]), 400 + + try: + upload = get_upload(api.config["COMPOSER_CFG"]["upload"], upload_uuid) + except RuntimeError as error: + return jsonify(status=False, errors=[{"id": UPLOAD_ERROR, "msg": str(error)}]) + return jsonify(status=True, upload_id=upload_uuid, log=upload.upload_log)
    + +
    [docs]@v1_api.route("/upload/reset", defaults={"upload_uuid": ""}, methods=["POST"]) +@v1_api.route("/upload/reset/<upload_uuid>", methods=["POST"]) +@checkparams([("upload_uuid", "", "no UUID given")]) +def v1_upload_reset(upload_uuid): + """Reset an upload so it can be attempted again + + **POST /api/v1/upload/reset/<upload_uuid>** + + Optionally pass in a new image name and/or new settings. + + Example request:: + + { + "image_name": "My renamed image", + "settings": { + "resource_group": "ROLL", + "storage_account_name": "ME", + "storage_container": "I", + "location": "AIN'T", + "subscription_id": "THE", + "client_id": "SHARPEST", + "secret": "TOOL", + "tenant": "IN" + } + } + + Example response:: + + { + "status": true, + "upload_id": "c75d5d62-9d26-42fc-a8ef-18bb14679fc7" + } + """ + if VALID_API_STRING.match(upload_uuid) is None: + error = {"id": INVALID_CHARS, "msg": "Invalid characters in API path"} + return jsonify(status=False, errors=[error]), 400 + + parsed = request.get_json(cache=False) + image_name = parsed.get("image_name") if parsed else None + settings = parsed.get("settings") if parsed else None + + try: + reset_upload(api.config["COMPOSER_CFG"]["upload"], upload_uuid, image_name, settings) + except RuntimeError as error: + return jsonify(status=False, errors=[{"id": UPLOAD_ERROR, "msg": str(error)}]) + return jsonify(status=True, upload_id=upload_uuid)
    + +
    [docs]@v1_api.route("/upload/cancel", defaults={"upload_uuid": ""}, methods=["DELETE"]) +@v1_api.route("/upload/cancel/<upload_uuid>", methods=["DELETE"]) +@checkparams([("upload_uuid", "", "no UUID given")]) +def v1_upload_cancel(upload_uuid): + """Cancel an upload that is either queued or in progress + + **DELETE /api/v1/upload/cancel/<upload_uuid>** + + Example response:: + + { + "status": true, + "upload_id": "037a3d56-b421-43e9-9935-c98350c89996" + } + """ + if VALID_API_STRING.match(upload_uuid) is None: + error = {"id": INVALID_CHARS, "msg": "Invalid characters in API path"} + return jsonify(status=False, errors=[error]), 400 + + try: + cancel_upload(api.config["COMPOSER_CFG"]["upload"], upload_uuid) + except RuntimeError as error: + return jsonify(status=False, errors=[{"id": UPLOAD_ERROR, "msg": str(error)}]) + return jsonify(status=True, upload_id=upload_uuid)
    + +
    [docs]@v1_api.route("/upload/providers") +def v1_upload_providers(): + """Return the information about all upload providers, including their + display names, expected settings, and saved profiles. Refer to the + `resolve_provider` function. + + **GET /api/v1/upload/providers** + + Example response:: + + { + "providers": { + "azure": { + "display": "Azure", + "profiles": { + "default": { + "client_id": "example", + ... + } + }, + "settings-info": { + "client_id": { + "display": "Client ID", + "placeholder": "", + "regex": "", + "type": "string" + }, + ... + }, + "supported_types": ["vhd"] + }, + ... + } + } + """ + + ucfg = api.config["COMPOSER_CFG"]["upload"] + + provider_names = list_providers(ucfg) + + def get_provider_info(provider_name): + provider = resolve_provider(ucfg, provider_name) + provider["profiles"] = load_profiles(ucfg, provider_name) + return provider + + providers = {provider_name: get_provider_info(provider_name) + for provider_name in provider_names} + return jsonify(status=True, providers=providers)
    + +
    [docs]@v1_api.route("/upload/providers/save", methods=["POST"]) +def v1_providers_save(): + """Save provider settings as a profile for later use + + **POST /api/v1/upload/providers/save** + + Example request:: + + { + "provider": "azure", + "profile": "my-profile", + "settings": { + "resource_group": "SOMEBODY", + "storage_account_name": "ONCE", + "storage_container": "TOLD", + "location": "ME", + "subscription_id": "THE", + "client_id": "WORLD", + "secret": "IS", + "tenant": "GONNA" + } + } + + Saving to an existing profile will overwrite it. + + Example response:: + + { + "status": true + } + """ + parsed = request.get_json(cache=False) + + if parsed is None: + return jsonify(status=False, errors=[{"id": MISSING_POST, "msg": "Missing POST body"}]), 400 + + try: + provider_name = parsed["provider"] + profile = parsed["profile"] + settings = parsed["settings"] + except KeyError as e: + error = {"id": UPLOAD_ERROR, "msg": f'Missing parameter {str(e)}!'} + return jsonify(status=False, errors=[error]), 400 + try: + save_settings(api.config["COMPOSER_CFG"]["upload"], provider_name, profile, settings) + except Exception as e: + error = {"id": UPLOAD_ERROR, "msg": str(e)} + return jsonify(status=False, errors=[error]) + return jsonify(status=True)
    + +
    [docs]@v1_api.route("/upload/providers/delete", defaults={"provider_name": "", "profile": ""}, methods=["DELETE"]) +@v1_api.route("/upload/providers/delete/<provider_name>/<profile>", methods=["DELETE"]) +@checkparams([("provider_name", "", "no provider name given"), ("profile", "", "no profile given")]) +def v1_providers_delete(provider_name, profile): + """Delete a provider's profile settings + + **DELETE /api/v1/upload/providers/delete/<provider_name>/<profile>** + + Example response:: + + { + "status": true + } + """ + if None in (VALID_API_STRING.match(provider_name), VALID_API_STRING.match(profile)): + error = {"id": INVALID_CHARS, "msg": "Invalid characters in API path"} + return jsonify(status=False, errors=[error]), 400 + + try: + delete_profile(api.config["COMPOSER_CFG"]["upload"], provider_name, profile) + except Exception as e: + error = {"id": UPLOAD_ERROR, "msg": str(e)} + return jsonify(status=False, errors=[error]) + return jsonify(status=True)
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/api/workspace.html b/f32-branch/_modules/pylorax/api/workspace.html new file mode 100644 index 00000000..496e8536 --- /dev/null +++ b/f32-branch/_modules/pylorax/api/workspace.html @@ -0,0 +1,300 @@ + + + + + + + + + + + pylorax.api.workspace — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.workspace

    +#
    +# Copyright (C) 2017  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import os
    +
    +from pylorax.api.recipes import recipe_filename, recipe_from_toml, RecipeFileError
    +from pylorax.sysutils import joinpaths
    +
    +
    +
    [docs]def workspace_dir(repo, branch): + """Create the workspace's path from a Repository and branch + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :returns: The path to the branch's workspace directory + :rtype: str + + """ + repo_path = repo.get_location().get_path() + return joinpaths(repo_path, "workspace", branch)
    + + +
    [docs]def workspace_read(repo, branch, recipe_name): + """Read a Recipe from the branch's workspace + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param recipe_name: The name of the recipe + :type recipe_name: str + :returns: The workspace copy of the recipe, or None if it doesn't exist + :rtype: Recipe or None + :raises: RecipeFileError + """ + ws_dir = workspace_dir(repo, branch) + if not os.path.isdir(ws_dir): + os.makedirs(ws_dir) + filename = joinpaths(ws_dir, recipe_filename(recipe_name)) + if not os.path.exists(filename): + return None + try: + f = open(filename, 'rb') + recipe = recipe_from_toml(f.read().decode("UTF-8")) + except IOError: + raise RecipeFileError + return recipe
    + + +
    [docs]def workspace_write(repo, branch, recipe): + """Write a recipe to the workspace + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param recipe: The recipe to write to the workspace + :type recipe: Recipe + :returns: None + :raises: IO related errors + """ + ws_dir = workspace_dir(repo, branch) + if not os.path.isdir(ws_dir): + os.makedirs(ws_dir) + filename = joinpaths(ws_dir, recipe.filename) + open(filename, 'wb').write(recipe.toml().encode("UTF-8"))
    + + +
    [docs]def workspace_delete(repo, branch, recipe_name): + """Delete the recipe from the workspace + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param recipe_name: The name of the recipe + :type recipe_name: str + :returns: None + :raises: IO related errors + """ + ws_dir = workspace_dir(repo, branch) + filename = joinpaths(ws_dir, recipe_filename(recipe_name)) + if os.path.exists(filename): + os.unlink(filename)
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/base.html b/f32-branch/_modules/pylorax/base.html new file mode 100644 index 00000000..d31d5710 --- /dev/null +++ b/f32-branch/_modules/pylorax/base.html @@ -0,0 +1,268 @@ + + + + + + + + + + + pylorax.base — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.base

    +#
    +# base.py
    +#
    +# Copyright (C) 2009-2015 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Red Hat Author(s):  Martin Gracik <mgracik@redhat.com>
    +#
    +
    +from abc import ABCMeta, abstractmethod
    +import sys
    +
    +import pylorax.output as output
    +
    +
    +
    [docs]class BaseLoraxClass(object, metaclass=ABCMeta): + @abstractmethod + def __init__(self): + self.output = output.LoraxOutput() + +
    [docs] def pcritical(self, msg, fobj=sys.stdout): + self.output.critical(msg, fobj)
    + +
    [docs] def perror(self, msg, fobj=sys.stdout): + self.output.error(msg, fobj)
    + +
    [docs] def pwarning(self, msg, fobj=sys.stdout): + self.output.warning(msg, fobj)
    + +
    [docs] def pinfo(self, msg, fobj=sys.stdout): + self.output.info(msg, fobj)
    + +
    [docs] def pdebug(self, msg, fobj=sys.stdout): + self.output.debug(msg, fobj)
    + + +
    [docs]class DataHolder(dict): + + def __init__(self, **kwargs): + dict.__init__(self) + + for attr, value in kwargs.items(): + self[attr] = value + + def __getattr__(self, attr): + if attr in self: + return self[attr] + else: + raise AttributeError + + def __setattr__(self, attr, value): + self[attr] = value + +
    [docs] def copy(self): + return DataHolder(**dict.copy(self))
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/buildstamp.html b/f32-branch/_modules/pylorax/buildstamp.html new file mode 100644 index 00000000..1423a560 --- /dev/null +++ b/f32-branch/_modules/pylorax/buildstamp.html @@ -0,0 +1,267 @@ + + + + + + + + + + + pylorax.buildstamp — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.buildstamp

    +#
    +# buildstamp.py
    +#
    +# Copyright (C) 2010-2015 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Red Hat Author(s):  Martin Gracik <mgracik@redhat.com>
    +#
    +
    +import logging
    +logger = logging.getLogger("pylorax.buildstamp")
    +
    +import datetime
    +import os
    +
    +
    +
    [docs]class BuildStamp(object): + + def __init__(self, product, version, bugurl, isfinal, buildarch, variant=""): + self.product = product + self.version = version + self.bugurl = bugurl + self.isfinal = isfinal + self.variant = variant + + if 'SOURCE_DATE_EPOCH' in os.environ: + now = datetime.datetime.utcfromtimestamp( + int(os.environ['SOURCE_DATE_EPOCH'])) + else: + now = datetime.datetime.now() + now = now.strftime("%Y%m%d%H%M") + self.uuid = "{0}.{1}".format(now, buildarch) + +
    [docs] def write(self, outfile): + # get lorax version + try: + import pylorax.version + except ImportError: + vernum = "devel" + else: + vernum = pylorax.version.num + + logger.info("writing .buildstamp file") + with open(outfile, "w") as fobj: + fobj.write("[Main]\n") + fobj.write("Product={0.product}\n".format(self)) + fobj.write("Version={0.version}\n".format(self)) + fobj.write("BugURL={0.bugurl}\n".format(self)) + fobj.write("IsFinal={0.isfinal}\n".format(self)) + fobj.write("UUID={0.uuid}\n".format(self)) + if self.variant: + fobj.write("Variant={0.variant}\n".format(self)) + fobj.write("[Compose]\n") + fobj.write("Lorax={0}\n".format(vernum))
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/cmdline.html b/f32-branch/_modules/pylorax/cmdline.html new file mode 100644 index 00000000..b485e68e --- /dev/null +++ b/f32-branch/_modules/pylorax/cmdline.html @@ -0,0 +1,522 @@ + + + + + + + + + + + pylorax.cmdline — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.cmdline

    +#
    +# cmdline.py
    +#
    +# Copyright (C) 2016  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Red Hat Author(s):  Brian C. Lane <bcl@redhat.com>
    +
    +import os
    +import sys
    +import argparse
    +
    +from pylorax import vernum
    +
    +version = "{0}-{1}".format(os.path.basename(sys.argv[0]), vernum)
    +
    +
    [docs]def lorax_parser(dracut_default=""): + """ Return the ArgumentParser for lorax""" + + parser = argparse.ArgumentParser(description="Create the Anaconda boot.iso") + + # required arguments for image creation + required = parser.add_argument_group("required arguments") + required.add_argument("-p", "--product", help="product name", required=True, metavar="PRODUCT") + required.add_argument("-v", "--version", help="version identifier", required=True, metavar="VERSION") + required.add_argument("-r", "--release", help="release information", required=True, metavar="RELEASE") + required.add_argument("-s", "--source", help="source repository (may be listed multiple times)", + metavar="REPOSITORY", action="append", default=[]) + required.add_argument("--repo", help="source dnf repository file", type=os.path.abspath, + dest="repos", metavar="REPOSITORY", action="append", default=[]) + + # optional arguments + optional = parser.add_argument_group("optional arguments") + optional.add_argument("-m", "--mirrorlist", + help="mirrorlist repository (may be listed multiple times)", + metavar="REPOSITORY", action="append", default=[]) + optional.add_argument("-t", "--variant", default="", + help="variant name", metavar="VARIANT") + optional.add_argument("-b", "--bugurl", + help="bug reporting URL for the product", metavar="URL", + default="your distribution provided bug reporting tool") + optional.add_argument("--isfinal", help="", + action="store_true", default=False, dest="isfinal") + optional.add_argument("-c", "--config", default="/etc/lorax/lorax.conf", + help="config file", metavar="CONFIGFILE") + optional.add_argument("--proxy", default=None, + help="repo proxy url:port", metavar="HOST") + optional.add_argument("-i", "--installpkgs", default=[], + action="append", metavar="PACKAGE", + help="package glob to install before runtime-install.tmpl runs. (may be listed multiple times)") + optional.add_argument("-e", "--excludepkgs", default=[], + action="append", metavar="PACKAGE", + help="package glob to remove before runtime-install.tmpl runs. (may be listed multiple times)") + optional.add_argument("--buildarch", default=None, + help="build architecture", metavar="ARCH") + optional.add_argument("--volid", default=None, + help="volume id", metavar="VOLID") + optional.add_argument("--macboot", help="", + action="store_true", default=True, dest="domacboot") + optional.add_argument("--nomacboot", help="", + action="store_false", dest="domacboot") + optional.add_argument("--noupgrade", help="", + action="store_false", default=True, dest="doupgrade") + optional.add_argument("--logfile", default="./lorax.log", type=os.path.abspath, + help="Path to logfile") + optional.add_argument("--tmp", default="/var/tmp/lorax", + help="Top level temporary directory" ) + optional.add_argument("--cachedir", default=None, type=os.path.abspath, + help="DNF cache directory. Default is a temporary dir.") + optional.add_argument("--workdir", default=None, type=os.path.abspath, + help="Work directory, overrides --tmp. Default is a temporary dir under /var/tmp/lorax") + optional.add_argument("--force", default=False, action="store_true", + help="Run even when the destination directory exists") + optional.add_argument("--add-template", dest="add_templates", + action="append", help="Additional template for runtime image", + default=[]) + optional.add_argument("--add-template-var", dest="add_template_vars", + action="append", help="Set variable for runtime image template", + default=[]) + optional.add_argument("--add-arch-template", dest="add_arch_templates", + action="append", help="Additional template for architecture-specific image", + default=[]) + optional.add_argument("--add-arch-template-var", dest="add_arch_template_vars", + action="append", help="Set variable for architecture-specific image", + default=[]) + optional.add_argument("--noverify", action="store_false", default=True, dest="verify", + help="Do not verify the install root") + optional.add_argument("--sharedir", metavar="SHAREDIR", type=os.path.abspath, + help="Directory containing all the templates. Overrides config file sharedir") + optional.add_argument("--enablerepo", action="append", default=[], dest="enablerepos", + metavar="[repo]", help="Names of repos to enable") + optional.add_argument("--disablerepo", action="append", default=[], dest="disablerepos", + metavar="[repo]", help="Names of repos to disable") + optional.add_argument("--rootfs-size", type=int, default=2, + help="Size of root filesystem in GiB. Defaults to 2.") + optional.add_argument("--noverifyssl", action="store_true", default=False, + help="Do not verify SSL certificates") + optional.add_argument("--dnfplugin", action="append", default=[], dest="dnfplugins", + help="Enable a DNF plugin by name/glob, or * to enable all of them.") + optional.add_argument("--squashfs-only", action="store_true", default=False, + help="Use a plain squashfs filesystem for the runtime.") + optional.add_argument("--skip-branding", action="store_true", default=False, + help="Disable automatic branding package selection. Use --installpkgs to add custom branding.") + + # dracut arguments + dracut_group = parser.add_argument_group("dracut arguments: (default: %s)" % dracut_default) + dracut_group.add_argument("--dracut-conf", + help="Path to a dracut.conf file to use instead of the " + "default arguments. See the dracut.conf(5) manpage.") + dracut_group.add_argument("--dracut-arg", action="append", dest="dracut_args", + help="Argument to pass to dracut when " + "rebuilding the initramfs. Pass this " + "once for each argument. NOTE: this " + "overrides the defaults.") + + # add the show version option + parser.add_argument("-V", help="show program's version number and exit", + action="version", version=version) + + parser.add_argument("outputdir", help="Output directory", metavar="OUTPUTDIR", type=os.path.abspath) + + return parser
    + + +
    [docs]def lmc_parser(dracut_default=""): + """ Return a ArgumentParser object for live-media-creator.""" + parser = argparse.ArgumentParser(description="Create Live Install Media", + fromfile_prefix_chars="@") + + # These are mutually exclusive, one is required + action = parser.add_mutually_exclusive_group(required=True) + action.add_argument("--make-iso", action="store_true", + help="Build a live iso") + action.add_argument("--make-disk", action="store_true", + help="Build a partitioned disk image") + action.add_argument("--make-fsimage", action="store_true", + help="Build a filesystem image") + action.add_argument("--make-appliance", action="store_true", + help="Build an appliance image and XML description") + action.add_argument("--make-ami", action="store_true", + help="Build an ami image") + action.add_argument("--make-tar", action="store_true", + help="Build a tar of the root filesystem") + action.add_argument("--make-tar-disk", action="store_true", + help="Build a tar of a partitioned disk image") + action.add_argument("--make-pxe-live", action="store_true", + help="Build a live pxe boot squashfs image") + action.add_argument("--make-ostree-live", action="store_true", + help="Build a live pxe boot squashfs image of Atomic Host") + action.add_argument("--make-oci", action="store_true", + help="Build an Open Container Initiative image") + action.add_argument("--make-vagrant", action="store_true", + help="Build a Vagrant Box image") + + parser.add_argument("--iso", type=os.path.abspath, + help="Anaconda installation .iso path to use for qemu") + parser.add_argument("--iso-only", action="store_true", + help="Remove all iso creation artifacts except the boot.iso, " + "combine with --iso-name to rename the boot.iso") + parser.add_argument("--iso-name", default=None, + help="Name of output iso file for --iso-only. Default is boot.iso") + parser.add_argument("--ks", action="append", type=os.path.abspath, + help="Kickstart file defining the install.") + parser.add_argument("--image-only", action="store_true", + help="Exit after creating fs/disk image.") + + parser.add_argument("--no-virt", action="store_true", + help="Run anaconda directly on host instead of using qemu") + parser.add_argument("--proxy", + help="proxy URL to use for the install") + parser.add_argument("--anaconda-arg", action="append", dest="anaconda_args", + help="Additional argument to pass to anaconda (no-virt " + "mode). Pass once for each argument") + parser.add_argument("--armplatform", + help="the platform to use when creating images for ARM, " + "i.e., highbank, mvebu, omap, tegra, etc.") + parser.add_argument("--location", default=None, type=os.path.abspath, + help="location of iso directory tree with initrd.img " + "and vmlinuz. Used to run qemu with a newer initrd " + "than the iso.") + + parser.add_argument("--logfile", default="./livemedia.log", + type=os.path.abspath, + help="Name and path for primary logfile, other logs will " + "be created in the same directory.") + parser.add_argument("--lorax-templates", default=None, + type=os.path.abspath, + help="Path to mako templates for lorax") + parser.add_argument("--tmp", default="/var/tmp", type=os.path.abspath, + help="Top level temporary directory") + parser.add_argument("--resultdir", default=None, dest="result_dir", + type=os.path.abspath, + help="Directory to copy the resulting images and iso into. " + "Defaults to the temporary working directory") + + parser.add_argument("--macboot", action="store_true", default=True, + dest="domacboot") + parser.add_argument("--nomacboot", action="store_false", + dest="domacboot") + + parser.add_argument("--extra-boot-args", default="", dest="extra_boot_args", + help="Extra arguments to add to the bootloader kernel cmdline in the templates") + + image_group = parser.add_argument_group("disk/fs image arguments") + image_group.add_argument("--disk-image", type=os.path.abspath, + help="Path to existing disk image to use for creating final image.") + image_group.add_argument("--keep-image", action="store_true", + help="Keep raw disk image after .iso creation") + image_group.add_argument("--fs-image", type=os.path.abspath, + help="Path to existing filesystem image to use for creating final image.") + image_group.add_argument("--image-name", default=None, + help="Name of output file to create. Used for tar, fs and disk image. Default is a random name.") + image_group.add_argument("--tar-disk-name", default=None, + help="Name of the archive member for make-tar-disk.") + image_group.add_argument("--fs-label", default="Anaconda", + help="Label to set on fsimage, default is 'Anaconda'") + image_group.add_argument("--image-size-align", type=int, default=0, + help="Create a disk image with a size that is a multiple of this value in MiB.") + image_group.add_argument("--image-type", default=None, + help="Create an image with qemu-img. See qemu-img --help for supported formats.") + image_group.add_argument("--qemu-arg", action="append", dest="qemu_args", default=[], + help="Arguments to pass to qemu-img. Pass once for each argument, they will be used for ALL calls to qemu-img.") + image_group.add_argument("--qcow2", action="store_true", + help="Create qcow2 image instead of raw sparse image when making disk images.") + image_group.add_argument("--qcow2-arg", action="append", dest="qemu_args", default=[], + help="Arguments to pass to qemu-img. Pass once for each argument, they will be used for ALL calls to qemu-img.") + image_group.add_argument("--compression", default="xz", + help="Compression binary for make-tar. xz, lzma, gzip, and bzip2 are supported. xz is the default.") + image_group.add_argument("--compress-arg", action="append", dest="compress_args", default=[], + help="Arguments to pass to compression. Pass once for each argument") + # Group of arguments for appliance creation + app_group = parser.add_argument_group("appliance arguments") + app_group.add_argument("--app-name", default=None, + help="Name of appliance to pass to template") + app_group.add_argument("--app-template", default=None, + help="Path to template to use for appliance data.") + app_group.add_argument("--app-file", default="appliance.xml", + help="Appliance template results file.") + + # Group of arguments to pass to qemu + virt_group = parser.add_argument_group("qemu arguments") + virt_group.add_argument("--ram", metavar="MEMORY", type=int, default=2048, + help="Memory to allocate for installer in megabytes.") + virt_group.add_argument("--vcpus", type=int, default=None, + help="Passed to qemu -smp command") + virt_group.add_argument("--vnc", + help="Passed to qemu -display command. eg. vnc=127.0.0.1:5, default is to " + "choose the first unused vnc port.") + virt_group.add_argument("--arch", default=None, + help="System arch to build for. Used to select qemu-system-* command. " + "Defaults to qemu-system-<arch>") + virt_group.add_argument("--kernel-args", + help="Additional argument to pass to the installation kernel") + virt_group.add_argument("--ovmf-path", default="/usr/share/edk2/ovmf/", + help="Path to OVMF firmware") + virt_group.add_argument("--virt-uefi", action="store_true", default=False, + help="Use OVMF firmware to boot the VM in UEFI mode") + virt_group.add_argument("--no-kvm", action="store_true", default=False, + help="Skip using kvm with qemu even if it is available.") + virt_group.add_argument("--with-rng", default="/dev/random", + help="RNG device for QEMU (none for no RNG)") + + # dracut arguments + dracut_group = parser.add_argument_group("dracut arguments: (default: %s)" % dracut_default) + dracut_group.add_argument("--dracut-conf", + help="Path to a dracut.conf file to use instead of the " + "default arguments. See the dracut.conf(5) manpage.") + dracut_group.add_argument("--dracut-arg", action="append", dest="dracut_args", + help="Argument to pass to dracut when " + "rebuilding the initramfs. Pass this " + "once for each argument. NOTE: this " + "overrides the defaults.") + + # pxe to live arguments + pxelive_group = parser.add_argument_group("pxe to live arguments") + pxelive_group.add_argument("--live-rootfs-size", type=int, default=0, + help="Size of root filesystem of live image in GiB") + pxelive_group.add_argument("--live-rootfs-keep-size", action="store_true", + help="Keep the original size of root filesystem in live image") + + # OCI specific commands + oci_group = parser.add_argument_group("OCI arguments") + oci_group.add_argument("--oci-config", + help="config.json OCI configuration file") + oci_group.add_argument("--oci-runtime", + help="runtime.json OCI configuration file") + + # Vagrant specific commands + vagrant_group = parser.add_argument_group("Vagrant arguments") + vagrant_group.add_argument("--vagrant-metadata", + help="optional metadata.json file") + vagrant_group.add_argument("--vagrantfile", + help="optional vagrantfile") + + parser.add_argument("--project", default="Linux", + help="substituted for @PROJECT@ in bootloader config files") + parser.add_argument("--releasever", default="32", + help="substituted for @VERSION@ in bootloader config files") + parser.add_argument("--volid", default=None, help="volume id") + parser.add_argument("--squashfs-only", action="store_true", default=False, + help="Use a plain squashfs filesystem for the runtime.") + parser.add_argument("--timeout", default=None, type=int, + help="Cancel installer after X minutes") + + # add the show version option + parser.add_argument("-V", help="show program's version number and exit", + action="version", version=version) + + return parser
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/creator.html b/f32-branch/_modules/pylorax/creator.html new file mode 100644 index 00000000..4f3c2da4 --- /dev/null +++ b/f32-branch/_modules/pylorax/creator.html @@ -0,0 +1,952 @@ + + + + + + + + + + + pylorax.creator — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.creator

    +#
    +# Copyright (C) 2011-2018  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("pylorax")
    +
    +import os
    +import tempfile
    +import subprocess
    +import shutil
    +import hashlib
    +import glob
    +
    +# Use Mako templates for appliance builder descriptions
    +from mako.template import Template
    +from mako.exceptions import text_error_template
    +
    +# Use pykickstart to calculate disk image size
    +from pykickstart.parser import KickstartParser
    +from pykickstart.constants import KS_SHUTDOWN
    +from pykickstart.version import makeVersion
    +
    +# Use the Lorax treebuilder branch for iso creation
    +from pylorax import ArchData
    +from pylorax.base import DataHolder
    +from pylorax.executils import execWithRedirect, runcmd
    +from pylorax.imgutils import PartitionMount
    +from pylorax.imgutils import mount, umount, Mount
    +from pylorax.imgutils import mksquashfs, mkrootfsimg
    +from pylorax.imgutils import copytree
    +from pylorax.installer import novirt_install, virt_install, InstallError
    +from pylorax.treebuilder import TreeBuilder, RuntimeBuilder
    +from pylorax.treebuilder import findkernels
    +from pylorax.sysutils import joinpaths, remove
    +
    +
    +# Default parameters for rebuilding initramfs, override with --dracut-arg or --dracut-conf
    +DRACUT_DEFAULT = ["--xz", "--add", "livenet dmsquash-live dmsquash-live-ntfs convertfs pollcdrom qemu qemu-net",
    +                  "--omit", "plymouth", "--no-hostonly", "--debug", "--no-early-microcode"]
    +
    +RUNTIME = "images/install.img"
    +
    +
    [docs]class FakeDNF(object): + """ + A minimal DNF object suitable for passing to RuntimeBuilder + + lmc uses RuntimeBuilder to run the arch specific iso creation + templates, so the the installroot config value is the important part of + this. Everything else should be a nop. + """ + def __init__(self, conf): + self.conf = conf + +
    [docs] def reset(self): + pass
    + +
    [docs]def is_image_mounted(disk_img): + """ + Check to see if the disk_img is mounted + + :returns: True if disk_img is in /proc/mounts + :rtype: bool + """ + with open("/proc/mounts") as mounts: + for mnt in mounts: + fields = mnt.split() + if len(fields) > 2 and fields[1] == disk_img: + return True + return False
    + +
    [docs]def find_ostree_root(phys_root): + """ + Find root of ostree deployment + + :param str phys_root: Path to physical root + :returns: Relative path of ostree deployment root + :rtype: str + :raise Exception: More than one deployment roots were found + """ + ostree_root = "" + ostree_sysroots = glob.glob(joinpaths(phys_root, "ostree/boot.?/*/*/0")) + log.debug("ostree_sysroots = %s", ostree_sysroots) + if ostree_sysroots: + if len(ostree_sysroots) > 1: + raise Exception("Too many deployment roots found: %s" % ostree_sysroots) + ostree_root = os.path.relpath(ostree_sysroots[0], phys_root) + return ostree_root
    + +
    [docs]def get_arch(mount_dir): + """ + Get the kernel arch + + :returns: Arch of first kernel found at mount_dir/boot/ or i386 + :rtype: str + """ + kernels = findkernels(mount_dir) + if not kernels: + return "i386" + return kernels[0].arch
    + +
    [docs]def squashfs_args(opts): + """ Returns the compression type and args to use when making squashfs + + :param opts: ArgumentParser object with compression and compressopts + :returns: tuple of compression type and args + :rtype: tuple + """ + compression = opts.compression or "xz" + arch = ArchData(opts.arch or os.uname().machine) + if compression == "xz" and arch.bcj and not opts.compress_args: + # default to bcj when using xz + compressargs = ["-Xbcj", arch.bcj] + elif opts.compress_args: + compressargs = [] + for arg in opts.compress_args: + compressargs += arg.split(" ", 1) + else: + compressargs = [] + return (compression, compressargs)
    + +
    [docs]def dracut_args(opts): + """Return a list of the args to pass to dracut + + Return the default argument list unless one of the dracut cmdline arguments + has been used. + """ + if opts.dracut_conf: + return ["--conf", opts.dracut_conf] + elif opts.dracut_args: + args = [] + for arg in opts.dracut_args: + args += arg.split(" ", 1) + return args + else: + return DRACUT_DEFAULT
    + +
    [docs]def make_appliance(disk_img, name, template, outfile, networks=None, ram=1024, + vcpus=1, arch=None, title="Linux", project="Linux", + releasever="32"): + """ + Generate an appliance description file + + :param str disk_img: Full path of the disk image + :param str name: Name of the appliance, passed to the template + :param str template: Full path of Mako template + :param str outfile: Full path of file to write, using template + :param list networks: List of networks(str) from the kickstart + :param int ram: Ram, in MiB, passed to template. Default is 1024 + :param int vcpus: CPUs, passed to template. Default is 1 + :param str arch: CPU architecture. Default is 'x86_64' + :param str title: Title, passed to template. Default is 'Linux' + :param str project: Project, passed to template. Default is 'Linux' + :param str releasever: Release version, passed to template. Default is 32 + """ + if not (disk_img and template and outfile): + return None + + log.info("Creating appliance definition using %s", template) + + if not arch: + arch = "x86_64" + + log.info("Calculating SHA256 checksum of %s", disk_img) + sha256 = hashlib.sha256() + with open(disk_img, "rb") as f: + while True: + data = f.read(1024**2) + if not data: + break + sha256.update(data) + log.info("SHA256 of %s is %s", disk_img, sha256.hexdigest()) + disk_info = DataHolder(name=os.path.basename(disk_img), format="raw", + checksum_type="sha256", checksum=sha256.hexdigest()) + try: + result = Template(filename=template).render(disks=[disk_info], name=name, + arch=arch, memory=ram, vcpus=vcpus, networks=networks, + title=title, project=project, releasever=releasever) + except Exception: + log.error(text_error_template().render()) + raise + + with open(outfile, "w") as f: + f.write(result)
    + + +
    [docs]def make_runtime(opts, mount_dir, work_dir, size=None): + """ + Make the squashfs image from a directory + + :param opts: options passed to livemedia-creator + :type opts: argparse options + :param str mount_dir: Directory tree to compress + :param str work_dir: Output compressed image to work_dir+images/install.img + :param int size: Size of disk image, in GiB + """ + kernel_arch = get_arch(mount_dir) + + # Fake dnf object + fake_dbo = FakeDNF(conf=DataHolder(installroot=mount_dir)) + # Fake arch with only basearch set + arch = ArchData(kernel_arch) + # TODO: Need to get release info from someplace... + product = DataHolder(name=opts.project, version=opts.releasever, release="", + variant="", bugurl="", isfinal=False) + + rb = RuntimeBuilder(product, arch, fake_dbo) + compression, compressargs = squashfs_args(opts) + + if opts.squashfs_only: + log.info("Creating a squashfs only runtime") + rb.create_squashfs_runtime(joinpaths(work_dir, RUNTIME), size=size, + compression=compression, compressargs=compressargs) + else: + log.info("Creating a squashfs+ext4 runtime") + rb.create_ext4_runtime(joinpaths(work_dir, RUNTIME), size=size, + compression=compression, compressargs=compressargs)
    + + +
    [docs]def rebuild_initrds_for_live(opts, sys_root_dir, results_dir): + """ + Rebuild intrds for pxe live image (root=live:http://) + + :param opts: options passed to livemedia-creator + :type opts: argparse options + :param str sys_root_dir: Path to root of the system + :param str results_dir: Path of directory for storing results + """ + # cmdline dracut args override the defaults, but need to be parsed + log.info("dracut args = %s", dracut_args(opts)) + + dracut = ["dracut", "--nomdadmconf", "--nolvmconf"] + dracut_args(opts) + + kdir = "boot" + if opts.ostree: + kernels_dir = glob.glob(joinpaths(sys_root_dir, "boot/ostree/*")) + if kernels_dir: + kdir = os.path.relpath(kernels_dir[0], sys_root_dir) + + kernels = [kernel for kernel in findkernels(sys_root_dir, kdir)] + if not kernels: + raise Exception("No initrds found, cannot rebuild_initrds") + + # Hush some dracut warnings. TODO: bind-mount proc in place? + open(joinpaths(sys_root_dir,"/proc/modules"),"w") + + if opts.ostree: + # Dracut assumes to have some dirs in disk image + # /var/tmp for temp files + vartmp_dir = joinpaths(sys_root_dir, "var/tmp") + if not os.path.isdir(vartmp_dir): + os.mkdir(vartmp_dir) + # /root (maybe not fatal) + root_dir = joinpaths(sys_root_dir, "var/roothome") + if not os.path.isdir(root_dir): + os.mkdir(root_dir) + # /tmp (maybe not fatal) + tmp_dir = joinpaths(sys_root_dir, "sysroot/tmp") + if not os.path.isdir(tmp_dir): + os.mkdir(tmp_dir) + + # Write the new initramfs directly to the results directory + os.mkdir(joinpaths(sys_root_dir, "results")) + mount(results_dir, opts="bind", mnt=joinpaths(sys_root_dir, "results")) + # Dracut runs out of space inside the minimal rootfs image + mount("/var/tmp", opts="bind", mnt=joinpaths(sys_root_dir, "var/tmp")) + for kernel in kernels: + if hasattr(kernel, "initrd"): + outfile = os.path.basename(kernel.initrd.path) + else: + # Construct an initrd from the kernel name + outfile = os.path.basename(kernel.path.replace("vmlinuz-", "initrd-") + ".img") + log.info("rebuilding %s", outfile) + + kver = kernel.version + + cmd = dracut + ["/results/"+outfile, kver] + runcmd(cmd, root=sys_root_dir) + + shutil.copy2(joinpaths(sys_root_dir, kernel.path), results_dir) + umount(joinpaths(sys_root_dir, "var/tmp"), delete=False) + umount(joinpaths(sys_root_dir, "results"), delete=False) + os.unlink(joinpaths(sys_root_dir,"/proc/modules"))
    + +
    [docs]def create_pxe_config(template, images_dir, live_image_name, add_args = None): + """ + Create template for pxe to live configuration + + :param str images_dir: Path of directory with images to be used + :param str live_image_name: Name of live rootfs image file + :param list add_args: Arguments to be added to initrd= pxe config + """ + + add_args = add_args or [] + + kernels = [kernel for kernel in findkernels(images_dir, kdir="") + if hasattr(kernel, "initrd")] + if not kernels: + return + + kernel = kernels[0] + + add_args_str = " ".join(add_args) + + + try: + result = Template(filename=template).render(kernel=kernel.path, + initrd=kernel.initrd.path, liveimg=live_image_name, + addargs=add_args_str) + except Exception: + log.error(text_error_template().render()) + raise + + with open (joinpaths(images_dir, "PXE_CONFIG"), "w") as f: + f.write(result)
    + + +
    [docs]def make_livecd(opts, mount_dir, work_dir): + """ + Take the content from the disk image and make a livecd out of it + + :param opts: options passed to livemedia-creator + :type opts: argparse options + :param str mount_dir: Directory tree to compress + :param str work_dir: Output compressed image to work_dir+images/install.img + + This uses wwood's squashfs live initramfs method: + * put the real / into LiveOS/rootfs.img + * make a squashfs of the LiveOS/rootfs.img tree + * This is loaded by dracut when the cmdline is passed to the kernel: + root=live:CDLABEL=<volid> rd.live.image + """ + kernel_arch = get_arch(mount_dir) + + arch = ArchData(kernel_arch) + # TODO: Need to get release info from someplace... + product = DataHolder(name=opts.project, version=opts.releasever, release="", + variant="", bugurl="", isfinal=False) + + # Link /images to work_dir/images to make the templates happy + if os.path.islink(joinpaths(mount_dir, "images")): + os.unlink(joinpaths(mount_dir, "images")) + rc = execWithRedirect("/bin/ln", ["-s", joinpaths(work_dir, "images"), + joinpaths(mount_dir, "images")]) + if rc: + raise RuntimeError("Failed to symlink images from mount_dir to work_dir") + + # The templates expect the config files to be in /tmp/config_files + # I think these should be release specific, not from lorax, but for now + configdir = joinpaths(opts.lorax_templates,"live/config_files/") + configdir_path = "tmp/config_files" + fullpath = joinpaths(mount_dir, configdir_path) + if os.path.exists(fullpath): + remove(fullpath) + copytree(configdir, fullpath) + + isolabel = opts.volid or "{0.name}-{0.version}-{1.basearch}".format(product, arch) + if len(isolabel) > 32: + isolabel = isolabel[:32] + log.warning("Truncating isolabel to 32 chars: %s", isolabel) + + tb = TreeBuilder(product=product, arch=arch, domacboot=opts.domacboot, + inroot=mount_dir, outroot=work_dir, + runtime=RUNTIME, isolabel=isolabel, + templatedir=joinpaths(opts.lorax_templates,"live/"), + extra_boot_args=opts.extra_boot_args) + log.info("Rebuilding initrds") + log.info("dracut args = %s", dracut_args(opts)) + tb.rebuild_initrds(add_args=dracut_args(opts)) + log.info("Building boot.iso") + tb.build() + + return work_dir
    + +
    [docs]def mount_boot_part_over_root(img_mount): + """ + Mount boot partition to /boot of root fs mounted in img_mount + + Used for OSTree so it finds deployment configurations on live rootfs + + param img_mount: object with mounted disk image root partition + type img_mount: imgutils.PartitionMount + """ + root_dir = img_mount.mount_dir + is_boot_part = lambda dir: os.path.exists(dir+"/loader.0") + tmp_mount_dir = tempfile.mkdtemp(prefix="lmc-tmpdir-") + sysroot_boot_dir = None + for dev, _size in img_mount.loop_devices: + if dev is img_mount.mount_dev: + continue + try: + mount("/dev/mapper/"+dev, mnt=tmp_mount_dir) + if is_boot_part(tmp_mount_dir): + umount(tmp_mount_dir) + sysroot_boot_dir = joinpaths(root_dir, "boot") + mount("/dev/mapper/"+dev, mnt=sysroot_boot_dir) + break + else: + umount(tmp_mount_dir) + except subprocess.CalledProcessError as e: + log.debug("Looking for boot partition error: %s", e) + remove(tmp_mount_dir) + return sysroot_boot_dir
    + +
    [docs]def calculate_disk_size(opts, ks): + """ Calculate the disk size from the kickstart + + :param opts: options passed to livemedia-creator + :type opts: argparse options + :param str ks: Path to the kickstart to use for the installation + :returns: Disk size in MiB + :rtype: int + + Also takes into account the use of reqpart or reqpart --add-boot + """ + # Disk size for a filesystem image should only be the size of / + # to prevent surprises when using the same kickstart for different installations. + unique_partitions = dict((p.mountpoint, p) for p in ks.handler.partition.partitions) + if opts.no_virt and (opts.make_iso or opts.make_fsimage): + disk_size = 2 + sum(p.size for p in unique_partitions.values() if p.mountpoint == "/") + else: + disk_size = 2 + sum(p.size for p in unique_partitions.values()) + + # reqpart can add 1M, 2M, 200M based on platform. Add 500M to be sure + if ks.handler.reqpart.seen: + log.info("Adding 500M for reqpart") + disk_size += 500 + + # It can also request adding /boot which is 1G + if ks.handler.reqpart.addBoot: + log.info("Adding 1024M for reqpart --addboot") + disk_size += 1024 + + if opts.image_size_align: + disk_size += opts.image_size_align - (disk_size % opts.image_size_align) + + log.info("Using disk size of %sMiB", disk_size) + return disk_size
    + +
    [docs]def make_image(opts, ks, cancel_func=None): + """ + Install to a disk image + + :param opts: options passed to livemedia-creator + :type opts: argparse options + :param str ks: Path to the kickstart to use for the installation + :param cancel_func: Function that returns True to cancel build + :type cancel_func: function + :returns: Path of the image created + :rtype: str + + Use qemu+boot.iso or anaconda to install to a disk image. + """ + + # For make_tar_disk, opts.image_name is the name of the final tarball. + # Use opts.tar_disk_name as the name of the disk image + if opts.make_tar_disk: + disk_img = joinpaths(opts.result_dir, opts.tar_disk_name) + elif opts.image_name: + disk_img = joinpaths(opts.result_dir, opts.image_name) + else: + disk_img = tempfile.mktemp(prefix="lmc-disk-", suffix=".img", dir=opts.result_dir) + log.info("disk_img = %s", disk_img) + disk_size = calculate_disk_size(opts, ks) + + # For make_tar_disk, pass a second path parameter for the final tarball + # not the final output file. + if opts.make_tar_disk: + tar_img = joinpaths(opts.result_dir, opts.image_name) + else: + tar_img = None + + try: + if opts.no_virt: + novirt_install(opts, disk_img, disk_size, cancel_func=cancel_func, tar_img=tar_img) + else: + install_log = os.path.abspath(os.path.dirname(opts.logfile))+"/virt-install.log" + log.info("install_log = %s", install_log) + + virt_install(opts, install_log, disk_img, disk_size, cancel_func=cancel_func, tar_img=tar_img) + except InstallError as e: + log.error("Install failed: %s", e) + if not opts.keep_image: + if os.path.exists(disk_img): + log.info("Removing bad disk image") + os.unlink(disk_img) + if tar_img and os.path.exists(tar_img): + log.info("Removing bad tar file") + os.unlink(tar_img) + raise + + log.info("Disk Image install successful") + + if opts.make_tar_disk: + return tar_img + + return disk_img
    + + +
    [docs]def make_live_images(opts, work_dir, disk_img): + """ + Create live images from direcory or rootfs image + + :param opts: options passed to livemedia-creator + :type opts: argparse options + :param str work_dir: Directory for storing results + :param str disk_img: Path to disk image (fsimage or partitioned) + :returns: Path of directory with created images or None + :rtype: str + + fsck.ext4 is run on the rootfs_image to make sure there are no errors and to zero + out any deleted blocks to make it compress better. If this fails for any reason + it will return None and log the error. + """ + sys_root = "" + + squashfs_root_dir = joinpaths(work_dir, "squashfs_root") + liveos_dir = joinpaths(squashfs_root_dir, "LiveOS") + os.makedirs(liveos_dir) + rootfs_img = joinpaths(liveos_dir, "rootfs.img") + + if opts.fs_image or opts.no_virt: + # Find the ostree root in the fsimage + if opts.ostree: + with Mount(disk_img, opts="loop") as mnt_dir: + sys_root = find_ostree_root(mnt_dir) + + # Try to hardlink the image, if that fails, copy it + rc = execWithRedirect("/bin/ln", [disk_img, rootfs_img]) + if rc != 0: + shutil.copy2(disk_img, rootfs_img) + else: + is_root_part = None + if opts.ostree: + is_root_part = lambda dir: os.path.exists(dir+"/ostree/deploy") + with PartitionMount(disk_img, mount_ok=is_root_part) as img_mount: + if img_mount and img_mount.mount_dir: + try: + mounted_sysroot_boot_dir = None + if opts.ostree: + sys_root = find_ostree_root(img_mount.mount_dir) + mounted_sysroot_boot_dir = mount_boot_part_over_root(img_mount) + if opts.live_rootfs_keep_size: + size = img_mount.mount_size / 1024**3 + else: + size = opts.live_rootfs_size or None + log.info("Creating live rootfs image") + mkrootfsimg(img_mount.mount_dir, rootfs_img, "LiveOS", size=size, sysroot=sys_root) + finally: + if mounted_sysroot_boot_dir: + umount(mounted_sysroot_boot_dir) + log.debug("sys_root = %s", sys_root) + + # Make sure free blocks are actually zeroed so it will compress + rc = execWithRedirect("/usr/sbin/fsck.ext4", ["-y", "-f", "-E", "discard", rootfs_img]) + if rc != 0: + log.error("Problem zeroing free blocks of %s", disk_img) + return None + + log.info("Packing live rootfs image") + add_pxe_args = [] + live_image_name = "live-rootfs.squashfs.img" + compression, compressargs = squashfs_args(opts) + mksquashfs(squashfs_root_dir, joinpaths(work_dir, live_image_name), compression, compressargs) + + log.info("Rebuilding initramfs for live") + with Mount(rootfs_img, opts="loop") as mnt_dir: + try: + mount(joinpaths(mnt_dir, "boot"), opts="bind", mnt=joinpaths(mnt_dir, sys_root, "boot")) + rebuild_initrds_for_live(opts, joinpaths(mnt_dir, sys_root), work_dir) + finally: + umount(joinpaths(mnt_dir, sys_root, "boot"), delete=False) + + remove(squashfs_root_dir) + + if opts.ostree: + add_pxe_args.append("ostree=/%s" % sys_root) + template = joinpaths(opts.lorax_templates, "pxe-live/pxe-config.tmpl") + create_pxe_config(template, work_dir, live_image_name, add_pxe_args) + + return work_dir
    + +
    [docs]def check_kickstart(ks, opts): + """Check the parsed kickstart object for errors + + :param ks: Parsed Kickstart object + :type ks: pykickstart.parser.KickstartParser + :param opts: Commandline options to control the process + :type opts: Either a DataHolder or ArgumentParser + :returns: List of error strings or empty list + :rtype: list + """ + errors = [] + if opts.no_virt and ks.handler.method.method not in ("url", "nfs") \ + and not ks.handler.ostreesetup.seen: + errors.append("Only url, nfs and ostreesetup install methods are currently supported." + "Please fix your kickstart file." ) + + if ks.handler.repo.seen and ks.handler.method.method != "url": + errors.append("repo can only be used with the url install method. Add url to your " + "kickstart file.") + + if ks.handler.method.method in ("url", "nfs") and not ks.handler.network.seen: + errors.append("The kickstart must activate networking if " + "the url or nfs install method is used.") + + if ks.handler.displaymode.displayMode is not None: + errors.append("The kickstart must not set a display mode (text, cmdline, " + "graphical), this will interfere with livemedia-creator.") + + if opts.make_fsimage or (opts.make_pxe_live and opts.no_virt): + # Make sure the kickstart isn't using autopart and only has a / mountpoint + part_ok = not any(p for p in ks.handler.partition.partitions + if p.mountpoint not in ["/", "swap"]) + if not part_ok or ks.handler.autopart.seen: + errors.append("Filesystem images must use a single / part, not autopart or " + "multiple partitions. swap is allowed but not used.") + + if not opts.no_virt and ks.handler.reboot.action != KS_SHUTDOWN: + errors.append("The kickstart must include shutdown when using virt installation.") + + return errors
    + +
    [docs]def run_creator(opts, cancel_func=None): + """Run the image creator process + + :param opts: Commandline options to control the process + :type opts: Either a DataHolder or ArgumentParser + :param cancel_func: Function that returns True to cancel build + :type cancel_func: function + :returns: The result directory and the disk image path. + :rtype: Tuple of str + + This function takes the opts arguments and creates the selected output image. + See the cmdline --help for livemedia-creator for the possible options + + (Yes, this is not ideal, but we can fix that later) + """ + result_dir = None + + # Parse the kickstart + if opts.ks: + ks_version = makeVersion() + ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False) + ks.readKickstart(opts.ks[0]) + + # live iso usually needs dracut-live so warn the user if it is missing + if opts.ks and opts.make_iso: + if "dracut-live" not in ks.handler.packages.packageList: + log.error("dracut-live package is missing from the kickstart.") + raise RuntimeError("dracut-live package is missing from the kickstart.") + + # Make the disk or filesystem image + if not opts.disk_image and not opts.fs_image: + if not opts.ks: + raise RuntimeError("Image creation requires a kickstart file") + + # Check the kickstart for problems + errors = check_kickstart(ks, opts) + if errors: + list(log.error(e) for e in errors) + raise RuntimeError("\n".join(errors)) + + # Make the image. Output of this is either a partitioned disk image or a fsimage + try: + disk_img = make_image(opts, ks, cancel_func=cancel_func) + except InstallError as e: + log.error("ERROR: Image creation failed: %s", e) + raise RuntimeError("Image creation failed: %s" % e) + + if opts.image_only: + return (result_dir, disk_img) + + if opts.make_iso: + work_dir = tempfile.mkdtemp(prefix="lmc-work-") + log.info("working dir is %s", work_dir) + + if (opts.fs_image or opts.no_virt) and not opts.disk_image: + # Create iso from a filesystem image + disk_img = opts.fs_image or disk_img + with Mount(disk_img, opts="loop") as mount_dir: + # TODO check rc + make_runtime(opts, mount_dir, work_dir, calculate_disk_size(opts, ks)/1024.0) + + if cancel_func and cancel_func(): + raise RuntimeError("ISO creation canceled") + + result_dir = make_livecd(opts, mount_dir, work_dir) + else: + # Create iso from a partitioned disk image + disk_img = opts.disk_image or disk_img + with PartitionMount(disk_img) as img_mount: + if img_mount and img_mount.mount_dir: + make_runtime(opts, img_mount.mount_dir, work_dir, calculate_disk_size(opts, ks)/1024.0) + result_dir = make_livecd(opts, img_mount.mount_dir, work_dir) + + # --iso-only removes the extra build artifacts, keeping only the boot.iso + if opts.iso_only and result_dir: + boot_iso = joinpaths(result_dir, "images/boot.iso") + if not os.path.exists(boot_iso): + log.error("%s is missing, skipping --iso-only.", boot_iso) + else: + iso_dir = tempfile.mkdtemp(prefix="lmc-result-") + dest_file = joinpaths(iso_dir, opts.iso_name or "boot.iso") + shutil.move(boot_iso, dest_file) + shutil.rmtree(result_dir) + result_dir = iso_dir + + # cleanup the mess + # cleanup work_dir? + if disk_img and not (opts.keep_image or opts.disk_image or opts.fs_image): + os.unlink(disk_img) + log.info("Disk image erased") + disk_img = None + elif opts.make_appliance: + if not opts.ks: + networks = [] + else: + networks = ks.handler.network.network + make_appliance(opts.disk_image or disk_img, opts.app_name, + opts.app_template, opts.app_file, networks, opts.ram, + opts.vcpus or 1, opts.arch, opts.title, opts.project, opts.releasever) + elif opts.make_pxe_live: + work_dir = tempfile.mkdtemp(prefix="lmc-work-") + log.info("working dir is %s", work_dir) + disk_img = opts.fs_image or opts.disk_image or disk_img + log.debug("disk image is %s", disk_img) + + result_dir = make_live_images(opts, work_dir, disk_img) + if result_dir is None: + log.error("Creating PXE live image failed.") + raise RuntimeError("Creating PXE live image failed.") + + if opts.result_dir != opts.tmp and result_dir: + copytree(result_dir, opts.result_dir, preserve=False) + shutil.rmtree(result_dir) + result_dir = None + + return (result_dir, disk_img)
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/decorators.html b/f32-branch/_modules/pylorax/decorators.html new file mode 100644 index 00000000..5abd4bd1 --- /dev/null +++ b/f32-branch/_modules/pylorax/decorators.html @@ -0,0 +1,231 @@ + + + + + + + + + + + pylorax.decorators — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.decorators

    +#
    +# decorators.py
    +#
    +# Copyright (C) 2009-2015 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Red Hat Author(s):  Martin Gracik <mgracik@redhat.com>
    +#
    +
    +
    [docs]def singleton(cls): + instances = {} + + def get_instance(): + if cls not in instances: + instances[cls] = cls() + return instances[cls] + + return get_instance
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/discinfo.html b/f32-branch/_modules/pylorax/discinfo.html new file mode 100644 index 00000000..2864b246 --- /dev/null +++ b/f32-branch/_modules/pylorax/discinfo.html @@ -0,0 +1,246 @@ + + + + + + + + + + + pylorax.discinfo — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.discinfo

    +#
    +# discinfo.py
    +#
    +# Copyright (C) 2010-2015  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Red Hat Author(s):  Martin Gracik <mgracik@redhat.com>
    +#
    +
    +import logging
    +logger = logging.getLogger("pylorax.discinfo")
    +
    +import os
    +import time
    +
    +
    +
    [docs]class DiscInfo(object): + + def __init__(self, release, basearch): + self.release = release + self.basearch = basearch + +
    [docs] def write(self, outfile): + if 'SOURCE_DATE_EPOCH' in os.environ: + timestamp = int(os.environ['SOURCE_DATE_EPOCH']) + else: + timestamp = time.time() + + logger.info("writing .discinfo file") + with open(outfile, "w") as fobj: + fobj.write("{0:f}\n".format(timestamp)) + fobj.write("{0.release}\n".format(self)) + fobj.write("{0.basearch}\n".format(self))
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/dnfbase.html b/f32-branch/_modules/pylorax/dnfbase.html new file mode 100644 index 00000000..134ab084 --- /dev/null +++ b/f32-branch/_modules/pylorax/dnfbase.html @@ -0,0 +1,388 @@ + + + + + + + + + + + pylorax.dnfbase — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.dnfbase

    +# Copyright (C) 2018 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("pylorax")
    +
    +import dnf
    +import os
    +import shutil
    +
    +from pylorax import DEFAULT_PLATFORM_ID
    +from pylorax.sysutils import flatconfig
    +
    +
    [docs]def get_dnf_base_object(installroot, sources, mirrorlists=None, repos=None, + enablerepos=None, disablerepos=None, + tempdir="/var/tmp", proxy=None, releasever="32", + cachedir=None, logdir=None, sslverify=True, dnfplugins=None): + """ Create a dnf Base object and setup the repositories and installroot + + :param string installroot: Full path to the installroot + :param list sources: List of source repo urls to use for the installation + :param list enablerepos: List of repo names to enable + :param list disablerepos: List of repo names to disable + :param list mirrorlist: List of mirrors to use + :param string tempdir: Path of temporary directory + :param string proxy: http proxy to use when fetching packages + :param string releasever: Release version to pass to dnf + :param string cachedir: Directory to use for caching packages + :param bool noverifyssl: Set to True to ignore the CA of ssl certs. eg. use self-signed ssl for https repos. + + If tempdir is not set /var/tmp is used. + If cachedir is None a dnf.cache directory is created inside tmpdir + """ + def sanitize_repo(repo): + """Convert bare paths to file:/// URIs, and silently reject protocols unhandled by yum""" + if repo.startswith("/"): + return "file://{0}".format(repo) + elif any(repo.startswith(p) for p in ('http://', 'https://', 'ftp://', 'file://')): + return repo + else: + return None + + mirrorlists = mirrorlists or [] + + # sanitize the repositories + sources = list(sanitize_repo(r) for r in sources) + mirrorlists = list(sanitize_repo(r) for r in mirrorlists) + + # remove invalid repositories + sources = list(r for r in sources if r) + mirrorlists = list(r for r in mirrorlists if r) + + if not cachedir: + cachedir = os.path.join(tempdir, "dnf.cache") + if not os.path.isdir(cachedir): + os.mkdir(cachedir) + + if not logdir: + logdir = os.path.join(tempdir, "dnf.logs") + if not os.path.isdir(logdir): + os.mkdir(logdir) + + dnfbase = dnf.Base() + # Enable DNF pluings + # NOTE: These come from the HOST system's environment + if dnfplugins: + if dnfplugins[0] == "*": + # Enable them all + dnfbase.init_plugins() + else: + # Only enable the listed plugins + dnfbase.init_plugins(disabled_glob=["*"], enable_plugins=dnfplugins) + conf = dnfbase.conf + conf.logdir = logdir + conf.cachedir = cachedir + + conf.install_weak_deps = False + conf.releasever = releasever + conf.installroot = installroot + conf.prepend_installroot('persistdir') + # this is a weird 'AppendOption' thing that, when you set it, + # actually appends. Doing this adds 'nodocs' to the existing list + # of values, over in libdnf, it does not replace the existing values. + conf.tsflags = ['nodocs'] + # Log details about the solver + conf.debug_solver = True + + if proxy: + conf.proxy = proxy + + if sslverify == False: + conf.sslverify = False + + # DNF 3.2 needs to have module_platform_id set, otherwise depsolve won't work correctly + if not os.path.exists("/etc/os-release"): + log.warning("/etc/os-release is missing, cannot determine platform id, falling back to %s", DEFAULT_PLATFORM_ID) + platform_id = DEFAULT_PLATFORM_ID + else: + os_release = flatconfig("/etc/os-release") + platform_id = os_release.get("PLATFORM_ID", DEFAULT_PLATFORM_ID) + log.info("Using %s for module_platform_id", platform_id) + conf.module_platform_id = platform_id + + # Add .repo files + if repos: + reposdir = os.path.join(tempdir, "dnf.repos") + if not os.path.isdir(reposdir): + os.mkdir(reposdir) + for r in repos: + shutil.copy2(r, reposdir) + conf.reposdir = [reposdir] + dnfbase.read_all_repos() + + # add the sources + for i, r in enumerate(sources): + if "SRPM" in r or "srpm" in r: + log.info("Skipping source repo: %s", r) + continue + repo_name = "lorax-repo-%d" % i + repo = dnf.repo.Repo(repo_name, conf) + repo.baseurl = [r] + if proxy: + repo.proxy = proxy + repo.enable() + dnfbase.repos.add(repo) + log.info("Added '%s': %s", repo_name, r) + log.info("Fetching metadata...") + try: + repo.load() + except dnf.exceptions.RepoError as e: + log.error("Error fetching metadata for %s: %s", repo_name, e) + return None + + # add the mirrorlists + for i, r in enumerate(mirrorlists): + if "SRPM" in r or "srpm" in r: + log.info("Skipping source repo: %s", r) + continue + repo_name = "lorax-mirrorlist-%d" % i + repo = dnf.repo.Repo(repo_name, conf) + repo.mirrorlist = r + if proxy: + repo.proxy = proxy + repo.enable() + dnfbase.repos.add(repo) + log.info("Added '%s': %s", repo_name, r) + log.info("Fetching metadata...") + try: + repo.load() + except dnf.exceptions.RepoError as e: + log.error("Error fetching metadata for %s: %s", repo_name, e) + return None + + # Enable repos listed on the cmdline + for r in enablerepos: + repolist = dnfbase.repos.get_matching(r) + if not repolist: + log.warning("%s is an unknown repo, not enabling it", r) + else: + repolist.enable() + log.info("Enabled repo %s", r) + + # Disable repos listed on the cmdline + for r in disablerepos: + repolist = dnfbase.repos.get_matching(r) + if not repolist: + log.warning("%s is an unknown repo, not disabling it", r) + else: + repolist.disable() + log.info("Disabled repo %s", r) + + dnfbase.fill_sack(load_system_repo=False) + dnfbase.read_comps() + + return dnfbase
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/dnfhelper.html b/f32-branch/_modules/pylorax/dnfhelper.html new file mode 100644 index 00000000..c0420ce6 --- /dev/null +++ b/f32-branch/_modules/pylorax/dnfhelper.html @@ -0,0 +1,311 @@ + + + + + + + + + + + pylorax.dnfhelper — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.dnfhelper

    +#
    +# dnfhelper.py
    +#
    +# Copyright (C) 2010-2015 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Red Hat Author(s):  Martin Gracik <mgracik@redhat.com>
    +#                     Brian C. Lane <bcl@redhat.com>
    +#
    +
    +import logging
    +logger = logging.getLogger("pylorax.dnfhelper")
    +import dnf
    +import dnf.transaction
    +import collections
    +import time
    +import pylorax.output as output
    +
    +__all__ = ['LoraxDownloadCallback', 'LoraxRpmCallback']
    +
    +def _paced(fn):
    +    """Execute `fn` no more often then every 2 seconds."""
    +    def paced_fn(self, *args):
    +        now = time.time()
    +        if now - self.last_time < 2:
    +            return
    +        self.last_time = now
    +        return fn(self, *args)
    +    return paced_fn
    +
    +
    +
    [docs]class LoraxDownloadCallback(dnf.callback.DownloadProgress): + def __init__(self): + self.downloads = collections.defaultdict(int) + self.last_time = time.time() + self.total_files = 0 + self.total_size = 0 + + self.pkgno = 0 + self.total = 0 + + self.output = output.LoraxOutput() + + @_paced + def _update(self): + msg = "Downloading %(pkgno)s / %(total_files)s RPMs, " \ + "%(downloaded)s / %(total_size)s (%(percent)d%%) done.\n" + downloaded = sum(self.downloads.values()) + vals = { + 'downloaded' : downloaded, + 'percent' : int(100 * downloaded/self.total_size), + 'pkgno' : self.pkgno, + 'total_files' : self.total_files, + 'total_size' : self.total_size + } + self.output.write(msg % vals) + +
    [docs] def end(self, payload, status, msg): + nevra = str(payload) + if status is dnf.callback.STATUS_OK: + self.downloads[nevra] = payload.download_size + self.pkgno += 1 + self._update() + return + logger.critical("Failed to download '%s': %d - %s", nevra, status, msg)
    + +
    [docs] def progress(self, payload, done): + nevra = str(payload) + self.downloads[nevra] = done + self._update()
    + + # dnf 2.5.0 adds a new argument, accept it if it is passed + # pylint: disable=arguments-differ +
    [docs] def start(self, total_files, total_size, total_drpms=0): + self.total_files = total_files + self.total_size = total_size
    + + +
    [docs]class LoraxRpmCallback(dnf.callback.TransactionProgress): + def __init__(self): + super(LoraxRpmCallback, self).__init__() + self._last_ts = None + +
    [docs] def progress(self, package, action, ti_done, ti_total, ts_done, ts_total): + if action == dnf.transaction.PKG_INSTALL: + # do not report same package twice + if self._last_ts == ts_done: + return + self._last_ts = ts_done + + msg = '(%d/%d) %s' % (ts_done, ts_total, package) + logger.info(msg) + elif action == dnf.transaction.TRANS_POST: + msg = "Performing post-installation setup tasks" + logger.info(msg)
    + +
    [docs] def error(self, message): + logger.warning(message)
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/executils.html b/f32-branch/_modules/pylorax/executils.html new file mode 100644 index 00000000..ba0f7fee --- /dev/null +++ b/f32-branch/_modules/pylorax/executils.html @@ -0,0 +1,550 @@ + + + + + + + + + + + pylorax.executils — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.executils

    +#
    +# executil.py - subprocess execution utility functions
    +#
    +# Copyright (C) 1999-2015
    +# Red Hat, Inc.  All rights reserved.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +import os
    +import subprocess
    +from subprocess import TimeoutExpired
    +import signal
    +
    +import logging
    +log = logging.getLogger("pylorax")
    +program_log = logging.getLogger("program")
    +
    +# pylint: disable=not-context-manager
    +from threading import Lock
    +program_log_lock = Lock()
    +
    +_child_env = {}
    +
    +
    [docs]def setenv(name, value): + """ Set an environment variable to be used by child processes. + + This method does not modify os.environ for the running process, which + is not thread-safe. If setenv has already been called for a particular + variable name, the old value is overwritten. + + :param str name: The name of the environment variable + :param str value: The value of the environment variable + """ + + _child_env[name] = value
    + +
    [docs]def augmentEnv(): + env = os.environ.copy() + env.update(_child_env) + return env
    + +
    [docs]class ExecProduct(object): + def __init__(self, rc, stdout, stderr): + self.rc = rc + self.stdout = stdout + self.stderr = stderr
    + +
    [docs]def startProgram(argv, root='/', stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + env_prune=None, env_add=None, reset_handlers=True, reset_lang=True, **kwargs): + """ Start an external program and return the Popen object. + + The root and reset_handlers arguments are handled by passing a + preexec_fn argument to subprocess.Popen, but an additional preexec_fn + can still be specified and will be run. The user preexec_fn will be run + last. + + :param argv: The command to run and argument + :param root: The directory to chroot to before running command. + :param stdin: The file object to read stdin from. + :param stdout: The file object to write stdout to. + :param stderr: The file object to write stderr to. + :param env_prune: environment variables to remove before execution + :param env_add: environment variables to add before execution + :param reset_handlers: whether to reset to SIG_DFL any signal handlers set to SIG_IGN + :param reset_lang: whether to set the locale of the child process to C + :param kwargs: Additional parameters to pass to subprocess.Popen + :return: A Popen object for the running command. + :keyword preexec_fn: A function to run before execution starts. + """ + if env_prune is None: + env_prune = [] + + # Check for and save a preexec_fn argument + preexec_fn = kwargs.pop("preexec_fn", None) + + def preexec(): + # If a target root was specificed, chroot into it + if root and root != '/': + os.chroot(root) + os.chdir("/") + + # Signal handlers set to SIG_IGN persist across exec. Reset + # these to SIG_DFL if requested. In particular this will include the + # SIGPIPE handler set by python. + if reset_handlers: + for signum in range(1, signal.NSIG): + if signal.getsignal(signum) == signal.SIG_IGN: + signal.signal(signum, signal.SIG_DFL) + + # If the user specified an additional preexec_fn argument, run it + if preexec_fn is not None: + preexec_fn() + + with program_log_lock: + program_log.info("Running... %s", " ".join(argv)) + + env = augmentEnv() + for var in env_prune: + env.pop(var, None) + + if reset_lang: + env.update({"LC_ALL": "C"}) + + if env_add: + env.update(env_add) + + # pylint: disable=subprocess-popen-preexec-fn + return subprocess.Popen(argv, + stdin=stdin, + stdout=stdout, + stderr=stderr, + close_fds=True, + preexec_fn=preexec, cwd=root, env=env, **kwargs)
    + +def _run_program(argv, root='/', stdin=None, stdout=None, env_prune=None, log_output=True, + binary_output=False, filter_stderr=False, raise_err=False, callback=None, + env_add=None, reset_handlers=True, reset_lang=True): + """ Run an external program, log the output and return it to the caller + + :param argv: The command to run and argument + :param root: The directory to chroot to before running command. + :param stdin: The file object to read stdin from. + :param stdout: Optional file object to write the output to. + :param env_prune: environment variable to remove before execution + :param log_output: whether to log the output of command + :param binary_output: whether to treat the output of command as binary data + :param filter_stderr: whether to exclude the contents of stderr from the returned output + :param raise_err: whether to raise a CalledProcessError if the returncode is non-zero + :param callback: method to call while waiting for process to finish, passed Popen object + :param env_add: environment variables to add before execution + :param reset_handlers: whether to reset to SIG_DFL any signal handlers set to SIG_IGN + :param reset_lang: whether to set the locale of the child process to C + :return: The return code of the command and the output + :raises: OSError or CalledProcessError + """ + try: + if filter_stderr: + stderr = subprocess.PIPE + else: + stderr = subprocess.STDOUT + + proc = startProgram(argv, root=root, stdin=stdin, stdout=subprocess.PIPE, stderr=stderr, + env_prune=env_prune, universal_newlines=not binary_output, + env_add=env_add, reset_handlers=reset_handlers, reset_lang=reset_lang) + + output_string = None + err_string = None + if callback: + while callback(proc) and proc.poll() is None: + try: + (output_string, err_string) = proc.communicate(timeout=1) + break + except TimeoutExpired: + pass + else: + (output_string, err_string) = proc.communicate() + if output_string: + if binary_output: + output_lines = [output_string] + else: + if output_string[-1] != "\n": + output_string = output_string + "\n" + output_lines = output_string.splitlines(True) + + if log_output: + with program_log_lock: + for line in output_lines: + program_log.info(line.strip()) + + if stdout: + stdout.write(output_string) + + # If stderr was filtered, log it separately + if filter_stderr and err_string and log_output: + err_lines = err_string.splitlines(True) + + with program_log_lock: + for line in err_lines: + program_log.info(line.strip()) + + except OSError as e: + with program_log_lock: + program_log.error("Error running %s: %s", argv[0], e.strerror) + raise + + with program_log_lock: + program_log.debug("Return code: %s", proc.returncode) + + if proc.returncode and raise_err: + output = (output_string or "") + (err_string or "") + raise subprocess.CalledProcessError(proc.returncode, argv, output) + + return (proc.returncode, output_string) + +
    [docs]def execWithRedirect(command, argv, stdin=None, stdout=None, root='/', env_prune=None, + log_output=True, binary_output=False, raise_err=False, callback=None, + env_add=None, reset_handlers=True, reset_lang=True): + """ Run an external program and redirect the output to a file. + + :param command: The command to run + :param argv: The argument list + :param stdin: The file object to read stdin from. + :param stdout: Optional file object to redirect stdout and stderr to. + :param root: The directory to chroot to before running command. + :param env_prune: environment variable to remove before execution + :param log_output: whether to log the output of command + :param binary_output: whether to treat the output of command as binary data + :param raise_err: whether to raise a CalledProcessError if the returncode is non-zero + :param callback: method to call while waiting for process to finish, passed Popen object + :param env_add: environment variables to add before execution + :param reset_handlers: whether to reset to SIG_DFL any signal handlers set to SIG_IGN + :param reset_lang: whether to set the locale of the child process to C + :return: The return code of the command + """ + argv = [command] + list(argv) + return _run_program(argv, stdin=stdin, stdout=stdout, root=root, env_prune=env_prune, + log_output=log_output, binary_output=binary_output, raise_err=raise_err, callback=callback, + env_add=env_add, reset_handlers=reset_handlers, reset_lang=reset_lang)[0]
    + +
    [docs]def execWithCapture(command, argv, stdin=None, root='/', log_output=True, filter_stderr=False, + raise_err=False, callback=None, env_add=None, reset_handlers=True, reset_lang=True): + """ Run an external program and capture standard out and err. + + :param command: The command to run + :param argv: The argument list + :param stdin: The file object to read stdin from. + :param root: The directory to chroot to before running command. + :param log_output: Whether to log the output of command + :param filter_stderr: Whether stderr should be excluded from the returned output + :param callback: method to call while waiting for process to finish, passed Popen object + :param env_add: environment variables to add before execution + :param reset_handlers: whether to reset to SIG_DFL any signal handlers set to SIG_IGN + :param reset_lang: whether to set the locale of the child process to C + :return: The output of the command + """ + argv = [command] + list(argv) + return _run_program(argv, stdin=stdin, root=root, log_output=log_output, filter_stderr=filter_stderr, + raise_err=raise_err, callback=callback, env_add=env_add, + reset_handlers=reset_handlers, reset_lang=reset_lang)[1]
    + +
    [docs]def execReadlines(command, argv, stdin=None, root='/', env_prune=None, filter_stderr=False, + callback=lambda x: True, env_add=None, reset_handlers=True, reset_lang=True): + """ Execute an external command and return the line output of the command + in real-time. + + This method assumes that there is a reasonably low delay between the + end of output and the process exiting. If the child process closes + stdout and then keeps on truckin' there will be problems. + + NOTE/WARNING: UnicodeDecodeError will be raised if the output of the + external command can't be decoded as UTF-8. + + :param command: The command to run + :param argv: The argument list + :param stdin: The file object to read stdin from. + :param stdout: Optional file object to redirect stdout and stderr to. + :param root: The directory to chroot to before running command. + :param env_prune: environment variable to remove before execution + :param filter_stderr: Whether stderr should be excluded from the returned output + :param callback: method to call while waiting for process to finish, passed Popen object + :param env_add: environment variables to add before execution + :param reset_handlers: whether to reset to SIG_DFL any signal handlers set to SIG_IGN + :param reset_lang: whether to set the locale of the child process to C + :return: Iterator of the lines from the command + + Output from the file is not logged to program.log + This returns an iterator with the lines from the command until it has finished + """ + + class ExecLineReader(object): + """Iterator class for returning lines from a process and cleaning + up the process when the output is no longer needed. + """ + + def __init__(self, proc, argv, callback): + self._proc = proc + self._argv = argv + self._callback = callback + + def __iter__(self): + return self + + def __del__(self): + # See if the process is still running + if self._proc.poll() is None: + # Stop the process and ignore any problems that might arise + try: + self._proc.terminate() + except OSError: + pass + + def __next__(self): + # Read the next line, blocking if a line is not yet available + line = self._proc.stdout.readline().decode("utf-8") + if line == '' or not self._callback(self._proc): + # Output finished, wait for the process to end + self._proc.communicate() + + # Check for successful exit + if self._proc.returncode < 0: + raise OSError("process '%s' was killed by signal %s" % + (self._argv, -self._proc.returncode)) + elif self._proc.returncode > 0: + raise OSError("process '%s' exited with status %s" % + (self._argv, self._proc.returncode)) + raise StopIteration + + return line.strip() + + argv = [command] + argv + + if filter_stderr: + stderr = subprocess.DEVNULL + else: + stderr = subprocess.STDOUT + + try: + proc = startProgram(argv, root=root, stdin=stdin, stdout=subprocess.PIPE, stderr=stderr, + env_prune=env_prune, env_add=env_add, reset_handlers=reset_handlers, reset_lang=reset_lang) + except OSError as e: + with program_log_lock: + program_log.error("Error running %s: %s", argv[0], e.strerror) + raise + + return ExecLineReader(proc, argv, callback)
    + +
    [docs]def runcmd(cmd, **kwargs): + """ run execWithRedirect with raise_err=True + """ + kwargs["raise_err"] = True + return execWithRedirect(cmd[0], cmd[1:], **kwargs)
    + +
    [docs]def runcmd_output(cmd, **kwargs): + """ run execWithCapture with raise_err=True + """ + kwargs["raise_err"] = True + return execWithCapture(cmd[0], cmd[1:], **kwargs)
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/imgutils.html b/f32-branch/_modules/pylorax/imgutils.html new file mode 100644 index 00000000..849dfcc6 --- /dev/null +++ b/f32-branch/_modules/pylorax/imgutils.html @@ -0,0 +1,755 @@ + + + + + + + + + + + pylorax.imgutils — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.imgutils

    +# imgutils.py - utility functions/classes for building disk images
    +#
    +# Copyright (C) 2011-2018 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author(s):  Will Woods <wwoods@redhat.com>
    +
    +import logging
    +logger = logging.getLogger("pylorax.imgutils")
    +
    +import os, tempfile
    +from os.path import join, dirname
    +from subprocess import Popen, PIPE, CalledProcessError
    +import sys
    +import time
    +import traceback
    +import multiprocessing
    +from time import sleep
    +import shutil
    +
    +from pylorax.sysutils import cpfile
    +from pylorax.executils import execWithRedirect, execWithCapture
    +from pylorax.executils import runcmd, runcmd_output
    +
    +######## Functions for making container images (cpio, tar, squashfs) ##########
    +
    +
    [docs]def compress(command, root, outfile, compression="xz", compressargs=None): + '''Make a compressed archive of the given rootdir or file. + command is a list of the archiver commands to run + compression should be "xz", "gzip", "lzma", "bzip2", or None. + compressargs will be used on the compression commandline.''' + if compression not in (None, "xz", "gzip", "lzma", "bzip2"): + raise ValueError("Unknown compression type %s" % compression) + compressargs = compressargs or ["-9"] + if compression == "xz": + compressargs.insert(0, "--check=crc32") + if compression is None: + compression = "cat" # this is a little silly + compressargs = [] + + # make compression run with multiple threads if possible + if compression in ("xz", "lzma"): + compressargs.insert(0, "-T%d" % multiprocessing.cpu_count()) + elif compression == "gzip": + compression = "pigz" + compressargs.insert(0, "-p%d" % multiprocessing.cpu_count()) + elif compression == "bzip2": + compression = "pbzip2" + compressargs.insert(0, "-p%d" % multiprocessing.cpu_count()) + + find, archive, comp = None, None, None + + try: + if os.path.isdir(root): + logger.debug("find %s -print0 |%s | %s %s > %s", root, " ".join(command), + compression, " ".join(compressargs), outfile) + + find = Popen(["find", ".", "-print0"], stdout=PIPE, cwd=root) + archive = Popen(command, stdin=find.stdout, stdout=PIPE, cwd=root) + else: + logger.debug("echo %s |%s | %s %s > %s", root, " ".join(command), + compression, " ".join(compressargs), outfile) + + archive = Popen(command, stdin=PIPE, stdout=PIPE, cwd=os.path.dirname(root)) + archive.stdin.write(os.path.basename(root).encode("utf-8") + b"\0") + archive.stdin.close() + + comp = Popen([compression] + compressargs, + stdin=archive.stdout, stdout=open(outfile, "wb")) + comp.wait() + return comp.returncode + except OSError as e: + logger.error(e) + # Kill off any hanging processes + list(p.kill() for p in (find, archive, comp) if p) + return 1
    + +
    [docs]def mkcpio(root, outfile, compression="xz", compressargs=None): + compressargs = compressargs or ["-9"] + return compress(["cpio", "--null", "--quiet", "-H", "newc", "-o"], + root, outfile, compression, compressargs)
    + +
    [docs]def mktar(root, outfile, compression="xz", compressargs=None, selinux=True): + compressargs = compressargs or ["-9"] + tar_cmd = ["tar", "--no-recursion"] + if selinux: + tar_cmd += ["--selinux", "--acls", "--xattrs"] + tar_cmd += ["-cf-", "--null", "-T-"] + return compress(tar_cmd, root, outfile, compression, compressargs)
    + +
    [docs]def mksquashfs(rootdir, outfile, compression="default", compressargs=None): + '''Make a squashfs image containing the given rootdir.''' + compressargs = compressargs or [] + if compression != "default": + compressargs = ["-comp", compression] + compressargs + return execWithRedirect("mksquashfs", [rootdir, outfile] + compressargs)
    + +
    [docs]def mkrootfsimg(rootdir, outfile, label, size=2, sysroot=""): + """ + Make rootfs image from a directory + + :param str rootdir: Root directory + :param str outfile: Path of output image file + :param str label: Filesystem label + :param int size: Size of the image in GiB, if None computed automatically + :param str sysroot: path to system (deployment) root relative to physical root + """ + if size: + fssize = size * (1024*1024*1024) # 2GB sparse file compresses down to nothin' + else: + fssize = None # Let mkext4img figure out the needed size + + mkext4img(rootdir, outfile, label=label, size=fssize)
    + + +######## Utility functions ############################################### + +
    [docs]def mksparse(outfile, size): + '''use os.ftruncate to create a sparse file of the given size.''' + fobj = open(outfile, "w") + os.ftruncate(fobj.fileno(), size)
    + +
    [docs]def mkqcow2(outfile, size, options=None): + '''use qemu-img to create a file of the given size. + options is a list of options passed to qemu-img + + Default format is qcow2, override by passing "-f", fmt + in options. + ''' + mkqemu_img(outfile, size, options)
    + +
    [docs]def mkqemu_img(outfile, size, options=None): + '''use qemu-img to create a file of the given size. + options is a list of options passed to qemu-img + + Default format is qcow2, override by passing "-f", fmt + in options. + ''' + options = options or [] + if "-f" not in options: + options.extend(["-f", "qcow2"]) + runcmd(["qemu-img", "create"] + options + [outfile, str(size)])
    + +
    [docs]def loop_waitfor(loop_dev, outfile): + """Make sure the loop device is attached to the outfile. + + It seems that on rare occasions losetup can return before the /dev/loopX is + ready for use, causing problems with mkfs. This tries to make sure that the + loop device really is associated with the backing file before continuing. + + Raise RuntimeError if it isn't setup after 5 tries. + """ + for _x in range(0,5): + runcmd(["udevadm", "settle", "--timeout", "300"]) + ## XXX Note that losetup --list output can be truncated to 64 bytes in some + ## situations. Don't use it to lookup backing file, go the other way + ## and lookup the loop for the backing file. See util-linux lib/loopdev.c + ## loopcxt_get_backing_file() + if get_loop_name(outfile) == os.path.basename(loop_dev): + return + + # If this really is a race, give it some time to settle down + time.sleep(1) + + raise RuntimeError("Unable to setup %s on %s" % (loop_dev, outfile))
    + +
    [docs]def loop_attach(outfile): + """Attach a loop device to the given file. Return the loop device name. + + On rare occasions it appears that the device never shows up, some experiments + seem to indicate that it may be a race with another process using /dev/loop* devices. + + So we now try 3 times before actually failing. + + Raises CalledProcessError if losetup fails. + """ + retries = 0 + while True: + try: + retries += 1 + dev = runcmd_output(["losetup", "--find", "--show", outfile]).strip() + + # Sometimes the loop device isn't ready yet, make extra sure before returning + loop_waitfor(dev, outfile) + except RuntimeError: + # Try to setup the loop device 3 times + if retries == 3: + logger.error("loop_attach failed, retries exhausted.") + raise + logger.debug("Try %d failed, %s did not appear.", retries, dev) + break + return dev
    + +
    [docs]def loop_detach(loopdev): + '''Detach the given loop device. Return False on failure.''' + return (execWithRedirect("losetup", ["--detach", loopdev]) == 0)
    + +
    [docs]def get_loop_name(path): + '''Return the loop device associated with the path. + Raises RuntimeError if more than one loop is associated''' + buf = runcmd_output(["losetup", "-j", path]) + if len(buf.splitlines()) > 1: + # there should never be more than one loop device listed + raise RuntimeError("multiple loops associated with %s" % path) + name = os.path.basename(buf.split(":")[0]) + return name
    + +
    [docs]def dm_attach(dev, size, name=None): + '''Attach a devicemapper device to the given device, with the given size. + If name is None, a random name will be chosen. Returns the device name. + raises CalledProcessError if dmsetup fails.''' + if name is None: + name = tempfile.mktemp(prefix="lorax.imgutils.", dir="") + runcmd(["dmsetup", "create", name, "--table", + "0 %i linear %s 0" % (size/512, dev)]) + return name
    + +
    [docs]def dm_detach(dev): + '''Detach the named devicemapper device. Returns False if dmsetup fails.''' + dev = dev.replace("/dev/mapper/", "") # strip prefix, if it's there + return execWithRedirect("dmsetup", ["remove", dev])
    + +
    [docs]def mount(dev, opts="", mnt=None): + '''Mount the given device at the given mountpoint, using the given opts. + opts should be a comma-separated string of mount options. + if mnt is none, a temporary directory will be created and its path will be + returned. + raises CalledProcessError if mount fails.''' + if mnt is None: + mnt = tempfile.mkdtemp(prefix="lorax.imgutils.") + logger.debug("make tmp mountdir %s", mnt) + cmd = ["mount"] + if opts: + cmd += ["-o", opts] + cmd += [dev, mnt] + runcmd(cmd) + return mnt
    + +
    [docs]def umount(mnt, lazy=False, maxretry=3, retrysleep=1.0, delete=True): + '''Unmount the given mountpoint. If lazy is True, do a lazy umount (-l). + If the mount was a temporary dir created by mount, it will be deleted. + raises CalledProcessError if umount fails.''' + cmd = ["umount"] + if lazy: cmd += ["-l"] + cmd += [mnt] + count = 0 + while maxretry > 0: + try: + rv = runcmd(cmd) + except CalledProcessError: + count += 1 + if count == maxretry: + raise + logger.warning("failed to unmount %s. retrying (%d/%d)...", + mnt, count, maxretry) + if logger.getEffectiveLevel() <= logging.DEBUG: + fuser = execWithCapture("fuser", ["-vm", mnt]) + logger.debug("fuser -vm:\n%s\n", fuser) + sleep(retrysleep) + else: + break + if delete and 'lorax.imgutils' in mnt: + os.rmdir(mnt) + logger.debug("remove tmp mountdir %s", mnt) + return (rv == 0)
    + +
    [docs]def copytree(src, dest, preserve=True): + '''Copy a tree of files using cp -a, thus preserving modes, timestamps, + links, acls, sparse files, xattrs, selinux contexts, etc. + If preserve is False, uses cp -R (useful for modeless filesystems) + raises CalledProcessError if copy fails.''' + logger.debug("copytree %s %s", src, dest) + cp = ["cp", "-a"] if preserve else ["cp", "-R", "-L", "--preserve=timestamps"] + cp += [join(src, "."), os.path.abspath(dest)] + runcmd(cp)
    + +
    [docs]def do_grafts(grafts, dest, preserve=True): + '''Copy each of the items listed in grafts into dest. + If the key ends with '/' it's assumed to be a directory which should be + created, otherwise just the leading directories will be created.''' + for imgpath, filename in grafts.items(): + if imgpath[-1] == '/': + targetdir = join(dest, imgpath) + imgpath = imgpath[:-1] + else: + targetdir = join(dest, dirname(imgpath)) + if not os.path.isdir(targetdir): + os.makedirs(targetdir) + if os.path.isdir(filename): + copytree(filename, join(dest, imgpath), preserve) + else: + cpfile(filename, join(dest, imgpath))
    + +
    [docs]def round_to_blocks(size, blocksize): + '''If size isn't a multiple of blocksize, round up to the next multiple''' + diff = size % blocksize + if diff or not size: + size += blocksize - diff + return size
    + +# TODO: move filesystem data outside this function +
    [docs]def estimate_size(rootdir, graft=None, fstype=None, blocksize=4096, overhead=256): + graft = graft or {} + getsize = lambda f: os.lstat(f).st_size + if fstype == "btrfs": + overhead = 64*1024 # don't worry, it's all sparse + if fstype == "hfsplus": + overhead = 200 # hack to deal with two bootloader copies + if fstype in ("vfat", "msdos"): + blocksize = 2048 + getsize = lambda f: os.stat(f).st_size # no symlinks, count as copies + total = overhead*blocksize + dirlist = list(graft.values()) + if rootdir: + dirlist.append(rootdir) + for root in dirlist: + for top, dirs, files in os.walk(root): + for f in files + dirs: + total += round_to_blocks(getsize(join(top,f)), blocksize) + if fstype == "btrfs": + total = max(256*1024*1024, total) # btrfs minimum size: 256MB + logger.info("Size of %s block %s fs at %s estimated to be %s", blocksize, fstype, rootdir, total) + return total
    + +######## Execution contexts - use with the 'with' statement ############## + +
    [docs]class LoopDev(object): + def __init__(self, filename, size=None): + self.loopdev = None + self.filename = filename + if size: + mksparse(self.filename, size) + def __enter__(self): + self.loopdev = loop_attach(self.filename) + return self.loopdev + def __exit__(self, exc_type, exc_value, tracebk): + loop_detach(self.loopdev)
    + +
    [docs]class DMDev(object): + def __init__(self, dev, size, name=None): + self.mapperdev = None + (self.dev, self.size, self.name) = (dev, size, name) + def __enter__(self): + self.mapperdev = dm_attach(self.dev, self.size, self.name) + return self.mapperdev + def __exit__(self, exc_type, exc_value, tracebk): + dm_detach(self.mapperdev)
    + +
    [docs]class Mount(object): + def __init__(self, dev, opts="", mnt=None): + (self.dev, self.opts, self.mnt) = (dev, opts, mnt) + def __enter__(self): + self.mnt = mount(self.dev, self.opts, self.mnt) + return self.mnt + def __exit__(self, exc_type, exc_value, tracebk): + umount(self.mnt)
    + +
    [docs]def kpartx_disk_img(disk_img): + """Attach a disk image's partitions to /dev/loopX using kpartx + + :param disk_img: The full path to a partitioned disk image + :type disk_img: str + :returns: list of (loopXpN, size) + :rtype: list of tuples + """ + # Example kpartx output + # kpartx -p p -v -a /tmp/diskV2DiCW.im + # add map loop2p1 (253:2): 0 3481600 linear /dev/loop2 2048 + # add map loop2p2 (253:3): 0 614400 linear /dev/loop2 3483648 + kpartx_output = runcmd_output(["kpartx", "-v", "-a", "-s", disk_img]) + logger.debug(kpartx_output) + + # list of (deviceName, sizeInBytes) + loop_devices = [] + for line in kpartx_output.splitlines(): + # add map loop2p3 (253:4): 0 7139328 linear /dev/loop2 528384 + # 3rd element is size in 512 byte blocks + if line.startswith("add map "): + fields = line[8:].split() + loop_devices.append( (fields[0], int(fields[3])*512) ) + return loop_devices
    + +
    [docs]class PartitionMount(object): + """ Mount a partitioned image file using kpartx """ + def __init__(self, disk_img, mount_ok=None, submount=None): + """ + :param str disk_img: The full path to a partitioned disk image + :param mount_ok: A function that is passed the mount point and + returns True if it should be mounted. + :param str submount: Directory inside mount_dir to mount at + + If mount_ok is not set it will look for /etc/passwd + + If the partition is found it will be mounted under a temporary + directory and self.temp_dir set to it. If submount is passed it will be + created and mounted there instead, with self.mount_dir set to point to + it. self.mount_dev is set to the loop device, and self.mount_size is + set to the size of the partition. + + When no subdir is passed self.temp_dir and self.mount_dir will be the same. + """ + self.mount_dev = None + self.mount_size = None + self.mount_dir = None + self.disk_img = disk_img + self.mount_ok = mount_ok + self.submount = submount + self.temp_dir = None + + # Default is to mount partition with /etc/passwd + if not self.mount_ok: + self.mount_ok = lambda mount_dir: os.path.isfile(mount_dir+"/etc/passwd") + + # list of (deviceName, sizeInBytes) + self.loop_devices = kpartx_disk_img(self.disk_img) + + def __enter__(self): + # Mount the device selected by mount_ok, if possible + self.temp_dir = tempfile.mkdtemp() + if self.submount: + mount_dir = os.path.normpath(os.path.sep.join([self.temp_dir, self.submount])) + os.makedirs(mount_dir, mode=0o755, exist_ok=True) + else: + mount_dir = self.temp_dir + for dev, size in self.loop_devices: + try: + mount( "/dev/mapper/"+dev, mnt=mount_dir ) + if self.mount_ok(mount_dir): + self.mount_dir = mount_dir + self.mount_dev = dev + self.mount_size = size + break + umount( mount_dir ) + except CalledProcessError: + logger.debug(traceback.format_exc()) + if self.mount_dir: + logger.info("Partition mounted on %s size=%s", self.mount_dir, self.mount_size) + else: + logger.debug("Unable to mount anything from %s", self.disk_img) + os.rmdir(self.temp_dir) + self.temp_dir = None + return self + + def __exit__(self, exc_type, exc_value, tracebk): + if self.temp_dir: + umount(self.mount_dir) + shutil.rmtree(self.temp_dir) + self.mount_dir = None + self.temp_dir = None + execWithRedirect("kpartx", ["-d", "-s", self.disk_img])
    + + +######## Functions for making filesystem images ########################## + +
    [docs]def mkfsimage(fstype, rootdir, outfile, size=None, mkfsargs=None, mountargs="", graft=None): + '''Generic filesystem image creation function. + fstype should be a filesystem type - "mkfs.${fstype}" must exist. + graft should be a dict: {"some/path/in/image": "local/file/or/dir"}; + if the path ends with a '/' it's assumed to be a directory. + Will raise CalledProcessError if something goes wrong.''' + mkfsargs = mkfsargs or [] + graft = graft or {} + preserve = (fstype not in ("msdos", "vfat")) + if not size: + size = estimate_size(rootdir, graft, fstype) + with LoopDev(outfile, size) as loopdev: + try: + runcmd(["mkfs.%s" % fstype] + mkfsargs + [loopdev]) + except CalledProcessError as e: + logger.error("mkfs exited with a non-zero return code: %d", e.returncode) + logger.error(e.output) + sys.exit(e.returncode) + + with Mount(loopdev, mountargs) as mnt: + if rootdir: + copytree(rootdir, mnt, preserve) + do_grafts(graft, mnt, preserve) + + # Save information about filesystem usage + execWithRedirect("df", [mnt]) + + # Make absolutely sure that the data has been written + runcmd(["sync"])
    + +# convenience functions with useful defaults +
    [docs]def mkdosimg(rootdir, outfile, size=None, label="", mountargs="shortname=winnt,umask=0077", graft=None): + graft = graft or {} + mkfsargs = ["-n", label] + if 'SOURCE_DATE_EPOCH' in os.environ: + mkfsargs.extend(["-i", + "{:x}".format(int(os.environ['SOURCE_DATE_EPOCH']))]) + mkfsimage("msdos", rootdir, outfile, size, mountargs=mountargs, + mkfsargs=mkfsargs, graft=graft)
    + +
    [docs]def mkext4img(rootdir, outfile, size=None, label="", mountargs="", graft=None): + graft = graft or {} + mkfsimage("ext4", rootdir, outfile, size, mountargs=mountargs, + mkfsargs=["-L", label, "-b", "4096", "-m", "0"], graft=graft)
    + +
    [docs]def mkbtrfsimg(rootdir, outfile, size=None, label="", mountargs="", graft=None): + graft = graft or {} + mkfsimage("btrfs", rootdir, outfile, size, mountargs=mountargs, + mkfsargs=["-L", label], graft=graft)
    + +
    [docs]def mkhfsimg(rootdir, outfile, size=None, label="", mountargs="", graft=None): + graft = graft or {} + mkfsimage("hfsplus", rootdir, outfile, size, mountargs=mountargs, + mkfsargs=["-v", label], graft=graft)
    + +
    [docs]def mkfsimage_from_disk(diskimage, fsimage, img_size=None, label="Anaconda"): + """ + Copy the / partition of a partitioned disk image to an un-partitioned + disk image. + + :param str diskimage: The full path to partitioned disk image with a / + :param str fsimage: The full path of the output fs image file + :param int img_size: Optional size of the fsimage in MiB or None to make + it as small as possible + :param str label: The label to apply to the image. Defaults to "Anaconda" + """ + with PartitionMount(diskimage) as img_mount: + if not img_mount or not img_mount.mount_dir: + return None + + logger.info("Creating fsimage %s (%s)", fsimage, img_size or "minimized") + if img_size: + # convert to Bytes + img_size *= 1024**2 + + mkext4img(img_mount.mount_dir, fsimage, size=img_size, label=label)
    + +
    [docs]def default_image_name(compression, basename): + """ Return a default image name with the correct suffix for the compression type. + + :param str compression: Compression type + :param str basename: Base filename + :returns: basename with compression suffix + + If the compression is unknown it defaults to xz + """ + SUFFIXES = {"xz": ".xz", "gzip": ".gz", "bzip2": ".bz2", "lzma": ".lzma"} + return basename + SUFFIXES.get(compression, ".xz")
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/installer.html b/f32-branch/_modules/pylorax/installer.html new file mode 100644 index 00000000..0db2ecc6 --- /dev/null +++ b/f32-branch/_modules/pylorax/installer.html @@ -0,0 +1,879 @@ + + + + + + + + + + + pylorax.installer — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.installer

    +#
    +# Copyright (C) 2011-2018  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +import logging
    +log = logging.getLogger("pylorax")
    +
    +import glob
    +import json
    +from math import ceil
    +import os
    +import subprocess
    +import shutil
    +import socket
    +import tempfile
    +
    +# Use the Lorax treebuilder branch for iso creation
    +from pylorax.executils import execWithRedirect, execReadlines
    +from pylorax.imgutils import PartitionMount, mksparse, mkext4img, loop_detach
    +from pylorax.imgutils import get_loop_name, dm_detach, mount, umount
    +from pylorax.imgutils import mkqemu_img, mktar, mkcpio, mkfsimage_from_disk
    +from pylorax.monitor import LogMonitor
    +from pylorax.mount import IsoMountpoint
    +from pylorax.sysutils import joinpaths
    +from pylorax.treebuilder import udev_escape
    +
    +
    +ROOT_PATH = "/mnt/sysimage/"
    +
    +
    [docs]class InstallError(Exception): + pass
    + + +
    [docs]def create_vagrant_metadata(path, size=0): + """ Create a default Vagrant metadata.json file + + :param str path: Path to metadata.json file + :param int size: Disk size in MiB + """ + metadata = { "provider":"libvirt", "format":"qcow2", "virtual_size": ceil(size / 1024) } + with open(path, "wt") as f: + json.dump(metadata, f, indent=4)
    + + +
    [docs]def update_vagrant_metadata(path, size): + """ Update the Vagrant metadata.json file + + :param str path: Path to metadata.json file + :param int size: Disk size in MiB + + This function makes sure that the provider, format and virtual size of the + metadata file are set correctly. All other values are left untouched. + """ + with open(path, "rt") as f: + try: + metadata = json.load(f) + except ValueError as e: + log.error("Problem reading metadata file %s: %s", path, e) + return + + metadata["provider"] = "libvirt" + metadata["format"] = "qcow2" + metadata["virtual_size"] = ceil(size / 1024) + with open(path, "wt") as f: + json.dump(metadata, f, indent=4)
    + + +
    [docs]def find_free_port(start=5900, end=5999, host="127.0.0.1"): + """ Return first free port in range. + + :param int start: Starting port number + :param int end: Ending port number + :param str host: Host IP to search + :returns: First free port or -1 if none found + :rtype: int + """ + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + for port in range(start, end+1): + try: + s.bind((host, port)) + s.close() + return port + except OSError: + pass + + return -1
    + +
    [docs]def append_initrd(initrd, files): + """ Append files to an initrd. + + :param str initrd: Path to initrd + :param list files: list of file paths to add + :returns: Path to a new initrd + :rtype: str + + The files are added to the initrd by creating a cpio image + of the files (stored at /) and writing the cpio to the end of a + copy of the initrd. + + The initrd is not changed, a copy is made before appending the + cpio archive. + """ + qemu_initrd = tempfile.mktemp(prefix="lmc-initrd-", suffix=".img") + shutil.copy2(initrd, qemu_initrd) + ks_dir = tempfile.mkdtemp(prefix="lmc-ksdir-") + for ks in files: + shutil.copy2(ks, ks_dir) + ks_initrd = tempfile.mktemp(prefix="lmc-ks-", suffix=".img") + mkcpio(ks_dir, ks_initrd) + shutil.rmtree(ks_dir) + with open(qemu_initrd, "ab") as initrd_fp: + with open(ks_initrd, "rb") as ks_fp: + while True: + data = ks_fp.read(1024**2) + if not data: + break + initrd_fp.write(data) + os.unlink(ks_initrd) + + return qemu_initrd
    + +
    [docs]class QEMUInstall(object): + """ + Run qemu using an iso and a kickstart + """ + # Mapping of arch to qemu command + QEMU_CMDS = {"x86_64": "qemu-system-x86_64", + "i386": "qemu-system-i386", + "arm": "qemu-system-arm", + "aarch64": "qemu-system-aarch64", + "ppc64le": "qemu-system-ppc64" + } + + def __init__(self, opts, iso, ks_paths, disk_img, img_size=2048, + kernel_args=None, memory=1024, vcpus=None, vnc=None, arch=None, + cancel_func=None, virtio_host="127.0.0.1", virtio_port=6080, + image_type=None, boot_uefi=False, ovmf_path=None): + """ + Start the installation + + :param iso: Information about the iso to use for the installation + :type iso: IsoMountpoint + :param list ks_paths: Paths to kickstart files. All are injected, the + first one is the one executed. + :param str disk_img: Path to a disk image, created it it doesn't exist + :param int img_size: The image size, in MiB, to create if it doesn't exist + :param str kernel_args: Extra kernel arguments to pass on the kernel cmdline + :param int memory: Amount of RAM to assign to the virt, in MiB + :param int vcpus: Number of virtual cpus + :param str vnc: Arguments to pass to qemu -display + :param str arch: Optional architecture to use in the virt + :param cancel_func: Function that returns True if the installation fails + :type cancel_func: function + :param str virtio_host: Hostname to connect virtio log to + :param int virtio_port: Port to connect virtio log to + :param str image_type: Type of qemu-img disk to create, or None. + :param bool boot_uefi: Use OVMF to boot the VM in UEFI mode + :param str ovmf_path: Path to the OVMF firmware + """ + # Lookup qemu-system- for arch if passed, or try to guess using host arch + qemu_cmd = [self.QEMU_CMDS.get(arch or os.uname().machine, "qemu-system-"+os.uname().machine)] + if not os.path.exists("/usr/bin/"+qemu_cmd[0]): + raise InstallError("%s does not exist, cannot run qemu" % qemu_cmd[0]) + + qemu_cmd += ["-no-user-config"] + qemu_cmd += ["-m", str(memory)] + if vcpus: + qemu_cmd += ["-smp", str(vcpus)] + + if not opts.no_kvm and os.path.exists("/dev/kvm"): + qemu_cmd += ["-machine", "accel=kvm"] + + if boot_uefi: + qemu_cmd += ["-machine", "q35,smm=on"] + qemu_cmd += ["-global", "driver=cfi.pflash01,property=secure,value=on"] + + # Copy the initrd from the iso, create a cpio archive of the kickstart files + # and append it to the temporary initrd. + qemu_initrd = append_initrd(iso.initrd, ks_paths) + qemu_cmd += ["-kernel", iso.kernel] + qemu_cmd += ["-initrd", qemu_initrd] + + # Add the disk and cdrom + if not os.path.isfile(disk_img): + mksparse(disk_img, img_size * 1024**2) + drive_args = "file=%s" % disk_img + drive_args += ",cache=unsafe,discard=unmap" + if image_type: + drive_args += ",format=%s" % image_type + else: + drive_args += ",format=raw" + qemu_cmd += ["-drive", drive_args] + + drive_args = "file=%s,media=cdrom,readonly=on" % iso.iso_path + qemu_cmd += ["-drive", drive_args] + + # Setup the cmdline args + # ====================== + cmdline_args = "ks=file:/%s" % os.path.basename(ks_paths[0]) + cmdline_args += " inst.stage2=hd:LABEL=%s" % udev_escape(iso.label) + if opts.proxy: + cmdline_args += " inst.proxy=%s" % opts.proxy + if kernel_args: + cmdline_args += " "+kernel_args + cmdline_args += " inst.text inst.cmdline" + + qemu_cmd += ["-append", cmdline_args] + + if not opts.vnc: + vnc_port = find_free_port() + if vnc_port == -1: + raise InstallError("No free VNC ports") + display_args = "vnc=127.0.0.1:%d" % (vnc_port - 5900) + else: + display_args = opts.vnc + log.info("qemu %s", display_args) + qemu_cmd += ["-nographic", "-monitor", "none", "-serial", "null", "-display", display_args ] + + # Setup the virtio log port + qemu_cmd += ["-device", "virtio-serial-pci,id=virtio-serial0"] + qemu_cmd += ["-device", "virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0" + ",id=channel0,name=org.fedoraproject.anaconda.log.0"] + qemu_cmd += ["-chardev", "socket,id=charchannel0,host=%s,port=%s" % (virtio_host, virtio_port)] + + # Pass through rng from host + if opts.with_rng != "none": + qemu_cmd += ["-object", "rng-random,id=virtio-rng0,filename=%s" % opts.with_rng] + if boot_uefi: + qemu_cmd += ["-device", "virtio-rng-pci,rng=virtio-rng0,id=rng0,bus=pcie.0,addr=0x9"] + else: + qemu_cmd += ["-device", "virtio-rng-pci,rng=virtio-rng0,id=rng0,bus=pci.0,addr=0x9"] + + if boot_uefi and ovmf_path: + qemu_cmd += ["-drive", "file=%s/OVMF_CODE.secboot.fd,if=pflash,format=raw,unit=0,readonly=on" % ovmf_path] + + # Make a copy of the OVMF_VARS.secboot.fd for this run + ovmf_vars = tempfile.mktemp(prefix="lmc-OVMF_VARS-", suffix=".fd") + shutil.copy2(joinpaths(ovmf_path, "/OVMF_VARS.secboot.fd"), ovmf_vars) + + qemu_cmd += ["-drive", "file=%s,if=pflash,format=raw,unit=1" % ovmf_vars] + + log.info("Running qemu") + log.debug(qemu_cmd) + try: + execWithRedirect(qemu_cmd[0], qemu_cmd[1:], reset_lang=False, raise_err=True, + callback=lambda p: not (cancel_func and cancel_func())) + except subprocess.CalledProcessError as e: + log.error("Running qemu failed:") + log.error("cmd: %s", " ".join(e.cmd)) + log.error("output: %s", e.output or "") + raise InstallError("QEMUInstall failed") + except (OSError, KeyboardInterrupt) as e: + log.error("Running qemu failed: %s", str(e)) + raise InstallError("QEMUInstall failed") + finally: + os.unlink(qemu_initrd) + if boot_uefi and ovmf_path: + os.unlink(ovmf_vars) + + if cancel_func and cancel_func(): + log.error("Installation error detected. See logfile for details.") + raise InstallError("QEMUInstall failed") + else: + log.info("Installation finished without errors.")
    + + +
    [docs]def novirt_cancel_check(cancel_funcs, proc): + """ + Check to see if there has been an error in the logs + + :param cancel_funcs: list of functions to call, True from any one cancels the build + :type cancel_funcs: list + :param proc: Popen object for the anaconda process + :type proc: subprocess.Popen + :returns: True if the process has been terminated + + The cancel_funcs functions should return a True if an error has been detected. + When an error is detected the process is terminated and this returns True + """ + for f in cancel_funcs: + if f(): + proc.terminate() + return True + return False
    + + +
    [docs]def anaconda_cleanup(dirinstall_path): + """ + Cleanup any leftover mounts from anaconda + + :param str dirinstall_path: Path where anaconda mounts things + :returns: True if cleanups were successful. False if any of them failed. + + If anaconda crashes it may leave things mounted under this path. It will + typically be set to /mnt/sysimage/ + + Attempts to cleanup may also fail. Catch these and continue trying the + other mountpoints. + + Anaconda may also leave /run/anaconda.pid behind, clean that up as well. + """ + # Anaconda may not clean up its /var/run/anaconda.pid file + # Make sure the process is really finished (it should be, since it was started from a subprocess call) + # and then remove the pid file. + if os.path.exists("/var/run/anaconda.pid"): + # lorax-composer runs anaconda using unshare so the pid is always 1 + if open("/var/run/anaconda.pid").read().strip() == "1": + os.unlink("/var/run/anaconda.pid") + + rc = True + dirinstall_path = os.path.abspath(dirinstall_path) + # unmount filesystems + for mounted in reversed(open("/proc/mounts").readlines()): + (_device, mountpoint, _rest) = mounted.split(" ", 2) + if mountpoint.startswith(dirinstall_path) and os.path.ismount(mountpoint): + try: + umount(mountpoint) + except subprocess.CalledProcessError: + log.error("Cleanup of %s failed. See program.log for details", mountpoint) + rc = False + return rc
    + + +
    [docs]def novirt_install(opts, disk_img, disk_size, cancel_func=None, tar_img=None): + """ + Use Anaconda to install to a disk image + + :param opts: options passed to livemedia-creator + :type opts: argparse options + :param str disk_img: The full path to the disk image to be created + :param int disk_size: The size of the disk_img in MiB + :param cancel_func: Function that returns True to cancel build + :type cancel_func: function + :param str tar_img: For make_tar_disk, the path to final tarball to be created + + This method runs anaconda to create the image and then based on the opts + passed creates a qemu disk image or tarfile. + """ + dirinstall_path = ROOT_PATH + + # Clean up /tmp/ from previous runs to prevent stale info from being used + for path in ["/tmp/yum.repos.d/", "/tmp/yum.cache/"]: + if os.path.isdir(path): + shutil.rmtree(path) + + args = ["--kickstart", opts.ks[0], "--cmdline", "--loglevel", "debug"] + if opts.anaconda_args: + for arg in opts.anaconda_args: + args += arg.split(" ", 1) + if opts.proxy: + args += ["--proxy", opts.proxy] + if opts.armplatform: + args += ["--armplatform", opts.armplatform] + + if opts.make_iso or opts.make_fsimage or opts.make_pxe_live: + # Make a blank fs image + args += ["--dirinstall"] + + mkext4img(None, disk_img, label=opts.fs_label, size=disk_size * 1024**2) + if not os.path.isdir(dirinstall_path): + os.mkdir(dirinstall_path) + mount(disk_img, opts="loop", mnt=dirinstall_path) + elif opts.make_tar or opts.make_oci: + # Install under dirinstall_path, make sure it starts clean + if os.path.exists(dirinstall_path): + shutil.rmtree(dirinstall_path) + + if opts.make_oci: + # OCI installs under /rootfs/ + dirinstall_path = joinpaths(dirinstall_path, "rootfs") + args += ["--dirinstall", dirinstall_path] + else: + args += ["--dirinstall"] + + os.makedirs(dirinstall_path) + else: + args += ["--image", disk_img] + + # Create the sparse image + mksparse(disk_img, disk_size * 1024**2) + + log_monitor = LogMonitor(timeout=opts.timeout) + args += ["--remotelog", "%s:%s" % (log_monitor.host, log_monitor.port)] + cancel_funcs = [log_monitor.server.log_check] + if cancel_func is not None: + cancel_funcs.append(cancel_func) + + # Make sure anaconda has the right product and release + # Preload libgomp.so.1 to workaround rhbz#1722181 + log.info("Running anaconda.") + try: + unshare_args = [ "--pid", "--kill-child", "--mount", "--propagation", "unchanged", "anaconda" ] + args + for line in execReadlines("unshare", unshare_args, reset_lang=False, + env_add={"ANACONDA_PRODUCTNAME": opts.project, + "ANACONDA_PRODUCTVERSION": opts.releasever, + "LD_PRELOAD": "libgomp.so.1"}, + callback=lambda p: not novirt_cancel_check(cancel_funcs, p)): + log.info(line) + + # Make sure the new filesystem is correctly labeled + setfiles_args = ["-e", "/proc", "-e", "/sys", + "/etc/selinux/targeted/contexts/files/file_contexts", "/"] + + if "--dirinstall" in args: + # setfiles may not be available, warn instead of fail + try: + execWithRedirect("setfiles", setfiles_args, root=dirinstall_path) + except (subprocess.CalledProcessError, OSError) as e: + log.warning("Running setfiles on install tree failed: %s", str(e)) + else: + with PartitionMount(disk_img) as img_mount: + if img_mount and img_mount.mount_dir: + try: + execWithRedirect("setfiles", setfiles_args, root=img_mount.mount_dir) + except (subprocess.CalledProcessError, OSError) as e: + log.warning("Running setfiles on install tree failed: %s", str(e)) + + # For image installs, run fstrim to discard unused blocks. This way + # unused blocks do not need to be allocated for sparse image types + execWithRedirect("fstrim", [img_mount.mount_dir]) + + except (subprocess.CalledProcessError, OSError) as e: + log.error("Running anaconda failed: %s", e) + raise InstallError("novirt_install failed") + finally: + log_monitor.shutdown() + + # Move the anaconda logs over to a log directory + log_dir = os.path.abspath(os.path.dirname(opts.logfile)) + log_anaconda = joinpaths(log_dir, "anaconda") + if not os.path.isdir(log_anaconda): + os.mkdir(log_anaconda) + for l in glob.glob("/tmp/*log")+glob.glob("/tmp/anaconda-tb-*"): + shutil.copy2(l, log_anaconda) + os.unlink(l) + + # Make sure any leftover anaconda mounts have been cleaned up + if not anaconda_cleanup(dirinstall_path): + raise InstallError("novirt_install cleanup of anaconda mounts failed.") + + if not opts.make_iso and not opts.make_fsimage and not opts.make_pxe_live: + dm_name = os.path.splitext(os.path.basename(disk_img))[0] + + # Remove device-mapper for partitions and disk + log.debug("Removing device-mapper setup on %s", dm_name) + for d in sorted(glob.glob("/dev/mapper/"+dm_name+"*"), reverse=True): + dm_detach(d) + + log.debug("Removing loop device for %s", disk_img) + loop_detach("/dev/"+get_loop_name(disk_img)) + + # qemu disk image is used by bare qcow2 images and by Vagrant + if opts.image_type: + log.info("Converting %s to %s", disk_img, opts.image_type) + qemu_args = [] + for arg in opts.qemu_args: + qemu_args += arg.split(" ", 1) + + # convert the image to the selected format + if "-O" not in qemu_args: + qemu_args.extend(["-O", opts.image_type]) + qemu_img = tempfile.mktemp(prefix="lmc-disk-", suffix=".img") + execWithRedirect("qemu-img", ["convert"] + qemu_args + [disk_img, qemu_img], raise_err=True) + if not opts.make_vagrant: + execWithRedirect("mv", ["-f", qemu_img, disk_img], raise_err=True) + else: + # Take the new qcow2 image and package it up for Vagrant + compress_args = [] + for arg in opts.compress_args: + compress_args += arg.split(" ", 1) + + vagrant_dir = tempfile.mkdtemp(prefix="lmc-tmpdir-") + metadata_path = joinpaths(vagrant_dir, "metadata.json") + execWithRedirect("mv", ["-f", qemu_img, joinpaths(vagrant_dir, "box.img")], raise_err=True) + if opts.vagrant_metadata: + shutil.copy2(opts.vagrant_metadata, metadata_path) + else: + create_vagrant_metadata(metadata_path) + update_vagrant_metadata(metadata_path, disk_size) + if opts.vagrantfile: + shutil.copy2(opts.vagrantfile, joinpaths(vagrant_dir, "vagrantfile")) + + log.info("Creating Vagrant image") + rc = mktar(vagrant_dir, disk_img, opts.compression, compress_args, selinux=False) + if rc: + raise InstallError("novirt_install mktar failed: rc=%s" % rc) + shutil.rmtree(vagrant_dir) + elif opts.make_tar: + compress_args = [] + for arg in opts.compress_args: + compress_args += arg.split(" ", 1) + + rc = mktar(dirinstall_path, disk_img, opts.compression, compress_args) + shutil.rmtree(dirinstall_path) + + if rc: + raise InstallError("novirt_install mktar failed: rc=%s" % rc) + elif opts.make_oci: + # An OCI image places the filesystem under /rootfs/ and adds the json files at the top + # And then creates a tar of the whole thing. + compress_args = [] + for arg in opts.compress_args: + compress_args += arg.split(" ", 1) + + shutil.copy2(opts.oci_config, ROOT_PATH) + shutil.copy2(opts.oci_runtime, ROOT_PATH) + rc = mktar(ROOT_PATH, disk_img, opts.compression, compress_args) + + if rc: + raise InstallError("novirt_install mktar failed: rc=%s" % rc) + else: + # For raw disk images, use fallocate to deallocate unused space + execWithRedirect("fallocate", ["--dig-holes", disk_img], raise_err=True) + + # For make_tar_disk, wrap the result in a tar file, and remove the original disk image. + if opts.make_tar_disk: + compress_args = [] + for arg in opts.compress_args: + compress_args += arg.split(" ", 1) + + rc = mktar(disk_img, tar_img, opts.compression, compress_args, selinux=False) + + if rc: + raise InstallError("novirt_install mktar failed: rc=%s" % rc) + + os.unlink(disk_img)
    + +
    [docs]def virt_install(opts, install_log, disk_img, disk_size, cancel_func=None, tar_img=None): + """ + Use qemu to install to a disk image + + :param opts: options passed to livemedia-creator + :type opts: argparse options + :param str install_log: The path to write the log from qemu + :param str disk_img: The full path to the disk image to be created + :param int disk_size: The size of the disk_img in MiB + :param cancel_func: Function that returns True to cancel build + :type cancel_func: function + :param str tar_img: For make_tar_disk, the path to final tarball to be created + + This uses qemu with a boot.iso and a kickstart to create a disk + image and then optionally, based on the opts passed, creates tarfile. + """ + iso_mount = IsoMountpoint(opts.iso, opts.location) + if not iso_mount.stage2: + iso_mount.umount() + raise InstallError("ISO is missing stage2, cannot continue") + + log_monitor = LogMonitor(install_log, timeout=opts.timeout) + cancel_funcs = [log_monitor.server.log_check] + if cancel_func is not None: + cancel_funcs.append(cancel_func) + + kernel_args = "" + if opts.kernel_args: + kernel_args += opts.kernel_args + if opts.proxy: + kernel_args += " proxy="+opts.proxy + + if opts.image_type and not opts.make_fsimage: + qemu_args = [] + for arg in opts.qemu_args: + qemu_args += arg.split(" ", 1) + if "-f" not in qemu_args: + qemu_args += ["-f", opts.image_type] + + mkqemu_img(disk_img, disk_size*1024**2, qemu_args) + + if opts.make_fsimage or opts.make_tar or opts.make_oci: + diskimg_path = tempfile.mktemp(prefix="lmc-disk-", suffix=".img") + else: + diskimg_path = disk_img + + try: + QEMUInstall(opts, iso_mount, opts.ks, diskimg_path, disk_size, + kernel_args, opts.ram, opts.vcpus, opts.vnc, opts.arch, + cancel_func = lambda : any(f() for f in cancel_funcs), + virtio_host = log_monitor.host, + virtio_port = log_monitor.port, + image_type=opts.image_type, boot_uefi=opts.virt_uefi, + ovmf_path=opts.ovmf_path) + log_monitor.shutdown() + except InstallError as e: + log.error("VirtualInstall failed: %s", e) + raise + finally: + log.info("unmounting the iso") + iso_mount.umount() + + if log_monitor.server.log_check(): + if not log_monitor.server.error_line and opts.timeout: + msg = "virt_install failed due to timeout" + else: + msg = "virt_install failed on line: %s" % log_monitor.server.error_line + raise InstallError(msg) + elif cancel_func and cancel_func(): + raise InstallError("virt_install canceled by cancel_func") + + if opts.make_fsimage: + mkfsimage_from_disk(diskimg_path, disk_img, disk_size, label=opts.fs_label) + os.unlink(diskimg_path) + elif opts.make_tar: + compress_args = [] + for arg in opts.compress_args: + compress_args += arg.split(" ", 1) + + with PartitionMount(diskimg_path) as img_mount: + if img_mount and img_mount.mount_dir: + rc = mktar(img_mount.mount_dir, disk_img, opts.compression, compress_args) + else: + rc = 1 + os.unlink(diskimg_path) + + if rc: + raise InstallError("virt_install failed") + elif opts.make_oci: + # An OCI image places the filesystem under /rootfs/ and adds the json files at the top + # And then creates a tar of the whole thing. + compress_args = [] + for arg in opts.compress_args: + compress_args += arg.split(" ", 1) + + with PartitionMount(diskimg_path, submount="rootfs") as img_mount: + if img_mount and img_mount.temp_dir: + shutil.copy2(opts.oci_config, img_mount.temp_dir) + shutil.copy2(opts.oci_runtime, img_mount.temp_dir) + rc = mktar(img_mount.temp_dir, disk_img, opts.compression, compress_args) + else: + rc = 1 + os.unlink(diskimg_path) + + if rc: + raise InstallError("virt_install failed") + elif opts.make_vagrant: + compress_args = [] + for arg in opts.compress_args: + compress_args += arg.split(" ", 1) + + vagrant_dir = tempfile.mkdtemp(prefix="lmc-tmpdir-") + metadata_path = joinpaths(vagrant_dir, "metadata.json") + execWithRedirect("mv", ["-f", disk_img, joinpaths(vagrant_dir, "box.img")], raise_err=True) + if opts.vagrant_metadata: + shutil.copy2(opts.vagrant_metadata, metadata_path) + else: + create_vagrant_metadata(metadata_path) + update_vagrant_metadata(metadata_path, disk_size) + if opts.vagrantfile: + shutil.copy2(opts.vagrantfile, joinpaths(vagrant_dir, "vagrantfile")) + + rc = mktar(vagrant_dir, disk_img, opts.compression, compress_args, selinux=False) + if rc: + raise InstallError("virt_install failed") + shutil.rmtree(vagrant_dir) + + # For make_tar_disk, wrap the result in a tar file, and remove the original disk image. + if opts.make_tar_disk: + compress_args = [] + for arg in opts.compress_args: + compress_args += arg.split(" ", 1) + + rc = mktar(disk_img, tar_img, opts.compression, compress_args, selinux=False) + + if rc: + raise InstallError("virt_install mktar failed: rc=%s" % rc) + + os.unlink(disk_img)
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/ltmpl.html b/f32-branch/_modules/pylorax/ltmpl.html new file mode 100644 index 00000000..bfd49771 --- /dev/null +++ b/f32-branch/_modules/pylorax/ltmpl.html @@ -0,0 +1,1085 @@ + + + + + + + + + + + pylorax.ltmpl — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.ltmpl

    +#
    +# ltmpl.py
    +#
    +# Copyright (C) 2009-2018  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Red Hat Author(s):  Martin Gracik <mgracik@redhat.com>
    +#                     Will Woods <wwoods@redhat.com>
    +#
    +
    +import logging
    +logger = logging.getLogger("pylorax.ltmpl")
    +
    +import os, re, glob, shlex, fnmatch
    +from os.path import basename, isdir
    +from subprocess import CalledProcessError
    +import shutil
    +
    +from pylorax.sysutils import joinpaths, cpfile, mvfile, replace, remove
    +from pylorax.dnfhelper import LoraxDownloadCallback, LoraxRpmCallback
    +from pylorax.base import DataHolder
    +from pylorax.executils import runcmd, runcmd_output
    +from pylorax.imgutils import mkcpio
    +
    +from mako.lookup import TemplateLookup
    +from mako.exceptions import text_error_template
    +import sys, traceback
    +import struct
    +import dnf
    +import collections.abc
    +
    +
    [docs]class LoraxTemplate(object): + def __init__(self, directories=None): + directories = directories or ["/usr/share/lorax"] + # we have to add ["/"] to the template lookup directories or the + # file includes won't work properly for absolute paths + self.directories = ["/"] + directories + +
    [docs] def parse(self, template_file, variables): + lookup = TemplateLookup(directories=self.directories) + template = lookup.get_template(template_file) + + try: + textbuf = template.render(**variables) + except: + logger.error("Problem rendering %s (%s):", template_file, variables) + logger.error(text_error_template().render()) + raise + + # split, strip and remove empty lines + lines = textbuf.splitlines() + lines = [line.strip() for line in lines] + lines = [line for line in lines if line] + + # remove comments + lines = [line for line in lines if not line.startswith("#")] + + # split with shlex and perform brace expansion. This can fail, so we unroll the loop + # for better error reporting. + expanded_lines = [] + try: + for line in lines: + expanded_lines.append(split_and_expand(line)) + except Exception as e: + logger.error('shlex error processing "%s": %s', line, str(e)) + raise + return expanded_lines
    + +
    [docs]def split_and_expand(line): + return [exp for word in shlex.split(line) for exp in brace_expand(word)]
    + +
    [docs]def brace_expand(s): + if not ('{' in s and ',' in s and '}' in s): + yield s + else: + right = s.find('}') + left = s[:right].rfind('{') + (prefix, choices, suffix) = (s[:left], s[left+1:right], s[right+1:]) + for choice in choices.split(','): + for alt in brace_expand(prefix+choice+suffix): + yield alt
    + +
    [docs]def rglob(pathname, root="/", fatal=False): + seen = set() + rootlen = len(root)+1 + for f in glob.iglob(joinpaths(root, pathname)): + if f not in seen: + seen.add(f) + yield f[rootlen:] # remove the root to produce relative path + if fatal and not seen: + raise IOError("nothing matching %s in %s" % (pathname, root))
    + +
    [docs]def rexists(pathname, root=""): + # Generator is always True, even with no values; + # bool(rglob(...)) won't work here. + for _path in rglob(pathname, root): + return True + return False
    + +
    [docs]class TemplateRunner(object): + ''' + This class parses and executes Lorax templates. Sample usage: + + # install a bunch of packages + runner = LoraxTemplateRunner(inroot=rundir, outroot=rundir, dbo=dnf_obj) + runner.run("install-packages.ltmpl") + + NOTES: + + * Parsing procedure is roughly: + 1. Mako template expansion (on the whole file) + 2. For each line of the result, + + a. Whitespace splitting (using shlex.split()) + b. Brace expansion (using brace_expand()) + c. If the first token is the name of a function, call that function + with the rest of the line as arguments + + * Parsing and execution are *separate* passes - so you can't use the result + of a command in an %if statement (or any other control statements)! + ''' + def __init__(self, fatalerrors=True, templatedir=None, defaults=None, builtins=None): + self.fatalerrors = fatalerrors + self.templatedir = templatedir or "/usr/share/lorax" + self.templatefile = None + self.builtins = builtins or {} + self.defaults = defaults or {} + + +
    [docs] def run(self, templatefile, **variables): + for k,v in list(self.defaults.items()) + list(self.builtins.items()): + variables.setdefault(k,v) + logger.debug("executing %s with variables=%s", templatefile, variables) + self.templatefile = templatefile + t = LoraxTemplate(directories=[self.templatedir]) + commands = t.parse(templatefile, variables) + self._run(commands)
    + + + def _run(self, parsed_template): + logger.info("running %s", self.templatefile) + for (num, line) in enumerate(parsed_template,1): + logger.debug("template line %i: %s", num, " ".join(line)) + skiperror = False + (cmd, args) = (line[0], line[1:]) + # Following Makefile convention, if the command is prefixed with + # a dash ('-'), we'll ignore any errors on that line. + if cmd.startswith('-'): + cmd = cmd[1:] + skiperror = True + try: + # grab the method named in cmd and pass it the given arguments + f = getattr(self, cmd, None) + if cmd[0] == '_' or cmd == 'run' or not isinstance(f, collections.abc.Callable): + raise ValueError("unknown command %s" % cmd) + f(*args) + except Exception: # pylint: disable=broad-except + if skiperror: + logger.debug("ignoring error") + continue + logger.error("template command error in %s:", self.templatefile) + logger.error(" %s", " ".join(line)) + # format the exception traceback + exclines = traceback.format_exception(*sys.exc_info()) + # skip the bit about "ltmpl.py, in _run()" - we know that + exclines.pop(1) + # log the "ErrorType: this is what happened" line + logger.error(" %s", exclines[-1].strip()) + # and log the entire traceback to the debug log + for _line in ''.join(exclines).splitlines(): + logger.debug(" %s", _line) + if self.fatalerrors: + raise
    + + +# TODO: operate inside an actual chroot for safety? Not that RPM bothers.. +
    [docs]class LoraxTemplateRunner(TemplateRunner): + ''' + This class parses and executes Lorax templates. Sample usage: + + # install a bunch of packages + runner = LoraxTemplateRunner(inroot=rundir, outroot=rundir, dbo=dnf_obj) + runner.run("install-packages.ltmpl") + + # modify a runtime dir + runner = LoraxTemplateRunner(inroot=rundir, outroot=newrun) + runner.run("runtime-transmogrify.ltmpl") + + NOTES: + + * Commands that run external programs (e.g. systemctl) currently use + the *host*'s copy of that program, which may cause problems if there's a + big enough difference between the host and the image you're modifying. + + * The commands are not executed under a real chroot, so absolute symlinks + will point *outside* the inroot/outroot. Be careful with symlinks! + + ADDING NEW COMMANDS: + + * Each template command is just a method of the LoraxTemplateRunner + object - so adding a new command is as easy as adding a new function. + + * Each function gets arguments that correspond to the rest of the tokens + on that line (after word splitting and brace expansion) + + * Commands should raise exceptions for errors - don't use sys.exit() + ''' + def __init__(self, inroot, outroot, dbo=None, fatalerrors=True, + templatedir=None, defaults=None): + self.inroot = inroot + self.outroot = outroot + self.dbo = dbo + builtins = DataHolder(exists=lambda p: rexists(p, root=inroot), + glob=lambda g: list(rglob(g, root=inroot))) + self.results = DataHolder(treeinfo=dict()) # just treeinfo for now + + super(LoraxTemplateRunner, self).__init__(fatalerrors, templatedir, defaults, builtins) + # TODO: set up custom logger with a filter to add line info + + def _out(self, path): + return joinpaths(self.outroot, path) + def _in(self, path): + return joinpaths(self.inroot, path) + + def _filelist(self, *pkgs): + """ Return the list of files in the packages """ + pkglist = [] + for pkg_glob in pkgs: + pkglist += list(self.dbo.sack.query().installed().filter(name__glob=pkg_glob)) + + # dnf/hawkey doesn't make any distinction between file, dir or ghost like yum did + # so only return the files. + return set(f for pkg in pkglist for f in pkg.files if not os.path.isdir(self._out(f))) + + def _getsize(self, *files): + return sum(os.path.getsize(self._out(f)) for f in files if os.path.isfile(self._out(f))) + + def _write_package_log(self): + """ + Write the list of installed packages to /root/ on the boot.iso + + If lorax is called with a debug repo find the corresponding debuginfo package + names and write them to /root/debubg-pkgs.log on the boot.iso + The non-debuginfo packages are written to /root/lorax-packages.log + """ + os.makedirs(self._out("root/"), exist_ok=True) + available = self.dbo.sack.query().available() + pkgs = [] + debug_pkgs = [] + for p in list(self.dbo.transaction.install_set): + pkgs.append(f"{p.name}-{p.version}-{p.release}.{p.arch}") + if available.filter(name=p.name+"-debuginfo"): + debug_pkgs.append(f"{p.name}-debuginfo-{p.epoch}:{p.version}-{p.release}") + + with open(self._out("root/lorax-packages.log"), "w") as f: + f.write("\n".join(sorted(pkgs))) + f.write("\n") + + if debug_pkgs: + with open(self._out("root/debug-pkgs.log"), "w") as f: + f.write("\n".join(sorted(debug_pkgs))) + f.write("\n") + +
    [docs] def install(self, srcglob, dest): + ''' + install SRC DEST + Copy the given file (or files, if a glob is used) from the input + tree to the given destination in the output tree. + The path to DEST must exist in the output tree. + If DEST is a directory, SRC will be copied into that directory. + If DEST doesn't exist, SRC will be copied to a file with that name, + assuming the rest of the path exists. + This is pretty much like how the 'cp' command works. + + Examples: + install usr/share/myconfig/grub.conf /boot + install /usr/share/myconfig/grub.conf.in /boot/grub.conf + ''' + for src in rglob(self._in(srcglob), fatal=True): + try: + cpfile(src, self._out(dest)) + except shutil.Error as e: + logger.error(e)
    + +
    [docs] def installimg(self, *args): + ''' + installimg [--xz|--gzip|--bzip2|--lzma] [-ARG|--ARG=OPTION] SRCDIR DESTFILE + Create a compressed cpio archive of the contents of SRCDIR and place + it in DESTFILE. + + If SRCDIR doesn't exist or is empty nothing is created. + + Examples: + installimg ${LORAXDIR}/product/ images/product.img + installimg ${LORAXDIR}/updates/ images/updates.img + installimg --xz -6 ${LORAXDIR}/updates/ images/updates.img + installimg --xz -9 --memlimit-compress=3700MiB ${LORAXDIR}/updates/ images/updates.img + + Optionally use a different compression type and override the default args + passed to it. The default is xz -9 + ''' + COMPRESSORS = ("--xz", "--gzip", "--bzip2", "--lzma") + if len(args) < 2: + raise ValueError("Not enough args for installimg.") + + srcdir = args[-2] + destfile = args[-1] + if not os.path.isdir(self._in(srcdir)) or not os.listdir(self._in(srcdir)): + return + + compression = "xz" + compressargs = [] + if args[0] in COMPRESSORS: + compression = args[0][2:] + + for arg in args[1:-2]: + if arg.startswith('-'): + compressargs.append(arg) + else: + raise ValueError("Argument is missing -") + + logger.info("Creating image file %s from contents of %s", self._out(destfile), self._in(srcdir)) + logger.debug("Using %s %s compression", compression, compressargs or "") + mkcpio(self._in(srcdir), self._out(destfile), compression=compression, compressargs=compressargs)
    + +
    [docs] def mkdir(self, *dirs): + ''' + mkdir DIR [DIR ...] + Create the named DIR(s). Will create leading directories as needed. + + Example: + mkdir /images + ''' + for d in dirs: + d = self._out(d) + if not isdir(d): + os.makedirs(d)
    + +
    [docs] def replace(self, pat, repl, *fileglobs): + ''' + replace PATTERN REPLACEMENT FILEGLOB [FILEGLOB ...] + Find-and-replace the given PATTERN (Python-style regex) with the given + REPLACEMENT string for each of the files listed. + + Example: + replace @VERSION@ ${product.version} /boot/grub.conf /boot/isolinux.cfg + ''' + match = False + for g in fileglobs: + for f in rglob(self._out(g)): + match = True + replace(f, pat, repl) + if not match: + raise IOError("no files matched %s" % " ".join(fileglobs))
    + +
    [docs] def append(self, filename, data): + ''' + append FILE STRING + Append STRING (followed by a newline character) to FILE. + Python character escape sequences ('\\n', '\\t', etc.) will be + converted to the appropriate characters. + + Examples: + + append /etc/depmod.d/dd.conf "search updates built-in" + append /etc/resolv.conf "" + ''' + with open(self._out(filename), "a") as fobj: + fobj.write(bytes(data, "utf8").decode('unicode_escape')+"\n")
    + +
    [docs] def treeinfo(self, section, key, *valuetoks): + ''' + treeinfo SECTION KEY ARG [ARG ...] + Add an item to the treeinfo data store. + The given SECTION will have a new item added where + KEY = ARG ARG ... + + Example: + treeinfo images-${kernel.arch} boot.iso images/boot.iso + ''' + if section not in self.results.treeinfo: + self.results.treeinfo[section] = dict() + self.results.treeinfo[section][key] = " ".join(valuetoks)
    + +
    [docs] def installkernel(self, section, src, dest): + ''' + installkernel SECTION SRC DEST + Install the kernel from SRC in the input tree to DEST in the output + tree, and then add an item to the treeinfo data store, in the named + SECTION, where "kernel" = DEST. + + Equivalent to: + install SRC DEST + treeinfo SECTION kernel DEST + ''' + self.install(src, dest) + self.treeinfo(section, "kernel", dest)
    + +
    [docs] def installinitrd(self, section, src, dest): + ''' + installinitrd SECTION SRC DEST + Same as installkernel, but for "initrd". + ''' + self.install(src, dest) + self.chmod(dest, '644') + self.treeinfo(section, "initrd", dest)
    + +
    [docs] def installupgradeinitrd(self, section, src, dest): + ''' + installupgradeinitrd SECTION SRC DEST + Same as installkernel, but for "upgrade". + ''' + self.install(src, dest) + self.chmod(dest, '644') + self.treeinfo(section, "upgrade", dest)
    + + + + + +
    [docs] def copy(self, src, dest): + ''' + copy SRC DEST + Copy SRC to DEST. + If DEST is a directory, SRC will be copied inside it. + If DEST doesn't exist, SRC will be copied to a file with + that name, if the path leading to it exists. + ''' + try: + cpfile(self._out(src), self._out(dest)) + except shutil.Error as e: + logger.error(e)
    + +
    [docs] def move(self, src, dest): + ''' + move SRC DEST + Move SRC to DEST. + ''' + mvfile(self._out(src), self._out(dest))
    + +
    [docs] def remove(self, *fileglobs): + ''' + remove FILEGLOB [FILEGLOB ...] + Remove all the named files or directories. + Will *not* raise exceptions if the file(s) are not found. + ''' + for g in fileglobs: + for f in rglob(self._out(g)): + remove(f) + logger.debug("removed %s", f)
    + +
    [docs] def chmod(self, fileglob, mode): + ''' + chmod FILEGLOB OCTALMODE + Change the mode of all the files matching FILEGLOB to OCTALMODE. + ''' + for f in rglob(self._out(fileglob), fatal=True): + os.chmod(f, int(mode,8))
    + +
    [docs] def log(self, msg): + ''' + log MESSAGE + Emit the given log message. Be sure to put it in quotes! + + Example: + log "Reticulating splines, please wait..." + ''' + logger.info(msg)
    + + # TODO: add ssh-keygen, mkisofs(?), find, and other useful commands +
    [docs] def runcmd(self, *cmdlist): + ''' + runcmd CMD [ARG ...] + Run the given command with the given arguments. + + NOTE: All paths given MUST be COMPLETE, ABSOLUTE PATHS to the file + or files mentioned. ${root}/${inroot}/${outroot} are good for + constructing these paths. + + FURTHER NOTE: Please use this command only as a last resort! + Whenever possible, you should use the existing template commands. + If the existing commands don't do what you need, fix them! + + Examples: + (this should be replaced with a "find" function) + runcmd find ${root} -name "*.pyo" -type f -delete + %for f in find(root, name="*.pyo"): + remove ${f} + %endfor + ''' + cmd = cmdlist + logger.debug('running command: %s', cmd) + if cmd[0].startswith("--chdir="): + logger.error("--chdir is no longer supported for runcmd.") + raise ValueError("--chdir is no longer supported for runcmd.") + + try: + stdout = runcmd_output(cmd) + if stdout: + logger.debug('command output:\n%s', stdout) + logger.debug("command finished successfully") + except CalledProcessError as e: + if e.output: + logger.error('command output:\n%s', e.output) + logger.error('command returned failure (%d)', e.returncode) + raise
    + +
    [docs] def installpkg(self, *pkgs): + ''' + installpkg [--required|--optional] [--except PKGGLOB [--except PKGGLOB ...]] PKGGLOB [PKGGLOB ...] + Request installation of all packages matching the given globs. + Note that this is just a *request* - nothing is *actually* installed + until the 'run_pkg_transaction' command is given. + + --required is now the default. If the PKGGLOB can be missing pass --optional + ''' + if pkgs[0] == '--optional': + pkgs = pkgs[1:] + required = False + elif pkgs[0] == '--required': + pkgs = pkgs[1:] + required = True + else: + required = True + + excludes = [] + while '--except' in pkgs: + idx = pkgs.index('--except') + if len(pkgs) == idx+1: + raise ValueError("installpkg needs an argument after --except") + + excludes.append(pkgs[idx+1]) + pkgs = pkgs[:idx] + pkgs[idx+2:] + + errors = False + for p in pkgs: + try: + # Start by using Subject to generate a package query, which will + # give us a query object similar to what dbo.install would select, + # minus the handling for multilib. This query may contain + # multiple arches. Pull the package names out of that, filter any + # that match the excludes patterns, and pass those names back to + # dbo.install to do the actual, arch and version and multilib + # aware, package selction. + + # dnf queries don't have a concept of negative globs which is why + # the filtering is done the hard way. + + pkgnames = [pkg for pkg in dnf.subject.Subject(p).get_best_query(self.dbo.sack).filter(latest=True)] + if not pkgnames: + raise dnf.exceptions.PackageNotFoundError("no package matched", p) + + # Apply excludes to the name only + for exclude in excludes: + pkgnames = [pkg for pkg in pkgnames if not fnmatch.fnmatch(pkg.name, exclude)] + + # Convert to a sorted NVR list for installation + pkgnvrs = sorted(["{}-{}-{}".format(pkg.name, pkg.version, pkg.release) for pkg in pkgnames]) + + # If the request is a glob, expand it in the log + if any(g for g in ['*','?','.'] if g in p): + logger.info("installpkg: %s expands to %s", p, ",".join(pkgnvrs)) + + for pkgnvr in pkgnvrs: + try: + self.dbo.install(pkgnvr) + except Exception as e: # pylint: disable=broad-except + if required: + raise + # Not required, log it and continue processing pkgs + logger.error("installpkg %s failed: %s", pkgnvr, str(e)) + except Exception as e: # pylint: disable=broad-except + logger.error("installpkg %s failed: %s", p, str(e)) + errors = True + + if errors and required: + raise Exception("Required installpkg failed.")
    + +
    [docs] def removepkg(self, *pkgs): + ''' + removepkg PKGGLOB [PKGGLOB...] + Delete the named package(s). + + IMPLEMENTATION NOTES: + RPM scriptlets (%preun/%postun) are *not* run. + Files are deleted, but directories are left behind. + ''' + for p in pkgs: + filepaths = [f.lstrip('/') for f in self._filelist(p)] + # TODO: also remove directories that aren't owned by anything else + if filepaths: + logger.debug("removepkg %s: %ikb", p, self._getsize(*filepaths)/1024) + self.remove(*filepaths) + else: + logger.debug("removepkg %s: no files to remove!", p)
    + +
    [docs] def run_pkg_transaction(self): + ''' + run_pkg_transaction + Actually install all the packages requested by previous 'installpkg' + commands. + ''' + try: + logger.info("Checking dependencies") + self.dbo.resolve() + except dnf.exceptions.DepsolveError as e: + logger.error("Dependency check failed: %s", e) + raise + logger.info("%d packages selected", len(self.dbo.transaction)) + if len(self.dbo.transaction) == 0: + raise Exception("No packages in transaction") + + # Write out the packages installed, including debuginfo packages + self._write_package_log() + + pkgs_to_download = self.dbo.transaction.install_set + logger.info("Downloading packages") + progress = LoraxDownloadCallback() + try: + self.dbo.download_packages(pkgs_to_download, progress) + except dnf.exceptions.DownloadError as e: + logger.error("Failed to download the following packages: %s", e) + raise + + logger.info("Preparing transaction from installation source") + try: + display = LoraxRpmCallback() + self.dbo.do_transaction(display=display) + except BaseException as e: + logger.error("The transaction process has ended abruptly: %s", e) + raise + + # Reset the package sack to pick up the installed packages + self.dbo.reset(repos=False) + self.dbo.fill_sack(load_system_repo=True, load_available_repos=False) + + # At this point dnf should know about the installed files. Double check that it really does. + if len(self._filelist("anaconda-core")) == 0: + raise Exception("Failed to reset dbo to installed package set")
    + +
    [docs] def removefrom(self, pkg, *globs): + ''' + removefrom PKGGLOB [--allbut] FILEGLOB [FILEGLOB...] + Remove all files matching the given file globs from the package + (or packages) named. + If '--allbut' is used, all the files from the given package(s) will + be removed *except* the ones which match the file globs. + + Examples: + removefrom usbutils /usr/bin/* + removefrom xfsprogs --allbut /sbin/* + ''' + cmd = "%s %s" % (pkg, " ".join(globs)) # save for later logging + keepmatches = False + if globs[0] == '--allbut': + keepmatches = True + globs = globs[1:] + # get pkg filelist and find files that match the globs + filelist = self._filelist(pkg) + matches = set() + for g in globs: + globs_re = re.compile(fnmatch.translate(g)) + m = [f for f in filelist if globs_re.match(f)] + if m: + matches.update(m) + else: + logger.debug("removefrom %s %s: no files matched!", pkg, g) + # are we removing the matches, or keeping only the matches? + if keepmatches: + remove_files = filelist.difference(matches) + else: + remove_files = matches + # remove the files + if remove_files: + logger.debug("removefrom %s: removed %i/%i files, %ikb/%ikb", cmd, + len(remove_files), len(filelist), + self._getsize(*remove_files)/1024, self._getsize(*filelist)/1024) + self.remove(*remove_files) + else: + logger.debug("removefrom %s: no files to remove!", cmd)
    + + # pylint: disable=anomalous-backslash-in-string +
    [docs] def removekmod(self, *globs): + ''' + removekmod GLOB [GLOB...] [--allbut] KEEPGLOB [KEEPGLOB...] + Remove all files and directories matching the given file globs from the kernel + modules directory. + + If '--allbut' is used, all the files from the modules will be removed *except* + the ones which match the file globs. There must be at least one initial GLOB + to search and one KEEPGLOB to keep. The KEEPGLOB is expanded to be *KEEPGLOB* + so that it will match anywhere in the path. + + This only removes files from under /lib/modules/\*/kernel/ + + Examples: + removekmod sound drivers/media drivers/hwmon drivers/video + removekmod drivers/char --allbut virtio_console hw_random + ''' + cmd = " ".join(globs) + if "--allbut" in globs: + idx = globs.index("--allbut") + if idx == 0: + raise ValueError("removekmod needs at least one GLOB before --allbut") + + # Apply keepglobs anywhere they appear in the path + keepglobs = globs[idx+1:] + if len(keepglobs) == 0: + raise ValueError("removekmod needs at least one GLOB after --allbut") + + globs = globs[:idx] + else: + # Nothing to keep + keepglobs = [] + + filelist = set() + for g in globs: + for top_dir in rglob(self._out("/lib/modules/*/kernel/"+g)): + for root, _dirs, files in os.walk(top_dir): + filelist.update(root+"/"+f for f in files) + + # Remove anything matching keepglobs from the list + matches = set() + for g in keepglobs: + globs_re = re.compile(fnmatch.translate("*"+g+"*")) + m = [f for f in filelist if globs_re.match(f)] + if m: + matches.update(m) + else: + logger.debug("removekmod %s: no files matched!", g) + remove_files = filelist.difference(matches) + + if remove_files: + logger.debug("removekmod: removing %d files", len(remove_files)) + list(remove(f) for f in remove_files) + else: + logger.debug("removekmod %s: no files to remove!", cmd)
    + +
    [docs] def createaddrsize(self, addr, src, dest): + ''' + createaddrsize INITRD_ADDRESS INITRD ADDRSIZE + Create the initrd.addrsize file required in LPAR boot process. + + Examples: + createaddrsize ${INITRD_ADDRESS} ${outroot}/${BOOTDIR}/initrd.img ${outroot}/${BOOTDIR}/initrd.addrsize + ''' + addrsize = open(dest, "wb") + addrsize_data = struct.pack(">iiii", 0, int(addr, 16), 0, os.stat(src).st_size) + addrsize.write(addrsize_data) + addrsize.close()
    + +
    [docs] def systemctl(self, cmd, *units): + ''' + systemctl [enable|disable|mask] UNIT [UNIT...] + Enable, disable, or mask the given systemd units. + + Examples: + systemctl disable lvm2-monitor.service + systemctl mask fedora-storage-init.service fedora-configure.service + ''' + if cmd not in ('enable', 'disable', 'mask'): + raise ValueError('unsupported systemctl cmd: %s' % cmd) + if not units: + logger.debug("systemctl: no units given for %s, ignoring", cmd) + return + self.mkdir("/run/systemd/system") # XXX workaround for systemctl bug + systemctl = ['systemctl', '--root', self.outroot, '--no-reload', cmd] + # When a unit doesn't exist systemd aborts the command. Run them one at a time. + # XXX for some reason 'systemctl enable/disable' always returns 1 + for unit in units: + try: + cmd = systemctl + [unit] + runcmd(cmd) + except CalledProcessError: + pass
    + +
    [docs]class LiveTemplateRunner(TemplateRunner): + """ + This class parses and executes a limited Lorax template. Sample usage: + + # install a bunch of packages + runner = LiveTemplateRunner(dbo, templatedir, defaults) + runner.run("live-install.tmpl") + + It is meant to be used with the live-install.tmpl which lists the per-arch + pacages needed to build the live-iso output. + """ + def __init__(self, dbo, fatalerrors=True, templatedir=None, defaults=None): + self.dbo = dbo + self.pkgs = [] + self.pkgnames = [] + + super(LiveTemplateRunner, self).__init__(fatalerrors, templatedir, defaults) + +
    [docs] def installpkg(self, *pkgs): + ''' + installpkg [--required|--optional] [--except PKGGLOB [--except PKGGLOB ...]] PKGGLOB [PKGGLOB ...] + Request installation of all packages matching the given globs. + Note that this is just a *request* - nothing is *actually* installed + until the 'run_pkg_transaction' command is given. + + --required is now the default. If the PKGGLOB can be missing pass --optional + ''' + if pkgs[0] == '--optional': + pkgs = pkgs[1:] + required = False + elif pkgs[0] == '--required': + pkgs = pkgs[1:] + required = True + else: + required = True + + excludes = [] + while '--except' in pkgs: + idx = pkgs.index('--except') + if len(pkgs) == idx+1: + raise ValueError("installpkg needs an argument after --except") + + excludes.append(pkgs[idx+1]) + pkgs = pkgs[:idx] + pkgs[idx+2:] + + errors = False + for p in pkgs: + try: + # Start by using Subject to generate a package query, which will + # give us a query object similar to what dbo.install would select, + # minus the handling for multilib. This query may contain + # multiple arches. Pull the package names out of that, filter any + # that match the excludes patterns, and pass those names back to + # dbo.install to do the actual, arch and version and multilib + # aware, package selction. + + # dnf queries don't have a concept of negative globs which is why + # the filtering is done the hard way. + + pkgnames = [pkg for pkg in dnf.subject.Subject(p).get_best_query(self.dbo.sack).filter(latest=True)] + if not pkgnames: + raise dnf.exceptions.PackageNotFoundError("no package matched", p) + + # Apply excludes to the name only + for exclude in excludes: + pkgnames = [pkg for pkg in pkgnames if not fnmatch.fnmatch(pkg.name, exclude)] + + # Convert to a sorted NVR list for installation + pkgnvrs = sorted(["{}-{}-{}".format(pkg.name, pkg.version, pkg.release) for pkg in pkgnames]) + + # If the request is a glob, expand it in the log + if any(g for g in ['*','?','.'] if g in p): + logger.info("installpkg: %s expands to %s", p, ",".join(pkgnvrs)) + + self.pkgs.extend(pkgnvrs) + self.pkgnames.extend([pkg.name for pkg in pkgnames]) + except Exception as e: # pylint: disable=broad-except + logger.error("installpkg %s failed: %s", p, str(e)) + errors = True + + if errors and required: + raise Exception("Required installpkg failed.")
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/monitor.html b/f32-branch/_modules/pylorax/monitor.html new file mode 100644 index 00000000..b2bd092a --- /dev/null +++ b/f32-branch/_modules/pylorax/monitor.html @@ -0,0 +1,404 @@ + + + + + + + + + + + pylorax.monitor — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.monitor

    +# monitor.py
    +#
    +# Copyright (C) 2011-2015  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author(s): Brian C. Lane <bcl@redhat.com>
    +#
    +import logging
    +log = logging.getLogger("livemedia-creator")
    +
    +import re
    +import socket
    +import socketserver
    +import threading
    +import time
    +
    +
    [docs]class LogRequestHandler(socketserver.BaseRequestHandler): + """ + Handle monitoring and saving the logfiles from the virtual install + + Incoming data is written to self.server.log_path and each line is checked + for patterns that would indicate that the installation failed. + self.server.log_error is set True when this happens. + """ + + simple_tests = [ + "Traceback (", + "traceback script(s) have been run", + "Out of memory:", + "Call Trace:", + "insufficient disk space:", + "Not enough disk space to download the packages", + "error populating transaction after", + "crashed on signal", + "packaging: Missed: NoSuchPackage", + "packaging: Installation failed", + "The following error occurred while installing. This is a fatal error" + ] + + re_tests = [ + r"packaging: base repo .* not valid", + r"packaging: .* requires .*" + ] + +
    [docs] def setup(self): + """Start writing to self.server.log_path""" + + if self.server.log_path: + self.fp = open(self.server.log_path, "w") # pylint: disable=attribute-defined-outside-init + else: + self.fp = None + self.request.settimeout(10)
    + +
    [docs] def handle(self): + """ + Write incoming data to a logfile and check for errors + + Split incoming data into lines and check for any Tracebacks or other + errors that indicate that the install failed. + + Loops until self.server.kill is True + """ + log.info("Processing logs from %s", self.client_address) + line = "" + while True: + if self.server.kill: + break + + try: + data = str(self.request.recv(4096), "utf8") + if self.fp: + self.fp.write(data) + self.fp.flush() + + # check the data for errors and set error flag + # need to assemble it into lines so we can test for the error + # string. + while data: + more = data.split("\n", 1) + line += more[0] + if len(more) > 1: + self.iserror(line) + line = "" + data = more[1] + else: + data = None + + except socket.timeout: + pass + except Exception as e: # pylint: disable=broad-except + log.info("log processing killed by exception: %s", e) + break
    + +
    [docs] def finish(self): + log.info("Shutting down log processing") + self.request.close() + if self.fp: + self.fp.close()
    + +
    [docs] def iserror(self, line): + """ + Check a line to see if it contains an error indicating installation failure + + :param str line: log line to check for failure + + If the line contains IGNORED it will be skipped. + """ + if "IGNORED" in line: + return + + for t in self.simple_tests: + if t in line: + self.server.log_error = True + self.server.error_line = line + return + for t in self.re_tests: + if re.search(t, line): + self.server.log_error = True + self.server.error_line = line + return
    + + +
    [docs]class LogServer(socketserver.TCPServer): + """A TCP Server that listens for log data""" + + # Number of seconds to wait for a connection after startup + timeout = 60 + + def __init__(self, log_path, *args, **kwargs): + """ + Setup the log server + + :param str log_path: Path to the log file to write + """ + self.kill = False + self.log_error = False + self.error_line = "" + self.log_path = log_path + self._timeout = kwargs.pop("timeout", None) + if self._timeout: + self._start_time = time.time() + socketserver.TCPServer.__init__(self, *args, **kwargs) + +
    [docs] def log_check(self): + """ + Check to see if an error has been found in the log + + :returns: True if there has been an error + :rtype: bool + """ + if self._timeout: + taking_too_long = time.time() > self._start_time + (self._timeout * 60) + if taking_too_long: + log.error("Canceling installation due to timeout") + else: + taking_too_long = False + return self.log_error or taking_too_long
    + + +
    [docs]class LogMonitor(object): + """ + Setup a server to monitor the logs output by the installation + + This needs to be running before the virt-install runs, it expects + there to be a listener on the port used for the virtio log port. + """ + def __init__(self, log_path=None, host="localhost", port=0, timeout=None, log_request_handler_class=LogRequestHandler): + """ + Start a thread to monitor the logs. + + :param str log_path: Path to the logfile to write + :param str host: Host to bind to. Default is localhost. + :param int port: Port to listen to or 0 to pick a port + + If 0 is passed for the port the dynamically assigned port will be + available as self.port + + If log_path isn't set then it only monitors the logs, instead of + also writing them to disk. + """ + self.server = LogServer(log_path, (host, port), log_request_handler_class, timeout=timeout) + self.host, self.port = self.server.server_address + self.log_path = log_path + self.server_thread = threading.Thread(target=self.server.handle_request) + self.server_thread.daemon = True + self.server_thread.start() + +
    [docs] def shutdown(self): + """Force shutdown of the monitoring thread""" + self.server.kill = True + self.server_thread.join()
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/mount.html b/f32-branch/_modules/pylorax/mount.html new file mode 100644 index 00000000..30766b84 --- /dev/null +++ b/f32-branch/_modules/pylorax/mount.html @@ -0,0 +1,305 @@ + + + + + + + + + + + pylorax.mount — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.mount

    +# mount.py
    +#
    +# Copyright (C) 2011-2015  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author(s): Brian C. Lane <bcl@redhat.com>
    +#
    +import logging
    +log = logging.getLogger("livemedia-creator")
    +
    +import os
    +import pycdlib
    +from pycdlib.pycdlibexception import PyCdlibException
    +
    +from pylorax.imgutils import mount, umount
    +
    +
    [docs]class IsoMountpoint(object): + """ + Mount the iso and check to make sure the vmlinuz and initrd.img files exist + + Also check the iso for a a stage2 image and set a flag and extract the + iso's label. + + stage2 can be either LiveOS/squashfs.img or images/install.img + """ + def __init__(self, iso_path, initrd_path=None): + """ + Mount the iso + + :param str iso_path: Path to the iso to mount + :param str initrd_path: Optional path to initrd + + initrd_path can be used to point to a tree with a newer + initrd.img than the iso has. The iso is still used for stage2. + + self.kernel and self.initrd point to the kernel and initrd. + self.stage2 is set to True if there is a stage2 image. + self.repo is the path to the mounted iso if there is a /repodata dir. + """ + self.label = None + self.iso_path = iso_path + self.initrd_path = initrd_path + + if not self.initrd_path: + self.mount_dir = mount(self.iso_path, opts="loop") + else: + self.mount_dir = self.initrd_path + + kernel_list = [("/isolinux/vmlinuz", "/isolinux/initrd.img"), + ("/ppc/ppc64/vmlinuz", "/ppc/ppc64/initrd.img"), + ("/images/pxeboot/vmlinuz", "/images/pxeboot/initrd.img")] + + if os.path.isdir(self.mount_dir+"/repodata"): + self.repo = self.mount_dir + else: + self.repo = None + self.stage2 = os.path.exists(self.mount_dir+"/LiveOS/squashfs.img") or \ + os.path.exists(self.mount_dir+"/images/install.img") + + try: + for kernel, initrd in kernel_list: + if (os.path.isfile(self.mount_dir+kernel) and + os.path.isfile(self.mount_dir+initrd)): + self.kernel = self.mount_dir+kernel + self.initrd = self.mount_dir+initrd + break + else: + raise Exception("Missing kernel and initrd file in iso, failed" + " to search under: {0}".format(kernel_list)) + except: + self.umount() + raise + + self.get_iso_label() + +
    [docs] def umount( self ): + """Unmount the iso""" + if not self.initrd_path: + umount(self.mount_dir)
    + +
    [docs] def get_iso_label(self): + """ + Get the iso's label using isoinfo + + Sets self.label if one is found + """ + try: + iso = pycdlib.PyCdlib() + iso.open(self.iso_path) + self.label = iso.pvd.volume_identifier.decode("UTF-8").strip() + except PyCdlibException as e: + log.error("Problem reading label from %s: %s", self.iso_path, e)
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/sysutils.html b/f32-branch/_modules/pylorax/sysutils.html new file mode 100644 index 00000000..91be7b43 --- /dev/null +++ b/f32-branch/_modules/pylorax/sysutils.html @@ -0,0 +1,361 @@ + + + + + + + + + + + pylorax.sysutils — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.sysutils

    +#
    +# sysutils.py
    +#
    +# Copyright (C) 2009-2019 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Red Hat Author(s):  Martin Gracik <mgracik@redhat.com>
    +#
    +
    +__all__ = ["joinpaths", "touch", "replace", "chown_", "chmod_", "remove",
    +           "linktree"]
    +
    +import sys
    +import os
    +import re
    +import fileinput
    +import pwd
    +import grp
    +import glob
    +import shutil
    +import shlex
    +from configparser import ConfigParser
    +
    +from pylorax.executils import runcmd
    +
    +
    [docs]def joinpaths(*args, **kwargs): + path = os.path.sep.join(args) + + if kwargs.get("follow_symlinks"): + return os.path.realpath(path) + else: + return path
    + + +
    [docs]def touch(fname): + # python closes the file when it goes out of scope + open(fname, "w").write("")
    + + +
    [docs]def replace(fname, find, sub): + fin = fileinput.input(fname, inplace=1) + pattern = re.compile(find) + + for line in fin: + line = pattern.sub(sub, line) + sys.stdout.write(line) + + fin.close()
    + + +
    [docs]def chown_(path, user=None, group=None, recursive=False): + uid = gid = -1 + + if user is not None: + uid = pwd.getpwnam(user)[2] + if group is not None: + gid = grp.getgrnam(group)[2] + + for fname in glob.iglob(path): + os.chown(fname, uid, gid) + + if recursive and os.path.isdir(fname): + for nested in os.listdir(fname): + nested = joinpaths(fname, nested) + chown_(nested, user, group, recursive)
    + + +
    [docs]def chmod_(path, mode, recursive=False): + for fname in glob.iglob(path): + os.chmod(fname, mode) + + if recursive and os.path.isdir(fname): + for nested in os.listdir(fname): + nested = joinpaths(fname, nested) + chmod_(nested, mode, recursive)
    + + +def cpfile(src, dst): + shutil.copy2(src, dst) + if os.path.isdir(dst): + dst = joinpaths(dst, os.path.basename(src)) + + return dst + +def mvfile(src, dst): + if os.path.isdir(dst): + dst = joinpaths(dst, os.path.basename(src)) + os.rename(src, dst) + return dst + +
    [docs]def remove(target): + if os.path.isdir(target) and not os.path.islink(target): + shutil.rmtree(target) + else: + os.unlink(target)
    + +
    [docs]def linktree(src, dst): + runcmd(["/bin/cp", "-alx", src, dst])
    + +def unquote(s): + return ' '.join(shlex.split(s)) + +class UnquotingConfigParser(ConfigParser): + """A ConfigParser, only with unquoting of the values.""" + # pylint: disable=arguments-differ + def get(self, *args, **kwargs): + ret = super().get(*args, **kwargs) + if ret: + ret = unquote(ret) + return ret + +def flatconfig(filename): + """Use UnquotingConfigParser to read a flat config file (without + section headers) by adding a section header. + """ + with open (filename, 'r') as conffh: + conftext = "[main]\n" + conffh.read() + config = UnquotingConfigParser() + config.read_string(conftext) + return config['main'] + +def read_tail(path, size): + """Read up to `size` kibibytes from the end of a file""" + + # NOTE: In py3 text files are unicode, not bytes so we have to open it as bytes + with open(path, "rb") as f: + return _read_file_end(f, size) + +def _read_file_end(f, size): + """Read the end of a file + + This skips to the next line to avoid starting in the middle of a unicode character. + And returns "" in the case of a UnicodeDecodeError + """ + f.seek(0, 2) + end = f.tell() + if end < 1024 * size: + f.seek(0, 0) + else: + f.seek(end - (1024 * size)) + data = f.read() + try: + # Find the first newline in the block + newline = min(1+data.find(b'\n'), len(data)) + text = data[newline:].decode("UTF-8") + except UnicodeDecodeError: + return "" + return text +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/treebuilder.html b/f32-branch/_modules/pylorax/treebuilder.html new file mode 100644 index 00000000..c967b789 --- /dev/null +++ b/f32-branch/_modules/pylorax/treebuilder.html @@ -0,0 +1,625 @@ + + + + + + + + + + + pylorax.treebuilder — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.treebuilder

    +# treebuilder.py - handle arch-specific tree building stuff using templates
    +#
    +# Copyright (C) 2011-2015 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author(s):  Will Woods <wwoods@redhat.com>
    +
    +import logging
    +logger = logging.getLogger("pylorax.treebuilder")
    +
    +import os, re
    +from os.path import basename
    +from shutil import copytree, copy2
    +from subprocess import CalledProcessError
    +from pathlib import Path
    +import itertools
    +
    +from pylorax.sysutils import joinpaths, remove
    +from pylorax.base import DataHolder
    +from pylorax.ltmpl import LoraxTemplateRunner
    +import pylorax.imgutils as imgutils
    +from pylorax.executils import runcmd, runcmd_output, execWithCapture
    +
    +templatemap = {
    +    'i386':    'x86.tmpl',
    +    'x86_64':  'x86.tmpl',
    +    'ppc64le': 'ppc64le.tmpl',
    +    's390':    's390.tmpl',
    +    's390x':   's390.tmpl',
    +    'aarch64': 'aarch64.tmpl',
    +    'arm':     'arm.tmpl',
    +    'armhfp':  'arm.tmpl',
    +}
    +
    +
    [docs]def generate_module_info(moddir, outfile=None): + def module_desc(mod): + output = runcmd_output(["modinfo", "-F", "description", mod]) + return output.strip() + def read_module_set(name): + return set(l.strip() for l in open(joinpaths(moddir,name)) if ".ko" in l) + modsets = {'scsi':read_module_set("modules.block"), + 'eth':read_module_set("modules.networking")} + + modinfo = list() + for root, _dirs, files in os.walk(moddir): + for modtype, modset in modsets.items(): + for mod in modset.intersection(files): # modules in this dir + (name, _ext) = os.path.splitext(mod) # foo.ko -> (foo, .ko) + desc = module_desc(joinpaths(root,mod)) or "%s driver" % name + modinfo.append(dict(name=name, type=modtype, desc=desc)) + + out = open(outfile or joinpaths(moddir,"module-info"), "w") + out.write("Version 0\n") + for mod in sorted(modinfo, key=lambda m: m.get('name')): + out.write('{name}\n\t{type}\n\t"{desc:.65}"\n'.format(**mod))
    + +
    [docs]class RuntimeBuilder(object): + '''Builds the anaconda runtime image.''' + def __init__(self, product, arch, dbo, templatedir=None, + installpkgs=None, excludepkgs=None, + add_templates=None, + add_template_vars=None, + skip_branding=False): + root = dbo.conf.installroot + # use a copy of product so we can modify it locally + product = product.copy() + product.name = product.name.lower() + self.vars = DataHolder(arch=arch, product=product, dbo=dbo, root=root, + basearch=arch.basearch, libdir=arch.libdir) + self.dbo = dbo + self._runner = LoraxTemplateRunner(inroot=root, outroot=root, + dbo=dbo, templatedir=templatedir) + self.add_templates = add_templates or [] + self.add_template_vars = add_template_vars or {} + self._installpkgs = installpkgs or [] + self._excludepkgs = excludepkgs or [] + self._runner.defaults = self.vars + self.dbo.reset() + self._skip_branding = skip_branding + + def _install_branding(self): + """Select the branding from the available 'system-release' packages + The *best* way to control this is to have a single package in the repo provide 'system-release' + When there are more than 1 package it will: + - Make a list of the available packages + - If variant is set look for a package ending with lower(variant) and use that + - If there are one or more non-generic packages, use the first one after sorting + """ + if self._skip_branding: + return + + release = None + q = self.dbo.sack.query() + a = q.available() + pkgs = sorted([p.name for p in a.filter(provides='system-release') + if not p.name.startswith("generic")]) + if not pkgs: + logger.error("No system-release packages found, could not get the release") + return + + logger.debug("system-release packages: %s", pkgs) + if self.vars.product.variant: + variant = [p for p in pkgs if p.endswith("-"+self.vars.product.variant.lower())] + if variant: + release = variant[0] + if not release: + release = pkgs[0] + + # release + logger.info('got release: %s', release) + self._runner.installpkg(release) + + # logos + release, _suffix = release.split('-', 1) + self._runner.installpkg('%s-logos' % release) + +
    [docs] def install(self): + '''Install packages and do initial setup with runtime-install.tmpl''' + self._install_branding() + if len(self._installpkgs) > 0: + self._runner.installpkg(*self._installpkgs) + if len(self._excludepkgs) > 0: + self._runner.removepkg(*self._excludepkgs) + self._runner.run("runtime-install.tmpl") + for tmpl in self.add_templates: + self._runner.run(tmpl, **self.add_template_vars)
    + +
    [docs] def writepkglists(self, pkglistdir): + '''debugging data: write out lists of package contents''' + if not os.path.isdir(pkglistdir): + os.makedirs(pkglistdir) + q = self.dbo.sack.query() + for pkgobj in q.installed(): + with open(joinpaths(pkglistdir, pkgobj.name), "w") as fobj: + for fname in pkgobj.files: + fobj.write("{0}\n".format(fname))
    + +
    [docs] def postinstall(self): + '''Do some post-install setup work with runtime-postinstall.tmpl''' + # copy configdir into runtime root beforehand + configdir = joinpaths(self._runner.templatedir,"config_files") + configdir_path = "tmp/config_files" + fullpath = joinpaths(self.vars.root, configdir_path) + if os.path.exists(fullpath): + remove(fullpath) + copytree(configdir, fullpath) + self._runner.run("runtime-postinstall.tmpl", configdir=configdir_path)
    + +
    [docs] def cleanup(self): + '''Remove unneeded packages and files with runtime-cleanup.tmpl''' + self._runner.run("runtime-cleanup.tmpl")
    + +
    [docs] def verify(self): + '''Ensure that contents of the installroot can run''' + status = True + + ELF_MAGIC = b'\x7fELF' + + # Iterate over all files in /usr/bin and /usr/sbin + # For ELF files, gather them into a list and we'll check them all at + # the end. For files with a #!, check them as we go + elf_files = [] + usr_bin = Path(self.vars.root + '/usr/bin') + usr_sbin = Path(self.vars.root + '/usr/sbin') + for path in (str(x) for x in itertools.chain(usr_bin.iterdir(), usr_sbin.iterdir()) \ + if x.is_file()): + with open(path, "rb") as f: + magic = f.read(4) + if magic == ELF_MAGIC: + # Save the path, minus the chroot prefix + elf_files.append(path[len(self.vars.root):]) + elif magic[:2] == b'#!': + # Reopen the file as text and read the first line. + # Open as latin-1 so that stray 8-bit characters don't make + # things blow up. We only really care about ASCII parts. + with open(path, "rt", encoding="latin-1") as f_text: + # Remove the #!, split on space, and take the first part + shabang = f_text.readline()[2:].split()[0] + + # Does the path exist? + if not os.path.exists(self.vars.root + shabang): + logger.error('%s, needed by %s, does not exist', shabang, path) + status = False + + # Now, run ldd on all the ELF files + # Just run ldd once on everything so it isn't logged a million times. + # At least one thing in the list isn't going to be a dynamic executable, + # so use execWithCapture to ignore the exit code. + filename = '' + for line in execWithCapture('ldd', elf_files, root=self.vars.root, + log_output=False, filter_stderr=True).split('\n'): + if line and not line[0].isspace(): + # New filename header, strip the : at the end and save + filename = line[:-1] + elif 'not found' in line: + logger.error('%s, needed by %s, not found', line.split()[0], filename) + status = False + + return status
    + +
    [docs] def writepkgsizes(self, pkgsizefile): + '''debugging data: write a big list of pkg sizes''' + fobj = open(pkgsizefile, "w") + getsize = lambda f: os.lstat(f).st_size if os.path.exists(f) else 0 + q = self.dbo.sack.query() + for p in sorted(q.installed()): + pkgsize = sum(getsize(joinpaths(self.vars.root,f)) for f in p.files) + fobj.write("{0.name}.{0.arch}: {1}\n".format(p, pkgsize))
    + +
    [docs] def generate_module_data(self): + root = self.vars.root + moddir = joinpaths(root, "lib/modules/") + for kernel in findkernels(root=root): + ksyms = joinpaths(root, "boot/System.map-%s" % kernel.version) + logger.info("doing depmod and module-info for %s", kernel.version) + runcmd(["depmod", "-a", "-F", ksyms, "-b", root, kernel.version]) + generate_module_info(moddir+kernel.version, outfile=moddir+"module-info")
    + +
    [docs] def create_squashfs_runtime(self, outfile="/var/tmp/squashfs.img", compression="xz", compressargs=None, size=2): + """Create a plain squashfs runtime""" + compressargs = compressargs or [] + os.makedirs(os.path.dirname(outfile)) + + # squash the rootfs + imgutils.mksquashfs(self.vars.root, outfile, compression, compressargs)
    + +
    [docs] def create_ext4_runtime(self, outfile="/var/tmp/squashfs.img", compression="xz", compressargs=None, size=2): + """Create a squashfs compressed ext4 runtime""" + # make live rootfs image - must be named "LiveOS/rootfs.img" for dracut + compressargs = compressargs or [] + workdir = joinpaths(os.path.dirname(outfile), "runtime-workdir") + os.makedirs(joinpaths(workdir, "LiveOS")) + + # Catch problems with the rootfs being too small and clearly log them + try: + imgutils.mkrootfsimg(self.vars.root, joinpaths(workdir, "LiveOS/rootfs.img"), + "Anaconda", size=size) + except CalledProcessError as e: + if e.stdout and "No space left on device" in e.stdout: + logger.error("The rootfs ran out of space with size=%d", size) + raise + + # squash the live rootfs and clean up workdir + imgutils.mksquashfs(workdir, outfile, compression, compressargs) + remove(workdir)
    + +
    [docs] def finished(self): + """ Done using RuntimeBuilder + + Close the dnf base object + """ + self.dbo.close()
    + +
    [docs]class TreeBuilder(object): + '''Builds the arch-specific boot images. + inroot should be the installtree root (the newly-built runtime dir)''' + def __init__(self, product, arch, inroot, outroot, runtime, isolabel, domacboot=True, doupgrade=True, + templatedir=None, add_templates=None, add_template_vars=None, workdir=None, extra_boot_args=""): + + # NOTE: if you pass an arg named "runtime" to a mako template it'll + # clobber some mako internal variables - hence "runtime_img". + self.vars = DataHolder(arch=arch, product=product, runtime_img=runtime, + runtime_base=basename(runtime), + inroot=inroot, outroot=outroot, + basearch=arch.basearch, libdir=arch.libdir, + isolabel=isolabel, udev=udev_escape, domacboot=domacboot, doupgrade=doupgrade, + workdir=workdir, lower=string_lower, + extra_boot_args=extra_boot_args) + self._runner = LoraxTemplateRunner(inroot, outroot, templatedir=templatedir) + self._runner.defaults = self.vars + self.add_templates = add_templates or [] + self.add_template_vars = add_template_vars or {} + self.templatedir = templatedir + self.treeinfo_data = None + + @property + def kernels(self): + return findkernels(root=self.vars.inroot) + +
    [docs] def rebuild_initrds(self, add_args=None, backup="", prefix=""): + '''Rebuild all the initrds in the tree. If backup is specified, each + initrd will be renamed with backup as a suffix before rebuilding. + If backup is empty, the existing initrd files will be overwritten. + If suffix is specified, the existing initrd is untouched and a new + image is built with the filename "${prefix}-${kernel.version}.img" + + If the initrd doesn't exist its name will be created based on the + name of the kernel. + ''' + add_args = add_args or [] + dracut = ["dracut", "--nomdadmconf", "--nolvmconf"] + add_args + if not backup: + dracut.append("--force") + + if not self.kernels: + raise Exception("No kernels found, cannot rebuild_initrds") + + # Hush some dracut warnings. TODO: bind-mount proc in place? + open(joinpaths(self.vars.inroot,"/proc/modules"),"w") + for kernel in self.kernels: + if prefix: + idir = os.path.dirname(kernel.path) + outfile = joinpaths(idir, prefix+'-'+kernel.version+'.img') + elif hasattr(kernel, "initrd"): + # If there is an existing initrd, use that + outfile = kernel.initrd.path + else: + # Construct an initrd from the kernel name + outfile = kernel.path.replace("vmlinuz-", "initrd-") + ".img" + logger.info("rebuilding %s", outfile) + if backup: + initrd = joinpaths(self.vars.inroot, outfile) + if os.path.exists(initrd): + os.rename(initrd, initrd + backup) + cmd = dracut + [outfile, kernel.version] + runcmd(cmd, root=self.vars.inroot) + + os.unlink(joinpaths(self.vars.inroot,"/proc/modules"))
    + +
    [docs] def build(self): + templatefile = templatemap[self.vars.arch.basearch] + for tmpl in self.add_templates: + self._runner.run(tmpl, **self.add_template_vars) + self._runner.run(templatefile, kernels=self.kernels) + self.treeinfo_data = self._runner.results.treeinfo + self.implantisomd5()
    + +
    [docs] def implantisomd5(self): + for _section, data in self.treeinfo_data.items(): + if 'boot.iso' in data: + iso = joinpaths(self.vars.outroot, data['boot.iso']) + runcmd(["implantisomd5", iso])
    + + @property + def dracut_hooks_path(self): + """ Return the path to the lorax dracut hooks scripts + + Use the configured share dir if it is setup, + otherwise default to /usr/share/lorax/dracut_hooks + """ + if self.templatedir: + return joinpaths(self.templatedir, "dracut_hooks") + else: + return "/usr/share/lorax/dracut_hooks" + +
    [docs] def copy_dracut_hooks(self, hooks): + """ Copy the hook scripts in hooks into the installroot's /tmp/ + and return a list of commands to pass to dracut when creating the + initramfs + + hooks is a list of tuples with the name of the hook script and the + target dracut hook directory + (eg. [("99anaconda-copy-ks.sh", "/lib/dracut/hooks/pre-pivot")]) + """ + dracut_commands = [] + for hook_script, dracut_path in hooks: + src = joinpaths(self.dracut_hooks_path, hook_script) + if not os.path.exists(src): + logger.error("Missing lorax dracut hook script %s", (src)) + continue + dst = joinpaths(self.vars.inroot, "/tmp/", hook_script) + copy2(src, dst) + dracut_commands += ["--include", joinpaths("/tmp/", hook_script), + dracut_path] + return dracut_commands
    + +#### TreeBuilder helper functions + +
    [docs]def findkernels(root="/", kdir="boot"): + # To find possible flavors, awk '/BuildKernel/ { print $4 }' kernel.spec + flavors = ('debug', 'PAE', 'PAEdebug', 'smp', 'xen', 'lpae') + kre = re.compile(r"vmlinuz-(?P<version>.+?\.(?P<arch>[a-z0-9_]+)" + r"(.(?P<flavor>{0}))?)$".format("|".join(flavors))) + kernels = [] + bootfiles = os.listdir(joinpaths(root, kdir)) + for f in bootfiles: + match = kre.match(f) + if match: + kernel = DataHolder(path=joinpaths(kdir, f)) + kernel.update(match.groupdict()) # sets version, arch, flavor + kernels.append(kernel) + + # look for associated initrd/initramfs/etc. + for kernel in kernels: + for f in bootfiles: + if f.endswith('-'+kernel.version+'.img'): + imgtype, _rest = f.split('-',1) + # special backwards-compat case + if imgtype == 'initramfs': + imgtype = 'initrd' + kernel[imgtype] = DataHolder(path=joinpaths(kdir, f)) + + logger.debug("kernels=%s", kernels) + return kernels
    + +# udev whitelist: 'a-zA-Z0-9#+.:=@_-' (see is_whitelisted in libudev-util.c) +udev_blacklist=' !"$%&\'()*,/;<>?[\\]^`{|}~' # ASCII printable, minus whitelist +udev_blacklist += ''.join(chr(i) for i in range(32)) # ASCII non-printable +
    [docs]def udev_escape(label): + out = '' + for ch in label: + out += ch if ch not in udev_blacklist else '\\x%02x' % ord(ch) + return out
    + +
    [docs]def string_lower(string): + """ Return a lowercase string. + + :param string: String to lowercase + + This is used as a filter in the templates. + """ + return string.lower()
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_modules/pylorax/treeinfo.html b/f32-branch/_modules/pylorax/treeinfo.html new file mode 100644 index 00000000..f47d9a81 --- /dev/null +++ b/f32-branch/_modules/pylorax/treeinfo.html @@ -0,0 +1,264 @@ + + + + + + + + + + + pylorax.treeinfo — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.treeinfo

    +#
    +# treeinfo.py
    +#
    +# Copyright (C) 2010-2015 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Red Hat Author(s):  Martin Gracik <mgracik@redhat.com>
    +#
    +
    +import logging
    +logger = logging.getLogger("pylorax.treeinfo")
    +
    +import configparser
    +import os
    +import time
    +
    +
    +
    [docs]class TreeInfo(object): + + def __init__(self, product, version, variant, basearch, + packagedir=""): + + self.c = configparser.ConfigParser() + + if 'SOURCE_DATE_EPOCH' in os.environ: + timestamp = os.environ['SOURCE_DATE_EPOCH'] + else: + timestamp = str(time.time()) + + section = "general" + data = {"timestamp": timestamp, + "family": product, + "version": version, + "name": "%s-%s" % (product, version), + "variant": variant or "", + "arch": basearch, + "packagedir": packagedir} + + self.c.add_section(section) + list(self.c.set(section, key, value) for key, value in data.items()) + +
    [docs] def add_section(self, section, data): + if not self.c.has_section(section): + self.c.add_section(section) + + list(self.c.set(section, key, value) for key, value in data.items())
    + +
    [docs] def write(self, outfile): + logger.info("writing .treeinfo file") + with open(outfile, "w") as fobj: + self.c.write(fobj)
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/f32-branch/_sources/composer-cli.rst.txt b/f32-branch/_sources/composer-cli.rst.txt new file mode 100644 index 00000000..c5857f32 --- /dev/null +++ b/f32-branch/_sources/composer-cli.rst.txt @@ -0,0 +1,178 @@ +composer-cli +============ + +:Authors: + Brian C. Lane + +``composer-cli`` is used to interact with the ``lorax-composer`` API server, managing blueprints, exploring available packages, and building new images. + +It requires `lorax-composer `_ to be installed on the +local system, and the user running it needs to be a member of the ``weldr`` +group. They do not need to be root, but all of the `security precautions +`_ apply. + +composer-cli cmdline arguments +------------------------------ + +.. argparse:: + :ref: composer.cli.cmdline.composer_cli_parser + :prog: composer-cli + +Edit a Blueprint +---------------- + +Start out by listing the available blueprints using ``composer-cli blueprints +list``, pick one and save it to the local directory by running ``composer-cli +blueprints save http-server``. If there are no blueprints available you can +copy one of the examples `from the test suite +`_. + +Edit the file (it will be saved with a .toml extension) and change the +description, add a package or module to it. Send it back to the server by +running ``composer-cli blueprints push http-server.toml``. You can verify that it was +saved by viewing the changelog - ``composer-cli blueprints changes http-server``. + +Build an image +---------------- + +Build a ``qcow2`` disk image from this blueprint by running ``composer-cli +compose start http-server qcow2``. It will print a UUID that you can use to +keep track of the build. You can also cancel the build if needed. + +The available types of images is displayed by ``composer-cli compose types``. +Currently this consists of: alibaba, ami, ext4-filesystem, google, hyper-v, +live-iso, openstack, partitioned-disk, qcow2, tar, vhd, vmdk + +You can optionally start an upload of the finished image, see `Image Uploads`_ for +more information. + + +Monitor the build status +------------------------ + +Monitor it using ``composer-cli compose status``, which will show the status of +all the builds on the system. You can view the end of the anaconda build logs +once it is in the ``RUNNING`` state using ``composer-cli compose log UUID`` +where UUID is the UUID returned by the start command. + +Once the build is in the ``FINISHED`` state you can download the image. + +Download the image +------------------ + +Downloading the final image is done with ``composer-cli compose image UUID`` and it will +save the qcow2 image as ``UUID-disk.qcow2`` which you can then use to boot a VM like this:: + + qemu-kvm --name test-image -m 1024 -hda ./UUID-disk.qcow2 + + +Image Uploads +------------- + +``composer-cli`` can upload the images to a number of services, including AWS, +OpenStack, and vSphere. The upload can be started when the build is finished, +by using ``composer-cli compose start ...`` or an existing image can be uploaded +with ``composer-cli upload start ...``. In order to access the service you need +to pass authentication details to composer-cli using a TOML file, or reference +a previously saved profile. + + +Providers +--------- + +Providers are the services providers with Ansible playbook support under +``/usr/share/lorax/lifted/providers/``, you will need to gather some provider +specific information in order to authenticate with it. You can view the +required fields using ``composer-cli providers template ``, eg. for AWS +you would run:: + + composer-cli upload template aws + +The output looks like this:: + + provider = "aws" + + [settings] + aws_access_key = "AWS Access Key" + aws_bucket = "AWS Bucket" + aws_region = "AWS Region" + aws_secret_key = "AWS Secret Key" + +Save this into an ``aws-credentials.toml`` file and use it when running ``start``. + +AWS +^^^ + +The access key and secret key can be created by going to the +``IAM->Users->Security Credentials`` section and creating a new access key. The +secret key will only be shown when it is first created so make sure to record +it in a secure place. The region should be the region that you want to use the +AMI in, and the bucket can be an existing bucket, or a new one, following the +normal AWS bucket naming rules. It will be created if it doesn't already exist. + +When uploading the image it is first uploaded to the s3 bucket, and then +converted to an AMI. If the conversion is successful the s3 object will be +deleted. If it fails, re-trying after correcting the problem will re-use the +object if you have not deleted it in the meantime, speeding up the process. + + +Profiles +-------- + +Profiles store the authentication settings associated with a specific provider. +Providers can have multiple profiles, as long as their names are unique. For +example, you may have one profile for testing and another for production +uploads. + +Profiles are created by pushing the provider settings template to the server using +``composer-cli providers push `` where ``PROFILE.TOML`` is the same as the +provider template, but with the addition of a ``profile`` field. For example, an AWS +profile named ``test-uploads`` would look like this:: + + provider = "aws" + profile = "test-uploads" + + [settings] + aws_access_key = "AWS Access Key" + aws_bucket = "AWS Bucket" + aws_region = "AWS Region" + aws_secret_key = "AWS Secret Key" + +You can view the profile by using ``composer-cli providers aws test-uploads``. + + +Build an image and upload results +--------------------------------- + +If you have a profile named ``test-uploads``:: + + composer-cli compose start example-http-server ami "http image" aws test-uploads + +Or if you have the settings stored in a TOML file:: + + composer-cli compose start example-http-server ami "http image" aws-settings.toml + +It will return the UUID of the image build, and the UUID of the upload. Once +the build has finished successfully it will start the upload process, which you +can monitor with ``composer-cli upload info `` + +You can also view the upload logs from the Ansible playbook with:: + + ``composer-cli upload log `` + +The type of the image must match the type supported by the provider. + + +Upload an existing image +------------------------ + +You can upload previously built images, as long as they are in the ``FINISHED`` state, using ``composer-cli upload start ...```. If you have a profile named ``test-uploads``:: + + composer-cli upload start "http-image" aws test-uploads + +Or if you have the settings stored in a TOML file:: + + composer-cli upload start "http-image" aws-settings.toml + +This will output the UUID of the upload, which can then be used to monitor the status in the same way +described above. diff --git a/f32-branch/_sources/composer.cli.rst.txt b/f32-branch/_sources/composer.cli.rst.txt new file mode 100644 index 00000000..c1366a8e --- /dev/null +++ b/f32-branch/_sources/composer.cli.rst.txt @@ -0,0 +1,102 @@ +composer.cli package +==================== + +Submodules +---------- + +composer.cli.blueprints module +------------------------------ + +.. automodule:: composer.cli.blueprints + :members: + :undoc-members: + :show-inheritance: + +composer.cli.cmdline module +--------------------------- + +.. automodule:: composer.cli.cmdline + :members: + :undoc-members: + :show-inheritance: + +composer.cli.compose module +--------------------------- + +.. automodule:: composer.cli.compose + :members: + :undoc-members: + :show-inheritance: + +composer.cli.help module +------------------------ + +.. automodule:: composer.cli.help + :members: + :undoc-members: + :show-inheritance: + +composer.cli.modules module +--------------------------- + +.. automodule:: composer.cli.modules + :members: + :undoc-members: + :show-inheritance: + +composer.cli.projects module +---------------------------- + +.. automodule:: composer.cli.projects + :members: + :undoc-members: + :show-inheritance: + +composer.cli.providers module +----------------------------- + +.. automodule:: composer.cli.providers + :members: + :undoc-members: + :show-inheritance: + +composer.cli.sources module +--------------------------- + +.. automodule:: composer.cli.sources + :members: + :undoc-members: + :show-inheritance: + +composer.cli.status module +-------------------------- + +.. automodule:: composer.cli.status + :members: + :undoc-members: + :show-inheritance: + +composer.cli.upload module +-------------------------- + +.. automodule:: composer.cli.upload + :members: + :undoc-members: + :show-inheritance: + +composer.cli.utilities module +----------------------------- + +.. automodule:: composer.cli.utilities + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: composer.cli + :members: + :undoc-members: + :show-inheritance: diff --git a/f32-branch/_sources/composer.rst.txt b/f32-branch/_sources/composer.rst.txt new file mode 100644 index 00000000..dd0c06cb --- /dev/null +++ b/f32-branch/_sources/composer.rst.txt @@ -0,0 +1,37 @@ +composer package +================ + +Subpackages +----------- + +.. toctree:: + + composer.cli + +Submodules +---------- + +composer.http\_client module +---------------------------- + +.. automodule:: composer.http_client + :members: + :undoc-members: + :show-inheritance: + +composer.unix\_socket module +---------------------------- + +.. automodule:: composer.unix_socket + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: composer + :members: + :undoc-members: + :show-inheritance: diff --git a/f32-branch/_sources/index.rst.txt b/f32-branch/_sources/index.rst.txt new file mode 100644 index 00000000..9000845d --- /dev/null +++ b/f32-branch/_sources/index.rst.txt @@ -0,0 +1,39 @@ +.. Lorax documentation master file, created by + sphinx-quickstart on Wed Apr 8 13:46:00 2015. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Lorax's documentation! +================================= + +Contents: + +.. toctree:: + :maxdepth: 1 + + intro + lorax + livemedia-creator + lorax-composer + composer-cli + mkksiso + product-images + modules + +Documentation for other Lorax Branches +====================================== + +* `Fedora 31 `_ +* `Fedora 30 `_ +* `Fedora 29 `_ +* `Fedora 28 `_ +* `RHEL8 lorax-composer `_ +* `RHEL7 lorax-composer `_ + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/f32-branch/_sources/intro.rst.txt b/f32-branch/_sources/intro.rst.txt new file mode 100644 index 00000000..01857ee9 --- /dev/null +++ b/f32-branch/_sources/intro.rst.txt @@ -0,0 +1,67 @@ +Introduction to Lorax +===================== + +I am the Lorax. I speak for the trees [and images]. + +Lorax is used to build the Anaconda Installer boot.iso, it consists of a +library, pylorax, a set of templates, and the lorax script. Its operation +is driven by a customized set of Mako templates that lists the packages +to be installed, steps to execute to remove unneeded files, and creation +of the iso for all of the supported architectures. + + + + + + +Before Lorax +============ + +Tree building tools such as pungi and revisor rely on 'buildinstall' in +anaconda/scripts/ to produce the boot images and other such control files +in the final tree. The existing buildinstall scripts written in a mix of +bash and Python are unmaintainable. Lorax is an attempt to replace them +with something more flexible. + + +EXISTING WORKFLOW: + +pungi and other tools call scripts/buildinstall, which in turn call other +scripts to do the image building and data generation. Here's how it +currently looks: + + -> buildinstall + * process command line options + * write temporary yum.conf to point to correct repo + * find anaconda release RPM + * unpack RPM, pull in those versions of upd-instroot, mk-images, + maketreeinfo.py, makestamp.py, and buildinstall + + -> call upd-instroot + + -> call maketreeinfo.py + + -> call mk-images (which figures out which mk-images.ARCH to call) + + -> call makestamp.py + + * clean up + + +PROBLEMS: + +The existing workflow presents some problems with maintaining the scripts. +First, almost all knowledge of what goes in to the stage 1 and stage 2 +images lives in upd-instroot. The mk-images* scripts copy things from the +root created by upd-instroot in order to build the stage 1 image, though +it's not completely clear from reading the scripts. + + +NEW IDEAS: + +Create a new central driver with all information living in Python modules. +Configuration files will provide the knowledge previously contained in the +upd-instroot and mk-images* scripts. + + + diff --git a/f32-branch/_sources/lifted.rst.txt b/f32-branch/_sources/lifted.rst.txt new file mode 100644 index 00000000..a9c4b004 --- /dev/null +++ b/f32-branch/_sources/lifted.rst.txt @@ -0,0 +1,46 @@ +lifted package +============== + +Submodules +---------- + +lifted.config module +-------------------- + +.. automodule:: lifted.config + :members: + :undoc-members: + :show-inheritance: + +lifted.providers module +----------------------- + +.. automodule:: lifted.providers + :members: + :undoc-members: + :show-inheritance: + +lifted.queue module +------------------- + +.. automodule:: lifted.queue + :members: + :undoc-members: + :show-inheritance: + +lifted.upload module +-------------------- + +.. automodule:: lifted.upload + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: lifted + :members: + :undoc-members: + :show-inheritance: diff --git a/f32-branch/_sources/livemedia-creator.rst.txt b/f32-branch/_sources/livemedia-creator.rst.txt new file mode 100644 index 00000000..962be311 --- /dev/null +++ b/f32-branch/_sources/livemedia-creator.rst.txt @@ -0,0 +1,670 @@ +livemedia-creator +================= + +:Authors: + Brian C. Lane + +livemedia-creator uses `Anaconda `_, +`kickstart `_ and `Lorax +`_ to create bootable media that use the +same install path as a normal system installation. It can be used to make live +isos, bootable (partitioned) disk images, tarfiles, and filesystem images for +use with virtualization and container solutions like libvirt, docker, and +OpenStack. + +The general idea is to use qemu with kickstart and an Anaconda boot.iso to +install into a disk image and then use the disk image to create the bootable +media. + +livemedia-creator --help will describe all of the options available. At the +minimum you need: + +``--make-iso`` to create a final bootable .iso or one of the other ``--make-*`` options. + +``--iso`` to specify the Anaconda install media to use with qemu. + +``--ks`` to select the kickstart file describing what to install. + +To use livemedia-creator with virtualization you will need to have qemu installed. + +If you are going to be using Anaconda directly, with ``--no-virt`` mode, make sure +you have the anaconda-tui package installed. + +Conventions used in this document: + +``lmc`` is an abbreviation for livemedia-creator. + +``builder`` is the system where livemedia-creator is being run + +``image`` is the disk image being created by running livemedia-creator + + +livemedia-creator cmdline arguments +----------------------------------- + +.. argparse:: + :ref: pylorax.cmdline.lmc_parser + :prog: livemedia-creator + + --macboot : @replace + Make the iso bootable on UEFI based Mac systems + + Default: True + + --nomacboot : @replace + Do not create a Mac bootable iso + + Default: False + + +Quickstart +---------- + +Run this to create a bootable live iso:: + + sudo livemedia-creator --make-iso \ + --iso=/extra/iso/boot.iso --ks=./docs/fedora-livemedia.ks + +You can run it directly from the lorax git repo like this:: + + sudo PATH=./src/sbin/:$PATH PYTHONPATH=./src/ ./src/sbin/livemedia-creator \ + --make-iso --iso=/extra/iso/boot.iso \ + --ks=./docs/fedora-livemedia.ks --lorax-templates=./share/ + +You can observe the installation using vnc. The logs will show what port was +chosen, or you can use a specific port by passing it. eg. ``--vnc vnc:127.0.0.1:5`` + +This is usually a good idea when testing changes to the kickstart. lmc tries +to monitor the logs for fatal errors, but may not catch everything. + + +How ISO creation works +---------------------- + +There are 2 stages, the install stage which produces a disk or filesystem image +as its output, and the boot media creation which uses the image as its input. +Normally you would run both stages, but it is possible to stop after the +install stage, by using ``--image-only``, or to skip the install stage and use +a previously created disk image by passing ``--disk-image`` or ``--fs-image`` + +When creating an iso qemu boots using the passed Anaconda installer iso +and installs the system based on the kickstart. The ``%post`` section of the +kickstart is used to customize the installed system in the same way that +current spin-kickstarts do. + +livemedia-creator monitors the install process for problems by watching the +install logs. They are written to the current directory or to the base +directory specified by the --logfile command. You can also monitor the install +by using a vnc client. This is recommended when first modifying a kickstart, +since there are still places where Anaconda may get stuck without the log +monitor catching it. + +The output from this process is a partitioned disk image. kpartx can be used +to mount and examine it when there is a problem with the install. It can also +be booted using kvm. + +When creating an iso the disk image's / partition is copied into a formatted +filesystem image which is then used as the input to lorax for creation of the +final media. + +The final image is created by lorax, using the templates in /usr/share/lorax/live/ +or the live directory below the directory specified by ``--lorax-templates``. The +templates are written using the Mako template system with some extra commands +added by lorax. + +.. note:: + The output from --make-iso includes the artifacts used to create the boot.iso; + the kernel, initrd, the squashfs filesystem, etc. If you only want the + boot.iso you can pass ``--iso-only`` and the other files will be removed. You + can also name the iso by using ``--iso-name my-live.iso``. + + +Kickstarts +---------- + +The docs/ directory includes several example kickstarts, one to create a live +desktop iso using GNOME, and another to create a minimal disk image. When +creating your own kickstarts you should start with the minimal example, it +includes several needed packages that are not always included by dependencies. + +Or you can use existing spin kickstarts to create live media with a few +changes. Here are the steps I used to convert the Fedora XFCE spin. + +1. Flatten the xfce kickstart using ksflatten +2. Add zerombr so you don't get the disk init dialog +3. Add clearpart --all +4. Add swap partition +5. bootloader target +6. Add shutdown to the kickstart +7. Add network --bootproto=dhcp --activate to activate the network + This works for F16 builds but for F15 and before you need to pass + something on the cmdline that activate the network, like sshd: + + ``livemedia-creator --kernel-args="sshd"`` + +8. Add a root password:: + + rootpw rootme + network --bootproto=dhcp --activate + zerombr + clearpart --all + bootloader --location=mbr + part swap --size=512 + shutdown + +9. In the livesys script section of the %post remove the root password. This + really depends on how the spin wants to work. You could add the live user + that you create to the %wheel group so that sudo works if you wanted to. + + ``passwd -d root > /dev/null`` + +10. Remove /etc/fstab in %post, dracut handles mounting the rootfs + + ``cat /dev/null > /dev/fstab`` + + Do this only for live iso's, the filesystem will be mounted read only if + there is no /etc/fstab + +11. Don't delete initramfs files from /boot in %post +12. When creating live iso's you need to have, at least, these packages in the %package section:: + dracut-config-generic + dracut-live + -dracut-config-rescue + grub2-efi + memtest86+ + syslinux + +User created repositories +~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you are using your own repositories and installing groups (eg. @core) make +sure you create the repodata with groups like this ``createrepo -g +/path/to/groups.xml /path/to/rpms`` + +Using a Proxy with repos +~~~~~~~~~~~~~~~~~~~~~~~~ + +One drawback to using qemu is that it pulls the packages from the repo each +time you run it. To speed things up you either need a local mirror of the +packages, or you can use a caching proxy. When using a proxy you pass it to +livemedia-creator like this: + + ``--proxy=http://proxy.yourdomain.com:3128`` + +You also need to use a specific mirror instead of mirrormanager so that the +packages will get cached, so your kickstart url would look like: + + ``url --url="http://dl.fedoraproject.org/pub/fedora/linux/development/rawhide/x86_64/os/"`` + +You can also add an update repo, but don't name it updates. Add --proxy to it +as well. You can use all of the `kickstart commands `_ in your kickstart. Make sure there +is only one ``url`` command, other repos have to use the ``repo`` command and cannot be +named ``updates`` which is reserved for Anaconda's use. eg.:: + + url --url=PRIMARY-REPO-URL --proxy=PROXY-URL + repo --name="repo1" --baseurl=FIRST-REPO-URL --proxy=PROXY-URL + repo --name="repo2" --baseurl=SECOND-REPO_URL --proxy=PROXY-URL + + +Anaconda image install (no-virt) +-------------------------------- + +You can create images without using qemu by passing ``--no-virt`` on the +cmdline. This will use Anaconda's directory install feature to handle the +install. There are a couple of things to keep in mind when doing this: + +1. It will be most reliable when building images for the same release that the + host is running. Because Anaconda has expectations about the system it is + running under you may encounter strange bugs if you try to build newer or + older releases. + +2. It may totally trash your host. So far I haven't had this happen, but the + possibility exists that a bug in Anaconda could result in it operating on + real devices. I recommend running it in a virt or on a system that you can + afford to lose all data from. + +The logs from anaconda will be placed in an ./anaconda/ directory in either +the current directory or in the directory used for --logfile + +Example cmdline: + +``sudo livemedia-creator --make-iso --no-virt --ks=./fedora-livemedia.ks`` + +.. note:: + Using no-virt to create a partitioned disk image (eg. --make-disk or + --make-vagrant) will only create disks usable on the host platform (BIOS + or UEFI). You can create BIOS partitioned disk images on UEFI by using + virt. + +.. note:: + As of version 30.7 SELinux can be set to Enforcing. The current state is + logged for debugging purposes and if there are SELinux denials they should + be reported as a bug. + +AMI Images +---------- + +Amazon EC2 images can be created by using the --make-ami switch and an appropriate +kickstart file. All of the work to customize the image is handled by the kickstart. +The example currently included was modified from the cloud-kickstarts version so +that it would work with livemedia-creator. + +Example cmdline: + +``sudo livemedia-creator --make-ami --iso=/path/to/boot.iso --ks=./docs/fedora-livemedia-ec2.ks`` + +This will produce an ami-root.img file in the working directory. + +At this time I have not tested the image with EC2. Feedback would be welcome. + + +Appliance Creation +------------------ + +livemedia-creator can now replace appliance-tools by using the --make-appliance +switch. This will create the partitioned disk image and an XML file that can be +used with virt-image to setup a virtual system. + +The XML is generated using the Mako template from +/usr/share/lorax/appliance/libvirt.xml You can use a different template by +passing ``--app-template

    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 + + + + + + + + composer.cli — Lorax 32.12 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    vAUiV^2VR&yLz)ZxZ2~5I-O47XO-P?im9l!pz?ZB%g-QBqWR-k*o*$zt&-fhG&Sm)j>i`>tnYaq@Z$b2Z<%2i2qL#w05%#BkFw zS~lmYk%o;7)PkERl1x{wPUXKOi;8In6dv6M@|oxCwx|L1MTP9zqGIt_GA%W1HXFy{f<)P20ykGoSiYtv z=?c%S#^m#r#$kQ$G!e(~7es$E#L1FQ7?JiUt`=Eosm%LxC#0MBOcqJMZQCA@cj|jD zVG$O)Ac{OJE#!Zo4MN1xh66`skmok}eB*RunH!G`#wwdwG&vWsY5T*Nwg-iU{dRF) zZ?XS5x0rhEL3gh~)iA74izzEBq#t^jQBSrQ*oY0H4ulm{qIP|}x$TPz@n_E!E0M15 z(OA=(HeF9Oxat?iJw5s~O|MwU#gfAR0m(={M4fl)%vWDwMPupGl`fW+*Rrw=WT)Ie zOS?;oYP%N|OJ`d1B$>nAaAb)J6?N|U07fN&X?TTHDJiN$zNlDQ0}cR~PvDcA|LQ9u zMs8XWVkJ91V1@~pTrnZMn-P+SH0uB!Z1&qadjtWUuu5_xe$seNif**%&g!5gr5ax> z;6)z1xOA9}b3*EP@B3t~*Mnoa0qhzmMq-t%`?`I{k5Y zowk(>~eO`vOAn zk!)&9U3QH0Tc?=vFEQW$GQfKQD)4w5n&hX%sgiYeju;1DNcg__$KU?W%LI_{ZP=kG7LXNN&lRjvO&UQbf4lU1{#(F1rgQ;Q2rjT{&i{ zYjD?H4DF`A}Is6qHL9pXoVCJ*enRSD29c zdqKYVgOlK~?zitDya@N?d)8f2VP4x(0(@moP?At|O}XFV*b+VjGpZH7tgwur z-vm0xye0Dtl{{;|u5GtTen=zsyt z+v`SBW#xqGeLWwqLu3Xme762#dz}a;T^)_%TqC_d7)E+cp!yAopDa_d|sC?eEyVP_*JC>If~ z+nbHUL95<{?g=fIUw6*>QO2m(-h0{T+qp4vjHHm#Y%xapQu8z%gJDJ~f`$tT&CHfa zNlb;rtz!W{qqo^j0qbp^R&TSPXNuj$8T0P_vsHZH3Q5JkWz1x$(ce3Aiq;8^bT%8# zF781Aqb0qKwdBgFElQGVTC|)JRji`>Od+Yom!b_3m&`rgWXk+4mjweqFX66`$@y|Z z|L#zFY9=ygvi@}Me!u;|^mWC)7M2kfE}ztrIoL6H`~aGtUuIZg4-h;^Ypq*9=}}e= z7r}H@advhj<^GPTL4~1TEGhN)D#J?t@wdMxOPp>$ftKs;xF&cWjv{ST3%;Bo9oL&D zJGKTDy`3*7{9o+sI2>k&fr&J%bnxIDM@i%4RkPbZ(XfUa9%X-Ue0;jo=Wrs^2^HH` zX<@0yzwCsFT$u%=WkDWgMBn=KBng5z*$E@e!A>&k(Mu`?l3{yTu9#HkVAM2-^oJ%}w?<5}wv^k7B-sWKHhW&`B~z?{1N|{PskU}ddjq~EG{ra%YIWxm_K6E6jo&6cyz1L zeT5@t=DXsHcK42&uh7$Ga#gqz3I&DtLk@xiOR5$EAHxM_3vyBR{#fPNDDql5BSy zZqT#-@133?&4~3J$MnCHlZJj*m(PxtKR}4J2ff7UBRUZGFeUJ48kX7-y1V6^dtQ(* zO4CLtf?<>(kz!Jp_vK@;D$DoS!gx39WHi3nuHjG*QZN51-jitJ3_z-Ioz9a*fYDjs zGJ|8@U&~YPH(r_LR^h-cDJpcg7H9*3rxH?(wk-IyFR{<+WD&?wEcR|IvmbGOJ#-jy1!}U zX3IAI#GPxm&UWsB)7Y&O<%H;So;3Je+^=No40g&H-%+?I*0j5Jg=f>265`vicYwjP zi}VlS;Z|l_@?gK2-z)$ya!Yo_gzD3}`^a1f+irH?`hW`Dt-ntAPYG^e)oF=jvj`=S zypOgPJ85HvGbk%HxH?DQB@Qofag?C*{kaS6|M5dJT_gI_l@f|4?i06>jEQd^f1S{O zAKZ8Uef-e<_sOG#739SeSiIP>xxc;Qx4XYxB4*tpf3k}@srb`3|^vpS) zad}Cdo3)l>J`GPyYq^wAU6;5~Zc1oR`1P@ipZE5f_6RIueP}r$s_AEL7;d&8@}!^a zHu|p{jgy4_C`UVUTl33oA%@Mw`)6Y`6QzXxOAz1_bMt^XUoO2W4{wG0>?ZLo+$Esi`jiahgbF1Ar7AVN5?d*S&vhc7koU1Hm1j=oDhFNF%^X4 zrZRmXrvSoHQJvgu{ndKkVrJ{F_l4)v-CyrBg+#Bj!M6KrvvZ%U1vMT`3-RaxVySWu zxJ0y2%L(&6{mk@wf~#NFI4>;xQ+jw|+q`#Zr*uS{QAC(O$3K}A<}pP?{{S)g8W+@k z_;nIonDMRv6zW^C5MhXNA))<>KQJ*LNbDk*3DANJ@2GqeALoF4oY`d5X1#ss?T-OIy8COWAAizNq%wCENBct}M0c9lxlpPeZv)@JRRiS z3+IL#6frx4339SGKswWtoN*g9L3~lE2FwTfs*e-C#vVd-b0->z(RXxKONeT-mK3s^ zbUu~gB^?*4O4Hw)g4v(%I`4>G1rerT5kcth75~Crzf#9l_#<*kA(n(fh+0s*#ftKJ zKFT5zoP$kl6n})CAC{H6Kp16sIuoJVS?(xoV6vF{f-qwh4e*1z_fvXfp z$NJK|hXheD)gkzQ>0=6>eX46op?U~z!Qz%a*ZVfS+Q|_}`NQN;OMc7iE}ZfNP)Ilu zH|4dcR0lf`SBKEF=jkU|3KHt^V4v$)CsNct*HPE{7kjvr!ZcfS)wm5q5%Mx%q3 zfWOe=1$>OiE%xRt{SC+PrteYzQRb`^la@lBFbdP-93Rn(5c~)feTn@?^tVjqpjKxZ zPWQB97krF{LxqI<%RTzQ%o<5U0SbFZ4QO;YDE|esyVs+KJGtT6Mo-18XFX=ONPx!M@gONG883Lh8|xRE-Q6;Aa&vIWSrc;A>J_SA!A&WzUwS*Os;PbUW|SvjoYmJsQP4O zr9OA&2lSn4nt`6p-QcAwnK!C)hYEItbPb9M>HEP~+y@JkX(2eT_FEbKu(&KDwlZH( zC?}X=n`7-U)x5%p-xc#LMJS9~PT>DpKXY@St>Pq39J%9YIm^KV zPW$nRSp3ce!wE0@*!6<)qjn}KCQSb-AKeUbh|qa{f#Jz-LNPyQMPjwAjWvPuXmTWB zME9sZ+3ba{6laQstnV?iH!CXjLTX8mhC3CwylLCsJUGZ}L@{l5#f0PYefN>u{;bi0 z0?>030op(GZ}k3tqXi9=sIwW>w2E-djB4t|b5J_Dz0mBDZGDXE`Ocprp-uE0j9Q{z zRMSl@cfAfKK`0m^#8FsQ+WqlX`=I~2jspaDPfDj5>Xgx-$(ew_AJ88dgOEH%Kxjc> zen_=pB)5d2`SJxSn&erinaW8Qf|?t6yq<^)2c{x11MiASHNHkhNJ8OCY|}qj)MLlQ zA(68C3!mr-ZUll%d3l-nh}_c{wUO;&>oMwiKcHNjzUdgsmhn;%kQDxk&_pGF`BYo zmq@_Iv*bh52kRC;9#>QI{}x~K5JT$ym9{GU+xIRt67?#NGAvPIC%Na3 zpj|mQJK!hFrJIa6g0`ilF1PKs-zVqz28lSn^x$nMrj^`6Lz9|e5%P@s!8@v?U_PH}gnu$CDXo8!eS;A|$P3R;{*sp|&r~^H z#ECUbE5t(A5s^<7%1zqwJcX_TuB=q*lkmImp*y+6+OAg8UpzSZ3Q)+BovG2Q#sojT zFBM=sRDk~*PD!tdyB`)+wg^=`C~DiyXxJ!_LIpkrSn3q3NniT3NnT%sag7{Mou;*& zBlJaIP^fGE3#Tu(+kLEhNk~Y$C^%GcbpBcIEo|Vd&g>Qu-a;xP%pcLenKV3^qc1}* zp||+3o19o*S&Y&}g@o@jMsS31E91m^KXG5V;}4vI9Pf%1l&v`3yR6WOS#iFk@L%&@ zXul!axqMI`wE7xY6mEVIb2%(4d|!s&akCc&#~qiv!QJP_IPW#+*qPR}@92X)#G;yU zjp%4DR2k zvu}!07e-Ea@#RC!?4*tmUs*|^y^7dey8E0gY4{pXBk%S<=y$M|OxH$u-CZf)GREL$ zEp2Zk8Y~QBfg&}iJF}KaO7EO^E~aI^q|)l4P44=$T=%o1D1~i*#*CsC)b8}VfwFUV zW`cr#&rZ3sP8TgGL_hGc2_bR6(k%!aTHq{-ykc4@7LwWV9OZu?`An%T!x*y(m6nG# zint=jNLE7X^T$JX^D37f9ruFRL!{|0{k+1HdblHW)_LVh3FUqFiQ7Mq^Vd_f%ITfz zi==x-EH?E%5)HbSS}0Bjc%}}39-#;=E z8?Qj&CV&KFcu(+Q?rCcVR#(wP? znn?aLY_Q3ya|Y7Ia>LLw1dPI&z`+q9a(}plRIE+VoyBL{t1F3fIJIzB zS*TGdZ>=(f6M1IvBedI~s8k3u1{D$kN^)h3GHBxsFRBJjz@PYELT87hf991&i$jQS z(7)Z(+lG1&99{$s#jizO2>U*&p}wf_@vCowmeH1ICEkO}m8BFL&BlM`BBCQan6|W3 zf{i~o+69yALFqP{a$Qqb#53v=*K%I+-bE6i+AS=?tPIOaeK=v3)JIebV&^{c(iYAq6o#^ zl@i7;+$Sbnp!9$U>_Dghwp|JrAQ6RQ8q^90L=XplcZb+8y%({&qlj>RjDIqrGc%bD zUqP`_)yBCOyhiQ*nBROORCixcn7{O2Fh6M*_$EyKj|RKnP;-5_r!RIFC;N2@Z7{8m z2=^=^NR@88oG8V=Qw99yU%XEpvH5c$p?QzmD#z$s>O)&`sYvWR#-&a;Tul3bF>)Te zV#0=TWE3}#<=-tjKMtq84ltG>=sT=AWUjaLuvEpNPfOuK`-Wk}bh#4w~*X9A&P^~D&0&{1{qi#6Oo zlSYyj!UKuTnw(IS%J6uAt`H!KYYWcnEKjEP?0}-*cP#LMrNAz#5$G>l_uR$r~Gi9F12uGsxWn%Ld z?#sq0g{K-qAdOnDQcO5MlaEYGF(0a$h{TXT^B(P&Esi-@mp0T9%T~(?_if?us`*x6 z$@;M-$LL-iak+*qVv75MLidILf*ZSu`Gym+Iy*cm^p{O;`VBYMZ?*J}Zcbx}*lJxV zVgB5GVp=Dv#Q&#Pu}KlqJTiWK%QDLWaMbupF`@oUJ~FpveuKY;&Zka!O1nXzndLQN zg+L%WLjFy^M`*;hbk+qNxCbSaFimybSHUZ5K7)Zm`5V=tc@UAoAYWc8^J)HjQyoth zF74K@$9CtBSlU!Z7;E%zW}&kTP3Mz^y{!Dl>YO#m{WPGsrQNo@eGAl4(?E&|{{#8R zRajM#-hgyxa5y1wF%=gMnsj>UoZ-9*OfB%bu9*vwwLmec#YaSkk5UWwZ}PYJ_$iu( ze&yl$Gg$71GGgVqQo{JhEqx*ffm+TH02P6D7m{<^w9y)wio%7b+oGBoKHl~xLE&b~ zdiQyaofz_*r!-He~#EqjnFsw|uv~jD=y>7dQkY6aBaD?Dm9nMzhSe4ot)Zx`$*V-phb)ZsN z9q1F+0eQ#|2CYQiUY7G-vbk5ck{|I#K+>hB=J50~>fj@(+rtX>MPGy&%7ujF5B!1K?*7G6Ls}(l-bOn)dvHFA2-7|M zlXp+sqIGCDiW^Iq#;V& zQxkFD{HUYV76F6c6|1d9jJ6b$c7Gusx!L6MfDeFB`J^@UzA(3U&(l){lniQ&#D_sq zsl(&oE3Sw7XWPm8))rs;haO3R1(Ic|;my@-8ekj4O9D2hOUyKoa#EGg*6DNdgS#Ay zGwF&1pfgEl_lk;U+XkTdHn=nqxK3ZCbVD6 zN9JAU%s^R=6IMrDxvpq&`)Nj(zYtOmUzAwQDMEz`{70a2`aB@xqIJ6io^^e-xe2wf0n!B_VYW&5oh@G7WKrsL*o4{BQc1sgq1*4ah)h zost08pRle1{Seyq0sn#3yl@-q(1Y~(^&C|xS57MRNO8DQa*f0Vv^qhuiuj22t>mZV zF8{K`=IFHXmowWvu9Vc`5AKs2ll6@UWeQU^_u9Rt^)JQDJt`z@Uw7yOlaV|*ZsY18 z?b_JMHrBV6f6{H#hYx3KzSG6tYUV-An&(nN{$YndF+0l_O4S74CV$H=^Z)wY@BZm` z^uNq^4*ijYt04y7$eHho3G?+pcy74AxK*9W=)S$+5OFrr>1$?=kMK`7fW5|Gzg>e0 z;&K|8+XWfdYkL$B!}VGdZhg>s?GkQLlYD#|tr3m9@d#&9wpMH0^lu&=}KDqvNk@e2+k?eNy3LG?$zyXu3lvCUT zGtG`!DO5;kpLFPho2%xfVHXL6Xm|Edv`5K@bE{5fvK*K@bE{6h%=KMS1Ttb7yvE@hj`T zzkeQ>**WKPZl8PZIp>B&C>dU(`$Zc)5*pd!>-_i$gfpJ^t&WMN@@An@2xIR%vwjW}4@C(b1&AFM^5e>PF5}k$$DI zOH%yo7|gRAJfixq<%p&V%TX)(DN>I3#b`$KgcANKywkM?;65;BzVu@ac$%w zw(bODqcg?@XR+{16Si$9L{AEyEhk<&GY~zJD2!e@@*xtvb7Ttt$mf*wFJ%ZOp$%## ziIw~yhZF5?VX`n*+wfx~TKs?xzSN&M@qmu3^PmA?WMsmWSoE}~@T9S3a!l9(GjIxz zrV7hbE&3@^oWUc5{NKGcd`jVNfOp{Ms_lZ z!jP4MKIq~6$zj)Bix$+VgX_x3DRYCH^mGe(+?`#97E-GCrk&tZ`gI#=XHGnmr>@#y z%CB^TdomI=k}8Z^-^*-+rE)gwA2gxIp2kP^s>l@Y=CJpeI=GQG&tR}=;}7JLg5Ej_ zD>(zt6Qv1b*Yf{pS4 z1NRDAw>@l3*V)G}GI6a6lZA0Ah96TS{X;u?>c*TlCKG*3lOn0YfHk6@BJtAnF%A2d z2G_0N938n2OE^9wZ`w=Pj2YR9BB|mVGWxbYJ5lOeK!WEavA$;U23;F6{(LojL$Pk{eMJRP&4sOX3RzgPh(wib>NQBMf<+d* z|Cv1lTAuWY?8{rootXKjDKqI-$?8MJ^R=1-@j+Y*#^dkj}pQcL8R%5 zn!37!$=(u{JR_?+NE3#wsxN&cZlv{18-z=tZ-Z)JP)7?Mb4Hdjejn{mLCcZ1qNm-} zGH@TAnlcRDAoZI_5fYvmrTJT|HWn#Jyds*EJm&a5AQ`BL#?pm_C>S3cIUqLEUFxYM zm_RGI3a4Gpj2zODRAKg2f=6%Gs6#raU}{?mze&6nrCGmzA8d%kE*cqHzp<2I>{FwW zaD$blQC3ro>7 zC`EK&t79v*6+Jm<3Ur$owDir2G@pm1jr=y<89Uvq=NUO;$EP7^5Ikg!?oyFQU8&VB z$5hZiE!YT=wv&XjSL)rw+@xsrEMZGzHNCDEF0)jsUGj4j*W-wbxtlL(6uSgy{B{)B)uP|p|uZSlMi%>THMWhe|BKfB2 zb&|T$$4;Gb+!AMGrHARlcuj+8#v}Pe!o_d!eLH=YH}pi7HQJUK&W{q#zn{A5Jts)l zCnCuGMAf*+_8AHsA8cPLGDtW$+GCx9)AsaCvvubrt4Jm+VTQJD zG+nrq)r~QbPq;G$!;>S`QxzNSRl&xM^%P6pl_M`IPG5b>$gUhq7!Mx%A{ssN>7Tp$ z#cRcpzKCfrFBw_6LI1@tWYx&@!!9cWf-hs|QcD`_Lb3N+*qZTkrUVlccccuQGoz`( zpe>@GA`97T>_~HN#To*GN~1qIg(U@Z1WyTy5uDOkk>-Qc<24xK6&!5|yH>C$Cp=!G$>JL~`Z2Q9VZ9-KldHepfYDRx zM+3)a4onVn2quY}9&~>lW9LjLMFwUL{HHv^BGvt;zeUQ|KMYtga_kMBI3}3z!d?(> zpN^$WPWN0o1MSmkl7{7|ndYlV_|EZp&SytLM@BqUjINyHi;!+d_%B6B-6P^fNRGb3 zX~1M-UxTjY!5(4hBh{&R%{h7cEi1>{2VFAfbc`Yw9erZkYLlNE_=|yGBI*SmR+JSY~#obY0;Rzt{7Z4d^I`t z48RR>umw8I$A6c25XjD1D%~UJjO>A_N#h$M^{X`NChR302@<(~O{~`k7yE>rAOrRK zAW0aqvZ_Ml+#l<>5Y`*wPlY1EQcwLUvy#(wD#*yGKawg8StdF1DH=8U-|#IP=?<_+ z3q{(^n~|MNqA*bFNQ+4%PN%s+PtBl_*f-&@(cm)U8W$b?qS`Vl_AZ-fLrcO1Z*F85 zY1*=6WT_*m!opMva*Z{OghQSqm8D3Dg4tJ+6Bj;cbWOKMWnkeWiNbir2FfAmqa0ke zf)2{5eUjrRPos8&D{G`ZBJGl8VAoBPGz?cU%~z2%9^42;uG^i`bWe%b)Pf%elP9IC zi)P^D6-yTetrGhjiJ{mDL6v`sS z9}8?MhQED5SJ}vePEI%#oR~T+ zOS8mp!?hH7S&csFvBnT*+MqFbnw?QGt)BQq9h(uOAcz-L8;<*87YYkq#3x&NQt$M)<{W-u87Dq0nrwL=-YHtQle7_ zq_&Hs9*-##|MNqolpsxfrwINZi8^p#_fD}XJ>1s?6A@VL!EVv7OUH^$8a8TVIpcAI zN41IXv&z7EK$v`5K9+EFBkh9DZ$`qrvKOoGJ9mYjs+Q5OliVEmHa;vBwb_I;P!)3H)j0CarW4e zlV^<`mvFELIi2XnF-#W5EE|4|E?baeP(2+t*4rDSV=UrL>$As>3cE%o1k6CwdTPor zW`opkq8n9Xz%&ym3W z_yI4 z{bKuC#b79Kn%S6?Bz}dTGiFvMuJF-RVL7TrKShdhe0R(to%%%{MT;7L3LSKhO<4aK zxcAYc);xQ`R2q8FrfF16Q%R1mV82e^y)#IDqQf^#76z&nevB-c&fA^Bnt3<@zUq1K zzR=()yoHMoDUM|lbSR&gz6=={Qk*V%SeAO}zK)csR}dk%iLKbFPp^OI4S8IFW~5A+ z^8ZnwFnL&@mazhbUq=d*_72H?S>(DE)N+!8`4}RljF0pxA66{t%O<#IA3L^Q&|%JH z#{Uy`j@B95ZpUR37PMh%gwD|j1A++gZJPEwJ65fe4yqeyS?u!l;*HjAVWZg!od(^mB|xD%yGo_1BF`8raZ4r#{QM*EMn9}@2w zX2*`#KEs8mr|WOJB4wcVnV32(QDpNgQSjGjwvjS*kBte96e!kXK3qrf+rn6mdeS9c zvNCX6n2e6KH_KA#FJ-G=yWr5W#IBl zho#6VJUV@4+FPZx3on;{nA$UA3!j=eT=*Jcxx$$4N`eB_Rif~#peh=S>bC~cmm(O` zk$x)6jF%#sI9(~CU&eOOpb02emgpZMrHEg|g87Dnen<(&NCvh;G*uY4LG)83U@(V| zXJXM7%*g10u+iVV#^H0(NCDy}iQo^%J)aCRKG8`cOcoZQa`-V)hQYzaZP6zh!@BoP z2pVro4SpV--!NgpGtibAPZ$QS7ylv>Iy!MkY^RI9Hep!0C6C{H%u8Q;$Uv=JnlN-N z|Bpn~u|4)|(%o;+V(R`g(pSUW(RRCB!CP&D*Rv#E9wPIvCbg_zKWH}##*9bDz)YVt zzJBBS;m^ZZMY{!E!pvKt{jg`4Q;=(^c%?jeNqBJE9aQB;BqdKxPCTXj%Zyn6D}5}k zMT>ODjJJ+Q_MW1t=``j|RhdZGl>gGA_YXa=15^^%=D(aB{xNYFEnhHHD%?pTtFTDwkG+Z^m>Vi#1^&yia9qML zLYXc>CCLbRnN^JSQjT{&E1a6{ACA3$xs6DlE(}*hwKAGh+QDdPejW4y$#CT(U9vDn zc`?E>SbRFbezBVa8>~dyglQ(=Ok3&rmn-}~rw*eZH>GEp)SrjF>_^0V*{2QoFRe!Z zJBKi6;hz7{e?QGqCIzc}%GiH6$}_Z-X;a6xV>oUg@dz)UTF~H~4O5IxkBsjOTlUf} z?Y~rV|22~^ez5`5XVi@ZNY`{&BzX7fbkm{L*Hd@em~>6X|8j&JmoN;KyL~L9V9!a+ zKA31d@!Xuz>?I7dFEMyR*ycSn7H+u)^^o#a@<}b`Ac^!IwT=7%EqqH&Yi& z{Y|t3PVfTa*$F3;e`$jLr?g>=lD*728$2l1si$HWGx@}4#w!_5=lmb^gAF>P1|2FA z&y@dC+5aEO!^nj^!qJO1mTRyE3&oQ}n%EN~1?m1*g(Y3GFhcRpkr!Gv3tIdvGdQLqw&^KsB1+BfoQ==SkfL$|D0v3pWd(0CtS;ipd2 z4LlqXSumby&`6Z-l=?4~#l%!$5sIccqYem1?)SBX>7gQS}^|Tb!fP#^UiAPmNPD^3BFl??~sZV`V57=NtK>Dh7 z@cR=Uu+e0(1?mv=jTjf4fPxci(8h0__Wy@j%TpI9nz~WKUX_sr3e$yQ>zz1ku^5Z^AxJ>B@12kHrl!r+w#g-j|)XwrlV=G6=? z`-ywv2}6a6!cc`B^+6tyb=AF7=g5gYU$juipF;no1vgESFzXUwZ8R8zm=fGk2TL(9 z^0Mq;Rpp8PI{k}sYX0wCJ)R)UyzIcp)Cyq;-9>_V-bPOho~kBA-qo5nn&7yn=l}A2 zFf~OOv9s$3OQ z(|@@SPn#x;QO5onopW&P?BEe}?0!M6!B$BdreP++G(2ILhUvp3o^&#{G>uLeCi>(w z%?fCoiKS_L!Z3}~FHMt7glTfZFip~jX_|>JO-~r6Y5FkDG7+ZP3Bxo?AEtRG!Zbf& znC6LL8fW6T3DW#ynC|i8My?6RP2+n1{kRFzoG?tf-Eq^n-hV%C zf;1-#lkT`_T<^ahH$j>chDmqaG_LpGkDDOP3B#m2ZW`D7@5fD$=7eF=9XE~Z{rBT0 zNOQt4#~n8<{`2A4xL%7BhH2rrIXQlY9v#e4Fg}>nFL9{XzjTZ^K4lm(PseyxL4<-SkBqUOiVXWxMk)_9myw_ zYtFHe_nH4+lsC*NmUDIu?Fsp2vb>ReV!7t_>9~hfZ8Ene;(4XXePXgfqzUEDbnanZ zvD|Y8=(WIBKRx(@iXil-5a|K<4 zN6#LU*vB!GM|&)*c;3OwQ%3}ECrT)GCi9ME70Wy4#9(6O;En5Pn{G3?M#7v@b2g4M zagoMJiWofzD{2ai$GPl}w$D@~f*ViEEL4;yA3KPPb}kNMQhV)++| ze>EbuvD5DCT{CxXIX=@^yzEn^r@Ja=@_G@;Czflr;Dsp(oA+Oy$Nk&IST?ad^LWo= zbV|syYb29vJ~gvg{`rEhCQJ_=rldcgx6j- zMr87cOwBBof6n0LH7V)FoM!Sm5$2R8=ioVDVmIzg=N!o?mUFIP&+u-ogteW?BPW(s zEbr{*E=|ZdlgD}_pIEN>lEx;F2oK1F%rkjBrp+!EBe;XiBbT!)! znOijp`Ng8-hz@W~d*#e*=_5mQWBKL^9)%e5`G2v-V_C)W&KVuPm5_BNkJ2!wSkAd; zC+SO*?#+>zygtP9ishbjPB7nV@OJLBD?5|r4s(j-oOh0X&e8Wpq|H5(_1iSL#UfW&XmX1;rzk{-hbfu;)3!MI(4Jt2?DOtx3-XO;G+_6#P4B36^3R zmSY80Vii_n4c1~E-oRT}j}3SS?_nc8z=!x4pI{Ri3CN0U$bp>5jXcPQ{3wV*D1wtw48>6rrBDWC zQ68tDA}XN@s-ik-pcYO=9n?jAG(aOXMpHCH3!H{lXpJ^#i}vV%PUwuT=!PCR1HI52 zeQ_rGV*mzWFot3nhU09Ez_}QO(HM(yn1G3xj47Cg>6nRGNJa`~V-Ds8q)a+L&~AF6 zuP(+VxD1!$N?e7jaSg7+0^EQbaWihgLfnQsa3}7@J-83|<3T)xNAM^f#}jx8PvcoU zhedb+FJUp3;$AwI$<_!OJ*8MfkcY{wVa zi7&AmUtur4#y9vD-{E`wfFJP_e#S5O6~Ezk{DD957yd?;x&bF48?qxOav=}$B0mbC z5DMdD6h(2AKq-_)S(L*msDMhSjH;-H8mNg=Q5$tp4-L=|jRR69H3_t00v<&hGH0o<7|w;xfq4f7>jY3fQgulDVT=o zn2A|PMha$Q4(8!}T!@Qs2`o?7)}Ug|Dy&Ut=G>#eRH`1NadK@iPwLR~*LgID$WM6o2CwPO2A> z71@ykxsV%qkq-q>5QR|$MNteTP!gq42IWv56;KhCQ3cgd9W_x4wNVH4P#+D^2u;uw z&Cvoa(F&)d4cehSI-(Q0pewqg2YR9x`UIp*>Ko{w?dPij7>L0bf?+rdXX6~4i;)i56Fsa$bp>5jXcPQ{3wV*D1wtw48>6rrBDWCQ68tDA}XN@s-ik-pcYO= z9n?jAG(aOXMpHCH3!H{lXpJ^#i}vV%PUwuT=!PCR1HI52eQ_rGV*mzWFot3nhU09E zz_}QO(HM(yn1G3xj47Cg>6nRGNJa`~V-Duwd|Zf&a0xEO<+uV@VLqK@#aTI^!7*1*skQLdH1G$hJd65qVP!NSt1VvE{B~TKjQ3mBu9u-g#l~D!N zP#rZ<3$;-P^-v!T(Fje@6wT2BEzt_6qYc`jJvyQjx}Yn%qX&AT7y6(t`k_AtVi1O4 zD9*xgoP!Y7UDMCfje`aUPJD^o_zHXRHNL^O_zvIW z2mFYi@H2kFulNnW;}86azwkG*Gz>Ti*^nJMkqdc{7x_^Dg-{qLqbQ1_1WKVa%Ay=j zK?PJoWmH8q)Id#~irT1)dT4-#XpAOkhUPd8EzugMqb=H@13IEJx}Y1n;|%mfZ}h>L z=!XFqh`|_wVK@tC;~boekr<6J7>Dtgh)I}&shEx#n1v*y;5^L1T%3;!a1k!XrML`N z;7ZKL)wmYd;d00v<&hGH0o<7|w;xfq4f7>jY3fQgulDVT=on2A|PMha$Q4(8!}T!@Qs z2`o?7)}U zg|Dy&Ut=G>#eRH`1NadK@iPwLR~*LgID$WM6o2CwPHG&G71@ykxsV%qkq-q>5QR|$ zMNteTP!gq42IWv56;KhCQ3cgd9W_x4wNVH4P#+D^2u;uw&Cvoa(F&)d4cehSI-(Q0 zpewqg2YR9x`k*iRp+5#<5QbnV&cbk@~{A^ud|vhXELf!5D&JI16Xv9Gr`h7>zL)hw+$*NtlAEn2s5k zg(RflJj}sdoR14|5iZ81xC~d|O3cUAxE9ypdfb4Ua5HYjLfno!a2M{zy|@n#;6Xf$ zNAMUP$CG#p&)``+k41P9FJTFmVi}fW1y*7eR$~p;VjbSVTUd_`cn9xcBR;@~_!ysH z6EZ=7aYcKID$WL6o26uvNR3IifqV% zoXCwl$cOwWh(aiWlTi%CQ4*z424ztmr=TJ#p$e*^I%=R6PDLHmMSV0tBQ!=+G(!uV zhE`~eHfW3X=zvb>jIQX09ykNN&>MYmCi-Il24OIUVi<dFU7=_Uoi*cBMiI|Kj zn1<LIuF2&`z0#{)^uEDiffa`H1Zo)0N6}RDb+=;tz5AMbN zcmNOKVLXb*@C2U3(|88Y;d#7(7qJ*i@G_R+6|BIkScTWH2Cris-o#sY8yoO0-oyL& z03YFFe2Pu@3|sIyw&4rxz?ayCudoMSV;{c7eteGu_z?&3GY;Wb9LDcBf2}5g3V47=y7G zj|rHB$(V|1n1Pu{LNd<7Y|Ow>IO1z5IcnxduI^MvWSdX{y z4&KE^ypIp@5kA4E*o@Dx6`x}}zQ9g=iQV`Ld+{~C!MFGh-{S}Th@bE?e!;K!4Zq_L z{E5HtH?lMjI0@O19XXK;d5{Qd7$>7BilYQdp)|^(98N(6R6=D`MK#nwO`M9_ zsEc}NfQD#{CTND{I1Me)8mFTz+MxqFqBFXn8@l5R^h9s;!I|iX0T_tE7=mFq3uogT zoQshdjWHO9@tBB7n1ZR8jv1JRB&6Ux%)wloj|*@SF2<#}3|HVv%*WNZ7T4i=+<=>K zGj7E~+>SeN7w*QrxDOBDK|G8{@E9J)lXwcx;8{G6MR*Y}VF{LE8J1%OR$>)aV-40~ z9p1oOSdR^O2k&7cKEQ|g7@uGhHe(C6VjH$&2XTQMIF>deKbHLG)7Z2LkpaSR%nejXp8pffKKR)uIPpyI0L=V8+~ym`eOhFVK9bb z7>46)jKH}Vh0z#`ahQOKn2afyhUu7zSx80-W@8TK;e1?(i*N}p#pSpHS7AP`!L?X` z>v1D)!Y#NJx8Zi&iMwzQ?#2Ch01x3|Jc`Hg1fImxcm~hmdAxuZu^3D6GM3>LtiY>S zh1akKuVWqF#9Me98}KgP!~6IEAK_zsicR$k7)qcdN}~+Qp*$*} zA}XT_s-Ze+q84hS4(g#k8ln-JpedT81zMsNPDdNGLwj^YCv-tqbVm>LL@)F~U-UzN z48$M|!BCuq;W!5)FcPCM24gWkAZ5~oK%Ji^`DzNLVmfAE7Lt&H^DqZv02a!p*o93voN{z+Jc-_u@W0fCup~9>HUH98cmYJcDQPJQm?a zyo4oKie*@i6ZpNQI2CnJ7xmEqjnEiP(F`qc8d{+>+Mq4kqXRmjGrFQ1 zdf*K7LT~iNndpxJ7=*zXieVUzvoQkaViZPWEXH91CSo$CU>c@lCT1ZSDVU8pn1}Om zAuhrtxD=P;3S5QxxCYl^0j|f5xCyu5R@{c$aVPG=J-8S5;{iN`hw&&L!xMNCPvaRp zhv)GEUc_Q7!OK{NSFi%FVijJ)8oZ8mcoT2oZEV21cn|O61AK&!@hLXpGi<@<*oH5# z17BhnzQP`SjeYnQ`|&*v;71(9&p3o%aTvej2>!%T{EcHcsZ~H$WJeCNt8wzltXz`Kt)tW6;wlY)I=@RMjg~ceKbTPG(l4|M+>w>E1ZrtXovRb zh)(E&uIP>)=!stFgTCm8{uqcs7=ocV3&U{^MqngHVGPD%JSJcgCSxk5VFqR*3CTDQ zvoRO*Z~-pF#kd5Q;c{Gwt8g{0!F5=G8*n3T#w}Qg+i(Z&#ND_D_u+m#h==e99>wE$ z0#D&-Jd5YB2ru9zEXGp2jOBO*EAc8;<29_s>v#iiVm;o*J9rlx@jgDpNB9JvVlzI& z)_{~rp9iWaZ1>d;?8GkY#vbg&K751y_znl~0}kRR9KtU+jNfnsf8Z$o!ZBoN9gr2- zkOMi98+niq`B4ysPy{EV7>c7LN}&wOqC8GPMN~o+R7G{vKrNh#I;e~KXn;m&jHYOY z7B~&9&>C&f7VXgiozNLw(G5Lt26~}4`r=IV#{dk%U<}1D49D3RfpakmqcIlaFaZ-W z8B;I~(=ijXkc=<3`+sTW~9G!|k{eci|q~ zi~I2a9>T+T6p!HvJc+0A44%XDcmXeBF_z$EEW;~Ufmg8#uVD>d$2z=;x9~PL;9b0j z_wfNf!pHa&oA4R7;B#!l7ubO>u?t^e55C4ee2e|~9tZFv4&rAV!ml`t-*E(g;wb*c zF`RUIKvrZ&4&*{^Fp*Rb}aSldcBt~Hj z#$r4sU=k){DyCruW+Dm6I1jTi7xQodF2u#S1ef7*T#2i2HLk&RSb!UFBW}hmScuzj z2kyk(xCi&)emsbW@CY8o<9Gs3;b}aJ=dcJb;3X`^QoM}icm*r*Dpun)ti|hi18-tI z-o`t47aQ?DKEy}(1fOCvKEqagj_vpYJMkrU<16gN*Z2nC;yZkgAMhi7!q4~xzv4Ii zjz91x{=(nL(k9>}WJ7l3L@wk(UgSps6hdK~jG`!x5-5ezD2sA91r<;Ul~EPdPy;n_ zDr%!H>Y)J|qA{AF8JgoXv_xy1j<#rr4(N!^=z?zOjx*2`z0n6}q8|oeAO>RyhT$xn zjdO4=Mq)I^U>wF{A|_!9reZo~U>1^)g7Yv3b8$W{z(u$im*O&9fh#c|SL0e-hwE_z zZojulvmRalKR zSc`Rd18-qHHsBq+hmH6EAL3(tf=$?rE!c`}*p408iCx%@J=lwV_y+s&9S-0J91KXA z^i!bfZ2hVp$VFzIa;74TH$oGK|8cZM|46LbVYacKu`2SAM`~( z^v6I9!VnC_Ss0FUFajen3S%%9<1qn~Fd0)Z4KpwkNl3e6VK2VM zH~1Fc;d}gmAMq1@#xM94zu|ZMfj{vV{zjH|0Vg3FvLh#QArJB*KMJ4_3gcuHMRAls zDU?Q8l*1{gfJ&&0s;Gtz2~#i?(=h|Hkc1SRhdG#w^Kk(# z!o|20m*EOriTSu1*Wx-{j~j3kZpN)xh}&@o?!w);7x&=-Jcx(!2p+@ZcoI+H89a;U zu?R2XB`m>GEW>iFz)GybYOKLptiv043+u4~@8CUb#0U5gALA2j!e(s2R&2v|?7&X! z!fx!rUhKm+*pKgU06*X$e!?OAg2VU?NAL%Z;x8OSmi7TzkqtSJ6S8^!EDUI zJe-dUaS<-TrMMhd;3~|=HMkZFa6N9sO}GWO;x^olJ8>88!M(U258xp@j7RYpp1_lM z8qeT4JdYRfA{Ju_UdA%Kf)#ibtMD4u;B~CSn|KRvV*}pBdw3ro;3IsDPq7J~VGBOT zHhh5{_!7JD753n3?8CR%kMD5+KjI*M#v%NQ!}uLX@F$MqZydu(9RjiYyI#qahlh37VogTA(Fb;dHb? zJG4hfbV3(&MR)W-PxL|`^hH1P$3P6i5Ddjx7>;u=0wXaBV=xxuF#(e>8B;M0GcXfL zNXB`Xjk%bI3veMW#wEB6m*YxYg{yH5uEPS{fE#f$Zoxv_hC6U4?#4a15BK9iJcLK^ zC?3ZXcnVMBSv-eDcmXeAF_z+GEXONYiC3{2uVF1-#~XMP>+v?;!MoUq_wgYJ-iBnM9uqMM zQ!o|NF$1%ZgcO{IIhc#{aRDyE#kdrg;R;-d`M4U_;yPT98*meD#;sV0+i?f(!rizR z_u&CNh==hA9>e2!5>Me7Jd5YC2ruF#EWuJN!*Z;^O02?atif8W!y9-D>#+gv;5}@_ z2lx;l;}dMcW^BP$Y{Pc!z)tMKZtTHc?87(MkMD2*Kj0vK!Xf;E!}twH@CT0KFC0Ub zP61hw4LOh#xseC?kRJt62t{x*ilI14q7=%YEXv~)R753IK~+>o4b;M^sDrwwj|OOj z#%PLWXo1tv3a!xwZP6Yb&|0y&)_*cj~DPF7Gnus#xlHu6?he^@EX?Ob*#gicnfc1 z1K!1Zcpo3&BYcccu?e4H3qHp-e1RSK61(sf_TX#m!?)Ov?{NS>;vjy;A^eKN_#H>^ zCywH89K%VS1F|AJav&FSBQNry01Bcoil8Wpp#(~zG|HeH%A*1*qB5$W8mglvYN0mj zpdRX@AsV3xnxZ*cpe0)2bhJS`v`0sDLKk#Jcl1C{^gML+b%Kn%hV48>U(j&m>q zBQXkNFc#x60h2HpQ!x!QFcV2g#(9{HxtNCwa3L)`S3Qyx%JcmVi0WV=Omf~eB$17NgSFsweVJ%+A z8+a4z@iyMUyV!{L@gY9KC-@Yb@fo(_b8N>K*oiN(8((2BzQ#BB7T@7}{D2?v6Mn`o z_!Yn5cl?1r@fZF^mM#G&AsezICvqVV@*+P9pb!eFcs4=1GA8X6r6`Sn2Ymq0WQMDxD=P+3S5c#xEj~u zI$Vz%a1(CEtyqZLaR=_g-MAO`;Q>5|hw%s=!{c}oPvIFni|4TjFXAOE!BQ;4a;(5g ztio!n!CI`t8+Z%ru>tSkJ#54W_z)lC6Kuj}Y{6D+!*=YzPVB;N?7?2_!#CKE?{EM= z;2?g&A^d{F_zg$!2ae(|97C3_0a=j^Igk^%kq7yZ9|cheMQ}2Tp*TvS6w071%HtGN zL?u)~Ra8d})WWH#gSx1X255xFXo_ZNfz!|mtSeO7w*BmxE~MTAv}yn@fe=KlXx1>;5j^x7w{q$V+mfy zGQ5HnconPg8rI--tizjl3vXis-o<-(A0OZ&e2h=A37=sLKF2nEfgSh~yYLnE;A`x| zx7d&GaR5K!Ab!Rn{EEZ)9Y^pdj^b||!%5u&vLZWjAQy5YFY=)P3ZgKIpeTx=1WKYb z%Ag#|qXH_TGOC~&s-q@qp*HHE9_phZ8lefAqB&ZiC0gNhv_U(xM@Mu*7j#8;^gvJa zLLc-+KlH~y48jl$#aS4Rb1(uUF$!Za7UMAilQ0=mF%2^?6G=$Md65+Auh%x zxD1!$N?e7jaSg7+0^EQbaWihgLfnQsa3}7@J-83|<3T)xNAM^f#}jx8PvcoUhedb+ zFJUp3;$AwI$<_!OJ*8MfkcY{wVai7&Am zUtur4#y9vD-{E`wfFJP_e#S5O6~Ezk{DD957yd?;?g1wu8?qxOav=}$B0mbC5DMdD z6h(2AKq-_)S(L*msDMhSjH;-H8mNg=Q5$tp4-L=|jnM?n&>W|sC0gTjv_(5~Ku2^& z7j#2+oPnO`jXpRN{V)InF&INI3}@kNoP%>Q5~DE&<1ii*F$q&J71J>Tvyg-ooQFA> zi}P^-F2cpQ6qn%&T#5O(8rR}FT#p-Y6K=+>Scuzk2kye%xEJ@~0X&F@@dzHn<9HHJ z;Tb%O=dlPc;w3D>QY^!AtiVdF!fLF+TCBqxcnj;X0q@{FY{Uon5Fg_cY{F)2!B%X; zcI?1T?80vB!CvgcH`tHwZ~#BxAb!Fj{DQ;y4M*??j^ZyILzW%^S&$q8Lh`Bub+U%Aq_epdu=x3aX(xYN8fuqYmn!J{qDCnxH9~qXk-` z6;4MRv_pGzL??7XS9C`Y^h7W8L0|Mke+;%?l7`*1%V z#6x%lkK%DWfv4~^p2c%mgctA<7Go)1#&W!Zm3S4a@fz0Rb-aN$u^w;Z9lVQ;cpo3) zBYc8Su^FFXD?Z0|e1V<#61(vg_Tp=NgKzO2zQ+&v5kKK){DNQc8-B+h_!EEOZ)7VI%Z%Nl8}P)Fb8vSJ}$sTxEPn>GF*WxF&|gsT3m5*o-aMif!1A9oUIo*o{5di+%V8`|%wP;0GMUPdJ2Ma2UVg2>!rP z{Dou4(la0{vLOd@A~*6NAM&Fh3ZV#2MllpeNt8kvltp=*f{LhwDyWL;sDWBI6?IS- z_0a&0&=^h83@vaPTA?-Cpe@>?13IBIx}qC;;0*LaZ}i2P=#K#yguxh!VHl3HF#_je z6h>n##$f^`Vlt*+8m40=W+53Vn2kA@hx2hEF2W_a6qn-)T!s0#2G?Q%uE&kI3Af-@ z+=kn6C+@;MxEJ^10X&3<@hBd{6L=C&;~6}M=kWqw#9}PL%UFh2umZ1Q6<)&{ypDBv z6K~;dY{0vC5AWjxe1wnjDK_CVY{BQ)hA*%KUt$-&!XA8$efSpp@jVXUM;ye@ID}tu z7{B8P{=`xIjbk{eS3p)|M-JpdZsbKi6hJ`~MiCT6F_b__ltvkpLwQs{MN~!=R6}*t zL@m@t9n?d8G(;mbK~pqG3$#QloQ^hVhxX`*PUwQJ=#C!fiC*Y~zUYVk7>Gd_f}uDI z!*LEqU?fIi48~$SCSVdKV=AU$24*4&$v6+QF&Fc20WQSFxCEEsa$Je4a5b*Mby$EK za3gNUEm(-#a0l+h-M9z$;eI@bhwum<#p8GaPvL1ii|4QiFW@CC#!|eD<#+`v@hVp1 zHLS(!cmr=@J>JGUco!S-K0d@p_ynI~Gd{yse2(q-0z2^~cH=AT#n<=--{L!bk00gF2F^&7?Sfm%2fbx;@e(EyFm7){X(EpQrIp*7l|E!v|4I-xVVq8obP4D>>8 z^u?Lzj{z8j!5E5R7>=_s0_S2BMq@0-VFD&%GNxb}reh{%AsH!{jX9Wy^Kl_A!X>yA zm*Wath55J!*J1&#$BnoNx8PRXhTCx`?!rB|7x&`V>qdAKvrZ&4&*{^Fp*Rb}aSldcBt~Hj#$r4sU=k){DyCruW+Dm6I1jTi7xQod zF2u#S1ef7*T#2i2HLk&RSb!UFBW}hmScuzj2kyk(xCi&)emsbW@CY8o<9Gs3;b}aJ z=dcJb;3X`^QoM}icm*r*Dpun)ti|hi18-tI-o`t47aQ?DKEy}(1fOCvKEqagj_vpY zJMkrU<16gN*Z2nC;yZkgAMhi7!q4~xzv4Iijz91x{=(nLa%R9u$cF65iCoBoyvUCN zD1^c|8AVYXB~S{bQ5NNJ3M!xyDx)f@p$2N=RMbXY)I$R_L}N5TGc?C(Xo=Q19c|GL z9ncY-(FNVm9cQ2?dZQ1{L_Z9`Kn%tZ48vJC8|UC$jKpY+!8nY^L`=dIOvQA}z$_#o z1?OQ7=Hh%@fQxW3F2!ZI0#{-_uEw>v4%g!b+=QEPD;DB*+=07rH}1uKcmNOLVLXDz z@Hn2tQ+Ni?;(08>i+Bl3uoTO%94oLAtFRhtuomm^2HwJYY`{Bs4;%3TKE%iP1e>rK zTd)<|upK+F6T7e*d$1S#@D29kI~>3dIEbHc2*2Pke!~&`fur~f$B?C8KvrZ!4&+2` zSJ#}&8=^KlKX#R6Q98*vkE!L7Irx8qLSg?n%>?#Bao z2oK{?JccLmB%a1Icn;6w1-yvGSb~?a46k4XUd1ZBhBbH{>+mMt!rRz@ckv$H#|QWb zALCPO!e`im&#?_(UZplYsEsNt8wzltXz`L?u)~Ra8d})Ix34MLje?Lo`McG(&T=L@TsGTeL?9 zbV6rzMK|<7PxM9~^h19P#2^g8Pz=WijKXM)#W+mBL`=pMOv7}{#4OCgT+GJ;EW%hj@f1c#7wEfme8qw|IvS_=wN=f^YbapZJA82vjA2AP9=!_zNKs3Ssa! z!XZ2&A`+q?DxxC>Vj(u-A|4VTArd1Ak|8-#A{EjgE&f4zWJD%pK~`i(4&*{^vVsOvEHi!BkAg49vo8%*8w`z(Op>5-h`V zti&p;!CI`x25iD+Y{fS0z)tMO9_+(@{2M@*6fF9Q_xOlU_=2zajvx4i-w0GKfWQcfVE79m5DKC3 zH^L%3A|MhXBPyaH24W&M;vgR4BOwwY36df?QXmylBQ4S)Ju)B@G9xRpAqR3IH}W7K z@}nRMp$LkiI7*-tN~0{wp#mzRGOC~&s-q@qp$_VzJ{q7A8lx$ip#@r^HQJyZ+M^>n zp$odAJ9?lOdZRD;VE_hVFos|lhGQf~VGPD%JSJcgCSxk5VFqSmHs)X+=3^liVF{LE zIaXj5R%0#JVFNZ|GqzwGwqqxDVGs6VKMvp^4&exn;y6y=6i(wT&fx+s;xew_8m{9e zZs898!#&)`Lp;J0JjHXoz$?7QTfD;ue8gvb!8d%zPyE6k1gaiD5ClbV{DqJRg)sOV z;Se4X5eZQc710p`u@D<^5f2HF5Q&il$&ef=kqT*$7XKhUG9nYQAS<#X2XY}d@**D! zpdbpP2#TRNN}?3Xpe)Lx0xF?0s-hZdpeAag4(g#k8ln-JpedT81zMps+M*pgpd&h? z3%a2@dZHKlpfCDk00v<&hGG~-U?fIk48~zRCSnq%U@E3#24-P4=3*WeU?CP`36^0w zR$>*_U@g{T12$nZwqhH0U?+BC5B6a{{>4EY#t|IDah${{oWWU~#|2!%Wn9HI+`vuT z#vRuY=#4(;hyECdK^TIe7>*Gbh0z#`ahQOKn2afyhUu7zS(t;ln2!ZmgvD5jWmtig zSdBGUhxOQqP1u61*p408h27YTeK>%BaR`TT6vuD^Cvh5Qa1Q5j5tncUS8*LTa0|Eb zAMWBl9^erk<0+ou1zzGc-rybH<0C%d3%=qze&82=BT&r%0wXAb;V*6&UgLsIKgh+%WNQ&f0fmBG1v`B~a$bd}9jI79p9LR~>$b)>ykAf(K zA}EUDD1lNajj||*3aE(6sDf&!j+&^2I;e~KXn;m&jHYOY7HEmqXoGfWkB;bsF6fHx z=z(77jlSrI0T_tE7=mFKj*%FJF&K;Sn1D%`jH#H08JLOLn1gwkkA+x-C0L5(SbZ4cLgy*n(}?j-A+rJ=lx=IDmsVgd;eL<2Zp+IE}M7hYPrf%eaDTxQ?5+g**5U z_i!H%@d!`w6wmPjukadg@eUvG5ufn|-|!tj@e6+ts8#?$5EQ}j7eXQw!r*U&LwH0) zBt$_}L`Mw7LTtoEJS0FuBt{Y>Lvo}ifX8Vny8IBsE7J!h(>6Frf7~9Xoc2ji+1RMj_8ao=!Wj- ziC*Y~zUYqu7=*zXieVUmkr<6J7>Dtgh)I}&shEx#n1$Jxi+Napg; za054S8+ULQ_wWD@@fc6=4A1crukZ$M@g5)W37_#5-|z!J@f&{-xOMY)J|qA{AF8JeRdTA>ZvqCGmG z6FQ?Sx}gVpqBr`WANpe;24M(>VmL-%6h>n##$f^`Vlt*+8m40=W?>HIVm=mN5f)=9 zmSF`}Vl~!a9oAzbHen04Vmo$V7j|PW_Td2j#UUKVQ5?ewoWyCI!8x4AMO?xaT*Y*ejX-q*2#lZzhQAO3p%5B> zBP_xr0wN(Yq9Ph%ASPlX4&os`5+V_jASsd~1yUh3(jpzwBLgxaGqNHZav&#iBMYy&_qX8PBF`A+oTA(FbqYc`jJvyQj zx}Yn%qX&ASH~OL<24EltV+e*}I7VU=#$YVQV*(~&GNxi0W?&{}V-DtFJ{DpTmS8EC zV+B@WHP&JsHee$*V+*!nJ9c6h_Fyme;{Xog5RTv|j^hMQ;WWO z7Vh9b+{1l5#3MYxQ#{8Dyuxd|#XEe!M|{Q?e8YGA#4r3opt=DBK~Mz8UkHg%2!p>7 z4&f0Ikq`w@5gjoQ3$YOw@sI!skr+vk49SrasgMR~@ek4?BQhZivLZWjAQy5YFY=)P z3ZgKIpcsmyBub$S%A!0fpb{#hDypFdYN9skpdRX@AsV3xnxZ*cpcPu9E!v?2I-)bW zpc}fQCwid|`l3GuU=RjlD28DKMq)I^U>wF{A|_!9reZo~U>0U$F6LnY7Gg1$U>TNU zC01b#)?z(2U=ucDE4E<=c49a7U?2A5UmV0?9KkUh$4Q*R8Jxv=T)-t<##LOy4cx?S z+`(Pk!vj3TV?4n#JjYAC!W+EBdwjqre8yLN!w>w#Z~Q^vdI1DMFa$>kghXhBL0E)C z1Vlt+L_st}M@+;*9K=O@BtRl0Mp7h03Zz78q(M6TgAB-s%*cXl$c~)Ig*?cM{3w7z zD2$>gh7u@=(kO#+D36M$ges_t>ZpNQsExX)hX!bf#%O|OXpWX>g*Ir5_UM34=!~xD zh92mN-sppV=#POIgdrG;;TVBY7>%(QhY6U7$(Vv^n2wp4g*lju`B;EOSd67uh80+e z)mVddSdWd^ge};L?bv}`*p0o|hXeQ*hj182aSSJL5~pzn=WreuaS2y&71wbCw{RQ( z;V$mu0UqHop5hr^;3Zz;4c_5BKH?L;;48l42Y%r<0@V*7FoGf&{z3?ZLTLPrun3O` zh=j<9ifD*|n23!yh==${h(t(&q)3hwNQKl$i*!hj49JAc$ck*pft<*VJjjRqD2PHR zf}$vn5-5ezD2sBafQqP$DyW9)sEJyrgSx1X255xFXo_ZNftF~EHfV?T=!j0}g0AR} z9_WSM=!Q9BgRvNo37CY*n2Kqbfti?%Ihcp}ScpYff~8oF6RNBxPXhej4QZ?>$r(qxP$+2 z5BKp9kMIOf@fvSKS+;^$b>A&itNaNT*!^Q$cF+bh{7m> zVknN1D1|a8i}I*|N~nygsD>J-iQ1@xdZ>?vXoMzcisop6R%ng3Xon8yh|cJOZs?Al z0R&9rddYpz7yU5+gD@CFF$^Ox5~DE&<1ii*F$q&J71J>TvoITTF%Ju{5R0({%di|P zu?lOj7VEJAo3I&Mu?;)06T7ho`>-GX;vf#=2#(=6PT~~K;4IGL0xsb)uHqVQ;3jV4 z4({R}9^fG!;|ZSOIbPxw-rz0X;{!h7Grr;*e&8p5;|~Hi3?K-CAvi)HBtjz$!Xg|Z zAR;0o3Zfx8Vj>peATHt~0TLlGk|G&WASF^G4btHsWI#q_Miyj4cH~4Zp46IE^znhx53IOSpooxQ-jRh1>WK zcX1yN@Cc9b6wmMiFYy|0@DA_s5ufk{U-2D3@C&~Ys8Ilc5fs7j7eXKuLgR0QMR-I& zBt%A3L_-Y3L~O)CJj6#rBtjA-MRKG-Dx^kQq(gdSKqh2HR%AmCs} z6h(2AKq-_)S(HNsR77P|K{ZrIP1Hgi)J1(XKqE9pQ#3;hv_xyPK|8cZM|46LbVYac zKri%0U-ZKO48&jz!7vQRNQ}Z5jKz3Nz$8q@R7}GR%*1TW!92{zLM*}(EX8uHz$&c9 zTCBqcY{X`4!8UBiPVB-S?8SZ@z(E|s5gf&FoWLoZ##x-h1zf~sT){P5$4%VA9sGxT zxQ~Z;geQ24=Xilvc#XGshY$FO&-j9G_>Q0Wg+B&)J7fDLwz(vBQ!x%G)D`xLTj`|J9I!tbVe6+LwEE< zFZ4lQ^v3`U!e9)=FpR)RjK&y@!+1=@Buv3nOven&!fedNJS@OMEXEQn!*Z;|Dy+d; ztj7jy!e(s6HtfJo?8YAK!+!jWgE)*MIELdmiBmX(vpA0nxP;5Nifg!mo4AcTxQlyu zfQNXDCwPYEc!^hdgSU8(5BP-7_=<1%fuHz|KM33;fFKBl;0S?`2#qiZi*Sg5h=`0R zh=%BhiCBn(xQLGgNQA^lieyNElt_&~Q4y6;1yxZUHBbw+Q5W^l01eR?P0$R@(GsoD25r$E9ncA#(G}g$13l3j zeb5j6F%W|=1Vb?#BQOf1F&5)60TVG9Q!owFF%z>e2XiqW3$O@_u@uX&0xPi^Yp@RM zu@RfF1zWKlJFpA8u^0Pr0RQ3;4&x|};RH_NG|u20&f_93;R>$eI&R<=ZsR}P#eF=$ zBRs}aJi`mT#B034JG{q7e8Lxe#drL`FZ@QJrU3*-Pz1wY2!T)tjlU5V;Sm9m5E)Ss z4KWZCu@MLH5FZJV2uY9>$&mu7kQ!-`4(X8rnUEP-kqtSJ6SSWg5xiQL@0#8-w22Bh=@ptf~bg& z7>I?~h>LhgfP_elBuIwjNQqQPgS7Yu>5&nckOf(h9XXH-xsez7Pyhu{7)4MF#ZeNa zPzGgD9u-gtl~EPdPy;nl8+A|*_0bTG&;(7<94*iat8+))1`|&Rh;xLZj7>?s4PT>sB;yfN8lod6 zVj&LVB0drz5fURQk|70BA~n(=9sWTEWJG3UK{jMZPUJ!!OIkBhj3E4Yg5xPe=^jsI{L_wfLa@EA|= z3@`8!uki-&@E#xW319FP-|+*#@Ed_z1P~ZO5e$DJ1VSM+{zh1YM+8JdWJE)JFp}LSr;VGqgZUv_>1WLwj^YCv-tqbVm>LLT~g%KMcS? z48{-)!*GnmD2%~ajK>5_!emUvG|a$E%*Gtd!+b2nA}qmDEXNA0!fLF=I&8p3Y{nLB z!*=Y%F6_Zx?8gBd#33BPQ5?q!oWg0G#W`HSMO?-eT*GzT#4X&xf4GPHc!)=Mf~RkIh035 zR6-S0MRn9bE!0L`)I$R_L}N5TGc-p_v_c!SMSFBWCv-+vbVCpHL~ry#KlH~y48jl$ z#c+(kD2&EfjKc&>#AHmtG)%`#%)%VZ#e6KlA}q#IEW-+{#A>X;I;_V=Y{C|7#dhq# zF6_o$?85>4i$ge!qd0~WIEm9ZgL62Ki@1a zBt#-4K~f|~3Zz16q(wTUM+Rgk zMio>;b<{*H)InX;M*}oMV>CrGv_MO=MjNz4dvru6bU{~iM-TKuZ}de!48TAP#t;m{ zaE!z#jKNrp#{^8mWK6|0%)m^{#vIJUd@RHwEWuJN#|o^%YOKXNY`{ir#ujYDcI?D1 z?7?2_#{nF~AsoR`9LEWq!fBkvIb6U+T*eh#!*$%mE!@F>xQF|Ah(~yWr+AJRc!k$^ zi+A{dkNAu)_=fNJiC_4GKy3mDf}jYFzYr3k5C(rE9Ks_aA|VQ*B06Fq7GfhV;voSN zA~BL68ImIS$cpU9fn3OqyvT2TD2wu_ zfJ&&0s;GtK)Xo}`&fmUdZwrGbA=!nkff^O)Jp6G=>=!^asfI%3H zp%{h{7>UssgK-#-iI{{bn2PC`fmxW1xtNCqSct_~f@N5al~{!}Sc~=8fKAwpt=NVg z*oocPgMHYKe{m3paRkS394B!KXK)thaRHZb8CP))H*gcTaR+yC4-fDVkMRW0@EkAk z3UBZh@9_bj@EKq64L|S`zwrlw+XfH>!4MoF5E7vg24N8n5fBlP5e3l@9WfCLaS#{r zkpPL17)g-~DUcGWkp}7T4>BMlG9wGJAvp)iV~7)qcdN}~+Qp*$+0 z5~`pos-p&Kp*HHG9vYw_8lwrCp*dQj722RJ+M@$Hp)vF0UNOy zTd)n=u@k$n2Yay}2XGLFa0Ewj94BxJr*RhNZ~+%_8CP%(*KrfKa0mb49`55I9^na| z;yGU66<*^l-r)m2;xoSB8@}Twe&G)SwF@8!f+9HnLP&%{82pWJ2#<(}geZuL=!k(> zh>f_2hXhE7#7Kf5QR|$#ZVk2Q3_>H z7UfX^l~5T~Q4KXv6SYwX^-v!T(Fje@6wT2BtTvoITTF%Ju{5R0({%di|Pu?lOj7VEJAo3I&M zu?;)06T7ho`>-GX;vf#=2#(=6PT~~K;4IGL0xsb)uHqVQ;3jV44({R}9^fG!;|ZSO zIbPxw-rz0X;{!h7Grr;*e&8p5;|~J24pe zATHt~0TLlGk|G&WASF^G4btHsWI#q_Miyj4cH~4Zp46IE^znhx53IOSpooxQ-jRh1>WKcX1yN@Cc9b6wmMi zFYy|0@DA_s5ufk{U-2D3@C&~Ys6zmO5fs7j7eXKuLgR0QMR-I&Bt%A3L_-Y3L~O)C zJj6#rBtjA-MRKG-Dx^kQq(gdSKqh2HR%AmCs}6h(2AKq-_)S(HNs zR77P|K{ZrIP1Hgi)J1(XKqE9pQ#3;hv_xyPK|8cZM|46LbVYacKri%0U-ZKO48&jz z!7vQRNQ}Z5jKz3Nz$8q@R7}GR%*1TW!92{zLM*}(EX8uHz$&c9TCBqcY{X`4!8UBi zPVB-S?8SZ@z(E|s5gf&FoWLoZ##x-h1zf~sT){P5$4%VA9sGxTxQ~Z;geQ24=Xilv zc#XGshY$FO&-j9G_>Q0Wg+B&)J7fDLwz(vBQ!x%G)D`xLTj`|J9I!tbVe6+LwEE~Q4y6; z1yxZUHBbw+Q5W^l01eR?P0$R@(GsoD25r$E9ncA#(G}g$13l3jeb5j6F%W|=1Vb?# zBQOf1F&5)60TVG9Q!owFF%z>e2XiqW3$O@_u@uX&0xPi^Yp@RMu@RfF1zWKlJFpA8 zu^0Pr0RQ3;4&x|};RH_NG|u20&f_93;R>$eI&R<=ZsR}P#eF=$BRs}aJi`mT#B034 zJG{q7e8Lxe#drL`FZ@QJ&H)5QPz1wY2!T)tjlU5V;Sm9m5E)Ss4KWZCu@MLH5FZJV z2uY9>$&mu7kQ!-`4(X8rnUEP-kqtSJ6SSWg5xiQL@0#8-w22Bh=@ptf~bg&7>I?~h>LhgfP_el zBuIwjNQqQPgS7Yu>5&nckOf(h9XXH-xsez7Pyhu{7)4MF#ZeNaPzGgD9u-gtl~EPd zPy;nl8+A|*_0bTG&;(7<94*iat8+))1 z`|&Rh;xLZj7>?s4PT>sB;yfN8lod6Vj&LVB0drz5fURQ zk|70BA~n(=9sWTEWJG3UK{jMZPUJ!!OIkBhj3E4Yg5xPe=^jsI{L_wfLa@EA|=3@`8!uki-&@E#xW z319FP-|+*#@Ed`;1rQiP5e$DJ1VSM+{zh1YM+8JdWJE)JFp}LSr;VGqgZUv_>1WLwj^YCv-tqbVm>LLT~g%KMcS?48{-)!*GnmD2%~a zjK>5_!emUvG|a$E%*Gtd!+b2nA}qmDEXNA0!fLF=I&8p3Y{nLB!*=Y%F6_Zx?8gBd z#33BPQ5?q!oWg0G#W`HSMO?-eT*GzT#4X&xf4GPHc!)=Mf~R`(&8VaM@D2q7GyXLyd6c!f83i}(0|Pxy?l z_=X?&iQo8xz&!#8f?x=a5D1CT2!pT)hX{y>$cTbyh>nr+F$hC26vHtBqc9p{F%A#!ahu?btS72B}`yRaL3u@49EFAm`_ zj^Y?j;3Q7t49?*^F5(id;3}@;25#Xt{=;3|#{)dVV?4z(yueGm#v8oDdwj$ve8E?I z#}E9%Zv^TYKwtz#F#LrO2!+u28(|S15fBNH5f#x812GXBaS#vjkr0WH1WAz`DUb@O zkrwHY9vP4cnUNLQkOMi98+niq`B5-{fH`gnp$odAJ9?lOdZRD;VE_hVFos|lhGQf~VGPD% zJSJcgCSxk5VFqSmHs)X+=3^liVF{LEIaXj5R%0#JVFNZ|GqzwGwqqxDVGs6VKMvp^ z4&exn;y6y=6i(wT&fx+s;xew_8m{9eZs898!#&)`Lp;J0JjHXoz$?7QTfD;ue8gvb z!8d%zPyE6k1nLz)5ClbV{DqJRg)sOV;Se4X5eZQc710p`u@D<^5f2HF5Q&il$&ef= zkqT*$7XKhUG9nYQAS<#X2XY}d@**D!pdbpP2#TRNN}?3Xpe)Lx0xF?0s-hZdpeAag z4(g#k8ln-JpedT81zMps+M*pgpd&h?3%a2@dZHKlpfCDk00v<&hGG~-U?fIk48~zR zCSnq%U@E3#24-P4=3*WeU?CP`36^0wR$>*_U@g{T12$nZwqhH0U?+BC5B6a{{>4EY z#t|IDah${{oWWU~#|2!%Wn9HI+`vuT#vRMLMKM24q5JWJNaQKu+XF9^^xQ6ht8uK~WS(36w%9L&RfEW{!#!BQ;83ar9vti?KPz(#Dw7Hq?I?8GkY!Cvgg z0UX339Klf>#|fOmX`ID5T);(K#uZ${b=<@)+`)gihx>SlM|gs#c#ao%h1YnCcldyh z_>3?3hVS@^U-*MSeF6xApa_n?5E7vf27evAEZY{WI`5XMRw#sF62gDMSl#yAPmM(48sVF#AuAc zIE=?cOu`gQ#dOTTEX>AS%)VOCTzx5Y{L%h#BS`tKJ3T8 zIEceIf@3(2lQ@MlIE(YRfJ?ZHtGI?6xQW}igS)tg2Y86bc!Fnmj+c0aH+YNp_<&FN zjIa2HANYyi_=CWG0|jxun30;h=|CDf@p}2n23cqh>Q40fJ8`)q)3Jo zNQu-)gLL=@8ITc~kpQd7)4PGB~TKjQ3mBu9u-juRZtbxQ3JJ5 z8+B0+4bTvc(FD!V94*lbZO|6&(E**%8C}s0JF#@A78e=gI z6EG2zF$L2w9WyZtb1)b4u>gy(7)!AXE3gu)u?Fj~9viU-rX8+)-22kK8y@1Vu3Xg%AjZ(D)l+5gri`36T*M(GUYM5gTz35Al%@iI45v{7kO`TQ71@vjIguNAkPrD$5QR_#MNu3jPzt3{7UfU@6;T;gPz}{l6SYtW zbx|J;&6T7end$At}a1e)Z z1V?ckCvXaN8lod6Vj&LVB0drz5fURQ zk|70BA~n(=9sWTEWJG3UK{jMZPUJ!!OIkBhj3E4Yg5xPe=^jsI{L_wfLa@EA|=3@`8!uki-&@E#xW z319FP-|+*#@Ed^!1P~ZO5e$DJ1VSM+{zh1YM+8JdWJE)JFp}LSr;VGqgZUv_>1WLwj^YCv-tqbVm>LLT~g%KMcS?48{-)!*GnmD2%~a zjK>5_!emUvG|a$E%*Gtd!+b2nA}qmDEXNA0!fLF=I&8p3Y{nLB!*=Y%F6_Zx?8gBd z#33BPQ5?q!oWg0G#W`HSMO?-eT*GzT#4X&xf4GPHc!)=Mf~R`(&8VaM@D2q7GyXLyd6c!f83i}(0|Pxy?l z_=X?&iQo8xz=Hw^g8wPFho~`(C=8&nZQHhO8;#Xijn!Czq7dKoo_jd znZ=uV!4MoF5ei`t7U2;Akq{YC5e+dA6R{Bo@em&gkqAkU6v>eSsgN3Jkq#M<5t)$% z*^nJMkqdc{7x_^Dg-{qpQ4A$e5~WcFw{DThYgwE)SZs>uY_!qs=7yU2*12Gsw@E?X@1V&;s#$X)AVnjb><$ zmS}}GXp8pv2OZG~UCr9K&&(#3`J? zS)9iOT*75s#Wmc(P29#E+{1l5#3MYxQ#{8Dyuxd|#XEe!M|{Q?e8YGA#4r3opuqtI zK~Mxo2!ujtghe<+Ktx1F6huRG#6&E_L0rT~0wh9WBt1WLwj^UM|4IPbVGOaL@)G4AM`_i48$M|!B7mtaE!z#jKNrp#{^8mWK6|0%)m^{ z#vIJUd@RHwEWuJN#|o^%YOKXNY`{ir#ujYDcI?D1?7?2_#{nF|VI0LVoWMz(#u=Q$ zd0fOLT)|ab#|_-VZQR8@JitRd#uGflbG*bWyun+%#|M1EXMDvs{J>BA#vcS85+ghvEKLS#fmG{itm#6}#%LwqDeA|ydlBu5IQLTaQ%I%GgbWJVTbLw4ju zF62R8UssgK-#-iI{{bn2PC`fmxW1 zxtNCqSct_~f@N5al~{!}Sc~=8fKAwpt=NVg*oocPgMHYKgE)jEIEv#qfm1k*vp9zf zxQNTRf@`>ro4AELxQqLEfJb z$b)>ykAf(KA}EUDD1lNajj||*3aE(6sDf&!j+*!jwNVH4P#+D^2u<)enxQ#bq7~Yp zE!yKBbVMg~L05D~5A?#n=!3rKj{z8j!5E7FFdQQ=3ZpR=<1hgeF&R@Z4bw3bvoHs9 zF&_)C2#c{4%di3~u^MZz4(qWIo3I62u^l_G3%juw`)~jUaTrH%499U2r*H;maUK_N z372sd*Kh+jaT|AV5BKp9kMIOf@fpBQhZivLZWjAQy5Y zFY=)P3ZgKIpcsmyBub$S%A!0fpb{#hDypFdYN8fuqb};90UDw)nxH9~p#@r^HQJyZ z+M@$HqBFXn8@i(>dZ9P^pdb2UAO>LwhGH0oVSGf+HkC zAq>JIJR%?xA|ooIAqHY1HsT;2;v*pvAqkQqIZ_}MQX?(WApXqBr`Y9|m9`24e{R!!V4%NQ}l9jKg?L#3W3?R7}SV%))HU#XKy) zLM+A-EW>iF#44=8TCB$gY{F)2#Ww7~PVB}W?8AN>#33BPQ5?q!oWg0G#W`HSMO?-e zT*GzT#4X&xUEIe5Ji=o<#WTFXOT5M#yu*8Z#3y{gSA540{K9Vp8XiDk1Vu1}KuCl} z7=%N3L_{P+K~zLX48%fg#6>(LKtd!&5+p-%q(myDL0Y6o24q5JWJNaQKu+XF9^^xQ z6ht8uK~WS(36w%%(QhY6U7$(Vv^n2wp4g*lju`B;EO zSd67uh80+e)mVddSdWd^ge};L?bv}`*p0o|hXXi>!#ILtIF6Gzg)=yd^SFRZxQwf~ zh8wtv+qi>!xQ~Z;geQ24=Xilvc#XGshY$FO&-j9G_>Q0Wg+B;1B7h(Wir@%=Pza5% z2!{xWh{%Y7Xo!xOh=n+ai}*-@L`aOJNQM+hiPT7gbV!ek$b>A&itNaNT*!^Q$cF+b zh{7m>VknN1D1|a8i}I*|N~nygsD>J-iCUn_kfJp%a{NkLfo{DLhfti?%Ihcp} zScpYff~8oF6TvoITTF%Ju{ z5R0({%di|Pu?lOj7VEJAo3I&Mu?;)06T7ho`>-DeaR^6n6vuG_r*Il)aSj)75tnfV z*Ki#-aSL~F7x(c1kMI~z@eD8U60h+F@9-WU@d;n>72oj#zwjG@Mgc0;NzIWl;_lP!W|;1=Ua;HSrf}qYmn!J{qDCn&59VLvyr5E3`pdw8uZ_ zh)(E&uIP>)=!JjL2Yt~W1271KF%4EA~-@I6hb2` z!XW}8A~K>N8lod6Vj&LVB0drz5fURQk|70BA~n(=9nvEsG9e4HB0F**7jh#n@}U3< zqA-e}7>c7LN}&wOqC6^~5-OuAs-XsIq84hSF6yBH8lo|ppedT61zMst+MpfUqXRmk zGrFJ~x}zt0p*Q-VANpe;24M(>Vi<;FBt~Hj#$r4sU=k){DyCruW@0wxU>@dUAr@f? zmSQzlE!JTJHexfjU>mk$Cw5^E_F_K{;1CYuD30L-PU1Aq;2h55A}-+yuHrgw z;1+JBPVhp5Aq^E3ZM`Q zqbQ1@1WKYb%Ag#|qarGy3aX+yYTz%_LLJmaeKbHLG{)a(isop6R%ng3Xor8$0iDnp zUC|9a&=dcnH~OL<24EltV+j7kFpR)RjK&y@!+1=@Buv3nOven&!fedNJS@OMEXEQn z!*Z;|Dy+d;tj7jy!e(s6HtfJo?8YAK!+spZAsoR`9LEWq!fBkvIb6U+T*eh#!*$%m zE!@Ff+{Xhv!eczeGrYh{yv7^6!+U(hCw#$Ie8&&`!fyl`8$e(LMKFXwNQ6chghO~l zL?lE(R76J%#6oPuMLZ-xLL^2KBtvqfL@J~~TBJt?WI|?SMKPUJ=&tI-v`? zqC0w^7yd;b^hJLRz#t69Q2dAC7=ck3jj z$cTbyh>nw!YG1b zD2|dSg)%6M@~D7HsEn$ph8n1eTBwb>sD}nT*o8gVi~Tr&LpY41IEE8AiPJcPb2yKSxP&XXitD(6Teyw8 zxQ7RLh{t$>XLyd6c!f83i}(0|Pxy?l_=X?&iQo8xz~ci5f?x=akO+k^2#fHDfJlgp zsECFbh>6&UgLsIKgh+%WNQ&f0fmBG1v`B{x$cW6yf^5i+oXCYd$cy|afI=vYq9}$E zD2dW2gK{X3il~GtsEX>Sfxl1-bx;@e(EyFm7=NQFnxh3;p*7l~9sWTFbV6rzMK|<7 zPyCDC=!8+))1`*9G5a0Ewj94BxJr*RhNZ~+%_8CP%(*KrfKa0hpB z9}n;dkMR`G@B%OK8gK9p@9`0z@C9G-9Y633zY%Cc0D%z{!4Lu=5gK6-4&f0Ikq`w@ z5gjoQ3$YOw@sI!skr+vk49SrasgMR~kscY437L@<*^mP{ksEoC5BX6Lg-`@VQ5+>u z3Z+pNe@BLqSrG{PbrA|N6nBMPD+ zI$|Og;vg>KBLNa2F_Iz~QXnN#BMs6aJu)H_vLGw6BL{LJH}WDM3ZNhgqX>$jI7*@v z%AhRDqXH_SGOD5)YM>@+p*HHG9vYw_8lwrCq8VDCC0e5m+Mzut+dSpN*WJXqGLk{FbZsb8e?vXoM#C8_m!hEzt^X&=&3S4?3a~x}Yn%qX&B7U-Us= z^v3`U!e9)=e;AGt7=_Uoi*cBMiI|Kjn1<2K; zgSd!~1W1I$NQz`gfs{y%G)RZ^$cRkHf~?4n9LR;-$cua^fPyHDA}EI9D2Y-igR&?e zK){Q*3hGLzjH;-H8mNg{sExX)hX!bf#%O}3XoePOiPmU?c4&_d=!nkff^O)Jp6G?% z=!1UfkAWD3AsC8b7>&Der%*p8jpg+17d{WyR_IEh7&l6(>Q~3IFF0Cge$m;>$rhixQ)BGhX;6w z$9RHgc#fBNg*SMM_xONM_>8akh9CHe-}r;TQv(QsUY{-tB$b~$}i~J~nLMV))D25U!iP9*8 zaww0AsDvu0it4C=zfcQxP#5*l0FBTXf1@dyqXk-_HQJ&b{y_(HLT7YEH}pVH{EOb` zi+&h@ff$S-_z%M{0wXaRV=xZmF%gq61yeB{GcXIYF&Fc&01L4gORx;fu@bAW25Ye% z8?XtRu@&2}13R%Bd$14taS(@a1V?ckCvXavbuOu!^e##Bth49vuA%)va&$3iT^5-i1XtiUR) z##*ey25iJ;Y{52c$4>0R9_+<_9KazQ#!(!@37o`foWVJq$31OLKuWactk)XL`GCZ zLkz@3Y{Wr4#79CTLJ}lJa-={iq()k#Lk46-W@JG&WJgZqLLTHreiT3<6h=`LLkW~b zX_P@Zlt)EWLKRd+b=1ILsD(PHi~4AQMre$`(G<Dtgh)I}&shEx#n1$Jxi+Napg;I?~h>LhgfP_elBuIwjNQqQPgS1GG49JAc$ck*pft<*VJjjRqD2PHRf}$vn5-5ez zD2sBafQqP$DyW9)sENN&8+A|*_0bTG&;);@8JeRdTA>ZvqCNgWM|46LbVYacKrj4@ zKIn`77=S?-jG_1s!!ZJ*FdAbq4ihjDlQ9L;FdZ{73v)0R^RWPnuoz3R3@fk_tFZ>_ zupS$+30trg+pz5v{7kqKFl71@ykxsV%qkq-q>5QR|$#ZVk2Q3_>H z7UfX^l~5T~Q4KXv6SYtqbx{uu&=8H$1WnNlEzlCJ(FX0%9v#pTozVr|&>cO|3%$_? z{m>r+F$hC26vHqaBQXkNFc#x60h2HpQ!x!QFcY&e2lFr=3$X}GuoTO&0;{kZYq1U+ zuo0WF1>3M4JFyFUuowGr0EciGM{x`%a1y6+2Ip`d7jX$!a23~a1GjJ+cX1C7@DPvj z1kdmsFYyX*@D}g!0iW<0U-1n;@DsoB2Z3h=5Cp*x93c@3VGtJK5do198Bq}pF%T26 z5eM-Q9|@5NNstuDkpiiZ8flRZ8ITc~kpQd7)4PGB~TKjQ3mBu z9u-juRZtbxQ3HRW7V4lb>Z1V~p)vkOQ#3~lv_fmNMLYb14(No==!$OWfu8smz0nu_ zFaQHF7(?(MhG7IoVl>8J9L8fJCSeMuVmfAE7G`5E=3xOAVlkFr8J1%uR$&d+Vm&rs z6E;M8ID1spbLLxN6ARNLYA|fFQq9QtCAQoaH zF5)2p5+X5@AQ_S)B~l>`(jq-FAQLhpE3zR6aw0eKARqFhAPS)filR75pcG1@EXtt* zDxxx~pc<;9CjLTg)ImMeM?*A16a0;4XpWX>g*Ir5_V@=K(FtA972VMTz3?ykpfCDk z00v<&hT=aA#|VtVXpF@;Ou$4;#uQA$bj-vo%)wmD#{w+EVl2fntiVdF#u}`{dThid zY{6D+#}4emZtTTA9Kb;w#t|IDah${{oWWU~#|2!%Wn9HI+`vuT#vR&)Ix34MLje?Lo`McG(|JCKufen8?-}vbU;URMi+ELcl1Or^hO`_Lw^j! zAPm7!48w4Y#3+oxSd7O6Ou}SL#Wc*oOw7g{%)@*v#3C%gQY^;`tio!n#X4-jMr_6w zY{Pc!#4hZ?UhKyK9KvB7#W9?~Nu0(RoWprs#3fw8Rb0mn+`?_##XUU0Lp;V4Ji~Lm z#4EhPTfD~ye8OjZ#W(!GPyEIo1fCl}5ClVTghVKWL0E)G1Vln)L`5{jKup9&9K=I> zBt#-4K~f|~3Zz16q(wSpKt^On7Gy(qo4g7^#sDrwwj|OOj#`qge(Ht$%3a!x=?eGsepc6WyE4rZvdg5R7Mql*901U)n z48eaGh7lNv(HMhq7>|jVgejPc>6n38n2ouZhXq)O#aM!6SdNugg*8}<_1J(-*o>{% zh8@_6-PnVD*pGuagd;eL<2Zp+IE}M7hYPrf%eaDTxQ?5+g*&*5`*?syc#Nlbh8K8= z*LZ_>c#n_xgfIAt@A!dV_>DmG0tk$t2!;>{iO>jxa0rixh=eGJis*=eScr|dh=&A7 zh{Q;OWJr#bNQE>=i}c8VOvsF^$c7xqiQLG8e8`W2D1;&?isC4NQYekGD2EEDh{~vf zYN(Ey_zSgB2lY@N4bccq@Hd*FIa;C>+Mq4k;~#WHCv-tqbVm>L!oTQ)zUYqu7=*zX zivKViBQOf1F&5)60TVG9Q!owFF%z>e2XiqW3$O@_u@uX&0xPi^Yp@RMu@RfF1zWKl zJFpA8u^0Pr00(gxM{o?saT2F+24`^|7jOxeaTV8a12=IScW@8)@eq&j1W)lCFYpSl z@fPp!0Uz-hU+@jz@e{xB2Z81X5ClOH93c=2p%E705CIVp8Bq`o(Ge4|5C?G)9|@2M ziIEh^kOC=@8flOY>5&nckOf(h9XXH-xsez7Pyhu{7)4MF#ZeNaPzGgD9u-gtl~EPd zPy;nl3$;-f_0Rwf(HKq86wS~AEzufn&<^d<0Ugm9UC<5P(G$JU8-36Z{V@=OFa$#} z48t)pfG({@1*nleMl=rNF%gq61yeB{GcXIYF&Fc&01L4gORx;fu@bAW25Ye%8?XtR zu@&2}13R%Bd$14taS(@a1V?ckCvXaY^SRpdlKg37VoATA(FbqYc`jJvyKxI-?7^p*wn_7kZ-) z`k_AtVi1O4D28D;Mq(7kU@XRC0w!THreYdqU?yf`4(4G#7Ge>WU@4Yk1y*4-)?ytt zU?VnT3$|f9c48OyU@!LL01n|Wj^Y?j;3Q7t49?*^F5(id;3}@;25#Xt?&2OE;2|F4 z37+9OUg8zr;4R+c13uw1zTz8x;3t0L4+1X?AP9mXI6@*6!XPZdBLX5JGNK|HVjw1B zBM#yrJ`y4kk{~IPBLz|+HPRv-G9V)|BMY)2J8~iy@*pqrqW}t_Fp8oWN}wc4qYTQS zJSw6Rs-P;WqXzy$E!06>)JFp}LSy`mrf7~9Xoc2ji+1=29ncA#(G}g$13mFCdZRD; zVE_hVFoxhi48sVF#AuAcIE=?cOu`gQ#dOTTEX>AS%)VO zCTzx5Y{L%h#BS`tKJ3Rq9Kw+Ry0khPpex|G=p;_z49?;_F5nU_<0`J<25#au?%*Eo z;~^g537+CPUf>m8<1OCd13uz2zTg|a<0pRM4+1R;AP9mYI6@#4LL)4~Ap#;IGNK?F zq9Z0^Ar9gqJ`x}i5+f;+Aq7$*HPRp*(jy}>Aq%o1J8~cwaw9MDp#Tb^Fp8iUilZb- zp$y8RJSw0PDx)f@p$2NA7HXp|>Y)J|qA{AFDVm`LTB0@DpdH$y13IEJx}Y1nqbGWy zH~OF-`ePslVF-p|7=~jcMqv!bVmu~b5+-9RreOwVVm9Vr9_C{q7GVjNVmVe|6;@*{ z)?ouSVl%d28@6L7c3}_pVm}Vx5Dw!gj^PAO;xx|S9M0n+F5wEU;yP~N7H;D%?%@F* z;xV4!8J^=MUf~Vi;ypg#6F%cBzTpRc;y3;v@Ztc1AQ*xpBtjt!!Xi8(AQB=YDxx6< zVj?!;ARgi)Arc`8k|H@$AQe(0Ez%(aG9ojwAX@-kT4fK=5tdVw2YFEd1yKY=Q354V z24ztJ6;TCMQ3Ewm8+A}04bT`(&jP&=uX#6TQ#}eK7z7F$6;~48t)B zqcINSF$t3~4bw3TvoR0zu?UN?49l?!tFaF2u?d^84coB`yRi@ZaR`TT499T_r*RhN zZ~+%_1y^wcH*p7daUT!x7*FsVFYp>~@E#xV8DH=nKkyrW5M)UJK@kEW5e8uq0TB@e zQ4s?%5eIRR011%6w9yzE3pP^u^t<+37fGM+prV6uowGq5QlICM{yh{a2jWD9v5&K zS8yFSa2t1U9}n;tPw*Ts@CvW-4)5^^pYaXf@e98ZcxeDZ5F8;83ZW4e;Sdp#5Eao7 z6R{8%@sJRSkQB*~5~+|D>5vhbkQLdG6Sb0wqxfWl;eYQ3X{|12s__ zbxx2#c`{%drZpu@39837fGE+p!C~u@C!k2#0YD$8id$aSrEk372sV*KrHCaS!+L z2#@g;&+rnj@D}gz5uflC-|!Q^5NKHdfe{qJ5E7vf7U2*Pkq`w@1DKSpT;M=fs~Dn~ zh=aI@j|51JBuI`FNR2c|j||9+EXaoJ$cbFYi+m`ELMV!2D2Y-ii*l%dil~CBsDYZO zjXJ20255{XXolu!h1O_?_UMRC=!$OWiC*Y~z8HXk7=ob~ju9A*F&K{tn2afyjv1JZ zIhcRCoxP;5NhU>V6+qj4O zc!bAzhUa*N*La8b_=L~+hVS@=-w3=sfFKBt5D1Mh2#*Mej3|hX7>JEHh>rwFj3h{o z6iAIUNRJH2j4a5G9LSA4$d3Xjj3OwG5-5!_D31!Lj4G&(8mNWZsE7J!gvMx!W@w34 zXp45}fR5;buIPcD=#4(;j{z8rAsB|?7>Q9Bi*cBUNtlXhn2A}Ki+NaxMOcbuScz3w zi*?wDP1uTU*oj@(i+wnVLpX|KIEhm@i*vY$OSp<_xQSc1i+gy8M|g^7c!^hdi+A{l zPxy*&_=#T#v?74O2!`MYh0q9x@Q8>=h>B>4iCBn>cu0suNQz`giBw37bjXNI$ck*p ziCoBoyeNQzD1xFWfs!bLvZ#QHsDi4fftsj|I;f8ZXpAOkhURF6)@X@~pRZIE!<*h)cMNYq*J9xQlyufQNX3r+9&vc!Rh2fRFfsulRwV_=7+z z0|<&>2#HV#i*SgDNQjDPh>2K;i+D(gL`aHcNQqQPi*(3{Ovs9C$cbFYi+m`ELMV!2 zD2Y-ii*l%lN~nrzsENN&2X)Z^4bcRDqd8ijHQJy({y`^nMmKavFZ_$X=!bzAgrWEk zBQO$UFcuRq5mPV~GcXf#Fc%B35KFKWE3gu4uofGz5nHeoJFpXbuonk#5JzwnCvXyH za26ME5m#^(H*gboa2F5o5Kr(FFYpp?@D?BN5nu2X-|+*#@drUx1rQV=5E5Y!77-8; zQ4kf;5d*Oi2l0^riID`!kpiia2I-LjnUMwAkpsDr2l-I|g;4~>Q39n=2IWx!l~D!N zQ3JJ58}(2hjnEiP(F`ro3T@F29ncY7&=oz<6TQ&~{V@Q8F$BXf9HTHA<1ikRFd5S@ z9kVbS^DrL^u?S1C3@fn;Yq1U+u?btT4Lh+5d$A7(aR^6o3@334XK@Y}aS2y(4L5KT zcW@UE@DNY%6ff`+Z}1i$@DX3|6+iG3e-LPO06`H9ArT5;5e^X$5m68oF%T265eM;+ z0Ev+V$&mu7kQ!-`4jGUUnUMwAkR3UZ3we+i`B4CcP#8r~3?)$tWl;_lQ3+L14K?u> z>Yy$fpdp&zZ!|{>v_>1W$3N(V&gh2j=!JjL7yU30gD?a`F&rZ>8e=dX6EGQ5FdZ{6 z8*?xp3$PeVupBF}8f&l~8?YH$upK+F8+))1`*8?|aSX?C3a4=n=Wz*_aShjT3%79( z_wfji@eI%L3a{}N@9+_y@C9G-13&Qxfz|{N6u}S@p%50~5D}3O710nAu@D#WkPwNG z6v>bhsgM@wkP(@X71@vzxsVt6P!NSs6va>yrBD{-P!W|-71dA^f1wWQq5&GB3I0ZN zv_NaLL3{jzPUwto=#F0a7k$wW12G6g@gGKDB*tJYCSW3_U@B%{Cgxx+7GNQkU@2B$ zCDvdqHee&RU@LZDC-z`34&We;;3!VuB+lS0F5n`r;3{t5Chp)a9^fIK;3;0CrGv_vbkMLTprM|43~ z^gvJaMj!OY01UiF!fLF;dThdGY{Pc! z!fx!tejLJK9K&&(!fBktd0fI}T*GzT!fo8ceLTWrJi~Lm!fU+4dwjxYe8YGA!fym# z7eEjMM+k&Q7=%XzL`D=uM-0S99K=TgBt{Y>M+&4y8l*=CWJVTbM-Jph9^^*>6h;vg zM+uZh8I(r_R7Mq4M-9|MZPY`3G(uxEMKiQSE3`#BbU;URL09xZPxM9~^v3`U#t;m{ zaE!uejKw%i#3W3`G|a>-%*8w`#3C%kGOWZZti?KP#3pRTHtfJo?7?0fz(E|rQJla@ zoWWUKz(riaRouW$+`(Nuz(YL2Q@p@Syun+1z(;(+SNyqzlt4+8L0MElMN~mm z)Id$tMjg~g12jexG(&T=LTj``dvru6bVWDxL@)F~Ukt!N48c$g#|VtZ7>vgROvV&U z#|+HI9L&c8EXEQn#|o^*8mz;5Y{F)2!*=Y#ZtTN;9K<0U#W9@3DV)VQT*M_@#Wmc- zE!@RDJj5eB#WTFbE4;-!e8eYw#W(!KF9g~UKwtzzaD+l=ghO~lLS#fkbi_hz#6x@} zLSiICa->3Pq(gdSLS|$`cH}~CiWhi^ zH+YNp_<+y&g75f&-}r+d8v_W65D1Ad2#W}ah$x7P7>J2Dh>HYBh$Kjg6iA6QNQ(@} zh%Cs89LR}0$cq9fh$1M85-5o>D2ocHh$^Ux8mNidsDt`wfW~NoW@wI9XpMGgkB;bs zuIPrI=!HJ$ivbvjAsC9`7=h6kgYlSv$(Vxan1R`tgZWs1#aM#nSb^18gZ0>e&DetN z*n!>HgZ(&w!#ILtIF3^|jdM7UOSp_{xQ<)6jeEF{M|g~9c#c)_>N!r zjli1%2!h}UfzSwp@Q8rOh=S;df!K(H_(*`nNP^@@fz(KYbV!ek$b>A&iX6y^Jjjaz zD2O5`iV`S^GAN4*sE8`4iW;biTBwbBsEL$|6v$LVid*(5HQ(zoO&WAVJfC!CT3wS=3yZgVJVhjC01cA)?p(yVJo&_Cw5^k z_TeB7;V6#bBu?Qh&fy|1;VQ1-CT`&_?%^RG;VGWsC0^kz-r*xY;VZu3Cw?K&<^TdC zD1sp*LLn@|AtE9n3Zf!9Vjwo+AU+ZxF_IuTQXnTsqaNy`5gMZ@nxQ3Hp)J~>13ID$x}pbqqBr`WKL%hhhF}{qmgWJm(y6J-7kf2yOy5 zgImC@;5KkOxC7h??gDp%d%(Tm-@$$0r{DqbAK)SIU*Hk&3-B2DZ}0^8HFygA20R1) z7d!`k2VMYw055?*fo=X-coWzTyant4-U@aCZwI@8cY@u(Ux7Wqd%#}ceINk)g8jf` zkOm(BQ$Z7$1`YrRf)9d2z+qq(I076A=7722Xs`gZfJI;lSPGVbc5pm60d#;9K_@r~ zbb}tS3iN?BpdS>#ASi({SO-o48^CGcqu_M#ad0O1B={8g3^)gT4x9)68f*ez1Q&uY zgNwo6fJ?#Ofy=?)gRg;q09S!;fNQ`%f$P9OgB!qiz)j$L;1=*N;5P6B@I&w;@UP&< z;QxVt1OEOzb1KtbX2U1{P@P05E><>Nw8bK470S*8M zgAan4;4pAFI0766=79O&XmAW@0gJ&B&<2))MQN{0+Da{4KZw zd=*>?z7DPi{|K%H-vrl#Z-E=Zx53TeyWm#veQ-PY0k{+V2;2>R4DJR02JQzx0S|(o zfrr6=f=9v6!Q_f@W|ym<^5s^T2$t z5F7(q!D4VMXamc^abN}b5LgL53^Je#WI->;fz@CDd<)zN zz71{$-vzgV?}OXH55S$^N8oPoV{k9{H*i1r33w3v3_J|}6Fdrj4ju=;1W$rrfv3U$ zfM>yP!Smq%z>DDb;AQYfFyY(6wqSekX0Rie2zCZ<1G|EEfZf5nz@FgUU~lkVun$Oq zN#Olp3fLbsfJQJK%m4?0gTbL-CTIqSgW2FHFb~WJ3&Am<6)XnFf;O-m90yi_4}q27 z!yp5?Ko<0Z99RtoKpvb7il744g7x53un~L&oB=)t&H|qRXM<0JbHKUaJa9hP1TFv< zf{Vb#;1X~txC~qlt^i*HSAwg+)!-U%Ew~O`4{iWAf}6n2;1+NzxDDJ6?f`d!yTIMx z9&j(X58MwP01twPz{B7X@F;i;JPw`!PlBhw)8HBKEO-t)4_*K-f|tO{V4Lp<6To(0 zd$0r85$ptZ2D^Y=!ERu8um{)^>;?7)0oVuZ2PT0um;$DP2G9hifdjyS;Dg{0a2S{c zjsQo3Ibbe08Y}=UU=dgXmV#xV9UKo%03F~&&cHz?Z-!;49!V@VDR!@Ktan_&T^6 z{3Ey)d=p#`z6EXs-v&2>?}A&w_rdMp2jEWdBXBqPF}N4}8@M0*1Uv|S1|A0g2_6MM z2akhaf+xYRz*FF9@Eh<9_+RiG_&@MF@FMssrFgO&<1kK=ZFdG~N=7ITOAvgxK zg2mui&<5JUa&Q7z0Zs%f!AT$kx6d51Gj@az@6YOa5uOI+zajl_k*8;2f%-ThroY;T>hb^>n)yMT9s-N0XgJ-~awUf{jpeINz) z1@8xw!T#U_pb<2I8Q=hLF!&&t2@V5?gCoFEU=ElMjt0ko7O)sB0c~IzI1U^SJ_I_z zhe0Rk0^Oh&tOBdS8juGCPy{8g7OVrOf(_s!;G^JU;N##E;FI9f;4|Q};B(;f;IF|K zz!$-nz?Z>Sz~6ws1%C&=3jQ8^9sC3MNAL~sP4G|PTi~C;w}r~;?}+T-y_rYf1Gj+h zgMR_HgCBr9z@6Y-Phi4#g>AuhV0-WuumhL~-U@aGZv(r4 zUBNrSZs1+uufU$*-C!@UH+UZiKnm;&CV}^ZG?)TD0H%UQ&;+J~8Q?&05cnWC1k417 zfo56`Te(f{%jJ!NGwI3Ii- zYyua6FMex1pfrC2j2oWfE&Sg zz)j%0;CtX!@O^L_xE=fu+yQ1_ko{)pMnR$&%i_AVentz5%6>H z3-CDjC3pfn34RTp0{;Vk1D*xH1DU;AQYfu+8^`3E)j&JMd=k7O*3j z2zCNHgSUfSz&pS@!S3K)U=Oe-cn{bMycfI=>;qC@KQIYQ7AmXLB3;=2Jemp`Kogh- zW`G00LEvC;2sjiR24;c7!4Y6KI10=K^T5$y0XPP=ECt7cWuP4#2aX3Tz=yzz zU?u1TCxI@|4YHsY^nn~$1NuQ86u`-#2+E)W)`3&NsbB-x2tEQ%2WNnfgEPS=gv#nq zie%r}Jo*ec2YeQM4xA4@4>o}dz!$-V;7j1k;1ci^a4EP9{2jO)d=>mXxDtFFTm`NM z-vHNuZ-RdU*Mo0?8^Dd=JK!epUGP0{EBHRR4crcX2<`ws0{;r`20sS(fP2BegZscw zz)!)0;Ah|=@G$r<@Cf)h_yu?z{1Q9?o&>)JPl5jdzX8vJ--74B^Wb;j1@L?D2ks-E5V1sNgxBdK@aE!t3VE{2K`_F6u=-Tf)c2Jwcr%69&7-ofscTX zf-}I!z?tAI@Ja9~@M-WFa4z^PI1ii;{u*ooUjSbO7lAK8GIMq0&WHW0&W9806zqGf**mqz}?{g zfqTHefqw`0gP(v0z=PmFz(e3a!GD2A!Oy{C;BoNZ;0f?6@N4ii_#f~LcozIGcnx+uSN_3*H2_2X6*DfE~eG!A{_9;O$^n@D8vW*d6>8*aN&9ya((J z-U|Y-57-y%2i^}RgDGHtFcma_CNK@m00)4Bz`@`Ua40wo%mRmlBfxBM6qpOT0$rdRWI-?J139n;^n*MofRjNHltBfo z1E+vf!3MAqd<2{h&Hx_=XM#_FPlB_-r@=YkT<|$?9{4=?Yj6Sh0=N)d1ilO|244Yx z11Mn%1Go{~1a1bmfLpSeECt7ccCZ|r09Jq#!Afuv$bcS@1$`g~`oRDg1Sf+ssDM+z zdT<)p2u=rQfHT2a;8Wmia1J;ZoCnSao4^I&LU0kd7+eA_1($)#!4=?Z;7V{6xEfpo zt_9bD>%k4+MsO3j8QcPH1-F6Q!5!dEa2L26+ym|f_ksJt1K>gM5O^3o0v-jAfycoU z;7RZlcp5wdo(0c==fMl$Meq`M8Eo?}!UV7#*dFWvb_6?toxv_(SFjt{9qa-21bczK zK>+pv`+-Ry4W@vppaDz+)4_q@AaDpc6wCt6;7BkV%mwqn0n<=_Oc z0-Oj|f|Ec7^nfhr13AzS2EZUV8I(ZIyeKI3C;qa0%wDBz`5W&a6Z@s zE&vyTi@?R;5^yQF3|tPb0AB-Ff~&yQ;2Ll(xDH$oZU8reo50QB7H})L4crdy0C$4B zz}?^;a4)zI+z%cA4}yol!{8C{D0mD!4xRu{f~UaK;2H2Ncn&-dUH~tGm%z(lo7;p5 zU^}oq*a7Sab^<$tUBIqjH?TX{1MCU*0(*l1>;v`#lRz3w0aHN(m<1=+G?)UWf(9@ROa}*ogTNu+P%sNLgCoIgFc-`N3&29K2(*Hw;8@TOmV*<( z3UDG=2~GkT&;zod59B~U7yyIdWKaeba0*xtP6Hdk>EH}-CO8Xx3Y-nj0q27A!1-Vk zxBy%TE&>;WOTeYzGH^M#0(=cz39bTHgKNOG;5u+UxB=V{ICug)37!H^gJ;0A;5qO-cmcc!UIH(JZGIq3 z0Na7>!46;iTLyMf)o9$-(f7uXvFU>~p_m;};b3YZESz%(!&90(2qhk!%D zEYJ*&1hc_hFb^yM3&A4L3YLOnK|5FuP5>*wiC`r-31mPI$bvqQ1N~qC41$wE8C1Y2 zU_CeuYy_u+Gr*bPEbu9CHaG{I3(f=QgH7N9a3Qz|TnsJ&mx9Z{<=_hNHE<=k3S14Y z0oQ`-!1dq;a3i=0+zf63w}RWi?cfe@C%6mT4ekN=g8RVz-~sR;cnCZU9s!Sn$H3#@ z3GgI%3Oo&-0ndWx!1Le*@FI8#ybQMap)dh#2et=0fE~e3U}vxk*cI#sb_aWaJ;7dJ zZxDcezC3}*bVFs_5gc=y};fe0Q-Rbz$B0cQ@~Wv0H%TI;6QK?I0PID zW`SmKB$y56f_Y#8SO^w@RS;!9(C-@CbMmJO&;I zPk<-EQ{ZXv40ski2c8EnfEU3_;AODQox%jL9oQc10CogBft|rFU{|mk*d6Qv_5^!@ zy+Hu>0sDbTAPuH~sX}FSgNP!liAU4H3~(Sg2z(G60%n54Kr=WT90_KFIbbfB4~_;4 z!7*SFXa!5aQqTsLf#u*hZ~|BXI>3qG!=MvnKo{r%S+EN9fz@CQ7yx-N2u=niPzGzk zIVNL;3n{0@I7!V_&&G|+zx&S z?f^d$DwT8IlgpR0#nND3E`LgAJ~NQ*>CENVX7lAjas8%^o6gy_b8RlWuDj5a?Hnld zRQj_eJx!mpTX$h#uu#et8~e)T!OrgfoIcrRkE0ha z501{}v&Bq*u(Z3uO+tIX2xV1^IE`8PEv6y--cQzqKQpfJd1Qxw zHGT3>>06iU?+?1NL8X-Kt@KY-NXm@h_=W8YmMm`%W-ne596!6QZT8~!6^F@fxv!wN zSrw!4DK{{v^63ebtHn&dyk1e42d(qk<}A<`vyWQ1Xkq&b#Xp$8uzm5oWy^y3OWK0j z!P41n?F;8DUo^WdSh~Dz>5^sh8iQb&@<$n=?}y3TUQ;^7Y|xV}XL9`|o8}cN&XQu* z-xKs@)@D_#-Pzn)#VZqZtGf6M9ok<7n&~g(SD6$l7E$F<#1{4j`GP7}NfDeyrJUK+ zv~JzH##Q-BW1+aJNo7yDmzoYIHp-Ghu^jXlR;|kAS54G^gJ%D$aaFdwNH4O*bjnxr z2G#J?l!^YkLdpMCS|9$ox>U$d>@5}sf=aQ!KiAbbm?^5FxuEpS{GQ6&O5XfE(K`2m zG*!lhm-QGg-C47Q$dQ-_v<=C0ksdR+Od&=Fg}MX7^CT&BGv5TvZuRPf5Hp!Sc36 zHrvT!>%g@SwRG2mDP;pe$`s4==5^`~-f#Y%(X7^8Oic}PjoHSjs`(}{{n<>9s&g>; zh{=tn-16CV&SQ0BnXnhh3=(Hm1)`x2Dtn6hSK0y9#zjQ^ZGKf_qFRInS5ViU%d1Z% z1$;Bp6ne72Y*jM8*+R1(6Ql_~_Mvm+%VuVxtVx5y@r~Z+RG5{ye0P6EiLw6GDQ5FR zaqCo!$|bdP{jEPsS&D0ld7JCyp>@z`V`H9^Hid6X*M1py6nr2^y+0+IPs|tD{!-R9 zzv^!zH?GbpMAr|bJHpUArmZw>*ap)vJ@ISC%Bf+r@ILl0^56h{62>|1*Fh^+x;m>4 zj*g?Vm|2&$-Hn1P_YK{7$f3IHQl(${r;3>gj-J=92TD?@oTwr(-)06&<)>-ds^0Wt z8rn_Q7HhOLQ+0m>>iN3OKx@)xt5d?Sux{9DrP$9jwL*URc#s?QDq^BGxs(hRkO53* zO}`;QM$O5FU8e@&Gee4MK>hwWo{P3d73G#s8eQztDP@`3t0Ep&xng6foGDjSC7Xi- zr%j8hO}5DAj3926~frtoMkXFF;Qo(nM~MjqG7>CqBpNNRu`Sk+kFFsO$IcV=dK(i>2+xuN>fqh zY37R)vD>kZeS!Z)YOC->kDU}pUMn0`6&8b0Gp=W(mrqW4B43%tZW;d=Z!&#M^ z%>FrgaZ_X_cEc2ym1IegogbM*_+g31eh!F7rjgoWw_k(;vCUjJG5&LwJJGbIKEy1A zh&O}AY`%^lJH}d~E_a}RWK|^-v@dC0gbsjN@_2p8nmNXwtDhKqeHo&D^-299^=$Ko zl(c1KsaYD@rSnP6)M%JJrQCE%12rYJamXPjG0+UrCw0~xX6klKrNTfqFhj|B_w>5% zo`S8oP^rds0H`4}8Pk#t@@sF-2wY+G{IZ5=q|Ots)1B{9 zY17c{TCWyGBnsqEdIv5kNYFEf(9lSUFAYgoWmP)0!1e?ZK&8E%>OL;nhL5hKP6#O@ zbSsiBqa(4qp0Z+8mYO1!pwvdi++cbN3k+qGJ?T`lo5m1?Qn)7Ar#VQ4VMihIeuxBl*UeG^ zY26DIP@Q~oF?GRZPwCDMmJ_ug3d@9J678JLGp;F4%|T*n(s~gxS|zPjXt_;ewU688 zD#%O zRzdW%^psgkT-5}eXffybxslr1>#4)EB--WHDy8~K{V1mGriu+U_hW%%u$VR3?P^!E z(MpDmbBk(4>4*|q(5QA2%~x0X8CKe6rutD=u0?a(+QT&as%aKtN@@RLOc$e=Doaz7 z)NWX;k)o@#CO0@pee>0qdhfq9t&SAZDHN0w8GdwrqPIFL{?mN?yo<1$uKbSsk#)13qKO>3&?wq0n=SdHE z*`<%ygvsDZZ{xb6bc|L@Wg8EV`6r)zBdzrb|2z3qBBAoIx3QeJv=xl zig~TKe4^D~b;dnfKy`6b0jUd`);Oa#XgvxSCl<}>p)Z%ICUe5rG=&*c8=d4z5`OuA z!-cx$sF8#iTRN!YX>Wg})TazGxj(46l13h{B~zJdm9doVRO8KiH*V%OZKAOac?(OW zk}Niz^CqciHnqH`Wzr`%owHM11Gj1QuVsGHGPz}z-n^B@A@?jtxfh4GEaemb0vXD^ zX>0kg-n=XRCQ>*#Hz&1xRBqnhqnO5YL+<4nE$8ax4qnILo_?<7D|))Ke`@BG?$xC& z*CbxWBJ<6b@9UL`rY~Uk(QPe1<0IcRP1|>`9%|ig!Y4OXu%ZcbYW1nxZnI5w7MW+Y zsW6YLeYW4ndznqn&v;I`XG7+m@g-Rt=20xSZ0KP=+03YV$TZ6aRT;uisJtomLTi8C z>OmGn7wkB0K{Rebgc@w1@H(&{GHbln{4F#IGOOJFmz!cuoG9z1_P(rEu4V+?{h5+X zk%DzB1Y~+LgIYN=`sb1{)#}AqiyUB`%M8Y5vBUW!^QB;kGr;IyZv|pvQIf&aDvjKg zu0}0?H4T(9U9#mVG`Xd%QUmSGikVGa{e`ZkflNtuY2kZyqv3lSr=pBv*1LEsKK=cL zb;uj*Bn9|Ln-z4U=s=-oBhy3riw*j8U$X>W6*2p|DRh;HjC)y@otox;#c~soVyGb| zCfn+)z^7w{(3muql3AWv5RxQiMl;q7I%VOQD|dFLOWFQj$x)`boB;&u*&5B851zLF zK{4q|Qt%wfBQigfIU*r2GjjG=2>TfsAj-a>r!bJwtjYQqNhtLc(W(jwL#*Ys-}{l- zeeR+*Ggurh!IfkWknhoQj#e>j#La3(6t_@*@?t!GmMViXZ6mF<*^ezMk8UCy}wM)C?DHO4YgB3A5I7=zH6-m?-MFAt5>t~jR5WQB|wnr$S?QneGL zcw;iyGg)@2p_h{SLSK{eS@^iIyI)qSUQVI(UFMj=kCiY{4rA_;-E=m)Jtov94V#kCU z$9t>^_MjeDH3eL5xn|(=k;y!Psjs4MkWpK0MGgz>&)5*cI4oY$K5r%qeZ`z=mh6lJ zshL>Dwq34P1F3sq>oyhz+4aU@9-BKlWtks_{*9z%k@c!QBX3<(eFWokW7Bqh#gNF1 z$yQip&97LS!UBv`RM&GSs@JxDTVZ1@*G4$1!bY}#Pwj_cf8pfYy^Xm4?z#?5LwD{b zw@i_UT+f}$edq22ElqOwj#~dVt)3#OS=tf{oG@8C_|DgXSYCxSlPI@d^ zBG*_c=cI{e=x_%5vP0G`l&Ofmr)Dt<8j!J@Th74vE%CEYMkf8)P81|sSds13NJ1FQ zbg#**$}XOFT-$7Ga~_Lk_dritdreACl+kFkv{>ktvO0(yX*e_Ha3woFxKWs|W(IQx zdiryD$+gZh-C9mrLj&tVZ_vVL8y8DwUQ%STX6%cMw2#ZE+d&3(V~d>=NHZo)W!dT3 z{F;q)Nj4JgnCY>=laXPbauX|@Ix)7wb#Enawmz7E{eY{KcMfE*$=whQ#@f$Q)`GA3 z7kSso<7gExB`f=NbzJc{=BitzwJKXO4r6|~$1#W6hSXcfJ08beX?1|L=<2BPIOfVK zt*pCPp!RXX-C(KEZ+%R-vyWpg2c^ub6E2TquGo5Ys*7LDKl?c5uAEurJ&ToBryj=~ zY4xb!UBx`(am>}aLUE0$PjVV_6+RA2b))%9(moZkQT4H;MKH{nQ#8^PJC|zSG&GoZ z(X_zoF=OHIK9aaY6(;4A?XM1u83^lPw$4SqM(Xv{^8A{-R)k_n@$JqmN@*qqogfp6iTAAiOH3(>b`(jI%WpPxxIRBE6pq0wM3@O)b2r> z;9{1UzM1j(j?*eX$Q6|yeX6OowkNe8``ijmx2y$Nn9(z}yUwf~vZO-K#~YK+#)?FG z3GzLcm)a)N0*%upjM>FQr_MEQoT_#TC^Uq_7C2 zHPOp_w$WslTNgPo?{+=d2z8{QOi8V*T7V`3s30OIos>>(R%n{ZCex{m%EPt9Wxjqy zK59o;-dedy@*Bwfd3NWFw?flYN6`vROP>`M1_s5Cj;Q^k>#5MWm`?b{iL3 zB~s=F)eVF`Ny+TC4wtfYH)xt=3w~n$#C)RFGfxOV!gEzU$+c-}U`$Omrp_Uk?=5H> z{{E%30U?O5Q4PNQG8vj)2nMBAQ* z-&8Y@IVCqx8HjDG(b8%u$4KrXhu@}d(;e&^%%i@A!JFd|jAlHe$y9Hz)|1TUV(qvx zDn!5eyI;*%TQwQRLcd&FQ4G=@-Qgx3Q>nY@0I-Ef4rgp1B^G1q1YC0bcIwnrH*UuJ znJIn`iJ2RZQG{U9?RK2GFvGHVEu@Q@jK@e66|G}%XbVPt6ch!V&^%?HMn3!1?vN21Bnt(d5o zQ6tbsUM*T?v~EajoUXw-ur{aiG`BX_Q_=SEFg4zXaFe4IoBe0eV=FP+cqLZC&`X$w zF#FC1Zg!=6$EY5NQoOMivukrmTItvjClS(y+mZ6GQ&oBFnof#+Zq|dqZi}k@Ff7Mf za~|)DYu`?w3{o;WvT@ev<~?K~NgI3z2DL#~W1dnGdx?4{S2k~aeA2EZ4eP1AEJ?9s zy|ja9m3T^@vSr3h-#bxCUD@)wtZcDn_!Ao3rt+{lB`q+$Nx3=Q+g3?}5%is4igwcXuorkG%;x3$OY-PByJ zBgOCd@MAl4J7{%wSD+ebZVr|M3+AJ&(p}TYuGgEwlUW+$;$Pk{R^90#wzHdlK8(VSdsYRxxdxe}C#tJz%*X`ko{lvurB`aUzhvARIf?3r z)LtBulb$@O)GWK+)MU+B)7r6NK8~8HX_<9=?NA7&Y5M?GBgY)3((B}98~Q5^e#6F5 zB{@-r$h)v1ne(MmK617UoWhxcHb=^p(*31!O~s?X%QQq<2|q)mzjSqk&az4N7Dd^$ zXZw4S)9Tl%4i*a>E5^Z4iRz}Rlp<>8z!jxWr5jZu6J3*bO=7Gw^RcNbR>Y@f4*!{% z3AoSVhYIZ*ESHH&Z?32boy`~gD#=<-x*eL8`G$I&h=z4QQ7Ed7xRa2mKdrFkh0$0& zi@vsp!k8UFl%&;ShIJy@2iZ(eqqOJlNsVk~1g2jzU6tE@n>=cR*E6N*vQt>iAgt4< zGclsPbrn4fdzi&cI@B+yyQ(fEzUfF6`gLSZMLF#U$C}i+LDYM_nRF%MS2KQlPxduSlx9LrKWQx-%Y}kA zf-x5{P8uhU4G?AuZ(i0VJ-Nd-|Qrj?N#ZX;0hii8gYje|7 zF7y=q*6-M;P}kS$rs*ZEWPRUqjWaPQ(#kX<#s#&S@v=Gt5>XjhzP<(%!9CBmcB=eR}sw;EMaU#sR^%)QTJdHCJ&19N} zNl#R?brUmW;~XZeE!8+p^>Gn!!zRldta6xv$^S^q9cryZi|1y1DrLC2` zNrMF zvh**$sg0=(+3>X##O%l|1KII0Tpn=NW!B{oCx?b%Cu_TOgURh1b<9vDG}LJm)++xM zw2GJwpxY0kZL!&`JH#KGU=BA!kQe7 z5AqH1TrcPm1RK*knkDC~_P-@e z%T)ea_|ze-+UHiS2=W$1^wg5hU9B{m)6)8Gh&AXiouy7T9@W;1kqYTc^>soxFekbq zzM&KXj94!i6CDEG-Zipv-vYfKS|cYj$TmU!<}@R4 zj!^VRTcZ`isuSJ9`d_so5wqNBb@oD`Q!U^2>&7DWB(Z)X>JBJJ?UYv)uS7<@;m3Yv zV8s0Jsk*PC1n-gvDrdl=%k9T5zP}^2bA0CU7n-|~{|C9qG6qKUwm+y);x05^J zcvvG(*D~+P{$69{%9`R*Rkw2I=*EH1ewXXq_ zF|VuB9DGBiRHL0aRwUl?Qsu~nF0&^0`fk4A5b3AZBj2VTj_USM^*Sd-ZJD(Xv;8=>Zav;UUKj0y z@=r97S#~ETEoGR}3|zSTB;TWn}WMiO#SirO{W}0L&)V zdO8bo-soWxLv;Nuqtzj9#%nW}jj81mkea^Nhd33H+nhOlsLh$LSw|2aJU8~07Ja%0aN zkGTu0!0B8j6c3&{x7s|dm&xWu{meD5;!(A=q{b_sndU{kOf=auVe#djf6iAI@TM*{)5Cve~B^rQvQop5{SIK5%9@T3oyr>L)oO|NJBq<&m zomNWcyzf8sg-LCaL>FYVdwpTPTi3>z8)zh2nyb<>TEMWYo7y_wTVAJ|5Dp7;Ub;C_ zteDj{L2ak*;uuh!m7?|XCe}O(Du1qZ(Ie%R_T?k%=n|O$v*C~*M=xF;*qz_~vf1d; zHK^Kq50yTDY@)sHVX8t> zW(3DCY+tZsd3!K>@rvO1*==pJ7q_oC%-qqVQ$zzz2l6IS<{BTRQn{*|Y|7l^Ee~4f zwarRLaM8l{6`VOUe_{LLdCQgs^Ov**vxB9x+u9e-S-xm?Td;I_o9;)R*BIzb zSfilT_rv6^S&@1@+?P}+`HPWsi=F>dGXZnN_{8LK=>CXx)qs3uAoBH%cr(6 z`K7Gq!j0+8sYRLCKlc(#T?bH-Msy&=p1dPdPDxRxzcR^Gs16dZm9t&?YgI` zIgD>xW?gLa`~qeEe3P+qI#RE7kQ3Gmoe~v#b&-XJEZx_gI?}6hY#udcdU`q)YGpt= z$aJbrTbY!S7&G7@QwNt`g(Jd3G z!2-Qh)$z)l`ynGRdq!}h6Rzt=6FV(M)0zs!;*@GCR`N~jbbv{*NwU2=!CMXnwEuc- zrr4a~LZNx>!<4CwcYJ$;4aJy*%r8C3EL(Habhy zoHSfYzmC7|+$}PzF__-m$_-R5^X#o}y_sBpV=$xM8=XDQFgkpNJWfd&qP0)~m`^C5 zHydlS^y*{=Sxvd3@kf?&rV2-HD`QPJx34*0O;7F71B`@O+OZk)!~2{WZtI<)u69<^ z!P^Y=zT1g)p2?13vRssOGg+Sh#(JrFt+N*{o;$BCsUEg1f*VTDd8el=S`p1Q1c_)HK0JOE&$x{Cx{=Y;X^-wI9@!2Ia9(hhV@kb1 z=6`!3FDCCXlKaPIi)B)_^FEB_1|Qe7M}2)y&FYbk2dTMt$9t~H*ASQP`2Jh})wK*& zCzf#|$JTY@PIYt{l60HBzi!8Ly|F~AqaW1zhI;nF98SBq!%{by_B00BRqjA9M9~eQ zz1hrQy2ke|<)k*0=$;oz9g=G~lGDftsf~8f@FqdkhUoqXcq&Zt`jZr*RFihSl`ADT zrfY)4^%)vjh@Ky&7@vCC8%HFF^fV0AHNj(aEm_TLOyZDyZX;oB6ZJ-eXlj}Z!X>22 zkx!l+x&tYkbK;@viDJ1C3n`H=&I^|vs$auiZRCptsV@?CB@vt4;Eo~h!aj<*L42`S z8ij7mqnHzYQ*@Uo#k?uTLsAdn@AvUe^eE;>cP8JR?Kf_`1N$iE#wz&|ZtSC&8}>xI zki0)Uin%}}R9BOcEAPTTin+37Y7*{UxkoWaN`lLp&?_FrT;v8gFWFq;F8cFlR zRZ3nymykP{Yu5kW)SXVFlsh#Wzq>*mjGMCSQ>lqGrNaqArkQ2R5A_oXi8OiIq`cSp zg!Vl3Ak&4mhn|KBhTm`&Hgn@w*y)*0)Gch`3EFe}%$ARa1QS!4<|szC^!#;c<%*#^ZSV)1dlv;otVqhF-jj++Gg4A2yW4d|&H&S0BJK*ehM<_qY08@| z77N8Abg8sG3CvfUBTOtCR8MT6F1mD}I&M;ay7vS2(vkJ7h);1QACPFsp)hrf$_>^wjT$ESt@t2b6Gac3Hkbf1WS<<>?6&O zO>@c?g#V#f8#mgs5ZnD=a-glEeN+S4d1QnX4mQUIDw?Qih_fec>Qhrwf=n;EMGD`w z2G`lwk3uXYt1_yMc(g=6D~O$|Y|Ex@%&N=-%n7>Y;-A*sQHqTz7adDuMnk!^KIxVy zQ_!YTCJKqN}D2;Xn zUDIke*>2Vpo92uzqUOlhjOq&W$?!H2-!H}PY6|sj41L*>#@}>G`WNo%VkBRe(d~`) z&t5l)<}t#6PTO>Ox2`XzTQ+o$wYL7oDp+3E;rL$D`A!4N&>pB+vAun|>wU@GB{N-) z+y27I23qk~#7vGOE4kc_o$^h;jCWDhG4W|M8(OtN#-z&@O>#p+!kLMXtqN|WQ-X9f zvI$sqHOv%ZZxgJvg!vObjbfo<=`^-i@<rv~#fmDf%)Y*~NC( znbNnxMBmkoZWJ+_ja;W$3O*qDO&2#*@+o@?H1GJ_mwTOb)qZZy4U2LrtSEIp9(|^S zzD4OPjxk?+!P-QJ9>)sV)$1)2ao@YLm6CpjtE>9k zO(^u2@97YnH`)_=@r{3OcYJs&oDab-LF~VO_Y}KCK#{nV`mIH-D{z+nJ`@|7SE)y3 z7_$Kwm7AtX_7Y1Mcv1$6HPi7+93|kJs_4%l3M=Sqafu^U%?0cS&Y4<~m4M|IGg;d8 zvv}i}x*86$GgbK#_wW|7rTk=RrFETdPfoVq<$hf^Csjb+2)L>YNd0P5Wn`W%-GL}E zPBq8(KSuv!nvSlvaHFc7=h)ddW2;t~C5X7y7Q39n0<;v%_Y>FT;~)4(^+Iql=p?V>-z1*b`_RlG z&739vS?p=Ok8HDze-Q7y>ZYe#8~>$%{x+U z%NH+RxL6BVLF)L~3)|hF^A|2&xNO0^xjddfd*LGe6^RL6&NZGiGJu?t)(vPbpIIS} z--pI2p86ft2Yw|>+KG-XJ(2VkDXN@%-Jn$|a&?=Uosvz{GG%GfJ9-JjeCxz6+eF78 zU)Wgd4sWe1_N0waukIloHApU)L*{bQmd=9lzm53B6%i)>QEKsoVa6A}Z?g8R>Cvat z`|}zmH4M^RfiYD2j70N_Qx_MvUW;OMvSK`CzD*7=w|Dh8?PgO`W!+-tQn5bYC{?pP z?&6a^tw`%TbATrUfom(amv{AxmYn8pmspdIrd)Nzz8aCwdQ?~9iv%kAv3-N3x*)>z zF#{MQEnmKHZfu9svi8~S%a@rVWmaeIK(u}*BvD~rLI!%haFo9bhv-|KGwDB zSF&qWaifYgVTddnAY> z5}SO><-7YUn2GdBPS!YFM9~!1zND-?`oYsg@Rg37^=IZaU9=s&M$|>Sj2Q7{>?WsN z?-kCvC6m}gJIquY9cL(;*krFXH_3FQvU#Q*>d@#zVrGBHmKv906JD#Aa$S;sNIzGz zmv(bn%w>2gp;q#duLshJ`y=W~I{4P?9Si$SqrN7>R*>>DP1y-)g<~*N?i-(lZ+)}y zWoX?C!E_*Pbp=yo*3=U+p{kB`W>!k#&fM&oo0@G4x4maH%lE52t~RLQZ^?Bj)0|u% zg}|r!+ToT%PB`I&m9c%2?zT@hOETa!P)`pJI%b)1*}s(4n6CQG77q_*=}*iJ4-ZZY zYTWR`oLhCcosGqofs{TDtztPK62r7A+i2D@(kXvx9`0Q0Z1U^zk)-7WL3fr@G$Tna z26koDyK?ci*4b#4b|FoMW4g3KYd&_GqRSSeh`4Tm^|fZJtI(fj^~8pqJ*7K4SPs(h zRh+58aa@~d)|wCMnhgoYRgZ9$Iw@inl8rmxs+gB zS?|xkA_~<3*5655H^4FYen7n(v1*9wn^k=cGYN5Z%-=9pFEOry=X-OjRAd{%{Eehl zbCr>F7L={l6C-^{QUrAlbh&8E4;lM+_vzczKt}es#Yi_CuJxOxv&5W1S*yw`aoHKk ztTczTRoTfz8A54LO|-RuHLY}&MNQyEh``CDZvEFN@BE&I+$xzhN7kcwS*sk^*^7QS6a9(WHhjn$!@}AhGds*GgjIhA?SVCkU|&W&dcMk z^gw2PmsIi-`PwHW+=Up0y$=VVB#8z=t;L$A&a&)lw#&&Ym8V(IAb|a^;{i>0~ z+#wLLr5{@(T$h8)nYcydv=+87^_~7t4VtPkf9RKP~7!Is69WbhwaKdm< z9T$lS!@=Vd1}FHBPZ(me6F+AeV#1(qaf{CuWJ_fxQrdoAX3MCt8enGSHIoW-TqjOf z@E5$c7AxyuR;7~bL5yZ>Ieg7g&RDdal`*5#(rF&r*C3-cRT5Kcrmr~)QE z8?$4+F_$bSqs=BQO*24x!_hUUe&*HfB>uX zuRdAE&p@;PIyzoTwmN{AXjP*OQ!r*FTzZZg>wWxkimyoT91S+S*5_WGzDN-!j|0E? zLHQ&vv#YYjxYW*9q2$hwq=G0GA2x*8raEdJQIovUS%F6oAE%VENuwVu{i2hpUayD_dh! z#n#3~cNG}4V{le_gIO|MCr9 z!=3Ge#;uS{6?y|SeOtq9(>F){+ve}8h!Krsfva^2FN3%WVp_iuqY8OhAUki|OS@ae zu5@7aFN3B&o#q$z1}1Z5aA*x2bQ%l0*Q!UKv2+G@anEkOLVh+_i&c#k@>VHjZA3j zed4A?{iT?RQsP5Q)Xf0kR>VX5@w&$2VGvl5o6l%WoBiiM+uZi1AwBXQgexnlmEJ&f z4ADsV;wEcjN{<%|josB~G9)SjXYJr}f2lpNs5H~*6x2rT9ddOupx$kA&LeU%x~*m>1xceaM4Y)}yU$;gs zcMe65Yb>2CXw|mFEurHhw5qGAWepZLow7a67TCzzLHYq#-idCYU6Qqb z?)DBPdxg-J#0U`9m_&MXcL<&|fD)-WMqgu&?LNlXYlM+VTAq8Y!*DAfW9&3sh+DkR z&^`?v5nd|y$QGtCSIU&j>(fr=a%(E1Uo6;sM?#s@c4Dt=U7)HLskbyXt|&CM?+qYD zP{9&iMUayaN|dR zvx2ZrKKT8vV^ILU#=VP4=u5+yG+=Ie;YTY&v~oYT$o#-etoCz8r!>Nf$p5z z!JO?PV~b6z&C_FAdi8WC@0`$o)cZd1!o^=@bXjw;|^{jBA; z@mIzq+s)hZmjBEer`ngT^Cz@^g|}hMRs8PNr4w3znE24H`?|MxPH25J@z$=> zxVOKU(E1W@!xW+oLaP8tF&D~yM{`xf8`=oq`rufXG(4kMBd0Oqic^F2>rZxG@ zmauu2%<3vMBIi2Vc38PF=M!4`cO~-<9h78SL8S zrkeX1oDx#^Gpv8}`27sy_cNd_A9y|7p{34b4EHm*exvwGZdY(kX2iEE)ELTGjhXjm z=zA2L3#5jv=pF?G#Fzp#ahkez;iou$J;muuHE$Xk%)7|$(k@;2j2P9q?Hq7TSDlJ{ zQ;qNzoXhj}1kb7*9L16C!{}^nx}y7;v{$6b1=M7smDuB>`g?;cZ_h=HxRjx8R2&Kt=!y?Cwu1A z+}EKY?y_CRhq&<}?k{(U)4A~G{7{{fwXT>M9O5R)vD_%+8__Er^g@4z9`(GFt$5f| z-ol#UbJPQC7{aJVR%{p5X}dHIJG}Y; zd{K>Je05#F3#B8T*pPYZ34+JgEnY%U(Vqacd*ot-(=8Z%!Ap8Y5@>m!74q7$@PjRMGUKxSr#p`w9cu zL2iH2-?5u|Q&ZR~K@irbm9ev0Y*)vQtkfjk^5c$BUDH_3m1U)%LsH9bv}%;uLVwzL zvPOHGN|mlsR@QF$a;Lk-AQhy7{ev_X8*8R~V1~|CwpkJj;l#Y;(E6rIJ_F?2=*@>~ zdIdZ|!J7&D2JioPkMKI^5lr!M8Xu#y-6cS*egB}!JOaBQU*c*(sti@je4&M1R7c&A z=j><3&<7EYQ^3a!^GmKBxP^+)9w_s&u&B^Ce zbmUlS<}kM%6W}oaoNuK{WJx*}+ux-B&dZ|qaAkBg^=NE>>w1(ak^zxGopiL> zUoJZ4Kb;)r{mT8)1@HM)S*fRt=EKLpDNbDFNT@>6=j`M=mrhB@;kC>SteAvvkV@UF zCbM=Gy`raZua0TSyQP#WKkZsV=$rkd>Y)w7E+`D4Rgu2sUDf&)bLIvLmn%Oogu>;} zAZU|`)q;$!5MP+@Zk)L9MBNs~PIg6TmChQaKkemEoKm5;tYaRthXvAH1X=}>)<_%O z%f(z*MTg4jHWnQR)T9<61(2@OlQ())(Y+P+dO96IIiRIjyOHzg#mj@Ev-xaMHyjYYZcEH~b3Eq0J6Tqv&d`sEF4zw?Q~G8cnjenI}4Q_l|zvN^pk`qNf}89oT- zpRCM^@*}MVJFak{zxvBuQ*a6wCZCC`oZa(+tjWx^K)!*zl4S=q4BM{8u7i=VtrI_u zeK0y&yABcgtFC5<8=XTpex{!^lVb+Hb=~P)8)43+jNR%?FYLuVr-aaCFm@C!U7u6c zgq{tf&WYU6kw&9WiuqfOKRk@N8LX5zFqeOkKRk@N!6voF4G&{(?9#V!75QTy#$1)N zx;|0|a?4%h%0D#oWFoR<^-!^zTO$x}fvb7Lbol!DXVyejUCyf+DK_$9EXSmoiXW^W z%}3kp##II@YAnN07|i%ol#0C7DW^=NbfA-j9Dly>81JnMOZt_lxa^s8Xu518^#W<6 z8yoRN(%Jv$ORWM%9@-<-+&sm(iS)`&^3}mGWQ<&e8n4KWm6aK0H*>{h@(7;ld3@~n zM;Dem-`vcg!j;O{rL#EWUu#v+0VnJPJ6?xe^|YC z%JolL5_VbC;XGr%o;@2}v&2SS6IGJ=eN6Y2Of!BD?{CZtljTtXBs(bvvRb`Cs2nAB zQq%b>ADicAv_-alC$)^T%^-MNJ51Ep1zJ+`_r@+73^s z=Bt}*{UgPU57ins*MXU<)?z9bSG`BAcKgfj7e~_Zy`oMp%yz0Z{{|Tr%w>tCuxAUU zP1j?oZ*^xS8{=xt%dL5}v2+X<540EC9d#$&Ou$-1<`vz)Re7(dtR4QuSbgYSv4aJoUi9aVb%$R1@Js34IUT?QX z_XQ?Wpa_yb(N#Rg={MvW?KG5katHkVZ7>EnF zkQ9k3qd?gyp{Y?Z$7WqzousbD zlA76^(_S|26GE)y;X<%38?3HyX0N$ul}?q}x#aelnl4nb_Fz>a6%IPp!(u!?Y$i<~ z!IHYai#Qry>-wXyDqJv(AIa(a{Zc2Ir!6zYn5!YpRe#=hUt-2USaXSWMOnd0g^#&v ziD8*b-^Pa?s>d5*=%KEK_u|>>?`-LN)wM(&f;ZQrViC4b6p>|*s;XXJ0(bNx?rX_r$xx?VQwgpwW5$QS>sXCX~S4{ZJQ zfj1kqe(b`pX*#Z)gxP*2Qsj*KIw==IvcIU=&oJDat+ z_6g^joO@_4V7gJpUAHlN6nv0rlb#fP-4NWNp$%)RSq`B?HD+I#oz%$9E? z-=V^B@2+jREBTJ;oqPA=mY4NzmnbfFWN~l*)Ve39*}Nlq?UQRAw7zFT>rrxH&X&Pm zI-XWz{9MOp^E{S%o5Jd+k*#z*r);XK-P-ijJTsDf6&A8`P@td=g_GzRij1&&>P4C_XJ!s5Drl&`m2J_Fm(4&|GyMxBKsqerJ0tpB9 zQRImokfoxFwvTH?a!e=I_&B^;`|6$lzAF5gjhUVGvQIRnJKDKbWUoBzu6h^5_}q!6 zu+=GDjI`*hCbhsk@SVfRXCRWg%;6YK)~}Int*@*eBRZ>LCVO4&D{EQLBygs7_t`BG#q2;Pm&dw5&np8u zRDj)u1sUK=q}!@Bory-ruo=v<6{3M1Tw}4Fb@i$4u66wMI~lFJdTZt;P8vv=&2?gw zAKC1Ty%!*D!)$J+N334X9`U{e^D#%x*9d1rEM4C+rAo{oc$>JQYlm*{ZWz zrKY-;Pq2yWJ$NuwsyBC$FW>UdDgdl6kv#%$ie!o1eZ|ksALfrM>s|Hjzq~Qt)xRCY z_hFLiYP<2_cN9dT1I9#}4p~`H>;Kl%abbbH-@1hb6}#`YoQV%{e&v!wKC5*^(;F3K zS{GJkCc3tAaJY?~n3;8om@Q9zn;-jC%o*{F=?lHtkMo_C7AKs$FHL0lh=1LMye!%( zkr|Q_JB&b<+>+ckrRMAsKlH6GRSYFrh^4UFjWR z=NEP6CJHuV?Y)-loa=t-DRzBKOU@jx;j%5z~6@ zgaL-f4zGo;ZV=Yx=2sPMA7S@9jIbF@H0toT+6q}p9K)eANzd8IzhENdl+QEFDIDP& zt0p$*m>$!zTHl18sXug|^tYU)7jN^P+4Q(~pKQ6%DXNnn8U=Cq$Y|-UCb`-d^Ry~D z$!9k5JgYu1-1)_Es_*ot7ntKz-BIM}6Rvy9xKeriY>&TOrScX#xWl%X5i62w`X@Kk zn)@Z_hlV(#!v^DZhFhWfc+03>Z8nTb^U7J_%vFa!D?FKhqtdw!eb9IEDAQDv2E`^D zkP}=-arRp5oKwUDW#?v(__mX^)a<1TwQgLLG$u6(*Od4RV%>YZo0}HEx zE;r{Di<-X-WJ@J(==CKor~Bc&ootxvSoASTu9 z(Q=4AX+7}@$)HqU0H_fR>`n!(Hg7k12*F_d&@Wdz$5)$m+H4o#5gU3FEkr@u#wSb0FF7I+0?Xd-MYqA`ATD< zxJoMx=CHR?)8UkWJETj~`_Ww_@>(AHWgFEil^vWfL(2}XO_Bu zd*xbHY{z`Em&+C=LD4dCv|R08SFKg6=Pa6o!Q5-}JNCJ%lU>X9z86---r8HN%tD$**n0kN~sOGo{hlD>HYWbj;;JfPE(kGk+M!A^8vi!pA9uB z{=3s;oUe>*TeM&6$(A!(62Vx~rcjoZ?pztVJR9tIA4ci?<@aIKf!YgpZU3Mn^oFS+ z>;UcVuk>KAL4%xXHr-0BH@XYN`{G(j^4fBwq0_X~v0R^P;#alV!q!j|=#YjFBVX6B zzBLihNES0j+%JzpXB76nR$(&|ossSOI0=D{-`ObHq;TMS^g3ln0^85%at|GKbqJV# zkpHuUp@TEA@EsL?P^cq5R=qX~wjR6!52D`v6?l>u6h`ciKV$+`8^cRF%1?8NO7znn z;h$Q*c>co03zsdJH#b$Q%Q45w+OlB`EN&q&bs1iTGU%XeEzEKFrd`+uH{OZAF*Ytqq<*(52 z!YyUt1W#+IP#we&2QipxUKNB%-Kb7^m=Q_8F;kJc@%Md(8M*YsY}K_=Q)$Qnr>oGj zUS079*Y(nCNIziK#iy?f=lh8)Js^rwjXfFOHC6_7kwMmOzV9!{>cn_A!<(Rzq0Su4 z>>O*Cy~*5cccCY1wbQySAsYpO>nP=QO~dTcyDgk-e|7O382Lr)%&}EwW0u+b=Asq~ z+o2P4gn>->ZC)H;Ygy84FN#*m7D%6>F6p9Bl;*J<@RqvY zmG%tIm)D|mutANae;BFdBL(f6T#aGT5St(3lS&)RmT8!Cosnaugu8lL?2pc_LOY5ziDrk zcF~Qu%r{2MH1+D0HcacuYtb%ENF!;Mqn=@J*y!fhqZ~)g27-yUCB-c5>|r`@b-o+;Y$Fl7SO2f& z@z^Wdo4Hs2ZI0IQ;g}3{Z~oM}dw6J0m8WJyfsaA78Nr9`12E2#X-hncb|NH`V;ogQ zDe=r@2hS>1mWno}Y+*>=P+BSH`g7%6mZNc+cN)T2ar|hUabrbYI4j*#k8Z&RPNLDzWgz@S6e3SA2LRrDy_2%GBECq+p16e7rpwx zErfb~lgqA-oY9r!q;3wl#KHX1$pgjpJTaMzE`>MxZC*5%bR<+ct*zlxR$||uTWR-x zpo0%@ZB2(ZF2)=s+8;fqkXMuC3ZKx0S;vs~_U==eX0Ui*)?^ap7P>b+&eTQB*~kwa zX~|bc+hvQX+Ie{NLRe4<4{Rh%wV51DRs}H8w5sCz&Zbi;%OKT|GS{3NUsE;*HMu-Bn>Tx6$1~Dou&bpb%1E1g@%$WtF2O46 zqw2Xx%EL^4eUN2;gD$FZ5n%DaFUOesQ4%#%LP({*JTo|E*^&RUiB9W{yfH zvdV3`7wf)JTIF=g7JwQ`$I2mhy30*RN*h!{we7ya@jCQQeSwL2_Yv6IOZ3uSBDCg% z@?SmJ)S#jbM4XOia(>^?AfLzTd{)V(M8k`XfN`Quj)ggSlZv7lrP~}Sq3$ak*&6D+ z9P8dKD<#+a!Vg#u9V*dNg2RJpu9)`?=4dowW0W1}U9D8SCpWJm^6>rmP z3f~VB9AflD@V5x_9hWooy3g@C=NTShFz=K%*|be?v!hu+ZH%bEOjs8;Vlq z$%LgLQ|#`uehkrJD<|b~N6LI3zfI5Ov{wMlY^%0`D%_z%9BCM4miK0j;*zS|Z0TJsDW+J7QQN)RuVt!U?N)C% zaxNOpS*yF&bg=IAAuVn4V5fM!aBtdMI^A~hFg9kQG(=$LUA?#?6c~+eu9#$Vm z8cnS<>)OdJgcsR3uDR9*w`1HtZqQ?M?&chA{VC>F^_7G4oGHPKY179iU#|L%?-YAI zPri(#;%mD(Js}jgG;9tG>bmDh&NgREOsxH6pn&a2=-&NAp;X7QL=1Dbp7-7V9>Tec zn|JMg4&m4x3E>_4(bD2#=KZuRpH3T^MLbMC4#FQMpGnHbiB^i>@Vly01ASRk%d%DWUwwY_-XS?DciVMl7gAk+l)_X@l4G{R}mbM z>#_rbI{i3Z?yG24fPGfRDhVV|8!bVl%N47YmiFblOh0EO{eSk}FE-Nb$`6y)Sz8{h zR@#+!V{a_)r)qb)x~Ey}ZvC-DiQ3_?*)ufBCQY(uG-*vr#bU9$hQ%tX{&Y8IGJ)f@ z9Rv{!7@iFfZ>YtPmeU( z?UJTh^?moxx#ymH&bjBDd+vqhG~$7SVl-?oA9ef7HUUFQ7uBtyf`m?yO2%)Yv{reD zENYyvp*BQ6t=As(Py2(XIAfti#jAVmm>4(jAtwz-Xu6EYw~dnExT*L%E1UG59AUfl z{`)#nf;cv9VR#$Q+MV;UoTqrv*gGEl{?|wfrZBv|^+P@KZ4W8WM)}XR z1KXIB?jwlt&0n8kGJSQv`<2xG9GOf-l%8Mo2E*2~#^_>1-86_%UKq|Z4#<;o+&SSM z9mEaxROh$2%VN$!rT=j8f=4`hl@?cJ#y9z9B{V7Ti@_1)a>6>b(7K)i9j;6N`dS$T zIPd*%6{?(q#wJ>~-(Vdur*?*o(PP|4+dSscQ83H!xYs?>hgzIR4Wwlh1Pp^AJRiZ3 z;kQNPR*2XzP7MMyH5_;cw6TQ}7BB04&MI&3QCdKeMiD^T904NWuWrZKtTlN}x3)h< zk5Rl~8~`EAU_HQsQaIyJZnYdrFZ0+08EI9UdU~+jp25o2RQxVWxw$Pl9*Ou2xar2c zsI*6>{8tH@P@i$;uWwyZ&YZsahr*sq+!*}%YsR0$h{2-&_{vNcy${3d+bx)CHv8@B z-Ngy4;z%NRGRDmWogWm)aaABL2{JBThroCpklZqi8&H?9^F>+)Jet6KtM;*RXLvSR zoXvsOiu1`4{0@kaE{@m??MwFv!GS?g+#8@>Sw%l6I>`EfE{x9>cf5;j&Fnxs4ce&V zdWKi2xoG}78}PzvIhF}S;}ziMz0VPc)(y;~-r&gfd4BiA9JtQG_DI8yf1`f3?Ab{b)RbpCilQFbd6+9-;B(JYe+9!`-GO|5`I6LGgOWb5OCEWYFdN`bPq5yci z(>o_k4_wD1eL5q(5WXu%<;0Z}nueX!I+lxvGwDDeJpY3U3FZ4@gwwaFw9s?q8PF@T zN@yT+`fv9JljG1m#?oN6?AC{nXlcgmQY-FUSqXg*6Vt8xSbzoIT$6xnZzTP8!8}{m zTaaP*Ch*k>hAg#O$VF6z}lP^bN_01oJw!EXa}oUeWEtSRtuyj_#*ku3pO_RK_wb;*sHWhKR8WkAhf{A0I{FW6NueuW9 zNuzGMLVefQ#*PnH#dEg8q{nsvHw4h}pflo($x@b{fx$C4w^49Z52bCbHwUM>+I4*j zm6qU3s+`oA2Y>|ov3kN3Fm$YpLwEsE>XX(Tv2dNuCVm#3mXr$XC)d`6)P4fUk!C^G zF{>gEf%jPZ=C%AJzjx9)Vrrbn+KcM4@J$SQPr&jFi&bndGPt)8@khtO@Jtoe))8+h z5-gv0+Fjgc82JjtHMC`13o1MA;OOz5!1jLX-vviMO^kK8KO~7e;q26KYubpS; z5W1Vpn@@2==Vpy=?K7mbIGdbd_FC=7P6TE#$XbIf0UAKBd)nz;pr4ZyT=Jyx#oe*S z3yk_8ie{Vn?nt=TW%61DS#YCRpWt*@f84`uK7biZnade51M*t58i!6-h6XxF6Gwvq z{388EaUj7D4&+EQC>SB2>cZVby9I)tTTp80wthV5L2pvdDK1da&gnBl`UGMPJDEO+ z+6*G7Htam=JgZ4DPzsUP%dK{hx_Ya#Eo5 z>!|T2)FkyO;xGN*n=nC2lmIlkKZ-kHJB{K3yte z1;pG+g0UG_JinB6AfhmKK=M!7x@^8Lvku$=+X4^6VO1zlVO)FwYw2m{LiSBQPGM%h zL}Hh&X;0B<3xX-qO$E75Q>l>xb$O*w7BTt9)~VPN$y2gbDZpi;L{oL1jqCm(DqWPx z*I~kqlAmdgxcdl&FRPzmk=}3{g8}|g3BWQsgmDW~pbZ|djNDQmWH%%uWXb8weM=(1 z5rKwyvaqxvT8W!1z()E48AALO6uNBs7t8-;0SHUB?tclw0Ep&VOrgluif@O0A#y=_ zmU$_uoR<|0hR4Q53m3`+UGya>pvfeu7Fy!o0=;u=;MKV`cF;lZRCXN+b(_(pL_Wzg z7>8O>lf>w%*G16kwM~|lHOoe;Yz9Ony{K3kA0gC@QQz=K z;|oNiZHVxj-!xl^k4~<%L!}_}=51J`m0*e6Rg1Z%*$qn2P2KZ|8`u^>LxRKWM*74Z z#*L!x{mp=g`Uwk8;o#)jzUL{P^nIJ^D`o`@677moD^t%Vto5c)8NvY#C>ilXltvOP zzOqrUhQ+{o4ae!jv?a}O!qONEXQGQ>QkX<>;Jpsgn?UHN%_L)IovC33X!(|(lWQBc z2M3El)Lq%!L!oor>! zw1_TX%vhS#U?Yc)4EcbDfI7_|I0ij@It0~T_rBCi*D4-~hUe@1vuDbmH)C>{vHOgZ zsT2D`n_~M2IN}_uwD7_yiLBE5<5$lQp33i#EX#rXJ(5B_R(g>Vs zg9$8U)VU6KceceBA?He}ETy)tTsNtBcz_~ z^{o6~JgyKl{6mnpVIjv8>3#&C42{ZRdn~lz$HjsvFz8hx1wKdarkQ|oaOMjO#6dfC zrn*bq2-XY^p%41d_ZZxL^ijU2i=-Ttk*gJ2NfGViE+q5d4Dw#(Jr~ znn#q_PWSnEW94F$b(q_X9Bi${WMgI1>&+)9fW0TCEiZ@y>9uyZT%Cx`>m-p zWUv3JWFYuTrUcuoKi>MY0Fy5xd-X52{x^1*FDHBVFSq_*JI6Bho*_`vV9L|-(36L; zZ+SQi6Y{bGzuHo1fby^kDSR=hh{@t{7z@;rU@`=0{p6dkg0yh%+RQ6-!Cn+S2&WL< zRUMudqtMI=-6CPJQ$;Lv_|^YHE62ZzPl{r8G@ z*Y@|O-qaF(|V(PyV%Uju61 zm5GA6q4ciULuY~=H48)arsW<}{1m$ZXd(E|()^uihJhAZ8*%;+I=K1P=KaH)u+w!J zD4-`hk0wX7G9NRfpBu-?kwMZyWSqnbmq9S72?;?hy>39?Kf_sm#+(5%Zf)phEElr^ zNnclr17x5DBrW7V>w^};I}QrFBnb{^KgP9j*fn7kjw0=Z-LW15d5yf>a1J=DN8+IB zVVpgkfY)@;SUSTN+p^IjI$#L*6_%lg*~K_KZj}5fgQzYMi6@9P#%FL^M-L>CtO8LE zVRc|Cg_c-#^8GQVhs*b@^^6fBNnT%21c+lOoSH+CN!G#~73 z@2=fFfbNL9>p`&iVr0vx=WS4MXIQT(gz&SJsQ_h>Rsh-85yCO7UvEI#Y=fQj>fXra z{d>D^$QR+RLB~`rM1i!Oo~at@{fTkO=Apd89WZ#Kj8ccultM6EYfv{R@e(0W?4>&T zY1)}1z*=7cS{(6~8yUn>l^yYau7Ef;0z|ul6dbdBZd$(~#EXbKwi16g3xsB|VmU5L zU=;IW>J^)zj3M`gSq3u02KNsOHM!LAVKnwa77und&+5VVZnt<2%Ll6gjhC{1uxte> zh-zrGKvZYGJVJglEmRr!?zN&d1r>g$461!~sIAKG5{u z8i0(5{Nllb&ATsQV@i~+NMjzdtZ-ABVH9eW5pRi>bYHy1r{yDB;gV#W_DzU$u`8Ne zbJ{B=Hi{6)XnjIv8*Uh%I2uEA7avUEoi@zN!5gjwH6fQfrzcARHeaEl+YtL{fs?p4 z@$Nv0Jw{#)C8Z81^760-SR$-CHdwuh5<`SdGo*hUvPH=`A!M&?yPl$15aAZ^8IftT zRvTyni=#GF+p5A;vaBZjNFl8kwS`-GmIt*ddXTLN zM^rn_H)rTHjt*70bMcCuS`36r-EPs{6Iao?XzW}_{mxS({7;1*rTYwq>9aby^Oh^Y z@HQUUv7qNZ7ZjsKRp`>vp3F$NT{S&rl}SBm(--cP<w@opwebs z{8|0g?3d<#Acyc^O|jOlR&Ix@z_}h&vsM3+yuxmOf~+K_p{|-9>c6F5 z>&Vv(jUX5Kk|A4ioKS0z>tl~|9YUx?qsPqSfe|c&BF^v zIX`h`Fu_$b1K!k(gdyRAxNi{;ogm5)gpwmX&JxUWm>*i?psw<039@-WDzv6jg}=Cz zpEpZb5{q{a`53c+KD`Jl;Wu#3MRX)nRBpqk$u=k{#uj$qs4X?`j}!joL|{t-A?j7L zsC;IcQAzt`BgB1N*xFcQ2FpoDLe0%eJ8-d?93x55h(9f?;8ESqXf3MR)ZL&n03atD)mFu zZ0FIuLYNRw&Xt^Is!64xwddo&9CM1alB+ai9<`#DR_g1W}C)Co3yP ziDQJ)rQoB7L1NR>Fj6aEXjIyU`ARP`sn6T$I)%ZEK6GA;03|Wyt27PhJ&>yjaUfCr z3it!93z@ADiOWq%*yM=`_@$xV2?vaUdmUhHPruax4G_5M!0N?pt4bKQ@wQ40^=hCl zcPN5ieDh3Xdd4s{d^_q+yV#FrK$~NqrgKT%yPzA-4Q#)hdLf!{=3r$-` zm|Sdoyh+hA@2zcaZ`>6iSrYukCKsSGvngYv_aEH9zj^MGT*7@3a6T7hePOo)#blfVM zE7GU7;WR2WlxpB1gHMc86}jn^VgsS5JQ09sJm_wt_F!<15f}R#Yj@wXp_>_iv`AYh z((6F-i>)0bJ9rv!Dt?(W-yd*1;Z-tc7+vKohO+sL+cAoy0XYh{8huywnrzTX% zYGHCS*@dK~9nMw%Qr)P8nZ@15?80$moa)A?*Xf+sZ(rAVny;2z5Ef)|d+YBY0Of0C zZf$Q@w(jBWZ%|DT<&gd0Uvl!h)f;HESz zeOQ7(9!_IN9%opVCpmuQQ3*r-EX9pHn=wAVo0Q^ul8kw}bP(zD5B}z>NS{}cKG;kB zDn$D5-~kz_$6)wx5B#vWhPfd#=A>pYAvH;_nnaSoobACwB1$bNgx|kyktr<%|HFUU z9OCXyB)dZz_|EVI=`tKJJZHR3QcPh=9|B1*8X_^?5iXxaF2p>k9eun|CtHY;q5dx#7uCxq z&Z>3C&1TdJ5K4a%MKxzitwlje!)!`FCMv5y*vcum4!^=(om(J+ZA2_m3|NktJ$ANC?q)xTZ04HH!&DVU)R zHL~BaKem~fgIP4iYF;!V73JcOypSUpMf_`CAVW1u<-aj3=MD{|%0=`O83!u(z10SQI~Uz~Zc-Q2Y@JL1)()%2jfKMPHzvehGE*s{#T% z)CRO#Gb! zvvxkl71^O93^t%8JY*C8)G#UUNJP&3C4z|k`U?tR!BSN@rYj~jpjW|XF zIv9skg0wVv8vX22nKteUnyO41FkJ;A_@+j*Xuh`8Q9qJ4=reP+lt=@B;d) zR3zi)UNU=Fst~!gmyS;=i&A*yMfs#uG-KUfI(t~E;1a>h`tMi_S!;*{rPshDi7Mxh z{x_GRIV~SB+JvO1*mDxLxfF7MBIQXK!iq`eU(M!PU6~)e2W9SV$AN`y$7~FQ-?*pN z50JhX^P6g9E)UeD0`>xnr|LS61h8$r3`ZM`d`GJ2!)XZ?q+T3FAa9Pe1YMcws83Pn zFUr)ZIn1YTPqn_F?24;eEP>)dO{~@6MrudH;4(jMG6}I;SS~@tP7U&$!qFB#tMFqH zdXmqAiN_`<^qXged&{qQ8rxJ?mgIJsG-64F{VRmvfLr~)jf=4?( zQv3>6`Ph@FvJrH}=tAu-l4k&GMn|>vv>zmvRl*-lV5jB5q>Iit?S;|e7?0RWK`0@L zlda1eYTR{5SYzJ80bmXfU?}*{MII&Ov4xy0HZva;HmcbBMqiqO@COO|4*G}RpO;V+ zP@L2aV7o37!dp4ubf!~X#MTG^Nfr2-FNEOYNpyJaQ~0CLb|6&Q^W`JPq}gF4H|N9Y z)aQ91JB!2>FQ``b)x>_r5^xgmU!DNUsC1^wlQ7O%6pAdz6IX>_&oXayl+clLEjUz9 zagI+Wpb>F~KE!a;&=X#B$asD2{`$r?ynAywok^if&-2E!PJ5D_!f6yc$oDECafpAR zHjhOrhn}E#Bkgb-)-*{zARg7xAW*QlbQ3}c5*b0GxMU-+%RsF^mP7ZEibDMo`aUnz zBw*QsV?Jrfa?{ex9h#`S$Dj82S(>l{^;>nzW4=xKK`Ws^RGV8*Z{ZlfAYcq`9FT) z3tNAC>qqd`e%W85aeMKGIJUoTFM=rv4jL=4zx89({7o;Q)*gHJZ*6t)?zjA1V7~VH zbn6LT|AxI5zHe`yZT(^P29soO{?XPy#hc%;I=N12MgG~=e~cnuu_7v2?bUy>^yY>5gHX+`^b8!rp8<&Su&C1hRpvueA*h|l3)bgwv z|MIE|yYj-p8Tpj(=>*9_^j^1#(7`86P~jJ<@Hj5q)-}7Yl|LKjxSR*4tjkxm-unI$ z?rZ%{@#_;GQ^B^C!vG11aS=ZiN-@)}shNS27>u8%E*me4N>uPDIlW5$M0;|@U?JeIZbxB!~d1fhRl6|O%9qSxN z>jjF2^tUVD-EG1)&f7TLjLnJeumHmd7bBejqE(CtMkR{d>ZTi^W~h_wn~_XnNQ48j z=W0}|Rkny!EPbfj&)=q3tZY@nOrIM}sa4tDap!3A0x)W|v_+$pyRC8SZMhc&*VeQ- z7b5hh=Kp4K5RFgIO6Cb%fF8u1CAIV zs5gNGk!gH~FagCSePD5KtfKz zF`fN&-dNhWgIrM+p)?4Sxwvsda2pF-nBl*kukC<*i-G&b*6%~5`0J%YVG&xXZ_2&# zzf&$HYr~5C?X9b5sNCDRk-8PSwpB-=zgBLC#A_vPY`u;WQ#}baT9Ku#28#S<-pD6E z|8?P1pKSe2dHwZ>n(~mpB@vdtn-vJuVtssnYZZOuWx`BanLpTi17*INv_s_E%Qv^y z@$$9!@{2TnKu*ieimk`U)lu8%NbagceAHWUT4FQC)1F(`9fR0k63q>9`e5e;Ym@uZDASMA=?n=k|6 zvf&=i#o~@Q1VZuwnrjW)$j$^iS{Eke)mkl)q!e8|vB!2Gi0xaDnDW|Mr<_J+WyW|= z%&O{4LNRcVn_o{8r79M9J3!-{_2PonFl)reU= zOYmCgO-tclD8j=Nf>Wwmht;_~B^L!#uzK?8a0REUM z%VN0FH0DClQeO=;5NSadnw{a|IB6qqMEN6Ug%SkDgiMBrm}rTcksMk+X(;k)4|k9y z{Cz}N}X2;vgBSXMu}esl8Z!TvVu>PmZ# zs+*&G+m@$^Bg;Ck|GyW!=hD|p{qGZ^b|6TArTq+bwTSXCLh{4*Z1d6mTXf2 zd)ly)91WMWyM6u5z;Mf|=I?LagckU4=T3H>o4Wx27Y0gU>}r%-)IORneAe zUR8<~^sle_s%W1bGr|zc*I-ALFMBdm^ZIV#){0kGa>KqTen3b!SZ5HFDYt~$p6^w* z*O^&lfwxv~09Gsf6mi6oV4NsK8rn?>M1j);>1coWcsxE|Szdnn^l9T!f6^EXAK_ep zWTG7{|46NuX35QLXKzv?Db^dsHZo}zKRjypGP_x#9+^aFyZ0CL#1=4`AyVyw zNJvk+QG(xu14C`2nX8Qu_yfre4W!zJb)LtP7g1<`%E*1dDgtK zIBYHI?e$vjMMGhaI${*zUn|eRpp5W zQqBh`uk&kg9`|{sIlxLC6h)Y`Y1NmT-7GyDPFkZ!SXR;wYQF&7wirTeuT!-ig$j@7 zQhq2ED%%A5i!wsa04r$atV@NMvomKd6lt+&inL$!1kV}|;OBTuHNy|5jM~D1Ssh>P zVFuq>+uuaK^96`J(vDThUDy|j3HIoPc~n3_7Ea3usK|o?0C+v8!7#uJo+=Fq;jupa z@D#$QvhJ9=e8FgzOyS0$bk^qp;EPet;x)%epOBzkE^^{5aB+B}x<+SBVOuc?VR6!Z zlr&Xa?u^@ZYENVm{8asuIe;nT+Kz6vl6AShd;i|%TlbLjVi77ZBhM}pIP#-!&Zy#F z?Usyy6Y%V!fN^7m{xh@@=Jf5|gGCh8RXi}yDI)34Pal!l`fNXZe>N}j2?^XW^t!jU zzP0w&#zLH(Bd&rM9r6xf#$_1{;NTD)9Y&OpapUem0j)7cqIo_XH5M`Y`7=+#!Q#bE zy*D}T{8C4(Nh3b%0WXO)fR?UgYUk6JQkT?&x`f2|V_fMp84`72n%8hc!y>AFGQhQJ z&)F;LKshX=Ug+$d-R;f0i+Ve2wW;=@zfZ?bn4HDA$??EjoljLu{ZR0^yFbBwQOeH9 zzn-JV$vJi$$E^CC1CBkaqMnb~n_Vzsn4V0Faeh&2DCfi#;^e8%r`+fe_ILsX%)lF8 z00WppLS8jFc8zBW#zGEsh%7rj+TjW&(SrdHN@U3HU$e_JXGxHyb_;jYqId#;tg06p z_uc#V5RQljBLI!!uI{5GzB>oe^D@l@?&)B7`m$hq7i~qbZpyuxLu@4&UI}E+gR_|Q zaZ7_9hmZ5JU{b;UMbCG#GV$&bCshGNosCj4ep71NN5TTeX!8DG-Fi|-fW1#nZicBw zG%b|U(IWnWUEmT4g;(atq;t7)Yv>OlJ7)sq&O}u!4K^(w-E{ZL$dttOg27MUV%NhnHQuRde&1W$isSI2S z*>S~m@RUi+sp9>!qb7g4?yn zAvJ&n3}*DW1w)WN5H8dd6K)=>S5MG5n@jIzU~Xn`KjJ zc0NWwcHayFQc@t^Stz@G;fzMTskKwN^PRa^9KL+H92{&H?GCI0CvsS7q1=P%>by6> zwPFc0b4V@}pFfX^xecLboZ6!Tq`mMQ7Ol?9+!#XJ7#24o-N}jqreVc6TZqWf&nB(W zW6bTK-W%bvpk z;v{mJ;lbjX&`7cfW#_0kLz($2kMJrA*31>c0sBP&3WjRTmmBdAk+_JZp}ZsIGm8}* zVJ9%uNWyvXj$N*$0dMK!3hH1h6foGZV|~xlP!O_&$fjhJP%!D6uW(i2Q;+(vj2A-8 z71RqC&O1Q9VovJ8@}3DSJZE+Ww6*`yL0sLY<njSs)n+C>3+dNd+@Z2y}=h{Dta%6WF%bhcC=?Xg8Ji~ zZTckKQGJOCXr0j>|Eb_O>t1^7$T9w@dMnU?%f^!Cdx^24^3ta#I0FG1*^5%%`Lhmk zm_7NFq$jHkO-bNER1B4<7nA=0agUwP8V=6Y8ZU zx7@P4Yzga9TV2>9G8d`$3eYWDwC*^K43%D42wd5Hsb_ZPq`wHG6JE?Qi+JO5J0F55 zG%E|aGA0*fG^9&+gyBOPEs`+I&?7OOAp&_sh9Bl-A#va+M{p34qhC(8yvXR?h=jcw z?oc%6pe_duX;lSh1{u$AUjyP7fn~lsdoCczvWI|OAh?VyZeS$hknfS776o1^_1q0! z6D$&*GgafMfJ3=p?1l8jr3u6Qps|pC?y3n+44LF$oEP=((=EkOzN6 zr6AoL2D*~?iJ5p&6qe&UX7rfGk>m=mxy_!Vn|ULX1X4@XiYV;TMS>tkn{_GEWSPr} zx(z0!3TC@tN5;%@7T8X2fOwT*af)M5h`O+o8kkin5SEWmicG$mO>*Ok3sR58rcSeb z!s`YYQ08ylv5_=0rRcNfk`#FEMJL*@N)YD)5=Wr)<+cx(nq-VYXvz^ph1Pl5JRnbT zzfJ%$CyE88pajM(G=iLhPeJlQLVI zxrh>kl{Oi&!61_o$z+n9vkE02nLIS>Sj26%`9RWea4`5%xYxPNjJt8Sxk%G$z=e-oa0_ToLG#)w6co9t$3(Fd_s66 z2|CEZcHro}G}ILD2`cCBc`E?z8>=bHa{TMH)+(WC)^gUd(VZkhO3K2NdD1CkK7*<_5YEv-yc42}Kdc z6d6^qwhgZ~Y#kzYLQ9vJk)O2(PwymyOeOqf_=FLUG-K1k&89gH$#F*_>wU@?iiY)< zi;2t42qB%nH~sT5B``7Zjs?2Zl2uZB_TlAN4G+Lt^#Z0U?nP3j*C?KSc(dqzc!sU! zqYt~-cT&AP!nZr%mGBArYGFaLB{EUlLR@BvJM{Bs%1gb>1>|jtUtgTBa}5Mnkedr< z*|_fwI+I{3dNW)tkcEK9m(j*z?a-<%!_dH#9)>s1E$dYGaxooyO*o3Hl$Yv16b>>e zxok*y*YrQR{^u>E%1eX`X%|{fKl3p`T_Yv@&_?4Kvfj=WX$sIH(L<-Unc$v9pg-A?>_E>pp-r+vSK!dY-XJbbX-^u>OKN+|7bhg{p1O>%NbpN^`|fbtlkdm{8a|Y7`yl2T%I#)!TRePU9B-cYEbKfzE}= z4HoUIN&U6<8 z>(R)jK}~|?CG`U@-G~TSV0DtwrIrIumN)Z5!u+Gfv!xqb+fiR)){^jV=an3rD@4Sy z5w7}?wEe|!44#~wEYTpB;JLOu84Z^u&~&+Te0pb@g_bW#TneP`z$r~M4+&pL~t zAPp={;Q0U)u0p2Tl?&C?g>h{ju=D_=mjNM^z^F^2>YW`b;tw|NZQ|ZXoQqkwxL|TW zeL@EGa-cgvEFTn7YIbN=O}(<@@*Hzfe@6&?9FWISwkk9YcxVA^QRAbSC zXfA_EZ>WsTtcfX%+FQhUj$7R4EF7X~>waEMwg9q0lF=p@y;Q%tVOlViq{!n zaLOR6-~)uqr^?he{JYQQj8f@lG(i&U?idMl)kyUQ(zyKHjrGGfxDXPDh|-hn&D?7- z0~AZJf-vC}ns32?HFNYcK(Rb8FAhrO>25=EJjJc+V#a9v1jW2Cm&RFqPHyh8}0UkA(FrS(NL4Wt;2;38T5Eu z)Yq>UxG3Q^^Xz`_RmwL#pz!LtgwMlu36`e~0WnaP9x+)iwp8}3B2zAzgjGR0T>D15 z9wnFmhNOX%;+<#V$>Yhm+w)(KaS{#}()&-It$Phw?8q*6rejxv!BNdDu$m=->?6%9 z$B>ssFfSTdhZX{p6wx44n55~Sr-=yh7|+H{$>ALiYdb9G7pEa`5-L0#I_-%ZicdUq z)Ga-=T_}x=bxc9$U4-z&wQ%2k*jifXsptUxT!AlRly?@@jAyl0rf)ph^#K>(ZBKI5%c{qNE-*Pu7q?Spk#yzAZ}OV z$dcoA5--T3b%?10N%9!ETA7yo{3En>o|p~4saU>tcYkgD!C~|6#=W%%+lSya50L25MH7{pC_2Ky z11eIr^WFuhMog1<3KJY7g6)JZ9>|pl3L4&ZTEpH2GRL*S+i22z|Fzd}d*I>b&IX2| z_t%YFM5{!Y|ga6q`WY=ta0t+xuFQgJF zufGJ5AdKQfpy9#DMzMiuxxiOI&1}*<+BkuVOY zVoSDSJ_DlpN6mw*2TxLGT)w%32-A$9xEV~t3WPUwj&YsJ=oF70l_p{Rai@Jsj4@9t zjH4XC7p0lhs%yV1s(6l8aNplVil;@fnOdgwTb4R%IGDPy)`u=J69b$}sn^mbfv{>!&mgG znGHFM0ySZ!*kS%R33{fHIzlOJAch$EFR)0FS|}sw1PkO1>h7_JV8FxGx8BE`2LX1Lf@RKjf6eq3JU)P)$9pe{x$ zDC5HQM!FK&u*}jj1zz`C-}|o7WKLba>P;?#01_#kfGCwQ8%!%>W#a_cP;2Z(>B^p1 zNuUS$kvRKer3!h87Amj1htZ4XBfL4kz?j@8{RbB>bF$XI{uoRakj^eZ)C<;CBlD80vgIQt( zk5nPDFcq9;Dz$v!Y^>OAl8O_DQ;CL^gym>C z{Qp>`T+B|k?z-0MN~~5v1bitw2D||hLx6+ZNHYX(Z_Syb$|Jp@JZ0Ph@2^f+!S~E*H^U%^r9v*~+#9`SdTCZ1Yuvt$DhJFVw6%bQ;pgyrY zfOo^TPe1=c(7vpNgY!AdLhOI0v?Pb zDHI5*;#98``>iuvha`c^*@&&%EP$PKQEo&?Vx?H$dw@Mmg0af_X=Un{DyX5#m6>`e0{4P}B~a>d!$+~M6ecRGcVY1# zrUJ?Q2z=~^zo=8|jMya&Nnd8AV|U1-cjr6bEs)6+=bv%a5vWtT@kOeF3QqZtQ5WuO*a$et>Nzdldp6tv(DR!_Gkp@}ElCVvv%^R{0O(K^eoj3N{5>9^)@p z<=;ePImesVpvout7mLxPll`UPO>VA$(PTA#H8o1pBE%hOSO}bNF;<+SR zA(Yg@qhHK4}`$yyaQtW<>b76ti&Jc2n+dXXQ=t}2092^+UP?cUvm+S5_(h8N!%@k0{; z6B2S54bEUvXtg_yhAP)sGjd#?GVJ-2<#wzIsOTpJySZlZtXx@4){HjBi z<8>0a(?Gu3l@1yvYI16L1YG8(*}B20N-B7yAzjDr#4@$tK|8)EWap;49i2|!PJ{xq zQ%8Xj*}ohD5^)APAqzBL;^>lr1kk4@G`!J4DFZbxikQ5I z$D<|$Xp?+QW*fLQtEqBPJ1fB-B|f^Zu05=lFMQxQ2R_yLCqgYen zKRc$Hjv<TB|1PaEQ$uPg2lI!KiIgw-wDeKW@GhsfML5-$gHBMLC@dfW#)3 zwUy-?ZcgSxMGr}1u?N00c*>^Pq`a7A)2<9HRs^s;)UPs$_7z*c)C8JVzbSoQSHp&> z$ktW_ZORgTpLrRO^HbIXtny$ntv>fMr8O6Wo!*{|;2VROv8gERI(2xlR6ya>-tm%1 zK`L%-Zc{}f{ee)PIBz1a%tlaipU&|FHl^D2n^duKW?r66cwQ}LeS{qgoO)0r9=G7k zPzZ6#h5bkUKw#hmT?rQ(2!5#vi-kfhH!Ojy_{i~LbTR|tqJ~n-Oa-D0nDq?zKK0!Z zD6JkFOSXV4jbdjcmb63)q_6;9o`n_1c{#yGqZd2l>&t-1a*r`-i{SM3WO4X(!3%eECr8!{L?8O#@~9mkPz6a@Mv!v_esJHv@T zj7v0Ufn7lf*Q%g%O0Ua75{Oy}jZ!2sped#Tf`=)fH69P^`VLG}nTi_;iA#QL?*!iF zt0U}>wI&Q8WJYp@WhC<4G|q;uFfSqGAMf{u!BJ}^#xu=PLNzzg>E-&T0TSx3Fsypb zQb8?IGHD-6*z>(!)FfOX0vP3A67V5b1RJq&F~V>P;R*!UcunnAa^-7S&GFV`f;yc5D*wzK zG!kV>FsVU9Giyh7$n%Lk1j4xD&#^7492QemWl+qdkIY=BvpO$J4~(3?5YyLj?4wDY zqWcKjf4v6=dqwV}Wpp@G4z16EAH>?hH0rXaz;w_^S5hWr(|{#tZ3S%-{6rK=?aNLX z==3IL@7Qsb)+XCTEkgbTwn}G-;6G`j1aLHnOaCc9P}4hSAT>q%_@WO|q$hgA8`biZ z=8+E`YO)SUfZ)DbzIYQrQTPg80q=^uR$8Ltez7VOF`|kLFQAo12)2FZF`5N>k2p$G zr~s6K2SqF&O_Pc>bV)38^6I(|4Fn|+y|8snJ6uhc*u34KA>T^tFIksLs|d=Gok~ix zWrR86@E3!iZole-;UE>kmPqt7vzQghf=y?+w)f+Wrrxp$Rj+tHa~f&9eQX=RU~-Ap zw9;xlbQ2n=c#N2tC@P|AD0X_<>cl(B=3VG^^B9}YZWkB^@(VSs3Dq3(9&8DVd-`-R zI7VK4w{X}7nSxnVCxkaX9vs`A;zogV_NGB0yl5Gs7#wRGv$K1!tUQRaQVH{hcKd15VFOvQ43MROJS}aEqk*p-nfs4oyw8ZmsRjk3u zT?6cnN0xDf1prKudDbxs)%T$qB9Jay9%OTYW9)v!=++%_o1Qam%D=Otal%)50 zTsmQ~v5l%B*u~Qr`LG>FqZ{&lbq+|BbG>#CN6c0JjxLys)J)s3STSBVv`y8(f%R=N zjKmqnJI`=1Q`e`;Z{6dXR)L){w_MBms!6wyZhx;7n^@EA855X=qq@b}k1E2g!%Zmx zlbCn45^=-OA3T*A(8kr;5-}uZW<7iq=;NjYGH1{%n-UNj!JQU}5P)zl!>vZ269f@h ziP%@b811Lj00E4&qw+7IMZHU~?yV$Lr=i~QjSWpB+!2ps&BAbP5SZSL*kQ@N29RaQ z!fqHSRr}~xgL>x2OZZ~D0DQmQaL>TUwFb}#M`3On4=^({)mvxG;kWKYs`BUP)xSPm z`PQAdW#ERz>^6u-ek z$@15)u$m8BG4G}hxb#rxFm4*nFf9|H#yBJUSi~frm}h6(RSClQ2>Vw#!{YYxpunzb zD~YG142hhUARH1x3#1t!XjGbnlV91Y=+lAyn4eRenyks2XU0vMku|Ux8bDKKv!s^o zu!i(SYcjmO@CT6eBsP@h4o*7rGfHLfL~yLomO}D?!9L_SxG$SNNG6&^6_{IK zxV&924^>Bvf;XFNJOq3qdZ~zi@QD6&TOB3QnO_`){14fJeHO_?^uh(#cE;F?@5c{l9!HO9g zM12xFc|8q}{Enr|>vUFYI2pl9VbKW898%Q`bJ{(gqqYRB5MM+(Qj^>)n)GXBQ-f61 z16WQaZ%Gn-2TqG;jIfv*Y3E7gUThrm1%_my^L&tPy7)jw1WAq-myv+{yfcJ_MBt&3 zjds8=W*rMF@dGGQgx2$-IT$Q&R*SrtV25x0Q-P@{fqagkQ*a^;xn7lj=Z~h`cs?N3 zpALJOHkz^A{K42(FrG(jtRoRu=Xeixd<1!le!`O$iIb6yl1*7`{q|rW*%3(`9BQ(z zCHBIEiA4pQRINa*MMsqfZYCW+S%?*a<0&LR+X~d2GIvm#y`9 zFbR8Ex%U;s&gn9qC=;g*On@g$z@G`UP-*> zFd(rTff4;IOIuesMDQ6LR73E_WQaWTJc5-(Z%Z90L~&M>!*owhaApLxQlyMDxM9-o z{%nHlz?{3%)O6f!kL&ewWufP=-{7d@IRYyI_&J%>>8OE}{KvS66~+{kIq{o0(y0?N z5TZY5@;suL286^A)sAQo2u2BZXAyZ|32_sJF;FHzx&xCjyi)*5>CZu#0>2>##zyt) zWK!u6c+{xo%5c82KV3&A&$)`P1Ui5VkoKbDHtvMD!~bsG+L4GASVY8`CwEFTiZzt^ z4&PyJG3%JtXl};<5=+4pL5u#;-EEZ9?~FZ%j%SvWgIR-u~Am(o$&L6jmwxG zOym#56rqI);`KNdwyatO0uK=o2^nlr#o|kDcY4he>@TVU+cx!ZFUcoO->g&mdFIAo z9IZ3bnU9V!;eEN26}%6poQz%TfkzBai|T=VndlW!6|)wIB`U!BJ}`U{7-lDvSu~G^ z`2&W^`C-jfv_T)1BfYPa@FY7tIksQs15k{OmXRKhVo3jpT0=eIZAdjPa@I~P5T{t* zVG~bdv1~mqGrgR%%gyfm8Hnw~VEb%4;au0GeIx=h`aC~@F*nC~!W?sMm#l1@-_e1r z+FzX*ww+6IKC#u=#PouyeRtP7g5O_Gc8UY20jl5%QjG*fiPG!WvGbFxoz{lj7bJLQ z!~8^=$-5DQf-YHXfTvwujO_gRsjEqF%F72!)}YG~ZDW zUQ8zmPZ$A{OwB*D6EIp&0X!Z5~rQ- z0f5sb&vur8aZ1U7X1y7(pn@!{xsZ6Pfhdvy_t@@T4r`N=+^G>vsm=W#Y@2BRGE3KV z1nW?%qqTd2WCRureX4z+e93fV{&&_iH@;e-u{6M@5c)_B5+X3f#0c1* zxl-Y9rw%+SvsFQu1`NH;P9t%D7>TQ>+wOux3R{-WvC>mK$M1@QU_hcjC5}MjA1ulq zmak#7;CPyapgf$6+NTW(42EcjF_r2*`L`lcXNZae<*}&ye2WA9%)F0Ww6Z?+G8Gj1 zurnM8(!uwkf$*?9147`yLu&6+i8YXRV6OAfVC*8skSUE~lQFM=flFK?b=d$SuaU%2 z>5q0f92hjBB4d|L8pv267Eq#2!<7SDf>e2THUpw_ohB9oELz4Qkg~;iV%a;w-gHW!LA*1U z1m{#EDb>P?ZLx@Hy~tVGB*w@jxy3C9UGkmK)((vd;nbT)n9=xW89DTj%QP2D<^sAw zo&^KuJEAQSLhx#7R(QB0j>REHXhrD5#7|Oz$}OZq4-f7kgTtOM^0U|h=xa}drv!(O z%vr|<&_3Gu=4x>(A4V2URn>;hXfEPmc;xhn#R60lY^m1KOl+6xEwlhzxUw3+6PX~h zw&!M#^7N^}bZ`o9Nd!|;tAPKiIW@-ta1-9h@(aJB1v{_7fo8fFANWW5?;LyPib|`q zm-WB%Xw=K_?>vgDfI1h}X+v{>RQz${HQNCa2s3Td2f=kNmvy@cTFZ_oc)yF!gANb)=tAYQ@$MkPYTGZiJ)&jfKojb4p^leA*>@_@h% z(!~iLxUCE|Jy*jS=GqF;kJD2q+mQ4OPznI%VAj;mo&htb&#I^(5G!ULPpD9oZvSn} z?h5nynPfeoH_JpN-9Dh@%kx5?Ba%o7u0CLqtT`Lo9(<)GOJjt*AsI$BDayOrB!LLd{9go(W`-h8i=y zO%T&`OnWHoq#df|>#^jcE}!X&2%KsVh;yXICM%crRJ`$2TLC!iU9)gyT}qPQZ+d=9 zd!VvKv0QTOo~Tatv23rYx1@8KvU}nL`_)26P+z7F1+=y>-2_2g)Nf zUpo{{yDZ$y!vPGIgjb!MT35`o9N9{-fn=PpbG4E){#3BnEUiu2qv8y8Jh_LAlS$dY z4rT9!nI2zY)s9p{^&MDv;667+5crSrG}jPPhg9NU(U{DJ{t@d3RQh@ihj7W!`zIsl z<3Ev+fktR=pn)W*uOy7K$P@UeG9Qfs63BR$=VH+;;=Zu6R?7vmjY-vDFHkt}9&)Qa z8Pa`+YVmG14b~#P=AYW0oI8dk<5_VrnBde&paiiR){40F66kSWV<2D)K*@_7Ezscw zBT<}}2FG^9d*pshxJr+8r$Yk4uuCIU7Z{&|mIUCLBP)-jav(Xp(^FV6bCyhD{;VAW z`Ut?;gg!C&8lEs;k2OGf4I-Nfzas#Y&zUy^AXEP%7?_>_;)<8z2$i9wWE!ARfWIMg z=y3<8OZmQo@2o{Sf)+|p#IyTXaxruKkrWv)y%2TpZHlPcHTWDLiiGw)R^@!X! zKiyIP8thg@qi9)QQufI{ahRuL0uwGe16Qd<1mzOKbM)Eu0GYY;`SnAG(O(aZR~ zLnHZ$v|pId%pJ}4L7q6BME){*+B&c0TV@s@+yn+vck5a>4x1tQ@T9$_#gnD2dYd{#^(s7&pgGKB zGPJJ)W?4ZCe&8XwCwPis1<&010Qr!a92xy$i(}!A_4hhZ-h}@dAI6c=76dy9|0%ja z6b0q57}uzs+HoP*P@;XjIf9~@w(*j|)G}tU3uH9)>*5TG()goT5NUzNBSuiw z(jiFOHQ_;EwFw8s5#UpvTZHl}U#M)x2FT%(J$VYJl_!@oz|?0#iVAZ@R>C&?Q*}b& zg&LJsP3nck1nxr3E@ktMtiWiw>dg1x3Xm{hH+RRe19_oVN@g5O)i^fA%Oz`%k;jY| z!kVXi4d`&MTEGd89&7UJ6loe>rsj{BK|r}M$X60}Rc)I>tAJcf$H5S2?hER1Hai-} z2FNO&(iH0CfjBGD_8_d4cb}fwd%bWIAS>VVjEO6dxLI|Kf zWqrP+${r**0c_JKBaJIEj+7l^ZAf+`^kw;|rej3|^|6AZ0wc_pH2e2=S%t*NycK36`^_M0&Vb7vajUKRA6%+ol}C&li7=HNpRB!^$~{8Fr0G5-~HqXqJ^ zl)$#jpGk|k#W8TT(u`l3*(=q9-v z_h(2(4TDq(sR6pg^&Z1OWeJ9qyOGMBLTSe-Yn7hM6j)4hiciy4QZCWt-FRnz1AXR@ zC<=3Y`ACeS0JTumj6;bCM3WPr!8fyYARm?^6#WR;Q<_jU z{sW5GpE-G1(yRoob9w6t+s;;C;QkAv;6jI>%A^T&l$%jGu7p#HUPde+>4t4-W$&XJ z?Pd0Si(3%T0G8k{fekh=r3$18BU^~C;xzkZVF}X;6yt%wby{gP*{wWlXr=Y$}*pXmj+SHrD; zh*w`u&imSnf4ubxUi@axVC>z0wDl)=_Z#xgRA77a-*5fzc=Ok1`E0G!|FLro7li)& zw?r+)sjQH3N#E~W|KiSDEb!$(?QI+W&fopw&cDZ3e?ygR5q4B7;~8RW;}5^M^PjTd z*DDloEApRxap%8dk=LXfLAJg5lP~W4E57+!0Kk@;z5l|m?fku8!~3t6_Urcg;MaCO z#|Sdu@X6>gT^MYJweK;O=)fSr$sV*T z8^<5GdB=^gcf1R04?K8?HtLA46!#|hIQE;g2Ed6;o3P)QP(AWEK)49iKKd95KmijP z#Q4PVhLeLZnj*IRCVHar`Q6RKw|5^L7Hjw4E8bn(-(S0b_}&l1E5}G;9wC)M;Xb`y z7o!ALaZ@L}>bOx47Ojo_^|w)D?aj^Y&BOPopxoO$yuWd9P~6+yFV>2^wf)1*^#|K) z`^Daa{k`3TjYd(JT^;r3;Ff_4$ZgM*xMRj8>zLoeblP=&l6Vw8gAO*>$1saYEb78J zL#M6Y0HRrJ8)A@$&IBjr835aq-4V7nn7|)ePU5FepEe%#Cyl}I(K6)u= zI>gO{gKjj#fAq2L5tvtx!pPsHh6^YFsO)BIFOk^%DX_!ihbW7S^jIaa`I}hIOKI2k zD((F>$myT|Rdomgc4f(1zq|Ff{{2rzr8i^;qspZZj_|d>5fA}K`x*GbAO5=W1A8=! z8{EF7+~5^EkTmkI*um%FuIejJjW56s>`Gm1A^e`}N8tAJuDWJuhb$XfA+36H=QZ;3 z;K+|&@Ol>|H?hFt4X?6yAX{-QTka@D2&(QEVZ^Zu6B65i+;Zv(saCyc*dWPkuLj8d zYh+<^Ws`LT(ZYRj(mWX1wS(OU`|BIcyK9FV&5ga?^|!B4j=><&>B9$)`z}Loz?EE+!VdB}@Ty86S6Y+PF~5>e zP(>}-iT#$7O?fN!`&-|HTK=2iwalxDfh$`}c=siLXPdEa@Tq9)$s181r&>`Ba#}V( zU<9=iSB4OH$csPyJ;;kGUGet!d?mh86QS-%T!iU3bW0rvJ@}QHI8(KMiE83BZ=cK9 z6MhatpJwf9eR(arVjcFc^8v!v?B4R`-uBud^zWVK=H0AZ1D^lvdi4`*D>QOhRZ=Q? z=(Wl9)zom{y6A<+9`6YcZb8lkRJ1JDt`2s%c8MC?5^a>#F++F><3|TU`sSjAwGM+9EJ8{H0q%N z>>D{gd9CyAVmjtol41)6iM$tMA$1^Ox^}uS$)oj&rytv)=3jc7*;EXK^fP_EmqQCOn}7cN?S~( zEw(E0yF3^#?P-xpc+x4JRo%)|){mqXYwI%~Nx7PafQtzmGaHkBlY(Gr)@ZXC zRfVor3hn_JkoQckE+Eb%htf%B%-eP!AudgWgJ!f6DRS!4L&h*mrU(4xI`{1=k0CU;|kYVH}dE zLLnjQqASbG%f*BJP4G5Zz<4Ba^uvziB?J+S2kikC&!n#ztt2<{#pKMp=ZK)ivd;$e zQs9t!AadrF?`5z}b z4)0o;*q6{6AZ$J9Gfk(Gl!|8jxE^VxNPmGcJRAL$FcrdL*vH7Yp!8*egrX2Ut6rKn zjl4n>P2ahhID(n>2cH;LVS#fRLKE%qZSJg z`T!2PIb-a4zyRN(KJ_NKRi$YiBxbhhZReF@muC!AbjmW}S^%51%8Oe!v3cC&&04Du zYd31RLsZ*y2v*~;bi%0bDW(Nl{*;dRg;{JsYkp0x?Gaj2txR&lvIyr;K)ynOsyPN>*@xI6JL`3iFd;~!FfNV+ z6s=Id4U9nb9VtsvmJU_#!F?pue?rNiAajMt9LF^x)sg~61BMN*;cqqW$gOrFcEy4Z z4-D=f1GTm!&tVf>8B+m-VF<&g$Xkh#oeR)7h{~fnj4%LzIOoPIrKIf=|FQJEwPmPj zxJz!ys4bPlAn%xxyHt*p6QZ0D?8hkrcHtA^c}54c=;8vP6Yu~|))DkT5`u($R_wwe ztMuv|CoVGHxVQFT`!L(E5&t=_K;9D@0;|0a%i6*I-cF4L zhji1`M#J+n{h5y?PWpid_$B*C%m0;(jN`}X^8C>pod(@89RRjm&#(y32TNCvc^hyyi!S-$mlo+ z+}Qx*x`hbvM&zu?txeaij;=XM0GvUcU?*0%=X*vR;%vbo+`^r~36)L-@e6>=EuMg9 zars1-e&qopLD~kbF{LDK947mhqX_ky771Hd2SfIAS8mqDMgHIS%EU!w07f&LN*)HV+!YFucfy0s-)von2xUX6tY zTV!O4tj)U0r$lF#1}RFL@Y0A0rk<>MOtoosQZKedI^crj@ik}-b&IIR(Z5Om6gRl= zOw{>6kJk!oqH56{L%Jrd=c)mlbO7NdBlrow@D5doD>ih~YpXp7m%D0)m9{R0s?4Yt z_@jgJi^Y|~@|?)B0nEgfVWbLOE+wF=^qM26emFD+nXOw+5!>lKj9yygI+M@@nQkoA z3P@nZ*DEaWpZxqU!L;?s*6(fow;E$nS?B|ewwUsgjS(XlLM{3yk2^hVnBY76|Gr|e z7XEBeu*Iv;s}aQQt5}O)?N|%4#Hr7l!!DTcdZXBGVTbp_qjv9&QoPo*6K`>VhA%8= zc~%`OJ^9+e-9>${4@pCAC17FhVP8wV&Py@~z`y%K#ulH+oe_Vi-(GvIDO-jn)#7X0 zRJiX#o{%lAV=KY!DNVxiV*mUsJi}d_5(WZ4M(4PG(l^BnChd)9oi;-ye|pmYDa4tE z;vuF{!vV3|fN9|ZcP(g|>QTe3;A~D>Yo7Ei*y9F6r4yA8k`7>|aTY!yA~~NTrM^Uy z^jbK2!(zn`i{!d37FNy~#7?O=Gjiy4Xt8Wj0!Qi^19o^r#7rdu>zF+_CKQ_uNADhk z2XSP_#wXa6tDu@q8GbTufs)B3I4!i}B$JKP3@0rl%8>gs5X}-dJyT<=LYx#D4{#!1 z@0CO2w{q<0OUpHw+~XiM&rjh8no&m{=WQAF!B8z^*bsE>%6EuUDfS!yWnJU zjy(^yri@F88qwK^hm>oMOp5TUb%Eyk2-!xi){`;e33jk>&(vaaB_o{L)w<&qnR?Tj z955c#(P{^dYasUc>ecHoz4bc{1lojg#p-~Ew}%K`{OKrM6%ywK_BqbsN1+MAa?NXW zj<3OmihgvqJIA>#EX-9mG(?OE7MYCk!PR zdAeyLqu+TlY;h8B!MPQUNC$(^TC~w+>+#@l?eM`tb9XBe7h4nPd=^FzrEx~UTFVW8 zCAWWsF@>7CFmU(D?df+-Bk2eotCctt)O`kywHY!7-jQB6>0K9QL^uZDlRdZqnWHD- z5!MXhH)Uj!qLYO+7mKry!ZyMDX#}ICp>`Zhn zR34J)L?aAwHANB$JepAu7NMrr^Zf}Byi>{*_N*CoynpC{OXn$R^=^FPWoDQwzZJ!DGO!(dj74CJto^n6OgRx<`C~lR^;z zzLUwcdTw#>0mBZ%{FRVqP&I<4%|)^}0%8#Br( zhqR)4B=2uj7lnARV)wRoX7}!-Ze@4n9N)iD-K4M(EBMaVkJ0GwR2H-#)tgd8!AsVA zdB8u}`nS>2bg>d-KixV-vEP*r)7E6R45+iMKFWNpT*lye$hQ(SI}2=ypq+XmM98>ayV55p-Ww*coeLYr&XwS^LQ50*u?V$VUF;a)wDOkiU@nBjxn)cOk zGX^Zct3;3UtK(+nBZ4n6j@WGg@svj-e2wyrzda!M5W8pS<{Qt>5$|~HEijm`)eFZ) zC?g<_Uc+DL7WRwQ?QKzB>ov1Fz>XnYqjhE%CRG*Hvveqmk(aeSSjCw{d5lykOJ}$x z4Vtk6K7LH&C`F=~LAG&cN!l4YgoAw*fetXXqU|P(?!DtCVteqA=j23Zgpa=eq|T7k zn;Jf0f)KU|34DZ&Cy53^5tx0LsSl2OJr*e;ebO|QDsmL$eTzDUtbNPD8iF_U1Zi?g zC4|-Dye!T9-V|d^a2aAyBcL18O`v068nsS3auW+w01itMkM@X`3jhbJ3oQ>=Y4rHE zps?VOA+KAF4yG^~9Y2@j0H!(#BcUG702J=e(0VeY7;Y*T%Sk|0cEwy3!om=e+R~3! z*DewJLKtS&r@=@XigWpppmTR7E$F1SCXX1pwSkGX*(7!(M$VeXnacAEQp=-W7ey1--VhNAxWZIp-K_@_Q~6|6n;WuYtR?viF`g({qKwK-07;H3d8kzY zu6_xK^OtBxU*d}qF(XF-6;Gtru|2|#&y2iZy~dbMMmhC8P+g!|jcdNKx4F0B(5250 z4)5ZCZ`|ht16gp)v>&XfuWmz17=D3xxK#-ATr53yAZqYX|-za7F}r;67Dkhviq_BZoGu5^<%K5NV>p?5x&) zEJzfd24(@A8XK~vHKL4rim-Y?RN4@OZ~PPkAprMLnv=|xRW-37Dyxbm$fzDrRaFJa z&#%hGQBgIJ?@A?ek;pO&^F8Va225SF%dC>28|BYwh#?M(TFF<;3PTD(=7e2zM+vw; z*nF#b_ue)p6q(sY{2CPxN7&1TBAajBpPFW-I>9!%|0ru&DuL)A7+ah)<+hpZA^_{< z=5*PvFybnZJrn*izD-c)hZ4#QCN`u?8BJs>c}na})7xq10>OI-Zw+gNjkty`_yWzB z(G4nMFujtHyBT0V2y{T{MvF+?ZpT+}hrq|dDaScM$s{TQ6w7MVV#e?UmVBW_7{QC}-fOP5>YJ~~NcwzjB-C_x7mUM*VJMy}Ji zW0g5btj)YXZ^FuCl|#3N9wQP~!L8Z4SVdl>GNoD;1-gVLfaQ@>NTf!t0_v0bN??bv zjC*I~fU-$v>hhvq$H66UEdFy}We7sn)I?n?EX^$?mnXT!s>51I6*ieUP79P%&PiC8 zu`fK5b%heyatd=ToG*|7i<^S?QEhv@2|HwMrKqjfJ~j-a9(w`b&ik-R_Rb1VZ&4!G zTf%DZ^p^~IODBDS!PJ;otRdQrYH9&WV!ixP-A(?Ds#v)Yf2*pvs(%(1g^*-X{Fz_0 z-5cOY=gF~YbaO$C1hZ;i!K9uZuad>^c)^oZ{CBemI-og`L7mVmFRi(fP^Gm@86`EU zH%T?k04VN1!ofX%CxPdPzwY)Rx0;FoPev{YT$@CUm2#)8YPg|AqlM?tdyRik+r^52 zFrU(O}&Zm1hyF#2({^vst)Z-PVh1%;pF+1I?)aE z=vG-h2-9guj0BYFOL&}43-l$^Ps;T(I?I|snolHBO2!czVI+oDEEw8bZZjj(tWAXR z%Dodp6*P_XVR1yeO3^W4ypj-h9*V+p2Z7|X#x;|1t5_G)!Jb+)HY8FQY?57Sv+Zy_ zOn)idBb(5rub&mafCgmDXEbO)_k7xdCW$>589mm&7-CTZ+4YbZi_R68QI0cRu?)Vg z#J?DNxZ+&5KE@ej0$hc+9iZ$2!F?@9z2=kWH>g^@Uj6#?j)^t-$!J9%>A&?1 zPPqrfAcLMP%bvN-&Vb)G<9ryT#0k8eZ%MqxBe2rb3~au!;|;mdI;wGAnSaStLj7r? zd`@U1kU(oT(7boN%_t>*OSr7EP!{m=Fl#IxS7Fg^J+J#V#9IfPU?ymHx;cGrS(mc0Cu5a;8cITugowk@H_`pmeisDEg{7crUoEab76(@m_hU@|U=?G)3YpJ}{s2$w;z zEmRjlKu%(OxdcdQ9{>lb6YX>owh-bn3Fncxzr<;5@Egvul#Pp3M4?KV1)ZiHTHfe= zgj(PhA&Oo*`-DPm97E${J~dLnl$KtoPT#`ORBkdN7L|~&0(0&or|obfF z(yt}Qzf@IAr0%p#7gnCYhX5aO4`{arttk}KWy@4f9|!HC?;=M9eBWY0uA55iEsHF+ z?U61S-z#Aws2+(RT1$H?Qd0OtiZ|~;#zcLWCMdYXwk^52aRbSedrq8|GB2vma*A3>I{K>mXl9xM=(e zH)duR%YI?=;ZkZfe3LtLpK{q)=O@1Ahgvi=t5?_bq>kenI~fe z8{+7W12iU{X;mgMGVBmT{Dg73Sn)xc=EiYac zhmVuCQoI{|pm>}L(P%Ua^Jfw-o8#Doi6+bX4L7{m%n%DR9GoR)teMs^CxKV?tC!(N zPT8layt(P>v*DZxtBi!U8o!pE0U0&r98Nif{u}v4_*TUsgQDqNF%WOs7{8Zv(EO(} z)3Q0};q8Q5?j!6%ci(gL@yII)Q5w#Z4SY7M^hL4SYn>e(w~A*Fh?4R0Q*p=*iPnW< zJ#me=I?TPefQU=j1z;%ZEyXp8km z1D=P+)d@Inc--O5YO;es_E{S7B=+=_%;Q39Yx4xtl-AD*QlhRkZVjB6O~Z{B}vrFZ~q8g`<0 zac9PHXG6@rURS6UfwyYM&(Ii#MijSZcxxs);SO$h>y-=yoW8=@ynn zHw2{FBdkMglfW8i=wv>=u$+bMX}92Tj0CZs#rQ?;RNXh69*AJ1#gakA>Xx&kx!m7K z`+8FVx%W0Ks+2%Dp_T>3l98Zz7_Qc!VNpS%_af<^kyXk<$x`JOLzD<(L1T8`p%;@x zd>n-FG6`n^Mi9j_l$3F4=GXu?p{fYiWutDzazR%L{*e$|2u|@#@lOhyoiDR(AOBRm z^@g!A^sjN64Jbw@OdSL#&?X28MY$4WRdpRiZsB4YWBHCZ;7J2i&32jrin4K>3!Oh` ze>~7zD7|$~9>Sv-N6H;L9*e|MaeKxCGO$9z5}NhO@y&E3CGY?_I0r{}QMBo@Ea(SRmB}3>K{?xO#|Z z1VS(DnKd!#$w*Wt!8og$Tm3rD^HZkQYq;oQ>HlZ%-D2#_vim-<1=;dgBgv9tIkMs$ z9ZshX$*NN%yQin8W@;oh$?hhKMbc!kyT_bHr7ow)Gj%yNb*gxoR>MFp76OlrBp3s6 zoTnhji{XbLL4Z6M0RkjQ0>`=dB?yE(If5M{2@)Vk9Kl9@|Fzb>eBb%1$nF^p6sONj zv(EXxeOY_$wbx#I-S*p+qF43l%A3HUZ%*oAt$lAT5t7HB8+o?qRt=CiG`NV_*kzND z5k9+MrrCp$Al@`!SM>^Tv8QCSt85=CrBCfNIXxk`cRJodbi0O)VvO)GZ3x6lbs>sk!e zvWU*k!o6>O9^i!^05`sjK7c6q&kA}cFddLP3bkyVF%$Y$*olS~d`9$^>||b`L#1VW z&d>{mHpP&P^f-+-JOpms{NT>R+qbPu)2i83x^@m|a0$)7menZ{5IXUg0__jpOCTMA z(qRuQ)^4Y-r~-3*JhzDWKSZXoporF9FXYecn6ANNVs>^vP_yJY8&Kvoc01O$I&Ws!j3FBK2kcz$K&O`iXXX6&BFE48DNzqYbOi9cSI zh$!N>?8VR3YbqN3=E|p3`MFwQ9dG{p%74Y1Uu+{k-u~AszsK8ONN;1L@$&Dj{5~&V z*Gp}-;yTlzpt{XBmnvJJul}>=R{Q5(rILwK-p}e+&aJ+#N?&CU%0 zjrSj?i0cqGt3#CQEufz6p*&5cyY9T2xyx#+8ez(lm-$a>Ru5{I z7aWV?No-^e$*J|7A)>}NnJ5GeV%_7@dza^yz0Y_RH#Un?Ddv5H4UiZZT?0=#vaQ20 zd0r885oo`6vN3(KGriDDjhv7BVL6)-eleXElc|fqC`dGym?@$F%X_*1{QJbCr6)-8 zjr*$R=H^y6b`|fIN=V&%gf^QXxUk+l<~#a!q-;n*r&4v|!B8Dm~;Edd8@l?DVjvs%&Bx6c-HFpgN4u2E~ocd1(!Qa~m+LQ2^fv{H40&|*+riwE0&eT|dob(gw2z5)&7Xdh@HrLdc%;Imf^+Xqo{K$Ay%k={N ztjK%GkaK)SbF7J2LcH)W}P6cP_Wos{v@V zXExdt_?l1vt$W<2Ji2U)ftuvim41qhy2($}fd;DTgaK!oQOu~^e|>}QKilkAN;@@9 z^7k>^C@WcRfGof zUppL1$4WqmPF9DuH+FCa;zi)tGcaFq_0ayVq#2u_yzYu50$yJto75<0UK&4}n`4D5 zlZzhp)w3<$g@cp5J^%K-lkrG7^ZN_$>tEu0w(Qr0rJd0(45ZKLQdJp-v6VDl|fa+$c1mgr(Mf<6#J8FP z`Fc`8-obW^MgyzqaFX<@gZ}<*8WOEM3TZuKs?EYU152#*LjR|BUap*?}F?Fb(mR+fVsYmDAFziUpCB zi&}Z0{N{FCvU7+brK({tb2lzW6u)+%XHV*42pcvgE6GJ5atL^D{0_IU?U>AC zghaM;&O|526Ylg-uHF!Ot4;$mOGKX?KarI_x*l*t+1})Z@>E^$oE==(MI)T8WXgZ? zVygD+jRBYtO7B8?A(tJ5VnD?PqCXdV{x ztQ$n=kW&s9-1z~hDO}|CCE^A9cx6E(m#*RzlsIWdvZn!CQG1A2NG0oXK`n$A-34QHj={-JtRH(&veDA^<3v#T^L zkz=dBumjK8+0SWU6t?HX@Z)-7p!>V(XkFYUvwvYEk2?5}K=~c$a2dC7kjxvR%r(Ub5&^5f=1H zvUQ_b+OQpCZ!$Stm#7M5aJvmZwntdhV>-*mV0*$;3`5L91#!oDO15Vs#p7eUXAnyz9nwDEyTU`ChXxDBtoiFuHa4FNNwuFh0iCJ z*V?X6)hM-s88UUj?k%arNV z2@QP$E6&xG9qYU10-Oq1#d*Y8CcI|PDy=mS#Tb)Hx4C$32YE@9Euo>E3o^4xGq+YS4x}096v;*65w~+1 zML3(#;orXr!F&sr{qcpS^N{+{2aiF}FB;TDwKo8*c<0La(vh8B8e(=XuJHPs(If5H~TMp0k$sV4L>n?j@KrqWb^zfOcxw8?Va=E7jvFMM4{ zWf>h|x`Wl^wn}OZN37mfd%CWPW;F|NRr3KNxZSYl)#9yIbzZ}kPfLtLaIxuUNjbV2 z%$`>Zc}er&y#ssn|FJR9%fW7%ELMlC0^j{^E`n$}vmL9V@13^ia&1s+)7_UlD|;Q{ zE5{%ks0<#tsU*j4p6H_Vvlh&E8H&0K(F^L~1Tdgpownh^1@zok3MpCgL?8&87+1Bx zeb`$&z+#HTE42}a$95*3#;DK>m_d~Tp@vfr#+jURdPAvEinyR-Uu zDr8E>z8Q#3KHT09vgho}+H~n&uUjH}-Xwe^`=Z{X#L63+g%`k)m4pNp8LDNUOg2k{ znyGRNg_!ukHX(raI0eR_Ek|XXNY>d>pi$+#En9x4G34!i=NHb96EQHib@ydD?J2jH zgo%B)zpJlgU>NO;pD+9E$3xCS=JKL-i$X-o6`KbqE`;^yl-EgC=N?etb?Hr;cfVVE z2|@HP_g){HOEGB{VHKD0lEo7i%q@QP3K|`Tf8mUY43?l$UF<+mY{!%}=C9z``2rZ~ zMjb6fYy69YG?#yG;TCP%tGBkOF_RzTyiOtGL-t`I&U7>5<2jqaBNr`$%gi#Ff;>D5 zElr%zJbIc=Gy7%&`20u^B8|0lh{FW?nF|WqRb1TR za2ETwzNO{O!Zxe>{swwiPZ*=5%9hiK1HCnv&SXxU;1S?-*f@YcVWl(L;!Z#Igsf^~ zouKBYaX;Cixss6RNe+!QE>~y1r`-@-L|X&dgsUK^xS5iCjDuwIbJrH8}EIeJh8q8 z{GLY++4%m86iU9o@f;F7da?Y5Z@w=~?q0q!!~&0}A+DUYY9Ge&@W3%zXvBUS{a8q$ zTGvENq@xYx7qLeULT|9JcOf%BHR8=F8&QiWG8v$+u|lk$<3t7l95a^^?BJB4sssQ>-$+R}xhoAfqoBO9xGGBOCk~Tqbsw!4cF3nT9;7izP@p z#jTY`_{MLKrZ5Bj_aHQCpep7Ux8WjX=Ae{ z;|a_fNylT^jhmR%P;K_QIi^SyHc7GZGfJ8~dM54ScR6pG0JDcKR793qkfyUGFyzS- zDIlH-L6$?o{4KQ3d@`HDIZ&BGNmhfs zIalE}HXWWE*PeqyT0H^yl>f-rKFn5R%N=>be)8)Y8D;_-{X;8 z7+MULM%gC)L-A92ZpM!c$nu+)zy20Wi=+7y*3$CTuf7!%Y;_r}|7BQQKP9?>-fcMS z#GX)NXGxT@r})1C*Lrf7wGBmOL5g>)-KM{Je6%yId^}U9bn=#4e>od*T_@T!uFp7n zA<<6U0{P!Jh=k~>O&p33_fAe}^(r?FpT{+bE47R}VVm|-_cJcS!ced4c@Y*MVfaR? zarnZZ|8xgmQ5f_7bbB&QZUP!u#via>z5M3eR#`7j!A=V~K*c@O(--@(3%ZDgv|E8< z*Ok(I!qUaur*+1>*73vyHu7YpKN=R0S4_7R{uDOIEeCD0J!L17&rz*L2`=V2qW>&-tAT z>~$Fp4)ob1mXL_7Ie@f_iva?OF4fg(+{m&=fcAKw8#P3`OFhc2zGFy>E#GcO?LW}U zhjFms8yNbs1BD*zOIm|zUo(*)Lz@;LCo1<9Nf1~s!2=AY%7x&jhZUiSOfnFR1IZ@H zm>qUb1U<(&o5e4)04AyWldb@}jk4^<=xH<4fjnkf*MAizEYSVj%ig8xyi8wn0Vc|Dn;)n}ynIab^Kj-=$MtMJzYZiL>q;=t0!W}GbzK9Vvgssd zTaCm3if)K!j-Yx4Ol+--W%@U}s*O3b0FT{@(yh}_E!FU_QF-c!8>_E^c{{obL9Pz# zM7`^gDA`87qtBbr$h;kc#H`_;fChYlD-73W1lZd?i`ZH{;X6vsku)-AT- zW0qR>)RY|4_FS7s^|Gam`evAVr$!W{JotvpW43`o3tPY*@WIujx>(Ejb>SIBE$0q z=`1M}$#+bfFBWv`;2pV5II9UhsS>){Jsg1~BM1``6B?~I3`<35Xrty0N6njtny+1X zHw79wBAq3T$4265&=?v}w;B z^wS*Ga-kaM;>10Uyb{a~MvvZJ`q+n3d0D7bjgBOZ^*H*du7&<{qE0{G`1ry_AiL0W zOa@b}TS$A&y|flPcpyaHv&XGPR-8{8D^^L6Z2VokGk64AH1XQ?$!?r0h^MqC?d>bI zrIA;Tris=*D!Qd&TDA_D#;?`D zmMHduRxu615$~(pS-mE$s%Ec{=o=^ucO4Zazw3dW)lN1AUZJTbhFTq}Xi`I|NMucc^tD+alS%ZS-=6Q? z2)A3%mI=QQs-4Aanig{OVb%E>K$P{-Pj<@|pb~A+LlxnL!G)$>NPrmlmuj-_QGDF*m421>cSyf@KFS68;C&7^CQ<4Q}bO}&< zyA`V^tvT=+i=05VZU()k8UK{_7yFZYO*0s`dJ$7+>p6Kd$~?SDSlan zn;6upZUEiT%w)mGp=8OJ+ouV3%Wj+zm1Oj$gPd(VLQ5IaEU`79u3Sv5H8vZrZuzY~Qoa>&PI=fgS3GZ@>DbYBc2`j`QBeuz;;Au;J z)>Nel(ekUeq61e#SL(cQA$5im^0104_AmVu8tu0{bBcC8I0ANt_eP}87;n|8f0xfq zp5j!TuaS0nB2?i;LiLMVVo-KoUO<1XXn?PL;)Or$V+6r|X1vy0aUFl%2=2t(hVn^Y zUdM=>$4?f=2a5)YuA#NdxEF=J#mNx|;G_Ph->|g_MY$w}xvv=hHeSK>=YV`DXCJf5 zp5jC-czm@zo^XzQc0}IPY~f4ThQ9Jwc7Zr*`XFZw8p+y9t(a7kKG-qvHZ;XQ767vZ z#D2ygPciY}c5sFvCaHjZX_)kLJLzRpB(HOa{v%HU=`|jLAKK=`rW`F)W8S z1sqTj$y3u8B3VvOiL@0J2g|b{NmsEJ<_D)aI+kX7`PujYB%kbWOm~+rU;f(Hy4d1r z3pbOvMSIIR$2xP9Ix{`@;O@iw*Ke-hxVCn4{pP*9*WWj{8g^h(5su*;g*H-C&|3;P z8+Ujz^*>p9{%JqNm4P%grLjjH-5~+TqEiRHZ)Bd5$*i$)R3z-;rHHxhQ@MIz6kH? z9=BQaaF6)O4ctxJKhnrE$6l_7e#!_jd;dhom(1)x(g+i=YJk!@`)ci;!dNZqlBvxk zF_2hiWTtI2zJLRBHfWOawSx^<+4e?K%qD%ybvblNJXx%?W$1oRvpGm-LF~lI!9vzq zL~w#&!HWlu9jc;A4VdBVP-<4~RJIMb=3-4S&RjJW<7_t+>MGwdWq&qEY%{4_fIZ36 z$PiTBB4KC1Xd*h$>3DVgPRdDUx*GNsYm99M?H*gmbYG4bd}-(&Drjvw9aj5l=sP@Q zQv#1dyCWr#QB=xx6|2olKe)YFgp3MD&*QXaC;u%_0w|(;_U=!S~QuY8}o{rp&@8Y)e z9+{HWEGCWDsZ#Iaa?esET)bMeRwYY8$1p4CY)4Kl#nSTx2C-Yj){f;5s`l8=l+*)x z1-FYxP*kjeDd3U37)i~ix+zK}qFc7`Aa3su`aol<7kQB`88cfDjU zvf_rIiuMw8OTBl1)0Tq73ojNL{iQqxUvO0i0iC1umY-qj*XS=#A{8EsAxS}^>*wFM zJ`&+Rc=+zSw?4Z0fV0FWme7u*Tb8geaKF7e>WaC8v4DJzt7{JG5!)I|G~;X^ zyHES$)n7eFu4ijDoe|>2Z=74btQWt~a&(HPLG2C(8TqnTZC-vizvkfX-Iy>+$|Oo`v}be>571T+d`~R&wSa{JeRww0r&M z&#i9i?JuOa%|5rzt&SR%8$IrvTYapzKVy}nzx8aO*d-ZuN&JGXjZ z{pHv72q))O53N6Y8~u&r;V-n*_koq8bF2S~>ilYRGit;2m(H#Jbrt(lGsT(!{*801 z|5!=VBB4c*FTJ+L~&g*~k}UHYBYqW$g!!rs)pAU{Z4ARd(UYY*BB z(;v3jjXj*DCVSjuX4Ruczb$5H#TqkYPck>RU)7Y`?|Q1!gOF5y_+5L@J%g#SH0k!c zuyXqeEQN{Nljhct+HlXl=&rG=Sc$at#1AP4qUeop}mUU9E|A~~)SVm^# z)zQ%p2Os_8?~;2R{f6ZKBfH9HaQy<_HYssBg3NaB{S9F6OmeX( zp?9t!nx`j_(fjb$+WU7OuJx|n`F4+6{_bD9v-a(8nAjz?7r|WK5;?H<#*7lI65@RP z0?=t-_2&KS?^EO2JGXA%TKl#H>UVFg-MRVTLGRtW_j}iR_paSvyLJ8H?Q8dY_a5HA z$DJd?o@GJ-5!62ew=xP^__Mlf1BwH<@XaQ>JV5*1f3CUYD&R`(9_$cjSb!4 z<$|TT=Lhis81f|QVi_m6BIwES@!`_q;|eY*H9%|N6DmwFVN zl5(LVOU5rreYbUW+7Xusy|9QeS+JwZrS|3ffHVz3-`O^Knch}bMU0Zt}s_ZYKie98;J2NhF!=5`l z-*Vn-xt|6%Ex9Xm9|uRdFVPOdL4@+IKiz=K;zWjFX9J$LF%Vo~MY~)bH|-FvAoFzG z{J<;rQpKUD-qj%O^P!rItc!9)iJqzoI)}%3QhE~|m*vNWn#c4dt{`a~^-?1`>h*M| z*Hc1sj>slK4konA7B}Mhex7;aGEQlFbF#5#N*OF^T9FpJgicCl`wKlk`I!R5^6@z` z`p=HZ9Dv?qr>HJ8+Tr#IDHswcocHk#!Nm*Lgg0RfhUJq(kUBaG%N33vT47t%KY8pL zdTr-T)(3oGcd_y{jT#BnjMlUH$@wbq>a*p0tTmTVV`M=daCUKg#zHBv_hQ()hEmJ( zBAJIj!5oy?8|`T4KAxPAZ9c-u(-D7WYMAQw)XdoGG8lvjYT6WeM6i^BDAEgiT*^umaKX0qHNs0nkNWGve$S?}dI`mo{$C;OYD z@I^n|Fqsi10su?Bn`GuXy%@ryLATU<9~gVL?n$RK#V>s8iD7Cf>#p8yLCDsyaK%04 z@Sfh0JQy|H%NPT2^go06b?x2tTX$}*!EkM#A3nHyeP#W@+Wni?R-Hbz zi8qkqST+P-x)RJolr=;3)8Qu5GZ+Z}P$Lu6@(7y_Q`U0TPoGeGsk{wA&trka^>T#? z>YZ;X`W7`8B4f7)xvdk~b$qmqxlVuJ8glxmc-}P&h4aUzv*yNGD>|!_^yg(G@!yVj zpLg>iv>r;Jfh|g{MN@g>HXajYq{mvl$1CfY`#PUR-%-TpQgIIUU=3l*8aFOQOUS56 zxo#lKQP4d_pgE*h(uN}(pp~`iN$W2J5Z;1#AsP3$x2V$qQaJWu(W*o`s~Js0#}a`z ztPLrv^&M` zWg!~Y8rijYNS}KHUKH8rQ3(&c@!U~htkKuZn0BY9j3-jkdz;p_x981A-{GBAcU%~7 zHF%_x4bu3Vb;U5fzH?X>TB$-q-U}6uq5{wA!Wwy34nIBDM`9lQ$ZFvs!d@7L4F}u{ z`M+V+QH=sjU7*`%(IEt=xMxB2y>Tq|CkKRP><;ok5S7$oaE}TlNuvF;H&-8qRND-p zO!Rr5J782VA}FvL>e!=2wb9!hZ|&N?)SzgNxhw!tzm^vKUJKcpKzXlQL9DboUcbJ2 zBMb^}zqS6>n~05M!d3EQ_wrhJ?vL9}0*t6Xe&g-8RK8Wi9(R@BINJB(%^vi)v$y~^ zh#CNG#N)0ihlg8ly-AWUOda(Y>~Xn$MiA@ssn3i~3#~|1kGccPM)t;COY9O-aIy?5 zI=cgo-On9`(OF5b*Pxp7$HEb(T?ZSy91(``H z#?M0^W-24csotj(&vdec?#snH>5$wzN&A4v7{WxmlTCMxrqqf)9-2pK8fu(E{dMlj z_D2?;O_*mnOrg4%8bs=i8Jp#1jkO{mh9 zkx&+7MK;zuuAcc0NhW1kdD#)sYRSrnf1y$lpqZZ*IV54MVOzJY&upJMEb0g*bGib& zqfN>V7yeDOp!p$;*DmeFzu!)Z{jfL3F z{cEdghE}-pT;J4?s4{`x)r>8PrQRJAb=67;`-loBCA6kOH|vH@XW*tgV{;3jo+NoC z_ib|Wp{F=8*NH6?(-ZnhHK9HIGKnEnJjIMDcSphBx}4kZDQr} zTen#_dwLq_0=Yj27JkI7EC<|s5y_+kbE};E>Xvx(=^8~WZG zU!9-s?=MddD)e;pEj9bbp1R&X!botmytOkP9`5XMx#i_6^C+iC{CfOid8+G*M)Rgr z@-{Or+!AH$D8zq@95G%bdB#_0I=&h6!zjU8R*BX|Sv6|Xrk`cmYgiO2uCs(^)by^( zayLvw|I2Y0%SYwugzNVFxSTfYBAT~w=sOSyVfP>U4|l=sK%O^B*{b(y-p==~5%?~+ zZC}=iwzlyA%%envd zI^@viK4clmJVmfLPYS87Pwp*hY2!v45#5oZC31=VL5nKGZ0HF-Q2&r!|ePwt;f$rYhP=OH@Ob2$`!UH8$e=B8d{l`JZ8GsE11gbf+{w7T>P(ec9J)_8urz1(<+L;kBZ zjaqKXUhi5|0MwU=?2IEZv_>nftl_lyFX%b_)8p7}^XQ)dA?2D#&_x#HpFd9g-A zPH;!9*3?azM4=ZTPLZYbw$=3vwFm-{3V+iyTmMXw{nhmIe#E4s&OTbc{5;(dt=9FK zU3Gf;W9qlrZH@RmW|vcww&hI3r#&?Z4~shNtY5!-!aSwT3l%DG%e8^P-Kn&OW$y|3TGRC~eS?aAe5CQxn$oQ(ZiBw(dE% z+E797)Q;_HuA%47&IN-!0Ep4C(E`x2*9y4;CG@arPoMT2OWYP!hiG;NBCkj$$s??g zR~RxH+XHD|)k(EWsDR(+oO&-jdd9xh_E#CCI+nmE|G2V56pvE+;+Kp?Bx&$$16#+U zYsn5elz@%}|5x`k>dq#7_V+ipiC9^(W8t9Ebr_*mzX_!;u!sGu`1%ZI6N;a0bFL8< z_qA|yMuVn=ys%Is9E1@%-&{Q!@~{F)1FLFyI7?JY0iinLb7w-Mm#&S!QqTu%RizmF zAdH9ey_M06%?X>!EoBuvIyoen+nMI}uA%#8uCwl_HKxxDACeHW+Y%8?(_m%_qa!~! zH4#yB=Cinz5M7$f%c5Fsv{Vt!EFm?yUNvclbBNp8tydK0IwXdz zVkrEt#WivHdtALPH5`I6P^fq2R1AU1h9GE-$7H*J_`4C8bFP z^3{}j+pD^|+uXFg-L{r8nyow4IHXY|>ub;DgRIX_!jO#>HColC*Q%I?HQ)t8m5Qd3 zR4svr)I`CCoL(Vs=)rNY#@W6`K-QOhl!V0&M+sz2gD9$8ikXVYQT!^hMy|%-o zh9KRbj071Lqi}Q6tQEr6TGB+yqRWw;%&Wz)Q{BYDyzkVx!Zp9@iaazi;8wo37?zM_ z{lss}Tp!e!CSrYywB`pVhv+T1J%zL9-ku#*+jQuq7z>WPI4mhquzM%sCWg|47aj-M zpgyT)TkVE|_L}Q- z{+8+9ylZJt8i}>*!&yWETTCM!9&*ds<_O%P#x_9c5&Hxh5O$(xqrE*>)Fo;}F;+Kg z-W8gDRnTQPi-=FN9fans~j)~IT47wFqI8}XS$2Utk_J2 zQy24{9EVvXdwae);Ry}WK%Xu%wJhd*?`gP##zzHNBy~(yl6MWD)&i4eQeMV(uQ(T9 zk*OMeTcIFV{qu;!qCE8lf%OWxZ0vEx=CpUkP@#pY{$Yfu=DT}!mxO#3pd~NAQY9`| z8)ZX1tre%Zqb&sNyy{ykk5>s1`Raz&nveNQx2_0@ZuWOREjDE|D7&Rlt}uYn_8`Wm ziC(n#s6uR5vJ!I3L8U4k=*nA5n^%Z=zPFCRYDsRR^+;lgG&kS7TI3K=S!zj7meOOk zM(Q3$X|Us|Rq~Wrwt6afgxwiYTMr{4QR%OMq1Ue>;x+{t)vAP<>%mabv}1bl8*f~S z0gZ|Tk-DIkWI)Afz^G}PdS~$V(_IaZwwl66aCl}+>4nkUn2kEVxjnhsg2EjDJWHWn z+x`=)kW+qU7O=T!UmQ<2*e7#$V^dJyq|A$Jn%%sn3VWQmOzXQ~HVFbrG!VD-dmVJN z*gxqqDtm!q5>4Z2$FS45R%n4o-NC!V246QLyQnqePT6ZzGoS1*h@>7w{#f1Xniby8 zGz8PN7bSLOych0yZK0}V`mLYT~7p;IW5?BrQw;J-{T$jqrKL64Q%s$ z#wYj5WV^-Q1fkh&4Qpl-D125bZOeBijA~k}v6w}#1{1WCZjEq&1(w2<69KhWE<7qb z{X5ZMze;G8 z8hmlG53eH6z;N3x&C3tX(6ZS7xGdvpEAi`2)KrU^H2vVLfDc3l28KsEiiK=eV@(T% z!(Gq9%d4ajNAti{(UZq}x{FGB2-6dU%G0(Ks-+FSrJ~m$=}lv_)=w#>)n!0odf;!( zbGh_bZ&N>Tq}r&EDrqS8DhZWBt%c z-G*ilQeuh5!^7vJb#au^Yu00Jq8K5^EfQdMR;_WNVHL8hExkFmXQ1>AHUBhg%(8*B zGez;TIpRnq#<854NtYFnaY?!=I~Dz&B8Uq@eJD%BZAUSiF_rM$E^#WSFx{9r(bZ4{ z(Ew6Y(zlvie-$RA#8jF{=0eySm2vb9LAli;-AH3-5}+hJRz6~*NuC)>_15%VXf<-? zx@wp8C8p6gM$rITZ_oGcUcbe{5S!Rjo&{wnUQ`O9ovCL;Q7L^|J+N|%qOtXk)#)v? zbPY9`mnuv``C&(`q5_{)Hk{H%rDYUBfNk2G&X7*b?6g`1b%RF#29L`DRjaVwvITf> zZELx77`!`a-C%%|kwFEuGi!7imzxw{HqfPGC`)|l#1CgaHJ}pi$v8H746t~rEV&(l zL~Oa$p==onxhqd(B?+gJYHv0kTo*&UM~s!UwQf3@%)hEiI?!vOYT1`nP!)g|`yDsc zvru`}$DzcDO=Y1C)FXu9o7*RNZ0Rs_L>6AQSi>528-5bKgKV_gdVl_s?JX+SRL9-u6QWBMJRfQYEHtrHc}6Hw4}|#w0W4BW*mKpoD4dRC{|1 zcqi?}Z{scg3ZM@+9-A^w5Ab|*4}ASd9rk<54yc*5e$}@&Cmjp4J2e6>2Q*;^DjKL^ z>d0i5Z?fTt2H?FPUyMOn_!|Q8zuC3n0A=r2|V~~mNCF<~I z4>JvZaP$6yTX*lIHe&*zsn6Ez?HfRN^Y-0qH{`BdPk8^+S83@KrTr^t9qaR%#+nI8 z^HeErYf2XJDuARM5w%8gsGFzTs&3cD9$`f@ne`XUyt2p?xZT-*a@_24{!UZi`LuDX zLrL;{k$r{G+0pi*)FwC;Of5^O|GS=^i5`*S8aqUDhZiY|M$5`pcifyDFq_gw%bz2| z##8h*x;UDQ@*77A-m(1ha+uN?u0ffNWtK)TW5(&HZU8iWH7t4hv+muxw6--mJSMy* zYezavE%UuFMs!&o)RHD#qd`<2^b^xau*ml}AL|se=4aKgowRKdvpbl@a@V3%Yes0}|)Qo0_E_qD^Ym&>yZR;c(-GD28KHL=Sv+Ain-|; ztr4;yyBa>VxuP28DY91*x|0ep{pPJ)G)yxjVMyG%vNfuK++{5bN6Yo5UzP^zclLZ! zH`NmICCl33rcox3!ej?=Yq`Y^^$%KA-HLRP^8E{!+K&^!3&)!a7i;~lsH)*az-g_! zOO*tw2;xHRoPnu#!-iEP_38()DY70@W;t=~1O)A$9OhO6L#fV7tTBQ{pI0C>>kEZF z8&hgL0Tjwc8793sJ2lxvNf}}1KOM3qjy9jBllJVJ+2gjFCX(R0$Ls6s)mr-GG#>*l zV1FslI==_x1`kJ|qJU_ETjd>LeF(t*rACU8vj0ZM=V$bF2y@Q&Uy#TUBZuXb@Drd6 zA$CbfByBLz)3Mt&6}!o>NK={vH<({n(q|84N9hf}YK$V3VWo*OEOSe+6Jfs0OK8-@ z@Kh|puq*-%@pD+(%Yw1;QZS`u+%z`hm!4jt1(IEH}9d1#-SWN^3E>&hI~#Q_%*uVP_YjGB=6IXWkJxR+=c71!Z4pc~Q10&$!_Y zunI|^(c!F&Ne(S3oYJABB37f-LwuQ(EEHW7OI<`$ldjOMPs(GNk0?biqt|U(YZPye zb+)y$=}zSXX|ECt&W^`!oua{2S)Y_%!&FKQbyd|g+jJ^t`DiLyQ5&y1NktXbYbg#5Rp8 zLA}!ZmgUhgUajU?s7@WKiu*<9+A*htgaL?v`HWvG)JI@z48P*M(&lON`ylcd8P{n| zzu6EicT}^F!VYW(66JH8!=E7X!p4y`j^^%mID>?vmWRG@^9r(zft020qpk3LKH6$_ z5D1JE1QnLN*sO-T%t2!mES|WD2|>@{EEnt6=lfl+Ybfw4iPW@qtT#@`%! ztHp{cSb6P9_|Yezh1rJIUCtz~bhnsgj6u4RQ=D29>)r(|J-qR3ly_b%=h;H;@Qs<< zxigik`S1WK#z*u*DT3|UlL_`f^X@6pXbGVmoc<4JwrAHiNRo<*0Ll4c@|>AZPaa~c zP8B$!OGn;WqavtmLj6pnlyUk8L?bmPb`1o+=q9m;T#4RSk^f0YU|I+{44K9tDI(Ar zY?V;n*$pdKci{p{-s1()KrJqJ>`pd#hbq~>!l?d?NDiY{d{nrOM6xDVT0&vYmL&^U zzDE-@`tq=?##P*qvV=r+YyA%m14@1%0?fp)&&ufk;D{%;T#n&sKZ36*S%auk8wyvZzlJ!N7tVziPQ6|kM;??b90Imoc z2c}c4!PRp8iCb{1&{klNi>lKRrg~XWSv{1>!I)|F%n2jhEii!9&NWprRqe}t_W6rt zvO#F~upiE95&%VgaJs^-KxPN+KPW|t#AST|O~?9IRf8UX7lZS`lkx`<)2Bc@aJ=TyctRTix_6HoSeZCI|V zP@}Z7rPUwEQku8Ay$UJaR^y7mq6wT$H(qmCRsT6OfOyPrZ_?sHOp!;o{{E29pRE0hMS zyQLg%=ndtcg>BZO&83)3T47;SP6ntCh#Ml0Zxqf4VN;$~ng-+2 zhNv#XQmA0Vw_7Y*hcK9ar3C2M0urxkjHTr=Q^%&T-o*bqikmeJpFDg&v>h6XgW(tc zB;4#zrS`NCaB_s0t5%G;x2@0!G_t-=lmPAK`g%zt==uePS+IMrpABlJyN)doIDM|| z{9CUDjj#G$QX$LKLRs0WtxtCgS=sa|O>{1V)Z;&4>mW4CWhTkYRE9Ev@WhIo(rVgI9 z7By@ZR6os{lghO%MYBq`+LV{1+0!i+uVN)i+guuGf~6q6n{eCZPqhxsve?gP75e-Z zq1M=R!hgkKxytdh`HHctP{R^bt<8iUGaZ$gddcP_$3*kEY@2m{L7)=>Os$*`2{44+3ub=xVeLnr+;0HffA94Irxs{76m$>yo{d ze|_~=&Qau#S49H&zu<3vxx=yATi2b816BUTY*0LtJ_NW60d)~&2Jv@C%?DY(u?P)hAyh3|~-pi?T zYOh-Z*RzwZyVkgY?aS!~wmo*aJ#Jt7?|;W{U$fuCL#{>R=BV~nY?r^jzmz-RV774+}1Tg_ek1VbH_zSc(ONo&W$Ie zA|8YA^*jpP_{5p<61&VA^f_f(FK;jw)MqRmh z+n#z`R?Jn8s34>ZF?`D*SB`y?qjeo6R4XI=1#^51)r~av{Pg&Uc(wEkyrr*O6RyGB zQlJMBahoI`@JreZkqMyYr4}8xEkGIOzCIrLtq7Hqc=ZZWt$(3EC7@f`uPumd(Gqx6 zDI(94=)_&IWw<5rFQsvOlrj<4mWGWoaI%Y!V5?<{WRd5*8U8T?Z|#wjmHa6aCGJ;1 zo=i1Rj}n|no4Yxk?CGjbbK1()k)(Hqb@K`d7bKVJPTdqB+*rbcfod@iF*)l_%;Xap zD-`NAMO>JC*x`5Vk7Up({vTkRTScW>E^#dO%kW?ranECWSfy-Ag&ye( zc3IjD>xmx7;2L1E> zW{Oe6irdI-Cos&g99Rqcx}uZJKBMP{8wa{KHsXj-Z<}HtT;jlhEOBrI|F8uK9oJ4? zT2PxK@+lofzB6TPFh}y@)n%=7NtKxx%t%}iHbbFmuz|BC^=aOl?WF);8z!MJ+w1;* zpjIl13B%6KbQ5LEs-uP*q&?@zGCEJGl0@HxITHu^`gD%S6nZdn>(2g{XEL&UHQ{y_ znQo|k%u($T^^BBYWghIH{XAUdZIJd>r65R~(1Zfj5HW~fHC`mn1U-s|26Laxsj^29 z%+1$7KJ_0JuYWNf?QQpbDK)h<9yQGsb3+~c26Laz6&7Z+hzEtrd{UJO z7kb2lClhiJvBUZGT^CrW18S-be8i@Y^ySi(Xh{#OO`cSq`l2LnM?;Gi18oek8j$8* zr8nG*tbr-=m+Xw6U-Igg0-RZzbezzDBm2l=ptQj#%m(oR1LiWj2~rr6$6lywycrS* z9xy(_U4rwdFnM`-#=isox^T&@3j)&Ywif6zwoZ!DNhSTdM|D~U4>Qd^(VAnrYr?N5 zLw4Rlbrq#h;$zx*6!0v4OuSF!QK!e+rrBHxlGlC7$R{NBuzl5NU)^fB#&JYv&A!9p zcK4J9MFL z&jF@HTwGkJ`=`xLa4^Bke~-&UzF}ZcBe}P+q_YIjRk9N@eP5(sLvvimPj;bCMyp2_tfz>Q7li^M(T&jj&Z!8QhZ7wQa1JT5-eid!&4r1u>{H2ACwJgBpn4DxWD;VbeIJ zAz_sF(+j_0EhVz=IE)x)vE6yy4$d99?0bQg8n8htm zwA~M~^Am(oZ*Ds1k<&@N5YmHObqxL*kGDVQIgxF&gD5Sj0 zXRoutQiQ-D)n@ZDSilMy7V|t=d)xU`SM44ln0l-x6_gOdLo^$(3WS1QP3eF;iCs>; zps5}4Q@i1a?NkXOb6@lI4ZfPa=rQIdVbM9|>*L5VVU6d^-Yt1st>B@@K|?N7%bp81 zPl4VJOtWGxfxI_)-BPBjp+^l-PNijSBIMwih7P+&Dq{^nA<>%n0KQaR8F9C`zM`Rb;F zms)Br0hOZ=gX3R~r~!lC)(Fb!LG?nPnX{1|p6{V*+_aHmdR2}^ z!p36+GE1To{9aAeAE^RRC2Sm%!rZw9t;`!|DwLEe_?Vd^1_MYvH5=?X<2Y;Csv_Dn3#c|Ka=ft0Dve`mJ^iJOR*A93 zq?R0d8yrWKeTDjii|B-jwcf()$AvhR_>-DJivy~y*G*{H?;!0bvk|NOz***nK7t6U z36Tb+tH|%vQUYjrI5`|d;>7e$f0awveJ%Sp#iMjr;u1|Ea`FFXGN(K-8|7%bZw%li zGZlzU-9B2l@^Mlb%@V37NKODC5upYw$W7W$W4{7(rfV^Gci99Xb8|zT0tcyUau!Py zX46r-IM$;Nq6h{buv?3>z>5B*9j%0-?qv`fIZPjGcW>NPppES|OxkqJmETB#8(iPX zfpCi(Z(tM}g|16Ge({^I9C0j=e*fMo2QbNn)8Vj7PkrCdM{AAa(*N(yNg`lw-5l?b zUtH!1x!y`s9i$>D;j^CK$QwqrH2>a$AK9Y)1q==cWNm(YM7L)h+pfFlufq#7N^O`h zIzq+YagtLOWwgYj;p1V?15LM%_b&9fDiKBRF=~3w6fq3#VHcG`@Zy}Zn5BDeXf)bk z@8*K6Czc9qYeR<-Uck}m0J0Soji~9j*7tgwW0>-RUA6?~c6h18<|r_qNeQFQ)R*m| z`e8okI_u1_Ivv@t^+;WRk(^6e+|ZedV;VFZXYrJ(p1C1ZG6)`ajg2GOAEqz%S)#k? z#BGLKOM~6J$cb7j=Awb*r|rc!Wpl8kS9-&`8(Q6H=QmucymsTptvm1a?%e#acm3|_ z>a{yJ%5nOpj=M8k3heH?CmOaQ_9arpS-2r1-#3DaX^G1t>?nxlNPFFerJYN=6isr@ zBw-@d$=A9_I<00j8c^w}q!A%AUvw-2vh;P+!wJGo*oEp-t(}w;7VW@K6*0fwU}Hy` zX;YjUOSF@_WF$L+WC+Bm83 z&N#RFY-XhiE|_RbJZ){oUti@mpo*QRDLv)rTZvl6$Q=emKmU?<7ke3W#@qPTd=0p~ z;@|u@9Rzt??5b==y7;!bsVM8}LLKUTpAvOa#wI0aYK2R??fmJ=HX=w(?Gz1F!i0^( zH93+;DyWW0lqb=H?0s8I)&-cTk$!q^^NUE~OG!{nPuRo;9ZSJwuM62hX;4jHIju4y zOmQ5fiDU^CL}Iey;=WgMN>&n-EfylTcKG(}>l>vHdJE_{45UWd8bo!9WU4}bmnyWH z?@&AzEpa`^t}S+0>@bQDq4)8;Z1UZ$IO0 zw{u*T6vt65n6^JmxM_%bNQrHYohQeG zTQ*0BM)fuyFECS6rTCixPBfv91dfBr!NN>G+A&Ag^s(faG)fytrDv}W5;f|W50Nc& zIW-LX+*w@2qVlB~D_@`Ndcw3krkrvW7He}jv!-&1%BHSCQlU!ZVxw7~eQrc8l5VbA zlR-I0u&~miU1t?kWFb@;E+hBzPXCj`p=RLI1->Zv8+Gk_Cu+<4DHU`aZ|ugvYQ%;8odYiulH`;e6W^hp=Zvk#sXZ$Cgx^V z4dZgAjodK*JMj^YCEG;Z>N+kvRva9jBuj~Uk?@fOTW?Ju>B2N^9C~ zL0i7+3&P&MBzar0FR2NmvkDT`wI_LI(s>(eaw6r#H8$lUt=my9m#bk&Ep1OmQwhY@ zduKy5W6}(~3YDxksfAew@}j*w;kGze&D3(f4b#QSx_2{)G6=N2$GG|IpO{6DUG<4+ zhDN=)t;4yjJd{6Jx};0E@AYmzHyde7Xh<_(9M|?=pt2(^(Bk8xlTBPa4|aNs+CD0p zCN=ZxcGZGFf(NkKOH3)kAY=yRzwt3Iuibx-U;Mj#_ud-m-9Hw=-nez&i22=Hw{K=tvPS)?gbmF; zz|B zISuS*rlHYN9h0`p${W^_1FK#~56iSVeY9}3n4`o1Yy(U0u9SBGB(+wN*=ZxBL}x_& z<{S;7M=?ojon^|(x1rd{rpPt*G?8QgoMr5$S2nCnD3cT`v%-9{uhf7@AclDP z<40F9$mKr7YiUZ&Sc_MdKv1(4@9Y&!enD_*C&_($Z!y@;1emk)do46!Vk0S~k1~vA zz=QvqJ*969PkX0pE^SU`HlLk_99PSuCbwxU|6*}qF%dJuBYAP zk^aH?t1N`Porq;fXxUal!a;BlQc#EUbX{9&`cQgF&hpwhm202tkjuPf!J|oJ4#A?$ zUtvZyjG|Pt_i7x?$}%-qv)ZJ%Sjc`s+IA)IYBlOp9|Ke7Yl+Pfn-RM>QW$zS!ZpC8 z=u0y6Y3Piay?fWz)^6Uv)4PB3-tBAGZ?4|Fv)0oV`rhrk@AMw!Z!L7ci+|_>%z7a; zBgDIWoEjY5dx66GU}1Xv0`dE3^mz0fXFV4!qim*M!pf@d<;=}G5i-pOEF=Mw-tEBo zDwCA}`>nWY=C|0oVrS0B%(kQ#ztK6M$2)mG+}bHSc0JAJ2FZMut0Of>g4dW-Mtze4 z^xl*$wZN#A^tkp1RZIG$K4x4G^fCq~6MmlaLQz3Y)&d}^xQ5KDx z@3Z|m52RK;#lhVdtV-A+0hf*Ajf!w**KiPaHyxos#E67FYwkPWIlwENKgawT z9d8Xqi*Sa`T8M-VE4Mej+nEYw;UOe*NW=&sDY^O6jwscja82}KEz%X)8+t8aqn0dk=12*U_Q3a`W3gP7=LG`lrQxt`Ula!CJ0wX{K_00gtmH&O*(D zXkt&PeVcu|X2Pvw))>YxCg1Mau4Yr9EE_NZ%S(5P42|y<3t#!fGl;n&D{D5>2_b7b zgP`#mn9KdMngf?6#UTXQHUdS+eR7z(YR+kA5xnP2HHVK7GPrCkxs$WYKVlA5DKmyL zn~sV~gX05j6M>y-?JQg1Yz$IPNqc)PtT z{>Jq*dC;!inNKEVq{~;LD|2+of=1O^ke1Bex^2Dh@by8QfN07W-#ZzDM7i4@PYOyj z|4F;iF?a{ql-P-k0|)9LLsBEwCN`RM-Ga?RE^F@-4KZs*AT0iXJv4ALvpnWn!lUia zIm=%8tXal29_A~HQ$-fC(79gDKo}Wzo9jJ z1=V@ggz4p7K8E77XPBZqokIZ{y=7Z%Uh}dUO>xo^%jeI?_7oCJXm~Yc@u`Yp1^mC_ z6xn4{9aFSQ6Wvo(57d(lSXXC`%aH3Q-wL)@IPDsE`8a#(!S=pin&t63NtYlo+EgT! z;-ID!(=l8`$96HafR1%kTFKMR&ROUqP+++$+75R*qH;*nRHNd@dyb4{+KL}kzcJ~d zH1cwG1jKSt$@RWdY8CT5lnNw=;3#m)anC9g9m3t~Yu9eC-o4RK{@b;;wjk7ybo&Y8 zj%z!RN(qo>jJ1+mIvsDF=j#OZStc16mk*Rt;(b04So3e!yc%@HN>C2dvQN}gN15I# z`sHiy)uX+MCf&yB3KA8<<3M45<}heielt8tt!~En-U&B1Ps3->NhB-~rQ4XnUjP2+ zc)WF@_)gFzPdXgEQ483O$lSLIPa6)qPmDnTrk=FCtVWK>=}E%yboyig+5ho~7>@m2 z^ddXc!EXwUsDE5;_8>8gsB(Ek_ot{b*NxdCwbUGewu^)XNCABc?(jraz{2&_8=Yr9 zd>ktrMo%q$lGMW+;BWJ$&&&GhY?Yd7b6*WP(>_x8iJ zo6?EB{~(<#MLl_)qKWfMEYSGMGn^=~?ID^aIlFzj_?1uG?MmM`YuH0u@sCL+BmGd- z4!Q>PT-b>;ZR`y4jumtb$lrZpsdvxkRF1Uf3ZIZ*-bixgB%3tyigX1> z#~!5T#PcCp^mVUZ?{Grmc|36EEl6niQ;==CiCf+ZDBs<-(~< zI9zglsk!GX2vK@f(aLj;Z@-J2TRPH#4J*K6YC_HBK|&0#FS_gJn93q{XqZ7iDv~Co zx1hbZ*S|V70A_O;A5Y)b85gMyXQ@lyd1SFs4>fIZ*y0+$fb80+Crra6HO7<;3Iv&RRdB!&hr6w>2ZsV31;|AY^;L zl4)Rsia%=tAT@{;ZL&Z?*Ti6671q$wcMdEcgx760*{H|GejXCb{Ew$kK*scB3*F%q z#D2V89Y%P79u0j&r-JP>GncxL(gAj=-3fTBrhENq7P(Yg z;n;)Mw=YQBNsbnIDoT6TY{w?G$m4O^#>*&iY;!m&kk`aq3d<|t2vsXam2J%bd&0~UY4$!Y?^D5+!tcH`xv;kA)SYiaXvprUS!NJ_@~zekAT{^G zBrE30(I^EIg?If$jessL61s#SXGsoNBo{p>X79zt)OU41dynKR$79dEqJ=9zx%J8g zu6VZ4k^$6U?geYUh7>E6?btcuJYht6Uto#J&S-&z1=)FhHKvHn0eFn1pukdku1u-c zj|#B>t!z6IGEFS+o7N7?bKPt{mHm9pHw+!k+$91sH4Y$FGLM+`=t-p-)@PIfSe@n) zz0EOwHo)e{$J@_i;Q0M)kDe298YElkgVZ|nUEDduxtZ)#;*`HH|`V+B)$6#-iVx) z%g>2q7%Sb2D3&Q+D0|!+M#Cmn$c;5nO6Z8B7Y-)$Tsx@=LW{t{hKIs~HN|N|>L)iT z?xQvz?~Ta+V_4QqreQ=tDjgue%M->HIYv|jKJQ=?jDm}f25ZECEW|Jk+_@Kx z$=akA!@<_RCq#6#w(*Q}s%(osf#BGEdVQ~O1pB|{Xm3a)^IXV)VO0U2=BNfn4n~hX z|BNwYrcz;HAphBuZsgcShaf_8MloV}+#5(bKh88S8hq3Nfpi^5umQfCD5JludqM$* zBuo^A4uet$hZihO+a@f3-AKSy56MkB#~E<0qKG^3)&2(FDQrQWHL36B(n)A?rXV1S zT3~q3QOkbxt~3EAK$t-`;XF*TIBgtO9wn(wu5dg&#Gxt^4s)&vH+fg*ftg9w8jsS# zNvhZlavBhvqK(Y_D#jkED~It{EYkeB<(h7cxz2c2z`yRMRxNDIbuNA0`QW~p_igU# zt$t=O0^;eB7+H8mKk9#i)42ZMA2L#qR{l#%ci zlBzorl`Tc5g8;xZyXHD{i1lVZ{Kf-MNsW=3(_iEHhQ>5{5ZX-*oqIrP%hbCS_YvNi zo2HuN&Rt|?Klw~C|EV>wmZXAiz*9k&bJMT(-}4sVoLV9!2l^SNQ?sfq zK{v7~a8+`?_z~kP&Ohz8Vxn9!PuY}2VN8_7^3itW=Wr}x8z8wuoeED4{&=wT>Y#K( zVUQ^JUdya0a)J1eB!r}dx#k==*UK|KKu_gI1jx;ddcumMBzr;@y)G|b;SAzBOEr|F zjbja)y5R6lqPm zD%WwrxOawoo)&X%ajv>o%oePr{j}JfL-=zIWmf;~5$EOzZh&Z#3xiNF0hvEIZpu^V z0ADXH4$19}<{*^}R1=fxG-$M;g4T4BKZB%HyPMkmlKm`2u$ivk265_gk=JV=*R zYkp$&8GsC*jwi^wb7grI9};rigle{sWDUv;hmVN~&($ZRtzFG7j!eo(d$5J9S7}6q zxx5Xyr_!kMEeUqk5`b=u4&~A`GRdbyb<$*Cl=hwx(*;eFnRco*1eHFGp}d}#K4Ii` zav*~UET6Mo9zk`2uZ+78@~NeCBD~zB?iu!XCkGzNtwH%j4v2A;s-!;mo$q<9q)rkN zCh}y*tV*HkS(JS~hD;>a3Nnw50JLYuB1Pu6wAo|1J-nvz*jn|TFZ zI&UeEFE`&nYRdL)yQ4GKnmpJ$A43(|Ml4i26;G+aD^i)E!wgUYG7V;GXYm?*SVeSH zIKnBU7XyAZ(tFpoZ3(Ig2AdgoRIG;_J9{TFb|dZ{3U2aIv$86Ddn{Vaw`;nllar&Z zQMKY`@I*v2DackV1Uo zAdb8W2f=-B^XP;<^u;S7O?mzmgI}!(a?{vRxOX__FTweGmlsK1HyQ7F+)yH6*&u#0 zZQsn3%dlhZt*e89*2TK#L0MNF&;0;T;c<>WwKuu7+$CqUP&0bw5EvjqTc)(I%t)R; zsR_6CO7sgiCMQ^Fg4NlMi$JPmCF}=sM<`spW=myL@26W-2;ez_a7<_QG7eP;-EgEl z5~BJUq(Vc-iDwmwON!UDrXAo{r2e6y9lCC=S1MtVb7 z$xAD2y6RUiEXXrLEGpW`Gen*{X}*GGUGT_(f?G3op%HYr=5*>)v?%J7(EfPmId;@L zj^3*jR5>Krb^em!Z%C-!k!UWD7$7H8a5&zZ_AJbC zb9}IPu^O-Rs2TOoccx;Qqz#QB_7I*w@8nzu2)>?U^P({dK#&%{usug1~LOvr}+S^d(+!DN49kMq)k zRO(awCY}&~L9CLbF{@K{wq1D&3+Pwc)Kt3X#!mgKolAz$w70F?ym`;xrf)CX+oWQt zbp%FpX?>i&*SQ0CCOQ)Q&WgDCVcv<|G z9)Z@d&dSpT{eoTOF+LuXrAXP@!a-mFT(g*s+5+* z!f4G3&m6M#(hu5oPTFdqVREhM$rj({h`o4}hn}QawWm+Au852bz(N4bKI$%lyTDvU z3>inNUaBP-#H_Zh9K(!CJUAEblF`-L=Ne$LEXNd7r+zi*V@kl8$v6*ScF!~YxM}xd zW#zJJE5k2Aqz>9n0+wW@SCxV!AstWb&Sqh^9Vppvtf9Pw`jk=1*TxyA1DVSOHbW+v&FB;Lzt_z~_fuZ3C z7P16rJOy95fu`(WllcmgWB(#}y2QW#Uy&eSsm5{;Zfd04mA!mnxB{XHVM9gN&d`A3j^W>IsBc zf_k^_UAu1)k;%x`*jT%_#1>p%`J@Tir#OJ3K}}A%@7%q+W|>(67SFhHMu7xurj~l= zOD`ccOZDX;LH%c&m3}UjS+{6ZR`jtveYuqYl~Vs(V?NN$W%o2!+4`+S?Vl_yR7xKy#ecShUf4@Au8-^U{)e!SzOS})!q{*Xut_sR4k zw^tJZ>_hqxIe)O94CWj+I9tvIX!@!y+xHI4?B>K(7ysJ=F0D&7I)|dg&M_K{K6I>3 z4P|FBt=y8aPb;1jV{D7Bvm2&N_)ub_2le6(qj}_ZV)Hy5{YA`Hi{AQn{3WpbeD9-= zKC%lPH@E=^8C9Eah5ISU zz(tL%Rj`<*JKbO9n49+eQZV6CZ5VJ6O2@R#sPa{ZAxaK-F~t?1{M-2RJyO*&Y!%Xn z$)N14w{#djW}TFqG@~ZuWR~w7d)@9~UtbTNZKJI6 z8HY(C1#KYecHOX4$+)(-q}*?&inhn-F{K@=GJvMX*}1Ng@gx88%uM(K{!HnYt4%8A z1W=OJMNm}(XfWd9O!9>rIu6fJc-sfz3paGJIrH0sv_(q|n}FVBc{Dto^h}@G!*IJ~ z-Xr0-U$~)*cNl`da6@+jLNMC@!VUckH*}p6zHmclO-LFJRw0Qua<-I9*kq(c4*xb;Qc&VGm$n(1$?&IiG6VT~zDrppv zN-H|S!VS7;qZK9U!K*hk6#Yvuo@mn$ z$EQLN=>ekX`nlBu75%lYHa(YOlsr7Q`l(8GVlCxDi?V>(R&Lwbj3RDn#CgtcX$iuf4YVpS+~BEJjiKKYeZW_f@*z z1ya+p5;gwOYpXx|)2EF%Ybm4fmwtNnH&nQ}qd3nDrusL%#Gk%Bqd98v_SNA}ufE|u z&lW9uqUianKfQXa!oM`zu6Mk8-bOtG*NE7QqF@_t}N&RR;g4_K+QxN2gOFD;nZ z?@Rl&RcWO@1FyC6r*j&6-8nt6jah-t>2W4$?>i|VF-I%WiO-r5ysVTn04wz}#$|;% z=Q!`UR^-)rnicOJWbonB`^?*u73qY%VnJ4@lZMO2Ze?b~J$u?IMcSK|7;Ddpv}!+- zJZnEXgkn8E`N5Zob=4(ien;yMkAL`sUr0~FlKI2IN8k9hpZY1?A?udS!xvvV&&9n; zc6c;?{N%VdxPGB`_41V~3;gp{lBZ*wcwadOZXIk5t>~Ik8(2Kd#=dMBJG#b*^j*ga z?Ei*ke^NpbGPYo{I2z+Jj-}q5p%*!zvsZA5EIsnbo!4}t#F?9$TP?rAsQ2EThrRbK z)x#dy5H|P5TfN&DUk^xCK#a$so>&r{O*Nz1?+Stk0Ri{L)2;=#e4{raCp`XfDK){> z)J3!>%Q0;XFw&7!itG6-zYLLkn_^_;Byx{d;#G+#L3L z4|LJglM(gLz^&9L`*K~|=3;of{C&*dCfQa*mRRluZZ{aQg<<(5?l0ZTd)A!MDc-QS zwM2gYLOcL=%S_I)>5O{cd~$qzxU{(V?Af#7ehP~SxcxZleb8GLnAUQBE5BG0DsUQ&BY>p8?cteA%BQ`!ZO3-kduiW<7 zmyyie9T!YMnHDzR&wM&p%JojHR?~jhsv*RaNa&-qpet^|CTR$g{?|V$; z`#3)C(Qn2_?M?y12lo}e`* z-cq^DnF}4y;_^V#g7}zp9Upp2@o88k1e(7aiQm zmfi6UFSE=^K@0Q@2e93Qx#fO1D00vBSDsTctieZJb9>aUz*o*>_8Ttf99}dR7Sf-O ziM`E~&?rrru(VAn-{{Kxm`G@LXx8D%EDW)ES|TkMTXOOdC!n>pTryEg6^BZ+t4vcL zZ6$UNVNK<7$5x|6Lg_Ncj!1*!*k8#yNSx7Vdx0H9*@n&gD35;D(pWmx4b-`yJr-_Q zN{sASZY#7nxN^BNpHi+jwj^k20PTq1G@E*H{)`^#{`U z!7%FTq)jEIpwf@FDr=|C%iQwlTGr4Ei#P6k=v1zhazzvvZciqMMC4ftwt5bCb*~51 z+K3BF4i%bnhKOQiXENyDD``D=81DL(Ma3H2Vsk%0v5AKs@ykUeZETiUxRO@Y7ma#s zQcjD!1X{Cz;MrtP+AZVKqfW1&;!J3yPZ}Gi0=E07gEudKT`q)uzqKRdR*mVC0NFX5 z?O*SM+QP9=J(c0=efp$wJ9{V7C&{%iz0}|HIcgOlMf;aod_0ecZHH_b&T)43HfBu} z=Phff*eq^IqkToe8lh#rOi%~Nh*t(%&bgOqDmus7Q5I1jNS(uwHJFASg(zN*JCgIVED}!zz++17X}O% zhF{iezu1Oh7=~dO@T0#kF6Z+9nPjp`HB(a{yGxn*|K}1XPMkOqapFYyr%ZxDmgJ7} z*Ziz9pY*LYAY3RLm>sC7kkl|nR7Iyan57L)IEc|ARSvp6gx{Zq<;(hKg}9dS%{_?8 z{JGSyt0Fjwc85R<Rwk!cM=z9lY5bK6=J9@)1VmKp2xFdhIHE8UX zW3e4S$_(&Z{Ab!n;st9T{TudohfpY0|j;7z4)fHa#gALvA1 z+7RUAdeY|d1AT13VJ4RfJcNczRZRDJx=O-YApDyPh)jl4E;EQ5N5{Qw6opWalr(*W z6el4wn7LG-T8ooFiJoFXG~vbxO==+3jT1p!d*g;S$o1o=hUQdA)KGbX|2q>B;^XQ8 z)cDNNFr~o_ikwQz02jQOT4kWOba`0Ah}TWs3~-z3r&k|14$5AkYTAj+oyafcoAL4{ zoz6Uhr@YRnE)h;bT~QWAzm}l~5TrmeqD>LefCf{q*;9Cla|4JQ5mruCEvHp|C6glU zVlLQ_Y!b;8&h&s6^F6)WoM8M2~ z`ExI*noD*eS5-q*Z!D?7DB}yf(b5eMQ*cg4+);~>mJrvb-xPyPhBrtJ6~taEWbBPF zeOE#Cahk{#2zB0UK3OaSOg4mm>b2z-;&y_$l(vLjgux>*tG)f?`0OV9a)Or;iX`p#UWtaul0l z@);e(gsEznP;eGR%v1(|#O(`*mL+>O?M26fPd>c*PvE=t=IW1dR*sX&av{Z(m3n*i z@%U1zBUz~r#ZL>zpyjqqX|ZC1)xU!T8Uj4_`uov)&v;zOt>OVz+ z%drJ(`9I`y@g~UL$pK*6Uu;fZjl+Pv7&9A==SlB| ztH+i&$_$5_J&06CILQ3*H}oJAzmSCG;u!Pd81oS40Nhu_!gg_t8ICdgBR`WIJljFK zg6+$4N@zc@c;sO)W+8X5$Q=)!Ewk`#_iDcE)zrxVzBU>T&Wg*ryj~p3r;FDsqy8G# ztHdcBFJa4j*|LxYEV1uH*66hku(2`WjL676s1C;;OOfQhy`FnY)+m*>mMFHU;fU4P zDygD{|6yC*Z{O79$kGlaBN&olFP5M16lXSYb|-QH>drtKY;Cu@CWKlGmNUg14CvK$ ze`9|1(J>C(_C^hc0YHzMqIupl0zQ>SeIp(tgrh$*9q0h%he+BJgy#%-QP@m`U2ifs z8W1T&Fy|&nKxr+whYWY6`-S4Z<=v6sM69O3#qJVd#eVMBT2WL3RN@N+eEMmK8-V1+ zhLJO8Yl%M~JC6{4u&Xy_IiorkiFP1@lsawM?Ba}08;^jH zCXzDNcYsBOF{2YbhX(YNjzrrP9UY+Lv=jwmsV;|+D8#Nr3`Yz6F6f3>FT-(#UmBZd z6)}h7mThd!Nri}#mW31{KUNR!(58y~NFifi^D(89gfel0lX=t-0Mb)ZAlK>Tt&D`h zZvcyYS5txa49}Xu(TMtEe{iZkUumq|cLYx745m-0ZMa8Vug#-3a)gulC(0S1q$Uq- zVzKIKlcUg~mBC<#|Gn{g)=YdlZ9BHw2PbVNUC$aTy-Hh5?mWYof*2j7mqwC7IA9t9 zf}BXonb-trLUg7Ig-U@0s-~2*Qk9&H&*5C!K+;^YI?bVZz%+*U;j|j7^Mla0FLV7o ztHCPQq(_doQ8~UOBT&+y4oj|u4|^iSl2b3+0ix>;MQ6nQqdY8ake*<>p=XDHpQqPW zFlG~$oz@k+8v`m&*EM}Uw$Ef`fd1uIoCoc4Y&|`JN+GDy0^e5RiqkEG>Z8HRBUVGO zSXh8%EI`D*k|@^kz&h3kgej_GT(OzW6k}yXql;l$=Lsu~)G5Cfd zL|T!8aP?}EEeYpLHEL@?Fj*vX1)lrxP%tYz8+B7I4BBColw>k=lgv399 zz!H*CrV*W0@JkR7%^sWx8M*IOtT1@8+j!FNB86%b4k~c0*z4fB)hc2S>VfnZNq0K?MOhG~-K%s;2Yua*%<#Ox*?tcPcjAtx(wl}pm*fv{sIuuZ(2;4! z>>7V|B^6i8MuOj3{Rvd{Z|7xns!f^y>FO3r{JFeDHrZD2k=Q=Io)rwH3YbMi@h`s? zwfXeMrN{&bRkbdu(NL^^)qRBF>ns92bnE}&SD{ODDS@zf?D2b6PJFcj00Uhq&0W-hq18IVj%h?aP-RH5xoAjFDf|j{5M7&|1?W1IR7e(my2?@c7WhhT7Gb zXUZ}bmVb@fd2~1C28-U0gU9jU>8_XG9}dD-gyHt@Gz50K@mIHfqWU@xv=MepuH8~4 z71e%Oo;_#{VV*9j_3e}PPNvu6Gzx*BE?=g)8gNoCpPcFzEy_-m8AphfD|TZ!{not- z`;r|3gE7`?>MV*x2o&KDklZ8g^>&u$vKIJxm+ja2k8U@)AY+Aae`3|O{5udGsf}AK5`&>s`<=9dd51TqIkVL$nMzMa7TOo% zfijCZG6Pz-_zjv0vkIM*nTV}H{2)m!ngbZ%r$;r)!zTk?kQ%NX4VnN!ffu;qNhAA- z_>za%y|q5`64vpbd2@vQAC!lEmYI=l5Ul1+cMcoDJ4nW*G%hHIX$RC|$A0^W#Wt|- za1uNQ|9jH5tQQK=afgA%_T}HX*TUSh4Tv)$L{aOA;A;gCI=%A;PcdnA7M|U@sZMVo z9O-p@ZS4qagSGdEtSzObx(uFp6O0pa3~k!z@LwgT2nNVa2JN#0unT^b%T2%kF!i&k0Gjh>4xxB?XHdXpsCkudc zo~}o5onGbAYt!Zx%nKW-rym>IfCAbB`|qT!;-iL~cW9ngn?7aU3&$AK{lq`LkiH5jhPFAUcU$8cEyc5fWUAYdr<_Up2iwLRDk;5#qZsL-9D62cU{;MkqC8IWwi z)`o~{%p!Xcw>DPzQea^0u*twZpk57DEQ6l#G9PwjXgV&@&FBye$xlu4ha4J3AU65yG1cMT*eP3;E(cv%h+PXTRjTn3e2_Bg`)vpS6dB)sIm0H^%Z83c^|1eS+G(xi)qRcEI%S@ zIb!$74)buxowG?OGHCwiy(+J%nlNufIdLk>nX{TUZq8>;m?- z^LTCquS*yxcl5+ks*)Wb4euT#12MlISt#StseUJBh`6{te_{{Y*Vq(7=pwcNRBw zd!4XD5Pk+!$&1USV{7sjwybyivhGv z1WJQt2}(>okgg9@nwX{bR%;yeMLzASpoxCa5(6hZpBe3pIy1PI0?|9^oPc-DbHX8@MIwvr1XeJUZ)s>^j)uuOl~4_{mdpmL;303t z2#PTh;sB30rUq7eZ&Xjpvu~>t%fS{4j$qoMsDBJEg3HEeMzY$8gbRx$`VImvTjHNg z4j_hLi6mRW>?7BD@l2=(P3`sjz6wKfi z^6g^KOqHsc)@sP&!P%`qhO)$QLxX)G3Ga{$J6q&Gv}6z-kS2#i zVzM>DZX-CT$pvJzfr~33eO?iVY253(iTo!(E|u~d(316KG6f^terWF!O>E*iTn(Nr zc3Zve-4+sv7Cnlv^%+7ulX_DCBx`--&q~=N)NWpxGSDPc&u$mN#71UXho-~O@9{~s5<&Y@uEYm{V@1KZL)SSa zi#jh>ebGK;q84ScIHE;aa{)GXKjx2eKxk6Tx7s$O53CUB2)2HHFF`gTO$LL<@?Mu^ zwBO8ArgRP?WL%{2*I96;prdOYrqc}}O}>{P%_t0j<-frf$~isK0zz%2O8N{HpT7uT z%WPqH4l4k4(qCh`0oM(y1Eten<4P-HVNlp>9d~8R3lx$=LGspI?j=Mtv()VIc`yNH!waeKy)%7$n6^C!5OAEvlMaUD>p26wf&H)p?1dumjlDWE# zqou33#f&S6aDB#I{9(U~wy|sB|9B+Y2W+5N)Uae(8{7kFrV__NtN|wW^gKkN!_bc; zLqc)b|7ZggAA51ueJ!@9G0&nEW)8>h@Zi?#iev`tE)K3TmN`ZQ!;(d4FYM&%d&LQSPw2#gco2gT2|lgdNE)_LG>qKxu{hnrcVr+0J0QYkKG4XZ0jf0=&DE|2 z)>CfNx3OwQ^|76Dz{VRe>sBNU6Jw~iGC9PtBB5lhK-o+;E{F|J426`_>NES80dJDI zhIs|aG!k;SF5LWwz48fQgD)2LJwfx=W5&a8yN0PIvRM=q1=PYPlYtC(xy2{dv^ zppXTvD+-X*77^C=9d4{VWOd1(1Z(Rno@k>3W|}bnj-)S^Mls%LLYYxoDB$yK&QAoQ zdBiFpclpRga41owuHtc9RNEq4xP&c@$o62Go1Dd=;fNlB%s+M-TxYDJ90yj5YVqw4 zUHyZLHxxhD!PGS-nW+ITgil_Fx3D2FMMl7ECYh+}ZNX^%4T3*gA;mB5P#_#9UK*;l1;ZPQVV#Ub~JTFe0 z^a$P#mkcqG1h`6`*PunGL%Xfv&6Q|F7k53p4c)uhRgR!L`@j@@*$kvOpbP`qsxQw0 zOkV-m#qiC*mR`ABcfjutt5FxR%+|&7iUVhc&tNX=0c)u;|C1q3Yhca- zOo+h)C3Vc+a2o+W5{@?T4}v#y4VY}s4en`s22F>HlRfDv5u-KQGQ^mMw3?v5Rb2T^%(O%Ylcr(7 zhC9H1KL7$&uj>M1Ow>g{-z4;l646LE!9eKnshIKc%|z;B9S-u0N-UDp626JSlWW%D zXHh@VgxM#25Y7bP`Um$4_#FyZv>*=2&%q$Q*Z6F9(hVmp!xP-#lJVA4yA^q3WXn9G zfXQr(7X-`k4`wE)CG-QJQMUei#DTt--Ny`%dq1Lo8|1Ep|t9*Y3dK4b*=vq0g5Q%$3I56h7rTL6h6TXv`vBONddr%M~l zD=R=URHE^~RcV0nb=rq;szD#PHK`z*cMPn1CncAwe5A%Ci7+lhF+Kw}4Ll4RB=Cml zM>_S2H^Me{m~43TxV7DaI0U+ru7&uB={kIA;gO*+D`zuxAqVIdeW;z#V3&au_QSE= zm4v7CieVrrZ~=p;w27sCnsTCHrXcpiHAy!N1ZCo{T|z{)QMzCnXdNWPAP{nOU3uGq zV{4SDFbMcZ^`FYAThZN>0L$dc9CF~bN!cGC!(j${ft5wD7R(MJy$|7vPQeqT31ZYx zJu(uyy7h2EOS?HO&Iuh|DVAV2g)NAYd^o3U04$7sQ|7d0_HlUufnOxtRI9MqLUJs4 ze8lY1F*q_V`SitPTRJmjWl7|%gagEJzuQgL8&{_pViSdjjMhDaN=?>hfGi+Ca1&sV zhSrjN6ENqq0G!y#rdp)wUr!?j{N-@wI+QfUxID(d!FBO3%2^AjOaS6SAPw*bs240+ zLUWe|XZDKuZ9f(EBLh^2LQoCwrwOVT3T*$xIbEvQFk-P+IY)va>2zVP6ed+z;|zfk z1IG+!k|py25TdgvJhq_@|H(2HbjeIr34IcQ`zfPHEKw?Q#ft8DiDJc{9BZ;dCu&wL z1l-!kAW6V5iy-HsG?vOqd(>|1_z4BP_2hhs7=ZkAeRN9O;=K z1{D<(R=}*_d}AJOd0IN3=sg^h-5tij=>Dg_Ms->B{HKJt16%{5d|c^4Zq#pxZ4e6d zU=D$_Vbam&8epV6Va$o!){B^{YP-S>agGKkWwk1_a&9T8m%!YoH3#mEOHerI*G724 zKi86fdD<^<^U*ebC{psqN>WjIG6YJ+uiXImK}8=0dz~M-#+9krwVED+gvUtSIn4NB zhq#NidCcoP)lVwok}_8|o1K_@08QQLp=1n8O5JEhd28;Fr&&zzE ziG+ll6kT{wp{L29&L=pY9F&9|>0fQ>umvN-E?JGNKK>IK9c;4g!BJ85f}`S75+bk- zwy`Jj;-8GU#?uzqQ$Qi@JqnX>KzV|EJK`PWCC`vUYMYRNbVvvv0q-NUjZIyf6~qhB zuObw`!aV;UGt_usQUnvA2~(?1E2(JMk{(-%3Kz8KBWi#vpM=c zi|QhNFIdyFE~k+dp6>Ocoe6g(iHNquW)P+YaeEk2i+WkFwL>sPhUag~N2o>E#ABtvIESq!dvD4nSL5a5(4}92!MZ_mFzAW!It7WNq_a)q zTN2j<`dSMfUJf4gIoQ&YwlJOB3_C97Y$+;kXUNH;hj!pqBYL632+$53u?ga?MH500 z8^KtobZ9XU+0deWkD6aVYW~IRkW?4>k8Hd4^lYYOE-IzjU&K-rDhN2qI}N|4_oq2? zAWmkB{smS%@VG_((}agui*AFF0>ihI3TGhtD$bRpt4oRiLMqfC*d z-;sR^DNN%klq^4|O)j0}`}jtuaFfXv9!N6(oeOjVZ(877Zb1pO=qLFVh)LQf2csn2 zq;7+P;!`0-egtV?0Jm@TG$ZSBO@tK_f!5UCimoE2~MIqgsf_xW@ zEwxvkE0SN#z4AQQ!(NDV8<{*t7?CYjLRx`kd|=@)8PdvI15{Gd zJe;i0@Xq&4GC3y1#&bDNn{`t@+6Dzc@H3(&lvY{D-j+(x)@5sbGln_!Abj*xfIjdY|!8sgSKw+Z^x89+8#c6sHn$FSA~=;E!`$ z7250^PEM}jssqKR47AKB6geJ_2vFI&iTfcz$GneQLGnr%el~>_;v3(nHS824b1_%t)69&Jn*fwpR!OuDlfD8F^b1d>%5GYLS zY5-kz2aymvaz}cep_on#xl*|-qvS2NNAyf?c%eYMQVN&Ny6}sIFx%VxZFqdjTgo!| z3zkiYh6!dXdQ4ky^a7#4^lq?DCO^CB*R z@KpI@#jV&@$skGu8~JV3vhiSHqHh$J;Z_AXrSaxtcnOchucS;=RMXetuZM_A-0I1X zd9=mva`DesiL_AYr7heI^eN{jBU7+E_ukGvygzWQONFrN+~^qU$5(1lJ|RDSb0FtN3?6rDI_Uolxi5tW$Os@&Qd ztDOp`#fc#K(PyZcjzMPNI&xuSN)k%sL@d(_i>TyFM>Yvku`eDee4RMb%!~>#SO?5d zA~YDIV>yhIJ-iTScTv@WXk&j8*-KaANvs%W|hi$kTX+B zFByhNs%h&Q^v0o(l9&k?evnBx^jB{q3oc?Azxk%$GMXbk=ME60OXAHT2llp6$h-gt zai%>t=sf8kWiHk!z1U;~oMbLHWC(1isiY2`AVQ}4ruj_d8Hstdy%FX3Q7QAvI%B7q7ftyqIy}gX*6w0ILbws;e6=d;?}4EZw#b@yzA- zQE$MHllCD$;2(+WfYQJLcyJabZy2P(`VSwxWm3)$8rOdKL4yw{JN#g)HTUt2xi_1S zuFdAsVZiaQR+r)m-w)uzIy?Kr*;j%WYwdSy8U@M*FpC2SR<Y*QMo##FCSXq&Tp~nH%p78;bp=qaq{#6+sxewy6!< zc23WKzuhxJ#=Z_Z^B~jnfjiH)k9O3OK5ftEPFJ8l#tYXC$9Uagl z^rkEVp5W+=E_vo|f~yG0O$09w?9j#m>n^niD7CvI@bw;q4+#pCA;=)JF6bUN6NWy) zNiLMNqPy|FfkU9k*|L)Gx|@mw1Tf>kc3H--yqFx3n^0>k#|nVeh!m1~WK#UC~2W|&iu%4ahalNrZuyG^_797B&bc4jY&k#-xZ{sEg>oGE^@ z_R6cj^}$Si_UiTd@4xkfA8vi{!K1(Yv**A2;$N8oF`CaEnT@zNnRjF8q|{ykt~_I* z+~ECK@2Cexhh&9=to?TVyElc%wO!s46Gq0iH9lOlA=l+B!*(*ryFj(MLy;b_V$r4) ziDbo6fPn8HKRuSs5vB4mtB=ae2OpfgdgJB^udwuo(9XD7GDt;|1I{dZC3JEgY3XyK1;MgCy*zdHpmp1C?;|NZJeL&+%Ls za%N5c^VR6Vawb5Nlt*wDuR-z_-#e#;vT6;?i1;MgCk`q-3$QqOV+9 z`!S1tGc77+3@dQ=(%L!;{6<2-n+E+ zjD>$CX<6~LcG+JglAhIiacS*uNiE?&dN5|M{_drki;UvN5Rnu*jee!T>5D~*{7Ob;@@N8omv<%d(k3!$Gmx21j-T zh&XTm=odAGfj^p*!r-+VOkwcbuo3MR@3!EkuyP1#b6g<*Jv5HPioGMqbM5boR{+z1 z!5oC0Ucl+}CJ3-+F;M~CctQqk?lmi@9Yg4d7D21RBnP3OHNr;B zSPwiP*Dxw$tRHsgPfQV+hmKfoXqifZZ7hqCR)Z?LmE2UUnT`7o*OzZMZ!K-!Zr*-y zfB9XpX+tw_A0h#FKZ&K!8XP5@$$N~L7RzjnX(gIrs^-+R6|jjqe>eCKu7*Xsqemx3 zOkowyy3sa4=?ow|uZ5;+3lX>~#%g;=B;9?6LOA)9I7AhFvt~1ZGCmj8GBk9e0D?`K zzcqtKXj~(!G{zgKW>dX>{(+8*n7Ey5naaY^-v{gt4e^%j!RjTN?|xQqUzU9P7=gGE~oL<63$~0 z4~$zG?=M8{HyNw;&)1fLNkkWNlSG)8pt!~A>ySf5+?UtMG+5Z#H&z!=;v3G6^uC0> zdu#QFc=t>G&SKvFMLrezHF=}LikD0&>yr=VU8M(=O+p%_BbPxSnEaxJc7#0g?1w6k zI8QuF9=Q-mE^;clr|uUZc z?+1`q$NilZxmFC*^b~gq===f^n3}OZaG7@@&vy|p$(n22LpTI~#vL4cB63Ofpc?ba zte3*2ue%a6w_dXXiExGZLsgk76=M7?&1vMa{#)YZSs+@Z_Cd>M1jDtlV+&%QRE;Ie zq&M^#pp?k(r8v0Uj{Wu9_%3m4m%DI(zMhzn9U>213zm<-v*h*qEeMiudM|Z=(P#Ok z!chdgPQ(XaE-*?0k5Wx?RD?l)7`CmcSLS)=vBNX<5$97 z-a~rG%LYL6!QG|JJNMVunk%~dws$_1CeVPKd@*D)F35fF4HVV( z>{k%bQl4e~EY=1zyAO88NWm92y2?Z#nC~j z6n;QKih?HOfQdXBTEM`<_fip4$vAYx`Wy~=!R@LZs+5`q&Y`EF2JeIdpFH2t{=6{= z*76{m9TKQiiAs;w+TlH5|0)w9Az`y7fhHvd;Z*gUX8}Pns){z6U@or_QN~_M<7+CH z78jt!LW2Ticr^_PP-hYS1Yo-vF!miMbL^uqtB>Y={M|^JFRZJad)}7boVZf?3Zy~AEqIo(1@A8B~}V#uAM%HF3B!W z8Br|m;Yv6pXpYR^I|dfPS*)Z1C8)!W!^C{@`s|T~v&P9C$07g{LK-&h19og*8xo*@ z3MBIA-fl-v?kp{YKIkvNzOa8zL`#{>1d4y2S%@9iS=wUp3+AdLSiz7l9 zWh&?Yp{<Pg5U2OuG%xE4=?JeEp`wn}2LSZM;H(I^%Hx`&hOMjQ#J z@E+)?oH-Whg*9r_^i5THQCC^*t9jwuq` zYHeZ6*7E$|Hd(a6Y)H{ys|mo49#d4k%e^I7b+~mzSZpYX^=AaPD`|j=gaAUj42?bk z445rMOp{NZoj~n-reZ8!q)cQlh4K#CaTwXA)C@Ke0th68HW7&s3NxDaOdG`h-k1T& zUU}Mx_RY} z9;?eQM(a&j-LNnuyM!M!N&Eez-|g(`_pH%yJ9~Vj05cs4;aJC6b#vWdV5D&SKO_$r z)1AbvxS5X&z&z9R%lXdm>&2TjER*1PBHX58Sxr&28l<@ zXflf7IFw~^?6m+mVQ2#eLENY|KBIyr)#6wnK{*y>`V0Gaa^E!xERAyMFD(~(1ZN9W zkaM$ODI@v$A81-bHo~K?P#U5}}hhK3Rdl0m_n&OTV-V0-m z1_u8I3~~z~UqJw*U4F+QF2j6A=ESm%TzX3{YiLgMwEbj1B+S@y8E6Pg+V%|Vd>r(^ z+8E%K$6@lN7t&H`%h3X7!KkH9fzAp0E7l%9^vLbIn#rA$jK7+@SXdMy?QlwdDuAvAFXTqYzl<^>IGhn*)_ zL0GQw+PQV4(vCzv=HWP1lTwwjR0}1zecVCJcDnnQ!th(mk+U2kQh5$W(k7>U0>?;( zf$(e+0izs)=&bRSLKY?cnwZ&voCg9%)S9|T4zv{0o?4o^abud?c6m%r+O`%28E0gn z8b=4tm090%eIzX=OToq#M3bERhsRg}n8#-LO$;QhWE28{Q@kf|E-B?<=-=Tzi5;eA zOwcL-nK5_?MdWBB^bi>c35}Qjsq@rlLIEmPFcwHgD!D5q_V}6cvthg{blG^7=On_f z*ffHLx51j=vJ^^O=g-t_>GUzeHVZKr*8|dRP8y45@_1|`x%6T#E@PpK_8CObMHfZG zf_3t!e7dY^pYSqMfmJ_vu~-FF`;6GlsmFoc#R*eNH}*W4@>0wwgqOxu65e07a962} zU@r&9hx;9h26D$r{4{+W>hq}uR9Zj)E5;|`-LR-1dh?h&5uO=NM18j0Z7W5&1P|5I zp_qEcrTj3_;iM-S999JbetUOJAoAUt`O+}F?Ez7ch^VRpqGM*vLySEQ2Z8`G-9E6w z81%3ueD`J&ggaRW#K8o%c26?X54R;50tPM7(kL_7`WE(32Va%Zc;o^{>TnxX@>64X zYtwuCHmiE0O&@VR=Bj|V=AVF}no&*qPc-n;n=t4_LrK1$UMZ257nAR&S4#Di(PH*% z`iiQOq?P5#=?&y6MfNKpw2Y}3D!92qpr;3Q%WP+n&=aN1f44LJ#vKeI*W94C8dZ0B^8v014_BGiEhIqE|P)Hqy%#5g_+ z92`vw(p1G&1!b4WmpQPVU4lw3v|{eWTu}oZ(|m_Xifol*N$ScihH-WK z!w#$}t?nEb11~c*j!tj`IT>9>A{yP7m#spM7}rO|J3e76=smfVHI`P~u_H{dKLFow zCy$&;d_zj-$@btlc5h|;Yy>$J8fwFfP98BYm2yQunlQ2_(@VygJO$XLsW+7YT_wem z%1}$h`$k9Ugp!n@@n<-aO8X+UFS`j-EEI13sX@g26xTOsy+U@4CmXdQ#ke{%T zsMRMgX^@d~(zs6itpr9ptF9cFdgT9E!S$5_MpxVdUVy$g;&t6c_$Kw*Jp|vZVAWv? z=aJqyuGA1T9!%y{`HeusCAI2*KtW>2CKFz2ETHxEu zKlb~!BL8DYNOV~Rsls>&u|&t-8;PkeUk3=wWdXby3yguJ!ASOyJG-|p0Zn`~JeZKP zI&Ui=lYnAHOt>MMu=iwLT{k)!bAP})WFYe7dmgnnydjdS`==Oh`A;OPDuQ43$kThS zUzAZ}Ucdr0dU3*4GP;5}5PF(0KV%D`AY^tOi8(1mKz*ZXucV)(l!q+OlvW|c$V-r? zNmSssn(a6x9KuEtRlz)Nn;AK3?ef1yb0H3H(92?c*eO~G7U;$B?bF4J1$c>WpyNp% zRH?c=9*rgGRaB5C4~Rz#=WQd(^jSMo2=)q_2^Kn*V3-U@&B!i^zDENr3=j+79FHkU>ixz_#Wg5 zXF!qzA*(6ww$P}!^>{&q+39w7c8C35@lm^XEdR_MwvXsd%dYvC;Z<8C48fR_bP^e2 zRw?wBR`Z7fYpj?od-w$j0|>EisSdJ<#ZukzpyD|HSW;c>S2+&(5P8y>tVh+CRN@O- zA0ZVNZAyy5$dKWVQQHubH$W5$DGQ?ucP`!YJa&S;Bs8M)kpC;YeMvvFb|&o9q`B-a z8L2Ntx5Ii$z&ere>=4(u=CP;9rfWRVD$$HqBf|o0E{LofZNvJ(OnYM5MZyXa5 zGH2`2zW0l;J~ZIQu>uGFPV(~GuFm}xG563w1$d(LDVt4#sdLqfw}@4V4n+;jmwg; zTT|%gu0VnNvHiiEx(}i}%#BF{Nh!Vqn`vk*DdUhE!g0FEkdX+03A;w!f3>!e;{w^v z{Wsnba(ZhJHUtEV^OK&Bdik^KD|<)MMnRy#Nz6cLfjwFI8Gc%i0y<0K3=&h6JGUgh zAYtqiOG!&-`q7;3L$lXo6eI(>aR=8raBzS-RJB*@tr4!i_S&-}SkmjbUp>Mp_^faF z+G;G1c9dP&$gsb-s|+1-xI*H9N-yQ@*`79rzp`7+87?)`3=rcJ0wiI~;v87cH^z@! zdz)(9blaIY?%>mNrMP_pgfqPawjkb5^DP$RmHPIWD|sR*upeGNn3`&@NyJ}vhcxyU zd-?1sfY(v()AZ7jKaSQW;ylGnLQ{g<5GyeX*&zlncmQrNAW!VPc*wbjzA^%EmEum> zb5Np{LcFX5;Yu}w1w>pNB!|~n^LoA~GHMY2Wl|TEX=80Y@G!R)GFB5}Eg%KLKsl%K zmz6Xcc<2?*h)IVQyu=#9D7ogOI|lMXG(6lLgLMU-FL@|$M+upSy zGTLbwMVSxen{UpES+KJ+FI^vNj~7lE`*iHg)1&XUXTNVoe8%g zkwcyLArs|2DN|}1Kd+*F$%4vd!awsKS~=WppCs4u^d+(a!edItWIJopxNfajGG(Wb zKsPOmjA!Zl>1+ftiyI~Q~!T~xKNDO-Hd9`=x@lR3$EK!U%KUT!KW%^X72HOCwpWzPq}{=m7rOB8OVrEU)Dk}aMpdv#)2uww7NTU0VA+R`_}*-Py~(s&T%4{tcLt z5(h|o`yX6d`%hW*o0x?_Z$h0`;6J~#_K#6O!z@G;ODF{gP<~XgDUT;(Kwh7QM=6jZ zM;=thAy3PAk%!|3rKL-V;=|(@?E#S=e$9P@4AO%y+umU%Y|v*d6&9HNKTY zaS3K7f#QVPCQpD1ROa29gLWIImDsstr$wXy~)p*qY{T6bVkg_izGUoTy{a{Q={`LHrksUbkP=?fz?V0}**J9gjQl5#4%P z2zQI@^?J8Oz#4TCJB}hoiygvmN5#${%WYaLSfsvVsJjjXKpbE)gDfj4%cEC@QxRa6 z@W*0NEn3ot<4t8*$~O#>JcL1kFd7~eb%IJUT(AelX-CN-#i$NH5r;58#3ju@QTpLS zD5$O8_AclT#G{CZPy|%Hm3m}qqNAU*y2ovi>5#)5zFM9?6>)(N+xze`c;X?+(F9Oi z=@8G*pWs;rj=;pw;ia?3od{PCj#9WM)$Lz<+?k!9zbR!&BWM;d*IQdC@n{wx^4G~M zRsu6`;Ni8`LRpcH2!*_m#|UI4)Pt6>lvRT?F|^yKboBFINoLA|CVg}Dwcr0_RC)It zd);X4{)TPu*VAoJ++t;cjQwFWA@+NLn&h=46?4MH(`n|10f*IL);HXHPa+kkeT)oOv1N&*x9qt{_ z=sA@lzsUT?*7%x#++L*W77A|Nc!c}JNVJKsuRW?3W(6#VMw{5G*Xpm1X4MS^7dK`0 zn@yk-m2Z}=SFs}h3@NrY5Usv-bUgCwg3{_}Q2@F5=n;tK^&2;Id)C^a{$6F=v6yv{ zFR*$Uam;(6b*y~Ax$cR{{MepYtX{W0F?*+b;>67l8{@aKjj^{28%-OVV()9J5aOm9 zpG*u2c%dJvXgNMIGhDqa05h|P2m^SGNR;>jiBmk6G&L!>!rpP03mCzgi}zMG-@X5E zvsk+Ke(~PY`uftn&G)}AUQS@71+E8cOW@UA3b$AvNDXoH4ALzcSi8Nx{4Q!Ny}fdG zW%GSH-QQW+yoU?y1wvMVk3U#i-&|RKcz0>Nc<^xj!TpWfU?Llc-wgJI`lrNx=6dZh zC+jZUCOci^QeZUd_i?|_5_kWxhXb_jD+UC{>7j3%U_jutBg6-mJjkZ@6{ z9(VkjWkJ(s0IrX{k=KRprOCGF)K(Lt95SIP46<`?w1)t*bdB1%UFDN_62AWvnBKP;&}w+^!SIJOCW21BXKn4u75r%tJKA zp3$Vt84f0ncd&dRV2LFe$EQHlDX>VIqcOk;O(xLD?=!)92U6L9@KEOHKRpB+d)ygN zLl&V*v31lx9VG0w0uU16AP$2ZF(&}l<}q0~ZnB_Ifj;M*&gC#Jf&A|Mcg}>{=hV6@ z>eF;Gd-^bX7%d5xL5?C35_n|poZsHv86nlL6=C|ZF!5`k!#gW?Z*NQu_K!F2-xDH4 zE@=-rNFqlb;GKhcERmzfBOBA0zRws(h=2hx2j^*vellgJ`U&70?=G$1zO`~T)!qt6 zXE;p&*FO}~7}?x}N# zd|3UHXGy0eoIF^+|I_!+?0*AHQ5q6fjhLXg09m5&bgsxmsn?z{XYlxk41f{M2@(P1 z1iDwUlXzW|ePxyGZ}ml^WzrM@krzGCgHBT+qK;7Sv*RAzA|YNh5YPwGCzP8ZbfMF5 z`S#t1w;zClHo@K^ou^NOX^-1h`d8h5gUU^ck$R@uD1D1w^PRC`kZCv)6rEPTNu^ZR z8LQ7!^c)p(py&K2{}c2aN&lK3dolOQn-}K43-jL>Mz^6B0Ja37je3}FL$Vnk>J^B~ zmzQ?MHThoqX>nh}UT;DQ7+szl|9AQFCid_{l-BDCA~Wa_0^Eymx^jS6VZtWDMo)RM zVQxge5zfbRq|0uCqi_&w*LgvQs;kHhIJkgC0r?t`gjp|_LulX|^UXmVH(j0Lv5liQ zLKzz~Rg+dcQ8!zM&$tg!&n0`4Ryu7MozNsC?WY~purVUY+TeTQH+q?_ehslZzG@NT zXnYeP#3vjFON0v6KLQSj)x@UEF4%cMv5qr>NCklf4q@5F!7I*Vc(D#3c@PB&FQh>D)k&!U`AsmO zLx+rrR-girCLJ0%y%U?KY<7T|CuF9^L&QI?p*tD?Waq1dl$WO+AWQAsh{T5BuiRIY z0MLQNm-=R>-RU|UqsNR3uVs!A9mUJ=`|B1w9Jl)d0y!Hnx9;!~0duj7)gA7n1+RX& z^&ymo8!wf8Z*sPR=?ltGS9#fKJ(UT0P;rZ=B3f#^D?;Cm?a-DHMA+WS;csrmzM~^-soK% z^KP1d;rcP|ArJGy5DBx!gO4I;0yL`nj``6aLFr1INO3U%mqTF4X*VH%N0$oRtAj+Y z(@GA~=DCa+56CPiwv+tfEFcHwlGTB{TFvMx0h*Ts`oOJNs1|~#)C)p9BmA|*?-9u{ zx|80eBL};+?u@&zPwR+MsXH=w=@bSttRVw!sVRkAi(*&Vfe!*am%-++(;z?yI)urU zl>{U|*mpphRxza9j+-|0Td+U|xfL%!>Q&CDg*VpA=;jb`5W=m(>f~o1m_H~VNGBh} z@hgyAE!1-0GZ9B}?m{OCb{Fa#jKZ|T{s>N(-OqOlfP(BBKa_$L?%CoRVgwwFVyOJ2 zMKmTEn36}*37W$JrN(hKwSc3&QoIXgzIP0o!hHsKd&q`Ix(fTNnbU2Z#K9ebAI9iW z=+F5joDL$Z#Jw!`!@mRGM=NpNdaQ?e;&IYwY1qEQ@G*WIBsM$j9fuOFab=XeOxu>B zh1T!DLaKWXdvIF0R{P+PJN^fUri~FShL`|gTjHIsUcDmt$;OSrAB-A^Q^O1}*g$p; z7_-m6kj&#X?)~9F8p5Z<4UtyxgLF5p5iv97O;mi8of`+nu0gg4Gqx3U7*Sx(#~HsS zn@pTuI9$httsBqEUb`(Pp9!ORl@~Ndwc^#Ho>Cu}6aqr=f=i}cmYOvl$K9)W)NdY) z>Tu1LP@(w8FH0rn_EZMuF_;{}h-`ziaQc*s8B7&99#6igu^s2na3HfCp&_5Ckt52F#3sXKV9(>pd(yHr0c_|a)v|%K$OwQp z3ao@(jPT5ZHY6J62{jirUt4wZ2)WXvc%@+kB`M-W;J}<9E`p)7WZVb}+it-zniA>A z2BSO&&s2I;GZz}l-J)>X2%3ikNQ@wDJ34}ubX3gE@hchN+?)+vilF16goMKD$P?KL z^Qg}u&eS3zPSpw~DX*gpf^~Uu9>Pc)@JeSZG@4=ffCpnNycOK-w{~%aN6(qVT?x8Q4^`YX z>DseIh+0wCNv`Ouh&i=jwP2m`?cAKU7uKu-U`&Io3DS`mV_Df{grPbN9pusz4Hzdc?i5oXrmwk-DlfI?_La61iLP#Scp zEpGQAXsMh(nA7Y-PB~ zj|Izu?GSCF`s~)+YluT2C+oack`1)3dSG0IrU9_$9e~j9bv~BuY1Ghqz5>KoDqDBj zk|N)Bbp?KL*ARkJ>Q#<@IGD>I<2e7!QiOwr1Bavu8oJ_BjO&JM9nOvwfEu-}I7U&Gwf$XO}8MNd>Os{@; zG=MdSN(aEnt_Q^WtgTR8@Wx5%6IS_jyiu}GlU|V2jXB)pAZ|34Bl?s#{0q3fSJ;Z} zsP4qo7ANx@jmJt^^YO9ANcrrXGK_;{Eeqe4U5QV6xl_5M7s72h#o;+PrPq~(kuA8- znMcY};>PzWnWO`LCdZ2eWhj3BB1QOQJ{Nj${?;cnno_ z6Bb%^1C5DjBzIl4`j&vU(#`$$(3^9%^`wxPo+J` zh2z98>!2#XS-`O~y91ln*8o8&I(iF{+EhQ|;rvmDhQVqnWWL8QH%nLQ1>_D%3)@uz= z+;omfMNgXAp4h=(8jo{GgldIO#tUCw?o?jqg$&a3b3AY0b6|Mnl(BhPFUIqfb0)!C zI0Ju_9M8e}qh)xZSLb&~rq_N7r-+2#xwJH%<9US=$D=b2w`Dzhq#lW@&ZVeiL4gfz zoSy?`3Tz_wd5>aLQ$S$6(L+ahX0eNt9n;6jxW*S+EknY5c7A!KFt1McIfd(n5*Q4@ zHU)YeI<3pK1VH0{V$S3yU_0QUCtIhm9T7_2I8_)QMPAP)ORn18GCNzwt%F3H~@Fbu%BV- z`1^$deNF?Z5BhJ{C=p7$PIbBoNF^XvKuQ}n0*=e$E zA+{AkjLq&4ppIvCIJVBFLHCw$3KU$ck^>Q} zYwEL{3qcTnL?Uz|eKh7>psuQ(3!On&(I3OvpY)5E3S9&$#EGWJ4AjpuJ=&6pWXKJX7ev-FowkR8!F`;EesuRcfwhEyI1O;3k#?Jp_|(eR+a_!^nNnB+tn^aOi&AuB%Q;k=r@3LS+3EO^4dD+iKh6w_Bc@yA!el zSRtTy>}r5}VJgoS4-Bt^U;`QyXKgM>&d(EQ@AQvk9e#>C*Ol zk8$rCn~(#j*GRV8c!~g`@aY4vPbC;XG8%f~Wb9aES8@-8tc_ebFj8q2{Mry%+QIDJ z!&8J>^b!f6xK08mSHI7pVL{M8c)7I7ethn8SGfSbCj0cCK1I4-!O#80RuG`La` zBr#@-^it}OmwSiUXt|AQ%oy{XXv3{CxVENluH^jmibyOX%U&l(Xz&J=y~{d+50KJ^ zxh=&`^gKUIN2smEg_IJI)H8{4Y)*tpY3Fb2nHPr?Si+|JtmG#`f(ZMZdz`u(B^+Ww zjHDl1BwF$~JA!6Uwz1#22E#F^TTe^2^?#{z|%hz%D>Akt1Ea6V-^}^yX zTrbvdKe)TJd|OZKuZWuJ!H4KkW? z_BuO`acjyhP2pBQ?qdz%Mbr;BzZ{^XHRqS&GK&@v84JEFk%Dvh;M;uMIpSpj;jBzS zK=H}gkk6|%zq02@Ap+F;gIN_0L%G?~yQUMQ7w`IqAZ+1ta3EEY6ca728aOncKd(iq zsbL3>zs$RF@_l74Is8p@$U3v;OzaGHFrGhAmqQ-4!!~jXZz5>GqiP$`tz!Y5Z#gki zi>wwF0OLOdHB@jm>>T#Y+B06Yc(}O?0A()5LCEtn;8Op#_-ktD!qMCGP_YV@A|l*0 z9&X;5``#(2b0d`ix8=X41};?4)0gQ%^op3}6F<2@hK{+pCx{dyM?S}+Q@{>Z5t(uS zH8t3w!ue<1s{&M$08arkY_0;P|C$<1uP`-QPm}0u`N(RI^k1lp%btW^#o9MBn_XpH zEH>==q}`^WkH2mtyjc=t0L?kY7x2uC$|OtEgB;tF^OyLNFw}7x!jMS3jDT=SjC2~p zvrv|hod${OL-j2*r#pcU!SvaN++rSa8>pj90)!WoAxeF;M@~}41UEe01GrgO=Q+II z7Ot%}EQR^H07+*3DlhHgQWZRJacv5`M_Y^cWV|*%C0=1Vd~<^o01!Hg;XxL47OD;8 zQd-(<0$51x>F`wBiGXnG&ggU-zIvJuh}EhfAOX2$66e+IB#DlgbVhR>RsS7YMZlPT zZIgQsTOhn^aiu&HstG^fgO2Q-0GN|dxXI^;NQt1j2AY$pKO1~q4s zNFh`(K$VllSTe1Wr*+_^jaVE*k+$Tn&H12-kXXIg8j+;1g#Kk^#C~P^O@HvGw7Sbe zs`JL8uA=0bX){8i)MOa{t&U7Ez)E`kRVgq^Y%C_GJfsk#s<>N>Mvt*snb0eMn7*-> z-o=tINtG+FD8lQKvd}Xpa@BnZ3%!s-OcjAn4q$2AHX&QxS+s08XNgy5$>qq^C>##^ zSWdXSg+UCSIzM#*GYnD(VW<6&#k#7Ht!T(Fl_E*Oh!RErejtEu1A;oo2FObnzuo9S zUGyI+(H2SsY8?Xyb+8kooOUOeM(_o$acB$}pX$pZ!E>|@f1}vwgB?Js#bBet9?*@74$0ieasQWc6TK0E?IO%4s}ga>pv9D+6=8ZPtCRK_B zdz5aB8nka#R1E#jt$C~V%FXRpuxHg?c|$*b`xW#$k(JznA|oagG%>d`d^VstC3Kjt z-7s>S=s9cyUL}sb40GN_X@;_`ySfb}JTC&;1-%|2OYZbwLh`UGp9M^z0Ao(+Fw~q9 z7!b!l1p{KSFDT!Ufnud|k$fsHfrAo{Eg-{0O#d!6Xs+VE;Ctk9ph&3nF9S>&OK{JJ5VsgvqPYW~5qr zz#UjZwXH8Suc~2yflDRV^|IB7kqS6d&Wz8fJY|nsdAMxu) z6;!45(@{zk1gwKo(WQk9U$yJC1_P_ufUSW5Y*--@<)Osmr7)Sid`S%CWieCUe=ahm zw44i-+8IU1)1*q_Bb=);Z*e0p*@j3i?v$=wNj;MExJ&NIIH7EdF`Oc$G-GZu0ijwp z<6ZKo%DkNBN&tkGu;_B4vvxA73#F5ZgjU$hZ)S2bE5{u)y643zGPa2P*+Iu=R~PI! zLl8dwHC4vV)G9JTh#-;1A)w}fJqJ55liaiz*9rFNo=EqJaXRcq(o#whIUY(UuhorZ zCdi1e`yN0lj$)vSP|`u(C?s|rdesffg?RYv!UdyL4GISo3tS=hOXdhdBSwFSvKZ{v zR$d-S2^iIa0e7&;mR|~7KvoCt7%)Q}B8OpK9nmu2B9Tbc`D@y@vRldF@(C=mCY$w`tsAImbawRUF}}d4~~L9=Cv#;Quis6Gb+}^pj>}6NIv6+EQiMaAFfZ ztd<;SvJSCDnI%w~HGrm6F{3_-*7R|NhjsZ!)j=WwAz8417w7|6IOq%ppn9lDT0Ih{ zRxU)vl^9L_fS=AvPF4N1#VrLM%Afzv)IS`g!2&18LM@$%Ru?DI8nlh56i(JC))-PD zB9>Ak$w$v58LvyD#t>0WsbW_q2VXew=~Iq(yXJQH`BI zkp?`9BE);h=yv{2S*xvf1fBDk)0d+!cH|K0>aodZ<-7=sjoYB48&zf!Tu5WK zKd~nNu83WM@Cp}cAqb6GFVF_IM1%(FD%5`J$6=U#M4J%Yu}9z1m<2^M6I7us;Xmk+ zoTs2ihNa{k1j}RgCRAqU<16!xk%|XxN+C^rT7{lYUHcrklo~gITD`ie<#|9%GLZ(= zI1IshOxvDRjbc|e^r}ElRFMlH-v*>-=&efLI}E2j5lo-`}n%X?2vkZPXmy7AW+UDS&JH1HO!m?-abSanRgAwl^pG6ZjeVk>v>osViXZ4OMu z3LTR8m*kDWtw7(YXadpcuH6|mOc~Ra*lxn`G%b}xch$Ya-InAYsWi5%8J1zr;veU{sRu+-AI7Ef76d@U|IGwb0ltsvnF zy&j~q7E(O}#aJO45snG~)pb_{kokn+J4v`wbg}UGt#zK?O7vpB;4(FrRzKLlW*ei6 z*6DS}f{Xk|f}Zh<5|_^ctu$$rM+j_5BIP6wCCtAZq}e+ZM%28EXPY*oP!0gNa*w3_ z#pHW9y&Ww&%nFY-*uV#p*P+dfR;|;-bZbmU10>4%kTpR5WvtaEAifYW#}0SoI9PF6 z-`U#-T!(v9E5M~Yh~LF8+eoRj^VoGb3Ba1OLIjv*q*NyVUc8ZL>>G@$FH^0Nre!LP z@1d^+Mn^(^49^}=Ir_0O!jpztHf_Qn1xMk|K@xxexc4^ZT7;h%CsFGNZwggVlC{$2 zOf^jI_mB`3^2j{BRN!mMj?;zkxpB^ihn4vfJKRSlb@IGke- z15%jY4l|6@Z938k*Hgo00zwAT^)ikPi5oT&kANdE>a9~?XPdt!74Pb6H`XB&R|sF0 zB8rR~$B!MHajD0ZXrSgTqTy==Y))O%A1}(;UKa3jlq}C#0Y2?T*AO!26Hvk+XRdtd~Lu`jS$L=%+3Ch zcgH#TtUCUdq#KUQ8j?&-?UVKnGh31t0sV;^$wR@r zwNomUKCKjM038h1=;3x}uFmL5s4AlLW_5JAK?I_c20IUK_&BAmC$L;gd&KI2!oFyk zod*jAvsnVoPnqUTXOknwpe+6d=azCpy%w1|SDep)Ydl&vi_mK(6f#FhwxiBA#6Y`9D1xIIr|ds4<7PG! zAq=tZjy@lu#X#!ov<#9*1Y>9rgKbX(!y*F`7!t?1mk@?KX$=!HZ3ym{5`G(9GYTHn zfiFl*%>)^hklPd;x%fU)xb4pvYCBuRm8BQAMOkz%SKFEsS1?~kAuM-Hu25QV7_A2C zPL~&LC&~RdXUC1hK3CtLoOMV1BwJ(7o-oO;VjIiQw}{h9Xw9l%1~!%z39ESxDe!v7 zz2ffLGR2MqN$NovzclT zO)--Kk^aX?NAT=+Jyl9W)8H{D4utk~Z8IyP5n;kqpeq!}FNA#vUBNj~d8gTJNT#xa zVU5tWj-dB)wFPb5 zB-Ox5(QbQ)WDRISz?R;v*$6xgsJ#O|Rz?5X@6R6}(dHl4Np@>achtXJ1rKh=%x=yGmr|In8*xc%#|N>btYl zFP!Ts{1!t|xf$4AJWNswkX4Sk#uginu2}OlY9&yTqV2F?rn|c5dlomegs`v{uQpJy zHd|V{?7+eI%A{0UJ?f}1yR|U)`lIq-yhbe~ElOxcll(c3HITmBX>q#3omy?RpzOdJ zL;X`7seBWOO9Nsyb4@2_D5WHY93a+oMGj3i5g-R8M)Ss|U<#JRliW+pXo#ECqs+<~ zwvTtregdhw3$J6-zkDadLW6bHm0(CTJ(+#_?8ty^i*>}yh3QdUlTG(W$Pp|Jcv>PG zikmbfsc$Sr4Wy^nc4hyiF1HI`eB_pgl?{L)**v1wGD&6zmW{ek9d83iV_!Bs>fgZg)qkq&+KDHP}X=@6C`&xSK)7pzb`+23;YN*+; z{yZ$u8iW|Xs!WRH-xjuNibBcVW-cl2bZJ>zhwxzRg0w%68^iNSCq8YaRJfsmDO)%E_E$K$ z;R%oiGD*&g(jzOy^AOH2#kzRE(65dfmFRJZV+HloG`euNENfl&1&DMwL?qovLTAnuQ+kcq0q15HwG(X1fotgw??INcfyc^c2pcq6iC1Fp2nR_4(qwl_XL%6~f!mnU+BjhBtVf51{;`8g5csnD;)o5xM>4eR-hCQ$)R-m#*v`pkY{9JjM}5c0NZj|F9_L4f({w`yN~1~2zkb^ zx61j z$E`Y!>~Vb#%LOoGE$T_AKKC)fu?aprzH&u^$VFu3mMOEOE{g+4s<2|GbGN5lWDjm0 zDN|6H$-QV2{+zp=gevZ_hl}Wxx_@RbbUNy@KNGB}V_^C!Nm?gP=n^!?@Y4cTDM7<6 zP_7)(t`83s81728r=#q-!$c;VEo1ai5fUn=vhHGJq! zaE$p8otx~HvxzhOqaAHYl`iknqluv)^WkASaoF%PTGbg&gT@v|fivUg+R_8i&GQ>X1#u{RQbjl7lfH6bp3G*G6EoU;k+ z1SKq;7Z+m?UC3TJH7d{o*L;rA^NnM0(r%JAv%#FN3FxvoBq+6V&L(y~Gd7>J_TjIW zDH7+H5FJB?1S8(52SO~0=k?wQS|1ESG;>LdpQ?#aTj01c4NYjGcvfseX4yZC!#PKF z3ShCKB0&cbSMwEJ^+n-Aq>BUZ!tT5ej zDV3KO*Ex6X1i`WSX^B@v2VX@QBvVd%q2svNsfhd9#ZFb!l%rnkRBw z^ux769BiS`@ekLip?UWrpLUyK3*%IDtPdJZrY5MDzAXoDruHs# z>d}sN+O|CP#EZ%^c3++rWzxdMwoEcp?eAh+j<~omb=tmqVd@kyhWXlFOSu^&ZV_|ft^dv zhYDYXnLu&ACN3e?vinKx2`&PDMyp_L4vruQl6$<38&0?dwYb+g!5vHd z*lFwShtKH4uXaPZSb4F5O?lhkOQ~PUrP_Q4yV$^N_ad*mIM@ovP+X{Pa&af^%X=qH zFWP^`9qi@oPrUIz4InPtU1(TeIt`0qR}jx*C%KAyu|Wl%e6c}AR2VKUHYlP*{C~fs zm!>Z~FA}1c$)0MHyl@T_w7vX0Xci_Y)uJx8s7Rt;cpd6oCw><;K;bxF@*^rn$(=^= zm}~}A%W_-=e-a{ls8tZkRAV3UJU)|QP@5XIo=(*cBPV(A&6JHoj@kdXGdNcp)u1O^ zwYfLbz;SU>O5bW1&W*rGjfT!ISU?hw2AB}X#TFZ>_Y1$pUYxVV$(kA$U-CWnGltG$ zSkRNHc81T}4`gaUF3gm^y?p7+lpf0VVuOl|F8Ow`K}BR-oTDYU_!7rQyWnU0`A^N-pTxLw-tu#8bg`Dp75o*<+TOJq9;%+~f>?I~-Uqf+8si672 zWa>&;;v_o^QyMWf(jjs)G8{A0*|(Xi#=0ux(nlVMn(5r%KJIi`C`sxrqp;}GEOHA8 zci-)IciWn<%)(eF(4vUv{gGTY$C?DfN+8neQ9o%jtLQ1&J(4q$Lm+9zmNIY%bG1h? zJ%lBcBLeF&zPJ?EHi-yWA+!Z0atYn?2m$<)UNz`A61=5-F)&cl*OlVF#H`i;++?B1 zA<$cQP5K+nBg;5vjMIS}1&Hm6px437bIuWX=o!Kv2b_##+)&4k zPU5*dV*Z?nUB6h7jQX7LG4;6m1Dq2=CBrMlaze09ry+$DGixGXIYQ4ehX`^Xbo+fo znD2HDGy$PR0xxBpLcvOi`U-&{w=%Y7D z@8R{=m>=b1_~kWsdS3AlSN{vV`3@_Fw;u7{D*uf1 z%`xc0Vg27%|6lfo)^Ine^#84W{Ssb%OX0NF-PSYY64B1qe)ZDYpJ$P;?SZ{K zWj=xc>)O9`Y3;Z9PM{6%b7 zHs5(L=2Ds8yR`PN3jm%gEX&7c4SjNH?SEvUuWL>k<^;r~*~|a=(%M(Pn!P+mANKOA zUtPPwm){6AC8@Z*{q9%SZt?A}RTGX`iFdxb_E)4nhY+*B+uOhP)wO?zZ+``TAH$=j zWR|g4fAH0{pZx-%GBVbr1NL&~7uKHh<=6ZrbBo!#7r(If&;AtNeS6#vXJ!8RpIZBW zQ0AC4KNj}qU;WBg#!|MtD0M5(%5ciV?@X8!Z6%P4kdr){Fw^qx8)Xz~7knC8ii9UG z$1Og2F`nAxReAZy!>_TINO|&X(gM{A`AU;#$#Rw76J|)>W!y$v^zL=>$g`YoDdsFzsK#KIfRk^ zWbf!HGW~qN0C$pXfJ0<>hV0V87R4Q&`~5t2SERh^>^(y>c%)(hWih6)3%Qlvx%aSm zr+tW=q}}4d@piYfgYbVl@W8^ZHYx^uGI|WKw%H78-ysAW20?L$St=zh;rEMn2k(a= zL*GqL-(>Aw$9|7C>PYheu!olT11X^opA}uCZwfWXk30@ga&Qoo$8Z$`OlT0}^E4fp znZ4ugb@asj`n{FScke&kESB!QU%a=pzP@yC^ZoBjGFtHUqWuJko7qyQH|TaSN??_l z5130B4XoW>Uw#)gmfl{uyR!K{<&`@toA+*SY!r9yuNON37BOUYmn9kAT{xL-0$4qRD{ksiWZ?}};cyhbw zwAJlnQ@7d)b8$aG&{_}4(gIbGS`98y%zGTC%HL~ zhR>o{MP18uA~qlyeM)VpXvKoR?iR&KM0uXhGXCk_rP2xklyvE))-tP|)=> ztsoj$0p(yg>`10Lt^*rENGz1-NvtJ<(6m0pj;me~YR50|8%+%Jp#1NfN zn)Z=bT27F#z!bi0i@qED936B9n8=pE9)L?)%_>7U?dm(7`_TfZucBlQ83&zjQo59C zt`M>#r1r^6)I-8S?7LxMrObWkxK3YRL=U19}YhE^cOA2A2u{ zogiK|scpP6_KMWN)v9JC7%%GxEna;(qJT`x6|qxHif7uj6-4Rw)t`?+hn<`G$D|W^>tBbcMeA_L`!eS)WGt37AHhs{5;r ztaUX8Iol^_Aqt`LQ@bvik8nfym&C6ma1aKbTBa2&6&Kcm(Uc|m;3y8WG*I%sqK0vP zKiLT0P9a@q8lN5xcgRk=OnDxfl~!%C`x%cM;u0^xLu!M( zxiiKCb6jdkYU6h%rwv}t)T7bkL)hhb^0{aVxm_zj;^p`;CIOB^#Rh?61rG)jJx)Wx zm`BsJas?egJWazn95=HAz%a370!W}^C>#BggTeF}Is$0@+PyKpapU`0-obZH68%ks zRBnv_=#OqzHMXB(Hc^cE7$xP70(S1vnh*C&TNNJl!lSJ=7XD@cb4NgeRq0KS`+U2% z`Ta(tZN9TqzS7IN83LhyQQ+uyvhAx}5xi*nHpuuaT=_euy-xEsItB*(P$&FqEF?4x zLG(5$#z=yl9opVRCP~Z_QZt3ky$M=&@&7A5FH4wXS0_;&@-(X-odRwb|Ie6VwbqRB zLa^%%$jzQ;?d|EJJxQDvOTe*SHmKHvzP=aq5+$ji&m&HxKz4FA(}4cwZ>2YAkyyxx z5BQSti0p9?EY9)^0=7pdjUl=e%gqKxEyTpTlB`&ZT~=%?00{buunexwSsR;L-w|Js z-0TpyoHI`ro;E}@e=pB^Rg#QR7{x`KwrwO94z{L}3JFZgOqMXOHAgO-aZn^;nVM7A zwGz_?i~-SM(B79$d9dMeuZd2y%A7!=vtSC?LpZI)IQx22x}+!W0UHAFC1yrbK#-EE zm&8;ZG+!FwU=WMV-N_h!s@2=Zv7f^5G1!KAR*DMMqS>(!p+=bk@Y)9q;haS+E}~_6MHwHcFd9HJ+BPrC9c)op&8BsVA|fi>x}{n&*;Q zBNs%Rr+iKe>))!kFNrmDd9%mf`#10X9xS%stm}RLlYjcZ!u#+yRrVW1#b^&_us3P$ z-DQ)S4!vyk-cyu)qvB;=^pks^qUbkOBn*i#z3{VpKXaq-%ur+oJa;0hQ4Z5Ahpj>A zQ6;#l`Y7E&KhH&XHt~Slx_8fPdkCY_({n6p* zxZii^#hQ zBu&D!0H>SN1nK}T6HIDg)WLBEh46P0SAoz!tr5ziTI}`7YrQ%9K5T8k0YUMnEbeFQ z%wG;`J7-buXifuc51JBY7U$eWc!JF=PY&k&biC6*+^4~0{{qHY{?Th!`y@ zmxSRMkY$DQZTK7M@R|V0#7~-Gi9Fj8PPnXg0rE6Fo z^R>G)`h!5g_kyFzwdKYrIz-0@s$qQ6ENYsY8)zd8*rh?H8>Fzw>={oI{Qc;EBJf6byrAyjUT#wt0nuwU(x_C_THq zwqgpLZQe}m?9IGXI>i9eas9?GqHnZ-CiC=Og}PM_igVC(_5 zA()U|9EIz7`}hPne$kjAZrW>ZkF62G?tm3tJ{<3ix2J$+;=u3|41!f?bk&G2(TMwe zuzxayt&ZMFnoFRO0_Ea&$?S?*?GJEJkdzV_YiPWU*g2j;gxVucHlu6Ay>dCQ>ZHd~ z3GLF}LM<6b?I$nr3tx69D1ZP}1aQ%|)yAnlfaA36n_D{7n@;yJDMV#-?Cd4!1u!}( z5i&ckZa%X(iUcGrw&QNq4s3I9NB{uhVF-3N2EGiEmt`=b}=a7riA0`0ap(YJLTzDtX&u%YS(M78Wa%p!lf!8<>6my?2Kl>M(PJ-OwxRc zJAI9ZpbvvKHaNB+CNeo4K@K5<8H0eE)A8YD#N3Q0&p^G3 zGu?kt;wiYPcIFf_A%%^n3qG(;v8^~c#N8Z%4b0RdKXQX0f{O=-Tms?=eikSeG0=wQ z#$9k8a*{1%j^d0&5OXxHOh(b1^IU4?RMmuPuf-T4leWfalGU@Bffv+Tcas5-^>jOh zE(m&?GYA`Rrhq4s4RR~dg#Q>z}FjK^wwOuM}24$=zr&5U7IurIGoKKtW6D+m+ z-biLq#nly{skRC>f>|d{3of_PFNOt&PNEPWp1HJwI9b0qIRHno_=~Iht=zxFh)3#kw(oXXRbY6{ zLGoje;g~@zJALd_>>|L+fivq;V}y#G6U5?eLuplO99{4a4BU(++I}CzE}oo8H8&kIun}fntQ0zCdvWk78oG&5!JM z4m+758WLH4?RLhYQB)>sQ}ED1mgIgiDsx#{$3br#0g6 zNS71G+;Ts<^`p{EE%Pyx%QI&3x6+|wBe^JYGK{nElWXL0M<1_;pA50{QH7#hkh>~S z2~k zLRAnh*%l7>{r(ivT9;<3GAPRfUejca$)OI8^knz*DYYH?hc*hv;WC}0`d9@*xbQTumJ;7uGHk1JET%V6$r$Y z1Po2U?O~Y1TXK*7mfQAwVdHjhh3b4t$CH>c!W?<2gDzZ*f|yb}RAdHSrs1)cr~mdj&! zCm;XD8Q#f1{*`0$SB}YuW%{Mxfq)^mxkKV@-V5TTr5#~w683SYfl=s3Vtlwy0=fOI z4`>=QUrW)3V&3wj)wmnO1~i}P&dSNujAo~}ctV~_MOIquTlj+}grpllZKBiqGSm|2 z>81f9a)s_44NCYzd>dUXTSNRc8c!fMkKvwqOV+(pgm~`oHpyj?#cz zeVE~D3f)K-EC!Poy=E2HULnv<-{KhE!cmTZliI-mpr*%kCc{0n7*613yaOx@KN;Yz zjk91G?@Lbc{6_dnpPME*TjOS`anqDL-UkEt=qK};?sG(>Kp^h}fp|^>_bR}Qu0OvK zrlePGc$4=s65^&yo1N>4r%e$X4?*ATvgZK4Id4P&3`KQ=_E%9vOhpk-A^KGVnT0e$S(zO4GqYj4rhgoUP-Vaw7yzX{+@SzOXHVR)Z6KYr^i zIykg4;_R^?iFk^#UdGT&HF*XeBlHvQa=Q?eAmpOQAk^-h?`}Yv;}cFj0yjrTP_<>i zhBXQ$e0F)NCUXsgXBo#Cg9L`W-G>4VgEaMIGLBN3tr5Zjb+{vblih~uldZ_BK z1{}co+-%{>_V!a8^f1v6_DmwO@enYZ(2oG$HZAZrG?SMpY`q0jy?e$15*Ks^hXdFy zci;u5n3RS>Fv_XZll0?pf3P3CW-uZG3nf7TPrLgkyT~YGm!u!#-~HkG(Sb4{MNFXw zA9@|U5(gVL1Jt9OsaoVL@fx&A)G>&?b8cft7!Hj$aEea1CnL#BxTSKuj&FY2k_6T* zR16ozay8&@d;cWeAr9)0WD3c92$#_|M#E#$V{#lWgKDT19wG zuM_dIP+*Dad5(~^iBa%E8$aywZ^c`I<{9A!;m%~;yQAY}BkYaAWD63!31Aq9b?rMM z6Tc`q5r3Kh&P7kf(!0opq(*1LaWf|IEAS{bCKXE}(%`6JCEXtFGJix`h#X$GA+qMR z3p!FEc&|TNd$7E=;utIPa^w-FvBi244a`qP{>vVVePUbbA1 zyUh;P7b0j!Q>7-`T1+S2d=Dg#2d&UpoF)1Beg$zB&dWTR|l=w-dku6l}p z>_d}1Iyq)5jN%vxqb5s5oyQxuk+CDgb8Bu<;}&+yaOaV+z~Mj%0$|ITL%zX_5JIg48up^(M{K&e;Q(v*RSgw__7a)pT%3Ugjw|gJGSO)w;8X zFYq(d1J2Xse?ri_ms-#o;kW7-$v(Q%prtg?(8>*a2fA`PB%i%01}Cz@2ttT#`klWu}ydGgzL@`;JkN;q+orqo#_&T zP6~3MxfQh4$2m-WK{!duM!idx<>e`)Y0^NOKZMf-hFai$96me5?V*BynZUVvxHJ3& z{4aH8pSyS4s%#9kIDOT|lVDkb&*mM(f|5iRK6$0u%00-B5&3B<6_TPK5djEER z{o%un>w%cSX`yyAqgn<2WGhyOOHXmz%yM1bWGJU*fz;FEnz>(Uu2V^sK0DY)C?(jc z1$w)0+AKXoRy*dDkqG((OK=L8IJ}5<4i^cgg_)DBUQF4JYfkw3RV;TJ&}=Xr#y+PN z5M)%sc^9cA$Q7|&14WJ(n;Z6BSQuP-nxnS|%Q1fSnmq7K{+B(wrX|i}a-o(TCSA?B z7tn0x&SYD#>o#Opl51v6nib0`k|vhD78 ze}8;xlIU=MXS%qUc|Mke_Mt`Ovy+b=ISZ+f=5j`qhdC|Tx4@?&?OfzVhfH?vXXO?mv96Qr5&>!Ort) zCW>(SA9;S*!on)O&)n>c4~J?&%$d;Gup!Mt{8Sv+ z+8ctLF!UqyhZOMP2j1%mbAdaxNSIsqs|s-t9vwsroAT8-SCL)O4p@e$X)$R`$A~bA z7>STr9@Dt{Ma*iF<{3z)vg)+teoH`rUmO?NP^Q+p6$|~ir};2%)adZKne`WlA4xf8 z+{d`MS&Qv zg4I;qm=%E#ee+eT&A~?pzBK&2**QcC^6jT_FjZCr>r+lx{F+2Q?;)QkUTGI9FhdZ6tAt+k>gsYVFYL3$zGM*j)}TrzB6{}i<@p=!(_|R%$RC@ z=L-KI;AFA&dEgkI@lniUsM$6<1CYvA!km+t(t!9!3ntP-1RO=FLwaORM*&2C>uy{7 zYe)O^?%hBH&%ZTWFS`gG;=A{LjGEt?sp;`P*HrvFC|>ttxZTxX-urhPK&l}-q{ILC z-T=javjm`H(XE|cYg=iv{3y-g6ZHZV9Gk!SRZp-1{6A z|9Vl;=lge5@b!}3y~%%k?|(v*Z`-1l$BdW%&-eZxkBpj!OocSPWIa@;9+N(uKOa?L zml<=E?LPm>oB~6Y3eLr~YMirXDxZrAm7GDrDr=#Z-&%Rr_H=^tHHY6RsZ7jygj!`)+p8{6=lc&3fjwUs^-tSxUqc7gvt(NQFPth!o{G<$XR5&f zFW!rg=8bVd)IC8CE68kaWADgSRSwchz2j2v=DQ|bx&$brwa6-)Sfg1TYNoHg5J%7U__UfI zFJ1hZ*I?z7;|VhCn0A4?m3&!6TXO(2$SK}g>OJxxOv_VOkscsH!$ z9}JHW1?&B@GG^MUR89~TJLQx*pVf3A`|jCPVCG+6u~(vn*C&N`%a>3>HAHAFCQ|uM7ze*qpHgv7&_0A%abiI~)he;#haRG6cl=3N1$%R3z0lmP` zp^kaKN{I%83y=Z$06~9sda3Yqu#S;)x$X_3wrc+1-1pOtrWh1R60kYfWEEyW(H|=X zM(S!Z4+b%_n($TE$;d;e>6l_=m5|e4X^~*UF^AdV6IXXv?mxWSf3UK0d*wE?<(Z#L z&5wWlW8#u#g_?`Z8x77l*!f}i+9idXGwasF2X|KQ_SaYLv>pZS*bIh;&%FV9_ckjJ zel)K^EWcs-)6ZJdGe@BnHpt82?^@XhBE~<|&DwMBgatRPk$-qeGwVI({`ldO^;;`* zCNa}pHK|WO`>e$Z{766+H{`v-B)+_Jp}nK4Jd5WZ3+@&D@b^trh14Zy6=Kk6MJD0fX2DDX<5M?hl_&1_;48%4l29 zsgAX-i@tP`m`)3zD+My*505G-8lZp`rPIWn7Q952E~4myiWR4CE@mtmbDP^!g|4;@cfJvNGWU2m0JhM-?t&EOg${ryxGw&G1i>CR|CWp5k#(=%2_+9bS2- zv*=BO-Y?XFR7wEqBhlMA_~&{qoV^GwV$i^h1Y(kTd4rd^Hs7bti7ar%#U)?&K~hJ3 zpLlj{-yUd!^@R&g5rwWsX#?2$da)9$`_hS?pjzE`HP_)nP6E#)eRzH{+bp4EFytci zifhObX?g>419(bwYCjcigcdD`Drw;-=3@c^CK3t2oXrPnBtNLwTPW{XT&M<6$5dz) zgDp5e;)csMbEnB*Qg4e_MjPx%$opQ6Afu3|f~1b;YP_>>ISQv5kl{v)(gG5jD6_1W ztqgc#p>xj>N`kxR<0eV};hn6PN26O!<2MYG@i7dGS0p{lL(0022W$5eW#(t^T=+6d zi1h|nsHd#nNTiquGu>iwdrYg;!@DMv7u_qp1Q5R?CIGoOx2WJ3={}#^tofmB3u1fg+l%yDW;HYLIkswwkYku@PqD!t0-b&VG#YjX9pC-Z_ zkerc;>AQ&vq=QKTME*$(80+a?Sy^%r2WK5=LDd^-06hDgV*Yl5F<~`R1E9Gnl0IB4 zpuYkau2$O)NHF-BCanQ;WL%eg91y`mFEU`CVui0{C$PmG2u!X|f*I{FnzOL5Mvww> zh|aD;_Xzi7U}jp{9~^Aqek_hcoD~F%ENit(qtEtZuk5VatewRO5Znogv0fZp8z9TnAB8z5bR_@<)$-v@ ze06aMc}F1m(BuL-)Z&@hHXvj!Zl+zUVtv|7tw;Nv(8JIIiUx`d{tImP{pX0sDtd_4 z!OmwHeY&X2r{N?--%+fYocS*DoR6pm`JFXh?Y0;hO^JM9zPjsGdQ z-qz4ko~Gy#9UyoU9&grQ1blphsaJ(9q+!Q$X=*Tfm26ETeX#PQ^<~d9#7%R67iONS z3Fl#(Nzj?O&PL4xMRV=$jR*UFD}j5(5#`qvGUp)vLf%ycPcwNfe^YXMS^-A zP7IIZEyDp*3G(J2?!)j^?+BJ-OSiN`UMti5tqms6uwb^rv@GPl*{B|K?A~tYF2{*D z3x-8#1iTbzDgS&|$E=Xr#se|Qgq@&rCzqN#v0t_jSDP{;2+^b|;#t^vCjsI?ti|I9 zEm<-1+`3$TfO(JLCkarXA71DYAsyN)@-T27HaF2ABF7Rm2?1CdqPda^OcFStTKOC| zWu`6;aAcXsq9dPdo*>64s4h$##L?&wyn$nFwze*S94{4bilP^iqJY-@oV8kSPZx@% zN-Kgj>pb8)t)OWvaE^_uEK57GsTMX^$0bJ%%3S=(>V3JWcv+ zZ%LyoCUvQK@Ni?rnD3Oyu|W-od<$py1acj1&f+XcF@fz1e_)53r-NuTSgf~@vyB4o zdoY6ImKWWO93p@8kOlrlz}O2ufp9v!3}BW}4td*WZ~A7H;sy{CQnzV=c3Sk7Tr7=J-$Esqh1 zx*l2X=&_>*CsK(?k#-!(fzPbRE{cY}w6pnT>uw8JokH9bIN$iLfd^2}KUr?O1UK(! zIcp=#2p7PN%Qg|z#{(zGt9|BR>+x15M_7m$SLU07pf?EDer%Y=gcn+6*`-c}zTu3m zVFe$+>uJXqk?(Dn@xlnWEZ$s$e9{d)6`nk1r`5-$@8A61_p;q>#T)4K^Q{ZPhRsPs z&?ek>O#-PlSpauQ)v8G@1zSy!jL6I&;8hmW=B*u8Zi=q9OCGm%qrYu**p-oG1R}zr z(%e8&P;fnmUqvsJaOOmEfX4*p^4!xL0tY@aca0N_X6GoR2w@NH;JE+0C%EX$%P#Vj zQ-K|AGt&t9KkYW;YF;@H*i+;SD2-iwQimEjh>(&18u;6{z2>n^o?z5|8yG-_C!8=f zhGJHNIlz-0hogg&14AI?rXi%;n4TR*Axo#(i)wHld)`l~ zZzQ$bF&i6$nEUx2L1vn2DS@wc4h4wN%YF%mQCc!1IASuRO$yIzoK(_Z$(y>^f!7i* z(ZOYsa`MuSHLGjC{CM~lNyDjRhM0j;;$j=UB)$HZGe9v55?{c z%etueMMxWNvQsHZSaYXioC@0w5y!B*Fyb-9J7)B5`>_y35x+H7!9h;-_Y;IgrZFHQnY z=J-^3oQCOb!#jH8yx|$n%hjxoyxQFP))kM2JHs7h{Aw;c<}VA9QxL@{6a8SI$WG*Z zP!)b6Ywv!b(4!paS=HLdS?w-@1R#7Nq$;Hb1PLeO;g>>!<*-4BB>qrGeDK7YjQ{k- zwf#nQ^I2!pomk`;9ZcJ9Jvs}^hNnvnZNinnKnDlr zg!xIbiWEJh3Lhkh)BDM%gneLEguE0T8sgJ9$Y-PnNvPTEMhmhQ-dXKj?Op9$;pNph zG@RbNFVhYnRO-$n>5fvF{?M~fSs_@DM3TTfMOv7yXk$cPBW+sg1bDatHwSS8&EK+~ zo{WwMOxM79#_L(Y0dkqq@+A?qA}xMh)MIx9V|OZT|4UP_Vj6&0e0$b$zZ_BA`Rf`Gp?05+l-C>oN4 zm8?>X$N~VUt=ccOtWJFOF?~=>XY=jpM}K)py1-v4M+Ix(?JP!k;un^hs067+Ul`=Z z2X!({CYa0$5yb__s+k5|JP4Ft*g6YdsxSjFm9$_wrq2Kv>yW3c@%d*&fjhKmVRfE& zFK->_fjMjn3W>GFG49BL84lYx4KOl7UE((V1UnyW&dqe{EpV&SGsbN#Tcg%TBjsup z%GX6>Wi`!Ipnj`1AWB`dYvVb-S0gnFK4Yj(-g&IaLZ~rVakfm_z?gk~wA(*9Oup_j zpeq}DU32LsQ<388_2k;A9rqDK-W(%?rF~ap2$JxIP*!-JHYRK0r#03AAWF z@TO=Gzc1{0Wx4f&gE)86IMU_o*J58LUsWT7hKF2I<`n|{*i=YKU_+yWgA-$`*2GI~ zAmWoPP<-399402ui!C%GI~T&2@EgRD%wv@2m7f;~G?G83aW{ZTih?w2Hz}_dR2W6h zRe1Et_xW_w=+H(rbEja%-yA7YlYFYGWa|h873KCpS%@J!2A;|oGcN?`&nq-)(}-2>Cv;%b%ePsp#F8__gT36=ed=S; zG8!E24-SXS@wxbeoA3TX-ILLQeW#E@yDYbjDy^Li%&x$Mg+u3k)?oY z0}qK1ESwxL52@oQ3Me9=45I|f-yz$b2R06wnd8xV z*z9nDDN3q`)_KS^ih3dyRur*#MI-y-V4o2aqIuO#&`Ki3s8x3o)n=QpM=&D^F z%Fe(J1@x@G$dWJKSJbZh(xgxVk$JWk`%d>`k5-%|;!hX%bP>da`5; z!2=Bl7Qy4(Kqox($bEf=0>>sEe`Df{o>jXUA`Qd}_#PA{#hUzKzk1=@z-$t#$>}U* zH{yl!I${MIR|L9Yd;vzS<_i4n4!x$v?_*bp4T6lur}S`-C*jbNvH)8VY(3P&_|`Gw zb8vE43av{b8*}a0IR#A++8VEQ^SxumL)E8Lop&^dnA03-xY%#1 z3jD-`gR8c9civV`6Tp#YZuDazkaRYz#G*5>7-K5p292SJJtum|{f7T`|D3KekDk+6 zF1%oOfuxSH*LhSFGsz4%rr}=_7mn`*r=1;R;?PZv!e9A~RY0wf;pyt-!0(#Z;@lsJ-G%x$8Ysg&9*%JjQY9lo7rfWddesBsQ2v1?m zP>zmIsUP{cs7pnwS+nDu-JOnu*x02Mrv1Q^AGNqg_^YhEiC4rPN(M?lMKTLin|!wT zZ?*|8^@eaFxjh2EM+z;=XRr=sdG9cBtCvRhsjac3kBFY8X9qIgIQC$LnWxi<__XKYHAqChBxyYu z?t9L9*ho`ykDSR6PLaT=tc3_uoOAr>S`U>5W#9oNQrW;iii#CkI$F6Z%ygMtbh?Jb zWu09s!a9GgNbhOAjEX=c7%~ggH{Cqy)7RS+kF!=Wu#oPx~c( zj+YL0lmOj6^|>8(JtVl&=YT>e4RGY`4-wB+ELYhD48A(@0VXfpZ8f1|$HW0o#zGKh z?jOUWuZ<%|4SeKWC^Oi-bPe3h8{;ymL9n3h0F2FO7R(6G(a&zW*SjlWQ**ZNY_ddv(f$7Gi_tek^e*h70862XknJIO9?&&BoLbm6ymMGm+4lv~#)XxK zKBX`@gll8CXcAYqLWSLBd?5HoHjP|_W~;Cp&f!cZ#6tcgX0%&}xF@AYgN5!`@uYmj z7?cJ!NgHoVUa?~9gz110|DqE+HU##75EEedFK)KPWg4oZ5*t9sYNyBZl4<-7`dMy`xzL9t#F?y zuz*~O5}j2xZ!r@iXWq()2fO)JaL34TFl!AH;$Hg_w{cSP#SL(iV4+=EmTvI)G=~6X z9LclkOY8*mUR8{>SnH5RXT|*XKIjt zHlGjRQ-a;ec`-sBkX#o!z%g#XV17#^|0Q;F;!&%LrK2a0*+?dRMK zjYSM`sn~KFr=thG6AP%KH>vQaxDO%HB~-FAf??z!g`MsM5fZ|svK?c&q@7Hu3QYPY z;NwBSJQ{3Dw&wvv>;O{Un%uP5?277F5iYK>s$T_QaSk71k%pYt0DryoDX?wjNM;x-k#m>cGu`* zDucf`J?Fs@nY%8b&~U-_bE504!Apb(61{v5-A=c4IxC@p5qZP=ze5~}1-&O>!T37| zmETX~+9Cv#3MFJV>;S?cgSID9XPy#520-KBSo;I8^Wt$Y&hD4REjg*zV+%gh#MA24 zdo>QhQJl>sB#&8s_HR`C(DQ~j_r8Pd;J=QL0wq=SoZ#QRcMV^^!LKO+pch@gw}hf^ z)=3|{?9cB#K-t&JEDT=qx0NUTx9e64W%UZr?)?-^-|`BGE%oo8-TU{|T@{+_Wk0+3 zpP=m5QCaDI{Odow_g~`cZ}6*<3i;>%>fS%b=WoD`B3`7BcrW^|@BOz`5!t*K{df2N z4+2X!1^x5?wf3*Pf$!f+&>|St%Gdt2H`acS6~0kj8t}sAjkR}K_`5T$^GzYI`iF0< z{cTqLy2s2Gqh8y1V{KTK;?zR{Cae2;)Xx`d_@U_Rm=Q zZRb(NG43_~>W#H;zsdG>4KMv0Z>}w=w6-&P>7Tv1cAurc)wX+i`GYstK4kf~O)V;I zEnZ{u&9%>1<2PG;$&3HpH`o4q6rX(ddG}{+!dE``HgW4?u@Ch3-0rPrraJvy(wjb< zg?bgX=|Ugp;6mTO*~Xy0CX%paufI`t^hElz__3<>Ce^oU_vy>bHrLnr+t?elHmbhP z+b1eGe+#He-m%3*^T%SQGjwbtYE!4a&ZTOWoSc!o|Cqb|g&u81B8U+aCY=nC(*MW* z9#Z(Mse#(^X`qCKY(zy)4V@`cE5Uv^skrjc96_W*z?H6fy5!S*$ye< z>>eW|V)(=6#rQ;C{0ZJWfz8b>{+r%#9m*6qz-adcz~GZ!<&pFOVH1!2xUg~e!IS3h z@DO>G_M1m|t8lc9yDmt5&5Qns0OyzKQ>iil!!!5}NATE3(A=SkMDhsuJ?h z{v6y=)rCw#KV608gdu6{5To4+gd>zXgOW z4De4pF!S{Ew6}M7qR>dJJ=cAD{ZBa>XvXlvm@iER%mXBgLADf(fYQumtTN97XG+)1CO$UNK95;RQ@kFgw*Fl%SvHVRT2LP%=`3YJN0ik?39sewvoMd1TzIz4UY-f zpM9D&WQUw>!12LCa)9g6)@0*x{}z&>Z>-$D*5LQY8=!js{m$xx)yMDi4_P-Q4yr9| z-~k329|Ff5R>=;J#|QgFH2fVcgpSPZ=gWbp9$0ORO-FT$%;@7C0jM0x_2$3J>WoxysmP@ct7%Rji(b%1 znbPu`?T@$gBq5YMKE7jCHu53bbz(=^{+hlxpz+pHkmJrR*00WA0I-YhQ9MC%Jl;rz zizJKAk{(vKWRBRHjGw_(pC+5EZZin6NeLcIAdVY6LJ0q1H!ZE~ z`MxtIZgI#%zzwr2c(?s8lWt9IDE(X%5?*J!PDp}6cFtu=b4_E*dO6hA(rrAN!V=OA z8v;mipQeT`p3m{EQV)lc)FC2-nkuAzu#$XTvn>EpkyHg#@M_q$N7B zmF0RsHx7g*ql_Ump+&x%Oeidc6~$&xa}<3#ZV2gE*SNitRqZn{YTG$BjN_8l3cS`} z6w4%)IDowflAKZ}9pV`R?H%1+vHpCK7Mk@Z59n(Qi2$-q+&D;RNp*cQMqPPGs~s5J zMaWXKS6e)vn@Bz{U5lpuQNAjKgY0XE^6ZJUmXp)Tn7IY~%Hr*Wp7tz=mt5Ua0m}OKvOP<{{6Rh6_+pcAf+DdO zxuy=+*P4Ny(?B5JfU-ly#atdC$d^n*_+A;5@t9S`F;yKxyh+87V{j||h<7L{Lz)HC zJ%+DvMBnmNxTVNU5w!!sP!^jfd>v~QOq)s%(lVOkFz;z|6sl^v=4PHkOad<>D+%FC z+pBJBZ_zBsfslNKaeVKOws^Q=uaSTtt#^?X#Ha{FgLg4h?A&vTtn9<{s;3Ix;279E z12T%dlB2(m0ibdgaJYO+_&*+eDd>91hXke@qghJ7X|e-7v1 zsQ1WLxC=tSl$U%2IG`qb(!5*IYO_>g^10a2=v~ii9`<-vJ>-B$v0UWyCcn zEwXMSHnME)9iI~J{#L3wGILL5VtH*pq;XCJfayY`2;6$Y_hQ3c}HE@MkKX9%h z?-X3cfFZA_YyrLNLXXLpf~(#M4~Bu+u90#_pC$UD7nlJiFPcBN!59m@o(43#PcAvh z1UB$aLkzBg&@ggE!wz{wzHN++ViJdjS;gQepGcG*gb=_$6@iUbrfVeg#?0j1G4C>j zZg04AYmDfnF`hnm_J1v8hifocgoftQg?fY}LhP6i(J&->#GrA{AMrEw%AFh@QtApT zi-bUmiBQXet(%l1d90dofdSBmVPG<(e2D=Z)PcB+lhaBfm;-y`1beYKV!(ACQ-kHe zRVzITZEkijq62gEQ_My!d>|D~gI)0m@z6Y;B#;v>cm#r(X)F{L`s%|rgy_eP4O8!I zHHAR#^eiW_d6C%%-O~n11>j;w81xKyu8|u%qsK#ZIjKv{qtW&=A%==FqS+{{Yn4do zMunt5jgKu{AkeV#C=C{3jhxP>iZ$Yv^-~RebALEQayo91W@}{k!PtyHM1D^dx__7@ z=Gm~O>0}$M@PZRJ)K8K6AcJIQJDBB#fMDLfezQPk+}DJR#hJ(z+{HlQES=)68o$Sn zyFX#<LWJ|M3k(uwdsHtzOt9~sos6<);(+SRG(h5yb9xBP1G z!`?=T%Zvj9Y4hVF+A)32qtbQir3zL_jI^2(rc4DNh0}r{F>{{cfKSCpvVDL2%=0r> z?YVI&$o7#Ycn1%MBSL{@JDdsRamxHtY-CP?KVBKj$m(D)y*sG=zJtj0QH-MmSg%R} zkSTTVgQxFn7=(L!<-I3&&#iw)>6~DMPHpm+&fDF=6v1~$HZpDA?(P#b8Os&OL~nOp z%ew+3&Gx{JVz}T6I96s!hJ&|4-d_w1IDTfKIuq-91zf8%bQdfkLnPbjb~!C2XQCCA z_EQkH8B(e9V!v;V4q^I20oJ-&TSD?5gW?UOEWES<7)R=n4gK$zw)4SVV;lT#^=nM{ z>^Z;9ml2;hmSd@)p<+>rfF{lsb=~A5fuE;eA$WPz!VGI@DRV}+^KA>RSjxCi;d?Gm z;_g&54>UB>Ot59C`A~~B!x0BlBdDGSvWB}Shi?;bLJXS<83VF8ks)1d!$A}q>WXU-{ijo&o8IZ)a$ zIkP;*&EJTB+8%Bpifm>OoPfveq)JZc>F*w}h`SbjbjJunxSKW}-hK$vR*r2F2u13^ z_C?tNmyB1|*B`Dg;0Z{b2mI)l!@^I6^HOFT0Brpfqtbax)j`6j%P2m=BBy)+coou= zDfBf7Gy3Dd&m zVQ+h%jHR{7zydsSoV>*>C9{mkIS4g--x-j%*9(teUSnZr;TdFADH}a_HKZ^UAigY3 z){GtnV2iy@;*Vr2gavY&QlZGPn2NYHt&@w!LYb&zc7HTzUeR@61w^Vol9x5NKVvsza;^m`It7%{d%VF;b4!|WZ_&)U)n5)2A`oFA; z>LUU)ZAX&V_&#aiH;Y2I!EitVIJ&3y&HWA0(RFoJPkp{5Evylg53m7P0>0CmAh z6ksKy*%S&a8rvdNdXa%^(mABT0j}GL!AFNc_XM6B9-umz$lXj+g4zt{uWlEZUzG|3H;rhD1$mi0JMWVO$?@K& zeb8uIFc{G5ga$}_d#2oF)|yXm_?AL6O5rI+m&lL5XR1~3GG+Tyyt2AHWZL$$zC<5V zlcYw%XV%HmHvqMukQ;lHE zJ^U`{m*_`8K6o~cC++1y!!Q|SCx+cNpXne)zAr#V?<^!2w)(Mh3N4yd zHZ~Nz2Q0<+uCqLBmt-c%7%D;ePVqf4>y@~AHQJ>;^_aWm+5X86JjGfD4*!q;c!3XY zE%20U-iE3TON<|*WKLm--JXDgG~XY4<9f8Xr;gU;L($f{=LU^ z%#`0Dls_)tsS{K6yNz*#Ji`4W3I>Db*7Ac}EBEch!8qn(+Rj}f3L?&M`vdSf#5Kx* z55WaYH})0aJzl-Lv9i9V#Q{AsmJy~ge@D7JLoAzb@T(a=bG>RdO4?%tm@351aO-3b z?kTv5KwQ$uibb+bQ)%AEFr&WgP~2E~yy2w59nlJb!u270BoK2i1E;bi4l$rLqtt6L zcY=n67e*f<5Bmrbo-psksX4L|f9Bg@RWg~QmZ(1og?y*+*pAdRh}M~^4*Wka*EdVh zH>)vX+C||~b8}YtnJ4%V+YE;=KSqc%1^zj-S!*-Dwp77tVG1(n<>Qfdry>%BeK)IX z%Xe3b{$~5a%0v)aq}Z1uFz9+0@svv?jXQ;MjQqI-k(;`{x}tT-w9=iX zJKXEh6poSN>nZ)_hglcOn}d8zuCO_QMc`{#pZ$aF1x8@idQe>gB=Ydd__7Ug3TH!OP@>69z#)3_Ak&L zurV_<=-}K1mk|PR*>G1TeepuMi=;9ma2+2rmjXZ@T zfi!34Sj@mj?k<>Preqhf2BBI!Ket;&(@^~8rtnU0J?I&9qFe*1$rixQ3h`~QDfCE} z-T1angj+LJc~c9@xiu41R7~vWzah*fhavtVvU$Uz1k!3B?lo#3SjoY4}JeI3aG@{5&eIP$q{L-d!& z)`4yxdm8bpNRS50I@{7WP>2CzCD7ptu)s%ap*6YM1QgPqJj%g1+a&s*uYaEZbP_Ihzwnt4eJ;I=o1s82Lpx7dW2FuIS^vU7qljh0B zt$ZWGb7QQ+hy$DA81}q)bOb=qvgiuuEs4(GZI<4HxgUBS{B7QoKpWDzZa)cmRGnGp zkv-qh#rzMMPz|5{;_<@=Fzkw`GC>yonIF(-GST5r##<)VV#VR=VPqF)E1?7jK3-oU zE$~yhudX7*V++rDz}BmFVUs3R>Jy}8$`-!htQ;$fUjAad#rPh`h&w5UDbuPb+sv>L z-6Ouq#6*bvb>C<@qvFG0YpNjog6%m!$C&0u4Hq?Wc7-c9?2L#9%E7~#=$WN_dvr9+ zw`_{2iW*{SBm+LrMWG{36Ky<5a_31x*24CStbbNN>oS$xw0Sd~n=xmEIR`hu`@uLH z16{6WXV8TZY#+5hg>VAv7Bv|v#ZpbD)|9HIH*EMKK`dP&MVV@=ky}OE!l?PFJz0=N zh#-J=_(I2HrnJJyb8pk0sZ|g;D%n63)0(e8%|u3Y3JRZT1Y+Smsrik9($Pv&j-Fy6 zW?PjcfmY?8GjmB)#X&XsOo}YiGYy>gTJ@?ylvJ-p5UAUdxyEXiSG5J*A5p*|ild(| z%NF`R?nuHpV~jYgU*L(clp-E>W;Oae2N~}nUpY60w={7pT4mXCdU9|8_6-dblB?D2 z*|!%6zoLd|AITb9;Bq8Ec-^h{E4F<&C?mzFXeQj$qlWHMqE$3Gu_Q(t_C*9kIT?T$ zjFW6uKrSpJYA6>H2Y&&w8RH&9lqn)=+%uA&$>TKrfCySQXGUmBx>cyD$#H6^rn^y& zBFTO4Dj(9chYak)Q)GI#X!#g{5tCGOo_ePPh*XpX6rfC6IyOQkN9>29Ckik>o}>j6TZi{l0{agQmTao9r^3#BJui?T!wmTg1GSF0 z1!2zS%l1BrY-Xv20= zuxlD$#A5BJG%WMOSz0VNYha2u2%G5<1R%T>-8^}M+a|tfhSe|iP7KCmdaL?zJxAw& z=Hl03R4c`4{DRcb+jgq#Rz&OvSgUUtH=@Ual+W6D4#j3k;u0pP8bIbY>ayQ?BON0D5^G+N z)nGfPSOYyvRnJ zEug<>DqYqQ83(dvlXh}ffim^l8;!&n97idS+%k$OAI4FmhD^3^4~yD8l$5^N(P=R^ zB5(^v>NQZ7`HsA_VW%f@9YY_-A1lFC(e+pA&3Yg!NW@OwCs3K~Oe2;!y7DPk>n zB*dPA#9FV8N?D`&%wxCuU`Jc6^HdesqNI!<3y(qeUCCO09Lw25(>T7pf|L;3+ZK&T zw`HKTOHshe1@|3zh2cxdXIbGEP#hFR9GgT!wz*LSvhaUY{39a^BX4=()DT-FlxqB% zBX}y!no#(Y7K9Q*h0#22tI3N#a*)LdSyQp`93KEr;)@-{N<7F8oB+KKJ1|`rQMN5P zj`OiO*I6M|9kL;*_{pRD50`I0mdWrda!UFZUThvA%AEYIJx(zW3Cx&)P>BFJq^=%s zk7OEj)l7RP_(kGwvd$waa=i#`bElvgJ0YvfR8NOSwJ9CvufG|}vknBsUP5R#e__!> zu^;C66Lv3mKIJL+nN$mz>2TF&A0{ZFLlgOq`*)mT^5!ji0pU9VK%y^%FT}^_-F3rc zCMVtFc#cRH^W?!En4-EAfThsTOmmMN4*jgI?ovjB*v)2N5ppx34B=FHUMASlXdK5A zqLfc|co$8TU~=xkiPjnX6v3tCks1}`=PYv3TOS!&PTMXu>N^SDaAb5V`&-!}QLq6+ zn4YjrkA{cj5(17Ga$6lxNQk;k189t@0GwM(nI&h*PwbGgV&dhHTy#tWx#(6J%+O}F zubj8LZN>h|Bxn4w;J;JJIhpN#f$gDTIAKD;gXW5N66|jdAnYrA9z1ZUl|6&*4IGfy zXD;6i$M$^~bBZezzBR3;z89OYWfgMfVe_t?&mrj;95ZI&jwCPJh!cE8Hd^BA8(`Zu zRw-!}@0Rt1)N8}1a%E)e#0SCfr%V-Q{<4sls*_(JbmE_PFe-h%V@&C&GDQ{VZ0gRh z>P%JDV|{y5q;A7SdLvO+L3oky!T4C&>Ey%9aDBNm%#!DxM>4YiWwyG^4DyMiO8>;x z_Z9z&EVeNz!>@)vt1Mfgt**FTRXcMTX*XpOh&a=w)p44fu1Q@yZ#NOd z#fS#y<-i_Zuzrjj@(L4@T(EJoi+$UzzooK87Wyv2{0KEOKpF+D)n@HqK>++l|o`u-x^akx`{ss_(^))Aj@#l;Uq*=C7 z^CxqrHZU6(9a;nUQZuisc0{4|ymaFg4f0*Fx4`L<5%Knip|jXIX%3n&`G`M! zwdCspNx!t+YN+CF;4+O4O=AMRaNmMhYV_3>nTzmg>>fh0s+r`@pc)KghFp9xMJ=S# z#Pw%bJwnd19p@!|y(dY~6viOXuuPFI*%O|`FlEF2_~IG*(iX+rv|CEa#VVKZN;$`3 zkPD!R&JiPr2>g&^K=M1V2lD+Sgh27R5?NJ#4(A9KVwNPe5~XaSTC+k4ldW)>crOCB za+@7=t~`1(B81F>Yd^^ONsQ}86C+ijtdShe9%&Td)P~O=SgK2!aQ)uC8i&MV{mtGM zxagtb_IEJWxVa$k7))3uJQAbms5oP2s$-t(ZpRmoe#&@LMix-d69tTrFSmsL8!+9BP><;DpY&MiDHBzjRWx)fv zD6}g}oP-}g$$rWY8V0dhnzYM#qpX@Y8)5Eb?yYSRpo;mkavg~u%B+Z*(Q>|^;rAz{ zXSXohJMEuq5@9|5U|?Py@Tn4!fbGl7sX+z7iL;fbk&qCueWLfa_*y3Jj7zM?SxILG zcCTG;OALzGPV30#{PEo^v>5X)IDKrDWnMDDVDXw0f>qOkDaavhZ_I!_Af21NU1Mh8 z;ue^l&(iY?=42vbq*2W|PLO&QQ5IrCjxBCIzO;pZZ6_0NvAH!d9|FjP;S)Xn$Fp@> zrm{NGmVHhVe8z^`0`0>2pdcO>nS(9FOp@L5M8`an`O#K@T%KCdo#(O%S5A;6`HyY$*j& z&b+UNxudrehopBOtDDHC?>O&kd48N|k(oL*_=j)94mPYE_@__wsN)h+A>;Ik~V~>cD5iN ze?j<$sltL&fso$n=4eg2zMGbZ#?|qytTdw8QzYRp1!bHSIKf&>-op&>gLK`*9HVxd zK;8e+<8y3|Fg4OC;@3E^-CjC;o*c;-8IpeCSQ+4z`S~tKMgK8$kmue$a+?bg#Rjmj zsxq{Y+$9Il>-kC^rAH^cP_&aG=b_|Y=mv-7!9ZOabmA%{y0GuQ-sxP z%vW=)uXh}eOu;FcE@DLUxW}Q>Kiw*GKp+eR_B#}$kAsqQ1*wqvpq>h#WIRn?t{S#O zVAtOM!OD-;m&r5>-icyF+YJx58K0{mxkOfyB#Hh@xsqa%rHcn&@Q%#SjnU1MYZ3KP z@DgVLqI047^%J}VXMwP0Wad{81lBokYe3*J(sIiIaa&b>{G6hu02_*@Gh5R<362|- zvfV4Bbun}1th!xH$f~@2LItP`&Z&SrcTNuRjA<490qr^5#p7qVW6qryE4+MG3CsoO zl%UR?k)WM1pVZU*+30B_tgh{7WdBx7WL8EP#o_UTqB>(O=VIX2!?m^54Y!w_L8W3) zuSTdfOM~=T6RJT3H}@!}VxZN`Q`nMiBAmErF>_Oegqq`U$>Mwm#{G+wVWw3pv01BF z&|0gajW2_X@wcjR`BEibXaM}*2?W&3e zNN?DN$0axy94qA9b6SZ4sx{9*lN7uRtr~WQ11{m#3nWf)7z4`=5rXb=+{(oxdzz)R zwu{NTmW?3Z>9A8^){QbN77JM@Y323h zvx_@K=`^CDW*hK5W}9>b73%FY%zg(8kr78~#)|WijoLXB$3M1k4zqhj6TESR`NvAY zf61ZxHoORC{R#J@mKrxx^O>R*`j<;`BTX6?S45u@lIg6eQ_UG$qAkX0N1;C5-2&-Y zo!uTZhbf)b-OhFHoHBBmJ-L|7BH>!SSMBmx3eZKuOigtVe1SAyhr{bK^O!G66?9SQYZLpJr zEu>b)oH$R3>LsDs!SR_ zG$9)2TQhhLmlUEJkV{_BCH699pG@ZF3du*JFQGqrO*WbGS^}bF);dC-{ej*xLO|yK1YLV^M|oY z&!m?8^Dc~k;O}0UiVT80e_{F&@e#I;Ycoxi<6`ixq&Iv^*PFG!U8(a#S2mM;OmD6+RO^$fx zPZLSAFR!9)k{!^o0{$SlCAN)^dNU^Vnzmw9H+`)u$L{pHS)I(Mg1w6bc|7V0LbfQS zC7N;iGiWfL6{XLr3~2FelQ9MMUn~N#=QxR8StHG{B~m!BG{>`{mHj1XGa*E&mYzT} zk%wf6h%kHmT^%s-kG+w`;l@uMM7wb=;biBxR$v#&AXOIEwx~E~QFyFufRogpVZ`hk%XP{m7;anAF!M-fXs)6V+WJ8g z3{2IV>fM@^n1p2eqaHk;fPV=C!;^FzembCgxc&j-_d#P^B~}U}cm_tyWx=Rf;xP;UFpSFf;fZ-@%N<1uYL1~!YFJDOUl7G7P-8WG5Tf_*E$d|KZGq>Wk-+yE6do2HEl$qJv zOTYid+LWbVFAe8jcJjvBf5x)EF1}<(f*1XxH`e|eH8bl|RrXKbSo_~t_N|$#S>E`6 ze`D>RvBK{d-1;J_*ZHeA*8X4C`7PDq)XeTa_45DkjkRBY6Xn0D@_ez%i{E;4?RQ!H zZ53CST)f8by}9-Wtnn?ck#Eg-g+F|A?R{3T*;^Em7yZSXYkxl%SpbF?{ew5x{vnHg zLttrh_k#cY&9(oN1;4HWP=|m2zu#Q@wO_;cx2yp#&3ehd`fF?7V#zl-`>c0(>2Lqq z+GUm+JkYOyzw&EqeSAL=eb%e<>6>5sTAOC|ZH6@Tbq+yU?e=&KZcUl`mPy#E)HJ4V z^EZl$W|vl<>-8u;#X9KI9J3eEabu9Q9$7}ekNC`1KwiAyDCP`1kI-K0+iP4MrN zpMC4-gSo{1KOr`v4IRK}hcYnO_PrmlGOL*Gq7E=08MtD7^>E621ynEy3 zA1&ZNf7~?4kKepMK#u>_!|mQ%tSa3@vOg^UILmgCr@EPrcaKkztLlf%i}8tKqmdmE z`LrgZtrG?4^C-LyrjCs6qumz(1IZnNyv{iIM~0Jw&?B0=51t_R8uNJWH;+!X_K~aS z{%D(*I?0cZ_=V5g!YU6iJRI+E1dn|LNUBK%fr`-&8&`omQydZuyJqX~nE3=Sx;Tz8 zZ0LwbY=)bkkQ5m$Gl^`V^JktXsBGXI%2Tjpp4xCQxH_|?Y?LtPT|-YmM)Sey#`_PS zY&6RcK1B5X`ug&NjSqjQ`-OBSASJhn;CK{mpYLS?s}m^QcoAtA0M=I4Z@rHe%kQn; zU)}hS$K;*WjRz}_A2)X%t~blgqviFD)mu;QFRwR`o~%DY;52e-J_dd;ITusWlp(S9*W6mBurk#>l3~HjgY`+c7A1 zgKrq(TL!G$h1f$sfp$gXG~NqAY(E}`89tv3>Y6m#MUC6=WxdaLbSHHkWTIix_yj3w z1u?F&TYHX+iunOsBi&oF}x=tVyo?CV-`cO{b5zaQ$^9N#TSGX@GEg;XuE5Vqaq-)&|OmcNAaj32pD`Xt6muwLn~FC+Oe_aLXU=Pm%4_@^DzMW~J=AR1N(u)(oKF*pmWA+GEE zRs0gbQ;;n`a{u?{Y@sFXqcl}kZT}Q|Y^nIYjw5O}a>8Enf6uS%6t)zUcJ6S3N|xf6 z^I_X^FZrsU3%SJ`>Oar#ML1v5f2+Ox0VIeqFR7i2*JXgf+7(HVMEKOBKTB5*vzx|=!)mkR?K>Y?RKn{F z+xE~a@UBFt}YwOTcJ%7qdNt`NyuK=b5N|(MK9aNt`GTLZirwjcpsjG3}x9TyGq;JXy;I zngnlDXKJkvTVoUfi!XC_v~r!i$h!FYia@EYCuOB*n;mEz@NDNr)%E~dGou($Vg?a9 zXU(yyM?Dc+xEf&5@=EV;_=#SI+EF|b5)#hGZ>{)DnWKwI#1_IBqEH6SWJWA#VFeD3yjz2A3(SZS)fxf#)2M{1i!sQ(;teA2x!420F z3dit>jt;MH!T+}Xbb-sIZHC1{5G76{Y&qJ&c^92m&Z|BFzSSkT0TMFH2%l4z`xDO^ z|MfIejq3<0TVX^~;2t~{xVq%wYApm-a8sYgog}WLyZ0xoHa+fp1`?%q(Y* zwC<0`&mj5W>2&(=7Cnyu*?46f7D#?|+Fk14EnScu9*sZT9qkzjdAU>Ll00^0L#Heh z7QXqvehFn}>IryQ>?``pTn+m{xP^ z{=)|=WyRg4&T~2r(=ZCOE_JTMGko1Ty6)=5gE1I~ydaM~ zwq#gG(n=IrK1sMbuQl{}PSbDr#gKn1J=Fx@N!|4Jn)ToWC3H24pfu```Kp5nG@cos zX~v8U#Avoya)evZx)Y1=Z# ze`8}+Lz7)!TkaP9EO(!^{CbCAbIQBPaW=54*0Ik0bqM@GEci#_#y(O+@;Rjc%u-} z{N2$zH%rZ#!_XB}pS@JEvr4!d^?*ncu>NG9P|1 z%Q?^!9S4m%{7-V;$b65pqJLL(%I+pLu%FB)zyp!=*c&oH=}%wWOUa;_p&F){Y_gN^cZ<0c%T$H!;GZWqvHsZ;tD~? zS2XQXq$;kCW*2k}IqU6^w)$(_`WV`oI`ofizwAc(N8e-HNVb&nF{;moQ|oQ=xYHiFjc}0j1^3&9$a6whD%Q%z~6C=;WV~lLoxoj)_Hdd|EmSm#a4co<{;>77na z_6JNj-u#7kF@}ELkM~GEoDOzAK zZy*2p$kt358Fvo8OKb$XFCj#u9laM;Rv4+7$~nSFw{axRV83;$*yu5GMha}_A-AL| zBCd=mW{(P&un^`c4sMubrcCODlvR8qPX;x}wWs6B4kUJh{|PxJO`a@<`A*As1w-T` z6BekAfpne?Cx^p*JhF%c2zfx~AAFk~JE`ar+TIKhAEiSubOeLl&!g-~+sNp%2DFK(W;Vu22!q3y5(95=0Y6to{gn3>5 z2P8Mtc1wk`8!n34TTbl8wpmmu&w&e2W;83dS$tAVaT=s6G1b0Pe&bh0!v5fJ?*#Wj zC7xrKZH)($9mjz~oW+0@oHKuK`D!f28WnR-W8>swZ1bkRi}Vwx5Jz8?0_1@4$tD=H z(~Y8YCLC2>alxZmF==xON%7>gNtL+V#_M4^kJ6HpoWyRug3aB?FTjFxp2g?SFwbpv zkPr@+b#^2Z;3~a-w=I#NezYlP9fyT`7g(6eju+K>Y3SwAe~$T^4ZAA(%+=PpNroTcAf%B5WQ9FWzu+Bs=|2Ju2~eh>5{W>f~YIoIs~m;(;bAo|7+c9Udy@$ z4rA_A=Me1lQnOiC`AE+O;>wztwDIiL&UhP6yF=cAg<^`Mk^WCan4Kc~z`)+Cia?R@ z5F{kvF8&npI;}1~qAt8Q8EhdP&z|^@pn|%G>?mgy0;P;#(nc^6USjOlP_D_T)RGMA zDnLm6Ve^JxMf0>f_l7T4dF-Gy^dLNTX}K8uvkNr0;2yGVU^0h^49sMqda(r7b01+FVm?P>I3UN*PLBFk z(6xWAX=XN-4dfN>-G6v%`M$9+Lo-r>13-pGwujVN6a3>Z-1!0$d)`MkH8uD)4e&N@ z2pF}nJ%{sFk@t~C%xRIA^O4nd;xxEMoWGp)v!?)jn2R{Qj04hdxPhxD@7efE3a~E- z#Az2B-r!#Evglg#c!XHe^`VC@giNbE&#y%RIC+P@dNu}s>d;n~r8Q-Ay@9P6$7D69 zBZ|5tM~o0rt8mETdeLbg2HS3DYiE19fb>EOR7cE^M~l<~yi22f_qZYY0|4M6+?`%0 zwNI~`55|Z}b8{Nf5O9PM6R7SKqugfTa~9x>n4hC@i=k@!VqYlN9vMIDC@|OBfYZ_& zjsv!$9g8Ik=4)&dsv~~MyIf4bDq<4@wy%Y_sA417m+^%NTjSXh>o<>cX#1k=Ia^u1 zEH_)&DGC^6CpZvrl?bk3n^ej)gsq=P9Ukl{LQh7pG2j_oM9kU2y^73wLJb^yOo8{p z5QeL+IYSYVO?jfYs3z7kHE*-D&0V0b#BKm#cojn)rFIh19$ z?ElZ+yT-Y1*PGaJ_CKYaQAwjJviK&a*}ZCs(r~4c6q1^rHn&|Y zvZ|*KiTQPN`>Jtn*af!}- zXTs&>paki55hLs4@>RXX4OXxP=C9*jWr1baNJm@N6}3Aj7q9ea<920%(xFwGo-#-g zeKdN7I_z6SQ1LZpH;U|^F(Yd+s&{+`m@CBUg?ti1S=i%%%M93G-pP8(bhxyI&?Bt- z1o~-MM6acyXZHU&(sb?A&1WeD?00vOMKbc1<+Bu|5*m2!Kq1+BsO_fB+rH^6rMa(_ zX>E(Btz8Ba*@vjHujCthYV=^$NBt(wj1F~-(ojpmje*N}Askzh5IKe}? zJL$?^26qr|t9nNs2LTIQcKlbX*B&t9h~N+$EecvZngTjyHW);Z-bch$gwEo~_@jR| zgcU0qMoB9es$z@yCg}oUIR0#9T;o^gc((U?+e++HBjZ;Q>}?;@e;bUM z+%RM&+3B^~WxMJQHC|30(PtG`+87)j+Gq)}S%{s+=ZWy~?f?t1-~i%r8&XQmLV3r4 zxLhxMt^>&#Vq(jN73tvl1r$RL3xC%&wJIPrU^tFocB;=EFp;_z%E#Qs=Q`$Eeed3b z_q1V_%fQJSiz$`q8NG=IY?u@bOCcKd=#4`Mu1qZnG@im0OGH`))FA1$*A0IS=x{AO z-TF;lP1#I`WjJlbu5e_ZN^Qsy`60#haOCGfjs)l&rk-LhI5E-(PobLLYmGc+xvAsz zpIzCmRT8*)x!O+^Un1 ziYIh@ajXuEJUSN!Qr5Vs%OC;sIeM^zJ4P-kHC9krdHwkghoZuQIW%}K<8_2_Mvph% zeC?cm0&4y)9nrrd$Y|nYTnl6|HMBt(8=SFD^Gw;z%{@ah$$bwtnvX;gHFZ+{TX7qx)~?i}gC~&X!06oN z-Ugp5r>ETTPAe1@UzJCuzYN7kxo`}8+7WxENTD0F_mHy>(pCQc056mB7Eb)E_lG#1 z!IMDdg-O6wx=V^2@h_>(a2QMo`ze)_iwT_h=pAGHbm1*8 zl4L8$lnjZHDacuK@YEfmw8~6zh_vRO^O{5g zstVHK;WR5;?OWihCH#ywQL@x@9PJl*i5&;&If@)Jr<09Nlwnq`SoB=;$LhsO7;PJE z2Z$Dn*T0ZaF@!w4v1?VZb1Zu4_RWnq{kG2SSg4lA0xx#EaJ3TOs$!4l|ivCmvMxeG2NLPPWuELa6$*+dGEY;l-1;7r{arIMK+h`=nR<8@3nh*4FlrNr*Clj;b0Ro9xw6HaI;F|NgUwxp$OGHo_v{4gr3tE z%U9_di9UKHd!@=FO3USBIrgfteIijtGbomFavis{6XfpY?kT*FPKPr4$~P6OwIutL z$TT?=x%dY6^P?`GujoqOIglxulHX^X3i^OFgb;vLM^jA&w~y+&^C-_33SH2>H4$-) zmPbc^%`s)({1@jv8Ni;prJ4n8?WX7?q|roNmlEB2gawQZBU~dJg##&Z!|X+pI{6}( z$Sk~rGW-It1~2i;a|_&V)=lMU8T#Y5 zuZiuo$reRY&geYoi1v}!)u0Mwy}*$>r>q1?!6G2!N>tHvC7 z?wLY#r8?)Reg3Ek29mm`n?MzvBH32%GIO>gTIdFGQ~tDtjP8RcU1U9uG}L&TB6btZ zrNuB*;K4W)B28eb)FH(@RFsLMIevuV94Nx& zWF1Rlr&HFjEzxFZMh*u!rh>;iRrKW{%6{s?vWL`_D#EP64%IIZRM|EsLa^&xUK7e8 zcbbOWq&WT-LrjSMt#Xs4f?YT^=Z}WLrg=Of3Xefxg=G$?expfaTp}45L|VrCNR$7v z@H;YU$I*CQFlH=Uor>EzOm@hbLTiW9tB#FuLxSfMY|Y)7cWNmUBP-<7Z>TO2%-?_s zumfC5r?J<=>kz(~D||5uS)&5k5fmy+8yZ6b6` zGdfwJP9B+WywGDMk>cPMF%X*#j0&M;EYKYA+kUbot`Yn`@wVc?cP8F;!+mF>|2E!W z@V4t6yt5_qd2j&dKjOCds_QlzI)kUL1d#*GU46Py7)RS4W)?=@h;PG$%P58dOsU11 zbpmFWS?B3eSQ7&ixEzAiu(42$Ch`ph%U~7iz(Ps8@{R^7B6JbaJ#VnxW>RAvm9t;6 zQ{6#y{C1jfaSiMmj%iw?m(?z5+&qvC>n^+?F5}STt)RHXI!?$dxcEug`Co&|(pOU! z2U%jVOgL=hc!4X*#yp96uG9S@3dE%y$iodDOnWhs#;L zk4W)`K|44xb~51&x0_;jVna7S#ehuxVM9B;JqR(0C}f#~atC)#fB&nFYb zR8m@K>^6CA#=4D=vtK9mwS=Ht3w6t2La>3g;eth!AIl{H@%i?kYZuSHBmY40uBt91 z+M{v^&DtXl#l;24Lj?Dg;9nS*)5RMPDUIyf3w&IC1l~p?U`ITWd?-*IoH%Il974zb z1iH^FV)#JR{V?*tm?`td_526pdkm0K39Y) z+YqSDI1DwH(A@$`fTooOL9|V zAtOC3wDuT*E<8kz?F{}@llS$Q15uBq%<{|%%UdS6#rOlPD?!RDa}P)d6jES7I- zh%2>6sFcG}p#_;LK*BNr*K}}obu7H!R}>RWI21k6hr@juhv3p+c;qV597XotrXIvr zh;eZ>tNp>@9{f13^bt9B>gr~tW)cAR;tg?VuP3W?Pt3k;p-shW$B9oKKopuIF18cf}7`Y6(<&8Zeh>Zf=Ox|x;>{cup< z|2{H^r}K0~11IVo*@K&$Try?$jQxo0&(g+%fi^G-2RMo4$#5s`LC_O183{rHQIN;? zKe!;E4>#`YFQQJ;BbCFn@$AibL?*wl6)x>RXfqclKXOHm&6X)kZ`L&Xx3ks6?Mh%s78bCh5-vl*7 zW0r;o3jeazOcN5{hjHPuqBcl2B5gQ;1-HAZLR9QyG!BV7YoFgu>I~&d5h<{$#0&Vp!g*m70D1R1JgMlqya|?2>&sVrMY*9m@AAVPHM>0A;gVT>UFd-kB!bo$ z!;d)*i=$>k!JCe9V)sCoVd(ip_Z-b>3rIS;j1@e~lTWsa?2TShcABEJ{9to%*-Ln6 z^i#u7i}x%V&hSL=2@(fb5SYj&$hun}SCeiVs^VAE$PQAD&h&zufx+4_NE1)7t zjV~aSXZ#dh6s^GDYB<1s4BY7rc9(clWfP(`^NRYd7* z^-`gf8NgTzvGv?wv{yU3{3@04JO|<1J8B}>Fvyj?^@Z$8u;j+mCOi~1zZi^j_y-<2 zK3f^EiHKJDlxgp^;6)9oDrt|@bW6&Y6ImVx%0xyT-6V`y{Ls;iXNj$WiwAAyk)=RC z+Da*nyc)Erbg^VTp{exkx|Ajn2&?Sn1`0yb$jJ-MMu*cVNGIETNWM8;O&q4%i~}k2 z)AoKHbm+EjMdApqNm?EOg{UlrZB<0l#4OXfJIJC6{ipDAAkt4E;g%bA^AkZ$d;BChhl~;lQbmHTkF42pETu6$ICX!Y$;{;+3 zpmp{TL|1_(EWDmNa#(?pJs48M1q zxm;Wje`?Kk!wMms#DfB3>S+{+dFYQK4-*U+&PDj zwFZvRVM6b%$kaw5)pVJ8BQc^>04KxG4D#|xHnZ3gK0QXz3hpT}Nv9{tZlGrG5AgRU z5z42Z>gcokyqN_CjO1Y<6uuj5$s#_v^VI|O(=u7-)Ps(vRzgL~rb;;x27ipVlQ3@O zL&FGKr2nbnK3nU$|oevM>*SZs*&{?zMa-3(a%#N+h~CTR*(&Ma;8s87*c78Y|Aip zMG1o|Eq$UFGDl8j>%oD?c;eGfZKwS}QY$ukD5rPCMO1|J>F6i0A zuOi}wV_%YfGCfD0zAlRJ0#^{1W;&8v?asOzV(lI1 zxH~t5G;T_F7=t;jOSuWz{&HxE6|~2=evFe?kX#wCbT%c z{q9ejlDw~4`oUA6et$}Htlfv3Pr(NcLr$E>DT6BRF&xd}9#5IZa5R-35n0F4bE9_Z zl);1v5<}#5SLlRK386@OM+@g978p`7mvZW|@KS;I!=P1gKxU0w-4KRTt{BI_pUa76 z;bX3YL2`wRJIoCDk0>uBKZ)c)(Dc2jwit0p)pyDQ!Tu<{0PI{ynAk)E)hMV`2kkv} zA#V#3)$?~DpfX(yGKQWUn2LMXj-g-NSKhwNoZ?(Q`k5!k2iT$B?g8SBw8;Nxl1g17 z%5HQWX)Tt)mb@r-3)l~T^bT5{u&_(zf-7c^1X(eCDU3KM&RCQl5XC1+kqgI=HX940 zvMiOxs|>mJr=0sS2;~sKr|h@KCuw?WG5^HXkjoj-uXstagmf64l+$8q4#G_JIgh^` zadoe$h`Q?gCvLNrlMaL_Dn$H!D#W-=3{jUs0zJt=6$z%jQrx>lpH>(XA1gXFQzo%V z^q3-RAmwsAaXl@2k|e?cI)Q0BWfru=biA8g0QWhKV`S_ZhWit%S{1gse08Y+_!vhv2PW)_AEQ5@ zZqWq&Lg)Uh3Fb;-2!1N#U(%wy36Z%lgOT0W@9%HhSCkdyR>!BuPIs0PO zs|?jOn*Mi0JPuLw6{_sDt=g1PPYDNrFDwEam6bBmoTZhMmy5>dvrj)O|Log0bLI}8 zee@sw&DUPL``x>x-~H@o-&8Vr8&-5;MPr4(arb*D{JIv#1y}BtLo08(`q@X<{scN`6~1i{T!jFjb$2%^ z7rdEj-@Utsa+|i~DI56;Ttxr4tD6L z4(Pvm_di6@SGCC2_XqOrSM{6Hvg~61$9Mlan*Cy2#Tx%LDY3qcR$0*>-2G3`$aX-; zOcv~adiOs=4V$9Wu%>@Q3V!i^`1F{#IW&yAW%@8vS4OH(p1pR54wUwYdJ)>-Aq^`F8}1K*IAo$MF7c3Hi4w-+H}% znN_~2RY+?ZJ4m2m#ov3qKFi`?b`Xs1-LYxa=U=b?rQ8rGi#7m%`StqWX8BhnPmg{4 zFJG_!SJJ7Qmbr6U@!xs9{@=3r>ru!bEBfzVum1xU{SrJKA&z%`gI4;#yk7tRSo)oU zWKve;^*8E&@(on^#W-Y#mHm@%)R$R?<@E87B^bDszxzi0KFhxzm0QunH|mdB^ld4! zX(_t18Xvt;|7UYGG~BV(_;YX6e~&eOSvJ88eu?kx-q-)tH|l>mR4`;3SNJP$)PJ89 zzG0yabsPr%uf9?L0~UVW3fa(#{_u_Z-;s7O84Drftnlx?QU4#MofSsy{{9>Fuf56s zY%Hn%e&Nmfue0#msX}qOHpt(7vp&rlzm~4y9q_H%?3?vEtNk)8G)+or7L-=u!JG9a zD}0j`IJ|W6&YSgrPKt#evA$5%TL12w^?#ei-$;2bS>a!Lv;Ob1@K+0MGp*9^zghnS zR{9e+g-n=%R_21&|Hhm3Kaze@wG?mE|IiA5Q7@ptaohg4-mJgz7Qla-W3b`3)U(0{ z@YY-PKgAlql(zD+(m(xHy~@&WWhLNNKKWLCh2_5>7~989jiSh> z4DFI{S*j%;^B7z{7h!HGC?*OD-%gpk&+>8jEtTTJYi=E-WV!Mp`s^bqO5-B=l*L{0 zF?Gb`i=Igvr(9|g^bykpW}7zU6+N8RL)G})3*S==HYbGKE# z7GeLWz-DY%UkWlfL%tPLKq<%M%m%TttMVAj44b+wsr7 zb9l1X>o-4!jHp}H`3^oi0xFNcLl#cXyZn>C{fn=?cKOm}1ROm)>34S@A0_3RSCgs9 z+I$87SxnX-2m4VIZWyZvJJn09DYjLI{T`AzLxWF;2sqLXdYz+Z;EjHmob--Gjsczz ze4Sd7(EJ9QHUWVd`2KF^1Yqz9ra|U<2<7#@$oTn2ymS9iatFC0`$)O-5a#~KEp)Go zpfhTnamX)&#~9W&!LY$?j$qwJkld!pk*IKfn6zPAjV>@%iL)@}B$@^fvV}filp*xM zu;JG&nSN-pcarSEklVK`o_Uy{&zSibT%bx(FhA!%0L??^c<(xTV)&r|maj2585|!W2#BlWV^m$bga_ok z-VQwn!?Kl2_7(EFO}GdiimBWls!@Q4)hR(_cuBDh8p@KE8}hDiG*HrLz+0=)pe(+m zwb;(Vgx&6M>enh9e~#MaD-&0)iY`RIHu}9DoC8%r?zX2~n!vm#kis4==jb90Aze7M z>}|2Nua zhuv;GTm=p##auGGa}_p!0(0}jE^S07OKGumNrJ?)qy>z=mo05=HwMRt#Aa>SOJTp^ zaNswbuuG_6RI3pD0J4$&=Ey4B&7CK}Q*53=h?%bT2fJd|`k~phZr~tZ;m0eg%yuE4 z%!VA2T+;Oega%PX*EWwZ7Pk*XO56?yJreUizhQTT9LnTEj1*AL!@cGS$cS0=QaN8u zsBXaV;RYD?PGCTZnn$=YICpZeTJ6I@Z|^BPMQ1SU-a8TKY-M=T5niZKbRucHeLHrB z*vqz1%cGY`cU<$xFDsr-ucKAKfmklpG8=AXVN;iLC&sFzH+E>X_y8?a246T9ZsM{b zP$+sj-QCU7#!CI+y&D@VNCkQ zkC&BBpczR>7IrNSyEcIukHDUyQ=wBZUOsU~{+H+?+~`B+DR!}PR7(?fyzQ9yzbCMc z$54)@YatlNfv~*!0*OzU`>cyS@%Hg?w>5YtSKK}5^t3RP;VOLu=4ddXBxpkG=pQPE zA6^$4HT3b}b1iUf0t7!S(Q^3p>L_@^xfE>};9b2W3Y4!$Jc3Gb?tWi%Ape*n<@WX3 z-8o8>_*ECqzAxPUrztFo4!9Mp-+d&apu#5=URu8zzqDv=1F-vtcx?UMuMBx?EhIR- zuO3>lwvBI;PeyCK3zYpx$lREp1JWP)Y{Cnxr#(Lu>G9z!S+)BXj zmk|09biGyL_w@}tTkSh8i?BufetY%)>iUmRfchQ@s(G>MQvB^IgBM|}VR(d|7zHBF ziH80K6RMP?nWzbg-bs2>%sP!CVC6%E&7s5kzu6j;so*h3t`c6AAS6v6g~2h>*}&Vy zkm&s*y^`5Ep`B$|o4|p)wws~wLyicW0z)6~Q!WOD9*V7GF%&C29g17`Vlb{W3rD6T z&-{3)o|Pa_ftV=3>QrU(%Cfet_7xJkO1~8lz=J5*g(-Om@2o_@WmsAfjOQiwjS7bpjbpW zJ^)pLS78~h1=}ZhO>u;qK*1M}O9hi}l)|_G(qSWn>egWG<`ZQnFE{C}s>k zRFqYGQR`FgX-GO7PCNom&=)IW{sq76W;OFGcYhTq`73f*3={v_-9ODwvOMaL5aH#AzA(Diy53Y#}C?^GmHDq)QGhn3}-Ha_MnMA02*E}hR$KcA$ablYS z6gHC%1ox@CM5xE#v_Sp3bx7tW;e$z{76hmOL}5q-$JO?swG@bSr!bCsM^Ksu!*LHu zv10_w8hKD!K^!dx$J-2qVHUe?@Y2=^)D79XvP~P=hnq_R7kV2~3@>17h+n{<3=s<` z7u1}>>NUld?ezfupeuAD{5cW%&1d_(*TOlI-oE5BRFHo zP_rDM@G+NYgy%3?+f-H1(A3hU$fi7&Fi40wRXTfTb>rTHn|Dhe;?249Bs`forTl5< zf)+HT8gA%1>)I(ik?tNzljt=ZCM4G;Me#auchFSMQ#e;oU<*v<}R7 zNF{=yUMetDh<)jjswfb?Y~Mo7?m%&_`ZFMFG^6^94NL(+wm=czrFB)qt+fY-Fnz## zppyBybZNZ@l?qL@Aw;8-3h1Gscm(E><`bf8!B+($@pGssbRWF2i)#>8Uq>`|C0OXSfuBIX&!B$uDw+LkhLDs4+up=_a>>a~bPsX$IF~sZ$0^`OMl(nA- zf+N-{={TTF;t1@sC_aVB7~NL-7F}rxCMZW0`5V47qJ<&BR(C;hOgyPd#vnXCnMDGc zNNx}n`-n>V(RObz&PELwm)gUJ#XM1{PU;LHXmQ0-YfuLTsoZSe?fJ?r(Kz@TBLz2$~3gz;T%uxzP| zDx|&d0O}fv{c`8A%_5kHp`v;}jw1Yht0`R`>Mqt;Hd->PWe*N+c))GC?J`5_By7nHSb z0Pne7Uni5CTNtO$bk*J8;)ep85>t0JsOOCSG~)u>ws`ukg#)M#Oap`G{!(xc4Z5Hd z8jis#6p<`dn|k_K)$Si{v;kyR-nYVkbPlrqLmsT?lHG9S57TdgH$28>_`j$oW_--{ z5nf61hayS)gL66sx-`OBaxM0oyABkbs(0FZR)8CrhotPXKfgIo6fR&kIk1bQCRR?w z3w+kmjYz#1PVK~4bRHYgFa&t~LV1|aJ*`!vJ)o&D>%$0y$wK(&sr}{LNPLHMWXL^j zi{S0HKc?ZB+CcvJ#=X^B4Pa-e&em4%-?^UXm-p^HT6u^M8;$!n>MIWM#pjrFBiiA= z`EF9Se-ZB;KiBjzmv8H_xErMZfK_TDcT4zNR2uOIJ$FnAy_v{-9GB8ZU>@d!e*F1QosmZi`QAr>CD9ILt zj#0Sj*)F9N2+oRky4j-y;-NNjy+d*%`NG{jaJ=n)r=T4zhAYY;=i3RBmH+(YcpFBx zKy`ys@?mCHB0j;m=aNrlG$oIa{l*Cg;YP}Y>|FIUpu4F_XFy5_dKQMZvZI1#zLiNDe#}72LL;+^5)}cB zwG{8&xYf9~T3_90JXmWyxP5zlWy3EBWH06R)%1MF7P*9zjHzvQHkT^18n+PK@_|wt zU0I<)BHTJf7GtT;xMs4H@QO`!65-o&D98#fW!LO==2j@wUd}@{iKmu0Xv?}SFqfdn zaG41m0uXB9N1!h<1UT_PUyNcqSpMXSZ>pwZS738mLS(E{U?3-{W8$2N8QMhrYk3nF zEM0{+jsHLB1yrcfZ;=8Oz7r+plFlPm4mnIvd&`L&`F3!I2<{E;yQi-Rb!$Y)c%S?4 zmT{mE^|IIeBsbs1;~dCf`E73BKSM(N&W8a*oBWf5`K|Q__sKotK?~FCpV3y9$WNldm9WZyvma!v-Zz#q5KnPfGTbTH`H zQ);3qawr;ogzS<5ldi67nQ~Ts3x%TJ)cA|r8Y=9Roy7v+f z-7#5$w0s7bTxBDa)WGwp-_oVACEZ%jh<~;k#x02ZO;Ja9`^(8g_eKO%BmjZJ4kGgo z;LH?e!y$^m!1~i|F>w%5q%)k7u8K)%i2j_U1{aBUz^_$?0Wpwl0m+RW-U7ZNhC4xQ3hziP~&h>7|#vJxJ;0B zM_HfS>m~*?-V||Zn>oe?bGAol!2)p-`JRU?Lw>EKV&sl6U7fF9D`jTJN`*nD#_hPW zv)3({*7%+029((uft26&{CrD3B2=D-C6H5QG<68)gt2BaRjpmrG9sR4;i~{w+ z``HyK>lF$9F5V+TBpfamjzNX8<;rv{hvnb{>!I#3(fXvH2cR1uNadmzxMTVqQB++g z5j!LOq@|})#-VuxqI^o#a%En>ay74ha~z;bY;yh;&+%N~5J<6+*<>XSI`n)qxpXd8dN9dW6?7q39C+;VDA&rvqU85h2X#2mZJxZTKp3BVx zXAvd`7se68&T8p8`0${;*7u$`-uf9xu2xov zdl8GhCi2(Y(6lI7Nn2d%v~RRp^cEy5?YHJx?-*)d;Z0kN7jOW>APW6(=KO-Ob#@lH z9Xr!r5F&rZI4P%g?B_DL_@jcm$ERTGs*ug+$JD^W9p|)=DAOV?_#;Uub5JGTZ{1HEi z=a>;vC*r!~CzM88zTEf6J`K@^2`cyLD+__gz_lJ;D>TN5#!MK#vft-;5}ElG?%L=b zLk2>pehqy=y#(d0NDKT9a>A*lINwyoaOl*zrp6vmHXGvla`GNun?f&;lCXJ#yKT#w znnA&2&o_^FHyFV;HR4m}7q>QCjSQ#^a{*zM8rSzE-z+XcS?RAaV*~CQ3obwJ^PF zYCjGAjO3HGD>xKWD$b$sCm%oja`HZNb&B8y(>sL7=viAMLpys1nuY7GLBiwLO-T!1 zg>FYJlbrTM(>}qGrQbgI?E}MNn|*n@z~YC~>Zf=umz+2~#LP@>-{H< zJy^Ci7%BKQP(ZcklKmQ(ykr#I^>4lq@vrrmAsWsL1Zti&-2kFEs|ztI#Jzr@DE&Q? z?04uSH{Vs!`|{-XMOME&HCZhEHC=XQAk|ow3Bshit|CTFJw7$b=m|7_hIBt%2Popn z@94M~JqfQoc_JrUIv|(?9Y~C(Eg9DqCCiZ*Q$&v@4dpSmi=tgIg8*!L5!__I*+;A# z@9Cz3TxWd*^(~hex^wvCK<=lO%G!|vGN=US;!bdwdi^zy2b}W#whSgHou1g@B4H(v zrV3b*T|k5eV{F?5FYq+E<4B={UW6jSo-7LrE=U`imm-Z2aS~JH8}KXQC2+Gbu2Oq) zVR~_@)|_v*YCD~&c6(>B)@;?Lwiof=_WWeKGd(jux$OcBuyy=XGOId*@++Kp`6%)- zSsX2q{3L@W;y_i0$+_Gf1K7dw9-?2xJ-Of25trWa>{FtS)oPWg>5a+BrP{($ZTin- z`pgOwF}h)3dFG$%VZ17eKCtO z{Q?(fa${XmvM97mvfpkZ{3>2(YTlAE<1z~y)imZNQMjQaWyO>e zrzeO#6uADY1b^!6SKL;4^E+8)HO(7sbO)yvVD){NYV}%!<;@a8 z`))9JU*6UYH6t71o3ii_Wu#nXbQ!K)BNQJYFHC@$)PhBt8BAwDh(X-(Awn%fUPsjm zt~DiG9*S9}nHLfSn3T_YfgPo2w#O>Bi=~AJ^@iL(i z0fd8;33}B}injQEgdIAcj@s{1st4b1Lq>Gg*>lpTFg(MV5v<7&M&v9m3v9On+ zrtV2`FI01mCU@!(G)mK;M&>a|ytQ&~Wn+azafIQy0?z6l5ZpAPtr4J+>Igow`2Q3a zBb@apTXY>kmep3?519OxIO3&r58~Yjy`rPqI=&*hJ!E!)mgk{osVr>M6iO?^C0D|t zvV744V8#sUZ_!MEPc>yE#PrZB@UB6JFgV&$cit-U5`Lr`hOC&psPkeYjgo{cM29=?D; z6yHJ7zkBuHrWs$H$+PH>p{Zbs4LK793{*f5{@KWY?rn;!D46FWsS&j2rYze1my)>n ztw>@0;V&v*KYCZa-$(SL6qe3$8M0f$-&h`Mz|KQ~G7LVF`t(l%6XS3njdxVtY1&m- zf@5HVWDB%^%Qy#zO_|>p3{k5GS7O=ZN2nB#aoWxo@+%GPBtj{cWo1rI3O7u5R=78Q^#WCrxD7&8v_p|vg*OtOlli{I zB-d6#Y-B|=NFual#6|Plfro^JI;?%w=vQ82qBILW{jcbXYLt{R5{{l2Wkwi@ghZmJ|tNH@eKEy#6Ks%jz#mxtGL|6hY zR%@9Tru9LXyfhK>=up=8xkx2o7E#K)CB<)^kAxN4VxaR3H40Q{qY0nXpcp||m^~)C zjC>7EDo0^nGr2<52fZe)oJN3(W*m{7bhipz@6TQv4rV4-1j!hPyC0w-Mi3pJVCHZL zT{(itntg^nOtz3RaWKJpSZImv{?5eP&S>kMiT>MeVXJ1Wzn{CDh*r*pE z@50jndS6|D0VCbeL+&W4$#sWU3L@`9iYUHPZ7ABs+6CHm=L@iRCbEfBXf)HzC7)YmWbd)j&ho>J z2r!TfBqrXNU?e>m9ZTUwkJXPcYbg4{NFUV~r_w$=8YN_{;w>SE_=M2H(FfQ#j(9kV zyIdyj9$$3PWA#P!0D8c{x;o5Ef9D>48u-N99w2kKpOdQRAEwbnux`%&gI^sv2~X5~ zYd^NAEna#?h(gOkZi1VaVJDCSD=aLdIocWrHe)TgwmKCVg1CXs9X%6L_ssQm1GYVqL7M`Nv+Yp$K@dqR3rKHiGjaHegtrQ=>M%-oTQ%_(#1u9+FpL%AKY*DE^ZH;Y;F8FnF$jVV!+0ebqVOJD(QcR( zsoN3vFs~%}u%}4F-># z9l7e3h>gQeJ0pwrI!noYiHm-#J=j6^z$3gI5G7na zc&{h*UJEJ70NwCq8<5&n;x4rJ{T8oks7x2e zaJ!8V6VlLGXL9Xr0)7`IJc0$@i#NySHje8yPY-;@Hm!+nPLbbq35$=4MGn;^TOv9n z7e=@%^gk|PNyY>?n|EnWJGT{dkRRx%8Q6vn8BgSickVcanT0MGIeOEj;hoAU>NO-B9D2s6g1x!D&Io#4GIk9cwkVDbD4L!kT%e4CCIbPE2; z9u3cl$-(e^)p^ebC{*ffct#2$0VLvmp3Hwd0q!RXwnRoL3Ie8qm4pvbcGoy==1@k@ zDI9JWJT=y!|8{+y`P8vt3g!j4W@H5P5)CfBbr*A|U--DQUPxzN-4`;#_~|J}-~e zI9=SqxS&pA;kz9peS&tF5j_-#&kA7WU=ojLEGCOiF8scWuZ`CdAJ^(O;&X4w`6*1O zFl^#E0Yg(AO;5?4p!ASKbngy6DRrRElT2QXhV;zBTjyhM89ro?H4Xd)Qw$sqdV5cu zJBwcm|1cWo5u@UDFz@FMEbsdt@)AJa9se{$mC}vpjXVz~e{}5mqBodQhq0o9SXEnb z4t2V^P@SpN@SkdXZ@&8R!dzo+CjYQv!@_7$XBp6lxb&F#a}Fv+Msi1&f|++`cbj$(_@*b&Q+%>3#T7~ zf;A~#?`S`VJ^wSX#(lZh;2=q~CBjL?u$@NF_>;d_!7lN7lhmoV$!$QY< zAed1qjCblqM_hbnmO2LQ$8-LNT9$`SKdl%S(+U42<6KJClCF!$+|d)yt<-hDz?9@0 z<{P$rT$tQSJ=bcnQM_V&&|Z+Do1pnKmcm=B(vA#z05WY1Vs*UxIS80 z)*&JaHqCBwLDm4N#)0_|;AXPu#a&r7_1WVYv5zy(BD#z?U13K%J(!>QaQaTKaM}@7 zY?BGtG(xV&Sn$5j2F`v%`Yj~|L4Pv=DgKM>KS z_us(g``@efI_KgsB9|NkFq@uT$wy#+F_FwoB$A3^-rfwMgmDZczK(`87w0EGiLpYO zhuXsk$`xC3@x35mj0qye^uUyd+Wp zNM=kP;1-%?;iuF->_J#S)q0^A18}H@V}+4P^!gAR!c05=sD%>>l5oTac)!{2z)PzL z(D5Ps0Nc&|#?u{KgrxN7;rhnf%8h#C$2Zrruk4(VDf?E;2wYt5lw_(lKOa)ey7!~Y z-;h$M$;N^@6=yNhZO7G}nk*rmfNmc=3OXH}v!ShCvfM|h`JPF67;wU}#|nx^V#D~9 z=1>>OwCxWKldOok9~2>qz?o6lx$7d}hj6JGJUKG`!o#%(zqN96Bdf8`IF`$fx~{RG zaoQh0dARS%ey0-uWX9rPEW2M^qoNcvwBknowPoh`@x3rxMb@L-0h?fi#I!QaibfkV zr`k`vooZ8L#+<4^F#`V&uLb))%!Ju>)8H_Pvp#~B#`MHWrE&Gv)Iqw{J_4NqK4V>` zpJ9U9<~FpbqU|9?L7{^Y{+WT%QPAg6Pd^ zXrM$WGT=27U^LSRB*-YD^anF%PJ-yr?`^Vu+}&%PjpDfBj7LATgMzxn^oC!(E@`v| zLLkH4{h-rjoD6z?mfm}`dhb@_=7amUSMM~|R&Ey{dg(#iwhx}B8?M~{@#(FY+n9Yx zy4uO<$|N$fBID@d($vu0vC0Mjv9Mi*%1Q*lrUKmJ*1#Ek8(z2|L2$k8QGSkRP1B%v+~48Ui{!!r3R#qpn_gDu&cl08 zr++YH{n0DpFP%0r)Y2~9Caphsw03i4#15fFBp|Oj_k_x{eRM;Tz<|Faem6O zLsUKAx&H|0xzB65+i&hm8cqa5r+RmMCg|C-XVu+<<7%(JJ2B{Wj-G)_K}eiRBK3_%!TTJ6qH}&uUM!YyINl7CT z2pu)k>4=nuYy{#S>^yT*hr=JPVa!=HXY?5u;tV%5k~4G0hQ^`sT`b8V@n1LwUr%Nx zCzb4HfVydW7Hbs4#1}W^o#$bi9E>cVQ4sDXwTjQdIJvGqALhyRmYrB&pl;dn$yqv$ zVG`kwZ5E&1j{Px1o`ZH9;XmwXWvq>yh5uQe;_e)PLXPpUc4ihsRq3NO%$^8r!w_b0 z0_L>v^&FX246`>#kxcl!och?!lmF8>w(%zeEup{dBrN=iEkvfo+oz~fMEYl72{V%; z{y7fl1jDP$nGEqrPjU8$kWm>#hMu?o!HHfe% z`9+ifP<|$nvJQqq z&@34%b=oatZptBF`(D}U4t9E#9yAP(r{Is9MdYrUW(^)x80{9LJgr_D^9?t$8C!xV zs|e&En>Un0uS&Hlw@})xo(JGs$)m8`~OlPy%uXd3y5m=*7tRXE8J!F_gYr1Uz zj&T6V+NQZhZL2tGShxVkjNmoNSGx%6Cf<%)7RlM-@`zj1&!TArFyg?fU)JGtA#!Q`cR!#GC;tP@47V%W{YJX~dJMon#K%sY1F z+7-T8>4(Sg#P@p$xG(Y9cH0LMV2}<#@GIJtSaf(F`5bDH!7>ao0Qig9-QPbx5-pc9 zb8ZdPpxwuYD;cW?;Sj^YQP|I@1jwgaO&$&4NhBfdTw@z^2rmaWKWn1FjFWX?QCxlI z3lJ|tgn*M=HLXNcppvN54|N>1l-foSg=C~CCek5x$#P!~yW~s20ZMT0#_l0SXq;{q zxA-c9!QSvHX#b>r(m3w#6`?m_HOaU^D>czR+L<_f(w*oZ?pM%kV(nqQa_8Zl%H5R@ zDvAaxQwx=0kq0uf7RXMMH3W%b2Dr2zpJ4P}HO9ZI+x>3yV6TY?hd8!N3$;QyqdOQw zSLX-`&)|m>UgMwHmo9IDhK3UV!LI(B;V)5X1RD> z(lWOAuW=bvy?!r^#K`+t0pDW=%$61=FL`q}#3j2HO!rbwA$S)_u@ggG~+uOw)&$l&mp=acNPR zf6|Lg%4H>mNV#2r70+RJc@mrxL1J3|5;{jmk^7L2>D0n>&+7MRV^v>f2~bMTUZMI~ z8iPmI#%k+$|8QU%fX4*~D3QjBhnOGU#)JAjhf3%#r}iYw6er85sK;!7P+971d~d+PH;8zIp zrW^_O7B2I6b&;=vT-iOTQrVcY%rANgj3GNI zxp-J^K8|243D>iZw)dpwKJsoteuj;F2&v=^abPt2VNgfE5O(>sE`_TbQ^oygi^D)Av09kBaxrvAtz$}#w;DjrnrzC^zkB=rk zu8<~0oS2;rSQC*}?e&_i0f?>gt+Wzw1S_TwzKyF$ricWmyn{gQ?d97|M42^Od~OEH zvy#r%HBbEmG0#%2qvp}^K*!_Bmdow7{=xdjO1)9c&42*JH{?2_!{;8t)xhDn!KIag zDdjPFXURDWP(DAw8cyo1F5JY+_aAJm@NSy1Xm@aM1 z)`7J;Gw;}Fbs1(P<{uI47T14et#R}A9mHlJ>&Uc=xK3@@6;SB{))&o;yXA4@4-iDm z6^|0A>)~X1Wtzaa1exGa zQ#xIo2?d=J)umHzMxX?9(OhhQP~I#%YZ<|+*gx(eY~<_)^J_kJrsI^1xkdyQ%6eky zT@c>gk}|>h1m;+OVTx=uah2p6g1OKP9F9H9Bye`!I_YG3(jv=?M0wV6lM?T=gv(N7 z2vzF9e2>q8%ykYTI-otntPvq4bL9rB)D84HHw`tR+tSHxIT@PBp@f?_Fu=kl$MBFg z4JaU%xyf?*NK=qm4!}eL&q@3sODPdy`yr+?x~U=uDF|d=e6|Hu=TPJ7eeL4rk8Z53 zhlk$kfj;lRB}b{Qh8WIV9O9Q5y#!ca4`eIC`Z6+)@`(rsSeo|v@oF*QAeSh1TYNK| z$lHXUbl*LLpu{8ylN&p81a(w497+|a`$P-Sn7*)c!6)A5GgAGyT@zEiiMksM2!6w@c z2cxZtxO1PiZ45a{X{d|ei#yM>EYEIA>hFwxvt*uSOUY#VmiWD?Ma^@{KAni-V&RX6 zaJ_N8mw@d}ac+MM{Pn<=#XAs~uJ|j24Dp|l=1VDHYSGRl#t78bbul=_=MRbq@od(U zm6A3*9Nz;_VQ60$!2Q%8+M6?4V4DD_FL+tG174mm9V`g8l z0_V2d(`E1v&YY3G8}&JS9}UE^{R>IExJ#bP^U+{U@M(~i|7eLGwP99SaqA2LDlp!U zAySxQ0v-K4%o@wOQ1_DDIwceLnc)E=l?sB9RzrY&9 zl3(gYR`9g~Ykt=)6n_5#{I2gplX31^B!s>dzb&4Fdq$1`b{-baSs)C&G9|t0InlNt94Uxhi+z|yJf8do1!zDgu zVGjXUb=YEP?#^Vw8cndCi`#9fY7 zT8?1P!i(*I?!-e_s8bEaiHR)G>^l5lG`@Le&?zT)JSsU5!pE0VN8(ZfpbV>P*= zLljeaXY(X&MQI1AYZHOl!?}hs<(K^^)pU03U-U z?3i%$Zr@nFw{pv25Vgk2Hk}&MboKt~`j4`WQ`C_?H-G}$AbG_hh**O!5+8ubGz>p( z?j5&RXf+;)MGVcHsO>xf{1}!cYJP~imWm2nNTOsgLO&T4uIoL-CZxW)zP@_@PJ`Fm zKSN9Pt}eY`86xA7*ZIkYq34j%LNBol1qQ#l(dej$Sl0R!BiGH%yo4k=SNt^+(6}^e zFZNsO5AM5lDw&0CJC)u!-4H8fqlxlw=x9GwS|jt26x^lE_^Hs278d}tT9lc~P&EvV zVyu%HkhDq-#NdPh*ccVTWrh(pwQw2VyTLdwV!+ba_~7A6*g-C14EPL-7&nVY9)B-| z1yr8bZ)D^CjrxkEmrrj;fvmD{QqQT2Hw~X%iqQ3$(ybQ`$Z6{Q9K$l7DX)4Mp>`8C zcbprmZQ=+FDO9Dwe1PTQjz_ktAs9_mb_*-{ndI_Bo-xn5yzWo%_}*mLE=^_rD7`HgnV4tP*CS+6>nz@BQS%AdGi zy=`}@UvO)%52Piy8sd;47VC5vHz!w$nBXglSd(NNMpUK%PGmD;L%6efF;K~7ZEQ>a zI(Rc)@~0Vas_G$N{=`-mX(f=iRly~Wts2r7H*cfp+nJGK<_yU!mvQb*QG0{~7^c(y zRG%5JiQ=_N9~2MyDvb7WR(o!Hh4ajxHThh8)|4l4Pdr*%lR51l9~_Y5lZH9R*HmxW z!z65d8me3pg_RB(S1e|g>I1l#bZO?|HrV)ky?S~Yq0_X1o=GN)Nsf2Yl(U|hot>Nl zZ(W(3YcEu07Min_=2UIAGPONZo1fX9o~zAlXEij@lo)^8-X7?-GlDnF(#BF$F8IpOFG)ZxeciZ0mMYo^;(aqLyv#SeJ{Aa4*^c5Uf*JOHfrdD)d*(6#k!Kbr}Q`0k5 zc2ax3L!KSlP<+~+TbylnI<3m|;(VtvgVnAqPEJi#AWfQ@o1SX}gDe)U>c3Gp_jD z)YQUab-uPZJv~!IS_)QNn=H=H)@nmHDZAox)3cM4RRj{4nVp-@t{zU<3qmVy7{8Y8;>f$uW+thdz(Ko5hOx0=yN4EgMu+8jjb#@Nty|7K@xaUKyJs%aNLrS}KmcuR* zUC2~VJ?h4~2F1$qCs!!w9t<-)aW4pMIPtbrE{Xso1r+P@|L`7q^l0_gAn!M1@QjBp zORK`CwRY&9J7!ZN)%CTSe=(Uq!<5&iA$I^4saryz_lN`@&cL_0ESQ zFD)O}ZTK^~aROk*B!O~dU#ur@0$9bVkUj_Gl zD0TZnuKSrd3f#oG8CYyg120V$5uQAKb4_MvNv_7e@N*!eiwkozU?~dPoO6fuRB{0k!cSe>4knX1+n7N*C3b4UxIOd#j%I@l}45ptYPeG!9^s8#1?@iZ>N z$(iNO$K_1TWcVuuLeU{+CURE_r0kh@jp2(I=LqK!6vS9gtpz8BfeNmCDR8TJlgPXc zLl!mAqEu~%>WI_|J7IxuAstxmYt%OFnab1kZ>fQWRm=vlZ1=Eyl|JOaY(YvNQ+as2 z!H0QS#Y>I=442tCYUcM?VNvjvh9Pj_D-2;#I09PPNyiEsP)ZOQz}KYJg_{JTM!4GS z>IXJl2k8eUQPve6$%85}mf@!b;i;}{X?YDrQcL;(nd0U_)z;LdZIWV%Eow^+69hP3 zUoTya6l?_Jh{&?+%{U89fVt%+DD1C;1`!^QUf5ce^Jk>~hg^V{-4_G_Qh_7;r<*+g z&4d9;ublRn(97O7%PC21m?lo=O8S9AK9}t1a_rI^>u`ouI}nC7@T)gv1~9B} z=)s0#hlnomFd1P2umOx!V8h&Hj*edc#PP5h_x8fs1P0W)6FVd7wGeSaOj7I!IO>Y4 z49$RgU5b$3?IjIeBBnEG+Ih933bvF=vj9{~T?T{B@!pwaS_%#{p4KX9PM{=fj_2Ow zG({;3tx9vJ1BuEG1h3nz=~|^TH?_Du-&~wo=*-4Cp-*L~&e8?b9zoDw0(x#MdJYtv z!XRnPo4I}3*AQbBr-*+JM4U=p;D@uBR)T!!tS>f$G9)QE`F2E^&N67t#GA8_>7l_Lp=m}ot=rNWk{ZaoF-0YE61!Ov{eCB$Pk6$j5$GN*zz^C z(9%~N&_1hJwD^qYL|%#6S?q85kcWv5Id4Ond@wf6 zM7Pu1+v`1J1$J$KeL&76xt2g8pw1QCqDa!*lK_UW0raT&8lR#tPDFj{f^bOy_4_dr zMABvuaiwUnW2qou43GB^Z!UbpRIJ6cY<2uq|uRp5B|8v%4qVohLYQ zeHTcRz(_4&Kd+Dws%EFTcNN zIg`zTJdT%$o*HzLWiCohJ1h-KDLIOq<_@l|`$*9&IhBhmaPfh)1`bA+)d7d%s$ka$ zWFuy zC%5NY3zHQnT3|HQoSKF;#OzdMuC_hDxHvz(xYJ(9j63~u#AdlGkgex0f6;D4xodeO zZZNEK6DJKw#~ZAfuUH0d!n~TPsm2rkl1Ug++>8)76E^Vok#cF}2x95Cn!oA zB5o*VZ1f?U^M{d9=Q!E3baw&L4W95cLzNl8wQC&b2vao|((UYAkZXAwCltSqhciMB zS}`-!lw7k$h+Ne`ZYfi7596%oo~v!c3~bSwIn6Z_qFl$BxavxN-3weK{TA2D2N@&b z24S>2$#r&&mF8F^Ux7GweFS6K(IDRf22@zWUOMJRX>FG0IP4uBgZ_X8kZ3Vc5I%}W zU7&bjBK*^Q1FXkB@-(Z*C(fot;7oaZB0h4nA6z~eZBe`T4$#1!Kg&1zlV(kjTXyAN~K{njwUREiiFkg-qAo!2P(Y{*5uy7oS z+%B@%%cai+%EDH*S3gleH9s82;l(_nV4qsI_(?mm{ejvxT`@;*EMw}uyk{teh!us`u2 z-zC;`JZg|0^ti;}dcxD8nkjo($=Pv4BO(u;8c1YgMwb*K5kHUN+RYTaR~fyBK6Dpo+068SI#K9FNP6$Ck&Wd6@m)zOeG1 zkJc;@X}N^daN-KXn?B2sv{X?E!Bcp__|we#|V=F)gzv8 zdq|(9ac_JjNPjr;-k{39sumR|^lo;bMD6@J%XTZP?jlLuMnJA$2lifM-?nd2rKD5M z>w-)nFqIZu134%&Ny@T_nOH(QF+YBrByY2}7i@5R(1q!-uM{BIV#4ITR4L)Vp~P3d zoc!b`KY@bteW_#pK~suKo=Hmz0zDOJ4SX}Gm9Xwcb71R7lofdC*#*t&beX#`81G-RIv z9CwcUeTcJgE~)8z+C&^eKpDY#+ekOx9dv)%UcTFXFXy|a@nf*~?8wqg@_2Y&935y( zKNXL2Pvw)E(b+aqc)?t6Cel%rJF8lfO33SXAti#_e603HoV^Wn#jzP2Nk9e@X_1Pg zLi{;{a0+;8Nxl1Cut`>2Vo9$=ly1=UXhF;@PPDRw znSzbp**+l0IU{Nw!y2NGET`5(q4QmBYH4VQ&Y+6{o4=xVlE|X7Mx|{F=a$c zw6K8m680HphoRq-a&2Z3X3x`$vr{uOh}jS<3z8%PKb-~dU~%vvQ>X?ZuptvKc@T@W z+z2lM1m-5|2WyMId!J?c%@2LA-4vskz3w*KNl>i>af>F7_74$dR6pK2Ia#>#QGP13 z*K4ygxz#vj9Bee3Yh>HOB?Kzz9TZI9VjJFRAGB$OBYW08LJGc4zR#J(>oarn*}_z`yOE?0|8UE+|}HEckpH>ug@>!4&DtAkl{dJ z3-lBhu#J4muuRGwfMSqtY~#;S;N%XH-O5|^b~@XY{n7{tQpN+s$e{hj!8%z8vRSH4 zPR*1Mu!Z}Yi`U6_LgX2C7Di}%g8?(8`nhnakX76pu3cm*UKd;H`Q8&_%7S5YCp@kY zLD0^V_E8m<#X{Lhe4lpVRp~tQ;7P%Orw)(p^;$}m2;w@1Dv?JEu^ETz+hmc{GzC}t z2wM3S+S0!0!}fd4-+xVhKKt~u^3T2vZwGIVq^Vp!`{>#qz4qGOwY&Y_{VZEf69y|k zy8C~l{8!WMHFx~Ls{Et+pM4#5emPwSZl_va-+I0N=UL%b(iPN0!Rq{l*Xw_Ub$%^f zhn)BTOkCTl{X4JM|A^K8sdP03)yUTVTd&vuC)Uo)9{iBauKqv2UjN1$sF4{vIC1On zn{U)7Ss??W)$Mew#?%}2e}y$Nv+MNR?Vq|~|K1z*|Ce?CM0VJRgWld#SL?Mm>;L?l zsP!$>av5SJ!;kg!vp4I1HCGHP-qk3TmYe!C!x?{@=6WH&M~T&&Tus zAKt1jd?iyH4QA;p_1|GJm(O^6jVESv8hoYx2ibC}@a-7a|L`mIzn3i+?^bL7-+ZP1 z)>i@lI}v>6t7uie`qlasR^f4SL(niNR^jSb>o>9$lpD?=UIhk-a#;Rxz$+wTKy4g z#C-r;x|MwYYxUn@al8}q+O_6`uhsvh>=@8oUY1tnU;bMC4^ZWp$ZHt#`Q(k)UdvuP zw-i!#DwdF1LocP27GC_Kp528nYNhL6RHAoIN-{V|?oUyHAg3Z&ir1uMI2!d3-Ojqx zl`BXsWzmV27R9$giVC)0zQ?B~TA3J9I1RZLdd_lvhcle(+b*$uFFez^7Q#n-_K|## zXYQ_Qu7TkZ`5t4hXnOJIXxE1zYu|%Ms}ZOI0wMKBAy}zUg!Lo1Ma9ujhhllcKK|J+ z9iB+SRQTF=t4}9CJNhj1srFgo$Vqw#Zg!yY)jShcY|$WXg$+3?8zt^#P*{;Q)pWk)k9Axr(u# zz($hNBWqba^Dsg03i7yz5GWEQ8S@i=c;xhe6as$k*U=LeBYA&y<3|r3Z6r7De*ov= zwY3}fH$M2GC`TaCOxjQJFy*AWusiQ!mRME9s6S!?767QPtRX4-{f!&%t=?PR_&_Z5 zRyXditgk1xAFLq=)WaKV8>=@T-Mg`tJbbiJ&KN-nYd5|*upEH*$$yO4ui z!oPTb+Fy)#a}NdWez}xRBa8rjmqc6D*=r7-aP0|%=~r-Auj4EOT@8*3s+b@ZUdx9( zoVaBM2rn?02Ui8nIe6&4aeT-`+5`#nU;mfld;h0mdHYj)HF&spPrJA^@KCpj;*ycg z)2{-ToTdLn<2a<F}eohP&nw?G{!iQ z^PL-T^r@h}g_XC-3Ch>d`T4r)lIpj1i)I1nyI|3e}lt@bKOPWQq_M{nPqN$uRPj z<+z4Nq+bkVJ2`|5^l1G__b}fobtvTzi{#^C+AB%Dt_ra9AK1Ru@m|{>Rnd`2s(JVA zl>StyhPQ0K9uDb8h+*Q-Ht!2f>l^wO!r_&_j@*aSA%I_tA>9EtF$?gK25IJXUxQi|cE14%!4{e$W zt6H0I-NY;6W>di`ypuJVNEr_|q1n--R$%2*0UXlZ!toX+X%93Mqw2Cu6m7$zR*Hcf zNiJb74pIWynH&%>E9yA9m+bEKwzoyxZ=$y2LlQ1}dq{2w0Pq^7)&2eBqvkez*;I?; z=C53eOXUV{?h~X~-7jfIH|L{r1j|WSXizZ+RR*ZPTRaNVk_ZI29&>ByG~p#*P1XgR zt5435S~f66Dz1XIkm0mQMOuESh03tBGh}Ia5DObxk$+#O-Rkw51tl(uquPW-ta1D|D=7=IPUKi#nIqel}Lxd=1joRcjE9#ccOo|UqQ2pwTJb}oriZS zcUL|@cz6!9GPO`KH_u2lr(1rhQgFRSoUxLGpA``0}kS zF5}jgU65zM`QYzc-t-D?^yMa5W-ySf=?gfTt4MtTNVUX6v1_2x?;gH)TYydP310;$ z;Gp*`-3vKtY@2sjg-T00GqpJTg8vGlfsJc4rMCuof=NybVB>S<-DuuME`Z84E^7h%`C7$MhM>Bx}2jCpGi)2-%=ngV?jEHA9S5F{Q94 z41QUGbO2y;UtLaSpBHiJt+69II4W~!A1h3fP7#ln|-R<+U`~5ELFRB4L2-J zO_|vhxa>Aw?9(TDgN!Hl;coQqJN^yzvMe2fJP{A#?pr^tiEHwkZ7j#9y>O6WB2o6* z=Ufy{3j;cB-WYIMyN%0Gv)v1N)UWU0AOyxEn)bBY%)MxGFqhoMb&uCNxHDBv^|4gH#ZiuO*Nw#Zy_?PwR<9rYm z`m+9Gncrl;Q{jMY^d1D{N;~brvY&Yx3T?_pbJKXj0NH`2J?^yz%bO*>SW8fsN+z*9 zSB&aWR)HHxNh--oy-%`^Ls(BGJ+cTNgD2*0z%D^=b}FT9o+(BzfemISW!zJR2kDu+ zvAn#XjmfjekZGCDi@o><5O<&@zHOjZC=h)_h)BMHv$3@$yoRTV5rc(qK(GBSo^MP^ z=B&IB3LOR@MhJV{Y%S+0fd3^JX~Ojh&TQ{RSnO#v`8NXfv2w0qAY@R;B%u&pgDN+Z zM{DL9)|^DO!h_g|S}yyrE#iMHmF0M99yHEF)4NcPfMKE)vLjS+1G$fwOn3 zMKK;GE=)e9sC*Wv4E1K{C%JKqQ`_%Cc!|2$iR7`^^9c4S8ap;OGj=e<2^eY}unhy_ z4kl@47Z?GS;cRWC4vG!i1eu2*e}bF3SaU0)oReZ}NUf3Kj)6byO6Y~b0q04=Bv7X4 z(;+ipg6)%}1(>k&N_agDq#Z%r6(>e^r_x=*Rg)3-z=A)+I_ZAFDE?`;cg)m4aMCwm zW4wv*wy^jq*xlZKMSH2#a?G@k|8i3*BDL?%6WIDfgic(QTrOylVZQO_1PyB^j(QWM zE_&=I@;$}Oz1^LBC4X?i-xoc-PJNq|qRj@3d?Xz#jobpf8{(m(Sp}yn4hBnv{-Lco zfB(7T{~bqdZtt5{V5iAMC$-GpUaW>98|l?PxgL^58b zVXRqjrKq8A^Z&PZEx&Od$=$Yc+GHO|kSv0|%#MNOP^%fv`@yxe;Yzg3NF)`Ciem@@ zcOKtRTvHrjW@uS!7&!%d@lgnJ2=Y$^xdpif$)6JB66CbVCBLfb>aV-M{)RJ@WNRG> zu%-F>U0q#WRb3CQNDLs|jin)6>JzzI4d($R*yCgEt(i$IS`L@d~G|*oAd?>DNS6>4s0N9F$DjN<1;ZDtZqVcA9He4j_JOO#5j;uS- z0Vu{T3fN!T+dteUno24&fcIo}wgx8ibG&>FPslpm-qJ*3=>kDw+ydY(s7B{=B|(Tt z6+-$?1HRuV*$<9xet5h1D4Wnzn;DsehNV9s?5=XzGfT4xd`W}?yUU0y8>zpHHXGA1 z2j|s=O7h<`ASyqZkyrJ0pF)ynX(1o%m4jOl7j?DcKN{9!$0Q z|39GW$^lg$hX|_>Xi=_)qhq|*JtfHB-{0N-#r~~NGTVdNVC$#kl-C~)VdOHmxVOJ| zb9+&JA_s^Gn@nkd!~MIrVwEXsDn~p*o!xkM=L7M@09rs(%$iKGV|CdF@dw4n{)`JMEs~@+=S3J@J;$I?8 z#Soe`iC9}wN?}b7HND}P&XhiKTec1|-e~DH!MU-yNbVn8nIu4p z2Q>`|LEH33>k_e=-|)GmP)fODqz%2d^LXIxm;pBaZk&K4!7HTc4LSgjW+gO4&5vQ{ zbH*$n&u0dHou2-wnxT{!9zHap-{HH9L;VqABeJ<<*-f=MMuG(~M{q3|b1fzX)RV!V zq&-IF?Lo8L8+L2RN!vjV8+$x9jZCK5`JOgZgI-Lkxo$SfToqu7m-c2HehtsT zie(Y^7D#cT-$Y%LeM-bNoqjq_obimOLG!J3RAkvT4$Q=^FdG?2U?d&d!zr{Ob0w?Yp$6O5eI4-vl3X4X0?}z8`Ck0TM={yXl`$+gGUI>f; z@irSQfH)q~%cmVkH77W};W8oB8_t4}IhYW)@+M;XNhe^2;BeOAG%kQ+);3GGkih76 zyaEv2X70@0@5sT%s|5h%dC=}8+wqtuLVr6VFNIO$2n@<}MLTD#Qzd2iv_Hh78SWp% zKZmM-^ksw(IwRV*bZ8R+05366Co=Hyx0?Sjf;k}pq7zaLhFxQdtq;yV#S8LT+96+t zni9qz#+hMy8At#+IA*6i?U5j&j431PZin0y#Yd2RZ9D7@D9FNH=$}AeMV5exu<5|C`nbN7;dO|&wAPx=xl3oM^Kf;5wiyc=yczK&>X1(E zKb^3$foRAEnflw)8u*Hcbp6-tVt8==Nt}AB2BBg6Gpz&boL+j`nO%8U)I~V!H4dD2 zlIPnIk2;>F*lpNc63isJHjx%@$7@RBQ+NI^j1uF=YlgH^ml<5tMFZNzVY>#gmjSpB zXF^x2m|}W}uo*yGJ81f-l}Pk|I_gdZ08S0HO!EkaPx~j3eqHax(s=EVR2IcATpIT! z#ty8%NLgklQ~W~z$r$iu@yBcaaxwPY;Wjc?SOo3<4`Sor@Ln0?_a)de(%(|9pGr@b3Q2JH-VtV$HdY z-vQT@HZtBocu{6;DHS3iuDzd(r8S8@jJ*QX6oxd9W#Fg^^xR86&^ns+MX1$EqdnNU zd+SJzyBFv;Y0ZYZJ6B7(OevF%X47O9bBu*^$)Ye#+_e_*iM6ky6r4q|GUBRCbZ$k20_UYe|B`f z2l8w~lA#ejohMNuk`Nxx=-HGTW-M_{w=!C)@XYO1}!Bwv5lZjAzrz=j&P- zIT-Ot#Yyi7jQ(w8IjXkX)e1#Xsz%buYkOD70TNoUf;*aG){%(@Em=t1ES#O6!e3C! z!oRI9pE)|h_P9bnZI^QDF)egj56J7OZYdV}f=N?Dc+#bM<7Mh+Ro)VdYu#RVG#-_E{b8@% zOzQRWU{D)Ts?PeTTC4YxwwEY59nq&?^gWc9{Tgnml&A(Z;8XbaUM8=+n5-_~Q8Wrf zmQB%;IH#h1I$BFP?p*dnD@HjK<4YUZd218fHilkB?Zu7H`cn!+xWO*y`mQ*I9p&u& zbUxcy230l?df?N_XO9qjJI6E*Uu#=RWS+-VSX0s=9~-2 zc)KiO9S|-T7fVLJAyK0)U>mrtz1T$=qp5&XD+1|i6_&y8_hlFcSzT5&5wlMb-9&fT zZ9nqwOxV`Ezn7k3U*W$gP z{h&Wantdyi3OF+Vhg1z+0UIc-a$|(nTdTBvd)s^iw+$1_Rqh%?x-PzHjM$#q3t#_Y zjb0&UX_9;2J5Y7v(omwZ&td^KxEHedq5lwDgF??3ldj_Wqs-N2u2623iKLNL;FFLH zb6l>Tcg6WreE4%K%3S}z{*x70H+~{juYaHq3G(~KPv~(f{Yt-XWa7@V+^k|Y8Br&2 zEK!4UbQlf7!4rq0Ag_QbQ>YELaua=ok@MVc$xYkLFJsfT@Et&QB75ED%8K8}ZEMWT zVmDUwzHK*~m3jkgK{Y1EMekc~(rS_LmvcpD@7p$n(q6aSgn%Atleup%EuVk=uP>|0 z=Z$8wUa57vjit5d+yWd6c%umHXo~`PH`)-(Yn67Z(XPi>q5#})_3m%=?g3BqR-%p& zP=(POrFVy2L{7vM;Q`2~XphnqSdtoO>dl=UH`u+Taipe|<}odkz(!mU58)w?m?|^z z&$FfAZ)l!k7a^01HjpB(wz3<zFrf@!fh9I8nTuhO4 z6y$ImotF^dW<4;dQ%3GG86FTAMNcsOjs4Z$GDk$~#ZB4v?(FS?THD3)Kxr@m>>Y8KB`g>JF38+ zH>>A#W|k^DZzpquil(=$ah8FHc$x}mQI}mShz7uBjHES#TSh6ulHho93gSQ&XlT>1 zmykr$22FVhuck%sXm9L5569~NV;5*8z+7V4WJs9%zX<-19>Wldkn=X69qS)h!R z-3PTsn)Zvrx}=9oe2z5@1pHdn(%*JrU5IEno6X3Z+LI^n0F$0dWQ1|L&Thq63Kbyz z%46&I>i6&TLQ^n(>}~(m!4}EFPCzmgBe7X>Hl!dsygJZY0RZJ`gXLTRF8XSWo}+%% zx-3Ktf>kYSg=g@NM+C4+O5(11x1pIFB$fWD(vNh{bPk1*ic{nfBW9t7?pc4-g+jUj zjb5rd)lN5Q)ocA$b5N@%{iIPFHpZiB9cFLUQNPo#!WgLE4BwWPaq< zee{Q?@d_pwCe^7mE6HgmUd@q#>y>(?l`-y97eN6E{Xb=>=vN3Pd0`ngs)Np`3m3(D z16F+fdIP2bt$Mj#8+3ZTPNO$Wy1|4pc6oXP!g}`b$9BU;kQ9{IqR2;mU>b8| zAuub#p7hB&FzB~XxCjFlJ$1x38ryhD+q=uz-TChu7e34{vqu*_%&+z+znt0LN+x@& znCnHn(=RgBTmDJpvZ?~x&Rogj)PBJm3LI`SuIm>yS;j0cILvgu=?~`EpPw@!m%Au) zbWASP!Io@+=jfvZ<(o(oJL z49VV5FBs@cG+{2DrijHL{w|eCVv#Ash?b_6jo6}nZ`k)9>hA`I%0{{TbB+zi?tin= z!;8scMY@h?;iox{r>WRVc%OHi}>EwK5eeLum zj2+T7ZbS&tVAZKqbO=VDqwqj9|2Blk@j1zyz%=$gWZo<6qLrs{?K?693f10 z!AfciWr0^Tadq8_aa~}-IU?8+VPEWh7n%)3gTC0>-t8C-`QmW`k$^9;JM%CS?!{+6 z;=x`VwjdJf1@Q(K1bT6AxyTS&zz-Ez`3+drA3O1ks zCM|Obq72Yn>5u1l=~UM5j?NoPvm}QU%i$WSyUPY2Fr>_%024P~L{!RwimxM9KvsY3 z45)C_PX;uL-TDIrzKk>fOJFZ;iH8_^+|0WU@e0d4PG~c#zy8p&8vF>9Zjj;(HixMA zs|zham>0$cU<@t!S)9JB5;tLQ?4}l2bG{KD2K2E+a zDL}}2N={Fy^l*!l8971H$fF$Y8i*4%8Ju&(a`Qys~N+< zK#`s!wL`-x7npGkxKMRIfI(q5>5j|QaUX7`-DFtqHF^kA&>GfzwQdVx3!3?=bE_n{ zz~6nbx;&!Iej96*u6g>iSOm|!S}mjEw&rewcB3cM-c-szPG)pn=c9(G5K zZqgXQ0mqN+>Wln5Kg6}6zriHusj?lyo4r`#H0<>mulZL9PYnVCNz_7h7Th6umq2B9 z4rBJ|^U`9L@C~>Q3`-bMGn;Dw`Is+Y26Jx#G<_YH0J>d#2iTyuYconGy@2FrX877D zJ|r1Zn=W;}d@%#MKS~Ht{Gf2}?$#%ThipDVIdmQsZs1kdJ&ke}FV=B6H*e%cDbNsn zLn^Md%q?_9?kH^^XxWT~B)CQHNailexc|^ss9(2&6Hg48Ekw zkyzf$I!QQk$c7s*SR$)hmHfjPW01mO7CD=*_GB@IM*Rtvz+(lk&x_ck2$OWMfA?7S*u-xy$8N1d+w4P?W z(;E*v?&Q8r6kF8MtZU^{K*s-({86+EsY(sirJcA6qy)C&xe)8&oQ;_=_zry#$WFb`izTi|zPrqBh=17T{m{D1Unntv+MS(ugRA zbF?M#m?#mw8Jwu4t$mZ7f##hJPtQljw*F+wL=_rym^(jbHVIXb6An41z|bf`mi#NT z{%81xY0xVw@=_fnV@lG=Sy8x~U*eE?Z*<7petyP@jSQo8^=d?IXBT$K(`MVplyVZR zF>4tOe#ESrM6<1kF$`UE`Z^u6t>$uLuN4`YiqU}=;n7(8W>_Ps8(R3vS64k_zJ#0= z^Hy`t7*!@T$eE2dmmHH|2PQW;tx#bn78ZskQUuBjlgE?OkywT1tO`u-aq>9Yry%Su-A_@f{XNBVVEq7IEu1;u?PMobHjXp2ks7l|HDwhH}@F2mEvod($rgm4lN zwBf@P=PA26+eDy@&-~&ZjM`5-@)t^L^n>GXUbw1YgD^?*tJD4&bnctIz*2T5u7Z@; zRPA7P-To_IB)3&Ii2QlXj!NGqFt@FFL^T~EeIGyVtSwC~P)c;Aro1pXoPeIf@n?|~ zY)9ew#3<&)0<88yhcXt-RxyCepFA(4I@`_oWM@UeHdp&^jp*K*+&RK6aE7mFSid^y zvCU3M@RT%THEy2@d@p64{R-^W6vu^1sEo?QjT6f_iHqT;GVyIdKgF)pY)&_B{nL2)Sq7~ z?3@iN-=SKENa0Sm-|@8nge+yo(*y~cCgb_D{xtbn;rZm8qQgK|hvo&bHU{TnvufTd zk!TjV+tCfoSkDm~LbBFFOnid;?_&-QaeMDU;dX*_(+Jsc?|g8I?2LC$h6!^166^Jp zzRZwIn6kOQ&ka7L8QeEBD13F*lCJ)nj>x5Cyh)JV7id(cI5PsKJvk1mN*G60*FHNJsO+$2*4~?LRmy zZ0&tg_;~B!U~BL2lb@mP{P6^(36duBqE6sNe}Yv4s>tU#e~zi6gWc_en;)UY)-QJM z?i_x?;VO0x_qOlfFMPOvfQXd$whj(=Za%oXbx^qX-~a;scBN3b5BOkqXuklqq=|Sk znI;&laEAz*gMT$I_*baLF z5yzbrKA@<=n;RR?o;|A^pPg4G(__TB=Y5}T+@RS2B$Mg9Fu}72TR^+`jCq|rMXUi+ zM}8tg;VHjlU!!@W{D|5e%_mPzuK}~^%ZI43O-4_Cm$T=y^ZCiC?eABUlQXhb#L%3! z%pM<}@LDZ9)rMoft=SBNp6!%z;CYOs3C)bHHfM+$x;pCZsYP zFzR}0f)`6`0OY!jy( z8XlUdXv59aFnzleSfvA~>2#(vpG^c=naTpx=7(l@#9fgB@9Bi!VD+uOw9Y@N*chg% zsG|U9;BtF#_I7Yc1TuHXKf#6o>LYJQ?B+X)MNIAh^?=2K2C^ZvRno1y&~I`-6bTr4 zY5uY^^e;Vng4xcd$_M7(WjjdcvFYusg`;rL0m4`iuM4Xm3~n+kYXfI|gRvx7@wnbI;25LhPB<%R z!)t}L>A=aMDg&dInSrHHrE!H(dA%}9hDgs|Dn2;;u-pxDuQruCGl%O+z9+; zo-$76*gTt_%#-N3Nh#XLR0n6q%-N6zyNhqiL6I|(PLh|Vge;vc!9hHrW9VxV^Iv2oQfTGJ)B+#hZuS6~#G0=nxH`0SzmylQ;W-MlUJ3qYhJ|xcXrA0)rOxaKF+(6m)(=x_1Q@C~KFH!h| sw9pkp?;PG48X+`NL!>09CC!FEX67LRQd-r_Km?>5X=wi9{CrUPKLGhZjQ{`u literal 0 HcmV?d00001 diff --git a/f32-branch/.doctrees/index.doctree b/f32-branch/.doctrees/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..f4b945c9e48de9b4b4c1831edef22d2cfb1a8256 GIT binary patch literal 8310 zcmds6+ix6K8FwzetS@WFjjJe4$^-H?*qw+T|d4aL5WxNbwd#=_sLcs#9WjpLy%?y|! zn58v$CPSaw?sntV$Tl}aVFW_Mz;TUpVru3UM3Y4VF+q?v}R z8J6J-O>jF@EH$X%J4`TVM-!g51BErm-n8BJvsyC}nk}@Ddy!*lhR_@aT_#P>6^8AC z2h#%26WWIGOc5})p;>moOkv+;OEDk66T{5opJUtPl>aN+z8))x`6wTgW4-}UMa-w7 zrXeQ{Ap#qYLr_o<9J8$ufCFvE2tyF@d(<_$$*&13@{5IVx=7u+oq`_cC)3C5+-j1?a`FH$=}RV9yORvvA!N7_bbV z@h9OZehSfY8vkeT|1|!!J8{IH;SEf>Ojh#q`~tstYg`#ngU^k2VEDYOXYC^hOh6H? zW%`sTh1?gx@`Hoqejt@cURLsz+zCn+FLJGt*u-;kHc7`N!?MyXVLZ)>eRB^qm@mjt zg&E=nb_BMHlErnRiolES$M~rrRzFWTNVG1qY@?yJ1uszKdJ+UmRfLVAO=oWn)3Ft0 zyt}y>+F`=9?gyR~nWABLjW&dmpz$t9j(TBo+ICGRvKVbb6rYRS;3j9h&27HPyWC@P zqHAnh%ojYqbp+v#O@< z4h$DA53|@Fc6t%`-+(@{>cFbEDB<=>33o~b{!}w^a7gHmjm;!G;R+*0WQ|62Td;0v zSf1YaIJ2-NY1gi3H(J-OG@8nY<(nINV#dwPdj5lK|EXaML@c=2`AUM+FrSmPoMD_B zRwhFGpB`qSJg#=n@)9`)iBVw3a;l`F+I@Zuc0W=M7{dYEW@X!Dz1O6~plmObwU)BH zaqUVef>I*f0b;t#<>L996z#u|leq(s4@VLWiipjkFuK_LG3oUJ zV59?oBSWDC*a}&1m%C3 zDUbk?Pr7*!AS?Xuwj-c^9`-zpR!Yd931f`RWGX5jEBT)hqyu3kSFh0fHGk&y}z zIjw}n)$4t*0Ff_r=D^`FZL4t5DuSa>D}$pmqgYiCDdru72sjp-Y?dO5SVg3xkp#+; z1e8?baJZa-v9$rlJ_a30yfpMuwQ`Z? z2V3X+P@4iI3x=xvYB1~@hv`2YV0uq5>}T*m&Q@&9!{H6ZxfBlb`~A@`AYMrCyIG=? z5?uwvJ|+6({Le^sDIgMEh6{-Iz$>p0@Jj!HIGDd2OYW($JaSn%=(Y6fO*bQTt1Tbm z@0O}}cXWl0R$7tnk7PmhJAkg#hkOUjf6}#VlZBe$ zTADDL^u?8iU%#RJ8r=CCya}iNbqJ^8mf!g^O)tKz-wUn2o!zCfazJr2oL$4UbZw)} zT=j*zQOU2)KZzS9$!$69Gg#oZ^=&LEUE+&5BXZ1kRYjt>;>(GQcV=xt$ZdpP3!Rap zh`LJMU{M}d(&VvFSonO#vq92X<@=`dpTtT39^fQ(D@S<5{1p`PSj+OdD0#)5X~>r2 zAc!3wrI}+SLr&qzwtdGoZGrDw8s0JjH{MlC(=UgTeF%!qBhn+OX*>g)9uCll;wZc3 z)BJx7F&{Vm&buTg2f6pMpF)c7{Qi(OU@Jk|`4^aEk%L^6hku5*^A7iLv3I}hJ34^X6x8O?v+5c3CNR!`C}WJX}} zjeV!wOwX{wq8B|2Iw(wg&>KtmW!Pn}y~x>p)L(oov!R091>n#e zphg)tn*YiW^ZVj<@Ilr29g?T>dpt;3c1lrVXS;IGK{byAr6Zw%BcYKV3B{q5jg}9L z{IDke)dL7y{lTi`7A{=7*Uf)=kHEi}QFa&Crc(KsaKntVm<7FxlgHn^biPy>WH3}TO&7j(+ zQ=ObfA#Rk)q&u;kZ=nz2dV-Y(QHGqMLN|(w`ZiALE)^#0AZDxok3 zrBqP#En9FstJXtex*#pz!}x&tUVu^RTOyF4GI2&JRL0-%$mc=?S)J) zuT)WD3jMAf+DVAc>XseST?~e#T8?K4!7s>Z7!x7|ROuE>XVPhURxp=!pZPl76I5xF zbip;rN4P>X#kSPA5PrC}yu7uwwdC&z?zu}|&|bFK-DS)Smt(m=D~Kbl&{1oJmxXE& zF~4zsb($qNweVmBN??rx} z-|PI5j*fTm;BWI^^GEz)=Q2?)(&J0?_yRp7J@)AF7Cqji$9It3o!96zlQrT>cUaY? zcG7o)Kgjl!fIeEOQsV6JM ze0HseV=a@a7R~qYSIu=gJQk|F(h=Mfu|4I}>gY})tI^{PRW}W)&F8yN4|yslt00=R PXk$$G5W2NT&87bV<-5#H literal 0 HcmV?d00001 diff --git a/f32-branch/.doctrees/intro.doctree b/f32-branch/.doctrees/intro.doctree new file mode 100644 index 0000000000000000000000000000000000000000..ec1909d39d1fbebf86804ae67022337a4c06d3d8 GIT binary patch literal 9092 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 VlOwWSEVOx%fGVugZEN1`{0AE-2F(Bf literal 0 HcmV?d00001 diff --git a/f32-branch/.doctrees/lifted.doctree b/f32-branch/.doctrees/lifted.doctree new file mode 100644 index 0000000000000000000000000000000000000000..d50b7740c4dd6836cf1454782520609daa6bfeae GIT binary patch literal 117005 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