Arduino Project: Platform Independent Clipboard

The Platform Independent Clipboard

The source code for the project is available on the GitHub: – this article references line numbers in the 596944 commit. This source code is released under an open MIT License, allowing you to copy, modify and redistribute it with your changes, commercially or not. If you like the project – please ping me on Twitter, I love when people get something out of whatever I publish.

Who would need such a thing?

The idea of a platform independent clipboard first came to me when a relative working at the state national police force of Denmark, introduced me to a challenge of theirs.

When a police officer is dealing with a case, it involves repeatedly entering name and birthdates into several computer systems. Some of these systems are different applications on the same computer, some are on different physical computers and some of these have entirely different operating systems. This part of the officer’s daily work has been identified by consultants as time consuming and error prone – resulting in additional time wasted, when correcting data or not finding the correct persons, due to mistakes made when typing.

Word of caution – this is almost password sniffing key-logger

With minor changes of the device’s source code, it could act as a key-logging device, that could potentially snoop/sniff/eavesdrop on classified information if hidden from the person using the computer. It is essentially a device performing a man in the middle attack.

Therefore it is important to permanently force the activation pin low, once this device is introduced in into a real police station. This way tinkers have a much harder time connecting to the Arduino in a state where it is reprogrammable. Alternatively change the source code to not wait for an activation signal before acting as a keyboard towards the computer.


This project aimed at designing and implementing a product prototype, utilizing both hardware and software, to propose a viable solution for the aforementioned problem.

The product should help the police officer transfer confidential data such as names and birthdates from one physical machine to another, reducing the time spent and the errors occurring when retyping the same data into multiple computer systems.


From an initial conversation with two officers, I formulated an ordered list of functional requirements – an initial backlog of user stories:

  1. As an officer, I want to be able to use the keyboard as usual, so that I can perform my daily work without any additional challenges introduced by technology.
  2. As an officer, I want to selectively start recording a sequence of keystrokes starting from the press of “a special key” until the press of the another or the same special key so that I can control from when to start the recording of my keystrokes.
  3. As an officer, I want to be able to replay a sequence of keystrokes previously recorded, so that I can retype names, numbers, etc. without introducing typing errors.
  4. As an officer, I want to be able to record and playback multiple sequences keystrokes so that I can store and replay more than one sequence of keystrokes.
  5. As an officer, I want to be able to transfer the recorded keystrokes between physical computers on a medium so that I can reuse the a recorded sequence from one machine on another machine.
  6. As an officer, I want to be able to encrypt and password protect my transfer medium (NFC chip) so that I do not have to worry that confidential data is compromised if I loose the transfer medium.

As qualitative / non-functional requirements, the following observations are made

  1. The cost of the device matters – we want a solution that is not too expensive in production. 80 euro (~ 600 DKK) per device seems to be a reasonable upper limit.
  2. Perhaps needless to say, the device has to be user friendly. Meaning that an officer should be able to operate the universal clipboard with little to no training and with no more instructions that what can be written on a sticky label on-top of the device.

What hardware is needed?

Why not just implement this in software? Well, as the problem suggests, this may take a long time as we are talking about a couple of different applications on a couple of different operating systems. Figuring out the plumbing, how to write a slick user interface across the broad range of configurations would probably end up taking too much time.

So I thought to myself – could this be implemented independently of the software on the PC? This was what I wanted to do.

These is the complete list of parts that you’ll need to build one platform independent clipboard:

This totals 563 DKK per device or alternatively 70 euro (~521 DKK) when producing 100 or more in a batch.

Implementing user story #1 – Being able to use the keyboard as usual

So – a user want to connect a device to her computer and her keyboard to the device, after which she expects the computer to respond to key presses made on the keyboard, as if nothing was in the middle.

Hardware compatibility issues encountered early on in the project

Initially I tried implementing user story #1 using the Arduino Due – I figured it had two USB ports, one that could act as a native USB device towards the computer and one that act as USB host towards the keyboard.

Unfortunately it turned out that the programming USB port on the Due, can only easily be used for programming the device. The native USB port can be used for either acting as a client (keyboard, mice, etc) towards the computer or as a host for peripherals, but of course not both at the same time.

The article about the Due on, talks about the native USB port:

Using the Native port enables you to use the Due as a client USB peripheral (acting as a mouse or a keyboard connected to the computer) or as a USB host device so that devices can be connected to the Due (like a mouse, keyboard, or an Android phone).

Bummer – I tried extending the Due with a USB host shield, but it seemed like the Due got confused and thought I was asking the native port to act as a USB host device, even when using the libraries provided with the host shield.

I then tried implementing user story #1 using the Arduino Uno and the USB host shield – this should in principle be possible, but the Uno board’s firmware has to be flashed between each reprogramming of the board, as it needs different firmware for the board to act as a keyboard towards the computer than the firmware needed to act as an Arduino to the computer. Read more about flashing the Uno to act as a peripheral to the computer on this article.

What to do? Go search the internet for more information.

It turns out that the Arduino Leonardo board has an interesting feature very suitable for this application. Its single USB port can act as both a programming port, enabling serial communication towards the computer while at the same time acting as several peripherals towards the PC.

Combined with a USB host shield the Arduino Leonardo gives the unique possibility of being able to listen for ingoing keystrokes from a keyboard connected to the USB host shield while being able to send these keystrokes onto the PC through the USB port on the Leonardo.

Registering key strokes from the USB host shield

This is done using the USB host shield, through the library provided by Oleg Mazurov and Alexei Glushchenko from [email protected], Kristian Lauszus and Andrew Kroll on GitHub (download).

Once the library has been installed, the projects source code line #143 and #146 initiates global objects USBHost and HidKeyboard that will enable communication with a keyboard connected to the USB Host shield.

USB UsbHost;
HIDBoot HidKeyboard(&UsbHost);

