Convert between numerical bases with #bash and #bc
#!/bin/bash num=$1 from=$2 to=$3 dec=$(echo "ibase=$from; $num" | bc) conv=$(echo "obase=$to; $dec" | bc) echo "$conv"
Convert between numerical bases with #bash and #bc
#!/bin/bash num=$1 from=$2 to=$3 dec=$(echo "ibase=$from; $num" | bc) conv=$(echo "obase=$to; $dec" | bc) echo "$conv"
Calculate factorials over a range with Python
#!/usr/bin/env python3
import sys
import functools
start = int(sys.argv[1])
end = int(sys.argv[2])
for n in range(start, end + 1):
factorial = 1 if n == 0 else functools.reduce(
lambda x, y: x * y, range(1, n + 1)
)
print(f"{n}! = {factorial}")
Using Python to graph relativistic apparent speed as a starship approaches c
#!/usr/bin/python3
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=(8,6))
major_ticks = np.arange(0, 101, 5)
unit_ticks = np.arange(0, 101, 1)
minor_ticks = np.arange(0, 101, 0.2)
ax.set_xticks(major_ticks)
ax.set_yticks(major_ticks)
ax.set_xticks(unit_ticks, minor=True)
ax.set_yticks(unit_ticks, minor=True)
ax.grid(which='major', color='gray', linestyle='-', linewidth=0.8, alpha=0.8)
ax.grid(which='minor', color='black', linestyle='-', linewidth=0.5, alpha=0.7)
x = np.arange(0.7, 0.999, 0.0001)
y = x / np.sqrt(1 - x**2)
plt.plot(x * 100, y, color='blue', linewidth=2)
ax.set_xlim(70, 100)
ax.set_ylim(0, max(y)*1.1)
plt.xlabel("Real speed (percentage of c)")
plt.ylabel("Apparent speed (multiple of c)")
plt.tight_layout()
plt.show()
Plot a cube.
#!/usr/bin/python3
import numpy as np
from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection
import matplotlib.pyplot as plt
points = np.array([[-1, -1, -1],
[1, -1, -1 ],
[1, 1, -1],
[-1, 1, -1],
[-1, -1, 1],
[1, -1, 1 ],
[1, 1, 1],
[-1, 1, 1]])
Z = points
Z = 10.0*Z
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
r = [-1,1]
X, Y = np.meshgrid(r, r)
ax.scatter3D(Z[:, 0], Z[:, 1], Z[:, 2])
verts = [[Z[0],Z[1],Z[2],Z[3]],
[Z[4],Z[5],Z[6],Z[7]],
[Z[0],Z[1],Z[5],Z[4]],
[Z[2],Z[3],Z[7],Z[6]],
[Z[1],Z[2],Z[6],Z[5]],
[Z[4],Z[7],Z[3],Z[0]]]
ax.add_collection3d(Poly3DCollection(verts, facecolors='cyan', linewidths=1, edgecolors='r', alpha=.20))
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
With Python find words longer than 10 characters that use all the vowels:
#! /usr/bin/env python3
with open('unixdict.txt') as f:
while (line := f.readline().strip()):
if (len(line) > 10 and all(
line.count(c) == 1 for c in 'aeiou')):
print(line)
Archimedes spiral with turtle graphics
#!/usr/bin/env python3
from turtle import *
from math import *
color("blue")
speed(0)
down()
for i in range(200):
t = i*pi/20
r = 1+5*t
goto(r*cos(t), r*sin(t))
done()
#!/usr/bin/env python3
from datetime import*
t=datetime.today()
print(“Only”,(datetime(t.year,12,25)-t).days,”shopping days until Christmas.”)
Rot13 with Python
#!/usr/bin/python3
import sys, string
def rot13(s):
return ''.join([chr(x.islower() and ((ord(x) - 84) % 26) + 97
or x.isupper() and ((ord(x) - 52) % 26) + 65
or ord(x))
for x in s])
for line in sys.stdin:
sys.stdout.write(rot13(line))
Plot the area under a curve with Python
#!/usr/bin/python3 from matplotlib import pyplot as plt import numpy as np x=np.arange(1,31) y= x * x plt.fill_between(x,y,color='blue', alpha=0.5) plt.show()
Generating truth tables
from sympy.logic.boolalg import truth_table
from sympy.abc import x, y, z
table = truth_table((x ^ y) ^ z, [x, y, z])
for t in table:
print('{0} -> {1}'.format(*t))
Boolean truth tables in Python
#!/usr/bin/env python3
import sys
from itertools import product
bexp=" ".join(sys.argv[1:])
code=compile(bexp,"<string>","eval")
names=code.co_names
print("\n" + " ".join(names),":",bexp)
for values in product(range(2), repeat=len(names)):
env=dict(zip(names,values))
print(" ".join(map(str,values)),":",int(eval(code,env)))
Plot a 3D sphere with Python
#!/usr/bin/python3
import numpy as np
import matplotlib.pyplot as plt
theta, phi = np.linspace(0, 2 * np.pi, 50), np.linspace(0, np.pi, 20)
THETA, PHI = np.meshgrid(theta, phi)
R = 1.0
X = R * np.sin(PHI) * np.cos(THETA)
Y = R * np.sin(PHI) * np.sin(THETA)
Z = R * np.cos(PHI)
fig = plt.figure()
ax = fig.add_subplot(1,1,1, projection=’3d’)
plot = ax.plot_wireframe(X, Y, Z, rstride=1, cstride=1, linewidth=.1, color=’red’, antialiased=False, alpha=1)
plt.show()
Print the shortest and longest verses in the Bible with Python
#!/usr/bin/env python3
import os
base=os.path.dirname(os.path.abspath(__file__))
path=os.path.join(base,"kjv.txt")
with open(path) as f:
print("Shortest verse:",min(f,key=len))
with open(path) as f:
print("Longest verse:",max(f,key=len))
#!/usr/bin/env python3 import matplotlib.pyplot as p,numpy as n x,y=n.meshgrid(n.linspace(-4,4,512),n.linspace(-4,4,512)) z=(1-x/2+x**4+y**3)*n.exp(-x**2-y**2)*(1-x/3-y**4)*(3-y+x**2) z+=.5*n.sin(.8*x+.6*y)+.4*n.cos(.5*x-.7*y)+.3*n.sin(.6*x-.4*y) p.contour(x,y,z,levels=n.linspace(z.min(),z.max(),25),cmap='terrain') p.show()
Top 20 bash commands in Python
#!/usr/bin/env python3
from collections import Counter
import matplotlib.pyplot as plt
import os
history_file = os.path.expanduser("~/.bash_history")
counter = Counter()
with open(history_file, "r", errors="ignore") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
cmdline = line.split("|", 1)[0].strip()
parts = cmdline.split()
if not parts:
continue
cmd = parts[1] if parts[0] == "sudo" and len(parts) > 1 else parts[0]
counter[cmd] += 1
top = counter.most_common(20)
commands, counts = zip(*top)
commands = commands[::-1]
counts = counts[::-1]
plt.figure(figsize=(10, 6))
plt.barh(commands, counts)
plt.title("Top 20 Bash Commands (frequency)")
plt.xlabel("Usage count")
plt.tight_layout()
plt.show()
List bash commands by frequency
#!/usr/bin/env python3
import os
history_file = os.path.expanduser("~/.bash_history")
counts = {}
with open(history_file, "r", errors="ignore") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
cmdline = line.split("|", 1)[0].strip()
parts = cmdline.split()
if not parts:
continue
cmd = parts[1] if parts[0] == "sudo" and len(parts) > 1 else parts[0]
counts[cmd] = counts.get(cmd, 0) + 1
sorted_cmds = sorted(counts.items(), key=lambda x: x[1], reverse=True)
for cmd, n in sorted_cmds:
print(f"{n} {cmd:20}")
Put text in an ASCII art box:
#!/usr/bin/env python3
import sys
print(“+” + “-” * 62 + “+”)
for line in sys.stdin:
print(f”| {line.rstrip():<60} |”)
print(“+” + “-” * 62 + “+”)
Reformat standard input to any width
#!/usr/bin/python3
import sys
import textwrap
w=int(sys.argv[1])
for line in sys.stdin:
print(textwrap.fill(line,width=w))
Use Python to reverse stdin by words (rev will do this by characters)
#!/usr/bin/env python3
import sys
for line in sys.stdin:
print(' '.join(line.split()[::-1]))
Number to words
#!/usr/bin/env python3
import sys
n = int(sys.argv[1])
ones = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]
teens = ["ten", "eleven", "twelve", "thirteen", "fourteen","fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
tens = ["", "", "twenty", "thirty", "forty","fifty", "sixty", "seventy", "eighty", "ninety"]
if n < 10:
print(ones[n])
elif n < 20:
print(teens[n - 10])
else:
t = n // 10
o = n % 10
if o == 0:
print(tens[t])
else:
print(f"{tens[t]}-{ones[o]}")
Convert text to italics with Python
#!/usr/bin/env python3
import sys
a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
b="𝘈𝘉𝘊𝘋𝘌𝘍𝘎𝘏𝘐𝘑𝘒𝘓𝘔𝘕𝘖𝘗𝘘𝘙𝘚𝘛𝘜𝘝𝘞𝘟𝘠𝘡𝘢𝘣𝘤𝘥𝘦𝘧𝘨𝘩𝘪𝘫𝘬𝘭𝘮𝘯𝘰𝘱𝘲𝘳𝘴𝘵𝘶𝘷𝘸𝘹𝘺𝘻"
print(" ".join(sys.argv[1:]).translate(str.maketrans(a,b)))
#!/usr/bin/env python3
import sys
c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
b="𝗔𝗕𝗖𝗗𝗘𝗙𝗚𝗛𝗜𝗝𝗞𝗟𝗠𝗡𝗢𝗣𝗤𝗥𝗦𝗧𝗨𝗩𝗪𝗫𝗬𝗭𝗮𝗯𝗰𝗱𝗲𝗳𝗴𝗵𝗶𝗷𝗸𝗹𝗺𝗻𝗼𝗽𝗾𝗿𝘀𝘁𝘂𝘃𝘄𝘅𝘆𝘇𝟬𝟭𝟮𝟯𝟰𝟱𝟲𝟳𝟴𝟵"
print("".join(b[c.find(x)] if x in c else x for x in " ".join(sys.argv[1:])))
Calculate parallel resistance (or series capacitance) with Python
#!/usr/bin/env python3 import sys,numpy as n print(sys.argv[1:],'->',1/(1/n.array(sys.argv[1:],float)).sum())
Python replacement for the uniq command.
#!/usr/bin/env python3
import sys
seen = set()
for line in sys.stdin:
if line not in seen:
seen.add(line)
sys.stdout.write(line)
This is not equivalent to sort -u because it preserves the original order, and it’s not equivalent to uniq because it removes duplicates even when they’re not adjacent.
#!/usr/bin/env python3
import sys
n = int(sys.argv[1])
ones = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]
teens = ["ten", "eleven", "twelve", "thirteen", "fourteen","fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
tens = ["", "", "twenty", "thirty", "forty","fifty", "sixty", "seventy", "eighty", "ninety"]
if n < 10:
print(ones[n])
elif n < 20:
print(teens[n - 10])
else:
t = n // 10
o = n % 10
if o == 0:
print(tens[t])
else:
print(f"{tens[t]}-{ones[o]}")
#!/usr/bin/python3
from random import shuffle, randrange
def makemaze(w=20,h=12):
vis = [[0] * w + [1] for _ in range(h)] + [[1] * (w + 1)]
ver = [["| "] * w + ['|'] for _ in range(h)] + [[]]
hor = [["+--"] * w + ['+'] for _ in range(h + 1)]
def walk(x, y):
vis[y][x] = 1
d = [(x - 1, y), (x, y + 1), (x + 1, y), (x, y - 1)]
shuffle(d)
for (xx, yy) in d:
if vis[yy][xx]: continue
if xx == x: hor[max(y, yy)][x] = "+ "
if yy == y: ver[y][max(x, xx)] = " "
walk(xx, yy)
walk(randrange(w), randrange(h))
s = ""
for (a, b) in zip(hor, ver):
s += ''.join(a + ['\n'] + b + ['\n'])
return s
print(makemaze())
Strip punctuation from stdin
#!/usr/bin/env python3
import sys
for line in sys.stdin:
sys.stdout.write(
.join(c for c in line if c.isalnum() or c.isspace())
)
Find anagrams with Python
#!/usr/bin/env python3
from collections import Counter
import sys,os
s=sys.argv[1]
def anagrams(word,words):
cw=Counter(word)
return [w for w in words if Counter(w)==cw]
base=os.path.dirname(os.path.abspath(__file__))
path=os.path.join(base,"words.txt")
with open(path) as f:
lines=f.read().splitlines()
print(anagrams(s,lines))
Convert csv data to sc format
#!/usr/bin/env python3
import sys,string
d=','
a="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
r=0
o=[":"]
for l in open(sys.argv[1]):
c=0
for p in l.rstrip().split(d):
if not p:continue
try:
o+=["let %s%d = %d"%(a[c],r,int(p))]
except:
o+=["leftstring %s%d = %s"%(a[c],r,p if p[0]=='"' else '"%s"'%p)]
c+=1
r+=1
print("\n".join(o))
π calculation using a Machin-like arctangent formula
#!/usr/bin/python3
from decimal import Decimal, getcontext
import sys
digits = int(sys.argv[1]) if len(sys.argv) > 1 else 50
getcontext().prec = digits + 5 # a few extra digits to avoid rounding errors
def arctan(x):
"""Compute arctan(1/x) using the Taylor series."""
x = Decimal(x)
x2 = x * x
term = Decimal(1) / x
total = term
n = 1
sign = -1
while True:
term = term / x2
delta = term / (2 * n + 1)
if delta == 0:
break
total += sign * delta
sign *= -1
n += 1
return total
pi = 16 * arctan(5) - 4 * arctan(239)
pi = +pi # unary plus applies current context precision
print(f"Pi to {digits} digits:\n{str(pi)[:digits+2]}")
Today is piday Here’s a bash script I saved as “pi” somewhere in $PTH
#!/bin/bash
echo “scale=$1;a(1)*4” | bc -l
I demonstrate it this way:
$ for i in {1..20}; do pi $i; done
2.8
3.12
3.140
3.1412
3.14156
3.141592
3.1415924
3.14159264
3.141592652
3.1415926532
3.14159265356
3.141592653588
3.1415926535896
3.14159265358976
3.141592653589792
3.1415926535897932
3.14159265358979320
3.141592653589793236
3.1415926535897932384
3.14159265358979323844
Print a hex array with #Bash
seq 0 255 | awk '{printf "%02X ", $1}' | xargs -n16
Shuffle and rename the files in a directory of images:
$ echo '#!/bin/bash' > files; chmod 744 files; ls -1 | shuf | nl -i1 -s' ' -nrz -w5 | awk '{print "mv " $2 " " $1 ".jpg"}' >> files ; ./files
Calculate #Easter for a range of years
$ seq 2026 2046 | xargs -i ncal -e {}
04/05/2026
03/28/2027
04/16/2028
04/01/2029
04/21/2030
04/13/2031
03/28/2032
04/17/2033
04/09/2034
03/25/2035
04/13/2036
04/05/2037
04/25/2038
04/10/2039
04/01/2040
04/21/2041
04/06/2042
03/29/2043
04/17/2044
04/09/2045
03/25/2046
Perl one-liner to highlight consecutive duplicated words:
perl -pe 's/\b(\w+)\s+\1\b/\e[31m$&\e[0m/gi' gettysburg.txt
Remove empty directories under the working directory:
find . -empty -exec rm -rf {} \;
Sort the Holy Bible by verse length with Perl
perl -e 'print sort {length $b length $a} ' kjv.txt
NEH.10:16 – Adonijah, Bigvai, Adin,
NEH.10:18 – Hodijah, Hashum, Bezai,
NEH.10:27 – Malluch, Harim, Baanah.
NEH.12:5 – Miamin, Maadiah, Bilgah,
JOH.6:48 – I am that bread of life.
1CH.1:24 – Shem, Arphaxad, Shelah,
NEH.10:13 – Hodijah, Bani, Beninu.
NEH.10:17 – Ater, Hizkijah, Azzur,
NEH.11:33 – Hazor, Ramah, Gittaim,
NEH.12:4 – Iddo, Ginnetho, Abijah,
JOB.3:2 – And Job spake, and said,
EXO.20:15 – Thou shalt not steal.
1TH.5:19 – Quench not the Spirit.
1TH.5:25 – Brethren, pray for us.
EXO.20:13 – Thou shalt not kill.
NEH.10:15 – Bunni, Azgad, Bebai,
LUK.17:32 – Remember Lot’s wife.
1TH.5:17 – Pray without ceasing.
DEU.5:17 – Thou shalt not kill.
1CH.1:26 – Serug, Nahor, Terah,
1CH.1:1 – Adam, Sheth, Enosh,
1CH.1:25 – Eber, Peleg, Reu,
1TH.5:16 – Rejoice evermore.
JOH.11:35 – Jesus wept.
#! /bin/bash
D2B=({0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1})
echo $((10#${D2B[$1]}))
List bash commands by frequency
#!/usr/bin/env python3
import os
history_file = os.path.expanduser("~/.bash_history")
counts = {}
with open(history_file, "r", errors="ignore") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
cmdline = line.split("|", 1)[0].strip()
parts = cmdline.split()
if not parts:
continue
cmd = parts[1] if parts[0] == "sudo" and len(parts) > 1 else parts[0]
counts[cmd] = counts.get(cmd, 0) + 1
sorted_cmds = sorted(counts.items(), key=lambda x: x[1], reverse=True)
for cmd, n in sorted_cmds:
print(f"{n} {cmd:20}")
#!/usr/bin/env python3
"""
Argo Alpha-AUXMOD Performance Calculator
Models the docked Alpha capsule and Auxiliary Module in orbit.
Calculates:
- Combined operating and dry mass
- Shared AUXMOD propellant budget
- Ideal delta-v available for maneuvering and docking
- Theoretical peak solar-array output
- Comparison with the specified 7 kW electrical output
Assumptions:
- Alpha mass remains constant at 5200 kg.
- AUXMOD RCS and retro-fire systems share one propellant supply.
- All AUXMOD operating mass above dry mass is treated as propellant.
- Hypergolic specific impulse is 314 seconds.
- Solar-array output uses 35% cell efficiency and standard
solar irradiance at Earth's orbital distance.
"""
import math
# --------------------------------------------------
# Physical constants
# --------------------------------------------------
G0 = 9.80665 # Standard gravity (m/s^2)
SOLAR_IRRADIANCE = 1361.0 # Solar irradiance (W/m^2)
# --------------------------------------------------
# Alpha capsule
# --------------------------------------------------
ALPHA_MASS = 5200.0 # Constant operating mass (kg)
ALPHA_DIAMETER = 3.6 # Diameter (m)
ALPHA_HEIGHT = 2.0 # Overall height (m)
# --------------------------------------------------
# Auxiliary Module
# --------------------------------------------------
AUXMOD_WET_MASS = 2850.0 # Operating mass (kg)
AUXMOD_DRY_MASS = 1640.0 # Dry mass (kg)
AUXMOD_ISP = 314.0 # Hypergolic specific impulse (s)
# Shared RCS and retro-fire propellant budget
AUXMOD_PROPELLANT = (
AUXMOD_WET_MASS - AUXMOD_DRY_MASS
)
# --------------------------------------------------
# Solar arrays
# --------------------------------------------------
SOLAR_ARRAY_AREA = 18.0 # Total deployed area (m^2)
SOLAR_CELL_EFFICIENCY = 0.35 # 35 percent
RATED_ELECTRICAL_OUTPUT = 7000.0 # Previously specified output (W)
# --------------------------------------------------
# Calculations
# --------------------------------------------------
def ideal_delta_v(initial_mass, final_mass, isp):
"""Calculate ideal delta-v using the Tsiolkovsky rocket equation."""
if initial_mass <= final_mass:
return 0.0
return isp * G0 * math.log(initial_mass / final_mass)
def solar_peak_power(area, efficiency, irradiance):
"""Calculate ideal solar-array electrical output in watts."""
return area * efficiency * irradiance
def main():
stack_wet_mass = ALPHA_MASS + AUXMOD_WET_MASS
stack_dry_mass = ALPHA_MASS + AUXMOD_DRY_MASS
print("=" * 54)
print(" ARGO ALPHA-AUXMOD PERFORMANCE")
print("=" * 54)
print("\nSPACECRAFT MASS")
print(f"Alpha capsule: {ALPHA_MASS:10,.1f} kg")
print(f"AUXMOD operating mass: {AUXMOD_WET_MASS:10,.1f} kg")
print(f"AUXMOD dry mass: {AUXMOD_DRY_MASS:10,.1f} kg")
print(f"AUXMOD propellant budget: {AUXMOD_PROPELLANT:10,.1f} kg")
print(f"Combined operating mass: {stack_wet_mass:10,.1f} kg")
print(f"Combined dry mass: {stack_dry_mass:10,.1f} kg")
print("\nPROPULSION AND MANEUVERING")
print(f"Hypergolic Isp: {AUXMOD_ISP:10.1f} s")
print(
"\nHow much propellant (kg) must be reserved for "
"retro-fire operations?"
)
print(
f"Enter a value from 0 to {AUXMOD_PROPELLANT:.1f}. "
"Press Enter for 0 kg (optimistic upper bound)."
)
entry = input("Retro-fire reserve (kg): ").strip()
if entry == "":
retro_reserve = 0.0
else:
try:
retro_reserve = float(entry)
except ValueError:
print("Invalid input. Please enter a numeric mass.")
return
if not 0.0 <= retro_reserve <= AUXMOD_PROPELLANT:
print(
f"Reserve must be between 0 and "
f"{AUXMOD_PROPELLANT:.1f} kg."
)
return
docking_propellant = AUXMOD_PROPELLANT - retro_reserve
# Propellant reserved for retro-fire remains aboard.
final_mass = stack_wet_mass - docking_propellant
docking_delta_v = ideal_delta_v(
stack_wet_mass,
final_mass,
AUXMOD_ISP
)
maximum_delta_v = ideal_delta_v(
stack_wet_mass,
stack_dry_mass,
AUXMOD_ISP
)
print(f"\nRetro-fire reserve: {retro_reserve:10,.1f} kg")
print(f"Propellant for maneuvering:{docking_propellant:9,.1f} kg")
print(f"Mass before maneuver: {stack_wet_mass:10,.1f} kg")
print(f"Mass after maneuver: {final_mass:10,.1f} kg")
print(f"Ideal docking Δv budget: {docking_delta_v:10,.1f} m/s")
print(f"Absolute ideal Δv maximum:{maximum_delta_v:10,.1f} m/s")
def aligned_number(value, decimals=1, width=10, comma=True):
formatted = f"{value:,.{decimals}f}" if comma else f"{value:.{decimals}f}"
integer, fraction = formatted.split(".")
return f"{integer:>{width - decimals - 1}}.{fraction}"
print("\nSOLAR POWER")
theoretical_power = solar_peak_power(
SOLAR_ARRAY_AREA,
SOLAR_CELL_EFFICIENCY,
SOLAR_IRRADIANCE
)
print(f"Deployed array area: {aligned_number(SOLAR_ARRAY_AREA)} m^2")
print(f"Cell efficiency: {aligned_number(SOLAR_CELL_EFFICIENCY * 100)}%")
print(f"Solar irradiance: {aligned_number(SOLAR_IRRADIANCE)} W/m^2")
print(f"Theoretical peak output: {aligned_number(theoretical_power / 1000, 2)} kW")
print(f"Specified system output: {aligned_number(RATED_ELECTRICAL_OUTPUT / 1000, 2)} kW")
derating = 1.0 - RATED_ELECTRICAL_OUTPUT / theoretical_power
print(f"Implied power derating: {aligned_number(derating * 100)}%")
print("\nNOTES")
print(
"- Delta-v is ideal: gravity, attitude-control, and other "
"operational losses are not included."
)
print(
"- The maneuvering result assumes all unreserved mass "
"allowance is usable propellant."
)
print(
"- Actual electrical output depends on array temperature, "
"illumination angle, degradation, and power-system losses."
)
print("=" * 54)
if __name__ == "__main__":
main()
====================================================== ARGO ALPHA-AUXMOD PERFORMANCE ====================================================== SPACECRAFT MASS Alpha capsule: 5,200.0 kg AUXMOD operating mass: 2,850.0 kg AUXMOD dry mass: 1,640.0 kg AUXMOD propellant budget: 1,210.0 kg Combined operating mass: 8,050.0 kg Combined dry mass: 6,840.0 kg PROPULSION AND MANEUVERING Hypergolic Isp: 314.0 s How much propellant (kg) must be reserved for retro-fire operations? Enter a value from 0 to 1210.0. Press Enter for 0 kg (optimistic upper bound). Retro-fire reserve (kg): 300 Retro-fire reserve: 300.0 kg Propellant for maneuvering: 910.0 kg Mass before maneuver: 8,050.0 kg Mass after maneuver: 7,140.0 kg Ideal docking Δv budget: 369.4 m/s Absolute ideal Δv maximum: 501.6 m/s
#!/usr/bin/env python3
import sys
import re
import codecs
SKIP_DESTINATIONS = {
"fonttbl", "colortbl", "stylesheet", "info", "pict",
"object", "objdata", "header", "headerl", "headerr",
"footer", "footerl", "footerr", "filetbl", "listtable",
"listoverridetable", "generator", "xmlnstbl", "datastore",
"themedata", "colorschememapping", "latentstyles",
"rsidtbl", "revtbl", "annotation", "atnauthor",
"atnid", "atnref", "atntime", "aftncn", "aftnsep",
"aftnsepc", "ftncn", "ftnsep", "ftnsepc",
"object", "nonshppict", "shppict", "do", "formfield",
}
SPECIAL_CHARS = {
"\\": "\\",
"{": "{",
"}": "}",
"~": "\u00a0",
"_": "\u2011",
"-": "",
}
SPECIAL_WORDS = {
"emdash": "\u2014",
"endash": "\u2013",
"emspace": "\u2003",
"enspace": "\u2002",
"qmspace": "\u2005",
"bullet": "\u2022",
"lquote": "\u2018",
"rquote": "\u2019",
"ldblquote": "\u201c",
"rdblquote": "\u201d",
"zwj": "\u200d",
"zwnj": "\u200c",
}
def convert(data):
text = data.decode("latin-1")
state = {
"skip": False,
"uc": 1,
"codepage": "cp1252",
"ignorable": False,
}
stack = []
output = []
i = 0
n = len(text)
def emit(s):
if not state["skip"]:
output.append(s)
def decode_byte(value):
try:
return bytes([value]).decode(
state["codepage"], errors="replace"
)
except LookupError:
return bytes([value]).decode("cp1252", errors="replace")
def decode_raw(s):
"""Decode raw RTF text bytes using the current code page."""
if state["skip"]:
return
raw = bytes(ord(c) for c in s)
try:
output.append(
raw.decode(state["codepage"], errors="replace")
)
except LookupError:
output.append(raw.decode("cp1252", errors="replace"))
while i < n:
c = text[i]
if c == "{":
stack.append(state.copy())
state = state.copy()
state["ignorable"] = False
i += 1
continue
if c == "}":
if stack:
state = stack.pop()
i += 1
continue
if c != "\\":
if c == "\r" or c == "\n":
i += 1
continue
if c == "\t":
emit("\t")
i += 1
continue
decode_raw(c)
i += 1
continue
i += 1
if i >= n:
break
c = text[i]
if c == "'":
if i + 2 < n:
try:
value = int(text[i + 1:i + 3], 16)
emit(decode_byte(value))
i += 3
continue
except ValueError:
pass
i += 1
continue
if not c.isalpha():
i += 1
if c == "*":
state["ignorable"] = True
continue
if c in SPECIAL_CHARS:
emit(SPECIAL_CHARS[c])
continue
if c == "~":
emit("\u00a0")
continue
if c == "\n" or c == "\r":
continue
if c == ":":
continue
if c == "|":
emit("|")
continue
if c == "\\":
emit("\\")
continue
continue
start = i
while i < n and text[i].isalpha():
i += 1
word = text[start:i]
sign = 1
if i < n and text[i] == "-":
sign = -1
i += 1
num_start = i
while i < n and text[i].isdigit():
i += 1
arg = None
if i > num_start:
arg = sign * int(text[num_start:i])
if i < n and text[i] == " ":
i += 1
if state["ignorable"]:
state["ignorable"] = False
state["skip"] = True
continue
if word in SKIP_DESTINATIONS:
state["skip"] = True
continue
if word == "ansicpg" and arg is not None:
state["codepage"] = f"cp{arg}"
continue
if word == "uc" and arg is not None:
state["uc"] = max(0, arg)
continue
if word == "u" and arg is not None:
value = arg if arg >= 0 else arg + 65536
emit(chr(value))
fallback = state["uc"]
while fallback > 0 and i < n:
if text[i] == "\\":
if i + 1 < n and text[i + 1] == "'":
i = min(i + 4, n)
elif i + 1 < n and not text[i + 1].isalpha():
i += 2
else:
break
elif text[i] in "{}":
break
else:
i += 1
fallback -= 1
continue
if word in ("par", "row"):
emit("\n")
continue
if word == "line":
emit("\n")
continue
if word == "tab":
emit("\t")
continue
if word == "page":
emit("\n")
continue
if word == "sect":
emit("\n")
continue
if word in SPECIAL_WORDS:
emit(SPECIAL_WORDS[word])
continue
if word == "emdash":
emit("\u2014")
continue
if word == "enspace":
emit("\u2002")
continue
if word == "ansi":
state["codepage"] = "cp1252"
continue
if word == "mac":
state["codepage"] = "mac_roman"
continue
if word == "pc":
state["codepage"] = "cp437"
continue
if word == "pca":
state["codepage"] = "cp850"
continue
result = "".join(output)
result = result.replace("\r\n", "\n").replace("\r", "\n")
result = re.sub(r"[ \t]+\n", "\n", result)
result = re.sub(r"\n{4,}", "\n\n\n", result)
return result
def main():
data = sys.stdin.buffer.read()
result = convert(data)
sys.stdout.write(result)
if __name__ == "__main__":
main()
#!/bin/bash
find . -type f -iname '*.rtf' -print0 |
while IFS= read -r -d file; do
rtf2txt < "$file" > "${file%.*}.txt"
done
#! /usr/bin/bc -lq
define t(x) {
return s(x) / c(x)
}
define y(y) {
if (y == -1) return -2 * a(1) /* -pi/2 */
if (y == 1) return 2 * a(1) /* pi/2 */
return a(y / sqrt(1 - y * y))
}
define x(x) {
auto angle
if (x == 0) return 2 * a(1) /* pi/2 */
angle = a(sqrt(1 - x * x) / x)
if (x < 0) return angle + 4 * a(1)
return angle
}
p = 4 * a(1) /* pi */
d = p / 180 /* one degree in radians */
print "Using radians:\n"
"sin(-pi / 6) = "; s(-p / 6)
"cos(3 * pi / 4) = "; c(3 * p / 4)
"tan(pi / 3) = "; t(p / 3)
"asin(-1 / 2) = "; y(-1 / 2)
"acos(-sqrt(2) / 2) = "; x(-sqrt(2) / 2)
"atan(sqrt(3)) = "; a(sqrt(3))
print "\n\nUsing degrees:\n"
"sin(-30) = "; s(-30 * d)
"cos(135) = "; c(135 * d)
"tan(60) = "; t(60 * d)
"asin(-1 / 2) = "; y(-1 / 2) / d
"acos(-sqrt(2) / 2) = "; x(-sqrt(2) / 2) / d
"atan(sqrt(3)) = "; a(sqrt(3)) / d
quit
Python code to generate 26 page headers for a chapter of my magnum opus: