Ancestors

Written by Foone🏳️‍⚧️ on 2025-01-05 at 03:40

maybe instead of fully decompiling it, I just hack it to grab data from external files, then make a tool for making those files

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-05 at 11:11

ahh, the PC. No one else ever thought XORing your VRAM was a good idea

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-05 at 12:12

turns out this version of the game has impressive support for older video cards. Here's Hercules support, which looks horrible without aspect ratio correction!

=> View attached media

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-05 at 12:19

wow, this is actually the first game I've seen actually use the VGA bios call to set the VGA palette. (int 10h, AX=1012h)

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-05 at 12:20

everyone else just programs the VGA card directly.

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-05 at 12:52

so when the game starts, it loads:

ACME.DAT

CARMEN.DAT

MIDISND.DAT

DIGISND.DAT

CITIES.DAT

Interestingly, it uses the same code to load the last three, suggesting they're some kind of basic container format

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-05 at 14:55

starting writing code to generate a JSON file of all the various switchable info in the EXE. Things like hobbies, hair colors, locations, etc.

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-06 at 02:15

this blit function seems to take a useless first argument, a second argument that's the height, a third argument that's the width, and a fourth argument that doesn't seem to do anything.

notice anything missing? like... a lot of things?

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-06 at 02:30

I think this game might be doing something weird where blit-source positions and destination positions are all globals, for some fucking reason

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-06 at 02:40

I think it stores them inside the VGA driver? huh

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-06 at 02:42

