On 5 March 2025, the Dutch Railways (NS) presented a model of their interior for the Dubbeldekker Nieuwe Generatie (Double-Decker New Generation), or DDNG for short. This train will be introduced in 2029 to replace the ageing DDZ and provide additional capacity to intercity services.
I was going to write an overview of the DDNG and realised the train did not have an English Wikipedia page yet, so I created that instead.
Read more...
All tags
Recent posts
















Recently, Simon Willison shared how he uses S3 event notifications with Lambda and DynamoDB to list recently uploaded files from an S3 bucket. The first thought that occurred to me was to use S3 inventory which provides a daily catalog of objects within a bucket queriable through Athena. The second idea involved doing the same with the recently announced S3 metadata feature. Both methods, I discovered, were already commented on by others.
Read more...
Last month, AWS announced multi-session support natively in the AWS console; previously I’d relied on Firefox containers to separate logins between accounts. This can be easily enabled from the account drop-down in the top right of the console.
Multi-session support enabled and the usual account ID and IAM role is visible in the top right.
Once enabled, this feature supports up to five sessions simultaneously and allows you to switch between them from the account drop-down.
Read more...
While trying to test recovery of a service from a backup, as everyone should, I discovered a container image was no longer available from Docker Hub anymore. I was greeted by the following error:
ERROR: The image for the service you're trying to recreate has been removed. If you continue, volume data could be lost. Consider backing up your data before continuing. Continue with the new image? [yN] Since I had a perfectly healthy and running instance of the service on my homelab which I could use to save the image from that I could then include in my backup copy.
Read more...
The New Jersey Transit Corporation (NJ Transit) operates bus, light rail, and commuter rail services for the population of New Jersey. For the purposes of this post, we’ll be looking at the River LINE, one of three light rail systems operated by NJ Transit. This is part of an ongoing series to explore Stadler rolling stock deployments in the United States, and New Jersey Transit was the first, in the US, to purchase from Stadler in the early 2000s.
Read more...
Earlier this month Google announced a software update to the Pixel 4a, under the Pixel 4a Battery Performance Program. This comes after going without any software update since 2023. For users of the Pixel 4a, this update claimed to “improve the stability of their battery’s performance”. However, for some devices, this update would have negative effects which “reduced available battery capacity and impacts charging performance”. For devices that are negatively impacted, Google would offer a battery replacement or monetary compensation where a replacement is not possible.
Read more...
Data sources are used to retrieve information outside of Terraform, in this case default VPC, subnets, security group and internet gateway resources provisioned in a region within an AWS account. Each opted-in region within an AWS account comes with default network resources, with can be used to provision resources within a default subnet, use the default internet gateway or security group for provisoned resources and more.
Retrieve the default VPC The default VPC can be retrieved using the aws_vpc data source and the default argument.
Read more...
AWS Identity Center is a service that allows you to manage and control user access to AWS accounts or applications. The user identities and groups can be provisioned from an external Identity Provider, like Okta or Keycloak, or managed directly within IAM Identity Center.
Disclaimer: Do not take the information here as a good or best practice. The purpose of this site is to post my learnings in somewhat real-time.
Read more...
Over the last two years, I have been blogging consistently here; this was something I last achieved in the early 2010s. Around 2011, I had a blog where I posted commentary on consumer technology news and the occasional tutorial/guide, which was used on and off until 2014 and is now lost to the internet. In 2016, I pieced together a portfolio website to have somewhere to link to when applying for jobs.
Read more...
Schedules, events and alarms can be shared using the iCalendar data format regardless of the Calendar service or application like Google Calendar or Outlook. This format is defined in RFC 5545. Creating iCalendar files can be done in Python using the icalendar package. I’ve outlined a few example scenarios below. The package documentation has more details on usage.
Installing the package pip install icalendar Other methods are available in the official documentation.
Read more...
Does IKEA have no shelf space for slower-moving items in the self-service furniture area? My wife and I hadn’t seen this before, but a few items just say “Place your order for this product at the search and order kiosk or ask a co-worker”1 instead of the usual row and shelf numbers.
Product tag with article number asking to place the order at a search and order kiosk or to ask a co-worker
Read more...

