Python is a Great Prototyping Language…but One Should Never Ship a Prototype

May 26th, 2020

I really like how Python lets me start to get things working before everything is working. I can fire up an interactive debugger and immediately start playing with some library I Googled up and think I might need, quickly get it doing stuff, plug it in to other code and quickly get the whole doing useful stuff.

I can get my Python program in a useful state before I have really decided what I wanted it to do, and well before I have stopped to think hard about the best way to do it.

This kind of exploratory programming is exactly what is needed to develop a prototype. But never “ship” the prototype!

Here is an analogy to the physical world: there are prototyping materials that are easy to work with but are not as durable nor economical as are materials suited to real manufacturing. For an extreme example, automobile bodies used to be prototyped, at least in part, with modeling clay. And the very properties that make modeling clay good for prototyping make it terrible for manufacturing. (Take it to go buy a Christmas tree, strapped on top.)

Similarly, in the case of Python, the key property that makes it good for prototyping, makes it terrible for “real” programs: Probably the biggest thing that makes Python powerful is precisely that it allows the programmer to defer so many decisions. What kind of parameter does the function take? “A parameter called X!” Not very useful. Even if the parameter is called something like “address_list”, that only hints–it might not actually be a list, maybe the address “list” is in a dictionary and the keys are customer numbers. (Likely.) And even if we really honestly know the address_list is a Python list. Okay…a list of what? Let’s guess dictionaries, Python loves dictionaries. And what will be in the dictionary? Whatever anyone anywhere else in the code might manage to put in there–or remove from there. And it gets worse: Some programmers think it is cool to put “**kwargs” in the parameters, which means we don’t even know what the parameters to the function are! We have to examine every line of code that might call this function to see what the possible parameters are, and even then you will see (you just now it) that some of that code is going to be passing a dictionary that is only known at runtime.

The fact the programmer doesn’t have to decide what s/he is doing can give the illusion that real programming is happening really fast, but there is an illusion there. A dangerous and beguiling illusion. Worse, of course, is when such dynamic features are actively abused (see kwargs), but merely deciding to use a simple list yet having no good way to pin down what is in it is such a rich place to hide bugs.

Strongly Typed Language: Python

There is this idea that compiled languages such as C (or C++, all the weaknesses of C without the virtues of being a small and elegant language) are strongly typed but an interpreted language such as Python is not. This is half-right.

In C you have to say what kind of data goes into your variable.

In Python you can put whatever you want in your variable–a string, a boolean, some kind of number, some enormous data structure, a function, or None. Not only can you put what you want in there, you can change it at your whim; in one line the you might declare an instance of the class your variable holds, and a couple of lines later (or a different thread, if it can get a chance to run) set your variable to 42. Python is very liberal about such things.

But this doesn’t mean Python isn’t strongly typed! It is very strongly typed, it just doesn’t make up its mind about types until the last possible moment, at runtime. Repeatedly. Every time through your loop.

In fact, Python does almost nothing but constantly checking types of things. It takes much longer to check the types of two variables for adding than it takes to actually add them. (To check whether they are numbers and that adding is sensible, and how to add these particular numbers–assuming they proved to be numbers. Python needs to check a lot before it can do the addition.)

Deferred Work Doesn’t Go Away

It is presumably important to you that when the Python code runs it not crash. One would think. In which case doing that clever thing of instantiating a class instance from a variable at one moment and doing arithmetic on 42 the next had better be done right because the reverse operations will not work. Even doing unclever things, such as misspelling a variable name and accidentally doing arithmetic on a class definition with a similar spelling is a bad idea.

And though Python will catch both of these mistakes if you make them, it will only do so if you exercise the right lines of code with the right (unfortunate) values. And only if the right person is watching in the right way will it do any good.

It is really hard to thoroughly exercise code. And in the case of a very dynamic language like Python the permutations are so great that it really isn’t possible.

Yes, Compilers are Annoying

In statically typed, compiled languages, it is more work to make the compiler happy, but a benefit is the compiler will prevent these sorts of errors. It is less work in total to catch a type problem up-front than to have to do it in the debugger and in vague bug reports from users. Unless you are planning to defer some of the work forever, planning on never finding and fixing some of the bugs…

Yes, Compilers are Inflexible

Yes. And in a good way, if it prevents accidentally doing arithmetic on a class definition.

