## Happy Halloween

This year's Jack-o'-lantern under construction. One large, one small and the tools of the trade. "Off with his head!" A few guide-lines drawn with a sharpie. Careful excavation. This is a good use of my Masters degree in Computing Science.

The finished product. Grrrrrrr...! Aaargh! Please like and share.

## History of computing timeline Scroll through the major events in computing science history on our Tiki-Toki timeline.
The timeline shows major events in computing and we intend to update it with more soon.

## Computer Abuser Introducing our new Flipboard magazine "Computer Abuser"!
Here you will find all things computer related. You might also like our page on Pinterest - including a new board on algorithms.  If you can contain your excitement, please do follow the links above to find out more.

## Source Code for Reverse Polish calculator

Source Code for the Reverse Polish Notation Calculator for any interested parties, or students of computing.  You will need the full version of BB4Win and copies of the library files indicated below.  Full downloads can be found on the downloads page.
REM RPN Calculator
REM calculates expressions entered in Reverse Polish Notation
REM by T Street
REM!Resource @dir\$+"rpn7.res"

(_Version_Info_)
GAME_NAME\$ = "RPN Calculator"
VERSION\$ = "1.07"
HELPFILE\$ = "RPNhelp7.html"
REM 2013-12-03
REM 2013-12-13 version 1.02
REM   COPY command added.  Copies accumulator to the clipboard
REM   Bug fixed with NOT function.  Now multiplies by -1
REM 2013-12-13 version 1.03
REM   Number bases supported 16, 8, 10, 2
REM   accumulate on/off (ACC ON/ACC OFF)
REM   last keyword : last value of the accumulator as a variable 'last'
REM 2014-02-26 version 1.04
REM   Octadecimal changed to Octal (base 8)
REM   := assignment operator becomes =
REM   = operator becomes ==
REM 2014-10-03 version 1.05
REM 2014-10-08 version 1.06
REM   new colour scheme
REM 2014-10-08 version 1.07

*float 64
PROMPT\$ = "Enter RPN expression, command or URL (or type 'HELP') : "
WELCOME\$ = "Welcome to the RPN Calculator."
ON ERROR SYS "MessageBox", @hwnd%, REPORT\$ + " at line " + STR\$ERL"Fatal Error", 48:QUIT

REM - Talk to me if you are having problems with these three files...

INSTALL @lib\$+"utilities6"
INSTALL @lib\$+"stringlib"

VDU 23,22,900;400;13,13,16,0 : REM screen MODE

OFF
PROC
_setWindowTitle(GAME_NAME\$+" "+VERSION\$+" by T Street")
PROC_preventResize
*font Courier New, 13
PROC_colours

SW% = 58  : REM Screen Width

ALPHABET% = 26 : REM number of letters in alphabet
REM setup the stack

SIZE_OF_STACK% = 100 : REM why not?  NB we have 101 items here, much more than we need
REM a stack object has:
REM   a stack (of strings)
REM   a size of the stack
REM   TOS pointer%
REM   a message
REM   an accumulator

DIM stack{ array\$( SIZE_OF_STACK% ), var\$(ALPHABET%-1), SIZE_OF_STACK%, pointer%, message\$, acc, base%, accumulate% }
stack.base% = 10 : REM start in base 10

PROC_main( stack{} )
STOP

DEFPROC_main( stack{} )
REM main loop

LOCAL user\$ : REM user input

LOCAL leave%: REM controls whether can leave the main loop

stack.message\$ = WELCOME\$
PROC_clearMemory( stack{} )
REPEAT

REM show output

PROC_pageSetup( stack{} )
PROC_reset( stack{} ) : REM reset the stack

user\$ = FN_getUserInput  : REM get user input
REM process user input

CASE TRUE OF
WHEN FN
_upper(user\$) = "HELP"
IF FN_fileExists(HELPFILE\$) THEN

PROC_openDocument(HELPFILE\$)
ELSE

ENDIF

WHEN FN
_upper(user\$) = "HEX"
stack.base% = 16
stack.message\$ = "Switched to HEXADECIMAL mode"

WHEN FN_upper(user\$) = "OCT"
stack.base% = 8
stack.message\$ = "Switched to OCTAL mode"

WHEN FN_upper(user\$) = "BIN"
stack.base% = 2
stack.message\$ = "Switched to BINARY mode"