Once initialized, the HidKeyboard object has a HIDReportParser named keyboard_in (initialized on line #157) registered on line #339 and the USB host shield is given program control on every loop-call that the Arduino does – see line #362


The ProxyKeyboardParser class, which is implemented for this particular project and extended from the KeyboardReportParser parser (which is again a specialization of the HIDReportParser), provides callback methods for the HidKeyboard object to call when the user interacts with the keyboard.

Sending key strokes onward to the connected computer

This step was the most trouble I had in the project. The Arduino keyboard library functionality kindly translates ASCII characters to a KeyReport object with key strokes that the computer understands. This way it is easy to send upper and lower-case letters using the Keyboard.write method. But if you have the raw key strokes and the modifier byte (communicating the left/right ctrl, shrift, alt and GUI key states), this turns out to be an anti-feature.

I looked into the Arduino cores implementation of the press and release methods and found that I could extend the Keyboard_ class and overwrite the implementation (lines 88-123 in the projects source code) to not do a transformation from ASCII to key stroke bytes and change of modifiers.

// Sending out a key press to the computer
size_t KeyboardOut::press(uint8_t k) {
  uint8_t i;
  // Add k to the key report only if it's not already present
  // and if there is an empty slot.
  if (_keyReport.keys[0] != k && _keyReport.keys[1] != k && 
    _keyReport.keys[2] != k && _keyReport.keys[3] != k &&
    _keyReport.keys[4] != k && _keyReport.keys[5] != k) {
    for (i=0; i<6; i++) {
      if (_keyReport.keys[i] == 0x00) {
        _keyReport.keys[i] = k;
    if (i == 6) {
      return 0;
  return 1;
// Sending out a key release to the computer
size_t KeyboardOut::release(uint8_t k) {
  uint8_t i;
  // Test the key report to see if k is present.  Clear it if it exists.
  // Check all positions in case the key is present more than once (which it shouldn't be)
  for (i=0; i<6; i++) {
    if (0 != k && _keyReport.keys[i] == k) {
      _keyReport.keys[i] = 0x00;
  return 1;

This functionality is called from the ProxyKeyboardParser class (lines 159-180). A simplified version of the source code below, shows how key presses from the USB host shield is communicated to the computer using the keyboard_out object.

void ProxyKeyboardParser::OnControlKeysChanged(uint8_t before, uint8_t after) {
void ProxyKeyboardParser::OnKeyDown(uint8_t mod, uint8_t key)
void ProxyKeyboardParser::OnKeyUp(uint8_t mod, uint8_t key)

The working LED blinks whenever a key press or release is intercepted – to show the user that something is happening, in the hopes of making the device more user friendly.

Implementing user story #2 – Being able to record keystrokes

In order for the user to be able to record their keystrokes, she must first activate the recording. This is done by pressing a special combination of keys. I thought of a sequence which I anticipated was rarely used when entering data into the systems at the police force. This has remains to be finally verified, but the code can easily be modified to support an alternative activation key sequence.

The ProxyKeyboardParser’s OnKeyDown method was extended with a call to an axillary function which evaluates if the user is trying to start or stop a recording.

void ProxyKeyboardParser::OnKeyDown(uint8_t mod, uint8_t key)
  bool controlled = intercept_recording_command(mod, key);
  if(!controlled) {
    intercept_recording_key(mod, key);;

The implementation of the intercept_recording_command function checks for three scenarios:

  1. Start the recording of keystrokes. (line 234)
  2. Replay a recording of keystrokes. (line 238)
  3. Stop the recording of keystrokes. (line 242)

The replaying of keystrokes are for the next user story to implement, whereas this focusses on starting and stopping a recording.

When the user holds down the left or right control key, while holding down the left or right shift key – and presses one of the numbers one though nine on the numeric pad, the recording of a sequence of keystrokes begins. See lines 234-237.

When recording is active and the user presses either the tabular key, the return/enter on either the main keyboard or the numeric pad, the recording is stopped.

When starting  are recording the an integer variable active_channel_index is set to zero and a call to the clear_channel function clears out the recording buffer (an array called channels), by writing zeros all in its entire length.

As seen above, the OnKeyDown callback on the ProxyKeyboardParser also calls the intercept_recording_key function, if the key press was one of the aforementioned command key scenarios.

This intercept_recording_key function saves the modifiers and key to the channels buffer, incrementing the active_channel_index by two, for every key pressed by the user. That way both the state of the eight modifier buttons are saved along with the key presses.

Implementing user story #3 – Being able to replay keystrokes

Replaying keystrokes can only happen when the user is not recording. If this is the case, the user replays by pressing either the left or right control key, together with one of the numbers one through nine on the numeric pad.

When this happens, the replay_channel function (lines 289-311) is called. A loop is going through each of the two-tuples of modifier and key:

  • First determining if the key is larger than zero. If this is not the case, the replay is stopped immediately – as a zero key indicates the end of a sequence of keystrokes.
  • Then the modifier byte of the report is set.
  • The key is pressed and
  • finally the key is released.

The state of the modifiers are saved (line 307) before and restored (line 291) after the channel is replayed to the computer.

Implementing user story #4 – Record and replay multiple sequences

This was actually implemented together with the user stories #2 and #3, as I found it easier to have this functionality implemented from the beginning, rather than implementing it simple and advancing from there.

The buffer, called channels, in which the keystrokes are recorded, is actually a two dimensional array, where the first index dictates which of nine channels the recording is to be stored in or replayed from. Every function manipulating keystroke data, takes an unsigned integer argument referencing which channel the operation is to be performed in.

This is again why the user presses control + shift + a number on the numeric pad, when starting a recording. The latter tells the device which channel the recording is going into, the same goes for the replay.

Implementing user story #5 – Storing sequences on a physical medium

The RFDI/NFC shield is connected and it is verified that the Arduino Leonardo can communicate with it (it uses an I²C bus). It had to be modified acording to this guide from, removing the connection to pin 2 and re-routing it to pin 6.

As I have had an agile approach to this, estimated what I could get implemented in the project period and done my implementation one user story at a time, I didn’t get to implement the storing of keystroke data on an RFID MiFare tag. This was mainly due to trouble in the initial phase of finding compatible hardware and implementing a keyboard proxy, bypassing the Arduino’s anti-feature of translating ASCII characters to key strokes.

Implementing user story #6 – Securing the physical medium

This could be implemented using hashes generated from a users password as keys when storing data on the MiFare card. The user could enter this password as the first key sequence when inserting a new RFID tag in the device.

The only problem is that the MiFare’s encryption scheme is no longer considered save as hackers as early as 2008 discovered ways to reveal secrets off the tags in minutes using a regular desktop computer, see–the-mifare-rfid-crack-explained.html.

One could employ a stronger encryption scheme, such as an algorithm in the AES family.

Further work

Below are suggestions for further work, for me or anyone reading this:

  • Implementing the two remaining user stories #5 and #6 as mentioned above,
  • Verifying the control sequence (ctrl + shift + # on numeric pad) is not used by other programs at the police,
  • verify that the relevant computers at the police force supports USB, alternatively implement the sending part of the device using the PS/2 keyboard protocol.


I have build a device, using the Arduino platform that sits between a USB keyboard and a USB enabled PC, forwarding any key press, except the ones that are used to control the recording, stopping and replaying of key strokes on nine channels.

The device fulfils the need of a platform independent clipboard across multiple applications on a single computer, but the transfer of key strokes between machines using a physical medium remains.

I hope you enjoyed reading this article – please feel free to ping me on e-mail or Twitter (@kraenhansen), in case you have comments or questions.

In data we trust! XSS sårbarhed på

Stor data, åbn data, data om data – den er alle vegne.

Vi bruger data som grundlag for at træffe beslutninger og derfor er vi dybt afhængige af at andre mennesker, myndigheder og virksomheder giver os korrekt data.

Når vi træffer beslutninger på baggrund af data, er det helt afgørende hvorfra vi har fået dataen, kommer den fx fra en offentlig myndighed, har vi en forventning til at dataen er korrekt.

Eksemplets magt

Det antages almindeligvis, at adresser indgår i helt op til 80 % af de digitale løsninger, som et moderne samfund betjener sig af.

I hvert fald hvis man skal tro på Ministeriet for By, Bolig og Landdistrikter.

Adresser står på postkasser. Ikke e-Bokse, nej. Den slags hvor man modtager helt almindelige, kedelige, snail mails. Her er et billede af min.

Det er ingen hemmelighed at jeg synes at IT sikkerhedsmæssige udfordringer er rigtig interessante. Da jeg samtidig elsker at dele ud af min viden, hvad ville så være en mere naturligt end at oprette en konsulentvirksomhed hvor jeg kan gøre netop dette?

Lad os kalde min nye virksomhed for CREEN security – og lad os fortælle Erhvervsstyrelsen at jeg har tænkt mig at være IT konsulent.

En sådan registrering kan ske via, hvor man med 3 klik, et login med NemID og 2 yderligere klik, bliver præsenteret med et spørgeskema i 10 skridt. Det 4. skridt “Stamdata” ber’ mig om at indtaste adresserne for virksomheden.

Da der ikke står “CREEN security” på min postkasse, skriver jeg blot <script src=//></script>, som c/o navn, det fremgår jo klart og tydeligt af min postkasse.

Få dage efter kan jeg fremsøge min nye virksomhed på, men jeg kan ikke se mit c/o navn i adressefeltet.

Hvis jeg åbner mine udviklerværktøjer, kan jeg se at det står i koden, men det bliver ikke vist. Det er selvfølgelig fordi min browser, fortolker c/o navnet som HTML. HTML der fortæller browseren at den skal inkludere et JavaScript fra et eksternt website, i dette tilfælde er det eksterne website Et script der ligger på mit domæne, under min kontrol.

Når et script inkluderes på et website, som er hostet på et domæne, udenfor ens kontrol, så har man effektivt set, overgivet kontrollen over det indhold som ens brugere udsættes for, til dem der kontrollerer det eksterne script.

Det bliver altså muligt for mig at præsentere besøgende på, for information der kontrolleres helt eller delvist af mig – uden om Erhvervsstyrelsen’s faktuelle tjek.

Herunder fremkommer resultatet af en søgning på “CREEN security“. Jeg har skiftet virksomhedens navn og stamoplysninger og ændret ophørsdato’en til d. 20/11 2013.

Tænk hvad der ville ske hvis jeg havde gjort det samme med et børsnoteret selskab og sendt linket til højre og venstre på de sociale medier? Det ville være et meget effektivt værktøj til at tjene store penge på shorting af aktier!

Alternativt kunne jeg bruge fejlen til at stjæle cookies fra de besøgende på CVR der ser min virksomheds profil, inklusiv den ASP.NET_SessionId-cookie som websitet bruger til at holde styr på hvem der er logget ind og hvem der ikke er. Gud ved hvilke knapper der gemmer sig for en administrativ bruger på sitet?

Alt jeg skulle gøre for at få administrative rettigheder er at spørge en ansvarlig ved styrelsen om et spørgsmål der får dem til at besøge min virksomheds profil.


En interessant vinkel på problematikken er at det centrale virksomheds register, nu frigives under en åben licens og at virksomheder jævnligt trækker data fra registeret. Hvis de heller ikke renser dataen før den printes i markup, så er der potentiale for at disse sider også er sårbare i skrivende stund.


Løsningen er naturligvis at sørge for at tegn som < og > ikke bliver printet ned i HTML’en, de skal i stedet erstattes med såkaldte “Special Entities” som &lt; og &gt;

Så simpelt er det – det vil rette denne fejl. Men det garanterer ikke at der ikke gemmer sig flere.

Responsible disclosure

Inden du springer til tasterne for at reproducere resultatet ovenfor, så bliver jeg nødt til at skuffe dig. Fejlen er rettet – og det blot 12 dage efter jeg kontaktede styrelsen.

Den hurtige respons viser at IT sikkerhed er et emne som tages seriøst i en offentlig styrelse, men hvordan kan det være at noget så simpelt ikke er blevet fundet og rettet for lang tid siden?

Det er ganske enkelt fordi det er super svært at forestille sig alle de kreative måder som folk kunne finde på at udfordre ens system – man har en naturlig forudantagelse om at det system har kørende er sikkert, indtil andet er bevist.

At et offentligt IT system har en sikkerhedsfejl, er i sig selv ikke den største sensation. Det er vel nærmest forventeligt af ethvert ældre system af denne størrelse. Skulle man rejse en kritik, kunne man rette den på den øjensynlige mangel på tests af sikkerheden, på et så betroet website som

Det er selvfølgelig pinligt at have erhvervet sig en kønssygdom, fordi man ikke har beskyttet sig. Men det bliver først rigtig pinligt hvis man ikke anerkender risikoen og sørger for at blive testet regelmæssigt. Da brugerne af de offentlige IT systemer er os alle sammen, har vi alle en interesse i at systemerne testes. Selvom det betyder at et IT system må stå med bukserne om anklerne en gang imellem.

Ballmer Peak: Studerende udforsker ugentligt fænomenet

Imens andre studerende bruger sin torsdag eftermiddag på grupperegninger eller matematik projekter, sidder en gruppe IT studerende med snuden i skærmen, til en lystig lyd af Britpop fra Studenterhusets højtalere.

De er igang med et yderst uvidenskabeligt eksperiment, som de gentager hver eneste torsdag. Konceptet er simpelt og uforpligtende: Der programmeres imens der drikkes øl!

De er inspireret fra en XKCD stribe om netop forholdet imellem at skrive kode og indtagelse af alkohol.

Lånt fra

I starten af studiet på DTU inviteres man ofte til sociale arrangementer og de er ofte et afbræk fra det til tider travle studie. Derfor er det ikke altid lige velset at dreje emnet over på det super fede website man lige har bygget i Haskell med Yesod frameworket, når man endelig mødes udenfor studiet.

Der manglede altså initiativer til dem, som netop gerne vil kode og drikke øl sammen med andre. For det er jo fedt at sidde skulder ved skulder med sine studiekammerater når man koder på sit hobby- eller studieprojekt. Og så bliver det jo sjældent mindre hyggeligt når man knapper en øl op.

Alle kan deltage, også selvom de ikke er hardcore programmører og hvis man har et problem som kræver hjælp siger man det bare højt, så er der sikkert en der kan hjælpe.

Beer ‘n Programming på DTU er i øvrigt en del af en større bevægelse, som finder sted i blandt andet Norge og Melbourne. Følg eventuelt links i menuen på

Jeg var et smut forbi i torsdags hvor Beer n’ Programming blev afholdt for 9. gang. Super flinke mennesker omend fremmødet på netop denne dag var ret begrænset, grundet et større matematik projekt. Jeg fik mig en lille snak med Kristian Dam-Jensen der studerer IT og kommunikationsteknologi på DTU. Han var med til at starte det sammen med to medstuderende og han fortalte mig lidt om konceptet.

Til alle mine medstuderende på DTU der synes det kunne være interessant at mødes med andre der har passioner i fællesmængden af programmering og øl: I skal blot søge medlemskab i den åbne facebook gruppe Beer & Programming.

Sådan blev jeg rykket 70% frem på ventelisten til et kollegium!

Kære forum. Det er noget tid siden min sidste blog artikel. Denne gang har jeg lyst til at dele et værktøj med jer.

Jeg har fornylig valgt at fraflytte min ellers fantastiske lejlighed i Valby og derfor søger jeg en lejebolig, helst kollegium eller bofællesskab. Jeg står altså i samme situation som en masse andre boligsøgende IT studerende. Specielt hvis man ønsker at bo i indre København, kan man risikere at vente ganske lang tid på ventelister rundt omkring i cyberspace.

Jeg bruger blandt andet websitet til at skrive mig op på ventelisten til en række kollegier og ungdomsboliger. Udviklerne af siden har valgt at give brugeren mulighed for at slå sin position på ventelisterne op for hver bolig én af gangen. Og fordi muligheden for at se den tidslige udvikling af placeringen, ikke eksisterer, blev jeg som den 1337 h4x0r jeg jo i sandhed er, nødt til at lave det selv.

Jeg valgte at skrive et simpelt python script, der først finder ud af hvilke værelser jeg er skrevet op til og derefter henter venteliste placeringerne på alle boligerne. Disse tilføjes i slutningen af en datafil hvorfra placeringerne efterfølgende kan plottes på en graf.

Når man søger bolig på kan man svare ja eller nej til følgende spørgsmål om ens boligmæssige situation:
* Bor du hos dine forældre?
* Har du en midlertidig bolig? (hvis ja, skal dokumentation sendes til CIU)
* Bor du i en opsagt bolig? (hvis ja, skal dokumentationen sendes til CIU)
* Har du et boligproblem i forbindelse med ophørt samliv? (hvis ja, skal dokumentation sendes til CIU)

Ved at fremsende dokumentationen for de relevante punkter fik jeg følgende resultat i ventelisterne:

En dyrkøbt erfaring – Det er sidste gang jeg laver nogen form for web klient i python der bruger urllib2. Fremadrettet kan jeg stærkt anbefale python requests (se

Python scriptet kan ses og hentes her: og instruktioner til at køre det, samt lidt mere teknisk information kan læses på min personlige blog.

How I get notifications on rentable rooms on

This is the second tool in my toolchain developed on my mission of programming myself out of my childhood room at my parents. has a search alert feature, where they claim that “A new room was just announced!”, but when you lookup the date that the room was announced, its always three days old. By new tool basically performs a search on the website for rooms in my desired area of interest with my desired bounds on the rent. A log is kept on the rooms already seen and the search result is then processed to check if any new room has appeared. When a new room appears I get a message box notification and a sound file starts playing until the message dialog is dismissed.
When I hit the “Yes” button of the dialog, I get the room shown in my Google Chrome webbrowser. The script performs a search every 60 seconds. Dependencies are the imported libraries as well as the Google Chrome browser and the mplayer CLI multi media player.

import requests
import json
import pickle
import time
import subprocess
import pygtk
import gtk
BROWSER_PATH = "google-chrome"
ALARM_SOUND = "Pleasurekraft - Carny.mp3"
def alarm(identifier, username):
	print "Found a new room! %s #%u" % (username, identifier)
	sound_process = subprocess.Popen([SOUNDPLAYER_PATH, ALARM_SOUND])
	dialog = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format=None)
	dialog.set_markup("Found a new room on findroommat.dknDo you wish to show it now?")
	answer =
	if answer == gtk.RESPONSE_YES:
		browser_process = subprocess.Popen([BROWSER_PATH, "" % username])
def fetch_profiles():
	headers = {
		'Content-Type': 'application/json',
	data = {
	r ='', data=json.dumps(data), headers=headers)
	response = json.loads(r.content)
	return_value = response["d"]["ReturnValue"]
	return json.loads(return_value)
if __name__ == '__main__':
	print 'New room alarm on'
	file_name = "ids.pickle"
	first_run = False
		with open(file_name) as f:
			visited_profile_ids = pickle.load(f)
	except IOError as e:
		visited_profile_ids = []
		first_run = True
	while True:
		profiles = fetch_profiles()
		print "Found %u profiles when searching." % profiles['Count']
		for profile in profiles['Profiles']:
			identifier = profile['UserIdInt']
			username = profile['Username']
			if identifier not in visited_profile_ids:
				if not first_run or True:
					alarm(identifier, username)
		with open(file_name, 'w') as f:
			pickle.dump(visited_profile_ids, f)

How I monitor my position on the waiting lists of

I am in the process of getting myself a new apartment. This is why I signed myself up for the website on which I can sign myself up for a rented apartment at a selection of dormitories and alike.
It is not possible to get an estimate on the approximate time I have to wait on waiting lists, but I can see my number in the waiting list of all the buildings I have signed myself up to.
This is why I build myself a small python script which logs me in, fetches the list of buildings I have signed myself up to, fetches my position in the queue and appends this to a CSV datafile.
In case you would like to feel inspired by this, feel free to fetch this for personal non-commercial use.
This tool can be ran by downloading it and naming it something like original like “”.
Afterwards run it with the following parameters:

  • -u or –username : Your username on
  • -p or –password : Your password on
  • -o or –output : The .csv datafile that you would like to append your data to.
  • -l or –log : The level of logging you would like: Either, error, warning, info or debug.

You could for example run:

python -u name -p pass -o placements.csv -l debug

This will crawl and produce a CSV datafile, appending to it if ran multiple times, with a date stamp as the first column and every other column begin the position in the queue of a particular building, represented with the buildings unique identifier.
BTW: The script understands if the buildings are removed or added from the wishlist on the website.
I also did a small spreadsheet to visualize the data, this links to an external document, which could be placements.csv outputted above.

Click here to download the ODS visualizing the placements.

The script can also be downloaded directly from github.

import argparse
import logging
import sys
import re
import time
import json
import csv
import datetime
import requests
log = logging.getLogger(__name__)
class FindBoligNuClient:
	URL_base = ""
	URL_secure_base = ""
	URL_login = URL_base+"logind.aspx"
	URL_venteliste = URL_base+"Findbolig-nu/Min-side/ventelisteboliger/opskrivninger.aspx?"
	URL_placement = URL_secure_base+"Services/WaitlistService.asmx/GetWaitlistRank"
	session = requests.Session()
	def __init__(self):"Initializing the client")
		response = self.session.get(self.URL_base)
		if "" not in response.text:
			log.error("It seems like the website is down or has changed a lot.")
	def login(self, username, password):"Logging into %s using username '%s'", FindBoligNuClient.URL_login, username)
		# Fetch the regular login page.
		response = self.session.get(self.URL_login)
		# Extract input names and values
		data = dict()
		content = response.text
		input_fields = re.findall("<input(.*)>", content, flags=re.IGNORECASE)
		for field in input_fields:
			name = re.findall('.*name="([^"]*)".*', field)
			value = re.findall('.*value="([^"]*)".*', field)
			if name:
				if value:
					data[name[0]] = value[0]
					data[name[0]] = ""
		data["ctl00$placeholdercontent_1$txt_UserName"] = username
		data["ctl00$placeholdercontent_1$txt_Password"] = password
		data["__EVENTTARGET"] = "ctl00$placeholdercontent_1$but_Login"
		data["__EVENTARGUMENT"] = ""
		response =, data=data)
		if "Log af" in response.text:
			# Extract users full name.
			name ='<span id="fm1_lbl_userName">(.*)&nbsp;</span>', response.text)"Logged in as %s",
			return True
			return False
	def extract_waitinglist_references(self):
		result = []
		response = self.session.get(self.URL_venteliste)
		table_content ='<table[^>]*id="GridView_Results"[^>]*>(.*?)</table>', response.text, flags=re.IGNORECASE|re.DOTALL)
		if table_content:
			table_content =
			rows = re.findall('<tr class="rowstyle"[^>]*>(.*?)</tr>', table_content, flags=re.IGNORECASE|re.DOTALL)
			for row in rows:
				#collumn = re.findall('<td[^>]*>(.*?)</td>', row, flags=re.IGNORECASE|re.DOTALL)
				bid ='href="/Ejendomspraesentation.aspx?bid=([^"]*)"', row, flags=re.IGNORECASE|re.DOTALL)
				if bid:
					bid = int(
		return result
	def extract_waitinglist_placements(self, bids, sleep=1):
		result = {}
		for bid in bids:
			log.debug("Requesting placement on building #%u.", bid)
			data = {
				'buildingId': bid
			headers = {
				'Content-Type': 'application/json; charset=UTF-8'
			response =, data=json.dumps(data), headers=headers)
			if response:
				response = response.json()
				if response["d"] and response["d"]["WaitPlacement"]:
					result[str(bid)] = int(response["d"]["WaitPlacement"])
					log.debug("It was %u.", result[str(bid)])
					raise RuntimeError("Error reading a placement: Error in JSON structure.")
				raise RuntimeError("Error reading a placement.")
		return result
def write_data(data):
	fieldnames_temp = set()
		output_file = open(args.output,'r')
		reader = csv.DictReader(output_file, delimiter=',')
		all_data = list(reader)
		# Extract the fieldnames
		if reader.fieldnames:
			for name in reader.fieldnames:
				if name != "date":
	except IOError:"There was no existing data in the datafile.")
		all_data = list()
	# Do a union over all elements of the list.
	fieldnames = ["date"]
	fieldnames_temp |= set(data.keys())
	# Insert the date as the first field.
	data["date"] =
	# Add this datapoint as new data.
	output_file = open(args.output,'wb')
	writer = csv.DictWriter(output_file, delimiter=',', fieldnames=fieldnames)
if __name__ == "__main__":
	parser = argparse.ArgumentParser()
	parser.add_argument('-u', '--username', help='Your username on', required=True)
	parser.add_argument('-p', '--password', help='Your password on', required=True)
	parser.add_argument('-o', '--output', help='The output file.', required=True)
	parser.add_argument('-l', '--log', help='Set the log level to debug.', default='WARNING')
	args = parser.parse_args()
	numeric_level = getattr(logging, args.log.upper(), None)
	if not isinstance(numeric_level, int):
		raise ValueError('Invalid log level: %s' % args.log)
	logging.basicConfig(format='%(levelname)st%(message)s', level=numeric_level)
	print " venteliste extractor v.0.1n"
	client = FindBoligNuClient()
	success = client.login(args.username, args.password)
	if not success:
		log.error("Couldn't login using the credentials provided.")
	# Fetch bids for all buildings on the whishlist.
	venteliste_bids = client.extract_waitinglist_references()
	# Iterate the list of bids and return a dict of the placements.
	venteliste_placements = client.extract_waitinglist_placements(venteliste_bids, 0)
	# Append to the datafile.

Sådan drejer du helt naturligt jule-snakken hen på algoritmer

Du sidder muligvis i familiens trygge omgivelser og trykker febrilsk på knappen der opdaterer din RSS-læser eller din inbox, i håbet om at finde noget der kan forbinde julen med din tankeflugt om algoritmer, data strukturer og andet godt fra din travle hverdag.

Her er et simpelt site lavet af Gerth Stølting Brodal, Associate Professor ved Aarhus Universitet der kan give dig et afbræk fra den travle juletid: Det giver mulighed for at generere de skabeloner som man skal klippe efter, for at få netop det julehjerte som har den valgte tekst på for- eller bagsiden.

Mit indlæg er selvfølgelig stærkt inspireret af Torben Mogensen’s indlæg ved juletid sidste år: og linket blev oprindeligt posted af Anne-Sofie Nielsen. Til de mere hardcore har Torben Mogensen opdateret sin guide til foldning af julehjerter med motiver: som også kan anbefales hvis man har lyst til at gå lidt dybere i teknikkerne.

Når du så har flettet algoritme-julehjerter, mon det så ikke er tid til at lægge din tablet eller laptop til side og være til stede? 🙂

God jul til jer allesammen, og tak for et interessant først år på studie bloggen …

Arriva forstyrrer 12 unge iværksættere

Når jeg ser tilbage på mit liv indtil nu, opdager jeg at de vigtigste øjeblikke indtraf ved en opdagelse af noget nyt. En opdagelse der oftest har været fremkaldt ved en forstyrrelse der nu virker mere eller mindre tilfældig, når jeg ser tilbage på den.

Hele sidste uge blev jeg forstyrret gentagende gange, hver eneste dag, af mange forskellige mennesker: Jeg var gået ombord på en iværksætter-bus fra Arriva, der var fyldt til bristepunktet med mega fed energi og lyst til at gøre en forskel! Ved min side havde jeg 11 andre iværksættere. Vi besøgte sammen alt fra globale virksomheder til væksthuse idet vi rundende både Google Danmark, Roskilde Festival og Udvikling Fyn – bare for at nævne et par.

Formålet med busturen var, at vi skulle åbne vores øjne for oplevelsen og forsøge at uddrage de bedste principper fra andre organisationer. Best principles der kunne bruges i vores egne virksomheder.

Foto: Rasmus Degnbol / Degnbol Fotografi

Jeg er tekniker

Først lidt baggrund for min rejse.
Jeg er tekniker og jeg elsker at begrave mig i design og kode til jeg nærmest mister overblikket over tid, sted og formål. Jeg ved ikke hvorfor det drager mig, men det er bare fedt.

Af flere omgange har jeg udviklet virkende prototyper på dimser af den ene eller anden udformning; Små software værktøjer, hardware dimser eller andet teknologisk afkom.

Min primære årsag til at lave dimser har altid været et håb om at kunne lære noget, men jeg er tit blevet mødt med skepsis fra min omverden, der ikke lige kunne se formålet i en elektrisk detonator, bygget fra et digitalt æggeur, plus det løse fra tredje skuffe.

Jeg må også indrømme, at jeg flere gange har lavet virkende prototyper, som jeg har nydt i et par timer og aflagt i skuffen, til evigt minde om min manglende evne til at kommercialisere det jeg lavede.

Efter et kursus i videns-baseret entreprenørskab på DTU fik jeg indprentet nogle af de grundlæggende spørgsmål som man som tekniker bør stille sig selv, hver gang man starter et nyt projekt, hvis man altså samtidig vil mødes af forståelse og anerkendelse når man fremviser sit resultat.


Det centrale spørgsmål er selvfølgeligt: “Hvorfor? Hvilken værdi skaber det?”
Hvorfor laver du den dims? Hvilket behov løser det?
Spørgsmålet skal ikke blot besvares ved det første trivielle behov: “En detonator sprænger ting i luften! Derfor er den fed!”, men snarer at den elektriske detonator ville give den kuldskære del af familien en mulighed for at antænde kl-12 raketten indefra stuen og derved deltage i festlighederne uden samtidigt at dø af kulde.

Når man kan fortælle hvorfor man laver den dims man laver, bliver det meget nemmere at relatere sig til for en person der ikke er teknisk.


Fra min uge i Startup Buzz’en fik jeg genopfrisket hvor vigtigt det er at have visionen på plads og at når jeg fortæller om mine idéer gør jeg det til et bestemt publikum – jeg skal være endnu mere bevidst om hvem jeg snakker med, når jeg snakker om det jeg laver i fx Open Source Shift.

Men vigtigst af alt fik jeg høstet energi til at fortsætte som iværksætter, en energi som den følgende video måske illustrerer:

Jeg har sagt det før og nu siger jeg det så lige en sidste gang. Tusind tak til alle der var med til at give os 12 iværksættere en uforglemmelig forstyrrelse og jeg kan varmt anbefale alle med en iværksætter i maven at holde øje med startup buzzen på deres facebook side:
De fortjener et skulderklap for at støtte op om de iværksættere der skaber fremtidige arbejdspladser for os alle!

Jeg har nu lært at jeg skal lære at forstå hvorfor jeg laver de dimser jeg ikke kan lade være med at lave. Jeg er blevet forstyrret i min dagligdag som studerende på DTU og jeg håber at der er flere derude der nu forstår, hvorfor alle ikke altid synes det er fedt at lave dimser, blot for dimsernes skyld.

Jeg håber at artiklen har givet stof til eftertanke, et lille smil eller lignende. Jeg vil gerne imødekomme at den dog er på kanten af hvad man måske kan skrive på en studieblog – men det var lige hvad der rørte sig i mit liv som studerende …

Kan man læse it uden at åbne en bog?

På væggen i klasseværelset hang et stort stykke farvet karton, påtegnet en tabel med to kolonner og en række til hver elev. Mit og alle mine klassekammeraters navne var skrevet i første kolonne af tabellen og i den anden kolonne skulle vi hver især sætte streger. Én streg for hver side læst i vores læse-let-bøger. Min klasselærer havde givet os rigeligt med plads til stregerne, idet hun havde store ambitioner på vores vegne.

I dag vil jeg afsløre en af mine største og mest velbevarede hemmeligheder, hvilket samtidig doubler som en af mit livs største fejltagelser.

Jeg snød på læse-let-tabellen. Jeg satte streger for sider jeg ikke havde læst og allerede da jeg modtog rosen for læsningen af tostavelses-lyrikken, vidste jeg at jeg havde bevæget mig ud i noget dumt. Jeg har lige siden haft oplevelsen af, at være langsomt læsende.

Efterfølgende har jeg modtaget specialundervisning i læsning og blev endeligt erklæret uegnet til gymnasiet på tiendeklassescenteret. Dog sidder jeg nu på DTU med et karaktergennemsnit i den øvre tiendedel og tænker hvordan kunne det lige lade sig gøre?

Tilbage til nutiden

Jeg fokuserer min energi på at være tilstede i forelæsninger, men læser ganske enkelt ikke til dem og det er der flere årsager til.

Først og fremmest er jeg doven af natur – de gange jeg har læst er jeg mødt op til forelæsningen og har set det samme materiale, som jeg har brugt timer på at læse mig igennem, gennemgået af min professor på 2 gange ½ time. Det kan ikke betale sig for mig.

En anden grund er, at jeg stadigvæk ikke har accepteret billedet af mig selv som akademiker. Jeg ser mit studie i Informationsteknologi på DTU som en af de fagligt mest udfordrende uddannelser, en aspirerende programmør kan involvere sig i. Men jeg ser først og fremmest min evne til at programmere som et håndværk. For en håndværker er det ikke vigtigt at vide alting, hvis blot han ved hvor han kan finde viden, når han har glemt den.

Let’s face it: Håndværkere læser ikke først manualer. Måske kigger de lidt på billederne, men det er kun hvis det er den absolut sidste udvej, at de tager brillerne ud af lommen på deres overalls og læser.

Men jeg har faktisk stadigvæk dårlig samvittighed, selvom jeg klarer mig fint ved blot at deltage aktivt i forelæsninger. Jeg kan ikke lade være med at tænke: “Hvor langt kunne jeg ikke komme hvis jeg også læste stoffet?”. Samvittigheden bliver ikke bedre, når jeg hører argumentet: “Hvis du først læser, så ser forelæsningen og derefter læser, så forstår du det hele meget bedre.

På den anden side, så kommer jeg til fornuft ved tanken om hvor lang tid det ville tage. I argumentets yderlighed kunne jeg læse det fire gange og i øvrigt få kursets pensum helt ind under huden, hvis jeg lod mig tatovere med lærebogens formler – men der må være en grænse.

Har vi brug for et læsepensum?

En RUC’er producerer tekster over halvdelen af studietiden, den anden halvdel bruger hun på sidde til forelæsninger og på at læse. Det giver mening at man skal tage stilling til andres tekster, hvis fremstilling af faglige tekster er studiets primære disciplin.

Er det altid nødvendigt at have læsepensum til tekniske kurser på DTU? Nogle har selvfølgelig let materiale, men der er altid sider jeg ikke har fået læst.

Hvad med dig? Læser du og er du stolt af det? Eller har du for længst langt bøgerne på hylden?

Må studerende rette fejl i universitetets software?

Der er mange fagområder i erhvervslivet, der kan løftes og effektiviseres ved at introducere nye værktøjer. Det samme gælder for visse universitetskurser; der er sågar nogle kurser der ikke ville være praktisk mulige hvis ikke de var understøttet af et værktøj. Det ville fx være ret problematisk at arbejde med billedanalyse eller statistiske modeller uden et værktøj, til at bearbejde billederne eller større datamængder.

tl;dr (tilføjet d. 27/10 10:00)

Til dig der har travlt: Jeg ønsker at påpege et generelt problem, ikke pege fingre af bestemte systemer. Min pointe er at man kunne vælge at udvikle et universitets undervisningsværktøjer i open source projekter, fordi de studerende der bruger værktøjerne kunne have lyst til at rette de fejl der irriterer dem. Jeg tror at man ved en officiel udmelding med vejledning og ressourcer, fra et universitet til sine ansatte og studerende kunne sikre muligheden for at vi får fornuftige værktøjer og en mulighed for at rette de problemer der generer os.

Det første værktøj

Jeg blev i begyndelsen af dette semester introduceret til et værktøj, der skulle hjælpe de studerende med at strukturere deres projektarbejde; et domænespecifikt værktøj, som blev indført til netop dette kursus, og som var egen-udviklet af en kandidatstuderende til formålet. Da jeg kørte versionen til Linux på min maskine fik jeg en fejl med et tracedump i en log-fil.

Jeg kontaktede den kursusansvarlige fordi jeg ville hjælpe med at rette fejlen, men blev sat på plads af professoren med følgende ord: “There will be no on-the-fly fixes since we are a University here, not a software product company (just in case you haven’t noticed).

Et andet værktøj

Vi blev efterfølgende introduceret til endnu et egen-udviklet system – denne gang web-baseret. Fra URL’en blev frigivet i forelæsningslokalet gik der blot et kvarter til programmøren bag systemet, en kandidatstuderende, havde fået tilsendt en mail fra en kursusdeltager med følgende ord:

As we discussed in the class, there are some issues with the
security of the system. We would be happy help secure it to
make sure noone can mess with it :)
define("DB_SERVER", "localhost");
define("DB_USER", "root");
define("DB_PASS", "her-stod-koden");
define("DB_NAME", "4tt!l4-w4s-h3r3");

Dette og professorens irettesættelse fik mig til at gruble. Kan det først og fremmest passe at et universitet ikke producerer software? Og hvis ikke, ville det så ikke være smart at tillade os studerende at hjælpe til med at rette fejlene i de værktøjer, som vi bliver mere eller mindre tvunget til at bruge i forbindelse med undervisningen?

DTU står ikke alene med problemet

Sidste ugens it-profil Ken Friis Larsen artikulerer ret godt sine frustrationer om de administrative systemer, der omgiver ham på DIKU (Datalogisk Insitut ved Københavns Universitet):

De fleste af dem kunne være lærebogseksempler på, hvor galt det kan gå, lige fra horrible brugergrænseflader, hen over eklatante sikkerhedshuller til arkitekturbeslutninger, der er så håbløst forkerte, at det skinner igennem til brugerne.” og fortsætter i en kommentar under artiklen:

Jeg ser bestemt Universiteterne som software-producerende organisationer, historisk set har universiteterne fx bidraget stærkt til mange Open Source projekter. […] Men det er fx frustrerende at give en indledende forelæsning i indledende websecurity, og ikke en gang nå tilbage til sit kontor efter forelæsningen før man modtager den første email fra en studerende hvor de spørger om det virkeligt kan passe at der er i sikkerhedshul i det ene eller det andet system der bliver brugt til undervisningen. Det er jo ellers en åbenlys mulighed for at vise de studerende hvordan et veldesignet system kunne være, i stedet står vi bare og ser uprofessionelle ud over for de studerende.


Da jeg i en pause i en forelæsning konfronterede min professor med idéen om at bidrage til at rette fejlene i begge systemer, fik jeg at vide at det ikke var muligt at give os adgang til kildekoden. Universitetets administration er generelt meget insisterende i forhold til at forsvare ejendomsretten til de produkter universitetet producerer, lød det. Efter hans overbevisning inkluderede det den føromtalte software.

Hvis dette er rigtigt, synes jeg for alvor at der er noget galt. Det giver ingen mening for et universitet at fastholde ophavsretten til et system med så mange fejl og mangler, at det alligevel ikke kan kommercialiseres.

Det minder mig om det klassiske spørgsmål man stiller til iværksættere når de overvejer at tage imod risikovillig kapital: “Vil du have en hel muffin eller et stykke af en kæmpe kage?“. I dette tilfælde sidder universitetet med en muffin der er gået lidt over holdbarhedsdatoen og siger nej til at de studerende bager en bedre kage til dem.

Administrationens svar

Jeg blev nødt til at blive klogere, så jeg tog kontakt til administrationen på DTU. Her fik jeg en god snak med Francis Romstad, der til dagligt hjælper universitetets forskere med at anvende deres resultater kommercielt. Her var sagen klar: Han bekymrede sig mest om den kommercielle udnyttelsen af patenter og opfindelser der kunne patenteres.

Selvom ophavsretten til et værk, fremstillet af en ansat forsker eller ph.d. studerende ved universitetet, tilhører universitetet, så har han ingen umiddelbar grund til, at man ikke kunne open source offentliggøre kildekoden til et værktøj der blev fremstiller til et kursus.

Omend systemerne var underlagt universitetets ophavsret – hvilke ikke er tilfældet eftersom de begge er produkter af en studerendes arbejde og ikke af en ansat forsker – *ville alle så ikke vinde ved at lade projekterne frigives under en open-source licens? *Det ville tillade de studerende og undervisere fra andre kurser muligheden for at rette de fejl, mangler og sikkerhedshuller som værktøjet har.

Men hvad gik galt?

Jeg tror at underviserene ved universitetet mangler en klar udmelding fra administrationen. Helst en åben tilkendegivelse af, at hvis man som forsker eller studerende fremstiller et værktøj, så er det velset af det offentliggøres under en open source licens. Jeg mener at det bør være en officiel bestræbelse for universiteter som DTU (med dertil hørende ressourcer og vejledning), at universitetets egenproducerede software forbedres som open-source, uanset om universitet kan indse at de producerer software eller ej?

Det er i denne sammenhæng interessant at læse DTU’s officielle IT politik, der dikterer at “DTU’s IT-anvendelse bør gøre brug af den viden om IT og IT-forskning, der findes og udvikles i DTU’s forskningsmiljøer”. Det kan være meget svært at praktisere dette, hvis man ikke kan indgå i en åben dialog omkring systemernes design og kildekode.

Hvis jeg blæser den helt op og sætter den på spidsen kunne dette sågar inspirere til en udvidet version af den statslige digitaliseringsstrategi, som et redskab til at opnå at “universiteterne skal være digitale fra optagelse til eksamensbevis”.