• entries
68
177
• views
82851

## Getting started with Node.JS part 1: Setup

I had been hearing about Node.JS for a while. "It's JavaScript on the server!" I mostly ignored it, as ASP.NET was forced on me at the time and I hadn't yet given employed life the finger and a flaming bag of poo on its doorstep[1]. What does "JavaScript on the server" even mean?

Well, it's a little more than just the bare meaning of a JS execution environment outside of a browser. Think of it like JS finally making something out of itself. All those years in college. Getting stuck in low paying design jobs. Now it commands respect! It can connect to databases!

Basically, start with V8--Google's JavaScript engine, not the salty-disgusting-juice that tricks you into eating vegetables when you were expecting a fruit smoothy instead. Just like the JavaScript that runs in their Chrome web browser. Then, throw away DOM--or rather--never add it because you didn't add WebKit into the sauce. Finally--and here comes the important part--throw on top a reliable package manager and a core set of libraries that make building a stand-alone Web server nothing more than a few lines of configuration code.

I should probably just shut up now and get to the point, because I'm the one late to the party and you, dear reader, probably know all this junk already.

## IEEE Float Suck

IEEE standard floating point numbers, at any bit depth, should not be used to define color spaces. Specifically, one should not use floats or doubles (henceforth collectively "floats") as color components when rendering High Dynamic Range Imagery (HDRI). Due to the nature of the representation of floats, they cannot be used to define uniform color spaces.

The IEEE standard for floating point numbers defines a 32 bit float as a 1 bit sign value, an 8 bit biased exponent value, and a 23 bit fraction value. The exponent is "biased" in that it represents an integer value from which the value 127 is subtracted, to give a real range of exponent values from -127 to +127. The fraction is the fraction portion of a number expressed in "floating point binary notation".

There are 6 reserved values

0 00000000 00000000000000000000000 = 0
1 00000000 00000000000000000000000 = -0

0 11111111 00000000000000000000000 = Infinity
1 11111111 00000000000000000000000 = -Infinity

0 11111111 00000100000000000000000 = NaN
1 11111111 00100010001001010101010 = NaN

Any value that uses a full bit field for the exponent value is a non-number with the IEEE representation. With this exponent, and a 0 fractional value, it is interpreted as signed infinity. With a non zero fractional value, it is interpreted as Not A Number. Because of this interpretation, there are a full 2**24 unusable values when using floats as color components.

For example, the number -32.5625 would be converted as

S = 1, as the number is negative
temp = 100000.1001, "floating point binary representation"
= 1.000001001 x 2**5
E = 5 + 127 = 132
= 10000100
F = 000001001, drop the "1." from representation

Full number:
1 10000100 00000100100000000000000

The problem with color spaces lies in calculating the difference between two "consecutive" floats, i.e. floats that differ only in their least significant bit. Color is equally dependant on the relationship between two very similar colors as it is on the absolute value of a single color. Without thinking about the problem, one might think that this difference is very small, as floats are capable of representing very small numbers. However, once we start calculating the exact decimal value of the float representation boundary cases, we see that the difference between "consecutive" floats is dependant on the actual value of the numbers.

As an example, I've constructed a "4bit IEEE-like floating point number." It has no sign bit; a positive, 2 bit, unbiased exponent (so translating the exponent is not necessary, as with 32 or 64 bit floats); and a 2 bit fraction. Otherwise, calculating the value follows the same rules as regular IEEE floats. The purpose of using such a limited example is to allow us to see the full range of values that can occur for a specific representation.

bin | sci not |fp bin| dec | delta
========================================
0000 | 1.00 x 1 | 1.00 | 1 | -
0001 | 1.01 x 1 | 1.01 | 1.25 | 0.25
0010 | 1.10 x 1 | 1.10 | 1.5 | 0.25
0011 | 1.11 x 1 | 1.11 | 1.75 | 0.25
0100 | 1.00 x 2 | 10.0 | 2 | 0.25
0101 | 1.01 x 2 | 10.1 | 2.5 | 0.5
0110 | 1.10 x 2 | 11.0 | 3 | 0.5
0111 | 1.11 x 2 | 11.1 | 3.5 | 0.5
1000 | 1.00 x 4 | 100 | 4 | 0.5
1001 | 1.01 x 4 | 101 | 5 | 1
1010 | 1.10 x 4 | 110 | 6 | 1
1011 | 1.11 x 4 | 111 | 7 | 1
1100 | 1.00 x 8 | 1000 | 8 | 1
1101 | 1.01 x 8 | 1010 | 10 | 2
1110 | 1.10 x 8 | 1100 | 12 | 2
1111 | 1.11 x 8 | 1110 | 14 | 2

What this shows us is that the difference in values in the range of floating point numbers is not fixed.

Next, we will calculate the exact decimal value that two "consecutive" floats represent. These numbers are the 2nd-largest and largest possible, positive floats.

2nd largest 32 bit float
Binary: 01111111011111111111111111111110
Sign: 0
Exponent: binary 11111110 - 01111111 = 254 - 127 = 127
Fraction: 11111111111111111111110 = 2**24 - 2
Binary scientific notation: 1.11111111111111111111110 x 2**127
Decimal: 3.4028232635611925616003375953727e+38
Equivalent: 2**128 - 2**105

largest 32 bit float
Binary: 01111111011111111111111111111111
Sign: 0
Exponent: binary 11111110 - 01111111 = 254 - 127 = 127
Fraction: 11111111111111111111110 = 2**24 - 1
Binary scientific notation: 1.11111111111111111111111 x 2**127
Decimal: 3.4028234663852885981170418348452e+38
Equivalent: 2**128 - 2**104

