← Home About Archive Photos Projects Uses Also on Micro.blog
  • Morning walk

    Mural in Guelph: Even Pavement Gives Way To Flowers

    Interesting things I passed on the way to the library with my daughter here in Guelph.

    An incredible house-converted-antique-shop-house? near my home
    → 8:00 PM, Dec 28
  • OptConnect Marketing Site

    • Timeline: July 2020 - December 2021
    • Status: the client switched to WordPress in May 2024
    • Technologies: CraftCMS, Bootstrap

    I built OptConnect’s Marketing site with CraftCMS, an elegant and opinionated alternative to WordPress. Over the years I’ve been able to work on several different Craft projects. The ecosystem is noticeably smaller than WordPress (as to be expected), but in my experience the sites are easier to setup, manage and troubleshoot. Craft is a bit more opinionated, you won’t find any plugins to reskin your entire admin panel, but once you know it you can jump into any Craft instance and be up and running in no time.

    OptConnect was looking for a ground up redesign for their entire site and had chosen Craft. I worked with their design team to bring their vision to life.

    Over the years I’ve continued to offer support and updates to OptConnect as needed. We used an innovative mobile menu with categories displayed as a horizontal slider at the top. OptConnect had a lot of interesting shapes and elements which made for some front-end challenges. On mobile screens we opted to have the products displayed via a slider (see above) which allowed you to scroll horizontally to see more categories (above). Unique design specifications such as these rounded link buttons presented some challenges due to the varied sizes of the titles and descriptions. Press release cards that appeared on the site. Part of the work I did for OptConnect included migrating a WordPress blog to Craft. This included building a custom search tool with CraftCMS. Blog search The final site was OptConnect’s main marketing resource for over three years before it was replaced in the spring of 2024. During those three years I would occasionally provide support or help the marketing department build new content types in the CMS but for the most part once the project was turned over it ran smoothly.

    → 8:00 PM, Dec 23
  • Merry Christmas everyone!

    → 8:00 PM, Dec 23
  • Canada Post Strike

    Canada Post Strike

    Photo by Birk Enwald

    For the past few weeks postal workers in Canada have been on strike. This has, of course, caused a fair amount of disruption during the Christmas season. Before I even knew the details of the strike I was naturally on the side of the workers. This is my default position: support labour. In general, I have found that if you are on the side of labour you’re on the right side of history. That’s not to say there aren’t corrupt unions, pointless strikes, or strikes that are regressive in their outcomes. However, in general strikes are a way for “the means of production” to get more of the benefits of that production. In other words; the people doing the work should be reaping the biggest rewards. Not the government, not billionaires, not some mythological “job creator” who took some risks a few years ago and has sat around collecting a “passive income” ever since. No, labor deserves the wealth, because they are the ones creating it.

    The arguments against strikes have always been a bit baffling to me. There is no multi-millionaire union. The picket line almost always represents the low and middle class. These are our people, and they deserve more for what they do. Even highly paid people, in my view, deserve more for what they do. In Ontario it’s taken for granted that public teachers are “highly paid”. OTF, the Ontario Teachers Federation is very powerful and well monied. So what are these rich teachers making? After 10 years salaries appear to be capped at $102,000*. Great money for a single person, maybe more than you make, maybe more than you take home but I would ask; “why not more?” Teachers work damn hard, long hours, lots of stress and there is the years-long grind of even becoming a full time placed teacher in Ontario. Not to mention these are people who spend as much time with your kids as you do! Yes, I also think you should make more money, but it’s not a zero sum game; that’s kind of the point of unions. We are living through a time when the wealth gap looks more like France before the revolution; the middle class is shrinking and not because families are getting rich. A “high paying” job ten years ago may barely get you by; but billionaires own more than ever. In the past 25 years the world’s billionaires have added six trillion to their collective wealth. Anybody, any union, who takes a stand is fighting for all of us not just their workers.

    Sure it’s an inconvenient time for a strike, but spare a thought. You may not get all your Christmas packages in time, but there are workers who literally cannot make ends meet 365 days a year, not just at Christmas. Strong labour is good for society as a whole!

    • https://www150.statcan.gc.ca/n1/pub/81-582-x/2023001/tbl/tblc.6.3-eng.htm ** https://www150.statcan.gc.ca/n1/pub/12-581-x/2023001/sec14-eng.htm
    → 8:00 PM, Dec 15
  • Not to rush Christmas, but I think I’ll try my hand at Advent of Code this year. It will be a good chance to play around with Rust.

    → 8:00 PM, Nov 10
  • Adding a `soft_delete` to Ecto Multi pipelines

    I’m a big fan of Ecto, Elixir’s database wrapper. The Multi library lets you build up a series of operations that happen in order, if one fails the entire operation rolls back. Multi comes with the a lot of standard CRUD built in, insert/4 , update/4 , delete/4 and their bulk counterparts insert_all/5 , update_all/5 and delete_all/5 for acting on multiple records.

    I’ve been working on a project where we make use of the soft delete pattern, rather than calling delete/4 on a record we generally update/4 the record passing in a deleted_at timestamp:

    |> Multi.update(:soft_delete, fn %{customer: customer} -> 
    	Changeset.change(customer, %{deleted_at: now})
    end)
    

    This works fine, and even updating multiple records one could take this approach:

    |> Multi.update_all(:soft_delete, fn %{customers: customers} ->
    	ids = Enum.map(customers, & &1.id)
    	from(c in Customer, where: c.id in ^ids, update: [set: [deleted_at: ^now]])
    end, [])
    

    I was working on a new feature that will require a cascade of soft deletes, deleting multiple records, their associated records, their children, etc. (As the second example above is doing). Admittedly, I could have just utilized this Multi.update_all/5 and put multiple steps into the multi . However; I thought continuously mapping specific ids, passing in set: [deleted_at: ^now] was a little cumbersome and not very idiomatic. Mostly, I wanted to have a bit of fun wondering: “what if Ecto.Multi had a soft_delete_all/5 function?” Of course it doesn’t, this is a niche use case but it makes sense in this application so I dug in and found the task to be (as is the case with a lot of Elixir) surprisingly easy.

    Just like update_all/5 I wanted to make sure soft_delete_all would handle queries or functions passed in. Pattern matching here using the is_function/1 guard. This made it a fairly straightforward operation:

    @spec soft_delete_all(Multi.t(), atom(), fun() | Query.t(), keyword()) :: Multi.t()
      def soft_delete_all(multi, name, func, opts \\ [])
    
      def soft_delete_all(multi, name, func, opts) when is_function(func) do
        Multi.run(
          multi,
          name,
          operation_fun({:soft_delete_all, func, [set: [deleted_at: Timex.now()]]}, opts)
        )
      end
    
      def soft_delete_all(multi, name, queryable, opts) do
        add_operation(multi, name, {:update_all, queryable, [set: [deleted_at: Timex.now()]], opts})
      end
    

    The first function matches against functions while the second matches against a queryable. I’ll explain the distinction between both.

    Under the hood Multi is already equipped to handle functions or queryables; by reading the source of the Multi module I was able to,matches, forward along the proper structure for the Multi to run, and in another case recreate the same functionality that Multi.update_all uses. Both operation_fun/2 and add_operation/3 are nearly copy-pasted from the Multi core.

    In the first instance the multi is passed a function, something like:

    |> soft_delete_all(:remove_customer, &remove_customer/1)
    

    In this case Ecto adds a new Multi operation to the pipeline: Multi.run/3 but it needs to run the function it’s passed. It does this with operation_fun/2 . The multi has several matchers for each of the bulk operations, in my case I only needed one :soft_delete_all .

    defp operation_fun({:soft_delete_all, fun, updates}, opts) do
        fn repo, changes ->
          {:ok, repo.update_all(fun.(changes), updates, opts)}
        end
      end
    

    Again, this is identical (save the :soft_delete_all atom) to the Multi module. It runs our function which creates a query, it passes our update: [set: [deleted_at: Timex.now()]] to the query and then updates the record.

    In cases where we pass a query in:

    |> soft_delete_all(:remove_customer, Query.from(c in Customer, where: c.id == 123))
    

    We match on the next function head, here again I used Ecto’s pattern writing my own custom add_operation/3

    defp add_operation(%Multi{} = multi, name, operation) do
        %{operations: operations, names: names} = multi
    
        if MapSet.member?(names, name) do
          raise "#{Kernel.inspect(name)} is already a member of the Ecto.Multi: \n#{Kernel.inspect(multi)}"
        else
          %{multi | operations: [{name, operation} | operations], names: MapSet.put(names, name)}
        end
      end
    

    This is going to first check that the operation name isn’t already in the Multi. If it’s not, we append the operation into the Multi. This works because of the parameters we’ve passed it:

    add_operation(multi, name, {:update_all, queryable, [set: [deleted_at: Timex.now()]], opts})
      end
    

    Specifically: {:update_all, queryable, [set: [deleted_at: Timex.now()]], opts} once again, we aren’t doing anything fancy to soft delete these records, we are using Multi’s ability to :update_all with our provided queryable. The update we are making is [set: [deleted_at: Timex.now()]] .

    There you have it, it’s :update_all all the way down, which makes sense because we are updating a record instead of deleting it, but I think it’s a lot cleaner to write something like this:

    query1 = from(c in Customer, where: c.last_purchase <= ^old_date)
    query2 = from(u in User, join: c in assoc(u, :customer), on: c.last_purchase <= ^old_date)
    
    Multi.new()
    |> soft_delete_all(:customers, query1)
    |> soft_delete_all(:users, query2)
    #👆don't judge this contrived example it's not production code
    
    → 8:00 PM, Oct 20
  • TIL Struct matching in Guards

    Not so much a TIL but I always get confused with the proper syntax. You can pattern match on a struct and use it in a guard to only let through the structs you want:

    @spec address_formater(BillAddress.t() | ShipAddress.t()) :: String.t()
    def address_formatter(%struct{} = address) when struct in [BillAddress, ShipAddress] do
     ...
    end 
    
    def address_formatter(_), do: raise "AddressError :: Not my address!"
    

    As with a lot of my examples it may be a little contrived but it is based on a real world but I fixed today where address_formatter/2 was getting an %Ecto.Association.NotLoaded{} and trying to format it.

    → 8:00 PM, Oct 9
  • I’m 33 years old and I only learned how to spell “doesn’t” this year. Getting enough practice where I almost spell it right the first time. (I think I used to default to dosen’t).

    → 8:00 PM, Sep 28
  • TIL UUIDv4 vs UUIDv7

    I’ve always run with UUID v4 because it’s the default for the Ecto.UUID library in Elixir. However a coworker recommended UUID v7. Having never really looked into UUID other than to implement as a primary key the distinction was news to me.

    Effectively;

    • UUID v4 is a totally random hash that is generated and extremely unlikely to ever conflict with any other generated UUID.
    • UUID v7 also contains a random hash but is also based on a timestamp, this means you can sort them and index them.

    For further reference, yes there are UUIDs v1-v8 as of this writing. If you want a good description of each you can check out this helpful link .

    → 8:00 PM, Sep 24
  • TIL INSERT INTO with SELECT constraints

    In the past month I’ve had to write a lot of SQL to migrate a system and split existing “locations” into tenants ie. migrating data from a public schema to a tenant’s schema is gets messy due to foreign key constraints. Order of operations is important but sometimes you still find yourself in a corner.

    In instances where I already have data in the tenant schema, for example customers and I need to load a subset of data from another table, eg. customer_addreses it’s possible to run the query with tenant.customers as a constraint for what your inserting:

    INSERT INTO tenant.customer_addresses SELECT * FROM public.customer_addresses AS pc WHERE EXISTS (SELECT 1 FROM tenant.customers AS tc WHERE tc.id == pc.customer_id)
    

    This will insert public.customer_addresses into tenant.customer_addresses for every teant.customer that already exists. I’ve gotten around a lot of tricky constraint issues with missing/incomplete data this way.

    → 8:00 PM, Sep 17
  • July 2024 Music Recap

    One of the things I miss most about Spotify is Wrapped. I always feel a pang of envy at the end of the year when people are sharing their Wrapped stats, to the point where I’ve thought about trying to hook into Tidal’s underdeveloped API and create something similar for myself. Alas, maybe someday, it’s about #5 on the project backlog.

    In the meantime I make due with Tidal’s monthly email of my most streamed artists. I love this and I rarely have the same artist appear on the top five two months in a row. I’d like to say I’m constantly seeking out new artists but more often than not my most streamed artists are dictated by a singular mood that may prevail for a week or even a day. Listening to a few albums in a single day can really shoot an artist towards the top of the personal chart.

    Without further ado:

    1. Car Seat Headrest - 47 songs
    2. Mondo Cozmo - 38 songs
    3. Broken Bells - 35 songs
    4. Wet Leg - 30 songs
    5. The Decemberists - 29 songs

    You can see even Car Seat Headrest represents the equivalent of about four albums from a prolific catalog, this isn’t me sitting in my room for hours a day listening to an artist on repeat.

    This month was mostly reliable listening, looking over my personal chart I wouldn’t look at this list and say it’s representative of my “favorites” but each one of these artists has something that really gets under my skin in the best way possible.

    Car Seat Headrest

    I only discovered this gem of a band a few years back. They present an odd mixture of DYI-kid-in-his-basement and anthemic pop hooks with a dash of Brand New style emo. While fans of the band have jumped down deep rabbit holes of mythology; frankly, I just like the music and the passion that Will Toledo manages to put into every word he sings. Call me basic but “Teens of Style” is my favorite album, I feel like it treads a fine line between their garage rock roots and their more avant-garde sounds.

    Mondo Cozmo

    Never on the heavy rotation, but in this day and age there is a rare quality about Mondo Cozmo: his albums feel extremely cohesive. He lacks the textures that I find in the early albums of, say, Bruce Springsteen but there aren’t any filler tracks. The melodies are catchy, and some of the cheesy poetry of lyrics can be forgiven as the music drowns them out. “New Medicine” or “This is For the Barbarians” are his best.

    Broken Bells

    Broken Bells is one of my favorites and how could they not be? I’m a big fan of The Shins early work and Danger Mouse has long been one of my most reliable producers so a collaboration between James Mercer and Brian Burton couldn’t go wrong. The first two albums (“Broken Bells” and “After The Disco”) are, essentially equal in my eyes, with their latest effort “Into the Blue” taking a close third (second?). That may be due to the problem of time and place, our experience with a band is forever frozen in the formative years when we first discovered them, all later work will be compared to this gilded memory.

    The third ingredient that makes the Broken Bells potion sizzle is veteran Cartoon Network artist and designer Jacob Escobedo who does phenomenal artwork for them.

    Wet Leg

    Catchy hooks, witty (and naughty) lyrics blend to make a very fun listening experience. Wet Leg writes about all the alt-rock standards; wanting someone who doesn’t want you back, quarter-life crises, post breakup sex, and a general malaise of the human condition but they manage to just be a bit more witty than most. Chaise Lounge was their breakout single but almost any of the songs on 2022’s “Wet Leg” could be singles. I’m interested to see what comes next.

    The Demberists

    Sometimes I think The Decemberists are rebels from the young America who somehow managed to time travel to our age. This may, in part, be due to their recording the hilarious Hamilton discard; “Ben Fanklin’s Song”. More likely it’s the out of place nature of their music; it’s very much 00s indie rock (you may notice a theme with me here) but neither the subject matter nor the heavy acoustics seem to quite fit with the genre. That’s not to mention Colin Meloy’s voice, which is unlike any of his contemporaries.

    Unlike Broken Bells, Wet Leg or Mondo Cozmo, I find The Decemberists’s catalog to be rather hit and miss. Every album has some standout songs, but every album also has a few that don’t connect at all with me.

    Lets see what happens in August! Maybe some repeats (in the process of writing this up I’ve been listening to a lot of these artists over).

    → 8:00 PM, Aug 5
  • Why Cybertruck when you could Cyberduck ! I think I’ve been using Cyberduck for 100% of my FTP needs for at least 15 years. Such a rock solid piece of software.

    → 8:00 PM, Jul 23
  • SQL is the way, SQL is always the way! I killed myself for hours this morning trying to query/clean some data in Rails, started writing raw SQL and had it sorted in 30 minutes!

    → 8:00 PM, Jul 3
  • Apparently I destroyed my fingerprint while climbing over the weekend- my MBP fingerprint no longer seems to work. It’s a small feature but very missed when it doesn’t work.

    → 8:00 PM, Jul 2
  • Rainy Morning in Guelph ON

    Morning Jog in Guelph. Rainy days like yesterday are perfect!

    → 8:00 PM, Jun 30
  • (Untitled)

    I just modified the Journal theme to allow for microblogging.

    → 8:00 PM, Jun 20
  • The UW Encampment

    UW Sign covered in solidarity with the people of Gaza

    I’ve been watching with admiration and humility as students around the world have set up encampments demanding their schools disclose and divest from Israeli/defense industries. While the situation in Palestine has been gut-wrenching; it’s been heartening to see the reactions of these brave students. Media coverage, however; has been less than favorable. Even fairly pro-Palestinian outlets such as The Guardian use incendiary language such as, “protest erupted” and the emphasis is generally on the concerns of the administrators, police, and potential safety issues. My reading of this coverage portrays these student activists, at best, as dangerous anarchists looking for a fight, at worst entitled white kids shirking summer internships.

    An angle of the encampment **The encampment is covered in art and slogans! Advertising for the people by the people.** When the encampment went up at the local university, The University of Waterloo, I rode up with my dad to take a look. He brought a few books to donate to the encampment's library (I found it charming that amid the tents and living space the students had already set up a thriving library). The atmosphere was calm and cordial we were offered snacks and there appeared to be a lecture circle going on next to the library.

    I found the atmosphere so tranquil and invigorating (a mix of being back at school and a yoga retreat). It was so enticing I went back the next day with Viv and Ruby. The entire day was planned out (they communicate their donation needs and the daily program via Telegram), we went for kite making and poppy planting - kid friendly activities. Ruby got right to work painting her kite, as parents Viv and I relish any time Ruby spends on her own working on a project so we sat back and tried not to hover. The care and concern that was shown for our daughter was remarkable. Over the course of half an hour multiple people approached her offering her water (it was very hot), a woman came around with bite brownies and asked if Ruby wanted one and if she was allowed. As the sun moved I helped a volunteer move the tent to provide better shade for the kids. This was a scene from a community picnic not an anarchist commune sizzling to the point of boiling.

    Another angle of the encampment from the Grad House **A few from in front of the Grad House.** As I watched the care and compassion shown towards my daughter as well as everyone else who had come to the encampment that day I couldn't help but wonder why *this* wasn't reported? Why is the media so hell-bent on making these students, out to be a volatile and potentially dangerous element? It's a tired trope. Of course there have been violent incidents, counter protesters, police forcibly removing students there are many echos of the 1970 Vietnam protests but from my experience an average day in the encampment is calm, communal, even jovial at times. Everyone is gathered for a higher purpose, and it is a grave one, but even in the face of this genocide a community is being built and it is thriving. My hope is that their time is shortened only by divestment and not batons.
    → 8:00 PM, Jun 13
  • On “Rewilding The Internet”

    I’ve been hearing this term a lot lately and, frankly, I think it is a fairly myopic view. If you live in a walled garden such as Facebook, Instagram, TikTok, The Artist Formally Known as Twitter, etc. then yes, it’s easy to the feel that the internet is a barren hardscrabble where all efforts must be made to conserve even the tiniest shrub of originality. However; simply peaking over these walls will reveal a vast untamed wilderness waiting to be discovered/rediscovered.

    My internet experience began around 2000 when I got a @hotmail email. I could barely read and write but there it was: email. A few years later I learned to type and to type fast by chatting with both friends and strangers on AIM. It was around 2003 or 2004 that I really started to “be online” and it coincided with my learning a bit of HTML. Here was this thing you could do at home without talking to anyone, lobbying anyone, going through gatekeepers; you could put it online and anyone in the world could see it.

    When people talk about a wild internet I think this and everything that came before is the era most people are talking about. It was a bit of a wild-west, there were few best practices, and even those were contested and debated. Fewer people were there for the money. Of course the dot-com bubble had already burst so it’s not like people weren’t aware of the potential to make large fortunes on the internet, but there wasn’t a lot of pressure on the individual to make money. People wrote blogs because they had something to say, or because they had nothing to say but wanted to shout into the void. People learned HTML not to become developers but because they had a passion for something and needed to get that thing online. People dumped snippets into Geocities forms to create weird and wonderful pages. Later, even MySpace; the closest thing to the era’s Facebook, allowed users an insane amount of control over the look and feel of their profiles. It was a little messy, but it was wild.

    Gmail and Google Maps had yet to be released, MySpace was nascent, and while there were were other social network prototypes they didn’t “capture” users the same way they do today. Social networks, these silos, just weren’t compelling enough to spend hours a day on. So you surfed. How did one surf? People had blogrolls which guided you to their favorite blogs. There were director pages and recommendations. Much like wandering a library rather than approaching a librarian directly one spent a lot more time aimlessly wandering.

    Eventually Google et, al. got so good you didn’t need to rely on third parties for recommendations, you didn’t need to browse as much, you could type in a query and get a result. The results were so good that you didn’t even need to go past the first page, and within a few years you didn’t need to get past the first result. At this stage it may feel like something was lost, that weirdness, those early sites, where did they go? Was the internet finally tamed?

    They were still there.

    At first the algorithm was designed to return useful results. This was, in large part, a worthwhile step. It disenfranchised a lot of the wild and weird internet but it made the place as a whole a lot more easy to juice. Answers were now literally at your fingertips, not several blocks away.

    That’s when the enshittification began. Enshittification, coined by Cory Doctorow, is the process by which platforms die:

    1. They begin by being good to their users
    2. Then they begin to abuse their users to make things better for their business partners
    3. Then they abuse their business partners to gain more value for themselves/shareholders
    4. Then they die

    As Google became less of an experiment in finding things and more of an engine for making money the search experience began to slowly degrade. More and more of the first results were advertisements, those advertisements became less and less relevant to the query. Additionally, anyone trying to “rank” highly in the Google search results had to play by their rules. We’ve seen several iterations of Page Rank’s bizarre rules from link stuffing (where pages would put an insane number of links to related/the same content), to the latest trend where long-form content is rewarded. (This is why you have to scroll through someone’s life story to get to the recipe).

    We were so hooked on the search that we barely noticed that the experience was degrading! Searching was so easy and the results were still so good that we put up with more ads, more invasions on our privacy for worse results. And all of this algorithmic gaming to make Google as much money as possible continued to cut out the weird and wonderful websites that made the original internet wild.

    But they were still there.

    The latest trend in search is AI. For two years I used a web browser called Arc, early this year with much fanfare they released an iOS app for search with an accompanying video about the future of the internet. Their vision is to have you type in your query, and have AI search for you and return a generated answer to your query. The pitch is, “no more searching, no more sifting through bad results”. Ironically, search has become so bad we need AI to do the most basic thing it’s there for. Perplexity AI and and a host of others are promising the same thing. This is not a net positive for the internet. If you are interested in re-wilding the internet you need to do more hunting not less. An AI that promises generative answers to search queries is far worse for the health of the internet than Google’s crappiest results, it is eliminating sources, content, experts, humans and anything else that might make the internet weird. This is a dark and dangerous path for a wild internet.

    But the wild internet is still there. You can’t find it in walled gardens, get rid of Facebook, jump ship from Instagram and stop looking for answers with Google. You will never find the wilderness if you remain in the concrete jungle. Where is the wild internet?

    It’s everywhere entrenched tech isn’t. I realize that’s a bit daunting, so where to start? That’s a huge question and it deserves a huge answer. As I write this blog I’m sure I’ll dive into more detailed answers but below I’ve provided a few of my favorites as a jumping off point:

    Marginalia Search is a small DIY search engine experiment that focuses on non-commercial sites you didn’t know existed.

    Kagi is a bit more mainstream, you get 100 searches for free/month after that it’s about $10/month. Mostly relying on Bing and other search providers it strips most of the cruft from these services. Kagi is powerful because you can create your own rankings and filters, what do you want to see? What do you want to see more of? Tired of StackOverflow? Rank it low. Like The Guardian. Rank it high.

    IndieWeb is a wealth of knowledge on the wild internet and a good place to start learning.

    Micro.blog imagine Instagram, Twitter, and Tumblr rolled into one also with podcast hosting. Micro blog is an easy way to get thoughts out of your head and into the world along with a supportive and interesting community. As is required with an open internet, there is no lock-in everything is transportable and it connects seamlessly with several “walled gardens” so you can cross post to Threads if you wanted.

    The Useless Web it is what it says it is.

    RSS I believe that RSS is one of the most powerful tools we have in the wild internet. RSS deserves a post in it’s own right but give a high level overview here. RSS stands for RDF Site Summary or better yet Really Simple Syndication. RSS lets you subscribe to feeds and receive an update every-time new content is added. This allows you to curate your own experience for online reading, no algorithms, you choose what you want and posts are shown in chronological order. You’ll need an RSS reader; I use NetNewsWire but other good options are FeedBin (paid) and The Old Reader (free), I believe Vivaldi has one out of the box as well (Safari used too 😢). Once you have a reader you start adding feeds, most content that gets updated regularly will have an RSS feed it can usually be found by adding /rss or /feed to the end of the url. You can try this here on my site!

    A few of the feeds I read regularly are:

    • https://feeds.kottke.org/main Jason Kottke one of the OG bloggers
    • https://www.theguardian.com/profile/arwa-mahdawi/rss Guardian columnist Arwa Mahdawi (you can get the RSS feed for specific writers on the Guardian by adding /rss after their profile.
    • https://www.manton.org/feed/json Manton Reece is the founder of Micro.blog (mentioned above) there’s something about his blog that I find very soothing.
    • https://www.thisiscolossal.com/feed/ Colossal’s feed
    • http://manuelmoreale.com/feed/rss Manuel runs a interview series called People and Blogs where he interviews people about their personal blogs I’ve found some interesting people to follow through this.

    Those are just a few general interest ones to get you started. I’ve curated about 30 that feeds that I actively follow some people have just one or two others have hundreds.

    If you’ve made it this far, I sincerely thank you. If you have questions about the open internet, RSS feeds, or anything else please drop me a line; trav@hey.com Marginalia Search search.marginalia.nu is a small independent do-it-yourself search engine for surprising but content-rich websites that never ask you to accept cookies or subscribe to newsletters. The goal is to bring you the sort of grass fed, free range HTML your grandma used to write. search.marginalia.nu Kagi Search - A Premium Search Engine Better search results with no ads. Welcome to Kagi (pronounced kah-gee), a paid search engine that gives power back to the user. A Premium Search Engine IndieWeb The IndieWeb is a people-focused alternative to the “corporate web”. IndieWeb Micro.blog Post short thoughts or long essays, share photos, all on your own blog. Micro.blog makes it easy, and provides a friendly community where you can share and engage with others. Micro.blog The Useless Web The Useless Web Button… just press it and find where it takes you. The perfect button for the bored, or those looking to find useless sites online! The Useless Web

    A wild place my daughter and I discovered in West Vancouver
    → 8:00 PM, Jun 3
  • Back up and blogging? Sort of.

    In conjunction with me finally overhauling my website I’ve decided to get on the blogging train. I’ve had a personal blog on and off since at least 2005. I started when I was 12 or 13 just adding text to a an HTML file and copying it into Geocities then Tripod then Dreamhost. Sometime around 2006 or 2007 I did the “Famous Five Minute Install” of WordPress and stayed the course there for a few years. As I’ve been reworking my site with SvelteKit I toyed with the idea of doing a Markdown blog. While I like this approach, in theory, I really missed the administration tools that a more full-fledged platform offers, drafts, the ability to post on the fly without having to run a deployment, etc. In the past I’ve solved those pain points with TinaCMS for clients but frankly it’s just more trouble than I’m willing to put in for a personal site.

    So with that I’ve chosen Ghost. I’ve always liked the Ghost ethos, small, remote-first, transparent non-profit. I used Ghost a few years back to document my year of consuming less . I’m not a huge fan of the Medium-like editor they use but their overall aesthetic is on point. I’m not 100% positive what I’m going to post here. I’m a developer by trade so I may write some technical articles; but for the most part this is going to be a collection of my public thoughts and ideas. Mostly short-form with some longer form stuff peppered in. Moving forward I’m going to tweak this template to handle single photos and short form micro posts. The goal being, this can be the central repository for all my online life.

    → 8:00 PM, May 26
  • Today I Learned ~D[2024-01-03]

    You can use Erlang’s tc function to see how many microseconds a function takes. For example, say you were curious if Enum.filter/2 or Kernel.--/2 took longer:

    Example:

    $iex> vals = [1, 2, 3, 4, 5]
    $iex> :timer.tc(Enum, :filter, [vals, &rem(&1, 2) == 1])
    {20, [1, 3, 5]}
    
    $iex> :timer.tc(Kernel, :--, [vals, [2, 4]])
    {3, [1, 3, 5]}
    

    Kernel.-- or vals -- [2, 4] took 3 micro seconds while Enum.filter/2 (Enum.filter(vals, & &1rem(&1, 2) == 1)) took 20.

    This is a fairly trivial example but I could see this coming in handy with larger operations. For more detailed analysis you can always use Benchee. Thanks to chriserin for helping me get the right Erlang syntax for tc

    → 10:00 PM, Jan 2
  • RSS
  • JSON Feed
  • Micro.blog