Tuesday, December 23, 2008

Tabs vs. Spaces

You know that 'tab' key on your keyboard? I hate it. Not because it's not useful; I actually like it for the purpose of navigating through fields of a form. I hate it for programming. Why? Because it's another way of making invisible spaces.

Non-programmers are probably already losing interest at this point. I don't blame them; there's not really any controversy about tabs vs. spaces in normal text editing. So let me explain a bit about why it matters to programmers.

Source code (the stuff programmers write) is generally stored in a source-code management system (commonly referred to as an SCM). The SCM is in charge of storing versions of source files, so that as you add features or fix bugs, you can go back and see what changed.

The problem comes in when you change between spaces/tabs, because the SCM will see that lines have changed, but only the invisible, non-functional spaces of some lines really changed. And each programmer has their own view on how tabs should be used, so sometimes one will 'fix' the spacing written by another.

Source code files are written in a very structured format that includes code 'blocks', which are groupings of lines that are related to each other. These code blocks are indented from the left margin to easily distinguish them visually while scanning through the text.

The 'standard' view on tabs, which I disagree with, is that a tab is worth 8 spaces. Beyond that, indentation levels should be in increments of 1/2 tab. The result is that your lines will start with 4 spaces, then 1 tab, then 1 tab plus 4 spaces, then 2 tabs... Alignment of adjacent lines within a block are done the same way, using tabs until you can only use spaces to finish. So basically, tabs are used as a lazy way of writing 8 spaces.

That completely wastes the possibilities of having a different type of spacing character.

My view on tabs is that they should only be used to indent blocks of code. Beyond the initial code block indentation, only spaces should be used to align adjacent lines within a block. The benefit here is that if I like indentation levels of 4 spaces, but you prefer indentation levels of 3 spaces, we can each set our editor tab width appropriately and it will just work. No reason to change someone else's code to match your preference, everything is aligned no matter what your tab width is set to.

But since the two main drivers of source code formatting are the Linux and Microsoft developers... the standard is not going to change. Linux standard practice is 1 tab = 8 spaces, with indentation levels of 1/2 tab width. Microsoft is a little bit better (which is painful for me to say), with standard practice being 1 tab = 4 spaces, indentation levels of 1 tab width. If Microsoft would just go on to say that alignment within a block must be done with spaces, we'd be partway to a better world.

Not that the Linux developers would care; they've hardcoded their editors to do it their way, and seeing Microsoft push something will only keep them from doing it out of spite. But maybe, just maybe, a few of them would realize that the additional flexibility would be beneficial and not just a Microsoft ploy to take over the world. But it probably would be, so nevermind.

Wednesday, November 26, 2008

Keyboard Layouts

Do you ever think about your keyboard? And I don't mean think about it like, "Stupid keyboard, I know I hit the spacebar, why didn't I jump his rocket?!" I mean think about the comfort, shape, and layout of the keys.

I'm sure everyone has used someone else's keyboard and been thrown off by a few slight changes in key positions. I used to get all messed up when the backslash key was placed next to the backspace key, instead of below it. Oh, and that modern trend towards the block of keys around Page Up and whatnot? You know, where there's the really large Delete key and the block is oriented vertically? That really F's me up every time I try to use it.

But I digress. That's not what I was planning to write about, although apparently some part of me wanted to. What I wanted to write about was ergonomic keyboards and the Dvorak layout.

History

Back when Sholes & Glidden created the QWERTY layout (Wikipedia), (sounds like I was actually there, eh?) the goal was (supposedly) to prevent the typebars from jamming together. Some theories about this include it being designed to be inefficient, so the user simply could not type fast enough to jam the keys, or, that by placing common letters far away, the internal mechanisms were less likely to conflict.

So, basically, the layout was not designed for comfort.

Dvorak

The Dvorak layout, however, was. By studying letter frequencies in the English language, Dr. August Dvorak designed the layout with these goals (copied from Wikipedia):

  • Letters should be typed by alternating between hands.
  • For maximum speed and efficiency, the most common letters and digraphs [two-letter combinations] should be the easiest to type. This means that they should be on the home row, which is where the fingers rest, and under the strongest fingers.
  • The least common letters should be on the bottom row, which is the hardest row to reach.
  • The right hand should do more of the typing, because most people are right-handed.
  • Digraphs should not be typed with adjacent fingers.
  • Stroking should generally move from the edges of the board to the middle. An observation of this principle is that, for many people, when tapping fingers on a table, it is easier going from the little finger to index than vice versa. This motion is called inboard stroke flow.

