Tuesday, December 31, 2013

Raspberry Pi Journal #43


Speech Synthesis Trouble

I'm having a hard time coming up with proper speech synthesis. I tried using espeak, and it seems to work, but the first few seconds was off as if having buffer underflow, and the last few seconds was slow, as if it's having buffer overflow. Tried festival, and that too, suffers from the same problem.

As a last resort, I installed Basic256, and use its "say" command. The speech was clear and concise. Unfortunately, the buffer overflow problem is still happening. So, in the end I gave up.

I think the problem does not lie in the speech program. After all, all the speech module does is chaining snippets of audio to make the speech. I don't see any problem in that regard. It's the audio driver that is a problem. Apparently, the buffer isn't set up properly and so the audio becomes scrambled.

It should be possible that the audio be working fine. After all, I don't see any trouble regarding audio in playing movies.

Monday, December 30, 2013

Cooking Journal #19


Exotic Butter




I usually just pick up the butter substitute. However, when I was wandering over to the butter section, I saw this butter, and I can't resist. It's certainly unique, and I'm glad I tasted this one. Something like a specially made butter. Not too sure that I have use for special ingredient, though. Yes, it's better. No, it's not so much better that I want to hunt this specific butter.

Saturday, December 28, 2013

Nintendo Journal #19


Craftsman Drill


I love this tool. I even use it around the house! Install this, install that. This is my first go to tool. It has light, auto tension, and all around a good tool.

Of course, the magazine review makes it only a so-so value. But I really don't care. This one is good enough for me.

Friday, December 27, 2013

Petit Computer Journal #31



Digital Koto

A while back, I wrote a little piano program. It includes song player. It's just a little simple music player, so I used BEEP instead of MML command. However, I'm rather curious since most of the code is created for the interface. In other words, drawing the piano keys. So, I'm wondering whether or not it's simpler to just draw the keys straight. Well, what kind of musical instrument is like that? The answer is simple: Japanese Koto. In truth, different cultures have different ideas and names for what basically amounts to a bunch of strings mounted on a board.

Still, the idea of it is interesting, and it's simple enough for me to do. So, let' do it! There are several different parts, but generally speaking, once you touch the screen, you come up with a string number and beep the appropriate sound. That's just look up table. Touch screen is easy. About the only thing that's difficult is drawing the strings proportionately. A little mathematic should do it.


  1. INIT
  2. Build BEEP table
  3. Build Note table
  4. Build String table
  5. LOOP
  6. Draw Strings
  7. If Touch screen
  8. Highlight nearest string
  9. Play BEEP sound
  10. GOTO LOOP


So, do you think this will take you one hour to do? Time for another "Hour of Code" challenge!


  1. ACLS:CLEAR
  2. DIM BP[49]:'BEEP TABLE
  3. DIM NT$[49]:'NOTE TABLE
  4. DIM ST[16]:'STRING TABLE
  5. BREPEAT 0,60,12
  6. BREPEAT 1,60,12
  7. BREPEAT 2,60,12
  8. BREPEAT 3,60,12

  9. @INIT
  10. NSI=0
  11. P=4096/12:T$="CcDdEFfGgAaB"
  12. FOR I=-24 TO 24:J=I+24
  13. BP[J]=P*I
  14. NT$[J]=MID$(T$,(J%12),1)
  15. NEXT
  16. ST[0]=14:ST[1]=19
  17. ST[2]=21:ST[3]=22
  18. ST[4]=26:ST[5]=27
  19. ST[6]=31:ST[7]=33
  20. ST[8]=34:ST[9]=38
  21. ST[10]=39:ST[11]=43
  22. ST[12]=45:ST[13]=0
  23. ST[14]=0:ST[15]=0

  24. ACLS


That's about it for the Initialization table. I want to fiddle with the string, so I'll put in button interface so I can change the string values on the fly.


  1. @LOOP
  2. NS=13:A=256/NS:B=A/2
  3. VSYNC 1:BT=BTRIG():TX=FLOOR(TCHX*NS/256)
  4. IF NS<1 THEN NS=1
  5. FOR I=0 TO NS-1
  6. GLINE B+I*A,16,B+I*A,192,15
  7. LOCATE (B+I*A)/8,0:?FLOOR(ST[I]/12)
  8. LOCATE (B+I*A)/8,0:?NT$[ST[I]]
  9. NEXT
  10. GLINE B+TX*A,16,B+TX*A,192,8
  11. IF TCHTIME>0 THEN BEEP 20,BP[ST[TX]]
  12. GOTO @LOOP


And that's about it. 35 minutes so far, and that's because I was having trouble with the math. The truth is, had I did the math correctly beforehand, I wouldn't have had so much trouble and I wouldn't have spend the time debugging.

Oh, yeah, about the tuning on the fly. I think that it is nice to be able to change the notes. So, what I'll do is add some button interface. That's what the BREPEAT command is for. Also, I may as well throw the instrument along with it. Instead of the locked in BEEP 20, I substitute it with a variable that will allow you to choose your own instrument.

Finally, we're going to move the whole thing down to the lower screen for ease of play. What should we put on the top of the screen? I don't know. Title screen, maybe? Or some internal variables?


  1. REM DIGITAL KOTO
  2. REM BY HARRY HARDJONO
  3. REM DEC 2013

  4. ACLS:CLEAR
  5. DIM BP[49]:'BEEP TABLE
  6. DIM NT$[49]:'NOTE TABLE
  7. DIM ST[16]:'STRING TABLE
  8. BREPEAT 0,60,12
  9. BREPEAT 1,60,12
  10. BREPEAT 2,60,12
  11. BREPEAT 3,60,12
  12. PNLTYPE "OFF"

  13. @INIT
  14. NSI=0
  15. CI=16:'CURRENT INSTRUMENT
  16. P=4096/12:T$="CcDdEFfGgAaB"
  17. FOR I=-24 TO 24:J=I+24
  18. BP[J]=P*I
  19. NT$[J]=MID$(T$,(J%12),1)
  20. NEXT
  21. ST[0]=14:ST[1]=19
  22. ST[2]=21:ST[3]=22
  23. ST[4]=26:ST[5]=27
  24. ST[6]=31:ST[7]=33
  25. ST[8]=34:ST[9]=38
  26. ST[10]=39:ST[11]=43
  27. ST[12]=45:ST[13]=0
  28. ST[14]=0:ST[15]=0

  29. GPAGE 1:ACLS

  30. @LOOP
  31. NS=13:A=256/NS:B=A/2
  32. VSYNC 1:BT=BTRIG():TX=FLOOR(TCHX*NS/256)
  33. IF NS<1 THEN NS=1
  34. GPAGE 1,1,1
  35. FOR I=0 TO NS-1
  36. GLINE B+I*A,16,B+I*A,192,15
  37. LOCATE (B+I*A)/8,0:?FLOOR(ST[I]/12)
  38. LOCATE (B+I*A)/8,0:?NT$[ST[I]]
  39. NEXT
  40. GLINE B+TX*A,16,B+TX*A,192,8
  41. IF TCHTIME>0 THEN BEEP CI,BP[ST[TX]]

  42. IF BT AND 1 THEN ST[NSI]=ST[NSI]+1
  43. IF BT AND 2 THEN ST[NSI]=ST[NSI]-1
  44. IF BT AND 4 THEN NSI=NSI-1
  45. IF BT AND 8 THEN NSI=NSI+1
  46. IF BT AND 16 THEN CI=CI+1:GOSUB @DISP
  47. IF BT AND 32 THEN CI=CI-1:GOSUB @DISP
  48. NSI=(NSI+NS)%NS
  49. ST[NSI]=(ST[NSI]+49)%49
  50. CI=(CI+70)%70
  51. GOTO @LOOP

  52. @DISP
  53. ACLS
  54. ?"INST: ";CI
  55. FOR I=0 TO 15
  56. ?I,ST[I]
  57. NEXT
  58. RETURN