But what about cases where one needs to be clever. Maybe not so clever as to mess with class definitions at runtime, but something more conventional, such as wanting either a value like 42 or some other flag value (such as Python’s None), isn’t that reasonable?

Yes. And compiled languages allow such things. Some in safe ways, even.

(Some Compilers are Nice)

The Rust compiler is demanding but in exchange lots of bugs simply won’t exist once the compiler is happy.

Rust: Not as slow as C without being as low-level as Python.

Prototypes are Expensive to Operate

I would like to see some hard numbers, but it feels to me like Python must spend a hundred times as much effort constantly checking the runtime type of every bit of data as it does doing real work on that data. Certainly Python is not very efficient, whatever the ratio. How much carbon is released just because of Python?

-kb, the Kent who is looking opportunities to finally get good at Rust.

P.S. Comments are broken and have been for sometime. Sorry.

©2020 Kent Borg

Patron Saint of Ham Radio?

May 18th, 2020

Today, 19 May 2020, is Oliver Heaviside’ 170th birthday.

Hurray!

Who?

Okay this post will be a bit technical…but only a bit.

One of the giants of science is James Clerk Maxwell, he figured out the science behind how radio waves work. Pretty important stuff. He is immortalized in the famous four Maxwell Equations. Maybe you have head of them, lots of science-y types have heard of them, but not that many understand them, so don’t feel too left out, this is rarefied territory. (I’m still learning this stuff, but I’m not there yet.) But it seems they are important to the experts that make modern life work.

And Maxwell did them!

Except he didn’t. Maxwell did eight equations, not four. Oliver Heaviside is the one who simplified the eight into four.

People will write otherwise, but it seems to me that it was Heaviside, not Maxwell, who created the whole field of electrical engineering.

In Heaviside’s day the hot new technology was the telegraph. You know, Morse code, dits and dahs. It was slow and cumbersome and expensive, but it could communicate over long distances very rapidly when compared with a horse or ship or even a racing locomotive (that means a train). The slight detail is that the longer the wires got the mushier the signal got. People would try to make up for it by turning up the voltage, and they had other tricks they tried, but it was a seat-of-the-pants, rule-of-thumb world, and don’t ask too many questions because even the most talented “electricians” didn’t really know why one trick might work and why a different did not. The first trans-Atlantic cable was not only very slow but burned out after a very short amount of use. (They turned up the voltage quite a bit.)

Heaviside worked for a telegraph company, and he wanted to figure out this stuff worked. Precisely how it worked, as in quantifying things. This rubbed some in the industry the wrong way, there was a lot of opposition of quantifying these things. And he did. Both rub people the wrong way and figure out these things. He figured out how to make telegraph wires operate at much faster speeds for much greater distances, without burning them out. His same principles were applied to voice telephone calls, for they had the same problem of the signal getting mushy if the lines got too long, and he explained how to fix that, too.

His solution was to set up what is now called a balanced transmission line. Back when TV antennas were put on roofs the first kind of cable for connecting it to the TV was a balanced transmission line, 300-ohm twin lead, to be precise, and it was a flat cable, made of plastic with a wire running down each edge. Don’t tape it directly to your metal antenna mast, it doesn’t like that, but if suspended away from metal, it is very efficient at getting a very weak signal down to the TV without picking up interference along they way. Heaviside invented the balanced transmission line. And it is useful for a lot more than ancient TV antennas. It you haven’t heard of balanced transmission line, but have heard of coax cable (it is perfectly okay to tape coax to the metal TV antenna mast–coax is not as efficient as twin lead, but easier to string), well Heaviside invented coaxial cable, too.

About the time telegraph and telephone were still pretty new there was another hot technology: radio. Heaviside was paying attention there, too. At this point sensible people knew the world was not flat but is round (spherical, to be pedantic). And people also knew that radio waves travel in straight lines, so radio wouldn’t be useful for long distance communications, right? Wrong. For some frequencies, under the right conditions, radio waves will bounce off the ionosphere and can travel great distances. Heaviside figured this out. He figured out that this should work before people found out that it did work. In fact the layer of the atmosphere (the ionosphere) that does this was originally called the Heaviside Layer.

Back to the Maxwell Equations. The way that Heaviside did all of this was by taking the science and figuring out how to apply it in a precise way to make an engineering discipline: he created electrical engineering. Including inventing new ways of doing the math.