So what does this mean for you? Probably very little, since most people aren't willing to put in the time to relearn how to type. But, if you are not yet a touch typist, or you have difficulty with the standard QWERTY layout, it may be worth the switch.

I am a touch typist. I have been for a long time, at least 14 years (that may not sound like a very long time to some, but I'm only 26). I learned on QWERTY. But last year I started to have problems with my hands; I would have trouble gripping stuff, some of my fingers would go numb, and my wrists always hurt. So I decided to make the switch.

I also got an ergonomic keyboard for work (already had one at home, thanks to my wife; that was an awesome birthday present) for my wrists, since changing the layout wouldn't help there.

How did it go? Well, thankfully there are keyboard shortcuts that you can set in both Windows and Linux for switching between layouts, since fighting your habits about which keys are where is draining. Additionally, I'm a programmer, so not being able to get my thoughts out quickly enough can be disruptive to my workflow. So I would use Dvorak as long as I could stand it (generally about half an hour at a time at first), and then switch to QWERTY to relax for a while. Probably three or four times a day I'd fight my way through some less-intensive work using Dvorak for practice.

It paid off. After about two weeks I'd gotten up to 20 WPM (there's a good WPM test here, which also makes for good practice). As a reference, I'm generally around 75 WPM using QWERTY.

After three more weeks I'd hit 40 WPM. Another month and I was around 60 WPM, which is comfortable enough to switch over full time. Now, a year and a couple months after starting, I am at 75ish WPM (I just took the test again), although I haven't improved significantly in quite some time.

Oh, and QWERTY? Can I still type that way? Yep. It takes a minute to warm up, and I'll make more mistakes (at least at first) than I used to, but I can still do it. I'll take the WPM test now to see how I do... 56... 67... I can't seem to get above 67. Probably because I haven't been practicing as much as I used to.

How do I keep going with both? I use Dvorak at work and QWERTY at home. That forces me to keep going with QWERTY, although I do have a tendency to switch to Dvorak if I will be typing something longer than an email. Lately I haven't been using my computer at home so much (now that we have a house, there's too much other stuff that needs to get done).

And I'm not the only one interested in switching; one of the guys at work has decided to take the plunge as well! I hope he has as good an experience with it as I did; he complained to me the other day about how it is getting harder to type on QWERTY now. Speaking of, I typed the first half of this article using Dvorak, and the second half using QWERTY.

How To Try It

Windows XP: Open up the control panel, choose "Regional and Language Options", switch to the "Languages" tab, click the "Details..." button, click the "Add..." button, leave the input language as is, and choose "United Sates-Dvorak" for the layout. Once you've OK'd your way out, pressing Ctrl+Shift will switch between the layouts for the program that owns whatever window you are currently in.

Fedora: Open the Control Center, expand "Regional & Accessibility", choose "Keyboard Layout", click "Enable keyboard layouts", choose an available layout, and then choose the "dvorak" layout variant. You can also set up options for whether the layout is per-application (like Windows), or for the session.

I would have outlined Ubuntu here, but apparently I don't have a VM of it like I thought I did. As for Mac OSX... You're on your own, I have no access to a Mac, so I can't even walk myself through it.

I recommend leaving a Notepad (or gedit or whatever) window open in which you've typed out the key layout, just as a reference in case you get stuck. You may want to find a layout diagram to print out (here's one). Also, there's a good, free, online beginner's course called ABCD (A Basic Course in Dvorak). The version that I used seems to be gone, but someone created a Flash-based version here.

Monday, November 17, 2008

Brew Day

Yesterday was my first Brew Day. I made a Scotch Ale, using an ingredient kit from my LHBS (Local HomeBrew Shop). I mostly ignored the recipe, since it didn't mention sanitation at all. Interestingly enough, though, the startup equipment kit included BTF (the link suggests that BTF is a chlorine-based sanitizer, but the bottle actually says that it is Iodophor-based; Iodophor is a very popular iodine-based sanitizer whose only real competition is Star-san).

Everything went pretty smoothly, except perhaps for the wort chilling. Need more practice with that, or perhaps a counterflow wort chiller... Xmas is coming up, I think I'll add the pieces for Bobby_M's counterflow chiller to my list.

The new pot I bought (from Walmart) specially for this and will never be used for anything else (at least until I get a really nice one):

Some of the ingredients (see the end of the post for the recipe). I didn't show the hops or the yeast, since pellet hops all look the same and I forgot to take a picture of the yeast:

The steeping grains:

