diff --git a/ape/etc/bochsrc.dbg b/ape/etc/bochsrc.dbg
deleted file mode 100644
index 28a8d2715..000000000
--- a/ape/etc/bochsrc.dbg
+++ /dev/null
@@ -1,1279 +0,0 @@
-# make boot.com
-# bochs -q -f .bochsrc.dbg floppya:1_44=win64.exe,status=inserted
-
-#=======================================================================
-# PLUGIN_CTRL:
-# Controls the presence of optional device plugins. These plugins are loaded
-# directly with this option and some of them install a config option that is
-# only available when the plugin device is loaded. The value "1" means to load
-# the plugin and "0" will unload it (if loaded before).
-#
-# These plugins will be loaded by default (if present): 'biosdev', 'extfpuirq',
-# 'gameport', 'iodebug','parallel', 'serial', 'speaker' and 'unmapped'.
-#
-# These plugins are also supported, but they are usually loaded directly with
-# their bochsrc option: 'e1000', 'es1370', 'ne2k', 'pcidev', 'pcipnic', 'sb16',
-# 'usb_ehci', 'usb_ohci', 'usb_uhci', 'usb_xhci' and 'voodoo'.
-#=======================================================================
-#plugin_ctrl: unmapped=0, e1000=1 # unload 'unmapped' and load 'e1000'
-
-#=======================================================================
-# CONFIG_INTERFACE
-#
-# The configuration interface is a series of menus or dialog boxes that
-# allows you to change all the settings that control Bochs's behavior.
-# Depending on the platform there are up to 3 choices of configuration
-# interface: a text mode version called "textconfig" and two graphical versions
-# called "win32config" and "wx".  The text mode version uses stdin/stdout and
-# is always compiled in, unless Bochs is compiled for wx only. The choice
-# "win32config" is only available on win32 and it is the default there.
-# The choice "wx" is only available when you use "--with-wx" on the configure
-# command.  If you do not write a config_interface line, Bochs will
-# choose a default for you.
-#
-# NOTE: if you use the "wx" configuration interface, you must also use
-# the "wx" display library.
-#=======================================================================
-#config_interface: textconfig
-#config_interface: win32config
-#config_interface: wx
-
-#=======================================================================
-# DISPLAY_LIBRARY
-#
-# The display library is the code that displays the Bochs VGA screen.  Bochs
-# has a selection of about 10 different display library implementations for
-# different platforms.  If you run configure with multiple --with-* options,
-# the display_library command lets you choose which one you want to run with.
-# If you do not write a display_library line, Bochs will choose a default for
-# you.
-#
-# The choices are:
-#   x              use X windows interface, cross platform
-#   win32          use native win32 libraries
-#   carbon         use Carbon library (for MacOS X)
-#   macintosh      use MacOS pre-10
-#   amigaos        use native AmigaOS libraries
-#   sdl            use SDL 1.2.x library, cross platform
-#   sdl2           use SDL 2.x library, cross platform
-#   svga           use SVGALIB library for Linux, allows graphics without X11
-#   term           text only, uses curses/ncurses library, cross platform
-#   rfb            provides an interface to AT&T's VNC viewer, cross platform
-#   vncsrv         use LibVNCServer for extended RFB(VNC) support
-#   wx             use wxWidgets library, cross platform
-#   nogui          no display at all
-#
-# NOTE: if you use the "wx" configuration interface, you must also use
-# the "wx" display library.
-#
-# Specific options:
-# Some display libraries now support specific options to control their
-# behaviour. These options are supported by more than one display library:
-#
-# "gui_debug"   - use GTK debugger gui (sdl, sdl2, x) / Win32 debugger gui (sdl,
-#                 sdl2, win32)
-# "hideIPS"     - disable IPS output in status bar (rfb, sdl, sdl2, vncsrv,
-#                 win32, wx, x)
-# "nokeyrepeat" - turn off host keyboard repeat (sdl, sdl2, win32, x)
-# "timeout"     - time (in seconds) to wait for client (rfb, vncsrv)
-#
-# See the examples below for other currently supported options.
-#=======================================================================
-#display_library: amigaos
-#display_library: carbon
-#display_library: macintosh
-#display_library: nogui
-#display_library: rfb
-#display_library: sdl, options="fullscreen" # startup in fullscreen mode
-#display_library: sdl2, options="fullscreen" # startup in fullscreen mode
-#display_library: term
-#display_library: vncsrv
-# "traphotkeys" - system hotkeys not handled by host OS, but sent to guest
-#                 (win32 in mouse capture and fullscreen mode: alt-tab, win,
-#                 alt-space, alt-esc, ctrl-esc)
-#display_library: win32, options="traphotkeys"
-#display_library: wx
-#display_library: x, gui_debug=1
-display_library: x, options="gui_debug"
-
-#=======================================================================
-# CPU:
-# This defines cpu-related parameters inside Bochs:
-#
-#  MODEL:
-#    Selects CPU configuration to emulate from pre-defined list of all
-#    supported configurations. When this option is used and the value
-#    is different from 'bx_generic', the parameters of the CPUID option
-#    have no effect anymore.
-#
-#  CPU configurations that can be selected:
-# -----------------------------------------------------------------
-#  pentium                    Intel Pentium (P54C)
-#  pentium_mmx                Intel Pentium MMX
-#  amd_k6_2_chomper           AMD-K6(tm) 3D processor (Chomper)
-#  p2_klamath                 Intel Pentium II (Klamath)
-#  p3_katmai                  Intel Pentium III (Katmai)
-#  p4_willamette              Intel(R) Pentium(R) 4 (Willamette)
-#  core_duo_t2400_yonah       Intel(R) Core(TM) Duo CPU T2400 (Yonah)
-#  atom_n270                  Intel(R) Atom(TM) CPU N270
-#  p4_prescott_celeron_336    Intel(R) Celeron(R) 336 (Prescott)
-#  athlon64_clawhammer        AMD Athlon(tm) 64 Processor 2800+ (Clawhammer)
-#  athlon64_venice            AMD Athlon(tm) 64 Processor 3000+ (Venice)
-#  turion64_tyler             AMD Turion(tm) 64 X2 Mobile TL-60 (Tyler)
-#  phenom_8650_toliman        AMD Phenom X3 8650 (Toliman)
-#  core2_penryn_t9600         Intel Mobile Core 2 Duo T9600 (Penryn)
-#  corei5_lynnfield_750       Intel(R) Core(TM) i5   750 (Lynnfield)
-#  corei5_arrandale_m520      Intel(R) Core(TM) i5 M 520 (Arrandale)
-#  corei7_sandy_bridge_2600k  Intel(R) Core(TM) i7-2600K (Sandy Bridge)
-#  zambezi                    AMD FX(tm)-4100 Quad-Core Processor (Zambezi)
-#  trinity_apu                AMD A8-5600K APU (Trinity)
-#  ryzen                      AMD Ryzen 7 1700
-#  corei7_ivy_bridge_3770k    Intel(R) Core(TM) i7-3770K CPU (Ivy Bridge)
-#  corei7_haswell_4770        Intel(R) Core(TM) i7-4770 CPU (Haswell)
-#  broadwell_ult              Intel(R) Processor 5Y70 CPU (Broadwell)
-#
-#  COUNT:
-#    Set the number of processors:cores per processor:threads per core when
-#    Bochs is compiled for SMP emulation. Bochs currently supports up to
-#    14 threads (legacy APIC) or 254 threads (xAPIC or higher) running
-#    simultaniosly. If Bochs is compiled without SMP support, it won't accept
-#    values different from 1.
-#
-#  QUANTUM:
-#    Maximum amount of instructions allowed to execute by processor before
-#    returning control to another cpu. This option exists only in Bochs
-#    binary compiled with SMP support.
-#
-#  RESET_ON_TRIPLE_FAULT:
-#    Reset the CPU when triple fault occur (highly recommended) rather than
-#    PANIC. Remember that if you trying to continue after triple fault the
-#    simulation will be completely bogus !
-#
-#  CPUID_LIMIT_WINNT:
-#    Determine whether to limit maximum CPUID function to 2. This mode is
-#    required to workaround WinNT installation and boot issues.
-#
-#  MSRS:
-#    Define path to user CPU Model Specific Registers (MSRs) specification.
-#    See example in msrs.def.
-#
-#  IGNORE_BAD_MSRS:
-#    Ignore MSR references that Bochs does not understand; print a warning
-#    message instead of generating #GP exception. This option is enabled
-#    by default but will not be avaiable if configurable MSRs are enabled.
-#
-#  MWAIT_IS_NOP:
-#    When this option is enabled MWAIT will not put the CPU into a sleep state.
-#    This option exists only if Bochs compiled with --enable-monitor-mwait.
-#
-#  IPS:
-#    Emulated Instructions Per Second. This is the number of IPS that bochs
-#    is capable of running on your machine. You can recompile Bochs with
-#    --enable-show-ips option enabled, to find your host's capability.
-#    Measured IPS value will then be logged into your log file or shown
-#    in the status bar (if supported by the gui).
-#
-#    IPS is used to calibrate many time-dependent events within the bochs
-#    simulation.  For example, changing IPS affects the frequency of VGA
-#    updates, the duration of time before a key starts to autorepeat, and
-#    the measurement of BogoMips and other benchmarks.
-#
-#  Examples:
-#
-#  Bochs Machine/Compiler                                 Mips
-# ______________________________________________________________________
-#  2.4.6 3.4Ghz Intel Core i7 2600 with Win7x64/g++ 4.5.2 85 to 95 Mips
-#  2.3.7 3.2Ghz Intel Core 2 Q9770 with WinXP/g++ 3.4     50 to 55 Mips
-#  2.3.7 2.6Ghz Intel Core 2 Duo with WinXP/g++ 3.4       38 to 43 Mips
-#  2.2.6 2.6Ghz Intel Core 2 Duo with WinXP/g++ 3.4       21 to 25 Mips
-#  2.2.6 2.1Ghz Athlon XP with Linux 2.6/g++ 3.4          12 to 15 Mips
-#=======================================================================
-#cpu: model=core2_penryn_t9600, count=1, ips=50000000, reset_on_triple_fault=1, ignore_bad_msrs=1, msrs="msrs.def"
-#cpu: cpuid_limit_winnt=0
-cpu: model=corei7_haswell_4770
-
-#=======================================================================
-# CPUID:
-#
-# This defines features and functionality supported by Bochs emulated CPU.
-# The option has no offect if CPU model was selected in CPU option.
-#
-#  MMX:
-#    Select MMX instruction set support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 5.
-#
-#  APIC:
-#    Select APIC configuration (LEGACY/XAPIC/XAPIC_EXT/X2APIC).
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 5.
-#
-#  SEP:
-#    Select SYSENTER/SYSEXIT instruction set support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  SIMD:
-#    Select SIMD instructions support.
-#    Any of NONE/SSE/SSE2/SSE3/SSSE3/SSE4_1/SSE4_2/AVX/AVX2/AVX512
-#    could be selected.
-#
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#    The AVX choises exists only if Bochs compiled with --enable-avx option.
-#
-#  SSE4A:
-#    Select AMD SSE4A instructions support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  MISALIGNED_SSE:
-#    Select AMD Misaligned SSE mode support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  AES:
-#    Select AES instruction set support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  SHA:
-#    Select SHA instruction set support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  MOVBE:
-#    Select MOVBE Intel(R) Atom instruction support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  ADX:
-#    Select ADCX/ADOX instructions support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  XSAVE:
-#    Select XSAVE extensions support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  XSAVEOPT:
-#    Select XSAVEOPT instruction support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  AVX_F16C:
-#    Select AVX float16 convert instructions support.
-#    This option exists only if Bochs compiled with --enable-avx option.
-#
-#  AVX_FMA:
-#    Select AVX fused multiply add (FMA) instructions support.
-#    This option exists only if Bochs compiled with --enable-avx option.
-#
-#  BMI:
-#    Select BMI1/BMI2 instructions support.
-#    This option exists only if Bochs compiled with --enable-avx option.
-#
-#  XOP:
-#    Select AMD XOP instructions support.
-#    This option exists only if Bochs compiled with --enable-avx option.
-#
-#  FMA4:
-#    Select AMD four operand FMA instructions support.
-#    This option exists only if Bochs compiled with --enable-avx option.
-#
-#  TBM:
-#    Select AMD Trailing Bit Manipulation (TBM) instructions support.
-#    This option exists only if Bochs compiled with --enable-avx option.
-#
-#  X86-64:
-#    Enable x86-64 and long mode support.
-#    This option exists only if Bochs compiled with x86-64 support.
-#
-#  1G_PAGES:
-#    Enable 1G page size support in long mode.
-#    This option exists only if Bochs compiled with x86-64 support.
-#
-#  PCID:
-#    Enable Process-Context Identifiers (PCID) support in long mode.
-#    This option exists only if Bochs compiled with x86-64 support.
-#
-#  FSGSBASE:
-#    Enable GS/GS BASE access instructions support in long mode.
-#    This option exists only if Bochs compiled with x86-64 support.
-#
-#  SMEP:
-#    Enable Supervisor Mode Execution Protection (SMEP) support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  SMAP:
-#    Enable Supervisor Mode Access Prevention (SMAP) support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  MWAIT:
-#    Select MONITOR/MWAIT instructions support.
-#    This option exists only if Bochs compiled with --enable-monitor-mwait.
-#
-#  VMX:
-#    Select VMX extensions emulation support.
-#    This option exists only if Bochs compiled with --enable-vmx option.
-#
-#  SVM:
-#    Select AMD SVM (Secure Virtual Machine) extensions emulation support.
-#    This option exists only if Bochs compiled with --enable-svm option.
-#
-#  VENDOR_STRING:
-#    Set the CPUID vendor string returned by CPUID(0x0). This should be a
-#    twelve-character ASCII string.
-#
-#  BRAND_STRING:
-#    Set the CPUID vendor string returned by CPUID(0x80000002 .. 0x80000004).
-#    This should be at most a forty-eight-character ASCII string.
-#
-#  LEVEL:
-#    Set emulated CPU level information returned by CPUID. Default value is
-#    determined by configure option --enable-cpu-level. Currently supported
-#    values are 5 (for Pentium and similar processors) and 6 (for P6 and
-#    later processors).
-#
-#  FAMILY:
-#    Set model information returned by CPUID. Default family value determined
-#    by configure option --enable-cpu-level.
-#
-#  MODEL:
-#    Set model information returned by CPUID. Default model value is 3.
-#
-#  STEPPING:
-#    Set stepping information returned by CPUID. Default stepping value is 3.
-#=======================================================================
-#cpuid: x86_64=1, mmx=1, sep=1, simd=sse4_2, apic=xapic, aes=1, movbe=1, xsave=1
-#cpuid: family=6, model=0x1a, stepping=5
-
-#=======================================================================
-# MEMORY
-# Set the amount of physical memory you want to emulate.
-#
-# GUEST:
-# Set amount of guest physical memory to emulate. The default is 32MB,
-# the maximum amount limited only by physical address space limitations.
-#
-# HOST:
-# Set amount of host memory you want to allocate for guest RAM emulation.
-# It is possible to allocate less memory than you want to emulate in guest
-# system. This will fake guest to see the non-existing memory. Once guest
-# system touches new memory block it will be dynamically taken from the
-# memory pool. You will be warned (by FATAL PANIC) in case guest already
-# used all allocated host memory and wants more.
-#
-#=======================================================================
-#memory: guest=512, host=256
-
-#=======================================================================
-# ROMIMAGE:
-# The ROM BIOS controls what the PC does when it first powers on.
-# Normally, you can use a precompiled BIOS in the source or binary
-# distribution called BIOS-bochs-latest. The default ROM BIOS is usually loaded
-# starting at address 0xfffe0000, and it is exactly 128k long. The legacy
-# version of the Bochs BIOS is usually loaded starting at address 0xffff0000,
-# and it is exactly 64k long.
-# You can use the environment variable $BXSHARE to specify the location
-# of the BIOS.
-# The usage of external large BIOS images (up to 512k) at memory top is
-# now supported, but we still recommend to use the BIOS distributed with Bochs.
-# The start address is optional, since it can be calculated from image size.
-# The Bochs BIOS currently supports only the option "fastboot" to skip the
-# boot menu delay.
-#=======================================================================
-romimage: file=$BXSHARE/BIOS-bochs-latest, options=fastboot
-#romimage: file=$BXSHARE/bios.bin-1.7.5 # http://www.seabios.org/SeaBIOS
-#romimage: file=mybios.bin, address=0xfff80000 # 512k at memory top
-#romimage: file=BIOS-bochs-latest, options=fastboot
-
-#=======================================================================
-# VGAROMIMAGE
-# You now need to load a VGA ROM BIOS into C0000.
-#=======================================================================
-#vgaromimage: file=$BXSHARE/VGABIOS-elpin-2.40
-vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest
-#vgaromimage: file=bios/VGABIOS-lgpl-latest-cirrus
-
-#=======================================================================
-# OPTROMIMAGE[1-4]:
-# You may now load up to 4 optional ROM images. Be sure to use a
-# read-only area, typically between C8000 and EFFFF. These optional
-# ROM images should not overwrite the rombios (located at
-# F0000-FFFFF) and the videobios (located at C0000-C7FFF).
-# Those ROM images will be initialized by the bios if they contain
-# the right signature (0x55AA) and a valid checksum.
-# It can also be a convenient way to upload some arbitrary code/data
-# in the simulation, that can be retrieved by the boot loader
-#=======================================================================
-#optromimage1: file=optionalrom.bin, address=0xd0000
-#optromimage2: file=optionalrom.bin, address=0xd1000
-#optromimage3: file=optionalrom.bin, address=0xd2000
-#optromimage4: file=optionalrom.bin, address=0xd3000
-
-#optramimage1: file=/path/file1.img, address=0x0010000
-#optramimage2: file=/path/file2.img, address=0x0020000
-#optramimage3: file=/path/file3.img, address=0x0030000
-#optramimage4: file=/path/file4.img, address=0x0040000
-
-#=======================================================================
-# VGA:
-# This defines parameters related to the VGA display
-#
-#   EXTENSION
-#     Here you can specify the display extension to be used. With the value
-#     'none' you can use standard VGA with no extension. Other supported
-#     values are 'vbe' for Bochs VBE, 'cirrus' for Cirrus SVGA support and
-#     'voodoo' for Voodoo Graphics support (see 'voodoo' option).
-#
-#   UPDATE_FREQ
-#     This parameter specifies the number of display updates per second.
-#     The VGA update timer by default uses the realtime engine with a value
-#     of 5. This parameter can be changed at runtime.
-#
-#   REALTIME
-#     If set to 1 (default), the VGA timer is based on realtime, otherwise it
-#     is driven by the cpu and depends on the ips setting. If the host is slow
-#     (low ips, update_freq) and the guest uses HLT appropriately, setting this
-#     to 0 and "clock: sync=none" may improve the responsiveness of the guest
-#     GUI when the guest is otherwise idle.
-#
-# Examples:
-#   vga: extension=cirrus, update_freq=10
-#=======================================================================
-vga: extension=vbe, update_freq=5, realtime=1
-
-#=======================================================================
-# VOODOO:
-# This defines the Voodoo Graphics emulation (experimental). Currently
-# supported models are 'voodoo1', 'voodoo2', 'banshee' and 'voodoo3'. The
-# Voodoo2 support is not yet complete, but almost usable. The Banshee and
-# Voodoo3 support is under construction, but basicly usable. The 2D/3D cards
-# require an external VGA BIOS the vga extension option to be set to 'voodoo'.
-# If the i440BX PCI chipset is selected, they can be assigned to AGP (slot #5).
-# The gui screen update timing for all models is controlled by the related 'vga'
-# options.
-#
-# Examples:
-#   voodoo: enabled=1, model=voodoo2
-#=======================================================================
-#voodoo: enabled=1, model=voodoo1
-
-#=======================================================================
-# KEYBOARD:
-# This defines parameters related to the emulated keyboard
-#
-#   TYPE:
-#     Type of keyboard return by a "identify keyboard" command to the
-#     keyboard controller. It must be one of "xt", "at" or "mf".
-#     Defaults to "mf". It should be ok for almost everybody. A known
-#     exception is french macs, that do have a "at"-like keyboard.
-#
-#   SERIAL_DELAY:
-#     Approximate time in microseconds that it takes one character to
-#     be transferred from the keyboard to controller over the serial path.
-#
-#   PASTE_DELAY:
-#     Approximate time in microseconds between attempts to paste
-#     characters to the keyboard controller. This leaves time for the
-#     guest os to deal with the flow of characters.  The ideal setting
-#     depends on how your operating system processes characters.  The
-#     default of 100000 usec (.1 seconds) was chosen because it works
-#     consistently in Windows.
-#     If your OS is losing characters during a paste, increase the paste
-#     delay until it stops losing characters.
-#
-#   KEYMAP:
-#     This enables a remap of a physical localized keyboard to a
-#     virtualized us keyboard, as the PC architecture expects.
-#
-#   USER_SHORTCUT:
-#     This defines the keyboard shortcut to be sent when you press the "user"
-#     button in the headerbar. The shortcut string is a combination of maximum
-#     3 key names (listed below) separated with a '-' character.
-#     Valid key names:
-#     "alt", "bksl", "bksp", "ctrl", "del", "down", "end", "enter", "esc",
-#     "f1", ... "f12", "home", "ins", "left", "menu", "minus", "pgdwn", "pgup",
-#     "plus", "power", "print", "right", "scrlck", "shift", "space", "tab", "up"
-#     and "win".
-
-# Examples:
-#   keyboard: type=mf, serial_delay=200, paste_delay=100000
-#   keyboard: keymap=gui/keymaps/x11-pc-de.map
-#   keyboard: user_shortcut=ctrl-alt-del
-#=======================================================================
-keyboard: type=mf, serial_delay=250
-
-#=======================================================================
-# MOUSE:
-# This defines parameters for the emulated mouse type, the initial status
-# of the mouse capture and the runtime method to toggle it.
-#
-#  TYPE:
-#  With the mouse type option you can select the type of mouse to emulate.
-#  The default value is 'ps2'. The other choices are 'imps2' (wheel mouse
-#  on PS/2), 'serial', 'serial_wheel', 'serial_msys' (one com port requires
-#  setting 'mode=mouse') 'inport' and 'bus' (if present). To connect a mouse
-#  to a USB port, see the 'usb_uhci', 'usb_ohci', 'usb_ehci' or 'usb_xhci'
-#  options (requires PCI and USB support).
-#
-#  ENABLED:
-#  The Bochs gui creates mouse "events" unless the 'enabled' option is
-#  set to 0. The hardware emulation itself is not disabled by this.
-#  Unless you have a particular reason for enabling the mouse by default,
-#  it is recommended that you leave it off. You can also toggle the mouse
-#  usage at runtime (RFB, SDL, Win32, wxWidgets and X11 - see below).
-#
-#  TOGGLE:
-#  The default method to toggle the mouse capture at runtime is to press the
-#  CTRL key and the middle mouse button ('ctrl+mbutton'). This option allows
-#  to change the method to 'ctrl+f10' (like DOSBox), 'ctrl+alt' (like QEMU)
-#  or 'f12'.
-#
-# Examples:
-#   mouse: enabled=1
-#   mouse: type=imps2, enabled=1
-#   mouse: type=serial, enabled=1
-#   mouse: enabled=0, toggle=ctrl+f10
-#=======================================================================
-mouse: enabled=1
-
-#=======================================================================
-# PCI:
-# This option controls the presence of a PCI chipset in Bochs. Currently it
-# supports the i430FX, i440FX and i440BX chipsets. You can also specify the
-# devices connected to PCI slots. Up to 5 slots are available. For these
-# combined PCI/ISA devices assigning to slot is mandatory if you want to emulate
-# the PCI model: cirrus, ne2k and pcivga. These PCI-only devices are also
-# supported, but they are auto-assigned if you don't use the slot configuration:
-# e1000, es1370, pcidev, pcipnic, usb_ehci, usb_ohci, usb_xhci and voodoo.
-# In case of the i440BX chipset, slot #5 is the AGP slot. Currently only the
-# 'voodoo' device can be assigned to AGP.
-#
-# Example:
-#   pci: enabled=1, chipset=i440fx, slot1=pcivga, slot2=ne2k
-#=======================================================================
-pci: enabled=1, chipset=i440fx
-
-#=======================================================================
-# CLOCK:
-# This defines the parameters of the clock inside Bochs:
-#
-#  SYNC:
-#  This defines the method how to synchronize the Bochs internal time
-#  with realtime. With the value 'none' the Bochs time relies on the IPS
-#  value and no host time synchronization is used. The 'slowdown' method
-#  sacrifices performance to preserve reproducibility while allowing host
-#  time correlation. The 'realtime' method sacrifices reproducibility to
-#  preserve performance and host-time correlation.
-#  It is possible to enable both synchronization methods.
-#
-#  RTC_SYNC:
-#  If this option is enabled together with the realtime synchronization,
-#  the RTC runs at realtime speed. This feature is disabled by default.
-#
-#  TIME0:
-#  Specifies the start (boot) time of the virtual machine. Use a time
-#  value as returned by the time(2) system call or a string as returned
-#  by the ctime(3) system call. If no time0 value is set or if time0
-#  equal to 1 (special case) or if time0 equal 'local', the simulation
-#  will be started at the current local host time. If time0 equal to 2
-#  (special case) or if time0 equal 'utc', the simulation will be started
-#  at the current utc time.
-#
-# Syntax:
-#  clock: sync=[none|slowdown|realtime|both], time0=[timeValue|local|utc]
-#
-# Example:
-#   clock: sync=none,     time0=local       # Now (localtime)
-#   clock: sync=slowdown, time0=315529200   # Tue Jan  1 00:00:00 1980
-#   clock: sync=none,     time0="Mon Jan  1 00:00:00 1990" # 631148400
-#   clock: sync=realtime, time0=938581955   # Wed Sep 29 07:12:35 1999
-#   clock: sync=realtime, time0="Sat Jan  1 00:00:00 2000" # 946681200
-#   clock: sync=none,     time0=1           # Now (localtime)
-#   clock: sync=none,     time0=utc         # Now (utc/gmt)
-#
-# Default value are sync=none, rtc_sync=0, time0=local
-#=======================================================================
-clock: sync=slowdown, time0=315529200
-
-#=======================================================================
-# CMOSIMAGE:
-# This defines a binary image file with size 128 bytes that can be loaded into
-# the CMOS RAM at startup. The rtc_init parameter controls whether initialize
-# the RTC with values stored in the image. By default the time0 argument given
-# to the clock option is used. With 'rtc_init=image' the image is the source
-# for the initial time.
-#
-# Example:
-#   cmosimage: file=cmos.img, rtc_init=image
-#=======================================================================
-#cmosimage: file=cmos.img, rtc_init=time0
-
-#=======================================================================
-# private_colormap: Request that the GUI create and use it's own
-#                   non-shared colormap.  This colormap will be used
-#                   when in the bochs window.  If not enabled, a
-#                   shared colormap scheme may be used.  Not implemented
-#                   on all GUI's.
-#
-# Examples:
-#   private_colormap: enabled=1
-#   private_colormap: enabled=0
-#=======================================================================
-private_colormap: enabled=0
-
-#=======================================================================
-# FLOPPYA:
-# Point this to pathname of floppy image file or device
-# This should be of a bootable floppy(image/device) if you're
-# booting from 'a' (or 'floppy').
-#
-# You can set the initial status of the media to 'ejected' or 'inserted'.
-#   floppya: 2_88=path, status=ejected    (2.88M 3.5"  media)
-#   floppya: 1_44=path, status=inserted   (1.44M 3.5"  media)
-#   floppya: 1_2=path, status=ejected     (1.2M  5.25" media)
-#   floppya: 720k=path, status=inserted   (720K  3.5"  media)
-#   floppya: 360k=path, status=inserted   (360K  5.25" media)
-#   floppya: 320k=path, status=inserted   (320K  5.25" media)
-#   floppya: 180k=path, status=inserted   (180K  5.25" media)
-#   floppya: 160k=path, status=inserted   (160K  5.25" media)
-#   floppya: image=path, status=inserted  (guess media type from image size)
-#   floppya: 1_44=vvfat:path, status=inserted  (use directory as VFAT media)
-#   floppya: type=1_44                    (1.44M 3.5" floppy drive, no media)
-#
-# The path should be the name of a disk image file.  On Unix, you can use a raw
-# device name such as /dev/fd0 on Linux.  On win32 platforms, use drive letters
-# such as a: or b: as the path.  The parameter 'image' works with image files
-# only. In that case the size must match one of the supported types.
-# The parameter 'type' can be used to enable the floppy drive without media
-# and status specified. Usually the drive type is set up based on the media type.
-# The optional parameter 'write_protected' can be used to control the media
-# write protect switch. By default it is turned off.
-#=======================================================================
-#floppya: 1_44=, status=inserted
-#floppya: image=../1.44, status=inserted
-#floppya: 1_44=/dev/fd0H1440, status=inserted
-#floppya: 1_2=../1_2, status=inserted
-#floppya: 1_44=a:, status=inserted
-#floppya: 1_44=a.img, status=inserted, write_protected=1
-#floppya: 1_44=/dev/rfd0a, status=inserted
-#floppya: 1_44=boot.img, status=inserted, write_protected=1
-
-#=======================================================================
-# FLOPPYB:
-# See FLOPPYA above for syntax
-#=======================================================================
-#floppyb: 1_44=b:, status=inserted
-#floppyb: 1_44=b.img, status=inserted
-
-#=======================================================================
-# ATA0, ATA1, ATA2, ATA3
-# ATA controller for hard disks and cdroms
-#
-# ata[0-3]: enabled=[0|1], ioaddr1=addr, ioaddr2=addr, irq=number
-#
-# These options enables up to 4 ata channels. For each channel
-# the two base io addresses and the irq must be specified.
-#
-# ata0 and ata1 are enabled by default with the values shown below
-#
-# Examples:
-#   ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
-#   ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
-#   ata2: enabled=1, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
-#   ata3: enabled=1, ioaddr1=0x168, ioaddr2=0x360, irq=9
-#=======================================================================
-ata0: enabled=0, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
-ata1: enabled=0, ioaddr1=0x170, ioaddr2=0x370, irq=15
-ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
-ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
-
-#=======================================================================
-# ATA[0-3]-MASTER, ATA[0-3]-SLAVE
-#
-# This defines the type and characteristics of all attached ata devices:
-#   type=       type of attached device [disk|cdrom]
-#   mode=       only valid for disks [flat|concat|external|dll|sparse|vmware3]
-#                                    [vmware4|undoable|growing|volatile|vpc]
-#                                    [vbox|vvfat]
-#   path=       path of the image / directory
-#   cylinders=  only valid for disks
-#   heads=      only valid for disks
-#   spt=        only valid for disks
-#   status=     only valid for cdroms [inserted|ejected]
-#   biosdetect= type of biosdetection [auto|cmos|none]
-#   translation=type of translation of the bios, only for disks [none|lba|large|rechs|auto]
-#   model=      string returned by identify device command
-#   journal=    optional filename of the redolog for undoable, volatile and vvfat disks
-#
-# Point this at a hard disk image file, cdrom iso file, or physical cdrom
-# device.  To create a hard disk image, try running bximage.  It will help you
-# choose the size and then suggest a line that works with it.
-#
-# In UNIX it may be possible to use a raw device as a Bochs hard disk,
-# but WE DON'T RECOMMEND IT.  In Windows there is no easy way.
-#
-# In windows, the drive letter + colon notation should be used for cdroms.
-# Depending on versions of windows and drivers, you may only be able to
-# access the "first" cdrom in the system.  On MacOSX, use path="drive"
-# to access the physical drive.
-#
-# The path is mandatory for hard disks. Disk geometry autodetection works with
-# images created by bximage if CHS is set to 0/0/0 (cylinders are calculated
-# using  heads=16 and spt=63). For other hard disk images and modes the
-# cylinders, heads, and spt are mandatory. In all cases the disk size reported
-# from the image must be exactly C*H*S*512.
-#
-# Default values are:
-#   mode=flat, biosdetect=auto, translation=auto, model="Generic 1234"
-#
-# The biosdetect option has currently no effect on the bios
-#
-# Examples:
-#   ata0-master: type=disk, mode=flat, path=10M.sample, cylinders=306, heads=4, spt=17
-#   ata0-slave:  type=disk, mode=flat, path=20M.sample, cylinders=615, heads=4, spt=17
-#   ata1-master: type=disk, mode=flat, path=30M.sample, cylinders=615, heads=6, spt=17
-#   ata1-slave:  type=disk, mode=flat, path=46M.sample, cylinders=940, heads=6, spt=17
-#   ata2-master: type=disk, mode=flat, path=62M.sample, cylinders=940, heads=8, spt=17
-#   ata2-slave:  type=disk, mode=flat, path=112M.sample, cylinders=900, heads=15, spt=17
-#   ata3-master: type=disk, mode=flat, path=483M.sample, cylinders=1024, heads=15, spt=63
-#   ata3-slave:  type=cdrom, path=iso.sample, status=inserted
-#=======================================================================
-#ata0-master: type=disk, mode=flat, path="30M.sample"
-#ata0-master: type=disk, mode=flat, path="30M.sample", cylinders=615, heads=6, spt=17
-#ata0-master: type=disk, mode=flat, path="c.img", cylinders=0 # autodetect
-#ata0-slave: type=disk, mode=vvfat, path=/bochs/images/vvfat, journal=vvfat.redolog
-#ata0-slave: type=cdrom, path=D:, status=inserted
-#ata0-slave: type=cdrom, path=/dev/cdrom, status=inserted
-#ata0-slave: type=cdrom, path="drive", status=inserted
-#ata0-slave: type=cdrom, path=/dev/rcd0d, status=inserted
-
-#=======================================================================
-# BOOT:
-# This defines the boot sequence. Now you can specify up to 3 boot drives,
-# which can be 'floppy', 'disk', 'cdrom' or 'network' (boot ROM).
-# Legacy 'a' and 'c' are also supported.
-# Examples:
-#   boot: floppy
-#   boot: cdrom, disk
-#   boot: network, disk
-#   boot: cdrom, floppy, disk
-#=======================================================================
-boot: floppy
-#boot: disk
-
-#=======================================================================
-# FLOPPY_BOOTSIG_CHECK: disabled=[0|1]
-# Enables or disables the 0xaa55 signature check on boot floppies
-# Defaults to disabled=0
-# Examples:
-#   floppy_bootsig_check: disabled=0
-#   floppy_bootsig_check: disabled=1
-#=======================================================================
-floppy_bootsig_check: disabled=0
-
-#=======================================================================
-# LOG:
-# Give the path of the log file you'd like Bochs debug and misc. verbiage
-# to be written to. If you don't use this option or set the filename to
-# '-' the output is written to the console. If you really don't want it,
-# make it "/dev/null" (Unix) or "nul" (win32). :^(
-#
-# Examples:
-#   log: ./bochs.out
-#   log: /dev/tty
-#=======================================================================
-#log: /dev/null
-log: .bochs.log
-
-#=======================================================================
-# LOGPREFIX:
-# This handles the format of the string prepended to each log line.
-# You may use those special tokens :
-#   %t : 11 decimal digits timer tick
-#   %i : 8 hexadecimal digits of cpu current eip (ignored in SMP configuration)
-#   %e : 1 character event type ('i'nfo, 'd'ebug, 'p'anic, 'e'rror)
-#   %d : 5 characters string of the device, between brackets
-#
-# Default : %t%e%d
-# Examples:
-#   logprefix: %t-%e-@%i-%d
-#   logprefix: %i%e%d
-#=======================================================================
-logprefix: %t%e%d
-
-#=======================================================================
-# LOG CONTROLS
-#
-# Bochs has four severity levels for event logging.
-#   panic: cannot proceed.  If you choose to continue after a panic,
-#          don't be surprised if you get strange behavior or crashes.
-#   error: something went wrong, but it is probably safe to continue the
-#          simulation.
-#   info: interesting or useful messages.
-#   debug: messages useful only when debugging the code.  This may
-#          spit out thousands per second.
-#
-# For events of each level, you can choose to exit Bochs ('fatal'), 'ask',
-# 'warn', 'report' or 'ignore'. The choices 'ask' and 'warn' are not supported
-# by all guis, since they should bring up a dialog box. The 'warn' dialog is
-# designed to confirm errors and the 'ask' dialog is usually used for panics
-# and asks the user how to proceed.
-#
-# It is also possible to specify the 'action' to do for each Bochs facility
-# separately (e.g. crash on panics from everything except the cdrom, and only
-# report those). See the 'log function' module list in the user documentation.
-#
-# If you are experiencing many panics, it can be helpful to change
-# the panic action to report instead of fatal.  However, be aware
-# that anything executed after a panic is uncharted territory and can
-# cause bochs to become unstable.  The panic is a "graceful exit," so
-# if you disable it you may get a spectacular disaster instead.
-#=======================================================================
-panic: action=ask
-error: action=report
-info: action=report
-debug: action=ignore  #, pci=report # report BX_DEBUG from module 'pci'
-
-#=======================================================================
-# DEBUGGER_LOG:
-# Give the path of the log file you'd like Bochs to log debugger output.
-# If you really don't want it, make it /dev/null or '-'. :^(
-#
-# Examples:
-#   debugger_log: ./debugger.out
-#=======================================================================
-#debugger_log: /dev/null
-#debugger_log: debugger.out
-debugger_log: -
-
-#=======================================================================
-# COM1, COM2, COM3, COM4:
-# This defines a serial port (UART type 16550A). In the 'term' mode you can
-# specify a device to use as com1. This can be a real serial line, or a pty.
-# To use a pty (under X/Unix), create two windows (xterms, usually).  One of
-# them will run bochs, and the other will act as com1. Find out the tty the com1
-# window using the `tty' command, and use that as the `dev' parameter.
-# Then do `sleep 1000000' in the com1 window to keep the shell from
-# messing with things, and run bochs in the other window.  Serial I/O to
-# com1 (port 0x3f8) will all go to the other window.
-# In socket* and pipe* (win32 only) modes Bochs becomes either socket/named pipe
-# client or server. In client mode it connects to an already running server (if
-# connection fails Bochs treats com port as not connected). In server mode it
-# opens socket/named pipe and waits until a client application connects to it
-# before starting simulation. This mode is useful for remote debugging (e.g.
-# with gdb's "target remote host:port" command or windbg's command line option
-# -k com:pipe,port=\\.\pipe\pipename). Socket modes use simple TCP communication,
-#  pipe modes use duplex byte mode pipes.
-# Other serial modes are 'null' (no input/output), 'file' (output to a file
-# specified as the 'dev' parameter and changeable at runtime), 'raw' (use the
-# real serial port - partly implemented on win32), 'mouse' (standard serial
-# mouse - requires mouse option setting 'type=serial', 'type=serial_wheel' or
-# 'type=serial_msys').
-#
-# Examples:
-#   com1: enabled=1, mode=null
-#   com1: enabled=1, mode=mouse
-#   com2: enabled=1, mode=file, dev=serial.out
-#   com3: enabled=1, mode=raw, dev=com1
-#   com3: enabled=1, mode=socket-client, dev=localhost:8888
-#   com3: enabled=1, mode=socket-server, dev=localhost:8888
-#   com4: enabled=1, mode=pipe-client, dev=\\.\pipe\mypipe
-#   com4: enabled=1, mode=pipe-server, dev=\\.\pipe\mypipe
-#=======================================================================
-com1: enabled=1, mode=file, dev=/dev/stdout
-
-#=======================================================================
-# PARPORT1, PARPORT2:
-# This defines a parallel (printer) port. When turned on and an output file is
-# defined the emulated printer port sends characters printed by the guest OS
-# into the output file. On some platforms a device filename can be used to
-# send the data to the real parallel port (e.g. "/dev/lp0" on Linux, "lpt1" on
-# win32 platforms). The output file can be changed at runtime.
-#
-# Examples:
-#   parport1: enabled=1, file="parport.out"
-#   parport2: enabled=1, file="/dev/lp0"
-#   parport1: enabled=0
-#=======================================================================
-#parport1: enabled=1, file="parport.out"
-
-#=======================================================================
-# SOUND:
-# This defines the lowlevel sound driver(s) for the wave (PCM) input / output
-# and the MIDI output feature and (if necessary) the devices to be used.
-# It can have several of the following properties.
-# All properties are in the format sound: property=value
-#
-# waveoutdrv:
-#      This defines the driver to be used for the waveout feature.
-#      Possible values are 'file' (all wave data sent to file), 'dummy' (no
-#      output) and the platform-dependant drivers 'alsa', 'oss', 'osx', 'sdl'
-#      and 'win'.
-# waveout:
-#      This defines the device to be used for wave output (if necessary) or
-#      the output file for the 'file' driver.
-# waveindrv:
-#      This defines the driver to be used for the wavein feature.
-#      Possible values are 'dummy' (recording silence) and platform-dependent
-#      drivers 'alsa', 'oss', 'sdl' and 'win'.
-# wavein:
-#      This defines the device to be used for wave input (if necessary).
-# midioutdrv:
-#      This defines the driver to be used for the MIDI output feature.
-#      Possible values are 'file' (all MIDI data sent to file), 'dummy' (no
-#      output) and platform-dependent drivers 'alsa', 'oss', 'osx' and 'win'.
-# midiout:
-#      This defines the device to be used for MIDI output (if necessary).
-# driver:
-#      This defines the driver to be used for all sound features with one
-#      property. Possible values are 'default' (platform default) and all
-#      other choices described above. Overriding one or more settings with
-#      the specific driver parameter is possible.
-#
-# Example for different drivers:
-#   sound: waveoutdrv=sdl, waveindrv=alsa, midioutdrv=dummy
-#=======================================================================
-#sound: driver=default, waveout=/dev/dsp. wavein=, midiout=
-
-#=======================================================================
-# SPEAKER:
-# This defines the PC speaker output mode. In the 'sound' mode the beep
-# is generated by the square wave generator which is a part of the
-# lowlevel sound support. The 'system' mode is only available on Linux
-# and Windows. On Linux /dev/console is used for output and on Windows
-# the Beep() function. The 'gui' mode forwards the beep to the related
-# gui methods (currently only used by the Carbon gui).
-#=======================================================================
-#speaker: enabled=0, mode=sound
-
-#=======================================================================
-# SB16:
-# This defines the SB16 sound emulation. It can have several of the
-# following properties.
-# All properties are in the format sb16: property=value
-#
-# enabled:
-#      This optional property controls the presence of the SB16 emulation.
-#      The emulation is turned on unless this property is used and set to 0.
-# midimode: This parameter specifies what to do with the MIDI output.
-#      0 = no output
-#      1 = output to device specified with the sound option (system dependent)
-#      2 = MIDI or raw data output to file (depends on file name extension)
-#      3 = dual output (mode 1 and 2 at the same time)
-# midifile: This is the file where the midi output is stored (midimode 2 or 3).
-# wavemode: This parameter specifies what to do with the PCM output.
-#      0 = no output
-#      1 = output to device specified with the sound option (system dependent)
-#      2 = VOC, WAV or raw data output to file (depends on file name extension)
-#      3 = dual output (mode 1 and 2 at the same time)
-# wavefile: This is the file where the wave output is stored (wavemode 2 or 3).
-# loglevel:
-#      0=no log
-#      1=resource changes, midi program and bank changes
-#      2=severe errors
-#      3=all errors
-#      4=all errors plus all port accesses
-#      5=all errors and port accesses plus a lot of extra info
-# log:  The file to write the sb16 emulator messages to.
-# dmatimer:
-#      microseconds per second for a DMA cycle.  Make it smaller to fix
-#      non-continuous sound.  750000 is usually a good value.  This needs a
-#      reasonably correct setting for the IPS parameter of the CPU option.
-#
-# Examples for output modes:
-#   sb16: midimode=2, midifile="output.mid", wavemode=1 # MIDI to file
-#   sb16: midimode=1, wavemode=3, wavefile="output.wav" # wave to file and device
-#=======================================================================
-#sb16: midimode=1, wavemode=1, loglevel=2, log=sb16.log, dmatimer=600000
-
-#=======================================================================
-# ES1370:
-# This defines the ES1370 sound emulation (recording and playback - except
-# DAC1+DAC2 output at the same time). The parameter 'enabled' controls the
-# presence of the device. The wave and MIDI output can be sent to device, file
-# or both using the parameters 'wavemode', 'wavefile', 'midimode' and
-# 'midifile'. See the description of these parameters at the SB16 directive.
-#
-# Examples:
-#   es1370: enabled=1, wavemode=1                       # use 'sound' parameters
-#   es1370: enabled=1, wavemode=2, wavefile=output.voc  # send output to file
-#=======================================================================
-#es1370: enabled=1, wavemode=1
-
-#=======================================================================
-# ne2k: NE2000 compatible ethernet adapter
-#
-# Format:
-# ne2k: enabled=1, ioaddr=IOADDR, irq=IRQ, mac=MACADDR, ethmod=MODULE,
-#       ethdev=DEVICE, script=SCRIPT, bootrom=BOOTROM
-#
-# IOADDR, IRQ: You probably won't need to change ioaddr and irq, unless there
-# are IRQ conflicts. These arguments are ignored when assign the ne2k to a
-# PCI slot.
-#
-# MAC: The MAC address MUST NOT match the address of any machine on the net.
-# Also, the first byte must be an even number (bit 0 set means a multicast
-# address), and you cannot use ff:ff:ff:ff:ff:ff because that's the broadcast
-# address.  For the ethertap module, you must use fe:fd:00:00:00:01.  There may
-# be other restrictions too.  To be safe, just use the b0:c4... address.
-#
-# ETHDEV: The ethdev value is the name of the network interface on your host
-# platform.  On UNIX machines, you can get the name by running ifconfig.  On
-# Windows machines, you must run niclist to get the name of the ethdev.
-# Niclist source code is in misc/niclist.c and it is included in Windows
-# binary releases.
-# The 'socket' module uses this parameter to specify the UDP port for
-# receiving packets and (optional) the host to connect.
-#
-# SCRIPT: The script value is optional, and is the name of a script that
-# is executed after bochs initialize the network interface. You can use
-# this script to configure this network interface, or enable masquerading.
-# This is mainly useful for the tun/tap devices that only exist during
-# Bochs execution. The network interface name is supplied to the script
-# as first parameter.
-# The 'slirp' module uses this parameter to specify a config file for
-# setting up an alternative IP configuration or additional features.
-# The 'vnet' module uses this parameter to specify an alternative
-# log file name.
-#
-# BOOTROM: The bootrom value is optional, and is the name of the ROM image
-# to load. Note that this feature is only implemented for the PCI version of
-# the NE2000.
-#
-# If you don't want to make connections to any physical networks,
-# you can use the following 'ethmod's to simulate a virtual network.
-#   null: All packets are discarded, but logged to a few files.
-#   vde:  Virtual Distributed Ethernet
-#   vnet: ARP, ICMP-echo(ping), DHCP and read/write TFTP are simulated.
-#         The virtual host uses 192.168.10.1.
-#         DHCP assigns 192.168.10.2 to the guest.
-#         TFTP uses the 'ethdev' value for the root directory and doesn't
-#         overwrite files.
-# socket: Connect up to 6 Bochs instances with external program 'bxhub'
-#         (simulating an ethernet hub). It provides the same services as the
-#         'vnet' module and assigns IP addresses like 'slirp' (10.0.2.x).
-#
-#=======================================================================
-# ne2k: ioaddr=0x300, irq=9, mac=fe:fd:00:00:00:01, ethmod=fbsd, ethdev=en0 #macosx
-# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:00, ethmod=fbsd, ethdev=xl0
-# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0
-# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=win32, ethdev=MYCARD
-# ne2k: ioaddr=0x300, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0
-# ne2k: ioaddr=0x300, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun0, script=./tunconfig
-# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=null, ethdev=eth0
-# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=vde, ethdev="/tmp/vde.ctl"
-# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=vnet, ethdev="c:/temp"
-# ne2k: mac=b0:c4:20:00:00:01, ethmod=socket, ethdev=40000 # use localhost
-# ne2k: mac=b0:c4:20:00:00:01, ethmod=socket, ethdev=mymachine:40000
-# ne2k: mac=b0:c4:20:00:00:01, ethmod=slirp, script=slirp.conf, bootrom=ne2k_pci.rom
-
-#=======================================================================
-# pcipnic: Bochs/Etherboot pseudo-NIC
-#
-# Format:
-# pcipnic: enabled=1, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT,
-#          bootrom=BOOTROM
-#
-# The pseudo-NIC accepts the same syntax (for mac, ethmod, ethdev, script,
-# bootrom) and supports the same networking modules as the NE2000 adapter.
-#=======================================================================
-#pcipnic: enabled=1, mac=b0:c4:20:00:00:00, ethmod=vnet
-
-#=======================================================================
-# e1000: Intel(R) 82540EM Gigabit Ethernet adapter
-#
-# Format:
-# e1000: enabled=1, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT
-#        bootrom=BOOTROM
-#
-# The E1000 accepts the same syntax (for mac, ethmod, ethdev, script, bootrom)
-# and supports the same networking modules as the NE2000 adapter.
-#=======================================================================
-#e1000: enabled=1, mac=52:54:00:12:34:56, ethmod=slirp, script=slirp.conf
-
-#=======================================================================
-# USB_UHCI:
-# This option controls the presence of the USB root hub which is a part
-# of the i440FX PCI chipset. With the portX parameter you can connect devices
-# to the hub (currently supported: 'mouse', 'tablet', 'keypad', 'disk', 'cdrom',
-# 'floppy', 'hub' and 'printer').
-#
-# If you connect the mouse or tablet to one of the ports, Bochs forwards the
-# mouse movement data to the USB device instead of the selected mouse type.
-# When connecting the keypad to one of the ports, Bochs forwards the input of
-# the numeric keypad to the USB device instead of the PS/2 keyboard.
-#
-# To connect a 'flat' mode image as a USB hardisk you can use the 'disk' device
-# with the path to the image separated with a colon. To use other disk image modes
-# similar to ATA disks the syntax 'disk:mode:filename' must be used (see below).
-#
-# To emulate a USB cdrom you can use the 'cdrom' device name and the path to
-# an ISO image or raw device name also separated with a colon. An option to
-# insert/eject media is available in the runtime configuration.
-#
-# To emulate a USB floppy you can use the 'floppy' device with the path to the
-# image separated with a colon. To use the VVFAT image mode similar to the
-# legacy floppy the syntax 'floppy:vvfat:directory' must be used (see below).
-# An option to insert/eject media is available in the runtime configuration.
-#
-# The device name 'hub' connects an external hub with max. 8 ports (default: 4)
-# to the root hub. To specify the number of ports you have to add the value
-# separated with a colon. Connecting devices to the external hub ports is only
-# available in the runtime configuration.
-#
-# The device 'printer' emulates the HP Deskjet 920C printer. The PCL data is
-# sent to a file specified in bochsrc.txt. The current code appends the PCL
-# code to the file if the file already existed. The output file can be
-# changed at runtime.
-#
-# The optionsX parameter can be used to assign specific options to the device
-# connected to the corresponding USB port. Currently this feature is used to
-# set the speed reported by device ('low', 'full', 'high' or 'super'). The
-# availabe speed choices depend on both HC and device. The option 'debug' turns
-# on debug output for the device at connection time.
-# For the USB 'disk' device the optionsX parameter can be used to specify an
-# alternative redolog file (journal) of some image modes. For 'vvfat' mode USB
-# disks the optionsX parameter can be used to specify the disk size (range
-# 128M ... 128G). If the size is not specified, it defaults to 504M.
-# For the USB 'floppy' device the optionsX parameter can be used to specify an
-# alternative device ID to be reported. Currently only the model "teac" is
-# supported (can fix hw detection in some guest OS). The USB floppy also
-# accepts the parameter "write_protected" with valid values 0 and 1 to select
-# the access mode (default is 0).
-#=======================================================================
-#usb_uhci: enabled=1
-#usb_uhci: enabled=1, port1=mouse, port2=disk:usbstick.img
-#usb_uhci: enabled=1, port1=hub:7, port2=disk:growing:usbdisk.img
-#usb_uhci: enabled=1, port2=disk:undoable:usbdisk.img, options2=journal:redo.log
-#usb_uhci: enabled=1, port2=disk:usbdisk2.img, options2=sect_size:1024
-#usb_uhci: enabled=1, port2=disk:vvfat:vvfat, options2="debug,speed:full"
-#usb_uhci: enabled=1, port1=printer:printdata.bin, port2=cdrom:image.iso
-#usb_uhci: enabled=1, port2=floppy:vvfat:diskette, options2="model:teac"
-
-#=======================================================================
-# USB_OHCI:
-# This option controls the presence of the USB OHCI host controller with a
-# 2-port hub. The portX parameter accepts the same device types with the same
-# syntax as the UHCI controller (see above). The optionsX parameter is also
-# available on OHCI.
-#=======================================================================
-#usb_ohci: enabled=1
-#usb_ohci: enabled=1, port1=printer:usbprinter.bin
-
-#=======================================================================
-# USB_EHCI:
-# This option controls the presence of the USB EHCI host controller with a
-# 6-port hub. The portX parameter accepts the same device types with the
-# same syntax as the UHCI controller (see above). The optionsX parameter is
-# also available on EHCI.
-#=======================================================================
-#usb_ehci: enabled=1
-
-#=======================================================================
-# USB_XHCI:
-# This option controls the presence of the USB xHCI host controller with a
-# 4-port hub. The portX parameter accepts the same device types with the
-# same syntax as the UHCI controller (see above). The optionsX parameter is
-# also available on xHCI. NOTE: port 1 and 2 are USB3 and only support
-# super-speed devices, but port 3 and 4 are USB2 and support speed settings
-# low, full and high.
-#=======================================================================
-#usb_xhci: enabled=1
-
-#=======================================================================
-# PCIDEV:
-# PCI host device mapping
-# WARNING: This Bochs feature is not maintained yet and may fail.
-#=======================================================================
-#pcidev: vendor=0x1234, device=0x5678
-
-#=======================================================================
-# GDBSTUB:
-# Enable GDB stub. See user documentation for details.
-# Default value is enabled=0.
-# WARNING: This Bochs feature is not maintained yet and may fail.
-#=======================================================================
-#gdbstub: enabled=0, port=1234, text_base=0, data_base=0, bss_base=0
-
-#=======================================================================
-# MAGIC_BREAK:
-# This enables the "magic breakpoint" feature when using the debugger.
-# The useless cpu instruction XCHG BX, BX causes Bochs to enter the
-# debugger mode. This might be useful for software development.
-#
-# Example:
-#   magic_break: enabled=1
-#=======================================================================
-magic_break: enabled=1
-
-#=======================================================================
-# DEBUG_SYMBOLS:
-# This loads symbols from the specified file for use in Bochs' internal
-# debugger. Symbols are loaded into global context. This is equivalent to
-# issuing ldsym debugger command at start up.
-#
-# Example:
-#   debug_symbols: file="kernel.sym"
-#   debug_symbols: file="kernel.sym", offset=0x80000000
-#=======================================================================
-#debug_symbols: file="kernel.sym"
-
-#print_timestamps: enabled=1
-
-#=======================================================================
-# PORT_E9_HACK:
-# The 0xE9 port doesn't exists in normal ISA architecture. However, we
-# define a convention here, to display on the console of the system running
-# Bochs anything that is written to it. The idea is to provide debug output
-# very early when writing BIOS or OS code for example, without having to
-# bother with setting up a serial port or etc. Reading from port 0xE9 will
-# will return 0xe9 to let you know if the feature is available.
-# Leave this 0 unless you have a reason to use it.
-#
-# Example:
-#   port_e9_hack: enabled=1
-#=======================================================================
-#port_e9_hack: enabled=1
-
-#=======================================================================
-# other stuff
-#=======================================================================
-# WARNING: This Bochs feature is not maintained yet. Is it still used ?
-# To use it, set BX_LOAD32BITOSHACK in config.h to 1 and recompile Bochs.
-#load32bitOSImage: os=nullkernel, path=../kernel.img, iolog=../vga_io.log
-#load32bitOSImage: os=linux, path=../linux.img, iolog=../vga_io.log, initrd=../initrd.img
-
-#=======================================================================
-# fullscreen: ONLY IMPLEMENTED ON AMIGA
-#             Request that Bochs occupy the entire screen instead of a
-#             window.
-#
-# Examples:
-#   fullscreen: enabled=0
-#   fullscreen: enabled=1
-#=======================================================================
-#fullscreen: enabled=0
-#screenmode: name="sample"
-
-#=======================================================================
-# USER_PLUGIN:
-# Load user-defined plugin. This option is available only if Bochs is
-# compiled with plugin support. Maximum 8 different plugins are supported.
-# See the example in the Bochs sources how to write a plugin device.
-#=======================================================================
-#user_plugin: name=testdev
-
-#=======================================================================
-# for Macintosh, use the style of pathnames in the following
-# examples.
-#
-# vgaromimage: :bios:VGABIOS-elpin-2.40
-# romimage: file=:bios:BIOS-bochs-latest, address=0xf0000
-# floppya: 1_44=[fd:], status=inserted
-#=======================================================================
-
-#=======================================================================
-# MEGS
-# Set the number of Megabytes of physical memory you want to emulate.
-# The default is 32MB, most OS's won't need more than that.
-# The maximum amount of memory supported is 2048Mb.
-# The 'MEGS' option is deprecated. Use 'MEMORY' option instead.
-#=======================================================================
-#megs: 256
-#megs: 128
-#megs: 64
-#megs: 32
-#megs: 16
-#megs: 8
diff --git a/ape/etc/bochsrc.ffs b/ape/etc/bochsrc.ffs
deleted file mode 100644
index 3467144ef..000000000
--- a/ape/etc/bochsrc.ffs
+++ /dev/null
@@ -1,1294 +0,0 @@
-# The default state is the unsafest state with Bochs, which makes it nearly
-# impossible to script. Here we'll attempt to turn off as much of its
-# functionality as possible, so we can have a non-interactive mode.
-
-#=======================================================================
-# PLUGIN_CTRL:
-# Controls the presence of optional device plugins. These plugins are loaded
-# directly with this option and some of them install a config option that is
-# only available when the plugin device is loaded. The value "1" means to load
-# the plugin and "0" will unload it (if loaded before).
-#
-# These plugins will be loaded by default (if present): 'biosdev', 'extfpuirq',
-# 'gameport', 'iodebug','parallel', 'serial', 'speaker' and 'unmapped'.
-#
-# These plugins are also supported, but they are usually loaded directly with
-# their bochsrc option: 'e1000', 'es1370', 'ne2k', 'pcidev', 'pcipnic', 'sb16',
-# 'usb_ehci', 'usb_ohci', 'usb_uhci', 'usb_xhci' and 'voodoo'.
-#=======================================================================
-#plugin_ctrl: unmapped=0, e1000=1 # unload 'unmapped' and load 'e1000'
-plugin_ctrl: biosdev=0, iodebug=0
-
-#=======================================================================
-# CONFIG_INTERFACE
-#
-# The configuration interface is a series of menus or dialog boxes that
-# allows you to change all the settings that control Bochs's behavior.
-# Depending on the platform there are up to 3 choices of configuration
-# interface: a text mode version called "textconfig" and two graphical versions
-# called "win32config" and "wx".  The text mode version uses stdin/stdout and
-# is always compiled in, unless Bochs is compiled for wx only. The choice
-# "win32config" is only available on win32 and it is the default there.
-# The choice "wx" is only available when you use "--with-wx" on the configure
-# command.  If you do not write a config_interface line, Bochs will
-# choose a default for you.
-#
-# NOTE: if you use the "wx" configuration interface, you must also use
-# the "wx" display library.
-#=======================================================================
-#config_interface: textconfig
-#config_interface: win32config
-#config_interface: wx
-
-#=======================================================================
-# DISPLAY_LIBRARY
-#
-# The display library is the code that displays the Bochs VGA screen.  Bochs
-# has a selection of about 10 different display library implementations for
-# different platforms.  If you run configure with multiple --with-* options,
-# the display_library command lets you choose which one you want to run with.
-# If you do not write a display_library line, Bochs will choose a default for
-# you.
-#
-# The choices are:
-#   x              use X windows interface, cross platform
-#   win32          use native win32 libraries
-#   carbon         use Carbon library (for MacOS X)
-#   macintosh      use MacOS pre-10
-#   amigaos        use native AmigaOS libraries
-#   sdl            use SDL 1.2.x library, cross platform
-#   sdl2           use SDL 2.x library, cross platform
-#   svga           use SVGALIB library for Linux, allows graphics without X11
-#   term           text only, uses curses/ncurses library, cross platform
-#   rfb            provides an interface to AT&T's VNC viewer, cross platform
-#   vncsrv         use LibVNCServer for extended RFB(VNC) support
-#   wx             use wxWidgets library, cross platform
-#   nogui          no display at all
-#
-# NOTE: if you use the "wx" configuration interface, you must also use
-# the "wx" display library.
-#
-# Specific options:
-# Some display libraries now support specific options to control their
-# behaviour. These options are supported by more than one display library:
-#
-# "gui_debug"   - use GTK debugger gui (sdl, sdl2, x) / Win32 debugger gui (sdl,
-#                 sdl2, win32)
-# "hideIPS"     - disable IPS output in status bar (rfb, sdl, sdl2, vncsrv,
-#                 win32, wx, x)
-# "nokeyrepeat" - turn off host keyboard repeat (sdl, sdl2, win32, x)
-# "timeout"     - time (in seconds) to wait for client (rfb, vncsrv)
-#
-# See the examples below for other currently supported options.
-#=======================================================================
-#display_library: amigaos
-#display_library: carbon
-#display_library: macintosh
-display_library: nogui
-#display_library: rfb
-#display_library: sdl, options="fullscreen" # startup in fullscreen mode
-#display_library: sdl2, options="fullscreen" # startup in fullscreen mode
-#display_library: term
-#display_library: vncsrv
-# "traphotkeys" - system hotkeys not handled by host OS, but sent to guest
-#                 (win32 in mouse capture and fullscreen mode: alt-tab, win,
-#                 alt-space, alt-esc, ctrl-esc)
-#display_library: win32, options="traphotkeys"
-#display_library: wx
-#display_library: x, gui_debug=1
-#display_library: x, options="gui_debug"
-
-#=======================================================================
-# CPU:
-# This defines cpu-related parameters inside Bochs:
-#
-#  MODEL:
-#    Selects CPU configuration to emulate from pre-defined list of all
-#    supported configurations. When this option is used and the value
-#    is different from 'bx_generic', the parameters of the CPUID option
-#    have no effect anymore.
-#
-#  CPU configurations that can be selected:
-# -----------------------------------------------------------------
-#  pentium                    Intel Pentium (P54C)
-#  pentium_mmx                Intel Pentium MMX
-#  amd_k6_2_chomper           AMD-K6(tm) 3D processor (Chomper)
-#  p2_klamath                 Intel Pentium II (Klamath)
-#  p3_katmai                  Intel Pentium III (Katmai)
-#  p4_willamette              Intel(R) Pentium(R) 4 (Willamette)
-#  core_duo_t2400_yonah       Intel(R) Core(TM) Duo CPU T2400 (Yonah)
-#  atom_n270                  Intel(R) Atom(TM) CPU N270
-#  p4_prescott_celeron_336    Intel(R) Celeron(R) 336 (Prescott)
-#  athlon64_clawhammer        AMD Athlon(tm) 64 Processor 2800+ (Clawhammer)
-#  athlon64_venice            AMD Athlon(tm) 64 Processor 3000+ (Venice)
-#  turion64_tyler             AMD Turion(tm) 64 X2 Mobile TL-60 (Tyler)
-#  phenom_8650_toliman        AMD Phenom X3 8650 (Toliman)
-#  core2_penryn_t9600         Intel Mobile Core 2 Duo T9600 (Penryn)
-#  corei5_lynnfield_750       Intel(R) Core(TM) i5   750 (Lynnfield)
-#  corei5_arrandale_m520      Intel(R) Core(TM) i5 M 520 (Arrandale)
-#  corei7_sandy_bridge_2600k  Intel(R) Core(TM) i7-2600K (Sandy Bridge)
-#  zambezi                    AMD FX(tm)-4100 Quad-Core Processor (Zambezi)
-#  trinity_apu                AMD A8-5600K APU (Trinity)
-#  ryzen                      AMD Ryzen 7 1700
-#  corei7_ivy_bridge_3770k    Intel(R) Core(TM) i7-3770K CPU (Ivy Bridge)
-#  corei7_haswell_4770        Intel(R) Core(TM) i7-4770 CPU (Haswell)
-#  broadwell_ult              Intel(R) Processor 5Y70 CPU (Broadwell)
-#
-#  COUNT:
-#    Set the number of processors:cores per processor:threads per core when
-#    Bochs is compiled for SMP emulation. Bochs currently supports up to
-#    14 threads (legacy APIC) or 254 threads (xAPIC or higher) running
-#    simultaniosly. If Bochs is compiled without SMP support, it won't accept
-#    values different from 1.
-#
-#  QUANTUM:
-#    Maximum amount of instructions allowed to execute by processor before
-#    returning control to another cpu. This option exists only in Bochs
-#    binary compiled with SMP support.
-#
-#  RESET_ON_TRIPLE_FAULT:
-#    Reset the CPU when triple fault occur (highly recommended) rather than
-#    PANIC. Remember that if you trying to continue after triple fault the
-#    simulation will be completely bogus !
-#
-#  CPUID_LIMIT_WINNT:
-#    Determine whether to limit maximum CPUID function to 2. This mode is
-#    required to workaround WinNT installation and boot issues.
-#
-#  MSRS:
-#    Define path to user CPU Model Specific Registers (MSRs) specification.
-#    See example in msrs.def.
-#
-#  IGNORE_BAD_MSRS:
-#    Ignore MSR references that Bochs does not understand; print a warning
-#    message instead of generating #GP exception. This option is enabled
-#    by default but will not be avaiable if configurable MSRs are enabled.
-#
-#  MWAIT_IS_NOP:
-#    When this option is enabled MWAIT will not put the CPU into a sleep state.
-#    This option exists only if Bochs compiled with --enable-monitor-mwait.
-#
-#  IPS:
-#    Emulated Instructions Per Second. This is the number of IPS that bochs
-#    is capable of running on your machine. You can recompile Bochs with
-#    --enable-show-ips option enabled, to find your host's capability.
-#    Measured IPS value will then be logged into your log file or shown
-#    in the status bar (if supported by the gui).
-#
-#    IPS is used to calibrate many time-dependent events within the bochs
-#    simulation.  For example, changing IPS affects the frequency of VGA
-#    updates, the duration of time before a key starts to autorepeat, and
-#    the measurement of BogoMips and other benchmarks.
-#
-#  Examples:
-#
-#  Bochs Machine/Compiler                                 Mips
-# ______________________________________________________________________
-#  2.4.6 3.4Ghz Intel Core i7 2600 with Win7x64/g++ 4.5.2 85 to 95 Mips
-#  2.3.7 3.2Ghz Intel Core 2 Q9770 with WinXP/g++ 3.4     50 to 55 Mips
-#  2.3.7 2.6Ghz Intel Core 2 Duo with WinXP/g++ 3.4       38 to 43 Mips
-#  2.2.6 2.6Ghz Intel Core 2 Duo with WinXP/g++ 3.4       21 to 25 Mips
-#  2.2.6 2.1Ghz Athlon XP with Linux 2.6/g++ 3.4          12 to 15 Mips
-#=======================================================================
-#cpu: model=core2_penryn_t9600, count=1, ips=50000000, reset_on_triple_fault=1, ignore_bad_msrs=1, msrs="msrs.def"
-#cpu: model=core2_penryn_t9600, count=1, ips=50000000, reset_on_triple_fault=0 cpuid_limit_winnt=1
-#cpu: model=corei7_haswell_4770, count=1, ips=50000000, reset_on_triple_fault=0
-#cpu: model=broadwell_ult, count=1, ips=50000000, reset_on_triple_fault=0
-#cpu: model=corei7_ivy_bridge_3770k, count=1, ips=50000000, reset_on_triple_fault=0
-#cpu: model=corei5_lynnfield_750, count=1, ips=50000000, reset_on_triple_fault=0
-
-#=======================================================================
-# CPUID:
-#
-# This defines features and functionality supported by Bochs emulated CPU.
-# The option has no offect if CPU model was selected in CPU option.
-#
-#  MMX:
-#    Select MMX instruction set support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 5.
-#
-#  APIC:
-#    Select APIC configuration (LEGACY/XAPIC/XAPIC_EXT/X2APIC).
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 5.
-#
-#  SEP:
-#    Select SYSENTER/SYSEXIT instruction set support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  SIMD:
-#    Select SIMD instructions support.
-#    Any of NONE/SSE/SSE2/SSE3/SSSE3/SSE4_1/SSE4_2/AVX/AVX2/AVX512
-#    could be selected.
-#
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#    The AVX choises exists only if Bochs compiled with --enable-avx option.
-#
-#  SSE4A:
-#    Select AMD SSE4A instructions support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  MISALIGNED_SSE:
-#    Select AMD Misaligned SSE mode support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  AES:
-#    Select AES instruction set support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  SHA:
-#    Select SHA instruction set support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  MOVBE:
-#    Select MOVBE Intel(R) Atom instruction support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  ADX:
-#    Select ADCX/ADOX instructions support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  XSAVE:
-#    Select XSAVE extensions support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  XSAVEOPT:
-#    Select XSAVEOPT instruction support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  AVX_F16C:
-#    Select AVX float16 convert instructions support.
-#    This option exists only if Bochs compiled with --enable-avx option.
-#
-#  AVX_FMA:
-#    Select AVX fused multiply add (FMA) instructions support.
-#    This option exists only if Bochs compiled with --enable-avx option.
-#
-#  BMI:
-#    Select BMI1/BMI2 instructions support.
-#    This option exists only if Bochs compiled with --enable-avx option.
-#
-#  XOP:
-#    Select AMD XOP instructions support.
-#    This option exists only if Bochs compiled with --enable-avx option.
-#
-#  FMA4:
-#    Select AMD four operand FMA instructions support.
-#    This option exists only if Bochs compiled with --enable-avx option.
-#
-#  TBM:
-#    Select AMD Trailing Bit Manipulation (TBM) instructions support.
-#    This option exists only if Bochs compiled with --enable-avx option.
-#
-#  X86-64:
-#    Enable x86-64 and long mode support.
-#    This option exists only if Bochs compiled with x86-64 support.
-#
-#  1G_PAGES:
-#    Enable 1G page size support in long mode.
-#    This option exists only if Bochs compiled with x86-64 support.
-#
-#  PCID:
-#    Enable Process-Context Identifiers (PCID) support in long mode.
-#    This option exists only if Bochs compiled with x86-64 support.
-#
-#  FSGSBASE:
-#    Enable GS/GS BASE access instructions support in long mode.
-#    This option exists only if Bochs compiled with x86-64 support.
-#
-#  SMEP:
-#    Enable Supervisor Mode Execution Protection (SMEP) support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  SMAP:
-#    Enable Supervisor Mode Access Prevention (SMAP) support.
-#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
-#
-#  MWAIT:
-#    Select MONITOR/MWAIT instructions support.
-#    This option exists only if Bochs compiled with --enable-monitor-mwait.
-#
-#  VMX:
-#    Select VMX extensions emulation support.
-#    This option exists only if Bochs compiled with --enable-vmx option.
-#
-#  SVM:
-#    Select AMD SVM (Secure Virtual Machine) extensions emulation support.
-#    This option exists only if Bochs compiled with --enable-svm option.
-#
-#  VENDOR_STRING:
-#    Set the CPUID vendor string returned by CPUID(0x0). This should be a
-#    twelve-character ASCII string.
-#
-#  BRAND_STRING:
-#    Set the CPUID vendor string returned by CPUID(0x80000002 .. 0x80000004).
-#    This should be at most a forty-eight-character ASCII string.
-#
-#  LEVEL:
-#    Set emulated CPU level information returned by CPUID. Default value is
-#    determined by configure option --enable-cpu-level. Currently supported
-#    values are 5 (for Pentium and similar processors) and 6 (for P6 and
-#    later processors).
-#
-#  FAMILY:
-#    Set model information returned by CPUID. Default family value determined
-#    by configure option --enable-cpu-level.
-#
-#  MODEL:
-#    Set model information returned by CPUID. Default model value is 3.
-#
-#  STEPPING:
-#    Set stepping information returned by CPUID. Default stepping value is 3.
-#=======================================================================
-#cpuid: x86_64=1, mmx=1, sep=1, simd=sse4_2, apic=xapic, aes=1, movbe=1, xsave=1
-#cpuid: family=6, model=0x1a, stepping=5
-
-#=======================================================================
-# MEMORY
-# Set the amount of physical memory you want to emulate.
-#
-# GUEST:
-# Set amount of guest physical memory to emulate. The default is 32MB,
-# the maximum amount limited only by physical address space limitations.
-#
-# HOST:
-# Set amount of host memory you want to allocate for guest RAM emulation.
-# It is possible to allocate less memory than you want to emulate in guest
-# system. This will fake guest to see the non-existing memory. Once guest
-# system touches new memory block it will be dynamically taken from the
-# memory pool. You will be warned (by FATAL PANIC) in case guest already
-# used all allocated host memory and wants more.
-#
-#=======================================================================
-memory: guest=32, host=32
-
-#=======================================================================
-# ROMIMAGE:
-# The ROM BIOS controls what the PC does when it first powers on.
-# Normally, you can use a precompiled BIOS in the source or binary
-# distribution called BIOS-bochs-latest. The default ROM BIOS is usually loaded
-# starting at address 0xfffe0000, and it is exactly 128k long. The legacy
-# version of the Bochs BIOS is usually loaded starting at address 0xffff0000,
-# and it is exactly 64k long.
-# You can use the environment variable $BXSHARE to specify the location
-# of the BIOS.
-# The usage of external large BIOS images (up to 512k) at memory top is
-# now supported, but we still recommend to use the BIOS distributed with Bochs.
-# The start address is optional, since it can be calculated from image size.
-# The Bochs BIOS currently supports only the option "fastboot" to skip the
-# boot menu delay.
-#=======================================================================
-#romimage: file=$BXSHARE/BIOS-bochs-latest, options=fastboot
-romimage: file=$BXSHARE/BIOS-bochs-legacy, options=fastboot
-#romimage: file=$BXSHARE/bios.bin-1.7.5 # http://www.seabios.org/SeaBIOS
-#romimage: file=mybios.bin, address=0xfff80000 # 512k at memory top
-#romimage: file=BIOS-bochs-latest, options=fastboot
-
-#=======================================================================
-# VGAROMIMAGE
-# You now need to load a VGA ROM BIOS into C0000.
-#=======================================================================
-#vgaromimage: file=$BXSHARE/VGABIOS-elpin-2.40
-#vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest
-#vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest-cirrus
-#vgaromimage: file=/usr/local/share/qemu/sgabios.bin
-
-#=======================================================================
-# OPTROMIMAGE[1-4]:
-# You may now load up to 4 optional ROM images. Be sure to use a
-# read-only area, typically between C8000 and EFFFF. These optional
-# ROM images should not overwrite the rombios (located at
-# F0000-FFFFF) and the videobios (located at C0000-C7FFF).
-# Those ROM images will be initialized by the bios if they contain
-# the right signature (0x55AA) and a valid checksum.
-# It can also be a convenient way to upload some arbitrary code/data
-# in the simulation, that can be retrieved by the boot loader
-#=======================================================================
-#optromimage1: file=optionalrom.bin, address=0xd0000
-#optromimage2: file=optionalrom.bin, address=0xd1000
-#optromimage3: file=optionalrom.bin, address=0xd2000
-#optromimage4: file=optionalrom.bin, address=0xd3000
-
-#optramimage1: file=/path/file1.img, address=0x0010000
-#optramimage2: file=/path/file2.img, address=0x0020000
-#optramimage3: file=/path/file3.img, address=0x0030000
-#optramimage4: file=/path/file4.img, address=0x0040000
-
-#=======================================================================
-# VGA:
-# This defines parameters related to the VGA display
-#
-#   EXTENSION
-#     Here you can specify the display extension to be used. With the value
-#     'none' you can use standard VGA with no extension. Other supported
-#     values are 'vbe' for Bochs VBE, 'cirrus' for Cirrus SVGA support and
-#     'voodoo' for Voodoo Graphics support (see 'voodoo' option).
-#
-#   UPDATE_FREQ
-#     This parameter specifies the number of display updates per second.
-#     The VGA update timer by default uses the realtime engine with a value
-#     of 5. This parameter can be changed at runtime.
-#
-#   REALTIME
-#     If set to 1 (default), the VGA timer is based on realtime, otherwise it
-#     is driven by the cpu and depends on the ips setting. If the host is slow
-#     (low ips, update_freq) and the guest uses HLT appropriately, setting this
-#     to 0 and "clock: sync=none" may improve the responsiveness of the guest
-#     GUI when the guest is otherwise idle.
-#
-# Examples:
-#   vga: extension=cirrus, update_freq=10
-#=======================================================================
-vga: extension=none, update_freq=5, realtime=1
-
-#=======================================================================
-# VOODOO:
-# This defines the Voodoo Graphics emulation (experimental). Currently
-# supported models are 'voodoo1', 'voodoo2', 'banshee' and 'voodoo3'. The
-# Voodoo2 support is not yet complete, but almost usable. The Banshee and
-# Voodoo3 support is under construction, but basicly usable. The 2D/3D cards
-# require an external VGA BIOS the vga extension option to be set to 'voodoo'.
-# If the i440BX PCI chipset is selected, they can be assigned to AGP (slot #5).
-# The gui screen update timing for all models is controlled by the related 'vga'
-# options.
-#
-# Examples:
-#   voodoo: enabled=1, model=voodoo2
-#=======================================================================
-#voodoo: enabled=1, model=voodoo1
-
-#=======================================================================
-# KEYBOARD:
-# This defines parameters related to the emulated keyboard
-#
-#   TYPE:
-#     Type of keyboard return by a "identify keyboard" command to the
-#     keyboard controller. It must be one of "xt", "at" or "mf".
-#     Defaults to "mf". It should be ok for almost everybody. A known
-#     exception is french macs, that do have a "at"-like keyboard.
-#
-#   SERIAL_DELAY:
-#     Approximate time in microseconds that it takes one character to
-#     be transferred from the keyboard to controller over the serial path.
-#
-#   PASTE_DELAY:
-#     Approximate time in microseconds between attempts to paste
-#     characters to the keyboard controller. This leaves time for the
-#     guest os to deal with the flow of characters.  The ideal setting
-#     depends on how your operating system processes characters.  The
-#     default of 100000 usec (.1 seconds) was chosen because it works
-#     consistently in Windows.
-#     If your OS is losing characters during a paste, increase the paste
-#     delay until it stops losing characters.
-#
-#   KEYMAP:
-#     This enables a remap of a physical localized keyboard to a
-#     virtualized us keyboard, as the PC architecture expects.
-#
-#   USER_SHORTCUT:
-#     This defines the keyboard shortcut to be sent when you press the "user"
-#     button in the headerbar. The shortcut string is a combination of maximum
-#     3 key names (listed below) separated with a '-' character.
-#     Valid key names:
-#     "alt", "bksl", "bksp", "ctrl", "del", "down", "end", "enter", "esc",
-#     "f1", ... "f12", "home", "ins", "left", "menu", "minus", "pgdwn", "pgup",
-#     "plus", "power", "print", "right", "scrlck", "shift", "space", "tab", "up"
-#     and "win".
-#
-# Examples:
-#   keyboard: type=mf, serial_delay=200, paste_delay=100000
-#   keyboard: keymap=gui/keymaps/x11-pc-de.map
-#   keyboard: user_shortcut=ctrl-alt-del
-#=======================================================================
-keyboard: type=mf, serial_delay=250
-
-#=======================================================================
-# MOUSE:
-# This defines parameters for the emulated mouse type, the initial status
-# of the mouse capture and the runtime method to toggle it.
-#
-#  TYPE:
-#  With the mouse type option you can select the type of mouse to emulate.
-#  The default value is 'ps2'. The other choices are 'imps2' (wheel mouse
-#  on PS/2), 'serial', 'serial_wheel', 'serial_msys' (one com port requires
-#  setting 'mode=mouse') 'inport' and 'bus' (if present). To connect a mouse
-#  to a USB port, see the 'usb_uhci', 'usb_ohci', 'usb_ehci' or 'usb_xhci'
-#  options (requires PCI and USB support).
-#
-#  ENABLED:
-#  The Bochs gui creates mouse "events" unless the 'enabled' option is
-#  set to 0. The hardware emulation itself is not disabled by this.
-#  Unless you have a particular reason for enabling the mouse by default,
-#  it is recommended that you leave it off. You can also toggle the mouse
-#  usage at runtime (RFB, SDL, Win32, wxWidgets and X11 - see below).
-#
-#  TOGGLE:
-#  The default method to toggle the mouse capture at runtime is to press the
-#  CTRL key and the middle mouse button ('ctrl+mbutton'). This option allows
-#  to change the method to 'ctrl+f10' (like DOSBox), 'ctrl+alt' (like QEMU)
-#  or 'f12'.
-#
-# Examples:
-#   mouse: enabled=1
-#   mouse: type=imps2, enabled=1
-#   mouse: type=serial, enabled=1
-#   mouse: enabled=0, toggle=ctrl+f10
-#=======================================================================
-mouse: enabled=0
-
-#=======================================================================
-# PCI:
-# This option controls the presence of a PCI chipset in Bochs. Currently it
-# supports the i430FX, i440FX and i440BX chipsets. You can also specify the
-# devices connected to PCI slots. Up to 5 slots are available. For these
-# combined PCI/ISA devices assigning to slot is mandatory if you want to emulate
-# the PCI model: cirrus, ne2k and pcivga. These PCI-only devices are also
-# supported, but they are auto-assigned if you don't use the slot configuration:
-# e1000, es1370, pcidev, pcipnic, usb_ehci, usb_ohci, usb_xhci and voodoo.
-# In case of the i440BX chipset, slot #5 is the AGP slot. Currently only the
-# 'voodoo' device can be assigned to AGP.
-#
-# Example:
-#   pci: enabled=1, chipset=i440fx, slot1=pcivga, slot2=ne2k
-#=======================================================================
-pci: enabled=1, chipset=i440fx
-
-#=======================================================================
-# CLOCK:
-# This defines the parameters of the clock inside Bochs:
-#
-#  SYNC:
-#  This defines the method how to synchronize the Bochs internal time
-#  with realtime. With the value 'none' the Bochs time relies on the IPS
-#  value and no host time synchronization is used. The 'slowdown' method
-#  sacrifices performance to preserve reproducibility while allowing host
-#  time correlation. The 'realtime' method sacrifices reproducibility to
-#  preserve performance and host-time correlation.
-#  It is possible to enable both synchronization methods.
-#
-#  RTC_SYNC:
-#  If this option is enabled together with the realtime synchronization,
-#  the RTC runs at realtime speed. This feature is disabled by default.
-#
-#  TIME0:
-#  Specifies the start (boot) time of the virtual machine. Use a time
-#  value as returned by the time(2) system call or a string as returned
-#  by the ctime(3) system call. If no time0 value is set or if time0
-#  equal to 1 (special case) or if time0 equal 'local', the simulation
-#  will be started at the current local host time. If time0 equal to 2
-#  (special case) or if time0 equal 'utc', the simulation will be started
-#  at the current utc time.
-#
-# Syntax:
-#  clock: sync=[none|slowdown|realtime|both], time0=[timeValue|local|utc]
-#
-# Example:
-#   clock: sync=none,     time0=local       # Now (localtime)
-#   clock: sync=slowdown, time0=315529200   # Tue Jan  1 00:00:00 1980
-#   clock: sync=none,     time0="Mon Jan  1 00:00:00 1990" # 631148400
-#   clock: sync=realtime, time0=938581955   # Wed Sep 29 07:12:35 1999
-#   clock: sync=realtime, time0="Sat Jan  1 00:00:00 2000" # 946681200
-#   clock: sync=none,     time0=1           # Now (localtime)
-#   clock: sync=none,     time0=utc         # Now (utc/gmt)
-#
-# Default value are sync=none, rtc_sync=0, time0=local
-#=======================================================================
-clock: sync=none, time0=local
-
-#=======================================================================
-# CMOSIMAGE:
-# This defines a binary image file with size 128 bytes that can be loaded into
-# the CMOS RAM at startup. The rtc_init parameter controls whether initialize
-# the RTC with values stored in the image. By default the time0 argument given
-# to the clock option is used. With 'rtc_init=image' the image is the source
-# for the initial time.
-#
-# Example:
-#   cmosimage: file=cmos.img, rtc_init=image
-#=======================================================================
-#cmosimage: file=cmos.img, rtc_init=time0
-
-#=======================================================================
-# private_colormap: Request that the GUI create and use it's own
-#                   non-shared colormap.  This colormap will be used
-#                   when in the bochs window.  If not enabled, a
-#                   shared colormap scheme may be used.  Not implemented
-#                   on all GUI's.
-#
-# Examples:
-#   private_colormap: enabled=1
-#   private_colormap: enabled=0
-#=======================================================================
-private_colormap: enabled=0
-
-#=======================================================================
-# FLOPPYA:
-# Point this to pathname of floppy image file or device
-# This should be of a bootable floppy(image/device) if you're
-# booting from 'a' (or 'floppy').
-#
-# You can set the initial status of the media to 'ejected' or 'inserted'.
-#   floppya: 2_88=path, status=ejected    (2.88M 3.5"  media)
-#   floppya: 1_44=path, status=inserted   (1.44M 3.5"  media)
-#   floppya: 1_2=path, status=ejected     (1.2M  5.25" media)
-#   floppya: 720k=path, status=inserted   (720K  3.5"  media)
-#   floppya: 360k=path, status=inserted   (360K  5.25" media)
-#   floppya: 320k=path, status=inserted   (320K  5.25" media)
-#   floppya: 180k=path, status=inserted   (180K  5.25" media)
-#   floppya: 160k=path, status=inserted   (160K  5.25" media)
-#   floppya: image=path, status=inserted  (guess media type from image size)
-#   floppya: 1_44=vvfat:path, status=inserted  (use directory as VFAT media)
-#   floppya: type=1_44                    (1.44M 3.5" floppy drive, no media)
-#
-# The path should be the name of a disk image file.  On Unix, you can use a raw
-# device name such as /dev/fd0 on Linux.  On win32 platforms, use drive letters
-# such as a: or b: as the path.  The parameter 'image' works with image files
-# only. In that case the size must match one of the supported types.
-# The parameter 'type' can be used to enable the floppy drive without media
-# and status specified. Usually the drive type is set up based on the media type.
-# The optional parameter 'write_protected' can be used to control the media
-# write protect switch. By default it is turned off.
-#=======================================================================
-#floppya: 1_44=, status=inserted
-#floppya: image=../1.44, status=inserted
-#floppya: 1_44=/dev/fd0H1440, status=inserted
-#floppya: 1_2=../1_2, status=inserted
-#floppya: 1_44=a:, status=inserted
-#floppya: 1_44=a.img, status=inserted, write_protected=1
-#floppya: 1_44=/dev/rfd0a, status=inserted
-#floppya: 1_44=boot.img, status=inserted, write_protected=1
-
-#=======================================================================
-# FLOPPYB:
-# See FLOPPYA above for syntax
-#=======================================================================
-#floppyb: 1_44=b:, status=inserted
-#floppyb: 1_44=b.img, status=inserted
-
-#=======================================================================
-# ATA0, ATA1, ATA2, ATA3
-# ATA controller for hard disks and cdroms
-#
-# ata[0-3]: enabled=[0|1], ioaddr1=addr, ioaddr2=addr, irq=number
-#
-# These options enables up to 4 ata channels. For each channel
-# the two base io addresses and the irq must be specified.
-#
-# ata0 and ata1 are enabled by default with the values shown below
-#
-# Examples:
-#   ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
-#   ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
-#   ata2: enabled=1, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
-#   ata3: enabled=1, ioaddr1=0x168, ioaddr2=0x360, irq=9
-#=======================================================================
-ata0: enabled=0, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
-ata1: enabled=0, ioaddr1=0x170, ioaddr2=0x370, irq=15
-ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
-ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
-
-#=======================================================================
-# ATA[0-3]-MASTER, ATA[0-3]-SLAVE
-#
-# This defines the type and characteristics of all attached ata devices:
-#   type=       type of attached device [disk|cdrom]
-#   mode=       only valid for disks [flat|concat|external|dll|sparse|vmware3]
-#                                    [vmware4|undoable|growing|volatile|vpc]
-#                                    [vbox|vvfat]
-#   path=       path of the image / directory
-#   cylinders=  only valid for disks
-#   heads=      only valid for disks
-#   spt=        only valid for disks
-#   status=     only valid for cdroms [inserted|ejected]
-#   biosdetect= type of biosdetection [auto|cmos|none]
-#   translation=type of translation of the bios, only for disks [none|lba|large|rechs|auto]
-#   model=      string returned by identify device command
-#   journal=    optional filename of the redolog for undoable, volatile and vvfat disks
-#
-# Point this at a hard disk image file, cdrom iso file, or physical cdrom
-# device.  To create a hard disk image, try running bximage.  It will help you
-# choose the size and then suggest a line that works with it.
-#
-# In UNIX it may be possible to use a raw device as a Bochs hard disk,
-# but WE DON'T RECOMMEND IT.  In Windows there is no easy way.
-#
-# In windows, the drive letter + colon notation should be used for cdroms.
-# Depending on versions of windows and drivers, you may only be able to
-# access the "first" cdrom in the system.  On MacOSX, use path="drive"
-# to access the physical drive.
-#
-# The path is mandatory for hard disks. Disk geometry autodetection works with
-# images created by bximage if CHS is set to 0/0/0 (cylinders are calculated
-# using  heads=16 and spt=63). For other hard disk images and modes the
-# cylinders, heads, and spt are mandatory. In all cases the disk size reported
-# from the image must be exactly C*H*S*512.
-#
-# Default values are:
-#   mode=flat, biosdetect=auto, translation=auto, model="Generic 1234"
-#
-# The biosdetect option has currently no effect on the bios
-#
-# Examples:
-#   ata0-master: type=disk, mode=flat, path=10M.sample, cylinders=306, heads=4, spt=17
-#   ata0-slave:  type=disk, mode=flat, path=20M.sample, cylinders=615, heads=4, spt=17
-#   ata1-master: type=disk, mode=flat, path=30M.sample, cylinders=615, heads=6, spt=17
-#   ata1-slave:  type=disk, mode=flat, path=46M.sample, cylinders=940, heads=6, spt=17
-#   ata2-master: type=disk, mode=flat, path=62M.sample, cylinders=940, heads=8, spt=17
-#   ata2-slave:  type=disk, mode=flat, path=112M.sample, cylinders=900, heads=15, spt=17
-#   ata3-master: type=disk, mode=flat, path=483M.sample, cylinders=1024, heads=15, spt=63
-#   ata3-slave:  type=cdrom, path=iso.sample, status=inserted
-#=======================================================================
-#ata0-master: type=disk, mode=flat, path="30M.sample"
-#ata0-master: type=disk, mode=flat, path="30M.sample", cylinders=615, heads=6, spt=17
-#ata0-master: type=disk, mode=flat, path="c.img", cylinders=0 # autodetect
-#ata0-slave: type=disk, mode=vvfat, path=/bochs/images/vvfat, journal=vvfat.redolog
-#ata0-slave: type=cdrom, path=D:, status=inserted
-#ata0-slave: type=cdrom, path=/dev/cdrom, status=inserted
-#ata0-slave: type=cdrom, path="drive", status=inserted
-#ata0-slave: type=cdrom, path=/dev/rcd0d, status=inserted
-
-#=======================================================================
-# BOOT:
-# This defines the boot sequence. Now you can specify up to 3 boot drives,
-# which can be 'floppy', 'disk', 'cdrom' or 'network' (boot ROM).
-# Legacy 'a' and 'c' are also supported.
-# Examples:
-#   boot: floppy
-#   boot: cdrom, disk
-#   boot: network, disk
-#   boot: cdrom, floppy, disk
-#=======================================================================
-boot: floppy
-#boot: disk
-
-#=======================================================================
-# FLOPPY_BOOTSIG_CHECK: disabled=[0|1]
-# Enables or disables the 0xaa55 signature check on boot floppies
-# Defaults to disabled=0
-# Examples:
-#   floppy_bootsig_check: disabled=0
-#   floppy_bootsig_check: disabled=1
-#=======================================================================
-floppy_bootsig_check: disabled=0
-
-#=======================================================================
-# LOG:
-# Give the path of the log file you'd like Bochs debug and misc. verbiage
-# to be written to. If you don't use this option or set the filename to
-# '-' the output is written to the console. If you really don't want it,
-# make it "/dev/null" (Unix) or "nul" (win32). :^(
-#
-# Examples:
-#   log: ./bochs.out
-#   log: /dev/tty
-#=======================================================================
-#log: /dev/null
-#log: .bochs.log
-#log: -
-log: /dev/stderr
-
-#=======================================================================
-# LOGPREFIX:
-# This handles the format of the string prepended to each log line.
-# You may use those special tokens :
-#   %t : 11 decimal digits timer tick
-#   %i : 8 hexadecimal digits of cpu current eip (ignored in SMP configuration)
-#   %e : 1 character event type ('i'nfo, 'd'ebug, 'p'anic, 'e'rror)
-#   %d : 5 characters string of the device, between brackets
-#
-# Default : %t%e%d
-# Examples:
-#   logprefix: %t-%e-@%i-%d
-#   logprefix: %i%e%d
-#=======================================================================
-logprefix: %t%e%d
-
-#=======================================================================
-# LOG CONTROLS
-#
-# Bochs has four severity levels for event logging.
-#   panic: cannot proceed.  If you choose to continue after a panic,
-#          don't be surprised if you get strange behavior or crashes.
-#   error: something went wrong, but it is probably safe to continue the
-#          simulation.
-#   info: interesting or useful messages.
-#   debug: messages useful only when debugging the code.  This may
-#          spit out thousands per second.
-#
-# For events of each level, you can choose to exit Bochs ('fatal'), 'ask',
-# 'warn', 'report' or 'ignore'. The choices 'ask' and 'warn' are not supported
-# by all guis, since they should bring up a dialog box. The 'warn' dialog is
-# designed to confirm errors and the 'ask' dialog is usually used for panics
-# and asks the user how to proceed.
-#
-# It is also possible to specify the 'action' to do for each Bochs facility
-# separately (e.g. crash on panics from everything except the cdrom, and only
-# report those). See the 'log function' module list in the user documentation.
-#
-# If you are experiencing many panics, it can be helpful to change
-# the panic action to report instead of fatal.  However, be aware
-# that anything executed after a panic is uncharted territory and can
-# cause bochs to become unstable.  The panic is a "graceful exit," so
-# if you disable it you may get a spectacular disaster instead.
-#=======================================================================
-panic: action=fatal
-error: action=ignore
-info: action=ignore
-debug: action=ignore  #, pci=report # report BX_DEBUG from module 'pci'
-
-#=======================================================================
-# DEBUGGER_LOG:
-# Give the path of the log file you'd like Bochs to log debugger output.
-# If you really don't want it, make it /dev/null or '-'. :^(
-#
-# Examples:
-#   debugger_log: ./debugger.out
-#=======================================================================
-#debugger_log: /dev/null
-#debugger_log: debugger.out
-#debugger_log: -
-debugger_log: /dev/null
-
-#=======================================================================
-# COM1, COM2, COM3, COM4:
-# This defines a serial port (UART type 16550A). In the 'term' mode you can
-# specify a device to use as com1. This can be a real serial line, or a pty.
-# To use a pty (under X/Unix), create two windows (xterms, usually).  One of
-# them will run bochs, and the other will act as com1. Find out the tty the com1
-# window using the `tty' command, and use that as the `dev' parameter.
-# Then do `sleep 1000000' in the com1 window to keep the shell from
-# messing with things, and run bochs in the other window.  Serial I/O to
-# com1 (port 0x3f8) will all go to the other window.
-# In socket* and pipe* (win32 only) modes Bochs becomes either socket/named pipe
-# client or server. In client mode it connects to an already running server (if
-# connection fails Bochs treats com port as not connected). In server mode it
-# opens socket/named pipe and waits until a client application connects to it
-# before starting simulation. This mode is useful for remote debugging (e.g.
-# with gdb's "target remote host:port" command or windbg's command line option
-# -k com:pipe,port=\\.\pipe\pipename). Socket modes use simple TCP communication,
-#  pipe modes use duplex byte mode pipes.
-# Other serial modes are 'null' (no input/output), 'file' (output to a file
-# specified as the 'dev' parameter and changeable at runtime), 'raw' (use the
-# real serial port - partly implemented on win32), 'mouse' (standard serial
-# mouse - requires mouse option setting 'type=serial', 'type=serial_wheel' or
-# 'type=serial_msys').
-#
-# Examples:
-#   com1: enabled=1, mode=null
-#   com1: enabled=1, mode=mouse
-#   com2: enabled=1, mode=file, dev=serial.out
-#   com3: enabled=1, mode=raw, dev=com1
-#   com3: enabled=1, mode=socket-client, dev=localhost:8888
-#   com3: enabled=1, mode=socket-server, dev=localhost:8888
-#   com4: enabled=1, mode=pipe-client, dev=\\.\pipe\mypipe
-#   com4: enabled=1, mode=pipe-server, dev=\\.\pipe\mypipe
-#=======================================================================
-com1: enabled=1, mode=file, dev=/proc/self/fd/4
-
-#=======================================================================
-# PARPORT1, PARPORT2:
-# This defines a parallel (printer) port. When turned on and an output file is
-# defined the emulated printer port sends characters printed by the guest OS
-# into the output file. On some platforms a device filename can be used to
-# send the data to the real parallel port (e.g. "/dev/lp0" on Linux, "lpt1" on
-# win32 platforms). The output file can be changed at runtime.
-#
-# Examples:
-#   parport1: enabled=1, file="parport.out"
-#   parport2: enabled=1, file="/dev/lp0"
-#   parport1: enabled=0
-#=======================================================================
-#parport1: enabled=1, file="parport.out"
-parport1: enabled=0
-
-#=======================================================================
-# SOUND:
-# This defines the lowlevel sound driver(s) for the wave (PCM) input / output
-# and the MIDI output feature and (if necessary) the devices to be used.
-# It can have several of the following properties.
-# All properties are in the format sound: property=value
-#
-# waveoutdrv:
-#      This defines the driver to be used for the waveout feature.
-#      Possible values are 'file' (all wave data sent to file), 'dummy' (no
-#      output) and the platform-dependant drivers 'alsa', 'oss', 'osx', 'sdl'
-#      and 'win'.
-# waveout:
-#      This defines the device to be used for wave output (if necessary) or
-#      the output file for the 'file' driver.
-# waveindrv:
-#      This defines the driver to be used for the wavein feature.
-#      Possible values are 'dummy' (recording silence) and platform-dependent
-#      drivers 'alsa', 'oss', 'sdl' and 'win'.
-# wavein:
-#      This defines the device to be used for wave input (if necessary).
-# midioutdrv:
-#      This defines the driver to be used for the MIDI output feature.
-#      Possible values are 'file' (all MIDI data sent to file), 'dummy' (no
-#      output) and platform-dependent drivers 'alsa', 'oss', 'osx' and 'win'.
-# midiout:
-#      This defines the device to be used for MIDI output (if necessary).
-# driver:
-#      This defines the driver to be used for all sound features with one
-#      property. Possible values are 'default' (platform default) and all
-#      other choices described above. Overriding one or more settings with
-#      the specific driver parameter is possible.
-#
-# Example for different drivers:
-#   sound: waveoutdrv=sdl, waveindrv=alsa, midioutdrv=dummy
-#=======================================================================
-#sound: driver=default, waveout=/dev/dsp. wavein=, midiout=
-
-#=======================================================================
-# SPEAKER:
-# This defines the PC speaker output mode. In the 'sound' mode the beep
-# is generated by the square wave generator which is a part of the
-# lowlevel sound support. The 'system' mode is only available on Linux
-# and Windows. On Linux /dev/console is used for output and on Windows
-# the Beep() function. The 'gui' mode forwards the beep to the related
-# gui methods (currently only used by the Carbon gui).
-#=======================================================================
-#speaker: enabled=0, mode=sound
-speaker: enabled=0
-
-#=======================================================================
-# SB16:
-# This defines the SB16 sound emulation. It can have several of the
-# following properties.
-# All properties are in the format sb16: property=value
-#
-# enabled:
-#      This optional property controls the presence of the SB16 emulation.
-#      The emulation is turned on unless this property is used and set to 0.
-# midimode: This parameter specifies what to do with the MIDI output.
-#      0 = no output
-#      1 = output to device specified with the sound option (system dependent)
-#      2 = MIDI or raw data output to file (depends on file name extension)
-#      3 = dual output (mode 1 and 2 at the same time)
-# midifile: This is the file where the midi output is stored (midimode 2 or 3).
-# wavemode: This parameter specifies what to do with the PCM output.
-#      0 = no output
-#      1 = output to device specified with the sound option (system dependent)
-#      2 = VOC, WAV or raw data output to file (depends on file name extension)
-#      3 = dual output (mode 1 and 2 at the same time)
-# wavefile: This is the file where the wave output is stored (wavemode 2 or 3).
-# loglevel:
-#      0=no log
-#      1=resource changes, midi program and bank changes
-#      2=severe errors
-#      3=all errors
-#      4=all errors plus all port accesses
-#      5=all errors and port accesses plus a lot of extra info
-# log:  The file to write the sb16 emulator messages to.
-# dmatimer:
-#      microseconds per second for a DMA cycle.  Make it smaller to fix
-#      non-continuous sound.  750000 is usually a good value.  This needs a
-#      reasonably correct setting for the IPS parameter of the CPU option.
-#
-# Examples for output modes:
-#   sb16: midimode=2, midifile="output.mid", wavemode=1 # MIDI to file
-#   sb16: midimode=1, wavemode=3, wavefile="output.wav" # wave to file and device
-#=======================================================================
-#sb16: midimode=1, wavemode=1, loglevel=2, log=sb16.log, dmatimer=600000
-#sb16: enabled=0
-
-#=======================================================================
-# ES1370:
-# This defines the ES1370 sound emulation (recording and playback - except
-# DAC1+DAC2 output at the same time). The parameter 'enabled' controls the
-# presence of the device. The wave and MIDI output can be sent to device, file
-# or both using the parameters 'wavemode', 'wavefile', 'midimode' and
-# 'midifile'. See the description of these parameters at the SB16 directive.
-#
-# Examples:
-#   es1370: enabled=1, wavemode=1                       # use 'sound' parameters
-#   es1370: enabled=1, wavemode=2, wavefile=output.voc  # send output to file
-#=======================================================================
-#es1370: enabled=1, wavemode=1
-#es1370: enabled=0
-
-#=======================================================================
-# ne2k: NE2000 compatible ethernet adapter
-#
-# Format:
-# ne2k: enabled=1, ioaddr=IOADDR, irq=IRQ, mac=MACADDR, ethmod=MODULE,
-#       ethdev=DEVICE, script=SCRIPT, bootrom=BOOTROM
-#
-# IOADDR, IRQ: You probably won't need to change ioaddr and irq, unless there
-# are IRQ conflicts. These arguments are ignored when assign the ne2k to a
-# PCI slot.
-#
-# MAC: The MAC address MUST NOT match the address of any machine on the net.
-# Also, the first byte must be an even number (bit 0 set means a multicast
-# address), and you cannot use ff:ff:ff:ff:ff:ff because that's the broadcast
-# address.  For the ethertap module, you must use fe:fd:00:00:00:01.  There may
-# be other restrictions too.  To be safe, just use the b0:c4... address.
-#
-# ETHDEV: The ethdev value is the name of the network interface on your host
-# platform.  On UNIX machines, you can get the name by running ifconfig.  On
-# Windows machines, you must run niclist to get the name of the ethdev.
-# Niclist source code is in misc/niclist.c and it is included in Windows
-# binary releases.
-# The 'socket' module uses this parameter to specify the UDP port for
-# receiving packets and (optional) the host to connect.
-#
-# SCRIPT: The script value is optional, and is the name of a script that
-# is executed after bochs initialize the network interface. You can use
-# this script to configure this network interface, or enable masquerading.
-# This is mainly useful for the tun/tap devices that only exist during
-# Bochs execution. The network interface name is supplied to the script
-# as first parameter.
-# The 'slirp' module uses this parameter to specify a config file for
-# setting up an alternative IP configuration or additional features.
-# The 'vnet' module uses this parameter to specify an alternative
-# log file name.
-#
-# BOOTROM: The bootrom value is optional, and is the name of the ROM image
-# to load. Note that this feature is only implemented for the PCI version of
-# the NE2000.
-#
-# If you don't want to make connections to any physical networks,
-# you can use the following 'ethmod's to simulate a virtual network.
-#   null: All packets are discarded, but logged to a few files.
-#   vde:  Virtual Distributed Ethernet
-#   vnet: ARP, ICMP-echo(ping), DHCP and read/write TFTP are simulated.
-#         The virtual host uses 192.168.10.1.
-#         DHCP assigns 192.168.10.2 to the guest.
-#         TFTP uses the 'ethdev' value for the root directory and doesn't
-#         overwrite files.
-# socket: Connect up to 6 Bochs instances with external program 'bxhub'
-#         (simulating an ethernet hub). It provides the same services as the
-#         'vnet' module and assigns IP addresses like 'slirp' (10.0.2.x).
-#
-#=======================================================================
-# ne2k: ioaddr=0x300, irq=9, mac=fe:fd:00:00:00:01, ethmod=fbsd, ethdev=en0 #macosx
-# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:00, ethmod=fbsd, ethdev=xl0
-# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0
-# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=win32, ethdev=MYCARD
-# ne2k: ioaddr=0x300, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0
-# ne2k: ioaddr=0x300, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun0, script=./tunconfig
-# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=null, ethdev=eth0
-# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=vde, ethdev="/tmp/vde.ctl"
-# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=vnet, ethdev="c:/temp"
-# ne2k: mac=b0:c4:20:00:00:01, ethmod=socket, ethdev=40000 # use localhost
-# ne2k: mac=b0:c4:20:00:00:01, ethmod=socket, ethdev=mymachine:40000
-# ne2k: mac=b0:c4:20:00:00:01, ethmod=slirp, script=slirp.conf, bootrom=ne2k_pci.rom
-
-#=======================================================================
-# pcipnic: Bochs/Etherboot pseudo-NIC
-#
-# Format:
-# pcipnic: enabled=1, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT,
-#          bootrom=BOOTROM
-#
-# The pseudo-NIC accepts the same syntax (for mac, ethmod, ethdev, script,
-# bootrom) and supports the same networking modules as the NE2000 adapter.
-#=======================================================================
-#pcipnic: enabled=1, mac=b0:c4:20:00:00:00, ethmod=vnet
-
-#=======================================================================
-# e1000: Intel(R) 82540EM Gigabit Ethernet adapter
-#
-# Format:
-# e1000: enabled=1, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT
-#        bootrom=BOOTROM
-#
-# The E1000 accepts the same syntax (for mac, ethmod, ethdev, script, bootrom)
-# and supports the same networking modules as the NE2000 adapter.
-#=======================================================================
-#e1000: enabled=1, mac=52:54:00:12:34:56, ethmod=slirp, script=slirp.conf
-
-#=======================================================================
-# USB_UHCI:
-# This option controls the presence of the USB root hub which is a part
-# of the i440FX PCI chipset. With the portX parameter you can connect devices
-# to the hub (currently supported: 'mouse', 'tablet', 'keypad', 'disk', 'cdrom',
-# 'floppy', 'hub' and 'printer').
-#
-# If you connect the mouse or tablet to one of the ports, Bochs forwards the
-# mouse movement data to the USB device instead of the selected mouse type.
-# When connecting the keypad to one of the ports, Bochs forwards the input of
-# the numeric keypad to the USB device instead of the PS/2 keyboard.
-#
-# To connect a 'flat' mode image as a USB hardisk you can use the 'disk' device
-# with the path to the image separated with a colon. To use other disk image modes
-# similar to ATA disks the syntax 'disk:mode:filename' must be used (see below).
-#
-# To emulate a USB cdrom you can use the 'cdrom' device name and the path to
-# an ISO image or raw device name also separated with a colon. An option to
-# insert/eject media is available in the runtime configuration.
-#
-# To emulate a USB floppy you can use the 'floppy' device with the path to the
-# image separated with a colon. To use the VVFAT image mode similar to the
-# legacy floppy the syntax 'floppy:vvfat:directory' must be used (see below).
-# An option to insert/eject media is available in the runtime configuration.
-#
-# The device name 'hub' connects an external hub with max. 8 ports (default: 4)
-# to the root hub. To specify the number of ports you have to add the value
-# separated with a colon. Connecting devices to the external hub ports is only
-# available in the runtime configuration.
-#
-# The device 'printer' emulates the HP Deskjet 920C printer. The PCL data is
-# sent to a file specified in bochsrc.txt. The current code appends the PCL
-# code to the file if the file already existed. The output file can be
-# changed at runtime.
-#
-# The optionsX parameter can be used to assign specific options to the device
-# connected to the corresponding USB port. Currently this feature is used to
-# set the speed reported by device ('low', 'full', 'high' or 'super'). The
-# availabe speed choices depend on both HC and device. The option 'debug' turns
-# on debug output for the device at connection time.
-# For the USB 'disk' device the optionsX parameter can be used to specify an
-# alternative redolog file (journal) of some image modes. For 'vvfat' mode USB
-# disks the optionsX parameter can be used to specify the disk size (range
-# 128M ... 128G). If the size is not specified, it defaults to 504M.
-# For the USB 'floppy' device the optionsX parameter can be used to specify an
-# alternative device ID to be reported. Currently only the model "teac" is
-# supported (can fix hw detection in some guest OS). The USB floppy also
-# accepts the parameter "write_protected" with valid values 0 and 1 to select
-# the access mode (default is 0).
-#=======================================================================
-#usb_uhci: enabled=1
-#usb_uhci: enabled=1, port1=mouse, port2=disk:usbstick.img
-#usb_uhci: enabled=1, port1=hub:7, port2=disk:growing:usbdisk.img
-#usb_uhci: enabled=1, port2=disk:undoable:usbdisk.img, options2=journal:redo.log
-#usb_uhci: enabled=1, port2=disk:usbdisk2.img, options2=sect_size:1024
-#usb_uhci: enabled=1, port2=disk:vvfat:vvfat, options2="debug,speed:full"
-#usb_uhci: enabled=1, port1=printer:printdata.bin, port2=cdrom:image.iso
-#usb_uhci: enabled=1, port2=floppy:vvfat:diskette, options2="model:teac"
-
-#=======================================================================
-# USB_OHCI:
-# This option controls the presence of the USB OHCI host controller with a
-# 2-port hub. The portX parameter accepts the same device types with the same
-# syntax as the UHCI controller (see above). The optionsX parameter is also
-# available on OHCI.
-#=======================================================================
-#usb_ohci: enabled=1
-#usb_ohci: enabled=1, port1=printer:usbprinter.bin
-
-#=======================================================================
-# USB_EHCI:
-# This option controls the presence of the USB EHCI host controller with a
-# 6-port hub. The portX parameter accepts the same device types with the
-# same syntax as the UHCI controller (see above). The optionsX parameter is
-# also available on EHCI.
-#=======================================================================
-#usb_ehci: enabled=1
-
-#=======================================================================
-# USB_XHCI:
-# This option controls the presence of the USB xHCI host controller with a
-# 4-port hub. The portX parameter accepts the same device types with the
-# same syntax as the UHCI controller (see above). The optionsX parameter is
-# also available on xHCI. NOTE: port 1 and 2 are USB3 and only support
-# super-speed devices, but port 3 and 4 are USB2 and support speed settings
-# low, full and high.
-#=======================================================================
-#usb_xhci: enabled=1
-
-#=======================================================================
-# PCIDEV:
-# PCI host device mapping
-# WARNING: This Bochs feature is not maintained yet and may fail.
-#=======================================================================
-#pcidev: vendor=0x1234, device=0x5678
-
-#=======================================================================
-# GDBSTUB:
-# Enable GDB stub. See user documentation for details.
-# Default value is enabled=0.
-# WARNING: This Bochs feature is not maintained yet and may fail.
-#=======================================================================
-#gdbstub: enabled=0, port=1234, text_base=0, data_base=0, bss_base=0
-
-#=======================================================================
-# MAGIC_BREAK:
-# This enables the "magic breakpoint" feature when using the debugger.
-# The useless cpu instruction XCHG BX, BX causes Bochs to enter the
-# debugger mode. This might be useful for software development.
-#
-# Example:
-#   magic_break: enabled=1
-#=======================================================================
-magic_break: enabled=0
-
-#=======================================================================
-# DEBUG_SYMBOLS:
-# This loads symbols from the specified file for use in Bochs' internal
-# debugger. Symbols are loaded into global context. This is equivalent to
-# issuing ldsym debugger command at start up.
-#
-# Example:
-#   debug_symbols: file="kernel.sym"
-#   debug_symbols: file="kernel.sym", offset=0x80000000
-#=======================================================================
-#debug_symbols: file="kernel.sym"
-
-print_timestamps: enabled=1
-
-#=======================================================================
-# PORT_E9_HACK:
-# The 0xE9 port doesn't exists in normal ISA architecture. However, we
-# define a convention here, to display on the console of the system running
-# Bochs anything that is written to it. The idea is to provide debug output
-# very early when writing BIOS or OS code for example, without having to
-# bother with setting up a serial port or etc. Reading from port 0xE9 will
-# will return 0xe9 to let you know if the feature is available.
-# Leave this 0 unless you have a reason to use it.
-#
-# Example:
-#   port_e9_hack: enabled=1
-#=======================================================================
-#port_e9_hack: enabled=1
-
-#=======================================================================
-# other stuff
-#=======================================================================
-# WARNING: This Bochs feature is not maintained yet. Is it still used ?
-# To use it, set BX_LOAD32BITOSHACK in config.h to 1 and recompile Bochs.
-#load32bitOSImage: os=nullkernel, path=../kernel.img, iolog=../vga_io.log
-#load32bitOSImage: os=linux, path=../linux.img, iolog=../vga_io.log, initrd=../initrd.img
-
-#=======================================================================
-# fullscreen: ONLY IMPLEMENTED ON AMIGA
-#             Request that Bochs occupy the entire screen instead of a
-#             window.
-#
-# Examples:
-#   fullscreen: enabled=0
-#   fullscreen: enabled=1
-#=======================================================================
-#fullscreen: enabled=0
-#screenmode: name="sample"
-
-#=======================================================================
-# USER_PLUGIN:
-# Load user-defined plugin. This option is available only if Bochs is
-# compiled with plugin support. Maximum 8 different plugins are supported.
-# See the example in the Bochs sources how to write a plugin device.
-#=======================================================================
-#user_plugin: name=testdev
-
-#=======================================================================
-# for Macintosh, use the style of pathnames in the following
-# examples.
-#
-# vgaromimage: :bios:VGABIOS-elpin-2.40
-# romimage: file=:bios:BIOS-bochs-latest, address=0xf0000
-# floppya: 1_44=[fd:], status=inserted
-#=======================================================================
-#:bios:VGABIOS-elpin-2.40
-
-#=======================================================================
-# MEGS
-# Set the number of Megabytes of physical memory you want to emulate.
-# The default is 32MB, most OS's won't need more than that.
-# The maximum amount of memory supported is 2048Mb.
-# The 'MEGS' option is deprecated. Use 'MEMORY' option instead.
-#=======================================================================
-#megs: 256
-#megs: 128
-#megs: 64
-#megs: 32
-#megs: 16
-#megs: 8
diff --git a/build/bootstrap/compile.com b/build/bootstrap/compile.com
index 8ca98c4da..6c337da07 100755
Binary files a/build/bootstrap/compile.com and b/build/bootstrap/compile.com differ
diff --git a/build/bootstrap/zipobj.com b/build/bootstrap/zipobj.com
index 5947dda14..4b2a15646 100755
Binary files a/build/bootstrap/zipobj.com and b/build/bootstrap/zipobj.com differ
diff --git a/examples/curl.c b/examples/curl.c
index 9c7d806cf..1fb7e8e69 100644
--- a/examples/curl.c
+++ b/examples/curl.c
@@ -21,9 +21,11 @@
 #include "libc/rand/rand.h"
 #include "libc/runtime/gc.h"
 #include "libc/runtime/runtime.h"
