29 Jan 2026
Planet Grep
FOSDEM organizers: Guided sightseeing tours
If your non-geek partner and/or kids are joining you to FOSDEM, they may be interested in spending some time exploring Brussels while you attend the conference. Like previous years, FOSDEM is organising sightseeing tours.
29 Jan 2026 1:30pm GMT
FOSDEM organizers: Call for volunteers
With FOSDEM just a few days away, it is time for us to enlist your help. Every year, an enthusiastic band of volunteers make FOSDEM happen and make it a fun and safe place for all our attendees. We could not do this without you. This year we again need as many hands as possible, especially for heralding during the conference, during the buildup (starting Friday at noon) and teardown (Sunday evening). No need to worry about missing lunch at the weekend, food will be provided. Would you like to be part of the team that makes FOSDEM tick?舰
29 Jan 2026 1:30pm GMT
Dries Buytaert: Drupal CMS 2.0 released

Today we released Drupal CMS 2.0. I've been looking forward to this release for a long time!
If Drupal is 25 years old, why only version 2.0? Because Drupal Core is the same powerful platform you've known for years, now at version 11. Drupal CMS is a product built on top of it, packaging best-practice solutions and extra features to help you get started faster. It was launched a year ago as part of Drupal Starshot.
Why build this layer at all? Because the criticism has been fair: Drupal is powerful but not easy. For years, features like easier content editing and better page building have topped the wishlist.
Drupal CMS is changing Drupal's story from powerful but hard to powerful and easy to use.
With Drupal CMS 2.0, we're taking another big step forward. You no longer begin with a blank slate. You can begin with site templates designed for common use cases, then shape them to fit your needs. You get a visual page builder, preconfigured content types, and a smoother editing experience out of the box. We also added more AI-powered features to help draft and refine content.
The biggest new feature in this release is Drupal Canvas, our new visual page builder that now ships by default with Drupal CMS 2.0. You can drag components onto a page, edit in place, and undo changes. No jumping between forms and preview screens.
WordPress and Webflow have shown how powerful visual editing can be. Drupal Canvas brings that same ease to Drupal with more power while keeping its strengths: custom content types, component-based layouts, granular permissions, and much more.
But Drupal Canvas is only part of the story. What matters more is how these pieces are starting to fit together, in line with the direction we set out more than a year ago: site templates to start from, a visual builder to shape pages, better defaults across the board, and AI features that help you get work done faster. It's the result of a lot of hard work by many people across the Drupal community.
If you tried Drupal years ago and found it too complex, I'd love for you to give it another look. Building a small site with a few landing pages, a campaign section, and a contact form used to take a lot of setup. With Drupal CMS 2.0, you can get something real up and running much faster than before.
For 25 years, Drupal traded ease for power and flexibility. That is finally starting to change, while keeping the power and flexibility that made Drupal what it is. Thank you to everyone who has been pushing this forward.
29 Jan 2026 1:30pm GMT
Planet Debian
C.J. Collier: Part 3: Building the Keystone – Dataproc Custom Images for Secure Boot & GPUs