On 5 September 1964, the last tram ran in the city of Luxembourg from the district of Beggen. First introduced in 1875 in the form of horse-drawn carriages on rails, trams helped transport passengers to and from the central train station in the country’s capital to the north of the city. The construction was funded by the city and the company SATL, Société Anonyme du Tramway Luxembourgeois, was created to operate the trams.
Read more...
sqlite3 CLI Using the sqlite3 CLI allows you to import CSV files into a new or existing database file. The following multi-line command will import the CSV file, disruptions.csv into the disruptions table. All columns will be of type TEXT if created by the import command.
sqlite3 data.db <<EOS .mode csv .import disruptions.csv disruptions EOS The command infers the input file type by the output mode (.mode csv), otherwise use --csv in the import command.
Read more...
The Dutch Railway, NS, has not been having a good week, in fact, this Monday NS reported the lowest punctuality score this year with 72.3% of passengers arriving to their destination with less than a five-minute delay, the average is around 90%. This week has been difficult due to several different factors. There were a few very unfortunate incidents between trains and passengers on the track on Monday. From Monday, no trains ran between Groningen and Groningen Europapark because of a land subsidence the day before after work on a bicycle tunnel, this would take a few days to fix.
Read more...
It’s an open secret that you can follow YouTube channels through RSS, it’s also something I’ve covered on this blog before. What I wasn’t aware of until recently was how difficult it could be to find the RSS feed for a YouTube channel. I mistakenly thought any RSS service could discover the feed URL from a YouTube channel, but after chatting with Andreas (82Mhz) on Mastodon we discovered this wasn’t the case.
Read more...
In my last post, I praised the NS International app, while it’s user-friendly and frankly better than some of the other apps or websites I’ve used there is still room for improvement. I’ll use a recent trip to Leuven from the Netherlands as an example.
The roughly 3-hour trip was booked over a month in advance and I was able to get a cheaper price through the Early Bird discount. Unlike the usual Flex fare ticket, you must take the same Intercity Brussels train as stated on your travel itinerary unless any previous train you were on is delayed.
Read more...

Train for Metz-Ville at Luxembourg station.
This month I had to travel to Metz and decided to book the trip by train from Utrecht. The other option was to fly from the Netherlands to Luxembourg and take the train across the border to Metz, France. I’m happy to say the 7-hour journey by train went great. There were a few minutes of delay in places but the transfer times between trains were enough of a buffer.
Read more...

At the time of writing this, the 50:HERTZ Club Train should be returning to Amsterdam Centraal after its final trip for the weekend. The Amsterdam Dance Event (ADE) is held every October with conferences and festivals for professionals in the industry and festivalgoers. This year 50:HERTZ organised the “Club Train” consisting of eight separate 4-ish hour trips all starting and ending at Amsterdam Centraal. The trips were between Friday 18th October and Sunday 20th October each with their line-up of DJs with stages (or clubs) per train ride.
Read more...

Tucked away in the fields of Bussnang, Switzerland is the headquarters of one of the world’s largest railway equipment manufacturers, Stadler Rail. Well-known for its configurable high-speed, intercity, and regional trains such as the SMILE, KISS, FLIRT, and GTW, Stadler also manufactures trams, locomotives, and other custom equipment such as rack railway rolling stock. You can find their equipment being used in many countries, including the Netherlands, Germany, Hungary, Norway, Turkey, the UK, Saudi Arabia, Azerbaijan, and the US.
Read more...
FFmpeg has the ability to stabilise a video using a 2 pass approach. I first learnt about this from a post on Paul Irish’s website and later also shared the link. Their post also includes a useful single command to stabilise and create a comparison video to see the before and after. The purpose of my entry is to add some references and commands that I’ve found useful mostly for me to look up later.
Read more...