Some more equipment (the red spray bottle is to keep curious cats from being too curious):

The second best way to enjoy homebrewing (best would be with another homebrew, this was a Saranac Vanilla Stout):

This is why I need a special spoon to go with the special pot:

Baby's first boilover, aww. Lesson learned: always turn the heat off for a few seconds before adding hops; the other two hop additions were uneventful.

Teh kitteh likes teh hops!

This one... not so much. Not sure where the bag came from, either:

And this one is trying to steal my recipe book!

Here is why you should always keep the cable for your digital thermometer dry. Even after 15 minutes in the fridge, it was still reading 194*F when the water felt like 75*F. Thanks to Bobby_M again, here's a trick I may use next time. Anyway, the pic:

Here's a video of how I aerated my wort (that's a whisk attached to the power drill). Thanks to Padstack31 for the idea. Unfortunately, I forgot to take a specific gravity reading until afterwards. Oh well, brew and learn:

And finally, about nine hours into fermentation:

Recipe:

Ingredients (Note: links are only to see details about products; I purchased everything from the LHBS in an ingredient kit):

Procedure:

  • Steep the Caramel Malt in a grainbag in 2 gallons of 155*F to 160*F water for 30-45 minutes with the lid on and the heat off (unless the temperature drops too much, then turn it on low for a bit).
  • Pour 2 quarts of 170*F water over the grains into the pot. Allow the grains to drip for a bit, then place in a collander over a bowl to collect anything else that might drain out; pour that into the pot also.
  • Turn heat to high and add 9 quarts of water. Assuming 1 quart was lost to the grains, this makes 20 quarts or 5 gallons. Wait for it to boil (putting the lid on will help).
  • Once boiling, TURN OFF THE HEAT and add the Chinook hops, then turn the heat back on. Set a timer for 1 hour. Leave the lid off.
  • Half an hour in, turn off the heat and the timer and add the malt extract. Make sure it is completely disolved (no thick feeling on the bottom of the pot), then turn the heat back to high and wait for it to boil again. Once it is boiling again, allow the timer to continue.
  • At 15 minutes remaining, add the Irish moss.
  • At 10 minutes remaining, turn off the heat and add the Aurora hops, then turn the heat back on.
  • At 5 minutes remaining, turn off the heat and add the Fuggle hops, then turn the heat back on.
  • When the hour is up, move the pot to a series of cold water baths. It helps to have a double-sided sink, so you can be filling up one side while the pot is giving up its heat to the other side. Ice is very helpful. (I actually froze a couple of two-liter soda bottles, sanitized the outsides of them, and used them to stir the cooling wort.)
  • When the wort has chilled to 70*F to 80*F, take a specific gravity reading. (I forgot to do this until after aeration, unfortunately.) The recipe provided by the LHBS did not mention the target gravity; mine was 1.054 after aeration and at an indeterminate temperature. I am assuming that, corrected, it would be 1.055 at the hydrometer's calibrated temperature, and 1.058-1.059 without the aeration. I will be using 1.058 when I calculate alcohol content.
  • Rehydrate the yeast (I did this too early, it was sitting in the water for at least 30 minutes instead of the target 15 minutes).
  • Get the wort into the fermentation vessel, add the yeast, and relax.

Here's the rest of the album, in case you want to see more pictures of beer and kitties.

Friday, October 31, 2008

Computer Software and Cars

As those who visit Slashdot are probably aware, many of the most vocal members of the site tend to push the ideology that all software should be open source. This is a noble goal, but it is not a workable model.

The main argument for people to want the source to their software (at least, in theory; in practice it is more because generally open source is free as in beer) is to tinker with it, to go "under the hood."

On the surface, this seems like an excellent analogy, comparing software developers to automobile hobbyists. You get a piece of software (or a car), and you tinker with it to really make it your own. Perhaps you make the user interface flashier (give it a good paint job) or tweak a few bits to make it run faster (tweak a few bits to make it run faster... yea, that translates pretty well).

So from that perspective, it seems like all software should be open source. Honestly, virtually everything technically is open for you to tweak, if you know how (for example, lawn mower races or anything that has received the Tim Taylor "more power!" treatment). But not software. Seems pretty unfair, as if we're getting the proverbial shaft.

But let's look a little closer. What is different between a piece of software and a car? Most notably, and what I'm focusing on here, is the price of the materials.

