From e05fa407bffb7da55eefe3a123084ad256f6ef52 Mon Sep 17 00:00:00 2001 From: Andrew Ozz Date: Thu, 20 Mar 2014 02:48:14 +0000 Subject: [PATCH] wpView: select/deselect views when moving the caret with the arrow keys, don't move the caret after deselect(), props gcorne, see #26959 Built from https://develop.svn.wordpress.org/trunk@27632 git-svn-id: http://core.svn.wordpress.org/trunk@27475 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- .../js/tinymce/plugins/wpview/plugin.js | 113 ++++++++++++------ .../js/tinymce/plugins/wpview/plugin.min.js | 2 +- wp-includes/js/tinymce/wp-tinymce.js.gz | Bin 121351 -> 121469 bytes 3 files changed, 79 insertions(+), 36 deletions(-) diff --git a/wp-includes/js/tinymce/plugins/wpview/plugin.js b/wp-includes/js/tinymce/plugins/wpview/plugin.js index 932785949e..75f704788a 100644 --- a/wp-includes/js/tinymce/plugins/wpview/plugin.js +++ b/wp-includes/js/tinymce/plugins/wpview/plugin.js @@ -109,15 +109,32 @@ tinymce.PluginManager.add( 'wpview', function( editor ) { dom.unbind( selected, 'beforedeactivate focusin focusout click mouseup', _stop ); dom.removeClass( selected, 'selected' ); - - editor.selection.select( selected.nextSibling ); - editor.selection.collapse(); - } selected = null; } + function selectSiblingView( node, direction ) { + var body = editor.getBody(), + sibling = direction === 'previous' ? 'previousSibling' : 'nextSibling'; + + while ( node && node.parentNode !== body ) { + if ( node[sibling] ) { + // The caret will be in another element + return false; + } + + node = node.parentNode; + } + + if ( isView( node[sibling] ) ) { + select( node[sibling] ); + return true; + } + + return false; + } + // Check if the `wp.mce` API exists. if ( typeof wp === 'undefined' || ! wp.mce ) { return; @@ -176,15 +193,16 @@ tinymce.PluginManager.add( 'wpview', function( editor ) { x = event.clientX; y = event.clientY; + // Detect clicks above or to the left if the first node is a wpview if ( isView( firstNode ) && ( ( x < firstNode.offsetLeft && y < ( firstNode.offsetHeight - scrollTop ) ) || y < firstNode.offsetTop ) ) { - // detect events above or to the left of the first view padNode = createPadNode(); body.insertBefore( padNode, firstNode ); + + // Detect clicks to the right and below the last view } else if ( isView( lastNode ) && ( x > ( lastNode.offsetLeft + lastNode.offsetWidth ) || ( ( scrollTop + y ) - ( lastNode.offsetTop + lastNode.offsetHeight ) ) > 0 ) ) { - // detect events to the right and below the last view padNode = createPadNode(); body.appendChild( padNode ); @@ -253,26 +271,23 @@ tinymce.PluginManager.add( 'wpview', function( editor ) { if ( view ) { event.stopPropagation(); - if ( event.type === 'click' ) { - if ( ! event.metaKey && ! event.ctrlKey ) { - if ( editor.dom.hasClass( event.target, 'edit' ) ) { - wp.mce.views.edit( view ); - } else if ( editor.dom.hasClass( event.target, 'remove' ) ) { - editor.dom.remove( view ); - } + if ( event.type === 'click' && ! event.metaKey && ! event.ctrlKey ) { + if ( editor.dom.hasClass( event.target, 'edit' ) ) { + wp.mce.views.edit( view ); + } else if ( editor.dom.hasClass( event.target, 'remove' ) ) { + editor.dom.remove( view ); } } select( view ); - // returning false stops the ugly bars from appearing in IE11 and stops the view being selected as a range in FF - // unfortunately, it also inhibits the dragging fo views to a new location + // Returning false stops the ugly bars from appearing in IE11 and stops the view being selected as a range in FF. + // Unfortunately, it also inhibits the dragging of views to a new location. return false; } else { - if ( event.type === 'click' ) { + if ( event.type === 'mousedown' ) { deselect(); } } }); - }); editor.on( 'PreProcess', function( event ) { @@ -296,7 +311,7 @@ tinymce.PluginManager.add( 'wpview', function( editor ) { node.innerText = ''; } - // TODO: that makes all views into block tags (as we use
). + // This makes all views into block tags (as we use
). // Can use 'PostProcess' and a regex instead. dom.replace( dom.create( 'p', null, window.decodeURIComponent( dom.getAttrib( node, 'data-wpview-text' ) ) ), node ); }); @@ -330,13 +345,14 @@ tinymce.PluginManager.add( 'wpview', function( editor ) { return; } + // Deselect views with the arrow keys if ( keyCode === VK.LEFT || keyCode === VK.UP ) { deselect(); // Handle case where two views are stacked on top of one another if ( isView( view.previousSibling ) ) { select( view.previousSibling ); // Handle case where view is the first node - } else if ( view.previousSibling === null ) { + } else if ( ! view.previousSibling ) { padNode = createPadNode(); body.insertBefore( padNode, body.firstChild ); editor.selection.setCursorLocation( body.firstChild, 0 ); @@ -351,13 +367,13 @@ tinymce.PluginManager.add( 'wpview', function( editor ) { if ( isView( view.nextSibling ) ) { select( view.nextSibling ); // Handle case were the view is that last node - } else if ( view.nextSibling === null ) { + } else if ( ! view.nextSibling ) { padNode = createPadNode(); body.appendChild( padNode ); editor.selection.setCursorLocation( body.lastChild, 0 ); // Handle default case where the next node is a non-wpview } else { - editor.selection.setCursorLocation( view.nextSibling.firstChild, 0 ); + editor.selection.setCursorLocation( view.nextSibling, 0 ); } } else if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) { // If delete or backspace is pressed, delete the view. @@ -367,30 +383,57 @@ tinymce.PluginManager.add( 'wpview', function( editor ) { event.preventDefault(); }); - // Select and deselect views when arrow keys are used to navigate the content of the editor. + // Select views when arrow keys are used to navigate the content of the editor. editor.on( 'keydown', function( event ) { var keyCode = event.keyCode, + dom = editor.dom, range = editor.selection.getRng(), + startNode = range.startContainer, body = editor.getBody(), - node; + node, container; - if ( ! range.collapsed || event.metaKey || event.ctrlKey ) { + if ( ! startNode || startNode === body || event.metaKey || event.ctrlKey ) { return; } - if ( keyCode === VK.LEFT || keyCode === VK.UP ) { - node = range.startContainer.parentNode === body ? range.startContainer : range.startContainer.parentNode; - // The caret is directly after a wpview - if ( range.startOffset === 0 && isView( node.previousSibling ) ) { - select( node.previousSibling ); + if ( keyCode === VK.UP || keyCode === VK.LEFT ) { + if ( keyCode === VK.LEFT && ( ! range.collapsed || range.startOffset !== 0 ) ) { + // Not at the beginning of the current range + return; + } + + if ( ! ( node = dom.getParent( startNode, dom.isBlock ) ) ) { + return; + } + + if ( selectSiblingView( node, 'previous' ) ) { event.preventDefault(); } - } else if ( keyCode === VK.RIGHT || keyCode === VK.DOWN ) { - node = range.startContainer.parentNode === body ? range.startContainer : range.startContainer.parentNode; - // The caret is directly before a wpview - if ( ( ( range.startOffset === 0 && ! range.endContainer.length ) || ( range.startOffset === range.endContainer.length ) ) && - isView( node.nextSibling ) ) { - select( node.nextSibling ); + } else if ( keyCode === VK.DOWN || keyCode === VK.RIGHT ) { + if ( ! ( node = dom.getParent( startNode, dom.isBlock ) ) ) { + return; + } + + if ( keyCode === VK.RIGHT ) { + container = range.endContainer; + + if ( ! range.collapsed || ( range.startOffset === 0 && container.length ) || + container.nextSibling || + ( container.nodeType === 3 && range.startOffset !== container.length ) ) { // Not at the end of the current range + + return; + } + + // In a child element + while ( container && container !== node && container !== body ) { + if ( container.nextSibling ) { + return; + } + container = container.parentNode; + } + } + + if ( selectSiblingView( node, 'next' ) ) { event.preventDefault(); } } diff --git a/wp-includes/js/tinymce/plugins/wpview/plugin.min.js b/wp-includes/js/tinymce/plugins/wpview/plugin.min.js index 6b05d567f5..9117193164 100644 --- a/wp-includes/js/tinymce/plugins/wpview/plugin.min.js +++ b/wp-includes/js/tinymce/plugins/wpview/plugin.min.js @@ -1 +1 @@ -tinymce.PluginManager.add("wpview",function(a){function b(a){for(;a&&"BODY"!==a.nodeName;){if(c(a))return a;a=a.parentNode}}function c(a){return a&&/\bwpview-wrap\b/.test(a.className)}function d(){return a.dom.create("p",{"data-wpview-pad":1},tinymce.Env.ie&&tinymce.Env.ie<11?"":'
')}function e(c){return c=b("string"==typeof c?a.dom.get(c):c),c?window.decodeURIComponent(a.dom.getAttrib(c,"data-wpview-text")||""):""}function f(c,d){return c=b("string"==typeof c?a.dom.get(c):c),c?(a.dom.setAttrib(c,"data-wpview-text",window.encodeURIComponent(d||"")),!0):!1}function g(a){a.stopPropagation()}function h(b){var c,d=a.dom;b!==j&&(i(),j=b,d.addClass(b,"selected"),c=d.create("div",{"class":"wpview-clipboard",contenteditable:"true"},e(b)),b.appendChild(c),a.dom.bind(c,"beforedeactivate focusin focusout",g),a.dom.bind(j,"beforedeactivate focusin focusout",g),a.getBody().focus(),a.selection.select(c,!0))}function i(){var b,c=a.dom;j&&(b=a.dom.select(".wpview-clipboard",j)[0],c.unbind(b),c.remove(b),c.unbind(j,"beforedeactivate focusin focusout click mouseup",g),c.removeClass(j,"selected"),a.selection.select(j.nextSibling),a.selection.collapse()),j=null}var j,k=tinymce.util.VK,l=tinymce.dom.TreeWalker,m=!1;if("undefined"!=typeof wp&&wp.mce)return a.on("BeforeAddUndo",function(a){j&&!m&&a.preventDefault()}),a.on("BeforeSetContent",function(a){a.content&&(a.content=wp.mce.views.toViews(a.content))}),a.on("SetContent",function(b){var e,f;"raw"!==b.format&&wp.mce.views.render(),(b.load||!b.set)&&(e=a.getBody(),c(e.lastChild)&&(f=d(),e.appendChild(f),a.selection.setCursorLocation(f,0)))}),a.on("click",function(b){var e,f,g,h,j,k=a.getBody(),l=a.getDoc(),m=l.documentElement.scrollTop||k.scrollTop||0;"HTML"!==b.target.nodeName||b.metaKey||b.ctrlKey||(g=k.firstChild,h=k.lastChild,e=b.clientX,f=b.clientY,c(g)&&(eh.offsetLeft+h.offsetWidth||m+f-(h.offsetTop+h.offsetHeight)>0)&&(j=d(),k.appendChild(j)),j&&(i(),a.getBody().focus(),a.selection.setCursorLocation(j,0)))}),a.on("init",function(){var d=a.selection;a.on("BeforeSetContent",function(){var e,f,g=b(d.getNode());g&&(!g.nextSibling||c(g.nextSibling)?(f=a.getDoc().createTextNode(""),a.dom.insertAfter(f,g)):(e=new l(g.nextSibling,g.nextSibling),f=e.next()),d.select(f),d.collapse(!0))}),a.on("SetContent",function(a){if(a.context){var b=d.getNode();b.innerHTML&&(b.innerHTML=wp.mce.views.toViews(b.innerHTML))}}),a.dom.bind(a.getBody(),"mousedown mouseup click",function(c){var d=b(c.target);return d?(c.stopPropagation(),"click"===c.type&&(c.metaKey||c.ctrlKey||(a.dom.hasClass(c.target,"edit")?wp.mce.views.edit(d):a.dom.hasClass(c.target,"remove")&&a.dom.remove(d))),h(d),!1):void("click"===c.type&&i())})}),a.on("PreProcess",function(b){var c=a.dom;tinymce.each(c.select("p[data-wpview-pad]",b.node),function(a){c.isEmpty(a)?c.remove(a):c.setAttrib(a,"data-wpview-pad",null)}),tinymce.each(c.select("div[data-wpview-text]",b.node),function(a){"textContent"in a?a.textContent="":a.innerText="",c.replace(c.create("p",null,window.decodeURIComponent(c.getAttrib(a,"data-wpview-text"))),a)})}),a.on("keydown",function(e){var f,g,l=e.keyCode,n=a.getBody();if(j){if(e.metaKey||e.ctrlKey||l>=112&&123>=l)return void((e.metaKey||e.ctrlKey)&&88===l&&(m=j));if(f=b(a.selection.getNode()),f!==j)return void i();l===k.LEFT||l===k.UP?(i(),c(f.previousSibling)?h(f.previousSibling):null===f.previousSibling?(g=d(),n.insertBefore(g,n.firstChild),a.selection.setCursorLocation(n.firstChild,0)):(a.selection.select(f.previousSibling,!0),a.selection.collapse())):l===k.RIGHT||l===k.DOWN?(i(),c(f.nextSibling)?h(f.nextSibling):null===f.nextSibling?(g=d(),n.appendChild(g),a.selection.setCursorLocation(n.lastChild,0)):a.selection.setCursorLocation(f.nextSibling.firstChild,0)):(l===k.DELETE||l===k.BACKSPACE)&&a.dom.remove(j),e.preventDefault()}}),a.on("keydown",function(b){var d,e=b.keyCode,f=a.selection.getRng(),g=a.getBody();!f.collapsed||b.metaKey||b.ctrlKey||(e===k.LEFT||e===k.UP?(d=f.startContainer.parentNode===g?f.startContainer:f.startContainer.parentNode,0===f.startOffset&&c(d.previousSibling)&&(h(d.previousSibling),b.preventDefault())):(e===k.RIGHT||e===k.DOWN)&&(d=f.startContainer.parentNode===g?f.startContainer:f.startContainer.parentNode,(0===f.startOffset&&!f.endContainer.length||f.startOffset===f.endContainer.length)&&c(d.nextSibling)&&(h(d.nextSibling),b.preventDefault())))}),a.on("keyup",function(b){var e,f,g=b.keyCode,h=a.getBody();m&&(a.dom.remove(m),m=!1),(g===k.DELETE||g===k.BACKSPACE)&&(c(h.lastChild)&&(e=d(),h.appendChild(e),2===h.childNodes.length&&a.selection.setCursorLocation(e,0)),f=a.selection.getRng(),h.firstChild===f.startContainer&&f.collapsed===!0&&c(f.startContainer.nextSibling)&&0===f.startOffset&&a.dom.remove(f.startContainer))}),{getViewText:e,setViewText:f}}); \ No newline at end of file +tinymce.PluginManager.add("wpview",function(a){function b(a){for(;a&&"BODY"!==a.nodeName;){if(c(a))return a;a=a.parentNode}}function c(a){return a&&/\bwpview-wrap\b/.test(a.className)}function d(){return a.dom.create("p",{"data-wpview-pad":1},tinymce.Env.ie&&tinymce.Env.ie<11?"":'
')}function e(c){return c=b("string"==typeof c?a.dom.get(c):c),c?window.decodeURIComponent(a.dom.getAttrib(c,"data-wpview-text")||""):""}function f(c,d){return c=b("string"==typeof c?a.dom.get(c):c),c?(a.dom.setAttrib(c,"data-wpview-text",window.encodeURIComponent(d||"")),!0):!1}function g(a){a.stopPropagation()}function h(b){var c,d=a.dom;b!==k&&(i(),k=b,d.addClass(b,"selected"),c=d.create("div",{"class":"wpview-clipboard",contenteditable:"true"},e(b)),b.appendChild(c),a.dom.bind(c,"beforedeactivate focusin focusout",g),a.dom.bind(k,"beforedeactivate focusin focusout",g),a.getBody().focus(),a.selection.select(c,!0))}function i(){var b,c=a.dom;k&&(b=a.dom.select(".wpview-clipboard",k)[0],c.unbind(b),c.remove(b),c.unbind(k,"beforedeactivate focusin focusout click mouseup",g),c.removeClass(k,"selected")),k=null}function j(b,d){for(var e=a.getBody(),f="previous"===d?"previousSibling":"nextSibling";b&&b.parentNode!==e;){if(b[f])return!1;b=b.parentNode}return c(b[f])?(h(b[f]),!0):!1}var k,l=tinymce.util.VK,m=tinymce.dom.TreeWalker,n=!1;if("undefined"!=typeof wp&&wp.mce)return a.on("BeforeAddUndo",function(a){k&&!n&&a.preventDefault()}),a.on("BeforeSetContent",function(a){a.content&&(a.content=wp.mce.views.toViews(a.content))}),a.on("SetContent",function(b){var e,f;"raw"!==b.format&&wp.mce.views.render(),(b.load||!b.set)&&(e=a.getBody(),c(e.lastChild)&&(f=d(),e.appendChild(f),a.selection.setCursorLocation(f,0)))}),a.on("click",function(b){var e,f,g,h,j,k=a.getBody(),l=a.getDoc(),m=l.documentElement.scrollTop||k.scrollTop||0;"HTML"!==b.target.nodeName||b.metaKey||b.ctrlKey||(g=k.firstChild,h=k.lastChild,e=b.clientX,f=b.clientY,c(g)&&(eh.offsetLeft+h.offsetWidth||m+f-(h.offsetTop+h.offsetHeight)>0)&&(j=d(),k.appendChild(j)),j&&(i(),a.getBody().focus(),a.selection.setCursorLocation(j,0)))}),a.on("init",function(){var d=a.selection;a.on("BeforeSetContent",function(){var e,f,g=b(d.getNode());g&&(!g.nextSibling||c(g.nextSibling)?(f=a.getDoc().createTextNode(""),a.dom.insertAfter(f,g)):(e=new m(g.nextSibling,g.nextSibling),f=e.next()),d.select(f),d.collapse(!0))}),a.on("SetContent",function(a){if(a.context){var b=d.getNode();b.innerHTML&&(b.innerHTML=wp.mce.views.toViews(b.innerHTML))}}),a.dom.bind(a.getBody(),"mousedown mouseup click",function(c){var d=b(c.target);return d?(c.stopPropagation(),"click"!==c.type||c.metaKey||c.ctrlKey||(a.dom.hasClass(c.target,"edit")?wp.mce.views.edit(d):a.dom.hasClass(c.target,"remove")&&a.dom.remove(d)),h(d),!1):void("mousedown"===c.type&&i())})}),a.on("PreProcess",function(b){var c=a.dom;tinymce.each(c.select("p[data-wpview-pad]",b.node),function(a){c.isEmpty(a)?c.remove(a):c.setAttrib(a,"data-wpview-pad",null)}),tinymce.each(c.select("div[data-wpview-text]",b.node),function(a){"textContent"in a?a.textContent="":a.innerText="",c.replace(c.create("p",null,window.decodeURIComponent(c.getAttrib(a,"data-wpview-text"))),a)})}),a.on("keydown",function(e){var f,g,j=e.keyCode,m=a.getBody();if(k){if(e.metaKey||e.ctrlKey||j>=112&&123>=j)return void((e.metaKey||e.ctrlKey)&&88===j&&(n=k));if(f=b(a.selection.getNode()),f!==k)return void i();j===l.LEFT||j===l.UP?(i(),c(f.previousSibling)?h(f.previousSibling):f.previousSibling?(a.selection.select(f.previousSibling,!0),a.selection.collapse()):(g=d(),m.insertBefore(g,m.firstChild),a.selection.setCursorLocation(m.firstChild,0))):j===l.RIGHT||j===l.DOWN?(i(),c(f.nextSibling)?h(f.nextSibling):f.nextSibling?a.selection.setCursorLocation(f.nextSibling,0):(g=d(),m.appendChild(g),a.selection.setCursorLocation(m.lastChild,0))):(j===l.DELETE||j===l.BACKSPACE)&&a.dom.remove(k),e.preventDefault()}}),a.on("keydown",function(b){var c,d,e=b.keyCode,f=a.dom,g=a.selection.getRng(),h=g.startContainer,i=a.getBody();if(h&&h!==i&&!b.metaKey&&!b.ctrlKey)if(e===l.UP||e===l.LEFT){if(e===l.LEFT&&(!g.collapsed||0!==g.startOffset))return;if(!(c=f.getParent(h,f.isBlock)))return;j(c,"previous")&&b.preventDefault()}else if(e===l.DOWN||e===l.RIGHT){if(!(c=f.getParent(h,f.isBlock)))return;if(e===l.RIGHT){if(d=g.endContainer,!g.collapsed||0===g.startOffset&&d.length||d.nextSibling||3===d.nodeType&&g.startOffset!==d.length)return;for(;d&&d!==c&&d!==i;){if(d.nextSibling)return;d=d.parentNode}}j(c,"next")&&b.preventDefault()}}),a.on("keyup",function(b){var e,f,g=b.keyCode,h=a.getBody();n&&(a.dom.remove(n),n=!1),(g===l.DELETE||g===l.BACKSPACE)&&(c(h.lastChild)&&(e=d(),h.appendChild(e),2===h.childNodes.length&&a.selection.setCursorLocation(e,0)),f=a.selection.getRng(),h.firstChild===f.startContainer&&f.collapsed===!0&&c(f.startContainer.nextSibling)&&0===f.startOffset&&a.dom.remove(f.startContainer))}),{getViewText:e,setViewText:f}}); \ No newline at end of file diff --git a/wp-includes/js/tinymce/wp-tinymce.js.gz b/wp-includes/js/tinymce/wp-tinymce.js.gz index c103883ce116fba3c3d46b0bb5cc5effe7a1bb51..705004d08a5d4bf4e191f423be00c0529bad7912 100644 GIT binary patch delta 1293 zcmV+o1@iibvod(53Q>CvR%FQM^1FZ_VC3^wQeSxt~Ma=!JH_Nxx738_ZH_7~FGQ)Fpqbb!o2_){=v! zT2=_m-O${HEV7kvMvT*lw%ZkH)JNLb7d)Ytt_Hvbommh|6R!1i zV%6HzFCRr?YStVb`IDl`rYl_vPT@V$v|=yY1=KnfIKLa(mDlvbUDH~_97lz)d*`{Z zwgKIbsYOqBAq0Or7~3{>yB$rs6V^bqkd1IiE+7Q@<4QbZvLrC9 zQYW!(_QDD>Y+_dLX`j%meis#Tg_!V7D=8w3I+neJLjxnKq~P;c)SUKX z$Tm+VuET$h!Kb#Tzp8Sk8Od}XT+pdgDoX_XtqqOa{E|;oR_wT}*l`!9(aFiS7yFk93m!W@0M)>ZB z@BeCs`|6jEKNkab;Pa%E&~aXSci<2XXg;<^WZ!AyyT?%6<~#&nbzAAj$(yYS=Kz>X z;6ByJ_V-hsEZk#bM1zKM^>ik8mahdVghf;nNL29@Dwy`OP1 z)DC~7ZEp6Z92xT}7pvYXgbKpFlWP4JMkF+M0F55_Ni?!l%_iZ902_NR4otoaP-ccm z2B;*0%vN<#YHJjML5O%*vZ1R^)`Z5-2Vr@&}{$$kOct% DvnG48 delta 1174 zcmV;H1Zn&IvXpH#n1{M)Lcy|-Cy zGw&vZRyzY2OUpiSd>GMO4Eg#@GloLcUV{}G^11vjAP5*cWiIYtrlK8Dr<|399Q@ic zx+p>jC~FIL3gN2bx2n@{A)=SocFz4A;zlpD`%U_N`rlxdQp4b$BjdgFZ`56z4zgn>e#X(+_$&l$FPw7lZ2O3e?$Q()v4{4(T1Z37 z5rdfOI(?Yha+X;%E%V@QKbx2K%W>C()@ZGa6k=%;*?CyR=Jm(Xr5(>|La$~5L<5#3 zEC0ie9OU`$G)-fkyXRviXMyg?;o-=BOqFsb4;d`qHd9I`St)l}%UF6P&`8qiMxnwhJ651zYb1J>@mMaM!ffO2*OW>)v@T ztZhJ-RcaBpT}Y%3#x{u9?P$^+m?0{`Mp7fU0iy14C7v-kcB2)HSzCq~gj2V|(5;>p zJmUn8FQviO2+x1E_1qnYRN`r=GyQp^t%!}d&q|62xs7Ef;mE+ADJfX)6^*0)$g0gA ziR%zmu#D~LuWEm3o-W-6Q#x}>dnlaSw*v0+3qDI(vE8y_yG>7{lat4XhbNDpoJLc9 zuk(heEkS=9=^1cl9n3FV0hH}|>1qNHpSxGZm=cQn>Mp2l=LG=o)M?#Rnhp<+_hMv0M+W-t zhwuMtM*ZrSk3SdVc7XJxlu(Ss8uef~}bN5Lrc2CrDOyaR(;2MbX9{$ONgKi!MOWY#{+%sxzMl3DZKgg~_D zZs@=E%HKP;6bO%b)%g1_jB!BNo>n$AG)8NZ!>UG`+{D&q%FJdGCB1)Z_x+mw)8t~e zne2ZeJB258D;pQ9$ri}??ai&m?w}EM<9487ovxnN4A)y_;_L}=IAZO`S-=Dj2V%0f z@wl>$eL^x_3_s(OHz}K%KNhv3a+EO~gxd}o>x=H&*%Ry36^mi!6|VZtUZ?K|$C%;D onz|ESv#QS2l#7e%nTjKdtFM!VYwK+U-Lne+4>N);)o70e09|rdI{*Lx