+#include "libc/sock/goodsocket.internal.h"
 #include "libc/sock/sock.h"
 #include "libc/stdio/append.internal.h"
 #include "libc/stdio/stdio.h"
+#include "libc/str/slice.h"
 #include "libc/str/str.h"
 #include "libc/sysv/consts/af.h"
 #include "libc/sysv/consts/dt.h"
@@ -63,32 +65,11 @@
 #define HeaderEqualCase(H, S) \
   SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
 
-static inline bool SlicesEqualCase(const char *a, size_t n, const char *b,
-                                   size_t m) {
-  return n == m && !memcasecmp(a, b, n);
-}
-
 static bool TuneSocket(int fd, int a, int b, int x) {
   if (!b) return false;
   return setsockopt(fd, a, b, &x, sizeof(x)) != -1;
 }
 
-static int Socket(int family, int type, int protocol) {
-  int fd;
-  if ((fd = socket(family, type, protocol)) != -1) {
-    TuneSocket(fd, SOL_SOCKET, SO_KEEPALIVE, 1);
-    if (protocol == SOL_TCP) {
-      TuneSocket(fd, SOL_TCP, TCP_KEEPIDLE, 60);
-      TuneSocket(fd, SOL_TCP, TCP_KEEPINTVL, 60);
-      TuneSocket(fd, SOL_TCP, TCP_FASTOPEN_CONNECT, 1);
-      if (!TuneSocket(fd, SOL_TCP, TCP_QUICKACK, 1)) {
-        TuneSocket(fd, SOL_TCP, TCP_NODELAY, 1);
-      }
-    }
-  }
-  return fd;
-}
-
 static int TlsSend(void *c, const unsigned char *p, size_t n) {
   int rc;
   NOISEF("begin send %zu", n);
@@ -119,35 +100,11 @@ static int TlsRecv(void *c, unsigned char *p, size_t n, uint32_t o) {
   return MIN(n, r);
 }
 
-static void TlsDebug(void *c, int v, const char *f, int l, const char *s) {
-  flogf(v, f, l, 0, "TLS %s", s);
-}
-
-static char *TlsError(int r) {
-  static char b[128];
-  mbedtls_strerror(r, b, sizeof(b));
-  return b;
-}
-
 static wontreturn void PrintUsage(FILE *f, int rc) {
   fprintf(f, "usage: %s [-ksvV] URL\n", program_invocation_name);
   exit(rc);
 }
 
-static wontreturn void TlsDie(const char *s, int r) {
-  if (IsTiny()) {
-    fprintf(stderr, "error: %s (-0x%04x %s)\n", s, -r, TlsError(r));
-  } else {
-    fprintf(stderr, "error: %s (grep -0x%04x)\n", s, -r);
-  }
-  exit(1);
-}
-
-static int GetEntropy(void *c, unsigned char *p, size_t n) {
-  CHECK_EQ(n, getrandom(p, n, 0));
-  return 0;
-}
-
 int main(int argc, char *argv[]) {
   if (!NoDebug()) showcrashreports();
   xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
@@ -302,8 +259,9 @@ int main(int argc, char *argv[]) {
    * Connect to server.
    */
   int ret, sock;
-  CHECK_NE(-1, (sock = Socket(addr->ai_family, addr->ai_socktype,
-                              addr->ai_protocol)));
+  CHECK_NE(-1, (sock = GoodSocket(addr->ai_family, addr->ai_socktype,
+                                  addr->ai_protocol, false,
+                                  &(struct timeval){-60})));
   CHECK_NE(-1, connect(sock, addr->ai_addr, addr->ai_addrlen));
   freeaddrinfo(addr);
   if (usessl) {
diff --git a/libc/calls/addrusage.c b/libc/calls/addrusage.c
new file mode 100644
index 000000000..41cd654ed
--- /dev/null
+++ b/libc/calls/addrusage.c
@@ -0,0 +1,39 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/calls/math.h"
+#include "libc/macros.internal.h"
+
+void AddRusage(struct rusage *x, const struct rusage *y) {
+  AddTimeval(&x->ru_utime, &y->ru_utime);
+  AddTimeval(&x->ru_stime, &y->ru_stime);
+  x->ru_maxrss = MAX(x->ru_maxrss, y->ru_maxrss);
+  x->ru_ixrss += y->ru_ixrss;
+  x->ru_idrss += y->ru_idrss;
+  x->ru_isrss += y->ru_isrss;
+  x->ru_minflt += y->ru_minflt;
+  x->ru_majflt += y->ru_majflt;
+  x->ru_nswap += y->ru_nswap;
+  x->ru_inblock += y->ru_inblock;
+  x->ru_oublock += y->ru_oublock;
+  x->ru_msgsnd += y->ru_msgsnd;
+  x->ru_msgrcv += y->ru_msgrcv;
+  x->ru_nsignals += y->ru_nsignals;
+  x->ru_nvcsw += y->ru_nvcsw;
+  x->ru_nivcsw += y->ru_nivcsw;
+}
diff --git a/libc/calls/addtimeval.c b/libc/calls/addtimeval.c
new file mode 100644
index 000000000..38ae4e369
--- /dev/null
+++ b/libc/calls/addtimeval.c
@@ -0,0 +1,28 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/calls/math.h"
+
+void AddTimeval(struct timeval *x, const struct timeval *y) {
+  x->tv_sec += y->tv_sec;
+  x->tv_usec += y->tv_usec;
+  if (x->tv_usec >= 1000000) {
+    x->tv_usec -= 1000000;
+    x->tv_sec += 1;
+  }
+}
diff --git a/libc/calls/math.h b/libc/calls/math.h
new file mode 100644
index 000000000..e99faa9db
--- /dev/null
+++ b/libc/calls/math.h
@@ -0,0 +1,13 @@
+#ifndef COSMOPOLITAN_LIBC_CALLS_MATH_H_
+#define COSMOPOLITAN_LIBC_CALLS_MATH_H_
+#include "libc/calls/struct/rusage.h"
+#include "libc/calls/struct/timeval.h"
+#if !(__ASSEMBLER__ + __LINKER__ + 0)
+COSMOPOLITAN_C_START_
+
+void AddTimeval(struct timeval *, const struct timeval *);
+void AddRusage(struct rusage *, const struct rusage *);
+
+COSMOPOLITAN_C_END_
+#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
+#endif /* COSMOPOLITAN_LIBC_CALLS_MATH_H_ */
diff --git a/libc/fmt/conv.h b/libc/fmt/conv.h
index 7b4f47d8f..ae10df609 100644
--- a/libc/fmt/conv.h
+++ b/libc/fmt/conv.h
@@ -39,6 +39,7 @@ long sizetol(const char *, long) paramsnonnull() libcesque;
 β”‚ cosmopolitan Β§ conversion Β» time                                         ─╬─│┼
 β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”‚*/
 
+struct timespec WindowsTimeToTime(uint64_t);
 int64_t DosDateTimeToUnix(unsigned, unsigned);
 struct timespec FileTimeToTimeSpec(struct NtFileTime);
 struct NtFileTime TimeSpecToFileTime(struct timespec);
@@ -48,6 +49,11 @@ void FileTimeToTimeVal(struct timeval *, struct NtFileTime) nothrow;
 struct NtFileTime TimeValToFileTime(const struct timeval *) nosideeffect;
 long convertmicros(const struct timeval *, long) paramsnonnull() nosideeffect;
 
+/* forceinline struct timespec WindowsTimeToTime(uint64_t x) { */
+/*   return (struct timespec){x / HECTONANOSECONDS - MODERNITYSECONDS, */
+/*                            x % HECTONANOSECONDS * 100}; */
+/* } */
+
 /*───────────────────────────────────────────────────────────────────────────│─╗
 β”‚ cosmopolitan Β§ conversion Β» manipulation                                 ─╬─│┼
 β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”‚*/
diff --git a/libc/fmt/fmt.mk b/libc/fmt/fmt.mk
index 221f6367c..b91b201f8 100644
--- a/libc/fmt/fmt.mk
+++ b/libc/fmt/fmt.mk
@@ -58,6 +58,7 @@ $(LIBC_FMT_A_OBJS):				\
 		OVERRIDE_CFLAGS +=		\
 			-fno-jump-tables
 
+o/$(MODE)/libc/fmt/windowstimetotime.o		\
 o/$(MODE)/libc/fmt/dosdatetimetounix.o		\
 o/$(MODE)/libc/fmt/itoa64radix10.greg.o		\
 o/$(MODE)/libc/fmt/timetofiletime.o		\
diff --git a/libc/sock/goodsocket.c b/libc/sock/goodsocket.c
new file mode 100644
index 000000000..6ead34788
--- /dev/null
+++ b/libc/sock/goodsocket.c
@@ -0,0 +1,59 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/calls/struct/timeval.h"
+#include "libc/sock/goodsocket.internal.h"
+#include "libc/sock/sock.h"
+#include "libc/sysv/consts/so.h"
+#include "libc/sysv/consts/sol.h"
+#include "libc/sysv/consts/tcp.h"
+
+static bool Tune(int fd, int a, int b, int x) {
+  if (!b) return false;
+  return setsockopt(fd, a, b, &x, sizeof(x)) != -1;
+}
+
+/**
+ * Returns new socket with modern goodness enabled.
+ */
+int GoodSocket(int family, int type, int protocol, bool isserver,
+               const struct timeval *timeout) {
+  int fd;
+  if ((fd = socket(family, type, protocol)) != -1) {
+    if (isserver) {
+      Tune(fd, SOL_TCP, TCP_FASTOPEN, 100);
+      Tune(fd, SOL_SOCKET, SO_REUSEADDR, 1);
+    } else {
+      Tune(fd, SOL_TCP, TCP_FASTOPEN_CONNECT, 1);
+    }
+    if (!Tune(fd, SOL_TCP, TCP_QUICKACK, 1)) {
+      Tune(fd, SOL_TCP, TCP_NODELAY, 1);
+    }
+    if (timeout) {
+      if (timeout->tv_sec < 0) {
+        Tune(fd, SOL_SOCKET, SO_KEEPALIVE, 1);
+        Tune(fd, SOL_TCP, TCP_KEEPIDLE, -timeout->tv_sec);
+        Tune(fd, SOL_TCP, TCP_KEEPINTVL, -timeout->tv_sec);
+      } else {
+        setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, timeout, sizeof(*timeout));
+        setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, timeout, sizeof(*timeout));
+      }
+    }
+  }
+  return fd;
+}
diff --git a/libc/sock/goodsocket.internal.h b/libc/sock/goodsocket.internal.h
new file mode 100644
index 000000000..8c2509893
--- /dev/null
+++ b/libc/sock/goodsocket.internal.h
@@ -0,0 +1,11 @@
+#ifndef COSMOPOLITAN_LIBC_SOCK_GOODSOCKET_H_
+#define COSMOPOLITAN_LIBC_SOCK_GOODSOCKET_H_
+#include "libc/calls/struct/timeval.h"
+#if !(__ASSEMBLER__ + __LINKER__ + 0)
+COSMOPOLITAN_C_START_
+
+int GoodSocket(int, int, int, bool, const struct timeval *);
+
+COSMOPOLITAN_C_END_
+#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
+#endif /* COSMOPOLITAN_LIBC_SOCK_GOODSOCKET_H_ */
diff --git a/libc/str/compareslices.c b/libc/str/compareslices.c
new file mode 100644
index 000000000..32346593f
--- /dev/null
+++ b/libc/str/compareslices.c
@@ -0,0 +1,28 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/macros.internal.h"
+#include "libc/str/slice.h"
+
+int CompareSlices(const char *a, size_t n, const char *b, size_t m) {
+  int c;
+  if ((c = memcmp(a, b, MIN(n, m)))) return c;
+  if (n < m) return -1;
+  if (n > m) return +1;
+  return 0;
+}
diff --git a/libc/str/compareslicescase.c b/libc/str/compareslicescase.c
new file mode 100644
index 000000000..a1b7a6e1b
--- /dev/null
+++ b/libc/str/compareslicescase.c
@@ -0,0 +1,28 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/macros.internal.h"
+#include "libc/str/slice.h"
+
+int CompareSlicesCase(const char *a, size_t n, const char *b, size_t m) {
+  int c;
+  if ((c = memcasecmp(a, b, MIN(n, m)))) return c;
+  if (n < m) return -1;
+  if (n > m) return +1;
+  return 0;
+}
diff --git a/libc/str/getzipcfiletimestamps.c b/libc/str/getzipcfiletimestamps.c
new file mode 100644
index 000000000..af6bd3d98
--- /dev/null
+++ b/libc/str/getzipcfiletimestamps.c
@@ -0,0 +1,101 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/fmt/conv.h"
+#include "libc/zip.h"
+
+static inline int pop(int x) {
+  return !!(x & 1) + !!(x & 2) + !!(x & 4);
+}
+
+/**
+ * Extracts modified/access/creation timestamps from zip entry.
+ *
+ * @param cf is pointer to central directory header for file
+ * @param mtim optionally receives last modified timestamp
+ * @param atim optionally receives modified timestamp
+ * @param ctim optionally receives creation timestamp
+ * @param gmtoff is seconds adjustment for legacy dos timestamps
+ */
+void GetZipCfileTimestamps(const uint8_t *cf, struct timespec *mtim,
+                           struct timespec *atim, struct timespec *ctim,
+                           int gmtoff) {
+  const uint8_t *p, *pe;
+  if (mtim) *mtim = (struct timespec){0};
+  if (atim) *atim = (struct timespec){0};
+  if (ctim) *ctim = (struct timespec){0};
+  for (p = ZIP_CFILE_EXTRA(cf), pe = p + ZIP_CFILE_EXTRASIZE(cf); p + 4 <= pe;
+       p += ZIP_EXTRA_SIZE(p)) {
+    if (ZIP_EXTRA_HEADERID(p) == kZipExtraNtfs &&
+        ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4 + 8 &&
+        READ16LE(ZIP_EXTRA_CONTENT(p) + 4) == 1 &&
+        READ16LE(ZIP_EXTRA_CONTENT(p) + 6) >= 8) {
+      if (mtim) {
+        *mtim = WindowsTimeToTime(READ64LE(ZIP_EXTRA_CONTENT(p) + 8));
+      }
+      if (atim && ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4 + 8 * 2 &&
+          READ16LE(ZIP_EXTRA_CONTENT(p) + 6) >= 16) {
+        *atim = WindowsTimeToTime(READ64LE(ZIP_EXTRA_CONTENT(p) + 8 * 2));
+      }
+      if (ctim && ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4 + 8 * 3 &&
+          READ16LE(ZIP_EXTRA_CONTENT(p) + 6) >= 24) {
+        *ctim = WindowsTimeToTime(READ64LE(ZIP_EXTRA_CONTENT(p) + 8 * 3));
+      }
+      return;
+    }
+  }
+  for (p = ZIP_CFILE_EXTRA(cf), pe = p + ZIP_CFILE_EXTRASIZE(cf); p + 4 <= pe;
+       p += ZIP_EXTRA_SIZE(p)) {
+    if (ZIP_EXTRA_HEADERID(p) == kZipExtraExtendedTimestamp &&
+        ZIP_EXTRA_CONTENTSIZE(p) > 1 &&
+        ZIP_EXTRA_CONTENTSIZE(p) == 1 + 4 * pop(*ZIP_EXTRA_CONTENT(p) & 7)) {
+      if (mtim) {
+        if (*ZIP_EXTRA_CONTENT(p) & 1) {
+          mtim->tv_sec = (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 1);
+        } else {
+          mtim->tv_sec = DosDateTimeToUnix(ZIP_CFILE_LASTMODIFIEDDATE(cf),
+                                           ZIP_CFILE_LASTMODIFIEDTIME(cf)) -
+                         gmtoff;
+        }
+      }
+      if (atim && (*ZIP_EXTRA_CONTENT(p) & 2)) {
+        atim->tv_sec = (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 1 +
+                                         4 * (*ZIP_EXTRA_CONTENT(p) & 1));
+      }
+      if (ctim && (*ZIP_EXTRA_CONTENT(p) & 4)) {
+        ctim->tv_sec = (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 1 +
+                                         4 * pop(*ZIP_EXTRA_CONTENT(p) & 3));
+      }
+      return;
+    }
+  }
+  for (p = ZIP_CFILE_EXTRA(cf), pe = p + ZIP_CFILE_EXTRASIZE(cf); p + 4 <= pe;
+       p += ZIP_EXTRA_SIZE(p)) {
+    if (ZIP_EXTRA_HEADERID(p) == kZipExtraUnix &&
+        ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4) {
+      if (atim) atim->tv_sec = (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 0);
+      if (mtim) mtim->tv_sec = (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 4);
+      return;
+    }
+  }
+  if (mtim) {
+    mtim->tv_sec = DosDateTimeToUnix(ZIP_CFILE_LASTMODIFIEDDATE(cf),
+                                     ZIP_CFILE_LASTMODIFIEDTIME(cf)) -
+                   gmtoff;
+  }
+}
diff --git a/libc/str/istext.c b/libc/str/istext.c
new file mode 100644
index 000000000..0a75f6021
--- /dev/null
+++ b/libc/str/istext.c
@@ -0,0 +1,32 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/str/str.h"
+
+/**
+ * Returns true if buffer is most likely plaintext.
+ */
+bool IsText(const void *data, size_t size) {
+  const unsigned char *p, *pe;
+  for (p = data, pe = p + size; p < pe; ++p) {
+    if (*p <= 3) {
+      return false;
+    }
+  }
+  return true;
+}
diff --git a/libc/str/isutf8.c b/libc/str/isutf8.c
new file mode 100644
index 000000000..983ce7282
--- /dev/null
+++ b/libc/str/isutf8.c
@@ -0,0 +1,38 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/str/str.h"
+
+/**
+ * Returns true if text data is most likely utf-8.
+ *
+ * This function will return false if a pure ascii string is passed.
+ */
+bool IsUtf8(const void *data, size_t size) {
+  const unsigned char *p, *pe;
+  for (p = data, pe = p + size; p + 2 <= pe; ++p) {
+    if (p[0] >= 0300) {
+      if (p[1] >= 0200 && p[1] < 0300) {
+        return true;
+      } else {
+        return false;
+      }
+    }
+  }
+  return false;
+}
diff --git a/libc/str/slice.h b/libc/str/slice.h
new file mode 100644
index 000000000..a7ced4564
--- /dev/null
+++ b/libc/str/slice.h
@@ -0,0 +1,22 @@
+#ifndef COSMOPOLITAN_LIBC_STR_SLICE_H_
+#define COSMOPOLITAN_LIBC_STR_SLICE_H_
+#include "libc/str/str.h"
+#if !(__ASSEMBLER__ + __LINKER__ + 0)
+COSMOPOLITAN_C_START_
+
+forceinline bool SlicesEqual(const char *a, size_t n, const char *b, size_t m) {
+  return n == m && !memcmp(a, b, n);
+}
+
+forceinline bool SlicesEqualCase(const void *a, size_t n, const void *b,
+                                 size_t m) {
+  return n == m && !memcasecmp(a, b, n);
+}
+
+int CompareSlices(const char *, size_t, const char *, size_t);
+int CompareSlicesCase(const char *, size_t, const char *, size_t);
+bool StartsWithIgnoreCase(const char *, const char *);
+
+COSMOPOLITAN_C_END_
+#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
+#endif /* COSMOPOLITAN_LIBC_STR_SLICE_H_ */
diff --git a/libc/str/startswithi.c b/libc/str/startswithi.c
new file mode 100644
index 000000000..737280807
--- /dev/null
+++ b/libc/str/startswithi.c
@@ -0,0 +1,27 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/str/str.h"
+
+bool startswithi(const char *s, const char *prefix) {
+  for (;;) {
+    if (!*prefix) return true;
+    if (!*s) return false;
+    if (kToLower[*s++ & 255] != (*prefix++ & 255)) return false;
+  }
+}
diff --git a/libc/str/str.h b/libc/str/str.h
index c864e5842..fede6a58d 100644
--- a/libc/str/str.h
+++ b/libc/str/str.h
@@ -171,6 +171,7 @@ wchar_t *wcstok(wchar_t *, const wchar_t *, wchar_t **) paramsnonnull((2, 3));
 char *wstrtrunc(uint16_t *) memcpyesque;
 char *wstrntrunc(uint16_t *, size_t) memcpyesque;
 bool startswith(const char *, const char *) strlenesque;
+bool startswithi(const char *, const char *) strlenesque;
 bool startswith16(const char16_t *, const char16_t *) strlenesque;
 bool wcsstartswith(const wchar_t *, const wchar_t *) strlenesque;
 bool endswith(const char *, const char *) strlenesque;
@@ -197,6 +198,8 @@ char *strtoupper(char *) paramsnonnull();
 char *chomp(char *);
 char16_t *chomp16(char16_t *);
 wchar_t *wchomp(wchar_t *);
+bool IsText(const void *, size_t);
+bool IsUtf8(const void *, size_t);
 
 bool escapedos(char16_t *, unsigned, const char16_t *, unsigned);
 
diff --git a/libc/str/str.mk b/libc/str/str.mk
index 1b47c9e96..e40f81e0e 100644
--- a/libc/str/str.mk
+++ b/libc/str/str.mk
@@ -48,6 +48,14 @@ o/$(MODE)/libc/str/memmem.o:					\
 		OVERRIDE_CPPFLAGS +=				\
 			-DSTACK_FRAME_UNLIMITED
 
+o//libc/str/bzero.o:						\
+		OVERRIDE_CFLAGS +=				\
+			-O2
+
+o/$(MODE)/libc/str/dosdatetimetounix.o:				\
+		OVERRIDE_CFLAGS +=				\
+			-O3
+
 o/$(MODE)/libc/str/getzipcdir.o					\
 o/$(MODE)/libc/str/getzipcdircomment.o				\
 o/$(MODE)/libc/str/getzipcdircommentsize.o			\
@@ -58,20 +66,21 @@ o/$(MODE)/libc/str/getzipcfilemode.o				\
 o/$(MODE)/libc/str/getzipcfileoffset.o				\
 o/$(MODE)/libc/str/getzipcfileuncompressedsize.o		\
 o/$(MODE)/libc/str/getziplfilecompressedsize.o			\
-o/$(MODE)/libc/str/getziplfileuncompressedsize.o:		\
+o/$(MODE)/libc/str/getziplfileuncompressedsize.o		\
+o/$(MODE)/libc/str/getzipcfiletimestamps.o:			\
 		OVERRIDE_CFLAGS +=				\
 			-Os
 
-o//libc/str/bzero.o:						\
-		OVERRIDE_CFLAGS +=				\
-			-O2
-
 o/$(MODE)/libc/str/iswpunct.o					\
 o/$(MODE)/libc/str/iswupper.o					\
 o/$(MODE)/libc/str/iswlower.o:					\
 		OVERRIDE_CFLAGS +=				\
 			-fno-jump-tables
 
+o/$(MODE)/libc/str/windowstimetotime.o:				\
+		OVERRIDE_CFLAGS +=				\
+			-O3
+
 LIBC_STR_LIBS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)))
 LIBC_STR_SRCS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_SRCS))
 LIBC_STR_HDRS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_HDRS))
