Empire Games (Empire Games 1), door Charles Stross

Technothriller
De laatste keer dat ik iets van Charles Stross las, noemde hij zich nog Charlie Stross. Zijn nieuwe werk stond al een poos op mijn lijstje omdat ik Singularity Sky en Iron Sunrise zeer goed en vermakelik vond. Empire Games is echter heel iets anders. Zoals veel science-fictionschrijvers kruipt zijn werk dichter en dichter naar onze eigen tijd toe en zonder de component van verschillende tijdlijnen zou zijn werk eerder technothriller (zgn. diamantharde scifi) zijn dan science fiction – of fantasy.

Tijdlijnen
Die tijdlijnen zijn een leuk concept: in lijn met hoe men tegenwoordig denkt over het multiversum, heeft de mens op cruciale momenten in de geschiedenis keuzes gemaakt die het universum heeft doen splitsen in verschillende versies. In elk van die tijdlijnen heeft de mens een (iets) andere geschiedenis doorgemaakt en zit de wereld dus anders in elkaar.

World-walkers
Het is voor gewone mensen met machines mogelijk om van de ene tijdlijn naar de andere te gaan. Alleen de zogenaamde world-walkers kunnen het zonder machines. Vanwege deze unieke gave waren de world-walkers vroeger een volk/familie (‘clan’ noemen ze zichzelf) van handelaren en smokkelaars. Na een grote aanslag door world-walkers worden ze voornamelijk als bedreiging gezien. Lastig genoeg is de enige manier om te spioneren in andere tijdlijnen alleen goed te doen met diezelfde world-walkers.

Fantasy
Een aardig concept dus maar het voelt erg fantasy-achtig aan, ware het niet dat Stross er min of meer plausibele technische verklaringen voor geeft, hoewel die jammergenoeg niet heel uitgebreid worden toegelicht. De nadruk ligt op het politieke vlak en de (contra-)spionage. Dat is op zich goed genoeg en het verhaal zit goed in elkaar, met levende karakters, plottwists en een fijne uitsmijter.

Al met al een prima technothriller waarin Stross laat zien dat hij zich heeft ontwikkeld tot een topschrijver. Heerlijk om te lezen, ook voor liefhebbers van fantasy en mensen die niet al te veel op hebben met scifi én fantasy maar een goeie spionageroman kunnen waarderen.

Lament for the fallen, door Gavin Chait

Een aardig boek met een vernieuwende insteek: ergens in de nabije toekomst (21ste of 22ste eeuw waarschijnlijk) zijn er steden in een baan om de Aarde. Een van de bewoners komt terecht in een Afrikaans dorp. Het verhaal wordt deels verteld vanuit het dorp en deels vanuit de bezoeker.

Hoewel het niet spectaculair goed geschreven is en ook het verhaal niet erg bijzonders is, is de achtergrond wel heel mooi (de world building, zoals dat heet): Chait geeft een boeiend beeld van een mogelijke toekomst waarin je levensstandaard nog veel sterker dan nu wordt bepaald door waar je bent geboren.

Meer menselijke drama dan space opera, een optimistische dystopie.

Achterin het boek staat een playlist met muziek en scènes. De playlist is ook online te vinden. Niet de eerste schrijver die het doet maar het geeft wel een extra dimensie aan het boek!

Advies: lezen, al is het maar voor de verandering.

Dark Intelligence, door Neal Asher

Neal Asher is een goeie science-fictionschrijver. Zijn bladzijdes staan boordevol sf-ideeën die voor de doorgewinterde sf-liefhebber gesneden koek zijn en die hij daarom verder niet uitlegt. Helemaal niet erg want van die uitleg word je soms ook beetje moe.

Dark intelligence speelt in zijn Polity-universe. Om het stand-alone leesbaar te houden, licht hij daar wel het een en ander over toe. Niet tot vervelens toe maar wel genoeg om het verhaal goed te kunnen volgen, en dat lukt ‘m aardig.