In the early days of Bell Labs they were working magic by taking Heaviside’s work and applying it in a practical way. Some Bell engineers were so impressed with Heaviside’s work, and so indebted to him, that they tried to send him money, but he said no.

At this point Heaviside was old and not rich, yet he said no. Oliver Heaviside could be difficult. Various folk tried to help him and to the extent it looked like help to him, he said no, even though he needed it. And part of why the Bell Labs engineers were having such a hay day on his work is he that, though he might have been brilliant, he didn’t stop to try to make his work easy to understand, it took awhile for his work to have full effect.

Back to the my claim he should be the patron saint of ham radio: He made practical much of what the field is built on, he was a hands-on man. And he died of complications from falling from a ladder.

-kb, AC1HJ

©2020 Kent Borg

P.S. Comments are broken and have been for sometime. Sorry.

Why Do They Deny?

September 15th, 2019

I think I have finally figured out something basic about human nature, something that has long puzzled me. I have gone from shaking my head in disbelief to maybe understanding.

Here is the most extreme example:

Why are the people who strenuously argue Hitler’s death camps never existed, also seem to argue they should have existed?

They are attracted to Hitler, Hitler is most infamous for his genocidal murder, there is clearly something attractive in that fact, but as they are attracted by infamy, they also go to great efforts to deny it! I mean, they are already going to a very taboo place, why not really go there and MGMGA? (Make Genocidal Mass-murder Great Again!).

Why this strange split?

This doesn’t only happen in the extreme: There is a resurgence of a kinder, gentler (than Nazis), racism these days…but as these newly outed racists gleefully promote their racism, they also say that they are not racist? They insist! Why?

To get all Star Wars here, I think it is a basic property of “the dark side”. Those who resist it see it as dark and repulsive. But my realization is that for those who embrace “the dark side” it is still dark and repulsive. Being dark and repulsive is somehow part of the appeal.

So in the case of neo-Nazis I think it is also the point, but in this case taken to its logical extreme.

And I think that extreme–of murder on an industrial scale, in a network of slave labor camps–is enough to make even Nazis queasy. So they lie. They lie to all of us, as hard as they can, because that is the best way to lie to themselves.

In some extremely dark corner of their already dark souls, they know it is true that it happened, and in some still darker corner they sort of wish to see it again. But first they want to be part of a rampaging mob, they want to be drunk on the high they get in abusing their choice of “the other”, to have violent power over others, laughing with their fellows, being goaded on by their fellows, goading on the others, spreading responsibility. Because they know it is wrong.

It is bad stuff. Few have the stomach to really go there, to go there alone, so they lie to themselves and look for support in others.

A silver lining: There is still some good in most of these people, maybe not much good, but some. (No, Donald Trump that doesn’t make them “good people”, not on balance.) If they are still capable of being revolted, there is still some good in there.

No, don’t think I am going so far as to assert that sociopaths don’t exist, they do, but most Nazis are not sociopaths, and I suspect most sociopaths are not attracted to Nazis.

My thesis here is that–excepting some pathological, diseased minds–there is good in everyone. Look for it. Try to draw it out. Try to tempt them away from the repulsive “dark side”, for they find it repulsive, too.

-kb

©2019 Kent Borg

P.S. Comments are broken and have been for sometime. Sorry.

Inviting Phishing: Stop Training People to Be Fooled

December 2nd, 2018

As we try to tighten up our computer systems, in 2018, phishing feels like one of the most dangerous things. Sure, getting someone to open a dangerous attachment that exploits a PDF bug (is there an infinite supply?) is a problem, but let’s imagine users running on such tight systems that dangerous attachments are no longer a problem. Phishing won’t be over.

People will still be fooled by crooks, and if a crook walks up to you in nose glasses and politely asks for the keys to your car you might think something is funny. You do expect give your car keys to strangers, but you expect these people to be, say, the mechanic at the car repair, or the parking valet at the restaurant. The point is if you initiate the transaction (you go to get your car fixed, you go out to eat), the transaction is much safer. In contrast, if a stranger approaches you and volunteers to be a mechanic or valet, you are less likely to fall for it.

We should apply that to computer credentials. If I decide to go to website tuklever.com, it is reasonable for me to then type my TuKlever login credentials. But if some website claiming to be tuklever.com approaches me (via e-mail), why should I hand it my password (aka my “car keys”)? I shouldn’t.

