NOVICEGUARD HOME > >     StumbleUpon.Com Recommend to StumbleUpon

NoviceGuardLite (file: ngl/index.htm)

A new venture, new design!

An Arduino with...

Not fancy! NOT EXPENSIVE! Not (very) limited. LIMITED by your experience, imagination, maybe!

((q-alt text for image))

The image shows a half built NoviceGuardLite. Instead of the four LEDs and four switches I'm just about to explain, you see positions for the switches, LEDs, (and the resistors needed by the LEDs).

Four LEDs in a straight line.

Four switches under them. In everything a pupil would see, they are called Bu0, Bu1, Bu2, and Bu3. ("Bu" for "button", and to teach them that computer people count from zero.) In the image above, the pads for the four switches are labeled Sw0, Sw1, Sw2, Sw3.

The area marked "A" in cyan is where you plug in an Arduino Pro Mini (about $10).

Over at the right: Pads to access GPIO lines not "served" by the board.

At the left: A pair of link selectors, a pair of sets of pads. (And in the one you see, some messy wires... wires that are usually less messy!) These let you use two GPIO lines EITHER as inputs driven by a puch button, OR as inputs driven by a potentiometer or similar.

Odds and ends...

Before continuing the NoviceGuardLite material....

This section is for links to a few pages "sort of" related to NoviceGuardLite... but even more scruffy than THIS page! Works in progress, all... but Good Stuff present. If poorly presented.