The Netherlands has a fairly large and busy railway network with close to 400 passenger stations on 3000 line kilometres and with its largest operator, NS, transporting over 1 million passengers per day. Where rail meets road there are over 2000 crossings throughout the country. That comes out to a crossing every 1.3 kilometres on average.1
Given the high density of rail traffic and the number of level crossings, the safety of road and rail users is important.
Read more...

After years of delays, the drielandentrein finally started operating at the end of June this year. However, despite all the planning and waiting, the train connection between the three countries is not without its hiccups. Earlier this week, Rover, the public transport traveller’s association, expressed their disappointment with the reliability of the drielandentrein. For starters, Arriva still has staff shortages which started during the pandemic and shortages in train equipment.
Read more...
Grafana has the ability to use Amazon Athena as a data source allowing you to run SQL queries to visualize data. The Athena table data types are conveniently inherited in Grafana to be used in dashboard panels. If the data types in Athena are not exactly how you’d like them in Grafana you can still apply conversion functions.
In this case the timestamp column in Athena is formatted as a string, and I do not have the ability to adjust the table in Athena (which is normally what you’d want to do).
Read more...

The Dutch Railway, NS, runs a few long train routes in the Netherlands and at times these routes may seem a bit “illogical”. An example of this in the July 2024 edition of the NS Panel news brief is the route from Dordrecht to Venlo through Schiphol. This train starts in the south, travels north to Schiphol and heads south again to Venlo. Even with all the major stops listed on the platform departure screen, this route may still confuse some passengers, especially if other quicker train connections exist between the two cities exist.
Read more...
Exporting the results of a query can be useful to import it into other tools for data preparation or visualisation particularly as a CSV file.
sqlite3 CLI Using the SQLite3 CLI allows you to set the query result mode to CSV and output that result to a file. A number of different output formats, including custom separators can be set as well.
sqlite> .open links.db sqlite> .mode csv sqlite> .headers on sqlite> .
Read more...

Brussel-Zuid to Paris Nord routes between the High-Speed line Eurostar uses and the classic line used by EuroCity.
Increasing both the frequency and capacity of cross-border trains is always a good thing, I’ve talked about this with the Drielandentrein between Belgium, the Netherlands, and Germany before. A train every hour that can be used by commuters between the cities of Luik, Maastricht, and Aachen. This was a route that previously required a transfer at Maastricht.
Read more...

After almost a year Tram 12 is back at Amstelstation after being stopped by the renovation of the Berlagebrug. The over 90-year old bridge was due for maintenance after a few inspections and was closed for all traffic on 24 July 2023. This meant that Tram 12 which runs from Amsterdam Centraal Station to Amstelstation through Leidseplein and De Pijp had to stop one stop short at Amsteldijk during the renovations.
Read more...
GitHub Markdown can render Mermaid diagrams including Mermaid Gantt charts. I discovered this from Simon Willison who shared Bryce Mecum’s post on using Mermaid Gantt diagrams to display traces.
A Gantt diagram can be created and rendered within a code block tagged mermaid, a simple example copied from the docs can be seen below.
gantt title A Gantt Diagram dateFormat YYYY-MM-DD section Section A task :a1, 2014-01-01, 30d Another task :after a1, 20d I previously used MarkWhen’s Meridiem online editor to create Gantt charts to visualise the service life on Dutch Sprinter trains, this required me to share screenshots of the chart unless I created a view-only copy.
Read more...
I use python-frontmatter to read and parse the front matter in Markdown files used on the main site. The front matter is used to set page or post titles, along with categories and tags. The python-frontmatter library provides ways to load a file and parse the front matter making it available as a dict. However, there isn’t a documented way to write1 the front matter content to files if you’re starting from a dict.
Read more...
Dynamically partitioning events on Amazon Data Firehouse is possible using the jq 1.6 engine or using a Lambda function for custom parsing. Using JQ expressions through the console to partition events when configuring a Firehouse stream is straight forward provided you know the JQ expression and the source event schema. I found it difficult translating this configuration into a CloudFormation template after initially setting up the stream by click through the console.
Read more...
sqlite-diffable is a tool, built by Simon Willison, to load and dump SQLite databases to JSON files. It’s intended to be used through the CLI, however since May I’ve been using this tool as a callable Python module to build my main site after making changes to the code1. This has allowed me to combine the build commands into one Python file. The changes aren’t available in the upstream code2 so it’ll have to be pulled from my fork if you’re looking to use this.
Read more...
I usually forget the syntax of defining enviornment variables on different platforms, so here’s a note for future me to look up.1
Bash/Zsh export VARIABLE_NAME=ABC123 Using export will set the environment variable within the current session, you can override the value by using export again on the same variable name. To apply this environment variable to all sessions set the variable within the shell’s startup script such as .bashrc or /etc/envrionment to be available by all users.
Read more...
After recently discovering Untappd’s RSS feed, I set out to find if AniList had the same hidden feature so I could ingest activity logs to the homepage of pesky.moe. After much searching I found that this wasn’t the case, but AniList did have a an open GraphQL API! I was able to use this to get my user’s activity and pass them along when generating my homepage.
This wasn’t enough. I have the urge to RSS all the things!
Read more...
Within a repository’s settings tab under Security you can set an Actions secrets and variables. A secret is encrypted and created for use with sensitive data whereas a variable is displayed as plain text. I intended to use a repository variable as an environment variable for a Python script within one of my workflows and the GitHub documentation was not very useful in describing how to accomplish that.
Thanks to mbaum0 on this discussion thread I learned that you can access variables with the vars context.
Read more...