Oh, by the way. The actual problem is so simple, that you can actually fit the minimalistic version of the program into one screen. That's right. It's another single screen challenge program!


  1. REM DIGITAL KOTO
  2. REM BY HARRY HARDJONO
  3. ACLS:CLEAR:DIM BP[49]
  4. DIM NT$[49]:DIM ST[16]
  5. P=4096/12:T$="CcDdEFfGgAaB"
  6. FOR I=-24 TO 24:J=I+24
  7. BP[J]=P*I
  8. NT$[J]=MID$(T$,(J%12),1):NEXT
  9. ST[0]=14:ST[1]=19:ST[2]=21
  10. ST[3]=22:ST[4]=26:ST[5]=27
  11. ST[6]=31:ST[7]=33:ST[8]=34
  12. ST[9]=38:ST[10]=39:ST[11]=43
  13. ST[12]=45:ST[13]=0:ST[14]=0
  14. @LOOP
  15. NS=13:A=256/NS:B=A/2
  16. VSYNC 1:TX=FLOOR(TCHX*NS/256)
  17. GPAGE 1,1,1:FOR I=0 TO NS-1
  18. GLINE B+I*A,0,B+I*A,192,15
  19. NEXT
  20. GLINE B+TX*A,16,B+TX*A,192,8
  21. SD=BP[ST[TX]]
  22. IF TCHTIME>0 THEN BEEP 16,SD
  23. GOTO @LOOP


Thursday, December 26, 2013

Book Review #16


American Bar Association: Legal Guide to Game Development
Ross Dannenberg (Editor)

I have always wanted to have my own video game development company. I just don't know how. All the books out there is simply a guide on how to build a generic business. That's not true. I found a book on how to run your own Food Truck. Somebody actually recommended a good book on video game company development. That book is out of print. This book is my substitute.

Unfortunately, it makes for a boring reading. I suppose lawyers are boring creatures. I understand the need for precise wording, but it's like, they have no imagination whatsoever. Oh, well. All the pertinent info are there. At least I think so, since I'm not a lawyer. The book does details the game development process from idea to implementation to execution. Of course, all the pertinent regulations are highlighted. The book does an admirable job explaining the laws as they affect the gaming development.

It has enough examples and exposition to make the issues clear to me. Well. It's just so boring, though. Of course, the value of this book isn't entertainment. It's legal advice, as close as you can get without actually consulting a lawyer. On that, the book succeeds. Give it a try. You may be surprised as just how many of those laws apply to a simple game development process.

Tuesday, December 24, 2013

Raspberry Pi Journal #42


Symbolic Linking

Here's something to ponder. Let's say that you want to have a certain file that is frequently modified. But, you also want to have a copy of all the modifications. Something like a running log. You can, of course, do it like this:


  1. Create the file, make changes to it, etc.
  2. Copy the file to some other name, adding timestamp.


So, let's say we have a file called Musings.txt. We can use this command copy the file, while adding time stamp.

cp Musings.txt `date Musings_%F.txt`

You can change the date format to anything you like. See the man pages for "date" for details.

Another way to have a file associated with changes, and this is important if you want to make changes to it, but want the file associated with the latest stable version, as opposed to the latest edited, is to use symbolic link command.

ln -s original_file linked_file

By making copy as a linked file, you can refer to the linked file whenever you want, and refer to the original file. Then when you're ready, simply replace the linked file to the updated one.


  1. rm linked_file
  2. ln -s updated_file linked_file


It's a two step process, but you can work with the updated file to your heart content, and be sure to have the updated file ready to be "released", without changing anything else.

It's similar to copy, but more space efficient.

Monday, December 23, 2013

Cooking Journal #18


Chicken Leg and Thigh



I usually cook my rice with hot dogs. However, I do like to get fancy from time to time. So, I'd go to the local supermarket and raid their chicken section. I usually grab their legs and thigh section. In the old days, I'd grab their boneless breast section. Nowadays, though, after reading Modernist Cuisine, I decided that cooking bone-in is the way to go!

It's a simple enough deal to cook these. Once the oil is warmed up in the pan, I set it to medium, and put a leg and a thigh into it. Wait 20 minutes, and turn them over. Wait another 10 minutes, and take the leg out. Wait another 10-15 minutes and take the thigh out. Total time: 25-30 minutes for the leg. 40-45 minutes for the thigh.

The only problem with this is that last 5 minutes. I have to watch over them. I have the pan with glass lid, so I can actually watch them fry. However, I still go by smell.

The end result is delicious! Not as good as KFC, because I simply don't care about spices, but the meat is tender and juicy. Just the right amount of cooking.

Saturday, December 21, 2013

Nintendo Journal #18


Dremel Tool



Dremel tool turns out to be very useful and versatile. On the other hand, unless your craft projects includes sanding and cutting, it has limited usage. I'm going to try and see if I can do some craft projects with it. Mostly trying to make a case with Raspberry Pi, though. We'll see.

Friday, December 20, 2013

Petit Computer Journal #30


Programming Turtle Graphic

It somewhat annoys me when people are teaching turtle graphic as the basis of learning computer programming. It's not that turtle graphic is bad, as I do believe that the thought process does indeed teach programming. It is that the turtle is presented as a module. A black box, if you will.