When you buy a car, the company that sold it to you really did sell the car to you; you can do whatever you want to it (except, probably, copy the design and sell it to others). They don't care what you do to it because they have your money. When you paid them, you covered the entire cost of the materials that went into the car, as well as the salaries of every engineer that helped design it, and every laborer that helped build it. Beyond that, there is no other car out there, even of the same model, that is exactly the same. (If you've ever seen discussion boards where people with the same cars are discussing their gas mileage, you'll understand this.)

When you buy a piece of software, most companies merely license it for your use. You don't own it. You don't even own your copy of it. You may own the media it was distributed on, but I am not a lawyer, so I can't say for sure. Like the car, though, what you paid for it covered the entire cost of materials and labor that created it.

But what's different? Why do they license instead of sell the software? Cost of materials. When you purchased that car, a very large percentage of the cost went towards the materials that made it (I don't know the exact numbers, but I remember someone once saying that, if it weren't for economies of scale, assembling a single average-priced car from individual parts would cost around $500,000). But when you purchased that piece of software, virtually none of the cost went towards the materials. A CD only costs a few cents to manufacture, and the extra packaging cannot possibly make up for much more of the usual $50 cost.

The car manufacturer doesn't need to worry about you copying the design, tweaking enough to avoid patent issues, and selling your own cars in competition, because it would simply cost too much; the barriers to entry in the automotive market are too high. But if you were allowed to tweak a few lines in that piece of software and start selling it, there's virtually nothing stopping you except the license agreement. Cost of materials? If you really wanted to get fancy, CDs and packaging are relatively cheap, but internet distribution is virtually free. There are no barriers to entry in the software markey beyond training!

So, although the car/software analogy is a nice way to talk about the benefits of open source, it doesn't quite fit. There will be a market for closed source software for the foreseeable future because it simply makes more business sense.

Now is the time that the Slashdot crowd would loudly exclaim "charge for service contracts, give away the software!" But honestly, I don't know about the rest of you, as a consumer I don't like service contracts. I feel like I'm wasting my money when I buy them for appliances and similar. I'm not going to pay someone else to answer my questions when I can find free answers myself.

Beyond that, service contracts just don't make sense for some software. Home office software, for example; OpenOffice.org doesn't even bother to offer anything of the sort, because it simply wouldn't make any money. The only people you can sell service contracts to are business users. For a business, it makes sense to buy the contract when it would be cheaper than hiring an expert. And, not all software is made for businesses (for example, games).

Before ending, I would like to say that I completely support open source software, I think it's great stuff, and I love watching as the quality and usage improve. I have donated money a couple of times (although not large amounts), and have released a few small utility programs with source myself. The purpose of this column was to illustrate that not everything can become open because there is no viable business model. If it really bothers you when someone keeps their software behind a restrictive license agreement and protects their source, start your own open version to compete. With enough enthusiasm, you'll probably beat them into submission in the end.

Wednesday, October 29, 2008

Beer

Homebrew beer has facinated me for probably about three years now, but I have not actually brewed any myself. In fact, I don't even know anybody else who has, so I haven't had a chance to try any. But that hasn't stopped me from wanting to experiment.

Unfortunately, my wife is less enthusiastic about the concept as I am. Perhaps because she doesn't like beer... I know, it should be a crime, right? Everybody should like beer! But anyway, she told me that I wasn't allowed to homebrew until we had a house, so I could let it ferment in the basement.

Well, guess what? We have a house now!

So as soon as there's a free minute (lots of redecorating going on right now), I'll be stopping by a homebrew shop (found one here) to get all the supplies.

In the meantime, though, I've been reading as much as I can about the process, so I'll be able to get it right on my first try. Here are a few sites that I've found that seem to have excellent information:

  • How to Brew, by John Palmer, is an online book covering all of the steps in great detail
  • Home Brew Forums is a message board for home brewers of various sorts, and includes an active set of forums about brewing beer
  • Beer Calculus is a calculator for helping create new recipes
  • Paul's Brewing Page is just some guy who does homebrew, but he has a much more complete link listing than this

As for what I will brew for my first batch... Well, I'm torn. Everybody seems to do their first-batch tutorials for pale ales, but I'm not particularly fond of those. I much prefer the darker ales, like Stouts and Porters. Lagers are pretty much out of the question, since they require so much extra care and time. So I still need to read more to discover whether brewing a stout is any more difficult than brewing a pale ale.

Tuesday, October 21, 2008

High Finance Using Excel

After making that last post, I realized that I might be using a few Excel features that other people don't know about. So now I'm going to explain how that mortgage calculator works.

Basic Excel Features

