SYNOPSIS

  redbean.com [-hvduzmbagf] [-p PORT] [-- SCRIPTARGS...]

DESCRIPTION

  redbean - single-file distributable web server

OVERVIEW

  redbean makes it possible to share web applications that run offline
  as a single-file Actually Portable Executable PKZIP archive which
  contains your assets. All you need to do is download the redbean.com
  program below, change the filename to .zip, add your content in a zip
  editing tool, and then change the extension back to .com.

  redbean can serve 1 million+ gzip encoded responses per second on a
  cheap personal computer. That performance is thanks to zip and gzip
  using the same compression format, which enables kernelspace copies.
  Another reason redbean goes fast is that it's a tiny static binary,
  which makes fork memory paging nearly free.

  redbean is also easy to modify to suit your own needs. The program
  itself is written as a single .c file. It embeds the Lua programming
  language and SQLite which let you write dynamic pages.

FLAGS

  -h        help
  -d        daemonize
  -u        uniprocess
  -z        print port
  -m        log messages
  -b        log message bodies
  -a        log resource usage
  -g        log handler latency
  -j        enable ssl client verify
  -k        disable ssl fetch verify
  -B        use stronger cryptography
  -f        log worker function calls
  -s        increase silence                  [repeatable]
  -v        increase verbosity                [repeatable]
  -V        increase ssl verbosity            [repeatable]
  -H K:V    sets http header globally         [repeatable]
  -D DIR    overlay assets in local directory [repeatable]
  -r /X=/Y  redirect X to Y                   [repeatable]
  -R /X=/Y  rewrites X to Y                   [repeatable]
  -K PATH   tls private key path              [repeatable]
  -C PATH   tls certificate(s) path           [repeatable]
  -M INT    tunes max message payload size    [def. 65536]
  -t INT    timeout ms or keepalive sec if <0 [def. 60000]
  -p PORT   listen port                       [def. 8080; repeatable]
  -l ADDR   listen addr                       [def. 0.0.0.0; repeatable]
  -c SEC    configures static cache-control
  -L PATH   log file location
  -P PATH   pid file location
  -U INT    daemon set user id
  -G INT    daemon set group id

FEATURES

  - Lua v5.4
  - SQLite 3.35.5
  - TLS v1.2 / v1.1 / v1.0
  - HTTP v1.1 / v1.0 / v0.9
  - Chromium-Zlib Compression
  - Statusz Monitoring Statistics
  - Self-Modifying PKZIP Object Store
  - Linux + Windows + Mac + FreeBSD + OpenBSD + NetBSD

USAGE

  This executable is also a ZIP file that contains static assets.
  You can run redbean interactively in your terminal as follows:

    ./redbean.com -vvvmbag        # starts server verbosely
    open http://127.0.0.1:8080/   # shows zip listing page
    CTRL-C                        # 1x: graceful shutdown
    CTRL-C                        # 2x: forceful shutdown

  You can override the default listing page by adding:

    zip redbean.com index.lua     # lua server pages take priority
    zip redbean.com index.html    # default page for directory

  The listing page only applies to the root directory. However the
  default index page applies to subdirectories too. In order for it
  to work, there needs to be an empty directory entry in the zip.
  That should already be the default practice of your zip editor.

    wget                     \
      --mirror               \
      --convert-links        \
      --adjust-extension     \
      --page-requisites      \
      --no-parent            \
      --no-if-modified-since \
      http://a.example/index.html
    zip -r redbean.com a.example/  # default page for directory

  redbean normalizes the trailing slash for you automatically:

    $ printf 'GET /a.example HTTP/1.0\n\n' | nc 127.0.0.1 8080
    HTTP/1.0 307 Temporary Redirect
    Location: /a.example/

  Virtual hosting is accomplished this way too. The Host is simply
  prepended to the path, and if it doesn't exist, it gets removed.

    $ printf 'GET / HTTP/1.1\nHost:a.example\n\n' | nc 127.0.0.1 8080
    HTTP/1.1 200 OK
    Link: <http://127.0.0.1/a.example/index.html>; rel="canonical"

  If you mirror a lot of websites within your redbean then you can
  actually tell your browser that redbean is your proxy server, in
  which redbean will act as your private version of the Internet.

    $ printf 'GET http://a.example HTTP/1.0\n\n' | nc 127.0.0.1 8080
    HTTP/1.0 200 OK
    Link: <http://127.0.0.1/a.example/index.html>; rel="canonical"

  If you use a reverse proxy, then redbean recognizes the following
  provided that the proxy forwards requests over the local network:

    X-Forwarded-For: 203.0.113.42:31337
    X-Forwarded-Host: foo.example:80

  There's a text/plain statistics page called /statusz that makes
  it easy to track and monitor the health of your redbean:

    printf 'GET /statusz\n\n' | nc 127.0.0.1 8080

  redbean will display an error page using the /redbean.png logo
  by default, embedded as a bas64 data uri. You can override the
  custom page for various errors by adding files to the zip root.

    zip redbean.com 404.html      # custom not found page

  Audio video content should not be compressed in your ZIP files.
  Uncompressed assets enable browsers to send Range HTTP request.
  On the other hand compressed assets are best for gzip encoding.

    zip redbean.com index.html    # adds file
    zip -0 redbean.com video.mp4  # adds without compression

  You can have redbean run as a daemon by doing the following:

    sudo ./redbean.com -vvdp80 -p443 -L redbean.log -P redbean.pid
    kill -TERM $(cat redbean.pid) # 1x: graceful shutdown
    kill -TERM $(cat redbean.pid) # 2x: forceful shutdown

  redbean currently has a 32kb limit on request messages and 64kb
  including the payload. redbean will grow to whatever the system
  limits allow. Should fork() or accept() fail redbean will react
  by going into "meltdown mode" which closes lingering workers.
  You can trigger this at any time using:

    kill -USR2 $(cat redbean.pid)

  Another failure condition is running out of disk space in which
  case redbean reacts by truncating the log file. Lastly, redbean
  does the best job possible reporting on resource usage when the
  logger is in debug mode noting that NetBSD is the best at this.

  Your redbean is an actually portable executable, that's able to
  run on six different operating systems. To do that, it needs to
  overwrite its own MZ header at startup, with ELF or Mach-O, and
  then puts the original back once the program loads. If you want
  your redbean to follow the platform-local executable convention
  then delete the /.ape file from zip.

  redbean contains software licensed ISC, MIT, BSD-2, BSD-3, zlib
  which makes it a permissively licensed gift to anyone who might
  find it useful. The transitive closure of legalese can be found
  inside the binary. redbean also respects your privacy and won't
  phone home because your computer is its home.

