IT

(The Russian Space Shuttle Buran on her way to the Technikmuseum Speyer. Picture taken on the rooftop of the United Nations tower in Bonn, Germany.)

Sic parvis magna

I’m blessed that I started using computers at a very young age and in a time where home computers had just arrived and only had one kilobyte of RAM. That allowed me to be part of the PC revolution from the start.

I know what’s happening underneath the graphical user interfaces and how machines communicate with each other over a global network.

I have commercially and professionally used multiple programming languages in my life and as far as operating systems are concerned, I am platform agnostic. I use a combination of tools that get the job done and that won’t break the bank.

Networking, Systems and Infrastructure

I used to be a certified Mikrotik Certified Network Associate (MTCNA) and a Microsoft Certified Professional (MCP) for Windows Server.

Such certificates are “time-bombed” and expire after three years or so, which is a nice business model to get the customers to pay for the exact same certification again and again and again.

When I was still in commercial satellite communications, I worked on a daily basis with:

    • Cisco IOS,
    • Mikrotik RouterOS,
    • Juniper Junos OS,
    • Ubuntu Linux,
    • Windows Server,
    • VMware vSphere and ESXi,
    • ProxMox VE,
    • PowerEdge Servers,
    • EqualLogic Storage Arrays,
    • iSCSI and NFS,
    • TCP/IPv4,
    • Subnetting and Supernetting,
    • Switching,
    • Static Routing,
    • BGP and OSPF,
    • BIND9 DNS servers,
    • CACTI and PHP Network Weathermaps (Graphing),
    • WhatsUp Gold (Monitoring, Alerting, Triggering of Actions and Automation Scripts).

I have also given TCP/IPv4 trainings.

Programming

I wrote my first line of code in 1982 on a Casio PB100 in BASIC.

I wrote a book on natural language parser programming in Pascal for interactive fiction games in the year I finished the Gymnasium/High School, 1989/90. I also had a version of that parser written in PowerBASIC. It could understand rather complex German and English sentences.

I have learned COBOL, JCL and DB2 SQL on an actual IBM mainframe.

I have worked for the company and with the team that created the Xbase++ programming language.

Since Xbase++, I know how multi-threading works.

In a previous job, I used Lua on a daily basis and also gave Lua trainings.