What is that equal-sign for?
Honestly, if you don't know this, you should be reading a real Excel tutorial. But basically, it means that Excel needs to compute the value for that cell instead of just displaying what you type into it.
Example 1: In cell A1, type the number 5. In cell B1 type "=A1" (without the quotes; never type the quotes unless I say specifically that you should). When you switch out of cell B1, it will display the value of cell A1.
Example 2: In cells A1 through A5, type the numbers 1 through 5. In cell B1, type "=sum(A1:A5)". When you switch out of cell B1, it will display the sum of all of the cells between A1 and A5, which should add to 15.

What are those dollar-signs doing in there?
If you place a dollar-sign ($) before a row or column identifier, that identifier will not change when you copy/paste the cell it is in.
Example: Set cell A1 to "=B1". Set cell B1 through B5 to the numbers 1 through 5. Set cells D1 through D5 to the numbers 6 through 10. Copy cell A1, and paste it into cell A2. Notice how the reference updated and now it is showing the value of cell B2? Now, copy A1 again and paste it into cell C3. See how both references changed and now it's pointing at D3?
The dollar signs prevent that. Set cell A3 to "=$B4". Copy cell A3 and paste it into cell C4. The reference to column B remained the same because the dollar-sign was there, but the row reference changed. Set cell A4 to "=B$2" and copy it into cell C5. It should now reflect the value of D2.

Function Descriptions

Date: The date function takes a year, month, and day number and makes them into a real date reference. So calling "date(2001, 1, 1)" should give you January 1, 2001.

Year/Month/Day: These functions extract portions of an existing date, allowing you to do some calendar math. I used them to increment months in the table of mortgage payments. By doing "date(year(B2), month(B2) + 1, day(B2))" in cell B3, I was able to have cell B3 be one month ahead of cell B2. Copying/pasting this down the B column continued incrementing the months, and Excel was smart enough to automatically roll over the years when the month got too large.

Sum: Pretty obvious; it takes one or more cells or cell ranges and adds all of the values together.

IPmt: Computes the amount of a periodic loan payment that goes towards paying the interest on the loan, rather than paying down the principle. You use it like this:
ipmt(rate, period, number of periods, present value [, future value]) (the stuff in [] is optional).

  • rate is the interest rate per period. If you are working with monthly payments, it will be the annual interest rate divided by 12.
  • period is the current period of the loan. This actually isn't very useful, because if you want to reduce your principle by pre-paying at some point, using this will cause a mis-calculation. I recommend always using the value "1" here.
  • numer of periods is the length of the loan. If you are working with monthly payments, this is the number of months (so multiply years by 12).
  • present value is the present value of the loan if you are using period = 1; if you are using period = current period, it is the original loan balance.
  • future value is the target value for the loan (in case you only wanted to pay off part of it). Defaults to 0, which is what pretty much everybody wants.
The function returns how much of the current payment will go towards interest instead of paying down the principle. It returns a negative number when you use it like this because that is the cash-flow model Excel uses. The model follows the perspective of the person paying the loan, so negative numbers are cash flowing away from you.

Pmt: Computes the periodic payment amount necessary to pay off a loan in a certain amount of time. Usage:
pmt(rate, number of periods, present value [, future value [, type]])

  • rate is the interest rate (per period) of the loan; if you are working with monthly payments, this will be the annual interest rate divided by 12.
  • number of periods is the length of the loan. Again, if you are working with mothly payments, it will be the number of years in the loan multiplied by 12.
  • present value is the size of the loan.
  • future value is not generally needed, but if you only wanted to pay down the loan to a certain amount in that time, you would type that in here; you probably want this to be 0, which is the default.
  • type specifies when payments are due; 0 (default) means payments are due at the end of each period, 1 means payments are due at the beginning of each period.
The function returns how much each payment will be. Since payments are cash flowing away from you, the return value will be negative for this kind of usage. (It could be used to determine monthly income if you lent money to someone else if present value was negative, meaning that the loan moved money away from you.)

These are some of the other functions related to finance that I didn't use:

  • ISPmt: Calculate interest paid during a period of a loan given the interest rate, period to calculate up to, number of periods, and present loan value.
  • Rate: Calculate the interest rate of a loan given the length, periodic payment, and size of the loan.
  • NPer: Calculate the length of a loan given the interest rate, periodic payment, present value, and optionally the future value and payment type (beginning/end of each period).
  • PPmt: Counterpart to IPmt; calculates the amount of principle paid down by a periodic payment given the interest rate, period, number of periods, present value, and optionally the future value and payment type.

Hope this was useful, and happy spreadsheeting!

