I lived in Korea last year and spent some time learning the language – just enough to shop and eat.  One of the biggest problems I had while shopping was translating numbers in my head without asking the person to repeat themselves 10 times.  I created this app to help me get better.

Pretend that you asked someone “How much does this cost?” and they answered ₩25,000. You know Korean numbers but now your on the spot and have to do the math quickly in your head.

You can use this app to practice. Just listen to the voice samples and punch in the numbers you hear.

There are three levels of difficulty:
Easy – ₩70,000, ₩5,000, ₩ 300, etc…
Medium – ₩76,000, ₩5,500, etc…
Hard – ₩76,500, etc…

Voice samples are downloaded from the internet. If you are not connected to the internet, it will use samples that you have heard before.

The following example uses a closure – on the local variable value – to mimic a private variable.

```// returns counter object
function createCounter() {
var value = 0; // used by add, sub, val
return {
add: function(x) { value += x; },
sub: function(x) { value -= x; },
val: function() { return value;}
};
}

// create two counters
counter1 = createCounter();
counter2 = createCounter();

// use the counters
var val1 = counter1.val();
var val2 = counter2.val();
counter1.sub(4);
var val3 = counter1.val();

// the result: val1 is 14, val2 is 32, val3 is 10
```

The functions add, sub, and val are created and returned every time the createCounter function is executed. When they are created, the local variable value is in scope meaning it can be used by those functions.  Normally, when createCounter returns, the variable value would fall out of scope and be destroyed.  However, because value is used by the functions add, sub, and val it is not destroyed.  Instead, value remains available to those functions – this is a closure.

The functions add, sub, and val all have access to the same instance of value meaning changes to value are seen by all three functions. That is why val1 is 14 and val3 is 10.  If each function had its own private copy of value, the code would be useless because val would always return 0.

Each time createCounter is executed a new closure is created with its own instance of value. Because of this, calls to the functions in counter1 and counter2 do not interfere with each other. That is why val1 is 14 and val2 is 32.  This is powerful technique for controlling the scope of variables – try writing similar code without using a closure.

Once you understand this example, check out this detailed explanation provided at the Mozilla Developer Center.

I am upgrading trackyourruns.com from Google Maps API version 2 to version 3. The process has been fairly painless but I have discovered that a few key functions are missing. For example I was using the getLength() method of GPolyLine (PolyLine if V3) to determine a line’s length in meters.  Currently, there is no way to do this using version 3 of the Maps API.  Fortunately, José Fernando Calcerrada created extendedApi which adds functions to LatLng, Marker, Polyline, Polygon that are missing in V3.

### ** No longer available **

trackyourruns.com allows you to figure out how far you ran (or plan to run) using Google Maps. A few different websites can already do this but I think they are a little user-unfriendly. Some improvements trackyourruns.com provides over the other websites include:

• Intuitive handling of mouse events (like zoom with the scroll-wheel)
• Map controls that are self-describing

I have many more convenient features planed. I will post updates here as they are developed.

Recently I encountered a very frustrating error while installing Joomla! 1.5 on my development machine (Windows 7 / Apache 2.0 / PHP 5.3 / MySQL 5.1). I followed the easy to use installation wizard but when I reached the database configuration step (step 4 I believe) things got ugly.

I entered the database information (host, user name, password, and database name) and then click next. After about 30 seconds I saw a blank screen. A quick look at the logs returned very little information; all I found was an error 500 in Apache’s access log. After some digging around I came to the conclusion that is must be a problem between PHP and MySQL.

I whipped up a quick test would help me diagnose the problem.

```mysql_connect("localhost", "root", "mypassword")
or die("Could not connect to database.");
print "Connected to database.";
```

I was expecting to see ‘Could not connect to database.’ and to have some useful info dumped into the logs. Instead I received a blank screen after about 30 seconds… Eureka! This is the exact same problem I had with the Joomla! install.

After reading through the mysql_connect docs, I discovered that connecting to ‘localhost’ actually attempts to use a socket (named pipe on Window) but connecting to ‘127.0.0.1’ will use TCP/IP.

Apparently, I configured MySQL to accept connections from TCP/IP but not sockets/pipes. When mysql_connect attempted to connect to MySQL it did not receive a response and after about 30 seconds PHP timed-out the request resulting in a 500 error response.