SECURITY

  redbean uses a protocol polyglot for serving HTTP and HTTPS on
  the same port numbers. For example, both of these are valid:

    http://127.0.0.1:8080/
    https://127.0.0.1:8080/

  The easiest way to use a self-signed certificate is to provide
  redbean with a key-signing key:

    openssl req -x509 -newkey rsa:2048 \
      -keyout .ca.key -out .ca.crt -days 6570 -nodes \
      -subj '/C=US/ST=CA/O=Jane Doe/CN=My Root CA 1' \
      -addext 'keyUsage = critical,cRLSign,keyCertSign'
    sudo ./redbean.com -C ca.crt -K .ca.key -p 80 -p 443

  Let's say you're migrating away from NGINX and you use Let's Encrypt.
  In that case you'll likely want something like the following:

     certbot certonly --nginx --key-type ecdsa \
       --cert-name redbean-ecdsa -d redbean.dev -d www.redbean.dev
     certbot certonly --nginx --key-type rsa \
       --cert-name redbean-rsa -d redbean.dev -d www.redbean.dev

  You can then program /var/www/html/.init.lua as such:

     ProgramPrivateKey(Slurp('/etc/letsencrypt/live/redbean-ecdsa/privkey.pem'))
     ProgramCertificate(Slurp('/etc/letsencrypt/live/redbean-ecdsa/fullchain.pem'))
     ProgramPrivateKey(Slurp('/etc/letsencrypt/live/redbean-rsa/privkey.pem'))
     ProgramCertificate(Slurp('/etc/letsencrypt/live/redbean-rsa/fullchain.pem'))
     if IsDaemon() then
        ProgramUid(33)  # see `vipw` to get appropriate number
        ProgramGid(33)  # see `vigr` to get appropriate number
        ProgramPort(80)
        ProgramPort(443)
        ProgramLogPath('/var/log/redbean.log')
        ProgramPidPath('/var/run/redbean.pid')
     end
     function OnHttpRequest()
        path = GetPath()
        if path == '/favicon.ico' or
           path == '/site.webmanifest' or
           path == '/favicon-16x16.png' or
           path == '/favicon-32x32.png' or
           path == '/apple-touch-icon' then
           SetLogLevel(kLogWarn)
        end
        Route()
        SetHeader('Content-Language', 'en-US')
     end

  You'd then run redbean as follows:

    redbean.com -dD /var/www/html

  You can load as many public and private keys as you want. They can be
  specified as pem, der, concatenated ascii, bundles, or chains. If you
  don't specify specific chains then redbean will automatically infer it
  based on SUBJECT → ISSUER relationships. Your redbean won't serve the
  self-signed root certificate at the end of the chain where self-signed
  is defined as SUBJECT == ISSUER. Otherwise you can control when chains
  terminate by setting the max length constraint to zero.

  Your redbean supports SSL virtual hosting. 99.76% of TLS clients send
  a Server Name Indicator (SNI), which is matched against DNS or IPs in
  Subject Alternative Names (SAN) or the Common Name (CN) of subject if
  SAN isn't used. This means you don't need to reveal your whole domain
  portfolio to each client just to have ssl. You can just use different
  certificates for each domain if you choose to do so. If redbean can't
  find an appropriate match, then the first certificate will be chosen.

  Your redbean has been secured with algorithms so strong that, until a
  few decades ago, it was illegal to share them with with those outside
  the United States. By default your redbean offers roughly 128 bits of
  security with modern clients but will fall back to at minimum 112 bit
  security depending on the preferences of legacy and iot clients. Both
  are secure based on public knowledge until 2030 according to NIST. If
  you'd rather restrict yourself to just 150+ bits of security but with
  the tradeoff of dropping support for old Internet Explorer and making
  embedded clients less happy, then pass the -B flag, which'll restrict
  redbean to a very short list of protocols, algorithms, and parameters
  that the NSA, NIST, and IANA all agree upon.

  SSL verbosity is controlled as follows for troubleshooting:

    -V       log ssl errors
    -VV      log ssl state changes too
    -VVV     log ssl informational messages too
    -VVVV    log ssl verbose details too

  That's in addition to existing flags like -vvvm.

LUA SERVER PAGES

   Any files with the extension .lua will be dynamically served by redbean.
   Here's the simplest possible example:

     Write('<b>Hello World</b>')

   The Lua Server Page above should be able to perform at 700,000 responses
   per second on a Core i9, without any sort of caching. If you want a Lua
   handler that can do 1,000,000 responses per second, then try adding the
   following global handler to your /.init.lua file:

     function OnHttpRequest()
        Write('<b>Hello World</b>')
     end

   Here's an example of a more typical workflow for Lua Server Pages using
   the redbean API:

     SetStatus(200)
     SetHeader('Content-Type', 'text/plain; charset=utf-8')
     Write('<p>Hello ')
     Write(EscapeHtml(GetParam('name')))

   We didn't need the first two lines in the previous example, because
   they're implied by redbean automatically if you don't set them. Responses
   are also buffered until the script finishes executing. That enables
   redbean to make HTTP as easy as possible. In the future, API capabilities
   will be expanded to make possible things like websockets.

   redbean embeds the Lua standard library. You can use packages such as io
   to persist and share state across requests and connections, as well as the
   StoreAsset function, and the lsqlite3 module.

   Your Lua interpreter begins its life in the main process at startup in the
   .init.lua, which is likely where you'll want to perform all your expensive
   one-time operations like importing modules. Then, as requests roll in,
   isolated processes are cloned from the blueprint you created.

SPECIAL PATHS

   /
           redbean will generate a zip central directory listing for this
           page, and this page only, but only if there isn't an /index.lua or
           /index.html file defined.

   /.init.lua
           This script is run once in the main process at startup. This lets
           you modify the state of the Lua interpreter before connection
           processes are forked off. For example, it's a good idea to do
           expensive one-time computations here. You can also use this file
           to call the ProgramFOO() functions below. The init module load
           happens after redbean's arguments and zip assets have been parsed,
           but before calling functions like socket() and fork(). Note that
           this path is a hidden file so that it can't be unintentionally run
           by the network client.

   /.reload.lua
           This script is run from the main process when SIGHUP is received.
           This only applies to redbean when running in daemon mode. Any
           changes that are made to the Lua interpreter state will be
           inherited by future forked connection processes. Note that this
           path is a hidden file so that it can't be unintentionally run by
           the network client.

   /.lua/...
           Your Lua modules go in this directory. The way it works is redbean
           sets Lua's package.path to /zip/.lua/?.lua;/zip/.lua/?/init.lua by
           default. Cosmopolitan Libc lets system calls like open read from
           the ZIP structure, if the filename is prefixed with zip:. So this
           works like magic.

   /redbean.png
           If it exists, it'll be used as the / listing page icon, embedded
           as a base64 URI.

   /usr/share/ssl/root
           This directory contains your root certificate authorities. It is
           needed so the Fetch() HTTPS client API can verify that a remote
           certificate was signed by a third party. You can add your own
           certificate files to this directory within the ZIP executable.
           If you enable HTTPS client verification then redbean will check
           that HTTPS clients (a) have a certificate and (b) it was signed.