Part
3: Building the Keystone - Dataproc Custom Images for Secure Boot &
GPUs
In Part 1, we established a secure, proxy-only network. In Part 2, we
explored the enhanced install_gpu_driver.sh initialization
action. Now, in Part 3, we'll focus on using the LLC-Technologies-Collier/custom-images
repository (branch proxy-exercise-2025-11) to build the
actual custom Dataproc images embedded with NVIDIA drivers signed for
Secure Boot, all within our proxied environment.
Why Custom Images?
To run NVIDIA GPUs on Shielded VMs with Secure Boot enabled, the
NVIDIA kernel modules must be signed with a key trusted by the VM's EFI
firmware. Since standard Dataproc images don't include these
custom-signed modules, we need to build our own. This process also
allows us to pre-install a full stack of GPU-accelerated software.
The
custom-images Toolkit
(examples/secure-boot)
The examples/secure-boot directory within the
custom-images repository contains the necessary scripts and
configurations, refined through significant development to handle proxy
and Secure Boot challenges.
Key Components & Development Insights:
env.json: The central configuration
file (as used in Part 1) for project, network, proxy, and bucket
details. This became the single source of truth to avoid configuration
drift.create-key-pair.sh: Manages the Secure
Boot signing keys (PK, KEK, DB) in Google Secret Manager, essential for
the module signing.build-and-run-podman.sh: Orchestrates
the image build process in an isolated Podman container. This was
introduced to standardize the build environment and encapsulate
dependencies, simplifying what the user needs to install locally.pre-init.sh: Sets up the build
environment within the container and calls
generate_custom_image.py. It crucially passes metadata
derived fromenv.json(like proxy settings and Secure Boot
key secret names) to the temporary build VM.generate_custom_image.py: The core
Python script that automates GCE VM creation, runs the customization
script, and creates the final GCE image.gce-proxy-setup.sh: This script from
startup_script/is vital. It's injected into the temporary
build VM and runs first to configure the OS, package
managers (apt, dnf), tools (curl, wget, GPG), Conda, and Java to use the
proxy settings passed in the metadata. This ensures the entire build
process is proxy-aware.install_gpu_driver.sh: Used as the
--customization-scriptwithin the build VM. As detailed in
Part 2, this script handles the driver/CUDA/ML stack installation and
signing, now able to function correctly due to the proxy setup by
gce-proxy-setup.sh.
Layered Image Strategy:
The pre-init.sh script employs a layered approach:
secure-bootImage: Base image with
Secure Boot certificates injected.tfImage: Based on
secure-boot, this image runs the full
install_gpu_driver.shwithin the proxy-configured build VM
to install NVIDIA drivers, CUDA, ML libraries (TensorFlow, PyTorch,
RAPIDS), and sign the modules. This is the primary target image for our
use case.
(Note: secure-proxy and proxy-tf layers
were experiments, but the -tf image combined with runtime
metadata emerged as the most effective solution for 2.2-debian12).
Build Steps:
-
Clone Repos & Configure
env.json: Ensure you have the
custom-imagesandcloud-dataprocrepos and a
completeenv.jsonas described in Part 1. -
Run the Build:
bash # Example: Build a 2.2-debian12 based image set # Run from the custom-images repository root bash examples/secure-boot/build-and-run-podman.sh 2.2-debian12
This command will build the layered images, leveraging the proxy
settings fromenv.jsonvia the metadata injected into the
build VM. Note the final image name produced (e.g.,
dataproc-2-2-deb12-YYYYMMDD-HHMMSS-tf).
Conclusion of Part 3
Through an iterative process, we've developed a robust workflow
within the custom-images repository to build Secure
Boot-compatible GPU images in a proxy-only environment. The key was
isolating the build in Podman, ensuring the build VM is fully
proxy-aware using gce-proxy-setup.sh, and leveraging the
enhanced install_gpu_driver.sh from Part 2.
In Part 4, we'll bring it all together, deploying a Dataproc cluster
using this custom -tf image within the secure network, and
verifying the end-to-end functionality.
29 Jan 2026 9:08am GMT
Bits from Debian: New Debian Developers and Maintainers (November and December 2025)

The following contributors got their Debian Developer accounts in the last two months:
- Aquila Macedo (aquila)
- Peter Blackman (peterb)
- Kiran S Kunjumon (hacksk)
- Ben Westover (bjw)
The following contributors were added as Debian Maintainers in the last two months:
- Vladimir Petko
- Antonin Delpeuch
- Nadzeya Hutsko
- Aryan Karamtoth
- Carl Keinath
- Richard Nelson
Congratulations!
29 Jan 2026 9:00am GMT
28 Jan 2026
Planet Lisp
Paolo Amoroso: Directory commands for an Interlisp file viewer
My ILsee program for viewing Interlisp source files is written in Common Lisp with a McCLIM GUI. It is the first of the ILtools collection of tools for viewing and accessing Interlisp data.
Although ILsee is good at its core functionality of displaying Interlisp code, entering full, absolute pathnames as command arguments involved a lot of typing.
The new directory navigation commands Cd and Pwd work like the analogous Unix shell commands and address the inconvenience. Once you set the current directory with Cd the See File command can take file names relative to the directory. This is handy when you want to view several files in the same directory.
Here I executed the new commands in the interactor pane. They print status messages in which directories are presentations, not just static text.
Thanks to the functionality of CLIM presentation types, previously output directories are accepted as input in contexts in which a command expects an argument of matching type. Clicking on a directory fulfills the required argument. In the screenshot the last Cd is prompting for a directory and the outlined, mouse sensitive path /home/paolo/il/ is ready for clicking.
Cd and Pwd accept and print presentations of type dirname, which inherits from the predefined type pathname and restricts input to valid directories. Via the functionality of the pathname type the program gets path completion for free from CLIM when typing directory names at the interactor.
The Cd command has a couple more tricks up its sleeve. A blank argument switches to the user's home directory, a double dot .. to the parent directory.
#ILtools #CommonLisp #Interlisp #Lisp
Discuss... Email | Reply @amoroso@oldbytes.space
28 Jan 2026 8:25pm GMT
Planet Debian
C.J. Collier: Part 2: Taming the Beast – Deep Dive into the Proxy-Aware GPU Initialization Action

