Skip to content

ptb/mac-setup

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

76 Commits
 
 
 
 
 
 

Repository files navigation

Mac Setup

From zero to fully installed and configured, in an hour.

Overview

Quick Start

case "${SHELL}" in
  (*zsh) ;;
  (*) chsh -s "$(which zsh)"; exit 1 ;;
esac
curl --location --silent \
  "https://github.com/ptb/mac-setup/raw/develop/mac-setup.command" | \
  source /dev/stdin 0
init && install && config
custom && personalize_all

init

  • Enter administrator account password only once
  • Select the cache folder for repeat installations
  • Turn off sleep and set computer name/hostname
  • Set write permission on destination folders
  • Cache software updates and App Store software
  • Install developer tools and macOS updates

install

  • Homebrew: The missing package mananger for macOS
  • Homebrew-Cask: “To install, drag this icon…” no more!
  • mas-cli/mas: Mac App Store command line interface
  • homebrew-bundle: List all Homebrew packages in Brewfile
  • Node.js: Cross-platform JavaScript run-time environment
  • Perl 5: Highly capable, feature-rich programming language
  • Python: Programming language that lets you work quickly
  • Ruby: Language with a focus on simplicity and productivity

config

  • Configure software requiring an administrator account
  • Optionally configure local Dovecot secure IMAP server
  • Create your primary non-administrator account
  • Remove password-less administrator account permission
  • Recommended that you log out of administrator account

custom

  • Log in with your new non-administrator account
  • Create or clone a git repository into your home folder
  • Install Atom packages and customize preferences
  • Set the desktop picture to a solid black color
  • Customize the dock with new default applications
  • Customize Emacs with Spacemacs: Emacs plus Vim!
  • Set all preferences automatically and consistently

Features

  • macOS High Sierra: Tested with macOS High Sierra 10.13 (17A365).
  • Completely Automated: Homebrew, Cask, and mas-cli install everything.
  • Latest Versions: Includes Node, Perl, Python, and Ruby separate from macOS.
  • Customized Terminal: Colors and fonts decyphered into editable preferences.
  • Idempotent: This script is intended to be safe to run more than once.

Walkthrough

Clone Internal Hard Disk to External Disk

Select the External Disk as Startup Disk

Download macOS Install from the App Store

macappstores://itunes.apple.com/app/id1209167288

Open /Applications/Utilities/Terminal.app

diskx="$(diskutil list internal physical | sed '/^\//!d;s/^\(.*\)\ (.*):/\1/')"
diskutil zeroDisk $diskx
diskutil partitionDisk $diskx 2 GPT \
  jhfs+ "Install" 6G \
  apfs $(ruby -e "print '$(hostname -s)'.capitalize") R
sudo "/Applications/Install macOS High Sierra.app/Contents/Resources/createinstallmedia" \
  --applicationpath "/Applications/Install macOS High Sierra.app" --nointeraction \
  --volume "/Volumes/Install"

Select the Install Disk as Startup Disk

License

Copyright 2017 Peter T Bosse II

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Initialize

Initialize New Terminal

if test -z "${1}"; then
  osascript - "${0}" << EOF > /dev/null 2>&1
<<new_term.applescript>>
EOF
fi

new_term.applescript

on run { _this }
  tell app "Terminal" to do script "source " & quoted form of _this & " 0"
end run

Define Function ask

ask () {
  osascript - "${1}" "${2}" "${3}" << EOF 2> /dev/null
<<ask.applescript>>
EOF
}

ask.applescript

on run { _title, _action, _default }
  tell app "System Events" to return text returned of (display dialog _title with title _title buttons { "Cancel", _action } default answer _default)
end run

Define Function ask2

ask2 () {
  osascript - "$1" "$2" "$3" "$4" "$5" "$6" << EOF 2> /dev/null
<<ask2.applescript>>
EOF
}

ask2.applescript

on run { _text, _title, _cancel, _action, _default, _hidden }
  tell app "Terminal" to return text returned of (display dialog _text with title _title buttons { _cancel, _action } cancel button _cancel default button _action default answer _default hidden answer _hidden)
end run

Define Function p

p () {
  printf "\n\033[1m\033[34m%s\033[0m\n\n" "${1}"
}

Define Function run

run () {
  osascript - "${1}" "${2}" "${3}" << EOF 2> /dev/null
<<run.applescript>>
EOF
}

run.applescript

on run { _title, _cancel, _action }
  tell app "Terminal" to return button returned of (display dialog _title with title _title buttons { _cancel, _action } cancel button 1 default button 2 giving up after 5)
end run

Define Function init

init () {
  init_sudo
  init_cache
  init_no_sleep
  init_hostname
  init_perms
  init_maskeep
  init_updates

  config_new_account
  config_rm_sudoers
}

if test "${1}" = 0; then
  printf "\n$(which init)\n"
fi

Define Function init_paths

init_paths () {
  test -x "/usr/libexec/path_helper" && \
    eval $(/usr/libexec/path_helper -s)
}

Eliminate Prompts for Password

init_sudo () {
  printf "%s\n" "%wheel ALL=(ALL) NOPASSWD: ALL" | \
  sudo tee "/etc/sudoers.d/wheel" > /dev/null && \
  sudo dscl /Local/Default append /Groups/wheel GroupMembership "$(whoami)"
}

Select Installation Cache Location

init_cache () {
  grep -q "CACHES" "/etc/zshenv" 2> /dev/null || \
  a=$(osascript << EOF 2> /dev/null
<<init_cache.applescript>>
EOF
) && \
  test -d "${a}" || \
    a="${HOME}/Library/Caches/"

  grep -q "CACHES" "/etc/zshenv" 2> /dev/null || \
  printf "%s\n" \
    "export CACHES=\"${a}\"" \
    "export HOMEBREW_CACHE=\"${a}/brew\"" \
    "export BREWFILE=\"${a}/brew/Brewfile\"" | \
  sudo tee -a "/etc/zshenv" > /dev/null
  . "/etc/zshenv"

  if test -d "${CACHES}/upd"; then
    sudo chown -R "$(whoami)" "/Library/Updates"
    rsync -a --delay-updates \
      "${CACHES}/upd/" "/Library/Updates/"
  fi
}

init_cache.applescript

on run
  return text 1 through -2 of POSIX path of (choose folder with prompt "Select Installation Cache Location")
end run

Set Defaults for Sleep

init_no_sleep () {
  sudo pmset -a sleep 0
  sudo pmset -a disksleep 0
}

Set Hostname from DNS

init_hostname () {
  a=$(ask2 "Set Computer Name and Hostname" "Set Hostname" "Cancel" "Set Hostname" $(ruby -e "print '$(hostname -s)'.capitalize") "false")
  if test -n $a; then
    sudo scutil --set ComputerName $(ruby -e "print '$a'.capitalize")
    sudo scutil --set HostName $(ruby -e "print '$a'.downcase")
  fi
}

Set Permissions on Install Destinations

init_perms () {
  printf "%s\n" "${_dest}" | \
  while IFS="$(printf '\t')" read d; do
    test -d "${d}" || sudo mkdir -p "${d}"
    sudo chgrp -R admin "${d}"
    sudo chmod -R g+w "${d}"
  done
}

_dest

LocationInstall Path
/usr/local/bin
/Library/Desktop Pictures
colorpickerdir/Library/ColorPickers
fontdir/Library/Fonts
input_methoddir/Library/Input Methods
prefpanedir/Library/PreferencePanes
qlplugindir/Library/QuickLook
screen_saverdir/Library/Screen Savers
/Library/User Pictures

Install Developer Tools

init_devtools () {
  p="${HOMEBREW_CACHE}/Cask/Command Line Tools (macOS High Sierra version 10.13).pkg"
  i="com.apple.pkg.CLTools_SDK_macOS1013"

  if test -f "${p}"; then
    if ! pkgutil --pkg-info "${i}" > /dev/null 2>&1; then
      sudo installer -pkg "${p}" -target /
    fi
  else
    xcode-select --install
  fi
}

Install Xcode

init_xcode () {
  if test -f ${HOMEBREW_CACHE}/Cask/xcode*.xip; then
    p "Installing Xcode"
    dest="${HOMEBREW_CACHE}/Cask/xcode"
    if ! test -d "$dest"; then
      pkgutil --expand ${HOMEBREW_CACHE}/Cask/xcode*.xip "$dest"
      curl --location --silent \
        "https://gist.githubusercontent.com/pudquick/ff412bcb29c9c1fa4b8d/raw/24b25538ea8df8d0634a2a6189aa581ccc6a5b4b/parse_pbzx2.py" | \
        python - "${dest}/Content"
      find "${dest}" -empty -name "*.xz" -type f -print0 | \
        xargs -0 -l 1 rm
      find "${dest}" -name "*.xz" -print0 | \
        xargs -0 -L 1 gunzip
      cat ${dest}/Content.part* > \
        ${dest}/Content.cpio
    fi
    cd /Applications && \
      sudo cpio -dimu --file=${dest}/Content.cpio
    for pkg in /Applications/Xcode*.app/Contents/Resources/Packages/*.pkg; do
      sudo installer -pkg "$pkg" -target /
    done
    x="$(find '/Applications' -maxdepth 1 -regex '.*/Xcode[^ ]*.app' -print -quit)"
    if test -n "${x}"; then
      sudo xcode-select -s "${x}"
      sudo xcodebuild -license accept
    fi
  fi
}

Install macOS Updates

init_updates () {
  sudo softwareupdate --install --all
}

Save Mac App Store Packages

sudo lsof -c softwareupdated -F -r 2 | sed '/^n\//!d;/com.apple.SoftwareUpdate/!d;s/^n//'
sudo lsof -c storedownloadd -F -r 2 | sed '/^n\//!d;/com.apple.appstore/!d;s/^n//'
init_maskeep () {
  sudo softwareupdate --reset-ignored > /dev/null

  cat << EOF > "/usr/local/bin/maskeep"
<<maskeep.sh>>
EOF

  chmod a+x "/usr/local/bin/maskeep"
  rehash

  config_launchd "/Library/LaunchDaemons/com.github.ptb.maskeep.plist" "$_maskeep_launchd" "sudo" ""
}

_maskeep_launchd

