<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">

  <channel>
    <title>Alexandru Nedelcu - Wiki</title>
    <description>Feed of wiki articles, published at alexn.org/wiki/</description>
    <link>https://alexn.org/wiki/</link>
    <atom:link href="https://alexn.org/feeds/wiki.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Fri, 06 Mar 2026 09:40:05 +0000</pubDate>
    <lastBuildDate>Fri, 06 Mar 2026 09:40:05 +0000</lastBuildDate>
    <language>en</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <generator>Jekyll v4.4.1</generator>
    
<item>
  <title>Bitwarden / Vaultwarden</title>
  <description>Article
    updated at August 26, 2024, 
    created at August 26, 2024.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at August 26, 2024, 
    created at August 26, 2024.
  &lt;/p&gt;
  &lt;hr&gt;
  
  &lt;img referrerpolicy=&quot;no-referrer-when-downgrade&quot; src=&quot;https://ly.alexn.org/m.php?idsite=1&amp;rec=1&amp;action_name=%2Ffeeds%2Fwiki.xml&amp;url=https%3A%2F%2Falexn.org%2Ffeeds%2Fwiki.xml&amp;pk_campaign=rss&amp;pk_kwd=open&quot; width=&quot;1&quot; height=&quot;1&quot; style=&quot;position: fixed !important; bottom: -1px !important; right: -1px !important; border:none !important; margin:0px !important;&quot; alt=&quot;&quot;&gt;
&lt;h2 id=&quot;self-hosting-vaultwarden&quot;&gt;Self-hosting (Vaultwarden)&lt;/h2&gt;

