blog.org

   1#+HUGO_BASE_DIR: ./
   2#+HUGO_SECTION: posts
   3#+HUGO_AUTO_SET_LASTMOD: t
   4#+HUGO_FRONT_MATTER_FORMAT: yaml
   5#+ORG-HUGO-EXTERNAL-FILE-EXTENSIONS-ALLOWED-FOR-COPYING: nil
   6
   7* Meta :@Meta:
   8** TODO Focus intentionally
   9:PROPERTIES:
  10:EXPORT_FILE_NAME: focus-intentionally
  11:EXPORT_HUGO_CUSTOM_FRONT_MATTER: :toc true
  12:END:
  13I am too easily distracted. Sitting at my desk on an average day, I have movies,
  14TV shows, and YouTube videos, about a million different chat applications, my
  15email client, Steam, and a web browser with yet more chat apps plus social media
  16all within a couple keystrokes' reach. Along with whatever primary task I've set
  17out to do, I /also/ have a really chaotic brain and about a million other tasks
  18bouncing around in it.
  19
  20Putting all of this together results in terrible productivity and incessant
  21procrastination If my primary task is something I'm less-than-motivated to
  22accomplish.
  23
  24In a recent episode of /The Art of Manliness/, Brett McKay interviews Dr. BJ Fogg
  25about his new book, /Tiny Habits: The Small Changes That Change Everything/. One
  26of Dr. Fogg's statements in this episode stuck with me; when training yourself
  27to adopt new behaviours, there are three things that must factors that determine
  28your success: motivation, ability, and a prompt. A prompt is just something that
  29reminds you of the behaviour you're trying to adopt. The act of brushing your
  30teeth might be the prompt for flossing. The act of flossing might be the prompt
  31for making coffee. In my situation, the prompt is just needing to get work done
  32so we'll ignore that factor. Ability refers to how simple you find the task and
  33motivation is how motivated you are to accomplish it. These last two must
  34balance each other out; if your motivation to complete the task is low, your
  35ability must be high — the task must be easy, while if your ability is low, your
  36motivation must be rather high.
  37
  38*** Notes
  39- Close primary browser with a million tabs open and use Epiphany
  40- Close all the chat apps
  41- Disable notifications/enable Do Not Disturb mode on /both/ your phone /and/
  42  computer
  43- Take off your smart/fitness watch
  44- If you listen to music, make it something calming, not eclectic
  45
  46*** References
  47- [[https://www.artofmanliness.com/character/behavior/monotasking-podcast/][The Art of Manliness: Become a Focused Monotasker]]
  48- [[https://www.artofmanliness.com/character/habits/podcast-581-the-tiny-habits-that-change-everything/][The Art of Manliness: The Tiny Habits That Change Everything]]
  49** TODO Email can be pleasant, but like all good things, it takes work
  50:PROPERTIES:
  51:EXPORT_FILE_NAME: email-can-be-pleasant-but-like-all-good-things-it-takes-work
  52:EXPORT_HUGO_CUSTOM_FRONT_MATTER: :toc true
  53:END:
  54* Technology                                                    :@Technology:
  55** DONE (Ab)using mesh networks for easy remote support :Mesh__networking:Open__source:Remote__support:
  56CLOSED: [2021-11-01 Mon 02:51]
  57:PROPERTIES:
  58:EXPORT_FILE_NAME: abusing-mesh-networks-for-easy-remote-support
  59:EXPORT_HUGO_CUSTOM_FRONT_MATTER: :toc true
  60:END:
  61One of the things many of us struggle with when setting friends and
  62family up with Linux is remote support. Commercial solutions like
  63[[https://www.realvnc.com/][RealVNC]] and [[https://rustdesk.com/][RustDesk]] do exist and function very well, but are often more
  64expensive than we would like for answering the odd "I can't get Facebook
  65open!" support call. I've been on the lookout for suitable alternatives
  66for a couple years but nothing has been satisfying. Because of this, I
  67have held off on setting others up with any Linux distribution, even the
  68particularly user-friendly options such as [[https://linuxmint.com/][Linux Mint]] and [[https://elementary.io/][elementary OS;]]
  69if I'm going drop someone in an unfamiliar environment, I want to be
  70able to help with any issue within a couple hours, not days and
  71/certainly/ not weeks.
  72
  73[[https://linuxunplugged.com/421][Episode 421 of LINUX Unplugged]] gave me an awesome idea to use [[https://github.com/slackhq/nebula][Nebula,]] a
  74networking tool created by Slack, [[https://libvnc.github.io/][X11vnc,]] a very minimal VNC server, and
  75[[https://remmina.org/][Remmina,]] a libre remote access tool available in pretty much every Linux
  76distribution, to set up a scalable, secure, and simple setup reminiscent
  77of products like RealVNC.
  78
  79*** Nebula
  80The first part of our stack is Nebula, the tool that creates a network
  81between all of our devices. With traditional VPNs, you have a client
  82with a persistent connection to a central VPN server and other clients
  83can communicate with the first by going through that central server.
  84This works wonderfully in most situations, but there are a lot of
  85latency and bandwidth restrictions that would make remote support an
  86unpleasant experience. Instead of this model, what we want is a /mesh/
  87network, where each client can connect directly to one another /without/
  88going through a central system and slowing things down. This is where
  89Nebula comes in.
  90
  91In Nebula's terminology, clients are referred to as /nodes/ and central
  92servers are referred to as /lighthouses/, so those are the terms I'll use
  93going forward.
  94
  95Mesh networks are usually only possible when dealing with devices that
  96have static IP addresses. Each node has to know /how/ to connect with the
  97other nodes; John can't meet up with Bob when Bob moves every other day
  98without notifying anyone of his new address. This wouldn't be a problem
  99if Bob phoned Jill and told her where he was moving; John would call
 100Jill, Jill would tell him where Bob is, and the two would be able to
 101find each other
 102
 103With Nebula, nodes are Bob and John and Jill is a lighthouse. Each node
 104connects to a lighthouse and the lighthouse tells the nodes how to
 105connect with one another when they ask. It /facilitates/ the P2P
 106connection then /backs out of the way/ so the two nodes can communicate
 107directly with each other.
 108
 109It allows any node to connect with any other node on any network from
 110anywhere in the world, as long as one lighthouse is accessible that
 111knows the connection details for both peers.
 112
 113**** Getting started
 114The /best/ resource is [[https://github.com/slackhq/nebula][the official documentation,]] but I'll describe the
 115process here as well.
 116
 117After [[https://github.com/slackhq/nebula#1-the-nebula-binaries-or-distribution-packages-for-your-specific-platform-specifically-youll-need-nebula-cert-and-the-specific-nebula-binary-for-each-platform-you-use][installing the required packages,]] make sure you have a VPS with a
 118static IP address to use as a lighthouse. If you want something dirt
 119cheap, I would recommend one of the small plans from [[https://buyvm.net][BuyVM.]] I do have a
 120[[https://my.frantech.ca/aff.php?aff=3783][referral link]] if you want them to kick me a few dollars for your
 121purchase. [[https://www.hetzner.com/cloud][Hetzner]] (referral: ~ckGrk4J45WdN~) or [[https://www.netcup.eu/][netcup]] (referral:
 122~36nc15758387844~) would also be very good options; I've used them all and
 123am very comfortable recommending them.
 124
 125**** Creating a Certificate Authority
 126After picking a device with a static IP address, it needs to be set up
 127as a lighthouse. This is done by first creating a Certificate Authority
 128(CA) that will be used for signing keys and certificates that allow our
 129other devices into the network. The ~.key~ file produced by the following
 130command is incredibly sensitive; with it, anyone can authorise a new
 131device and give it access to your network. Store it in a safe,
 132preferably encrypted location.
 133
 134#+BEGIN_SRC bash
 135  nebula-cert ca -name "nebula.example.com"
 136#+END_SRC
 137
 138I'll explain why we used a Fully-Qualified Domain Name (FQDN) as the
 139CA's name in a later section. If you have your own domain, feel free to
 140use that instead; it doesn't really matter what domain is used as long
 141as the format is valid.
 142
 143**** Generating lighthouse credentials
 144Now that we have the CA's ~.crt~ and ~.key~ files, we can create and sign
 145keys and certificates for the lighthouse.
 146
 147#+BEGIN_SRC bash
 148  nebula-cert sign -name "buyvm.lh.nebula.example.com" -ip "192.168.100.1/24"
 149#+END_SRC
 150
 151Here, we're using a FQDN for the same reason as we did in the CA. You
 152can use whatever naming scheme you like, I just prefer
 153~<vps-host>.lh.nebula...~ for my lighthouses. The IP address can be on any
 154of the following private IP ranges, I just happened to use ~192.168.100.X~
 155for my network.
 156
 157| IP Range                      | Number of addresses |
 158|-------------------------------+---------------------|
 159| 10.0.0.0 – 10.255.255.255     | 16 777 216          |
 160| 172.16.0.0 – 172.31.255.255   | 10 48 576           |
 161| 192.168.0.0 – 192.168.255.255 | 65 536              |
 162
 163**** Creating a config file
 164The next step is creating our lighthouse's config file. The reference
 165config can be found in [[https://github.com/slackhq/nebula/blob/master/examples/config.yml][Nebula's repo.]] We only need to change a few of
 166the lines for the lighthouse to work properly. If I don't mention a
 167specific section here, I've left the default values.
 168
 169The section below is where we'll define certificates and keys. ~ca.crt~
 170will remain ~ca.crt~ when we copy it over but I like to leave the node's
 171cert and key files named as they were when generated; this makes it easy
 172to identify nodes by their configs. Once we copy everything over to the
 173server, we'll add the proper paths to the ~cert~ and ~key~ fields.
 174
 175#+BEGIN_SRC yaml
 176  pki:
 177    ca: /etc/nebula/ca.crt
 178    cert: /etc/nebula/
 179    key: /etc/nebula/
 180#+END_SRC
 181
 182The next section is for identifying and mapping your lighthouses. This
 183needs to be present in /all/ of the configs on /all/ nodes, otherwise they
 184won't know how to reach the lighthouses and will never actually join the
 185network. Make sure you replace ~XX.XX.XX.XX~ with whatever your VPS's
 186public IP address is. If you've used a different private network range,
 187those changes need to be reflected here as well.
 188
 189#+BEGIN_SRC yaml
 190  static_host_map:
 191    "192.168.100.1": ["XX.XX.XX.XX:4242"]
 192#+END_SRC
 193
 194Below, we're specifying how the node should behave. It is a lighthouse,
 195it should answer DNS requests, the DNS server should listen on all
 196interfaces on port 53, it sends its IP address to lighthouses every 60
 197seconds (this option doesn't actually have any effect when ~am_lighthouse~
 198is set to ~true~ though), and this lighthouse should not send reports to
 199other lighthouses. The bit about DNS will be discussed later.
 200
 201#+BEGIN_SRC yaml
 202  lighthouse:
 203    am_lighthouse: true
 204    serve_dns: true
 205    dns:
 206      host: 0.0.0.0
 207      port: 53
 208    interval: 60
 209    hosts:
 210#+END_SRC
 211
 212The next bit is about [[https://en.wikipedia.org/wiki/Hole_punching_%28networking%29][hole punching]], also called /NAT punching/, /NAT
 213busting/, and a few other variations. Make sure you read the comments for
 214better explanations than I'll give here. ~punch: true~ enables hole
 215punching. I also like to enable ~respond~ just in case nodes are on
 216particularly troublesome networks; because we're using this as a support
 217system, we have no idea what networks our nodes will actually be
 218connected to. We want to make sure devices are available no matter where
 219they are.
 220
 221#+BEGIN_SRC yaml
 222  punchy:
 223    punch: true
 224    respond: true
 225    delay: 1s
 226#+END_SRC
 227
 228~cipher~ is a big one. The value /must/ be identical on /all/ nodes /and/
 229lighthouses. ~chachapoly~ is more compatible so it's used by default. The
 230devices /I/ want to connect to are all x86 Linux, so I can switch to ~aes~
 231and benefit from [[https://www.reddit.com/r/networking/comments/iksyuu/comment/g3ra5cv/?utm_source=share&utm_medium=web2x&context=3][a small performance boost.]] Unless you know /for sure/
 232that you won't need to work with /anything/ else, I recommend leaving it
 233set to ~chachapoly~.
 234
 235#+BEGIN_SRC yaml
 236  cipher: chachapoly
 237#+END_SRC
 238
 239The last bit I modify is the firewall section. I leave most everything
 240default but /remove/ the bits after ~port: 443~. I don't /need/ the ~laptop~ and
 241~home~ groups (groups will be explained later) to access port ~443~ on this
 242node, so I shouldn't include the statement. If you have different needs,
 243take a look at the comment explaining how the firewall portion works and
 244make those changes.
 245
 246Again, I /remove/ the following bit from the config.
 247
 248#+BEGIN_SRC yaml
 249    - port: 443
 250      proto: tcp
 251      groups:
 252        - laptop
 253        - home
 254#+END_SRC
 255
 256**** Setting the lighthouse up
 257We've got the config, the certificates, and the keys. Now we're ready to
 258actually set it up. After SSHing into the server, grab the [[https://github.com/slackhq/nebula/releases/latest][latest
 259release of Nebula for your platform,]] unpack it, make the ~nebula~ binary
 260executable, then move it to ~/usr/local/bin~ (or some other location
 261fitting for your platform).
 262
 263#+BEGIN_SRC bash
 264  wget https://github.com/slackhq/nebula/releases/download/vX.X.X/nebula-PLATFORM-ARCH.tar.gz
 265  tar -xvf nebula-*
 266  chmod +x nebula
 267  mv nebula /usr/local/bin/
 268  rm nebula-*
 269#+END_SRC
 270
 271Now we need a place to store our config file, keys, and certificates.
 272
 273#+BEGIN_SRC bash
 274  mkdir /etc/nebula/
 275#+END_SRC
 276
 277The next step is copying the config, keys, and certificates to the
 278server. I use ~rsync~ but you can use whatever you're comfortable with.
 279The following four files need to be uploaded to the server.
 280
 281- ~config.yml~
 282- ~ca.crt~
 283- ~buyvm.lh.nebula.example.com.crt~
 284- ~buyvm.lh.nebula.example.com.key~
 285
 286With ~rsync~, that would look something like this. Make sure ~rsync~ is also
 287installed on the VPS before attempting to run the commands though;
 288you'll get an error otherwise.
 289
 290#+BEGIN_SRC bash
 291  rsync -avmzz ca.crt user@example.com:
 292  rsync -avmzz config.yml user@example.com:
 293  rsync -avmzz buyvm.lh.* user@example.com:
 294#+END_SRC
 295
 296SSH back into the server and move everything to ~/etc/nebula/~.
 297
 298#+BEGIN_SRC bash
 299  mv ca.crt /etc/nebula/
 300  mv config.yml /etc/nebula/
 301  mv buyvm.lh* /etc/nebula/
 302#+END_SRC
 303
 304Edit the config file and ensure the ~pki:~ section looks something like
 305this, modified to match your hostnames of course.
 306
 307#+BEGIN_SRC yaml
 308  pki:
 309    ca: /etc/nebula/ca.crt
 310    cert: /etc/nebula/buyvm.lh.nebula.example.com.crt
 311    key: /etc/nebula/buyvm.lh.nebula.example.com.key
 312#+END_SRC
 313
 314Run the following command to make sure everything works properly.
 315
 316#+BEGIN_SRC bash
 317  nebula -config /etc/nebula/config.yml
 318#+END_SRC
 319
 320The last step is daemonizing Nebula so it runs every time the server
 321boots. If you're on a machine using systemd, dropping the following
 322snippet into ~/etc/systemd/system/nebula.service~ should be sufficient. If
 323you're using something else, check the [[https://github.com/slackhq/nebula/tree/master/examples/][the examples directory]] for more
 324options.
 325
 326#+BEGIN_SRC text
 327  [Unit]
 328  Description=nebula
 329  Wants=basic.target
 330  After=basic.target network.target
 331  Before=sshd.service
 332
 333  [Service]
 334  SyslogIdentifier=nebula
 335  ExecReload=/bin/kill -HUP $MAINPID
 336  ExecStart=/usr/local/bin/nebula -config /etc/nebula/config.yml
 337  Restart=always
 338
 339  [Install]
 340  WantedBy=multi-user.target
 341#+END_SRC
 342
 343We're almost done!
 344
 345**** Setting individual nodes up
 346This process is almost exactly the same as setting lighthouses up. All
 347you'll need to do is generate a couple of certs and keys then tweak the
 348configs a bit.
 349
 350The following command creates a new cert/key for USER's node with the IP
 351address ~192.168.100.2~. The resulting files would go on the /remote/ node
 352not yours. Replace ~HOST~ and ~USER~ with fitting values.
 353
 354#+BEGIN_SRC bash
 355  nebula-cert sign -name "HOST.USER.nebula.example.com" -ip "192.168.100.2/24"
 356#+END_SRC
 357
 358The following command will create a /similar/ cert/key but it will be part
 359of the ~support~ group. The files resulting from this should go on /your/
 360nodes. With the config we'll create next, nodes in the ~support~ group
 361will be able to VNC and SSH into other nodes. Your nodes need to be in
 362the ~support~ group so you'll have access to the others.
 363
 364#+BEGIN_SRC bash
 365  nebula-cert sign -name "HOST.USER.nebula.example.com" -ip "192.168.100.2/24" -groups "support"
 366#+END_SRC
 367
 368On to the config now. This tells the node that it is /not/ a lighthouse,
 369it should /not/ resolve DNS requests, it /should/ ping the lighthouses and
 370tell them its IP address every 60 seconds, and the node at ~192.168.100.1~
 371is one of the lighthouses it should report to and query from. If you
 372have more than one lighthouse, add them to the list as well.
 373
 374#+BEGIN_SRC yaml
 375  lighthouse:
 376    am_lighthouse: false
 377    #serve_dns: false
 378    #dns:
 379      #host: 0.0.0.0
 380      #port: 53
 381    interval: 60
 382    hosts:
 383      - "192.168.100.1"
 384#+END_SRC
 385
 386The other bit that should be modified is the ~firewall:~ section and this
 387is where the groups we created earlier are important. Review its
 388comments and make sure you understand how it works before proceeding.
 389
 390We want to allow inbound connections on ports 5900, the standard port
 391for VNC, and 22, the standard for SSH. Additionally, we /only/ want to
 392allow connections from nodes in the ~support~ group. Any /other/ nodes
 393should be denied access.
 394
 395Note that including this section is not necessary on /your/ nodes, those
 396in the ~support~ group. It's only necessary on the remote nodes that
 397you'll be connecting to. As long as the ~outbound:~ section in the config
 398on /your/ node allows any outbound connection, you'll be able to access
 399other nodes.
 400
 401#+BEGIN_SRC yaml
 402    - port: 5900
 403      proto: tcp
 404      groups:
 405      - support
 406
 407    - port: 22
 408      proto: tcp
 409      groups:
 410      - support
 411#+END_SRC
 412
 413The certs, key, config, binary, and systemd service should all be copied
 414to the same places on all of these nodes as on the lighthouse.
 415
 416*** X11vnc
 417/Alright./ The hardest part is finished. Now on to setting ~x11vnc~ up on
 418the nodes you'll be supporting.
 419
 420All you should need to do is install ~x11vnc~ using the package manager
 421your distro ships with, generate a 20 character password with ~pwgen -s
 42220 1~, run the following command, paste the password, wait for ~x11vnc~ to
 423start up, make sure it's running correctly, press ~Ctrl~ + ~C~, then add the
 424command to the DE's startup applications!
 425
 426#+BEGIN_SRC bash
 427  x11vnc --loop -usepw -listen <nebula-ip> -display :0
 428#+END_SRC
 429
 430~--loop~ tells ~x11vnc~ to restart once you disconnect from the session.
 431~-usepw~ is pretty self-explanatory. ~-listen <nebula-ip>~ is important; it
 432tells ~x11vnc~ to only listen on the node's Nebula IP address. This
 433prevents randos in a coffee shop from seeing an open VNC port and trying
 434to brute-force the credentials. ~-display :0~ just defines which X11
 435server display to connect to.
 436
 437Some distributions like elementaryOS and those that use KDE and GNOME
 438will surface a dialogue for managing startup applications if you just
 439press the Windows (Super) key and type ~startup~. If that doesn't work,
 440you'll have to root around in the settings menus, consult the
 441distribution's documentation, or ask someone else that might know.
 442
 443After adding it to the startup application, log out and back in to make
 444sure it's running in the background.
 445
 446*** Remmina
 447Now that our network is functioning properly and the VNC server is set
 448up, we need something that connects to the VNC server over the fancy
 449mesh network. Enter [[https://remmina.org/][Remmina.]] This one goes on /your/ nodes.
 450
 451Remmina is a multi-protocol remote access tool available in pretty much
 452ever distribution's package archive as ~remmina~. Install it, launch it,
 453add a new connection profile in the top left, give the profile a
 454friendly name (I like to use the name of the person I'll be supporting),
 455assign it to a group, such as ~Family~ or ~Friends~, set the Protocol to
 456~Remmina VNC Plugin~, enter the node's Nebula IP address in the Server
 457field, then enter their username and the 20 character password you
 458generated earlier. I recommend setting the quality to Poor, but Nebula
 459is generally performant enough that any of the options are suitable. I
 460just don't want to have to disconnect and reconnect with a lower quality
 461if the other person happens to be on a slow network.
 462
 463Save and test the connection!
 464
 465If all goes well and you see the other device's desktop, you're done
 466with the VNC section! Now on to SSH.
 467
 468*** SSH
 469First off, make sure ~openssh-server~ is installed on the remote node;
 470~openssh-client~ would also be good to have, but from what I can tell,
 471it's not strictly necessary. You /will/ need ~openssh-client~ on /your/ node,
 472however. If you already have an SSH key, copy it over to
 473~~/.ssh/authorized_keys~ on the remote node. If you don't, generate one
 474with ~ssh-keygen -t ed25519~. This will create an Ed25519 SSH key pair.
 475Ed25519 keys are shorter and faster than RSA and more secure than ECDSA
 476or DSA. If that means nothing to you, don't worry about it. Just note
 477than this key might not interact well with older SSH servers; you'll
 478know if you need to stick with the default RSA. Otherwise, Ed25519 is
 479the better option. After key generation has finished, copy
 480~~/.ssh/id_ed25519.pub~ (note the ~.pub~ extension) from your node to
 481~~/.ssh/authorized_keys~ on the remote node. The file /without/ ~.pub~ is your
 482/private/ key. Like the Nebula CA certificate we generated earlier, this
 483is extremely sensitive and should never be shared with anyone else.
 484
 485Next is configuring SSH to only listen on Nebula's interface; as with
 486~x11vnc~, this prevents randos in a coffee shop from seeing an open SSH
 487port and trying to brute-force their way in. Set the ~ListenAddress~
 488option in ~/etc/ssh/sshd_config~ to the remote node's Nebula IP address.
 489If you want to take security a step further, search for
 490~PasswordAuthentication~ and set it to ~no~. This means your SSH key is
 491/required/ for gaining access via SSH. If you mess up Nebula's firewall
 492rules and accidentally give other Nebula devices access to this machine,
 493they still won't be able to get in unless they have your SSH key. I
 494/personally/ recommend disabling password authentication, but it's not
 495absolutely necessary. After making these changes, run ~systemctl restart
 496sshd~ to apply them.
 497
 498Now that the SSH server is listening on Nebula's interface, it will
 499actually fail to start when the machine (re)boots. The SSH server starts
 500faster than Nebula does, so it will look for the interface before Nebula
 501has even had a chance to connect. We need to make sure systemd waits for
 502Nebula to start up and connect before it tells SSH to start; run
 503~systemctl edit --full sshd~ and add the following line in the ~[Unit]~
 504section, above ~[Service]~.
 505
 506#+BEGIN_SRC text
 507  After=nebula.service
 508#+END_SRC
 509
 510Even now, there's still a bit of a hiccup. Systemd won't start SSH until
 511Nebula is up and running, which is good. Unfortunately, even after
 512Nebula has started, it still takes a minute to bring the interface up,
 513causing SSH to crash. To fix /this/, add the following line directly below
 514~[Service]~.
 515
 516#+BEGIN_SRC text
 517  ExecStartPre=/usr/bin/sleep 30
 518#+END_SRC
 519
 520If the ~sleep~ executable is stored in a different location, make sure you
 521use that path instead. You can check by running ~which sleep~.
 522
 523When the SSH /service/ starts up, it will now wait an additional 30
 524seconds before actually starting the SSH /daemon/. It's a bit of a hacky
 525solution but it works™. If you come up with something better, please
 526send it to me and I'll include it in the post! My contact information is
 527at the bottom of [[/][this site's home page.]]
 528
 529After you've made these changes, run ~systemctl daemon-reload~ to make
 530sure systemd picks up on the modified service file, then run ~systemctl
 531restart sshd~. You should be able to connect to the remote node from your
 532node using the following command.
 533
 534#+BEGIN_SRC bash
 535  ssh USER@<nebula-ip>
 536#+END_SRC
 537
 538If you want to make the command a little simpler so you don't have to
 539remember the IP every time, create ~~/.ssh/config~ on your node and add
 540these lines to it.
 541
 542#+BEGIN_SRC text
 543  Host USER
 544    Hostname <nebula-ip>
 545    User USER
 546#+END_SRC
 547
 548Now you can just run ~ssh USER~ to get in. If you duplicate the above
 549block for all of the remote nodes you need to support, you'll only have
 550to remember the person's username to SSH into their machine.
 551
 552*** Going further with Nebula
 553This section explains why we used FQDNs in the certs and why the DNS
 554resolver is enabled on the lighthouse.
 555
 556Nebula ships with a built-in resolver meant specifically for mapping
 557Nebula node hostnames to their Nebula IP addresses. Running a public DNS
 558resolver is very much discouraged because it can be abused in terrible
 559ways. However, the Nebula resolver mitigates this risk because it /only/
 560answers queries for Nebula nodes. It doesn't forward requests to any
 561other servers nor does it attempt to resolve any domain other than what
 562was defined in its certificate. If you use the example I gave above,
 563that would be ~nebula.example.com~; the lighthouse will attempt to resolve
 564any subdomain of ~nebula.example.com~ but it will just ignore ~example.com~,
 565~nebula.duckduckgo.com~, ~live.secluded.site~, etc.
 566
 567Taking advantage of this resolver requires setting it as your secondary
 568resolver on any device you want to be able to resolve hostnames from.
 569If you were to add the lighthouse's IP address as your secondary
 570resolver on your PC, you could enter ~host.user.nebula.example.com~ in
 571Remmina's server settings /instead of/ ~192.168.1.2~.
 572
 573But how you do so is beyond the scope of this post!
 574
 575If you're up for some /more/ shenanigans later on down the line, you could
 576set up a Pi-Hole instance backed by Unbound and configure Nebula as
 577Unbound's secondary resolver. With this setup, you'd get DNS-level ad
 578blocking /and/ the ability to resolve Nebula hostname. Pi-Hole would query
 579Unbound for ~host.user.nebula.example.com~, Unbound would receive no
 580answer from the root servers because the domain doesn't exist outside of
 581your VPN, Unbound would fall back to Nebula, Nebula would give it an
 582answer, Unbound would cache the answer, tell Pi-Hole, Pi-Hole would
 583cache the answer, tell your device, then your device would cache the
 584answer, and you can now resolve any Nebula host!
 585
 586Exactly how you do /that/ is */definitely/* beyond the scope of this post :P
 587
 588If you set any of this up, I would be interested to hear how it goes! As
 589stated earlier, my contact information is at the bottom of the site's
 590home page :)
 591** TODO FreeBSD quirks on the Framework laptop :FreeBSD:Framework:
 592:PROPERTIES:
 593:EXPORT_FILE_NAME: freebsd-quirks-on-the-framework-laptop
 594:EXPORT_HUGO_CUSTOM_FRONT_MATTER: :toc true
 595:END:
 596This is primarily intended for people new to FreeBSD. If you're already familiar
 597with it, [[https://wiki.freebsd.org/Laptops/Framework_Laptop][the wiki page]] will probably tell you everything you need. I had no idea
 598what I was doing so I had no idea what I was looking for! I had been beating my
 599head against a wall for about three hours before I decided to join ~#freebsd~ on
 600[[https://libera.chat/][Libera.Chat]]; the people there were friendly, helpful, and gave me tons of great
 601advice. I highly recommend popping in if you have any issues!
 602
 603*** The Handbook
 604Open [[https://docs.freebsd.org/en/books/handbook/][the handbook.]] Follow [[https://docs.freebsd.org/en/books/handbook/][the handbook.]] Read [[https://docs.freebsd.org/en/books/handbook/][the whole handbook.]] The developers
 605spend a /lot/ of time making sure it's the best resource available for learning
 606FreeBSD. In most cases, it will have an answer for any question related to
 607FreeBSD.
 608
 609That said, the Framework laptop is so new that it's not fully supported by the
 610current stable release, so for now, we'll need to diverge a bit. This guide is
 611really only applicable until the release of FreeBSD 13.1 and until ~drm-kmod~ hits
 612version 5.5+. Once those two criteria are met, following the handbook should be
 613entirely sufficient!
 614
 615*** The Source
 616In section 2.5.3 of the handbook/installer, make sure you tick the ~src~ box to
 617download the FreeBSD source code. It'll be necessary for building our graphics
 618drivers later on.
 619
 620*** The Graphics
 621This is where things are less-than-ideal at the moment. /Usually/, installing
 622[[https://cgit.freebsd.org/ports/tree/graphics/drm-kmod][graphics/drm-kmod]] would be sufficient, but the version in both FreeBSD's package
 623repos and in the ports tree is too old. At the time of writing, it's compatible
 624with Linux kernel 5.4 while the Framework's drivers are in Linux kernel 5.5+.
 625We'll need to clone the /sources/ for ~graphics/drm-kmod~, check out a more recent
 626branch, build the drivers, and use those instead.
 627
 628I'm not 100% certain whether the first step here is necessary but I don't feel
 629like reinstalling to check.
 630
 6311. Install ~graphics/drm-kmod~ with ~pkg install drm-kmod~
 6322. Install ~devel/git~ with ~pkg install git~
 6333. Clone ~drm-kmod~'s source with
 634   #+BEGIN_SRC bash
 635git clone https://github.com/freebsd/drm-kmod
 636   #+END_SRC
 6374. Check out the ~5.7-stable~ branch with
 638   #+BEGIN_SRC bash
 639git checkout -b 5.7-stable --track remotes/origin/5.7-stable
 640   #+END_SRC
 6415. Build the package with ~make~
 6426. Uninstall ~drm-kmod~ and all of its dependencies with ~pkg remove drm-kmod~
 643   followed by ~pkg autoremove~
 6447. Install the more up-to-date drivers with ~make install~
 6458. Make sure the module works as expected with ~kldload /boot/modules/i915kms.ko~
 6469. If you suddenly see grey in your terminal, it works! Go ahead and add it to
 647   your boot config by appending the following line to ~/etc/rc.conf~
 648  #+BEGIN_SRC text
 649kld_load="/boot/modules/i915kms.ko"
 650  #+END_SRC
 65110. Reboot and you should be able to start Xorg as the handbook describes!
 652
 653Again all of this information is available on [[https://wiki.freebsd.org/Laptops/Framework_Laptop][the FreeBSD wiki page for the
 654Framework laptop.]] The ~Graphics~ row in section 2 says /requires DRM-KMOD 5.5 or
 655higher. Fails to initialize with DRM-KMOD 5.4./ That's in reference to the
 656package we just built and installed.
 657
 658Hope this helps!
 659
 660** TODO A perfect email setup (for me) :Email:Workflow:
 661:PROPERTIES:
 662:EXPORT_FILE_NAME: a-perfect-email-setup-for-me
 663:EXPORT_HUGO_CUSTOM_FRONT_MATTER: :toc true
 664:END:
 665
 666I've never been satisfied with any of the email clients most people use.
 667I've tried [[https://www.thunderbird.net/en-GB/][Thunderbird,]] [[https://wiki.gnome.org/Apps/Evolution][Evolution,]] [[https://getmailspring.com/][Mailspring,]] [[https://support.apple.com/mail][Mail.app,]] [[https://roundcube.net/][Roundcube,]]
 668[[https://sogo.nu/][SOGo,]] [[https://wiki.gnome.org/Apps/Geary][Geary,]] and /many/ more. /None/ of them handle multiple accounts
 669particularly well because all of the emails associated with that account
 670are bound within it. Sure, you can make a new folder somewhere called
 671~TODO~ and move all of your actionable emails to that folder but, when you
 672go to move actionable emails from /another/ account into that folder,
 673you'll likely find that the client simply doesn't let you. If it does,
 674when you reply, it will likely be sent from the wrong account. This is a
 675limitation of the IMAP protocol; everything is /managed/ locally but
 676changes are pushed to the remote server and mixing things the way I want
 677leads to broken setups.
 678
 679Before I go any further, these are a few characteristics of my ideal
 680email tool.
 681
 682- Support for multiple accounts (obviously)
 683- /Native desktop application/ (*not* [[https://github.com/electron/electron][Electron]])
 684- Has stellar keyboard shortcuts
 685- Doesn't require internet connectivity (other than downloading and
 686  sending of course)
 687- Organisation can be done with tags
 688
 689*** Why tags?
 690Because they're better. Hierarchies are useful for prose and code but
 691not for files, emails, notes, or anything where an item may fit within
 692multiple categories. Imagine you get an email from your Computer Science
 693professor that includes test dates, homework, and information about
 694another assignment. In that same email, he asks every student to reply
 695with something they learned from the previous class as a form of
 696attendance. In a hierarchy, the best place for this might just be a ~TODO~
 697folder /even though/ it would also fit under ~School~, ~CS~, ~Dates~, ~To read~,
 698and ~Homework~. Maybe you have a few minutes and want to clear out some
 699emails that don't require any interaction. In a tag-based workflow, this
 700would be a good time to open ~To read~, get that email out of the way, and
 701remove the ~To read~ tag. It would still show up under the other tags so
 702you can find it later and take the time to fully answer the professor's
 703question, add those dates to your calendar, and add the homework
 704assignments to your ~TODO~ list. Hierarchies can be quite cumbersome to
 705work with, especially when one folder ends up getting all the data. Tags
 706ensure that you only see what you want when you want it. Tags are more
 707efficient and they will remain my organisation system of choice.
 708
 709*** The tools
 710In short, the tools we will be using are...
 711+ [[https://isync.sourceforge.io/mbsync.html][~mbsync~]] to download our emails
 712+ [[https://notmuchmail.org/][~notmuch~,]] the primary way emails will be organised
 713+ [[https://afew.readthedocs.io/en/latest/][~afew~]] to apply initial ~notmuch~ tags based on subject, sender, recipient, etc.
 714+ [[https://neomutt.org/][NeoMutt]] to interact with those emails, reply, compose, add/remove
 715  tags, etc.
 716+ [[https://marlam.de/msmtp/][~msmtp~]] for relaying our replies and compositions to our mail provider
 717
 718Yes, it's a lot. Yes, it's time-consuming to set up. Yes, it's worth it
 719(in my opinion).
 720
 721*** ~mbsync~
 722As I said above, IMAP is limiting; we need to use some other method of
 723downloading our emails. There's an awesome piece of software called
 724[[https://isync.sourceforge.io/mbsync.html][mbsync]] which is built for exactly this purpose. Its configuration
 725can be rather daunting if you have as many accounts as I do (19) but
 726it's not /terrible/.
 727
 728The following sections are named *Near*, *Far*, and *Sync*. Near and Far are
 729terms mbsync uses to profile /how/ your emails are stored, /where/ they're
 730stored, and how to interact with them. In this guide, Far will our mail
 731provider's IMAP server and Near will be our local Maildir.
 732
 733**** Far
 734#+BEGIN_SRC text
 735IMAPAccount amo_ema
 736Host imap.nixnet.email
 737CertificateFile /etc/ssl/certs/ca-certificates.crt
 738SSLType STARTTLS
 739User amolith@nixnet.email
 740PassCmd "secret-tool lookup Title amolith@nixnet.email"
 741
 742IMAPStore amo_ema-remote
 743Account amo_ema
 744#+END_SRC
 745
 746**** Near
 747#+BEGIN_SRC text
 748MaildirStore amo_ema-local
 749SubFolders Verbatim
 750Path ~/new-mail/amo_ema/
 751Inbox ~/new-mail/amo_ema/INBOX/
 752#+END_SRC
 753
 754In the first block, ~localrepository~ and ~remoterepository~ tell OfflineIMAP where
 755to look for your emails. ~use_exa-local~ is an arbitrary naming scheme I use to
 756differentiate between the various local and remote accounts. It can easily be
 757swapped with something else.
 758
 759**** Sync
 760#+BEGIN_SRC text
 761Channel amo_ema
 762Far :amo_ema-remote:
 763Near :amo_ema-local:
 764SyncState *
 765Patterns *
 766Create Both
 767#+END_SRC
 768
 769The repository sections describe how the emails are stored or retrieved.
 770In the ~local~ block, you'll notice that the type is ~Maildir~. In this
 771format, each email is given a unique filename and stored in a hierarchy
 772of folders within your account. This is often how your emails are stored
 773on your provider's mail server.
 774
 775~pythonfile~ is used here to authenticate with the remote server. This can
 776be complicated and depends /entirely/ on how you manage your passwords. I
 777use [[https://keepassxc.org/][KeePassXC]] and love it. When I set OfflineIMAP up, however, it didn't
 778have ~libsecret~ compatibility. This would have made setup significantly
 779easier but, as it already just works™, I don't really see a reason to
 780change it.
 781
 782This new feature allows ~libresecret~-based applications to query
 783KeePassXC for your passwords or store them there on your behalf. CLI/TUI
 784applications that need a secure mechanism for background authentication
 785can use ~secret-tool lookup Title "TITLE_OF_PASSWORD"~ as the password
 786command. See [[https://github.com/keepassxreboot/keepassxc/pull/2726][the pull request]] for more details. Because this wasn't a
 787feature when I first set it up, I put my passwords in plaintext files
 788and encrypted them with the GPG key stored on my YubiKey. As long as my
 789key is plugged in, OfflineIMAP can authenticate and download all my
 790emails just fine. The process for using a GPG key /not/ stored on a
 791hardware token is pretty much the same and I'll talk about that process
 792instead.
 793
 794These are the contents of my ~~/.offlineimap.py~.
 795
 796#+BEGIN_SRC python
 797  #! /usr/bin/env python2
 798  from subprocess import check_output
 799  def get_pass(account):
 800      return check_output(["gpg", "-dq", f" ~/.mail_pass/{account}.gpg"]).strip("\n")
 801#+END_SRC
 802
 803This runs ~gpg -dq ~/.mail_pass/use_exa.gpg~ then strips the newline
 804character before returning it to OfflineIMAP. ~-d~ tells GPG that you're
 805passing it a file you want decrypted and ~-q~ tells it not to give any
 806output other than the file's contents. For a setup that works with this
 807Python script, put your passwords in plaintext files with the account
 808name as the file name (e.g. ~use_exa~). You'll then encrypt it with ~gpg
 809-er <YOUR_KEY_ID> use_exa~. Running ~gpg -dq use_exa.gpg~ should display
 810your password. Repeat for every account and store the resulting files in
 811~~/.mail_pass/~.
 812
 813The other option, ~sync_deletes~, is whether or not to delete remote
 814emails that have been deleted locally. I enabled that because I want to
 815have easy control over how much remote storage is used.
 816
 817Here's the next block again so you don't have to scroll up:
 818
 819#+BEGIN_SRC text
 820[Repository use_exa-remote]
 821type = IMAP
 822remotehost = imap.example.com
 823starttls = yes
 824ssl = no
 825remoteport = 143
 826remoteuser = user@example.com
 827remotepasseval = get_pass("use_exa")
 828auth_mechanisms = GSSAPI, XOAUTH2, CRAM-MD5, PLAIN, LOGIN
 829maxconnections = 1
 830createfolders = True
 831sync_deletes = yes
 832#+END_SRC
 833
 834This one's pretty self-explanatory. ~type~, ~remotehost~, ~starttls~, ~ssl~, and
 835~remoteport~ should all be somewhere in your provider's documentation.
 836~remoteuser~ is your email address and ~remotepasseval~ is the function that
 837will return your password and allow OfflineIMAP to authenticate. You'll
 838want enter the name of your password file without the ~.gpg~ extension;
 839the script takes care of adding that. Leave ~auth_mechanisms~ alone and
 840the same for ~maxconnections~ unless you know your provider won't rate
 841limit you or something for opening multiple connections. ~sync_deletes~ is
 842the same as in the previous block.
 843
 844Copy those three blocks for as many accounts as you want emails
 845downloaded from. I have 510 lines just for ~Account~ and ~Repository~ blocks
 846due to the number of address I'm keeping track of.
 847
 848*** ~notmuch~
 849[[https://notmuchmail.org/][~notmuch~]] is /a fast, global-search, and tag-based email system/. This
 850what does all of our organisation as well as what provides the "virtual"
 851mailboxes NeoMutt will display later on. Configuration is incredibly
 852simple. This file goes in ~~/.notmuch-config~.
 853
 854#+BEGIN_SRC text
 855  [database]
 856  path=/home/user/mail/
 857
 858  [user]
 859  name=Amolith
 860  primary_email=user@example.com
 861
 862  [new]
 863  tags=unread;new;
 864  ignore=Trash;
 865
 866  [search]
 867  exclude_tags=deleted;spam;
 868
 869  [maildir]
 870  synchronize_flags=true
 871#+END_SRC
 872
 873First section is the path to where all of your archives are, the ~[user]~
 874section is where you list all of your accounts, ~[new]~ adds ~tags~ to mail
 875notmuch hasn't indexed yet and ignores indexing the ~Trash~ folder, and
 876~[search]~ ignores mail tagged with ~deleted~ or ~spam~. The final section
 877tells ~notmuch~ to add maildir flags which correspond with ~notmuch~ tags.
 878These flags will be synced to the remote server the next time
 879OfflineIMAP runs and things will be somewhat organised in your webmail
 880interface.
 881
 882After creating the configuration file, run ~notmuch new~ and wait for all
 883of your mail to be indexed. This could take a short amount of time or it
 884could take minutes up to an hour, depending on how many emails you have.
 885After it's finished, you'll be able to run queries and see matching
 886emails:
 887
 888#+BEGIN_SRC text
 889  $ notmuch search from:user@example.com
 890  thread:0000000000002e9d  December 28 [1/1] Example User; Random subject that means nothing
 891#+END_SRC
 892
 893This is not terribly useful in and of itself because you can't read it
 894or reply to it or anything. That's where the Mail User Agent (MUA) comes
 895in.
 896
 897*** ~afew~
 898[[https://afew.readthedocs.io/en/latest/][~afew~]] is /an initial tagging script for notmuch/. After calling ~notmuch
 899new~, ~afew~ will add tags based on headers such as ~From:~, ~To:~, ~Subject:~,
 900etc. as well as handle killed threads and spam. The official [[https://afew.readthedocs.io/en/latest/quickstart.html][quickstart
 901guide]] is probably the best resource on getting started but I'll include
 902a few tips here as well.
 903
 904*** NeoMutt
 905*** ~msmtp~
 906~msmtp~ is what's known as a /Mail Transfer Agent/ (MTA). You throw it an
 907email and it will relay that to your mail provider's SMTP server so it
 908can have the proper headers attached for authentication, it can be sent
 909from the proper domain, etc. All the necessary security measures can be
 910applied that prevent your email from going directly to spam or from
 911being rejected outright.
 912
 913~msmtp~'s configuration is also fairly simple if a bit long, just like
 914OfflineIMAP's.
 915
 916#+BEGIN_SRC text
 917  # Set default values for all following accounts.
 918  defaults
 919
 920  # Use the mail submission port 587 instead of the SMTP port 25.
 921  port 587
 922
 923  # Always use TLS.
 924  tls on
 925#+END_SRC
 926
 927This section just sets the defaults. It uses port 587 (STARTTLS) for all
 928SMTP servers unless otherwise specified and enables TLS.
 929
 930#+BEGIN_SRC text
 931  account user@example.com
 932  host smtp.example.com
 933  from user@example.com
 934  auth on
 935  user user@example.com
 936  passwordeval secret-tool lookup Title "user@example.com"
 937#+END_SRC
 938
 939This section is where things get tedious. When passing an email to
 940~msmtp~, it looks at the ~From:~ header and searches for a block with a
 941matching ~from~ line. If it finds one, it will use those configuration
 942options to relay the email. ~host~ is simply the SMTP server of your mail
 943provider, sometimes this is ~mail.example.com~, ~smtp.example.com~, etc.
 944I've already explained ~from~, ~auth~ simply says that a username and
 945password will have to be provided, ~user~ is that username, and
 946~passwordeval~ is a method to obtain the password.
 947
 948When I got to configuring ~msmtp~, [[https://keepassxc.org/][KeePassXC]] had just released their
 949~libsecret~ integration and I wanted to try it. ~secret-tool~ is a command
 950line tool used to store and retrieve passwords from whatever keyring
 951you're using. I think KDE has ~kwallet~ and GNOME has ~gnome-keyring~ if
 952you already have those set up and want to use them; the process should
 953be quite similar regardless.
 954
 955As mentioned above ~secret-tool~ stores and retrieves passwords. For
 956retrieval, it expects the command to look like this.
 957
 958#+BEGIN_SRC text
 959secret-tool lookup {attribute} {value} ...
 960#+END_SRC
 961
 962I don't know what ~kwallet~ and ~gnome-keyring~'s attributes are but
 963this can be used with KeePassXC by specifying the ~Title~ attribute. If
 964the password to your email account is stored in KeePassXC with the
 965address as the entry title, you can retrieve it by simply running...
 966
 967#+BEGIN_SRC text
 968secret-tool lookup Title "user@example.com"
 969#+END_SRC
 970
 971If you have a different naming system, you'll have to experiment and try
 972different things; I don't know what KeePassXC's other attributes are so
 973I can't give other examples.
 974
 975#+BEGIN_SRC text
 976passwordeval gpg -dq ~/.mail_pass/use_exa.gpg
 977#+END_SRC
 978
 979Now that the whole block is assembled, copy/paste/edit for as many
 980accounts as you want to send email from.
 981
 982*** Summary
 983
 984*** TODO Pong fluffy when finished
 985** TODO Audacity and the telemetry pull request :Open__source__culture:Audio__editing:Music:Drama:
 986:PROPERTIES:
 987:EXPORT_FILE_NAME: audacity-and-the-telemetry-pull-request
 988:EXPORT_HUGO_CUSTOM_FRONT_MATTER: :toc true
 989:END:
 990
 991Five days ago at the time of writing, [[https://github.com/crsib][Dmitry Vedenko]] opened a Pull
 992Request (PR) in [[https://github.com/audacity/audacity/pull/835][Audacity's GitHub repository]] entitled [[https://github.com/audacity/audacity/pull/835][/Basic telemetry
 993for the Audacity/.]] About two days later, all hell broke loose. That PR
 994now has over 3.3 thousand downvotes and more than one thousand comments
 995from nearly 400 individuals. I started reading the posts shortly after
 996they began and kept up with them over the following days, reading every
 997single new post. I recognise that few people are going to feel like
 998wading through over 1k comments so this is my attempt to provide a
 999summary of the PR itself using the community's code reviews along with a
1000summary of the various opinions conveyed in the comments.
1001
1002When I reference comments, I'll provide a footnote that includes a link
1003to the comment and a link to a screenshot just in case it's removed or
1004edited in the future.
1005
1006*** Audacity's acquisition
1007
1008I haven't been able to find /much/ information in this area so forgive me
1009if I'm scant on details.
1010
1011On 30 April, a company called [[https://mu.se/][Muse Group]] acquired [[https://www.audacityteam.org/][Audacity.]] According to
1012[[https://mu.se][their website]], Muse is the parent company behind many musical
1013applications and tools. It was founded by Eugeny Naidenov just days
1014before it acquired Audacity. Before all of this, Eugeny Naidenov founded
1015[[https://www.ultimate-guitar.com/][Ultimate Guitar]] (UG) in 1998. The service grew rather quickly and now
1016has over 300 million users. UG acquired [[https://deanzelinsky.com/][Dean Zelinsky Guitars]] in 2012,
1017[[http://agilepartners.com/][Agile Partners]] in 2013, [[https://musescore.org/][MuseScore]] in 2017, and [[http://trycrescendo.com/][Crescendo]] in 2018. Muse
1018Group was established in 2021 and it seems as if all of the services UG
1019acquired were (or will be) transferred to Muse Group, as well as UG
1020itself. Immediately following its establishment, Muse not only acquired
1021Audacity but also [[https://www.staffpad.net/][StaffPad.]]
1022
1023I say 30 April because that's when Muse published their [[https://mu.se/newsroom/tpost/6dhedma301-muse-group-acquires-audacity-expanding-c][press release]]
1024and when Martin Keary (Tantacrul) published a video entitled [[https://www.youtube.com/watch?v=RMWNvwLiXIQ][/I’m now in
1025charge of Audacity. Seriously./]] According to his comment,[fn:17] Martin
1026will help with proposing Audacity's roadmap and many of its future
1027features as well as working with the community. This has been his role
1028with MuseScore since he joined that project and he will be continuing it
1029here.
1030
1031~-----BEGIN PERSONAL OPINION-----~
1032
1033Looking at [[https://www.martinkeary.com/][his website,]] I also suspect he will play a large role in
1034redesigning Audacity's interface. Considering that he was instrumental
1035in designing [[https://www.martinkeary.com/#/ubuntu-touch-os/][the best mobile interface I've ever had the absolute
1036pleasure of experiencing,]] I have high hopes that this is the case.
1037
1038~------END PERSONAL OPINION------~
1039
1040*** Telemetry implementation
1041**** Implementation Basics
1042
1043A few days after the acquisition, a PR was opened that adds /Basic
1044telemetry for the Audacity/. This implementation collects "application
1045opened" events and sends those to Yandex to estimate the number of
1046Audacity users. It also collects session start and end events, errors
1047for debugging, file used for import and export, OS and Audacity
1048versions, and the use of effects, generators, and analysis tools so they
1049can prioritise future improvements. Sending this data would be optional
1050and the user would be presented with a dialogue the first time they
1051launch the application after installation or after they update to the
1052including release. This description was mostly copied directly from [[https://github.com/audacity/audacity/pull/835#issue-629891447][the
1053PR description itself.]]
1054
1055**** Frontend Implementation
1056This is fairly straightforward and a pretty standard UI for prompting
1057users to consent to analytics and crash logging. This section is
1058included because the community has strong opinions regarding the
1059language used and its design, but that will be discussed later. The
1060screenshot below is copied directly from the PR.
1061
1062[[~/repos/sites/secluded/static/assets/pngs/audacity-pr/consentdialogue.png][file:~/repos/sites/secluded/static/assets/pngs/audacity-pr/consentdialogue.png]]
1063
1064**** Backend Implementation
1065Many of the code reviews include the reviewer's personal opinion so I
1066will summarise the comment, provide the code block in question, and link
1067directly to the comment in a footnote.[fn:9]
1068
1069#+BEGIN_SRC c
1070  if (!inputFile.Write (wxString::FromUTF8 (ClientID + "\n")))
1071    return false;
1072#+END_SRC
1073[[https://github.com/crsib/audacity/blob/c9264d2478fe2af82aeb6e2a0295b00b3a27ce53/libraries/lib-telemetry/TelemetryManager.cpp#L199-L200][Lines 199-200 of TelemetryManager.cpp]] save the user's unique client ID
1074to a file.[fn:8] This allows the analytics tool (in this case, Google
1075Analytics) to aggregate data produced by a single user.
1076
1077#+BEGIN_SRC c
1078  def_vars()
1079
1080    set( CURL_DIR "${_INTDIR}/libcurl" )
1081    set( CURL_TAG "curl-7_76_0")
1082#+END_SRC
1083[[https://github.com/crsib/audacity/blob/c9264d2478fe2af82aeb6e2a0295b00b3a27ce53/cmake-proxies/libcurl/CMakeLists.txt#L3-L6][Lines 3-6 of CMakeLists.txt]] "vendor in" libcurl.[fn:10] This is when an
1084application directly includes sources for a utility rather than making
1085use utilities provided by the system itself.
1086
1087#+BEGIN_SRC c
1088  ExternalProject_Add(curl
1089     PREFIX "${CURL_DIR}"
1090     INSTALL_DIR "${CURL_DIR}"
1091     GIT_REPOSITORY https://github.com/curl/curl
1092     GIT_TAG ${CURL_TAG}
1093     GIT_SHALLOW Yes
1094     CMAKE_CACHE_ARGS ${CURL_CMAKE_ARGS}
1095  )
1096#+END_SRC
1097[[https://github.com/crsib/audacity/blob/c9264d2478fe2af82aeb6e2a0295b00b3a27ce53/cmake-proxies/libcurl/CMakeLists.txt#L29-L36][Lines 29-36 of CMakeLists.txt]] add curl as a remote dependency.[fn:11]
1098This means that the machine building Audacity from its source code has
1099to download curl during that build.
1100
1101#+BEGIN_SRC c
1102  S.Id (wxID_NO).AddButton (rejectButtonTitle);
1103  S.Id (wxID_YES).AddButton (acceptButtonTitle)->SetDefault ();
1104#+END_SRC
1105[[https://github.com/crsib/audacity/blob/c9264d2478fe2af82aeb6e2a0295b00b3a27ce53/src/telemetry/TelemetryDialog.cpp#L93-L94][Lines 93-94 of TelemetryDialog.cpp]] add buttons to the dialogue asking
1106the user whether they consent to data collection.[fn:12] ~SetDefault~
1107focuses the button indicating that the user does consent. This means
1108that if the user doesn't really look at the dialogue and presses
1109Spacebar or Enter, or if they do so accidentally by simply bumping the
1110key, they unintentionally consent to data collection. If the user
1111desires, this can later be changed in the settings menu. However, if
1112they weren't aware what they were consenting to /or that they did
1113consent/, they won't know to go back and opt out.
1114
1115There are other problems with the code that include [[https://github.com/audacity/audacity/pull/835#discussion_r628816050][simple mistakes,]]
1116[[https://github.https://github.com/audacity/audacity/pull/835#discussion_r628774985][styling that's inconsistent with the rest of the project,]] [[https://github.com/audacity/audacity/pull/835#discussion_r628500849][unhandled
1117return values resulting in skewed data,]] [[https://github.com/audacity/audacity/pull/835#discussion_r628792423][use of inappropriate functions,]]
1118and [[https://github.com/audacity/audacity/pull/835#discussion_r628818054][spelling errors in the comments.]] I believe these are less important
1119than those above so they won't be discussed.
1120
1121*** Community opinions
1122There were many strong opinions regarding both the frontend and backend
1123implementations of this PR, from the wording of the dialogue and
1124highlighting the consent button to devices running something other than
1125Windows and macOS not being able to send telemetry and thus skewing the
1126data that /was/ collected.
1127
1128**** Opinions on the frontend
1129
1130Really, the only frontend here is the consent dialogue. However, there
1131are /many/ comments about it, the most common of which is probably that
1132the wording is not only too vague[fn:13] but also inaccurate.[fn:14] The
1133assertion that Google Analytics are not anonymous and any data sent can
1134be trivially de-anonymised (or de-pseudonymised) is repeated many times
1135over. Below are a few links to comments stating such. I searched for the
1136term /"anonymous"/, copied relevant links, and stopped when my scrollbar
1137reached halfway down the page.
1138
1139- [[https://github.com/audacity/audacity/pull/835#discussion_r628156527][r628156527]]
1140- [[https://github.com/audacity/audacity/pull/835#issuecomment-833969780][833969780]]
1141- [[https://github.com/audacity/audacity/pull/835#issuecomment-833969933][833969933]]
1142- [[https://github.com/audacity/audacity/pull/835#discussion_r627995927][r627995927]]
1143- [[https://github.com/audacity/audacity/pull/835#issuecomment-834358022][834358022]]
1144- [[https://github.com/audacity/audacity/pull/835#issuecomment-834377549][834377549]]
1145- [[https://github.com/audacity/audacity/pull/835#issuecomment-834382007][834382007]]
1146- [[https://github.com/audacity/audacity/pull/835#issuecomment-834385463][834385463]]
1147- [[https://github.com/audacity/audacity/pull/835#issuecomment-834405825][834405825]]
1148- [[https://github.com/audacity/audacity/pull/835#issuecomment-834531779][834531779]]
1149- [[https://github.com/audacity/audacity/pull/835#issuecomment-834546874][834546874]]
1150- [[https://github.com/audacity/audacity/pull/835#issuecomment-834638000][834638000]]
1151
1152The next most pervasive comment is regarding the consent buttons at the
1153bottom of the dialogue where users opt in or out.[fn:15] Many individuals call
1154this design a /dark pattern/. Harry Brignull, a UX specialist focusing on
1155deceptive interface practises, describes dark patterns as [[https://www.darkpatterns.org/][/tricks used
1156in websites and apps that make you do things that you didn't mean to/.]]
1157The dark pattern in this situation is the opt-in button being
1158highlighted. Many community members assert that users will see the big
1159blue button and click it without actually reading the dialogue's
1160contents. They just want to record their audio and this window is a
1161distraction that prevents them from doing so; it needs to get out of the
1162way and the quickest way to dismiss it is clicking that blue button.
1163Below is a list of some comments criticising this design.
1164
1165  - [[https://github.com/audacity/audacity/pull/835#issuecomment-834286641][834286641]]
1166  - [[https://github.com/audacity/audacity/pull/835#issuecomment-834358022][834358022]]
1167  - [[https://github.com/audacity/audacity/pull/835#issuecomment-834399813][834399813]]
1168  - [[https://github.com/audacity/audacity/pull/835#issuecomment-834479968][834479968]]
1169  - [[https://github.com/audacity/audacity/pull/835#issuecomment-835250737][835250737]]
1170  - [[https://github.com/audacity/audacity/pull/835#issuecomment-835253882][835253882]]
1171  - [[https://github.com/audacity/audacity/pull/835#issuecomment-835291066][835291066]]
1172  - [[https://github.com/audacity/audacity/pull/835#issuecomment-835445481][835445481]]
1173
1174Another issue that was brought up by a couple of individuals was the
1175lack of a privacy policy.[fn:16] The consent dialogue links to one, but, at the
1176time of writing, one does not exist at [[https://www.audacityteam.org/contact/privacy-policy/][the provided URL.]] I have [[https://web.archive.org/web/20210510012924/https://www.audacityteam.org/contact/privacy-policy/][archived
1177the state of the page]] in case that changes in the future.
1178
1179**** Opinions on the backend
1180
1181#+BEGIN_SRC c
1182  if (!inputFile.Write (wxString::FromUTF8 (ClientID + "\n")))
1183    return false;
1184#+END_SRC
1185
1186The issue many individuals take with this snippet is saving the
1187~ClientID~. Say an individual has an odd file that causes Audacity to
1188crash any time they try to open it. Say they attempt to open it a
1189hundred times. Without giving the client a unique ID, it could look like
1190there are 100 people having an issue opening a file instead of just the
1191one. However, by virtue of each installation having an entirely unique
1192ID, this telemetry /is not anonymous/. Anonymity would be sending
1193statistics in such a way that connecting those failed attempts to a
1194single user would be impossible. At best, this implementation is
1195/pseudonymous/ because the client is given a random ID, you don't have to
1196sign in with an account or something.
1197
1198#+BEGIN_SRC c
1199  def_vars()
1200
1201    set( CURL_DIR "${_INTDIR}/libcurl" )
1202    set( CURL_TAG "curl-7_76_0")
1203#+END_SRC
1204
1205Timothe Litt's comment gives a good description of why "vendoring in"
1206libcurl is a bad idea[fn:19] and Tyler True's comment gives a good
1207overview of the pros and cons of doing so.[fn:18] Many people take issue
1208with this /specifically/ because it's libcurl. Security flaws in it are
1209/very/ common and Audacity's copy would need to be /manually/ kept up to
1210date with every upstream release to ensure none of its vulnerabilities
1211can be leveraged to compromise users. If the Audacity team was going to
1212stay on top of all of the security fixes, they would need to release a
1213new version every week or so.
1214
1215#+BEGIN_SRC c
1216  ExternalProject_Add(curl
1217     PREFIX "${CURL_DIR}"
1218     INSTALL_DIR "${CURL_DIR}"
1219     GIT_REPOSITORY https://github.com/curl/curl
1220     GIT_TAG ${CURL_TAG}
1221     GIT_SHALLOW Yes
1222     CMAKE_CACHE_ARGS ${CURL_CMAKE_ARGS}
1223  )
1224#+END_SRC
1225The problem with downloading curl at build-time is that it's simply
1226disallowed for many Linux- and BSD-based operation systems. When a
1227distribution builds an application from source, its build dependencies
1228are often downloaded ahead of time and, as a security measure, the build
1229machine is cut off from the internet to prevent any interference.
1230Because this is disallowed, the build will fail and the application
1231won't be available on those operation systems.
1232
1233Note, however, that these build machines would have the option to
1234disable telemetry at build-time. This means the machine wouldn't attempt
1235to download curl from GitHub and the build would succeed but, again,
1236telemetry would be disabled for anyone not on Windows or macOS. This
1237defeats the whole purpose of adding telemetry in the first place.
1238
1239#+BEGIN_SRC c
1240  S.Id (wxID_NO).AddButton (rejectButtonTitle);
1241  S.Id (wxID_YES).AddButton (acceptButtonTitle)->SetDefault ();
1242#+END_SRC
1243
1244There was a lot of feedback about the decision to highlight the consent
1245button but that was mentioned up in the frontend section; I won't rehash
1246it here.
1247
1248**** Broader and particularly well-structured comments
1249These are simply some comments I feel deserve particular attention.
1250
1251From SndChaser...
1252- [[https://github.com/audacity/audacity/pull/835#issuecomment-834037351][834037351]]
1253-
1254
1255*** The Audacity team's response
1256
1257
1258-----------------
1259
1260*** The privacy policy modification
1261
1262https://github.com/audacity/audacity/issues/1213#issuecomment-875274890
1263
1264** TODO Catchy title about Supernote being "the new paper" :Supernote:Writing:Productivity:Organisation:
1265:PROPERTIES:
1266:EXPORT_FILE_NAME: something-about-supernote
1267:EXPORT_HUGO_CUSTOM_FRONT_MATTER: :toc true
1268:END:
1269
1270I like writing things down. I like the feel of the pen (preferably a
1271fountain pen) gliding smoothly over the paper, that nice solid feeling
1272of the tip against the table, seeing the ink dry as it flows from the
1273nib, accidentally swiping my hand through it before it's finished and
1274smearing a bit of ink across the page, then cursing under my breath as I
1275dab it up with a handkerchief or a napkin or something else nearby. I
1276also love that writing things by hand [[https://journals.sagepub.com/doi/abs/10.1177/0956797614524581][has an impact on memory and
1277improves retention.]]
1278
1279*** The problem
1280Unfortunately, I don't love keeping up with that paper. Across many
1281different classes, even with dedicated folders for each one, something
1282important inevitably gets lost. Notebooks are also bulky and can take up
1283a lot of space. I tried [[https://bulletjournal.com/][bullet journalling]] for about a month earlier
1284this year and, while the process was enjoyable, the maintenance was not.
1285My brain moves faster than my pen (even though I have terrible
1286handwriting) and I inevitably forget letters or even whole words. This
1287is a problem while writing in pen because white-out looks ugly and I
1288dislike wasting whole pages because of a couple mistakes.
1289
1290The obvious solution here is to get an iPad with an Apple Pen, right?
1291Right??
1292
1293Wrong because Apple bad.[fn:2]
1294
1295*** The solution
1296Enter the world of ... what are they even called? E-ink notebooks? Paper
1297tablets? E-R/W?[fn:1] Do they even have a "device category" yet? I don't
1298know, but they solve my problem in a wonderful way.
1299
1300As the names suggest, these are devices that can /usually/ open and read
1301e-books (EPUBs, PDFs, etc.), annotate them, and create standalone pages
1302of notes as if they were full notebooks. The most well-known of these
1303devices is likely the [[https://remarkable.com/][reMarkable.]] They had a [[https://venturebeat.com/2019/10/08/remarkable-raises-15-million-to-bring-its-e-paper-tablets-to-more-scribblers/][hugely successful
1304crowdfunding campaign]] and produced the reMarkable 1, followed by [[https://blog.remarkable.com/remarkable-2-the-next-generation-paper-tablet-91b47d0080cb][the
1305reMarkable 2 in 2020.]] There are a few devices like these by now but
1306we'll look at the reMarkable first.
1307
1308*** The reMarkable
1309This device boasts all of the features I was looking for. It renders
1310digital content, from books and manuals to comics and manga, allows you
1311to mark those documents up as you would if they were physical media,
1312create full notebooks of hand written text, organise them, search, and,
1313if your handwriting is legible enough (mine certainly is not), perform
1314OCR on your notes and email a transcription to yourself. It even runs
1315Linux and the developers have opened SSH up so you can remote in and
1316tinker with it as much as you like. Because of this, there's a pretty
1317awesome [[https://github.com/reHackable/awesome-reMarkable][community of people creating third-party tools and integrations]]
1318that add even further functionality. My favourite is probably [[https://github.com/bordaigorl/rmview][rMview,]] a
1319really fast VNC client for the reMarkable that allows you to view your
1320device's screen on any computer.
1321
1322After watching all of [[https://www.youtube.com/c/MyDeepGuide][MyDeepGuide's]] [[https://www.youtube.com/playlist?list=PLsSI9-gaSSmiXwb7Vjk5Vb-nB41UTnrXd][extensive playlist on the
1323reMarkable,]] however, I decided to go with a different product.
1324
1325*** Enter the Supernote A5X
1326The [[https://www.supernote.com/#/product?type=SN-A5-X][Supernote A5X]] has all of the basic features the reMarkable has:
1327reading documents, writing notes, and organising your content. Its
1328implementation, on the other hand, seems to be much more polished. It
1329also lacks some features from the reMarkable while adding others.
1330
1331*** Operating System
1332While the reMarkable runs Codex,[fn:3] a /"custom Linux-based OS
1333optimised for low-latency e-paper"/, the Supernote just runs Android.
1334There are both benefits and detriments to this; on one hand, they're
1335running all of Android, bloated that it is, on a very lightweight
1336tablet. On the other, they don't have to develop and maintain a custom
1337operating system. This allows them to focus on other aspects that are
1338arguably more important so I don't actually mind that it runs Android.
1339
1340The only place that Android stands out is in system operations; file
1341transfer uses MTP and, when you swipe down from the top of the device, a
1342small bar appears similar to what was in early Android. This lets you
1343change WiFi networks, sync with the Supernote Cloud, take a screenshot,
1344search, and access the system settings. Nothing else about the device
1345really screams Android to me.
1346
1347*** Community
1348I don't usually browse Reddit but [[https://old.reddit.com/r/Supernote/][the Supernote community]] there is
1349fascinating. I haven't looked around enough to know exactly what his
1350relationship is with the company, but one of the members, [[https://old.reddit.com/user/hex2asc][u/hex2asc,]]
1351seems to represent Supernote in something of an official capacity. He's
1352incredibly active and usually responds to posts and questions within a
1353day or two.
1354
1355Before I purchased a Supernote, [[https://old.reddit.com/r/Supernote/comments/lhffyd/sync_targets_open_document_formats_and_crossnote/][I wrote a post]] asking about a couple of
1356things that concerned me: sync targets, open document formats, and
1357cross-note links. I don't really plan to write full documents on the
1358device but having the option to do so would still be nice. The other
1359features are absolutely killer for me as I would like to maintain a
1360Zettelkasten (I wrote about [[/vim-as-a-markdown-editor/][using Vim to do so]] last year but didn't end
1361up sticking with it) and manage document synchronisation with my own
1362Nextcloud server. The community was quick to respond and confirm that
1363Zettelkasten functionality would be implemented soon™. u/hex2asc
1364responded /the day after/ and said that WebDAV would be supported but not
1365earlier than May (September update: it's still not supported), ODF would
1366likely not be supported, and cross-note links were definitely a
1367possibility. Another community member has been avidly following the
1368subreddit and even put together an [[https://app-rm.roadmunk.com/publish/03e6dca3d769e2b7015f7f48a649cb3f75f44d9e][unofficial roadmap.]]
1369
1370*** Interfaces
1371
1372**** Home & Organisation
1373
1374***** TODO Record very short video about home/organisation
1375
1376**** Settings
1377
1378***** TODO Record very short video about settings
1379
1380**** Writing & Annotating
1381
1382The following images are screenshots of the full page above with the
1383possible UI variations while reading a book. This first one is default,
1384with the editing bar at the top. It is exactly the same as what's
1385displayed on the blank pages for hand writing full notes. From left to
1386right is the Table of Contents toggle, the pen tools (fineliner,
1387"fountain" pen,[fn:5] and highlighter), the erasers, lasso select tool,
1388undo/redo, context menu, palm rejection toggle, previous page, goto
1389page, next page, and exit.
1390
1391[[~/repos/sites/secluded/static/assets/pngs/supernote-reader-default.png]]
1392
1393You can hold your finger on that bar and drag it down to detach it from
1394the top. The default width exposes all the tools without whitespace. You
1395can move it around the screen by dragging the circle with a straight
1396line through the middle on the far left.
1397
1398[[~/repos/sites/secluded/static/assets/pngs/supernote-reader-medium.png]]
1399
1400If you tap that circle, the width shrinks and everything except the
1401pens, erasers, and undo/redo buttons are hidden. It can be dragged the
1402same was as in the previous image and tapping that circle will expand
1403the bar again.
1404
1405[[~/repos/sites/secluded/static/assets/pngs/supernote-reader-small.png]]
1406
1407The last mode is with the bar completely hidden. You achieve this just
1408by dragging it to the right edge of the screen. Once hidden, you can
1409swipe right to left from the edge and it will be revealed flush with the
1410right edge.
1411
1412[[~/repos/sites/secluded/static/assets/pngs/supernote-reader-minimal.png]]
1413
1414*** Experience
1415**** Reading content
1416I love e-ink. I think it looks beautiful and would love to have an e-ink
1417monitor.[fn:4] That said, the Supernote has an especially nice display
1418with 226 PPI (pixels per inch). The image below was taken with my
1419phone's camera so it's not very good. However, if you zoom in a bit, you
1420can see that the curved edges of some letters are /slightly/ pixellated.
1421Viewing with my naked eye at a comfortable distance, it does look better
1422/to me/ than some of my print books, however.
1423
1424[[~/repos/sites/secluded/static/assets/pngs/supernote-resolution.png]]
1425
1426/At the moment,/ I am pretty disappointed with Table of Contents detection
1427for ePUBs. A great many of my books seem to use a legacy ToC format that
1428the Supernote sees and tries/fails to read before attempting to read the
1429more up-to-date one. This is easily remedied by editing the ePUB in
1430[[https://calibre-ebook.com/][Calibre,]] going to Tools → Upgrade Book Internals → Remove the legacy
1431Table of Contents in NCX format. You might need to make a small change
1432to one of the HTML files and revert it before the save button is
1433enabled. After that, just copy it back over to the Supernote and
1434everything should work properly.
1435
1436**** Writing notes
1437I write notes as often if not /more/ often than I read and annotate books.
1438It's the main reason I purchased the device and I love the experience.
1439The Supernote doesn't /really/ feel like paper despite what their
1440marketing materials claim, though it doesn't feel /bad/ either. It's hard
1441to describe but I would say it's something like writing with a
1442rollerball pen on high-quality paper with a marble counter underneath:
1443incredibly smooth with but a little bit of texture so it doesn't feel
1444like writing on a glass display.
1445
1446While writing latency[fn:6] is noticeable, I really don't have a huge
1447issue with it. I write very quickly but find that the slight latency
1448actually makes writing /more/ enjoyable. It sounds weird and I'm not sure
1449why, but I /really/ like writing on the Supernote; it's wonderfully
1450smooth, pressure-sensitive, the latency makes things interesting, and
1451[[https://supernote.com/#/part?id=SP-04][the Heart of Metal pen]] feels good in my hand.
1452
1453**** Surfacing Content
1454While organisation is done using a regular filesystem hierarchy, the
1455Supernote does have other ways to search for and surface your notes. As
1456you're writing, you can use the lasso select tool and encircle a word. A
1457little dialogue pops up and gives you a few buttons for things you can
1458do with that selection: copy, move to another page, cut, add it to the
1459Table of Contents, or mark it as a key word. If you select the key word
1460icon, the Supernote does some incredible OCR[fn:7] on it and displays a
1461dialogue where you can add it to the note file as a tag. This dialogue
1462allows you to edit the word before adding it just in case the OCR was
1463wonky. Even with my terrible handwriting, I've found that it works very
1464well and I rarely have to make edits.
1465
1466*** TODO Ping Isi and Volpeon when finished
1467** TODO Making yourself overly available
1468
1469*** References
1470[[https://www.nytimes.com/2021/03/05/opinion/ezra-klein-podcast-cal-newport.html?showTranscript=1][Stop. Breathe. We Can’t Keep Working Like This.]]
1471
1472*** Notes
1473**** Get rid of information that isn't important
1474**** Escalate the info that is
1475**** Set /clear/ boundaries for when you are available
1476**** Enforce those with automatic DnD rules or use timers
1477**** With groups...
1478***** Specialisation is /good/ and should be /encouraged/
1479***** /All/ of the above points apply with coworkers as well
1480
1481*** TODO Pong Jake when finished
1482** TODO Setting LXC up for local "cloud" development
1483** TODO Stop using Gmail!
1484* Education                                                      :@Education:
1485** TODO Homeschooling
1486* Music                                                              :@Music:
1487* Pipe Smoking                                               :@Pipe__Smoking:
1488* Dungeons & Dragons                                :@Dungeons__and__Dragons:
1489
1490* Footnotes
1491
1492[fn:19] [[https://github.com/audacity/audacity/pull/835#issuecomment-834451187][Link to the comment]] and [[/assets/pngs/audacity-pr/privatelibcurl.png][link to the screenshot]]
1493
1494[fn:18] [[https://github.com/audacity/audacity/pull/835#issuecomment-834010117][Link to the comment]] and [[/assets/pngs/audacity-pr/vendorproscons.png][link to the screenshot]]
1495
1496[fn:17] [[https://github.com/audacity/audacity/pull/835#issuecomment-836069326][Link to the comment]] and [[/assets/pngs/audacity-pr/tantacrulrole.png][link to the screenshot]]
1497
1498[fn:16] [[https://github.com/audacity/audacity/pull/835#discussion_r627762185][Link to the comment]] and [[/assets/pngs/audacity-pr/missingprivacypolicy.png][link to the screenshot]]
1499
1500[fn:15] [[https://github.com/audacity/audacity/pull/835#issuecomment-834286641][Link to the comment]] and [[/assets/pngs/audacity-pr/darkpattern.png][link to the screenshot]]
1501
1502[fn:14] [[https://github.com/audacity/audacity/pull/835#discussion_r627764300][Link to the comment]] and the screenshot is the same as previous
1503
1504[fn:13] [[https://github.com/audacity/audacity/pull/835#discussion_r627756976][Link to the comment]] and [[/assets/pngs/audacity-pr/vaguedialogue.png][link to the screenshot]]
1505
1506[fn:12] [[https://github.com/audacity/audacity/pull/835#discussion_r628124998][Link to the review]] and [[/assets/pngs/audacity-pr/defaultconsentbutton.png][link to the screenshot]]
1507
1508[fn:11] [[https://github.com/audacity/audacity/pull/835#discussion_r628008821][Link to the review]] and [[/assets/pngs/audacity-pr/externaldependency.png][link to the screenshot]]
1509
1510[fn:10] [[https://github.com/audacity/audacity/pull/835#discussion_r628005925][Link to the review]] and [[/assets/pngs/audacity-pr/vendorcurl.png][link to the screenshot]]
1511
1512[fn:9] Note that because I am not a C programmer, these reviews might
1513not be entirely accurate and I wouldn't be able to catch the reviewer's
1514error. I am relying on other community members to catch issues and
1515comment on them; none of the reviews I link to have such comments so I'm
1516assuming they are correct.
1517
1518[fn:8] [[https://github.com/audacity/audacity/pull/835#discussion_r627993755][Link to the review]] and [[/assets/pngs/audacity-pr/writeanalyticsid.png][link to the screenshot]]
1519
1520[fn:7] /Optical Character Recognition/: the program looks at your
1521handwriting and tries to turn it into text.
1522
1523[fn:6] In this situation, latency refers to how long it takes for "ink"
1524to show up on the "page" after writing something.
1525
1526[fn:5] It's not really a fountain pen even though that's what they call
1527it; it's just pressure-sensitive.
1528
1529[fn:4] There does seem to be a group of people interested in just such a
1530thing: /[[https://alexsoto.dev/challenges-building-an-open-source-eink-laptop.html][Challenges Building an Open-Source E Ink Laptop]]/
1531
1532[fn:3]Taken from their [[https://support.remarkable.com/hc/en-us/articles/360006699537-About-reMarkable-2-][support page about the reMarkable 2;]] search the
1533page for /operating system/ and it should show up.
1534
1535[fn:2]I dislike Apple's operating system, their hardware, business
1536model, privacy practises, and much of what they stand for as a company.
1537Don't @ me.
1538
1539[fn:1]E-R/W is a play on media commonly being labelled as R/W when you
1540can read from it and write to it.