Welcome! :-)

This is both a wiki (a website editable by all) and a blog (an online diary about the stuff Alex Schroeder reads and does). If you’re a friend or relative, you might be interested in reading Life instead of this page. If you’ve come here from an RPG blog, you might want to head over to RPG. There are other similar categories to be found on the SiteMap.

Für Rollenspieler gibt es ebenfalls eine eigene RSP Kategorie.

2018-07-19 Paginated Feeds

Recently, @jamey was talking about feed pagination (RFC 5005). I finally got around to adding the necessary code to Oddmuse and deploy it for all my sites. So if you check out Recent Changes and click on RSS with pages you should get a feed for all the pages changed in the last month (ignoring minor changes), and if your feed reader supported it, you could fetch previous pages of the same feed and thus scroll through the backlog until somewhere around 2003 those edits would dry up and there’d be nothing left but empty pages.

I’m currently not implementing the first page link so your feed reader wouldn’t realize that it should stop going back in time. It will follow links forever but eventually loops things will get strange. I just tried to see how far back in “negative time” we can go and if we try it with Recent Changes, you’ll get a page saying “Updates since 1900-01-00 00:00 UTC up to 1970-01-01 00:00 UTC”. I guess 1900 is the limit, then. 😂


Comments on 2018-07-19 Paginated Feeds

Sadly, the Journal RSS Extension – which I use a lot – doesn’t fit into the existing RC/RSS framework.

– Alex Schroeder 2018-07-19 12:03 UTC

Add Comment

2018-07-18 Looking At Many Pictures

Do you know the feeling when you’re back from holidays and all you need to do is look through a thousand pictures or more? I know the feeling. And I never really had a good tool to do it. Apple’s iPhoto? Apple’s Preview? Apple’s Finder? Emacs with image-dired?

The answer turns out to be Geeqie. Use m to show marks and use the numbers 1-9 to assign marks. I used 1 for “album”, 2 for “delete”, 3 for “Alex standing in front of things” and so on. Quickly go through the entire list. Then filter by marks and use Ctrl + d to delete or Ctrl + m to move images around.

That’s 99% of what I need to do with images!


Comments on 2018-07-18 Looking At Many Pictures

This looks like it’ll be really useful for culling ahead of Lightroom import. Thanks!

Aaron 2018-07-18 17:18 UTC

Isn’t this what Lightroom is supposed to do? I thought Geeqie was basically a Free Software alternative to Lightroom and the like with fewer features?

– Alex Schroeder 2018-07-18 20:44 UTC

Add Comment

2018-07-18 Geocoding using Perl

Back from those holidays and don’t remember where the pictures were taken? If you took them with a smartphone, chances are the coordinates are part of the EXIF data encoded in the image itself. Here’s a Perl script which extracts that data and tries to find a city nearby using Open Street Map data.

#!/usr/bin/env perl
use Modern::Perl;
use Image::ExifTool;
use Geo::Coder::OSM;
use JSON;
use Data::Dumper;
binmode(STDOUT, ':utf8'); # force UTF-8 output
my $geocoder = Geo::Coder::OSM->new;
my $exifTool = Image::ExifTool->new;
$exifTool->Options(CoordFormat => q{%+.6f},
		   DateFormat => "%Y-%m-%d %H:%M:%S");