Difference: (2**128 - 2**104) - (2**128 - 2**105) = 2**105 - 2**104 = 2**104 = 20282409603651670423947251286016
or roughly
2.0282 x 10**31

We can do the same calculations for the difference between the two smallest numbers and come up with a difference of 2**-150, or an extremely small number.

Using floats to define a color space will result in a non-uniform color space. There will be a lot of subtlety in the middle of the range, and giant leaps between values at the ends of the range. In the end, there are really only 2**32 - 2**24 unique and usable 32 bit floats (as was previously demonstrated) unique and usable 32 bit floats, because of the 5 "special values" that the IEEE float specification defines for values such as plus or minus infinity. Just these special values alone limit the expressive power of floats in defining a color space.

Unsigned integers work much better for defining color spaces, as there are a full 2**32 unique and usable values, and the difference between the largest two integers is the same as the difference between the smallest two integers: only 1.

## AAGHH!

I am so pissed off right now, and this is why:

MOTHER OF PEARL! LINE THE HELL UP!!!

This is a mapping application that we are customizing for a client. They have a format of data called RPF that ESRI MapObjects is particularly bad at cacheing. However, we found an open source project called OpenMap that handles RPF data very well. So it should be a whiz-bang process to create a custom MobObjects layer (the MapObjects API supports this) that uses the OpenMap code to spit out images. Making a small application that did nothing but spit out images given a path to RPF data and the extents of the image was nothing, simple task. Writing custom MapObjects layers is also not a big deal, we do it all the time.l

EXCEPT OPENMAP DOESN'T DEFINE MAP EXTENTS IN ANY SANE MANNER!!!!

Typically, a map extent is defined as the min/max latitude and longitude. OpenMap on the other hand expects a center latitude and longitude, along with a map scale. Fine, whatever, except it completely ignores any concept of aspect ratio! But let's ignore that, let's just calculate the damn scale... wait, you CAN'T because a monitor's pixel-per-inch ratio is not fixed!

So, after much trial and error, I've come up with something that is a reasonable scale factor... I think. Panning the map left-right is good, panning it up-down is okay, but if you pan it diagonally you get this freaking fracturing of the image.

GHAKGHAKALHGAH!!!!!!!

## TDD for the masses

If you hang out in #gamedev, then you've heard Washu and I talk a lot about WHY you should use TDD, with plenty of horror stories of when people DIDN'T use TDD. But we don't really talk about HOW to use TDD. I wrote this 1-printed-page (had to cheat on the margins) document for use at work, in an attempt to convince everyone else that they should be using TDD, just like they said they would. (don't ask) Anyway, it covers the main points (though not all of them), and has a couple of resource links for more information. The point of this doc is to be short. People won't pay attention to 2+ page docs.

Test First, Ask No Questions Later

Test driven development (TDD) can help developers create higher quality code on first iteration, as it helps developers avoid common errors of logic and design. The tests serve as a form of documentation, making clear the proper usage of the code. A large test suite facilitates subsystem integration, as it provides immediate feedback when new changes break old code. Test results are explicit and discrete, giving a better overview of the development progress. In short, tested code is confident code.

The TDD cycle:
1.) Take small implementation steps; large changes introduce large bugs,
2.) Design your implementation with testing in mind; determine what defines successful completion of the requirement and how to test for that completion
3.) Write one test; resist the urge to code in large runs,
4.) Write enough code so that your tests compile; do not write an implementation--just stubs,
5.) Run your tests, your new test should fail; if this is a tertiary pass through the TDD cycle, your changes may cause other, previously passing tests to fail,
6.) Write just enough code to pass all the tests; do not continue until all the tests pass, in this way you know that your changes do not break existing code,
7.) Refactor as necessary; minimize duplicate code, eliminate inefficiencies,
8.) Continue from step 2; consider if you need to expand your testing, remember to test boundary cases of input (bad input, good input that is close to being bad, typical input, etc.),
9.) Return to step 1; continue implementing small pieces of the requirement.

Tips on writing good tests:
1.) How to move a mountain: blast it into pebbles. Small tests (as defined by the number of Assertions made by the test) have a very high "Testing Resolution". A failed assertion immediately terminates the test, even if the test contains more assertions. Large tests with multiple assertions may hide assertion failures that occur after the first failed assertion. By splitting multi-assertion tests into single-assertion tests, all Assertions that can fail will fail, giving a higher resolution picture of the defect at hand. The test itself may be long on code to prepare for the Assertion, but it should only have one or two assertions.
2.) Test early, test often, test everything. Developers may feel like TDD requires more time than coding without testing. Initially, this is true. The developer not only takes the time to write the code, they also take the time to write the tests. The total amount of time spent on the code is far less, as higher quality code requires fewer bug fixes.
3.) The only good GUI is a thin GUI. How will you programmatically duplicate user interaction with reliability, precision, accuracy, and flexibility? Design GUI's as only being a front end to well-tested, GUI-independent logic classes. Ensure the GUI elements are receiving the expected bindings and trust that the GUI elements of the Operating System work as advertised. This also aids in code reuse.
4.) In with the good data, out with the bad. How will you programmatically ensure that a map does not render 500 feet off kilter? In general, data validation must be completed via Regression Testing (comparison to known good results) or typically "by eye".

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp02172004.asp (includes an example project)
http://www.nunit.org/getStarted.html (getting started with nUnit)