Skip to content

Instantly share code, notes, and snippets.

@livibetter
Last active June 29, 2021 22:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save livibetter/4228803 to your computer and use it in GitHub Desktop.
Save livibetter/4228803 to your computer and use it in GitHub Desktop.
Single files
#!/bin/bash
# Bash Bulls and Cows game
# Copyright (c) 2014 by Yu-Jie Lin
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# possible choices
NUMS=(0 1 2 3 4 5 6 7 8 9)
# number of digits
DIGITS=4
# non-empty == no numbers are repeated
NO_REPEAT=1
new_N() {
local nums=(${NUMS[@]}) i idx
N=
for ((i = 0; i < DIGITS; i++)) {
((idx = ${#nums[@]} * RANDOM / 32768))
N="$N${nums[idx]}"
[[ $NO_REPEAT ]] && nums=(${nums[@]:0:$((idx ? idx : 0))} ${nums[@]:idx + 1})
}
}
guesses=0
new_N
echo ${N[@]}
while read -p 'Guess? ' G; do
((${#G} != ${#N})) && continue
((guesses++))
A=0
B=0
for ((i = 0; i < DIGITS; i++)) {
[[ ${G:i:1} == ${N:i:1} ]] && ((++A)) && continue
for ((j = 0; j < DIGITS; j++)) {
((i == j)) && continue;
[[ ${G:j:1} == ${N:i:1} ]] && ((++B)) && break
}
}
printf '#%2d: %s -> %d A %d B\n' $guesses $G $A $B
if [[ $G == $N ]]; then
echo 'You win!'
break
fi
done
#!/bin/bash
# Written by Yu-Jie Lin
func() {
while caller $((i++)); do :; done | tac
caller
}
func1() {
func
}
func2() {
func1
}
caller
echo
func
echo
func1
echo
func2
#!/usr/bin/env python
# Simple HTTP Server which echos status code indicated by request path
#
# Copyright (C) 2013 by Yu-Jie Lin
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Gist: https://gist.github.com/4228803
# Code from lnkckr: https://bitbucket.org/livibetter/lnkckr
# Inspired by: http://httpstat.us
try:
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import unquote
except ImportError:
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from urlparse import unquote
import re
HOST = 'localhost'
PORT = 8000
H = 'http://%s:%s/' % (HOST, PORT)
class Handler(BaseHTTPRequestHandler):
RE_CODE = re.compile(r'/(\d{3})')
def do_GET(self):
headers = {}
body = None
m = self.RE_CODE.match(self.path)
code = int(m.group(1)) if m else None
if self.path == '/' or code == 200:
code = 200
elif self.path == '/loop':
code = 302
headers['Location'] = '/loop'
elif code in (301, 302):
headers['Location'] = H
else:
code = 404
if 'Location' not in headers:
headers['Content-Type'] = 'text/html'
body = unquote(self.headers.get('X-Echo'))
self.send_response(code)
for k, v in headers.items():
self.send_header(k, v)
self.end_headers()
if body:
self.wfile.write(body.encode('utf8'))
def do_HEAD(self):
self.do_GET()
def main():
try:
httpd = HTTPServer((HOST, PORT), Handler)
httpd.serve_forever()
except KeyboardInterrupt:
pass
if __name__ == '__main__':
main()
#!/usr/bin/env python3
# Written by Yu-Jie Lin in 2015
# Public Domain
#
# Blog: http://blog.yjl.im/2015/02/plotting-number-of-installed-gentoo.html
# Dependencies:
# - Python 2 or 3
# - Matplotlib
import re
from datetime import datetime
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import dates
EMERGE_LOG = '/var/log/emerge.log'
EMERGE_LdOG = 'emerge.log'
# http://dev.gentoo.org/~ulm/pms/5/pms.html#x1-170003.1
RE_PKG = re.compile('([A-Za-z0-9+_.-]+/[A-Za-z0-9+_-]+)-([0-9]+(?:\.[0-9]+)*(?:-r[0-9]+)?)')
def main():
_f = lambda line: 'completed emerge' in line or 'unmerge success' in line
_m = lambda line: (
datetime.fromtimestamp(float(line.split(':', 1)[0])),
RE_PKG.search(line).groups(),
'emerge' in line,
)
pkg_t = []
pkg_ver = {}
with open(EMERGE_LOG) as log:
logs = map(_m, filter(_f, log))
pkgs = 0
vers = 0
for t, (name, version), merged in logs:
if merged:
if name not in pkg_ver:
pkg_ver[name] = []
pkg_ver[name].append(version)
if len(pkg_ver[name]) == 1:
pkgs += 1
else:
try:
pkg_ver[name].remove(version)
except (KeyError, ValueError):
print('%s %s-%s' % (t, name, version))
continue
if len(pkg_ver[name]) == 0:
pkgs -= 1
vers += merged or -1
pkg_t.append((t, pkgs, vers))
print(pkgs, vers)
data = np.array(pkg_t)
date = dates.date2num(data[:, 0])
pkgs = data[:, 1]
vers = data[:, 2]
fig, ax = plt.subplots()
ax.xaxis.set_major_locator(dates.YearLocator())
ax.xaxis.set_major_formatter(dates.DateFormatter('%Y-%m-%d'))
ax.set_title('Installed Packages')
ax.set_ylabel('Amount')
ax.plot(date, vers, date, pkgs)
plt.legend(('Versions', 'Packages'))
plt.show()
if __name__ == '__main__':
main()
#!/usr/bin/env python
# Written by Yu-Jie Lin
# Publice Domain
#
# <googleapis.json jq '.items | map(select(.name == "name"))'
from __future__ import print_function
from itertools import groupby
from os import path
import json
JSON = 'googleapis.json'
# https://developers.google.com/api-client-library/python/apis/discovery/v1
from apiclient.discovery import build
def main():
if path.exists(JSON):
with open(JSON) as f:
resp = json.load(f)
else:
service = build('discovery', 'v1')
# http://goo.gl/dE6qqb - discovery_v1.apis list method
req = service.apis().list()
resp = req.execute()
with open(JSON, 'w') as f:
json.dump(resp, f)
apis = resp['items']
width = max(len(api['name']) for api in apis)
g = groupby(apis, key=lambda item: (item['name'], item['title']))
for name_title, versions in g:
name, title = name_title
versions = ', '.join(version['version'] for version in versions)
print('{name:{width}}: {title}'.format(
width=width, name=name, title=title))
print(' {versions}'.format(versions=versions))
if __name__:
main()
#!/bin/bash
# Copyright (c) 2013 Yu-Jie Lin
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Blog: http://blog.yjl.im/2013/10/letterize-and-cwtext-morse-code.html
usage() {
echo "Usage: $(basename $0) [OPTION]...
Option:
-a play audio
-h help message
"
}
PLAY_AUDIO=
while getopts "ah" arg; do
case $arg in
a)
PLAY_AUDIO=1
;;
h)
usage
exit 0
;;
esac
done
if [[ $PLAY_AUDIO ]]; then
while read -N 1 ch; do
echo "$ch"
done | cwpcm | mplayer -msglevel all=-1 -rawaudio samplesize=1:channels=1:rate=44100 -demuxer rawaudio -
else
while read -N 1 ch; do
echo "$ch" | cwtext
done
fi
#!/usr/bin/env python
# Using pangocairo to list monospace fonts
# Written by Yu-Jie Lin
#
# Blog: http://blog.yjl.im/2012/12/listing-monospace-fonts-using-pango.html
# Gist: https://gist.github.com/4228803
import pangocairo
fmap = pangocairo.cairo_font_map_get_default()
# fonts = {fontname: font, ...}
fonts = dict((font.get_name(), font) for font in fmap.list_families() \
if font.is_monospace() and ' - subset of ' not in font.get_name())
fname_maxlen = max(map(len, fonts.keys()))
for fontname, font in sorted(fonts.items()):
faces = ' '.join(face.get_face_name() for face in font.list_faces())
print '{1:{0}s}: {2}'.format(fname_maxlen, fontname, faces)
#!/bin/bash
# Printing out longest and shortest package names in Gentoo Portage tree
# Written by Yu-Jie Lin
#
# Web : http://yjl.im
# Gist: https://gist.github.com/4228803
# sorting and print top and bottom N
stb () {
N=${1:-5}
sort -n | tee >(sed -n "1,${N}p") >(tail -$N) >/dev/null
}
echo 'Name lengths including category names:'
eix --only-names | while read line; do echo ${#line} $line; done | stb
echo
echo 'Name lengths without counting category names:'
PRINT_COUNT_ALWAYS=never eix --format '<category> <name>\n' | while read cat name; do echo ${#name} $cat/$name ; done | stb
#!/bin/bash
# Unleash the dark side of Bash (unfinished code)
#
# In $HOME/.bashrc:
# source /path/to/mean.bash
#
# Copyright (c) 2012 Yu-Jie Lin
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
trap 'CMD2=$CMD1 ; CMD1=$BASH_COMMAND' DEBUG
mean_bash() {
local ret=$?
local CMD2=($CMD2) CMD=($CMD1)
local mocks=() cmd=
# no errors
if ((ret == 0)); then
return
fi
# find the erroneous command from $CMD1 and $CMD2
if [[ ${CMD[0]} == ${FUNCNAME[0]} ]]; then
CMD=${CMD2[@]}
fi
if [[ ${CMD[0]} != ${FUNCNAME[0]} ]]; then
# find the real command name
for cmd in ${CMD[@]}; do
if [[ $cmd != *=* ]]; then
break
fi
done
fi
# command not found error, this also can be done through
# command_not_found_handler
if ((${#mocks[@]} == 0)) && ! type $cmd &>/dev/null; then
mocks=(
"LOL @ \`$cmd\`, you can't type?"
"\`$cmd\`, are you drunk?"
)
fi
# mocking with specific command and exit status
if ((${#mocks[@]} == 0)); then
case "$cmd/$ret" in
diff/[01])
# not actually an error
return $ret
;;
sleep/130)
mocks=(
"Can't sleep, huh?"
)
;;
esac
fi
# mocking with only the command
if ((${#mocks[@]} == 0)); then
case "$cmd" in
cp|ls|mv)
mocks=(
"Really? you failed at $cmd?"
)
;;
sleep)
mocks=(
"Need a some energy drink?"
)
;;
esac
fi
# generic mocks for specific exit status
if ((${#mocks[@]} == 0)); then
case "$ret" in
130)
mocks=(
"I swear to god, if you hit Ctrl+C one more time, I will stick Ctrl and C keys on your head, see if you dare!"
"Stop the Ctrl+C already! I warn you!"
)
;;
esac
fi
# generic mocks when no matches from cases above
if ((${#mocks[@]} == 0)); then
mocks=(
'Go back to Windows!'
'My grandma can do better than you!'
"$(uname) is not a toy, kiddo!"
"RTFM!"
"STFW!"
)
fi
if [[ ! -z $cmd ]] && ! type $cmd &>/dev/null; then
mocks=(
"${mocks[@]}"
"Dudu, read \`man $cmd\`!"
"Run \`$cmd --help\`, please!"
)
fi
echo -e "\e[31;1m${mocks[RANDOM * ${#mocks[@]} / 32767]}\e[0m"
return $ret
}
if [[ $PROMPT_COMMAND != mean_bash* ]]; then
PROMPT_COMMAND="mean_bash;$PROMPT_COMMAND"
fi
#!/bin/bash
# Finding packages has never been installed on the system.
# Written by Yu-Jie Lin
#
# Blog: http://blog.yjl.im/2012/12/listing-packages-you-have-never-tried.html
# Gist: https://gist.github.com/4228803
# the `genlop`: Get list of ever installed packages
# the `eix` : Get list of not installed packages
diff <(genlop -ln | sed 's/.* >>> \(.*\/.*\)-[0-9.]\+.*/\1/' | sort | uniq) \
<(eix -! -I $@ --only-names) \
| sed -n '/>/ s/> //p'
#!/bin/bash
# *** unfinished ***
# noisy-blocks.sh
# Copyright 2013 Yu-Jie Lin
#
# examples:
#
# cat /dev/urandom | ./noisy-blocks.sh
# cat FILE | ./noisy-blocks.sh
# wget URL -O - | ./noisy-blocks.sh
W=$(tput cols)
H=$(tput lines)
I=(16777216 65536 256 1)
while :; do while read -N 9 data; do
x=0
for ((i=0; i<4; i++)); do
printf -v ii '%d' "'${data:i}"
((x += ii * ${I[i]}))
done
y=0
for ((i=4; i<8; i++)); do
printf -v ii '%d' "'${data:i}"
((y += ii * ${I[i-4]}))
done
printf -v c '%d' "'${data:8}"
((x = (x % (W / 2)) * 2 + 1))
((y = (y % H) + 1))
((c = c % 8 + 40))
echo -ne "\e[${y};${x}H\e[${c}m \e[0m"
sleep 0.001
done; done
#!/bin/bash
# Copyright (c) 2013 Yu-Jie Lin
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# gunzip the following files of
# The Online Encyclopedia of Integer Sequences (R) http://oeis.org/
#
# 1. http://oeis.org/stripped.gz
# 2. http://oeis.org/names.gz
read AS LINE <<< "$(grep '^A' stripped | shuf -n 1)"
read _ NAME <<< "$(grep $AS names)"
NUMBERS=(${LINE//,/ })
trap 'echo;echo;echo;echo;exit' INT EXIT
clear
W=$(tput cols)
H=$(tput lines)
CX=$((W / 2))
CY=$((H / 2))
echo -ne "\e[$((1 + CY - 2));$((1 + (W - ${#AS}) / 2))H"
echo -ne "\e[1;37m$AS\e[0m"
echo -ne "\e[$((1 + CY + 2));$((1 + (W - ${#NAME}) / 2))H"
echo -ne "\e[37m$NAME\e[0m"
for num in ${NUMBERS[@]}; do
for ((i = 0; i < ${#prev_num}; i++)); do
echo -ne '\e[D \e[D'
sleep 0.1
done
echo -ne "\e[$((1 + CY));$((1 + (W - ${#num}) / 2))H"
for ((i = 0; i < ${#num}; i++)); do
echo -ne "\e[1;32m${num:i:1}\e[0m"
sleep 0.1
done
sleep 3
prev_num=$num
done
Vim scroll to / cursor motions: H M L zt z. zb
Drawn by Yu-Jie Lin
[t]
. .|.[H]---[L]--------------+
[Shift] [z]. . .[b]. . [M] [.] |
| | | | | |
| | | +---|-------------+
+-----+-------+----------+ |
| |
| Top Middle Bottom of screen |
Cursor to | [H] [M] [L]-------------+
|
Scroll cursor|
line to +-[zt] [z.] [zb]
#!/bin/bash
# Converting date/time timestamp into Wikidot [[date]] [1] and optionally
# copying the tag to X selection if xsel is available
#
# Copyright:
# - Public Domain
# - Written by Yu-Jie Lin in 2015
#
# Note on my wiki [2].
#
# Dependencies:
# - date
# - xsel (optional)
#
# Note:
# - If no string is given, it returns the tag with current time.
# - If already Unix epoch timestamp, use @123456789.
# - Default format is %c local time format, environment variable can be used to
# override.
# - The input timestamp is kept as comment for the record.
#
# [1]: http://www.wikidot.com/doc-wiki-syntax:date
# [2]: http://note.yjl.im/wikidot#toc3
ts="${@:-now}"
tag="[[date $(date -d "$ts" +%s) format=\"${TIMEFORMAT:-%c}|agohover\"]][!-- $ts --]"
echo "$tag"
if which xsel &>/dev/null; then
echo -n "$tag" | xsel
if [[ "$tag" != "$(xsel -o)" ]]; then
echo "Failed to copy to X selection" >&2
exit 1
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment