From 28517deeeb3d7684a84a3f1623077a31e1c261c8 Mon Sep 17 00:00:00 2001 From: Scott Wittenburg Date: Wed, 2 Jun 2021 14:20:57 -0600 Subject: [PATCH] Pipelines: pass relative artifact paths to child jobs (#24085) Passing absolute paths from pipeline generate job to downstream rebuild jobs causes problems when the CI_PROJECT_DIR is not the same for the generate and rebuild jobs. This has happened, for example, when gitlab checks out the project into a runner-specific directory and different runners are chosen for the generate and rebuild jobs. --- lib/spack/spack/ci.py | 42 ++++++--- lib/spack/spack/cmd/ci.py | 12 ++- lib/spack/spack/test/cmd/ci.py | 84 +++++++++++++----- .../spack/test/data/ci/gitlab/artifacts.zip | Bin 7985 -> 18269 bytes 4 files changed, 104 insertions(+), 34 deletions(-) diff --git a/lib/spack/spack/ci.py b/lib/spack/spack/ci.py index f94000e1f70..bdad3a242ee 100644 --- a/lib/spack/spack/ci.py +++ b/lib/spack/spack/ci.py @@ -642,6 +642,25 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file, local_mirror_dir = os.path.join(pipeline_artifacts_dir, 'mirror') user_artifacts_dir = os.path.join(pipeline_artifacts_dir, 'user_data') + # We communicate relative paths to the downstream jobs to avoid issues in + # situations where the CI_PROJECT_DIR varies between the pipeline + # generation job and the rebuild jobs. This can happen when gitlab + # checks out the project into a runner-specific directory, for example, + # and different runners are picked for generate and rebuild jobs. + ci_project_dir = os.environ.get('CI_PROJECT_DIR') + rel_artifacts_root = os.path.relpath( + pipeline_artifacts_dir, ci_project_dir) + rel_concrete_env_dir = os.path.relpath( + concrete_env_dir, ci_project_dir) + rel_job_log_dir = os.path.relpath( + job_log_dir, ci_project_dir) + rel_job_repro_dir = os.path.relpath( + job_repro_dir, ci_project_dir) + rel_local_mirror_dir = os.path.relpath( + local_mirror_dir, ci_project_dir) + rel_user_artifacts_dir = os.path.relpath( + user_artifacts_dir, ci_project_dir) + # Speed up staging by first fetching binary indices from all mirrors # (including the per-PR mirror we may have just added above). bindist.binary_index.update() @@ -884,9 +903,9 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file, variables.update(job_vars) artifact_paths = [ - job_log_dir, - job_repro_dir, - user_artifacts_dir + rel_job_log_dir, + rel_job_repro_dir, + rel_user_artifacts_dir ] if enable_artifacts_buildcache: @@ -1042,14 +1061,14 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file, version_to_clone = spack_version output_object['variables'] = { - 'SPACK_ARTIFACTS_ROOT': pipeline_artifacts_dir, - 'SPACK_CONCRETE_ENV_DIR': concrete_env_dir, + 'SPACK_ARTIFACTS_ROOT': rel_artifacts_root, + 'SPACK_CONCRETE_ENV_DIR': rel_concrete_env_dir, 'SPACK_VERSION': spack_version, 'SPACK_CHECKOUT_VERSION': version_to_clone, 'SPACK_REMOTE_MIRROR_URL': remote_mirror_url, - 'SPACK_JOB_LOG_DIR': job_log_dir, - 'SPACK_JOB_REPRO_DIR': job_repro_dir, - 'SPACK_LOCAL_MIRROR_DIR': local_mirror_dir, + 'SPACK_JOB_LOG_DIR': rel_job_log_dir, + 'SPACK_JOB_REPRO_DIR': rel_job_repro_dir, + 'SPACK_LOCAL_MIRROR_DIR': rel_local_mirror_dir, 'SPACK_IS_PR_PIPELINE': str(is_pr_pipeline) } @@ -1535,7 +1554,6 @@ def reproduce_ci_job(url, work_dir): tty.debug(' {0}'.format(yaml_file)) pipeline_yaml = None - pipeline_variables = None # Try to find the dynamically generated pipeline yaml file in the # reproducer. If the user did not put it in the artifacts root, @@ -1546,7 +1564,6 @@ def reproduce_ci_job(url, work_dir): yaml_obj = syaml.load(y_fd) if 'variables' in yaml_obj and 'stages' in yaml_obj: pipeline_yaml = yaml_obj - pipeline_variables = pipeline_yaml['variables'] if pipeline_yaml: tty.debug('\n{0} is likely your pipeline file'.format(yf)) @@ -1603,9 +1620,8 @@ def reproduce_ci_job(url, work_dir): # more faithful reproducer if everything appears to run in the same # absolute path used during the CI build. mount_as_dir = '/work' - if pipeline_variables: - artifacts_root = pipeline_variables['SPACK_ARTIFACTS_ROOT'] - mount_as_dir = os.path.dirname(artifacts_root) + if repro_details: + mount_as_dir = repro_details['ci_project_dir'] mounted_repro_dir = os.path.join(mount_as_dir, rel_repro_dir) # We will also try to clone spack from your local checkout and diff --git a/lib/spack/spack/cmd/ci.py b/lib/spack/spack/cmd/ci.py index 5c5c0482ddc..d63e5c7b188 100644 --- a/lib/spack/spack/cmd/ci.py +++ b/lib/spack/spack/cmd/ci.py @@ -201,6 +201,15 @@ def ci_rebuild(args): pr_mirror_url = get_env_var('SPACK_PR_MIRROR_URL') remote_mirror_url = get_env_var('SPACK_REMOTE_MIRROR_URL') + # Construct absolute paths relative to current $CI_PROJECT_DIR + ci_project_dir = get_env_var('CI_PROJECT_DIR') + pipeline_artifacts_dir = os.path.join( + ci_project_dir, pipeline_artifacts_dir) + job_log_dir = os.path.join(ci_project_dir, job_log_dir) + repro_dir = os.path.join(ci_project_dir, repro_dir) + local_mirror_dir = os.path.join(ci_project_dir, local_mirror_dir) + concrete_env_dir = os.path.join(ci_project_dir, concrete_env_dir) + # Debug print some of the key environment variables we should have received tty.debug('pipeline_artifacts_dir = {0}'.format(pipeline_artifacts_dir)) tty.debug('root_spec = {0}'.format(root_spec)) @@ -342,7 +351,8 @@ def ci_rebuild(args): repro_details = { 'job_name': ci_job_name, 'job_spec_yaml': job_spec_yaml_file, - 'root_spec_yaml': 'root.yaml' + 'root_spec_yaml': 'root.yaml', + 'ci_project_dir': ci_project_dir } with open(repro_file, 'w') as fd: fd.write(json.dumps(repro_details)) diff --git a/lib/spack/spack/test/cmd/ci.py b/lib/spack/spack/test/cmd/ci.py index a6fe1b4c9d1..cdc52477991 100644 --- a/lib/spack/spack/test/cmd/ci.py +++ b/lib/spack/spack/test/cmd/ci.py @@ -41,6 +41,17 @@ pytestmark = pytest.mark.maybeslow +@pytest.fixture() +def project_dir_env(): + def _set_project_dir(path): + os.environ['CI_PROJECT_DIR'] = path + + yield _set_project_dir + + if 'CI_PROJECT_DIR' in os.environ: + os.environ.pop('CI_PROJECT_DIR') + + @pytest.fixture() def env_deactivate(): yield @@ -112,9 +123,10 @@ def test_specs_staging(config): def test_ci_generate_with_env(tmpdir, mutable_mock_env_path, env_deactivate, - install_mockery, mock_packages): + install_mockery, mock_packages, project_dir_env): """Make sure we can get a .gitlab-ci.yml from an environment file which has the gitlab-ci, cdash, and mirrors sections.""" + project_dir_env(tmpdir.strpath) mirror_url = 'https://my.fake.mirror' filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: @@ -183,6 +195,11 @@ def test_ci_generate_with_env(tmpdir, mutable_mock_env_path, env_deactivate, mirror_url) assert(rebuild_job['script'][0] == expected) + assert('variables' in yaml_contents) + assert('SPACK_ARTIFACTS_ROOT' in yaml_contents['variables']) + artifacts_root = yaml_contents['variables']['SPACK_ARTIFACTS_ROOT'] + assert(artifacts_root == 'jobs_scratch_dir') + def _validate_needs_graph(yaml_contents, needs_graph, artifacts): for job_name, job_def in yaml_contents.items(): @@ -202,9 +219,10 @@ def _validate_needs_graph(yaml_contents, needs_graph, artifacts): def test_ci_generate_bootstrap_gcc(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, - mock_packages): + mock_packages, project_dir_env): """Test that we can bootstrap a compiler and use it as the compiler for a spec in the environment""" + project_dir_env(tmpdir.strpath) filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: f.write("""\ @@ -265,9 +283,11 @@ def test_ci_generate_bootstrap_artifacts_buildcache(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, - mock_packages): + mock_packages, + project_dir_env): """Test that we can bootstrap a compiler when artifacts buildcache is turned on""" + project_dir_env(tmpdir.strpath) filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: f.write("""\ @@ -329,8 +349,9 @@ def test_ci_generate_bootstrap_artifacts_buildcache(tmpdir, def test_ci_generate_with_env_missing_section(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, - mock_packages): + mock_packages, project_dir_env): """Make sure we get a reasonable message if we omit gitlab-ci section""" + project_dir_env(tmpdir.strpath) filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: f.write("""\ @@ -353,8 +374,9 @@ def test_ci_generate_with_env_missing_section(tmpdir, mutable_mock_env_path, def test_ci_generate_with_cdash_token(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, - mock_packages): + mock_packages, project_dir_env): """Make sure we it doesn't break if we configure cdash""" + project_dir_env(tmpdir.strpath) filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: f.write("""\ @@ -407,8 +429,10 @@ def test_ci_generate_with_cdash_token(tmpdir, mutable_mock_env_path, def test_ci_generate_with_custom_scripts(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, - mock_packages, monkeypatch): + mock_packages, monkeypatch, + project_dir_env): """Test use of user-provided scripts""" + project_dir_env(tmpdir.strpath) filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: f.write("""\ @@ -496,8 +520,9 @@ def test_ci_generate_with_custom_scripts(tmpdir, mutable_mock_env_path, def test_ci_generate_pkg_with_deps(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, - mock_packages): + mock_packages, project_dir_env): """Test pipeline generation for a package w/ dependencies""" + project_dir_env(tmpdir.strpath) filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: f.write("""\ @@ -549,10 +574,12 @@ def test_ci_generate_pkg_with_deps(tmpdir, mutable_mock_env_path, def test_ci_generate_for_pr_pipeline(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, - mock_packages, monkeypatch): + mock_packages, monkeypatch, + project_dir_env): """Test that PR pipelines do not include a final stage job for rebuilding the mirror index, even if that job is specifically configured""" + project_dir_env(tmpdir.strpath) filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: f.write("""\ @@ -609,8 +636,10 @@ def test_ci_generate_for_pr_pipeline(tmpdir, mutable_mock_env_path, def test_ci_generate_with_external_pkg(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, - mock_packages, monkeypatch): + mock_packages, monkeypatch, + project_dir_env): """Make sure we do not generate jobs for external pkgs""" + project_dir_env(tmpdir.strpath) filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: f.write("""\ @@ -649,7 +678,8 @@ def test_ci_generate_with_external_pkg(tmpdir, mutable_mock_env_path, def test_ci_rebuild(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, mock_packages, monkeypatch, - mock_gnupghome, mock_fetch): + mock_gnupghome, mock_fetch, project_dir_env): + project_dir_env(tmpdir.strpath) working_dir = tmpdir.join('working_dir') log_dir = os.path.join(working_dir.strpath, 'logs') @@ -790,7 +820,8 @@ def mystrip(s): def test_ci_nothing_to_rebuild(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, mock_packages, monkeypatch, - mock_fetch): + mock_fetch, project_dir_env): + project_dir_env(tmpdir.strpath) working_dir = tmpdir.join('working_dir') mirror_dir = working_dir.join('mirror') @@ -864,7 +895,8 @@ def fake_dl_method(spec, dest, require_cdashid, m_url=None): @pytest.mark.disable_clean_stage_check def test_push_mirror_contents(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, mock_packages, mock_fetch, - mock_stage, mock_gnupghome): + mock_stage, mock_gnupghome, project_dir_env): + project_dir_env(tmpdir.strpath) working_dir = tmpdir.join('working_dir') mirror_dir = working_dir.join('mirror') @@ -1033,11 +1065,13 @@ def faked(env, spec_yaml=None, packages=None, add_spec=True, def test_ci_generate_override_runner_attrs(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, - mock_packages, monkeypatch): + mock_packages, monkeypatch, + project_dir_env): """Test that we get the behavior we want with respect to the provision of runner attributes like tags, variables, and scripts, both when we inherit them from the top level, as well as when we override one or more at the runner level""" + project_dir_env(tmpdir.strpath) filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: f.write("""\ @@ -1174,8 +1208,10 @@ def test_ci_generate_override_runner_attrs(tmpdir, mutable_mock_env_path, def test_ci_generate_with_workarounds(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, - mock_packages, monkeypatch): + mock_packages, monkeypatch, + project_dir_env): """Make sure the post-processing cli workarounds do what they should""" + project_dir_env(tmpdir.strpath) filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: f.write("""\ @@ -1274,13 +1310,14 @@ def test_ci_rebuild_index(tmpdir, mutable_mock_env_path, env_deactivate, def test_ci_generate_bootstrap_prune_dag( install_mockery_mutable_config, mock_packages, mock_fetch, mock_archive, mutable_config, monkeypatch, tmpdir, - mutable_mock_env_path, env_deactivate): + mutable_mock_env_path, env_deactivate, project_dir_env): """Test compiler bootstrapping with DAG pruning. Specifically, make sure that if we detect the bootstrapped compiler needs to be rebuilt, we ensure the spec we want to build with that compiler is scheduled for rebuild as well.""" # Create a temp mirror directory for buildcache usage + project_dir_env(tmpdir.strpath) mirror_dir = tmpdir.join('mirror_dir') mirror_url = 'file://{0}'.format(mirror_dir.strpath) @@ -1404,8 +1441,9 @@ def fake_get_mirrors_for_spec(spec=None, full_hash_match=False, def test_ci_subcommands_without_mirror(tmpdir, mutable_mock_env_path, env_deactivate, mock_packages, - install_mockery): + install_mockery, project_dir_env): """Make sure we catch if there is not a mirror and report an error""" + project_dir_env(tmpdir.strpath) filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: f.write("""\ @@ -1481,8 +1519,10 @@ def test_ensure_only_one_temporary_storage(): def test_ci_generate_temp_storage_url(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, - mock_packages, monkeypatch): + mock_packages, monkeypatch, + project_dir_env): """Verify correct behavior when using temporary-storage-url-prefix""" + project_dir_env(tmpdir.strpath) filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: f.write("""\ @@ -1533,8 +1573,10 @@ def test_ci_generate_temp_storage_url(tmpdir, mutable_mock_env_path, def test_ci_generate_read_broken_specs_url(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, - mock_packages, monkeypatch): + mock_packages, monkeypatch, + project_dir_env): """Verify that `broken-specs-url` works as intended""" + project_dir_env(tmpdir.strpath) spec_a = Spec('a') spec_a.concretize() a_full_hash = spec_a.full_hash() @@ -1585,7 +1627,8 @@ def test_ci_generate_read_broken_specs_url(tmpdir, mutable_mock_env_path, def test_ci_reproduce(tmpdir, mutable_mock_env_path, env_deactivate, install_mockery, mock_packages, monkeypatch, - last_two_git_commits): + last_two_git_commits, project_dir_env): + project_dir_env(tmpdir.strpath) working_dir = tmpdir.join('repro_dir') image_name = 'org/image:tag' @@ -1657,7 +1700,8 @@ def test_ci_reproduce(tmpdir, mutable_mock_env_path, env_deactivate, repro_details = { 'job_name': job_name, 'job_spec_yaml': 'archivefiles.yaml', - 'root_spec_yaml': 'root.yaml' + 'root_spec_yaml': 'root.yaml', + 'ci_project_dir': working_dir.strpath } with open(repro_file, 'w') as fd: fd.write(json.dumps(repro_details)) diff --git a/lib/spack/spack/test/data/ci/gitlab/artifacts.zip b/lib/spack/spack/test/data/ci/gitlab/artifacts.zip index a6fa6de360c315b749a28ff0f8a58986c566dabc..bff88661eb1cf9d1f74626184c5c924b1091f357 100644 GIT binary patch literal 18269 zcmb`v1#l(Fk|io;W|f$knVDH7W@ctqiJ6(1OHzrMnVGS~%q50ZzqdWpum8NAn%y7Q z?!B32X?fBkA|p=taSwSZU=S1l00;npXZK!3fWMS400aPb=61$b<~GK zM&=H5R<@>&bk1(j0DvHWT>g(AWhGDmz_Q#Xz5h6n|Hq9XARzufH>UYN-q_Jj-_VlA zz}ei&h{o30iPp)@>A%G~Q$MxEVnh0<>N5D&7O)G@R%^AA9OO7NXb)8&^QD{SIWGmd zdGCyth_}&8O_6VX%Lm`J!K3QSSO=~hJFxxYUORi{(?o20#~YLn2Ok$6v8n3FiaTR7 zHazW6UxbsBv%Rw{?PLh}exSXM zTLAa~3|(-aoZYNz?Fm+;_LfSZEb^(i-|3b_0R?8^(lLG9`Z%4v&g*ka`Q%eIV@8;i zNYSW|P+nk>l#0*`71uVg1Z4n6&epvYO^vPdg-Jhi_{mm6c(a2dq+rdwf8Nu_)yKA- zu0;THUGvRtzo`xfA4ZXBpAm0sx)$sUXwitXM_Tr;9CU9o9u2~*V5{Kg8Y)`3erc>< zv6QH%ZOV0s3{sKlu+1(hFYyn71Q5ggVhUH=WMofoGp7U&zcDmOkkX$lH<$$T!vL|Y zu8QKRisUM{N|jFX5>-})Dms^_+4kwFT{q$RXlPDPdZc)XyF!3mOf-4>!0COsk2Z)Wyo*&?BQ7x%rB>fd7DgBhE(BWqLa8y% z=$fzlF)~;|Dnb>IG=oyPa3F#KF!F|0it)WWsb4?>1=&o%O!?b3ly%3N8r5Doo*7#U z1B~_fCHdn)-!AaFKv-a&I>|{@3VP!u8tQ8OS!PpobCvlJ$P_1;41fGv0#XrcL_nrC ztNlJ)`Wc3*Hkju?rJ-*9vTEWq(#kO{jvrf$Z34n{|Ftx}ow0U;iMOrHda?;jJP#`V zAY!h^jwn^wC}5LbSZ{|3qFs?dFOrl42#4`Hf9>kWez!_s+=`Q~|F8-7YnNpz@mG+D z$zEOEj*o-3m$}KnDhh99^IfZP^s3S;7(e@f`RkH>gKgz+KBs6va=voWf~T=P$PDc? z>R2b3Dy0~dt)(Qv7EVqYV8@_E=tF7^e4Hmy4bZ3Zf)KO(8V^Kas$YvtDa){u1)rSv zYA!IULRFJ~jy6yv6#wGy#1TSMk7AcD04>5{-$f;X%P7u=C2!Li19I#Hx81akhXCU> z8%CpBi#}wEU@>&ZB~q|s5dp4_Ms)e2$N=(P&ohC+h}R7G5^o6*zuo}9*;$}6z647= zmzdaAMbSS9>nikV;9Cxrzxz)w&dRZ^NjD3nJa2`lt|*3vwN~$oZGzfUKo} zRPO>4GtLqcRO2G-7nJlLStjfZ85&OaY3`V}B~R<>w(K?N;UB>?og4_~tVy zTaY7Gsll|Yhxjzf3EeH(Xu=5Q^L{Sce?j$r`C0P*khdH}+kYYGDFIWEu5Y*r)N8*O zJV;<7q8}RR(406d2)WF{ul(M4F5%+QP^2|*Fu8Vj=8O|3QuMH( z&(@Y3UJVB`4T}pLvf0j$U=K$b*qdnlo>mpFu=OG`Q++&kBaaPACAg zXvVb($}k3~;bU%(hsL7V*tEouCABpg&*RvQ#p$Idd)JA;%k7l!`P1>jk%YyS08tB+ zd-{E{Ix{XPG_0bIejq#gXkWk|qarpRK>J$&hDQ31X1eA^|BjXX3m7Bw4|;kAuup#U zPfL+3#ztX2?FRe&{`&`^{;dZww{djRx3Z#jH2bf}(Z4)~Rjfb^3IRgUR`wyYy$XFm&aN?+!}b3H~-qF+4-^9;JU@bP`r<6 zV}s$j>7Z^Udl(|Ib@FyPuo|N2Jzen4qR+d39#=U-bBA@~*uEO~GP-0}r~Td-VSOq9sZb(j7xBLcxnaM@1ITf z&o*rF!G?k z^SIK}gnD*oF7D7Jk<>=c#&IVy;eISF5}a57$qN}^Ky2{i1&6nAI7~<(engF;vz|A) zy-f}9Wo_X0R@dBL`kCrme^^wifZ1)xMxbrjjem7*`nKcQ0GCk4Nce2WVpBA}uTm5nO*7ffGaIt^66d|*QcjD%J`|`qO zTWx!()A{^(aIgW?-sbMwkvuEz=IZ_S+_!Q5YwP3f;QSPn{Y9M7sqwwPVu_CL)n(~* zPSqmWQU9F}YsrNZ@LRvr$3vUX`zcZMyL08~{qy-)%u=b& zJ3AB2)#23XL5HWa=iBx3#q);mg-%yX2Ok$WvtKd1d_B;#ksBx`P@Q^o8kVV5V=p;) z@2Z&Tx#n?o{AfX_LkQ3j_%@&m~d31s2wc`WbsqQ#$TWsrtscBcHH4L0L zG%~#uE3TXS%k>1`A9ay;9P(fwir7+zA7FZTdN4t)XTTq;@PhRU`+8mtleYoX4?;%X zjo2E&MEb-3t@SCn2sjX5(1Kvw);G?F=fw#Q!|4dN>)R9oH5$JL z^!x7EvbmC1D<3$!L1-+s{x5cQ08vIKI2fa$LWVjla5$50n4P1sB|Fcz_k(vSQwhcs zjSaWQF+l$V3BP6oL6%K@MI{)R@7IAIy z>1WgaTBG3nB>oNE$)+xT`V8l+hdGXJePoUdoelugXiFr(Awm|zL5FdS@W@DZLPq4m zY490;BZWY5bY`^KASZ@4H-@%UTa92s(NW?-h24-kxrc{Cy}oae1HbUm5)f4C=lzJy z=(3T3PT(Na-X&SM)5$^0xyJ^=2fZrnD*ILE*hTMUA)JCwr-h5MQ)=XJxSBG7341A z$=zUuA^)s2_@qT5VW$LoN-Y>A0hPcAK#L}39!6TvdANQZq7SYku2eUyf-b_XpW`pH za`$>$xA{5{-o&eUUo6VhRe96#;UC|@9p$hxJhP4q{Y8|~B*`TdF@zoV^l0dL8Y4WN zZ^^cGDos{AT%m3%6~>;1o?JO!xtJmOFhqG^*5g~&zU5hP<$1>0k%406dB)qJ1F}`( zN%wX@G;f&Z0E5E{d!ghym|zml-j2^((RZO7_%jlte;M!9M)p&V8=Ici*U_l;yPJK` zGYAUr58Y7@Cc8A!H*Nb_R$Ni-bx`OYJd0wgV4#2=#6!LA&@;@wKKr@);s!-}O2j|h zW;)!C6MkfLfuo6iOx$Kg+4&a6Ohuff!v94H6`s_O_dZ_UwCS`Qji3y3l#$rMfVk`{ zDq7_@FH%1s78am=cXB+v#JVmWkG8c%zB7-DG3y7GUcdlDbv!#xHXBZ~R@Ek@8JG%{ z9=~%ViE|UA5UQ(Sm+}XQqp~I#yp20DnQ*T()uJRm^z1<6CQVoXHOBV`zim>{uxw?F z?1^v0GRhN>tuYmDdcYxE3=>ZF-d?*yuCo|mU9oT;&zWP7-w*IWke_&ILaZ)AboGjOQ} z#~(1mzfm6n6C#vMP4VZv`+vB-o~@!FAG=tv8}A)sAXe8F`R~Q+$P>xbmg@bKeRV1Z zPe-Fjt7acoNT9Ya4WLTo96sua;pmA@6&bGBB08B1F;f@%W>w8 z^}*_U$aFo+(+9D5RFBPZdA9Ea4$3kJcb-Z#`chI9=N7kj zfGM?)aLT37{I&Z*q50e|F08rIVujruiuOib9Ih|H@2CEpA9!CZy3tfAK36@qFCz>N z55e+^%4NvyI0Z%=*Q;L{M+2SCHjy6YNTMe|CRaAc0dj zDi4VGe${jya^T)+G}q|L2=+i9j6nG~e$sMLzc5E)EXd)2l@Rr zQPH{OXr`{qLan*Gxa+wiHOa3Fynw7Q7WQ{`cbQNgFcx7NL8@plJwfz2@EQr*M^Bj3 zhJDL|eyNn%!EfcVTsm520gZ2PgHsVT4}dO%SjK1wQx7Kqr2F(y#s~OT5|Z#fs|PXT zIVvL#=W7%g^JhF~(FE-FXCR>jqv^)w^gWp}nKEQO#lTJEc#*}O#?Lf)Z8R9=O~}vk zFDZajl*&i@it0oA5dt!NZYmC*VYJdeFpBKEYoW+{gK}?BTLq502d}>B<~dRmp+F}l zBxSR3^mOuEraA(Or4(fSq+qs6r;I+_84X`YK!scUMH$HR#J_PBSLdf8k^n6o2aW(z z=>cNDU zC0~Uvb=y0K5dH&gP|>6kV)TVnu&pr$Hb-Tw_Wlgz)qJY3QkCrlFPuKMYH^JelUP+` z;Aj6&CnP%$|2iSf+|`j{zlZ=$Lhv+twQJy>iEdPq{J~ZwKnXX3@rNq0rSztqiRfay zM!8?xR(h4m0)(yh`hp_hjshyh&MpdJBrc2=f&8e2=O>4+SN9qFg111TWmst z2#bm{DSa|kya86(^{gPQQD`*b9g*yj&WQpOLKBY2NaHfVYbY$JYYNvbZ3;YRG4+hC zz?_q%R4_BLB@G$BX}ioje$gDoOZ&Eg)V3C!m(G>86chzF=gKq2z<@LvVT(g{bWAv^bE=I-X4OUHC2iQTjobI$=~58JS2$?dXjF9 zJwTt$?YE^5aKV}7Ze=|GvV9y`#XYB3iA^-dQW{c77?`~_mAeYQD^$8zyMBL#LcQ~g zykwR_F)YQXo%qF%1XCj~G%QY4G*|;rA{F|!<3$$_!ByMXgBgKqjs`5NTPh6|GZ{Nr zo(4%fPTJoEpvLAMMELsxwdSQPppZ`-MaVXVfZbA5z8oLXSVi5Ta@Gnf+QuvkArg@L zM{hg4KmlLH+6pZ6S8akbM937XKzOhc31 z+f#V6S(MLsPL`Xufc&Oz`UXXe&SPY#N@wH2W#=WFHLlb!EKzuPfKlnj=bEyBvVJ{+ z?4azRr1{-76^?w#fR+1jH5G~y_0z$iz2q?15$-K}KYYLfkVDw`m3;gr+2`MSG+_0OIL$>V>(| zC$oO$g-fNcS;U_z%^EMz6D3soJAr4l9mGr>$j;Q>U!oWtG<*TSVgkS7N4e6lrbNR| z1cN2*Ich8A8q*FmJTPa5i)Yso*a&yr0Si4-`%#9)#|vgbGl97!F3Tv`rRBQXxy#6Go%if5X6fV5Cg zg3tYAF-9(1W32YqIm*$>I#ql27wU4V_Zw#L*%5%_X;^7Z>{VNnvovXFT+hC9UTmFH z?z5!J0G^5KkH{-uryWR|gvat6 zi?=76A`j#J%JL*}zm4)ke&qoT*2q z=?~@``B8I3QxO#LU`fd}`IoD&P2N_I^PH;@>m_+|BkSxtS3j>fU>}(`lwq*>3~hjn zemX4YLx)Vs0p@)60%+kQP7i%9ek9t!r`Yw~kt@f$aZS@!lioyq8LCi343pGlQehv3 zS)JGVN<1w7%4FlyH3|d}CNwrn>tFB$cQXqfzPwuyy**BZdK#_<43PRFQaIxNtb0)} z0X_AV&F-81a0~KM6DB=!u}ymytOlhgvPW~+!t5ST=dmQI0UHyy-%Jz1`ys=7K_V2s zfKyj|Bh)(U+F45h(~8alb4oV#>!-A;2)^K;gn=P4VjQ)uwtewkdW@UCee6+{uWTk{jo6_!zWRV+vyQMp>rMsr1iVjnLXcKoj?SfyN zMI?^6PTIiWv{<{6a3K0NYovSmlqu^U6<_OTauQUKQ}AIl{UMIpX^XIPw0pD$?j0r( zi$QRrPX?OeU;EH5h4;&4Lo`rPGcQT2RxLzlySbC5$YRt#b0BZOZ$b9NIkopkFdrY_8Roc;N23C|dn!X! z?yTcg$_kjY{W2tS5*NYG6+qk|$3?_jXr%VVJY{mFYDwrj7$Gl|JV#w5)exiLB+%ri zf7Ra^W%Z=_Use@gaI^xxFDw~~P|M4zcr0oSwUXF3J?BY&PDO$}u&-b8#DK0W@2oXG zbp5+a)ZE_lK;=za5qRv>l z!c?kWA)_aMojbjUYKx>q7TZH&=M_?!pnf+QM?UB~x|fa!2#^PSxM z*SQa9-rftp~FfJs|_zw3~hXZ109u9r-% zG%e|#GBJsm(zS=kf(e8h4}hoj_pqp@No#|}C~rh=MF(=-sYYxi19Hu?oqO(qScmpr z)4o>+pdX6H7>!NUS<#xUb-kDq>(XXZ#_OWUZNPqFpdM3ON?0EVB2-S&DQ1Ovh67uo z!OQUGa7jN^FK!{5Cq4?-Ri0>Zm0ag~mLEi`1QW8oIX<`bdx&a!0NN^;wiL#N>-6hh z!{{V?^oU&w%S`oxL7ItzMyBLUg}&Luxx~1@(f;KeEEG9G+;BrK0d0|{Qzh!B^VGQ5 z#{)JpylfatZ5bmA*zwEI0^1GSjSR4TME3(r&5Gp)eg`hc78@?>lKK|6srkhaVLr`f zuR<%FYGpA#ab}b($=ISX=T3&(XFn*;{x0cLvpA*L?vG%YEdFXRmlq<;p5gO_HE5cc z;eSu69YF!4`QVP`OB{Ixmr!TYrYeyP49sE2!H_s~OT-$8JK}B4^B#Ioqz&oGl`$pT zh@I9a4EXG={KwQwh4>8w`ANFON{fs%OXb|biZj6e`CmBR z(HCm%$zz_mPvFsd3wUFmzY4$g-S6_{bZ@267TF{TYaE&N#{*N$z)FZBI%j2f>#}+8 zP3u;uHR|lolGLG6nYXJDWi2pRxU3uA^!(PuPtr5Y0hDCvY+SD1iB z`TG1ixOmHWShC$}Z|n5Deg2+N=*_;k#NZfA1dZBmnk7GF z@wEYbYik#$;^`Zt47wk6%?bIY7sj{=FQxg$rN;}J0HBdukclP##1~GU#T;BItS*}; zpwK9R`tz?*(P^lMh{hm2@?Iz^CfI2p3{D~WsHFBN`Jo$Zg%<78cX`eSt?F7E*mUce zx64{!EAP44zAY$4ZvuQD@i0@gOI_af?~n98XH<`OsqnZ5a1mmD>lW|XQ(&IPSr#rl z9)Prg=ygv;uYx(+>2%C)d6PwB;H{lsfT4f2YUh~&K$knUyhrx5P-q?ft@JDPJF8WxVqa0e*Ye$?7jh6E z%5+XdVMO}J9cgSCo@G>-vo(>C5MY9O*mt(N9Ry+ql#!-*ihgHK^K1zMgiX+5n)KLP zcPJxiY_)C6s$UO(pZ+46Z|NEjwo#)KyUZjz9LR1)@Z^l39%HC*b@>6S=#lU2P5c7k zj2cB>n|*l4sKU4Ds|9ow<2%B*phNB%$*J^dfXh z)q7D4g13Q}Wi7sbP6jWfY>W1wwwr3dw<@p6Z@cJeyPUIo6T{-RWsqL53$SAgTs}zs zoo?_DzJRUeN|b!?iSf$H^+_vE#3YY0VK+vpX!^^-gWP|JiWg@2LnWVQOaCIZ{avP^ z`Yox=!PeI4_j>7k;+V}THNwz?JCuv|zzwMGXoc4^3Lvf(whdV3vima;iTz1oM7E?@ zQtRz&>IV$HFEX}W?OK6dGR_J?;54LH>>@&70`o|9sK@3O8lpqEsD1~jxCGM#-JKq= z0CI+OW-Y12wKs?2mH@GtO}UVBz`6w)>SIGy-WP}y_O78A>v@T^!ZsEX_EA54RteOi z76UP!1%#fE1~l|=7r)$(cU?cnoN4YZ!fPm{mo)MbUVdmeY3N`nH)hxMzUL@;IU%`N zKl))CZuJs5h3=iAMk_lhws~cak^MMa^d`j1>O(8Gn)rj}dk&ZNFW0M*QhX`&uDjb> zv|H~PT@Ng z?+mU!eV%I^J`~G*o|pDP>WXBKsR*3+AEwkm$v0CI`l?c7ycsIE zeZmtIxyv|#wOPwpK|kcIVwbM}I%)Uy^{zAr?kcA7BkIA(GKUWI4^iu%65liq>tpZd z+vWHv`u)GYUH=GXqqVX%wES=1t}|~5+r4I_gASh{eLWj(QBsPyQ82L7KCJ`J6b^1? zC@m7nLUD!p=jjjcZIR>oo%quv-6AaYp+aL3`bQCZR>hBZ2iK2@Q2vXL_Lqm0wl>eQ z`o}L|WS^&P)j0YCs@Ce)>|P&3yTEhR)s5uG?c9TfSZ`Z4ZmV&+k)hzTPdK z9xEH(q9K z{BS`P) zXLp4xU8!P4pPZtSDALfH#?MSZwKa=eS~`J6mOOvapP(YLURiNBmdJ_k5~J;AhUrVR zCj+Us(jw$2?NiNEJEIx|=!qmXTCda-NMqr}LTQF1Uc8diFL2wP#YvWoSNKU+=8R2#8BuGNa7dUR`;rFn303 z3d6$`tshUsHBVBwAGOY-JL5Xo z82-3i3UJ^ld|FIZxpOxoopi<88yfn^zSG}|mnHYA&&z-Sfe+CX*xqG&U8@gy*UkIL zfm-=MyZcC-%{HerSI4^<%aSQvjQ-JH=Yu9eB;k=z~I_@+e|KBaS*< z#SwzuiGapR<5-p+wSv81al3VoPx5ALBN(zg19#hFyf)QSmjRgIdRjrX$Z+a3jz)U= zLL-N*mqhQt1R~330M1*`(;%OwIZuCE$!;OHT`zzM=TPHQ$xTQ1OZWlZq$;(OaYNJ2 z^^>i~MnPeZ=rs7d9j8zyY5PKzgCV_P`0V>(=~N+OoKtY*uWtYA)}j_nklV=-mfI*Ykcar(*x zxwF+DjJ3C&OOJ7{HPM2i^K~D&^u)RgxV?o*pI{}2L+L`$1XpL; zq*3~{1rtczrW!ZX2x>S-l~OJwMlYq&^O={E7JrqUKzmZDYb?XWGP0(b6=7cPBp8KO zGis+^%OU1No)%_uEIwljS~V%8cTz4a5GWcv%$yx{vB(o_LrPaNlbU4$r*LQI6>ch! z^zNF5v&mtMzFl8ljmZbVB{4*dNlOe->xYRa=MY7TOC1hik3$wj6lVt(i`+Tt2IT4& z9z7Zsf$1K7fqX_TJ6^qgN_~27;D4gEIwapx?uXoGlF>2p^#$+f0^qk@ei}L#uW(>$ zAqpa7jl$Z9S;Sm^@D8|%k88eGbidcV7W15WLSsYCtF6jso|+#X8xQ4G#)t`~ew*Pz zBYUkpaBpcGIak8xB><6He0+A;Bg}zxsuTseNsbOOEu76q8JIRLJs(Vu_y7Y+18y+1 z=b-0i|NdNROw&tbR3k36qyi0cQOizX$1yRMBm%#!0w7-6s=H7HcH7Kdq0I|nTc4j} zhUEj?TP40l35>D-qIPGV#09QoY*w-xpB5i2n9}4r8BE|rb<1C~(TPfjr$(x&ms4T!7vn*b_LKjwu^Gx&;Af($L)B`L)}3zE&hO$y z&4A^gKN5;8KpQ}!8EOePmtHO%=@X{XO!U_C1&EYHWe|%9qqKKtIh6}a6$Q}4n?L(_ z=$JVzYfgxvJym&gQh7xPCq!Q$ycErIAm=S~V-)_$RdR3S)XZeKm-QKaG@8=Nk))C0 z9>;vQK2$FGDfJuR&E+CmRC=uoElHuM0tf(B<}V~Bjz(i*>!#^sZ8S3LvjPE-gj2ZSH1xMe9hTMc3y zm*%uWq=~Q`<&`dr^&pOGPtttp=N#)Ua$M4OZQO@f!ECU$CGj$u_7*Kc$V=6kW}KAZ zDxPnqb;`Egk4)!vZTxSHeZMZ$(;=6pO3XGLB;~-JxI|)<1DhA_CIiupoImAaMxAKu z`XS4V;&SO6dX#4CNz%)A^(@+7c_?{xoo-%@)Bzr-7o0Kr?x94Gvg~hF@2tO}9(4aOn z!f6&$qN}gwGrPK#5~Jsz4on}F_a%*JFAV1}D<85vEo6O^HI$*r3Cw~mbna|QT%@~& z!T^W^!Ha-vFHj2EzxPdiATJCdysLjzC59|lp0kWGP=cvHo6~|?zx!d*T6GeB5&znm zYigEdrlJt7#4wvT!%OEd#R$r&sE(nS#~zC2*-ML7%%dM&EW!f55u1YiT^&?|`nIut zOh9H-iE1=cv*^_dGn6vNP4`XU?i3~OS0m&U55z6soi|Rl>|Iv;Z6pWej;6c`CcX_W zDhdxWEjRShjegltI!{@>o9rlcwk(hRih*>ENyFO;r<;Iuhnte7=v}Lmf$_{kChKMMTa(&Nc1u_m!gGU zs{93U*8a{GjzvnEFdYYlikq4B4p}E6*T!{YiFBx{k*gz<@015}&pe*5#~Wh;#@XNO zIqvffZ97_(8}cRja&$VTP!99C3mS;d9rmkRPP-b?I{T@qu=tk46>MKH26Jhtk2Tj8 zoaqY9=1M0ca_X;<+j1z*$mbYwYyE40M%iVgdaOsyL7}Ihm!hr>B36>7-6PUQ+&Txa zacvHAr|!cp8ls*{gvYfcRzQkQXu&zOMj$zpgZ|y`gX0EUHG4j_0nzW+xKo;WRJZkZDG7#8eVO5r_s?BY6b;ty;HdsNIYLQx71dFrFc3DKnPe>6l>Ni;D|pwaHHN+# zsalP!kX2#Zj31<3?it4Q*IomdznkvUaa6NQYf$TJ5QD=V~U9Y*ENC%Ic0>%O1;EUaTk zL9HZjN|B?RZ|r@i5njVuaRdB{_$fa8N?H0Y*V#(FTZaegAJej zh~J{^JM2Y4;MMwevh`?pzxCu=xjB?MKSn_&{gC3$YQ zrIy^$lj+DPFnuM)Vs<&hd`tBmId4A-p2p7R;Q!w1^vqeCgY^G zX^;K%{x|sKefx6_#aQlyxNorwBAwLn7lekj8W{*}^^hT3kZDvI-*lbXwo!9=c~1JsrvJgGU-hE)jQWOhmZ_U3l$efuU|gMU>sp!eNu1K!x; zi)DKGz?VF6kF5~nG-p-81d?Wit0Id5_-z-)o&;RkihCrdEY)igzsJ{GmWY;%FU`d( zZcR4hezh6YZOe=Ym`zXF_Fn9pF3pak*L z$oLTU6dcm{e%KLxel=h3pg=%~rNjkEM9E2y@R2ZUkWmtEFb2tcrRBp4b}8ag#R)+p zmI=Zn;=iThz?qrzSC`SB){cmc90&B@Ej_Tjd~tQv+Jy#J6{pm?rY0FtTpvSWPy`K< zzbq>rXCDbAf6mik^}RrICk1YyM$t~s+9Po3GJMw6bJ&bN1yRii8u#N2o5K)}6C9V+ zP0EaPnx_~FM17hX#6<2}l2g~6l1pQMl+MduY{nd%P8MW7o>n|C=%(bXU4@}(s*tyZ zCrQD5C7C^Vs~@V~28af~;tKH*F|_kmehuQtPU9yfRFLF83&sv5k0k~Tlx_@anU-l*c|mfcc?P7pT{sZ&iAW+$eBx#;u0ki@hG^x97`Q> zIiC|>CpiGqON&~`@u4Ck!GhP@_7--68`tI#YEurP+0of3sF_kJy&hW}X)%aU) zPY-M%)h3DE`5g7A*K;f91*(ckyk1(IW$=eGq*LBij zrK%a)FGmlU!h=kWvdSu0v+T-qVtLF^waY}Z_aE95#_SF&gfT$E0~xwW zrQGFC3U(O^yI5Esi8tA!fFb5a zv2O(6Ss+v`9;G0L2|E^*QgL8$bnExt6)}dZ`Q2Z8ZC>6h_$ryDf-tod$9iU{EC})6 z^0gi|h3z2lmGJsUE*GOIwo=e!hP4t-%R`}(hB~W+b%jN$E4Pbv+*;b&`uFxHAJW_v z?t&R{H54>Hfc;;Xa;W6<6&f-zV72+`gZhbSwFm034|!!Z-|Eh_Gji8ORsAY4t z#vNw5yxX%*uldM;CP)Ds(?!yY%Tjg`IE;vogOEf^xc6|xA0l!-00CSPS-`hxBhUeu z*B-fe*Qb{-t022v`z$*9+h%&|`^O**ZH&4nl-f%8T^p~hy$y+!$CyJ@>M4|QUT@FK zF2!#_YTKL7MtWZMGAPf%!K33-JM8Y%vAjMPJiasnts$)(;;waG$l~Z>y`bW|YaE$<-)*Fy zKAmvvkYkehTHYO!tR!pHgwNYSkJ4l=yjvw*WYK(IT~H`YgaH$;+!flUB^U`Of@c*J zB~U9n>FQG2vr*0}g&zs!JcM$-y$7~lK}QH@Z0{xyH5%1ha_NbY$5jaOp!w{ zXlG15un~8R+!2LsGke*6eMvwOF`Z>c_Uo_nLI@)1(_?VaE`ElHB*LYXxU2o;rAmps zX=;#_!y9Hpx;K_nYjtahfrW#Dla1XWMOF-XgSGPd=>_oo-t#ZyUr z>@%^LJoo=EFY0dzMfJ*Cwri{iJ`cL~<7hGT^caqTni-BxN$>nhDK+}t6G19(Nq?W`W zPNP(V&xW>IiYs7%v5?i7R)58h`GHT zTAAEl0G*{UUGxCTt4Jc*Mo+^rSj1x1oC>UWOGR@q7PeK^vzCs4)$3%~0*qY=Sd*X@ zT-w21Dr#v&1Pyr_IpQehst1`YPUoqVcjToshq@<5Q-+Z?H+X%MdAL0JfXMA6g71r< zyXy#Kzugo~(1iRkywOf&s5>)u4!4}_q;QViTHm%jd>Lyv&&Gv32=`!}ovT@#DABjz z_9kBO1UD^crsJ9g%gL+7wgm%a(uEA?drmj zCWk&}tSD_U95Jw&pvuZ<1_~n{c2nWK2&F7gu^=>(D{z&Z@ zt*S0gI6Ij*J-d0GI#!A93gaDYTV$^A=Z0va`|#>)emwW8ZJs=+TQSHO{KiX#QqiY_ zmJ7*!5O)Hk(>r#Fd3}pfMijz=Ic~KVX!{f*kWlgg4Afyuu)RNH4nIeJIGpIY&l>Jb z@-qvT?xO7I%|=1ga2k5xj3OrTAsLsYTo_XOk~nfq@+HvfOTBR?feEwwopJc;Pjzy_K_(+GAFyD zXFn1a@f2UQDd9)kN#1~>`etU{T{p(AGor_ZfNzU-^Py3LU5k;wlXpbP_F`u>iOeT1 zK~!rk*(I3Hd1MWyH=$S15orhY&jIr`m2xieQ?9K1hhzx|gaZ8U zw`KUe_*ZZa!rub_ zpM;J49sI9h0smU*-9*0w{yzwo_&fApRpme84*o2Kemlg!1^wGm2!BWZD--)yqjAZ8 z2l;=XVgDWaufzPmLK|`aKJ;%9zrREObvXTF9{IBr`uX$!HuUe$D)LgGf24H-z+}g1pYYtUw{wq*8l(j literal 7985 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