diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index b8f472e020..c35008ad68 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -455,7 +455,7 @@ function install_begin_request($class_loader, &$install_state) { } // Use the language from profile configuration if available. - if ($install_state['config_install'] && $install_state['config']['system.site']) { + if (!empty($install_state['config_install']) && $install_state['config']['system.site']) { $install_state['parameters']['langcode'] = $install_state['config']['system.site']['default_langcode']; } else { @@ -802,7 +802,7 @@ function install_tasks($install_state) { ], ]; - if ($install_state['config_install']) { + if (!empty($install_state['config_install'])) { // The chosen profile indicates that rather than installing a new site, an // instance of the same site should be installed from the given // configuration. @@ -1508,7 +1508,7 @@ function install_load_profile(&$install_state) { $profile = $install_state['parameters']['profile']; $install_state['profiles'][$profile]->load(); $install_state['profile_info'] = install_profile_info($profile, isset($install_state['parameters']['langcode']) ? $install_state['parameters']['langcode'] : 'en'); - if ($install_state['profile_info']['config_install'] && !empty($config_directories[CONFIG_SYNC_DIRECTORY])) { + if (!empty($install_state['profile_info']['config_install']) && !empty($config_directories[CONFIG_SYNC_DIRECTORY])) { $install_state['config_install'] = TRUE; $install_state['config']['system.site'] = \Drupal::service('config.storage.sync')->read('system.site'); } diff --git a/core/includes/install.inc b/core/includes/install.inc index ef4a161383..5ba241bbf0 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -1086,11 +1086,9 @@ function install_profile_info($profile, $langcode = 'en') { 'version' => NULL, 'hidden' => FALSE, 'php' => DRUPAL_MINIMUM_PHP, - 'config_install' => FALSE, - 'profile_sync' => NULL, ]; - $profile_path = drupal_get_path('profile', $profile); - $info = \Drupal::service('info_parser')->parse($profile_path . "/$profile.info.yml"); + $profile_file = drupal_get_path('profile', $profile) . "/$profile.info.yml"; + $info = \Drupal::service('info_parser')->parse($profile_file); $info += $defaults; // drupal_required_modules() includes the current profile as a dependency. @@ -1102,6 +1100,7 @@ function install_profile_info($profile, $langcode = 'en') { $info['dependencies'] = array_unique(array_merge($required, $info['dependencies'], $locale)); // If the profile has a config/sync directory use that to install drupal. + $profile_path = drupal_get_path('profile', $profile); if (is_dir($profile_path . '/config/sync')) { $info['profile_sync'] = $profile_path . '/config/sync'; $sync = new FileStorage($profile_path . '/config/sync'); diff --git a/core/modules/system/src/Tests/Installer/InstallerExistingConfigMultilingualConfigDirTest.php b/core/modules/system/src/Tests/Installer/InstallerExistingConfigMultilingualConfigDirTest.php deleted file mode 100644 index 2198d1f650..0000000000 --- a/core/modules/system/src/Tests/Installer/InstallerExistingConfigMultilingualConfigDirTest.php +++ /dev/null @@ -1,69 +0,0 @@ -getConfigTarball(), 'gz'); - - // Create a profile for testing. - $info = [ - 'type' => 'profile', - 'core' => \Drupal::CORE_COMPATIBILITY, - 'name' => 'Configuration installation test profile (' . $this->profile . ')', - 'config_install' => TRUE, - ]; - // File API functions are not available yet. - $path = $this->siteDirectory . '/profiles/' . $this->profile; - mkdir($path, 0777, TRUE); - file_put_contents("$path/{$this->profile}.info.yml", Yaml::encode($info)); - - // Create config/sync directory and extract tarball contents to it. - $config_sync_directory = $this->siteDirectory . '/config/sync'; - mkdir($config_sync_directory, 0777, TRUE); - $files = []; - $list = $archiver->listContent(); - if (is_array($list)) { - /** @var array $list */ - foreach ($list as $file) { - $files[] = $file['filename']; - } - $archiver->extractList($files, $config_sync_directory); - } - - $this->settings['config_directories'] = [ - CONFIG_SYNC_DIRECTORY => (object) [ - 'value' => $config_sync_directory, - 'required' => TRUE, - ], - ]; - - InstallerTestBase::setUp(); - } - - /** - * @inheritDoc - */ - protected function getConfigTarball() { - return __DIR__ . '/../../../tests/fixtures/config_install/multilingual.tar.gz'; - } - -} diff --git a/core/modules/system/src/Tests/Installer/InstallerExistingConfigMultilingualTest.php b/core/modules/system/src/Tests/Installer/InstallerExistingConfigMultilingualTest.php deleted file mode 100644 index 60cac03df3..0000000000 --- a/core/modules/system/src/Tests/Installer/InstallerExistingConfigMultilingualTest.php +++ /dev/null @@ -1,24 +0,0 @@ -assertTitle('Configuration validation | Drupal'); - $this->assertText('The configuration synchronization failed validation.'); - $this->assertText('This import is empty and if applied would delete all of your configuration, so has been rejected.'); - - // Ensure there is no continuation button. - $this->assertNoText('Save and continue'); - $this->assertNoFieldById('edit-submit'); - } - -} diff --git a/core/modules/system/src/Tests/Installer/InstallerExistingConfigTest.php b/core/modules/system/src/Tests/Installer/InstallerExistingConfigTest.php deleted file mode 100644 index 4ea2c5c112..0000000000 --- a/core/modules/system/src/Tests/Installer/InstallerExistingConfigTest.php +++ /dev/null @@ -1,30 +0,0 @@ -translations['Save and continue'] = 'Enregistrer et continuer'; - parent::setUpSite(); - } - - /** - * @inheritDoc - */ - protected function getConfigTarball() { - return __DIR__ . '/../../../tests/fixtures/config_install/testing_config_install.tar.gz'; - } - -} diff --git a/core/modules/system/src/Tests/Installer/InstallerExistingConfigTestBase.php b/core/modules/system/src/Tests/Installer/InstallerExistingConfigTestBase.php deleted file mode 100644 index 2f42fc8579..0000000000 --- a/core/modules/system/src/Tests/Installer/InstallerExistingConfigTestBase.php +++ /dev/null @@ -1,100 +0,0 @@ -getConfigTarball(), 'gz'); - - if ($this->profile === NULL) { - $core_extension = Yaml::decode($archiver->extractInString('core.extension.yml')); - $this->profile = $core_extension['profile']; - } - - // Create a profile for testing. - $info = [ - 'type' => 'profile', - 'core' => \Drupal::CORE_COMPATIBILITY, - 'name' => 'Configuration installation test profile (' . $this->profile . ')', - ]; - // File API functions are not available yet. - $path = $this->siteDirectory . '/profiles/' . $this->profile; - mkdir($path, 0777, TRUE); - file_put_contents("$path/{$this->profile}.info.yml", Yaml::encode($info)); - - // Create config/sync directory and extract tarball contents to it. - $config_sync_directory = $path . '/config/sync'; - mkdir($config_sync_directory, 0777, TRUE); - $files = []; - $list = $archiver->listContent(); - if (is_array($list)) { - /** @var array $list */ - foreach ($list as $file) { - $files[] = $file['filename']; - } - $archiver->extractList($files, $config_sync_directory); - } - - parent::setUp(); - } - - /** - * Gets the filepath to the configuration tarball. - * - * The tarball will be extracted to the install profile's config/sync - * directory for testing. - * - * @return string - * The filepath to the configuration tarball. - */ - abstract protected function getConfigTarball(); - - /** - * {@inheritdoc} - */ - protected function installParameters() { - $parameters = parent::installParameters(); - - // The options that change configuration are disabled when installing from - // existing configuration. - unset($parameters['forms']['install_configure_form']['site_name']); - unset($parameters['forms']['install_configure_form']['site_mail']); - unset($parameters['forms']['install_configure_form']['update_status_module']); - - 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' => [], - // The system.mail is changed configuration because the test system - // changes it to ensure that mails are not sent. - 'update' => ['system.mail'], - 'delete' => [], - 'rename' => [], - ]; - $this->assertEqual($expected, $change_list); - } - -} diff --git a/core/modules/system/tests/fixtures/config_install/multilingual.tar.gz b/core/modules/system/tests/fixtures/config_install/multilingual.tar.gz deleted file mode 100644 index d43aafa1e5..0000000000 --- a/core/modules/system/tests/fixtures/config_install/multilingual.tar.gz +++ /dev/null @@ -1,52 +0,0 @@ -",X}r8fSp:QѷX&,˷n(@(q3m0`* -E5 # >M-RN>u^;!?t$K/!ԑ -aAx2Cp~wr":hhɭȏ,7~z0)~ʯפ( BR 2\|t3,SBNɓBli!(}>tt|;K  5^1XA4 Ce5j ?C0yyzQ,K-Q+OaU~#1̦_cvJUc eXr5OX1VgOESԋ4 Zrn7JH~ni+C'-y#Das(BE?+J9@g@82Ԁ!hDSuIo&aMP(BX%Q9eœN]ϹvcK_l}vb` MwJ^Ku~6FT=+t}(kߛRC)tK,dBH4pup'BO8ëy-Ôo.s)\ z%(lHU~ǬIUoOژ:i >=| -t, py:+,Aֱ1(2@HҿLtyeCs@wKp|*k٫kfAN{M -f?>EŧK_1 {? ?hϳP aM@CJs(GY;5yao"ÇyStx OL!$g,bip< p_?$74 *f$Uu14Ry/.6mzlyc3m.wJyᇝ`MU 8<3|??*D<'uej(kxnUJצ5D{{qumz*6Iܗ?w%h^:h -w ?@p$^Yl -iQ5h:QJYm;Za d@!t |/50Yeb_ -4uovS{{?USv:mP1bgS&FSnK^r_ g?7$ 8ZUӈ @!/2:˫~L7hb67ف R#kP8Y /8~QGaq-mctW>cZ*{6@fl+Z:DEܩ; n5VAs>if YV&' F4.l "ϐ濨Iʲ`H?o7rʙWǏTлɎռbNáC YXw`D.vH{%._ Gs@VI?jh"PETfSﱆRyi|P[O'ж -w;zos&~?$wFL֐,&@9I߸AuYl]׺T3R/Uњt.f] s= G~]D?kc?]Z>#Ck$H:0bhRu {MQ%>M]<  -9I`:^[x!f3<iO%` B+m<|fU_xhw3=ޢg'sNrs2U͵=a-0]tngUONf =5P7!kD%7KL];meq|_-ЙJS-<|OJ|[?sa?$W+@t"TNꀪiuQ!Ue`ܷ}ieԁ` ->(eX՞qj< "'0^H /L$&E%6SrDh u0_JHi$]9ĝ2D* _e l,NL$#?Y}G#[bnqՇcyNQkEcol[Z XL84#E s )}S?2cƙjGK.vA3fcTP\0+C}?~Dԟ~?? K{ Ӂm#Y`5CfVn=6ꥶZp,/UAoXtLEP0F\bX8$ )4K -,Wzuqw[5bqz_8RidDt.H>Œu?bw\> R$hIU 0Sg5E#1y=A6+|?vdox.{w43n\NkˀGrb$sJ?EuӁIp}$X0W=<f^qM;kR.'s"<?| th 8sϚ qGL8CVaSKj馏4iI/9LRp(`P[N04i#&U"W!>ɔY׳ ?(8w" 5]PE ^/"ȊbE!j$£_Cq2Dwز2$\j*|6~P'ɀ~zGf,NOzL= }tXI>AXA/UJ{Sw -q֯% - -ʑo]}Ǖvm^f|ywqN]Hj?fW XXeV S5``]OUn\zzq0JA*ۙcڣjPUV7y!#2^^^?6Y5~r?6>96~.Xw -;4?eM"u,n5_Gor/ ߙ^9fXǶ~@D@9ziދ/FV,7`.~T8C}.i?3 Dm9! rG=ng9:3j/Edȏ?6Q ?A]٥ӡ'&WS&+ /e?F񟱽'x_׵r-GI'$>3:j*VQ!4LdUˑ r⾯p{t5_wC -zɯZ(ςM'ΠFv{AZݢ;1+W#O3(z>s$}:y!3{%QL` c30Cm_M]ᮃ.>Ya, bw)݀BeG JQU<@DPx?^?yύo1R?f9J3Q57[cO iG? -_&H~|'&cO(yLY.Upon.~"|&ۋ.yl HWx@e"F4)1?ZŇot#_[~m]PӧA ;IZB9Dv~z|&ew|ig^h1G -CP@H6Ǭ Vm{yLGn?!&"-J+BZ%IW~u[)þ9ڈk nTbMe-ߔJ4'2O_)Z^Gn w0V>sgtWT`E yD&9nwN(!:Kh.BmA A3fW>xhC^y+{濍E?=l_;a~$e&ACsu9#g4Mv -lw@#l.qvZ ;(x.9/CR?*zרGBZǻ+Ya޶ }yoEq -4}h8WK7I#Ü/PaV&nju3YxFY σ]ΕދtTfܕLaq{h ufn~橨_Ś$'Ŧ~1jl5ϋg7ܪP<2<+y! ߙ׍mJm۸m -FĉZ޵eύb>*xԇg?A$_8:_ϫd ˜ĨE"0yh*+^Qzi`T{Dԟ,=f3Z*KykI]Kt> :##rX*s@*U)ZLC|ۗ_5878N?}Y*m R{L8s PE W `y;fhV⢬#AƝz37m\v9i #[f9@[dJ`da4K -%N#j@Y 'm Qԩ͹5Yc1OBlY ~ O ^q-w?e"3@gϨ@dE]- -GXm>U-Z4lpY]Y3ʬX_56~oa$ N??Gvϲ b(ʐg ȼFYCU^w//޲ctF ]4gS;B]aӿ{'_kP$gp =$+k$uDp CH@ <iK X8*CԿUԊi-SU o:W,HzGv(۠}~?] R|j_PP ߔ/㊂9G.u!Eҟ|dw}tdYpC4[M2p=q,ar?##׊79)2}d#' 3;3B1+iO"҇BBv/vo,HGKعz0ȅEHO~9fo7 6s,!٧L)*]D7QO4-E鍖 {lC MU1jTVUjKSsߌM43\/+d8e:(XϮ}`ZiTezбhLk@  r 6naH[u^ρ <_|?@rg hy `5NChIpx\;`{D9md}<ܴ#{fBRW)/XBv9K0BQ[J( D&nǏNpp𢔏`)bKҘ\_w;KT}Xݶ~u>li~3A -A.9:3;1>3%AEJ3ӬP3(#Os}Sg6Ho!>'+"4>6d|dԍ88D/ڸ`h\bg̲4}.B. M_,x=%R4 a}ؽD+F]Yqe?)OvJOJӻ?6 -x$ -1e>rBkAҮ!TQȍ,RE"CW>:#LQ듿> ol"mڃiI^s^Gq%Ų#u?3rљ]??Hx -@F -x(C H4yMc #qgtubiRp;Ò^+3}Ӟ޻O{!L{ޚ$|D$q&Sg3I{?+&HBCAHU"C:-(d'"H -z&/W+eѼ zë{v՛b]QXt^M㞹bA$z b?=_& 'ϋo&H@'Z0u2'@&+·zRYC#VnڵqXV^E*TI\ JrMvl8c]?1>c' etWE$,CVƚhUG<5Ѡwl rcýϯDF]bAraqgn5ʁSs}WA΅!lJgiof -i@3Y 1&Jn0c!q$0ݱoyKhA -~ဧyRs;?aߐz>o%_=guh_W|૩_հ_UUh<7I&F4׬]7|f؋-ET6Q~Fӿ [??~ BOvvTQ]}3ب~x[$ -Eod#nwِ)'X %T-4r42;'k ?Ab"ij -hMEրI'I&v4 KWg,tI`CH^Ez|L>8(ꜬȞ㯘IA-LMmd&ќ3"m < -ȍYFu10Q֓^W'-~)gCU@_wA 8ƗGm3mDF󩣟٦滁kg:a}ȷV;*  #?LB$QK°x} H~L]ON?`:bD hr03ݝ}8"b{u:9ZOnߨ-Ӗ7rמ i֑\mkf/%FF?_ڟ -@ 'iYx~0b %=n -jQQ!_"u4}s;yd>6f͢[_xx3ͪ~,wH1/~,=?*(2- _ VH,xC#>c j6B>H+aqF] Z'-L?tGC3IdGdԻzE]>oWn=iׯGaΨ(~q}qgf|㤘ΈȌ'[\da&Y] yϗ}qv/ܿ}w -A8=j{o Y{OCtb2vQD|I ϱ{ Sg 6N՝Q ͍1.96_4DA"+DDSQBӉ{ކp^_;įqoJKkG>}P[x" -֏odyuO.~HygC=Jso:/ xIX5;%7>ObQ[q#{7vųӍ<֟^W$~ƪ5jSm\'[8} 63[7))! L]>}LI̶a¸RIjZ\+נZ6V~i_/O"ː4%D)& Dc(3-pS:C!k|)l6{fo%'04 Y^uhg02Hy Ӵ|eA9:~Ad/DW:r#[3shm})h|=Fvx1n;zhK0@M+a+EsIG @Wd -lNY#{xіr&sS ekOniWFX*>YrML߸W3dMr=gy7;+ -&%tܜ&˕ g~g&cAY7,n|-}s*\do"ДAGO 𳡮edWzO?@3iʪ -8(D(7\6՜Lwme7gF^(N1b"W :bDMb^kDiʬ~9 _(/+wǼjCrg> Gh)P#2?8evP4-%?˩LQ)p"0T9İ&߀oz0 ͵|PvO~S"? 9:}o熖Pv|ٛo~g7Z 9"뙤.Sx΃ŧ"i1P9GPU#JP[q] 8p{_\TKE{8D3G.{߆"IHJgo7-a_NJ1bPǫt-h߆@߽S{װZv7rY|5T*HsԷ< X qW -o ސ6KchϚ e(vcyC8>sM?}H3tKPV $d i h^5d9RGV|kkKMӅGC%^[`oA>O6F|k=f C ,t. p/rOC(#JMH0ɺJG =M;KήSs1*i=SO\o}3?谁w <+WXg:LKPYEIx 18MrD #j-{/b39|s4 RZqui:=~Ѥaop7G|^Ջ?i/鹖$5+'~ߊӽֱz7-KXO?+T簊o@^3NYʢ !RCӨSsGV/w K1 3m.ub~ٚmNc{)Vsn1bV2%=Z+,' @i ُCc,gp)oU<ŋ4dYT - sVi}M4OMB!T hF[=fʵkW3{` mL2<_9 hAcGC"P*k:{)΍5{)7˺6xtG˼P<9-3U owOP7H_Kg=zcg[|RJ `@l ƞ/C*JWoWc3H:T|C:+RĔௐwV)ڏ?O("ҢJ -hIC. !q.Y_S:0h.xWֽ,,r`)еE8,ↆ̾lsy?Bg4~Oө"H!MP ?CSy@xU #Qd=<)bLeneVy--.FK}Ywd6'L.ny{M^A/B$@q# HM(Ұv{fgqR_k,-a]pz:@oBRPW5 1XxD 3 eAFO; g~[Ϗsj5F;45̵]PCn[!xo9 O ߅(?528h4[ Ŀӗ ީw˰?i-\q2{Ԍ\ű7vBS/f 7{txy}_`wJDA((KY<"eXY8Z"Je;ןK)|6_h̒”Z?ف," &%Ǐ}_PQ1y`@t0*S~#~A[sy~-cmP/=^qŧ#3C}ws%Qp1u{$V`4?5,ƿMe]$+I*/PFNxP4?o9[^P. tlo2SiзkD//"ROx|/"j*$' 3x@ -F ^PRPOr₆q~qhM Sc4Ylt=Z)濇 Q?͋"pX7(h2-ckF(iV3x*S5omީF`M:BMm͠u@+jD:(ǿ|~8f_g(JL -YdSuFd+ſP`Xge^!m)oԉ=Zyݲ/ /McrC?@?slJ 2YC3XySf hRt=z=Pa3[*ᐭwE1p4NM:#]a/;/0ZBfN5R$뒬 GE:zcC \jh)nJ?ϕ'_S;xٷ3iPD -08 CaN_ ƍrQ1pl?ۑ2z U<iM[o2v]WꡩHQaAdQ<mjƝ% ģ C:8#n3'}e%Efsz{pQᅣO[y( נ4{moZWH\GPհr^R/2 j/hQ L|@Q?b"#O~]16V\q_N z0lFw_:chڻ>$teA @[T/r$t'˱VŊQϛ}nͳUz^NHkOuTZ2E\*~[rjD -g C8؞ - C,<4vƫu[!c]qߧuF\֏|.& ܛ_ֽЅֵ#4u_y)I(# e\nv+N#qݨB$]T_WAB^`(+z$7(7[4ݒ,jI6bq0)**KtRHSO 1qO`j|K{[rA`X&`6t0,K3(85,Q-Di\cXv?ˤ뿋Pa AuQd^PX rx('/sjXB -k0|( n۰s߹UGu.n"[6?M_x#l}c8"GfE(@eRS)ր1ip6Rta=>}]:cRΥ?ϥKgxE0 M%Ve&PRB=18r.t!*u~>v\5ÕM=>]#78z(`o^Ϥ_4+B^K48,*ͩT?t# h(N!_/=aHņ -cȞt[ (ߥW9>.B1eiˤ!IUP -d@A?{ߑ|_>εྌP+BaQPZT8z]kU=U"·e?x}f N]19 -YAe`rP} *?,#yoW-C-eӵh3(x?>I8Qs?}J,Ҫ85I4Ugi8^HKg廳EYZK)w;-e͜YП_:u1~.Iy%*D#4 gIPǀ7h p cM@"@3T]G ~ w6ڃg*3nܪ oox'uuC>] 9 (;~+I]J1! -^m YgGЬ"ZsLk `yDN4 8q{=jѴQ5kłˊz.V T[O7C 5 ]Iʸ]Q -C+~OZHPi *%BVt -٪g65Il͖0Ѕ4F"Tg۶86OT;ׅ~D+%c !ll8 8VZ4ϛR"ͣ|i#_ԣiY7aJw=yWV$|RNOYUb~7MǠQO?/Bвb>B)k9ԧu-NmkWQR- $dݫwe 8+QY;b=6w²g UVʓr@P__8r sRsLϟQAgNL$L -Zwڃ;Ty^C45y@;Qsq~,au ]䚓Y0kQ@f߇CRi(XxUHȌ)6G=uCCiL·^bNEAf M̌^隬t3P14Oi -NI -a#1ԡQg>*/z1\Zv$AZ>V[I? Reh|?2}8 HlmTs蘇-x~F5י -4:Hc|ˮ 8y~hUƝlWPE1[JgnR|xRQcWcچ#]?>#xM.B1]fJҺ -xce4o0M 4 5? h6O.{F쁑H gn5 f?KB?F'{S`gSPY@k2?P@bX41h>+s ->e>UiIdJ>,ՆRx?m܃H%mg@- LmEt!s1dcAKu$`ȋVLagSE(W'c8v+͏]!_|1(ő G_zũ\[4~'mfjoͰi}7oe7_MR5+${ȋ-+>d(^6j/_?SuL mq/_./pw_[=_( -D>3vefظAgR$ؿ|u_r5Eo2_^WӾ1\fHoljYWn%rA emٗjMcV1ǹE^hլ^e+G?!NeGY13Ezש_Ms|Iuág>h;*  B/!MRY\S#A%֒+\}6 ,F/} {W"s6&piiV|arڶ9O-?.CѬad@FG!X >W䅿P+ rz`6h=;zSF?5`n{Uf)|SPt/kzg72:ArM7rM3Ӳq]`L#x@|Iz4G  ?TH o{r);׹z~@?s<]o}я`8щ,O9/~,]y7 -? UFbȹEr!c0CQ<*VO:S֬yq×of&I1gqz>jAl} :+pQ g=bdD|kH:WE?Qw4lw7N ꌐX<ՒtN㍙': yțӞ(gK|lG9Sh)IS=͐VEo~WG垄Cte \Ϲ)׵m[|߮z&WY]uFޱ5Ň+H$BDQ)Jhm j:! |?G<׈G>}dy" -֏HxyuEO.zH{! "[R?'R /ՀgI ϓXa$5.F6Zk<{l Fr]nc54D#cm֜)n'aWzTl p2-eyT`E;Td^@GBsJh  C3t:KIuC^OJMMZ`w:rWd`K'u`vO!EE}؊Q@ W7?|&m?u1:fQ8>qJ<-p UX4%