├── awk └── num.awk ├── tcsh ├── reply ├── nodud ├── giphy ├── ogit ├── duck ├── define ├── unspace ├── nav ├── gbook ├── map ├── unzoom ├── news ├── slideshare ├── twit ├── walk ├── docs ├── md2tex2pdf ├── ttg ├── gsearch ├── gdocs ├── goog2eml ├── vlickr ├── gmail ├── unspace-mvs ├── clio └── ocr ├── sh ├── update ├── words ├── werds ├── npr ├── img ├── jorb ├── ffix ├── nypls ├── fix ├── flickr ├── r-install ├── oai_no_key └── login-public.sh ├── aux ├── md2pptx │ ├── image_url.jpg │ └── example.md ├── mdata.csv ├── mbody.asc ├── gift.txt ├── no-wiml.txt ├── manel.txt ├── rp-decline.asc ├── belmont.asc └── yeats.txt ├── osa └── embiggen.osa ├── doc ├── meeting.txt ├── learning.txt ├── curses.txt └── strategies.txt ├── csh ├── ghg ├── gshark └── twit ├── sed ├── normalize └── unai.sed ├── README.md ├── bash ├── ocr-latest.sh ├── quote-search ├── chrome-profile-open ├── pbwiki ├── rename ├── sniff ├── git-clean ├── gmail_search ├── doi2json ├── friends ├── ocr-grey ├── gh-add ├── ide ├── alarm ├── unspace-mvs ├── imake ├── oai-no-key.sh ├── doctor-link ├── imap ├── laugh ├── sunzip ├── vm2notes └── megunzip ├── py ├── pptx2txt ├── prose ├── repos ├── xlsx2xls ├── pdf2asc ├── alpha ├── xkcd ├── xlsx2tsv ├── tune ├── airport_codes.py ├── bsearch.py ├── vttclean ├── slides_util ├── yt-clean.py ├── eml2txt ├── create_presentation ├── unspace-mvit-ex ├── xls2tsv ├── gsheet-download ├── merge ├── zalgo ├── track-alias-count.py ├── weather ├── tz2tz ├── clip ├── iata ├── ocr2txt ├── md2pptx └── mise-track └── dotfiles ├── .vimrc-noline └── .vimrc /awk/num.awk: -------------------------------------------------------------------------------- 1 | {print NR". "$0} 2 | -------------------------------------------------------------------------------- /tcsh/reply: -------------------------------------------------------------------------------- 1 | awk '{print "> "$0}' 2 | -------------------------------------------------------------------------------- /sh/update: -------------------------------------------------------------------------------- 1 | vi `date +"%Y-%m-%dT%H:%M:%S"`.md 2 | -------------------------------------------------------------------------------- /sh/words: -------------------------------------------------------------------------------- 1 | tr '\-\t <>&".?,()/\\+:\!{}' '\n' 2 | -------------------------------------------------------------------------------- /tcsh/nodud: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | grep -v -e '^[ ]*$' 3 | -------------------------------------------------------------------------------- /aux/md2pptx/image_url.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrishwiggins/mise/HEAD/aux/md2pptx/image_url.jpg -------------------------------------------------------------------------------- /osa/embiggen.osa: -------------------------------------------------------------------------------- 1 | tell application "System Events" to tell process "Terminal" to keystroke "f" using {control down, command down} 2 | -------------------------------------------------------------------------------- /aux/mdata.csv: -------------------------------------------------------------------------------- 1 | email,name 2 | example1@example.com,John Doe 3 | example2@example.com,Jane Smith 4 | example3@example.com,Bob Johnson 5 | -------------------------------------------------------------------------------- /sh/werds: -------------------------------------------------------------------------------- 1 | sed -e 's/'"'"'//g' | /usr/bin/perl -pe 's/[^[:ascii:]]/+/g' | tr ';[]%=#\-\t <>&"?,()/\\+:\!{}' '\n' | sed -e 's/\.$//' | grep -v '^$' 2 | -------------------------------------------------------------------------------- /doc/meeting.txt: -------------------------------------------------------------------------------- 1 | 2 | It looks like this meeting is informational. Would it be possible for your group to send out an overview rather than having a meeting? 3 | 4 | 5 | -------------------------------------------------------------------------------- /tcsh/giphy: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% wraps around giphy, turns space into - 3 | 4 | set str=`echo $* | sed -e 's/ /-/g' ` 5 | echo $str 6 | open 'http://giphy.com/search/'$str 7 | -------------------------------------------------------------------------------- /aux/mbody.asc: -------------------------------------------------------------------------------- 1 | To: ${email} 2 | Subject: test 3 | 4 | Dear ${name}, 5 | 6 | This is a sample email body intended to demonstrate how you might structure an email. 7 | 8 | Best regards, 9 | Your Team 10 | -------------------------------------------------------------------------------- /aux/gift.txt: -------------------------------------------------------------------------------- 1 | Remember that you are the culmination of 315,000 years of homo sapiens, 4 billion years of evolution, and 14 billion years of space time. Forces are conspiring in your favor. Stay strong through the struggle. 2 | -------------------------------------------------------------------------------- /tcsh/ogit: -------------------------------------------------------------------------------- 1 | #open http://github.com/`git remote -v | cut -d: -f2 | cut -d\ -f1| head -1` 2 | open http://github.com/`git remote -v | cut -d: -f2 | sed -e 's/[\/]*github.com\///' | awk '{print $1}' | head -1 | sed 's/\.git$//'` 3 | -------------------------------------------------------------------------------- /aux/no-wiml.txt: -------------------------------------------------------------------------------- 1 | Thank you for considering me for this opportunity. 2 | I'd like to encourage you to consider instead any 3 | of these women working in machine learning 4 | (please let me know if you'd like an introduction): 5 | 6 | 7 | -------------------------------------------------------------------------------- /tcsh/duck: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% wraps around ddg, turns + into quotes 3 | #% turns spaces into URL spaces (%22) 4 | 5 | set str=`echo $* | sed -e 's/+/%22/g' | sed -e 's/ /+/g' ` 6 | echo $str 7 | open 'https://duckduckgo.com/?q='$str 8 | -------------------------------------------------------------------------------- /sh/npr: -------------------------------------------------------------------------------- 1 | # 2017-05-27: 2 | open `curl 'https://www.npr.org/rss/podcast.php?id=500005' | tr '<>?"' '\n' | grep -i mp3| head -1` 3 | 4 | # before 2017-05-27: 5 | # open `curl http://www.npr.org/rss/podcast.php?id=500005| tr '<>"' '\n' | grep -i mp3 | head -1` 6 | -------------------------------------------------------------------------------- /tcsh/define: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% wraps around site, turns + into quotes 3 | #% turns spaces into URL spaces (%22) 4 | 5 | set str=`echo $* | sed -e 's/+/%22/g' | sed -e 's/ /+/g' ` 6 | echo $str 7 | open 'https://en.wiktionary.org/wiki/Special:Search?search='$str 8 | -------------------------------------------------------------------------------- /aux/manel.txt: -------------------------------------------------------------------------------- 1 | Thanks for thinking of me! 2 | 3 | At a public conference, 4 | I won’t serve on a panel of two people or more, 5 | unless there is at least one woman on the panel, 6 | not including the moderator/chair. 7 | 8 | Please let me know if you'd like me to suggest other participants. 9 | -------------------------------------------------------------------------------- /tcsh/unspace: -------------------------------------------------------------------------------- 1 | #/bin/tcsh -f -X -V 2 | 3 | # replace contents of clipboard with something in ascii w/o spaces 4 | # ex: Jan-Willem Van de Meent 5 | 6 | pbpaste | /usr/bin/perl -pe 's/[^[:ascii:]]/-/g' | sed 's/[ ,][ ,]*/_/g' | sed -e 's/^[ ]*//' -e 's/[ ]*$//' -e 's/^_//' -e 's/_$//' | pbcopy 7 | -------------------------------------------------------------------------------- /csh/ghg: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% github search 3 | #% turns + into quotes 4 | #% turns spaces into URL spaces (%22) 5 | 6 | set str=`echo $* | sed -e 's/+/%22/g' | sed -e 's/ /+/g' ` 7 | echo $str 8 | open 'http://github.com/search?q='$str'&type=Everything&repo=&langOverride=&start_value=1' 9 | -------------------------------------------------------------------------------- /tcsh/nav: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% wraps around google maps 3 | #OLD:% turns spaces into URL spaces (%22) 4 | #NEW:% turns spaces into + 5 | # make sure you include "/" in the input, separating places 6 | 7 | set str=`echo $* | sed -e 's/ /+/g'` 8 | echo $str 9 | open 'http://www.google.com/maps/dir/'$str 10 | -------------------------------------------------------------------------------- /tcsh/gbook: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% wraps around google, turns + into quotes 3 | #% turns spaces into URL spaces (%22) 4 | 5 | set str=`echo $* | sed -e 's/+/%22/g' | sed -e 's/ /+/g' ` 6 | echo $str 7 | open 'https://www.google.com/search?tbm=bks&q='$str 8 | 9 | # examples 10 | # https://www.google.com/search?tbm=bks&q=word+%22a+phrase%22 11 | -------------------------------------------------------------------------------- /tcsh/map: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% wraps around google maps, turns + into quotes 3 | #% turns spaces into URL spaces (%22) 4 | 5 | set str=`echo $* | sed -e 's/ /%20/g'` 6 | echo $str 7 | #open 'http://www.google.com/maps/place/'$str 8 | chrome-profile-open 0 'http://www.google.com/maps/place/'$str 9 | # open -a safari 'http://www.google.com/maps/place/'$str 10 | -------------------------------------------------------------------------------- /sh/img: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% script for google images 3 | #% wraps around google, turns + into quotes 4 | #% turns spaces into URL spaces (%22) 5 | 6 | set str=`echo $* | sed -e 's/+/%22/g' | sed -e 's/ /+/g' | sed -e 's/\#/%23/g' ` 7 | echo $str 8 | open 'http://www.google.com/images?hl=en&lr=&safe=off&c2coff=1&q='$str'&um=1&ie=UTF-8&source=og&sa=N&tab=wi&biw=1255&bih=668' 9 | -------------------------------------------------------------------------------- /tcsh/unzoom: -------------------------------------------------------------------------------- 1 | kill -9 `lsof -i :19421 | awk '{print $2}' | tail -1` 2 | # For just your local account 3 | defaults write ~/Library/Preferences/us.zoom.config.plist ZDisableVideo 1 4 | # For all users on the machine 5 | sudo defaults write /Library/Preferences/us.zoom.config.plist ZDisableVideo 1 6 | mi ~/.zoomus ~/.zoomus-brk 7 | touch ~/.zoomus 8 | rm -rf /Applications/zoom.us.app/ 9 | -------------------------------------------------------------------------------- /tcsh/news: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% wraps around google, turns + into quotes 3 | #% turns spaces into URL spaces (%22) 4 | 5 | if ( $#argv != 1 ) then 6 | open http://news.google.com/ 7 | else 8 | set str=`echo $* | sed -e 's/+/%22/g' | sed -e 's/ /+/g' ` 9 | echo $str 10 | open 'http://www.google.com/search?hl=en&gl=us&tbm=nws&btnmeta_news_search=1&q='$str 11 | endif 12 | -------------------------------------------------------------------------------- /aux/rp-decline.asc: -------------------------------------------------------------------------------- 1 | Thank you for inviting me to this meeting. It seems from the subject, agenda and attendees list that I’m not a required participant for this meeting. If I’m mistaken and my presence is required in this meeting, please accept my apologies and let me know that I should attend. 2 | % text from rajiv pant, CTO of NYT, http://www.rajiv.com/blog/2013/11/09/how-to-reply-to-meeting-requests/ 3 | -------------------------------------------------------------------------------- /sh/jorb: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh 2 | 3 | lynx -width=999 -dump -hiddenlinks=ignore -image_links=no -minimal -nobold -nolist -pseudo_inlines -force_html http://www.hrwiki.org/wiki/A_Jorb_Well_Done \ 4 | | /usr/bin/perl -pe 's/[^[:ascii:]]/+/g'\ 5 | | tr '\-\t <>&".?,()/\\+:\!{}' '\n' \ 6 | | tr '[A-Z]' '[a-z]' \ 7 | | grep ^j \ 8 | | grep b$ \ 9 | | sort -bfd \ 10 | | uniq -c \ 11 | | sort -nr 12 | -------------------------------------------------------------------------------- /csh/gshark: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% turns + into URL spaces (%22) 3 | #% turns spaces into + 4 | 5 | set str=`echo $* | sed -e 's/+/%22/g' | sed -e 's/ /+/g' ` 6 | open -a firefox 'http://grooveshark.com/#\!/search?q='$str 7 | 8 | # example: 9 | # open 'http://grooveshark.com/#!/search?q=stuff+%22a+phrase%22'$str'&btnG=Search' 10 | # http://grooveshark.com/#!/search?q=some+words+%22a+phrase%22 11 | -------------------------------------------------------------------------------- /tcsh/slideshare: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% wraps around slideshare search, 3 | #% turns + into quotes 4 | #% turns spaces into URL spaces (%22) 5 | 6 | set str=`echo $* | sed -e 's/+/%22/g' | sed -e 's/ /+/g' ` 7 | echo $str 8 | open 'http://www.slideshare.net/search/slideshow?searchfrom=header&q=' 9 | 10 | 11 | # examples 12 | # http://www.slideshare.net/search/slideshow?searchfrom=header&q=word+%22a+phrase%22 13 | -------------------------------------------------------------------------------- /sed/normalize: -------------------------------------------------------------------------------- 1 | s/\#/\\\#/g 2 | s/\*/\\\*/g 3 | s/\&/\\\&/g 4 | s/\[/\\\[/g 5 | s/\]/\\\]/g 6 | s/ /\\ /g 7 | s/(/\\(/g 8 | s/)/\\)/g 9 | s/\,/\\\,/g 10 | s/'/\\\'/g 11 | s/"/\\\"/g 12 | s/\!/\\\!/g 13 | #s/\/\\\>/g 15 | s/\;/\\;/g 16 | s/\$/\\\$/g 17 | s/\?/\\\?/g 18 | #s/\|/\\\|/g 19 | ## THESE DON'T NEED ESCAPE ( \ ) 20 | s//\\\>/g 22 | s/|/\\\|/g 23 | s/`/\\\`/g 24 | s/^-/\.\\\/-/ 25 | -------------------------------------------------------------------------------- /tcsh/twit: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | # wraps around twitter search 3 | # turns + into quotes 4 | # turns spaces into URL spaces (%22) 5 | # http://search.twitter.com/search?q=this+is+%22a+phrase%22 6 | # chris.wiggins@gmail.com 7 | 8 | set str=`echo $* | sed -e 's/+/%22/g' | sed -e 's/ /+/g' ` 9 | # comment me out for unverbose 10 | echo $str 11 | #was: open 'http://search.twitter.com/search?q='$str 12 | open 'http://twitter.com/#\!/search/'$str 13 | -------------------------------------------------------------------------------- /csh/twit: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% turns + into quotes 3 | #% turns spaces into URL spaces (%22) 4 | #% http://search.twitter.com/search?q=this+is+%22a+phrase%22 5 | 6 | set str=`echo $* | sed -e 's/+/%22/g' | sed -e 's/ /+/g' ` 7 | echo $str 8 | # brave breaks 9 | #open -a safari 'http://twitter.com/search?f=realtime&q='$str'&src=typd' 10 | # back to brave 20211022 11 | open -a ~/bin/brave 'http://twitter.com/search?f=realtime&q='$str'&src=typd' 12 | -------------------------------------------------------------------------------- /tcsh/walk: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | 3 | # example: 4 | # wiggins@tantanmen{cli-fu}144: walk "united nations, nyc" "time square, nyc" 5 | # "23 mins" 6 | # wiggins@tantanmen{cli-fu}145: 7 | 8 | 9 | set orig=`echo $1|sed -e 's/ /+/g'` 10 | set dest=`echo $2|sed -e 's/ /+/g'` 11 | curl --silent 'http://maps.googleapis.com/maps/api/directions/json?origin='$orig'&destination='$dest'&sensor=true&mode=walking' | jq '.routes|.[0]|.legs|.[0]|.duration|.text' 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | mise 2 | ==== 3 | 4 | public [mise](http://en.wikipedia.org/wiki/Mise_en_place) 5 | 6 | "He has his mise en place," his friend the chef Eric Ripert told me, noting that Bourdain's punctiliousness is a reflection not only of his personality and his culinary training but also of necessity: if he weren't so structured, he could never stay on top of his proliferating commitments. 7 | 8 | -- [source](https://www.newyorker.com/magazine/2017/02/13/anthony-bourdains-moveable-feast) 9 | -------------------------------------------------------------------------------- /sed/unai.sed: -------------------------------------------------------------------------------- 1 | s/🧠//g 2 | s/🎯//g 3 | s/📚//g 4 | s/📊//g 5 | s/🚀//g 6 | s/🛠//g 7 | s/📂//g 8 | s/🔑//g 9 | s/🌟//g 10 | s/💡//g 11 | s/🎉//g 12 | s/🤖//g 13 | s/✅//g 14 | s/❤️//g 15 | s/❌//g 16 | s/📧//g 17 | s/🗓️//g 18 | s/🎉//g 19 | s/💬//g 20 | s/🌐//g 21 | s/🔮//g 22 | s/📋//g 23 | s/🎭//g 24 | s/🤔//g 25 | s/💭//g 26 | s/📈//g 27 | s/🔗//g 28 | s/🔍//g 29 | s/📥//g 30 | s/🔄//g 31 | s/🎮//g 32 | s/🧪//g 33 | s/🏆//g 34 | s/📖//g 35 | s/🙏//g 36 | s/✓/[YES]/g 37 | s/✗/[NO]/g 38 | s/→/->/g 39 | -------------------------------------------------------------------------------- /bash/ocr-latest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Get the latest screenshot file 4 | latest_screenshot=$(ls -t ~/Shots/ | grep -E '^Screenshot ' | head -n 1) 5 | 6 | # Check if a screenshot is found 7 | if [ -z "$latest_screenshot" ]; then 8 | echo "No screenshot found." 9 | exit 1 10 | fi 11 | 12 | # Run Tesseract OCR on the latest screenshot 13 | #tesseract ~/Shots/"$latest_screenshot" /tmp/ocr.txt 14 | tesseract ~/Shots/"$latest_screenshot" /tmp/ocr 15 | 16 | # Inform the user 17 | echo "OCR output written to /tmp/ocr.txt" 18 | -------------------------------------------------------------------------------- /sh/ffix: -------------------------------------------------------------------------------- 1 | # i suggest that before you fix you sometimes asciify, i.e., 2 | # /usr/bin/perl -pe 's/[^[:ascii:]]/+/g' \ 3 | # 4 | # NB: smoetimes when i indent at beginning, i mean it. so i deleted these 5 | # 6 | # 20210203 adding grep -v 7 | # 1) '\f' and 8 | # 2) lines that are just numbers 9 | 10 | fix| \ 11 | sed \ 12 | -e 's/^[ ]*//' \ 13 | -e 's/^[ ]*,[ ]*//' \ 14 | -e 's/^[> ]*//' \ 15 | | grep -v -e '\f' -e '^[0-9][0-9]*$' \ 16 | | uniq 17 | 18 | # cf http://www.w3schools.com/TAGS/ref_urlencode.asp 19 | -------------------------------------------------------------------------------- /sh/nypls: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh 2 | 3 | open -a /Applications/Brave\ Browser.app 'https://browse.nypl.org/iii/encore/myaccount?lang=eng' 4 | open -a /Applications/Firefox.app/ 'https://browse.nypl.org/iii/encore/myaccount?lang=eng' 5 | open -a /Applications/Google\ Chrome.app 'https://browse.nypl.org/iii/encore/myaccount?lang=eng' 6 | open -a /Applications/Safari.app 'https://browse.nypl.org/iii/encore/myaccount?lang=eng' 7 | open -a /Applications/Opera.app 'https://browse.nypl.org/iii/encore/myaccount?lang=eng' 8 | 9 | grep '^nypl ' /Users/wiggins/gd/local/seiton/aux/phone.asc 10 | -------------------------------------------------------------------------------- /tcsh/docs: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% open your browser in a search 3 | #% eliminates spaces 4 | #% turns / (for dates) into url-formatted / 5 | # 6 | # ex https://docs.google.com/#search/projects 7 | # ex https://drive.google.com/drive/u/0/search?q=Charlotte 8 | # 20180412T06h38PDT https://drive.google.com/drive/u/0/search?q=word%20%22a%20phrase%22 9 | 10 | set str=`echo $* | sed -e 's/\ /+/g' -e 's/\//%2F/g'` 11 | # echo $str 12 | # 13 | # changed 2014-12-19 14 | # open 'https://drive.google.com/?authuser=0#search/'$str 15 | # 16 | open 'https://drive.google.com/drive/u/0/#search?q='$str 17 | -------------------------------------------------------------------------------- /py/pptx2txt: -------------------------------------------------------------------------------- 1 | #!/opt/homebrew/bin/python3 2 | 3 | from pptx import Presentation 4 | import sys 5 | 6 | 7 | def pptx_to_text(pptx_file): 8 | presentation = Presentation(pptx_file) 9 | text = [] 10 | for slide in presentation.slides: 11 | for shape in slide.shapes: 12 | if hasattr(shape, "text"): 13 | text.append(shape.text) 14 | return "\n".join(text) 15 | 16 | 17 | if __name__ == "__main__": 18 | if len(sys.argv) != 2: 19 | print("Usage: python pptx2txt.py ") 20 | sys.exit(1) 21 | 22 | pptx_file = sys.argv[1] 23 | print(pptx_to_text(pptx_file)) 24 | -------------------------------------------------------------------------------- /bash/quote-search: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Base URL 4 | url="https://quoteinvestigator.com/?s=" 5 | 6 | # Initialize the formatted string 7 | formatted_input="" 8 | 9 | # Process each argument 10 | for arg in "$@"; do 11 | # If argument contains spaces, wrap with encoded quotes 12 | if [[ $arg =~ \ ]]; then 13 | arg="%22$(echo "$arg" | sed 's/ /+/g')%22" 14 | else 15 | arg=$(echo "$arg" | sed 's/ /+/g') 16 | fi 17 | # Append to the formatted string 18 | formatted_input+="$arg+" 19 | done 20 | 21 | # Remove trailing '+' 22 | formatted_input=${formatted_input%+} 23 | 24 | # Open the URL 25 | open "${url}${formatted_input}" 26 | -------------------------------------------------------------------------------- /tcsh/md2tex2pdf: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | 3 | setenv tex $1:r.tex 4 | setenv pdf $tex:r.pdf 5 | 6 | setenv owd $cwd 7 | 8 | setenv dir /tmp/md2tex2pdf-$$ 9 | setenv aux aux.asc 10 | 11 | 12 | echo owd $owd 13 | 14 | # mk dir & mv stuff there 15 | mkdir $dir 16 | cp -f $1 $dir 17 | cd $dir 18 | 19 | # do work 20 | pandoc -f markdown -t latex $1 -o $aux 21 | 22 | # add header & footer 23 | echo "\documentclass{article}\begin{document}" >! $tex 24 | cat $aux >> $tex 25 | echo "\end{document}" >> $tex 26 | 27 | # tex it 28 | pdflatex $tex 29 | mv -i $tex $owd 30 | mv -i $tex:r.pdf $owd 31 | 32 | # go back 33 | cd $owd 34 | 35 | # look at result 36 | open $pdf 37 | -------------------------------------------------------------------------------- /aux/belmont.asc: -------------------------------------------------------------------------------- 1 | Belmont: 2 | 6.4.1 Respect for Persons (Deontologist) 3 | 6.4.2 beneficence (Consequentialist) 4 | 6.4.3 Justice 5 | 6 | elaborate: 7 | 8 | (from https://en.wikipedia.org/wiki/Menlo_Report ) 9 | 10 | 1 Respect for Persons: 11 | - informed consent; 12 | - respect for individuals' auntonomy; 13 | - respect individuals impacted; 14 | - protection for individuals with diminished autonomy or decision making capability. 15 | 16 | 2 Beneficence: 17 | - Do not harm; 18 | - assess risk. 19 | 20 | 3 Justice: 21 | - equal consideration; 22 | - fair distribution of benefits of research; 23 | - fair selection of subjects; 24 | - equitable allocation of burdens. 25 | 26 | -------------------------------------------------------------------------------- /tcsh/ttg: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% wraps around google, turns + into quotes 3 | #% turns spaces into URL spaces (%22) 4 | 5 | set str=`echo $* | sed -e 's/+/%22/g' | sed -e 's/ /+/g' ` 6 | echo $str 7 | lynx --dump 'http://encrypted.google.com/search?hl=en&lr=&safe=off&c2coff=1&q='$str'&btnG=Search' 8 | 9 | 10 | # examples 11 | # https://encrypted.google.com/#sclient=psy-ab&hl=en&source=hp&q=foo+bar+%22a+phrase%22&pbx=1&oq=foo+bar+%22a+phrase%22&aq=f&aqi=&aql=&gs_sm=e&gs_upl=2860l5461l2l5610l10l10l0l0l0l0l219l944l7.2.1l10l0&bav=on.2,or.r_gc.r_pw.,cf.osb&fp=87d046bd4f62ca5c&biw=1342&bih=638 12 | # https://encrypted.google.com/search?hl=en&lr=&safe=off&c2coff=1&q=bar+foo+%22phrase+a%22&btnG=Search 13 | -------------------------------------------------------------------------------- /sh/fix: -------------------------------------------------------------------------------- 1 | # i suggest that before you fix you sometimes asciify, i.e., 2 | # /usr/bin/perl -pe 's/[^[:ascii:]]/+/g' \ 3 | # 4 | # NB: smoetimes when i indent at beginning, i mean it. so i deleted these 5 | #-e 's/^[ ]*//' \ 6 | #-e 's/^[ ]*,[ ]*//' \ 7 | # -e 's/^[> ]*//' \ 8 | 9 | expand \ 10 | | tr '\r' '\n' \ 11 | | sed \ 12 | -e 's/^>[ ]*//' \ 13 | -e 's/[ ]*$//' \ 14 | -e 's/ [ ]*/ /g' \ 15 | -e 's/ =$//' \ 16 | -e 's/=$/-/' \ 17 | -e 's/[ ]*=20$//'\ 18 | -e 's/=91/'"'"'/g' \ 19 | -e 's/=92/`/g' \ 20 | -e 's/=96/-/g' \ 21 | -e 's/,[,]*$/,/g' \ 22 | -e 's/^[,]*//g' 23 | 24 | # cf http://www.w3schools.com/TAGS/ref_urlencode.asp 25 | -------------------------------------------------------------------------------- /aux/md2pptx/example.md: -------------------------------------------------------------------------------- 1 | % Title of the Presentation 2 | % Author Name 3 | % Presentation Date 4 | 5 | # Section 1: Introduction 6 | 7 | ## Slide 1 Title 8 | 9 | - Point 1 10 | - Point 2 11 | - Point 3 12 | 13 | ## Slide 2 Title 14 | 15 | This is a paragraph in Slide 2. 16 | 17 | *Italic text*, **Bold text** 18 | 19 | # Section 2: Main Content 20 | 21 | ## Slide 1 in Main Content 22 | 23 | Here is some text. 24 | 25 | - Bullet list item 1 26 | - Bullet list item 2 27 | 28 | ## Slide 2 in Main Content 29 | 30 | > This is a blockquote. 31 | 32 | # Section 3: Conclusion 33 | 34 | ## Slide 1 in Conclusion 35 | 36 | Conclusion text here. 37 | 38 | ![Image Description](image_url.jpg) 39 | 40 | ## Slide 2 in Conclusion 41 | 42 | Final thoughts or summary. 43 | -------------------------------------------------------------------------------- /bash/chrome-profile-open: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Usage: chrome-profile-open [profile_number] [url] 4 | # Opens Chrome with specified profile (0 or empty = Default, N = Profile N) 5 | 6 | # Parse arguments 7 | PROFILE_NUM="${1:-0}" 8 | URL="${2:-about:blank}" 9 | 10 | # Determine profile directory 11 | if [[ "$PROFILE_NUM" == "0" ]] || [[ -z "$PROFILE_NUM" ]]; then 12 | PROFILE_DIRECTORY="Default" 13 | else 14 | PROFILE_DIRECTORY="Profile ${PROFILE_NUM}" 15 | fi 16 | 17 | # Setup logging 18 | LOG_DIR="/tmp/chrome-log" 19 | mkdir -p "$LOG_DIR" 20 | 21 | # Launch Chrome in background 22 | exec /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \ 23 | --profile-directory="$PROFILE_DIRECTORY" \ 24 | "$URL" \ 25 | 2>"${LOG_DIR}/$$" & 26 | 27 | -------------------------------------------------------------------------------- /sh/flickr: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% turns + into quotes 3 | #% turns spaces into URL spaces (%22) 4 | 5 | set str=`echo $* | sed -e 's/+/%22/g' | sed -e 's/ /%20/g' ` 6 | echo $str 7 | #WAS 8 | #open 'http://flickr.com/search/?q='$str'&w=all' 9 | #open 'http://www.flickr.com/search/show/?q='$str 10 | 11 | #is (restricts to photo only, no video) 12 | #open -a /Applications/Google\ Chrome.app/ --args --kiosk 'http://www.flickr.com/search/show/?q='$str'&ss=0&ct=0&mt=photos&adv=1' 13 | open 'http://www.flickr.com/search/show/?q='$str'&ss=0&ct=0&mt=photos&adv=1' 14 | 15 | 16 | # example: http://www.google.com/search?hl=en&lr=&safe=off&c2coff=1&q=%22albert+einstein%22+site%3Acolumbia.edu&btnG=Search 17 | # http://www.flickr.com/search/show/?q=killer+whale&ss=0&ct=0&mt=videos&adv=1 18 | # 19 | # see also: vlickr 20 | -------------------------------------------------------------------------------- /tcsh/gsearch: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% wraps around google, turns + into quotes 3 | #% turns spaces into URL spaces (%22) 4 | 5 | set str=`echo $* | sed -e 's/+/%22/g' | sed -e 's/ /+/g' | sed -e 's/\#/%23/g' ` 6 | echo $str 7 | # open -a safari 'http://encrypted.google.com/search?hl=en&lr=&safe=off&c2coff=1&q='$str'&btnG=Search' 8 | open 'http://encrypted.google.com/search?hl=en&lr=&safe=off&c2coff=1&q='$str'&btnG=Search' 9 | 10 | 11 | # examples 12 | # https://encrypted.google.com/#sclient=psy-ab&hl=en&source=hp&q=foo+bar+%22a+phrase%22&pbx=1&oq=foo+bar+%22a+phrase%22&aq=f&aqi=&aql=&gs_sm=e&gs_upl=2860l5461l2l5610l10l10l0l0l0l0l219l944l7.2.1l10l0&bav=on.2,or.r_gc.r_pw.,cf.osb&fp=87d046bd4f62ca5c&biw=1342&bih=638 13 | # https://encrypted.google.com/search?hl=en&lr=&safe=off&c2coff=1&q=bar+foo+%22phrase+a%22&btnG=Search 14 | -------------------------------------------------------------------------------- /tcsh/gdocs: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X #-V 2 | 3 | #% open your browser in a search 4 | #% eliminates spaces 5 | #% turns / (for dates) into url-formatted / 6 | # 7 | # ex https://docs.google.com/#search/projects 8 | # ex https://drive.google.com/drive/u/0/search?q=Charlotte 9 | # 20180412T06h38PDT https://drive.google.com/drive/u/0/search?q=word%20%22a%20phrase%22 10 | 11 | set str=`echo $* | sed -e 's/\ /+/g' -e 's/\//%2F/g'` 12 | # echo $str 13 | # 14 | # changed 2014-12-19 15 | # open 'https://drive.google.com/?authuser=0#search/'$str 16 | # 17 | # made gdocs from docs by this line 2019-05-13T04h55 18 | #open -a /Applications/Google\ Chrome.app 'https://drive.google.com/drive/u/0/#search?q='$str 19 | # changed to firefox 2020-11-24 20 | #open -a firefox 'https://drive.google.com/drive/u/0/#search?q='$str 21 | # changed to safari 20201214 22 | open -a safari 'https://drive.google.com/drive/u/0/#search?q='$str 23 | -------------------------------------------------------------------------------- /dotfiles/.vimrc-noline: -------------------------------------------------------------------------------- 1 | " Switch syntax highlighting on, when the terminal has colors 2 | " Also switch on highlighting the last used search pattern. 3 | if &t_Co > 2 || has("gui_running") 4 | syntax on 5 | set hlsearch 6 | endif 7 | " causes problems on pasting: 8 | " set smartindent 9 | set tabstop=2 10 | " for '>', e.g., set shiftwidth=4 11 | set shiftwidth=2 12 | " causes problems with makefiles: 13 | set expandtab 14 | filetype plugin on 15 | ":let b:col=substitute(b:col, ',', ';', 'g') 16 | "use docx2txt.pl to allow VIm to view the text content of a .docx file directly. 17 | autocmd BufReadPre *.docx set ro 18 | autocmd BufReadPost *.docx %!docx2txt.pl 19 | 20 | " show line #s 21 | " set number 22 | 23 | " from https://github.com/tpope/vim-markdown 24 | autocmd BufNewFile,BufReadPost *.md set filetype=markdown 25 | let g:markdown_fenced_languages = ['html', 'python', 'bash=sh'] 26 | 27 | 28 | " cwstuff 29 | set ic 30 | -------------------------------------------------------------------------------- /tcsh/goog2eml: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | # 3 | # gmail recently changed the UX around 4 | # "download original" 5 | # now defining the file as original msg.txt 6 | # with a space 7 | # which is annoying 8 | # so you end up with a bunch of files called 9 | # original\ msg\ \({n}\).txt 10 | # in osx 11 | # 12 | # ugh 13 | # 14 | # so this script calls unspace-mvs then 15 | # renames after the date in the email 16 | # 17 | # update 2019-07-01 18 | # goog changed file name convention and 19 | # also i wanna do this for other uses 20 | # so i'm changing it to take filename as input 21 | # rather than assuming a buncha files named `original_msg*.txt` 22 | 23 | # cw defined: 24 | unspace-mvs 25 | #foreach efile ( original_msg*.txt ) 26 | foreach efile ( $* ) 27 | echo $efile 28 | mv -i $efile `grep '^Date:' $efile | tr ',\r' ' ' | sed -e 's/Date: //' -e 's/[0-9,_ -]*$//' | head -1 | sed -e 's/ [ ]*/_/g'`.eml 29 | end 30 | -------------------------------------------------------------------------------- /py/prose: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import sys 4 | import re 5 | 6 | def main(): 7 | # Read input from stdin 8 | input_text = sys.stdin.read() 9 | 10 | # Define a dictionary mapping delimiters to replacement strings 11 | replacements = { 12 | r'(?<=[.?!])\s+(?!\n)': '\n', # Replace with newline for .?! delimiters 13 | r'(?<=[,;—])\s+(?!\n)': '\n\t', # Replace with newline and tab for ,;— delimiters 14 | r'(?[] 11 | # 12 | # FAIL: set str=`echo \'$*\' | sed -e 's/\ /+/g' -e 's/\:/%3a/g' -e 's/{/%5B/g' -e 's/}/%5D/g'` 13 | # 14 | # this url barfed 02/14/12 15 | # set cmd="open -a ~/bin/chrome http://mail.google.com/mail/#search/"$str 16 | # new url: 17 | # 18 | # old url barfed 10/10/12 19 | # old string: 20 | # set cmd="open -a ~/bin/chrome http://mail.google.com/mail/u/0/#search/"$str 21 | # 22 | # new url: 23 | # https://mail.google.com/mail/u/0/#search/from%3Ahsomeone%40columbia.edu 24 | 25 | set str=`echo $* | sed -e 's/\ /+/g' -e 's/\:/%3a/g' -e 's/\//%2F/g' -e 's/@/%40/g'` 26 | set url="http://mail.google.com/mail/u/0/#search/"$str 27 | source ~/.login > /dev/null 28 | pers-gmail-browser $url 29 | -------------------------------------------------------------------------------- /tcsh/unspace-mvs: -------------------------------------------------------------------------------- 1 | #/bin/tcsh -f -X -V 2 | 3 | 4 | # old and busted 5 | ## ls -1 | grep ' ' | sed -e 's/ /_/g' | sed -f ~//mise//sed/normalize >! /tmp/new_$$ 6 | ## ls -1 | grep ' ' | sed -f ~//mise//sed/normalize >! /tmp/old_$$ 7 | # new hotness (include files in all subfolders and the folders themselves) 8 | # 20201030 change to undo recursive 9 | # find . | grep -e ' ' -e ',' -e '-' -e '_' | sed -f ~//mise//sed/normalize >! /tmp/old_$$ 10 | ls -1 | grep -e '&' -e ' ' -e ',' -e '-' -e '_' | sed -f ~//mise//sed/normalize >! /tmp/old_$$ 11 | # 20200723 changing becuase 20200722 i ran on ~ and killed files named '-' 12 | # cat /tmp/old_$$ | sed -e 's/[, _-][, _-]*/_/g' -e 's/'"'"'/_/g' | tr '()' '-' >! /tmp/new_$$ 13 | cat /tmp/old_$$ | sed -e 's/-/_/g' -e 's/[, _][, _]*/_/g' -e 's/'"'"'/_/g' | tr '()&' '-' >! /tmp/new_$$ 14 | # 20211222 replacing home with ~ 15 | 16 | 17 | # paste /tmp/old_$$ /tmp/new_$$ | awk '{print "mv -i "$0}' >! /tmp/mvs.sh 18 | paste /tmp/old_$$ /tmp/new_$$ | awk '{print "mv -f "$0}' >! /tmp/mvs.sh 19 | source /tmp/mvs.sh 20 | -------------------------------------------------------------------------------- /aux/yeats.txt: -------------------------------------------------------------------------------- 1 | Turning and turning in the widening gyre 2 | The falcon cannot hear the falconer; 3 | Things fall apart; the centre cannot hold; 4 | Mere anarchy is loosed upon the world, 5 | The blood-dimmed tide is loosed, and everywhere 6 | The ceremony of innocence is drowned; 7 | The best lack all conviction, while the worst 8 | Are full of passionate intensity. 9 | 10 | Surely some revelation is at hand; 11 | Surely the Second Coming is at hand. 12 | The Second Coming! Hardly are those words out 13 | When a vast image out of Spiritus Mundi 14 | Troubles my sight: somewhere in sands of the desert 15 | A shape with lion body and the head of a man, 16 | A gaze blank and pitiless as the sun, 17 | Is moving its slow thighs, while all about it 18 | Reel shadows of the indignant desert birds. 19 | The darkness drops again; but now I know 20 | That twenty centuries of stony sleep 21 | Were vexed to nightmare by a rocking cradle, 22 | And what rough beast, its hour come round at last, 23 | Slouches towards Bethlehem to be born? 24 | -------------------------------------------------------------------------------- /bash/rename: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check for -f argument to determine forceful move 4 | FORCE=false 5 | if [[ "$1" == "-f" ]]; then 6 | FORCE=true 7 | shift # Remove the argument so it's not passed to the rename function 8 | fi 9 | 10 | # Define a function to safely rename files 11 | safe_rename() { 12 | local old_name="$1" 13 | local new_name="$(echo "$old_name" | perl -pe 's/[& ,_-]+/_/g; s/[()&]/-/g; s/'"'"'/_/g')" 14 | if [[ "$old_name" != "$new_name" ]]; then 15 | if [[ "$FORCE" == true ]]; then 16 | echo "Forcibly renaming '$old_name' to '$new_name'" 17 | mv -f -- "$old_name" "$new_name" 18 | else 19 | echo "Interactively renaming '$old_name' to '$new_name'" 20 | mv -i -- "$old_name" "$new_name" 21 | fi 22 | fi 23 | } 24 | 25 | # Export the function so it's available to subshells 26 | export -f safe_rename 27 | 28 | # Find all files and directories, excluding the top directory 29 | find . -mindepth 1 -depth | while IFS= read -r file; do 30 | safe_rename "$file" 31 | done 32 | -------------------------------------------------------------------------------- /bash/sniff: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # WiFi network scanner - replacement for deprecated 'airport -s' 3 | # Enumerates available WiFi networks sorted by signal strength 4 | 5 | system_profiler SPAirPortDataType 2>/dev/null | \ 6 | awk ' 7 | BEGIN { 8 | printf "%-40s %10s\n", "SSID", "RSSI" 9 | print "--------------------------------------------------------------------------------" 10 | } 11 | /Other Local Wi-Fi Networks:/ { in_other=1; next } 12 | in_other && /^[[:space:]]*$/ { next } 13 | in_other && /:$/ { 14 | gsub(/^[[:space:]]+/, "") 15 | gsub(/:$/, "") 16 | ssid=$0 17 | getline 18 | while ($0 ~ /^[[:space:]]/ && $0 !~ /:$/) { 19 | if ($0 ~ /Signal \/ Noise:/) { 20 | split($0, parts, ":") 21 | signal = parts[2] 22 | gsub(/^[[:space:]]+/, "", signal) 23 | split(signal, sig_parts, "/") 24 | sig = sig_parts[1] 25 | gsub(/[[:space:]].*$/, "", sig) 26 | print ssid "\t" sig 27 | break 28 | } 29 | getline 30 | } 31 | } 32 | ' | sort -t$'\t' -k2 -rn | \ 33 | while IFS=$'\t' read -r ssid signal; do 34 | printf "%-40s %4s dBm\n" "$ssid" "$signal" 35 | done 36 | -------------------------------------------------------------------------------- /bash/git-clean: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to prompt for user confirmation 4 | confirm() { 5 | read -r -p "$1 (y/n): " response 6 | case "$response" in 7 | [yY][eE][sS]|[yY]) 8 | true 9 | ;; 10 | *) 11 | false 12 | ;; 13 | esac 14 | } 15 | 16 | # Prune remote tracking branches 17 | if confirm "Prune remote tracking branches"; then 18 | echo "Executing: git remote prune origin" 19 | git remote prune origin 20 | fi 21 | 22 | # Remove unused objects 23 | if confirm "Remove unused objects"; then 24 | echo "Executing: git gc --prune=now" 25 | git gc --prune=now 26 | fi 27 | 28 | # Clear reflog 29 | if confirm "Clear reflog"; then 30 | echo "Executing: git reflog expire --expire=now --all" 31 | git reflog expire --expire=now --all 32 | fi 33 | 34 | # Perform garbage collection 35 | if confirm "Perform garbage collection"; then 36 | echo "Executing: git gc --aggressive --prune=now" 37 | git gc --aggressive --prune=now 38 | fi 39 | 40 | # Remove unnecessary local branches 41 | if confirm "Remove unnecessary local branches"; then 42 | echo -n "Enter the branch name to delete: " 43 | read -r branch_name 44 | echo "Executing: git branch -d $branch_name" 45 | git branch -d "$branch_name" 46 | fi 47 | -------------------------------------------------------------------------------- /doc/learning.txt: -------------------------------------------------------------------------------- 1 | A student asked how much of the code and readings are we expected to be internalizing, pointing out that some things we did esp. towards the end, are hard to grasp. For all complex reading, including code & notebooks, I recommend that you follow these steps: 2 | 3 | - Initialization: read the whole piece and skip without pausing over any Thing that is in the least bit confusing. Remember to stay calm and stay positive. You will be able to learn it and it is absolutely fine that it does not all make sense on the first reading. 4 | 5 | - Expansion: go back and mark or enumerate each confusing Thing 6 | 7 | - Contraction: Find a resource that works for your learning style and environment (e.g., sending a Slack message to professor or graders; asking your favorite LLM to ELI5, etc.); consult that resource for each confusing Thing. You might need different resources for different Things, and also you may realize with experimentation that different resources are the most useful for you for different Things, different subjects, or different points in your development (also as the tools and environment changes in time) 8 | 9 | - Iteration: iterate Expansion and Contraction until you understand the whole reading, with no confusing Things left 10 | -------------------------------------------------------------------------------- /py/xlsx2xls: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import openpyxl 3 | import xlwt 4 | import sys 5 | 6 | 7 | def convert_xlsx_to_xls(input_file, output_file): 8 | try: 9 | # Load the .xlsx file 10 | workbook = openpyxl.load_workbook(input_file) 11 | sheet = workbook.active 12 | 13 | # Create a new .xls workbook 14 | new_workbook = xlwt.Workbook() 15 | new_sheet = new_workbook.add_sheet(sheet.title) 16 | 17 | # Copy data from .xlsx to .xls 18 | for row_index, row in enumerate(sheet.iter_rows(values_only=True)): 19 | for col_index, cell in enumerate(row): 20 | new_sheet.write(row_index, col_index, cell) 21 | 22 | # Save the new .xls file 23 | new_workbook.save(output_file) 24 | print(f"File converted and saved as {output_file}") 25 | except Exception as e: 26 | print(f"An error occurred: {e}") 27 | 28 | 29 | if __name__ == "__main__": 30 | if len(sys.argv) != 3: 31 | print( 32 | "Usage: python convert_xlsx_to_xls.py " 33 | ) 34 | else: 35 | input_file = sys.argv[1] 36 | output_file = sys.argv[2] 37 | convert_xlsx_to_xls(input_file, output_file) 38 | -------------------------------------------------------------------------------- /sh/r-install: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | 3 | # usage: r-install foo 4 | 5 | #R -e 'install.packages("'$1'", dependencies = c("Depends", "Suggests"),repos="http://cran.us.r-project.org")' 6 | which R 7 | whereis R 8 | echo "so.... is it /usr/local/bin/R ?" 9 | echo "so.... is it /opt/homebrew/bin/R ?" 10 | 11 | R --version 12 | R -e 'install.packages("'$1'", verbose=TRUE, dependencies = TRUE, repos="http://cran.us.r-project.org")' 13 | 14 | # dependencies 15 | # logical indicating to also install uninstalled packages which these packages depend on/link to/import/suggest (and so on recursively). Not used if repos = NULL. Can also be a character vector, a subset of c("Depends", "Imports", "LinkingTo", "Suggests", "Enhances"). 16 | # 17 | # Only supported if lib is of length one (or missing), so it is unambiguous where to install the dependent packages. If this is not the case it is ignored, with a warning. 18 | # 19 | # The default, NA, means c("Depends", "Imports", "LinkingTo"). 20 | # 21 | # TRUE means (as from R 2.15.0) to use c("Depends", "Imports", "LinkingTo", "Suggests") for pkgs and c("Depends", "Imports", "LinkingTo") for added dependencies: this installs all the packages needed to run pkgs, their examples, tests and vignettes (if the package author specified them correctly). 22 | -------------------------------------------------------------------------------- /bash/gmail_search: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Join all command-line arguments into a single string and replace spaces with '+' 4 | 5 | 6 | # Determine the profile directory based on the first argument 7 | if [ $# -eq 0 ]; then 8 | PROFILE_DIRECTORY="Default" 9 | elif [ "$1" -eq 0 ]; then 10 | PROFILE_DIRECTORY="Default" 11 | else 12 | PROFILE_DIRECTORY="Profile $1" 13 | fi 14 | 15 | # shift 1 16 | 17 | args=("$@") 18 | unset args[0] 19 | set -- "${args[@]}" 20 | # Construct the Gmail search phrase using the provided search phrase 21 | # 22 | # The search phrase is URL-encoded by replacing spaces with '+' 23 | # and double quotes with '%22' 24 | # 25 | SEARCH_PHRASE=$(echo "$*" | sed 's/"/%22/g' | sed 's/ /+/g') 26 | 27 | # Construct the Gmail search URL using the provided search phrase 28 | URL="https://mail.google.com/mail/u/0/#search/$SEARCH_PHRASE" 29 | 30 | # Open Chrome with the specified profile and the constructed URL 31 | /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --profile-directory="$PROFILE_DIRECTORY" "$URL" 32 | 33 | # diagnostics: dump all strings 34 | echo "SEARCH_PHRASE: $SEARCH_PHRASE" 35 | echo "URL: $URL" 36 | echo "PROFILE_DIRECTORY: $PROFILE_DIRECTORY" 37 | echo "COMMAND: /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --profile-directory=\"$PROFILE_DIRECTORY\" \"$URL\"" 38 | -------------------------------------------------------------------------------- /py/pdf2asc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | from io import StringIO 3 | from pdfminer.converter import TextConverter 4 | from pdfminer.layout import LAParams 5 | from pdfminer.pdfdocument import PDFDocument 6 | from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter 7 | from pdfminer.pdfpage import PDFPage 8 | from pdfminer.pdfparser import PDFParser 9 | import argparse 10 | 11 | def pdf_to_ascii(pdf_file): 12 | output_string = StringIO() 13 | with open(pdf_file, 'rb') as in_file: 14 | parser = PDFParser(in_file) 15 | doc = PDFDocument(parser) 16 | rsrcmgr = PDFResourceManager() 17 | device = TextConverter(rsrcmgr, output_string, laparams=LAParams()) 18 | interpreter = PDFPageInterpreter(rsrcmgr, device) 19 | for page in PDFPage.create_pages(doc): 20 | interpreter.process_page(page) 21 | return output_string.getvalue() 22 | 23 | def main(): 24 | parser = argparse.ArgumentParser(description='Convert PDF to ASCII') 25 | parser.add_argument('filename', help='PDF file to convert') 26 | args = parser.parse_args() 27 | try: 28 | ascii_text = pdf_to_ascii(args.filename) 29 | print(ascii_text) 30 | except FileNotFoundError: 31 | print(f"Error: File '{args.filename}' not found") 32 | except Exception as e: 33 | print(f"An error occurred: {e}") 34 | 35 | if __name__ == "__main__": 36 | main() 37 | 38 | -------------------------------------------------------------------------------- /py/alpha: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | 4 | # Hard-coded NATO phonetic & digit mapping 5 | MAPPING = { 6 | 'A': 'Alfa', 'B': 'Bravo', 'C': 'Charlie', 'D': 'Delta', 7 | 'E': 'Echo', 'F': 'Foxtrot', 'G': 'Golf', 'H': 'Hotel', 8 | 'I': 'India', 'J': 'Juliett', 'K': 'Kilo', 'L': 'Lima', 9 | 'M': 'Mike', 'N': 'November','O': 'Oscar', 'P': 'Papa', 10 | 'Q': 'Quebec', 'R': 'Romeo', 'S': 'Sierra', 'T': 'Tango', 11 | 'U': 'Uniform', 'V': 'Victor', 'W': 'Whiskey', 'X': 'X-ray', 12 | 'Y': 'Yankee', 'Z': 'Zulu', 13 | '0': 'Zero', '1': 'One', '2': 'Two', '3': 'Three', 14 | '4': 'Four', '5': 'Five', '6': 'Six', '7': 'Seven', 15 | '8': 'Eight', '9': 'Nine' 16 | } 17 | 18 | def main(): 19 | prog = sys.argv[0] 20 | # No arguments: dump the full mapping 21 | if len(sys.argv) == 1: 22 | for key in sorted(MAPPING): 23 | print(f"{key} {MAPPING[key]}") 24 | return 25 | 26 | # One argument: spell each char 27 | if len(sys.argv) == 2: 28 | text = sys.argv[1] 29 | for ch in text: 30 | code = MAPPING.get(ch.upper()) 31 | if code: 32 | print(code) 33 | else: 34 | # not in A–Z or 0–9 35 | print(f"[{ch}]") 36 | return 37 | 38 | # Too many args 39 | print(f"Usage: {prog} [string_of_letters_and_numbers]") 40 | 41 | if __name__ == '__main__': 42 | main() 43 | -------------------------------------------------------------------------------- /sh/oai_no_key: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Instead of using $1 directly in the JSON data, escape the input using jq 4 | # This will handle special characters like single quotes and exclamation marks properly 5 | escaped_input=$(printf '%s' "$1" | jq -Rs '.') 6 | 7 | # Create a temporary file to store the JSON data 8 | json_file="/tmp/oai_json_$$.json" 9 | 10 | # Write the JSON data to the temporary file 11 | cat > "${json_file}" < /tmp/oai_$$.out 39 | cat /tmp/oai_$$.out 40 | 41 | # Save the curl request and output for debugging purposes 42 | mv "${json_file}" /tmp/oai_`date +%s`.in 43 | mv /tmp/oai_$$.out /tmp/oai_`date +%s`.out 44 | -------------------------------------------------------------------------------- /tcsh/clio: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f #-X -V 2 | #% wraps around google, turns + into quotes 3 | #% turns spaces into URL spaces (%22) 4 | 5 | set str=`echo $* | sed -e 's/+/%22/g' | sed -e 's/ /+/g' | sed -e 's/\#/%23/g' ` 6 | echo $str 7 | # open -a safari 'http://encrypted.google.com/search?hl=en&lr=&safe=off&c2coff=1&q='$str'&btnG=Search' 8 | #open 'http://encrypted.google.com/search?hl=en&lr=&safe=off&c2coff=1&q='$str'&btnG=Search' 9 | #chrome-profile-open 1 'https://clio.columbia.edu/quicksearch?q='$str'&commit=Search' 10 | chrome-profile-open 1 'https://clio-columbia-edu.ezproxy.cul.columbia.edu/quicksearch?q='$str'&commit=Search' 11 | # https://clio.columbia.edu/quicksearch?q=word+%22a+phrase%22#gsc.tab=0&gsc.q=word%20%22a%20phrase%22&gsc.page=1 12 | # broke as of 2025-10-11 chrome-profile-open 1 'https://clio.columbia.edu/quicksearch?q='$str' 13 | chrome-profile-open 1 'https://clio.columbia.edu/quicksearch?q='$str'&commit=Search#gsc.tab=0&gsc.q='$str'&gsc.page=1' 14 | 15 | 16 | # examples 17 | # https://encrypted.google.com/#sclient=psy-ab&hl=en&source=hp&q=foo+bar+%22a+phrase%22&pbx=1&oq=foo+bar+%22a+phrase%22&aq=f&aqi=&aql=&gs_sm=e&gs_upl=2860l5461l2l5610l10l10l0l0l0l0l219l944l7.2.1l10l0&bav=on.2,or.r_gc.r_pw.,cf.osb&fp=87d046bd4f62ca5c&biw=1342&bih=638 18 | # https://encrypted.google.com/search?hl=en&lr=&safe=off&c2coff=1&q=bar+foo+%22phrase+a%22&btnG=Search 19 | # https://clio-columbia-edu.ezproxy.cul.columbia.edu/quicksearch?q=experimental+conversations&commit=Search#gsc.tab=0&gsc.q=experimental%20conversations&gsc.page=1 20 | -------------------------------------------------------------------------------- /bash/doi2json: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to display usage 4 | usage() { 5 | echo "Usage: $0 [OPTIONS] " 6 | echo "Options:" 7 | echo " -o Open the article URL in a web browser" 8 | echo " -u Display the article URL" 9 | echo " -t Display the title of the article" 10 | echo "Without any option, the full JSON metadata will be displayed." 11 | exit 1 12 | } 13 | 14 | # Ensure at least one argument is provided 15 | if [ "$#" -lt 1 ]; then 16 | usage 17 | fi 18 | 19 | # The DOI should be the last argument 20 | DOI="${!#}" 21 | URL="https://api.crossref.org/works/$DOI" 22 | DATA=$(curl -s -LH "Accept: application/json" "$URL") 23 | 24 | # If only the DOI is provided, display the full JSON 25 | if [ "$#" -eq 1 ]; then 26 | echo "$DATA" | jq '.' 27 | exit 0 28 | fi 29 | 30 | # Process the options 31 | while getopts ":outa" opt; do 32 | case $opt in 33 | o) 34 | open "$(echo "$DATA" | jq -r '.message.URL')" 35 | ;; 36 | u) 37 | echo "URL: $(echo "$DATA" | jq -r '.message.URL')" 38 | ;; 39 | t) 40 | echo "Title: $(echo "$DATA" | jq -r '.message.title[0]')" 41 | ;; 42 | a) 43 | authors=$(echo "$DATA" | jq -r '.message.author[] | "\(.given) \(.family)"') 44 | echo "Authors:" 45 | echo "$authors" 46 | ;; 47 | \?) 48 | echo "Invalid option: -$OPTARG" >&2 49 | usage 50 | ;; 51 | esac 52 | done 53 | -------------------------------------------------------------------------------- /bash/friends: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # GitHub collaborators via API - FAST! 3 | 4 | # Check if gh CLI is installed 5 | if ! command -v gh &> /dev/null; then 6 | echo "Error: GitHub CLI (gh) is required. Install with: brew install gh" 7 | exit 1 8 | fi 9 | 10 | echo "GitHub Collaborators (from recent repos):" 11 | echo "==========================================" 12 | echo 13 | 14 | # Get list of repos you've contributed to recently 15 | gh api graphql -f query=' 16 | query { 17 | viewer { 18 | repositories(first: 50, orderBy: {field: PUSHED_AT, direction: DESC}) { 19 | nodes { 20 | nameWithOwner 21 | collaborators(first: 20) { 22 | nodes { 23 | login 24 | name 25 | id 26 | } 27 | } 28 | mentionableUsers(first: 20) { 29 | nodes { 30 | login 31 | name 32 | id 33 | } 34 | } 35 | } 36 | } 37 | repositoriesContributedTo(first: 30, orderBy: {field: PUSHED_AT, direction: DESC}) { 38 | nodes { 39 | nameWithOwner 40 | mentionableUsers(first: 20) { 41 | nodes { 42 | login 43 | name 44 | id 45 | } 46 | } 47 | } 48 | } 49 | } 50 | }' --jq ' 51 | [ 52 | .data.viewer.repositories.nodes[].collaborators.nodes[]?, 53 | .data.viewer.repositories.nodes[].mentionableUsers.nodes[]?, 54 | .data.viewer.repositoriesContributedTo.nodes[].mentionableUsers.nodes[]? 55 | ] | 56 | map(select(.login != "'$(gh api user --jq '.login')'")) | 57 | unique_by(.login) | 58 | .[] | 59 | "• \(.name // .login) (@\(.login), ID: \(.id))" 60 | ' -------------------------------------------------------------------------------- /py/xkcd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | """ 4 | from https://twitter.com/NoncanonicAleae/status/1749833072625713567 5 | 6 | it's easy to forget the average person probably doesn't know by name xkcd 2501. they probably only know the really famous ones, like xkcd 356 and xkcd 435. and, of course, xkcd 927. of course. 7 | """ 8 | 9 | import sys 10 | import requests 11 | import webbrowser 12 | 13 | 14 | def get_xkcd_comic(comic_num): 15 | # URL for the xkcd API 16 | url = f"https://xkcd.com/{comic_num}/info.0.json" 17 | 18 | try: 19 | # Send a GET request to the xkcd API 20 | response = requests.get(url) 21 | response.raise_for_status() # Raise an exception if the request was not successful 22 | 23 | # Parse the JSON response 24 | comic_data = response.json() 25 | 26 | # Extract the comic title and image URL 27 | comic_title = comic_data["title"] 28 | comic_img_url = comic_data["img"] 29 | 30 | print(f"Opening xkcd {comic_num}: {comic_title}") 31 | 32 | # Open the comic in a web browser 33 | webbrowser.open(comic_img_url) 34 | except requests.exceptions.RequestException as e: 35 | print(f"Error: {e}") 36 | except KeyError: 37 | print(f"Comic {comic_num} not found") 38 | 39 | 40 | if __name__ == "__main__": 41 | if len(sys.argv) != 2: 42 | print("Usage: ./xkcd.py ") 43 | sys.exit(1) 44 | 45 | try: 46 | # Get the comic number from the command-line argument 47 | comic_number = int(sys.argv[1]) 48 | 49 | # Call the function to retrieve and open the comic 50 | get_xkcd_comic(comic_number) 51 | except ValueError: 52 | print("Invalid input. Please enter a valid integer comic number.") 53 | -------------------------------------------------------------------------------- /bash/ocr-grey: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Enable verbose output for better understanding of the script flow 4 | # set -x 5 | 6 | # Declare input file and output directory 7 | input_file=$1 8 | output_dir=out 9 | output_file="$output_dir/$(basename "$input_file" .pdf).txt" 10 | 11 | # Check if the input file exists 12 | if [ ! -f "$input_file" ]; then 13 | echo "Input file $input_file not found!" 14 | exit 1 15 | fi 16 | 17 | # Create the output directory if it does not exist 18 | mkdir -p "$output_dir" 19 | 20 | # Use pdf2image to convert the PDF to a set of PNG images 21 | # The resulting images are saved in the output directory 22 | echo "Converting PDF to PNG..." 23 | python3 -c " 24 | from pdf2image import convert_from_path 25 | images = convert_from_path('$input_file') 26 | for i, image in enumerate(images): 27 | image.save('$output_dir/page_'+ str(i) +'.png', 'PNG') 28 | " 29 | 30 | # Use ImageMagick to convert the PNG images to grayscale 31 | # This can help with removing any highlights in the original PDF 32 | echo "Converting images to grayscale..." 33 | for file in $output_dir/*.png; do 34 | convert "$file" -colorspace GRAY "$file" 35 | done 36 | 37 | # Use Tesseract to perform OCR on the PNG images 38 | # The resulting text is saved in the output directory 39 | echo "Performing OCR with Tesseract..." 40 | for file in $output_dir/*.png; do 41 | tesseract "$file" "$output_dir/$(basename "$file" .png).txt" -l eng --oem 1 42 | done 43 | 44 | # Concatenate all the individual text files into a single file 45 | # This is the final output of the script 46 | echo "Concatenating text files..." 47 | cat $output_dir/*.txt > "$output_file" 48 | 49 | # Output the path to the OCR text file 50 | echo "OCR complete! Text file can be found at $output_file" 51 | 52 | # Disable verbose output 53 | # set +x 54 | -------------------------------------------------------------------------------- /bash/gh-add: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Add a GitHub user as collaborator to a repository 3 | # Usage: gh-add [person] [repo] 4 | 5 | if [[ $# -ne 2 ]]; then 6 | echo "Usage: gh-add [person] [repo]" 7 | echo "" 8 | echo "Available people from gfile.asc:" 9 | if [[ -f ~/gd/local/prj/comms/gfile.asc ]]; then 10 | while IFS=';' read -r username userid repos; do 11 | if [[ -n "$username" && "$username" != *"@"* ]]; then 12 | echo " $username" 13 | fi 14 | done < ~/gd/local/prj/comms/gfile.asc 15 | fi 16 | echo "" 17 | echo "Recent repositories (use 'repos' command for full list):" 18 | ~/gd/local/prj/comms/repos 2>/dev/null | head -5 19 | exit 1 20 | fi 21 | 22 | person="$1" 23 | repo="$2" 24 | 25 | # Check if person exists in gfile.asc 26 | if [[ -f ~/gd/local/prj/comms/gfile.asc ]]; then 27 | found=$(grep "^$person;" ~/gd/local/prj/comms/gfile.asc) 28 | if [[ -z "$found" ]]; then 29 | echo "Person '$person' not found in gfile.asc" 30 | echo "Available people:" 31 | while IFS=';' read -r username userid repos; do 32 | if [[ -n "$username" && "$username" != *"@"* ]]; then 33 | echo " $username" 34 | fi 35 | done < ~/gd/local/prj/comms/gfile.asc 36 | exit 1 37 | fi 38 | fi 39 | 40 | # Add collaborator using gh CLI 41 | echo "Adding $person as collaborator to $repo..." 42 | gh api repos/"$repo"/collaborators/"$person" --method PUT --field permission=push 43 | 44 | if [[ $? -eq 0 ]]; then 45 | echo "Successfully added $person to $repo as collaborator" 46 | else 47 | echo "Failed to add $person to $repo" 48 | echo "Make sure:" 49 | echo " - You have admin access to the repository" 50 | echo " - The repository name is correct (format: owner/repo)" 51 | echo " - You're authenticated with gh CLI (run 'gh auth login')" 52 | fi -------------------------------------------------------------------------------- /py/xlsx2tsv: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import pandas as pd 4 | import sys 5 | 6 | 7 | def xlsx_to_tsv(excel_file, sheet=None): 8 | # Read the Excel file 9 | xls = pd.ExcelFile(excel_file) 10 | 11 | # List all sheet names 12 | sheet_names = xls.sheet_names 13 | 14 | # Determine the sheet to convert 15 | if sheet is not None: 16 | # Validate the provided sheet number 17 | if sheet > len(sheet_names) or sheet < 1: 18 | print( 19 | f"Invalid sheet number. Please choose a number between 1 and {len(sheet_names)}." 20 | ) 21 | return 22 | selected_sheet = sheet_names[sheet - 1] 23 | elif len(sheet_names) == 1: 24 | # Automatically select the only sheet 25 | selected_sheet = sheet_names[0] 26 | else: 27 | # Prompt the user to select a sheet 28 | for i, name in enumerate(sheet_names, start=1): 29 | print(f"{i}. {name}") 30 | choice = int(input("Choose a sheet number: ")) 31 | if choice > len(sheet_names) or choice < 1: 32 | print( 33 | f"Invalid choice. Please choose a number between 1 and {len(sheet_names)}." 34 | ) 35 | return 36 | selected_sheet = sheet_names[choice - 1] 37 | 38 | # Read the selected sheet 39 | df = pd.read_excel(excel_file, sheet_name=selected_sheet) 40 | 41 | # Convert to TSV and save 42 | tsv_file = excel_file.replace(".xlsx", f"_{selected_sheet}.tsv") 43 | df.to_csv(tsv_file, sep="\t", index=False) 44 | print(f"TSV file created: {tsv_file}") 45 | 46 | 47 | if __name__ == "__main__": 48 | if len(sys.argv) < 2: 49 | print("Usage: python script.py excel_file.xlsx [sheet_number]") 50 | else: 51 | excel_file = sys.argv[1] 52 | sheet_number = int(sys.argv[2]) if len(sys.argv) > 2 else None 53 | xlsx_to_tsv(excel_file, sheet=sheet_number) 54 | -------------------------------------------------------------------------------- /bash/ide: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Set the shebang to use bash shell 4 | 5 | # Assign command-line arguments to variables with default values 6 | command=${1:-cat} # The command to be run, default is 'cat' 7 | input_file=${2:-ein.txt} # The input file for the command, default is 'ein.txt' 8 | output_file=${3:-aus.txt} # The output file for the command, default is 'aus.txt' 9 | wait_time=${4:-4} # The wait time between iterations, default is 4 seconds 10 | 11 | # Print usage and exit if no arguments were passed 12 | if [ $# -eq 0 ]; then 13 | echo "Usage: $0 [command=$command] [input_file=$input_file] [output_file=$output_file] [wait_time=$wait_time]" 14 | exit 1 15 | fi 16 | 17 | # Check if input file exists. If it doesn't, create it and exit 18 | if [ ! -f "$input_file" ]; then 19 | echo "Input file not found. Creating file and exiting." 20 | touch "$input_file" # 'touch' is used to create the file 21 | exit 0 22 | fi 23 | 24 | # Check if output file exists. If it doesn't, create it 25 | if [ ! -f "$output_file" ]; then 26 | echo "Output file not found. Creating file." 27 | touch "$output_file" # 'touch' is used to create the file 28 | fi 29 | 30 | # Run the command once before entering the loop 31 | $command < "$input_file" > "$output_file" # Input redirection '<' and output redirection '>' 32 | 33 | # Start of the infinite loop 34 | while true 35 | do 36 | # Check if the input file is newer than the output file 37 | if [ "$input_file" -nt "$output_file" ] 38 | then 39 | # Clear screen if the input file is newer 40 | clear 41 | 42 | # Run the command with input file as input and output file as output 43 | $command < "$input_file" > "$output_file" # The same command is run again 44 | 45 | # Output the contents of the output file to the terminal 46 | cat "$output_file" 47 | fi 48 | 49 | # Wait for the specified amount of time before the next iteration 50 | sleep $wait_time 51 | done 52 | # End of the script 53 | -------------------------------------------------------------------------------- /py/tune: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """Guitar tuner - plays standard tuning reference tones.""" 3 | 4 | import subprocess 5 | import sys 6 | 7 | # Standard tuning frequencies (Hz) - one octave up 8 | TUNING = [ 9 | ("E3", 164.81), 10 | ("A3", 220.00), 11 | ("D4", 293.66), 12 | ("G4", 392.00), 13 | ("B4", 493.88), 14 | ("E5", 659.26), 15 | ] 16 | 17 | def play_tone(freq, duration=3): 18 | """Play a tone using sox (install with: brew install sox).""" 19 | try: 20 | subprocess.run( 21 | ["play", "-n", "synth", str(duration), "sine", str(freq)], 22 | stdout=subprocess.DEVNULL, 23 | stderr=subprocess.DEVNULL, 24 | ) 25 | except FileNotFoundError: 26 | print("Error: 'sox' not installed. Run: brew install sox") 27 | sys.exit(1) 28 | 29 | def main(): 30 | # If no arguments, just play all strings once and exit 31 | if len(sys.argv) == 1: 32 | for note, freq in reversed(TUNING): 33 | print(f"{note}...") 34 | play_tone(freq, 1) 35 | return 36 | 37 | print("Guitar Tuner - Standard Tuning (EADGBE)") 38 | print("-" * 40) 39 | 40 | for i, (note, freq) in enumerate(TUNING, 1): 41 | print(f"String {7-i}: {note} ({freq:.2f} Hz)") 42 | 43 | print("\nPress Enter to play each string, 'q' to quit, or 'a' for all.") 44 | 45 | while True: 46 | choice = input("\nString (1-6), 'a' for all, 'q' to quit: ").strip().lower() 47 | 48 | if choice == 'q': 49 | break 50 | elif choice == 'a': 51 | for note, freq in reversed(TUNING): 52 | print(f"Playing {note}...") 53 | play_tone(freq, 2) 54 | elif choice in "123456" and len(choice) == 1: 55 | idx = 6 - int(choice) 56 | note, freq = TUNING[idx] 57 | print(f"Playing {note}...") 58 | play_tone(freq, 3) 59 | else: 60 | print("Invalid input.") 61 | 62 | if __name__ == "__main__": 63 | main() 64 | -------------------------------------------------------------------------------- /py/airport_codes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Dictionary of common airport codes 4 | airport_codes = { 5 | 'sfo': 'San Francisco International Airport', 6 | 'ewr': 'Newark Liberty International Airport', 7 | 'agp': 'Málaga-Costa del Sol Airport', 8 | 'vie': 'Vienna International Airport', 9 | 'ist': 'Istanbul Airport', 10 | 'auh': 'Abu Dhabi International Airport', 11 | 'cnx': 'Chiang Mai International Airport', 12 | 'hkt': 'Phuket International Airport', 13 | 'bkk': 'Suvarnabhumi Airport (Bangkok)', 14 | 'lax': 'Los Angeles International Airport', 15 | 'jfk': 'John F. Kennedy International Airport', 16 | 'lhr': 'London Heathrow Airport', 17 | 'cdg': 'Charles de Gaulle Airport (Paris)', 18 | 'nrt': 'Narita International Airport (Tokyo)', 19 | 'dxb': 'Dubai International Airport', 20 | 'sin': 'Singapore Changi Airport', 21 | 'hkg': 'Hong Kong International Airport', 22 | 'ams': 'Amsterdam Airport Schiphol', 23 | 'fra': 'Frankfurt Airport', 24 | 'muc': 'Munich Airport', 25 | } 26 | 27 | def unlock_airport_codes(route_string): 28 | """Convert airport codes in a route string to full names.""" 29 | # Split by arrow and strip whitespace 30 | codes = [code.strip() for code in route_string.split('->')] 31 | 32 | # Convert each code to full name 33 | full_names = [] 34 | for code in codes: 35 | code_lower = code.lower() 36 | if code_lower in airport_codes: 37 | full_names.append(f"{code.upper()} ({airport_codes[code_lower]})") 38 | else: 39 | full_names.append(f"{code.upper()} (Unknown Airport)") 40 | 41 | return full_names 42 | 43 | # Test with the provided string 44 | route = "sfo -> ewr -> ist -> lax" 45 | print("Original route:") 46 | print(route) 47 | print("\nExpanded route:") 48 | expanded = unlock_airport_codes(route) 49 | for i, airport in enumerate(expanded, 1): 50 | print(f"{i:2}. {airport}") 51 | 52 | print("\nFull journey:") 53 | print(" -> ".join([name.split('(')[1].rstrip(')') for name in expanded])) 54 | -------------------------------------------------------------------------------- /bash/alarm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Usage: alarm at