diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 34e68241ab..26348da43e 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -1686,8 +1686,8 @@ function install_download_additional_translations_operations(&$install_state) { $language->save(); // If a non-English language was selected, change the default language and - // remove English. - if ($langcode != 'en') { + // remove English unless installing from existing configuration. + if (empty($install_state['config_install_path']) && $langcode != 'en') { \Drupal::configFactory()->getEditable('system.site') ->set('langcode', $langcode) ->set('default_langcode', $langcode) @@ -2398,8 +2398,6 @@ function install_config_download_translations(&$install_state) { * provided to the installer. */ function install_config_revert_install_changes() { - global $install_state; - $config_manager = \Drupal::service('config.manager'); $storage_comparer = new StorageComparer(\Drupal::service('config.storage.sync'), \Drupal::service('config.storage'), $config_manager); $storage_comparer->createChangelist(); @@ -2428,15 +2426,5 @@ function install_config_revert_install_changes() { } install_display_output(['#title' => t('Configuration validation')], $install_state); } - - // At this point the configuration should match completely. - if (\Drupal::moduleHandler()->moduleExists('language')) { - // If the English language exists at this point we need to ensure - // install_download_additional_translations_operations() does not delete - // it. - if (ConfigurableLanguage::load('en')) { - $install_state['profile_info']['keep_english'] = TRUE; - } - } } } diff --git a/core/lib/Drupal/Core/Installer/InstallerKernel.php b/core/lib/Drupal/Core/Installer/InstallerKernel.php index adeb5c53ee..658cf05a72 100644 --- a/core/lib/Drupal/Core/Installer/InstallerKernel.php +++ b/core/lib/Drupal/Core/Installer/InstallerKernel.php @@ -66,4 +66,19 @@ public function getInstallProfile() { return $profile; } + /** + * {@inheritdoc} + */ + public function invalidateContainer() { + global $install_state; + if (isset($install_state['interactive']) && !$install_state['interactive']) { + // If we are doing a non-interactive install then rebuild the container + // instead. + $this->rebuildContainer(); + } + else { + parent::invalidateContainer(); + } + } + } diff --git a/core/modules/language/src/EventSubscriber/ConfigSubscriber.php b/core/modules/language/src/EventSubscriber/ConfigSubscriber.php index 5fd08e6b65..c30ec26d97 100644 --- a/core/modules/language/src/EventSubscriber/ConfigSubscriber.php +++ b/core/modules/language/src/EventSubscriber/ConfigSubscriber.php @@ -86,7 +86,10 @@ public function __construct(LanguageManagerInterface $language_manager, Language */ public function onConfigSave(ConfigCrudEvent $event) { $saved_config = $event->getConfig(); - if ($saved_config->getName() == 'system.site' && $event->isChanged('default_langcode')) { + // During an install from configuration this event can be fired whilst + // system.site is being created. If this occurs it is not necessary to + // update language configuration. + if ($saved_config->getName() == 'system.site' && !$saved_config->isNew() && $event->isChanged('default_langcode')) { $new_default_langcode = $saved_config->get('default_langcode'); $default_language = $this->configFactory->get('language.entity.' . $new_default_langcode); // During an import the language might not exist yet. diff --git a/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigMultilingualTest.php b/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigMultilingualTest.php index db05d32031..f8626394f3 100644 --- a/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigMultilingualTest.php +++ b/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigMultilingualTest.php @@ -12,13 +12,31 @@ class InstallerExistingConfigMultilingualTest extends InstallerExistingConfigTes /** * {@inheritdoc} */ - protected $profile = 'testing_config_install_multilingual'; + protected $profile = 'testing_multilingual'; /** * {@inheritdoc} */ protected function getConfigTarball() { + // A minimal install in German with the config_translation module and views + // modules enabled. The install also has the English language and the + // install profile does not have "keep_english" set to TRUE. return __DIR__ . '/../../../fixtures/config_install/multilingual.tar.gz'; } + /** + * {@inheritdoc} + */ + protected function prepareEnvironment() { + parent::prepareEnvironment(); + // Create a German translation file so that we don't try to get a German + // translation from localize.drupal.org during the test. + $po = <<root . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE); + file_put_contents($this->root . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $po); + } + } diff --git a/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigSyncDirectoryMultilingualTest.php b/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigSyncDirectoryMultilingualTest.php index e223998ed7..1da2d46fff 100644 --- a/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigSyncDirectoryMultilingualTest.php +++ b/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigSyncDirectoryMultilingualTest.php @@ -12,7 +12,7 @@ class InstallerExistingConfigSyncDirectoryMultilingualTest extends InstallerExis /** * {@inheritdoc} */ - protected $profile = 'testing_config_install_multilingual'; + protected $profile = 'testing_multilingual'; /** * {@inheritdoc} @@ -23,6 +23,15 @@ class InstallerExistingConfigSyncDirectoryMultilingualTest extends InstallerExis * Installer step: Select installation profile. */ protected function setUpProfile() { + // Create a German translation file so that we don't try to get a German + // translation from localize.drupal.org during the test. + $po = <<root . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE); + file_put_contents($this->root . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $po); + // Ensure the site name 'Multilingual' appears as expected in the 'Use // existing configuration' radio description. $this->assertSession()->pageTextContains('Install Multilingual using existing configuration.'); diff --git a/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigSyncDirectoryProfileHookInstall.php b/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigSyncDirectoryProfileHookInstall.php index 63aea303de..c87f5201fa 100644 --- a/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigSyncDirectoryProfileHookInstall.php +++ b/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigSyncDirectoryProfileHookInstall.php @@ -12,7 +12,7 @@ class InstallerExistingConfigSyncDirectoryProfileHookInstall extends InstallerEx /** * {@inheritdoc} */ - protected $profile = 'testing_config_install_multilingual'; + protected $profile = 'testing_multilingual'; /** * {@inheritdoc} @@ -28,7 +28,7 @@ protected function visitInstaller() { $contents = <<profile}.install", $contents); diff --git a/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigSyncDriectoryProfileMismatchTest.php b/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigSyncDriectoryProfileMismatchTest.php index 54b25ee8de..b75ae548c6 100644 --- a/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigSyncDriectoryProfileMismatchTest.php +++ b/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigSyncDriectoryProfileMismatchTest.php @@ -12,7 +12,7 @@ class InstallerExistingConfigSyncDriectoryProfileMismatchTest extends InstallerE /** * {@inheritdoc} */ - protected $profile = 'testing_config_install_multilingual'; + protected $profile = 'testing_multilingual'; /** * {@inheritdoc} @@ -47,7 +47,7 @@ public function testConfigSync() { $this->htmlOutput(NULL); $this->assertTitle('Configuration validation | Drupal'); $this->assertText('The configuration synchronization failed validation.'); - $this->assertText('The selected installation profile minimal does not match the profile stored in configuration testing_config_install_multilingual.'); + $this->assertText('The selected installation profile minimal does not match the profile stored in configuration testing_multilingual.'); // Ensure there is no continuation button. $this->assertNoText('Save and continue'); diff --git a/core/tests/Drupal/FunctionalTests/Installer/NonInteractiveMultilingualExistingConfigTest.php b/core/tests/Drupal/FunctionalTests/Installer/NonInteractiveMultilingualExistingConfigTest.php new file mode 100644 index 0000000000..f8429cf3f6 --- /dev/null +++ b/core/tests/Drupal/FunctionalTests/Installer/NonInteractiveMultilingualExistingConfigTest.php @@ -0,0 +1,97 @@ +siteDirectory . '/config_sync'; + mkdir($conf_directory); + + $tarball = __DIR__ . '/../../../fixtures/config_install/multilingual.tar.gz'; + $archiver = new ArchiveTar($tarball, 'gz'); + $list = $archiver->listContent(); + if (is_array($list)) { + /** @var array $list */ + foreach ($list as $file) { + $files[] = $file['filename']; + } + $archiver->extractList($files, $conf_directory); + } + + // Set up the config_directories setting in settings.php and the global + // variable. + $settings['config_directories'][CONFIG_SYNC_DIRECTORY] = (object) [ + 'value' => $conf_directory, + 'required' => TRUE, + ]; + $this->writeSettings($settings); + $settings = Settings::getAll(); + $settings['config_directories'][CONFIG_SYNC_DIRECTORY] = $conf_directory; + new Settings($settings); + + // Create a German translation file so that we don't try to get a German + // translation from localize.drupal.org during the test. + $po = <<root . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE); + file_put_contents($this->root . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $po); + + return $parameters; + } + + /** + * Confirms that the installation installed the configuration correctly. + */ + public function testConfigSync() { + // After installation there is no snapshot and nothing to import. + $change_list = $this->configImporter()->getStorageComparer()->getChangelist(); + $expected = [ + 'create' => [], + // These system.* configuration objects are changed by + // \Drupal\Core\Test\FunctionalTestSetupTrait::initConfig(). + 'update' => [ + 'system.date', + 'system.logging', + 'system.mail', + 'system.performance', + ], + 'delete' => [], + 'rename' => [], + ]; + $this->assertEqual($expected, $change_list); + } + +} diff --git a/core/tests/fixtures/config_install/multilingual.tar.gz b/core/tests/fixtures/config_install/multilingual.tar.gz index 7d00ad0278..3cfa6e5e1d 100644 --- a/core/tests/fixtures/config_install/multilingual.tar.gz +++ b/core/tests/fixtures/config_install/multilingual.tar.gz @@ -1,27 +1,113 @@ -,D[multilingual.tar}r8fSh:okMdYuD"i.ڦȁy~Hj-S2]]f@/ Z6P~i_,&O"ˑE8"r4K4P(Z`u;xB@ ꇻ㟒[oBah9!K2UI`D^D,44̂@sttC~A_/Dg:r#[3yim)9hr1Avx1n8zh ɦ㙢9^Ԥ#Vă+C/s^ ^üE^~HsS ejhwnignY|2LS 22G3ŧ˜Z֙kw?o]!?NPt ~~ 0A<ȕ_YPEe.OM?`o.~BQWE7}ׂMB1I~6Ytִ_>;|U:Ӊg/R7 ߁`!a8Vb @xi q4g)R3 P^Y>MX\wUfvt?ĩD?sXob9I#|%]A)߷95 <#32XptQYCi}wz?"ն{m>ޔ[UWC:j5*Ӏ7;Ba}"w<+FSiҨ?[#S/Ek/YFHN -~k"OBR Ǜ€B, N'} |6B1 t%Q/ -@)4d^uFދކ8Mћ-`?0R)G^4^_1j-' 9ºuܔ yso>)ח'ζ<:0`AҳYV?cCQ`!GԀIqU7lLm2v=W#>4N ЌAg͔kpݩJ5ԏɉdǿfP2*C @ϱ0oҼ f֤;vfCA@NEہIl?:27?-d)QZ Pe -CES +']s{k:cYz ۋaPhj5:gq=X#5ހX?ʹϹl5:f8Ib -%C 2$ "xF9YO{yjǛGEX!,CYd1\"`L1SH ȼޢC N/ZXCr5͐[KXy. 7n>[HXRfI`aGGПAm P& _0 phgP@e -`m_2+@XD?żIc=;{mFO[}/?{aß+Z:@Uԝ[ jUҜ~D6cJҡP#6yI/hƩ+۷cI+|]A80ai0kDU " LE6[K_f!K@RI?jhPiYPebS2\iy_Yϭg S4kYnt= Q?_* ƐxI &@Y1ϊx(S,m]FWNJ`M[:BMo͠k=5L8J!#ٷ@eO?]Z>d!Ciȋ:-BXoQizvQQB.*}}?f}n 7̌z V޳M%~4 AA@u?R~yۿ&VR=-4![m= c\e>zL\`/8} TfBDC?zin AP5D~O^b;)60nj}pr᪓-4ج'0[zO -  :%*+au@4:OMY1hb?=j%؁WJ٭EIWJxTՍY2BMs—3!"Mit u;3Uϙ_xg2B3~b6${=+{B]^OZmT)?wk2[P}:03?rCl(+* KDŽ};:faiACFTo* C#2!Ga[,S}n/ffP/!Fy UM<1uF_?'p34`Sie8;wf(>\Ö'aٳʸQCl.`NH-MJ?" zi8>}x-@Z+FG8(y'%s09%A&Q3܁e鐎|3]UY$bԨ= e%hF:3nzHL|#t`v~Q2p;ԟ|nZ"X2C)^H] B^)E4SLOJyUxpҁ$P^agӡdGyJ"0-Nh_%`PVOYǒ3:͡'TG۫En){/ו=LxQF+ -5.|?@8:303/J?8(D,4YxFwPn~tϢ}~rpt>%AR $Pdhq+?6ڣ`J/v:d;,[SbJwŢ;M=l}]s"4L&R$Пzx⟧ iP2˪a 0Hu^PTJTHv@PCRtfו6@+w]25`3Zf:_;A_leEX]~t٪!> 㽆נ4{moZT{H\G%PU -~Ը1epk_2!pHkh& > -k ~BNP⊳dwB,0* sN}@f$"~dc:h/w}dF) Џ ?B΍<bhM~==GZTPWiIk;Ną*t -+tBK_E-ߒ u@YIxLrV;VWETVG,ˊ8ӏ*%?}YThOW2]~]LXlk}S;չgVmV{U_=?-+?8VУ?l}[کւHe)Qq*-T6x:ϳH#>ͩQ|+ )T\.U@mJ߬vt8iݪsp`E1t9XҟOX6^F? ro*_bEZv8P ( ,@$|$kTxڢz #EioNҥ Hmȧk!PŧV" wyQ6ב?O'_/Ro*_i U H@ -U }$RULo*Pj$/aε=q?4Rclx{|Xu:" -R/ԝ8>s{x6H_uZ0d pY74B,~$kTT%2+!U-4u H4NT(/wo n0^ |n1[s>@b4x1hŭ}>] 81@ɻLHxfc*$h(s iOS|$YŢE-̔bÝVf>jYltW'ޥ ԁ]R+JTF>Fǿ?3L -%lȺJeHAZCTNG+-ct4U.7gq/5I޹t- -L.*$$AtO+Ih_B N(_<ҡR#IP-u,ҡ=elZt¨5r-EPv;jmPnȧkPNJU7% yE k~|fCt!Y֟x$w~miN/-aiD,f!wlqLmn/~D+%c=0m=hOpSUI_Tu[~PVM؆R21(T;3TZ3SLGZ!%t-V&pnN‰dBIbW.-He|~9Â87Hr))9!nNϲlOF.(aRV'n^2eOq5{ RR -cMlc Cw P>ssM<˗Ft=4Jpp?1\Jo9>'+B2>6d|h Y`%3e8yŪL-J(oh\dfCe}.%@? ? x^wBX0@ h4{kSQ7ܝ~E- -kmkydzPDJOJQ?K&E,9i!;rۼ로?tBKϩ(G2CwuN3&";< >WU~0*MuY;þT(u/t^339hdst8z꿥EIXN<JH<ҁ atNXߪJa(ю_Zt쁪 JM/Ԟ˪$,tL_87yQzf՛B]S_t#\?OL?]}c=x1/i`c`7J@<+J1u+@呄&"ß³zR^BTϏwjӸv]Jj,Z3WY/66=&\P.?1>#yRdWeYDH MFš`UG5wMّ<)m淏.ZC!~Y7`l;R™[}M;gé9GKBgBmJg ӡ)@d - Ҳ&n{JU0}ђo)ŰRI3 w"Uyg2ͯC*{?)6H!mdRc[:?vď&C&1S͔Ib]ݎu-jcNp<'1E +~J%6UʊFG _wt( dALJ%1lhY\E:#>b?N\ ]h̷J"=:&S2~_1-ÅZ8mT&ٜHHԮZ KEGzW,#ߺRIaQ'ZFuY/ Qߋ~Sgl(LV~*]ɕāQlm:)aÇ,KD0,]c?YTc[mJS`fں3̱D DZt|:/ݾQ]ݖFwў n֐Tkmkjf$FJC?_<\c:[ObN .ٕ?\_?jjW$"v -Xϩٹ Q$˗ds l^`".ejc#x9q:6} gQUϙ_B_V\]Fn|ŠGcx;CSjt!_$3$43- ?4[ķGC~T_Cu43}{3|(}) -Y !yd|D+yUȜGB".r}\Q@#>#l<QHq ֬yfI1^nR ^w zWDpn;zɈׯ#aܟgĸ=shp|q3}c8i&3B$ 4ޘtW׹$ysw{セ_g(Q0{ZJ8=|D-z$?*$"Kop>,\J/lN{r'՝\[s\| -miĞA"+DDJQBӎ8oKPC poC9xFJjz1=V/sSȐuOP0t -GeoE!" EmxDƳaJݧR举F W!+> j^W=w!@#O1,~xOk_ MKYeiG"9+xlv1C+/ϯT ha>C/65gG>_46B=B(=y! -οOZpx?MF>)2A/y`gme ,u8B,~w*&>oFg"D!(?Z P2_9?eOV]XbC4~z"oc.Ң^z <%ӠIe$,ZPBOr¨tEgׇS$ ?, -~`ThJ=zI0g _^?)yt}_3? ߏ}3J_qlPwr3B'ۃ ?=8M?G}J]*y|s.>""+,z i3"bm[.>0 Bð K+g8ƆHk@g^(E;#s}+Y7ël{N̜_\ux\+z;ѳ$Z0 U/?>~AyD ]gd01k߂ܰ&3D0m#hC'C`z) +i+ńv(ABX/O a<ԗ raLz5͑#\FnQ\o%~ƽՋ&,Jy" A)ǍS8~7 t,9y@ݐл zx|ѿ{0z"l7/Kͨak#BFS+>2=Uj%"+Sb5͖X^x]h\Opg0>c#0< +NO7np +˭{_w?zg-_.4I+f!vKT:^t;^ _/<2^  lhj+r:k*<*\CLHF@ыÕ!t=t@r+eZ' +k׺^E 3*bD@៳, 8ꎆ,:T֑DUG}?!ºև~.~3~bz`Ðx1"θ17ÍӁ_ʋeU,1vuvi'h6P<<sxk+1~κb10J Dž@o+dH̪`40>:eҚ4Gĸ#'t]\j WE)yL`8~0LL%$)Oˢ5E{uaD6 /rL[q=%ϵ@=f?;`h4.5`YnQt4Z8[lhTVas-ɽZmך֝(1nlICa·,C}&ǩF&f=RMYG ,BtWe|4Z~@7Z|i.L?=NU։j*8#"El!N,٣=*Bb8/ q tŶU#mb ʔbZ?1<_|qDLae1IdF<ΐj9R \%Q(\_, d`J ioq^ӸK,^iY^b7,EȣL[}qhjy-Ih*˽Z `F4rY| s`!L1@F3,tVfu>tư&o*F_lXf4h(%ϵ(q#C-3l`<^J)ho#Z@Ѽz;ܨ!h '͋'7t&} H*&|iJ{S/)2LaT$KjZ,δ4*ge< 0PeZS9! U\҄hA=h!-]m>7ZZ#vAwq\b*>w+22!p"EW05aWyn1|[|c5aM.9~-\/!CtcDזCύЭ0ŹI/nF1j&YPƒ Zn)J8LUGM UIX.ޞ О tzs,gMH贷 +GЧVFך&#=8LqMu5ph3Tj[2B Ml !@ȸ5(X&Ww^HxcFT>ޟ>Iܫ\3AEkxO1 xn*RJUFØln wZeMF#.#pBa(U;k `vPCaG6B75 a㩛Bz)tJH tNoK)N( +5]݆iakÜ4l +(dHyzqZs Dbk^P' +߀r. aIg->d"$T@i__;ǻWm#u3]yvjwwzp&4f'Xzi(!Er~OE\V)v$:ВՓvև}6ߠ6vM$tFU u~Vd]:MW~,y1i"!ضWXSZ3ҽƸ +ʧ? R Bov* FƸh0cl>2,u)\\+tYFM}#2v fJ Xč"Ҥ>xfፒ c4tBcQbJqR㳾HP"A=(QB hdFE"KKwu[?7Wł7ʭ'++(xa"1l{^ލǾQ%K]-E$4{0tUA.nNd~r&rf#kê\V~R?m:rADz Y ̠ T9k9,̶>Z$ +%a/0"G_2]GAVcȊ)pc4VM5ɳe[oKyVst\|zrg쯝ӷdp?>yY<#*F@a#7z.Dht5W `1QQ L܃ _87@L1OЁ~Ԥ݊I=O1^Ȝߋ~ķ,VϤYeJ^jQП/,*/cOgqWieM($eRiEEfi[ET*LV(Md.&Y{J 2"K,yW iOANWSAAi^*ݪ)ߙľe*j%"[郺`ʱ.#޿;`E}>ML~F +y3]\Fԋ.PwkbT-f%@).5ALkQEvIo0)KS +Bw|ϛX|˘;5SȉMrN]9YYtrEQ6Zڑr [fň`~ M?J~4T1xJ<"Vb]J_A0UWTVJ"iiEK3wG/M?\pVʷSUo 8Wku`G>vɉ RGZ_F 9+1dbtlc/"+OB,xIDd"J] "'Rv~2dp^mQ ~kG3F O.Zy|Gzns?Cn<*㮏)d?&w|fWJR&$?}?IHy`hlY3b6RAm/%H3 =j;Ωwt'I6r)rlFoCcX['xKПG4!f:yW _Te5ukUY8*80NY,7G KECv"_txFtgDٵ}S=m tL<, q%Lp?񼕌Kט(!6/\1Y*:eC31&=OW0os^Բ`,W +nA( +iJ갚LSdGU,knomZO߹gHWK|ؖe<6{O^n;vi. z% Z$lRj5qڿ$L??cAOTd>GZ)!gSsdThdˬnZr$ŖT?.,Hzx;=_͵xA7ߥݙ~H78t8vwy X-72<lbEȣ `|c<i|GkGDrcO%}>~\$IZ_F{]{lIx ({$qaXZaBRaB*'' 8 +yx%CVx*teMܘ pG_˧dwg_/~o)cɱkb%C8UP,>{g#݉,qRBOcۀ%[c%E0YM 9u[o`v=}twit+Lٺpע]s'ak'~r V[L0)?ꡙ[_^/RǴm6-VJϳ@t dI!3%̛ ^{wO'g:{qw,r_=LyO:W^ t\iFBg=^^#>/(_4'ULgClV =}ˑ4]M3#B\blNDs'eI}}fs&[ֆ%:7i\'h\DslMNڏsh1ﮪl4j:&ߪTHaLy6N6-U-7.t`-~S,2[xYϗb33[1vFndce-$u- c|g<_o> ~Y~ +߾-%,뺥grtˬeSx=Q/FbmGgݻ88̛c;/ t+:N|֣v(Kum`B U_JpkQʾ">D|ɷQk8JFk9EfO +e0 O1V>p-Sȥ'i謇oW޲|1-|9vc :0vB. ;[w?s?! >`+\* ia%,TEh-(k{6[r>|zS Սqsw޵w }ڬrs`V?j-Cm&P|u6xàH%W_J4^p ++IjX]t!g"7$'Gqdsp҅'Gٳ0=kmr%.5a?x3ʅA4W X[f2t*+)\{/%o+#|3Cm%)Pb:lu)Z!N?}# a3tϲ7/{ iʁ*~gnRP|/Y[ߥ` ::%r۪ Y:yGFOhktu& qlo?>ijt|6{WRDx_-4_V!їvh3q@8SEϭBAP ӨXμHdi8"NH L+=Rj1z]KvriJ#cҨ¸y])ybX['2?ζ(rf;0< 1t};~fDVELe3LWw Vܩup= +YX +c2c 47 +7Irc?aI59sIay<12Ș'\'4An^!uto 3?BZRF^ 8g~f{Fȁ{+kE +$WT[)LŮ3!Um=WiL|R>?e #?j~<̔߻ڋAy}݉kv ]":3[ɚZ&B̗0A})%A\ʑQsJS(ʜ[bp^ot` 8VqQk';c]wp5:gۗ_}O8ڹڗYsw08ݸj=!yAhݏ}ok{)a)sgJ&"G/.p}F[}DZgU/n?+Ӣ 4l`C ΂CUR*9H:[%QS95Y,w~'GJAFcW_Lmp+9 +@&hsK`Fs\.Oц8fAUO|jwvY/)5j¿%,Ttʼ]❹׸;X>nsl~$vtn[訇vi(I#bJIGH2XO4$! `&r5N| O vI/?['cE7Cg~Ksil !<*@3yEZR=,D,"Pg-%Y,txOG]p^G[}:Ȗ-Z%%"-: ;D|쮶&) B+#_xՠ" t-˴xmno:Nl\M::Wa[ }ktgpڦyfO͞8g\߷QƵd͵ߢ=fuL2zٞ|hkŠ-/1xULLj22?y}g(6!GbOq3;A\\Y +9Я?tكĸ>0]'f"G |݈ok\i3+sL5ګ$F !"ygAn)Y߹3ms6͝9i??@8ظ>k/lLhbz};x6'K 7yYe- + tXMYəO֑$P c6<.But+_[w>0ԴK;J-@e&~j'gP:FA\=ϋRZT͊谒V4)&'Y_w^rt\{ܕwmzm?jlV J5^14:Y͝NTEaD^E,J;$D1",=ѱ=ߐ]r\|Ò &sXmysi._w;spJfD񛜧~źmv;Um|FANWmeE=-5oV3u0<[J[ \8ʳ9az K92WrM +q2JE+](bё;D`F4ԇ76L|/X2,f"7jJ'S)Ϣe3ԙX)!6^`4|LC?r4 4Rf]x N< MifyrBuMתT,"ݩirPT25WHPݗ 5oU_PK[Uƾe*j%uOZ[2bsN-mqrɠ]}3A)K6@Q"uiN<]ـh1]  +8I FOZaAl1irgL,cb3==khGkԊ=w~FH#\'&7׊ei +rј3lm_l.^yj{K<Y*ȅc ,*hdJU\)}LLZn @0\҉Xp}(a'! Ta+s唂1xҀO77L7٧qR[ُ<fJquU1Npq^,{lF)Y#YtOĈl4 +mתU ќ JHTK G4dElW,:` +u][g_{;/Gkg7J= +=«AQKIv vW [ЕY.</6GGlQ- u4SG¿ $D bgD`g el;d/{}zrw_Nm_9 +},/ɒXU_JHY"ʪ-V3yy-E +'YFʘ% r>b&n:X'>1+s1 0-wI?=@xER'@>A_)'7&`특dkRΠbg| 6-*hz>Rxe^+q ;(%)Ff *B.nLRH?ʽ$+: CmEpec,ERB.-,`.PL8 $ @JYM4t5FyO $}hI><(~䨼`ؼ~Ū@!ދ5l1LȾ=r VWE-A7~-ڔJZwÆylIzq=u!Uœ3dlkFDѦRǕӄqbHxqeBQ7gX^O*k { 3.(%Շ6(6 +jqyQ4E $rIU fxqrmƲʵ~N^[ߛv!*O$Ta u\I7G楴 %dpfH~_M?Zs`f>(Yr}Dx0X{dN_"hihɭV?Tg,1cnЄZݰMЄ@Xj%p4N(PY-Ƨ̍[,3WW/u +y'?I/` ԊÏy_C7~?d*-XiSԞzh(:?2Iz3da + ܛիf41E!E)k_ f ̒$,n$czw͢K/jrDplyPDj > o~%$e3JywPe ~尶N9*%'JUYF@g2 +#zQ/y>;tYH7 #Lv:ry8]jჼ+|?"16_ZEς*'𿌐pP5UQcYI8VZu4mv^'O]ِ*{?c[s"Qt4gusgǩQf¿RE)?Nu%V%@ r(ۜ ڥw U;/&+z^VꉛձEL Ohu_wrkkC{_T +«-/#PeSYV5^bU%ک9ؿ9p)WQ5'|/{ ͣ(r?]fƌ!#8)}&@C)df);Pbk"w')t!.E}Cdj44Y٣qg9hYg9$?,Qڞȴ-@omŮ ESZ듞Q3$c`&|.eMUI|"?=b:;zDJIٛd;6E DW?r0d;3sWk-24,veѴjDO &u 5 =wkT:I)e 8& AMC>cDCX@?p}n< ^8\D=&Z<* ߕNEUi&,TK53؏.Q^Tߢ=]R LQ- `UcBXOnQo? Zt[eY2# Od5j:mx@~c،ӝ'%&4oX X@ +fj/XAAPd_7LB%n3s ÿ)I?3W 1=7ͣM>7ҩl%-c&ɅaŁ{ V}nR + ﲭ>DXZ5k2%Z?͎ٵ7,?Q`Cl2(0L1N^]] ,O T+$y}mj&2ƹSţG7>NKdҚU;T4c"v[s\k[E4\1457tAega:XO{hOTVFӸt*AFA`3W5N"̐9-ʆ7Xe8qREo/- N!*pw˷J3 6# A6=+R[ nښ-ׄ-MFդC>駙i_46Wbl/,{)hU mâtv}R9_MgoqP kP=v'e u+TZ$띏wWukmth6}4cUW^k ;*N"V9nZV^CBzBfh_UD@?hTWx4H<+p:Er|bVn퍫@}ުÁs۵^B +!sbƎ?נ]cVa rs-/#YVriK"j`zXGX#,R2 C,.RJ/vi/uۧα Gq 2?d/-ۄݵ:a|1,<h-_j_@6 EQg%UwXMU9.ifJ`Ǽ?yh30t]7qt` ݮZ7Ͼ쭤r]dkCJJ<­ %ֳ}|(Iu9R|ɹ CN6tB6v~.0[I7;'+:y'o(?0F4\o2fBVY2"iw{bx`}{ <5x,*)Phu$ }zƜ5v gM% 'uѤT53rGv^Q3HPuh+!>DK4V}>t ÔeG"Ffڕ_E킇jcq9"p=US;`?_1 %(TQZ݂=me< +zxad-xY3h %Ft˱}u}+]^\ab^ lP`]8)UIjK '[nAeeI( +5րG5r976ݓ{tnxk=[Ke{Çtݯ 9'&@'CG.JG^9bXW$-/#P|(ޙ,hd)/gy8{о~amZR `> +)b+@T9Vt4JY]+"IiHKtx} wt`{LzdKVGqT^sfh T_ >ѫ,bay2 "hLrF ȸmy%{-H7O*l:j*l],t[Q͸LG P1$\FtwfሊVDSJdv 4T-݈1yMoP&lVƵ@=u~[,*8N}ȵ]pnlN˙b+IY(ⵈ9m^_.v +hVkK>+$YYeq,Kނy:!թ"RSfX4+1#40R1Hᨒ!|r?gūv0, J}V tCSro#-WwXƄZY[V,tfU'F@en2]LMΝw&Q!Vl `rdOȯ崞FkBfH}v#6bj  eX!0 C׆uH]P1^i(sZ]\]޷aZqMo4ݎA)tƁ7죔'R>R; f2RvCv˞]iԅS嶾 =>U}>h"%t!㨻`aF2#  MpӡDkt^HQb1L-3Y&5c  n^Xn-γu胱#ޤrJ:z9m^NiNDW[2]%wB37ΑJ!܌YiE-mmhh +U4V= +elԼ |%hvE-Znr݋d0, Te3Ss% ܁L!v""paX|XLmР@kԝU z2K/8<ڞL{VgE{V,HQnoh}ؑ 2lx+rpExWܸKt"D*Z L;bxAS"ڶ?0@7MeE#W-sS&33aB"$w^;Y\ q,5醮gD{FgD9=#3A߂s jhES5amq2ШEwZ`fe崇D{HCb! FR9ڑ)(l "aRn{#^ȗi"ؗעt9"xi=QnpIŀ,N*w5^ ЦFФHS5Zh爦S7^T M=f(M¤z;^jr)Mї-\=o~M84Dݸ~/G8`#dU ++P:\5fAtDHy [+)(ih8 coe/F/.Fj8þ O%-Y9bVSIEuK?YpEy)Pfp#,q>6mKSJՃ4M6!WjSZv6ۺyq#O V5VwpK*[@XU#J;n_ntw%W848d3JM v~0?>b:_@Nm%4 0 ״T%$W;l +SZӹl kVF9X# @3Z/<+S ;iɴnt ;Vg'ݰy*7ܲj;ef9"D!UIW6urJ,qK|Bj<>dNR kpm>&jTv, T{dqpbMT # =b SĿHi茛"D % MrXnvYQT o\{]Ȑ +hm>WĂч18#s*xb\92ҝ:#dv@QޙeQ F쥺~BKl%g%tz4@!uXX'֔Iz9cŦ0:"dZ_}&*샩jp5=0[ڻCl=v3YM#}>%2,?FIwIaעV%ڽ8*:kB-g~ S$h6PD8W͈]5ՠV]:vP@Ag +5l\$/'HreQt^Vmbm*dKtNam8U0UPT`g{;P?X[%6v'|ge;Yu`enM}9[!ӫbeRKR2]LGg܍rw|?~%!p^;j}}!6` 4LT=%Qh@5UVTȱ:Uy]ueq2Ēx8|97/MH9m Z{(Y][$/Oٵ!Rjs8 +V{?#~? U_J/ʊ:Z_VX(UP?QHpA&Sxfׁsx[bw_إ9=L4."C**E?y&0T)¿Ȧę:Jq*(=ޅws_N'Rֳv%xe 蔠.Gg4XAcuJI:rQ,WC$O/H^X6C(1Ꝏ y}\i$\Ir}[}fZ)b_J("O}7n8[;~F<>s8M$3vZ=y5g3C0d`b!1.į[̈́jم`!`:`}n]'QN=SܛKmx$wƖ~&ssGx$Fb̾"-/#?SUMY`i+9jXp4;';M u_w36vm˻48*~E&@s0;3*@_5m:z X:kBf(qP[;<wohIJLw{8a`ssDhO}ȊA}]hBuvCHp%쀏4?,Ե "*GT'Dƹrf?_eRQy ޾S;W\|ŞE}d(hOݑn 6.v]#P)-:U?XE49f =@DW<"h2{DJr_5V"^4nzHg2bstwut_mY-Bu{8̈́^jH&/DHeoveE&.L!Ao]i`lUOlTI}aE\3j2!yeLFH-U;!\!lt(?dl_R 0[R +T OHJTi L.R + 0tchs v>3[{x6s~Fvч?$!}CA +៙Se}}6srrI"@&X3;⇯S760Z0 A?/ ]|Q/əg<^z_I_\9.="r $O?ϼ],-LOa(CjVaP}x#pd-AX,L#8oX<9cOs6t仛3ż6]1ܸ;84nmX= Xv{~\v(/(A(k=d@f¿\@V{)¿K< La%A,̪j) 8l-R#:1eb$:sX1zGb> ?4G()ahF9I:" S?XAf[3PdEK[籠TB k."9j@L~3aA7/:qx|jueKߓ=sz}8ؾ܌HwgkBvgMBxR)\ !:QrXޑ5Vx5MKa[@Dv6׽=z: +Y{um}PҖO/GV;Q/|v?G'W%4we΄W=RoYs,/(kڂ8^rsAWnn{h(nŨӷ̫cxh9f@oɂjG1SnOsiU?'IwS 5/URUEhZkPf%SYSdR(m[yOlI7Qpm wOSwO[K8:zx<8wob&wonZx }akV|0yQi志R_4ޑx֑lV"eSRTPwI"+!$6o"5s\_zCb(ېX,JT̈́9q mcBY !XTϽStH=]Ȗ2 +U bR]dY,4tERtGthH?9(cdS 0_iIƊi,+ .y)QC ZrLJm=7Rp3œr:7oy 9??0cBwR[Ճփ<7w}X>eĎOOY{vG35߿?ۺC=z!@`R+Ev8".jϫ-qK!t`H?8a>ʍ|m_v}Ԧݫsu,/s5Vk9~cwߟ?]J;rCkE:!"[ +_k,)PwRj"#_X 4h˯;U󋂄7ϝ[va_~r;gæIۣMOGw+cW}ጚ{6c `+ihb=B[ "DKS|8A34! + +=dq5+ +KySXGD'q/[n]+#f<旋hXtBl̩TVofI2+D Ȝ)4B<VL&.m [q=%ĭw={\ua:! +^=%fߍ 3c|;D7QDaS3bkoJx~!oM@4x~e|$~$I :UM%o<; s;m vn IB+$6R.xpTIRKp1?i֧nt#_m mz\V,UbW)c`{;Vȝw>r!VdOȯdbzp -][qu3qΗBzeg;^>OA[_hIn{eG:nz#=Hf_供%Z2jf_ KIY0Ja[8~U5юk#(FIv/gaFdu͍κSϷ F ڎϗh`j뱐#ev &fH&!hG5J)Ô?XbZ 3dW6Q_0u%]ȅ0;@q9W?e8eqΣRW :NX)Ȧ\h9 m (=>s5a gSW=hO]WR0hAyD+<v8sJ7`SZLj I)Փ%5ѮYikZaavVJfy!`JCYiMtJeݛ&W +QΉA'{"J4z?M[Jsfvq|UQDŇ; Suu_)1 `#coa/ D6MƒXΫ/2ji@ܤVi h̰G?h#uroB yѼyrZO㓎fjO0-XXt,q&_2mJ,+!KRŨJfb_3AM%EZ2 K=a9'`v;r9uylsh>X)xBP +A) 쌫$QG|Z $@xWK`Z\kBvF d  ,~wJO(=8 i,:2Uy*yЃ$|dZ(Zɾ7CE̠=>?˛F_o|C,*۔>rS4(W5z&(X +sp3v_9D\Rkyx3tx&.?Oñ)IcRzV|5hߗ>Osۗ)NM+Um&ʈ3C`NpL)ފbJChS6l.`@FVatVeesx|ҽ+R #]g[DknҫH|8Ń%;d5$+XTF} UH<)bdoEL&DXHpksHxN:hIЏ-u [_@ +n5m-^^լ{C[ $\9uBݵ/&FHRM,7lD0[v1D'p l֟h^>BaAɞ qS|אOG\ +_w%<%}W&5כF&qrw3,G˪}&/G}J]Y ;ݞ^t`wZ1ׁ֨ݻAg9s$7ltl7$e.V$VOë׃ӏ64~n/~|>YZGh E-rkS/zZ8FWmWJWp %@jhkv7ߠ q}\BFP]oGVd@HG!G=!RWWW ˟π{!ݵѬnCG߿E%s\.:,6ێm okڔrs"mZk"B͝zХe&I0!ޠ +^b q[ez#4\,{H{A_0hJ`\rsgDZ%+-# Lc*R6cʏd\STiQkqm9FdJ>8/t]qE[ù r-28nM^%7Dz4̂nUl(~QP0ty!Z7=!&ߤ G'F?ϟ İ8TV/xs%[)Rb=+{iP X#+E%8b%#iLhJcU߉7#=JH|?#($IKۿe怅w+0mܦhYv5 |x26lMIa6$% &ue!5yV#>`Nj(:HjED+o_w`ym=]:tm -D*IQVz~]h%$`wpq,׵WDgqV`l@E-#DgCӗ80EvE!g1̵ԝ *UV5b$>aa^1eqGe=vP|̐:R:Aи: ++iM?B-Rxv]I2 y˫'Ѫd4PlmRMŖMMy(%o"\bOJ:A~r6L`TԴA}رA|kgbf?fUU;Qnn4-g{GbOOm'=k{ͳ[?owb)?K#?kz929h>~r(rט잡2ou[Wh -Kw#namuaڰ>jިeJ11NA{8g|Շ7G??9>8|Pp=x^ ~\pi s3.›dC:k;g^Ďwb'Ikg}BG6]2Z ^s4[z v0hT{^Mjw(j[N_Sۙ(#9`:s`;ݍM/fN6h}Gs4T bkT:&2tK. {`>~]zb?=dN$X̑2ScGi77(Օ ոNcU[̾ƫOo_<_M>jju]N:>wDjțT\0r% .0 {}Fm;M~[vgQ[7um~xNNY'Oj1x.~yF<%CΏ_j芰c*;}%F킰1EU5DC2Ac왠GNކmFVt`koM;Z9N |$S Ϯuɼ2>OGB f8w- er U4HӼq&p!0/H,6F I"weOd. (A4WA4zu`~ч-`"q _pwh ŽqdTq|\G q;qKÂuGSjAb^ U^Gnuף5}iMhhl&=aVMI_{}xӽ_j{i88nT;Dɇcip{6q*uqE@[W6 )vF]/1FF-9\H6{Gc|.|īх\{h;vK:2=YI`9nGTCCMh:b^=j u8lWi2(!?oyfɳؽ~䇏AJBVHCs)5&HHCZFRKwп ߳\N&Hď뤓f.y9O1faN>c~/Ϗ1TӪ*LR_=ggj?_-NPJW% $?c ^@;0p*FRo-+!Ξ 4Vm E_Pk-> Sb"q*:?>v :@J_ﴺbUJ(6x֏Bs jJ9r%Zg3'y#c=<*S>+6.Qت>;ʱ▽17 ]-x$Jip/WHC)@H1geo:Ϗ$xc |FnJ̃ vk~AR|/~lMw+& [+2DRP?&^ N@+G@ 7 yL'<1{!"?~(ޱ*ZX薔k9A]3O=S EOGg~ӶY8qBc0M9(ɵМT$`@&X%y}D2+;7ܶ2;ͫUw=e!8(mV>*E꒠+车ZUB2/GT)^贌J"?S2I5BcΥͺv* R +?!4b+? j^?M +-TcF:@X!RUJ8TF?=_]wK5?1(Mư 3PnJ%|$PUTv/Cw `wBE2Gg]V-JH` `Xw0wWc5`͞ZWBI'fhS~<JX݌U_Pԏ[#\]kV~ط0xPUw/3ϷqZ|^R)NAh6m_ E<9[_ulA%Tx@:90> ~rDS/5Hz0-0x"^͝Oi\.5JmӄAi(N=E`2vNC+ #"s]h/"=x#z`L +i"Ѩ1gT +'=@sߧt>ê_ p100{_֟,kjss&l3eeϴg8xvJ=6VwLf?*HLǛL$_МXxF;sCBWAQq6’HB투JM{\qRGQ^W\ve2{q_ %.%x3i!t9Lgq,D|M~mǴ$xr݈.QVa}$O}Dl$W8>=UXKƐ _Aܷ]?{dcP0.X*XXeٵ{x\ 陟c|Z6K&pMc PHO0g?N0)w%#ߎ:4jUgk=Կ(4*,sV5~,X+ xrD ׉ mCR (Rw=_JвM{_ t35lWoK0oG)mawdqߙ[/zKO-K{-4ԦR;A` +_8O1WD> 9]_/34!5mm;xɰ$ߨ̨C +$~!kl*s>L,YGv֍Vj#Kjfq<0cT&lrı|6w#V46dk.^wGA4# bgzֲG~ LgyhYA`Fqz P|*NK0G!HpmfU @Y[9K$[*xyDW#ëwC[?, :-X ED?l%-GsTwF*CE<8~{hgˮbvS?VB4Њ_fzMd/$ x% :I^u/8#XxZljzb_{<ٙ~_͇0q(I !6@%COjh>xsT\JZGS6 '7ۼ@Ah2[(1ejZGjfMuTœW dqh[oķ +0%jq[aތ>j@&]h5{DH+DMHU*-`h?BXSvFA$c& +ϷĔ~'c'B]E_Ǒ}uqN +VXVG$j ~/ Qh 튀DkQo4a<(RRvp +8pPә >ضHq,{RWC(VC` +J2t}ܹfJb| +ƽ6t@Хy|# H\QHNISr+1$(Idq 1oi! ezӡ.t魯C($)3+.I(pc_x>ѐL }_OLYW }bʤbJ)dO@e"^AN˨=VwA`i+ҀkhMƜ%cd oEj*{5vtC,M_ %/xUQ)vܿZOSJ(>|o yIO|,*s5&o8JɁOr/.W;U_%e6j&ܵgs=D`΢Nx(!~N{Ju-@ԕ62?HT?7{JWBI"P fдG6o fiP(m(jHëMAw6W J) ͋:JWBCb-Lo:Cvuq?Um CL7g0JWB!hJOK+qL*H}}ϯ'?}fBApEK1"=b4BtA$tS.u8qF;y0,BoͲ3RNN:^z0q),.&k9XTpRX 3Ef`f1q&#`\L'KN̵_MOGJWCF[$Yt=҉!s*qIRaۡ8X[Q h_<&>}h`wap?޵<3 0mޠoأ Zs\.wEh'1+AA$#Y:7%ب"r$V%fNzml'v/P#FO8<N HJ+9JmWs=&嚰8ñ$:A+ 8Ez +8W2?ŴO[8sm?1S5O l,@+J(GcA{ۈ Ab }@mY߮:KoWAS# \)g𿚽ZWBa)RH"E)Rh \ No newline at end of file