Traveling by train across countries has been getting a lot easier, especially within central Europe where everything is a bit closer together.1 We’ve got the Thalys (now Eurostar) doing 12 trips a day from Amsterdam to Paris through Brussels, and the actual Eurostar doing 4 trips a day from Amsterdam to London, via Brussels and Lille. There are also other relatively good frequency and direct services to larger cities at high speed.
Read more...

Leaflet is a popular and feature-rich JavaScript library for displaying maps. One of these features includes creating and placing markers on a map with an icon, that could represent a dropped pin or something custom. I need to create icons for markers that also contain a number that could be different for each marker and adding text to Leaflet icons can be done in a few ways.
Using L.DivIcon to insert a div element inside of an image.
Read more...
Cross account access to an S3 bucket is a well documented setup. Most guides will cover creating and applying a bucket policy to an S3 bucket and then creating a policy and role to access that bucket from another account. A user or service from that account can then assume that role, provided they’re allowed to by the roles trust relationship to acccess the S3 bucket via the CLI or API.
Read more...

Since I’ve begun blogging semi-regularly I’ve learned that having visuals helps especially when it comes to talking about different locations and their relation to each other. It can be difficult to judge the space and distance between two streets in a city or two cities in a country without some familiarity with the location. A problem I come across frequently when reading transit-related articles and blogs. It’s for this reason I try to include maps in my transport-related posts from very early on.
Read more...

Timetable or schedule graphs visualise railway traffic on a route during a set time. Typically when these graphs are shared online they look like they’ve been created using jTrainGraph although I find it very difficult to get started. I attempted to use both Google Sheets and LibreOffice Calc to some degree of success but only achieved what I wanted through by using R. This was made possible by a single StackOverflow question from 2011.
Read more...

