/br-investigation

Primary LanguagePythonMIT LicenseMIT

Brotli's Problematic chunking

Problem

When using brotli compression RSC stream responses are being processed later than they should be. The final streamed bytes have been confirmed to be the same so the next most likely cause is that there is a difference in how the compression is chunked and recombined both on the sending side and possibly on the receiving side

Investigation

This repo has two python scripts gz.py and br.py They each have a sequence of byte strings captured using wireshark along with timing information. Each script progressively decmpresses the bytes mimicing what the networks layer would do on the client computer when receiving these packets.

Summary

Brotli witholds newline characters in some cases to be delivered with the next large block of data. This is problematic for RSC which relies on newline termination to know when it can safely processing bytes receieved (there are some exceptions where bytelength is checked instead but this does not apply to htis particular issue).

Reproduction

There is likely a scriptable way to automate this but what I did was set up wireshark to capture curl request traffic to the brotli and gzip serving endpoints and extracted the http2 frame bodies into bytestring arrays in the corresponding python scripts. If you want to do a similar investigation you just need to make sure you are grabbing only the data frame from the http2 packet and not any other information

Details

Here are the gzip decompressed chunks as they arrive

  1. Immediately: ``
  2. Immediately: 0:[...]\n
  3. Immediately: 3:I{...}\n4:"$Sreact.suspense"\n1:[...]\n
  4. After 2 Seconds: 5:[...]\n

Here are the brotli decompressed chunks as they arrive

  1. Immediately: 0:[...]\n
  2. Immediately: 3:I{...}\n4:"$Sreact.suspense"\n1:[...]
  3. After 2 Seconds: \n5:[...]
  4. After 2 Seconds: \n

Notice that in the gzip case each chunk is decompressable and ends in a newline character. This is what signals to react that the row is complete and it can begin to process it. In the brotli case the newline that is supposed to terminate the row with id 1 (which appears last in the second chunk) is not delivered until the third chunk which is delayed. Because this newline arrives 2 seconds late the row cannot be processed for 2 seconds and this is the row that defines the loading state from loading.js

full decoding results

gzip

# python3 gz.py

Decompressed data: 0 b''


Decompressed data: 1 b'0:["t6C-eG7igp0V0mjFfigSe",[["children","__PAGE__?{\\"wait\\":\\"on\\",\\"search\\":\\"pika\\"}",["__PAGE__?{\\"wait\\":\\"on\\",\\"search\\":\\"pika\\"}",{}],"$L1",[[],["$L2",null]]]]]\n'


Decompressed data: 2 b'3:I{"id":"4589","chunks":["931:static/chunks/app/page-4e4236e9cbfa863f.js"],"name":"SearchInput","async":false}\n4:"$Sreact.suspense"\n1:[["$","section",null,{"className":"flex flex-col","children":[["$","$L3",null,{}],["$","$4","search=pika&wait=on",{"fallback":["$","ul",null,{"className":"grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 lg:gap-6 py-4 pb-52 place-items-stretch","children":[["$","div",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","span",null,{"className":"sr-only","children":"Loading pokemon..."}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}],["$","div",null,{"className":"h-[200px] w-full bg-slate-400 rounded animate-pulse"}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}]]}],["$","div",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","span",null,{"className":"sr-only","children":"Loading pokemon..."}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}],["$","div",null,{"className":"h-[200px] w-full bg-slate-400 rounded animate-pulse"}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}]]}],["$","div",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","span",null,{"className":"sr-only","children":"Loading pokemon..."}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}],["$","div",null,{"className":"h-[200px] w-full bg-slate-400 rounded animate-pulse"}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}]]}],["$","div",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","span",null,{"className":"sr-only","children":"Loading pokemon..."}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}],["$","div",null,{"className":"h-[200px] w-full bg-slate-400 rounded animate-pulse"}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}]]}]]}],"children":"$L5"}]]}],null]\n2:[["$","meta","0",{"charSet":"utf-8"}],["$","title","1",{"children":"Searching for pika"}],["$","meta","2",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]\n'


Decompressed data: 3 b'5:["$","ul",null,{"className":"grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 lg:gap-6 py-4 pb-52 place-items-stretch","children":[["$","li","25",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":25}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/25.png","alt":"pikachu","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu"}]]}]]}]}],["$","li","10080",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10080}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10080.png","alt":"pikachu-rock-star","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-rock-star"}]]}]]}]}],["$","li","10081",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10081}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10081.png","alt":"pikachu-belle","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-belle"}]]}]]}]}],["$","li","10082",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10082}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10082.png","alt":"pikachu-pop-star","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-pop-star"}]]}]]}]}],["$","li","10083",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10083}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10083.png","alt":"pikachu-phd","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-phd"}]]}]]}]}],["$","li","10084",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10084}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10084.png","alt":"pikachu-libre","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-libre"}]]}]]}]}],["$","li","10085",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10085}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10085.png","alt":"pikachu-cosplay","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-cosplay"}]]}]]}]}],["$","li","10094",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10094}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10094.png","alt":"pikachu-original-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-original-cap"}]]}]]}]}],["$","li","10095",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10095}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10095.png","alt":"pikachu-hoenn-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-hoenn-cap"}]]}]]}]}],["$","li","10096",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10096}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10096.png","alt":"pikachu-sinnoh-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-sinnoh-cap"}]]}]]}]}],["$","li","10097",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10097}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10097.png","alt":"pikachu-unova-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-unova-cap"}]]}]]}]}],["$","li","10098",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10098}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10098.png","alt":"pikachu-kalos-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-kalos-cap"}]]}]]}]}],["$","li","10099",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10099}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10099.png","alt":"pikachu-alola-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-alola-cap"}]]}]]}]}],["$","li","10148",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10148}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10148.png","alt":"pikachu-partner-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-partner-cap"}]]}]]}]}],["$","li","10158",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10158}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10158.png","alt":"pikachu-starter","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-starter"}]]}]]}]}],["$","li","10160",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10160}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10160.png","alt":"pikachu-world-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-world-cap"}]]}]]}]}],["$","li","10199",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10199}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10199.png","alt":"pikachu-gmax","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-gmax"}]]}]]}]}]]}]\n'