I think it's more appropriate, especially for computer programming students to learn how simple and easy it can be to write their own turtle module. Therefore, I propose that instead of turtle graphic module, it should be a turtle graphic routines. Instead of a mysterious black box, it should be a transparent wrapper.

Done as a function call, especially interested students can take a peek into the function and see exactly how easy it can be to write a useful program such as turtle graphic.

In fact, I believe that it can be done in one hour. Turtle Graphic algorithm as an "Hour of Code" challenge? Bring it on!

First, what is involved in a turtle graphic program? Well, there's turtle and there's graphic. What are the commands necessary? Forward, Left, Right, and Pen. Each of those commands are followed by a number. We'll call that Number variable. Well, well. There are only 4 commands, are they? Would you believe that they are doable in about one hour? Why not?

If you are familiar with Object Oriented methodology, those are called "methods". What about variables? There's the position of the turtle, X0 and Y0. There's the destination of the turtle, X1 and Y1. There's Angle and Distance. And there's Pen Color. Is that 8 variables total? Are you saying coding these 8 variables into 4 commands is a great challenge? I don't think so!

Of course, we're skipping a lot of things. Namely, the LOGO language. LOGO is a programming language and if you are learning LOGO, you are learning computer programming language. The first turtle graphic and LOGO make effective combination. Most people incorrectly assume that turtle graphic must involve LOGO somewhat. Yet, Turtle graphic is just the graphical component of it. As for the language, we'll use Petit Computer Smile Basic.

That's all there is to it. So, let's set the timer and begin. 1 hour is all that takes. For simplicity, I will assume that commands are given in Strings and consist of 3 characters: A letter command, followed by 2 digit number. If the string has more than 3 characters, then the program will extract the first three characters only. If the string is less than 3 characters, it will be ignored. Also, Color 0 means Pen Up, which means moving the turtle without drawing the line. And perhaps, we should expand the language so we can do GPAINT command for colorful final image. With that in mind, let's begin!

In 15 minutes, I got the initial framework already.


  1. ACLS:CLEAR

  2. @INIT
  3. C$="":'COMMAND STRING
  4. N=0:'COMMAND PARAMETER
  5. X0=128:Y0=96:'TURTLE POSITION
  6. X1=0:Y1=0:'TURTLE DESTINATION
  7. A=0:'ANGLE
  8. D=0:'DISTANCE
  9. C=0:'PEN COLOR
  10. SPSET 1,139,0,0,0,0:SPOFS 1,X0,Y0

  11. @MAIN
  12. 'CLASSIC RECTANGLE
  13. C$="F35R90F35R90F35R90F35R90"
  14. GOSUB @TURTLE
  15. WAIT 300

  16. @END
  17. BEEP 6
  18. END

  19. @TURTLE
  20. IF LEN(C$)<3 THEN RETURN
  21. TC$=LEFT$(C$,3)
  22. N=VAL(RIGHT$(TC$,2))
  23. TC$=LEFT$(C$,1)
  24. C$=RIGHT$(C$,LEN(C$)-3)
  25. ?TC$;" ",N;"  ":WAIT 60

  26. GOTO @TURTLE


If you look at the code, there is nothing much there. It's simply the structure to pass on the command for the turtle. We can use IF-THEN ladder structure, or we can use ON-GOTO command structure. Depending on TC$, which contains the actual command. We can actually skip TC$, and specify LEFT$(C$,1) instead, but using that extra variable clarifies things for now.

I decided to do the easy thing first and implement Paint and Color command. Change C$ to "C01P00C02P00C03P00C04P00" for now. Also, we'll use ON-GOTO. This requires a numeric variable, so we'll do this


  1. TN=INSTR("FLRCP",TC$)
  2. ?TC$,TN,N:WAIT 60

  3. ON TN GOTO @TTF,@TTL,@TTR,@TTC,@TTP
  4. GOTO @TURTLE
  5. @TTF
  6. GOTO @TURTLE
  7. @TTL
  8. GOTO @TURTLE
  9. @TTR
  10. GOTO @TURTLE
  11. @TTC
  12. C=N:GCOLOR C
  13. GOTO @TURTLE
  14. @TTP
  15. IF N==0 THEN GPAINT X0,Y0,C ELSE GPAINT X0,Y0,N
  16. GOTO @TURTLE


Wow, that was easy! Of course, the hard part is coming up. Specifically, we're going to talk a bit about polar coordinates. We need it to draw the turtle. But first, we're going to just set the angle. That's not too difficult. All we have to do is adjust the angle variable just like we did with color. About the only thing that we have to do is to convert the angle to radians.

A bit of caution here. Mostly, we can just to "L180" to do a turn-about movement. However, since we decided to limit the numeric portion to just 2 digits, the most we can do is quarter turn. If we want to have turn-about the turtle, then we have to do it twice, with "L90L90" command.

Another thing. We want to rotate the turtle to the appropriate angle. So far, all we did was display the sprite. Now we want to set the angle and have the turtle facing in the right direction. So, there are two steps. First, we want to convert degrees to radians, and second, we want to orient the sprite accordingly.

There is a complication here. That is, computers have 0,0 coordinate on the top-left corner of the screen, unlike math with their 0,0 coordinate on the bottom-left of the screen. We'll have to fudge the math a bit, and the best way to do it is to just experiment. So, we're going to set up a new subroutine @ROTATE which will rotate the sprites according to angles. That is, given the value of A in degree, set the direction accordingly. All we have to do then, is decide which values goes which direction. I think 0 degree should point up. With that in mind, do this real quick:


  1. @TEST
  2. FOR A=0 to 360 STEP 360/12
  3. GOSUB @ROTATE:WAIT 60
  4. NEXT

  5. @ROTATE
  6. A=A%360
  7. SPANGLE 1,A,6
  8. RETURN



We discovered a weakness in our program in that the rotation is not centered on the sprite. We fix it by adding this line on the @INIT subroutine.

SPHOME 1,8,8

Then we simply add these lines to the LEFT and RIGHT portion of the code:


  1. @TTL
  2. A=A-N:'TURN LEFT
  3. GOSUB @ROTATE

  4. @TTR
  5. A=A+N:'TURN RIGHT
  6. GOSUB @ROTATE



And there you go! Just one more function and that's all there is to it! Who says turtle graphic programming is hard? Haha, joking aside, we have been delaying the inevitable. Not only we have to convert degree to radians, but we also have to make sure that the turtle is facing the right way. Fortunately, there are functions RAD(),SIN() and COS() that makes it simple. There is something else that we have to worry about, but we'll defer that until later. For now, let's draw!


  1. @TEST
  2. FOR A=0 to 360 STEP 360/12
  3. SPOFS 1,128,96:GOSUB @ROTATE
  4. X1=50*SIN(RAD(A)):'RSINTHETA
  5. Y1=50*COS(RAD(A)):'RCOSTHETA
  6. SPOFS 1,128+X1,96+Y1,50:'50 IS THE DISTANCE
  7. WAIT 60
  8. NEXT