The MerwedeLingelijn stretches 49km from Dordrecht to Gorinchem across the Drechtsteden, Molenlanden, and Gorinchem (DMG) regions in Zuid Holland. The line is mostly single-track with passing opportunities at most stations. Like other public transport modes in the area, the trains on the MerwedeLingelijn are operated by Qbuzz. They began providing public transport in the DMG regions in 2018, taking over from Arriva. With that, Qbuzz also inherited 10 electric Stadler GTW trains to run services on the line.
Read more...
As a long-time user of RSS (Really Simple Syndication) to consume media, I thought I’d write a short post about it. The first specification was released on 15 March 1999, so it did celebrate its 25th birthday yesterday after all. Subscribing to RSS feeds allows you to receive updates on new posts to a website, it’s used by news aggregators to get you articles from different sources, and most famously used to deliver the latest podcast episodes to your app of choice.
Read more...
Granting a user permission to access resources across AWS accounts is a common task, typically the account with the resources contains an IAM role with the appropriate policy defining the actions the user can perform. In addition to this a trust policy is created that specifies which principal can assume that role in order to perform the allowed actions. Sometimes an external ID is added to the trust policy which verifies the user wanting to assume that role.
Read more...
When examining passenger mobility, there are many angles from which to explore effective transportation systems: service reliability, cleanliness, comfort, cost, transit coverage, service frequency, and more. While this topic is extensive, I will specifically focus on the coverage of a public transit network within an area and the significant role that frequency plays in it. I will be using the public transit system in the region of Utrecht, which is operated by Qbuzz under the name U-OV, as a demonstration.
Read more...
AWS allows you to enable server-side encryption (SSE) for you data at rest in your SQS queue. Disabling this option also has an effect on your encryption in transit as well. From the SQS documentation:
All requests to queues with SSE enabled must use HTTPS and Signature Version 4.
In other words disabling SSE also means you can now communicate to the SQS without TLS.
I wrote a Python script to send a message to a queue using the HTTP API and botocore without using the higher level abstractions of boto3.
Read more...
This week I open sourced a Terraform project I’ve been using for the past few months. This solution allows the user to schedule the start or stop of EC2 instances in a single AWS account. This schedule is defined through Terraform and created EventBridge Schedulers. This post will be a snapshot in time of how the solutions looks at the time of publishing. An up to date and concise description of the solution can be found on its GitHub page.
Read more...
The Venlo train station has a great regional express connection to North Rhine-Westphalia (NRW), Germany every hour operated by Eurobahn from 5 am to 10 pm. The station also has stoptrein services to Nijmegen and Roermond along the Maaslijn, where they go twice an hour in both directions operated by Arriva. Lastly, it has an NS Intercity service to Dordrecht via Schiphol Airport, which is also twice an hour. As good as the timetable is, the services that connect you to and from the German train could be better.
Read more...
On my Linux machine I have sometimes shared by screen as a virtual device so it can be used in other programs as a webcam. A similar FFmpeg can also just be used to capture video to the file as well.
Capture as a video device The v4l2loopback module allows you to create a virtual video devices under /dev/.
Load the module, with the command below. After doing so you will see a new video device under /dev/, since I have no video devices currently attached v4l2loopback creates device /dev/video0.
Read more...

This is the third installment about Sprinters in the Netherlands. In the first post we’ve taken a look at the emergence of more regional, sprinter-like services in the 1970s as the Dutch moved towards suburbanisation. This required a new trainset designed to provide stop-train services, which was called the Stadsgewestelijk Materieel (SGM) and was first purchased in 1972. After three decades of service, between 2003 and 2006, the fleet of 90 SGMs was renovated, extending their lifespan to 2021.
Read more...

This Christmas my wife and I booked a semi-spontaneous trip to Berlin, Germany for a few days. Our trip included visiting the typical Christmas markets, restaurants, East Side Gallery, and Museum Island. Most of our traveling around the city was done through the public tram network, with the occasional use of the U or S-Bahn. A line from Vladimir Nabokov’s 1925 short story, A Guide to Berlin, comes to mind.
Read more...
You can track changes to a tag through AWS CloudTrail, AWS Config, or Amazon CloudWatch Events, these methods have already been documented but they’re too slow to respond to changes, too expensive to run, not as extensible out-of-the-box, or outdated. I haven’t seen much coverage on doing this with Amazon EventBridge, which has many integration options, is low-latency, and is fairly low cost (and in this case free). There is a page in the documentation titled Monitor tag changes with serverless workflows and Amazon EventBridge that covers just that, I’d recommend starting there.
Read more...