Moving final computer over to OpenBSD 7.6. - dotfiles - These are my dotfiles. There are many like it, but these are mine.
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
 (DIR) commit 2274190a12736e2d3c2dce6e346e582a7092dd5e
 (DIR) parent 38522989aa40a65ccd5ce9d8635ec097f20a61d8
 (HTM) Author: Jay Scott <me@jay.scot>
       Date:   Tue,  7 Jan 2025 20:11:03 +0000
       
       Moving final computer over to OpenBSD 7.6.
       
       Diffstat:
         M README                              |      14 +++++++-------
         A Xdefaults                           |      54 +++++++++++++++++++++++++++++++
         D ashrc                               |      67 -------------------------------
         A bin/diceware                        |    1338 ++++++++++++++++++++++++++++++
         A bin/mullvad                         |      31 +++++++++++++++++++++++++++++++
         M bin/music                           |       2 +-
         A bin/pass                            |     279 +++++++++++++++++++++++++++++++
         D bin/sway-start                      |      22 ----------------------
         M bootstrap.sh                        |       4 ++--
         D foot/foot.ini                       |      27 ---------------------------
         A kshrc                               |      63 +++++++++++++++++++++++++++++++
         A mpd/mpd.conf                        |      20 ++++++++++++++++++++
         A ncmpcpp/config                      |      31 +++++++++++++++++++++++++++++++
         M profile                             |       2 +-
         D qutebrowser/blank.html              |      44 -------------------------------
         D qutebrowser/config.py               |      92 -------------------------------
         D qutebrowser/scripts/fingerprint.py  |      43 ------------------------------
         D qutebrowser/scripts/gruvbox.py      |     332 -------------------------------
         D qutebrowser/scripts/redirects.py    |      70 -------------------------------
         D qutebrowser/scripts/user_agent.py   |      31 -------------------------------
         A suckless/dmenu/Makefile             |      39 +++++++++++++++++++++++++++++++
         A suckless/dmenu/config.h             |      16 ++++++++++++++++
         A suckless/dmenu/patches/01-dmenu-bo… |      36 +++++++++++++++++++++++++++++++
         A suckless/dmenu/patches/02-dmenu-ce… |     120 +++++++++++++++++++++++++++++++
         A suckless/dwm/Makefile               |      41 +++++++++++++++++++++++++++++++
         A suckless/dwm/config.h               |     201 ++++++++++++++++++++++++++++++
         A suckless/dwm/patches/01-dwm-systra… |     746 +++++++++++++++++++++++++++++++
         A suckless/herbe/Makefile             |      40 +++++++++++++++++++++++++++++++
         A suckless/herbe/config.h             |      19 +++++++++++++++++++
         A suckless/slstatus/Makefile          |      35 +++++++++++++++++++++++++++++++
         A suckless/slstatus/config.h          |      71 +++++++++++++++++++++++++++++++
         D sway/config                         |      69 ------------------------------
         D waybar/config                       |      67 -------------------------------
         D waybar/style.css                    |      55 -------------------------------
         D waybar/waybar_mail.sh               |      12 ------------
         D waybar/waybar_vpn.sh                |       9 ---------
         A xenodm/Xresources                   |      24 ++++++++++++++++++++++++
         A xenodm/Xsetup_0                     |       7 +++++++
       
       38 files changed, 3222 insertions(+), 951 deletions(-)
       ---
 (DIR) diff --git a/README b/README
       @@ -8,16 +8,16 @@
        These are my dotfiles. There are many like it, but these are mine.
        
        They are managed via the bootstrap.sh shell script, this links the files and
       -folders in the appropriate place. They are used on Alpine Linux which I use as
       -my main desktop OS and are forever evolving.
       +folders in the appropriate place. They are used on OpenBSD which I use as my
       +main desktop OS and are forever evolving.
        
        
       -  operating sys  : alpine linux
       -  window manager : sway
       -  terminal       : foot
       -  launcher       : bemenu
       +  operating sys  : openbsd 7.6
       +  window manager : dwm
       +  terminal       : xterm
       +  launcher       : dmenu
          email          : neomutt
       -  browser        : qutebrowser / librewolf
       +  browser        : firefox / lynx
          media          : mpv
          password mgmt  : pass
          vpn            : mullvad
 (DIR) diff --git a/Xdefaults b/Xdefaults
       @@ -0,0 +1,54 @@
       +xterm*FaceName:        Hack
       +xterm*FaceSize:        14
       +xterm*toolBar: false
       +xterm*scrollBar: false
       +xterm*selectToClipboard: false
       +XTerm*loginShell:        true
       +XTerm*scrollBar:        false
       +XTerm*selectToClipboard:true
       +
       +/* XFT */
       +Xft.dpi:       96
       +Xft.hinting:   true
       +Xft.rgba:      rgb
       +Xft.antialias: true
       +Xft.autohint:  false
       +Xft.hintstyle: hintslight
       +Xft.lcdfilter: lcddefault
       +
       +! special
       +*.foreground:   #ebdbb2
       +*.background:   #282828
       +*.cursorColor:  #fbf0d2
       +
       +! black
       +*.color0:       #181512
       +*.color8:       #454545
       +
       +! red
       +*.color1:       #bb6055
       +*.color9:       #c94539
       +
       +! green
       +*.color2:       #80964d
       +*.color10:      #aabb46
       +
       +! yellow
       +*.color3:       #8b6268
       +*.color11:      #dab733
       +
       +! blue
       +*.color4:       #756583
       +*.color12:      #a3535e
       +
       +! magenta
       +*.color5:       #628185
       +*.color13:      #becc90
       +
       +! cyan
       +*.color6:       #a4b810
       +*.color14:      #69c884
       +
       +! white
       +*.color7:       #d3cab3
       +*.color15:      #c9b09a
 (DIR) diff --git a/ashrc b/ashrc
       @@ -1,67 +0,0 @@
       -export XDG_CONFIG_HOME="$HOME/.config"
       -export XDG_CACHE_HOME="$HOME/.cache"
       -export XDG_DATA_HOME="$HOME/.local/share"
       -export XDG_STATE_HOME="$HOME/.local/state"
       -
       -# cleanup ~/
       -export PASSWORD_STORE_DIR="$XDG_CONFIG_HOME"/pass
       -export CARGO_HOME="$XDG_DATA_HOME"/cargo
       -
       -# common exports
       -GPG_TTY=$(tty)
       -export GPG_TTY
       -export EDITOR="nvim"
       -export BROWSER="qutebrowser"
       -export PATH=$PATH:$HOME/bin
       -
       -# tools
       -export OPENER=~/bin/link-handler
       -export BEMENU_OPTS="-l 10 -p '>>> ' --tb '#55a1ba' --tf '#ffffff' --hf '#444444' -c  -W0.4 --fn 'Hack 10'"
       -
       -# lynx
       -export LYNX_CFG=$HOME/.config/lynx/config
       -export LYNX_LSS=$HOME/.config/lynx/theme.lss
       -
       -# safety first kids!
       -alias cp='cp -i'
       -alias mv='mv -i'
       -alias rm='rm -i'
       -
       -# random alias
       -alias weather='curl wttr.in/?1QF'
       -alias wget='wget --hsts-file="$XDG_CACHE_HOME/wget-hsts"'
       -
       -# git alias
       -alias ga='git add -A'
       -alias gs='git status -s'
       -alias gl="git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
       -alias gd='git diff'
       -alias gma='git commit -am'
       -
       -# neo
       -alias vim='nvim'
       -alias mutt='neomutt'
       -alias mpv="mpv --autofit=30% --really-quiet --no-terminal"
       -alias w="w3m -B"
       -
       -# vpn
       -alias von='doas wg-quick up mullvad'
       -alias voff='doas wg-quick down mullvad'
       -alias vcheck='curl https://am.i.mullvad.net/connected'
       -
       -# ash
       -export LANG=en_US.UTF-8
       -export LC_CTYPE="en_US.UTF-8"
       -export LC_ALL=en_US.UTF-8
       -export PS1="\[\e[00;34m\]▶▶▶ \W \[\e[0m\]"
       -
       -mirror_repo() {
       -    if [ -d .git ] || git rev-parse --git-dir > /dev/null 2>&1; then
       -        remote_url="git@jay.scot:$(basename $(pwd))"
       -        git remote add mirror "$remote_url" 2>/dev/null || true
       -        git push --mirror mirror
       -        echo "Mirrored to $remote_url"
       -    else
       -        echo "Not a git repository"
       -    fi
       -}
 (DIR) diff --git a/bin/diceware b/bin/diceware
       @@ -0,0 +1,1338 @@
       +#!/bin/sh
       +#
       +# diceware generates random phrases with 10 bits of entropy per
       +# word. For a passphrase use 8 words or more.
       +#
       +# https://www.romanzolotarev.com/bin/diceware
       +# Copyright 2017 Roman Zolotarev <hi@romanzolotarev.com>
       +#
       +# Permission to use, copy, modify, and/or distribute this software for any
       +# purpose with or without fee is hereby granted, provided that the above
       +# copyright notice and this permission notice appear in all copies.
       +#
       +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
       +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
       +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
       +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
       +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
       +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
       +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
       +#
       +# The word list: CC BY 3.0 US 2016 Electronic Frontier Foundation
       +# https://www.eff.org/deeplinks/2016/07/new-wordlists-random-passphrases
       +#
       +set -e
       +
       +wordlist=$(cat << EOF
       +1111 aardvark
       +1112 abandoned
       +1113 abbreviate
       +1114 abdomen
       +1115 abhorrence
       +1116 abiding
       +1121 abnormal
       +1122 abrasion
       +1123 absorbing
       +1124 abundant
       +1125 abyss
       +1126 academy
       +1131 accountant
       +1132 acetone
       +1133 achiness
       +1134 acid
       +1135 acoustics
       +1136 acquire
       +1141 acrobat
       +1142 actress
       +1143 acuteness
       +1144 aerosol
       +1145 aesthetic
       +1146 affidavit
       +1151 afloat
       +1152 afraid
       +1153 aftershave
       +1154 again
       +1155 agency
       +1156 aggressor
       +1161 aghast
       +1162 agitate
       +1163 agnostic
       +1164 agonizing
       +1165 agreeing
       +1166 aidless
       +1211 aimlessly
       +1212 ajar
       +1213 alarmclock
       +1214 albatross
       +1215 alchemy
       +1216 alfalfa
       +1221 algae
       +1222 aliens
       +1223 alkaline
       +1224 almanac
       +1225 alongside
       +1226 alphabet
       +1231 already
       +1232 also
       +1233 altitude
       +1234 aluminum
       +1235 always
       +1236 amazingly
       +1241 ambulance
       +1242 amendment
       +1243 amiable
       +1244 ammunition
       +1245 amnesty
       +1246 amoeba
       +1251 amplifier
       +1252 amuser
       +1253 anagram
       +1254 anchor
       +1255 android
       +1256 anesthesia
       +1261 angelfish
       +1262 animal
       +1263 anklet
       +1264 announcer
       +1265 anonymous
       +1266 answer
       +1311 antelope
       +1312 anxiety
       +1313 anyplace
       +1314 aorta
       +1315 apartment
       +1316 apnea
       +1321 apostrophe
       +1322 apple
       +1323 apricot
       +1324 aquamarine
       +1325 arachnid
       +1326 arbitrate
       +1331 ardently
       +1332 arena
       +1333 argument
       +1334 aristocrat
       +1335 armchair
       +1336 aromatic
       +1341 arrowhead
       +1342 arsonist
       +1343 artichoke
       +1344 asbestos
       +1345 ascend
       +1346 aseptic
       +1351 ashamed
       +1352 asinine
       +1353 asleep
       +1354 asocial
       +1355 asparagus
       +1356 astronaut
       +1361 asymmetric
       +1362 atlas
       +1363 atmosphere
       +1364 atom
       +1365 atrocious
       +1366 attic
       +1411 atypical
       +1412 auctioneer
       +1413 auditorium
       +1414 augmented
       +1415 auspicious
       +1416 automobile
       +1421 auxiliary
       +1422 avalanche
       +1423 avenue
       +1424 aviator
       +1425 avocado
       +1426 awareness
       +1431 awhile
       +1432 awkward
       +1433 awning
       +1434 awoke
       +1435 axially
       +1436 azalea
       +1441 babbling
       +1442 backpack
       +1443 badass
       +1444 bagpipe
       +1445 bakery
       +1446 balancing
       +1451 bamboo
       +1452 banana
       +1453 barracuda
       +1454 basket
       +1455 bathrobe
       +1456 bazooka
       +1461 blade
       +1462 blender
       +1463 blimp
       +1464 blouse
       +1465 blurred
       +1466 boatyard
       +1511 bobcat
       +1512 body
       +1513 bogusness
       +1514 bohemian
       +1515 boiler
       +1516 bonnet
       +1521 boots
       +1522 borough
       +1523 bossiness
       +1524 bottle
       +1525 bouquet
       +1526 boxlike
       +1531 breath
       +1532 briefcase
       +1533 broom
       +1534 brushes
       +1535 bubblegum
       +1536 buckle
       +1541 buddhist
       +1542 buffalo
       +1543 bullfrog
       +1544 bunny
       +1545 busboy
       +1546 buzzard
       +1551 cabin
       +1552 cactus
       +1553 cadillac
       +1554 cafeteria
       +1555 cage
       +1556 cahoots
       +1561 cajoling
       +1562 cakewalk
       +1563 calculator
       +1564 camera
       +1565 canister
       +1566 capsule
       +1611 carrot
       +1612 cashew
       +1613 cathedral
       +1614 caucasian
       +1615 caviar
       +1616 ceasefire
       +1621 cedar
       +1622 celery
       +1623 cement
       +1624 census
       +1625 ceramics
       +1626 cesspool
       +1631 chalkboard
       +1632 cheesecake
       +1633 chimney
       +1634 chlorine
       +1635 chopsticks
       +1636 chrome
       +1641 chute
       +1642 cilantro
       +1643 cinnamon
       +1644 circle
       +1645 cityscape
       +1646 civilian
       +1651 clay
       +1652 clergyman
       +1653 clipboard
       +1654 clock
       +1655 clubhouse
       +1656 coathanger
       +1661 cobweb
       +1662 coconut
       +1663 codeword
       +1664 coexistent
       +1665 coffeecake
       +1666 cognitive
       +2111 cohabitate
       +2112 collarbone
       +2113 computer
       +2114 confetti
       +2115 copier
       +2116 cornea
       +2121 cosmetics
       +2122 cotton
       +2123 couch
       +2124 coverless
       +2125 coyote
       +2126 coziness
       +2131 crawfish
       +2132 crewmember
       +2133 crib
       +2134 croissant
       +2135 crumble
       +2136 crystal
       +2141 cubical
       +2142 cucumber
       +2143 cuddly
       +2144 cufflink
       +2145 cuisine
       +2146 culprit
       +2151 cup
       +2152 curry
       +2153 cushion
       +2154 cuticle
       +2155 cybernetic
       +2156 cyclist
       +2161 cylinder
       +2162 cymbal
       +2163 cynicism
       +2164 cypress
       +2165 cytoplasm
       +2166 dachshund
       +2211 daffodil
       +2212 dagger
       +2213 dairy
       +2214 dalmatian
       +2215 dandelion
       +2216 dartboard
       +2221 dastardly
       +2222 datebook
       +2223 daughter
       +2224 dawn
       +2225 daytime
       +2226 dazzler
       +2231 dealer
       +2232 debris
       +2233 decal
       +2234 dedicate
       +2235 deepness
       +2236 defrost
       +2241 degree
       +2242 dehydrator
       +2243 deliverer
       +2244 democrat
       +2245 dentist
       +2246 deodorant
       +2251 depot
       +2252 deranged
       +2253 desktop
       +2254 detergent
       +2255 device
       +2256 dexterity
       +2261 diamond
       +2262 dibs
       +2263 dictionary
       +2264 diffuser
       +2265 digit
       +2266 dilated
       +2311 dimple
       +2312 dinnerware
       +2313 dioxide
       +2314 diploma
       +2315 directory
       +2316 dishcloth
       +2321 ditto
       +2322 dividers
       +2323 dizziness
       +2324 doctor
       +2325 dodge
       +2326 doll
       +2331 dominoes
       +2332 donut
       +2333 doorstep
       +2334 dorsal
       +2335 double
       +2336 downstairs
       +2341 dozed
       +2342 drainpipe
       +2343 dresser
       +2344 driftwood
       +2345 droppings
       +2346 drum
       +2351 dryer
       +2352 dubiously
       +2353 duckling
       +2354 duffel
       +2355 dugout
       +2356 dumpster
       +2361 duplex
       +2362 durable
       +2363 dustpan
       +2364 dutiful
       +2365 duvet
       +2366 dwarfism
       +2411 dwelling
       +2412 dwindling
       +2413 dynamite
       +2414 dyslexia
       +2415 eagerness
       +2416 earlobe
       +2421 easel
       +2422 eavesdrop
       +2423 ebook
       +2424 eccentric
       +2425 echoless
       +2426 eclipse
       +2431 ecosystem
       +2432 ecstasy
       +2433 edged
       +2434 editor
       +2435 educator
       +2436 eelworm
       +2441 eerie
       +2442 effects
       +2443 eggnog
       +2444 egomaniac
       +2445 ejection
       +2446 elastic
       +2451 elbow
       +2452 elderly
       +2453 elephant
       +2454 elfishly
       +2455 eliminator
       +2456 elk
       +2461 elliptical
       +2462 elongated
       +2463 elsewhere
       +2464 elusive
       +2465 elves
       +2466 emancipate
       +2511 embroidery
       +2512 emcee
       +2513 emerald
       +2514 emission
       +2515 emoticon
       +2516 emperor
       +2521 emulate
       +2522 enactment
       +2523 enchilada
       +2524 endorphin
       +2525 energy
       +2526 enforcer
       +2531 engine
       +2532 enhance
       +2533 enigmatic
       +2534 enjoyably
       +2535 enlarged
       +2536 enormous
       +2541 enquirer
       +2542 enrollment
       +2543 ensemble
       +2544 entryway
       +2545 enunciate
       +2546 envoy
       +2551 enzyme
       +2552 epidemic
       +2553 equipment
       +2554 erasable
       +2555 ergonomic
       +2556 erratic
       +2561 eruption
       +2562 escalator
       +2563 eskimo
       +2564 esophagus
       +2565 espresso
       +2566 essay
       +2611 estrogen
       +2612 etching
       +2613 eternal
       +2614 ethics
       +2615 etiquette
       +2616 eucalyptus
       +2621 eulogy
       +2622 euphemism
       +2623 euthanize
       +2624 evacuation
       +2625 evergreen
       +2626 evidence
       +2631 evolution
       +2632 exam
       +2633 excerpt
       +2634 exerciser
       +2635 exfoliate
       +2636 exhale
       +2641 exist
       +2642 exorcist
       +2643 explode
       +2644 exquisite
       +2645 exterior
       +2646 exuberant
       +2651 fabric
       +2652 factory
       +2653 faded
       +2654 failsafe
       +2655 falcon
       +2656 family
       +2661 fanfare
       +2662 fasten
       +2663 faucet
       +2664 favorite
       +2665 feasibly
       +2666 february
       +3111 federal
       +3112 feedback
       +3113 feigned
       +3114 feline
       +3115 femur
       +3116 fence
       +3121 ferret
       +3122 festival
       +3123 fettuccine
       +3124 feudalist
       +3125 feverish
       +3126 fiberglass
       +3131 fictitious
       +3132 fiddle
       +3133 figurine
       +3134 fillet
       +3135 finalist
       +3136 fiscally
       +3141 fixture
       +3142 flashlight
       +3143 fleshiness
       +3144 flight
       +3145 florist
       +3146 flypaper
       +3151 foamless
       +3152 focus
       +3153 foggy
       +3154 folksong
       +3155 fondue
       +3156 footpath
       +3161 fossil
       +3162 fountain
       +3163 fox
       +3164 fragment
       +3165 freeway
       +3166 fridge
       +3211 frosting
       +3212 fruit
       +3213 fryingpan
       +3214 gadget
       +3215 gainfully
       +3216 gallstone
       +3221 gamekeeper
       +3222 gangway
       +3223 garlic
       +3224 gaslight
       +3225 gathering
       +3226 gauntlet
       +3231 gearbox
       +3232 gecko
       +3233 gem
       +3234 generator
       +3235 geographer
       +3236 gerbil
       +3241 gesture
       +3242 getaway
       +3243 geyser
       +3244 ghoulishly
       +3245 gibberish
       +3246 giddiness
       +3251 giftshop
       +3252 gigabyte
       +3253 gimmick
       +3254 giraffe
       +3255 giveaway
       +3256 gizmo
       +3261 glasses
       +3262 gleeful
       +3263 glisten
       +3264 glove
       +3265 glucose
       +3266 glycerin
       +3311 gnarly
       +3312 gnomish
       +3313 goatskin
       +3314 goggles
       +3315 goldfish
       +3316 gong
       +3321 gooey
       +3322 gorgeous
       +3323 gosling
       +3324 gothic
       +3325 gourmet
       +3326 governor
       +3331 grape
       +3332 greyhound
       +3333 grill
       +3334 groundhog
       +3335 grumbling
       +3336 guacamole
       +3341 guerrilla
       +3342 guitar
       +3343 gullible
       +3344 gumdrop
       +3345 gurgling
       +3346 gusto
       +3351 gutless
       +3352 gymnast
       +3353 gynecology
       +3354 gyration
       +3355 habitat
       +3356 hacking
       +3361 haggard
       +3362 haiku
       +3363 halogen
       +3364 hamburger
       +3365 handgun
       +3366 happiness
       +3411 hardhat
       +3412 hastily
       +3413 hatchling
       +3414 haughty
       +3415 hazelnut
       +3416 headband
       +3421 hedgehog
       +3422 hefty
       +3423 heinously
       +3424 helmet
       +3425 hemoglobin
       +3426 henceforth
       +3431 herbs
       +3432 hesitation
       +3433 hexagon
       +3434 hubcap
       +3435 huddling
       +3436 huff
       +3441 hugeness
       +3442 hullabaloo
       +3443 human
       +3444 hunter
       +3445 hurricane
       +3446 hushing
       +3451 hyacinth
       +3452 hybrid
       +3453 hydrant
       +3454 hygienist
       +3455 hypnotist
       +3456 ibuprofen
       +3461 icepack
       +3462 icing
       +3463 iconic
       +3464 identical
       +3465 idiocy
       +3466 idly
       +3511 igloo
       +3512 ignition
       +3513 iguana
       +3514 illuminate
       +3515 imaging
       +3516 imbecile
       +3521 imitator
       +3522 immigrant
       +3523 imprint
       +3524 iodine
       +3525 ionosphere
       +3526 ipad
       +3531 iphone
       +3532 iridescent
       +3533 irksome
       +3534 iron
       +3535 irrigation
       +3536 island
       +3541 isotope
       +3542 issueless
       +3543 italicize
       +3544 itemizer
       +3545 itinerary
       +3546 itunes
       +3551 ivory
       +3552 jabbering
       +3553 jackrabbit
       +3554 jaguar
       +3555 jailhouse
       +3556 jalapeno
       +3561 jamboree
       +3562 janitor
       +3563 jarring
       +3564 jasmine
       +3565 jaundice
       +3566 jawbreaker
       +3611 jaywalker
       +3612 jazz
       +3613 jealous
       +3614 jeep
       +3615 jelly
       +3616 jeopardize
       +3621 jersey
       +3622 jetski
       +3623 jezebel
       +3624 jiffy
       +3625 jigsaw
       +3626 jingling
       +3631 jobholder
       +3632 jockstrap
       +3633 jogging
       +3634 john
       +3635 joinable
       +3636 jokingly
       +3641 journal
       +3642 jovial
       +3643 joystick
       +3644 jubilant
       +3645 judiciary
       +3646 juggle
       +3651 juice
       +3652 jujitsu
       +3653 jukebox
       +3654 jumpiness
       +3655 junkyard
       +3656 juror
       +3661 justifying
       +3662 juvenile
       +3663 kabob
       +3664 kamikaze
       +3665 kangaroo
       +3666 karate
       +4111 kayak
       +4112 keepsake
       +4113 kennel
       +4114 kerosene
       +4115 ketchup
       +4116 khaki
       +4121 kickstand
       +4122 kilogram
       +4123 kimono
       +4124 kingdom
       +4125 kiosk
       +4126 kissing
       +4131 kite
       +4132 kleenex
       +4133 knapsack
       +4134 kneecap
       +4135 knickers
       +4136 koala
       +4141 krypton
       +4142 laboratory
       +4143 ladder
       +4144 lakefront
       +4145 lantern
       +4146 laptop
       +4151 laryngitis
       +4152 lasagna
       +4153 latch
       +4154 laundry
       +4155 lavender
       +4156 laxative
       +4161 lazybones
       +4162 lecturer
       +4163 leftover
       +4164 leggings
       +4165 leisure
       +4166 lemon
       +4211 length
       +4212 leopard
       +4213 leprechaun
       +4214 lettuce
       +4215 leukemia
       +4216 levers
       +4221 lewdness
       +4222 liability
       +4223 library
       +4224 licorice
       +4225 lifeboat
       +4226 lightbulb
       +4231 likewise
       +4232 lilac
       +4233 limousine
       +4234 lint
       +4235 lioness
       +4236 lipstick
       +4241 liquid
       +4242 listless
       +4243 litter
       +4244 liverwurst
       +4245 lizard
       +4246 llama
       +4251 luau
       +4252 lubricant
       +4253 lucidity
       +4254 ludicrous
       +4255 luggage
       +4256 lukewarm
       +4261 lullaby
       +4262 lumberjack
       +4263 lunchbox
       +4264 luridness
       +4265 luscious
       +4266 luxurious
       +4311 lyrics
       +4312 macaroni
       +4313 maestro
       +4314 magazine
       +4315 mahogany
       +4316 maimed
       +4321 majority
       +4322 makeover
       +4323 malformed
       +4324 mammal
       +4325 mango
       +4326 mapmaker
       +4331 marbles
       +4332 massager
       +4333 matchstick
       +4334 maverick
       +4335 maximum
       +4336 mayonnaise
       +4341 moaning
       +4342 mobilize
       +4343 moccasin
       +4344 modify
       +4345 moisture
       +4346 molecule
       +4351 momentum
       +4352 monastery
       +4353 moonshine
       +4354 mortuary
       +4355 mosquito
       +4356 motorcycle
       +4361 mousetrap
       +4362 movie
       +4363 mower
       +4364 mozzarella
       +4365 muckiness
       +4366 mudflow
       +4411 mugshot
       +4412 mule
       +4413 mummy
       +4414 mundane
       +4415 muppet
       +4416 mural
       +4421 mustard
       +4422 mutation
       +4423 myriad
       +4424 myspace
       +4425 myth
       +4426 nail
       +4431 namesake
       +4432 nanosecond
       +4433 napkin
       +4434 narrator
       +4435 nastiness
       +4436 natives
       +4441 nautically
       +4442 navigate
       +4443 nearest
       +4444 nebula
       +4445 nectar
       +4446 nefarious
       +4451 negotiator
       +4452 neither
       +4453 nemesis
       +4454 neoliberal
       +4455 nephew
       +4456 nervously
       +4461 nest
       +4462 netting
       +4463 neuron
       +4464 nevermore
       +4465 nextdoor
       +4466 nicotine
       +4511 niece
       +4512 nimbleness
       +4513 nintendo
       +4514 nirvana
       +4515 nuclear
       +4516 nugget
       +4521 nuisance
       +4522 nullify
       +4523 numbing
       +4524 nuptials
       +4525 nursery
       +4526 nutcracker
       +4531 nylon
       +4532 oasis
       +4533 oat
       +4534 obediently
       +4535 obituary
       +4536 object
       +4541 obliterate
       +4542 obnoxious
       +4543 observer
       +4544 obtain
       +4545 obvious
       +4546 occupation
       +4551 oceanic
       +4552 octopus
       +4553 ocular
       +4554 office
       +4555 oftentimes
       +4556 oiliness
       +4561 ointment
       +4562 older
       +4563 olympics
       +4564 omissible
       +4565 omnivorous
       +4566 oncoming
       +4611 onion
       +4612 onlooker
       +4613 onstage
       +4614 onward
       +4615 onyx
       +4616 oomph
       +4621 opaquely
       +4622 opera
       +4623 opium
       +4624 opossum
       +4625 opponent
       +4626 optical
       +4631 opulently
       +4632 oscillator
       +4633 osmosis
       +4634 ostrich
       +4635 otherwise
       +4636 ought
       +4641 outhouse
       +4642 ovation
       +4643 oven
       +4644 owlish
       +4645 oxford
       +4646 oxidize
       +4651 oxygen
       +4652 oyster
       +4653 ozone
       +4654 pacemaker
       +4655 padlock
       +4656 pageant
       +4661 pajamas
       +4662 palm
       +4663 pamphlet
       +4664 pantyhose
       +4665 paprika
       +4666 parakeet
       +5111 passport
       +5112 patio
       +5113 pauper
       +5114 pavement
       +5115 payphone
       +5116 pebble
       +5121 peculiarly
       +5122 pedometer
       +5123 pegboard
       +5124 pelican
       +5125 penguin
       +5126 peony
       +5131 pepperoni
       +5132 peroxide
       +5133 pesticide
       +5134 petroleum
       +5135 pewter
       +5136 pharmacy
       +5141 pheasant
       +5142 phonebook
       +5143 phrasing
       +5144 physician
       +5145 plank
       +5146 pledge
       +5151 plotted
       +5152 plug
       +5153 plywood
       +5154 pneumonia
       +5155 podiatrist
       +5156 poetic
       +5161 pogo
       +5162 poison
       +5163 poking
       +5164 policeman
       +5165 poncho
       +5166 popcorn
       +5211 porcupine
       +5212 postcard
       +5213 poultry
       +5214 powerboat
       +5215 prairie
       +5216 pretzel
       +5221 princess
       +5222 propeller
       +5223 prune
       +5224 pry
       +5225 pseudo
       +5226 psychopath
       +5231 publisher
       +5232 pucker
       +5233 pueblo
       +5234 pulley
       +5235 pumpkin
       +5236 punchbowl
       +5241 puppy
       +5242 purse
       +5243 pushup
       +5244 putt
       +5245 puzzle
       +5246 pyramid
       +5251 python
       +5252 quarters
       +5253 quesadilla
       +5254 quilt
       +5255 quote
       +5256 racoon
       +5261 radish
       +5262 ragweed
       +5263 railroad
       +5264 rampantly
       +5265 rancidity
       +5266 rarity
       +5311 raspberry
       +5312 ravishing
       +5313 rearrange
       +5314 rebuilt
       +5315 receipt
       +5316 reentry
       +5321 refinery
       +5322 register
       +5323 rehydrate
       +5324 reimburse
       +5325 rejoicing
       +5326 rekindle
       +5331 relic
       +5332 remote
       +5333 renovator
       +5334 reopen
       +5335 reporter
       +5336 request
       +5341 rerun
       +5342 reservoir
       +5343 retriever
       +5344 reunion
       +5345 revolver
       +5346 rewrite
       +5351 rhapsody
       +5352 rhetoric
       +5353 rhino
       +5354 rhubarb
       +5355 rhyme
       +5356 ribbon
       +5361 riches
       +5362 ridden
       +5363 rigidness
       +5364 rimmed
       +5365 riptide
       +5366 riskily
       +5411 ritzy
       +5412 riverboat
       +5413 roamer
       +5414 robe
       +5415 rocket
       +5416 romancer
       +5421 ropelike
       +5422 rotisserie
       +5423 roundtable
       +5424 royal
       +5425 rubber
       +5426 rudderless
       +5431 rugby
       +5432 ruined
       +5433 rulebook
       +5434 rummage
       +5435 running
       +5436 rupture
       +5441 rustproof
       +5442 sabotage
       +5443 sacrifice
       +5444 saddlebag
       +5445 saffron
       +5446 sainthood
       +5451 saltshaker
       +5452 samurai
       +5453 sandworm
       +5454 sapphire
       +5455 sardine
       +5456 sassy
       +5461 satchel
       +5462 sauna
       +5463 savage
       +5464 saxophone
       +5465 scarf
       +5466 scenario
       +5511 schoolbook
       +5512 scientist
       +5513 scooter
       +5514 scrapbook
       +5515 sculpture
       +5516 scythe
       +5521 secretary
       +5522 sedative
       +5523 segregator
       +5524 seismology
       +5525 selected
       +5526 semicolon
       +5531 senator
       +5532 septum
       +5533 sequence
       +5534 serpent
       +5535 sesame
       +5536 settler
       +5541 severely
       +5542 shack
       +5543 shelf
       +5544 shirt
       +5545 shovel
       +5546 shrimp
       +5551 shuttle
       +5552 shyness
       +5553 siamese
       +5554 sibling
       +5555 siesta
       +5556 silicon
       +5561 simmering
       +5562 singles
       +5563 sisterhood
       +5564 sitcom
       +5565 sixfold
       +5566 sizable
       +5611 skateboard
       +5612 skeleton
       +5613 skies
       +5614 skulk
       +5615 skylight
       +5616 slapping
       +5621 sled
       +5622 slingshot
       +5623 sloth
       +5624 slumbering
       +5625 smartphone
       +5626 smelliness
       +5631 smitten
       +5632 smokestack
       +5633 smudge
       +5634 snapshot
       +5635 sneezing
       +5636 sniff
       +5641 snowsuit
       +5642 snugness
       +5643 speakers
       +5644 sphinx
       +5645 spider
       +5646 splashing
       +5651 sponge
       +5652 sprout
       +5653 spur
       +5654 spyglass
       +5655 squirrel
       +5656 statue
       +5661 steamboat
       +5662 stingray
       +5663 stopwatch
       +5664 strawberry
       +5665 student
       +5666 stylus
       +6111 suave
       +6112 subway
       +6113 suction
       +6114 suds
       +6115 suffocate
       +6116 sugar
       +6121 suitcase
       +6122 sulphur
       +6123 superstore
       +6124 surfer
       +6125 sushi
       +6126 swan
       +6131 sweatshirt
       +6132 swimwear
       +6133 sword
       +6134 sycamore
       +6135 syllable
       +6136 symphony
       +6141 synagogue
       +6142 syringes
       +6143 systemize
       +6144 tablespoon
       +6145 taco
       +6146 tadpole
       +6151 taekwondo
       +6152 tagalong
       +6153 takeout
       +6154 tallness
       +6155 tamale
       +6156 tanned
       +6161 tapestry
       +6162 tarantula
       +6163 tastebud
       +6164 tattoo
       +6165 tavern
       +6166 thaw
       +6211 theater
       +6212 thimble
       +6213 thorn
       +6214 throat
       +6215 thumb
       +6216 thwarting
       +6221 tiara
       +6222 tidbit
       +6223 tiebreaker
       +6224 tiger
       +6225 timid
       +6226 tinsel
       +6231 tiptoeing
       +6232 tirade
       +6233 tissue
       +6234 tractor
       +6235 tree
       +6236 tripod
       +6241 trousers
       +6242 trucks
       +6243 tryout
       +6244 tubeless
       +6245 tuesday
       +6246 tugboat
       +6251 tulip
       +6252 tumbleweed
       +6253 tupperware
       +6254 turtle
       +6255 tusk
       +6256 tutorial
       +6261 tuxedo
       +6262 tweezers
       +6263 twins
       +6264 tyrannical
       +6265 ultrasound
       +6266 umbrella
       +6311 umpire
       +6312 unarmored
       +6313 unbuttoned
       +6314 uncle
       +6315 underwear
       +6316 unevenness
       +6321 unflavored
       +6322 ungloved
       +6323 unhinge
       +6324 unicycle
       +6325 unjustly
       +6326 unknown
       +6331 unlocking
       +6332 unmarked
       +6333 unnoticed
       +6334 unopened
       +6335 unpaved
       +6336 unquenched
       +6341 unroll
       +6342 unscrewing
       +6343 untied
       +6344 unusual
       +6345 unveiled
       +6346 unwrinkled
       +6351 unyielding
       +6352 unzip
       +6353 upbeat
       +6354 upcountry
       +6355 update
       +6356 upfront
       +6361 upgrade
       +6362 upholstery
       +6363 upkeep
       +6364 upload
       +6365 uppercut
       +6366 upright
       +6411 upstairs
       +6412 uptown
       +6413 upwind
       +6414 uranium
       +6415 urban
       +6416 urchin
       +6421 urethane
       +6422 urgent
       +6423 urologist
       +6424 username
       +6425 usher
       +6426 utensil
       +6431 utility
       +6432 utmost
       +6433 utopia
       +6434 utterance
       +6435 vacuum
       +6436 vagrancy
       +6441 valuables
       +6442 vanquished
       +6443 vaporizer
       +6444 varied
       +6445 vaseline
       +6446 vegetable
       +6451 vehicle
       +6452 velcro
       +6453 vendor
       +6454 vertebrae
       +6455 vestibule
       +6456 veteran
       +6461 vexingly
       +6462 vicinity
       +6463 videogame
       +6464 viewfinder
       +6465 vigilante
       +6466 village
       +6511 vinegar
       +6512 violin
       +6513 viperfish
       +6514 virus
       +6515 visor
       +6516 vitamins
       +6521 vivacious
       +6522 vixen
       +6523 vocalist
       +6524 vogue
       +6525 voicemail
       +6526 volleyball
       +6531 voucher
       +6532 voyage
       +6533 vulnerable
       +6534 waffle
       +6535 wagon
       +6536 wakeup
       +6541 walrus
       +6542 wanderer
       +6543 wasp
       +6544 water
       +6545 waving
       +6546 wheat
       +6551 whisper
       +6552 wholesaler
       +6553 wick
       +6554 widow
       +6555 wielder
       +6556 wifeless
       +6561 wikipedia
       +6562 wildcat
       +6563 windmill
       +6564 wipeout
       +6565 wired
       +6566 wishbone
       +6611 wizardry
       +6612 wobbliness
       +6613 wolverine
       +6614 womb
       +6615 woolworker
       +6616 workbasket
       +6621 wound
       +6622 wrangle
       +6623 wreckage
       +6624 wristwatch
       +6625 wrongdoing
       +6626 xerox
       +6631 xylophone
       +6632 yacht
       +6633 yahoo
       +6634 yard
       +6635 yearbook
       +6636 yesterday
       +6641 yiddish
       +6642 yield
       +6643 yo-yo
       +6644 yodel
       +6645 yogurt
       +6646 yuppie
       +6651 zealot
       +6652 zebra
       +6653 zeppelin
       +6654 zestfully
       +6655 zigzagged
       +6656 zillion
       +6661 zipping
       +6662 zirconium
       +6663 zodiac
       +6664 zombie
       +6665 zookeeper
       +6666 zucchini
       +EOF
       +)
       +
       +dice() {
       +        tr -cd '1-6'</dev/urandom|fold -w 4|head -n "$1"
       +}
       +
       +for num in $(dice "${1:-8}")
       +do
       +        echo "$wordlist"|
       +        grep "$num"|
       +        cut -d' ' -f2|
       +        tr '\n' ' '
       +done
       +
       +echo
 (DIR) diff --git a/bin/mullvad b/bin/mullvad
       @@ -0,0 +1,31 @@
       +#!/bin/sh
       +gw="$(route -n show | awk '$1 == "default" { print $2 }')"
       +awk -v gw="$gw" '
       +$1 == "PrivateKey" { key = $3 }
       +$1 == "Address" {
       +        addr = $3
       +        sub(/,.*/, "", addr)
       +}
       +$1 == "DNS" { dns = $3 }
       +$1 == "PublicKey" { peer = $3 }
       +$1 == "AllowedIPs" {
       +        aip = $3
       +        sub(/,.*/, "", aip)
       +}
       +$1 == "Endpoint" {
       +        endpoint = $3
       +        sub(/:/, " ", endpoint)
       +}
       +END {
       +        epip = substr(endpoint, 1, index(endpoint, " ")-1)
       +        ifip = substr(addr, 1, index(addr, "/")-1)
       +        printf("ifconfig wg0 create wgkey %s wgpeer %s wgendpoint %s wgaip %s\n", key, peer, endpoint, aip)
       +        printf("ifconfig wg0 %s\n", addr)
       +        printf("route nameserver wg0 %s\n", dns)
       +        printf("route add %s %s\n", epip, gw)
       +        printf("route change default %s\n", ifip)
       +        printf("curl https://am.i.mullvad.net/connected\n")
       +        printf("trap '\''ifconfig wg0 destroy; route delete %s; route add default %s'\'' EXIT\n", epip, gw)
       +        printf("while read -r ch; do [ \"$ch\" = q ] && break; done </dev/tty\n")
       +}' "$@" | doas /bin/sh -ex
       +
 (DIR) diff --git a/bin/music b/bin/music
       @@ -3,7 +3,7 @@
        DIRECTORY="$HOME/media/music_videos"
        
        directories=$(find "$DIRECTORY" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sort)
       -selected_directory=$(printf "%s\n" "$directories" | bemenu -l 10 -p 'music: ')
       +selected_directory=$(printf "%s\n" "$directories" | dmenu -l 10 -p 'music: ')
        if [ -n "$selected_directory" ]; then
            mpv --autofit=30% --really-quiet --no-terminal "$DIRECTORY/$selected_directory"
        fi
 (DIR) diff --git a/bin/pass b/bin/pass
       @@ -0,0 +1,279 @@
       +#!/bin/sh -e
       +#
       +# https://romanzolotarev.com/bin/pass
       +# copyright 2018 roman zolotarev <hi@romanzolotarev.com>
       +# copyright 2019-2022 romanzolotarev.com ou <hi@romanzolotarev.com>
       +#
       +# permission to use, copy, modify, and/or distribute this software for any
       +# purpose with or without fee is hereby granted, provided that the above
       +# copyright notice and this permission notice appear in all copies.
       +#
       +# the software is provided "as is" and the author disclaims all warranties
       +# with regard to this software including all implied warranties of
       +# merchantability and fitness. in no event shall the author be liable for
       +# any special, direct, indirect, or consequential damages or any damages
       +# whatsoever resulting from loss of use, data or profits, whether in an
       +# action of contract, negligence or other tortious action, arising out of
       +# or in connection with the use or performance of this software.
       +#
       +
       +fail() { echo "$1"; exit 1; }
       +should_exist() { if [ ! -f "$1" ]; then fail "Can't find $1."; fi; }
       +should_not_exist() { if [ -f "$1" ]; then fail "$1 already exists."; fi; }
       +should_be_dir() { if [ ! -d "$1" ]; then fail "$1 is not a directory."; fi; }
       +should_be_defined() { if [ ! "$1" ]; then fail "$2 should be defined."; fi; }
       +
       +
       +keygen() {
       +  private_key="$1"
       +  public_key="$2"
       +  should_be_defined "$private_key" "Private key path"
       +  should_be_defined "$public_key" "Public key path"
       +  should_not_exist "$private_key"
       +  should_be_dir "$(dirname "$private_key")"
       +  should_not_exist "$public_key"
       +  should_be_dir "$(dirname "$public_key")"
       +
       +  echo 'Generating public/private key pair.'
       +
       +  printf 'New pass phrase: '; stty -echo; read -r pass; stty echo; printf '\n'
       +  if [ ! "$pass" ]; then fail 'The pass phrase cannot be empty.'; fi
       +  printf 'Confirm: '; stty -echo; read -r pass_confirm; stty echo; printf '\n'
       +
       +  if [ "$pass" = "$pass_confirm" ]; then
       +    openssl genrsa 2048 |
       +      openssl pkcs8 -topk8 -inform pem -outform pem -out "$private_key" -v2 aes256 -passout "pass:$pass"
       +    chmod 0400 "$private_key"
       +    openssl rsa -in "$private_key" -out "$public_key" -outform pem -pubout -passin "pass:$pass"
       +    chmod 0600 "$public_key"
       +  else
       +    fail 'Pass phrase mismatch.'
       +  fi
       +}
       +
       +
       +passphrase() {
       +  private_key="$1"
       +  should_be_defined "$private_key" "Private key path"
       +  should_exist "$private_key"
       +
       +  echo "Changing $private_key pass phrase."
       +
       +  printf 'Current pass phrase: '; stty -echo; read -r pass; stty echo; printf '\n'
       +  printf 'New pass phrase: '; stty -echo; read -r new_pass; stty echo; printf '\n'
       +  if [ ! "$new_pass" ]; then fail 'The pass phrase cannot be empty.'; fi
       +  printf 'Confirm: '; stty -echo; read -r new_pass_confirm; stty echo; printf '\n'
       +
       +  if [ "$new_pass" = "$new_pass_confirm" ]; then
       +    chmod 0600 "$private_key" &&
       +    openssl rsa -aes256 -in "$private_key" -out "$private_key" -passin "pass:$pass" -passout "pass:$new_pass" 2>/dev/null ||
       +      fail 'Pass phrase change failed.' &&
       +      { echo 'Pass phrase changed.'; chmod 0400 "$private_key"; }
       +  else
       +    fail 'Pass phrase mismatch.'
       +  fi
       +}
       +
       +
       +encrypt() {
       +  public_key="$1"
       +  data_file="$2"
       +  should_be_defined "$data_file" "Data file path"
       +  enc_file="$data_file.enc"
       +  key_file="$data_file.key"
       +  base_dir="$(dirname "$data_file")"
       +  should_be_dir "$base_dir"
       +  should_exist "$public_key"
       +  should_not_exist "$enc_file"
       +  should_not_exist "$key_file"
       +
       +  key=$(openssl rand -base64 180)
       +  cleartext="$(cat)"
       +  dir=$(dirname "$data_file"); mkdir -p "$dir"; chmod 0700 "$dir"
       +
       +  echo "$key" |
       +    openssl rsautl -encrypt -pubin -inkey "$public_key" |
       +      openssl enc -md md5 -base64 -out "$key_file" >/dev/null 2>&1 ||
       +      fail 'Encryption failed.'
       +
       +  echo "$cleartext" |
       +    openssl enc -md md5 -aes-256-cbc -base64 -salt -k "$key" -out "$enc_file"
       +
       +  cleartext=''
       +  key=''
       +
       +  tar cf "$data_file" -C "$base_dir" "$(basename "$key_file")" "$(basename "$enc_file")"
       +  rm "$key_file" "$enc_file"
       +  chmod 0600 "$data_file"
       +}
       +
       +
       +sign() {
       +  private_key="$1"
       +  data_file="$2"
       +  pass="$3"
       +  should_be_defined "$data_file" "Data file path"
       +  signature="$data_file.sig"
       +  base_dir="$(dirname "$data_file")"
       +  should_be_dir "$base_dir"
       +  should_exist "$private_key"
       +  should_exist "$data_file"
       +
       +  if [ ! "$pass" ]; then
       +    if ! openssl dgst -sha256 -sign "$private_key" -out "$signature" "$data_file" 2>/dev/null; then
       +      rm "$signature"
       +      fail 'Signing failed.'
       +    fi
       +  else
       +    if ! openssl dgst -sha256 -passin "pass:$pass" -sign "$private_key" -out "$signature" "$data_file" 2>/dev/null; then
       +      rm "$signature"
       +      fail 'Signing failed.'
       +    fi
       +  fi
       +
       +  chmod 0600 "$signature"
       +}
       +
       +
       +decrypt() {
       +  private_key="$1"
       +  data_file="$2"
       +  pass="$3"
       +  should_be_defined "$private_key" "Private key path"
       +  should_be_defined "$data_file" "Data file path"
       +  enc_file="$data_file.enc"
       +  key_file="$data_file.key"
       +  should_exist "$private_key"
       +  should_exist "$data_file"
       +
       +  base_dir="$(dirname "$data_file")"
       +  tar xf "$data_file" -C "$base_dir"
       +  if [ ! "$pass" ]; then
       +    key=$(openssl enc -d -base64 -in "$key_file"|openssl rsautl -decrypt -inkey "$private_key" 2>/dev/null)
       +  else
       +    key=$(openssl enc -d -base64 -in "$key_file"|openssl rsautl -passin "pass:$pass" -decrypt -inkey "$private_key" 2>/dev/null)
       +  fi
       +  openssl enc -md md5 -aes-256-cbc -d -base64 -k "$key" -in "$enc_file" 2>/dev/null
       +  rm "$key_file" "$enc_file"
       +}
       +
       +verify () {
       +  public_key="$1"
       +  data_file="$2"
       +  signature="$data_file.sig"
       +  should_exist "$public_key"
       +  should_exist "$data_file"
       +  should_exist "$signature"
       +
       +  if ! openssl dgst -sha256 -verify "$public_key" -signature "$signature" "$data_file" >/dev/null 2>&1; then
       +    fail 'Invalid signature.'
       +  fi
       +}
       +
       +if [ ! "$PASS_BASE_DIR" ]; then PASS_BASE_DIR="$HOME/.pass"; fi
       +if [ ! "$PASS_PRIVATE_KEY" ]; then PASS_PRIVATE_KEY="$PASS_BASE_DIR/.key"; fi
       +if [ ! "$PASS_PUBLIC_KEY" ]; then PASS_PUBLIC_KEY="$PASS_BASE_DIR/.key.pub"; fi
       +if [ "$2" ]; then ID="$2"; fi
       +if [ "$3" ]; then PASS="$3"; fi
       +
       +
       +case "$1" in
       +
       +passphrase)
       +  passphrase "$PASS_PRIVATE_KEY"
       +  ;;
       +
       +
       +init)
       +  mkdir -p "$(dirname "$PASS_PRIVATE_KEY")"; chmod 0700 "$(dirname "$PASS_PRIVATE_KEY")"
       +  mkdir -p "$(dirname "$PASS_PUBLIC_KEY")"; chmod 0700 "$(dirname "$PASS_PUBLIC_KEY")"
       +  keygen "$PASS_PRIVATE_KEY" "$PASS_PUBLIC_KEY"
       +  ;;
       +
       +add)
       +  should_be_defined "$ID" "id"
       +  should_not_exist "$PASS_BASE_DIR/$ID"
       +  printf 'Pass phrase: '; stty -echo; read -r pass; stty echo; printf '\n'
       +  if [ ! "$pass" ]; then fail 'The pass phrase cannot be empty.'; fi
       +  openssl rand -base64 10 |
       +    openssl dgst -sha256 -passin "pass:$pass" -sign "$PASS_PRIVATE_KEY" >/dev/null 2>&1 ||
       +    fail 'Invalid pass phrase.'
       +  echo 'Press Enter and CTRL-D to complete.'
       +  encrypt "$PASS_PUBLIC_KEY" "$PASS_BASE_DIR/$ID"
       +  sign "$PASS_PRIVATE_KEY" "$PASS_BASE_DIR/$ID" "$pass"
       +  ;;
       +
       +import)
       +  should_be_defined "$ID" "id"
       +  should_not_exist "$PASS_BASE_DIR/$ID"
       +  encrypt "$PASS_PUBLIC_KEY" "$PASS_BASE_DIR/$ID"
       +  sign "$PASS_PRIVATE_KEY" "$PASS_BASE_DIR/$ID" "$PASS"
       +  ;;
       +
       +show)
       +  should_be_defined "$ID" "id"
       +  verify "$PASS_PUBLIC_KEY" "$PASS_BASE_DIR/$ID"
       +  cleartext="$(decrypt "$PASS_PRIVATE_KEY" "$PASS_BASE_DIR/$ID")"
       +  echo "$cleartext"|head -n1
       +  totp_seed="$(echo "$cleartext"|grep 'totp: '|head -n1|cut -d' ' -f2)"
       +  if [ "$totp_seed" ]; then
       +    if oathtool --version >/dev/null 2>&1; then
       +      oathtool --totp -b "$totp_seed"
       +    else
       +      echo 'oathtool(1) should be installed'
       +    fi
       +  fi
       +  ;;
       +
       +export)
       +  should_be_defined "$ID" "id"
       +  verify "$PASS_PUBLIC_KEY" "$PASS_BASE_DIR/$ID"
       +  decrypt "$PASS_PRIVATE_KEY" "$PASS_BASE_DIR/$ID" "$PASS"
       +  ;;
       +
       +ls)
       +  cd "$PASS_BASE_DIR"
       +  find . \( -type f \
       +    -name "${ID}"\* \
       +    \! -name \*.enc \
       +    \! -name \*.key \
       +    \! -name \*.sig \
       +    \! -name \.key \
       +    \! -name \.key.pub \
       +    \! -path \*/.git/\* \) | cut -f2 -d'/' | sort
       +  ;;
       +
       +edit)
       +  should_be_defined "$ID" "id"
       +  # verify "$PASS_PUBLIC_KEY" "$PASS_BASE_DIR/$ID"
       +  cleartext_file="$PASS_BASE_DIR/$ID.cleartext"
       +  cleartext=$(decrypt "$PASS_PRIVATE_KEY" "$PASS_BASE_DIR/$ID")
       +  touch "$cleartext_file"; chmod 0600 "$cleartext_file"
       +  echo "$cleartext" > "$cleartext_file"
       +  ${EDITOR:-$(which vi)} "$cleartext_file"
       +  after=$(cat "$cleartext_file")
       +  rm "$cleartext_file"
       +  if [ "$(echo "$cleartext"|openssl dgst -r -sha256)" = "$(echo "$after"|openssl dgst -r -sha256)" ]; then
       +    echo "No changes in $ID"
       +  else
       +    echo "$after"|encrypt "$PASS_PUBLIC_KEY" "$PASS_BASE_DIR/$ID"
       +    sign "$PASS_PRIVATE_KEY" "$PASS_BASE_DIR/$ID"
       +  fi
       +  ;;
       +
       +*)
       +  echo 'usage: export PASS_BASE_DIR=~/.pass'
       +  echo '       export PASS_PRIVATE_KEY=~/.pass/.key'
       +  echo '       export PASS_PUBLIC_KEY=~/.pass/.key.pub'
       +  echo
       +  echo '       pass init'
       +  echo '          | passphrase'
       +  echo '          | add        id'
       +  echo '          | import     id <pass>'
       +  echo '          | show       id'
       +  echo '          | export     id <pass>'
       +  echo '          | ls        <id>'
       +  exit 1
       +  ;;
       +
       +esac
 (DIR) diff --git a/bin/sway-start b/bin/sway-start
       @@ -1,22 +0,0 @@
       -#!/bin/sh
       -export TERM=foot
       -export _JAVA_AWT_WM_NONREPARENTING=1
       -export XKB_DEFAULT_OPTIONS=caps:escape
       -export GDK_BACKEND=wayland
       -export XDG_SESSION_TYPE=wayland
       -#export XCURSOR_THEME=Adwaita
       -export XDG_DESKTOP_DIR="$HOME"
       -export XDG_DOWNLOAD_DIR="$HOME/tmp"
       -export XDG_DOCUMENTS_DIR="$HOME/tmp"
       -export XDG_MUSIC_DIR="$HOME/tmp"
       -export XDG_PICTURES_DIR="$HOME/tmp"
       -export XDG_VIDEOS_DIR="$HOME/tmp"
       -export XDG_CURRENT_DESKTOP=sway
       -
       -if [ -z "$XDG_RUNTIME_DIR" ]; then
       -        mkdir -p /tmp/runtime/jay
       -        chmod 700 /tmp/runtime/jay
       -        export XDG_RUNTIME_DIR=/tmp/runtime/jay
       -fi
       -
       -exec dbus-run-session sway
 (DIR) diff --git a/bootstrap.sh b/bootstrap.sh
       @@ -2,9 +2,9 @@
        
        DOTFILES=$(pwd)
        
       -FILES='ashrc profile'
       +FILES='kshrc profile Xdefaults Xresources'
        ROOT='bin'
       -CONFIG='foot git lynx mutt newsraft nvim qutebrowser sway waybar'
       +CONFIG='git lynx mpd mutt ncmpcpp newsraft nvim'
        
        link() {
                for f in $FILES; do ln -sfn "$DOTFILES/$f" "$HOME/.$f"; done
 (DIR) diff --git a/foot/foot.ini b/foot/foot.ini
       @@ -1,27 +0,0 @@
       -font=Hack:size=14
       -
       -[url]
       -launch=link-handler ${url}
       -
       -[key-bindings]
       -show-urls-launch=Control+Shift+p
       -
       -[colors]
       -background=282828
       -foreground=ebdbb2
       -regular0=282828
       -regular1=cc241d
       -regular2=98971a
       -regular3=d79921
       -regular4=458588
       -regular5=b16286
       -regular6=689d6a
       -regular7=a89984
       -bright0=928374
       -bright1=fb4934
       -bright2=b8bb26
       -bright3=fabd2f
       -bright4=83a598
       -bright5=d3869b
       -bright6=8ec07c
       -bright7=ebdbb2
 (DIR) diff --git a/kshrc b/kshrc
       @@ -0,0 +1,63 @@
       +export XDG_CONFIG_HOME="$HOME/.config"
       +export XDG_CACHE_HOME="$HOME/.cache"
       +export XDG_DATA_HOME="$HOME/.local/share"
       +export XDG_STATE_HOME="$HOME/.local/state"
       +
       +# cleanup ~/
       +export CARGO_HOME="$XDG_DATA_HOME"/cargo
       +
       +# common exports
       +GPG_TTY=$(tty)
       +export GPG_TTY
       +export EDITOR="nvim"
       +export BROWSER="firefox"
       +export PATH=$PATH:$HOME/bin
       +
       +# tools
       +export OPENER=~/bin/link-handler
       +
       +# pass
       +export PASS_BASE_DIR=~/src/pass
       +export PASS_PRIVATE_KEY=~/src/pass/.key
       +export PASS_PUBLIC_KEY=~/src/pass/.key.pub
       +
       +# lynx
       +export LYNX_CFG=$HOME/.config/lynx/config
       +export LYNX_LSS=$HOME/.config/lynx/theme.lss
       +
       +# safety first kids!
       +alias cp='cp -i'
       +alias mv='mv -i'
       +alias rm='rm -i'
       +
       +# random alias
       +alias weather='curl wttr.in/?1QF'
       +
       +# git alias
       +alias ga='git add -A'
       +alias gs='git status -s'
       +alias gl="git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
       +alias gd='git diff'
       +alias gma='git commit -am'
       +
       +# neo
       +alias vim='nvim'
       +alias mutt='neomutt'
       +alias mpv="mpv --autofit=30% --really-quiet --no-terminal"
       +alias w="w3m -B"
       +
       +# vpn
       +alias von='mullvad ~/.config/mullvad/se-mma-wg-111.conf'
       +alias vcheck='curl https://am.i.mullvad.net/connected'
       +
       +# ksh
       +export LANG=en_US.UTF-8
       +export LC_CTYPE="en_US.UTF-8"
       +export LC_ALL=en_US.UTF-8
       +export PS1="\[\e[00;34m\]▶▶▶ \W \[\e[0m\]"
       +export HISTFILE=/home/jay/.cache/sh_history
       +export HISTSIZE=1000
       +
       +alias ls='colorls -G'
       +set -o emacs
       +
 (DIR) diff --git a/mpd/mpd.conf b/mpd/mpd.conf
       @@ -0,0 +1,20 @@
       +music_directory                "/home/jay/media/music"
       +playlist_directory         "/home/jay/.config/mpd/playlists"
       +db_file                 "/home/jay/.config/mpd/mpd.db"
       +log_file                   "syslog"
       +pid_file                 "/home/jay/.config/mpd/mpd.pid"
       +state_file                 "/home/jay/.config/mpd/mpdstate"
       +
       +audio_output {
       +        type "pulse"
       +        name "pulse audio"
       +}
       +audio_output {
       +    type                    "fifo"
       +    name                    "my_fifo"
       +    path                    "/tmp/mpd.fifo"
       +    format                  "44100:16:2"
       +}
       +
       +bind_to_address "127.0.0.1"
       +port "6600"
 (DIR) diff --git a/ncmpcpp/config b/ncmpcpp/config
       @@ -0,0 +1,31 @@
       +# visual stuff for 8
       +visualizer_data_source = /tmp/mpd.fifo
       +visualizer_output_name = my_fifo
       +visualizer_in_stereo = no
       +#visualizer_type = spectrum
       +visualizer_look = ∙▋
       +visualizer_color = 7,5,8,3
       +song_columns_list_format = "(50)[green]{a} (50)[white]{t|f}"
       +
       +playlist_display_mode = columns
       +browser_display_mode = columns
       +
       +ncmpcpp_directory = ~/.config/ncmpcpp
       +lyrics_directory = /tmp
       +store_lyrics_in_song_dir = yes
       +autocenter_mode = "yes"
       +centered_cursor = "yes"
       +cyclic_scrolling = "no"
       +
       +titles_visibility = "no"
       +header_visibility = "no"
       +statusbar_visibility = "no"
       +progressbar_look = "❙❙❙"
       +progressbar_color = "white"
       +
       +user_interface = "classic"
       +
       +startup_screen = playlist
       +#startup_slave_screen = visualizer
       +'startup_slave_screen_focus = no
       +locked_screen_width_part = 35
 (DIR) diff --git a/profile b/profile
       @@ -1,2 +1,2 @@
       -export ENV=$HOME/.ashrc
       +export ENV=$HOME/.kshrc
        . $ENV
 (DIR) diff --git a/qutebrowser/blank.html b/qutebrowser/blank.html
       @@ -1,44 +0,0 @@
       -<!DOCTYPE html>
       -<html lang="en">
       -
       -  <head>
       -    <style>
       -        body {
       -          color: #cfba58;
       -          background-color: #191919;
       -          font-family: monospace;
       -        }
       -
       -        .flex {
       -          flex-direction: column;
       -          display: flex;
       -          justify-content: center;
       -          align-items: center;
       -          margin-top: 450px;
       -        }
       -
       -        input {
       -          border: none;
       -          border-bottom: 2px solid #959A1C;
       -          min-width: 500px;
       -          max-width: 750px;
       -          width: 75%;
       -          padding-bottom: 10px;
       -          background-color: transparent;
       -          color: #fff;
       -          outline: 0;
       -          margin-bottom: 20px;
       -          font-size: 22px;
       -        }
       -    </style>
       -  </head>
       -
       -  <body>
       -    <div class="flex">
       -      <form action="https://html.duckduckgo.com/html" method="get" target="_self">
       -        <input type="text" name="q" autofocus="autofocus" onfocus="this.select()" />
       -      </form>
       -    </div>
       -  </body>
       -
       -</html>
 (DIR) diff --git a/qutebrowser/config.py b/qutebrowser/config.py
       @@ -1,92 +0,0 @@
       -config.load_autoconfig(False)
       -
       -try:
       -    from qutebrowser.api import message
       -
       -    # gruvbox colour theme
       -    config.source('scripts/gruvbox.py')
       -    #config.source('scripts/redirects.py')
       -
       -except ImportError:
       -    pass
       -
       -# default local page
       -DEFAULT_PAGE = str(config.configdir / 'blank.html')
       -
       -# keybinds remapping
       -config.bind("xx", "set tabs.show always;; later 5000 set tabs.show switching")
       -config.bind("xc", "spawn --userscript password_fill")
       -config.bind("zd", "download-open")
       -config.bind("xz", "hint links spawn --detach ~/bin/link-handler {hint-url}")
       -config.bind("j", "cmd-run-with-count 5 scroll down")
       -config.bind("k", "cmd-run-with-count 5 scroll up")
       -
       -# tabbar
       -c.tabs.position = "top"
       -c.tabs.show = "multiple"
       -c.tabs.title.format = ""
       -c.tabs.width = 28
       -c.tabs.favicons.show = "never"
       -
       -# hints
       -c.colors.hints.bg = "rgb(207,186,88)" #cfba58
       -c.colors.hints.fg = "rgb(34, 34, 34)" #222222
       -c.colors.webpage.darkmode.enabled = False
       -c.colors.webpage.darkmode.algorithm = "lightness-hsl"
       -
       -# misc
       -c.fonts.hints = "10pt Hack"
       -c.fonts.default_size = '12pt'
       -c.fonts.default_family = 'Hack'
       -c.hints.uppercase = True
       -c.scrolling.smooth = True
       -c.editor.command = ["alacritty", "vim '{}'"]
       -c.auto_save.session = True
       -
       -# ad-block
       -c.content.blocking.enabled = True
       -c.content.blocking.method = "both"
       -c.content.blocking.adblock.lists = [
       -        "https://easylist.to/easylist/easyprivacy.txt",
       -        "https://secure.fanboy.co.nz/fanboy-cookiemonster.txt",
       -        "https://easylist.to/easylist/easylist.txt"
       -        ]
       -
       -# general privacy
       -c.completion.web_history.max_items = 0 # no history
       -c.downloads.remove_finished = 800 # clear dl history
       -c.downloads.location.directory = '~/tmp'
       -c.url.default_page = DEFAULT_PAGE
       -c.url.start_pages = DEFAULT_PAGE
       -c.content.private_browsing = True # always use private browsing
       -c.content.register_protocol_handler = False
       -c.content.webgl = False
       -
       -# normally default, lets make sure
       -c.content.media.audio_capture = False
       -c.content.media.audio_video_capture = False
       -c.content.media.video_capture = False
       -c.content.desktop_capture = False
       -c.content.mouse_lock = False
       -c.content.autoplay = False # no autoplay on <video> tags
       -
       -# fingerprint
       -c.content.headers.accept_language = "en-US,en;q=0.5"
       -c.content.headers.user_agent = "Mozilla/5.0 (X11; Linux i686; rv:109.0) Gecko/20100101 Firefox/120.0"
       -c.content.headers.custom = {"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"}
       -c.content.headers.referer = "same-domain"
       -c.content.cookies.accept = "no-3rdparty"
       -c.content.javascript.enabled = False # disable tracking etc
       -c.content.canvas_reading = False # canvas blocking
       -c.content.geolocation = False # location ident
       -c.content.webrtc_ip_handling_policy = "disable-non-proxied-udp"
       -c.content.hyperlink_auditing = False # disable pingbacks
       -c.content.dns_prefetch = False # disable pre-fetching
       -
       -# search engine shortneners
       -c.url.searchengines = {
       -    "DEFAULT": "https://html.duckduckgo.com/html?q={}",
       -    "ru": "https://rutracker.org/forum/tracker.php?f=1992&nm={}",
       -    "wiby": "https://wiby.me/?q={}",
       -    "book": "http://libgen.rs/search.php?req={}&lg_topic=libgen&open=0&view=simple&res=25&phrase=1&column=def",
       -}
 (DIR) diff --git a/qutebrowser/scripts/fingerprint.py b/qutebrowser/scripts/fingerprint.py
       @@ -1,43 +0,0 @@
       -import random
       -import json
       -import datetime
       -
       -from pathlib import Path
       -from qutebrowser.api import message, interceptor
       -
       -home = str(config.configdir)
       -agentfile = Path("{}/useragent_list.json".format(home))
       -
       -fp_timer = datetime.datetime.now() + datetime.timedelta(minutes=1)
       -
       -if agentfile.is_file():
       -    with open(agentfile, "r") as filehandle:
       -        agentList = json.load(filehandle)
       -
       -
       -def fingerprint_getheader(agent):
       -
       -    FP_HTTP_HEADER = {
       -        "Firefox": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
       -        "Chrome": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
       -        "Edge": "text/html, application/xhtml+xml, image/jxr, */*",
       -        "Opera": "text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1",
       -        "Safari": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
       -    }
       -
       -    for a, h in FP_HTTP_HEADER.items():
       -        if "{a}" in agent:
       -            return h
       -
       -
       -def fingerprint(info: interceptor.Request):
       -    global fp_timer
       -
       -    if fp_timer < datetime.datetime.now():
       -        fp_timer = datetime.datetime.now() + datetime.timedelta(minutes=1)
       -        agent = random.choice(tuple(agentList))
       -        c.content.headers.user_agent = agent
       -        c.content.headers.custom = {"accept": fingerprint_getheader(agent)}
       -
       -
       -interceptor.register(fingerprint)
 (DIR) diff --git a/qutebrowser/scripts/gruvbox.py b/qutebrowser/scripts/gruvbox.py
       @@ -1,332 +0,0 @@
       -# gruvbox dark hard qutebrowser theme by Florian Bruhin <me@the-compiler.org>
       -#
       -# Originally based on:
       -#   base16-qutebrowser (https://github.com/theova/base16-qutebrowser)
       -#   Base16 qutebrowser template by theova and Daniel Mulford
       -#   Gruvbox dark, hard scheme by Dawid Kurek (dawikur@gmail.com), morhetz (https://github.com/morhetz/gruvbox)
       -
       -bg0_hard = "#1d2021"
       -bg0_soft = '#32302f'
       -bg0_normal = '#282828'
       -
       -bg0 = bg0_normal
       -bg1 = "#3c3836"
       -bg2 = "#504945"
       -bg3 = "#665c54"
       -bg4 = "#7c6f64"
       -
       -fg0 = "#fbf1c7"
       -fg1 = "#ebdbb2"
       -fg2 = "#d5c4a1"
       -fg3 = "#bdae93"
       -fg4 = "#a89984"
       -
       -bright_red = "#fb4934"
       -bright_green = "#b8bb26"
       -bright_yellow = "#fabd2f"
       -bright_blue = "#83a598"
       -bright_purple = "#d3869b"
       -bright_aqua = "#8ec07c"
       -bright_gray = "#928374"
       -bright_orange = "#fe8019"
       -
       -dark_red = "#cc241d"
       -dark_green = "#98971a"
       -dark_yellow = "#d79921"
       -dark_blue = "#458588"
       -dark_purple = "#b16286"
       -dark_aqua = "#689d6a"
       -dark_gray = "#a89984"
       -dark_orange = "#d65d0e"
       -
       -### Completion
       -
       -# Text color of the completion widget. May be a single color to use for
       -# all columns or a list of three colors, one for each column.
       -c.colors.completion.fg = [fg1, bright_aqua, bright_yellow]
       -
       -# Background color of the completion widget for odd rows.
       -c.colors.completion.odd.bg = bg0
       -
       -# Background color of the completion widget for even rows.
       -c.colors.completion.even.bg = c.colors.completion.odd.bg
       -
       -# Foreground color of completion widget category headers.
       -c.colors.completion.category.fg = bright_blue
       -
       -# Background color of the completion widget category headers.
       -c.colors.completion.category.bg = bg1
       -
       -# Top border color of the completion widget category headers.
       -c.colors.completion.category.border.top = c.colors.completion.category.bg
       -
       -# Bottom border color of the completion widget category headers.
       -c.colors.completion.category.border.bottom = c.colors.completion.category.bg
       -
       -# Foreground color of the selected completion item.
       -c.colors.completion.item.selected.fg = fg0
       -
       -# Background color of the selected completion item.
       -c.colors.completion.item.selected.bg = bg4
       -
       -# Top border color of the selected completion item.
       -c.colors.completion.item.selected.border.top = bg2
       -
       -# Bottom border color of the selected completion item.
       -c.colors.completion.item.selected.border.bottom = c.colors.completion.item.selected.border.top
       -
       -# Foreground color of the matched text in the selected completion item.
       -c.colors.completion.item.selected.match.fg = bright_orange
       -
       -# Foreground color of the matched text in the completion.
       -c.colors.completion.match.fg = c.colors.completion.item.selected.match.fg
       -
       -# Color of the scrollbar handle in the completion view.
       -c.colors.completion.scrollbar.fg = c.colors.completion.item.selected.fg
       -
       -# Color of the scrollbar in the completion view.
       -c.colors.completion.scrollbar.bg = c.colors.completion.category.bg
       -
       -### Context menu
       -
       -# Background color of disabled items in the context menu.
       -c.colors.contextmenu.disabled.bg = bg3
       -
       -# Foreground color of disabled items in the context menu.
       -c.colors.contextmenu.disabled.fg = fg3
       -
       -# Background color of the context menu. If set to null, the Qt default is used.
       -c.colors.contextmenu.menu.bg = bg0
       -
       -# Foreground color of the context menu. If set to null, the Qt default is used.
       -c.colors.contextmenu.menu.fg =  fg2
       -
       -# Background color of the context menu’s selected item. If set to null, the Qt default is used.
       -c.colors.contextmenu.selected.bg = bg2
       -
       -#Foreground color of the context menu’s selected item. If set to null, the Qt default is used.
       -c.colors.contextmenu.selected.fg = c.colors.contextmenu.menu.fg
       -
       -### Downloads
       -
       -# Background color for the download bar.
       -c.colors.downloads.bar.bg = bg0
       -
       -# Color gradient start for download text.
       -c.colors.downloads.start.fg = bg0
       -
       -# Color gradient start for download backgrounds.
       -c.colors.downloads.start.bg = bright_blue
       -
       -# Color gradient end for download text.
       -c.colors.downloads.stop.fg = c.colors.downloads.start.fg
       -
       -# Color gradient stop for download backgrounds.
       -c.colors.downloads.stop.bg = bright_aqua
       -
       -# Foreground color for downloads with errors.
       -c.colors.downloads.error.fg = bright_red
       -
       -### Hints
       -
       -# Font color for hints.
       -c.colors.hints.fg = bg0
       -
       -# Background color for hints.
       -c.colors.hints.bg = 'rgba(250, 191, 47, 200)'  # bright_yellow
       -
       -# Font color for the matched part of hints.
       -c.colors.hints.match.fg = bg4
       -
       -### Keyhint widget
       -
       -# Text color for the keyhint widget.
       -c.colors.keyhint.fg = fg4
       -
       -# Highlight color for keys to complete the current keychain.
       -c.colors.keyhint.suffix.fg = fg0
       -
       -# Background color of the keyhint widget.
       -c.colors.keyhint.bg = bg0
       -
       -### Messages
       -
       -# Foreground color of an error message.
       -c.colors.messages.error.fg = bg0
       -
       -# Background color of an error message.
       -c.colors.messages.error.bg = bright_red
       -
       -# Border color of an error message.
       -c.colors.messages.error.border = c.colors.messages.error.bg
       -
       -# Foreground color of a warning message.
       -c.colors.messages.warning.fg = bg0
       -
       -# Background color of a warning message.
       -c.colors.messages.warning.bg = bright_purple
       -
       -# Border color of a warning message.
       -c.colors.messages.warning.border = c.colors.messages.warning.bg
       -
       -# Foreground color of an info message.
       -c.colors.messages.info.fg = fg2
       -
       -# Background color of an info message.
       -c.colors.messages.info.bg = bg0
       -
       -# Border color of an info message.
       -c.colors.messages.info.border = c.colors.messages.info.bg
       -
       -### Prompts
       -
       -# Foreground color for prompts.
       -c.colors.prompts.fg = fg2
       -
       -# Border used around UI elements in prompts.
       -c.colors.prompts.border = f'1px solid {bg1}'
       -
       -# Background color for prompts.
       -c.colors.prompts.bg = bg3
       -
       -# Background color for the selected item in filename prompts.
       -c.colors.prompts.selected.bg = bg2
       -
       -### Statusbar
       -
       -# Foreground color of the statusbar.
       -c.colors.statusbar.normal.fg = fg2
       -
       -# Background color of the statusbar.
       -c.colors.statusbar.normal.bg = bg0
       -
       -# Foreground color of the statusbar in insert mode.
       -c.colors.statusbar.insert.fg = bg0
       -
       -# Background color of the statusbar in insert mode.
       -c.colors.statusbar.insert.bg = dark_aqua
       -
       -# Foreground color of the statusbar in passthrough mode.
       -c.colors.statusbar.passthrough.fg = bg0
       -
       -# Background color of the statusbar in passthrough mode.
       -c.colors.statusbar.passthrough.bg = dark_blue
       -
       -# Foreground color of the statusbar in private browsing mode.
       -c.colors.statusbar.private.fg = bright_purple
       -
       -# Background color of the statusbar in private browsing mode.
       -c.colors.statusbar.private.bg = bg0
       -
       -# Foreground color of the statusbar in command mode.
       -c.colors.statusbar.command.fg = fg3
       -
       -# Background color of the statusbar in command mode.
       -c.colors.statusbar.command.bg = bg1
       -
       -# Foreground color of the statusbar in private browsing + command mode.
       -c.colors.statusbar.command.private.fg = c.colors.statusbar.private.fg
       -
       -# Background color of the statusbar in private browsing + command mode.
       -c.colors.statusbar.command.private.bg = c.colors.statusbar.command.bg
       -
       -# Foreground color of the statusbar in caret mode.
       -c.colors.statusbar.caret.fg = bg0
       -
       -# Background color of the statusbar in caret mode.
       -c.colors.statusbar.caret.bg = dark_purple
       -
       -# Foreground color of the statusbar in caret mode with a selection.
       -c.colors.statusbar.caret.selection.fg = c.colors.statusbar.caret.fg
       -
       -# Background color of the statusbar in caret mode with a selection.
       -c.colors.statusbar.caret.selection.bg = bright_purple
       -
       -# Background color of the progress bar.
       -c.colors.statusbar.progress.bg = bright_blue
       -
       -# Default foreground color of the URL in the statusbar.
       -c.colors.statusbar.url.fg = fg4
       -
       -# Foreground color of the URL in the statusbar on error.
       -c.colors.statusbar.url.error.fg = dark_red
       -
       -# Foreground color of the URL in the statusbar for hovered links.
       -c.colors.statusbar.url.hover.fg = bright_orange
       -
       -# Foreground color of the URL in the statusbar on successful load
       -# (http).
       -c.colors.statusbar.url.success.http.fg = bright_red
       -
       -# Foreground color of the URL in the statusbar on successful load
       -# (https).
       -c.colors.statusbar.url.success.https.fg = fg0
       -
       -# Foreground color of the URL in the statusbar when there's a warning.
       -c.colors.statusbar.url.warn.fg = bright_purple
       -
       -### tabs
       -
       -# Background color of the tab bar.
       -c.colors.tabs.bar.bg = bg0
       -
       -# Color gradient start for the tab indicator.
       -c.colors.tabs.indicator.start = bright_blue
       -
       -# Color gradient end for the tab indicator.
       -c.colors.tabs.indicator.stop = bright_aqua
       -
       -# Color for the tab indicator on errors.
       -c.colors.tabs.indicator.error = bright_red
       -
       -# Foreground color of unselected odd tabs.
       -c.colors.tabs.odd.fg = fg2
       -
       -# Background color of unselected odd tabs.
       -c.colors.tabs.odd.bg = bg2
       -
       -# Foreground color of unselected even tabs.
       -c.colors.tabs.even.fg = c.colors.tabs.odd.fg
       -
       -# Background color of unselected even tabs.
       -c.colors.tabs.even.bg = bg3
       -
       -# Foreground color of selected odd tabs.
       -c.colors.tabs.selected.odd.fg = fg2
       -
       -# Background color of selected odd tabs.
       -c.colors.tabs.selected.odd.bg = bg0
       -
       -# Foreground color of selected even tabs.
       -c.colors.tabs.selected.even.fg = c.colors.tabs.selected.odd.fg
       -
       -# Background color of selected even tabs.
       -c.colors.tabs.selected.even.bg = bg0
       -
       -# Background color of pinned unselected even tabs.
       -c.colors.tabs.pinned.even.bg = bright_green
       -
       -# Foreground color of pinned unselected even tabs.
       -c.colors.tabs.pinned.even.fg = bg2
       -
       -# Background color of pinned unselected odd tabs.
       -c.colors.tabs.pinned.odd.bg = bright_green
       -
       -# Foreground color of pinned unselected odd tabs.
       -c.colors.tabs.pinned.odd.fg = c.colors.tabs.pinned.even.fg
       -
       -# Background color of pinned selected even tabs.
       -c.colors.tabs.pinned.selected.even.bg = bg0
       -
       -# Foreground color of pinned selected even tabs.
       -c.colors.tabs.pinned.selected.even.fg = c.colors.tabs.selected.odd.fg
       -
       -# Background color of pinned selected odd tabs.
       -c.colors.tabs.pinned.selected.odd.bg = c.colors.tabs.pinned.selected.even.bg
       -
       -# Foreground color of pinned selected odd tabs.
       -c.colors.tabs.pinned.selected.odd.fg = c.colors.tabs.selected.odd.fg
       -
       -# Background color for webpages if unset (or empty to use the theme's
       -# color).
       -# c.colors.webpage.bg = bg4
 (DIR) diff --git a/qutebrowser/scripts/redirects.py b/qutebrowser/scripts/redirects.py
       @@ -1,70 +0,0 @@
       -from qutebrowser.api import interceptor
       -from urllib.parse import urljoin
       -from PyQt6.QtCore import QUrl
       -import operator
       -
       -o = operator.methodcaller
       -s = 'setHost'
       -i = interceptor
       -
       -def farside(url: QUrl, i) -> bool:
       -    url.setHost('farside.link')
       -    p = url.path().strip('/')
       -    url.setPath(urljoin(i, p))
       -    return True
       -
       -def nitter(url: QUrl) -> bool:
       -    return farside(url, '/nitter/')
       -def rimgo(url: QUrl) -> bool:
       -    return farside(url, '/rimgo/')
       -def scribe(url: QUrl) -> bool:
       -    return farside(url, '/scribe/')
       -def wikiless(url: QUrl) -> bool:
       -    return farside(url, '/wikiless/')
       -def invid(url: QUrl) -> bool:
       -    return farside(url, '/invidious/')
       -def reddit(url: QUrl) -> bool:
       -    return farside(url, '/libreddit/')
       -def bibliogram(url: QUrl) -> bool:
       -    return farside(url, '/bibliogram/')
       -def simplytranslate(url: QUrl) -> bool:
       -    return farside(url, '/simplytranslate/')
       -def proxitok(url: QUrl) -> bool:
       -    return farside(url, '/proxitok/')
       -def querte (url: QUrl) -> bool:
       -    return farside(url, '/querte/')
       -
       -map = {
       -        "reddit.com": reddit,
       -        "www.reddit.com": reddit,
       -        "old.reddit.com": reddit,
       -
       -        "youtu.be": invid,
       -        "youtube.com": invid,
       -        "www.youtube.com": invid,
       -
       -        "twitter.com": nitter,
       -        "mobile.twitter.com": nitter,
       -
       -        "imgur.com" : rimgo,
       -        "medium.com" : scribe,
       -        "en.wikipedia.org" : wikiless,
       -        "www.instagram.com": bibliogram,
       -        "translate.google.com" : simplytranslate,
       -        "vm.tiktok.com" : proxitok,
       -        "www.tiktok.com" : proxitok,
       -        "www.quora.com": querte,
       -
       -        "www.twitch.tv" : o(s, 'm.twitch.tv'),
       -        "tumblr.com" : o(s, 'splashblr.fly.dev'),
       -        "www.npr.org" : o(s, 'text.npr.org'),
       -        }
       -def f(info: i.Request):
       -    if (info.resource_type != i.ResourceType.main_frame or
       -            info.request_url.scheme() in {"data", "blob"}):
       -        return
       -    url = info.request_url
       -    redir = map.get(url.host())
       -    if redir is not None and redir(url) is not False:
       -        info.redirect(url)
       -i.register(f)
 (DIR) diff --git a/qutebrowser/scripts/user_agent.py b/qutebrowser/scripts/user_agent.py
       @@ -1,31 +0,0 @@
       -# qutebrowser script to set a random user-agent on launch. Add the following to
       -# your qutebrowser config.py file:
       -#
       -#        config.source('scripts/user_agent.py')
       -#
       -# You can download the most common user-agents with a script like this, I run
       -# mine on cron every 3 days. :
       -#
       -# #!/bin/bash
       -#
       -# url='https://raw.githubusercontent.com/Kikobeats/top-user-agents/master/index.json'
       -# path="$HOME/.config/qutebrowser/useragent_list.json"
       -#
       -# curl "$url" -o "$path"
       -# awk '!/Firefox/' "$path" > /tmp/1 && mv /tmp/1 "$path"
       -
       -import random
       -import json
       -
       -from pathlib import Path
       -from qutebrowser.api import message
       -
       -home = str(config.configdir)
       -agentfile = Path("{}/useragent_list.json".format(home))
       -
       -if agentfile.is_file():
       -    with open(agentfile, "r") as filehandle:
       -        agentList = json.load(filehandle)
       -
       -    agent = random.choice(tuple(agentList))
       -    c.content.headers.user_agent = agent
 (DIR) diff --git a/suckless/dmenu/Makefile b/suckless/dmenu/Makefile
       @@ -0,0 +1,39 @@
       +REPOSITORY = http://git.suckless.org/dmenu
       +SRC_DIR = src
       +PINNED_REVISION = HEAD
       +PATCH_DIR = patches
       +
       +all: $(SRC_DIR)
       +
       +clean: reset
       +        @if test -d $(SRC_DIR); then \
       +                $(MAKE) -C "${SRC_DIR}" -s clean; \
       +                git -C "${SRC_DIR}" clean -f; \
       +        fi
       +
       +$(SRC_DIR): clone reset patch
       +        @cp config.h $@
       +        $(MAKE) -C "${SRC_DIR}" -s
       +
       +patch: $(PATCH_DIR)/*
       +        @for file in $^ ; do \
       +                patch -d "${SRC_DIR}" < $${file}; \
       +        done
       +reset:
       +        @if [ -n "$(strip $(PINNED_REVISION))" ]; then \
       +                git -C "${SRC_DIR}" reset --hard $(PINNED_REVISION); \
       +        fi
       +
       +clone:
       +        @if ! test -d $(SRC_DIR); then \
       +                git clone $(REPOSITORY) $(SRC_DIR); \
       +        fi
       +
       +update: clean
       +        @git -C "${SRC_DIR}" pull
       +
       +install:
       +        $(MAKE) -C "${SRC_DIR}" -s install
       +
       +
       +.PHONY: all clean update install reset clone
 (DIR) diff --git a/suckless/dmenu/config.h b/suckless/dmenu/config.h
       @@ -0,0 +1,16 @@
       +static int topbar = 1;
       +static const char *fonts[] = {
       +        "Hack:pixelsize=14"
       +};
       +static int centered = 1;
       +static const char *prompt      = "run »";
       +static const char *colors[SchemeLast][2] = {
       +        [SchemeNorm] = { "#ebdbb2", "#282828" },
       +        [SchemeSel] = { "#ebdbb2", "#98971a" },
       +        [SchemeOut] = { "#ebdbb2", "#8ec07c" },
       +};
       +
       +static unsigned int lines = 0;
       +static const char worddelimiters[] = " ";
       +static int min_width = 800;
       +static unsigned int border_width = 3;
 (DIR) diff --git a/suckless/dmenu/patches/01-dmenu-border-4.9.diff b/suckless/dmenu/patches/01-dmenu-border-4.9.diff
       @@ -0,0 +1,36 @@
       +diff --git a/config.def.h b/config.def.h
       +index 1edb647..dd3eb31 100644
       +--- a/config.def.h
       ++++ b/config.def.h
       +@@ -21,3 +21,6 @@ static unsigned int lines      = 0;
       +  * for example: " /?\"&[]"
       +  */
       + static const char worddelimiters[] = " ";
       ++
       ++/* Size of the window border */
       ++static unsigned int border_width = 0;
       +diff --git a/dmenu.c b/dmenu.c
       +index 27b7a30..7c130fc 100644
       +--- a/dmenu.c
       ++++ b/dmenu.c
       +@@ -684,9 +684,11 @@ setup(void)
       +         swa.override_redirect = True;
       +         swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
       +         swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
       +-        win = XCreateWindow(dpy, root, x, y, mw, mh, 0,
       ++        win = XCreateWindow(dpy, root, x, y, mw, mh, border_width,
       +                             CopyFromParent, CopyFromParent, CopyFromParent,
       +                             CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
       ++        if (border_width)
       ++                XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel);
       +         XSetClassHint(dpy, win, &ch);
       +
       +
       +@@ -757,6 +759,8 @@ main(int argc, char *argv[])
       +                         colors[SchemeSel][ColFg] = argv[++i];
       +                 else if (!strcmp(argv[i], "-w"))   /* embedding window id */
       +                         embed = argv[++i];
       ++                else if (!strcmp(argv[i], "-bw"))
       ++                        border_width = atoi(argv[++i]); /* border width */
       +                 else
       +                         usage();
 (DIR) diff --git a/suckless/dmenu/patches/02-dmenu-center-20200111-8cd37e1.diff b/suckless/dmenu/patches/02-dmenu-center-20200111-8cd37e1.diff
       @@ -0,0 +1,120 @@
       +From 8cd37e1ab9e7cb025224aeb3543f1a5be8bceb93 Mon Sep 17 00:00:00 2001
       +From: Nihal Jere <nihal@nihaljere.xyz>
       +Date: Sat, 11 Jan 2020 21:16:08 -0600
       +Subject: [PATCH] center patch now has adjustable minimum width
       +
       +---
       + config.def.h |  2 ++
       + dmenu.1      |  3 +++
       + dmenu.c      | 39 ++++++++++++++++++++++++++++++++-------
       + 3 files changed, 37 insertions(+), 7 deletions(-)
       +
       +diff --git a/config.def.h b/config.def.h
       +index 1edb647..88ef264 100644
       +--- a/config.def.h
       ++++ b/config.def.h
       +@@ -2,6 +2,8 @@
       + /* Default settings; can be overriden by command line. */
       + 
       + static int topbar = 1;                      /* -b  option; if 0, dmenu appears at bottom     */
       ++static int centered = 0;                    /* -c option; centers dmenu on screen */
       ++static int min_width = 500;                    /* minimum width when centered */
       + /* -fn option overrides fonts[0]; default X11 font or font set */
       + static const char *fonts[] = {
       +         "monospace:size=10"
       +diff --git a/dmenu.1 b/dmenu.1
       +index 323f93c..c036baa 100644
       +--- a/dmenu.1
       ++++ b/dmenu.1
       +@@ -40,6 +40,9 @@ which lists programs in the user's $PATH and runs the result in their $SHELL.
       + .B \-b
       + dmenu appears at the bottom of the screen.
       + .TP
       ++.B \-c
       ++dmenu appears centered on the screen.
       ++.TP
       + .B \-f
       + dmenu grabs the keyboard before reading stdin if not reading from a tty. This
       + is faster, but will lock up X until stdin reaches end\-of\-file.
       +diff --git a/dmenu.c b/dmenu.c
       +index 65f25ce..041c7f8 100644
       +--- a/dmenu.c
       ++++ b/dmenu.c
       +@@ -89,6 +89,15 @@ calcoffsets(void)
       +                         break;
       + }
       + 
       ++static int
       ++max_textw(void)
       ++{
       ++        int len = 0;
       ++        for (struct item *item = items; item && item->text; item++)
       ++                len = MAX(TEXTW(item->text), len);
       ++        return len;
       ++}
       ++
       + static void
       + cleanup(void)
       + {
       +@@ -611,6 +620,7 @@ setup(void)
       +         bh = drw->fonts->h + 2;
       +         lines = MAX(lines, 0);
       +         mh = (lines + 1) * bh;
       ++        promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
       + #ifdef XINERAMA
       +         i = 0;
       +         if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
       +@@ -637,9 +647,16 @@ setup(void)
       +                                 if (INTERSECT(x, y, 1, 1, info[i]))
       +                                         break;
       + 
       +-                x = info[i].x_org;
       +-                y = info[i].y_org + (topbar ? 0 : info[i].height - mh);
       +-                mw = info[i].width;
       ++                if (centered) {
       ++                        mw = MIN(MAX(max_textw() + promptw, min_width), info[i].width);
       ++                        x = info[i].x_org + ((info[i].width  - mw) / 2);
       ++                        y = info[i].y_org + ((info[i].height - mh) / 2);
       ++                } else {
       ++                        x = info[i].x_org;
       ++                        y = info[i].y_org + (topbar ? 0 : info[i].height - mh);
       ++                        mw = info[i].width;
       ++                }
       ++
       +                 XFree(info);
       +         } else
       + #endif
       +@@ -647,11 +664,17 @@ setup(void)
       +                 if (!XGetWindowAttributes(dpy, parentwin, &wa))
       +                         die("could not get embedding window attributes: 0x%lx",
       +                             parentwin);
       +-                x = 0;
       +-                y = topbar ? 0 : wa.height - mh;
       +-                mw = wa.width;
       ++
       ++                if (centered) {
       ++                        mw = MIN(MAX(max_textw() + promptw, min_width), wa.width);
       ++                        x = (wa.width  - mw) / 2;
       ++                        y = (wa.height - mh) / 2;
       ++                } else {
       ++                        x = 0;
       ++                        y = topbar ? 0 : wa.height - mh;
       ++                        mw = wa.width;
       ++                }
       +         }
       +-        promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
       +         inputw = MIN(inputw, mw/3);
       +         match();
       + 
       +@@ -709,6 +732,8 @@ main(int argc, char *argv[])
       +                         topbar = 0;
       +                 else if (!strcmp(argv[i], "-f"))   /* grabs keyboard before reading stdin */
       +                         fast = 1;
       ++                else if (!strcmp(argv[i], "-c"))   /* centers dmenu on screen */
       ++                        centered = 1;
       +                 else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
       +                         fstrncmp = strncasecmp;
       +                         fstrstr = cistrstr;
       +-- 
       +2.24.1
       +
 (DIR) diff --git a/suckless/dwm/Makefile b/suckless/dwm/Makefile
       @@ -0,0 +1,41 @@
       +REPOSITORY = http://git.suckless.org/dwm
       +SRC_DIR = src
       +PINNED_REVISION = HEAD
       +PATCH_DIR = patches
       +
       +all: $(SRC_DIR)
       +
       +clean: reset
       +        @if test -d $(SRC_DIR); then \
       +                cd $(SRC_DIR); \
       +                $(MAKE) -s clean; \
       +                git clean -f; \
       +        fi
       +
       +$(SRC_DIR): clone reset patch
       +        @cp config.h $@
       +        @cd $@ && $(MAKE) -s
       +
       +reset:
       +        @if [ -n "$(strip $(PINNED_REVISION))" ]; then \
       +                cd $(SRC_DIR) && git reset --hard $(PINNED_REVISION); \
       +        fi
       +
       +patch: $(PATCH_DIR)/*
       +        @for file in $^ ; do \
       +                patch -d "${SRC_DIR}" < $${file}; \
       +        done
       +
       +clone:
       +        @if ! test -d $(SRC_DIR); then \
       +                git clone $(REPOSITORY) $(SRC_DIR); \
       +        fi
       +
       +update: clean
       +        @cd $(SRC_DIR) && git pull
       +
       +install:
       +        $(MAKE) -C "${SRC_DIR}" -s install
       +
       +
       +.PHONY: all clean update install reset clone
 (DIR) diff --git a/suckless/dwm/config.h b/suckless/dwm/config.h
       @@ -0,0 +1,201 @@
       +/* See LICENSE file for copyright and license details. */
       +
       +#include <X11/XF86keysym.h>
       +
       +/* appearance */
       +static const unsigned int borderpx  = 3;
       +static const unsigned int snap      = 32;
       +static const int lockfullscreen            = 1;
       +static const int showbar            = 1;
       +static const int topbar             = 1;
       +static const unsigned int systraypinning = 0;
       +static const unsigned int systrayonleft = 0;
       +static const unsigned int systrayspacing = 2;
       +static const int systraypinningfailfirst = 1;
       +static const int showsystray        = 1;
       +
       +static const char *fonts[]          = { "Hack:size=10" };
       +static const char dmenufont[]       = "Hack:size=10";
       +static const char col_gray1[]       = "#222222";
       +static const char col_gray2[]       = "#98971A";
       +static const char col_gray3[]       = "#bbbbbb";
       +static const char col_gray4[]       = "#eeeeee";
       +static const char col_cyan[]        = "#222222";
       +static const char *colors[][3]      = {
       +        /*               fg         bg         border   */
       +        [SchemeNorm] = { col_gray3, col_gray1, col_cyan },
       +        [SchemeSel]  = { col_gray4, col_cyan,  col_gray2  },
       +};
       +
       +
       +/* custom functions */
       +static void togglefullscreen(const Arg *arg);
       +static void bstack(Monitor *m);
       +static void centeredfloatingmaster(Monitor *m);
       +
       +/* custom defines for mouse buttons */
       +/* only 1-5 are defined in X11/X.h */
       +#define Button8 8
       +#define Button9 9
       +
       +/* tagging */
       +static const char *tags[] = { "1", "2", "3", "4", "5" };
       +
       +static Rule rules[] = {
       +        /* class      instance    title       tags mask     isfloating   monitor */
       +        { NULL,       NULL,       NULL,       0,            False,       -1 },
       +};
       +
       +/* layout(s) */
       +static const float mfact     = 0.65;
       +static const int nmaster     = 1;
       +static const int resizehints = 0;
       +
       +static const Layout layouts[] = {
       +        { "TTT",      bstack },
       +        { "[]=",      tile },
       +        { ">M>",      centeredfloatingmaster },
       +        { "><>",      NULL },
       +};
       +
       +#define MODKEY Mod1Mask
       +#define TAGKEYS(KEY,TAG) \
       +{ MODKEY,                       KEY,      view,           {.ui = 1 << TAG} }, \
       +{ MODKEY|ControlMask,           KEY,      toggleview,     {.ui = 1 << TAG} }, \
       +{ MODKEY|ShiftMask,             KEY,      tag,            {.ui = 1 << TAG} }, \
       +{ MODKEY|ControlMask|ShiftMask, KEY,      toggletag,      {.ui = 1 << TAG} },
       +
       +#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
       +
       +/* commands */
       +static char dmenumon[2] = "0";
       +static const char *dmenucmd[] = { "dmenu_run", NULL };
       +static const char *termcmd[]  = { "xterm", NULL };
       +static const char *webcmd[]  = { "firefox", NULL };
       +static const char *musiccmd[]  = { "/home/jay/bin/music", NULL };
       +static const char *volup[] = { "sndioctl", "output.level=+0.1", NULL };
       +static const char *voldown[] = { "sndioctl", "output.level=-0.1", NULL };
       +
       +
       +static Key keys[] = {
       +        /* modifier                     key        function        argument */
       +        { MODKEY,                       XK_p,      spawn,          {.v = dmenucmd } },
       +        { MODKEY,                       XK_space,  spawn,          {.v = termcmd } },
       +        { MODKEY,                       XK_f,      spawn,          {.v = webcmd } },
       +        { MODKEY,                       XK_m,      spawn,          {.v = musiccmd } },
       +        { MODKEY,                       XF86XK_AudioRaiseVolume,      spawn,          {.v = volup } },
       +        { MODKEY,                       XF86XK_AudioLowerVolume,      spawn,          {.v = voldown } },
       +        { MODKEY,                       XK_j,      focusstack,     {.i = +1 } },
       +        { MODKEY,                       XK_k,      focusstack,     {.i = -1 } },
       +        { MODKEY,                       XK_h,      setmfact,       {.f = -0.05} },
       +        { MODKEY,                       XK_l,      setmfact,       {.f = +0.05} },
       +        { MODKEY,                       XK_Return, zoom,           {0} },
       +        { MODKEY,                       XK_Tab,    view,           {0} },
       +        { MODKEY,                       XK_c,      killclient,     {0} },
       +        { MODKEY|ShiftMask,             XK_m,      togglefullscreen, {0} },
       +        { MODKEY,                       XK_period, focusmon,       {.i = +1 } },
       +        { MODKEY,                        XK_comma,  tagmon,         {.i = +1 } },
       +        { MODKEY,                       XK_b,      togglebar,      {0} },
       +        { MODKEY,                       XK_x,      setlayout,      {.v = &layouts[0]} },
       +        { MODKEY|ShiftMask,             XK_x,      setlayout,      {.v = &layouts[1]} },
       +        TAGKEYS(                        XK_1,                      0)
       +        TAGKEYS(                        XK_2,                      1)
       +        TAGKEYS(                        XK_3,                      2)
       +        TAGKEYS(                        XK_4,                      3)
       +        TAGKEYS(                        XK_5,                      4)
       +        { MODKEY|ShiftMask,             XK_q,      quit,           {0} },
       +};
       +
       +/* button definitions */
       +static Button buttons[] = {
       +               { ClkRootWin,        0,              Button8,        spawn,          {.v = voldown } },
       +               { ClkRootWin,        0,              Button9,        spawn,          {.v = volup } },
       +        };
       +
       +void
       +togglefullscreen(const Arg *arg)
       +{
       +        if (!selmon->sel)
       +                return;
       +        setfullscreen(selmon->sel, !selmon->sel->isfullscreen);
       +}
       +
       +static void
       +bstack(Monitor *m) {
       +        int w, h, mh, mx, tx, ty, tw;
       +        unsigned int i, n;
       +        Client *c;
       +
       +        for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
       +        if (n == 0)
       +                return;
       +        if (n > m->nmaster) {
       +                mh = m->nmaster ? m->mfact * m->wh : 0;
       +                tw = m->ww / (n - m->nmaster);
       +                ty = m->wy + mh;
       +        } else {
       +                mh = m->wh;
       +                tw = m->ww;
       +                ty = m->wy;
       +        }
       +        for (i = mx = 0, tx = m->wx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
       +                if (i < m->nmaster) {
       +                        w = (m->ww - mx) / (MIN(n, m->nmaster) - i);
       +                        resize(c, m->wx + mx, m->wy, w - (2 * c->bw), mh - (2 * c->bw), 0);
       +                        mx += WIDTH(c);
       +                } else {
       +                        h = m->wh - mh;
       +                        resize(c, tx, ty, tw - (2 * c->bw), h - (2 * c->bw), 0);
       +                        if (tw != m->ww)
       +                                tx += WIDTH(c);
       +                }
       +        }
       +}
       +
       +void
       +centeredfloatingmaster(Monitor *m)
       +{
       +        unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx;
       +        Client *c;
       +
       +        /* count number of clients in the selected monitor */
       +        for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
       +        if (n == 0)
       +                return;
       +
       +        /* initialize nmaster area */
       +        if (n > m->nmaster) {
       +                /* go mfact box in the center if more than nmaster clients */
       +                if (m->ww > m->wh) {
       +                        mw = m->nmaster ? m->ww * m->mfact : 0;
       +                        mh = m->nmaster ? m->wh * 0.9 : 0;
       +                } else {
       +                        mh = m->nmaster ? m->wh * m->mfact : 0;
       +                        mw = m->nmaster ? m->ww * 0.9 : 0;
       +                }
       +                mx = mxo = (m->ww - mw) / 2;
       +                my = myo = (m->wh - mh) / 2;
       +        } else {
       +                /* go fullscreen if all clients are in the master area */
       +                mh = m->wh;
       +                mw = m->ww;
       +                mx = mxo = 0;
       +                my = myo = 0;
       +        }
       +
       +        for(i = tx = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
       +        if (i < m->nmaster) {
       +                /* nmaster clients are stacked horizontally, in the center
       +                 * of the screen */
       +                w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i);
       +                resize(c, m->wx + mx, m->wy + my, w - (2*c->bw),
       +                       mh - (2*c->bw), 0);
       +                mx += WIDTH(c);
       +        } else {
       +                /* stack clients are stacked horizontally */
       +                w = (m->ww - tx) / (n - i);
       +                resize(c, m->wx + tx, m->wy, w - (2*c->bw),
       +                       m->wh - (2*c->bw), 0);
       +                tx += WIDTH(c);
       +        }
       +}
 (DIR) diff --git a/suckless/dwm/patches/01-dwm-systray-6.4.diff b/suckless/dwm/patches/01-dwm-systray-6.4.diff
       @@ -0,0 +1,746 @@
       +diff --git a/config.def.h b/config.def.h
       +index 9efa774..750529d 100644
       +--- a/config.def.h
       ++++ b/config.def.h
       +@@ -3,6 +3,11 @@
       + /* appearance */
       + static const unsigned int borderpx  = 1;        /* border pixel of windows */
       + static const unsigned int snap      = 32;       /* snap pixel */
       ++static const unsigned int systraypinning = 0;   /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */
       ++static const unsigned int systrayonleft = 0;    /* 0: systray in the right corner, >0: systray on left of status text */
       ++static const unsigned int systrayspacing = 2;   /* systray spacing */
       ++static const int systraypinningfailfirst = 1;   /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/
       ++static const int showsystray        = 1;        /* 0 means no systray */
       + static const int showbar            = 1;        /* 0 means no bar */
       + static const int topbar             = 1;        /* 0 means bottom bar */
       + static const char *fonts[]          = { "monospace:size=10" };
       +@@ -101,8 +106,8 @@ static const Key keys[] = {
       + /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
       + static const Button buttons[] = {
       +         /* click                event mask      button          function        argument */
       +-        { ClkLtSymbol,          0,              Button1,        setlayout,      {0} },
       +-        { ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} },
       ++        { ClkTagBar,            MODKEY,         Button1,        tag,            {0} },
       ++        { ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} },
       +         { ClkWinTitle,          0,              Button2,        zoom,           {0} },
       +         { ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } },
       +         { ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} },
       +diff --git a/dwm.c b/dwm.c
       +index 03baf42..4611a03 100644
       +--- a/dwm.c
       ++++ b/dwm.c
       +@@ -57,12 +57,27 @@
       + #define TAGMASK                 ((1 << LENGTH(tags)) - 1)
       + #define TEXTW(X)                (drw_fontset_getwidth(drw, (X)) + lrpad)
       + 
       ++#define SYSTEM_TRAY_REQUEST_DOCK    0
       ++/* XEMBED messages */
       ++#define XEMBED_EMBEDDED_NOTIFY      0
       ++#define XEMBED_WINDOW_ACTIVATE      1
       ++#define XEMBED_FOCUS_IN             4
       ++#define XEMBED_MODALITY_ON         10
       ++#define XEMBED_MAPPED              (1 << 0)
       ++#define XEMBED_WINDOW_ACTIVATE      1
       ++#define XEMBED_WINDOW_DEACTIVATE    2
       ++#define VERSION_MAJOR               0
       ++#define VERSION_MINOR               0
       ++#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
       ++
       + /* enums */
       + enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
       + enum { SchemeNorm, SchemeSel }; /* color schemes */
       + enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
       ++       NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz,
       +        NetWMFullscreen, NetActiveWindow, NetWMWindowType,
       +        NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
       ++enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
       + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
       + enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
       +        ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
       +@@ -141,6 +156,12 @@ typedef struct {
       +         int monitor;
       + } Rule;
       + 
       ++typedef struct Systray   Systray;
       ++struct Systray {
       ++        Window win;
       ++        Client *icons;
       ++};
       ++
       + /* function declarations */
       + static void applyrules(Client *c);
       + static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
       +@@ -172,6 +193,7 @@ static void focusstack(const Arg *arg);
       + static Atom getatomprop(Client *c, Atom prop);
       + static int getrootptr(int *x, int *y);
       + static long getstate(Window w);
       ++static unsigned int getsystraywidth();
       + static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
       + static void grabbuttons(Client *c, int focused);
       + static void grabkeys(void);
       +@@ -189,13 +211,16 @@ static void pop(Client *c);
       + static void propertynotify(XEvent *e);
       + static void quit(const Arg *arg);
       + static Monitor *recttomon(int x, int y, int w, int h);
       ++static void removesystrayicon(Client *i);
       + static void resize(Client *c, int x, int y, int w, int h, int interact);
       ++static void resizebarwin(Monitor *m);
       + static void resizeclient(Client *c, int x, int y, int w, int h);
       + static void resizemouse(const Arg *arg);
       ++static void resizerequest(XEvent *e);
       + static void restack(Monitor *m);
       + static void run(void);
       + static void scan(void);
       +-static int sendevent(Client *c, Atom proto);
       ++static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
       + static void sendmon(Client *c, Monitor *m);
       + static void setclientstate(Client *c, long state);
       + static void setfocus(Client *c);
       +@@ -207,6 +232,7 @@ static void seturgent(Client *c, int urg);
       + static void showhide(Client *c);
       + static void sigchld(int unused);
       + static void spawn(const Arg *arg);
       ++static Monitor *systraytomon(Monitor *m);
       + static void tag(const Arg *arg);
       + static void tagmon(const Arg *arg);
       + static void tile(Monitor *m);
       +@@ -224,18 +250,23 @@ static int updategeom(void);
       + static void updatenumlockmask(void);
       + static void updatesizehints(Client *c);
       + static void updatestatus(void);
       ++static void updatesystray(void);
       ++static void updatesystrayicongeom(Client *i, int w, int h);
       ++static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
       + static void updatetitle(Client *c);
       + static void updatewindowtype(Client *c);
       + static void updatewmhints(Client *c);
       + static void view(const Arg *arg);
       + static Client *wintoclient(Window w);
       + static Monitor *wintomon(Window w);
       ++static Client *wintosystrayicon(Window w);
       + static int xerror(Display *dpy, XErrorEvent *ee);
       + static int xerrordummy(Display *dpy, XErrorEvent *ee);
       + static int xerrorstart(Display *dpy, XErrorEvent *ee);
       + static void zoom(const Arg *arg);
       + 
       + /* variables */
       ++static Systray *systray = NULL;
       + static const char broken[] = "broken";
       + static char stext[256];
       + static int screen;
       +@@ -258,9 +289,10 @@ static void (*handler[LASTEvent]) (XEvent *) = {
       +         [MapRequest] = maprequest,
       +         [MotionNotify] = motionnotify,
       +         [PropertyNotify] = propertynotify,
       ++        [ResizeRequest] = resizerequest,
       +         [UnmapNotify] = unmapnotify
       + };
       +-static Atom wmatom[WMLast], netatom[NetLast];
       ++static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
       + static int running = 1;
       + static Cur *cursor[CurLast];
       + static Clr **scheme;
       +@@ -442,7 +474,7 @@ buttonpress(XEvent *e)
       +                         arg.ui = 1 << i;
       +                 } else if (ev->x < x + TEXTW(selmon->ltsymbol))
       +                         click = ClkLtSymbol;
       +-                else if (ev->x > selmon->ww - (int)TEXTW(stext))
       ++                else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth())
       +                         click = ClkStatusText;
       +                 else
       +                         click = ClkWinTitle;
       +@@ -485,6 +517,13 @@ cleanup(void)
       +         XUngrabKey(dpy, AnyKey, AnyModifier, root);
       +         while (mons)
       +                 cleanupmon(mons);
       ++
       ++        if (showsystray) {
       ++                XUnmapWindow(dpy, systray->win);
       ++                XDestroyWindow(dpy, systray->win);
       ++                free(systray);
       ++        }
       ++
       +         for (i = 0; i < CurLast; i++)
       +                 drw_cur_free(drw, cursor[i]);
       +         for (i = 0; i < LENGTH(colors); i++)
       +@@ -516,9 +555,58 @@ cleanupmon(Monitor *mon)
       + void
       + clientmessage(XEvent *e)
       + {
       ++        XWindowAttributes wa;
       ++        XSetWindowAttributes swa;
       +         XClientMessageEvent *cme = &e->xclient;
       +         Client *c = wintoclient(cme->window);
       + 
       ++        if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
       ++                /* add systray icons */
       ++                if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
       ++                        if (!(c = (Client *)calloc(1, sizeof(Client))))
       ++                                die("fatal: could not malloc() %u bytes\n", sizeof(Client));
       ++                        if (!(c->win = cme->data.l[2])) {
       ++                                free(c);
       ++                                return;
       ++                        }
       ++                        c->mon = selmon;
       ++                        c->next = systray->icons;
       ++                        systray->icons = c;
       ++                        if (!XGetWindowAttributes(dpy, c->win, &wa)) {
       ++                                /* use sane defaults */
       ++                                wa.width = bh;
       ++                                wa.height = bh;
       ++                                wa.border_width = 0;
       ++                        }
       ++                        c->x = c->oldx = c->y = c->oldy = 0;
       ++                        c->w = c->oldw = wa.width;
       ++                        c->h = c->oldh = wa.height;
       ++                        c->oldbw = wa.border_width;
       ++                        c->bw = 0;
       ++                        c->isfloating = True;
       ++                        /* reuse tags field as mapped status */
       ++                        c->tags = 1;
       ++                        updatesizehints(c);
       ++                        updatesystrayicongeom(c, wa.width, wa.height);
       ++                        XAddToSaveSet(dpy, c->win);
       ++                        XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
       ++                        XReparentWindow(dpy, c->win, systray->win, 0, 0);
       ++                        /* use parents background color */
       ++                        swa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
       ++                        XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
       ++                        sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
       ++                        /* FIXME not sure if I have to send these events, too */
       ++                        sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
       ++                        sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
       ++                        sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
       ++                        XSync(dpy, False);
       ++                        resizebarwin(selmon);
       ++                        updatesystray();
       ++                        setclientstate(c, NormalState);
       ++                }
       ++                return;
       ++        }
       ++
       +         if (!c)
       +                 return;
       +         if (cme->message_type == netatom[NetWMState]) {
       +@@ -571,7 +659,7 @@ configurenotify(XEvent *e)
       +                                 for (c = m->clients; c; c = c->next)
       +                                         if (c->isfullscreen)
       +                                                 resizeclient(c, m->mx, m->my, m->mw, m->mh);
       +-                                XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
       ++                                resizebarwin(m);
       +                         }
       +                         focus(NULL);
       +                         arrange(NULL);
       +@@ -656,6 +744,11 @@ destroynotify(XEvent *e)
       + 
       +         if ((c = wintoclient(ev->window)))
       +                 unmanage(c, 1);
       ++        else if ((c = wintosystrayicon(ev->window))) {
       ++                removesystrayicon(c);
       ++                resizebarwin(selmon);
       ++                updatesystray();
       ++        }
       + }
       + 
       + void
       +@@ -699,7 +792,7 @@ dirtomon(int dir)
       + void
       + drawbar(Monitor *m)
       + {
       +-        int x, w, tw = 0;
       ++        int x, w, tw = 0, stw = 0;
       +         int boxs = drw->fonts->h / 9;
       +         int boxw = drw->fonts->h / 6 + 2;
       +         unsigned int i, occ = 0, urg = 0;
       +@@ -708,13 +801,17 @@ drawbar(Monitor *m)
       +         if (!m->showbar)
       +                 return;
       + 
       ++        if(showsystray && m == systraytomon(m) && !systrayonleft)
       ++                stw = getsystraywidth();
       ++
       +         /* draw status first so it can be overdrawn by tags later */
       +         if (m == selmon) { /* status is only drawn on selected monitor */
       +                 drw_setscheme(drw, scheme[SchemeNorm]);
       +-                tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
       +-                drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
       ++                tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px extra right padding */
       ++                drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0);
       +         }
       + 
       ++        resizebarwin(m);
       +         for (c = m->clients; c; c = c->next) {
       +                 occ |= c->tags;
       +                 if (c->isurgent)
       +@@ -735,7 +832,7 @@ drawbar(Monitor *m)
       +         drw_setscheme(drw, scheme[SchemeNorm]);
       +         x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
       + 
       +-        if ((w = m->ww - tw - x) > bh) {
       ++        if ((w = m->ww - tw - stw - x) > bh) {
       +                 if (m->sel) {
       +                         drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
       +                         drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
       +@@ -746,7 +843,7 @@ drawbar(Monitor *m)
       +                         drw_rect(drw, x, 0, w, bh, 1, 1);
       +                 }
       +         }
       +-        drw_map(drw, m->barwin, 0, 0, m->ww, bh);
       ++        drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh);
       + }
       + 
       + void
       +@@ -783,8 +880,11 @@ expose(XEvent *e)
       +         Monitor *m;
       +         XExposeEvent *ev = &e->xexpose;
       + 
       +-        if (ev->count == 0 && (m = wintomon(ev->window)))
       ++        if (ev->count == 0 && (m = wintomon(ev->window))) {
       +                 drawbar(m);
       ++                if (m == selmon)
       ++                        updatesystray();
       ++        }
       + }
       + 
       + void
       +@@ -870,14 +970,32 @@ getatomprop(Client *c, Atom prop)
       +         unsigned char *p = NULL;
       +         Atom da, atom = None;
       + 
       +-        if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
       ++        /* FIXME getatomprop should return the number of items and a pointer to
       ++         * the stored data instead of this workaround */
       ++        Atom req = XA_ATOM;
       ++        if (prop == xatom[XembedInfo])
       ++                req = xatom[XembedInfo];
       ++
       ++        if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
       +                 &da, &di, &dl, &dl, &p) == Success && p) {
       +                 atom = *(Atom *)p;
       ++                if (da == xatom[XembedInfo] && dl == 2)
       ++                        atom = ((Atom *)p)[1];
       +                 XFree(p);
       +         }
       +         return atom;
       + }
       + 
       ++unsigned int
       ++getsystraywidth()
       ++{
       ++        unsigned int w = 0;
       ++        Client *i;
       ++        if(showsystray)
       ++                for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ;
       ++        return w ? w + systrayspacing : 1;
       ++}
       ++
       + int
       + getrootptr(int *x, int *y)
       + {
       +@@ -1018,7 +1136,8 @@ killclient(const Arg *arg)
       + {
       +         if (!selmon->sel)
       +                 return;
       +-        if (!sendevent(selmon->sel, wmatom[WMDelete])) {
       ++
       ++        if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) {
       +                 XGrabServer(dpy);
       +                 XSetErrorHandler(xerrordummy);
       +                 XSetCloseDownMode(dpy, DestroyAll);
       +@@ -1105,6 +1224,13 @@ maprequest(XEvent *e)
       +         static XWindowAttributes wa;
       +         XMapRequestEvent *ev = &e->xmaprequest;
       + 
       ++        Client *i;
       ++        if ((i = wintosystrayicon(ev->window))) {
       ++                sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION);
       ++                resizebarwin(selmon);
       ++                updatesystray();
       ++        }
       ++
       +         if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)
       +                 return;
       +         if (!wintoclient(ev->window))
       +@@ -1226,6 +1352,17 @@ propertynotify(XEvent *e)
       +         Window trans;
       +         XPropertyEvent *ev = &e->xproperty;
       + 
       ++        if ((c = wintosystrayicon(ev->window))) {
       ++                if (ev->atom == XA_WM_NORMAL_HINTS) {
       ++                        updatesizehints(c);
       ++                        updatesystrayicongeom(c, c->w, c->h);
       ++                }
       ++                else
       ++                        updatesystrayiconstate(c, ev);
       ++                resizebarwin(selmon);
       ++                updatesystray();
       ++        }
       ++
       +         if ((ev->window == root) && (ev->atom == XA_WM_NAME))
       +                 updatestatus();
       +         else if (ev->state == PropertyDelete)
       +@@ -1276,6 +1413,19 @@ recttomon(int x, int y, int w, int h)
       +         return r;
       + }
       + 
       ++void
       ++removesystrayicon(Client *i)
       ++{
       ++        Client **ii;
       ++
       ++        if (!showsystray || !i)
       ++                return;
       ++        for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
       ++        if (ii)
       ++                *ii = i->next;
       ++        free(i);
       ++}
       ++
       + void
       + resize(Client *c, int x, int y, int w, int h, int interact)
       + {
       +@@ -1283,6 +1433,14 @@ resize(Client *c, int x, int y, int w, int h, int interact)
       +                 resizeclient(c, x, y, w, h);
       + }
       + 
       ++void
       ++resizebarwin(Monitor *m) {
       ++        unsigned int w = m->ww;
       ++        if (showsystray && m == systraytomon(m) && !systrayonleft)
       ++                w -= getsystraywidth();
       ++        XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh);
       ++}
       ++
       + void
       + resizeclient(Client *c, int x, int y, int w, int h)
       + {
       +@@ -1298,6 +1456,19 @@ resizeclient(Client *c, int x, int y, int w, int h)
       +         XSync(dpy, False);
       + }
       + 
       ++void
       ++resizerequest(XEvent *e)
       ++{
       ++        XResizeRequestEvent *ev = &e->xresizerequest;
       ++        Client *i;
       ++
       ++        if ((i = wintosystrayicon(ev->window))) {
       ++                updatesystrayicongeom(i, ev->width, ev->height);
       ++                resizebarwin(selmon);
       ++                updatesystray();
       ++        }
       ++}
       ++
       + void
       + resizemouse(const Arg *arg)
       + {
       +@@ -1444,26 +1615,37 @@ setclientstate(Client *c, long state)
       + }
       + 
       + int
       +-sendevent(Client *c, Atom proto)
       ++sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4)
       + {
       +         int n;
       +-        Atom *protocols;
       ++        Atom *protocols, mt;
       +         int exists = 0;
       +         XEvent ev;
       + 
       +-        if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
       +-                while (!exists && n--)
       +-                        exists = protocols[n] == proto;
       +-                XFree(protocols);
       ++        if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
       ++                mt = wmatom[WMProtocols];
       ++                if (XGetWMProtocols(dpy, w, &protocols, &n)) {
       ++                        while (!exists && n--)
       ++                                exists = protocols[n] == proto;
       ++                        XFree(protocols);
       ++                }
       ++        }
       ++        else {
       ++                exists = True;
       ++                mt = proto;
       +         }
       ++
       +         if (exists) {
       +                 ev.type = ClientMessage;
       +-                ev.xclient.window = c->win;
       +-                ev.xclient.message_type = wmatom[WMProtocols];
       ++                ev.xclient.window = w;
       ++                ev.xclient.message_type = mt;
       +                 ev.xclient.format = 32;
       +-                ev.xclient.data.l[0] = proto;
       +-                ev.xclient.data.l[1] = CurrentTime;
       +-                XSendEvent(dpy, c->win, False, NoEventMask, &ev);
       ++                ev.xclient.data.l[0] = d0;
       ++                ev.xclient.data.l[1] = d1;
       ++                ev.xclient.data.l[2] = d2;
       ++                ev.xclient.data.l[3] = d3;
       ++                ev.xclient.data.l[4] = d4;
       ++                XSendEvent(dpy, w, False, mask, &ev);
       +         }
       +         return exists;
       + }
       +@@ -1477,7 +1659,7 @@ setfocus(Client *c)
       +                         XA_WINDOW, 32, PropModeReplace,
       +                         (unsigned char *) &(c->win), 1);
       +         }
       +-        sendevent(c, wmatom[WMTakeFocus]);
       ++        sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
       + }
       + 
       + void
       +@@ -1566,6 +1748,10 @@ setup(void)
       +         wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
       +         netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
       +         netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
       ++        netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
       ++        netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
       ++        netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
       ++        netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
       +         netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
       +         netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
       +         netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
       +@@ -1573,6 +1759,9 @@ setup(void)
       +         netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
       +         netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
       +         netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
       ++        xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
       ++        xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
       ++        xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
       +         /* init cursors */
       +         cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
       +         cursor[CurResize] = drw_cur_create(drw, XC_sizing);
       +@@ -1581,6 +1770,8 @@ setup(void)
       +         scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
       +         for (i = 0; i < LENGTH(colors); i++)
       +                 scheme[i] = drw_scm_create(drw, colors[i], 3);
       ++        /* init system tray */
       ++        updatesystray();
       +         /* init bars */
       +         updatebars();
       +         updatestatus();
       +@@ -1711,7 +1902,18 @@ togglebar(const Arg *arg)
       + {
       +         selmon->showbar = !selmon->showbar;
       +         updatebarpos(selmon);
       +-        XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
       ++        resizebarwin(selmon);
       ++        if (showsystray) {
       ++                XWindowChanges wc;
       ++                if (!selmon->showbar)
       ++                        wc.y = -bh;
       ++                else if (selmon->showbar) {
       ++                        wc.y = 0;
       ++                        if (!selmon->topbar)
       ++                                wc.y = selmon->mh - bh;
       ++                }
       ++                XConfigureWindow(dpy, systray->win, CWY, &wc);
       ++        }
       +         arrange(selmon);
       + }
       + 
       +@@ -1807,11 +2009,18 @@ unmapnotify(XEvent *e)
       +                 else
       +                         unmanage(c, 0);
       +         }
       ++        else if ((c = wintosystrayicon(ev->window))) {
       ++                /* KLUDGE! sometimes icons occasionally unmap their windows, but do
       ++                 * _not_ destroy them. We map those windows back */
       ++                XMapRaised(dpy, c->win);
       ++                updatesystray();
       ++        }
       + }
       + 
       + void
       + updatebars(void)
       + {
       ++        unsigned int w;
       +         Monitor *m;
       +         XSetWindowAttributes wa = {
       +                 .override_redirect = True,
       +@@ -1822,10 +2031,15 @@ updatebars(void)
       +         for (m = mons; m; m = m->next) {
       +                 if (m->barwin)
       +                         continue;
       +-                m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
       ++                w = m->ww;
       ++                if (showsystray && m == systraytomon(m))
       ++                        w -= getsystraywidth();
       ++                m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen),
       +                                 CopyFromParent, DefaultVisual(dpy, screen),
       +                                 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
       +                 XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
       ++                if (showsystray && m == systraytomon(m))
       ++                        XMapRaised(dpy, systray->win);
       +                 XMapRaised(dpy, m->barwin);
       +                 XSetClassHint(dpy, m->barwin, &ch);
       +         }
       +@@ -2002,6 +2216,125 @@ updatestatus(void)
       +         if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
       +                 strcpy(stext, "dwm-"VERSION);
       +         drawbar(selmon);
       ++        updatesystray();
       ++}
       ++
       ++
       ++void
       ++updatesystrayicongeom(Client *i, int w, int h)
       ++{
       ++        if (i) {
       ++                i->h = bh;
       ++                if (w == h)
       ++                        i->w = bh;
       ++                else if (h == bh)
       ++                        i->w = w;
       ++                else
       ++                        i->w = (int) ((float)bh * ((float)w / (float)h));
       ++                applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
       ++                /* force icons into the systray dimensions if they don't want to */
       ++                if (i->h > bh) {
       ++                        if (i->w == i->h)
       ++                                i->w = bh;
       ++                        else
       ++                                i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
       ++                        i->h = bh;
       ++                }
       ++        }
       ++}
       ++
       ++void
       ++updatesystrayiconstate(Client *i, XPropertyEvent *ev)
       ++{
       ++        long flags;
       ++        int code = 0;
       ++
       ++        if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
       ++                        !(flags = getatomprop(i, xatom[XembedInfo])))
       ++                return;
       ++
       ++        if (flags & XEMBED_MAPPED && !i->tags) {
       ++                i->tags = 1;
       ++                code = XEMBED_WINDOW_ACTIVATE;
       ++                XMapRaised(dpy, i->win);
       ++                setclientstate(i, NormalState);
       ++        }
       ++        else if (!(flags & XEMBED_MAPPED) && i->tags) {
       ++                i->tags = 0;
       ++                code = XEMBED_WINDOW_DEACTIVATE;
       ++                XUnmapWindow(dpy, i->win);
       ++                setclientstate(i, WithdrawnState);
       ++        }
       ++        else
       ++                return;
       ++        sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
       ++                        systray->win, XEMBED_EMBEDDED_VERSION);
       ++}
       ++
       ++void
       ++updatesystray(void)
       ++{
       ++        XSetWindowAttributes wa;
       ++        XWindowChanges wc;
       ++        Client *i;
       ++        Monitor *m = systraytomon(NULL);
       ++        unsigned int x = m->mx + m->mw;
       ++        unsigned int sw = TEXTW(stext) - lrpad + systrayspacing;
       ++        unsigned int w = 1;
       ++
       ++        if (!showsystray)
       ++                return;
       ++        if (systrayonleft)
       ++                x -= sw + lrpad / 2;
       ++        if (!systray) {
       ++                /* init systray */
       ++                if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
       ++                        die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
       ++                systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel);
       ++                wa.event_mask        = ButtonPressMask | ExposureMask;
       ++                wa.override_redirect = True;
       ++                wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
       ++                XSelectInput(dpy, systray->win, SubstructureNotifyMask);
       ++                XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
       ++                                PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1);
       ++                XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa);
       ++                XMapRaised(dpy, systray->win);
       ++                XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
       ++                if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
       ++                        sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
       ++                        XSync(dpy, False);
       ++                }
       ++                else {
       ++                        fprintf(stderr, "dwm: unable to obtain system tray.\n");
       ++                        free(systray);
       ++                        systray = NULL;
       ++                        return;
       ++                }
       ++        }
       ++        for (w = 0, i = systray->icons; i; i = i->next) {
       ++                /* make sure the background color stays the same */
       ++                wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
       ++                XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
       ++                XMapRaised(dpy, i->win);
       ++                w += systrayspacing;
       ++                i->x = w;
       ++                XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
       ++                w += i->w;
       ++                if (i->mon != m)
       ++                        i->mon = m;
       ++        }
       ++        w = w ? w + systrayspacing : 1;
       ++        x -= w;
       ++        XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh);
       ++        wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh;
       ++        wc.stack_mode = Above; wc.sibling = m->barwin;
       ++        XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc);
       ++        XMapWindow(dpy, systray->win);
       ++        XMapSubwindows(dpy, systray->win);
       ++        /* redraw background */
       ++        XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel);
       ++        XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
       ++        XSync(dpy, False);
       + }
       + 
       + void
       +@@ -2069,6 +2402,16 @@ wintoclient(Window w)
       +         return NULL;
       + }
       + 
       ++Client *
       ++wintosystrayicon(Window w) {
       ++        Client *i = NULL;
       ++
       ++        if (!showsystray || !w)
       ++                return i;
       ++        for (i = systray->icons; i && i->win != w; i = i->next) ;
       ++        return i;
       ++}
       ++
       + Monitor *
       + wintomon(Window w)
       + {
       +@@ -2122,6 +2465,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
       +         return -1;
       + }
       + 
       ++Monitor *
       ++systraytomon(Monitor *m) {
       ++        Monitor *t;
       ++        int i, n;
       ++        if(!systraypinning) {
       ++                if(!m)
       ++                        return selmon;
       ++                return m == selmon ? m : NULL;
       ++        }
       ++        for(n = 1, t = mons; t && t->next; n++, t = t->next) ;
       ++        for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ;
       ++        if(systraypinningfailfirst && n < systraypinning)
       ++                return mons;
       ++        return t;
       ++}
       ++
       + void
       + zoom(const Arg *arg)
       + {
 (DIR) diff --git a/suckless/herbe/Makefile b/suckless/herbe/Makefile
       @@ -0,0 +1,40 @@
       +REPOSITORY = https://github.com/dudik/herbe.git
       +SRC_DIR = src
       +PINNED_REVISION = HEAD
       +PATCH_DIR = patches
       +
       +all: $(SRC_DIR)
       +
       +clean: reset
       +        @if test -d $(SRC_DIR); then \
       +                $(MAKE) -C "${SRC_DIR}" -s clean; \
       +                git -C "${SRC_DIR}" clean -f; \
       +        fi
       +
       +$(SRC_DIR): clone reset
       +        @cp config.h $@
       +        $(MAKE) -C "${SRC_DIR}" -s
       +
       +reset:
       +        @if [ -n "$(strip $(PINNED_REVISION))" ]; then \
       +                git -C "${SRC_DIR}" reset --hard $(PINNED_REVISION); \
       +        fi
       +
       +patch: $(PATCH_DIR)/*
       +        @for file in $^ ; do \
       +                patch -d "${SRC_DIR}" < $${file}; \
       +        done
       +
       +clone:
       +        @if ! test -d $(SRC_DIR); then \
       +                git clone $(REPOSITORY) $(SRC_DIR); \
       +        fi
       +
       +update: clean
       +        @git -C "${SRC_DIR}" pull
       +
       +install:
       +        $(MAKE) -C "${SRC_DIR}" -s install
       +
       +
       +.PHONY: all clean update install reset clone
 (DIR) diff --git a/suckless/herbe/config.h b/suckless/herbe/config.h
       @@ -0,0 +1,19 @@
       +static const char *background_color = "#222222";
       +static const char *border_color = "#008000";
       +static const char *font_color = "#ffd7af";
       +static const char *font_pattern = "Hack:pixelsize=12";
       +static unsigned line_spacing = 5;
       +static unsigned int padding = 12;
       +
       +static unsigned int width = 300;
       +static unsigned int border_size = 3;
       +static unsigned int pos_x = 30;
       +static unsigned int pos_y = 60;
       +
       +enum corners { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT };
       +enum corners corner = TOP_RIGHT;
       +
       +static unsigned int duration = 5; /* in seconds */
       +
       +#define DISMISS_BUTTON Button1
       +#define ACTION_BUTTON Button3
 (DIR) diff --git a/suckless/slstatus/Makefile b/suckless/slstatus/Makefile
       @@ -0,0 +1,35 @@
       +REPOSITORY = git://git.suckless.org/slstatus
       +SRC_DIR = src
       +PINNED_REVISION = HEAD
       +
       +all: $(SRC_DIR)
       +
       +clean: reset
       +        @if test -d $(SRC_DIR); then \
       +                cd $(SRC_DIR); \
       +                $(MAKE) -s clean; \
       +                git clean -f; \
       +        fi
       +
       +$(SRC_DIR): clone reset
       +        @cp config.h $@
       +        @cd $@ && $(MAKE) -s
       +
       +reset:
       +        @if [ -n "$(strip $(PINNED_REVISION))" ]; then \
       +                cd $(SRC_DIR) && git reset --hard $(PINNED_REVISION); \
       +        fi
       +
       +clone:
       +        @if ! test -d $(SRC_DIR); then \
       +                git clone $(REPOSITORY) $(SRC_DIR); \
       +        fi
       +
       +update: clean
       +        @cd $(SRC_DIR) && git pull
       +
       +install:
       +        $(MAKE) -C "${SRC_DIR}" -s install
       +
       +
       +.PHONY: all clean update install reset clone
 (DIR) diff --git a/suckless/slstatus/config.h b/suckless/slstatus/config.h
       @@ -0,0 +1,71 @@
       +/* See LICENSE file for copyright and license details. */
       +
       +/* interval between updates (in ms) */
       +const unsigned int interval = 1000;
       +
       +/* text to show if no value can be retrieved */
       +static const char unknown_str[] = "n/a";
       +
       +/* maximum output string length */
       +#define MAXLEN 2048
       +
       +/*
       + * function            description                     argument (example)
       + *
       + * battery_perc        battery percentage              battery name (BAT0)
       + *                                                     NULL on OpenBSD/FreeBSD
       + * battery_remaining   battery remaining HH:MM         battery name (BAT0)
       + *                                                     NULL on OpenBSD/FreeBSD
       + * battery_state       battery charging state          battery name (BAT0)
       + *                                                     NULL on OpenBSD/FreeBSD
       + * cat                 read arbitrary file             path
       + * cpu_freq            cpu frequency in MHz            NULL
       + * cpu_perc            cpu usage in percent            NULL
       + * datetime            date and time                   format string (%F %T)
       + * disk_free           free disk space in GB           mountpoint path (/)
       + * disk_perc           disk usage in percent           mountpoint path (/)
       + * disk_total          total disk space in GB          mountpoint path (/)
       + * disk_used           used disk space in GB           mountpoint path (/)
       + * entropy             available entropy               NULL
       + * gid                 GID of current user             NULL
       + * hostname            hostname                        NULL
       + * ipv4                IPv4 address                    interface name (eth0)
       + * ipv6                IPv6 address                    interface name (eth0)
       + * kernel_release      `uname -r`                      NULL
       + * keyboard_indicators caps/num lock indicators        format string (c?n?)
       + *                                                     see keyboard_indicators.c
       + * keymap              layout (variant) of current     NULL
       + *                     keymap
       + * load_avg            load average                    NULL
       + * netspeed_rx         receive network speed           interface name (wlan0)
       + * netspeed_tx         transfer network speed          interface name (wlan0)
       + * num_files           number of files in a directory  path
       + *                                                     (/home/foo/Inbox/cur)
       + * ram_free            free memory in GB               NULL
       + * ram_perc            memory usage in percent         NULL
       + * ram_total           total memory size in GB         NULL
       + * ram_used            used memory in GB               NULL
       + * run_command         custom shell command            command (echo foo)
       + * swap_free           free swap in GB                 NULL
       + * swap_perc           swap usage in percent           NULL
       + * swap_total          total swap size in GB           NULL
       + * swap_used           used swap in GB                 NULL
       + * temp                temperature in degree celsius   sensor file
       + *                                                     (/sys/class/thermal/...)
       + *                                                     NULL on OpenBSD
       + *                                                     thermal zone on FreeBSD
       + *                                                     (tz0, tz1, etc.)
       + * uid                 UID of current user             NULL
       + * uptime              system uptime                   NULL
       + * username            username of current user        NULL
       + * vol_perc            OSS/ALSA volume in percent      mixer file (/dev/mixer)
       + *                                                     NULL on OpenBSD/FreeBSD
       + * wifi_essid          WiFi ESSID                      interface name (wlan0)
       + * wifi_perc           WiFi signal in percent          interface name (wlan0)
       + */
       +static const struct arg args[] = {
       +        /* function format          argument */
       +        { run_command, "VPN:%4s | ", "if curl -s https://am.i.mullvad.net/connected | grep -q 'server'; then echo 'On'; else echo 'Off'; fi" },
       +        // { run_command, "VOL:%4s | ", "pactl list sinks | tr ' ' '\n' | grep -m1 '%'" },
       +        { datetime, "%s",            "%T" },
       +};
 (DIR) diff --git a/sway/config b/sway/config
       @@ -1,69 +0,0 @@
       -set $mod Mod1
       -
       -# colour theme
       -set $colour #1c3c46
       -set $menu bemenu-run -p '>>> ' --tb '#55a1ba' --tf '#ffffff' --hf '#444444' -c  -W0.4 --fn 'Hack 10'
       -
       -# autostart
       -exec foot --server
       -exec wl-paste -t text --watch clipman store --no-persist
       -exec /usr/libexec/pipewire-launcher
       -
       -# appearance
       -default_border pixel 3
       -default_floating_border pixel 5
       -workspace_layout default
       -font pango: Hack:style=Regular 2
       -
       -for_window [app_id="mpv"] floating enable, sticky enable, move absolute position 1340 760, no_focus
       -
       -# misc
       -xwayland enable
       -bar swaybar_command waybar
       -
       -# keyboard layout
       -input * {
       -    xkb_layout "gb"
       -    xkb_variant "extd"
       -}
       -
       -# keybinds
       -bindsym $mod+Space exec footclient
       -bindsym $mod+p exec $menu
       -bindsym $mod+f exec qutebrowser
       -bindsym $mod+m exec /home/jay/bin/music
       -
       -bindsym XF86AudioRaiseVolume exec pamixer -i 5
       -bindsym XF86AudioLowerVolume exec pamixer -d 5
       -
       -bindsym $mod+c kill
       -bindsym $mod+x exec killall -SIGUSR1 waybar
       -bindsym $mod+Shift+c reload
       -bindsym $mod+Shift+q exec swaymsg exit
       -
       -bindsym $mod+h focus left
       -bindsym $mod+j focus down
       -bindsym $mod+k focus up
       -bindsym $mod+l focus right
       -
       -bindsym $mod+Left focus left
       -bindsym $mod+Down focus down
       -bindsym $mod+Up focus up
       -bindsym $mod+Right focus right
       -
       -bindsym $mod+1 workspace number 1
       -bindsym $mod+2 workspace number 2
       -bindsym $mod+3 workspace number 3
       -bindsym $mod+4 workspace number 4
       -
       -bindsym $mod+Tab focus next
       -bindsym $mod+Shift+1 move container to workspace number 1
       -bindsym $mod+Shift+2 move container to workspace number 2
       -bindsym $mod+Shift+3 move container to workspace number 3
       -bindsym $mod+Shift+4 move container to workspace number 4
       -
       -bindsym $mod+Shift+e layout toggle split
       -bindsym $mod+Shift+m fullscreen
       -bindsym $mod+Shift+w layout tabbed
       -
       -client.focused $colour $colour $colour
 (DIR) diff --git a/waybar/config b/waybar/config
       @@ -1,67 +0,0 @@
       -{
       -        "layer": "top",
       -        "position": "top",
       -
       -        "modules-left": [
       -                "sway/workspaces",
       -                "custom/right-arrow-dark"
       -        ],
       -
       -        "modules-center": [
       -                "custom/vpn"
       -        ],
       -
       -        "modules-right": [
       -                "custom/left-arrow-dark",
       -                "pulseaudio",
       -                "tray",
       -                "clock"
       -        ],
       -
       -        "custom/right-arrow-dark": {
       -                "format": "",
       -                "tooltip": false
       -        },
       -
       -        "custom/left-arrow-dark": {
       -                "format": "",
       -                "tooltip": false
       -        },
       -
       -        "sway/workspaces": {
       -                "disable-scroll": true,
       -                "format": "{name}"
       -        },
       -
       -        "clock": {
       -                "format": "{:%H:%M}",
       -                "tooltip": false
       -        },
       -
       -        "pulseaudio": {
       -                "format": "{icon} {volume:2}% ",
       -                "format-muted": "MUTE",
       -                "format-icons": {
       -                        "default": [
       -                                "",
       -                                ""
       -                        ]
       -                },
       -                "scroll-step": 5,
       -                "on-click": "pamixer -t"
       -        },
       -
       -        "custom/vpn":{
       -                "format": "{icon} {}",
       -                "format-icons": {
       -                        "default": [""]
       -                },
       -                "return-type": "json",
       -                "interval": 60,
       -                "exec": "$HOME/.config/waybar/waybar_vpn.sh"
       -        },
       -
       -        "tray": {
       -                "icon-size": 12
       -        }
       -}
 (DIR) diff --git a/waybar/style.css b/waybar/style.css
       @@ -1,55 +0,0 @@
       -* {
       -        font-size: 12px;
       -        font-family: Hack;
       -}
       -
       -
       -#custom-vpn,
       -window#waybar {
       -        background: #292b2e;
       -        color: #fdf6e3;
       -}
       -
       -#workspaces,
       -#clock,
       -#custom-mail,
       -#pulseaudio,
       -#tray {
       -        background: #1a1a1a;
       -}
       -
       -#custom-right-arrow-dark,
       -#custom-left-arrow-dark {
       -        color: #1a1a1a;
       -}
       -
       -#workspaces button {
       -        padding: 0 0px;
       -        color: #fdf6e3;
       -}
       -#workspaces button.focused {
       -        color: #268bd2;
       -}
       -#workspaces button:hover {
       -        box-shadow: inherit;
       -        text-shadow: inherit;
       -}
       -#workspaces button:hover {
       -        background: #1a1a1a;
       -        border: #1a1a1a;
       -        padding: 0 1px;
       -}
       -
       -#custom-vpn.connected {
       -        color: #007300;
       -}
       -
       -#custom-vpn.disconnected {
       -        color: #d22635;
       -}
       -
       -#clock,
       -#custom-vpn,
       -#pulseaudio {
       -        padding: 0 3px;
       -}
 (DIR) diff --git a/waybar/waybar_mail.sh b/waybar/waybar_mail.sh
       @@ -1,12 +0,0 @@
       -#!/bin/sh
       -
       -maildirnew="$HOME/.mail/jay/Inbox/new/"
       -new="$(find $maildirnew -type f | wc -l)"
       -
       -if [ $new -gt 0 ]
       -then
       -        echo "{\"text\":\"$new\",\"tooltip\":\"$new Mail\",\"class\":\"new\"}"
       -else
       -        echo '{"text":"No new mail","tooltip":"","class":""}'
       -fi
       -
 (DIR) diff --git a/waybar/waybar_vpn.sh b/waybar/waybar_vpn.sh
       @@ -1,9 +0,0 @@
       -#!/bin/sh
       -
       -country=$(curl -s https://am.i.mullvad.net/country)
       -
       -if curl -s https://am.i.mullvad.net/connected | grep -q "server"; then
       -    echo "{\"text\":\"$country\",\"class\":\"connected\"}"
       -else
       -    echo "{\"text\":\"$country\",\"class\":\"disconnected\"}"
       -fi
 (DIR) diff --git a/xenodm/Xresources b/xenodm/Xresources
       @@ -0,0 +1,24 @@
       +! $OpenBSD: Xresources.in,v 1.4 2022/11/07 17:12:06 matthieu Exp $
       +!
       +
       +xlogin.Login.echoPasswd:       true
       +xlogin.Login.fail:             fail
       +xlogin.Login.greeting:
       +xlogin.Login.namePrompt:       \040login\040
       +xlogin.Login.passwdPrompt:     passwd\040
       +
       +xlogin.Login.height:           180
       +xlogin.Login.width:            500
       +xlogin.Login.y:                320
       +xlogin.Login.frameWidth:       0
       +xlogin.Login.innerFramesWidth: 0
       +
       +xlogin.Login.background:       black
       +xlogin.Login.foreground:       #eeeeee
       +xlogin.Login.failColor:        white
       +xlogin.Login.inpColor:         black
       +xlogin.Login.promptColor:      #eeeeec
       +
       +xlogin.Login.face:             Hack-14
       +xlogin.Login.failFace:         Hack-14
       +xlogin.Login.promptFace:       Hack-14
 (DIR) diff --git a/xenodm/Xsetup_0 b/xenodm/Xsetup_0
       @@ -0,0 +1,7 @@
       +#!/bin/sh
       +# $OpenBSD: Xsetup_0.in,v 1.1 2021/08/30 15:38:27 matthieu Exp $
       +
       +xrandr --output default --dpi 96
       +
       +# set background
       +/usr/X11R6/bin/xsetroot -solid black