Skip Navigation

  • I'd say fsnotify is the least interesting part

  • Spectacle OCR is fantastic news. That is really going to simplify one of my current workflows.

  • It’s Lemmy.

  • Accessibility @programming.dev

    Apple, What Have You Done?

    onlinegoddess.net /2026/01/apple-what-have-you-done/
  • I have used and enjoyed lawnchair for the past year. It's quite minimal and I've found it very stable.

  • Accessibility @programming.dev

    CAPTCHAs are over (in ticketing)

    behind.pretix.eu /2025/05/23/captchas-are-over/
  • How is Lobste.rs? Why did it break from HN? How does one even get in?

    Jump
  • Personally, I think it's great. It's a smaller community than HN and the registration requirements, whilst not a perfect solution, do create a litmus test and ultimately creates an envrionment of mostly high quality posting.

    To get in, you need to be invited in by an existing user. If you don't know anybody, you can hang around on their IRC channel and once you're familiar, somebody may be willing to invite you.

  • Deleted Locked

    Permanently Deleted

    Jump
  • This should have been posted in programming.dev/c/meta. I'm leaving it up here as the question has been answered.

  • Thanks - appreciate the feedback!

  • I'm a bit less extreme about it than many here. But, in short, back when Reddit made sweeping API changes it immediately gave me 'the ick' and so I sought less centralised platforms. Lemmy is the closest thing I've found to people just hosting their own message boards like back in the early internet.

    I'm a big fan of decentralized platforms and I love the concept of ActivityPub.

    That said, I still use Reddit and have recently started to really enjoy BlueSky, so I'm not militantly against the corporate platforms or anything.

    Finally, I just like the natural selection things like Lemmy and Mastodon have for those who are naturally more techy and nerdy.

  • Gleam

    Late as usual. This one challenged me. Functional programming is a lot of fun, but it's kicking my ass.

     gleam
        
    import gleam/dict
    import gleam/io
    import gleam/list
    import gleam/option.{None, Some}
    import gleam/result
    import gleam/set.{type Set}
    import gleam/string
    import simplifile
    
    pub type Point =
      #(Int, Int)
    
    pub type Grid(a) =
      dict.Dict(Point, a)
    
    pub type Direction {
      North
      East
      South
      West
    }
    
    pub type Loops {
      DoesLoop
      DoesNotLoop
    }
    
    pub type Guard {
      Guard(position: Point, direction: Direction)
    }
    
    fn get_guard(grid: Grid(String)) -> Guard {
      let pos = dict.filter(grid, fn(_pos, char) { char == "^" })
      let assert Ok(pos) = case dict.size(pos) {
        1 -> list.first(dict.keys(pos))
        0 -> panic as "No guard found in input!"
        _ -> panic as "More than one guard found in input!"
      }
      Guard(pos, North)
    }
    
    fn move_guard(guard: Guard) -> Guard {
      let new_pos = case guard.direction {
        North -> #(-1, 0)
        East -> #(0, 1)
        South -> #(1, 0)
        West -> #(0, -1)
      }
      Guard(
        #(guard.position.0 + new_pos.0, guard.position.1 + new_pos.1),
        guard.direction,
      )
    }
    
    fn turn_guard(guard: Guard) -> Guard {
      let new_dir = case guard.direction {
        North -> East
        East -> South
        South -> West
        West -> North
      }
      Guard(guard.position, new_dir)
    }
    
    fn get_obstacles(grid: Grid(String)) -> List(Point) {
      dict.filter(grid, fn(_pos, char) { char == "#" })
      |> dict.keys()
    }
    
    fn recurse_grid(
      grid: Grid(String),
      guard: Guard,
      obstacles: List(#(Int, Int)),
      visited: Set(#(#(Int, Int), Direction)),
    ) -> #(Set(#(#(Int, Int), Direction)), Loops) {
      let new_guard = move_guard(guard)
      let position = new_guard.position
      let dir = new_guard.direction
      case dict.has_key(grid, position) {
        False -> #(visited, DoesNotLoop)
        True -> {
          case set.contains(visited, #(position, dir)) {
            True -> {
              #(visited, DoesLoop)
            }
            False -> {
              case list.contains(obstacles, position) {
                True -> recurse_grid(grid, turn_guard(guard), obstacles, visited)
                False ->
                  recurse_grid(
                    grid,
                    new_guard,
                    obstacles,
                    set.insert(visited, #(position, dir)),
                  )
              }
            }
          }
        }
      }
    }
    
    fn get_grid_input(filename: String) -> Grid(String) {
      let lines =
        filename
        |> simplifile.read()
        |> result.unwrap("")
        |> string.trim()
        |> string.split("\n")
      use grid, row, row_idx <- list.index_fold(lines, dict.new())
      use grid, col, col_idx <- list.index_fold(string.to_graphemes(row), grid)
      dict.insert(grid, #(row_idx, col_idx), col)
    }
    
    fn part_one(
      grid: Grid(String),
    ) -> #(#(Set(#(#(Int, Int), Direction)), Loops), Int) {
      let guard = get_guard(grid)
      let obstacles = get_obstacles(grid)
      let visited = set.new() |> set.insert(#(guard.position, guard.direction))
      let visited = recurse_grid(grid, guard, obstacles, visited)
      let visited_without_dir =
        set.fold(visited.0, set.new(), fn(acc, x) { set.insert(acc, x.0) })
      #(visited, visited_without_dir |> set.size())
    }
    
    fn check_loop(grid: Grid(String), blocker: Point) -> Loops {
      let blocked_grid =
        dict.upsert(grid, blocker, fn(x) {
          case x {
            Some("^") -> "^"
            Some(_) -> "#"
            None -> "#"
          }
        })
      let visited = part_one(blocked_grid).0
      visited.1
    }
    
    fn part_two(grid: Grid(String), visited: Set(#(#(Int, Int), Direction))) {
      let visited =
        set.fold(visited, set.new(), fn(acc, x) { set.insert(acc, x.0) })
      use counter, position <- set.fold(visited, 0)
      case check_loop(grid, position) {
        DoesLoop -> counter + 1
        DoesNotLoop -> counter
      }
    }
    
    pub fn main() {
      let input = "input.in"
      let p1 = input |> get_grid_input() |> part_one
      let visited = p1.0.0
      io.debug(p1.1)
      input |> get_grid_input |> part_two(visited) |> io.debug()
    }
    
      
  • Advent Of Code @programming.dev

    Any Gleamings in the house?

  • Gleam

    Struggled with the second part as I am still very new to this very cool language, but got there after scrolling for some inspiration.

     gleam
        
    import gleam/int
    import gleam/io
    import gleam/list
    import gleam/regex
    import gleam/result
    import gleam/string
    import simplifile
    
    pub fn main() {
      let assert Ok(data) = simplifile.read("input.in")
      part_one(data) |> io.debug
      part_two(data) |> io.debug
    }
    
    fn part_one(data) {
      let assert Ok(multiplication_pattern) =
        regex.from_string("mul\\(\\d{1,3},\\d{1,3}\\)")
      let assert Ok(digit_pattern) = regex.from_string("\\d{1,3},\\d{1,3}")
      let multiplications =
        regex.scan(multiplication_pattern, data)
        |> list.flat_map(fn(reg) {
          regex.scan(digit_pattern, reg.content)
          |> list.map(fn(digits) {
            digits.content
            |> string.split(",")
            |> list.map(fn(x) { x |> int.parse |> result.unwrap(0) })
            |> list.reduce(fn(a, b) { a * b })
            |> result.unwrap(0)
          })
        })
        |> list.reduce(fn(a, b) { a + b })
        |> result.unwrap(0)
    }
    
    fn part_two(data) {
      let data = "do()" <> string.replace(data, "\n", "") <> "don't()"
      let assert Ok(pattern) = regex.from_string("do\\(\\).*?don't\\(\\)")
      regex.scan(pattern, data)
      |> list.map(fn(input) { input.content |> part_one })
      |> list.reduce(fn(a, b) { a + b })
    }
    
      
  • Elixir

     elixir
        
    defmodule Day02 do
      defp part1(reports) do
        reports
        |> Enum.map(fn report ->
          levels =
            report
            |> String.split()
            |> Enum.map(&String.to_integer/1)
    
          cond do
            sequence_is_safe?(levels) ->
              :safe
    
            true ->
              :unsafe
          end
        end)
        |> Enum.count(fn x -> x == :safe end)
      end
    
      defp part2(reports) do
        reports
        |> Enum.map(fn report ->
          levels =
            report
            |> String.split()
            |> Enum.map(&String.to_integer/1)
    
          sequences =
            0..(length(levels) - 1)
            |> Enum.map(fn i ->
              List.delete_at(levels, i)
            end)
    
          cond do
            sequence_is_safe?(levels) ->
              :safe
    
            Enum.any?(sequences, &sequence_is_safe?/1) ->
              :safe
    
            true ->
              :unsafe
          end
        end)
        |> Enum.count(fn x -> x == :safe end)
      end
    
      defp all_gaps_within_max_diff?(numbers) do
        numbers
        |> Enum.chunk_every(2, 1, :discard)
        |> Enum.all?(fn [a, b] -> abs(b - a) <= 3 end)
      end
    
      defp is_strictly_increasing?(numbers) do
        numbers
        |> Enum.chunk_every(2, 1, :discard)
        |> Enum.all?(fn [a, b] -> a < b end)
      end
    
      defp is_strictly_decreasing?(numbers) do
        numbers
        |> Enum.chunk_every(2, 1, :discard)
        |> Enum.all?(fn [a, b] -> a > b end)
      end
    
      defp sequence_is_safe?(numbers) do
        (is_strictly_increasing?(numbers) or
           is_strictly_decreasing?(numbers)) and all_gaps_within_max_diff?(numbers)
      end
    
      def run(data) do
        reports = data |> String.split("\n", trim: true)
        p1 = part1(reports)
        p2 = part2(reports)
        IO.puts(p1)
        IO.puts(p2)
      end
    end
    
    data = File.read!("input.in")
    Day02.run(data)
    
      
  • I'm late to the party, as usual. Damned timezones. This year I'm going to tackle with a small handful of languages, but primarily Elixir and Gleam. This is my first time trying this languages in earnest, so expect some terrible, inefficient and totally unidiomatic code!Here's day one:

    Elixir

     elixir
        
    part_one =
      File.read!("input.in")
      |> String.split("\n", trim: true)
      |> Enum.map(fn line ->
        line
        |> String.split()
        |> Enum.map(&String.to_integer/1)
      end)
      |> Enum.reduce({[], []}, fn [first, second], {list1, list2} ->
        {[first | list1], [second | list2]}
      end)
      |> then(fn {list1, list2} ->
        {Enum.sort(list1), Enum.sort(list2)}
      end)
      |> then(fn {list1, list2} ->
        Enum.zip(list1, list2)
        |> Enum.map(fn {x, y} -> abs(x - y) end)
      end)
      |> Enum.sum()
    
    part_two =
      File.read!("input.in")
      |> String.split("\n", trim: true)
      |> Enum.map(fn line ->
        line
        |> String.split()
        |> Enum.map(&String.to_integer/1)
      end)
      |> Enum.reduce({[], []}, fn [first, second], {list1, list2} ->
        {[first | list1], [second | list2]}
      end)
      |> then(fn {list1, list2} ->
        Enum.map(list1, fn line ->
          line * Enum.count(list2, fn x -> x === line end)
        end)
        |> Enum.sum()
      end)
    
    IO.inspect(part_one)
    IO.inspect(part_two)
    
      
  • She was 89 and no doubt lead a truly fulfilling life, and so I think objectively it's not a sad passing - she had a truly remarkable life and long life.

    That said, she was a significant part of my childhood, and always on the television in the various households I've lived in for one show or another. It feels like losing a beloved grandmother, and I'm devastated. RIP Maggie.

  • Programming @programming.dev

    My Software Bookshelf

    olano.dev /blog/my-software-bookshelf/
  • Totally agree. Like most "rules", it just needs treating with nuance and context.

  • Programming @programming.dev

    Good software development habits

    zarar.dev /good-software-development-habits/
  • I can totally see how it could be read like that!

  • Five-a-side is a specific format of football (soccer), aimed at more casual play with a much lower bar to skill level. Outside of five-a-side leagues (which do exist), it's rarely played with fixed teams and often ran in a more "pick up group" fashion.

  • Five-a-side football (soccer). I'm not a sporty person, but started going with a local group a few years ago and have reaped the benefits of doing some intensive team exercise once per week. I go with a bunch of guys way older than I am, and it's amazing how fit and healthy they are compared to the average person I meet of their age. I certainly plan to keep this up so long an injury doesn't prevent me.

  • Python @programming.dev

    Polars — Announcing Polars 1.0

    pola.rs /posts/announcing-polars-1/
  • Nice. I've not seen any of your other videos yet, but I can say that for this one, I really loved that you just jumped straight in to the action and kept the video tight, without missing important details.

  • United Kingdom @feddit.uk

    Self-proclaimed working class Clacton woman speaks out against Farage

  • Game Development @programming.dev

    What is a collision?

    www.sassnow.ski /rigid-body-collisions/1
  • Programming.dev Meta @programming.dev

    Piracy-Related Content on P.D: An Open Dialogue with Our Community

  • Golang @programming.dev

    Go Enums Still Suck

    www.zarl.dev /articles/enums-take-two
  • Game Development @programming.dev

    Watt-Wise Game Jam

    wattwise.games
  • Programming @programming.dev

    Semantic AJAX-HTML

    herman.bearblog.dev /semantic-ajax-html/
  • Golang @programming.dev

    What even is “Dependency Injection”? (a practical example using Go)

    medium.com /@LittleLeverages/what-even-is-dependency-injection-using-go-7f85724bbdb2
  • Programming @programming.dev

    What even is “Dependency Injection”? (a practical example using Go)

    medium.com /@LittleLeverages/what-even-is-dependency-injection-using-go-7f85724bbdb2
  • Golang @programming.dev

    Go Enums Suck

    www.zarl.dev /articles/enums
  • Accessibility @programming.dev

    AccessKit: UI accessibility infrastructure across platforms and programming languages

    github.com /AccessKit/accesskit