GLOBALS

   argv: array[str]
           Array of command line arguments, excluding those parsed by
           getopt() in the C code, which stops parsing at the first
           non-hyphenated arg. In some cases you can use the magic --
           argument to delimit C from Lua arguments.

HOOKS

   OnHttpRequest()
           If this function is defined in the global scope by your /.init.lua
           then redbean will call it at the ealiest possible moment to
           hand over control for all messages (with the exception of OPTIONS
           *). See functions like Route which asks redbean to do its default
           thing from the handler.

   OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
           If this function is defined it'll be called from the main process
           each time redbean accepts a new client connection. If it returns
           true then redbean will close the connection without calling fork.

   OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
           If this function is defined it'll be called from the main process
           each time redbean forks a connection handler worker process. The
           ip/port of the remote client is provided, along with the ip/port
           of the listening interface that accepted the connection. This may
           be used to create a server activity dashboard, in which case the
           data provider handler should set SetHeader('Connection','Close').
           This won't be called in uniprocess mode.

   OnProcessDestroy(pid:int)
           If this function is defined it'll be called from the main process
           each time redbean reaps a child connection process using wait4().
           This won't be called in uniprocess mode.

   OnServerStart()
           If this function is defined it'll be called from the main process
           right before the main event loop starts.

   OnServerStop()
           If this function is defined it'll be called from the main process
           after all the connection processes have been reaped and exit() is
           ready to be called.

   OnWorkerStart()
           If this function is defined it'll be called from the child worker
           process after it's been forked and before messages are handled.
           This won't be called in uniprocess mode.

   OnWorkerStop()
           If this function is defined it'll be called from the child worker
           process once _exit() is ready to be called. This won't be called
           in uniprocess mode.

