New York is hot, and you are on your way to the office complex. It seems like it is well guarded, even though you are expected under the alias of the assassin, perhaps it will be a better idea to sneak inside the building, unseen? You climb through a window on the side of the building. Inside you spot more guards, quick, hide behind a desk. Now you have to sneak past the guards into the main office.
### Challenge: Spycam (hardware)
You manage to find some exposed wires and quickly hook them up to your portable terminal. It seems to be a live feed of the internal CCTV system. If you can manage to decode the signal you might find something interesting, maybe a code or a password to get past the locked door.
### After solving
Congratulations, you successfully sneaked past the guards, and now you are inside the main office. Look over there, a safe case! Wait, what, it is open, no way! It’s only a photo inside, what a disappointment... But wait, don’t get hasty now, it seems like it’s a harbor in the picture, and there is something scribbled on the back, it’s coordinates to the harbor which seems to be located in Singapore.
Extracting this file gives seven `csv` files of about 25MB:
- 1.csv
- 2.csv
- 3.csv
- 4.csv
- 5.csv
- 6.csv
- 7.csv
They all contain 600255 lines.
A sample of the first csv file:
```text
-0.0018051198211097765 ,4.25 ,-0.05 ,-0.05 ,-0.18
-0.001805079821043734 ,4.25 ,-0.05 ,-0.08 ,-0.18
-0.0018050398209776917 ,4.3 ,-0.05 ,-0.08 ,-0.18
-0.0018049998209116493 ,4.3 ,-0.05 ,-0.08 ,-0.18
-0.0018049598208456068 ,4.25 ,-0.05 ,-0.08 ,-0.2
-0.0018049198207795644 ,4.25 ,-0.05 ,-0.05 ,-0.18
-0.001804879820713522 ,4.25 ,-0.05 ,-0.05 ,-0.18
```
## Solving
I found this challenge to be pretty difficult as it gives us very little information to start with.
The description says something about CCTV footage, so these CSVs probably contains some kind of image or video. I don't know any format though that looks like this.
The first column in the CSV file seems to only be incrementing. This could be a timing signal for something like [VGA](https://en.wikipedia.org/wiki/Video_Graphics_Array). I though of this because [Ben Eater](https://www.youtube.com/channel/UCS0N5baNlQWJCUrhCEo8WlA) makes great videos about how computers work and made [a video about creating a graphics card](https://www.youtube.com/watch?v=l7rce6IQDWs). I recommend you go watch it if you don't know how VGA works. I also remmend you to watch [this follow-up video about RGB in VGA](https://www.youtube.com/watch?v=uqY3FMuMuRo).
With my basic understanding about VGA, I tried to make sense of the data.
As I said, the first column seems to be the timing, but the others are still unclear. I continued by taking a look at the value range of the columns using a Python script.
```py
filename = "1.csv"
with open(filename, "r") as file:
min_max = [[float(value), float(value)]
for value in file.readline().split(",")]
for line in file:
for index, value in enumerate(map(float, line.split(","))):
min_max[index][0] = min(min_max[index][0], value)
min_max[index][1] = max(min_max[index][1], value)
for index, [low, high] in enumerate(min_max):
print(f"#index: {index}")
print(f"{low=}")
print(f"{high=}")
print(f"rng={high-low}")
print()
```
```py
#index: 0
low=-0.0018051198211097765
high=0.022205119821109773
rng=0.02401023964221955
#index: 1
low=-0.35
high=4.8
rng=5.1499999999999995
#index: 2
low=-0.4
high=0.28
rng=0.68
#index: 3
low=-0.38
high=0.28
rng=0.66
#index: 4
low=-0.43
high=0.15
rng=0.58
```
The output shows the ranges of the last three indexes are about the same. This hints at color values, and, if you know VGA, this makes sense as the value would be between 0 and 0.7 volts.
In today's images, the range is defined in a byte with a value between 0 and 255. So later these numbers will have to multiplied by `255/0.7`.
The purpose of the second column is, however, still unclear. From the range I could see it goes from 0 to 5 and from scrolling through the CSV file I could see it only turned to 0 twice. To confirm this, I wrote the following script:
```py
filename = "1.csv"
x_values = set()
with open(filename, "r") as file:
for index, line in enumerate(file):
_, x, _, _, _ = map(float, line.split(","))
x_values.add(x)
# Only print every 1000 lines as the output would be too cluttered otherwise
In this script I count the number of lines that I want to use and also printed the timings in (probably) milliseconds. I want these numbers so I can find out what the resolution of the VGA signal is.
The output was roughly the same for all seven files:
```py
counter=415492, timing=16.619707440046454
counter=415492, timing=16.619707440046454
counter=415491, timing=16.61966743998041
counter=415491, timing=16.619667439980415
counter=415491, timing=16.619667439980415
counter=415491, timing=16.61966743998041
counter=415491, timing=16.619667439980415
```
This means the frame is about 415492 pixels in total and it takes 16.6 ms to draw it.
With this information I went to [TinyVGA](http://tinyvga.com/vga-timing). This website contains the timings for all VGA resolutions. From it's catalog, I found [`640 x 480 @ 60 Hz`](http://tinyvga.com/vga-timing/640x480@60Hz) to be the best match as it the total amount of pixels would be `800 * 525 = 420000`, with a total frame time of `16.683217477656 ms`.
This is pretty close to our values, so I tried to render a picture using it's vertical refresh rate of `31.46875 kHz`.
The script I used is the following:
```py
import glob
from PIL import Image
width = 800 # amount of pixels in one line
height = 525 # amount of lines in whole frame
vertical_refresh = 31468.75 # vertical refresh rate in Hz
lowest_voltage = -0.4 # lowest voltage of a signal