CommandEntryTypeValue
add:KeepAliveboolfalse
add:Labelstringcom.github.ptb.maskeep
add:ProcessTypestringBackground
add:Programstring/usr/local/bin/maskeep
add:RunAtLoadbooltrue
add:StandardErrorPathstring/dev/stderr
add:StandardOutPathstring/dev/stdout
add:UserNamestringroot
add:WatchPathsarray
add:WatchPaths:0string$(sudo find ‘/private/var/folders’ -name ‘com.apple.SoftwareUpdate’ -type d -user _softwareupdate -print -quit 2> /dev/null)
add:WatchPaths:1string$(sudo -u \#501 – sh -c ‘getconf DARWIN_USER_CACHE_DIR’ 2> /dev/null)com.apple.appstore
add:WatchPaths:2string$(sudo -u \#502 – sh -c ‘getconf DARWIN_USER_CACHE_DIR’ 2> /dev/null)com.apple.appstore
add:WatchPaths:3string$(sudo -u \#503 – sh -c ‘getconf DARWIN_USER_CACHE_DIR’ 2> /dev/null)com.apple.appstore
add:WatchPaths:4string/Library/Updates

/usr/local/bin/maskeep

#!/bin/sh

asdir="/Library/Caches/storedownloadd"
as1="\$(sudo -u \\#501 -- sh -c 'getconf DARWIN_USER_CACHE_DIR' 2> /dev/null)com.apple.appstore"
as2="\$(sudo -u \\#502 -- sh -c 'getconf DARWIN_USER_CACHE_DIR' 2> /dev/null)com.apple.appstore"
as3="\$(sudo -u \\#503 -- sh -c 'getconf DARWIN_USER_CACHE_DIR' 2> /dev/null)com.apple.appstore"
upd="/Library/Updates"
sudir="/Library/Caches/softwareupdated"
su="\$(sudo find '/private/var/folders' -name 'com.apple.SoftwareUpdate' -type d -user _softwareupdate 2> /dev/null)"

for i in 1 2 3 4 5; do
  mkdir -m a=rwxt -p "\$asdir"
  for as in "\$as1" "\$as2" "\$as3" "\$upd"; do
    test -d "\$as" && \
    find "\${as}" -type d -print | \\
    while read a; do
      b="\${asdir}/\$(basename \$a)"
      mkdir -p "\${b}"
      find "\${a}" -type f -print | \\
      while read c; do
        d="\$(basename \$c)"
        test -e "\${b}/\${d}" || \\
          ln "\${c}" "\${b}/\${d}" && \\
          chmod 666 "\${b}/\${d}"
      done
    done
  done

  mkdir -m a=rwxt -p "\${sudir}"
  find "\${su}" -name "*.tmp" -type f -print | \\
  while read a; do
    d="\$(basename \$a)"
    test -e "\${sudir}/\${d}.xar" ||
      ln "\${a}" "\${sudir}/\${d}.xar" && \\
      chmod 666 "\${sudir}/\${d}.xar"
  done

  sleep 1
done

exit 0

Install

Define Function install

install () {
  install_macos_sw
  install_node_sw
  install_perl_sw
  install_python_sw
  install_ruby_sw

  which config
}

Install macOS Software with brew

install_macos_sw () {
  p "Installing macOS Software"
  install_paths
  install_brew
  install_brewfile_taps
  install_brewfile_brew_pkgs
  install_brewfile_cask_args
  install_brewfile_cask_pkgs
  install_brewfile_mas_apps

  x=$(find '/Applications' -maxdepth 1 -regex '.*/Xcode[^ ]*.app' -print -quit)
  if test -n "$x"; then
    sudo xcode-select -s "$x"
    sudo xcodebuild -license accept
  fi

  brew bundle --file="${BREWFILE}"

  x=$(find '/Applications' -maxdepth 1 -regex '.*/Xcode[^ ]*.app' -print -quit)
  if test -n "$x"; then
    sudo xcode-select -s "$x"
    sudo xcodebuild -license accept
  fi

  install_links
  sudo xattr -rd "com.apple.quarantine" "/Applications" > /dev/null 2>&1
  sudo chmod -R go=u-w "/Applications" > /dev/null 2>&1
}

Add /usr/local/bin/sbin to Default Path

install_paths () {
  if ! grep -Fq "/usr/local/sbin" /etc/paths; then
    sudo sed -i "" -e "/\/usr\/sbin/{x;s/$/\/usr\/local\/sbin/;G;}" /etc/paths
  fi
}

Install Homebrew Package Manager

install_brew () {
  if ! which brew > /dev/null; then
    ruby -e \
      "$(curl -Ls 'https://github.com/Homebrew/install/raw/master/install')" \
      < /dev/null > /dev/null 2>&1
  fi
  printf "" > "${BREWFILE}"
  brew analytics off
  brew update
  brew doctor
  brew tap "homebrew/bundle"
}

Add Homebrew Taps to Brewfile

install_brewfile_taps () {
  printf "%s\n" "${_taps}" | \
  while IFS="$(printf '\t')" read tap; do
    printf 'tap "%s"\n' "${tap}" >> "${BREWFILE}"
  done
  printf "\n" >> "${BREWFILE}"
}

_taps

Homebrew Tap NameReference URL
caskroom/caskhttps://github.com/caskroom/homebrew-cask
caskroom/fontshttps://github.com/caskroom/homebrew-fonts
caskroom/versionshttps://github.com/caskroom/homebrew-versions
homebrew/bundlehttps://github.com/Homebrew/homebrew-bundle
homebrew/command-not-foundhttps://github.com/Homebrew/homebrew-command-not-found
homebrew/nginxhttps://github.com/Homebrew/homebrew-nginx
homebrew/phphttps://github.com/Homebrew/homebrew-php
homebrew/serviceshttps://github.com/Homebrew/homebrew-services
ptb/customhttps://github.com/ptb/homebrew-custom
railwaycat/emacsmacporthttps://github.com/railwaycat/homebrew-emacsmacport

Add Homebrew Packages to Brewfile

install_brewfile_brew_pkgs () {
  printf "%s\n" "${_pkgs}" | \
  while IFS="$(printf '\t')" read pkg; do
    # printf 'brew "%s", args: [ "force-bottle" ]\n' "${pkg}" >> "${BREWFILE}"
    printf 'brew "%s"\n' "${pkg}" >> "${BREWFILE}"
  done
  printf "\n" >> "${BREWFILE}"
}

_pkgs

Homebrew Package NameReference URL
aspellhttp://aspell.net/
bashhttps://www.gnu.org/software/bash/
certbothttps://certbot.eff.org/
chromedriverhttps://sites.google.com/a/chromium.org/chromedriver/
coreutilshttps://www.gnu.org/software/coreutils/
dashhttp://gondor.apana.org.au/~herbert/dash/
dutihttps://github.com/moretension/duti
e2fsprogshttps://e2fsprogs.sourceforge.io/
fasdhttps://github.com/clvv/fasd
fdupeshttps://github.com/adrianlopezroche/fdupes
gawkhttps://www.gnu.org/software/gawk/
getmailhttp://pyropus.ca/software/getmail/
githttps://git-scm.com/
git-flowhttp://nvie.com/posts/a-successful-git-branching-model/
git-lfshttps://git-lfs.github.com/
gnu-sedhttps://www.gnu.org/software/sed/
gnupghttps://www.gnupg.org/
gpachttps://gpac.wp.imt.fr/
httpiehttps://httpie.org/
hubhttps://hub.github.com/
ievmshttps://xdissent.github.io/ievms/
imagemagickhttps://www.imagemagick.org/
mashttps://github.com/argon/mas
mercurialhttps://www.mercurial-scm.org/
mp4v2https://code.google.com/archive/p/mp4v2/
mtrhttps://www.bitwizard.nl/mtr/
nmaphttps://nmap.org/
nodehttps://nodejs.org/
nodenvhttps://github.com/nodenv/nodenv
opensslhttps://www.openssl.org/
p7ziphttp://p7zip.sourceforge.net/
perl-buildhttps://github.com/tokuhirom/Perl-Build
pinentry-machttps://github.com/GPGTools/pinentry-mac
plenvhttps://github.com/tokuhirom/plenv
pyenvhttps://github.com/pyenv/pyenv
rbenvhttps://github.com/rbenv/rbenv
rsynchttps://rsync.samba.org/
selenium-server-standalonehttp://www.seleniumhq.org/
shellcheckhttps://github.com/koalaman/shellcheck
sleepwatcherhttp://www.bernhard-baehr.de/
sqlitehttps://sqlite.org
stowhttps://www.gnu.org/software/stow/
syncthinghttps://syncthing.net/
syncthing-inotifyhttps://github.com/syncthing/syncthing-inotify
taghttps://github.com/jdberry/tag
terminal-notifierhttps://github.com/julienXX/terminal-notifier
the_silver_searcherhttps://geoff.greer.fm/ag/
trashhttp://hasseg.org/trash/
unrarhttp://www.rarlab.com/
vcshhttps://github.com/RichiH/vcsh
vimhttps://vim.sourceforge.io/
yarnhttps://yarnpkg.com/
youtube-dlhttps://rg3.github.io/youtube-dl/
zshhttps://www.zsh.org/
zsh-syntax-highlightinghttps://github.com/zsh-users/zsh-syntax-highlighting
zsh-history-substring-searchhttps://github.com/zsh-users/zsh-history-substring-search
homebrew/php/php71https://github.com/Homebrew/homebrew-php
ptb/custom/dovecot
ptb/custom/ffmpeg
sdl2
zimg
x265
webp
wavpack
libvorbis
libvidstab
two-lame
theora
tesseract
speex
libssh
libsoxr
snappy
schroedinger
rubberband
rtmpdump
opus
openh264
opencore-amr
libmodplug
libgsm
game-music-emu
fontconfig
fdk-aac
libcaca
libbs2b
libbluray
libass
chromaprint
ptb/custom/nginx-full

Add Caskroom Options to Brewfile

install_brewfile_cask_args () {
  printf 'cask_args \' >> "${BREWFILE}"
  printf "%s\n" "${_args}" | \
  while IFS="$(printf '\t')" read arg dir; do
    printf '\n  %s: "%s",' "${arg}" "${dir}" >> "${BREWFILE}"
  done
  sed -i "" -e '$ s/,/\
/' "${BREWFILE}"
}

Add Homebrew Casks to Brewfile

install_brewfile_cask_pkgs () {
  printf "%s\n" "${_casks}" | \
  while IFS="$(printf '\t')" read cask; do
    printf 'cask "%s"\n' "${cask}" >> "${BREWFILE}"
  done
  printf "\n" >> "${BREWFILE}"
}

_casks

Caskroom Package NameReference URL
javahttps://www.oracle.com/technetwork/java/javase/
xquartzhttps://www.xquartz.org/
adiumhttps://www.adium.im/
alfredhttps://www.alfredapp.com/
arduinohttps://www.arduino.cc/
atomhttps://atom.io/
bbedithttps://www.barebones.com/products/bbedit/
betterziphttps://macitbetter.com/
bitbarhttps://getbitbar.com/
caffeinehttp://lightheadsw.com/caffeine/
carbon-copy-clonerhttps://bombich.com/
charleshttps://www.charlesproxy.com/
dashhttps://kapeli.com/dash
dropboxhttps://www.dropbox.com/
exifrenamerhttp://www.qdev.de/?location=mac/exifrenamer
find-empty-foldershttp://www.tempel.org/FindEmptyFolders
firefoxhttps://www.mozilla.org/firefox/
github-desktophttps://desktop.github.com/
gituphttp://gitup.co/
google-chromehttps://www.google.com/chrome/
hammerspoonhttp://www.hammerspoon.org/
handbrakehttps://handbrake.fr/
hermeshttp://hermesapp.org/
imageoptimhttps://imageoptim.com/mac
inkscapehttps://inkscape.org/
integrityhttp://peacockmedia.software/mac/integrity/
istat-menushttps://bjango.com/mac/istatmenus/
iterm2https://www.iterm2.com/
jublerhttp://www.jubler.org/
little-snitchhttps://www.obdev.at/products/littlesnitch/
machghttp://jasonfharris.com/machg/
menubar-countdownhttp://capablehands.net/menubarcountdown
meteorologisthttp://heat-meteo.sourceforge.net/
moomhttps://manytricks.com/moom/
mp4toolshttp://www.emmgunn.com/mp4tools-home/
musicbrainz-picardhttps://picard.musicbrainz.org/
namechangerhttps://mrrsoftware.com/namechanger/
nvalthttp://brettterpstra.com/projects/nvalt/
nzbgethttps://nzbget.net/
nzbvortexhttps://www.nzbvortex.com/
openemuhttp://openemu.org/
operahttps://www.opera.com/
pacifisthttps://www.charlessoft.com/
platypushttps://sveinbjorn.org/platypus
plex-media-serverhttps://www.plex.tv/
qlstephenhttps://whomwah.github.io/qlstephen/
quitterhttps://marco.org/apps#quitter
radarrhttps://radarr.video/
rescuetimehttps://www.rescuetime.com/
resilio-synchttps://www.resilio.com/individuals/
scrivenerhttps://literatureandlatte.com/scrivener.php
sizeuphttps://www.irradiatedsoftware.com/sizeup/
sketchhttps://www.sketchapp.com/
sketchuphttps://www.sketchup.com/
skitchhttps://evernote.com/products/skitch
skypehttps://www.skype.com/
slackhttps://slack.com/
sonarrhttps://sonarr.tv/
sonarr-menuhttps://github.com/jefbarn/Sonarr-Menu
sourcetreehttps://www.sourcetreeapp.com/
steermousehttp://plentycom.jp/en/steermouse/
sublerhttps://subler.org/
sublime-texthttps://www.sublimetext.com/3
the-unarchiverhttps://theunarchiver.com/
time-sinkhttps://manytricks.com/timesink/
torbrowserhttps://www.torproject.org/projects/torbrowser.html
towerhttps://www.git-tower.com/
unrarxhttp://www.unrarx.com/
vimrhttp://vimr.org/
vlchttps://www.videolan.org/vlc/
vmware-fusionhttps://www.vmware.com/products/fusion.html
wiresharkhttps://www.wireshark.org/
xldhttp://tmkk.undo.jp/xld/index_e.html
caskroom/fonts/font-inconsolata-lgchttps://github.com/DeLaGuardo/Inconsolata-LGC
caskroom/versions/transmit4https://panic.com/transmit/
ptb/custom/adobe-creative-cloud-2014https://www.adobe.com/creativecloud.html
ptb/custom/blankscreenhttp://www.wurst-wasser.net/wiki/index.php/Blank_Screen_Saver
ptb/custom/composerhttps://www.jamf.com/products/jamf-composer/
ptb/custom/enhanced-dictation
ptb/custom/ipmenulethttps://github.com/mcandre/IPMenulet
ptb/custom/pcalc-3http://www.pcalc.com/english/about.html
ptb/custom/sketchup-prohttps://www.sketchup.com/products/sketchup-pro
ptb/custom/text-to-speech-alex
ptb/custom/text-to-speech-allison
ptb/custom/text-to-speech-samantha
ptb/custom/text-to-speech-tom
railwaycat/emacsmacport/emacs-mac-spacemacs-iconhttps://github.com/railwaycat/homebrew-emacsmacport

Add App Store Packages to Brewfile

install_brewfile_mas_apps () {
  open "/Applications/App Store.app"
  run "Sign in to the App Store with your Apple ID" "Cancel" "OK"

  MASDIR="$(getconf DARWIN_USER_CACHE_DIR)com.apple.appstore"
  sudo chown -R "$(whoami)" "${MASDIR}"
  rsync -a --delay-updates \
    "${CACHES}/mas/" "${MASDIR}/"

  printf "%s\n" "${_mas}" | \
  while IFS="$(printf '\t')" read app id; do
    printf 'mas "%s", id: %s\n' "${app}" "${id}" >> "${BREWFILE}"
  done
}

_mas

App NameApp IDApp Store URL
1Password443987910https://itunes.apple.com/app/id443987910
Affinity Photo824183456https://itunes.apple.com/app/id824183456
Coffitivity659901392https://itunes.apple.com/app/id659901392
Duplicate Photos Fixer Pro963642514https://itunes.apple.com/app/id963642514
Growl467939042https://itunes.apple.com/app/id467939042
HardwareGrowler475260933https://itunes.apple.com/app/id475260933
I Love Stars402642760https://itunes.apple.com/app/id402642760
Icon Slate439697913https://itunes.apple.com/app/id439697913
Justnotes511230166https://itunes.apple.com/app/id511230166
Keynote409183694https://itunes.apple.com/app/id409183694
Metanota Pro515250764https://itunes.apple.com/app/id515250764
Numbers409203825https://itunes.apple.com/app/id409203825
Pages409201541https://itunes.apple.com/app/id409201541
WiFi Explorer494803304https://itunes.apple.com/app/id494803304
Xcode497799835https://itunes.apple.com/app/id497799835
macOS High Sierra1209167288https://itunes.apple.com/app/id1209167288

Link System Utilities to Applications

install_links () {
  printf "%s\n" "${_links}" | \
  while IFS="$(printf '\t')" read link; do
    find "${link}" -maxdepth 1 -name "*.app" -type d -print0 2> /dev/null | \
    xargs -0 -I {} -L 1 ln -s "{}" "/Applications" 2> /dev/null
  done
}

_links

Application Locations
/System/Library/CoreServices/Applications
/Applications/Xcode.app/Contents/Applications
/Applications/Xcode.app/Contents/Developer/Applications
/Applications/Xcode-beta.app/Contents/Applications
/Applications/Xcode-beta.app/Contents/Developer/Applications

Install Node.js with nodenv

install_node_sw () {
  if which nodenv > /dev/null; then
    NODENV_ROOT="/usr/local/node" && export NODENV_ROOT

    sudo mkdir -p "$NODENV_ROOT"
    sudo chown -R "$(whoami):admin" "$NODENV_ROOT"

    p "Installing Node.js with nodenv"
    git clone https://github.com/nodenv/node-build-update-defs.git \
      "$(nodenv root)"/plugins/node-build-update-defs
    nodenv update-version-defs > /dev/null

    nodenv install --skip-existing 8.7.0
    nodenv global 8.7.0

    grep -q "${NODENV_ROOT}" "/etc/paths" || \
    sudo sed -i "" -e "1i\\
${NODENV_ROOT}/shims
" "/etc/paths"

    init_paths
    rehash
  fi

  T=$(printf '\t')

  printf "%s\n" "$_npm" | \
  while IFS="$T" read pkg; do
    npm install --global "$pkg"
  done

  rehash
}
NPM Package NameReference URL
eslinthttps://eslint.org/
eslint-config-cleanjshttps://github.com/bodil/eslint-config-cleanjs
eslint-plugin-betterhttps://github.com/idmitriev/eslint-plugin-better
eslint-plugin-fphttps://github.com/jfmengels/eslint-plugin-fp
eslint-plugin-importhttps://github.com/benmosher/eslint-plugin-import
eslint-plugin-jsonhttps://github.com/azeemba/eslint-plugin-json
eslint-plugin-promisehttps://github.com/xjamundx/eslint-plugin-promise
eslint-plugin-standardhttps://github.com/xjamundx/eslint-plugin-standard
gatsby
jsonhttp://trentm.com/json/
sort-jsonhttps://github.com/kesla/sort-json

Install Perl 5 with plenv

install_perl_sw () {
  if which plenv > /dev/null; then
    PLENV_ROOT="/usr/local/perl" && export PLENV_ROOT

    sudo mkdir -p "$PLENV_ROOT"
    sudo chown -R "$(whoami):admin" "$PLENV_ROOT"

    p "Installing Perl 5 with plenv"
    plenv install 5.26.0 > /dev/null 2>&1
    plenv global 5.26.0

    grep -q "${PLENV_ROOT}" "/etc/paths" || \
    sudo sed -i "" -e "1i\\
${PLENV_ROOT}/shims
" "/etc/paths"

    init_paths
    rehash
  fi
}

Install Python with pyenv

install_python_sw () {
  if which pyenv > /dev/null; then
    CFLAGS="-I$(brew --prefix openssl)/include" && export CFLAGS
    LDFLAGS="-L$(brew --prefix openssl)/lib" && export LDFLAGS
    PYENV_ROOT="/usr/local/python" && export PYENV_ROOT

    sudo mkdir -p "$PYENV_ROOT"
    sudo chown -R "$(whoami):admin" "$PYENV_ROOT"

    p "Installing Python 2 with pyenv"
    pyenv install --skip-existing 2.7.13
    p "Installing Python 3 with pyenv"
    pyenv install --skip-existing 3.6.2
    pyenv global 2.7.13

    grep -q "${PYENV_ROOT}" "/etc/paths" || \
    sudo sed -i "" -e "1i\\
${PYENV_ROOT}/shims
" "/etc/paths"

    init_paths
    rehash

    pip install --upgrade "pip" "setuptools"

    # Reference: https://github.com/mdhiggins/sickbeard_mp4_automator
    pip install --upgrade "babelfish" "guessit<2" "qtfaststart" "requests" "stevedore==1.19.1" "subliminal<2"
    pip install --upgrade "requests-cache" "requests[security]"

    # Reference: https://github.com/pixelb/crudini
    pip install --upgrade "crudini"
  fi
}

Install Ruby with rbenv

install_ruby_sw () {
  if which rbenv > /dev/null; then
    RBENV_ROOT="/usr/local/ruby" && export RBENV_ROOT

    sudo mkdir -p "$RBENV_ROOT"
    sudo chown -R "$(whoami):admin" "$RBENV_ROOT"

    p "Installing Ruby with rbenv"
    rbenv install --skip-existing 2.4.2
    rbenv global 2.4.2

    grep -q "${RBENV_ROOT}" "/etc/paths" || \
    sudo sed -i "" -e "1i\\
${RBENV_ROOT}/shims
" "/etc/paths"

    init_paths
    rehash

    printf "%s\n" \
      "gem: --no-document" | \
    tee "${HOME}/.gemrc" > /dev/null

    gem update --system > /dev/null

    trash "$(which rdoc)"
    trash "$(which ri)"
    gem update

    gem install bundler
  fi
}

Configure

Define Function config

config () {
  config_admin_req
  config_bbedit
  config_certbot
  config_desktop
  config_dovecot
  config_emacs
  config_environment
  config_ipmenulet
  config_istatmenus
  config_nginx
  config_openssl
  config_sysprefs
  config_zsh
  config_guest

  which custom
}

Define Function config_defaults

config_defaults () {
  printf "%s\n" "${1}" | \
  while IFS="$(printf '\t')" read domain key type value host; do
    ${2} defaults ${host} write ${domain} "${key}" ${type} "${value}"
  done
}

Define Function config_plist

T="$(printf '\t')"

config_plist () {
  printf "%s\n" "$1" | \
  while IFS="$T" read command entry type value; do
    case "$value" in
      (\$*)
        $4 /usr/libexec/PlistBuddy "$2" \
          -c "$command '${3}${entry}' $type '$(eval echo \"$value\")'" 2> /dev/null ;;
      (*)
        $4 /usr/libexec/PlistBuddy "$2" \
          -c "$command '${3}${entry}' $type '$value'" 2> /dev/null ;;
    esac
  done
}

Define Function config_launchd

config_launchd () {
  test -d "$(dirname $1)" || \
    $3 mkdir -p "$(dirname $1)"

  test -f "$1" && \
    $3 launchctl unload "$1" && \
    $3 rm -f "$1"

  config_plist "$2" "$1" "$4" "$3" && \
    $3 plutil -convert xml1 "$1" && \
    $3 launchctl load "$1"
}

Mark Applications Requiring Administrator Account

config_admin_req () {
  printf "%s\n" "${_admin_req}" | \
  while IFS="$(printf '\t')" read app; do
    sudo tag -a "Red, admin" "/Applications/${app}"
  done
}

_admin_req

Admin Apps
Carbon Copy Cloner.app
Charles.app
Composer.app
Dropbox.app
iStat Menus.app
Moom.app
VMware Fusion.app
Wireshark.app

Configure BBEdit

config_bbedit () {
  if test -d "/Applications/BBEdit.app"; then
    test -f "/usr/local/bin/bbdiff" || \
    ln /Applications/BBEdit.app/Contents/Helpers/bbdiff /usr/local/bin/bbdiff && \
    ln /Applications/BBEdit.app/Contents/Helpers/bbedit_tool /usr/local/bin/bbedit && \
    ln /Applications/BBEdit.app/Contents/Helpers/bbfind /usr/local/bin/bbfind && \
    ln /Applications/BBEdit.app/Contents/Helpers/bbresults /usr/local/bin/bbresults
  fi
}

Configure Let’s Encrypt

config_certbot () {
  test -d "/etc/letsencrypt" || \
    sudo mkdir -p /etc/letsencrypt

  sudo tee "/etc/letsencrypt/cli.ini" << EOF > /dev/null
agree-tos = True
authenticator = standalone
eff-email = True
manual-public-ip-logging-ok = True
nginx-ctl = $(which nginx)
nginx-server-root = /usr/local/etc/nginx
preferred-challenges = tls-sni-01
keep-until-expiring = True
rsa-key-size = 4096
text = True
EOF

  if ! test -e "/etc/letsencrypt/.git"; then
    a=$(ask "Existing Let’s Encrypt Git Repository Path or URL?" "Clone Repository" "")
    test -n "$a" && \
    case "$a" in
      (/*)
        sudo tee "/etc/letsencrypt/.git" << EOF > /dev/null ;;
gitdir: $a
EOF
      (*)
        sudo git -C "/etc/letsencrypt" remote add origin "$a"
        sudo git -C "/etc/letsencrypt" fetch origin master ;;
    esac
    sudo git -C "/etc/letsencrypt" reset --hard
    sudo git checkout -f -b master HEAD
  fi

  sudo launchctl unload /Library/LaunchDaemons/org.nginx.nginx.plist 2> /dev/null
  sudo certbot renew

  while true; do
    test -n "$1" && server_name="$1" || \
      server_name="$(ask 'New SSL Server: Server Name?' 'Create Server' 'example.com')"
    test -n "$server_name" || break

    test -n "$2" && proxy_address="$2" || \
      proxy_address="$(ask "Proxy Address for $server_name?" 'Set Address' 'http://127.0.0.1:80')"

    sudo certbot certonly --domain $server_name

    key1="$(openssl x509 -pubkey < /etc/letsencrypt/live/$server_name/fullchain.pem | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64)"
    key2="$(curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64)"
    key3="$(curl -s https://letsencrypt.org/certs/isrgrootx1.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64)"

    pkp="$(printf "add_header Public-Key-Pins 'pin-sha256=\"%s\"; pin-sha256=\"%s\"; pin-sha256=\"%s\"; max-age=2592000;';\n" $key1 $key2 $key3)"

    cat << EOF > "/usr/local/etc/nginx/servers/$server_name.conf"
<<server_name.conf>>
EOF
    unset argv
  done

  sudo launchctl load /Library/LaunchDaemons/org.nginx.nginx.plist
}

/usr/local/etc/nginx/servers/server_name/server_name.conf

server {
  server_name $server_name;

  location / {
    proxy_pass $proxy_address;
  }

  ssl_certificate /etc/letsencrypt/live/$server_name/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/$server_name/privkey.pem;
  ssl_trusted_certificate /etc/letsencrypt/live/$server_name/chain.pem;

  $pkp

  add_header Content-Security-Policy "upgrade-insecure-requests;";
  add_header Referrer-Policy "strict-origin";
  add_header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload" always;
  add_header X-Content-Type-Options nosniff;
  add_header X-Frame-Options DENY;
  add_header X-Robots-Tag none;
  add_header X-XSS-Protection "1; mode=block";

  listen 443 ssl http2;
  listen [::]:443 ssl http2;

  ssl_stapling on;
  ssl_stapling_verify on;

  # https://securityheaders.io/?q=https%3A%2F%2F$server_name&hide=on&followRedirects=on
  # https://www.ssllabs.com/ssltest/analyze.html?d=$server_name&hideResults=on&latest
}

Configure Default Apps

config_default_apps () {
  true
}

Configure Desktop Picture

config_desktop () {
  sudo rm -f "/Library/Caches/com.apple.desktop.admin.png"

  base64 -D << EOF > "/Library/Desktop Pictures/Solid Colors/Solid Black.png"
<<black.png.b64>>
EOF
}

black.png.b64

iVBORw0KGgoAAAANSUhEUgAAAIAAAACAAQAAAADrRVxmAAAAGElEQVR4AWOgMxgFo2AUjIJRMApGwSgAAAiAAAH3bJXBAAAAAElFTkSuQmCC

Configure Dovecot

config_dovecot () {
  if which /usr/local/sbin/dovecot > /dev/null; then
    if ! run "Configure Dovecot Email Server?" "Configure Server" "Cancel"; then
      sudo tee "/usr/local/etc/dovecot/dovecot.conf" << EOF > /dev/null
<<dovecot.conf>>
EOF

      MAILADM="$(ask 'Email: Postmaster Email?' 'Set Email' "$(whoami)@$(hostname -f | cut -d. -f2-)")"
      MAILSVR="$(ask 'Email: Server Hostname for DNS?' 'Set Hostname' "$(hostname -f)")"
      sudo certbot certonly --domain $MAILSVR
      printf "%s\n" \
        "postmaster_address = '${MAILADM}'" \
        "ssl_cert = </etc/letsencrypt/live/$MAILSVR/fullchain.pem" \
        "ssl_key = </etc/letsencrypt/live/$MAILSVR/privkey.pem" | \
      sudo tee -a "/usr/local/etc/dovecot/dovecot.conf" > /dev/null

      if test ! -f "/usr/local/etc/dovecot/cram-md5.pwd"; then
        while true; do
          MAILUSR="$(ask 'New Email Account: User Name?' 'Create Account' "$(whoami)")"
          test -n "${MAILUSR}" || break
          doveadm pw | \
          sed -e "s/^/${MAILUSR}:/" | \
          sudo tee -a "/usr/local/etc/dovecot/cram-md5.pwd"
        done
        sudo chown _dovecot "/usr/local/etc/dovecot/cram-md5.pwd"
        sudo chmod go= "/usr/local/etc/dovecot/cram-md5.pwd"
      fi

      sudo tee "/etc/pam.d/dovecot" << EOF > /dev/null
<<dovecot.pam>>
EOF

      sudo brew services start dovecot

      cat << EOF > "/usr/local/bin/imaptimefix.py"
<<imaptimefix.py>>
EOF
      chmod +x /usr/local/bin/imaptimefix.py
    fi
  fi
}

/usr/local/etc/dovecot/dovecot.conf

auth_mechanisms = cram-md5
default_internal_user = _dovecot
default_login_user = _dovenull
log_path = /dev/stderr
mail_location = maildir:~/.mail:INBOX=~/.mail/Inbox:LAYOUT=fs
mail_plugins = zlib
maildir_copy_with_hardlinks = no
namespace {
  inbox = yes
  mailbox Drafts {
    auto = subscribe
    special_use = \Drafts
  }
  mailbox Junk {
    auto = subscribe
    special_use = \Junk
  }
  mailbox Sent {
    auto = subscribe
    special_use = \Sent
  }
  mailbox "Sent Messages" {
    special_use = \Sent
  }
  mailbox Trash {
    auto = subscribe
    special_use = \Trash
  }
  separator = .
  type = private
}
passdb {
  args = scheme=cram-md5 /usr/local/etc/dovecot/cram-md5.pwd
  driver = passwd-file

  # driver = pam

  # args = nopassword=y
  # driver = static
}
plugin {
  sieve = file:/Users/%u/.sieve
  sieve_plugins = sieve_extprograms
  zlib_save = bz2
  zlib_save_level = 9
}
protocols = imap
service imap-login {
  inet_listener imap {
    port = 0
  }
}
ssl = required
ssl_cipher_list = ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS:!AES128
ssl_dh_parameters_length = 4096
ssl_prefer_server_ciphers = yes
ssl_protocols = !SSLv2 !SSLv3
userdb {
  driver = passwd
}
protocol lda {
  mail_plugins = sieve zlib
}

# auth_debug = yes
# auth_debug_passwords = yes
# auth_verbose = yes
# auth_verbose_passwords = plain
# mail_debug = yes
# verbose_ssl = yes

/etc/pam.d/dovecot

auth	required	pam_opendirectory.so	try_first_pass
account	required	pam_nologin.so
account	required	pam_opendirectory.so
password	required	pam_opendirectory.so

/usr/local/bin/imaptimefix.py

#!/usr/bin/env python

# Author: Zachary Cutlip <@zcutlip>
# http://shadow-file.blogspot.com/2012/06/parsing-email-and-fixing-timestamps-in.html
# Updated: Peter T Bosse II <@ptb>
# Purpose: A program to fix sorting of mail messages that have been POPed or
#          IMAPed in the wrong order. Compares time stamp sent and timestamp
#          received on an RFC822-formatted email message, and renames the
#          message file using the most recent timestamp that is no more than
#          24 hours after the date sent. Updates the file's atime/mtime with
#          the timestamp, as well. Does not modify the headers or contents of
#          the message.

from bz2 import BZ2File
from email import message_from_string
from email.utils import mktime_tz, parsedate_tz
from os import rename, utime, walk
from os.path import abspath, isdir, isfile, join
from re import compile, match
from sys import argv

if isdir(argv[1]):
  e = compile("([0-9]+)(\..*$)")

  for a, b, c in walk(argv[1]):
    for d in c:
      if e.match(d):
        f = message_from_string(BZ2File(join(a, d)).read())
        g = mktime_tz(parsedate_tz(f.get("Date")))

        h = 0
        for i in f.get_all("Received", []):
          j = i.split(";")[-1]
          if parsedate_tz(j):
            k = mktime_tz(parsedate_tz(j))
            if (k - g) > (60*60*24):
              continue

            h = k
          break

        if (h < 1):
          h = g

        l = e.match(d)

        if len(l.groups()) == 2:
          m = str(int(h)) + l.groups()[1]
          if not isfile(join(a, m)):
            rename(join(a, d), join(a, m))
          utime(join(a, m), (h, h))

Configure Emacs

config_emacs () {
  test -f "/usr/local/bin/vi" || \
  cat << EOF > "/usr/local/bin/vi"
<<vi.sh>>
EOF

  chmod a+x /usr/local/bin/vi
  rehash
}

/usr/local/bin/vi

#!/bin/sh

if [ -e "/Applications/Emacs.app" ]; then
  t=()

  if [ \${#@} -ne 0 ]; then
    while IFS= read -r file; do
      [ ! -f "\$file" ] && t+=("\$file") && /usr/bin/touch "\$file"
      file=\$(echo \$(cd \$(dirname "\$file") && pwd -P)/\$(basename "\$file"))
      \$(/usr/bin/osascript <<-END
        if application "Emacs.app" is running then
          tell application id (id of application "Emacs.app") to open POSIX file "\$file"
        else
          tell application ((path to applications folder as text) & "Emacs.app")
            activate
            open POSIX file "\$file"
          end tell
        end if
END
        ) &  # Note: END on the previous line may be indented with tabs but not spaces
    done <<<"\$(printf '%s\n' "\$@")"
  fi

  if [ ! -z "\$t" ]; then
    \$(/bin/sleep 10; for file in "\${t[@]}"; do
      [ ! -s "\$file" ] && /bin/rm "\$file";
    done) &
  fi
else
  vim -No "\$@"
fi

Configure Environment Variables

config_environment () {
  sudo tee "/etc/environment.sh" << 'EOF' > /dev/null
<<environment.sh>>
EOF
  sudo chmod a+x "/etc/environment.sh"
  rehash

  la="/Library/LaunchAgents/environment.user"
  ld="/Library/LaunchDaemons/environment"

  sudo mkdir -p "$(dirname $la)" "$(dirname $ld)"
  sudo launchctl unload "${la}.plist" "${ld}.plist" 2> /dev/null
  sudo rm -f "${la}.plist" "${ld}.plist"

  config_defaults "$_environment_defaults" "sudo"
  sudo plutil -convert xml1 "${la}.plist" "${ld}.plist"
  sudo launchctl load "${la}.plist" "${ld}.plist" 2> /dev/null
}

/etc/environment.sh

#!/bin/sh

set -e

if test -x /usr/libexec/path_helper; then
  export PATH=""
  eval `/usr/libexec/path_helper -s`
  launchctl setenv PATH $PATH
fi

osascript -e 'tell app "Dock" to quit'

_environment_defaults

DomainKeyTypeValueHost
/Library/LaunchAgents/environment.userKeepAlive-boolfalse
/Library/LaunchAgents/environment.userLabel-stringenvironment.user
/Library/LaunchAgents/environment.userProcessType-stringBackground
/Library/LaunchAgents/environment.userProgram-string/etc/environment.sh
/Library/LaunchAgents/environment.userRunAtLoad-booltrue
/Library/LaunchAgents/environment.userWatchPaths-array-add/etc/environment.sh
/Library/LaunchAgents/environment.userWatchPaths-array-add/etc/paths
/Library/LaunchAgents/environment.userWatchPaths-array-add/etc/paths.d
/Library/LaunchDaemons/environmentKeepAlive-boolfalse
/Library/LaunchDaemons/environmentLabel-stringenvironment
/Library/LaunchDaemons/environmentProcessType-stringBackground
/Library/LaunchDaemons/environmentProgram-string/etc/environment.sh
/Library/LaunchDaemons/environmentRunAtLoad-booltrue
/Library/LaunchDaemons/environmentWatchPaths-array-add/etc/environment.sh
/Library/LaunchDaemons/environmentWatchPaths-array-add/etc/paths
/Library/LaunchDaemons/environmentWatchPaths-array-add/etc/paths.d

Configure IPMenulet

config_ipmenulet () {
  _ipm="/Applications/IPMenulet.app/Contents/Resources"
  if test -d "$_ipm"; then
    rm "${_ipm}/icon-19x19-black.png"
    ln "${_ipm}/icon-19x19-white.png" "${_ipm}/icon-19x19-black.png"
  fi
}

Configure iStat Menus

config_istatmenus () {
  test -d "/Applications/iStat Menus.app" && \
  open "/Applications/iStat Menus.app"
}

Notes

client_max_body_size 0;

location / {
  if ($http_x_plex_device_name = "") {
    rewrite ^/$ https://$host/web/index.html permanent;
  }
}

Configure nginx

config_nginx () {
  cat << 'EOF' > /usr/local/etc/nginx/nginx.conf
<<nginx.conf>>
EOF

  ld="/Library/LaunchDaemons/org.nginx.nginx"

  sudo mkdir -p "$(dirname $ld)"
  sudo launchctl unload "${ld}.plist" 2> /dev/null
  sudo rm -f "${ld}.plist"

  config_defaults "$_nginx_defaults" "sudo"
  sudo plutil -convert xml1 "${ld}.plist"
  sudo launchctl load "${ld}.plist" 2> /dev/null
}

/usr/local/etc/nginx/nginx.conf

daemon off;

events {
  accept_mutex off;
  worker_connections 8000;
}

http {
  charset utf-8;
  charset_types
    application/javascript
    application/json
    application/rss+xml
    application/xhtml+xml
    application/xml
    text/css
    text/plain
    text/vnd.wap.wml;

  default_type application/octet-stream;

  error_log /dev/stderr;

  gzip on;
  gzip_comp_level 9;
  gzip_min_length 256;
  gzip_proxied any;
  gzip_static on;
  gzip_vary on;

  gzip_types
    application/atom+xml
    application/javascript
    application/json
    application/ld+json
    application/manifest+json
    application/rss+xml
    application/vnd.geo+json
    application/vnd.ms-fontobject
    application/x-font-ttf
    application/x-web-app-manifest+json
    application/xhtml+xml
    application/xml
    font/opentype
    image/bmp
    image/svg+xml
    image/x-icon
    text/cache-manifest
    text/css
    text/plain
    text/vcard
    text/vnd.rim.location.xloc
    text/vtt
    text/x-component
    text/x-cross-domain-policy;

  index index.html index.xhtml;

  log_format default '$host $status $body_bytes_sent "$request" "$http_referer"\n'
    '  $remote_addr "$http_user_agent"';

  map $http_upgrade $connection_upgrade {
    default upgrade;
    "" close;
  }

  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection $connection_upgrade;

  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header X-Real-IP $remote_addr;

  proxy_buffering off;
  proxy_redirect off;

  sendfile on;
  sendfile_max_chunk 512k;

  server_tokens off;

  resolver 8.8.8.8 8.8.4.4 [2001:4860:4860::8888] [2001:4860:4860::8844] valid=300s;
  resolver_timeout 5s;

  # https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
  ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS:!AES128;

  # openssl dhparam -out /etc/letsencrypt/ssl-dhparam.pem 4096
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

  ssl_ecdh_curve secp384r1;
  ssl_prefer_server_ciphers on;
  ssl_protocols TLSv1.2;
  ssl_session_cache shared:TLS:10m;

  types {
    application/atom+xml atom;
    application/font-woff woff;
    application/font-woff2 woff2;
    application/java-archive ear jar war;
    application/javascript js;
    application/json json map topojson;
    application/ld+json jsonld;
    application/mac-binhex40 hqx;
    application/manifest+json webmanifest;
    application/msword doc;
    application/octet-stream bin deb dll dmg exe img iso msi msm msp safariextz;
    application/pdf pdf;
    application/postscript ai eps ps;
    application/rss+xml rss;
    application/rtf rtf;
    application/vnd.geo+json geojson;
    application/vnd.google-earth.kml+xml kml;
    application/vnd.google-earth.kmz kmz;
    application/vnd.ms-excel xls;
    application/vnd.ms-fontobject eot;
    application/vnd.ms-powerpoint ppt;
    application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
    application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
    application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
    application/vnd.wap.wmlc wmlc;
    application/x-7z-compressed 7z;
    application/x-bb-appworld bbaw;
    application/x-bittorrent torrent;
    application/x-chrome-extension crx;
    application/x-cocoa cco;
    application/x-font-ttf ttc ttf;
    application/x-java-archive-diff jardiff;
    application/x-java-jnlp-file jnlp;
    application/x-makeself run;
    application/x-opera-extension oex;
    application/x-perl pl pm;
    application/x-pilot pdb prc;
    application/x-rar-compressed rar;
    application/x-redhat-package-manager rpm;
    application/x-sea sea;
    application/x-shockwave-flash swf;
    application/x-stuffit sit;
    application/x-tcl tcl tk;
    application/x-web-app-manifest+json webapp;
    application/x-x509-ca-cert crt der pem;
    application/x-xpinstall xpi;
    application/xhtml+xml xhtml;
    application/xml rdf xml;
    application/xslt+xml xsl;
    application/zip zip;
    audio/midi mid midi kar;
    audio/mp4 aac f4a f4b m4a;
    audio/mpeg mp3;
    audio/ogg oga ogg opus;
    audio/x-realaudio ra;
    audio/x-wav wav;
    font/opentype otf;
    image/bmp bmp;
    image/gif gif;
    image/jpeg jpeg jpg;
    image/png png;
    image/svg+xml svg svgz;
    image/tiff tif tiff;
    image/vnd.wap.wbmp wbmp;
    image/webp webp;
    image/x-icon cur ico;
    image/x-jng jng;
    text/cache-manifest appcache;
    text/css css;
    text/html htm html shtml;
    text/mathml mml;
    text/plain txt;
    text/vcard vcard vcf;
    text/vnd.rim.location.xloc xloc;
    text/vnd.sun.j2me.app-descriptor jad;
    text/vnd.wap.wml wml;
    text/vtt vtt;
    text/x-component htc;
    video/3gpp 3gp 3gpp;
    video/mp4 f4p f4v m4v mp4;
    video/mpeg mpeg mpg;
    video/ogg ogv;
    video/quicktime mov;
    video/webm webm;
    video/x-flv flv;
    video/x-mng mng;
    video/x-ms-asf asf asx;
    video/x-ms-wmv wmv;
    video/x-msvideo avi;
  }

  include servers/*.conf;
}

worker_processes auto;

_nginx_defaults

DomainKeyTypeValueHost
/Library/LaunchDaemons/org.nginx.nginxKeepAlive-booltrue
/Library/LaunchDaemons/org.nginx.nginxLabel-stringorg.nginx.nginx
/Library/LaunchDaemons/org.nginx.nginxProcessType-stringBackground
/Library/LaunchDaemons/org.nginx.nginxProgram-string/usr/local/bin/nginx
/Library/LaunchDaemons/org.nginx.nginxRunAtLoad-booltrue
/Library/LaunchDaemons/org.nginx.nginxStandardErrorPath-string/usr/local/var/log/nginx/error.log
/Library/LaunchDaemons/org.nginx.nginxStandardOutPath-string/usr/local/var/log/nginx/access.log
/Library/LaunchDaemons/org.nginx.nginxUserName-stringroot
/Library/LaunchDaemons/org.nginx.nginxWatchPaths-array-add/usr/local/etc/nginx

Configure OpenSSL

Create an intentionally invalid certificate for use with a DNS-based ad blocker, e.g. https://pi-hole.net

config_openssl () {
  _default="/etc/letsencrypt/live/default"
  test -d "$_default" || mkdir -p "$_default"

  cat << EOF > "${_default}/default.cnf"
<<openssl.cnf>>
EOF

  openssl req -days 1 -new -newkey rsa -x509 \
    -config "${_default}/default.cnf" \
    -out "${_default}/default.crt"

  cat << EOF > "/usr/local/etc/nginx/servers/default.conf"
<<default.conf>>
EOF
}

/etc/letsencrypt/live/default/default.cnf

[ req ]
default_bits = 4096
default_keyfile = ${_default}/default.key
default_md = sha256
distinguished_name = dn
encrypt_key = no
prompt = no
utf8 = yes
x509_extensions = v3_ca

[ dn ]
CN = *

[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = CA:true

/usr/local/etc/nginx/servers/default.conf

server {
  server_name .$(hostname -f | cut -d. -f2-);

  listen 80;
  listen [::]:80;

  return 301 https://\$host\$request_uri;
}

server {
  listen 80 default_server;
  listen [::]:80 default_server;

  listen 443 default_server ssl http2;
  listen [::]:443 default_server ssl http2;

  ssl_certificate ${_default}/default.crt;
  ssl_certificate_key ${_default}/default.key;

  ssl_ciphers NULL;

  return 204;
}

Configure System Preferences

config_sysprefs () {
  config_energy
  config_loginwindow
  config_mas
}

Configure Energy Saver

config_energy () {
  printf "%s\n" "${_energy}" | \
  while IFS="$(printf '\t')" read flag setting value; do
    sudo pmset $flag ${setting} ${value}
  done
}
_energy
PreferenceFlagSettingValue
Power: Turn display off after: 20 min-cdisplaysleep20
Power: on Prevent computer from sleeping automatically when the display is off-csleep0
Power: 60 min Put hard disks to sleep when possible-cdisksleep60
Power: on Wake for network access-cwomp1
Power: on Start up automatically after a power failure-cautorestart1
Power: on Enable Power Nap-cpowernap1
UPS: Turn display off after: 2 min-udisplaysleep2
UPS: on Slightly dim the display when using this power source-ulessbright1
UPS: on Shut down the computer after using the UPS battery for: 5 min-uhaltafter5
UPS: off Shut down the computer when the time remaining on the UPS battery is:-uhaltremain-1
UPS: off Shut down the computer when the UPS battery level is below:-uhaltlevel-1

Configure Login Window

config_loginwindow () {
  config_defaults "${_loginwindow}" "sudo"
}

_loginwindow

PreferenceDomainKeyTypeValueHost
Display login window as: Name and password/Library/Preferences/com.apple.loginwindowSHOWFULLNAME-booltrue

Configure App Store

config_mas () {
  config_defaults "${_swupdate}" "sudo"
}

_swupdate

PreferenceDomainKeyTypeValueHost
on Install app updates/Library/Preferences/com.apple.commerceAutoUpdate-booltrue
on Install macOS updates/Library/Preferences/com.apple.commerceAutoUpdateRestartRequired-booltrue

Configure Z-Shell

config_zsh () {
  grep -q "$(which zsh)" /etc/shells ||
  print "$(which zsh)\n" | \
  sudo tee -a /etc/shells > /dev/null

  case "$SHELL" in
    ($(which zsh)) ;;
    (*)
      chsh -s "$(which zsh)"
      sudo chsh -s $(which zsh) ;;
  esac

  sudo tee -a /etc/zshenv << 'EOF' > /dev/null
<<etc-zshenv>>
EOF
  sudo chmod +x "/etc/zshenv"
  . "/etc/zshenv"

  sudo tee /etc/zshrc << 'EOF' > /dev/null
<<etc-zshrc>>
EOF
  sudo chmod +x "/etc/zshrc"
  . "/etc/zshrc"
}

/etc/zshenv

#-- Exports ----------------------------------------------------

export \
  ZDOTDIR="${HOME}/.zsh" \
  MASDIR="$(getconf DARWIN_USER_CACHE_DIR)com.apple.appstore" \
  NODENV_ROOT="/usr/local/node" \
  PLENV_ROOT="/usr/local/perl" \
  PYENV_ROOT="/usr/local/python" \
  RBENV_ROOT="/usr/local/ruby" \
  EDITOR="vi" \
  VISUAL="vi" \
  PAGER="less" \
  LANG="en_US.UTF-8" \
  LESS="-egiMQRS -x2 -z-2" \
  LESSHISTFILE="/dev/null" \
  HISTSIZE=50000 \
  SAVEHIST=50000 \
  KEYTIMEOUT=1

test -d "$ZDOTDIR" || \
  mkdir -p "$ZDOTDIR"

test -f "${ZDOTDIR}/.zshrc" || \
  touch "${ZDOTDIR}/.zshrc"

# Ensure path arrays do not contain duplicates.
typeset -gU cdpath fpath mailpath path

/etc/zshrc

#-- Exports ----------------------------------------------------

export \
  HISTFILE="${ZDOTDIR:-$HOME}/.zhistory"

#-- Changing Directories ---------------------------------------

setopt \
  autocd \
  autopushd \
  cdablevars \
  chasedots \
  chaselinks \
  NO_posixcd \
  pushdignoredups \
  no_pushdminus \
  pushdsilent \
  pushdtohome

#-- Completion -------------------------------------------------

setopt \
  ALWAYSLASTPROMPT \
  no_alwaystoend \
  AUTOLIST \
  AUTOMENU \
  autonamedirs \
  AUTOPARAMKEYS \
  AUTOPARAMSLASH \
  AUTOREMOVESLASH \
  no_bashautolist \
  no_completealiases \
  completeinword \
  no_globcomplete \
  HASHLISTALL \
  LISTAMBIGUOUS \
  no_LISTBEEP \
  no_listpacked \
  no_listrowsfirst \
  LISTTYPES \
  no_menucomplete \
  no_recexact

#-- Expansion and Globbing -------------------------------------

setopt \
  BADPATTERN \
  BAREGLOBQUAL \
  braceccl \
  CASEGLOB \
  CASEMATCH \
  NO_cshnullglob \
  EQUALS \
  extendedglob \
  no_forcefloat \
  GLOB \
  NO_globassign \
  no_globdots \
  no_globstarshort \
  NO_globsubst \
  no_histsubstpattern \
  NO_ignorebraces \
  no_ignoreclosebraces \
  NO_kshglob \
  no_magicequalsubst \
  no_markdirs \
  MULTIBYTE \
  NOMATCH \
  no_nullglob \
  no_numericglobsort \
  no_rcexpandparam \
  no_rematchpcre \
  NO_shglob \
  UNSET \
  no_warncreateglobal \
  no_warnnestedvar

#-- History ----------------------------------------------------

setopt \
  APPENDHISTORY \
  BANGHIST \
  extendedhistory \
  no_histallowclobber \
  no_HISTBEEP \
  histexpiredupsfirst \
  no_histfcntllock \
  histfindnodups \
  histignorealldups \
  histignoredups \
  histignorespace \
  histlexwords \
  no_histnofunctions \
  no_histnostore \
  histreduceblanks \
  HISTSAVEBYCOPY \
  histsavenodups \
  histverify \
  incappendhistory \
  incappendhistorytime \
  sharehistory

#-- Initialisation ---------------------------------------------

setopt \
  no_allexport \
  GLOBALEXPORT \
  GLOBALRCS \
  RCS

#-- Input/Output -----------------------------------------------

setopt \
  ALIASES \
  no_CLOBBER \
  no_correct \
  no_correctall \
  dvorak \
  no_FLOWCONTROL \
  no_ignoreeof \
  NO_interactivecomments \
  HASHCMDS \
  HASHDIRS \
  no_hashexecutablesonly \
  no_mailwarning \
  pathdirs \
  NO_pathscript \
  no_printeightbit \
  no_printexitvalue \
  rcquotes \
  NO_rmstarsilent \
  no_rmstarwait \
  SHORTLOOPS \
  no_sunkeyboardhack

#-- Job Control ------------------------------------------------

setopt \
  no_autocontinue \
  autoresume \
  no_BGNICE \
  CHECKJOBS \
  no_HUP \
  longlistjobs \
  MONITOR \
  NOTIFY \
  NO_posixjobs

#-- Prompting --------------------------------------------------

setopt \
  NO_promptbang \
  PROMPTCR \
  PROMPTSP \
  PROMPTPERCENT \
  promptsubst \
  transientrprompt

#-- Scripts and Functions --------------------------------------

setopt \
  NO_aliasfuncdef \
  no_cbases \
  no_cprecedences \
  DEBUGBEFORECMD \
  no_errexit \
  no_errreturn \
  EVALLINENO \
  EXEC \
  FUNCTIONARGZERO \
  no_localloops \
  NO_localoptions \
  no_localpatterns \
  NO_localtraps \
  MULTIFUNCDEF \
  MULTIOS \
  NO_octalzeroes \
  no_pipefail \
  no_sourcetrace \
  no_typesetsilent \
  no_verbose \
  no_xtrace

#-- Shell Emulation --------------------------------------------

setopt \
  NO_appendcreate \
  no_bashrematch \
  NO_bsdecho \
  no_continueonerror \
  NO_cshjunkiehistory \
  NO_cshjunkieloops \
  NO_cshjunkiequotes \
  NO_cshnullcmd \
  NO_ksharrays \
  NO_kshautoload \
  NO_kshoptionprint \
  no_kshtypeset \
  no_kshzerosubscript \
  NO_posixaliases \
  no_posixargzero \
  NO_posixbuiltins \
  NO_posixidentifiers \
  NO_posixstrings \
  NO_posixtraps \
  NO_shfileexpansion \
  NO_shnullcmd \
  NO_shoptionletters \
  NO_shwordsplit \
  no_trapsasync

#-- Zle --------------------------------------------------------

setopt \
  no_BEEP \
  combiningchars \
  no_overstrike \
  NO_singlelinezle

#-- Aliases ----------------------------------------------------

alias \
  ll="/bin/ls -aFGHhlOw"

#-- Functions --------------------------------------------------

autoload -Uz \
  add-zsh-hook \
  compaudit \
  compinit

compaudit 2> /dev/null | \
  xargs -L 1 chmod go-w 2> /dev/null

compinit -u

which nodenv > /dev/null && \
  eval "$(nodenv init - zsh)"

which plenv > /dev/null && \
  eval "$(plenv init - zsh)"

which pyenv > /dev/null && \
  eval "$(pyenv init - zsh)"

which rbenv > /dev/null && \
  eval "$(rbenv init - zsh)"

sf () {
  SetFile -P -d "$1 12:00:00" -m "$1 12:00:00" $argv[2,$]
}

ssh-add -A 2> /dev/null

#-- zsh-syntax-highlighting ------------------------------------

. "$(brew --prefix)/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh"

#-- zsh-history-substring-search -------------------------------

. "$(brew --prefix)/share/zsh-history-substring-search/zsh-history-substring-search.zsh"

HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND="fg=default,underline" && \
  export HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND
HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND="fg=red,underline" && \
  export HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND

#-- Zle --------------------------------------------------------

zmodload zsh/zle

bindkey -d
bindkey -v

for k in "vicmd" "viins"; do
  bindkey -M $k '\C-A' beginning-of-line
  bindkey -M $k '\C-E' end-of-line
  bindkey -M $k '\C-U' kill-whole-line
  bindkey -M $k '\e[3~' delete-char
  bindkey -M $k '\e[A' history-substring-search-up
  bindkey -M $k '\e[B' history-substring-search-down
  bindkey -M $k '\x7f' backward-delete-char
done

for f in \
  "zle-keymap-select" \
  "zle-line-finish" \
  "zle-line-init"
do
  eval "$f () {
    case \$TERM_PROGRAM in
      ('Apple_Terminal')
        test \$KEYMAP = 'vicmd' && \
          printf '%b' '\e[4 q' || \
          printf '%b' '\e[6 q' ;;
      ('iTerm.app')
        test \$KEYMAP = 'vicmd' && \
          printf '%b' '\e]Plf27f7f\e\x5c\e[4 q' || \
          printf '%b' '\e]Pl99cc99\e\x5c\e[6 q' ;;
    esac
  }"
  zle -N $f
done

#-- prompt_ptb_setup -------------------------------------------

prompt_ptb_setup () {
  I="$(printf '%b' '%{\e[3m%}')"
  i="$(printf '%b' '%{\e[0m%}')"
  PROMPT="%F{004}$I%d$i %(!.%F{001}.%F{002})%n %B❯%b%f " && \
  export PROMPT
}

prompt_ptb_setup

prompt_ptb_precmd () {
  if test "$(uname -s)" = "Darwin"; then
    print -Pn "\e]7;file://%M\${PWD// /%%20}\a"
    print -Pn "\e]2;%n@%m\a"
    print -Pn "\e]1;%~\a"
  fi

  test -n "$(git rev-parse --git-dir 2> /dev/null)" && \
  RPROMPT="%F{000}$(git rev-parse --abbrev-ref HEAD 2> /dev/null)%f" && \
  export RPROMPT
}

add-zsh-hook precmd \
  prompt_ptb_precmd

Configure New Account

config_new_account () {
  e="$(ask 'New macOS Account: Email Address?' 'OK' '')"
  curl --output "/Library/User Pictures/${e}.jpg" --silent \
    "https://www.gravatar.com/avatar/$(md5 -qs ${e}).jpg?s=512"

  g="$(curl --location --silent \
    "https://api.github.com/search/users?q=${e}" | \
    sed -n 's/^.*"url": "\(.*\)".*/\1/p')"
  g="$(curl --location --silent ${g})"

  n="$(printf ${g} | sed -n 's/^.*"name": "\(.*\)".*/\1/p')"
  n="$(ask 'New macOS Account: Real Name?' 'OK' ${n})"

  u="$(printf ${g} | sed -n 's/^.*"login": "\(.*\)".*/\1/p')"
  u="$(ask 'New macOS Account: User Name?' 'OK' ${u})"

  sudo defaults write \
    "/System/Library/User Template/Non_localized/Library/Preferences/.GlobalPreferences.plist" \
    "com.apple.swipescrolldirection" -bool false

  sudo sysadminctl -admin -addUser "${u}" -fullName "${n}" -password - \
    -shell "$(which zsh)" -picture "/Library/User Pictures/${e}.jpg"
}

Configure Guest Users

config_guest () {
  sudo sysadminctl -guestAccount off
}

Reinstate sudo Password

config_rm_sudoers () {
  sudo -- sh -c \
    "rm -f /etc/sudoers.d/wheel; dscl /Local/Default -delete /Groups/wheel GroupMembership $(whoami)"

  /usr/bin/read -n 1 -p "Press any key to continue.
" -s
  if run "Log Out Then Log Back In?" "Cancel" "Log Out"; then
    osascript -e 'tell app "loginwindow" to «event aevtrlgo»'
  fi
}

Customize

Define Function custom

custom () {
  custom_githome
  custom_atom
  custom_autoping
  custom_dropbox
  custom_duti
  custom_emacs
  custom_finder
  custom_getmail
  custom_git
  custom_gnupg
  custom_istatmenus
  custom_meteorologist
  custom_moom
  custom_mp4_automator
  custom_nvalt
  custom_nzbget
  custom_safari
  custom_sieve
  custom_sonarr
  custom_ssh
  custom_sysprefs
  custom_terminal
  custom_vim
  custom_vlc

  which personalize_all
}

Customize Home

custom_githome () {
  git -C "${HOME}" init

  test -f "${CACHES}/dbx/.zshenv" && \
    mkdir -p "${ZDOTDIR:-$HOME}" && \
    cp "${CACHES}/dbx/.zshenv" "${ZDOTDIR:-$HOME}" && \
    . "${ZDOTDIR:-$HOME}/.zshenv"

  a=$(ask "Existing Git Home Repository Path or URL" "Add Remote" "")
  if test -n "${a}"; then
    git -C "${HOME}" remote add origin "${a}"
    git -C "${HOME}" fetch origin master
  fi

  if run "Encrypt and commit changes to Git and push to GitHub, automatically?" "No" "Add AutoKeep"; then
    curl --location --silent \
      "https://github.com/ptb/autokeep/raw/master/autokeep.command" | \
      . /dev/stdin 0

    autokeep_remote
    autokeep_push
    autokeep_gitignore
    autokeep_post_commit
    autokeep_launchagent
    autokeep_crypt

    git reset --hard
    git checkout -f -b master FETCH_HEAD
  fi

  chmod -R go= "${HOME}" > /dev/null 2>&1
}

Customize Atom

custom_atom () {
  if which apm > /dev/null; then
    mkdir -p "${HOME}/.atom/.apm"

    cat << EOF > "${HOME}/.atom/.apmrc"
cache = ${CACHES}/apm
EOF

    cat << EOF > "${HOME}/.atom/.apm/.apmrc"
cache = ${CACHES}/apm
EOF

    printf "%s\n" "${_atom}" | \
    while IFS="$(printf '\t')" read pkg; do
      test -d "${HOME}/.atom/packages/${pkg}" ||
      apm install "${pkg}"
    done

    cat << EOF > "${HOME}/.atom/config.cson"
<<config.cson>>
EOF

    cat << EOF > "${HOME}/.atom/packages/tomorrow-night-eighties-syntax/styles/colors.less"
<<colors.less>>
EOF
  fi
}

_atom

Atom Package NameReference URL
atom-beautifyhttps://atom.io/packages/atom-beautify
atom-css-combhttps://atom.io/packages/atom-css-comb
atom-fuzzy-grephttps://atom.io/packages/atom-fuzzy-grep
atom-jadehttps://atom.io/packages/atom-jade
atom-wallabyhttps://atom.io/packages/atom-wallaby
autoclose-htmlhttps://atom.io/packages/autoclose-html
autocomplete-pythonhttps://atom.io/packages/autocomplete-python
busy-signalhttps://atom.io/packages/busy-signal
double-taghttps://atom.io/packages/double-tag
editorconfighttps://atom.io/packages/editorconfig
ex-modehttps://atom.io/packages/ex-mode
file-iconshttps://atom.io/packages/file-icons
git-plushttps://atom.io/packages/git-plus
git-time-machinehttps://atom.io/packages/git-time-machine
highlight-selectedhttps://atom.io/packages/highlight-selected
intentionshttps://atom.io/packages/intentions
language-dockerhttps://atom.io/packages/language-docker
language-jadehttps://atom.io/packages/language-jade
language-javascript-jsxhttps://atom.io/packages/language-javascript-jsx
language-lisphttps://atom.io/packages/language-lisp
language-slimhttps://atom.io/packages/language-slim
linterhttps://atom.io/packages/linter
linter-eslinthttps://atom.io/packages/linter-eslint
linter-rubocophttps://atom.io/packages/linter-rubocop
linter-shellcheckhttps://atom.io/packages/linter-shellcheck
linter-ui-defaulthttps://atom.io/packages/linter-ui-default
MagicPythonhttps://atom.io/packages/MagicPython
python-yapfhttps://atom.io/packages/python-yapf
reacthttps://atom.io/packages/react
riothttps://atom.io/packages/riot
sort-lineshttps://atom.io/packages/sort-lines
term3https://atom.io/packages/term3
tomorrow-night-eighties-syntaxhttps://atom.io/packages/tomorrow-night-eighties-syntax
tree-view-open-fileshttps://atom.io/packages/tree-view-open-files
vim-mode-plushttps://atom.io/packages/vim-mode-plus
vim-mode-zzhttps://atom.io/packages/vim-mode-zz

${HOME}/.atom/config.cson

"*":
  "autocomplete-python":
    useKite: false
  core:
    telemetryConsent: "limited"
    themes: [
      "one-dark-ui"
      "tomorrow-night-eighties-syntax"
    ]
  editor:
    fontFamily: "Inconsolata LGC"
    fontSize: 13
  welcome:
    showOnStartup: false

${HOME}/.atom/packages/tomorrow-night-eighties-syntax/styles/colors.less

@background: #222222;
@current-line: #333333;
@selection: #4c4c4c;
@foreground: #cccccc;
@comment: #999999;
@red: #f27f7f;
@orange: #ff994c;
@yellow: #ffcc66;
@green: #99cc99;
@aqua: #66cccc;
@blue: #6699cc;
@purple: #cc99cc;

Customize autoping

custom_autoping () {
  config_defaults "${_autoping}"
}

_autoping

PreferenceDomainKeyTypeValueHost
Host to Pingcom.memset.autopingHostname-stringgoogle.com
Slow Ping Threshold (ms) 100com.memset.autopingSlowPingLowThreshold-int100
Launch at Login oncom.memset.autopingLaunchAtLogin-booltrue
Display Icon and Textcom.memset.autopingShowIcon-booltrue
com.memset.autopingShowText-booltrue
Packet Loss Text oncom.memset.autopingShowPacketLossText-booltrue
Connection Up/Down Alerts oncom.memset.autopingShowNotifications-booltrue

Customize Dropbox

custom_dropbox () {
  test -d "/Applications/Dropbox.app" && \
    open "/Applications/Dropbox.app"
}

Customize Default UTIs

custom_duti () {
  if test -x "/usr/local/bin/duti"; then
    test -f "${HOME}/Library/Preferences/org.duti.plist" && \
      rm "${HOME}/Library/Preferences/org.duti.plist"

    printf "%s\n" "${_duti}" | \
    while IFS="$(printf '\t')" read id uti role; do
      defaults write org.duti DUTISettings -array-add \
        "{
          DUTIBundleIdentifier = '$a';
          DUTIUniformTypeIdentifier = '$b';
          DUTIRole = '$c';
        }"
    done

    duti "${HOME}/Library/Preferences/org.duti.plist" 2> /dev/null
  fi
}

_duti

Bundle IDUTIRole
com.apple.DiskImageMountercom.apple.disk-imageall
com.apple.DiskImageMounterpublic.disk-imageall
com.apple.DiskImageMounterpublic.iso-imageall
com.apple.QuickTimePlayerXcom.apple.coreaudio-formatall
com.apple.QuickTimePlayerXcom.apple.quicktime-movieall
com.apple.QuickTimePlayerXcom.microsoft.waveform-audioall
com.apple.QuickTimePlayerXpublic.aifc-audioall
com.apple.QuickTimePlayerXpublic.aiff-audioall
com.apple.QuickTimePlayerXpublic.audioall
com.apple.QuickTimePlayerXpublic.mp3all
com.apple.Safaricom.compuserve.gifall
com.apple.Terminalcom.apple.terminal.shell-scriptall
com.apple.iTunescom.apple.iTunes.audibleall
com.apple.iTunescom.apple.iTunes.ipgall
com.apple.iTunescom.apple.iTunes.ipswall
com.apple.iTunescom.apple.iTunes.iteall
com.apple.iTunescom.apple.iTunes.itlpall
com.apple.iTunescom.apple.iTunes.itmsall
com.apple.iTunescom.apple.iTunes.podcastall
com.apple.iTunescom.apple.m4a-audioall
com.apple.iTunescom.apple.mpeg-4-ringtoneall
com.apple.iTunescom.apple.protected-mpeg-4-audioall
com.apple.iTunescom.apple.protected-mpeg-4-videoall
com.apple.iTunescom.audible.aa-audioall
com.apple.iTunespublic.mpeg-4-audioall
com.apple.installercom.apple.installer-package-archiveall
com.github.atomcom.apple.binary-property-listeditor
com.github.atomcom.apple.crashreporteditor
com.github.atomcom.apple.dt.document.ascii-property-listeditor
com.github.atomcom.apple.dt.document.script-suite-property-listeditor
com.github.atomcom.apple.dt.document.script-terminology-property-listeditor
com.github.atomcom.apple.logeditor
com.github.atomcom.apple.property-listeditor
com.github.atomcom.apple.rez-sourceeditor
com.github.atomcom.apple.symbol-exporteditor
com.github.atomcom.apple.xcode.ada-sourceeditor
com.github.atomcom.apple.xcode.bash-scripteditor
com.github.atomcom.apple.xcode.configsettingseditor
com.github.atomcom.apple.xcode.csh-scripteditor
com.github.atomcom.apple.xcode.fortran-sourceeditor
com.github.atomcom.apple.xcode.ksh-scripteditor
com.github.atomcom.apple.xcode.lex-sourceeditor
com.github.atomcom.apple.xcode.make-scripteditor
com.github.atomcom.apple.xcode.mig-sourceeditor
com.github.atomcom.apple.xcode.pascal-sourceeditor
com.github.atomcom.apple.xcode.strings-texteditor
com.github.atomcom.apple.xcode.tcsh-scripteditor
com.github.atomcom.apple.xcode.yacc-sourceeditor
com.github.atomcom.apple.xcode.zsh-scripteditor
com.github.atomcom.apple.xml-property-listeditor
com.github.atomcom.barebones.bbedit.actionscript-sourceeditor
com.github.atomcom.barebones.bbedit.erb-sourceeditor
com.github.atomcom.barebones.bbedit.ini-configurationeditor
com.github.atomcom.barebones.bbedit.javascript-sourceeditor
com.github.atomcom.barebones.bbedit.json-sourceeditor
com.github.atomcom.barebones.bbedit.jsp-sourceeditor
com.github.atomcom.barebones.bbedit.lasso-sourceeditor
com.github.atomcom.barebones.bbedit.lua-sourceeditor
com.github.atomcom.barebones.bbedit.setext-sourceeditor
com.github.atomcom.barebones.bbedit.sql-sourceeditor
com.github.atomcom.barebones.bbedit.tcl-sourceeditor
com.github.atomcom.barebones.bbedit.tex-sourceeditor
com.github.atomcom.barebones.bbedit.textile-sourceeditor
com.github.atomcom.barebones.bbedit.vbscript-sourceeditor
com.github.atomcom.barebones.bbedit.vectorscript-sourceeditor
com.github.atomcom.barebones.bbedit.verilog-hdl-sourceeditor
com.github.atomcom.barebones.bbedit.vhdl-sourceeditor
com.github.atomcom.barebones.bbedit.yaml-sourceeditor
com.github.atomcom.netscape.javascript-sourceeditor
com.github.atomcom.sun.java-sourceeditor
com.github.atomdyn.ah62d4rv4ge80255drqall
com.github.atomdyn.ah62d4rv4ge80g55gq3w0nall
com.github.atomdyn.ah62d4rv4ge80g55sq2all
com.github.atomdyn.ah62d4rv4ge80y2xzrf0gk3pwall
com.github.atomdyn.ah62d4rv4ge81e3dtqqall
com.github.atomdyn.ah62d4rv4ge81e7kall
com.github.atomdyn.ah62d4rv4ge81g25xsqall
com.github.atomdyn.ah62d4rv4ge81g2pxsqall
com.github.atomnet.daringfireball.markdowneditor
com.github.atompublic.assembly-sourceeditor
com.github.atompublic.c-headereditor
com.github.atompublic.c-plus-plus-sourceeditor
com.github.atompublic.c-sourceeditor
com.github.atompublic.csh-scripteditor
com.github.atompublic.jsoneditor
com.github.atompublic.lex-sourceeditor
com.github.atompublic.logeditor
com.github.atompublic.mig-sourceeditor
com.github.atompublic.nasm-assembly-sourceeditor
com.github.atompublic.objective-c-plus-plus-sourceeditor
com.github.atompublic.objective-c-sourceeditor
com.github.atompublic.patch-fileeditor
com.github.atompublic.perl-scripteditor
com.github.atompublic.php-scripteditor
com.github.atompublic.plain-texteditor
com.github.atompublic.precompiled-c-headereditor
com.github.atompublic.precompiled-c-plus-plus-headereditor
com.github.atompublic.python-scripteditor
com.github.atompublic.ruby-scripteditor
com.github.atompublic.scripteditor
com.github.atompublic.shell-scripteditor
com.github.atompublic.source-codeeditor
com.github.atompublic.texteditor
com.github.atompublic.utf16-external-plain-texteditor
com.github.atompublic.utf16-plain-texteditor
com.github.atompublic.utf8-plain-texteditor
com.github.atompublic.xmleditor
com.kodlian.Icon-Slatecom.apple.icnsall
com.kodlian.Icon-Slatecom.microsoft.icoall
com.microsoft.Wordpublic.rtfall
com.panayotis.jublerdyn.ah62d4rv4ge81g6xyall
com.sketchup.SketchUp.2017com.sketchup.skpall
com.VortexApps.NZBVortex3dyn.ah62d4rv4ge8068xcall
com.vmware.fusioncom.microsoft.windows-executableall
cx.c3.theunarchivercom.alcohol-soft.mdf-imageall
cx.c3.theunarchivercom.allume.stuffit-archiveall
cx.c3.theunarchivercom.altools.alz-archiveall
cx.c3.theunarchivercom.amiga.adf-archiveall
cx.c3.theunarchivercom.amiga.adz-archiveall
cx.c3.theunarchivercom.apple.applesingle-archiveall
cx.c3.theunarchivercom.apple.binhex-archiveall
cx.c3.theunarchivercom.apple.bom-compressed-cpioall
cx.c3.theunarchivercom.apple.itunes.ipaall
cx.c3.theunarchivercom.apple.macbinary-archiveall
cx.c3.theunarchivercom.apple.self-extracting-archiveall
cx.c3.theunarchivercom.apple.xar-archiveall
cx.c3.theunarchivercom.apple.xip-archiveall
cx.c3.theunarchivercom.cyclos.cpt-archiveall
cx.c3.theunarchivercom.microsoft.cab-archiveall
cx.c3.theunarchivercom.microsoft.msi-installerall
cx.c3.theunarchivercom.nero.nrg-imageall
cx.c3.theunarchivercom.network172.pit-archiveall
cx.c3.theunarchivercom.nowsoftware.now-archiveall
cx.c3.theunarchivercom.nscripter.nsa-archiveall
cx.c3.theunarchivercom.padus.cdi-imageall
cx.c3.theunarchivercom.pkware.zip-archiveall
cx.c3.theunarchivercom.rarlab.rar-archiveall
cx.c3.theunarchivercom.redhat.rpm-archiveall
cx.c3.theunarchivercom.stuffit.archive.sitall
cx.c3.theunarchivercom.stuffit.archive.sitxall
cx.c3.theunarchivercom.sun.java-archiveall
cx.c3.theunarchivercom.symantec.dd-archiveall
cx.c3.theunarchivercom.winace.ace-archiveall
cx.c3.theunarchivercom.winzip.zipx-archiveall
cx.c3.theunarchivercx.c3.arc-archiveall
cx.c3.theunarchivercx.c3.arj-archiveall
cx.c3.theunarchivercx.c3.dcs-archiveall
cx.c3.theunarchivercx.c3.dms-archiveall
cx.c3.theunarchivercx.c3.ha-archiveall
cx.c3.theunarchivercx.c3.lbr-archiveall
cx.c3.theunarchivercx.c3.lha-archiveall
cx.c3.theunarchivercx.c3.lhf-archiveall
cx.c3.theunarchivercx.c3.lzx-archiveall
cx.c3.theunarchivercx.c3.packdev-archiveall
cx.c3.theunarchivercx.c3.pax-archiveall
cx.c3.theunarchivercx.c3.pma-archiveall
cx.c3.theunarchivercx.c3.pp-archiveall
cx.c3.theunarchivercx.c3.xmash-archiveall
cx.c3.theunarchivercx.c3.zoo-archiveall
cx.c3.theunarchivercx.c3.zoom-archiveall
cx.c3.theunarchiverorg.7-zip.7-zip-archiveall
cx.c3.theunarchiverorg.archive.warc-archiveall
cx.c3.theunarchiverorg.debian.deb-archiveall
cx.c3.theunarchiverorg.gnu.gnu-tar-archiveall
cx.c3.theunarchiverorg.gnu.gnu-zip-archiveall
cx.c3.theunarchiverorg.gnu.gnu-zip-tar-archiveall
cx.c3.theunarchiverorg.tukaani.lzma-archiveall
cx.c3.theunarchiverorg.tukaani.xz-archiveall
cx.c3.theunarchiverpublic.bzip2-archiveall
cx.c3.theunarchiverpublic.cpio-archiveall
cx.c3.theunarchiverpublic.tar-archiveall
cx.c3.theunarchiverpublic.tar-bzip2-archiveall
cx.c3.theunarchiverpublic.z-archiveall
cx.c3.theunarchiverpublic.zip-archiveall
cx.c3.theunarchiverpublic.zip-archive.first-partall
org.gnu.Emacsdyn.ah62d4rv4ge8086xhall
org.inkscape.Inkscapepublic.svg-imageeditor
org.videolan.vlccom.apple.m4v-videoall
org.videolan.vlccom.microsoft.windows-media-wmvall
org.videolan.vlcorg.videolan.3gpall
org.videolan.vlcorg.videolan.aacall
org.videolan.vlcorg.videolan.ac3all
org.videolan.vlcorg.videolan.aiffall
org.videolan.vlcorg.videolan.amrall
org.videolan.vlcorg.videolan.aoball
org.videolan.vlcorg.videolan.apeall
org.videolan.vlcorg.videolan.asfall
org.videolan.vlcorg.videolan.aviall
org.videolan.vlcorg.videolan.axaall
org.videolan.vlcorg.videolan.axvall
org.videolan.vlcorg.videolan.divxall
org.videolan.vlcorg.videolan.dtsall
org.videolan.vlcorg.videolan.dvall
org.videolan.vlcorg.videolan.flacall
org.videolan.vlcorg.videolan.flashall
org.videolan.vlcorg.videolan.gxfall
org.videolan.vlcorg.videolan.itall
org.videolan.vlcorg.videolan.midall
org.videolan.vlcorg.videolan.mkaall
org.videolan.vlcorg.videolan.mkvall
org.videolan.vlcorg.videolan.mlpall
org.videolan.vlcorg.videolan.modall
org.videolan.vlcorg.videolan.mpcall
org.videolan.vlcorg.videolan.mpeg-audioall
org.videolan.vlcorg.videolan.mpeg-streamall
org.videolan.vlcorg.videolan.mpeg-videoall
org.videolan.vlcorg.videolan.mxfall
org.videolan.vlcorg.videolan.nsvall
org.videolan.vlcorg.videolan.nuvall
org.videolan.vlcorg.videolan.ogg-audioall
org.videolan.vlcorg.videolan.ogg-videoall
org.videolan.vlcorg.videolan.omaall
org.videolan.vlcorg.videolan.opusall
org.videolan.vlcorg.videolan.quicktimeall
org.videolan.vlcorg.videolan.realmediaall
org.videolan.vlcorg.videolan.recall
org.videolan.vlcorg.videolan.rmiall
org.videolan.vlcorg.videolan.s3mall
org.videolan.vlcorg.videolan.spxall
org.videolan.vlcorg.videolan.todall
org.videolan.vlcorg.videolan.ttaall
org.videolan.vlcorg.videolan.voball
org.videolan.vlcorg.videolan.vocall
org.videolan.vlcorg.videolan.vqfall
org.videolan.vlcorg.videolan.vroall
org.videolan.vlcorg.videolan.wavall
org.videolan.vlcorg.videolan.webmall
org.videolan.vlcorg.videolan.wmaall
org.videolan.vlcorg.videolan.wmvall
org.videolan.vlcorg.videolan.wtvall
org.videolan.vlcorg.videolan.wvall
org.videolan.vlcorg.videolan.xaall
org.videolan.vlcorg.videolan.xescall
org.videolan.vlcorg.videolan.xmall
org.videolan.vlcpublic.ac3-audioall
org.videolan.vlcpublic.audiovisual-contentall
org.videolan.vlcpublic.aviall
org.videolan.vlcpublic.movieall
org.videolan.vlcpublic.mpegall
org.videolan.vlcpublic.mpeg-2-videoall
org.videolan.vlcpublic.mpeg-4all

Customize Emacs

custom_emacs () {
  mkdir -p "${HOME}/.emacs.d" && \
  curl --compressed --location --silent \
    "https://github.com/syl20bnr/spacemacs/archive/master.tar.gz" | \
  tar -C "${HOME}/.emacs.d" --strip-components 1 -xf -
  mkdir -p "${HOME}/.emacs.d/private/ptb"
  chmod -R go= "${HOME}/.emacs.d"

  cat << EOF > "${HOME}/.spacemacs"
<<.spacemacs>>
EOF

  cat << EOF > "${HOME}/.emacs.d/private/ptb/config.el"
<<config.el>>
EOF

  cat << EOF > "${HOME}/.emacs.d/private/ptb/funcs.el"
<<funcs.el>>
EOF

  cat << EOF > "${HOME}/.emacs.d/private/ptb/keybindings.el"
<<keybindings.el>>
EOF

  cat << EOF > "${HOME}/.emacs.d/private/ptb/packages.el"
<<packages.el>>
EOF
}

~/.spacemacs

(defun dotspacemacs/layers ()
  (setq-default
    dotspacemacs-configuration-layers '(
      auto-completion
      (colors :variables
        colors-colorize-identifiers 'variables)
      dash
      deft
      docker
      emacs-lisp
      evil-cleverparens
      git
      github
      helm
      html
      ibuffer
      imenu-list
      javascript
      markdown
      nginx
      (org :variables
        org-enable-github-support t)
      (osx :variables
        osx-use-option-as-meta nil)
      ptb
      react
      ruby
      ruby-on-rails
      search-engine
      semantic
      shell-scripts
      (spell-checking :variables
        spell-checking-enable-by-default nil)
      syntax-checking
      (version-control :variables
        version-control-diff-side 'left)
      vim-empty-lines
    )
    dotspacemacs-excluded-packages '(org-bullets)
  )
)

(defun dotspacemacs/init ()
  (setq-default
    dotspacemacs-startup-banner nil
    dotspacemacs-startup-lists nil
    dotspacemacs-scratch-mode 'org-mode
    dotspacemacs-themes '(sanityinc-tomorrow-eighties)
    dotspacemacs-default-font '(
      "Inconsolata LGC"
      :size 13
      :weight normal
      :width normal
      :powerline-scale 1.1)
    dotspacemacs-loading-progress-bar nil
    dotspacemacs-active-transparency 100
    dotspacemacs-inactive-transparency 100
    dotspacemacs-line-numbers t
    dotspacemacs-whitespace-cleanup 'all
  )
)

(defun dotspacemacs/user-init ())
(defun dotspacemacs/user-config ())

~/.emacs.d/private/ptb/config.el

(setq
  default-frame-alist '(
    (top . 22)
    (left . 1201)
    (height . 50)
    (width . 120)
    (vertical-scroll-bars . right))
  initial-frame-alist (copy-alist default-frame-alist)

  deft-directory "~/Dropbox/Notes"
  focus-follows-mouse t
  mouse-wheel-follow-mouse t
  mouse-wheel-scroll-amount '(1 ((shift) . 1))
  org-src-preserve-indentation t
  purpose-display-at-right 20
  recentf-max-saved-items 5
  scroll-step 1
  system-uses-terminfo nil

  ibuffer-formats '(
    (mark modified read-only " "
    (name 18 18 :left :elide)))

  ibuffer-shrink-to-minimum-size t
  ibuffer-always-show-last-buffer nil
  ibuffer-sorting-mode 'recency
  ibuffer-use-header-line nil
  x-select-enable-clipboard nil)

(global-linum-mode t)
(recentf-mode t)
(x-focus-frame nil)
(with-eval-after-load 'org
  (org-babel-do-load-languages
    'org-babel-load-languages '(
      (ruby . t)
      (shell . t)
    )
  )
)

~/.emacs.d/private/ptb/funcs.el

(defun is-useless-buffer (buffer)
  (let ((name (buffer-name buffer)))
    (and (= ?* (aref name 0))
        (string-match "^\\**" name))))

(defun kill-useless-buffers ()
  (interactive)
  (loop for buffer being the buffers
        do (and (is-useless-buffer buffer) (kill-buffer buffer))))

(defun org-babel-tangle-hook ()
  (add-hook 'after-save-hook 'org-babel-tangle))

(add-hook 'org-mode-hook #'org-babel-tangle-hook)

(defun ptb/new-untitled-buffer ()
  "Create a new untitled buffer in the current frame."
  (interactive)
  (let
    ((buffer "Untitled-") (count 1))
    (while
      (get-buffer (concat buffer (number-to-string count)))
      (setq count (1+ count)))
    (switch-to-buffer
    (concat buffer (number-to-string count))))
  (org-mode))

(defun ptb/previous-buffer ()
  (interactive)
  (kill-useless-buffers)
  (previous-buffer))

(defun ptb/next-buffer ()
  (interactive)
  (kill-useless-buffers)
  (next-buffer))

(defun ptb/kill-current-buffer ()
  (interactive)
  (kill-buffer (current-buffer))
  (kill-useless-buffers))

~/.emacs.d/private/ptb/keybindings.el

(define-key evil-insert-state-map (kbd "<return>") 'newline)

(define-key evil-normal-state-map (kbd "s-c") 'clipboard-kill-ring-save)
(define-key evil-insert-state-map (kbd "s-c") 'clipboard-kill-ring-save)
(define-key evil-visual-state-map (kbd "s-c") 'clipboard-kill-ring-save)

(define-key evil-ex-completion-map (kbd "s-v") 'clipboard-yank)
(define-key evil-ex-search-keymap (kbd "s-v") 'clipboard-yank)
(define-key evil-insert-state-map (kbd "s-v") 'clipboard-yank)

(define-key evil-normal-state-map (kbd "s-x") 'clipboard-kill-region)
(define-key evil-insert-state-map (kbd "s-x") 'clipboard-kill-region)
(define-key evil-visual-state-map (kbd "s-x") 'clipboard-kill-region)

(define-key evil-normal-state-map (kbd "<S-up>") 'evil-previous-visual-line)
(define-key evil-insert-state-map (kbd "<S-up>") 'evil-previous-visual-line)
(define-key evil-visual-state-map (kbd "<S-up>") 'evil-previous-visual-line)

(define-key evil-normal-state-map (kbd "<S-down>") 'evil-next-visual-line)
(define-key evil-insert-state-map (kbd "<S-down>") 'evil-next-visual-line)
(define-key evil-visual-state-map (kbd "<S-down>") 'evil-next-visual-line)

(global-set-key (kbd "C-l") 'evil-search-highlight-persist-remove-all)

(global-set-key (kbd "s-t") 'make-frame)
(global-set-key (kbd "s-n") 'ptb/new-untitled-buffer)
(global-set-key (kbd "s-w") 'ptb/kill-current-buffer)
(global-set-key (kbd "s-{") 'ptb/previous-buffer)
(global-set-key (kbd "s-}") 'ptb/next-buffer)

~/.emacs.d/private/ptb/packages.el

(setq ptb-packages '(adaptive-wrap auto-indent-mode))

(defun ptb/init-adaptive-wrap ()
  "Load the adaptive wrap package"
  (use-package adaptive-wrap
    :init
    (setq adaptive-wrap-extra-indent 2)
    :config
    (progn
      ;; http://stackoverflow.com/questions/13559061
      (when (fboundp 'adaptive-wrap-prefix-mode)
        (defun ptb/activate-adaptive-wrap-prefix-mode ()
          "Toggle 'visual-line-mode' and 'adaptive-wrap-prefix-mode' simultaneously."
          (adaptive-wrap-prefix-mode (if visual-line-mode 1 -1)))
        (add-hook 'visual-line-mode-hook 'ptb/activate-adaptive-wrap-prefix-mode)))))

(defun ptb/init-auto-indent-mode ()
  (use-package auto-indent-mode
    :init
    (setq
      auto-indent-delete-backward-char t
      auto-indent-fix-org-auto-fill t
      auto-indent-fix-org-move-beginning-of-line t
      auto-indent-fix-org-return t
      auto-indent-fix-org-yank t
      auto-indent-start-org-indent t
    )
  )
)

Customize Finder

custom_finder () {
  config_defaults "${_finder}"
  defaults write "com.apple.finder" "NSToolbar Configuration Browser" \
    '{
      "TB Display Mode" = 2;
      "TB Item Identifiers" = (
        "com.apple.finder.BACK",
        "com.apple.finder.PATH",
        "com.apple.finder.SWCH",
        "com.apple.finder.ARNG",
        "NSToolbarFlexibleSpaceItem",
        "com.apple.finder.SRCH",
        "com.apple.finder.ACTN"
      );
    }'
}

_finder

PreferenceDomainKeyTypeValueHost
Show these items on the desktop: off Hard diskscom.apple.finderShowHardDrivesOnDesktop-boolfalse
Show these items on the desktop: off External diskscom.apple.finderShowExternalHardDrivesOnDesktop-boolfalse
Show these items on the desktop: on CDs, DVDs, and iPodscom.apple.finderShowRemovableMediaOnDesktop-booltrue
Show these items on the desktop: on Connected servers:com.apple.finderShowMountedServersOnDesktop-booltrue
New Finder windows show: ${HOME}com.apple.finderNewWindowTarget-stringPfLo
com.apple.finderNewWindowTargetPath-stringfile://${HOME}/Dropbox/
on Show all filename extensions-globalDomainAppleShowAllExtensions-booltrue
off Show warning before changing an extensioncom.apple.finderFXEnableExtensionChangeWarning-boolfalse
on Show warning before removing from iCloud Drivecom.apple.finderFXEnableRemoveFromICloudDriveWarning-booltrue
off Show warning before emptying the Trashcom.apple.finderWarnOnEmptyTrash-boolfalse
ViewShow Path Barcom.apple.finderShowPathbar-booltrue
ViewShow Status Barcom.apple.finderShowStatusBar-booltrue

Customize getmail

custom_getmail () {
  test -d "${HOME}/.getmail" || \
    mkdir -m go= "${HOME}/.getmail"

  while true; do
    e=$(ask2 "To configure getmail, enter your email address." "Configure Getmail" "No More Addresses" "Create Configuration" "$(whoami)@$(hostname -f | cut -d. -f2-)" "false")
    test -n "$e" || break

    security find-internet-password -a "$e" -D "getmail password" > /dev/null || \
    p=$(ask2 "Enter your password for $e." "Configure Getmail" "Cancel" "Set Password" "" "true") && \
    security add-internet-password -a "$e" -s "imap.gmail.com" -r "imap" \
      -l "$e" -D "getmail password" -P 993 -w "$p"

    if which crudini > /dev/null; then
      gm="${HOME}/.getmail/${e}"
      printf "%s\n" "${_getmail_ini}" | \
      while IFS="$(printf '\t')" read section key value; do
        crudini --set "$gm" "$section" "$key" "$value"
      done
      crudini --set "$gm" "destination" "arguments" "('-c','/usr/local/etc/dovecot/dovecot.conf','-d','$(whoami)')"
      crudini --set "$gm" "destination" "path" "$(find '/usr/local/Cellar/dovecot' -name 'dovecot-lda' -print -quit)"
      crudini --set "$gm" "retriever" "username" "$e"
    fi

    la="${HOME}/Library/LaunchAgents/ca.pyropus.getmail.${e}"

    test -d "$(dirname $la)" || \
      mkdir -p "$(dirname $la)"
    launchctl unload "${la}.plist" 2> /dev/null
    rm -f "${la}.plist"

    config_plist "$_getmail_plist" "${la}.plist"
    config_defaults "$(printf "${la}\tLabel\t-string\tca.pyropus.getmail.${e}\t")"
    config_defaults "$(printf "${la}\tProgramArguments\t-array-add\t${e}\t")"
    config_defaults "$(printf "${la}\tWorkingDirectory\t-string\t${HOME}/.getmail\t")"

    plutil -convert xml1 "${la}.plist"
    launchctl load "${la}.plist" 2> /dev/null
  done
}

_getmail_ini

SectionKeyValue
destinationignore_stderrtrue
destinationtypeMDA_external
optionsdeletetrue
optionsdelivered_tofalse
optionsread_allfalse
optionsreceivedfalse
optionsverbose0
retrievermailboxes(“[Gmail]/All Mail”,)
retrievermove_on_delete“[Gmail]/Trash”
retrieverport993
retrieverserverimap.gmail.com
retrievertypeSimpleIMAPSSLRetriever

_getmail_plist

CommandEntryTypeValue
add:KeepAlivebooltrue
add:ProcessTypestringBackground
add:ProgramArgumentsarray
add:ProgramArguments:0string/usr/local/bin/getmail
add:ProgramArguments:1string–idle
add:ProgramArguments:2string[Gmail]/All Mail
add:ProgramArguments:3string–rcfile
add:RunAtLoadbooltrue
add:StandardOutPathstringgetmail.log
add:StandardErrorPathstringgetmail.err

Customize Git

custom_git () {
  if ! test -e "${HOME}/.gitconfig"; then
    true
  fi
}

Customize GnuPG

custom_gnupg () {
  if ! test -d "${HOME}/.gnupg"; then
    true
  fi
}

Customize iStat Menus

custom_istatmenus () {
  defaults delete com.bjango.istatmenus5.extras Time_MenubarFormat > /dev/null 2>&1
  defaults delete com.bjango.istatmenus5.extras Time_DropdownFormat > /dev/null 2>&1
  defaults delete com.bjango.istatmenus5.extras Time_Cities > /dev/null 2>&1
  config_defaults "${_istatmenus}"
}

_istatmenus

PreferenceDomainKeyTypeValueHost
com.bjango.istatmenus5.extrasMenubarSkinColor-int8
com.bjango.istatmenus5.extrasMenubarTheme-int0
com.bjango.istatmenus5.extrasDropdownTheme-int1
com.bjango.istatmenus5.extrasCPU_MenubarMode-string100,2,0
com.bjango.istatmenus5.extrasCPU_MenubarTextSize-int14
com.bjango.istatmenus5.extrasCPU_MenubarGraphShowBackground-int0
com.bjango.istatmenus5.extrasCPU_MenubarGraphWidth-int32
com.bjango.istatmenus5.extrasCPU_MenubarGraphBreakdowns-int0
com.bjango.istatmenus5.extrasCPU_MenubarGraphCustomColors-int0
com.bjango.istatmenus5.extrasCPU_MenubarGraphOverall-string0.40 0.60 0.40 1.00
com.bjango.istatmenus5.extrasCPU_MenubarCombineCores-int1
com.bjango.istatmenus5.extrasCPU_MenubarGroupItems-int0
com.bjango.istatmenus5.extrasCPU_MenubarSingleHistoryGraph-int0
com.bjango.istatmenus5.extrasCPU_CombineLogicalCores-int1
com.bjango.istatmenus5.extrasCPU_AppFormat-int0
com.bjango.istatmenus5.extrasMemory_MenubarMode-string100,2,6
com.bjango.istatmenus5.extrasMemory_MenubarPercentageSize-int14
com.bjango.istatmenus5.extrasMemory_MenubarGraphBreakdowns-int1
com.bjango.istatmenus5.extrasMemory_MenubarGraphCustomColors-int0
com.bjango.istatmenus5.extrasMemory_MenubarGraphOverall-string0.40 0.60 0.40 1.00
com.bjango.istatmenus5.extrasMemory_MenubarGraphWired-string0.40 0.60 0.40 1.00
com.bjango.istatmenus5.extrasMemory_MenubarGraphActive-string0.47 0.67 0.47 1.00
com.bjango.istatmenus5.extrasMemory_MenubarGraphCompressed-string0.53 0.73 0.53 1.00
com.bjango.istatmenus5.extrasMemory_MenubarGraphInactive-string0.60 0.80 0.60 1.00
com.bjango.istatmenus5.extrasMemory_IgnoreInactive-int0
com.bjango.istatmenus5.extrasMemory_AppFormat-int0
com.bjango.istatmenus5.extrasMemory_DisplayFormat-int1
com.bjango.istatmenus5.extrasDisks_MenubarMode-string100,9,8
com.bjango.istatmenus5.extrasDisks_MenubarGroupItems-int1
com.bjango.istatmenus5.extrasDisks_MenubarRWShowLabel-int1
com.bjango.istatmenus5.extrasDisks_MenubarRWBold-int0
com.bjango.istatmenus5.extrasDisks_MenubarGraphActivityWidth-int32
com.bjango.istatmenus5.extrasDisks_MenubarGraphActivityShowBackground-int0
com.bjango.istatmenus5.extrasDisks_MenubarGraphActivityCustomColors-int0
com.bjango.istatmenus5.extrasDisks_MenubarGraphActivityRead-string0.60 0.80 0.60 1.00
com.bjango.istatmenus5.extrasDisks_MenubarGraphActivityWrite-string0.40 0.60 0.40 1.00
com.bjango.istatmenus5.extrasDisks_SeperateFusion-int1
com.bjango.istatmenus5.extrasNetwork_MenubarMode-string4,0,1
com.bjango.istatmenus5.extrasNetwork_TextUploadColor-Dark-string1.00 1.00 1.00 1.00
com.bjango.istatmenus5.extrasNetwork_TextDownloadColor-Dark-string1.00 1.00 1.00 1.00
com.bjango.istatmenus5.extrasNetwork_GraphWidth-int32
com.bjango.istatmenus5.extrasNetwork_GraphShowBackground-int0
com.bjango.istatmenus5.extrasNetwork_GraphCustomColors-int0
com.bjango.istatmenus5.extrasNetwork_GraphUpload-string0.60 0.80 0.60 1.00
com.bjango.istatmenus5.extrasNetwork_GraphDownload-string0.40 0.60 0.40 1.00
com.bjango.istatmenus5.extrasNetwork_GraphMode-int1
com.bjango.istatmenus5.extrasBattery_MenubarMode-string5,0
com.bjango.istatmenus5.extrasBattery_ColorGraphCustomColors-int1
com.bjango.istatmenus5.extrasBattery_ColorGraphCharged-string0.40 0.60 0.40 1.00
com.bjango.istatmenus5.extrasBattery_ColorGraphCharging-string0.60 0.80 0.60 1.00
com.bjango.istatmenus5.extrasBattery_ColorGraphDraining-string1.00 0.60 0.60 1.00
com.bjango.istatmenus5.extrasBattery_ColorGraphLow-string1.00 0.20 0.20 1.00
com.bjango.istatmenus5.extrasBattery_PercentageSize-int14
com.bjango.istatmenus5.extrasBattery_MenubarCustomizeStates-int0
com.bjango.istatmenus5.extrasBattery_MenubarHideBluetooth-int1
com.bjango.istatmenus5.extrasTime_MenubarFormat-array-addEE
com.bjango.istatmenus5.extrasTime_MenubarFormat-array-add\040
com.bjango.istatmenus5.extrasTime_MenubarFormat-array-addMMM
com.bjango.istatmenus5.extrasTime_MenubarFormat-array-add\040
com.bjango.istatmenus5.extrasTime_MenubarFormat-array-addd
com.bjango.istatmenus5.extrasTime_MenubarFormat-array-add\040
com.bjango.istatmenus5.extrasTime_MenubarFormat-array-addh
com.bjango.istatmenus5.extrasTime_MenubarFormat-array-add:
com.bjango.istatmenus5.extrasTime_MenubarFormat-array-addmm
com.bjango.istatmenus5.extrasTime_MenubarFormat-array-add:
com.bjango.istatmenus5.extrasTime_MenubarFormat-array-addss
com.bjango.istatmenus5.extrasTime_MenubarFormat-array-add\040
com.bjango.istatmenus5.extrasTime_MenubarFormat-array-adda
com.bjango.istatmenus5.extrasTime_DropdownFormat-array-addEE
com.bjango.istatmenus5.extrasTime_DropdownFormat-array-add\040
com.bjango.istatmenus5.extrasTime_DropdownFormat-array-addh
com.bjango.istatmenus5.extrasTime_DropdownFormat-array-add:
com.bjango.istatmenus5.extrasTime_DropdownFormat-array-addmm
com.bjango.istatmenus5.extrasTime_DropdownFormat-array-add\040
com.bjango.istatmenus5.extrasTime_DropdownFormat-array-adda
com.bjango.istatmenus5.extrasTime_DropdownFormat-array-add\040\050
com.bjango.istatmenus5.extrasTime_DropdownFormat-array-addzzz
com.bjango.istatmenus5.extrasTime_DropdownFormat-array-add\051
com.bjango.istatmenus5.extrasTime_Cities-array-add4930956
com.bjango.istatmenus5.extrasTime_Cities-array-add4887398
com.bjango.istatmenus5.extrasTime_Cities-array-add5419384
com.bjango.istatmenus5.extrasTime_Cities-array-add5392171
com.bjango.istatmenus5.extrasTime_Cities-array-add5879400
com.bjango.istatmenus5.extrasTime_Cities-array-add5856195
com.bjango.istatmenus5.extrasTime_TextSize-int14

Customize Meteorologist

custom_meteorologist () {
  config_defaults "${_meteorologist}"
}

_meteorologist

PreferenceDomainKeyTypeValueHost
com.heat.meteorologistcontrolsInSubmenu-string0
com.heat.meteorologistcurrentWeatherInSubmenu-string0
com.heat.meteorologistdisplayCityName-string0
com.heat.meteorologistdisplayHumidity-string0
com.heat.meteorologistdisplayWeatherIcon-string1
com.heat.meteorologistextendedForecastIcons-string1
com.heat.meteorologistextendedForecastInSubmenu-string0
com.heat.meteorologistextendedForecastSingleLine-string1
com.heat.meteorologistforecastDays-int8
com.heat.meteorologistviewExtendedForecast-string1
com.heat.meteorologistweatherSource_1-int3

Customize Moom

custom_moom () {
  killall Moom > /dev/null 2>&1
  defaults delete com.manytricks.Moom "Custom Controls" > /dev/null 2>&1
  config_defaults "${_moom}"
  test -d "/Applications/Moom.app" && \
    open "/Applications/Moom.app"
}

_moom

PreferenceDomainKeyTypeValueHost
on Treat drawers as part of their parent windowscom.manytricks.MoomAllow For Drawers-booltrue
on Separate windows by 2 ptcom.manytricks.MoomGrid Spacing-booltrue
com.manytricks.MoomGrid Spacing: Gap-int2
off Apply to screen edgescom.manytricks.MoomGrid Spacing: Apply To Edges-boolfalse
Grid/keyboard control highlight: 25%com.manytricks.MoomTarget Window Highlight-float0.25
off Show preferences on launchcom.manytricks.MoomStealth Mode-booltrue
Run as faceless applicationcom.manytricks.MoomApplication Mode-int2
on Pop up controls when hovering over a Zoom buttoncom.manytricks.MoomMouse Controls-booltrue
Delay: 0.1 secondcom.manytricks.MoomMouse Controls Delay-float0.1
on Enable hexagon grid with 16 × 9 cellscom.manytricks.MoomMouse Controls Grid-booltrue
com.manytricks.MoomMouse Controls Grid: Mode-int3
com.manytricks.MoomMouse Controls Grid: Columns-int16
com.manytricks.MoomMouse Controls Grid: Rows-int9
on Enable access to custom controlscom.manytricks.MoomMouse Controls Include Custom Controls-booltrue
off Show on hovercom.manytricks.MoomMouse Controls Include Custom Controls: Show On Hover-boolfalse
on Bring moomed windows to the front automaticallycom.manytricks.MoomMouse Controls Auto-Activate Window-booltrue
off Move & Zoom when dragging a window to a display edge or cornercom.manytricks.MoomSnap-boolfalse
Move & Zoomcom.manytricks.MoomCustom Controls-array-add{ Action = 19; “Relative Frame” = “{{0, 0.5}, {0.375, 0.5}}”; }
com.manytricks.MoomCustom Controls-array-add{ Action = 19; “Relative Frame” = “{{0, 0}, {0.375, 0.5}}”; }
com.manytricks.MoomCustom Controls-array-add{ Action = 19; “Relative Frame” = “{{0, 0}, {0.375, 1}}”; }
com.manytricks.MoomCustom Controls-array-add{ Action = 19; “Relative Frame” = “{{0.125, 0}, {0.25, 0.33333}}”; }
com.manytricks.MoomCustom Controls-array-add{ Action = 19; “Relative Frame” = “{{0.375, 0.33333}, {0.3125, 0.66666}}”; }
com.manytricks.MoomCustom Controls-array-add{ Action = 19; “Relative Frame” = “{{0.375, 0}, {0.3125, 0.33333}}”; }
com.manytricks.MoomCustom Controls-array-add{ Action = 19; “Relative Frame” = “{{0.6875, 0.66666}, {0.3125, 0.66666}}”; }
com.manytricks.MoomCustom Controls-array-add{ Action = 19; “Relative Frame” = “{{0.6875, 0.33333}, {0.3125, 0.33333}}”; }
com.manytricks.MoomCustom Controls-array-add{ Action = 19; “Relative Frame” = “{{0.6875, 0}, {0.3125, 0.33333}}”; }
com.manytricks.MoomCustom Controls-array-add{ Action = 1001; “Apply to Overlapping Windows” = 1; Snapshot = ({ “Application Name” = Safari; “Bundle Identifier” = “com.apple.safari”; “Window Frame” = “{{0, 890}, {1199, 888}}”; “Window Subrole” = AXStandardWindow; }, { “Application Name” = Chrome; “Bundle Identifier” = “com.google.chrome”; “Window Frame” = “{{0, 0}, {1199, 888}}”; “Window Subrole” = AXStandardWindow; }, { “Application Name” = Firefox; “Bundle Identifier” = “org.mozilla.firefox”; “Window Frame” = “{{0, 0}, {1199, 888}}”; “Window Subrole” = AXStandardWindow; }, { “Application Name” = Emacs; “Bundle Identifier” = “org.gnu.emacs”; “Window Frame” = “{{1201, 597}, {991, 1181}}”; “Window Subrole” = AXStandardWindow; }, { “Application Name” = Code; “Bundle Identifier” = “com.microsoft.vscode”; “Window Frame” = “{{1201, 594}, {1999, 1184}}”; “Window Subrole” = AXStandardWindow; }, { “Application Name” = Mail; “Bundle Identifier” = “com.apple.mail”; “Window Frame” = “{{2201, 594}, {999, 1184}}”; “Window Subrole” = AXStandardWindow; }, { “Application Name” = nvALT; “Bundle Identifier” = “net.elasticthreads.nv”; “Window Frame” = “{{2201, 989}, {999, 789}}”; “Window Subrole” = AXStandardWindow; }, { “Application Name” = SimpleNote; “Bundle Identifier” = “bogdanf.osx.metanota.pro”; “Window Frame” = “{{2201, 989}, {999, 789}}”; “Window Subrole” = AXStandardWindow; }, { “Application Name” = Finder; “Bundle Identifier” = “com.apple.finder”; “Window Frame” = “{{2401, 1186}, {799, 592}}”; “Window Subrole” = AXStandardWindow; }, { “Application Name” = Messages; “Bundle Identifier” = “com.apple.ichat”; “Window Frame” = “{{401, 0}, {798, 591}}”; “Window Subrole” = AXStandardWindow; }, { “Application Name” = Slack; “Bundle Identifier” = “com.tinyspeck.slackmacgap”; “Window Frame” = “{{0, 0}, {999, 591}}”; “Window Subrole” = AXStandardWindow; }, { “Application Name” = Terminal; “Bundle Identifier” = “com.apple.terminal”; “Window Frame” = “{{1201, 20}, {993, 572}}”; “Window Subrole” = AXStandardWindow; }, { “Application Name” = iTerm2; “Bundle Identifier” = “com.googlecode.iterm2”; “Window Frame” = “{{1201, 17}, {993, 572}}”; “Window Subrole” = AXStandardWindow; }, { “Application Name” = QuickTime; “Bundle Identifier” = “com.apple.quicktimeplayerx”; “Window Frame” = “{{2201, 0}, {999, 592}}”; “Window Subrole” = AXStandardWindow; }, { “Application Name” = VLC; “Bundle Identifier” = “org.videolan.vlc”; “Window Frame” = “{{2201, 0}, {999, 592}}”; “Window Subrole” = AXStandardWindow; }); “Snapshot Screens” = ( “{{0, 0}, {3200, 1800}}” ); }
Define window sizes using 16 × 9 cellscom.manytricks.MoomConfiguration Grid: Columns-int16
com.manytricks.MoomConfiguration Grid: Rows-int9
on Check for updates automaticallycom.manytricks.MoomSUEnableAutomaticChecks-booltrue

Customize MP4 Automator

custom_mp4_automator () {
  mkdir -p "${HOME}/.config/mp4_automator" && \
  curl --compressed --location --silent \
    "https://github.com/mdhiggins/sickbeard_mp4_automator/archive/master.tar.gz" | \
  tar -C "${HOME}/.config/mp4_automator" --strip-components 1 -xf -
  printf "%s\n" "2.7.13" > "${HOME}/.config/mp4_automator/.python-version"

  if which crudini > /dev/null; then
    printf "%s\n" "${_mp4_automator}" | \
    while IFS="$(printf '\t')" read section key value; do
      crudini --set "${HOME}/.config/mp4_automator/autoProcess.ini" "${section}" "${key}" "${value}"
    done

    open "http://localhost:7878/settings/general"
    RADARRAPI="$(ask 'Radarr API Key?' 'Set API Key' '')"
    crudini --set "${HOME}/.config/mp4_automator/autoProcess.ini" "Radarr" "apikey" "$RADARRAPI"

    open "http://localhost:8989/settings/general"
    SONARRAPI="$(ask 'Sonarr API Key?' 'Set API Key' '')"
    crudini --set "${HOME}/.config/mp4_automator/autoProcess.ini" "Sonarr" "apikey" "$SONARRAPI"
  fi

  find "${HOME}/.config/mp4_automator" -name "*.py" -print0 | \
    xargs -0 -L 1 sed -i "" -e "s:/usr/bin/env python:/usr/local/python/versions/2.7.13/bin/python:"
}

_mp4_automator

PreferenceSectionKeyValue
MP4aac_adtstoascTrue
MP4audio-channel-bitrate256
MP4audio-codecac3,aac
MP4audio-default-languageeng
MP4audio-filter
MP4audio-languageeng
MP4convert-mp4True
MP4copy_to
MP4delete_originalFalse
MP4download-artworkPoster
MP4download-subsTrue
MP4embed-subsTrue
MP4ffmpeg/usr/local/bin/ffmpeg
MP4ffprobe/usr/local/bin/ffprobe
MP4fullpathguessTrue
MP4h264-max-level4.1
MP4ios-audioTrue
MP4ios-audio-filter
MP4ios-first-track-onlyTrue
MP4max-audio-channels
MP4move_to
MP4output_directory
MP4output_extensionm4v
MP4output_formatmp4
MP4permissions0644
MP4pix-fmt
MP4post-processFalse
MP4postopts
MP4preopts
MP4relocate_moovTrue
MP4sub-providersaddic7ed,podnapisi,thesubdb,opensubtitles
MP4subtitle-codecmov_text
MP4subtitle-default-languageeng
MP4subtitle-encoding
MP4subtitle-languageeng
MP4tag-languageeng
MP4tagfileTrue
MP4threadsauto
MP4use-qsv-decoder-with-encoderTrue
MP4video-bitrate
MP4video-codech264,x264
MP4video-crf
MP4video-max-width1920
Plexhostlocalhost
Plexport32400
PlexrefreshFalse
Plextoken
Radarrhostlocalhost
Radarrport7878
RadarrsslFalse
Radarrweb_root
Sonarrhostlocalhost
Sonarrport8989
SonarrsslFalse
Sonarrweb_root

Customize nvALT

custom_nvalt () {
  config_defaults "$_nvalt"
  config_launchd "${HOME}/Library/LaunchAgents/net.elasticthreads.nv.plist" "$_nvalt_launchd"
}

_nvalt

PreferenceDomainKeyTypeValueHost
List Text Size: Smallnet.elasticthreads.nvTableFontPointSize-int11
Bring-to-Front Hotkey: (None)net.elasticthreads.nvAppActivationKeyCode-int-1
net.elasticthreads.nvAppActivationModifiers-int-1
on Auto-select notes by title when searchingnet.elasticthreads.nvAutoCompleteSearches-booltrue
on Confirm note deletionnet.elasticthreads.nvConfirmNoteDeletion-booltrue
off Quit when closing windownet.elasticthreads.nvQuitWhenClosingMainWindow-boolfalse
on Show menu bar iconnet.elasticthreads.nvStatusBarItem-booltrue
Hide Dock Iconnet.elasticthreads.nvShowDockIcon-boolfalse
Styled Text: off Copy basic styles from other appsnet.elasticthreads.nvPastePreservesStyle-boolfalse
Spelling: off Check as you typenet.elasticthreads.nvCheckSpellingInNoteBody-boolfalse
Tab Key: Indent linesnet.elasticthreads.nvTabKeyIndents-booltrue
on Soft tabs (spaces)net.elasticthreads.nvUseSoftTabs-booltrue
Links: on Make URLs clickable linksnet.elasticthreads.nvMakeURLsClickable-booltrue
Links: off Suggest titles for note-linksnet.elasticthreads.nvAutoSuggestLinks-boolfalse
URL Import: off Convert imported URLs to Markdownnet.elasticthreads.nvUseMarkdownImport-boolfalse
URL Import: off Process with Readabilitynet.elasticthreads.nvUseReadability-boolfalse
Direction: off Right-To-Left (RTL)net.elasticthreads.nvrtl-boolfalse
Auto-pair: onnet.elasticthreads.nvUseAutoPairing-booltrue
External Text Editor: Emacs.appnet.elasticthreads.nvDefaultEEIdentifier-stringorg.gnu.Emacs
net.elasticthreads.nvUserEEIdentifiers-array-addcom.apple.TextEdit
net.elasticthreads.nvUserEEIdentifiers-array-addorg.gnu.Emacs
Body Font: InconsolataLGC 13net.elasticthreads.nvNoteBodyFont-data040b73747265616d747970656481e803840140848484064e53466f6e741e8484084e534f626a65637400858401692884055b3430635d060000001e000000fffe49006e0063006f006e0073006f006c006100740061004c004700430000008401660d8401630098019800980086
on Search Highlight: #CCFFCCnet.elasticthreads.nvHighlightSearchTerms-booltrue
net.elasticthreads.nvSearchTermHighlightColor-data040b73747265616d747970656481e803840140848484074e53436f6c6f72008484084e534f626a65637400858401630184046666666683cdcc4c3f0183cdcc4c3f0186
Foreground Text: #CCCCCCnet.elasticthreads.nvForegroundTextColor-data040b73747265616d747970656481e803840140848484074e53436f6c6f72008484084e534f626a65637400858401630184046666666683cdcc4c3f83cdcc4c3f83cdcc4c3f0186
Background: #1A1A1Anet.elasticthreads.nvBackgroundTextColor-data040b73747265616d747970656481e803840140848484074e53436f6c6f72008484084e534f626a65637400858401630184046666666683d1d0d03d83d1d0d03d83d1d0d03d0186
Always Show Grid Lines in Notes List: onnet.elasticthreads.nvShowGrid-booltrue
Alternating Row Colors: onnet.elasticthreads.nvAlternatingRows-booltrue
Use nvALT Scrollbars: offnet.elasticthreads.nvUseETScrollbarsOnLion-boolfalse
Keep Note Body Width Readable: onnet.elasticthreads.nvKeepsMaxTextWidth-booltrue
Max. Note Body Width: 650 pixelsnet.elasticthreads.nvNoteBodyMaxWidth-int650
ViewSwitch to Horizontal Layoutnet.elasticthreads.nvHorizontalLayout-booltrue
ViewColumns✓ Title ✓ Tagsnet.elasticthreads.nvNoteAttributesVisible-array-addTitle
net.elasticthreads.nvNoteAttributesVisible-array-addTags
ViewSort By ▶︎ ▼ Date Modifiednet.elasticthreads.nvTableIsReverseSorted-booltrue
net.elasticthreads.nvTableSortColumn-stringDate Modified
ViewShow Note Previews in Titlenet.elasticthreads.nvTableColumnsHaveBodyPreview-booltrue

_nvalt_launchd

CommandEntryTypeValue
add:KeepAlivebooltrue
add:Labelstringnet.elasticthreads.nv
add:ProcessTypestringInteractive
add:Programstring/Applications/nvALT.app/Contents/MacOS/nvALT
add:RunAtLoadbooltrue

Customize NZBGet

custom_nzbget () {
  f="${HOME}/Library/Application Support/NZBGet/nzbget.conf"
  mkdir -p "$(dirname $f)"
  if which crudini > /dev/null; then
    printf "%s\n" "${_nzbget}" | \
    while IFS="$(printf '\t')" read key value; do
      crudini --set "$f" "" "${key}" "${value}"
    done
  fi
  sed -i "" -e "s/ = /=/g" "$f"
}

_nzbget

PreferenceKeyValue
SecurityControlIP127.0.0.1
ControlPort6789
AuthorizedIP127.0.0.1
News-ServersServer1.Level0
Server1Server1.Hostssl.astraweb.com
Server1.Port443
Server1.Encryptionyes
Server1.Connections6
Server1.Retention3000
News-ServersServer2.Level0
Server2Server2.Hostssl-us.astraweb.com
Server2.Port443
Server2.Encryptionyes
Server2.Connections6
Server2.Retention3000
News-ServersServer3.Level0
Server3Server3.Hostssl-eu.astraweb.com
Server3.Port443
Server3.Encryptionyes
Server3.Connections6
Server3.Retention3000
News-ServersServer4.Level1
Server4Server4.Hostnews.tweaknews.eu
Server4.Port443
Server4.Encryptionyes
Server4.Connections40
Server4.Retention2500
News-ServersServer5.Level2
Server5Server5.Hostnews.newsdemon.com
Server5.Port563
Server5.Encryptionyes
Server5.Connections12
Server5.Retention3303
News-ServersServer6.Level2
Server6Server6.Hostus.newsdemon.com
Server6.Port563
Server6.Encryptionyes
Server6.Connections12
Server6.Retention3303
News-ServersServer7.Level2
Server7Server7.Hosteu.newsdemon.com
Server7.Port563
Server7.Encryptionyes
Server7.Connections12
Server7.Retention3303
News-ServersServer8.Level2
Server8Server8.Hostnl.newsdemon.com
Server8.Port563
Server8.Encryptionyes
Server8.Connections12
Server8.Retention3303
News-ServersServer9.Level2
Server9Server9.Hostusnews.blocknews.net
Server9.Port443
Server9.Encryptionyes
Server9.Connections16
Server9.Retention3240
News-ServersServer10.Level2
Server10Server10.Hosteunews.blocknews.net
Server10.Port443
Server10.Encryptionyes
Server10.Connections16
Server10.Retention3240
News-ServersServer11.Level2
Server11Server11.Hosteunews2.blocknews.net
Server11.Port443
Server11.Encryptionyes
Server11.Connections16
Server11.Retention3240

Customize Safari

custom_safari () {
  config_defaults "${_safari}"
}

_safari

PreferenceDomainKeyTypeValueHost
Safari opens with: A new windowcom.apple.SafariAlwaysRestoreSessionAtLaunch-boolfalse
com.apple.SafariOpenPrivateWindowWhenNotRestoringSessionAtLaunch-boolfalse
New windows open with: Empty Pagecom.apple.SafariNewWindowBehavior-int1
New tabs open with: Empty Pagecom.apple.SafariNewTabBehavior-int1
off Open “safe” files after downloadingcom.apple.SafariAutoOpenSafeDownloads-boolfalse
Open pages in tabs instead of windows: Alwayscom.apple.SafariTabCreationPolicy-int2
AutoFill web forms: off Using info from my contactscom.apple.SafariAutoFillFromAddressBook-boolfalse
AutoFill web forms: on User names and passwordscom.apple.SafariAutoFillPasswords-booltrue
AutoFill web forms: off Credit cardscom.apple.SafariAutoFillCreditCardData-boolfalse
AutoFill web forms: off Other formscom.apple.SafariAutoFillMiscellaneousForms-boolfalse
on Include search engine suggestionscom.apple.SafariSuppressSearchSuggestions-boolfalse
Smart Search Field: off Include Safari Suggestionscom.apple.SafariUniversalSearchEnabled-boolfalse
Smart Search Field: on Enable Quick Website Searchcom.apple.SafariWebsiteSpecificSearchEnabled-booltrue
Smart Search Field: on Preload Top Hit in the backgroundcom.apple.SafariPreloadTopHit-booltrue
Smart Search Field: off Show Favoritescom.apple.SafariShowFavoritesUnderSmartSearchField-boolfalse
Website use of location services: Deny without promptingcom.apple.SafariSafariGeolocationPermissionPolicy-int0
Website tracking: ~on~ *Prevent cross-site trackingcom.apple.SafariBlockStoragePolicy-int2
com.apple.SafariWebKitStorageBlockingPolicy-int1
com.apple.Safaricom.apple.Safari.ContentPageGroupIdentifier.WebKit2StorageBlockingPolicy-int1
Website tracking: on Ask websites not to track mecom.apple.SafariSendDoNotTrackHTTPHeader-booltrue
Cookies and website data: off Block all cookiescom.apple.WebFoundationNSHTTPAcceptCookies-stringalways
Apple Pay: on Allow websites to check if Apple Pay is set upcom.apple.Safaricom.apple.Safari.ContentPageGroupIdentifier.WebKit2ApplePayCapabilityDisclosureAllowed-booltrue
off Allow websites to ask for permission to send push notificationscom.apple.SafariCanPromptForPushNotifications-boolfalse
Smart Search Field: on Show full website addresscom.apple.SafariShowFullURLInSmartSearchField-booltrue
Default encoding: Unicode (UTF-8)com.apple.SafariWebKitDefaultTextEncodingName-stringutf-8
com.apple.Safaricom.apple.Safari.ContentPageGroupIdentifier.WebKit2DefaultTextEncodingName-stringutf-8
on Show Develop menu in menu barcom.apple.SafariIncludeDevelopMenu-booltrue
com.apple.SafariWebKitDeveloperExtrasEnabledPreferenceKey-booltrue
com.apple.Safaricom.apple.Safari.ContentPageGroupIdentifier.WebKit2DeveloperExtrasEnabled-booltrue
ViewShow Favorites Barcom.apple.SafariShowFavoritesBar-v2-booltrue
ViewShow Tab Barcom.apple.SafariAlwaysShowTabBar-booltrue
ViewShow Status Barcom.apple.SafariShowStatusBar-booltrue
com.apple.SafariShowStatusBarInFullScreen-booltrue

Customize Sieve

custom_sieve () {
  cat > "${HOME}/.sieve" << EOF
require ["date", "fileinto", "imap4flags", "mailbox", "relational", "variables"];

setflag "\\\\Seen";

if date :is "date" "year" "1995" { fileinto :create "Archives.1995"; }
if date :is "date" "year" "1996" { fileinto :create "Archives.1996"; }
if date :is "date" "year" "1997" { fileinto :create "Archives.1997"; }
if date :is "date" "year" "1998" { fileinto :create "Archives.1998"; }
if date :is "date" "year" "1999" { fileinto :create "Archives.1999"; }
if date :is "date" "year" "2000" { fileinto :create "Archives.2000"; }
if date :is "date" "year" "2001" { fileinto :create "Archives.2001"; }
if date :is "date" "year" "2002" { fileinto :create "Archives.2002"; }
if date :is "date" "year" "2003" { fileinto :create "Archives.2003"; }
if date :is "date" "year" "2004" { fileinto :create "Archives.2004"; }
if date :is "date" "year" "2005" { fileinto :create "Archives.2005"; }
if date :is "date" "year" "2006" { fileinto :create "Archives.2006"; }
if date :is "date" "year" "2007" { fileinto :create "Archives.2007"; }
if date :is "date" "year" "2008" { fileinto :create "Archives.2008"; }
if date :is "date" "year" "2009" { fileinto :create "Archives.2009"; }
if date :is "date" "year" "2010" { fileinto :create "Archives.2010"; }
if date :is "date" "year" "2011" { fileinto :create "Archives.2011"; }
if date :is "date" "year" "2012" { fileinto :create "Archives.2012"; }
if date :is "date" "year" "2013" { fileinto :create "Archives.2013"; }
if date :is "date" "year" "2014" { fileinto :create "Archives.2014"; }
if date :is "date" "year" "2015" { fileinto :create "Archives.2015"; }
if date :is "date" "year" "2016" { fileinto :create "Archives.2016"; }
if date :is "date" "year" "2017" { fileinto :create "Archives.2017"; }
if date :is "date" "year" "2018" { fileinto :create "Archives.2018"; }
if date :is "date" "year" "2019" { fileinto :create "Archives.2019"; }
if date :is "date" "year" "2020" { fileinto :create "Archives.2020"; }
EOF
}

Customize Sonarr

custom_sonarr () {
  open "http://localhost:7878/settings/mediamanagement"
  open "http://localhost:8989/settings/mediamanagement"
  printf "%s" "$_sonarr" | \
  while IFS="$(printf '\t')" read pref value; do
    printf "\033[1m\033[34m%s:\033[0m %s\n" "$pref" "$value"
  done
}

_sonarr