Monday, October 20, 2008

Mortgages

My wife and I just bought a house on Friday. It's our first house, after living in two different apartments, so we are very excited about finally paying for something that will hold a value. We both feel like we're dumping money into a black hole by paying rent, whereas with a house, each mortgage payment is adding more and more to the portion of the house that we own, instead of the bank.
So today at work, I decided I'd like to see what the payments and whatnot will look like. Like any good computer guy, I built up a nice Excel spreadsheet to list everything out. Turns out the whole mortgage thing is a little frightening! We'll be paying for this house through about 2038, and we'll end up shelling out about 2.25x the purchase price!
Obviously, this got me thinking of ways to pay it off a little early, and so I decided to make the spreadsheet easy for anyone to use. Assuming I can figure out how to post it in here somewhere, I'll release it for everyone to take advantage of...
Update: So it seems Blogspot is unable to accept files other than images/video, nor can I place it into a CDATA section within a text area. So until I find a good hosting service, you'll just have to type this stuff in yourself. Here is how I set up my spreadsheet:

Excel Mortgage Calculator

Across the top starting at cell A1, create bold, centered column headers:
  • Year
  • Month
  • Payment
  • Interest Paid
  • Principle Paid
  • Remaining Balance
  • Paid So Far

On the next row, fill in a few of the cells like this:
  • 1
  • =$J$4
  • (Empty)
  • (Empty)
  • (Empty)
  • =$J$1
  • (Empty)

On the next row, fill in the cells like this:
  • (Empty)
  • =DATE(YEAR(B2), MONTH(B2) + 1, DAY(B2))
  • =$J$6
  • =-IPMT($J$2 / 12, 1, $J$3 * 12, F2)
  • =C3-D3
  • =F2 - E3
  • =SUM($C$3:C3)

Now, copy that last row and paste it into every row through 362. As a shortcut, after copying the row, you can select that whole huge block of cells and paste; they'll all fill in properly. After filling those in, write in the year numbers down column A, one every 12 cells (so cell A2 has "1", A14 has "2", and so on down to "31" in cell A362).
Next, create a small table over on the right side by creating bold labels down column I like this:
  • Starting Balance
  • Interest Rate
  • Term (years)
  • Starting Date
  • (Empty)
  • Monthly Payment

Values for those labels you just created go in column J. For now, just enter "30" for the term, and "=-PMT($J$2 / 12, $J$3 * 12, $J$1)" for the monthly payment.
You're almost done now. Everything would work, but it wouldn't be very legible, so let's do some quick formatting:
  • Click on the "B" column to select the whole thing, go to the menu item "Format | Cells", choose "Date" as the category and "Mar-01" as the type.
  • Columns C through G get the "Currency" category with negative numbers marked as red and in parenthesis.
  • Cells J1 and J6 get the same Currency formatting as columns C-G.
  • Cell J2 gets formatting as a Percentage with 3 decimal places.
  • Cell J4 gets the same Date formatting as column B.
  • Feel free to change the column widths however you like.

To Use

Type in your mortgage terms in the little table at the right. It defaults to 30 years because that is common and it prevents Excel from filling all of the cells with error codes, but you can change the value however you need. The length of the table won't change if you change the term, though, so you may need to copy/paste some new rows or delete/ignore existing rows.
The monthly payment will automatically be calculated based on the values you set above; if it is not the same as your real mortgage, it is probably due to extra fees charged by your bank (such as mortgage insurance), which have nothing to do with your loan payments and are only tacked on for convenience.
Now the table should be listing out how your mortgage will act as you pay it off. To pre-pay portions of it, just change the payment for the month to see how things change. For example, you can save quite a bit of time by paying an extra $1000 per year or by paying as if it was a 20-year loan whenever possible.
I hope this helps all of those other new home-buyers like myself figure out how all this financing stuff works. Please feel free to leave comments on how you like the spreadsheet. I'm sorry I wasn't able to post the original.
2013-04-22 Update: This spreadsheet is completely compatible with OpenOffice and LibreOffice, which is what I use now.
2016-02-28 Update: I have since switched to Google Docs, which means I can make a template so anybody can copy and edit without needing to trust a downloaded MS Office file. Just go here and choose Make a Copy from the File menu. I've changed the formatting a little from what I described above.

Thursday, October 16, 2008

Shell Scripting

One thing that Linux and its brethren have always done well is shell scripting. Windows users are unfortunately missing out on this wonderful tool.