Part
2: Taming the Beast - Deep Dive into the Proxy-Aware GPU Initialization
Action
In Part 1 of this series, we laid the network foundation for running
secure Dataproc clusters. Now, let's zoom in on the core component
responsible for installing and configuring NVIDIA GPU drivers and the
associated ML stack in this restricted environment: the
install_gpu_driver.sh script from the LLC-Technologies-Collier/initialization-actions
repository (branch gpu-202601).
This isn't just any installation script; it has been significantly
enhanced to handle the nuances of Secure Boot and to operate seamlessly
behind an HTTP/S proxy.
The
Challenge: Installing GPU Drivers Without Direct Internet
Our goal was to create a Dataproc custom image with NVIDIA GPU
drivers, sign the kernel modules for Secure Boot, and ensure the entire
process works seamlessly when the build VM and the eventual cluster
nodes have no direct internet access, relying solely on an HTTP/S proxy.
This involved:
- Proxy-Aware Build: Ensuring all build steps within
the custom image creation process (package downloads, driver downloads,
GPG keys, etc.) correctly use the customer's proxy. - Secure Boot Signing: Integrating kernel module
signing using keys managed in GCP Secret Manager, especially when
drivers are built from source. - Conda Environment: Reliably and speedily installing
a complex Conda environment with PyTorch, TensorFlow, Rapids, and other
GPU-accelerated libraries through the proxy. - Dataproc Integration: Making sure the custom image
works correctly with Dataproc's own startup, agent processes, and
cluster-specific configurations like YARN.
The
Development Journey: Key Enhancements in
install_gpu_driver.sh
To address these challenges, the script incorporates several key
features:
- Robust Proxy Handling (
set_proxy
function):- Challenge: Initial script versions had spotty proxy
support. Many tools likeapt,curl,
gpg, and evengsutilfailed in proxy-only
environments. - Enhancements: The
set_proxyfunction
(also used ingce-proxy-setup.sh) was completely overhauled
to parse various proxy metadata (http-proxy,
https-proxy,proxy-uri,
no-proxy). Critically, environment variables
(HTTP_PROXY,HTTPS_PROXY,
NO_PROXY) are now set before any network
operations.NO_PROXYis carefully set to include
.google.comand.googleapis.comto allow
direct access to Google APIs via Private Google Access. System-wide
trust stores (OS, Java, Conda) are updated with the proxy's CA
certificate if provided viahttp-proxy-pem-uri.
gcloud,apt,dnf, and
dirmngrare also configured to use the proxy.
- Challenge: Initial script versions had spotty proxy
- Reliable GPG Key Fetching (
import_gpg_keys
function):- Challenge: Importing GPG keys for repositories
often failed as keyservers use non-HTTP ports (e.g., 11371) blocked by
firewalls, andgpg --recv-keysis not proxy-friendly. - Solution: A new
import_gpg_keys
function now fetches keys over HTTPS usingcurl, which
respects the environment's proxy settings. This replaced all direct
gpg --recv-keyscalls.
- Challenge: Importing GPG keys for repositories
- GCS Caching is King:
- Challenge: Repeatedly downloading large files
(drivers, CUDA, source code) through a proxy is slow and
inefficient. - Solution: Implemented extensive GCS caching for
NVIDIA drivers, CUDA runfiles, NVIDIA Open Kernel Module source
tarballs, compiled kernel modules, and even packed Conda environments.
Scripts now check a GCS bucket (dataproc-temp-bucket)
before hitting the internet. - Impact: Dramatically speeds up subsequent runs and
init action execution times on cluster nodes after the cache is
warmed.
- Challenge: Repeatedly downloading large files
- Conda Environment Stability & Speed:
- Challenge: Large Conda environments are prone to
solver conflicts and slow installation times. - Solution: Integrated Mamba for faster package
solving. Refined package lists for better compatibility. Added logic to
force-clean and rebuild the Conda environment cache on GCS and locally
if inconsistencies are detected (e.g., driver installed but Conda env
not fully set up).
- Challenge: Large Conda environments are prone to
- Secure Boot & Kernel Module Signing:
- Challenge: Custom-compiled kernel modules must be
signed to load when Secure Boot is enabled. - Solution: The script integrates with GCP Secret
Manager to fetch signing keys. Thebuild_driver_from_github
function now includes robust steps to compile, sign (using
sign-file), install, and verify the signed modules.
- Challenge: Custom-compiled kernel modules must be
- Custom Image Workflow & Deferred Configuration:
- Challenge: Cluster-specific settings (like YARN GPU
configuration) should not be baked into the image. - Solution: The
install_gpu_driver.sh
script detects when it's run during image creation
(--metadata invocation-type=custom-images). In this mode,
it defers cluster-specific setups to a systemd service
(dataproc-gpu-config.service) that runs on the first boot
of a cluster instance. This ensures that YARN and Spark configurations
are applied in the context of the running cluster, not at image build
time.
- Challenge: Cluster-specific settings (like YARN GPU
Conclusion of Part 2
The install_gpu_driver.sh initialization action is more
than just an installer; it's a carefully crafted tool designed to handle
the complexities of secure, proxied environments. Its robust proxy
support, comprehensive GCS caching, refined Conda management, Secure
Boot signing capabilities, and awareness of the custom image build
lifecycle make it a critical enabler.
In Part 3, we'll explore how the LLC-Technologies-Collier/custom-images
repository (branch proxy-exercise-2025-11) uses this
initialization action to build the complete, ready-to-deploy Secure Boot
GPU custom images.
28 Jan 2026 10:45am GMT
26 Jan 2026
FOSDEM 2026
Guided sightseeing tours
If your non-geek partner and/or kids are joining you to FOSDEM, they may be interested in spending some time exploring Brussels while you attend the conference. Like previous years, FOSDEM is organising sightseeing tours.
26 Jan 2026 11:00pm GMT
Call for volunteers
With FOSDEM just a few days away, it is time for us to enlist your help. Every year, an enthusiastic band of volunteers make FOSDEM happen and make it a fun and safe place for all our attendees. We could not do this without you. This year we again need as many hands as possible, especially for heralding during the conference, during the buildup (starting Friday at noon) and teardown (Sunday evening). No need to worry about missing lunch at the weekend, food will be provided. Would you like to be part of the team that makes FOSDEM tick?舰
26 Jan 2026 11:00pm GMT
Planet Lisp
TurtleWare: McCLIM and 7GUIs - Part 1: The Counter
Table of Contents
For the last two months I've been polishing the upcoming release of McCLIM. The most notable change is the rewriting of the input editing and accepting-values abstractions. As it happens, I got tired of it, so as a breather I've decided to tackle something I had in mind for some time to improve the McCLIM manual - namely the 7GUIs: A GUI Programming Benchmark.
This challenge presents seven distinct tasks commonly found in graphical interface requirements. In this post I'll address the first challenge - The Counter. It is a fairly easy task, a warm-up of sorts. The description states:
Challenge: Understanding the basic ideas of a language/toolkit.
The task is to build a frame containing a label or read-only textfield T and a button B. Initially, the value in T is "0" and each click of B increases the value in T by one.
Counter serves as a gentle introduction to the basics of the language, paradigm and toolkit for one of the simplest GUI applications imaginable. Thus, Counter reveals the required scaffolding and how the very basic features work together to build a GUI application. A good solution will have almost no scaffolding.
In this first post, to make things more interesting, I'll solve it in two ways:
- using contemporary abstractions like layouts and gadgets
- using CLIM-specific abstractions like presentations and translators
In CLIM it is possible to mix both paradigms for defining graphical interfaces. Layouts and gadgets are predefined components that are easy to use, while using application streams enables a high degree of flexibility and composability.
First, we define a package shared by both versions:
(eval-when (:compile-toplevel :load-toplevel :execute)
(unless (member :mcclim *features*)
(ql:quickload "mcclim")))
(defpackage "EU.TURTLEWARE.7GUIS/TASK1"
(:use "CLIM-LISP" "CLIM" "CLIM-EXTENSIONS")
(:export "COUNTER-V1" "COUNTER-V2"))
(in-package "EU.TURTLEWARE.7GUIS/TASK1")
Note that "CLIM-EXTENSIONS" package is McCLIM-specific.
Version 1: Using Gadgets and Layouts
Assuming that we are interested only in the functionality and we are willing to ignore the visual aspect of the program, the definition will look like this:
(define-application-frame counter-v1 ()
((value :initform 0 :accessor value))
(:panes
;; v type v initarg
(tfield :label :label (princ-to-string (value *application-frame*))
:background +white+)
(button :push-button :label "Count"
:activate-callback (lambda (gadget)
(declare (ignore gadget))
(with-application-frame (frame)
(incf (value frame))
(setf (label-pane-label (find-pane-named frame 'tfield))
(princ-to-string (value frame)))))))
(:layouts (default (vertically () tfield button))))
;;; Start the application (if not already running).
;; (find-application-frame 'counter-v1)

The macro define-application-frame is like defclass with additional clauses. In our program we store the current value as a slot with an accessor.
The clause :panes is responsible for defining named panes (sub-windows). The first element is the pane name, then we specify its type, and finally we specify initargs for it. Panes are created in a dynamic context where the application frame is already bound to *application-frame*, so we can use it there.
The clause :layouts allows us to arrange panes on the screen. There may be multiple layouts that can be changed at runtime, but we define only one. The macro vertically creates another (anonymous) pane that arranges one gadget below another.
Gadgets in CLIM operate directly on top of the event loop. When the pointer button is pressed, it is handled by activating the callback, that updates the frame's value and the label. Effects are visible immediately.
Now if we want the demo to look nicer, all we need to do is to fiddle a bit with spacing and bordering in the :layouts section:
(define-application-frame counter-v1 ()
((value :initform 0 :accessor value))
(:panes
(tfield :label :label (princ-to-string (value *application-frame*))
:background +white+)
(button :push-button :label "Count"
:activate-callback (lambda (gadget)
(declare (ignore gadget))
(with-application-frame (frame)
(incf (value frame))
(setf (label-pane-label (find-pane-named frame 'tfield))
(princ-to-string (value frame)))))))
(:layouts (default
(spacing (:thickness 10)
(horizontally ()
(100
(bordering (:thickness 1 :background +black+)
(spacing (:thickness 4 :background +white+) tfield)))
15
(100 button))))))
;;; Start the application (if not already running).
;; (find-application-frame 'counter-v1)

This gives us a layout that is roughly similar to the example presented on the 7GUIs page.
Version 2: Using the CLIM Command Loop
Unlike gadgets, stream panes in CLIM operate on top of the command loop. A single command may span multiple events after which we redisplay the stream to reflect the new state of the model. This is closer to the interaction type found in the command line interfaces:
(define-application-frame counter-v2 ()
((value :initform 0 :accessor value))
(:pane :application
:display-function (lambda (frame stream)
(format stream "~d" (value frame)))))
(define-counter-v2-command (com-incf-value :name "Count" :menu t)
()
(with-application-frame (frame)
(incf (value frame))))
;; (find-application-frame 'counter-v2)

Here we've used :pane option this is a syntactic sugar for when we have only one named pane. Skipping :layouts clause means that named panes will be stacked vertically one below another.
Defining the application frame defines a command-defining macro. When we define a command with define-counter-v2-command, then this command will be inserted into a command table associated with the frame. Passing the option :menu t causes the command to be available in the frame menu as a top-level entry.
After the command is executed (in this case it modifies the counter value), the application pane is redisplayed; that is a display function is called, and its output is captured. In more demanding scenarios it is possible to refine both the time of redisplay and the scope of changes.
Now we want the demo to look nicer and to have a button counterpart placed beside the counter value, to resemble the example more:
(define-presentation-type counter-button ())
(define-application-frame counter-v2 ()
((value :initform 0 :accessor value))
(:menu-bar nil)
(:pane :application
:width 250 :height 32
:borders nil :scroll-bars nil
:end-of-line-action :allow
:display-function (lambda (frame stream)
(formatting-item-list (stream :n-columns 2)
(formatting-cell (stream :min-width 100 :min-height 32)
(format stream "~d" (value frame)))
(formatting-cell (stream :min-width 100 :min-height 32)
(with-output-as-presentation (stream nil 'counter-button :single-box t)
(surrounding-output-with-border (stream :padding-x 20 :padding-y 0
:filled t :ink +light-grey+)
(format stream "Count"))))))))
(define-counter-v2-command (com-incf-value :name "Count" :menu t)
()
(with-application-frame (frame)
(incf (value frame))))
(define-presentation-to-command-translator act-incf-value
(counter-button com-incf-value counter-v2)
(object)
`())
;; (find-application-frame 'counter-v2)

The main addition is the definition of a new presentation type counter-button. This faux button is printed inside a cell and surrounded with a background. Later we define a translator that converts clicks on the counter button to the com-incf-value command. The translator body returns arguments for the command.
Presenting an object on the stream associates a semantic meaning with the output. We can now extend the application with new gestures (names :scroll-up and :scroll-down are McCLIM-specific):
(define-counter-v2-command (com-scroll-value :name "Increment")
((count 'integer))
(with-application-frame (frame)
(if (plusp count)
(incf (value frame) count)
(decf (value frame) (- count)))))
(define-presentation-to-command-translator act-scroll-up-value
(counter-button com-scroll-value counter-v2 :gesture :scroll-up)
(object)
`(10))
(define-presentation-to-command-translator act-scroll-dn-value
(counter-button com-scroll-value counter-v2 :gesture :scroll-down)
(object)
`(-10))
(define-presentation-action act-popup-value
(counter-button nil counter-v2 :gesture :describe)
(object frame)
(notify-user frame (format nil "Current value: ~a" (value frame))))
A difference between presentation to command translators and presentation actions is that the latter does not automatically progress the command loop. Actions are often used for side effects, help, inspection etc.
Conclusion
In this short post we've solved the first task from the 7GUIs challenge. We've used two techniques available in CLIM - using layouts and gadgets, and using display and command tables. Both techniques can be combined, but differences are visible at a glance:
- gadgets provide easy and reusable components for rudimentary interactions
- streams provide extensible and reusable abstractions for semantic interactions
This post only scratched the capabilities of the latter, but the second version demonstrates why the command loop and presentations scale better than gadget-only solutions.
Following tasks have gradually increasing level of difficulty that will help us to emphasize how useful are presentations and commands when we want to write maintainable applications with reusable user-defined graphical metaphors.
26 Jan 2026 12:00am GMT
25 Jan 2026
FOSDEM 2026
Present a lightning lightning talk
The same as last year: come and take part in a very rapid set of talks! Thought of a last minute topic you want to share? Got your interesting talk rejected? Has something exciting happened in the last few weeks you want to talk about? Get that talk submitted to Lightning Lightning Talks! We have two sessions for participants to speak about subjects which are interesting, amusing, or just something the FOSDEM audience would appreciate: Saturday Sunday Selected speakers line up and present in one continuous automated stream, with an SLO of 99% talk uptime. To submit your talk for舰
25 Jan 2026 11:00pm GMT
20 Jan 2026
Planet Lisp
Joe Marshall: Filter
One of the core ideas in functional programming is to filter a set of items by some criterion. It may be somewhat suprising to learn that lisp does not have a built-in function named "filter" "select", or "keep" that performs this operation. Instead, Common Lisp provides the "remove", "remove-if", and "remove-if-not" functions, which perform the complementary operation of removing items that satisfy or do not satisfy a given predicate.
The remove function, like similar sequence functions, takes an optional keyword :test-not argument that can be used to specify a test that must fail for an item to be considered for removal. Thus if you invert your logic for inclusion, you can use the remove function as a "filter" by specifying the predicate with :test-not.
> (defvar *nums* (map 'list (λ (n) (format nil "~r" n)) (iota 10)))
*NUMS*
;; Keep *nums* with four letters
> (remove 4 *nums* :key #'length :test-not #'=)
("zero" "four" "five" "nine")
;; Keep *nums* starting with the letter "t"
> (remove #\t *nums* :key (partial-apply-right #'elt 0) :test-not #'eql)
("two" "three")20 Jan 2026 11:46am GMT