brotli

# python3 br.py

Decompressed data: b'0:["WIMnA-J9fSC-mT55SMPBg",[["children","__PAGE__?{\\"wait\\":\\"on\\",\\"search\\":\\"pika\\"}",["__PAGE__?{\\"wait\\":\\"on\\",\\"search\\":\\"pika\\"}",{}],"$L1",[[],["$L2",null]]]]]\n'


Decompressed data: b'3:I{"id":"4589","chunks":["931:static/chunks/app/page-66f60725d3c39b68.js"],"name":"SearchInput","async":false}\n4:"$Sreact.suspense"\n1:[["$","section",null,{"className":"flex flex-col","children":[["$","$L3",null,{}],["$","$4","search=pika&wait=on",{"fallback":["$","ul",null,{"className":"grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 lg:gap-6 py-4 pb-52 place-items-stretch","children":[["$","div",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","span",null,{"className":"sr-only","children":"Loading pokemon..."}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}],["$","div",null,{"className":"h-[200px] w-full bg-slate-400 rounded animate-pulse"}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}]]}],["$","div",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","span",null,{"className":"sr-only","children":"Loading pokemon..."}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}],["$","div",null,{"className":"h-[200px] w-full bg-slate-400 rounded animate-pulse"}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}]]}],["$","div",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","span",null,{"className":"sr-only","children":"Loading pokemon..."}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}],["$","div",null,{"className":"h-[200px] w-full bg-slate-400 rounded animate-pulse"}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}]]}],["$","div",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","span",null,{"className":"sr-only","children":"Loading pokemon..."}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}],["$","div",null,{"className":"h-[200px] w-full bg-slate-400 rounded animate-pulse"}],["$","div",null,{"className":"flex gap-2 bg-slate-400 h-4 rounded animate-pulse"}]]}]]}],"children":"$L5"}]]}],null]\n2:[["$","meta","0",{"charSet":"utf-8"}],["$","title","1",{"children":"Searching for pika"}],["$","meta","2",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]'


Decompressed data: b'\n5:["$","ul",null,{"className":"grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 lg:gap-6 py-4 pb-52 place-items-stretch","children":[["$","li","25",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":25}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/25.png","alt":"pikachu","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu"}]]}]]}]}],["$","li","10080",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10080}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10080.png","alt":"pikachu-rock-star","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-rock-star"}]]}]]}]}],["$","li","10081",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10081}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10081.png","alt":"pikachu-belle","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-belle"}]]}]]}]}],["$","li","10082",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10082}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10082.png","alt":"pikachu-pop-star","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-pop-star"}]]}]]}]}],["$","li","10083",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10083}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10083.png","alt":"pikachu-phd","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-phd"}]]}]]}]}],["$","li","10084",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10084}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10084.png","alt":"pikachu-libre","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-libre"}]]}]]}]}],["$","li","10085",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10085}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10085.png","alt":"pikachu-cosplay","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-cosplay"}]]}]]}]}],["$","li","10094",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10094}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10094.png","alt":"pikachu-original-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-original-cap"}]]}]]}]}],["$","li","10095",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10095}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10095.png","alt":"pikachu-hoenn-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-hoenn-cap"}]]}]]}]}],["$","li","10096",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10096}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10096.png","alt":"pikachu-sinnoh-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-sinnoh-cap"}]]}]]}]}],["$","li","10097",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10097}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10097.png","alt":"pikachu-unova-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-unova-cap"}]]}]]}]}],["$","li","10098",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10098}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10098.png","alt":"pikachu-kalos-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-kalos-cap"}]]}]]}]}],["$","li","10099",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10099}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10099.png","alt":"pikachu-alola-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-alola-cap"}]]}]]}]}],["$","li","10148",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10148}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10148.png","alt":"pikachu-partner-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-partner-cap"}]]}]]}]}],["$","li","10158",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10158}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10158.png","alt":"pikachu-starter","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-starter"}]]}]]}]}],["$","li","10160",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10160}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10160.png","alt":"pikachu-world-cap","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-world-cap"}]]}]]}]}],["$","li","10199",{"children":["$","dl",null,{"className":"border rounded-md bg-gray-600 border-gray-200 font-normal p-2 flex flex-col gap-4","children":[["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"ID : "}],["$","dd",null,{"children":["$","strong",null,{"children":10199}]}]]}],["$","img",null,{"width":200,"height":200,"src":"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10199.png","alt":"pikachu-gmax","className":"h-[200px] w-[200px] self-center drop-shadow-md relative z-1"}],["$","div",null,{"className":"flex gap-2 justify-center items-center","children":[["$","dt",null,{"children":"Name: "}],["$","dd",null,{"children":"pikachu-gmax"}]]}]]}]}]]}]'


Decompressed data: b'\n'