Het verhaal zit stampvol actie en leest als een snelle actiefilm, ook door de wisselende perspectieven.

Dit alles zorgt voor een prima boek… Als ook het verhaal in orde was geweest. Begrijp me niet verkeerd: het verhaal is niet slecht. Het is spannend en intelligent maar niet te ingewikkeld. Mijn bezwaar is dat het een dertien-in-een-dozijnverhaal is. Soldaat zoekt wraak. Ja, de uitwerking is fantastisch en de stijl zalig. Maar het verhaal is te eendimensionaal.

Advies: lezen als je van harde scifi houdt en eens een kijkje in de Polity wil nemen.

Cowsay when logging on via SSH

To give my server a bit of personality I have it render words of wisdom everytime I log on to it through SSH. Also, show its uptime and any tunning tmux sessions.

This is for Debian 8, I’m not sure about Red Hat or other distros.

First install fortune and cowsay:

# aptitude install fortune cowsay

Place the following commands in ~/.ssh/rc:

#!/bin/bash
clear
fortune | cowsay -f $(ls /usr/share/cowsay/cows/ | shuf -n 1)
echo "$(uptime)"
echo ""

tmux list-sessions >/dev/null 2>&1
if [ "$?" = "0" ] ; then
  echo "Running tmux sessions:"
  echo "$(tmux list-sessions)"
else
  echo "No running tmux sessions."
fi

echo ""

Restart ssh (this will not disconnect any running ssh sessions):

# service ssh restart

Let’s see what happens…

 

Sweet!

Strafkrediet en de grappigheidsclausule

Grappigheidsclausule
Soms kom je acties tegen die overduidelijk illegaal maar desondanks grappig zijn. Zoals de muur in de deuropening van een Hamburgse metro of de Belg die probeert een boete te ontlopen met een parkeerschijf op batterijen. Het mag niet maar er zijn geen slachtoffers (geen natuurlijke personen in ieder geval) en je moest lachen toen je het voor het eerst las.

Ik vind dat we moeten afspreken dat de dader of overtreder in zulke gevallen straf- of boetevermindering moet kunnen krijgen. Geen complete kwijtschelding want we willen geen aanzuigende werking natuurlijk.

Strafkrediet
Weleens een boete gekregen voor te hard rijden en daarna aan kunnen tonen dat je auto op die dag bij de garage was? Twee jaar gezeten voor een moordaanslag waarvan achteraf kon worden vastgesteld dat jij het niet had kunnen doen? Dan is het tijd voor het strafkrediet.

Strafkrediet houdt in dat je voor normale stervelingen strafbare feiten mag plegen zonder dat je daar straf voor krijgt. Een eventueel nieuwe door de rechter opgelegde straf, bijvoorbeeld omdat je een ruit ingegooid hebt bij de verzekeraar die jou een poot uitgedraaid had, wordt van het strafkrediet afgetrokken. Een soort omgekeerde oog om oog, tand om tand. Zestig km/u te snel gereden op de provinciale weg? Gaat gewoon af van uw strafkrediet; u hebt nog één jaar en zeven maanden over.

Misschien wordt het toch tijd om ook een politieke partij op te richten! #StemVork!

Randomly follow your Twitter friends’ friends

Following a rather radical pruning of my Twitter followings (people who I am following) my timeline has got both better and less exciting. So I wanted to follow some new people but not just random accounts.

I have a list of ununfollowables: the followings I like best. Those people are probably good judges of the people I should follow – or in any case better at it than random followings.

This script looks who they are following and follows those account. The result is that periodically I automatically follow some of my friends’ friends. It keeps a list of those I’ve followed automatically. If it doesn’t work out I unfollow them again. Of course nothing is keeping me from re-following them manually.

The script relies heavily on @sferik’s Twitter client for Ruby called ‘t’. It’s easy to install but it helps if you read the help file and get to know it a bit should you need to troubleshoot or adjust the script.