A powerful way to avoid a lot of phishing attempts is:

Never (never ever) type credentials because someone else supplied you with a link, possibly in an e-mail.

Instead, if the link looks good, login to that website manually (type a trusted URL by hand, use a bookmark you typed by hand). Now log in. Now try that link in the e-mail–and if you are asked for another password, don’t do it.

This logic applies in other circumstances, too. Get a call from our credit card company about a suspicious transaction?, and that professional sounding voice asks for verification information from you? Say no, ask what it is about, say you will call back. Call what number? The number the voice on the phone gives you? No! Call the number on the back of your credit card. Same idea as the website example.

Back to my headline: We train people to do the dangerous thing.

  • Employees frequently get real e-mail from, say, HR, that includes links to, say, the new payroll system, and click and type in sensitive information.
  • For years now American Express has been sending me e-mails that include links to click on and an invitation fo type a password.
  • Other credit card companies–fraud departments even–have called me and expected me to give them identifying information.

In each of these cases we are conditioning people to do the dangerous thing. In each of these cases the safe thing to do and the normal thing to do are different. Do we really expect people to rock-the-boat, and refuse to log into the new payroll system, and not get paid?

No. We expect people to be phished, and we are training them for that.

I realize there is a heresy in what I am saying. I am implying that user behavior matters, that how we condition users matters. I am a hairsbreadth from suggesting that user education is a good thing! Horrors, the first step down the slippery slope of blaming the user for bad system design. Next thing you know I’ll make a snide remark about some celebrity caught on live camera entering the PIN 000000.

-kb

©2018 Kent Borg

Why Trump Grovels so to Putin, I Figured it Out, Now That it is Obvious

August 1st, 2018

I have wondered what Putin has on Trump to get such deference. For a very long time I was deeply puzzled. Until a week or so ago when I realized that John Brennen nailed it a year ago May!

    "Frequently, people who go along a treasonous path do 
     not know they are on a treasonous path until it is too late"

It is as if Brennen knew something.

Recently someone smarter than I pointed out that the Russians likely started cultivating Trump years ago. (That’s part of how they do business.) And when his credit landed in the toilet and no US bank would touch him, their opening got ripe. He needed cash and there were plenty of oligarchs wanting to launder money into the US.

So do the Russians have him for “money laundering”? No, too simple. They laid a treasonous path, and he walked down it. They reeled him in, bit by bit, and as he thinks back, he’s not sure what all they have over him, but he knows they have plenty.

At this point I think Putin keeps his distance, never giving Trump the warm reassurance he craves. Rather, I think Putin takes pleasure in occasionally yanking Trump’s chain, torturing him, making him nervous as hell. Putin has no respect for Trump, but he still likes groveling from anyone, particularly from a US President.

-kb

©2018 Kent Borg

We Are Really Unhappy with Our Operating Systems, and Don’t Know It

September 24th, 2016

Linux has won. It is taking over everything, from tiny devices to the biggest super-computers. Apple’s operating systems are all pretty much on the same model, and Microsoft always seems to be trotting along in roughly this direction, too.

The idea is pretty cool: Give each program a uniform view of the machine, keep them from interfering with each other. Not only can each program mostly pretend it owns the entire machine, the model is good enough to be extended to multiple users, all running on the same machine.

Yes, there will be resource limits with all this sharing going on, but that is a necessary limitation, the larger sharing model is great.

So why are we so unhappy with it? Why do we have this big virtualization fad? The operating system was supposed to let multiple users share the same physical machine, why an extra layer of multiple operating systems sharing the same hardware? If these multiple operating systems were different kinds of operating systems (needed to be compatible with different kinds of programs) that would make sense, but mostly we run multiple virtual copies of the same operating system. Frequently the same version of the same operating system. The popularity of hypervisors for providing multiple uniform views of the hardware, keeping them from interfering with each other, seems a big indictment of what the OS was supposed to do. Something is wrong with the API offered by the OS if we prefer the API offered by BIOS. Something is wrong.

And inside the OS, different programs were supposed to do the different things. So why are we now inventing enormous container facilities like Docker and Kubernetes for supplying the features we want? Isn’t that what the OS was supposed to orchestrate?

