Compare commits
246 Commits
Author | SHA1 | Date | |
---|---|---|---|
Connor Olding | 94ef6784e7 | ||
Connor Olding | b130583327 | ||
Connor Olding | 61a0c64421 | ||
Connor Olding | 11c454bb24 | ||
Connor | a3f1adadc2 | ||
Connor | 733bd0fbd6 | ||
Connor | a4dd7f6ee9 | ||
Connor | 655355f34a | ||
Connor Olding | 8e78d08c07 | ||
Connor Olding | edc739ea98 | ||
Connor Olding | 1240ecd266 | ||
Connor Olding | 46970df021 | ||
Connor Olding | b372392aa3 | ||
Connor Olding | f463e58706 | ||
Connor Olding | 9debd3f5ce | ||
Connor Olding | 9d99af3745 | ||
Connor Olding | 94d9de15a4 | ||
Connor Olding | d3f05daf6d | ||
Connor Olding | 9babd47832 | ||
Connor Olding | 02f586f1cd | ||
Connor Olding | a492e20819 | ||
Connor Olding | fc6c9faeb2 | ||
Connor Olding | 591d5bb5ca | ||
Connor Olding | 67d6447acf | ||
Connor | 591b496479 | ||
Connor Olding | ca0e5c7fca | ||
Connor Olding | 7220056b79 | ||
Connor | 1d216288db | ||
Connor | fe84c73459 | ||
Connor | b87651c549 | ||
Connor Olding | f8c15bc5b7 | ||
Connor Olding | 70b59d455d | ||
Connor Olding | bc2365daff | ||
Connor | 04ccfec87b | ||
Connor | f66ec0a8a6 | ||
Connor Olding | ffeef6ee6d | ||
Connor Olding | 57461ace0b | ||
Connor Olding | 18fbf59cb7 | ||
Connor Olding | 96a45a4ac4 | ||
Connor Olding | 53a13fb30b | ||
Connor Olding | f8ffcc851a | ||
Connor Olding | 3d0fb91f5d | ||
Connor Olding | bd110dca48 | ||
Connor Olding | f9bd047c58 | ||
Connor Olding | 93f7ce654d | ||
Connor Olding | c626d93521 | ||
Connor Olding | 88bde0c705 | ||
Connor Olding | 47b5fcc31c | ||
Connor Olding | 07c587287a | ||
Connor Olding | 0527b538ed | ||
Connor Olding | 9ec61f013f | ||
Connor Olding | 71da8551ab | ||
Connor Olding | cddb62a3a0 | ||
Connor Olding | fc9ff7a8b4 | ||
Connor Olding | 376ab80b03 | ||
Connor Olding | 67a6535439 | ||
Connor Olding | 2c226e0ec8 | ||
Connor Olding | 6c7a9be5df | ||
Connor Olding | bc4506b3bd | ||
Connor Olding | e1996520c2 | ||
Connor Olding | 498cdba5a2 | ||
Connor Olding | d5c51aae94 | ||
Connor Olding | 999da5ac53 | ||
Connor Olding | ffbdf32f13 | ||
Connor Olding | cf507ec580 | ||
Connor Olding | 4f5375a378 | ||
Connor Olding | b79aed3f66 | ||
Connor Olding | 71705de4ac | ||
Connor Olding | e1c1844fb2 | ||
Connor Olding | 4ce6e4ae96 | ||
Connor Olding | f2c1354637 | ||
Connor Olding | c088d79dec | ||
Connor Olding | 213b5d0ccb | ||
Connor Olding | 9f39f4aa14 | ||
Connor Olding | b9960ee594 | ||
Connor Olding | 6b81464a74 | ||
Connor Olding | d0efbb3886 | ||
Connor Olding | 35921704e3 | ||
Connor Olding | 703f4b7039 | ||
Connor Olding | 8f42809229 | ||
Connor Olding | e0160e220c | ||
Connor Olding | 41488120af | ||
Connor Olding | b7924de0c4 | ||
Connor Olding | 130989789a | ||
Connor Olding | 7cb3341158 | ||
Connor Olding | 965064ef90 | ||
Connor Olding | bec9cc266a | ||
Connor Olding | 7a7597ce83 | ||
Connor Olding | 8f568e07ff | ||
Connor Olding | e12cde76c0 | ||
Connor Olding | 52ee141c09 | ||
Connor Olding | 7de1254516 | ||
Connor Olding | 31de1416b1 | ||
Connor Olding | 1576082e43 | ||
Connor Olding | 221362d19b | ||
Connor Olding | 3a378d5e56 | ||
Connor Olding | 130725b759 | ||
Connor Olding | 6247148a85 | ||
Connor Olding | e9c0c0b245 | ||
Connor Olding | 145ccd8f82 | ||
Connor Olding | 6dbace24f9 | ||
Connor Olding | 54de7512c9 | ||
Connor | cf893660eb | ||
Connor | eeed9ea275 | ||
Connor | 4031c2dbda | ||
Connor | 17040c6b77 | ||
Connor | e8e11c3ad3 | ||
Connor | f6c8945b8c | ||
Connor | dfe69c396f | ||
Connor | 248a9c0305 | ||
Connor | 7c5834de20 | ||
Connor | a904f76704 | ||
Connor | 207603e462 | ||
Connor | 74cd548adb | ||
Connor | 7321c3c9e2 | ||
Connor | 5b83a72513 | ||
Connor | 50b1e9a48e | ||
Connor | cd0b5a8b4b | ||
Connor | 22e3eceb5d | ||
Connor | f4c682bbea | ||
Connor | aab2829c9c | ||
Connor | db487fe6c3 | ||
Connor | 40b0a332a5 | ||
Connor | d31b7b580e | ||
Connor | dd81f51280 | ||
Connor | 29e33e832e | ||
Connor Olding | 614fa18ea6 | ||
Connor | 14d49ba33c | ||
Connor | 1ec021fc8a | ||
Connor | 5bd84506a0 | ||
Connor | daafe529f3 | ||
Connor | 8ebad01de8 | ||
Connor | f8cc5a50db | ||
Connor | 4c0887edfb | ||
Connor | 401732d4be | ||
Connor | a8cc797d0f | ||
Connor | cebd8b94aa | ||
Connor | f055ff2497 | ||
Connor | 12a9b1640d | ||
Connor | 7ccb616fee | ||
Connor | bd2496fa0e | ||
Connor | 0243eb33dd | ||
Connor | 075418af21 | ||
Connor | 1815a0b996 | ||
Connor Olding | add6801a23 | ||
Connor Olding | eb7ead0b78 | ||
Connor Olding | 56e4333bab | ||
Connor | 273abe1ee4 | ||
Connor | 89a434c5e8 | ||
Connor | f8fbea1e92 | ||
Connor | 309749f0db | ||
Connor | 1ee01e95ef | ||
Connor | e8e5428400 | ||
Connor | ef338fea75 | ||
Connor | 44a3945bf2 | ||
Connor | 8093266ec7 | ||
Connor | caf9a2aab7 | ||
Connor Olding | 327b8ef28c | ||
Connor Olding | 2f145eb879 | ||
Connor Olding | f361a02852 | ||
Connor Olding | 2c824ad30b | ||
Connor Olding | 959be16350 | ||
Connor Olding | af75dcc7c5 | ||
Connor Olding | c76f172975 | ||
Connor Olding | 6fb6d3ba62 | ||
Connor Olding | 03860a8c7f | ||
Connor | 82010d49d8 | ||
Connor | 259475bfe6 | ||
Connor | 7f5dd0453e | ||
Connor | 121dd44429 | ||
Connor | 8c8b5d313a | ||
Connor | fd56c5124a | ||
Connor Olding | 98f669262c | ||
Connor | d88fe0dde7 | ||
Connor Olding | 00c1942cba | ||
Connor Olding | 828c74cb72 | ||
Connor | 82917de18f | ||
Connor | bc1eceaaf7 | ||
Connor Olding | 6a2eb1ffae | ||
Connor Olding | 26904c640f | ||
Connor Olding | ec865923a5 | ||
Connor Olding | a111b309cb | ||
Connor Olding | 814cd636c0 | ||
Connor | b4e1ec0a59 | ||
Connor Olding | 176b8b32b0 | ||
Connor | 8d44432e0f | ||
Connor Olding | 11b0a802f3 | ||
Connor Olding | a6aed4fcc5 | ||
Connor Olding | 62f12d031a | ||
Connor Olding | 2bbe301cdc | ||
Connor Olding | d4fbd7a829 | ||
Connor Olding | 34db3bf060 | ||
Connor | e824a1f8ba | ||
Connor Olding | f937547991 | ||
Connor Olding | 9ef423de71 | ||
Connor Olding | 83f1fbe6fc | ||
Connor Olding | 3aae7d6c1d | ||
Connor Olding | 115a30cc5b | ||
Connor Olding | 1fb3df1403 | ||
Connor Olding | bb5eabbd56 | ||
Connor | cf0d3cf896 | ||
Connor Olding | 051265ea3a | ||
Connor Olding | 124ec51da3 | ||
Connor Olding | 62866ee36c | ||
Connor | ab2b4a4dff | ||
Connor Olding | a61ff7660c | ||
Connor | 5cb1407dfa | ||
Connor Olding | c61c00dfd6 | ||
Connor Olding | fef8ae685d | ||
Connor Olding | 9d475fdba7 | ||
Connor Olding | 4bbf061085 | ||
Connor Olding | f7ac8f0704 | ||
Connor Olding | b4eeededf8 | ||
Connor Olding | a236ef5a51 | ||
Connor Olding | dbed8bb926 | ||
Connor Olding | 14014e2e93 | ||
Connor Olding | 6ae05ac68d | ||
Connor Olding | d1ea330243 | ||
Connor Olding | 1a2c9ae1e6 | ||
Connor Olding | 6a1562c5f5 | ||
Connor Olding | e5b036d9b8 | ||
Connor | c716e824dd | ||
Connor Olding | 9c69160563 | ||
Connor Olding | e4732d88cd | ||
Connor Olding | 20b8930ee6 | ||
notwa | 98b94536f7 | ||
notwa | 290370630e | ||
Connor Olding | dceb0894b3 | ||
notwa | 654b8ce3f7 | ||
Connor Olding | c8fc1d462e | ||
Connor Olding | 2edb454851 | ||
Connor Olding | 2ed08389c9 | ||
Connor Olding | 5865c56fd8 | ||
Connor Olding | 31ebe0b649 | ||
Connor Olding | ea6bf420b2 | ||
Connor Olding | 6e286aec91 | ||
notwa | 85da14dad0 | ||
notwa | b26f4074ec | ||
notwa | b739c4b6c0 | ||
notwa | 097b5e519b | ||
notwa | 39c1899843 | ||
notwa | 5456e17c8b | ||
notwa | 0c131cf1ea | ||
notwa | 9da2f9fc2e | ||
notwa | 54aff32db3 | ||
notwa | 15b7cb75e5 |
64
360_wasd/360-stick.ahk
Normal file
64
360_wasd/360-stick.ahk
Normal file
|
@ -0,0 +1,64 @@
|
|||
#Persistent
|
||||
#SingleInstance Force
|
||||
Send {w up}
|
||||
Send {a up}
|
||||
Send {s up}
|
||||
Send {d up}
|
||||
|
||||
Deadzone := 0.6
|
||||
SetTimer Wax, 5
|
||||
return
|
||||
|
||||
Wax:
|
||||
GetKeyState JoyX, JoyX
|
||||
GetKeyState JoyY, JoyY
|
||||
JoyX := (JoyX - 50)/50
|
||||
JoyY := (JoyY - 50)/50
|
||||
Angle := ATan(JoyX/JoyY)*2/3.14159
|
||||
Angle := (JoyY > 0) ? Angle + 3: Angle + 1
|
||||
Length := Sqrt(JoyX**2 + JoyY**2)
|
||||
; 1 1 0
|
||||
; 2 - 0
|
||||
; 2 3 3
|
||||
|
||||
OldX = %HoldX%
|
||||
OldY = %HoldY%
|
||||
|
||||
if Length > %Deadzone%
|
||||
{
|
||||
if % Angle >= 1.2 && Angle < 2.7
|
||||
HoldX = a
|
||||
else if % Angle >= 3.2 || Angle < 0.7
|
||||
HoldX = d
|
||||
else
|
||||
HoldX =
|
||||
if % Angle >= 0.3 && Angle < 1.7
|
||||
HoldY = w
|
||||
else if % Angle >= 2.3 && Angle < 3.7
|
||||
HoldY = s
|
||||
else
|
||||
HoldY =
|
||||
} else
|
||||
{
|
||||
HoldX =
|
||||
HoldY =
|
||||
}
|
||||
|
||||
SetKeyDelay -1
|
||||
if OldX != %HoldX%
|
||||
{
|
||||
if HoldX
|
||||
Send {%HoldX% down}
|
||||
if OldX
|
||||
Send {%OldX% up}
|
||||
}
|
||||
if OldY != %HoldY%
|
||||
{
|
||||
if HoldY
|
||||
Send {%HoldY% down}
|
||||
if OldY
|
||||
Send {%OldY% up}
|
||||
}
|
||||
return
|
||||
|
||||
F10::ExitApp
|
276
README.md
Normal file
276
README.md
Normal file
|
@ -0,0 +1,276 @@
|
|||
# gists
|
||||
|
||||
all files are [Unlicensed,](http://unlicense.org/) unless otherwise noted:
|
||||
|
||||
```
|
||||
This is free and unencumbered software released into the public domain.
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
```
|
||||
|
||||
the Python scripts here only work with Python 3.
|
||||
|
||||
### 360\_wasd
|
||||
|
||||
an ancient AutoHotKey script i wrote to convert the left control stick
|
||||
of a 360 controller to WASD inputs on a keyboard.
|
||||
i used it to play an equally ancient version of [The Binding of Isaac,](https://store.steampowered.com/app/113200/The_Binding_of_Isaac/)
|
||||
among a couple other games.
|
||||
|
||||
it should still work fine even today, but
|
||||
you can press F10 to kill it if it starts acting up.
|
||||
|
||||
### arithmetic\_coding
|
||||
|
||||
a GPL-licensed arithmetic coding compressor and decompressor for binary strings.
|
||||
originally by [David MacKay,](http://www.inference.org.uk/mackay/python/compress/)
|
||||
this has been cleaned up (passes pycodestyle) and ported to Python 3.
|
||||
|
||||
### batch\_encoding
|
||||
|
||||
another old script. this time it's a Windows batch file for re-encoding
|
||||
videos to be suitable for online distribution.
|
||||
i don't really use this anymore, but
|
||||
it looks like i once used it for N64 videos recorded with Bizhawk.
|
||||
|
||||
it contains some advanced `compand` nonsense from before `acompressor` was a thing.
|
||||
|
||||
### batch\_font\_render
|
||||
|
||||
a zsh script to render fonts — all the otf & ttf's in a directory —
|
||||
to png's, with some good ol' Lorem Ipsum.
|
||||
it uses pango and fontconfig, so i've only tested it on \*nix.
|
||||
|
||||
i recently repurposed this script
|
||||
to render characters to bitmaps for use as textures in games,
|
||||
but i haven't uploaded that version yet.
|
||||
|
||||
### coin\_or\_build
|
||||
|
||||
a shell script that builds Bonmin and its many, *many* dependencies
|
||||
on other coin\_or projects.
|
||||
|
||||
### danbooru\_atomizer
|
||||
|
||||
a Python script that scrapes atom feeds on [danbooru (nsfw)](https://danbooru.donmai.us/)
|
||||
and merges them into one mega-feed.
|
||||
|
||||
### danbooru\_scrape
|
||||
|
||||
another danbooru scraper, this time for batch-downloading all the images
|
||||
for a given search query. requires zsh and xml2.
|
||||
|
||||
i don't think this version works anymore,
|
||||
so i'll have to update it with my local changes sometime.
|
||||
|
||||
### debug\_saves
|
||||
|
||||
for Majora's Mask:
|
||||
these gameshark cheats will override the default save file
|
||||
with the debug save file. create a new file on the file select screen
|
||||
and it should create a debug save.
|
||||
*note:* this is probably the same as using map select.
|
||||
|
||||
### desmos
|
||||
|
||||
[stuff i've plotted in desmos.](/desmos/desmos.md)
|
||||
just click the link; it's another markdown file.
|
||||
|
||||
### dictionary\_attack
|
||||
|
||||
i went looking for a dead-simple tool to
|
||||
construct random, fixed-length strings from a list of shorter strings,
|
||||
but i realized in the time i'd find something i liked,
|
||||
i could just write my own in Python.
|
||||
so that's exactly what i did!
|
||||
|
||||
beware, this is highly unoptimized, favoring simplicity over speed.
|
||||
|
||||
### dnm
|
||||
|
||||
stuff related to Doubutsu no Mori,
|
||||
the original Japan-only release of Animal Crossing for the N64.
|
||||
|
||||
right now, this just contains a patch to make the game boot
|
||||
directly into the NES emulator for experimenting with.
|
||||
|
||||
since this game is built on the Zelda 64 engine (go figure),
|
||||
you can extract files and reconstruct ROMs
|
||||
by using the `z64_dump.py` script, found elsewhere in my `mm` repo.
|
||||
|
||||
### ds1
|
||||
|
||||
stuff related to Dark Souls 1.
|
||||
contains scripts to extract raw dialog and weapon/armor/npc/etc data.
|
||||
|
||||
you can extract the necessary files from the game's archives
|
||||
using this tool:
|
||||
[PC](https://github.com/HotPocketRemix/UnpackDarkSoulsForModding)
|
||||
or [PS3](https://github.com/notwa/UnpackDarkSoulsForModding)
|
||||
|
||||
### dwarf\_font
|
||||
|
||||
the 8x12 bitmap font included with [Dwarf Fortress](http://www.bay12games.com/dwarves),
|
||||
alongside a [love2d](https://love2d.org/) Lua script for loading it
|
||||
with all the appropriate character mappings.
|
||||
|
||||
the code is Unlicensed, and i believe the font itself is public domain.
|
||||
|
||||
### filter\_tutorial
|
||||
|
||||
a single Python file that walks you through
|
||||
designing and plotting an IIR filter.
|
||||
requires numpy, scipy, and matplotlib.
|
||||
|
||||
### image\_deduplication
|
||||
|
||||
a Python script to find duplicate images given a hamming distance threshold.
|
||||
it employs dhash to do the heavy lifting. requires pillow and dhash.
|
||||
|
||||
it doesn't recurse into `./_duplicate/` so you can dump things there if you wish.
|
||||
|
||||
### kill\_reboot
|
||||
|
||||
does nasty stuff to Windows 10 to
|
||||
prevent updates from automatically triggering reboots.
|
||||
|
||||
the C# portion is based on [NSudo.](https://github.com/M2Team/NSudo)
|
||||
the batch script exploits [a UAC bypass found by Tyranid.](https://tyranidslair.blogspot.ca/2017/05/exploiting-environment-variables-in.html)
|
||||
|
||||
### kyaa
|
||||
|
||||
[*moved to its own repo*](/git/notwa/kyaa)
|
||||
|
||||
### lsca
|
||||
|
||||
a brief cellular automata experiment.
|
||||
inspired by [Loren Schmidt.](https://twitter.com/lorenschmidt)
|
||||
|
||||
### love\_plotting
|
||||
|
||||
plotting equations with [love2d](https://love2d.org/).
|
||||
it probably doesn't work on the latest version.
|
||||
|
||||
it's nothing special, and i only included it here for archival sake.
|
||||
i have a newer version locally, but it needs to be cleaned up before it can be committed.
|
||||
|
||||
### lsf
|
||||
|
||||
an awful bash script i started writing just for fun,
|
||||
left here for archival sake.
|
||||
heaven forbid you actually enjoy this program,
|
||||
please instead consider using [ls--](https://github.com/trapd00r/ls--)
|
||||
or the like.
|
||||
|
||||
### mario\_tennis
|
||||
|
||||
this C program validates, brute-forces, and generates codes
|
||||
for the defunct Ring Tournament mode in Mario Tennis (N64),
|
||||
once used to hold competitions in magazines and the like.
|
||||
|
||||
### mips\_disassembler
|
||||
|
||||
an old disassembler for MIPS III binaries by spinout.
|
||||
the license is ambiguous.
|
||||
|
||||
i've since tweaked and cleaned the code. a little. not a lot.
|
||||
|
||||
### music\_sync
|
||||
|
||||
a Python script for syncing and re-encoding audio files
|
||||
for use on music players that support ogg vorbis.
|
||||
if you actually want to use this for some reason,
|
||||
be aware that you will need to know how to write Python
|
||||
to get it to work the way you want. and also, it's *really* slow,
|
||||
and even runs out of memory if too many files need updating (thanks mutagenx).
|
||||
|
||||
### n64\_models
|
||||
|
||||
a hastily-written Python script for outlining the F3DEX model format
|
||||
used in some N64 games.
|
||||
|
||||
### phasmophobia
|
||||
|
||||
an AutoHotKey script for quickly adding and removing equipment to games.
|
||||
|
||||
### polyphase\_halfband
|
||||
|
||||
a C port (from C++) of the polyphase halfband filter coefficient generator
|
||||
by [Laurent de Soras.](http://ldesoras.free.fr/index.html)
|
||||
|
||||
the original is licensed under the [WTFPL,](http://www.wtfpl.net/)
|
||||
so i'm re-licensing this under [Unlicense,](http://unlicense.org/) because i can.
|
||||
|
||||
don't read into the code too much, it's not meant to be understood (sadly).
|
||||
|
||||
### print\_tables
|
||||
|
||||
provides the `pt` Lua module for recursively dumping table contents
|
||||
into a semi-human-readable format.
|
||||
since the resulting format cannot be deserialized,
|
||||
this is primarily intended for debugging purposes,
|
||||
and i'd like to think it excels at that.
|
||||
|
||||
### response
|
||||
|
||||
some old, brief notes on biquads.
|
||||
|
||||
### rng64
|
||||
|
||||
some notes on the random number generator that Ocarina of Time
|
||||
and Majora's Mask use. don't get your hopes up about the manipulation stuff.
|
||||
|
||||
### speedrun\_comparison
|
||||
|
||||
an avisynth script for creating
|
||||
[speedrun comparison videos like this.](https://youtu.be/Y2wW5TmOzFw)
|
||||
|
||||
### starcraft\_cdkey
|
||||
|
||||
a C program to validate Starcraft 1 CD-keys.
|
||||
the original Starcraft is free now,
|
||||
so this program doesn't serve much purpose other than
|
||||
to demonstrate how *not* to write a CD-key validation routine —
|
||||
you can brute-force any key by hand just by tweaking the final digit!
|
||||
|
||||
### starcraft\_maps
|
||||
|
||||
a Python script for reading and re-writing Starcraft 1 maps,
|
||||
i.e. deprotection, or what-have-you.
|
||||
|
||||
### string\_tensions
|
||||
|
||||
Python scripts for determining optimal guitar string tensions
|
||||
for a given tuning, and similar tasks,
|
||||
backed by a database of manufacturers' strings.
|
||||
the data here is probably obsolete by now.
|
||||
|
||||
### thps1
|
||||
|
||||
a C program for exploring the "TYR" glitch in Tony Hawk's Pro Skater 1 (N64).
|
||||
|
||||
### tiny\_crc32
|
||||
|
||||
a very small C program for computing CRC-32s.
|
||||
this is a rewrite of [the code by Karl Malbrain.](http://www.geocities.ws/malbrain/crc_c.html)
|
||||
the license is ambiguous?
|
||||
|
||||
i've written [a similar routine in MIPS assembly.](https://eaguru.guru/git/notwa/mm/src/branch/master/asm/crc32.asm)
|
||||
|
||||
### trackmogrify
|
||||
|
||||
just a list of strings recognized by [Distance's](https://store.steampowered.com/app/233610/Distance/)
|
||||
trackmogrify feature. this was extracted directly from the game's memory,
|
||||
and was last updated for version 1.0.
|
||||
|
||||
### warcraft\_hash
|
||||
|
||||
a C program for the unique hashing function found in Warcraft III.
|
||||
|
||||
### warcraft\_hashes
|
||||
|
||||
a list of hashes and the source strings
|
||||
found in the game that use the aforementioned hash function.
|
||||
|
||||
### README.md
|
||||
|
||||
you're lookin' at it!
|
251
arithmetic_coding/ac_encode.py
Normal file
251
arithmetic_coding/ac_encode.py
Normal file
|
@ -0,0 +1,251 @@
|
|||
# Arithmetic coding compressor and decompressor for binary strings.
|
||||
# via: http://www.inference.org.uk/mackay/python/compress/ac/ac_encode.py
|
||||
# main page: http://www.inference.org.uk/mackay/python/compress/
|
||||
# this has been cleaned up (passes pycodestyle) and ported to python 3.
|
||||
|
||||
# default prior distribution
|
||||
BETA0 = 1
|
||||
BETA1 = 1
|
||||
|
||||
M = 30
|
||||
ONE = 1 << M
|
||||
HALF = 1 << (M - 1)
|
||||
QUARTER = 1 << (M - 2)
|
||||
THREEQU = HALF + QUARTER
|
||||
|
||||
|
||||
def clear(c, charstack):
|
||||
# print out character c, and other queued characters
|
||||
a = repr(c) + repr(1 - c) * charstack[0]
|
||||
charstack[0] = 0
|
||||
return a
|
||||
|
||||
|
||||
def encode(string, c0=BETA0, c1=BETA1, adaptive=True):
|
||||
assert c0 > 0
|
||||
assert c1 > 0
|
||||
|
||||
b = ONE
|
||||
a = 0
|
||||
if not adaptive:
|
||||
p0 = c0 / (c0 + c1)
|
||||
ans = ""
|
||||
charstack = [0] # how many undecided characters remain to print
|
||||
|
||||
for c in string:
|
||||
w = b - a
|
||||
if adaptive:
|
||||
cT = c0 + c1
|
||||
p0 = c0 / cT
|
||||
boundary = a + int(p0 * w)
|
||||
|
||||
# these warnings mean that some of the probabilities
|
||||
# requested by the probabilistic model are so small
|
||||
# (compared to our integers) that we had to round them up
|
||||
# to bigger values.
|
||||
if boundary == a:
|
||||
boundary += 1
|
||||
print("warningA")
|
||||
if boundary == b:
|
||||
boundary -= 1
|
||||
print("warningB")
|
||||
|
||||
if c == '1':
|
||||
a = boundary
|
||||
if adaptive:
|
||||
c1 += 1
|
||||
elif c == '0':
|
||||
b = boundary
|
||||
if adaptive:
|
||||
c0 += 1
|
||||
# ignore other characters
|
||||
|
||||
while a >= HALF or b <= HALF: # output bits
|
||||
if a >= HALF:
|
||||
ans += clear(1, charstack)
|
||||
a -= HALF
|
||||
b -= HALF
|
||||
else:
|
||||
ans += clear(0, charstack)
|
||||
a *= 2
|
||||
b *= 2
|
||||
|
||||
assert a <= HALF
|
||||
assert b >= HALF
|
||||
assert a >= 0
|
||||
assert b <= ONE
|
||||
|
||||
# if the gap a-b is getting small, rescale it
|
||||
while a > QUARTER and b < THREEQU:
|
||||
charstack[0] += 1
|
||||
a *= 2
|
||||
b *= 2
|
||||
a -= HALF
|
||||
b -= HALF
|
||||
|
||||
assert a <= HALF
|
||||
assert b >= HALF
|
||||
assert a >= 0
|
||||
assert b <= ONE
|
||||
|
||||
# terminate
|
||||
if HALF - a > b - HALF:
|
||||
w = HALF - a
|
||||
ans += clear(0, charstack)
|
||||
while w < HALF:
|
||||
ans += clear(1, charstack)
|
||||
w *= 2
|
||||
else:
|
||||
w = b - HALF
|
||||
ans += clear(1, charstack)
|
||||
while w < HALF:
|
||||
ans += clear(0, charstack)
|
||||
w *= 2
|
||||
|
||||
return ans
|
||||
|
||||
|
||||
def decode(string, N, c0=BETA0, c1=BETA1, adaptive=True):
|
||||
# must supply N, the number of source characters remaining.
|
||||
assert c0 > 0
|
||||
assert c1 > 0
|
||||
|
||||
b = ONE
|
||||
a = 0
|
||||
model_needs_updating = True
|
||||
if not adaptive:
|
||||
p0 = c0 / (c0 + c1)
|
||||
ans = ""
|
||||
|
||||
u = 0
|
||||
v = ONE
|
||||
for c in string:
|
||||
if N <= 0:
|
||||
break # out of the string-reading loop
|
||||
assert N > 0
|
||||
|
||||
# (u,v) is the current "encoded alphabet" binary interval,
|
||||
# and halfway is its midpoint.
|
||||
# (a,b) is the current "source alphabet" interval,
|
||||
# and boundary is the "midpoint"
|
||||
assert u >= 0
|
||||
assert v <= ONE
|
||||
halfway = u + (v - u) / 2
|
||||
if c == '1':
|
||||
u = halfway
|
||||
elif c == '0':
|
||||
v = halfway
|
||||
|
||||
# Read bits until we can decide what the source symbol was.
|
||||
# Then emulate the encoder's computations,
|
||||
# and tie (u,v) to tag along for the ride.
|
||||
while 1: # do-while
|
||||
if model_needs_updating:
|
||||
w = b - a
|
||||
if adaptive:
|
||||
cT = c0 + c1
|
||||
p0 = c0 / cT
|
||||
boundary = a + int(p0 * w)
|
||||
if boundary == a:
|
||||
boundary += 1
|
||||
print("warningA")
|
||||
if boundary == b:
|
||||
boundary -= 1
|
||||
print("warningB")
|
||||
model_needs_updating = False
|
||||
|
||||
if boundary <= u:
|
||||
ans += "1"
|
||||
if adaptive:
|
||||
c1 += 1
|
||||
a = boundary
|
||||
model_needs_updating = True
|
||||
N -= 1
|
||||
elif boundary >= v:
|
||||
ans += "0"
|
||||
if adaptive:
|
||||
c0 += 1
|
||||
b = boundary
|
||||
model_needs_updating = True
|
||||
N -= 1
|
||||
else:
|
||||
# not enough bits have yet been read to know the decision.
|
||||
pass
|
||||
|
||||
# emulate outputting of bits by the encoder,
|
||||
# and tie (u,v) to tag along for the ride.
|
||||
while a >= HALF or b <= HALF:
|
||||
if a >= HALF:
|
||||
a -= HALF
|
||||
b -= HALF
|
||||
u -= HALF
|
||||
v -= HALF
|
||||
a *= 2
|
||||
b *= 2
|
||||
u *= 2
|
||||
v *= 2
|
||||
model_needs_updating = True
|
||||
|
||||
assert a <= HALF
|
||||
assert b >= HALF
|
||||
assert a >= 0
|
||||
assert b <= ONE
|
||||
|
||||
# if the gap a-b is getting small, rescale it
|
||||
while a > QUARTER and b < THREEQU:
|
||||
a *= 2
|
||||
b *= 2
|
||||
u *= 2
|
||||
v *= 2
|
||||
a -= HALF
|
||||
b -= HALF
|
||||
u -= HALF
|
||||
v -= HALF
|
||||
|
||||
# this is the condition for this do-while loop
|
||||
if not (N > 0 and model_needs_updating):
|
||||
break
|
||||
|
||||
return ans
|
||||
|
||||
|
||||
def test():
|
||||
tests = [
|
||||
"1010",
|
||||
"111",
|
||||
"00001000000000000000",
|
||||
"1",
|
||||
"10",
|
||||
"01",
|
||||
"0",
|
||||
"0000000",
|
||||
"""
|
||||
00000000000000010000000000000000
|
||||
00000000000000001000000000000000
|
||||
00011000000
|
||||
""",
|
||||
]
|
||||
|
||||
for s in tests:
|
||||
# an ugly way to remove whitespace and newlines from the test strings:
|
||||
s = "".join(s.split())
|
||||
|
||||
N = len(s) # required for decoding later.
|
||||
print("original:", s)
|
||||
|
||||
e = encode(s, c0=10, c1=1)
|
||||
print("encoded: ", e)
|
||||
|
||||
ds = decode(e, N, c0=10, c1=1)
|
||||
print("decoded: ", ds)
|
||||
|
||||
if ds != s:
|
||||
print("FAIL")
|
||||
else:
|
||||
print("PASS")
|
||||
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
40
batch_encoding/enc.bat
Executable file
40
batch_encoding/enc.bat
Executable file
|
@ -0,0 +1,40 @@
|
|||
@ECHO OFF
|
||||
set input=%1
|
||||
set output="%~p1%~n1.fdk.mp4"
|
||||
|
||||
REM any of these can be commented out
|
||||
set trim=start=0:duration=41
|
||||
set scale=640:480
|
||||
set aspect=4:3
|
||||
set volume=24dB
|
||||
|
||||
REM -b:v 1280k + -vbr 5 ~= 10MiB/s
|
||||
set video_bitrate=-crf 23 -maxrate 2560k -bufsize 5120k
|
||||
set x264=-profile:v high -preset slow
|
||||
set fdk=-profile:a aac_he_v2 -vbr 5 -cutoff 18000
|
||||
|
||||
set general=-y -sn -dn -metadata = -map_chapters -1 -movflags +faststart
|
||||
|
||||
REM attack|right :release|right:inL/out|./...:knee:g:start:delay
|
||||
set "limA=compand=0.0050|0.0050:0.0500|0.0500:-14/-14|0/-14:0.01:0:-14:0.0052"
|
||||
set "limB=compand=0.0010|0.0010:0.0100|0.0100:-13/-13|0/-13:0.01:0:-13:0.0010"
|
||||
set "limC=compand=0.0005|0.0005:0.0100|0.0100:-12/-12|0/-12:0.01:0:-12:0.0015"
|
||||
set "limD=compand=0.0000|0.0000:0.0100|0.0100:-12/-12|0/-12"
|
||||
set "louderizer=volume=0.25,aformat=channel_layouts=stereo,asetrate=705600,%limA%,%limB%,%limC%,asetrate=44100,%limD%,volume=3.98"
|
||||
|
||||
set sanity=lowpass=18000:4,highpass=40:4
|
||||
|
||||
set vf=
|
||||
set af=
|
||||
if NOT "%scale%"=="" set "vf=%vf%,scale=%scale%"
|
||||
if NOT "%trim%"=="" set "vf=%vf%,trim=%trim%,setpts=PTS-STARTPTS"
|
||||
if NOT "%trim%"=="" set "af=%af%,atrim=%trim%,asetpts=PTS-STARTPTS"
|
||||
if NOT "%volume%"=="" set "af=%af%,asetrate=44100,volume=%volume%,%sanity%,%louderizer%"
|
||||
|
||||
if NOT "%vf%"=="" set vf=-vf "%vf:~1%"
|
||||
if NOT "%af%"=="" set af=-af "%af:~1%"
|
||||
if NOT "%aspect%"=="" set "aspect=-aspect %aspect%"
|
||||
set video=%video_bitrate% -c:v libx264 %x264% -threads 0 %aspect% %vf%
|
||||
set audio=-c:a libfdk_aac %fdk% -ar 44100 -ac 2 %af%
|
||||
|
||||
start /low /wait /b ffmpeg -i %input% %general% %video% %audio% %output%
|
54
batch_font_render/render.zsh
Normal file
54
batch_font_render/render.zsh
Normal file
|
@ -0,0 +1,54 @@
|
|||
#!/bin/zsh
|
||||
in=(**/*.(otf|ttf))
|
||||
size=16
|
||||
outdir='rendered-again'
|
||||
lipsum='Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.'
|
||||
|
||||
mkdir -p $outdir
|
||||
|
||||
flags=(-q --font $size --pixels --justify --hinting=auto)
|
||||
flags+=(--width=$((size*32)) --margin=$((size*4))\ $((size*5)))
|
||||
|
||||
cleanup() {
|
||||
rm -f $tf $out
|
||||
rm -rf $td
|
||||
exit
|
||||
}
|
||||
trap cleanup INT
|
||||
|
||||
tf=$(mktemp)
|
||||
td=$(mktemp -d)
|
||||
<<<"$lipsum">$tf
|
||||
export FONTCONFIG_PATH=$td
|
||||
|
||||
<<<'<?xml version="1.0"?>
|
||||
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||
<fontconfig>
|
||||
<dir>'$td'</dir>
|
||||
<cachedir>'$td'</cachedir>
|
||||
<include ignore_missing="yes">/etc/fonts/infinality/infinality.conf</include>
|
||||
<config></config>
|
||||
</fontconfig>
|
||||
'>>$td/fonts.conf
|
||||
|
||||
for font in ${in[@]}; do
|
||||
filename=${font:t}
|
||||
stripped=${filename:r}
|
||||
out=$outdir/$stripped.png
|
||||
[ -s $out ] && continue
|
||||
|
||||
ok=1
|
||||
cp $font $td
|
||||
pango-view ${flags[@]} -o $out $tf 2>&1 | while read -r; do
|
||||
<<<$REPLY >&2
|
||||
ok=0
|
||||
done
|
||||
[ $ok -eq 1 ] && <<<$stripped || {
|
||||
<<<$'\e[7m'$stripped$'\e[0m'
|
||||
rm -f $out
|
||||
}
|
||||
|
||||
rm -f $td/$filename $td/*.cache-4
|
||||
done
|
||||
|
||||
cleanup
|
19
danbooru_atomizer/get.py
Normal file
19
danbooru_atomizer/get.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
from retry import retry
|
||||
import requests, requests.exceptions
|
||||
|
||||
class StatusCodeError(Exception):
|
||||
def __init__(self, code, url):
|
||||
self.code = code
|
||||
self.url = url
|
||||
def __str__(self):
|
||||
return 'request for {} returned status code {}'.format(self.url, self.code)
|
||||
|
||||
@retry((requests.exceptions.ConnectionError, StatusCodeError, ValueError), tries=6, wait=300)
|
||||
def get(uri, json=False):
|
||||
r = requests.get(uri)
|
||||
if r.status_code != 200:
|
||||
raise StatusCodeError(r.status_code, uri)
|
||||
if json:
|
||||
return r.json()
|
||||
return r
|
||||
|
17
danbooru_atomizer/retry.py
Normal file
17
danbooru_atomizer/retry.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# so damn useful it deserved its own file
|
||||
|
||||
import time
|
||||
|
||||
def retry(Exceptions, tries=10, wait=1):
|
||||
if type(Exceptions) == Exception:
|
||||
Exceptions = (Exceptions,)
|
||||
def retryer(f):
|
||||
def deco(*args, **kwargs):
|
||||
for i in range(tries - 1):
|
||||
try:
|
||||
return f(*args, **kwargs)
|
||||
except Exceptions:
|
||||
time.sleep(wait)
|
||||
return f(*args, **kwargs)
|
||||
return deco
|
||||
return retryer
|
124
danbooru_atomizer/run.py
Executable file
124
danbooru_atomizer/run.py
Executable file
|
@ -0,0 +1,124 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
from urllib.parse import quote_plus
|
||||
from xml.dom.minidom import parseString as parseXML
|
||||
import datetime
|
||||
from get import get
|
||||
|
||||
lament = lambda *args, **kwargs: print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
parseDate = lambda s: datetime.datetime.strptime(s+'+0000', '%Y-%m-%dT%H:%M:%SZ%z')
|
||||
formatDate = lambda dt: dt.strftime('%FT%TZ')
|
||||
|
||||
# we only need a handful of mime types so we may as well inline them
|
||||
mimes = {
|
||||
'png': 'image/png',
|
||||
'jpg': 'image/jpeg',
|
||||
'gif': 'image/gif',
|
||||
'swf': 'application/x-shockwave-flash',
|
||||
}
|
||||
|
||||
class Untitled:
|
||||
template = """
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
</feed>
|
||||
""".strip()
|
||||
|
||||
def __init__(self, urls, max_entries=512):
|
||||
self.urls = urls
|
||||
self.max_entries = max_entries
|
||||
self.title = 'Danbooru - Personalized Feed'
|
||||
self.items = []
|
||||
|
||||
def parse(self, q):
|
||||
url = self.urls['atom'] + quote_plus(q)
|
||||
xml = get(url).text
|
||||
dom = parseXML(xml)
|
||||
|
||||
entries = dom.getElementsByTagName('entry')
|
||||
for entry in entries:
|
||||
getText = lambda tn: entry.getElementsByTagName(tn)[0].firstChild.nodeValue
|
||||
|
||||
item = {
|
||||
'title': getText('title'),
|
||||
'id': getText('id').split('/')[-1],
|
||||
'updated': getText('updated'),
|
||||
'summary': getText('summary'),
|
||||
'img': entry.getElementsByTagName('img')[0].getAttribute('src'),
|
||||
'query': q,
|
||||
}
|
||||
item['updated_unix'] = parseDate(item['updated']).timestamp()
|
||||
|
||||
self.items.append(item)
|
||||
|
||||
def generate(self):
|
||||
self.items = sorted(self.items, key=lambda d: d['updated_unix'], reverse=True)
|
||||
self.items = self.items[:self.max_entries]
|
||||
|
||||
now = formatDate(datetime.datetime.utcnow())
|
||||
|
||||
dom = parseXML(self.template)
|
||||
feed = dom.firstChild
|
||||
|
||||
def newText(entity_name, text):
|
||||
e = dom.createElement(entity_name)
|
||||
e.appendChild(dom.createTextNode(text))
|
||||
return e
|
||||
|
||||
def newLink(**kwargs):
|
||||
link = dom.createElement('link')
|
||||
for k, v in kwargs.items():
|
||||
link.setAttribute(k, v)
|
||||
return link
|
||||
|
||||
feed.appendChild(newText('title', self.title))
|
||||
feed.appendChild(newLink(href=self.urls['feed'], rel='self'))
|
||||
feed.appendChild(newText('id', self.urls['feed']))
|
||||
feed.appendChild(newText('updated', now))
|
||||
|
||||
for item in self.items:
|
||||
ext = item['img'].split('.')[-1]
|
||||
mime = mimes[ext]
|
||||
alt = self.urls['post'] + item['id']
|
||||
query_quote = quote_plus(item['query'])
|
||||
|
||||
entry = dom.createElement('entry')
|
||||
entry.appendChild(newText('title', item['title']))
|
||||
entry.appendChild(newLink(href=alt, rel="alternate"))
|
||||
entry.appendChild(newText('id', alt))
|
||||
entry.appendChild(newText('published', item['updated']))
|
||||
entry.appendChild(newText('updated', item['updated']))
|
||||
entry.appendChild(newLink(rel="enclosure", type=mime, href=item['img']))
|
||||
entry.appendChild(newText('summary', item['summary']))
|
||||
|
||||
author = dom.createElement('author')
|
||||
author.appendChild(newText('name', item['query']))
|
||||
author.appendChild(newText('uri', self.urls['query'] + query_quote))
|
||||
|
||||
entry.appendChild(author)
|
||||
|
||||
feed.appendChild(entry)
|
||||
|
||||
return dom.toxml()
|
||||
|
||||
urls = {
|
||||
'atom': 'https://danbooru.donmai.us/posts.atom?limit=48&tags=',
|
||||
'post': 'https://danbooru.donmai.us/posts/',
|
||||
'img': 'https://danbooru.donmai.us/ssd/data/preview/',
|
||||
'query': 'https://danbooru.donmai.us/posts?tags=',
|
||||
}
|
||||
|
||||
if __name__ == '__main__':
|
||||
urls['feed'] = sys.argv[1]
|
||||
|
||||
untitled = Untitled(urls)
|
||||
|
||||
queries = sys.stdin.read()
|
||||
|
||||
for q in queries.splitlines():
|
||||
lament(q)
|
||||
untitled.parse(q)
|
||||
|
||||
print(untitled.generate())
|
44
danbooru_scrape/boorufind
Executable file
44
danbooru_scrape/boorufind
Executable file
|
@ -0,0 +1,44 @@
|
|||
#!/bin/zsh
|
||||
q=$1
|
||||
url='http://danbooru.donmai.us/posts.xml'
|
||||
de=--data-urlencode
|
||||
|
||||
curl=(curl -sS -m 32 --connect-timeout 8 --retry 3 --retry-delay 1)
|
||||
|
||||
die() {
|
||||
echo -E "$@" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
push() {
|
||||
if [ -z $md5 ] || [ -z $ext ] || [ -z $size ]; then
|
||||
print missing value >&2
|
||||
return
|
||||
fi
|
||||
local fn=$md5.$ext
|
||||
local s="$(find . -name $fn -print -quit 2>/dev/null)"
|
||||
[ -n "$s" ] && print $s || print \#$fn
|
||||
md5= ext= size=
|
||||
}
|
||||
|
||||
page=1
|
||||
while; do
|
||||
once=0
|
||||
${curl[@]} -G -d limit=100 -d page=$page $de tags=$q $url \
|
||||
| xml2 2>/dev/null \
|
||||
| while IFS== read -r tree val; do
|
||||
[ $tree = /posts/post ] && push && continue
|
||||
[ ${tree:0:12} = /posts/post/ ] && tree=${tree:12} || continue
|
||||
once=1
|
||||
|
||||
case $tree in
|
||||
(md5) md5=$val ;;
|
||||
(file-ext) ext=$val ;;
|
||||
(file-size) size=$val ;;
|
||||
esac
|
||||
done
|
||||
[[ ${PIPESTATUS[1]} -eq 0 ]] || die "curl failed on page $page"
|
||||
[[ $once -eq 0 ]] && exit 0 # no posts left, well done
|
||||
push
|
||||
let page++
|
||||
done
|
40
danbooru_scrape/boorugrab
Executable file
40
danbooru_scrape/boorugrab
Executable file
|
@ -0,0 +1,40 @@
|
|||
#!/bin/zsh
|
||||
dir=$1
|
||||
url='http://danbooru.donmai.us/data/'
|
||||
|
||||
curl=(curl -sS -m 900 --connect-timeout 8 --retry 3 --retry-delay 1)
|
||||
|
||||
cleanup() {
|
||||
[ -e $dir/$md5e ] && {
|
||||
rm -f $dir/$md5e
|
||||
echo "\e[F\e[K$md5e - canceled"
|
||||
}
|
||||
exit 1
|
||||
}
|
||||
trap cleanup INT
|
||||
|
||||
mkdir -p $dir
|
||||
while read -r; do
|
||||
if [[ ${REPLY[1]} = "#" ]]; then
|
||||
md5e=${REPLY:1}
|
||||
echo "$md5e - downloading..."
|
||||
${curl[@]} $url$md5e > $dir/$md5e || {
|
||||
rm -f $dir/$md5e
|
||||
echo "\e[F\e[K$md5e - failed"
|
||||
}
|
||||
echo "\e[F\e[K$md5e - downloaded!"
|
||||
else
|
||||
md5e=${REPLY##*/}
|
||||
[ $REPLY -ef $dir/$md5e ] && {
|
||||
echo "$md5e - skipping (ef)"
|
||||
continue
|
||||
}
|
||||
[ -s $dir/$md5e ] && {
|
||||
echo "$md5e - skipping (s)"
|
||||
continue
|
||||
}
|
||||
echo "$md5e - copying..."
|
||||
cp $REPLY $dir
|
||||
echo "\e[F\e[K$md5e - copied!"
|
||||
fi
|
||||
done
|
26
debug_saves/use-debug-saves.md
Normal file
26
debug_saves/use-debug-saves.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
### how to use:
|
||||
|
||||
these gameshark cheats will override the default save file with the debug save file.
|
||||
create a new file on the file select screen and it should create a debug save.
|
||||
note: this is probably the same as using map select.
|
||||
|
||||
### MM (J) 1.0
|
||||
```
|
||||
D1142850 0C05
|
||||
D1142852 053D
|
||||
81142852 0573
|
||||
```
|
||||
|
||||
### MM (J) 1.1
|
||||
```
|
||||
D11428B0 0C05
|
||||
D11428B2 0555
|
||||
811428B2 058B
|
||||
```
|
||||
|
||||
### MM (U)
|
||||
```
|
||||
D1146AC8 0C05
|
||||
D1146ACA 1224
|
||||
81146ACA 125A
|
||||
```
|
117
desmos/desmos.md
Normal file
117
desmos/desmos.md
Normal file
|
@ -0,0 +1,117 @@
|
|||
## stuff i've plotted in desmos
|
||||
|
||||
in some order idk
|
||||
|
||||
### [circumcircle](https://www.desmos.com/calculator/zaf29i2xrk)
|
||||
|
||||
drag around the three points to see how their circumcircle is affected.
|
||||
sorry, i never finished simplifying the math here.
|
||||
|
||||
### [parabola arc length](https://www.desmos.com/calculator/hrokhmphrf)
|
||||
|
||||
not closed form, sorry. drag the points around like it's a jumprope.
|
||||
|
||||
### ["diode"](https://www.desmos.com/calculator/vappug98ky)
|
||||
|
||||
i didn't name this function; i have no idea if or how it relates to a diode.
|
||||
the red line (the line of interest) is actually just the 12th order smoothstep.
|
||||
|
||||
btw, you can find smoothstep coefficients for any order
|
||||
by the triangular table of this integer sequence:
|
||||
[OEIS A091811](http://oeis.org/A091811)
|
||||
|
||||
[punching it into wolfram][smoothie] (try changing n)
|
||||
|
||||
[smoothie]: https://www.wolframalpha.com/input/?i=ReplaceAll%5BBinomial%5Bn+%2B+k+-+2,+k+-+1%5D+Binomial%5B2+n+-+1,+n+-+k%5D,+%7Bk+-%3E+Range%5B1,n%5D%7D%5D+where+n+%3D+12
|
||||
|
||||
### [smoothstep alternatives](https://www.desmos.com/calculator/ibigyiumzb)
|
||||
|
||||
refer to shadertoy:
|
||||
|
||||
* [Inverse Smoothstep](https://www.shadertoy.com/view/MsSBRh)
|
||||
* [gain()](https://www.shadertoy.com/view/ldBfR1)
|
||||
* [Alt smoothstep](https://www.shadertoy.com/view/lsBfz1)
|
||||
|
||||
### [tanh approximation](https://www.desmos.com/calculator/k3jzkhmoid)
|
||||
|
||||
approximating tanh by taking its continued fraction form and (externally) optimizing the constants.
|
||||
probably not useful.
|
||||
|
||||
### [TanhTest lolremez approx](https://www.desmos.com/calculator/carcltkgem)
|
||||
|
||||
a polynomial approximation of a scaled tanh function
|
||||
made with [the excellent lolremez](https://github.com/samhocevar/lolremez).
|
||||
|
||||
### [e^(-2/x) approximations](https://www.desmos.com/calculator/q8jtxgnmlh)
|
||||
|
||||
i forget where i read about this but basically you can
|
||||
approximate `e^(-2/x)` by `(x-1)/(x+1)` when x is large.
|
||||
|
||||
the black line shows the absolute error.
|
||||
|
||||
### [compressor gain](https://www.desmos.com/calculator/rizrdxsrbg)
|
||||
|
||||
trying to design a cheap-to-compute gain curve for a dynamic range compressor.
|
||||
this thing uses just one division.
|
||||
iirc it didn't wind up being all that useful.
|
||||
|
||||
both axes are in power decibels. note that it acts as a gate under -70 dB.
|
||||
|
||||
### [compressor approx stuff](https://www.desmos.com/calculator/5wbup88lev)
|
||||
|
||||
trying to compute abs(x) by polynomials, or something. weird stuff.
|
||||
|
||||
### [doom turnspeeds](https://www.desmos.com/calculator/zfscpmsdbk)
|
||||
|
||||
i used this to help design turnspeed smoothing in [my zdoom patch.](https://eaguru.guru/t/zdoom_smoothstep.diff)
|
||||
|
||||
*note to self: i think i have a more recent version of that patch lying around somewhere.*
|
||||
|
||||
### [Biweight Funtimes](https://www.desmos.com/calculator/mlnqmf6ogp)
|
||||
|
||||
messing around with a variations of Tukey's Biweight?
|
||||
i think the only reason i kept this around was 'cause it's fun to watch animated.
|
||||
|
||||
### [sincmod](https://www.desmos.com/calculator/lqgl4o0naz)
|
||||
|
||||
something something windowing functions i dunno.
|
||||
|
||||
### [SGDR](https://www.desmos.com/calculator/hlgqmyswy2)
|
||||
|
||||
simple case of a [SGDR](https://arxiv.org/abs/1608.03983) curve.
|
||||
i just kept this around 'cause the logarithmic plot complements
|
||||
the linear plot in a kinda cool way.
|
||||
|
||||
### [sqr/abs generalization](https://www.desmos.com/calculator/fagjg9vuz7)
|
||||
|
||||
self-explanitory.
|
||||
|
||||
### [SELU](https://www.desmos.com/calculator/bqu264oprw)
|
||||
|
||||
[it's SELU!](https://arxiv.org/abs/1706.02515)
|
||||
|
||||
### [GELU](https://www.desmos.com/calculator/ydzgtccsld)
|
||||
|
||||
[GELU activation](https://arxiv.org/abs/1606.08415)
|
||||
alongside an approximation i lifted off reddit or someplace.
|
||||
|
||||
### [erf cdf approximations](https://www.desmos.com/calculator/22r29cude2)
|
||||
|
||||
approximate gaussian stuff, with inversions and integrals.
|
||||
|
||||
### [squish](https://www.desmos.com/calculator/1qdx4ovpb6)
|
||||
|
||||
possibly useful functions for squishing values.
|
||||
mostly based on sigmoidal functions.
|
||||
|
||||
### [sin LUT approx 2](https://www.desmos.com/calculator/zdbgkxadns)
|
||||
|
||||
approximating a quadrant of sin(x) with a polynomial and a LUT.
|
||||
|
||||
### [circle calculus](https://www.desmos.com/calculator/yd5hyagaoj)
|
||||
|
||||
some fun curves relating to unit circles.
|
||||
|
||||
### [archimedes spiral](https://www.desmos.com/calculator/63vi3wnqug)
|
||||
|
||||
it's just Archimedes' Spiral, plus some related functions.
|
82
dictionary_attack/attack.py
Normal file
82
dictionary_attack/attack.py
Normal file
|
@ -0,0 +1,82 @@
|
|||
# dead simple dictionary attack for fixed-length passwords.
|
||||
# this is far from optimal.
|
||||
|
||||
from collections import defaultdict
|
||||
import argparse
|
||||
import sys
|
||||
import random
|
||||
|
||||
program = sys.argv[0]
|
||||
args = sys.argv[1:]
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="attack: produce fixed-length strings from dictionaries")
|
||||
|
||||
parser.add_argument(
|
||||
'length', type=int,
|
||||
help="the length of the strings to output")
|
||||
parser.add_argument(
|
||||
'path', metavar='text-file', nargs='+',
|
||||
help="a dictionary file containing one string per line")
|
||||
parser.add_argument(
|
||||
'-n', metavar='limit', type=float, default='inf',
|
||||
help="output this many strings and exit")
|
||||
parser.add_argument(
|
||||
'-s', metavar='seed', type=int, default=None,
|
||||
help="use as a seed for the random number generator")
|
||||
|
||||
a = parser.parse_args(args)
|
||||
seed = a.s
|
||||
limit = a.n
|
||||
paths = a.path
|
||||
fixed_length = a.length
|
||||
del a
|
||||
|
||||
lines = []
|
||||
for path in paths:
|
||||
with open(path, "r") as f:
|
||||
for line in f:
|
||||
lines.append(line.strip('\r\n'))
|
||||
|
||||
nlines = defaultdict(lambda: [])
|
||||
ncount = defaultdict(lambda: 0)
|
||||
for line in lines:
|
||||
length = len(line)
|
||||
if length == 0 or length > fixed_length:
|
||||
continue
|
||||
nlines[length].append(line)
|
||||
ncount[length] += 1
|
||||
|
||||
del lines
|
||||
|
||||
if seed is not None:
|
||||
random.seed(seed)
|
||||
|
||||
lengths = list(ncount.keys())
|
||||
length_weights = list(ncount.values())
|
||||
|
||||
i = 0
|
||||
while i < limit:
|
||||
s = ''
|
||||
new_weights = length_weights.copy()
|
||||
|
||||
while len(s) < fixed_length:
|
||||
if len(s) > 0:
|
||||
for j, length in enumerate(lengths):
|
||||
if len(s) + length > fixed_length:
|
||||
new_weights[j] = 0
|
||||
|
||||
if sum(new_weights) == 0:
|
||||
s = ''
|
||||
new_weights = length_weights.copy()
|
||||
continue
|
||||
|
||||
chosen_length = random.choices(lengths, new_weights)[0]
|
||||
s += random.choice(nlines[chosen_length])
|
||||
|
||||
try:
|
||||
print(s)
|
||||
except OSError:
|
||||
# pipe closed.
|
||||
break
|
||||
i += 1
|
4
dnm/0017 V00744020.xxd.patch
Normal file
4
dnm/0017 V00744020.xxd.patch
Normal file
|
@ -0,0 +1,4 @@
|
|||
40c40
|
||||
< 00000270: a040 009f 3c0e 8080 25ce 32f8 240f 2410 .@..<...%.2.$.$.
|
||||
---
|
||||
> 00000270: a040 009f 3c0e 8083 25ce df6c 240f 00e0 .@..<...%..l$...
|
10
dnm/0023 V007492E0.xxd.patch
Normal file
10
dnm/0023 V007492E0.xxd.patch
Normal file
|
@ -0,0 +1,10 @@
|
|||
1011,1012c1011,1012
|
||||
< 00003f20: 910f 09f8 a100 09f9 3c01 8085 a02f 49ce ........<..../I.
|
||||
< 00003f30: 8d18 07a0 8fa7 0048 3c01 8085 0018 c82b .......H<......+
|
||||
---
|
||||
> 00003f20: 340f 0002 a100 09f9 3c01 8085 a02f 49ce 4.......<..../I.
|
||||
> 00003f30: 3418 0014 8fa7 0048 3c01 8085 0018 c82b 4......H<......+
|
||||
1057c1057
|
||||
< 00004200: 0000 0000 0c03 483d 0000 0000 1040 fff9 ......H=.....@..
|
||||
---
|
||||
> 00004200: 0000 0000 0c03 483d 0000 0000 0000 0000 ......H=........
|
10
dnm/cmd.sh
Normal file
10
dnm/cmd.sh
Normal file
|
@ -0,0 +1,10 @@
|
|||
# the patch for file 0017 (N64 logo overlay) tells it to load the Famicom overlay next
|
||||
# instead of the normal gameplay overlay. it's specified by its VRAM address and context size.
|
||||
# these values were taken from the table loaded at 80106E20 (each element is 0x30 long).
|
||||
diff <(xxd e106dff*/0017*) <(xxd dnm-instant-famicom/0017*) > '0017 V00744020.xxd.patch'
|
||||
|
||||
# the patch for file 0023 (Famicom emulator overlay) tells it to load some constant values
|
||||
# instead of loading them from a setup we never did.
|
||||
# change the "340f 0002" instruction to select a game. (0001 to 0007)
|
||||
# it also NOPs out of a loop that expects a flag to be set.
|
||||
diff <(xxd e106dff*/0023*) <(xxd dnm-instant-famicom/0023*) > '0023 V007492E0.xxd.patch'
|
238
ds1/extract_params.py
Normal file
238
ds1/extract_params.py
Normal file
|
@ -0,0 +1,238 @@
|
|||
#!/usr/bin/env python3
|
||||
import struct
|
||||
import csv
|
||||
import sys
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
Def = namedtuple("Def", "name desc notes typedef ctype pytype length bits default min max step".split(" "))
|
||||
|
||||
typemap = dict(
|
||||
s8="b",
|
||||
u8="B",
|
||||
s16="h",
|
||||
u16="H",
|
||||
s32="i",
|
||||
u32="I",
|
||||
s64="q",
|
||||
u64="Q",
|
||||
f32="f",
|
||||
f64="d",
|
||||
|
||||
dummy8="B", # note the array length typically alongside them.
|
||||
)
|
||||
|
||||
|
||||
def U(fmt, *args, **kwargs):
|
||||
return struct.unpack(E + fmt, *args, **kwargs)
|
||||
|
||||
|
||||
def trunc(s):
|
||||
if b"\0" in s:
|
||||
return s[:s.find(b"\0")]
|
||||
return s
|
||||
|
||||
|
||||
def readcstr(f, offset=None):
|
||||
if offset is not None:
|
||||
here = f.tell()
|
||||
f.seek(offset)
|
||||
|
||||
raw = b""
|
||||
while True:
|
||||
buf = f.read(16)
|
||||
if len(buf) == 0:
|
||||
break
|
||||
|
||||
if b"\0" in buf:
|
||||
raw += buf[:buf.find(b"\0")]
|
||||
break
|
||||
else:
|
||||
raw += buf
|
||||
|
||||
if offset is not None:
|
||||
f.seek(here)
|
||||
|
||||
return raw
|
||||
|
||||
|
||||
def read_paramdef(f):
|
||||
defs = []
|
||||
|
||||
filesize, unk1, unk2, count, unk3 = U("IHHHH", f.read(12))
|
||||
paramdef_title = f.read(32)
|
||||
unk4, unk5 = U("HH", f.read(4))
|
||||
|
||||
for i in range(count):
|
||||
# TODO: rename a lot of the variables here.
|
||||
|
||||
desc = f.read(64)
|
||||
typename = f.read(8)
|
||||
printformat = f.read(8)
|
||||
default, min_, max_, step = U("ffff", f.read(16))
|
||||
unk6, unk7, notes_offset = U("IIi", f.read(12))
|
||||
full_typename = f.read(32)
|
||||
name = f.read(32)
|
||||
# ID? it seems to increase by 100 sometimes.
|
||||
(unk8,) = U("I", f.read(4))
|
||||
|
||||
desc_str = trunc(desc).decode("shift-jis", errors="replace")
|
||||
type_str = trunc(full_typename).decode("shift-jis")
|
||||
name_str = trunc(name).decode("shift-jis")
|
||||
|
||||
length = None
|
||||
if "[" in name_str and "]" in name_str:
|
||||
length = int(name_str.split("[")[1].split("]")[0])
|
||||
|
||||
bits = None
|
||||
if ":" in name_str:
|
||||
bits = int(name_str.split(":")[1])
|
||||
|
||||
if type_str in typemap:
|
||||
type_ = typemap[type_str]
|
||||
else:
|
||||
underlying_type = trunc(typename).decode()
|
||||
type_ = typemap[underlying_type]
|
||||
|
||||
if notes_offset in (0, -1):
|
||||
notes_str = ""
|
||||
else:
|
||||
notes = readcstr(f, notes_offset)
|
||||
notes_str = notes.decode("shift-jis", errors="replace")
|
||||
|
||||
d = Def(name_str, desc_str, notes_str,
|
||||
type_str, trunc(typename).decode(), type_, length, bits,
|
||||
default, min_, max_, step)
|
||||
defs.append(d)
|
||||
|
||||
return paramdef_title, defs
|
||||
|
||||
|
||||
def read_param(f, paramdef_title=None):
|
||||
entries = []
|
||||
|
||||
filesize, unk1, unk2, unk3, count = U("IHHHH", f.read(12))
|
||||
param_title = f.read(32)
|
||||
if paramdef_title is not None:
|
||||
if trunc(paramdef_title) != trunc(param_title):
|
||||
raise Exception(
|
||||
"that's the wrong paramdef for this param file!" +
|
||||
f"\nexpected: {paramedef_title}\nretrieved: {param_title}")
|
||||
|
||||
unk4, unk5 = U("HH", f.read(4))
|
||||
here = f.tell()
|
||||
|
||||
for i in range(count):
|
||||
f.seek(here)
|
||||
entry_id, param_offset, notes_offset = U("iii", f.read(12))
|
||||
here = f.tell()
|
||||
f.seek(param_offset)
|
||||
|
||||
entry = [entry_id]
|
||||
prev_type = None
|
||||
for d in defs:
|
||||
is_simple = d.length is None and d.bits is None
|
||||
if d.pytype != prev_type or d.bits is None:
|
||||
buf, bufbits = 0, 0
|
||||
|
||||
# print(f"{d.pytype:24} {f.tell():X}")
|
||||
|
||||
size = struct.calcsize(d.pytype)
|
||||
if is_simple:
|
||||
(datum,) = U(d.pytype, f.read(size))
|
||||
|
||||
elif d.length is not None:
|
||||
# this only seems to be used for padding, so we can skip it.
|
||||
assert d.ctype == "dummy8" # let's assert that though.
|
||||
datum = f.read(d.length * size)
|
||||
|
||||
elif d.bits is not None:
|
||||
if bufbits == 0 or bufbits < d.bits:
|
||||
assert d.pytype not in ("f", "d")
|
||||
(buf,) = U(d.pytype.upper(), f.read(size))
|
||||
bufbits = size * 8
|
||||
|
||||
mask = (1 << d.bits) - 1
|
||||
if big_endian:
|
||||
datum = (buf >> (size * 8 - d.bits)) & mask
|
||||
buf <<= d.bits
|
||||
else:
|
||||
datum = buf & mask
|
||||
buf >>= d.bits
|
||||
bufbits -= d.bits
|
||||
|
||||
else:
|
||||
raise Exception("unhandled definition: " + name)
|
||||
|
||||
if d.ctype != "dummy8":
|
||||
entry.append(datum)
|
||||
|
||||
prev_type = d.pytype
|
||||
|
||||
if notes_offset in (0, -1):
|
||||
notes_str = ""
|
||||
else:
|
||||
notes = readcstr(f, notes_offset)
|
||||
notes_str = notes.decode("shift-jis", errors="replace")
|
||||
entry.append(notes_str)
|
||||
|
||||
entries.append(entry)
|
||||
|
||||
return param_title, entries
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) == 6:
|
||||
fp1 = sys.argv[1]
|
||||
fp2 = sys.argv[2]
|
||||
fpo = sys.argv[3]
|
||||
fph = sys.argv[4]
|
||||
# ew, nasty global:
|
||||
big_endian = sys.argv[5] == "big"
|
||||
elif len(sys.argv) == 4:
|
||||
fp1 = sys.argv[1]
|
||||
fp2 = None
|
||||
fpo = None
|
||||
fph = sys.argv[2]
|
||||
# ew, nasty global:
|
||||
big_endian = sys.argv[3] == "big"
|
||||
else:
|
||||
print("usage:")
|
||||
print(" python3 extract_params.py {paramdef in} {param in} {param out} {paramdef out} [big]")
|
||||
print(" python3 extract_params.py {paramdef in} {paramdef out} [big]")
|
||||
sys.exit(1)
|
||||
|
||||
# ew, nasty global:
|
||||
E = ">" if big_endian else "<"
|
||||
|
||||
with open(fp1, "rb") as f:
|
||||
paramdef_title, defs = read_paramdef(f)
|
||||
|
||||
if fp2 is not None and fph is not None:
|
||||
header = ["entryId"]
|
||||
for d in defs:
|
||||
name = d.name
|
||||
if ":" in name:
|
||||
name = name.split(":")[0]
|
||||
if "[" in name:
|
||||
name = name.split("[")[0]
|
||||
if d.ctype == "dummy8":
|
||||
# print("skipping", name)
|
||||
continue
|
||||
header.append(name)
|
||||
header.append("notes")
|
||||
|
||||
with open(fp2, "rb") as f:
|
||||
param_title, entries = read_param(f, paramdef_title)
|
||||
|
||||
with open(fpo, "w", newline="", encoding="utf-8") as f:
|
||||
cw = csv.writer(f, dialect="excel-tab")
|
||||
cw.writerow(header)
|
||||
for entry in entries:
|
||||
cw.writerow(entry)
|
||||
|
||||
with open(fph, "w", newline="", encoding="utf-8") as f:
|
||||
cw = csv.writer(f, dialect="excel-tab")
|
||||
cw.writerow(Def._fields)
|
||||
for d in defs:
|
||||
cw.writerow(d)
|
115
ds1/fmg_flatten.py
Normal file
115
ds1/fmg_flatten.py
Normal file
|
@ -0,0 +1,115 @@
|
|||
from struct import unpack as U
|
||||
import csv
|
||||
import sys
|
||||
|
||||
big_endian = False
|
||||
|
||||
def readint(f):
|
||||
if big_endian:
|
||||
return U(">i", f.read(4))[0]
|
||||
else:
|
||||
return U("<i", f.read(4))[0]
|
||||
|
||||
def dumpy(f, mapping):
|
||||
f.seek(0, 2)
|
||||
fsize = f.tell()
|
||||
f.seek(0, 0)
|
||||
|
||||
something = readint(f)
|
||||
assert something == 0x10000, something
|
||||
|
||||
size = readint(f)
|
||||
assert size == fsize, size
|
||||
|
||||
unk = readint(f)
|
||||
if big_endian:
|
||||
assert unk == 0x01FF0000, unk
|
||||
else:
|
||||
assert unk == 1, unk
|
||||
|
||||
count = readint(f)
|
||||
|
||||
offset_count = readint(f)
|
||||
|
||||
somecount1 = readint(f) # still unknown!
|
||||
something = readint(f) # still unknown!
|
||||
|
||||
starts = {}
|
||||
lengths = {}
|
||||
ids = []
|
||||
cumulative_length = 0
|
||||
previous_end = None
|
||||
|
||||
for i in range(count):
|
||||
if big_endian:
|
||||
a, b, c = U(">iii", f.read(4 * 3))
|
||||
else:
|
||||
a, b, c = U("<iii", f.read(4 * 3))
|
||||
#print(f"{a:10}: {b:10} to {c:10}")
|
||||
length = c - b + 1
|
||||
|
||||
assert a not in starts
|
||||
if previous_end is not None:
|
||||
assert a == previous_end
|
||||
|
||||
starts[a] = b
|
||||
lengths[a] = length
|
||||
|
||||
for i in range(length):
|
||||
ids.append(b + i)
|
||||
|
||||
cumulative_length += length
|
||||
previous_end = a + length
|
||||
|
||||
assert offset_count == cumulative_length
|
||||
|
||||
offsets = []
|
||||
for i in range(offset_count):
|
||||
offsets.append(readint(f))
|
||||
|
||||
for id, offset in zip(ids, offsets):
|
||||
if offset == 0:
|
||||
#mapping[id] = ""
|
||||
continue
|
||||
|
||||
f.seek(offset)
|
||||
string = ""
|
||||
while True:
|
||||
char = f.read(2)
|
||||
if char == b"\0\0":
|
||||
break
|
||||
if big_endian:
|
||||
string += char.decode("utf-16be")
|
||||
else:
|
||||
string += char.decode("utf-16le")
|
||||
mapping[id] = string
|
||||
|
||||
fp = sys.argv[1]
|
||||
fpo = sys.argv[2]
|
||||
|
||||
if len(sys.argv) > 3:
|
||||
big_endian = sys.argv[3] == "big"
|
||||
|
||||
en_mapping = {}
|
||||
jp_mapping = {}
|
||||
|
||||
with open(fp, "rb") as f:
|
||||
dumpy(f, en_mapping)
|
||||
|
||||
with open(fp.replace("ENGLISH", "JAPANESE"), "rb") as f:
|
||||
dumpy(f, jp_mapping)
|
||||
|
||||
from collections import defaultdict
|
||||
mappings = defaultdict(lambda: ["", ""])
|
||||
|
||||
for k, v in en_mapping.items():
|
||||
mappings[k][0] = v
|
||||
|
||||
for k, v in jp_mapping.items():
|
||||
mappings[k][1] = v
|
||||
|
||||
with open(fpo, "w", newline="", encoding="utf-8") as f:
|
||||
cw = csv.writer(f, dialect="excel-tab")
|
||||
for k in sorted(mappings.keys()):
|
||||
en_v, jp_v = mappings[k]
|
||||
cw.writerow([k, en_v, jp_v])
|
27
ds1/param_notes.py
Normal file
27
ds1/param_notes.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
from sys import argv
|
||||
from struct import unpack as U
|
||||
|
||||
big_endian = False
|
||||
if len(argv) > 2:
|
||||
big_endian = argv[2] == "big"
|
||||
|
||||
with open(argv[1], "rb") as f:
|
||||
f.seek(0xA)
|
||||
if big_endian:
|
||||
count = U(">h", f.read(2))[0]
|
||||
else:
|
||||
count = U("<h", f.read(2))[0]
|
||||
|
||||
for i in range(count):
|
||||
f.seek(0x30 + i * 3 * 4)
|
||||
|
||||
if big_endian:
|
||||
entryID, paramAddr, infoAddr = U(">iii", f.read(3 * 4))
|
||||
else:
|
||||
entryID, paramAddr, infoAddr = U("<iii", f.read(3 * 4))
|
||||
|
||||
if infoAddr not in (0, -1):
|
||||
f.seek(infoAddr)
|
||||
string = f.read()
|
||||
string = string[:string.index(b"\0")]
|
||||
print(entryID, string.decode("shift-jis", errors="replace"), sep="\t")
|
22
dwarf_font/dwarf.lua
Normal file
22
dwarf_font/dwarf.lua
Normal file
|
@ -0,0 +1,22 @@
|
|||
-- This is free and unencumbered software released into the public domain.
|
||||
-- For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
local charset = ("\
|
||||
\x00☺☻♥♦♣♠•◘○◙♂♀♪♫☼\
|
||||
►◄↕‼¶§▬↨↑↓→←∟↔▲▼\
|
||||
!\"#$%&'()*+,-./\
|
||||
0123456789:;<=>?\
|
||||
@ABCDEFGHIJKLMNO\
|
||||
PQRSTUVWXYZ[\\]^_\
|
||||
`abcdefghijklmno\
|
||||
pqrstuvwxyz{|}~⌂\
|
||||
ÇüéâäàåçêëèïîìÄÅ\
|
||||
ÉæÆôöòûùÿÖÜ¢£¥₧ƒ\
|
||||
áíóúñѪº¿⌐¬½¼¡«»\
|
||||
░▒▓│┤╡╢╖╕╣║╗╝╜╛┐\
|
||||
└┴┬├─┼╞╟╚╔╩╦╠═╬╧\
|
||||
╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀\
|
||||
αßΓπΣσµτΦΘΩδ∞φε∩\
|
||||
≡±≥≤⌠⌡÷≈°∙·√ⁿ²■<EFBFBD>"):gsub('\n', '')
|
||||
|
||||
return love.graphics.newImageFont("dwarf.png", charset)
|
BIN
dwarf_font/dwarf.png
Normal file
BIN
dwarf_font/dwarf.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
239
filter_tutorial/filter_example.py
Normal file
239
filter_tutorial/filter_example.py
Normal file
|
@ -0,0 +1,239 @@
|
|||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import scipy.signal as sig
|
||||
|
||||
# optionally, use an alternate style for plotting.
|
||||
# this reconfigures colors, fonts, padding, etc.
|
||||
# i personally prefer the look of ggplot, but the contrast is generally worse.
|
||||
plt.style.use('ggplot')
|
||||
|
||||
# create log-spaced points from 20 to 20480 Hz.
|
||||
# we'll compute our y values using these later.
|
||||
# increasing precision will result in a smoother plot.
|
||||
precision = 4096
|
||||
xs = np.arange(0, precision) / precision
|
||||
xs = 20 * 1024**xs
|
||||
|
||||
# decide on a sample-rate and a center-frequency (the -3dB point).
|
||||
fs = 44100
|
||||
fc = 1000
|
||||
|
||||
|
||||
def response_setup(ax, ymin=-24, ymax=24, major_ticks_every=6, minor_ticks_split=2):
|
||||
"""configure axes for magnitude plotting within the range of human hearing."""
|
||||
ax.set_xlim(20, 20000)
|
||||
ax.set_ylim(ymin, ymax)
|
||||
ax.grid(True, 'both') # enable major and minor gridlines on both axes
|
||||
ax.set_xlabel('frequency (Hz)')
|
||||
ax.set_ylabel('magnitude (dB)')
|
||||
# manually set y tick positions.
|
||||
# this is usually better than relying on matplotlib to choose good values.
|
||||
from matplotlib import ticker
|
||||
ax.set_yticks(tuple(range(ymin, ymax + 1, major_ticks_every)))
|
||||
minor_ticker = ticker.AutoMinorLocator(minor_ticks_split)
|
||||
ax.yaxis.set_minor_locator(minor_ticker)
|
||||
|
||||
|
||||
def modified_bilinear(b, a, w0):
|
||||
"""
|
||||
the modified bilinear transform defers specifying the center frequency
|
||||
of an analog filter to the conversion to a digital filter:
|
||||
this s-plane to z-plane transformation.
|
||||
it also compensates for the frequency-warping effect.
|
||||
|
||||
b and a are the normalized numerator and denominator coefficients (respectively)
|
||||
of the polynomial in the s-plane, and w0 is the angular center frequency.
|
||||
effectively, w0 = 2 * pi * fc / fs.
|
||||
|
||||
the modified bilinear transform is specified by RBJ [1] as:
|
||||
s := (1 - z^-1) / (1 + z^-1) / tan(w0 / 2)
|
||||
as opposed to the traditional bilinear transform:
|
||||
s := (1 - z^-1) / (1 + z^-1)
|
||||
|
||||
[1]: http://musicdsp.org/files/Audio-EQ-Cookbook.txt
|
||||
"""
|
||||
|
||||
# in my opinion, this is a more convenient way of creating digital filters.
|
||||
# scipy doesn't implement the modified bilinear transform,
|
||||
# so i'll just write the expanded form for second-order filters here.
|
||||
# TODO: include the equation that expanded/simplified to this
|
||||
|
||||
# use padding to allow for first-order filters.
|
||||
# untested
|
||||
if len(b) == 2:
|
||||
b = (b[0], b[1], 0)
|
||||
if len(a) == 2:
|
||||
a = (a[0], a[1], 0)
|
||||
|
||||
assert len(b) == 3 and len(a) == 3, "unsupported order of filter"
|
||||
|
||||
cw = np.cos(w0)
|
||||
sw = np.sin(w0)
|
||||
zb = np.array((
|
||||
b[0]*(1 - cw) + b[2]*(1 + cw) - b[1]*sw,
|
||||
2*(b[0]*(1 - cw) - b[2]*(1 + cw)),
|
||||
b[0]*(1 - cw) + b[2]*(1 + cw) + b[1]*sw,
|
||||
))
|
||||
za = np.array((
|
||||
a[0]*(1 - cw) + a[2]*(1 + cw) - a[1]*sw,
|
||||
2*(a[0]*(1 - cw) - a[2]*(1 + cw)),
|
||||
a[0]*(1 - cw) + a[2]*(1 + cw) + a[1]*sw,
|
||||
))
|
||||
return zb, za
|
||||
|
||||
|
||||
def digital_magnitude(xs, cascade, fc, fs, decibels=True):
|
||||
"""
|
||||
compute the digital magnitude response
|
||||
of an analog SOS filter (cascade)
|
||||
at the points given at xs
|
||||
and the center frequency fc
|
||||
for the sampling rate of fs.
|
||||
"""
|
||||
|
||||
to_magnitude_decibels = lambda x: np.real(np.log10(np.abs(x)**2) * 10)
|
||||
|
||||
# compute angular frequencies
|
||||
ws = 2 * np.pi * xs / fs
|
||||
w0 = 2 * np.pi * fc / fs
|
||||
|
||||
digital_cascade = [modified_bilinear(*ba, w0=w0) for ba in cascade]
|
||||
|
||||
# we don't need the first result freqz returns
|
||||
# because it'll just be the worN we're passing.
|
||||
responses = [sig.freqz(*ba, worN=ws)[1] for ba in digital_cascade]
|
||||
|
||||
if decibels:
|
||||
mags = [to_magnitude_decibels(response) for response in responses]
|
||||
mags = np.array(mags)
|
||||
composite = np.sum(mags, axis=0)
|
||||
else:
|
||||
# untested
|
||||
mags = [np.abs(response) for response in responses]
|
||||
mags = np.array(mags)
|
||||
composite = np.prod(mags, axis=0)
|
||||
|
||||
# we could also compute phase using (untested):
|
||||
# -np.arctan2(np.imag(response), np.real(response))
|
||||
|
||||
return composite, mags
|
||||
|
||||
|
||||
# compute the butterworth coefficients for later.
|
||||
# we'll request them in SOS format: second-order sections.
|
||||
# that means we'll get an array of second-order filters
|
||||
# that combine to produce one higher-order filter.
|
||||
# note that we specify 1 as the frequency; we'll give the actual frequency
|
||||
# later, when we transform it to a digital filter.
|
||||
butterworth_2 = sig.butter(N=2, Wn=1, analog=True, output='sos')
|
||||
butterworth_6 = sig.butter(N=6, Wn=1, analog=True, output='sos')
|
||||
# scipy returns the b and a coefficients in a flat array,
|
||||
# but we need them separate.
|
||||
butterworth_2 = butterworth_2.reshape(-1, 2, 3)
|
||||
butterworth_6 = butterworth_6.reshape(-1, 2, 3)
|
||||
butterworth_2_times3 = butterworth_2.repeat(3, axis=0)
|
||||
|
||||
|
||||
# set up our first plot.
|
||||
fig, ax = plt.subplots()
|
||||
response_setup(ax, -30, 3)
|
||||
ax.set_title("comparison of digital butterworth filters (fc=1kHz, fs=44.1kHz)")
|
||||
|
||||
# compute the magnitude of the filters at our x positions.
|
||||
# we don't want the individual magnitudes here,
|
||||
# so assign them to the dummy variable _.
|
||||
ys1, _ = digital_magnitude(xs, butterworth_2, fc, fs)
|
||||
ys2, _ = digital_magnitude(xs, butterworth_2_times3, fc, fs)
|
||||
ys3, _ = digital_magnitude(xs, butterworth_6, fc, fs)
|
||||
|
||||
# our x axis is frequency, so it should be spaced logarithmically.
|
||||
# our y axis is decibels, which is already a logarithmic unit.
|
||||
# thus, semilogx is the plotting function to use here.
|
||||
ax.semilogx(xs, ys1, label="second order")
|
||||
ax.semilogx(xs, ys2, label="second order, three times")
|
||||
ax.semilogx(xs, ys3, label="sixth order")
|
||||
|
||||
ax.legend() # display the legend, given by labels when plotting.
|
||||
fig.show()
|
||||
fig.savefig('butterworth_comparison.png')
|
||||
|
||||
|
||||
# set up our second plot.
|
||||
fig, ax = plt.subplots()
|
||||
response_setup(ax, -12, 12)
|
||||
ax.set_title("digital butterworth decomposition (fc=1kHz, fs=44.1kHz)")
|
||||
|
||||
cascade = butterworth_6
|
||||
composite, mags = digital_magnitude(xs, cascade, fc, fs)
|
||||
for i, mag in enumerate(mags):
|
||||
# Q has an inverse relation to the 1st-degree coefficient
|
||||
# of the analog filter's denominator, so we can compute it that way.
|
||||
Q = 1 / cascade[i][1][1]
|
||||
ax.semilogx(xs, mag, label="second order (Q = {:.6f})".format(Q))
|
||||
ax.semilogx(xs, composite, label="composite")
|
||||
|
||||
ax.legend()
|
||||
fig.show()
|
||||
fig.savefig('butterworth_composite.png')
|
||||
|
||||
|
||||
# as a bonus, here's how the modified bilinear transform is especially useful:
|
||||
# we can specify all the basic second-order analog filter types
|
||||
# with minimal code!
|
||||
|
||||
lowpass2 = lambda A, Q: ((1, 0, 0),
|
||||
(1, 1/Q, 1))
|
||||
highpass2 = lambda A, Q: ((0, 0, 1),
|
||||
(1, 1/Q, 1))
|
||||
|
||||
allpass2 = lambda A, Q: ((1, 1/Q, 1),
|
||||
(1, 1/Q, 1))
|
||||
|
||||
# peaking filters are also (perhaps for the better) known as bell filters.
|
||||
peaking2 = lambda A, Q: ((1, A/Q, 1),
|
||||
(1, 1/A/Q, 1))
|
||||
# TODO: add classical "analog" peaking filter, where bandwidth and amplitude are interlinked
|
||||
|
||||
# there are two common bandpass variants:
|
||||
# one where the bandwidth and amplitude are interlinked,
|
||||
bandpass2a = lambda A, Q: ((0, -A/Q, 0),
|
||||
(1, 1/A/Q, 1))
|
||||
# and one where they aren't.
|
||||
bandpass2b = lambda A, Q: ((0,-A*A/Q, 0),
|
||||
(1, 1/Q, 1))
|
||||
|
||||
notch2 = lambda A, Q: ((1, 0, 1),
|
||||
(1, 1/Q, 1))
|
||||
|
||||
lowshelf2 = lambda A, Q: (( A, np.sqrt(A)/Q, 1),
|
||||
(1/A, 1/np.sqrt(A)/Q, 1))
|
||||
|
||||
highshelf2 = lambda A, Q: ((1, np.sqrt(A)/Q, A),
|
||||
(1, 1/np.sqrt(A)/Q, 1/A))
|
||||
|
||||
|
||||
# here's an example of how to plot these.
|
||||
# we specify the gain in decibels and bandwidth in octaves,
|
||||
# then convert these to A and Q.
|
||||
fig, ax = plt.subplots()
|
||||
response_setup(ax, -30, 30)
|
||||
|
||||
invsqrt2 = 1 / np.sqrt(2) # for bandwidth <-> Q calculation
|
||||
# note that A is squared, so the decibel math here is a little different.
|
||||
designer = lambda f, decibels, bandwidth: f(10**(decibels / 40.), invsqrt2 / bandwidth)
|
||||
|
||||
ax.set_title("example of interlinked bandpass amplitude/bandwidth")
|
||||
cascade = [
|
||||
designer(bandpass2a, 0, 2),
|
||||
designer(bandpass2a, -18, 2),
|
||||
designer(bandpass2a, 18, 2),
|
||||
]
|
||||
|
||||
composite, mags = digital_magnitude(xs, cascade, fc, fs)
|
||||
for mag in mags:
|
||||
ax.semilogx(xs, mag)
|
||||
#ax.semilogx(xs, composite)
|
||||
|
||||
#ax.legend()
|
||||
fig.show()
|
||||
fig.savefig('filter_example.png')
|
136
image_deduplication/idup.py
Normal file
136
image_deduplication/idup.py
Normal file
|
@ -0,0 +1,136 @@
|
|||
#!/usr/bin/env python3
|
||||
# find duplicate images given a hamming distance threshold.
|
||||
# employs dhash to do the heavy lifting.
|
||||
# doesn't recurse into "./_duplicate/" so you can dump things there if you wish.
|
||||
# dependencies: pillow, dhash
|
||||
|
||||
import sys, os, os.path, pickle
|
||||
from PIL import Image
|
||||
import dhash
|
||||
|
||||
def lament(*args, **kwargs):
|
||||
print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
def result(diff, p1, p2): # TODO: rename
|
||||
print("{}\t{}\t{}".format(diff, p1, p2))
|
||||
|
||||
dbname = "idup.db"
|
||||
exts = ".jpeg .jpg .png".split()
|
||||
|
||||
rootpath = "."
|
||||
ignore_dir = os.path.join(rootpath, "_duplicate")
|
||||
|
||||
"""verbosity:
|
||||
-1: only unrecoverable errors.
|
||||
0: include failures.
|
||||
1: include image opening/hashing.
|
||||
2: the kitchen sink.
|
||||
"""
|
||||
verbosity = 1
|
||||
|
||||
pname = sys.argv[0]
|
||||
if len(sys.argv) <= 1:
|
||||
print("usage: {} {{threshold}}".format(pname))
|
||||
print(" utilizes {} in the current working directory".format(dbname))
|
||||
sys.exit(1)
|
||||
args = sys.argv[1:]
|
||||
|
||||
threshold = int(args[0])
|
||||
|
||||
paths = {} # path to hash mapping.
|
||||
|
||||
if os.path.exists(dbname) and os.path.getsize(dbname) > 0:
|
||||
with open(dbname, "rb") as f:
|
||||
paths = pickle.load(f)
|
||||
#lament("loaded", len(paths.keys()), "hashes")
|
||||
else:
|
||||
if verbosity >= 0:
|
||||
lament("warning: no database found. starting from scratch.")
|
||||
|
||||
existing = dict((path, h) for path, h in paths.items() if os.path.exists(path))
|
||||
for path in paths.keys():
|
||||
if path not in existing:
|
||||
if verbosity >= 0:
|
||||
lament("#d", path)
|
||||
|
||||
paths = existing
|
||||
|
||||
def compare_hash(h1, h2):
|
||||
# hashes are in byte strings, so we have to convert them to integers.
|
||||
i1 = int.from_bytes(h1, byteorder="big")
|
||||
i2 = int.from_bytes(h2, byteorder="big")
|
||||
# return the hamming distance.
|
||||
return bin(i1 ^ i2).count('1')
|
||||
|
||||
def run():
|
||||
for dn, _, fns in os.walk(rootpath):
|
||||
if dn == ignore_dir:
|
||||
continue
|
||||
|
||||
for fn in fns:
|
||||
name, ext = os.path.splitext(fn)
|
||||
path = os.path.join(dn, fn)
|
||||
if ext not in exts:
|
||||
continue
|
||||
|
||||
if path in paths:
|
||||
if verbosity >= 2:
|
||||
lament("#s", path)
|
||||
continue
|
||||
|
||||
try:
|
||||
image = Image.open(path)
|
||||
except OSError:
|
||||
if verbosity >= 0:
|
||||
lament("#f", path)
|
||||
else:
|
||||
try:
|
||||
row, col = dhash.dhash_row_col(image)
|
||||
except OSError:
|
||||
if verbosity >= 0:
|
||||
lament("#f", path)
|
||||
else:
|
||||
if verbosity >= 1:
|
||||
lament("#o", path)
|
||||
h = dhash.format_bytes(row, col)
|
||||
paths[path] = h
|
||||
finally:
|
||||
image.close()
|
||||
|
||||
# first pass: exact hash matching.
|
||||
hashes = dict((v, k) for k, v in paths.items())
|
||||
for p1, h in paths.items():
|
||||
p2 = hashes[h]
|
||||
if p1 != p2:
|
||||
result(-1, p1, p2)
|
||||
|
||||
# second pass: fuzzy hash matching.
|
||||
if threshold <= 0:
|
||||
return
|
||||
seen = set()
|
||||
for p1, h1 in paths.items():
|
||||
if verbosity >= 2:
|
||||
lament("#c", p1)
|
||||
seen.add(p1)
|
||||
for p2, h2 in paths.items():
|
||||
if p2 in seen:
|
||||
continue
|
||||
if h1 == h2:
|
||||
continue
|
||||
diff = compare_hash(h1, h2)
|
||||
if diff <= threshold:
|
||||
result(diff, p1, p2)
|
||||
|
||||
try:
|
||||
run()
|
||||
except KeyboardInterrupt:
|
||||
if verbosity >= 0:
|
||||
lament("# interrupted")
|
||||
finally:
|
||||
if os.path.exists(dbname):
|
||||
backup = dbname+".bak"
|
||||
if os.path.exists(backup):
|
||||
os.remove(backup)
|
||||
os.rename(dbname, dbname+".bak")
|
||||
with open(dbname, "wb") as f:
|
||||
pickle.dump(paths, f)
|
314
kill_reboot/elevate.ps1
Normal file
314
kill_reboot/elevate.ps1
Normal file
|
@ -0,0 +1,314 @@
|
|||
# this is a very stripped-down C# port of NSudo:
|
||||
# https://github.com/M2Team/NSudo
|
||||
# you should already be running this script as an administrator.
|
||||
|
||||
param([string]$command="cmd")
|
||||
|
||||
function Execute-Elevated {
|
||||
param([string]$command="cmd")
|
||||
|
||||
$Definition = @"
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Diagnostics;
|
||||
|
||||
public class Dummy {
|
||||
const int CREATE_NO_WINDOW = 0x8000000;
|
||||
const int CREATE_UNICODE_ENVIRONMENT = 0x400;
|
||||
const int MAXIMUM_ALLOWED = 0x2000000;
|
||||
const int PROCESS_QUERY_INFORMATION = 0x400;
|
||||
const int SE_PRIVILEGE_ENABLED = 0x2;
|
||||
const int SecurityImpersonation = 2;
|
||||
const int TOKEN_QUERY = 0x8;
|
||||
const int TokenPrimary = 1;
|
||||
const int TokenImpersonation = 2;
|
||||
const int TokenUser = 1;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SID_AND_ATTRIBUTES {
|
||||
public IntPtr Sid;
|
||||
public int Attributes;
|
||||
}
|
||||
|
||||
public struct TOKEN_USER {
|
||||
public SID_AND_ATTRIBUTES User;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct LUID {
|
||||
public UInt32 LowPart;
|
||||
public Int32 HighPart;
|
||||
}
|
||||
|
||||
// hack to make a simple TOKEN_PRIVILEGES struct when Count=1.
|
||||
[StructLayout(LayoutKind.Sequential, Pack=1)]
|
||||
public struct TokenPrivilegeSingle {
|
||||
public int Count;
|
||||
public LUID Luid;
|
||||
public uint Attr;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
|
||||
public struct STARTUPINFOW {
|
||||
public int cb;
|
||||
public string lpReserved;
|
||||
public string lpDesktop;
|
||||
public string lpTitle;
|
||||
public uint dwX;
|
||||
public uint dwY;
|
||||
public uint dwXSize;
|
||||
public uint dwYSize;
|
||||
public uint dwXCountChars;
|
||||
public uint dwYCountChars;
|
||||
public uint dwFillAttribute;
|
||||
public uint dwFlags;
|
||||
public ushort wShowWindow;
|
||||
public ushort cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct PROCESS_INFORMATION {
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public int dwProcessId;
|
||||
public int dwThreadId;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern IntPtr LocalFree(
|
||||
IntPtr hMem);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
static extern bool CloseHandle(
|
||||
IntPtr hHandle);
|
||||
|
||||
[DllImport("userenv.dll", SetLastError=true)]
|
||||
static extern bool CreateEnvironmentBlock(
|
||||
out IntPtr lpEnvironment,
|
||||
IntPtr hToken, bool bInherit);
|
||||
|
||||
[DllImport("userenv.dll", SetLastError=true)]
|
||||
static extern bool DestroyEnvironmentBlock(
|
||||
IntPtr lpEnvironment);
|
||||
|
||||
[DllImport("advapi32", CharSet=CharSet.Auto, SetLastError=true)]
|
||||
static extern bool ConvertSidToStringSid(
|
||||
IntPtr pSID,
|
||||
out IntPtr ptrSid);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
static extern IntPtr OpenProcess(
|
||||
int dwDesiredAccess,
|
||||
bool bInheritHandle,
|
||||
long dwProcessId);
|
||||
|
||||
[DllImport("advapi32.dll", ExactSpelling=true, SetLastError=true)]
|
||||
static extern bool OpenProcessToken(
|
||||
IntPtr h,
|
||||
int acc,
|
||||
out IntPtr phtok);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
private static extern bool SetThreadToken(
|
||||
IntPtr pHandle,
|
||||
IntPtr hToken);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError=true)]
|
||||
static extern bool GetTokenInformation(
|
||||
IntPtr TokenHandle,
|
||||
int TokenInformationClass,
|
||||
IntPtr TokenInformation,
|
||||
int TokenInformationLength,
|
||||
out int ReturnLength);
|
||||
|
||||
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
|
||||
static extern bool DuplicateTokenEx(
|
||||
IntPtr hExistingToken,
|
||||
uint dwDesiredAccess,
|
||||
IntPtr lpTokenAttributes,
|
||||
int ImpersonationLevel,
|
||||
int TokenType,
|
||||
out IntPtr phNewToken);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
|
||||
static extern bool CreateProcessAsUserW(
|
||||
IntPtr hToken,
|
||||
string lpApplicationName,
|
||||
string lpCommandLine,
|
||||
IntPtr lpProcessAttributes,
|
||||
IntPtr lpThreadAttributes,
|
||||
bool bInheritHandles,
|
||||
uint dwCreationFlags,
|
||||
IntPtr lpEnvironment,
|
||||
string lpCurrentDirectory,
|
||||
ref STARTUPINFOW lpStartupInfo,
|
||||
out PROCESS_INFORMATION lpProcessInformation);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
static extern bool AdjustTokenPrivileges(
|
||||
IntPtr TokenHandle,
|
||||
bool DisableAllPrivileges,
|
||||
ref TokenPrivilegeSingle NewState,
|
||||
uint Zero,
|
||||
IntPtr Null1,
|
||||
IntPtr Null2);
|
||||
|
||||
public static string ConvertSidToStringSid(IntPtr sid) {
|
||||
IntPtr pstr = IntPtr.Zero;
|
||||
bool ok = ConvertSidToStringSid(sid, out pstr);
|
||||
if (!ok) {
|
||||
LocalFree(pstr);
|
||||
throw new Exception("ConvertSidToStringSid: not ok");
|
||||
}
|
||||
string sidstr = Marshal.PtrToStringAuto(pstr);
|
||||
LocalFree(pstr);
|
||||
return sidstr;
|
||||
}
|
||||
|
||||
public static bool HasPrivileges(int pid) {
|
||||
bool ok = true;
|
||||
IntPtr hProc = OpenProcess(PROCESS_QUERY_INFORMATION, false, pid);
|
||||
if (hProc == IntPtr.Zero) throw new Exception("OpenProcess: null");
|
||||
IntPtr hToken = IntPtr.Zero;
|
||||
ok = OpenProcessToken(hProc, TOKEN_QUERY, out hToken);
|
||||
if (!ok || hToken == IntPtr.Zero) throw new Exception("OpenProcessToken: not ok or null");
|
||||
|
||||
int tiLength = -1;
|
||||
GetTokenInformation(hToken, TokenUser, IntPtr.Zero, 0, out tiLength);
|
||||
IntPtr ti = Marshal.AllocHGlobal(tiLength);
|
||||
ok = GetTokenInformation(hToken, TokenUser, ti, tiLength, out tiLength);
|
||||
if (!ok) {
|
||||
Marshal.FreeHGlobal(ti);
|
||||
throw new Exception("GetTokenInformation: not ok");
|
||||
}
|
||||
|
||||
TOKEN_USER tokenUser = (TOKEN_USER)Marshal.PtrToStructure(ti, typeof(TOKEN_USER));
|
||||
string sidstr = ConvertSidToStringSid(tokenUser.User.Sid);
|
||||
|
||||
return sidstr == "S-1-5-18"; // described as "Local System"
|
||||
}
|
||||
|
||||
public static int FindSystemPid(string processName) {
|
||||
Process currentProc = Process.GetCurrentProcess();
|
||||
Process[] processes = Process.GetProcessesByName(processName);
|
||||
int pid = -1;
|
||||
foreach (Process proc in processes) {
|
||||
if (currentProc.SessionId == proc.SessionId && HasPrivileges(proc.Id)) {
|
||||
pid = proc.Id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pid == -1) throw new Exception("FindSystemPid: couldn't find " + processName);
|
||||
return pid;
|
||||
}
|
||||
|
||||
public static IntPtr DuplicateProcessToken(int pid, int impLevel, int tokenType) {
|
||||
// desiredAccess is always MAXIMUM_ALLOWED
|
||||
// lpTokenAttributes is always null (IntPtr.Zero)
|
||||
bool ok = true;
|
||||
IntPtr hProc = OpenProcess(MAXIMUM_ALLOWED, false, pid);
|
||||
if (hProc == IntPtr.Zero) throw new Exception("OpenProcess: null");
|
||||
|
||||
IntPtr hToken = IntPtr.Zero;
|
||||
ok = OpenProcessToken(hProc, MAXIMUM_ALLOWED, out hToken);
|
||||
if (!ok || hToken == IntPtr.Zero) throw new Exception("OpenProcessToken: not ok or null");
|
||||
|
||||
IntPtr phToken = IntPtr.Zero;
|
||||
ok = DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, IntPtr.Zero,
|
||||
impLevel, tokenType,
|
||||
out phToken);
|
||||
if (!ok || phToken == IntPtr.Zero) throw new Exception("DuplicateTokenEx: not ok or null");
|
||||
|
||||
return phToken;
|
||||
}
|
||||
|
||||
public static void CreateProcessW(IntPtr hToken, IntPtr environment, string directory,
|
||||
string comSpec, string command) {
|
||||
bool ok = true;
|
||||
|
||||
STARTUPINFOW startupInfo = new STARTUPINFOW();
|
||||
PROCESS_INFORMATION processInfo = new PROCESS_INFORMATION();
|
||||
|
||||
startupInfo.cb = Marshal.SizeOf(startupInfo);
|
||||
startupInfo.lpDesktop = "WinSta0\\Default";
|
||||
|
||||
ok = CreateProcessAsUserW(hToken, comSpec, command,
|
||||
IntPtr.Zero, IntPtr.Zero, false,
|
||||
CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
|
||||
environment, directory,
|
||||
ref startupInfo, out processInfo);
|
||||
|
||||
if (!ok) {
|
||||
int err = Marshal.GetLastWin32Error();
|
||||
CloseHandle(processInfo.hProcess);
|
||||
CloseHandle(processInfo.hThread);
|
||||
throw new Exception("CreateProcessAsUser failure: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr CreateEnvironment(IntPtr hToken) {
|
||||
bool ok = true;
|
||||
IntPtr environment;
|
||||
ok = CreateEnvironmentBlock(out environment, hToken, true);
|
||||
if (!ok || environment == IntPtr.Zero) throw new Exception("CreateEnvironmentBlock: not ok or null");
|
||||
return environment;
|
||||
}
|
||||
|
||||
public static void SetTokenAllPrivileges(IntPtr hToken, bool enable) {
|
||||
// turns out the only one we need is 3: SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
|
||||
bool ok = true;
|
||||
|
||||
TokenPrivilegeSingle tp = new TokenPrivilegeSingle();
|
||||
tp.Count = 1;
|
||||
tp.Attr = (uint)(enable ? SE_PRIVILEGE_ENABLED : 0);
|
||||
tp.Luid.LowPart = 3;
|
||||
|
||||
ok = AdjustTokenPrivileges(hToken, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
|
||||
if (!ok) throw new Exception("AdjustTokenPrivileges: not ok");
|
||||
|
||||
int err = Marshal.GetLastWin32Error();
|
||||
if (err != 0) throw new Exception("AdjustTokenPrivileges failure: " + err);
|
||||
}
|
||||
|
||||
public static void Execute(string comSpec, string command) {
|
||||
bool ok = true;
|
||||
|
||||
IntPtr hTokenSelf;
|
||||
|
||||
ok = OpenProcessToken((IntPtr)(-1), MAXIMUM_ALLOWED, out hTokenSelf);
|
||||
if (!ok || hTokenSelf == IntPtr.Zero) throw new Exception("OpenProcessToken: not ok or null");
|
||||
|
||||
IntPtr environment = CreateEnvironment(hTokenSelf);
|
||||
|
||||
int pid = FindSystemPid("winlogon");
|
||||
Console.WriteLine("winlogon PID: " + pid);
|
||||
|
||||
IntPtr hTokenSystemImpersonate = DuplicateProcessToken(pid, SecurityImpersonation, TokenImpersonation);
|
||||
|
||||
SetTokenAllPrivileges(hTokenSystemImpersonate, true);
|
||||
ok = SetThreadToken(IntPtr.Zero, hTokenSystemImpersonate);
|
||||
if (!ok) throw new Exception("SetThreadToken: not ok");
|
||||
|
||||
IntPtr hTokenSystemPrimary = DuplicateProcessToken(pid, SecurityImpersonation, TokenPrimary);
|
||||
|
||||
string fullCommand = "/c start \"" + comSpec + "\" " + command;
|
||||
Console.WriteLine(comSpec + " " + fullCommand);
|
||||
|
||||
CreateProcessW(hTokenSystemPrimary, environment, null, comSpec, fullCommand);
|
||||
|
||||
// TODO: always clean up regardless of exceptions.
|
||||
DestroyEnvironmentBlock(environment);
|
||||
}
|
||||
}
|
||||
"@
|
||||
|
||||
$type = Add-Type $definition -PassThru
|
||||
$type[0]::Execute((get-item env:"ComSpec").Value, $command)
|
||||
}
|
||||
|
||||
Execute-Elevated $command
|
||||
exit
|
32
kill_reboot/kill-reboot.cmd
Normal file
32
kill_reboot/kill-reboot.cmd
Normal file
|
@ -0,0 +1,32 @@
|
|||
@echo off
|
||||
set debug=0
|
||||
|
||||
set ps_reg="HKCU\Software\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell"
|
||||
|
||||
rem check if the key already exists.
|
||||
reg query %ps_reg% /v ExecutionPolicy >nul 2>&1
|
||||
if NOT %errorLevel% == 0 (
|
||||
rem set it just high enough so we can run our script.
|
||||
reg add %ps_reg% /t REG_SZ /v ExecutionPolicy /d RemoteSigned
|
||||
)
|
||||
|
||||
rem check if we're at least running as an admin.
|
||||
net session >nul 2>&1
|
||||
if NOT %errorLevel% == 0 (
|
||||
rem re-run this script as system.
|
||||
rem that's more than administrator, but less than trusted installer.
|
||||
if "%debug%"=="1" (
|
||||
powershell -Command "Start-Process powershell {%~dp0\elevate.ps1 %0} -Verb RunAs"
|
||||
) else (
|
||||
rem this version bypasses UAC. please refer to the following post:
|
||||
rem https://tyranidslair.blogspot.ca/2017/05/exploiting-environment-variables-in.html
|
||||
reg add hkcu\Environment /v windir /d "cmd /K reg delete hkcu\Environment /v windir /f && powershell -WindowStyle Hidden -NonInteractive %~dp0\elevate.ps1 %0 && REM "
|
||||
)
|
||||
schtasks /Run /TN \Microsoft\Windows\DiskCleanup\SilentCleanup /I
|
||||
exit
|
||||
)
|
||||
|
||||
schtasks /change /tn \Microsoft\Windows\UpdateOrchestrator\Reboot /DISABLE
|
||||
icacls "%WINDIR%\System32\Tasks\Microsoft\Windows\UpdateOrchestrator\Reboot" /inheritance:r /deny "Everyone:F" /deny "SYSTEM:F" /deny "Local Service:F" /deny "Administrators:F"
|
||||
if "%debug%"=="1" ( pause )
|
||||
exit
|
165
love_plotting/main.lua
Normal file
165
love_plotting/main.lua
Normal file
|
@ -0,0 +1,165 @@
|
|||
function lerp(x0, x1, t)
|
||||
return x0*(1-t) + x1*t
|
||||
end
|
||||
|
||||
function blendExp(x0, x1, t)
|
||||
return x0^(1-t)*x1^t
|
||||
end
|
||||
|
||||
local sw = 640
|
||||
local sh = 480
|
||||
|
||||
local font
|
||||
local fs = 12
|
||||
|
||||
local coordsA = {}
|
||||
local coordsB = {}
|
||||
local coordsAL = {}
|
||||
local coordsBL = {}
|
||||
|
||||
local input = {
|
||||
[0]=0.9013,
|
||||
[60]=1.3685,
|
||||
[120]=1.1046,
|
||||
[180]=1.1633,
|
||||
[240]=0.7332,
|
||||
[300]=0.8603,
|
||||
[360]=0.9013,
|
||||
}
|
||||
local xPrecision = 60/20
|
||||
|
||||
local win = {
|
||||
T = 1.5,
|
||||
B = -0.5,
|
||||
L = 0,
|
||||
R = 360,
|
||||
stepX = 30,
|
||||
stepY = 0.25,
|
||||
}
|
||||
win.scaleX = 1/(win.L - win.R)
|
||||
win.scaleY = 1/(win.T - win.B)
|
||||
|
||||
function screenX(x)
|
||||
return sw*(win.L-x)*win.scaleX
|
||||
end
|
||||
|
||||
function screenY(y)
|
||||
return sh*(win.T-y)*win.scaleY
|
||||
end
|
||||
|
||||
function addPoint(coords, x, y)
|
||||
coords[#coords+1] = screenX(x)
|
||||
coords[#coords+1] = screenY(y)
|
||||
end
|
||||
|
||||
function index(t, x)
|
||||
if type(x) ~= type(0) then
|
||||
return nil
|
||||
end
|
||||
|
||||
local x0
|
||||
local x1
|
||||
for tx, ty in pairs(t) do
|
||||
-- we can't guarantee the order the key/values come in
|
||||
if tx ~= "interpolator" then
|
||||
-- x0 = largest tx that doesn't go over x
|
||||
if tx <= x and (x0 == nil or tx > x0) then
|
||||
x0 = tx
|
||||
end
|
||||
-- x1 = smallest tx that doesn't go under x
|
||||
if tx > x and (x1 == nil or tx < x1) then
|
||||
x1 = tx
|
||||
end
|
||||
end
|
||||
end
|
||||
x1 = x1 or x0
|
||||
|
||||
local y0 = rawget(t, x0)
|
||||
local y1 = rawget(t, x1)
|
||||
local f = rawget(t, "interpolator")
|
||||
local y = f(y0, y1, (x - x0)/(x1 - x0))
|
||||
return y
|
||||
end
|
||||
|
||||
function love.load()
|
||||
if not love.graphics.setMode(sw, sh) then
|
||||
error("couldn't setMode ("..sw.." by "..sh..")")
|
||||
end
|
||||
|
||||
love.graphics.setCaption("hey it's a graph")
|
||||
|
||||
--font = love.graphics.newFont("DejaVuSansMono.ttf", fs)
|
||||
--love.graphics.setFont(font)
|
||||
setmetatable(input, {__index = index})
|
||||
|
||||
input.interpolator = lerp
|
||||
for x=win.L, win.R, xPrecision do
|
||||
local y = input[x]
|
||||
addPoint(coordsA, x, y)
|
||||
addPoint(coordsAL, x, math.log(y))
|
||||
end
|
||||
|
||||
input.interpolator = blendExp
|
||||
for x=win.L, win.R, xPrecision do
|
||||
local y = input[x]
|
||||
addPoint(coordsB, x, y)
|
||||
addPoint(coordsBL, x, math.log(y))
|
||||
end
|
||||
end
|
||||
|
||||
function love.keypressed(key)
|
||||
if key == "escape" then
|
||||
love.event.push("quit")
|
||||
end
|
||||
end
|
||||
|
||||
local drawCoords = love.graphics.line
|
||||
local drawText = love.graphics.print
|
||||
|
||||
function color(hex)
|
||||
local r = tonumber(string.sub(hex, 1,2), 16)
|
||||
local g = tonumber(string.sub(hex, 3,4), 16)
|
||||
local b = tonumber(string.sub(hex, 5,6), 16)
|
||||
love.graphics.setColor(r,g,b)
|
||||
end
|
||||
|
||||
function drawVert(x)
|
||||
drawCoords(x, 0, x, sh)
|
||||
end
|
||||
|
||||
function drawHoriz(y)
|
||||
drawCoords(0, y, sw, y)
|
||||
end
|
||||
|
||||
function love.draw()
|
||||
love.graphics.setBackgroundColor(255,255,255)
|
||||
love.graphics.clear()
|
||||
|
||||
for x=win.L, win.R, win.stepX do
|
||||
color("d3e2e7")
|
||||
local rx = screenX(x)
|
||||
drawVert(rx)
|
||||
color("808080")
|
||||
drawText(tostring(x), rx, sh - fs)
|
||||
end
|
||||
|
||||
for y=win.B, win.T, win.stepY do
|
||||
color("c6cce3")
|
||||
local ry = screenY(y)
|
||||
drawHoriz(ry)
|
||||
color("808080")
|
||||
drawText(tostring(y), 0, ry)
|
||||
end
|
||||
|
||||
color("404040")
|
||||
drawVert(screenX(0))
|
||||
drawHoriz(screenY(0))
|
||||
|
||||
color("57C1BB")
|
||||
drawCoords(coordsA)
|
||||
drawCoords(coordsAL)
|
||||
|
||||
color("9F65C5")
|
||||
drawCoords(coordsB)
|
||||
drawCoords(coordsBL)
|
||||
end
|
83
lsca/lsca.uni.py
Normal file
83
lsca/lsca.uni.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import numpy as np
|
||||
|
||||
|
||||
def lament(*args, **kwargs):
|
||||
return print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
|
||||
def colorize(x):
|
||||
return x * 17 % 256
|
||||
|
||||
|
||||
def render(row, scale):
|
||||
grays = colorize(row)
|
||||
if scale > 1:
|
||||
grays = np.repeat(grays, scale)
|
||||
line = " ".join(str(x) for x in grays)
|
||||
for y in range(scale):
|
||||
print(line)
|
||||
|
||||
|
||||
def limit(row): # in-place
|
||||
row[row < 0] = 0
|
||||
row[row > 15] = 15
|
||||
return row
|
||||
|
||||
|
||||
def initialize(width):
|
||||
row = np.zeros(width, int)
|
||||
value = 0
|
||||
for i in range(width):
|
||||
if np.random.randint(8) == 0: # only change values occasionally
|
||||
value = np.random.randint(16)
|
||||
row[i] = value
|
||||
limit(row)
|
||||
return row
|
||||
|
||||
|
||||
name, args = sys.argv[0], sys.argv[1:]
|
||||
|
||||
if len(args) == 0:
|
||||
rule_lut = None
|
||||
elif len(args) == 16:
|
||||
rule_lut = [int(x.strip(",")) for x in args]
|
||||
else:
|
||||
lament(f"usage: {name}")
|
||||
lament(f"usage: {name} {{rules 1 through 16}}")
|
||||
sys.exit(1)
|
||||
|
||||
scale = 3
|
||||
width, height = 960 // scale, 960 // scale
|
||||
|
||||
if rule_lut is None:
|
||||
rule_lut = np.random.randint(-2, 2 + 1, size=(4, 4))
|
||||
lament(" ".join(f"{x:+2}" for x in rule_lut.flat))
|
||||
else:
|
||||
rule_lut = np.array(rule_lut).reshape(4, 4)
|
||||
|
||||
print("P2") # magic code for an ascii Portable GrayMap (PGM) file
|
||||
print(width * scale, height * scale)
|
||||
print(255) # maximum color value
|
||||
|
||||
row = initialize(width)
|
||||
|
||||
for i in range(height):
|
||||
# left, center, right:
|
||||
L = np.roll(row, 1)
|
||||
C = row.copy()
|
||||
R = np.roll(row, -1)
|
||||
|
||||
diffusion = (L + C + C + R + 2) // 4
|
||||
|
||||
# v = [0,1,2,3,1,0,3,2,2,3,0,1,3,2,1,0][V]
|
||||
y = (L ^ (L >> 2)) % 4
|
||||
x = (R ^ (R >> 2)) % 4
|
||||
|
||||
delta = rule_lut[y, x]
|
||||
row = diffusion + delta
|
||||
|
||||
limit(row)
|
||||
render(row, scale)
|
172
lsf/lsf.sh
Executable file
172
lsf/lsf.sh
Executable file
|
@ -0,0 +1,172 @@
|
|||
#!/bin/bash
|
||||
# ultra-fancy ultra-pointless `ls -l` alternative
|
||||
# to be sourced by bash or zsh
|
||||
# similar project: https://github.com/trapd00r/ls--
|
||||
|
||||
# to maintain zsh compatibility:
|
||||
# $() is surrounded in double quotes
|
||||
# echo -E is used to avoid \033 expanding
|
||||
# bare asterisks are escaped to prevent globbing
|
||||
# arrays are used instead of relying on word expansion
|
||||
# for loops over "${array[@]}" as it works the same in both
|
||||
|
||||
# TODO: set better defaults for quick glances at filesize
|
||||
# TODO: include sorting somehow
|
||||
# TODO: handle symlinks nicely
|
||||
# TODO: append WHI / clr to dir names
|
||||
|
||||
_lsf_begin(){
|
||||
local begin='
|
||||
me='$UID'
|
||||
'"$(
|
||||
awk -F: '{print "unames["$3"]=\""$1"\""}' < /etc/passwd
|
||||
awk -F: '{print "gnames["$3"]=\""$1"\""}' < /etc/group
|
||||
for x in $(groups); do echo "us[\"$x\"]=1"; done
|
||||
i=0;for x in bla red gre yel blu pur cya whi; do
|
||||
echo -E $x'="\033[3'${i}'m"'
|
||||
echo -n "$x" | tr a-z A-Z
|
||||
echo -E '="\033[1;3'${i}'m"'
|
||||
let i++
|
||||
done
|
||||
)"'
|
||||
clr="\033[0m"
|
||||
BLD="\033[1m"
|
||||
s=1
|
||||
m=60*s
|
||||
h=60*m
|
||||
d=24*h
|
||||
y=365*d
|
||||
B=1
|
||||
K=1024*B
|
||||
M=1024*K
|
||||
G=1024*M
|
||||
T=1024*G
|
||||
ff["time"]="%3d%s " clr
|
||||
ff["size"]="%4d" clr "%s "
|
||||
'"$(
|
||||
for x in s m h d y;do echo "u[\"time,$x\"]=$x";done
|
||||
for x in B K M G T;do echo "u[\"size,$x\"]=$x";done
|
||||
ft=(-1 m m\*10 h h\*12 d d\*7 30\*d y y\*2 y\*10)
|
||||
fut=(s s s m m h h d d d y y)
|
||||
fct=(RED PUR pur YEL yel GRE gre CYA cya BLU blu BLA)
|
||||
fs=( 0 K K\*8 M M\*8 G G\*8 T T\*8)
|
||||
fus=(B B B K K M M G G T)
|
||||
fcs=(BLA cya CYA CYA yel yel pur pur red red)
|
||||
pc=(BLA WHI yel YEL blu BLU gre GRE)
|
||||
i=0;for x in "${ft[@]}"; do echo "f[\"time,$i\"]=$x"; let i++;done
|
||||
echo "f[\"times\"]=$i"
|
||||
i=0;for x in "${fs[@]}"; do echo "f[\"size,$i\"]=$x"; let i++;done
|
||||
echo "f[\"sizes\"]=$i"
|
||||
i=0;for x in "${fut[@]}";do echo "fu[\"time,$i\"]=\"$x\"";let i++;done
|
||||
i=0;for x in "${fus[@]}";do echo "fu[\"size,$i\"]=\"$x\"";let i++;done
|
||||
i=0;for x in "${fct[@]}";do echo "fc[\"time,$i\"]=$x"; let i++;done
|
||||
i=0;for x in "${fcs[@]}";do echo "fc[\"size,$i\"]=$x"; let i++;done
|
||||
i=0;for x in "${pc[@]}"; do echo "pc[$i]=$x"; let i++;done
|
||||
)"
|
||||
echo -E "$begin"
|
||||
}
|
||||
|
||||
_lsf_cached=
|
||||
_lsf_program='
|
||||
function printff(id, n) {
|
||||
len=f[id "s"]
|
||||
for(i=0;i<=len;i++) {
|
||||
idi=id "," i
|
||||
if(i!=len && n>f[idi]) continue
|
||||
unit=fu[idi]
|
||||
printf(fc[idi] ff[id], n/u[id "," unit], unit)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
function trunc(str, len) {
|
||||
e=length(str)>len?"…":""
|
||||
return substr(str,0,len-(e?1:0)) e
|
||||
}
|
||||
function fixlen(str, len) {
|
||||
return trunc(sprintf("%" len "s", str), len)
|
||||
}
|
||||
{
|
||||
printff("size", $(NF-14))
|
||||
|
||||
uid=$(NF-11)
|
||||
gid=$(NF-10)
|
||||
is_me=(uid==me)
|
||||
is_us=(gnames[gid] in us)
|
||||
|
||||
bits=("0x" $(NF-12))+0
|
||||
# note: we ignore the set and sticky bits... for now
|
||||
type=rshift(and(bits, 0170000), 12)
|
||||
operm=and(bits, 07)
|
||||
gperm=rshift(and(bits, 070), 3)
|
||||
uperm=rshift(and(bits, 0700), 6)
|
||||
our_perm=or(or((is_me)?uperm:0, (is_us)?gperm:0), operm)
|
||||
|
||||
printf(pc[our_perm] "%o " clr, our_perm)
|
||||
if(OSP) {
|
||||
printf(pc[uperm] "%o" clr, uperm)
|
||||
printf(pc[gperm] "%o" clr, gperm)
|
||||
printf(pc[operm] "%o " clr, operm)
|
||||
}
|
||||
|
||||
if(OSU) {
|
||||
name=fixlen((uid in unames)?unames[uid]:uid, 6)
|
||||
if(is_me) name=WHI name clr
|
||||
printf("%s ", name)
|
||||
}
|
||||
|
||||
if(OSG) {
|
||||
name=fixlen((gid in gnames)?gnames[gid]:gid, 6)
|
||||
if(is_us) name=WHI name clr
|
||||
printf("%s ", name)
|
||||
}
|
||||
|
||||
da=$(NF-4)
|
||||
dc=$(NF-3)
|
||||
dm=$(NF-2)
|
||||
if(OMR) {
|
||||
max=(da>dm)?da:dm
|
||||
max=(max>dc)?max:dc
|
||||
printff("time", now-max)
|
||||
} else {
|
||||
printff("time", now-da)
|
||||
printff("time", now-dm)
|
||||
printff("time", now-dc)
|
||||
}
|
||||
|
||||
# acquire filename by killing all fields not part of it
|
||||
NF-=15
|
||||
fn=$0
|
||||
|
||||
if (!OSPA) {
|
||||
if (NR!=1) fn=substr(fn,firstlen)
|
||||
else firstlen=length(fn)+2-(fn ~ /\/$/)
|
||||
}
|
||||
|
||||
print fn
|
||||
}'
|
||||
|
||||
lsf(){
|
||||
local o_showallperm=1 o_showuser=1 o_showgroup=1
|
||||
local o_mostrecent=0 o_showpath=1 opts=mgupfs opt
|
||||
while getopts $opts'h' opt; do
|
||||
case $opt in
|
||||
f) _lsf_cached=;;
|
||||
p) o_showallperm=0;;
|
||||
u) o_showuser=0;;
|
||||
g) o_showgroup=0;;
|
||||
m) o_mostrecent=1;;
|
||||
s) o_showpath=0;;
|
||||
?) echo "usage: $0 [-$opts] [dir]"
|
||||
return 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
[ "$_lsf_cached" ] || _lsf_cached="$(_lsf_begin)"
|
||||
|
||||
shift $((OPTIND-1))
|
||||
find "${1:-.}" -maxdepth 1 -exec stat -t {} + | awk --non-decimal-data \
|
||||
-v"now=$(date +%s)" -v"OMR=$o_mostrecent" -v"OSU=$o_showuser" \
|
||||
-v"OSG=$o_showgroup" -v"OSP=$o_showallperm" -v"OSPA=$o_showpath" \
|
||||
"BEGIN{$_lsf_cached}$_lsf_program"
|
||||
}
|
328
mario_tennis/tennis.c
Normal file
328
mario_tennis/tennis.c
Normal file
|
@ -0,0 +1,328 @@
|
|||
// arbitrary terminology i made up on the spot:
|
||||
// "entry" = code as exposed to user, in ASCII.
|
||||
// "code" = code as indices into lut, used internally.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
#define lament(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define sizeofel(a) (sizeof(*(a)))
|
||||
#define LEN(a) (sizeof(a) / sizeofel(a))
|
||||
|
||||
const char *lut[] = {
|
||||
// characters within the same string are considered the same.
|
||||
// that means the number of choices for a single character
|
||||
// goes down from 36 to 28.
|
||||
"N", "P", "Q", "R",
|
||||
"T", "W", "X", "Y",
|
||||
"17I", "2Z", "5S", "8B",
|
||||
"0OD", "UV", "3", "4",
|
||||
"6", "9", "A", "C",
|
||||
"E", "F", "G", "H",
|
||||
"J", "K", "L", "M",
|
||||
};
|
||||
|
||||
enum {lutlen = LEN(lut)}; // should be 28.
|
||||
|
||||
const u32 bases[] = {
|
||||
64,
|
||||
11,
|
||||
21,
|
||||
2,
|
||||
21,
|
||||
8,
|
||||
6, // dummy value.
|
||||
};
|
||||
|
||||
enum {
|
||||
MT_CHOICE = -1,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
MT_YOSHI,
|
||||
MT_PEACH,
|
||||
MT_MARIO,
|
||||
MT_BOWSER,
|
||||
MT_BOO,
|
||||
MT_DK,
|
||||
MT_BABY_MARIO,
|
||||
MT_TOAD,
|
||||
MT_WALUIGI,
|
||||
MT_WARIO,
|
||||
MT_LUIGI,
|
||||
MT_DAISY,
|
||||
MT_BIRDO,
|
||||
MT_SHYGUY,
|
||||
MT_DK_JR,
|
||||
MT_PARATROOPA,
|
||||
} character_t;
|
||||
|
||||
typedef enum {
|
||||
MT_SINGLES_GAME,
|
||||
MT_SINGLES_TIME_3,
|
||||
MT_SINGLES_TIME_5,
|
||||
MT_SINGLES_BALL_1,
|
||||
MT_SINGLES_BALL_3,
|
||||
MT_SINGLES_POINT_3,
|
||||
MT_SINGLES_POINT_5,
|
||||
MT_DOUBLES_GAME_1,
|
||||
MT_DOUBLES_TIME_3,
|
||||
MT_DOUBLES_BALL_1,
|
||||
MT_DOUBLES_POINT_3,
|
||||
} gamemode_t;
|
||||
|
||||
typedef enum {
|
||||
MT_HARD,
|
||||
MT_CLAY,
|
||||
MT_GRASS,
|
||||
MT_COMPOSITION,
|
||||
MT_OPEN,
|
||||
} court_t;
|
||||
|
||||
typedef struct {
|
||||
char code[9];
|
||||
// data[0]: cup name
|
||||
// data[1]: gamemode
|
||||
// data[2]: player character (-1 for player's choice)
|
||||
// data[3]: unknown (boolean)
|
||||
// data[4]: opponent character (-1 for player's choice)
|
||||
// data[5]: unknown
|
||||
// data[6]: court (-1 for player's choice)
|
||||
u32 data[7];
|
||||
} code_t;
|
||||
|
||||
code_t translate(const char *entry) {
|
||||
code_t code = {0};
|
||||
for (int i = 0; i < 9; i++) {
|
||||
char e = entry[i];
|
||||
if (e == '\0') return code;
|
||||
for (int j = 0; j < lutlen; j++) {
|
||||
const char *c = lut[j];
|
||||
while (*c != '\0') {
|
||||
if (e == *c) {
|
||||
code.code[i] = j;
|
||||
goto nextchar;
|
||||
}
|
||||
c++;
|
||||
}
|
||||
}
|
||||
nextchar:
|
||||
;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
int check_ranges(const code_t *code) {
|
||||
const u32 choice = (u32)MT_CHOICE;
|
||||
const u32 *data = code->data;
|
||||
|
||||
return
|
||||
(data[0] < bases[0]) &&
|
||||
(data[1] < bases[1]) &&
|
||||
(data[2] + 1 < bases[2] - 4) &&
|
||||
(data[3] < bases[3]) &&
|
||||
(data[4] + 1 < bases[4] - 4) &&
|
||||
(data[5] < bases[5]) &&
|
||||
(data[6] + 1 < bases[6]) &&
|
||||
(data[2] == choice || data[2] != data[4]) &&
|
||||
(data[1] < 7 || (data[2] != choice && data[4] != choice));
|
||||
}
|
||||
|
||||
int decode_data(code_t *code) {
|
||||
u32 part0 = 0, part1 = 0;
|
||||
for (int i = 5; i >= 0; i--) part0 = part0 * lutlen + code->code[i];
|
||||
for (int i = 8; i >= 6; i--) part1 = part1 * lutlen + code->code[i];
|
||||
u32 checksum = (part0 + 0x2AE0) % (lutlen * lutlen * lutlen);
|
||||
|
||||
#if !NDEBUG
|
||||
lament("merged data: %08X\n", part0);
|
||||
lament("expected checksum: %08X\n", part1);
|
||||
lament("actual checksum: %08X\n", checksum);
|
||||
#endif
|
||||
|
||||
u32 leftover = part0 ^ 0x02AAAAAA;
|
||||
|
||||
code->data[0] = leftover % bases[0]; leftover /= bases[0];
|
||||
code->data[1] = leftover % bases[1]; leftover /= bases[1];
|
||||
code->data[2] = leftover % bases[2]; leftover /= bases[2];
|
||||
code->data[3] = leftover % bases[3]; leftover /= bases[3];
|
||||
code->data[4] = leftover % bases[4]; leftover /= bases[4];
|
||||
code->data[5] = leftover % bases[5]; leftover /= bases[5];
|
||||
code->data[6] = leftover;
|
||||
|
||||
code->data[2]--;
|
||||
code->data[4]--;
|
||||
code->data[6]--;
|
||||
|
||||
#if !NDEBUG
|
||||
lament("stored data:");
|
||||
for (int i = 0; i < 7; i++) lament(" %i", code->data[i]);
|
||||
lament("\n");
|
||||
#endif
|
||||
|
||||
if (checksum != part1) return 0;
|
||||
|
||||
if (!check_ranges(code)) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int encode_data(code_t *code) {
|
||||
if (!check_ranges(code)) return 0;
|
||||
|
||||
u32 combined = 0;
|
||||
combined = code->data[6] + 1;
|
||||
combined = combined * bases[5] + code->data[5];
|
||||
combined = combined * bases[4] + code->data[4] + 1;
|
||||
combined = combined * bases[3] + code->data[3];
|
||||
combined = combined * bases[2] + code->data[2] + 1;
|
||||
combined = combined * bases[1] + code->data[1];
|
||||
combined = combined * bases[0] + code->data[0];
|
||||
combined = combined ^ 0x02AAAAAA;
|
||||
|
||||
u32 checksum = (combined + 0x2AE0) % (lutlen * lutlen * lutlen);
|
||||
|
||||
#if !NDEBUG
|
||||
lament("merged data: %08X\n", combined);
|
||||
lament("checksum: %08X\n", checksum);
|
||||
#endif
|
||||
|
||||
u32 part0 = combined, part1 = checksum;
|
||||
for (int i = 0; i <= 5; i++) {
|
||||
code->code[i] = part0 % lutlen; part0 /= lutlen;
|
||||
}
|
||||
for (int i = 6; i <= 8; i++) {
|
||||
code->code[i] = part1 % lutlen; part1 /= lutlen;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int validate_entry(const char *entry) {
|
||||
code_t code = translate(entry);
|
||||
|
||||
#if !NDEBUG
|
||||
lament("character mapping:");
|
||||
for (int i = 0; i < 9; i++) {
|
||||
lament(" %c->%i,", entry[i], code.code[i]);
|
||||
}
|
||||
lament("\n");
|
||||
#endif
|
||||
|
||||
return decode_data(&code);
|
||||
}
|
||||
|
||||
static void print_code(const code_t *code) {
|
||||
for (int j = 0; j < 9; j++) {
|
||||
int index = code->code[j];
|
||||
printf("%c", lut[index][0]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static u64 prng_state = 1;
|
||||
static u32 prng() {
|
||||
prng_state = 3935559000370003845 * prng_state + 1;
|
||||
return prng_state ^ (prng_state >> 32);
|
||||
}
|
||||
|
||||
int bruteforce(int count) {
|
||||
/* with a fixed seed, this is useful for testing.
|
||||
the first 10 results should be:
|
||||
8RPEHR8R4
|
||||
MNXKWQMNE
|
||||
CE922RCER
|
||||
MQ1KMQMQG
|
||||
2N9GGR2NR
|
||||
25L53R250
|
||||
15R09R159
|
||||
9R9LMQ9RR
|
||||
L312MQL3G
|
||||
P93M6QP9N
|
||||
*/
|
||||
|
||||
int found = 0;
|
||||
code_t code = {0};
|
||||
while (found < count) {
|
||||
for (int j = 0; j < 9; j++) {
|
||||
code.code[j] = prng() % lutlen;
|
||||
}
|
||||
if (decode_data(&code)) {
|
||||
found++;
|
||||
print_code(&code);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef TENNIS_NO_MAIN
|
||||
int main(int argc, char **argv) {
|
||||
if (argc == 1) {
|
||||
// self-test with codes known before this program was written.
|
||||
#define TEST(entry) if (!validate_entry(entry)) return -1
|
||||
TEST("48HWOR482");
|
||||
TEST("5G3LTQ5GN");
|
||||
TEST("A3W5KQA3C");
|
||||
TEST("ARM6JQARU");
|
||||
TEST("E880MPE8K");
|
||||
TEST("E8ULJRE8M");
|
||||
TEST("EPJEGREP5");
|
||||
TEST("GH4KNQGHP");
|
||||
TEST("H6L3MPH60");
|
||||
TEST("HH4KNQHHP");
|
||||
TEST("J6M9PQJ6U");
|
||||
TEST("JEP8YQJE4");
|
||||
TEST("LA98JRLAR");
|
||||
TEST("LQM1MPLQU");
|
||||
TEST("LTHWYQLT2");
|
||||
TEST("M1C2YQM1W");
|
||||
TEST("MM55MQMMJ");
|
||||
TEST("N24K8QN2P");
|
||||
TEST("OF9XFQOFR");
|
||||
TEST("P4K6GRP48");
|
||||
TEST("TE6WARTEQ");
|
||||
TEST("TQJEGRTQ5");
|
||||
TEST("UOUFMPUOM");
|
||||
TEST("V2UFMPUZM");
|
||||
TEST("W2HEGRW22");
|
||||
TEST("WQJEGRWQ5");
|
||||
TEST("WRWQARWRC");
|
||||
TEST("YQJEGRYQ5");
|
||||
#undef TEST
|
||||
return 0;
|
||||
}
|
||||
|
||||
code_t code = {0};
|
||||
int code_i = 0;
|
||||
|
||||
int invalid_count = 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (strlen(arg) == 9) {
|
||||
//if (validate_entry(arg)) printf("%s\n", arg);
|
||||
invalid_count += !validate_entry(arg);
|
||||
} else if (!strcmp(arg, "bruteforce")) {
|
||||
invalid_count += !bruteforce(10);
|
||||
} else {
|
||||
u32 datum = strtoul(arg, NULL, 0);
|
||||
code.data[code_i] = datum;
|
||||
code_i++;
|
||||
|
||||
if (code_i >= 7) {
|
||||
code_i = 0;
|
||||
if (encode_data(&code)) {
|
||||
print_code(&code);
|
||||
} else {
|
||||
invalid_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return invalid_count;
|
||||
}
|
||||
#endif
|
11
mips_disassembler/Makefile
Executable file
11
mips_disassembler/Makefile
Executable file
|
@ -0,0 +1,11 @@
|
|||
#CFLAGS = -ggdb -Wall
|
||||
CFLAGS = -Ofast -Wall
|
||||
|
||||
install: all
|
||||
cp zadis /usr/bin/zadis
|
||||
|
||||
all:
|
||||
$(CC) $(CFLAGS) -o zadis adis.c
|
||||
|
||||
clean:
|
||||
rm -vf adis
|
1634
mips_disassembler/adis.c
Executable file
1634
mips_disassembler/adis.c
Executable file
File diff suppressed because it is too large
Load Diff
10
music_sync/convert.py
Normal file
10
music_sync/convert.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
import subprocess as sp
|
||||
import os
|
||||
|
||||
def ogg(fin, fout):
|
||||
p1 = sp.Popen(["ffmpeg", "-loglevel", "error", "-i", fin, "-f", "flac", "-"], stdout=sp.PIPE)
|
||||
p2 = sp.Popen(["oggenc", "-Q", "-q", "5", "-", "-o", fout], stdin=p1.stdout, stdout=sp.PIPE)
|
||||
p1.stdout.close()
|
||||
p2.communicate()
|
||||
ret = p1.poll() or p2.poll()
|
||||
return ret
|
117
music_sync/mutaext.py
Normal file
117
music_sync/mutaext.py
Normal file
|
@ -0,0 +1,117 @@
|
|||
from collections import MutableMapping
|
||||
import mutagenx
|
||||
import mutagenx.id3
|
||||
from mutagenx.easyid3 import EasyID3
|
||||
|
||||
def popms(id3):
|
||||
for k, v in id3.items():
|
||||
if k.startswith('POPM'):
|
||||
yield k, v
|
||||
|
||||
def byte2rating(b):
|
||||
if b >= 224: return 5
|
||||
if b >= 160: return 4
|
||||
if b >= 96: return 3
|
||||
if b >= 32: return 2
|
||||
if b >= 1: return 1
|
||||
return 0
|
||||
|
||||
def rating2byte(r):
|
||||
if r == 5: return 256
|
||||
if r == 4: return 192
|
||||
if r == 3: return 128
|
||||
if r == 2: return 64
|
||||
if r == 1: return 1
|
||||
return 0
|
||||
|
||||
def rating_get(id3, key):
|
||||
if 'TXXX:RATING' in id3:
|
||||
rating = id3['TXXX:RATING']
|
||||
return list(rating.text)
|
||||
else:
|
||||
try:
|
||||
_, popm = next(popms(id3))
|
||||
except StopIteration:
|
||||
return []
|
||||
else:
|
||||
return [str(byte2rating(popm.rating))]
|
||||
|
||||
def _canconv(r):
|
||||
try:
|
||||
ir = int(r)
|
||||
if ir != str(ir):
|
||||
return False
|
||||
return ir >= 1 and ir <= 5
|
||||
except (ValueError, TypeError):
|
||||
return False
|
||||
|
||||
def rating_set(id3, key, val):
|
||||
rating_delete(id3, key)
|
||||
if _canconv(val):
|
||||
popm = mutagenx.id3.POPM()
|
||||
popm.email = "Windows Media Player 9 Series"
|
||||
popm.count = 0
|
||||
popm.rating = rating2byte(int(val))
|
||||
id3.add(popm)
|
||||
else:
|
||||
if 'TXXX:RATING' in id3:
|
||||
del(id3['TXXX:RATING'])
|
||||
id3.add(mutagenx.id3.TXXX(encoding=3, desc='RATING', text=str(val)))
|
||||
|
||||
def rating_delete(id3, key):
|
||||
for k, v in popms(id3):
|
||||
del(id3[k])
|
||||
if 'TXXX:RATING' in id3:
|
||||
del(id3['TXXX:RATING'])
|
||||
|
||||
replaygain_tags = ('replaygain_album_gain', 'replaygain_album_peak', \
|
||||
'replaygain_track_gain', 'replaygain_track_peak')
|
||||
for tag in replaygain_tags:
|
||||
EasyID3.RegisterTXXXKey(tag, tag)
|
||||
|
||||
extra_tags = ('sync', 'totaltracks', 'totaldiscs')
|
||||
for tag in extra_tags:
|
||||
EasyID3.RegisterTXXXKey(tag, tag.upper())
|
||||
|
||||
EasyID3.RegisterTextKey('albumartist', 'TPE2')
|
||||
EasyID3.RegisterKey('rating', rating_get, rating_set, rating_delete)
|
||||
|
||||
class SyncFile(MutableMapping):
|
||||
def __init__(self, path):
|
||||
self.md = mutagenx.File(path, easy=True)
|
||||
self.path = path
|
||||
self.seen = False
|
||||
|
||||
def __getitem__(self, key):
|
||||
if self.md == None:
|
||||
print(self.path)
|
||||
d = self.md[key]
|
||||
try:
|
||||
return d[0]
|
||||
except IndexError:
|
||||
raise KeyError(key)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
#if type(value) != str:
|
||||
#raise ValueError
|
||||
if type(value) is type(None):
|
||||
raise ValueError
|
||||
self.md[key] = [value]
|
||||
|
||||
def __delitem__(self, key):
|
||||
del(self.md[key])
|
||||
|
||||
def __iter__(self):
|
||||
for k in self.md:
|
||||
try:
|
||||
self.__getitem__(k)
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
yield k
|
||||
|
||||
def __len__(self):
|
||||
return len([k for k in self.__iter__()])
|
||||
|
||||
def save(self):
|
||||
return self.md.save()
|
172
music_sync/unsync.py
Executable file
172
music_sync/unsync.py
Executable file
|
@ -0,0 +1,172 @@
|
|||
#!/bin/python
|
||||
|
||||
import os, os.path
|
||||
import sys
|
||||
from shutil import copy2
|
||||
from tempfile import mkstemp
|
||||
from zlib import crc32
|
||||
|
||||
import mutaext
|
||||
import convert
|
||||
from mutaext import SyncFile
|
||||
|
||||
goodexts = ('.mp3', '.flac', '.ogg')
|
||||
|
||||
matchtags = ['artist', 'album', 'title', 'tracknumber', 'discnumber']
|
||||
alltags = [
|
||||
'albumartist', 'composer', 'comment',
|
||||
'genre', 'date',
|
||||
]
|
||||
alltags.extend(mutaext.replaygain_tags)
|
||||
alltags.extend(mutaext.extra_tags)
|
||||
alltags.extend(matchtags)
|
||||
|
||||
lament = lambda *args, **kwargs: print(*args, file=sys.stderr, **kwargs)
|
||||
walkfiles = lambda w: (os.path.join(r, f) for r, _, fs in w for f in fs)
|
||||
extof = lambda p: os.path.splitext(p)[1].lower()
|
||||
filterext = lambda ps, es: (p for p in ps if extof(p) in es)
|
||||
|
||||
def shouldsync(md):
|
||||
rating = md.get('rating', '')
|
||||
sync = md.get('sync', '')
|
||||
if rating.isnumeric():
|
||||
rating = int(rating)
|
||||
if sync:
|
||||
sync = sync.lower()
|
||||
|
||||
return sync == 'yes' or type(rating) == int and rating >= 3 and sync != 'no' and sync != 'space'
|
||||
|
||||
import re
|
||||
re_digits = re.compile(r'\d+')
|
||||
def tonumber(crap):
|
||||
if crap is None or len(crap) == 0:
|
||||
return 0
|
||||
nums = re_digits.findall(crap)
|
||||
if len(nums) == 0:
|
||||
return 0
|
||||
return int(nums[0])
|
||||
|
||||
def fixmetadata(md):
|
||||
md['artist'] = md.get('artist', "Unknown Artist")
|
||||
md['album'] = md.get('album', "Unknown Album")
|
||||
md['discnumber'] = str(tonumber(md.get('discnumber', '0')))
|
||||
md['tracknumber'] = str(tonumber(md.get('tracknumber', '0')))
|
||||
if 'title' not in md:
|
||||
fn = os.path.basename(md.path)
|
||||
fn = os.path.splitext(fn)[0]
|
||||
md['title'] = str(fn)
|
||||
|
||||
def findmatching(haystack, needle):
|
||||
#matchme = [needle[t].lower() for t in matchtags]
|
||||
#ismatch = lambda hay: [hay[t].lower() for t in matchtags] == matchme
|
||||
matchme = [needle[t] for t in matchtags]
|
||||
ismatch = lambda hay: [hay[t] for t in matchtags] == matchme
|
||||
for match in (hay for hay in haystack if ismatch(hay)):
|
||||
if match.seen:
|
||||
# TODO: check other tags too?
|
||||
lament("Duplicate")
|
||||
return None
|
||||
match.seen = needle.path
|
||||
return match
|
||||
|
||||
def updatemetadata(mdold, mdnew):
|
||||
modified = False
|
||||
for tag in alltags:
|
||||
if tag in mdnew:
|
||||
if tag not in mdold or mdnew[tag] != mdold[tag]:
|
||||
mdold[tag] = mdnew[tag]
|
||||
modified = True
|
||||
elif tag in mdold:
|
||||
del mdold[tag]
|
||||
modified = True
|
||||
return modified
|
||||
|
||||
def makefilename(md):
|
||||
title = md['title']
|
||||
artist = md['artist']
|
||||
album = md['album']
|
||||
track = md['tracknumber']
|
||||
disc = md['discnumber']
|
||||
|
||||
fn = "%(disc)s-%(track)s - %(artist)s - %(album)s - %(title)s" % locals()
|
||||
# FAT is a pain to deal with so just use nondescript filenames
|
||||
crc = crc32(fn.encode('utf-8')) & 0xFFFFFFFF
|
||||
fn = '{:08X}.ogg'.format(crc)
|
||||
|
||||
return fn
|
||||
|
||||
def run(args):
|
||||
if not len(args) in (2, 3):
|
||||
lament("I need a path or two!")
|
||||
return 1
|
||||
inonly = len(args) == 2
|
||||
|
||||
tosync = []
|
||||
indir = args[1]
|
||||
paths = lambda dir: filterext(walkfiles(os.walk(dir)), goodexts)
|
||||
|
||||
for p in paths(indir):
|
||||
md = SyncFile(p)
|
||||
if shouldsync(md):
|
||||
if inonly:
|
||||
print(p)
|
||||
else:
|
||||
fixmetadata(md)
|
||||
tosync.append(md)
|
||||
|
||||
if inonly:
|
||||
return 0
|
||||
|
||||
lament("Matching tags...")
|
||||
|
||||
outdir = args[2]
|
||||
for p in paths(outdir):
|
||||
md = SyncFile(p)
|
||||
fixmetadata(md)
|
||||
match = findmatching(tosync, md)
|
||||
if match == None:
|
||||
print("DEL", p)
|
||||
print('was', md['title'], 'by', md['artist'])
|
||||
os.remove(p)
|
||||
elif updatemetadata(md, match):
|
||||
print("UPD", p)
|
||||
md.save()
|
||||
|
||||
lament("Syncing files...")
|
||||
|
||||
for md in tosync:
|
||||
fn = makefilename(md)
|
||||
fout = os.path.join(outdir, fn)
|
||||
|
||||
if md.seen:
|
||||
_from = md.seen
|
||||
_to = fout
|
||||
if _from != _to:
|
||||
print("MOV", _from)
|
||||
os.rename(_from, _to)
|
||||
continue
|
||||
|
||||
print("ADD", md.path)
|
||||
|
||||
_, ftemp = mkstemp()
|
||||
try:
|
||||
convert.ogg(md.path, ftemp)
|
||||
mdnew = SyncFile(ftemp)
|
||||
for tag in alltags:
|
||||
if tag in md:
|
||||
mdnew[tag] = md[tag]
|
||||
fixmetadata(mdnew) # redundant?
|
||||
mdnew.save()
|
||||
copy2(ftemp, fout)
|
||||
finally:
|
||||
os.remove(ftemp)
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
ret = 0
|
||||
try:
|
||||
ret = run(sys.argv)
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(1)
|
||||
sys.exit(ret)
|
139
n64_models/pot3d.py
Normal file
139
n64_models/pot3d.py
Normal file
|
@ -0,0 +1,139 @@
|
|||
# hi this is super hacky and only converts a tiny segment of display lists.
|
||||
# it's really just to get a feel for how the formats work.
|
||||
# after extracting/decompressing OoT, run this script on object_tsubo.
|
||||
# the top of the pot is missing, i know. see the comment above.
|
||||
|
||||
import array
|
||||
import io
|
||||
import struct
|
||||
import sys
|
||||
|
||||
name = "pot"
|
||||
tw, th = 32, 64 # hardcoded texture width and height
|
||||
viscale = 256 # inverted scale, this is arbitrary
|
||||
v_base = 0x1838 # offset to first G_VTX command
|
||||
|
||||
with open(sys.argv[1], "rb") as f:
|
||||
data = f.read()
|
||||
|
||||
f = io.BytesIO(data)
|
||||
|
||||
# hardcoded for a rga5a1 texture at the start of the file:
|
||||
pix = array.array('H', f.read(tw * th * 2))
|
||||
pix.byteswap()
|
||||
rgbs = []
|
||||
for p in pix:
|
||||
r = (p & 0xF800) >> 11
|
||||
g = (p & 0x07C0) >> 6
|
||||
b = (p & 0x003E) >> 1
|
||||
a = p & 1
|
||||
# TODO: round color calculations. or not? i don't imagine the N64 bothers.
|
||||
rgb = (r * 255 // 31, g * 255 // 31, b * 255 // 31)
|
||||
rgbs.append(rgb)
|
||||
|
||||
verts = []
|
||||
texes = []
|
||||
norms = [] # unimplemented
|
||||
polys = []
|
||||
|
||||
vi = 0 # vertex index to offset by (incremented after each chunk)
|
||||
|
||||
f.seek(v_base)
|
||||
opcode = ord(f.read(1))
|
||||
|
||||
while opcode == 0x01: # G_VTX
|
||||
counts = f.read(3)
|
||||
numv = ((counts[0] & 0xF) << 4) | ((counts[1] & 0xF0) >> 4)
|
||||
vbidx = counts[2] // 2 - numv
|
||||
vaddr = struct.unpack(">i", f.read(4))[0]
|
||||
|
||||
back = f.tell()
|
||||
f.seek(vaddr & 0xFFFFFF)
|
||||
|
||||
for i in range(numv):
|
||||
if 0:
|
||||
# colored vertices
|
||||
vertex = struct.unpack(">hhhHhhBBBB", f.read(16))
|
||||
x, y, z, w, tx, ty, r, g, b, a = vertex
|
||||
else:
|
||||
# lit vertices
|
||||
vertex = struct.unpack(">hhhHhhbbbB", f.read(16))
|
||||
x, y, z, w, tx, ty, n, p, q, a = vertex
|
||||
|
||||
pos = (x / viscale, y / viscale, z / viscale)
|
||||
# FIXME: texture coordinates are slightly off
|
||||
tpos = ((tx / 32 / tw), 1 - (ty / 32 / th))
|
||||
verts.append(pos)
|
||||
texes.append(tpos)
|
||||
|
||||
f.seek(back)
|
||||
|
||||
while 1:
|
||||
opcode = ord(f.read(1))
|
||||
if opcode not in (6, 5):
|
||||
break
|
||||
if opcode == 5:
|
||||
indices = struct.unpack('>bbbbbbb', f.read(7))
|
||||
a0, a1, a2, _, _, _, _ = indices
|
||||
atri = a0 // 2 + 1 + vi, a1 // 2 + 1 + vi, a2 // 2 + 1 + vi
|
||||
polys.append(atri)
|
||||
elif opcode == 6:
|
||||
indices = struct.unpack('>bbbbbbb', f.read(7))
|
||||
a0, a1, a2, _, b0, b1, b2 = indices
|
||||
# TODO: assert all indices are in range(32)
|
||||
atri = a0 // 2 + 1 + vi, a1 // 2 + 1 + vi, a2 // 2 + 1 + vi
|
||||
btri = b0 // 2 + 1 + vi, b1 // 2 + 1 + vi, b2 // 2 + 1 + vi
|
||||
polys.append(atri)
|
||||
polys.append(btri)
|
||||
|
||||
vi = len(verts)
|
||||
|
||||
# write the model file
|
||||
with open("{}.obj".format(name), "w") as f:
|
||||
fprint = lambda *args, **kwargs: print(*args, file=f, **kwargs)
|
||||
|
||||
fprint("mtllib {}.mtl".format(name))
|
||||
|
||||
fprint("o {}".format(name))
|
||||
|
||||
for vert in verts:
|
||||
fprint("v", *("{:.8f}".format(v) for v in vert))
|
||||
|
||||
for tex in texes:
|
||||
fprint("vt", *("{:.8f}".format(v) for v in tex))
|
||||
|
||||
#fprint("g {}".format(name))
|
||||
fprint("usemtl {}".format(name))
|
||||
fprint("s off")
|
||||
|
||||
for poly in polys:
|
||||
fprint("f", *("{}/{}".format(i, i) for i in poly))
|
||||
|
||||
# write the material file
|
||||
with open("{}.mtl".format(name), "w") as f:
|
||||
fprint = lambda *args, **kwargs: print(*args, file=f, **kwargs)
|
||||
|
||||
fprint("newmtl {}".format(name))
|
||||
fprint("Ns 0.0")
|
||||
# i don't know what any of these do but they all look terrible
|
||||
fprint("Ka 1.0 1.0 1.0")
|
||||
fprint("Kd 0.8 0.8 0.8")
|
||||
fprint("Ks 0.0 0.0 0.0")
|
||||
fprint("Ke 0.0 0.0 0.0")
|
||||
fprint("d 1.0")
|
||||
fprint("illum 0")
|
||||
|
||||
fprint("map_Kd {}.bmp".format(name))
|
||||
#fprint("map_Ka {}.bmp".format(name))
|
||||
|
||||
# write the texture file
|
||||
with open("{}.bmp".format(name), "wb") as f:
|
||||
f.write(b'BM')
|
||||
# format: 32-bit BGRA
|
||||
# everything else: sane default
|
||||
f.write(struct.pack("<ihhi", len(rgbs) * 4 + 14, 0, 0, 14 + 40))
|
||||
f.write(struct.pack("<iiihhiiiiii", 40, tw, th, 1, 32, 0, 0, 0, 0, 0, 0))
|
||||
for rgb in reversed(rgbs):
|
||||
r, g, b = rgb
|
||||
a = 0xFF
|
||||
f.write(struct.pack("<BBBB", b, g, r, a))
|
125
phasmo.ahk
Normal file
125
phasmo.ahk
Normal file
|
@ -0,0 +1,125 @@
|
|||
#SingleInstance Force
|
||||
#IfWinActive ahk_exe Phasmophobia.exe
|
||||
Return
|
||||
|
||||
; 1 = EMF Reader
|
||||
; 2 = Flashlight
|
||||
; 3 = Photo Camera
|
||||
; 4 = Lighter
|
||||
; 5 = Candle
|
||||
; 6 = UV Light
|
||||
; 7 = Crucifix
|
||||
; 8 = Video Camera
|
||||
; 9 = Spirit Box
|
||||
; 10 = Salt
|
||||
; 11 = Smudge Sticks
|
||||
; 12 = Tripod
|
||||
; 13 = Strong Flashlight
|
||||
; 14 = Motion Sensor
|
||||
; 15 = Sound Sensor
|
||||
; 16 = Thermometer
|
||||
; 17 = Sanity Pills
|
||||
; 18 = Ghost Writing Book
|
||||
; 19 = Infrared Light Sensor
|
||||
; 20 = Parabolic Microphone
|
||||
; 21 = Glowstick
|
||||
; 22 = Head Mounted Camera
|
||||
|
||||
*,::
|
||||
; add just the stuff you need.
|
||||
Prologue("ahk_class UnityWndClass", mouseX, mouseY)
|
||||
PhasmoAdd(2) ; Flashlight
|
||||
PhasmoAdd(3) ; Photo Camera
|
||||
PhasmoAdd(4) ; Lighter
|
||||
PhasmoAdd(7) ; Crucifix
|
||||
PhasmoAdd(8) ; Video Camera
|
||||
PhasmoAdd(10) ; Salt
|
||||
PhasmoAdd(11) ; Smudge Sticks
|
||||
PhasmoAdd(12,2) ; Tripod (x2)
|
||||
PhasmoAdd(13,2) ; Strong Flashlight (x2)
|
||||
PhasmoAdd(14) ; Motion Sensor
|
||||
PhasmoAdd(16) ; Thermometer
|
||||
PhasmoAdd(17,4) ; Sanity Pills (x4)
|
||||
PhasmoAdd(21) ; Glowstick
|
||||
PhasmoAdd(22) ; Head Mounted Camera
|
||||
Epilogue(mouseX, mouseY)
|
||||
Return
|
||||
|
||||
*;::
|
||||
; add one of everything.
|
||||
Prologue("ahk_class UnityWndClass", mouseX, mouseY)
|
||||
Loop 22
|
||||
PhasmoAdd(A_Index)
|
||||
Epilogue(mouseX, mouseY)
|
||||
Return
|
||||
|
||||
*'::
|
||||
; remove one of everything.
|
||||
Prologue("ahk_class UnityWndClass", mouseX, mouseY)
|
||||
Loop 22
|
||||
PhasmoRemove(A_Index)
|
||||
Epilogue(mouseX, mouseY)
|
||||
Return
|
||||
|
||||
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
|
||||
; internal stuff from hereon! ;
|
||||
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
|
||||
|
||||
GetClientSize(hwnd, ByRef w, ByRef h)
|
||||
{
|
||||
VarSetCapacity(rc, 16)
|
||||
DllCall("GetClientRect", "uint", hwnd, "uint", &rc)
|
||||
w := NumGet(rc, 8, "int")
|
||||
h := NumGet(rc, 12, "int")
|
||||
}
|
||||
|
||||
Prologue(hint, ByRef mouseX, ByRef mouseY)
|
||||
{
|
||||
global winW, winH
|
||||
hwnd := WinExist(hint)
|
||||
GetClientSize(hwnd, winW, winH)
|
||||
SetDefaultMouseSpeed 0
|
||||
SetMouseDelay 0
|
||||
CoordMode Mouse, Screen
|
||||
MouseGetPos mouseX, mouseY ; store mouse position to restore later
|
||||
CoordMode Mouse, Client
|
||||
}
|
||||
|
||||
Epilogue(mouseX, mouseY)
|
||||
{
|
||||
CoordMode Mouse, Screen
|
||||
MouseMove mouseX, mouseY ; restore original mouse position
|
||||
Sleep 100 ; prevent accidental repetition of macro
|
||||
}
|
||||
|
||||
PhasmoClick(relX, relY, n:=1)
|
||||
{
|
||||
global winW, winH
|
||||
fakeW := 1.6 * winH
|
||||
off := (winW - fakeW) / 2
|
||||
MouseMove % off + fakeW * relX, winH * relY
|
||||
Sleep 10
|
||||
Click
|
||||
Loop % n - 1
|
||||
{
|
||||
Sleep 60
|
||||
Click
|
||||
}
|
||||
Sleep 10
|
||||
}
|
||||
|
||||
PhasmoAdd(id, n:=1)
|
||||
{
|
||||
If id between 1 and 15
|
||||
PhasmoClick(0.41, (id + 11.5) / 37.1, n)
|
||||
If id between 16 and 22
|
||||
PhasmoClick(0.72, (id - 3.5) / 37.1, n)
|
||||
}
|
||||
|
||||
PhasmoRemove(id, n:=1)
|
||||
{
|
||||
If id between 1 and 15
|
||||
PhasmoClick(0.435, (id + 11.5) / 37.1, n)
|
||||
If id between 16 and 22
|
||||
PhasmoClick(0.745, (id - 3.5) / 37.1, n)
|
||||
}
|
98
polyphase_halfband/halfband.c
Normal file
98
polyphase_halfband/halfband.c
Normal file
|
@ -0,0 +1,98 @@
|
|||
// C port of http://ldesoras.free.fr/prod.html#src_hiir
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
const double PI = 3.1415926535897932384626433832795;
|
||||
|
||||
void
|
||||
compute_transition_param(double *kp, double *qp, double transition)
|
||||
{
|
||||
double k = *kp;
|
||||
double q = *qp;
|
||||
k = tan((1 - transition*2)*PI/4);
|
||||
k *= k;
|
||||
double kksqrt = pow(1 - k*k, 0.25);
|
||||
double e = 0.5*(1 - kksqrt)/(1 + kksqrt);
|
||||
double e4 = e*e*e*e;
|
||||
q = e*(1 + e4*(2 + e4*(15 + 150*e4)));
|
||||
*kp = k;
|
||||
*qp = q;
|
||||
}
|
||||
|
||||
double
|
||||
compute_acc_numden(double q, int order, int c, int den)
|
||||
{
|
||||
den = den == 1;
|
||||
int i = den;
|
||||
int sign = den ? -1 : 1;
|
||||
double sum = 0;
|
||||
double q_ii;
|
||||
do {
|
||||
int i2 = i + 1 - den;
|
||||
q_ii = pow(q, i*i2);
|
||||
q_ii *= sin((i + i2)*c*PI/order + den*PI/2);
|
||||
q_ii *= sign;
|
||||
sum += q_ii;
|
||||
|
||||
sign = -sign;
|
||||
++i;
|
||||
} while (fabs(q_ii) > 1e-100);
|
||||
return sum;
|
||||
}
|
||||
|
||||
double
|
||||
compute_coef(int c, double k, double q, int order)
|
||||
{
|
||||
double num = compute_acc_numden(q, order, c, 0)*pow(q, 0.25);
|
||||
double den = compute_acc_numden(q, order, c, 1) + 0.5;
|
||||
double ww = num/den;
|
||||
ww *= ww;
|
||||
|
||||
double x = sqrt((1 - ww*k)*(1 - ww/k))/(1 + ww);
|
||||
double coef = (1 - x)/(1 + x);
|
||||
|
||||
return coef;
|
||||
}
|
||||
|
||||
void
|
||||
compute_coefs_spec_order_tbw(double coef_arr[], int n, double transition)
|
||||
{
|
||||
double k;
|
||||
double q;
|
||||
compute_transition_param(&k, &q, transition);
|
||||
const int order = n*2 + 1;
|
||||
|
||||
/*printf("k: %.18f\nq: %.18f\n", k, q);*/
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
coef_arr[i] = compute_coef(i + 1, k, q, order);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 3) {
|
||||
fputs("usage: halfband COUNT TRANSITION\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
double tv[2];
|
||||
for (int i = 1; i <= 2; i++) {
|
||||
tv[i - 1]=strtold(argv[i], NULL);
|
||||
if (errno) {
|
||||
fprintf(stderr, "arg #%i failed to convert to double\n", i);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
int count = (int) tv[0];
|
||||
|
||||
double *coefs = malloc(count*sizeof(double));
|
||||
compute_coefs_spec_order_tbw(coefs, count, tv[1]);
|
||||
for (int i = 0; i < count; i++)
|
||||
printf("%.18f\n", coefs[i]);
|
||||
free(coefs);
|
||||
|
||||
return 0;
|
||||
}
|
246
print_tables/_G.yml
Normal file
246
print_tables/_G.yml
Normal file
|
@ -0,0 +1,246 @@
|
|||
__root: &__root_t0x4004f960
|
||||
_G: *__root_t0x4004f960
|
||||
_VERSION: Lua 5.1
|
||||
arg: &arg_t0x40055cc8
|
||||
"-1": luajit
|
||||
0: run.lua
|
||||
assert: fbuiltin#2
|
||||
bit: &bit_t0x40054d58
|
||||
arshift: fbuiltin#70
|
||||
band: fbuiltin#73
|
||||
bnot: fbuiltin#66
|
||||
bor: fbuiltin#74
|
||||
bswap: fbuiltin#67
|
||||
bxor: fbuiltin#75
|
||||
lshift: fbuiltin#68
|
||||
rol: fbuiltin#71
|
||||
ror: fbuiltin#72
|
||||
rshift: fbuiltin#69
|
||||
tobit: fbuiltin#65
|
||||
tohex: fbuiltin#76
|
||||
collectgarbage: fbuiltin#27
|
||||
coroutine: &coroutine_t0x40051730
|
||||
create: fbuiltin#32
|
||||
resume: fbuiltin#34
|
||||
running: fbuiltin#31
|
||||
status: fbuiltin#30
|
||||
wrap: fbuiltin#36
|
||||
yield: fbuiltin#33
|
||||
debug: &debug_t0x40054740
|
||||
debug: fbuiltin#145
|
||||
getfenv: fbuiltin#134
|
||||
gethook: fbuiltin#144
|
||||
getinfo: fbuiltin#136
|
||||
getlocal: fbuiltin#137
|
||||
getmetatable: fbuiltin#132
|
||||
getregistry: fbuiltin#131
|
||||
getupvalue: fbuiltin#139
|
||||
setfenv: fbuiltin#135
|
||||
sethook: fbuiltin#143
|
||||
setlocal: fbuiltin#138
|
||||
setmetatable: fbuiltin#133
|
||||
setupvalue: fbuiltin#140
|
||||
traceback: fbuiltin#146
|
||||
upvalueid: fbuiltin#141
|
||||
upvaluejoin: fbuiltin#142
|
||||
dofile: fbuiltin#25
|
||||
dump: f0x4005dd40
|
||||
error: fbuiltin#19
|
||||
gcinfo: fbuiltin#26
|
||||
getfenv: fbuiltin#10
|
||||
getmetatable: fbuiltin#8
|
||||
io: &io_t0x40052a90
|
||||
close: fbuiltin#112
|
||||
flush: fbuiltin#115
|
||||
input: fbuiltin#116
|
||||
lines: fbuiltin#118
|
||||
open: fbuiltin#109
|
||||
output: fbuiltin#117
|
||||
popen: fbuiltin#110
|
||||
read: fbuiltin#113
|
||||
stderr: file (0x7ff9dd21f500)
|
||||
stdin: file (0x7ff9dd21e8a0)
|
||||
stdout: file (0x7ff9dd21f5e0)
|
||||
tmpfile: fbuiltin#111
|
||||
type: fbuiltin#119
|
||||
write: fbuiltin#114
|
||||
ipairs: fbuiltin#7
|
||||
jit: &jit_t0x40055318
|
||||
arch: x64
|
||||
attach: fbuiltin#151
|
||||
flush: fbuiltin#149
|
||||
off: fbuiltin#148
|
||||
on: fbuiltin#147
|
||||
opt: &opt_t0x40055bd8
|
||||
start: fbuiltin#163
|
||||
os: Linux
|
||||
status: fbuiltin#150
|
||||
util: &util_t0x400556a0
|
||||
funcbc: fbuiltin#153
|
||||
funcinfo: fbuiltin#152
|
||||
funck: fbuiltin#154
|
||||
funcuvname: fbuiltin#155
|
||||
ircalladdr: fbuiltin#162
|
||||
traceexitstub: fbuiltin#161
|
||||
traceinfo: fbuiltin#156
|
||||
traceir: fbuiltin#157
|
||||
tracek: fbuiltin#158
|
||||
tracemc: fbuiltin#160
|
||||
tracesnap: fbuiltin#159
|
||||
version: LuaJIT 2.0.4
|
||||
version_num: 20004
|
||||
load: fbuiltin#23
|
||||
loadfile: fbuiltin#22
|
||||
loadstring: fbuiltin#24
|
||||
math: &math_t0x40053b60
|
||||
abs: fbuiltin#37
|
||||
acos: fbuiltin#47
|
||||
asin: fbuiltin#46
|
||||
atan: fbuiltin#48
|
||||
atan2: fbuiltin#57
|
||||
ceil: fbuiltin#39
|
||||
cos: fbuiltin#44
|
||||
cosh: fbuiltin#50
|
||||
deg: fbuiltin#54
|
||||
exp: fbuiltin#42
|
||||
floor: fbuiltin#38
|
||||
fmod: fbuiltin#59
|
||||
frexp: fbuiltin#52
|
||||
huge: inf
|
||||
ldexp: fbuiltin#60
|
||||
log: fbuiltin#56
|
||||
log10: fbuiltin#41
|
||||
max: fbuiltin#62
|
||||
min: fbuiltin#61
|
||||
mod: fbuiltin#59
|
||||
modf: fbuiltin#53
|
||||
pi: 3.1415926535898
|
||||
pow: fbuiltin#58
|
||||
rad: fbuiltin#55
|
||||
random: fbuiltin#63
|
||||
randomseed: fbuiltin#64
|
||||
sin: fbuiltin#43
|
||||
sinh: fbuiltin#49
|
||||
sqrt: fbuiltin#40
|
||||
tan: fbuiltin#45
|
||||
tanh: fbuiltin#51
|
||||
module: f0x40051ee0
|
||||
newproxy: fbuiltin#28
|
||||
next: fbuiltin#4
|
||||
os: &os_t0x40052fd0
|
||||
clock: fbuiltin#126
|
||||
date: fbuiltin#127
|
||||
difftime: fbuiltin#129
|
||||
execute: fbuiltin#120
|
||||
exit: fbuiltin#125
|
||||
getenv: fbuiltin#124
|
||||
remove: fbuiltin#121
|
||||
rename: fbuiltin#122
|
||||
setlocale: fbuiltin#130
|
||||
time: fbuiltin#128
|
||||
tmpname: fbuiltin#123
|
||||
package: &package_t0x40051ac8
|
||||
config:
|
||||
/
|
||||
;
|
||||
?
|
||||
!
|
||||
-
|
||||
cpath: /home/notwa/opt/local/lib/?.so;/home/notwa/.luarocks/lib/lua/5.1/?.so;/home/notwa/opt/local/lib/lua/5.1/?.so;./?.so;/usr/local/lib/lua/5.1/?.so;/usr/local/lib/lua/5.1/loadall.so
|
||||
loaded: &loaded_t0x40050b38
|
||||
_G: *__root_t0x4004f960
|
||||
bit: *bit_t0x40054d58
|
||||
coroutine: *coroutine_t0x40051730
|
||||
debug: *debug_t0x40054740
|
||||
extra: &extra_t0x4005cd30
|
||||
add_zeros: f0x4005db58
|
||||
mixed_sorter: f0x4005db98
|
||||
opairs: f0x4005cca8
|
||||
order_keys: f0x4005b2f8
|
||||
strpad: f0x4004f8b8
|
||||
traverse: f0x4005cce8
|
||||
io: *io_t0x40052a90
|
||||
jit: *jit_t0x40055318
|
||||
"jit.opt": *opt_t0x40055bd8
|
||||
"jit.util": *util_t0x400556a0
|
||||
math: *math_t0x40053b60
|
||||
os: *os_t0x40052fd0
|
||||
package: *package_t0x40051ac8
|
||||
pt: &pt_t0x4005ce20
|
||||
__metatable: *pt_t0x4005ce20
|
||||
__call: f0x4005dc98
|
||||
__index: *pt_t0x4005ce20
|
||||
inner: f0x4005dde0
|
||||
outer: f0x4005dd18
|
||||
outer_old: f0x4005dc00
|
||||
safecanon: f0x4005dd60
|
||||
safekey: f0x4005dd80
|
||||
safeval: f0x4005ddc0
|
||||
write: f0x4005dcd8
|
||||
string: *string_t0x400534b0
|
||||
table: *table_t0x400522f8
|
||||
loaders: &loaders_t0x40051c38
|
||||
1: f0x40051c88
|
||||
2: f0x40051cb0
|
||||
3: f0x40051cd8
|
||||
4: f0x40051d00
|
||||
loadlib: f0x40051b58
|
||||
path: /home/notwa/.luarocks/share/lua/5.1/?.lua;/home/notwa/.luarocks/share/lua/5.1/?/init.lua;/home/notwa/opt/local/share/lua/5.1/?.lua;/home/notwa/opt/local/share/lua/5.1/?/init.lua;./?.lua;/home/notwa/opt/local/share/luajit-2.1.0-beta1/?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua
|
||||
preload: &preload_t0x400520c0
|
||||
ffi: f0x40055c80
|
||||
searchpath: f0x40051ba0
|
||||
seeall: f0x40051bf0
|
||||
pairs: fbuiltin#5
|
||||
pcall: fbuiltin#20
|
||||
print: fbuiltin#29
|
||||
rawequal: fbuiltin#14
|
||||
rawget: fbuiltin#12
|
||||
rawset: fbuiltin#13
|
||||
require: f0x40051f28
|
||||
select: fbuiltin#16
|
||||
setfenv: fbuiltin#11
|
||||
setmetatable: fbuiltin#9
|
||||
string: &string_t0x400534b0
|
||||
byte: fbuiltin#78
|
||||
char: fbuiltin#79
|
||||
dump: fbuiltin#85
|
||||
find: fbuiltin#86
|
||||
format: fbuiltin#91
|
||||
gfind: fbuiltin#89
|
||||
gmatch: fbuiltin#89
|
||||
gsub: fbuiltin#90
|
||||
len: fbuiltin#77
|
||||
lower: fbuiltin#83
|
||||
match: fbuiltin#87
|
||||
rep: fbuiltin#81
|
||||
reverse: fbuiltin#82
|
||||
sub: fbuiltin#80
|
||||
upper: fbuiltin#84
|
||||
t: &t_t0x4005e298
|
||||
A: hello
|
||||
B: &B_t0x4005e328
|
||||
a: beep
|
||||
b: boop
|
||||
c: burp
|
||||
d: *d_t0x4005e550
|
||||
C: &d_t0x4005e550
|
||||
a: nude
|
||||
b: dude
|
||||
c: lewd
|
||||
d: *B_t0x4005e328
|
||||
D: goodbye
|
||||
E: *t_t0x4005e298
|
||||
table: &table_t0x400522f8
|
||||
concat: fbuiltin#98
|
||||
foreach: fbuiltin#93
|
||||
foreachi: fbuiltin#92
|
||||
getn: fbuiltin#94
|
||||
insert: fbuiltin#96
|
||||
maxn: fbuiltin#95
|
||||
remove: fbuiltin#97
|
||||
sort: fbuiltin#99
|
||||
tonumber: fbuiltin#17
|
||||
tostring: fbuiltin#18
|
||||
type: fbuiltin#3
|
||||
unpack: fbuiltin#15
|
||||
xpcall: fbuiltin#21
|
69
print_tables/extra.lua
Executable file
69
print_tables/extra.lua
Executable file
|
@ -0,0 +1,69 @@
|
|||
local insert = table.insert
|
||||
local pairs = pairs
|
||||
local rawget = rawget
|
||||
local sort = table.sort
|
||||
local tostring = tostring
|
||||
local type = type
|
||||
|
||||
local function strpad(num, count, pad)
|
||||
num = tostring(num)
|
||||
return (pad:rep(count)..num):sub(#num)
|
||||
end
|
||||
|
||||
local function add_zeros(num, count)
|
||||
return strpad(num, count - 1, '0')
|
||||
end
|
||||
|
||||
local function mixed_sorter(a, b)
|
||||
a = type(a) == 'number' and add_zeros(a, 16) or tostring(a)
|
||||
b = type(b) == 'number' and add_zeros(b, 16) or tostring(b)
|
||||
return a < b
|
||||
end
|
||||
|
||||
-- loosely based on http://lua-users.org/wiki/SortedIteration
|
||||
-- the original didn't make use of closures for who knows why
|
||||
local function order_keys(t)
|
||||
local oi = {}
|
||||
for key in pairs(t) do
|
||||
insert(oi, key)
|
||||
end
|
||||
sort(oi, mixed_sorter)
|
||||
return oi
|
||||
end
|
||||
|
||||
local function opairs(t, cache)
|
||||
local oi = cache and cache[t] or order_keys(t)
|
||||
if cache then
|
||||
cache[t] = oi
|
||||
end
|
||||
local i = 0
|
||||
return function()
|
||||
i = i + 1
|
||||
local key = oi[i]
|
||||
if key ~= nil then return key, t[key] end
|
||||
end
|
||||
end
|
||||
|
||||
local function traverse(path)
|
||||
if not path then return end
|
||||
local parent = _G
|
||||
local key
|
||||
for w in path:gfind("[%w_]+") do
|
||||
if key then
|
||||
parent = rawget(parent, key)
|
||||
if type(parent) ~= 'table' then return end
|
||||
end
|
||||
key = w
|
||||
end
|
||||
if not key then return end
|
||||
return {parent=parent, key=key}
|
||||
end
|
||||
|
||||
return {
|
||||
strpad = strpad,
|
||||
add_zeros = add_zeros,
|
||||
mixed_sorter = mixed_sorter,
|
||||
order_keys = order_keys,
|
||||
opairs = opairs,
|
||||
traverse = traverse,
|
||||
}
|
2
print_tables/init.lua
Normal file
2
print_tables/init.lua
Normal file
|
@ -0,0 +1,2 @@
|
|||
local path = string.gsub(..., "[^.]+$", "")
|
||||
return require(path.."pt")
|
203
print_tables/pt.lua
Executable file
203
print_tables/pt.lua
Executable file
|
@ -0,0 +1,203 @@
|
|||
local path = string.gsub(..., "[^.]+$", "")
|
||||
local extra = require(path.."extra")
|
||||
local opairs = extra.opairs
|
||||
|
||||
local pt = {}
|
||||
pt.__index = pt
|
||||
setmetatable(pt, pt)
|
||||
|
||||
local function rawstr(v)
|
||||
if v == nil then return 'nil' end
|
||||
local mt = getmetatable(v)
|
||||
local ts = mt and rawget(mt, '__tostring')
|
||||
if not ts then return tostring(v) end
|
||||
mt.__tostring = nil
|
||||
local s = tostring(v)
|
||||
mt.__tostring = ts
|
||||
return s
|
||||
end
|
||||
|
||||
local function getaddr(t)
|
||||
return rawstr(t):sub(#type(t) + 3)
|
||||
end
|
||||
|
||||
local function copy(t)
|
||||
-- shallow copy
|
||||
if type(t) ~= 'table' then return end
|
||||
local new = {}
|
||||
for k,v in pairs(t) do
|
||||
new[k] = v
|
||||
end
|
||||
return new
|
||||
end
|
||||
|
||||
function pt.__call(pt, args)
|
||||
-- print a table as semi-valid YAML
|
||||
-- with references to prevent recursion/duplication
|
||||
local t = args.table or args[1]
|
||||
local self = {}
|
||||
setmetatable(self, pt)
|
||||
self.seen = copy(args.seen) or {}
|
||||
self.skipped = copy(args.skipped) or {}
|
||||
self.seen_elsewhere = args.seen or {}
|
||||
self.depth = args.depth or 16
|
||||
self.writer = args.writer or io.write
|
||||
self.skeleton = args.skeleton or false
|
||||
self.outer = args.alt_order and self.outer_old or self.outer
|
||||
self.noncanon = args.noncanon or false
|
||||
self.indent = args.indent or ' '
|
||||
self.queued = {}
|
||||
self.cache = {}
|
||||
self.canonicalized = {}
|
||||
self:inner('__root', t, '')
|
||||
return self.seen
|
||||
end
|
||||
|
||||
function pt:write(...)
|
||||
self.writer(...)
|
||||
end
|
||||
|
||||
function pt:safecanon(k)
|
||||
local s = tostring(k)
|
||||
return s:gsub('[^%w_]', '_')
|
||||
end
|
||||
|
||||
function pt:safekey(k)
|
||||
if type(k) == 'table' then
|
||||
return 't'..getaddr(k)
|
||||
end
|
||||
local s = tostring(k)
|
||||
s = s:gsub('[\r\n]', '')
|
||||
return s:find('[^%w_]') and ('%q'):format(s) or s
|
||||
end
|
||||
|
||||
function pt:safeval(v, indentation)
|
||||
if type(v) == 'function' then
|
||||
return 'f'..getaddr(v)
|
||||
end
|
||||
local s = tostring(v)
|
||||
if type(v) == 'number' then
|
||||
return s
|
||||
end
|
||||
-- TODO: move newline/indentation handling to another function?
|
||||
if s:find('[\r\n]') then
|
||||
s = ('\n'..s):gsub('[\r\n]', '\n'..indentation..self.indent)
|
||||
end
|
||||
--local safe = ('%q'):format(s)
|
||||
--return s == safe:sub(2, -2) and s or safe
|
||||
-- TODO: finish matching valid characters
|
||||
return s:find('[^%w_()[]{}.]') and ('%q'):format(s) or s
|
||||
end
|
||||
|
||||
function pt:inner(k, v, indentation)
|
||||
if type(v) ~= 'table' then
|
||||
if self.skeleton then return end
|
||||
self:write(indentation, self:safekey(k), ': ')
|
||||
self:write(self:safeval(v, indentation), '\n')
|
||||
return
|
||||
end
|
||||
|
||||
local addr = getaddr(v)
|
||||
self:write(indentation, self:safekey(k))
|
||||
|
||||
local canon
|
||||
if not self.noncanon and type(k) ~= 'table' then
|
||||
canon = self.canonicalized[addr]
|
||||
if canon == nil then
|
||||
canon = self:safecanon(k)..'_t'..addr
|
||||
self.canonicalized[addr] = canon
|
||||
end
|
||||
else
|
||||
canon = 't'..addr
|
||||
end
|
||||
|
||||
if #indentation > self.depth or self.skipped[addr] then
|
||||
--self.skipped[addr] = true -- TODO: extra logics
|
||||
self:write(': #', canon, '\n')
|
||||
return
|
||||
end
|
||||
|
||||
if self.seen[addr] or self.queued[addr] then
|
||||
self:write(': *', canon, self.seen_elsewhere[addr] and ' #\n' or '\n')
|
||||
return
|
||||
end
|
||||
|
||||
self.seen[addr] = true
|
||||
|
||||
self:write(': &', canon, '\n')
|
||||
self:outer(v, indentation..self.indent)
|
||||
end
|
||||
|
||||
function pt:outer_old(t, indentation)
|
||||
if type(t) ~= "table" then
|
||||
local s = self:safeval(t, indentation)
|
||||
self:write(indentation, s, '\n')
|
||||
return
|
||||
end
|
||||
|
||||
local ours = {}
|
||||
local not_ours = {}
|
||||
|
||||
for k,v in opairs(t) do
|
||||
if type(v) == 'table' then
|
||||
local addr = getaddr(v)
|
||||
if not (self.queued[addr] or self.seen[addr] or self.skipped[addr]) then
|
||||
self.queued[addr] = true
|
||||
ours[k] = v
|
||||
else
|
||||
not_ours[k] = v
|
||||
end
|
||||
else
|
||||
self:inner(k, v, indentation)
|
||||
end
|
||||
end
|
||||
|
||||
for k,v in opairs(not_ours) do
|
||||
self:inner(k, v, indentation)
|
||||
end
|
||||
|
||||
for k,v in opairs(ours) do
|
||||
self.queued[getaddr(v)] = nil
|
||||
self:inner(k, v, indentation)
|
||||
end
|
||||
|
||||
local mt = getmetatable(t)
|
||||
if mt ~= nil then
|
||||
self:inner('__metatable', mt, indentation)
|
||||
end
|
||||
end
|
||||
|
||||
function pt:outer(t, indentation)
|
||||
if type(t) ~= "table" then
|
||||
local s = self:safeval(t, indentation)
|
||||
self:write(indentation, s, '\n')
|
||||
return
|
||||
end
|
||||
|
||||
local ours = {}
|
||||
|
||||
for k,v in opairs(t, self.cache) do
|
||||
if type(v) == 'table' then
|
||||
local addr = getaddr(v)
|
||||
if not (self.queued[addr] or self.seen[addr] or self.skipped[addr]) then
|
||||
self.queued[addr] = true
|
||||
ours[k] = addr
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local mt = getmetatable(t)
|
||||
if mt ~= nil then
|
||||
self:inner('__metatable', mt, indentation)
|
||||
end
|
||||
|
||||
for k,v in opairs(t, self.cache) do
|
||||
local addr = ours[k]
|
||||
if addr then
|
||||
self.queued[addr] = nil
|
||||
end
|
||||
self:inner(k, v, indentation)
|
||||
end
|
||||
end
|
||||
|
||||
return pt
|
41
print_tables/run.lua
Executable file
41
print_tables/run.lua
Executable file
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/lua
|
||||
local pt = require('pt')
|
||||
|
||||
t = {
|
||||
A = 'hello',
|
||||
B = {
|
||||
a = 'beep',
|
||||
b = 'boop',
|
||||
c = 'burp',
|
||||
},
|
||||
C = {
|
||||
a = 'nude',
|
||||
b = 'dude',
|
||||
c = 'lewd',
|
||||
},
|
||||
D = 'goodbye',
|
||||
}
|
||||
t.B.d = t.C
|
||||
t.C.d = t.B
|
||||
t.E = t
|
||||
|
||||
function dump(t, fn, seen)
|
||||
if t == nil then return end
|
||||
|
||||
local file = io.open(fn, "w")
|
||||
if not file then
|
||||
io.write("Failed opening ", fn, "\n")
|
||||
return
|
||||
end
|
||||
|
||||
local writer = function(...)
|
||||
file:write(...)
|
||||
end
|
||||
seen = pt{t, writer=writer, seen=seen}
|
||||
|
||||
file:close()
|
||||
return seen
|
||||
end
|
||||
|
||||
pt{t}
|
||||
dump(_G, '_G.yml')
|
26
response.txt
Normal file
26
response.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
if you have a transfer function like,
|
||||
|
||||
b2·s² + b1·s + b0
|
||||
H(s) = ———————————————————
|
||||
a2·s² + a1·s + a0
|
||||
|
||||
whereas s would be (1 - z⁻¹)∕(1 + z⁻¹)∕e^(j·ω) in the bilinear transform,
|
||||
you can find its magnitude response with this equation:
|
||||
|
||||
(b2·x)² - (2·b2·b0 - b1²)·W·x·y + (b0·W·y)²
|
||||
|H(j·ω)|² = —————————————————————————————————————————————
|
||||
(a2·x)² - (2·a2·a0 - a1²)·W·x·y + (a0·W·y)²
|
||||
|
||||
(analog) x = ω²
|
||||
y = 1
|
||||
W = ω0²
|
||||
|
||||
(digital) x = sin(ω∕2)²
|
||||
y = cos(ω∕2)²
|
||||
W = tan(ω0∕2)²
|
||||
|
||||
whereas ω is the physical frequency in rads/sec
|
||||
ω0 is the center frequency in rads/sec
|
||||
|
||||
and the phase? maybe some other time
|
||||
note: I'm no math genius and there's probably an error in here
|
121
rng64/rng.md
Normal file
121
rng64/rng.md
Normal file
|
@ -0,0 +1,121 @@
|
|||
# info dump on the RNG in OoT and MM
|
||||
|
||||
if you find any discrepancies, please
|
||||
leave a comment or tweet at [@antiformant][twitter].
|
||||
|
||||
[twitter]: https://twitter.com/antiformant
|
||||
|
||||
## the function itself
|
||||
|
||||
the random number generator in both games is an LCG:
|
||||
https://en.wikipedia.org/wiki/Linear_congruential_generator
|
||||
specifically, it uses the constants from Numerical Recipes in C.
|
||||
|
||||
```c
|
||||
/* the C code looks something like this: */
|
||||
static uint32_t rng_value = 1;
|
||||
uint32_t prng() {
|
||||
/* note: intentional unsigned overflow. */
|
||||
rng_value = rng_value * 1664525 + 1013904223;
|
||||
return rng_value;
|
||||
/* note: in the game, there's some code to reinterpret the value
|
||||
as a floating point number, which I've omitted here. */
|
||||
}
|
||||
```
|
||||
|
||||
if you're interested, you can find the function(s) in any version by searching
|
||||
for F35F in RAM. you should see a 660D nearby, usually a bit before.
|
||||
you can find the rng_value variable
|
||||
by looking at the disassembly of the RNG function.
|
||||
note that there are a few different variations of the function
|
||||
that are not commonly invoked; you can find these the same way.
|
||||
|
||||
here are some known addresses:
|
||||
|
||||
game, version | RNG value | RNG function | variants
|
||||
------------- | --------- | ------------ | --------
|
||||
OoT 1.0 | 80105440 | 800CDC90 | ?
|
||||
OoT 1.2 | 80105A80 | 800CE4D0 | ?
|
||||
MM (J) 1.1 | 8009E890 | 8008797C | 80087940
|
||||
MM (U): | 80097530 | 80086FDC | ?
|
||||
|
||||
## the quirks
|
||||
|
||||
when a new scene is loaded,
|
||||
the RNG value is set directly to the CPU's cycle count.
|
||||
that means, depending on all the code that has been run
|
||||
up to that point, the RNG value is set to a
|
||||
pseudo-unpredictable value when you enter a new area.
|
||||
|
||||
to clarify what a "new scene" being loaded is:
|
||||
|
||||
* loading the title screen
|
||||
* loading a save file
|
||||
* entering a new area (TODO: do rooms within a scene count?)
|
||||
* **not** the N64 logo being shown
|
||||
* **not** the file select screen
|
||||
|
||||
### other invocations
|
||||
|
||||
creating a new file will invoke the RNG
|
||||
to determine the Bomber's Code, etc.
|
||||
obviously, this does not apply to OoT.
|
||||
|
||||
although the GameCube versions don't have an N64 logo,
|
||||
they still do similar initializations before the title screen is shown.
|
||||
|
||||
### emulators
|
||||
|
||||
as far as i know, the cycle counter in emulators
|
||||
(including Virtual Console, excluding CEN64)
|
||||
is very roughly approximated.
|
||||
it's not a critical component to emulating most games,
|
||||
so emulators can skimp on it to achieve better performance.
|
||||
|
||||
this means RNG should be fairly consistent, given identical inputs.
|
||||
*this does not mean RNG will be consistent across emulators.*
|
||||
the plugins you use might affect this as well.
|
||||
|
||||
## exploiting the RNG
|
||||
|
||||
### in Ocarina of Time
|
||||
|
||||
because the title screen sequence starts on Hyrule Field
|
||||
with a ton of actors loaded,
|
||||
the RNG value is updated many times each frame.
|
||||
|
||||
as far as i know, you'd have to be frame perfect to reach the file select screen
|
||||
with a consistent RNG, but i haven't done a lot of testing.
|
||||
maybe there's a part of the title sequence
|
||||
with wider gaps between RNG invocations,
|
||||
giving you a wider window to enter the inputs to reach the file select screen.
|
||||
|
||||
this might not be exploitable anyway due to
|
||||
the reset that occurs when loading scenes, as described earlier.
|
||||
|
||||
### in Majora's Mask
|
||||
|
||||
the first title screen in this game is very simple.
|
||||
only a handful of actors are loaded and executing.
|
||||
as a result, the RNG is only invoked
|
||||
something like every 75 frames *on average.*
|
||||
|
||||
this is a big window to reach the file select screen.
|
||||
*in theory,* you should be able mash A and Start to reach the
|
||||
file select to create a file, and that file will have the same
|
||||
Bomber's code, lottery codes, and Spider House mask order.
|
||||
|
||||
remember that "the same" is specific to each emulator,
|
||||
as described earlier.
|
||||
|
||||
### in practice
|
||||
|
||||
this needs testing.
|
||||
|
||||
i can somewhat consistently reach the file select screen
|
||||
with the same RNG value in Project64 2.2 and Bizhawk 1.12.1.
|
||||
|
||||
Virtual Console and N64 have not been tested.
|
||||
|
||||
this might be useful for the new MM 100% ruleset
|
||||
if it's found to be consistent, but don't hold your breath.
|
171
speedrun_comparison/spddiff.avs
Normal file
171
speedrun_comparison/spddiff.avs
Normal file
|
@ -0,0 +1,171 @@
|
|||
global fontsize = 26
|
||||
|
||||
function DiffClip(clip c, int diff)
|
||||
{ BlankClip(c, diff).Subtitle(String(-diff), align=5, size=c.Height / 8) }
|
||||
|
||||
function PadWithDiff(clip c, int len)
|
||||
{ c.FrameCount < len ? c + DiffClip(c, len - c.FrameCount) : c }
|
||||
|
||||
function DualMonoToStereo(clip left, clip right)
|
||||
{ MergeChannels(ConvertToMono(left), ConvertToMono(right)) }
|
||||
|
||||
function MergeHoriz(clip left, clip right, int audio_index)
|
||||
{
|
||||
v = Overlay(AddBorders(left, 0, 0, right.Width, 0), right, left.Width, 0)
|
||||
return audio_index == 0 \
|
||||
? AudioDub(v, DualMonoToStereo(left, right)) \
|
||||
: audio_index == 1 ? AudioDub(v, left) \
|
||||
: audio_index == 2 ? AudioDub(v, right) \
|
||||
: v
|
||||
}
|
||||
|
||||
function MergeVert(clip top, clip bottom, int audio_index)
|
||||
{
|
||||
v = Overlay(AddBorders(top, 0, 0, 0, bottom.Height), bottom, 0, top.Height)
|
||||
return audio_index == 0 \
|
||||
? AudioDub(v, DualMonoToStereo(top, bottom)) \
|
||||
: audio_index == 1 ? AudioDub(v, top) \
|
||||
: audio_index == 2 ? AudioDub(v, bottom) \
|
||||
: v
|
||||
}
|
||||
|
||||
function Cmp(clip left, clip right)
|
||||
{
|
||||
frames = max(left.FrameCount, right.FrameCount)
|
||||
left = PadWithDiff(left, frames)
|
||||
right = PadWithDiff(right, frames)
|
||||
return MergeHoriz(left, right, 0)
|
||||
}
|
||||
|
||||
function TextHoriz(clip c, int frames, string left, string right)
|
||||
{
|
||||
size = fontsize
|
||||
tleft = BlankClip(c, frames, height=size).Subtitle(left, align=2, size=size)
|
||||
tright = BlankClip(c, frames, height=size).Subtitle(right, align=2, size=size)
|
||||
MergeHoriz(tleft, tright, -1)
|
||||
AddBorders(0, 2, 0, 2)
|
||||
}
|
||||
|
||||
function MakeFrameNumberClip(clip c, int frames)
|
||||
{
|
||||
width = fontsize * 5 / 2 + 1
|
||||
halved = (c.Width - width) / 2
|
||||
ShowFrameNumber(BlankClip(c, frames, width=width, height=fontsize + 1), size=fontsize)
|
||||
Crop(0, 5, -0, -0)
|
||||
AddBorders(halved, 0, halved, 4)
|
||||
AddBorders(0, 2, 0, 2)
|
||||
}
|
||||
|
||||
function AdjustClip(clip c, int offset)
|
||||
{
|
||||
# set up your padding and resizing here
|
||||
PointResize(c, c.Width * 2, c.Height * 2)
|
||||
AddBorders(64 + offset, 0, 64 - offset, 0)
|
||||
MergeVert(MakeFrameNumberClip(last.FrameCount), last, 2)
|
||||
AddBorders(0, 16 - 2, 0, 16)
|
||||
}
|
||||
|
||||
# http://tasvideos.org/485M.html
|
||||
global old_name = "phil"
|
||||
global old_date = "2006-02-25"
|
||||
global old_frames = 32248
|
||||
global old_time = "08:57.47"
|
||||
global old_comment = "http://tasvideos.org/985S.html"
|
||||
AviSource("phil5-ddragon-again.avi")+\
|
||||
AviSource("phil5-ddragon-again_part2.avi")+\
|
||||
AviSource("phil5-ddragon-again_part3.avi")
|
||||
Trim(0, old_frames + 1636)
|
||||
#ShowFrameNumber(scroll=true)
|
||||
AdjustClip(0)#-48)
|
||||
global old = last
|
||||
|
||||
# http://tasvideos.org/3211M.html
|
||||
global new_name = "alyosha"
|
||||
global new_date = "2016-08-28"
|
||||
global new_frames = 31869
|
||||
global new_time = "08:50.28"
|
||||
global new_comment = "http://tasvideos.org/5207S.html"
|
||||
AviSource("alyosha-doubledragon-again.avi")+\
|
||||
AviSource("alyosha-doubledragon-again_part2.avi")+\
|
||||
AviSource("alyosha-doubledragon-again_part3.avi")
|
||||
Trim(0, new_frames + 1636)
|
||||
#ShowFrameNumber(scroll=true)
|
||||
AdjustClip(0)#48)
|
||||
global new = last
|
||||
|
||||
# compare by slice
|
||||
function x(int oldStart, int oldEnd, int newStart, int newEnd, string title)
|
||||
{
|
||||
left = Trim(old, oldStart, oldEnd)
|
||||
right = Trim(new, newStart, newEnd)
|
||||
frames = max(left.FrameCount, right.FrameCount)
|
||||
fc = MakeFrameNumberClip(left, frames)
|
||||
TextHoriz(left, frames, old_name + " (" + old_date + ")", new_name + " (" + new_date + ")")
|
||||
MergeVert(last, TextHoriz(left, frames, String(old_frames) + " frames (" + old_time + ")", string(new_frames) + " frames (" + new_time + ")"), -1)
|
||||
MergeVert(last, TextHoriz(left, frames, old_comment, new_comment), -1)
|
||||
MergeVert(last, Cmp(left, right), 2)
|
||||
MergeVert(last, TextHoriz(left, frames, title, title), 1)
|
||||
MergeVert(last, TextHoriz(left, frames, "in " + String(left.FrameCount) + " frames", "in " + String(Right.FrameCount) + " frames"), 1)
|
||||
MergeVert(last, MergeHoriz(fc, fc, -1), 1)
|
||||
}
|
||||
|
||||
# compare by split (start is last split)
|
||||
global prevOldSplit = 0
|
||||
global prevNewSplit = 0
|
||||
function s(int oldSplit, int newSplit, string title)
|
||||
{
|
||||
ot = prevOldSplit
|
||||
nt = prevNewSplit
|
||||
global prevOldSplit = oldSplit + 1
|
||||
global prevNewSplit = newSplit + 1
|
||||
return x(ot, oldSplit, nt, newSplit, title)
|
||||
}
|
||||
|
||||
# TODO: frames gained/lost in corner per file
|
||||
|
||||
s( 1557, 1547, "first screen scroll")+\
|
||||
s( 1869, 1862, "first door opening")+\
|
||||
s( 2123, 2143, "second screen scroll")+\
|
||||
s( 3041, 3067, "third screen scroll")+\
|
||||
s( 3973, 4017, "door entered")+\
|
||||
s( 4729, 4817, "mission completed")+\
|
||||
s( 5943, 6059, "first screen scroll")+\
|
||||
s( 6489, 6601, "background visible again")+\
|
||||
s( 7118, 7229, "second screen scroll")+\
|
||||
s( 7604, 7713, "top of first ladder")+\
|
||||
s( 7988, 8094, "top of second ladder")+\
|
||||
s( 8316, 8416, "top of third ladder")+\
|
||||
s( 8649, 8749, "first door opening")+\
|
||||
s( 9291, 9393, "mission completed")+\
|
||||
s(10515,10611, "first screen scroll")+\
|
||||
s(11695,11747, "second screen scroll")+\
|
||||
s(12514,12581, "third screen scroll")+\
|
||||
s(13412,13543, "fourth screen scroll")+\
|
||||
s(14588,14773, "door entered")+\
|
||||
s(15369,15548, "platformer begin")+\
|
||||
s(15764,15933, "platformer finished")+\
|
||||
s(16087,16256, "first door opening")+\
|
||||
s(16941,17111, "door entered")+\
|
||||
s(17008,17179, "loaded")+\
|
||||
s(17794,17984, "first screen scroll")+\
|
||||
s(18793,18983, "black screen")+\
|
||||
s(19398,19608, "boss defeated")+\
|
||||
s(20776,20994, "mission completed")+\
|
||||
s(22572,22804, "first screen scroll")+\
|
||||
s(23183,23400, "climbed wall")+\
|
||||
s(24076,24398, "black screen")+\
|
||||
s(24326,24642, "top of first ladder")+\
|
||||
s(24788,25108, "top of second ladder")+\
|
||||
s(25606,25917, "top of third ladder")+\
|
||||
s(26147,26446, "top of fourth ladder")+\
|
||||
s(26283,26642, "black screen")+\
|
||||
s(27623,27788, "first screen scroll")+\
|
||||
s(27951,28118, "first door opening")+\
|
||||
s(28800,28585, "second door opening")+\
|
||||
s(29492,29152, "third door opening")+\
|
||||
s(29660,29320, "fourth door opening")+\
|
||||
s(29944,29545, "fifth door opening")+\
|
||||
s(30683,30290, "sixth door opening")+\
|
||||
s(old_frames,new_frames, "end of input")+\
|
||||
s( 0, 0, "end of game")
|
||||
AddBorders(0, 16, 0, 16)
|
34
starcraft_cdkey/sckey.c
Normal file
34
starcraft_cdkey/sckey.c
Normal file
|
@ -0,0 +1,34 @@
|
|||
int validate(const char *key) {
|
||||
int magic = 3;
|
||||
int count = 0;
|
||||
for (char c; (c = *key); key++) {
|
||||
if (c < '0' || c > '9') continue;
|
||||
int v = c - '0';
|
||||
if (++count == 13) {
|
||||
// final character.
|
||||
return magic % 10 == v;
|
||||
} else {
|
||||
v ^= magic * 2;
|
||||
magic += v;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc == 1) {
|
||||
// self-test.
|
||||
if (!validate("0000-00000-0003")) return -1;
|
||||
if (!validate("1234-56789-0123")) return -1;
|
||||
if (!validate("1337-42069-0008")) return -1;
|
||||
if (!validate("1998-00000-1997")) return -1;
|
||||
if (!validate("3333-33333-3333")) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!validate(argv[i])) ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
507
starcraft_maps/bwmap.py
Normal file
507
starcraft_maps/bwmap.py
Normal file
|
@ -0,0 +1,507 @@
|
|||
import sys
|
||||
import struct
|
||||
|
||||
# sorry not sorry
|
||||
P = struct.pack
|
||||
U = struct.unpack
|
||||
|
||||
# notes:
|
||||
# SCMDraft 2 requires, at bare minimum:
|
||||
scmdraft_req = b"ERA ~DIM ~TILE~UNIT~PUNI~IOWN~THG2~SPRP~WAV ~MASK~STR ~OWNR~SIDE~FORC".split(b"~")
|
||||
|
||||
# Starcraft 1.18+ Melee requires, at bare minimum:
|
||||
# absolutely required:
|
||||
# VER TYPE OWNR SIDE COLR ERA DIM MTXM UNIT THG2 SPRP FORC
|
||||
# not needed at all:
|
||||
# IVER IOWN ISOM TILE DD2
|
||||
# not required for Melee mode (non-UMS):
|
||||
# PUPx UPGx PUNI MASK MRGN WAV PTEx UNIx TECx TRIG MBRF UPRP UPUS SWNM
|
||||
# special cases:
|
||||
# VCOD partly: 34 19 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1F 29 7D A6 D7 B0 00 BB CC 31 24 ED 17 4C 13 0B
|
||||
# STR kinda (can be empty for melee)
|
||||
melee_req = b"VER ~TYPE~VCOD~OWNR~SIDE~COLR~ERA ~DIM ~MTXM~UNIT~THG2~STR ~SPRP~FORC".split(b"~")
|
||||
|
||||
# TODO: try more things to add to this list.
|
||||
ums_req = melee_req + b"MRGN~PTEx~PUPx~TECx~TRIG~UNIx~UPGx~UPRP".split(b"~")
|
||||
|
||||
both_req = set(melee_req + scmdraft_req)
|
||||
|
||||
known_keys = [ # in the order we want to write them.
|
||||
# boring filetype stuff
|
||||
b"TYPE",
|
||||
b"VER ",
|
||||
b"IVER",
|
||||
b"IVE2",
|
||||
b"VCOD",
|
||||
|
||||
b"SPRP", # scenario name and description
|
||||
b"COLR", # player colors
|
||||
b"FORC", # player forces and settings
|
||||
b"SIDE", # player races
|
||||
b"IOWN", # editor player types
|
||||
b"OWNR", # ingame player types
|
||||
|
||||
b"DIM ", # map dimensions
|
||||
b"ERA ", # tileset
|
||||
b"MTXM", # ingame tiles
|
||||
b"TILE", # editor tiles
|
||||
b"ISOM", # editor isometric tiles
|
||||
b"MASK", # fog of war per tile
|
||||
b"DD2 ", # editor doodads
|
||||
b"UNIT", # placed units
|
||||
b"THG2", # placed sprites (e.g. doodad)
|
||||
|
||||
b"MRGN", # locations
|
||||
|
||||
b"UNIS", # unit settings (a bunch of stuff, including names)
|
||||
b"UNIx", # broodwar override
|
||||
|
||||
b"PUNI", # build unit restrictions
|
||||
|
||||
b"PTEC", # tech restrictions
|
||||
b"PTEx", # broodwar override
|
||||
|
||||
b"UPGR", # upgrade restrictions (and defaults, max levels...)
|
||||
b"PUPx", # broodwar override
|
||||
|
||||
b"TECS", # tech settings (costs and times)
|
||||
b"TECx", # broodwar override
|
||||
|
||||
b"UPGS", # upgrade settings (costs and times)
|
||||
b"UPGx", # broodwar override
|
||||
|
||||
b"UPRP", # properties of spawn-with-properties
|
||||
b"UPUS", # booleans of which properties are used
|
||||
|
||||
b"MBRF", # mission briefings (triggers without conditions)
|
||||
b"TRIG", # triggers
|
||||
|
||||
b"SWNM", # switch names
|
||||
b"WAV ", # wav paths (editor only)
|
||||
b"STR ", # string data
|
||||
]
|
||||
|
||||
skippable_keys = set(known_keys).symmetric_difference(both_req)
|
||||
|
||||
vcod_valid = b"\
|
||||
\x34\x19\xCA\x77\x99\xDC\x68\x71\x0A\x60\xBF\xC3\xA7\xE7\x75\xA7\
|
||||
\x1F\x29\x7D\xA6\xD7\xB0\x3A\xBB\xCC\x31\x24\xED\x17\x4C\x13\x0B\
|
||||
\x65\x20\xA2\xB7\x91\xBD\x18\x6B\x8D\xC3\x5D\xDD\xE2\x7A\xD5\x37\
|
||||
\xF6\x59\x64\xD4\x63\x9A\x12\x0F\x43\x5C\x2E\x46\xE3\x74\xF8\x2A\
|
||||
\x08\x6A\x37\x06\x37\xF6\xD6\x3B\x0E\x94\x63\x16\x45\x67\x5C\xEC\
|
||||
\xD7\x7B\xF7\xB7\x1A\xFC\xD4\x9E\x73\xFA\x3F\x8C\x2E\xC0\xE1\x0F\
|
||||
\xD1\x74\x09\x07\x95\xE3\x64\xD7\x75\x16\x68\x74\x99\xA7\x4F\xDA\
|
||||
\xD5\x20\x18\x1F\xE7\xE6\xA0\xBE\xA6\xB6\xE3\x1F\xCA\x0C\xEF\x70\
|
||||
\x31\xD5\x1A\x31\x4D\xB8\x24\x35\xE3\xF8\xC7\x7D\xE1\x1A\x58\xDE\
|
||||
\xF4\x05\x27\x43\xBA\xAC\xDB\x07\xDC\x69\xBE\x0A\xA8\x8F\xEC\x49\
|
||||
\xD7\x58\x16\x3F\xE5\xDB\xC1\x8A\x41\xCF\xC0\x05\x9D\xCA\x1C\x72\
|
||||
\xA2\xB1\x5F\xA5\xC4\x23\x70\x9B\x84\x04\xE1\x14\x80\x7B\x90\xDA\
|
||||
\xFA\xDB\x69\x06\xA3\xF3\x0F\x40\xBE\xF3\xCE\xD4\xE3\xC9\xCB\xD7\
|
||||
\x5A\x40\x01\x34\xF2\x68\x14\xF8\x38\x8E\xC5\x1A\xFE\xD6\x3D\x4B\
|
||||
\x53\x05\x05\xFA\x34\x10\x45\x8E\xDD\x91\x69\xFE\xAF\xE0\xEE\xF0\
|
||||
\xF3\x48\x7E\xDD\x9F\xAD\xDC\x75\x62\x7A\xAC\xE5\x31\x1B\x62\x67\
|
||||
\x20\xCD\x36\x4D\xE0\x98\x21\x74\xFB\x09\x79\x71\x36\x67\xCD\x7F\
|
||||
\x77\x5F\xD6\x3C\xA2\xA2\xA6\xC6\x1A\xE3\xCE\x6A\x4E\xCD\xA9\x6C\
|
||||
\x86\xBA\x9D\x3B\xB5\xF4\x76\xFD\xF8\x44\xF0\xBC\x2E\xE9\x6E\x29\
|
||||
\x23\x25\x2F\x6B\x08\xAB\x27\x44\x7A\x12\xCC\x99\xED\xDC\xF2\x75\
|
||||
\xC5\x3C\x38\x7E\xF7\x1C\x1B\xC5\xD1\x2D\x94\x65\x06\xC9\x48\xDD\
|
||||
\xBE\x32\x2D\xAC\xB5\xC9\x32\x81\x66\x4A\xD8\x34\x35\x3F\x15\xDF\
|
||||
\xB2\xEE\xEB\xB6\x04\xF6\x4D\x96\x35\x42\x94\x9C\x62\x8A\xD3\x61\
|
||||
\x52\xA8\x7B\x6F\xDC\x61\xFC\xF4\x6C\x14\x2D\xFE\x99\xEA\xA4\x0A\
|
||||
\xE8\xD9\xFE\x13\xD0\x48\x44\x59\x80\x66\xF3\xE3\x34\xD9\x8D\x19\
|
||||
\x16\xD7\x63\xFE\x30\x18\x7E\x3A\x9B\x8D\x0F\xB1\x12\xF0\xF5\x8C\
|
||||
\x0A\x78\x58\xDB\x3E\x63\xB8\x8C\x3A\xAA\xF3\x8E\x37\x8A\x1A\x2E\
|
||||
\x5C\x31\xF9\xEF\xE3\x6D\xE3\x7E\x9B\xBD\x3E\x13\xC6\x44\xC0\xB9\
|
||||
\xBC\x3A\xDA\x90\xA4\xAD\xB0\x74\xF8\x57\x27\x89\x47\xE6\x3F\x37\
|
||||
\xE4\x42\x79\x5A\xDF\x43\x8D\xEE\xB4\x0A\x49\xE8\x3C\xC3\x88\x1A\
|
||||
\x88\x01\x6B\x76\x8A\xC3\xFD\xA3\x16\x7A\x4E\x56\xA7\x7F\xCB\xBA\
|
||||
\x02\x5E\x1C\xEC\xB0\xB9\xC9\x76\x1E\x82\xB1\x39\x3E\xC9\x57\xC5\
|
||||
\x19\x24\x38\x4C\x5D\x2F\x54\xB8\x6F\x5D\x57\x8E\x30\xA1\x0A\x52\
|
||||
\x6D\x18\x71\x5E\x13\x06\xC3\x59\x1F\xDC\x3E\x62\xDC\xDA\xB5\xEB\
|
||||
\x1B\x91\x95\xF9\xA7\x91\xD5\xDA\x33\x53\xCE\x6B\xF5\x00\x70\x01\
|
||||
\x7F\xD8\xEE\xE8\xC0\x0A\xF1\xCE\x63\xEB\xB6\xD3\x78\xEF\xCC\xA5\
|
||||
\xAA\x5D\xBC\xA4\x96\xAB\xF2\xD2\x61\xFF\xEA\x9A\xA8\x6A\xED\xA2\
|
||||
\xBD\x3E\xED\x61\x39\xC1\x82\x92\x16\x36\x23\xB1\xB0\xA0\x24\xE5\
|
||||
\x05\x9B\xA7\xAA\x0D\x12\x9B\x33\x83\x92\x20\xDA\x25\xB0\xEC\xFC\
|
||||
\x24\xD0\x38\x23\xFC\x95\xF2\x74\x80\x73\xE5\x19\x97\x50\x7D\x44\
|
||||
\x45\x93\x44\xDB\xA2\xAD\x1D\x69\x44\x14\xEE\xE7\x2C\x7F\x87\xFF\
|
||||
\x38\x9E\x32\xF1\x4D\xBC\x29\xDA\x42\x27\x26\xFE\xC1\xD2\x2B\xA9\
|
||||
\xF6\x42\x7A\x0E\xCB\xE8\x7C\xD1\x0F\x5B\xEC\x56\x69\xB7\x61\x31\
|
||||
\xB4\x6D\xF9\x25\x40\x34\x79\x6D\xFA\x53\xA7\x0B\xFA\xA4\x82\xCE\
|
||||
\xC3\x45\x49\x61\x0D\x45\x2C\x8F\x28\x49\x60\xF7\xF3\x7D\xC9\x1E\
|
||||
\x0F\xD0\x89\xC1\x26\x52\xF8\xD3\x4D\x8F\x35\x14\xBA\x9D\x5F\x0B\
|
||||
\x07\xA9\x4A\x00\xF7\x22\x26\x2F\x3E\x67\xFB\x1F\xA1\x9C\x11\xC6\
|
||||
\x69\x4F\x5D\x66\x58\x34\x15\x90\x6C\xE5\x54\x46\xAF\x5F\x63\xD6\
|
||||
\x8A\x0C\x95\xDF\xBD\x0D\xE4\xAF\xBF\x40\x40\x4C\xA3\xF6\x51\x71\
|
||||
\x29\xED\x26\xF8\x85\x28\x22\xD5\xBF\xBE\xCF\xFA\x28\xC5\x7F\x51\
|
||||
\xB8\x06\x63\x07\xEC\xBD\x8F\x29\xFA\x55\x7E\x71\x1A\x40\x32\x66\
|
||||
\xE8\xD4\xDE\x9D\xD4\x5E\xFC\x93\x7A\x3D\xD5\x3B\xCD\x75\x2E\x80\
|
||||
\x0A\x4F\x74\x87\x1B\xCC\x8F\xEA\x9A\xA9\xDB\x7C\x16\x53\xE5\xEF\
|
||||
\xAB\x78\xC1\x6E\xA4\x72\x89\x5A\x98\x2C\x70\x50\xFB\xA1\xDF\x1F\
|
||||
\x6B\xB7\xD9\x44\x07\x80\x82\x56\xFD\xBF\xC0\x83\x0E\x49\xD0\x5B\
|
||||
\x1E\x68\x6A\x0E\x9A\xC2\x0B\x2F\x8E\x43\xA0\xE1\x99\x0C\xF6\xB2\
|
||||
\xE0\x7A\x1C\x5E\x2C\xC8\xA0\x45\x3C\x0B\xE9\x88\xAC\xB9\x96\xC6\
|
||||
\x74\xAE\x83\x2A\xBB\x13\xFA\x65\xEB\x4F\x1F\xA6\xB0\x8A\x8A\xE1\
|
||||
\x81\xE9\xB8\xB9\xD5\x55\x15\x4E\x45\xF2\xAD\x9B\x3E\xC2\x35\x7E\
|
||||
\x5F\x92\x2E\x72\xB6\x5B\x68\x23\x6E\xC6\x45\x0E\xE9\x3B\x87\xD4\
|
||||
\xF4\x41\xC0\xE3\xA8\x05\x44\xBE\xE4\x0F\x8A\x13\x1A\xC4\x37\xF4\
|
||||
\x5A\x40\x55\xEF\x9D\x79\x1D\x4B\x4A\x79\x3A\x9C\x76\x85\x37\xCC\
|
||||
\x82\x3D\x0F\xB6\x60\xA6\x93\x7E\xBD\x5C\xC2\xC4\x72\xC7\x7F\x90\
|
||||
\x4D\x1B\x96\x10\x13\x05\x68\x68\x35\xC0\x7B\xFF\x46\x85\x43\x2A\
|
||||
\x01\x04\x05\x06\x02\x01\x05\x02\x00\x03\x07\x07\x05\x04\x06\x03\
|
||||
"
|
||||
|
||||
mrgn_default = bytearray(b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" * 255)
|
||||
# set up the "Anywhere" location correctly. this is always location 64.
|
||||
mrgn_default[63*20 + 9] = 0x10
|
||||
mrgn_default[63*20 + 13] = 0x10
|
||||
mrgn_default[63*20 + 16] = 0x03
|
||||
mrgn_default = bytes(mrgn_default)
|
||||
|
||||
def readit(f):
|
||||
f.seek(0, 2)
|
||||
fs = f.tell()
|
||||
f.seek(0)
|
||||
|
||||
src = {}
|
||||
|
||||
while f.tell() < fs:
|
||||
k = f.read(4)
|
||||
|
||||
try:
|
||||
name = k.decode('ascii')
|
||||
except UnicodeDecodeError:
|
||||
print("! skipping invalid section name:", k)
|
||||
size = U("<l", f.read(4))[0]
|
||||
if size > 0:
|
||||
f.read(size)
|
||||
continue
|
||||
|
||||
size = U("<l", f.read(4))[0]
|
||||
if size < 0:
|
||||
print("gotcha!", size)
|
||||
return
|
||||
print(name, size)
|
||||
section = f.read(size)
|
||||
if len(section) != size:
|
||||
print("bad section size:", len(section))
|
||||
print("expected:", size)
|
||||
return
|
||||
|
||||
#if k not in b"ERA ~DIM ~MTXM~THG2~UNIT".split(b"~"): continue
|
||||
|
||||
if k not in src:
|
||||
src[k] = []
|
||||
src[k].append(section)
|
||||
|
||||
return src
|
||||
|
||||
def makestringtable(strings):
|
||||
count = len(strings)
|
||||
|
||||
if len(strings) > 0 and type(strings[0]) != bytes:
|
||||
strings = [str(s).encode("CP1252") for s in strings]
|
||||
|
||||
flat = b"\0" + b"\0".join(strings)
|
||||
|
||||
offsets = []
|
||||
o = count * 2 + 3
|
||||
for s in strings:
|
||||
offsets += [o]
|
||||
o += len(s) + 1
|
||||
|
||||
out = P("<H", count)
|
||||
for o in offsets:
|
||||
out += P("<H", o)
|
||||
out += flat
|
||||
|
||||
return out
|
||||
|
||||
def rewrite(src):
|
||||
if b"STR " not in src:
|
||||
return
|
||||
|
||||
ok = b"MRGN~MBRF~TRIG~SPRP~FORC~WAV ~UNIx~SWNM".split(b"~")
|
||||
|
||||
refs = []
|
||||
|
||||
def mark(k, v, i, ki=0, extra=None):
|
||||
num = v[i] + v[i+1]*256
|
||||
if num != 0:
|
||||
print("ref {:04X} found at {}[{}]".format(num, k, i))
|
||||
ref = [k, ki, i, num, extra]
|
||||
refs.append(ref)
|
||||
|
||||
for k, a in src.items():
|
||||
if k not in ok:
|
||||
continue
|
||||
|
||||
if k == b"MRGN":
|
||||
for ki, v in enumerate(a):
|
||||
for i in range(0, len(v), 20):
|
||||
mark(k, v, i+16, ki)
|
||||
|
||||
if k == b"SPRP":
|
||||
for ki, v in enumerate(a):
|
||||
mark(k, v, 0, ki)
|
||||
mark(k, v, 2, ki)
|
||||
|
||||
if k == b"FORC":
|
||||
for ki, v in enumerate(a):
|
||||
# TODO: handle truncated FORC.
|
||||
mark(k, v, 8, ki)
|
||||
mark(k, v, 10, ki)
|
||||
mark(k, v, 12, ki)
|
||||
mark(k, v, 14, ki)
|
||||
|
||||
if k == b"WAV ":
|
||||
for ki, v in enumerate(a):
|
||||
for i in range(0, 512, 2):
|
||||
if v[i] != 0 and v[i+1] != 0:
|
||||
mark(k, v, i, ki)
|
||||
|
||||
if k == b"UNIx":
|
||||
for ki, v in enumerate(a):
|
||||
uc = 228
|
||||
stringstart = uc + uc*4 + uc*2 + uc + uc*2 + uc*2 + uc*2
|
||||
for i in range(stringstart, stringstart + uc*2, 2):
|
||||
if v[i] != 0 and v[i+1] != 0:
|
||||
mark(k, v, i, ki)
|
||||
|
||||
if k == b"SWNM":
|
||||
for ki, v in enumerate(a):
|
||||
for i in range(0, 1024, 4):
|
||||
if v[i] != 0 and v[i+1] != 0:
|
||||
mark(k, v, i, ki)
|
||||
|
||||
if k == b"TRIG" or k == b"MBRF":
|
||||
for ki, v in enumerate(a):
|
||||
# trigger size: (20)*16 + (32)*64 + (4+28) = 2400
|
||||
for i in range(0, len(v), 2400):
|
||||
# iterate through each of the 64 actions per trigger.
|
||||
for j in range(20*16, 2400, 32):
|
||||
atype = v[i+j+26]
|
||||
if atype == 0:
|
||||
continue
|
||||
#full = U("<l", v[i+j+4:i+j+4+4])[0]
|
||||
#if full != 0: print("DEBUG:", full, atype)
|
||||
#full = U("<l", v[i+j+8:i+j+8+4])[0]
|
||||
#if full != 0: print("DEBUG:", full, atype)
|
||||
mark(k, v, i+j+4, ki)
|
||||
mark(k, v, i+j+8, ki, "wav")
|
||||
|
||||
strings = []
|
||||
wavstrings = []
|
||||
|
||||
# dereference.
|
||||
STR = src[b"STR "][0] # TODO: rename
|
||||
for ref in refs:
|
||||
k, ki, i, num, extra = ref
|
||||
offset = STR[num*2] + STR[num*2+1]*256
|
||||
null = STR.find(b'\0', offset)
|
||||
string = STR[offset:null]
|
||||
#print("found string at {}[{}] + {:04X} (ref {:04X}):".format(k, ki, offset, num))
|
||||
#print(string.decode('CP949', errors='replace'))
|
||||
if string not in strings: # FIXME: potentially slow.
|
||||
strings.append(string)
|
||||
if extra == "wav":
|
||||
wavstrings.append(string)
|
||||
|
||||
# create new table.
|
||||
src[b"STR "][0] = makestringtable(strings)
|
||||
|
||||
# update references to point at the new table.
|
||||
for ref in refs:
|
||||
k, ki, i, num, extra = ref
|
||||
# TODO: don't repeat ourselves.
|
||||
offset = STR[num*2] + STR[num*2+1]*256
|
||||
null = STR.find(b'\0', offset)
|
||||
string = STR[offset:null]
|
||||
|
||||
assert string in strings # FIXME: potentially slow.
|
||||
|
||||
si = strings.index(string) # FIXME: potentially slow.
|
||||
ba = bytearray(src[k][ki]) # FIXME: potentially slow.
|
||||
ba[i+0] = (1 + si) % 256
|
||||
ba[i+1] = (1 + si) // 256
|
||||
src[k][ki] = bytes(ba) # FIXME: potentially slow.
|
||||
|
||||
# fix wav table.
|
||||
# NOTE: since we're dealing with raw .chk and not .mpq,
|
||||
# you still need to reimport the wavs with an MPQ editor!
|
||||
wavs = bytearray(b'\0\0\0\0' * 512)
|
||||
for i, string in enumerate(wavstrings):
|
||||
assert string in strings # FIXME: potentially slow.
|
||||
si = strings.index(string) # FIXME: potentially slow.
|
||||
wavs[i*4+0] = (1 + si) % 256
|
||||
wavs[i*4+1] = (1 + si) // 256
|
||||
|
||||
src[b"WAV "] = [bytes(wavs)]
|
||||
|
||||
def section(k, v):
|
||||
assert type(k) == bytes, type(k)
|
||||
assert type(v) == bytes, type(v)
|
||||
assert len(k) == 4, k
|
||||
return k + P("<L", len(v)) + v
|
||||
|
||||
def check_dim(v):
|
||||
w, h = U("<HH", v)
|
||||
if w not in (64, 96, 128, 192, 256):
|
||||
return False
|
||||
if h not in (64, 96, 128, 192, 256):
|
||||
return False
|
||||
return True
|
||||
|
||||
def writeit(f, src):
|
||||
wroteonce = {}
|
||||
def W(k, v):
|
||||
wroteonce[k] = True
|
||||
f.write(section(k, v))
|
||||
|
||||
# set some essentials that there's no need to change.
|
||||
# (unless you're writing expansionless maps for some reason)
|
||||
src[b"TYPE"] = [b"RAWB"]
|
||||
src[b"VER "] = [b"\315\0"]
|
||||
src[b"IVER"] = [b"\12\0"]
|
||||
src[b"IVE2"] = [b"\13\0"]
|
||||
src[b"VCOD"] = [vcod_valid]
|
||||
|
||||
if b"TILE" not in src:
|
||||
src[b"TILE"] = src[b"MTXM"]
|
||||
|
||||
w, h = 0, 0
|
||||
|
||||
for k, a in src.items():
|
||||
# TODO: consider removing this since we check in the write func anyway.
|
||||
assert type(k) == bytes
|
||||
assert type(a) == list
|
||||
assert len(k) == 4
|
||||
|
||||
if k == b"DIM ": # TODO: move out of loop.
|
||||
a = [v for v in a if check_dim(v)]
|
||||
w, h = U("<HH", a[0])
|
||||
|
||||
placed_starts = [False] * 12
|
||||
k = b"UNIT"
|
||||
if k in src:
|
||||
for ki, v in enumerate(src[k]):
|
||||
for i in range(0, len(v), 36):
|
||||
unit = v[i:i+36]
|
||||
uid = unit[8] + unit[9]*256
|
||||
if uid != 214:
|
||||
continue
|
||||
pi = unit[16]
|
||||
if pi >= 12:
|
||||
print("# ignoring start location for player", pi)
|
||||
placed_starts[pi] = True
|
||||
|
||||
k = b"ERA "
|
||||
if k in src:
|
||||
for ki, v in enumerate(src[k]):
|
||||
era = U("<H", v)[0]
|
||||
era &= 7
|
||||
src[k][ki] = P("<H", era)
|
||||
|
||||
assert b"DIM " in src # TODO: try to guess map dimensions.
|
||||
|
||||
if b"COLR" not in src:
|
||||
src[b"COLR"] = [b"\0\1\2\3\4\5\6\7"]
|
||||
|
||||
# SCMDraft 2 seems to require this to be the correct length.
|
||||
if b"MASK" not in src or len(src[b"MASK"][0]) != w * h:
|
||||
src[b"MASK"] = [b"\xFF" * (w * h)]
|
||||
|
||||
if b"STR " not in src:
|
||||
src[b"STR "] = [b""]
|
||||
|
||||
# SCMDraft 2 calls this "player settings" in its errors.
|
||||
if b"OWNR" not in src:
|
||||
b = b""
|
||||
for i in range(12):
|
||||
b += b"\6" if placed_starts[i] else b"\0"
|
||||
src[b"OWNR"] = [b]
|
||||
assert len(b) == 12, b
|
||||
|
||||
# SCMDraft 2 calls this "player settings" in its errors.
|
||||
if b"SIDE" not in src:
|
||||
src[b"SIDE"] = [b"\5\5\5\5\5\5\5\5\7\7\7\4"]
|
||||
|
||||
if b"FORC" not in src:
|
||||
b = P("<BBBBBBBBHHHHBBBB",
|
||||
0,0,0,0,0,0,0,0, # player->force mapping
|
||||
0,0,0,0, # strings for forces
|
||||
1,1,1,1, # bitmasks: randstart, ally, allyvic, vis, unused...
|
||||
)
|
||||
src[b"FORC"] = [b]
|
||||
assert len(b) == 20, b
|
||||
|
||||
if b"IOWN" not in src:
|
||||
# FIXME: possibly invalid.
|
||||
b = b""
|
||||
for i in range(8):
|
||||
b += b"\6" if placed_starts[i] else b"\0"
|
||||
b += b"\0\0\0\7"
|
||||
src[b"IOWN"] = [b]
|
||||
assert len(b) == 12, b
|
||||
|
||||
if b"MRGN" not in src:
|
||||
src[b"MRGN"] = [mrgn_default]
|
||||
|
||||
if b"THG2" not in src:
|
||||
src[b"THG2"] = [b""]
|
||||
|
||||
if b"SPRP" not in src:
|
||||
src[b"SPRP"] = [b"\0\0\0\0"]
|
||||
|
||||
if b"WAV " not in src:
|
||||
src[b"WAV "] = [b"\0\0\0\0" * 512]
|
||||
|
||||
#if b"ISOM" not in src:
|
||||
# size = (w // 2 + 1) * (h + 1) * 4
|
||||
# src[b"ISOM"] = [b'\0' * size]
|
||||
|
||||
if b"PUNI" not in src:
|
||||
src[b"PUNI"] = [b"\1" * 5700]
|
||||
|
||||
done = {}
|
||||
for k in known_keys:
|
||||
if k in src:
|
||||
for v in src[k]:
|
||||
W(k, v)
|
||||
done[k] = True
|
||||
|
||||
for k, v in src.items():
|
||||
if not done[k]:
|
||||
print("# deferred write:", k)
|
||||
W(k, v)
|
||||
|
||||
for k in known_keys:
|
||||
if k not in skippable_keys and k not in wroteonce:
|
||||
print("# never wrote section:", k)
|
||||
|
||||
for k in scmdraft_req:
|
||||
if k not in wroteonce:
|
||||
print("# map might not open in SCMDraft 2. missing", k)
|
||||
for k in melee_req:
|
||||
if k not in wroteonce:
|
||||
print("# map might not open in StarCraft (Melee). missing", k)
|
||||
for k in ums_req:
|
||||
if k not in wroteonce:
|
||||
print("# map might not open in StarCraft (Use Map Settings). missing", k)
|
||||
|
||||
def run(args):
|
||||
for fn in args:
|
||||
with open(fn, 'rb') as f:
|
||||
src = readit(f)
|
||||
|
||||
if src is None:
|
||||
print("! failed to rewrite", fn) # FIXME: reuse of terminology.
|
||||
ofn = fn.replace('.chk', '') + '.x.chk'
|
||||
assert fn != ofn, ofn
|
||||
rewrite(src)
|
||||
with open(ofn, 'wb') as f:
|
||||
writeit(f, src)
|
||||
|
||||
if __name__ == '__main__':
|
||||
ret = run(sys.argv[1:])
|
||||
sys.exit(ret)
|
156
string_tensions/data.py
Executable file
156
string_tensions/data.py
Executable file
|
@ -0,0 +1,156 @@
|
|||
# (product name, unit weight)
|
||||
|
||||
# D'Addario stock via http://www.daddario.com/upload/tension_chart_13934.pdf
|
||||
# Circle K String stock http://circlekstrings.com/CKSIMAGES/UnitWeightChart130105.pdf
|
||||
|
||||
# string names don't necessarily match up with their actual product names
|
||||
|
||||
daddario_plain_steel = (
|
||||
('DAPL007' , .00001085),
|
||||
('DAPL008' , .00001418),
|
||||
('DAPL0085', .00001601),
|
||||
('DAPL009' , .00001794),
|
||||
('DAPL0095', .00001999),
|
||||
('DAPL010' , .00002215),
|
||||
('DAPL0105', .00002442),
|
||||
('DAPL011' , .00002680),
|
||||
('DAPL0115', .00002930),
|
||||
('DAPL012' , .00003190),
|
||||
('DAPL013' , .00003744),
|
||||
('DAPL0135', .00004037),
|
||||
('DAPL014' , .00004342),
|
||||
('DAPL015' , .00004984),
|
||||
('DAPL016' , .00005671),
|
||||
('DAPL017' , .00006402),
|
||||
('DAPL018' , .00007177),
|
||||
('DAPL019' , .00007997),
|
||||
('DAPL020' , .00008861),
|
||||
('DAPL022' , .00010722),
|
||||
('DAPL024' , .00012760),
|
||||
('DAPL027' , .00014975),
|
||||
)
|
||||
|
||||
daddario_nickle_wound = ( # XL
|
||||
('DANW017' , .00005524),
|
||||
('DANW018' , .00006215),
|
||||
('DANW019' , .00006947),
|
||||
('DANW020' , .00007495),
|
||||
('DANW021' , .00008293),
|
||||
('DANW022' , .00009184),
|
||||
('DANW024' , .00010857),
|
||||
('DANW025*', .00011875), # from the EXL110BT, an approximation
|
||||
('DANW026' , .00012671),
|
||||
('DANW028' , .00014666),
|
||||
('DANW030' , .00017236),
|
||||
('DANW032' , .00019347),
|
||||
('DANW034' , .00021590),
|
||||
('DANW036' , .00023964),
|
||||
('DANW037*', .00024872), # from the EXL115BT, an approximation
|
||||
('DANW038' , .00026471),
|
||||
('DANW039' , .00027932),
|
||||
('DANW040*', .00029570), # from the EXL120BT, an approximation
|
||||
('DANW042' , .00032279),
|
||||
('DANW044' , .00035182),
|
||||
('DANW046' , .00038216),
|
||||
('DANW048' , .00041382),
|
||||
('DANW049' , .00043014),
|
||||
('DANW050*', .00044720), # from the EXL115BT, an approximation
|
||||
('DANW052' , .00048109),
|
||||
('DANW054' , .00053838),
|
||||
('DANW056' , .00057598),
|
||||
('DANW059' , .00064191),
|
||||
('DANW060' , .00066542),
|
||||
('DANW062' , .00070697),
|
||||
('DANW064' , .00074984),
|
||||
('DANW066' , .00079889),
|
||||
('DANW068' , .00084614),
|
||||
('DANW070' , .00089304),
|
||||
('DANW072' , .00094124),
|
||||
('DANW074' , .00098869),
|
||||
('DANW080' , .00115011),
|
||||
)
|
||||
|
||||
kalium_plain = (
|
||||
('CKPL008 ',.0000142401458191),
|
||||
('CKPL0085',.00001607510288),
|
||||
('CKPL009', .0000180219146483),
|
||||
('CKPL0095',.00002008032129),
|
||||
('CKPL010', .0000222518914107),
|
||||
('CKPL0105',.00002453144932),
|
||||
('CKPL011', .0000269251480883),
|
||||
('CKPL0115',.00002942561205),
|
||||
('CKPL012', .0000320389593746),
|
||||
('CKPL0125',.00003476567932),
|
||||
('CKPL013', .0000376052948255),
|
||||
('CKPL0135',.00004055150041),
|
||||
('CKPL014', .000043607),
|
||||
('CKPL015', .000050050),
|
||||
('CKPL016', .000056961),
|
||||
('CKPL017', .000064300),
|
||||
('CKPL018', .000072088),
|
||||
('CKPL019', .000080360),
|
||||
('CKPL020', .000089031),
|
||||
('CKPL021', .000098155),
|
||||
('CKPL022', .000107666),
|
||||
('CKPL023', .000117702),
|
||||
)
|
||||
|
||||
kalium_hybrid_wound = (
|
||||
('CKHW021', .000093873),
|
||||
('CKHW022', .000103500),
|
||||
('CKHW023', .000113985),
|
||||
('CKHW024', .000124963),
|
||||
('CKHW025', .000136054),
|
||||
('CKHW026', .000144691),
|
||||
('CKHW027', .000153146),
|
||||
('CKHW028', .000161203),
|
||||
('CKHW029', .000178551),
|
||||
('CKHW031', .000198902),
|
||||
('CKHW033', .000223217),
|
||||
('CKHW035', .000249034),
|
||||
('CKHW037', .000276237),
|
||||
('CKHW039', .000304788),
|
||||
('CKHW041', .000334965),
|
||||
('CKHW043', .000366357),
|
||||
('CKHW045', .000404956),
|
||||
('CKHW047', .000447408),
|
||||
('CKHW049', .000475438),
|
||||
('CKHW051', .000512645),
|
||||
('CKHW053', .000551898),
|
||||
('CKHW055', .000584407),
|
||||
('CKHW057', .000625704),
|
||||
('CKHW059', .000679149),
|
||||
('CKHW061', .000720293),
|
||||
('CKHW063', .000765973),
|
||||
('CKHW065', .000821116),
|
||||
('CKHW067', .000870707),
|
||||
('CKHW070', .000939851),
|
||||
('CKHW073', .001021518),
|
||||
('CKHW076', .001110192),
|
||||
('CKHW079', .001188974),
|
||||
('CKHW082', .001293598),
|
||||
('CKHW086', .001416131),
|
||||
('CKHW090', .001544107),
|
||||
('CKHW094', .001677765),
|
||||
('CKHW098', .001831487),
|
||||
('CKHW102', .001986524),
|
||||
('CKHW106', .002127413),
|
||||
('CKHW112', .002367064),
|
||||
('CKHW118', .002616406),
|
||||
('CKHW124', .002880915),
|
||||
('CKHW130', .003154996),
|
||||
('CKHW136', .003441822),
|
||||
('CKHW142', .003741715),
|
||||
('CKHW150', .004051506),
|
||||
('CKHW158', .004375389),
|
||||
('CKHW166', .005078724),
|
||||
('CKHW174', .005469937),
|
||||
('CKHW182', .006071822),
|
||||
('CKHW190', .006605072),
|
||||
('CKHW200', .007311717),
|
||||
('CKHW210', .008037439),
|
||||
('CKHW222', .009091287),
|
||||
('CKHW232', .009888443),
|
||||
('CKHW244', .010907182),
|
||||
('CKHW254', .011787319),
|
||||
)
|
50
string_tensions/notes.py
Executable file
50
string_tensions/notes.py
Executable file
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
A = 440
|
||||
notes = {
|
||||
'C' : 0,
|
||||
'D' : 2,
|
||||
'E' : 4,
|
||||
'F' : 5,
|
||||
'G' : 7,
|
||||
'A' : 9,
|
||||
'B' : 11,
|
||||
}
|
||||
|
||||
rel = (2**(1/12.))
|
||||
def note2freq(name):
|
||||
sharp = name[1] == '#'
|
||||
flat = name[1] == 'b'
|
||||
if sharp or flat:
|
||||
note = name[0:1]
|
||||
octave = int(name[2])
|
||||
else:
|
||||
note = name[0]
|
||||
octave = int(name[1])
|
||||
num = notes[note]
|
||||
if sharp:
|
||||
num += 1
|
||||
if flat:
|
||||
num -= 1
|
||||
fullnum = num + 12*(octave - 5)
|
||||
return A*rel**(fullnum + 3)
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_fmt = '{:3} gave {: 9.2f} Hz\nexpected {: 9.2f} Hz'
|
||||
def test(name, expected):
|
||||
print(test_fmt.format(name, note2freq(name), expected))
|
||||
|
||||
test('C2' , 65.41)
|
||||
test('Ab4', 415.30)
|
||||
test('A4' , 440.00)
|
||||
test('B4' , 493.88)
|
||||
test('B#4', 523.25)
|
||||
test('Cb5', 493.88)
|
||||
test('C5' , 523.25)
|
||||
print()
|
||||
test('E4' , 329.63)
|
||||
test('B3' , 246.94)
|
||||
test('G3' , 196.00)
|
||||
test('D3' , 146.83)
|
||||
test('A2' , 110.00)
|
||||
test('E2' , 82.41)
|
81
string_tensions/run.py
Executable file
81
string_tensions/run.py
Executable file
|
@ -0,0 +1,81 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
from strings import print_ideal_stock
|
||||
|
||||
in_mm = 25.4
|
||||
default_scale_length = 648/in_mm
|
||||
|
||||
sets = """
|
||||
regular light
|
||||
E4 16 PD
|
||||
B3 16 PD
|
||||
G3 16 PD
|
||||
D3 16 WD
|
||||
A2 16 WD
|
||||
E2 16 WD
|
||||
|
||||
jazz medium
|
||||
E4 24 PD
|
||||
B3 24 PD
|
||||
G3 24 WD
|
||||
D3 24 WD
|
||||
A2 24 WD
|
||||
E2 24 WD
|
||||
|
||||
regular light (DADGAD)
|
||||
D4 16 PD
|
||||
A3 16 PD
|
||||
G3 16 PD
|
||||
D3 16 WD
|
||||
A2 16 WD
|
||||
D2 16 WD
|
||||
|
||||
fanned-fret bass
|
||||
G2 35 WC 34.00
|
||||
D2 35 WC 34.75
|
||||
A1 35 WC 35.50
|
||||
E1 35 WC 36.25
|
||||
B0 35 WC 37.00
|
||||
|
||||
regular light (Open G 7-string)
|
||||
D4 16 PD
|
||||
B3 16 PD
|
||||
G3 16 PD
|
||||
D3 16 WD
|
||||
B2 16 WD
|
||||
G2 16 WD
|
||||
D2 16 WD
|
||||
"""
|
||||
|
||||
string_sets = {}
|
||||
sets = sets+'\n\n'
|
||||
title = None
|
||||
for line in sets.splitlines():
|
||||
if not line:
|
||||
title = None
|
||||
continue
|
||||
if not title:
|
||||
title = line
|
||||
string_sets[title] = []
|
||||
else:
|
||||
fields = line.split()
|
||||
note, tension = fields[0:2]
|
||||
tension = int(tension)
|
||||
|
||||
req = ''
|
||||
if len(fields) > 2:
|
||||
req = fields[2]
|
||||
|
||||
length = None
|
||||
if len(fields) > 3:
|
||||
length = float(fields[3])
|
||||
|
||||
string = (note, tension, req, length)
|
||||
string_sets[title].append(string)
|
||||
|
||||
print('for a scale length of {:>5.2f} inches'.format(default_scale_length))
|
||||
for name, strings in sorted(string_sets.items()):
|
||||
print()
|
||||
print('"{}"'.format(name))
|
||||
print_ideal_stock(strings, default_scale_length)
|
||||
|
84
string_tensions/run2.py
Executable file
84
string_tensions/run2.py
Executable file
|
@ -0,0 +1,84 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
from strings import print_tensions
|
||||
|
||||
in_mm = 25.4
|
||||
default_scale_length = 648/in_mm
|
||||
|
||||
sets = """
|
||||
E standard (super light balanced)
|
||||
E4 DAPL009
|
||||
B3 DAPL012
|
||||
G3 DAPL015
|
||||
D3 DANW022
|
||||
A2 DANW030
|
||||
E2 DANW040
|
||||
|
||||
E standard (medium balanced)
|
||||
E4 DAPL011
|
||||
B3 DAPL015
|
||||
G3 DAPL019
|
||||
D3 DANW028
|
||||
A2 DANW037
|
||||
E2 DANW050
|
||||
|
||||
C standard (medium balanced)
|
||||
C4 DAPL011
|
||||
G3 DAPL015
|
||||
D#3 DAPL019
|
||||
A#2 DANW028
|
||||
F2 DANW037
|
||||
C2 DANW050
|
||||
|
||||
C standard (jazz medium)
|
||||
C4 DAPL013
|
||||
G3 DAPL017
|
||||
D#3 DANW026
|
||||
A#2 DANW036
|
||||
F2 DANW046
|
||||
C2 DANW056
|
||||
|
||||
C standard (CKS-G6-14-59mb)
|
||||
C4 CKPL014
|
||||
G3 CKPL019
|
||||
D#3 CKHW025
|
||||
A#2 CKHW033
|
||||
F2 CKHW045
|
||||
C2 CKHW059
|
||||
|
||||
B standard (CKS-G6-14-59mb)
|
||||
B3 CKPL014
|
||||
F#3 CKPL019
|
||||
D3 CKHW025
|
||||
A2 CKHW033
|
||||
E2 CKHW045
|
||||
B1 CKHW059
|
||||
|
||||
D standard drop C (medium balanced)
|
||||
D4 DAPL011
|
||||
A3 DAPL015
|
||||
F3 DAPL019
|
||||
C3 DANW028
|
||||
G2 DANW037
|
||||
C2 DANW050
|
||||
"""
|
||||
|
||||
string_sets = {}
|
||||
sets = sets+'\n\n'
|
||||
title = None
|
||||
for line in sets.splitlines():
|
||||
if not line:
|
||||
title = None
|
||||
continue
|
||||
if not title:
|
||||
title = line
|
||||
string_sets[title] = []
|
||||
else:
|
||||
note, string = line.split()
|
||||
string_sets[title].append((note, string))
|
||||
|
||||
print('for a scale length of {:>5.2f} inches'.format(default_scale_length))
|
||||
for name, strings in sorted(string_sets.items()):
|
||||
print()
|
||||
print('"{}"'.format(name))
|
||||
print_tensions(strings, default_scale_length)
|
117
string_tensions/strings.py
Executable file
117
string_tensions/strings.py
Executable file
|
@ -0,0 +1,117 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
from data import *
|
||||
from notes import note2freq
|
||||
|
||||
stock = []
|
||||
stock += daddario_plain_steel
|
||||
stock += daddario_nickle_wound
|
||||
stock += kalium_plain
|
||||
stock += kalium_hybrid_wound
|
||||
|
||||
uw_const = 386.4
|
||||
def uw2tension(uw, freq, SL):
|
||||
return (uw*(2*SL*freq)**2)/uw_const
|
||||
|
||||
def tension2uw(t, freq, SL):
|
||||
return (t*uw_const)/(2*SL*freq)**2
|
||||
|
||||
outfmt = '\
|
||||
{:<8} at {:>6.2f} lb ({:>+4.2f})'
|
||||
finalfmt = '\
|
||||
average: {:>7.2f} lb ({:>+5.2f})\n\
|
||||
total: {:>7.2f} lb ({:>+5.2f})'
|
||||
tension_outfmt = '\
|
||||
{:<3} {:<8} at {:>6.2f} lb'
|
||||
tension_finalfmt = '\
|
||||
average: {:>7.2f} lb\n\
|
||||
total: {:>7.2f} lb'
|
||||
|
||||
def print_ideal_stock(strings, scale_length=25.512):
|
||||
SL = scale_length
|
||||
total_tension = 0
|
||||
total_desired_tension = 0
|
||||
for note, tension, req, length in strings:
|
||||
freq = note2freq(note)
|
||||
if length:
|
||||
SL = length
|
||||
else:
|
||||
SL = scale_length
|
||||
uw = tension2uw(tension, freq, SL)
|
||||
|
||||
kind = len(req) > 0 and req[0]
|
||||
brand = len(req) > 1 and req[1]
|
||||
|
||||
closest = ('n/a', 0)
|
||||
for name, stock_uw in stock:
|
||||
if kind and kind == 'P' and name[2] != 'P':
|
||||
continue
|
||||
if kind and kind == 'W' and name[3] != 'W':
|
||||
continue
|
||||
if brand and brand[0] != name[0]:
|
||||
continue
|
||||
if abs(stock_uw - uw) < abs(closest[1] - uw):
|
||||
closest = (name, stock_uw)
|
||||
|
||||
closest_tension = uw2tension(closest[1], freq, SL)
|
||||
diff = closest_tension - tension
|
||||
print(outfmt.format(closest[0], closest_tension, diff))
|
||||
|
||||
total_tension += closest_tension
|
||||
total_desired_tension += tension
|
||||
|
||||
error = total_tension - total_desired_tension
|
||||
average_tension = total_tension/len(strings)
|
||||
average_error = error/len(strings)
|
||||
print(finalfmt.format(average_tension, average_error, total_tension, error))
|
||||
|
||||
def print_tensions(strings, scale_length=25.512):
|
||||
SL = scale_length
|
||||
total_tension = 0
|
||||
for note, name in strings:
|
||||
freq = note2freq(note)
|
||||
uw = 0
|
||||
for stock_name, stock_uw in stock:
|
||||
if name == stock_name or name + '*' == stock_name:
|
||||
uw = stock_uw
|
||||
break
|
||||
if uw:
|
||||
tension = uw2tension(uw, freq, SL)
|
||||
else:
|
||||
tension = 0
|
||||
print(tension_outfmt.format(note, name, tension))
|
||||
total_tension += tension
|
||||
|
||||
print(tension_finalfmt.format(total_tension/len(strings), total_tension))
|
||||
|
||||
if __name__ == '__main__':
|
||||
# DAd's data is all screwy so we use change scale lengths for a best-fit
|
||||
SL = 25.4825
|
||||
D3 = note2freq('D3')
|
||||
A2 = note2freq('A2')
|
||||
E2 = note2freq('E2')
|
||||
|
||||
test_fmt = '{:8} {:10.8f} == {:10}'
|
||||
def test(name, unit, tension, note):
|
||||
print(test_fmt.format(name, tension2uw(tension, note, SL), unit))
|
||||
|
||||
test('NW024' , '0.00010857', 15.73, D3)
|
||||
test('NW025*', '?' , 17.21, D3)
|
||||
test('NW026' , '0.00012671', 18.38, D3)
|
||||
print()
|
||||
|
||||
test('NW036' , '0.00023964', 19.04, A2)
|
||||
test('NW037*', '? ', 20.23, A2)
|
||||
test('NW038' , '0.00026471', 20.96, A2)
|
||||
print()
|
||||
|
||||
SL = 25.18
|
||||
test('NW039' , '0.00027932', 12.46, E2)
|
||||
test('NW040*', '? ', 13.18, E2)
|
||||
test('NW042' , '0.00032279', 14.37, E2)
|
||||
print()
|
||||
|
||||
SL = 25.02
|
||||
test('NW049' , '0.00043014', 18.97, E2)
|
||||
test('NW050*', '? ', 19.68, E2)
|
||||
test('NW052' , '0.00048109', 21.15, E2)
|
2170
thps1/names.txt
Normal file
2170
thps1/names.txt
Normal file
File diff suppressed because it is too large
Load Diff
168
thps1/thps1.c
Normal file
168
thps1/thps1.c
Normal file
|
@ -0,0 +1,168 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef int32_t s32;
|
||||
typedef uint32_t u32;
|
||||
typedef int64_t s64;
|
||||
typedef uint64_t u64;
|
||||
|
||||
static u64 prng_state = 1;
|
||||
static u32 prng() {
|
||||
prng_state = 3935559000370003845 * prng_state + 1;
|
||||
return prng_state ^ (prng_state >> 32);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
u8 name[13];
|
||||
u8 payload[11];
|
||||
u32 residual;
|
||||
} code_t;
|
||||
|
||||
void translate(u8 *name) {
|
||||
// in-place translation of ascii to alphabetical indices.
|
||||
// the input argument must be able to hold at least 13 characters.
|
||||
// the resulting translation is no longer null-terminated (if the input even was).
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 13; i++) {
|
||||
u8 c = name[i];
|
||||
if (c == '\0') break;
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
name[i] = c - 'a';
|
||||
} else if (c >= 'A' && c <= 'Z') {
|
||||
name[i] = c - 'A';
|
||||
} else {
|
||||
name[i] = 26;
|
||||
}
|
||||
}
|
||||
|
||||
// remaining space gets filled with a null-like character:
|
||||
for (; i < 13; i++) {
|
||||
name[i] = 26;
|
||||
}
|
||||
}
|
||||
|
||||
u32 multu_hi(u32 a, u32 b) {
|
||||
// returns the upper 32-bits of a * b (unsigned).
|
||||
return (u32)(((u64)a * (u64)b) >> 32);
|
||||
}
|
||||
|
||||
s32 mult_lo(s32 a, s32 b) {
|
||||
// returns the lower 32-bits of a * b (signed).
|
||||
return (s32)(((s64)a * (s64)b) & 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void decode(code_t *code) {
|
||||
u32 r = 0;
|
||||
u32 a3 = 0x98534637;
|
||||
|
||||
for (int i = 0; i < 11; i++) {
|
||||
u32 a1 = code->name[i];
|
||||
u32 temp = 0x10000 - (a3 & 0xFFFF);
|
||||
u32 a0 = a1 + 20 + temp;
|
||||
u32 v1 = a0 % 27;
|
||||
code->payload[i] = v1;
|
||||
r += a1 + mult_lo(r, 0x75344393) + 0x92438937;
|
||||
a3 = mult_lo(a3 + v1, 0x34985343) + 0x64358931;
|
||||
}
|
||||
|
||||
code->residual = r;
|
||||
}
|
||||
|
||||
int validate(const code_t *code) {
|
||||
u32 r = code->residual;
|
||||
if (code->name[11] != r % 27) return 0;
|
||||
r /= 27;
|
||||
if (code->name[12] != r % 27) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void print_code(const code_t *code) {
|
||||
for (int i = 0; i < 13; i++) {
|
||||
char c = code->name[i];
|
||||
c = c == 26 ? ' ' : c + 'A';
|
||||
printf("%c", c);
|
||||
}
|
||||
|
||||
printf(" -> ");
|
||||
|
||||
for (int i = 0; i < 11; i++) {
|
||||
char c = code->payload[i];
|
||||
c = c == 26 ? ' ' : c + 'A';
|
||||
printf("%c", c);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int validate_entry(const char *entry) {
|
||||
code_t code = {0};
|
||||
for (int i = 0; i < 13; i++) {
|
||||
code.name[i] = entry[i];
|
||||
if (entry[i] == '\0') break;
|
||||
}
|
||||
|
||||
translate(code.name);
|
||||
decode(&code);
|
||||
int result = validate(&code);
|
||||
if (result) print_code(&code);
|
||||
|
||||
// DEBUG:
|
||||
//if (result) printf("%s\n", entry);
|
||||
//for (i = 0; i < 13; i++) printf(" %02X", code.name[i]); printf("\n");
|
||||
//for (i = 0; i < 11; i++) printf(" %02X", code.payload[i]); printf("\n");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int bruteforce(int count) {
|
||||
/* with a fixed seed, this is useful for testing.
|
||||
the first 10 results should be:
|
||||
AQPIEOJSFIMJE
|
||||
JHVBASITTCRQR
|
||||
RXCUCODXHPAIS
|
||||
GEXEPVFQBBWZN
|
||||
EZRTHUSHOWHYG
|
||||
LBSXAAOTMSUXV
|
||||
WCDKPNSEWDKAF
|
||||
NJVIYIYNRWZJQ
|
||||
RVGLKPYDWYCIA
|
||||
CEIQQHURYAJAV
|
||||
*/
|
||||
|
||||
int found = 0;
|
||||
code_t code = {0};
|
||||
while (found < count) {
|
||||
for (int j = 0; j < 13; j++) code.name[j] = prng() % 27;
|
||||
//for (int j = 3; j < 13; j++) code.name[j] = 26;
|
||||
decode(&code);
|
||||
if (validate(&code)) {
|
||||
found++;
|
||||
print_code(&code);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc == 1) {
|
||||
// self-test. only one code was known prior, so...
|
||||
if (!validate_entry("TYR")) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int invalid_count = 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (!strcmp(arg, "bruteforce")) {
|
||||
invalid_count += !bruteforce(10);
|
||||
} else {
|
||||
invalid_count += !validate_entry(arg);
|
||||
}
|
||||
}
|
||||
return !!invalid_count;
|
||||
}
|
60
tiny_crc32/crc32.c
Normal file
60
tiny_crc32/crc32.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef BUFFER
|
||||
#define BUFFER 4096
|
||||
#endif
|
||||
uint8_t msg[BUFFER];
|
||||
|
||||
/* CRC-32, eg. ethernet */
|
||||
const uint32_t crc32_tbl[] = {
|
||||
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
|
||||
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
|
||||
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
|
||||
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
|
||||
};
|
||||
|
||||
/* the idea is to act on nybbles instead of bytes to require less CPU cache */
|
||||
uint32_t crc32_calc(uint8_t *ptr, int cnt, uint32_t crc)
|
||||
{
|
||||
while (cnt--) {
|
||||
crc = (crc >> 4) ^ crc32_tbl[(crc & 0xf) ^ (*ptr & 0xf)];
|
||||
crc = (crc >> 4) ^ crc32_tbl[(crc & 0xf) ^ (*(ptr++) >> 4)];
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int len;
|
||||
uint32_t v32 = ~0;
|
||||
FILE *f;
|
||||
|
||||
if (argc == 1) {
|
||||
freopen(NULL, "rb", stdin);
|
||||
f = stdin;
|
||||
} else if (argc == 2) {
|
||||
f = fopen(argv[1], "rb");
|
||||
if (f == NULL) {
|
||||
perror(argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
fputs("usage: crc32 [filename]", stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
do {
|
||||
len = fread(msg, 1, BUFFER, f);
|
||||
if (ferror(f)) {
|
||||
perror(NULL);
|
||||
exit(1);
|
||||
}
|
||||
v32 = crc32_calc(msg, len, v32);
|
||||
} while (!feof(f));
|
||||
|
||||
fclose(f);
|
||||
|
||||
printf("%08lX\n", (unsigned long) ~v32);
|
||||
}
|
139
trackmogrify/colors.txt
Normal file
139
trackmogrify/colors.txt
Normal file
|
@ -0,0 +1,139 @@
|
|||
indianRed
|
||||
lightCoral
|
||||
salmon
|
||||
darkSalmon
|
||||
lightSalmon
|
||||
crimson
|
||||
red
|
||||
fireBrick
|
||||
darkRed
|
||||
pink
|
||||
lightPink
|
||||
hotPink
|
||||
deepPink
|
||||
mediumVioletRed
|
||||
paleVioletRed
|
||||
coral
|
||||
tomato
|
||||
orangeRed
|
||||
darkOrange
|
||||
orange
|
||||
yellow
|
||||
lightYellow
|
||||
lemonChiffon
|
||||
lightGoldenrodYellow
|
||||
papayaWhip
|
||||
moccasin
|
||||
peachPuff
|
||||
paleGoldenrod
|
||||
khaki
|
||||
darkKhaki
|
||||
lavender
|
||||
thistle
|
||||
plum
|
||||
violet
|
||||
orchid
|
||||
fuchsia
|
||||
magenta
|
||||
mediumOrchid
|
||||
mediumPurple
|
||||
amethyst
|
||||
blueViolet
|
||||
darkViolet
|
||||
darkOrchid
|
||||
darkMagenta
|
||||
purple
|
||||
indigo
|
||||
slateBlue
|
||||
darkSlateBlue
|
||||
mediumSlateBlue
|
||||
greenYellow
|
||||
chartreuse
|
||||
lawnGreen
|
||||
lime
|
||||
limeGreen
|
||||
paleGreen
|
||||
lightGreen
|
||||
mediumSpringGreen
|
||||
springGreen
|
||||
mediumSeaGreen
|
||||
seaGreen
|
||||
forestGreen
|
||||
green
|
||||
darkGreen
|
||||
yellowGreen
|
||||
oliveDrab
|
||||
olive
|
||||
darkOliveGreen
|
||||
mediumAquamarine
|
||||
darkSeaGreen
|
||||
lightSeaGreen
|
||||
darkCyan
|
||||
teal
|
||||
aqua
|
||||
cyan
|
||||
lightCyan
|
||||
paleTurquoise
|
||||
aquamarine
|
||||
turquoise
|
||||
mediumTurquoise
|
||||
darkTurquoise
|
||||
cadetBlue
|
||||
steelBlue
|
||||
lightSteelBlue
|
||||
powderBlue
|
||||
lightBlue
|
||||
skyBlue
|
||||
lightSkyBlue
|
||||
deepSkyBlue
|
||||
dodgerBlue
|
||||
cornflowerBlue
|
||||
royalBlue
|
||||
blue
|
||||
mediumBlue
|
||||
darkBlue
|
||||
navy
|
||||
midnightBlue
|
||||
cornsilk
|
||||
blanchedAlmond
|
||||
bisque
|
||||
navajoWhite
|
||||
wheat
|
||||
burlyWood
|
||||
tan
|
||||
rosyBrown
|
||||
sandyBrown
|
||||
goldenrod
|
||||
darkGoldenrod
|
||||
peru
|
||||
chocolate
|
||||
saddleBrown
|
||||
sienna
|
||||
brown
|
||||
maroon
|
||||
white
|
||||
snow
|
||||
honeydew
|
||||
mintCream
|
||||
azure
|
||||
aliceBlue
|
||||
ghostWhite
|
||||
whiteSmoke
|
||||
seashell
|
||||
beige
|
||||
oldLace
|
||||
floralWhite
|
||||
ivory
|
||||
antiqueWhite
|
||||
linen
|
||||
lavenderBlush
|
||||
mistyRose
|
||||
gainsboro
|
||||
lightGrey
|
||||
darkGray
|
||||
gray
|
||||
dimGray
|
||||
lightSlateGray
|
||||
slateGray
|
||||
darkSlateGray
|
||||
black
|
161
trackmogrify/modifiers.txt
Normal file
161
trackmogrify/modifiers.txt
Normal file
|
@ -0,0 +1,161 @@
|
|||
america
|
||||
rainbow
|
||||
neon
|
||||
zebra
|
||||
minecraft
|
||||
distance
|
||||
infected
|
||||
old
|
||||
toon
|
||||
spooky
|
||||
graveyard
|
||||
spike
|
||||
ball
|
||||
tube
|
||||
hex
|
||||
donut
|
||||
pill
|
||||
clear
|
||||
party
|
||||
disco
|
||||
dance
|
||||
plant
|
||||
industrial
|
||||
forest
|
||||
alliance
|
||||
logo
|
||||
sponsored
|
||||
pop-up
|
||||
thunder
|
||||
lantern
|
||||
downhill
|
||||
fall
|
||||
lower
|
||||
uphill
|
||||
climb
|
||||
ascent
|
||||
rise
|
||||
elevate
|
||||
above
|
||||
under
|
||||
below
|
||||
chill
|
||||
boring
|
||||
angry
|
||||
never
|
||||
not
|
||||
anti
|
||||
barely
|
||||
slightly
|
||||
kinda
|
||||
so
|
||||
very
|
||||
double
|
||||
super
|
||||
triple
|
||||
mega
|
||||
ultra
|
||||
insanely
|
||||
long
|
||||
marathon
|
||||
short
|
||||
momentary
|
||||
quick
|
||||
fleeting
|
||||
dash
|
||||
monster
|
||||
colossus
|
||||
big
|
||||
giant
|
||||
small
|
||||
mini
|
||||
tiny
|
||||
shrunk
|
||||
micro
|
||||
vast
|
||||
space
|
||||
tight
|
||||
uniform
|
||||
iridescent
|
||||
pearl
|
||||
tron
|
||||
metallic
|
||||
metal
|
||||
copper
|
||||
gold
|
||||
silver
|
||||
platinum
|
||||
brass
|
||||
iron
|
||||
steel
|
||||
aluminum
|
||||
bronze
|
||||
titanium
|
||||
road
|
||||
casual
|
||||
trivial
|
||||
realm
|
||||
safe
|
||||
easy
|
||||
medium
|
||||
advanced
|
||||
hard
|
||||
expert
|
||||
hazardous
|
||||
nightmare
|
||||
doom
|
||||
desaturated
|
||||
mute
|
||||
saturated
|
||||
bright
|
||||
dim
|
||||
stone
|
||||
light
|
||||
dark
|
||||
shadow
|
||||
flame
|
||||
fire
|
||||
ice
|
||||
ooze
|
||||
slime
|
||||
radioactive
|
||||
radiation
|
||||
biohazard
|
||||
sea
|
||||
ocean
|
||||
water
|
||||
marine
|
||||
storm
|
||||
stop
|
||||
morning
|
||||
sunrise
|
||||
noon
|
||||
day
|
||||
afternoon
|
||||
evening
|
||||
sunset
|
||||
night
|
||||
midnight
|
||||
moon
|
||||
fog
|
||||
foggy
|
||||
mist
|
||||
misty
|
||||
gas
|
||||
shiny
|
||||
calm
|
||||
rollercoaster
|
||||
twisted
|
||||
crazy
|
||||
snakey
|
||||
snaky
|
||||
zigzag
|
||||
winding
|
||||
bumpy
|
||||
bouncy
|
||||
corkscrew
|
||||
helix
|
||||
upsidedown
|
||||
inverse
|
||||
inverted
|
||||
ceiling
|
61
twitch_following/following
Normal file
61
twitch_following/following
Normal file
|
@ -0,0 +1,61 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# super quickly hacked together script
|
||||
# for listing your twitch following from the command-line.
|
||||
|
||||
# REQUIREMENTS:
|
||||
# editing this script.
|
||||
# downloading a python script.
|
||||
# python 2 or 3.
|
||||
# a web browser.
|
||||
# curl.
|
||||
# GNU sort.
|
||||
# GNU awk.
|
||||
|
||||
# TODO:
|
||||
# fix known issues.
|
||||
# automatically extract relevant values from a cURL string.
|
||||
# add toggle for colors.
|
||||
# optional CSV output.
|
||||
# automatically download json2?
|
||||
# rewrite in python?
|
||||
|
||||
# fill these in with values extracted from your browser's
|
||||
# "copy as cURL" feature.
|
||||
# 1. open a new tab in Chromium or Firefox; these instructions apply to either.
|
||||
# 2. open the web inspector (ctrl+shift+I) and click on the network tab.
|
||||
# 3. go to https://www.twitch.tv/directory/following/live
|
||||
# make sure this is with the network tab already open!
|
||||
# if it isn't, open it up and just refresh the page.
|
||||
# 4. type "followed" in the filter of the network tab.
|
||||
# 5. right click on the first result and click copy as cURL.
|
||||
# in Chromium, it's in a submenu as "copy as cURL (bash)"
|
||||
# 6. paste into a text editor and extract the following header values:
|
||||
# (each header is specified by a -H flag)
|
||||
authorization="Authorization: OAuth abcdefghijklmnopqrstuvwxyz1234"
|
||||
|
||||
|
||||
json2() {
|
||||
# download this from https://github.com/vi/json2/blob/master/json2
|
||||
# and edit this line accordingly.
|
||||
python3 ~/src/json2/json2 "$@"
|
||||
}
|
||||
|
||||
curl -LsS 'https://gql.twitch.tv/gql' \
|
||||
-H "$authorization" \
|
||||
--data-binary '[{"variables":{"limit":100},"extensions":{},"operationName":"FollowingLive_CurrentUser","query":"query FollowingLive_CurrentUser($limit: Int, $cursor: Cursor) {\n currentUser {\n follows {\n totalCount\n }\n followedLiveUsers(first: $limit, after: $cursor) {\n edges {\n node {\n login\n displayName\n stream {\n game {\n name\n }\n viewersCount\n title\n type\n }\n }\n }\n pageInfo {\n hasNextPage\n }\n }\n }\n}\n"}]' \
|
||||
| json2 | tr -d '\r' | awk '
|
||||
function trunc(s,L) {
|
||||
e = length(s) > L ? "…" : "";
|
||||
return (substr(s, 0, L -(e ? 1 : 0)) e);
|
||||
}
|
||||
$1~/\/stream\/game\/name$/{game=substr($2,2)}
|
||||
$1~/\/stream\/title$/{title=substr($2,2)}
|
||||
$1~/\/login$/{name=substr($2,2)}
|
||||
$1~/\/viewersCount$/{viewers=substr($2,2)}
|
||||
$1~/\/stream\/type$/{
|
||||
printf "\x1b[90m%5s\x1b[0m \x1b[97m%-25s\x1b[0m %s\n \x1b[36m%s\x1b[0m\n",
|
||||
viewers, name, trunc(game, 48), title;
|
||||
}
|
||||
' FPAT='(^[^=]+)|(=.*)'
|
81
warcraft_hash/wc3hash.c
Normal file
81
warcraft_hash/wc3hash.c
Normal file
|
@ -0,0 +1,81 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
const u64 table[16] = {
|
||||
// magic numbers for each possible value of a nybble.
|
||||
0x486E26EEDCAA16B3, 0xE1918EEF202DAFDB,
|
||||
0x341C7DC71C365303, 0x40EF2D3765FD5E49,
|
||||
0xD6057177904ECE93, 0x1C38024F98FD323B,
|
||||
0xE3061AE7A39B0FA1, 0x9797F25FE4444563,
|
||||
0xCD2EC20C8DC1B898, 0x31759633799A306D,
|
||||
0x8C2063852E6E9627, 0x79237D9973922C66,
|
||||
0x8728628D28628824, 0x8F1F7E9625887795,
|
||||
0x296E3281389C0D60, 0x6F4893CA61636542
|
||||
};
|
||||
|
||||
u64 wc3hash(const char *key, size_t len, u64 hash, bool isPath) {
|
||||
// technically there doesn't seem to be a
|
||||
// length argument in the original function,
|
||||
// I'm just adding it so you can hash strings with '\0' in them.
|
||||
|
||||
if (key == NULL)
|
||||
return 0;
|
||||
|
||||
if (hash == 0)
|
||||
hash = 0x7FED7FED7FED7FED;
|
||||
|
||||
u64 state = 0xEEEEEEEEEEEEEEEE;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
u8 v;
|
||||
if (isPath) {
|
||||
char c = key[i];
|
||||
if (c >= 'a' && c <= 'z')
|
||||
c -= 'a' - 'A'; // uppercase
|
||||
if (c == '/')
|
||||
c = '\\'; // DOS-style paths
|
||||
|
||||
v = (u8)c;
|
||||
} else {
|
||||
v = (u8)key[i];
|
||||
}
|
||||
|
||||
hash += state;
|
||||
hash ^= table[v >> 4] + table[v & 0xF];
|
||||
state += state << 5;
|
||||
state += hash + v + 3;
|
||||
}
|
||||
|
||||
if (hash == 0)
|
||||
return 1;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
u64 wc3hashC(const char *key) {
|
||||
// simple interface that only takes a null-terminated string.
|
||||
return wc3hash(key, strlen(key), 0, true);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc == 1) {
|
||||
const char str[] = "IseeDeadPeople";
|
||||
u64 hash = wc3hashC(str);
|
||||
fprintf(stderr, "%" PRIX64 " should equal 701EA16D47F385FC\n", hash);
|
||||
return hash != 0x701EA16D47F385FC;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
u64 hash = wc3hashC(argv[i]);
|
||||
u32 hash32 = (hash >> 32) ^ hash;
|
||||
printf("%" PRIX64 "\t%08X\n", hash, hash32);
|
||||
}
|
||||
return 0;
|
||||
}
|
207
warcraft_hashes/wc3hashes.md
Normal file
207
warcraft_hashes/wc3hashes.md
Normal file
|
@ -0,0 +1,207 @@
|
|||
# found hashes in Warcraft III (The Frozen Throne) 1.28c
|
||||
|
||||
## known cheats
|
||||
|
||||
### Synergy
|
||||
`F9CC37EF6A43F87B 938FCF94 0AD0048C 0AD008A8 0AD00854 0AD00428 00000000`
|
||||
### RiseAndShine
|
||||
`3A307C034564F51C 7F54891F 0AB801E8 0AD00908 0AD00404 0AD00458 00000000`
|
||||
### LightsOut
|
||||
`AB05DD8482042FDD 2901F259 0AB801A0 0AD00878 0AD00434 0AD00488 00000000`
|
||||
### DayLightSavings
|
||||
`274C1EE817B2556C 30FE4B84 0AB801C4 0AD003F8 0AD00464 0AD004B8 00000000`
|
||||
### SharpAndShiny
|
||||
`DEEE313DDE8F4C46 00617D7B 0AD004EC 0AD00848 0AD00494 0AD004E8 00000000`
|
||||
### SomebodySetUpUsTheBomb
|
||||
`559E5996EE428C15 BBDCD583 0AB801B8 0AD004B8 0AD004C4 0AD00C98 00000000`
|
||||
### TenthLevelTaurenChieftain
|
||||
`831ED0A2DC6523A9 5F7BF30B 0AD004BC 0AD008D8 0AD00884 0AD003F8 00000000`
|
||||
### IseeDeadPeople
|
||||
`701EA16D47F385FC 37ED2491 0AD0045C 0AD00B18 0AD008B4 0AD00848 00000000`
|
||||
### GreedIsGood
|
||||
`20ACC89F1CC95E1B 3C659684 0AD003FC 0AD00B48 0AD008E4 0AD00878 00000000`
|
||||
### WhoIsJohnGalt
|
||||
`AF7D59528BF4CA21 24899373 0AD0084C 0AD00A88 0AD00914 0AD008A8 00000000`
|
||||
### TheDudeAbides
|
||||
`EEE62EB91EB79CA6 F051B21F 0AD0042C 0AD00968 0AD00944 0AD008D8 00000000`
|
||||
### ItVexesMe
|
||||
`CA29470C3EB71379 F49E5475 0AB801D0 0AD00AE8 0AD00974 0AD00908 00000000`
|
||||
### StrengthAndHonor
|
||||
`762B2E78DB40C1E7 AD6BEF9F 0AD0090C 0AD00218 0AD009A4 0AD00938 00000000`
|
||||
### ThereIsNoSpoon
|
||||
`9131AC63D1E29109 40D33D6A 0AD0099C 0AD00A58 0AD00A04 0AD00998 00000000`
|
||||
### LeafitToMe
|
||||
`F3E36048DD3DADB8 2EDECDF0 0AB80194 0AD00A28 0AD00A34 0AD009C8 00000000`
|
||||
### Motherland
|
||||
`AA5CEFDDC541C195 6F1D2E48 0AD009FC 0AD00188 0AD00A64 0AD009F8 00000000`
|
||||
### KeyserSoze
|
||||
`90DAFFD11E7A8FC3 8EA07012 0AD009CC 0AD00AB8 0AD00A94 0AD00A28 00000000`
|
||||
### WhosYourDaddy
|
||||
`F3176D0490330CF7 632461F3 0AD008DC 0AD00128 0AD00AC4 0AD00A58 00000000`
|
||||
### PointBreak
|
||||
`0B03F57AA3F85088 A8FBA5F2 0AD00A5C 0AD00248 0AD00AF4 0AD00A88 00000000`
|
||||
### IocainePowder
|
||||
`D225C8F453D8E4C9 81FD2C3D 0AD0093C 0AD001B8 0AD00B24 0AD00AB8 00000000`
|
||||
### WarpTen
|
||||
`9F4929AF30929AE6 AFDBB349 0AD0087C 0AD001E8 0AD00B54 0AD00AE8 00000000`
|
||||
### AllYourBaseAreBelongToUs
|
||||
`F1DACF199149F9EF 609336F6 0AB801DC 0AD00278 0AD004F4 F548FF4F 00000000`
|
||||
|
||||
## known hashes
|
||||
|
||||
### SMReload
|
||||
`5C103D4172ECF421 2EFCC960 0AD000CC F547FE6B 0AB700B0 0AD000C8 52333D20`
|
||||
### ps
|
||||
`BCE67317FD3989EF 41DFFAF8 0AD0018C 0AD00098 0AD000A4 0AD000F8 52333D2C`
|
||||
### ptm
|
||||
`8D06F935F3B3CBBF 7EB5328A 0AD0024C F547FE53 0AD000D4 0AD00128 52333D30`
|
||||
### SMLoadCustomSLK
|
||||
`4D86DCAB95A991D8 D82F4D73 0AD00A8C F547FE47 0AD00104 0AD00158 52333D34`
|
||||
### SMUnloadCustomSLK
|
||||
`6B8E333B3BB2AA14 503C992F 0AD0021C F547FE17 0AD00134 0AD00188 52333D44`
|
||||
### SMEnable
|
||||
`558C46F5E6B0AB35 B33CEDC0 0AD00A2C 0AD000C8 0AD00164 0AD001B8 52333D58`
|
||||
### SMDisable
|
||||
`B2F0229471D85C61 C3287EF5 0AD00AEC F547FE2F 0AD00194 0AD001E8 52333D64`
|
||||
### ChannelVolume
|
||||
`BB507AD60538D687 BE68AC51 0AD00B1C F547FE5F 0AD001C4 0AD00218 52333D70`
|
||||
### SMEnvironment
|
||||
`656682F14532D42E 205456DF 0AD0096C 0AD00158 0AD001F4 0AD00248 52333D80`
|
||||
### SMVerbose
|
||||
`FF46DE59CD796AC3 323FB49A 0AD00ABC 0AD000F8 0AD00224 0AD00278 52333D90`
|
||||
### SM3DVolumeScale
|
||||
`F77E958F2DD2CF09 DAAC5A86 0AD00C9C F547FE23 0AD00254 0AD00B48 52333D9C`
|
||||
### wenodel
|
||||
`FF2E83780E1BF8A1 F1357BD9 0AD0030C F547FEFF 0AB700F8 0AD002D8 523FE874`
|
||||
### mmhires
|
||||
`D938517FCD2C1095 141441EA 0AD0036C F547FEF3 0AD002B4 0AD00308 523FE8A4`
|
||||
### mmfilter
|
||||
`55E017D0FA9D51C5 AF7D4615 0AD003CC 0AD002A8 0AD002E4 0AD00338 523FE8D0`
|
||||
### wenoanim
|
||||
`B62FE0AA562D4C62 E002ACC8 0AD0039C F547FF0B 0AD00314 0AD00368 523FE8F4`
|
||||
### debugimageload
|
||||
`DACCB9B21890F58C C25C4C3E 0AB8010C 0AD002D8 0AD00344 0AD00398 523FE920`
|
||||
### combinecliffs
|
||||
`9043F7C49F06AC08 0F455BCC 0AB800F4 0AD00338 0AD00374 0AD003C8 523FE950`
|
||||
### desthm
|
||||
`DF5D5BD9F36D078C 2C305C55 0AB80100 0AD00308 0AD003A4 F548FF07 523FE984`
|
||||
### terstats
|
||||
`CAF538359FE3B43B 55168C0E 0AD0060C F547FE8B 0AB70140 0AD00548 52402584`
|
||||
### showgridnorms
|
||||
`095FF91A9C8ECFDE 95D136C4 0AD006CC F547FEA3 0AD00524 0AD00578 524025AC`
|
||||
### showcliffnorms
|
||||
`A5E6D9C3C53B8004 60DD59C7 0AD007EC F547FE7F 0AD00554 0AD005A8 524025D0`
|
||||
### showvertcolor
|
||||
`A9E4099B6A680CBE C38C0525 0AD0069C F547FE97 0AD00584 0AD005D8 524025F8`
|
||||
### togcliffmeld
|
||||
`880E433F593BEFA6 D135AC99 0AD0078C F547FEC7 0AD005B4 0AD00608 52402628`
|
||||
### testfog
|
||||
`7FC2CDAE434EE518 3C8C28B6 0AD00C3C 0AD00518 0AD005E4 0AD00638 52402650`
|
||||
### tetris
|
||||
`C0DBC99B9AED0083 5A36C918 0AD0066C F547FED3 0AD00614 0AD00668 52402670`
|
||||
### debugcliffadjust
|
||||
`5EBE4C01F65F44C1 A8E108C0 0AD00B7C 0AD00638 0AD00644 0AD00698 52402694`
|
||||
### puffstats
|
||||
`4868E581E70D2E84 AF65CB05 0AD006FC 0AD005A8 0AD00674 0AD006C8 524026C8`
|
||||
### markwater
|
||||
`C5F3A6A3AD116C47 68E2CAE4 0AD0075C 0AD00548 0AD006A4 0AD006F8 524026EC`
|
||||
### debugdoodsearch
|
||||
`71DB3C34684345F9 199879CD 0AB80168 0AD00698 0AD006D4 0AD00728 5240270C`
|
||||
### showocc
|
||||
`E7A83F207AF3FFAA 9D5BC08A 0AD00C6C F547FEBB 0AD00704 0AD00758 52402738`
|
||||
### occalpha
|
||||
`870461D7A64988D3 214DE904 0AD007BC 0AD006C8 0AD00734 0AD00788 52402760`
|
||||
### gcstats
|
||||
`FC7C3275F856BDBC 042A8FC9 0AD0081C 0AD005D8 0AD00764 0AD007B8 52402788`
|
||||
### fcstats
|
||||
`AF5C1C16C20A72D2 6D566EC4 0AD00C0C 0AD00758 0AD00794 0AD007E8 524027A8`
|
||||
### tersort
|
||||
`1490D7F9D53D3986 C1ADEE7F 0AB80180 0AD00578 0AD007C4 0AD00818 524027C8`
|
||||
### shownaval
|
||||
`F2605BB3FF968B32 0DF6D081 0AB80138 0AD00788 0AD007F4 0AD00C68 524027E8`
|
||||
### maxfps
|
||||
`F3C623DE6158790C 929E5AD2 0AB801AC 0AD009C8 0AD009D4 0AD00968 522FA6C0`
|
||||
### gridhl
|
||||
`3C01956D04BC7671 38BDE31C 0AD008AC F547FE3B 0AD00284 0AD00B18 52402F10`
|
||||
### occstats
|
||||
`A45FA7037D01759B D95ED298 0AB8012C 0AD00668 0AD00BB4 F548FEBF 52402838`
|
||||
### termesh
|
||||
`4E933DDD69E6A867 277595BA 0AB80144 0AD00C68 0AD00BE4 0AD00B78 52402830`
|
||||
### termemf
|
||||
`84ADED3C39A35A2A BD0EB716 0AB80174 0AD00C38 0AD00C14 0AD00BA8 52402828`
|
||||
### termemd
|
||||
`91AC838C2AD71938 BB7B9AB4 0AB8015C 0AD007B8 0AD00C44 0AD00BD8 52402820`
|
||||
### termem
|
||||
`71B5C4882E2E089E 5F9BCC16 0AD00BDC 0AD00608 0AD00C74 0AD00C08 52402818`
|
||||
### revwarnings
|
||||
`C2205630D42AC772 160A9142 0AD00BAC 0AD00728 0AD00824 0AD00C38 5240280C`
|
||||
|
||||
## raw data
|
||||
|
||||
```
|
||||
00000030 6F6D0AD0 2EFCC960 0AD000CC F547FE6B 0AB700B0 0AD000C8 00000000 72ECF421 5C103D41 52333D20 00000000
|
||||
00000030 6F6D0AD0 41DFFAF8 0AD0018C 0AD00098 0AD000A4 0AD000F8 00000000 FD3989EF BCE67317 52333D2C 00000000
|
||||
00000030 6F6D0AD0 7EB5328A 0AD0024C F547FE53 0AD000D4 0AD00128 00000000 F3B3CBBF 8D06F935 52333D30 00000000
|
||||
00000030 6F6D0AD0 D82F4D73 0AD00A8C F547FE47 0AD00104 0AD00158 00000000 95A991D8 4D86DCAB 52333D34 00000000
|
||||
00000030 6F6D0AD0 503C992F 0AD0021C F547FE17 0AD00134 0AD00188 00000000 3BB2AA14 6B8E333B 52333D44 00000000
|
||||
00000030 6F6D0AD0 B33CEDC0 0AD00A2C 0AD000C8 0AD00164 0AD001B8 00000000 E6B0AB35 558C46F5 52333D58 00000000
|
||||
00000030 6F6D0AD0 C3287EF5 0AD00AEC F547FE2F 0AD00194 0AD001E8 00000000 71D85C61 B2F02294 52333D64 00000000
|
||||
00000030 6F6D0AD0 BE68AC51 0AD00B1C F547FE5F 0AD001C4 0AD00218 00000000 0538D687 BB507AD6 52333D70 00000000
|
||||
00000030 6F6D0AD0 205456DF 0AD0096C 0AD00158 0AD001F4 0AD00248 00000000 4532D42E 656682F1 52333D80 00000000
|
||||
00000030 6F6D0AD0 323FB49A 0AD00ABC 0AD000F8 0AD00224 0AD00278 00000000 CD796AC3 FF46DE59 52333D90 00000000
|
||||
00000030 6F6D0AD0 DAAC5A86 0AD00C9C F547FE23 0AD00254 0AD00B48 00000000 2DD2CF09 F77E958F 52333D9C 00000000
|
||||
00000030 6F6D0AD0 F1357BD9 0AD0030C F547FEFF 0AB700F8 0AD002D8 00000000 0E1BF8A1 FF2E8378 523FE874 00000000
|
||||
00000030 6F6D0AD0 141441EA 0AD0036C F547FEF3 0AD002B4 0AD00308 00000000 CD2C1095 D938517F 523FE8A4 00000000
|
||||
00000030 6F6D0AD0 AF7D4615 0AD003CC 0AD002A8 0AD002E4 0AD00338 00000000 FA9D51C5 55E017D0 523FE8D0 00000000
|
||||
00000030 6F6D0AD0 E002ACC8 0AD0039C F547FF0B 0AD00314 0AD00368 00000000 562D4C62 B62FE0AA 523FE8F4 00000000
|
||||
00000030 6F6D0AD0 C25C4C3E 0AB8010C 0AD002D8 0AD00344 0AD00398 00000000 1890F58C DACCB9B2 523FE920 00000000
|
||||
00000030 6F6D0AD0 0F455BCC 0AB800F4 0AD00338 0AD00374 0AD003C8 00000000 9F06AC08 9043F7C4 523FE950 00000000
|
||||
00000030 6F6D0AD0 2C305C55 0AB80100 0AD00308 0AD003A4 F548FF07 00000000 F36D078C DF5D5BD9 523FE984 00000000
|
||||
00000030 6F6D0AD0 938FCF94 0AD0048C 0AD008A8 0AD00854 0AD00428 00000000 6A43F87B F9CC37EF 00000000 00000000
|
||||
00000030 6F6D0AD0 7F54891F 0AB801E8 0AD00908 0AD00404 0AD00458 00000000 4564F51C 3A307C03 00000000 00000000
|
||||
00000030 6F6D0AD0 2901F259 0AB801A0 0AD00878 0AD00434 0AD00488 00000000 82042FDD AB05DD84 00000000 00000000
|
||||
00000030 6F6D0AD0 30FE4B84 0AB801C4 0AD003F8 0AD00464 0AD004B8 00000000 17B2556C 274C1EE8 00000000 00000000
|
||||
00000030 6F6D0AD0 00617D7B 0AD004EC 0AD00848 0AD00494 0AD004E8 00000000 DE8F4C46 DEEE313D 00000000 00000000
|
||||
00000030 6F6D0AD0 BBDCD583 0AB801B8 0AD004B8 0AD004C4 0AD00C98 00000000 EE428C15 559E5996 00000000 00000000
|
||||
00000030 6F6D0AD0 55168C0E 0AD0060C F547FE8B 0AB70140 0AD00548 00000000 9FE3B43B CAF53835 52402584 00000000
|
||||
00000030 6F6D0AD0 95D136C4 0AD006CC F547FEA3 0AD00524 0AD00578 00000000 9C8ECFDE 095FF91A 524025AC 00000000
|
||||
00000030 6F6D0AD0 60DD59C7 0AD007EC F547FE7F 0AD00554 0AD005A8 00000000 C53B8004 A5E6D9C3 524025D0 00000000
|
||||
00000030 6F6D0AD0 C38C0525 0AD0069C F547FE97 0AD00584 0AD005D8 00000000 6A680CBE A9E4099B 524025F8 00000000
|
||||
00000030 6F6D0AD0 D135AC99 0AD0078C F547FEC7 0AD005B4 0AD00608 00000000 593BEFA6 880E433F 52402628 00000000
|
||||
00000030 6F6D0AD0 3C8C28B6 0AD00C3C 0AD00518 0AD005E4 0AD00638 00000000 434EE518 7FC2CDAE 52402650 00000000
|
||||
00000030 6F6D0AD0 5A36C918 0AD0066C F547FED3 0AD00614 0AD00668 00000000 9AED0083 C0DBC99B 52402670 00000000
|
||||
00000030 6F6D0AD0 A8E108C0 0AD00B7C 0AD00638 0AD00644 0AD00698 00000000 F65F44C1 5EBE4C01 52402694 00000000
|
||||
00000030 6F6D0AD0 AF65CB05 0AD006FC 0AD005A8 0AD00674 0AD006C8 00000000 E70D2E84 4868E581 524026C8 00000000
|
||||
00000030 6F6D0AD0 68E2CAE4 0AD0075C 0AD00548 0AD006A4 0AD006F8 00000000 AD116C47 C5F3A6A3 524026EC 00000000
|
||||
00000030 6F6D0AD0 199879CD 0AB80168 0AD00698 0AD006D4 0AD00728 00000000 684345F9 71DB3C34 5240270C 00000000
|
||||
00000030 6F6D0AD0 9D5BC08A 0AD00C6C F547FEBB 0AD00704 0AD00758 00000000 7AF3FFAA E7A83F20 52402738 00000000
|
||||
00000030 6F6D0AD0 214DE904 0AD007BC 0AD006C8 0AD00734 0AD00788 00000000 A64988D3 870461D7 52402760 00000000
|
||||
00000030 6F6D0AD0 042A8FC9 0AD0081C 0AD005D8 0AD00764 0AD007B8 00000000 F856BDBC FC7C3275 52402788 00000000
|
||||
00000030 6F6D0AD0 6D566EC4 0AD00C0C 0AD00758 0AD00794 0AD007E8 00000000 C20A72D2 AF5C1C16 524027A8 00000000
|
||||
00000030 6F6D0AD0 C1ADEE7F 0AB80180 0AD00578 0AD007C4 0AD00818 00000000 D53D3986 1490D7F9 524027C8 00000000
|
||||
00000030 6F6D0AD0 0DF6D081 0AB80138 0AD00788 0AD007F4 0AD00C68 00000000 FF968B32 F2605BB3 524027E8 00000000
|
||||
00000030 6F6D0AD0 5F7BF30B 0AD004BC 0AD008D8 0AD00884 0AD003F8 00000000 DC6523A9 831ED0A2 00000000 00000000
|
||||
00000030 6F6D0AD0 37ED2491 0AD0045C 0AD00B18 0AD008B4 0AD00848 00000000 47F385FC 701EA16D 00000000 00000000
|
||||
00000030 6F6D0AD0 3C659684 0AD003FC 0AD00B48 0AD008E4 0AD00878 00000000 1CC95E1B 20ACC89F 00000000 00000000
|
||||
00000030 6F6D0AD0 24899373 0AD0084C 0AD00A88 0AD00914 0AD008A8 00000000 8BF4CA21 AF7D5952 00000000 00000000
|
||||
00000030 6F6D0AD0 F051B21F 0AD0042C 0AD00968 0AD00944 0AD008D8 00000000 1EB79CA6 EEE62EB9 00000000 00000000
|
||||
00000030 6F6D0AD0 F49E5475 0AB801D0 0AD00AE8 0AD00974 0AD00908 00000000 3EB71379 CA29470C 00000000 00000000
|
||||
00000030 6F6D0AD0 AD6BEF9F 0AD0090C 0AD00218 0AD009A4 0AD00938 00000000 DB40C1E7 762B2E78 00000000 00000000
|
||||
00000030 6F6D0AD0 929E5AD2 0AB801AC 0AD009C8 0AD009D4 0AD00968 00000000 6158790C F3C623DE 522FA6C0 00000000
|
||||
00000030 6F6D0AD0 40D33D6A 0AD0099C 0AD00A58 0AD00A04 0AD00998 00000000 D1E29109 9131AC63 00000000 00000000
|
||||
00000030 6F6D0AD0 2EDECDF0 0AB80194 0AD00A28 0AD00A34 0AD009C8 00000000 DD3DADB8 F3E36048 00000000 00000000
|
||||
00000030 6F6D0AD0 6F1D2E48 0AD009FC 0AD00188 0AD00A64 0AD009F8 00000000 C541C195 AA5CEFDD 00000000 00000000
|
||||
00000030 6F6D0AD0 8EA07012 0AD009CC 0AD00AB8 0AD00A94 0AD00A28 00000000 1E7A8FC3 90DAFFD1 00000000 00000000
|
||||
00000030 6F6D0AD0 632461F3 0AD008DC 0AD00128 0AD00AC4 0AD00A58 00000000 90330CF7 F3176D04 00000000 00000000
|
||||
00000030 6F6D0AD0 A8FBA5F2 0AD00A5C 0AD00248 0AD00AF4 0AD00A88 00000000 A3F85088 0B03F57A 00000000 00000000
|
||||
00000030 6F6D0AD0 81FD2C3D 0AD0093C 0AD001B8 0AD00B24 0AD00AB8 00000000 53D8E4C9 D225C8F4 00000000 00000000
|
||||
00000030 6F6D0AD0 AFDBB349 0AD0087C 0AD001E8 0AD00B54 0AD00AE8 00000000 30929AE6 9F4929AF 00000000 00000000
|
||||
00000030 6F6D0AD0 38BDE31C 0AD008AC F547FE3B 0AD00284 0AD00B18 00000000 04BC7671 3C01956D 52402F10 00000000
|
||||
00000030 6F6D0AD0 D95ED298 0AB8012C 0AD00668 0AD00BB4 F548FEBF 00000000 7D01759B A45FA703 52402838 00000000
|
||||
00000030 6F6D0AD0 277595BA 0AB80144 0AD00C68 0AD00BE4 0AD00B78 00000000 69E6A867 4E933DDD 52402830 00000000
|
||||
00000030 6F6D0AD0 BD0EB716 0AB80174 0AD00C38 0AD00C14 0AD00BA8 00000000 39A35A2A 84ADED3C 52402828 00000000
|
||||
00000030 6F6D0AD0 BB7B9AB4 0AB8015C 0AD007B8 0AD00C44 0AD00BD8 00000000 2AD71938 91AC838C 52402820 00000000
|
||||
00000030 6F6D0AD0 5F9BCC16 0AD00BDC 0AD00608 0AD00C74 0AD00C08 00000000 2E2E089E 71B5C488 52402818 00000000
|
||||
00000030 6F6D0AD0 160A9142 0AD00BAC 0AD00728 0AD00824 0AD00C38 00000000 D42AC772 C2205630 5240280C 00000000
|
||||
00000030 6F6D0AD0 609336F6 0AB801DC 0AD00278 0AD004F4 F548FF4F 00000000 9149F9EF F1DACF19 00000000 00000000
|
||||
```
|
Loading…
Reference in New Issue
Block a user