&lt;p&gt;See &lt;a href=&quot;https://github.com/dani-garcia/vaultwarden/wiki&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Setup for &lt;code&gt;docker-compose.yaml&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;vaultwarden:
  container_name: vaultwarden
  image: vaultwarden/server:latest
  restart: always
  healthcheck:
    test: [&apos;CMD-SHELL&apos;, &apos;curl --silent --fail http://localhost:80/ || exit 1&apos;]
  ports:
    - &quot;3201:80&quot;
  volumes:
    - vaultwarden:/data
  networks:
    - external_network
  env_file:
    - ./envs/vaultwarden.env
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Related &lt;code&gt;./envs/vaultwarden.env&lt;/code&gt; file:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;##
# Documentation:
# https://github.com/dani-garcia/vaultwarden/wiki/Enabling-admin-page
#
# To generate:
# echo -n &quot;MySecretPassword&quot; | argon2 &quot;$(openssl rand -base64 32)&quot; -e -id -k 65540 -t 3 -p 4
#
ADMIN_TOKEN=

##
# https://github.com/dani-garcia/vaultwarden/wiki/Disable-registration-of-new-users
#
SIGNUPS_ALLOWED=false

##
# https://github.com/dani-garcia/vaultwarden/wiki/SMTP-Configuration
#
# NOTE: Hetzner and other cloud providers, are blocking port 467
# https://www.fastmail.help/hc/en-us/articles/1500000278342-Server-names-and-ports
#
SMTP_HOST=smtp.fastmail.com
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_FROM=
SMTP_USERNAME=
SMTP_PASSWORD=

##
# https://github.com/dani-garcia/vaultwarden/wiki/Enabling-Mobile-Client-push-notification
# https://bitwarden.com/host/
#
PUSH_RELAY_URI=https://api.bitwarden.eu
PUSH_IDENTITY_URI=https://identity.bitwarden.eu
PUSH_ENABLED=true
PUSH_INSTALLATION_ID=
PUSH_INSTALLATION_KEY=
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;My Nginx reverse proxy configuration:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-conf&quot;&gt;root /var/www/vault.nedelcu.net;
log_not_found off;

include ./snippets/gzip.conf;

location / {
    proxy_pass http://vaultwarden;
    include ./snippets/proxy-backend.conf;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Where &lt;code&gt;./snippets/proxy-backend.conf&lt;/code&gt; is:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-conf&quot;&gt;include ./snippets/cloudflare-ips.conf;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Proxy &quot;&quot;;
proxy_pass_header Server;

proxy_buffering on;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

proxy_cache CACHE;
proxy_cache_valid 200 7d;
proxy_cache_valid 410 24h;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;

add_header X-Cached $upstream_cache_status;
tcp_nodelay on;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For &lt;code&gt;./snippets/cloudflare-ips.conf&lt;/code&gt; see &lt;a href=&quot;https://developers.cloudflare.com/support/troubleshooting/restoring-visitor-ips/restoring-original-visitor-ips/&quot;&gt;Restoring original visitor IPs (Cloudflare.com)&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;cli-commands&quot;&gt;CLI commands&lt;/h2&gt;

&lt;p&gt;Installation for macOS:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;brew install bitwarden-cli jq
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Lists items in the order they were modified:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bw list items | jq &apos;[.[] | {name: .name, date: .revisionDate}] | sort_by(.date)&apos;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Lists items with &lt;a href=&quot;https://www.passkeys.io/&quot;&gt;passkeys&lt;/a&gt; defined:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bw list items | jq &apos;.[] | select(.login.fido2Credentials | length &gt; 0) | {name: .name, id: .id, updated: .revisionDate}&apos;
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Mon, 26 Aug 2024 10:45:19 +0000</pubDate>
  <dc:modified>Mon, 26 Aug 2024 14:46:39 +0000</dc:modified>
  <atom:modified>Mon, 26 Aug 2024 14:46:39 +0000</atom:modified>
  <link>https://alexn.org/wiki/bitwarden/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/bitwarden/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Gradle</title>
  <description>Article
    updated at May 25, 2024, 
    created at May 25, 2024.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at May 25, 2024, 
    created at May 25, 2024.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;p&gt;Upgrading the Gradle wrapper to the latest version:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;./gradlew wrapper --gradle-version latest
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Sat, 25 May 2024 15:27:05 +0000</pubDate>
  <dc:modified>Sat, 25 May 2024 15:28:04 +0000</dc:modified>
  <atom:modified>Sat, 25 May 2024 15:28:04 +0000</atom:modified>
  <link>https://alexn.org/wiki/gradle/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/gradle/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>OCaml</title>
  <description>Article
    updated at April 15, 2024, 
    created at April 15, 2024.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at April 15, 2024, 
    created at April 15, 2024.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;installing&quot;&gt;Installing&lt;/h2&gt;

&lt;p&gt;For macOS (&lt;a href=&quot;https://opam.ocaml.org/doc/Install.html&quot;&gt;see other platforms&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;brew install opam
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Initialize:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;opam init

# Test
opam switch
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Some utilities:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# For the VS Code extension (OCaml Platform)
opam install ocaml-lsp-server

# OCaml REPL
opam install utop

# Standard library recommended by Real World OCaml
opam install core core_bench
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Mon, 15 Apr 2024 17:23:07 +0000</pubDate>
  <dc:modified>Mon, 15 Apr 2024 17:27:49 +0000</dc:modified>
  <atom:modified>Mon, 15 Apr 2024 17:27:49 +0000</atom:modified>
  <link>https://alexn.org/wiki/ocaml/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/ocaml/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>JavaScript / TypeScript</title>
  <description>Article
    updated at May 30, 2023, 
    created at May 30, 2023.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at May 30, 2023, 
    created at May 30, 2023.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;

&lt;h3 id=&quot;vite&quot;&gt;Vite&lt;/h3&gt;

&lt;p&gt;Starting a new TypeScript + React project, using a &lt;a href=&quot;https://vitejs.dev/guide/&quot;&gt;Vite&lt;/a&gt; template:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;npm create vite@latest name-of-your-project -- \
    --template react-ts
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;webpack&quot;&gt;Webpack:&lt;/h3&gt;

&lt;p&gt;Relevant documentation:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://webpack.js.org/guides/getting-started/&quot;&gt;Getting started&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://webpack.js.org/guides/typescript/&quot;&gt;Using TypeScript&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://bulma.io/&quot;&gt;Bulma&lt;/a&gt;: CSS framework;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://reactrouter.com/&quot;&gt;React Router&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Tue, 30 May 2023 08:05:11 +0000</pubDate>
  <dc:modified>Tue, 30 May 2023 18:16:32 +0000</dc:modified>
  <atom:modified>Tue, 30 May 2023 18:16:32 +0000</atom:modified>
  <link>https://alexn.org/wiki/javascript/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/javascript/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Scala</title>
  <description>Article
    updated at October 6, 2023, 
    created at May 20, 2023.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at October 6, 2023, 
    created at May 20, 2023.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;libraries&quot;&gt;Libraries&lt;/h2&gt;

&lt;p&gt;For building UI:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/oyvindberg/tui-scala&quot;&gt;tui-scala&lt;/a&gt;: Beautiful Text-based User Interfaces for Scala;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/scalafx/scalafx&quot;&gt;ScalaFX&lt;/a&gt;: simplifies the creation of JavaFX-based user interfaces in Scala;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For parsing command-line arguments:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/alexarchambault/case-app&quot;&gt;case-app&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/bkirwi/decline&quot;&gt;decline&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/com-lihaoyi/mainargs&quot;&gt;mainargs&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/scopt/scopt&quot;&gt;scopt&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;documentation&quot;&gt;Documentation&lt;/h2&gt;

&lt;p&gt;Macros:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/lampepfl/dotty-macro-examples&quot;&gt;Scala 3 Metaprogramming Examples (github.com/lampepfl)&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://docs.scala-lang.org/scala3/reference/metaprogramming/index.html&quot;&gt;Scala 3 reference — Metaprogramming&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://eed3si9n.com/intro-to-scala-3-macros/&quot;&gt;Intro to Scala 3 macros (eed3si9n.com)&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://softwaremill.com/scala-3-macros-tips-and-tricks/&quot;&gt;Scala 3 macros tips &amp; tricks (softwaremill.com)&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Sat, 20 May 2023 12:53:40 +0000</pubDate>
  <dc:modified>Fri, 06 Oct 2023 06:36:57 +0000</dc:modified>
  <atom:modified>Fri, 06 Oct 2023 06:36:57 +0000</atom:modified>
  <link>https://alexn.org/wiki/scala/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/scala/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Kotlin</title>
  <description>Article
    updated at January 28, 2025, 
    created at April 30, 2023.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at January 28, 2025, 
    created at April 30, 2023.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;

&lt;p&gt;Kotlin-specific:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://arrow-kt.io/learn/&quot;&gt;Arrow&lt;/a&gt;: Functional companion to Kotlin’s Standard Library;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/Kotlin/kotlinx.serialization&quot;&gt;kotlinx.serialization&lt;/a&gt;: Kotlin multiplatform / multi-format serialization;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://ktor.io/&quot;&gt;Ktor&lt;/a&gt;: HTTP client/server library;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/cashapp/sqldelight&quot;&gt;SQLDelight&lt;/a&gt;: Generates type-safe Kotlin APIs from SQL;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/kropp/kotlinx-gettext/tree/main&quot;&gt;kotlinx-gettext&lt;/a&gt;: I18N library;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CLI:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/ajalt/clikt&quot;&gt;clikt&lt;/a&gt;: Multiplatform command line interface parsing for Kotlin;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/varabyte/kotter&quot;&gt;kotter&lt;/a&gt;: A declarative, Kotlin-idiomatic API for writing dynamic console applications;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;UI, Kotlin/JS:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/JetBrains/kotlin-wrappers/&quot;&gt;kotlin-wrappers&lt;/a&gt;: wrappers for popular JavaScript libraries;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://kvision.io/&quot;&gt;kvision&lt;/a&gt;: web UI framework for Kotlin, alternative to React;
    &lt;ul&gt;
      &lt;li&gt;
&lt;a href=&quot;https://github.com/rjaros/kvision-io/&quot;&gt;kvision-io (GitHub)&lt;/a&gt;: source code for a presentation website built in Kotlin, useful sample of a &lt;a href=&quot;https://webpack.js.org/&quot;&gt;Webpack&lt;/a&gt; configuration that integrates &lt;a href=&quot;https://en.wikipedia.org/wiki/Sass_(style_sheet_language)&quot;&gt;Sass&lt;/a&gt; and &lt;a href=&quot;https://bulma.io/&quot;&gt;Bulma&lt;/a&gt;;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/varabyte/kobweb&quot;&gt;kobweb&lt;/a&gt;: A modern framework for full stack web apps in Kotlin, built upon Compose HTML;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/JetBrains/compose-multiplatform&quot;&gt;compose-multiplatform&lt;/a&gt;: modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Samples:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://gist.github.com/alexandru/7527f83da03a32dbb46c281e95429ed6&quot;&gt;Uncancelable, like in Cats-Effect&lt;/a&gt;;
    &lt;ul&gt;
      &lt;li&gt;Using &lt;a href=&quot;https://github.com/nomisRev/arrow-fx-coroutines-utils/blob/main/src/commonMain/kotlin/io/github/nomisrev/UncancellableRegion.kt&quot;&gt;UncancellableRegion&lt;/a&gt;;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;multiplatform&quot;&gt;Multiplatform&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://klibs.io/&quot;&gt;klibs.io&lt;/a&gt;: browse multiplatform libraries&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://kmp.jetbrains.com/#newProject&quot;&gt;KMP project wizard&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;kotlinjs--faq&quot;&gt;Kotlin/JS — FAQ&lt;/h2&gt;

&lt;h3 id=&quot;integrate-sasscss-files-in-the-webpack-build&quot;&gt;Integrate SASS/CSS files in the Webpack build&lt;/h3&gt;

&lt;p&gt;Declare a &lt;code&gt;require&lt;/code&gt; function:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;@JsName(&quot;require&quot;)
external fun jsRequire(name: String): dynamic
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Declare dependencies in &lt;code&gt;build.gradle.kts&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;implementation(devNpm(&quot;sass&quot;, &quot;^1.62.1&quot;))
implementation(devNpm(&quot;sass-loader&quot;, &quot;^13.2.2&quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For configuring Webpack, create a file &lt;code&gt;webpack.config.d/css.js&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;config.module.rules.push({
    test: /\.css$/,
    use: [
        &quot;style-loader&quot;,
        {
            loader: &quot;css-loader&quot;,
            options: {sourceMap: false}
        }
    ]
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And another file at &lt;code&gt;webpack.config.d/sass.js&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;config.module.rules.push({
    test: /\.s[ac]ss$/,
    use: [
        &quot;style-loader&quot;,
        {
            loader: &quot;css-loader&quot;,
            options: {sourceMap: false}
        },
        &quot;sass-loader&quot;
    ]
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can also declare external dependencies on CSS frameworks, such as &lt;a href=&quot;https://bulma.io/&quot;&gt;Bulma&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;implementation(npm(&quot;bulma&quot;, &quot;^0.9.4&quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Create &lt;code&gt;src/main/resources/sass/main.scss&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-scss&quot;&gt;@import &apos;~bulma/bulma&apos;;

html {
  background-color: antiquewhite;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then in &lt;code&gt;src/main/kotlin/main.kt&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;fun main() {
    jsRequire(&quot;./sass/main.scss&quot;)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Reference: &lt;a href=&quot;https://kotlinlang.slack.com/archives/C0B8L3U69/p1684137369719519&quot;&gt;Slack conversation&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;custom-html-attributes-in-the-kotlin-react-dsl&quot;&gt;Custom HTML attributes in the kotlin-react DSL&lt;/h3&gt;

&lt;p&gt;When using the React DSL from &lt;a href=&quot;https://github.com/JetBrains/kotlin-wrappers/&quot;&gt;kotlin-wrappers&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;import react.dom.html.AnchorHTMLAttributes
import react.dom.html.HTMLAttributes

operator fun HTMLAttributes&lt;*&gt;.get(key: String): String? =
    asDynamic()[key]

operator fun HTMLAttributes&lt;*&gt;.set(key: String, value: String?) {
    if (value == null)
        asDynamic().removeAttribute(key)
    else
        asDynamic()[key] = value
}

var AnchorHTMLAttributes&lt;*&gt;.dataTarget: String?
    get() = this[&quot;data-target&quot;]
    set(value) { this[&quot;data-target&quot;] = value }

//...
import react.dom.html.ReactHTML as html

html.a {
    dataTarget = &quot;siteNavBar&quot;
    //...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Reference: &lt;a href=&quot;https://github.com/JetBrains/kotlin-wrappers/issues/1788&quot;&gt;kotlin-wrappers#1788&lt;/a&gt;.&lt;/p&gt;</content:encoded><pubDate>Sun, 30 Apr 2023 13:07:39 +0000</pubDate>
  <dc:modified>Tue, 28 Jan 2025 16:02:13 +0000</dc:modified>
  <atom:modified>Tue, 28 Jan 2025 16:02:13 +0000</atom:modified>
  <link>https://alexn.org/wiki/kotlin/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/kotlin/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Rclone</title>
  <description>Article
    updated at January 26, 2023, 
    created at January 23, 2023.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at January 26, 2023, 
    created at January 23, 2023.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;install-macos&quot;&gt;Install (macOS)&lt;/h2&gt;

&lt;p&gt;This is required for getting &lt;code&gt;mount&lt;/code&gt; to work properly, see:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/rclone/rclone/issues/5373&quot;&gt;Issue #5373&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/gromgit/homebrew-fuse&quot;&gt;gromgit/homebrew-fuse&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;brew install --cask macfuse

brew install gromgit/fuse/rclone-mac
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;mount-onedrive&quot;&gt;Mount (OneDrive)&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;#!/usr/bin/env bash

LOG_PATH=&quot;$HOME/Library/Logs/rclone-onedrive-mirror.log&quot;
MOUNT_DIR=&quot;$HOME/Library/CloudStorage/OneDrive&quot;
mkdir -p &quot;$MOUNT_DIR&quot;

/usr/local/opt/rclone-mac/libexec/rclone/rclone mount \
    onedrive: &quot;$MOUNT_DIR&quot; \
    --volname &quot;OneDrive&quot; \
    --buffer-size 64M \
    --vfs-read-ahead 512M \
    --vfs-cache-mode full \
    --vfs-cache-max-age 8760h \
    --vfs-cache-max-size 100G \
    --vfs-cache-poll-interval 30s \
    --vfs-write-back 5s \
    --attr-timeout 8700h \
    --dir-cache-time 8760h \
    --poll-interval 30s \
    --log-level INFO \
    --log-file &quot;$LOG_PATH&quot;
    # Optional:
    # --rc \
    # --rc-web-gui \
    # --rc-web-gui-no-open-browser \
    # --rc-htpasswd &quot;$HOME/.config/rclone/htpasswd&quot;

# Optionally, inform the user when the process stops.
# Requires: brew install terminal-notifier
PROC_EXIT_CODE=&quot;$?&quot;
terminal-notifier -title &quot;OneDrive mount stopped!&quot; -message &quot;$LOG_PATH&quot;
exit $PROC_EXIT_CODE
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Web interface is served at &lt;a href=&quot;http://127.0.0.1:5572/&quot;&gt;http://127.0.0.1:5572/&lt;/a&gt;, see: &lt;a href=&quot;https://rclone.org/rc/&quot;&gt;Remote controlling rclone with its API&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;For the cache options used, see: &lt;a href=&quot;https://rclone.org/commands/rclone_mount/#vfs-file-caching&quot;&gt;VFS File Caching&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For serving the remote control web UI, you need credentials:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;touch ~/.config/rclone/htpasswd
htpasswd -B ~/.config/rclone/htpasswd alex
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;macos-service&quot;&gt;macOS service&lt;/h3&gt;

&lt;p&gt;The above command supports a &lt;code&gt;--daemon&lt;/code&gt; option, but I’d like automatic launch at startup, maybe even restarts.
Create a script in &lt;code&gt;~/bin/mount-onedrive&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;~/Library/LaunchAgents/my.rclone-onedrive-mount.plist&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
&lt;plist version=&quot;1.0&quot;&gt;
  &lt;dict&gt;
    &lt;key&gt;KeepAlive&lt;/key&gt;
    &lt;true/&gt;
    &lt;key&gt;Label&lt;/key&gt;
    &lt;string&gt;my.rclone-onedrive-mount&lt;/string&gt;
    &lt;key&gt;ProgramArguments&lt;/key&gt;
    &lt;array&gt;
      &lt;string&gt;/Users/myname/bin/mount-onedrive&lt;/string&gt;
    &lt;/array&gt;
    &lt;key&gt;RunAtLoad&lt;/key&gt;
    &lt;true/&gt;
    &lt;key&gt;UserName&lt;/key&gt;
    &lt;string&gt;myname&lt;/string&gt;
  &lt;/dict&gt;
&lt;/plist&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The service can then be loaded via:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;launchctl load -w ~/Library/LaunchAgents/my.rclone-onedrive-mount.plist
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or unloaded via:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;launchctl unload ~/Library/LaunchAgents/my.rclone-onedrive-mount.plist
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;bisync&quot;&gt;Bisync&lt;/h2&gt;

&lt;p&gt;Alternatively there’s a &lt;a href=&quot;https://rclone.org/bisync/&quot;&gt;bisync&lt;/a&gt; command.&lt;/p&gt;

&lt;p&gt;On first run, the database needs to be initialized, via &lt;code&gt;--resync&lt;/code&gt;, but as a warning, this can override the files of “path2” with those of “path1”.&lt;/p&gt;

&lt;p&gt;This is the &lt;code&gt;onedrive-sync-init&lt;/code&gt; script:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;#!/usr/bin/env bash

function notifyIfError() {
    PROC_EXIT_CODE=&quot;$1&quot;
    if [ &quot;$PROC_EXIT_CODE&quot; -ne 0 ]; then
        terminal-notifier -title &quot;OneDrive sync failed!&quot; -message &quot;Check the logs&quot;
        echo &quot;OneDrive sync failed&quot;
        exit &quot;$PROC_EXIT_CODE&quot;
    fi
}

mkdir -p ~/OneDrive/Bisync
mkdir -p ~/OneDrive/.db

rclone bisync onedrive: ~/OneDrive/Bisync \
    --resync \
    --filters-file ~/.config/rclone/onedrive-filter.conf \
    --workdir ~/OneDrive/.db \
    -v &quot;$@&quot;
notifyIfError &quot;$?&quot;

# Adds .rclone-check files in the top sub-directories
find ~/OneDrive/Bisync -type d -d 1 -exec touch &quot;{}/.rclone-check&quot; \;
notifyIfError &quot;$?&quot;

# Syncs those .rclone-check files
rclone bisync onedrive: ~/OneDrive/Bisync \
    --filters-file ~/.config/rclone/onedrive-filter.conf \
    --workdir ~/OneDrive/.db \
    -v &quot;$@&quot;
notifyIfError &quot;$?&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is the &lt;code&gt;onedrive-sync-periodic&lt;/code&gt; script, which could be installed in crontab:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;#!/usr/bin/env bash

rclone bisync onedrive: ~/OneDrive/Bisync \
    --check-access \
    --check-filename &quot;.rclone-check&quot; \
    --filters-file ~/.config/rclone/onedrive-filter.conf \
    --workdir ~/OneDrive/.db \
    -v &quot;$@&quot;

PROC_EXIT_CODE=&quot;$1&quot;
if [ &quot;$PROC_EXIT_CODE&quot; -ne 0 ]; then
    terminal-notifier -title &quot;OneDrive sync failed!&quot; -message &quot;Check the logs&quot;
    echo &quot;OneDrive sync failed&quot;
    exit &quot;$PROC_EXIT_CODE&quot;
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And then there’s the &lt;code&gt;~/.config/rclone/onedrive-filter.conf&lt;/code&gt; file, which dictates what to sync (aka selective sync):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-conf&quot;&gt;- **/.DS_Store
- **/.localized
- **/*.swp

+ /Documents/**
+ /Scanned/**
+ /Screenshots/**

# Exclude everything by default
- **
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Mon, 23 Jan 2023 11:34:49 +0000</pubDate>
  <dc:modified>Thu, 26 Jan 2023 08:08:50 +0000</dc:modified>
  <atom:modified>Thu, 26 Jan 2023 08:08:50 +0000</atom:modified>
  <link>https://alexn.org/wiki/rclone/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/rclone/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Web Design</title>
  <description>Article
    updated at December 13, 2022, 
    created at December 13, 2022.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at December 13, 2022, 
    created at December 13, 2022.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;p&gt;&lt;img src=&quot;https://alexn.org/wiki/assets/under-construction.gif&quot; alt=&apos;&quot;Under Construction&quot;&apos; style=&quot;max-width:100%;height:auto;&quot; width=&quot;266&quot; height=&quot;266&quot;&gt;&lt;/p&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://getbootstrap.com/&quot;&gt;Bootstrap&lt;/a&gt;: ready-made generic CSS;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.svgrepo.com/&quot;&gt;SVGrepo.com&lt;/a&gt;: collection of SVG Icons;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://codepen.io/sosuke/pen/Pjoqqp&quot;&gt;CSS filter generator&lt;/a&gt;: for colorizing images;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Tue, 13 Dec 2022 13:04:51 +0000</pubDate>
  <dc:modified>Tue, 13 Dec 2022 13:26:01 +0000</dc:modified>
  <atom:modified>Tue, 13 Dec 2022 13:26:01 +0000</atom:modified>
  <link>https://alexn.org/wiki/web-design/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/web-design/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Bookmarklets</title>
  <description>Article
    updated at March 4, 2025, 
    created at December 4, 2022.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at March 4, 2025, 
    created at December 4, 2022.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;about&quot;&gt;About&lt;/h2&gt;

&lt;p&gt;Samples are meant for the &lt;a href=&quot;https://alexn.org/assets/html/bookmarklet-generator/&quot; target=&quot;_blank&quot;&gt;bookmarklet generator&lt;/a&gt; (just a simple HTML+JS file), that generates code compatible with Firefox for Android (as the latter has issues with the classic &lt;code&gt;window.open&lt;/code&gt;, which has to be avoided).&lt;/p&gt;

&lt;h2 id=&quot;sharing&quot;&gt;Sharing&lt;/h2&gt;

&lt;h3 id=&quot;bluesky&quot;&gt;Bluesky&lt;/h3&gt;

&lt;p&gt;URL (page URL and title):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;https://bsky.app/intent/compose?text=%22%t%22%0A%0A%s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://alexn.org/assets/html/bookmarklet-generator/?title=Share%2520on%2520Bluesky&amp;url=https%253A%252F%252Fbsky.app%252Fintent%252Fcompose%253Ftext%253D%252522%2525t%252522%25250A%25250A%2525s&quot; target=&quot;_blank&quot;&gt;👉 Generate bookmarklet&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;mastodon&quot;&gt;Mastodon&lt;/h3&gt;

&lt;p&gt;URL used (both page title and URL):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;https://mastodon.social/share?text=%22%t%22%0A%0A%s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://alexn.org/assets/html/bookmarklet-generator/?title=Share%2520on%2520Mastodon&amp;url=https%253A%252F%252Fmastodon.social%252Fshare%253Ftext%253D%252522%2525t%252522%25250A%25250A%2525s&quot; target=&quot;_blank&quot;&gt;👉 Generate bookmarklet&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;reddit&quot;&gt;Reddit&lt;/h3&gt;

&lt;p&gt;URL (just page URL):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;https://old.reddit.com/submit?url=%s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://alexn.org/assets/html/bookmarklet-generator/?title=Share%2520on%2520Reddit&amp;url=https%253A%252F%252Fold.reddit.com%252Fsubmit%253Furl%253D%2525s&quot; target=&quot;_blank&quot;&gt;👉 Generate bookmarklet&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;linkedin&quot;&gt;LinkedIn&lt;/h3&gt;

&lt;p&gt;URL (just page URL):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;https://www.linkedin.com/sharing/share-offsite/?url=%s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://alexn.org/assets/html/bookmarklet-generator/?title=Share%2520on%2520LinkedIn&amp;url=https%253A%252F%252Fwww.linkedin.com%252Fsharing%252Fshare-offsite%252F%253Furl%253D%2525s&quot; target=&quot;_blank&quot;&gt;👉 Generate bookmarklet&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;facebook&quot;&gt;Facebook&lt;/h3&gt;

&lt;p&gt;URL used (just page URL):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;https://www.facebook.com/sharer.php?src=bm&amp;v=4&amp;i=1628766166&amp;u=%s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://alexn.org/assets/html/bookmarklet-generator/?title=Share%2520on%2520Facebook&amp;url=https%253A%252F%252Fwww.facebook.com%252Fsharer.php%253Fsrc%253Dbm%2526v%253D4%2526i%253D1628766166%2526u%253D%2525s&quot; target=&quot;_blank&quot;&gt;👉 Generate bookmarklet&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;𝕏twitter&quot;&gt;𝕏/Twitter&lt;/h3&gt;

&lt;p&gt;URL used (both page title and URL):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;https://x.com/intent/tweet?text=%22%t%22%0A%0A%s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://alexn.org/assets/html/bookmarklet-generator/?title=Share%2520on%2520%25F0%259D%2595%258F%252FTwitter&amp;url=https%253A%252F%252Fx.com%252Fintent%252Ftweet%253Ftext%253D%252522%2525t%252522%25250A%25250A%2525s&quot; target=&quot;_blank&quot;&gt;👉 Generate bookmarklet&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;subscribing&quot;&gt;Subscribing&lt;/h2&gt;

&lt;h3 id=&quot;linkding&quot;&gt;Linkding&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://linkding.link/&quot;&gt;See homepage&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;URL:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;https://my.linkding.host/bookmarks/new?url=%s&amp;title=%t&amp;auto_close
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://alexn.org/assets/html/bookmarklet-generator/?title=Save&amp;url=https%253A%252F%252Fmy.linkding.host%252Fbookmarks%252Fnew%253Furl%253D%2525s%2526title%253D%2525t%2526auto_close&quot; target=&quot;_blank&quot;&gt;👉 Generate bookmarklet&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;freshrss&quot;&gt;FreshRSS&lt;/h3&gt;

&lt;p&gt;URL:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;https://my.freshrss.host/i/?c=feed&amp;a=add&amp;url_rss=%s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://alexn.org/assets/html/bookmarklet-generator/?title=Subscribe%2520(FreshRSS)&amp;url=https%253A%252F%252Fmy.freshrss.host%252Fi%252F%253Fc%253Dfeed%2526a%253Dadd%2526url_rss%253D%2525s&quot; target=&quot;_blank&quot;&gt;👉 Generate bookmarklet&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;newsblur&quot;&gt;NewsBlur&lt;/h3&gt;

&lt;p&gt;URL:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;https://www.newsblur.com/?url=%s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://alexn.org/assets/html/bookmarklet-generator/?title=Subscribe%2520(NewsBlur)&amp;url=https%253A%252F%252Fwww.newsblur.com%252F%253Furl%253D%2525s&quot; target=&quot;_blank&quot;&gt;👉 Generate bookmarklet&lt;/a&gt;&lt;/p&gt;</content:encoded><pubDate>Sun, 04 Dec 2022 10:01:00 +0000</pubDate>
  <dc:modified>Tue, 04 Mar 2025 17:28:36 +0000</dc:modified>
  <atom:modified>Tue, 04 Mar 2025 17:28:36 +0000</atom:modified>
  <link>https://alexn.org/wiki/bookmarklets/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/bookmarklets/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Mastodon</title>
  <description>Article
    updated at October 9, 2024, 
    created at November 22, 2022.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at October 9, 2024, 
    created at November 22, 2022.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;twitter-migration&quot;&gt;Twitter migration&lt;/h2&gt;

&lt;p class=&quot;warn-bubble&quot;&gt;
&lt;strong&gt;WARN:&lt;/strong&gt; Mastodon ain’t Twitter. Its design and available features are slightly different, as a matter of philosophy.
&lt;/p&gt;

&lt;h3 id=&quot;instances&quot;&gt;Instances&lt;/h3&gt;

&lt;p&gt;Mastodon is “federated”. At &lt;a href=&quot;https://joinmastodon.org/&quot;&gt;joinmastodon.org&lt;/a&gt; you can find a list of instances available, but it’s not complete.&lt;/p&gt;

&lt;p&gt;It’s a good idea to prefer alternatives to &lt;a href=&quot;https://mastodon.social&quot;&gt;mastodon.social&lt;/a&gt;, because this server is being hammered by new traffic. On the other hand, instances are servers maintained by volunteers, so it’s best to find some properly maintained ones.&lt;/p&gt;

&lt;p&gt;For professionals in the software industry, these instances seem to be pretty good:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://fosstodon.org/&quot;&gt;fosstodon.org&lt;/a&gt; (English-only)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hachyderm.io/&quot;&gt;hachyderm.io&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some smaller instances you might want to consider:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://functional.cafe/&quot;&gt;functional.cafe&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://indieweb.social/&quot;&gt;indieweb.social&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://types.pl&quot;&gt;types.pl&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;getting-started-resources&quot;&gt;Getting started resources&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://fedi.tips/how-to-use-mastodon-and-the-fediverse-basic-tips/&quot;&gt;How To Use Mastodon and the Fediverse: Basic Tips&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://blog.joinmastodon.org/2018/08/mastodon-quick-start-guide/&quot;&gt;Quick-start guide&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/joyeusenoelle/GuideToMastodon/&quot;&gt;An Increasingly Less-Brief Guide to Mastodon&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;available-apps&quot;&gt;Available apps&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;The website works well on mobile too;&lt;/li&gt;
  &lt;li&gt;On Android, the official app isn’t very good for now, prefer &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.keylesspalace.tusky&amp;pli=1&quot;&gt;Tusky&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;See list of &lt;a href=&quot;https://joinmastodon.org/apps&quot;&gt;available apps&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;utilities&quot;&gt;Utilities&lt;/h3&gt;

&lt;p&gt;Browser extension that redirects you from Mastodon4 instances to your home instance (makes it easier to follow people):&lt;br&gt;
&lt;a href=&quot;https://github.com/raikasdev/mastodon4-redirect&quot;&gt;mastodon4-redirect&lt;/a&gt; (&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/mastodon4-redirect/&quot; target=&quot;_blank&quot;&gt;Firefox&lt;/a&gt;, &lt;a href=&quot;https://chrome.google.com/webstore/detail/mastodon4-redirect/acbfckpoogjdigldffcbldijhgnjpfnc&quot; target=&quot;_blank&quot;&gt;Chrome&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;To find your Twitter friends on Mastodon: &lt;br&gt;
&lt;a href=&quot;https://fedifinder.glitch.me&quot;&gt;https://fedifinder.glitch.me&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the cool factor, implement “WebFinger” on your own domain: &lt;br&gt;
&lt;a href=&quot;https://rossabaker.com/projects/webfinger/&quot;&gt;https://rossabaker.com/projects/webfinger/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For following Twitter’s drama, without logging into Twitter: &lt;br&gt;
&lt;a href=&quot;https://twitterisgoinggreat.com&quot;&gt;https://twitterisgoinggreat.com&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;download-twitter-archive&quot;&gt;Download Twitter archive&lt;/h3&gt;

&lt;p&gt;Download your Twitter archive and store it somewhere safe, even if you don’t plan on leaving Twitter: &lt;br&gt;
&lt;a href=&quot;https://x.com/settings/download_your_data&quot;&gt;https://x.com/settings/download_your_data&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The archive download is fairly usable. But you might want to parse your archive, to replace &lt;code&gt;t.co&lt;/code&gt; links and spit out markdown files:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://matthiasott.com/notes/converting-your-twitter-archive-to-markdown&quot;&gt;Converting Your Twitter Archive to Markdown&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/timhutton/twitter-archive-parser&quot;&gt;twitter-archive-parser (GitHub)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;leaving-twitter&quot;&gt;Leaving Twitter?&lt;/h3&gt;

&lt;p&gt;First download your Twitter archive and store it somewhere safe: &lt;br&gt;
&lt;a href=&quot;https://x.com/settings/download_your_data&quot;&gt;https://x.com/settings/download_your_data&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’d like to delete your Twitter account, depending on how popular your account is, you might want to avoid deleting it, to prevent impersonation/cybersquatting. I recommend to:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Download your Twitter archive;&lt;/li&gt;
  &lt;li&gt;Delete all your tweets: &lt;a href=&quot;https://tweetdelete.net&quot;&gt;https://tweetdelete.net&lt;/a&gt;
&lt;/li&gt;
  &lt;li&gt;Modify your profile to inform your visitors that you moved;&lt;/li&gt;
  &lt;li&gt;Maybe also lock your account, to prevent new followers;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;self-hosting&quot;&gt;Self-Hosting&lt;/h2&gt;

&lt;p&gt;I have self-hosted my own Mastodon instance at &lt;a href=&quot;https://social.alexn.org&quot;&gt;https://social.alexn.org&lt;/a&gt; (at the time of writing I’ve moved to &lt;a href=&quot;https://mastodon.social/@alexelcu&quot;&gt;https://mastodon.social/@alexelcu&lt;/a&gt;).
This is my own configuration, tuned to my needs…&lt;/p&gt;

&lt;h3 id=&quot;services-used&quot;&gt;Services used&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.hetzner.com/cloud&quot;&gt;Hetzner&lt;/a&gt;, for a VPS with 4 GB of RAM and
40 GB of disk space; 2 GB should be fine, but it may need a swap setup;
I might also need more disk space in the future, or block storage;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.cloudflare.com/&quot;&gt;Cloudflare&lt;/a&gt; because it can save you bandwidth
(must ensure correct caching setup);&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.fastmail.com/&quot;&gt;Fastmail&lt;/a&gt; for sending emails via SMTP, as I was
already using it for my personal email, and supports SMTP-only passwords;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.backblaze.com/cloud-storage&quot;&gt;Backblaze B2&lt;/a&gt; for backups
and potentially for storing cached files;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;docker-docker-compose&quot;&gt;Docker (docker-compose)&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;version: &apos;3.8&apos;

services:
  redis:
    container_name: redis
    image: redis:7
    restart: unless-stopped
    command: /bin/sh -c &quot;redis-server --appendonly yes --requirepass $$REDIS_PASSWORD&quot;
    healthcheck:
      test: [&apos;CMD&apos;, &apos;redis-cli&apos;, &apos;-a&apos;, &apos;$$REDIS_PASSWORD&apos;, &apos;ping&apos;]
    volumes:
      - redis:/data
    networks:
      - internal_network
    sysctls: # https://github.com/docker-library/redis/issues/191#issuecomment-528693994
      - net.core.somaxconn=511
    env_file:
      ./envs/redis.env

  postgresdb:
    container_name: postgresdb
    image: &apos;postgres:15-alpine&apos;
    healthcheck:
      test: [&apos;CMD&apos;, &apos;pg_isready&apos;, &apos;-U&apos;, &apos;postgres&apos;]
    volumes:
      - &apos;postgres-db:/var/lib/postgresql/data&apos;
    restart: unless-stopped
    env_file:
      - ./envs/postgres.env
    networks:
      - internal_network

  mastodon-web:
    container_name: mastodon-web
    image: &apos;ghcr.io/mastodon/mastodon:latest&apos;
    command: &apos;bash -c &quot;bundle exec rake db:migrate &amp;&amp; rm -f /mastodon/tmp/pids/server.pid &amp;&amp; bundle exec rails s -p 3000&quot;&apos;
    ports:
      - 3000:3000
    restart: unless-stopped
    healthcheck:
      test: [&apos;CMD-SHELL&apos;, &apos;wget -q --spider --proxy=off localhost:3000/health || exit 1&apos;]
    volumes:
      - &apos;mastodon-volume:/mastodon/public/system&apos;
    env_file:
      - ./envs/mastodon.env
    depends_on:
      - postgresdb
      - redis
    networks:
      - internal_network
      - external_network

  mastodon-sidekiq:
    container_name: mastodon-sidekiq
    image: &apos;ghcr.io/mastodon/mastodon&apos;
    command: &apos;bundle exec sidekiq&apos;
    restart: unless-stopped
    healthcheck:
      test: [&apos;CMD-SHELL&apos;, &quot;ps aux | grep &apos;[s]idekiq\ 6&apos; || false&quot;]
    volumes:
      - &apos;mastodon-volume:/mastodon/public/system&apos;
    env_file:
      - ./envs/mastodon.env
    depends_on:
      - postgresdb
      - redis
    networks:
      - internal_network
      - external_network

  mastodon-streaming:
    container_name: mastodon-streaming
    image: &apos;ghcr.io/mastodon/mastodon-streaming:latest&apos;
    restart: always
    command: node ./streaming/index.js
    healthcheck:
      test: [&apos;CMD-SHELL&apos;, &quot;curl -s --noproxy localhost localhost:4000/api/v1/streaming/health | grep -q &apos;OK&apos; || exit 1&quot;]
    ports:
      - &apos;127.0.0.1:4000:4000&apos;
    env_file:
      - ./envs/mastodon.env
    depends_on:
      - postgresdb
      - redis
    networks:
      - external_network
      - internal_network

networks:
  external_network:
  internal_network:
    internal: true

volumes:
  redis:
  postgres-db:
  mastodon-volume:
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;File &lt;code&gt;redis.env&lt;/code&gt; for the Redis database:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;REDIS_PASSWORD=&quot;&lt;your redis pass&gt;&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;File &lt;code&gt;postgres.env&lt;/code&gt; for the Postgres database:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;POSTGRES_PASSWORD=&quot;&lt;password for &apos;postgres&apos; admin&gt;&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;File &lt;code&gt;mastodon.env&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;RAILS_ENV=&quot;production&quot;
LOCAL_DOMAIN=&quot;social.alexn.org&quot;
# WEB_DOMAIN=&quot;social.alexn.org&quot;

# Must create DB user and database
DB_HOST=&quot;postgresdb&quot;
DB_NAME=&quot;mastodon&quot;
DB_USER=&quot;mastodon&quot;
DB_PASS=

# Must reuse the password from `redis.env`
REDIS_URL=&quot;redis://default:password@redis:6379&quot;

# -----------
# App Secrets
# -----------
# Can be generated with:
# docker-compose run --rm mastodon-web bundle exec rake secret
# -----------
SECRET_KEY_BASE=
OTP_SECRET=

# -----------
# Secrets for DB encryption
# -----------
# Can be generated with:
# docker run -it ghcr.io/mastodon/mastodon:latest bin/rails db:encryption:init
# -----------
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=

# ----------------------
# Web Push Notifications
# ----------------------
# Generate with `rake mastodon:webpush:generate_vapid_key`
#
# docker exec mastodon-web bundle exec rake mastodon:webpush:generate_vapid_key
# ----------------------
VAPID_PRIVATE_KEY=
VAPID_PUBLIC_KEY=

# --------
MASTODON_ADMIN_USERNAME=&quot;alexelcu&quot;
MASTODON_ADMIN_EMAIL=&quot;alexelcu@social.alexn.org&quot;

# ------------------------------------------
# Email settings / via external SMTP service
# ------------------------------------------
# See Fastmail&apos;s App Passwords:
# https://www.fastmail.help/hc/en-us/articles/360058752854-App-passwords
# ------------------------------------------
SMTP_SERVER=&quot;smtp.fastmail.com&quot;
SMTP_PORT=465
SMTP_FROM_ADDRESS=&quot;noreply@social.alexn.org&quot;
SMTP_LOGIN=
SMTP_PASSWORD=

# --------------------------------
# For enabling cloud block storage
# --------------------------------
# S3_ENABLED=true
# S3_PROTOCOL=https
# S3_ENDPOINT=https://s3.eu-central-003.backblazeb2.com
# S3_HOSTNAME=s3.eu-central-003.backblazeb2.com
# S3_BUCKET=alexn-social-files
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
# S3_ALIAS_HOST=&quot;files-social.alexn.org&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;postgres-setup&quot;&gt;Postgres Setup&lt;/h3&gt;

&lt;p&gt;To create the database for Mastodon, first connect via the &lt;code&gt;psql&lt;/code&gt; client:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker exec -it postgresdb psql -U postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then run:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE DATABASE mastodon;
CREATE USER mastodon WITH ENCRYPTED PASSWORD &apos;your-password&apos;;
GRANT ALL PRIVILEGES ON DATABASE mastodon TO mastodon;
-- Above was apparently not enough to run DB migrations,
-- so this is needed too:
ALTER DATABASE mastodon OWNER TO mastodon;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;nginx-config&quot;&gt;Nginx Config&lt;/h3&gt;

&lt;p&gt;Mastodon has an official recommended Nginx configuration
(&lt;a href=&quot;https://github.com/mastodon/mastodon/blob/v4.0.2/dist/nginx.conf&quot;&gt;see their repository&lt;/a&gt;),
however I am hosting Mastodon inside a Docker container, and using Cloudflare, which makes
things more complicated.&lt;/p&gt;

&lt;p class=&quot;info-bubble&quot;&gt;
Make sure to check your HTTP caching headers (&lt;code&gt;Cache-Control&lt;/code&gt;), and ensure
it plays well with Cloudflare 😉
&lt;/p&gt;

&lt;p&gt;Here’s my &lt;code&gt;/etc/nginx/available-sites/social.alexn.org.conf&lt;/code&gt; file:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-conf&quot;&gt;upstream backend {
    server 127.0.0.1:3000 fail_timeout=0;
}

upstream streaming {
    server 127.0.0.1:4000 fail_timeout=0;
}

server {
    server_name social.alexn.org;
    listen   80;
    listen   [::]:80;

    access_log /var/log/nginx/social.alexn.org.log combined;

    location ~ /.well-known {
        root   /var/www/social.alexn.org;
        allow all;
        break;
    }

    location / {
        rewrite ^(.*)$ https://social.alexn.org$1 permanent;
    }
}

server {
    server_name social.alexn.org;
    listen 443 ssl;
    listen [::]:443 ssl;

    access_log /var/log/nginx/social.alexn.org.log combined;

    ###############
    # SSL

    # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
    ssl_certificate /etc/letsencrypt/live/alexn.org/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/alexn.org/privkey.pem;

    ## verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /etc/letsencrypt/live/alexn.org/fullchain.pem;

    # Common config
    include ./snippets/ssl.conf;

    # END SSL
    ##############

    keepalive_timeout    70;
    sendfile             on;
    client_max_body_size 80m;

    root /var/www/social.alexn.org;
    include ./snippets/gzip.conf;

    location / {
        proxy_pass http://backend;
        include ./snippets/proxy-backend.conf;
    }

    location = /sw.js {
        proxy_pass http://backend;
        add_header Cache-Control &quot;public, max-age=604800, must-revalidate&quot;;
        include ./snippets/proxy-backend.conf;
    }

    location ~ ^/system/ {
        proxy_pass http://backend;
        add_header Cache-Control &quot;public, max-age=2419200, immutable&quot;;
        include ./snippets/proxy-backend.conf;
    }

    location ~ ^/(assets/|avatars/|emoji/|headers/|packs/|shortcuts/|sounds/) {
        proxy_pass http://backend;
        add_header Cache-Control &quot;public, max-age=2419200, must-revalidate&quot;;
        include ./snippets/proxy-backend.conf;
    }

    location ^~ /api/v1/streaming {
        proxy_pass http://streaming;
        include ./snippets/proxy-streaming.conf;
    }

    error_page 500 501 502 503 504 /500.html;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Depends on this &lt;code&gt;./snippets/ssl.conf&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-conf&quot;&gt;###
# https://ssl-config.mozilla.org/#server=nginx&amp;version=1.17.7&amp;config=intermediate&amp;openssl=1.1.1k&amp;guideline=5.6

ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;  # about 40000 sessions
ssl_session_tickets off;

# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
ssl_dhparam /etc/nginx/certs/dh2048.pem;

# intermediate configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;

# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security &quot;max-age=63072000; includeSubdomains; preload&quot;;

# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Also, depends on &lt;code&gt;./snippets/proxy-backend.conf&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-conf&quot;&gt;include ./snippets/cloudflare-ips.conf;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Proxy &quot;&quot;;
proxy_pass_header Server;

proxy_buffering on;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

proxy_cache CACHE;
proxy_cache_valid 200 7d;
proxy_cache_valid 410 24h;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;

add_header X-Cached $upstream_cache_status;
tcp_nodelay on;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Also, depends on &lt;code&gt;./snippets/proxy-streaming.conf&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-conf&quot;&gt;include ./snippets/cloudflare-ips.conf;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Proxy &quot;&quot;;

proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Also, depends on &lt;code&gt;./snippets/cloudflare-ips.conf&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-conf&quot;&gt;## Docs:
# https://support.cloudflare.com/hc/en-us/articles/200170786-Restoring-original-visitor-IPs-Logging-visitor-IP-addresses-with-mod-cloudflare-
#
# MUST KEEP UP TO DATE!

# https://www.cloudflare.com/ips-v4
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;

# https://www.cloudflare.com/ips-v6
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;

real_ip_header CF-Connecting-IP;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Also, depends on this &lt;code&gt;./snippets/gzip.conf&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-conf&quot;&gt;gzip on;
gzip_disable &quot;msie6&quot;;

# Enable compression both for HTTP/1.0 and HTTP/1.1.
gzip_http_version  1.1;

# Compression level (1-9).
# 5 is a perfect compromise between size and cpu usage, offering about
# 75% reduction for most ascii files (almost identical to level 9).
gzip_comp_level    6;

# Don&apos;t compress anything that&apos;s already small and unlikely to shrink much
# if at all (the default is 20 bytes, which is bad as that usually leads to
# larger files after gzipping).
gzip_min_length    256;

# Compress data even for clients that are connecting to us via proxies,
# identified by the &quot;Via&quot; header (required for CloudFront).
gzip_proxied       any;

# Tell proxies to cache both the gzipped and regular version of a resource
# whenever the client&apos;s Accept-Encoding capabilities header varies;
# Avoids the issue where a non-gzip capable client (which is extremely rare
# today) would display gibberish if their proxy gave them the gzipped version.
gzip_vary          on;

# Sets the number and size of buffers used to compress a response.
# By default, the buffer size is equal to one memory page.
# This is either 4K or 8K, depending on a platform.
gzip_buffers	16 8k;

# Compress all output labeled with one of the following MIME-types.
gzip_types
	application/atom+xml
	application/font-woff
	application/javascript
	application/json
	application/rss+xml
	application/vnd.ms-fontobject
	application/x-font-ttf
	application/x-font-woff
	application/x-web-app-manifest+json
	application/xhtml+xml
	application/xml
	application/xml+rss
	font/opentype
	font/woff
	font/woff2
	image/svg+xml
	image/x-icon
	text/css
	text/javascript
	text/plain
	text/x-component
	text/xml;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;backups&quot;&gt;Backups&lt;/h3&gt;

&lt;p&gt;Script for periodically backing up Postgres via &lt;code&gt;rclone&lt;/code&gt;, to install in &lt;code&gt;cron.d&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;#!/usr/bin/env bash

set -e

FILENAME=&quot;postgres-$(date +&quot;%Y-%m&quot;).sql.gz&quot;
FILEPATH=&quot;/var/lib/my-backups/$FILENAME&quot;

mkdir -p /var/lib/my-backups

docker exec -i postgresdb pg_dumpall -U postgres | gzip &gt; &quot;$FILEPATH&quot;

if [ -f &quot;$FILEPATH&quot; ]; then
  rclone copy &quot;$FILEPATH&quot; &quot;backup:Postgres/&quot;
fi

rm -f /var/lib/my-backups/postgres-*.sql.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Script for periodically backing up your media files (but without the cache),
via &lt;code&gt;rclone&lt;/code&gt;, to install in &lt;code&gt;cron.d&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;#!/usr/bin/env bash

set -e

FILENAME=&quot;mastodon-volume.tar&quot;
FILEPATH=&quot;/var/lib/my-backups/$FILENAME&quot;

docker run \
    --rm \
    --volumes-from mastodon-web \
    -v /var/lib/my-backups:/backup \
    ubuntu \
    tar --exclude=&apos;mastodon/public/system/cache&apos; -cf &quot;/backup/$FILENAME&quot; -C / &quot;mastodon/public/system&quot; \
    2&gt;&amp;1

if [ -f &quot;$FILEPATH&quot; ]; then
  rclone copy &quot;$FILEPATH&quot; &quot;backup:Mastodon/&quot;
  rm -f &quot;$FILEPATH&quot;
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;p class=&quot;warn-bubble&quot;&gt;
There may be better ways of doing this (like simply using block storage),
I’m still learning.
&lt;/p&gt;</content:encoded><pubDate>Tue, 22 Nov 2022 09:55:19 +0000</pubDate>
  <dc:modified>Wed, 09 Oct 2024 10:37:21 +0000</dc:modified>
  <atom:modified>Wed, 09 Oct 2024 10:37:21 +0000</atom:modified>
  <link>https://alexn.org/wiki/mastodon/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/mastodon/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Java</title>
  <description>Article
    updated at April 4, 2025, 
    created at September 12, 2022.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at April 4, 2025, 
    created at September 12, 2022.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;

&lt;h3 id=&quot;core-functionality&quot;&gt;Core functionality&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/google/guava&quot;&gt;Guava&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/vavr-io/vavr&quot;&gt;Vavr&lt;/a&gt;: persistent collections, Scala-inspired;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/hrldcpr/pcollections&quot;&gt;PCollections&lt;/a&gt;: persistent collections;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;sql-libraries&quot;&gt;SQL libraries&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://hibernate.org/&quot;&gt;Hibernate&lt;/a&gt;: ORM, and I hate ORMs;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://jdbi.org/&quot;&gt;JDBI&lt;/a&gt;: light layer on top of JDBC, string-based queries;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.jooq.org/&quot;&gt;jOOQ&lt;/a&gt;: type safe SQL, alternative to Hibernate;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;database-migrations&quot;&gt;Database migrations&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://flywaydb.org/&quot;&gt;Flyway&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.liquibase.org/&quot;&gt;Liquidbase&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;frameworks&quot;&gt;Frameworks&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.dropwizard.io/&quot;&gt;Dropwizard&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://quarkus.io/&quot;&gt;Quarkus&lt;/a&gt;: built for compatibility with GraalVM’s native image;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://spring.io/projects/spring-boot/&quot;&gt;Spring Boot&lt;/a&gt; (see &lt;a href=&quot;https://start.spring.io/&quot;&gt;the initializer&lt;/a&gt;);&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;tools&quot;&gt;Tools&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://gradle.org/&quot;&gt;Gradle&lt;/a&gt;: the accepted Maven alternative;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.jbang.dev/&quot;&gt;JBang&lt;/a&gt;: scripting with Java;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;

&lt;h3 id=&quot;sdkman&quot;&gt;SDKMan!&lt;/h3&gt;

&lt;p&gt;Install:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;https://sdkman.io/install
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To list available Java SDKs:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sdk list java
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To install:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# OpenJDK
sdk install java 11.0.2-open

# GraalVM
sdk install 22.2.r17-grl

# Oracle
sdk install 17.0.4-oracle
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After the installation of GraalVM, add this to &lt;code&gt;.zshrc&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;export GRAALVM_HOME=$HOME/.sdkman/candidates/java/22.2.r17-grl/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Also install the &lt;code&gt;native-image&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;${GRAALVM_HOME}/bin/gu install native-image
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;openjdk-builds&quot;&gt;OpenJDK Builds&lt;/h3&gt;

&lt;p&gt;Noteworthy:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://adoptium.net/&quot;&gt;Eclipse Temurin&lt;/a&gt;: the old AdoptOpenJDK;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://developer.ibm.com/languages/java/semeru-runtimes/&quot;&gt;IBM Semeru&lt;/a&gt;: these are the new &lt;a href=&quot;https://www.eclipse.org/openj9/&quot;&gt;OpenJ9&lt;/a&gt; builds;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://jdk.java.net/&quot;&gt;jdk.java.net&lt;/a&gt;: reference OpenJDK builds;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also see: &lt;a href=&quot;https://sdkman.io/jdks&quot;&gt;JDK distributions&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;resources--links&quot;&gt;Resources / Links&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://piotrminkowski.com/2021/02/01/new-developer-friendly-features-after-java-8/&quot;&gt;New Developer Friendly Features After Java 8&lt;/a&gt; — Piotr Mińkowski;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://advancedweb.hu/new-language-features-since-java-8-to-18/&quot;&gt;New language features since Java 8 to 18&lt;/a&gt; — Dávid Csákvári;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;dependency-injection--cdi&quot;&gt;Dependency injection / CDI&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://stackoverflow.com/questions/58544079/quarkus-cdi-and-java-config-di-definitions&quot;&gt;Quarkus / CDI and “java config” DI definitions&lt;/a&gt;;
    &lt;ul&gt;
      &lt;li&gt;
&lt;a href=&quot;https://blog.ploeh.dk/2011/07/28/CompositionRoot/&quot;&gt;Composition Root&lt;/a&gt;;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;gc--garbage-collection-tweaks&quot;&gt;GC / Garbage Collection tweaks&lt;/h2&gt;

&lt;p&gt;Since Java 24+:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-XX:+UnlockExperimentalVMOptions -XX:+UseCompactObjectHeaders
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Mon, 12 Sep 2022 05:58:10 +0000</pubDate>
  <dc:modified>Fri, 04 Apr 2025 09:15:04 +0000</dc:modified>
  <atom:modified>Fri, 04 Apr 2025 09:15:04 +0000</atom:modified>
  <link>https://alexn.org/wiki/java/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/java/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Chromium (Brave, Vivaldi, …)</title>
  <description>Article
    updated at February 4, 2023, 
    created at September 1, 2022.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at February 4, 2023, 
    created at September 1, 2022.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;favorite-extensions&quot;&gt;Favorite Extensions&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/1password-%E2%80%93-password-mana/aeblfdkhhhdcdjpifhhbdiojplfjncoa&quot;&gt;1Password&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/chatgpt-for-google/jgjaeacdkonaoafenlfkkkmbaopkbilf&quot;&gt;ChatGPT for Google&lt;/a&gt; (&lt;a href=&quot;https://github.com/wong2/chatgpt-google-extension&quot;&gt;GitHub&lt;/a&gt;): displays ChatGPT response alongside search results, works with all search engines, not just Google;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/consent-o-matic/mdjildafknihdffpkfmmpnpoiajfjnjd&quot;&gt;Consent-o-matic&lt;/a&gt; (&lt;a href=&quot;https://github.com/cavi-au/Consent-O-Matic&quot;&gt;GitHub&lt;/a&gt;): automatic handling of GDPR consent popups;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/dark-reader/eimadpbcbfnmbkopoojfekhnkhdbieeh&quot;&gt;Dark Reader&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/enhancer-for-youtube/ponfpcnoihfmfllpaingbgckeeldkhle&quot;&gt;Enhancer for YouTube&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/grammar-spell-checker-%E2%80%94-l/oldceeleldhonbafppcapldpdifcinji?utm_source=lt-homepage&quot;&gt;LanguageTool&lt;/a&gt;: for spell-checking, can run with a local server (&lt;code&gt;brew install languagetool&lt;/code&gt;);&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/leechblock-ng/blaaajhemilngeeffpbfkdjjoefldkok&quot;&gt;LeechBlock NG&lt;/a&gt;: Time-based restrictions for websites;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/netflix-1080p/cankofcoohmbhfpcemhmaaeennfbnmgp&quot;&gt;Netflix 1080p&lt;/a&gt; (&lt;a href=&quot;https://github.com/truedread/netflix-1080p&quot;&gt;GitHub&lt;/a&gt;): enables 1080p on Netflix;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/old-reddit-redirect/dneaehbmnbhcippjikoajpoabadpodje&quot;&gt;Old Reddit Redirect&lt;/a&gt; (&lt;a href=&quot;https://github.com/tom-james-watson/old-reddit-redirect&quot;&gt;GitHub&lt;/a&gt;): redirects all Reddit links to &lt;code&gt;old.reddit.com&lt;/code&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/picture-in-picture-extens/hkgfoiooedgoejojocmhlaklaeopbecg&quot;&gt;Picture-in-Picture Extension (by Google)&lt;/a&gt; (make sure to disable Google Analytics);&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/save-to-pocket/niloccemoadcdkdjlinkgdfekeahmflj&quot;&gt;Save to Pocket&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/tab-pinner/mcclikmfcmcpejkaobpfkmmbekbhedoi&quot;&gt;Tab pinner&lt;/a&gt; (&lt;a href=&quot;https://github.com/bibixx/tab-pinner&quot;&gt;GitHub&lt;/a&gt;): adds a keyboard shortcut for pinning/unpinning a tab;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/tabliss-a-beautiful-new-t/hipekcciheckooncpjeljhnekcoolahp&quot;&gt;Tabliss&lt;/a&gt; (&lt;a href=&quot;https://github.com/joelshepherd/tabliss&quot;&gt;GitHub&lt;/a&gt;): a customizable new tab page with beautiful backgrounds;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm&quot;&gt;uBlock Origin&lt;/a&gt;, the best ad-blocker, deprecated due to MV3;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/vimium/dbepggeogbaibhgnhhndojpepiihcmeb&quot;&gt;Vimium&lt;/a&gt; (&lt;a href=&quot;https://github.com/philc/vimium&quot;&gt;GitHub&lt;/a&gt;): adds some Vim-like keyboard shortcuts;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ad-blocking compatible with Manifest v3:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/adguard-adblocker-mv3-exp/apjcbfpjihpedihablmalmbbhjpklbdf/related&quot;&gt;AdGuard AdBlocker MV3 Experimental&lt;/a&gt;: an experimental ad-blocker, built on top of Manifest v3;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://chrome.google.com/webstore/detail/ublock-origin-lite/ddkjiahejlhfcafbddmgiahcphecmpfh&quot;&gt;uBlock Origin Lite&lt;/a&gt;: a version of uBlock Origin based on Manifest V3;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;internal-urls&quot;&gt;Internal URLs&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;about://chrome-urls&quot;&gt;about://chrome-urls&lt;/a&gt;: lists all special URLs;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;about://flags&quot;&gt;about://flags&lt;/a&gt;: for activating experimental browser features;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Brave-specific:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;about://adblock&quot;&gt;brave://adblock&lt;/a&gt;: for adding extra filter lists to Brave;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;brave://rewards-internals/&quot;&gt;brave://rewards-internals&lt;/a&gt;: for debugging Brave’s Rewards;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;chrome-alternatives&quot;&gt;Chrome alternatives&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://brave.com/&quot;&gt;Brave&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.bromite.org/&quot;&gt;Bromite&lt;/a&gt; (Android)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/ungoogled-software/ungoogled-chromium&quot;&gt;Ungoogled Chromium&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://vivaldi.com/&quot;&gt;Vivaldi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;misc&quot;&gt;Misc&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://madaidans-insecurities.github.io/firefox-chromium.html&quot;&gt;Firefox and Chromium Security (2020)&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20210105142528/https://madaidans-insecurities.github.io/firefox-chromium.html&quot;&gt;archive&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://neugierig.org/software/blog/2022/12/chrome.html&quot;&gt;Chrome, 10 years later (2022)&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20221209034236/https://neugierig.org/software/blog/2022/12/chrome.html&quot;&gt;archive&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Thu, 01 Sep 2022 13:10:16 +0000</pubDate>
  <dc:modified>Sat, 04 Feb 2023 19:27:24 +0000</dc:modified>
  <atom:modified>Sat, 04 Feb 2023 19:27:24 +0000</atom:modified>
  <link>https://alexn.org/wiki/chromium/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/chromium/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Ubuntu Server</title>
  <description>Article
    updated at September 1, 2022, 
    created at March 11, 2022.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at March 11, 2022.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;initial-setup-firewall-user-updates&quot;&gt;Initial setup (firewall, user, updates)&lt;/h2&gt;

&lt;p&gt;As &lt;code&gt;root&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Installing available security updates
apt update &amp;&amp; apt upgrade

# Enabling firewall (super important!)
apt install ufw
ufw default deny incoming
# I&apos;ve decided to be super strict and block everything by default

# SSH
ufw allow in 22
# HTTP(S)
ufw allow in 80
ufw allow in 443
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can also configure the firewall to deny outgoing connections:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ufw default deny outgoing
# SSH
ufw allow out 22
# HTTP(S)
ufw allow out 80
ufw allow out 443

# Allow DNS requests
ufw allow out 53

# Allow outgoing SMTP via FastMail
ufw allow out 587
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Enable ufw (after making sure that SSH is enabled):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ufw --force enable
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Status should now look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;root@vm~# ufw status
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
80                         ALLOW       Anywhere
443                        ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
80 (v6)                    ALLOW       Anywhere (v6)
443 (v6)                   ALLOW       Anywhere (v6)

80                         ALLOW OUT   Anywhere
443                        ALLOW OUT   Anywhere
53                         ALLOW OUT   Anywhere
587                        ALLOW OUT   Anywhere
80 (v6)                    ALLOW OUT   Anywhere (v6)
443 (v6)                   ALLOW OUT   Anywhere (v6)
53 (v6)                    ALLOW OUT   Anywhere (v6)
587 (v6)                   ALLOW OUT   Anywhere (v6)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Fix the UFW+Docker combination via &lt;a href=&quot;https://github.com/chaifeng/ufw-docker&quot;&gt;ufw-docker&lt;/a&gt; utility (otherwise Docker will just ignore your firewall rules):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;wget -O /usr/local/bin/ufw-docker \
  https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker

chmod +x /usr/local/bin/ufw-docker

ufw-docker install

systemctl restart ufw
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Creating a new user and disabling &lt;code&gt;root&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;adduser alex
# Adds the user to sudoers
usermod -aG sudo alex

# Create its OpenSSH config
mkdir /home/alex/.ssh
vim /home/alex/.ssh/authorized_keys
chmod -R go-rwx /home/alex/.ssh
chown -R alex:alex /home/alex/.ssh

# Disable root&apos;s password
passwd -l root

# It&apos;s a good time to reboot
reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Setup automatic updates:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo apt-get install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Edit &lt;code&gt;/etc/apt/apt.conf.d/50unattended-upgrades&lt;/code&gt; for customizations.&lt;/p&gt;

&lt;h2 id=&quot;secure-openssh&quot;&gt;Secure OpenSSH&lt;/h2&gt;

&lt;p&gt;Edit the config file:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo vim /etc/ssh/sshd_config
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Add these options:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Port 22
Protocol 2
LoginGraceTime 30
PermitRootLogin no
AllowUsers alex
StrictModes yes
MaxAuthTries 3
IgnoreRhosts yes
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
KerberosAuthentication no
GSSAPIAuthentication no
UsePAM no
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
PrintMotd yes
ClientAliveInterval 6m
ClientAliveCountMax 0
UseDNS no
PermitTunnel no
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;configure-sending-emails-via-fastmail-or-another-smtp-server&quot;&gt;Configure sending emails via FastMail (or another SMTP server)&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;sudo apt-get install postfix mailutils libsasl2-2 ca-certificates libsasl2-modules
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Add the following lines in &lt;code&gt;/etc/postfix/main.cf&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;relayhost = [smtp.fastmail.com]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_tls_CAfile = /etc/postfix/cacert.pem
smtp_use_tls = yes
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Create &lt;code&gt;/etc/postfix/sasl_passwd&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[smtp.fastmail.com]:587 username:password
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Fix the permissions:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo chmod 400 /etc/postfix/sasl_passwd
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Tell postfix about the password entry:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo postmap /etc/postfix/sasl_passwd
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Download the &lt;a href=&quot;https://www.thawte.com/roots/&quot;&gt;Thawte Primary Root CA&lt;/a&gt; if not available:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cd /etc/ssl/certs/
sudo wget https://www.thawte.com/roots/thawte_Primary_Root_CA.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then create &lt;code&gt;cacert.pem&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo cp /etc/ssl/certs/thawte_Primary_Root_CA.pem /etc/postfix/cacert.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Restart the service:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo /etc/init.d/postfix reload
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Test it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;echo &quot;Test Email message body&quot; | mail -s &quot;Email test subject&quot;  test@domain.tld
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;install-clamav-anti-virus&quot;&gt;Install ClamAV anti-virus&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo apt install clamav -y
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Update its definitions:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo systemctl stop clamav-freshclam

sudo freshclam

sudo systemctl start clamav-freshclam
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;install-swap-file&quot;&gt;Install swap file&lt;/h2&gt;

&lt;p&gt;Source: &lt;a href=&quot;https://bookofzeus.com/harden-ubuntu/server-setup/add-swap/&quot;&gt;https://bookofzeus.com/harden-ubuntu/server-setup/add-swap/&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# Let&apos;s check if a SWAP file exists and it&apos;s enabled before we create one.
sudo swapon -s

# To create the SWAP file, you will need to use this.
sudo fallocate -l 4G /swapfile

# Secure swap.
sudo chown root:root /swapfile
sudo chmod 0600 /swapfile

# Prepare the swap file by creating a Linux swap area.
sudo mkswap /swapfile

# Activate the swap file.
sudo swapon /swapfile

# Confirm that the swap partition exists.
sudo swapon -s

# This will last until the server reboots. Let&apos;s create the entry in the fstab.
sudo nano /etc/fstab
: /swapfile	none	swap	sw	0 0

# Swappiness in the file should be set to 0. Skipping this step may cause both poor performance,
# whereas setting it to 0 will cause swap to act as an emergency buffer, preventing out-of-memory crashes.
echo 0 | sudo tee /proc/sys/vm/swappiness
echo vm.swappiness = 0 | sudo tee -a /etc/sysctl.conf
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Fri, 11 Mar 2022 11:59:24 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:25:55 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:25:55 +0000</atom:modified>
  <link>https://alexn.org/wiki/ubuntu-server/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/ubuntu-server/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Excel</title>
  <description>Article
    updated at September 1, 2022, 
    created at January 29, 2022.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at January 29, 2022.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;p&gt;Shortcuts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;code&gt;Ctrl-D&lt;/code&gt;/&lt;code&gt;Cmd-D&lt;/code&gt;: fill the selected cell with the content of the cell above;&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;Ctrl-G&lt;/code&gt;: “go to” any area;&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;Ctrl-K&lt;/code&gt;/&lt;code&gt;Cmd-K&lt;/code&gt;: insert hyperlink;&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;Ctrl-L&lt;/code&gt;: define name for cell range;&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;Ctrl-R&lt;/code&gt;/&lt;code&gt;Cmd-R&lt;/code&gt;: fill the selected cell with the content of the cell on the left;&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;Ctrl-;&lt;/code&gt;: enter the current date in a cell;&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;Cmd-;&lt;/code&gt;: enter the current time in a cell;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Sat, 29 Jan 2022 16:21:03 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:20:41 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:20:41 +0000</atom:modified>
  <link>https://alexn.org/wiki/excel/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/excel/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Unix shell (CLI)</title>
  <description>Article
    updated at May 15, 2023, 
    created at January 29, 2022.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at May 15, 2023, 
    created at January 29, 2022.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;find-zombie-processes&quot;&gt;Find zombie processes:&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;ps axo stat,ppid,pid,comm | grep -w defunct
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;measure-memory&quot;&gt;Measure memory&lt;/h2&gt;

&lt;p&gt;Useful project:
&lt;a href=&quot;https://github.com/astrofrog/psrecord&quot;&gt;https://github.com/astrofrog/psrecord&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;psrecord \
    --duration 30 \
    --interval 2 \
    --include-children \
    --plot /tmp/plot.png \
    &lt;pid&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;loadunload-environment-variables-based-on-directory&quot;&gt;Load/unload environment variables based on directory&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/direnv/direnv&quot;&gt;https://github.com/direnv/direnv&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;brew install direnv
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For integrating with &lt;code&gt;zsh&lt;/code&gt;, add in &lt;code&gt;~/.zshrc&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;eval &quot;$(direnv hook zsh)&quot;
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Sat, 29 Jan 2022 05:08:17 +0000</pubDate>
  <dc:modified>Mon, 15 May 2023 05:25:09 +0000</dc:modified>
  <atom:modified>Mon, 15 May 2023 05:25:09 +0000</atom:modified>
  <link>https://alexn.org/wiki/unix-shell-cli/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/unix-shell-cli/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>TLS/SSL (HTTPS)</title>
  <description>Article
    updated at September 1, 2022, 
    created at June 24, 2021.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at June 24, 2021.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;p&gt;Download the certificate of a domain:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;echo -n | openssl s_client -connect google.com:443 -servername google.com | openssl x509
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Verify that the certificate corresponds to CA certificate:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;openssl verify -verbose -purpose sslserver -CAfile /path/to/cafile.pem /path/to/cert.pem
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Thu, 24 Jun 2021 07:13:23 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:25:35 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:25:35 +0000</atom:modified>
  <link>https://alexn.org/wiki/tls/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/tls/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Web</title>
  <description>Article
    updated at August 31, 2025, 
    created at November 30, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at August 31, 2025, 
    created at November 30, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;browser-benchmarks&quot;&gt;Browser benchmarks&lt;/h2&gt;

&lt;p&gt;Performance:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://browserbench.org&quot; target=&quot;_blank&quot;&gt;browserbench.org&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://browserbench.org/Speedometer2.0/&quot; target=&quot;_blank&quot;&gt;Speedometer2.0&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://browserbench.org/JetStream/&quot; target=&quot;_blank&quot;&gt;JetStream&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://browserbench.org/MotionMark&quot; target=&quot;_blank&quot;&gt;MotionMark&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.wirple.com/bmark/&quot; target=&quot;_blank&quot;&gt;BMark (HTML5 3D benchmark)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://web.basemark.com/&quot; target=&quot;_blank&quot;&gt;Basemark Web&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.testufo.com/&quot; target=&quot;_blank&quot;&gt;UFO test (for framerate)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Features:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://tomayac.github.io/pwa-feature-detector&quot; target=&quot;_blank&quot;&gt;PWA feature detector&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.bennish.net/web-notifications.html&quot; target=&quot;_blank&quot;&gt;Web Notifications Test&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;for-testing-tracking--ads-blocking&quot;&gt;For testing tracking &amp; ads blocking&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://privacytests.org/&quot; target=&quot;_blank&quot;&gt;PrivacyTests&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://adblock-tester.com/&quot; target=&quot;_blank&quot;&gt;https://adblock-tester.com/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://coveryourtracks.eff.org/&quot; target=&quot;_blank&quot;&gt;https://coveryourtracks.eff.org/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://d3ward.github.io/toolz/adblock.html&quot; target=&quot;_blank&quot;&gt;https://d3ward.github.io/toolz/adblock.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blockads.fivefilters.org/&quot; target=&quot;_blank&quot;&gt;https://blockads.fivefilters.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;block-lists&quot;&gt;Block lists&lt;/h2&gt;

&lt;p&gt;Extra lists I used:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/gijsdev/ublock-hide-yt-shorts&quot;&gt;Hide YouTube Shorts&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/laylavish/uBlockOrigin-HUGE-AI-Blocklist&quot;&gt;Huge AI Blocklist&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://gitflic.ru/project/magnolia1234/bypass-paywalls-clean-filters&quot;&gt;Bypass Paywalls Clean filters&lt;/a&gt; (unsure if this is trustworthy)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Personal:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://alexn.org/assets/misc/block-lists/my-hosting.txt&quot;&gt;my-hosting&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://alexn.org/assets/misc/block-lists/no-news.txt&quot;&gt;no-news&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://alexn.org/assets/misc/block-lists/no-social.txt&quot;&gt;no-social&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://alexn.org/assets/misc/block-lists/no-comments.txt&quot;&gt;no-comments&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;progressive-web-apps-pwas&quot;&gt;Progressive Web Apps (PWAs)&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://web.dev/progressive-web-apps/&quot;&gt;https://web.dev/progressive-web-apps/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;wrap-web-pages-as-desktop-apps&quot;&gt;Wrap web pages as desktop apps&lt;/h3&gt;

&lt;p&gt;Using: &lt;a href=&quot;https://github.com/jiahaog/nativefier&quot;&gt;https://github.com/jiahaog/nativefier&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;nativefier \
    --maximize \
    -u &quot;Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:76.0) Gecko/20100101 Firefox/76.0&quot; \
    --internal-urls &quot;.*.google.com.*&quot; \
    --name &quot;YouTube Music&quot; \
    &quot;https://music.youtube.com/&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;nativefier \
    -u &quot;Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:76.0) Gecko/20100101 Firefox/76.0&quot; \
    --maximize \
    --counter \
    --name &quot;Twitter&quot; \
    &quot;https://x.com&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;nativefier \
    -u &quot;Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:76.0) Gecko/20100101 Firefox/76.0&quot; \
    --maximize \
    --counter \
    --name &quot;Gitter&quot; \
    &quot;https://gitter.im&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;browser-comparisons&quot;&gt;Browser comparisons&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://madaidans-insecurities.github.io/firefox-chromium.html&quot;&gt;Firefox and Chromium Security (2020)&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20210105142528/https://madaidans-insecurities.github.io/firefox-chromium.html&quot;&gt;archive&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://itsfoss.com/brave-vs-firefox/&quot;&gt;Brave vs Firefox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;client-tricks&quot;&gt;Client Tricks&lt;/h2&gt;

&lt;h3 id=&quot;detect-the-brave-browser&quot;&gt;Detect the Brave Browser&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;(navigator.brave &amp;&amp; await navigator.brave.isBrave() || false)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Credit: &lt;a href=&quot;https://stackoverflow.com/a/60954062&quot;&gt;https://stackoverflow.com/a/60954062&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;detect-dark-mode&quot;&gt;Detect Dark Mode&lt;/h3&gt;

&lt;p&gt;From JavaScript:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&quot;matchMedia&quot; in window &amp;&amp;
window.matchMedia(&apos;(prefers-color-scheme: dark)&apos;).matches
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From CSS:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;@media (prefers-color-scheme: dark) {
    /* ... */
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;detect-dark-reader-browser-extension&quot;&gt;Detect Dark Reader (browser extension)&lt;/h3&gt;

&lt;p&gt;For detecting the &lt;a href=&quot;https://darkreader.org/&quot;&gt;Dark Reader&lt;/a&gt; browser extension:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&quot;querySelector&quot; in document &amp;&amp;
!!document.querySelector(&quot;meta[name=darkreader]&quot;)
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Mon, 30 Nov 2020 14:38:13 +0000</pubDate>
  <dc:modified>Sun, 31 Aug 2025 06:56:20 +0000</dc:modified>
  <atom:modified>Sun, 31 Aug 2025 06:56:20 +0000</atom:modified>
  <link>https://alexn.org/wiki/web/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/web/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Vim</title>
  <description>Article
    updated at September 1, 2022, 
    created at November 4, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at November 4, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;docs--articles&quot;&gt;Docs &amp; Articles&lt;/h2&gt;

&lt;p&gt;Important:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://vim.rtorr.com/&quot;&gt;Vim Cheatsheet&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20210201154856/https://vim.rtorr.com/&quot;&gt;archive&lt;/a&gt;) / &lt;a href=&quot;https://github.com/rtorr/vim-cheat-sheet&quot;&gt;Github Repo&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20210201155116/https://github.com/rtorr/vim-cheat-sheet&quot;&gt;archive&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;http://www.viemu.com/vi-vim-cheat-sheet.gif&quot;&gt;Vim Graphical Cheatsheet&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20210201160106/http://www.viemu.com/vi-vim-cheat-sheet.gif&quot;&gt;archive&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.redhat.com/sysadmin/use-vim-macros&quot;&gt;Use Vim macros to automate frequent tasks&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://medium.com/@danidiaz/configuring-ideavimrc-de16a4da0715&quot;&gt;Configuring .ideavimrc&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20210201132546/https://medium.com/@danidiaz/configuring-ideavimrc-de16a4da0715&quot;&gt;archive&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://yehudakatz.com/2010/07/29/everyone-who-tried-to-convince-me-to-use-vim-was-wrong/&quot;&gt;Everyone Who Tried to Convince Me to use Vim was Wrong&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20210201154621/https://yehudakatz.com/2010/07/29/everyone-who-tried-to-convince-me-to-use-vim-was-wrong/&quot;&gt;archive&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.moolenaar.net/habits.html&quot;&gt;Seven habits of effective text editing&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20210201155823/https://www.moolenaar.net/habits.html&quot;&gt;archive&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://vimeo.com/53144573&quot;&gt;Vim - precision editing at the speed of thought (Vimeo.com video)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://vim-adventures.com/&quot;&gt;Vim Adventures (game)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://alvinalexander.com/taxonomy/term/3013/&quot;&gt;Vim content by Alvin Alexander&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20210201155458/https://alvinalexander.com/taxonomy/term/3013/&quot;&gt;archive&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://jemma.dev/blog/intermediate-vim-tips&quot;&gt;Vim Tips for the Intermediate Vim User&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20210201151013/https://jemma.dev/blog/intermediate-vim-tips&quot;&gt;archive&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.vimgolf.com/&quot;&gt;VimGolf&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20210201151233/https://www.vimgolf.com/&quot;&gt;archive&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;

&lt;h3 id=&quot;installing-the-python-provider&quot;&gt;Installing the Python provider&lt;/h3&gt;

&lt;p&gt;Some plugins require the Python provider to be available. This can be checked
with the following vim command:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-vim&quot;&gt;:checkhealth provider
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This requires the &lt;a href=&quot;https://github.com/neovim/pynvim&quot;&gt;pynvim&lt;/a&gt; Python package.
It’s best if the setup uses &lt;code&gt;virtualenv&lt;/code&gt;. On macOS prefer to use &lt;code&gt;pyenv&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;brew install pyenv pyenv-virtualenv
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This needs the following initialization code in &lt;code&gt;~/.zshrc&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;eval &quot;$(pyenv init -)&quot;
eval &quot;$(pyenv virtualenv-init -)&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, install a Python 3 version:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pyenv install 3.10.6
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Create a new virtualenv:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pyenv virtualenv 3.10.6 neovim
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Activate it temporarily in your shell session:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pyenv activate neovim
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Install the required Python package:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pip install pynvim
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then add this to &lt;code&gt;~/.config/nvim/init.vim&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-vim&quot;&gt;let g:python3_host_prog=expand(&apos;~/.pyenv/versions/neovim/bin/python&apos;)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;random-tips&quot;&gt;Random tips&lt;/h2&gt;

&lt;h3 id=&quot;documentation&quot;&gt;Documentation&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;:help&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;:help g&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;:help motion.txt&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;:help spell.txt&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;:help user-manual&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;:help visual.txt&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;surround-text&quot;&gt;Surround text&lt;/h3&gt;

&lt;p&gt;Functionality from &lt;a href=&quot;https://github.com/tpope/vim-surround&quot;&gt;vim-surround&lt;/a&gt;, which also works in VS Code (with VSCodeVim):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;v                    # Enter visual mode
&lt;visually select&gt;    # Use the keyboard to select the section of text
s                    # Press upper case S
&quot;                    # Specify what you want to surround the visual selection with
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;visual-block-mode&quot;&gt;Visual-block mode&lt;/h3&gt;

&lt;p&gt;This works like (and implemented with) multi-cursors in other editors (see &lt;a href=&quot;https://code.visualstudio.com/docs/editor/codebasics#_multiple-selections-multicursor&quot;&gt;VS Code&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20210201153540/https://code.visualstudio.com/docs/editor/codebasics#_multiple-selections-multicursor&quot;&gt;archive&lt;/a&gt;)).&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;code&gt;Ctrl-v&lt;/code&gt; to enter visual-block mode
    &lt;ul&gt;
      &lt;li&gt;Select block&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;I&lt;/code&gt; (capital letter) to enter insert mode&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;&lt;Esc&gt;&lt;/code&gt; to exit insert mode&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;copy--paste&quot;&gt;Copy &amp; Paste&lt;/h3&gt;

&lt;p&gt;Shortcuts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;code&gt;d&lt;/code&gt; is for cut, &lt;code&gt;y&lt;/code&gt; is for copy, &lt;code&gt;p&lt;/code&gt; or &lt;code&gt;P&lt;/code&gt; are for paste&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Normally one uses the clipboard register to cut, copy and paste, which is &lt;code&gt;*&lt;/code&gt;. 
So &lt;code&gt;&quot;*y&lt;/code&gt; copies to the system clipboard, and &lt;code&gt;&quot;*p&lt;/code&gt; pastes from that clipboard.&lt;/p&gt;

&lt;p&gt;To activate the system clipboard for copy and pasting with the “unnamed” register, add this to &lt;code&gt;.vimrc&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;set clipboard+=unnamed
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;fold--unfold&quot;&gt;Fold / Unfold&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;code&gt;zc&lt;/code&gt;: fold&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;zo&lt;/code&gt;: unfold&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;zM&lt;/code&gt;: fold all&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;zR&lt;/code&gt;: unfold all&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;go-to-&quot;&gt;Go to …&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;code&gt;gd&lt;/code&gt;: go to definition&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;gx&lt;/code&gt;: open link&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;Ctrl+O&lt;/code&gt;: jump back to last position&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;vimdiff&quot;&gt;Vimdiff&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;code&gt;do&lt;/code&gt;: Get changes from other window into the current window&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;dp&lt;/code&gt;: Put the changes from current window into the other window.&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;]c&lt;/code&gt;: Jump to the next change.&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;[c&lt;/code&gt;: Jump to the previous change.&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;Ctrl W + Ctrl W&lt;/code&gt;: Switch to the other split window.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;record-macros&quot;&gt;Record macros&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;to record macros: &lt;code&gt;q&lt;register&gt;&lt;commands&gt;q&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;pressing &lt;code&gt;qa&lt;/code&gt; starts recording in register &lt;code&gt;a&lt;/code&gt;
&lt;/li&gt;
      &lt;li&gt;pressing &lt;code&gt;q&lt;/code&gt; again stops recording&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;to view recorded macros: &lt;code&gt;:reg&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;to play the macro once: &lt;code&gt;@&lt;register&gt;&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;
&lt;code&gt;@a&lt;/code&gt; plays the macro in register &lt;code&gt;a&lt;/code&gt;
&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;to repeat the macro execution: &lt;code&gt;@@&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;lazyvim-setup&quot;&gt;LazyVim setup&lt;/h2&gt;

&lt;p&gt;The following tips assume &lt;a href=&quot;https://www.lazyvim.org/&quot;&gt;LazyVim&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;shortcuts&quot;&gt;Shortcuts&lt;/h3&gt;

&lt;p&gt;Search for files:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;leader&gt;&lt;leader&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Search text in files:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;leader&gt;sg
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;View list of errors and warnings reported in project:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;leader&gt;xx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Switch to window:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ctrl-w + h/j/k/l
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Close current window:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ctrl-w + q
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open link at cursor:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Go to definition at cursor:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Go back:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ctrl-t
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Wed, 04 Nov 2020 11:57:32 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:26:34 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:26:34 +0000</atom:modified>
  <link>https://alexn.org/wiki/vim/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/vim/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Android</title>
  <description>Article
    updated at September 1, 2022, 
    created at November 2, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at November 2, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;apps&quot;&gt;Apps&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.davx5.com/&quot;&gt;DAVx5&lt;/a&gt;: CalDAV/CardDAV for Android&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://f-droid.org&quot;&gt;F-Droid&lt;/a&gt;: FOSS app store&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.seazon.feedme&quot;&gt;FeedMe RSS Reader&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mozilla.org/firefox/mobile/&quot;&gt;Firefox for Android&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.foxit.mobile.pdf.lite&quot;&gt;Foxit PDF Reader&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://gitlab.com/proninyaroslav/libretorrent&quot;&gt;LibreTorrent&lt;/a&gt;: open-source torrent client&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.flyersoft.moonreaderp&quot;&gt;Moon+ Reader Pro&lt;/a&gt;: e-book reader&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.newsblur.com/android&quot;&gt;Newsblur&lt;/a&gt;: RSS reader service&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;http://www.orgzly.com/&quot;&gt;Orgzly&lt;/a&gt;: notes and to-do lists, Org-Mode&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://osmand.net/&quot;&gt;OsmAnd&lt;/a&gt;: maps based on OpenStreetMap and Wikipedia&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.pocketcasts.com/&quot;&gt;Pocket Casts&lt;/a&gt;: podcasts&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.resilio.com/platforms/mobile/&quot;&gt;Resilio Sync&lt;/a&gt;: local files sync&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/klinker-apps/talon-for-twitter-android&quot;&gt;Talon&lt;/a&gt; (&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.klinker.android.twitter_l&amp;hl=en&amp;gl=US&quot;&gt;store&lt;/a&gt;): open-source Twitter client&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://tasker.joaoapps.com/&quot;&gt;Tasker&lt;/a&gt;: automation&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://termux.com/&quot;&gt;Termux&lt;/a&gt;: terminal emulator and Linux environment&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.videolan.org/vlc/download-android.html&quot;&gt;VLC&lt;/a&gt;: video player&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/PaulWoitaschek/Voice&quot;&gt;Voice&lt;/a&gt;: open-source audiobook player&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;screen-sharing-with-laptop&quot;&gt;Screen-sharing with Laptop&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://deskreen.com/lang-en&quot;&gt;Deskreen&lt;/a&gt;: for sharing the desktop’s screen over the local network, works with any device&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/Genymobile/scrcpy&quot;&gt;Scrcpy&lt;/a&gt;: display &amp; control Android device from desktop&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 02 Nov 2020 19:09:46 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:15:19 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:15:19 +0000</atom:modified>
  <link>https://alexn.org/wiki/android/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/android/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Microsoft .NET (dotNET)</title>
  <description>Article
    updated at December 23, 2023, 
    created at October 8, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at December 23, 2023, 
    created at October 8, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;net-core&quot;&gt;.NET Core&lt;/h2&gt;

&lt;p&gt;To build self-contained executables, add this in &lt;code&gt;.csproj&lt;/code&gt;/&lt;code&gt;.fsproj&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;PropertyGroup&gt;
    &lt;SelfContained&gt;true&lt;/SelfContained&gt;
    &lt;PublishTrimmed&gt;true&lt;/PublishTrimmed&gt;
    &lt;PublishSingleFile&gt;true&lt;/PublishSingleFile&gt;
&lt;/PropertyGroup&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For NativeAOT:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/MichalStrehovsky/zerosharp&quot;&gt;zerosharp&lt;/a&gt;: “demo of the potential of C# for systems programming with the .NET native ahead-of-time compilation technology”;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;libraries-general&quot;&gt;Libraries (General)&lt;/h3&gt;

&lt;p&gt;Database migrations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/DbUp/DbUp&quot;&gt;DbUp&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/fluentmigrator/fluentmigrator&quot;&gt;Fluent Migrator&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;c-csharp&quot;&gt;C# (CSharp)&lt;/h2&gt;

&lt;h3 id=&quot;game-development&quot;&gt;Game Development&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://devblogs.microsoft.com/dotnet/game-development-with-net/&quot;&gt;Game Development with .NET&lt;/a&gt; (article)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://dotnet.microsoft.com/apps/games/engines?WT.mc_id=gamedev-blog-abhamed&quot;&gt;Available game engines&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;web-development&quot;&gt;Web Development&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://dotnet.microsoft.com/en-us/apps/aspnet&quot;&gt;ASP.NET&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://michaelscodingspot.com/postgres-in-csharp/&quot;&gt;PostgreSQL in C# .NET with Npgsql, Dapper, and Entity Framework&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# Starting a new solution
dotnet new sln -o MyBigProject
cd MyBigProject

# Start a new web app
dotnet new webapp -o web-app --no-https -f net7.0
cd web-app

# Start development server
dotnet watch
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;f-fsharp&quot;&gt;F# (FSharp)&lt;/h2&gt;

&lt;h3 id=&quot;start-new-project&quot;&gt;Start New Project&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# Starting a new solution
dotnet new sln -o AdventOfCode

# Start a console applicatin
cd AdventOfCode/
dotnet new console -lang &quot;F#&quot; -o App

# Add project to the solution
dotnet sln add App/App.fsproj

# Restore NuGet dependencies
dotnet restore

# Build the project
dotnet build

# Run the project
cd ./App
dotnet run

# Build for release
dotnet publish --configuration Release
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;articles&quot;&gt;Articles&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/fsharp/get-started/get-started-command-line&quot;&gt;Get started with F# with the .NET Core CLI&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/&quot;&gt;F# Style Guide&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/core/deploying/&quot;&gt;.NET Core application deployment&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://fsprojects.github.io/Paket/paket-generate-load-scripts.html&quot;&gt;paket generate-load-scripts&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.fssnip.net/mp/title/An-attempt-at-encoding-GADTs&quot;&gt;An attempt at encoding GADTs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Native AOT:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/&quot;&gt;Native AOT deployment&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://devblogs.microsoft.com/dotnet/announcing-fsharp-7/#f-self-contained-deployments-native-aot&quot;&gt;F# 7 release notes&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;presentations&quot;&gt;Presentations&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=MGLxyyTF3OM&quot;&gt;Don Syme - Keynote - F# Code I Love&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;templates&quot;&gt;Templates&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/fsprojects/ProjectScaffold&quot;&gt;ProjectScaffold&lt;/a&gt;: template for new projects&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/TheAngryByrd/MiniScaffold&quot;&gt;MiniScaffold&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;tools-f&quot;&gt;Tools (F#)&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/ionide/Forge/&quot;&gt;Forge&lt;/a&gt;: for creating projects&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://fsprojects.github.io/Paket/&quot;&gt;Paket&lt;/a&gt;: for Nuget dependencies management&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://fake.build/&quot;&gt;FAKE&lt;/a&gt;: build management&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;libraries-f&quot;&gt;Libraries (F#)&lt;/h3&gt;

&lt;p&gt;Unit testing:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/haf/expecto#installing&quot;&gt;Expecto&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Database access:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/efcore/EFCore.FSharp&quot;&gt;EFCore Sharp&lt;/a&gt;: F# migrations (design-time) support for EF Core.&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Thu, 08 Oct 2020 05:31:40 +0000</pubDate>
  <dc:modified>Sat, 23 Dec 2023 15:39:56 +0000</dc:modified>
  <atom:modified>Sat, 23 Dec 2023 15:39:56 +0000</atom:modified>
  <link>https://alexn.org/wiki/dotnet/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/dotnet/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Privacy</title>
  <description>Article
    updated at September 1, 2022, 
    created at September 21, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at September 21, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;firefox-extensions&quot;&gt;Firefox Extensions&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/clearurls/&quot;&gt;CleanURLs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/decentraleyes/&quot;&gt;Decentraleyes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/facebook-container/&quot;&gt;Facebook Container&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.eff.org/https-everywhere&quot;&gt;HTTPs Everywhere&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://privacybadger.org/&quot;&gt;Privacy Badger&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/&quot;&gt;uBlock Origin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;safari-extensions&quot;&gt;Safari Extensions&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://giorgiocalderolla.com/wipr.html&quot;&gt;Wipr&lt;/a&gt;
(&lt;a href=&quot;https://apps.apple.com/us/app/wipr/id1030595027?mt=8&quot;&gt;iOS&lt;/a&gt;, &lt;a href=&quot;https://apps.apple.com/app/wipr/id1320666476&quot;&gt;macOS&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;network-wide-blocking&quot;&gt;Network-wide blocking&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://pi-hole.net/&quot;&gt;Pi-hole&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://nextdns.io/&quot;&gt;NextDNS&lt;/a&gt; (pi-hole as a service)&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/StevenBlack/hosts&quot;&gt;StevenBlack/hosts&lt;/a&gt; for blocking via &lt;code&gt;/etc/hosts&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;testing&quot;&gt;Testing&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://panopticlick.eff.org/&quot;&gt;Panopticlick:  Is your browser safe against tracking?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.emailprivacytester.com/&quot;&gt;Email Privacy Tester&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://canyoublockit.com/&quot;&gt;A simple Ad Block Tester (canyoublockit.com)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;vpn&quot;&gt;VPN&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.privateinternetaccess.com/&quot;&gt;PrivateInternetAccess&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.torproject.org/download&quot;&gt;Tor Browser&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 21 Sep 2020 13:20:35 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:24:36 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:24:36 +0000</atom:modified>
  <link>https://alexn.org/wiki/privacy/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/privacy/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>De-DRM</title>
  <description>Article
    updated at September 1, 2022, 
    created at September 17, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at September 17, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;e-books&quot;&gt;e-Books&lt;/h2&gt;

&lt;p&gt;Tools:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://calibre-ebook.com/&quot;&gt;Calibre&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/apprenticeharper/DeDRM_tools/&quot;&gt;DeDRM_tools&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Installation for Calibre:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;brew cask install calibre
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For DeDRM:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/apprenticeharper/DeDRM_tools/blob/master/CALIBRE_CLI_INSTRUCTIONS.md&quot;&gt;Using the DeDRM plugin with the Calibre command line interface&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;audible-audiobooks&quot;&gt;Audible Audiobooks&lt;/h2&gt;

&lt;p&gt;Extract encryption keys: &lt;a href=&quot;https://github.com/inAudible-NG/audible-activator&quot;&gt;https://github.com/inAudible-NG/audible-activator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;ffmpeg -activation_bytes XXXXXXXX -i in.AAX out.mp3
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or for m4b, without transcoding, keeping all metadata:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;ffmpeg -activation_bytes XXXXXXXX -i in.AAX -c copy out.m4b
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Thu, 17 Sep 2020 09:02:43 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:16:47 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:16:47 +0000</atom:modified>
  <link>https://alexn.org/wiki/dedrm/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/dedrm/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Image Formats</title>
  <description>Article
    updated at September 1, 2022, 
    created at September 15, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at September 15, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;convert-heic-to-jpeg-in-a-directory&quot;&gt;Convert HEIC to JPEG in a directory&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;#!/usr/bin/env bash

set -e
shopt -s nocaseglob

echo &quot;Converting directory: $1&quot;
cd &quot;$1&quot; || exit 1

convert()
{
    local source=&quot;$1&quot;
    local dest=&quot;${source//.HEIC/.jpeg}&quot;
    dest=&quot;${dest//.heic/.jpeg}&quot;
    sips -s format jpeg &quot;$source&quot; --out &quot;$dest&quot;
}

find . -iname &quot;*.heic&quot; | while read file; do convert &quot;$file&quot;; done
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;converting-to-avifwebpother&quot;&gt;Converting to AVIF/WebP/Other&lt;/h2&gt;

&lt;p&gt;Use: &lt;a href=&quot;https://github.com/GoogleChromeLabs/squoosh/tree/dev/cli&quot;&gt;squoosh/cli&lt;/a&gt;&lt;/p&gt;</content:encoded><pubDate>Tue, 15 Sep 2020 18:48:09 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:23:07 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:23:07 +0000</atom:modified>
  <link>https://alexn.org/wiki/image-formats/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/image-formats/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Apache Kafka</title>
  <description>Article
    updated at April 8, 2023, 
    created at September 4, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at April 8, 2023, 
    created at September 4, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;docker-setup&quot;&gt;Docker Setup&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;  #
  # Kafka config taken from:
  # https://raw.githubusercontent.com/bitnami/bitnami-docker-kafka/master/docker-compose.yml
  #

  zookeeper:
    image: bitnami/zookeeper:latest
    container_name: zookeeper
    networks: [ main ]
    ports:
      - &apos;2181:2181&apos;
    volumes:
      - &apos;zookeeper_data:/bitnami&apos;
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes

  kafka:
    image: bitnami/kafka:latest
    container_name: kafka
    networks: [ main ]
    ports:
      - &apos;9092:9092&apos;
    volumes:
      - &apos;kafka_data:/bitnami&apos;
    environment:
      # - KAFKA_BROKER_ID=1
      - KAFKA_LISTENERS=PLAINTEXT://:9092
      - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://127.0.0.1:9092
      - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
      - ALLOW_PLAINTEXT_LISTENER=yes
    depends_on:
      - zookeeper
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;utils&quot;&gt;Utils&lt;/h2&gt;

&lt;p&gt;To create topics:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker exec -it kafka /opt/bitnami/kafka/bin/kafka-topics.sh \
    --create \
    --zookeeper zookeeper:2181 \
    --replication-factor 1 \
    --partitions 1 \
    --topic test
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To view messages pushed to a topic:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker exec -it kafka /opt/bitnami/kafka/bin/kafka-console-consumer.sh \
  --bootstrap-server localhost:9092 \
  --from-beginning \
  --topic test
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To push messages on a topic:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker exec -it kafka /opt/bitnami/kafka/bin/kafka-console-producer.sh \
    --broker-list localhost:9092 \
    --topic test
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Tools:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/provectus/kafka-ui&quot;&gt;provectus/kafka-ui&lt;/a&gt;: Open-Source Web UI for Apache Kafka Management;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Fri, 04 Sep 2020 07:30:08 +0000</pubDate>
  <dc:modified>Sat, 08 Apr 2023 07:08:37 +0000</dc:modified>
  <atom:modified>Sat, 08 Apr 2023 07:08:37 +0000</atom:modified>
  <link>https://alexn.org/wiki/kafka/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/kafka/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Agile</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;kanban&quot;&gt;Kanban&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=CD0y-aU1sXo&quot;&gt;Eric Brechner: “Agile Project Management with Kanban”&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;WIP - limit number of tickets equal to number of people, with some buffer&lt;/li&gt;
  &lt;li&gt;Unlimited in scope as far as time goes&lt;/li&gt;
  &lt;li&gt;Tasks should be limited to be smaller in size&lt;/li&gt;
  &lt;li&gt;Example board:
    &lt;ul&gt;
      &lt;li&gt;Backlog&lt;/li&gt;
      &lt;li&gt;Breakdown&lt;/li&gt;
      &lt;li&gt;Implement&lt;/li&gt;
      &lt;li&gt;Validate&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Each column has an “in progress” and “done” sub-columns&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:15:06 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:15:06 +0000</atom:modified>
  <link>https://alexn.org/wiki/agile/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/agile/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Cloudflare</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;invalidate-cache&quot;&gt;Invalidate cache&lt;/h2&gt;

&lt;p&gt;Create an API token:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;go here: &lt;a href=&quot;https://dash.cloudflare.com/profile/api-tokens&quot;&gt;https://dash.cloudflare.com/profile/api-tokens&lt;/a&gt;
&lt;/li&gt;
  &lt;li&gt;select permissions: &lt;code&gt;Zone.Zone (Read)&lt;/code&gt; and &lt;code&gt;Zone.Cache Purge (Purge)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Screenshot of how that looks like:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://alexn.org/wiki/assets/cloudflare-cache-purge-permissions.png&quot; alt=&quot;Cloudflare permissions dialog&quot; width=&quot;1806&quot; height=&quot;692&quot; style=&quot;max-width:100%;height:auto;&quot;&gt;&lt;/p&gt;

&lt;p&gt;Bash function:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;#!/usr/bin/env bash

cloudflare_invalidate_cache() {
  local DOMAIN_NAME=&quot;$1&quot;
  local CF_API_TOKEN=&quot;$2&quot;

  if [[ -z &quot;$DOMAIN_NAME&quot; ]]; then
    echo &gt;&amp;2 &quot;ERROR (invalidating cloudflare): DOMAIN_NAME (1) not given!&quot;
    exit 1
  fi

  if [[ -z &quot;$CF_API_TOKEN&quot; ]]; then
    echo &gt;&amp;2 &quot;ERROR (invalidating cloudflare): CF_API_TOKEN (2) is not set!&quot;
    exit 1
  fi

  echo &quot;--- Purging Cloudflare cache for $DOMAIN_NAME&quot;
  
  CF_ZONEID=$(curl -s -X GET &quot;https://api.cloudflare.com/client/v4/zones&quot; -H &quot;Authorization: Bearer $CF_API_TOKEN&quot; -H &quot;Content-Type: application/json&quot; | jq -r &apos;.result[] | &quot;\(.id) \(.name)&quot;&apos; | grep &quot;$DOMAIN_NAME&quot; | cut -f1 -d&quot; &quot;)
  curl -s -X POST &quot;https://api.cloudflare.com/client/v4/zones/$CF_ZONEID/purge_cache&quot; -H &quot;Authorization: Bearer $CF_API_TOKEN&quot; -H &quot;Content-Type: application/json&quot; --data &apos;{&quot;purge_everything&quot;:true}&apos; 1&gt;/dev/null
  return 0
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Required tools for this work:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://stedolan.github.io/jq/&quot;&gt;jq&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:15:35 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:15:35 +0000</atom:modified>
  <link>https://alexn.org/wiki/cloudflare/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/cloudflare/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Debian Packages (deb)</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.debian.org/doc/manuals/debmake-doc/ch04.en.html&quot;&gt;https://www.debian.org/doc/manuals/debmake-doc/ch04.en.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wiki.opf-labs.org/display/SP/The+Hello+World+Debian+Package&quot;&gt;http://wiki.opf-labs.org/display/SP/The+Hello+World+Debian+Package&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://santi-bassett.blogspot.com/2014/07/how-to-create-debian-package.html&quot;&gt;https://santi-bassett.blogspot.com/2014/07/how-to-create-debian-package.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:15:50 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:15:50 +0000</atom:modified>
  <link>https://alexn.org/wiki/debian-packages-deb/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/debian-packages-deb/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>DNS settings</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;macos&quot;&gt;MacOS&lt;/h2&gt;

&lt;h3 id=&quot;refresh-dns&quot;&gt;Refresh DNS&lt;/h3&gt;

&lt;p&gt;To flush the local DNS cache:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;set-dns-to-cloudflare&quot;&gt;Set DNS to Cloudflare&lt;/h3&gt;

&lt;p&gt;To set the DNS to Cloudflare’s 1.1.1.1:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo networksetup -setdnsservers Wi-Fi 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001

sudo networksetup -setdnsservers &quot;USB 10/100/1000 LAN&quot; 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To revert the setup:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo networksetup -setdnsservers &quot;Wi-Fi&quot; empty

sudo networksetup -setdnsservers &quot;USB 10/100/1000 LAN&quot; empty
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To see what DNS service the connection is using:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ nslookup google.com
Server:		1.1.1.1
Address:	1.1.1.1#53

Non-authoritative answer:
Name:	google.com
Address: 172.217.21.238
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;split-dns&quot;&gt;Split DNS&lt;/h3&gt;

&lt;p&gt;Source: &lt;a href=&quot;https://gist.github.com/dferg/0472269333be4aca6aaa21cf3b165c02&quot;&gt;https://gist.github.com/dferg/0472269333be4aca6aaa21cf3b165c02&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sometimes you may want to use a DNS server for specific domain requests and another DNS server for all other requests. This is helpful, for instance, when connected to a VPN. For hosts behind that VPN you want to use the VPN’s DNS server but all other hosts you want to use Google’s public DNS. This is called “DNS splitting.”&lt;/p&gt;

&lt;p&gt;Here, we run &lt;code&gt;dnsmasq&lt;/code&gt; as a background service on macOS. The dnsmasq configuration described below implements DNS splitting.&lt;/p&gt;

&lt;p&gt;Install via Homebrew:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;brew install dnsmasq
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Edit &lt;code&gt;$(brew --prefix)/etc/dnsmasq.conf&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-conf&quot;&gt;# Ignore /etc/resolv.conf
no-resolv

# For queries *.domain.com and *.domain.net, forward to the specified DNS server
# Servers are queried in order (if the previous fails)
# -- Note: These are EXAMPLES. Replace with your desired config.
server=/domain.com/domain.net/IP_ADDR_OF_SERVER1
server=/domain.com/domain.net/IP_ADDR_OF_SERVER2

# Forward all other requests to Google&apos;s public DNS server
server=8.8.8.8

# Only listen for DNS queries on localhost
listen-address=127.0.0.1

# Required due to macOS limitations
bind-interfaces
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Start the service:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo brew services start dnsmasq
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Point to the new local DNS server:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo networksetup -setdnsservers &quot;Wi-Fi&quot; 127.0.0.1

sudo networksetup -setdnsservers &quot;USB 10/100/1000 LAN&quot; 127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&quot;uninstall-dnsmasq&quot;&gt;Uninstall dnsmasq&lt;/h4&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo brew services stop dnsmasq
brew uninstall dnsmasq
rm &quot;$(brew --prefix)/etc/dnsmasq.conf&quot;
sudo networksetup -setdnsservers &quot;Wi-Fi&quot; empty
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;nextdns&quot;&gt;NextDNS&lt;/h3&gt;

&lt;p&gt;Install:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;brew install nextdns/tap/nextdns

sudo nextdns install \
  -report-client-info \
  -auto-activate \
  -detect-captive-portals \
  --config &lt;id&gt;
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:18:15 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:18:15 +0000</atom:modified>
  <link>https://alexn.org/wiki/dns-settings/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/dns-settings/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Docker</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;h3 id=&quot;macos&quot;&gt;MacOS&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;brew cask install docker&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;basic-usage&quot;&gt;Basic usage&lt;/h2&gt;

&lt;h3 id=&quot;running-a-container-interactively&quot;&gt;Running a container interactively&lt;/h3&gt;

&lt;p&gt;Pulling an existing from the repository:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker pull nats:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then to run this image in a container:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker run -p 4222:4222 -ti nats:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Params used:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;code&gt;-p&lt;/code&gt;: publishes a container’s port (a mapping from container to host)&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;-i&lt;/code&gt;: keep STDIN open even if not attached — this means &lt;code&gt;&lt;cmd&gt; | docker run&lt;/code&gt; works&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;-t&lt;/code&gt;: allocates a pseudo-TTY, which in combination with &lt;code&gt;-i&lt;/code&gt; means we can interact with the process&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;running-a-container-as-daemon&quot;&gt;Running a container as daemon&lt;/h3&gt;

&lt;p&gt;For this we add the &lt;code&gt;-d&lt;/code&gt; option:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker run -p 4222:4222 -d -ti nats:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;list-containers&quot;&gt;List containers&lt;/h3&gt;

&lt;p&gt;List active containers:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker ps --no-trunc
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;List all containers:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker ps -a
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;start--stop-containers&quot;&gt;Start &amp; stop containers&lt;/h3&gt;

&lt;p&gt;Stops container with the id &lt;code&gt;&lt;containerid&gt;&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker stop &lt;containerid&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Stops all running containers:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker stop $(docker ps -a -q)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To re-start a certain container:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker start &lt;containerid&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;remove-containers&quot;&gt;Remove containers&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker rm &lt;container_id&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Remove all containers:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker rm $(docker ps -a -q)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If some containers are still running as a daemon, use &lt;code&gt;-f&lt;/code&gt; (force):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker rm -f $(docker ps -a -q)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;remove-orphan-volumes&quot;&gt;Remove orphan volumes&lt;/h3&gt;

&lt;p&gt;List:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker volume ls -qf dangling=true
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Remove:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker volume rm $(docker volume ls -qf dangling=true)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;list-or-remove-images&quot;&gt;List or remove images&lt;/h3&gt;

&lt;p&gt;List images available locally:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker images
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Remove all images:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker rmi $(docker images -q -a)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;list-or-remove-volumes&quot;&gt;List or remove volumes&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker volume ls
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To remove:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker volume rm &lt;id&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Remove all volumes:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker volume rm $(docker volume ls -q)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;gain-shell-access-to-a-container&quot;&gt;Gain shell access to a container&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker exec -it &lt;container_id&gt; sh
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;clean-restart-of-all-docker-instances&quot;&gt;Clean Restart of all Docker Instances&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# Stop all containers
docker-compose down

# Delete all containers
docker rm -f $(docker ps -a -q)

# Delete all volumes
docker volume rm $(docker volume ls -q)

# Restart all containers
docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;building-docker-images&quot;&gt;Building Docker images&lt;/h2&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/docs/guides/nodejs-docker-webapp/&quot;&gt;Dockerizing a Node.js web app&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;auto-update-containers-to-latest&quot;&gt;Auto-update containers to latest&lt;/h2&gt;

&lt;p&gt;Run watchtower container, with option to auto update only labelled containers:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker run -d \
  --restart=always \
  --name=watchtower \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower \
  --label-enable
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If using &lt;code&gt;docker-compose&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;watchtower:
  container_name: watchtower
  image: &apos;containrrr/watchtower:latest&apos;
  restart: unless-stopped
  volumes:
    - /var/run/docker.sock:/var/run/docker.sock
  restart: unless-stopped
  networks:
    - main
  command: --label-enable
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To mark images for auto-updating:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker run -d --label=com.centurylinklabs.watchtower.enable=true someimage
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or if using &lt;code&gt;docker-compose&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;version: &apos;3&apos;

services:
  app:
    image: &apos;someimage&apos;
    restart: always
    labels:
      - &quot;com.centurylinklabs.watchtower.enable=true&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Watchtower will check periodically for newer images and will restart services/containers with new image.&lt;/p&gt;

&lt;h2 id=&quot;docker-compose&quot;&gt;Docker Compose&lt;/h2&gt;

&lt;p&gt;See &lt;a href=&quot;https://docs.docker.com/compose/install/&quot;&gt;docs for installing&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;brew install docker-compose
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Given a &lt;a href=&quot;https://docs.docker.com/compose/&quot;&gt;docker-compose.yml&lt;/a&gt; in the current directory, starting all containers:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker-compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or to start them as a daemons (in the background):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;example-docker-composeyml&quot;&gt;Example docker-compose.yml&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;version: &quot;3.7&quot;

services:
  nats:
    image: nats-streaming:latest
    entrypoint:
    - /nats-streaming-server
    - -cid
    - amethyst-cluster
    ports:
    - &quot;4222:4222&quot;
    - &quot;8222:8222&quot;
    - &quot;6222:6222&quot;
    restart: always
    tty: true
    networks:
      - main

  mysql:
    image: mysql:8.0
    ports:
      - &quot;3306:3306&quot;
    restart: always
    tty: true
    environment:
      MYSQL_DATABASE: mydb
      MYSQL_USER: myuser
      MYSQL_PASSWORD: mypass
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - main

  redis:
    image: redis:latest
    ports:
      - &quot;6379:6379&quot;
    restart: always
    tty: true
    networks:
      - main

  myimage:
    image: myorganization/myimage:latest
    build: .
    depends_on:
      - nats
      - mysql
      - redis
    environment:
      ENV: stage
      LANG: C.UTF-8
      NATS_SERVERS: &quot;nats://nats:4222&quot;
      VOLUME_PATH: &quot;/tmp/dont_care&quot;
    networks:
      - main
    command: bash /path/to/custom-command.sh
    volumes:
      - .:/tmp/dont_care

volumes:
  db-data:

networks:
  main:
    external:
      name: main
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:18:22 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:18:22 +0000</atom:modified>
  <link>https://alexn.org/wiki/docker/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/docker/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Dropbox</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;remove-all-shared-links&quot;&gt;Remove all shared links&lt;/h2&gt;

&lt;p&gt;Go to &lt;a href=&quot;https://www.dropbox.com/share/links&quot;&gt;https://www.dropbox.com/share/links&lt;/a&gt;, open the browser’s JavaScript console (⌘ + ⎇ + I) and paste the following:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;$$(&quot;#links-list .mc-popover-trigger&quot;).forEach((n) =&gt; {
  console.log(&quot;delete&quot;, n);
  n.click();
  $(&quot;.delete-link&quot;).click();
  $(&quot;.button-primary&quot;).click();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;screenshots-sync-on-macos&quot;&gt;Screenshots Sync on MacOS&lt;/h2&gt;

&lt;p&gt;In case Dropbox’s “Share Screenshots” option isn’t working (since it periodically stops working), or in case you don’t want to automatically share a link to synchronized screenshots …&lt;/p&gt;

&lt;h3 id=&quot;solution-1-configure-macoss-screen-capture&quot;&gt;Solution 1: Configure MacOS’s Screen Capture&lt;/h3&gt;

&lt;p&gt;Change the filename prefix:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;defaults write com.apple.screencapture name &quot;Screenshot&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Change the location:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;defaults write com.apple.screencapture location /Users/alex/Dropbox/Screenshots/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, refresh settings:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;killall SystemUIServer
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;solution-2-sync-via-script&quot;&gt;Solution 2: Sync via Script&lt;/h3&gt;

&lt;p&gt;Have a script in &lt;code&gt;/usr/local/bin/detect-screenshots.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;#!/usr/bin/env ruby

Dir[&quot;/Users/alex/Desktop/Screen*at*.png&quot;].each do |f|
  if f =~ /(\d{4}-\d{2}-\d{2})\s+at\s+(\d{2}\.\d{2}\.\d{2})/
    cmd = &quot;mv \&quot;#{f}\&quot; \&quot;/Users/alex/Dropbox/Screenshots/Screenshot #{$1} #{$2}\.png\&quot;&quot;
    puts cmd
    `#{cmd}`
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then add this file in &lt;code&gt;~/Library/LaunchAgents/alex.screenshot.detect.plist&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
&lt;plist version=&quot;1.0&quot;&gt;
&lt;dict&gt;
    &lt;key&gt;Label&lt;/key&gt;
    &lt;string&gt;alex.screenshot.detect&lt;/string&gt;
    &lt;key&gt;EnableGlobbing&lt;/key&gt;
    &lt;true /&gt;
    &lt;key&gt;ProgramArguments&lt;/key&gt;
    &lt;array&gt;
        &lt;string&gt;/usr/local/bin/detect-screenshots&lt;/string&gt;
    &lt;/array&gt;
    &lt;key&gt;WatchPaths&lt;/key&gt;
    &lt;array&gt;
        &lt;string&gt;/Users/alex/Desktop/&lt;/string&gt;
    &lt;/array&gt;
    &lt;key&gt;ThrottleInterval&lt;/key&gt;
    &lt;integer&gt;5&lt;/integer&gt;
    &lt;key&gt;StandardOutPath&lt;/key&gt;
    &lt;string&gt;/Users/alex/Library/Logs/detect-screenshots.log&lt;/string&gt;
    &lt;key&gt;StandardErrorPath&lt;/key&gt;
    &lt;string&gt;/Users/alex/Library/Logs/detect-screenshots.log&lt;/string&gt;
&lt;/dict&gt;
&lt;/plist&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then load it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;launchctl load -w ~/Library/LaunchAgents/alex.screenshot.detect.plist
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:19:11 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:19:11 +0000</atom:modified>
  <link>https://alexn.org/wiki/dropbox/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/dropbox/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Emacs</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;My preferred installation on macOS:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;brew install emacs --cask
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This installs:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;App &apos;/Applications/Emacs.app&apos;.
Binary &apos;/usr/local/bin/emacs&apos;.
Binary &apos;/usr/local/bin/ebrowse&apos;.
Binary &apos;/usr/local/bin/emacsclient&apos;.
Binary &apos;/usr/local/bin/etags&apos;.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;GOTCHA:&lt;/strong&gt; make sure these are on the system path and have priority over the system’s Emacs.&lt;/p&gt;

&lt;h2 id=&quot;settings&quot;&gt;Settings&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;git clone https://github.com/alexandru/emacs.d ~/.emacs.d
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See &lt;a href=&quot;https://github.com/alexandru/emacs.d&quot;&gt;repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;emacs-server-as-macos-service&quot;&gt;Emacs Server as MacOS Service&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;~/Library/LaunchAgents/alex.emacs.plist&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
&lt;plist version=&quot;1.0&quot;&gt;
  &lt;dict&gt;
    &lt;key&gt;KeepAlive&lt;/key&gt;
    &lt;true/&gt;
    &lt;key&gt;Label&lt;/key&gt;
    &lt;string&gt;alex.Emacs&lt;/string&gt;
    &lt;key&gt;ProgramArguments&lt;/key&gt;
    &lt;array&gt;
      &lt;string&gt;/usr/local/bin/emacs&lt;/string&gt;
      &lt;string&gt;--fg-daemon&lt;/string&gt;
    &lt;/array&gt;
    &lt;key&gt;RunAtLoad&lt;/key&gt;
    &lt;true/&gt;
    &lt;key&gt;UserName&lt;/key&gt;
    &lt;string&gt;replace_me_with_mac_username&lt;/string&gt;
  &lt;/dict&gt;
&lt;/plist&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The service can then be loaded via:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;launchctl load -w ~/Library/LaunchAgents/alex.emacs.plist
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or unloaded via:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;launchctl unload ~/Library/LaunchAgents/alex.emacs.plist
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;script-for-running-emacsclient&quot;&gt;Script for running EmacsClient&lt;/h2&gt;

&lt;p&gt;Placed in &lt;code&gt;~/bin/run-emacsclient&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/usr/bin/env bash

if [ -z &quot;$EMACSCLIENT_OPTS&quot; ]; then
  EMACSCLIENT_OPTS=&quot;-nc&quot;
fi

if [ $# -eq 0 ]; then
  COMMAND=&apos;/usr/local/bin/emacsclient &apos;$EMACSCLIENT_OPTS&apos; -e &quot;(if (display-graphic-p) (x-focus-frame nil))&quot;&apos;
else
  COMMAND=&apos;/usr/local/bin/emacsclient &apos;$EMACSCLIENT_OPTS&apos; &quot;$@&quot;&apos;
fi

if [ -z &quot;$(shopt | grep login_shell)&quot; ]; then
  echo &quot;$COMMAND&quot; | exec bash --login -s &quot;$@&quot;
else
  eval &quot;exec $COMMAND&quot;
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And a corresponding &lt;code&gt;~/bin/run-emacs-client-cli&lt;/code&gt; to force the CLI mode in the terminal, instead of opening a buffer in some opened GUI window:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/usr/bin/env bash

export EMACSCLIENT_OPTS=&apos;-t&apos;
exec run-emacsclient &quot;$@&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;bashzsh-settings&quot;&gt;Bash/Zsh Settings&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Default zsh keybindings (emacs; might want to switch to vim later)
bindkey -e

# Adding Emacs to PATH
export PATH=&quot;$PATH:~/Applications/Emacs.app/Contents/MacOS/bin:/Applications/Emacs.app/Contents/MacOS/bin:~/Applications/Emacs.app/Contents/MacOS:/Applications/Emacs.app/Contents/MacOS&quot;

# Default editor
export EDITOR=&quot;$HOME/bin/run-emacsclient-cli&quot;
export VISUAL=&quot;$EDITOR&quot;
export ALTERNATE_EDITOR=&quot;vim&quot;

## Editor aliases
alias e=&quot;$HOME/bin/run-emacsclient-cli&quot;
alias ew=&quot;$HOME/bin/run-emacsclient&quot;
alias notes=&apos;$HOME/bin/run-emacsclient-cli -e &quot;(deft)&quot;&apos;

emacs_open_buffer()
{
  run-emacsclient-cli -e &quot;(let ((b (find-buffer-by-prefix \&quot;$1\&quot;))) nil)&quot;
}
alias eb=emacs_open_buffer
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;troubleshooting&quot;&gt;Troubleshooting&lt;/h2&gt;

&lt;h3 id=&quot;failed-to-verify-signature&quot;&gt;Failed to verify signature&lt;/h3&gt;

&lt;p&gt;In my case Emacs was complaining that key &lt;code&gt;066DAFCB81E42C40&lt;/code&gt; is missing.&lt;/p&gt;

&lt;p&gt;I managed to solve it by running:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;gpg --keyserver hkp://keys.gnupg.net --recv-keys 066DAFCB81E42C40
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Afterwards starting Emacs from the command line might be a good idea.&lt;/p&gt;

&lt;h3 id=&quot;general-unhappiness&quot;&gt;General unhappiness&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;brew uninstall emacs
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then download &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;VS Code&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/bbatsov/emacs-lisp-style-guide&quot;&gt;The Emacs Lisp Style Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:20:20 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:20:20 +0000</atom:modified>
  <link>https://alexn.org/wiki/emacs/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/emacs/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Email</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;send-email-from-localhost&quot;&gt;Send email from localhost&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;brew install swaks
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;swaks --auth \
	--server smtp.mailgun.org \
	--au postmaster@mail.mydomain.com \
	--ap password \
  --from alex@mail.mydomain.com \
	--to user@domain.com \
	--h-Subject: &quot;Hello&quot; \
	--body &apos;World!&apos;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;via-python-script&quot;&gt;Via Python script&lt;/h2&gt;

&lt;p&gt;See: &lt;a href=&quot;https://alexn.org/blog/2020/03/18/send-mail.py/&quot;&gt;send-mail.py&lt;/a&gt;&lt;/p&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:20:30 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:20:30 +0000</atom:modified>
  <link>https://alexn.org/wiki/email/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/email/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Firefox</title>
  <description>Article
    updated at April 10, 2025, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at April 10, 2025, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;cool-extensions&quot;&gt;Cool Extensions&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/auto-tab-discard/&quot;&gt;Auto Tab Discard&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/consent-o-matic/&quot;&gt;Consent-o-matic&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/cookie-autodelete/&quot;&gt;Cookie AutoDelete&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/cookie-quick-manager/&quot;&gt;Cookie Quick Manager&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/darkreader/&quot;&gt;Dark Reader&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/enhancer-for-youtube/&quot;&gt;Enhancer for YouTube™&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/multi-account-containers/&quot;&gt;Firefox Multi-Account Containers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/leechblock-ng/&quot;&gt;LeechBlock NG&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/netflix-1080p-firefox/&quot;&gt;Netflix 1080p&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/notifier-for-github/&quot;&gt;Notifier for GitHub&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/old-reddit-redirect/&quot;&gt;Old Reddit Redirect&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/rsspreview/&quot;&gt;RSS Preview&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/sidebery/&quot;&gt;Sideberry&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/sponsorblock/&quot;&gt;SponsorBlock - Skip Sponsorships on YouTube&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/styl-us/&quot;&gt;Stylus&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/tab-reloader/&quot;&gt;Tab Reloader&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/tabliss/&quot;&gt;Tabliss&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/terms-of-service-didnt-read/&quot;&gt;Terms of Service; Didn’t Read&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/toggle-pin-tab/&quot;&gt;Toggle Tab Pin&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/tree-style-tab/&quot;&gt;Tree Style Tab&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/&quot;&gt;uBlock Origin&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/wayback-machine_new/&quot;&gt;Wayback Machine&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/view-page-archive/&quot;&gt;Web Archives&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/yang-addon/&quot;&gt;Yang!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;settings&quot;&gt;Settings&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;about:config&quot;&gt;about:config&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;auto-sync-aboutconfig-settings&quot;&gt;Auto-sync about:config settings&lt;/h3&gt;

&lt;p&gt;Source:
&lt;a href=&quot;https://www.addictivetips.com/web/sync-about-config-preferences-with-firefox-sync/&quot;&gt;https://www.addictivetips.com/web/sync-about-config-preferences-with-firefox-sync/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For each setting to be synched, add:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;services.sync.prefs.&lt;setting&gt; true
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;services.sync.prefs.toolkit.legacyUserProfileCustomizations.stylesheets

services.sync.prefs.media.hardwaremediakeys.enabled
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;activate-compact-mode-after-proton&quot;&gt;Activate compact mode (after Proton)&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;about:config&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;browser.compactmode.show = true
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Source: &lt;a href=&quot;https://support.mozilla.org/en-US/kb/compact-mode-workaround-firefox&quot;&gt;https://support.mozilla.org/en-US/kb/compact-mode-workaround-firefox&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;restore-pinned-tabs-on-demand&quot;&gt;Restore Pinned Tabs on Demand&lt;/h3&gt;

&lt;p&gt;Note sure how to prevent the pinned tabs from opening at all, but at least this delays them loading, until you activate the tabs:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;browser.sessionstore.restore_pinned_tabs_on_demand = true

services.sync.prefs.browser.sessionstore.restore_pinned_tabs_on_demand = true
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;hide-native-tabs-for-tree-style-tabs&quot;&gt;Hide Native Tabs (for Tree Style Tabs)&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://medium.com/@Aenon/firefox-hide-native-tabs-and-titlebar-f0b00bdbb88b&quot;&gt;https://medium.com/@Aenon/firefox-hide-native-tabs-and-titlebar-f0b00bdbb88b&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;about:config&quot;&gt;about:config&lt;/a&gt; set:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;toolkit.legacyUserProfileCustomizations.stylesheets = true

// For syncing the setting
services.sync.prefs.toolkit.legacyUserProfileCustomizations.stylesheets = true
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then in the &lt;code&gt;&lt;Profile folder&gt;/chrome/userChrome.css&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;/* hides the native tabs */
#TabsToolbar {
  visibility: collapse;
}

#sidebar-header {
  visibility: collapse !important;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;suggest-javascript-bookmarklets&quot;&gt;Suggest JavaScript Bookmarklets&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;browser.urlbar.filter.javascript = true

services.sync.prefs.browser.urlbar.filter.javascript = true
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://old.reddit.com/r/firefox/comments/1i5wryz/searching_bookmarks_missing_results_bookmarklets/m89n7pv/&quot;&gt;Source&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;enable-calculator&quot;&gt;Enable calculator&lt;/h3&gt;

&lt;p&gt;Source: &lt;a href=&quot;https://xoxo.zone/@annika/111459732964070961&quot;&gt;https://xoxo.zone/@annika/111459732964070961&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;browser.urlbar.suggest.calculator = true

services.sync.prefs.browser.urlbar.suggest.calculator = true
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;all-about-pages&quot;&gt;All about: Pages&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;about:about&quot;&gt;about:about&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:addons&quot;&gt;about:addons&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:buildconfig&quot;&gt;about:buildconfig&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:cache&quot;&gt;about:cache&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:checkerboard&quot;&gt;about:checkerboard&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:config&quot;&gt;about:config&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:crashes&quot;&gt;about:crashes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:credits&quot;&gt;about:credits&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:debugging&quot;&gt;about:debugging&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:devtools&quot;&gt;about:devtools&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:downloads&quot;&gt;about:downloads&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:home&quot;&gt;about:home&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:license&quot;&gt;about:license&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:logo&quot;&gt;about:logo&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:memory&quot;&gt;about:memory&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:mozilla&quot;&gt;about:mozilla&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:networking&quot;&gt;about:networking&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:newtab&quot;&gt;about:newtab&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:performance&quot;&gt;about:performance&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:plugins&quot;&gt;about:plugins&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:preferences&quot;&gt;about:preferences&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:privatebrowsing&quot;&gt;about:privatebrowsing&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:profiles&quot;&gt;about:profiles&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:rights&quot;&gt;about:rights&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:robots&quot;&gt;about:robots&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:serviceworkers&quot;&gt;about:serviceworkers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:studies&quot;&gt;about:studies&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:support&quot;&gt;about:support&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:sync-log&quot;&gt;about:sync-log&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:telemetry&quot;&gt;about:telemetry&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:url-classifier&quot;&gt;about:url-classifier&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;about:webrtc&quot;&gt;about:webrtc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;docs&quot;&gt;Docs&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://support.mozilla.org/ro/kb/configuring-networks-disable-dns-over-https&quot;&gt;Configuring Networks to Disable DNS over HTTPS&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://support.mozilla.org/en-US/kb/canary-domain-use-application-dnsnet&quot;&gt;Canary domain - use-application-dns.net&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.mozilla.org/Trusted_Recursive_Resolver&quot;&gt;Trusted Recursive Resolver&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 10 Apr 2025 12:43:34 +0000</dc:modified>
  <atom:modified>Thu, 10 Apr 2025 12:43:34 +0000</atom:modified>
  <link>https://alexn.org/wiki/firefox/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/firefox/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Git</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;commands&quot;&gt;Commands&lt;/h2&gt;

&lt;p&gt;Cleanup a local repository of all untracked files:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git clean -dfx
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Throw away all uncommitted changes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git reset --hard HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;large-files-support&quot;&gt;Large files support&lt;/h2&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://git-lfs.github.com/&quot;&gt;Project homepage&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/github/managing-large-files/versioning-large-files&quot;&gt;Versioning large files&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Installation:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;brew install git-lfs
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the git repository:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git lfs install
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To add file extensions to track via “lfs”:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git lfs track &quot;*.psd&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;git-sync&quot;&gt;git-sync&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://worthe-it.co.za/programming/2016/08/13/automated-syncing-with-git.html&quot;&gt;Automated Syncing with Git&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/simonthum/git-sync&quot;&gt;github.com/simonthum/git-sync&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:21:01 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:21:01 +0000</atom:modified>
  <link>https://alexn.org/wiki/git/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/git/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>GitHub</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;tools&quot;&gt;Tools&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;For creating labels: &lt;a href=&quot;https://github.com/integratedexperts/github-labels/&quot;&gt;https://github.com/integratedexperts/github-labels/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;trigger-manual-build&quot;&gt;Trigger manual build&lt;/h2&gt;

&lt;p&gt;We can use GitHub’s API to trigger a custom event, e.g:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;curl --fail \
  -XPOST -u &quot;${GH_USERNAME}:${GH_TOKEN}&quot; \
  -H &quot;Accept: application/vnd.github.everest-preview+json&quot; \
  -H &quot;Content-Type: application/json&quot; \
  https://api.github.com/repos/${REPO_ORGANIZATION}/${REPO_NAME}/dispatches \
  --data &apos;{&quot;event_type&quot;: &quot;custom_event&quot;}&apos;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Set the &lt;code&gt;GH_USERNAME&lt;/code&gt;, &lt;code&gt;GH_TOKEN&lt;/code&gt;, &lt;code&gt;REPO_ORGANIZATION&lt;/code&gt; and &lt;code&gt;REPO_NAME&lt;/code&gt; environment variables. Might also want to set the &lt;code&gt;custom_event&lt;/code&gt; identifier to something that makes sense for you.&lt;/p&gt;

&lt;p&gt;Then in GitHub Actions to trigger an action in response to this &lt;code&gt;custom_event&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;on:
  repository_dispatch:
    types: [custom_event]
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:21:08 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:21:08 +0000</atom:modified>
  <link>https://alexn.org/wiki/github/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/github/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>GNU Screen</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.gnu.org/software/screen/manual/screen.html&quot;&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;cheatsheet&quot;&gt;Cheatsheet&lt;/h2&gt;

&lt;p&gt;Start a new session:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Start a new named session:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;screen -S &lt;name&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;List sessions:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;screen -ls
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Re-attach session:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;screen -r &lt;name&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Main commands:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Shortcuts menu: &lt;code&gt;Ctrl-a ?&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;Command mode: &lt;code&gt;Ctrl-a :&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;Detach session: &lt;code&gt;Ctrl-a d&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Window management:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Create a new window: &lt;code&gt;Ctrl-a c&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;Kill current window: &lt;code&gt;Ctrl-a k&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;Next window: &lt;code&gt;Ctrl-a n&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;Previous window: &lt;code&gt;Ctrl-a p&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;Jump to window: &lt;code&gt;Ctrl-a 0-9&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;Split vertical: &lt;code&gt;Ctrl-a |&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;Split horizontal: &lt;code&gt;Ctrl-a S&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;Focus next region: &lt;code&gt;Ctrl-a ^&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;Quit split screen mode: &lt;code&gt;Ctrl-a Q&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;custom-screenrc&quot;&gt;Custom ~/.screenrc&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;shell -$SHELL

# Buffer size
defscrollback 50000

# Allow bold colors - necessary for some reason
attrcolor b &quot;.I&quot;

# Tell screen how to set colors. AB = background, AF=foreground
termcapinfo xterm &apos;Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm&apos;

# Erase background with current bg color
defbce &quot;on&quot;

# Enable 256 color term
term xterm-256color

# Very nice tabbed colored hardstatus line
hardstatus string &apos;%{= Kd} %{= Kd}%-w%{= Kr}[%{= KW}%n %t%{= Kr}]%{= Kd}%+w %-= %{KG} %H%{KW}|%{KY}%101`%{KW}|%D %M %d %Y%{= Kc} %C%A%{-}&apos;

#
## Control-^ (usually Control-Shift-6) is traditional and the only key not used by emacs
escape ^^^^
#
## do not trash BackSpace, usually DEL
bindkey -k kb
bindkey -d -k kb
#
## do not trash Delete, usually ESC [ 3 ~
bindkey -k kD
bindkey -d -k kD
  
# Hide hardstatus: ctrl-a f 
bind f eval &quot;hardstatus ignore&quot;
# Show hardstatus: ctrl-a F
bind F eval &quot;hardstatus alwayslastline&quot;
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:22:42 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:22:42 +0000</atom:modified>
  <link>https://alexn.org/wiki/gnu-screen/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/gnu-screen/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Haskell</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;educational-resources&quot;&gt;Educational Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/Gabriel439/post-rfc/blob/master/sotu.md&quot;&gt;State of the Haskell ecosystem&lt;/a&gt;: describes the best tools available&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://dev.stephendiehl.com/hask/&quot;&gt;What I Wish I Knew When Learning Haskell&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.vacationlabs.com/haskell/index.html&quot;&gt;Haskell without the theory&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://kowainik.github.io/posts/2018-06-21-haskell-build-tools&quot;&gt;Haskell: Build Tools&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/soupi/haskell-study-plan/blob/master/README.org&quot;&gt;Haskell Study Plan&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://typeclasses.com/&quot;&gt;Type Classes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;books&quot;&gt;Books&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://haskellbook.com/&quot;&gt;Haskell Programming from First Principles&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://simonmar.github.io/pages/pcph.html&quot;&gt;Concurrent Parallel and Concurrent Programming in Haskell&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.apress.com/gp/book/9781484244791&quot;&gt;Practical Haskell&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.apress.com/gp/book/9781484237380&quot;&gt;Practical Web Development with Haskell&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://atypeofprogramming.com/&quot;&gt;A Type of Programming&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.cs.yale.edu/homes/hudak/Papers/HSoM.pdf&quot;&gt;Haskell School of Music&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://leanpub.com/finding-success-in-haskell/&quot;&gt;Finding Success (and Failure) in Haskell&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.manning.com/books/get-programming-with-haskell&quot;&gt;Get Programming in Haskell&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;blog-articles&quot;&gt;Blog articles&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://kowainik.github.io/posts/haskell-mini-patterns&quot;&gt;Haskell mini-patterns handbook&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://jacobstanley.io/help-my-haskell-program-consumes-more-memory-the-longer-it-runs/&quot;&gt;Help! My Haskell program consumes more memory the longer it runs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.cloudflare.com/cloudflare-worker-with-webassembly-and-haskell/&quot;&gt;Let’s build a Cloudflare Worker with WebAssembly and Haskell&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;tools&quot;&gt;Tools&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://hackage.haskell.org/package/hlint&quot;&gt;hlint&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/ndmitchell/ghcid&quot;&gt;ghcid&lt;/a&gt;: very basic IDE engine based on &lt;code&gt;ghci&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/rikvdkleij/intellij-haskell&quot;&gt;IntelliJ-Haskell&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://haskellformac.com/&quot;&gt;Haskell for Mac&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:22:59 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:22:59 +0000</atom:modified>
  <link>https://alexn.org/wiki/haskell/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/haskell/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>iTerm2</title>
  <description>Article
    updated at September 2, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 2, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;configure-opening-of-file-paths-semantic-history&quot;&gt;Configure opening of file paths (semantic history)&lt;/h2&gt;

&lt;p&gt;In iTerm’s settings, goto &lt;code&gt;Profiles&lt;/code&gt; -&gt; &lt;code&gt;Advanced&lt;/code&gt; -&gt; &lt;code&gt;Semantic
History&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;opening-files-in-intellij-idea--visual-studio-code&quot;&gt;Opening files in IntelliJ IDEA + Visual Studio Code&lt;/h3&gt;

&lt;p&gt;First create IntelliJ IDEA’s command line launcher. Press &lt;code&gt;⇧ Shift + ⇧ Shift&lt;/code&gt; (twice) to bring up the &lt;a href=&quot;https://www.jetbrains.com/help/idea/searching-everywhere.html#search_all&quot; target=&quot;_blank&quot;&gt;Navigate -&gt; Search Everywhere&lt;/a&gt; dialog. Then write “&lt;em&gt;create command-line launcher&lt;/em&gt;” in the search box, to select the desired action, then press &lt;code&gt;⏎ Enter&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://alexn.org/wiki/assets/intellij-idea-create-cmd-line-launcher.png&quot; alt=&quot;Screenshot of Search Everywhere dialog&quot; width=&quot;1362&quot; height=&quot;260&quot; style=&quot;max-width:100%;height:auto;&quot;&gt;&lt;/p&gt;

&lt;p&gt;Now &lt;code&gt;idea&lt;/code&gt; is installed on the command line, on MacOS this is tipically in &lt;code&gt;/usr/local/bin/idea&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Similarly, in &lt;a href=&quot;https://code.visualstudio.com/&quot; target=&quot;_blank&quot;&gt;Visual Studio Code&lt;/a&gt; press &lt;code&gt;⌘ Cmd + P&lt;/code&gt;, type “&lt;em&gt;install code command&lt;/em&gt;”, and press &lt;code&gt;⏎ Enter&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://alexn.org/wiki/assets/vs-code-install-cmd-line.png&quot; alt=&quot;Screenshot of &apos;install code command&apos; in VS Code&quot; width=&quot;1100&quot; height=&quot;198&quot; style=&quot;max-width:100%;height:auto;&quot;&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;idea&lt;/code&gt; command line utility isn’t compatible with iTerm’s settings, plus if we want to discriminate based on file type, an extra script is needed. Save this in &lt;code&gt;$HOME/bin/iterm-goto&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;#!/bin/sh

GOTO_FILE=&quot;$1&quot;
GOTO_LINE=&quot;$2&quot;
GOTO_CHAR=&quot;$3&quot;

if ! [ -f &quot;$GOTO_FILE&quot; ]; then
    echo &quot;ERROR: file path missing or invalid!&quot; &gt;&amp;2
    exit 1
fi

# Discriminate based on file extension, open only .scala or .sbt files in IntelliJ IDEA ...
if [[ &quot;$GOTO_FILE&quot; =~ ^.*\.(scala|sbt)$ ]]; then
    EDITOR_PATH=&quot;$(which idea)&quot;

    if [ -z &quot;$IDEA_PATH&quot; ]; then
        EDITOR_PATH=&quot;/usr/local/bin/idea&quot;
    fi

    if ! [ -z &quot;$GOTO_LINE&quot; ]; then
        exec &quot;$EDITOR_PATH&quot; --line &quot;$GOTO_LINE&quot; &quot;$GOTO_FILE&quot;
    else
        exec &quot;$EDITOR_PATH&quot; &quot;$GOTO_FILE&quot;
    fi
else
    EDITOR_PATH=&quot;$(which code)&quot;

    if [ -z &quot;$EDITOR_PATH&quot; ]; then
        EDITOR_PATH=&quot;/usr/local/bin/code&quot;
    fi

    if ! [ -z &quot;$GOTO_CHAR&quot; ]; then
        exec &quot;$EDITOR_PATH&quot; --goto &quot;$GOTO_FILE:$GOTO_LINE:$GOTO_CHAR&quot;
    elif ! [ -z &quot;$GOTO_LINE&quot; ]; then
        exec &quot;$EDITOR_PATH&quot; --goto &quot;$GOTO_FILE:$GOTO_LINE&quot;
    else
        exec &quot;$EDITOR_PATH&quot; &quot;$GOTO_FILE&quot;
    fi
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then in iTerm’s settings, goto &lt;code&gt;Profiles&lt;/code&gt; -&gt; &lt;code&gt;Advanced&lt;/code&gt; -&gt; &lt;code&gt;Semantic
History&lt;/code&gt;, and set &lt;code&gt;Run command ...&lt;/code&gt; to:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;$HOME/bin/iterm-goto \1 \2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&quot;https://alexn.org/wiki/assets/iterm-semantic-history-setting.png&quot; alt=&quot;Screenshot of iTerm&apos;s Semantic History setting&quot; width=&quot;1066&quot; height=&quot;290&quot; style=&quot;max-width:100%;height:auto;&quot;&gt;&lt;/p&gt;

&lt;h2 id=&quot;setup-automatic-dark-mode&quot;&gt;Setup automatic dark mode&lt;/h2&gt;

&lt;p&gt;NOTE: this is intended for the &lt;strong&gt;stable 3.4.x&lt;/strong&gt; versions, and isn’t needed in the &lt;a href=&quot;https://iterm2.com/downloads.html&quot;&gt;3.5.x betas&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Create this file in &lt;code&gt;~/Library/Application\ Support/iTerm2/Scripts/AutoLaunch/auto_dark_mode.py&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;#!/usr/bin/env python3.7

import asyncio
import iterm2

async def changeTheme(connection,parts):
    theme_dark = &quot;Dark Background&quot;
    theme_light = &quot;Light Background&quot;
    print(parts)
    
    if &quot;dark&quot; in parts:
        preset = await iterm2.ColorPreset.async_get(connection, theme_dark)
    else:
        preset = await iterm2.ColorPreset.async_get(connection, theme_light)

    # Update the list of all profiles and iterate over them.
    profiles=await iterm2.PartialProfile.async_query(connection)
    for partial in profiles:
        # Fetch the full profile and then set the color preset in it.
        profile = await partial.async_get_full_profile()
        await profile.async_set_color_preset(preset)

async def main(connection):
    app = await iterm2.async_get_app(connection)
    window = app.current_window
    initial_theme = await app.async_get_theme()
    await changeTheme(connection,initial_theme)

    async with iterm2.VariableMonitor(connection, iterm2.VariableScopes.APP, &quot;effectiveTheme&quot;, None) as mon:
        while True:
            # Block until theme changes
            theme = await mon.async_get()
            # Themes have space-delimited attributes, one of which will be light or dark.
            parts = theme.split(&quot; &quot;)
    
            await changeTheme(connection,parts)

iterm2.run_forever(main)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Credits: &lt;a href=&quot;https://gist.github.com/FradSer/de1ca0989a9d615bd15dc6eaf712eb93&quot;&gt;@FradSer&lt;/a&gt;.&lt;/p&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Fri, 02 Sep 2022 07:14:59 +0000</dc:modified>
  <atom:modified>Fri, 02 Sep 2022 07:14:59 +0000</atom:modified>
  <link>https://alexn.org/wiki/iterm/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/iterm/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>JSON</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;command-line-parsing&quot;&gt;Command-line parsing&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://stedolan.github.io/jq/&quot;&gt;jq&lt;/a&gt; — command-line JSON processor.&lt;/p&gt;

&lt;p&gt;Sorting in descending order by field:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bw list items | jq &apos;sort_by(.revisionDate)|reverse&apos;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Tutorial:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://leonid.shevtsov.me/post/handle-large-jsons-effortlessly-with-jq/&quot;&gt;Handle large JSONs effortlessly with jq&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:23:41 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:23:41 +0000</atom:modified>
  <link>https://alexn.org/wiki/json/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/json/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>macOS</title>
  <description>Article
    updated at January 24, 2025, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at January 24, 2025, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;finder-shortcuts&quot;&gt;Finder Shortcuts&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;code&gt;Cmd + Shift + G&lt;/code&gt;: Go to Folder&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;Cmd + Shift + .&lt;/code&gt;: Toggle visibility of dot files&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;useful-apps&quot;&gt;Useful Apps&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/jordanbaird/Ice&quot;&gt;Ice&lt;/a&gt;: Powerful menu bar manager for macOS, OSS alternative to Bartender;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/macmade/Hot&quot;&gt;Hot&lt;/a&gt;: for monitoring the CPU temperature;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.marcmoini.com/sx_en.html&quot;&gt;Smart Scroll&lt;/a&gt;: makes the mouse more useful;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/rugarciap/Turbo-Boost-Switcher&quot;&gt;Turbo Booster Switcher&lt;/a&gt;: switches off “turbo boost” for Intel CPUs, prevents overheating;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;stop-apple-music--itunes-from-starting-on-play&quot;&gt;Stop Apple Music / iTunes from starting on Play&lt;/h2&gt;

&lt;p&gt;Source: &lt;a href=&quot;https://www.howtogeek.com/274345/stop-itunes-from-launching-when-you-press-play-on-your-macs-keyboard/&quot;&gt;Stop iTunes From Launching When You Press Play On Your Mac’s Keyboard&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;launchctl unload -w /System/Library/LaunchAgents/com.apple.rcd.plist
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;find-which-app-is-stealing-focus&quot;&gt;Find which app is stealing focus&lt;/h2&gt;

&lt;p&gt;Answer from &lt;a href=&quot;https://apple.stackexchange.com/questions/123730/is-there-a-way-to-detect-what-program-is-stealing-focus-on-my-mac&quot;&gt;StackExchange&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;#!/usr/bin/python

try:
    from AppKit import NSWorkspace
except ImportError:
    print &quot;Can&apos;t import AppKit -- maybe you&apos;re running python from brew?&quot;
    print &quot;Try running with Apple&apos;s /usr/bin/python instead.&quot;
    exit(1)

from datetime import datetime
from time import sleep

last_active_name = None
while True:
    active_app = NSWorkspace.sharedWorkspace().activeApplication()
    if active_app[&apos;NSApplicationName&apos;] != last_active_name:
        last_active_name = active_app[&apos;NSApplicationName&apos;]
        print &apos;%s: %s [%s]&apos; % (
            datetime.now().strftime(&apos;%Y-%m-%d %H:%M:%S&apos;),
            active_app[&apos;NSApplicationName&apos;],
            active_app[&apos;NSApplicationPath&apos;]
        )
    sleep(1)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Needs &lt;code&gt;pyobjc&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pip install pyobjc
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;resources--troubleshooting&quot;&gt;Resources / Troubleshooting&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;PRAM reset: &lt;a href=&quot;https://support.apple.com/en-us/HT204063&quot;&gt;https://support.apple.com/en-us/HT204063&lt;/a&gt;
&lt;/li&gt;
  &lt;li&gt;SMC reset: &lt;a href=&quot;https://support.apple.com/en-us/HT201295&quot;&gt;https://support.apple.com/en-us/HT201295&lt;/a&gt;
&lt;/li&gt;
  &lt;li&gt;System Integrity Protection:
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://osxdaily.com/2015/10/05/disable-rootless-system-integrity-protection-mac-os-x/&quot;&gt;How to Disable System Integrity Protection (rootless) in Mac OS X&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/Security/Conceptual/System_Integrity_Protection_Guide/ConfiguringSystemIntegrityProtection/ConfiguringSystemIntegrityProtection.html&quot;&gt;Configuring System Integrity Protection&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/dortania/OpenCore-Legacy-Patcher&quot;&gt;Force updates for older Macs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;other-documents&quot;&gt;Other Documents&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://alexn.org/wiki/dns-settings/#macos&quot;&gt;DNS Settings&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://alexn.org/wiki/emacs/#emacs-server-as-macos-service&quot;&gt;Emacs server setup&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://alexn.org/wiki/dropbox/#screenshots-sync-on-macos&quot;&gt;Screenshots synchronization&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Fri, 24 Jan 2025 12:18:11 +0000</dc:modified>
  <atom:modified>Fri, 24 Jan 2025 12:18:11 +0000</atom:modified>
  <link>https://alexn.org/wiki/macos/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/macos/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>MySQL / MariaDB</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;start-a-docker-instance&quot;&gt;Start a Docker Instance&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker run --rm --name mariadb -e MYSQL_ROOT_PASSWORD=pass -p 3306:3306 mariadb:10.5 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note &lt;code&gt;--rm&lt;/code&gt; deletes the container after stop. Also add &lt;code&gt;-d&lt;/code&gt; to detach (daemon mode).&lt;/p&gt;

&lt;p&gt;To connect to it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker exec -it mariadb mysql -uroot -ppass
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;create-user&quot;&gt;Create user&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE USER &apos;myuser&apos;@&apos;%&apos; IDENTIFIED BY &apos;password&apos;;

GRANT ALL PRIVILEGES ON mydatabase.* TO &apos;myuser&apos;@&apos;%&apos;;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note: &lt;code&gt;localhost&lt;/code&gt; used as the host only allows access from &lt;code&gt;localhost&lt;/code&gt;, whereas &lt;code&gt;%&lt;/code&gt; allows access from everywhere.&lt;/p&gt;

&lt;h2 id=&quot;create-database&quot;&gt;Create Database&lt;/h2&gt;

&lt;p&gt;After 8.0:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE DATABASE mydatabase CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Before 8.0:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE DATABASE mydatabase CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Version 5.7:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE DATABASE mydatabase CHARACTER SET utf8 COLLATE utf8_general_ci;
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:24:09 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:24:09 +0000</atom:modified>
  <link>https://alexn.org/wiki/mysql/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/mysql/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Nix</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;installuninstall-instructions&quot;&gt;Install/Uninstall instructions&lt;/h2&gt;

&lt;p&gt;Install with:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sh &lt;(curl https://nixos.org/nix/install) --darwin-use-unencrypted-nix-store-volume
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To uninstall:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Remove the entry from &lt;code&gt;fstab&lt;/code&gt; using &lt;code&gt;sudo vifs&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;Destroy the data volume using &lt;code&gt;diskutil apfs deleteVolume&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;Remove the &lt;code&gt;nix&lt;/code&gt; line from &lt;code&gt;/etc/synthetic.conf&lt;/code&gt; or the file&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/functional-streams-for-scala/fs2/blob/main/shell.nix&quot;&gt;Nix configuration for a Scala project&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.softinio.com/post/moving-from-homebrew-to-nix-package-manager/&quot;&gt;Moving from Homebrew to Nix Package Manager&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/gvolpe/nix-config&quot;&gt;Nix sample config&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://nix-tutorial.gitlabpages.inria.fr/nix-tutorial/index.html&quot;&gt;Nix tutorial&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/samdroid-apps/nix-articles&quot;&gt;Environments with Nix Shell&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;aliases&quot;&gt;Aliases&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;alias nix-env-search=&quot;nix-env -qaP&quot;
alias nix-env-install=&quot;nix-env -iA&quot;
alias nix-env-update-all=&quot;nix-channel --update nixpkgs &amp;&amp; nix-env -u &apos;*&apos;&quot;
alias nix-up=&quot;nix-env -u&quot;
alias nix-gc=&quot;nix-collect-garbage -d&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;nix-env-cheatsheet&quot;&gt;Nix-env Cheatsheet&lt;/h2&gt;

&lt;p&gt;List installed packages:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;nix-env --query --installed
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To search for packages:&lt;/p&gt;

&lt;p&gt;https://nixos.org/nixos/packages.html?channel=nixpkgs-unstable&lt;/p&gt;

&lt;p&gt;To install a certain package:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;nix-env -iA nixpkgs.ripgrep
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Uninstall:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;nix-env -e tree ripgrep
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;List generations (all of the different versions of the nix-env profile):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;nix-env --list-generations
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To rollback to a previous version of the profile:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;nix-env --rollback
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or pick a specific generation:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;nix-env --switch-generation 2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To use a program without installing it, we can create a temporary
environment with &lt;code&gt;nix-shell&lt;/code&gt; (in this case &lt;code&gt;tectonic&lt;/code&gt; is the name of
the package we want):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;nix-shell &apos;&lt;nixpkgs&gt;&apos; -A tectonic
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To update all packages:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;nix-channel --update nixpkgs
nix-env -u &apos;*&apos;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;nix-shell-cheatsheet&quot;&gt;Nix-shell Cheatsheet&lt;/h2&gt;

&lt;p&gt;To enable &lt;code&gt;nix-shell&lt;/code&gt; for a project, define a &lt;code&gt;default.nix&lt;/code&gt; in the project’s root, like so:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-nix&quot;&gt;# This imports the nix package collection,
# so we can access the `pkgs` and `stdenv` variables
with import &lt;nixpkgs&gt; {};

# Make a new &quot;derivation&quot; that represents our shell
stdenv.mkDerivation {
  name = &quot;fpinscala-courses&quot;;

  # The packages in the `buildInputs` list will be added to the PATH in our shell
  buildInputs = [
    # see https://nixos.org/nixos/packages.html to search for more
    pkgs.tectonic
    pkgs.cmake
  ];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then execute &lt;code&gt;nix-shell&lt;/code&gt; in the directory.&lt;/p&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:24:15 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:24:15 +0000</atom:modified>
  <link>https://alexn.org/wiki/nix/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/nix/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Org-mode</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;shortcuts&quot;&gt;Shortcuts&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;code&gt;C-c a&lt;/code&gt; show agenda&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;C-c C-t&lt;/code&gt; rotate state (change TODO to DONE)&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;C-c C-s&lt;/code&gt; schedule&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;C-c C-x p&lt;/code&gt; set property (e.g. &lt;code&gt;STYLE&lt;/code&gt; to &lt;code&gt;habit&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;M-x org-time-stamp-inactive&lt;/code&gt; for inserting the current date&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For clock timing:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;code&gt;C-c C-x C-i&lt;/code&gt;: start clock&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;C-c C-x C-o&lt;/code&gt;: stop the clock&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;C-c C-x C-d&lt;/code&gt;: display times&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;M-x org-resolve-clocks&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;repeated-tasks&quot;&gt;Repeated tasks&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://orgmode.org/manual/Repeated-tasks.html&quot;&gt;Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using a &lt;code&gt;+1m&lt;/code&gt; says the date shift is exactly one month:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-org&quot;&gt;** TODO Pay the rent
   DEADLINE: &lt;2005-11-01 Tue +1m&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Using &lt;code&gt;++1w&lt;/code&gt; shifts the date by at least one week, but also by as many
weeks as it takes to get this date into the future. However, it stays
on a Sunday, even if you called and marked it done on Saturday:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-org&quot;&gt;** TODO Call Father
   DEADLINE: &lt;2008-02-10 Sun ++1w&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Using &lt;code&gt;.+1m&lt;/code&gt; will shift the date to one month after today:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-org&quot;&gt;** TODO Check the batteries in the smoke detectors
   DEADLINE: &lt;2005-11-01 Tue .+1m&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;deadline-vs-scheduling&quot;&gt;DEADLINE vs SCHEDULING&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://orgmode.org/manual/Deadlines-and-scheduling.html&quot;&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DEADLINE&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the task is supposed to be finished on that date&lt;/li&gt;
  &lt;li&gt;the agenda for today will carry a warning about the approaching or missed deadline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;SCHEDULED&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;you are planning to start working on that task on the given date&lt;/li&gt;
  &lt;li&gt;a reminder that the scheduled date has passed will be present in the compilation for today, until the entry is marked DONE&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:24:22 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:24:22 +0000</atom:modified>
  <link>https://alexn.org/wiki/org-mode/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/org-mode/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>PostgreSQL</title>
  <description>Article
    updated at September 2, 2025, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 2, 2025, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;creating-new-database-and-user&quot;&gt;Creating new database and user&lt;/h2&gt;

&lt;p&gt;Open the client:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;psql -U postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Execute:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE DATABASE yourdbname;
CREATE USER youruser WITH ENCRYPTED PASSWORD &apos;yourpass&apos;;
GRANT ALL PRIVILEGES ON DATABASE yourdbname TO youruser;
ALTER DATABASE yourdbname OWNER TO youruser;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;running-in-a-docker-container&quot;&gt;Running in a Docker container&lt;/h2&gt;

&lt;p&gt;Setup for &lt;code&gt;docker-compose.yaml&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;services:
  postgresdb:
    container_name: postgresdb
    image: &apos;postgres:15-alpine&apos;
    volumes:
      - &apos;postgres-db:/var/lib/postgresql/data&apos;
    restart: unless-stopped
    env_file:
      - ./envs/postgres.env
    networks:
      - main

networks:
  main:
    name: main

volumes:
  postgres-db:
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Where &lt;code&gt;./envs/postgres.env&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;POSTGRES_PASSWORD=&quot;your-admin-password&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;backup-and-restore&quot;&gt;Backup and Restore&lt;/h2&gt;

&lt;p&gt;Assuming a Docker container, to create a backup:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker exec -i postgresdb pg_dumpall -U postgres | gzip &gt; /tmp/dump.sql.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To restore from that backup:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;gunzip -c /tmp/dump.sql.gz | docker exec -i postgresdb psql -U postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;documentation&quot;&gt;Documentation&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://pglocks.org/&quot;&gt;PostgreSQL Lock Conflicts&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Tue, 02 Sep 2025 12:04:07 +0000</dc:modified>
  <atom:modified>Tue, 02 Sep 2025 12:04:07 +0000</atom:modified>
  <link>https://alexn.org/wiki/postgresql/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/postgresql/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Python</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;pyenv--virtualenv&quot;&gt;Pyenv + Virtualenv&lt;/h2&gt;

&lt;p&gt;Requirements:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pyenv/pyenv&quot;&gt;pyenv&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pyenv/pyenv-virtualenv&quot;&gt;pyenv-virtualenv&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pypa/virtualenv&quot;&gt;virtualenv&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Installation via Homebrew:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;brew install pyenv pyenv-virtualenv
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;List available versions:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pyenv install --list
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Install a specific Python version:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pyenv install 2.7.16
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Create a new virtualenv:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pyenv virtualenv 2.7.16 my_project_name
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Uninstall a virtualenv:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pyenv uninstall my_project_name
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To activate an environment manually:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pyenv activate my_project_name
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To automatically switch virtualenv when switching to a project’s directory, go
to the project’s directory and create &lt;code&gt;.python-version&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;echo &quot;my_project_name&quot; &gt; .python-version
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:25:03 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:25:03 +0000</atom:modified>
  <link>https://alexn.org/wiki/python/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/python/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>RSS / Atom feeds</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;readers&quot;&gt;Readers&lt;/h2&gt;

&lt;p&gt;Web:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://feedly.com/&quot;&gt;Feedly&lt;/a&gt; (web)&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://freshrss.org/&quot;&gt;FreshRSS&lt;/a&gt; (web, open source, self-hosted)&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/miniflux/miniflux&quot;&gt;Miniflux&lt;/a&gt; (web, open-source, self-hosted)&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://newsblur.com&quot;&gt;Newsblur&lt;/a&gt; (web, open source)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Native, MacOS:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://reederapp.com/&quot;&gt;Reeder&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://ranchero.com/netnewswire/&quot;&gt;NetNewsWire&lt;/a&gt; (open source)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Native, Linux:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://gitlab.com/news-flash/news_flash_gtk&quot;&gt;NewsFlash&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Native, Android:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.seazon.feedme&amp;hl=en_US&amp;gl=US&quot;&gt;FeedMe&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=me.hyliu.fluent_reader_lite&amp;hl=en_US&amp;gl=US&quot;&gt;Fluent Reader Lite&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;recommendation-newsblur&quot;&gt;Recommendation: Newsblur&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://newsblur.com&quot;&gt;Newsblur&lt;/a&gt; is probably the best:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Mobile client included for Android/iOS, OK for tablets, readable, auto Dark Mode, good integration&lt;/li&gt;
  &lt;li&gt;Organizing with multiple categories per feed&lt;/li&gt;
  &lt;li&gt;Newsletters forwarding support&lt;/li&gt;
  &lt;li&gt;Filtering via “infrequent articles” and training&lt;/li&gt;
  &lt;li&gt;Easy to migrate away&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;self-hosted-recommendation-freshrss&quot;&gt;Self-hosted recommendation: FreshRSS&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://freshrss.org/&quot;&gt;FreshRSS&lt;/a&gt; is the best for self-hosting:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Very easy to install and manage via Docker&lt;/li&gt;
  &lt;li&gt;Responsive web design, can work on mobile without client&lt;/li&gt;
  &lt;li&gt;Exposes the Fever and the GReader APIs out of the box, compatible with Reeder and other clients&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Annoyances:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Feeds can’t belong to multiple categories, making organization hard&lt;/li&gt;
  &lt;li&gt;Filtering support for dealing with noise is only rudimentary&lt;/li&gt;
  &lt;li&gt;Couldn’t find any Android clients that I liked (FeedMe is close)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://mailchimp.com/features/rss-to-email/&quot;&gt;Mailchimp RSS to Email&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/jekyll/jekyll-feed&quot;&gt;jekyll-feed&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:25:10 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:25:10 +0000</atom:modified>
  <link>https://alexn.org/wiki/rss-feeds/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/rss-feeds/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Rust</title>
  <description>Article
    updated at September 15, 2024, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 15, 2024, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;See &lt;a href=&quot;https://www.rust-lang.org/tools/install&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To update Rust:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;rustup update
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To uninstall:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;rustup self uninstall
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;tools-libraries&quot;&gt;Tools, Libraries&lt;/h2&gt;

&lt;p&gt;Build tools:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/rust-lang/rust-clippy&quot;&gt;rust-clippy&lt;/a&gt;: linting for catching common mistakes;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://github.com/rust-lang/rustfmt&quot;&gt;rustfmt&lt;/a&gt;: automatic code formatting;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fun stuff:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://neon-bindings.com/&quot;&gt;Neon: Write fast, safe native Node plugins with Rust&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://amethyst.rs/&quot;&gt;Amethyst - Game Engine&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Web:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://leptos.dev/&quot;&gt;Leptos&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://rocket.rs/&quot;&gt;Rocket&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.arewewebyet.org/&quot;&gt;Other&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;documentation&quot;&gt;Documentation&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://doc.rust-lang.org/&quot;&gt;The Rust Programming Language&lt;/a&gt;: official book for beginners&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://doc.rust-lang.org/rust-by-example/&quot;&gt;Rust by Example&lt;/a&gt;: another official book&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://rust-unofficial.github.io/too-many-lists/&quot;&gt;Learn Rust With Entirely Too Many Linked Lists&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://rust-lang.github.io/async-book/&quot;&gt;Asynchronous Programming in Rust&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://sokoban.iolivia.me/&quot;&gt;Rust Sokoban&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tourofrust.com/&quot;&gt;Tour of Rust&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;exercises&quot;&gt;Exercises&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rustlings/&quot;&gt;Rustlings&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;tutorials&quot;&gt;Tutorials&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=DMAnfOlhSpU&quot;&gt;Choosing Rust - Intro to Rust and Ownership&lt;/a&gt; (YouTube video)&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=GFi_EdS_s_c&quot;&gt;Beginning Game Development with Amethyst&lt;/a&gt; (YouTube video)
    &lt;ul&gt;
      &lt;li&gt;
&lt;a href=&quot;https://mtigley.dev/posts/sprite-animations-with-amethyst/&quot;&gt;Creating a Simple Spritesheet Animation with Amethyst&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20200915172323/https://mtigley.dev/posts/sprite-animations-with-amethyst/&quot;&gt;archive&lt;/a&gt;)&lt;/li&gt;
      &lt;li&gt;
&lt;a href=&quot;https://mtigley.dev/posts/running-animation/&quot;&gt;Running Animation&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20200915172354/https://mtigley.dev/posts/running-animation/&quot;&gt;archive&lt;/a&gt;)&lt;/li&gt;
      &lt;li&gt;
&lt;a href=&quot;https://mtigley.dev/posts/camera-follow-system/&quot;&gt;Camera Follow System&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20200821172558/https://mtigley.dev/posts/camera-follow-system/&quot;&gt;archive&lt;/a&gt;)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;how-to&quot;&gt;How-to&lt;/h2&gt;

&lt;h3 id=&quot;cargo&quot;&gt;Cargo&lt;/h3&gt;

&lt;p&gt;To start a new project:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cargo new hello_world
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To build:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;carbo build

# To build for release:

cargo build --release

# Type checks (faster than &quot;build&quot;):

cargo check
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To compile and execute the project:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cargo run
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To update dependencies:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cargo update
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To generate and show the documentation of all dependencies:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cargo doc --open
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;language-server&quot;&gt;Language Server&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;rustup component add rls
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Sun, 15 Sep 2024 15:15:04 +0000</dc:modified>
  <atom:modified>Sun, 15 Sep 2024 15:15:04 +0000</atom:modified>
  <link>https://alexn.org/wiki/rust/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/rust/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Teach Kids to Code</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;p&gt;Platforms, engines, toys:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;http://worrydream.com/AlligatorEggs/&quot;&gt;Alligator Eggs&lt;/a&gt;: offline games&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://codecombat.com/&quot;&gt;Code Combat&lt;/a&gt;: learn typed code through a programming game, learn Python, JavaScript, and HTML as you solve puzzles&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://code.world/#&quot;&gt;Code World&lt;/a&gt; (from Google): educational computer programming environment using Haskell (&lt;a href=&quot;https://youtu.be/mFSeyhkPTAs&quot;&gt;intro video&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.codingame.com/&quot;&gt;CodinGame&lt;/a&gt;: challenge-based training platform for programmers where you can improve your coding skills with fun exercises&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://godotengine.org/&quot;&gt;Godot game engine&lt;/a&gt;: provides a huge set of common tools, so you can just focus on making your game without reinventing the wheel&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;http://kogics.net/kojo&quot;&gt;Kojo&lt;/a&gt;: open source learning environment, Scala programs&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.cmu.edu/roboticsacademy/roboticscurriculum/Lego%20Curriculum/EV3-Intro.html&quot;&gt;Lego Mindstorms EV3&lt;/a&gt;: programmable robotics kit&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://lightbot.com/&quot;&gt;Lightbot&lt;/a&gt;: solve puzzles using programming&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.mecabricks.com/&quot;&gt;MecaBricks&lt;/a&gt;: publish and display 3D models made with LEGO bricks&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.microsoft.com/en-us/makecode?rtc=1&quot;&gt;Microsoft MakeCode&lt;/a&gt; / &lt;a href=&quot;https://arcade.makecode.com/&quot;&gt;MakeCode Arcade&lt;/a&gt;: brings computer science to life for all students with fun projects, immediate results, and both block and text editors for learners at different levels&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://ozobot.com/&quot;&gt;Ozobot&lt;/a&gt;: makes desk-friendly coding robots that come with infinite ways to create, learn, and share&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.puzzlescript.net/&quot;&gt;PuzzleScript&lt;/a&gt;: open-source HTML5 puzzle game engine&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.pygame.org/&quot;&gt;PyGame&lt;/a&gt;: a cross-platform set of Python modules designed for writing video games&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://scratch.mit.edu/&quot;&gt;Scratch&lt;/a&gt;: Create stories, games, and animations&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://sonic-pi.net/&quot;&gt;Sonic Pi&lt;/a&gt;: code-based music creation and performance tool&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://sphero.com/products/sphero-bolt&quot;&gt;Sphero BOLT&lt;/a&gt;: programmable robot ball&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.apple.com/swift/playgrounds/&quot;&gt;Swift Playgrounds&lt;/a&gt;: revolutionary app for iPad and Mac that makes learning Swift interactive and fun&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://tidalcycles.org/index.php/Welcome&quot;&gt;TidalCycles&lt;/a&gt;: make patterns with code, whether live coding music at algoraves or composing in the studio&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.turingtumble.com/&quot;&gt;Turing Tumble&lt;/a&gt;: a game where players build marble-powered computers to solve logic puzzles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Books:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;http://landoflisp.com/&quot;&gt;Land of Lisp&lt;/a&gt;: learn to program in Lisp, one game at a time&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://nostarch.com/realmofracket.htm&quot;&gt;Realm of Racket&lt;/a&gt;: learn to program in Racket, one game at a time&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;http://teachyourkidstocode.com/&quot;&gt;Teach Your Kids to Code&lt;/a&gt;: book and Udemy online course teaching to build apps and games in Python&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Articles &amp; Videos:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://youtu.be/g1ib43q3uXQ&quot;&gt;How to teach programming (and other things)?&lt;/a&gt; by Felienne Hermans&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.snoyman.com/blog/2018/12/kids-coding-interlude-the-function-game&quot;&gt;Kids Coding Interlude&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.ted.com/talks/mitch_resnick_let_s_teach_kids_to_code&quot;&gt;Scratch Ted Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.itworld.com/article/2978142/why-john-carmack-thinks-racket-is-aces-for-beginning-programmers.html&quot;&gt;Why John Carmack thinks Racket is aces for beginning programmers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Courses:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.coderdojo.ro/&quot;&gt;Coder Dojo&lt;/a&gt;: a volunteer-led community of free programming workshops for young people between 7 and 17&lt;/li&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.edx.org/course/scratch-programming-for-kids-8&quot;&gt;Scratch: Programming for Kids (8+)&lt;/a&gt;: MOOC from EdX&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;games&quot;&gt;Games&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://libgdx.com/&quot;&gt;libGDX&lt;/a&gt;: Desktop/Android/HTML5/iOS Java game development framework
    &lt;ul&gt;
      &lt;li&gt;
&lt;a href=&quot;https://github.com/libktx/ktx&quot;&gt;KTX&lt;/a&gt;: Kotlin extensions for the libGDX game framework&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:25:25 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:25:25 +0000</atom:modified>
  <link>https://alexn.org/wiki/teach-kids/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/teach-kids/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>tmux shortcuts &amp; cheatsheet</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;start new:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;tmux
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;start new with session name:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;tmux new -s myname
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;attach:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;tmux a  #  (or at, or attach)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;attach to named:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;tmux a -t myname
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;list sessions:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;tmux ls
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a name=&quot;killSessions&quot; href=&quot;&quot;&gt;&lt;/a&gt;kill session:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;tmux kill-session -t myname
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a name=&quot;killAllSessions&quot; href=&quot;&quot;&gt;&lt;/a&gt;Kill all the tmux sessions:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;tmux ls | grep : | cut -d. -f1 | awk &apos;{print substr($1, 0, length($1)-1)}&apos; | xargs kill
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In tmux, hit the prefix &lt;code&gt;ctrl+b&lt;/code&gt; (my modified prefix is ctrl+a) and then:&lt;/p&gt;

&lt;h2 id=&quot;sessions&quot;&gt;Sessions&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;:new&lt;CR&gt;  new session
s  list sessions
$  name session
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;windows-tabs&quot;&gt;Windows (tabs)&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;c  create window
w  list windows
n  next window
p  previous window
f  find window
,  name window
&amp;  kill window
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;panes-splits&quot;&gt;Panes (splits)&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;%  vertical split
&quot;  horizontal split

o  swap panes
q  show pane numbers
x  kill pane
+  break pane into window (e.g. to select text by mouse to copy)
-  restore pane from window
⍽  space - toggle between layouts
&lt;prefix&gt; q (Show pane numbers, when the numbers show up type the key to goto that pane)
&lt;prefix&gt; { (Move the current pane left)
&lt;prefix&gt; } (Move the current pane right)
&lt;prefix&gt; z toggle pane zoom
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;sync-panes&quot;&gt;Sync Panes&lt;/h2&gt;

&lt;p&gt;You can do this by switching to the appropriate window, typing your Tmux prefix (commonly Ctrl-B or Ctrl-A) and then a colon to bring up a Tmux command line, and typing:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:setw synchronize-panes
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can optionally add on or off to specify which state you want; otherwise the option is simply toggled. This option is specific to one window, so it won’t change the way your other sessions or windows operate. When you’re done, toggle it off again by repeating the command. &lt;a href=&quot;http://blog.sanctum.geek.nz/sync-tmux-panes/&quot;&gt;tip source&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;resizing-panes&quot;&gt;Resizing Panes&lt;/h2&gt;

&lt;p&gt;You can also resize panes if you don’t like the layout defaults. I personally rarely need to do this, though it’s handy to know how. Here is the basic syntax to resize panes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;PREFIX : resize-pane -D (Resizes the current pane down)
PREFIX : resize-pane -U (Resizes the current pane upward)
PREFIX : resize-pane -L (Resizes the current pane left)
PREFIX : resize-pane -R (Resizes the current pane right)
PREFIX : resize-pane -D 20 (Resizes the current pane down by 20 cells)
PREFIX : resize-pane -U 20 (Resizes the current pane upward by 20 cells)
PREFIX : resize-pane -L 20 (Resizes the current pane left by 20 cells)
PREFIX : resize-pane -R 20 (Resizes the current pane right by 20 cells)
PREFIX : resize-pane -t 2 20 (Resizes the pane with the id of 2 down by 20 cells)
PREFIX : resize-pane -t -L 20 (Resizes the pane with the id of 2 left by 20 cells)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;copy-mode&quot;&gt;Copy mode:&lt;/h2&gt;

&lt;p&gt;Pressing PREFIX [ places us in Copy mode. We can then use our movement keys to move our cursor around the screen. By default, the arrow keys work. we set our configuration file to use Vim keys for moving between windows and resizing panes so we wouldn’t have to take our hands off the home row. tmux has a vi mode for working with the buffer as well. To enable it, add this line to .tmux.conf:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;setw -g mode-keys vi
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With this option set, we can use h, j, k, and l to move around our buffer.&lt;/p&gt;

&lt;p&gt;To get out of Copy mode, we just press the ENTER key. Moving around one character at a time isn’t very efficient. Since we enabled vi mode, we can also use some other visible shortcuts to move around the buffer.&lt;/p&gt;

&lt;p&gt;For example, we can use “w” to jump to the next word and “b” to jump back one word. And we can use “f”, followed by any character, to jump to that character on the same line, and “F” to jump backwards on the line.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;   Function                vi             emacs
   Back to indentation     ^              M-m
   Clear selection         Escape         C-g
   Copy selection          Enter          M-w
   Cursor down             j              Down
   Cursor left             h              Left
   Cursor right            l              Right
   Cursor to bottom line   L
   Cursor to middle line   M              M-r
   Cursor to top line      H              M-R
   Cursor up               k              Up
   Delete entire line      d              C-u
   Delete to end of line   D              C-k
   End of line             $              C-e
   Goto line               :              g
   Half page down          C-d            M-Down
   Half page up            C-u            M-Up
   Next page               C-f            Page down
   Next word               w              M-f
   Paste buffer            p              C-y
   Previous page           C-b            Page up
   Previous word           b              M-b
   Quit mode               q              Escape
   Scroll down             C-Down or J    C-Down
   Scroll up               C-Up or K      C-Up
   Search again            n              n
   Search backward         ?              C-r
   Search forward          /              C-s
   Start of line           0              C-a
   Start selection         Space          C-Space
   Transpose chars                        C-t
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;misc&quot;&gt;Misc&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;d  detach
t  big clock
?  list shortcuts
:  prompt
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;configurations-options&quot;&gt;Configurations Options:&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;# Mouse support - set to on if you want to use the mouse
* setw -g mode-mouse off
* set -g mouse-select-pane off
* set -g mouse-resize-pane off
* set -g mouse-select-window off

# Set the default terminal mode to 256color mode
set -g default-terminal &quot;screen-256color&quot;

# enable activity alerts
setw -g monitor-activity on
set -g visual-activity on

# Center the window list
set -g status-justify centre

# Maximize and restore a pane
unbind Up bind Up new-window -d -n tmp \; swap-pane -s tmp.1 \; select-window -t tmp
unbind Down
bind Down last-window \; swap-pane -s tmp.1 \; kill-window -t tmp
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources:&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://pragprog.com/book/bhtmux/tmux&quot;&gt;tmux: Productive Mouse-Free Development&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://superuser.com/questions/343572/tmux-how-do-i-reorder-my-windows&quot;&gt;How to reorder windows&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;credits&quot;&gt;Credits&lt;/h2&gt;

&lt;p&gt;Forked from: &lt;a href=&quot;https://gist.github.com/MohamedAlaa/2961058&quot;&gt;https://gist.github.com/MohamedAlaa/2961058&lt;/a&gt;&lt;/p&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:25:45 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:25:45 +0000</atom:modified>
  <link>https://alexn.org/wiki/tmux/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/tmux/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Windows 10</title>
  <description>Article
    updated at January 21, 2025, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at January 21, 2025, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;h2 id=&quot;installation-on-macbooks&quot;&gt;Installation on Macbooks&lt;/h2&gt;

&lt;h3 id=&quot;create-bootable-usb-stick-for-installing-windows&quot;&gt;Create bootable USB stick for installing Windows&lt;/h3&gt;

&lt;p&gt;1: Download the Windows ISO file from Microsoft’s website.
2: Identify the disk number of the USB drive: &lt;code&gt;diskutil list&lt;/code&gt;
3: &lt;code&gt;diskutil unmountDisk /dev/diskN&lt;/code&gt; 
4: &lt;code&gt;sudo dd if=/path/to/windows.iso of=/dev/rdiskN bs=1m&lt;/code&gt;&lt;/p&gt;

&lt;h3 id=&quot;boot-camp&quot;&gt;Boot Camp&lt;/h3&gt;

&lt;p&gt;To download the drivers:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;From MacOS: Boot Camp Assistant -&gt; Menu -&gt; “Action” -&gt; “Download Windows Support Software”&lt;/li&gt;
  &lt;li&gt;From Windows: &lt;a href=&quot;https://github.com/timsutton/brigadier&quot;&gt;https://github.com/timsutton/brigadier&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;third-party-utilities&quot;&gt;Third-party utilities&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;To make the Macbook’s touchpad not suck: &lt;a href=&quot;https://github.com/imbushuo/mac-precision-touchpad&quot;&gt;https://github.com/imbushuo/mac-precision-touchpad&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;support-for-hyper-threading&quot;&gt;Support for Hyper-Threading&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Source: &lt;a href=&quot;https://news.ycombinator.com/item?id=22875681&quot;&gt;Hacker News comment&lt;/a&gt;
&lt;/li&gt;
  &lt;li&gt;Documentation: &lt;a href=&quot;https://dea.nbird.com.au/2017/02/24/enabling-vt-x-on-mac-book-air-in-bootcamp/&quot;&gt;Enabling VT-x on Mac Book Air in Bootcamp&lt;/a&gt;
&lt;/li&gt;
  &lt;li&gt;Download: &lt;a href=&quot;https://www.rodsbooks.com/refind/&quot;&gt;rEFInd&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;set-up-tutorials&quot;&gt;Set-up tutorials&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://b.s5.pm/os/2021/08/28/windows-setup.html&quot;&gt;A No-Bullshit Guide to Setting up Windows 10&lt;/a&gt; (&lt;a href=&quot;https://web.archive.org/web/20210809064346/https://b.s5.pm/os/2021/08/28/windows-setup.html&quot;&gt;archive&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Tue, 21 Jan 2025 16:59:34 +0000</dc:modified>
  <atom:modified>Tue, 21 Jan 2025 16:59:34 +0000</atom:modified>
  <link>https://alexn.org/wiki/windows/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/windows/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>Custom Zsh Prompt</title>
  <description>Article
    updated at September 1, 2022, 
    created at August 24, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at August 24, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;p&gt;References:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://scriptingosx.com/2019/07/moving-to-zsh-06-customizing-the-zsh-prompt/&quot;&gt;Moving to zsh, part 6 – Customizing the zsh Prompt&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://jonasjacek.github.io/colors/&quot;&gt;256 COLORS - CHEAT SHEET&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html&quot;&gt;256 Terminal colors and their 24bit equivalent (or
similar)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# ------------------------------------------------------------------------------
# Customize PROMPT
# ------------------------------------------------------------------------------

autoload -Uz vcs_info
precmd_vcs_info() {
  vcs_info
}
precmd_functions+=(precmd_vcs_info)
setopt prompt_subst

export PROMPT=&quot;%F{196}%B%(?..?%? )%b%f%F{117}%2~%f%F{245} %#%f &quot;
export RPROMPT=&quot;%B\$vcs_info_msg_0_%f%b&quot;

zstyle &apos;:vcs_info:git:*&apos; formats &apos;%F{240}%b %f %F{237}%r%f&apos;
zstyle &apos;:vcs_info:*&apos; enable git
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In iTerm2 make sure to enable &lt;a href=&quot;https://www.iterm2.com/documentation-preferences-profiles-text.html&quot;&gt;Use built-in Powerline glyphs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;How this looks:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://alexn.org/wiki/assets/custom-zsh-prompt.png&quot; alt=&quot;Screenshot of zsh prompt&quot; width=&quot;1394&quot; height=&quot;909&quot; style=&quot;max-width:100%;height:auto;&quot;&gt;&lt;/p&gt;</content:encoded><pubDate>Mon, 24 Aug 2020 13:24:31 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:27:13 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:27:13 +0000</atom:modified>
  <link>https://alexn.org/wiki/zshrc-prompt/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/zshrc-prompt/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>

<item>
  <title>DNS Lookup - Check Domain’s DNS Records</title>
  <description>Article
    updated at September 1, 2022, 
    created at July 30, 2020.</description>
  <content:encoded>&lt;p&gt;
    Article
    updated at September 1, 2022, 
    created at July 30, 2020.
  &lt;/p&gt;
  &lt;hr&gt;
  &lt;p&gt;For MX records (email):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;dig mydomain.com MX
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Checking records using different resolvers:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;dig @1.1.1.1 mydomain.com MX # Cloudflare

dig @8.26.56.26 mydomain.com MX # Comodo

dig @8.8.8.8 mydomain.com MX # Google

dig @9.9.9.9 mydomain.com MX # Quad

dig @64.6.65.6 mydomain.com MX # Verisign

dig @192.71.245.208 mydomain.com MX # OpenNIC

dig @91.239.100.100 mydomain.com MX # UncensoredDNS

dig @77.88.8.7 mydomain.com MX # Yandex

dig @156.154.70.1 mydomain.com MX # Ultrarecursive DNS

dig @198.101.242.72 mydomain.com MX # Alternate DNS

dig @176.103.130.130 mydomain.com MX
&lt;/code&gt;&lt;/pre&gt;</content:encoded><pubDate>Thu, 30 Jul 2020 10:00:27 +0000</pubDate>
  <dc:modified>Thu, 01 Sep 2022 14:17:02 +0000</dc:modified>
  <atom:modified>Thu, 01 Sep 2022 14:17:02 +0000</atom:modified>
  <link>https://alexn.org/wiki/dns-lookup/?pk_campaign=rss</link>
  <guid isPermaLink="true">https://alexn.org/wiki/dns-lookup/</guid>
  <dc:creator>Alexandru Nedelcu</dc:creator>
  <category>Wiki</category>
  
</item>
</channel>
</rss>