I don’t see much questioning of the role of the OS, but I see an awful lot of ad hoc reinventing of OS-like services.

Part of this is clearly a limitation of the OS model: Individual programs are isolated from each other, but it seems not isolated enough, we want more isolation, so we fire up new OS instances. Also, individual programs have complicated and conflicting dependencies to shared libraries that the old OS model isn’t good at mediating. Finally, individual programs are not where the action is, we run different programs in concert with both dependency confusions between them, and contradicting desires to be isolated from other programs (so they don’t interfere) but not isolated from other programs (so they can cooperate). It seems these are all issues the OS should handle, and it doesn’t, that’s why we have so many VMs, and these container facilities.

Recently I ran across the various name-spaces that the Linux kernel offers. (Linus is very pedantic that the kernel just be the kernel, but that doesn’t mean it isn’t still freaking gigantic and bursting with features.) These name spaces provide a lot of granularity for controlling what is isolated and what is shared between different programs. It seems they make it possible to completely isolate software, as if you were running completely different operating systems. I say “it seems” because I don’t know that I am right, I don’t know that these different name spaces cover all the bases. And, even if I knew they did cover all the bases, how would anyone ever trust that they did it in a bugfree way? How would anyone ever know that there isn’t some unintended leaking between spaces, security holes hidden in the confusion.

I think this gets to the point: The confusion. The old OS model was simple, that was a virtue. The model implicit in Linux name spaces is so complicated that I almost don’t want to call it a model: if almost no one can understand the implications of all those features, can it be called a “model”? Does it instead become an “artifact”? Something to be studied, as opposed to a model, something clear enough to be understood?

Maybe I am just being overwhelmed and demonstrating my ignorance. But something tells me that the simplicity of hypervisors, presenting a near bare-metal model, isn’t about to lose its appeal as everybody starts to grok Linux name spaces.

I think we are choking on unmanaged complexity, that we are building systems that are more complicated than we know, that not only are they riddled with conventional bugs, but attackers are waltzing though our systems via the security holes made possible by that complexity. But that’s another topic.

My conclusion here is we have run out the old OS model to the point of absurdity, that we need to rethink what abstractions an OS should offer. The old OS model was both powerful and simple, but look at the layers of baroque filigree we are accumulating, it is time to revisit our assumptions about what an OS is.

-kb

©2016 Kent Borg

Kent’s Super-Simple, Excellent Password Advice

September 22nd, 2016

This excellent advice is simple, in fact its excellence depends upon being simple. Complicated is the enemy of security. If you follow this advice you will be among a very rare elite in how secure your passwords will be.

Four parts:

1. Write down your passwords. On real paper, with a real pen or pencil, and keep the list safe. If you want to get fancy, maybe don’t quite tell the truth, at least not the whole truth, maybe leave something off each password (something you will remember), so if someone finds the list they won’t quite know any of the passwords on the list. And keep the list safe.

2. Now that you can keep track of what your passwords are, never recycle passwords between accounts. So, if someone breaks into one site, your other accounts aren’t at risk. (Today’s news, as I write this, is information on 500,000,000 accounts were stolen from Yahoo.) Don’t reuse passwords in different places.

3. When you make up a new password, dream up something you think no one will guess. (I know, you already do that.) Now, to be extra secure, add something even you couldn’t guess. Maybe look at the time, exactly how many minutes past the hour? Include that in the password. Or look around you, pick something else—but pick something you could not anticipate—and include it as part of the password.

4. Keep this entirely manual, the whole approach is low-tech for a reason. Computers are usually pretty insecure. (Ask Yahoo…) Don’t automate any of it, because that’s really hard to do safely (ask Yahoo), keep it manual. Don’t even photocopy your password list, because copiers are really computers these days. Don’t take a picture of the list, because cameras are also computers these days. Yes, backups are good, but sorry that has to be manual. The benefit is, as long as you keep all of this manual, you can trust your common sense, because you will understand every aspect, you have real expertise manual stuff because you can see it.

That’s it. Low-tech as hell, which means most techies will hate it, but who cares that it’s controversial as hell? It’s smart. Because it is simple.

-kb

P.S. And I really am so very sorry you can’t use a password manager program, but they are just too complicated, they will have security problems, admit it, you know it in your heart they will. Don’t trust them.

Snowden, the Movie

September 16th, 2016