Oh, sure, Windows has DOS .bat and .cmd files, PowerShell scripts, and VBScript .vbs files. That's three different scripting languages to learn, if you want to work with other people (since in a group, someone else is bound to prefer something different than you). Plus, I have an intense dislike of VBScript, mainly for reasons like this:

Three lines to copy a file? Honestly? Anyway, I digress.

Shell scripting may not always be clear, but it does provide powerful tools for doing tasks that would otherwise take forever. Here are a few examples that may help with your media collection:

Rename with Lowercase Extensions

This will rename all files in the current directory and all subdirectories to have lower-case file extensions. It also demonstrates how you may get around the spaces-in-filenames issue that plagues most script writers:

Convert All Files to AVI

Here is one example that I use regularly at home. It takes all non-AVI files in this and all subdirectories and makes them into 2-pass encoded XviD AVIs using MEncoder. My wife and I own a DVD player that plays DivX/XviD files, so this makes any videos we may acquire playable on it:

I hope these are useful. Check back again for other scripting tips.

Tuesday, October 14, 2008

Raytracing for Dummies

A little while ago, I posted about NVidia's CUDA; this is a follow-up on what I've been doing with it.

Most people, I noticed, seem to start out by writing yet another Matrix Multiplication for parallel processing. I don't know about the rest of you, but I never seem to need a faster matrix multiplication... Heck, I rarely even need a slow one.

So instead, I decided to write a raytracer. I wrote one in Java just for fun a few months ago, so this isn't completely out of the blue; Java, simply by being Java, is not exactly the fastest language for rendering. So this time I decided to focus on performance, and add visual features after I was happy with that.

About the title of this post: I plan to describe how a raytracer works from a programmer's perspective. Here's where that starts:

Raytracing is done by shooting rays from the viewer (camera) into the scene to see what they hit. An image is generated by using the results of these ray-object intersections to color pixels.

To make things more complicated, at each ray-object intersection, multiple rays may be shot in other directions to detect light sources, reflections, and refractions. All of these rays return color data, which is somehow combined into a single color for a pixel.

This is the kind of description that you can find anywhere. The problem that I have with it is that there are no details. How do you shoot the rays? What directions? How do you combine the colors?

I'm going to answer some of this, and I'm going to be specific.

Firstly, you need to understand how everything is laid out. To start, you will need a camera and a viewport. Think of the camera as the eye of the person viewing your scene, and the viewport as the screen displaying the image.

You will need the following data: Position of the camera (x, y, z), direction the camera is facing (x, y, z), distance from the camera to the viewport, dimensions of the viewport (width, height) both in pixels and in scene units.

Scene units? Your scene should be defined using floating-point coordinates in 3-space. You can choose whatever size these units should represent, just be consistant within your scene. I like to think of 1 unit = 1 foot.

Now what about shooting those rays into the scene? This is actually relatively simple now: Shoot one ray from the camera through each pixel of the viewport. That will give you a starting point and a direction, which is exactly how rays are defined. Then all you need to do is search your scene objects for intersections.

This involves a significant amount of 3-D trigonometry, however, which wasn't exactly stressed in my High School. But I've figured out some calculations that should help:

Firstly, you need to imagine your viewing plane as being a screen in front of the camera. You need to know the positions of each of the pixels in this screen so you can determine the directions for all of your rays. Here is how to compute the position of each pixel:

Variables used here that you must define (a vector has .x, .y, and sometimes .z coordinates):

  • cameraPos = The position of the camera; a floating-point 3-D vector
  • cameraDir = A point that the camera is looking at directly; a floating-point 3-D vector
  • cameraDist = The distance between the camera and the viewport; a floating-point number
  • viewportSize = The size of the viewport in scene units; a floating-point 2-D vector
  • screenSize = The size of the screen in pixels; an integral 2-D vector

The function 'normalize()' on Vector3 objects returns a vector pointing in the same direction that is 1 unit long.

So if anyone is trying to write their own raytracer, grab that 'angle' variable and use it as the direction of each ray you try to shoot.

Lighting is one of the simplest features you can add to a raytracer. Each time a ray hits an object, loop through all of your light sources and try to reach it from the point where the ray hit the object; if you can reach the light source without striking another object in between (including the one that the original ray hit), that point is lit by that light source.

One thing to be careful of, though: Any time you have a hitpoint and you want to shoot a new ray from there, add just a little bit of the normal for the surface at that hitpoint to the starting point for the new ray, so you don't immediately strike the object you are bouncing off of.