WHEN FN_upper(user\$) = "DEN"
stack.base% = 10
stack.message\$ = "Switched to DENARY mode"

WHEN FN_upper(user\$) = "ACC OFF"
stack.accumulate% = FALSE

stack.message\$ = "Accumulator off"

WHEN FN_upper(user\$) = "ACC ON"
stack.accumulate% = TRUE

stack.message\$ = "Accumulator on"

WHEN FN_upper(user\$) = "CLEAR"
stack.acc = 0
stack.message\$ = "Memory cleared."
PROC_clearMemory( stack{} )

WHEN FN_upper(user\$) = "QUIT"
QUIT

WHEN FN
_upper(user\$) = "COPY"
stack.message\$ = "Copied to clipboard."
REM ficed in version 1.5 - copies in correct base

IF stack.base%<>10 THEN
PROC
_toClipboard(FN_tobase( stack.acc, stack.base%, 16 DIV stack.base%))
ELSE
PROC
_toClipboard(STR\$(stack.acc))
ENDIF

REM new in version 1.5

WHEN FN_upper(user\$) = "SET TIME" : OSCLI ("time")
stack.message\$ = "Set time dialogue invoked."

WHEN FN_upper(user\$) =  "SET DATE" : OSCLI ("date")
stack.message\$ = "Set date dialogue invoked."

WHEN FN_upper(user\$) = "PROGRAMS" : OSCLI ("appwiz.cpl")
stack.message\$ = "Add/remove programs dialogue invoked."

stack.message\$ = "Admin tools dialogue invoked."

WHEN FN_upper(user\$) = "SOUND" : OSCLI("mmsys.cpl")
stack.message\$ = "Sound dialogue invoked."

WHEN FN_upper(user\$) = "VERSION"
stack.message\$ = GAME_NAME\$+" version "+VERSION\$ + " " + FN_getWindowsVersion

WHEN FN_upper(user\$) = "FILES" : OSCLI("explorer")
stack.message\$ = "Windows explorer invoked."

WHEN FN_upper(user\$) = "POWER"
stack.message\$ = FN_powerStatus

WHEN FN_upper(user\$) = "CP" :  OSCLI ("control panel")
stack.message\$ = "Control panel invoked."

WHEN LEFT\$(FN_upper(user\$), 4) = "BING" PROC_bing(FN_trim(RIGHT\$(FN_upper(user\$),LEN(FN_upper(user\$))-4)))
stack.message\$  = "I sent your search query to Bing."

WHEN LEFT\$(FN_upper(user\$),4) = "WWW." PROC_openDocument( user\$ )
stack.message\$  = "Attempted to open a web resource."

WHEN LEFT\$(FN_upper(user\$),4) = "HTTP" PROC_openDocument( user\$ )
stack.message\$  = "Attempted to open a web resource."

WHEN LEFT\$(FN_upper(user\$),10 )= "FREE SPACE" PROC_freeSpace( RIGHT\$(FN_upper(user\$),1), stack.message\$):

WHEN FN_upper(user\$) = "MAGNIFIER" : OSCLI("magnify")
stack.message\$ = "Magnifier invoked."

WHEN FN_upper(user\$) = "HELLO"
stack.message\$ = "Hello, human."

stack.message\$ = "Windows task scheduler launched."

WHEN LEFT\$(FN_upper(user\$), 4) = "PING" PROC_ping(FN_trim(RIGHT\$(FN_upper(user\$),LEN(FN_upper(user\$))-4)))
stack.message\$ = "Ping sent."

WHEN LEFT\$(FN_upper(user\$),3) = "CMD" stack.message\$ = FN_winCmd( FN_trim( RIGHT\$( FN_upper(user\$), LEN(FN_upper(user\$))-3 ) ) )

OTHERWISE
IF
stack.accumulate% THEN

stack.acc += FN_evaluate( user\$, stack{}, success% )
ELSE

stack.acc = FN_evaluate( user\$, stack{}, success% )
ENDIF

stack.message\$ = RED\$+stack.message\$+" " +BLACK\$+"'"+user\$+"'"
ENDCASE
UNTIL
leave%
ENDPROC