I went to one of the first Boston matinees of the movie Snowden today.

It was all very familiar territory: it could have been boring or–as with any subject I know a lot about–it could have been excruciating in its errors. It was neither. It held my attention, it did not disappoint.

But was it a good movie? I usually have tons of opinions, I fret over whether a movie hits the ten-minute mark right, whether the script is “economical”, whether characters are compelling, whether the plot is interesting. In this case I can’t say, I am not unbiased: I am an American. And this is really important material–important to any American.

I do know it was at least a competent movie, because it had me wanting to cry. I knew Edward Snowden was a hero, but Oliver Stone tugs for tears. At least from me.

Is it a great movie? Probably not, just because great movies are rare. But I don’t know. Ask me in a few years, I’ll know better. But right now I am kinda choked up over a man whose illusions were shattered, followed by his world being shattered as he followed his conscience with selfless acts.

Another bit of praise: Usually it is painful to see a movie on a topic that I know something about, worse if the movie is technical, and far worse if it is about a technical topic I know something about. This movie did well by that measure.

-kb, the Kent who thinks the three branches of government should not be secret legislative measures, implemented by secret executive orders and agencies, overseen by secret courts.

©2016 Kent Borg

Why We Got Ourselves a Trump: 4 Crazy Tricks

May 4th, 2016

Four things came together to give us Donald J. Trump as the all-but-official GOP nominee.

First, the so-called cable news channels in the US are, indeed, for-profit businesses, looking for ratings, looking for an edge. Thump was ratings gold for them. He got enormous free publicity in exchange for supplying viewers. He did a very good clown-act. Maybe professional “wrestling” is a closer approximation, but either way they have airtime to fill and he provided them with riveting free content.

Second, the GOP has been pandering to, and fanning the flames of, a very dissatisfied base. They have been promoting a “reality” that is remote from actual facts. And, they have not delivered on their promises. This left the GOP a hollow party, dependent on a narrowing base, that no one could reason with. They created a monster. A monster that apparently watches cable TV.

Third, due to something the GOP has accomplished, the 1% have done great in this otherwise tepid recovery, but vast areas of this country (it goes zip code, by zip code) have been left behind and are still where George II’s Great Recession left them. They have not seen the recovery at all. They are rightfully afraid, and unfortunately very angry. And they watch TV.

Fourth, The Donald turned out to be a political genius. The man is nothing if not arrogant, but I don’t think even he had a clue how good he would be at this. He took his entertainment TV experience and turned it into an entertaining campaign, driven by free TV.

I thought the Trump phenomenon would burn out. I think he guessed it would, too, that he would come away with a bigger “brand”. Well, the second part sure came true.

-kb

©2016 Kent Borg

Touchscreen Password Idea

February 1st, 2016

Passwords are a problem, and lots of people say they are doomed, but I have seen no good alternatives, so I sometimes think about making them better.

Touchscreens are important yet really hard to enter good passwords.

Also, I would like to do more of a “key exchange” when entering my password. I use different computers and I don’t reuse passwords between these computers, which means I sometimes enter a password for the wrong computer. Oops! Some sort of richer interaction with the other end would prevent this.

So here is my (embrionic) idea.

Have the password be a location in a virtual 3D space. Use the 3D hardware capabilities of phones and tablets and have the user drag around the screen to drive to the location that is the password. By having different randomly chosen starting points in the 3D space for each login attempt a simple “key logger” is made more difficult as is reading screen smudges. By having more of the space revealed as the user navigates the computer has to reveal more information in response to the user’s input, making it more of a “key exchange” and making the space richer and so lengthing the password.

Put another way: a complex 3D space, uniquely generated for each user. The password is a “secret button” somewhere is the space. To authenticate the computer starts the user in some random location and the user flies through the space and touches the secret button but no other.

Shoulder surfing is a problem, but once the user gets good at it s/he might be swooping through so fast that a casual observer might have a hard time realizing what just happened. Particularly if there were a needle-threading aspect where some routes are good and other are not.

By using the full power of the GPU it also puts a limit on how far away a man-in-the-middle could be. (Which makes remote authentication tricky.)

By drawing on the user’s motor skills there might be a way to drop the password down in the brain so the user doesn’t know it in a way that can be told to others. Make the password more like a customized motor skill.

-kb

©2016 Kent Borg