From 9d10815415c5e9d7f581e77d1357349e5825d491 Mon Sep 17 00:00:00 2001 From: Antigravity Date: Sat, 18 Jul 2026 09:41:27 +0000 Subject: [PATCH] =?UTF-8?q?fix(extension):=20forwarder=20les=20messages=20?= =?UTF-8?q?content=E2=86=92sidepanel=20via=20le=20background?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug réel : chrome.runtime.sendMessage depuis un content script ne va QU'au background service worker en MV3. Le side panel qui écoute via chrome.runtime.onMessage ne reçoit jamais rien directement. Résultat : la sélection, le titre de la page et le contexte n'atteignaient jamais le panneau. Fix : - background.js : ajouter un onMessage qui forward SELECTION_CHANGED et PAGE_CONTEXT_CHANGED vers toutes les surfaces (side panel). - sidepanel.js applySelectionFromMessage : normaliser les URLs (ignorer query/fragment/trailing slash), amorcer pageUrl depuis le premier message si tabs.query a échoué, accepter une sélection qui arrive avant refreshPageContext. La v0.3.1 souffrait du même bug — la sélection fonctionnait parfois par chance quand Chrome routait le message avant que le side panel ne soit complètement initialisé. Maintenant c'est garanti. --- memento-note/extension/background.js | 23 ++++++++++++ .../extension/dist-chrome-store/background.js | 23 ++++++++++++ .../extension/dist-chrome-store/sidepanel.js | 34 ++++++++++++++++-- .../extension/dist-firefox/background.js | 23 ++++++++++++ .../extension/dist-firefox/sidepanel.js | 34 ++++++++++++++++-- .../memento-web-clipper-chrome-store.zip | Bin 324701 -> 325566 bytes .../extension/memento-web-clipper-firefox.xpi | Bin 324775 -> 325640 bytes memento-note/extension/sidepanel.js | 34 ++++++++++++++++-- 8 files changed, 165 insertions(+), 6 deletions(-) diff --git a/memento-note/extension/background.js b/memento-note/extension/background.js index 4aa7216..4931e9a 100644 --- a/memento-note/extension/background.js +++ b/memento-note/extension/background.js @@ -21,3 +21,26 @@ extApi.runtime?.onStartup?.addListener?.(() => { extApi.sidePanel.setPanelBehavior({ openPanelOnActionClick: true }).catch(() => {}) } }) + +// === Forwarding content script → side panel === +// En Chrome MV3, chrome.runtime.sendMessage depuis un content script arrive +// uniquement au background service worker (PAS au side panel directement). +// On doit broadcaster manuellement vers toutes les surfaces ouvertes. +extApi.runtime?.onMessage?.addListener?.((msg, sender) => { + if (!msg || typeof msg !== 'object') return + // Messages émis par le content script qui doivent atteindre le side panel. + const FORWARD_TYPES = new Set([ + 'SELECTION_CHANGED', + 'PAGE_CONTEXT_CHANGED', + ]) + if (!FORWARD_TYPES.has(msg.type)) return + // Broadcast à toutes les surfaces (side panel, popup). + // runAt permet au receiver de filtrer par URL s'il veut. + extApi.runtime.sendMessage({ + ...msg, + _fromContentScript: true, + _fromTabId: sender?.tab?.id, + }).catch(() => { /* no listener */ }) + // Retourne true pour permettre une réponse asynchrone si besoin. + return false +}) diff --git a/memento-note/extension/dist-chrome-store/background.js b/memento-note/extension/dist-chrome-store/background.js index 4aa7216..4931e9a 100644 --- a/memento-note/extension/dist-chrome-store/background.js +++ b/memento-note/extension/dist-chrome-store/background.js @@ -21,3 +21,26 @@ extApi.runtime?.onStartup?.addListener?.(() => { extApi.sidePanel.setPanelBehavior({ openPanelOnActionClick: true }).catch(() => {}) } }) + +// === Forwarding content script → side panel === +// En Chrome MV3, chrome.runtime.sendMessage depuis un content script arrive +// uniquement au background service worker (PAS au side panel directement). +// On doit broadcaster manuellement vers toutes les surfaces ouvertes. +extApi.runtime?.onMessage?.addListener?.((msg, sender) => { + if (!msg || typeof msg !== 'object') return + // Messages émis par le content script qui doivent atteindre le side panel. + const FORWARD_TYPES = new Set([ + 'SELECTION_CHANGED', + 'PAGE_CONTEXT_CHANGED', + ]) + if (!FORWARD_TYPES.has(msg.type)) return + // Broadcast à toutes les surfaces (side panel, popup). + // runAt permet au receiver de filtrer par URL s'il veut. + extApi.runtime.sendMessage({ + ...msg, + _fromContentScript: true, + _fromTabId: sender?.tab?.id, + }).catch(() => { /* no listener */ }) + // Retourne true pour permettre une réponse asynchrone si besoin. + return false +}) diff --git a/memento-note/extension/dist-chrome-store/sidepanel.js b/memento-note/extension/dist-chrome-store/sidepanel.js index e7f0185..d441400 100644 --- a/memento-note/extension/dist-chrome-store/sidepanel.js +++ b/memento-note/extension/dist-chrome-store/sidepanel.js @@ -293,11 +293,41 @@ function updateSelectionUI() { } function applySelectionFromMessage(msg) { - if (!msg || msg.url !== pageUrl) return + if (!msg) return + // Tolérance sur la comparaison d'URL : ignorer trailing slash, query, + // fragment. Si pageUrl est vide (panel ouvert avant refreshPageContext), + // on accepte la première sélection qui arrive. + const normalize = (u) => { + try { + const p = new URL(u) + return `${p.origin}${p.pathname.replace(/\/$/, '')}` + } catch { return u || '' } + } + // Si on n'a pas encore de pageUrl mais qu'un message arrive avec URL, + // on l'utilise pour amorcer la fiche page. Très utile quand chrome.tabs.query + // rate (ex. onglet sans permission, side panel non focus, etc.). + if (msg.url && (!pageUrl || normalize(msg.url) !== normalize(pageUrl))) { + if (!pageUrl) { + pageUrl = msg.url + pageTitle = msg.title || pageTitle || '' + try { + const u = new URL(msg.url) + pageDomain = u.hostname + pageFavicon = `https://www.google.com/s2/favicons?domain=${u.hostname}&sz=32` + } catch { /* ignore */ } + } else { + // URL vraiment différente — ignorer. + return + } + } selectionText = msg.text || '' if (msg.dir?.toLowerCase() === 'rtl') pageDir = 'rtl' if (msg.lang) pageLang = msg.lang - if (state === 'idle') updateSelectionUI() + if (state === 'idle') { + updateSelectionUI() + } else { + console.debug('[memento] selection updated while busy, deferring UI') + } } async function refreshPageContext() { diff --git a/memento-note/extension/dist-firefox/background.js b/memento-note/extension/dist-firefox/background.js index 4aa7216..4931e9a 100644 --- a/memento-note/extension/dist-firefox/background.js +++ b/memento-note/extension/dist-firefox/background.js @@ -21,3 +21,26 @@ extApi.runtime?.onStartup?.addListener?.(() => { extApi.sidePanel.setPanelBehavior({ openPanelOnActionClick: true }).catch(() => {}) } }) + +// === Forwarding content script → side panel === +// En Chrome MV3, chrome.runtime.sendMessage depuis un content script arrive +// uniquement au background service worker (PAS au side panel directement). +// On doit broadcaster manuellement vers toutes les surfaces ouvertes. +extApi.runtime?.onMessage?.addListener?.((msg, sender) => { + if (!msg || typeof msg !== 'object') return + // Messages émis par le content script qui doivent atteindre le side panel. + const FORWARD_TYPES = new Set([ + 'SELECTION_CHANGED', + 'PAGE_CONTEXT_CHANGED', + ]) + if (!FORWARD_TYPES.has(msg.type)) return + // Broadcast à toutes les surfaces (side panel, popup). + // runAt permet au receiver de filtrer par URL s'il veut. + extApi.runtime.sendMessage({ + ...msg, + _fromContentScript: true, + _fromTabId: sender?.tab?.id, + }).catch(() => { /* no listener */ }) + // Retourne true pour permettre une réponse asynchrone si besoin. + return false +}) diff --git a/memento-note/extension/dist-firefox/sidepanel.js b/memento-note/extension/dist-firefox/sidepanel.js index e7f0185..d441400 100644 --- a/memento-note/extension/dist-firefox/sidepanel.js +++ b/memento-note/extension/dist-firefox/sidepanel.js @@ -293,11 +293,41 @@ function updateSelectionUI() { } function applySelectionFromMessage(msg) { - if (!msg || msg.url !== pageUrl) return + if (!msg) return + // Tolérance sur la comparaison d'URL : ignorer trailing slash, query, + // fragment. Si pageUrl est vide (panel ouvert avant refreshPageContext), + // on accepte la première sélection qui arrive. + const normalize = (u) => { + try { + const p = new URL(u) + return `${p.origin}${p.pathname.replace(/\/$/, '')}` + } catch { return u || '' } + } + // Si on n'a pas encore de pageUrl mais qu'un message arrive avec URL, + // on l'utilise pour amorcer la fiche page. Très utile quand chrome.tabs.query + // rate (ex. onglet sans permission, side panel non focus, etc.). + if (msg.url && (!pageUrl || normalize(msg.url) !== normalize(pageUrl))) { + if (!pageUrl) { + pageUrl = msg.url + pageTitle = msg.title || pageTitle || '' + try { + const u = new URL(msg.url) + pageDomain = u.hostname + pageFavicon = `https://www.google.com/s2/favicons?domain=${u.hostname}&sz=32` + } catch { /* ignore */ } + } else { + // URL vraiment différente — ignorer. + return + } + } selectionText = msg.text || '' if (msg.dir?.toLowerCase() === 'rtl') pageDir = 'rtl' if (msg.lang) pageLang = msg.lang - if (state === 'idle') updateSelectionUI() + if (state === 'idle') { + updateSelectionUI() + } else { + console.debug('[memento] selection updated while busy, deferring UI') + } } async function refreshPageContext() { diff --git a/memento-note/extension/memento-web-clipper-chrome-store.zip b/memento-note/extension/memento-web-clipper-chrome-store.zip index bcca1c7e9d5f1b6c1b7a98b412f1be3493c99396..0701cc7d1f5222b58b30f58a20c05b541d81db37 100644 GIT binary patch delta 9066 zcmZX41yEee*7e}-1lQp1?hrz7hv4q+&fpN-2M9jFHMj*0?hqhAAh^Te4*4PXzN+uN ze`-#xUTgPW-RDg0Q&Y8jWe=wlf`h6e4+Dz}03ad)7!<#vPQpVoDAupQ%l$;4iH@?XE^jH5W(C`=I#W(-zZttD`@-2mxzr0T^ z{coP0t|>f_LGfJw%$B^20R{k2LjVBK004lgiJ6_1tCNSLIjgPPoQ8xWu?%JhglPod z4Mbsy(TZe@m{m*yRreuEVS@rOY+WfO%UYoRB(uPN2-bB3CPbJ*d*un{`8ykur5D4e zWaI8g5?8&tlJ<)7c0q_I2i59ch_l08G=b6cEisVSK0^hY(FS!mNbP=wWfXgVFZno& zeKwjsEkf>RklA=c1NmA*VfYp*XFk0L6h48441W7$1Zk^3bW#W{xZ!#bOMWifcwOh;l;16wa4-cbgVs8w|Gg*gQ-@gek@G55&Y9jIS59{ ztLPwiU%gTsHk;Z39bxk-%M^^W*}*(o(|8X|mwn_@gIPBJED{>HL-U~Wgi%Z96Cc=> zU^cptoW{$9JMYa&R&8wH<9~Nig$KU6u#@?z*saUOr(_q z6DM%YSQPW?>;>(kNITGSN#tD5{FyBzSjnhOm6e3Krqah!f~!}`BZty&jhoo!9mAFL zrgC#{D@27n&xGD|rUVZo@Wvr5Z=km?H+q&*57ys)sJfAmG5xGd4Ur|D%bxV(cn8hh z4Doh-zBqln>VE|7dq;?(8koHoeQGoWmQ2|D3zCg1(^}z!$s??s25N-9(Xx|v5*o$Q zT3wvA-$@)b+bbXCH?*X(+ETooJW8CacmmWu?CN}*_1hBBXhPPc&C)=(+*8G>DO*J> z4!MjVh_3xnWVNANL_Vp!F4*=xA_V{D<{*i=jHCB4@1inqcHf392VtBbbf{00r*I9m?i;@5u;>cu2 zBGHyWD>(eU%v55+7RQFC&Xhr3X1d`I^#3jBdMQ&_q}Pg-wfhPEid2rwe=AYdodD{U z+j)ro#R^Zazj10GvA^8Hx8g5i`&*;F&hwA@1@pI3kG^>-O%MYBE2aPd>Pw}%*_c~6 zn>bq7zZB}Yh=Ch1UozzW4g2Iaq2N|x^07y{ogB@wYhlczYI=vCSCcZdl{og9vn8}K zH4}Eld4sZ-aRg}x3-5bu{MhSU-N4xiND>nah{E$kcR+zy|;sP}Zm4@c< z{oaW&(*zgm)bsT8s8|kJC%@<-@N8@Ca(EPf61_{(EZne9Sj4;O&(7Y~<=OKY6cN~% z^<9rlXio_92io(%bQJ9VySG!PgLFVPBM8vL`F^}dj2z6-CW$jPOq?FClHZ;^z`%ms zt5mSvU~V%d6=adTOOBp`$3N>WmjYmEZi4rM6w=)lc84fg%k`I#Uu_{w(o@YoQV~&J z#P~D2Dya}1bqT%`W)l$nT>BV;gSR4b=upr;#ID3Ma8B9ghgSe19C2;xW&rYZu)>8S z>;x4+b0vYGY4|s530!h9hfM{g3tE^zh)N?9#SNO_rs_x*b5qF%o&1s@5>E+pyu&nb zZw#Me9;f3M$y6sJd{^8z?`p?H1MLzF*MV-GoGjkSsjz7syV|L(LQV6PVi;xAey^|_ zML1OR+$dWm3H#67tbef0P8ZNGV$vpi!7z{okH=n_Ar!yNc&?o)dz_J8nqs^j=UnwR z#|Vd&0Pdj5Us64~HE6#@odeRbf65t;wA)CS+3dYj`-wfhemBfb*iGDpc~3x~2S-3d ztGKK%&KzmnQdvzmTOSXbY-lckGuto_qXAUr?3WaVEG&D78h^n|wF)G;Dt^l_h0xn= z_WlE}q%0YzR=$uB3!&^6djcCq3cCtGqPaP|ys8;nSBlqFofv z&ZZ(?gD>OMEPHGyO9`*|z%`7{4yl1%)MXGlCfP|m4_YI~MfD3Pk`SLiX83-8PU1~S z2gRbQD0uOHf|bBsKMU9>=6`PQzjacuvF{D zxLBGJeTb7&Wpvq&rFZ#RklH%0gW9pEq@&HS(O1zNF?{I}+iFdi8B(=(`-#&dXyo5$ z`o`+f$V2U~8A*A3F{}XIZ-FTYOME;PlL=b~QaW&f3o(y=C6tuAZzt7PNztsS5%IBw zP!sMf@TlZrhrNe~0ws*Fn(|2m?N;e2M+kFI+9-C>Up*oyu))P+e+0`6i?r)FZl$&DFvm$F3`oax$rMof{yj>wVJMoG)$rFs2h2 z%;_2oL|?l_l_tO(D9;q5A%u&8zi0i{_*QrzoEu;Agk|QdG56NfdA=(3Hh_n^^t+V z^EXfaw}a=yM+;Lq=Uee{iEC_%|k8|LKZ z58O=``8DuQ;94ycWyp7E)GsBe40a5-TVQ9Jm`!QQW8`s3YXlbzXs_Kc97MeIKN0}7Lg_z_3xYmzi&LR(j*wFcD^Cs+ zFAXRY3@ud~XTxOKihH}}r}Cf}tCIlwoA?!*n*N(1Fj_myq+JzL^ zM|6LdWpnPtrqy;dg?pExsoQMK{Z7nS;KEK{~!G&8F?1u*dYl+fu zI?fd1*GV#T810@nQ14*<5v6`frLYn~3Nd8}4Kcx_Gr|K5NfSI&>)&k-3zEr(=W&El z+6|;aL`UTcNa!m<5Qn)j5LRh#qFM{;CT#NHiq-L>d>>Zb z)jGmCX!PnooWGfn$x3?{I%JtmU9QtLCSTy~8(v61!p*T0D;2G^XRO;PzFh85Mo2+f zo_12Ot_Tfou#5ZYDf!;I)LKWYFb~w5V!ydhE)UTm`?6}1$mQ{~<|h=d3UI1Qs~%I| zi{g_Y6MhR~pF(u3No#sL^Yk)}8tRg?)KoKMWZfB9`V8-UfXOV0HY;tEzg8mlhYxwI zy86^5Sh%V5wzY(zosud1 z6X2se42-IjC?#nPaZptgaoQ->LoACZe!b~|BLd@Zn@WD1^9^8Ofd~FXLAe|f8i08q zqc&dVjbb;R6KCVvaBZ8X-+@&kbO5llIl$k?Mg`!^oi&Z=1=B$ecfNMxkOgRCdlDM% zTTdY(X(f}*bS~#vr*GjO6eS}`5$9H3V&raRQe^VS6SBOcr|A6h0qbZ+$e3VVnn^L+ z{1du%*|Uf{4NMFbZU<1%|4egD_bAAMZA45%!9q=fRW(*xc!3K2x;{(0d>RkjS)}Y}pHvLl_3{_Ur#U=MgL=y+4Krq)=xV*;D+mw%| znRSgz!P_op(4)71GHnjs7QG+jW|@>_Mjkk$Sd?YFN5o)x+CMS%2BwP3lcA!EZwqXb7!-<~E&d%`p%L6ZW})j0FX-L0*UB9k7|=Jvw| zZODMms8klrf~^tNHC7X3G?%|fCh=;Gx*sX%XCplhhqzXn$VytLO4ucjpLSvC@L&sM zI=VB%lSiY}e3b;-4dqpfvoBNhDW2EsU|gD^t=dZiy_ZdL<&2bx80FFQ(F7R6hq%hj z2S~4sj}w9XG#OWPZ`HX{5(cRqmXPF@=^v3Jb8aXKb`LYzhf_u;j+qYa?hk8!Jw0Ij z*_o_@4|;y?>k{fK&9mwZ?=XGZ;nu6SO^6Aao9M-S zyfo;Oi=913+Zf^+rloETwPK9McgwF<%Y5cxP_?woWuE#n48VB<1q!5Xrs< z75{Lgh18b27!Q_l!tA2lKxTjqiwB$+Ra|oo_wuz0#XgNoE=`7kTqC>_@_YQ#j>?@g zUVg}M4G0rp3kzuD6?DcaI;%cG~H`p4B%)5O}98Dtin8)W3SBcNaP2n>J6 z+72-f3zrZcT#SVk`4XF$$Zu$7hfEavw)RbhaTgx$?-^WyJ}zu1HA03~Nv9Rl(9&{B zZ!ufq51C3U9umd+NAmIEFF;1___LOdpg3NlBHl#3h zAZgZJff>c*f>_3<$10wWHjlX|6iRS-_T|AiTVY1F@yD7H4h*D9Einh#wj>#T1V+I2 zaThJ3p5b2jU<|MPQqL$xouvLe&CwXH8iwMogae&P<_vRwp3NS7DlkF8%ViNZDRC(0 zbpqbA)t}*vm8C>f(O|F3&wCy~+{g?3q5kf78m`H}p1`N0ti#@VNKY4%yi9YekQ^PE zd&blFA-I;?#Li4uK7Robf{xr3o4k@APEKmBvERyxI$m z!wTHPdN6GyI_|%5X6@<+v3nnDvi#00yXpPGv{E~(e&QW@E>0`QOA%b(!O7HRRi#VnCHCVGiwB;%&d708qLISoI2oXCB zpRhR@tV~X|w0k;hXp6p5@0luDEV6-K-pwYMTkoCFLrYGc-303O_>ka*>+CNBew=GlHAoVgDY6yLI_oV*4LR+_Zf>RK?fZzHP zeG?{v^n-|{x-5bn28U>0Q`(Z^e8*No_WL-ih z+09VmIQKYpZDj$u$`k)K;LNWUE^vCs##Q{g&B z!RDi-JARKzjb`6NSZVINc{5|N;&S?3jzw9jF00N0V7IZ2oB?&W$hjk%*|UMPG;pGH zfh+5louTmwve+Gv@?N9>zc%;)O-vu$cPrAs7&V&(XyNoQjpG)#E0$DtQBL_O*Yn`( zQ+C2#-lf0P03>wo-5KfQ{k1B*q@zPgpCSBRc4q9U&9^~I?to0_eCqu0gNph_Q(RNW`0uP6Gf3DCd}-uz3zV00r7uw2soi2kIbQJI`J zVY#njClf>HkI{33oknrMVO+<)xpry0Fc&IE@Wu7pB`R$#jUQv~s&+^Pl0B zFm8x2yMfYkC^{02oQxH+t`;~Xh2@=LyC|k|A@;5Dbi;lp;8^p}h`A`1!k3?7iQor| zu41cNQ4F-!Cyk4N_$*D4uZJ2J&TEX78p@w4KWkw)^w=I_&)J&%j$*~O@$!cAY5GP- z*D;cDqt={Dre(Y4hO)<}(9BqWyBod}S4=94T?AycF(4h+M~?hj&t4_hOj&OU?-@SE zSWO&FP1m}Vu~yL1tHOjGaZ3hu)>fO>-!kpDi?FF(IR4?Gi=^}3q~S7f_H3F-q_mU zqycVDy!@9Ozkkd2-UyHUDR#rsM>b_wT^S{f%WexMD;6ekxAih>IeGT#k=u1qmqSa7 zen{ROYn+pKRCrckVJVsI%B~)B215e6hZh$&njU$22R7INuJ43e zs>p&W-^J=^dar>yC1j&ew z%{&u9y98dMznPBngQc`{>~(t9M~YD>1N@sm^uR;4HD;-bao)^g0FlNV4T9Uuujag< zV~-IZ3!{Da`_l2cn`%4WOuQ!{)17ccA7E-kkfFJ?D=Y77YqLpdxrn3m9W+nFwqXM% zFi?j)!}Up*1oWUH^2ezFHr+~)K8D)h7FF({QeV%_@HK~x>Cf1EW`meLQ_qPs#=p@J zmcnR`+^+C>^Yvz62HV73(|=^`Ggv$-3$v!MlS5+$x)oVa66kqbk=zmBXa#K^7+9^w zD1@FdD>AFD7FG9*G!LwCTa~0TvV(y{Jl`8vl}wx#h(ENio~mn>qS(ae`Uonm>4@dd z7EbV0EKRg&ZeLF(JM^#E6e8rA+vzHj|Tk|BEO6gK+ieuibL9T^F;nE&jBRidj z!Z-e>n1sSt^`>x`KT;i(>K5I-PPj!yDC*nl>P&eOJZ_o<_KHtt>VFM)6mtM#KixOlce>NR*NdSiQxzldT8Ln}+e4fF1sy~+9bPd#Vl_&uP1XP)GD-O#5 zOg1p!lz!|d;e(G!2g$E0nfjAEFU389_ceb$T5-17XNlLAYQ?w~lJ+85Z!}H&A z0rE^$iUpE=1;h^GVo!Hsz+mJ-E@rW(84@JZ+Xo$1wuY+NHM<|Vx&1qDQZe7ViGqI^ zsH^SMkgn}C9ybavf7zN>cmx`~X?`Q|$f;OWc-hq?!yM|Qi@$OYMBSaU?k5nX;krlQ z{098<{8X&3$e}3Tl*zQ**8FX+$<@}X)|NZne{l%u>CLqrv~-Tb@!R*X?e;6ub=&w^ zI>zrLYPT+!D|!676Q3@4OX*HlvIxJ}vzM}#;~OpfiumkR%5`jHlG3zm`#jlP?T1rY zz9^^pg{f4|V%si$5@-=M&_%O@FqpM=z*rc4K|+iQzW$kTVSs~>gwC$IAV#RnQ9oi5bc2C^C_XJw@$9w7={6zr|T1fgI+v8foM%M+KUtFp=KjxtO9Vjy?KqYOx>jAABTF1Pme!#c4(t$@tP>aT)d;Vb; zJiUWHu8WdcZON*dhuYoeOu6Tk3k3&c$q3`6<#C4v(z)XMY2P=ry{b0=VeGnWCV|&$ zZ%z!ueKab%Y^sC}#PZ97IEzH>5W5wo2v`-_3|0>na^{>H+hX2m5)(aFT7A;TGF{US=2G!7HIuv9HPHiGuw@@v$5US@vMVQAJu!z-Bpwy;yUcOF{jLzeN>zdL{wb&WZC5A-!#;DxDV`EzyIp+C^IMEofUh85)p)me&Y?u}v%>zB*+&JJa@ zoT1Dzsa8Z{1k3XiTKM@54pnT_N78fC<<&Oiy^1?EH%9&*r`&t1&Yx{jDsdMYC%JSU zFhHms1&8SY7E*26!9irzoaazx)N%8@*R*skfr(9})BS|0s(sWQoLGZ( zv7|V=oxV$3S)vLg9!P}Z>CFq=D*q_^48%kx0wxx>bW&wt`z$LPT!%h{!*Z$#fHOKx7Ha~)(JO^F}?uO9e+OLC$M(Fa6*FlLZ zO#k1IqX6vV*B1q3e+Vo6iuM2E{l6%2^p76(FHZi8c*pK}>CygYt%l$|Uy#Jv zKSl;;FUAc1AipzM;#cF07cMd%@P9kHW^Vs;Tj%;*x^M(_F9$WykO2Vn|M z=Na{{;~nQ@|5XfVvx-#>}#7Dl=!NV)q$$dVQDE} zowi4DLj?u^0F6-qfbu^!f7es}34P=^F!Aw!Q-)2TUsDJ{ zxrWe4|6iWP-H&mX4gjEd8~`BwuccI4p+P_aSVBx%f0oG0N`y7J8Ga1o&;h(e# z&h;}52uTs2v=;^3bN&;p&$GT~nR?Doaos(~Ck3mX87aQ<9Cwv*eAcT-uH!MBwjCUVfgUN#@8x&V z&WBkSlXyT#RXkXmrM)eoAyh=V3Tl2C!JD){E)eSFRn*LWI(&_j491uXIBmITzF;Ot z5J=x|7jO43Lh&bGaJvudl%*JqidknW{*1q7 z+~$9M#9xHKq!qX@JVaVM`10Y?-HXTNBme*Hf5)|eLw;H>k^Lm>6Hgpjp4Ud{P6+d) zg+0Wc>HWduIe+T)`dRb(6g_j<*Bb4qPU*|+i|4gcFVH555(5B{MgRcX<62#9EG(T& z9W38HZgoJ!&~-*2_TU~rgbiPTC^VMLTeK)**M;=$GRaT*uEG5|IzbXDQ)F|LRX{pf zR7s)lbY4SVL!ozluy4x74e}NJckpWAkpwIatsR#uzjlF(ROW~^4{^jj>`fF!7Fb(K z0XV$Tl7R|E@~h<8V4$>yj?u{6sHYAhUE>mE;U>EHO&`pYXN2cDlglS@NfCZ=okt#7 zxz~&1q8ynY8QFQALPnkj-6uPsfbO-3eRRG=C$>37SifouYx0oIdpmRv#27|`S7+qr z+`V{fA@fbinau&eyiXJHeD z4ujl!DNZX`0%`^GOdTb5kp8>{O_Mk=afA#t-YN^-%eWW;@hEc27bbF&m_8vGKMdbk z$7Y*Dp}+zpR;n3O`{tSitk8f?93w;?pj^6n3*^y9>Ts>?6)Vlc1RV|=;IMEl^rk&HyW1`t1^0Un}GC- z5oFv$&qJ#t_bpNw|7I{bvL`D9Ni{LXH;f)58EJzNEFI8_i-;#1YZRj{qV=XiM4rb! zpes)K95*Rt-U5ZZhu4=7=ZK3foP;FJ+b(hQB%X=?C{<PBJSGts7VT^#wld#L%cp z)*k@+a5vrb49&nG%K#C`Wx79b>JdH^PQY-N>|OlBuBdQT~~& zFNtUy$L~_tc{=fhQ*cbvuZgFDeBmVyDH`vP)E01@6gthzZF$L;D3!l)`u|7HZ_F zB(osy9n8>GxVbsc)|BY4EN$2}7q3q#&Knqzgvw1()bbgI!aPK5Hbh1=5;@6NMPRb; zz&1P7XTXOE>NFZtzueu(PF$DZpEhgBbfy(u`F02l6h-N1;Ld3tkc^i`?dzpha*oI&aU+HBi`K6Ni0*XMI6&Ou24qY zJ$-*gv=Q&S9qJ^HT`HxD;SRkj+{i>R3xdq`)f>{>8m#Ya_MrFC(Bo5LPL~Lb#mjen z?&1RM;J5cs4ip0P(-dzzX{i8iOSY=OS~>bybv_$ZQG@!`sOzt6DCA4J=fUaI=Nh%N zmGf0u$#m$-taGQnsfFE=XU(FbLNnm{3xWvH!(FgX`Pq#G=DqjP@*A8gBQGZ^&7V_1{sGGRq-oNA6yt_AF zFx6I~38f*F8)BUJqo)7(ON?jv{5G+Y84WdqtWy+eHif!bZ45&wL(W=i+Mmsfix3T^ zenjWXTp>DtKr3hoN2%zurveSX%1cIBd*wGg(p&JA0uHD#6(ZyM^hxeQpZ1E%@BlEi z2;g)UYSMfu7kFO&Q$}JLYMy*mYjPNqx7qnK(l8MDPeBOX@vnhWNd_?Cd3%-ZH=V&I0%EDZ?}yohv{PhDf@{zB8sB5sZS-%FN+T1P{f1TZGN5C{Qx~&sD+{h227laF24)-R z{giFY4lpNIcAQ4WpZ`O&(AegL;a?3b9btx63pbl^NAFZ7?|oBUdl`_p{gJTf&fOi{ zJ*JVG0-w`e^&&u>Wtu2LIK`|VgoRx8WAje7B=bu`sKZu(E?chsAI_Ur$}j~kTyeb- zS+bPOIYxI1@qpG~cM^}0I)54A{D?O}Z#!*+X(F5?<6H;iy?3kLs{*4mb{JEugvk{B z1p8bH$nquOvD?uwRYHD?R4F<~eC?|NuaDKP=7yQY{wm0+?6paQuTe(~@p>3>A8ice z#Mjr&zeL%fwiM)iRY>%+!hw%{%)mBvK9d72k+M70S#Au4>|LL>wPEc5`U^a%`cXrk zIu(;D_Y$lbr5-GF9@Z1J(=h|DSbNbs+%?f6|KGxBYNePr@WSaxcy7Jp{n;F3V7cO< zUZTNi`&_B+%Gn;WumN{uUVryt!0BGF562|QW(y2d2(GW@^HzEp=y1&Vfdt-N8*&LJ zkH<9$%u-eFH+u=+Wrz7$6J2FYiBrZN0HTfz&8QP~6m7((Nj&(VY(;0B!N&KI4|y!{_1+Gp`(QN#q5pCNIIhw?y+6#4K$$U*d`Ee}MS>il|3Ojq-knqI-77 z?mpFCFxXsI2__+a&`~0rA%;F$>{6t`VI;DR@0?4PJ982`C#(eGM2*=$2sX&O~7R=o%Auu!KWoDiwGX%b~D`4 z(YuCCEqH=ph7YbEZj~4HcEO)4`IXoeb6s*?Z7{TRB_(0sL}6Ple4Z8CCs|XET~U37 zHy5WYc^oQLPh&+@D`zG~>4H?1pFY)y`jH(*1s0ZvW9v{D8}Gi8%S$OaGL#50vt3zY zm4w)^S;71`sm%`u0lQ}MNM;TzwW33Te}pSr!w&*qo2=C=W@Q8C3)>nBE1P!{+9a&)8P!~JT71;*j#9I4Ub zE*D~ptoZVfHdB)diokS4Z`yXt&dl?h+;$7dJLSs%)?rla^4jvH+p#Q@o7h^nZf6cQ z6eWd;yb(2OQD)egOK_sNqZBLf^mA#<$#CmT1F*2Zm% zP-a@k%>|vzcnJDBVk=%W6}8m};ql8*!u(T`GkBVLMkAji7>I4V|C&~SO&rUMiK`!l zp*ox)Lp!^ArP{)iN{$^!iv!_j4Qa6awwJ!WWQcZRaOKqtN+ely>2YSW?2U^hsy=;V z8Z3p}*2tfrGz3->O^wcWptrWqIKE$703H~ktp2J7iMa~9RuSGZ&;LZ z{d6tWP#O3ccz><8QC?>7cJiK^#dwTdjlL&W4C;LF3ivb==vJnw^alQT_$kmP2h$2IS)L|Z^veWbu+Y(|d$3R2A z9f0B^4F+u4CCu{R%+OSu_bzt`P_lD|;kF0HOb6;REd(M9H7tTC46x~<@}mQ==P@!F zt#EPNV)!JdJCBG-)Q3&*K9}eq+(e{bCgds!rbc5$7s~x&^*SIR39v+O`)N8RKJB*6 zlAJp3iAt9+yvenhS(7xZsbFp){H;!BgM8OL4O|kQw((AdK8DO5Z}xTg6oN4iFgNF} znKB#z9>FT7*eA;D32t88QrcO#LFBrRHMfz4n#fPrG6ai!NX)EkFAoB>L^WUCQqz;t zMt^@LD9b4^f@guVDd8N+<`(L&SndLUHk#K+7SLLg`q?g5bH-w>oyGA6yAu^kV@~>c z227bTX}+v0!E&IgV{@h7ugM0L@h>l2Grg2WxcW@+=5rIM|0~BKGGQ#x^n0a zb|R-Dg|%jFg#atl{>m_O>o*TnfmiO<2@iULi>(5|n{&}$b-kp|V^>)j=tlM@=eti% z=L(YEXa-$Zm8ma&^q6!w4s3Mi$AVM+OO*Y>Ms5y{O#Ku%$pJ*S$Bc)t*8@Fa&^W8PPA;+Rnw-AxcD6o4)W4}O> zMFq;6jr(;Si+Q`Z|KoLqIqrx|6cSP!F@kYI)yluN9p~S1d z_1G~-?j=VIA3{CxCDAXHA~;4($s8niUsorTn7}cAun?1W)NIN-$bwFM%j5$D=;WOT(vjSfPh$ zC4^qYz99`I5m2S6omQ@E^5pqmDHZMP0#hn!pz^2At4i%=ja+zp_!x}Z;v{pksB;!Z zI$xi5&-iD@ug4n2@@@JXYTzqJd1tC11`c?9qrnXrddVCgQgqD%?mq{16+ZO!7y?Ss zI5b|a49Eb&~QU2~-Sv`_X~OjM{KO(^0mx*qVRBeZ&sA*`VTE>*RqH zC56MBSZm-Ks^)PyN4S}sizTj4I~OI(C{cyrEmh0D{Bh|`zN88`-4uNpcI2i_)*LN~ zAS>6PfJ?Vgno5(sV&Z$Dl^OK30Z`hm@V>g|hiAFFs;O4}S-H-nc4k-r_nkM4r?j`W za@}`vbnkis6-+zc!yNoF=5^UB-P;p08?7-6{7?l5PidqnTVThe?l+kn{ja*h{$_zf z(s52lAQ~~{vu-#rW*2^tf+mGP)#6((w2i=xOsJZ<3FN+?mru5Kte=f3A=cZ$GzzVN0jrvYY~H+x1F}L+4DP&a2+fKBlVLlsZVS> z%?_#N5KTLgPPo)JH;_-9QwaBtAnhBYppJntJAP#Ox41MPGzxfJ3;+ zFTb&_!qdruOV}?I^z#pfHEH#83=F5-DC43ItnkBLiRY=UYRVwCHs5ctKVVPJ{Q$fl zEGlyJ$3Vrt)E%}hbs0c1Q70|I8q`}v(;Ga9O0}s*l%>723uS}WH93B*JBdL08c~d#Pgfy{i$2z*~Wq-5D{H*UayW=-1@t+2UX|=I8?Oh^o%t_4Lwd7I0}`GR5S7` zY_7$7p`5Nj(&9~Upg?F&#c4lGPNbq)7p9!b970_A<9F-vgtnfh!(pOFcZ>@55|KdZ z{9VV~FrUuQXgALI+E0{XFFSOgw>wh-EO(*SsrJ^M#`62d&*3}huiwiTXsmD6=dIAB zo@O!*fD3(?HD)~XSgLPzD@*EgPz96Dc3|J9IcKuD#Dv9t#q}A_wyrKG6nPm(Q*9O% z^hL3tI;Os45>z3fo3L}NO1l+&ILWn9!S=?6$@Prwn;$~jlFE-)ZoeO2Nd*eeZHz|@ z$#uJit+2_ObU02mQ-)C4Au}j=gXa?p+ z!?#o1T9{VmN0B>f)6_8lUZ>5mp(t4iS^V(y4o#sCrU6M96_8_9?D`W$%ZcbT(iHwg zefn!=*m=tSR}$LYMr;gWb`=n-s5*BYAut8wW&B{ju~#OzLe$1^@W6#~t4n$4_h(FY zoMUA1y4yEF=DuFpQ%=4eN3x7+MS@rIQ{k0Ne+e6H-*_$YHnjvAI4Wlwp_dE2S!yp)x7g?y&Xi}P zfj)(n7i2UFQ>sAFw7yaFyJsr&;h<KR^GD%lpqZu_xmOQ{7E_(%{-^b>YvNSux9f3c$^>a%1!S_GPb^&Qw>*D{N}4 zEyMk=)F^(m##W}RQ!f&B(`qF|oewnnU)lS&-CfvLTXfmifrEv{?(z9-Tuav;JO3D84tE^FOBDhotw7#_?`{-1RQF?%}B`_4)#qlokPJn{S2`drs#uH50jFVGv z!BHboEo-Xw$9t1$6s1x1on4Qj4-bAqybC;uoNN9)HnX+9YiHZB=TTP$73K=d>bCBY zccr@34tuXE{)TQX_F-zf)13SStet~m7hJW7`u10(E6&=Nr zkJzp*@d8hDu3diL@idN(uRB;J<%~{aPI^0?D52WfkVny+p-D|A94yA((lXKsgJjAx zpLD(4rZ_u?b5gDbUKy#G{`3R3H{qIv65uLNUAHFS;pxcrJ}{{0w;@aZG{@n_oL>)7 z%ov`S_2v56FB{dJ-v(u-`b&|7OR!8Wuupix55RA(csw2dcel$f5rcG^qS0FQjV{cZ{_kVezFHeWIa8g4Hkz+boypBs9A zsj@O<>dhZSiSk>TEDzGo7)E<{(r3FoJ*CD>q!V|-{?=J(^?k4Xh%aY=R%bO#Qhce{ zYDz;-Gb>1oMSpi)Ne`S2QjTlo_!V^lyY_MSSZsc(T?~=8(^V_M7jO@zxwJeTA4BcZ z?}|Jgk)dQ#;x1DZz=bJoPn^K;62aC?=Sov+ucr{T&)=+Xc+-_9-Y3)@6oEF&9(L8= zK3-GqyHEwj587Ubk15%m?bYVNr)UZaGKfu6ki4fCK5JDH^#YgtC~SCF!#lio&k;1{ z_`NM6r`;7nH`dn=jo+Kgn>lV4S{hGB@6Sa^?yywL6MWl+SKQ`lQt#4?z)Qr`0J+C_b+)1E8()ei zj~=dZ$disW$DD%k*`yf!yJt-R-HI1qM$4AU7zlnl)RZj~&OgL=<_ez==D`zGGsY$z z6zJz@h{$FPP<Q8|Gle9|_Lnn=_R z0I=Z{aCr3DK#DN1crX6r@Iq3b%3nG_8c*PepUNj6HJP;AW4XDb11l#Vo0G%af3;wr zKDHRYhp?ai)1vsOwbR`Hw(to2-i+M;nx78S^@7Zv!jU}9clD^j2tNPYJ2ZFw*Fzl}aO=SnRz7*hC;$M)f6jVj)n})W z|J`csX8-QLpYGV;-zMdM+N(YT!~f}p#GS$6Jq=TM_BdR1E~MuSj{Zp>J?W-W2vFW|7B=6iJkNBSb!<;6cy coxf4Lr>L1A+*6bsl79h*gTVeID?o&(u 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 np$z0;?;jJMt1qnx|fpMAHJe7 z`-gYxB>(XlmgYRlu~H6G9J)X7I4 z>XWwgTy+QMY?yl?RS1GvEkv+U*4G*t!9W33(+SE7-(dcHj^3cErDOfY^M(*X{0~fo_9GsnG?9&Agtb@VIRUik!vaC znw$6Y8KmzmZ3Aw*bVvefUL7Qm-P+$eU}@j(*+v~(nMfN8irk=ClRTU{3(nMCEJ^nywPf&r<5t%^aFI^nH<4OH=iRz1L_u$?vi#Qd7 z703o_1&~P-TUr!2UC>z2SmfUj9+@46VYWUGpA$!C@h%)*H z^(vMw2X3gK1|D8-&B8`v22}~Iv(Y;s$C#9^bkhehFNrB~h*La+ruXM)v)&eX(5j{i zD3HJLngfk2-xwzf(2vZGjBGznqoK_}?$PYiA$MD4UV2>MQaYZXul;I|YW7hscsg_j z#v8^&(`6Ur-#LG3tMp#OpDT&!?I_f8K?`ir3ZK1NTiBTihRet?!lHVN;(VkivfE(d zQADYBAsKStpo8x+qX6H;GjwYrh zXpQdwPR9Jo4zcKE6=F70c^@N5dNueVrZ*=7Q#&O-Fp3rL1LitATrs4L7=uJP!8~49 z%HT<*l&X+RNOz*<8F6aboGlh@uW%qa*!3k~`dHy}vx){YEvr7dGP_OJhny)rI1|dH zEV)7#$m$76fi_+v6OzC;t`PTlXN}JlgYwY^Yy#47N+wT*iOUm_n5fxB)!$nMrbW)5 zrkJXkfbtsKLoya$$S1=%Ecu=KRQhoY`yXm#au&ky_P947)T|Mt` z5B|Uk9Stq~Y9{Wn?6wwPg?HwSOSs90#UJ)Zx$8~4F5$s0r>vW$;WJbY(m&089jd=A39lM}fDoSpS;ON)EQ)lTSm{`iFMtdR{fdazljfiqETiGPi4s#+!=!q(UW?U z(?(H|Wd&h&C=7lzSDGh~$w8H%nscC66HhD5Ir+Wl(%$HMd+3Y8-<^4OD4ah!NnmBL zKxCCD5XnxwYZ9!EGva@}&6w)5!=O<)+-Y1*9FrnrOP0O1az&kAOYo`P1@b%&d2~X_ z?-`A^aPjP$x2za1{OJvn4~q=4EU8<`?5|6$na0?nGlnOTrQ)D4 z9n9k=K#qgeFkmj?ci{=v{#Z9y-F<0#PN~v)Z)>Lna zSG&dKBmk5;ba*BgBXyyICz`P62|J|{qfnu?11*Z>)7-)tMHGbUt1$GQq{m=|RMU8$ z>c|W}h*e{d2cAP8%Hr48qd&M_nJoaw_gcG}7FQF6mbc*>PeZWZOoboLhTovw@U>9I z=HM?llWH0~pxAEK?X;zRh!s5qO4(8Us%UqEO>vSr7zfXcYgaHi>$atnmfwHPZPp!L zmU{6eu8Qre4FlHM^I;wd!!+g6@Vc|zrssIh>-`(liXbxU@2EO{rYzhfx-w4f<>7V1 z@Rxg<;9OJVFUn21AvUy{Zqp#rxgQksP3`V@!8PEr5l&={WQ(O>+;-K6-S^t74?|M6 zUXmAIdwaus#`MzD(DHh!AB5;~O;bcmrdjtx2tehZH?EaSv)?2~x^9L*dGcL;@L#pj zN2v)A%Nma;)1+n3vU}6XhO~uyQ~8Y42P;VyMn4IA+T|3^6zwjb=ry3~zf=8O8yu^* z&7NK@NuwSl{>}3vO`$v*VFwPrR>XIyYITq3ci(E^Yh!gQ`BByhUq9wm^*Lss)#_qI z_}z|pk2Zz!lbS#aFR<1b?Zo*X6;XVtbQR$pGj&Rz%jUyLq3=oeP#MFbdG^iF!K`io z_W_AQ!>E~1y_RLQcPYV)MlS)b5cjdp$(X5Mf{XMu@v3xj@OMcZoih9@G|5a%5?J4O ze=Z*lT%}~Fk797zC10VZ>Sr%a)POfgIM{m_aIza7z&A;?(TakU0Dh}|y_s1KIT*9J zr9$&IL|gz>NdzXrIoi7Y)(_FTo$+7m<7$m*@GH3hAdE4QS@qIx(oLjHDf=%p?O80c zL^xN>Yae{e@WC+;0*$3S-rc769;{&_4_<17Csui9_D2PgX|iYYlmFh6uPH(QRPNu= z^aZ(Oj(X!9`eF*tnt{oV9KDVUB$4LptgL--P-`^6NB@kWz`?M5t)eIS2bfe;9s3Zo zNj2y|de`~LJD|o7g;3yEvSmaNa+Jbxi0vCQVHxJ&Fec6VC;mmd?b);{a!cO+VcmUl zIR2aSM=0Bh!Ot+7s5gWec?vkAJ=GQx`O$|<#%wdSB7T0-rg8h$gn040(ur1Gifr** zd{K1Qgcz5S;j7oEVvo-iv7LussfANYMfKvL{H^6z%i zY@>xh9oEEUqt}fa254mAY%jcC{MKAB-hsce6V>2V&-cuGw9eKckeW((6-#J0|N5uQ z9@VOD!m{=wlG#K}`J+gM1}1xkIu&afdQZ&i!px~A?3cVKTBxW(e47W7gd{gz0)84F zVj?LpvO6^8R;Vb=TGVWgQrm-w&ri$RiTj^ll?mH(1=@=}mh)Z?+HK)28#q#GcA3Qd*Klt>Ctfj}UVV-&p#| zKzqgE-bmzL5DOb^Fdk(`)O)P;G&eXok?&IX^|T=WCId$zqe)5(9eqjvS2q}o2=P06 z0yvQ%|46NYV1)!vOy!%~jG5YWNHo41Zu1r_H@hHcatjtxa3WCnzSF$K^ReAS*pV^^ zOlGwQ+LcF$#7g6!ZNiRSP#X5&QI#Av#e}`>35T;xNe>%fX^5$Od*#cQl?9KdQ#vyI zkxQJ;>3-yMbq{*ThU!ISJ$Ce=LgP(r7@$IN0p zvIKq{0{vKQHE-Fn40CIiYixZPRCvM6LyW;n;Dzx?_jDO3xdy&gPv zeTfMaH78H3!WBU6O`^#fLvRi0^tfDCRtJ}yLucylrYrttjr(m@ciwO+aTZNdV?E1uTd+zow~uUqrnFUl(PhZkLw?HOOk^9sMM}mi?R)X zN8m)WD=tmqAgG-VHk&A$@Yl6=`im^#F5xrlc%PA9qt9v8!+H`aw~Z zv_n{^urbkYgyVO4ci58Tb*T~hRdnV>a=wOmdK^Jqk;+$YzkM>Q5IfxV zFIHo+)37bB59#B+*euDz8v+~IwW-7UYBsi#@9T}$X?MIc;H7Uf)}Lvy#?!cv{Cxa& z3f)2ooS%2yLjM*3A0eoq+oQ-?*_TC3u?2)%a@~yG>LYr9l#%$a>sGs6l!U{JV z%gEm3T+i{z?8nq6`eB#V<+=+meI{LxLYurr2@tt$<#6V4j2LaA#1S#CBi`*Ta*WW~ z-?Gs@KH;=RKp&rc$cEhFTv8Zs6v(YHy*@?I5;SH?baQkvPDm+iJief{B_}ofSre$p zUc*?h_nw3+WWbGPHRZk7+k1O?F9P6Qo5Mlvd`n%`6ZeY zx0DNqyo2v~6d{l}xF_m*eH|Zdt9VNh+8zaxQMQFu$6^f&3L0|JoVN$>P83v^JP45o zIY#!(eQL~+Um6KCW@pD&l?%|2Yafx>7c{fngSHZVs>{9K?7Yfg!)c>ZLurxc9!w_XaU`Eoox+p|S zwA89-0zL6|Rc9zKFYi=M1rzBLOg*Fu^rDWKHL{|VZsO)2po^qa(h?bTKBRWDeWKf0 z(Z1E0T-9Q1u`8Ir2r`}c-2Wwo)@$y5%|ihQ*pgOLzBFjSPlGiH|8s*#I;Qy0tZ@Y%Z5)0 z0r-R$HZu^tsx^|x>Lucsk>lNHq6^@PAA}dPHnSS|`8p-&Be=1R2zd?LxO#_@`L+7E z$h3wHYPGfsR1%gZdqe_tfmmJ6XtL?yXqyJ}tpXl(JjN@}g_U+(U96P3T_?zmg>-)k zGl}RNR2t*kOW+pst}7y`#I%{}rZwxEeT6<%Da3hrqLj&-YW=A9tJb+%rIp+oK7wPn zx+`5R7@bB@&oyM+u>aT&>UF@fdz$%#5&Xza)q^37jSr2~d~h9wRX#6(8dv|L;E#Rh z$^g~|JTZ+pA|^kt3iBmhneSe2Sh+|OlpG=iZhn1HN$O)oF?|xD7b3o%0T;?UdEZl{ zjreW@GM`v)ZMd+G!l&j=6coy_&Od|8ndq~(iN7fW8qZJSVJto}4G+(0wt-#b6DPl^ z) zm{z`To7`8Rr*oZ^X$xJ&)<3G?duy%YX-6E;AwbVHN>M5Po1t}2^{DKsP+kk3X@$Fl zI&#&nY=e_ZmXmM#Q2^Sc$e_<#Iq|8;-Wqw*2q^1NdtTG~*|)-5+sdHfw8Ci8Fgq$l z@Y)~6SJB^4v;LDTu73lW7QVCaK^|#2=bCag^!Kr~qrn&+X`~uLs4T{cC$w`C`d%r| zC=f-FFf_bSr1*$M(WsDB5wLA1yEqDI2LEx zh_tO=aYSwCZ@!g;fcz1I0XzknCjBqDz0xZT%?>&7u+Z3eX}>N?(h zf9``SDpT%`<@+v9+d1r4NL9MVr^SgW*2icS#tiM~Yo}ux7!A%SO%ls+z>0nmkH4_p zyCM+tN>z<*i5h#62`{}}38oD41Cy%V*Y&j;Gt5;C$1svePSNZ9E%&Wl-onm9Vpluy z7?TfnjK@x0)&~r;7*<`F#{#+=>!4$gH1gd;M92Clq;p`*SrnxDl$hy--bW!%(}BUJ zPellfwOBeP)w9Q?n@;ePZmsJ!#Y<*#eyveI<;xmYYr9 zTf)iN&w%HH#l>#Hc-Vv&&|#-C&jCzJUFuSTLE{A+re38|EWCT|~UGjE0;ObV=5@;q_m@H*vrAB3Kso{*;5h+oNG!8#E6f=lSyFJZ8VYD|c941R(STOk7_f|H-U#}wrTfdgh~P@!f>r`B-^d!UPPu+oj&<@0)u&X-lYe+T33E#gcHHWh zjwm?`Z9DV;IIl~@v9=0gwN`!rEy|X|UhIFB@Jd?PxZ*?@7Pe ztvU4lH9jxV5lFWF_meQ2K)>86_rT6WW$A6TPq_tBacLPh+w+K&w>%$u2zEB}5Sj?O zT#3mK+bn67C>4fYVn6rQ^@a#rccY?}-IG6t(H0cp!;C z7kP4q!GC$0-I#oIv&$1^*K-hq<=}1*&I6WqCwIMMbwgpTBlYI372h>S^9pgxA&RO1{?5iC_Ar2Hq&Iu&^oYSn_-5 z!SG9SnMa4ab+{ju5i5wOt~OMxC6r$G%?wBbVUz>vN|X+isV7c(}ya4XKEu zSJ~Qa!1iZD(Z1{=1?A5{RkfPUWEX0o4!@mgUb>gymF?qgiVa0}^F52X7NcWuCrAN2 z@rBd35aoS5=c|>gQMS_g;lIH#iq)k3%(+)RK!`Ls$rFuA#jEg!kki4$tE>IU_prN? z0e_imWea-fU!`lm&D*CyrCu(ztN)xOI zu3EYmJ4M_auAF+X>6MZ-*E>pTY>~*Dr(|ZXp7c>PqJb{Ao=pKmne;vC3gz>VZ(ZcX zM2ptY@*{69w3er={6)j)vA!$P6d*d-qnNLczd0>UPw8+{7$qL_KK0O8dEVzT638E7 z&{czynp7sUlGfPU!VNLtGTB+vFox$sG!xtSzQ&%TuD;wkl9`+8kiih{@-j#c1l+)x zF6>Um$FRFix?_$;l;}A$1k2UMh*8QqQYP^HqzLsh1u}Fx8t9~53O5=WpL7?e^0ZAu+7Dj(xv243 zt?=;b4PV%p+o$&EybdpPXbhhn`eX8$(7WHVT;wy;KglO?zvbx97fXc{hx4Atw2Hr= zh3z%mRG=HY*`6-Y7{9SmwRYPmva^_u+nbG*-{z`OC40YvroJWAtlO<0O_GAI2l0;g z>uSd~vAB@^FnX}cr%FB65`O|GD_`<# zumFv$hCLy5zi5{kWNNsqKmeL(4hFx7KYBo|IkQ{I)p{tH{A?WC2h2}(;#A*&p5e=r zMEFX+dCV!#`54^3u*GU%s3D@qaUg+(xauAsH*oHb3Z>oNeo_8rpGyz!*5_xfZOOK% zrN#?shVi%yTZkO(&vBC+FaRnTI}dXHGbnTBnh-&VM;uFSnp*?9fa2F;&*J(jb@h*gIc%;V9P5 zDB>NvYC`8}c}kARHPLU{j78$|moZb^_0~z-zYT}aZ|}vf|I@mj6`^C^YgMo+{>?kA zEBJuo-E%*ovqlXyyr1MZpcXaVPjtK=bpJ6?NCSUY-mM@W?gJI?(flvw{l%TXD0uK6 zyWd}I|BIN1|5?}ii^+d+_AfFW{m1V77pwl_uRFy1r%sB{I0kax*WiB)q?Qo11^{f_ zTw!*uusdlDqK<+}^5DOs?vbg)%l7RWQ~-b$0|2a$hUL5V9vgihDnk6Ckyr#d83_@vZ=FesKXF zFYl-SuAnpR@*Hwkf%@I}XQT}8zn(&3JnpXlazqT?1xF?KMeLjaDeseEo&u?*p?&~> zi6+Ry^%%mKWg%SORs(n2|!q#0;%ppy}S#B`Z)rDyhG#r zr~S8B`F~#T-~Lm&{C7UkAxLKA?qK`x2E~8f?y&mxZT`D}A}R#;8Sq{hMM$3A<-{mQ zK+k|I_x$xemw1oJI0N$D^Wi)GpvoK-!Do%ifcMWd2)gsT&EmBP>2o0G{br{-{$SPf w0Yc^+NFgBb|DWEGsXp5JWqTz60P6$*X#P=Hi8%0&A7b|$NQz##4ZO4dKP9dL8UO$Q diff --git a/memento-note/extension/sidepanel.js b/memento-note/extension/sidepanel.js index 287d9af..716975b 100644 --- a/memento-note/extension/sidepanel.js +++ b/memento-note/extension/sidepanel.js @@ -293,11 +293,41 @@ function updateSelectionUI() { } function applySelectionFromMessage(msg) { - if (!msg || msg.url !== pageUrl) return + if (!msg) return + // Tolérance sur la comparaison d'URL : ignorer trailing slash, query, + // fragment. Si pageUrl est vide (panel ouvert avant refreshPageContext), + // on accepte la première sélection qui arrive. + const normalize = (u) => { + try { + const p = new URL(u) + return `${p.origin}${p.pathname.replace(/\/$/, '')}` + } catch { return u || '' } + } + // Si on n'a pas encore de pageUrl mais qu'un message arrive avec URL, + // on l'utilise pour amorcer la fiche page. Très utile quand chrome.tabs.query + // rate (ex. onglet sans permission, side panel non focus, etc.). + if (msg.url && (!pageUrl || normalize(msg.url) !== normalize(pageUrl))) { + if (!pageUrl) { + pageUrl = msg.url + pageTitle = msg.title || pageTitle || '' + try { + const u = new URL(msg.url) + pageDomain = u.hostname + pageFavicon = `https://www.google.com/s2/favicons?domain=${u.hostname}&sz=32` + } catch { /* ignore */ } + } else { + // URL vraiment différente — ignorer. + return + } + } selectionText = msg.text || '' if (msg.dir?.toLowerCase() === 'rtl') pageDir = 'rtl' if (msg.lang) pageLang = msg.lang - if (state === 'idle') updateSelectionUI() + if (state === 'idle') { + updateSelectionUI() + } else { + console.debug('[memento] selection updated while busy, deferring UI') + } } async function refreshPageContext() {