((Some code that will run on the NGL. It is for driving NeoPixels... https://github.com/Flat-earth-academy/NGL-SmartLEDs))

((Ideas for "stuff to do" with arrays of LEDs.))

((Syntax shows some of what's allowed. Language structure is an essay related to that guide to structure. JS- Have a look. If the second is too much "heavy going", skip down to the end, have a glance at the "grand finale", but don't worry if you don't know everything in it by Monday. The first will sometimes help with "can't compile" issues.))

((Another day, another page... quite a "simple" one, this time... "words you should know"))

((And now... notes on using subroutines))

Back to "the main story"....

Levels...

What you can do with a microprocessor (e.g. Arduino... or Pi, or Micro:bit) depends on the following. (These essays are written with Arduino users getting the best service, but most of the ideas here apply perfectly well in other "worlds". If authors from those worlds want to work together with me, I would be pleased to hear from them.)

What you can do depends on...

This page will suggest challenges. They are here to give you ideas. If you can't think of something you want do, that you think you can do, try doing the things below. If you can think of something you would rather try, go for it! (But don't be too downhearted if you aren't successful... yet. Can you do something similar... but a bit simplified? Go the various online forums, get help there!)

Below, there are a number of "big sections". Each "big section is defined by some hardware that is necessary for all of the challenges in that section. They "build", like your years of schooling were intended to build. Do the first section first. In the next section, you will continue to use the assets of the previous section... plus some more.

Within each "big section", there are "subsections". They are defined by things you need to know on the software side. As with the big sections, the second sub-section presents challenges which can be accomplished using skills required by that sub-section and the one before it. Sub-section three uses skills from the previous two sub-sections, and so on.

By the way... this page is written primarily for users of Novice Guard Lite (NGL). Note that there is a very close correspondence between NGL and the fancier "full" Novice Guard. Most of the challenges here can also be tackled using the big Novice Guard. The main "problem" will be compensating for the different layout of the LEDs and buttons.

Things people can do with NoviceGuardLite...

====First Big section... ===========
- Hardware: Four LEDs.
Identify the LEDs by the following "names": LED0 ("LED zero"... computer programmers often number things from zero, instead of the more usual "one".) Call the others LED1, LED2, and LED3.

Software....

You need to understand that all Arduino programs have two essential ingredients: The "setup()" part, and the "loop()" part.

You need to have the right "pinMode(xxx,value)" lines to put in the setup() part. You don't have to understand them! (At this stage.) But you do have to remember to put them in!!

You need "delay(mmm)" and "digitalWrite(xxx,state)"

With no more hardware or software that that, you can "do stuff". Not the most amazing stuff, admittedly... but many people have found it fun, in its way, for a bit.


In delay(mmm), you put a number in place of the "mmm". It sets how long the delay will be, in milliseconds. ("delay(500)" makes the program pause for a half second.)


In "digitalWrite", for "xxx", for NGL, please use pLED0 or pLED1 or pLED2... etc. (If this doesn't work, be careful that you have included the lines you should have been told to near the top of the program. Things like...

const byte pLED0=13;//Leave in const byte pLED1=12;//Leave in

Beware! The numbers you've been given may be different that what you see above!




First challenge!...

Basic Blinky: Make one of the LEDs go on/ off/ on/ off... This is the Great "Hello World" program for all microprocessors. (Known in the Arduino world as "Blinky". (The first thing programmers do with a new language or a new machine is to get it to put "Hello World" on the screen. Arduinos and the like not having screens (easily), winking an LED takes the place of that.)

Change....



Create pretty patterns in the LEDs! "The point" is not that any display on four LEDs is going to be breath-taking. The point is the fun you can have with the challenge of Making It Work!!! Will you find it fun? Who knows. Many before you have, though. Not fun yet? Maybe you haven't thought of a fun pattern.

Try to come up with your own ideas of a pattern to create, and finding a way to get it out of the NGL (NoviceGuardLite). But in case you are stuck, you can try these...


-

Make the LEDs come on one after the other, with only one on at any given time.




-

Make the LEDs come on one after the other, as before, but this time, once an LED comes on it stays on. So you start with one on, then you have two, then you have three, then all four... and then they all go off, and it starts again.



A long time ago, engineers got tired of the shortcomings of English, and devised diagrams to "say" things. The diagrams say the same things, but quickly, with less ambiguity. In the following, when the line is high, the LED is on. When it is low, it is off. The vertical lines aren't really important, and are pretty meaningless. (The lines are graphs of the LED's state over time. What does any part of a line between "on" and "off" mean? What is the LED when it is between "on" and "off"? It "doesn't do" many degrees of "on", after all.) But the vertical lines are traditional, perhaps because it makes drawing the diagrams easier. It also makes reading them easier on the eye.)

Each "squiggly line" below is a DIFFERENT challenge. None of the lines are related to one another. Some of the lines "say", in a different way, what I said earlier when I presented the first simple challenges.

-

Some of those lines show challenges which were presented earlier. Can you spot them?

Try to make your NGL behave in each of different ways described by the squiggly lines.

Software....

Now try making more than one LED do things. In the following, there are several squiggly lines for each challenge. Within each section, each squiggly line is what one LED is doing.

Again, make sure you can do all of the challenges. And along the way, I hope you will find yourself thinking of your own patterns of blinks to make the LEDs do.

Obviously, we are just getting started, but I hope already you will be discovering the buzz that Making It Work gives some people... I hope you are one of them?!

In the diagram below, there are three separate challenges. Isn't this description of the challenge (once you get the nag of it!) = better? "Picture worth a thousand words" and all that?

-

====Big section... ========== - Hardware: As before, plus some push buttons identified Bu0 ("BUtton zero") and Bu1. Maybe more than two.

Software highlights of this section: This is a huge section for new bits of software. Take your time. It doesn't have to be "finished" in twenty minutes!

We use variables for the first time, and meet a useful tool: the "serial monitor". We use the "if" statement, and the "do"... "while" structure (Plus a few useful constants.) But we won't need all of those things for the challenges in the first software section in this (bigger) hardware section. (Many hardware sections have several software sections.)

We've already met "input" and "output"... two thirds of "all computing". (The remaining third is the "processing" which goes on between the input arriving and the output being generated. We've "done" processing, too... it just isn't as "in your face" as the other two, and we haven't done very much of it. Variables help us do processing.

--- The importance of variables... and what they are, and how we use them... is a bit like the issue of "what is processing"? It isn't as obvious, or easy to state as "what is input?" "what is output?"... but when we start doing things with them, as we will in a moment, I think their importance will begin to emerge. You can use them without "understanding" them!

--- The "useful tool" is the serial monitor. It allows us to put writing on the screen of the big computer we are using to program our Arduino... a form of output. How is that "useful"? That's also something that I think will become obvious as we go along.

Software....

You need: digitalRead and if.

You should be starting to use "comments, also known as "rems".

You'll use three new "little" things. None of them hard: millis(), random(xxx) and randomSeed(xxx)

In "digitalRead", for "xxx", for NGL, please use pBu0 or pBu1 (etc). (If this doesn't work, be careful that you have included the lines you should have been told to near the top of the program. Things like...

const byte pBu0=3;//Leave in const byte pBu1=2;//Leave in

Beware! The numbers you've been given may be different that what you see above!


Useful built-in constants: You can always use HIGH, LOW, true, false anywhere in a program. Note: They are case-sensitive: "high" won't do for "HIGH", "TRUE" won't do for "true". Annoying. But... true!


"If" statements look like...

if (condition) {block-stmts} else {block-stmts}

Here's a tiny example, with no "else".

if (digitalRead(pBu0)==HIGH) { digitalWrite(pLED0,HIGH); delay(100); digitalWrite(pLED0,LOW); delay(100); }

(Remember if your condition asks if two things are equal that you need to use a double equals sign.)




First challenge in this section...

Challenges...

A simple doorbell! (Where you have an LED, you could have a buzzer.) If Bu0 is pressed, LED0 goes on. (It is off, otherwise.)


Make the NoviceGuardLite light LED0 when Bu0 is pressed, light LED1 when Bu1 is pressed, and light LED2 when Bu2 is pressed. Each goes off again as soon as it's button is released.


Make something similar to the result of the previous challenge, but using only Bu0 and Bu1, and the first two LEDs. However, this time, the LEDs "latch"... that is, once they come on, they STAY on.... until Bu2 is pressed. Only then do the LEDs go off again. This simple (and not hard to program) setup isn't much "fun", but it simulates a vast range of devices... consider a burglar alarm... once the burglar as been detected, it is no use if the bells stop ringing as soon as he goes away again, is it? The "detect burglar" electronics look just like a button being pressed to the alarm system. (The alarm system uses a bell, of course... and hooking up a bell is just like hooking up an LED.)


Make a "thing" to show about binary numbers... In the following, "p" means pressed, "n" means "not", "*" shows an LED that is on, "." shows an LED that is off....


   Bu0  Bu1  LED0  LED1  LED2
    n    n    .     .     .
    n    p    *     .     .
    p    n    *     *     .
    p    p    *     *     *

Here's what the above is all about: We are treating the two buttons as the digits of a two digit binary number. Not pressed stands for a zero, pressed stands for a one. And the patters we can have with 2 buttons are: 00, 01, 10, 11. They "translate" into the decimal numbers, 0, 1, 2, 3... and in our device, you get zero, one, two or three LEDs lit, depending on which buttons are down. Get it? (^_^)

Such tables are usually written as follows....


    Bu0  Bu1  LED0  LED1  LED2
     0    0    0     0     0
     0    1    1     0     0
     1    0    1     1     0
     1    1    1     1     1

That information can also be presented by "squiggly line" diagrams like the ones we used previously. I've done one below. This time some of the lines show you the inputs (The state (pressed or not) of the buttons.), and some of the lines show (as before) the outputs (The state of the LEDs (on or off).)

-

Another challenge: write something which has two different patterns of blinking LEDs. One that happens if no buttons are pressed, the other happens (eventually) if Bu0 is held down. For now, don't try to make it "perfect". ("Perfect" would be a program that changes the blink pattern as soon as the button is pressed... You may notice that your program doesn't respond immediately. We will be able to achieve that eventually, but it would be hard with the amount of software you know so far.)

Once you get the previous achieved, ask yourself what it would take to have a system that could do more than two blink patterns. If you're pretty sure you answer would work, don't worry too much about actually writing the code.... it could be a bit tedious. But if in doubt, see what you see when you try your idea.

Software.... In addition to the above, now we'll use variables.

The "do"..."while" structure looks like...

do {block-stmts} while (condition)

... and to use it, we need a variable. In our simple example, the variable we are using is bCount

byte bCount; bCount=1;//Here, we put "0" into the variable "bCount" while { // The "{" marks the start of a block of statements digitalWrite(pLED0,HIGH); delay(100*bCount);//"100 TIMES the number in bCount" digitalWrite(pLED0,LOW); delay(100); bCount=bCount+1;//We change the number stored in the variable. ONE equals sign, notice. }//end of the block of statements we are "Do"ing. until (bCount==5);// The "exit condition". Note: TWO equals signs, be cause we are asking if bCount has 5 in it. Asking "are they equal?"

What does that program do? Don't be downhearted if you can't answer immediately. Look at it, make sure that you see it will cause the LED to wink... but for a longer and longer time, until it is winking on for 500ms.

Software.... In addition to the above, now we'll use the serial monitor.

Start of biggish section. This goes down to "end of Serial Monitor Introduction"

Time to meet "the serial monitor". We'll also use variables some more. This means a longer than usual "new software tools" sub-section header... but normal service (a list of specific challenges) will follow shortly.

The serial monitor is a tool that is available to help you in your programming work. It isn't something to "put in a program", like, say, a "do"..."while" structure.

(This section needs work! Sorry!...)

Here's a small program which shows the serial monitor in use. Remember: You have to "open" the monitor window. You can do this before or after uploading some code.. but don't try to do it while you are uploading code.

//------------------- int iCount=0; //------------------- void setup() { //(all the usual "leave in" things... plus....) Serial.begin(9600); Serial.println("Hello programmer."); }//end of setup() //-------------------- void loop() { if (digitalRead(bBu0)==LOW) { Serial.print("The button is pressed. "); Serial.println(iCount); };//end of "if..." delay(400); iCount=iCount+1; }//end of loop()

A longer page exists at... http://sheepdogguides.com/arduino/aht1serimoni.htm... Don't worry about the "warning" regarding RS-232, if you are just using the serial monitor to "see what the program is doing". I.e. if all of the output to it is going to arise simply from Serial.print("Hello World" type stuff.

One detail, before we get to the challenges made achievable by knowledge of the serial monitor...

An Arduino does not need to be connected forever to the big computer used to program it. Once the program has been uploaded to the Arduino, the Arduino can be disconnected from the big computer.

It will still need power! But it can be given this over the same cable as was used to program it, but plugged into a mere USB charger.

"End of Serial Monitor Introduction"

First challenge in this section...

Challenges...

We'll see some more useful challenges in a moment. For now, redo the "doorbell" challenge so that once every 500ms message appears on the serial monitor saying either "No button pressed", or "Button zero pressed" or "Button one pressed". That much is quite easy.

But if you have done it "the obvious way", it will be flawed! It will be possible, if you time things properly, to press a button briefly and have nothing but "No button pressed" messages on the screen!


I'll give you help in the form of some unfinished code in a moment.

The program "translates" from binary to decimal. If the user presses all 3 buttons down, the output is "7", because binary "111" is decimal 7.

In it, the program...

Sets up three variables: bState0, bState1 and bState2.

Reads each of the buttons, and as they are read, sets the associated bState to 0 if the button is not pressed, to 1 if it is set.do something like.

Then, using a bunch of "if"s, with multiple conditions, the state of the buttons is "translated" to a character, 0, 1, 2... 6, or 7 (depending on which buttons are pressed), and the "answer" sent to the serial monitor.

void loop() { byte bState0;//Create the variable. byte bState1; byte bState2; //------------------- //See if buttons pressed or not, store answer in // variables... if (digitalRead(pBu0)==HIGH) {bState0=0;} else {bState0=1;} //The above four lines will be (nearly) repeated // two more times... to do the same thing // to bState1, bState2, based on whether the // other buttons are pressed. //-------------------- /*The next DOES the println... IF.... bState2 is equal to zero, AND bState1 is equal to zero, AND bState0 is equal to zero */ if (bState2==0)&&(bState1==0)&&(bState0==0) {Serial.println("0");} if (bState2=0)&&(bState1==0)&&(bState0==1) {Serial.println("1");} if (bState2=0)&&(bState1==1)&&(bState0==0) {Serial.println("2");} //... etc! There will be 5 more like the above 3 delay(400); }//end of loop()


A "challenge" to show off millis()

"millis()" "returns" a number.

Run a program with not much in it, and in loop, just...

void loop() { Serial.println(millis()); delay(1000); }//end of loop()

... and open the serial monitor when you run it.

You should see numbers appearing, one per second. And each about 1000 bigger than the last.

Add...

do {delay(10); } until (pB0==LOW);

The program will "get stuck" in that loop if the button is pressed, and stay there until the button is released.

And when it is released, the stream of numbers will resume.

The numbers you were getting before might have been something like...

254017
255019
256023
257026
258030...

Adding about a thousand each time, starting from 254017.. so the bottom three digits have stayed near 020 since when we began.

If you pause the program for a bit, unless you pause it for exactly a second, you'll find that the "start number", to which 1000 is added over and over, changes.

Useful? Probably not! But helps you understand "millis()" I hope.


Write a similar program, but this time it says...

Add...

Serial.println(random(16)); delay(500);

The program will give you a stream of numbers. They smallest will be 0, the biggest 15. (See what happens if you change the 16 in the program given.)

They are picked "at random". Except they aren't exactly. Worst of all: You get the SAME random numbers each time you run the program!

This "sameness" can be fixed.

In the setup() part of the program, insert...

Serial.print("Press and release Bu0 to start the program"); do {delay(10); } until (pB0==HIGH); randomSeed(millis());

.. and when you run the program, it will enter the do.. delay... until loop. Notice that the test to exit the loop has changed.

How long you are in the loop will depend on how fast you press the button. So the number in millis() a moment later will be different each time. And you get different sequences of "random" numbers if you have done "randomSeed" with different numbers.

(When you know about analogRead(xxx), you will see why people usually use...

randomSeed(analogRead(xxx));

It works too, and you don't have to press any buttons!


Challenge: "Dice machine"... simulates throwing dice. Well. A die (one of them.) Well... at first, one with only four sides. Better than a flip-the-coin simulator!

First step: Write a program which waits for you to press a button. When you do, a random number from 0 to 4 is sent to the serial monitor.

Next level: Now make the number appear on the LEDs... light up LED 0, 1, 2 or 3 depending on the number from the random number generator.

Next level. This to make it "more exciting" for the user...

When you press the button, an LED starts flashing. The "answer" from the "die machine" appears when you RELEASE the button.

Fancier. Make the LEDs flash randomly (different LEDs, different numbers of LEDs in each flash) while the button is pressed.

Fancier... go for a 6 sided die. Do it two ways... once on the LEDs. You can assum the user knows the binary code. Once on the serial monitor, using crude graphics, i.e. show a "5" like this...

*   *
  *
*   *

====Big section... ========== - Hardware: As above, plus one or two potentiometers feeding analog inputs. Names: VR0 ("Variable Resistor zero"), VR1.

Our last big section! We have enough basics!

Prior knowledge expected: Simple use of variables, use of the serial monitor, "random(xxx)", "randomSeed(xxx)", millis()". The "if" statement, the "do"... "while" structure, reading button presses, and running one or more LEDs. By simple means.

Two words in that need to be well understood: "analog" and "potentiometer".

"Analog" is the complement of "digital". Anything digital has only two states: On/ off or +ve voltage / no voltage. Anything you like... Up/ Down, even... as long as there are only two possible states for "it".

When there are more than two states... the volume of a TV, for instance... you dealing with an analog parameter. The TV can be off... or on very low, or on quite low, or quite loud, or very loud... or VERY VERY LOUD!". This make the TV's volume an analog "thing".

Temperature makes another nice example of an analog parameter.

Just tuck that information away. I think you'll see why it matters in a moment.


-

Potentiometer:
The diagram is trying to show a pot. It is what's in the green part. It has three connections to the outside world. (I've made dark blobs at the connection points.)

Another name for the potentiometer, or "pot", is "variable resistor". That's why there's the resistor symbol (rectangle) as part of the pot symbol.

There is a resistor inside the pot. One end is connected to "Vcc", "the positive end of your battery", as it were, and the other to "ground", the "negative end of the battery", or "0 volts". "Ground", "negative" and "0" are (more or less) the same thing.

Inside the pot, there is a "wiper", and it can be moved by a knob on the outside of the pot. It connects the third leg of the pot to a point in the resistor... sometimes a point near the top, sometimes near the bottom, and sometimes near the middle.

-

In Case "A", the wiper is near the top of the resistor. Current flowing through it has not had to deal with very much of it yet. The resistor doesn't actually "split in two", as you might think I was trying to say with the diagram. But, if the whole resistor is 10k, then the current has passed through 1k's worth of it by the time it reaches the wiper, and have another 9k to go.

In Case "B" it is the other way around. By the time the current reaches the wiper, it has already passed through much of the resistor.

Now... if you were to attach a voltmeter to the wiper, you would find that the voltage on the wiper in Case "A" was nearly the 5v which happens to be Vcc in this instance. And in Case "B", the voltage would be nearly zero.

Hmmm.. "Voltage can be 5v, nearly 5v, nearly zero, actually zero". Sounds like an analog parameter... and it is!

While most of what's going on in a computer is digital, and while LEDs and pushbuttons only need digital outputs and inputs, there are many things which are analog. And the Arduino can handle them. In this section, we'll see how it deals with analog inputs.

Software....

I'll give you the answer to the first challenge for (almost) free. It involves a variable (iAnIno) and it uses the serial monitor. This time, you only have to say what "the challenge" was!

But before we get to that... add the following to the top part of the program, like the "const byte pLED0=13;//Leave in" that has been part of every program. (Put it near the pLED0=)

const byte pAnIn0=2;//Leave in
const byte pAnIn1=3;//Leave in

Right... that prepares the way for...

Put the following into your NoviceGuardLite (or big NoviceGuard, or other). Describe what it does so that a non-computer person can understand you.

//------------------- void setup() { Serial.begin(9600); }//end of setup() //-------------------- void loop() { int iAnIn0; //This is where we "declare" the variable. iAnIn0=analogRead(pAnIn0); Serial.println(iAnIn0); delay(800); }//end of loop()

Once you have that entered into an Arduino, run it. (By the way... each time you open the serial monitor's window, the Arduino is "reset". In other words, it starts its program again, from scratch. Re-does "setup()", and then goes into loop() and does that over and over.)

While the program is running turn the knob on the pot, and watch what numbers the serial monitor reports. (In theory, they can go down to (and including) 0, and up to (and including) 1023. How close it gets to each will depend on the quality of the pot.

Leave the program running, but close the serial monitor's page. Click on "Tools/ Serial Plotter". In a moment, something a bit like the serial monitor should appear. While it is on the screen, try turning the pot's knob. (It can plot several graphs at a time... If you send it three numbers per line, it will do three lines on the graph, in different colors.

In the little program above, we "declare" the variable iAnIno in the line with the rem saying that's what we've done. As always, we must declare a variable before we try to use it. (Declaring it makes the variable available to the program.)

In this case, we have said it will be of "type" "int", which is what we use if we want an "integer" type variable. Variables are a place where we can store stuff. "Int" type variables can only hold whole numbers, and only a certain range of numbers, at that. ("Int" type variables in and AtMega based Arduino (the common, "unfancy" ones) can hold any number from -32,768 to 32,767, inclusive.) (In other programming languages, an "int" variable could be different. For instance it might only hold positive numbers, or handle a different range of integers.)

So! Our little program has a variable- iAnIn0. We use analogRead to put a number in the variable. A moment later, we use Serial.println to output what's in iAnIn0 to the computer screen.

Challenge: Try taking the really simple program shown above and adding a few "if..." statements so that when the pot is turned so that the value in iAnIn0 is below 500... even if just a little below... no LEDs are on. If it is below 550, but above 499, the first LED is on. If it is below 600, but above 499, make it put two LEDs on.

Note the slightly fussy "below 500"/ "above 499" wording above. Computers are fussy. Successful computer programmers are fussy.

New challenge: Change what you have just written so that only one LED is on at a time. LED0 of the number in iAnIn0 is 0-499, LED1 if the number is 500-549, LED2 if the number is above 549. (You can use "the greater than" and "less than" signs, as necessary.)


Challenge: Do a version of Blinky, the microprocessor "Hello World" program we used a LONG time ago at the start of all this. But make how long the LED stays in for each "Blink" depend upon the setting of the pot. ("Pot" is a common abbreviation for "potentiometer".)

If you have two pots, do a version of Blinky which has "on" times depending on one of the pots, "off" times depending on the other.

Now improve THAT (whether it uses one or two pots) so that the time taken "on" or "off" can be changed with the pot(s)... but only if Bu0 is pressed at the time.

Do a version in which the "on" time doesn't change, as long as the pot is returning about 550. If the pot starts returning something a little higher, the length of the "on" time starts increasing... but slowly. If the pot is returning something a lot higher, the length of the "on" time increases rapidly. (And if it is a little BELOW 550, the "on" time decreases slowly; if it is a lot below 550, the "on" time decreases rapidly.

What are the pros and cons of the different approaches?!




That's it for now... sorry. "Complain" when you've worked through the above!

====Big section... ==========




How to email or write this page's editor, Tom Boyd. This page, and the software it references, ©TK Boyd, 2/18.






Valid HTML 4.01 Transitional Page has been tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org. Mostly passes, just a few "No attribute" issues, arising from Google code.


If this page causes a script to run, why? Because of things like Google panels, and the code for the search button. Why do I mention scripts? Be sure you know all you need to about spyware.

....... P a g e . . . E n d s .....