It is designed to be run from cron and written on a Debian 8 system but it should run on any Linux flavour. Be sure to add t’s path to your cron file.

The script is called freshmeat.sh on my system.

#!/bin/bash

#######################################################################
# Purpose of this script:                                             #
# Follow random followings from followings from the ununfollowables   #
# list, hopefully generating a bit more diversity in your timeline.   #
#                                                                     #
# The ununfollowables list is just a list of people you like.         #
# A 'following' is someone you are following. It is the reverse of    #
# a follower.                                                         #
#                                                                     #
# Requires:                                                           #
#  - Working and authenticated installation of Ruby gem t:            #
#    https://github.com/sferik/t                                      #
#  - Twitter list called 'Ununfollowables' (change as needed)         #
#    containing friends whose followings you might like to follow     #
#  - Twitter list called 'freshmeat' for the new followings           #
#                                                                     # 
# Feel free to use, change and redistribute this script as long as    #
# you include a link to https://vorkbaard.nl and this text. Enjoy 🙂  #
#                                                                     # 
#  @Vorkbaard, 2017                                                   #
#######################################################################


#######################################################################
#  Settings                                                           #
#######################################################################

# Ununfollowables list
UNUNFOLLOWABLES_LIST=de-onontvolgbaren

# Freshmeat list
FRESHMEAT_LIST=freshmeat
 
# Number to days to wait before unfollowing if they're not interested
WAITDAYS=13

# Number of new random followings to add - must be more than 0.
# Note that this script uses up your api access allowance:
# https://dev.twitter.com/rest/public/rate-limiting 
# Also note that a list cannot contain over 5000 members.
NEWADDINGS=5

# Do not follow people with the following words in their bio.
NOTFOLLOW="entrepreneur|founder|coach"


## MAIL - Make sure your server can send out mail first.
## I'm using xmail but you may want to change it.

# Send mail here:
MY_EMAIL=your@email.here

# The mail's from address
FROMADDR=your@servers_email.here


#######################################################################
#  End of settings                                                    #
#######################################################################

# Change to directory this script is in so we can use relative file locations when running from cron
cd "$(dirname "$0")";

# Retrieve Twitter handle
ME=@$(t whoami | head -4 | tail -1 | cut -d'@' -f2)
if [ "$?" != "0" ] ; then
	echo "Unable to retrieve Twitter handle, please make sure t is installed and working correctly."
	echo "Either that or we've ran out of api calls."
	exit
fi

echo "---------------------- $(date) --------------------" >> freshmeat.log
echo "Twitter handle: $ME" >> freshmeat.log

if [ -e mailtext ] ; then rm mailtext; fi

# Ok, here's the gist.

# Unfollow those not interested
# 1. Get list of randomfollowings followed over two weeks ago.
# 2. If they're not interested then unfollow them.
# 3. Remove them from the freshmeat list and the inprocess file.

# Get new users
# 4. Select random user from ununfollowables list.
# 5. Select random following from selected user.
# 6. Check if we're not already following the random following. If we do, select another one.
# 7. Follow the random following.
# 8. Put following on the freshmeat list.

# Create list of leaders so we only need to retrieve it once.
# Leaders are people who you are following but who don't follow you.
echo "Creating list of leaders. Please hold." >> freshmeat.log
t leaders > leaderslist
if [ "$?" != "0" ] ; then 
	echo "Error: probably not enough api calls left. Try again later." >> freshmeat.log
	echo "We ran out of api calls. Better luck next time!" | mailx -a "From: Freshmeat provider <$FROMADDR>" -s "Fresh meat!" $MY_EMAIL
	exit
fi