FUNCTIONS

   Write(data:str)
           Appends data to HTTP response payload buffer. This is buffered
           independently of headers.

   SetStatus(code:int[,reason:str])
           Starts an HTTP response, specifying the parameters on its first
           line. reason is optional since redbean can fill in the appropriate
           text for well-known magic numbers, e.g. 200, 404, etc. This method
           will reset the response and is therefore mutually exclusive with
           ServeAsset and other Serve* functions. If this function isn't
           called, then the default behavior is to send 200 OK.

   SetHeader(name:str,value:str)
           Appends HTTP header to response header buffer. name is
           case-insensitive and restricted to non-space ASCII. value is a
           UTF-8 string that must be encodable as ISO-8859-1. Leading and
           trailing whitespace is trimmed automatically. Overlong characters
           are canonicalized. C0 and C1 control codes are forbidden, with the
           exception of tab. This function automatically calls SetStatus(200,
           "OK") if a status has not yet been set. As SetStatus and Serve*
           functions reset the response, SetHeader needs to be called after
           SetStatus and Serve* functions are called. The header buffer is
           independent of the payload buffer. Neither is written to the wire
           until the Lua Server Page has finished executing. This function
           disallows the setting of certain headers such as Content-Range and
           Date, which are abstracted by the transport layer. In such cases,
           consider calling ServeAsset.

   SetCookie(name:str,value:str[,options:table])
           Appends Set-Cookie HTTP header to the response header buffer.
           Several Set-Cookie headers can be added to the same response.
           __Host- and __Secure- prefixes are supported and may set or
           overwrite some of the options (for example, specifying __Host-
           prefix sets the Secure option to true, sets the path to "/", and
           removes the Domain option). The following options can be used (their
           lowercase equivalents are supported as well):
             - Expires: sets the maximum lifetime of the cookie as an HTTP-date
               timestamp. Can be specified as a Date in the RFC1123 (string)
               format or as a UNIX timestamp (number of seconds).
             - MaxAge: sets number of seconds until the cookie expires. A zero
               or negative number will expire the cookie immediately. If both
               Expires and MaxAge are set, MaxAge has precedence.
             - Domain: sets the host to which the cookie will be sent.
             - Path: sets the path that must be present in the request URL, or
               the client will not send the Cookie header.
             - Secure: (bool) requests the cookie to be only send to the
               server when a request is made with the https: scheme.
             - HttpOnly: (bool) forbids JavaScript from accessing the cookie.
             - SameSite: (Strict, Lax, or None) controls whether a cookie is
               sent with cross-origin requests, providing some protection
               against cross-site request forgery attacks.

   GetParam(name:str) → value:str
           Returns first value associated with name. name is handled in a
           case-sensitive manner. This function checks Request-URL parameters
           first. Then it checks application/x-www-form-urlencoded from the
           message body, if it exists, which is common for HTML forms sending
           POST requests. If a parameter is supplied matching name that has
           no value, e.g. foo in ?foo&bar=value, then the returned value will
           be nil, whereas for ?foo=&bar=value it would be "". To
           differentiate between no-equal and absent, use the HasParam
           function. The returned value is decoded from ISO-8859-1 (only in
           the case of Request-URL) and we assume that percent-encoded
           characters were supplied by the client as UTF-8 sequences, which
           are returned exactly as the client supplied them, and may
           therefore may contain overlong sequences, control codes, NUL
           characters, and even numbers which have been banned by the IETF.
           It is the responsibility of the caller to impose further
           restrictions on validity, if they're desired.

   EscapeHtml(str) → str
           Escapes HTML entities: The set of entities is &><"' which become
           &amp;&gt;&lt;&quot;&#39;. This function is charset agnostic and
           will not canonicalize overlong encodings. It is assumed that a
           UTF-8 string will be supplied. See escapehtml.c.

   LaunchBrowser([path:str])
           Launches web browser on local machine with URL to this redbean
           server. This function may be called from your /.init.lua.

   CategorizeIp(ip:uint32) → str
           Returns a string describing an IP address. This is currently Class
           A granular. It can tell you if traffic originated from private
           networks, ARIN, APNIC, DOD, etc.

   DecodeBase64(ascii:str) → binary:str
           Turns ASCII into binary, in a permissive way that ignores
           characters outside the base64 alphabet, such as whitespace. See
            decodebase64.c.

   DecodeLatin1(iso-8859-1:str) → utf-8:str
           Turns ISO-8859-1 string into UTF-8.

   EncodeBase64(binary:str) → ascii:str
           Turns binary into ASCII. This can be used to create HTML data:
           URIs that do things like embed a PNG file in a web page. See
           encodebase64.c.

   EncodeJson(value[,options:table]) → json:str
           Turns passed Lua value into a JSON string. Tables with non-zero
           length (as reported by `#`) are encoded as arrays with non-array
           elements ignored. Empty tables are encoded as empty arrays. All
           other tables are encoded as objects with numerical keys
           converted to strings (so `{[3]=1}` is encoded as `{"3":1}`).
           The following options can be used:
             - useoutput: (bool=false) encodes the result directly to the
               output buffer and returns `nil` value. This option is
               ignored if used outside of request handling code.
             - numformat: (string="%.14g") sets numeric format to be used.
             - maxdepth: (number=64) sets the max number of nested tables.

   EncodeLua(value[,options:table]) → json:str
           Turns passed Lua value into a Lua string. The following options
           can be used:
             - useoutput: (bool=false) encodes the result directly to the
               output buffer and returns `nil` value. This option is
               ignored if used outside of request handling code.
             - numformat: (string="%.14g") sets numeric format to be used.
             - maxdepth: (number=64) sets the max number of nested tables.

   EncodeLatin1(utf-8:str[,flags:int]) → iso-8859-1:str
           Turns UTF-8 into ISO-8859-1 string.

   EscapeFragment(str) → str
           Escapes URL #fragment. The allowed characters are
           -/?.~_@:!$&'()*+,;=0-9A-Za-z and everything else gets %XX encoded.
           Please note that '& can still break HTML and that '() can still
           break CSS URLs. This function is charset agnostic and will not
           canonicalize overlong encodings. It is assumed that a UTF-8 string
           will be supplied. See kescapefragment.c.

   EscapeHost(str) → str
           Escapes URL host. See kescapeauthority.c

   EscapeLiteral(str) → str
           Escapes JavaScript or JSON string literal content. The caller is
           responsible for adding the surrounding quotation marks. This
           implementation \uxxxx sequences for all non-ASCII sequences. HTML
           entities are also encoded, so the output doesn't need EscapeHtml.
           This function assumes UTF-8 input. Overlong encodings are
           canonicalized. Invalid input sequences are assumed to be
           ISO-8859-1. The output is UTF-16 since that's what JavaScript
           uses. For example, some individual codepoints such as emoji
           characters will encode as multiple \uxxxx sequences. Ints that are
           impossible to encode as UTF-16 are substituted with the \xFFFD
           replacement character. See escapejsstringliteral.c.

   EscapeParam(str) → str
           Escapes URL parameter name or value. The allowed characters are
           -.*_0-9A-Za-z and everything else gets %XX encoded. This function
           is charset agnostic and will not canonicalize overlong encodings.
           It is assumed that a UTF-8 string will be supplied. See
           kescapeparam.c.

   EscapePass(str) → str
           Escapes URL password. See kescapeauthority.c.

   EscapePath(str) → str
           Escapes URL path. This is the same as EscapeSegment except slash
           is allowed. The allowed characters are -.~_@:!$&'()*+,;=0-9A-Za-z/
           and everything else gets %XX encoded. Please note that '& can
           still break HTML, so the output may need EscapeHtml too. Also note
           that '() can still break CSS URLs. This function is charset
           agnostic and will not canonicalize overlong encodings. It is
           assumed that a UTF-8 string will be supplied. See kescapepath.c.

   EscapeSegment(str) → str
           Escapes URL path segment. This is the same as EscapePath except
           slash isn't allowed. The allowed characters are
           -.~_@:!$&'()*+,;=0-9A-Za-z and everything else gets %XX encoded.
           Please note that '& can still break HTML, so the output may need
           EscapeHtml too. Also note that '() can still break CSS URLs. This
           function is charset agnostic and will not canonicalize overlong
           encodings. It is assumed that a UTF-8 string will be supplied. See
           kescapesegment.c.

   EscapeUser(str) → str
           Escapes URL username. See kescapeauthority.c.

   Fetch(url:str[,body:str|{method=value:str,body=value:str,...}])
       → status:int,{header:str=value:str,...},body:str
           Sends an HTTP/HTTPS request to the specified URL. If only the URL is
           provided, then a GET request is sent. If both URL and body parameters
           are specified, then a POST request is sent. If any other method needs
           to be specified (for example, PUT or DELETE), then passing a table as
           the second value allows setting method and body values as well other
           options:
             - method (default = "GET"): sets the method to be used for the
               request. The specified method is converted to uppercase.
             - body (default = ""): sets the body value to be sent.
             - followredirect (default = true): forces temporary and permanent
               redirects to be followed. This behavior can be disabled by
               passing `false`.
             - maxredirects (default = 5): sets the number of allowed redirects
               to minimize looping due to misconfigured servers. When the number
               is exceeded, the result of the last redirect is returned.
           When the redirect is being followed, the same method and body values
           are being sent in all cases except when 303 status is returned. In
           that case the method is set to GET and the body is removed before the
           redirect is followed. Note that if these (method/body) values are
           provided as table fields, they will be modified in place.

   FormatHttpDateTime(seconds:int) → rfc1123:str
           Converts UNIX timestamp to an RFC1123 string that looks like this:
           Mon, 29 Mar 2021 15:37:13 GMT. See formathttpdatetime.c.

   FormatIp(uint32) → str
           Turns integer like 0x01020304 into a string like 1.2.3.4. See also
           ParseIp for the inverse operation.

   GetAssetComment(path:str) → str
           Returns comment text associated with asset in the ZIP central
           directory. Also available as GetComment (deprecated).

   GetAssetMode(path:str) → int
           Returns UNIX-style octal mode for ZIP asset (or local file if the
           -D flag is used)

   GetAssetSize(path:str) → int
           Returns byte size of uncompressed contents of ZIP asset (or local
           file if the -D flag is used)

   GetBody() → str
           Returns the request message body if present or an empty string.
           Also available as GetPayload (deprecated).

   GetCookie(name:str) → str
           Returns cookie value.

   GetCryptoHash(name:str,payload:str[,key:str]) → str
           Returns value of the specified cryptographic hash function. If the
           key is provided, then HMAC value of the same function is returned.
           The name can be one of the following strings: MD5, SHA1, SHA224,
           SHA256, SHA384, SHA512, and BLAKE2B256.

   GetRemoteAddr() → ip:uint32,port:uint16
           Returns client ip4 address and port, e.g. 0x01020304,31337 would
           represent 1.2.3.4:31337. This is the same as GetClientAddr except
           it will use the ip:port from the X-Forwarded-For header, only if
           IsPrivateIp or IsLoopbackIp return true.

   GetClientAddr() → ip:uint32,port:uint16
           Returns client socket ip4 address and port, e.g. 0x01020304,31337
           would represent 1.2.3.4:31337. Please consider using GetRemoteAddr
           instead, since the latter takes into consideration reverse proxy
           scenarios.

   GetServerAddr() → ip:uint32,port:uint16
           Returns address to which listening server socket is bound, e.g.
           0x01020304,8080 would represent 1.2.3.4:8080. If -p 0 was supplied
           as the listening port, then the port in this string will be
           whatever number the operating system assigned.

   GetDate() → seconds:int
           Returns date associated with request that's used to generate the
           Date header, which is now, give or take a second. The returned
           value is a UNIX timestamp.

   GetHeader(name:str) → value:str
           Returns HTTP header. name is case-insensitive. The header value is
           returned as a canonical UTF-8 string, with leading and trailing
           whitespace trimmed, which was decoded from ISO-8859-1, which is
           guaranteed to not have C0/C1 control sequences, with the exception
           of the tab character. Leading and trailing whitespace is
           automatically removed. In the event that the client suplies raw
           UTF-8 in the HTTP message headers, the original UTF-8 sequence can
           be losslessly restored by counter-intuitively recoding the
           returned string back to Latin1. If the requested header is defined
           by the RFCs as storing comma-separated values (e.g. Allow,
           Accept-Encoding) and the field name occurs multiple times in the
           message, then this function will fold those multiple entries into
           a single string.

   GetHeaders() → {name:str=value:str,...}
           Returns HTTP headers as dictionary mapping header key strings to
           their UTF-8 decoded values. The ordering of headers from the
           request message is not preserved. Whether or not the same key can
           repeat depends on whether or not it's a standard header, and if
           so, if it's one of the ones that the RFCs define as repeatable.
           See khttprepeatable.c. Those headers will not be folded. Standard
           headers which aren't on that list, will be overwritten with the
           last-occurring one during parsing. Extended headers are always
           passed through exactly as they're received. Please consider using
           GetHeader API if possible since it does a better job abstracting
           these issues.

   GetLogLevel() → int
           Returns logger verbosity level. Likely return values are kLogDebug
           > kLogVerbose > kLogInfo > kLogWarn > kLogError > kLogFatal.

   GetHost() → str
           Returns host associated with request. This will be the Host
           header, if it's supplied. Otherwise it's the bind address.

   GetHostOs() → str
           Returns string that describes the host OS.

   GetMonospaceWidth(str|char) → int
           Returns monospace display width of string. This is useful for
           fixed-width formatting. For example, CJK characters typically take
           up two cells. This function takes into consideration combining
           characters, which are discounted, as well as control codes and
           ANSI escape sequences.

   GetMethod() → str
           Returns HTTP method. Normally this will be GET, HEAD, or POST in
           which case redbean normalizes this value to its uppercase form.
           Anything else that the RFC classifies as a "token" string is
           accepted too, which might contain characters like &".

   GetParams() → {{name:str[,value:str]},...}
           Returns name=value parameters from Request-URL and
           application/x-www-form-urlencoded message body in the order they
           were received. This may contain duplicates. The inner array will
           have either one or two items, depending on whether or not the
           equals sign was used.

   GetPath() → str
           Returns the Request-URL path. This is guaranteed to begin with
           "/". It is further guaranteed that no "//" or "/." exists in the
           path. The returned value is returned as a UTF-8 string which was
           decoded from ISO-8859-1. We assume that percent-encoded characters
           were supplied by the client as UTF-8 sequences, which are returned
           exactly as the client supplied them, and may therefore may contain
           overlong sequences, control codes, NUL characters, and even
           numbers which have been banned by the IETF. redbean takes those
           things into consideration when performing path safety checks. It
           is the responsibility of the caller to impose further restrictions
           on validity, if they're desired.

   GetEffectivePath() → str
           Returns path as it was resolved by the routing algorithms, which
           might contain the virtual host prepended if used.

   GetScheme() → str
           Returns scheme from Request-URL, if any.

   GetStatus() → int
           Returns current status (as set by an earlier SetStatus call) or
           `nil` if the status hasn't been set yet.

   GetTime() → seconds:number
           Returns current time as a UNIX timestamp with 0.0001s precision.

   GetUrl() → str
           Returns the effective Request-URL as an ASCII string, where
           illegal characters or UTF-8 is guaranteed to be percent encoded,
           and has been normalized to include either the Host or
           X-Forwarded-Host headers, if they exist, and possibly a scheme too
           if redbean is being used as an HTTP proxy server. In the future
           this API might change to return an object instead.

   GetHttpVersion() → int
           Returns the request HTTP protocol version, which can be 9 for
           HTTP/0.9, 10 for HTTP/1.0, or 11 for HTTP/1.1.

   GetRandomBytes([length:int]) → str
           Returns string with the specified number of random bytes (1..256).
           If no length is specified, then a string of length 16 is returned.

   GetRedbeanVersion() → int
           Returns the Redbean version in the format 0xMMmmpp, with major (MM),
           minor (mm), and patch (pp) versions encoded. The version value 1.4
           would be represented as 0x010400.

   GetZipPaths([prefix:str]) → {path:str,...}
           Returns paths of all assets in the zip central directory, prefixed
           by a slash. If prefix parameter is provided, then only paths that
           start with the prefix (case sensitive) are returned.

   HasParam(name:str) → bool
           Returns true if parameter with name was supplied in either the
           Request-URL or an application/x-www-form-urlencoded message body.

   HidePath(prefix:str)
           Programs redbean / listing page to not display any paths beginning
           with prefix. This function should only be called from /.init.lua.

   IsPublicIp(uint32) → bool
           Returns true if IP address is not a private network (10.0.0.0/8,
           172.16.0.0/12, 192.168.0.0/16) and is not localhost (127.0.0.0/8).
           Note: we intentionally regard TEST-NET IPs as public.

   IsPrivateIp(uint32) → bool
           Returns true if IP address is part of a private network
           (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16).

   IsLoopbackClient() → bool
           Returns true if the client IP address (returned by GetRemoteAddr)
           is part of the localhost network (127.0.0.0/8).

   IsLoopbackIp(uint32) → bool
           Returns true if IP address is part of the localhost network
           (127.0.0.0/8).

   IsCompressed(path:str) → bool
           Returns true if ZIP artifact at path is stored on disk using
           DEFLATE compression.

   IndentLines(str[,int]) → str
           Adds spaces to beginnings of multiline string. If the int
           parameter is not supplied then 1 space will be added.

   LoadAsset(path:str) → str
           Returns contents of file as string. The asset may be sourced from
           either the zip (decompressed) or the local filesystem if the -D
           flag was used. If slurping large file into memory is a concern,
           then consider using ServeAsset which can serve directly off disk.

   StoreAsset(path:str,data:str,mode:int)
           Stores asset to executable's ZIP central directory. This currently
           happens in an append-only fashion and is still largely in the
           proof-of-concept stages. Currently only supported on Linux, XNU,
           and FreeBSD.

   Log(level:int,message:str)
           Emits message string to log, if level is less than or equal to
           GetLogLevel. If redbean is running in interactive mode, then this
           will log to the console. If redbean is running as a daemon or the
           -L LOGFILE flag is passed, then this will log to the file.
           Reasonable values for level are kLogDebug > kLogVerbose > kLogInfo
           > kLogWarn > kLogError > kLogFatal. The logger emits timestamps in
           the local timezone with microsecond precision. If log entries are
           emitted more frequently than once per second, then the log entry
           will display a delta timestamp, showing how much time has elapsed
           since the previous log entry. This behavior is useful for quickly
           measuring how long various portions of your code take to execute.

   ParseHttpDateTime(rfc1123:str) → seconds:int
           Converts RFC1123 string that looks like this: Mon, 29 Mar 2021
           15:37:13 GMT to a UNIX timestamp. See parsehttpdatetime.c.

   ParseUrl(str) → URL
           Parses URL, returning object having the following fields: scheme,
           user, pass, host, port, path, params, fragment. This parser is
           charset agnostic. Percent encoded bytes are decoded for all
           fields. Returned values might contain things like NUL characters,
           spaces, control codes, and non-canonical encodings. Absent can be
           discerned from empty by checking if the pointer is set. There's no
           failure condition for this routine. This is a permissive parser.
           This doesn't normalize path segments like `.` or `..` so use
           IsAcceptablePath() to check for those. No restrictions are imposed
           beyond that which is strictly necessary for parsing. All the data
           that is provided will be consumed to the one of the fields. Strict
           conformance is enforced on some fields more than others, like
           scheme, since it's the most non-deterministically defined field of
           them all. Please note this is a URL parser, not a URI parser.
           Which means we support everything everything the URI spec says we
           should do except for the things we won't do, like tokenizing path
           segments into an array and then nesting another array beneath each
           of those for storing semicolon parameters. So this parser won't
           make SIP easy. What it can do is parse HTTP URLs and most URIs
           like data:opaque, better in fact than most things which claim to
           be URI parsers.

   EncodeUrl(URL) → str
           This function is the inverse of ParseUrl. The output will always
           be correctly formatted. The exception is if illegal characters are
           supplied in the scheme field, since there's no way of escaping
           those. Opaque parts are escaped as though they were paths, since
           many URI parsers won't understand things like an unescaped
           question mark in path.

   ParseIp(str) → int
           Converts IPv4 address string to integer, e.g. "1.2.3.4" →
           0x01020304, or returns -1 for invalid inputs. See also FormatIp
           for the inverse operation.

   ProgramAddr(str)
           Configures the address on which to listen. Can be used multiple
           times to set more than one address.

   ProgramBrand(str)
           Changes HTTP Server header, as well as the <h1> title on the /
           listing page. The brand string needs to be a UTF-8 value that's
           encodable as ISO-8859-1. If the brand is changed to something
           other than redbean, then the promotional links will be removed
           from the listing page too. This function should only be called
           from /.init.lua.

   ProgramCache(seconds:int)
           Configures Cache-Control and Expires header generation for static
           asset serving. A negative value will disable the headers. Zero
           means don't cache. Greater than zero asks public proxies and
           browsers to cache for a given number of seconds. This should only
           be called from /.init.lua.

   ProgramCertificate(pem:str)
           Same as the -C flag if called from .init.lua, e.g.
           ProgramCertificate(LoadAsset("/.sign.crt")) for zip loading or
           ProgramCertificate(Slurp("/etc/letsencrypt.lol/fullchain.pem")) for
           local file system only.

   ProgramHeader(name:str,value:str)
           Appends HTTP header to the header buffer for all responses (whereas
           SetHeader only appends a header to the current response buffer).
           name is case-insensitive and restricted to non-space ASCII. value
           is a UTF-8 string that must be encodable as ISO-8859-1. Leading and
           trailing whitespace is trimmed automatically. Overlong characters
           are canonicalized. C0 and C1 control codes are forbidden, with the
           exception of tab. The header buffer is independent of the payload
           buffer. This function disallows the setting of certain headers such
           as Content-Range and Date, which are abstracted by the transport
           layer.

   ProgramPort(uint16)
           Hard-codes the port number on which to listen, which can be any
           number in the range 1..65535, or alternatively 0 to ask the
           operating system to choose a port, which may be revealed later on
           by GetServerAddr or the -z flag to stdout.

   ProgramPrivateKey(pem:str)
           Same as the -K flag if called from .init.lua, e.g.
           ProgramPrivateKey(LoadAsset("/.sign.key")) for zip loading or
           ProgramPrivateKey(Slurp("/etc/letsencrypt/fullchain.pem")) for
           local file system only.

   ProgramRedirect(code:int,src:str,location:str)
           Configures fallback routing for paths which would otherwise return
           404 Not Found. If code is 0 then the path is rewritten internally
           as an accelerated redirect. If code is 301, 302, 307, or 308 then
           a redirect response will be sent to the client. This should only
           be called from /.init.lua.

   ProgramSslTicketLifetime(seconds:int)
           Defaults to 86400 (24 hours). This may be set to ≤0 to disable
           SSL tickets. It's a good idea to use these since it increases
           handshake performance 10x and eliminates a network round trip.

   EvadeDragnetSurveillance(bool)
           If this option is programmed then redbean will not transmit a
           Server Name Indicator (SNI) when performing Fetch() requests.

   ProgramSslPresharedKey(key:str,identity:str)
           This function can be used to enable the PSK ciphersuites
           which simplify SSL and enhance its performance in controlled
           environments. `key` may contain 1..32 bytes of random binary
           data and identity is usually a short plaintext string. The
           first time this function is called, the preshared key will
           be added to both the client and the server SSL configs. If
           it's called multiple times, then the remaining keys will be
           added to the server, which is useful if you want to assign
           separate keys to each client, each of which needs a separate
           identity too. If this function is called multiple times with
           the same identity string, then the latter call will overwrite
           the prior. If a preshared key is supplied and no certificates
           or key-signing-keys are programmed, then redbean won't bother
           auto-generating any serving certificates and will instead use
           only PSK ciphersuites.

   ProgramSslCiphersuite(name:str)
           This function may be called multiple times to specify which
           ciphersuites should be used in the server and client. The
           default list, ordered by preference, is as follows:

               ECDHE-ECDSA-AES256-GCM-SHA384
               ECDHE-ECDSA-AES128-GCM-SHA256
               ECDHE-ECDSA-CHACHA20-POLY1305-SHA256
               ECDHE-PSK-AES256-GCM-SHA384
               ECDHE-PSK-AES128-GCM-SHA256
               ECDHE-PSK-CHACHA20-POLY1305-SHA256
               ECDHE-RSA-AES256-GCM-SHA384
               ECDHE-RSA-AES128-GCM-SHA256
               ECDHE-RSA-CHACHA20-POLY1305-SHA256
               DHE-RSA-AES256-GCM-SHA384
               DHE-RSA-AES128-GCM-SHA256
               DHE-RSA-CHACHA20-POLY1305-SHA256
               ECDHE-ECDSA-AES128-CBC-SHA256
               ECDHE-RSA-AES256-CBC-SHA384
               ECDHE-RSA-AES128-CBC-SHA256
               DHE-RSA-AES256-CBC-SHA256
               DHE-RSA-AES128-CBC-SHA256
               ECDHE-PSK-AES256-CBC-SHA384
               ECDHE-PSK-AES128-CBC-SHA256
               ECDHE-ECDSA-AES256-CBC-SHA
               ECDHE-ECDSA-AES128-CBC-SHA
               ECDHE-RSA-AES256-CBC-SHA
               ECDHE-RSA-AES128-CBC-SHA
               DHE-RSA-AES256-CBC-SHA
               DHE-RSA-AES128-CBC-SHA
               ECDHE-PSK-AES256-CBC-SHA
               ECDHE-PSK-AES128-CBC-SHA
               RSA-AES256-GCM-SHA384
               RSA-AES128-GCM-SHA256
               RSA-AES256-CBC-SHA256
               RSA-AES128-CBC-SHA256
               RSA-AES256-CBC-SHA
               RSA-AES128-CBC-SHA
               PSK-AES256-GCM-SHA384
               PSK-AES128-GCM-SHA256
               PSK-CHACHA20-POLY1305-SHA256
               PSK-AES256-CBC-SHA384
               PSK-AES128-CBC-SHA256
               PSK-AES256-CBC-SHA
               PSK-AES128-CBC-SHA
               ECDHE-RSA-3DES-EDE-CBC-SHA
               DHE-RSA-3DES-EDE-CBC-SHA
               ECDHE-PSK-3DES-EDE-CBC-SHA
               RSA-3DES-EDE-CBC-SHA
               PSK-3DES-EDE-CBC-SHA

           The names above are canonical to redbean and were simplified
           programmatically from the official IANA names. This function
           will accept the IANA names too. In most cases it will accept
           the OpenSSL and GnuTLS naming convention as well.

   IsDaemon() → bool
           Returns true if -d flag was passed to redbean.

   ProgramUid(int)
           Same as the -U flag if called from .init.lua for setuid()

   ProgramGid(int)
           Same as the -U flag if called from .init.lua for setgid()

   ProgramDirectory(str)
           Same as the -D flag if called from .init.lua for overlaying local
           file system directories. This may be called multiple times. The
           first directory programmed is preferred. These currently do not
           show up in the index page listing.

   ProgramLogMessages(bool)
           Same as the -m flag if called from .init.lua for logging message
           headers only.

   ProgramLogBodies(bool)
           Same as the -b flag if called from .init.lua for logging message
           bodies as part of POST / PUT / etc. requests.

   ProgramLogPath(str)
           Same as the -L flag if called from .init.lua for setting the log
           file path on the local file system. It's created if it doesn't
           exist. This is called before de-escalating the uesr / group id.
           The file is opened in append only mode. If the disk runs out of
           space then redbean will truncate the log file if has access to
           change the log file after daemonizing.

   ProgramPidPath(str)
           Same as the -P flag if called from .init.lua for setting the pid
           file path on the local file system. It's useful for reloading
           daemonized redbean using `kill -HUP $(cat /var/run/redbean.pid)`
           or terminating redbean with `kill $(cat /var/run/redbean.pid)`
           which will gracefully terminate all clients. Sending the TERM
           signal twice will cause a forceful shutdown, which might make
           someone with a slow internet connection who's downloading big
           files unhappy.

   Slurp(filename:str) → str
           Reads file data from local file system.

   Sleep(seconds:number)
           Sleeps the specified number of seconds (can be fractional). The
           smallest interval is a microsecond.

   Route([host:str,[path:str]])
           Instructs redbean to follow the normal HTTP serving path. This
           function is useful when writing an OnHttpRequest handler, since
           that overrides the serving path entirely. So if the handler
           decides it doesn't want to do anything, it can simply call this
           function, to hand over control back to the redbean core. By
           default, the host and path arguments are supplied from the
           resolved GetUrl value. This handler always resolves, since it will
           generate a 404 Not Found response if redbean couldn't find an
           appropriate endpoint.

   RouteHost([host:str,[path:str]]) → bool
           This is the same as Route, except it only implements the subset of
           request routing needed for serving virtual-hosted assets, where
           redbean tries to prefix the path with the hostname when looking up
           a file. This function returns true if the request was resolved. If
           it was resolved, then your OnHttpRequest request handler can still
           set additional headers.

   RoutePath([path:str]) → bool
           This is the same as Route, except it only implements the subset of
           request routing needed for serving assets. This function returns
           true if the request was resolved. If it was resolved, then your
           OnHttpRequest request handler can still set additional headers.

   ServeAsset(path:str)
           Instructs redbean to serve static asset at path. This function
           causes what would normally happen outside a dynamic handler to
           happen. The asset can be sourced from either the zip or local
           filesystem if -D is used. This function is mutually exclusive with
           SetStatus and other Serve* functions.

   ServeError(code:int[,reason:str])
           Instructs redbean to serve a boilerplate error page. This takes
           care of logging the error, setting the reason phrase, and adding a
           payload. This function is mutually exclusive with SetStatus and
           other Serve* functions.

   ServeRedirect(code:int,location:str)
           Instructs redbean to return the specified redirect code along with
           the Location header set. This function is mutually exclusive with
           SetStatus and other Serve* functions.

   SetLogLevel(level:int)
           Sets logger verbosity. Reasonable values for level are kLogDebug >
           kLogVerbose > kLogInfo > kLogWarn > kLogError > kLogFatal. This is
           reset at the end of the http request, so it can be used to disable
           access log and message logging.

   VisualizeControlCodes(str) → str
           Replaces C0 control codes with their UNICODE pictures
           representation. This function also canonicalizes overlong
           encodings. C1 control codes are replaced with a JavaScript-like
           escape sequence.

   Underlong(str) → str
           Canonicalizes overlong encodings.

   Crc32(initial:int,data:str) → int
           Computes 32-bit CRC-32 used by zip/zlib/gzip/etc.

   Crc32c(initial:int,data:str) → int
           Computes 32-bit Castagnoli Cyclic Redundancy Check.

   Md5(str) → str
           Computes MD5 checksum, returning 16 bytes of binary.

   Sha1(str) → str
           Computes SHA1 checksum, returning 20 bytes of binary.

   Sha224(str) → str
           Computes SHA224 checksum, returning 28 bytes of binary.

   Sha256(str) → str
           Computes SHA256 checksum, returning 32 bytes of binary.

   Sha384(str) → str
           Computes SHA384 checksum, returning 48 bytes of binary.

   Sha512(str) → str
           Computes SHA512 checksum, returning 64 bytes of binary.

   Bsf(x:int) → int
           Returns position of first bit set. Passing 0 will raise an error.
           Same as the Intel x86 instruction BSF.

   Bsr(x:int) → int
           Returns binary logarithm of 𝑥. Passing 0 will raise an error. Same
           as the Intel x86 instruction BSR.

   Popcnt(x:int) → int
           Returns number of bits set in integer.

