[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"i-ri:search-line":3,"i-ri:moon-line":8,"i-ri:sun-line":10,"i-ri:menu-3-line":12,"i-ri:close-line":14,"notes-module-items-im":16,"notes-page-im-02-connection-protocol\u002F01-stream-parsing":66,"i-ri:arrow-left-s-line":578,"i-ri:menu-2-line":580,"i-ri:arrow-right-s-line":582,"i-ep:copy-document":584},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cpath fill=\"currentColor\" d=\"m18.031 16.617l4.283 4.282l-1.415 1.415l-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9s9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617m-2.006-.742A6.98 6.98 0 0 0 18 11c0-3.867-3.133-7-7-7s-7 3.133-7 7s3.133 7 7 7a6.98 6.98 0 0 0 4.875-1.975z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":9},"\u003Cpath fill=\"currentColor\" d=\"M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2h.1A6.98 6.98 0 0 0 10 7m-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938A8 8 0 0 0 4 12\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":11},"\u003Cpath fill=\"currentColor\" d=\"M12 18a6 6 0 1 1 0-12a6 6 0 0 1 0 12m0-2a4 4 0 1 0 0-8a4 4 0 0 0 0 8M11 1h2v3h-2zm0 19h2v3h-2zM3.515 4.929l1.414-1.414L7.05 5.636L5.636 7.05zM16.95 18.364l1.414-1.414l2.121 2.121l-1.414 1.414zm2.121-14.85l1.414 1.415l-2.121 2.121l-1.414-1.414zM5.636 16.95l1.414 1.414l-2.121 2.121l-1.414-1.414zM23 11v2h-3v-2zM4 11v2H1v-2z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":13},"\u003Cpath fill=\"currentColor\" d=\"M3 4h18v2H3zm6 7h12v2H9zm-6 7h18v2H3z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":15},"\u003Cpath fill=\"currentColor\" d=\"m12 10.587l4.95-4.95l1.414 1.414l-4.95 4.95l4.95 4.95l-1.415 1.414l-4.95-4.95l-4.949 4.95l-1.414-1.415l4.95-4.95l-4.95-4.95L7.05 5.638z\"\u002F>",[17,22,26,30,34,38,42,46,50,54,58,62],{"path":18,"title":19,"meta":20},"\u002Fnotes\u002Fim\u002F01-message-state\u002F01-offline-sync","连接恢复了，离线消息为什么还没补齐？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},"2026-11-05T09:47:15.000Z",{"path":23,"title":24,"meta":25},"\u002Fnotes\u002Fim\u002F01-message-state\u002F02-read-cursor","手机读过了，电脑为何又显示未读？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":27,"title":28,"meta":29},"\u002Fnotes\u002Fim\u002F01-message-state\u002F03-pagination-search","聊天搜索跳回旧消息后，怎样继续翻页？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":31,"title":32,"meta":33},"\u002Fnotes\u002Fim\u002F01-message-state\u002F04-unread-refresh","消息没停，未读角标就不更新？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":35,"title":36,"meta":37},"\u002Fnotes\u002Fim\u002F02-connection-protocol\u002F01-stream-parsing","一次接收回调，为什么不是一条消息？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":39,"title":40,"meta":41},"\u002Fnotes\u002Fim\u002F02-connection-protocol\u002F02-request-response","长连接上的请求，怎样等到自己的响应？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":43,"title":44,"meta":45},"\u002Fnotes\u002Fim\u002F02-connection-protocol\u002F03-connection-lifecycle","登录一直在连接中，到底在等什么？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":47,"title":48,"meta":49},"\u002Fnotes\u002Fim\u002F03-message-content\u002F01-file-download","附件下载完了，为什么还是打不开？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":51,"title":52,"meta":53},"\u002Fnotes\u002Fim\u002F03-message-content\u002F02-image-send","图片上传到 100%，为什么还没发出去？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":55,"title":56,"meta":57},"\u002Fnotes\u002Fim\u002F03-message-content\u002F03-mentions","聊天 @提及怎样保存身份和位置？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":59,"title":60,"meta":61},"\u002Fnotes\u002Fim\u002F04-client-release\u002F01-flutter-build","Release 包为什么仍连着测试环境？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":63,"title":64,"meta":65},"\u002Fnotes\u002Fim","即时通信",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"id":67,"type":68,"sourcePath":69,"routePath":35,"path":35,"title":36,"description":70,"updatedAt":21,"meta":71,"body":80,"toc":572},"bm90ZTpub3Rlcy9pbS8wMi1jb25uZWN0aW9uLXByb3RvY29sLzAxLXN0cmVhbS1wYXJzaW5nLm1k","note","notes\u002Fim\u002F02-connection-protocol\u002F01-stream-parsing.md","聊天客户端收到网络数据时，可能只有半条消息，也可能一次来了好几条。这个 Flutter App 的 Dart 协议层使用 XMPP，消息以 XML 传输，接收端需要先把字节解码，再提取完整元素。",{"id":67,"type":68,"sourcePath":69,"slug":72,"title":36,"updatedAt":21,"description":70,"tags":73,"date":77,"comment":78,"summary":79,"lastUpdated":21},"im\u002F02-connection-protocol\u002F01-stream-parsing",[74,75,76],"dart","IM","network","2026-08-05",true,"长连接传的是字节流，XML 和中文都可能被拆开。分别处理连续解码与元素边界，再明确超长输入怎么结束。",{"type":81,"children":82},"root",[83,91,96,101,108,122,136,215,220,226,240,448,461,466,472,501,515,520,526,531,561,566],{"type":84,"tag":85,"props":86,"children":88},"element","h1",{"id":87},"一次接收回调为什么不是一条消息",[89],{"type":90,"value":36},"text",{"type":84,"tag":92,"props":93,"children":94},"p",{},[95],{"type":90,"value":70},{"type":84,"tag":92,"props":97,"children":98},{},[99],{"type":90,"value":100},"问题出在“这一块数据”的边界与“这一条消息”的边界没有必然关系。把每次回调直接当完整 XML，正常网络上的分片就可能变成解析错误。",{"type":84,"tag":102,"props":103,"children":105},"h2",{"id":104},"通常怎样从流里取出完整消息",[106],{"type":90,"value":107},"通常怎样从流里取出完整消息？",{"type":84,"tag":92,"props":109,"children":110},{},[111,120],{"type":84,"tag":112,"props":113,"children":117},"a",{"href":114,"rel":115},"https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc9293.html#section-3.7",[116],"nofollow",[118],{"type":90,"value":119},"TCP 规范 RFC 9293",{"type":90,"value":121}," 描述的是有序字节流，接收边界不保证对应发送端的一次写入。于是接收端需要连续解码，并让解析器保留尚未完成的部分。",{"type":84,"tag":92,"props":123,"children":124},{},[125,127,134],{"type":90,"value":126},"项目当前的做法是先解码，将字符串追加到缓冲区，从中找完整 ",{"type":84,"tag":128,"props":129,"children":131},"code",{"className":130},[],[132],{"type":90,"value":133},"\u003Cmessage>",{"type":90,"value":135},"；提取一条后留下剩余内容，继续寻找。示意消息是：",{"type":84,"tag":137,"props":138,"children":143},"pre",{"className":139,"code":140,"language":141,"meta":142,"style":142},"language-xml shiki shiki-themes github-light github-dark","\u003Cmessage id=\"m1\">\u003Cbody>你好\u003C\u002Fbody>\u003C\u002Fmessage>\n","xml","",[144],{"type":84,"tag":128,"props":145,"children":146},{"__ignoreMap":142},[147],{"type":84,"tag":148,"props":149,"children":152},"span",{"class":150,"line":151},"line",1,[153,159,165,171,176,182,187,192,197,201,206,210],{"type":84,"tag":148,"props":154,"children":156},{"style":155},"--shiki-default:#24292E;--shiki-dark:#E1E4E8",[157],{"type":90,"value":158},"\u003C",{"type":84,"tag":148,"props":160,"children":162},{"style":161},"--shiki-default:#22863A;--shiki-dark:#85E89D",[163],{"type":90,"value":164},"message",{"type":84,"tag":148,"props":166,"children":168},{"style":167},"--shiki-default:#6F42C1;--shiki-dark:#B392F0",[169],{"type":90,"value":170}," id",{"type":84,"tag":148,"props":172,"children":173},{"style":155},[174],{"type":90,"value":175},"=",{"type":84,"tag":148,"props":177,"children":179},{"style":178},"--shiki-default:#032F62;--shiki-dark:#9ECBFF",[180],{"type":90,"value":181},"\"m1\"",{"type":84,"tag":148,"props":183,"children":184},{"style":155},[185],{"type":90,"value":186},">\u003C",{"type":84,"tag":148,"props":188,"children":189},{"style":161},[190],{"type":90,"value":191},"body",{"type":84,"tag":148,"props":193,"children":194},{"style":155},[195],{"type":90,"value":196},">你好\u003C\u002F",{"type":84,"tag":148,"props":198,"children":199},{"style":161},[200],{"type":90,"value":191},{"type":84,"tag":148,"props":202,"children":203},{"style":155},[204],{"type":90,"value":205},">\u003C\u002F",{"type":84,"tag":148,"props":207,"children":208},{"style":161},[209],{"type":90,"value":164},{"type":84,"tag":148,"props":211,"children":212},{"style":155},[213],{"type":90,"value":214},">\n",{"type":84,"tag":92,"props":216,"children":217},{},[218],{"type":90,"value":219},"它可能在“你”和“好”之间分两次到达，也可能与下一条消息一起到达。缓冲能处理这种情况，但当前这条缓冲路径主要负责聊天 message，握手和其他响应仍有各自的监听，没有统一进入同一个完整元素解析入口。",{"type":84,"tag":102,"props":221,"children":223},{"id":222},"找到第一个结束标签为什么还不能截",[224],{"type":90,"value":225},"找到第一个结束标签，为什么还不能截？",{"type":84,"tag":92,"props":227,"children":228},{},[229,231,238],{"type":90,"value":230},"多端转发会把消息嵌套。",{"type":84,"tag":112,"props":232,"children":235},{"href":233,"rel":234},"https:\u002F\u002Fxmpp.org\u002Fextensions\u002Fxep-0280.html#received",[116],[236],{"type":90,"value":237},"XEP-0280",{"type":90,"value":239}," 的消息转发结构，省略地址等属性后可以写成：",{"type":84,"tag":137,"props":241,"children":243},{"className":139,"code":242,"language":141,"meta":142,"style":142},"\u003Cmessage>\n  \u003Creceived xmlns=\"urn:xmpp:carbons:2\">\n    \u003Cforwarded xmlns=\"urn:xmpp:forward:0\">\n      \u003Cmessage xmlns=\"jabber:client\">\n        \u003Cbody>你好\u003C\u002Fbody>\n      \u003C\u002Fmessage>\n    \u003C\u002Fforwarded>\n  \u003C\u002Freceived>\n\u003C\u002Fmessage>\n",[244],{"type":84,"tag":128,"props":245,"children":246},{"__ignoreMap":142},[247,262,294,325,355,380,397,414,431],{"type":84,"tag":148,"props":248,"children":249},{"class":150,"line":151},[250,254,258],{"type":84,"tag":148,"props":251,"children":252},{"style":155},[253],{"type":90,"value":158},{"type":84,"tag":148,"props":255,"children":256},{"style":161},[257],{"type":90,"value":164},{"type":84,"tag":148,"props":259,"children":260},{"style":155},[261],{"type":90,"value":214},{"type":84,"tag":148,"props":263,"children":265},{"class":150,"line":264},2,[266,271,276,281,285,290],{"type":84,"tag":148,"props":267,"children":268},{"style":155},[269],{"type":90,"value":270},"  \u003C",{"type":84,"tag":148,"props":272,"children":273},{"style":161},[274],{"type":90,"value":275},"received",{"type":84,"tag":148,"props":277,"children":278},{"style":167},[279],{"type":90,"value":280}," xmlns",{"type":84,"tag":148,"props":282,"children":283},{"style":155},[284],{"type":90,"value":175},{"type":84,"tag":148,"props":286,"children":287},{"style":178},[288],{"type":90,"value":289},"\"urn:xmpp:carbons:2\"",{"type":84,"tag":148,"props":291,"children":292},{"style":155},[293],{"type":90,"value":214},{"type":84,"tag":148,"props":295,"children":297},{"class":150,"line":296},3,[298,303,308,312,316,321],{"type":84,"tag":148,"props":299,"children":300},{"style":155},[301],{"type":90,"value":302},"    \u003C",{"type":84,"tag":148,"props":304,"children":305},{"style":161},[306],{"type":90,"value":307},"forwarded",{"type":84,"tag":148,"props":309,"children":310},{"style":167},[311],{"type":90,"value":280},{"type":84,"tag":148,"props":313,"children":314},{"style":155},[315],{"type":90,"value":175},{"type":84,"tag":148,"props":317,"children":318},{"style":178},[319],{"type":90,"value":320},"\"urn:xmpp:forward:0\"",{"type":84,"tag":148,"props":322,"children":323},{"style":155},[324],{"type":90,"value":214},{"type":84,"tag":148,"props":326,"children":328},{"class":150,"line":327},4,[329,334,338,342,346,351],{"type":84,"tag":148,"props":330,"children":331},{"style":155},[332],{"type":90,"value":333},"      \u003C",{"type":84,"tag":148,"props":335,"children":336},{"style":161},[337],{"type":90,"value":164},{"type":84,"tag":148,"props":339,"children":340},{"style":167},[341],{"type":90,"value":280},{"type":84,"tag":148,"props":343,"children":344},{"style":155},[345],{"type":90,"value":175},{"type":84,"tag":148,"props":347,"children":348},{"style":178},[349],{"type":90,"value":350},"\"jabber:client\"",{"type":84,"tag":148,"props":352,"children":353},{"style":155},[354],{"type":90,"value":214},{"type":84,"tag":148,"props":356,"children":358},{"class":150,"line":357},5,[359,364,368,372,376],{"type":84,"tag":148,"props":360,"children":361},{"style":155},[362],{"type":90,"value":363},"        \u003C",{"type":84,"tag":148,"props":365,"children":366},{"style":161},[367],{"type":90,"value":191},{"type":84,"tag":148,"props":369,"children":370},{"style":155},[371],{"type":90,"value":196},{"type":84,"tag":148,"props":373,"children":374},{"style":161},[375],{"type":90,"value":191},{"type":84,"tag":148,"props":377,"children":378},{"style":155},[379],{"type":90,"value":214},{"type":84,"tag":148,"props":381,"children":383},{"class":150,"line":382},6,[384,389,393],{"type":84,"tag":148,"props":385,"children":386},{"style":155},[387],{"type":90,"value":388},"      \u003C\u002F",{"type":84,"tag":148,"props":390,"children":391},{"style":161},[392],{"type":90,"value":164},{"type":84,"tag":148,"props":394,"children":395},{"style":155},[396],{"type":90,"value":214},{"type":84,"tag":148,"props":398,"children":400},{"class":150,"line":399},7,[401,406,410],{"type":84,"tag":148,"props":402,"children":403},{"style":155},[404],{"type":90,"value":405},"    \u003C\u002F",{"type":84,"tag":148,"props":407,"children":408},{"style":161},[409],{"type":90,"value":307},{"type":84,"tag":148,"props":411,"children":412},{"style":155},[413],{"type":90,"value":214},{"type":84,"tag":148,"props":415,"children":417},{"class":150,"line":416},8,[418,423,427],{"type":84,"tag":148,"props":419,"children":420},{"style":155},[421],{"type":90,"value":422},"  \u003C\u002F",{"type":84,"tag":148,"props":424,"children":425},{"style":161},[426],{"type":90,"value":275},{"type":84,"tag":148,"props":428,"children":429},{"style":155},[430],{"type":90,"value":214},{"type":84,"tag":148,"props":432,"children":434},{"class":150,"line":433},9,[435,440,444],{"type":84,"tag":148,"props":436,"children":437},{"style":155},[438],{"type":90,"value":439},"\u003C\u002F",{"type":84,"tag":148,"props":441,"children":442},{"style":161},[443],{"type":90,"value":164},{"type":84,"tag":148,"props":445,"children":446},{"style":155},[447],{"type":90,"value":214},{"type":84,"tag":92,"props":449,"children":450},{},[451,453,459],{"type":90,"value":452},"第一个 ",{"type":84,"tag":128,"props":454,"children":456},{"className":455},[],[457],{"type":90,"value":458},"\u003C\u002Fmessage>",{"type":90,"value":460}," 只结束内层，外面的 forwarded 和 received 尚未关闭。项目用深度计数处理：遇到 message 开始就加一，结束就减一，归零时才提取。",{"type":84,"tag":92,"props":462,"children":463},{},[464],{"type":90,"value":465},"另一种选择是使用理解完整 XML 语法的流式解析。当前深度计数仍在扫描标签字符串，注释、CDATA 和自闭合等输入还需要规则，不能把这段扫描当成完整词法解析器。",{"type":84,"tag":102,"props":467,"children":469},{"id":468},"标签或一个汉字本身被拆开怎么办",[470],{"type":90,"value":471},"标签或一个汉字本身被拆开，怎么办？",{"type":84,"tag":92,"props":473,"children":474},{},[475,477,483,485,491,493,499],{"type":90,"value":476},"缓冲必须能保留潜在的起点。例如第一次只收到 ",{"type":84,"tag":128,"props":478,"children":480},{"className":479},[],[481],{"type":90,"value":482},"\u003Cmes",{"type":90,"value":484},"，下一次才收到 ",{"type":84,"tag":128,"props":486,"children":488},{"className":487},[],[489],{"type":90,"value":490},"sage...",{"type":90,"value":492},"。当前实现找不到完整 ",{"type":84,"tag":128,"props":494,"children":496},{"className":495},[],[497],{"type":90,"value":498},"\u003Cmessage",{"type":90,"value":500}," 就清空，按这条路径推演，第一段会丢掉，后面无法重新拼回。这是尚需补测试的源码风险。",{"type":84,"tag":92,"props":502,"children":503},{},[504,506,513],{"type":90,"value":505},"字节解码更早就可能出问题。现在每块数据分别调用 UTF-8 解码，一个多字节字符拆在两个回调里时，还没进入 XML 缓冲便可能失败。Dart 的 ",{"type":84,"tag":112,"props":507,"children":510},{"href":508,"rel":509},"https:\u002F\u002Fapi.dart.dev\u002Fdart-convert\u002FUtf8Decoder-class.html",[116],[511],{"type":90,"value":512},"Utf8Decoder",{"type":90,"value":514}," 提供流转换与分块转换，用来保留尚未解完的字节。",{"type":84,"tag":92,"props":516,"children":517},{},[518],{"type":90,"value":519},"允许非法输入时使用替代字符，并不能还原原来的字节。后续需要先连续解码，再处理 XML 边界；仅修字符串缓冲，补不回解码阶段已丢失的信息。",{"type":84,"tag":102,"props":521,"children":523},{"id":522},"缓冲超长时丢掉尾部还是断开",[524],{"type":90,"value":525},"缓冲超长时，丢掉尾部还是断开？",{"type":84,"tag":92,"props":527,"children":528},{},[529],{"type":90,"value":530},"需要根据协议和恢复要求选择。保留尾部能控制长度，但尾部可能已没有完整起点；清空则直接放弃未完成消息。若要终止流并报告错误，也需要让上层知道发生了什么。",{"type":84,"tag":92,"props":532,"children":533},{},[534,536,542,544,550,552,559],{"type":90,"value":535},"当前入口超过 ",{"type":84,"tag":128,"props":537,"children":539},{"className":538},[],[540],{"type":90,"value":541},"2 * 1024 * 1024",{"type":90,"value":543}," 时保留尾部，解析器遇到未完成消息超过 ",{"type":84,"tag":128,"props":545,"children":547},{"className":546},[],[548],{"type":90,"value":549},"16384",{"type":90,"value":551}," 时清空。比较使用 Dart 的 ",{"type":84,"tag":112,"props":553,"children":556},{"href":554,"rel":555},"https:\u002F\u002Fapi.dart.dev\u002Fdart-core\u002FString\u002Flength.html",[116],[557],{"type":90,"value":558},"String.length",{"type":90,"value":560},"，单位是 UTF-16 code unit，不是网络 UTF-8 字节。",{"type":84,"tag":92,"props":562,"children":563},{},[564],{"type":90,"value":565},"因此单纯调大数字，不能解决丢弃后的恢复问题。验证时可以把一条合法消息的字节在每个位置分别切成两块，对照一次性输入的结果，再加入连续分块、消息相连、嵌套转发和中文，检查两层缓冲在什么位置留下或丢掉了数据。",{"type":84,"tag":567,"props":568,"children":569},"style",{},[570],{"type":90,"value":571},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":142,"searchDepth":264,"depth":264,"links":573},[574,575,576,577],{"id":104,"depth":264,"text":107},{"id":222,"depth":264,"text":225},{"id":468,"depth":264,"text":471},{"id":522,"depth":264,"text":525},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":579},"\u003Cpath fill=\"currentColor\" d=\"m10.828 12l4.95 4.95l-1.414 1.415L8 12l6.364-6.364l1.414 1.414z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":581},"\u003Cpath fill=\"currentColor\" d=\"M3 4h18v2H3zm0 7h12v2H3zm0 7h18v2H3z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":583},"\u003Cpath fill=\"currentColor\" d=\"m13.172 12l-4.95-4.95l1.414-1.413L16 12l-6.364 6.364l-1.414-1.415z\"\u002F>",{"left":4,"top":4,"width":585,"height":585,"rotate":4,"vFlip":6,"hFlip":6,"body":586},1024,"\u003Cpath fill=\"currentColor\" d=\"M768 832a128 128 0 0 1-128 128H192A128 128 0 0 1 64 832V384a128 128 0 0 1 128-128v64a64 64 0 0 0-64 64v448a64 64 0 0 0 64 64h448a64 64 0 0 0 64-64z\"\u002F>\u003Cpath fill=\"currentColor\" d=\"M384 128a64 64 0 0 0-64 64v448a64 64 0 0 0 64 64h448a64 64 0 0 0 64-64V192a64 64 0 0 0-64-64zm0-64h448a128 128 0 0 1 128 128v448a128 128 0 0 1-128 128H384a128 128 0 0 1-128-128V192A128 128 0 0 1 384 64\"\u002F>"]