I fixed this problem by simply changing my host parameter from ‘localhost’ to ‘127.0.0.1’.

Jeff Atwood posted a white-list approach to sanitizing HTML output on RefactorMyCode (http://refactormycode.com/codes/333-sanitize-html). I ported the code to ColdFusion and decided to share it with the community.

```<!--- ORIGINAL CODESNIPPET:4100A61A-1711-4366-B0B0-144D1179A937 --->
<cfcomponent>
<cfset variables.reTags = '<[^>]*(>|\$)'>
<cfset variables.reWhitelist = '(?x) ^</?(b(lockquote)?|code|d(d|t|l|el)|em|h(1|2|3)|i|kbd|li|ol|p(re)?|s(ub|up|trong|trike)?|ul)>\$ | ^<(b|h)r\s?/?>\$'>
<cfset variables.reWhitelistLinks = '(?x) ^<a\s href="(\##\d+|(https?|ftp)://[-a-z0-9+&@##/%?=~_|!:,.;\(\)]+)" (\stitle="[^"<>]+")?\s?>\$ | ^</a>\$'>
<cfset variables.reWhitelistImages = '(?x) ^<img\s src="https?://[-a-z0-9+&@##/%?=~_|!:,.;\(\)]+" (\swidth="\d{1,3}")? (\sheight="\d{1,3}")? (\salt="[^"<>]*")? (\stitle="[^"<>]*")? \s?/?>\$'>

<cffunction name="findAll" returntype="array" output="no" access="private">
<cfargument name="regex" type="string" required="yes">
<cfargument name="text" type="string" required="yes">

<cfset var L = structNew()>
<cfset L.result = []>
<cfset L.offset = 1>
<cfloop condition="true">
<cfset L.match = reFind(arguments.regex, arguments.text, L.offset, true)>

<cfif L.match.len[1] GT 0>
<cfset L.details = {
text = Mid(arguments.text, L.match.pos[1], L.match.len[1]),
index = L.match.pos[1],
length = L.match.len[1]
}>
<cfset arrayAppend(L.result, L.details)>
<cfset L.offset = L.details.index + L.details.length>
<cfelse>
<cfbreak>
</cfif>
</cfloop>
<cfreturn L.result>
</cffunction>

<cffunction name="sanatize" output="no" returntype="string" access="public">
<cfargument name="html" required="yes" type="string">
<cfset var L = structNew()>
<cfset L.result = arguments.html>
<cfif len(arguments.html) GT 0>
<cfset L.tags = findAll(variables.reTags, arguments.html)>
<cfloop from='#ArrayLen(L.tags)#' to='1' index='L.i' step='-1'>
<cfset L.tagname = lcase(L.tags[L.i].text)>
<cfset L.allowTag = reFind(variables.reWhitelist, L.tagname) GT 0
OR reFind(variables.reWhitelistImages, L.tagname) GT 0>
<cfif NOT L.allowTag>
<cfset L.result = RemoveChars(L.result, L.tags[L.i].index, L.tags[L.i].length)>
</cfif>
</cfloop>
</cfif>
<cfreturn L.result>
</cffunction>
</cfcomponent>
```

Many people understand that computers store colors as RGB values and that a value like 770000 represents a dark shade of red.  However, RGB values are hard to manipulate in a meaningful way (like brightening a color).  That is where the HSL color space comes in handy.  In the HSL color space, colors are represented by there Hue, Saturation, and Luminance.  The image below shows the full range of Saturation (horizontal axis) and Luminance (vertical axis) when the Hue is fixed at an arbitrary blue value.Once you understand how saturation and luminance affect a hue, you can manipulate these values to produce colors that work well together.  For example, the background of the interior boxes in the simple counters shown below were created by adjusting the luminance of the outer box.

The following code was used to do brighten the main color.  The functions  ColorHLSToRGB and ColorRGBToHSL are defined in the unit GraphUtil.

```
function Brighten(AColor: TColor): TColor;
var
H, S, L: Word;
begin
ColorRGBToHLS(AColor, H, L, S);
Result := ColorHLSToRGB(H, 225, S);
end;
```

Warning: this code assumes AColor will have a low luminance value.