Programming, query and domain specific languages that I’ve learned (most of them self-taught) and used in my career:

    • BASIC: Too many dialects too count, from the ZX81 over the Apple ][ to PowerBasic to modern multi-threaded, object-oriented dialects like BlitzMax,
    • 6502 Assembler,
    • UCSD Pascal, Turbo Pascal, object-oriented Borland Pascal,
    • C and C++,
    • COBOL,
    • JCL,
    • DB2 and MySQL SQL,
    • HTML,
    • Xbase++,
    • Flash/Actionscript,
    • C#,
    • Python,
    • Go,
    • Lua.

Ancient history

One of my first tasks at Alaska Software was to write a parser that extracted all code samples from the documentation and checked if they could compile properly. This led to a second project, the Sample Inspector, that provided a GUI interface to a library of useful code samples – an extension to the technical documentation of the product.

The Sample Inspector during early development.

Later, I also implemented client-side parts of the NNTP protocol for a News Reader GUI client that I had written in Xbase++ (as a pet project) – it was later shipped under the name Baumbart.

Baumbart 1.0. Oh, the nostalgia.

In another pet project, I had implemented the IRC protocol to write an Internet Relay Chat bot that also included a very basic natural language parser, so it could interact with human users. It was called Xenia B, but it as never released or shipped with the product.

The bot connecting to an IRC server.
The bot acting as an interactive fiction game for its users.

During my work on the Alaska ADSDBE reference documentation, I also wrote a GUI management interface for the Advantage Database Server.

ADSDBE Management Console.

Archeological Dig Site

Most of the code that I have written is owned by my previous employers and I no longer have access to any of that work.

The downloads below were hobby projects of mine which I have abandoned in the meanwhile and they come with no warranty or support whatsoever. Follow the instructions (if there are any), respect the licenses and hopefully you will have some fun with the stuff or find some use for it.

BlitzMax thread class module

A thread class for BlitzMax.

This BlitzMax module contains an (abstract) class for OOP-style multithreading and multi-threading/multi-processing related helper functions. Since I’ve given up on BlitzMax and the language’s creator has also abandoned it, there won’t be any further development of this module. (BSD license.)

GUICoffee

The following sample code is a remake of the old Alaska Software Xbase++ ‘coffee’ sample application. I haven’t used Xbase++ in quite a few years now, so I had to rewrite it based upon what I could remember of the coffee sample. Basically, it is about ten programmers who drink coffee while they are working and when their cups run empty, they go to a coffee machine and get themselves a refill. When the coffee machine runs empty, too, the guy who needs coffee has to cook some fresh one first. I’ve added to this simple scenario a button that will ‘close the office’ for the day and send the developers home. Before they do that, they finish their coffees and return their cups. The last one to do so turns off the coffee machine.

This idea is implemented using ten worker threads, one for each developer. They share one resource, namely the coffee machine. The purpose of the sample is to demonstrate mutexes as a means of synchronizing access to shared resources by concurrently running threads. As you probably already know, not synchronizing the access to shared resources is a perfect way to crash your application and giving you a hell of time to find the bug.

Here is the code, written on OS X, but it also works on Windows:

'GUI Coffee, Inc.
SuperStrict

'Put something on the screen.

Import MaxGui.Drivers
Import MaxGui.CocoaMaxGui
Import Pub.Threads
Import BRL.Random
Import BRL.Event
Import BRL.Eventqueue

AppTitle = "Coffee, Inc."

Global x:Int = 0
Global y:Int = 0
Global width:Int = 640
Global height:Int = 480

Global AppWindow:TGadget = CreateWindow (AppTitle, x, y, width, height)

Global fileMenu:TGadget = CreateMenu ("&File", 0, WindowMenu (AppWindow))
Global xit:TGadget = CreateMenu ("E&xit", 1, fileMenu)

Global helpMenu:TGadget = CreateMenu ("&Help", 2, WindowMenu (AppWindow))
Global about:TGadget = CreateMenu ("&About...", 3, helpMenu)

UpdateWindowMenu AppWindow

Global devStatus:TGadget[10]

For Local n:Int = 0 To 9
	devStatus[n] = CreateTextField (4, 4 + n*30, ClientWidth (AppWindow) - 8, 24, AppWindow)
Next

Global goHome:TGadget = CreateButton ("Go home, guys!", 240, 400, 140, 24, AppWindow, BUTTON_OK)

'Setup the office environment.

Const cupSize:Int = 200

'Your simple Italian coffee machine. One load is good for eight cups.
Type CoffeeMachine

	Field hasCups:Int = 10
	Field hasCoffee:Int
	Field isCooking:Int
	Field myMutex:Int

	Method Create()
		hasCoffee = 0
		myMutex = CreateMutex()
	End Method

	Method giveCoffee:Int( name: String, nPos:Int )
		LockMutex( myMutex )
		If hasCoffee <= 0
			Local boiler:String = ""
			For Local n:Int = 1 To 8
				boiler :+ "+++"
				SetGadgetText( devStatus[nPos], name + " is cooking fresh coffee: " + boiler )
				Delay 300
			Next
			hasCoffee = 8 * cupSize
		End If
		SetGadgetText( devStatus[nPos], name + " takes coffee." )
		hasCoffee :- cupSize
		Delay 750
		UnlockMutex( myMutex )
		Return cupSize
	End Method

	Method giveCup( name: String, nPos:Int )
		LockMutex( myMutex )
		SetGadgetText( devStatus[nPos], name + " takes a cup.")
		hasCups :- 1
		Delay 400
		UnlockMutex( myMutex )
	End Method		

	Method returnCup( name: String, nPos:Int )
		LockMutex( myMutex )
		SetGadgetText( devStatus[nPos], name + " returns his cup to the kitchen.")
		hasCups :+ 1
		Delay 1000
		If hasCups = 10
			SetGadgetText( devStatus[nPos], name + " is last, he turns off the coffee machine.")
			Delay 3000
			HideGadget( goHome )
		End If
		UnlockMutex( myMutex )
	End Method

End Type

'A very simple software developer. He only works as long as he has coffee.
Type Developer
	Field Name:String
	Field Position:Int
	Field hasCoffee:Int
	Field machine:CoffeeMachine
	Global EOB:Int = False

	Method Create:Developer( name:String, pos:Int, machine:CoffeeMachine )
		Self.Name = name
		Self.Position = pos
		Self.hasCoffee = 0
		Self.machine = machine
		Return Self
	End Method

	Function SignalEOB()
		SetGadgetText( goHome, "Office is closing!" )
		DisableGadget( goHome )
		EOB = True
	End Function

	Method Working()
		machine.giveCup( name, Position )
		Repeat
			hasCoffee :- Rand(1, Int(cupSize/4) )
			If hasCoffee <= 0
				SetGadgetText( devStatus[Position], name + " needs coffee !!!")
				hasCoffee = machine.GiveCoffee( name, Position )
			Else
				Local cupContents:String = ""
				For Local n:Int = 1 To Int( 1 + hasCoffee/10)
					cupContents :+ "#"
				Next
				SetGadgetText( devStatus[Position], name + " is happily working. Coffee left: " + cupContents + " ( " + hasCoffee + " ml)." )
			End If
			Delay 600
		Until EOB
		machine.returnCup( name, Position )
		SetGadgetText( devStatus[Position], name + " went home.")
	End Method
End Type

'The thread factory
Function BuildThread:Object( data:Object)
	Local myDev:Developer = Developer(data)
	myDev.Working()
End Function

'Start the coffee machine
Global Luigi:CoffeeMachine = New CoffeeMachine
Luigi.Create()

'Get the guys to work
Global DevTeam:Developer[10]
Global devName:String[] = [ "Mark", ..
"Brucey", ..
"Skidracer", ..
"SebHoll", ..
"SimonH", ..
"SimonA", ..
"FlameDuck", ..
"MarkT", ..
"RobH", ..
"Woz"]

For Local n:Int = 0 To 9
	DevTeam[n] = New Developer
	DevTeam[n].Create( devName[n], n, Luigi )
Next

'Ready, steady, go!
Global handles:Int[10]

For Local n:Int = 0 To 9
	handles[n]=CreateThread( BuildThread,  Object(DevTeam[n]) )
Next

'Send the boys home
Function ShutDown()
	Developer.SignalEOB()
	For Local n:Int = 0 To 9
		DetachThread( handles[n] )
	Next
End Function

'Your good old fashioned GUI event loop
Repeat
	Select WaitEvent ()
		Case EVENT_GADGETACTION
			If (EventSource () = goHome)
				ShutDown()
			End If 

		Case EVENT_WINDOWCLOSE
			ShutDown()
			End

		Case EVENT_MENUACTION
			If EventData () = 1 Then
				ShutDown()
				End
			End If

			If EventData () = 3 Then Notify ("Coffee, Inc. only works with coffee!")

	End Select
Forever

Application bundle for Mac OS X/Intel.

Application bundle for Mac OS X/PPC.

Executable for Windows.

Digital Nomad NNTP Server

As mentioned earlier, back at Alaska Software, I had written the first version of an NNTP desktop GUI client called Baumbart. This here is a multi-threaded NNTP/News server written in C#. I wrote it a couple of years ago to get familiar with the C# language. (GPL.)

Digital Nomad for Mono/MySQL
(C# Source Code only, compatible with OS X.)

Digital Nomad for Windows
(Installer bundled with MSDE 2000, Windows only. This was created in Windows XP times and it probably won’t run on current versions of Windows, but I won’t be investing time in this build anymore to fix or update it.)