DEF FN_winCmd(cli\$)
LOCAL ch%,eErr\$,tmp\$,tempStr\$:tmp\$=FN_specialFolder(5)+"\"+STR\$TIME+".tmp"
OSCLI "cmd /c "+cli\$+" 2>"+tmp\$
ch%=OPENIN(tmp\$):IF ch%=0:="Could not complete request."
WHILE NOTEOF#ch%
INPUT#ch%, tempStr\$
eErr\$ += (tempStr\$+" ")
ENDWHILE

eErr\$ = FN_removeCRLF( eErr\$)
CLOSE#ch%:OSCLI"Delete "+tmp\$
REMproc_OK(eErr\$)

=eErr\$

DEFFN_evaluate( this\$, stack{}, RETURN success% )
REM takes a string from the user and evaluates it as an RPN expression

ON ERROR LOCAL stack.message\$ = REPORT\$ : success% = FALSE : = 0
LOCAL term\$() : DIM term\$(1)
LOCAL parts%
LOCAL item\$ : REM operand

LOCAL n% , leave%
parts% = FN_split( this\$, " ", term\$() )
WHILE n% < parts% AND NOTleave%
IF (FN_toDenary(term\$(n%), stack.base%)=0 AND LEFT\$(term\$(n%),1)<>"0" AND stack.base%<>10) OR(stack.base% = 10 AND VAL(term\$(n%))=0 AND LEFT\$(term\$(n%),1)<>"0"THEN

REM operator

CASE FN_lower(term\$(n%)) OF
WHEN
"pi"
IF NOTFN_push( STR\$(PI), stack{} ) THEN

leave% = TRUE
ENDIF

WHEN
"time"
IF NOTFN_push( STR\$(TIME), stack{} ) THEN

leave% = TRUE
ENDIF

WHEN
"last"
IF NOTFN_push( STR\$(stack.acc), stack{} ) THEN

leave% = TRUE
ENDIF

WHEN
"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"

IF NOTFN_push( stack.var\$(ASC(FN_upper(term\$(n%)))-65), stack{} ) THEN

leave% = TRUE
ENDIF

WHEN
"="
IF n% = parts%-1 THEN

leave% = TRUE
ELSE
IF FN
_pop(item\$, stack{} ) THEN

stack.var\$( ASC(FN_upper(term\$(n%+1)))-65 ) = item\$
ELSE

leave% = TRUE
ENDIF
ENDIF

WHEN
"+","-","/","*","^","div","mod","and","eor","or","=="
IF NOTFN_findValue( stack{}, " "+FN_upper(term\$(n%))+" " ) THEN

leave% = TRUE
ENDIF

WHEN
IF NOTFN_findFunction( stack{}, FN_upper(term\$(n%))) THEN

leave% = TRUE
ENDIF

OTHERWISE

leave% = FALSE

stack.message\$ = "Unknown operator. "
ENDCASE
ELSE

REM operand

IF stack.base%<>10 THEN
IF NOTFN
_push( STR\$FN_toDenary(term\$(n%), stack.base%), stack{} ) THEN

leave% = TRUE
ENDIF
ELSE
IF NOTFN
_push( term\$(n%), stack{} ) THEN

leave% = TRUE
ENDIF

ENDIF
ENDIF

n% += 1
ENDWHILE
IF NOT
leave% THEN

REM the stack should just contain the answer

IF stack.pointer% = 1 THEN

success% = TRUE

VAL( stack.array\$(0) )
ELSE

success% = FALSE

stack.message\$ += "Insufficient Operators."
= 0
ENDIF
ELSE

success% = FALSE

= 0
ENDIF

DEFFN_findValue( stack{}, operator\$ )
REM evalutes the operation passed in operator\$
REM by popping the two values from the stack
REM and performing the infix operation upon them

ON ERROR LOCAL stack.message\$ = "Fatal error with operation : "+operator\$+". "+REPORT\$: = FALSE
LOCAL
a\$, b\$
IF FN_pop( b\$, stack{}) THEN
IF FN
_pop(a\$, stack{} ) THEN

REM might need to change the values based on the current mode
REM have operands, now find operator

CASE operator\$ OF
WHEN
"="
IF VAL(a\$) = VAL(b\$) THEN
IF FN
_push( "-1", stack{}) THEN

TRUE
ENDIF
ELSE
IF FN
_push( "0", stack{} ) THEN

TRUE
ENDIF
ENDIF

OTHERWISE
IF FN
_push( STR\$EVAL(a\$+operator\$+b\$), stack{} ) THEN

TRUE
ENDIF
ENDCASE
ENDIF
ENDIF

stack.message\$ += (" Error with operation : "+operator\$+".")
= FALSE

DEFFN_findFunction( stack{}, operator\$ )
ON ERROR LOCAL stack.message\$ = "Fatal error with function : "+operator\$+". "+REPORT\$: = FALSE

REM evalutes the operation passed in operator\$
REM by popping the first value from the stack
REM and performing the infix operation upon them

LOCAL e\$,f, a\$
IF FN_pop(a\$, stack{} ) THEN
CASE
operator\$ OF
WHEN
"ROUND"
IF FN_push( STR\$(FN_round(VAL(a\$))), stack{} ) THEN

TRUE
ENDIF
WHEN
"NOT"  : REM overides NOT

IF VAL(a\$)= 0 THEN
IF FN
_push( "-1", stack{} ) THEN

TRUE
ENDIF
ELSE
IF FN
_push( "0", stack{} ) THEN

TRUE
ENDIF
ENDIF
WHEN
"INV"
IF FN_push( STR\$(1/(VAL(a\$))), stack{} ) THEN

TRUE
ENDIF

OTHERWISE

e\$ = operator\$+"("+a\$+")"
f = EVAL(e\$)
IF FN_push( STR\$(f), stack{} ) THEN

TRUE
ENDIF
ENDCASE
ENDIF

stack.message\$ += (" Error with "+operator\$+" function.")
= FALSE

DEF PROC_clearMemory( stack{} )
REM sets the values of all the user-defined variables to zero

LOCAL n%
FOR n% = 0 TO ALPHABET% - 1
stack.var\$(n%) = "0"
NEXT

REM and resets the internal clock

TIME = 0
ENDPROC

DEFFN_push( item\$, stack{} )
ON ERROR LOCAL stack.message\$ = "Fatal error stack.push : "+REPORT\$: = FALSE

REM pushes the item onto the stack
REM returns true if the push was successful
REM returns false if the push was unsuccessful

IF stack.pointer% > SIZE_OF_STACK% THEN

REM unable to push to the stack, so return with a warning message

stack.message\$ = "No room on stack. "
= FALSE
ENDIF

stack.array\$( stack.pointer% ) = item\$
stack.pointer% += 1
= TRUE

DEFFN_pop( RETURN item\$, stack{} )
ON ERROR LOCAL stack.message\$ = "Fatal error stack.pop : "+REPORT\$: = FALSE

REM pops the item off the stack
REM returns the item popped.

IF stack.pointer% <= 0 THEN

REM unable to pop (nothing to pop)

stack.message\$ = "Stack is empty. "
= FALSE
ENDIF

stack.pointer% -= 1
item\$ = stack.array\$( stack.pointer%)
= TRUE

DEFPROC_reset( stack{} )
REM reset the stack

stack.pointer% = 0
stack.message\$ = ""
ENDPROC

DEF FN_getUserInput
ON ERROR LOCAL stack.message\$ = "Fatal error with user input : "+REPORT\$: = FALSE

REM gets player's input

LOCAL s\$
COLOUR CYAN%:*font Courier New, 16b
REM input viewport coords

VDU 28,3,14,65,9
COLOUR BLUE%+128 : CLS
PRINT
PROMPT\$
PRINT"> ";:COLOURYELLOW%
PROC_soak
*font Courier New, 18b
COLOURWHITE%
*font Courier New, 14
= FN_trim(s\$)

DEFFN_toDenary( code\$, base%)
LOCAL size%
size% = LEN(code\$)
LOCAL n%: REM iterator

LOCAL v%: REM value of each digit in the hex string passed

LOCAL t : REM running total

FOR n% = size%-1 TO STEP -1
v% = INSTR("0123456789ABCDEF",FN_upper(MID\$(code\$, size%-n%, 1))) - 1
IF v%>=0 AND  v%<base% THEN

t += (v%*base%^n%)
ELSE

= 0 : REM breakout

ENDIF
NEXT

= t

DEFFN_myTime( t\$ )
REM returns a formatted time from the string passed
REM pass a time\$

LOCAL a\$
CASE LEFT\$(t\$, 3) OF
WHEN
"Mon" a\$ = "Monday"
WHEN "Tue" a\$ = "Tuesday"
WHEN "Wed" a\$ = "Wednesday"
WHEN "Thu" a\$ = "Thursday"
WHEN "Fri" a\$ = "Friday"
WHEN "Sat" a\$ = "Saturday"
WHEN "Sun" a\$ = "Sunday"
ENDCASE

a\$ = a\$ + " "MID\$(t\$, 5, 11) + " > " +MID\$(t\$, 17, 5)
= a\$

DEFPROC_pageSetup( stack{} )
ON ERROR LOCALPRINTTAB(0,4)BLACK\$"---> ";:COLOUR RED%+128:PRINTWHITE\$" ERROR '"+REPORT\$+"'. ":ENDPROC

LOCAL
out\$
VDU 26
COLOUR BLACK%+128 : CLS COLOUR WHITE%
REM output view port coords

*font Courier New, 16b

PRINT TAB(3,16)LIGHTGRAY\$" superdecade.blogspot.com > "FN_myTime( TIME\$ )
*font Courier New, 32b
PRINTTAB(0,0)WHITE\$"  RPN Calculator ";
CASE stack.base% OF
WHEN
16
WHEN 10
PRINT"(DENARY)";
WHEN 8
PRINT"(OCTAL)";
WHEN 2
PRINT"(BINARY)";
ENDCASE
IF
stack.accumulate% THEN
PRINT
"(ACC)"
ELSE
PRINT
ENDIF

*font Courier New, 16b

VDU 28,3,7,65,3

COLOUR CYAN%+128 : CLS

PROC
_ww(BLACK\$+LEFT\$(">"+stack.message\$, 2*SW%-8) , SW% )

IF stack.base%<>10 THEN

out\$ = FN_tobase( stack.acc, stack.base%, 16 DIV stack.base%)
ELSE

out\$ = STR\$(stack.acc)
ENDIF

PRINTTAB(
0,3)BLACK\$"---> ";:COLOUR GREY%+128:PRINTWHITE\$" "out\$" "

ENDPROC

DEFPROC_colours
COLOUR 1, 220,20,0 : RED% = 1
COLOUR 2, 220,220,220 : WHITE% = 2
COLOUR 3, 200,200,0 : YELLOW% = 3
COLOUR 4, 10,200,20 : GREEN% = 4
COLOUR 5, 0,10,230  : BLUE% = 5
COLOUR 6, 1,1,1 : BLACK% = 6
COLOUR 8, 200,0,200 : MAGENTA% = 8
COLOUR 9, 40,40,40 : GRAY% = 9 : GREY% = GRAY%
COLOUR 10, 0,0,0  : BLACK% = 10
COLOUR 11, 0, 200,200 : CYAN% = 11
COLOUR 12, 150,150,150 : LIGHTGRAY% = 12
GREEN\$=CHR\$(17)+CHR\$(GREEN%)
RED\$=CHR\$(17)+CHR\$(RED%)
YELLOW\$=CHR\$(17)+CHR\$(YELLOW%)
CYAN\$=CHR\$(17)+CHR\$(CYAN%)
WHITE\$=CHR\$(17)+CHR\$(WHITE%)
MAGENTA\$ = CHR\$(17)+CHR\$(MAGENTA%)
BLUE\$  = CHR\$(17)+CHR\$(BLUE%)
GREY\$ = CHR\$(17)+CHR\$(GREY%)
BLACK\$ = CHR\$(17)+CHR\$(BLACK%)
LIGHTGRAY\$ = CHR\$(17)+CHR\$(LIGHTGRAY%)
ENDPROC

DEFFN_message(caption\$,message\$,symbol%,type%)
REM Displays a message box
REM Returns a value relating to user selection
REM params
REM caption\$ - title for message box
REM message\$ - the message
REM
REM symbol%
REM         16 Stop symbol
REM         32 Question mark
REM         48 Exclamation mark
REM         64 Information symbol
REM
REM type%
REM          0 OK
REM          1 OK and Cancel
REM          2 Abort, Retry and Ignore
REM          3 Yes, No and Cancel
REM          4 Yes and No
REM          5 Retry and Cancel
REM          6 Cancel, Try Again and Continue (Windows 2000 or later only)
REM
REM The return value of result% will be one of the following depending on user choice:
REM          1 OK
REM          2 Cancel
REM          3 Abort
REM          4 Retry
REM          5 Ignore
REM          6 Yes
REM          7 No
REM         10 Try Again
REM         11 Continue

LOCAL result%
SYS "MessageBox", @hwnd%, message\$, caption\$, (symbol%+type%) TO result%
=result%

DEFPROC_OK( t\$ )
REM creates an OK message box
REM using the message stored in t\$

IF FN_message( GAME_NAME\$, t\$, 64, 0 )
ENDPROC

DEFFN_powerStatus
REM returns a string containing the current power status

LOCAL sps{}
LOCAL message\$
DIM sps{ACLineStatus&, BatteryFlag&, BatteryLifePercent&, Reserved1&, \

SYS "GetSystemPowerStatus", sps{}
CASE sps.ACLineStatus& OF
WHEN
0: message\$="Operating from batteries. "
WHEN 1: message\$="Operating on mains. "
ENDCASE
CASE
sps.BatteryFlag& OF
WHEN
1: message\$+="Battery charge status is high. "
WHEN 2: message\$+="Battery charge status is low. "
WHEN 4: message\$+="Battery charge status is critical. "
WHEN 8: message\$+="Battery is charging. "
WHEN 128: message\$+="No battery fitted. "
ENDCASE
IF

message\$=message\$ + "Approx remaining battery life is "+ \

\     STR\$(sps.BatteryLifeTime% DIV 60 )+" mins."
ENDIF
IF

message\$=message\$ +"Approx battery life when fully charged is "+ \

\     STR\$(sps.BatteryFullLifeTime% DIV 60)+ " mins."
ENDIF

= message\$

ENDPROC

DEFPROC_bing( t\$ )
PROC_openDocument("https://www.bing.com/search?q="+t\$)
ENDPROC

DEFPROC_ping( t\$)
OSCLI("ping "+t\$)
ENDPROC

DEF FN_getWindowsVersion
LOCAL a\$
LOCAL osci{}
DIM osci{Size%,     \ Size of structure

\        Major%,    \ Major version number

\        Minor%,    \ Minor Version number

\        Build%,    \ Build number

\        Platform%, \ Platform ID

\        SP&(127)   \ Service Pack string

\       }
osci.Size% = 148
SYS "GetVersionEx", osci{}
CASE TRUE OF
WHEN
osci.Major% = 4 AND osci.Minor% = 0
a\$ = "95"
WHEN osci.Major% = 4 AND osci.Minor% = 10
a\$ = "98"
WHEN osci.Major% = 4 AND osci.Minor% = 90
a\$ = "Me"
WHEN osci.Major% = 4 AND osci.Minor% <>0 AND osci.Minor%<>10 AND osci.Minor%<>90
a\$ = "NT4"
WHEN osci.Major% = 5 AND osci.Minor% = 0
a\$ = "2000"
WHEN osci.Major% = 5 AND osci.Minor% = 1
a\$ = "XP"
WHEN osci.Major% = 6 AND osci.Minor% = 0
a\$ = "Vista"
WHEN osci.Major% = 6 AND osci.Minor% = 1
a\$ = "7"
WHEN osci.Major% = 6 AND osci.Minor% = 2
a\$ = "8"
WHEN osci.Major% = 6 AND osci.Minor% = 3
a\$ = "8.1"
OTHERWISE a\$ = "(unknown)"
ENDCASE

"Windows "+a\$+" (build "+STR\$(osci.Build%)+")"

DEFPROC_freeSpace( mydrive\$,  RETURN message\$ )
drive\$ = mydrive\$+":\"
SYS "GetDiskFreeSpace", drive\$, ^SpC%, ^BpS%, ^Free%, ^Total%
gbytes_total = SpC% * BpS% * Total% / 2^30
gbytes_free  = SpC% * BpS% * Free% / 2^30
message\$ = "Total "+STR\$INTgbytes_total+"GB, Available "+STR\$INTgbytes_free+"GB, Used "+STR\$INT(gbytes_total-gbytes_free)+"GB"
ENDPROC