If you run this code, you will see that the whole thing breaks up. You see that the sprite and the movement do not match. We want to see the sprites to move in a clock-wise pattern. The problem now is how to fix it? Remember that the coordinate is centered at top-left? That's the problem! To the math savvy among you, it may interest you to come up with the solution yourself. Otherwise, here's the fix!

Y1=-50*COS(RAD(A)):'RCOSTHETA

Yes, it's that easy! Simply turn R into negative R, and that's all there is to it. Really. Now, all we have to do is do the @TTF subroutine and we'll be done!


  1. @TTF
  2. D=N
  3. X1=D*SIN(RAD(A))
  4. Y1=(-1*D)*COS(RAD(A))
  5. SPOFS 1,X0+X1,Y0+Y1,D
  6. @TTF1
  7. SPREAD(1),TTFX,TTFY:'GOSUB @WRAP
  8. IF C!=0 THEN GPSET TTFX,TTFY,C
  9. IF SPCHK(1)!=0 GOTO @TTF1
  10. X0=X0+X1:Y0=Y0+Y1


And that's it! You're probably wondering why we're doing interval D on SPOFS. The reason for it is so that we can retrieve sprite coordinates TTFX,TTFY along the way, and plot the points with color C. That's a pretty neat trick. Otherwise, we'd have to mess around with line drawing algorithm. Not that coming up with line drawing algorithm is bad, just that it's an unnecessary complexity if all that we want is a simple subroutine.

Oh, one more thing: Suppose we want to do a wrap around? What should we do? Well, I don't like to mess with the current code, but basically, what we want to do is adjust the sprite location and update the target accordingly. So, we need to check whether TTFX or TTFY is below zero and if so, shift everything by the screenful. Trivial, had we did our own line drawing algorithm. Not so much if we're dependent upon internal routines, just like we did.

What exactly do we need to implement coordinate wrapping, anyway? Well, we need the start and stop coordinates, which are X0,y0 and X1,Y1. We also need a coordinate that specifies the current location going there. And we want to be able to reset the coordinates from the sprites.

So, we can do a bunch of calculation, but basically, we want to handle these 2 lines:

SPOFS 1,NEWX,NEWY
SPOFS 1,ADJX,ADJY,TIMELEFT

So, we need 5 variables to be set. To the math savvy among you, I suggest that you work it out yourself.

Time left is easy. We have already have D. For the new D, all we have to do is calculate the distance of the current position with the target coordinate. TIMELEFT=SQR((X1-TTFX)^2+(Y1-TTFY)^2) The old distance formula standby. NEWX and NEWY is simply OLDX=OLDX+256 and OLDY=OLDy+192. Basically, screen width and height. Same thing with ADJX and ADJY.

There's nothing to it, is there? We need to add WRAP=1 and replace the commented 'GOSUB @WRAP with IF WRAP THEN GOSUB @WRAP.

Before we do a bunch of complicated math, though, I'll point out to you something very interesting. The fact that there is only one GPSET makes it easy. If we don't care about drawing the point where the turtle is, and just worry about wrap, we can easily modify the line to this:


  1. IF C!=0 THEN GPSET ((TTFX+256)%256),((TTFY+192)%192),C
  2. IF SPCHK(1)!=0 GOTO @TTF1
  3. X0=((X0+X1+256)%256):Y0=((Y0+Y1+192)%192)
  4. SPOFS 1,XO,YO


That's something to think about. Do we want to write some complicated routines or do we just want to get the job done? With that in mind, instead of doing a bunch of mathematics, we can simply create a secondary sprite and put it into the current point set whenever the original turtle is out of bound! Simple, yet effective!


  1. @WRAP
  2. SPOFS 2,((TTFX+256)%256),((TTFY+192)%192)
  3. SPANGLE 2,A,0
  4. RETURN


And that's all there is to it! We can easily implement this within one hour. With wrap function, we're pushing it into the hour, depending on how fast you can type with the stylus. Regardless, we're only typing less than 100 lines program, with testing subroutine. What's the test? Well, remember that we're limiting the data to only 2 digits? That helps when we're doing wrapping test cases. But how about when we want to do large drawings? The test subroutine is used throughout the development process in order to try out subroutines outside the main program.

I commented out the test subroutine in the final program, but it's a good example on how you can use it in your program, so I'm leaving it there. The total time that it takes to do this program is:

15 min Initial Framework
10 min C and P command
10 min Rotation
15 min TTF drawing
10 min Wrap option

