commits
HyperNeutrino has expressed interest in using fava. Therefore, let's add
a file for them.
Since a while back this plugin has been deprecated. We should remove it
to avoid the error...
Coded wanted this, and I'm fine with this... internal and interwiki
links still won't do this (which is good)
Previously our Johnny Decimal templates wouldn't work with pages that
started with Public:. Setting that up as a namespace will make it work
again with no further modification. It'll also have the benefit of
easily listing them and changing the UI around moving pages to be public
Previously when a link was put into menu it was impossible to overwrite
it without editing the database. Instead, we can change our INSERT to
an UPSERT to allow that. This lets me fix typos (such as y/bsky missing
the /profile/ path)
Scary transclusion, so called because it's scarily inefficient and
might cause frightful differences between pages on different wikis due
to caching, is Probably Not That Bad and Might Actually Be Quite Useful
For Transcluding Stuff From Freshly Wiki Onto Starry Sky Wiki.
It's not that useful to have it enabled the other way around, since as
it'll cause permission errors anyway, but it also is unlikely to really
cause problems in a vacuum...
If we edit the wiki but don't save, we'll lose our edits. We can enable
autosaving to let users use a setting to ... let that not happen! So
let's let that not happen!
It seems like this is causing issues with category updating on new
Johnny Decimal pages, so we should disable it - I've left the comment
to stop us noticing it's disabled and mistakenly re-enabling it in the
future
Our servers are tagged, so aren't considered to be any specific user.
We can give them a username to allow them to access pages. This still
won't allow servers access to the private wiki as there users aren't
auto-created, so "Server" won't be valid...
This option specifies what other wikis call this one - in our case
it's FBC (for the wiki on teal) and S (for the wiki on umber). We don't
really need this for our use, but we *do* need to be able to refer to
the other wiki for interwiki links...
We may want to make this an option later, but it certainly isn't correct
to have it the same on every wiki...
We previously had the same icon and favicon for all wikis... it would
be nice to configure this on a per-wiki basis. Therefore, let's make it
into an ingredient option!
I want to have a private copy of the wiki on umber and a public copy on
teal. It would be good to share configs between them, so we should use
an ingredient for this
As a regression from some of the assertion refactoring...
When you have multiple homes, we were previously comparing the entire
config of each of them to all of the rest. This was a Bad Thing as it
caused us to evaluate the whole of each home, including some attributes
that normally aren't evaluated and broke evaluation completely.
This was relevant for Maya but not for the rest of us - I'm not sure how
CI missed it...
There are some libraries that were updated in nixpkgs 25.11 but which
Collabora gtimelog doesn't support newer versions of. Building gtimelog
from 25.11 will get you an error that looks like this
Traceback (most recent call last):
File "/nix/store/akvr4z3wjiw2gizz6jnbb3f29wa29h8a-python3.13-pygobject-3.54.5/lib/python3.13/site-packages/gi/importer.py", line 137, in create_module
introspection_module = get_introspection_module(namespace)
File "/nix/store/akvr4z3wjiw2gizz6jnbb3f29wa29h8a-python3.13-pygobject-3.54.5/lib/python3.13/site-packages/gi/module.py", line 244, in get_introspection_module
module = IntrospectionModule(namespace, version)
File "/nix/store/akvr4z3wjiw2gizz6jnbb3f29wa29h8a-python3.13-pygobject-3.54.5/lib/python3.13/site-packages/gi/module.py", line 104, in __init__
repository.require(namespace, version)
~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
gi.RepositoryError: Typelib file for namespace 'cairo', version '1.0' not found
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/nix/store/bmy9cw4hbnrq00cc29sza5083yamw74s-gtimelog-0.12.0/bin/.gtimelog-wrapped", line 6, in <module>
from gtimelog.main import main
File "/nix/store/bmy9cw4hbnrq00cc29sza5083yamw74s-gtimelog-0.12.0/lib/python3.13/site-packages/gtimelog/main.py", line 72, in <module>
from gi.repository import Gdk, Gio, GLib, GObject, Gtk, Pango, Soup # noqa: E402
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/nix/store/akvr4z3wjiw2gizz6jnbb3f29wa29h8a-python3.13-pygobject-3.54.5/lib/python3.13/site-packages/gi/importer.py", line 139, in create_module
raise ImportError(e) from e
ImportError: Typelib file for namespace 'cairo', version '1.0' not found
From using nix-locate we can see that cairo-1.0.typelib is in gobject
introspection 1.84.0...
$ nix-locate cairo-1.0.typelib
gobject-introspection.out 0 s /nix/store/i6asc7b7ws92inj5bqvmdbcs3n77dknz-gobject-introspection-wrapped-1.84.0/lib/girepository-1.0/cairo-1.0.typelib
gobject-introspection-unwrapped.out 14,740 r /nix/store/dpwppqwbm76q7h1gk8mv0mg4ylf4b551-gobject-introspection-1.84.0/lib/girepository-1.0/cairo-1.0.typelib
...but search.nixos.org tells us that gobject-introspection is at 1.86.0
Downgrading to 25.05 fixes this issue...
I woke up this morning to a dead menu instance and the following
backtrace:
Jan 05 04:46:24 teal menu-start[1351]: thread 'main' (1351) panicked at src/main.rs:173:6:
Jan 05 04:46:24 teal menu-start[1351]: Failed to connect to database defined in $DATABASE_URL: Io(Os { code: 2, kind: NotFound, message: "No such file or directory" })
Jan 05 04:46:24 teal menu-start[1351]: note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
It seems like this is because, when teal restarted, postgresql hadn't
created a socket by the time menu connected. Restarting menu after the
fact let it run Just Fine. Adding some retries should stop this problem
from coming up...
...a proper solution is probably to fix whatever decides that postgresql
is ready in packetmix, but this is much easier to locate and implement
We're seeing some issues with jobs choking up when we have a
long-waiting maintenance service
Instead, we think it might be better to have this run every 30 seconds
for at most 30 seconds, thus causing stuck jobs not to cause trouble...
Since https://github.com/NixOS/nixpkgs/commit/2d0a48912550cdc39a64e71d09d2c838973871ad,
ACME certificates have been issued using a different set of services.
The missinghost.invalid configuration here ended up breaking the nginx
startup by making it so no selfsigned certificate was ever generated,
getting nginx to die on a missing certificate.
Additonally, also as a result of this ACME rework, Stalwart was waiting
on a bunch of nonexistent things and now no longer is
CategoryWatch looks like it's going to work when you load it, but
at runtime there is an error which prevents category reindexes. To
workaround this, we can remove the extension entirely...
It's not good if our links are case sensitive as different
capitalizations aren't that distinct really. It's still important to
make sure we don't mess up capitalization in the UI or when forwarding
to search engines/etc., though
BREAKING-CHANGE: If you're using links that were made with capitals, those links will stop working
By default, there's no good mobile skin for Mediawiki. You can load
"minerva", which appears to come bundled but not by-default-enabled, but
there's no auto-switching to it when on mobile devices.
The MobileFrontend plugin (as used on Wikipedia) fixes this by using
minerva on mobile devices and a different theme on desktop.
There are some repositories where there's no "main" or "master" branch.
In this case, it would be nice to use "truck" as the main branch
We have some drives in umber that should be set up as a software RAID.
To do that, we need to enable this in the hardware config
I want a private file host for things I can't put on our main copyparty
instance. I'll host that on umber
Grocy is a stock tracking application for groceries. I'd like to use it
to keep track of some of my stuff, so let's host it on umber!
There's no need for us to be listening for silverbullet on our
clicks.domains host, nor should we be listening for plain HTTP anymore
We previously returned One Of The Websites when nginx was accessed from
a host that we didn't know about. That included direct IP address access
as well as things which have been CNAMEd to us (either through a starred
record or due to past services) but which aren't actually hosted by us.
This leads to a number of undesireable effects:
- User confusion ("why does the aux docs website have Stalwart?")
- Incorrect SSL certificates ("your blog seems to have an invalid
certificate")
- SSL being offered via direct IPs, which isn't possible to sign on the
public internet
We can block this by making a default server to take control whenever
nothing matches, and setting that default server to block all
connections and reject all SSL handshakes
We need to have a certificate for this, but it needn't actually be valid
for anything so let's self sign stuff...
I've chatted with Coded, and we think it's better to run the same
shortener on all our short domains than to have separate shorteners for
separate domains. Therefore, let's extend menu to starry.sk
It's only basic routes for now - but this is effectively a first
prototype of a golinks server. We still need to make everything
beautiful, but it should be in a workable state when deployed on teal as
of now...
This needs some changes on packetmix to set up a database as well, so
let's make those here too...
Doing this as a oneshot means that on switch-ing configuration, the
service never "comes up" (as it gets stuck in the --wait). It's far
better to just have a standard service that is restarted by a timer when
it exits rather than a oneshot here...
We have an extension called Cargo which lets you query through pages.
As well as letting you add arbitrary data to select pages, you can also
have a table which is auto-filled with standard page data. By default,
the table doesn't store much info about each page. It might be nice for
querying if we had various other fields enabled!
The network plugin lets you visualize the relationship between
pages in a graph - similar to what Obsidian Graph View does, say:
https://help.obsidian.md/plugins/graph
Hyperneutrino requested it, and it's not a particularly difficult plugin
to install so hyperneutrino gets it :)
menu is the golinks provider and URL shortener that we're writing. So we
can start using it right away, it would be good to host it on teal ASAP
If we want to use menu on teal, it needs to be packaged for Nix. Let's
do that!
We're going to need some routes to fallback to when we hit a URL that
doesn't yet exist. I've added some basic ones - which means we can
deploy this project as soon as it's packaged, as even if it's not
really ready to use yet, switching your search engine to it won't cause
problems
Our josh files and combined project pieces have been a mess for a while.
As I'm creating a new project, I thought it was high time to tidy them
up so they pull out the right files and we can share things like our
inputs.
For fixing the warning
> trace: evaluation warning: 'system' has been renamed to/replaced by 'stdenv.hostPlatform.system'
There's a few bits and pieces in upstream libraries, which have been
updated to unreleased (or unmerged) versions - I'm putting this through
because it's so critical, with approval from Coded - we will need to
upstream, verify, etc. these changes more properly to consider this
"fixed". This is a "good enough for now"
From https://www.mediawiki.org/wiki/Manual:CategoryMembershipChanges,
under https://creativecommons.org/licenses/by-sa/4.0/
> Catwatch is a MediaWiki feature that tracks category membership
> changes. It is possible to view these changes in the recent changes
> and watchlists.
We would previously get this error when fetching on new machines
… while fetching the input 'git+https://gerrit.wikimedia.org/r/mediawiki/extensions/AdvancedSearch?rev=398c9fa782843d8b3aeaa5ebb1c1b3db35c3382f'
error: Cannot find Git revision '398c9fa782843d8b3aeaa5ebb1c1b3db35c3382f' in ref 'refs/heads/master' of repository 'https://gerrit.wikimedia.org/r/mediawiki/extensions/AdvancedSearch'! Please make sure that the rev exists on the ref you've specified or add allRefs = true; to fetchGit.
Now, this is what I'd expect - because we're not meant to be fetching
master of this extension - we're meant to be fetching a branch! This
seems to be an issue with npins' fetchgit call, which misses out the ref
Due to a nilla bug, fetching dependencies is required for evaluation
so this prevented any evaluation
We don't have anything licensed under GPL-3.0-or-later anymore (I think
we previously had a patch under it). We need to remove it...
Pinea has decided to leave packetmix. Their modules are quite different
from ours anyway, so we can no longer maintain KDE and suchlike. Let's
remove the modules from the tree.
I think this may be due to the recent 25.11 updates, but I'm not
entirely sure.
sshd started to create forwarded agents under $HOME. This broke Josh
since as home was /var/empty, so forwarding was impossible, resulting in
this error:
debug1: Requesting authentication agent forwarding.
... 8< -- snip -- 8< ...
debug1: Remote: Agent forwarding disabled: couldn't create listener socket
Creating a home for Josh fixes this
This was added before Stalwart was our live mailserver. At that point,
we could only access it over Tailscale. Nowadays, we can access it
without this record, so it's better to avoid it as it only serves to
make the Tailscale network different to the live internet.
Hyperneutrino is a friend of mine, and they have asked for access to the
headscale instance. Let's give them the standard permissions...
In the copyparty code, we previously hid a header before overriding it.
Hiding a header hides it from the client when the server sends it.
There's no point to it here. It isn't actively harmful, since as we set
the header after anyway, but it's also not required and could be
confusing.
We run Tailscale, which sometimes has internal routes to things. These
override all DNS address entries for specified domains, which breaks
verifying ACME TXT records, which prevents us fetching certificates.
Resolving ACME using Cloudflare avoids the issue...
In https://github.com/josh-project/josh/pull/1704 I fixed the way Josh
works with redirects. Since as that's not yet in a release, we'll need
to pull in Josh's master for it to be effective.
The bug prevented Josh working entirely with Tangled, since as Tangled
redirects .git -> bare in repo URLs rather than the other way around. As
we use Josh with Tangled, there was a period of time where we couldn't
clone or pull through it at all. This had a multitude of knock-on
effects including making it difficult for me to upstream patches (so I
often didn't bother) and entirely breaking our auto-sync mechanism
(which relies on Josh to pull out packetmix from patisserie)
We run silverbullet on teal, and it's a great piece of software. It's
not ideal for us, however, as it doesn't support multiple users the best
and we've had various sync conflicts/delays/etc. even with 1 user. We
also don't need all of its features - for example it seems to be leaning
heavily into offline mode which we don't need...
...insetad, mediawiki. It's heavier, uses wikitext rather than markdown,
etc. but for collaborative features, history, etc. it far exceeds
SilverBullet
We hadn't set up client routing on our personal machines, which stopped
us from using exit nodes/routes/etc.
I've just switched over to a new, larger, SSD. This led to a repartition
which means my drive UUIDs became wrong. Rather than copy down the new
UUIDs, I decided it was nicer to use the drive labels - which also works
I have some apps that I want to install via flatpak, so let's get and
persist flatpak :)
I'm using https://github.com/juliusknorr/nextcloud-docker-dev to test
some changes to a nextcloud plugin, as the plugin needs a more recent
version of Nextcloud than is in nixpkgs.
To be available, I need to set up my hosts file correctly and forward
this over nginx for my other devices.
provokateurin is a GitHub user who works for Nextcloud, so I end up
interacting with her/seeing her commits around sometimes. It'd be nice
to verify them...
I'm doing some development using leptos. There are some recommended
options for rust-analyzer in its book:
https://book.leptos.dev/getting_started/leptos_dx.html
Co-Authored-By: Skyler Grey <sky@a.starrysky.fyi>
deadnix finds unused nix code, some versions were giving us trouble
as we rely on some unused parameters to be introspected by callers...
though not all of them
Previously we were running in to a race condition where OIDC wouldn't
start early enough, so kavita would load without it. As we have turned
off passwords entirely, this would cause the instance to be unusable
I've copied this wait code directly from our oauth2-proxy stuff, which
has the same problem. We should consider if there's a better way to do
this...
Without these, Kavita cannot access files in the library properly
Scary transclusion, so called because it's scarily inefficient and
might cause frightful differences between pages on different wikis due
to caching, is Probably Not That Bad and Might Actually Be Quite Useful
For Transcluding Stuff From Freshly Wiki Onto Starry Sky Wiki.
It's not that useful to have it enabled the other way around, since as
it'll cause permission errors anyway, but it also is unlikely to really
cause problems in a vacuum...
This option specifies what other wikis call this one - in our case
it's FBC (for the wiki on teal) and S (for the wiki on umber). We don't
really need this for our use, but we *do* need to be able to refer to
the other wiki for interwiki links...
We may want to make this an option later, but it certainly isn't correct
to have it the same on every wiki...
As a regression from some of the assertion refactoring...
When you have multiple homes, we were previously comparing the entire
config of each of them to all of the rest. This was a Bad Thing as it
caused us to evaluate the whole of each home, including some attributes
that normally aren't evaluated and broke evaluation completely.
This was relevant for Maya but not for the rest of us - I'm not sure how
CI missed it...
There are some libraries that were updated in nixpkgs 25.11 but which
Collabora gtimelog doesn't support newer versions of. Building gtimelog
from 25.11 will get you an error that looks like this
Traceback (most recent call last):
File "/nix/store/akvr4z3wjiw2gizz6jnbb3f29wa29h8a-python3.13-pygobject-3.54.5/lib/python3.13/site-packages/gi/importer.py", line 137, in create_module
introspection_module = get_introspection_module(namespace)
File "/nix/store/akvr4z3wjiw2gizz6jnbb3f29wa29h8a-python3.13-pygobject-3.54.5/lib/python3.13/site-packages/gi/module.py", line 244, in get_introspection_module
module = IntrospectionModule(namespace, version)
File "/nix/store/akvr4z3wjiw2gizz6jnbb3f29wa29h8a-python3.13-pygobject-3.54.5/lib/python3.13/site-packages/gi/module.py", line 104, in __init__
repository.require(namespace, version)
~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
gi.RepositoryError: Typelib file for namespace 'cairo', version '1.0' not found
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/nix/store/bmy9cw4hbnrq00cc29sza5083yamw74s-gtimelog-0.12.0/bin/.gtimelog-wrapped", line 6, in <module>
from gtimelog.main import main
File "/nix/store/bmy9cw4hbnrq00cc29sza5083yamw74s-gtimelog-0.12.0/lib/python3.13/site-packages/gtimelog/main.py", line 72, in <module>
from gi.repository import Gdk, Gio, GLib, GObject, Gtk, Pango, Soup # noqa: E402
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/nix/store/akvr4z3wjiw2gizz6jnbb3f29wa29h8a-python3.13-pygobject-3.54.5/lib/python3.13/site-packages/gi/importer.py", line 139, in create_module
raise ImportError(e) from e
ImportError: Typelib file for namespace 'cairo', version '1.0' not found
From using nix-locate we can see that cairo-1.0.typelib is in gobject
introspection 1.84.0...
$ nix-locate cairo-1.0.typelib
gobject-introspection.out 0 s /nix/store/i6asc7b7ws92inj5bqvmdbcs3n77dknz-gobject-introspection-wrapped-1.84.0/lib/girepository-1.0/cairo-1.0.typelib
gobject-introspection-unwrapped.out 14,740 r /nix/store/dpwppqwbm76q7h1gk8mv0mg4ylf4b551-gobject-introspection-1.84.0/lib/girepository-1.0/cairo-1.0.typelib
...but search.nixos.org tells us that gobject-introspection is at 1.86.0
Downgrading to 25.05 fixes this issue...
I woke up this morning to a dead menu instance and the following
backtrace:
Jan 05 04:46:24 teal menu-start[1351]: thread 'main' (1351) panicked at src/main.rs:173:6:
Jan 05 04:46:24 teal menu-start[1351]: Failed to connect to database defined in $DATABASE_URL: Io(Os { code: 2, kind: NotFound, message: "No such file or directory" })
Jan 05 04:46:24 teal menu-start[1351]: note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
It seems like this is because, when teal restarted, postgresql hadn't
created a socket by the time menu connected. Restarting menu after the
fact let it run Just Fine. Adding some retries should stop this problem
from coming up...
...a proper solution is probably to fix whatever decides that postgresql
is ready in packetmix, but this is much easier to locate and implement
Since https://github.com/NixOS/nixpkgs/commit/2d0a48912550cdc39a64e71d09d2c838973871ad,
ACME certificates have been issued using a different set of services.
The missinghost.invalid configuration here ended up breaking the nginx
startup by making it so no selfsigned certificate was ever generated,
getting nginx to die on a missing certificate.
Additonally, also as a result of this ACME rework, Stalwart was waiting
on a bunch of nonexistent things and now no longer is
It's not good if our links are case sensitive as different
capitalizations aren't that distinct really. It's still important to
make sure we don't mess up capitalization in the UI or when forwarding
to search engines/etc., though
BREAKING-CHANGE: If you're using links that were made with capitals, those links will stop working
By default, there's no good mobile skin for Mediawiki. You can load
"minerva", which appears to come bundled but not by-default-enabled, but
there's no auto-switching to it when on mobile devices.
The MobileFrontend plugin (as used on Wikipedia) fixes this by using
minerva on mobile devices and a different theme on desktop.
We previously returned One Of The Websites when nginx was accessed from
a host that we didn't know about. That included direct IP address access
as well as things which have been CNAMEd to us (either through a starred
record or due to past services) but which aren't actually hosted by us.
This leads to a number of undesireable effects:
- User confusion ("why does the aux docs website have Stalwart?")
- Incorrect SSL certificates ("your blog seems to have an invalid
certificate")
- SSL being offered via direct IPs, which isn't possible to sign on the
public internet
We can block this by making a default server to take control whenever
nothing matches, and setting that default server to block all
connections and reject all SSL handshakes
We need to have a certificate for this, but it needn't actually be valid
for anything so let's self sign stuff...
It's only basic routes for now - but this is effectively a first
prototype of a golinks server. We still need to make everything
beautiful, but it should be in a workable state when deployed on teal as
of now...
This needs some changes on packetmix to set up a database as well, so
let's make those here too...
We have an extension called Cargo which lets you query through pages.
As well as letting you add arbitrary data to select pages, you can also
have a table which is auto-filled with standard page data. By default,
the table doesn't store much info about each page. It might be nice for
querying if we had various other fields enabled!
For fixing the warning
> trace: evaluation warning: 'system' has been renamed to/replaced by 'stdenv.hostPlatform.system'
There's a few bits and pieces in upstream libraries, which have been
updated to unreleased (or unmerged) versions - I'm putting this through
because it's so critical, with approval from Coded - we will need to
upstream, verify, etc. these changes more properly to consider this
"fixed". This is a "good enough for now"
We would previously get this error when fetching on new machines
… while fetching the input 'git+https://gerrit.wikimedia.org/r/mediawiki/extensions/AdvancedSearch?rev=398c9fa782843d8b3aeaa5ebb1c1b3db35c3382f'
error: Cannot find Git revision '398c9fa782843d8b3aeaa5ebb1c1b3db35c3382f' in ref 'refs/heads/master' of repository 'https://gerrit.wikimedia.org/r/mediawiki/extensions/AdvancedSearch'! Please make sure that the rev exists on the ref you've specified or add allRefs = true; to fetchGit.
Now, this is what I'd expect - because we're not meant to be fetching
master of this extension - we're meant to be fetching a branch! This
seems to be an issue with npins' fetchgit call, which misses out the ref
Due to a nilla bug, fetching dependencies is required for evaluation
so this prevented any evaluation
I think this may be due to the recent 25.11 updates, but I'm not
entirely sure.
sshd started to create forwarded agents under $HOME. This broke Josh
since as home was /var/empty, so forwarding was impossible, resulting in
this error:
debug1: Requesting authentication agent forwarding.
... 8< -- snip -- 8< ...
debug1: Remote: Agent forwarding disabled: couldn't create listener socket
Creating a home for Josh fixes this
In https://github.com/josh-project/josh/pull/1704 I fixed the way Josh
works with redirects. Since as that's not yet in a release, we'll need
to pull in Josh's master for it to be effective.
The bug prevented Josh working entirely with Tangled, since as Tangled
redirects .git -> bare in repo URLs rather than the other way around. As
we use Josh with Tangled, there was a period of time where we couldn't
clone or pull through it at all. This had a multitude of knock-on
effects including making it difficult for me to upstream patches (so I
often didn't bother) and entirely breaking our auto-sync mechanism
(which relies on Josh to pull out packetmix from patisserie)
We run silverbullet on teal, and it's a great piece of software. It's
not ideal for us, however, as it doesn't support multiple users the best
and we've had various sync conflicts/delays/etc. even with 1 user. We
also don't need all of its features - for example it seems to be leaning
heavily into offline mode which we don't need...
...insetad, mediawiki. It's heavier, uses wikitext rather than markdown,
etc. but for collaborative features, history, etc. it far exceeds
SilverBullet
Previously we were running in to a race condition where OIDC wouldn't
start early enough, so kavita would load without it. As we have turned
off passwords entirely, this would cause the instance to be unusable
I've copied this wait code directly from our oauth2-proxy stuff, which
has the same problem. We should consider if there's a better way to do
this...