[
  {
    "path": "README.md",
    "content": "# Dotfiles\n\n> Configuration of software I personally use for software development\n\n![Showcase](./showcase.png)\n*Hyprland with foot terminal, tmux and neovim*\n\n## Install\n\nAdd user:\n\n```sh\nuseradd -m -G docker,systemd-journal,users,wheel -k /dev/null -s /usr/bin/zsh cj\n```\n\nClone repository and install dotfiles as a new user:\n\n```sh\nsudo -iu cj\ngit clone https://github.com/codingjerk/dotfiles.git\npython ~/dotfiles/tools/render install\n```\n\n**WARNING:** it's for me and myself only,\nI don't recommend to run it on your own machines.\n\nIf you're not me (lol), just clone this repository and poke into configuration files (it's in `config` directory!).\n\n### Optional extra steps (on new hosts)\n\n1. Generate ssh keys:\n\n```sh\nssh-keygen -t ed25519\n```\n\n2. Import gpg keys:\n\n```sh\ngpg --import <key>.gpg\ngpg --edit-key <key-id>\n# trust, 5, save\n```\n\n3. Initialize stores:\n\n```sh\ngit clone cj:private-pass .password-store\ngit clone cj:when-private .when\ngit clone cj:ledger-private .ledger\ngit clone cj:notes-private notes\n```\n\n4. Install LSPs for `neovim`.\n   Check `neovim`'s `init.lua` for actual sources\n   and build instructions.\n\n5. Install lazy\n\n```sh\nmkdir -p ~/.local/share/nvim/lazy\ncd $$\ngit clone https://github.com/folke/lazy.nvim.git\n\nin vim:\n:Lazy Install\n```\n\n## Update (re-render configuration files)\n\nPull sources and re-render configs:\n\n```sh\ngit pull\npython ~/dotfiles/tools/render install\n```\n\n## How it works?\n\nThis repository contains:\n\n- `config` -- a bunch of configuration files and templates. Main directory here\n- `settings.toml` -- configurable settings (color palette, font, etc.), used by templates\n- `wallpaper.png` -- a wallpaper\n- `tools`\n   - `render` -- tool to render templates into configuration files\n\nItself, repository should be placed somewhere in your home directory,\nand after running `update` it will place rendered configuration files\ninto your home directory.\n"
  },
  {
    "path": "config/aria2/aria2.conf",
    "content": "# Default download dir\ndir=${HOME}/downloads/aria\n\n# I usually have very bad internet, so no seeding :(\nseed-time=0\n\n# Speed up some downloads\ndisable-ipv6=true\nfile-allocation=falloc\nbt-enable-lpd=true\n"
  },
  {
    "path": "config/cargo/config.toml",
    "content": "[cargo-new]\nvcs = \"none\" # do not automatically create git repository\n\n# Let's make cargo quiet, more UNIX-like\n[term]\nquiet = true\nverbose = false\nprogress.when = \"never\"\n\n[build]\n# WARN: be careful deploying stuff built locally\nrustflags = [\"-Ctarget-cpu=native\"]\n"
  },
  {
    "path": "config/chrome/flags.conf",
    "content": "# === Wayland support ===\n\n--ozone-platform=wayland\n\n# === Hardware acceleration tweaks ===\n\n# HW accelerated video encoding is not needed, but it does not hurt\n--enable-features=AcceleratedVideoDecodeLinuxGL,AcceleratedVideoEncoder\n\n# === Other ===\n\n--force-device-scale-factor=1.5\n--password-store=basic\n"
  },
  {
    "path": "config/cspell/cspell.yml",
    "content": "---\n$schema: https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json\nversion: '0.2'\nlanguage: en\ndictionaries:\n  - python\n  - python-common\n  - cpp\n  - node\n  - typescript\n  - html\n  - bash\n  - en-us\n  - ru-ru\n  - custom-cj\n  - custom-radar\ndictionaryDefinitions:\n  - name: custom-cj\n    path: .local/cspell-cj.txt\n  - name: custom-radar\n    path: .local/cspell-radar.txt\n"
  },
  {
    "path": "config/cspell/dict-cj.txt",
    "content": "# Kekich\nКекич\nkekich\n\n# Assembler\ncmov\ncmovne\n\n# Helix\nnonwhitespace\ntextobject\nnoyank\n\n# Chess\nbitboard\nbitboards\nbitscan\nmovegen\nstartpos\nperft\nstockfish\nshakmaty\nzobrist\n\n# Uci\nwtime\nbtime\nwinc\nbinc\nbestmove\nuciok\nreadyok\nucinewgame\n\n# Russian\nдешборд\nревьюшка\nревьюшке\nревьюшках\nскилл\nскиллы\nдисклеймер\nдебаг\nдебага\nфронтенд\n\n# Names\ngruzdev\ncodingjerk\n\n# Words\nblazingly\n\n# Rirs\nrir\nrirdb\nrirs\nafrinic\napnic\narin\nlacnic\nripe\nripencc\n\n# My projects\nniced\n\n# BGP\nasnames\nUUNET\n\n# Countries\nÅland\nPlurinational\nSint\nEustatius\nBouvet\nBurkina\nFaso\nCabo\nRica\nCôte\nd'Ivoire\nEswatini\nRéunion\nBarthélemy\nCunha\nKitts\nMarino\nSint\nMaarten\nMayen\nLeste\nTokelau\nCaicos\nBolivarian\nViet\nFutuna\n\n# Programs\nnmap\nlibrir\naddopts\nnorecursedirs\ndockerhub\npastebin\n\n# Other\nducati\ntestpaths\nlockfile\nlockfiles\npyright\nlangserver\nwasd\nautoimport\nuserns\ninitdb\nwillfarrell\nautoheal\ncrond\nlinestyle\npytest\nmypy\nhealthcheck\nfastapi\nloguru\nuvicorn\naiohttp\nbrotli\nasgi\norjson\njsonify\npydantic\nasyncpg\nmiddleware\nmiddlewares\nredoc\nstarlette\nfetchval\nbitnami\nblackbox\nblkio\ncacheprovider\ncobertura\ngunicorn\nhadolint\nhealthchecks\nhttpx\nisready\nmicrobenchmarking\npsqlrc\npyndantic\nqnet\nqnetd\nqrator\nbview\nbviews\nbatchwait\npromtail\nvarlogs\npeeringdb\nsetenv\ntestsuites\nuvloop\nEeuo\nexitfirst\ngsed\n\n# Python\npopleft\nmaxsplit\n\n# Python libs\nfernet\nlibnotify\npypackages\naiopg\n\n# Bash & Linux\niptables\nwg\nhtoprc\ntraceroute\niwctl\niwd\nhypr\nhypridle\nhyprland\nhyprlock\nlesskey\ncurlrc\nwaybar\nwofi\nfontconfig\nlinenr\nsatty\nparu\nzoxide\nhexview\npowertop\ntermdown\nvimium\ncolemak\npipewire\nwireplumber\ntextfiles\ncadvisor\nrootfs\ntmpfs\npipefs\nsecurityfs\nsysfs\ntracefs\ndevpts\ndevtmpfs\nfusectl\nhugetlbfs\nautofs\nsshfs\nconfigfs\ndebugfs\nsmartctl\ngrub\njournalctl\nswapon\nlocalectl\npkgfile\ntimedatectl\nhwclock\nsysyohc\noomd\nnetworkd\ntimesyncd\nzram\nbootctl\nmkinitcpio\nnvme\ncfdisk\nsfdisk\nnoatime\nlazytime\nwriteback\npackstrap\ndevel\nnetcat\nucode\ndhcpcd\nnoto\npulseaudio\nzathura\nswaybg\nswayidle\npolkit\nvfat\nfmask\ndmask\niocharset\nconsolefonts\nvconsole\nmodconf\nzstd\nkver\npacman\nmirrorlist\nvconsole\nsetfont\nconsolefonts\npowersave\ncentisecs\nprintk\nautogroup\nlogind\npoweroff\nLLMNR\nresolv\npcspkr\nuvcvideo\niwlwifi\niwlmvm\nuapsd\nmultilib\nrootflags\nzswap\nudev\nwlan\ntmpfiles\naspm\npowersupersave\nscache\npacstrap\nnowatchdog\ncpufreq\nnofail\ncoredump\nnspawn\nnconfig\npipefail\n\n# Technologies\nnextdns\ndotenv\n\n# Own language servers\npylsp\ntsls\ndmypy\nyapf\nscls\n\n# Configuration files\ncursorline\nstatusline\n\n# Typst\ntypst\nsmallcaps\nemph\n\n# Rust\nrustflags\nCtarget\nchrono\nDatelike\nTimelike\nDEBG\npeekable\nrsplitn\nuserauth\nrustfmt\nflate\nmimalloc\nlumbermill\nsqlx\nunseparated\nhumantime\nreqwest\nserde\nrustls\nshadowsocks\nclippy\nchacha\nrngs\ndalek\ngetrandom\nwgapi\ndefguard\nprvkey\n\n# Tech\nCQRS\nphind\nublock\nmatplotlibrc\nxcompose\nzathurarc\npypoetry\nledgerrc\ntermux\notus\nipinfo\nmmdb\nkeepalive\nkeepalives\n\n# Chess\nhalfmove\nfullmove\nrnbqkbnr\n"
  },
  {
    "path": "config/curl/curlrc",
    "content": "# Follow redirects\nlocation\n\n# Do not output anything except on error\nsilent\nshow-error\n\n# Fail fast on server errors and show body\nfail-with-body\n\n# Use remote name for output files (if used if -O)\n# NOTE: conflicts with some URLs, do not enable\n# remote-header-name\n\n# When following a redirect, automatically set the previous URL as referer.\nreferer = \";auto\"\n\n# Wait 5 seconds before timing out.\nconnect-timeout = 5\n\n# Retry automatically\nretry = 3\nretry-delay = 1\n"
  },
  {
    "path": "config/electron/electron-flags.conf",
    "content": "# Wayland support\n--enable-features=UseOzonePlatform,WaylandWindowDecorations,WebRTCPipeWireCapturer\n--ozone-platform=wayland\n"
  },
  {
    "path": "config/fd/ignore",
    "content": ".git/\nnode_modules/\ntarget/\ndist/\n__pycache__/\n.mypy_cache/\n.venv/\n.zig-cache/\nzig-out/\n"
  },
  {
    "path": "config/fontconfig/fonts.conf",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE fontconfig SYSTEM \"urn:fontconfig:fonts.dtd\">\n<fontconfig>\n  <!-- Disable embedded bitmap fonts -->\n  <match target=\"font\">\n    <edit name=\"embeddedbitmap\" mode=\"assign\">\n      <bool>false</bool>\n    </edit>\n  </match>\n\n  <!-- Use Noto Thai Serif for Thai -->\n  <match>\n    <test name=\"lang\" compare=\"contains\">\n      <string>th</string>\n    </test>\n    <test name=\"family\">\n      <string>serif</string>\n    </test>\n    <edit name=\"family\" mode=\"prepend\">\n      <string>Noto Serif Thai</string>\n    </edit>\n  </match>\n  <match>\n    <test name=\"lang\" compare=\"contains\">\n      <string>th</string>\n    </test>\n    <test name=\"family\">\n      <string>sans-serif</string>\n    </test>\n    <edit name=\"family\" mode=\"prepend\">\n      <string>Noto Serif Thai</string>\n    </edit>\n  </match>\n</fontconfig>\n"
  },
  {
    "path": "config/foot/foot.ini",
    "content": "[main]\n# Fonts\nfont=Noto Sans Mono Light:size=11,Arundina Sans Mono:size=17\nfont-bold=Noto Sans Mono Light:size=11\nfont-italic=Noto Sans Mono Light:size=11:slant=italic\nfont-bold-italic=Noto Sans Mono Light:size=11:slant=italic\n\n# Fonts fine-tuning\nvertical-letter-offset=-1\nline-height=13\nunderline-thickness=0.6\nunderline-offset=2\n\n# Styling\nbold-text-in-bright=palette-based\npad=24x24 center\ninitial-window-size-chars=80x30\nresize-by-cells=no\n\n# Misc\nterm=xterm\nlocked-title=yes\nselection-target=both\nworkers=0\nutmp-helper=none\n\n# Colors\ngamma-correct-blending=false\n\n[bell]\nurgent=yes\n\n[scrollback]\nlines=1000\n\n[cursor]\nbeam-thickness=1.0\n\n[mouse]\nhide-when-typing=yes\n\n[key-bindings]\nclipboard-paste=Control+v Control+Shift+v\nscrollback-up-page=none\nscrollback-down-page=none\nscrollback-up-half-page=Shift+Page_Up\nscrollback-down-half-page=Shift+Page_Down\nscrollback-up-line=Shift+Up\nscrollback-down-line=Shift+Down\n\n[mouse-bindings]\nprimary-paste=none\n\n[tweak]\nscaling-filter=none\nfont-monospace-warn=no\ngrapheme-width-method=wcswidth  # necessary to make emoji not too wide\n\ngrapheme-shaping=no\nsixel=no\n\n[colors]\ncursor=${bg} ${fg_half_dim}\n\nbackground=${bg}\nforeground=${fg}\n\nselection-foreground=${fg}\nselection-background=${bg_sel}\n\nregular0=${bg}\nregular1=${red}\nregular2=${green}\nregular3=${yellow}\nregular4=${blue}\nregular5=${purple}\nregular6=${cyan}\nregular7=${fg_half_dim}\n\nbright0=${fg_dim}\nbright1=${orange}\nbright2=${green}\nbright3=${yellow}\nbright4=${blue}\nbright5=${pink}\nbright6=${cyan}\nbright7=${fg}\n\ndim0=${fg_dim}\ndim1=${orange}\ndim2=${green}\ndim3=${yellow}\ndim4=${blue}\ndim5=${pink}\ndim6=${cyan}\ndim7=${fg}\n"
  },
  {
    "path": "config/fuzzel/fuzzel.ini",
    "content": "font = Noto Sans Mono Light:pixelsize=18\nprompt = \"\"\nicons-enabled = no\nlines = 8\nwidth = 50\nhorizontal-pad = 24\nvertical-pad = 24\nanchor = top\ny-margin = 75\ninner-pad = 16\nline-height = 24\n\n[colors]\nbackground = ${bg_dim_more}ff\ntext = ${fg_half_dim}ff\nprompt = ff0000ff\nplaceholder = ff0000ff\ninput = ${blue}ff\nmatch = ${purple}ff\nselection = ${bg_dim_more}ff\nselection-text = ${blue}ff\nselection-match = ${purple}ff\nborder = ${bg_dim_more}ff\n\n[border]\nwidth = 1\nradius = 24\n"
  },
  {
    "path": "config/git/config",
    "content": "[user]\n    name = Denis Gruzdev\n    email = codingjerk@gmail.com\n    signingkey = E3DFEC736900FDE2\n\n[commit]\n    gpgSign = true\n    template = ~/.config/git/template\n    verbose = true  # add more context to commit messages\n\n[core]\n    autocrlf = input  # keep newlines as in input\n    compression = 9  # trade cpu for network\n    fsync = none\n    whitespace = error  # threat incorrect whitespace as errors\n    preloadindex = true  # preload index for faster status\n\n[advice]  # disable advices\n    addEmptyPathspec = false\n    pushNonFastForward = false\n    statusHints = false\n\n[blame]\n    coloring = highlightRecent\n    date = relative\n\n[diff]\n    context = 3  # less context in diffs\n    renames = copies  # detect copies as renames in diffs\n    interHunkContext = 10  # merge near hunks in diffs\n\n[init]\n    defaultBranch = dev\n\n[log]\n    abbrevCommit = true  # short commits\n    graphColors  = blue,yellow,cyan,magenta,green,red\n\n[status]\n    branch = true\n    short = true\n    showStash = true\n    showUntrackedFiles = all  # show individual untracked files\n\n[pager]\n    branch = false  # no need to use pager for git branch\n    tag = false\n    diff = diff-so-fancy | $PAGER  # diff-so-fancy as diff pager\n\n[push]\n    autoSetupRemote = true  # easier to push new branches\n    default = current  # push only current branch by default\n    followTags = true  # push also tags\n    gpgSign = false  # my remotes doesn't support sign pushes\n\n[pull]\n    rebase = true\n    default = current\n\n[submodule]\n    fetchJobs = 16\n\n[rebase]\n    autoStash = true\n    missingCommitsCheck = warn  # warn if rebasing with missing commits\n\n[pack]\n    threads = 0  # use all available threads\n    windowMemory = 1g  # use 1g of memory for pack window\n    packSizeLimit = 1g  # max size of a packfile\n\n# Integrity\n[transfer]\n    fsckObjects = true\n\n[receive]\n    fsckObjects = true\n\n[fetch]\n    fsckObjects = true\n\n[branch]\n    sort = -committerdate\n\n[tag]\n    sort = -taggerdate\n\n# Colors\n[color \"blame\"]\n    highlightRecent = black bold,1 year ago,white,1 month ago,default,7 days ago,blue\n\n[color \"branch\"]\n    current  = magenta\n    local    = default\n    remote   = yellow\n    upstream = green\n    plain    = blue\n\n[color \"diff\"]\n    meta       = black bold\n    frag       = magenta\n    context    = white\n    whitespace = yellow reverse\n    old        = red\n\n[color.decorate]\n    HEAD = red\n    branch = blue\n    tag = yellow\n    remoteBranch = magenta\n\n[interactive]\n    diffFilter = diff-so-fancy --patch\n    singlekey = true\n\n# Third-party: diff-so-fancy\n[diff-so-fancy]\n    markEmptyLines = false\n\n# URL shortcuts\n[url \"git@github.com:\"]\n    insteadOf = \"gh:\"\n\n[url \"git@github.com:codingjerk/\"]\n    insteadOf = \"cj:\"\n\n[url \"ssh://git@git.qrator.net:2202/\"]\n    insteadOf = \"qrator:\"\n\n[url \"ssh://git@git.qrator.net:2202/radar/\"]\n    insteadOf = \"radar:\"\n"
  },
  {
    "path": "config/git/ignore",
    "content": "# Python specific\n.venv/\n.mypy_cache/\n.pytest_cache/\n__pycache__/\n.hypothesis/\n.ruff_cache/\n.ropeproject/\n\n# Rust specific\ntarget/\n\n# Zig specific\n.zig-cache/\nzig-out/\n"
  },
  {
    "path": "config/git/template",
    "content": "# feat: ✨ \n# feat: 🔍 \n# feat: 🔗 \n# feat: 🔒 \n\n# fix: 🐛 \n# fix: 🐞 \n# fix: 🩹 \n# fix: 🚑️ \n\n# style: 💅 \n# style: 🎨 \n# style: 💄 \n\n# ci: 🦊 \n# ci: 📦 \n\n# deploy: 🚀 \n# deploy: 📦 \n\n# chore: 🧹 \n# chore: 🔧 \n# chore: ⚙️ \n# docs: 📜 \n\n# refactor: 🔨 \n# perf: 🚀 \n\n# test: 🚦 \n# debug: 🧪 \n\n# BREAKING CHANGE: 🚨 \n# BREAKING CHANGE: 💥 \n# BREAKING CHANGE: 💣 \n"
  },
  {
    "path": "config/gnupg/gpg-agent.conf",
    "content": "default-cache-ttl 1800  # 30 minutes\n\n# Ask for password in nicer menu\npinentry-program /usr/bin/pinentry-tty\n"
  },
  {
    "path": "config/gnupg/gpg.conf",
    "content": "no-greeting\ncharset utf-8\n\nkeyserver https://keys.openpgp.org\nkeyserver https://keyserver.ubuntu.com\nkeyserver https://pgp.mit.edu\n"
  },
  {
    "path": "config/helix/config.toml",
    "content": "theme = \"cj\"\n\n[editor]\n  auto-save = false  # pretty annoying\n  auto-pairs = false  # too annoying sometimes\n  mouse = false  # I don't have mouse\n  cursorline = true\n  idle-timeout = 250\n  completion-timeout = 5  # instant autocompletion\n  completion-trigger-len = 1  # minimal length for autocompletion\n  true-color = true  # force true color support\n  color-modes = true  # use color to show modes\n  jump-label-alphabet = \"asdfzxcqwervtgbyhnujmikolp\"\n  rulers = [ 80, 120 ]\n  end-of-line-diagnostics = \"hint\"\n\n[editor.cursor-shape]\n  insert = \"bar\"\n\n[editor.file-picker]\n  hidden = false  # show files starting with dot\n\n[editor.gutters.line-numbers]\n  min-width = 2\n\n# TODO: enable similar line for rulers\n# WATCH: https://github.com/helix-editor/helix/issues/5190\n[editor.indent-guides]\n  render = true\n  character = \"¦\"  # \"🭲\" is okay too\n  skip-levels = 1\n\n[editor.search]\n  wrap-around = false  # easier to navigate through matches\n\n# TODO: disable cmdline / maybe statusline\n# WATCH: https://github.com/helix-editor/helix/issues/1662\n[editor.statusline]\n  left = [ \"mode\", \"read-only-indicator\" ]\n  center = []\n  right = [ \"diagnostics\" ]\n  mode.normal = \" \"\n  mode.insert = \"I\"\n  mode.select = \"S\"\n\n[editor.whitespace.render]\n  tab = \"all\"\n  nbsp = \"all\"\n\n[editor.whitespace.characters]\n  nbsp = \"⍽\"\n\n[keys.normal]\n  # WASD movements\n  w = \"move_line_up\"\n  a = \"move_char_left\"\n  s = \"move_line_down\"\n  d = \"move_char_right\"\n\n  W = [\"move_line_up\", \"move_line_up\", \"move_line_up\", \"move_line_up\", \"move_line_up\"]\n  A = \"move_prev_word_end\"\n  S = [\"move_line_down\", \"move_line_down\", \"move_line_down\", \"move_line_down\", \"move_line_down\"]\n  D = \"move_next_word_start\"\n\n  q = \"extend_to_line_start\"\n  e = \"extend_to_line_end\"\n  Q = \"insert_at_line_start\"\n  E = \"insert_at_line_end\"\n\n  # Bash-like C-a / C-e\n  C-a = \"goto_line_start\"\n  C-e = \"goto_line_end\"\n\n  # Multiple cursors\n  C-s = \"select_regex\"\n  C-d = [\"search_selection\", \"extend_search_next\"]\n  l = \"split_selection_on_newline\"\n\n  # Command palette\n  \"C-p\" = \"command_palette\"\n\n  # Search\n  \"?\" = \"global_search\"\n\n  # Rebind missing actions\n  x = \"delete_selection\"\n  v = \"extend_line_below\"\n  V = \"select_mode\"\n\n  # Jump back / forward\n  \"j\" = \"jump_backward\"\n  \"J\" = \"jump_forward\"\n\n  # Help\n  \"h\" = \"hover\"\n\n[keys.insert]\n  # Bash-like C-a / C-e\n  C-a = \"goto_line_start\"\n  C-e = \"goto_line_end_newline\"\n\n  # Insert tab character\n  C-t = \"insert_tab\"\n\n  # Command palette\n  \"C-p\" = \"command_palette\"\n\n[keys.select]\n  # WASD movements\n  w = \"extend_line_up\"\n  a = \"extend_char_left\"\n  s = \"extend_line_down\"\n  d = \"extend_char_right\"\n\n  W = \"extend_line_up\"\n  A = \"extend_prev_word_end\"\n  S = \"extend_line_down\"\n  D = \"extend_next_word_start\"\n\n  q = \"extend_to_line_start\"\n  e = \"extend_to_line_end\"\n  Q = \"extend_to_line_start\"\n  E = \"extend_to_line_end\"\n\n  # Bash-like C-a / C-e\n  C-a = \"goto_line_start\"\n  C-e = \"goto_line_end\"\n\n  # Multiple cursors\n  C-s = \"select_regex\"\n  C-d = [\"search_selection\", \"extend_search_next\"]\n  l = \"split_selection_on_newline\"\n\n  # Command palette\n  \"C-p\" = \"command_palette\"\n\n  # Search\n  \"?\" = \"global_search\"\n\n  # Rebind missing actions\n  x = \"delete_selection\"\n"
  },
  {
    "path": "config/helix/ignore",
    "content": "# Home directories\n.cache/\n.password-store/\n.cargo/registry/\n.npm/\n\n*.tdb\n\n# Git specific\n.git-crypt/\n\n# Python specific\n.pyenv/\n.venv/\n\n# Rust specific\nCargo.lock\ntarget/\n\n# Zig specific\n.zig-cache/\nzig-out/\n"
  },
  {
    "path": "config/helix/languages.toml",
    "content": "# Source: https://github.com/estin/simple-completion-language-server\n# Build: `cargo build --release`\n[language-server.buffer]\n  command = \"${home}/dev/simple-completion-language-server/target/release/simple-completion-language-server\"\n\n  [language-server.buffer.config]\n    max_completion_items = 500\n    feature_snippets = false\n    feature_unicode_input = false\n\n# Source: https://github.com/vlabo/cspell-lsp\n# Build: `npm install; npm run build`\n[language-server.cspell]\n  command = \"node\"\n  args = [ \"${home}/dev/cspell-lsp/index.js\", \"--stdio\" ]\n\n# Install: ruff-lsp\n[language-server.ruff]\n  command = \"ruff-lsp\"\n\n# Install: pyright\n[language-server.pyright]\n  command = \"pyright-langserver\"\n\n  [language-server.pyright.config.python.analysis]\n    typeCheckingMode = \"strict\"\n\n  [language-server.pyright.config.python.analysis.diagnosticSeverityOverrides]\n    reportMissingImports = false\n    reportMissingTypeStubs = false\n    reportUntypedFunctionDecorator = false\n    reportUnknownVariableType = false\n\n    # Covered by ruff\n    reportUnusedImport = false\n\n# Install: python-lsp-server, python-rope, python-pylsp-mypy\n[language-server.pylsp]\n  command = \"pylsp\"\n\n  [language-server.pylsp.config.pylsp.plugins]\n    # Disable unused plugins\n    autopep8.enabled = false\n    flake8.enabled = false\n    mccabe.enabled = false\n    preload.enabled = false\n    pycodestyle.enabled = false\n    pyflakes.enabled = false\n    yapf.enabled = false\n\n    # Settings\n    [language-server.pylsp.config.pylsp.plugins.jedi_completion]\n      include_params = false\n      fuzzy = true\n      resolve_at_most = 100\n\n[language-server.zls]\n  command = \"zls\"\n\n  [language-server.zls.config]\n    enable_autofix = true\n    enable_inlay_hints = false\n    enable_argument_placeholders = false\n    warn_style = true\n\n[language-server.rust-analyzer]\n  command = \"${home}/.cargo/bin/ra-multiplex\"\n\n  [language-server.rust-analyzer.config]\n    cachePriming.enable = false\n    completion.callable.snippets = \"none\"\n    completion.fullFunctionSignatures.enable = false  # make list shorter\n    completion.limit = 1024\n    completion.postfix.enable = false  # disable postfix snippets\n    completion.hideDeprecated = true\n\n    imports.preferNoStd = true\n\n    hover.actions.run.enable = false\n    hover.show.fields = 10\n\n    inlayHints.chainingHints.enable = false\n    inlayHints.closingBraceHints.enable = false\n    inlayHints.genericParameterHints.const.enable = false\n    inlayHints.typeHints.enable = false\n    inlayHints.parameterHints.enable = false\n    inlayHints.renderColons = false\n\n    lens.enable = false\n\n    lru.capacity = 512\n\n    diagnostics.experimental.enable = true\n    diagnostics.styleLints.enable = true\n\n    check.command = \"clippy\"\n\n    # Use separate target directory for rust-analyzer to remove interferences with cargo\n    cargo.targetDir = true\n\n    cargo.allTargets = false\n\n    rustfmt.extraArgs = [\n      \"--config=empty_item_single_line=false\",\n      \"--config=wrap_comments=true\",\n      \"--config=condense_wildcard_suffixes=true\",\n      \"--config=enum_discrim_align_threshold=10\",\n      \"--config=format_code_in_doc_comments=true\",\n      \"--config=hex_literal_case=Upper\",\n      \"--config=max_width=80\",\n      \"--config=reorder_impl_items=true\",\n      \"--config=group_imports=StdExternalCrate\",\n      \"--config=use_field_init_shorthand=true\",\n    ]\n\n[[language]]\n  name = \"python\"\n  auto-format = true\n  language-servers = [\n    # Completions, documentation, go to definition\n    { name = \"pylsp\", except-features = [ \"diagnostics\", \"format\" ] },\n    # Linting, fixes, formatting\n    \"ruff\",\n    # Type checking\n    { name = \"pyright\", only-features = [ \"diagnostics\" ] },\n    \"buffer\",\n    \"cspell\",\n  ]\n\n[[language]]\n  name = \"bash\"\n  # Install: bash-language-server\n  language-servers = [ \"bash-language-server\", \"buffer\", \"cspell\" ]\n\n[[language]]\n  name = \"dockerfile\"\n  # Install: dockerfile-language-server (aur)\n  language-servers = [ \"docker-langserver\", \"buffer\", \"cspell\" ]\n\n[[language]]\n  name = \"markdown\"\n  # Install: marksman\n  language-servers = [ \"marksman\", \"buffer\", \"cspell\" ]\n  roots = [\"README.md\"]\n\n[[language]]\n  name = \"yaml\"\n  language-servers = [ \"buffer\", \"cspell\" ]\n\n[[language]]\n  name = \"html\"\n  language-servers = [ \"buffer\", \"cspell\" ]\n\n[[language]]\n  name = \"toml\"\n  language-servers = [ \"buffer\", \"cspell\" ]\n\n[[language]]\n  name = \"git-commit\"\n  rulers = []\n  language-servers = [ \"buffer\", \"cspell\" ]\n\n[[language]]\n  name = \"zig\"\n  # Install: zls\n  language-servers = [ \"zls\", \"buffer\", \"cspell\" ]\n\n[[language]]\n  name = \"rust\"\n  # Install: rust-analyzer, ra-multiplex\n  language-servers = [ \"rust-analyzer\", \"buffer\", \"cspell\" ]\n"
  },
  {
    "path": "config/helix/theme.toml",
    "content": "# Syntax\n\"comment\" = \"fg-dim\"\n\n\"type\" = \"fg-half-dim\"\n\"constructor\" = \"yellow\"\n\n\"constant.numeric\" = \"yellow\"\n\"constant.builtin\" = \"orange\"\n\n\"string\" = \"green\"\n\"constant.character.escape\" = \"pink\"\n\"string.special\" = \"green\"\n\n\"variable.builtin\" = \"orange\"\n\"variable.parameter\" = \"cyan\"\n\n\"function\" = \"purple\"\n\"function.method\" = \"fg\"\n\"function.builtin\" = \"orange\"\n\n\"punctuation\" = \"fg-half-dim\"\n\"punctuation.bracket\" = \"fg-dim\"\n\"punctuation.special\" = \"pink\"\n\"operator\" = \"fg-dim\"\n\"label\" = \"fg-dim\"\n\n\"keyword\" = \"blue\"\n\"namespace\" = \"fg\"\n\n\"markup.heading\" = \"orange\"\n\"markup.list\" = \"fg-dim\"\n\"markup.list.unchecked\" = \"red\"\n\"markup.bold\" = \"red\"\n\"markup.italic\" = { modifiers = [\"italic\"] }\n\"markup.strikethrough\" = { modifiers = [\"crossed_out\"] }\n\"markup.link.url\" = { underline.style = \"line\" }\n\"markup.quote\" = \"fg-half-dim\"\n\"markup.raw.inline\" = \"yellow\"\n\n\"special\" = \"blue\"  # also, highlight in file picker\n\n# HTML\n\"attribute\" = \"yellow\"\n\"string.regexp\" = \"pink\"\n\"tag\" = \"purple\"\n\n# Diff\n\"diff.plus\" = \"green\"\n\"diff.minus\" = \"red\"\n\"diff.delta\" = \"purple\"\n\n# Background\n\"ui.background\" = { bg = \"bg\", fg = \"fg\" }\n\n# Cursor\n\"ui.cursor\" = { bg = \"fg-dim\", fg = \"bg\" }\n\"ui.selection\" = { bg = \"bg-sel\" }\n\"ui.cursor.match\" = { fg = \"purple\", underline.style = \"line\" }\n\"ui.cursorline.primary\" = { bg = \"bg-dim\" }\n\n# Gutter\n\"ui.linenr\" = \"fg-dim\"\n\"ui.linenr.selected\" = \"fg\"\n\n\"error\" = \"red\"\n\"warning\" = \"orange\"\n\"info\" = \"yellow\"  # for TODO highlighting\n\"hint\" = \"gray\"\n\n# Diagnostics\n\"diagnostic.error\" = { fg = \"red\", underline.style = \"line\" }\n\"diagnostic.warning\" = { fg = \"orange\", underline.style = \"line\" }\n\"diagnostic.info\" = { underline.style = \"line\" }\n\"diagnostic.hint\" = { underline.style = \"line\" }\n\n# Statusline\n\"ui.statusline\" = { fg = \"fg\" }\n\"ui.statusline.insert\" = { bg = \"yellow\", fg = \"bg\" }\n\"ui.statusline.select\" = { bg = \"purple\", fg = \"bg\" }\n\n# Whitespace\n\"ui.virtual.whitespace\" = \"red\"\n\"ui.virtual.indent-guide\" = \"bg-sel\"\n\"ui.virtual.ruler\" = { bg = \"bg-sel\" }\n\n# Windows & Popups\n\"ui.popup\" = { bg = \"bg-dim\", fg = \"fg-half-dim\" }\n\"ui.popup.info\" = { bg = \"bg\", fg = \"fg-half-dim\" }\n\"ui.window\" = { fg = \"fg-dim\" }\n\"ui.help\" = { fg = \"fg-half-dim\", bg = \"bg-dim\" }\n\n\"ui.text\" = \"fg\"\n\"ui.text.focus\" = { fg = \"fg\", bg = \"bg-sel\" }\n\"ui.text.inactive\" = \"fg-dim\"\n\n\"ui.menu\" = { fg = \"fg-half-dim\", bg = \"bg-dim\" }\n\"ui.menu.selected\" = { fg = \"fg\", bg = \"bg-sel\" }\n\"ui.menu.scroll\" = { bg = \"bg-sel\", fg = \"bg-sel\" }\n\n\"ui.highlight\" = { bg = \"bg-dim\" }  # highlight in file picker\n\n# Jump labels\n\"ui.virtual.jump-label\" = { fg = \"yellow\", modifiers = [ \"reversed\" ] }\n\n[palette]\n  bg          = \"#${bg}\"\n  bg-dim      = \"#${bg_dim}\"  # panels, line highlighting\n  bg-sel      = \"#${bg_sel}\"  # selection\n\n  fg          = \"#${fg}\"\n  fg-half-dim = \"#${fg_half_dim}\"  # some menus\n  fg-dim      = \"#${fg_dim}\"       # comments\n\n  red         = \"#${red}\"     # errors, important stuff\n  orange      = \"#${orange}\"  # warnings, less important stuff\n  yellow      = \"#${yellow}\"  # highlighting\n  green       = \"#${green}\"   # strings, good stuff\n  cyan        = \"#${cyan}\"    # arguments\n  blue        = \"#${blue}\"    # keywords\n  purple      = \"#${purple}\"  # functions and tags\n  pink        = \"#${pink}\"    # string interpolation, regexps\n"
  },
  {
    "path": "config/htop/htoprc",
    "content": "# Beware! This file is rewritten by htop when settings are changed in the interface.\n# The parser is also very primitive, and not human-friendly.\nhtop_version=3.3.0\nconfig_reader_min_version=3\nfields=48 39 46 1\nhide_kernel_threads=1\nhide_userland_threads=1\nhide_running_in_container=0\nshadow_other_users=0\nshow_thread_names=0\nshow_program_path=0\nhighlight_base_name=1\nhighlight_deleted_exe=1\nshadow_distribution_path_prefix=0\nhighlight_megabytes=1\nhighlight_threads=0\nhighlight_changes=1\nhighlight_changes_delay_secs=5\nfind_comm_in_cmdline=0\nstrip_exe_from_cmdline=0\nshow_merged_command=0\nheader_margin=0\nscreen_tabs=1\ndetailed_cpu_time=0\ncpu_count_from_one=1\nshow_cpu_usage=1\nshow_cpu_frequency=0\nshow_cpu_temperature=0\ndegree_fahrenheit=0\nupdate_process_names=0\naccount_guest_in_cpu_meter=0\ncolor_scheme=0\nenable_mouse=1\ndelay=50\nhide_function_bar=2\nheader_layout=two_67_33\ncolumn_meters_0=AllCPUs4\ncolumn_meter_modes_0=1\ncolumn_meters_1=Memory Swap Tasks DiskIO NetworkIO\ncolumn_meter_modes_1=1 1 2 2 2\ntree_view=0\nsort_key=46\ntree_sort_key=0\nsort_direction=-1\ntree_sort_direction=1\ntree_view_always_by_pid=0\nall_branches_collapsed=0\nscreen:Main=USER M_RESIDENT PERCENT_CPU Command\n.sort_key=PERCENT_CPU\n.tree_sort_key=PID\n.tree_view_always_by_pid=0\n.tree_view=0\n.sort_direction=-1\n.tree_sort_direction=1\n.all_branches_collapsed=0\nscreen:More=PID USER STATE ELAPSED UTIME STIME NICE IO_PRIORITY M_RESIDENT M_SHARE IO_RATE IO_READ_RATE IO_WRITE_RATE Command\n.sort_key=IO_RATE\n.tree_sort_key=PID\n.tree_view_always_by_pid=0\n.tree_view=0\n.sort_direction=-1\n.tree_sort_direction=1\n.all_branches_collapsed=0\n"
  },
  {
    "path": "config/hypr/hypridle.conf",
    "content": "general {\n  lock_cmd = pidof hyprlock || hyprlock\n}\n\n# Lock the screen after inactivity\nlistener {\n  timeout = 600  # 10 minutes\n  on-timeout = pidof hyprlock || loginctl lock-session\n}\n\n# Turn off monitor faster when it's locked\nlistener {\n  timeout = 15\n  on-timeout = pidof hyprlock && niri msg action power-off-monitors\n}\n\n"
  },
  {
    "path": "config/hypr/hyprland.conf",
    "content": "monitor=eDP-1,preferred,auto,auto\n\necosystem {\n  no_update_news = true\n  no_donation_nag = true\n}\n\nmisc {\n  vrr = 1\n  vfr = true\n\n  enable_swallow = true\n  swallow_regex = ^(footclient)$\n\n  disable_hyprland_logo = true\n  disable_splash_rendering = true\n  force_default_wallpaper = 0\n  disable_autoreload = true\n  background_color = rgb(000000)\n\n  mouse_move_enables_dpms = false\n  key_press_enables_dpms = true\n  focus_on_activate = false\n\n  # Discard fullscreen on new window\n  new_window_takes_over_fullscreen = 2\n\n  # Keep special workspace open after closing last window\n  close_special_on_empty = false\n\n  # I often missclick middle button on my touchpad\n  middle_click_paste = false\n}\n\nxwayland {\n  # Disable scaling for xwayland applications\n  force_zero_scaling = true\n}\n\ndebug {\n  # Disable watchdog\n  watchdog_timeout = 0\n}\n\ngroup {\n  groupbar {\n    enabled = true\n\n    gradients = false\n    render_titles = false\n    height = 2\n\n    col.active = rgba(${bg}A0)\n    col.inactive = rgba(${fg_dim}70)\n  }\n}\n\n# Startup\nexec-once = swaybg --image ${repo}/wallpaper.png --mode fill\nexec-once = waybar\nexec-once = hypridle\nexec-once = foot --server --log-level=none\nexec-once = hyprctl setcursor capitaine-cursors-light 32\n\n# Environment variables\n\nenv = XCURSOR_THEME, capitaine-cursors-light\nenv = XCURSOR_SIZE, 32\nenv = GDK_SCALE, 2\nenv = QT_WAYLAND_DISABLE_WINDOWDECORATION, 1\n\n# Hotkeys: windows\nbind = SUPER, W, movefocus, u\nbind = SUPER, A, movefocus, l\nbind = SUPER, S, movefocus, d\nbind = SUPER, D, movefocus, r\n\nbind = SUPER SHIFT, W, movewindow, u\nbind = SUPER SHIFT, A, movewindow, l\nbind = SUPER SHIFT, S, movewindow, d\nbind = SUPER SHIFT, D, movewindow, r\n\nbind = SUPER, V, togglefloating,\nbind = SUPER, P, pseudo,\nbind = SUPER SHIFT, P, pin,\nbind = SUPER, T, togglesplit,\nbind = SUPER, U, focusurgentorlast,\nbind = SUPER, Q, killactive,\n\n# Hide waybar\nbind = SUPER, M, exec, killall -SIGUSR1 waybar\n\n# Hotkeys: groups\nbind = SUPER, G, togglegroup,\nbind = SUPER SHIFT, G, moveoutofgroup\n\nbind = SUPER, X, changegroupactive, f\nbind = SUPER SHIFT, X, changegroupactive, b\n\n# Hotkeys: fullscreen\nbind = SUPER, F, fullscreen,\nbind = SUPER ALT, F, fullscreenstate, 1  # maximize with gaps\nbind = SUPER SHIFT, F, fullscreenstate, 2  # maximize without gaps\n\n# Hotkeys: workspaces\nbind = SUPER, 1, workspace, 1\nbind = SUPER, 2, workspace, 2\nbind = SUPER, 3, workspace, 3\nbind = SUPER, 4, workspace, 4\nbind = SUPER, 5, workspace, 5\nbind = SUPER, 6, workspace, 6\nbind = SUPER, 7, workspace, 7\nbind = SUPER, 8, workspace, 8\nbind = SUPER, 9, workspace, 9\nbind = SUPER, 0, workspace, 10\n\nbind = SUPER SHIFT, 1, movetoworkspace, 1\nbind = SUPER SHIFT, 2, movetoworkspace, 2\nbind = SUPER SHIFT, 3, movetoworkspace, 3\nbind = SUPER SHIFT, 4, movetoworkspace, 4\nbind = SUPER SHIFT, 5, movetoworkspace, 5\nbind = SUPER SHIFT, 6, movetoworkspace, 6\nbind = SUPER SHIFT, 7, movetoworkspace, 7\nbind = SUPER SHIFT, 8, movetoworkspace, 8\nbind = SUPER SHIFT, 9, movetoworkspace, 9\nbind = SUPER SHIFT, 0, movetoworkspace, 10\n\n# Hotkeys: scratchpads\nbind = SUPER, TAB, togglespecialworkspace, magicTab\nbind = SUPER, E, togglespecialworkspace, magicE\nbind = SUPER, C, togglespecialworkspace, magicC\n\nbind = SUPER SHIFT, TAB, movetoworkspacesilent, special:magicTab\nbind = SUPER SHIFT, E, movetoworkspacesilent, special:magicE\nbind = SUPER SHIFT, C, movetoworkspacesilent, special:magicC\n\n# Hotkeys: applications\nbind = SUPER, R, exec, wofi\nbind = SUPER, J, exec, footclient\nbind = SUPER SHIFT, B, exec, google-chrome-unstable\nbind = SUPER, B, exec, google-chrome-unstable --new-window 'https://www.google.com'\n\nbind = SUPER ALT, E, exec, wofi-emoji\nbind = SUPER ALT, C, exec, wl-color-picker\n\n# Hotkeys: hyprland\nbind = SUPER ALT, R, exec, hyprctl reload\nbind = SUPER ALT, X, exec, pkill Hyprland\nbind = SUPER, N, exec, makoctl dismiss --all\n\n# Hotkeys: zoom\nbind = SUPER, Z, exec, hyprctl keyword cursor:zoom_factor 4\nbind = SUPER SHIFT, Z, exec, hyprctl keyword cursor:zoom_factor 1\n\n# Hotkeys: media\nbindl = , XF86AudioMute, exec, wpctl set-mute @DEFAULT_SINK@ toggle\nbindle = , XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_SINK@ 5%-\nbindle = , XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_SINK@ 5%+\nbindl = , XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_SOURCE@ toggle\n\nbindl = , XF86MonBrightnessDown, exec, brightnessctl -e set 5%-\nbindl = , XF86MonBrightnessUp, exec, brightnessctl -e set 5%+\n\nbindl = , Print, exec, slurp -b ${fg_dim}20 -c ${fg_dim}30 -w 1 | grim -g - - | wl-copy\nbind = SHIFT, Print, exec, slurp -b ${fg_dim}20 -c ${fg_dim}30 -w 1 | grim -g - - | satty --filename=- --init-tool=rectangle\nbind = ALT, Print, exec, grim - | satty --filename=- --init-tool=rectangle\n\n# Mouse bindings\nbindm = SUPER, mouse:272, movewindow  # Left button\nbindm = SUPER, mouse:273, resizewindow  # Right button\n\n# Locking / DPMS\nbind = SUPER, L, exec, hyprlock\nbindlr = SUPER SHIFT, L, exec, systemctl suspend\nbindlr = SUPER, K, exec, sleep 0.5; hyprctl dispatch dpms off\n\n# HACK: looks like my laptop sends wrong events on lid off / on\nbindl = , switch:off:Lid Switch, dpms, on\nbindl = , switch:on:Lid Switch, dpms, off\n\n# OBS\nbind = , F1, pass, class:^(com\\.obsproject\\.Studio)$\nbind = , F2, pass, class:^(com\\.obsproject\\.Studio)$\n\ninput {\n  kb_layout = us,ru\n  kb_variant =\n  kb_model =\n  kb_options = grp:caps_toggle,grp_led:caps,compose:ralt\n  kb_rules =\n\n  repeat_rate = 15\n  # 200 is too low for typing, cause in some cases\n  # I just get repeated letters for no reason\n  repeat_delay = 300\n\n  follow_mouse = 1\n\n  # Allow to use windows under special workspace\n  special_fallthrough = true\n\n  # Makes me use keyboard\n  sensitivity = 0.25\n\n  touchpad {\n    natural_scroll = true\n    scroll_factor = 0.15\n  }\n}\n\ndwindle {\n  pseudotile = true\n  preserve_split = true  # allow to manually select split direction\n  force_split = 2  # always split to right or bottom\n}\n\nanimations {\n  enabled = true\n  first_launch_animation = false\n\n  bezier=overshot,0.5,0.1,0.4,1.2\n\n  animation = global, 1, 3, default\n  animation = workspaces, 1, 4, default\n  animation = windowsMove, 1, 2, default\n  animation = fade, 1, 2, default\n}\n\n# Allow sliding animation for notifications\nlayerrule = animation slide, notifications\n\ngeneral {\n    gaps_in = 12\n    gaps_out = 24\n    border_size = 0\n\n    layout = dwindle\n    allow_tearing = false\n\n}\n\ndecoration {\n  rounding = 24\n\n  blur {\n    enabled = false\n  }\n\n  shadow {\n    enabled = true\n    range = 16\n    render_power = 3\n    offset = 2 2\n    color = rgba(${bg_dim}A0)\n    color_inactive = rgba(${bg_dim}70)\n  }\n\n  dim_special = 0.35\n}\n\ngestures {\n  workspace_swipe = false\n}\n"
  },
  {
    "path": "config/hypr/hyprlock.conf",
    "content": "general {\n  disable_loading_bar = false\n  hide_cursor = true\n  ignore_empty_input = true\n}\n\nbackground {\n  path = ${repo}/wallpaper.png\n}\n\ninput-field {\n  size = 500, 75\n  position = 0, 0\n\n  fade_on_empty = true\n  dots_size = 0.2\n  dots_spacing = 0.5\n  outline_thickness = 3\n  placeholder_text =\n  fail_text =\n\n  outer_color = rgb(${bg})\n  inner_color = rgb(${bg})\n  font_color = rgb(${fg})\n  check_color = rgb(${blue})\n  fail_color = rgb(${red})\n  capslock_color = rgb(${orange})\n\n  shadow_passes = 1\n  shadow_size = 8\n  shadow_boost = 0.6\n}\n\nlabel {\n  text = cmd[update:60000] TZ=Asia/Bangkok date \"+%H:%M\"\n  position = 150, 250\n\n  color = rgba(${blue}90)\n\n  font_size = 120\n  font_family = Noto Sans Mono Thin\n\n  shadow_passes = 1\n  shadow_size = 6\n  shadow_boost = 0.75\n}\n\nlabel {\n  text = cmd[update:60000] TZ=Asia/Bangkok TZ=Asia/Bangkok date \"+%e %B, %A\"\n  position = 150, 150\n\n  color = rgba(${blue}70)\n\n  font_size = 40\n  font_family = Noto Sans Mono Light\n\n  shadow_passes = 1\n  shadow_size = 4\n  shadow_boost = 0.9\n}\n"
  },
  {
    "path": "config/ipython/ipython_config.py",
    "content": "# No banner\nc.TerminalIPythonApp.display_banner = False\n\n# No exception tracebacks\nc.InteractiveShell.xmode = \"minimal\"\n\n# Do not confirm on exit\nc.TerminalInteractiveShell.confirm_exit = False\n\n# Useful DS/ML libraries\nc.InteractiveShellApp.exec_lines = [\n    \"import matplotlib.pyplot as plt\",\n    \"import numpy as np\",\n    \"import pandas as pd\",\n    \"import scipy as scp\",\n    \"from pylab import plot\",\n    \"%matplotlib\",\n    \"%load_ext autoreload\",\n    \"%autoreload 2\",\n]\n"
  },
  {
    "path": "config/ledger/ledgerrc",
    "content": "--file ~/.ledger/journal.ldg\n--no-pager\n"
  },
  {
    "path": "config/less/lesskey",
    "content": "#command\nw back-line\nW back-screen\n\ns forw-line\nS forw-screen\n\na left-scroll\nd right-scroll\n"
  },
  {
    "path": "config/mako/config",
    "content": "font=Noto Sans Mono Light 11\n\nmax-history=0\nignore-timeout=1\nmax-visible=-1\n\nwidth=450\nheight=200\nanchor=top-right\nouter-margin=0\nmargin=12\npadding=24\nformat=%s\\n%b\n\nbackground-color=#${bg}\ntext-color=#${fg}\n\nborder-radius=16\nborder-size=0\n"
  },
  {
    "path": "config/matplotlib/matplotlibrc",
    "content": "#### MATPLOTLIBRC FORMAT\n\n## NOTE FOR END USERS: DO NOT EDIT THIS FILE!\n##\n## This is a sample Matplotlib configuration file - you can find a copy\n## of it on your system in site-packages/matplotlib/mpl-data/matplotlibrc\n## (relative to your Python installation location).\n##\n## You should find a copy of it on your system at\n## site-packages/matplotlib/mpl-data/matplotlibrc (relative to your Python\n## installation location).  DO NOT EDIT IT!\n##\n## If you wish to change your default style, copy this file to one of the\n## following locations:\n##     Unix/Linux:\n##         $HOME/.config/matplotlib/matplotlibrc OR\n##         $XDG_CONFIG_HOME/matplotlib/matplotlibrc (if $XDG_CONFIG_HOME is set)\n##     Other platforms:\n##         $HOME/.matplotlib/matplotlibrc\n## and edit that copy.\n##\n## See https://matplotlib.org/users/customizing.html#the-matplotlibrc-file\n## for more details on the paths which are checked for the configuration file.\n##\n## Blank lines, or lines starting with a comment symbol, are ignored, as are\n## trailing comments.  Other lines must have the format:\n##     key: val  # optional comment\n##\n## Formatting: Use PEP8-like style (as enforced in the rest of the codebase).\n## All lines start with an additional '#', so that removing all leading '#'s\n## yields a valid style file.\n##\n## Colors: for the color values below, you can either use\n##     - a Matplotlib color string, such as r, k, or b\n##     - an RGB tuple, such as (1.0, 0.5, 0.0)\n##     - a hex string, such as ff00ff\n##     - a scalar grayscale intensity such as 0.75\n##     - a legal html color name, e.g., red, blue, darkslategray\n##\n## Matplotlib configuration are currently divided into following parts:\n##     - BACKENDS\n##     - LINES\n##     - PATCHES\n##     - HATCHES\n##     - BOXPLOT\n##     - FONT\n##     - TEXT\n##     - LaTeX\n##     - AXES\n##     - DATES\n##     - TICKS\n##     - GRIDS\n##     - LEGEND\n##     - FIGURE\n##     - IMAGES\n##     - CONTOUR PLOTS\n##     - ERRORBAR PLOTS\n##     - HISTOGRAM PLOTS\n##     - SCATTER PLOTS\n##     - AGG RENDERING\n##     - PATHS\n##     - SAVING FIGURES\n##     - INTERACTIVE KEYMAPS\n##     - ANIMATION\n\n##### CONFIGURATION BEGINS HERE\n\n\n## ***************************************************************************\n## * BACKENDS                                                                *\n## ***************************************************************************\n## The default backend.  If you omit this parameter, the first working\n## backend from the following list is used:\n##     MacOSX Qt5Agg Gtk3Agg TkAgg WxAgg Agg\n## Other choices include:\n##     Qt5Cairo GTK3Cairo TkCairo WxCairo Cairo\n##     Qt4Agg Qt4Cairo Wx  # deprecated.\n##     PS PDF SVG Template\n## You can also deploy your own backend outside of Matplotlib by referring to\n## the module name (which must be in the PYTHONPATH) as 'module://my_backend'.\n#backend: Agg\n\n## The port to use for the web server in the WebAgg backend.\n#webagg.port: 8988\n\n## The address on which the WebAgg web server should be reachable\n#webagg.address: 127.0.0.1\n\n## If webagg.port is unavailable, a number of other random ports will\n## be tried until one that is available is found.\n#webagg.port_retries: 50\n\n## When True, open the web browser to the plot that is shown\n#webagg.open_in_browser: True\n\n## If you are running pyplot inside a GUI and your backend choice\n## conflicts, we will automatically try to find a compatible one for\n## you if backend_fallback is True\n#backend_fallback: True\n\n#interactive: False\n#toolbar:     toolbar2  # {None, toolbar2, toolmanager}\n#timezone:    UTC       # a pytz timezone string, e.g., US/Central or Europe/Paris\n\n\n## ***************************************************************************\n## * LINES                                                                   *\n## ***************************************************************************\n## See https://matplotlib.org/api/artist_api.html#module-matplotlib.lines\n## for more information on line properties.\n#lines.linewidth: 1.5               # line width in points\n#lines.linestyle: -                 # solid line\n#lines.color:     C0                # has no affect on plot(); see axes.prop_cycle\n#lines.marker:          None        # the default marker\n#lines.markerfacecolor: auto        # the default marker face color\n#lines.markeredgecolor: auto        # the default marker edge color\n#lines.markeredgewidth: 1.0         # the line width around the marker symbol\n#lines.markersize:      6           # marker size, in points\n#lines.dash_joinstyle:  round       # {miter, round, bevel}\n#lines.dash_capstyle:   butt        # {butt, round, projecting}\n#lines.solid_joinstyle: round       # {miter, round, bevel}\n#lines.solid_capstyle:  projecting  # {butt, round, projecting}\n#lines.antialiased: True            # render lines in antialiased (no jaggies)\n\n## The three standard dash patterns.  These are scaled by the linewidth.\n#lines.dashed_pattern: 3.7, 1.6\n#lines.dashdot_pattern: 6.4, 1.6, 1, 1.6\n#lines.dotted_pattern: 1, 1.65\n#lines.scale_dashes: True\n\n#markers.fillstyle: full  # {full, left, right, bottom, top, none}\n\n#pcolor.shading : flat\n#pcolormesh.snap : True  # Whether to snap the mesh to pixel boundaries. This\n                         # is provided solely to allow old test images to remain\n                         # unchanged. Set to False to obtain the previous behavior.\n\n## ***************************************************************************\n## * PATCHES                                                                 *\n## ***************************************************************************\n## Patches are graphical objects that fill 2D space, like polygons or circles.\n## See https://matplotlib.org/api/artist_api.html#module-matplotlib.patches\n## for more information on patch properties.\n#patch.linewidth:       1      # edge width in points.\n#patch.facecolor:       C0\n#patch.edgecolor:       black  # if forced, or patch is not filled\n#patch.force_edgecolor: False  # True to always use edgecolor\n#patch.antialiased:     True   # render patches in antialiased (no jaggies)\n\n\n## ***************************************************************************\n## * HATCHES                                                                 *\n## ***************************************************************************\n#hatch.color:     black\n#hatch.linewidth: 1.0\n\n\n## ***************************************************************************\n## * BOXPLOT                                                                 *\n## ***************************************************************************\n#boxplot.notch:       False\n#boxplot.vertical:    True\n#boxplot.whiskers:    1.5\n#boxplot.bootstrap:   None\n#boxplot.patchartist: False\n#boxplot.showmeans:   False\n#boxplot.showcaps:    True\n#boxplot.showbox:     True\n#boxplot.showfliers:  True\n#boxplot.meanline:    False\n\nboxplot.flierprops.color:            white\n#boxplot.flierprops.marker:          o\n#boxplot.flierprops.markerfacecolor: none\nboxplot.flierprops.markeredgecolor:  817c9c \n#boxplot.flierprops.markeredgewidth: 1.0\n#boxplot.flierprops.markersize:      6\n#boxplot.flierprops.linestyle:       none\n#boxplot.flierprops.linewidth:       1.0\n\nboxplot.boxprops.color:      817c9c\n#boxplot.boxprops.linewidth: 1.0\n#boxplot.boxprops.linestyle: -\n\nboxplot.whiskerprops.color:     817c9c\n#boxplot.whiskerprops.linewidth: 1.0\n#boxplot.whiskerprops.linestyle: -\n\nboxplot.capprops.color:      817c9c\n#boxplot.capprops.linewidth: 1.0\n#boxplot.capprops.linestyle: -\n\nboxplot.medianprops.color:      393552\n#boxplot.medianprops.linewidth: 1.0\n#boxplot.medianprops.linestyle: -\n\n#boxplot.meanprops.color:           C2\n#boxplot.meanprops.marker:          ^\n#boxplot.meanprops.markerfacecolor: C2\n#boxplot.meanprops.markeredgecolor: C2\n#boxplot.meanprops.markersize:       6\n#boxplot.meanprops.linestyle:       --\n#boxplot.meanprops.linewidth:       1.0\n\n\n## ***************************************************************************\n## * FONT                                                                    *\n## ***************************************************************************\n## The font properties used by `text.Text`.\n## See https://matplotlib.org/api/font_manager_api.html for more information\n## on font properties.  The 6 font properties used for font matching are\n## given below with their default values.\n##\n## The font.family property can take either a concrete font name (not supported\n## when rendering text with usetex), or one of the following five generic\n## values:\n##     - 'serif' (e.g., Times),\n##     - 'sans-serif' (e.g., Helvetica),\n##     - 'cursive' (e.g., Zapf-Chancery),\n##     - 'fantasy' (e.g., Western), and\n##     - 'monospace' (e.g., Courier).\n## Each of these values has a corresponding default list of font names\n## (font.serif, etc.); the first available font in the list is used.  Note that\n## for font.serif, font.sans-serif, and font.monospace, the first element of\n## the list (a DejaVu font) will always be used because DejaVu is shipped with\n## Matplotlib and is thus guaranteed to be available; the other entries are\n## left as examples of other possible values.\n##\n## The font.style property has three values: normal (or roman), italic\n## or oblique.  The oblique style will be used for italic, if it is not\n## present.\n##\n## The font.variant property has two values: normal or small-caps.  For\n## TrueType fonts, which are scalable fonts, small-caps is equivalent\n## to using a font size of 'smaller', or about 83%% of the current font\n## size.\n##\n## The font.weight property has effectively 13 values: normal, bold,\n## bolder, lighter, 100, 200, 300, ..., 900.  Normal is the same as\n## 400, and bold is 700.  bolder and lighter are relative values with\n## respect to the current weight.\n##\n## The font.stretch property has 11 values: ultra-condensed,\n## extra-condensed, condensed, semi-condensed, normal, semi-expanded,\n## expanded, extra-expanded, ultra-expanded, wider, and narrower.  This\n## property is not currently implemented.\n##\n## The font.size property is the default font size for text, given in points.\n## 10 pt is the standard value.\n##\n## Note that font.size controls default text sizes.  To configure\n## special text sizes tick labels, axes, labels, title, etc., see the rc\n## settings for axes and ticks.  Special text sizes can be defined\n## relative to font.size, using the following values: xx-small, x-small,\n## small, medium, large, x-large, xx-large, larger, or smaller\n\n#font.family:  sans-serif\n#font.style:   normal\n#font.variant: normal\n#font.weight:  normal\n#font.stretch: normal\nfont.size:    18.0\n\nfont.serif:      Source Code Pro, DejaVu Serif, Bitstream Vera Serif, Computer Modern Roman, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif\nfont.sans-serif: Source Code Pro, DejaVu Sans, Bitstream Vera Sans, Computer Modern Sans Serif, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif\nfont.cursive:    Source Code Pro, Apple Chancery, Textile, Zapf Chancery, Sand, Script MT, Felipa, Comic Neue, Comic Sans MS, cursive\nfont.fantasy:    Source Code Pro, Chicago, Charcoal, Impact, Western, Humor Sans, xkcd, fantasy\nfont.monospace:  Source Code Pro, DejaVu Sans Mono, Bitstream Vera Sans Mono, Computer Modern Typewriter, Andale Mono, Nimbus Mono L, Courier New, Courier, Fixed, Terminal, monospace\n\n\n## ***************************************************************************\n## * TEXT                                                                    *\n## ***************************************************************************\n## The text properties used by `text.Text`.\n## See https://matplotlib.org/api/artist_api.html#module-matplotlib.text\n## for more information on text properties\ntext.color: e0def4\n\n\n## ***************************************************************************\n## * LaTeX                                                                   *\n## ***************************************************************************\n## For more information on LaTeX properties, see\n## https://matplotlib.org/tutorials/text/usetex.html\n#text.usetex: False  # use latex for all text handling. The following fonts\n                     # are supported through the usual rc parameter settings:\n                     # new century schoolbook, bookman, times, palatino,\n                     # zapf chancery, charter, serif, sans-serif, helvetica,\n                     # avant garde, courier, monospace, computer modern roman,\n                     # computer modern sans serif, computer modern typewriter\n                     # If another font is desired which can loaded using the\n                     # LaTeX \\usepackage command, please inquire at the\n                     # Matplotlib mailing list\n#text.latex.preamble:   # IMPROPER USE OF THIS FEATURE WILL LEAD TO LATEX FAILURES\n                        # AND IS THEREFORE UNSUPPORTED. PLEASE DO NOT ASK FOR HELP\n                        # IF THIS FEATURE DOES NOT DO WHAT YOU EXPECT IT TO.\n                        # text.latex.preamble is a single line of LaTeX code that\n                        # will be passed on to the LaTeX system. It may contain\n                        # any code that is valid for the LaTeX \"preamble\", i.e.\n                        # between the \"\\documentclass\" and \"\\begin{document}\"\n                        # statements.\n                        # Note that it has to be put on a single line, which may\n                        # become quite long.\n                        # The following packages are always loaded with usetex, so\n                        # beware of package collisions: color, geometry, graphicx,\n                        # type1cm, textcomp.\n                        # Adobe Postscript (PSSNFS) font packages may also be\n                        # loaded, depending on your font settings.\n\n## FreeType hinting flag (\"foo\" corresponds to FT_LOAD_FOO); may be one of the\n## following (Proprietary Matplotlib-specific synonyms are given in parentheses,\n## but their use is discouraged):\n## - default: Use the font's native hinter if possible, else FreeType's auto-hinter.\n##            (\"either\" is a synonym).\n## - no_autohint: Use the font's native hinter if possible, else don't hint.\n##                (\"native\" is a synonym.)\n## - force_autohint: Use FreeType's auto-hinter.  (\"auto\" is a synonym.)\n## - no_hinting: Disable hinting.  (\"none\" is a synonym.)\n#text.hinting: force_autohint\n\n#text.hinting_factor: 8  # Specifies the amount of softness for hinting in the\n                         # horizontal direction.  A value of 1 will hint to full\n                         # pixels.  A value of 2 will hint to half pixels etc.\n#text.kerning_factor : 0  # Specifies the scaling factor for kerning values. This\n                          # is provided solely to allow old test images to remain\n                          # unchanged. Set to 6 to obtain previous behavior. Values\n                          # other than 0 or 6 have no defined meaning.\n#text.antialiased: True  # If True (default), the text will be antialiased.\n                         # This only affects raster outputs.\n\n## The following settings allow you to select the fonts in math mode.\n#mathtext.fontset: dejavusans  # Should be 'dejavusans' (default),\n                               # 'dejavuserif', 'cm' (Computer Modern), 'stix',\n                               # 'stixsans' or 'custom' (unsupported, may go\n                               # away in the future)\n## \"mathtext.fontset: custom\" is defined by the mathtext.bf, .cal, .it, ...\n## settings which map a TeX font name to a fontconfig font pattern.  (These\n## settings are not used for other font sets.)\n#mathtext.bf:  sans:bold\n#mathtext.cal: cursive\n#mathtext.it:  sans:italic\n#mathtext.rm:  sans\n#mathtext.sf:  sans\n#mathtext.tt:  monospace\n#mathtext.fallback: cm  # Select fallback font from ['cm' (Computer Modern), 'stix'\n                        # 'stixsans'] when a symbol can not be found in one of the\n                        # custom math fonts. Select 'None' to not perform fallback\n                        # and replace the missing character by a dummy symbol.\n#mathtext.default: it  # The default font to use for math.\n                       # Can be any of the LaTeX font names, including\n                       # the special name \"regular\" for the same font\n                       # used in regular text.\n\n\n## ***************************************************************************\n## * AXES                                                                    *\n## ***************************************************************************\n## Following are default face and edge colors, default tick sizes,\n## default font sizes for tick labels, and so on.  See\n## https://matplotlib.org/api/axes_api.html#module-matplotlib.axes\naxes.facecolor:      232136  # axes background color\naxes.edgecolor:      59546d  # axes edge color\n#axes.linewidth:     0.8     # edge line width\naxes.grid:           True    # display grid or not\naxes.grid.axis:      y       # which axis the grid should apply to\n#axes.grid.which:    major   # grid lines at {major, minor, both} ticks\n#axes.titlelocation: center  # alignment of the title: {left, right, center}\n#axes.titlesize:     large   # font size of the axes title\n#axes.titleweight:   normal  # font weight of title\n#axes.titlecolor:    auto    # color of the axes title, auto falls back to\n                             # text.color as default value\n#axes.titley:        None    # position title (axes relative units).  None implies auto\n#axes.titlepad:      6.0     # pad between axes and title in points\n#axes.labelsize:     medium  # font size of the x and y labels\n#axes.labelpad:      4.0     # space between label and axis\n#axes.labelweight:   normal  # weight of the x and y labels\naxes.labelcolor:     817c9c\naxes.axisbelow:      True    # draw axis gridlines and ticks:\n                             #     - below patches (True)\n                             #     - above patches but below lines ('line')\n                             #     - above all (False)\n\n#axes.formatter.limits: -5, 6  # use scientific notation if log10\n                               # of the axis range is smaller than the\n                               # first or larger than the second\n#axes.formatter.use_locale: False  # When True, format tick labels\n                                   # according to the user's locale.\n                                   # For example, use ',' as a decimal\n                                   # separator in the fr_FR locale.\n#axes.formatter.use_mathtext: False  # When True, use mathtext for scientific\n                                     # notation.\n#axes.formatter.min_exponent: 0  # minimum exponent to format in scientific notation\n#axes.formatter.useoffset: True  # If True, the tick label formatter\n                                 # will default to labeling ticks relative\n                                 # to an offset when the data range is\n                                 # small compared to the minimum absolute\n                                 # value of the data.\n#axes.formatter.offset_threshold: 4  # When useoffset is True, the offset\n                                     # will be used when it can remove\n                                     # at least this number of significant\n                                     # digits from tick labels.\n\naxes.spines.left:   True  # display axis spines\naxes.spines.bottom: True\naxes.spines.top:    False \naxes.spines.right:  False\n\n#axes.unicode_minus: True  # use Unicode for the minus symbol rather than hyphen.  See\n                           # https://en.wikipedia.org/wiki/Plus_and_minus_signs#Character_codes\naxes.prop_cycle: cycler('color', ['eb6f92', 'f6c177', 'ea9a97', '3e8fb0', '9ccfd8', 'c4a7e7'])\n                  # color cycle for plot lines as list of string color specs:\n                  # single letter, long name, or web-style hex\n                  # As opposed to all other parameters in this file, the color\n                  # values must be enclosed in quotes for this parameter,\n                  # e.g. '1f77b4', instead of 1f77b4.\n                  # See also https://matplotlib.org/tutorials/intermediate/color_cycle.html\n                  # for more details on prop_cycle usage.\n#axes.xmargin:   .05  # x margin.  See `axes.Axes.margins`\n#axes.ymargin:   .05  # y margin.  See `axes.Axes.margins`\n#axes.zmargin:   .05  # z margin.  See `axes.Axes.margins`\n#axes.autolimit_mode: data  # If \"data\", use axes.xmargin and axes.ymargin as is.\n                            # If \"round_numbers\", after application of margins, axis\n                            # limits are further expanded to the nearest \"round\" number.\n#polaraxes.grid: True  # display grid on polar axes\n#axes3d.grid:    True  # display grid on 3D axes\n\n\n## ***************************************************************************\n## * AXIS                                                                    *\n## ***************************************************************************\n#xaxis.labellocation: center  # alignment of the xaxis label: {left, right, center}\n#yaxis.labellocation: center  # alignment of the yaxis label: {bottom, top, center}\n\n\n## ***************************************************************************\n## * DATES                                                                   *\n## ***************************************************************************\n## These control the default format strings used in AutoDateFormatter.\n## Any valid format datetime format string can be used (see the python\n## `datetime` for details).  For example, by using:\n##     - '%%x' will use the locale date representation\n##     - '%%X' will use the locale time representation\n##     - '%%c' will use the full locale datetime representation\n## These values map to the scales:\n##     {'year': 365, 'month': 30, 'day': 1, 'hour': 1/24, 'minute': 1 / (24 * 60)}\n\n#date.autoformatter.year:        %Y\n#date.autoformatter.month:       %Y-%m\n#date.autoformatter.day:         %Y-%m-%d\n#date.autoformatter.hour:        %m-%d %H\n#date.autoformatter.minute:      %d %H:%M\n#date.autoformatter.second:      %H:%M:%S\n#date.autoformatter.microsecond: %M:%S.%f\n## The reference date for Matplotlib's internal date representation\n## See https://matplotlib.org/examples/ticks_and_spines/date_precision_and_epochs.py\n#date.epoch: 1970-01-01T00:00:00\n## 'auto', 'concise':\n#date.converter:                  auto\n## For auto converter whether to use interval_multiples:\n#date.interval_multiples:         True\n\n## ***************************************************************************\n## * TICKS                                                                   *\n## ***************************************************************************\n## See https://matplotlib.org/api/axis_api.html#matplotlib.axis.Tick\n#xtick.top:           False   # draw ticks on the top side\n#xtick.bottom:        True    # draw ticks on the bottom side\n#xtick.labeltop:      False   # draw label on the top\n#xtick.labelbottom:   True    # draw label on the bottom\n#xtick.major.size:    3.5     # major tick size in points\n#xtick.minor.size:    2       # minor tick size in points\n#xtick.major.width:   0.8     # major tick width in points\n#xtick.minor.width:   0.6     # minor tick width in points\n#xtick.major.pad:     3.5     # distance to major tick label in points\n#xtick.minor.pad:     3.4     # distance to the minor tick label in points\nxtick.color:          817c9c  # color of the ticks\n#xtick.labelcolor:    inherit # color of the tick labels or inherit from xtick.color\n#xtick.labelsize:     medium  # font size of the tick labels\n#xtick.direction:     out     # direction: {in, out, inout}\n#xtick.minor.visible: False   # visibility of minor ticks on x-axis\n#xtick.major.top:     True    # draw x axis top major ticks\n#xtick.major.bottom:  True    # draw x axis bottom major ticks\n#xtick.minor.top:     True    # draw x axis top minor ticks\n#xtick.minor.bottom:  True    # draw x axis bottom minor ticks\n#xtick.alignment:     center  # alignment of xticks\n\n#ytick.left:          True    # draw ticks on the left side\n#ytick.right:         False   # draw ticks on the right side\n#ytick.labelleft:     True    # draw tick labels on the left side\n#ytick.labelright:    False   # draw tick labels on the right side\n#ytick.major.size:    3.5     # major tick size in points\n#ytick.minor.size:    2       # minor tick size in points\n#ytick.major.width:   0.8     # major tick width in points\n#ytick.minor.width:   0.6     # minor tick width in points\n#ytick.major.pad:     3.5     # distance to major tick label in points\n#ytick.minor.pad:     3.4     # distance to the minor tick label in points\nytick.color:          817c9c  # color of the ticks\n#ytick.labelcolor:    inherit # color of the tick labels or inherit from ytick.color\n#ytick.labelsize:     medium  # font size of the tick labels\n#ytick.direction:     out     # direction: {in, out, inout}\n#ytick.minor.visible: False   # visibility of minor ticks on y-axis\n#ytick.major.left:    True    # draw y axis left major ticks\n#ytick.major.right:   True    # draw y axis right major ticks\n#ytick.minor.left:    True    # draw y axis left minor ticks\n#ytick.minor.right:   True    # draw y axis right minor ticks\n#ytick.alignment:     center_baseline  # alignment of yticks\n\n\n## ***************************************************************************\n## * GRIDS                                                                   *\n## ***************************************************************************\ngrid.color:      393552  # grid color\n#grid.linestyle: -       # solid\n#grid.linewidth: 0.8     # in points\n#grid.alpha:     1.0     # transparency, between 0.0 and 1.0\n\n\n## ***************************************************************************\n## * LEGEND                                                                  *\n## ***************************************************************************\n#legend.loc:           best\n#legend.frameon:       True     # if True, draw the legend on a background patch\n#legend.framealpha:    0.8      # legend patch transparency\n#legend.facecolor:     inherit  # inherit from axes.facecolor; or color spec\n#legend.edgecolor:     0.8      # background patch boundary color\n#legend.fancybox:      True     # if True, use a rounded box for the\n                                # legend background, else a rectangle\n#legend.shadow:        False    # if True, give background a shadow effect\n#legend.numpoints:     1        # the number of marker points in the legend line\n#legend.scatterpoints: 1        # number of scatter points\n#legend.markerscale:   1.0      # the relative size of legend markers vs. original\n#legend.fontsize:      medium\n#legend.title_fontsize: None    # None sets to the same as the default axes.\n\n## Dimensions as fraction of font size:\n#legend.borderpad:     0.4  # border whitespace\n#legend.labelspacing:  0.5  # the vertical space between the legend entries\n#legend.handlelength:  2.0  # the length of the legend lines\n#legend.handleheight:  0.7  # the height of the legend handle\n#legend.handletextpad: 0.8  # the space between the legend line and legend text\n#legend.borderaxespad: 0.5  # the border between the axes and legend edge\n#legend.columnspacing: 2.0  # column separation\n\n\n## ***************************************************************************\n## * FIGURE                                                                  *\n## ***************************************************************************\n## See https://matplotlib.org/api/figure_api.html#matplotlib.figure.Figure\n#figure.titlesize:   large     # size of the figure title (``Figure.suptitle()``)\n#figure.titleweight: normal    # weight of the figure title\n#figure.figsize:     6.4, 4.8  # figure size in inches\n#figure.dpi:         100       # figure dots per inch\nfigure.facecolor:    232136    # figure face color\nfigure.edgecolor:    59546d    # figure edge color\n#figure.frameon:     True      # enable figure frame\n#figure.max_open_warning: 20   # The maximum number of figures to open through\n                               # the pyplot interface before emitting a warning.\n                               # If less than one this feature is disabled.\n#figure.raise_window : True    # Raise the GUI window to front when show() is called.\n\n## The figure subplot parameters.  All dimensions are a fraction of the figure width and height.\n#figure.subplot.left:   0.125  # the left side of the subplots of the figure\n#figure.subplot.right:  0.9    # the right side of the subplots of the figure\n#figure.subplot.bottom: 0.11   # the bottom of the subplots of the figure\n#figure.subplot.top:    0.88   # the top of the subplots of the figure\n#figure.subplot.wspace: 0.2    # the amount of width reserved for space between subplots,\n                               # expressed as a fraction of the average axis width\n#figure.subplot.hspace: 0.2    # the amount of height reserved for space between subplots,\n                               # expressed as a fraction of the average axis height\n\n## Figure layout\n#figure.autolayout: False  # When True, automatically adjust subplot\n                           # parameters to make the plot fit the figure\n                           # using `tight_layout`\n#figure.constrained_layout.use: False  # When True, automatically make plot\n                                       # elements fit on the figure. (Not\n                                       # compatible with `autolayout`, above).\n#figure.constrained_layout.h_pad:  0.04167  # Padding around axes objects. Float representing\n#figure.constrained_layout.w_pad:  0.04167  # inches. Default is 3/72 inches (3 points)\n#figure.constrained_layout.hspace: 0.02     # Space between subplot groups. Float representing\n#figure.constrained_layout.wspace: 0.02     # a fraction of the subplot widths being separated.\n\n\n## ***************************************************************************\n## * IMAGES                                                                  *\n## ***************************************************************************\n#image.aspect: equal                # {equal, auto} or a number\n#image.interpolation:  antialiased  # see help(imshow) for options\n#image.cmap:   viridis              # A colormap name, gray etc...\n#image.lut:    256                  # the size of the colormap lookup table\n#image.origin: upper                # {lower, upper}\n#image.resample:  True\n#image.composite_image: True  # When True, all the images on a set of axes are\n                              # combined into a single composite image before\n                              # saving a figure as a vector graphics file,\n                              # such as a PDF.\n\n\n## ***************************************************************************\n## * CONTOUR PLOTS                                                           *\n## ***************************************************************************\n#contour.negative_linestyle: dashed  # string or on-off ink sequence\n#contour.corner_mask:        True    # {True, False, legacy}\n#contour.linewidth:          None    # {float, None} Size of the contour line\n                                     # widths. If set to None, it falls back to\n                                     # `line.linewidth`.\n\n\n## ***************************************************************************\n## * ERRORBAR PLOTS                                                          *\n## ***************************************************************************\n#errorbar.capsize: 0  # length of end cap on error bars in pixels\n\n\n## ***************************************************************************\n## * HISTOGRAM PLOTS                                                         *\n## ***************************************************************************\n#hist.bins: 10  # The default number of histogram bins or 'auto'.\n\n\n## ***************************************************************************\n## * SCATTER PLOTS                                                           *\n## ***************************************************************************\n#scatter.marker: o         # The default marker type for scatter plots.\n#scatter.edgecolors: face  # The default edge colors for scatter plots.\n\n\n## ***************************************************************************\n## * AGG RENDERING                                                           *\n## ***************************************************************************\n## Warning: experimental, 2008/10/10\n#agg.path.chunksize: 0  # 0 to disable; values in the range\n                        # 10000 to 100000 can improve speed slightly\n                        # and prevent an Agg rendering failure\n                        # when plotting very large data sets,\n                        # especially if they are very gappy.\n                        # It may cause minor artifacts, though.\n                        # A value of 20000 is probably a good\n                        # starting point.\n\n\n## ***************************************************************************\n## * PATHS                                                                   *\n## ***************************************************************************\n#path.simplify: True  # When True, simplify paths by removing \"invisible\"\n                      # points to reduce file size and increase rendering\n                      # speed\n#path.simplify_threshold: 0.111111111111  # The threshold of similarity below\n                                          # which vertices will be removed in\n                                          # the simplification process.\n#path.snap: True  # When True, rectilinear axis-aligned paths will be snapped\n                  # to the nearest pixel when certain criteria are met.\n                  # When False, paths will never be snapped.\n#path.sketch: None  # May be None, or a 3-tuple of the form:\n                    # (scale, length, randomness).\n                    #     - *scale* is the amplitude of the wiggle\n                    #         perpendicular to the line (in pixels).\n                    #     - *length* is the length of the wiggle along the\n                    #         line (in pixels).\n                    #     - *randomness* is the factor by which the length is\n                    #         randomly scaled.\n#path.effects:\n\n\n## ***************************************************************************\n## * SAVING FIGURES                                                          *\n## ***************************************************************************\n## The default savefig parameters can be different from the display parameters\n## e.g., you may want a higher resolution, or to make the figure\n## background white\n#savefig.dpi:       figure      # figure dots per inch or 'figure'\nsavefig.facecolor:  232136      # figure face color when saving\n#savefig.edgecolor: auto        # figure edge color when saving\n#savefig.format:    png         # {png, ps, pdf, svg}\n#savefig.bbox:      standard    # {tight, standard}\n                                # 'tight' is incompatible with pipe-based animation\n                                # backends (e.g. 'ffmpeg') but will work with those\n                                # based on temporary files (e.g. 'ffmpeg_file')\n#savefig.pad_inches:   0.1      # Padding to be used when bbox is set to 'tight'\n#savefig.directory:    ~        # default directory in savefig dialog box,\n                                # leave empty to always use current working directory\n#savefig.transparent: False     # setting that controls whether figures are saved with a\n                                # transparent background by default\n#savefig.orientation: portrait  # Orientation of saved figure\n\n### tk backend params\n#tk.window_focus:   False  # Maintain shell focus for TkAgg\n\n### ps backend params\n#ps.papersize:      letter  # {auto, letter, legal, ledger, A0-A10, B0-B10}\n#ps.useafm:         False   # use of AFM fonts, results in small files\n#ps.usedistiller:   False   # {ghostscript, xpdf, None}\n                            # Experimental: may produce smaller files.\n                            # xpdf intended for production of publication quality files,\n                            # but requires ghostscript, xpdf and ps2eps\n#ps.distiller.res:  6000    # dpi\n#ps.fonttype:       3       # Output Type 3 (Type3) or Type 42 (TrueType)\n\n### PDF backend params\n#pdf.compression:    6  # integer from 0 to 9\n                        # 0 disables compression (good for debugging)\n#pdf.fonttype:       3  # Output Type 3 (Type3) or Type 42 (TrueType)\n#pdf.use14corefonts : False\n#pdf.inheritcolor:   False\n\n### SVG backend params\n#svg.image_inline: True  # Write raster image data directly into the SVG file\n#svg.fonttype: path      # How to handle SVG fonts:\n                         #     path: Embed characters as paths -- supported\n                         #           by most SVG renderers\n                         #     None: Assume fonts are installed on the\n                         #           machine where the SVG will be viewed.\n#svg.hashsalt: None      # If not None, use this string as hash salt instead of uuid4\n\n### pgf parameter\n## See https://matplotlib.org/tutorials/text/pgf.html for more information.\n#pgf.rcfonts: True\n#pgf.preamble:  # See text.latex.preamble for documentation\n#pgf.texsystem: xelatex\n\n### docstring params\n#docstring.hardcopy: False  # set this when you want to generate hardcopy docstring\n\n\n## ***************************************************************************\n## * INTERACTIVE KEYMAPS                                                     *\n## ***************************************************************************\n## Event keys to interact with figures/plots via keyboard.\n## See https://matplotlib.org/users/navigation_toolbar.html for more details on\n## interactive navigation.  Customize these settings according to your needs.\n## Leave the field(s) empty if you don't need a key-map. (i.e., fullscreen : '')\n#keymap.fullscreen: f, ctrl+f   # toggling\n#keymap.home: h, r, home        # home or reset mnemonic\n#keymap.back: left, c, backspace, MouseButton.BACK  # forward / backward keys\n#keymap.forward: right, v, MouseButton.FORWARD      # for quick navigation\n#keymap.pan: p                  # pan mnemonic\n#keymap.zoom: o                 # zoom mnemonic\n#keymap.save: s, ctrl+s         # saving current figure\n#keymap.help: f1                # display help about active tools\n#keymap.quit: ctrl+w, cmd+w, q  # close the current figure\n#keymap.quit_all:               # close all figures\n#keymap.grid: g                 # switching on/off major grids in current axes\n#keymap.grid_minor: G           # switching on/off minor grids in current axes\n#keymap.yscale: l               # toggle scaling of y-axes ('log'/'linear')\n#keymap.xscale: k, L            # toggle scaling of x-axes ('log'/'linear')\n#keymap.copy: ctrl+c, cmd+c     # Copy figure to clipboard\n\n\n## ***************************************************************************\n## * ANIMATION                                                               *\n## ***************************************************************************\n#animation.html: none  # How to display the animation as HTML in\n                       # the IPython notebook:\n                       #     - 'html5' uses HTML5 video tag\n                       #     - 'jshtml' creates a JavaScript animation\n#animation.writer:  ffmpeg        # MovieWriter 'backend' to use\n#animation.codec:   h264          # Codec to use for writing movie\n#animation.bitrate: -1            # Controls size/quality trade-off for movie.\n                                  # -1 implies let utility auto-determine\n#animation.frame_format: png      # Controls frame format used by temp files\n#animation.ffmpeg_path:  ffmpeg   # Path to ffmpeg binary. Without full path\n                                  # $PATH is searched\n#animation.ffmpeg_args:           # Additional arguments to pass to ffmpeg\n#animation.convert_path: convert  # Path to ImageMagick's convert binary.\n                                  # On Windows use the full path since convert\n                                  # is also the name of a system tool.\n#animation.convert_args:          # Additional arguments to pass to convert\n#animation.embed_limit:  20.0     # Limit, in MB, of size of base64 encoded\n                                  # animation in HTML (i.e. IPython notebook)\n\n"
  },
  {
    "path": "config/mpv/input.conf",
    "content": "# === Normalization ===\nN af toggle \"lavfi=[dynaudnorm=framelen=100:gausssize=11:peak=0.95:maxgain=100:coupling=1]\"\n\n# === Seeking ===\na seek -5 exact\nd seek +5 exact\nk seek +80 exact\nLEFT  seek -5 exact\nRIGHT seek +5 exact\n\n# === Per-frame seeking ===\nCtrl+a frame-back-step\nCtrl+d frame-step\nCtrl+LEFT  frame-back-step\nCtrl+RIGHT frame-step\n\n# === Chapters ===\nPGUP  add chapter -1\nPGDWN add chapter +1\n\n# === Playback ===\nMBTN_RIGHT cycle pause\nSPACE      cycle pause\n\nl ab-loop\n\nA playlist-prev\nD playlist-next\n\n# === Video ===\nz add panscan +0.1\nZ add panscan -0.1\n\nf cycle fullscreen\n\n# === Effects ===\n1 add contrast -1 ; show-text \"Contrast: ${contrast}\"\n! add contrast +1 ; show-text \"Contrast: ${contrast}\"\n\n2 add brightness -1 ; show-text \"Brightness: ${brightness}\"\n@ add brightness +1 ; show-text \"Brightness: ${brightness}\"\n\n3 add gamma -1 ; show-text \"Gamma: ${gamma}\"\nSHARP add gamma +1 ; show-text \"Gamma: ${gamma}\"\n\n4 add saturation -1 ; show-text \"Saturation: ${saturation}\"\n$ add saturation +1 ; show-text \"Saturation: ${saturation}\"\n\n5 add speed -0.05 ; show-text \"Speed: ${speed}\"\n% add speed +0.05 ; show-text \"Speed: ${speed}\"\n\n# === Audio ===\nUP            add volume +5\nWHEEL_UP      add volume +5\nCtrl+WHEEL_UP add volume +1\n\nDOWN            add volume -5\nWHEEL_DOWN      add volume -5\nCtrl+WHEEL_DOWN add volume -1\n\nw cycle aid\nW cycle aid down\n\n# === Subs ===\ns cycle sid\nS cycle sid down\nCtrl+s cycle secondary-sid\nCtrl+S cycle secondary-sid down\nx add sub-delay -0.1\nX add sub-delay +0.1\nv add sub-scale -0.05\nV add sub-scale +0.05\n\n# === Info ===\ni show-text \"${osd-ass-cc/0}{\\\\an5}${media-title}\\\\N\\\\N(${path})\\\\NResolution: ${width} x ${height}\\\\NTime: ${time-pos} / ${duration}\\\\NCache: ${demuxer-cache-duration}s + ${cache-used} / ${cache-size}\\\\N\\\\NFrames dropped: ${frame-drop-count}${osd-ass-cc/1}\"\np show-text \"${osd-ass-cc/0}{\\\\an5}${osd-ass-cc/1}${playlist-pos-1} / ${playlist-count}\\n${playlist}\"\nc show-text \"${osd-ass-cc/0}{\\\\an5}${osd-ass-cc/1}${chapter} / ${chapters}\\n${chapter-list}\"\no show-progress\nI script-binding stats/display-stats-toggle\n\n# === Misc ===\nq quit\n"
  },
  {
    "path": "config/mpv/mpv.conf",
    "content": "# === Interface ===\nwindow-dragging=no\n\nosd-font=Noto Sans\nosd-font-size=30\nosd-duration=2500\nosd-bar-align-y=0.50\nosd-bar-w=51\nosd-bar-h=2\n\nforce-window=immediate\n\n# === Video ===\nprofile=opengl-hq\nhwdec=auto\n\npanscan=1.0\n\n# === Audio ===\nad-lavc-downmix=no\naudio-normalize-downmix=yes\naudio-channels=2\nvolume-max=300\nalang=jp,fr,fre,en,eng,enm,ru,rus\naudio-file-auto=fuzzy\n\n# === Subs ===\nsecondary-sid=auto\nsid=auto\nslang=fr,fre,en,eng,enm,jp,ru,rus\nsub-ass=no\nsub-auto=fuzzy\nsub-pos=95\nsubs-with-matching-audio=no\n\n# === Network ===\nytdl-format=bestvideo+bestaudio/best\nytdl-raw-options=sub-lang=\"en,ru,th\",write-sub=,write-auto-sub=\n\ncache=yes\n\ndemuxer-max-bytes=104857600 # 100 MiB\ndemuxer-max-back-bytes=10485760 # 10 MiB\n\ndemuxer-cache-wait=no\ndemuxer-seekable-cache=yes\n\n# === Misc ===\ninput-default-bindings=no\nsave-position-on-quit=yes\nreset-on-next-file=pause\nload-unsafe-playlists=yes\n"
  },
  {
    "path": "config/niri/config.kdl",
    "content": "// vim: set ts=2 sw=2:\n\n// Startup\nspawn-at-startup \"waybar\"\nspawn-at-startup \"mako\"\nspawn-at-startup \"swaybg\" \"--image\" \"/home/cj/dotfiles/wallpaper.png\" \"--mode\" \"fill\"\nspawn-at-startup \"foot\" \"--server\" \"--log-level=none\"\n\nenvironment {\n  QT_QPA_PLATFORM \"wayland\"\n  ELECTRON_OZONE_PLATFORM_HINT \"wayland\"\n\n  QT_WAYLAND_DISABLE_WINDOWDECORATION \"1\"\n\n  GDK_DPI_SCALE \"1.5\"\n}\n\ncursor {\n  xcursor-theme \"capitaine-cursors-light\"\n  xcursor-size 48\n\n  hide-when-typing\n  hide-after-inactive-ms 3000\n}\n\noverview {\n  zoom 0.5\n  backdrop-color \"#171c29\" // bg-dim-more\n}\n\ninput {\n  disable-power-key-handling\n  focus-follows-mouse max-scroll-amount=\"25%\"\n  workspace-auto-back-and-forth // for tab workspace\n  warp-mouse-to-focus mode=\"center-xy\"\n\n  mod-key \"Super\"\n\n  keyboard {\n    xkb {\n      layout \"us,ru,th\"\n      options \"grp:caps_toggle12,grp_led:caps,compose:ralt\"\n    }\n\n    repeat-delay 300\n    repeat-rate 15\n    track-layout \"window\"\n  }\n\n  touchpad {\n    tap\n    drag true\n    natural-scroll\n    scroll-factor 0.15\n  }\n\n  // TODO: trackpoint\n}\n\noutput \"HDMI-A-1\" {\n  mode \"2560x1440@60\"\n  scale 1\n  variable-refresh-rate\n}\n\nbinds {\n  // Spawn\n  Super+J repeat=false { spawn \"footclient\"; }\n  Super+B repeat=false { spawn \"google-chrome-unstable\"; }\n  Super+R repeat=false { spawn \"fuzzel\"; }\n\n  // Window control\n  Super+X repeat=false { close-window; }\n  Super+V repeat=false { toggle-window-floating; }\n  Super+Space repeat=false { switch-focus-between-floating-and-tiling; }\n\n  Super+Alt+C { center-column; }\n\n  // Tabs\n  Super+Alt+T { toggle-column-tabbed-display; }\n  Super+G { toggle-column-tabbed-display; }\n\n  // Window size control\n  Super+T { switch-preset-column-width; }\n  Super+Shift+T { switch-preset-window-height; }\n\n  Super+F { fullscreen-window; }\n  Super+Alt+F { maximize-column; }\n  Super+Shift+F { toggle-windowed-fullscreen; }\n\n  Super+Minus { set-column-width \"-5%\"; }\n  Super+Equal { set-column-width \"+5%\"; }\n\n  Super+Shift+Minus { set-window-height \"-5%\"; }\n  Super+Shift+Equal { set-window-height \"+5%\"; }\n\n  // Window focus\n  Super+A { focus-column-left; }\n  Super+D { focus-column-right; }\n  Super+W { focus-window-or-workspace-up; }\n  Super+S { focus-window-or-workspace-down; }\n\n  Super+Q { focus-column-first; }\n  Super+E { focus-column-last; }\n\n  // Window movement\n  Super+Shift+A { move-column-left; }\n  Super+Shift+D { move-column-right; }\n  Super+Shift+W { move-window-up-or-to-workspace-up; }\n  Super+Shift+S { move-window-down-or-to-workspace-down; }\n\n  Super+Alt+A { consume-or-expel-window-left; }\n  Super+Alt+D { consume-or-expel-window-right; }\n\n  Super+Shift+Q { move-column-to-first; }\n  Super+Shift+E { move-column-to-last; }\n\n  // Workspaces\n  Super+1 { focus-workspace \"1\"; }\n  Super+2 { focus-workspace \"2\"; }\n  Super+3 { focus-workspace \"3\"; }\n  Super+4 { focus-workspace \"4\"; }\n  Super+5 { focus-workspace \"5\"; }\n  Super+6 { focus-workspace \"6\"; }\n  Super+7 { focus-workspace \"7\"; }\n  Super+8 { focus-workspace \"8\"; }\n  Super+9 { focus-workspace \"9\"; }\n\n  Super+0 { focus-workspace \"obs\"; }\n  Super+C { focus-workspace \"msg\"; }\n  Super+Tab { focus-workspace \"tab\"; }\n\n  Super+Shift+1 { move-window-to-workspace \"1\"; }\n  Super+Shift+2 { move-window-to-workspace \"2\"; }\n  Super+Shift+3 { move-window-to-workspace \"3\"; }\n  Super+Shift+4 { move-window-to-workspace \"4\"; }\n  Super+Shift+5 { move-window-to-workspace \"5\"; }\n  Super+Shift+6 { move-window-to-workspace \"6\"; }\n  Super+Shift+7 { move-window-to-workspace \"7\"; }\n  Super+Shift+8 { move-window-to-workspace \"8\"; }\n  Super+Shift+9 { move-window-to-workspace \"9\"; }\n\n  Super+Shift+0 { move-window-to-workspace \"obs\"; }\n  Super+Shift+C { move-window-to-workspace \"msg\"; }\n  Super+Shift+Tab { move-window-to-workspace \"tab\"; }\n\n  // Moving workspaces\n  Super+Alt+W { move-workspace-up; }\n  Super+Alt+S { move-workspace-down; }\n\n  // Niri control\n  Super+Alt+X repeat=false { quit skip-confirmation=true; }\n  Super+O repeat=false { toggle-overview; }\n  Super+Z repeat=false { toggle-overview; }\n  Super+Alt+H repeat=false { show-hotkey-overlay; }\n\n  // Waybar\n  Super+Alt+B repeat=false { spawn \"pkill\" \"-SIGUSR1\" \"waybar\"; }\n\n  // Monitor control\n  Super+L repeat=false { spawn \"hyprlock\"; }\n  Super+Alt+K repeat=false { power-off-monitors; }\n  Super+Alt+Shift+K repeat=false { power-on-monitors; }\n\n  // Notifications\n  Super+N repeat=false { spawn \"makoctl\" \"dismiss\" \"--all\"; }\n  Super+Alt+N repeat=false { spawn \"systemctl\" \"--user\" \"restart\" \"mako\"; }\n\n  // Media\n  XF86AudioMute allow-when-locked=true repeat=false { spawn \"wpctl\" \"set-mute\" \"@DEFAULT_SINK@\" \"toggle\"; }\n  XF86AudioLowerVolume allow-when-locked=true { spawn \"wpctl\" \"set-volume\" \"@DEFAULT_SINK@\" \"5%-\"; }\n  XF86AudioRaiseVolume allow-when-locked=true { spawn \"wpctl\" \"set-volume\" \"@DEFAULT_SINK@\" \"5%+\"; }\n\n  XF86AudioMicMute allow-when-locked=true repeat=false { spawn \"wpctl\" \"set-mute\" \"@DEFAULT_SOURCE@\" \"toggle\"; }\n  F7 allow-when-locked=true repeat=false { spawn \"wpctl\" \"set-mute\" \"@DEFAULT_SOURCE@\" \"toggle\"; }\n\n  // Brightness\n  XF86MonBrightnessUp allow-when-locked=true {   spawn \"brightnessctl\" \"-e\" \"set\" \"5%+\"; }\n  XF86MonBrightnessDown allow-when-locked=true { spawn \"brightnessctl\" \"-e\" \"set\" \"5%-\"; }\n\n  // Print screen\n  Print repeat=false { spawn \"flameshot\" \"gui\"; }\n\n  // Language\n  Super+Backspace repeat=false { switch-layout \"2\"; }\n}\n\nswitch-events {\n  // TODO: lid-close / lid-open\n}\n\ngestures {\n  hot-corners {\n    top-left\n  }\n}\n\nlayout {\n  gaps 16\n\n  struts {\n    left 16\n    right 16\n    top 16\n    bottom 16\n  }\n\n  center-focused-column \"never\" // \"on-overflow\"\n  always-center-single-column\n\n  preset-column-widths {\n    proportion 0.5\n    proportion 1.0\n  }\n\n  default-column-width { proportion 0.5; }\n\n  preset-window-heights {\n    proportion 1.0\n    proportion 0.5\n  }\n\n  border {\n    off\n  }\n\n  focus-ring {\n    width 3\n    active-color \"#92b7ea\" // blue\n    inactive-color \"#54678c\" // fg-half-dim\n    urgent-color \"#D0879D\" // red\n  }\n\n  shadow {\n    on\n\n    spread 10\n    softness 50\n  }\n\n  tab-indicator {\n    on\n    hide-when-single-tab\n    place-within-column\n\n    gap 12\n    width 12\n    length total-proportion=0.25\n    position \"left\"\n    gaps-between-tabs 16\n    corner-radius 16\n    active-color \"#AD9BEA\" // purple\n\n    inactive-color \"#54678c90\" // fg-half-dim with alpha\n    urgent-color \"#E0778D\" // reder (brighter red)\n  }\n\n  insert-hint {\n    on\n    color \"#92b7ea90\" // blue with alpha\n  }\n}\n\n// Workspaces\nworkspace \"1\" {}\nworkspace \"2\" {}\nworkspace \"3\" {}\nworkspace \"4\" {}\nworkspace \"5\" {}\nworkspace \"6\" {}\nworkspace \"7\" {}\nworkspace \"8\" {}\nworkspace \"9\" {}\n\nworkspace \"obs\" {}\nworkspace \"msg\" {}\nworkspace \"tab\" {}\n\n// Window rules\nwindow-rule {\n  default-column-width { proportion 1.0; }\n  open-focused true\n  tiled-state true\n\n  geometry-corner-radius 24\n  clip-to-geometry true\n}\n\nwindow-rule {\n  match app-id=\"^google-chrome-unstable$\"\n  focus-ring {\n    active-color \"#d3e3fd\" // color of chrome window theme\n  }\n}\n\nwindow-rule {\n  match app-id=\"^foot(client)?$\"\n  default-column-width { proportion 0.5; }\n}\n\nwindow-rule {\n  match app-id=\"^org.telegram.desktop|Element|discord$\"\n  exclude title=\"^Media viewer$\"\n  open-on-workspace \"msg\"\n  open-focused false\n  default-column-width { proportion 0.5; }\n}\n\nwindow-rule {\n  match app-id=\"^com.obsproject.Studio$\"\n  open-on-workspace \"obs\"\n}\n\nwindow-rule {\n  match app-id=\"^steam$\"\n  open-on-workspace \"tab\"\n}\n\nlayer-rule {\n  match namespace=\"^notifications$\"\n\n  block-out-from \"screencast\"\n  baba-is-float true\n}\n\nlayer-rule {\n  match namespace=\"^launcher$\"\n\n  baba-is-float true\n  shadow {\n    on\n  }\n\n  geometry-corner-radius 24\n}\n\nanimations {\n  window-open {\n    off\n  }\n}\n\n// Other options\nprefer-no-csd\n\nhotkey-overlay {\n  skip-at-startup\n  hide-not-bound\n}\n\n// Recent windows\nrecent-windows {\n  debounce-ms 0\n  open-delay-ms 0\n\n  highlight {\n    active-color \"#92b7ea\" // blue\n    urgent-color \"#D0879D\" // red\n    padding 64\n    corner-radius 24\n  }\n\n  previews {\n    max-height 9999\n    max-scale 0.66\n  }\n\n  binds {\n    Super+BracketLeft  { previous-window; }\n    Super+BracketRight { next-window; }\n  }\n}\n"
  },
  {
    "path": "config/npm/npmrc",
    "content": "prefix=~/.npm\n"
  },
  {
    "path": "config/numbat/config.toml",
    "content": "intro-banner = \"off\"\nprompt = \"\\u001B[0;32m 󰪚\\u001B[0;37m ❯ \\u001B[0m\"\npretty-print = \"auto\"\n\n[exchange-rates]\nfetching-policy = \"on-first-use\"\n"
  },
  {
    "path": "config/nvim/init.lua",
    "content": "---@diagnostic disable: lowercase-global\n---@diagnostic disable: need-check-nil\n\n----------\n-- TODO --\n----------\n\n-- - clipboard manager (prbly for wayland)\n-- - markdown wrapping\n-- - 2-space indent for html, css, md\n-- - Autoformatting for html and css\n-- - Better help in python (like in Helix)\n\n----------------\n-- File types --\n----------------\n\n-- 2-space indent for some file types\nvim.api.nvim_create_autocmd(\"FileType\", {\n    pattern = \"yaml,toml,markdown,html,css\",\n    callback = function()\n        vim.opt_local.tabstop = 2\n        vim.opt_local.softtabstop = 2\n        vim.opt_local.shiftwidth = 2\n    end\n})\n\n-- Enable soft wrapping for some file types\nvim.api.nvim_create_autocmd(\"FileType\", {\n    pattern = \"markdown\",\n    callback = function()\n        vim.opt_local.wrap = true\n    end\n})\n\n-- Disable comment continuation\nvim.api.nvim_create_autocmd(\"BufEnter\", {\n    pattern = \"*\",\n    callback = function()\n        vim.opt.formatoptions = \"jql\"\n    end,\n})\n\n-------------\n-- Plugins --\n-------------\n\nlocal lazypath = vim.fn.stdpath(\"data\") .. \"/lazy/lazy.nvim\"\nvim.opt.rtp:prepend(lazypath)\n\nvim.cmd.colorscheme(\"nuitbleue\")\nvim.opt.termguicolors = true\n\nrequire(\"lazy\").setup({\n    local_spec = false,\n    install = { missing = false },\n\n    spec = {\n        -- Surround\n        {\n            \"kylechui/nvim-surround\",\n            version = \"*\", -- Use for stability; omit to use `main` branch for the latest features\n            event = \"VeryLazy\",\n            config = function()\n                require(\"nvim-surround\").setup({\n                    keymaps = {},\n                })\n\n                -- HACK: restore an \"S\" overwritten by plugin. Fuck nvim-surround\n                vim.keymap.set({ \"n\", \"v\" }, \"S\", \"5j\", {})\n\n                -- HACK: remove \"ds\" keymap since it's breaking WASD movements\n                vim.keymap.del({ \"n\" }, \"ds\")\n            end\n        },\n\n        -- File Manager\n        {\n            \"stevearc/oil.nvim\",\n            event = \"VeryLazy\",\n            opts = {\n                columns = { \"icon\", \"permissions\", \"size\" },\n\n                delete_to_trash = true,\n                skip_confirm_for_simple_edits = true,\n                watch_for_changes = true,\n                view_options = {\n                    show_hidden = true,\n                    show_column_number = false,\n                },\n                float = {\n                    padding = 3,\n                    max_width = 80,\n                    max_height = 30,\n                    ---@diagnostic disable-next-line: unused-local\n                    get_win_title = function(winid)\n                        return \"\"\n                    end,\n                },\n                keymaps = {\n                    [\"?\"] = { \"actions.show_help\", mode = \"n\" },\n                    [\"<bs>\"] = { \"actions.parent\", mode = \"n\" },\n                    [\"<c-cr>\"] = { \"actions.preview\", mode = \"n\" },\n                },\n            },\n        },\n\n        -- Highlight word under cursor\n        {\n            \"tzachar/local-highlight.nvim\",\n            event = \"VeryLazy\",\n            config = function()\n                require(\"local-highlight\").setup({\n                    min_match_len = 2,\n                    max_match_len = 30,\n                    cw_hlgroup = \"LocalHighlight\",\n                    highlight_single_match = true,\n                    debounce_timeout = 50,\n                    animate = {\n                        enabled = false,\n                    },\n                })\n\n                vim.cmd(\"LocalHighlightOn\")\n            end,\n        },\n\n        -- Copilot\n        {\n            \"zbirenbaum/copilot.lua\",\n            event = \"VeryLazy\",\n            config = function()\n                require(\"copilot\").setup({\n                    panel = {\n                        enabled = false,\n                    },\n                    suggestion = {\n                        auto_trigger = true,\n                        debounce = 25,\n                    },\n                    filetypes = {\n                        markdown = true,\n                        yaml = true,\n                        gitcommit = true,\n                    },\n                })\n            end,\n        },\n\n        -- Better notifications\n        {\n            \"rcarriga/nvim-notify\",\n            event = \"VeryLazy\",\n            opts = {\n                timeout = 2000,\n                stages = \"static\",\n                render = \"minimal\",\n            },\n        },\n\n        -- Better UI\n        {\n            \"folke/noice.nvim\",\n            event = \"VeryLazy\",\n            config = function()\n                require(\"noice\").setup({\n                    routes = {\n                        -- Remove search counter\n                        {\n                            filter = { event = \"msg_show\", kind = \"search_count\" },\n                            opts = { skip = true },\n                        },\n                        -- Remove save file message\n                        {\n                            filter = { find = \" written\" },\n                            opts = { skip = true },\n                        },\n                        -- Remove undo/redo messages\n                        {\n                            filter = { find = \" before #\" },\n                            opts = { skip = true },\n                        },\n                        {\n                            filter = { find = \" after #\" },\n                            opts = { skip = true },\n                        },\n                        -- Remove paste messages\n                        {\n                            filter = { find = \" more lines\" },\n                            opts = { skip = true },\n                        },\n                        -- Remove deprecated messages\n                        {\n                            filter = { find = \" deprecate\" },\n                            opts = { skip = true },\n                        },\n                        -- Remove deprecated messages about diagnostic signs\n                        {\n                            filter = { find = \"Defining diagnostic signs \" },\n                            opts = { skip = true },\n                        },\n                        -- Remove some non-critical LSP messages (?)\n                        {\n                            filter = { find = \"ServerNotInitialized\" },\n                            opts = { skip = true },\n                        },\n                        -- LSP hover messages\n                        {\n                            filter = { find = \"No information available\" },\n                            opts = { skip = true },\n                        },\n                        -- LSP shit\n                        {\n                            filter = { find = \"method textDocument/signatureHelp is not supported\" },\n                            opts = { skip = true },\n                        },\n                    },\n                    window = {\n                        border = \"rounded\",\n                    },\n                    messages = {\n                        enabled = true,\n                    },\n                    lsp = {\n                        progress = {\n                            enabled = false,\n                        },\n                    },\n                    presets = {\n                        bottom_search = true,\n                        command_palette = true,\n                        long_message_to_split = true,\n                        inc_rename = false,\n                        lsp_doc_border = true,\n                    },\n                })\n            end,\n        },\n\n        -- Color column as a characters\n        {\n            \"lukas-reineke/virt-column.nvim\",\n            opts = {},\n            config = function()\n                require(\"virt-column\").setup({\n                    char = \"¦\",\n                    virtcolumn = \"80,120\",\n                })\n            end,\n        },\n\n        -- Move diagnostics to top\n        {\n            \"dgagn/diagflow.nvim\",\n            version = false,\n            event = \"VeryLazy\",\n            opts = {\n                padding_right = 2,\n                gap_size = 2,\n                -- FIXME: wait until author fixes https://github.com/dgagn/diagflow.nvim/issues/54\n                show_borders = true,\n                border_chars = {\n                    top_left = \" \",\n                    top_right = \" \",\n                    bottom_left = \" \",\n                    bottom_right = \" \",\n                    horizontal = \" \",\n                    vertical = \" \"\n                },\n                scope = \"line\",\n                format = function(diagnostic)\n                    -- No errors in insert mode\n                    if vim.api.nvim_get_mode().mode == \"i\" then\n                        return \"\"\n                    end\n\n                    local current_line = vim.fn.line(\".\")\n                    local top_line = vim.fn.line(\"w0\")\n                    local relative_line = current_line - top_line\n\n                    -- No diagnostics then current line is too high in visible area\n                    if relative_line < 8 then\n                        return \"\"\n                    end\n\n                    -- NOTE: NBSP from pyright breaking the border\n                    -- NOTE: quotes from harper too\n                    return diagnostic.message:gsub(\" \", \".\")\n                        :gsub(\"“\", \"\\\"\")\n                        :gsub(\"”\", \"\\\"\")\n                end,\n            }\n        },\n\n        -- Indentation guides\n        {\n            \"lukas-reineke/indent-blankline.nvim\",\n            main = \"ibl\",\n            opts = {},\n            config = function()\n                require(\"ibl\").setup({\n                    indent = { char = \"¦\" },\n                    scope = {\n                        enabled = true,\n                        show_start = false,\n                        show_end = false,\n                    },\n                })\n            end,\n        },\n\n        -- Completion\n        {\n            \"hrsh7th/nvim-cmp\",\n            event = \"VeryLazy\",\n            dependencies = {\n                \"hrsh7th/cmp-nvim-lsp\",\n                \"hrsh7th/cmp-buffer\",\n                \"hrsh7th/cmp-path\",\n                \"hrsh7th/cmp-cmdline\",\n            },\n            config = function()\n                local cmp = require(\"cmp\")\n\n                local cmp_kinds = {\n                    Text = '󰊄 ',\n                    Method = '󰊕 ',\n                    Function = '󰊕 ',\n                    Constructor = '󰊕 ',\n                    Field = '󰬟 ',\n                    Variable = '󰬟 ',\n                    Class = ' ',\n                    Interface = '󰬐 ',\n                    Module = '󰰐 ',\n                    Property = '󰬟  ',\n                    Unit = ' ',\n                    Value = ' ',\n                    Enum = ' ',\n                    Keyword = ' ',\n                    Snippet = ' ',\n                    Color = ' ',\n                    File = ' ',\n                    Reference = ' ',\n                    Folder = ' ',\n                    EnumMember = ' ',\n                    Constant = ' ',\n                    Struct = ' ',\n                    Event = ' ',\n                    Operator = ' ',\n                    TypeParameter = ' ',\n                }\n\n                cmp.setup({\n                    preselect = false,\n                    window = {\n                        completion = cmp.config.window.bordered {\n                            border = 'single',\n                            winhighlight = 'Normal:NormalFloat,FloatBorder:FloatBorder,CursorLine:Visual,Search:None',\n                        },\n                        documentation = cmp.config.window.bordered {\n                            border = 'single',\n                            winhighlight = 'Normal:NormalFloat,FloatBorder:FloatBorder,CursorLine:Visual,Search:None',\n                        },\n                    },\n                    mapping = {\n                        [\"<down>\"] = cmp.mapping.select_next_item(),\n                        [\"<up>\"] = cmp.mapping.select_prev_item(),\n                        [\"<c-e>\"] = cmp.mapping.close(),\n                        [\"<c-cr>\"] = cmp.mapping.confirm(),\n                        -- NOTE: handled by tab_complete function\n                        -- [\"<tab>\"] = cmp.mapping.select_next_item(),\n                        [\"<s-tab>\"] = cmp.mapping.select_prev_item(),\n                    },\n                    sources = {\n                        { name = \"nvim_lsp\" },\n                        { name = \"buffer\" },\n                        { name = \"path\" },\n                    },\n                    formatting = {\n                        fields = { 'kind', 'abbr' },\n                        format = function(_, vim_item)\n                            vim_item.kind = cmp_kinds[vim_item.kind] or ''\n                            vim_item.menu = ''\n                            return vim_item\n                        end,\n                    },\n                })\n            end,\n        },\n\n        -- Multiple cursors\n        --   Alternatives:\n        --   - terryma/vim-multiple-cursors -- kinda works with custom mappings, but deprecated and buggy\n        --   - mg979/vim-visual-multi -- doesn't work with custom mappings\n        --   - jake-stewart/multicursor.nvim -- works, but is not interactive\n        --   - brenton-leighton/multiple-cursors.nvim -- doesn't work with custom mappings\n        {\n            \"jake-stewart/multicursor.nvim\",\n            event = \"VeryLazy\",\n            branch = \"1.0\",\n            config = function()\n                local mc = require(\"multicursor-nvim\")\n\n                mc.setup()\n\n                vim.keymap.set({ \"n\", \"v\" }, \"C\", function() mc.lineAddCursor(1) end)\n                vim.keymap.set({ \"n\" }, \"<c-d>\", function()\n                    vim.cmd('normal! viw')\n                end)\n                vim.keymap.set({ \"v\" }, \"<c-d>\", function() mc.matchAddCursor(1) end)\n                vim.keymap.set({ \"v\" }, \"l\", function() mc.splitCursors(\"\\n\") end)\n\n                vim.keymap.set(\"n\", \"<esc>\", function()\n                    if not mc.cursorsEnabled() then\n                        mc.enableCursors()\n                    elseif mc.hasCursors() then\n                        mc.clearCursors()\n                    else\n                        vim.cmd(\"nohlsearch\")\n\n                        -- Close all floating windows except zen-mode\n                        -- vim.cmd(\"fclose\")\n                        for _, win in ipairs(vim.api.nvim_list_wins()) do\n                            local conf = vim.api.nvim_win_get_config(win)\n                            if conf.relative ~= \"\" and conf.zindex > 40 then\n                                vim.api.nvim_win_close(win, true)\n                            end\n                        end\n                    end\n                end)\n            end,\n        },\n\n        -- LSP\n        {\n            \"neovim/nvim-lspconfig\",\n            config = function()\n                local lsp = require(\"lspconfig\")\n                local border = {\n                    { \"┌\", \"FloatBorder\" },\n                    { \"─\", \"FloatBorder\" },\n                    { \"┐\", \"FloatBorder\" },\n                    { \"│\", \"FloatBorder\" },\n                    { \"┘\", \"FloatBorder\" },\n                    { \"─\", \"FloatBorder\" },\n                    { \"└\", \"FloatBorder\" },\n                    { \"│\", \"FloatBorder\" },\n                }\n\n                local orig_util_open_floating_preview = vim.lsp.util.open_floating_preview\n                function vim.lsp.util.open_floating_preview(contents, syntax, opts, ...)\n                    opts = opts or {}\n                    opts.border = opts.border or border\n                    return orig_util_open_floating_preview(contents, syntax, opts, ...)\n                end\n\n                -- General\n                -- lsp.harper_ls.setup({\n                --     settings = {\n                --         [\"harper-ls\"] = {\n                --             diagnosticSeverity = \"warning\",\n                --             linters = {\n                --                 AvoidCurses = false,\n                --             },\n                --         }\n                --     },\n                -- })\n\n                -- LanguageTool\n                -- lsp.ltex.setup({})\n                -- lsp.ltex_plus.setup({\n                --     settings = {\n                --         ltex = {\n                --             diagnosticSeverity = \"hint\",\n                --             checkFrequency = \"save\",\n                --             dictionary = {\n                --                 [\"en-US\"] = {\n                --                     \"zig\",\n                --                     \"Zig\",\n                --                     \"inlining\",\n                --                 },\n                --             },\n                --         }\n                --     }\n                -- })\n\n                -- LUA\n                lsp.lua_ls.setup({\n                    settings = {\n                        Lua = {\n                            diagnostics = {\n                                -- For init.lua\n                                globals = {\n                                    'vim',\n                                    'require'\n                                },\n                            },\n                            telemetry = { enable = false },\n                        },\n                    },\n                })\n\n                -- Python\n                -- Autocomplete, Imports, Type checking\n                lsp.pyright.setup({\n                    settings = {\n                        python = {\n                            analysis = {\n                                typeCheckingMode = \"strict\",\n\n                                diagnosticSeverityOverrides = {\n                                    -- Fix diagnostics level\n                                    reportUnknownParameterType = \"warning\",\n                                    reportMissingParameterType = \"warning\",\n                                    reportUnknownArgumentType = \"warning\",\n                                    reportUnknownLambdaType = \"warning\",\n                                    reportUnknownMemberType = \"warning\",\n                                    reportUnusedFunction = \"warning\",\n                                    reportUnusedVariable = \"warning\",\n                                    reportUntypedFunctionDecorator = \"warning\",\n                                    reportDeprecated = \"warning\",\n\n                                    -- Enable extra diagnostics\n                                    reportUnusedCallResult = \"warning\",\n                                    reportUninitializedInstanceVariable = \"warning\",\n\n                                    -- Gradual typing in new projects\n                                    reportMissingImports = false,\n                                    reportMissingTypeStubs = false,\n                                    reportUnknownVariableType = false,\n\n                                    -- Covered by ruff\n                                    reportUnusedImport = false,\n                                },\n                            },\n                        },\n                    },\n                })\n\n                -- Linting / formatting\n                lsp.ruff.setup({})\n\n                -- YAML\n                lsp.yamlls.setup({})\n\n                -- TOML\n                lsp.taplo.setup({})\n\n                -- HTML\n                lsp.emmet_language_server.setup({\n                    filetypes = { \"python\", \"html\" },\n                    preferences = {\n                        caniuse = {\n                            enabled = false,\n                        },\n                    },\n                })\n                -- lsp.html.setup({}) -- vscode shit, doesn't provide autocomplete anyway\n                lsp.superhtml.setup({})\n\n                -- Bash\n                lsp.bashls.setup({})\n\n                -- Typst\n                lsp.tinymist.setup({\n                    settings = {\n                        formatterMode = \"typstyle\",\n                        exportPdf = \"onType\",\n                    },\n                })\n\n                -- Zig\n                lsp.zls.setup({\n                    settings = {\n                        zls = {\n                            enable_autofix = true,\n                            enable_inlay_hints = false,\n                            enable_argument_placeholders = false,\n                            semantic_tokens = \"partial\",\n\n                            enable_build_on_save = true,\n                            build_on_save_args = { \"check\" },\n\n                            -- Mostly annoying\n                            -- warn_style = true,\n                        },\n                    },\n                })\n\n                -- Rust\n                lsp.rust_analyzer.setup({\n                    settings = {\n                        [\"rust-analyzer\"] = {\n                            cachePriming = {\n                                enable = false,\n                            },\n                            cargo = {\n                                -- Use separate target directory for rust-analyzer to remove interferences with cargo\n                                targetDir = true,\n                            },\n                            check = {\n                                command = \"clippy\",\n                            },\n                            procMacro = {\n                                enable = true,\n                            },\n                            completion = {\n                                limit = 1024,\n                                callable = {\n                                    snippets = \"none\",\n                                },\n                                postfix = {\n                                    enable = false,\n                                },\n                                hideDeprecated = true,\n                            },\n                            imports = {\n                                preferNoStd = true,\n                            },\n                            lens = {\n                                enable = false,\n                            },\n                            diagnostics = {\n                                experimental = {\n                                    enabled = true,\n                                },\n                                styleLints = {\n                                    enable = true,\n                                },\n                            },\n                            rustfmt = {\n                                extraArgs = {\n                                    \"--config=empty_item_single_line=false\",\n                                    \"--config=wrap_comments=true\",\n                                    \"--config=condense_wildcard_suffixes=true\",\n                                    \"--config=enum_discrim_align_threshold=10\",\n                                    \"--config=format_code_in_doc_comments=true\",\n                                    \"--config=hex_literal_case=Upper\",\n                                    \"--config=max_width=120\",\n                                    \"--config=reorder_impl_items=true\",\n                                    \"--config=group_imports=StdExternalCrate\",\n                                    \"--config=use_field_init_shorthand=true\",\n                                },\n                            },\n                        },\n                    },\n                })\n\n                -- JavaScript\n                lsp.ts_ls.setup({})\n\n                -- Go\n                lsp.gopls.setup({})\n\n                -- Codebook (spell checking)\n                lsp.codebook.setup({})\n                vim.lsp.enable(\"codebook\")\n            end,\n        },\n\n        -- Treesitter\n        {\n            \"nvim-treesitter/nvim-treesitter\",\n            version = false, -- Last release is way too old\n            event = \"VeryLazy\",\n            build = \":TSUpdate\",\n            config = function()\n                local configs = require(\"nvim-treesitter.configs\")\n\n                configs.setup({\n                    ensure_installed = {\n                        -- Programming\n                        \"python\",\n                        \"rust\",\n                        \"zig\",\n                        \"javascript\",\n                        \"typescript\",\n\n                        -- Scripting\n                        \"lua\",\n                        \"bash\",\n\n                        -- Markup & Web\n                        \"markdown\",\n                        \"html\",\n                        \"css\",\n\n                        -- Configuration\n                        \"toml\",\n                        \"yaml\",\n                        \"json\",\n                        \"ini\",\n                        \"kdl\",\n\n                        -- Other\n                        \"git_config\",\n                    },\n                    sync_install = false,\n                    highlight = {\n                        enable = true,\n                        additional_vim_regex_highlighting = false,\n                    },\n                    indent = { enable = true },\n                })\n            end,\n        },\n\n        -- Treesitter text objects\n        {\n            \"nvim-treesitter/nvim-treesitter-textobjects\",\n            event = \"VeryLazy\",\n            keys = {\n                {\n                    \"mf\",\n                    function()\n                        vim.cmd(\"normal! v\")\n                        require(\"nvim-treesitter.textobjects.select\").select_textobject(\"@function.inner\")\n                    end,\n                    mode = \"n\",\n                },\n                {\n                    \"ma\",\n                    function()\n                        vim.cmd(\"normal! v\")\n                        require(\"nvim-treesitter.textobjects.select\").select_textobject(\"@parameter.inner\")\n                    end,\n                    mode = \"n\",\n                },\n                {\n                    \"mm\",\n                    function()\n                        vim.cmd(\"normal! v\")\n                        require(\"nvim-treesitter.textobjects.select\").select_textobject(\"@call.inner\")\n                    end,\n                    mode = \"n\",\n                },\n                {\n                    \"Mf\",\n                    function()\n                        vim.cmd(\"normal! v\")\n                        require(\"nvim-treesitter.textobjects.select\").select_textobject(\"@function.outer\")\n                    end,\n                    mode = \"n\",\n                },\n            },\n        },\n\n        -- Git gutter\n        {\n            \"lewis6991/gitsigns.nvim\",\n            event = \"VeryLazy\",\n            config = function()\n                local signs = {\n                    add          = { text = '│' },\n                    change       = { text = '│' },\n                    delete       = { text = '▁' },\n                    topdelete    = { text = '▔' },\n                    changedelete = { text = '⋯' },\n                    untracked    = { text = '┆' },\n                }\n\n                require(\"gitsigns\").setup({\n                    signs = signs,\n                    signs_staged = signs,\n                    numhl = false,\n                })\n            end,\n        },\n\n        -- Scrollbar\n        {\n            \"petertriho/nvim-scrollbar\",\n            event = \"VeryLazy\",\n            opts = {\n                handle = {\n                    -- highlight = \"Visual\",\n                },\n                handlers = {\n                    cursor = false,\n                    diagnostic = true,\n                    gitsigns = true,\n                    handle = true,\n                },\n            },\n        },\n\n        -- File picker / Live grep\n        {\n            \"nvim-telescope/telescope.nvim\",\n            event = \"VeryLazy\",\n            dependencies = { 'nvim-lua/plenary.nvim' },\n            config = function()\n                local actions = require(\"telescope.actions\");\n                local actions_layout = require(\"telescope.actions.layout\")\n                local themes = require(\"telescope.themes\")\n\n                require(\"telescope\").setup({\n                    extensions = {\n                        [\"ui-select\"] = {\n                            themes.get_dropdown({\n                                prompt_title = \"\",\n                                layout_config = {\n                                    vertical = {\n                                        width = 0.3,\n                                        height = 0.5,\n                                    },\n                                },\n                            }),\n                        },\n                    },\n                    defaults = {\n                        -- Close pickers on first Escape instead of going to normal mode\n                        mappings = {\n                            i = {\n                                [\"<esc>\"] = actions.close,\n                                [\"<c-p>\"] = actions_layout.toggle_preview,\n                                [\"<c-down>\"] = actions.cycle_history_next,\n                                [\"<c-up>\"] = actions.cycle_history_prev,\n                            },\n                        },\n                        sorting_strategy = \"ascending\",\n\n                        hidden = true,\n                        use_fd = true,\n\n                        results_title = \"\",\n                        prompt_title = \"\",\n                        preview_title = \"\",\n                        prompt_prefix = \" \",\n\n                        layout_config = {\n                            horizontal = {\n                                width = 0.9,\n                                height = 0.9,\n                                prompt_position = \"top\",\n                                preview_cutoff = 80,\n                                preview_width = 0.5,\n                            },\n                            vertical = {\n                                width = 0.9,\n                                height = 0.9,\n                                prompt_position = \"top\",\n                                preview_cutoff = 20,\n                                preview_width = 0.5,\n                                preview_height = 0.5,\n                            },\n                        },\n                    },\n                    pickers = {\n                        buffers = {\n                            bufnr_width = 0,\n                            sort_lastused = true,\n                            prompt_title = \"\",\n                            preview_title = \"\",\n                        },\n                        diagnostics = {\n                            layout_strategy = \"vertical\",\n                            path_display = \"hidden\",\n                            prompt_title = \"\",\n                            preview_title = \"\",\n                        },\n                        find_files = {\n                            hidden = true,\n                            find_command = { \"fd\", \"--type\", \"f\", \"--hidden\" },\n                            prompt_title = \"\",\n                            preview_title = \"\",\n                        },\n                        lsp_document_symbols = {\n                            prompt_title = \"\",\n                            preview_title = \"\",\n                        },\n                        live_grep = {\n                            file_ignore_patterns = { 'node_modules', '.git', '.venv', 'CHANGELOG.md', 'poetry.lock' },\n                            additional_args = function(_)\n                                return { \"--hidden\" }\n                            end,\n                            prompt_title = \"\",\n                            preview_title = \"\",\n                        },\n                        lsp_references = {\n                            prompt_title = \"\",\n                        },\n                        -- FIXME: todo-comments picker doesn't respect these settings\n                        [\"todo-comments\"] = {\n                            preview_title = \"\",\n                            prompt_title = \"\",\n                        },\n                    },\n                })\n            end,\n        },\n\n        -- Code actions with telescope\n        {\n            'nvim-telescope/telescope-ui-select.nvim',\n            event = \"VeryLazy\",\n            config = function()\n                require(\"telescope\").load_extension(\"ui-select\")\n            end,\n        },\n\n        -- Yaml Schemata\n        {\n            \"someone-stole-my-name/yaml-companion.nvim\",\n            event = \"VeryLazy\",\n            config = function()\n                require(\"telescope\").load_extension(\"yaml_schema\")\n            end,\n        },\n\n        -- Highlight TODO-style comments\n        {\n            \"folke/todo-comments.nvim\",\n            event = \"VeryLazy\",\n            dependencies = { \"nvim-lua/plenary.nvim\" },\n            config = function()\n                local todos = require(\"todo-comments\")\n                todos.setup({\n                    keywords = {\n                        FIX = { icon = \" \", color = \"error\", alt = { \"FIXME\", \"BUG\", \"FIXIT\", \"ISSUE\" } },\n                        TODO = { icon = \" \", color = \"info\" },\n                        HACK = { icon = \"󰈸 \", color = \"warning\" },\n                        WARN = { icon = \" \", color = \"warning\", alt = { \"WARNING\", \"XXX\" } },\n                        PERF = { icon = \" \", color = \"info\", alt = { \"OPTIM\", \"PERFORMANCE\", \"OPTIMIZE\" } },\n                        NOTE = { icon = \" \", color = \"info\", alt = { \"INFO\" } },\n                        TEST = { icon = \"󰙨 \", color = \"warning\", alt = { \"TESTING\", \"PASSED\", \"FAILED\" } },\n                    },\n                    highlight = {\n                        multiline = false,\n                        pattern = [[.*<(KEYWORDS)\\s*]],\n                        keyword = \"fg\",\n                        after = \"\",\n                    },\n                    colors = {\n                        error = { \"ErrorMsg\" },\n                        warning = { \"WarningMsg\" },\n                        info = { \"Todo\", \"Normal\" },\n                        hint = { \"Comment\" },\n                    },\n                })\n\n                vim.keymap.set(\"n\", \"]t\", todos.jump_next, {})\n                vim.keymap.set(\"n\", \"[t\", todos.jump_prev, {})\n            end,\n        },\n\n        -- Restore last position in file\n        -- NOTE: it's deprecated, but works just fine\n        -- NOTE: we need it in addition to session restore\n        {\n            \"ethanholz/nvim-lastplace\",\n            config = function()\n                require(\"nvim-lastplace\").setup({})\n            end,\n        },\n\n        -- Restore all buffers and their positions\n        {\n            \"rmagatti/auto-session\",\n            lazy = false, -- We need to restore session ASAP\n            opts = {\n                suppressed_dirs = { '~/', '/', '~/downloads' },\n                session_lens = {\n                    theme_conf = {\n                        layout_strategy = \"horizontal\",\n                        prompt_title = \"\",\n                        layout_config = {\n                            prompt_position = \"top\",\n                            width = 60,\n                            height = 30,\n                        },\n                    },\n                },\n            },\n        },\n    }\n})\n\n--------------\n-- Settings --\n--------------\n\n-- Do not hide markdown elements in AI chat and documentation\nvim.opt.conceallevel = 0\n\n-- Disable swap files\nvim.opt.swapfile = false\n\n-- Increase gutter spacing\nvim.opt.statuscolumn = \"%s%=%l  \"\n\n-- Enable some mouse (for selections)\nvim.opt.mouse = \"nv\"\n\n-- Show line numbers\nvim.opt.number = true\n\n-- Disable fill character (in gutter)\nvim.opt.fillchars = \"eob: ,vert:¦\"\n\n-- Enable case-insensitive search\nvim.opt.ignorecase = true\nvim.opt.smartcase = true\n\n-- Disable soft wrapping\nvim.opt.wrap = false\n\n-- Merge command line and status line\nvim.opt.cmdheight = 0\n\n-- Tab as 4 spaces\nvim.opt.tabstop = 4\nvim.opt.expandtab = true\nvim.opt.softtabstop = 4\nvim.opt.shiftwidth = 4\n\n-- Always keep sign column on\nvim.opt.signcolumn = \"yes\"\n\n-- Copy to system's clipboard\nvim.schedule(function()\n    vim.opt.clipboard = 'unnamedplus'\nend)\n\n-- Save undo history\nvim.opt.undofile = true\n\n-- Configure how new splits should be opened\nvim.opt.splitright = true\nvim.opt.splitbelow = true\n\n-- Decrease update time. Used for swapfile and by gitsigns and local-highlight\nvim.opt.updatetime = 25\n\n-- Decrease mapped sequence wait time\nvim.opt.timeoutlen = 300\n\n-- White space characters\nvim.opt.list = true\nvim.opt.listchars = { tab = '» ', trail = '•', nbsp = '␣' }\n\n-- Show which line your cursor is on\nvim.opt.cursorline = true\n\n-- Minimal number of screen lines to keep above and below the cursor\nvim.opt.scrolloff = 6\n\n-- Minimal number of screen columns to keep to the left and right of the cursor\nvim.opt.sidescrolloff = 20\n\n-- Hide status line\nvim.opt.laststatus = 0\n\n-- Replace window splitter status line with a character\nvim.opt.statusline = \"%{repeat('⸺',winwidth('.'))}\"\n\n-- Remove welcome screen\nvim.opt.shortmess:append(\"A\")\nvim.opt.shortmess:append(\"I\") -- No intro\nvim.opt.shortmess:append(\"s\") -- Search wrap without message\nvim.opt.shortmess:append(\"c\") -- Unsuccessful search without prompt\n\n-- Diagnostics\nvim.fn.sign_define(\"DiagnosticSignError\", { text = \"\", texthl = \"Error\" })\nvim.fn.sign_define(\"DiagnosticSignWarn\", { text = \"󰈸\", texthl = \"Warn\" })\nvim.fn.sign_define(\"DiagnosticSignSpell\", { text = \"X\", texthl = \"Warn\" })\nvim.fn.sign_define(\"DiagnosticSignInfo\", { text = \"󰋽\", texthl = \"Info\" })\nvim.fn.sign_define(\"DiagnosticSignHint\", { text = \"\", texthl = \"Hint\" })\n\nvim.diagnostic.config({\n    underline = {\n        min = vim.diagnostic.severity.ERROR,\n        max = vim.diagnostic.severity.ERROR,\n    },\n    severity_sort = true,\n})\n\n-----------------\n-- Keybindings --\n-----------------\n\n-- Leader key\nvim.g.mapleader = \" \"\n\nvim.keymap.set({ \"n\", \"v\" }, \"<leader>t\", \"<cmd> Telescope todo-comments <cr>\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"<leader>f\", \"<cmd> Telescope find_files <cr>\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"<leader>k\", \"<cmd> Telescope keymaps <cr>\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"<leader>b\", \"<cmd> Telescope buffers <cr>\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"<leader>/\", \"<cmd> Telescope live_grep <cr>\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"<leader>j\", \"<cmd> Telescope jumplist <cr>\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"<leader>h\", \"<cmd> Telescope help_tags <cr>\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"<leader>d\", \"<cmd> Telescope diagnostics <cr>\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"<leader>s\", \"<cmd> Telescope lsp_document_symbols <cr>\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"<leader>S\", \"<cmd> Telescope lsp_workspace_symbols <cr>\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"<leader><leader>\", \"<cmd> Telescope resume <cr>\", {})\n\nvim.keymap.set({ \"n\", \"v\" }, \"<leader>p\", \"<cmd> SessionSearch <cr>\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"<leader>o\", function() require(\"oil\").toggle_float() end, {})\n\n-- WASD\nvim.keymap.set({ \"n\", \"v\" }, \"w\", \"k\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"s\", \"j\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"a\", \"h\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"d\", \"l\", {})\n\nvim.keymap.set({ \"n\", \"v\", \"o\" }, \"q\", \"^\", {})\nvim.keymap.set({ \"n\", \"v\", \"o\" }, \"e\", \"$\", {})\n\nvim.keymap.set({ \"n\", \"v\" }, \"W\", \"5k\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"S\", \"5j\", {})\nvim.keymap.set({ \"n\", \"v\", \"o\" }, \"A\", \"b\", {})\nvim.keymap.set({ \"n\", \"v\", \"o\" }, \"D\", \"w\", {})\n\nvim.keymap.set({ \"n\", \"v\" }, \"Q\", \"I\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"E\", \"A\", {})\n\n-- Movements\nvim.keymap.set({ \"n\", \"v\" }, \"ge\", \"G\", {})\n\n-- Windows\nvim.keymap.set({ \"n\", \"v\" }, \"<c-left>\", \"<c-w>h\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"<c-right>\", \"<c-w>l\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"<c-down>\", \"<c-w>j\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"<c-up>\", \"<c-w>k\", {})\n\nvim.keymap.set({ \"i\" }, \"<c-left>\", \"<c-o><c-w>h\", {})\nvim.keymap.set({ \"i\" }, \"<c-right>\", \"<c-o><c-w>l\", {})\nvim.keymap.set({ \"i\" }, \"<c-down>\", \"<c-o><c-w>j\", {})\nvim.keymap.set({ \"i\" }, \"<c-up>\", \"<c-o><c-w>k\", {})\n\n-- Jumps\nvim.keymap.set({ \"n\", \"v\" }, \"j\", \"<c-o>\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"J\", \"<c-i>\", {})\n\n-- Modifications\nvim.keymap.set(\"v\", \"<\", \"<gv\", {})\nvim.keymap.set(\"v\", \">\", \">gv\", {})\n\n-- Undo\nvim.keymap.set({ \"n\", \"v\" }, \"U\", \"<c-r>\", {})\n\n-- Git\nvim.keymap.set({ \"n\", \"v\" }, \"gs\", \"<cmd> Telescope git_status <cr>\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"gl\", \"<cmd> Telescope git_bcommits <cr>\", {})\n\n-- Save\nvim.keymap.set({ \"n\", \"v\", \"i\" }, \"<c-s>\", \"<cmd> w <cr>\", {})\n\n-- Surround: selections\nvim.keymap.set({ \"n\", \"v\" }, \"mw\", \"viw\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"mb\", \"vib\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"m(\", \"vib\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"mp\", \"vip\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"mq\", \"vi\\\"\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"m\\\"\", \"vi\\\"\", {})\n\nvim.keymap.set({ \"n\" }, \"(\", \"vib\", {})\nvim.keymap.set({ \"n\" }, \"\\\"\", \"vi\\\"\", {})\nvim.keymap.set({ \"n\" }, \"{\", \"vi{\", {})\nvim.keymap.set({ \"n\" }, \"[\", \"vi[\", {})\nvim.keymap.set({ \"n\" }, \"<\", \"vi<\", {})\nvim.keymap.set({ \"n\" }, \">\", \"vit\", {})\nvim.keymap.set({ \"n\" }, \"`\", \"vi`\", {})\n\n-- Surround: wrapping\nvim.keymap.set({ \"v\" }, \"(\", \"<Plug>(nvim-surround-visual))\", { remap = true, silent = true })\nvim.keymap.set({ \"v\" }, \")\", \"<Plug>(nvim-surround-visual))\", { remap = true, silent = true })\nvim.keymap.set({ \"v\" }, \"[\", \"<Plug>(nvim-surround-visual)]\", { remap = true, silent = true })\nvim.keymap.set({ \"v\" }, \"]\", \"<Plug>(nvim-surround-visual)]\", { remap = true, silent = true })\nvim.keymap.set({ \"v\" }, \"{\", \"<Plug>(nvim-surround-visual)}\", { remap = true, silent = true })\nvim.keymap.set({ \"v\" }, \"}\", \"<Plug>(nvim-surround-visual)}\", { remap = true, silent = true })\nvim.keymap.set({ \"v\" }, \"\\\"\", \"<Plug>(nvim-surround-visual)\\\"\", { remap = true, silent = true })\nvim.keymap.set({ \"v\" }, \"\\'\", \"<Plug>(nvim-surround-visual)\\'\", { remap = true, silent = true })\nvim.keymap.set({ \"v\" }, \"`\", \"<Plug>(nvim-surround-visual)`\", { remap = true, silent = true })\nvim.keymap.set({ \"n\" }, \"t\", \"<Plug>(nvim-surround-change)t\", { remap = true, silent = true })\nvim.keymap.set({ \"v\" }, \"t\", \"<Plug>(nvim-surround-visual)t\", { remap = true, silent = true })\n\n-- Select all\nvim.keymap.set({ \"n\", \"v\" }, \"%\", \"ggVG\", {})\n\n-- LSP\nvim.keymap.set({ \"n\", \"v\" }, \"gd\", vim.lsp.buf.definition, {})\nvim.keymap.set({ \"n\", \"v\" }, \"gr\", \"<cmd> Telescope lsp_references <cr>\", {})\nvim.keymap.set({ \"n\", \"v\" }, \"h\", vim.lsp.buf.hover, {})\nvim.keymap.set({ \"n\", \"v\" }, \"<leader>a\", vim.lsp.buf.code_action, {})\nvim.keymap.set({ \"n\", \"v\" }, \"<leader>r\", vim.lsp.buf.rename, {})\nvim.keymap.set({ \"n\", \"v\" }, \"<c-f>\", vim.lsp.buf.format, {})\n\n-- Commenting\nvim.keymap.set({ \"v\", \"x\" }, \"<c-c>\", \"gcgv\", { remap = true })\nvim.keymap.set({ \"n\" }, \"<c-c>\", \"gcc\", { remap = true })\n\n-- Completion\n-- Some advanced but very practical and easy to use logic:\n--   Continue nvim-cmp completion, if it's already active\n--   Accept copilot suggestion, if any\n--   Use nvim-cmp, if any\n--   If in insert mode, insert tab\nfunction tab_complete()\n    local copilot = require(\"copilot.suggestion\")\n    local cmp = require(\"cmp\")\n\n    if cmp.get_selected_index() ~= nil then\n        return cmp.select_next_item()\n    end\n\n    if copilot.is_visible() then\n        return copilot.accept()\n    end\n\n    if cmp.visible() then\n        return cmp.select_next_item()\n    end\n\n    if vim.api.nvim_get_mode().mode == \"i\" then\n        vim.fn.feedkeys(\"\\t\")\n        return\n    end\nend\n\n-- Enter completion\n-- Again, some advanced logic to simplify completion usage\n--   If there is SELECTED completion, accept it\n--   Feed enter key otherwise\nfunction enter_complete()\n    local cmp = require(\"cmp\")\n\n    if cmp.get_selected_index() ~= nil then\n        return cmp.confirm()\n    end\n\n    vim.fn.feedkeys(\"\\n\")\nend\n\nfunction esc_complete()\n    local cmp = require(\"cmp\")\n    local copilot = require(\"copilot.suggestion\")\n\n    if cmp.visible() and copilot.is_visible() then\n        return cmp.close()\n    end\n\n    vim.fn.feedkeys(\"\\027\")\nend\n\nvim.keymap.set({ \"i\" }, \"<tab>\", tab_complete, {})\nvim.keymap.set({ \"i\" }, \"<cr>\", enter_complete, {})\nvim.keymap.set({ \"i\" }, \"<esc>\", esc_complete, {})\n\n-- Don't modify clipboard\nvim.keymap.set({ \"n\", \"v\" }, \"X\", '\"_x', {})\nvim.keymap.set({ \"n\", \"v\" }, \"c\", '\"_c', {})\nvim.keymap.set({ \"x\", \"v\" }, \"p\", 'P', {})\nvim.keymap.set({ \"x\", \"v\" }, \"P\", 'P', {})\nvim.keymap.set({ \"n\" }, \"V\", '\"_V', {})\n"
  },
  {
    "path": "config/nvim/nuitbleue.vim",
    "content": "set background=dark\n\nsource $VIMRUNTIME/colors/vim.lua\nlet g:colors_name = \"nuitbleue\"\n\nlet s:bg=\"#1d2433\"\nlet s:bg_dim=\"#1a202e\"\nlet s:bg_dim_more=\"#171c29\"\nlet s:bg_sel=\"#333e59\"\nlet s:bg_sel_hi=\"#293145\"\n\nlet s:fg=\"#bfd3ff\"\nlet s:fg_half_dim=\"#54678c\"\nlet s:fg_dim=\"#3d4a66\"\n\nlet s:red=\"#D0879D\"\nlet s:orange=\"#D0B1A2\"\nlet s:yellow=\"#CDD2AF\"\nlet s:green=\"#9FD6B6\"\nlet s:blue=\"#92b7ea\"\nlet s:purple=\"#AD9BEA\"\nlet s:pink=\"#CD9BCC\"\n\nlet s:accent_dim=\"#7C7FB7\"\n\nfunction! s:hl(group, fg, bg)\n  exec \"highlight \" . a:group . \" guifg=\" . a:fg . \" guibg=\" . a:bg\nendfunction\n\n\" Backgrounds\ncall s:hl(\"Normal\", s:fg, s:bg)\ncall s:hl(\"CursorLine\", \"NONE\", s:bg_dim)\ncall s:hl(\"CursorLineNr\", s:blue, s:bg_dim)\ncall s:hl(\"Visual\", \"NONE\", s:bg_sel)\ncall s:hl(\"SignColumn\", \"NONE\", s:bg)\ncall s:hl(\"FoldColumn\", \"NONE\", s:bg)\n\ncall s:hl(\"TabLine\", \"NONE\", s:bg_dim)\ncall s:hl(\"TabLineFill\", \"NONE\", s:bg_dim)\nhighlight TabLineFill gui=none\n\ncall s:hl(\"StatusLine\", s:purple, \"NONE\")\nhighlight StatusLine gui=none\n\ncall s:hl(\"StatusLineNC\", s:fg_dim, \"NONE\")\nhighlight StatusLineNC gui=none\n\ncall s:hl(\"NormalFloat\", \"NONE\", s:bg_dim)\ncall s:hl(\"FloatBorder\", s:bg_dim, s:bg_dim)\n\n\" Color column\ncall s:hl(\"NonText\", s:fg_dim, \"NONE\")\ncall s:hl(\"WinSeparator\", s:fg_dim, \"NONE\")\ncall s:hl(\"CursorColumn\", \"NONE\", s:fg_dim)\n\n\" Ident guide\ncall s:hl(\"IblScope\", s:accent_dim, \"NONE\")\n\n\" Cursor\ncall s:hl(\"MatchParen\", s:purple, s:bg_sel)\ncall s:hl(\"Cursor\", s:bg, s:fg_half_dim)\ncall s:hl(\"MultiCursorSign\", s:blue, \"NONE\")\n\" exec \"hi MatchParen gui=underline guisp=\" . s:purple\n\n\" Search\ncall s:hl(\"Search\",    s:yellow, \"NONE\")\ncall s:hl(\"CurSearch\", s:yellow, \"NONE\")\ncall s:hl(\"IncSearch\", s:yellow, \"NONE\")\nexec \"hi Search gui=underline guisp=\" . s:yellow\nexec \"hi CurSearch gui=underline guisp=\" . s:yellow\nexec \"hi IncSearch gui=underline guisp=\" . s:yellow\n\n\" Autocomplete menu\ncall s:hl(\"Pmenu\", s:fg, s:bg)\ncall s:hl(\"PmenuSel\", s:fg, s:bg_sel)\ncall s:hl(\"PmenuThumb\", s:fg_dim, s:fg_dim)\ncall s:hl(\"PmenuSbar\", s:red, s:bg_dim)\n\n\" Dimmed text\ncall s:hl(\"LineNr\", s:fg_dim, s:bg)\ncall s:hl(\"Comment\", s:fg_half_dim, \"NONE\")\ncall s:hl(\"Question\", s:fg_half_dim, \"NONE\")\n\n\" Trailing white space\ncall s:hl(\"EoLSpace\", s:red, \"NONE\")\nmatch EoLSpace /\\s\\+$/\n\n\" White\ncall s:hl(\"Statement\", s:fg, \"NONE\")\ncall s:hl(\"Identifier\", s:fg, \"NONE\")\n\n\" Blue (functions)\ncall s:hl(\"Function\", s:blue, \"NONE\")\ncall s:hl(\"Todo\", s:blue, \"NONE\")\ncall s:hl(\"@tag.html\", s:blue, \"NONE\")\ncall s:hl(\"@tag.xml\", s:blue, \"NONE\")\ncall s:hl(\"@tag.vue\", s:blue, \"NONE\")\ncall s:hl(\"@tag.delimiter.vue\", s:blue, \"NONE\")\ncall s:hl(\"@tag.delimiter\", s:blue, \"NONE\")\ncall s:hl(\"dosiniLabel\", s:blue, \"NONE\")\ncall s:hl(\"tomlKey\", s:blue, \"NONE\")\n\n\" Red (mutable variables)\ncall s:hl(\"@lsp.mod.mutable\", s:red, \"NONE\")\n\n\" Purple (keywords, directories, html attributes)\ncall s:hl(\"Keyword\", s:purple, \"NONE\")\ncall s:hl(\"@keyword\", s:purple, \"NONE\")\ncall s:hl(\"@keyword.repeat\", s:purple, \"NONE\")\ncall s:hl(\"@keyword.import\", s:purple, \"NONE\")\ncall s:hl(\"@keyword.exception\", s:purple, \"NONE\")\ncall s:hl(\"@keyword.conditional\", s:purple, \"NONE\")\ncall s:hl(\"@keyword.type.python\", s:purple, \"NONE\")\ncall s:hl(\"Directory\", s:purple, \"NONE\")\ncall s:hl(\"@tag.attribute.html\", s:purple, \"NONE\")\ncall s:hl(\"@tag.attribute.xml\", s:purple, \"NONE\")\ncall s:hl(\"@tag.attribute.vue\", s:purple, \"NONE\")\ncall s:hl(\"dosiniHeader\", s:purple, \"NONE\")\ncall s:hl(\"zigVarDecl\", s:purple, \"NONE\")\ncall s:hl(\"zigConditional\", s:purple, \"NONE\")\ncall s:hl(\"zigExecution\", s:purple, \"NONE\")\n\ncall s:hl(\"CfgSection\", s:purple, \"NONE\")\ncall s:hl(\"tomlTable\", s:purple, \"NONE\")\ncall s:hl(\"tomlTableArray\", s:purple, \"NONE\")\ncall s:hl(\"Title\", s:purple, \"NONE\")\n\n\" Green (strings)\ncall s:hl(\"String\", s:green, \"NONE\")\ncall s:hl(\"CfgValues\", s:green, \"NONE\")\ncall s:hl(\"CfgOnOff\", s:green, \"NONE\")\ncall s:hl(\"@punctuation.special.vue\", s:green, \"NONE\")\n\n\" Yellow (constants)\ncall s:hl(\"Constant\", s:yellow, \"NONE\")\ncall s:hl(\"@constant.bash\", s:blue, \"NONE\") \" special case\n\n\" Orange (types, classes)\ncall s:hl(\"Type\", s:orange, \"NONE\")\ncall s:hl(\"@constructor\", s:orange, \"NONE\")\ncall s:hl(\"@type.builtin\", s:orange, \"NONE\")\ncall s:hl(\"@character.rust\", s:orange, \"NONE\") \" special case to distinguish from strings\ncall s:hl(\"@character.zig\", s:orange, \"NONE\")\n\n\" Pink (special, rare, important, builtins)\ncall s:hl(\"Special\", s:pink, \"NONE\")\ncall s:hl(\"PreProc\", s:pink, \"NONE\")\ncall s:hl(\"@boolean\", s:pink, \"NONE\")\ncall s:hl(\"@constant.html\", s:pink, \"NONE\")\ncall s:hl(\"@lsp.type.builtin.zig\", s:pink, \"NONE\")\ncall s:hl(\"zigBuiltinFn\", s:pink, \"NONE\")\ncall s:hl(\"zigNull\", s:pink, \"NONE\")\ncall s:hl(\"@keyword.import.zig\", s:pink, \"NONE\")\n\n\" Disabled\ncall s:hl(\"Delimiter\", s:fg_half_dim, \"NONE\")\ncall s:hl(\"Operator\", s:fg_half_dim, \"NONE\")\ncall s:hl(\"@constructor.lua\", s:fg_half_dim, \"NONE\")\ncall s:hl(\"@tag.delimiter.html\", s:fg_half_dim, \"NONE\")\ncall s:hl(\"dosiniSection\", s:fg_half_dim, \"NONE\")\ncall s:hl(\"Conceal\", s:red, s:green)\n\n\" Diagnostic\ncall s:hl(\"DiagnosticError\", s:red, \"NONE\")\ncall s:hl(\"Error\", s:red, \"NONE\")\ncall s:hl(\"ErrorMsg\", s:red, \"NONE\")\ncall s:hl(\"DiagnosticOk\", s:green, \"NONE\")\n\ncall s:hl(\"DiagnosticWarn\", s:orange, \"NONE\")\ncall s:hl(\"WarningMsg\", s:orange, \"NONE\")\nexec \"highlight SpellBad\" . \" guisp=\" . s:orange\n\ncall s:hl(\"DiagnosticInfo\", s:fg_half_dim, \"NONE\")\ncall s:hl(\"DiagnosticHint\", s:fg_half_dim, \"NONE\")\n\nexec \"highlight DiagnosticUnderlineHint gui=NONE\"\nexec \"highlight DiagnosticUnderlineInfo gui=NONE\"\nexec \"highlight DiagnosticUnderlineWarn gui=NONE\"\nexec \"highlight DiagnosticUnderlineError gui=NONE\"\n\n\" Notifications\ncall s:hl(\"NotifyBackground\", s:bg_dim, s:bg_dim)\ncall s:hl(\"NotifyERRORBody\", s:red, s:bg_dim)\ncall s:hl(\"NotifyERRORBorder\", s:bg_dim, s:bg_dim)\ncall s:hl(\"NotifyERRORIcon\", s:red, \"NONE\")\ncall s:hl(\"NotifyERRORTitle\", s:red, \"NONE\")\n\ncall s:hl(\"NotifyWARNBody\", s:bg_dim, s:bg_dim)\ncall s:hl(\"NotifyWARNBorder\", s:bg_dim, s:bg_dim)\ncall s:hl(\"NotifyWARNIcon\", s:orange, \"NONE\")\ncall s:hl(\"NotifyWARNTitle\", s:orange, \"NONE\")\n\ncall s:hl(\"NotifyINFOBody\", s:bg_dim, s:bg_dim)\ncall s:hl(\"NotifyINFOBorder\", s:bg_dim, s:bg_dim)\ncall s:hl(\"NotifyINFOIcon\", s:blue, \"NONE\")\ncall s:hl(\"NotifyINFOTitle\", s:blue, \"NONE\")\n\ncall s:hl(\"NotifyDEBUGBody\", s:bg_dim, s:bg_dim)\ncall s:hl(\"NotifyDEBUGBorder\", s:bg_dim, s:bg_dim)\ncall s:hl(\"NotifyDEBUGIcon\", s:fg_dim, \"NONE\")\ncall s:hl(\"NotifyDEBUGTitle\", s:fg_dim, \"NONE\")\n\ncall s:hl(\"NotifyTRACEBody\", s:bg_dim, s:bg_dim)\ncall s:hl(\"NotifyTRACEBorder\", s:bg_dim, s:bg_dim)\ncall s:hl(\"NotifyTRACEIcon\", s:fg_dim, \"NONE\")\ncall s:hl(\"NotifyTRACETitle\", s:fg_dim, \"NONE\")\n\n\" Diff\ncall s:hl(\"DiffAdd\", s:green, \"NONE\")\ncall s:hl(\"GitSignsAdd\", s:green, \"NONE\")\ncall s:hl(\"GitSignsStagedAdd\", s:green, \"NONE\")\ncall s:hl(\"GitSignsStagedAddNr\", s:green, \"NONE\")\n\ncall s:hl(\"DiffChange\", s:purple, \"NONE\")\ncall s:hl(\"Changed\", s:purple, \"NONE\")\ncall s:hl(\"GitSignsChange\", s:purple, \"NONE\")\ncall s:hl(\"GitSignsStagedChange\", s:purple, \"NONE\")\ncall s:hl(\"GitSignsStagedChangeNr\", s:purple, \"NONE\")\n\ncall s:hl(\"DiffDelete\", s:red, \"NONE\")\ncall s:hl(\"Removed\", s:red, \"NONE\")\ncall s:hl(\"GitSignsDelete\", s:red, \"NONE\")\ncall s:hl(\"GitSignsStagedDelete\", s:red, \"NONE\")\ncall s:hl(\"GitSignsStagedDeleteNr\", s:red, \"NONE\")\n\n\" Language:Markdown\ncall s:hl(\"@markup.list.markdown\", s:fg_dim, \"NONE\")\ncall s:hl(\"@markup.list.checked.markdown\", s:fg_dim, \"NONE\")\ncall s:hl(\"@markup.list.unchecked.markdown\", s:red, \"NONE\")\ncall s:hl(\"@markup.raw.markdown_inline\", s:green, \"NONE\")\ncall s:hl(\"@markup.raw.block.markdown\", s:fg_half_dim, \"NONE\")\ncall s:hl(\"@label.markdown\", s:orange, \"NONE\")\ncall s:hl(\"@markup.quote.markdown\", s:fg, \"NONE\")\nhi @markup.quote.markdown gui=italic\ncall s:hl(\"@punctuation.special.markdown\", s:fg_half_dim, \"NONE\")\ncall s:hl(\"@markup.link.url.markdown_inline\", s:fg_half_dim, \"NONE\")\ncall s:hl(\"@markup.link.label.markdown_inline\", s:blue, \"NONE\")\nhi @markup.link.url.markdown_inline gui=underline\n\n\" Language:calendar\ncall s:hl(\"calendarMonth\", s:purple, \"NONE\")\n\n\" Plugin:Telescope\ncall s:hl(\"TelescopeNormal\", s:fg, s:bg_dim)\ncall s:hl(\"TelescopeBorder\", s:bg_dim, s:bg_dim)\n\ncall s:hl(\"TelescopePromptNormal\", s:fg, s:bg_dim_more)\ncall s:hl(\"TelescopePromptTitle\", s:fg, s:bg_dim_more)\ncall s:hl(\"TelescopePromptBorder\", s:bg_dim_more, s:bg_dim_more)\n\ncall s:hl(\"TelescopePreviewBorder\", s:bg_dim, s:bg_dim)\ncall s:hl(\"TelescopePreviewTitle\", s:bg_dim, s:bg_dim)\n\ncall s:hl(\"TelescopeSelectionCaret\", s:bg_sel, s:bg_sel)\n\n\" Plugin:Noice\ncall s:hl(\"NoiceCmdlinePopup\", s:fg, s:bg_dim)\ncall s:hl(\"NoiceCmdlinePopupBorder\", s:bg_dim, s:bg_dim)\ncall s:hl(\"NoicePopup\", \"NONE\", s:bg_dim)\n\n\" Plugin:Diagflow\ncall s:hl(\"DiagnosticFloatingError\", s:red, s:bg_dim)\ncall s:hl(\"DiagnosticFloatingWarn\", s:orange, s:bg_dim)\ncall s:hl(\"DiagnosticFloatingOK\", s:fg_half_dim, s:bg_dim)\ncall s:hl(\"DiagnosticFloatingInfo\", s:fg_half_dim, s:bg_dim)\ncall s:hl(\"DiagnosticFloatingHint\", s:fg_half_dim, s:bg_dim)\n\n\" Plugin:LocalHighlight\ncall s:hl(\"LocalHighlight\", \"NONE\", s:bg_sel_hi)\n\n\" Plugin:Oil\ncall s:hl(\"OilFile\", s:blue, \"NONE\")\n"
  },
  {
    "path": "config/paru/paru.conf",
    "content": "[options]\nAurOnly\nSortBy=votes\nSkipReview\n\n# Skip check step and dependencies\nNoCheck\n\n# Exit after first package build failed\nFailFast\n\n# Update \"devel\" packages\nDevel\nDevelSuffixes = -git -cvs -svn -bzr -darcs -always -hg -fossil\n"
  },
  {
    "path": "config/postgres/psqlrc",
    "content": "\\set QUIET 1\n\n-- Prompt (database ❯)\n\\set PROMPT1 ' %[%033[34m%]%/%[%033[37m%] ❯%[%033[0m%] '\n\n-- Table style\n-- border with outer lines\n\\pset border 2\n-- ascii borders -- renders well in code blocks and looks okay\n\\pset linestyle ascii\n\\pset null '∅'\n\n-- Other options\n\\set ON_ERROR_STOP on\n\\set VERBOSITY verbose\n\n-- Change application name for debugging\nset application_name to psql;\n\n-- Enable command timing\n\\timing on\n\n\\unset QUIET\n"
  },
  {
    "path": "config/pypoetry/config.toml",
    "content": "[installer]\nmax-workers = 16\n\n[keyring]\nenabled = false\n\n[virtualenvs]\nin-project = true\nprefer-active-python = true\n\n  [virtualenvs.options]\n  no-pip = true\n  no-setuptools = true\n"
  },
  {
    "path": "config/ruff/ruff.toml",
    "content": "# NOTE: to use this configuration with local config file\n#       you'll need to add `extend = \"~/.config/ruff/ruff.toml\"` there\n#       see https://github.com/astral-sh/ruff/discussions/16516\n\nline-length = 80\ntarget-version = \"py314\"\n\n[format]\n  line-ending = \"lf\"\n  docstring-code-format = true\n\n[lint]\n  select = [ \"ALL\" ]\n  fixable = [ \"ALL\" ]\n  ignore = [\n    # Documentation\n    \"D\",\n\n    # Formatter rules\n    \"COM812\", \"ISC001\",\n\n    # TODO notes\n    \"FIX002\",  # Ignore TODO, and HACK, but lint FIXME\n    \"FIX004\",  # ^\n    \"TD001\",   # ^\n    \"TD002\",   # Do not ask for TODO's author and issue link\n    \"TD003\",   # ^\n\n    # __init__.py\n    \"INP001\",\n\n    # Controversial\n    \"SIM118\",  # `key in dict.keys()` is better than `key in dict`\n    \"T201\",    # Yeah it's bad in finished products, but in most scripts and\n               # while debugging it's really annoying\n    \"RET504\",  # Naming result before returning can improve readability\n  ]\n\n[lint.isort]\n  force-sort-within-sections = false\n\n[lint.flake8-bugbear]\n  extend-immutable-calls = [\"fastapi.Depends\", \"fastapi.Query\", \"fastapi.params.Query\"]\n\n[lint.flake8-builtins]\n  builtins-ignorelist = [\"id\"]\n\n[lint.flake8-quotes]\n  avoid-escape = false\n\n[lint.per-file-ignores]\n  \"tests/**/*.py\" = [\n    \"S101\",    # Asserts are necessary in tests\n    \"PLR2004\", # Magic values are useful in tests\n  ]\n  \"tests/**/test_bench_*.py\" = [\n    \"ANN001\",  # Allows usage of benchmark fixture\n  ]\n"
  },
  {
    "path": "config/ssh/authorized_keys",
    "content": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGucK2JUauI8z8ghO5AzutHt8G6G7mZe2n1Ri6wWhcSs zeta\nssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMcy3e1Fwb1VloEWSTQNFbZCVhBh1ky4eKEERHvCxFPx xi\nssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGrKycMDC9eFJd1Y8jMdXXux1PXCvzSpRB/3pbA8yKZm iota\nssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG3HwhJT74a+T63HO38F5Vz4BvUgKC2+tQmoa2DKc/fQ tau\n"
  },
  {
    "path": "config/ssh/config",
    "content": "# vim: set ft=sshconfig\n\nHost lambda lambda.cj.dog\n    User cj\n    Port 1022\n\nHost *.cj.dog\n    User cj\n\nHost voyager\n    Port 2206\n\nHost *\n    # If user is unspecified, connect as root\n    User root\n    ExitOnForwardFailure yes\n\n    # Security\n    StrictHostKeyChecking accept-new\n    HashKnownHosts yes\n\n    # Avoid unnecessary output\n    LogLevel QUIET\n\n    # Network options\n    ConnectTimeout 5\n    ConnectionAttempts 3\n\n    Compression yes\n    IPQoS lowdelay\n    AddressFamily inet\n\n    # Multiplexing\n    ControlMaster auto\n    ControlPersist 15m\n    ControlPath ~/.ssh/control/%h-%p-%r\n\n    # Keepalive\n    TCPKeepAlive yes\n    ServerAliveInterval 3\n    ServerAliveCountMax 20\n"
  },
  {
    "path": "config/sway/config",
    "content": "# Update user's systemd environment variables\ninclude /etc/sway/config.d/*\n\n# Startup\nexec foot --server --log-level=none\nexec waybar\n\n# Disable X11 support\nxwayland disable\n\n# Configure outputs\noutput \"*\" {\n  mode \"2880x1620@60Hz\"\n  background \"${repo}/wallpaper.png\" fill\n}\n\nseat \"*\" {\n  xcursor_theme capitaine-cursors-light 32\n  hide_cursor when-typing enable\n}\n\ninput type:keyboard {\n  xkb_layout \"us,ru\"\n  xkb_options \"grp:caps_toggle,grp_led:caps,compose:ralt\"\n\n  repeat_delay 250\n  repeat_rate 20\n}\n\ninput \"*\" {\n  tap enabled\n\n  pointer_accel 0.25\n  scroll_factor 0.15\n  natural_scroll enabled\n  drag_lock disabled\n  dwt disabled  # do not disable while typing\n}\n\n# Options\nfloating_modifier Mod4\n\n# Look and feel\ndefault_border pixel 2\nsmart_borders on\npopup_during_fullscreen ignore\n\nclient.focused #${blue} #${blue} #${bg} #${purple}\nclient.urgent #${red} #${red} #${bg}\nclient.focused_inactive #${bg} #${bg} #${fg_half_dim}\nclient.unfocused #${bg} #${bg} #${fg_half_dim}\n\n# Hotkeys: windows\nbindsym --to-code Mod4+w focus up\nbindsym --to-code Mod4+a focus left\nbindsym --to-code Mod4+s focus down\nbindsym --to-code Mod4+d focus right\n\nbindsym --to-code Mod4+Shift+w move up\nbindsym --to-code Mod4+Shift+a move left\nbindsym --to-code Mod4+Shift+s move down\nbindsym --to-code Mod4+Shift+d move right\n\n# Hotkeys: Scratchpads\nbindsym --to-code Mod4+Shift+e mark \"scratchpad-e\", move scratchpad\nbindsym --to-code Mod4+e [con_mark=\"scratchpad-e\"] scratchpad show\n\nbindsym --to-code Mod4+Shift+tab mark \"scratchpad-tab\", move scratchpad\nbindsym --to-code Mod4+tab [con_mark=\"scratchpad-tab\"] scratchpad show\n\nbindsym --to-code Mod4+Shift+c mark \"scratchpad-c\", move scratchpad\nbindsym --to-code Mod4+c [con_mark=\"scratchpad-c\"] scratchpad show\n\n# Hotkeys: control\n\nbindsym --to-code Mod4+f fullscreen toggle\nbindsym --to-code Mod4+g floating toggle\nbindsym --to-code Mod4+q kill\n\n# Hotkeys: split\nbindsym --to-code Mod4+h split h\nbindsym --to-code Mod4+v split v\n\n# Hotkeys: sway\nbindsym --to-code Mod4+Alt+r reload\nbindsym --to-code Mod4+Alt+q exit\nbindsym --to-code Mod4+Alt+x exit\n\n# Hotkeys: workspaces\nbindsym --to-code Mod4+1 workspace 1\nbindsym --to-code Mod4+2 workspace 2\nbindsym --to-code Mod4+3 workspace 3\nbindsym --to-code Mod4+4 workspace 4\nbindsym --to-code Mod4+5 workspace 5\nbindsym --to-code Mod4+6 workspace 6\nbindsym --to-code Mod4+7 workspace 7\nbindsym --to-code Mod4+8 workspace 8\nbindsym --to-code Mod4+9 workspace 9\nbindsym --to-code Mod4+0 workspace 10\nbindsym --to-code Mod4+minus workspace 11\nbindsym --to-code Mod4+equal workspace 12\n\nbindsym --to-code Mod4+Shift+1 move window to workspace 1\nbindsym --to-code Mod4+Shift+2 move window to workspace 2\nbindsym --to-code Mod4+Shift+3 move window to workspace 3\nbindsym --to-code Mod4+Shift+4 move window to workspace 4\nbindsym --to-code Mod4+Shift+5 move window to workspace 5\nbindsym --to-code Mod4+Shift+6 move window to workspace 6\nbindsym --to-code Mod4+Shift+7 move window to workspace 7\nbindsym --to-code Mod4+Shift+8 move window to workspace 8\nbindsym --to-code Mod4+Shift+9 move window to workspace 9\nbindsym --to-code Mod4+Shift+0 move window to workspace 10\nbindsym --to-code Mod4+Shift+minus move window to workspace 11\nbindsym --to-code Mod4+Shift+equal move window to workspace 12\n\n# Hotkeys: applications\nbindsym --to-code Mod4+j exec footclient\nbindsym --to-code Mod4+r exec fuzzel\nbindsym --to-code Mod4+b exec firefox\nbindsym --to-code Mod4+n exec makoctl dismiss --all\n\n# Hotkeys: locking\nbindsym --to-code Mod4+l exec swaylock\nbindsym --no-repeat --release --locked --to-code Mod4+k output eDP-1 dpms toggle\n\n# Hotkeys: audio\nbindsym --locked XF86AudioMute exec wpctl set-mute \\@DEFAULT_SINK@ toggle\nbindsym --locked XF86AudioLowerVolume exec wpctl set-volume \\@DEFAULT_SINK@ 5%-\nbindsym --locked XF86AudioRaiseVolume exec wpctl set-volume \\@DEFAULT_SINK@ 5%+\n\n# Hotkeys: mic\nbindsym --locked XF86AudioMicMute exec wpctl set-mute \\@DEFAULT_SOURCE@ toggle\nbindsym --locked F7 exec wpctl set-mute \\@DEFAULT_SOURCE@ toggle\n\n# Hotkeys: media\nbindsym --locked XF86AudioPlay exec playerctl play-pause\nbindsym --locked XF86AudioPause exec playerctl play-pause\nbindsym --locked XF86AudioNext exec playerctl next\nbindsym --locked XF86AudioPrev exec playerctl previous\n\n# Hotkeys: brightness\nbindsym --locked XF86MonBrightnessDown exec brightnessctl -e set 5%-\nbindsym --locked XF86MonBrightnessUp exec brightnessctl -e set 5%+\n\n# Hotkeys: screenshots\nbindsym --locked Print exec slurp -b ${fg_dim}20 -c ${fg_dim}30 -w 1 | grim -g - - | wl-copy\nbindsym --locked F12 exec slurp -b ${fg_dim}20 -c ${fg_dim}30 -w 1 | grim -g - - | wl-copy\n\n# Switches. On is closed, off is open\nbindswitch --locked --reload lid:off exec swaymsg \"output * dpms on\"\nbindswitch --locked --reload lid:on exec swaymsg \"output * dpms off\"\n"
  },
  {
    "path": "config/swaylock/config",
    "content": "ignore-empty-password\nshow-failed-attempts\nclock\nimage=${repo}/wallpaper.png\neffect-blur=10x1\nhide-keyboard-layout\nfont=Noto Sans Mono Light\nfont-size=100\ntimestr=%R\ndatestr=%d %b\n\nindicator-x-position=300\n\nindicator-idle-visible\nindicator-radius=200\nindicator-thickness=20\n\ninside-color=00000000\ninside-clear-color=00000000\ninside-ver-color=00000000\ninside-wrong-color=00000000\nkey-hl-color=${blue}50\nbs-hl-color=${red}50\nline-uses-inside\n\nseparator-color=00000000\n\nring-color=00000000\nring-ver-color=${blue}50\nring-wrong-color=${red}80\nring-clear-color=${green}50\n\ntext-color=${fg}\ntext-ver=\ntext-wrong=\ntext-clear=\n"
  },
  {
    "path": "config/termux/colors.properties",
    "content": "background : #${bg}\nforeground : #${fg}\ncolor0  : #${bg}\ncolor1  : #${red}\ncolor2  : #${green}\ncolor3  : #${yellow}\ncolor4  : #${blue}\ncolor5  : #${purple}\ncolor6  : #${cyan}\ncolor7  : #${fg_half_dim}\ncolor8  : #${fg_dim}\ncolor9  : #${orange}\ncolor10 : #${green}\ncolor11 : #${yellow}\ncolor12 : #${blue}\ncolor13 : #${pink}\ncolor14 : #${cyan}\ncolor15 : #${fg}\n"
  },
  {
    "path": "config/termux/termux.properties",
    "content": "back-key=back\nextra-keys=[['\\`','ESC','TAB','CTRL','LEFT','DOWN','UP','RIGHT']]\nterminal-margin-horizontal=0\nterminal-margin-vertical=0\n"
  },
  {
    "path": "config/tmux/tmux.conf",
    "content": "# Options\nset -sg terminal-overrides \",*:RGB\"  # true color support\nset -g escape-time 0  # disable delays on escape sequences\nset -g mouse on\nset -g renumber-windows on  # keep numbering sequential\nset -g repeat-time 1000  # increase \"prefix-free\" window\n\n# Options: start indexes from 1\nset -g base-index 1\nset -g pane-base-index 1\n\n# Change prefix\nunbind C-b\nset -g prefix `\nbind ` send-prefix\n\n# Theme: borders\nset -g pane-border-lines simple\nset -g pane-border-style fg=black,bright\nset -g pane-active-border-style fg=magenta\n\n# Theme: status\nset -g status-style bg=default,fg=black,bright\nset -g status-left \"\"\nset -g status-right \"#[fg=black,bright]#S\"\n\n# Theme: status (windows)\nset -g window-status-format \"●\"\nset -g window-status-current-format \"●\"\n\nset -g window-status-current-style \"#{?window_zoomed_flag,fg=yellow,fg=magenta\\#,nobold}\"\nset -g window-status-bell-style \"fg=red,nobold\"\n\n# Keybindings: wasd\nbind w select-pane -U\nbind a select-pane -L\nbind s select-pane -D\nbind d select-pane -R\n\nbind -r W resize-pane -U\nbind -r A resize-pane -L\nbind -r S resize-pane -D\nbind -r D resize-pane -R\n\n# Keybindings: disable repeat for arrows\nbind Up select-pane -U\nbind Left select-pane -L\nbind Down select-pane -D\nbind Right select-pane -R\n\n# Keybindings: split\nbind h split-window -h\nbind | split-window -h\nbind v split-window -v\nbind - split-window -v\n\n# Keybindings: windows\nbind -n C-Tab next-window\nbind -n C-S-Tab previous-window\n\nbind -n M-1 select-window -t :1\nbind -n M-2 select-window -t :2\nbind -n M-3 select-window -t :3\nbind -n M-4 select-window -t :4\nbind -n M-5 select-window -t :5\nbind -n M-6 select-window -t :6\nbind -n M-7 select-window -t :7\nbind -n M-8 select-window -t :8\nbind -n M-9 select-window -t :9\n\n# Keybindings: other\nbind f resize-pane -Z\nbind q detach-client\nbind e choose-window -Z\n\nbind -n M-w select-pane -U\nbind -n M-a select-pane -L\nbind -n M-s select-pane -D\nbind -n M-d select-pane -R\nbind -n M-f resize-pane -Z\n"
  },
  {
    "path": "config/waybar/config",
    "content": "{\n  \"layer\": \"top\", // don't dim in special workspaces\n\n  \"modules-left\": [],\n\n  \"modules-center\": [\n    \"niri/workspaces\",\n  ],\n\n  \"modules-right\": [\n    \"battery\",\n    \"pulseaudio\",\n    \"niri/language\",\n    \"clock\",\n  ],\n\n  \"niri/workspaces\": {\n    \"format\": \"{icon}\",\n    \"format-icons\": {\n      \"1\": \"1\",\n      \"2\": \"2\",\n      \"3\": \"3\",\n      \"4\": \"4\",\n      \"5\": \"5\",\n      \"6\": \"6\",\n      \"7\": \"7\",\n      \"8\": \"8\",\n      \"9\": \"\",\n      \"13\": \"\", // no icon for default empty workspace\n\n      \"obs\": \"󰕧\",\n      \"msg\": \"\",\n      \"tab\": \"\",\n    }\n  },\n\n  \"battery\": {\n    \"format\": \"{icon} {capacity}%\",\n    \"format-charging\": \"󰂄 {capacity}%\",\n\n    \"tooltip-format\": \"{timeTo} | {power}w\",\n    \"format-icons\": [ \"󰂃\", \"󰂎\", \"󰁺\", \"󰁻\", \"󰁼\", \"󰁽\", \"󰁾\", \"󰁿\", \"󰂀\", \"󰂁\", \"󰂂\", \"󰁹\" ],\n\n    \"states\": {\n      \"critical\": 10,\n      \"warning\": 25,\n      \"low\": 50,\n      \"full\": 100,\n    },\n  },\n\n  \"pulseaudio\": {\n    \"format\": \"{format_source}{icon} {volume}%\",\n    \"format-muted\": \"{format_source}󰝟\",\n\n    \"format-source\": \"<span color='#${red}'>󰍬 on</span>  \",  // red\n    \"format-source-muted\": \"\",\n\n    \"format-icons\": {\n      \"default\": [ \"󰕿\", \"󰖀\", \"󰕾\", \"󱄠\" ],\n    },\n\n    \"tooltip\": false,\n    \"on-click\": \"pavucontrol\",\n    \"on-click-right\": \"wpctl set-mute @DEFAULT_SINK@ toggle\",\n  },\n\n  \"niri/language\": {\n    \"format\": \"󰌌 {}\",\n    \"format-en\": \"us\",\n    \"format-ru\": \"ru\",\n    \"format-th\": \"th\",\n\n    \"keyboard-name\": \"keyd-virtual-keyboard\",\n  },\n\n  \"clock\": {\n    \"timezone\": \"Asia/Bangkok\",\n    \"format\": \"󰅐 {:%H:%M}\",\n\n    \"tooltip\": true,\n    \"tooltip-format\": \"{:%e %B, %A}\",  // 2 April, Saturday\n\n    \"on-click\": \"footclient --hold when ci\"\n  },\n}\n"
  },
  {
    "path": "config/waybar/style.css",
    "content": "#waybar {\n  background: #${bg};\n  color: #${fg};\n  font-family: \"Noto Sans Mono Light\";\n  font-size: 14px;\n  font-feature-settings: \"calt\";\n}\n\n/* padding */\n\n#workspaces,\n#backlight,\n#battery,\n#pulseaudio,\n#language,\n#clock {\n  padding: 6px 10px;\n}\n#workspaces {\n  padding-left: 16px;\n}\n\n#clock {\n  padding-right: 20px;\n}\n\n/* clock */\n\n#clock:hover {\n  color: #AD9BEA;\n}\n\n/* pulseaudio */\n\n#pulseaudio:hover {\n  color: #AD9BEA;\n}\n\n/* workspaces */\n\n#workspaces button.empty {\n  opacity: 0.25;\n  font-size: 0;\n  margin-left: -10px;\n  margin-right: -10px;\n  padding: 0;\n}\n\n#workspaces button.empty.active {\n  opacity: 1.0;\n}\n\n#workspaces button {\n  color: #${fg_dim};\n\n  border: none;\n  border-radius: 0;\n\n  font-size: 24px;\n  padding: 0 16px;\n  margin-left: 2px;\n  margin-right: 2px;\n}\n\n#workspaces button.active, #workspaces button.focused {\n  color: #${blue};\n  border-bottom: 5px solid #${blue};\n  margin-bottom: -5px;\n\n  padding: 0 16px;\n  font-size: 24px;\n  margin-left: 2px;\n  margin-right: 2px;\n}\n\n#workspaces button.urgent {\n  color: #${red};\n  border-bottom: 5px solid #${red};\n  margin-bottom: -5px;\n\n  padding: 0 16px;\n  font-size: 24px;\n  margin-left: 2px;\n  margin-right: 2px;\n}\n\n#workspaces button:hover {\n  background: none;\n  color: #${purple};\n\n  /* SEE https://github.com/Alexays/Waybar/issues/60 */\n  box-shadow: inherit;\n  text-shadow: inherit;\n}\n\n/* battery */\n\n#battery.critical {\n  color: #${red};\n}\n\n#battery.warning {\n  color: #${orange};\n}\n\n#battery.low {\n  color: #${yellow};\n}\n\n#battery.charging {\n  color: #${green};\n}\n"
  },
  {
    "path": "config/wofi/config",
    "content": "mode=drun\nprompt=\n\nwidth=100%\nheight=100%\nxoffset=0\nyoffset=0\n\nhide_scroll=true\nno_actions=true\n\ninsensitive=true\nhalign=start\ncontent_halign=start\nfilter_rate=25\n"
  },
  {
    "path": "config/wofi/style.css",
    "content": "* {\n  background: none;\n  color: #${fg};\n  border: none;\n  outline: none;\n  box-shadow: none;\n  font: Noto Sans Mono Light;\n  font-size: 24px;\n}\n\n#window {\n  background: rgba(29, 36, 51, 0.75);  /* bg with opacity */\n}\n\n#input {\n  padding: 24px;\n}\n\n#input * {\n  color: transparent;\n}\n\n#outer-box {\n  margin: 24px;\n}\n\n#inner-box {\n  margin-left: 48px;\n}\n\n#entry {\n  padding: 8px;\n}\n\n#entry:selected * {\n  color: #${blue};\n}\n"
  },
  {
    "path": "config/x11/xcompose",
    "content": "include \"%L\"\n\n# === Math ===\n<Multi_key> <plus> <minus> : \"±\"\n<Multi_key> <minus> <plus> : \"∓\"\n\n<Multi_key> <x> <x>     : \"×\"\n<Multi_key> <m> <u> <l> : \"⋅\"\n\n<Multi_key> <slash> <equal> : \"≠\"\n<Multi_key> <equal> <slash> : \"≠\"\n\n<Multi_key> <asciitilde> <asciitilde> : \"≈\"\n<Multi_key> <asciitilde> <equal>      : \"≈\"\n\n<Multi_key> <slash> <asciitilde> : \"≉\"\n<Multi_key> <asciitilde> <slash> : \"≉\"\n\n<Multi_key> <less> <equal> : \"≤\"\n<Multi_key> <equal> <less> : \"≤\"\n\n<Multi_key> <greater> <equal> : \"≥\"\n<Multi_key> <equal> <greater> : \"≥\"\n\n<Multi_key> <0> <0> : \"∞\"\n<Multi_key> <o> <o> : \"∞\"\n\n<Multi_key> <asciicircum> <0> : \"°\"\n<Multi_key> <0> <asciicircum> : \"°\"\n\n<Multi_key> <p> <r> <o> <d> : \"∏\"\n<Multi_key> <s> <u> <m> : \"∑\"\n\n# === Arrows ===\n<Multi_key> <asciicircum> <bar> : \"↑\"\n<Multi_key> <bar> <asciicircum> : \"↑\"\n\n<Multi_key> <bar> <v> : \"↓\"\n<Multi_key> <v> <bar> : \"↓\"\n\n# === Esperanto ===\n<Multi_key> <c> <asciicircum> : \"ĉ\"\n<Multi_key> <c> <x>           : \"ĉ\"\n<Multi_key> <g> <asciicircum> : \"ĝ\"\n<Multi_key> <g> <x>           : \"ĝ\"\n<Multi_key> <j> <asciicircum> : \"ĵ\"\n<Multi_key> <j> <x>           : \"ĵ\"\n<Multi_key> <s> <asciicircum> : \"ŝ\"\n<Multi_key> <s> <x>           : \"ŝ\"\n<Multi_key> <u> <asciicircum> : \"û\"\n<Multi_key> <u> <x>           : \"û\"\n\n<Multi_key> <C> <asciicircum> : \"Ĉ\"\n<Multi_key> <C> <x>           : \"Ĉ\"\n<Multi_key> <G> <asciicircum> : \"Ĝ\"\n<Multi_key> <G> <x>           : \"Ĝ\"\n<Multi_key> <J> <asciicircum> : \"Ĵ\"\n<Multi_key> <J> <x>           : \"Ĵ\"\n<Multi_key> <S> <asciicircum> : \"Ŝ\"\n<Multi_key> <S> <x>           : \"Ŝ\"\n<Multi_key> <U> <asciicircum> : \"Û\"\n<Multi_key> <U> <x>           : \"Û\"\n\n# === French ===\n<Multi_key> <asciicircum> <o> : \"ô\"\n<Multi_key> <o> <asciicircum> : \"ô\"\n<Multi_key> <o> <x>           : \"ô\"\n\n<Multi_key> <asciicircum> <O> : \"Ô\"\n<Multi_key> <O> <asciicircum> : \"Ô\"\n<Multi_key> <O> <x>           : \"Ô\"\n\n# === Bullets ===\n<Multi_key> <minus> <v> : \"✓\"\n<Multi_key> <minus> <x> : \"✗\"\n<Multi_key> <minus> <o> : \"•\"\n<Multi_key> <minus> <bracketleft> : \"□\"\n\n<Multi_key> <bracketleft>     <bracketright> : \"☐\"\n<Multi_key> <bracketleft> <v> <bracketright> : \"☑\"\n<Multi_key> <bracketleft> <x> <bracketright> : \"☒\"\n"
  },
  {
    "path": "config/xdg/mimeapps.list",
    "content": "[Default Applications]\nx-scheme-handler/http=google-chrome-unstable.desktop\nx-scheme-handler/https=google-chrome-unstable.desktop\nx-scheme-handler/chrome=google-chrome-unstable.desktop\ntext/html=google-chrome-unstable.desktop\napplication/x-extension-htm=google-chrome-unstable.desktop\napplication/x-extension-html=google-chrome-unstable.desktop\napplication/x-extension-shtml=google-chrome-unstable.desktop\napplication/xhtml+xml=google-chrome-unstable.desktop\napplication/x-extension-xhtml=google-chrome-unstable.desktop\napplication/x-extension-xht=google-chrome-unstable.desktop\n\napplication/pdf=org.pwmt.zathura.desktop\n"
  },
  {
    "path": "config/xdg/user-dirs.dirs",
    "content": "XDG_DESKTOP_DIR=\"$HOME/\"\nXDG_DOWNLOAD_DIR=\"$HOME/downloads\"\nXDG_TEMPLATES_DIR=\"$HOME/\"\nXDG_PUBLICSHARE_DIR=\"$HOME/\"\nXDG_DOCUMENTS_DIR=\"$HOME/\"\nXDG_MUSIC_DIR=\"$HOME/\"\nXDG_PICTURES_DIR=\"$HOME/\"\nXDG_VIDEOS_DIR=\"$HOME/\"\n"
  },
  {
    "path": "config/xdg-desktop-portal-wlr/config",
    "content": "[screencast]\noutput_name=eDP-1\nchooser_type=none\n"
  },
  {
    "path": "config/xkb/rules/evdev",
    "content": "! include %S/evdev\n\n! layout[1] option = symbols\n* grp:caps_toggle12 = +group(caps_will_switch_to_second_layout):1\n\n! layout[2] option = symbols\n* grp:caps_toggle12 = +group(caps_will_switch_to_first_layout):2\n\n! layout[3] option = symbols\n* grp:caps_toggle12 = +group(caps_will_switch_to_first_layout):3\n"
  },
  {
    "path": "config/xkb/symbols/group",
    "content": "partial xkb_symbols \"caps_will_switch_to_first_layout\" {\n  replace key <CAPS> { [ ISO_First_Group ] };\n};\n\npartial xkb_symbols \"caps_will_switch_to_second_layout\" {\n  // NOTE: name is ISO_Last_Group but it maps to the second group\n  replace key <CAPS> { [ ISO_Last_Group ] };\n};\n"
  },
  {
    "path": "config/zathura/zathurarc",
    "content": "# === Keybindings ===\nmap w scroll up\nmap a scroll left\nmap s scroll down\nmap d scroll right\n\nmap W scroll half-up\nmap A scroll left\nmap S scroll half-down\nmap D scroll right\n\nmap <PageUp> scroll half-up\nmap <PageDown> scroll half-down\n\nmap r set recolor\nmap R reload\nmap f adjust_window width\n\nmap Z zoom in\nmap z zoom out\n\n# === Options ===\nset guioptions \"\"\nset font \"Noto Sans Mono Light 11\"\nset adjust-open width\nset database plain\nset dbus-service false\nset page-cache-size 32\nset show-recent false\nset selection-clipboard secondary\nset sandbox strict\nset page-padding 16\n\n# === Colors ===\nset default-bg \\#${bg_dim}\nset completion-bg \\#${bg}\nset completion-fg \\#${fg}\nset inputbar-bg \\#${bg}\nset inputbar-fg \\#${fg}\nset completion-group-bg \\#${bg}\nset completion-group-fg \\#${fg}\nset tabbar-bg \\#${bg}\nset tabbar-fg \\#${fg}\nset statusbar-bg \\#${bg}\nset statusbar-fg \\#${fg}\nset index-bg \\#${bg}\nset index-fg \\#${fg}\n\nset completion-highlight-bg \\#${blue}\nset completion-highlight-fg \\#${bg}\nset tabbar-focus-bg \\#${blue}\nset tabbar-focus-fg \\#${bg}\nset index-active-bg \\#${blue}\nset index-active-fg \\#${bg}\n\nset notification-bg \\#${fg}\nset notification-fg \\#${bg}\n\nset notification-warning-bg \\#${yellow}\nset notification-warning-fg \\#${bg}\n\nset notification-error-bg \\#${red}\nset notification-error-fg \\#${bg}\n\nset recolor-darkcolor \\#${fg}\nset recolor-lightcolor \\#${bg}\n"
  },
  {
    "path": "config/zed/keymap.json",
    "content": "[\n  {\n    \"bindings\": {\n      \"ctrl-shift-w\": null,\n      \"ctrl-q\": \"pane::CloseActiveItem\",\n      \"ctrl-b\": \"workspace::ToggleLeftDock\",\n\n      // Tabs\n      \"ctrl-tab\": \"pane::ActivateNextItem\",\n      \"ctrl-shift-tab\": \"pane::ActivatePrevItem\",\n\n      // Projects\n      \"ctrl-o\": \"projects::OpenRecent\",\n      \"ctrl-shift-o\": \"workspace::Open\",\n\n      // Search\n      \"ctrl-f\": \"vim::Search\",\n      \"ctrl-shift-f\": \"pane::DeploySearch\",\n\n      // AI\n      // Toggle right dock panel\n      \"ctrl-e\": \"workspace::ToggleRightDock\",\n      // Navigate to previous AI suggestion\n      \"ctrl-[\": \"copilot::PreviousSuggestion\",\n      // Navigate to next AI suggestion\n      \"ctrl-]\": \"copilot::NextSuggestion\",\n      // Manually trigger AI suggestions\n      \"ctrl-shift-space\": \"copilot::Suggest\",\n\n      // Global file finder\n      \"f\": \"file_finder::Toggle\"\n    }\n  },\n\n  {\n    \"context\": \"Editor\",\n\n    \"bindings\": {\n      // Restore \"f\"\n      \"f\": [\"vim::PushOperator\", { \"FindForward\": { \"before\": false } }],\n\n      // Ctrl+W to delete word\n      \"ctrl-w\": \"editor::DeleteToPreviousWordStart\",\n\n      // Multi-cursor\n      \"ctrl-up\": \"editor::AddSelectionAbove\",\n      \"ctrl-down\": \"editor::AddSelectionBelow\",\n\n      // Copy paste\n      \"ctrl-c\": \"editor::Copy\",\n      \"ctrl-v\": \"editor::Paste\",\n      \"ctrl-x\": \"editor::Cut\"\n    }\n  },\n\n  {\n    // Reset global one-char hotkeys\n    \"context\": \"vim_mode == insert || mode == single_line || Terminal || mode == auto_height\",\n    \"bindings\": {\n      \"[\": null,\n      \"]\": null,\n      \"f\": null\n    }\n  },\n\n  {\n    \"context\": \"VimControl\",\n\n    \"bindings\": {\n      // WASD movements\n      \"w\": \"vim::Up\",\n      \"s\": \"vim::Down\",\n      \"a\": \"vim::Left\",\n      \"d\": \"vim::Right\",\n\n      // Move by word with capital A/D\n      \"A\": \"vim::PreviousWordStart\",\n      \"D\": \"vim::NextWordEnd\",\n\n      // Move by 5 lines with W/S\n      \"W\": [\"workspace::SendKeystrokes\", \"5 w\"],\n      \"S\": [\"workspace::SendKeystrokes\", \"5 s\"],\n\n      // Q/E to move to start/end of line\n      \"q\": \"vim::FirstNonWhitespace\",\n      \"e\": \"vim::EndOfLine\",\n\n      \"Q\": \"vim::InsertFirstNonWhitespace\",\n      \"E\": \"vim::InsertEndOfLine\",\n\n      // Ctrl+W to delete word\n      \"ctrl-w\": \"editor::DeleteToPreviousWordStart\",\n\n      // Modifications\n      \"x\": \"vim::HelixDelete\",\n      \"U\": \"vim::Redo\",\n\n      // Jumps\n      \"j\": \"pane::GoBack\",\n      \"J\": \"pane::GoForward\",\n      \"g e\": \"vim::StartOfDocument\",\n      \"g r\": \"editor::GoToDefinitionSplit\",\n      \"g f\": \"editor::OpenExcerpts\",\n      \"g F\": \"editor::OpenExcerptsSplit\",\n\n      // Excerpts (TODO)\n      \"z w\": \"editor::ExpandExcerptsUp\",\n      \"z s\": \"editor::ExpandExcerptsDown\",\n\n      // Multi-cursor\n      \"ctrl-up\": \"editor::AddSelectionAbove\",\n      \"ctrl-down\": \"editor::AddSelectionBelow\",\n      \"C\": \"editor::AddSelectionBelow\",\n      \"v\": \"vim::ToggleVisualLine\",\n      \"ctrl-d\": [\"editor::SelectNext\", { \"replace_newest\": false }],\n      \"l\": \"editor::SplitSelectionIntoLines\",\n\n      // Visual mode\n      \"ctrl-shift-v\": \"vim::ToggleVisual\"\n    }\n  },\n\n  {\n    \"context\": \"vim_mode == normal || vim_mode == visual\",\n\n    \"bindings\": {\n      // Pickers\n      \"space f\": \"file_finder::Toggle\",\n      \"space d\": \"editor::GoToDiagnostic\",\n      \"space D\": \"diagnostics::Deploy\",\n      \"space a\": \"editor::ToggleCodeActions\",\n      \"space s\": \"outline::Toggle\",\n\n      // Indentation\n      \">\": \"vim::Indent\",\n      \"<\": \"editor::TabPrev\",\n\n      // Panes\n      \"[\": [\"workspace::ActivatePaneInDirection\", \"Left\"],\n      \"]\": [\"workspace::ActivatePaneInDirection\", \"Right\"],\n\n      // Help\n      \"h\": \"editor::Hover\",\n\n      // AI\n      \"shift-enter\": \"assistant::InlineAssist\",\n\n      // Selection\n      \"\\\"\": [\"workspace::SendKeystrokes\", \"ctrl-shift-v i \\\"\"]\n    }\n  },\n\n  {\n    \"context\": \"vim_mode == normal\",\n\n    // TODO: clipboard make c and p not touch the clipboard (only x should do it)\n    \"bindings\": {\n      \"y\": \"vim::YankLine\",\n\n      // Vim-like Modifications\n      \"c w\": [\"workspace::SendKeystrokes\", \"ctrl-d c\"],\n      \"c c\": [\"workspace::SendKeystrokes\", \"v c\"]\n    }\n  },\n\n  {\n    \"context\": \"vim_mode == visual\",\n\n    \"bindings\": {\n      \"y\": \"vim::VisualYank\",\n\n      // AI\n      \"r\": \"assistant::InlineAssist\"\n    }\n  },\n\n  {\n    \"context\": \"vim_mode == insert\",\n\n    \"bindings\": {\n      // Bash-like: Ctrl+A / Ctrl+E to move to start/end of file\n      \"ctrl-a\": \"vim::FirstNonWhitespace\"\n      // Conflicts with AI\n      // \"ctrl-e\": \"vim::EndOfLine\"\n    }\n  }\n]\n"
  },
  {
    "path": "config/zed/settings.json",
    "content": "{\n  // Disable shit\n  \"telemetry\": {\n    \"diagnostics\": false,\n    \"metrics\": false\n  },\n  \"show_user_picture\": false,\n  \"scrollbar\": {\n    \"show\": \"auto\",\n    \"axes\": {\n      \"vertical\": true,\n      \"horizontal\": false\n    }\n  },\n  \"toolbar\": {\n    \"breadcrumbs\": true,\n    \"quick_actions\": false\n  },\n  \"tab_bar\": { \"show\": false },\n  \"project_panel\": { \"button\": false },\n  \"outline_panel\": { \"button\": false },\n  \"collaboration_panel\": { \"button\": false },\n  \"notification_panel\": { \"button\": false },\n  \"terminal\": {\n    \"button\": false,\n    \"copy_on_select\": true,\n    \"dock\": \"left\",\n    \"toolbar\": {\n      \"breadcrumbs\": false\n    }\n  },\n  \"git\": {\n    \"inline_blame\": {\n      \"enabled\": false\n    }\n  },\n\n  // AI\n  \"assistant\": {\n    \"default_model\": {\n      \"provider\": \"copilot_chat\",\n      \"model\": \"o3-mini\"\n    },\n    \"version\": \"2\"\n  },\n\n  // Rullers and wrapping\n  \"wrap_guides\": [80, 120],\n  \"preferred_line_length\": 80,\n  \"soft_wrap\": \"none\", // enable per-language\n\n  // Smaller gutter\n  \"gutter\": {\n    \"code_actions\": false,\n    \"runnables\": false,\n    \"folds\": false\n  },\n\n  // Smaller statusbar\n  \"line_indicator_format\": \"short\",\n\n  // Maybe\n  \"active_pane_modifiers\": {\n    \"magnification\": 1.5,\n    \"inactive_opacity\": 0.85\n  },\n\n  // Usability\n  \"vim_mode\": true,\n  \"auto_signature_help\": true,\n  \"hover_popover_delay\": 50,\n  \"scroll_sensitivity\": 5,\n  \"restore_on_startup\": \"none\",\n\n  // Extensions\n  \"auto_install_extensions\": {\n    \"html\": true,\n    \"dockerfile\": true,\n    \"docker-compose\": true,\n    \"ruff\": true\n  },\n\n  // Looks\n  \"buffer_line_height\": {\n    \"custom\": 1.16 // Like I've used in terminal, but it's pretty dense\n  },\n  \"ui_font_size\": 15,\n  \"buffer_font_size\": 15.0,\n  \"buffer_font_family\": \"Noto Sans Mono\",\n  \"buffer_font_weight\": 300,\n  \"ui_font_weight\": 400,\n  \"ui_font_family\": \"Noto Sans\",\n  \"theme\": {\n    \"mode\": \"dark\",\n    \"light\": \"One Light\",\n    \"dark\": \"Casablanca\"\n  },\n\n  // LSPs\n  \"lsp\": {\n    \"rust-analyzer\": {\n      \"initialization_options\": {\n        \"cachePriming\": { \"enable\": false },\n        \"completion\": {\n          \"callable\": { \"snippets\": \"none\" },\n          \"fullFunctionSignatures\": { \"enable\": false },\n          \"limit\": 1024,\n          \"postfix\": { \"enable\": false },\n          \"hideDeprecated\": true\n        },\n\n        \"imports\": { \"preferNoStd\": true },\n\n        \"hover\": {\n          \"actions\": { \"run\": { \"enable\": false } },\n          \"show\": { \"fields\": 10 }\n        },\n\n        \"inlayHints\": {\n          \"chainingHints\": { \"enable\": false },\n          \"closingBraceHints\": { \"enable\": false },\n          \"genericParameterHints\": { \"const\": { \"enable\": false } },\n          \"typeHints\": { \"enable\": false },\n          \"parameterHints\": { \"enable\": false },\n          \"renderColons\": false\n        },\n        \"lens\": {\n          \"enable\": false\n        },\n        \"lru\": {\n          \"capacity\": 512\n        },\n        \"diagnostics\": {\n          \"experimental\": {\n            \"enable\": true\n          },\n          \"styleLints\": {\n            \"enable\": true\n          }\n        },\n        \"check\": {\n          \"command\": \"clippy\"\n        },\n        \"cargo\": {\n          \"targetDir\": true,\n          \"allTargets\": false\n        },\n        \"rustfmt\": {\n          \"extraArgs\": [\n            \"--config=empty_item_single_line=false\",\n            \"--config=wrap_comments=true\",\n            \"--config=condense_wildcard_suffixes=true\",\n            \"--config=enum_discrim_align_threshold=10\",\n            \"--config=format_code_in_doc_comments=true\",\n            \"--config=hex_literal_case=Upper\",\n            \"--config=max_width=80\",\n            \"--config=reorder_impl_items=true\",\n            \"--config=group_imports=StdExternalCrate\",\n            \"--config=use_field_init_shorthand=true\"\n          ]\n        }\n      }\n    }\n  },\n\n  // Languages\n  \"languages\": {\n    \"Python\": {\n      \"format_on_save\": \"on\",\n      \"formatter\": [{ \"language_server\": { \"name\": \"ruff\" } }]\n    },\n    \"Markdown\": { \"soft_wrap\": \"preferred_line_length\" }\n  }\n}\n"
  },
  {
    "path": "config/zed/theme.json",
    "content": "{\n  \"$schema\": \"https://zed.dev/schema/themes/v0.1.0.json\",\n  \"name\": \"Casablanca\",\n  \"author\": \"Denis Gruzdev\",\n  \"themes\": [\n    {\n      \"name\": \"Casablanca\",\n      \"appearance\": \"dark\",\n      \"style\": {\n        \"border\": \"#181E2C\",\n        \"border.variant\": \"#181E2C\",\n        \"border.focused\": \"#babbf1\",\n        \"border.selected\": \"#BBAAF2\",\n        \"border.transparent\": \"#ACDF96\",\n        \"border.disabled\": \"#626880\",\n        \"elevated_surface.background\": \"#181E2C\",\n        \"surface.background\": \"#1D2433\",\n        \"background\": \"#1D2433\",\n        \"element.background\": \"#181E2C\",\n        \"element.hover\": \"#7379944d\",\n        \"element.active\": \"#ca9ee633\",\n        \"element.selected\": \"#313847\",\n        \"element.disabled\": \"#737994\",\n        \"drop_target.background\": \"#ca9ee666\",\n        \"ghost_element.background\": null,\n        \"ghost_element.hover\": \"#606D88\",\n        \"ghost_element.active\": \"#62688080\",\n        \"ghost_element.selected\": \"#313847\",\n        \"ghost_element.disabled\": \"#737994\",\n        \"text\": \"#BDD9F2\",\n        \"text.muted\": \"#b5bfe2\",\n        \"text.placeholder\": \"#626880\",\n        \"text.disabled\": \"#737994\",\n        \"text.accent\": \"#BBAAF2\",\n        \"icon\": \"#BDD9F2\",\n        \"icon.muted\": \"#606D88\",\n        \"icon.disabled\": \"#737994\",\n        \"icon.placeholder\": \"#626880\",\n        \"icon.accent\": \"#BBAAF2\",\n        \"status_bar.background\": \"#181E2C\",\n        \"title_bar.background\": \"#181E2C\",\n        \"title_bar.inactive_background\": \"#1D2433\",\n        \"toolbar.background\": \"#1D2433\",\n        \"tab_bar.background\": \"#181E2C\",\n        \"tab.inactive_background\": \"#181E2C\",\n        \"tab.active_background\": \"#1D2433\",\n        \"search.match_background\": \"#313847\",\n        \"panel.background\": \"#181E2C\",\n        \"panel.focused_border\": \"#181E2C\",\n        \"pane.focused_border\": \"#181E2C\",\n        \"scrollbar.thumb.background\": \"#9BB8F210\",\n        \"scrollbar.thumb.hover_background\": \"#737994\",\n        \"scrollbar.thumb.border\": \"#9BB8F200\",\n        \"scrollbar.track.background\": \"#1D2433\",\n        \"scrollbar.track.border\": \"#1D2433\",\n        \"editor.foreground\": \"#BDD9F2\",\n        \"editor.background\": \"#1D2433\",\n        \"editor.gutter.background\": \"#1D2433\",\n        \"editor.subheader.background\": \"#181E2C\",\n        \"editor.active_line.background\": \"#181E2C\",\n        \"editor.highlighted_line.background\": \"#606D88\",\n        \"editor.line_number\": \"#606D88\",\n        \"editor.active_line_number\": \"#BDD9F2\",\n        \"editor.invisible\": \"#505D78\",\n        \"editor.wrap_guide\": \"#313847\",\n        \"editor.active_wrap_guide\": \"#626880\",\n        \"editor.indent_guide\": \"#313847\",\n        \"editor.indent_guide_active\": \"#505D78\",\n        \"editor.document_highlight.read_background\": \"#303D58\",\n        \"editor.document_highlight.write_background\": \"#303D58\",\n        \"terminal.background\": \"#1D2433\",\n        \"terminal.foreground\": \"#BDD9F2\",\n        \"terminal.dim_foreground\": \"#606D88\",\n        \"terminal.bright_foreground\": \"#BDD9F2\",\n        \"terminal.ansi.black\": \"#51576d\",\n        \"terminal.ansi.red\": \"#e78284\",\n        \"terminal.ansi.green\": \"#ACDF96\",\n        \"terminal.ansi.yellow\": \"#e5c890\",\n        \"terminal.ansi.blue\": \"#9BB8F2\",\n        \"terminal.ansi.magenta\": \"#f4b8e4\",\n        \"terminal.ansi.cyan\": \"#81c8be\",\n        \"terminal.ansi.white\": \"#BDD9F2\",\n        \"terminal.ansi.bright_black\": \"#626880\",\n        \"terminal.ansi.bright_red\": \"#e78284\",\n        \"terminal.ansi.bright_green\": \"#ACDF96\",\n        \"terminal.ansi.bright_yellow\": \"#e5c890\",\n        \"terminal.ansi.bright_blue\": \"#9BB8F2\",\n        \"terminal.ansi.bright_magenta\": \"#f4b8e4\",\n        \"terminal.ansi.bright_cyan\": \"#81c8be\",\n        \"terminal.ansi.bright_white\": \"#a5adce\",\n        \"terminal.ansi.dim_black\": \"#51576d\",\n        \"terminal.ansi.dim_red\": \"#e78284\",\n        \"terminal.ansi.dim_green\": \"#ACDF96\",\n        \"terminal.ansi.dim_yellow\": \"#e5c890\",\n        \"terminal.ansi.dim_blue\": \"#9BB8F2\",\n        \"terminal.ansi.dim_magenta\": \"#f4b8e4\",\n        \"terminal.ansi.dim_cyan\": \"#81c8be\",\n        \"terminal.ansi.dim_white\": \"#b5bfe2\",\n        \"link_text.hover\": \"#99d1db\",\n        \"conflict\": \"#BBAAF2\",\n        \"conflict.border\": \"#BBAAF2\",\n        \"conflict.background\": \"#181E2C\",\n        \"created\": \"#ACDF96\",\n        \"created.border\": \"#ACDF96\",\n        \"created.background\": \"#181E2C\",\n        \"deleted\": \"#e78284\",\n        \"deleted.border\": \"#e78284\",\n        \"deleted.background\": \"#181E2C\",\n        \"error\": \"#e78284\",\n        \"error.border\": \"#e78284\",\n        \"error.background\": \"#181E2C\",\n        \"hidden\": \"#737994\",\n        \"hidden.border\": \"#737994\",\n        \"hidden.background\": \"#181E2C\",\n        \"hint\": \"#71989f\",\n        \"hint.border\": \"#626880\",\n        \"hint.background\": \"#181E2C\",\n        \"ignored\": \"#737994\",\n        \"ignored.border\": \"#737994\",\n        \"ignored.background\": \"#181E2C\",\n        \"info\": \"#81c8be\",\n        \"info.border\": \"#81c8be\",\n        \"info.background\": \"#ca9ee666\",\n        \"modified\": \"#e5c890\",\n        \"modified.border\": \"#e5c890\",\n        \"modified.background\": \"#181E2C\",\n        \"predictive\": \"#7d93c8\",\n        \"predictive.border\": \"#babbf1\",\n        \"predictive.background\": \"#181E2C\",\n        \"renamed\": \"#85c1dc\",\n        \"renamed.border\": \"#85c1dc\",\n        \"renamed.background\": \"#181E2C\",\n        \"success\": \"#ACDF96\",\n        \"success.border\": \"#ACDF96\",\n        \"success.background\": \"#181E2C\",\n        \"unreachable\": \"#e78284\",\n        \"unreachable.border\": \"#e78284\",\n        \"unreachable.background\": \"#181E2C\",\n        \"warning\": \"#ef9f76\",\n        \"warning.border\": \"#ef9f76\",\n        \"warning.background\": \"#181E2C\",\n        \"players\": [\n          {\n            \"cursor\": \"#BDD9F280\",\n            \"selection\": \"#313847\",\n            \"background\": \"#f2d5cf\"\n          },\n          {\n            \"cursor\": \"#accaeb\",\n            \"selection\": \"#accaeb33\",\n            \"background\": \"#accaeb\"\n          },\n          {\n            \"cursor\": \"#d3b1c8\",\n            \"selection\": \"#d3b1c833\",\n            \"background\": \"#d3b1c8\"\n          },\n          {\n            \"cursor\": \"#abcddf\",\n            \"selection\": \"#abcddf33\",\n            \"background\": \"#abcddf\"\n          },\n          {\n            \"cursor\": \"#d7bdc2\",\n            \"selection\": \"#d7bdc233\",\n            \"background\": \"#d7bdc2\"\n          },\n          {\n            \"cursor\": \"#d3cdcd\",\n            \"selection\": \"#d3cdcd33\",\n            \"background\": \"#d3cdcd\"\n          },\n          {\n            \"cursor\": \"#afc1f2\",\n            \"selection\": \"#afc1f233\",\n            \"background\": \"#afc1f2\"\n          },\n          {\n            \"cursor\": \"#b9d1ca\",\n            \"selection\": \"#b9d1ca33\",\n            \"background\": \"#b9d1ca\"\n          }\n        ],\n        \"syntax\": {\n          \"attribute\": {\n            \"color\": \"#BBAAF2\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"boolean\": {\n            \"color\": \"#ef9f76\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"comment\": {\n            \"color\": \"#606D88\",\n            \"font_style\": \"italic\",\n            \"font_weight\": null\n          },\n          \"comment.doc\": {\n            \"color\": \"#606D88\",\n            \"font_style\": \"italic\",\n            \"font_weight\": null\n          },\n          \"constant\": {\n            \"color\": \"#BDD9F2\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"constructor\": {\n            \"color\": \"#9BB8F2\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"embedded\": {\n            \"color\": \"#ea999c\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"emphasis\": {\n            \"color\": \"#e78284\",\n            \"font_style\": \"italic\",\n            \"font_weight\": null\n          },\n          \"emphasis.strong\": {\n            \"color\": \"#e78284\",\n            \"font_style\": null,\n            \"font_weight\": 700\n          },\n          \"enum\": {\n            \"color\": \"#81c8be\",\n            \"font_style\": null,\n            \"font_weight\": 700\n          },\n          \"function\": {\n            \"color\": \"#9BB8F2\",\n            \"font_style\": \"italic\",\n            \"font_weight\": null\n          },\n          \"hint\": {\n            \"color\": \"#71989f\",\n            \"font_style\": \"italic\",\n            \"font_weight\": null\n          },\n          \"keyword\": {\n            \"color\": \"#BBAAF2\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"link_text\": {\n            \"color\": \"#9BB8F2\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"link_uri\": {\n            \"color\": \"#9BB8F2\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"number\": {\n            \"color\": \"#DFD6c6\", // NOTE: this is new yellow\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"operator\": {\n            \"color\": \"#606D88\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"predictive\": {\n            \"color\": \"#7d93c8\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"predoc\": {\n            \"color\": \"#e78284\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"primary\": {\n            \"color\": \"#ea999c\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"property\": {\n            \"color\": \"#9BB8F2\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"punctuation\": {\n            \"color\": \"#81c8be\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"punctuation.bracket\": {\n            \"color\": \"#606D88\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"punctuation.delimiter\": {\n            \"color\": \"#606D88\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"punctuation.list_marker\": {\n            \"color\": \"#81c8be\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"punctuation.special\": {\n            \"color\": \"#606D88\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"punctuation.special.symbol\": {\n            \"color\": \"#e78284\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"string\": {\n            \"color\": \"#99dfbc\", // NOTE: this is new green\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"string.escape\": {\n            \"color\": \"#f4b8e4\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"string.regex\": {\n            \"color\": \"#f4b8e4\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"string.special\": {\n            \"color\": \"#f4b8e4\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"string.special.symbol\": {\n            \"color\": \"#eebebe\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"tag\": {\n            \"color\": \"#9BB8F2\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"text.literal\": {\n            \"color\": \"#ACDF96\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"title\": {\n            \"color\": \"#BDD9F2\",\n            \"font_style\": null,\n            \"font_weight\": 800\n          },\n          \"type\": {\n            \"color\": \"#818DA7\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"type.interface\": {\n            \"color\": \"#e5c890\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"type.super\": {\n            \"color\": \"#e5c890\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"variable\": {\n            \"color\": \"#96bFe0\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"variable.member\": {\n            \"color\": \"#BDD9F2\",\n            \"font_style\": null,\n            \"font_weight\": null\n          },\n          \"variable.parameter\": {\n            \"color\": \"#96cFd0\", // NOTE: this is new cyan\n            \"font_style\": \"italic\",\n            \"font_weight\": null\n          },\n          \"variable.special\": {\n            \"color\": \"#DF96C7\",\n            \"font_style\": \"italic\",\n            \"font_weight\": null\n          },\n          \"variant\": {\n            \"color\": \"#e78284\",\n            \"font_style\": null,\n            \"font_weight\": null\n          }\n        }\n      }\n    }\n  ],\n  \"id\": \"9Mm3QFvdaQXFHg7WHrWax\"\n}\n"
  },
  {
    "path": "config/zsh/zprofile",
    "content": "# Programs\nexport EDITOR='nvim'\nexport TERMINAL='footclient'\nexport BROWSER='google-chrome-unstable'\nexport PAGER='less'\n\nexport VISUAL=\"${EDITOR}\"\n\n# Settings: fzf\nFZF_DEFAULT_OPTS_ARR=(\n  --scheme=history\n  --ansi\n  --exact\n  --no-mouse\n\n  # Reverse order\n  --tac\n  --layout=reverse\n\n  # Styling\n  --height=90%\n  --min-height=7\n  '--prompt=\"  \"'\n  --info=inline-right\n  --border=none\n  --no-scrollbar\n  --no-separator\n  --color='bw,fg:white,hl:regular:blue,fg+:regular,hl+:regular:blue,info:black:bold,prompt:black:bold,pointer:black:bold'\n)\nexport FZF_DEFAULT_OPTS=\"$FZF_DEFAULT_OPTS_ARR\"\n\n# Settings: less\nexport LESS='-cigRS -j4 -x4 -#5 -z-10'\nexport LESSHISTFILE=\"-\"\n\n# Settings: pass\nexport PASSWORD_STORE_CLIP_TIME=8\n\n# Settings: LS_COLORS\nLS_COLORS='no=0:fi=0:di=34'\n\n# Hidden files\nLS_COLORS+=\":.*=90\"\n\n# Programming (purple)\nLS_COLORS+=\":*.py=36:*.sh=36\"\nLS_COLORS+=\":*Dockerfile=36:*Makefile=36\"\n\n# Text files (green)\nLS_COLORS+=\":*.md=32:*.txt=32:*.html=32\"\n\n# Config files (yellow)\nLS_COLORS+=\":*.json=33:*.toml=33:*.yml=33\"\nLS_COLORS+=\":*.in=33:*.conf=33:*.example=33\"\nLS_COLORS+=\":.zshrc=33:.zprofile=33\"\nexport LS_COLORS\n\n# Cleanup environment variables\nunset MAIL\nunset DEBUGINFOD_URLS\n\n# Path: zvm, local binaries, cargo\nexport ZVM_INSTALL=\"$HOME/.zvm/self\"\nexport PATH=\"$HOME/.zvm/bin:$ZVM_INSTALL:$HOME/.local/bin:$HOME/.cargo/bin:$HOME/.npm/bin:$PATH\"\n"
  },
  {
    "path": "config/zsh/zshrc",
    "content": "# Aliases: editor\nalias e=\"$EDITOR\"\nalias E=\"sudo -e\"\n\n# Aliases: ls\nalias l='eza -1A --group-directories-first --color=always --git-ignore'\nalias ls='l'\nalias la='l -l --time-style=\"+%Y-%m-%d %H:%M\" --no-permissions --octal-permissions'\nalias tree='l --tree'\n\n# Aliases: git\nalias ga='git add'\nalias gap='ga --patch'\nalias gb='git branch'\nalias gba='gb --all'\nalias gc='git commit'\nalias gca='gc --amend --no-edit'\nalias gce='gc --amend'\nalias gco='git checkout'\nalias gcl='git clone --recursive'\nalias gd='git diff --output-indicator-new=\" \" --output-indicator-old=\" \"'\nalias gds='gd --staged'\nalias gi='git init'\nalias gl='git log --graph --all --pretty=format:\"%C(magenta)%h %C(white) %an  %ar%C(auto)  %D%n%s%n\"'\nalias gm='git merge'\nalias gn='git checkout -b'  # new branch\nalias gp='git push'\nalias gr='git reset'\nalias gs='git status --short'\nalias gu='git pull'\nalias gw='git switch'\n\ngcm() { git commit --message \"$*\" }\n\n# Aliases: docker\nalias dps='docker ps --format \"table {{.Names}}\\t{{.Status}}\\t{{.Ports}}\"'\nalias dl='docker logs --tail=100'\nalias dc='docker compose'\n\n# Aliases: tmux\nalias ta='tmux attach'\nalias tl='tmux list-sessions'\nalias tn='tmux new-session -s'\n\n# Aliases: rg\nalias rg=\"rg --hidden --smart-case --glob='!.git/' --no-search-zip --trim --colors=line:fg:black --colors=line:style:bold --colors=path:fg:magenta --colors=match:style:nobold\"\n\n# Aliases: pass\nalias pa='pass'\nalias pac='pass -c'\nalias po='pass otp'\nalias poc='pass otp -c'\nalias pg='openssl rand -base64 33'\n\n# Aliases: systemd\nalias sd='sudo systemctl'\nalias sdu='systemctl --user'\nalias jd='journalctl --no-pager'\n\n# Aliases: human-readable\nalias cal='TZ=Asia/Bangkok cal --monday'\nalias du='du --human-readable'\nalias free='free --human'\n\n# Aliases: safety\nalias cp='cp --interactive'\nalias mv='mv --interactive'\n\n# Aliases: misc\nmk() {\n  mkdir --parents \"$1\" && cd \"$1\"\n}\nalias rf='rm -rf'\nalias py='python3'\nalias ipy='ipython'\nalias ping='ping -A'\n\nalias -g p='2>&1 | less'\nalias sudo='sudo '  # allow aliases with sudo\n\n# Aliases: package managers\nif [[ -n \"$TERMUX_VERSION\" ]]; then\n  alias pi='pkg install'\n  alias pf='pkg search'\n  alias pr='pkg uninstall'\nelse\n  alias pi='sudo pacman -S --needed'\n  alias pf='pacman -Ss'\n  alias pr='sudo pacman -Rs'\nfi\n\n# Recommended kind of update with reduced keyring-related problems\nalias pu='sudo pacman -Sy --needed archlinux-keyring && sudo pacman -Su'\n\n# Aliases: ledger\nalias lg='ledger'\nalias lga='ledger accounts'\nalias lgb='ledger balance'\nalias lgr='ledger register'\n\n# Aliases: when\nalias wi='TZ=Asia/Bangkok when ci --future=30'\n\n# Aliases: editors\nalias ew='when eci'\nalias en='cd ~/notes && e'\nalias el='e ~/.ledger/journal.ldg'\n\n# Aliases: git\nalias git-notes='git -C ~/notes'\nalias git-when='git -C ~/.when'\nalias git-ledger='git -C ~/.ledger'\n\nalias sync-commit-notes='git-notes add --all; git-notes commit --message sync; git-notes pull; git-notes push'\n\nalias cj-pull='pass git pull; git-notes pull; git-when pull; git-ledger pull'\nalias cj-status='pass git status; git-notes status; git-when status; git-ledger status'\n\n# Man colors\nman() {\n  GROFF_NO_SGR=1 \\\n  LESS_TERMCAP_mb=$'\\e[31m' \\\n  LESS_TERMCAP_md=$'\\e[34m' \\\n  LESS_TERMCAP_me=$'\\e[0m' \\\n  LESS_TERMCAP_se=$'\\e[0m' \\\n  LESS_TERMCAP_so=$'\\e[1;30m' \\\n  LESS_TERMCAP_ue=$'\\e[0m' \\\n  LESS_TERMCAP_us=$'\\e[35m' \\\n  command man \"$@\"\n}\n\n# Prompt\nPROMPT=$'%{\\033[34m%} %2~ %{\\033[37m%}❯ %{\\033[0m%}'\nPROMPT2=$'%{\\033[33m%} ... %{\\033[0m%}'\nRPROMPT=$'%(0?..%(130?..%{\\033[31m%}%?%{\\033[0m%}))'\n\n# ZLE\nKEYTIMEOUT=1  # 10ms for grouping escape sequences\nWORDCHARS='-_:'\n\nsetopt interactive_comments\n\n# Jobs\nsetopt auto_continue  # continue jobs on disown\nsetopt check_jobs  # do not exit shell with jobs\nsetopt check_running_jobs\n\n# History\nHISTFILE=\"$HOME/.zsh_history\"\nHISTSIZE=10000\nSAVEHIST=\"$HISTSIZE\"\n\nsetopt extended_history\nsetopt inc_append_history\nsetopt inc_append_history_time\nsetopt share_history\nsetopt hist_fcntl_lock\n\nsetopt hist_ignore_dups\nsetopt hist_ignore_all_dups\nsetopt hist_save_no_dups\nsetopt hist_ignore_space\nsetopt hist_reduce_blanks\nsetopt hist_no_store  # ignore fc command\n\nHISTORY_IGNORE='(rm *|rf *)'\n\n# History: interactive search\n__history() {\n  LBUFFER=\"$(fc -ln 0 | fzf --query=\"${LBUFFER}\")\"\n  zle redisplay\n}\n\nzle -N __history\n\n# Completion\nLISTMAX=10000  # do not show warning if there is too much items in completion\n\nsetopt glob_dots  # include dotfiles into completion by default\nsetopt hash_cmds  # hash command locations\nsetopt list_packed\n\nautoload -Uz compinit\ncompinit -C  # -C disables security checks on dump file\n\n# _complete is base completer\n# _extensions will complete glob patters with extensions\nzstyle ':completion:*' completer _extensions _complete\n\nzstyle ':completion:*' menu select  # menu with selection\nzstyle ':completion:*' increment yes\nzstyle ':completion:*' verbose yes\nzstyle ':completion:*' squeeze-slashes yes  # replace // with /\n\nzstyle ':completion:*' file-sort modification  # show recently used files first\nzstyle ':completion:*' list-dirs-first yes\nzstyle ':completion:*' list-colors \"${(s.:.)LS_COLORS}\"  # colored files and directories, blue selection box\nzstyle ':completion:*' ignored-patterns '.git'\n\nzstyle ':completion:*' rehash false  # improves performance\nzstyle ':completion:*' use-cache true\n\n\n# Keyboard\nunsetopt flow_control  # disable ^S / ^Q\n\nbindkey -e  # Zsh default keybindings are vim, because EDITOR is set to vim, use emacs ones\n\nbindkey '^I' complete-word  # Tab, complete instead of expand-and-complete\nbindkey '^[[3~' delete-char  # Delete\nbindkey '^[[Z' reverse-menu-complete  # Shift+Tab\nbindkey '^[[1;5D' backward-word  # Control-Left\nbindkey '^[[1;5C' forward-word  # Control-Right\n\nbindkey '^R' __history\n\n# Line editor\nautoload -Uz edit-command-line\nzle -N edit-command-line\nbindkey '^S' edit-command-line\n\n# Super Ctrl-Z\nfg-ctrl-z () {\n  fg 2> /dev/null\n}\nzle -N fg-ctrl-z\nbindkey '^Z' fg-ctrl-z\n\n# Fix for GPG pinentry\n# SOURCE: https://github.com/keybase/keybase-issues/issues/2798\nexport GPG_TTY=$(tty)\n\n# Plugin: zoxide\nexport _ZO_FZF_OPTS=\"$FZF_DEFAULT_OPTS --no-tac --select-1 --exit-0\"\neval \"$(zoxide init zsh --no-cmd)\"\nalias z='__zoxide_zi'\nalias ~='cd ~'\nze() {\n  DIR=$(zoxide query -i \"$@\")\n  [ -n \"$DIR\" ] && cd \"$DIR\" && e .\n}\n\n# Plugin: autosuggestions\nif [[ -n \"$TERMUX_VERSION\" ]]; then\n  source ~/third-party/zsh-autosuggestions/zsh-autosuggestions.zsh\nelse\n  source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh\nfi\n\nZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=#606090'\nZSH_AUTOSUGGEST_STRATEGY=(history completion)\nZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=40\n\n# Plugin: syntax highlighting\nif [[ -n \"$TERMUX_VERSION\" ]]; then\n  source ~/third-party/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh\nelse\n  source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh\nfi\n\nZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets)\nZSH_HIGHLIGHT_MAXLENGTH=120\n\n# Rainbow brackets in special order, easier for eyes\nZSH_HIGHLIGHT_STYLES[bracket-level-1]='fg=magenta'\nZSH_HIGHLIGHT_STYLES[bracket-level-2]='fg=green'\nZSH_HIGHLIGHT_STYLES[bracket-level-3]='fg=blue'\nZSH_HIGHLIGHT_STYLES[bracket-level-4]='fg=yellow'\nZSH_HIGHLIGHT_STYLES[bracket-level-5]='fg=cyan'\nZSH_HIGHLIGHT_STYLES[bracket-level-6]='fg=red'\n\n# Custom styles\n# Errors\nZSH_HIGHLIGHT_STYLES[unknown-token]='fg=red,underline'\n\n# Keywords\nZSH_HIGHLIGHT_STYLES[reserved-word]='fg=blue'\n\n# Commands\nZSH_HIGHLIGHT_STYLES[precommand]='fg=cyan'\nZSH_HIGHLIGHT_STYLES[suffix-alias]='fg=magenta'\nZSH_HIGHLIGHT_STYLES[global-alias]='fg=magenta'\nZSH_HIGHLIGHT_STYLES[arg0]='fg=magenta'\n\n# Strings\nZSH_HIGHLIGHT_STYLES[single-quoted-argument]='fg=green'\nZSH_HIGHLIGHT_STYLES[double-quoted-argument]='fg=green'\nZSH_HIGHLIGHT_STYLES[dollar-quoted-argument]='fg=yellow'\n\n# Redirections\nZSH_HIGHLIGHT_STYLES[redirection]='fg=cyan'\n\n# Paths\nZSH_HIGHLIGHT_STYLES[path]='none'\n"
  },
  {
    "path": "settings.toml",
    "content": "# Colors\nbg          = \"1d2433\"\nbg_dim      = \"1a202e\"\nbg_dim_more = \"171c29\"\nbg_sel      = \"293145\"\n\nfg          = \"bfd3ff\"\nfg_half_dim = \"54678c\"\nfg_dim      = \"3d4a66\"\n\nred         = \"D0879D\"\norange      = \"D0B1A2\"\nyellow      = \"CDD2AF\"\ngreen       = \"9FD6B6\"\ncyan        = \"acd9ec\"\nblue        = \"92b7ea\"\npurple      = \"AD9BEA\"\npink        = \"CD9BCC\"\n"
  },
  {
    "path": "tools/deps",
    "content": "#!/usr/bin/env python\n\nimport shutil\nimport sys\nfrom dataclasses import dataclass\n\n\n@dataclass\nclass Binary:\n    name: str\n    binary: str\n\n    def exists(self) -> bool:\n        return shutil.which(self.binary) is not None\n\n\nDEPENDENCIES = [\n    # Core\n    Binary(name=\"Z Shell\", binary=\"zsh\"),\n    Binary(name=\"fd\", binary=\"fd\"),\n    Binary(name=\"eza\", binary=\"eza\"),\n\n    # CLI Tools\n    Binary(name=\"Git\", binary=\"git\"),\n    Binary(name=\"diff-so-fancy\", binary=\"diff-so-fancy\"),\n\n    Binary(name=\"Less\", binary=\"less\"),\n    Binary(name=\"Curl\", binary=\"curl\"),\n    Binary(name=\"OpenSSH\", binary=\"ssh\"),\n    Binary(name=\"OpenGPG\", binary=\"gpg\"),\n    Binary(name=\"Tmux\", binary=\"tmux\"),\n    Binary(name=\"Htop\", binary=\"htop\"),\n    Binary(name=\"psql\", binary=\"psql\"),\n\n    # Development\n    Binary(name=\"Ruff\", binary=\"ruff\"),\n    Binary(name=\"Cargo\", binary=\"cargo\"),\n    Binary(name=\"Poetry\", binary=\"poetry\"),\n    Binary(name=\"UV\", binary=\"uv\"),\n\n    # LSP Servers\n    Binary(name=\"Taplo (TOML LSP)\", binary=\"taplo\"),\n    Binary(name=\"Codebook (spell checking LSP)\", binary=\"codebook-lsp\"),\n\n    # Arch linux\n    Binary(name=\"paru\", binary=\"paru\"),\n\n    # WM\n    Binary(name=\"NiriWM\", binary=\"niri\"),\n    Binary(name=\"Foot Terminal\", binary=\"foot\"),\n    Binary(name=\"Mako\", binary=\"mako\"),\n    Binary(name=\"Waybar\", binary=\"waybar\"),\n    Binary(name=\"Fuzzel\", binary=\"fuzzel\"),\n    Binary(name=\"Hyprlock\", binary=\"hyprlock\"),\n    Binary(name=\"Hypridle\", binary=\"hypridle\"),\n\n    # GUI Apps\n    Binary(name=\"Google Chrome (unstable)\", binary=\"google-chrome-unstable\"),\n    Binary(name=\"Zathura\", binary=\"zathura\"),\n    Binary(name=\"MPV\", binary=\"mpv\"),\n]\n\n\ndef warn(message: str) -> None:\n    _ = sys.stderr.write(f\"× WARNING: {message}\\n\")  # noqa: RUF001\n\n\ndef main() -> None:\n    for dep in DEPENDENCIES:\n        if not dep.exists():\n            warn(\n                f\"binary `{dep.binary}` for \"\n                f'dependency \"{dep.name}\" doesn\\'t exist'\n            )\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "tools/render",
    "content": "#!/usr/bin/env python\n\nimport os\nimport shutil\nimport sys\nimport tomllib\nfrom dataclasses import dataclass\nfrom pathlib import Path\nfrom string import Template\nfrom typing import Self\n\nHOST_ROOT: Path = Path.home()\nREPO_ROOT: Path = Path(__file__).parent.parent\nCONFIG_ROOT: Path = REPO_ROOT / \"config\"\n\nOS_TERMUX = \"com.termux\" in os.environ.get(\"PREFIX\", \"\")\n\n\n@dataclass\nclass Config:\n    host: Path  # relative to home directory\n    repo: Path  # relative to `dotfiles/config` directory\n    templated: bool\n\n    @classmethod\n    def home(\n        cls: type[Self],\n        host: str,\n        repo: str,\n        templated: bool = False,\n    ) -> Self:\n        return cls(\n            host=HOST_ROOT / host,\n            repo=CONFIG_ROOT / repo,\n            templated=templated,\n        )\n\n\n@dataclass\nclass Directory:\n    path: Path\n    mode: int\n\n    @classmethod\n    def home(\n        cls: type[Self],\n        partial_path: str,\n        mode: int = 0o755,\n    ) -> Self:\n        return cls(\n            path=HOST_ROOT / partial_path,\n            mode=mode,\n        )\n\n    def ensure(self) -> None:\n        self.path.mkdir(parents=True, exist_ok=True, mode=self.mode)\n        self.path.chmod(self.mode)\n\n\nDIRECTORIES = [\n    Directory.home(\".ssh/control\", mode=0o700),\n]\n\n\nCONFIG_FILES = [\n    # Zsh\n    Config.home(\".zshrc\", \"zsh/zshrc\"),\n    Config.home(\".zprofile\", \"zsh/zprofile\"),\n    # Ssh\n    Config.home(\".ssh/config\", \"ssh/config\"),\n    Config.home(\".ssh/authorized_keys\", \"ssh/authorized_keys\"),\n    # Git\n    Config.home(\".config/git/config\", \"git/config\"),\n    Config.home(\".config/git/ignore\", \"git/ignore\"),\n    Config.home(\".config/git/template\", \"git/template\"),\n    # Less\n    Config.home(\".lesskey\", \"less/lesskey\"),\n    # Htop\n    Config.home(\".config/htop/htoprc\", \"htop/htoprc\"),\n    # Curl\n    Config.home(\".config/curlrc\", \"curl/curlrc\"),\n    # Postgres\n    Config.home(\".psqlrc\", \"postgres/psqlrc\"),\n    # Gnupg\n    Config.home(\".gnupg/gpg.conf\", \"gnupg/gpg.conf\"),\n    Config.home(\".gnupg/gpg-agent.conf\", \"gnupg/gpg-agent.conf\"),\n    # Tmux\n    Config.home(\".tmux.conf\", \"tmux/tmux.conf\"),\n    # Ruff\n    Config.home(\".config/ruff/ruff.toml\", \"ruff/ruff.toml\"),\n    # Paru\n    Config.home(\".config/paru/paru.conf\", \"paru/paru.conf\"),\n    # Hyprland\n    Config.home(\n        \".config/hypr/hyprlock.conf\",\n        \"hypr/hyprlock.conf\",\n        templated=True,\n    ),\n    Config.home(\".config/hypr/hypridle.conf\", \"hypr/hypridle.conf\"),\n    # Waybar\n    Config.home(\n        \".config/waybar/config\",\n        \"waybar/config\",\n        templated=True,\n    ),\n    Config.home(\n        \".config/waybar/style.css\",\n        \"waybar/style.css\",\n        templated=True,\n    ),\n    # Foot\n    Config.home(\n        \".config/foot/foot.ini\",\n        \"foot/foot.ini\",\n        templated=True,\n    ),\n    # Mako\n    Config.home(\n        \".config/mako/config\",\n        \"mako/config\",\n        templated=True,\n    ),\n    # Fuzzel\n    Config.home(\n        \".config/fuzzel/fuzzel.ini\", \"fuzzel/fuzzel.ini\", templated=True\n    ),\n    # Fontconfig\n    Config.home(\".config/fontconfig/fonts.conf\", \"fontconfig/fonts.conf\"),\n    # Electron\n    Config.home(\n        \".config/electron29-flags.conf\",\n        \"electron/electron-flags.conf\",\n    ),\n    Config.home(\n        \".config/electron30-flags.conf\",\n        \"electron/electron-flags.conf\",\n    ),\n    # XDG\n    Config.home(\".config/user-dirs.dirs\", \"xdg/user-dirs.dirs\"),\n    Config.home(\".config/mimeapps.list\", \"xdg/mimeapps.list\"),\n    # IPython\n    Config.home(\n        \".ipython/profile_default/ipython_config.py\",\n        \"ipython/ipython_config.py\",\n    ),\n    # Matplotlib\n    Config.home(\n        \".config/matplotlib/matplotlibrc\",\n        \"matplotlib/matplotlibrc\",\n    ),\n    # XCompose\n    Config.home(\".XCompose\", \"x11/xcompose\"),\n    # Zathura\n    Config.home(\n        \".config/zathura/zathurarc\",\n        \"zathura/zathurarc\",\n        templated=True,\n    ),\n    # Aria2\n    Config.home(\".config/aria2/aria2.conf\", \"aria2/aria2.conf\"),\n    # Mpv\n    Config.home(\".config/mpv/mpv.conf\", \"mpv/mpv.conf\"),\n    Config.home(\".config/mpv/input.conf\", \"mpv/input.conf\"),\n    # Cargo\n    Config.home(\".cargo/config.toml\", \"cargo/config.toml\"),\n    # Numbat\n    Config.home(\".config/numbat/config.toml\", \"numbat/config.toml\"),\n    # Poetry\n    Config.home(\".config/pypoetry/config.toml\", \"pypoetry/config.toml\"),\n    # Ledger\n    Config.home(\".ledgerrc\", \"ledger/ledgerrc\"),\n    # Zed\n    Config.home(\".config/zed/settings.json\", \"zed/settings.json\"),\n    Config.home(\".config/zed/keymap.json\", \"zed/keymap.json\"),\n    Config.home(\".config/zed/themes/Casablanca.json\", \"zed/theme.json\"),\n    # Neovim\n    Config.home(\".config/nvim/init.lua\", \"nvim/init.lua\"),\n    Config.home(\".config/nvim/colors/nuitbleue.vim\", \"nvim/nuitbleue.vim\"),\n    # Fd\n    Config.home(\".config/fd/ignore\", \"fd/ignore\"),\n    # NPM\n    Config.home(\".npmrc\", \"npm/npmrc\"),\n    # Niri\n    Config.home(\".config/niri/config.kdl\", \"niri/config.kdl\"),\n    # XKB\n    Config.home(\".config/xkb/symbols/group\", \"xkb/symbols/group\"),\n    Config.home(\".config/xkb/rules/evdev\", \"xkb/rules/evdev\"),\n]\n\n\nLEGACY_CONFIG_FILES = [\n    # Helix (replaced by neovim)\n    Config.home(\".config/helix/config.toml\", \"helix/config.toml\"),\n    Config.home(\n        \".config/helix/languages.toml\",\n        \"helix/languages.toml\",\n        templated=True,\n    ),\n    Config.home(\".config/helix/ignore\", \"helix/ignore\"),\n    Config.home(\n        \".config/helix/themes/cj.toml\",\n        \"helix/theme.toml\",\n        templated=True,\n    ),\n    # Wofi (replaced by fuzzel)\n    Config.home(\".config/wofi/config\", \"wofi/config\"),\n    Config.home(\".config/wofi/style.css\", \"wofi/style.css\", templated=True),\n    # Sway (replaced by niri)\n    Config.home(\n        \".config/sway/config\",\n        \"sway/config\",\n        templated=True,\n    ),\n    # Swaylock (replaced by hyprlock)\n    Config.home(\n        \".config/swaylock/config\",\n        \"swaylock/config\",\n        templated=True,\n    ),\n    # Hyprland (replaced by niri)\n    Config.home(\n        \".config/hypr/hyprland.conf\",\n        \"hypr/hyprland.conf\",\n        templated=True,\n    ),\n    # Cspell (replaced by codebook)\n    Config.home(\".cspell.yml\", \"cspell/cspell.yml\"),\n    Config.home(\".local/cspell-cj.txt\", \"cspell/dict-cj.txt\"),\n]\n\n\n# Termux-dependent files\nif OS_TERMUX:\n    CONFIG_FILES += [\n        Config.home(\n            \".termux/termux.properties\",\n            \"termux/termux.properties\",\n        ),\n        Config.home(\n            \".termux/colors.properties\",\n            \"termux/colors.properties\",\n            templated=True,\n        ),\n    ]\n\n\ndef main() -> None:\n    try:\n        action = sys.argv[1]\n    except IndexError:\n        sys.stderr.write(\n            \"× CRIT: action is not specified. Should be `install` or `sync-repo`\\n\"\n        )\n        sys.exit(1)\n\n    if action == \"install\":\n        ensure_directories()\n        render_all(reverse=False)\n    elif action == \"sync-repo\":\n        render_all(reverse=True)\n    else:\n        sys.stderr.write(\n            f\"× CRIT: unknown action `{action}`. Should be `install` or `sync-repo`\\n\"\n        )\n        sys.exit(1)\n\n\ndef ensure_directories() -> None:\n    for dir in DIRECTORIES:\n        sys.stderr.write(f\"× INFO: ensure directory {dir.path} exists\\n\")\n        dir.ensure()\n\n\ndef render_all(reverse: bool) -> None:\n    if reverse:\n        process = de_render\n    else:\n        settings = load_settings()\n        process = lambda file: render(file, settings)\n\n    for file in CONFIG_FILES:\n        process(file)\n\n\ndef load_settings() -> dict[str, str]:\n    settings_path = REPO_ROOT / \"settings.toml\"\n\n    with settings_path.open(\"rb\") as settings_file:\n        settings = tomllib.load(settings_file)\n\n    # Add builtin variables\n    builtin_vars = {\n        \"home\": str(Path.home()),\n        \"repo\": str(REPO_ROOT),\n    }\n    settings.update(builtin_vars)\n\n    return settings\n\n\ndef render(file: Config, settings: dict[str, str]) -> None:\n    sys.stderr.write(f\"× INFO: render {file.repo} to {file.host}\\n\")\n\n    file.host.parent.mkdir(parents=True, exist_ok=True)\n\n    # Load original file\n    with file.repo.open(\"r\") as repo_file:\n        original_data = repo_file.read()\n\n    # Render template\n    if file.templated:\n        template = Template(original_data)\n        config_data = template.safe_substitute(**settings)\n    else:\n        config_data = original_data\n\n    # Write final config\n    with file.host.open(\"w\") as host_file:\n        host_file.write(config_data)\n\n\ndef de_render(file: Config) -> None:\n    \"\"\"\n    Copies file from host back to config directory\n    \"\"\"\n\n    sys.stderr.write(f\"× INFO: de-render {file.host} to {file.repo}\\n\")\n\n    file.repo.parent.mkdir(parents=True, exist_ok=True)\n\n    if file.host.exists():\n        shutil.copy(file.host, file.repo)\n    else:\n        sys.stderr.write(\n            f\"× WARNING: file {file.host} doesn't exist. Skipping\\n\"\n        )\n\n\nif __name__ == \"__main__\":\n    main()\n"
  }
]