Add unobfuscated alt code to 2020/otterness
This code was found on the author's web page about the entry and has been added as prog.alt.c. I added the try.alt.sh script as well. Manifest updated and rebuilt .entry.json and index.html files.
This commit is contained in:
1 parent
12320c548d
commit
94bdb2c1d8
14 files changed
+411
-4
No files matched your search
@@ -33,6 +33,14 @@
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "original source code"
|
||||
},
|
||||
{
|
||||
"file_path" : "try.alt.sh",
|
||||
"inventory_order" : 100,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "shellscript",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "script to try alternate code"
|
||||
},
|
||||
{
|
||||
"file_path" : "try.sh",
|
||||
"inventory_order" : 100,
|
||||
@@ -41,6 +49,14 @@
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "script to try entry"
|
||||
},
|
||||
{
|
||||
"file_path" : "prog.alt.c",
|
||||
"inventory_order" : 120,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "c",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "unobfuscated source code"
|
||||
},
|
||||
{
|
||||
"file_path" : "cvikl.mid",
|
||||
"inventory_order" : 150,
|
||||
|
||||
@@ -6,6 +6,7 @@ indent
|
||||
indent.c
|
||||
indent.o
|
||||
prog
|
||||
prog.alt
|
||||
prog.orig
|
||||
!cvikl.mid
|
||||
!entertainer.mid
|
||||
@@ -115,8 +115,8 @@ OBJ= ${PROG}.o
|
||||
DATA=
|
||||
TARGET= ${PROG}
|
||||
#
|
||||
ALT_OBJ=
|
||||
ALT_TARGET=
|
||||
ALT_OBJ= ${PROG}.alt.o
|
||||
ALT_TARGET= ${PROG}.alt
|
||||
|
||||
|
||||
#################
|
||||
@@ -139,6 +139,9 @@ ${PROG}: ${PROG}.c
|
||||
alt: data ${ALT_TARGET}
|
||||
@${TRUE}
|
||||
|
||||
${PROG}.alt: ${PROG}.alt.c
|
||||
${CC} ${CFLAGS} $< -o $@ ${LDFLAGS}
|
||||
|
||||
# data files
|
||||
#
|
||||
data: ${DATA}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
make
|
||||
```
|
||||
|
||||
There is an unobfuscated version for those who wish to see the original final
|
||||
prior to obfuscation. See [Alternate code](#alternate-code) below.
|
||||
|
||||
|
||||
### Bugs and (Mis)features:
|
||||
|
||||
@@ -33,6 +36,37 @@ Now play `output.mid` and `output2.mid` in an audio player that can play MIDI
|
||||
files.
|
||||
|
||||
|
||||
## Alternate code:
|
||||
|
||||
### NOTICE to those who wish for a greater challenge:
|
||||
|
||||
**If you want a greater challenge, don't check this version**:
|
||||
just try to understand the program via the entry source.
|
||||
|
||||
If you get stuck, come back and take a look at the alternate, unobfuscated code,
|
||||
described by the author as:
|
||||
|
||||
> If you're curious about the un-obfuscated program that I originally wrote,
|
||||
this was the final working version. I tried to keep the functions names and
|
||||
comments understandable, but it will make a lot more sense to readers familiar
|
||||
with the MIDI "SMF" file format.
|
||||
|
||||
... at their [web page about the
|
||||
entry](https://www.nathanotterness.com/2021/04/obfuscated_c_2020.html).
|
||||
|
||||
|
||||
## Alternate use:
|
||||
|
||||
Use `prog.alt` as you would `prog`.
|
||||
|
||||
|
||||
### Alternate try:
|
||||
|
||||
``` <!---sh-->
|
||||
./try.alt.sh
|
||||
```
|
||||
|
||||
|
||||
## Judges' remarks:
|
||||
|
||||
In an entry that boasts not using literals, one would expect to see
|
||||
@@ -105,6 +139,13 @@ especially true for "live performance" .mid files.
|
||||
correctly parse, but I have rarely seen this in practice. The largest
|
||||
cause of program failures, in my experience, has been Limitation 2.
|
||||
|
||||
### NOTICE to those who wish for a greater challenge:
|
||||
|
||||
**If you want a greater challenge, don't read any further**:
|
||||
just try to understand the program via the source.
|
||||
|
||||
If you get stuck, come back and read below for additional hints and information.
|
||||
|
||||
|
||||
#### Obfuscation notes
|
||||
|
||||
|
||||
@@ -409,6 +409,8 @@ Location: <a href="../../location.html#US">US</a> - <em>United States of America
|
||||
<!-- BEFORE: 1st line of markdown file: 2020/otterness/README.md -->
|
||||
<h2 id="to-build">To build:</h2>
|
||||
<pre><code> make</code></pre>
|
||||
<p>There is an unobfuscated version for those who wish to see the original final
|
||||
prior to obfuscation. See <a href="#alternate-code">Alternate code</a> below.</p>
|
||||
<h3 id="bugs-and-misfeatures">Bugs and (Mis)features:</h3>
|
||||
<p>The current status of this entry is:</p>
|
||||
<pre><code> STATUS: INABIAF - please DO NOT fix</code></pre>
|
||||
@@ -419,6 +421,24 @@ Location: <a href="../../location.html#US">US</a> - <em>United States of America
|
||||
<pre><code> ./try.sh</code></pre>
|
||||
<p>Now play <code>output.mid</code> and <code>output2.mid</code> in an audio player that can play MIDI
|
||||
files.</p>
|
||||
<h2 id="alternate-code">Alternate code:</h2>
|
||||
<h3 id="notice-to-those-who-wish-for-a-greater-challenge">NOTICE to those who wish for a greater challenge:</h3>
|
||||
<p><strong>If you want a greater challenge, don’t check this version</strong>:
|
||||
just try to understand the program via the entry source.</p>
|
||||
<p>If you get stuck, come back and take a look at the alternate, unobfuscated code,
|
||||
described by the author as:</p>
|
||||
<blockquote>
|
||||
<p>If you’re curious about the un-obfuscated program that I originally wrote,
|
||||
this was the final working version. I tried to keep the functions names and
|
||||
comments understandable, but it will make a lot more sense to readers familiar
|
||||
with the MIDI “SMF” file format.</p>
|
||||
</blockquote>
|
||||
<p>… at their <a href="https://www.nathanotterness.com/2021/04/obfuscated_c_2020.html">web page about the
|
||||
entry</a>.</p>
|
||||
<h2 id="alternate-use">Alternate use:</h2>
|
||||
<p>Use <code>prog.alt</code> as you would <code>prog</code>.</p>
|
||||
<h3 id="alternate-try">Alternate try:</h3>
|
||||
<pre><code> ./try.alt.sh</code></pre>
|
||||
<h2 id="judges-remarks">Judges’ remarks:</h2>
|
||||
<p>In an entry that boasts not using literals, one would expect to see
|
||||
straightforward ways to produce small integers like <code>!(x^x)<<!(x^x)</code>, etc. but
|
||||
@@ -537,7 +557,9 @@ very thoroughly).</li>
|
||||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/prog.c">prog.c</a> - entry source code</li>
|
||||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/Makefile">Makefile</a> - entry Makefile</li>
|
||||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/prog.orig.c">prog.orig.c</a> - original source code</li>
|
||||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/try.alt.sh">try.alt.sh</a> - script to try alternate code</li>
|
||||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/try.sh">try.sh</a> - script to try entry</li>
|
||||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/prog.alt.c">prog.alt.c</a> - unobfuscated source code</li>
|
||||
<li><a href="cvikl.mid">cvikl.mid</a> - sample MIDI file</li>
|
||||
<li><a href="entertainer.mid">entertainer.mid</a> - sample MIDI file</li>
|
||||
</ul>
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
uint16_t ReadBigEndian16(uint8_t *c) {
|
||||
return *(c + 1) | (uint16_t) (*c) << 8;
|
||||
}
|
||||
|
||||
void WriteBigEndian16(uint8_t *c, uint16_t v) {
|
||||
c[1] = v;
|
||||
c[0] = v >> 8;
|
||||
}
|
||||
|
||||
uint32_t ReadBigEndian32(uint8_t *c) {
|
||||
return (uint32_t) ReadBigEndian16(c) << 16 | ReadBigEndian16(c + 2);
|
||||
}
|
||||
|
||||
void WriteBigEndian32(uint8_t *c, uint32_t v) {
|
||||
WriteBigEndian16(c + 2, v);
|
||||
WriteBigEndian16(c, v >> 16);
|
||||
}
|
||||
|
||||
// Fills in the *value. Returns the length in bytes.
|
||||
int ReadVarInt(uint8_t *content, uint32_t *value) {
|
||||
int i;
|
||||
uint8_t b;
|
||||
*value = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
b = content[i];
|
||||
*value |= b & 0x7f;
|
||||
if (!(b & 0x80)) return i + 1;
|
||||
*value = *value << 7;
|
||||
}
|
||||
fprintf(stderr, "Bad variable int.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uint8_t HighestBit(uint32_t n) {
|
||||
uint8_t r = 1;
|
||||
if (!n) return 0;
|
||||
while (n >>= 1) r++;
|
||||
return r;
|
||||
}
|
||||
|
||||
uint8_t VarIntBytes(uint32_t n) {
|
||||
uint8_t bits = HighestBit(n);
|
||||
return bits / 7 + !!(bits % 7);
|
||||
}
|
||||
|
||||
int WriteVarInt(uint32_t n, uint8_t *c) {
|
||||
uint8_t bytes_needed = VarIntBytes(n);
|
||||
*c = 0;
|
||||
if (!n) return bytes_needed;
|
||||
if (bytes_needed > 4) {
|
||||
fprintf(stderr, "Int too big for MIDI.\n");
|
||||
exit(1);
|
||||
}
|
||||
c += bytes_needed - 1;
|
||||
while (n != 0) {
|
||||
*c = n & 0x7f;
|
||||
n = n >> 7;
|
||||
c--;
|
||||
}
|
||||
return bytes_needed;
|
||||
}
|
||||
|
||||
// Advances past the next MIDI message, returning a pointer after it, and
|
||||
// updating running status if necessary.
|
||||
uint8_t* AdvancePastMessage(uint8_t *c, uint8_t *running_status) {
|
||||
uint32_t tmp;
|
||||
uint8_t b;
|
||||
switch (*c) {
|
||||
case 0xf0:
|
||||
case 0xf7:
|
||||
// Skip past system exclusive messages
|
||||
*running_status = 0;
|
||||
c++;
|
||||
c += ReadVarInt(c, &tmp);
|
||||
return c + tmp;
|
||||
case 0xff:
|
||||
// Skip past meta events
|
||||
*running_status = 0;
|
||||
c++;
|
||||
c++;
|
||||
c += ReadVarInt(c, &tmp);
|
||||
return c + tmp;
|
||||
}
|
||||
// We're assuming this is a channel voice message now.
|
||||
if (*c & 0x80) {
|
||||
// Advance past the new status byte.
|
||||
b = *c;
|
||||
c++;
|
||||
*running_status = b;
|
||||
} else {
|
||||
b = *running_status;
|
||||
}
|
||||
// Just test the different channel voice message types.
|
||||
switch (b >> 4) {
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 14:
|
||||
return c + 2;
|
||||
case 12:
|
||||
case 13:
|
||||
return c + 1;
|
||||
}
|
||||
fprintf(stderr, "Bad message status byte: %x\n", b);
|
||||
exit(1);
|
||||
return c;
|
||||
}
|
||||
|
||||
// Assumes we're pointing at the start of a MTrk. Returns a pointer to the
|
||||
// start of the next track.
|
||||
uint8_t* GetTrackTicks(uint8_t *c, uint32_t *ticks) {
|
||||
uint32_t length, tmp;
|
||||
uint8_t *end;
|
||||
uint8_t running_status = 0;
|
||||
*ticks = 0;
|
||||
if (c[3] != 'k') {
|
||||
fprintf(stderr, "Not at a track start.\n");
|
||||
exit(1);
|
||||
}
|
||||
length = ReadBigEndian32(c + 4);
|
||||
c += 8;
|
||||
end = c + length;
|
||||
while (c < end) {
|
||||
c += ReadVarInt(c, &tmp);
|
||||
*ticks += tmp;
|
||||
c = AdvancePastMessage(c, &running_status);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
// Requires a pointer to the start of the first track, and the total number of
|
||||
// tracks.
|
||||
uint32_t GetHighestTrackTicks(uint8_t *c, int track_count) {
|
||||
uint32_t tmp, max = 0;
|
||||
int i;
|
||||
for (i = 0; i < track_count; i++) {
|
||||
c = GetTrackTicks(c, &tmp);
|
||||
fprintf(stderr, "Track %d: %u ticks\n", i, (unsigned) tmp);
|
||||
if (tmp > max) max = tmp;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
void DumpHex(uint8_t *data, int size) {
|
||||
int i;
|
||||
for (i = 0; i < size; i++) {
|
||||
fprintf(stderr, "%p + %d: 0x%02x\n", data, i, data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *beat = NULL;
|
||||
uint8_t *note_off_note = NULL;
|
||||
// Writes a beat at the given offset. Requires the beat size.
|
||||
uint8_t* WriteBeat(uint8_t *c, int i, int bs) {
|
||||
uint8_t n = 42, v = 80;
|
||||
if ((i % 4) == 0) {
|
||||
n = 36;
|
||||
v = 120;
|
||||
} else if ((i % 4) == 2) {
|
||||
n = 40;
|
||||
v = 100;
|
||||
}
|
||||
beat[1] = n;
|
||||
beat[2] = v;
|
||||
*note_off_note = n;
|
||||
memcpy(c, beat, bs);
|
||||
return c + bs;
|
||||
}
|
||||
|
||||
void WriteBootsAndCats(uint8_t *c, uint32_t length) {
|
||||
uint16_t ticks_per_beat, track_count;
|
||||
uint32_t beats_to_generate, tmp, data_size, beat_size;
|
||||
uint8_t *cur, *data = NULL;
|
||||
track_count = ReadBigEndian16(c + 10);
|
||||
ticks_per_beat = ReadBigEndian16(c + 12) >> 1;
|
||||
if (ticks_per_beat >> 15) {
|
||||
fprintf(stderr, "SMPTE timing isn't supported\n");
|
||||
exit(1);
|
||||
}
|
||||
beats_to_generate = GetHighestTrackTicks(c + 14, track_count) / ticks_per_beat;
|
||||
// A "beat" is simply a note-on followed by a note-off event. The tricky part
|
||||
// is the delta time may be more than one byte. We'll assume running status.
|
||||
// Note on = 00 <note> <velocity>
|
||||
// Note off = <delta time> <note> 00
|
||||
beat_size = 5 + VarIntBytes(ticks_per_beat);
|
||||
beat = malloc(beat_size);
|
||||
if (!beat) {
|
||||
fprintf(stderr, "Failed allocating beat.\n");
|
||||
exit(1);
|
||||
}
|
||||
// This requires 8 bytes in the track header + 4 bytes for end-of-track +
|
||||
// the track data, plus an additional byte to set up running status in the
|
||||
// first beat.
|
||||
data_size = beats_to_generate * beat_size + 13;
|
||||
data = malloc(data_size);
|
||||
if (!data) {
|
||||
fprintf(stderr, "Failed allocating data.\n");
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "Data size: %d (0x%x), beat size %d, # beats %d\n",
|
||||
(int) data_size, data_size, beat_size, beats_to_generate);
|
||||
memcpy(data, "MTrk", 4);
|
||||
WriteBigEndian32(data + 4, data_size - 8);
|
||||
fprintf(stderr, "Data size: %d\n", (int) data_size);
|
||||
|
||||
// Build the "beat" data
|
||||
cur = beat;
|
||||
*cur++ = 0;
|
||||
// Initial note number and velocity.
|
||||
*cur++ = 36;
|
||||
*cur++ = 120;
|
||||
cur += WriteVarInt(ticks_per_beat, cur);
|
||||
// Keep a pointer to where to write the note to turn off
|
||||
note_off_note = cur;
|
||||
*cur++ = 36;
|
||||
// The note-off velocity is 0.
|
||||
*cur = 0;
|
||||
|
||||
cur = data + 8;
|
||||
// Write the first note-on and off:
|
||||
*cur++ = 0;
|
||||
*cur++ = 0x99;
|
||||
memcpy(cur, beat + 1, beat_size - 1);
|
||||
cur += beat_size - 1;
|
||||
for (tmp = 1; tmp < beats_to_generate; tmp++) {
|
||||
cur = WriteBeat(cur, tmp, beat_size);
|
||||
}
|
||||
*cur++ = 0;
|
||||
*cur++ = 0xff;
|
||||
*cur++ = 0x2f;
|
||||
*cur = 0;
|
||||
// Update the original MIDI header to increment the track count and make sure
|
||||
// the format is 1.
|
||||
c[9] = 1;
|
||||
WriteBigEndian16(c + 10, track_count + 1);
|
||||
fwrite(c, length, 1, stdout);
|
||||
fwrite(data, data_size, 1, stdout);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
FILE *f = NULL;
|
||||
uint8_t *content = NULL;
|
||||
long size = 0;
|
||||
int result;
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
f = fopen(argv[1], "rb");
|
||||
if (!f) {
|
||||
fprintf(stderr, "Coudn't open %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
content = malloc(size);
|
||||
if (!content) {
|
||||
fprintf(stderr, "Couldn't allocate content buffer.\n");
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
result = fread(content, size, 1, f);
|
||||
fclose(f);
|
||||
if (result != 1) {
|
||||
fprintf(stderr, "Couldn't read %s.\n", argv[1]);
|
||||
free(content);
|
||||
return 1;
|
||||
}
|
||||
if ((content[3] != 'd') || (content[7] != 6)) {
|
||||
fprintf(stderr, "Bad MIDI file.\n");
|
||||
free(content);
|
||||
return 1;
|
||||
}
|
||||
WriteBootsAndCats(content, size);
|
||||
free(content);
|
||||
return 0;
|
||||
}
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# try.sh - demonstrate IOCCC entry 2020/otterness alt code
|
||||
#
|
||||
|
||||
# make sure CC is set so that when we do make CC="$CC" it isn't empty. Doing it
|
||||
# this way allows us to have the user specify a different compiler in an easy
|
||||
# way.
|
||||
[[ -z "$CC" || ! -f "$CC" || ! -x "$CC" ]] && CC="cc"
|
||||
|
||||
make CC="$CC" alt >/dev/null || exit 1
|
||||
|
||||
# clear screen after compilation so that only the entry is shown
|
||||
clear
|
||||
|
||||
read -r -n 1 -p "Press any key to run: ./prog.alt < cvikl.mid > output.mid: "
|
||||
echo 1>&2
|
||||
./prog.alt < cvikl.mid > output.mid
|
||||
echo "Now play output.wav in an audio player that can play MIDI files." 1>&2
|
||||
echo 1>&2
|
||||
|
||||
read -r -n 1 -p "Press any key to run: ./prog.alt < entertainer.mid > output2.mid: "
|
||||
echo 1>&2
|
||||
./prog.alt < entertainer.mid > output2.mid
|
||||
echo "Now play output2.wav in an audio player that can play MIDI files." 1>&2
|
||||
echo 1>&2
|
||||
@@ -4659,7 +4659,10 @@ Tolkien</a>.</p>
|
||||
<a href="2020/otterness/entertainer.mid">entertainer.mid</a> from the URLs we suggested so
|
||||
that one need not download them and to make sure they can always be obtained
|
||||
even if the domain or link goes dead.</p>
|
||||
<p>Cody also added the <a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/try.sh">try.sh</a> script.</p>
|
||||
<p>Cody also added the <a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/try.sh">try.sh</a> script and the
|
||||
<a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/try.alt.sh">try.alt.sh</a> script for the author’s
|
||||
unobfuscated version that Cody added as
|
||||
<a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/prog.alt.c">prog.alt.c</a>.</p>
|
||||
<div id="2020_tsoj">
|
||||
<h2 id="winning-entry-2020tsoj">Winning entry: <a href="2020/tsoj/index.html">2020/tsoj</a></h2>
|
||||
<h3 id="winning-entry-source-code-prog.c-62">Winning entry source code: <a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/tsoj//prog.c">prog.c</a></h3>
|
||||
|
||||
+4
-1
@@ -6038,7 +6038,10 @@ Tolkien](https://www.tolkienestate.com/life/biography/).
|
||||
that one need not download them and to make sure they can always be obtained
|
||||
even if the domain or link goes dead.
|
||||
|
||||
Cody also added the [try.sh](%%REPO_URL%%/2020/otterness/try.sh) script.
|
||||
Cody also added the [try.sh](%%REPO_URL%%/2020/otterness/try.sh) script and the
|
||||
[try.alt.sh](%%REPO_URL%%/2020/otterness/try.alt.sh) script for the author's
|
||||
unobfuscated version that Cody added as
|
||||
[prog.alt.c](%%REPO_URL%%/2020/otterness/prog.alt.c).
|
||||
|
||||
|
||||
<div id="2020_tsoj">
|
||||
|
||||
@@ -4319,7 +4319,9 @@
|
||||
2020,otterness,prog.c,20,true,c,true,entry source code
|
||||
2020,otterness,Makefile,30,true,makefile,true,entry Makefile
|
||||
2020,otterness,prog.orig.c,50,false,c,true,original source code
|
||||
2020,otterness,try.alt.sh,100,true,shellscript,true,script to try alternate code
|
||||
2020,otterness,try.sh,100,true,shellscript,true,script to try entry
|
||||
2020,otterness,prog.alt.c,120,true,c,true,unobfuscated source code
|
||||
2020,otterness,cvikl.mid,150,true,midi,false,sample MIDI file
|
||||
2020,otterness,entertainer.mid,159,true,midi,false,sample MIDI file
|
||||
2020,otterness,2020_otterness.tar.bz2,1415926535,false,tbz2,false,download entry tarball
|
||||
|
||||
|
Binary file not shown.
@@ -4324,8 +4324,10 @@
|
||||
2020/otterness/cvikl.mid
|
||||
2020/otterness/entertainer.mid
|
||||
2020/otterness/index.html
|
||||
2020/otterness/prog.alt.c
|
||||
2020/otterness/prog.c
|
||||
2020/otterness/prog.orig.c
|
||||
2020/otterness/try.alt.sh
|
||||
2020/otterness/try.sh
|
||||
2020/tsoj/.entry.json
|
||||
2020/tsoj/.gitignore
|
||||
|
||||
@@ -4324,8 +4324,10 @@
|
||||
2020/otterness/cvikl.mid
|
||||
2020/otterness/entertainer.mid
|
||||
2020/otterness/index.html
|
||||
2020/otterness/prog.alt.c
|
||||
2020/otterness/prog.c
|
||||
2020/otterness/prog.orig.c
|
||||
2020/otterness/try.alt.sh
|
||||
2020/otterness/try.sh
|
||||
2020/tsoj/.entry.json
|
||||
2020/tsoj/.gitignore
|
||||
|
||||
@@ -3091,7 +3091,9 @@
|
||||
2020/otterness/README.md
|
||||
2020/otterness/cvikl.mid
|
||||
2020/otterness/entertainer.mid
|
||||
2020/otterness/prog.alt.c
|
||||
2020/otterness/prog.c
|
||||
2020/otterness/try.alt.sh
|
||||
2020/otterness/try.sh
|
||||
2020/tsoj/.entry.json
|
||||
2020/tsoj/.gitignore
|
||||
|
||||
Reference in new issue
Block a user