Total Development time? 1 hour, including screen wrap function. Now that's what I call "Hour of Code"!





  1. REM TURTLE GRAPHIC
  2. REM BY HARRY HARDJONO
  3. REM DEC 2013

  4. ACLS:CLEAR

  5. @INIT
  6. WRAP=1
  7. C$="":'COMMAND STRING
  8. N=0:'COMMAND PARAMETER
  9. X0=128:Y0=96:'TURTLE POSITION
  10. X1=0:Y1=0:'TURTLE DESTINATION
  11. A=0:'ANGLE
  12. D=0:'DISTANCE
  13. C=0:'PEN COLOR
  14. SPSET 1,139,0,0,0,0:SPOFS 1,X0,Y0
  15. SPHOME 1,8,8
  16. SPSET 2,139,0,0,0,0:SPOFS 1,-255,-255
  17. SPHOME 2,8,8

  18. @MAIN
  19. 'GOSUB @TEST
  20. 'CLASSIC RECTANGLE
  21. FOR I=1 TO 8
  22. C$="F35R90F35R90F35R90F35R90"
  23. GOSUB @TURTLE
  24. NEXT

  25. @END
  26. BEEP 6:WAIT 600
  27. END

  28. @TURTLE
  29. IF LEN(C$)<3 THEN RETURN
  30. TC$=LEFT$(C$,3)
  31. N=VAL(RIGHT$(TC$,2))
  32. TC$=LEFT$(C$,1)
  33. C$=RIGHT$(C$,LEN(C$)-3)
  34. TN=INSTR("FLRCP",TC$)
  35. ON TN GOTO @TTF,@TTL,@TTR,@TTC,@TTP
  36. GOTO @TURTLE
  37. @TTF
  38. D=N
  39. X1=D*SIN(RAD(A))
  40. Y1=(-1*D)*COS(RAD(A))
  41. SPOFS 1,X0+X1,Y0+Y1,D
  42. @TTF1
  43. SPREAD(1),TTFX,TTFY:IF WRAP THEN GOSUB @WRAP
  44. IF C!=0 AND WRAP==1 THEN GPSET ((TTFX+256)%256),((TTFY+192)%102),C
  45. IF C!=0 AND WRAP==0 THEN GPSET TTFX,TTFY,C
  46. IF SPCHK(1)!=0 GOTO @TTF1
  47. IF WRAP==1 THEN X0=((X0+X1+256)%256:Y0=((Y0+Y1+192)%192):SPOFS1,X0,Y0
  48. IF WRAP==0 THEN X0=X0+X1:Y0=Y0+Y1
  49. GOTO @TURTLE

  50. @TTL
  51. A=A-N:'TURN LEFT
  52. GOSUB @ROTATE
  53. GOTO @TURTLE
  54. @TTR
  55. A=A+N:'TURN RIGHT
  56. GOSUB @ROTATE
  57. GOTO @TURTLE
  58. @TTC
  59. C=N:GCOLOR C
  60. GOTO @TURTLE
  61. @TTP
  62. IF N==0 THEN GPAINT X0,Y0,C ELSE GPAINT X0,Y0,N
  63. GOTO @TURTLE

  64. @TEST
  65. WRAP=1:'0 OR 1
  66. FOR SP=0 TO 150 STEP 3
  67. V=SP:LOCATE 0,0:?SP
  68. @LINER
  69. IF V>99 THEN C$="F99":GOSUB @TURTLE:V=V-99:GOTO @LINER
  70. L1$=RIGHT$(("000"+STR$(V)),2)
  71. C$="F"+L1$+"R70C"+L1$:GOSUB @TURTLE
  72. NEXT
  73. RETURN

  74. @ROTATE
  75. IF A<0 THEN A=A+360:GOTO @ROTATE
  76. A=A%360:SPANGLE 1,A,6
  77. RETURN

  78. @WRAP
  79. SPOFS 2,((TTFX+256)%256),((TTFY+192)%192)
  80. SPANGLE 2,A,0
  81. RETURN



Thursday, December 19, 2013

Book Review #15


The Reluctant Entrepreneur
Michael Masterson

"Turning Dreams into Profits"

Ha! Right. If I have a nickel every time I hear that sales pitch...

Except in this case, he's right. One advice after another, and they're all good. I probably won't be able to follow them all, but I can imagine tripling my productivity if I can only follow half. The book pulls no punches. It's not exactly step-by-step to success, but it does follow a definite path toward success. Along the way, you are guided to question not only your commitment, but also those around you.

Some wise words are sprinkled in here and there, and I appreciate them. The truth is, after reading this book, I never want to put it down. Hard cover edition is notoriously expensive. I don't care. This one is a keeper!

Not everybody can be an entrepreneur, and if you don't want to be one, this book won't make you one, even if you follow all the steps. But if you truly want to be a successful entrepreneur, this book gives you a great head start.

Tuesday, December 17, 2013

Raspberry Pi Journal #41


Portable Webcam Network cron @reboot

Okay. Last time we messed around with webcam, we messed around with motion daemon as a service. Well, I found out an easier way to do it. So, the first thing we want to do is to disable the motion service. This, of course, after spending a whole day setting it up. Siiiiiiiiigh.


  1. Go to /etc/default
  2. Open up motion file
  3. change the line start_motion_daemon=yes to start_motion_daemon=no
  4. Go to /etc/motion
  5. set motion not to run as daemon in motion.conf (daemon off)
  6. set process_id_file as undefined
  7. Goto to home directory
  8. run crontab -e
  9. Add the line @reboot motion &



And that's it. Just one little @reboot word in the right place. It runs the program at boot (and reboot) time. That's all there is to it. For bonus, it runs as the proper user, so file permission isn't a problem. Make sure that it runs in the background (enable daemon) on motion.conf. Tada!!! Done! 10 minutes!

Monday, December 16, 2013

Cooking Journal #17


Rolled Sushi


If you are interested in sushi at all, you probably have one of those sushi making kit. The truth is, you don't really need it. But if you have it, I'll show you how to do it real quick.

You need nori sheet. That's seaweed. I bought the cheap kind, which is not what you want. You want the nice flat kind with smooth surface on one side. Mine, as you can see, is bumpy all over.




Lay down the nori sheet on bamboo mat, shiny side down. Put rice and meat on top. I use spicy hot dog cut length-wise. If you want, you can add some veggies like cut carrots or celery sticks. You can use condiment. I like to use sriracha on mine. No need to use wasabi on it unless you crave authenticity.




Roll the sushi using bamboo mat. The most important point is to press evenly along the spine. Firm enough to press the rice, but not so hard as to compress them solid. By the way, use two hands while doing it. My other hand was holding the camera.

Also, I should tell you that the bamboo mat is optional. One time, I was doing it, and I realized that I forgot to put the mat under the sheet. So what I did was pick up the paper towel and roll the sheet with it. Works just fine, although not as easy as with the mat.

Wet the end of the sheet so that it sticks together when rolled over.




And that's what you should have. One rolled sushi.



Cut into six equal length. Notice that I'm using a proper kitchen knife for this. Buck knife is not good enough for this. To be honest, even this sharp kitchen knife is less than ideal. The sharper the knife, the better! Use the sharpest knife you have, and use it only for cutting sushi rolls!



That's the result, and I can tell you that spicy hot-dog makes a good substitute for avocado used in California Rolls. Serve on plate with pickled ginger. I have yet to find a good substitute for pickled ginger. So that and the nori seaweed are the two must have ingredient for a good rolled sushi.

Saturday, December 14, 2013

Nintendo Journal #17


Automatic Blood Pressure Monitor



I'm maintaining my blood pressure. So far, I'm keeping 120/80. It has been at that for a long time. However, with good exercise, my recovery rate has improved tremendously. I'm thinking that in order to lower the levels, I must change my diet. Well, I'll have to think about that. Exercise, yes. Diet, less chance of it happening than a snowball in hell!

Friday, December 13, 2013

Petit Computer Journal #29

A Simple Sprite Game


I've always said that writing a computer program is pretty easy if you know what you're doing. The question is, how easy can it be? I've written a version of Snakes and Ladders game in under 10 minutes. How quickly and easily can I write a sprite based game? Certainly, not too difficult.

I'm curious as to just how easy it is to write one. Certainly, there is the control. I settled for Up-Down-Fire, which is a variation of Left-Right-Fire. I was hoping for a single screen challenge program, and I managed to do it. However, it isn't fun at all. Also, it turns out that I don't need the Up-Down movement at all. Just sit there and hit the fire button!


  1. CLS:Y=0:A=256:C=128:S=0
  2. SPSET 1,96,0,0,0,0:T=3600
  3. SPSET 2,40,0,0,0,0
  4. SPOFS 2,-16,0,0:SPANIM 2,2,15
  5. SPSET 10,13,3,0,0,0
  6. @LOOP
  7. T=T-1:IF T<0 THEN END
  8. VSYNC 1:B=BUTTON(0):DX=0:DY=0
  9. LOCATE 0,0:?"S=";S,"T=";T;" "
  10. IF SPHIT(10) THEN S=S+1:BEEP
  11. IF !SPCHK(10) THEN GOSUB @MM
  12. IF (B AND 16) THEN GOSUB @FR
  13. IF !(B AND 3) GOTO @LOOP
  14. DY=(B AND 3)*2-3
  15. Y=Y+DY:IF Y<0 THEN Y=Y+192
  16. Y=Y%192:SPOFS 1,0,Y,0
  17. GOTO @LOOP
  18. @FR
  19. SPOFS 2,0,Y,0:SPOFS 2,A,Y,C/2
  20. RETURN
  21. @MM
  22. SPOFS 10,99+RND(99),-20,0
  23. SPOFS 10,99+RND(99),2*C,C
  24. RETURN


It's all very well and good for a single screen challenge, but I was curious as to how much better it would be, had it been a better fleshed out game. So, forget about the single screen challenge and just do better!


  1. CLS:Y=0:A=256:C=128:S=0
  2. BGFILL 0,0,0,63,63,9,8,0,0
  3. FOR I=1 TO 32
  4. BGPUT 0,RND(64),RND(64),32,8,0,0
  5. NEXT
  6. SPSET 1,96,0,0,0,0
  7. SPSET 2,40,0,0,0,0
  8. SPOFS 2,-16,0,0:SPANIM 2,2,15
  9. FOR I=10 TO 70
  10. SPSET I,13,3,0,0,0
  11. SPOFS I,99,-50,0
  12. NEXT
  13. @INIT
  14. BGMPLAY 23
  15. T=10800:S=0
  16. @LOOP
  17. IF HYC<S THEN HC=S
  18. IF !BGCHK(0) THEN BGOFS 0,RND(512),RND(512),360
  19. T=T-1:M=FLOOR(T/180):IF T<0 THEN GOTO @END
  20. VSYNC 1:B=BUTTON(0):DX=0:DY=0
  21. LOCATE 0,0:?"$=";S,"TIME=";M;"   ","HI $=";HC;"   "
  22. FOR I=10 TO 70-M
  23. IF SPHITSP(I,2) THEN S=S+1:BEEP 3:GOSUB @HIT
  24. IF !SPCHK(I) THEN GOSUB @MM
  25. NEXT
  26. IF (B AND 16) THEN GOSUB @FR
  27. IF !(B AND 3) GOTO @LOOP
  28. DY=(B AND 3)*2-3
  29. Y=Y+DY:IF Y<0 THEN Y=Y+192
  30. Y=Y%192:SPOFS 1,0,Y,0
  31. GOTO @LOOP
  32. @FR
  33. SPOFS 2,0,Y,0:SPOFS 2,A,Y,C/2
  34. RETURN
  35. @MM
  36. SPCHR I,13
  37. SPOFS I,99+RND(99),-20+256*RND(2),0
  38. SPOFS I,99+RND(99),-20+256*RND(2),99+RND(C)
  39. RETURN
  40. @HIT
  41. SPCHR I,248
  42. SPANIM I,8,6,1
  43. RETURN
  44. @END
  45. BGMPLAY 6
  46. WAIT 360
  47. FOR I=0 TO 16:I=BUTTON(0):NEXT
  48. GOTO @INIT


So far, I'm using standard graphics. It's very convenient that the graphics are all built-in. However, there is always a way to have custom made graphic. I won't list the source code, but check out the QR made for this game.

http://petitcomputer.wikia.com/wiki/Santa_Helper










Thursday, December 12, 2013

Book Review 14


Book #14 Getting Started with Processing
Casey Reas and Ben Fry

First of all, I love the Processing language. It's fun, portable, and easy to learn. I abhor the name. Why? Because every time I google it, I never found it! Really, I think Proce55ing is better because when I google that, it goes right to the site!

So, having actually learned the language, why did I pick up the book? Because I love the language and I want as many people to use it as possible. The book is interesting because it is the first "Getting Started" book from O'Reilly that I found. And I found out that hand-drawn sketches makes perfectly usable illustrations, even when it can best served with computer graphic or CAD.

I find the book features just the right amount of personal touches for the artist in me, and yet not skimp on the technical side for the scientist in me. A rare treat that is yet to be duplicated from other "Getting Started" books.

The only complaint that I have is that the subject matter is too brief. It touches on other Processing usage, such as Arduino. However, I think that extra projects such as Arduino is best left to other "Getting Started" book. You can put a mention there, of course, but let's not dwell upon them.

All in all, a good book marred only by trying to be comprehensive in a small book. Highly recommended.

Tuesday, December 10, 2013

Raspberry Pi Journal #40


Portable Webcam Software - motion



Last part, we have all the software and hardware installed and ready to go. In this section, we are going to set up the software that does the motion detection: motion.

First, we're going to SSH into the device:

SSH hostname

Enter your password. Next, we're going to set up a few configurations options. We want to set up some directories. We need to be careful here because we're going to run the software as daemon, which means its own user name and priviliges. The user name is called "motion". The password? I don't know. I can tell you that "sudo login" followed by "motion" and no password does not work.

So, the first thing we want is to set up a directory for the webcam. I'm going to set it up under /home/common/webcam


  • sudo mkdir /home/common/
  • sudo mkdir /home/common/webcam
  • sudo cd /home/common
  • sudo chown motion webcam
  • sudo chgrp motion webcam
  • sudo chmod 777 webcam


That will create a special webcam directory, that is accessible by all. Hopefully, nobody will login into it and cause trouble. I would prefer chmod 775, but let's make things easy for now.

Next, we need to configure the motion program and set up some parameters. Specifically, I want:

Save a picture per second everytime motion is detected, continue for about 10 seconds after.
Create a time-lapse movie for the day
Create a time-lapse movie for all motion capture
Set a webserver, so we can view it on the web browser
Create a log directory and file


So, the first thing we need to do is to locate motion.conf file. I found it in /etc/motion/ directory. Otherwise, check /usr/local/etc/ directory. If all else, you can do it the hard way:


  • cd /
  • ls -lR * | grep motion | grep motion


Yes, I did "grep motion" twice. I did it to filter out the error messages because I run the command as a normal user, instead of root.

So, let's get to /etc/motion directory


  • cd /etc/motion
  • ls -l


You'll see the files motion.conf, and thread1.conf-thread4.conf. This is because motion software can handle up to 4 simultaneous webcams. I'm using only one, so I don't have to worry about threadN.conf files. The first thing I want to do is make a backup or motion.conf before doing anything else.


  • cp motion.conf motion_conf_orig
  • sudo nano motion.conf


Next, I'll just scan the file and change the appropriate fields, according to my wish list above.


  1. daemon on
  2. width 640
  3. height 480
  4. framerate 2
  5. minimum_frame_time 1
  6. brightness 200
  7. threshold 6000
  8. noise_level 128
  9. pre_capture 1
  10. post_capture 10
  11. gap 120


All right, so that was for the camera settings. Now we go to the Image File Output settings:


  1. ffmpeg_cap_new on
  2. ffmpeg_timelapse 5
  3. ffmpeg_timelapse_mode hourly
  4. ffmpeg_video_codec mpeg4
  5. text_double on



Now that we have all the files set up. Let's set up all the file names and directories:


  1. target_dir /home/common/webcam
  2. jpeg_filename %H%M%S
  3. movie_filename %H%M%S
  4. timelapse_filename lapseview


Finally, we're into the server territory. We want to configure the ports for our webcam. There are two factors here: control and webcam. Control is the user interface for our webcam. webcam is the address that we want to use as mjpeg streamer to see what our camera see


  1. webcam_port 8081 <-change this to any open port you like
  2. webcam_quality 50
  3. webcam_motion on
  4. webcam_localhost off
  5. webcam_limit 600

  6. control_html_output off


And that should do it! There are other settings that I can use, especially the ones regarding picture/movie generation. This is useful if we want to copy the movie files somewhere.

So, now, let's reboot, and see if everything works as expected!


  • sudo reboot


and load a web browser, connected to the camera host address and port, and check to see if there's a web stream out there!

Pinging cloudypi seems to work, but I don't see the webcam being on? This where trouble starts. How come I can't start the process? Because there's something that I need to do, that is missing from the step. Reading the magazine, it says to set "start_motion_daemon yes" to motion.conf. And yet, reading the manual "man motion", it does not mention it at all!

So, which should I believe? The printed one? Or the one live on my device? Obviously, the one on my device. Is there no hope for me? There is something about user guide. Let's check it out:

/usr/share/doc/motion/motion_guide.html

Well, that didn't help at all. I know there's something that I need to change in order to start motion from boot, but what?

I tried to run motion from command line. Failed due to lack of permission. Create the motion.pid file, and change all permission.

sudo mkdir /var/run/motion
sudo touch /var/run/motion/motion.pid
sudo chmod 666 /var/run/motion/motion.pid

Now, let's see if it works. Well, the daemon works. The SSH hangs. Not good at all! In the end, I had to unplug the cable, and replug. Second time around, I got clever and use the setup mode:


  • motion -s -c /etc/motion/motion.conf


It works fine. I see avi, jpg, and mpg files. Set up is a success, now to automate it. There's quite a bit of assumption that you know how to start a program during boot, but as you can see, it's not obvious. With wrong headed instruction such as "start service" things, then I'm just as confused as ever.

However, there is the salvation that is the net. Digging around for hours did yield something. There is a motion file in /etc/init.d. Aha! Let's check it out.

It sure looks like one of those service files. So, maybe the instruction does mean something. Just not 100% accurate. Looking at the file, I see this:


  1. check_daemon_enabled () {
  2.     if [ "$start_motion_daemon" = "yes" ] ; then
  3.         return 0
  4.     else
  5.         log_warning_msg "Not starting $NAME daemon, disabled via /etc/default/$NAME"
  6.         return 1
  7.     fi


And the simplest thing is to go open up /etc/default/motion file and see what it says.


  1. # set to 'yes' to enable the motion daemon
  2. start_motion_daemon=no


Uh, I think we hit the jackpot, here! Are you kidding me? This is all that's needed? How come there's not one single line telling me to do this in the manual? Do you know how much time I wasted looking for this one line? Sigh.

Well, change it to "yes", and see what happens! Changed the file. Reboot. SSH into it. Run "top". Yes, it's up there. Check webcam directory. Does not seem to write to the directory. Stop the program and check it out.


  • sudo service motion stop


Further checking yields images still not being written. There's only one conclusion that I can gather: motion.conf is not being read correctly. Strange thing is, if I just start it normally, it works fine! So, back to /etc/init.d/motion and see if I can force motion.conf to be read.


  1. DAEMON=/usr/bin/motion -c /etc/motion/motion.conf


I just don't see how nobody is running into these kind of problems! Or if they did, they don't say. Did the setting somehow changed? I don't know. It certainly is frustrating. I know it is possible, but there's absolutely no instructions, and so, I have to try things out myself.

Did not work. After reading the manual for start-stop daemon, I came up with this:


  1. if start-stop-daemon --start --oknodo --exec $DAEMON -b --chuid motion -- -c /etc/motion/motion.conf ; then


That seems to work. Alas, no new images is loaded. So, maybe the configuration file is read correctly, after all, but then what is wrong with the process? Doing it interactively works fine, after all. Why would putting it into the service fails?

Interestingly, not only starting it manually with service fails to write images, but it somehow kicked the "output_motion on", and yet, checking it via the web control interface shows that it's off. Obviously, there's something seriously wrong here, but I don't know what. Gremlins, that's what it is.

Checked /var/log/user.log

It turns out that the program is having trouble writing to timelapse.mpg. I changed the attribute with


  • chmod 777 timelapse.mpg


And restarted the service. It works fine, now. Jeez. Do you know how long it took me to find that? There's just not enough instructions on the web!

So, reboot, and see if the process still hopefully works.

Everything looks good to me! Well done!

And it only took one whole day!

Monday, December 9, 2013

Cooking Journal #16


Cooking Sushi


Probably not the best title. You're probably wondering: It's Sushi! What is there to cook? Actually, sushi refers to the vinegared rice or sumeshi. There are all kinds. Rolled sushi, finger sushi, scattered sushi, and pressed sushi.

The one I like to make is actually scattered sushi, which is vinegared rice in a bowl with ingredient scattered on top.

Finger sushi is the one you find in a good sushi restaurant. It takes skill to press sushi and meat just right.

Rolled sushi is the one you find in a supermarket. It's relatively easy to make, and makes a nice presentation. Better than the scattered sushi type.

I've never seen pressed sushi. I imagine it's a cheap industrialized kind.




The traditional way to cook sushi rice is with wooden bowl. Once the rice is cooked, dump it into a wooden bowl. Sprinkle vinegar+sugar mixture, while fanning vigorously. The rice will then have the proper texture and consistency while having illustrious sheen on the surface.

Does it matter? Having done it that way, I'd say yes. It makes for a better sushi rice. Of course, my motto is "cheap, fast, and easy" and so I don't usually bother doing any of that.

I also just cook my regular long-grain rice, instead of special sushi rice.

As soon as the rice is done, I fluff the rice using bamboo spatula while sprinkling vinegar a little bit. As you can see, I use it straight from the bottle. I don't bother mixing a special solution for it. And no, I don't use wooden bowl to do it.

The result is less than ideal, but close enough to the real thing, that I don't mind at all. Of course, you may have a different opinion about it.

Then I simply put the rice into a bowl and top it off with some meat I have on hand. That usually means hot-dog.

What? You expect maybe some special sashimi for it? ;)


Saturday, December 7, 2013

Nintendo Journal #16


2 Bird Houses



Just a little something I pick up from Thrift stores. I'm using these as inpirations for craft projects. I had in mind using cardboard for the craft projects, but unfortunately, it petered out. Didn't work.

Oh, well. I'll think of something else. In the meantime, the left open birdhouse is used as pen holder. The right one is perched on top of my bookshelf.

Friday, December 6, 2013

Petit Computer Journal #28

Petit BrainF

Yeah, I was wondering just exactly how hard it is to implement a language that has only 8 operators involved. Not hard at all! Of course, I cheated and used graphic screens for my memory. It'll be probably a bit more complicated if I use straight memory. A bit.

The program cannot fit into one screen, but it's certainly a candidate for less than 100 lines program. It took me a couple hours because I was careless in moving the pointers.

The CYCLE subroutine is there to keep the variables within range, and the FB subroutine is there as a debugger that I use when debugging the program. So, I commented it out in the final version.

Another person, IAmAPersson (what a name!) was working on a version of the compiler as well. Check Petit Wikia for it. Maybe he posted it there by now.

I don't know the policy of this blogspot, but I know my policy and that is family friendly. I don't want to use the full name of the program. Thank you. Next time you designed a programming language, make sure you name it proper!



  1. REM PBF BY HARRY HARDJONO
  2. @INIT
  3. ACLS:CLEAR
  4. GPAGE 0:GCLS
  5. GPAGE 1:GCLS
  6. MS=30000
  7. PTR=0
  8. PC=0
  9. MPC=0
  10. CSR=0

  11. GPAGE1:RESTORE @HELLO
  12. @LOADP
  13. READ A$
  14. IF A$=="" GOTO @RUNP
  15. FOR I=0 TO LEN(A$)-1
  16. GPSET PC%256,PC/256,ASC(MID$(A$,I,1))
  17. PC=PC+1:NEXT
  18. GOTO @LOADP

  19. @RUNP
  20. PC=0:GPAGE 0
  21. @LOOP
  22. GPAGE 0:VAR=GSPOIT(PTR%256,PTR/256)
  23. GPAGE 1:C=GSPOIT(PC%256,PC/256)
  24. 'GOSUB @FB
  25. IF C==62 THEN PTR=PTR+1:GOSUB @CYCLE:GOTO @LOOP2 
  26. IF C==60 THEN PTR=PTR-1:GOSUB @CYCLE:GOTO @LOOP2
  27. IF C==43 THEN VAR=VAR+1:GOSUB @CYCLE
  28. IF C==45 THEN VAR=VAR-1:GOSUB @CYCLE
  29. IF C==46 THEN LOCATE CSR%32,CSR/32:?CHR$(VAR);:CSR=CSR+1:GOTO @LOOP2
  30. IF C==44 THEN GOSUB @GETCHAR 
  31. IF C==91 THEN MPC=1:GOSUB @SR:GOTO @LOOP2
  32. IF C==93 THEN MPC=1:GOSUB @SL:GOTO @LOOP2
  33. IF C==0 GOTO @END 
  34. GPAGE 0:GPSET PTR%256,PTR/256,VAR
  35. @LOOP2
  36. PC=PC+1:GOSUB @CYCLE
  37. GOTO @LOOP

  38. @FB
  39. LOCATE 0,5:?PTR,PC,VAR
  40. LOCATE 0,6:?CHR$(C)
  41. WAIT 6
  42. RETURN

  43. @CYCLE
  44. IF PC<0 THEN PC=PC+49152
  45. IF PTR<0 THEN PTR=PTR+MS
  46. IF VAR<0 THEN VAR=VAR+256
  47. PC=PC%49152
  48. PTR=PTR%MS
  49. VAR=VAR%256
  50. CSR=CSR%768
  51. RETURN

  52. @GETCHAR
  53. A$=INKEY$():IF A$=="" GOTO @GETCHAR
  54. VAR=ASC(A$):WAIT 30
  55. RETURN

  56. @SR
  57. IF VAR!=0 THEN RETURN
  58. PC=PC+1:GOSUB @CYCLE
  59. GPAGE 1:C=GSPOIT(PC%256,PC/256)
  60. IF C==91 THEN MPC=MPC+1
  61. IF C==93 THEN MPC=MPC-1
  62. IF MPC<=0 THEN RETURN
  63. GOTO @SR

  64. @SL
  65. IF VAR==0 THEN RETURN
  66. PC=PC+1:GOSUB @CYCLE
  67. GPAGE 1:C=GSPOIT(PC%256,PC/256)
  68. IF C==91 THEN MPC=MPC-1
  69. IF C==93 THEN MPC=MPC+1
  70. IF MPC<=0 THEN RETURN
  71. GOTO @SL

  72. @END
  73. WAIT 600
  74. END

  75. @PLOP
  76. DATA "-[>-[.-]<]"
  77. DATA ">>++++[.->++++++[.-]<]"
  78. DATA ""

  79. @CAT
  80. DATA ",[.,]"
  81. DATA ""

  82. @HELLO
  83. DATA "+++++ +++++ [>+++++++"
  84. DATA ">+++++ +++++ >+++ >+ <<<<-]"
  85. DATA ">++.>+.+++++++ ..+++.>++.<<"
  86. DATA "+++++ +++++ +++++"
  87. DATA ".>.+++. ------ .----- --- .>+.>."
  88. DATA ""