if [ -e freshmeat.inprocess ] ; then
	let WAITSECONDS=$WAITDAYS*60*60*24
	echo "WAITSECONDS: $WAITSECONDS" >> freshmeat.log
	echo "Getting list of randomfollowings followed over two weeks ago" >> freshmeat.log
	NOW=`date +%s`
	while read RANDOMFOLLOWING; do
		SINCE=$(echo $RANDOMFOLLOWING | cut -d' ' -f2)
		RAFO=$(echo $RANDOMFOLLOWING | cut -d' ' -f1)
		echo "Rafo: $RAFO" >> freshmeat.log
		echo "Since: $SINCE" >> freshmeat.log
		echo "NOW..: $NOW" >> freshmeat.log
		let DIFF=$NOW-$SINCE
		let HDIFF=$DIFF/3600
		echo "Time difference: $DIFF ($HDIFF hours)" >> freshmeat.log
		if [ "$DIFF" -lt "$WAITSECONDS" ] ; then
			echo "Time difference is less than $WAITDAYS days." >> freshmeat.log
			# Not doing anything with them now, just add them to the list for next time
			echo $RANDOMFOLLOWING >> freshmeat.inprocess_new.log
		else
			echo "Time difference is greater than $WAITDAYS days." >> freshmeat.log
			# Check if they're following back
			
			grep -iq "^$RAFO$" leaderslist
			if [ "$?" == "1" ] ; then
				# They're following back
				echo "$RAFO is following back!" >> freshmeat.log
				echo "$RAFO" >> newfollowers.log
				echo "New connection made: $RAFO - https://twitter.com/$RAFO" >> mailtext				
			else
				# They're not following back
				echo "$RAFO is not interested so unfollowing them." >> freshmeat.log
				t unfollow $RAFO >/dev/null 2>&1
				echo "Unfollowed $RAFO." >> mailtext			
			fi
			
			echo "Removing $RAFO from freshmeat list." >> freshmeat.log
			t list remove $FRESHMEAT_LIST $RAFO >/dev/null 2>&1
			if [ "$?" == "0" ] ; then
				echo "Removing $RAFO from random follower log file." >> freshmeat.log
			else
				echo "Error unfollowing $RAFO. Perhaps we've ran out of api calls." >> freshmeat.log
			fi
		fi
		echo "----" >> freshmeat.log
	done <freshmeat.inprocess
	# Recreate freshmeat.inprocess file with only remaining (current) followings
	mv freshmeat.inprocess_new.log freshmeat.inprocess 
else
	# if not exist freshmeat.inprocess
	echo "freshmeat.inprocess doesn't exist; nothing to compare so skipping the unfollow part." >> freshmeat.log
fi

# Create list of ununfollowables so we only need to retrieve it once
echo "Creating list of ununfollowables. This may take a while." >> freshmeat.log
t list members $ME/$UNUNFOLLOWABLES_LIST > ununfollowableslist
if [ "$?" != "0" ] ; then
	echo "Error: probably not enough api calls left. Try again later." >> freshmeat.log
	echo "We ran out of api calls. Better luck next time!" | mailx -a "From: Freshmeat provider <$FROMADDR>" -s "Fresh meat!" $MY_EMAIL
	exit
fi

# Create list of followings so we only need to retrieve it once.
echo "Creating list of followings. Please hold." >> freshmeat.log
t followings > followingslist
if [ "$?" != "0" ] ; then 
	echo "Error: probably not enough api calls left. Try again later." >> freshmeat.log
	echo "We ran out of api calls. Better luck next time!" | mailx -a "From: Freshmeat provider <$FROMADDR>" -s "Fresh meat!" $MY_EMAIL
	exit
fi

# Initialize the number of succesfull new followings
ADDINGS=0

