From 20a40f8427840c4badfda3c2577387cf5f892223 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Tue, 20 Oct 2026 02:22:02 -0700 Subject: [PATCH 01/12] Move setting the Adaptive Cards Markdown engine into setMarkdownEngine --- .../Attachment/private/renderAdaptiveCard.ts | 23 ++++--------------- .../Attachment/private/setMarkdownEngine.ts | 20 ++++++++++++++++ 2 files changed, 24 insertions(+), 19 deletions(-) create mode 100644 packages/bundle/src/adaptiveCards/Attachment/private/setMarkdownEngine.ts diff --git a/packages/bundle/src/adaptiveCards/Attachment/private/renderAdaptiveCard.ts b/packages/bundle/src/adaptiveCards/Attachment/private/renderAdaptiveCard.ts index a41cc32e71..8ea39fadc4 100644 --- a/packages/bundle/src/adaptiveCards/Attachment/private/renderAdaptiveCard.ts +++ b/packages/bundle/src/adaptiveCards/Attachment/private/renderAdaptiveCard.ts @@ -1,9 +1,6 @@ -import type { - AdaptiveCard, - GlobalSettings as GlobalSettingsType, - HostConfig as HostConfigType, - IMarkdownProcessingResult -} from 'adaptivecards'; +import type { AdaptiveCard, GlobalSettings as GlobalSettingsType, HostConfig as HostConfigType } from 'adaptivecards'; + +import setMarkdownEngine from './setMarkdownEngine'; /** * Returns `true`, if the object is a plain object and not a class, otherwise, `false`. @@ -29,19 +26,7 @@ export default function renderAdaptiveCard( setTabIndexAtCardRoot: boolean; } ): { element: HTMLElement } | { errors: Error[] } { - // Currently, the only way to set the Markdown engine is to set it thru static member of AdaptiveCard class - - // TODO: [P3] Checks if we could make the "renderMarkdownAsHTML" per card - // This could be limitations from Adaptive Cards package (not supported as of 1.2.5) - // Because there could be timing difference between .parse and .render, we could be using wrong Markdown engine - - // "onProcessMarkdown" is a static function but we are trying to scope it to the current object instead. - adaptiveCard.constructor['onProcessMarkdown'] = (text: string, result: IMarkdownProcessingResult) => { - if (renderMarkdownAsHTML) { - result.outputHtml = renderMarkdownAsHTML(text); - result.didProcess = true; - } - }; + setMarkdownEngine(adaptiveCard, renderMarkdownAsHTML); if (adaptiveCardsHostConfig) { adaptiveCard.hostConfig = isPlainObject(adaptiveCardsHostConfig) diff --git a/packages/bundle/src/adaptiveCards/Attachment/private/setMarkdownEngine.ts b/packages/bundle/src/adaptiveCards/Attachment/private/setMarkdownEngine.ts new file mode 100644 index 0000000000..2f4d2e325b --- /dev/null +++ b/packages/bundle/src/adaptiveCards/Attachment/private/setMarkdownEngine.ts @@ -0,0 +1,20 @@ +import type { AdaptiveCard, IMarkdownProcessingResult } from 'adaptivecards'; + +export default function setMarkdownEngine( + adaptiveCard: AdaptiveCard, + renderMarkdownAsHTML: ((markdown: string) => string) | undefined +): void { + // Currently, the only way to set the Markdown engine is to set it thru static member of AdaptiveCard class + + // TODO: [P3] Checks if we could make the "renderMarkdownAsHTML" per card + // This could be limitations from Adaptive Cards package (not supported as of 1.2.5) + // Because there could be timing difference between .parse and .render, we could be using wrong Markdown engine + + // "onProcessMarkdown" is a static function but we are trying to scope it to the current object instead. + adaptiveCard.constructor['onProcessMarkdown'] = (text: string, result: IMarkdownProcessingResult) => { + if (renderMarkdownAsHTML) { + result.outputHtml = renderMarkdownAsHTML(text); + result.didProcess = true; + } + }; +} From cc1443ac9ad1009fb3b73809f028094d7be525d3 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Tue, 20 Oct 2026 02:22:02 -0700 Subject: [PATCH 02/12] Read Adaptive Card text in the live region as the card shows it Text blocks, rich text blocks, and facts are rendered with Adaptive Cards and the same Markdown engine as the visible card, so Markdown syntax and {{DATE()}}/{{TIME()}} are no longer read as written. --- CHANGELOG.md | 1 + .../attachment/adaptiveCard.dateTime.html | 91 ++++++++++++++++++ .../adaptiveCard.dateTime.html.snap-1.png | Bin 0 -> 11519 bytes .../attachment/adaptiveCard.markdown.html | 88 +++++++++++++++++ .../adaptiveCard.markdown.html.snap-1.png | Bin 0 -> 21011 bytes .../AdaptiveCardAttachment.js | 34 ++++++- 6 files changed, 210 insertions(+), 4 deletions(-) create mode 100644 __tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.dateTime.html create mode 100644 __tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.dateTime.html.snap-1.png create mode 100644 __tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.markdown.html create mode 100644 __tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.markdown.html.snap-1.png diff --git a/CHANGELOG.md b/CHANGELOG.md index ff95eb4dc0..fbe0941f0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,7 @@ Legends: - Fixed GIFs in animation cards looping with no way to stop them: they now have a pause button, and do not play when the user prefers reduced motion or the card has `autostart: false`; the icons of the Copy and View code buttons are now visible in forced colors, fixes [#5734](https://github.com/microsoft/BotFramework-WebChat/issues/5734), in PR [#5897](https://github.com/microsoft/BotFramework-WebChat/pull/5897), by [@OEvgeny](https://github.com/OEvgeny) - Fixed the "Positive" card action button having less than 4.5:1 color contrast, fixes [#5713](https://github.com/microsoft/BotFramework-WebChat/issues/5713), in PR [#5905](https://github.com/microsoft/BotFramework-WebChat/pull/5905), by [@OEvgeny](https://github.com/OEvgeny) - Fixed screen readers announcing Adaptive Cards without `speak` as just "A card", they now read the card text, in PR [#5922](https://github.com/microsoft/BotFramework-WebChat/pull/5922), by [@OEvgeny](https://github.com/OEvgeny) +- Fixed screen readers reading Adaptive Card text with its Markdown and `{{DATE()}}` syntax, in PR [#XXXX](https://github.com/microsoft/BotFramework-WebChat/pull/XXXX), by [@OEvgeny](https://github.com/OEvgeny) - Fixed screen readers announcing a single audio, video, or animation in a card as a list item, such as "1 of 1", fixes [#5722](https://github.com/microsoft/BotFramework-WebChat/issues/5722), in PR [#5903](https://github.com/microsoft/BotFramework-WebChat/pull/5903), by [@OEvgeny](https://github.com/OEvgeny) - Fixed video and animation cards disappearing in production builds when the video URL is relative or invalid, in PR [#5889](https://github.com/microsoft/BotFramework-WebChat/pull/5889), by [@OEvgeny](https://github.com/OEvgeny) - Fixed timestamps always using the 12-hour clock, such as "4:41 PM" instead of "16:41" in German, in PR [#5920](https://github.com/microsoft/BotFramework-WebChat/pull/5920), by [@OEvgeny](https://github.com/OEvgeny) diff --git a/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.dateTime.html b/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.dateTime.html new file mode 100644 index 0000000000..494fbfdd32 --- /dev/null +++ b/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.dateTime.html @@ -0,0 +1,91 @@ + + + + + + + + +
+ + + + diff --git a/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.dateTime.html.snap-1.png b/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.dateTime.html.snap-1.png new file mode 100644 index 0000000000000000000000000000000000000000..d02e7faa075d5dc1785489b6892fc872b6c06387 GIT binary patch literal 11519 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 + + + + + + + +
+ + + + diff --git a/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.markdown.html.snap-1.png b/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.markdown.html.snap-1.png new file mode 100644 index 0000000000000000000000000000000000000000..f330909696843e3212aa8ab4bc9c97da49a7c176 GIT binary patch literal 21011 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, which has no text content. + renderedElement?.querySelectorAll('br').forEach(br => br.replaceWith(' ')); + + return (renderedElement?.textContent || '').replace(/\s+/gu, ' ').trim(); +} // Perform a depth-first search of the visible elements of the Adaptive Card tree, skipping hidden subtrees. // Actions are visited but not walked into, so the card of Action.ShowCard, hidden until opened, is not visited. @@ -69,6 +80,7 @@ AdaptiveCardChoiceSetInput.propTypes = { const AdaptiveCardAttachment = ({ content }) => { const localize = useLocalizer(); const parseAdaptiveCardJSON = useParseAdaptiveCardJSON(); + const renderMarkdownAsHTML = useRenderMarkdownAsHTML('adaptive cards'); const [ { ChoiceSetInput, @@ -127,19 +139,33 @@ const AdaptiveCardAttachment = ({ content }) => { walkAllItems(card, node => nodes.push(node)); + // Facts are rendered as text blocks, as Adaptive Cards does. + const getFactText = (factSet, text) => { + const textBlock = new TextBlock(text); + + textBlock.setParent(factSet); + + return getRenderedText(textBlock); + }; + + // Same Markdown engine as the visible card. + setMarkdownEngine(card, renderMarkdownAsHTML); + return nodes .flatMap(node => node instanceof FactSet - ? node.facts.map(({ name, value }) => [name, value].filter(Boolean).join(': ')) + ? node.facts.map(({ name, value }) => + [getFactText(node, name), getFactText(node, value)].filter(Boolean).join(': ') + ) : node instanceof Image ? [node.altText] : node instanceof RichTextBlock || node instanceof TextBlock - ? [node.asString()] + ? [getRenderedText(node)] : [] ) .filter(Boolean) .join(' '); - }, [card, FactSet, Image, RichTextBlock, TextBlock]); + }, [card, FactSet, Image, renderMarkdownAsHTML, RichTextBlock, TextBlock]); const cardLabel = localize('ATTACHMENT_CARD', card.speak || text, '', ''); From f55e6349186272b737db13f101e4f79b94b4106c Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Tue, 20 Oct 2026 02:36:24 -0700 Subject: [PATCH 03/12] Let htmlTextAlternatives read any HTML node and export it as internal --- packages/component/src/Utils/activityAltText.ts | 14 ++++++++------ packages/component/src/boot/internal.ts | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/component/src/Utils/activityAltText.ts b/packages/component/src/Utils/activityAltText.ts index ddf5e4e175..bb7131f8e2 100644 --- a/packages/component/src/Utils/activityAltText.ts +++ b/packages/component/src/Utils/activityAltText.ts @@ -1,7 +1,7 @@ import textFormatToContentType from './textFormatToContentType'; -function walk(document: Document, walker: (node: T) => string[]): string[] { - const nodes: T[] = [].slice.call(document.childNodes); +function walk(root: Node, walker: (node: T) => string[]): string[] { + const nodes: T[] = [].slice.call(root.childNodes); const results: string[] = []; while (nodes.length) { @@ -75,15 +75,15 @@ const HTML_INLINE_TAGS = [ ]; /** - * Computes all text from a given HTML document as flattened array. This is best-effort. + * Computes all text from the descendants of a given HTML node, such as a document, as flattened array. This is best-effort. * - * @param {Document} document - HTML document to computes texts from. + * @param {Node} root - HTML node to compute texts from. */ -function htmlTextAlternatives(document: Document): string[] { +function htmlTextAlternatives(root: Node): string[] { // TODO: [P2] #3923 Revisit this logic with W3C standard, we could do a better text alternatives computation. // For example, is not computed. // https://www.w3.org/TR/accname-1.1/#mapping_additional_nd_name - return walk(document, node => { + return walk(root, node => { const { nodeType, tagName, textContent } = node; if (nodeType === Node.TEXT_NODE) { @@ -133,3 +133,5 @@ export default function activityAltText( return text; } + +export { htmlTextAlternatives }; diff --git a/packages/component/src/boot/internal.ts b/packages/component/src/boot/internal.ts index cada18e9f3..674de1fa16 100644 --- a/packages/component/src/boot/internal.ts +++ b/packages/component/src/boot/internal.ts @@ -15,6 +15,7 @@ export { export { default as PartGrouping } from '../Middleware/ActivityGrouping/ui/PartGrouping/PartGrouping'; export { useLiveRegion } from '../providers/LiveRegionTwin/index'; export { default as ScreenReaderText } from '../ScreenReaderText'; +export { htmlTextAlternatives } from '../Utils/activityAltText'; export { default as createIconComponent } from '../Utils/createIconComponent'; export { default as FixedWidthImage } from '../Utils/FixedWidthImage'; From 9d9b9447cb1e919cedea3a68ae21618ddaf0034f Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Tue, 20 Oct 2026 02:39:57 -0700 Subject: [PATCH 04/12] Read Adaptive Card text in the live region with htmlTextAlternatives() Image alt text in Markdown is read, and HTML blocks without whitespace between them are no longer read as one word. --- .../adaptiveCard.imageAndBlocks.html | 92 ++++++++++++++++++ ...daptiveCard.imageAndBlocks.html.snap-1.png | Bin 0 -> 25177 bytes .../AdaptiveCardAttachment.js | 8 +- 3 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 __tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.imageAndBlocks.html create mode 100644 __tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.imageAndBlocks.html.snap-1.png diff --git a/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.imageAndBlocks.html b/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.imageAndBlocks.html new file mode 100644 index 0000000000..2dad3ea518 --- /dev/null +++ b/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.imageAndBlocks.html @@ -0,0 +1,92 @@ + + + + + + + + +
+ + + + diff --git a/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.imageAndBlocks.html.snap-1.png b/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.imageAndBlocks.html.snap-1.png new file mode 100644 index 0000000000000000000000000000000000000000..f2a916ac38bc02f5dba92e90468a8c2bc8f549d5 GIT binary patch literal 25177 zcmeFZRZyH!w=J3kYn;YigS)%CySuvtcLFr-uEE{igKG#D+%34f!|nWc?}u~h-l|h| zUN;Zx0lx13SZmHP#vF5g9igNki3o=a_vzCoL}@88l~12OTYdWUM0}Z`A!4FR;rGf5|v(-Dv>PINyF%@ck<8+aQ`EAFy`w zY0~4o$wvFL+H6hDfl$D(rkNm-*q!-Yi;dyJ0m%xku>&KQs5ehp5u4F zoJ1ktU-u*BY>oA_<>#=6fGx&;pe988Q4WE3a zhjow5Bt-$(1fH{|**xvpQbkGbBFF=$N$vwZzq@&^&)FMLSbFhO2fREy3Ib1m6@7Qm zkOf~aYXjbFsgj97U5KYzTn0X8&EQRdP7Nxt_Us%X^f_%_G-$M(l7RpCODRbGC2ngc ziqZdS25?o+4J@TLOWy}malXOA01|6iDOBWAF^j1NLePdlIv>S&U-Rl{R>P8 z5O}-8F;PP%N`W~!IoH6xKp4U{ZNy5A>R)@#ng(9vEd(Rnx6`8Z<3WqTxWsHhDA(>P z)-X(qZXRt@8tetA4DEjtU3v8V;kQu&@$EiTCnhEgKb{w1($-vO<-u3qH|~b9@&URS zbegQ3wnr1l#8HS4H$y{3+e*>%wd=L_5D^jG+}xtD7&j(iwoA8E>sUA{5s_rcaU}sy z9!vF3#IfJMjv@y<4s2`~0I|OS6p8=TgF{IVyzQh+5-1U%4^#>Kq9t$$KdiY-IR?C} zO06L|8had-OdNN-siRg2^-Off0kqU5W@hb4&scF%U_88&qU3&Z{ zF$$bM>3texPhb{*-UYvtI2}Yt>zXsXN*#cKcqA}-xVm*CQbbH{rUl3&PJ?bS`a6S_ zgmW~@p%On(eJ)9+7==OHY zB+Qkvm`c8e)QHI97F7%ZFJ?f;aYdz*%*%P_#q-@sLbteq1d2#S4M{t(C>Bz9Ms%D6clp>-ineGR(vjg zBJ-ZsUHD!2WVtPS^J=v_@BJN1BJw`WpZFCg`2L9OcPI)zDu#Mf&Aqb1SQ~5WKpQ>p zqhhOiDzDubP6h70WbH-{{uPDk^Ji934M)i9WEq^_y)lMDSqnoq9(E?(4x&S*M5hN)av_ z5YPioTe4F*4XBo3eUJ6K0it)N>?f1A=R2#*MZ*AogBfo{u5Czk5rOWHw~I}eDSoBE ziH@e8>tD338{Q|U%Z=>vomazn@F8E|IPI1$lX73pR+_A9d)}YHnd7;iVTnY*gAP6Z zFAlF^{z2Z)`<0XZEJqD=C>s{b$?Q75+$l>I956hW#@BJ>eF5j#o;a4i>+?}*zz$k2 zV3%ME3@^04kxrP5gG$Eeb^!(m>Dc=E`rAe=;PBZclZZy?v(hYs=E%b$Wn$oXLGLH8 z1%JjrfTS-a?tZ-<$70aq@{~Xp8C{J84F!I;qQYb%HF7wuA0hNS9ca|*_Vrp?5d{Y+ zwEmL9r1_@b0|B@5SF0tngy4eBm_Y{2yw#V4mSm&o-DYPfY$GEt-EqB6P)Zsb(({1-FwsE}YTp;f4F5(q$ zFrV04lB0`BUv(Juefh^`%hKC`gMIFUY?rziA&N}Dwk5cr!hadsKuDTiCu^6f?!+|3 z|De|n0oci`(*x7W?4Li^U>@qt6CyUPloVqz2V*OsB-9a@K>rb;jUlpOOmocrTk`MZT+1d9I=*e?u72>oA|{hwSAOSZK?-H(dXN@kC) zWgLoVUhi9b*1>`Kaq;o4*tP5Qr-i;99G+oF1kYg1lODYRQ=H#jrJ*<;EEf0c@|3@O z?`N2Q($8kUa-&J`{Rh9z;Rij`>H*7pUxaba-tYIsPw8H zew6AYwWP=t8@}#ffn~uXIO=%aj^~bMOT#K(euPslIdF z(%KrZ&zh?ZCPeZ(-?tM(#jmI)rAuJs8gNJ@F?{UD8jd4k+z|c?+THNEc-z71d0gyy zcWa!_*~GYn_q#158v2LN-r!*V`FvbS^#tA5S4eT^)ZiF0j1A#lsW7 zjLHRzppT<NfkywnY5mLH*<0q?J~3cQG^Uk4xKMUk|-JelDH zuObw;=;87gjK_#R9!Ho>hqv}SA9tdReaLD8OKC;$E(PkQ*cbIwYfuz9(v4XyC($vc zXJ=JaRnZ&%lbwCfyj*y7|u9f9xV=FVXnbk8lwE% z^YPNNopc6{P-+FDC;Ha4AWCGK3#9J^fdrRuAB|dc1&OK(+{NA9gzQ^Y z95G1c<5(?1Lb%eC*p zJHGzl@DE9$(``YJKxCk1xEnwg)T_Z!bZqk=UP+3)n^+Ubh8}wBBoqMgis(=F`pXIVN_3#S4}*}|1k#^aulIU#ith%2fgsiyyn|t%qv*3F7}A0> zye|7-cKMWJTUP}Gt0zk-=VRT&K~7sLBB$a^%rJ6qfq{Ya4}CvyrQiH|}zZTAm zuM|fxUBR01JFVw+uMRTxE6t$rH_9I#8(wX(cpP@$%eFHM$hVAReLNavICvFbe`^~0 zvFE@t2@g=GDZ}bu&6!mi!u5waVL3>u#qJ~GA&E|c8ba^$2;LL!tn#7o38M6iFyiPKsKPV7UnoQKS>UUQoNr8iLSbKkeztj%%!E(Gh+;DDPb?o6sjR57t zeA*<*E`0q5KUyqiqw#(Dh2YGGiQ`(c^mN#|-j>;JS*=oNQrBySK<0DOJ-7!;Qv4}M zeE9y)cYXE*sk`3-HL&7F#HU~D>P3;w$8QFoc4H;6$?3w1l^ifupH<8+ml^$zWJ#GS zIKi=Ml#aUjvhl$20?=_>)(yP+q6@tUxr3Lw)eZZG&c`&vaVa-Y9f#QT`;5qesk*w_ z3Y!bA#@ADJB7+r%)0Ha>FLU~ErVuDV6~LYivGy68+5|68TF6S|1oj~K;Hw&JU;mlh zN+=^?<{?+cB{Tda*DgYtwAJ!P8tZdvF5 z-(Emp5LBD*CDvupN`wFF>k{HToR?9~R_loAXRO12qF-H8KjeU(ftf+o%Ni;hRiVmm z$05c32W5`PBl$GywEwi&0Ez{0FLP7@Qp(;=LxXB+or)j)Gd@Ta8DEf5HhYmnjN zLaJNipp~B{LvUQ?+f$!uk)<`bC_E>n2#`>TEb{uxk&SHg{Ox)N0i|MP@lMVhdSRFL z>1~1Ks5*1H@_jq-{kmd>xNE1z17zdh9V00q^AYG1=mXW`;&xa1i$+)>6iq!L3s~|r zbp8G!G1OkN6$!0UFUF0Zb4{kc^nMzob(onbxf{8NS|V+t>+-o06}=dAU*7ih{t!rk z8v&<{%USbcsG=iKik(I1alVzUrL~LdlJ81(SNJm;Qq7=-uA@2~6%~)(IV>7Q-kTkF z^D|OhL-mbV)Q~8)gk(Atf_Z%+BNQtk603s)+xxE@F3+-^SLF|I4IP3UX*7(cHAjV? zEf=T-azE|yYGaw+q?ugR>7LUya0zGZ;(pvVHfZ;)h^N=$w5n%PS*SH6Qdn=IH>%yv z6yndXE~rp*#?9Bqe~t@YKDw;{ScFk6c9FNyI$cD-0S;z^IU}PGW|k+}{63H{+G#vp z$)>e55P^dqS9L*sUCTL2@_Ydtx{gqRqHCn98EA5lQ?z9)EP$O&h!V-Rz+T>#ab=#h zZqJ&~f^Pa2w;UxnY=XyzOV$3v(6UomW1^*EtO)YRS$pl~-uwy*&t zYJ{Y>Iua$vGJx0bYM>HV!fcS@1&U#+g~EQos~?rlCpox}Glby%#P9<*FtnNw{wl4{ zQ51`KEp+~SX?+l zHnUm!vZq*7@6dM_Y~0^c6dyw0k5foqK13~d&m1z+SgC3NzWthY?(rX27UKa{Eg^^#-8;uppaTMOS5(`wj72rfz_av{g+GEOMNAiNhodcQkhFLXd8tM2Y;l079s{kp3OJPo0zmMkZ~VE?;fNN*BVkt@ER;0(P4mVa z_BQtMc~S=$cytB!uCJqzuLM>wat_(7{;F#TZ6QuMPPEg%l>pixE>ilSX)*?2&_~@< zf+mu!L=ki#VNpk`x4Dz)7VVY|S#qpRerdRUNSuZ*uP+o|Q{Jwp!}bQe{ol)sz}o1- zE!tg=LCs<1799f)oR$FGPjM=GmU{M0P-{lhN_sJu4#Le`{DYxa>B7F~=h!tg-7NlO zd}>a@d8d!o(>6|yqM}#dPQT9ztw6Oxve4;rAT9wPZI;l=XQM&; z;sLA1t)s~O)?E+A(ZMLBFqYhupi=~NB$05o|84na(N(u64z?Wlk%GE{&bT}F^rTlaAEdz+$%T{$H{(=FQ?*wv*qVA%NC_^S&xA_>8!Z+GFzxoX z8Dd`#8cWAss&0G`KiI-U=KdS+ zD`03K`W@x^J+#mimc-e~mG1w?So+_5rmGOsM)6iy60;X7{3#hgLP!l9i5M;%%>OL^ zvj_hZ2mg}>{{sd8gM|NwNSH|g2s`Nj8`>@Q@FJry5c-RFxVUQS>yrYJ2VSdBE|!*- zG%1l1h2XYAU!D?`8B0byRs|D)&@+R#2*mUm5b}x4+XmC5t?*{lfG7@zUA@{#Rqm z8k{_{33msTU>wi`wk_0UWql<>&TSW>^#Ty3i zo@*Hy@6IT^m(2a=p-I0~jfym}0ICnE*iOvzz1=Hoa>T7)#k{bN zYA3fA6i=XRuSp)x9-imd5xi3Z zJndR|xb&oV@$9y2r*XI1UNK}sn#CHKO4L5OZ(o_-C_9w1k(oLyW=gPwr9o0lC85nC zGJh#rT4#tl^X`Usok7T{DP$iJ%0q@RPuh{VYNi9ZFepI=xSA3AJ}8JLG>0Ve6&$6> z^4~Ad1PS0oCA<2?KcOol2@X|wYt&B*#$OyM4w_tfuGR5#>V{Ki0wc6j)t#f1$!d5E zJUk4$)$A_Utn_jHqgbiF0z>uR^2&FA`|RC8+^;-D#}O`~NdNx9`>@A(K!0WcQ(7vl zm^@`)m{b5F(%`fSJ(10>#S4nS5TPml)o*;9Ks=92!5MUq!*|>mJ6%|kG9musj}+Oy z8?v2NW8d7oCrjYI&UGVwEEBfmhtRSYv&twHEK|E`3#^nQED7gFYUP7ZE6@ zNxG-YQ2^Sq6T9;X-x{J%c_pSPAQ@9b1&ByNsqt1eQ0votS$2XTM(iknT~)#744tc> zwHskaoKSC0EP;w07(Ru)M-(Tv&5qtwa670R}4~g_$98#m>S?dVm?3#19rad=~?(f5g*fFHZ6^A0( zI@(#EYjy5x_B`FC7=C2tj8A29pVaseN|&q_*fcD-^f>QRhanN^=#H8#)Hum{aZ$!s zw_%Exajb4y+Su5t-b|3k7d<8_Ty_mBruLlfQr!!21F#Tj>5sNPG4Z<9>CEqi!T7hhcSwH52`M}g%(J%bM!E=u-Bc{ zMW*vH-McQKCey6dXPvI+!L_wvBBt(-Yvsv_Otzn^Dwig=A#K;IX)PUZh~z5Uro}>| z1*yq2hmakP)N5kHA>W|w$$4Um<_)lB~;l481D;i zc%RNlSrfOqH;?YQ{A|ycKZ8;nDGBs)Vv7)t$EIJU#;I#w>}@dMlG1BS+1;Vnb;#Ba5?`Qmh1&q&KTCF8l-?3G{S7 zl*aWe*&b;a3cAv)Xk9D~wTMwW0CXd&Hm0>*JJ@H?)aQzuwCifO!t z4Bi{xH5|79ysN=MH-=m(&*3t2B8f|*SCfc_ZM^+%RGieGW;07G%E4V(Q&MXzA;j5S zP|@q8+YyPyr&P(JUk0=z2pl-mNx)Mel7dd-Y2aaSTP}E$>DcU+ko_yv)q%pJ4;EYI zy^VDcUGg`Fph?+7GLQ=DIf^%f$#kz55TR9aqHH0~ipGYD*@nqSYlUGbF#<92X;$}x zG?!HnHBjNSiKzI41XcCWsd0mh6u5jS1@C z4lv^1-QAgv#EK_{u78GrBwwnLFWKtJ+dhbddIWZ(^zs5ANt;-pJvivUr-Si@6i3@C?%04vPlv zaW|4L#{cT;V~6Vhvdi#76m1MbQTaR{`>oAD_auH{VZoKf+{!y3Ab=z-%r_d3yQ96P z?*jIi%k$3*nYsNcO)5&(AawE<;4fzla#!_V{mR3+s8wnz0|b1)s39W{q4dkXuA}nU zG~H!(|KG_W?Q5LiZWVb(f8CX;shfO`Ibw`WDN&c=pGmJ}JAo|r392Ue4>6`jB_>+z zhVIN?U}c=5Y`#4mR8J|3$q*?C z$1?HqdiwX)tz3Iza`AJC38amiu}qU~>9pkAKy9a2WZurLs5SU4>L1jcKmJMS@pO?^ zJW0PY_$n~H+N|qy6IK%KzDOVJUMA6{SB;G>0UIX^SSC@&j17JEUTxsv;i(b)AF8*!g76fg#yK}|!Ta{%^XcFElA_o)XtAId`qK@Rz`IzufJs)MU$u*ny zYxGYdtlqC>-5bq6Dm7zsnhv6(7JSbwIctsy${dMO%E}ib-%5$nHt=HnY0g>3*hj_=Q8GRu5x7MvXKh{E1-Ln9l6ROR$C{`FbsY zbUMLVP7NUw($(n($qx;r_AUAR+(Akry;C||O7>-%Q=?nEu7P?&ifX2#MV~Oh<%#J1 z8jC$Avcy)clkJ<-S^EfK3CZTkp|MaCKIxF4ohm1w9Gny*OZPy1+r^iw@fEd=dT;pU zKoyeAXv&`^f7GHdO)_lsBIXXiHO;Gt3Bl5pCPxqQt^NrK%Z@g&ff|CP0Nn9L8-Flq zL_*dGu61`Z9s|Cb0+Xi;B;1J$|3(ei;OgMvy>xo76_|<@SkPs*MqPnsR`gtk-dGKF zx*AHl*;m-?)HgeV@5^`}Mwx#^8ET*GHJ9N~b4e@CAS7I|L@Kkbe-;Lme+R31LT0q` zuXIQO8%pCM09E90aXG$a`%(}UbQNmyW1sRk+&I)?O>+1cUAUTMdN%73xJ zSx)Q@YIq^pOw@iP^bTUEtCCuQX`PuS3@aF7=-Af({eYKOA2EN5#O-eA{m<=sNlx>o zz!SSId`5Ia>|IJEps~pGNU!Cv44*(&N*oNZ8dZ9*Bf?gAmGePt5vI$`6G{V5BipEu z@a0SH(wfao&Oij#)x*TYKqaaVzFOi-;9u!C0y@e~!7ZqYFVD4alH_AbND&x0I%@XFUd{ysa!!x5wAJhwfz&!R+qeqS z$!aC0u;t<4qf0cGoyi%vgk0%_6?ftXgl$tpXCsX>d^Zs={M|Plo)wBKcV~?oy3g2K zQnszcseFEmflW}+TFx1E@L<+@3Tpp`87Ia9OKWPcNx6nrhA~K*L~t4QTf!8${+&-; zoqdDvdMa*GZ~eziv=*BNt<3#k>QXxl0Sc}8VvQk=JO$eX6%x8>eNnLz7vSFwg_Y7I zSh4+X36+MESDpz?3N`LW_+~$H<>LT?(8{Csw{%&BrM!ln`64KOQ~Cx+bBmRA7d9@; z9`v~(bH^LvEkmVy3)wCNaEDxE8ll2LG%Nr08)+!@tKwr==mA%p=YN@rvjViLA!Sily|JD zUYwr0DIWHu$v=Fm*#H+QYa+1s@Mg5SqhuF&SFWO3-YoZ9<2U=Rx8%n*(djDDHi+L& zs>qPD*R(b}%_1yQjH0&K*cASXf~!PruE=mt9{)MjN7kH^?NPRM!zTH9cycX#39&Hh z`ftz#>hPFUPB0#YfR{LEYaK^bEjBHqzTB=QL$W^?0wpg=&wo3-lOmOEhcSCN1RZEa z|J+TC;ZkaTNBn{Y-H9P1j#mxEwNBHSKQ0Q~Z@0$R-?AU^Y~#o(+=JK4jE?QwcN|H*@HxMmQC*j?mDtvg9g?H`N(!6sIn)x-hznB z_8h!@-z1PYYFfa<}oNF@u!r;MD8?|VLM|6M1`?Q@L4XF$QSFK+wlvC zx7(WQ8lgdje4Jq{R;YDOcZgam)i&CLGJhjQib1FI)1~Wa`Wr>h zw?);E!03M!;C#ry!zT`Cabto*+@J)V8YZUrX1;CY0_1G6Hp)IK?advg!UQMMo#`S# z*hU)V{HD2qq((-eSVJK)80XGq+`Zj6wczuGT;3W=VJA7GjAtr zyPSoVX$SK#!@)nK2-!8Hn7fpdk1Ol2UEX`g^>6()AQZgW1X>yPm3dNK!sgqTf30-i zYOK@i=K{Mciydw!ugm-m%ZMinNRC7c8v=Hs9*Tw>2it8|a|OkfdAJ2icD8m7G7EHm zrpA7J^VxFbdi70(oHI;zev|rL9hQEIC2FJGPkN%HGyoC|r9EsIlQeDP&a1L4`gz@% z5~&JK-YrDybN$856vpL>@FN*}798cKs!}ul*1t6U% zE86N>160rezz5`dFVG zhltl`D1s@Gm+RPzIpF7ESJKpC(Q&me!|E&cql4kejxan~Cl?g8c+>zX={v2F`dQM6z0>>7UqS*=rIUp7{BBrCCzc?PfW4 zFSFOw3$o^k7sOhMn_4XVk|a%NVeZ5p8{SB~>$j~{WgEVQ#?~EJ9acZ0eSu|mJ)Dl%9p29`N=;3>bF(22g zJ*VkvF0q{NVBnqoSps1kJ67-dgURHo$a=LHEd5u8OR@`_<8VBl*cT@Zn;sJx{hv2@ z-y0Zoz3n#sblVw9dejoc6dfP`S2e3J)&Rt!N7s>DAZVIO-tcmyV?a-^0rrtLYzIeZ}e&}m5t9|}XjVex-`e7F1N#(ckUY7URZsNL;6 zpV@q(S!*ymyO=wdQj$MVs))~iemLfXP&>8<9W6#6Lj4j| z>F@uTFhZeb{}dT(An9X14?WM;CFVz(P)A?$UwRc~Ir>P4B$wL!1(D?V&r!Is1Q=p}F9vK)-+@t=rBF+YW)UoV?QVf~Ue2J;9^~EpI^RaCr+Asp%f`F?@Vf{ErT3%k>exg~XJYYU@50G(>^)v9!wsX-V2A|hm z>t*!3dq-2?!yHml@L>ktVk)=U#5^oZ%5z4FEu(?NGv`<*_Ww2B2BL@Uwuwb|w8a-& zcCM`Wa&FazkS)u$3uNBQ*vI<}Nb%|L%xrG(UQ)dAcuQ^jAP*H#9+?m!8X8Q7BFP=; z^_JHSvlL>i%5Z+Z_;;SOI6uZe14Z$0@oa3x2#F^4Z~Sb1Ugr z|LZo|HkNR29Pk95$L4>1xcj01;di8YFJLq^^6@?j@3K!}dtw3I zsZgPdF+CV|r_*9Yq96@&t>}hjdyj(r?l&0uU5l`(=nPxHG{Tu9HP_T+-q5niI>=^Y z^Y+a(lgQCclfmG!^d(nscKIo8xe*N!(eU|qDP=6d%iN9P$NLngj*W}GzG(S$txqb0 z(KoBqlPM_Df8cpm6?sf4*QLUY5pm~!H!PE*OEXNC&>UJQEZ>k(#w4fTjDkbI=b|vi zX7bMDrG?S2>?*D~uSb%kP%17Gb%@(gUb2@l)>hLAWaOE#gScMHii|qC43J)aeP|cWo%{Rw36`^Tcs*3d)=Fa$@O=z7?X{* zuXW4*oZn6!5SR)={q0qu0v6CLD&Nr~foRVu(S_)Usww}3ON z%JiuNWdpnz#B&fK!(I5g%Gg)7K8$w`5#;*t^W?}fcGQSGVlEVu@^`U=NL#ANv$zV? zkM`d|4%jnVbb*gDEX&i=#HTwI>Xi#M`kf8~(64TT;lR;(5QNQO$$L4WdT@MX`MXxi zwNoN^hFXpS?Vemw!UT{GH?GVVP~q}d2H_@Ge^PY&`vB_XNpRetJlXV@O+RMH*GL`q zOTGSgBN4mo0QA7PI@BR}i4#1YE|O8?Td2eYg_28-Z0X3avnBx_Cq!Zf7&GdG!%hJs9^u0y!*zV}EqUo-~ALl<91=fQ*a0JPYt- z3dyP?F?I-7g}TU4rkGR?Ccsa6P#7cNiqepM3xj$(LS7Q=z`%|`;%ti1om;vCr+U93 zt{ci=rpCrvmEn$pR5TD7v#F)3-{*<{`bpnq$&_I!K@JMcP#AwBmi@ExM=dGn2qgyk zM-|ErK$qIRF*syhBv%|V38J4=O0rN?Cv&>sO?n_QqzGs)^#YHVH}T>U^z?+>v;J}q zb&5@}A71I8g9L{g=mbp{#q-yKvsylCQI8~dVz0jtz>bF4f73ZI)_Ae{w9i4R~Lk2k)6kQCZF_;r{H(wR`4+XFXp2(@5Q zh}D{{fy)6Iv23n#{fI@zudx*^At-eBi}GaIM*Ik!j~21k&kTtT%DleyN+0GDZX%;d z<@a-e6=-Zy1IV0I;)}E^sg}o9H&@1@coK1TzqFqOH1)H_u&U%tyNJ7@OFD;q%hO$s z(cBzrl+c)WLkoD8Q`5QKZquK&I;aMtH4O*_EaY@&QS>8h-&GbU^f0lU^SxqAdXcHA z3$|*-DvxuFxhlSYn`y17CKqU8u*P^MV`fF>9GjM{DW&b$K5kKUecd2*h}Ze%H$usz z^&hGi&>%O#pkG2sFyq@?{aI40${v$?-!#waI@#q#n^t4k;XKfgqMuZH3Y4BZU@4il zSDcbiDVOWpnBF9cJG`>`T@U}xm6p!z)!zoT?5LFWh+?CtHhiU1%ckuU(`Xen1; zS5O@tX&^u93RXqQ@a~lu-^%=+rB{l)m*FM{tVYsp+IMBnnhuoP_ktl|sbVn5Kf7oH z&G?BS+3(zDlCM_^hTdxFp20-X_l(j)AiqH9b?D%8(d^@&$GUy@W-9*hTyq|3p&BL5 zGUO{JjH0fXS?>zR5XR~~$TYs;0v;a^-3LGWOO84^^b89OC_iRugQYZ2%1|;`wVvfW zlA%edsIAuT@&uxG)&=F^EzLXA%de+%-0K%H(H+}YiGcfidB6IB5#mrH_>t%6&|-WW zi$DCft|+}1(kLz(#~BJG_nsS{0$-EY@5OS8P4y*bYdSL-Co{NrVLOvKw|vEZ>(z%F zQLD7Fk4f>Qgl9bq_{b@Uxr&j8A`#$9e@zbGhJsM;QsVLz?Yp@ATrgu)Q%8J;yKjX; zYF#0_s-etPL&3H>wGIfF#}Z`1yZwCgk`DERp?(ED;Vc7K7Er%%KF5F;pKpxkUyh$b zj|u^oha7INf%12L6*l*-dm64)hHEoVmsMU-yd4V<7B84@g|_nrW!e?CHV);oSS}iL zsO-~`?9Ii+(zCZK9diki_#G{cvQc7a&4^F|Pn`2ti>bG-5edN#Cfm+%fRJZZpX5lq zv?ISIkSx(}D zVWIlDrL~UDThX0VPtP3i!*vZC>XpzORXUqj3oEha6V+!)tCEP^S7mLD7b`<920tDo zG&P0UlcbgwitjQ*C9t|BSUwMsWK=9SH&b;nh5xq~K(Fbl&$`_XHKiGo7u9ww8@PE2 zRDqo(7cO;U3^xNE%xYOBf(=lYz&kB9{!LS@Y{Q@new2!t-Dr(bG2}IX?SoZ={_<8%_EnKo86cbC>yo5 zk}@?fdGiy#bG<-2NkKw4jH4+I+rbCip%;dHX35xJDbeD~X$BqFe#KjY-;1_0VkuIQ z#>Na0>0>G!GMTBbD$5^uwJsYl+-W)S;Kk?&{iw_ogur>F-qgL~M|VsbB1ummFA@Rw znC^};!`9pH>?jxBFWFqu`ew4v0cLa7(|0;$NxL3^2Qx7XQY+MY4sC>&Eu=m zGmJAztS2ePJ-F?S8d;YF8=$8bz#vuPS&>^mA0HGtw3Ff!)YkpEQ91g*s)d&DBiO=2 z?Z_HWsozMqa(DvQMde8;e zPbLA5JUE`zhMIQx3!$?VRMd&SKJ{~HGlN?) z_S;S}-qYoBs_68%Zg9oqCp_o5+=bQ66u2>z$0yNJzUq#-JW6&b%=r>z6-N>#;vd$v zHWfA)*UD2hih~&Ae>mtLF=NvZ7aEbhZ4g=Df60pO!*e7yi?9B&V5x`nErLX44pD&x z#%R&$EKS>I`om}ls-9T-H3>0&*#lftcUSjK7J}5|z`1Zkxul$uXp)A{T48;qc ze(-CN!&Sl*)>zCHFmjE7CJ{&2JR;CsA5LkfF1#iZ2;Ay$=a|J~L>Qd49-o~zGB0uR zj%{#)RE8yiZoX{jF~Lp%KcFuKo=1RyEG?zntUSL2JFfQIS#f(Hrw`BK@>9vS z{g{@RsKD3UMSe!0^q?uT?;JIz+M>#-UOFBycn2w%R~vx=VVrEnDqjm^Gnfc#rUl*b zBvKw8qsGVK{m3+M!FinNUB)Am%+TsmPKSDgOMj zF)WYGnUK6)G1Sr$THYBGEMT$+ET2aC!v4C4wLLkA#>}qOO!xRuke>zr+q!|QkmOow*y4$gCU*Hz~;Ep}oz=Px9On_g% z$5LrXh;)0^X2Ku8qg$n3iZ!wFu2QOVBmcu;)Aak|(lK0u z`IirY)gjY@3nP6AeH0L4T4xh3oS+P1jSsr>$t3#?l(W*iq!xD0%*1ua;fG5>JXbw_ zqebad68jHEWUEsXgSNbn5;wQ#rzUJ`5KV<r?Uw9X8nKIO+AY>^hj6t-(V(y~+bK7hmKR|%lgKgjXOcUvMVD9V`3!ZEA{KCD$g9ruH-_{NHyg<^d`WolB zA9#ad$#8Eh3DHQEbxlhWCo3>q4kmw|c?f!gzbS-gp~}|URDW2r1@p;?`&M!b+z* zomG8;C~K#DyBA|q87u?+&JX=GJSuAcAMEzP>N^uhSb0kTk&$^`E`339gxU&{j1!` z*5tX|zdY-%xoAHM*H}$X0$Be9mV}wKY-urm3-}8Llf1c-k{(Ilg>kpp~j=Rrop@%{i58jRb;-jDxZViF!x>fBx)@3d;A$8Au0#6-0k#TZ+%96 zJ3aH2hz!oeR>$}fX0Y!c+b<(JmgXUkFObO9sr9p0?#QOIK1{Oi?0m}Cb9kqh%Kn}6 zi_cL@OTkwweD3v#-BQ_7HGj!sLCMBLuTUNw%F8*=TKTPI0&kX2TK)F646DLoV;Kee zObKy&+&4Y^zV99xljx(u$3H@!2*Vb3)Lk2nD>+}jeJ?HPKs){}h&Fw0#Wtaidccl- za*tI^$JiMCgoz@ZMqke>H2-65JZj@Y_Lvcc8w(Q5wWcy04mDdWL-PvgDRu{1lYSNzzyrLyGfz&9!0>24mIAI-6fmGv4F*mIsWm*e`P z+J0D&?cI}1%b>fXe!uEk)%sr2!XS-8(6g9v4!6;9ej3b^+y(+?q(KD2uGVEcCbCMK zvPfnIZBK7i^u*nS02~SrXP%le@L>Ky)jnJVPjAtg7*HvK3O*sF$K0DK*V`XJU*U2le+pJ)gp~&^t z_NNR1hCC}vt7lqA_>TqleV+|q((JweRd<4yDR*wL$&fySRO?K(_?f^{RLUKjTQg+( zXKdD@^%{%A_TJju^4p5%<|ZEA)b;3-flP{T-)`Y*kqqQzp+jfw=agId!jnL}|)y8P*i!8BT4(tj%h7_4f_9 za*Q5P$%Q_fWU)wb8FibHl#)8#F7`0KdU9|`b?5pj_NQ)%(?ZntdD|Y62hL$Ov&-_Y z`rh2~;5!i?=`LW1>XbbCd$-_&c%Cu`XI6EM54QZFjr4C-5@SDS9Yx-hw(T8MR_y2D z*w3!P=w~VBd+ldkS-j@WTDVm5_MV2OvF$%~jPRUQ;Hm_>;drl)(}O;9|F^dK`+&(1 z!4zp=EI#QF${ZhVXrSjWua~8($(Jg;r;933EGC=_?<~3GTv8#AA6oD{m z-l{-Vi~qH#%Op~>s5@{x-(NdjqGxr$+_hC@3k^&CeSJJKBzreZF1^2-sz`A%cIt=p zsYqU-(*lhqxK+VDpTgOQF<}q$NC*GhJBc#3=pW`gL(ZFc?PiY3uD=c2e~y9)GdMlQ zM>9FkZ*8V;%WiylZh>~KtH@+`s%HuEILzUba~tjPt0nU{?@YP^ycFq}>^9b%$OlJ zby~z0jP3WA+3%Ss;B@QCgjXEFT0oE_-zZgBEKn*wlc~y5G`2jslOVm1RoIc6`rv0^ zm7dr2>S^=QOF8#3qYb8?juabNbn3Rx*;pfI15(6xIeMPaS9)*L^;35;vx=E=QQDC) zc~P{ahNxm_YGR3-#(HURtFfxWJ)~#uZYN1t&im86YbjPA{p_*+!IVy^SdD!&bigR+ zvZ|$Byo@^vzjU?QZ8ItmM=@7A)HuH48%u5=WGyFs8r7n2ksR=pCGb=?H|RjYO6AZD zRh{yBxk4pQ>^tBcxSeq z4m(drxcu?{KyBbJ9FZ;HXZAs`&Vzj*edlJY0QB&>ZULorbW!ZnP1&GUnf;Z_#N%jn27DQ0fyzr!rzB)}mEmd9!!AEWr z$~s_31aAn9UrO@apUY?J#t5n<1+OE>9N-(`fCC1A!sJmTe9D|4&5y$MhTLvF)n#j} zx8%iQl5j4Jlv!gi;_79UTDN{ANVhi_;4-Ea_`wC##24+%i6sVILxQD5IPWXQn)3$1 zzsg&)mJoIa>OD;44H1*TIzvqSM|MFHw$rqymUjE{Jc-#>;Z5PgUosW{j_N|+vatSa zs8B_W?eoty^6Ei-V{=oll6=Iv=5Y7Jf!zWVx> z3<0h#6L_rd{GODf!3KI_USB27h#YZYV!RHjxiiEoB;?hTF``{ACOmltW+Mpuq{wYn z<4km@pcbB5`j5^fh4Z}Bv|X#;=uGE%)4sw9lZdAIUm?wv9W|XVS~!AEZ?%iplE>dL zpuHLP3gj{QE@D|<)Z+z&r;@qNCH4m8POV2hb~r87^Fb43_2jFrbvwI+i&FX@>+xei z5;3*QisB{pnyDRn`6dMG^(fQ2=6cPx5L0&|mwqrHBhaTbaUioOQ(u7IGvzyHQ%o%j z{LPyES$Zag_)@kvUGH4vb5@OiyT3|z@#3w%u>QwJqJ2Z0Vq#o@M<3~*MVZcjsxCY< zN#`q8mj6zj*da5oJ~kETcrwt^_tYtZbAu<%Qg88Qv)q4^#TcTT_JZ#%b)d#Qb}da+ z++6P0E3r=vLQ4h*ZW1ajo_N%NU^Ob7{B#2M>de`vJuW9wd?r$5rCM57=B8^EHaG9j z(eLJvR9TFimU2Ze`IQUY%V!XN;BWVW8%xIE3B?hEK4bEvS=5gh=E?nX zc)P>wC*SKnsz=wXzt4kX{Dwq>@ecP<={MNzDyA3}l`yrmS{XyRcXRHmmk6&h3ih9Q zEBYwAN%fNDmT2^D{$o|`eu=pEF~7TewgNeSY@xc=c%vt7ptTomnYDU*qE$=9@)ufpV(Z zaTgbaxQEww$Ni#T)fp&Wht2Nr+eE)pzkVgVyEg7emBxOD;*5y>di=d<72|zcGa^$l z!UC#d(^i7*v3Y*~mqjZz2ag6=nn!nRw z#)rHZI_W;}WvG3~8&zKfwr<7rO5K*oGp^;VA&+52`!@KN;n3Vtt8Wo)t5==JKx@fq zv9$i3#Lv=+OG%&F(XtI2QHOp7-ovbR4T~f)?wb6hH%~jx5)+;MS>Yct+D$U_R@BPd zp8LAbfCCAJz4c~{%4(GIH1SR9vt+(ut=0ab6gVwObN_QDZ@J4tmBhlmSk7g^fc zO4SfZvH6O^&Fv9K^`v=#S@=ua$FI^*C(C+Vl}`*F$He&E8-Ja8`OLHN$Mu02N{!DF zJj54C3r~jE<@wP*HlWT@+LX*;G$u0hf5+s1DBQL^({2DJXB3YD(cX=d3M5w@AnuW@ z6PO24peJwsc;NjfXtsH4!1x&CH4^z!Z_LfolS#=?%G8yyCYAGlA`kGh4ge&NRKAoV z0F;3LyKkx`Opi$!U23NjtSF_&y@!T|)+Srf&i(r8a!17=A4X=?*t>%tRsq?H6bI}9z!xkOhLl4LI_>-&~82kUf1yfU~#tA)=9D+`yEnahd?Vz8*V=bh7=|S z=HO(7Km6cz>s1_0gK0kFB;1%AV; zg>Pkn=%wXl&xsJh@^T@b6$!W=B)oM;08kgsCbgUf2;EG|>(bh`$E}&NTVGsdA}E-d zp7ab_?tua2HDL6Tf}Grh?Y(+}IcC|C`@HsgSS@MYnRuq_kP4_v6P!gNW)0F2#$Or509*w0$$fF`ub%v4@pSkR__GFt66MFDq-&D9{* zTSWX0*E&4LbQUI3FqqwpZ|DY4^LAXD&;ILh4~~qu*Ap}47?g>Lw9o)3Inm+b39poZT9RwKXc>YsBYBSUiNYM> zu-R5E#j0iQjCmacsHjK1PB6{EKzV3Q^@)eJBp+60CAbUba6i zf#lBl9q)J<19Oa&>}VS>U-zx8o_s;d$Ef#J z%avr#E>2E{kPJ-s1})GWxdLT_EMmqr?l9+~l3A@=0B#SW10LQp%6kCB?E#~?u--1N zd|v|%qMZL(=9b#s zCh@?j8Mp%v)TtQT5ZcF@Ij{hDXK4TB8kYLw)QhO5bZXKB!xH}(yx_xPG8ih(rI;Hebr2Z7q$0M%L5nOWR`fT z6Xq;@A2F=mnD*h+mvkqu@sFUs)0Uqb$ahO8q+ak&>*;Wa zO))~+ZEDIWUo!1XwLZyj7*~MKzW1}kYE*R1yqljL9AMd(4?>*aO{)l66VzBipXRkmtO9mnABuJNVDo_o;8bp~b#K1yL46F`@GG*C#n z1A3QLeF`grr2bWXf6?6U+YdjKF?sa{L_*ZpY2N#IpVbm=t=Qb&=KXZCV<_84q4l)?{Apz>+1+tu5WyNuA|&Eb zUN<+eIk}*|X7FT(#zb5LO|5tMi7}#zNO5-@nZdFP#Hfngux_D~Xe`SdLnB}5Z%SqX z1f%PuxN&X=8EMF@cAtj7UYYv*AFcPLZF8CEnx`GCjryjf^{;#<{p!AP|Md$k{3h}g z^{`#-3z^;_^|Ddb?PvZLj!|#4C9qSKl$)|Foc(|Cm|Mskw)kaRZjk@3$ zD{Xak<7|cz9N|QEPj~mn?BSwwF5IBS7xKS(@$W$Nzc@Z$ZcC@YWD^$osM(N&Y#PKN zaBg}k&NxNJ&EX6!jepb*jV1pz4u@7A1SW<_g8vy1&+QBJ=;2RHLx40VlfLu-jTXi; z4;KtCq)!}1i{|d(Mwi@b9U-z{Gtm^bQngY8D+#9Ci-Q63NH#6|<1$=`6eQ4)pZ|7w zd09BO9J5ia%;m9(Ed2~4V4O^1$EZWQ=tU5wA!9%{vBn-uLq-P&S+e^gJvY-KH$vtn z8I~Hc_p=#>0Dz#?nkCFFP;_|xjaE*xsmdk$;mwZBr}Jv|=OO2#)iT?wzGRcKHA;4< zd(3M?To5Cj)W4+zH_%5DrQm)jE!r*UGLe=R7(yG*Ex4zTe}y&#>V76M+U(M z3p692BS2*&4JElIO10j2jq#VC?qan)4pU&>lEz-;?Bw*juMejUk7QZ%QrIMz-~Mqg zpo*B<*fVk&oPssKKb@T#@%9Ru^m=DCh^!lOP-Ju=iehmM!tP1H+KPay4*s(*zb}QW zWR@Y4QC&=4a61%0&!#?=@=5@>3GLt6224mtv(*gha^u-=?Xh_vu~hH?T8p zc)|Y3i28h!i8oWLS6j`64pO>;=&_Bp1^%1J%Rq(#3|$zB|JfH+)gL;cO8Cl;>4X> LYKpn?Ccgg#_3fkq literal 0 HcmV?d00001 diff --git a/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js b/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js index 71e8372505..bded58edf8 100644 --- a/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js +++ b/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js @@ -1,6 +1,7 @@ /* eslint-disable react/no-array-index-key */ /* eslint-disable react/forbid-dom-props */ import { hooks } from 'botframework-webchat-component'; +import { htmlTextAlternatives } from 'botframework-webchat-component/internal.js'; import PropTypes from 'prop-types'; import React, { useMemo } from 'react'; @@ -12,13 +13,14 @@ import useUniqueId from '../hooks/internal/useUniqueId'; const { useLocalizer, useRenderMarkdownAsHTML } = hooks; // Returns the text as the visible card shows it: Adaptive Cards formats {{DATE()}} and {{TIME()}}, then renders the Markdown. +// Images are read by their alt text and blocks are separated, as in the live region of message text. function getRenderedText(element) { const renderedElement = element.render(); - // Line breaks are rendered as
, which has no text content. - renderedElement?.querySelectorAll('br').forEach(br => br.replaceWith(' ')); + // Plain text, such as a TextRun, is set with innerText, which renders line breaks as
; htmlTextAlternatives() reads
as nothing. + renderedElement?.querySelectorAll('br').forEach(br => br.replaceWith('\n')); - return (renderedElement?.textContent || '').replace(/\s+/gu, ' ').trim(); + return renderedElement ? htmlTextAlternatives(renderedElement).join('').replace(/\s+/gu, ' ').trim() : ''; } // Perform a depth-first search of the visible elements of the Adaptive Card tree, skipping hidden subtrees. From 6c94abf7ef85978156693574be29defc21a82668 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Tue, 20 Oct 2026 02:40:00 -0700 Subject: [PATCH 05/12] Fix test comments: the live region is above the card in the snapshots --- .../liveRegion/attachment/adaptiveCard.dateTime.html | 2 +- .../liveRegion/attachment/adaptiveCard.markdown.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.dateTime.html b/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.dateTime.html index 494fbfdd32..39af46ff3c 100644 --- a/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.dateTime.html +++ b/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.dateTime.html @@ -83,7 +83,7 @@ .map(text => text.trim()) ).toEqual(['Bot said:', `A card: ${cardText}`]); - // THEN: The card and the live region below show the same formatted date and time. + // THEN: The card and the live region above show the same formatted date and time. await host.snapshot('local'); }); diff --git a/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.markdown.html b/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.markdown.html index 242c2f30ea..83410cd233 100644 --- a/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.markdown.html +++ b/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.markdown.html @@ -80,7 +80,7 @@ 'A card: Today is sunny, see \u200bdocs\u200b. Umbrella: no Sunscreen: yes' ]); - // THEN: The card shows bold "sunny", a "docs" link and a bullet list; the live region below shows the same words without Markdown syntax. + // THEN: The card shows bold "sunny", a "docs" link and a bullet list; the live region above shows the same words without Markdown syntax. await host.snapshot('local'); }); From cc2b208873cffb805ec39b07926753f1bbee828f Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Tue, 20 Oct 2026 02:40:22 -0700 Subject: [PATCH 06/12] Read Adaptive Card text as written if rendering it throws --- .../AdaptiveCardAttachment.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js b/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js index bded58edf8..b2827e5639 100644 --- a/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js +++ b/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js @@ -2,6 +2,7 @@ /* eslint-disable react/forbid-dom-props */ import { hooks } from 'botframework-webchat-component'; import { htmlTextAlternatives } from 'botframework-webchat-component/internal.js'; +import { onErrorResumeNext } from 'botframework-webchat-core'; import PropTypes from 'prop-types'; import React, { useMemo } from 'react'; @@ -14,13 +15,16 @@ const { useLocalizer, useRenderMarkdownAsHTML } = hooks; // Returns the text as the visible card shows it: Adaptive Cards formats {{DATE()}} and {{TIME()}}, then renders the Markdown. // Images are read by their alt text and blocks are separated, as in the live region of message text. +// If the Markdown engine or Adaptive Cards throws, the visible card shows an error, and the text is read as written. function getRenderedText(element) { - const renderedElement = element.render(); + return onErrorResumeNext(() => { + const renderedElement = element.render(); - // Plain text, such as a TextRun, is set with innerText, which renders line breaks as
; htmlTextAlternatives() reads
as nothing. - renderedElement?.querySelectorAll('br').forEach(br => br.replaceWith('\n')); + // Plain text, such as a TextRun, is set with innerText, which renders line breaks as
; htmlTextAlternatives() reads
as nothing. + renderedElement?.querySelectorAll('br').forEach(br => br.replaceWith('\n')); - return renderedElement ? htmlTextAlternatives(renderedElement).join('').replace(/\s+/gu, ' ').trim() : ''; + return renderedElement ? htmlTextAlternatives(renderedElement).join('').replace(/\s+/gu, ' ').trim() : ''; + }, element.asString()); } // Perform a depth-first search of the visible elements of the Adaptive Card tree, skipping hidden subtrees. From 81b494029e8789851ca6b691765ead6a408fc92d Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Tue, 20 Oct 2026 02:40:23 -0700 Subject: [PATCH 07/12] Move getFactText to module level --- .../AdaptiveCardAttachment.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js b/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js index b2827e5639..1cf73760dd 100644 --- a/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js +++ b/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js @@ -27,6 +27,15 @@ function getRenderedText(element) { }, element.asString()); } +// Facts are rendered as text blocks, as Adaptive Cards does. +function getFactText(TextBlock, factSet, text) { + const textBlock = new TextBlock(text); + + textBlock.setParent(factSet); + + return getRenderedText(textBlock); +} + // Perform a depth-first search of the visible elements of the Adaptive Card tree, skipping hidden subtrees. // Actions are visited but not walked into, so the card of Action.ShowCard, hidden until opened, is not visited. function walkAllItems(node, fn) { @@ -145,15 +154,6 @@ const AdaptiveCardAttachment = ({ content }) => { walkAllItems(card, node => nodes.push(node)); - // Facts are rendered as text blocks, as Adaptive Cards does. - const getFactText = (factSet, text) => { - const textBlock = new TextBlock(text); - - textBlock.setParent(factSet); - - return getRenderedText(textBlock); - }; - // Same Markdown engine as the visible card. setMarkdownEngine(card, renderMarkdownAsHTML); @@ -161,7 +161,7 @@ const AdaptiveCardAttachment = ({ content }) => { .flatMap(node => node instanceof FactSet ? node.facts.map(({ name, value }) => - [getFactText(node, name), getFactText(node, value)].filter(Boolean).join(': ') + [getFactText(TextBlock, node, name), getFactText(TextBlock, node, value)].filter(Boolean).join(': ') ) : node instanceof Image ? [node.altText] From a38915cc3cc389d707401c2e8b9bf9ecd1a5adce Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Tue, 20 Oct 2026 02:40:27 -0700 Subject: [PATCH 08/12] Comment on setting the shared Markdown engine while rendering --- .../AttachmentForScreenReader/AdaptiveCardAttachment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js b/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js index 1cf73760dd..c21c53f1e9 100644 --- a/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js +++ b/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js @@ -154,7 +154,7 @@ const AdaptiveCardAttachment = ({ content }) => { walkAllItems(card, node => nodes.push(node)); - // Same Markdown engine as the visible card. + // Same Markdown engine as the visible card. This sets a static shared by all cards while rendering, which is safe because every render sets it first. setMarkdownEngine(card, renderMarkdownAsHTML); return nodes From 123b82ed340799a2878ff7ce2fd256ce75cad263 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Tue, 20 Oct 2026 02:40:49 -0700 Subject: [PATCH 09/12] Compare the Markdown test with the text of the visible card --- .../attachment/adaptiveCard.markdown.html | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.markdown.html b/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.markdown.html index 83410cd233..c469d239d7 100644 --- a/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.markdown.html +++ b/__tests__/html2/accessibility/liveRegion/attachment/adaptiveCard.markdown.html @@ -69,16 +69,24 @@ await pageConditions.numActivitiesShown(1); await pageConditions.liveRegionStabilized(); - // THEN: The live region copy reads the text as the card shows it, without Markdown syntax ("**", "[", "](", "- "). + // The card shows the list items on separate lines, the live region reads them as one line. + const cardText = pageElements + .activities()[0] + .querySelector('.ac-textBlock') + .textContent.replace(/\s+/gu, ' ') + .trim(); + + // THEN: The card shows the text without Markdown syntax ("**", "[", "](", "- "). + expect(cardText).toEqual( + expect.stringMatching(/^Today is sunny, see .*docs.*\. Umbrella: no Sunscreen: yes$/u) + ); + + // THEN: The live region copy reads the same text as the card. expect( testHelpers .getAllTextContents(pageElements.liveRegion().querySelector('.webchat__live-region-activity')) .map(text => text.trim()) - ).toEqual([ - 'Bot said:', - // Web Chat wraps links in zero-width spaces, in the card too. - 'A card: Today is sunny, see \u200bdocs\u200b. Umbrella: no Sunscreen: yes' - ]); + ).toEqual(['Bot said:', `A card: ${cardText}`]); // THEN: The card shows bold "sunny", a "docs" link and a bullet list; the live region above shows the same words without Markdown syntax. await host.snapshot('local'); From fe0dcb6e458a3e378ac0a38f33d3975d6fd97f30 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Tue, 20 Oct 2026 03:00:02 -0700 Subject: [PATCH 10/12] Collapse whitespace of the raw text fallback too --- .../AdaptiveCardAttachment.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js b/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js index c21c53f1e9..f58abbaa7e 100644 --- a/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js +++ b/packages/bundle/src/adaptiveCards/AttachmentForScreenReader/AdaptiveCardAttachment.js @@ -17,14 +17,18 @@ const { useLocalizer, useRenderMarkdownAsHTML } = hooks; // Images are read by their alt text and blocks are separated, as in the live region of message text. // If the Markdown engine or Adaptive Cards throws, the visible card shows an error, and the text is read as written. function getRenderedText(element) { - return onErrorResumeNext(() => { - const renderedElement = element.render(); + return ( + onErrorResumeNext(() => { + const renderedElement = element.render(); - // Plain text, such as a TextRun, is set with innerText, which renders line breaks as
; htmlTextAlternatives() reads
as nothing. - renderedElement?.querySelectorAll('br').forEach(br => br.replaceWith('\n')); + // Plain text, such as a TextRun, is set with innerText, which renders line breaks as
; htmlTextAlternatives() reads
as nothing. + renderedElement?.querySelectorAll('br').forEach(br => br.replaceWith('\n')); - return renderedElement ? htmlTextAlternatives(renderedElement).join('').replace(/\s+/gu, ' ').trim() : ''; - }, element.asString()); + return renderedElement ? htmlTextAlternatives(renderedElement).join('') : ''; + }, element.asString()) || '' + ) + .replace(/\s+/gu, ' ') + .trim(); } // Facts are rendered as text blocks, as Adaptive Cards does. From f9228107e66ad17e8f88b6a1037d4b88dcac0b58 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Tue, 20 Oct 2026 03:04:15 -0700 Subject: [PATCH 11/12] Add PR number to changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbe0941f0b..5226a6b5d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,7 +60,7 @@ Legends: - Fixed GIFs in animation cards looping with no way to stop them: they now have a pause button, and do not play when the user prefers reduced motion or the card has `autostart: false`; the icons of the Copy and View code buttons are now visible in forced colors, fixes [#5734](https://github.com/microsoft/BotFramework-WebChat/issues/5734), in PR [#5897](https://github.com/microsoft/BotFramework-WebChat/pull/5897), by [@OEvgeny](https://github.com/OEvgeny) - Fixed the "Positive" card action button having less than 4.5:1 color contrast, fixes [#5713](https://github.com/microsoft/BotFramework-WebChat/issues/5713), in PR [#5905](https://github.com/microsoft/BotFramework-WebChat/pull/5905), by [@OEvgeny](https://github.com/OEvgeny) - Fixed screen readers announcing Adaptive Cards without `speak` as just "A card", they now read the card text, in PR [#5922](https://github.com/microsoft/BotFramework-WebChat/pull/5922), by [@OEvgeny](https://github.com/OEvgeny) -- Fixed screen readers reading Adaptive Card text with its Markdown and `{{DATE()}}` syntax, in PR [#XXXX](https://github.com/microsoft/BotFramework-WebChat/pull/XXXX), by [@OEvgeny](https://github.com/OEvgeny) +- Fixed screen readers reading Adaptive Card text with its Markdown and `{{DATE()}}` syntax, in PR [#5929](https://github.com/microsoft/BotFramework-WebChat/pull/5929), by [@OEvgeny](https://github.com/OEvgeny) - Fixed screen readers announcing a single audio, video, or animation in a card as a list item, such as "1 of 1", fixes [#5722](https://github.com/microsoft/BotFramework-WebChat/issues/5722), in PR [#5903](https://github.com/microsoft/BotFramework-WebChat/pull/5903), by [@OEvgeny](https://github.com/OEvgeny) - Fixed video and animation cards disappearing in production builds when the video URL is relative or invalid, in PR [#5889](https://github.com/microsoft/BotFramework-WebChat/pull/5889), by [@OEvgeny](https://github.com/OEvgeny) - Fixed timestamps always using the 12-hour clock, such as "4:41 PM" instead of "16:41" in German, in PR [#5920](https://github.com/microsoft/BotFramework-WebChat/pull/5920), by [@OEvgeny](https://github.com/OEvgeny) From 4020042fb1293c7c29f4b3780360d3721ecb1851 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Tue, 20 Oct 2026 16:09:05 -0700 Subject: [PATCH 12/12] Move the changelog entry to .changelog/ --- .changelog/5929-fix-liveregion-card-text-format.md | 3 +++ CHANGELOG.md | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 .changelog/5929-fix-liveregion-card-text-format.md diff --git a/.changelog/5929-fix-liveregion-card-text-format.md b/.changelog/5929-fix-liveregion-card-text-format.md new file mode 100644 index 0000000000..76444827c6 --- /dev/null +++ b/.changelog/5929-fix-liveregion-card-text-format.md @@ -0,0 +1,3 @@ +### Fixed + +- Fixed screen readers reading Adaptive Card text with its Markdown and `{{DATE()}}` syntax, in PR [#5929](https://github.com/microsoft/BotFramework-WebChat/pull/5929), by [@OEvgeny](https://github.com/OEvgeny) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5226a6b5d7..ff95eb4dc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,7 +60,6 @@ Legends: - Fixed GIFs in animation cards looping with no way to stop them: they now have a pause button, and do not play when the user prefers reduced motion or the card has `autostart: false`; the icons of the Copy and View code buttons are now visible in forced colors, fixes [#5734](https://github.com/microsoft/BotFramework-WebChat/issues/5734), in PR [#5897](https://github.com/microsoft/BotFramework-WebChat/pull/5897), by [@OEvgeny](https://github.com/OEvgeny) - Fixed the "Positive" card action button having less than 4.5:1 color contrast, fixes [#5713](https://github.com/microsoft/BotFramework-WebChat/issues/5713), in PR [#5905](https://github.com/microsoft/BotFramework-WebChat/pull/5905), by [@OEvgeny](https://github.com/OEvgeny) - Fixed screen readers announcing Adaptive Cards without `speak` as just "A card", they now read the card text, in PR [#5922](https://github.com/microsoft/BotFramework-WebChat/pull/5922), by [@OEvgeny](https://github.com/OEvgeny) -- Fixed screen readers reading Adaptive Card text with its Markdown and `{{DATE()}}` syntax, in PR [#5929](https://github.com/microsoft/BotFramework-WebChat/pull/5929), by [@OEvgeny](https://github.com/OEvgeny) - Fixed screen readers announcing a single audio, video, or animation in a card as a list item, such as "1 of 1", fixes [#5722](https://github.com/microsoft/BotFramework-WebChat/issues/5722), in PR [#5903](https://github.com/microsoft/BotFramework-WebChat/pull/5903), by [@OEvgeny](https://github.com/OEvgeny) - Fixed video and animation cards disappearing in production builds when the video URL is relative or invalid, in PR [#5889](https://github.com/microsoft/BotFramework-WebChat/pull/5889), by [@OEvgeny](https://github.com/OEvgeny) - Fixed timestamps always using the 12-hour clock, such as "4:41 PM" instead of "16:41" in German, in PR [#5920](https://github.com/microsoft/BotFramework-WebChat/pull/5920), by [@OEvgeny](https://github.com/OEvgeny)