LSQLITE3 MODULE

   Please refer to the LuaSQLite3 Documentation.

   For example, you could put the following in your /.init.lua file:

     sqlite3 = require "lsqlite3"
     db = sqlite3.open_memory()
     db:exec[[
       CREATE TABLE test (
         id INTEGER PRIMARY KEY,
         content TEXT
       );
       INSERT INTO test (content) VALUES ('Hello World');
       INSERT INTO test (content) VALUES ('Hello Lua');
       INSERT INTO test (content) VALUES ('Hello Sqlite3');
     ]]

   Then, your Lua server pages or OnHttpRequest handler may perform SQL
   queries by accessing the db global. The performance is good too, at about
   400k qps.

     for row in db:nrows("SELECT * FROM test") do
        Write(row.id.." "..row.content.."<br>")
     end

   redbean supports a subset of what's defined in the upstream LuaSQLite3
   project. Most of the unsupported APIs relate to pointers and database
   notification hooks.

   redbean also currently disables SQLite features which don't make sense for
   production serving, such as ALTER, VACUUM, ANALYZE, etc. For that reason
   we provide an APE build of the SQLite shell which you can use to
   administrate your redbean database. See the sqlite3.com download above.

RE MODULE

   This module exposes an API for POSIX regular expressions which enable you
   to validate input, search for substrings, extract pieces of strings, etc.
   Here's a usage example:

     # Example IPv4 Address Regular Expression (see also ParseIP)
     p = re.compile([[^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$]])
     m,a,b,c,d = p:search(𝑠)
     if m then
       print("ok", tonumber(a), tonumber(b), tonumber(c), tonumber(d))
     else
       print("not ok")
     end

   re.search(regex:str,text:str[,flags:int]) → [match[,group_1,...]]
           Shortcut for re.compile plus regex_t*:search.

   re.compile(regex:str[,flags:int]) → regex_t*
           Compiles regular expression, using the POSIX extended syntax. This
           has an O(2^𝑛) cost, so it's a good idea to do this from your
           /.init.lua file. Flags may contain re.BASIC, re.ICASE, re.NOSUB,
           and/or re.NEWLINE. See also regcomp() from libc.

   regex_t*:search(text:str[,flags:int]) → [match[,group_1,...]]
           Executes regular expression. This has an O(𝑛) cost. This returns
           nothing (nil) if the pattern doesn't match anything. Otherwise it
           pushes the matched substring and any parenthesis-captured values
           too. Flags may contain re.NOTBOL or re.NOTEOL to indicate whether
           or not text should be considered at the start and/or end of a
           line.

   re.BASIC
           Use this flag if you prefer the default POSIX regex syntax. We use
           extended regex notation by default. For example, an extended
           regular expression for matching an IP address might look like
           ([0-9]*)\.([0-9]*)\.([0-9]*)\.([0-9]*) whereas with basic syntax
           it would look like \([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).
           This flag may only be used with re.compile and re.search.

   re.ICASE
           Use this flag to make your pattern case ASCII case-insensitive.
           This means [a-z] will mean the same thing as [A-Za-z]. This flag
           may only be used with re.compile and re.search.

   re.NEWLINE
           Use this flag to change the handling of NEWLINE (\x0a) characters.
           When this flag is set, (1) a NEWLINE shall not be matched by a "."
           or any form of a non-matching list, (2) a "^" shall match the
           zero-length string immediately after a NEWLINE (regardless of
           re.NOTBOL), and (3) a "$" shall match the zero-length string
           immediately before a NEWLINE (regardless of re.NOTEOL).

   re.NOSUB
           Causes re.search to only report success and failure. This is
           reported via the API by returning empty string for success. This
           flag may only be used with re.compile and re.search.

   re.NOTBOL
           The first character of the string pointed to by string is not the
           beginning of the line. This flag may only be used with re.search
           and regex_t*:search.

   re.NOTEOL
           The last character of the string pointed to by string is not the
           end of the line. This flag may only be used with re.search and
           regex_t*:search.

CONSTANTS

   kLogDebug
           Integer for debug logging level. See Log.

   kLogVerbose
           Integer for verbose logging level, which is less than kLogDebug.

   kLogInfo
           Integer for info logging level, which is less than kLogVerbose.

   kLogWarn
           Integer for warn logging level, which is less than kLogVerbose.

   kLogError
           Integer for error logging level, which is less than kLogWarn.

   kLogFatal
           Integer for fatal logging level, which is less than kLogError.
           Logging anything at this level will result in a backtrace and
           process exit.

SEE ALSO

  https://justine.lol/redbean/index.html
  https://news.ycombinator.com/item?id=26271117