#+TITLE: Phundrak’s executable scripts
#+AUTHOR: Lucien "Phundrak” Cartier-Tilet
#+EMAIL: phundrak@phundrak.fr
#+OPTIONS: H:4 broken_links:mark email:t ^:{} auto-id:t

# ### LaTeX ####################################################################
#+LATEX_CLASS: conlang
#+LaTeX_CLASS_OPTIONS: [a4paper,twoside]
#+LATEX_HEADER_EXTRA: \usepackage{tocloft} \setlength{\cftchapnumwidth}{3em}
#+LATEX_HEADER_EXTRA: \usepackage{xltxtra,fontspec,xunicode,svg}
#+LATEX_HEADER_EXTRA: \usepackage[total={17cm,24cm}]{geometry}
#+LATEX_HEADER_EXTRA: \setromanfont{Charis SIL}
#+LATEX_HEADER_EXTRA: \usepackage{xcolor}
#+LATEX_HEADER_EXTRA: \usepackage{hyperref}
#+LATEX_HEADER_EXTRA: \hypersetup{colorlinks=true,linkbordercolor=red,linkcolor=blue,pdfborderstyle={/S/U/W 1}}
#+LATEX_HEADER_EXTRA: \usepackage{multicol}
#+LATEX_HEADER_EXTRA: \usepackage{indentfirst}
#+LATEX_HEADER_EXTRA: \sloppy

# ### HTML #####################################################################
#+HTML_DOCTYPE: html5
#+HTML_HEAD_EXTRA: <meta name="description" content="Phundrak's i3 config" />
#+HTML_HEAD_EXTRA: <meta property="og:title" content="Phundrak's i3 config" />
#+HTML_HEAD_EXTRA: <meta property="og:description" content="Description of the i3 config file of Phundrak" />
#+HTML_HEAD_EXTRA: <script src="https://kit.fontawesome.com/4d42d0c8c5.js"></script>
#+HTML_HEAD_EXTRA: <script src="https://cdn.jsdelivr.net/npm/js-cookie@2/src/js.cookie.min.js"></script>
#+HTML_HEAD_EXTRA: <link rel="shortcut icon" href="https://cdn.phundrak.com/img/mahakala-128x128.png" type="img/png" media="screen" />
#+HTML_HEAD_EXTRA: <link rel="shortcut icon" href="https://cdn.phundrak.com/img/favicon.ico" type="image/x-icon" media="screen" />
#+HTML_HEAD_EXTRA: <meta property="og:image" content="https://cdn.phundrak.com/img/rich_preview.png" />
#+HTML_HEAD_EXTRA: <meta name="twitter:card" content="summary" />
#+HTML_HEAD_EXTRA: <meta name="twitter:site" content="@phundrak" />
#+HTML_HEAD_EXTRA: <meta name="twitter:creator" content="@phundrak" />
#+HTML_HEAD_EXTRA: <style>.org-svg{width:auto}</style>
#+INFOJS_OPT: view:info toc:1 home:https://phundrak.com/config toc:t
#+HTML_HEAD_EXTRA: <link rel="stylesheet" href="https://langue.phundrak.com/css/htmlize.min.css"/>
#+HTML_HEAD_EXTRA: <link rel="stylesheet" href="https://langue.phundrak.com/css/main.css"/>
#+HTML_HEAD_EXTRA: <script src="https://langue.phundrak.com/js/jquery.min.js"></script>
#+HTML_HEAD_EXTRA: <script defer src="https://langue.phundrak.com/js/main.js"></script>

* Table of Contents                                        :TOC_4_gh:noexport:
  :PROPERTIES:
  :CUSTOM_ID: h-400070eb-725f-4416-a4c6-da3053df750b
  :END:
- [[#presentation][Presentation]]
- [[#4chandl][4chandl]]
- [[#askpass][Askpass]]
- [[#backup][Backup]]
- [[#connectwifi][ConnectWifi]]
- [[#cppnew][Cppnew]]
- [[#cnew][Cnew]]
- [[#dart-language-server][Dart Language Server]]
- [[#dmenu][Dmenu]]
- [[#emoji-picker][Emoji picker]]
- [[#polybar-launch][Polybar-launch]]
- [[#rofi-mount][Rofi-mount]]
  - [[#get-the-mountable-elements][Get the mountable elements]]
  - [[#get-the-mount-point][Get the mount point]]
  - [[#mount-a-usb-drive-hard-drive-or-partition][Mount a USB drive, hard drive or partition]]
  - [[#mount-an-android-device][Mount an Android device]]
  - [[#mount-a-cd-drive][Mount a CD drive]]
  - [[#ask-what-type-of-drive-we-want-to-mount][Ask what type of drive we want to mount]]
  - [[#launch-the-mounting-functions][Launch the mounting functions]]
- [[#rofi-pass][Rofi-pass]]
- [[#rofi-umount][Rofi-umount]]
  - [[#get-the-unmountable-drives][Get the unmountable drives]]
  - [[#unmount-disk-partitions][Unmount disk partitions]]
  - [[#unmount-android-device][Unmount Android device]]
  - [[#unmount-cd-drive][Unmount CD drive]]
  - [[#ask-what-type-of-drive-to-unmount][Ask what type of drive to unmount]]
  - [[#launch-the-unmounting-functions][Launch the unmounting functions]]
- [[#starwars][Starwars]]
- [[#updateflutter][UpdateFlutter]]
- [[#wacom-setup][Wacom setup]]
  - [[#set-our-variables][Set our variables]]
  - [[#select-our-screen][Select our screen]]
  - [[#adjust-the-tablet][Adjust the tablet]]
  - [[#lauch-the-functions][Lauch the functions]]
- [[#yadm][Yadm]]

* Presentation
  :PROPERTIES:
  :CUSTOM_ID: h-309d8596-c35e-4700-a174-13f40884940d
  :END:
  This file will  present all the executable  scripts I wrote. It  is also their
  original source code, all the following code snippets are exported and tangled
  from this file to the actual executables.

  Please do not forget to run the following before tangling files from this file
  to make sure the tangled files will be executables.
  #+begin_src emacs-lisp :exports code :results silent
    (defun phundrak/make-tangled-files-executable ()
      (set-file-modes (buffer-file-name) #o755))
    (add-hook 'org-babel-post-tangle-hook 'phundrak/make-tangled-files-executable)
  #+end_src

* 4chandl
  :PROPERTIES:
  :CUSTOM_ID: h-39e14885-9da7-4cba-b24e-c3b181ef5f6b
  :HEADER-ARGS: :tangle 4chandl :exports code
  :END:
  Usage: =4chandl [ URL TO THREAD ]=

  I made  this small  script to  download the attached  files of  4chan threads.
  First of all, let’s declare it as a fish script.
  #+BEGIN_SRC fish
  #!/usr/bin/env fish
  #+END_SRC

  Now, let’s check if any arguments were  passed to the executable. If none were
  passed, the script should be aborted.
  #+BEGIN_SRC fish
    if ! count $argv > /dev/null
        echo 'No URL specified! Give the URL to thread as the only argument.'
        exit 1
    end
  #+END_SRC

  Now, let’s store the regex we use to get the link to the attached files.
  #+BEGIN_SRC fish
  set regex_4cdn '\/\/is2\.4chan\.org\/[a-z]+\/[A-Za-z0-9]+\.[A-Za-z]{3,4}'
  #+END_SRC

  We’ll use a thread  counter to get a visual indication on  how the download is
  going.
  #+BEGIN_SRC fish
    set thread_counter 1
  #+END_SRC

  Now, we will use  each of the arguments passed as a URL  to download the files
  from.
  #+BEGIN_SRC fish
  for url in $argv
  #+END_SRC

  As  a visual  indicator, let’s  get the  amount of  elements we  are going  to
  download from the current thread and print it.
  #+BEGIN_SRC fish
    set file_total (curl -ks $url | grep -oE $regex_4cdn | uniq | wc -l)
    echo total files to download in current thread: $file_total
  #+END_SRC

  Let’s set a file counter so we can visualize the download progress.
  #+BEGIN_SRC fish
  set file_counter 1
  #+END_SRC

  Now, let’s download each file from the current thread.
  #+BEGIN_SRC fish
    for image_url in (curl -k -s $url | grep -Eo $regex_4cdn | uniq | sed 's/^/https:/')
        echo -n Downloading image $counter of $total...
        wget --no-check-certificate -q -nc $image_url
        echo ' Done (thread: $thread_counter/thread_total\tfile: $file_counter/file_total)'
        set file_counter (math $file_counter + 1)
    end
  #+END_SRC

  Let’s increment the thread counter.
  #+BEGIN_SRC fish
  set thread_counter (math $thread_counter + 1)
  #+END_SRC

  Let’s now close the for loop.
  #+BEGIN_SRC fish
  end
  #+END_SRC

* Askpass
  :PROPERTIES:
  :CUSTOM_ID: h-b2bef089-69e3-4efb-ac2f-a5eb6a3a80e8
  :HEADER-ARGS: :tangle askpass :exports code
  :END:
  Askpass is a simple script that invokes =rofi=  as a way to get from a GUI the
  user’s sudo password. It is inspired  by [[https://github.com/ODEX-TOS/tools/blob/master/rofi/askpass][this original tool]], rewritten in fish
  and with [[https://wiki.archlinux.org/index.php/Rofi][rofi]] support instead of [[https://wiki.archlinux.org/index.php/Dmenu][dmenu]]. As  you can see, this is a oneliner if
  we ignore the initial shebang. This executable is pointed at by the
  #+BEGIN_SRC fish :exports code
    #!/usr/bin/env fish
    rofi -dmenu -font 'DejaVu Sans 10' -password -no-fixed-num-lines \
    -p (printf $argv[1] | sed s/://)
  #+END_SRC

* Backup
  :PROPERTIES:
  :CUSTOM_ID: h-30cb6655-382f-492a-a005-df15512ab7a5
  :HEADER-ARGS: :tangle backup :exports code
  :END:
  =backup= is a very simple, oneliner script  that will create a local copy of a
  file and add the date at which it  was copied in the filename. You can see its
  source code here:
  #+BEGIN_SRC fish
    #!/usr/bin/env fish
    cp $argv[1] $argv[1].bak.(date +"%Y%m%d%H%M%S")
  #+END_SRC

* ConnectWifi
  :PROPERTIES:
  :HEADER-ARGS: :tangle connect-wifi :exports code
  :CUSTOM_ID: h-7a958906-1f79-448f-95b3-7226bc80e88c
  :END:
  =connect-wifi= is  a small  utility tool  that allows the  user to  connect to
  available WiFi networks. The  first thing to do is to select  the WiFi we want
  to connect  to. We’ll  use the  =nmcli c  s= command  to get  the list  of the
  available networks, and we’ll chose one with =rofi=.
  #+BEGIN_SRC fish
    #!/usr/bin/env fish
    set SELECTEDWIFI (nmcli d w l | egrep -o '([0-9A-F]{2}:){5}[0-9A-F]{2}\s*(.*)Infra' | egrep -o '\s+(.*)\s+' | awk '{$1=$1}1' | rofi -dmenu -p "Select your WiFi network")
  #+END_SRC
  Now, if  a network was  selected, let’s attempt  to connect to  it. Otherwise,
  let’s just send a notification no network was selected.
  #+BEGIN_SRC fish
    if test -z $SELECTEDWIFI
        notify-send "No WiFi network selected" -u low && exit
    end
    nmcli c u $SELECTEDWIFI
  #+END_SRC

* Cppnew
  :PROPERTIES:
  :CUSTOM_ID: h-264945df-fe7a-4f9d-845a-9cc26c196f4b
  :HEADER-ARGS: :tangle cppnew :exports code
  :END:
  =cppnew= is a small utility that helps you create a new C++ project. Several
  templates are available, the default one using CMake, and three others that
  are a bit more advances, based on:
  - CMake + [[https://conan.io/][Conan]]
  - [[https://mesonbuild.com/][Meson]] + [[https://ninja-build.org/][Ninja]]
  - Meson + Ninja + Conan
  There is also a default [[http://doxygen.nl/][Doxygen]] file included for your documentation, ready to
  go. I  even made it  so that you  can execute it  as an executable  file, like
  =./doc/Doxyfile= from the project root.

  The choice is given to the user which of them to use with options that will be
  given to =cppnew=.

  #+begin_src fish
#!/usr/bin/env fish
  #+end_src

  First of all, if no arguments were passed, return an error.
  #+begin_src fish
    if ! count $argv >/dev/null
        echo "Missing argument: PROJECT" && return -1
    end
  #+end_src

  Now, let’s set a couple of variables which will prove useful later on when
  trying to set up our project.

* Cnew
  :PROPERTIES:
  :CUSTOM_ID: h-a4ccdc0f-6813-4207-9479-4d68296f5fdb
  :HEADER-ARGS: :tangle cnew :exports code
  :END:
  =cnew=  is a  small utility  script similar  to but  simpler than  cppnew that
  creates a  CMake template C project  from the template that  already exists in
  [[file:~/dev/templateC][~/dev/templateC]]. This script is a fish script, so let’s insert the shebang.
  #+BEGIN_SRC fish
  #!/usr/bin/env fish
  #+END_SRC

  If no argument was passed, display an error message and exit.
  #+BEGIN_SRC fish
    if ! count $argv > /dev/null
        echo "Missing argument: PROJECT" && return -1
    end
  #+END_SRC

  Pass the first argument to a switch statement.
  #+BEGIN_SRC fish
  switch "$argv[1]"
  #+END_SRC

  If the argument  is =-h= or =--help=,  then display the help  message and exit
  the script normally.
  #+BEGIN_SRC fish
    case -h --help
        man ~/dev/fishfunctions/cnew.man
        exit 0
  #+END_SRC

  Else, the argument is the name of the project the user wants to create.
  #+BEGIN_SRC fish
    case '*'
        set -g project_name $argv[1]
  #+END_SRC

  Let’s close the switch statement.
  #+BEGIN_SRC fish
  end
  #+END_SRC

  Now, let’s copy the template where the  user is executing =cnew= from, give it
  the name of the project and move to the project.
  #+BEGIN_SRC fish
    cp -r ~/dev/templateC $argv[1]
    cd $argv[1]
  #+END_SRC

  The  default files  have a  placeholder  for the  name of  the project.  Let’s
  replace these placeholders with the project’s name.
  #+BEGIN_SRC fish
    sed -i "s/PROJECTNAME/$argv[1]/g" CMakeLists.txt
    sed -i "s/PROJECTNAME/$argv[1]/g" README.org
    sed -i "s/CPROJECTNAME/$argv[1]/g" doc/Doxyfile
  #+END_SRC

  Now, let’s create a git repository and initialize it.
  #+BEGIN_SRC fish
    git init
    git add .
    git commit -m "initial commit"
  #+END_SRC

  And we’re done!

* Dart Language Server
  :PROPERTIES:
  :CUSTOM_ID: h-771896e9-ab96-4158-af0b-1fcbef9ab969
  :HEADER-ARGS: :tangle dart_language_server :exports code
  :END:
  Spacemacs' recommendations  on how  to use  Dart with  LSP is  outdated, since
  [[https://github.com/natebosch/dart_language_server][=dart_language_server=]]  is obsolete.  As  recommended by  the  repo owner,  we
  should launch instead the following code:
  #+BEGIN_SRC fish
    #!/usr/bin/env fish
    /usr/bin/dart $DART_SDK/snapshots/analysis_server.dart.snapshot --lsp
  #+END_SRC
  So, instead of  using the obsolete executable, instead we  will be calling the
  analysis server as requested.

* Dmenu
  :PROPERTIES:
  :CUSTOM_ID: h-50623ecd-b633-4af7-9cc4-5a032f01d1ee
  :HEADER-ARGS: :tangle dmenu :exports code
  :END:
  I  wrote this  very simple  script  in order  to replace  =dmenu= with  rofi’s
  emulation  of dmenu,  since I  prefer  rofi’s appearance.  It basically  calls
  rofi’s dmenu emulation with the arguments initially passed to dmenu.
  #+BEGIN_SRC fish
    #!/usr/bin/env fish
    rofi -dmenu $argv
  #+END_SRC

* Emoji picker
  :PROPERTIES:
  :CUSTOM_ID: h-477cd486-c9a6-4d59-bd9d-62d8f08ee62d
  :HEADER-ARGS: :tangle rofi-emoji :exports code
  :END:
  The   emoji  picker   is   a   simple  fish   script   that   uses  rofi   and
  [[file:~/.config/emoji.txt][~/.config/emoji.txt]]  to provide  a small,  local search  for emojis.  Once the
  emoji is selected, it is copied to the clipboard using =xclipboard=.
  #+BEGIN_SRC fish
    #!/usr/bin/env fish
    grep -v "#" ~/.config/emoji.txt | rofi -dmenu -p "Select emoji" -i | awk '{print $1}' | tr -d '\n' | xclip -selection clipboard
  #+END_SRC

  Also, let’s send a notification telling the user the emoji has been copied!
  #+BEGIN_SRC fish
    set emoji (xclip -o -selection clipboard | tr -d '\n')
    test -z "$emoji" && notify-send "No emoji copied" -u low && exit
    set -a emoji "copied to clipboard"
    pgrep -x dunst >/dev/null && notify-send -u low $emoji
  #+END_SRC

  It is inspired from [[https://www.youtube.com/watch?v=UCEXY46t3OA][this video]] from [[https://lukesmith.xyz/][Luke Smith]], rewritten in Fish.

* Polybar-launch
  :PROPERTIES:
  :CUSTOM_ID: h-68587918-879b-42db-b304-901d01233f95
  :HEADER-ARGS: :tangle polybar-launch :exports code
  :END:
  This scripts  allows the user  to kill polybar and  relaunch it, or  to simply
  launch it  if polybar  isn’t launched yet.  This script is  a bash  script, so
  let’s declare its shebang.
  #+BEGIN_SRC bash
  #!/usr/bin/env bash
  #+END_SRC

  First thing to do is kill all polybar processes.
  #+BEGIN_SRC bash
  killall -q polybar
  #+END_SRC

  Now we have to wait untill all polybar processes have been shut down.
  #+BEGIN_SRC bash
  while pgrep -u $UID -x polybar >/dev/null; do sleep 1; done
  #+END_SRC

  Now that  our system isn’t running  polybar anymore, we’ll launch  it again on
  all of our  screens. By the way, I  have two bars, so I’ll have  to lauch them
  both.
  #+BEGIN_SRC bash
    if type "xrandr"; then
        for m in $(xrandr --query | grep " connected" | cut -d" " -f1); do
            MONITOR=$m polybar --reload top &
            MONITOR=$m polybar --reload bottom &
        done
    else
        polybar --reload top &
        polybar --reload bottom &
    fi
  #+END_SRC

  And we’re done! Let’s just launch a notification polybar has been relaunched.
  #+BEGIN_SRC bash
    notify-send "Polybar restarted!" -a "polybar-launch"
  #+END_SRC

* Rofi-mount
  :PROPERTIES:
  :HEADER-ARGS: :tangle rofi-mount :exports code
  :CUSTOM_ID: h-32ee4a66-e7fb-4abf-a168-fa259efdb1f4
  :END:
  =rofimount=  is  a  script  inspired  by  [[https://github.com/ihebchagra/dotfiles/blob/master/.local/bin/dmount][this  one]],  based  on  dmenu,  which
  interactively asks the user  what to mount, and where to mount  it. What I did
  was replace  dmenu with rofi, and  fix a couple  of bugs I encountered  in the
  original script.  For the  record, this  is a fish  script. Let’s  declare our
  shebang.
  #+BEGIN_SRC fish
  #!/usr/bin/env fish
  #+END_SRC

** Get the mountable elements
   :PROPERTIES:
   :CUSTOM_ID: h-2307005f-385e-4149-b885-55e699c822bb
   :END:
   #+BEGIN_SRC fish
     begin
   #+END_SRC
   What the script does first is detect everything that can be mounted. Between
   a =begin= and =end=, let’s set =LFS= as a local variable. This si in order to
   get sane variables in the current block.
   #+BEGIN_SRC fish
   set -l LFS
   #+END_SRC

   Now, let’s detect the amount of mountable Android filesystems, and if any are
   detected, let’s read them into a global variable.
   #+BEGIN_SRC fish
     set -l a (math (jmtpfs -l | wc -l) - 2)
     test $a -ge 0 && jmtpfs -l 2> /dev/null | tail -n $a | read -zg anddrives
   #+END_SRC

   We’ll do the same for external and internal drives and partitions that can be
   mounted here.
   #+BEGIN_SRC fish
     lsblk -rpo "name,type,size,mountpoint" | \
     awk '$2=="part"&&$4==""{printf "%s (%s)\n",$1,$3}' | \
     read -zg usbdrives
   #+END_SRC

   Finally, we look for any CD drive that could be mounted on our device.
   #+BEGIN_SRC fish
     blkid /dev/sr0 | awk '{print $1}' | sed 's/://' | read -z cddrives
   #+END_SRC

   And that’s the end of our first block!
   #+BEGIN_SRC fish
     end
   #+END_SRC

   Alright, we’ll  save what  kind on drives  we can mount  in a  temporary file
   called =/tmp/drives=. We’ll make sure it’s  blank by erasing it then creating
   it again with  =touch=, like so. The =-f=  flag on =rm= is here so  we get no
   error if we try to delete a file that doesn’t exist (yet).
   #+BEGIN_SRC fish
     set -g TMPDRIVES /tmp/drives
     rm -f $TMPDRIVES
     touch $TMPDRIVES
   #+END_SRC

   Now, let’s write what type of drives we can mount in this temporary file.
   #+BEGIN_SRC fish
     test -n "$usbdrives" && echo "USB" >> $TMPDRIVES
     test -n "$cddrives" && echo "CD" >> $TMPDRIVES
     test -n "$anddrives" && echo "Android" >> $TMPDRIVES
   #+END_SRC

   Now, we want to  declare where to look for mount  directories. For now, we’ll
   only look in =/media=, but you can add more if you wish.
   #+BEGIN_SRC fish
     set -g basemount /media
   #+END_SRC

** Get the mount point
   :PROPERTIES:
   :CUSTOM_ID: h-a17825bd-96e2-4c90-99ef-b0f2895cffb6
   :END:
   Now, let’s declare a function that will allow us to chose the drive we want
   to mount.
   #+BEGIN_SRC fish
     function getmount
   #+END_SRC

   First, we want to get our mount point.  We’ll run a =find= command on each of
   the directories listed in =$basemount= to look for folders on which our drive
   could be mounted. This  list will be passed to rofi from  which we will chose
   our mount point.
   #+BEGIN_SRC fish
     set -g mp (for d in $basemount
         find $d -maxdepth 5 -type d
     end | rofi -dmenu -i -p 'Type in mount point.')
   #+END_SRC

   We  should verify  that something  has been  actually selected,  otherwise we
   should abort the script.
   #+BEGIN_SRC fish
     if test -z $mp || test $mp = ""
         return 1
     end
   #+END_SRC

   Now, if the selected  mount point does not exist, we’ll  ask the user whether
   the directory  should be created.  If no, the script  will abort. If  yes, an
   attempt will be made at creating the  directory as the user; if that fails, a
   new attempt will be made as sudo.
   #+BEGIN_SRC fish
     if test ! -d $mp
         switch (printf "No\\nYes" | rofi -dmenu -i -p "$mp does not exist. Create it?")
             case 'Yes'
                 mkdir -p $mp || sudo -A mkdir -p $mp
             case '*'
                 return 1
         end
     end
   #+END_SRC

   Finally, let’s close the function
   #+BEGIN_SRC fish
     end
   #+END_SRC

** Mount a USB drive, hard drive or partition
   :PROPERTIES:
   :CUSTOM_ID: h-72781187-ebf2-418c-99b3-bba44922fc60
   :END:
   Alright,  we  want  to  mount  a  partition  that  answers  by  the  name  of
   =/dev/sdXX=, how  do we do that?  Let’s create first the  function =mountusb=
   that will take care of it for us.
   #+BEGIN_SRC fish
   function mountusb
   #+END_SRC

   Now, the first thing we want to do  is select the partition we want to mount.
   Remember, we  stored those in =$usbdrives=  earlier, so let’s pipe  them into
   rofi so we can chose from it. Also, =awk= will get their path in =/dev=.
   #+BEGIN_SRC fish
     set -g chosen (echo $usbdrives | \
     rofi -dmenu -i -p "Mount which drive?" | \
     awk '{print $1}')
   #+END_SRC

   As usual  after a user  selection, let’s  verify something has  actually been
   selected. If not, let’s abort the script.
   #+BEGIN_SRC fish
   test -z $chosen && return 1
   #+END_SRC

   Now, let’s select  the mount point of our partition.  We’ll call the function
   =getmount= described in [[#h-a17825bd-96e2-4c90-99ef-b0f2895cffb6][Get the mount point]] to select it.
   #+BEGIN_SRC fish
   getmount
   #+END_SRC

   Let’s verify  the variable  =mp= set  in =getmount=  is not  empty, otherwise
   abort the script.
   #+BEGIN_SRC fish
   test -z $mp && return 1
   #+END_SRC

   Now, let’s mount it! We’ll use a switch which will detect the filesystem used
   so we know how to mount the partition.
   #+BEGIN_SRC fish
   switch (lsblk -no "fstype" $chosen)
   #+END_SRC

   We have two named case: =vfat= filesystems.
   #+BEGIN_SRC fish
     case "vfat"
         sudo -A mount -t vfat $chosen $mp -o rw,umask=0000
   #+END_SRC

   And =ntfs= filesystems.
   #+BEGIN_SRC fish
     case "ntfs"
         sudo -A mount -t ntfs $chosen $mp -o rw,umask=0000
   #+END_SRC

   Else, we’ll let  =mount= determine which filesystem is used  by the partition
   (generally =ext4=).
   #+BEGIN_SRC fish
     case '*'
         sudo -A mount $chosen $mp
   #+END_SRC

   We’ll also  run a =chown=  on this newly mounted  filesystem so the  user can
   access it without any issues.
   #+BEGIN_SRC fish
     sudo -A chown -R $USER:(id -g $USER) $mp
   #+END_SRC

   Let’s close the  switch block and send a notification  the partition has been
   mounted.
   #+BEGIN_SRC fish
   end && notify-send -a "dmount" "💻 USB mounting" "$chosen mounted to $mp."
   #+END_SRC

   And let’s close the function.
   #+BEGIN_SRC fish
   end
   #+END_SRC

** Mount an Android device
   :PROPERTIES:
   :CUSTOM_ID: h-af36260f-2c00-43b7-9383-5235ebac9b51
   :END:
   The function  that manages  to mount  Android filesystems  is =mountandroid=.
   Let’s declare it.
   #+BEGIN_SRC fish
   function mountandroid -d "Mount an Android device"
   #+END_SRC

   We’ll select which Android we want to mount. We will be asked through rofi.
   #+BEGIN_SRC fish
   set chosen (echo $anddrives | rofi -dmenu -i -p "Which Android device?" | awk '{print $1 $2}' | sed 's/,$//')
   #+END_SRC

   Now, we need to  get the bus of the Android device we  want to mount. It will
   be useful  later, after we  authorized mounting from  our device, to  get the
   path to our partition.
   #+BEGIN_SRC fish
   set bus (echo $chosen | sed 's/,.*//')
   #+END_SRC

   Let’s temporarily mount our device.
   #+BEGIN_SRC fish
   jmtpfs -device=$chosen $mp
   #+END_SRC

   Now, we need to allow our computer  to mount our Android device. Depending on
   the Android version it is running on, we either need to specify our device is
   USB connected in order to exchange  files, or Android will explicitely ask us
   if it is OK for our computer to access it. Let’s inform the user of that.
   #+BEGIN_SRC fish
     echo "OK" | \
     rofi -dmenu -i -p "Press (Allow) on your phone screen, or set your USB settings to allow file transfert"
   #+END_SRC

   Now, let’s get the actual path of our Android filesystem we wish to mount,
   and let’s unmount the previous temporary filesystem.
   #+BEGIN_SRC fish
     set newchosen (jmtpfs -l | grep $bus | awk '{print $1 $2}' | sed 's/,$//')
     sudo -A umount $mp
   #+END_SRC

   Now we  cam mount the  new filesystem and  send a notification  if everything
   went well.
   #+BEGIN_SRC fish
     jmtpfs -device=$newchosen $mp && \
     notify-send -a "dmount" "🤖 Android Mounting" "Android device mounted to $mp."
   #+END_SRC

   And now, we can close our function.
   #+BEGIN_SRC fish
   end
   #+END_SRC

** Mount a CD drive
   :PROPERTIES:
   :CUSTOM_ID: h-73ff10ea-10aa-4044-9315-2321fff73c3f
   :END:
   This part  is way  easier than the  previous functions. As  we will  see, the
   function =mountcd='s body is only three  lines long. First, let’s declare the
   function.
   #+BEGIN_SRC fish
   function mountcd
   #+END_SRC

   Now, let’s chose the CD drive we want to mount using =rofi=.
   #+BEGIN_SRC fish
     set chosen (echo $cddrives | rofi -dmenu -i -p "Which CD drive?")
   #+END_SRC

   We’ll also  get the  mountpoint thanks to  the =getmount=  function described
   earlier.
   #+BEGIN_SRC fish
   getmount
   #+END_SRC

   And finally, let’s mount it and send the notification everything went well.
   #+BEGIN_SRC fish
     sudo -A mount $chosen $mp && \
     notify-send -a "dmount" "💿 CD mounting" "$chosen mounted."
   #+END_SRC

   Finally, let’s close our function.
   #+BEGIN_SRC fish
   end
   #+END_SRC

** Ask what type of drive we want to mount
   :PROPERTIES:
   :CUSTOM_ID: h-0bc6ffba-5c45-44e5-a3d3-039a8ea43905
   :END:
   The first thing we will be asked if different types of drives are detected is
   which of these types the user wishes to mount. This is done with the function
   =asktype= which is declared below.
   #+BEGIN_SRC fish
   function asktype
   #+END_SRC

   We will use a  switch statement which will use our anwser  to rofi about what
   we wish to mount.
   #+BEGIN_SRC fish
   switch (cat $TMPDRIVES | rofi -dmenu -i -p "Mount which drive?")
   #+END_SRC

   If we  chose the  option "USB", we’ll  mount a hard  drive, partition  or USB
   drive. In which case we’ll call the =mountusb= function.
   #+BEGIN_SRC fish
     case "USB"
         mountusb
   #+END_SRC

   If we chose the "Android" option, the =mountandroid= function is called.
   #+BEGIN_SRC fish
     case "Android"
         mountandroid
   #+END_SRC

   Else if we chose the "CD" option, we’ll call the =mountcd= function.
   #+BEGIN_SRC fish
     case "CD"
         mountcd
   #+END_SRC
   If nothing  is selected, the function  will naturally exit. Now,  let’s close
   our switch statement and our function.
   #+BEGIN_SRC fish
   end
   end
   #+END_SRC

** Launch the mounting functions
   :PROPERTIES:
   :CUSTOM_ID: h-646dc678-4d87-4fec-8130-5d7d0fc16756
   :END:
   Now that we have declared our functions and set our variables, we’ll read the
   temporary file described  in [[#h-2307005f-385e-4149-b885-55e699c822bb][Get the mountable elements]]. The  amount of lines
   is passed in a switch statement.
   #+BEGIN_SRC fish
   switch (wc -l < $TMPDRIVES)
   #+END_SRC

   If the file has no lines, i.e. it is empty, we have no mountable media. Let’s
   inform our user this is the case.
   #+BEGIN_SRC fish
     case 0
         notify-send "No USB drive or Android device or CD detected" -a "dmount"
   #+END_SRC

   If we  only have one line,  we have only  one type of mountable  media. We’ll
   pass this line to a second switch statement.
   #+BEGIN_SRC fish
     case 1
         switch (cat $TMPDRIVES)
   #+END_SRC
   This will allow the script to automatically  detect what type of media it is,
   and mount the corresponding function.
   #+BEGIN_SRC fish
     case "USB"
         mountusb
     case "Android"
         mountandroid
     case "CD"
         mountCD
   #+END_SRC
   Let’s close this nested switch case.
   #+BEGIN_SRC fish
   end
   #+END_SRC

   If we have more than one line, we’ll have to ask the user what type of media
   they want to mount.
   #+BEGIN_SRC fish
     case '*'
         asktype
   #+END_SRC

   Now, let’s end our switch statement!
   #+BEGIN_SRC fish
   end
   #+END_SRC

   Finally, we’ll delete our temporary file.
   #+BEGIN_SRC fish
   rm -f $TMPDRIVES
   #+END_SRC

   And with that, this is the end of our script!

* Rofi-pass
  :PROPERTIES:
  :HEADER-ARGS: :tangle rofi-pass :exports code
  :CUSTOM_ID: h-a52876ed-351b-400a-b250-d93aab27e0c8
  :END:
  =rofi-pass= is  a simple  utility that  gets a password  stored in  the [[https://www.passwordstore.org/][=pass=]]
  password manager with  rofi as its interface, and then  stores the password in
  the clipboard. It is a fish script, so let’s declare it as one.
  #+BEGIN_SRC fish
  #!/usr/bin/env fish
  #+END_SRC

  Let’s  parse all  the  arguments passed  to  the  script. If  one  of them  is
  =--type=, =-t= or =type=, the script will  attempt to type the password to the
  text area already selected without pasting the password to the clipboard.
  #+BEGIN_SRC fish
    for arg in $argv
        switch $arg
            case '--type'
                set -g TYPE "yes"
            case '-t'
                set -g TYPE "yes"
            case 'type'
                set -g TYPE "yes"
            case '*'
                printf 'Unknown argument: %s\n.' $arg
                exit 1
        end
    end
  #+END_SRC

  Now, let’s get the list of the passwords that exist in our =pass= repository.
  #+BEGIN_SRC fish
    set passwords (find $HOME/.password-store -type f -name "*.gpg" | \
    string replace -r ".*.password-store/" "" | \
    string replace -r ".gpg" "" | sort)
  #+END_SRC

  Let the user choose which password they wish to select.
  #+BEGIN_SRC fish
    set password (for elem in $passwords
        echo $elem
    end | rofi -dmenu -i -p "Select your password")
  #+END_SRC

  Let’s  verify we  actually selected  a  password and  not just  exited. If  no
  password was selected, let’s simply exit the script.
  #+BEGIN_SRC fish
    if test -z $password
        exit
    end
  #+END_SRC

  Depending  on the  arguments  passed  earlier, we  might  want some  different
  behavior.
  #+BEGIN_SRC fish :noweb yes
    if test $TYPE = "yes"
        <<rofi-pass-type>>
    else
        <<rofi-pass-copy>>
    end
  #+END_SRC

  The default behavior is to copy the  password to the clipboard for 45 seconds,
  so let’s do that.
  #+NAME: rofi-pass-copy
  #+BEGIN_SRC fish :noweb yes :tangle no
    pass show -c $password 2> /dev/null
  #+END_SRC

  Else, if we passed  =--type=, =-t= or =type= as an argument  of the script, we
  want it to attempt to type our  password in the currently selected text input.
  Let’s do that.
  #+NAME: rofi-pass-type
  #+BEGIN_SRC fish :noweb yes :tangle no
    set -l IFS
    <<rofi-pass-type-get-password>>
    printf %s $pass | xvkbd -file -
  #+END_SRC

  To correctly  get the password  from =pass=, we need  to parse the  output and
  only get the first line, hence the following command.
  #+NAME: rofi-pass-type-get-password
  #+BEGIN_SRC fish :tangle no
  set pass (pass show $password | string split -n \n)[1]
  #+END_SRC

* Rofi-umount
  :PROPERTIES:
  :CUSTOM_ID: h-68a1f671-5dc6-4120-81c8-c94fffa7d7a3
  :HEADER-ARGS: :tangle rofi-umount :exports code
  :END:
  =rofiumount=  is the  counterpart of  =rofimount= for  unmounting our  mounted
  partitions. It is a fish script, so let’s declare it as that with its shebang.
  #+BEGIN_SRC fish
  #!/usr/bin/env fish
  #+END_SRC

** Get the unmountable drives
   :PROPERTIES:
   :CUSTOM_ID: h-dab41471-4f69-4be8-8d77-58ccc604e4e2
   :END:
   First, we will need to list all the drives that can be safely unmounted.
   Let’s run this.
   #+BEGIN_SRC fish
     set -g drives (lsblk -nrpo "name,type,size,mountpoint" | \
     awk '$2=="part"&&$4!~/\/boot|\/home$|SWAP/&&length($4)>1{printf "%s (%s)\n",$4,$3}')
   #+END_SRC

   Now, let’s get the android devices that are mounted.
   #+BEGIN_SRC fish
   set -g androids (awk '/jmtpfs/ {print $2}' /etc/mtab)
   #+END_SRC

   And let’s get the CD drives that are mounted.
   #+BEGIN_SRC fish
   set -g cds (awk '/sr0/ {print $2}' /etc/mtab)
   #+END_SRC

   We’ll store all of our information in a temporary file, =/tmp/undrives=.
   #+BEGIN_SRC fish
   set -g undrivefile /tmp/undrives
   #+END_SRC

   Let’s make sure we begin with a clean, empty file.
   #+BEGIN_SRC fish
     rm -f $undrivefile
     touch $undrivefile
   #+END_SRC

   Depending on if  the related variables are set, write  the different types of
   mounted drives in the temporary file.
   #+BEGIN_SRC fish
     test -n "$drives" && echo "USB" >> $undrivefile
     test -n "$cds" && echo "CD" >> $undrivefile
     test -n "$androids" && echo "Android" >> $undrivefile
   #+END_SRC

** Unmount disk partitions
   :PROPERTIES:
   :CUSTOM_ID: h-01c37335-5ae8-484f-911a-a08cc4679398
   :END:
   The  function =unmountusb=  will take  care of  unmounting any  drive we  can
   safely unmount. First, let’s declare the function.
   #+BEGIN_SRC fish
   function unmountusb
   #+END_SRC

   Let’s chose the drive to unmount with rofi.
   #+BEGIN_SRC fish
     set chosen (echo $drives | \
     rofi -dmenu -i -p "Unmount which drive?" | \
     awk '{print $1}')
   #+END_SRC

   Let’s verify if the user actually selected  any drive. If no, let’s abort the
   script.
   #+BEGIN_SRC fish
   test -z "$chosen" && exit 0
   #+END_SRC

   Now, let’s unmount  the chosen drive and  send a notification if  it has been
   done.
   #+BEGIN_SRC fish
     sudo -A umount $chosen && \
     notify-send "💻 USB unmounting" "$chosen unmounted." -a "dumount"
   #+END_SRC

   Now, let’s close the function.
   #+BEGIN_SRC fish
   end
   #+END_SRC

** Unmount Android device
   :PROPERTIES:
   :CUSTOM_ID: h-d7d2a12e-c759-4dbe-a17b-bb90c514dca2
   :END:
   The  function  =unmountandroid= will  take  care  of unmounting  any  mounted
   Android device. First, let’s declare our function.
   #+BEGIN_SRC fish
   function unmountandroid
   #+END_SRC

   Let the user choose which Android device to unmount.
   #+BEGIN_SRC fish
   set chosen (echo $androids | rofi -dmenu -i -p "Unmount which device?")
   #+END_SRC

   We’ll verify the user chose any device.
   #+BEGIN_SRC fish
     test -z "$chosen" && exit 0
   #+END_SRC

   If a device has been chosen, let’s  unmount it and send a notification it has
   been successfuly unmounted.
   #+BEGIN_SRC fish
     sudo -A umount -l $chosen && \
     notify-send "🤖 Android unmounting" "$chosen unmounted." -a "dumount"
   #+END_SRC

   Finally, let’s close the function.
   #+BEGIN_SRC fish
   end
   #+END_SRC

** Unmount CD drive
   :PROPERTIES:
   :CUSTOM_ID: h-ae7a8a83-f022-493c-8410-ad99abf42b89
   :END:
   =unmountcd= will take care of unmounting any mounted CD drive. Let’s declare
   this function.
   #+BEGIN_SRC fish
   function unmountcd
   #+END_SRC

   As before, let the user chose which CD drive to unmount.
   #+BEGIN_SRC fish
   set chosen (echo "$cds" | rofi -dmenu -i -p "Unmount which CD?")
   #+END_SRC

   We’ll verify the user chose any device.
   #+BEGIN_SRC fish
     test -z "$chosen" && exit 0
   #+END_SRC

   If a drive has  been chosen, let’s unmount it and send  a notification it has
   been successfuly unmounted.
   #+BEGIN_SRC fish
     sudo -A umount -l $chosen && \
     notify-send "💿 CD unmounting" "$chosen unmounted." -a "dumount"
   #+END_SRC

   Now, let’s close the function.
   #+BEGIN_SRC fish
   end
   #+END_SRC

** Ask what type of drive to unmount
   :PROPERTIES:
   :CUSTOM_ID: h-4320a68b-8369-4ac5-a049-cfb12435e45e
   :END:
   If several  types of  unmountable drives  are available,  let’s ask  the user
   which type to unmount based on the  content of the temporary file declared in
   [[#h-dab41471-4f69-4be8-8d77-58ccc604e4e2][Get the unmountable drives]]. First, let’s declare the function.
   #+BEGIN_SRC fish
   function asktype
   #+END_SRC

   Let’s create a switch statement to which  will be passed the selection of the
   user from rofi.
   #+BEGIN_SRC fish
     switch (cat $undrivefile | rofi -dmenu -i -p "Unmount which type of device?")
   #+END_SRC

   Three types of values can be returned: "USB", "CD", or "Android". These
   values will be used to launch their corresponding function.
   #+BEGIN_SRC fish
     case 'USB'
         unmountusb
     case 'CD'
         unmountcd
     case 'Android'
         unmountandroid
   #+END_SRC

   Let’s close the switch statement.
   #+BEGIN_SRC fish
   end
   #+END_SRC

   Let’s now close the function.
   #+BEGIN_SRC fish
   end
   #+END_SRC

** Launch the unmounting functions
   :PROPERTIES:
   :CUSTOM_ID: h-5880963f-1403-41dc-ae7a-3958e2013fa9
   :END:
   Now back to the  body of our script, let’s input in a  switch case the number
   of lines contained in our temporary file.
   #+BEGIN_SRC fish
   switch (wc -l < $undrivefile)
   #+END_SRC

   If the file containes no lines. i.e. it is empty, nothing is to be unmounted.
   Let’s inform the user of that.
   #+BEGIN_SRC fish
     case 0
         notify-send "No USB drive or Android device or CD to unmount" -a "dumount"
   #+END_SRC

   Else, if there is only one type  of drive, we’ll automatically let our script
   choose based on the content of this sole line.
   #+BEGIN_SRC fish
     case 1
         switch (cat $undrivefile)
             case 'USB'
                 unmountusb
             case 'CD'
                 unmountcd
             case 'Android'
                 unmountandroid
         end
   #+END_SRC

   And if there are more types than one, let’s ask the user.
   #+BEGIN_SRC fish
   case '*'
        asktype
   #+END_SRC

   Let’s close our main switch statement.
   #+BEGIN_SRC fish
   end
   #+END_SRC

   And finally, let’s delete our temporary file.
   #+BEGIN_SRC fish
   rm -f $undrivefile
   #+END_SRC

* Starwars
  :PROPERTIES:
  :CUSTOM_ID: h-127de2b2-d84b-4508-89d2-b4577e8dbece
  :HEADER-ARGS: :tangle starwars :exports code
  :END:
  This is a one-liner that allows you to  watch Star Wars episode 4 in ASCII art
  in your terminal. Here is the code:
  #+BEGIN_SRC fish
    #!/usr/bin/env fish
    telnet towel.blinkenlights.nl
  #+END_SRC

* UpdateFlutter
  :PROPERTIES:
  :header-args: :tangle UpdateFlutter :exports code
  :CUSTOM_ID: h-1005db1f-aecc-4fca-be2d-98fd33c1461a
  :END:

  This is a simple utility to be ran when the ~flutter~ package is updated.
  #+BEGIN_SRC fish
    #!/usr/bin/fish
    sudo chown -R :flutterusers /opt/flutter
    sudo chmod -R g+w /opt/flutter
    sudo chmod a+rw /opt/flutter/version
    sudo chown $USER:(id -g $USER) /opt/flutter/bin/cache
  #+END_SRC

* Wacom setup
  :PROPERTIES:
  :CUSTOM_ID: h-e407ceef-2f14-4474-916b-6b687cf9f2e9
  :HEADER-ARGS: :tangle wacom-setup :exports code
  :END:
  I made a small and quick utility to set up my Wacom tablet so it is only bound
  to one screen. This is a fish script, so let’s insert the sheband.
  #+BEGIN_SRC fish
  #!/usr/bin/env fish
  #+END_SRC

** Set our variables
   :PROPERTIES:
   :CUSTOM_ID: h-c46f0eaf-ae46-4595-8d7a-944bc789cc06
   :END:
   Let’s first declare our function that will be called to set our variables.
   #+BEGIN_SRC fish
   function set_device
   #+END_SRC

   We need some variables in order to correctly set our tablet. First, let’s get
   declare what the name of our tablet is, and what the name of its touchpad is.
   #+BEGIN_SRC fish
     set -g DEVICE "Wacom USB Bamboo PAD Pen stylus"
     set -g DEVICETOUCH "Wacom USB Bamboo PAD Finger touch"
   #+END_SRC

   We will also  modify two settings: the  speed of the cursor  on the touchpad,
   and the scroll speed. Let’s declare the name of these two settings.
   #+BEGIN_SRC fish
     set -g WACOMPROPTOUCHSPEED "Device Accel Velocity Scaling"
     set -g WACOMPROPSCROLLPSEED "ScrollDistance"
   #+END_SRC

   To get the correct values for the area  it can cover, we’ll need to reset our
   tablet.
   #+BEGIN_SRC fish
   xsetwacom set "$DEVICE" ResetArea
   #+END_SRC

   Now we can get the X and Y areas.
   #+BEGIN_SRC fish
     set -l AREATOT (xsetwacom get "$DEVICE" Area)
     set -g AREAX (echo $AREATOT | awk '{print $3}')
     set -g AREAY (echo $AREATOT | awk '{print $4}')
   #+END_SRC

   Now let’s close our function.
   #+BEGIN_SRC fish
   end
   #+END_SRC

** Select our screen
   :PROPERTIES:
   :CUSTOM_ID: h-c81850ec-b2dd-4c57-8570-aca14ca4061b
   :END:
   This function will allow us to select  the screen on which the tablet will be
   active.  We can  also select  the option  “desktop” so  that all  screens are
   selected. Let’s declare our function.
   #+BEGIN_SRC fish
   function set_screen
   #+END_SRC

   First, let’s set what screens are available, including the desktop option.
   #+BEGIN_SRC fish
     set CONNECTED_DISPLAYS (xrandr -q --current | \
     sed -n 's/^\([^ ]\+\) connected .*/\1/p') desktop
   #+END_SRC

   Now, let’s select the one we wish to use using rofi.
   #+BEGIN_SRC fish
     set -g SCREEN (for d in $CONNECTED_DISPLAYS
         echo $d
     end | rofi -dmenu -i -p "Select your dispaly" | tr -d '\n')
   #+END_SRC

   Now, let’s get the resolution of our selected screen.
   #+BEGIN_SRC fish
     set -l LINE (xrandr -q --current | if [ "$SCREEN" = "desktop" ]
         sed -n 's/^Screen 0:.*, current \([0-9]\+\) x \([0-9]\+\),.*/\1 \2/p'
     else
         sed -n "s/^$SCREEN"' connected \(primary \)\{0,1\}\([0-9]\+\)x\([0-9]\+\)+.*/\2 \3/p'
     end)
   #+END_SRC

   From that, let’s get the vertical and horizontal resolution of our screen.
   #+BEGIN_SRC fish
   echo $LINE | read -g WIDTH HEIGHT
   #+END_SRC

   If any of our =WIDTH= ou =HEIGHT= it empty, we’ll have to abort the script.
   #+BEGIN_SRC fish
     if test -z $WIDTH || test -z $HEIGHT
         exit 1
     end
   #+END_SRC

   Let’s close our function now.
   #+BEGIN_SRC fish
   end
   #+END_SRC

** Adjust the tablet
   :PROPERTIES:
   :CUSTOM_ID: h-7e7bcdd1-dce8-43aa-b26e-cc4f38be2a1b
   :END:
   This function  will take care  of adjusting our  tablet to our  screen. Let’s
   declare our function.
   #+BEGIN_SRC fish
   function adjust_device
   #+END_SRC

   If our screen is too high or too  wide for our tablet, we will have to adjust
   the  height or  width  of the  area  used by  the tablet.  So  let’s get  the
   theoretical new height and width of the area.
   #+BEGIN_SRC fish
     set RATIOAREAY (math ceil \($AREAX \* $HEIGHT \/ $WIDTH\))
     set RATIOAREAX (math ceil \($AREAY \* $WIDTH \/ $HEIGHT\))
   #+END_SRC

   Now,  if  the  current height  of  the  tablet’s  area  is greater  than  the
   theoretical new  area, it means the  current area is too  high. Otherwise, it
   should be the other way around. Let’s set =NEWAREAX= and =NEWAREAY= that will
   be used to set the new area for the tablet.

   #+BEGIN_SRC fish
     if test $AREAY -gt $RATIOAREAY
         set -g NEWAREAX $AREAX
         set -g NEWAREAY $RATIOAREAY
     else
         set -g NEWAREAX $RATIOAREAX
         set -g NEWAREAY $AREAY
     end
   #+END_SRC

   Alright, now let’s set the new area with these new variables.
   #+BEGIN_SRC fish
     xsetwacom set "$DEVICE" Area 0 0 $NEWAREAX $NEWAREAY
     xsetwacom set "$DEVICE" MapToOutput "$SCREEN"
   #+END_SRC

   Let’s slow down the cursor’s speed on the touchpad.
   #+BEGIN_SRC fish
   xinput set-float-prop $DEVICETOUCH $WACOMPROPTOUCHSPEED 0.5
   #+END_SRC

   Let’s also slow down the scroll speed of the touchpad.
   #+BEGIN_SRC fish
     xsetwacom set $DEVICETOUCH $WACOMPROPSCROLLPSEED "90"
   #+END_SRC

   Now, let’s close the function.
   #+BEGIN_SRC fish
   end
   #+END_SRC

** Lauch the functions
   :PROPERTIES:
   :CUSTOM_ID: h-e8699018-acf1-42f9-9ce7-4f7bd1a83f9c
   :END:
   Back  to the  main  body of  the  script,  we can  now  launch the  functions
   sequencially.
   #+BEGIN_SRC fish
     set_device
     set_screen
     adjust_device
   #+END_SRC

* Yadm
  :PROPERTIES:
  :CUSTOM_ID: h-9535957b-7559-4244-a5e0-d056c4770fea
  :HEADER-ARGS: :tangle yadm :exports code
  :END:
  For some  reason, =yadm= won’t stop  making polybar crash. So,  I created this
  script  that  will  wrap yadm  with  a  call  to  yadm,  and then  a  call  to
  =polybar-launch= declared  in [[#h-68587918-879b-42db-b304-901d01233f95][Polybar-launch]]. This  is a oneliner, as  you can
  see below:
  #+BEGIN_SRC fish
    #!/usr/bin/env fish
    /usr/bin/yadm $argv; polybar-launch 2>/dev/null >/dev/null
  #+END_SRC