Skip to content

Blog

My blog about programming & other stuff

If you find a typo or would like to improve my posts feel free to submit a pull request to https://github.com/inwenis/blog.

Check out my other projects on my github like https://github.com/inwenis/collider where I tried to simulate Brownian motions.

My collection of various kata's I've done: https://github.com/inwenis/kata

I used to teach programming, out of sentiment I kept these two repos: - https://github.com/inwenis/sda.javawwa13.prog1.day5.complexity - https://github.com/inwenis/sda.javawwa13.prog1.day3.array_vs_hashtable

Enjoy!

You can reach me at inwenis at gmail.com

Me gusta

I don't have a better place for this yet so here's a list of links I like: - dict in F# - https://www.fssnip.net/fy/title/Typeinference-friendly-division-and-multiplication

Google/Google Photos

Google products seem to slowly become worse, examples:

  • Gmail no longer recognizes flight itineraries.
  • Google Photos:
    • Removed the map view.
    • Doesn’t let you easily delete all photos.
    • Doesn’t offer a simple way to download everything.
    • Takeout exports require dealing with messy JSON metadata.
  • Google Search:
    • Cluttered with ads.
    • Results feel worse than they used to be.
  • Android removed native phone call recording.
  • YouTube is overloaded with ads.

I just moved away from Google Photos. For geeks I recommend . They're amazing.

Just moved away from Google Photos. For geeks, https://immich.app/ is a great alternative — they're amazing.

To fix the chaos from Google Takeout, I used this https://github.com/TheLastGimbus/GooglePhotosTakeoutHelper.

Would definitely consider paying for Immich if they offered a hosted version.

PowerShell quirk 2

tl;dr

Let's say you have a File[1].txt file and you would like to read it.

Get-Content "File[1].txt"
^ this returns nothing

Why?

PowerShell interprets [] as special characters. A range in this case. PowerShell is actually looking for a file named File1.txt.

What to do?

Get-Content "File``[1``].txt"

longer reads

git goodies

git branch -d `git branch | grep feature`                             # delete all branches with feature in its name
git branch | grep feature | xargs git branch -d                       # same as ^
git push origin --delete branchXYZ                                    # git push origin :branchXYZ
git push origin --delete `git branch -r | grep feature | cut -c10-`   # delete all feature branches from remote
git show branch:file > write_here                                     # https://stackoverflow.com/questions/7856416/view-a-file-in-a-different-git-branch-without-changing-branches
git checkout branch -- path/to/file                                   # similar to previous but checkout the file
git checkout --ours foo/bar.java                                      # useful for rebases or merges, works with --theirs too
git log -p -- src/data_capture_tools                                  # changes only made to a specific directory
git log --all --full-history -- "**/thefile.*"                        # https://stackoverflow.com/questions/7203515/how-to-find-a-deleted-file-in-the-project-commit-history
git log --left-right --graph --cherry-pick --oneline feature...branch # https://til.hashrocket.com/posts/18139f4f20-list-different-commits-between-two-branches

escape!

Why does escaping a character mean escaping a character?

When a C compiler (or any other compiler) encounters a " it thinks to it self "huh, this is the begninning or end of a string!".

Say you need " in your string?

You have to tell the compiler "do not process this character like you always do, I want you to ESCAPE the default processing". You do this with "dear compiler this \" will become a double quotation mark in my string".

Likewise if you want a new line you need to tell the compile "do not process this n as a "n", escape the default processing and process it as a new line \n".

npm wsl EAI_AGAIN

Running npm ci on WSL (Windows Subsystem for Linux) failed with:

npm ERR! syscall getaddrinfo
npm ERR! errno EAI_AGAIN
npm ERR! request to http://registry.npmjs.org/nodemon failed, reason: getaddrinfo EAI_AGAIN registry.npmjs.org

dig registry.npmjs.org
^ confirmed that my Ubuntu WSL can't reach registry.npmjs.org

Solution

In WSL:

rm /etc/resolv.conf
bash -c 'echo "nameserver 8.8.8.8" > /etc/resolv.conf'
bash -c 'echo "[network]" > /etc/wsl.conf'
bash -c 'echo "generateResolvConf = false" >> /etc/wsl.conf'
chattr +i /etc/resolv.conf
^ use 8.8.8.8 (Google's DNS). Stop recreating resolv.conf on startup

In Windows:

Set-Content -Path "C:\Users\{user}\.wslconfig" -Value "[wsl2]`nnetworkingMode=mirrored"

Works now, also on my company's VPN.

kudos https://github.com/microsoft/WSL/issues/5420#issuecomment-646479747

more info https://gist.github.com/machuu/7663aa653828d81efbc2aaad6e3b1431

update 2025-03-18

Today the above solution didn't work - I could not reach 8.8.8.8 - I tested it with dig registry.npmjs.org. This fixed it today :confused:

WSL:

chattr -i /etc/resolv.conf
rm /etc/resolv.conf
rm /etc/wsl.conf

Windows:

rm "C:\Users\{user}\.wslconfig"

Post25

1024 * 1024 - this many bytes is an mibibyte (MiB).

A megabyte like a megameter is 10^6 bytes.

We all frequently say megabyte meaning a mibibyte. Like wise a kilobyte != kibibyte

Unit Abbreviation Size in Bytes
Kibibyte KiB 1,024
Mebibyte MiB 1,048,576
Gibibyte GiB 1,073,741,824
Kilobyte KB 1,000
Megabyte MB 1,000,000
Gigabyte GB 1,000,000,000

Network speeds are measured in Mbps - that is mega bits per second - that is 1,000,000 bits per second.

MB - Megabyte (SI) MiB - Mibibyte (IEC) Mb - Megabit (SI)

https://www.iec.ch/prefixes-binary-multiples

Some neat fsx F#

My company had a hackathon focused on data scraping/processing.

Each team had to scrape 3 endpoints. I came up with something similar to this:

open System
open System.Net.Http
open System.Text

let c = new HttpClient()
c.Timeout <- TimeSpan.FromSeconds(5.0)

let lockObject = new obj()
let printSync text =
    let now = DateTimeOffset.Now.ToString("O")
    lock lockObject (fun _ -> printfn "[%s] %s" now text)

let s = new HttpClient()
s.Timeout <- TimeSpan.FromSeconds(5.0)
s.DefaultRequestHeaders.Add("X-Sender", "this is me, Mario!")
let sendToDestination stream response = async {
    let template = """{
    "CreatedAt": "xxXCreatedAtXxx",
    "Stream": "xxXStreamXxx",
    "Data": [
        xxXDataXxx
    ]
}"""
    let payload = template.Replace("xxXCreatedAtXxx", DateTimeOffset.Now.ToString("O"))
                          .Replace("xxXStreamXxx", stream)
                          .Replace("xxXDataXxx", response)
    let! response = s.PostAsync("http://localhost:8080", new StringContent(payload, Encoding.UTF8, "application/json") ) |> Async.AwaitTask
    sprintf "%s done sending response code %A" stream response.StatusCode |> printSync
}

let scraper (url:string) stream = async {
    while true do
        try
            let! response = c.GetStringAsync(url) |> Async.AwaitTask
            do! sendToDestination stream response
            sprintf "scraped %40s sendTo %s" url stream |> printSync
        with
        | _ -> sprintf "failed to scrape/or send %40s" url |> printSync

        do! Async.Sleep 1000
}

let urls = [
    "https://jsonplaceholder.typicode.com/posts", "123"
    "https://jsonplaceholder.typicode.com/posts", "124"
    "https://jsonplaceholder.typicode.com/posts", "125"
]

urls
|> List.map (fun (url, stream) -> scraper url stream)
|> Async.Parallel
|> Async.Ignore
|> Async.Start

// Async.CancelDefaultToken()

Things to keep in mind:

  • always have a try/catch all exceptions in async/tasks/threads
    • you don't want your thread to die without you knowing
  • always set a timeout when scraping (default timeout in .NET is 100s which is excessive for this script)

A minimalistic http server to listen to our scrapers:

open System.Net
open System.Text

// https://sergeytihon.com/2013/05/18/three-easy-ways-to-create-simple-web-server-with-f/
// run with `fsi --load:ws.fsx`
// visit http://localhost:8080

let host = "http://localhost:8080/"

let listener (handler:(HttpListenerRequest->HttpListenerResponse->Async<unit>)) =
    let hl = new HttpListener()
    hl.Prefixes.Add host
    hl.Start()
    let task = Async.FromBeginEnd(hl.BeginGetContext, hl.EndGetContext)
    async {
        while true do
            let! context = task
            Async.Start(handler context.Request context.Response)
    } |> Async.Start

listener (fun req response ->
    async {
        response.ContentType <- "text/html"
        let bytes = UTF8Encoding.UTF8.GetBytes("thanks!")
        response.OutputStream.Write(bytes, 0, bytes.Length)
        response.OutputStream.Close()
    })

PowerShell Gotcha! - dynamic scoping

PowerShell uses dynamic scoping. Yet the about_Scopes page doesn't mention the word "dynamic".

Wird (wird - so weird that you need to misspell weird to get your point across).

tl;dr;

In PowerShell variables are copied into the stack frame created for the function you're calling. So the "child" function can use your variables but can only modify its own copies. You can avoid this by setting your variable to private $private:varName=... and using Set-StrictMode -version latest to throw an error if "child" functions try to access a undefined variable.

PowerShell uses dynamic scoping. What we know from most programming languages is lexical scoping.


function Do-InnerFunction  { Write-Host $t }
function Do-OutterFunction {
    $t = "hello"
    Do-InnerFunction
}

Do-OutterFunction
hello

Weird! (this is dynamic scoping)


Set-StrictMode -Version Latest
function Do-InnerFunction  { Write-Host $t }
function Do-OutterFunction {
    $t = "hello"
    Do-InnerFunction
}

Do-OutterFunction
Set-StrictMode -Off # remember to turn strict mode off for further testing
hello

Weird! (but makes sense since in PowerShell's world this is perfectly legal hence "strict" changes nothing here)


function Do-InnerFunction  { Write-Host $t }
function Do-OutterFunction {
    $private:t = "hello"
    Do-InnerFunction
}

Do-OutterFunction

Output is empty. No errors but at least $t behaves more like a variable we know from C#/F#.


Set-StrictMode -Version Latest
function Do-InnerFunction  { Write-Host $t }
function Do-OutterFunction {
    $private:t = "hello"
    Do-InnerFunction
}

Do-OutterFunction
InvalidOperation: C:\Users\...\Temp\44f5ff41-4105-482b-a134-b505049d2c61\test3.ps1:2
Line |
   2 |      Write-Host $t
     |                 ~~
     | The variable '$t' cannot be retrieved because it has not been set.

Finally!


function Do-InnerFunction {
    Write-Host $t
    $t = "world"
    Write-Host $t
}

function Do-OutterFunction {
    $t = "hello"
    Do-InnerFunction
    Write-Host $t
}

Do-OutterFunction
hello
world
hello

Ah! So variables are copied to the next "scope".


function Do-InnerFunction {
    Write-Host $t
    $global:t = "world"
    Write-Host $t
}

function Do-OutterFunction {
    $t = "hello"
    Do-InnerFunction
    Write-Host $t
}

Do-OutterFunction
Write-Host $t
hello
hello
hello
world

Now we have created a global $t variable.

This https://ig2600.blogspot.com/2010/01/powershell-is-dynamically-scoped-and.html explains it nicely.

Post22

W chatce w lesie siedzi Pan
Nie odzywa się do nikogo bo jest sam
Myśli ciężkie, głowa pogrążona w chorobie
Zaraz zawiśnie na grobie
Wspomnienia zaplątane same w sobie
Siedzi, mruga, własną głowę zruga
Pora zaraz będzie na spanie
A on wciąż, o matko Boska, gdzie jego posłanie?
Poradzić nic nie może, bo siedzi wciąż na dworze
Robaczki, wykałaczki go wkurwiają
Chciałby uciec jak ten zając
co poradzić temu Panu?
Myślę że to cud że doszedł aż tu
Drogi miał w brud
Co zrobić? Ktr pomoże
Matko boska on wciąż siedzi na dworze
Siedzi, mruga
Fajkę pyka
Tytoń słaby
Jest już cały osiwiały