the game internally has 5 drivers (as of 2.2, I have other versions here and they're different): CGA, Hercules, EGA, Tandy, VGA.

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-06 at 02:53

WHY ARE THERE TWO STRCATS

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-23 at 10:38

I've been working on cities.dat. I can now confirm that this game (Where in the World is Carmen Sandiego Enhanced (DOS, 1990)) has 30 cities, and they're the same 30 cities as the 1985 original.

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-23 at 10:48

hmm. I could reuse my readString code between these two formats, but it would technically enable world cities to have pronouns.

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-23 at 11:10

this game uses a fun text encoding method: both-ended null terminated!

It stores city names with a nul at the beginning because it reads them backwards. For some fucking reason.

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-23 at 11:15

why in the fuck is loading the data for Paris suddenly grabbing some random data out of Kigali? this implies some weird things about the compression, or the data normalization

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-23 at 11:22

going to moscow loads the same byte. strange.

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-23 at 11:40

they seek to position X

read 1 byte

read 99 more bytes

then seek to position X+100

now if you know how both math and random access files work, you'll realize something the programmers of Where in the World is Carmen Sandiego? Enhanced (1990, DOS) did not:

THEY'RE SEEKING TO THE POSITION THEY'RE ALREADY AT

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-23 at 12:18

I tried to corrupt the image to see if that'd tell me anything about how it was encoded, and it told me to put my hard drive back in.

=> View attached media

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-23 at 13:30

the way this game does the investigations is interesting.

so the basic gameplay is that you're in location X, you get 3 hints, which lead you to location Y, where the whole process repeats.

But if you savescum to experience the same pursuit again, they'll always go through the same places... but if you don't get the hints, they won't be there.

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-23 at 13:30

like the hints will always tell you to go to sri lanka, but if you go there without first having heard those hints, then he won't be in sri lanka

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 02:27

Hah! the game apparently calculates some info ahead of time, but only a few steps. I changed who the suspect was by memory editing, and it didn't take effect... until I got to the third location.

Since I went from a robbery by Fast Eddie B to one by Merey LaRoc, it means the pronouns changed when I got to London.

Congrats on coming out as a trans woman, Merey.

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 03:57

ok I ran my dosspin tool to gibberish every byte of the save game file (it's only 102 bytes, so this is easy!) and none of them change where you start. very interesting... I'm guessing either the values are spread out too much for my gibberishing to reach, or you need to modify multiple bytes at once

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 04:43

huh, I found a hidden(?) key: if you hold down either shift, it skips all the pauses in the printing. so it goes at MAX CPU SPEED

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 04:46

ahh good. it's always fun to find code that looks like:

do{

while(variable!=0);

some one has a custom tick handler that's permutating a global!

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 04:46

can't be threading, this is 16-bit DOS. There is no threading.

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 05:21

looking at interrupts, and I think I found a bug.

they set handlers for various CPU errors, but they accidentally set 10 (COPROCESSOR ERROR) twice, instead of the 05 (BOUND check)/10 (COPRPOCESSOR) interrupts they save

someone copy-pasted and missed a bit

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 06:08

I finally found the two helper functions they use to get and set vectors!

all the 30 other places I've seen them set/get vectors, they do it manually, but hey, maybe they use the helpers too

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 06:08

could also be that this is a compiler-provided bit of code, which is left in because the runtime needs it, or they just didn't eliminate dead code

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 07:11

okay I've figured out there's a shared format they're using here. it chunks the file into chunks, which have a 16-bit ID (unique per file, but not globally), an offset, and 16-bit length

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 07:13

so like, midisnd.dat will have 12 entries, and the first 11 are 200-500 bytes each, and then the last is 3k.

presumably it's each song and then some config info?

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 07:15

cities.dat is very interesting. There's 30 cities in total, but 491 entries in it!

So they must be doing something odd there, that doesn't divide equally. Maybe one city-chunk gives IDs of the others?

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 07:17

idea for a test: it's easy to spot which chunk in a city is the image, because it's the biggest. Here's a way to determine if it's looking up by IDs or offsets/indices: swap the IDs of two images

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 07:23

darn. turns out you can't just renumber the chunks, because they have to be in increasing order.

so maybe I just need to leave the chunk indexes as is, and instead of moving the entries around, I move where they're pointing?

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 07:28

Bingo! I'm in Athens, but I'm seeing the image for Baghdad, and apparently with the Baghdad palette?

So one of these other chunks must be the palette for a city. Or it selects from a selection of palettes? Maybe they've just got a couple defined.

=> View attached media

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 07:34

okay I figured out the cities.dat IDs:

They're all 1XXYY (in decimal):

XX is the city number (0-29), YY is the sub-chunk-id.

So like:

YY=0: City name

YY=2: City image.

They go between 00 and 22, and not all numbers need to be present.

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 08:26

hmm, reading a buffer and then summing all the values of the bytes in it.

suspicious behavior.

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 08:40

okay I think it has a very simple 1-byte CRC check on the chunks, which are optionally not run.

I can't make the math work but I'm reasonably sure that's what it is

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 09:26

okay they're using a blit that's UI-aware, so it starts the coordinate system at (1,13). Fun!

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 09:39

looking into the blitting code I managed to steal the world map out of RAM

=> View attached media

=> More informations about this toot | More toots from foone@digipres.club

Toot

Written by Foone🏳️‍⚧️ on 2025-01-24 at 09:55

ugh. TODO for my eventual Good DOS Debugger:

Instant Video display.

I don't know exactly how DOSBox-X is doing it, but while single-stepping the debugger, the display never updates. I can dump the ram at A000:0000 and see what updated, but not on the screen in DOSBox

=> More informations about this toot | More toots from foone@digipres.club

Descendants

Written by Foone🏳️‍⚧️ on 2025-01-24 at 10:19

found a suspicious array, which goes:

[

(-1,0),

(-1,1),

(0,1),

(1,1),

(1,0),

(1,-1),

(0, -1),

(-1,-1),

(0,0)

]

POP QUIZ: why does the font renderer need this array? how are they being "lazy" with this array?

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 10:20

there's also this code in the for-loop that steps through this array:

if index==8:

color=white

else:

color=black

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-24 at 10:30

@dividuum got it:

they're drawing the font 9 times, offset in each of the 8 directions, and in black. then they draw it in white, with no offset.

It's a pixel-outliner! By drawing their pixel font offset in each direction, they get a black outline on their font.

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-25 at 09:36

The Answer to the DRM questions for Where in the world is Carmen Sandiego? Enhanced (DOS, 1990) are, in no particular order:

23

Kent

dragon

calcium

1796

Warren

revenue

1792

Willard

1937

Crater

Tanzania

Hartford

Duluth

London

Gem

Silent

squeaker

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 16:46

if ((0x80 >> ((byte)local_4 & 7) &

        (int)(char)*(byte *)((int)((int *)param_1 + 1) + (local_4 >> 3))) != 0) {

COULD YOU USE SOME MORE CASTS MAYBE?

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 16:52

oh it's because ghidra's near/far pointer support is shit.

I had param2 defined as a byte32 and it was casting it to a byte before using it

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 16:53

if I define it as byte* and let the calling convention implicitly define it as 32bit, it doesn't do the cast

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 17:03

well I found the decompression method.

as always, I hate it. decompression routines are probably my least favorite thing to reverse engineer

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 17:09

I think this compression is specifically designed for ASCII text, which is annoying because they've also got compressed images... which probably use a DIFFERENT COMPRESSION!

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 17:17

it looks like this chunk has length 256, which means 253 usable bytes, and it expands to 374 bytes.

Not the greatest compression. a little better than just doing 6-bit ASCII.

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 17:29

it's some kind of shifting bit mask but it starts at encoding values in 4 bits, then it can increase (or decrease, I guess) based on the input stream.

then it has an output filter, where if the number specified wasn't 8 bits, it's actually an index into a predefined text table

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 17:30

the predefined table starts with NUL, space, then:

aetonisrdlhugfcwypbmk,vSA.T'PMxBCIRGDWHqE-zNFKL0j:51YJ8\U?73Q;2!469

\r\nOVXZ()*+"#$%&<=>/@[]^_`

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 17:47

given that the most comment symbols are near the beginning, this is presumably a sort of lazy huffman coding

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 17:47

but I've got the predefined table, an input file, an output file, and now I need to write some python code to replicate this, hopefully without crying

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 18:07

"vs ses oa is isgit's tc eital and largest t u anhtA ttggh os nnotosnhrdsmarosogdn ss drte tishoth's isdhsceohtsnthminder of isgit's t nuorhdhtpast\x00 geru is slightltsn oaller than ndhd na and is o nnsgtgstbtst oa dotlalssaaolootbiaoht Sal gh, sonuhvia and sl ghh\x00isgit, ontvdn ss nhsiaalgarsnadlfnaatawlarst oadrlhrs i is a rugged land dooousr'casrbhe nrdsgs fountainsnht iah"

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 18:07

I mean, it's not 100% wrong, but it's not right either

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 18:09

that's supposed to read:

"\x03Lima is Peru's capital and largest city. A well-known landmark is the Archbishop's Palace, a reminder of Peru's colonial past\x00Peru is slightly smaller than Alaska and is bordered by Ecuador, Colombia, Brazil, Bolivia and Chile\x00Peru, once the center of the mighty Incan Empire, is a rugged land dominated by the Andes Mountains. Forests and jungles cover half its land area\x00"

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 18:35

I somehow confused the dosbox-x debugger into not accepting letters anymore

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 18:49

it was a trivial off-by-one error.

I was doing saved_byte=input[3]

but while I needed the 3rd byte, that's at input[2]

=> More informations about this toot | More toots from foone@digipres.club

Written by Foone🏳️‍⚧️ on 2025-01-27 at 19:12

yess!

C:\DOSBox-X\drive_c\carmen\py>python datfile.py cities.dat --dump=12803 --decompress

"\x03Sydney, with a population of more than 3.3 million people, is Australia's largest city. A well-known sight is Sydney's distinctively designed Opera House\x00An island continent, Australia is nearly as large as the United States but has only one-fifteenth the population\x00The capital of Australia is Canberra, located in the southeast corner of the country between Sydney and Melbourne\x00"

=> More informations about this toot | More toots from foone@digipres.club

Written by Riley S. Faelan on 2025-01-24 at 10:09

@foone Perhaps it only updates an internal SDL canvas, but never throws it on the actual screen.

=> More informations about this toot | More toots from riley@toot.cat

Written by Foone🏳️‍⚧️ on 2025-01-24 at 10:21

@riley could be. I may have to see if I can hack it so that stepping the debugger tails the main window to update somehow

=> More informations about this toot | More toots from foone@digipres.club

Written by Riley S. Faelan on 2025-01-24 at 11:58

@foone I've never gotten around to looking into how DOSBox actually does it, but from my last foray into SDL, I recall it had some weird ideas about graphics updates due to the path dependency of how it implemented multiple-buffering. On classic PC during ordinary operations, this might tie into the VGA's frame refresh interrupt; during human-stepping debugging, obviously, the target program just can't have access to all the frame refreshes, and something in DOSBox's emulation architecture might be doing something clever about it that just happens to break things.

Obviously, DOSBox's idea of how frame refresh works doesn't have to have anything to do with actual target-visible interrupts, but it might potentially give you a bit of information to let the software think it has a CGA, not a VGA. CGA, IIRC, didn't have support for proper frame interrupt, and a different synchronisation mechanism (status register polling?) might fail in a different, and perhaps illuminating, way.

=> More informations about this toot | More toots from riley@toot.cat

Written by Riley S. Faelan on 2025-01-24 at 11:59

@foone I can't quite remember which way MCGA would have fallen, either. It was kind of a halfway between CGA and (a subset of) VGA.

=> More informations about this toot | More toots from riley@toot.cat

Written by Lucy 🧙🏼‍♀️🦇 on 2025-01-24 at 10:27

@foone to draw the black shadow around the map?

=> More informations about this toot | More toots from rappet@chaos.social

Written by Foone🏳️‍⚧️ on 2025-01-24 at 10:29

@rappet Nope. Remember, it's in the font renderer

=> More informations about this toot | More toots from foone@digipres.club

Written by Otte Homan - remember Geordie on 2025-01-24 at 12:16

@foone that sounds, ..., complicated?

=> More informations about this toot | More toots from otte_homan@theblower.au

Written by Haydn on 2025-01-25 at 09:42

@foone does this count as breaking DRM?

=> More informations about this toot | More toots from haydng@mastodon.social

Written by Janek @ IndieDev.site on 2025-01-25 at 11:11

@foone oh yeah I remember this game

=> More informations about this toot | More toots from hardpenguin13@mastodon.gamedev.place

Written by jordan on 2025-01-27 at 16:48

@foone If I had any more casts, I'd be beloved long-running musical Cats

=> More informations about this toot | More toots from jordan@sometimes.social

Written by b4ux1t3 :trek_ds9_sisko:#1️⃣ on 2025-01-27 at 16:59

@jordan You should know I actually squirted coffee out of my nose from this. Thanks for that.

=> More informations about this toot | More toots from b4ux1t3@hachyderm.io

Written by Cassandrich on 2025-01-27 at 16:49

@foone Garbage decompiler that doesn't choose suitable type for synthesized locals and vomits redundant integer type casts...

=> More informations about this toot | More toots from dalias@hachyderm.io

Written by Avebury Rosetta :transistor: 🍉🏴🚩 on 2025-01-27 at 16:52

@foone Is this some kind of unicode project? Why convert from char* to byte*?

=> More informations about this toot | More toots from avesbury_rosetta@wetdry.world

Written by Foone🏳️‍⚧️ on 2025-01-27 at 16:57

@avesbury_rosetta no unicode, this game predates unicode.

I'm not really sure why it's casting.

=> More informations about this toot | More toots from foone@digipres.club

Written by Graham Sutherland / Polynomial on 2025-01-27 at 18:08

@foone bames jond's having a stronk

=> More informations about this toot | More toots from gsuberland@chaos.social

Written by Pxl Phile on 2025-01-28 at 06:23

@gsuberland @foone ah I thought it was Welsh

=> More informations about this toot | More toots from ppxl@social.tchncs.de

Written by Sekoia on 2025-01-27 at 18:13

@foone@digipres.club weird shuffling. "and largest" is exactly correct, but the rest seems... pretty random. Wonder how that happened

=> More informations about this toot | More toots from sekoiatree@blahaj.zone

Written by jaKa Močnik on 2025-01-27 at 18:29

@sekoiatree could be it was random. 🤷 @foone

=> More informations about this toot | More toots from jkmcnk@mastodon.social

Written by Ben Cox on 2025-01-27 at 18:55

@foone The two hardest things in computer science are naming, resource allocation, and fencepost errors.

=> More informations about this toot | More toots from ben@s.djehuti.com

Written by Bill Ricker on 2025-01-27 at 19:44

@foone

... because of course it is ...

[#]FencepostAllTheThings

=> More informations about this toot | More toots from n1vux@mastodon.radio

Written by genstar.service on 2025-01-27 at 19:05

@foone ? . - . . . ?! . . . !!!!!!! - - . ? @ . 0003 ??? :neodog_pat_happy:

=> More informations about this toot | More toots from Genstar@meow.social

Written by Fanny Matrice :trainsgender: on 2025-01-27 at 18:09

@foone so true

=> More informations about this toot | More toots from dlatchx@tfnux.org

Written by Lynne on 2025-01-27 at 18:44

@foone this is what it sounds like when two people try to talk to me at once or one person starts but I don't pick it up on a whole syllable and my brain's verbal parser crashes

=> More informations about this toot | More toots from Lynne@housecat.space

Written by Foone🏳️‍⚧️ on 2025-01-27 at 18:50

@Lynne yep, same

=> More informations about this toot | More toots from foone@digipres.club

Written by JamesTrading on 2025-01-27 at 17:57

@foone https://t.me/TradersEdgesignal

=> More informations about this toot | More toots from JamesTrading@mastodon.social

Written by Luis Correia on 2025-01-27 at 16:55

@foone that reminds me when DoubleFine had to modify their Lua language version to support longer jumps for the first Psychonauts Game

=> More informations about this toot | More toots from luisfcorreia@mastodon.social

Written by BenBE on 2025-01-28 at 07:22

@foone Nah, that source is not a casting show …

=> More informations about this toot | More toots from benbe@social.chaotikum.org

Written by Dave Ackley on 2025-01-24 at 10:26

@foone cheesy boldface

=> More informations about this toot | More toots from livcomp@hachyderm.io

Written by Florian Wesch on 2025-01-24 at 10:28

@foone „outlining by overdrawing“. I may or may not have used this technique in the past :)

=> More informations about this toot | More toots from dividuum@chaos.social

Written by Foone🏳️‍⚧️ on 2025-01-24 at 10:29

@dividuum bingo!

=> More informations about this toot | More toots from foone@digipres.club

Proxy Information
Original URL
gemini://mastogem.picasoft.net/thread/113882730995965387
Status Code
Success (20)
Meta
text/gemini
Capsule Response Time
733.993953 milliseconds
Gemini-to-HTML Time
58.512605 milliseconds

This content has been proxied by September (3851b).