printf "\n\n" >> mailtext
echo "New followings" >> mailtext
echo "------------------------------" >> mailtext
while [ $ADDINGS -lt $NEWADDINGS ] ; do
	echo "Succesfull addings: $ADDINGS" >> freshmeat.log

	# Get random ununfollowable
	UNUNFOLLOWABLES=$(cat ununfollowableslist | shuf -n 1)
	echo "Following from ununfollowableslist: $UNUNFOLLOWABLES" >> freshmeat.log

	for UNUNFOLLOWABLE in $UNUNFOLLOWABLES; do
		echo "Getting random following from $UNUNFOLLOWABLES_LIST." >> freshmeat.log
		RANDOMFOLLOWING=$(t followings $UNUNFOLLOWABLE | shuf -n 1)
		echo "Randomfollowing: $RANDOMFOLLOWING" >> freshmeat.log
		if [ -n "$RANDOMFOLLOWING" ] ; then
			
			# Check if we're not already following this particular random following
			grep -iq "^$RANDOMFOLLOWING$" followingslist
			if [ "$?" == "1" ] ; then
				echo "Not already following, but is this a protected account?" >> freshmeat.log

				# Protected accounts don't have the 'Last update' bit set in their public profile.
				# Also, get to know them a bit by reading their bio. 
				t whois $RANDOMFOLLOWING > tmpwhois

				# Check if the account is protected
				grep -q "Last update" tmpwhois
				if [ "$?" == "0" ] ; then

					# Check if they're not unwanted
					BIO=$(grep "Bio" tmpwhois)
					if echo $BIO | egrep -iqv $NOTFOLLOW; then

						echo "Not already following $RANDOMFOLLOWING AND not a protectect account AND they're not unwanted so following them now." >> freshmeat.log
						t follow $RANDOMFOLLOWING >/dev/null 2>&1
						if [ "$?" == "0" ] ; then
							echo "Follow succesful so adding them to $FRESHMEAT_LIST." >> freshmeat.log
							t list add $FRESHMEAT_LIST $RANDOMFOLLOWING >/dev/null 2>&1
							NOW=`date +%s`
							echo "$RANDOMFOLLOWING $NOW" >> freshmeat.inprocess
							# Increase addings number
							ADDINGS=$(( $ADDINGS + 1 ))
							SHOWBIO="$(echo $BIO|cut -c5-)"
							echo "Via $UNUNFOLLOWABLES: $RANDOMFOLLOWING - $SHOWBIO [https://twitter.com/$RANDOMFOLLOWING]" >> mailtext
						fi 
					else
						echo "Not going to follow $NOTFOLLOW." >> freshmeat.log   
					fi
				else
					echo "Not going to follow protected account." >> freshmeat.log
				fi
			else
				echo "Already following $RANDOMFOLLOWING." >> freshmeat.log
			fi
			echo "---- done ----"  >> freshmeat.log
		else
			echo "We've probably ran out of api calls so let's call it a day." >> freshmeat.log
			ADDINGS=$(( $NEWADDINGS + 1 ))

		# if -n $RANDOMFOLLOWING
		fi

	# for UNUNFOLLOWABLE
	done

# Addings
done

# Mail logfile
	# Get number of connections generated
	if [ -e newfollowers.log ] ; then
		FreshFollNr=$(wc -l newfollowers.log | cut -d' ' -f1)
		echo "Freshmeat has generated $FreshFollNr connections." >> mailtext
	else
		echo "Freshmeat has not generated any connections yet." >> mailtext
	fi	

	# Get number of people in Freshmeat list
	FreshmeatMembersNr=$(t list information $FRESHMEAT_LIST | head -5 | tail -1 | cut -d ' ' -f7)
	echo "There are now $FreshmeatMembersNr people on the $FRESHMEAT_LIST list." >> mailtext

	# Send mail
	cat mailtext | mailx -a "From: Freshmeat provider <$FROMADDR>" -s "Fresh meat!" $MY_EMAIL
	rm mailtext

# Clean up
	if [ -e tmpwhois ] ; then rm tmpwhois; fi
	if [ -e followingslist ] ; then rm followingslist; fi
	if [ -e ununfollowableslist ] ; then rm ununfollowableslist; fi
	if [ -e leaderslist ] ; then rm leaderslist; fi