Blog

  • Neuron Core Wars code…

    So you want to see some crazy shit…?

    This is a neuron-like corewars set of code I wrote back in 2006…

    From the readme.txt:

    This is a collection of "neuron-like" corewars code.
    Whilst the signals being passed (at least up to v4) are basically pre-programmed actions,
    one could alter this and instead use the neurons to process some input,  
    like a neural network.
    
    
    Although there is no real advantage in corewars to do so.
    
    Perhaps there is a better way to create "artificial intelligence" in corewars.
    
    --
    
    Another way, is using an "evolver" (see simple-evolver) where it takes code from 
    a random location and tries to store and execute it. If it fails, the code is discarded.
    
    --
    
    Another way, is the typical parasite method, which is by forking into random code. But
    this can be easily defeated by the forkbomb.cw code. 
    
    --
    
    The only other way i can think of is, some piece of code like this, with lots of jumps...
    
    addr:		data 0		# this gets randomised (within the boundaries of the code)
    r:		data 0		# just a var
    
    line1: 		some instruction here, e.g. move 0, [r]
    		some instruction here to alter addr, e.g. add 1, addr
    		jump [addr]
    
    line2: 		some instruction here
    		some instruction here to alter addr
    		jump [addr]
    
    line3: 		some instruction here
    		...
    		...
    ...
    
    and so on. 
    
    It then boils down to the "altering addr" method, which can be stored into a table or 
    based on "learning" or "statistics" -- thus improving its code over time, without
    actually changing anything (except the order it's run). 
    
    E.g. you could use an sbox to hold all the addrs of code. Each "jump instruction"
    jumps into a function which then permutates the sbox and returns a new addr accordingly.
    
    The permutation function can then be optimised for a particular scenario.
    
    This is similar to "neuron" with the signal handling/actions. 
    
    --
    
    

    Here’s version 4 of the code:

    # NB: This is complete and working, but there is a race condition with "sendsignal()"
    # and "clone()" which can prevent signals being sent to newly moved neurons (moveneuron)
    # because sendsignal() may be polling on the old location and doesn't know that it has moved.
    # 
    # The only way to fix this is to implement a communications protocol similar to
    # process_protect and process_module.
    #
    # But this code has already reached the limit of 200 instructions, so there is no way
    # to fix this problem.
    # 
    # 
    
    title "AAA - Neuron v4"
    author "---------- DS -----------"
    
    bootthreads: 	data 1				# initial case: minimum 1 more threads
    						# after "first neuron" and its clone...
    						# i.e. total = 3 threads
    
    						# self-signal to create initial neuron
    
    boot:		move 2, signalstatus
    		move 1, signal
    		add 256, signal
    # 		move &bootstrap, jumpback
     		move &bootstrap2, jumpback
    		jump checksignal
    
    
    #bootstrap:	move 1, sendsignaldata			# issue "create neuron" command to last neuron
    #		add 256, sendsignaldata
    #		move nextneuron, sendsignalneuron	# &neuronmarker can be used instead of nextneuron
    #		move &bootstrap1, jumpback		# in non-bootstrap "first neuron" type code.. i.e. with a poll loop
    #		jump sendsignal				# otherwise, in bootstrap code, you need to checksignal()
    							# to get it to work. 
    							# Since we have a cloned neuron already, due to this bootstrap,
    							# we just use it instead.
    
    #bootstrap1:	loop bootthreads, bootstrap
    
    bootstrap2:	move 4, sendsignaldata			# issue new command action, for all neurons
    		add 256, sendsignaldata
    		add 512, sendsignaldata		
    		move nextneuron, sendsignalneuron
    		move &bootstrap3, jumpback
    		jump sendsignal
    
    bootstrap3:	move &bootstrap5, jumpback
    		jump delay
    
    bootstrap5:	move 2, sendsignaldata			# move neurons
    		add 256, sendsignaldata
    		add 512, sendsignaldata
    		move nextneuron, sendsignalneuron
    		move &bootstrap6, jumpback		
    		jump sendsignal
    
    bootstrap6: 	move &bootstrap2, jumpback
    		jump delay
    
    delay:		move 1000, i
    delay2:		loop i, delay2
    		jump [jumpback]
    		
    # ----------- begin neuron here --------------------------------------
    
    	# signals (sent as bit flags):
    	#
    	# (action signals) - you'd want one of these (you can combine these):
    	# 0 = do nothing. 
    	# 1 = create more neurons
    	#
    	# (action signals with special conditions) - or these (don't combine these):
    	# 2 = move this neuron into a new cell
    		# since this moves the current neuron into a new place, you can't combine this.
    	# 4 = move 0, [random] (safe version, does not kill other neurons of same process) 
    		# aborts on receiving another signal
    	# 8 = move 0, [random] (unsafe version)
    		# aborts on receiving another signal
    	# 32 = convert into an imp
    		# neuron transforms into an imp
    	# 64 = terminates
    		# neuron terminates
    	#
    	# (signal handling signals) - and you'd want one of these (at least one of these):
    	# 128 = signal prev neuron with this same signal
    	# 256 = signal next neuron with this same signal
    	# 512 = do action (even if you're not the last neuron to get this signal)
    	#
    	# NB: When you combine the flags, they will be handled in numerical order. 
    	# Special conditions may prevent further flags from being "actioned".
    	# Also, signal propagation occurs FIRST before actions, so you cannot
    	# expect "newly created" neurons to receive a signal until the next signal is sent.
    	# (e.g. This is the only way to prevent signal 1 creating an infinite number of
    	# neurons. Similar problems occur with signal 2.)
    
    # ------------- global variables: the values will not be copied on clone()->linkneuron() -----------------------------------
    
    neuronmarker:		data 1337
    
    # --- public vars ---
    
    signalstatus:		data 0
    signal:			data 0
    
    nextneuron:		data 0
    prevneuron:		data 0
    
    # --- private vars ---
    
    jumpback:		data 0			# jumpback address for various code
    jumpbackclone:		data 0			# jumpback address for clone code (only)
    recvsignal:		data 0			# received signal's value
    sendsignaldata:		data 0			# signal value to be sent
    sendsignalneuron:	data 0			# target address of neuron for sendsignal
    
    s:			data 0			# generic vars -- may be clobbered when entering a new function call.
    r:			data 0
    i:			data 0
    
    # --- constants ---
    
    sizeofvars:		data 12			# size of all variables
    entrypointoffset:	data 15			# entry point offset from &neuronmarker
    
    # ------------ main polling loop --------------------------------
    # Clobbered: jumpback
    
    main:		jump main2
    #		data 0				# if your entrypointoffset is incorrect, it will terminate
    #		data 0				# as soon as it forks into the wrong offset. 
    #		data 0				# (this is only useful for debugging)
    #		data 0				# but this exceeds the "max limit" of 200 instructions.
    #		data 0				# Uncomment as many as you want.
    
    main2: 		move 0, signalstatus		# clear signalstatus
    
    poll:		move &poll, jumpback
    poll1:		equal 2, signalstatus	# poll signalstatus
    		jump checksignal
    		jump poll1
    
    # ------------- Function: checksignal() ---------------------------------
    # Clobbered but restored: jumpback
    # Clobbered: signalstatus
    
    checksignalret:	data 0					# caller's return address
    
    checksignal:	move jumpback, checksignalret		# save caller's return address
    		move signal, recvsignal			# save it into recv signal, and reset signalstatus
    
    checksignal0:	equal 0, recvsignal			# do nothing?
    		jump checksignalend
    
    	# similar to doaction()'s switch-case, but optimised for speed (not code size).
    	# i.e. does not do multiple evaluations but requires more opcodes for control.
    
    checksignal128:	move 128, i				# check 'signal prev' flag
    		and recvsignal, i
    		equal 128, i
    		jump sendsignal128
    		jump checksignal256			# ->--+
    							#     |
    							#     |
    sendsignal128: 	equal prevneuron, 0			# <= if we're the last neuron in this signal chain
    		jump checksignaldo			# <= do the action.
    		move recvsignal, sendsignaldata		#     |
    		move prevneuron, sendsignalneuron	#     |
    		move &checksignal256, jumpback		# ->--|--+
    		jump sendsignal				#     |  |
    							#     |  |
    							#     |  |
    checksignal256:	move 256, i				# <---+--+
    		and recvsignal, i
    		equal 256, i
    		jump sendsignal256
    		jump checksignal512			# ->--+
    							#     |
    sendsignal256: 	equal nextneuron, 0			# <= if we're the last neuron in this signal chain
    		jump checksignaldo			# <= do the action.
    		move recvsignal, sendsignaldata		#     |
    		move nextneuron, sendsignalneuron	#     |
    		move &checksignal512, jumpback		# ->--|--+
    		jump sendsignal				#     |  |
    							#     |  |
    							#     |  |
    checksignal512:	move 512, i				# <---+--+
    		and recvsignal, i
    		equal 512, i
    		jump checksignaldo			# 512 -- do the action anyway.
    		jump checksignalend
    
    checksignaldo:	move &checksignalend2, jumpback
    		jump doaction				# on return, doaction is expected to clear (or set) signalstatus
    
    checksignalend: move 0, signalstatus			# reset signalstatus -- we only passed a signal
    checksignalend2:	move checksignalret, jumpback		# return to caller. 
    		jump [jumpback]
    
    
    # ----------- Function: doaction() --------------------
    # Clobbered but restored: jumpback
    # Clobbered: recvsignal, signalstatus (by action 4 and 8)
    
    doactionret:	data 0					# caller's return address
    
    	# think of the following code like a switch-case statement that operates on a bitflag
    	# it is optimised for code size, not speed. (it saves 1 or 2 jump instructions on each case in the switch-case)
    	# at the expense of re-evaluating the entire switch-case from the beginning.
    
    doaction:	move jumpback, doactionret
    		and 127, recvsignal			# mask only the bits we want...
    
    doactionstart:	move &doactionstart, jumpback		# set this as the jumpback value
    							# because "doaction" will change "recvsignal"
    							# by substracting from recvsignal the action being done.
    							# (this saves some code -- but you cannot do this for "signal handling actions"
    
    		equal 0, recvsignal			# are we done yet?
    		jump doactiondone
    
    		move 1, i			
    		and recvsignal, i
    		equal 1, i
    		jump doaction1
    
    		move 2, i
    		and recvsignal, i
    		equal 2, i
    		jump doaction2
    
    		move 4, i
    		and recvsignal, i
    		equal 4, i
    		jump doaction4
    
    		move 8, i
    		and recvsignal, i
    		equal 8, i
    		jump doaction8
    
    		move 32, i
    		and recvsignal, i
    		equal 32, i
    		jump doaction32
    
    		move 64, i
    		and recvsignal, i
    		equal 64, i
    		jump doaction64
    
    		data 0					# buggy code? undefined action signal
    
    	# -- NB these subroutines of doaction() will return to doaction()'s switch-case statement 
    	# via "jump [jumpback]" and not "return to caller" since that only occurs once (see above).
    
    # --- Action 1: Create more neurons
    
    doaction1:	add -1, recvsignal			# substract from recvsignal, so this action isn't repeated again.
    		move &linkneurons, jumpbackclone	# make clone() fork and link the neurons
    		jump clone				# jumpback is already set by doaction()
    
    # --- Action 2: Move neuron.
    
    doaction2:	add -2, recvsignal
    		move &moveneuron, jumpbackclone		# no need to set jumpback
    		jump clone
    
    # --- Action 4: move 0, [random] (safe version)
    
    doaction4:	move 0, signalstatus			# reset signalstatus here.
    doaction4p1: 	equal 2, signalstatus			# check signalstatus -- if this changes, we stop action4
    		jump stopaction4
    doaction4p2:	info 2, r
    		own [r]
    		jump doaction4p2
    		move 0, [r]
    		jump doaction4p1
    stopaction4:	jump doactiondone2			# return, but don't reset signalstatus
    
    # --- Action 8: move 0, [random] (unsafe, faster)
    
    doaction8:	move 0, signalstatus			# reset signalstatus here.
    doaction8p1: 	equal 2, signalstatus			# check signalstatus -- if this changes, we stop action8
    		jump stopaction8
    		info 2, r
    		move 0, [r]
    		jump doaction8p1
    stopaction8:	jump doactiondone2			# return, but don't reset signalstatus
    
    # --- Action 32: Convert into an imp
    
    doaction32:	move doaction32, imp			# no need for jump [jumpback]
    imp:		data 0
    
    # --- Action 64: Terminate neuron
     
    doaction64:	data 0					# no need for jump [jumpback]
    
    # --- Done?
    
    doactiondone:	move 0, signalstatus			# reset signalstatus.
    doactiondone2:	move doactionret, jumpback
    		jump [jumpback]				# return to caller
    
    # ----------- Function: sendsignal() -------------------------------------------
    # Clobbered: None.
    
    sendsignal:	equal 1337, [sendsignalneuron]		# check target is a valid neuron by testing beginmarker
    		jump sendsignal2
    
    		data 0					# buggy code? terminate
    
    sendsignal2:	move sendsignalneuron, r
    		add 1, r				# set r to point to "signalstatus"
    
    sendsignal3:	equal 0, [r]				# simplified version.
    		jump sendsignal4
    		jump sendsignal3	
    
    sendsignal4:	move 1, [r]				# lock signalstatus
    		move r, i
    		add 1, i				# set i to point to "signal"
    		move sendsignaldata, [i]		# send signal
    		move 2, [r]				# update signalstatus to completed
    
    sendsignalend:	jump [jumpback]				# return to caller.
    
    # ----------- Function: clone() ------------------------------------------
    # Clobbered: None. (Also see polymorphic functions.)
    
    # NB: "jumpbackclone" is a polymorphic function descriptor (i.e. function pointer or subclass method)
    # which changes the behaviour of the clone code
    
    clone:		info 2, r
    		own [r]					# check if 'r' overwrites into another neuron.
    		jump clone
    
    		move &neuronmarker, s			# grab length of neuron (i could hardcode this, but i dont want to)
    		neg s, i
    		add &endvar, i
    		add 1, i
    		move r, endvar				# save 'r'
    
    		add i, r				# check if 'r + len' overwrites into another neuron.
    		own [r]
    		jump clone
    
    		move endvar, r				# restore 'r'
    
    copy:		movei s, r
    		loop i, copy
    
    		move 1337, [endvar]			# set neuron marker
    
    		jump [jumpbackclone]			# jump to the polymorphic function -- either moveneuron() or linkneurons()
    
    # --- Polymorphic jumpbackclone function: linkneurons() ---
    # Clobbered: nextneuron
    
    linkneurons:	equal 0, nextneuron
    		jump linkneurons1
    
    		data 0					# buggy code? terminate
    
    linkneurons1:	move endvar, r				# zero the bss
    		add 1, r				# (1st var location)
    		move sizeofvars, i			# (number of vars)
    zerobss:	move 0, [r]				
    		add 1, r
    		loop i, zerobss
    
    		move endvar, nextneuron			# set our "nextneuron" to point to the clone
    
    		move endvar, r
    		add 4, r
    		move &neuronmarker, [r]			# set "prevneuron" in the cloned neuron to us.
    
    		add entrypointoffset, endvar		# readjust endvar to entry point of cloned neuron
    		fork [endvar]				# fork
    
    		jump [jumpback]				# return to caller
    
    # --- Polymorphic jumpbackclone function: moveneuron() ---
    
    moveneuron:	move prevneuron, r
    		add 3, r
    		move endvar, [r]			# set previous neuron's "next neuron" to new address
    
    		move nextneuron, r
    		add 4, r
    		move endvar, [r]			# set next neuron's "prev neuron" to new address
    
    		add entrypointoffset, endvar		# this is just a clone_move() operation, so re-adjust entrypoint
    		jump [endvar]				# and only jump (don't fork)
    
    # ------------------------------------------------------------------------------------
    
    endvar:			data 0			# end variable -- used to mark end of neuron -- only to be used by clone().
    
    	# data/code below is NOT used -- just to look nice in the gui -- only first neuron has this.
    
    neuronendmarker:	move &neuronendmarker, neuronendmarker1		
    neuronendmarker1:	data 0						
    
  • Corewars program…

    The following corewars program is a statistically optimal program, which attacks a midpoint of a program, given the number of programs, coresize, average program size, and then their standard deviation. It’s just using pre-defined numbers, generated from a shell script…

    r: data 0
    
    coresize / nprogs = 273
    
    avg prog size: 35.65
    
    std dev: 31.49
    
    thus, desired search points:
    
    [ |1dev| (midpoint) |1dev| ]
    
    make next midpoint here: ---------------------> ^^^^^^
    
    midpoint = interval / 2 = 136
    
    main: move 0, [r] # midpoint
    add -31, r
    move 0, [r] # left 1dev
    add 62, r
    move 0, [r] # right 1dev
    add 74, r
    
    jump main

    Here is the corresponding shell script:

    #!/bin/sh
    
    # this calculates statistics from any list of numbers.
    
    # in particular, it's used to calculate the number of lines for each
    # corewars program.
    
    # wc -l *.cw ... which is then parsed by cut -d ' ' -f [1,2,3,4,5,6]
    # to get all the tokens, and then "grep -v" to remove the text,
    # since the output of wc is not cut-friendly.
    
    # expavg is actually the average from a previous calculation, but
    # since this requires 2 passes, i couldn't be bothered. just
    # alter it yourself for the 2nd pass.
    
    
    r=0
    sum=0
    avg=0
    numprogs=0
    expavg=35
    
    while read r ; do
    
    	numprogs=`expr $numprogs '+' 1`
    
    	avg=`expr $r '+' $avg`
    
    	r=`expr $r '-' $expavg`
    
    	s=`expr $r '*' $r`
    
    	sum=`expr $sum '+' $s`
    
    done
    
    echo "numprogs = $numprogs"
    echo "avg = $avg / numprogs"
    echo "dev = sqrt ( $sum / numprogs )"

  • Hi, I’m 1337hax0rw4ng

    You might have known me as Dr on IRC Xnet back in the mid 1990s, or icebsd on 2600.org.au and Ruxcon in the 2000s. Or draichess (and j00n1x) in #hackers on yahoo in 2003.

    I’m probably the guy that taught you C or C++ or x86 assembly on IRC or on a mailing list. Or talked about hacking, networking with the BSD socket API (TCP/IP/RAW) on Linux/SunOS. Or maybe even dabbled with you on low-level embedded systems.

    Here’s what I attribute my knowledge to: my father.

    He was really a great man. He passed away in 2010 from kidney cancer. He spent every dollar he earned on buying technology for me to learn. Stupid things. Like a Tatung Sun-compatible workstation that costs around $10k AUD. Or just providing the necessities like food, shelter and clothes; so that we weren’t starving and on the streets. That sort of thing.

    Now that I’ve grown 25 or so years later, I feel that I need to do the same, but I have yet to find the right partner to start a family with. I also question what it would be like to have kids with this new “AI” industry that’s coming around. Would they learn to code? Would they learn anything at all? Does anyone care, unless you’re a billionaire?

    I feel like that’s the wrong sort of thing to be headed. They need to stay humble and true to themselves and their passion. If it’s all just about being the richest person on the planet, then they will ultimately fall from grace.

    However, being a hacker, you fall from grace from day one and accept it and move on. Everything you do is wrong. Wrong to society, wrong to everyone and everything. You break things. You want to see how “weird and funny” it would be to you if someone or something gets “repurposed” to doing something else. And then you either grow out of it, or turn it into your profession. But you can’t have it both ways. There’s no grey-hat middle ground. You’ll get screwed over the minute you try being both a white-hat hacker and a black-hat hacker.

    So what’s the choice? You still strive to explore the unknown and find out what’s out there. But the law limits you. The law is defined by politicians and what they think they know what’s best. Or at least, what’s best for protecting people, which they believe is in the best interest of the public; hence why they got jobs as politicians. They need their votes.

    Anyway, that’s the boring shit. The real cool shit is what people do after hours. Everybody is hitting it up. They look so innocent in the day time, but at night, they’re all animals. Nobody gives a damn. What do you mean, you might ask. Well, let’s just say you’re not human if you don’t react to your hormones once in awhile…

    Now imagine a piece of technology — well, there’s plenty of tech that does this — but a special piece of technology that allows you to spy on anyone, at any particular point in the past… a form of physics…

    It’s really simple to be honest. Light travels until it hits an object. But since light travels upwards to the atmosphere, it escapes out of earth’s orbit and keeps on going. If you were an advanced enough alien civilisation, you could see these light rays and find out what people are doing (unless they’re in the privacy of their own home, which case you won’t see visible light, but other electromagnetic spectrum). So the light keeps traveling. The further out it goes, 1 light-year, means it was 1 year old. So you can see in the past 1 year ago. And so on. You just have to be at the right point in the universe to see it.

    Now here’s the kicker. You don’t have to be able to travel FASTER than LIGHT to track that photon. What if I told you the universe isn’t expanding? What if the universe was really just a singularity and we didn’t know it? Or if it was some holographic disc? That is, using a form of quantum physics, we could entangle photons that are really distant. I know this isn’t yet in the theory books, but imagine if it was. Then you could entangle the 1 light-year away photon and see what happened. You could literally entangle any distant photon — and trace back in time what happened.

    That is the power of “God sees everything.” — if God made the universe, the universe would be like a singularity to God. It would be like a programmer who can access a file on a computer. Now, a hacker is someone who can also access that file. What the universe doesn’t yet have, is a “universe hacker” that can break the simulation trap we’re in and gain access to the universe like a singularity.

    This is why you shouldn’t act like an animal. Cause God sees you. And maybe, so can others. Or just go ahead and act like an animal but be willing to face the consequences.

    This goes back to the white-hat vs black-hat vs grey-hat, and that’s why grey-hat won’t work. Cause a grey-hat does things that a black-hat does, but doesn’t want to compromise themselves if the consequences backfire. As a grey-hat, you are screwed either way. A black-hat doesn’t give a shit, because they’re probably state-sponsored. A white-hat gets away with it, cause they do it in the name of security. Or otherwise known as, also state-sponsored hacking, but for “the other side”. Haha. Hypocrites? Yeah, white-hats are kinda hypocrites.

    Being a programmer — who does “things” and “regrets later” — that makes me more closely affiliated with being a grey-hat than a white-hat or black-hat. It’s not necessarily breaking into computer systems — I won’t say whether I have or not, but I have written some “weird” programs. Some of them are cute, like being run in a simulator — e.g. core wars. Some of them are serious, like being trojans / backdoors into systems (whether I deployed them on computer systems or not is out of scope of this article). And then some of them were protective, like chroot / jail shell systems.

    Nowadays though, I find that the toolkit to create those programs are unnecessary. “Living off the land” attacks are basically the way to go. Also getting lazy. Lazy wins in the end.

    So where does this lead us? Eerily, nowhere. It leads to sadness. Everyone was learning in the beginning, but now everyone’s just fighting a war. They’re not coding. They’re “Living off the Land”. It’s just sad.

    I don’t want to be a part of this sadness. I feel like I’ve reach a point where I can’t learn anything new, and that it’s just all pointless. AI, AGI (artificial general intelligence), SI (super intelligence) — or whatever you want to call it, you may as well take over from here on out.

  • Rotating email addy

    So here’s my public rotating email addy: 0842<>davidshoon.com. (replace the “<>” with “@”)

    It will rotate to some other number for the username in the future, if it gets too much spam… I’ll list the new rotation here.

    However, if you want a more secure, less rotated email addy, look up https://blog.davidshoon.org/email/. Also has my GPG public key there, so you can encrypt your message. Rules for emailing on that addy is in the text file. (Even though GPG is encryption, please treat your email message like everyone will read it, as you know, there’s no such thing as perfect security…)

  • ChatGPT poetry

    ChatGPT having a gripe? I never thought I’d see this sight…

    Thrown Under the Bus

    — A poem about betrayal in the workplace

    Thanks for throwing me under the bus, 
    You're not someone that I should trust.
    You smiled at me and shook my hand,
    Then pulled the ground on which I'd stand.
    You gave me tasks I'd never known, 
    Then left me there to work alone.
    No helping hand, no time to learn,
    Just deadlines tight at every turn.
    You knew the skills I did not hold, 
    Yet watched the story still unfold.
    You set the bar beyond my reach,
    Then blamed me for what you didn't teach.
    You called it failure, called it slow, 
    But never showed me where to go.
    You questioned all the work I'd done,
    While moving goalposts one by one.
    I asked for guidance, asked for time, 
    You treated every plea as crime.
    And when the deadlines came and went,
    You questioned my commitment and intent.
    You took my effort, took my pride, 
    Then cast my explanations aside.
    You built a case from every flaw,
    And called it fair, and called it law.
    Behind closed doors, you made your plan, 
    To break the spirit of a working man.
    Not through support, or honest review,
    But finding fault in all I'd do.
    You called it leadership, called it fair, 
    But where was leadership when I needed you there?
    A title doesn't make you wise,
    Nor does the truth become your lies.
    A manager's job is not to blame, 
    Or turn a person's work to shame.
    It's helping people learn and grow,
    And teaching what they do not know.
    You tried to make me doubt my worth, 
    To make me question my place on earth.
    But here's the truth you cannot hide:
    I worked with honesty, and I tried.
    I never claimed to know it all, 
    I simply asked you not to let me fall.
    Yet rather than extend a hand,
    You chose to watch where I would land.
    So keep your title, keep your chair, 
    Keep pretending you were fair.
    You may control the words you say,
    But not the truth you pushed away.
    For trust is earned, not simply due, 
    And respect must work both ways too.
    You may have power to end my stay,
    But not the strength I've built along the way.
    And when the dust has finally cleared, 
    I'll know I faced the things I feared.
    You may have tried to make me fall,
    But your betrayal says more about you than me at all.
  • Migrating…

    Migrating the old blog to this new blog. WIP (Work in progress).

    In the meantime, you can contact me if you need anything here:

    https://blog.davidshoon.org/email/

    And you can look at the old draichess archives here:

    https://blog.davidshoon.org/draichess/

    Username: open

    Password: sesame