for my $file (@ARGV) {
  die "Cannot read $file" unless -f "$file";
  say "$file";
  # Date
  my $date = $exifTool->GetValue('CreateDate', '');
  say $date if $date;
  # City
  my $lat = $exifTool->GetValue('GPSLatitude', '');
  my $long = $exifTool->GetValue('GPSLongitude', '');
  my $location = $geocoder->reverse_geocode(lat => $lat, lon => $long);
  die "No location data found\n" unless $geocoder->response;
  my $json = decode_json($geocoder->response->content);
  die $json->{error} . " $lat/$long\n" if $json->{error};
  say $location->{display_name} if $location;

Example usage:

$ where-was-it.pl IMG_1001.JPG 
2018-06-29 12:35:15
Stationen, Olof Palmes plats, Vaksalastaden, Centrum, Uppsala, Uppsala County, Svealand, 75460, Sweden


Add Comment

2018-07-16 Standing in Front of Things

OK, this is more of a joke album but since I had a laugh looking at me standing in front of Swedish things, here’s a collection of photos:

And we love to eat...


Comments on 2018-07-16 Standing in Front of Things

Notes to myself: I copied all the files from the external disk onto the laptop’s SSD and did the picture selecting in Emacs using M-x image-dired and % m JPG RET C-t C-t and such things. It worked surprisingly well.

rm -rf 2018-sweden-alex/ && ~/src/sitelen-mute/sitelen-mute --title "Schweden 2018 (Alex)" --description "Alex standing in front of Swedish things." --url https://alexschroeder.ch/gallery/2018-sweden-alex/ ~/Pictures/Schweden/Alex 2018-sweden-alex

rsync --progress --recursive -e "ssh -p 882" 2018-sweden-alex alexschroeder.ch:alexschroeder.ch/gallery/

– Alex Schroeder 2018-07-16 16:13 UTC

Add Comment

2018-07-16 Blocking IP Addresses

OK, I’ve fiddled with my setup and I think it should work, but these guys still get on my nerves because I don’t understand why they need to download my entire site, ten thousand selectors and counting. And so I learned about blocking IP addresses using iptables and ipset.

I got all the info from this blog post: Block IP addresses in Linux with iptables.

Here’s the gist of it:

# Install
apt-get install ipset

# create blacklist once
ipset create blacklist hash:ip hashsize 4096
# set up iptables rules
iptables -I INPUT -m set --match-set blacklist src -j DROP
iptables -I FORWARD -m set --match-set blacklist src -j DROP
# add a specific IP address
ipset add blacklist
# confirm the blacklist contains the IP address
ipset list blacklist
# show firewall setup
iptables -L
# unblock IP address
ipset del blacklist

And for IPv6, same same but different.

ipset create blacklist6 hash:net hashsize 4096 family inet6
ip6tables -I INPUT -m set --match-set blacklist6 src -j DROP
ip6tables -I FORWARD -m set --match-set blacklist6 src -j DROP
ipset add blacklist6 ...
ipset list blacklist6
ip6tables -L

To save and restore iptables rules, use the package iptables-persistent. We don’t need this, for now.

This seems to work.


Add Comment

2018-07-15 Russian Gopher Idiots at Work

My Gopher site seems sluggish. I wonder what’s up...

top - 21:28:34 up 99 days,  5:38,  1 user,  load average: 38.37, 32.55, 17.14

Well, load average approaching 40 gives me an idea...

$ bin/time-grouping-gopher < farm/gopher-server.log
         Hour Connections   [%]  Selectors   [%]
2018-07-15 06          25    1%         25   1%
2018-07-15 07          39    1%         39   1%
2018-07-15 08          33    1%         33   1%
2018-07-15 09          36    1%         36   1%
2018-07-15 10          32    1%         32   1%
2018-07-15 11          36    1%         36   1%
2018-07-15 12          40    1%         40   1%
2018-07-15 13          36    1%         36   1%
2018-07-15 14          38    1%         37   1%
2018-07-15 15          36    1%         36   1%
2018-07-15 16          37    1%         37   1%
2018-07-15 17          39    1%         39   1%
2018-07-15 18          38    1%         38   1%
2018-07-15 19          37    1%         37   1%
2018-07-15 20          32    1%         32   1%
2018-07-15 21        2324   81%       2288  81%

Yes indeed! I guess it’s time to stop the server.

And who did it?

$ bin/ip-numbers-gopher < farm/gopher-server.log | head -n 2
                  IP Connections   [%]        2448   82%

Same guys like the other day!

$ whois|grep "org-name\|address"|head -n5
org-name:       "Central Telegraph" Public Joint-stock Company
address:        7, Tverskaya street
address:        125375,
address:        Moscow
address:        RUSSIAN FEDERATION

I think I need to install the honeypot ckeen was talking about.


Comments on 2018-07-15 Russian Gopher Idiots at Work

Time to take another look at the tarpit idea again.

– Alex Schroeder 2018-07-16 06:38 UTC

I just added default Surge Protection.

– Alex Schroeder 2018-07-16 07:41 UTC

Apparently it doesn’t help. I come back to the server and my web and gopher services are down. Load is up to 128. Fiddled with the code some more. As these people are forcing me to spend time writing code I’m not interested in because they wrote a gopher bot that requests pages faster than people usually read, I’m growing angrier every time I’m forced to look at this.

Right now their bot is behaving, though: twenty requests in around 50s.

– Alex Schroeder 2018-07-16 18:56 UTC

Add Comment

2018-07-13 Killing Gopher From Russia

My gopher server crashed...

Remember Killing Gopher Servers From Russia, part 1, from April 2018? Well, It’s July and they’re at it again.

$ bin/time-grouping-gopher < farm/gopher-server.log.1
         Hour Connections   [%]  Selectors   [%]
2018-07-12 06          22    1%         22   1%
2018-07-12 07          38    1%         38   1%
2018-07-12 08          32    1%         32   1%
2018-07-12 09          35    1%         35   1%
2018-07-12 10          34    1%         34   1%
2018-07-12 11          37    1%         37   1%
2018-07-12 12          38    1%         38   1%
2018-07-12 13          35    1%         35   1%
2018-07-12 14          32    1%         32   1%
2018-07-12 15          36    1%         36   1%
2018-07-12 16          35    1%         35   1%
2018-07-12 17          38    1%         38   1%
2018-07-12 18          39    1%         39   1%
2018-07-12 19          41    1%         41   1%
2018-07-12 20        3619   88%       3607  88%

OK, so who did this?

$ bin/ip-numbers-gopher < farm/gopher-server.log.1 | head -n 2
                  IP Connections   [%]        3610   88%

And who is this?

$ whois|grep "org-name\|address"|head -n5
org-name:       "Central Telegraph" Public Joint-stock Company
address:        7, Tverskaya street
address:        125375,
address:        Moscow
address:        RUSSIAN FEDERATION

And who was it last time? It was, also “Central Telegraph”, Russia.


To get a feeling for those 3610 requests:

$ grep < farm/gopher-server.log.1 | head
2018/07/12-20:01:50 CONNECT TCP Peer: "[]:59651" Local: "[]:70"
2018/07/12-20:01:51 CONNECT TCP Peer: "[]:59776" Local: "[]:70"
2018/07/12-20:01:51 CONNECT TCP Peer: "[]:59808" Local: "[]:70"
2018/07/12-20:01:51 CONNECT TCP Peer: "[]:59825" Local: "[]:70"
2018/07/12-20:01:51 CONNECT TCP Peer: "[]:59900" Local: "[]:70"
2018/07/12-20:01:51 CONNECT TCP Peer: "[]:60000" Local: "[]:70"
2018/07/12-20:01:52 CONNECT TCP Peer: "[]:60020" Local: "[]:70"
2018/07/12-20:01:52 CONNECT TCP Peer: "[]:60083" Local: "[]:70"
2018/07/12-20:01:52 CONNECT TCP Peer: "[]:60085" Local: "[]:70"
2018/07/12-20:01:52 CONNECT TCP Peer: "[]:60123" Local: "[]:70"
$ grep < farm/gopher-server.log.1 | tail
2018/07/12-20:17:01 CONNECT TCP Peer: "[]:62389" Local: "[]:70"
2018/07/12-20:17:01 CONNECT TCP Peer: "[]:62397" Local: "[]:70"
2018/07/12-20:17:01 CONNECT TCP Peer: "[]:62400" Local: "[]:70"
2018/07/12-20:17:01 CONNECT TCP Peer: "[]:62415" Local: "[]:70"
2018/07/12-20:17:01 CONNECT TCP Peer: "[]:62418" Local: "[]:70"
2018/07/12-20:17:01 CONNECT TCP Peer: "[]:62427" Local: "[]:70"
2018/07/12-20:17:02 CONNECT TCP Peer: "[]:62436" Local: "[]:70"
2018/07/12-20:17:02 CONNECT TCP Peer: "[]:62442" Local: "[]:70"
2018/07/12-20:17:02 CONNECT TCP Peer: "[]:62449" Local: "[]:70"
2018/07/12-20:17:02 CONNECT TCP Peer: "[]:62471" Local: "[]:70"

It took them 16 minutes to take out the server...


Add Comment

2018-07-05 Preventing Dog Piling

@freakazoid recently said “the Internet can’t just be a wide open mesh where everyone is broadcasting to everyone and can see everything all the time.” This inspired the following blog post.

I think we could write a list of design patterns to make harassment and dog piling on the Internet much harder and most people growing up on today’s Internet would be shocked and say that this is not what they wanted. We’ve been raised to expect the kind of features that make the negative interactions possible.

Everything we post must be non-public. This prevents random strangers from discovering it and thus it works like talking in meatspace. You cannot shout and the whole world will hear it, let alone look it up long after you’ve said it.

We need to bring back introductions because the lack of public interaction also means that you cannot step into a timeline of strangers and join the conversation. You need to be introduced to strangers. The situation is very similar in meatspace: it is hard to talk to strangers unless you are introduced, or the situation is highly scripted by cultural expectations: it’s easy to talk to hair dressers or shop keepers because the topics and the nodes of interaction are highly constrained.

We will call people you have been introduced to your acquaintances. This works better than “friends” because we’re not friends, yet; it also works better than “followers” because it’s a mutual relationship.

Next, we need constrained conversation starts with strangers. All your posts are shown to your acquaintances and a very small number of strangers. We want to prevent dog piling of strangers, right? One possible implementation would shown your “public” post to all your acquaintances and one other person. If they don’t interact with it, they lose access to your post. They didn’t care and so the opportunity to interact went away. Another person is shown the post and the cycle repeats until somebody picks it up or enough time has passed.

If the post is picked up by a stranger, the conversation is no longer shown to strangers but with every interaction, participants can invite one of their acquaintances. This automatically introduces them to the existing participants, if they aren’t acquainted already.

A participant is a person that said something in a conversation. If none of your acquaintances spoke up or your don’t have any, then you are the only participant in the conversation. The stranger reacting is another participant.

We could implement this by saying that you cannot add (“mention”) more than one acquaintance per response of all the participants that joined before you. The later you joined the harder it is to add new friends of yours.

Example: If Alice makes a public post and Beatrice is the stranger making a reply, then Alice doesn’t need to add another participant because all her acquaintances can already see the conversation. If Alice replies to Beatrice, the Beatrice can mention her acquaintance Claudia, thus introducing her to Alice. Both Claudia and Alice are now acquainted by default unless they choose to undo this.

If the conversation goes sour, people can leave and cancel their introductions. If they do, they will not get reacquainted by future introductions. This would require an explicit action on both parts.

This service doesn’t do celebrity accounts and news bots. Use blogs for this.

This setup doesn’t solve people working their way into your inner circles and then turning on you. It doesn’t solve ostracizing by your supposed friends. It doesn’t solve gossip and rumors and slander. And yet, it already feels very different from Twitter and Mastodon.

I guess one could make Facebook behave like this by avoiding public posts and groups?

This service would need lists and mass introductions: it was called “circle sharing” in the old Google+ user interface. Sadly, it is no more.


Comments on 2018-07-05 Preventing Dog Piling

A good thread on Mastodon by @freakazoid, @ajroach42 and @ishara starts here: Sean argues for organic growth, like I do in my doomed proposal. Andrew says we need to keep the possibility of meeting strangers alive. Barry adds that hashtags facilitate community finding. It’s interesting food for thought!

– Alex Schroeder 2018-07-06 20:41 UTC

Add Comment

2018-07-03 Rotating Text Mapper Maps

A user sent me a little NodeJS script to rotate a map in order to get “stacked columns”.

I wonder whether I should add a different hex stacking option to Text Mapper.


Add Comment

2018-07-03 Privancy and Agency

Why personal agency matters more than personal data: „For example, the clothes that we wear are privacy technologies. We also have norms that discourage others from, for example sticking their hands inside our clothes without permission. The fact that adtech plants tracking beacons on our naked digital selves and tracks us like animals across the digital frontier may be a norm for now, but it is also morally wrong, massively rude and now illegal under the GDPR.“


Add Comment



Please make sure you contribute only your own work, or work licensed under the GNU Free Documentation License. Note: in order to facilitate peer review and fight vandalism, we will store your IP number for a number of days. See Privacy Policy for more information. See Info for text formatting rules. You can edit this page if you need to fix typos. You can subscribe to updates by email without leaving a comment.

To save this page you must answer this question:

Please say HELLO.

Referrers: Gothridge Manor Diary Alex Schroeder 🐝 (@kensanata@octodon.social) - Octodon ZENOPUS ARCHIVES HERR ZINNLINGS ARBEITSZIMMER Strange Magic: B/X D&D and Armor Dreams of Mythic Fantasy Diary frothsof D&D rsp-blogs.de