LazyGH is a Terminal User Interface (TUI) application for managing multiple GitHub accounts easily. It allows you to switch between different Git configurations and SSH keys seamlessly.
+
Demo
+
Check out the demo to see LazyGH in action:
+
+
Features
+
+
Manage multiple GitHub accounts
+
Switch between accounts with ease
+
Automatically update Git global configuration
+
Generate and manage SSH keys for each account
+
Copy SSH public keys to clipboard
+
+
Contributing
+
Contributions are welcome! Here's how you can contribute:
+
+
Fork the repository
+
Create your feature branch (git checkout -b feature/AmazingFeature)
+
Commit your changes (git commit -m 'Add some AmazingFeature')
+
Push to the branch (git push origin feature/AmazingFeature)
+
Open a Pull Request
+
+
Please make sure to update tests as appropriate and adhere to the existing coding style.
+
Issues
+
If you encounter any problems or have suggestions for improvements, please open an issue on the GitHub Issues page.
+
Roadmap
+
+
fix the cargo auto release version mangment with release workflow
+
adding lazygh to binstall
+
adding lazygh to nix-env
+
adding lazygh to nix flake
+
ability to maintain multiple gh config files and able to categorise them in workspace fashion but in simpler way
+
don't know other things to add, create an issue if you have any ideas
+
+
Security
+
LazyGH takes your security seriously. If you discover a security vulnerability within LazyGH, please send an e-mail to Karan Janthe via karanjanthe@gmail.com. All security vulnerabilities will be addressed.
+
+
+
+
+
+ window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date());gtag('config', 'G-TKS59X89PP');
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lazygh-installer.ps1.txt b/lazygh-installer.ps1.txt
new file mode 100644
index 0000000..421b61a
--- /dev/null
+++ b/lazygh-installer.ps1.txt
@@ -0,0 +1,465 @@
+# Licensed under the MIT license
+# , at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+<#
+.SYNOPSIS
+
+The installer for lazygh 0.5.0
+
+.DESCRIPTION
+
+This script detects what platform you're on and fetches an appropriate archive from
+https://github.com/kmj-007/lazygh/releases/download/v0.5.0
+then unpacks the binaries and installs them to
+
+ $env:CARGO_HOME/bin (or $HOME/.cargo/bin)
+
+It will then add that dir to PATH by editing your Environment.Path registry key
+
+.PARAMETER ArtifactDownloadUrl
+The URL of the directory where artifacts can be fetched from
+
+.PARAMETER NoModifyPath
+Don't add the install directory to PATH
+
+.PARAMETER Help
+Print help
+
+#>
+
+param (
+ [Parameter(HelpMessage = "The URL of the directory where artifacts can be fetched from")]
+ [string]$ArtifactDownloadUrl = 'https://github.com/kmj-007/lazygh/releases/download/v0.5.0',
+ [Parameter(HelpMessage = "Don't add the install directory to PATH")]
+ [switch]$NoModifyPath,
+ [Parameter(HelpMessage = "Print Help")]
+ [switch]$Help
+)
+
+$app_name = 'lazygh'
+$app_version = '0.5.0'
+
+$receipt = @"
+{"binaries":["CARGO_DIST_BINS"],"binary_aliases":{},"cdylibs":["CARGO_DIST_DYLIBS"],"cstaticlibs":["CARGO_DIST_STATICLIBS"],"install_prefix":"AXO_INSTALL_PREFIX","provider":{"source":"cargo-dist","version":"0.22.1"},"source":{"app_name":"lazygh","name":"lazygh","owner":"kmj-007","release_type":"github"},"version":"0.5.0"}
+"@
+$receipt_home = "${env:LOCALAPPDATA}\lazygh"
+
+function Install-Binary($install_args) {
+ if ($Help) {
+ Get-Help $PSCommandPath -Detailed
+ Exit
+ }
+
+ Initialize-Environment
+
+ # Platform info injected by cargo-dist
+ $platforms = @{
+ "aarch64-pc-windows-msvc" = @{
+ "artifact_name" = "lazygh-x86_64-pc-windows-msvc.tar.gz"
+ "bins" = @("lazygh.exe")
+ "libs" = @()
+ "staticlibs" = @()
+ "zip_ext" = ".tar.gz"
+ "aliases" = @{
+ }
+ "aliases_json" = '{}'
+ "updater" = @{
+ "artifact_name" = "lazygh-x86_64-pc-windows-msvc-update"
+ "bin" = "lazygh-x86_64-pc-windows-msvc-update"
+ }
+ }
+ "x86_64-pc-windows-msvc" = @{
+ "artifact_name" = "lazygh-x86_64-pc-windows-msvc.tar.gz"
+ "bins" = @("lazygh.exe")
+ "libs" = @()
+ "staticlibs" = @()
+ "zip_ext" = ".tar.gz"
+ "aliases" = @{
+ }
+ "aliases_json" = '{}'
+ "updater" = @{
+ "artifact_name" = "lazygh-x86_64-pc-windows-msvc-update"
+ "bin" = "lazygh-x86_64-pc-windows-msvc-update"
+ }
+ }
+ }
+
+ $fetched = Download "$ArtifactDownloadUrl" $platforms
+ # FIXME: add a flag that lets the user not do this step
+ try {
+ Invoke-Installer -artifacts $fetched -platforms $platforms "$install_args"
+ } catch {
+ throw @"
+We encountered an error trying to perform the installation;
+please review the error messages below.
+
+$_
+"@
+ }
+}
+
+function Get-TargetTriple() {
+ try {
+ # NOTE: this might return X64 on ARM64 Windows, which is OK since emulation is available.
+ # It works correctly starting in PowerShell Core 7.3 and Windows PowerShell in Win 11 22H2.
+ # Ideally this would just be
+ # [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture
+ # but that gets a type from the wrong assembly on Windows PowerShell (i.e. not Core)
+ $a = [System.Reflection.Assembly]::LoadWithPartialName("System.Runtime.InteropServices.RuntimeInformation")
+ $t = $a.GetType("System.Runtime.InteropServices.RuntimeInformation")
+ $p = $t.GetProperty("OSArchitecture")
+ # Possible OSArchitecture Values: https://learn.microsoft.com/dotnet/api/system.runtime.interopservices.architecture
+ # Rust supported platforms: https://doc.rust-lang.org/stable/rustc/platform-support.html
+ switch ($p.GetValue($null).ToString())
+ {
+ "X86" { return "i686-pc-windows-msvc" }
+ "X64" { return "x86_64-pc-windows-msvc" }
+ "Arm" { return "thumbv7a-pc-windows-msvc" }
+ "Arm64" { return "aarch64-pc-windows-msvc" }
+ }
+ } catch {
+ # The above was added in .NET 4.7.1, so Windows PowerShell in versions of Windows
+ # prior to Windows 10 v1709 may not have this API.
+ Write-Verbose "Get-TargetTriple: Exception when trying to determine OS architecture."
+ Write-Verbose $_
+ }
+
+ # This is available in .NET 4.0. We already checked for PS 5, which requires .NET 4.5.
+ Write-Verbose("Get-TargetTriple: falling back to Is64BitOperatingSystem.")
+ if ([System.Environment]::Is64BitOperatingSystem) {
+ return "x86_64-pc-windows-msvc"
+ } else {
+ return "i686-pc-windows-msvc"
+ }
+}
+
+function Download($download_url, $platforms) {
+ $arch = Get-TargetTriple
+
+ if (-not $platforms.ContainsKey($arch)) {
+ $platforms_json = ConvertTo-Json $platforms
+ throw "ERROR: could not find binaries for this platform. Last platform tried: $arch platform info: $platforms_json"
+ }
+
+ # Lookup what we expect this platform to look like
+ $info = $platforms[$arch]
+ $zip_ext = $info["zip_ext"]
+ $bin_names = $info["bins"]
+ $lib_names = $info["libs"]
+ $staticlib_names = $info["staticlibs"]
+ $artifact_name = $info["artifact_name"]
+
+ # Make a new temp dir to unpack things to
+ $tmp = New-Temp-Dir
+ $dir_path = "$tmp\$app_name$zip_ext"
+
+ # Download and unpack!
+ $url = "$download_url/$artifact_name"
+ Write-Information "Downloading $app_name $app_version ($arch)"
+ Write-Verbose " from $url"
+ Write-Verbose " to $dir_path"
+ $wc = New-Object Net.Webclient
+ $wc.downloadFile($url, $dir_path)
+
+ Write-Verbose "Unpacking to $tmp"
+
+ # Select the tool to unpack the files with.
+ #
+ # As of windows 10(?), powershell comes with tar preinstalled, but in practice
+ # it only seems to support .tar.gz, and not xz/zstd. Still, we should try to
+ # forward all tars to it in case the user has a machine that can handle it!
+ switch -Wildcard ($zip_ext) {
+ ".zip" {
+ Expand-Archive -Path $dir_path -DestinationPath "$tmp";
+ Break
+ }
+ ".tar.*" {
+ tar xf $dir_path --strip-components 1 -C "$tmp";
+ Break
+ }
+ Default {
+ throw "ERROR: unknown archive format $zip_ext"
+ }
+ }
+
+ # Let the next step know what to copy
+ $bin_paths = @()
+ foreach ($bin_name in $bin_names) {
+ Write-Verbose " Unpacked $bin_name"
+ $bin_paths += "$tmp\$bin_name"
+ }
+ $lib_paths = @()
+ foreach ($lib_name in $lib_names) {
+ Write-Verbose " Unpacked $lib_name"
+ $lib_paths += "$tmp\$lib_name"
+ }
+ $staticlib_paths = @()
+ foreach ($lib_name in $staticlib_names) {
+ Write-Verbose " Unpacked $lib_name"
+ $staticlib_paths += "$tmp\$lib_name"
+ }
+
+ if ($null -ne $info["updater"]) {
+ $updater_id = $info["updater"]["artifact_name"]
+ $updater_url = "$download_url/$updater_id"
+ $out_name = "$tmp\lazygh-update.exe"
+
+ $wc.downloadFile($updater_url, $out_name)
+ $bin_paths += $out_name
+ }
+
+ return @{
+ "bin_paths" = $bin_paths
+ "lib_paths" = $lib_paths
+ "staticlib_paths" = $staticlib_paths
+ }
+}
+
+function Invoke-Installer($artifacts, $platforms) {
+ # Replaces the placeholder binary entry with the actual list of binaries
+ $arch = Get-TargetTriple
+
+ if (-not $platforms.ContainsKey($arch)) {
+ $platforms_json = ConvertTo-Json $platforms
+ throw "ERROR: could not find binaries for this platform. Last platform tried: $arch platform info: $platforms_json"
+ }
+
+ $info = $platforms[$arch]
+
+ # Forces the install to occur at this path, not the default
+ $force_install_dir = $null
+ # Check the newer app-specific variable before falling back
+ # to the older generic one
+ if (($env:LAZYGH_INSTALL_DIR)) {
+ $force_install_dir = $env:LAZYGH_INSTALL_DIR
+ } elseif (($env:CARGO_DIST_FORCE_INSTALL_DIR)) {
+ $force_install_dir = $env:CARGO_DIST_FORCE_INSTALL_DIR
+ }
+
+ # The actual path we're going to install to
+ $dest_dir = $null
+ $dest_dir_lib = $null
+ # The install prefix we write to the receipt.
+ # For organized install methods like CargoHome, which have
+ # subdirectories, this is the root without `/bin`. For other
+ # methods, this is the same as `_install_dir`.
+ $receipt_dest_dir = $null
+ # Before actually consulting the configured install strategy, see
+ # if we're overriding it.
+ if (($force_install_dir)) {
+
+ $dest_dir = Join-Path $force_install_dir "bin"
+ $dest_dir_lib = $dest_dir
+ $receipt_dest_dir = $force_install_dir
+ }
+ if (-Not $dest_dir) {
+ # first try $env:CARGO_HOME, then fallback to $HOME
+ # (for whatever reason $HOME is not a normal env var and doesn't need the $env: prefix)
+ $root = if (($base_dir = $env:CARGO_HOME)) {
+ $base_dir
+ } elseif (($base_dir = $HOME)) {
+ Join-Path $base_dir ".cargo"
+ } else {
+ throw "ERROR: could not find your HOME dir or CARGO_HOME to install binaries to"
+ }
+
+ $dest_dir = Join-Path $root "bin"
+ $dest_dir_lib = $dest_dir
+ $receipt_dest_dir = $root
+ }
+
+ # Looks like all of the above assignments failed
+ if (-Not $dest_dir) {
+ throw "ERROR: could not find a valid path to install to; please check the installation instructions"
+ }
+
+ # The replace call here ensures proper escaping is inlined into the receipt
+ $receipt = $receipt.Replace('AXO_INSTALL_PREFIX', $receipt_dest_dir.replace("\", "\\"))
+
+ $dest_dir = New-Item -Force -ItemType Directory -Path $dest_dir
+ $dest_dir_lib = New-Item -Force -ItemType Directory -Path $dest_dir_lib
+ Write-Information "Installing to $dest_dir"
+ # Just copy the binaries from the temp location to the install dir
+ foreach ($bin_path in $artifacts["bin_paths"]) {
+ $installed_file = Split-Path -Path "$bin_path" -Leaf
+ Copy-Item "$bin_path" -Destination "$dest_dir" -ErrorAction Stop
+ Remove-Item "$bin_path" -Recurse -Force -ErrorAction Stop
+ Write-Information " $installed_file"
+
+ if (($dests = $info["aliases"][$installed_file])) {
+ $source = Join-Path "$dest_dir" "$installed_file"
+ foreach ($dest_name in $dests) {
+ $dest = Join-Path $dest_dir $dest_name
+ $null = New-Item -ItemType HardLink -Target "$source" -Path "$dest" -Force -ErrorAction Stop
+ }
+ }
+ }
+ foreach ($lib_path in $artifacts["lib_paths"]) {
+ $installed_file = Split-Path -Path "$lib_path" -Leaf
+ Copy-Item "$lib_path" -Destination "$dest_dir_lib" -ErrorAction Stop
+ Remove-Item "$lib_path" -Recurse -Force -ErrorAction Stop
+ Write-Information " $installed_file"
+ }
+ foreach ($lib_path in $artifacts["staticlib_paths"]) {
+ $installed_file = Split-Path -Path "$lib_path" -Leaf
+ Copy-Item "$lib_path" -Destination "$dest_dir_lib" -ErrorAction Stop
+ Remove-Item "$lib_path" -Recurse -Force -ErrorAction Stop
+ Write-Information " $installed_file"
+ }
+
+ $formatted_bins = ($info["bins"] | ForEach-Object { '"' + $_ + '"' }) -join ","
+ $receipt = $receipt.Replace('"CARGO_DIST_BINS"', $formatted_bins)
+ $formatted_libs = ($info["libs"] | ForEach-Object { '"' + $_ + '"' }) -join ","
+ $receipt = $receipt.Replace('"CARGO_DIST_DYLIBS"', $formatted_libs)
+ $formatted_staticlibs = ($info["staticlibs"] | ForEach-Object { '"' + $_ + '"' }) -join ","
+ $receipt = $receipt.Replace('"CARGO_DIST_STATICLIBS"', $formatted_staticlibs)
+ # Also replace the aliases with the arch-specific one
+ $receipt = $receipt.Replace('"binary_aliases":{}', -join('"binary_aliases":', $info['aliases_json']))
+
+ # Write the install receipt
+ $null = New-Item -Path $receipt_home -ItemType "directory" -ErrorAction SilentlyContinue
+ # Trying to get Powershell 5.1 (not 6+, which is fake and lies) to write utf8 is a crime
+ # because "Out-File -Encoding utf8" actually still means utf8BOM, so we need to pull out
+ # .NET's APIs which actually do what you tell them (also apparently utf8NoBOM is the
+ # default in newer .NETs but I'd rather not rely on that at this point).
+ $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
+ [IO.File]::WriteAllLines("$receipt_home/lazygh-receipt.json", "$receipt", $Utf8NoBomEncoding)
+
+ # Respect the environment, but CLI takes precedence
+ if ($null -eq $NoModifyPath) {
+ $NoModifyPath = $env:INSTALLER_NO_MODIFY_PATH
+ }
+
+ Write-Information "everything's installed!"
+ if (-not $NoModifyPath) {
+ Add-Ci-Path $dest_dir
+ if (Add-Path $dest_dir) {
+ Write-Information ""
+ Write-Information "To add $dest_dir to your PATH, either restart your system or run:"
+ Write-Information ""
+ Write-Information " set Path=$dest_dir;%Path% (cmd)"
+ Write-Information " `$env:Path = `"$dest_dir;`$env:Path`" (powershell)"
+ }
+ }
+}
+
+# Attempt to do CI-specific rituals to get the install-dir on PATH faster
+function Add-Ci-Path($OrigPathToAdd) {
+ # If GITHUB_PATH is present, then write install_dir to the file it refs.
+ # After each GitHub Action, the contents will be added to PATH.
+ # So if you put a curl | sh for this script in its own "run" step,
+ # the next step will have this dir on PATH.
+ #
+ # Note that GITHUB_PATH will not resolve any variables, so we in fact
+ # want to write the install dir and not an expression that evals to it
+ if (($gh_path = $env:GITHUB_PATH)) {
+ Write-Output "$OrigPathToAdd" | Out-File -FilePath "$gh_path" -Encoding utf8 -Append
+ }
+}
+
+# Try to add the given path to PATH via the registry
+#
+# Returns true if the registry was modified, otherwise returns false
+# (indicating it was already on PATH)
+function Add-Path($OrigPathToAdd) {
+ Write-Verbose "Adding $OrigPathToAdd to your PATH"
+ $RegistryPath = "HKCU:\Environment"
+ $PropertyName = "Path"
+ $PathToAdd = $OrigPathToAdd
+
+ $Item = if (Test-Path $RegistryPath) {
+ # If the registry key exists, get it
+ Get-Item -Path $RegistryPath
+ } else {
+ # If the registry key doesn't exist, create it
+ Write-Verbose "Creating $RegistryPath"
+ New-Item -Path $RegistryPath -Force
+ }
+
+ $OldPath = ""
+ try {
+ # Try to get the old PATH value. If that fails, assume we're making it from scratch.
+ # Otherwise assume there's already paths in here and use a ; separator
+ $OldPath = $Item | Get-ItemPropertyValue -Name $PropertyName
+ $PathToAdd = "$PathToAdd;"
+ } catch {
+ # We'll be creating the PATH from scratch
+ Write-Verbose "No $PropertyName Property exists on $RegistryPath (we'll make one)"
+ }
+
+ # Check if the path is already there
+ #
+ # We don't want to incorrectly match "C:\blah\" to "C:\blah\blah\", so we include the semicolon
+ # delimiters when searching, ensuring exact matches. To avoid corner cases we add semicolons to
+ # both sides of the input, allowing us to pretend we're always in the middle of a list.
+ Write-Verbose "Old $PropertyName Property is $OldPath"
+ if (";$OldPath;" -like "*;$OrigPathToAdd;*") {
+ # Already on path, nothing to do
+ Write-Verbose "install dir already on PATH, all done!"
+ return $false
+ } else {
+ # Actually update PATH
+ Write-Verbose "Actually mutating $PropertyName Property"
+ $NewPath = $PathToAdd + $OldPath
+ # We use -Force here to make the value already existing not be an error
+ $Item | New-ItemProperty -Name $PropertyName -Value $NewPath -PropertyType String -Force | Out-Null
+ return $true
+ }
+}
+
+function Initialize-Environment() {
+ If (($PSVersionTable.PSVersion.Major) -lt 5) {
+ throw @"
+Error: PowerShell 5 or later is required to install $app_name.
+Upgrade PowerShell:
+
+ https://docs.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell
+
+"@
+ }
+
+ # show notification to change execution policy:
+ $allowedExecutionPolicy = @('Unrestricted', 'RemoteSigned', 'ByPass')
+ If ((Get-ExecutionPolicy).ToString() -notin $allowedExecutionPolicy) {
+ throw @"
+Error: PowerShell requires an execution policy in [$($allowedExecutionPolicy -join ", ")] to run $app_name. For example, to set the execution policy to 'RemoteSigned' please run:
+
+ Set-ExecutionPolicy RemoteSigned -scope CurrentUser
+
+"@
+ }
+
+ # GitHub requires TLS 1.2
+ If ([System.Enum]::GetNames([System.Net.SecurityProtocolType]) -notcontains 'Tls12') {
+ throw @"
+Error: Installing $app_name requires at least .NET Framework 4.5
+Please download and install it first:
+
+ https://www.microsoft.com/net/download
+
+"@
+ }
+}
+
+function New-Temp-Dir() {
+ [CmdletBinding(SupportsShouldProcess)]
+ param()
+ $parent = [System.IO.Path]::GetTempPath()
+ [string] $name = [System.Guid]::NewGuid()
+ New-Item -ItemType Directory -Path (Join-Path $parent $name)
+}
+
+# PSScriptAnalyzer doesn't like how we use our params as globals, this calms it
+$Null = $ArtifactDownloadUrl, $NoModifyPath, $Help
+# Make Write-Information statements be visible
+$InformationPreference = "Continue"
+
+# The default interactive handler
+try {
+ Install-Binary "$Args"
+} catch {
+ Write-Information $_
+ exit 1
+}
diff --git a/lazygh-installer.sh.txt b/lazygh-installer.sh.txt
new file mode 100644
index 0000000..478e30d
--- /dev/null
+++ b/lazygh-installer.sh.txt
@@ -0,0 +1,1196 @@
+#!/bin/sh
+# shellcheck shell=dash
+#
+# Licensed under the MIT license
+# , at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+if [ "$KSH_VERSION" = 'Version JM 93t+ 2010-03-05' ]; then
+ # The version of ksh93 that ships with many illumos systems does not
+ # support the "local" extension. Print a message rather than fail in
+ # subtle ways later on:
+ echo 'this installer does not work with this ksh93 version; please try bash!' >&2
+ exit 1
+fi
+
+set -u
+
+APP_NAME="lazygh"
+APP_VERSION="0.5.0"
+ARTIFACT_DOWNLOAD_URL="${INSTALLER_DOWNLOAD_URL:-https://github.com/kmj-007/lazygh/releases/download/v0.5.0}"
+PRINT_VERBOSE=${INSTALLER_PRINT_VERBOSE:-0}
+PRINT_QUIET=${INSTALLER_PRINT_QUIET:-0}
+NO_MODIFY_PATH=${INSTALLER_NO_MODIFY_PATH:-0}
+read -r RECEIPT <&2
+ say_verbose " from $_url" 1>&2
+ say_verbose " to $_file" 1>&2
+
+ ensure mkdir -p "$_dir"
+
+ if ! downloader "$_url" "$_file"; then
+ say "failed to download $_url"
+ say "this may be a standard network error, but it may also indicate"
+ say "that $APP_NAME's release process is not working. When in doubt"
+ say "please feel free to open an issue!"
+ exit 1
+ fi
+
+ # ...and then the updater, if it exists
+ if [ -n "$_updater_name" ]; then
+ local _updater_url="$ARTIFACT_DOWNLOAD_URL/$_updater_name"
+ # This renames the artifact while doing the download, removing the
+ # target triple and leaving just the appname-update format
+ local _updater_file="$_dir/$APP_NAME-update"
+
+ if ! downloader "$_updater_url" "$_updater_file"; then
+ say "failed to download $_updater_url"
+ say "this may be a standard network error, but it may also indicate"
+ say "that $APP_NAME's release process is not working. When in doubt"
+ say "please feel free to open an issue!"
+ exit 1
+ fi
+
+ # Add the updater to the list of binaries to install
+ _bins="$_bins $APP_NAME-update"
+ fi
+
+ # unpack the archive
+ case "$_zip_ext" in
+ ".zip")
+ ensure unzip -q "$_file" -d "$_dir"
+ ;;
+
+ ".tar."*)
+ ensure tar xf "$_file" --strip-components 1 -C "$_dir"
+ ;;
+ *)
+ err "unknown archive format: $_zip_ext"
+ ;;
+ esac
+
+ install "$_dir" "$_bins" "$_libs" "$_staticlibs" "$_arch" "$@"
+ local _retval=$?
+ if [ "$_retval" != 0 ]; then
+ return "$_retval"
+ fi
+
+ ignore rm -rf "$_dir"
+
+ # Install the install receipt
+ mkdir -p "$RECEIPT_HOME" || {
+ err "unable to create receipt directory at $RECEIPT_HOME"
+ }
+ echo "$RECEIPT" > "$RECEIPT_HOME/$APP_NAME-receipt.json"
+ # shellcheck disable=SC2320
+ local _retval=$?
+
+ return "$_retval"
+}
+
+# Replaces $HOME with the variable name for display to the user,
+# only if $HOME is defined.
+replace_home() {
+ local _str="$1"
+
+ if [ -n "${HOME:-}" ]; then
+ echo "$_str" | sed "s,$HOME,\$HOME,"
+ else
+ echo "$_str"
+ fi
+}
+
+json_binary_aliases() {
+ local _arch="$1"
+
+ case "$_arch" in
+ "aarch64-apple-darwin")
+ echo '{}'
+ ;;
+ "x86_64-apple-darwin")
+ echo '{}'
+ ;;
+ "x86_64-pc-windows-gnu")
+ echo '{}'
+ ;;
+ "x86_64-unknown-linux-gnu")
+ echo '{}'
+ ;;
+ "x86_64-unknown-linux-musl-dynamic")
+ echo '{}'
+ ;;
+ "x86_64-unknown-linux-musl-static")
+ echo '{}'
+ ;;
+ *)
+ echo '{}'
+ ;;
+ esac
+}
+
+aliases_for_binary() {
+ local _bin="$1"
+ local _arch="$2"
+
+ case "$_arch" in
+ "aarch64-apple-darwin")
+ case "$_bin" in
+ *)
+ echo ""
+ ;;
+ esac
+ ;;
+ "x86_64-apple-darwin")
+ case "$_bin" in
+ *)
+ echo ""
+ ;;
+ esac
+ ;;
+ "x86_64-pc-windows-gnu")
+ case "$_bin" in
+ *)
+ echo ""
+ ;;
+ esac
+ ;;
+ "x86_64-unknown-linux-gnu")
+ case "$_bin" in
+ *)
+ echo ""
+ ;;
+ esac
+ ;;
+ "x86_64-unknown-linux-musl-dynamic")
+ case "$_bin" in
+ *)
+ echo ""
+ ;;
+ esac
+ ;;
+ "x86_64-unknown-linux-musl-static")
+ case "$_bin" in
+ *)
+ echo ""
+ ;;
+ esac
+ ;;
+ *)
+ echo ""
+ ;;
+ esac
+}
+
+select_archive_for_arch() {
+ local _true_arch="$1"
+ local _archive
+ case "$_true_arch" in
+ "aarch64-apple-darwin")
+ _archive="lazygh-aarch64-apple-darwin.tar.gz"
+ if [ -n "$_archive" ]; then
+ echo "$_archive"
+ return 0
+ fi
+ _archive="lazygh-x86_64-apple-darwin.tar.gz"
+ if [ -n "$_archive" ]; then
+ echo "$_archive"
+ return 0
+ fi
+ ;;
+ "aarch64-pc-windows-msvc")
+ _archive="lazygh-x86_64-pc-windows-msvc.tar.gz"
+ if [ -n "$_archive" ]; then
+ echo "$_archive"
+ return 0
+ fi
+ ;;
+ "x86_64-apple-darwin")
+ _archive="lazygh-x86_64-apple-darwin.tar.gz"
+ if [ -n "$_archive" ]; then
+ echo "$_archive"
+ return 0
+ fi
+ ;;
+ "x86_64-pc-windows-gnu")
+ _archive="lazygh-x86_64-pc-windows-msvc.tar.gz"
+ if [ -n "$_archive" ]; then
+ echo "$_archive"
+ return 0
+ fi
+ ;;
+ "x86_64-pc-windows-msvc")
+ _archive="lazygh-x86_64-pc-windows-msvc.tar.gz"
+ if [ -n "$_archive" ]; then
+ echo "$_archive"
+ return 0
+ fi
+ ;;
+ "x86_64-unknown-linux-gnu")
+ _archive="lazygh-x86_64-unknown-linux-gnu.tar.gz"
+ if ! check_glibc "2" "31"; then
+ _archive=""
+ fi
+ if [ -n "$_archive" ]; then
+ echo "$_archive"
+ return 0
+ fi
+ _archive="lazygh-x86_64-unknown-linux-musl.tar.gz"
+ if [ -n "$_archive" ]; then
+ echo "$_archive"
+ return 0
+ fi
+ ;;
+ "x86_64-unknown-linux-musl-dynamic")
+ _archive="lazygh-x86_64-unknown-linux-musl.tar.gz"
+ if [ -n "$_archive" ]; then
+ echo "$_archive"
+ return 0
+ fi
+ ;;
+ "x86_64-unknown-linux-musl-static")
+ _archive="lazygh-x86_64-unknown-linux-musl.tar.gz"
+ if [ -n "$_archive" ]; then
+ echo "$_archive"
+ return 0
+ fi
+ ;;
+ *)
+ err "there isn't a download for your platform $_true_arch"
+ ;;
+ esac
+ err "no compatible downloads were found for your platform $_true_arch"
+}
+
+check_glibc() {
+ local _min_glibc_major="$1"
+ local _min_glibc_series="$2"
+
+ # Parsing version out from line 1 like:
+ # ldd (Ubuntu GLIBC 2.35-0ubuntu3.1) 2.35
+ _local_glibc="$(ldd --version | awk -F' ' '{ if (FNR<=1) print $NF }')"
+
+ if [ "$(echo "${_local_glibc}" | awk -F. '{ print $1 }')" = "$_min_glibc_major" ] && [ "$(echo "${_local_glibc}" | awk -F. '{ print $2 }')" -ge "$_min_glibc_series" ]; then
+ return 0
+ else
+ say "System glibc version (\`${_local_glibc}') is too old; checking alternatives" >&2
+ return 1
+ fi
+}
+
+# See discussion of late-bound vs early-bound for why we use single-quotes with env vars
+# shellcheck disable=SC2016
+install() {
+ # This code needs to both compute certain paths for itself to write to, and
+ # also write them to shell/rc files so that they can look them up to e.g.
+ # add them to PATH. This requires an active distinction between paths
+ # and expressions that can compute them.
+ #
+ # The distinction lies in when we want env-vars to be evaluated. For instance
+ # if we determine that we want to install to $HOME/.myapp, which do we add
+ # to e.g. $HOME/.profile:
+ #
+ # * early-bound: export PATH="/home/myuser/.myapp:$PATH"
+ # * late-bound: export PATH="$HOME/.myapp:$PATH"
+ #
+ # In this case most people would prefer the late-bound version, but in other
+ # cases the early-bound version might be a better idea. In particular when using
+ # other env-vars than $HOME, they are more likely to be only set temporarily
+ # for the duration of this install script, so it's more advisable to erase their
+ # existence with early-bounding.
+ #
+ # This distinction is handled by "double-quotes" (early) vs 'single-quotes' (late).
+ #
+ # However if we detect that "$SOME_VAR/..." is a subdir of $HOME, we try to rewrite
+ # it to be '$HOME/...' to get the best of both worlds.
+ #
+ # This script has a few different variants, the most complex one being the
+ # CARGO_HOME version which attempts to install things to Cargo's bin dir,
+ # potentially setting up a minimal version if the user hasn't ever installed Cargo.
+ #
+ # In this case we need to:
+ #
+ # * Install to $HOME/.cargo/bin/
+ # * Create a shell script at $HOME/.cargo/env that:
+ # * Checks if $HOME/.cargo/bin/ is on PATH
+ # * and if not prepends it to PATH
+ # * Edits $HOME/.profile to run $HOME/.cargo/env (if the line doesn't exist)
+ #
+ # To do this we need these 4 values:
+
+ # The actual path we're going to install to
+ local _install_dir
+ # The directory C dynamic/static libraries install to
+ local _lib_install_dir
+ # The install prefix we write to the receipt.
+ # For organized install methods like CargoHome, which have
+ # subdirectories, this is the root without `/bin`. For other
+ # methods, this is the same as `_install_dir`.
+ local _receipt_install_dir
+ # Path to the an shell script that adds install_dir to PATH
+ local _env_script_path
+ # Potentially-late-bound version of install_dir to write env_script
+ local _install_dir_expr
+ # Potentially-late-bound version of env_script_path to write to rcfiles like $HOME/.profile
+ local _env_script_path_expr
+ # Forces the install to occur at this path, not the default
+ local _force_install_dir
+
+ # Check the newer app-specific variable before falling back
+ # to the older generic one
+ if [ -n "${LAZYGH_INSTALL_DIR:-}" ]; then
+ _force_install_dir="$LAZYGH_INSTALL_DIR"
+ elif [ -n "${CARGO_DIST_FORCE_INSTALL_DIR:-}" ]; then
+ _force_install_dir="$CARGO_DIST_FORCE_INSTALL_DIR"
+ fi
+
+ # Before actually consulting the configured install strategy, see
+ # if we're overriding it.
+ if [ -n "${_force_install_dir:-}" ]; then
+ _install_dir="$_force_install_dir/bin"
+ _lib_install_dir="$_force_install_dir/bin"
+ _receipt_install_dir="$_force_install_dir"
+ _env_script_path="$_force_install_dir/env"
+ _install_dir_expr="$(replace_home "$_force_install_dir/bin")"
+ _env_script_path_expr="$(replace_home "$_force_install_dir/env")"
+ fi
+ if [ -z "${_install_dir:-}" ]; then
+ # first try $CARGO_HOME, then fallback to $HOME/.cargo
+ if [ -n "${CARGO_HOME:-}" ]; then
+ _receipt_install_dir="$CARGO_HOME"
+ _install_dir="$CARGO_HOME/bin"
+ _lib_install_dir="$CARGO_HOME/bin"
+ _env_script_path="$CARGO_HOME/env"
+ # Initially make this early-bound to erase the potentially-temporary env-var
+ _install_dir_expr="$_install_dir"
+ _env_script_path_expr="$_env_script_path"
+ # If CARGO_HOME was set but it ended up being the default $HOME-based path,
+ # then keep things late-bound. Otherwise bake the value for safety.
+ # This is what rustup does, and accurately reproducing it is useful.
+ if [ -n "${HOME:-}" ]; then
+ if [ "$HOME/.cargo/bin" = "$_install_dir" ]; then
+ _install_dir_expr='$HOME/.cargo/bin'
+ _env_script_path_expr='$HOME/.cargo/env'
+ fi
+ fi
+ elif [ -n "${HOME:-}" ]; then
+ _receipt_install_dir="$HOME/.cargo"
+ _install_dir="$HOME/.cargo/bin"
+ _lib_install_dir="$HOME/.cargo/bin"
+ _env_script_path="$HOME/.cargo/env"
+ _install_dir_expr='$HOME/.cargo/bin'
+ _env_script_path_expr='$HOME/.cargo/env'
+ fi
+ fi
+
+ if [ -z "$_install_dir_expr" ]; then
+ err "could not find a valid path to install to!"
+ fi
+
+ # Identical to the sh version, just with a .fish file extension
+ # We place it down here to wait until it's been assigned in every
+ # path.
+ _fish_env_script_path="${_env_script_path}.fish"
+ _fish_env_script_path_expr="${_env_script_path_expr}.fish"
+
+ # Replace the temporary cargo home with the calculated one
+ RECEIPT=$(echo "$RECEIPT" | sed "s,AXO_INSTALL_PREFIX,$_receipt_install_dir,")
+ # Also replace the aliases with the arch-specific one
+ RECEIPT=$(echo "$RECEIPT" | sed "s'\"binary_aliases\":{}'\"binary_aliases\":$(json_binary_aliases "$_arch")'")
+
+ say "installing to $_install_dir"
+ ensure mkdir -p "$_install_dir"
+ ensure mkdir -p "$_lib_install_dir"
+
+ # copy all the binaries to the install dir
+ local _src_dir="$1"
+ local _bins="$2"
+ local _libs="$3"
+ local _staticlibs="$4"
+ local _arch="$5"
+ for _bin_name in $_bins; do
+ local _bin="$_src_dir/$_bin_name"
+ ensure mv "$_bin" "$_install_dir"
+ # unzip seems to need this chmod
+ ensure chmod +x "$_install_dir/$_bin_name"
+ for _dest in $(aliases_for_binary "$_bin_name" "$_arch"); do
+ ln -sf "$_install_dir/$_bin_name" "$_install_dir/$_dest"
+ done
+ say " $_bin_name"
+ done
+ # Like the above, but no aliases
+ for _lib_name in $_libs; do
+ local _lib="$_src_dir/$_lib_name"
+ ensure mv "$_lib" "$_lib_install_dir"
+ # unzip seems to need this chmod
+ ensure chmod +x "$_lib_install_dir/$_lib_name"
+ say " $_lib_name"
+ done
+ for _lib_name in $_staticlibs; do
+ local _lib="$_src_dir/$_lib_name"
+ ensure mv "$_lib" "$_lib_install_dir"
+ # unzip seems to need this chmod
+ ensure chmod +x "$_lib_install_dir/$_lib_name"
+ say " $_lib_name"
+ done
+
+ say "everything's installed!"
+
+ # Avoid modifying the users PATH if they are managing their PATH manually
+ case :$PATH:
+ in *:$_install_dir:*) NO_MODIFY_PATH=1 ;;
+ *) ;;
+ esac
+
+ if [ "0" = "$NO_MODIFY_PATH" ]; then
+ add_install_dir_to_ci_path "$_install_dir"
+ add_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr" ".profile" "sh"
+ exit1=$?
+ shotgun_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr" ".profile .bashrc .bash_profile .bash_login" "sh"
+ exit2=$?
+ add_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr" ".zshrc .zshenv" "sh"
+ exit3=$?
+ # This path may not exist by default
+ ensure mkdir -p "$HOME/.config/fish/conf.d"
+ exit4=$?
+ add_install_dir_to_path "$_install_dir_expr" "$_fish_env_script_path" "$_fish_env_script_path_expr" ".config/fish/conf.d/$APP_NAME.env.fish" "fish"
+ exit5=$?
+
+ if [ "${exit1:-0}" = 1 ] || [ "${exit2:-0}" = 1 ] || [ "${exit3:-0}" = 1 ] || [ "${exit4:-0}" = 1 ] || [ "${exit5:-0}" = 1 ]; then
+ say ""
+ say "To add $_install_dir_expr to your PATH, either restart your shell or run:"
+ say ""
+ say " source $_env_script_path_expr (sh, bash, zsh)"
+ say " source $_fish_env_script_path_expr (fish)"
+ fi
+ fi
+}
+
+print_home_for_script() {
+ local script="$1"
+
+ local _home
+ case "$script" in
+ # zsh has a special ZDOTDIR directory, which if set
+ # should be considered instead of $HOME
+ .zsh*)
+ if [ -n "${ZDOTDIR:-}" ]; then
+ _home="$ZDOTDIR"
+ else
+ _home="$HOME"
+ fi
+ ;;
+ *)
+ _home="$HOME"
+ ;;
+ esac
+
+ echo "$_home"
+}
+
+add_install_dir_to_ci_path() {
+ # Attempt to do CI-specific rituals to get the install-dir on PATH faster
+ local _install_dir="$1"
+
+ # If GITHUB_PATH is present, then write install_dir to the file it refs.
+ # After each GitHub Action, the contents will be added to PATH.
+ # So if you put a curl | sh for this script in its own "run" step,
+ # the next step will have this dir on PATH.
+ #
+ # Note that GITHUB_PATH will not resolve any variables, so we in fact
+ # want to write install_dir and not install_dir_expr
+ if [ -n "${GITHUB_PATH:-}" ]; then
+ ensure echo "$_install_dir" >> "$GITHUB_PATH"
+ fi
+}
+
+add_install_dir_to_path() {
+ # Edit rcfiles ($HOME/.profile) to add install_dir to $PATH
+ #
+ # We do this slightly indirectly by creating an "env" shell script which checks if install_dir
+ # is on $PATH already, and prepends it if not. The actual line we then add to rcfiles
+ # is to just source that script. This allows us to blast it into lots of different rcfiles and
+ # have it run multiple times without causing problems. It's also specifically compatible
+ # with the system rustup uses, so that we don't conflict with it.
+ local _install_dir_expr="$1"
+ local _env_script_path="$2"
+ local _env_script_path_expr="$3"
+ local _rcfiles="$4"
+ local _shell="$5"
+
+ if [ -n "${HOME:-}" ]; then
+ local _target
+ local _home
+
+ # Find the first file in the array that exists and choose
+ # that as our target to write to
+ for _rcfile_relative in $_rcfiles; do
+ _home="$(print_home_for_script "$_rcfile_relative")"
+ local _rcfile="$_home/$_rcfile_relative"
+
+ if [ -f "$_rcfile" ]; then
+ _target="$_rcfile"
+ break
+ fi
+ done
+
+ # If we didn't find anything, pick the first entry in the
+ # list as the default to create and write to
+ if [ -z "${_target:-}" ]; then
+ local _rcfile_relative
+ _rcfile_relative="$(echo "$_rcfiles" | awk '{ print $1 }')"
+ _home="$(print_home_for_script "$_rcfile_relative")"
+ _target="$_home/$_rcfile_relative"
+ fi
+
+ # `source x` is an alias for `. x`, and the latter is more portable/actually-posix.
+ # This apparently comes up a lot on freebsd. It's easy enough to always add
+ # the more robust line to rcfiles, but when telling the user to apply the change
+ # to their current shell ". x" is pretty easy to misread/miscopy, so we use the
+ # prettier "source x" line there. Hopefully people with Weird Shells are aware
+ # this is a thing and know to tweak it (or just restart their shell).
+ local _robust_line=". \"$_env_script_path_expr\""
+ local _pretty_line="source \"$_env_script_path_expr\""
+
+ # Add the env script if it doesn't already exist
+ if [ ! -f "$_env_script_path" ]; then
+ say_verbose "creating $_env_script_path"
+ if [ "$_shell" = "sh" ]; then
+ write_env_script_sh "$_install_dir_expr" "$_env_script_path"
+ else
+ write_env_script_fish "$_install_dir_expr" "$_env_script_path"
+ fi
+ else
+ say_verbose "$_env_script_path already exists"
+ fi
+
+ # Check if the line is already in the rcfile
+ # grep: 0 if matched, 1 if no match, and 2 if an error occurred
+ #
+ # Ideally we could use quiet grep (-q), but that makes "match" and "error"
+ # have the same behaviour, when we want "no match" and "error" to be the same
+ # (on error we want to create the file, which >> conveniently does)
+ #
+ # We search for both kinds of line here just to do the right thing in more cases.
+ if ! grep -F "$_robust_line" "$_target" > /dev/null 2>/dev/null && \
+ ! grep -F "$_pretty_line" "$_target" > /dev/null 2>/dev/null
+ then
+ # If the script now exists, add the line to source it to the rcfile
+ # (This will also create the rcfile if it doesn't exist)
+ if [ -f "$_env_script_path" ]; then
+ local _line
+ # Fish has deprecated `.` as an alias for `source` and
+ # it will be removed in a later version.
+ # https://fishshell.com/docs/current/cmds/source.html
+ # By contrast, `.` is the traditional syntax in sh and
+ # `source` isn't always supported in all circumstances.
+ if [ "$_shell" = "fish" ]; then
+ _line="$_pretty_line"
+ else
+ _line="$_robust_line"
+ fi
+ say_verbose "adding $_line to $_target"
+ # prepend an extra newline in case the user's file is missing a trailing one
+ ensure echo "" >> "$_target"
+ ensure echo "$_line" >> "$_target"
+ return 1
+ fi
+ else
+ say_verbose "$_install_dir already on PATH"
+ fi
+ fi
+}
+
+shotgun_install_dir_to_path() {
+ # Edit rcfiles ($HOME/.profile) to add install_dir to $PATH
+ # (Shotgun edition - write to all provided files that exist rather than just the first)
+ local _install_dir_expr="$1"
+ local _env_script_path="$2"
+ local _env_script_path_expr="$3"
+ local _rcfiles="$4"
+ local _shell="$5"
+
+ if [ -n "${HOME:-}" ]; then
+ local _found=false
+ local _home
+
+ for _rcfile_relative in $_rcfiles; do
+ _home="$(print_home_for_script "$_rcfile_relative")"
+ local _rcfile_abs="$_home/$_rcfile_relative"
+
+ if [ -f "$_rcfile_abs" ]; then
+ _found=true
+ add_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr" "$_rcfile_relative" "$_shell"
+ fi
+ done
+
+ # Fall through to previous "create + write to first file in list" behavior
+ if [ "$_found" = false ]; then
+ add_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr" "$_rcfiles" "$_shell"
+ fi
+ fi
+}
+
+write_env_script_sh() {
+ # write this env script to the given path (this cat/EOF stuff is a "heredoc" string)
+ local _install_dir_expr="$1"
+ local _env_script_path="$2"
+ ensure cat < "$_env_script_path"
+#!/bin/sh
+# add binaries to PATH if they aren't added yet
+# affix colons on either side of \$PATH to simplify matching
+case ":\${PATH}:" in
+ *:"$_install_dir_expr":*)
+ ;;
+ *)
+ # Prepending path in case a system-installed binary needs to be overridden
+ export PATH="$_install_dir_expr:\$PATH"
+ ;;
+esac
+EOF
+}
+
+write_env_script_fish() {
+ # write this env script to the given path (this cat/EOF stuff is a "heredoc" string)
+ local _install_dir_expr="$1"
+ local _env_script_path="$2"
+ ensure cat < "$_env_script_path"
+if not contains "$_install_dir_expr" \$PATH
+ # Prepending path in case a system-installed binary needs to be overridden
+ set -x PATH "$_install_dir_expr" \$PATH
+end
+EOF
+}
+
+check_proc() {
+ # Check for /proc by looking for the /proc/self/exe link
+ # This is only run on Linux
+ if ! test -L /proc/self/exe ; then
+ err "fatal: Unable to find /proc/self/exe. Is /proc mounted? Installation cannot proceed without /proc."
+ fi
+}
+
+get_bitness() {
+ need_cmd head
+ # Architecture detection without dependencies beyond coreutils.
+ # ELF files start out "\x7fELF", and the following byte is
+ # 0x01 for 32-bit and
+ # 0x02 for 64-bit.
+ # The printf builtin on some shells like dash only supports octal
+ # escape sequences, so we use those.
+ local _current_exe_head
+ _current_exe_head=$(head -c 5 /proc/self/exe )
+ if [ "$_current_exe_head" = "$(printf '\177ELF\001')" ]; then
+ echo 32
+ elif [ "$_current_exe_head" = "$(printf '\177ELF\002')" ]; then
+ echo 64
+ else
+ err "unknown platform bitness"
+ fi
+}
+
+is_host_amd64_elf() {
+ need_cmd head
+ need_cmd tail
+ # ELF e_machine detection without dependencies beyond coreutils.
+ # Two-byte field at offset 0x12 indicates the CPU,
+ # but we're interested in it being 0x3E to indicate amd64, or not that.
+ local _current_exe_machine
+ _current_exe_machine=$(head -c 19 /proc/self/exe | tail -c 1)
+ [ "$_current_exe_machine" = "$(printf '\076')" ]
+}
+
+get_endianness() {
+ local cputype=$1
+ local suffix_eb=$2
+ local suffix_el=$3
+
+ # detect endianness without od/hexdump, like get_bitness() does.
+ need_cmd head
+ need_cmd tail
+
+ local _current_exe_endianness
+ _current_exe_endianness="$(head -c 6 /proc/self/exe | tail -c 1)"
+ if [ "$_current_exe_endianness" = "$(printf '\001')" ]; then
+ echo "${cputype}${suffix_el}"
+ elif [ "$_current_exe_endianness" = "$(printf '\002')" ]; then
+ echo "${cputype}${suffix_eb}"
+ else
+ err "unknown platform endianness"
+ fi
+}
+
+get_architecture() {
+ local _ostype
+ local _cputype
+ _ostype="$(uname -s)"
+ _cputype="$(uname -m)"
+ local _clibtype="gnu"
+ local _local_glibc
+
+ if [ "$_ostype" = Linux ]; then
+ if [ "$(uname -o)" = Android ]; then
+ _ostype=Android
+ fi
+ if ldd --version 2>&1 | grep -q 'musl'; then
+ _clibtype="musl-dynamic"
+ else
+ # Assume all other linuxes are glibc (even if wrong, static libc fallback will apply)
+ _clibtype="gnu"
+ fi
+ fi
+
+ if [ "$_ostype" = Darwin ] && [ "$_cputype" = i386 ]; then
+ # Darwin `uname -m` lies
+ if sysctl hw.optional.x86_64 | grep -q ': 1'; then
+ _cputype=x86_64
+ fi
+ fi
+
+ if [ "$_ostype" = Darwin ] && [ "$_cputype" = x86_64 ]; then
+ # Rosetta on aarch64
+ if [ "$(sysctl -n hw.optional.arm64 2>/dev/null)" = "1" ]; then
+ _cputype=aarch64
+ fi
+ fi
+
+ if [ "$_ostype" = SunOS ]; then
+ # Both Solaris and illumos presently announce as "SunOS" in "uname -s"
+ # so use "uname -o" to disambiguate. We use the full path to the
+ # system uname in case the user has coreutils uname first in PATH,
+ # which has historically sometimes printed the wrong value here.
+ if [ "$(/usr/bin/uname -o)" = illumos ]; then
+ _ostype=illumos
+ fi
+
+ # illumos systems have multi-arch userlands, and "uname -m" reports the
+ # machine hardware name; e.g., "i86pc" on both 32- and 64-bit x86
+ # systems. Check for the native (widest) instruction set on the
+ # running kernel:
+ if [ "$_cputype" = i86pc ]; then
+ _cputype="$(isainfo -n)"
+ fi
+ fi
+
+ case "$_ostype" in
+
+ Android)
+ _ostype=linux-android
+ ;;
+
+ Linux)
+ check_proc
+ _ostype=unknown-linux-$_clibtype
+ _bitness=$(get_bitness)
+ ;;
+
+ FreeBSD)
+ _ostype=unknown-freebsd
+ ;;
+
+ NetBSD)
+ _ostype=unknown-netbsd
+ ;;
+
+ DragonFly)
+ _ostype=unknown-dragonfly
+ ;;
+
+ Darwin)
+ _ostype=apple-darwin
+ ;;
+
+ illumos)
+ _ostype=unknown-illumos
+ ;;
+
+ MINGW* | MSYS* | CYGWIN* | Windows_NT)
+ _ostype=pc-windows-gnu
+ ;;
+
+ *)
+ err "unrecognized OS type: $_ostype"
+ ;;
+
+ esac
+
+ case "$_cputype" in
+
+ i386 | i486 | i686 | i786 | x86)
+ _cputype=i686
+ ;;
+
+ xscale | arm)
+ _cputype=arm
+ if [ "$_ostype" = "linux-android" ]; then
+ _ostype=linux-androideabi
+ fi
+ ;;
+
+ armv6l)
+ _cputype=arm
+ if [ "$_ostype" = "linux-android" ]; then
+ _ostype=linux-androideabi
+ else
+ _ostype="${_ostype}eabihf"
+ fi
+ ;;
+
+ armv7l | armv8l)
+ _cputype=armv7
+ if [ "$_ostype" = "linux-android" ]; then
+ _ostype=linux-androideabi
+ else
+ _ostype="${_ostype}eabihf"
+ fi
+ ;;
+
+ aarch64 | arm64)
+ _cputype=aarch64
+ ;;
+
+ x86_64 | x86-64 | x64 | amd64)
+ _cputype=x86_64
+ ;;
+
+ mips)
+ _cputype=$(get_endianness mips '' el)
+ ;;
+
+ mips64)
+ if [ "$_bitness" -eq 64 ]; then
+ # only n64 ABI is supported for now
+ _ostype="${_ostype}abi64"
+ _cputype=$(get_endianness mips64 '' el)
+ fi
+ ;;
+
+ ppc)
+ _cputype=powerpc
+ ;;
+
+ ppc64)
+ _cputype=powerpc64
+ ;;
+
+ ppc64le)
+ _cputype=powerpc64le
+ ;;
+
+ s390x)
+ _cputype=s390x
+ ;;
+ riscv64)
+ _cputype=riscv64gc
+ ;;
+ loongarch64)
+ _cputype=loongarch64
+ ;;
+ *)
+ err "unknown CPU type: $_cputype"
+
+ esac
+
+ # Detect 64-bit linux with 32-bit userland
+ if [ "${_ostype}" = unknown-linux-gnu ] && [ "${_bitness}" -eq 32 ]; then
+ case $_cputype in
+ x86_64)
+ # 32-bit executable for amd64 = x32
+ if is_host_amd64_elf; then {
+ err "x32 linux unsupported"
+ }; else
+ _cputype=i686
+ fi
+ ;;
+ mips64)
+ _cputype=$(get_endianness mips '' el)
+ ;;
+ powerpc64)
+ _cputype=powerpc
+ ;;
+ aarch64)
+ _cputype=armv7
+ if [ "$_ostype" = "linux-android" ]; then
+ _ostype=linux-androideabi
+ else
+ _ostype="${_ostype}eabihf"
+ fi
+ ;;
+ riscv64gc)
+ err "riscv64 with 32-bit userland unsupported"
+ ;;
+ esac
+ fi
+
+ # treat armv7 systems without neon as plain arm
+ if [ "$_ostype" = "unknown-linux-gnueabihf" ] && [ "$_cputype" = armv7 ]; then
+ if ensure grep '^Features' /proc/cpuinfo | grep -q -v neon; then
+ # At least one processor does not have NEON.
+ _cputype=arm
+ fi
+ fi
+
+ _arch="${_cputype}-${_ostype}"
+
+ RETVAL="$_arch"
+}
+
+say() {
+ if [ "0" = "$PRINT_QUIET" ]; then
+ echo "$1"
+ fi
+}
+
+say_verbose() {
+ if [ "1" = "$PRINT_VERBOSE" ]; then
+ echo "$1"
+ fi
+}
+
+err() {
+ if [ "0" = "$PRINT_QUIET" ]; then
+ local red
+ local reset
+ red=$(tput setaf 1 2>/dev/null || echo '')
+ reset=$(tput sgr0 2>/dev/null || echo '')
+ say "${red}ERROR${reset}: $1" >&2
+ fi
+ exit 1
+}
+
+need_cmd() {
+ if ! check_cmd "$1"
+ then err "need '$1' (command not found)"
+ fi
+}
+
+check_cmd() {
+ command -v "$1" > /dev/null 2>&1
+ return $?
+}
+
+assert_nz() {
+ if [ -z "$1" ]; then err "assert_nz $2"; fi
+}
+
+# Run a command that should never fail. If the command fails execution
+# will immediately terminate with an error showing the failing
+# command.
+ensure() {
+ if ! "$@"; then err "command failed: $*"; fi
+}
+
+# This is just for indicating that commands' results are being
+# intentionally ignored. Usually, because it's being executed
+# as part of error handling.
+ignore() {
+ "$@"
+}
+
+# This wraps curl or wget. Try curl first, if not installed,
+# use wget instead.
+downloader() {
+ if check_cmd curl
+ then _dld=curl
+ elif check_cmd wget
+ then _dld=wget
+ else _dld='curl or wget' # to be used in error message of need_cmd
+ fi
+
+ if [ "$1" = --check ]
+ then need_cmd "$_dld"
+ elif [ "$_dld" = curl ]
+ then curl -sSfL "$1" -o "$2"
+ elif [ "$_dld" = wget ]
+ then wget "$1" -O "$2"
+ else err "Unknown downloader" # should not reach here
+ fi
+}
+
+download_binary_and_run_installer "$@" || exit 1
diff --git a/oranda-v0.6.1.css b/oranda-v0.6.1.css
new file mode 100644
index 0000000..2845f5e
--- /dev/null
+++ b/oranda-v0.6.1.css
@@ -0,0 +1,3 @@
+@import url("https://fonts.googleapis.com/css2?family=Fira+Sans:wght@400;700;900&display=swap");@import url("https://fonts.googleapis.com/css2?family=Comfortaa:wght@400;700&display=swap");@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600;700&display=swap");@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap");:root{--dark-fg-color:#fff;--light-fg-color:#141414;--light-bg-color:var(--dark-fg-color);--dark-bg-color:var(--light-fg-color);--fg-color:var(--light-fg-color);--bg-color:var(--light-bg-color);--light-link-color:#0284c7;--dark-link-color:#8bb9fe;--link-color:var(--light-link-color);--light-highlight-bg-color:#ededed;--light-highlight-fg-color:#595959;--dark-highlight-bg-color:#27272a;--dark-highlight-fg-color:#ededed;--highlight-fg-color:var(--light-highlight-fg-color);--highlight-bg-color:var(--light-highlight-bg-color);--font-face:"Fira Sans",sans-serif}:root.dark{--fg-color:var(--dark-fg-color);--bg-color:var(--dark-bg-color);--link-color:var(--dark-link-color);--highlight-fg-color:var(--dark-highlight-fg-color);--highlight-bg-color:var(--dark-highlight-bg-color)}
+
+/*! tailwindcss v3.4.0 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}:host,html{-webkit-text-size-adjust:100%;font-feature-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-variation-settings:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-feature-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em;font-variation-settings:normal}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{font-feature-settings:inherit;color:inherit;font-family:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],select,textarea{--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-radius:0;border-width:1px;font-size:1rem;line-height:1.5rem;padding:.5rem .75rem}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,select:focus,textarea:focus{--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);border-color:#2563eb;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);outline:2px solid #0000;outline-offset:2px}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}::-webkit-datetime-edit,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-year-field{padding-bottom:0;padding-top:0}select{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple]{background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;background-origin:border-box;border-color:#6b7280;border-width:1px;color:#2563eb;display:inline-block;flex-shrink:0;height:1rem;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:middle;width:1rem}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);outline:2px solid #0000;outline-offset:2px}[type=checkbox]:checked,[type=radio]:checked{background-color:currentColor;background-position:50%;background-repeat:no-repeat;background-size:100% 100%;border-color:#0000}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:checked:focus,[type=checkbox]:checked:hover,[type=checkbox]:indeterminate,[type=radio]:checked:focus,[type=radio]:checked:hover{background-color:currentColor;border-color:#0000}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-position:50%;background-repeat:no-repeat;background-size:100% 100%}[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{background-color:currentColor;border-color:#0000}[type=file]{background:unset;border-color:inherit;border-radius:0;border-width:0;font-size:unset;line-height:inherit;padding:0}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}:root{--color-inherit:inherit;--color-current:currentColor;--color-transparent:#0000;--color-black:#000;--color-white:#fff;--color-slate-50:#f8fafc;--color-slate-100:#f1f5f9;--color-slate-200:#e2e8f0;--color-slate-300:#cbd5e1;--color-slate-400:#94a3b8;--color-slate-500:#64748b;--color-slate-600:#475569;--color-slate-700:#334155;--color-slate-800:#1e293b;--color-slate-900:#0f172a;--color-slate-950:#020617;--color-gray-50:#f9fafb;--color-gray-100:#f3f4f6;--color-gray-200:#e5e7eb;--color-gray-300:#d1d5db;--color-gray-400:#9ca3af;--color-gray-500:#6b7280;--color-gray-600:#4b5563;--color-gray-700:#374151;--color-gray-800:#1f2937;--color-gray-900:#111827;--color-gray-950:#030712;--color-zinc-50:#fafafa;--color-zinc-100:#f4f4f5;--color-zinc-200:#e4e4e7;--color-zinc-300:#d4d4d8;--color-zinc-400:#a1a1aa;--color-zinc-500:#71717a;--color-zinc-600:#52525b;--color-zinc-700:#3f3f46;--color-zinc-800:#27272a;--color-zinc-900:#18181b;--color-zinc-950:#09090b;--color-neutral-50:#fafafa;--color-neutral-100:#f5f5f5;--color-neutral-200:#e5e5e5;--color-neutral-300:#d4d4d4;--color-neutral-400:#a3a3a3;--color-neutral-500:#737373;--color-neutral-600:#525252;--color-neutral-700:#404040;--color-neutral-800:#262626;--color-neutral-900:#171717;--color-neutral-950:#0a0a0a;--color-stone-50:#fafaf9;--color-stone-100:#f5f5f4;--color-stone-200:#e7e5e4;--color-stone-300:#d6d3d1;--color-stone-400:#a8a29e;--color-stone-500:#78716c;--color-stone-600:#57534e;--color-stone-700:#44403c;--color-stone-800:#292524;--color-stone-900:#1c1917;--color-stone-950:#0c0a09;--color-red-50:#fef2f2;--color-red-100:#fee2e2;--color-red-200:#fecaca;--color-red-300:#fca5a5;--color-red-400:#f87171;--color-red-500:#ef4444;--color-red-600:#dc2626;--color-red-700:#b91c1c;--color-red-800:#991b1b;--color-red-900:#7f1d1d;--color-red-950:#450a0a;--color-orange-50:#fff7ed;--color-orange-100:#ffedd5;--color-orange-200:#fed7aa;--color-orange-300:#fdba74;--color-orange-400:#fb923c;--color-orange-500:#f97316;--color-orange-600:#ea580c;--color-orange-700:#c2410c;--color-orange-800:#9a3412;--color-orange-900:#7c2d12;--color-orange-950:#431407;--color-amber-50:#fffbeb;--color-amber-100:#fef3c7;--color-amber-200:#fde68a;--color-amber-300:#fcd34d;--color-amber-400:#fbbf24;--color-amber-500:#f59e0b;--color-amber-600:#d97706;--color-amber-700:#b45309;--color-amber-800:#92400e;--color-amber-900:#78350f;--color-amber-950:#451a03;--color-yellow-50:#fefce8;--color-yellow-100:#fef9c3;--color-yellow-200:#fef08a;--color-yellow-300:#fde047;--color-yellow-400:#facc15;--color-yellow-500:#eab308;--color-yellow-600:#ca8a04;--color-yellow-700:#a16207;--color-yellow-800:#854d0e;--color-yellow-900:#713f12;--color-yellow-950:#422006;--color-lime-50:#f7fee7;--color-lime-100:#ecfccb;--color-lime-200:#d9f99d;--color-lime-300:#bef264;--color-lime-400:#a3e635;--color-lime-500:#84cc16;--color-lime-600:#65a30d;--color-lime-700:#4d7c0f;--color-lime-800:#3f6212;--color-lime-900:#365314;--color-lime-950:#1a2e05;--color-green-50:#f0fdf4;--color-green-100:#dcfce7;--color-green-200:#bbf7d0;--color-green-300:#86efac;--color-green-400:#4ade80;--color-green-500:#22c55e;--color-green-600:#16a34a;--color-green-700:#15803d;--color-green-800:#166534;--color-green-900:#14532d;--color-green-950:#052e16;--color-emerald-50:#ecfdf5;--color-emerald-100:#d1fae5;--color-emerald-200:#a7f3d0;--color-emerald-300:#6ee7b7;--color-emerald-400:#34d399;--color-emerald-500:#10b981;--color-emerald-600:#059669;--color-emerald-700:#047857;--color-emerald-800:#065f46;--color-emerald-900:#064e3b;--color-emerald-950:#022c22;--color-teal-50:#f0fdfa;--color-teal-100:#ccfbf1;--color-teal-200:#99f6e4;--color-teal-300:#5eead4;--color-teal-400:#2dd4bf;--color-teal-500:#14b8a6;--color-teal-600:#0d9488;--color-teal-700:#0f766e;--color-teal-800:#115e59;--color-teal-900:#134e4a;--color-teal-950:#042f2e;--color-cyan-50:#ecfeff;--color-cyan-100:#cffafe;--color-cyan-200:#a5f3fc;--color-cyan-300:#67e8f9;--color-cyan-400:#22d3ee;--color-cyan-500:#06b6d4;--color-cyan-600:#0891b2;--color-cyan-700:#0e7490;--color-cyan-800:#155e75;--color-cyan-900:#164e63;--color-cyan-950:#083344;--color-sky-50:#f0f9ff;--color-sky-100:#e0f2fe;--color-sky-200:#bae6fd;--color-sky-300:#7dd3fc;--color-sky-400:#38bdf8;--color-sky-500:#0ea5e9;--color-sky-600:#0284c7;--color-sky-700:#0369a1;--color-sky-800:#075985;--color-sky-900:#0c4a6e;--color-sky-950:#082f49;--color-blue-50:#eff6ff;--color-blue-100:#dbeafe;--color-blue-200:#bfdbfe;--color-blue-300:#93c5fd;--color-blue-400:#60a5fa;--color-blue-500:#3b82f6;--color-blue-600:#2563eb;--color-blue-700:#1d4ed8;--color-blue-800:#1e40af;--color-blue-900:#1e3a8a;--color-blue-950:#172554;--color-indigo-50:#eef2ff;--color-indigo-100:#e0e7ff;--color-indigo-200:#c7d2fe;--color-indigo-300:#a5b4fc;--color-indigo-400:#818cf8;--color-indigo-500:#6366f1;--color-indigo-600:#4f46e5;--color-indigo-700:#4338ca;--color-indigo-800:#3730a3;--color-indigo-900:#312e81;--color-indigo-950:#1e1b4b;--color-violet-50:#f5f3ff;--color-violet-100:#ede9fe;--color-violet-200:#ddd6fe;--color-violet-300:#c4b5fd;--color-violet-400:#a78bfa;--color-violet-500:#8b5cf6;--color-violet-600:#7c3aed;--color-violet-700:#6d28d9;--color-violet-800:#5b21b6;--color-violet-900:#4c1d95;--color-violet-950:#2e1065;--color-purple-50:#faf5ff;--color-purple-100:#f3e8ff;--color-purple-200:#e9d5ff;--color-purple-300:#d8b4fe;--color-purple-400:#c084fc;--color-purple-500:#a855f7;--color-purple-600:#9333ea;--color-purple-700:#7e22ce;--color-purple-800:#6b21a8;--color-purple-900:#581c87;--color-purple-950:#3b0764;--color-fuchsia-50:#fdf4ff;--color-fuchsia-100:#fae8ff;--color-fuchsia-200:#f5d0fe;--color-fuchsia-300:#f0abfc;--color-fuchsia-400:#e879f9;--color-fuchsia-500:#d946ef;--color-fuchsia-600:#c026d3;--color-fuchsia-700:#a21caf;--color-fuchsia-800:#86198f;--color-fuchsia-900:#701a75;--color-fuchsia-950:#4a044e;--color-pink-50:#fdf2f8;--color-pink-100:#fce7f3;--color-pink-200:#fbcfe8;--color-pink-300:#f9a8d4;--color-pink-400:#f472b6;--color-pink-500:#ec4899;--color-pink-600:#db2777;--color-pink-700:#be185d;--color-pink-800:#9d174d;--color-pink-900:#831843;--color-pink-950:#500724;--color-rose-50:#fff1f2;--color-rose-100:#ffe4e6;--color-rose-200:#fecdd3;--color-rose-300:#fda4af;--color-rose-400:#fb7185;--color-rose-500:#f43f5e;--color-rose-600:#e11d48;--color-rose-700:#be123c;--color-rose-800:#9f1239;--color-rose-900:#881337;--color-rose-950:#4c0519;--color-axo-pink:#ff75c3;--color-axo-pink-dark:#cc5c9b;--color-axo-orange:#f57070;--color-axo-orange-dark:#e85e68;--color-axo-highlighter:#ffd900;--color-axo-black:#141414;--color-axo-light-gray:#ededed;--color-axo-dark-gray:#595959}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }body,html{font-family:var(--font-face);height:100%;scroll-behavior:smooth}.container{display:flex;flex-direction:column;min-height:100%}.page-body{flex-grow:1}:focus{outline-offset:4px;outline-style:solid;outline-width:2px}body{background-color:var(--bg-color);color:var(--fg-color)}a{color:var(--link-color)}a:hover{text-decoration-line:underline;text-underline-offset:4px}.title{font-size:3.75rem;line-height:1;padding-bottom:.5rem;text-align:center}@media (min-width:640px){.title{font-size:6rem;line-height:1}}h1{font-size:1.875rem;font-weight:900;line-height:2.25rem;line-height:1.25;margin-bottom:2rem}@media (min-width:640px){h1{font-size:3.75rem;line-height:1}}h2{font-size:1.5rem;font-weight:700;line-height:2rem;line-height:1.25;margin-bottom:1.5rem}@media (min-width:640px){h2{font-size:3rem;line-height:1}}h2,h3{margin-top:3rem}@media (min-width:640px){h2,h3{margin-top:6rem}}h3{font-size:1.5rem;font-weight:700;line-height:2rem;line-height:1.25;margin-bottom:1rem}@media (min-width:640px){h3{font-size:2.25rem;line-height:2.5rem}}h4{font-size:1.5rem;line-height:2rem;line-height:1.25;margin-bottom:1rem}@media (min-width:640px){h4{font-size:1.875rem;line-height:2.25rem}}h5{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity));font-size:1.25rem;font-weight:700;line-height:1.75rem;line-height:1.25;margin-bottom:1rem}@media (min-width:640px){h5{font-size:1.5rem;line-height:2rem}}:is(:where(.dark) h5){--tw-text-opacity:1;color:rgb(226 232 240/var(--tw-text-opacity))}h6{--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity));font-size:1.25rem;font-weight:700;line-height:1.75rem;line-height:1.25;margin-bottom:1rem}@media (min-width:640px){h6{font-size:1.25rem;line-height:1.75rem}}:is(:where(.dark) h6){--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity))}p,table{font-size:1rem;line-height:1.5rem;line-height:1.625;margin-bottom:2rem}@media (min-width:640px){p,table{font-size:1.125rem;line-height:1.75rem}}b,li{font-size:1rem;line-height:1.5rem;line-height:1.625}@media (min-width:640px){b,li{font-size:1.125rem;line-height:1.75rem}}table{margin-bottom:4rem;margin-top:4rem}table th{padding:1rem;text-align:left;text-transform:uppercase}table td{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;padding:1rem;vertical-align:top}table td,table td>code{font-size:.875rem;line-height:1.25rem}table tbody tr{border-color:var(--fg-color);border-top-width:1px}div.table{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));margin-bottom:4rem;margin-top:4rem;width:100%}div.table .th{font-size:1.125rem;font-weight:700;line-height:1.75rem;text-align:left;text-transform:uppercase}div.table .th,div.table span:not(.th){border-color:var(--fg-color);border-top-width:1px;padding:1rem}div.table span:not(.th){font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:.875rem;line-height:1.25rem}li,ul{list-style-type:none}.rendered-markdown li,.rendered-markdown ul{list-style-type:disc}li{margin-bottom:1rem;margin-left:1rem}@media (min-width:640px){li{margin-left:2rem}}code{font-size:1rem;line-height:1.5rem;line-height:1.625;margin-bottom:1rem;white-space:pre-wrap}@media (min-width:640px){code{font-size:1.125rem;line-height:1.75rem}}code{color:var(--link-color)}div.table code{font-size:.875rem;line-height:1.25rem}h1 code,h2 code,h3 code,h4 code,h5 code,h6 code{font-size:inherit;line-height:inherit}pre{margin-bottom:4rem;margin-top:4rem;overflow:auto;padding:1rem}pre>code{font-size:.75rem;line-height:1rem}@media (min-width:640px){pre>code{font-size:1rem;line-height:1.5rem}}hr{border-style:dashed;border-width:1px;margin:5rem auto;text-align:center;width:16rem}@media (min-width:768px){hr{width:24rem}}img{display:inline}p>img:only-child{display:block;margin:auto}blockquote{border-color:var(--link-color);border-left-width:2px;font-size:1.5rem;line-height:2rem;padding-left:1.5rem}main{margin:6rem auto;max-width:80%}@media (min-width:1024px){main{max-width:56rem}}.github-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E");height:1.25rem;width:1.25rem}.dark .github-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23141414' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E")}.dark .artifacts,.light .artifacts{padding:2rem}.logo{display:block;margin:auto;max-width:20rem}.inline-code{text-align:center;word-break:break-all}.oblique{font-style:oblique}.well-color{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}.oranda-hide{display:none}.heading-1{font-size:1.875rem;font-weight:900;line-height:2.25rem;line-height:1.25;margin-bottom:2rem}@media (min-width:640px){.heading-1{font-size:3.75rem;line-height:1}}.heading-2{font-size:1.5rem;font-weight:700;line-height:2rem;line-height:1.25;margin-bottom:1.5rem}@media (min-width:640px){.heading-2{font-size:3rem;line-height:1}}.heading-3{font-size:1.5rem;font-weight:700;line-height:2rem;line-height:1.25;margin-bottom:1rem}@media (min-width:640px){.heading-3{font-size:2.25rem;line-height:2.5rem}}.heading-4{font-size:1.5rem;line-height:2rem;line-height:1.25;margin-bottom:1rem}@media (min-width:640px){.heading-4{font-size:1.875rem;line-height:2.25rem}}.heading-5{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity));font-size:1.25rem;font-weight:700;line-height:1.75rem;line-height:1.25;margin-bottom:1rem}@media (min-width:640px){.heading-5{font-size:1.5rem;line-height:2rem}}:is(:where(.dark) .heading-5){--tw-text-opacity:1;color:rgb(226 232 240/var(--tw-text-opacity))}.heading-6{--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity));font-size:1.25rem;font-weight:700;line-height:1.75rem;line-height:1.25;margin-bottom:1rem}@media (min-width:640px){.heading-6{font-size:1.25rem;line-height:1.75rem}}:is(:where(.dark) .heading-6){--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity))}.hidden{display:none}.inline-icon>svg{display:inline-block;height:25px;width:25px}.button{border-radius:.25rem;border-width:2px;cursor:pointer;font-size:1.125rem;line-height:1.75rem;min-width:-moz-max-content;min-width:max-content;padding:.75rem;transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);width:10rem}.button:disabled{cursor:default;opacity:.6}.button.primary{border-color:#0000}.button.primary,.button.secondary{background-color:var(--bg-color);color:var(--fg-color)}.button.secondary{border-color:var(--fg-color)}.button.secondary:hover{background-color:var(--fg-color);border-color:var(--bg-color);color:var(--bg-color)}select{background-color:var(--bg-color);color:var(--fg-color)}footer{align-items:center;background-color:var(--fg-color);color:var(--bg-color);display:flex;flex-grow:0;flex-shrink:1;font-size:.75rem;justify-content:space-between;line-height:1rem;padding:.5rem 1rem;width:100%}.nav{margin-bottom:3rem}.nav,.nav ul{padding:0;text-align:center}.nav ul{align-items:center;display:flex;flex-wrap:wrap;gap:1.5rem;justify-content:center;list-style-type:none}.nav ul li{margin:0;text-transform:capitalize}.repo_banner{background-color:var(--fg-color);color:var(--bg-color);padding-bottom:.375rem;padding-top:.375rem}.repo_banner>a{align-items:flex-start;display:flex;gap:.5rem;height:20px;justify-content:center}.repo_banner>a,.repo_banner>a:hover{--tw-text-opacity:1;color:rgb(248 250 252/var(--tw-text-opacity))}.repo_banner>a:hover{text-decoration-color:#f8fafc;text-decoration-line:underline;text-underline-offset:1px}:is(:where(.dark) .repo_banner>a){color:#141414}:is(:where(.dark) .repo_banner>a:hover){color:#141414;text-decoration-color:#141414}.funding-wrapper{align-items:center;display:flex;flex-direction:column;margin-top:2rem}.funding-list{gap:1rem;grid-template-columns:repeat(2,minmax(0,1fr));margin-bottom:3rem;margin-top:3rem;width:100%}@media (min-width:1024px){.funding-list{display:grid}}.funding-list li{margin:0 0 1rem}.funding-list li a{align-items:center;display:flex;gap:.5rem}.funding-list li a:hover button{--tw-text-opacity:1;background-color:#e85e68;background-color:var(--fg-color);border-color:#e85e68;border-color:var(--bg-color);color:rgb(241 245 249/var(--tw-text-opacity));color:var(--bg-color)}.funding-list .button{display:block;margin-right:.5rem;width:auto}.preferred-funding-list{grid-template-columns:repeat(1,minmax(0,1fr))}.preferred-funding-list li a{flex-direction:column;font-size:2.25rem;font-weight:700;line-height:2.5rem}.preferred-funding-list svg{height:3rem;width:3rem}.preferred-funding-list .button{border-width:0}.package-managers-downloads ul{margin-bottom:4rem;margin-top:4rem}.package-managers-downloads ul li{margin-left:0}.package-managers-downloads pre{margin-bottom:0;margin-top:0}.artifacts{align-items:center;display:none;flex-direction:column;margin-bottom:2rem;padding:0}@media (min-width:640px){.artifacts{display:flex}}.artifacts{background-color:var(--highlight-bg-color);color:var(--highlight-fg-color)}.artifacts-table{display:block;max-width:100%;overflow:auto}ul.tabs{border-bottom-width:2px;border-color:var(--highlight-fg-color);display:flex}ul.tabs li{font-size:1rem;line-height:1.5rem;margin:0;padding:.5rem .75rem}ul.tabs li:hover{cursor:pointer}ul.tabs li small{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity));display:block;font-size:.75rem;line-height:1rem}ul.tabs li.selected,ul.tabs li.selected small{background-color:var(--highlight-fg-color);color:var(--highlight-bg-color)}.install-content{margin:0;max-width:100%;padding:0}.detect{padding-right:.5rem;text-align:center}@media (min-width:768px){.detect{padding-right:0}}.detect+a{display:block;margin-bottom:.5rem;margin-top:.5rem}@media (min-width:640px){.detect+a{display:inline;margin-bottom:0;margin-top:0}}.detect .detected-os{text-transform:capitalize}.artifact-header pre{margin:0 auto}.artifact-header>h4{font-weight:700;margin-bottom:-.5rem;text-align:center}.artifact-header{max-width:100%;width:100%}.artifact-header>div:not(.install-code-wrapper){align-items:center;justify-content:center;margin-top:1rem;text-align:center}@media (min-width:768px){.artifact-header>div:not(.install-code-wrapper){display:flex;gap:1rem;text-align:left}}.backup-download:hover{text-decoration-line:none}.bottom-options{align-items:center;display:flex;flex-direction:row;justify-content:space-between;width:100%}.bottom-options.one{justify-content:center}.install-code-wrapper{align-items:stretch;display:flex}.install-code-wrapper>pre{flex-grow:1;flex-shrink:1}.install-code-wrapper>.button{align-items:center;border-bottom-left-radius:0;border-top-left-radius:0;display:flex;width:auto}.install-code-wrapper>.button:hover{text-decoration-line:none}.install-code-wrapper>.button:focus{outline-offset:-2px}.install-code-wrapper>.button.copy-clipboard-button{border-radius:0}.download-wrapper{display:flex;flex-direction:row;justify-content:center}.button .button-subtitle{display:block;font-size:.75rem;line-height:1rem}.published-date{display:block;margin-bottom:.5rem}.arch{margin:0;padding:1rem 0 0}.arch .contents{min-height:7rem;padding-top:1rem}.mobile-download{display:block;margin-bottom:3rem;margin-left:auto;margin-right:auto}@media (min-width:640px){.mobile-download{display:none}}.install-code-wrapper>.button svg{height:1.5rem;width:1.5rem}.release-body{margin-top:2rem;word-break:break-word}.release-body h1{font-size:1.5rem;font-weight:700;line-height:2rem;line-height:1.25;margin-bottom:1.5rem;margin-top:3rem}@media (min-width:640px){.release-body h1{font-size:3rem;line-height:1}}.release-body h2{font-size:1.5rem;font-weight:700;line-height:2rem;line-height:1.25;margin-bottom:1rem;margin-top:3rem}@media (min-width:640px){.release-body h2{font-size:2.25rem;line-height:2.5rem}}.release-body h3{font-size:1.5rem;line-height:2rem;line-height:1.25;margin-bottom:1rem}@media (min-width:640px){.release-body h3{font-size:1.875rem;line-height:2.25rem}}.release-body h4{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity));font-size:1.25rem;font-weight:700;line-height:1.75rem;line-height:1.25;margin-bottom:1rem}@media (min-width:640px){.release-body h4{font-size:1.5rem;line-height:2rem}}:is(:where(.dark) .release-body h4){--tw-text-opacity:1;color:rgb(226 232 240/var(--tw-text-opacity))}.release-body h5{--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity));font-size:1.25rem;font-weight:700;line-height:1.75rem;line-height:1.25;margin-bottom:1rem}@media (min-width:640px){.release-body h5{font-size:1.25rem;line-height:1.75rem}}:is(:where(.dark) .release-body h5){--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity))}.release-body li,.release-body ul{list-style-type:disc}.releases-nav{align-self:flex-start;position:sticky;top:3rem;width:-moz-max-content;width:max-content}.release>h2{margin-top:0}.release>h2 a{color:var(--fg-color)}.releases-list{display:flex;flex-direction:column;gap:8rem}.releases-wrapper{gap:3rem;margin-top:3rem;position:relative}@media (min-width:768px){.releases-wrapper{display:grid}}.releases-wrapper{grid-template-columns:160px minmax(0,1fr)}.releases-nav ul{border-left-width:4px;display:none;flex-direction:column;gap:.5rem;list-style-type:none;margin:0;padding-left:1rem}@media (min-width:768px){.releases-nav ul{display:flex}}.releases-nav ul{border-color:var(--fg-color)}.releases-nav ul li{font-size:.875rem;line-height:1.25rem;margin:0 0 0 .25rem;position:relative}.releases-nav ul li:before{--tw-translate-y:-50%;background-color:var(--fg-color);content:"";display:block;height:.25rem;left:-1.25rem;position:absolute;top:50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));width:1rem}.releases-nav ul li a{text-decoration-color:#0000;text-underline-offset:2px}.releases-nav ul li a:hover{text-decoration-line:underline}.releases-nav ul li a{color:var(--fg-color)}.release-info{display:flex;font-size:1rem;gap:2rem;line-height:1.5rem}.prereleases-toggle,.release-info{align-items:center}.prereleases-toggle{display:none;margin-bottom:1.5rem;position:relative;width:-moz-max-content;width:max-content}@media (min-width:768px){.prereleases-toggle{display:flex}}.prereleases-toggle input{border-radius:.25rem;color:var(--fg-color);height:1.25rem;width:1.25rem}.prereleases-toggle label{font-weight:500;margin-left:.75rem}.release-info svg{height:1.5rem;width:1.5rem}.release-info>span{align-items:center;display:flex;gap:.5rem}ul.index-grid{align-items:stretch;display:grid;gap:2rem;margin-top:4rem}@media (min-width:768px){ul.index-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){ul.index-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}.index-grid li{border-color:var(--bg-color);border-radius:.25rem;border-width:1px;box-shadow:0 0 0 8px #0000004d;flex-direction:column;margin-left:0}.index-grid .content,.index-grid li{display:flex;justify-content:space-between}.index-grid .content{padding:1rem}.index-grid .links{display:flex;width:100%}.index-grid .links>:not([hidden])~:not([hidden]){--tw-divide-x-reverse:0;border-left-width:calc(1px*(1 - var(--tw-divide-x-reverse)));border-right-width:calc(1px*var(--tw-divide-x-reverse))}.index-grid .links{border-top-width:1px}.index-grid .links a{align-items:center;display:inline-flex;width:50%}.index-grid .links a>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.5rem*var(--tw-space-x-reverse))}.index-grid .links a{padding:1rem 1.5rem}.index-grid .content .index-logo{flex-shrink:0;height:5rem;position:relative;width:5rem}.index-grid li.preferred{grid-column:span 2/span 2}.index-about h2{margin-top:0}html.axo{--highlight-color:#a78bfa;--axo-orange-color:#f57070;--axo-pink-color:#ff75c3;--light-fg-color:#141414;--light-link-color:var(--axo-pink-color);--dark-link-color:var(--axo-pink-color);--light-highlight-bg-color:var(--light-bg-color);--light-highlight-fg-color:var(--light-fg-color);--dark-highlight-bg-color:var(--light-fg-color);--dark-highlight-fg-color:var(--light-bg-color);--font-face:"Comfortaa",sans-serif}code,h1,h2,h3{color:var(--highlight-color)}html.axo .button.primary{background-color:var(--link-color)}html.axo .repo_banner,html.axo footer{animation-duration:3s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:animation-gradient-title;background:-webkit-linear-gradient(left,var(--axo-orange-color),var(--axo-pink-color),var(--axo-orange-color));background-size:1600px 200px}@media (prefers-reduced-motion){html.axo .repo_banner,html.axo footer{animation-duration:0s}}html.hacker html.axo .repo_banner,html.hacker html.axo footer{background:-webkit-linear-gradient(left,var(--hacker-green),var(--color-green-600),var(--hacker-green))}html.cupcake html.axo .repo_banner,html.cupcake html.axo footer{background:var(--secondary)}html.axo h1.title{-webkit-text-fill-color:#0000;animation-duration:3s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:animation-gradient-title;background:-webkit-linear-gradient(left,var(--axo-orange-color),var(--axo-pink-color),var(--axo-orange-color));background-size:1600px 200px}@media (prefers-reduced-motion){html.axo h1.title{animation-duration:0s}}html.hacker html.axo h1.title{background:-webkit-linear-gradient(left,var(--hacker-green),var(--color-green-600),var(--hacker-green))}html.cupcake html.axo h1.title{background:var(--secondary)}html.axo h1.title{-webkit-background-clip:text;background-clip:text}.axo-gradient{animation-duration:3s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:animation-gradient-title;background:-webkit-linear-gradient(left,var(--axo-orange-color),var(--axo-pink-color),var(--axo-orange-color));background-size:1600px 200px}.text-fill-transparent{-webkit-text-fill-color:#0000}.axo-gradient-text{-webkit-text-fill-color:#0000;animation-duration:3s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:animation-gradient-title;background:-webkit-linear-gradient(left,var(--axo-orange-color),var(--axo-pink-color),var(--axo-orange-color));background-size:1600px 200px}@media (prefers-reduced-motion){.axo-gradient-text{animation-duration:0s}}html.hacker .axo-gradient-text{background:-webkit-linear-gradient(left,var(--hacker-green),var(--color-green-600),var(--hacker-green))}html.cupcake .axo-gradient-text{background:var(--secondary)}.axo-gradient-text{-webkit-background-clip:text;background-clip:text}@media (prefers-reduced-motion){.axo-gradient{animation-duration:0s}}@keyframes slide-in{0%{top:-100vh}to{top:0}}@keyframes animation-gradient-title{0%{background-position:0 1600px}to{background-position:1600px 0}}html.hacker{--light-highlight-bg-color:var(--dark-highlight-bg-color);--light-highlight-fg-color:var(--dark-highlight-fg-color);--hacker-green:#20c20e}html.hacker ::-moz-selection{background-color:#20c20e;color:#141414}html.hacker ::selection{background-color:#20c20e;color:#141414}html.hacker body{--tw-text-opacity:1;background-color:#141414;font-family:IBM Plex Mono,monospace}html.hacker .button.secondary,html.hacker body{color:rgb(203 213 225/var(--tw-text-opacity))}html.hacker .button.secondary{--tw-border-opacity:1;--tw-text-opacity:1;border-color:rgb(249 115 22/var(--tw-border-opacity))}html.hacker .button.secondary:hover{--tw-bg-opacity:1;background-color:rgb(249 115 22/var(--tw-bg-opacity));color:#141414}html.hacker h2,html.hacker h3,html.hacker h4,html.hacker h5,html.hacker h6{--tw-text-opacity:1;color:rgb(124 58 237/var(--tw-text-opacity))}html.hacker .repo_banner>a,html.hacker footer{color:var(--light-color);padding-bottom:.5rem;padding-top:.5rem}html.hacker p,html.hacker table{--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity))}html.hacker .title{display:inline-block;margin-left:2rem;position:relative;text-align:left}@keyframes blink-animation{to{visibility:hidden}}html.hacker .title:after{animation:blink-animation 1s steps(5,start) infinite;background:var(--hacker-green);content:"";display:block;height:70px;left:100%;margin-left:.75rem;position:absolute;top:.75rem;width:1rem}html.hacker .title:before{--tw-translate-y:-50%;--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity));content:"> ";display:block;font-size:3rem;left:-2rem;line-height:1;margin-top:.5rem;position:absolute;top:50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}html.hacker .title,html.hacker div.table .th,html.hacker h1{color:var(--hacker-green)}html.hacker a{--tw-text-opacity:1;color:rgb(249 115 22/var(--tw-text-opacity))}html.hacker a:hover{text-decoration-color:#f97316}html.hacker .axo-gradient{background:-webkit-linear-gradient(left,var(--hacker-green),var(--color-green-600),var(--hacker-green))}html.hacker .nav ul{justify-content:flex-start}html.hacker .button.primary{--tw-bg-opacity:1;background-color:rgb(249 115 22/var(--tw-bg-opacity));border-color:#0000;color:#141414}html.hacker .button.primary:hover{--tw-bg-opacity:1;background-color:rgb(234 88 12/var(--tw-bg-opacity))}html.hacker .artifact-header>h4{color:var(--light-color);text-align:left}html.hacker .releases-nav ul li a{--tw-text-opacity:1;color:rgb(226 232 240/var(--tw-text-opacity))}html.hacker .releases-nav ul li:before{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}html.hacker .releases-nav ul{--tw-border-opacity:1;border-left-color:rgb(75 85 99/var(--tw-border-opacity))}html.hacker .prereleases-toggle input:checked{--tw-bg-opacity:1;background-color:rgb(249 115 22/var(--tw-bg-opacity))}html.hacker .releases-nav ul li a:hover{text-decoration-color:#f97316}html.hacker .funding-wrapper{align-items:flex-start}html.hacker .artifacts{padding:2rem}html.hacker .published-date{display:block;width:100%}html.hacker .logo{display:block;margin:0}html.cupcake body{--b1:#faf7f5;--b2:#dfaff7;--text:#291334cc;--links:#291334;--primary:#65c3c8;--secondary:#291334;--secondary-100:#210f2a;--code:#291334;background-color:var(--b1);color:var(--text);font-family:Inter,sans-serif}html.cupcake ::-moz-selection{-webkit-text-fill-color:var(--code);background-color:var(--b2);color:var(--code)}html.cupcake ::selection{-webkit-text-fill-color:var(--code);background-color:var(--b2);color:var(--code)}html.cupcake .button.primary{background:var(--secondary);border-color:#0000;color:var(--b2);text-decoration-line:none}html.cupcake .button.primary:hover{--tw-bg-opacity:1;background-color:rgb(234 88 12/var(--tw-bg-opacity));background:var(--secondary-100)}html.cupcake .button.secondary{border:1px solid var(--secondary);color:var(--secondary-100)}html.cupcake .button.secondary:hover{background:var(--secondary);color:var(--b2)}html.cupcake h1,html.cupcake h2,html.cupcake h3,html.cupcake h4,html.cupcake h5,html.cupcake h6,html.cupcake p,html.cupcake table{color:var(--text)}html.cupcake .title{color:var(--primary)}html.cupcake a{color:var(--links);font-weight:500;text-decoration-line:underline;text-underline-offset:4px}html.cupcake a:hover{color:var(--code);text-underline-offset:2px}html.cupcake .axo-gradient{background:var(--secondary)}html.cupcake .github-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23dfaff7' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E")}html.cupcake .repo_banner>a,html.cupcake footer{color:var(--b2);text-decoration:none}html.cupcake code{color:var(--code);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-weight:500}html.cupcake .prereleases-toggle input:checked{background-color:var(--primary)}html.cupcake .artifacts{padding:2rem}html.cupcake .releases-nav ul li a{color:var(--links)}html.cupcake .releases-nav ul li:before{--tw-bg-opacity:1;background-color:rgb(209 213 219/var(--tw-bg-opacity))}html.cupcake .releases-nav ul{--tw-border-opacity:1;border-left-color:rgb(209 213 219/var(--tw-border-opacity))}html.cupcake div.table .th{color:var(--primary)}
\ No newline at end of file