
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.
360° Communication
I can feel and read the room and translate C-level visions into budgets and projects and customer requirements into working implementations – and I can translate tech talk and jargon into language that non-technical people can understand.
Platform Development, Integration and Automation
I understand complex IT systems, their architecture, and how their components communicate.
During my time working in commercial satellite communications, I have repeatedly proven that I can build custom solutions that enable otherwise incompatible systems to communicate with each other.
Network Weather Maps, Monitoring, Alerting and Automation, including triggering scripts for self-healing actions, have been my bread & butter for over a decade.
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).
Trainings

I can explain deeply technical topics to non-technical people so they will understand the subject and won’t feel stupid or patronized while attending my training sessions.
I have experience giving
-
- Programming (Lua, Basic dialects, Xbase++),
- System Integration (OPC Classic & UA, MQTT, ODBC, Custom Scripting and Data transformation) and
- TCP/IPv4 Networking (including DNS, BGP, OSPF, SNMP, Graphing & Monitoring)
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 to 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.

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.

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.


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

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
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.)