Here is a simple ray-object intersection equation that you may find useful; it is for a sphere, and was originally taken from the WildMagic foundation library of intersections (GPL code):

Requires:

  • center = center of the sphere; floating-point 3-D vector
  • radius = radius of the sphere; floating-point number
  • origin = starting point of the ray; floating-point 3-D vector
  • direction = direction of the ray; floating-point 3-D vector

Outputs:

  • hitpoint: the first point where the ray hits the sphere, or null if it does not; floating-point 3-D vector
  • normal: the normal of the sphere surface where the ray struck it; floating-point 3-D vector

A note about ZERO_TOLERANCE: Since floating-point calculations are not exact (if you have variables A and B which both contain numeric results that should be equal but were achieved using different calculations, A == B may come back false), ZERO_TOLERANCE is used to put a small boundary around 0 that is considered equal to 0. You should probably set it to something like 0.00001.

Combining colors is a much more difficult concept, I've discovered. Here is what I have been doing, although I am not satisfied with it:

Colors are represented as Vector3 objects; x = red, y = green, z = blue. Each color channel should be in the range [0, 1] with 0 = 0 and 1 = 255.

I simply add the color of each object struck by the ray to the colors of any lights shining on those hitpoints, and either clamp (bound x, y, and z to the range [0, 1] independently of each other), or scale (scale all components back by the largest one, if any are above 1) the colors. I haven't found a better way to do this yet, although I am planning to try scaling back the influence of each color as I traverse more and more rays to reach it.

Hope I got someone interested in this stuff; it's a cool way to generate 3-D scenes.

NVidia CUDA

The other day I picked up NVidia's CUDA (Compute Unified Device Architecture, which I must say is a pretty bad acronym) to have something new to play with. (Some people tinker with car engines, I tinker with software packages... I know, I'm a little odd.) I've always had an interest in parallel programming, so CUDA seemed right up my alley.

Then I tried to install it. Maybe others have had an easier time of it, but my experience was less than top-notch. I run a dual-boot system at home, Windows XP Pro and KUbuntu 8.04.

Windows

I had no trouble at all installing CUDA on Windows, but the compiler that comes with it enforces a requirement for version 7.1 or 8.0 of Microsoft's compiler (Visual Studio 2003 or 2005, respectively). I don't have either of those, and it didn't seem worth hunting down a copy, so I gave up at that point.

Linux

Being created by and for software developers, I've found that the one thing you can always count on in Linux is the C compiler. It never seems to break.

Unfortunately, drivers are another issue. CUDA requires a new version of NVidia's device drivers, and the drivers require a new version of the Kernel module that supports them. I must have installed the drivers four or five times, always getting the same failure back from the device query program that comes with the CUDA SDK. It kept reporting that the driver was version 173.something, and the kernel module was version 167.someotherthing.

I fought with it for a day and a half, only to discover from a forum post that I needed to add "nv" to the list of disabled kernel modules in some /etc file that I'd never seen before. And suddenly it worked! I love that feeling of accomplishment when something suddenly works, even if I needed help. Sort of like when you finally kill the mosquito that bit you three times and has been buzzing in your ear for half an hour.

So expect some updates soon about how my CUDA programming is coming.

Friday, October 10, 2008

My First Day

For a while I've been toying with the idea of creating my own blog. I'm a software engineer, and surprisingly often I will encounter something that I'd like to share. So yesterday I gave in and signed up for a Blogger account. I was reading someone else's blog (can't remember whose now) and saw the sign-up link and just decided to go for it.

After getting through the tedious procedure of choosing a name for my account (my top choices were all taken by inactive blogs with "First Post!" entries from over a year ago), I finally had my own place to post insights/rants about whatever I felt like.

I didn't have anything to say.

I'm sure everybody has the same problem; you get all pumped up to do something creative, and... Nothing comes to mind. So I figured I'd just leave it alone and come back in a day or two with something.

Then this morning I checked my email to find out that Blogger had disabled my account. One fucking day into owning my own blog and they DISABLED MY ACCOUNT. Why? Was it because I didn't have anything to say?

No. It was because my shiny new blog looked like a spam blog to their moronic spiders. What is a spam blog? According to this page it is a blog with nonsensical text linking elsewhere. I assume the goal is to confuse search engines, which rank pages by how many links point to them.

What I'm confused about is how my empty blog looked like I was link-spamming!

Anyway, I went through their page to request an unlock review today (October 10, 2008) and we'll see if they can unlock things as quickly as they lock them. My guess is no.

Edit: October 13, 2008, I am no longer under suspicion of being a spam blog.