diff --git a/libc/str/windowstimetotime.c b/libc/str/windowstimetotime.c
new file mode 100644
index 000000000..1e36ad328
--- /dev/null
+++ b/libc/str/windowstimetotime.c
@@ -0,0 +1,24 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/fmt/conv.h"
+
+struct timespec WindowsTimeToTime(uint64_t x) {
+  return (struct timespec){x / HECTONANOSECONDS - MODERNITYSECONDS,
+                           x % HECTONANOSECONDS * 100};
+}
diff --git a/libc/zip.h b/libc/zip.h
index 359a5298e..be640422d 100644
--- a/libc/zip.h
+++ b/libc/zip.h
@@ -1,6 +1,7 @@
 #ifndef COSMOPOLITAN_LIBC_ZIP_H_
 #define COSMOPOLITAN_LIBC_ZIP_H_
 #include "libc/bits/bits.h"
+#include "libc/calls/struct/timespec.h"
 #include "libc/macros.internal.h"
 #include "libc/str/str.h"
 
@@ -199,6 +200,8 @@ uint64_t GetZipCfileOffset(const uint8_t *);
 uint64_t GetZipLfileUncompressedSize(const uint8_t *);
 uint64_t GetZipLfileCompressedSize(const uint8_t *);
 uint8_t *zipfindcentraldir(const uint8_t *, size_t);
