# forensic -- puzzle forensics, steganography, ciphers, number theory
# Audio analysis, image stego, esoteric languages, file format forensics, math puzzles
# ============================================================================
# aliases: audio analysis
# ============================================================================
alias soxinfo='sox "$1" -n stat'
alias soxspec='sox "$1" -n spectrogram -x 1024 -y 512 -z 120 -o spec.png'
alias soxreverse='sox "$1" "$2" reverse'
alias ffextraudio='ffmpeg -hide_banner -i "$1" -vn -acodec pcm_s16le -ar 44100'
alias ffaudioinfo='ffprobe -hide_banner -v error -select_streams a:0 -show_entries stream=codec_name,channels,sample_rate,duration -of csv=p=0'
alias dtmf='multimon-ng -a DTMF -t wav'
alias midi2csv='midicsv'
# ============================================================================
# functions: audio analysis
# ============================================================================
spectrogram() {
[ -z "$1" ] && { echo "Usage: spectrogram <audio> [output.png]"; return 1; }
local out="${2:-spectrogram.png}"
if command -v sox >/dev/null; then sox "$1" -n spectrogram -x 1024 -y 512 -z 120 -w hamming -o "$out"
else ffmpeg -i "$1" -vf "showspectrumpic=s=1024x512:log=1" -frames:v 1 "$out" 2>/dev/null
fi && echo "[+] $out"
}
audiostego() {
[ -z "$1" ] && { echo "Usage: audiostego <audio> [output]"; return 1; }
local out="${2:-extracted.txt}"
command -v steghide >/dev/null && steghide extract -sf "$1" -xf "$out" 2>/dev/null && echo "[+] steghide" && return 0
command -v mp3stego >/dev/null && mp3stego -d -P "" "$1" "${1%.mp3}.pcm" "$out" 2>/dev/null && echo "[+] mp3stego" && return 0
echo "[-] No extraction method succeeded"
}
dtmfdecode() {
[ -z "$1" ] && { echo "Usage: dtmfdecode <audio>"; return 1; }
multimon-ng -a DTMF -t wav "$1" | grep -oE '[0-9A-D*#]' | tr -d '\n'; echo
}
morsedecode() {
[ -z "$1" ] && { echo "Usage: morsedecode <audio>"; return 1; }
command -v morse-audio-decoder >/dev/null && morse-audio-decoder "$1" && return 0
command -v rscw >/dev/null && rscw < "$1" && return 0
echo "[-] No Morse decoder installed"
}
audioinfo() {
[ -z "$1" ] && { echo "Usage: audioinfo <file>"; return 1; }
if command -v sox >/dev/null; then sox "$1" -n stat 2>&1
elif command -v ffprobe >/dev/null; then ffprobe -hide_banner "$1" 2>&1 | head -20
fi
}
sstvdecode() {
[ -z "$1" ] && { echo "Usage: sstvdecode <audio>"; return 1; }
command -v qsstv >/dev/null && qsstv --decode "$1" && return 0
command -v sstv >/dev/null && sstv -i "$1" -o "sstv_out.png" && return 0
echo "[-] qsstv or sstv not installed"
}
midi2text() {
[ -z "$1" ] && { echo "Usage: midi2text <midi>"; return 1; }
midicsv "$1" | grep -E "Note_on|Note_off|Program_c"
}
tonegen() {
[ -z "$1" ] && { echo "Usage: tonegen <freq_hz> [dur_sec] [output.wav]"; return 1; }
sox -n -t wav "${3:-tone_${1}hz.wav}" synth "${2:-1}" sine "$1" && echo "[+] ${3:-tone_${1}hz.wav}"
}
audioreverse() {
[ -z "$1" ] && { echo "Usage: audioreverse <input> [output]"; return 1; }
sox "$1" "${2:-reversed.wav}" reverse && echo "[+] ${2:-reversed.wav}"
}
# ============================================================================
# aliases: image steganography
# ============================================================================
alias outguess_hide='outguess -k'
alias outguess_extract='outguess -r'
alias pngcheck='pngcheck -v'
alias qrdecode='zbarimg'
alias qrencode='qrencode -o'
# ============================================================================
# functions: image steganography
# ============================================================================
imgstego() {
[ -z "$1" ] && { echo "Usage: imgstego <image>"; return 1; }
echo "=== FILE ===" && file "$1" && identify -verbose "$1" 2>/dev/null | grep -E "Geometry|Colorspace|Depth"
echo "=== EXIF ===" && exiftool "$1" 2>/dev/null | head -20
echo "=== STRINGS ===" && strings -n 8 "$1" | head -20
echo "=== BINWALK ===" && binwalk "$1" 2>/dev/null
echo "=== OUTGUESS ===" && outguess -r "$1" /dev/null 2>/dev/null && echo "Hidden data found!" || echo "No outguess data"
echo "=== STEGHIDE ===" && steghide info "$1" 2>/dev/null
echo "=== ZSTEG ===" && command -v zsteg >/dev/null && zsteg "$1" 2>/dev/null | head -10
}
lsbextract() {
[ -z "$1" ] && { echo "Usage: lsbextract <image> [bits]"; return 1; }
python3 -c "
from PIL import Image; import sys
img=Image.open('$1'); px=list(img.tobytes())
bits=${2:-1}; lsbs=[]
for p in px:
for i in range(bits): lsbs.append((p>>i)&1)
result=bytearray()
for i in range(0,len(lsbs)-7,8):
b=0
for j in range(8): b|=(lsbs[i+j]<<j)
result.append(b)
sys.stdout.buffer.write(result)
"
}
colorplanes() {
[ -z "$1" ] && { echo "Usage: colorplanes <image> [prefix]"; return 1; }
local p="${2:-plane}"
convert "$1" -channel R -separate "${p}_red.png" && echo "${p}_red.png"
convert "$1" -channel G -separate "${p}_green.png" && echo "${p}_green.png"
convert "$1" -channel B -separate "${p}_blue.png" && echo "${p}_blue.png"
for i in 0 1 2 3 4 5 6 7; do
convert "$1" -depth 8 -fx "((u*255)>>$i)&1" "${p}_bit${i}.png" 2>/dev/null && echo "${p}_bit${i}.png"
done
}
xorimage() {
[ $# -lt 2 ] && { echo "Usage: xorimage <img1> <img2> [output]"; return 1; }
python3 -c "
from PIL import Image
a,b=Image.open('$1').convert('RGB'),Image.open('$2').convert('RGB')
px1,px2=a.load(),b.load()
out=Image.new('RGB',a.size)
po=out.load()
for y in range(a.size[1]):
for x in range(a.size[0]):
r1,g1,b1=px1[x,y]; r2,g2,b2=px2[x,y]
po[x,y]=(r1^r2,g1^g2,b1^b2)
out.save('${3:-xor_result.png}')
print('[+] ${3:-xor_result.png}')
"
}
pngchunks() {
[ -z "$1" ] && { echo "Usage: pngchunks <png>"; return 1; }
python3 -c "
import struct,zlib
with open('$1','rb') as f:
assert f.read(8)==b'\x89PNG\r\n\x1a\n','Not PNG'
while True:
lb=f.read(4)
if not lb: break
l=struct.unpack('>I',lb)[0]; t=f.read(4).decode('ascii',errors='replace')
d=f.read(l); f.read(4)
print(f'{t:4s} | {l:8d} bytes')
if t in ['tEXt','zTXt','iTXt']:
try:
n=d.index(b'\x00'); k=d[:n].decode()
v=zlib.decompress(d[n+2:]) if t=='zTXt' else d[n+1:]
print(f' -> {k}: {v[:100]}')
except: pass
if t=='IEND':
trail=f.read()
if trail: print(f'*** TRAILING DATA: {len(trail)} bytes ***'); print(f' {trail[:100]}')
break
"
}
pixelcount() {
[ -z "$1" ] && { echo "Usage: pixelcount <image>"; return 1; }
python3 -c "
from PIL import Image; from collections import Counter
img=Image.open('$1').convert('RGB'); px=list(img.getdata())
u=len(set(px)); t=len(px)
print(f'Total: {t} Unique: {u} Diversity: {u/t*100:.2f}%')
for c,n in Counter(px).most_common(10): print(f' {c}: {n} ({n/t*100:.2f}%)')
"
}
gifframes() {
[ -z "$1" ] && { echo "Usage: gifframes <gif> [outdir]"; return 1; }
local d="${2:-frames}"; mkdir -p "$d"
convert "$1" +adjoin "$d/frame_%03d.png"
echo "[+] $(ls "$d"/frame_*.png | wc -l) frames extracted to $d/"
}
imgpolyglot() {
[ -z "$1" ] && { echo "Usage: imgpolyglot <file>"; return 1; }
echo "=== Magic bytes ===" && od -A x -t x1z -v -N 32 "$1"
echo "=== Format tests ==="
head -c 8 "$1" | od -An -tx1 | grep -q '89 50 4e 47' && echo "[+] PNG"
head -c 2 "$1" | od -An -tx1 | grep -q 'ff d8' && echo "[+] JPEG"
head -c 4 "$1" | od -An -tx1 | grep -q '50 4b 03 04' && echo "[+] ZIP"
head -c 5 "$1" | grep -q '%PDF' && echo "[+] PDF"
head -c 6 "$1" | grep -q 'GIF8' && echo "[+] GIF"
}
pietrun() {
[ -z "$1" ] && { echo "Usage: pietrun <image.png>"; return 1; }
command -v npiet >/dev/null && npiet -n -t 100000 "$1" || echo "[-] npiet not installed"
}
# ============================================================================
# aliases: esoteric languages / ciphers
# ============================================================================
alias rot13="tr 'a-zA-Z' 'n-za-mN-ZA-M'"
alias rot47="perl -pe 's/([!-~])/chr(33+((ord(\$1)-33+47)%94))/ge'"
alias atbash="tr 'a-z' 'z-a' | tr 'A-Z' 'Z-A'"
alias codepoints="perl -C -ne 'print join(\", \", map { sprintf(\"U+%04X\", ord(\$_)) } split //) . \" \\n\"'"
alias wordfreq="tr ' ' '\n' | grep -v '^$' | sort | uniq -c | sort -rn"
alias charfreq="fold -w1 | sort | uniq -c | sort -rn"
# ============================================================================
# functions: esoteric languages / ciphers
# ============================================================================
caesar() {
shift_n="${1:-13}"
python3 -c "
import sys
s=int('$shift_n')
for line in sys.stdin:
r=[]
for c in line:
if 'a'<=c<='z': r.append(chr((ord(c)-97+s)%26+97))
elif 'A'<=c<='Z': r.append(chr((ord(c)-65+s)%26+65))
else: r.append(c)
print(''.join(r),end='')
"
}
rot() {
[ -z "$1" ] && { echo "Usage: echo text | rot <n>"; return 1; }
caesar "$1"
}
vigenere() {
[ $# -lt 2 ] && { echo "Usage: echo text | vigenere <enc|dec> <key>"; return 1; }
python3 -c "
import sys
mode,key='$1','$2'.upper()
ki=0
for line in sys.stdin:
r=[]
for c in line:
if c.isalpha():
base=65 if c.isupper() else 97
shift=ord(key[ki%len(key)])-65
if mode=='dec': shift=-shift
r.append(chr((ord(c)-base+shift)%26+base))
ki+=1
else: r.append(c)
print(''.join(r),end='')
"
}
railfence() {
[ $# -lt 2 ] && { echo "Usage: echo text | railfence <enc|dec> <rails>"; return 1; }
python3 -c "
import sys
mode,rails='$1',int('$2')
text=sys.stdin.read().strip()
if mode=='enc':
fence=[[] for _ in range(rails)]
rail,d=0,1
for c in text:
fence[rail].append(c)
if rail==0: d=1
elif rail==rails-1: d=-1
rail+=d
print(''.join(''.join(r) for r in fence))
else:
n=len(text); fence=[[None]*n for _ in range(rails)]
rail,d=0,1
for i in range(n):
fence[rail][i]='*'
if rail==0: d=1
elif rail==rails-1: d=-1
rail+=d
idx=0
for r in range(rails):
for i in range(n):
if fence[r][i]=='*': fence[r][i]=text[idx]; idx+=1
rail,d=0,1; result=[]
for i in range(n):
result.append(fence[rail][i])
if rail==0: d=1
elif rail==rails-1: d=-1
rail+=d
print(''.join(result))
"
}
brainfuck() {
[ -z "$1" ] && { echo "Usage: brainfuck <code>"; return 1; }
python3 -c "
code='$1'; tape=[0]*30000; ptr=0; ip=0; output=[]
while ip<len(code):
c=code[ip]
if c=='>': ptr+=1
elif c=='<': ptr-=1
elif c=='+': tape[ptr]=(tape[ptr]+1)%256
elif c=='-': tape[ptr]=(tape[ptr]-1)%256
elif c=='.': output.append(chr(tape[ptr]))
elif c=='[' and tape[ptr]==0:
d=1
while d>0: ip+=1; d+=(1 if code[ip]=='[' else -1 if code[ip]==']' else 0)
elif c==']' and tape[ptr]!=0:
d=1
while d>0: ip-=1; d+=(1 if code[ip]==']' else -1 if code[ip]=='[' else 0)
ip+=1
print(''.join(output))
"
}
bacon() {
[ $# -lt 1 ] && { echo "Usage: echo text | bacon <enc|dec>"; return 1; }
python3 -c "
import sys
mode='$1'
bacon_map={chr(65+i):format(i,'05b').replace('0','a').replace('1','b') for i in range(26)}
rev_map={v:k for k,v in bacon_map.items()}
text=sys.stdin.read().strip()
if mode=='enc':
print(' '.join(bacon_map.get(c.upper(),'?') for c in text if c.isalpha()))
else:
text=text.lower().replace(' ','')
print(''.join(rev_map.get(text[i:i+5],'?') for i in range(0,len(text)-4,5)))
"
}
polybius() {
[ $# -lt 1 ] && { echo "Usage: echo text | polybius <enc|dec>"; return 1; }
python3 -c "
import sys
mode='$1'
grid='ABCDEFGHIKLMNOPQRSTUVWXYZ'
text=sys.stdin.read().strip().upper().replace('J','I')
if mode=='enc':
for c in text:
if c in grid: i=grid.index(c); print(f'{i//5+1}{i%5+1}',end=' ')
else: print(c,end=' ')
print()
else:
nums=text.split()
for n in nums:
if len(n)==2 and n.isdigit(): print(grid[(int(n[0])-1)*5+(int(n[1])-1)],end='')
else: print(n,end='')
print()
"
}
bookcip() {
[ $# -lt 2 ] && { echo "Usage: bookcip <textfile> <indices> [-w]"; return 1; }
python3 -c "
text=open('$1').read()
indices=[int(x) for x in '$2'.split(',')]
if '-w' in '$3':
words=text.split()
print(''.join(words[i-1] if i<=len(words) else '?' for i in indices))
else:
print(''.join(text[i-1] if i<=len(text) else '?' for i in indices))
"
}
zwchars() {
python3 -c "
import sys
text=sys.stdin.read()
zw={'\u200b':'ZWSP','\u200c':'ZWNJ','\u200d':'ZWJ','\ufeff':'BOM','\u200e':'LRM','\u200f':'RLM'}
found=[]
for i,c in enumerate(text):
if c in zw: found.append(f'pos {i}: {zw[c]} (U+{ord(c):04X})')
if found:
for f in found: print(f)
bits=''.join('1' if c=='\u200b' else '0' for c in text if c in zw)
if len(bits)>=8:
decoded=''.join(chr(int(bits[i:i+8],2)) for i in range(0,len(bits)-7,8))
print(f'Binary decode attempt: {decoded}')
else: print('No zero-width characters found')
"
}
acrostic() {
[ -z "$1" ] && { echo "Usage: acrostic <file> [-w]"; return 1; }
if [ "$2" = "-w" ]; then
awk '{print substr($1,1,1)}' "$1" | tr -d '\n'; echo
else
cut -c1 "$1" | tr -d '\n'; echo
fi
}
tapcode() {
[ $# -lt 1 ] && { echo "Usage: echo text | tapcode <enc|dec>"; return 1; }
python3 -c "
import sys
grid='ABCDEFGHIKLMNOPQRSTUVWXYZ'
mode='$1'; text=sys.stdin.read().strip().upper().replace('K','C')
if mode=='enc':
for c in text:
if c in grid: i=grid.index(c); print(f'{i//5+1},{i%5+1}',end=' ')
print()
else:
for pair in text.split():
r,c=pair.split(',')
print(grid[(int(r)-1)*5+(int(c)-1)],end='')
print()
"
}
runic() {
[ -z "$1" ] && { echo "Usage: runic <text> [-r]"; return 1; }
python3 -c "
latin2rune={'f':'ᚠ','u':'ᚢ','th':'ᚦ','a':'ᚨ','r':'ᚱ','k':'ᚲ','g':'ᚷ','w':'ᚹ',
'h':'ᚺ','n':'ᚾ','i':'ᛁ','j':'ᛃ','p':'ᛈ','z':'ᛉ','s':'ᛊ','t':'ᛏ',
'b':'ᛒ','e':'ᛖ','m':'ᛗ','l':'ᛚ','d':'ᛞ','o':'ᛟ'}
rune2latin={v:k for k,v in latin2rune.items()}
text='$1'
if '${2:--}' == '-r':
print(''.join(rune2latin.get(c,c) for c in text))
else:
i=0; r=[]
while i<len(text):
if i+1<len(text) and text[i:i+2] in latin2rune: r.append(latin2rune[text[i:i+2]]); i+=2
elif text[i] in latin2rune: r.append(latin2rune[text[i]]); i+=1
else: r.append(text[i]); i+=1
print(''.join(r))
"
}
# ============================================================================
# aliases: file format forensics
# ============================================================================
alias pdfinfo='pdfinfo'
alias pdftxt='pdftotext -'
alias ziplist='unzip -l'
alias 7zlist='7z l'
alias hexhead='od -A x -t x1z -v -N 512'
alias hexeof='tail -c 512 | hexdump -C'
alias gpgpackets='gpg --list-packets'
# ============================================================================
# functions: file format forensics
# ============================================================================
filedeep() {
[ -z "$1" ] && { echo "Usage: filedeep <file>"; return 1; }
echo "=== TYPE ===" && file "$1"
echo "=== MIME ===" && file -b --mime-type "$1"
echo "=== MAGIC ===" && od -A x -t x1z -v -N 256 "$1" | head -5
echo "=== STRINGS ===" && strings -n 4 "$1" | head -20
echo "=== EXIF ===" && exiftool "$1" 2>/dev/null | head -15
echo "=== ENTROPY ===" && python3 -c "
import math; data=open('$1','rb').read()
h=sum(-p*math.log2(p) for p in [data.count(bytes([b]))/len(data) for b in range(256)] if p>0)
print(f'{h:.4f} bits/byte')
"
}
polyglotcheck() {
[ -z "$1" ] && { echo "Usage: polyglotcheck <file>"; return 1; }
echo "=== POLYGLOT TEST ==="
head -c 8 "$1" | od -An -tx1 | grep -q '89 50 4e 47' && echo "[+] PNG"
head -c 2 "$1" | od -An -tx1 | grep -q 'ff d8' && echo "[+] JPEG"
head -c 4 "$1" | od -An -tx1 | grep -q '50 4b 03 04' && echo "[+] ZIP"
head -c 5 "$1" | grep -q '%PDF' && echo "[+] PDF"
head -c 6 "$1" | grep -q 'GIF8' && echo "[+] GIF"
local t="$(mktemp -d)"; cp "$1" "$t/t.zip"
unzip -t "$t/t.zip" >/dev/null 2>&1 && echo "[+] Valid ZIP archive"
rm -rf "$t"
}
eofdata() {
[ -z "$1" ] && { echo "Usage: eofdata <file> [pdf|png]"; return 1; }
case "${2:-auto}" in
pdf) grep -a -b "%%EOF" "$1" | tail -1 ;;
png) python3 -c "
d=open('$1','rb').read(); i=d.find(b'IEND\xae\x42\x60\x82')
if i>=0:
t=d[i+12:]
if t: print(f'{len(t)} bytes after IEND'); print(t[:200])
else: print('No trailing data')
" ;;
*) echo "Last 512 bytes:" && tail -c 512 "$1" | od -A x -t x1z -v ;;
esac
}
pdfextract() {
[ -z "$1" ] && { echo "Usage: pdfextract <pdf> [outdir]"; return 1; }
local d="${2:-.}"; mkdir -p "$d"
pdftotext "$1" "$d/text.txt" 2>/dev/null && echo "[+] text.txt"
pdfinfo "$1" > "$d/info.txt" 2>/dev/null && echo "[+] info.txt"
strings "$1" | grep -a "obj\|stream" | head -50 > "$d/structure.txt" && echo "[+] structure.txt"
}
embedfind() {
[ -z "$1" ] && { echo "Usage: embedfind <file>"; return 1; }
local h="$(hexdump -C "$1")"
echo "ZIP sigs: $(echo "$h" | grep -c '50 4b 03 04')"
echo "PNG sigs: $(echo "$h" | grep -c '89 50 4e 47')"
echo "PDF sigs: $(echo "$h" | grep -c '25 50 44 46')"
echo "JPEG sigs: $(echo "$h" | grep -c 'ff d8 ff')"
}
hexcompare() {
[ $# -lt 2 ] && { echo "Usage: hexcompare <f1> <f2>"; return 1; }
cmp -s "$1" "$2" && echo "[IDENTICAL]" || { echo "[DIFFERENT]"; cmp -l "$1" "$2" | head -20; }
}
svgextract() {
[ -z "$1" ] && { echo "Usage: svgextract <svg>"; return 1; }
echo "=== Comments ===" && grep -o '<!--.*-->' "$1" | head -10
echo "=== Hidden ===" && grep -E 'display.*none|opacity.*0|visibility.*hidden' "$1" | head -10
echo "=== Metadata ===" && grep -o '<metadata>.*</metadata>' "$1" | head -5
echo "=== Data URIs ===" && grep -oE 'data:[^"]+' "$1" | head -5
}
qrextract() {
[ -z "$1" ] && { echo "Usage: qrextract <image>"; return 1; }
command -v zbarimg >/dev/null && zbarimg "$1" 2>/dev/null || echo "[-] zbarimg not installed"
}
pgppackets() {
[ -z "$1" ] && { echo "Usage: pgppackets <file>"; return 1; }
gpg --list-packets "$1" 2>/dev/null || od -A x -t x1z -v -N 256 "$1"
}
torrentparse() {
[ -z "$1" ] && { echo "Usage: torrentparse <torrent>"; return 1; }
echo "=== Content ===" && strings "$1" | head -30
echo "=== Trackers ===" && strings "$1" | grep -E "http|udp|announce" | head -10
}
# ============================================================================
# aliases: math / number theory
# ============================================================================
alias sage='sage --no-banner'
alias gp='gp -q'
alias bc='bc -l'
# ============================================================================
# functions: math / number theory
# ============================================================================
isprime() {
[ -z "$1" ] && { echo "Usage: isprime <n>"; return 1; }
python3 -c "from sympy import isprime; print(1 if isprime($1) else 0)"
}
factorize() {
[ -z "$1" ] && { echo "Usage: factorize <n>"; return 1; }
if [ "$1" -lt 1000000000000000 ] 2>/dev/null; then factor "$1"
else python3 -c "from sympy import factorint; f=factorint($1); print(' '.join(f'{p}^{e}' if e>1 else str(p) for p,e in sorted(f.items())))"
fi
}
primes() {
python3 -c "from sympy import primerange; [print(p) for p in primerange(${1:-2}, ${2:-100}+1)]"
}
nthprime() {
[ -z "$1" ] && { echo "Usage: nthprime <n>"; return 1; }
python3 -c "from sympy import prime; print(prime($1))"
}
fibonacci() {
[ -z "$1" ] && { echo "Usage: fibonacci <n> [compute|check]"; return 1; }
python3 -c "
n=$1
if '${2:-compute}'=='check':
import math
print(1 if any(int(math.sqrt(x))**2==x for x in [5*n*n+4,5*n*n-4]) else 0)
else:
a,b=0,1
for _ in range(n): a,b=b,a+b
print(a)
"
}
totient() {
[ -z "$1" ] && { echo "Usage: totient <n>"; return 1; }
python3 -c "from sympy import totient; print(totient($1))"
}
modpow() {
[ $# -lt 3 ] && { echo "Usage: modpow <base> <exp> <mod>"; return 1; }
python3 -c "print(pow($1,$2,$3))"
}
modinv() {
[ $# -lt 2 ] && { echo "Usage: modinv <a> <mod>"; return 1; }
python3 -c "from sympy import mod_inverse; print(mod_inverse($1,$2))" 2>/dev/null || echo "No inverse"
}
gematria() {
[ -z "$1" ] && { echo "Usage: gematria <text> [ordinal|hebrew|reduced]"; return 1; }
python3 -c "
text='$1'; sys='${2:-ordinal}'
def en(s): return sum(ord(c)-64 for c in s.upper() if 'A'<=c<='Z')
if sys=='ordinal': print(en(text))
elif sys=='reduced':
t=en(text)
while t>=10: t=sum(int(d) for d in str(t))
print(t)
else: print(en(text))
"
}
baseconv() {
[ -z "$1" ] && { echo "Usage: baseconv <value> [from_base] [to_base]"; return 1; }
python3 -c "
v=int('$1',${2:-10})
tb=${3:-16}
if tb==10: print(v)
elif tb==16: print(hex(v))
elif tb==8: print(oct(v))
elif tb==2: print(bin(v))
else:
d='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/'
r=[]
while v>0: r.append(d[v%tb]); v//=tb
print(''.join(reversed(r)) or '0')
"
}
oeis() {
[ -z "$1" ] && { echo "Usage: oeis <sequence>"; return 1; }
curl -s "https://oeis.org/search?fmt=json&q=$1" | python3 -c "import json,sys; r=json.load(sys.stdin); print(r['results'][0]['name']) if r.get('results') else print('Not found')" 2>/dev/null
}
runelookup() {
[ -z "$1" ] && { echo "Usage: runelookup <runes>"; return 1; }
python3 -c "
runes={'ᚠ':'f','ᚢ':'u','ᚦ':'th','ᚨ':'a','ᚱ':'r','ᚲ':'k','ᚷ':'g','ᚹ':'w',
'ᚺ':'h','ᚾ':'n','ᛁ':'i','ᛃ':'j','ᛇ':'p','ᛈ':'p','ᛉ':'z','ᛊ':'s',
'ᛏ':'t','ᛒ':'b','ᛖ':'e','ᛗ':'m','ᛚ':'l','ᛜ':'ng','ᛞ':'d','ᛟ':'o'}
print(''.join(runes.get(c,c) for c in '$1'))
"
}
romannum() {
[ -z "$1" ] && { echo "Usage: romannum <value> [decode|encode]"; return 1; }
python3 -c "
if '${2:-decode}'=='decode':
v={'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000}
s='$1'.upper(); t=0
for i,c in enumerate(s): t+=(-1 if i+1<len(s) and v[c]<v[s[i+1]] else 1)*v[c]
print(t)
else:
n=int('$1'); r=''
for x,y in zip([1000,900,500,400,100,90,50,40,10,9,5,4,1],['M','CM','D','CD','C','XC','L','XL','X','IX','V','IV','I']):
while n>=x: r+=y; n-=x
print(r)
"
}
collatz() {
[ -z "$1" ] && { echo "Usage: collatz <n>"; return 1; }
python3 -c "
n=$1; s=[n]
while n!=1 and len(s)<200: n=n//2 if n%2==0 else 3*n+1; s.append(n)
print(' -> '.join(map(str,s[:50]))); print(f'Steps: {len(s)-1}')
"
}
primefactors() {
[ -z "$1" ] && { echo "Usage: primefactors <n>"; return 1; }
python3 -c "from sympy import factorint; f=factorint($1); print(' x '.join(f'{p}^{e}' if e>1 else str(p) for p,e in sorted(f.items())))"
}