+void GetZipCfileTimestamps(const uint8_t *, struct timespec *,
+                           struct timespec *, struct timespec *, int);
 
 #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
 #endif /* COSMOPOLITAN_LIBC_ZIP_H_ */
diff --git a/libc/zipos/stat-impl.c b/libc/zipos/stat-impl.c
index 702737c63..4d8a28451 100644
--- a/libc/zipos/stat-impl.c
+++ b/libc/zipos/stat-impl.c
@@ -18,75 +18,12 @@
 β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
 #include "libc/bits/safemacros.internal.h"
 #include "libc/calls/calls.h"
-#include "libc/calls/struct/stat.h"
 #include "libc/fmt/conv.h"
 #include "libc/str/str.h"
 #include "libc/sysv/errfuns.h"
 #include "libc/zip.h"
 #include "libc/zipos/zipos.internal.h"
 
-static int popcnt3(int x) {
-  return !!(x & 1) + !!(x & 2) + !!(x & 4);
-}
-
-static struct timespec WindowsTimeToTime(uint64_t x) {
-  return (struct timespec){x / HECTONANOSECONDS - MODERNITYSECONDS,
-                           x % HECTONANOSECONDS * 100};
-}
-
-static void GetZipCfileTimestamps(const uint8_t *zcf, struct stat *st) {
-  const uint8_t *p, *pe;
-  for (p = ZIP_CFILE_EXTRA(zcf), pe = p + ZIP_CFILE_EXTRASIZE(zcf); p + 4 <= pe;
-       p += ZIP_EXTRA_SIZE(p)) {
-    if (ZIP_EXTRA_HEADERID(p) == kZipExtraNtfs &&
-        ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4 + 8 &&
-        READ16LE(ZIP_EXTRA_CONTENT(p) + 4) == 1 &&
-        READ16LE(ZIP_EXTRA_CONTENT(p) + 6) >= 8) {
-      st->st_mtim = WindowsTimeToTime(READ64LE(ZIP_EXTRA_CONTENT(p) + 8));
-      if (ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4 + 8 * 2 &&
-          READ16LE(ZIP_EXTRA_CONTENT(p) + 6) >= 16) {
-        st->st_atim = WindowsTimeToTime(READ64LE(ZIP_EXTRA_CONTENT(p) + 8 * 2));
-      }
-      if (ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4 + 8 * 3 &&
-          READ16LE(ZIP_EXTRA_CONTENT(p) + 6) >= 24) {
-        st->st_ctim = WindowsTimeToTime(READ64LE(ZIP_EXTRA_CONTENT(p) + 8 * 3));
-      }
-      return;
-    }
-  }
-  for (p = ZIP_CFILE_EXTRA(zcf), pe = p + ZIP_CFILE_EXTRASIZE(zcf); p + 4 <= pe;
-       p += ZIP_EXTRA_SIZE(p)) {
-    if (ZIP_EXTRA_HEADERID(p) == kZipExtraExtendedTimestamp &&
-        ZIP_EXTRA_CONTENTSIZE(p) > 1 &&
-        ZIP_EXTRA_CONTENTSIZE(p) ==
-            1 + 4 * popcnt3(*ZIP_EXTRA_CONTENT(p) & 7)) {
-      if (*ZIP_EXTRA_CONTENT(p) & 1) {
-        st->st_mtim.tv_sec = READ32LE(ZIP_EXTRA_CONTENT(p) + 1);
-      }
-      if (*ZIP_EXTRA_CONTENT(p) & 2) {
-        st->st_atim.tv_sec = READ32LE(ZIP_EXTRA_CONTENT(p) + 1 +
-                                      4 * (*ZIP_EXTRA_CONTENT(p) & 1));
-      }
-      if (*ZIP_EXTRA_CONTENT(p) & 4) {
-        st->st_ctim.tv_sec = READ32LE(ZIP_EXTRA_CONTENT(p) + 1 +
-                                      4 * popcnt3(*ZIP_EXTRA_CONTENT(p) & 3));
-      }
-      return;
-    }
-  }
-  for (p = ZIP_CFILE_EXTRA(zcf), pe = p + ZIP_CFILE_EXTRASIZE(zcf); p + 4 <= pe;
-       p += ZIP_EXTRA_SIZE(p)) {
-    if (ZIP_EXTRA_HEADERID(p) == kZipExtraUnix &&
-        ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4) {
-      st->st_atim.tv_sec = (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 0);
-      st->st_mtim.tv_sec = (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 4);
-      return;
-    }
-  }
-  st->st_mtim.tv_sec = DosDateTimeToUnix(ZIP_CFILE_LASTMODIFIEDDATE(zcf),
-                                         ZIP_CFILE_LASTMODIFIEDTIME(zcf));
-}
-
 int __zipos_stat_impl(struct Zipos *zipos, size_t cf, struct stat *st) {
   size_t lf;
   if (zipos && st) {
@@ -100,7 +37,8 @@ int __zipos_stat_impl(struct Zipos *zipos, size_t cf, struct stat *st) {
     st->st_size = GetZipLfileUncompressedSize(zipos->map + lf);
     st->st_blocks =
         roundup(GetZipLfileCompressedSize(zipos->map + lf), 512) / 512;
-    GetZipCfileTimestamps(zipos->map + cf, st);
+    GetZipCfileTimestamps(zipos->map + cf, &st->st_mtim, &st->st_atim,
+                          &st->st_ctim, 0);
     return 0;
   } else {
     return einval();
diff --git a/net/https/certhashost.c b/net/https/certhashost.c
new file mode 100644
index 000000000..efabb542d
--- /dev/null
+++ b/net/https/certhashost.c
@@ -0,0 +1,32 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/str/slice.h"
+#include "net/https/https.h"
+
+bool CertHasHost(const mbedtls_x509_crt *cert, const void *s, size_t n) {
+  const mbedtls_x509_sequence *cur;
+  for (cur = &cert->subject_alt_names; cur; cur = cur->next) {
+    if ((cur->buf.tag & MBEDTLS_ASN1_TAG_VALUE_MASK) ==
+            MBEDTLS_X509_SAN_DNS_NAME &&
+        SlicesEqualCase(s, n, cur->buf.p, cur->buf.len)) {
+      return true;
+    }
+  }
+  return false;
+}
diff --git a/net/https/certhasip.c b/net/https/certhasip.c
new file mode 100644
index 000000000..e229037ba
--- /dev/null
+++ b/net/https/certhasip.c
@@ -0,0 +1,32 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/bits/bits.h"
+#include "net/https/https.h"
+
+bool CertHasIp(const mbedtls_x509_crt *cert, uint32_t ip) {
+  const mbedtls_x509_sequence *cur;
+  for (cur = &cert->subject_alt_names; cur; cur = cur->next) {
+    if ((cur->buf.tag & MBEDTLS_ASN1_TAG_VALUE_MASK) ==
+            MBEDTLS_X509_SAN_IP_ADDRESS &&
+        cur->buf.len == 4 && ip == READ32BE(cur->buf.p)) {
+      return true;
+    }
+  }
+  return false;
+}
diff --git a/net/https/chaincertificate.c b/net/https/chaincertificate.c
new file mode 100644
index 000000000..6825dc60b
--- /dev/null
+++ b/net/https/chaincertificate.c
@@ -0,0 +1,35 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/log/log.h"
+#include "libc/runtime/gc.internal.h"
+#include "net/https/https.h"
+
+bool ChainCertificate(mbedtls_x509_crt *cert, mbedtls_x509_crt *parent) {
+  if (!mbedtls_x509_crt_check_signature(cert, parent, 0)) {
+    DEBUGF("chaining %`'s to %`'s", gc(FormatX509Name(&cert->subject)),
+           gc(FormatX509Name(&parent->subject)));
+    cert->next = parent;
+    return true;
+  } else {
+    WARNF("signature check failed for %`'s -> %`'s",
+          gc(FormatX509Name(&cert->subject)),
+          gc(FormatX509Name(&parent->subject)));
+    return false;
+  }
+}
diff --git a/net/https/choosecertificatelifetime.c b/net/https/choosecertificatelifetime.c
new file mode 100644
index 000000000..310f34649
--- /dev/null
+++ b/net/https/choosecertificatelifetime.c
@@ -0,0 +1,33 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/time/struct/tm.h"
+#include "libc/time/time.h"
+#include "net/https/https.h"
+
+void ChooseCertificateLifetime(char notbefore[16], char notafter[16]) {
+  struct tm tm;
+  int64_t past, now, future, lifetime, tolerance;
+  tolerance = 60 * 60 * 24;
+  lifetime = 60 * 60 * 24 * 365;
+  now = nowl();
+  past = now - tolerance;
+  future = now + tolerance + lifetime;
+  FormatSslTime(notbefore, gmtime_r(&past, &tm));
+  FormatSslTime(notafter, gmtime_r(&future, &tm));
+}
diff --git a/net/https/finishcertificate.c b/net/https/finishcertificate.c
new file mode 100644
index 000000000..e94fa6710
--- /dev/null
+++ b/net/https/finishcertificate.c
@@ -0,0 +1,46 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/log/log.h"
+#include "libc/runtime/gc.internal.h"
+#include "libc/x/x.h"
+#include "net/https/https.h"
+
+struct Cert FinishCertificate(struct Cert *ca, mbedtls_x509write_cert *wcert,
+                              mbedtls_ctr_drbg_context *kr,
+                              mbedtls_pk_context *key) {
+  int i, n, rc;
+  unsigned char *p;
+  mbedtls_x509_crt *cert;
+  p = malloc((n = FRAMESIZE));
+  i = mbedtls_x509write_crt_der(wcert, p, n, mbedtls_ctr_drbg_random, kr);
+  if (i < 0) FATALF("write key (grep -0x%04x)", -i);
+  cert = calloc(1, sizeof(mbedtls_x509_crt));
+  mbedtls_x509_crt_parse(cert, p + n - i, i);
+  if (ca) cert->next = ca->cert;
+  mbedtls_x509write_crt_free(wcert);
+  mbedtls_ctr_drbg_free(kr);
+  free(p);
+  if ((rc = mbedtls_pk_check_pair(&cert->pk, key))) {
+    FATALF("generate key (grep -0x%04x)", -rc);
+  }
+  LogCertificate(
+      gc(xasprintf("generated %s certificate", mbedtls_pk_get_name(&cert->pk))),
+      cert);
+  return (struct Cert){cert, key};
+}
diff --git a/net/https/formatx509name.c b/net/https/formatx509name.c
new file mode 100644
index 000000000..b5084d8da
--- /dev/null
+++ b/net/https/formatx509name.c
@@ -0,0 +1,26 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/log/check.h"
+#include "net/https/https.h"
+
+char *FormatX509Name(mbedtls_x509_name *name) {
+  char *s = calloc(1, 1000);
+  CHECK_GT(mbedtls_x509_dn_gets(s, 1000, name), 0);
+  return s;
+}
diff --git a/net/https/generatecertificateserial.c b/net/https/generatecertificateserial.c
new file mode 100644
index 000000000..a90decb39
--- /dev/null
+++ b/net/https/generatecertificateserial.c
@@ -0,0 +1,30 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "net/https/https.h"
+#include "third_party/mbedtls/bignum.h"
+#include "third_party/mbedtls/ctr_drbg.h"
+
+void GenerateCertificateSerial(mbedtls_x509write_cert *wcert,
+                               mbedtls_ctr_drbg_context *kr) {
+  mbedtls_mpi x;
+  mbedtls_mpi_init(&x);
+  mbedtls_mpi_fill_random(&x, 128 / 8, mbedtls_ctr_drbg_random, kr);
+  mbedtls_x509write_crt_set_serial(wcert, &x);
+  mbedtls_mpi_free(&x);
+}
diff --git a/net/https/getentropy.c b/net/https/getentropy.c
new file mode 100644
index 000000000..dee1c7a5e
--- /dev/null
+++ b/net/https/getentropy.c
@@ -0,0 +1,26 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/log/check.h"
+#include "libc/rand/rand.h"
+#include "net/https/https.h"
+
+int GetEntropy(void *c, unsigned char *p, size_t n) {
+  CHECK_EQ(n, getrandom(p, n, 0));
+  return 0;
+}
diff --git a/net/https/https.h b/net/https/https.h
index dbacf4651..32c9e443c 100644
--- a/net/https/https.h
+++ b/net/https/https.h
@@ -1,14 +1,44 @@
 #ifndef COSMOPOLITAN_NET_HTTPS_HTTPS_H_
 #define COSMOPOLITAN_NET_HTTPS_HTTPS_H_
 #include "libc/time/struct/tm.h"
+#include "third_party/mbedtls/ctr_drbg.h"
+#include "third_party/mbedtls/ecp.h"
+#include "third_party/mbedtls/md.h"
+#include "third_party/mbedtls/pk.h"
 #include "third_party/mbedtls/ssl_ciphersuites.h"
 #include "third_party/mbedtls/x509_crt.h"
 #if !(__ASSEMBLER__ + __LINKER__ + 0)
 COSMOPOLITAN_C_START_
 
+struct Cert {
+  mbedtls_x509_crt *cert;
+  mbedtls_pk_context *key;
+};
+
+char *TlsError(int);
 char *DescribeSslVerifyFailure(int);
 mbedtls_x509_crt *GetSslRoots(void);
+void InitializeRng(mbedtls_ctr_drbg_context *);
+int GetEntropy(void *, unsigned char *, size_t);
 void FormatSslTime(char[restrict hasatleast 16], struct tm *);
+void ChooseCertificateLifetime(char[16], char[16]);
+void LogCertificate(const char *, mbedtls_x509_crt *);
+bool IsSelfSigned(mbedtls_x509_crt *);
+char *FormatX509Name(mbedtls_x509_name *);
+void TlsDie(const char *, int) wontreturn;
+bool ChainCertificate(mbedtls_x509_crt *, mbedtls_x509_crt *);
+bool CertHasIp(const mbedtls_x509_crt *, uint32_t);
+bool CertHasHost(const mbedtls_x509_crt *, const void *, size_t);
+bool CertHasCommonName(const mbedtls_x509_crt *, const void *, size_t);
+bool IsServerCert(const struct Cert *, mbedtls_pk_type_t);
+void TlsDebug(void *, int, const char *, int, const char *);
+
+void GenerateCertificateSerial(mbedtls_x509write_cert *,
+                               mbedtls_ctr_drbg_context *);
+mbedtls_pk_context *InitializeKey(struct Cert *, mbedtls_x509write_cert *,
+                                  mbedtls_md_type_t, int);
+struct Cert FinishCertificate(struct Cert *, mbedtls_x509write_cert *,
+                              mbedtls_ctr_drbg_context *, mbedtls_pk_context *);
 
 COSMOPOLITAN_C_END_
 #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
diff --git a/net/https/https.mk b/net/https/https.mk
index 1b7e01ce2..35094697d 100644
--- a/net/https/https.mk
+++ b/net/https/https.mk
@@ -27,11 +27,13 @@ NET_HTTPS_A_DIRECTDEPS =			\
 	LIBC_LOG				\
 	LIBC_MEM				\
 	LIBC_NEXGEN32E				\
+	LIBC_RAND				\
 	LIBC_RUNTIME				\
 	LIBC_STDIO				\
 	LIBC_STR				\
 	LIBC_STUBS				\
 	LIBC_SYSV				\
+	LIBC_TIME				\
 	LIBC_X					\
 	LIBC_ZIPOS				\
 	THIRD_PARTY_MBEDTLS
diff --git a/net/https/initializekey.c b/net/https/initializekey.c
new file mode 100644
index 000000000..22cbdcb45
--- /dev/null
+++ b/net/https/initializekey.c
@@ -0,0 +1,35 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/log/check.h"
+#include "net/https/https.h"
+
+mbedtls_pk_context *InitializeKey(struct Cert *ca,
+                                  mbedtls_x509write_cert *wcert,
+                                  mbedtls_md_type_t md_alg, int type) {
+  mbedtls_pk_context *k;
+  mbedtls_ctr_drbg_context kr;
+  k = calloc(1, sizeof(mbedtls_pk_context));
+  mbedtls_x509write_crt_init(wcert);
+  mbedtls_x509write_crt_set_issuer_key(wcert, ca ? ca->key : k);
+  mbedtls_x509write_crt_set_subject_key(wcert, k);
+  mbedtls_x509write_crt_set_md_alg(wcert, md_alg);
+  mbedtls_x509write_crt_set_version(wcert, MBEDTLS_X509_CRT_VERSION_3);
+  CHECK_EQ(0, mbedtls_pk_setup(k, mbedtls_pk_info_from_type(type)));
+  return k;
+}
diff --git a/net/https/initializerng.c b/net/https/initializerng.c
new file mode 100644
index 000000000..737af255a
--- /dev/null
+++ b/net/https/initializerng.c
@@ -0,0 +1,30 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/log/check.h"
+#include "libc/rand/rand.h"
+#include "net/https/https.h"
+#include "third_party/mbedtls/ctr_drbg.h"
+
+void InitializeRng(mbedtls_ctr_drbg_context *r) {
+  volatile unsigned char b[64];
+  mbedtls_ctr_drbg_init(r);
+  CHECK(getrandom(b, 64, 0) == 64);
+  CHECK(!mbedtls_ctr_drbg_seed(r, GetEntropy, 0, b, 64));
+  mbedtls_platform_zeroize(b, 64);
+}
diff --git a/net/https/isselfsigned.c b/net/https/isselfsigned.c
new file mode 100644
index 000000000..79c8008ba
--- /dev/null
+++ b/net/https/isselfsigned.c
@@ -0,0 +1,23 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "net/https/https.h"
+
+bool IsSelfSigned(mbedtls_x509_crt *cert) {
+  return !mbedtls_x509_name_cmp(&cert->issuer, &cert->subject);
+}
diff --git a/net/https/isservercert.c b/net/https/isservercert.c
new file mode 100644
index 000000000..ea2683b74
--- /dev/null
+++ b/net/https/isservercert.c
@@ -0,0 +1,29 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "net/https/https.h"
+#include "third_party/mbedtls/asn1.h"
+#include "third_party/mbedtls/oid.h"
+
+bool IsServerCert(const struct Cert *cert, mbedtls_pk_type_t type) {
+  return cert->cert && cert->key && !cert->cert->ca_istrue &&
+         mbedtls_pk_get_type(cert->key) == type &&
+         !mbedtls_x509_crt_check_extended_key_usage(
+             cert->cert, MBEDTLS_OID_SERVER_AUTH,
+             MBEDTLS_OID_SIZE(MBEDTLS_OID_SERVER_AUTH));
+}
diff --git a/net/https/logcertificate.c b/net/https/logcertificate.c
new file mode 100644
index 000000000..cf46521e4
--- /dev/null
+++ b/net/https/logcertificate.c
@@ -0,0 +1,33 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/log/log.h"
+#include "net/https/https.h"
+
+void LogCertificate(const char *msg, mbedtls_x509_crt *cert) {
+  char *s;
+  size_t n;
+  if (LOGGABLE(kLogDebug)) {
+    if ((s = malloc((n = 15000)))) {
+      if (mbedtls_x509_crt_info(s, n, " ", cert) > 0) {
+        DEBUGF("%s\n%s", msg, chomp(s));
+      }
+      free(s);
+    }
+  }
+}
diff --git a/net/https/tlsdebug.c b/net/https/tlsdebug.c
new file mode 100644
index 000000000..0605ceb00
--- /dev/null
+++ b/net/https/tlsdebug.c
@@ -0,0 +1,24 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "libc/log/log.h"
+#include "net/https/https.h"
+
+void TlsDebug(void *c, int v, const char *f, int l, const char *s) {
+  flogf(v, f, l, 0, "TLS %s", s);
+}
diff --git a/net/https/tlsdie.c b/net/https/tlsdie.c
new file mode 100644
index 000000000..3eaee5f08
--- /dev/null
+++ b/net/https/tlsdie.c
@@ -0,0 +1,28 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "net/https/https.h"
+
+void TlsDie(const char *s, int r) {
+  if (IsTiny()) {
+    (fprintf)(stderr, "error: %s (-0x%04x %s)\n", s, -r, TlsError(r));
+  } else {
+    (fprintf)(stderr, "error: %s (grep -0x%04x)\n", s, -r);
+  }
+  exit(1);
+}
diff --git a/net/https/tlserror.c b/net/https/tlserror.c
new file mode 100644
index 000000000..4af0c4f80
--- /dev/null
+++ b/net/https/tlserror.c
@@ -0,0 +1,26 @@
+/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚
+β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viβ”‚
+β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
+β”‚ Copyright 2021 Justine Alexandra Roberts Tunney                              β”‚
+β”‚                                                                              β”‚
+β”‚ Permission to use, copy, modify, and/or distribute this software for         β”‚
+β”‚ any purpose with or without fee is hereby granted, provided that the         β”‚
+β”‚ above copyright notice and this permission notice appear in all copies.      β”‚
+β”‚                                                                              β”‚
+β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                β”‚
+β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                β”‚
+β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             β”‚
+β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         β”‚
+β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        β”‚
+β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               β”‚
+β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             β”‚
+β”‚ PERFORMANCE OF THIS SOFTWARE.                                                β”‚
+β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/
+#include "net/https/https.h"
+#include "third_party/mbedtls/error.h"
+
+char *TlsError(int r) {
+  static char b[128];
+  mbedtls_strerror(r, b, sizeof(b));
+  return b;
+}
diff --git a/test/tool/net/redbean_test.c b/test/tool/net/redbean_test.c
index c69707dcd..909a76ede 100644
--- a/test/tool/net/redbean_test.c
+++ b/test/tool/net/redbean_test.c
@@ -22,6 +22,7 @@
 #include "libc/log/check.h"
 #include "libc/runtime/gc.internal.h"
 #include "libc/runtime/runtime.h"
+#include "libc/sock/goodsocket.internal.h"
 #include "libc/sock/sock.h"
 #include "libc/stdio/stdio.h"
 #include "libc/sysv/consts/af.h"
@@ -60,18 +61,8 @@ void SetUpOnce(void) {
   close(fdin);
 }
 
-void Tune(int fd, int a, int b, int x) {
-  if (!b) return;
-  setsockopt(fd, a, b, &x, sizeof(x));
-}
-
 int Socket(void) {
-  int fd;
-  if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
-    Tune(fd, IPPROTO_TCP, TCP_CORK, 0);
-    Tune(fd, IPPROTO_TCP, TCP_NODELAY, 1);
-  }
-  return fd;
+  return GoodSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, false, 0);
 }
 
 char *SendHttpRequest(const char *s) {
diff --git a/third_party/getopt/getopt.c b/third_party/getopt/getopt.c
index dee19a621..c526f0f28 100644
--- a/third_party/getopt/getopt.c
+++ b/third_party/getopt/getopt.c
@@ -156,9 +156,10 @@ int getopt(int nargc, char *const nargv[], const char *ostr) {
       /* option-argument absent */
       getopt_place = kGetoptEmsg;
       if (*ostr == ':') return (BADARG);
-      if (opterr)
+      if (opterr) {
         fprintf(stderr, "%s%s%c\n", program_invocation_name,
                 ": option requires an argument -- ", optopt);
+      }
       return (BADCH);
     }
     getopt_place = kGetoptEmsg;
diff --git a/third_party/mbedtls/check.h b/third_party/mbedtls/check.inc
similarity index 97%
rename from third_party/mbedtls/check.h
rename to third_party/mbedtls/check.inc
index aebf48665..4603ae108 100644
--- a/third_party/mbedtls/check.h
+++ b/third_party/mbedtls/check.inc
@@ -1,5 +1,3 @@
-#ifndef MBEDTLS_CHECK_H
-#define MBEDTLS_CHECK_H
 /* clang-format off */
 
 #if defined(TARGET_LIKE_MBED) && \
@@ -16,10 +14,6 @@
 #error "MBEDTLS_HAVE_TIME_DATE without MBEDTLS_HAVE_TIME does not make sense"
 #endif
 
-#if defined(MBEDTLS_AESNI_C) && !defined(MBEDTLS_HAVE_ASM)
-#error "MBEDTLS_AESNI_C defined, but not all prerequisites"
-#endif
-
 #if defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_AES_C)
 #error "MBEDTLS_CTR_DRBG_C defined, but not all prerequisites"
 #endif
@@ -283,10 +277,6 @@
 #error "MBEDTLS_MEMORY_DEBUG defined, but not all prerequesites"
 #endif
 
-#if defined(MBEDTLS_PADLOCK_C) && !defined(MBEDTLS_HAVE_ASM)
-#error "MBEDTLS_PADLOCK_C defined, but not all prerequisites"
-#endif
-
 #if defined(MBEDTLS_PEM_PARSE_C) && !defined(MBEDTLS_BASE64_C)
 #error "MBEDTLS_PEM_PARSE_C defined, but not all prerequisites"
 #endif
@@ -525,11 +515,6 @@
 #error "MBEDTLS_HAVE_INT32 and MBEDTLS_HAVE_INT64 cannot be defined simultaneously"
 #endif /* MBEDTLS_HAVE_INT32 && MBEDTLS_HAVE_INT64 */
 
-#if ( defined(MBEDTLS_HAVE_INT32) || defined(MBEDTLS_HAVE_INT64) ) && \
-    defined(MBEDTLS_HAVE_ASM)
-#error "MBEDTLS_HAVE_INT32/MBEDTLS_HAVE_INT64 and MBEDTLS_HAVE_ASM cannot be defined simultaneously"
-#endif /* (MBEDTLS_HAVE_INT32 || MBEDTLS_HAVE_INT64) && MBEDTLS_HAVE_ASM */
-
 #if defined(MBEDTLS_SSL_PROTO_SSL3)
 #if defined(MBEDTLS_DEPRECATED_REMOVED)
 #error "MBEDTLS_SSL_PROTO_SSL3 is deprecated and will be removed in a future version of Mbed TLS"
@@ -707,5 +692,3 @@
  * #if defined(MBEDTLS_xxx_C) that results in empty translation units.
  */
 typedef int mbedtls_iso_c_forbids_empty_translation_units;
-
-#endif /* MBEDTLS_CHECK_H */
diff --git a/third_party/mbedtls/config.h b/third_party/mbedtls/config.h
index 76a21a29c..367242e09 100644
--- a/third_party/mbedtls/config.h
+++ b/third_party/mbedtls/config.h
@@ -109,13 +109,12 @@
 #define MBEDTLS_ENTROPY_MAX_SOURCES       4
 #define MBEDTLS_X509_MAX_INTERMEDIATE_CA  8
 
-#ifndef TINY
 /*
  * Boosts performance from 230k qps to 330k
  * Hardens against against sbox side channels
  */
 #define MBEDTLS_AESNI_C
-#define MBEDTLS_HAVE_ASM
+#ifndef TINY
 #define MBEDTLS_HAVE_X86_64
 #define MBEDTLS_HAVE_SSE2
 #endif
@@ -1263,5 +1262,5 @@
 #define MBEDTLS_HAVE_UDBL
 
 #include "libc/dce.h"
-#include "third_party/mbedtls/check.h"
+#include "third_party/mbedtls/check.inc"
 #endif /* MBEDTLS_CONFIG_H_ */
diff --git a/third_party/mbedtls/ecp.c b/third_party/mbedtls/ecp.c
index 557394433..39aa2c10d 100644
--- a/third_party/mbedtls/ecp.c
+++ b/third_party/mbedtls/ecp.c
@@ -22,6 +22,7 @@
 #include "third_party/mbedtls/bignum.h"
 #include "third_party/mbedtls/bignum_internal.h"
 #include "third_party/mbedtls/common.h"
+#include "third_party/mbedtls/config.h"
 #include "third_party/mbedtls/ctr_drbg.h"
 #include "third_party/mbedtls/ecp.h"
 #include "third_party/mbedtls/ecp_internal.h"
@@ -3656,10 +3657,6 @@ cleanup:
     return( ret );
 }
 
-#ifndef MBEDTLS_ECP_DP_SECP192R1_ENABLED
-#undef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED /* >:\ */
-#endif
-
 /**
  * \brief          The ECP checkup routine.
  *
diff --git a/third_party/mbedtls/test/test_suite_asn1parse.c b/third_party/mbedtls/test/test_suite_asn1parse.c
index 5aea897a9..7eb1a2034 100644
--- a/third_party/mbedtls/test/test_suite_asn1parse.c
+++ b/third_party/mbedtls/test/test_suite_asn1parse.c
@@ -689,7 +689,6 @@ void test_get_sequence_of( const data_t *input, int tag,
                 mbedtls_test_set_step( step );
                 TEST_ASSERT( cur != NULL );
                 TEST_EQUAL( cur->buf.tag, tag );
-                printf("yo %`'s\n", rest);
                 n = strtoul( rest, (char **) &rest, 0 );
                 TEST_EQUAL( n, (size_t)( cur->buf.p - input->x ) );
                 ++rest;
diff --git a/tool/build/build.mk b/tool/build/build.mk
index 4ef7a41cf..ae345b52c 100644
--- a/tool/build/build.mk
+++ b/tool/build/build.mk
@@ -36,8 +36,8 @@ TOOL_BUILD_DIRECTDEPS =					\
 	LIBC_MEM					\
 	LIBC_NEXGEN32E					\
 	LIBC_NT_KERNEL32				\
-	LIBC_NT_WS2_32					\
 	LIBC_NT_USER32					\
+	LIBC_NT_WS2_32					\
 	LIBC_RAND					\
 	LIBC_RUNTIME					\
 	LIBC_SOCK					\
@@ -50,12 +50,13 @@ TOOL_BUILD_DIRECTDEPS =					\
 	LIBC_TINYMATH					\
 	LIBC_UNICODE					\
 	LIBC_X						\
+	NET_HTTPS					\
 	THIRD_PARTY_COMPILER_RT				\
 	THIRD_PARTY_GDTOA				\
 	THIRD_PARTY_GETOPT				\
+	THIRD_PARTY_MBEDTLS				\
 	THIRD_PARTY_STB					\
 	THIRD_PARTY_XED					\
-	THIRD_PARTY_MBEDTLS				\
 	THIRD_PARTY_ZLIB				\
 	TOOL_BUILD_LIB
 
diff --git a/tool/build/compile.c b/tool/build/compile.c
index ba48ce5ee..0ee578a76 100644
--- a/tool/build/compile.c
+++ b/tool/build/compile.c
@@ -33,6 +33,7 @@
 #include "libc/nexgen32e/kcpuids.h"
 #include "libc/runtime/runtime.h"
 #include "libc/stdio/append.internal.h"
+#include "libc/stdio/stdio.h"
 #include "libc/str/str.h"
 #include "libc/sysv/consts/rlimit.h"
 #include "libc/sysv/consts/sig.h"
@@ -353,7 +354,7 @@ int main(int argc, char *argv[]) {
   /*
    * parse prefix arguments
    */
-  while ((opt = getopt(argc, argv, "?hntC:M:F:A:T:V:")) != -1) {
+  while ((opt = getopt(argc, argv, "hntC:M:F:A:T:V:")) != -1) {
     switch (opt) {
       case 'n':
         exit(0);
@@ -378,17 +379,16 @@ int main(int argc, char *argv[]) {
       case 'F':
         fszquota = sizetol(optarg, 1000);
         break;
-      case '?':
       case 'h':
-        write(1, MANUAL, sizeof(MANUAL) - 1);
+        fputs(MANUAL, stdout);
         exit(0);
       default:
-        write(2, MANUAL, sizeof(MANUAL) - 1);
+        fputs(MANUAL, stderr);
         exit(1);
     }
   }
   if (optind == argc) {
-    write(2, MANUAL, sizeof(MANUAL) - 1);
+    fputs("error: missing arguments\n", stderr);
     exit(1);
   }
 
diff --git a/tool/build/lib/buildlib.mk b/tool/build/lib/buildlib.mk
index a3133eb9e..5f3012b60 100644
--- a/tool/build/lib/buildlib.mk
+++ b/tool/build/lib/buildlib.mk
@@ -45,6 +45,7 @@ TOOL_BUILD_LIB_A_DIRECTDEPS =				\
 	LIBC_TINYMATH					\
 	LIBC_UNICODE					\
 	LIBC_X						\
+	NET_HTTPS					\
 	THIRD_PARTY_COMPILER_RT				\
 	THIRD_PARTY_MBEDTLS				\
 	THIRD_PARTY_XED
diff --git a/tool/build/lib/eztls.c b/tool/build/lib/eztls.c
index f871e21d6..8815a18a1 100644
--- a/tool/build/lib/eztls.c
+++ b/tool/build/lib/eztls.c
@@ -25,9 +25,11 @@
 #include "libc/sock/sock.h"
 #include "libc/sysv/consts/sig.h"
 #include "libc/x/x.h"
+#include "net/https/https.h"
 #include "third_party/mbedtls/ctr_drbg.h"
 #include "third_party/mbedtls/ecp.h"
 #include "third_party/mbedtls/error.h"
+#include "third_party/mbedtls/platform.h"
 #include "third_party/mbedtls/ssl.h"
 #include "tool/build/lib/eztls.h"
 #include "tool/build/lib/psk.h"
@@ -37,34 +39,6 @@ mbedtls_ssl_config ezconf;
 mbedtls_ssl_context ezssl;
 mbedtls_ctr_drbg_context ezrng;
 
-static char *EzTlsError(int r) {
-  static char b[128];
-  mbedtls_strerror(r, b, sizeof(b));
-  return b;
-}
-
-void EzTlsDie(const char *s, int r) {
-  if (IsTiny()) {
-    fprintf(stderr, "error: %s (-0x%04x %s)\n", s, -r, EzTlsError(r));
-  } else {
-    fprintf(stderr, "error: %s (grep -0x%04x)\n", s, -r);
-  }
-  exit(1);
-}
-
-static int EzGetEntropy(void *c, unsigned char *p, size_t n) {
-  CHECK_EQ(n, getrandom(p, n, 0));
-  return 0;
-}
-
-static void EzInitializeRng(mbedtls_ctr_drbg_context *r) {
-  volatile unsigned char b[64];
-  mbedtls_ctr_drbg_init(r);
-  CHECK(getrandom(b, 64, 0) == 64);
-  CHECK(!mbedtls_ctr_drbg_seed(r, EzGetEntropy, 0, b, 64));
-  mbedtls_platform_zeroize(b, 64);
-}
-
 static ssize_t EzWritevAll(int fd, struct iovec *iov, int iovlen) {
   int i;
   ssize_t rc;
@@ -165,34 +139,38 @@ static int EzTlsRecv(void *ctx, unsigned char *buf, size_t len, uint32_t tmo) {
   return EzTlsRecvImpl(ctx, buf, len, tmo);
 }
 
+void EzFd(int fd) {
+  mbedtls_ssl_session_reset(&ezssl);
+  mbedtls_platform_zeroize(&ezbio, sizeof(ezbio));
+  ezbio.fd = fd;
+}
+
 void EzHandshake(void) {
   int rc;
   while ((rc = mbedtls_ssl_handshake(&ezssl))) {
     if (rc != MBEDTLS_ERR_SSL_WANT_READ) {
-      EzTlsDie("handshake failed", rc);
+      TlsDie("handshake failed", rc);
     }
   }
   while ((rc = EzTlsFlush(&ezbio, 0, 0))) {
     if (rc != MBEDTLS_ERR_SSL_WANT_READ) {
-      EzTlsDie("handshake flush failed", rc);
+      TlsDie("handshake flush failed", rc);
     }
   }
 }
 
-/*
- * openssl s_client -connect 127.0.0.1:31337 \
- *   -psk $(hex <~/.runit.psk)               \
- *   -psk_identity runit
- */
-
-void SetupPresharedKeySsl(int endpoint) {
+void EzInitialize(void) {
   xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
-  EzInitializeRng(&ezrng);
   ezconf.disable_compression = 1; /* TODO(jart): Why does it behave weirdly? */
-  mbedtls_ssl_config_defaults(&ezconf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM,
-                              MBEDTLS_SSL_PRESET_SUITEC);
+  InitializeRng(&ezrng);
+}
+
+void EzSetup(char psk[32]) {
+  int rc;
   mbedtls_ssl_conf_rng(&ezconf, mbedtls_ctr_drbg_random, &ezrng);
-  DCHECK_EQ(0, mbedtls_ssl_conf_psk(&ezconf, GetRunitPsk(), 32, "runit", 5));
-  DCHECK_EQ(0, mbedtls_ssl_setup(&ezssl, &ezconf));
+  if ((rc = mbedtls_ssl_conf_psk(&ezconf, psk, 32, "runit", 5)) ||
+      (rc = mbedtls_ssl_setup(&ezssl, &ezconf))) {
+    TlsDie("EzSetup", rc);
+  }
   mbedtls_ssl_set_bio(&ezssl, &ezbio, EzTlsSend, 0, EzTlsRecv);
 }
diff --git a/tool/build/lib/eztls.h b/tool/build/lib/eztls.h
index f0ee84350..5c659f227 100644
--- a/tool/build/lib/eztls.h
+++ b/tool/build/lib/eztls.h
@@ -2,6 +2,7 @@
 #define COSMOPOLITAN_TOOL_BUILD_LIB_EZTLS_H_
 #include "third_party/mbedtls/ctr_drbg.h"
 #include "third_party/mbedtls/ssl.h"
+#include "third_party/mbedtls/x509_crt.h"
 #if !(__ASSEMBLER__ + __LINKER__ + 0)
 COSMOPOLITAN_C_START_
 
@@ -17,11 +18,24 @@ extern mbedtls_ssl_config ezconf;
 extern mbedtls_ssl_context ezssl;
 extern mbedtls_ctr_drbg_context ezrng;
 
+void EzFd(int);
 void EzHandshake(void);
-void SetupPresharedKeySsl(int);
-void EzTlsDie(const char *, int) wontreturn;
+void EzSetup(char[32]);
+void EzInitialize(void);
 int EzTlsFlush(struct EzTlsBio *, const unsigned char *, size_t);
 
+/*
+ * openssl s_client -connect 127.0.0.1:31337 \
+ *   -psk $(hex <~/.runit.psk)               \
+ *   -psk_identity runit
+ */
+forceinline void SetupPresharedKeySsl(int endpoint, char psk[32]) {
+  EzInitialize();
+  mbedtls_ssl_config_defaults(&ezconf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM,
+                              MBEDTLS_SSL_PRESET_SUITEC);
+  EzSetup(psk);
+}
+
 COSMOPOLITAN_C_END_
 #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
 #endif /* COSMOPOLITAN_TOOL_BUILD_LIB_EZTLS_H_ */
diff --git a/tool/build/runit.c b/tool/build/runit.c
index 34ddc1a7b..00ccf8414 100644
--- a/tool/build/runit.c
+++ b/tool/build/runit.c
@@ -42,8 +42,10 @@
 #include "libc/sysv/consts/sock.h"
 #include "libc/time/time.h"
 #include "libc/x/x.h"
+#include "net/https/https.h"
 #include "third_party/mbedtls/ssl.h"
 #include "tool/build/lib/eztls.h"
+#include "tool/build/lib/psk.h"
 #include "tool/build/runit.h"
 
 /**
@@ -336,7 +338,7 @@ bool Recv(unsigned char *p, size_t n) {
       usleep((backoff = (backoff + 1000) * 2));
       return false;
     } else if (rc < 0) {
-      EzTlsDie("read response failed", rc);
+      TlsDie("read response failed", rc);
     }
   }
   return true;
@@ -387,9 +389,8 @@ int RunOnHost(char *spec) {
            1);
   if (!strchr(g_hostname, '.')) strcat(g_hostname, ".test.");
   do {
-    mbedtls_ssl_session_reset(&ezssl);
     Connect();
-    ezbio.fd = g_sock;
+    EzFd(g_sock);
     EzHandshake();
     SendRequest();
   } while ((rc = ReadResponse()) == -1);
@@ -454,7 +455,7 @@ int RunRemoteTestsInParallel(char *hosts[], int count) {
 
 int main(int argc, char *argv[]) {
   showcrashreports();
-  SetupPresharedKeySsl(MBEDTLS_SSL_IS_CLIENT);
+  SetupPresharedKeySsl(MBEDTLS_SSL_IS_CLIENT, GetRunitPsk());
   /* __log_level = kLogDebug; */
   if (argc > 1 &&
       (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
diff --git a/tool/build/runitd.c b/tool/build/runitd.c
index b1de47ce4..0af4f97da 100644
--- a/tool/build/runitd.c
+++ b/tool/build/runitd.c
@@ -45,9 +45,11 @@
 #include "libc/sysv/consts/w.h"
 #include "libc/time/time.h"
 #include "libc/x/x.h"
+#include "net/https/https.h"
 #include "third_party/getopt/getopt.h"
 #include "third_party/mbedtls/ssl.h"
 #include "tool/build/lib/eztls.h"
+#include "tool/build/lib/psk.h"
 #include "tool/build/runit.h"
 
 /**
@@ -264,13 +266,13 @@ void HandleClient(void) {
     close(g_clifd);
     return;
   }
-  ezbio.fd = g_clifd;
+  EzFd(g_clifd);
   EzHandshake();
   addrstr = gc(DescribeAddress(&addr));
   DEBUGF("%s %s %s", gc(DescribeAddress(&g_servaddr)), "accepted", addrstr);
   while ((got = mbedtls_ssl_read(&ezssl, (p = g_buf), sizeof(g_buf))) < 0) {
     if (got != MBEDTLS_ERR_SSL_WANT_READ) {
-      EzTlsDie("ssl read failed", got);
+      TlsDie("ssl read failed", got);
     }
   }
   CHECK_GE(got, kMinMsgSize);
@@ -302,7 +304,7 @@ void HandleClient(void) {
   while (remaining) {
     while ((got = mbedtls_ssl_read(&ezssl, g_buf, sizeof(g_buf))) < 0) {
       if (got != MBEDTLS_ERR_SSL_WANT_READ) {
-        EzTlsDie("ssl read failed", got);
+        TlsDie("ssl read failed", got);
       }
     }
     CHECK_LE(got, remaining);
@@ -443,7 +445,7 @@ void Daemonize(void) {
 
 int main(int argc, char *argv[]) {
   showcrashreports();
-  SetupPresharedKeySsl(MBEDTLS_SSL_IS_SERVER);
+  SetupPresharedKeySsl(MBEDTLS_SSL_IS_SERVER, GetRunitPsk());
   /* __log_level = kLogDebug; */
   GetOpts(argc, argv);
   CHECK_NE(-1, (g_devnullfd = open("/dev/null", O_RDWR)));
diff --git a/tool/build/zipobj.c b/tool/build/zipobj.c
index 1271b2891..3b6a79e38 100644
--- a/tool/build/zipobj.c
+++ b/tool/build/zipobj.c
@@ -124,34 +124,10 @@ void GetOpts(int *argc, char ***argv) {
   CHECK_NOTNULL(outpath_);
 }
 
-bool IsUtf8(const void *data, size_t size) {
-  const unsigned char *p, *pe;
-  for (p = data, pe = p + size; p + 2 <= pe; ++p) {
-    if (p[0] >= 0300) {
-      if (p[1] >= 0200 && p[1] < 0300) {
-        return true;
-      } else {
-        return false;
-      }
-    }
-  }
-  return false;
-}
-
-bool IsText(const void *data, size_t size) {
-  const unsigned char *p, *pe;
-  for (p = data, pe = p + size; p < pe; ++p) {
-    if (*p <= 3) {
-      return false;
-    }
-  }
-  return true;
-}
-
 bool ShouldCompress(const char *name, size_t namesize,
                     const unsigned char *data, size_t datasize) {
   return !nocompress_ && datasize >= 64 && !IsNoCompressExt(name, namesize) &&
-         (datasize < 1000 || MeasureEntropy((void *)data, 1000) < 6);
+         (datasize < 1000 || MeasureEntropy((void *)data, 1000) < 7);
 }
 
 void GetDosLocalTime(int64_t utcunixts, uint16_t *out_time,
diff --git a/tool/net/redbean.c b/tool/net/redbean.c
index a936e2113..371886586 100644
--- a/tool/net/redbean.c
+++ b/tool/net/redbean.c
@@ -21,6 +21,7 @@
 #include "libc/bits/popcnt.h"
 #include "libc/bits/safemacros.internal.h"
 #include "libc/calls/calls.h"
+#include "libc/calls/math.h"
 #include "libc/calls/sigbits.h"
 #include "libc/calls/struct/dirent.h"
 #include "libc/calls/struct/flock.h"
@@ -50,10 +51,12 @@
 #include "libc/runtime/directmap.internal.h"
 #include "libc/runtime/gc.internal.h"
 #include "libc/runtime/runtime.h"
+#include "libc/sock/goodsocket.internal.h"
 #include "libc/sock/sock.h"
 #include "libc/stdio/append.internal.h"
 #include "libc/stdio/hex.internal.h"
 #include "libc/stdio/stdio.h"
+#include "libc/str/slice.h"
 #include "libc/str/str.h"
 #include "libc/str/undeflate.h"
 #include "libc/sysv/consts/af.h"
@@ -106,6 +109,7 @@
 #include "third_party/mbedtls/entropy_poll.h"
 #include "third_party/mbedtls/error.h"
 #include "third_party/mbedtls/iana.h"
+#include "third_party/mbedtls/md.h"
 #include "third_party/mbedtls/md5.h"
 #include "third_party/mbedtls/oid.h"
 #include "third_party/mbedtls/pk.h"
@@ -267,10 +271,7 @@ static struct Suites {
 
 static struct Certs {
   size_t n;
-  struct Cert {
-    mbedtls_x509_crt *cert;
-    mbedtls_pk_context *key;
-  } * p;
+  struct Cert *p;
 } certs;
 
 static struct Redirects {
@@ -480,39 +481,6 @@ static long ParseInt(const char *s) {
   return strtol(s, 0, 0);
 }
 
-forceinline bool SlicesEqual(const char *a, size_t n, const char *b, size_t m) {
-  return n == m && !memcmp(a, b, n);
-}
-
-forceinline bool SlicesEqualCase(const void *a, size_t n, const void *b,
-                                 size_t m) {
-  return n == m && !memcasecmp(a, b, n);
-}
-
-static int CompareSlices(const char *a, size_t n, const char *b, size_t m) {
-  int c;
-  if ((c = memcmp(a, b, MIN(n, m)))) return c;
-  if (n < m) return -1;
-  if (n > m) return +1;
-  return 0;
-}
-
-static int CompareSlicesCase(const char *a, size_t n, const char *b, size_t m) {
-  int c;
-  if ((c = memcasecmp(a, b, MIN(n, m)))) return c;
-  if (n < m) return -1;
-  if (n > m) return +1;
-  return 0;
-}
-
-static bool StartsWithIgnoreCase(const char *s, const char *prefix) {
-  for (;;) {
-    if (!*prefix) return true;
-    if (!*s) return false;
-    if (kToLower[*s++ & 255] != (*prefix++ & 255)) return false;
-  }
-}
-
 static void *FreeLater(void *p) {
   if (p) {
     if (++freelist.n > freelist.c) {
@@ -587,28 +555,6 @@ static long FindRedirect(const char *s, size_t n) {
   return -1;
 }
 
-static void LogCertificate(const char *msg, mbedtls_x509_crt *cert) {
-  char *s;
-  size_t n;
-  if (LOGGABLE(kLogDebug)) {
-    if ((s = gc(malloc((n = 15000))))) {
-      if (mbedtls_x509_crt_info(s, n, " ", cert) > 0) {
-        DEBUGF("%s\n%s", msg, chomp(s));
-      }
-    }
-  }
-}
-
-static char *FormatX509Name(mbedtls_x509_name *name) {
-  char *s = calloc(1, 1000);
-  CHECK_GT(mbedtls_x509_dn_gets(s, 1000, name), 0);
-  return s;
-}
-
-static bool IsSelfSigned(mbedtls_x509_crt *cert) {
-  return !mbedtls_x509_name_cmp(&cert->issuer, &cert->subject);
-}
-
 static mbedtls_x509_crt *GetTrustedCertificate(mbedtls_x509_name *name) {
   size_t i;
   for (i = 0; i < certs.n; ++i) {
@@ -628,20 +574,6 @@ static void UseCertificate(mbedtls_ssl_config *c, struct Cert *kp,
   CHECK_EQ(0, mbedtls_ssl_conf_own_cert(c, kp->cert, kp->key));
 }
 
-static bool ChainCertificate(mbedtls_x509_crt *cert, mbedtls_x509_crt *parent) {
-  if (!mbedtls_x509_crt_check_signature(cert, parent, 0)) {
-    DEBUGF("chaining %`'s to %`'s", gc(FormatX509Name(&cert->subject)),
-           gc(FormatX509Name(&parent->subject)));
-    cert->next = parent;
-    return true;
-  } else {
-    WARNF("signature check failed for %`'s -> %`'s",
-          gc(FormatX509Name(&cert->subject)),
-          gc(FormatX509Name(&parent->subject)));
-    return false;
-  }
-}
-
 static void AppendCert(mbedtls_x509_crt *cert, mbedtls_pk_context *key) {
   certs.p = realloc(certs.p, ++certs.n * sizeof(*certs.p));
   certs.p[certs.n - 1].cert = cert;
@@ -1179,34 +1111,6 @@ static void ReportWorkerExit(int pid, int ws) {
   }
 }
 
-static void AddTimeval(struct timeval *x, const struct timeval *y) {
-  x->tv_sec += y->tv_sec;
-  x->tv_usec += y->tv_usec;
-  if (x->tv_usec >= 1000000) {
-    x->tv_usec -= 1000000;
-    x->tv_sec += 1;
-  }
-}
-
-static void AddRusage(struct rusage *x, const struct rusage *y) {
-  AddTimeval(&x->ru_utime, &y->ru_utime);
-  AddTimeval(&x->ru_stime, &y->ru_stime);
-  x->ru_maxrss = MAX(x->ru_maxrss, y->ru_maxrss);
-  x->ru_ixrss += y->ru_ixrss;
-  x->ru_idrss += y->ru_idrss;
-  x->ru_isrss += y->ru_isrss;
-  x->ru_minflt += y->ru_minflt;
-  x->ru_majflt += y->ru_majflt;
-  x->ru_nswap += y->ru_nswap;
-  x->ru_inblock += y->ru_inblock;
-  x->ru_oublock += y->ru_oublock;
-  x->ru_msgsnd += y->ru_msgsnd;
-  x->ru_msgrcv += y->ru_msgrcv;
-  x->ru_nsignals += y->ru_nsignals;
-  x->ru_nvcsw += y->ru_nvcsw;
-  x->ru_nivcsw += y->ru_nivcsw;
-}
-
 static void ReportWorkerResources(int pid, struct rusage *ru) {
   char *s, *b = 0;
   if (logrusage || LOGGABLE(kLogDebug)) {
@@ -1389,11 +1293,6 @@ static int TlsRecv(void *ctx, unsigned char *buf, size_t len, uint32_t tmo) {
   return TlsRecvImpl(ctx, buf, len, tmo);
 }
 
-static void TlsDebug(void *ctx, int level, const char *file, int line,
-                     const char *message) {
-  flogf(level, file, line, 0, "TLS %s", message);
-}
-
 static ssize_t SslRead(int fd, void *buf, size_t size) {
   int rc;
   rc = mbedtls_ssl_read(&ssl, buf, size);
@@ -1473,12 +1372,11 @@ static void WipeServingKeys(void) {
   }
 }
 
-static bool CertHasCommonName(const mbedtls_x509_crt *cert,
-                              const unsigned char *host, size_t size) {
+bool CertHasCommonName(const mbedtls_x509_crt *cert, const void *s, size_t n) {
   const mbedtls_x509_name *name;
   for (name = &cert->subject; name; name = name->next) {
     if (!MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid)) {
-      if (SlicesEqualCase(host, size, name->val.p, name->val.len)) {
+      if (SlicesEqualCase(s, n, name->val.p, name->val.len)) {
         return true;
       }
       break;
@@ -1487,44 +1385,11 @@ static bool CertHasCommonName(const mbedtls_x509_crt *cert,
   return false;
 }
 
-static bool CertHasHost(const mbedtls_x509_crt *cert, const unsigned char *host,
-                        size_t size) {
-  const mbedtls_x509_sequence *cur;
-  for (cur = &cert->subject_alt_names; cur; cur = cur->next) {
-    if ((cur->buf.tag & MBEDTLS_ASN1_TAG_VALUE_MASK) ==
-            MBEDTLS_X509_SAN_DNS_NAME &&
-        SlicesEqualCase(host, size, cur->buf.p, cur->buf.len)) {
-      return true;
-    }
-  }
-  return false;
-}
-
-static bool CertHasIp(const mbedtls_x509_crt *cert, uint32_t ip) {
-  const mbedtls_x509_sequence *cur;
-  for (cur = &cert->subject_alt_names; cur; cur = cur->next) {
-    if ((cur->buf.tag & MBEDTLS_ASN1_TAG_VALUE_MASK) ==
-            MBEDTLS_X509_SAN_IP_ADDRESS &&
-        cur->buf.len == 4 && ip == READ32BE(cur->buf.p)) {
-      return true;
-    }
-  }
-  return false;
-}
-
-static bool IsServerCert(mbedtls_pk_type_t type, int i) {
-  return certs.p[i].cert && certs.p[i].key && !certs.p[i].cert->ca_istrue &&
-         mbedtls_pk_get_type(certs.p[i].key) == type &&
-         !mbedtls_x509_crt_check_extended_key_usage(
-             certs.p[i].cert, MBEDTLS_OID_SERVER_AUTH,
-             MBEDTLS_OID_SIZE(MBEDTLS_OID_SERVER_AUTH));
-}
-
 static bool TlsRouteFind(mbedtls_pk_type_t type, mbedtls_ssl_context *ssl,
                          const unsigned char *host, size_t size, int64_t ip) {
   int i;
   for (i = 0; i < certs.n; ++i) {
-    if (IsServerCert(type, i) &&
+    if (IsServerCert(certs.p + i, type) &&
         (((certs.p[i].cert->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) &&
           (ip == -1 ? CertHasHost(certs.p[i].cert, host, size)
                     : CertHasIp(certs.p[i].cert, ip))) ||
@@ -1543,7 +1408,7 @@ static bool TlsRouteFind(mbedtls_pk_type_t type, mbedtls_ssl_context *ssl,
 static bool TlsRouteFirst(mbedtls_pk_type_t type, mbedtls_ssl_context *ssl) {
   int i;
   for (i = 0; i < certs.n; ++i) {
-    if (IsServerCert(type, i)) {
+    if (IsServerCert(certs.p + i, type)) {
       CHECK_EQ(
           0, mbedtls_ssl_set_hs_own_cert(ssl, certs.p[i].cert, certs.p[i].key));
       DEBUGF("TlsRoute(%s) %s %`'s", mbedtls_pk_type_name(type),
@@ -1679,40 +1544,6 @@ static bool TlsSetup(void) {
   }
 }
 
-static int GetEntropy(void *c, unsigned char *p, size_t n) {
-  CHECK_EQ(n, getrandom(p, n, 0));
-  return 0;
-}
-
-static void InitializeRng(mbedtls_ctr_drbg_context *r) {
-  volatile unsigned char b[64];
-  mbedtls_ctr_drbg_init(r);
-  CHECK(getrandom(b, 64, 0) == 64);
-  CHECK(!mbedtls_ctr_drbg_seed(r, GetEntropy, 0, b, 64));
-  mbedtls_platform_zeroize(b, 64);
-}
-
-static void GenerateSerial(mbedtls_x509write_cert *wcert,
-                           mbedtls_ctr_drbg_context *kr) {
-  mbedtls_mpi x;
-  mbedtls_mpi_init(&x);
-  mbedtls_mpi_fill_random(&x, 128 / 8, mbedtls_ctr_drbg_random, kr);
-  mbedtls_x509write_crt_set_serial(wcert, &x);
-  mbedtls_mpi_free(&x);
-}
-
-static void ChooseCertificateLifetime(char notbefore[16], char notafter[16]) {
-  struct tm tm;
-  int64_t past, now, future, lifetime, tolerance;
-  tolerance = 60 * 60 * 24;
-  lifetime = 60 * 60 * 24 * 365;
-  now = nowl();
-  past = now - tolerance;
-  future = now + tolerance + lifetime;
-  FormatSslTime(notbefore, gmtime_r(&past, &tm));
-  FormatSslTime(notafter, gmtime_r(&future, &tm));
-}
-
 static void ConfigureCertificate(mbedtls_x509write_cert *cw, struct Cert *ca,
                                  int usage, int type) {
   int r;
@@ -1766,8 +1597,10 @@ static void ConfigureCertificate(mbedtls_x509write_cert *cw, struct Cert *ca,
   if ((r = mbedtls_x509write_crt_set_subject_alternative_name(cw, san, nsan)) ||
       (r = mbedtls_x509write_crt_set_validity(cw, notbefore, notafter)) ||
       (r = mbedtls_x509write_crt_set_basic_constraints(cw, false, -1)) ||
+#if defined(MBEDTLS_SHA1_C)
       (r = mbedtls_x509write_crt_set_subject_key_identifier(cw)) ||
       (r = mbedtls_x509write_crt_set_authority_key_identifier(cw)) ||
+#endif
       (r = mbedtls_x509write_crt_set_key_usage(cw, usage)) ||
       (r = mbedtls_x509write_crt_set_ext_key_usage(cw, type)) ||
       (r = mbedtls_x509write_crt_set_subject_name(cw, subject)) ||
@@ -1794,57 +1627,18 @@ static struct Cert GetKeySigningKey(void) {
   return (struct Cert){0};
 }
 
-static mbedtls_pk_context *InitializeKey(struct Cert *ca,
-                                         mbedtls_x509write_cert *wcert,
-                                         int type) {
-  mbedtls_pk_context *k;
-  mbedtls_ctr_drbg_context kr;
-  k = calloc(1, sizeof(mbedtls_pk_context));
-  mbedtls_x509write_crt_init(wcert);
-  mbedtls_x509write_crt_set_issuer_key(wcert, ca ? ca->key : k);
-  mbedtls_x509write_crt_set_subject_key(wcert, k);
-  mbedtls_x509write_crt_set_md_alg(
-      wcert, suiteb ? MBEDTLS_MD_SHA384 : MBEDTLS_MD_SHA256);
-  mbedtls_x509write_crt_set_version(wcert, MBEDTLS_X509_CRT_VERSION_3);
-  CHECK_EQ(0, mbedtls_pk_setup(k, mbedtls_pk_info_from_type(type)));
-  return k;
-}
-
-static struct Cert FinishCertificate(struct Cert *ca,
-                                     mbedtls_x509write_cert *wcert,
-                                     mbedtls_ctr_drbg_context *kr,
-                                     mbedtls_pk_context *key) {
-  int i, n, rc;
-  unsigned char *p;
-  mbedtls_x509_crt *cert;
-  p = malloc((n = FRAMESIZE));
-  i = mbedtls_x509write_crt_der(wcert, p, n, mbedtls_ctr_drbg_random, kr);
-  if (i < 0) FATALF("write key (grep -0x%04x)", -i);
-  cert = calloc(1, sizeof(mbedtls_x509_crt));
-  mbedtls_x509_crt_parse(cert, p + n - i, i);
-  if (ca) cert->next = ca->cert;
-  mbedtls_x509write_crt_free(wcert);
-  mbedtls_ctr_drbg_free(kr);
-  free(p);
-  if ((rc = mbedtls_pk_check_pair(&cert->pk, key))) {
-    FATALF("generate key (grep -0x%04x)", -rc);
-  }
-  LogCertificate(
-      gc(xasprintf("generated %s certificate", mbedtls_pk_get_name(&cert->pk))),
-      cert);
-  return (struct Cert){cert, key};
-}
-
 static struct Cert GenerateEcpCertificate(struct Cert *ca) {
   mbedtls_pk_context *key;
+  mbedtls_md_type_t md_alg;
   mbedtls_ctr_drbg_context kr;
   mbedtls_x509write_cert wcert;
   InitializeRng(&kr);
-  key = InitializeKey(ca, &wcert, MBEDTLS_PK_ECKEY);
+  md_alg = suiteb ? MBEDTLS_MD_SHA384 : MBEDTLS_MD_SHA256;
+  key = InitializeKey(ca, &wcert, md_alg, MBEDTLS_PK_ECKEY);
   CHECK_EQ(0, mbedtls_ecp_gen_key(
                   suiteb ? MBEDTLS_ECP_DP_SECP384R1 : MBEDTLS_ECP_DP_SECP256R1,
                   mbedtls_pk_ec(*key), mbedtls_ctr_drbg_random, &kr));
-  GenerateSerial(&wcert, &kr);
+  GenerateCertificateSerial(&wcert, &kr);
   ConfigureCertificate(&wcert, ca, MBEDTLS_X509_KU_DIGITAL_SIGNATURE,
                        MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER |
                            MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT);
@@ -1853,13 +1647,15 @@ static struct Cert GenerateEcpCertificate(struct Cert *ca) {
 
 static struct Cert GenerateRsaCertificate(struct Cert *ca) {
   mbedtls_pk_context *key;
+  mbedtls_md_type_t md_alg;
   mbedtls_ctr_drbg_context kr;
   mbedtls_x509write_cert wcert;
   InitializeRng(&kr);
-  key = InitializeKey(ca, &wcert, MBEDTLS_PK_RSA);
+  md_alg = suiteb ? MBEDTLS_MD_SHA384 : MBEDTLS_MD_SHA256;
+  key = InitializeKey(ca, &wcert, md_alg, MBEDTLS_PK_RSA);
   CHECK_EQ(0, mbedtls_rsa_gen_key(mbedtls_pk_rsa(*key), mbedtls_ctr_drbg_random,
                                   &kr, suiteb ? 4096 : 2048, 65537));
-  GenerateSerial(&wcert, &kr);
+  GenerateCertificateSerial(&wcert, &kr);
   ConfigureCertificate(
       &wcert, ca,
       MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_ENCIPHERMENT,
@@ -1942,65 +1738,6 @@ static int64_t GetGmtOffset(int64_t t) {
   return tm.tm_gmtoff;
 }
 
-static int64_t LocoTimeToZulu(int64_t x) {
-  return x - gmtoff;
-}
-
-static int64_t GetZipCfileLastModified(const uint8_t *zcf) {
-  const uint8_t *p, *pe;
-  for (p = ZIP_CFILE_EXTRA(zcf), pe = p + ZIP_CFILE_EXTRASIZE(zcf); p + 4 <= pe;
-       p += ZIP_EXTRA_SIZE(p)) {
-    if (ZIP_EXTRA_HEADERID(p) == kZipExtraNtfs &&
-        ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4 + 8 &&
-        READ16LE(ZIP_EXTRA_CONTENT(p) + 4) == 1 &&
-        READ16LE(ZIP_EXTRA_CONTENT(p) + 6) >= 8) {
-      return READ64LE(ZIP_EXTRA_CONTENT(p) + 8) / HECTONANOSECONDS -
-             MODERNITYSECONDS; /* TODO(jart): update access time */
-    }
-  }
-  for (p = ZIP_CFILE_EXTRA(zcf), pe = p + ZIP_CFILE_EXTRASIZE(zcf); p + 4 <= pe;
-       p += ZIP_EXTRA_SIZE(p)) {
-    if (ZIP_EXTRA_HEADERID(p) == kZipExtraExtendedTimestamp &&
-        ZIP_EXTRA_CONTENTSIZE(p) >= 1 + 4 && (*ZIP_EXTRA_CONTENT(p) & 1)) {
-      return (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 1);
-    }
-  }
-  for (p = ZIP_CFILE_EXTRA(zcf), pe = p + ZIP_CFILE_EXTRASIZE(zcf); p + 4 <= pe;
-       p += ZIP_EXTRA_SIZE(p)) {
-    if (ZIP_EXTRA_HEADERID(p) == kZipExtraUnix &&
-        ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4) {
-      return (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 4);
-    }
-  }
-  return LocoTimeToZulu(DosDateTimeToUnix(ZIP_CFILE_LASTMODIFIEDDATE(zcf),
-                                          ZIP_CFILE_LASTMODIFIEDTIME(zcf)));
-}
-
-static int64_t GetZipCfileCreation(const uint8_t *zcf) {
-  const uint8_t *p, *pe;
-  for (p = ZIP_CFILE_EXTRA(zcf), pe = p + ZIP_CFILE_EXTRASIZE(zcf); p + 4 <= pe;
-       p += ZIP_EXTRA_SIZE(p)) {
-    if (ZIP_EXTRA_HEADERID(p) == kZipExtraNtfs &&
-        ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4 + 8 * 3 &&
-        READ16LE(ZIP_EXTRA_CONTENT(p) + 4) == 1 &&
-        READ16LE(ZIP_EXTRA_CONTENT(p) + 6) >= 24) {
-      return READ64LE(ZIP_EXTRA_CONTENT(p) + 8 + 8 + 8) / HECTONANOSECONDS -
-             MODERNITYSECONDS;
-    }
-  }
-  for (p = ZIP_CFILE_EXTRA(zcf), pe = p + ZIP_CFILE_EXTRASIZE(zcf); p + 4 <= pe;
-       p += ZIP_EXTRA_SIZE(p)) {
-    if (ZIP_EXTRA_HEADERID(p) == kZipExtraExtendedTimestamp &&
-        ZIP_EXTRA_CONTENTSIZE(p) >= 1 && (*ZIP_EXTRA_CONTENT(p) & 4) &&
-        ZIP_EXTRA_CONTENTSIZE(p) >=
-            1 + popcnt((*ZIP_EXTRA_CONTENT(p) & 7)) * 4) {
-      return (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 1 +
-                               popcnt((*ZIP_EXTRA_CONTENT(p) & 3)) * 4);
-    }
-  }
-  return GetZipCfileLastModified(zcf);
-}
-
 forceinline bool IsCompressed(struct Asset *a) {
   return !a->file &&
          ZIP_LFILE_COMPRESSIONMETHOD(zbase + a->lf) == kZipCompressionDeflate;
@@ -2054,9 +1791,9 @@ static void FreeStrings(struct Strings *l) {
 }
 
 static void IndexAssets(void) {
-  int64_t lm;
   uint64_t cf;
   struct Asset *p;
+  struct timespec lm;
   uint32_t i, n, m, step, hash;
   DEBUGF("indexing assets (inode %#lx)", zst.st_ino);
   CHECK_GE(HASH_LOAD_FACTOR, 2);
@@ -2080,13 +1817,13 @@ static void IndexAssets(void) {
       i = (hash + (step * (step + 1)) >> 1) & (m - 1);
       ++step;
     } while (p[i].hash);
-    lm = GetZipCfileLastModified(zbase + cf);
+    GetZipCfileTimestamps(zbase + cf, &lm, 0, 0, gmtoff);
     p[i].hash = hash;
     p[i].cf = cf;
     p[i].lf = GetZipCfileOffset(zbase + cf);
     p[i].istext = !!(ZIP_CFILE_INTERNALATTRIBUTES(zbase + cf) & kZipIattrText);
-    p[i].lastmodified = lm;
-    p[i].lastmodifiedstr = FormatUnixHttpDateTime(xmalloc(30), lm);
+    p[i].lastmodified = lm.tv_sec;
+    p[i].lastmodifiedstr = FormatUnixHttpDateTime(xmalloc(30), lm.tv_sec);
   }
   assets.p = p;
   assets.n = m;
@@ -2891,9 +2628,9 @@ static char *ServeListing(void) {
   uint8_t *zcf;
   struct tm tm;
   const char *and;
-  int64_t lastmod;
   struct rusage ru;
   char *p, *q, *path;
+  struct timespec lastmod;
   char rb[8], tb[20], *rp[6];
   size_t i, n, pathlen, rn[6];
   LockInc(&shared->c.listingrequests);
@@ -2951,8 +2688,8 @@ td { padding-right: 3em; }\r\n\
           ZIP_CFILE_COMMENT(zcf),
           strnlen(ZIP_CFILE_COMMENT(zcf), ZIP_CFILE_COMMENTSIZE(zcf)), &rn[3]);
       rp[4] = EscapeHtml(rp[0], rn[0], &rn[4]);
-      lastmod = GetZipCfileLastModified(zcf);
-      localtime_r(&lastmod, &tm);
+      GetZipCfileTimestamps(zcf, &lastmod, 0, 0, gmtoff);
+      localtime_r(&lastmod.tv_sec, &tm);
       iso8601(tb, &tm);
       if (IsCompressionMethodSupported(ZIP_CFILE_COMPRESSIONMETHOD(zcf)) &&
           IsAcceptablePath(path, pathlen)) {
@@ -3421,30 +3158,6 @@ static void GetDosLocalTime(int64_t utcunixts, uint16_t *out_time,
   *out_date = DOS_DATE(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday + 1);
 }
 
-static bool IsUtf8(const void *data, size_t size) {
-  const unsigned char *p, *pe;
-  for (p = data, pe = p + size; p + 2 <= pe; ++p) {
-    if (p[0] >= 0300) {
-      if (p[1] >= 0200 && p[1] < 0300) {
-        return true;
-      } else {
-        return false;
-      }
-    }
-  }
-  return false;
-}
-
-static bool IsText(const void *data, size_t size) {
-  const unsigned char *p, *pe;
-  for (p = data, pe = p + size; p < pe; ++p) {
-    if (*p <= 3) {
-      return false;
-    }
-  }
-  return true;
-}
-
 static int LuaStoreAsset(lua_State *L) {
   int64_t ft;
   int i, mode;
@@ -3646,12 +3359,6 @@ static void ReseedRng(mbedtls_ctr_drbg_context *r, const char *s) {
 #endif
 }
 
-static char *TlsError(int r) {
-  static char b[128];
-  mbedtls_strerror(r, b, sizeof(b));
-  return b;
-}
-
 static wontreturn void LuaThrowTlsError(lua_State *L, const char *s, int r) {
   const char *code;
   code = gc(xasprintf("-0x%04x", -r));
@@ -3663,35 +3370,6 @@ static wontreturn void LuaThrowTlsError(lua_State *L, const char *s, int r) {
   unreachable;
 }
 
-static bool Tune(int fd, int a, int b, int x) {
-  if (!b) return false;
-  return setsockopt(fd, a, b, &x, sizeof(x)) != -1;
-}
-
-static int Socket(int family, int type, int protocol, bool isserver) {
-  int fd;
-  if ((fd = socket(family, type, protocol)) != -1) {
-    if (isserver) {
-      Tune(fd, SOL_TCP, TCP_FASTOPEN, 100);
-      Tune(fd, SOL_SOCKET, SO_REUSEADDR, 1);
-    } else {
-      Tune(fd, SOL_TCP, TCP_FASTOPEN_CONNECT, 1);
-    }
-    if (!Tune(fd, SOL_TCP, TCP_QUICKACK, 1)) {
-      Tune(fd, SOL_TCP, TCP_NODELAY, 1);
-    }
-    if (timeout.tv_sec < 0) {
-      Tune(fd, SOL_SOCKET, SO_KEEPALIVE, 1);
-      Tune(fd, SOL_TCP, TCP_KEEPIDLE, -timeout.tv_sec);
-      Tune(fd, SOL_TCP, TCP_KEEPINTVL, -timeout.tv_sec);
-    } else {
-      setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
-      setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
-    }
-  }
-  return fd;
-}
-
 static char *FoldHeader(struct HttpMessage *msg, char *b, int h, size_t *z) {
   char *p;
   size_t i, n, m;
@@ -3924,8 +3602,8 @@ static int LuaFetch(lua_State *L) {
   ip = ntohl(((struct sockaddr_in *)addr->ai_addr)->sin_addr.s_addr);
   DEBUGF("client connecting %hhu.%hhu.%hhu.%hhu:%d", ip >> 24, ip >> 16,
          ip >> 8, ip, ntohs(((struct sockaddr_in *)addr->ai_addr)->sin_port));
-  CHECK_NE(-1, (sock = Socket(addr->ai_family, addr->ai_socktype,
-                              addr->ai_protocol, false)));
+  CHECK_NE(-1, (sock = GoodSocket(addr->ai_family, addr->ai_socktype,
+                                  addr->ai_protocol, false, &timeout)));
   if (connect(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
     close(sock);
     luaL_error(L, "connect(%s:%s) failed: %s", host, port, strerror(errno));
@@ -5168,13 +4846,17 @@ static int LuaGetLastModifiedTime(lua_State *L) {
   size_t pathlen;
   struct Asset *a;
   const char *path;
+  struct timespec lm;
+  int64_t zuluseconds;
   path = LuaCheckPath(L, 1, &pathlen);
   if ((a = GetAsset(path, pathlen))) {
     if (a->file) {
-      lua_pushinteger(L, a->file->st.st_mtim.tv_sec);
+      zuluseconds = a->file->st.st_mtim.tv_sec;
     } else {
-      lua_pushinteger(L, GetZipCfileLastModified(zbase + a->cf));
+      GetZipCfileTimestamps(zbase + a->cf, &lm, 0, 0, gmtoff);
+      zuluseconds = lm.tv_sec;
     }
+    lua_pushinteger(L, zuluseconds);
   } else {
     lua_pushnil(L);
   }
@@ -6216,8 +5898,8 @@ static char *ServeAsset(struct Asset *a, const char *path, size_t pathlen) {
       }
     } else if (!IsTiny() && msg.method != kHttpHead && !IsSslCompressed() &&
                ClientAcceptsGzip() &&
-               ((contentlength >= 100 && StartsWithIgnoreCase(ct, "text/")) ||
-                (contentlength >= 1000 && MeasureEntropy(content, 1000) < 6))) {
+               ((contentlength >= 100 && startswithi(ct, "text/")) ||
+                (contentlength >= 1000 && MeasureEntropy(content, 1000) < 7))) {
       p = ServeAssetCompressed(a);
     } else {
       p = ServeAssetIdentity(a, ct);
@@ -6725,8 +6407,8 @@ static void Listen(void) {
       servers.p[n].addr.sin_family = AF_INET;
       servers.p[n].addr.sin_port = htons(ports.p[j]);
       servers.p[n].addr.sin_addr.s_addr = htonl(ips.p[i]);
-      if ((servers.p[n].fd = Socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC,
-                                    IPPROTO_TCP, true)) == -1) {
+      if ((servers.p[n].fd = GoodSocket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC,
+                                        IPPROTO_TCP, true, &timeout)) == -1) {
         perror("socket");
         exit(1);
       }
diff --git a/tool/net/wb.c b/tool/net/wb.c
index 2ae4cd5d0..923a48415 100644
--- a/tool/net/wb.c
+++ b/tool/net/wb.c
@@ -27,9 +27,11 @@
 #include "libc/mem/mem.h"
 #include "libc/rand/rand.h"
 #include "libc/runtime/gc.internal.h"
+#include "libc/sock/goodsocket.internal.h"
 #include "libc/sock/sock.h"
 #include "libc/stdio/append.internal.h"
 #include "libc/stdio/stdio.h"
+#include "libc/str/slice.h"
 #include "libc/str/str.h"
 #include "libc/sysv/consts/af.h"
 #include "libc/sysv/consts/ex.h"
@@ -109,37 +111,6 @@ void OnInt(int sig) {
   isdone = true;
 }
 
-static inline bool SlicesEqualCase(const char *a, size_t n, const char *b,
-                                   size_t m) {
-  return n == m && !memcasecmp(a, b, n);
-}
-
-static int GetEntropy(void *c, unsigned char *p, size_t n) {
-  rngset(p, n, rand64, -1);
-  return 0;
-}
-
-static bool TuneSocket(int fd, int a, int b, int x) {
-  if (!b) return false;
-  return setsockopt(fd, a, b, &x, sizeof(x)) != -1;
-}
-
-static int Socket(int family, int type, int protocol) {
-  int fd;
-  if ((fd = socket(family, type, protocol)) != -1) {
-    /* TuneSocket(fd, SOL_SOCKET, SO_KEEPALIVE, 1); */
-    /* if (protocol == SOL_TCP) { */
-    /*   TuneSocket(fd, SOL_TCP, TCP_KEEPIDLE, 60); */
-    /*   TuneSocket(fd, SOL_TCP, TCP_KEEPINTVL, 60); */
-    /*   TuneSocket(fd, SOL_TCP, TCP_FASTOPEN_CONNECT, 1); */
-    /*   if (!TuneSocket(fd, SOL_TCP, TCP_QUICKACK, 1)) { */
-    /*     TuneSocket(fd, SOL_TCP, TCP_NODELAY, 1); */
-    /*   } */
-    /* } */
-  }
-  return fd;
-}
-
 static int TlsSend(void *c, const unsigned char *p, size_t n) {
   int rc;
   if ((rc = write(*(int *)c, p, n)) == -1) {
@@ -174,21 +145,6 @@ static int TlsRecv(void *c, unsigned char *p, size_t n, uint32_t o) {
   return r;
 }
 
-static char *TlsError(int r) {
-  static char b[128];
-  mbedtls_strerror(r, b, sizeof(b));
-  return b;
-}
-
-static wontreturn void TlsDie(const char *s, int r) {
-  if (IsTiny()) {
-    fprintf(stderr, "error: %s (-0x%04x %s)\n", s, -r, TlsError(r));
-  } else {
-    fprintf(stderr, "error: %s (grep -0x%04x)\n", s, -r);
-  }
-  exit(1);
-}
-
 static wontreturn void PrintUsage(FILE *f, int rc) {
   fprintf(f, "usage: %s [-ksvV] URL\n", program_invocation_name);
   exit(rc);
@@ -219,8 +175,8 @@ int fetch(void) {
    */
   InitHttpMessage(&msg, kHttpResponse);
   ip = ntohl(((struct sockaddr_in *)addr->ai_addr)->sin_addr.s_addr);
-  CHECK_NE(-1, (sock = Socket(addr->ai_family, addr->ai_socktype,
-                              addr->ai_protocol)));
+  CHECK_NE(-1, (sock = GoodSocket(addr->ai_family, addr->ai_socktype,
+                                  addr->ai_protocol, false, 0)));
   if (connect(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
     goto TransportError;
   }