Latest Entries »

I recently needed to verify that a user’s input was a valid US social security number.  Initially, I thought it was just a simple task of verifying 3 digits, a dash, 2 numbers, another dash, and finally 4 numbers.  However, as I started reading online, I realized that each block of numbers has a significance (which I assumed) and more importantly to my task, that they have specific numeric ranges.

If you want to read the details of the format then see the links at the bottom of the post.  The gist is that as of June 25, 2011, a valid social security number needs to follow the following guidelines:

  • It must begin with 3 digits in a range from 001 to 899. The cap previously was 772, but was recently extended to 899.  They cannot be 666 (go figure), and as the range implies, they cannot be 000.   These numbers were originally associated with an assignment territory, but that is no longer the case for new numbers.  If you’re wondering about 900-999, the government holds those out for use in marketing materials, and other documentation.
  • The second set of numbers must be 2 digits in the range of 01 to 99. Similar to the first set, these can’t be 00. The government uses an odd/even number formula to determine which to use.  See the links for more information.
  • The last set of numbers is a set of 4 digits, in the range of 0001 to 9999, and also can’t be 0000.  These numbers are sequentially assigned to individual people as their unique id.

So, armed with those guidelines, knowing that there are dashes between the sets, and after seeing how a few other people did this incorrectly, I came up with the following function to validate my data:

function isValidSSN(value) 
{ 
 /* validates a US Social Security Number (SSN):
 + 3 digits from 001 to 899 (can't be 666)
 + 2 digits from 01 to 99 (based on some US govt odd/even formula)
 + 4 digits from 0001 to 9999 (assigned sequentially to individual people)
 + last section verifies that none of the number groups are all zeros
 */
 var re = '^([0-8]\d{2})([ \-]?)(\d{2})\2(\d{4})$'; 

 if (ArrayLen(ReMatch(re,value)) == 0) { return false; } 

 //remove the dashes & spaces to check for zero sequences
 var temp = Replace(Replace(value,'-','','all' ),' ','','all' );

 if(Left(temp,3) == "000" || Left(temp,3) == "666") { return false; } 
 if(Mid(temp,4,2) == "00") { return false; } 
 if(Right(temp,4) == "0000") { return false; } 

 return true; 
}

Let’s break down the Regular Expression first. The first section handles the first 3 digit number set:

^([0-8]\d{2})

The ^ says this value must begin with the following pattern, inside the parenthesis, ( ).

Then [0-8]\d{2} tells the regex engine to match any number 0 through 8, [0-8] denotes the range, followed by any 2 other digits, 0 through 9, \d{2}. The \d means any digit, and the curly braced 2 says to look for that 2 times in a row.  So this piece matches 001, 235, 575, or 899.

The next section of the pattern simply says “followed by a space or a dash or nothing”.  The ? at the end means zero or 1 occurrence of the subexpression, which is why you only have to add the space and the dash literally:

([ \-]?)

The next section is also simple, stating that the next piece should be any 2 digits.  Again, \d means any digit 0-9:

(\d{2})

The next part, the \2 tells the regex engine to look for the second part of the expression again. In this case, look for a space, dash or nothing again between the second and third number sets.

And now for the last section, we simple need any 4 digits. The only new character here is the ? which is telling the engine that this expression inside the parenthesis, must come at the end of the pattern:

(\d{4})$

Now that we have brook down the pattern, the rest of the function is just simple string functions.  First we run this pattern agains our input value.  The ReMatch() function will return an array of the matched parts. So we run that, and check to see if the returned array has any length. If not, we immediately return False and the function ends:

if (ArrayLen(ReMatch(re,value)) == 0) { return false; }

In the last part, we need to check each number set to be sure that the numbers are all zeros and that the first set is also not all sixes. First we strip out any dashes and spaces, so we are working with a 9 digit number no matter what the user entered.  Then, with simple string functions, we check the first three digits, the middle 2 digits and finally the last three numbers.  If any of these matches our criteria of “000″ or (“666″ for the first set), we return false and end the function.

If all of these steps match; if we find the patterns allowed, and none of those are all zeros, or sixes in the first set, then we simple return True, letting the user know that the value they entered is indeed a valid US Social Security based on the regulations as of June 25, 2011.

Sources:

Wikipedia: “Social Security Number”

Social Security Online: History

ColdFusion 9: Regular Expression Syntax

CFQuickDocs: ReMatch()

Knowledge is Power

Michael Zagaris/Getty Images "Knowledge is Power"

Pretty interesting article about how current technology, especially the Apple iPad, is helping baseball players keep up with the industry, track stats, improve their game and better prepare for their competition. Read More

Windows 8 UI

Windows 8 UI

This is just horrible, to think that Microsoft actually believes that this UI experience is better for their users. Windows 98 was better than this!

I also notice the OSX folder naming scheme, so sadly they are even looking at better and still miss the mark.

Read more here.

See some other user perspectives here.

I recently updated a Mura CMS site I maintain, by adding a new “portal of portals” section. The main portal listed a series of guest authors that are writing articles for our site. Each author block in the portal list was actually its own portal or article pages. This is all common practice in Mura and in my opinion, one of the areas where it excels at adding content.

All the pages in this section are a two-column, 70/30 layout, with the main content on the left and some author specific information in the right. Both the author article portal list and each article all have the same content on the right, so I made an “authors info” component for that information. This content is a set of the author’s favorite Web sites. To make that content easy for my Editors to maintain, I extended the author’s portal template in the Class Extension Manager, and added new attributes to collect the link information. In my case, I added 10 fields to collect up to 5 links in the form of a Text/URL combination. My attributes are named Link1Text, Link1Url, Link2Text, Link2Url and so on.

So I now have one common “authors info” component in mu Mura admin that I include in the right side of my two column layout. The code view of that component looks like this:

<div class="span-7 last sidebar">
   <img alt="About the Author" src="/xyzsite/assets/Image/sidebars/sidebar_authorsinfo.gif" />

   <p style="font-style: italic;">"Take a look at some of my favorite sites"</p>
   <ul>
	[mura]dspInclude('display_objects/custom/ali/dsp_authorsInfo.cfm')[/mura]
   </ul>

<!--- static content to link users to other author sections --->
   <hr width="50px" />
   <p>See all of our authors pages:</p>
   <ul>
	<li> <a href="/index.cfm/articles/author/Author-A/">Author A</a> </li>
	<li> <a href="/index.cfm/articles/author/Author-B/">Author A</a> </li>
	<li> <a href="/index.cfm/articles/author/Author-C/">Author A</a> </li>
	<li> <a href="/index.cfm/articles/author/Author-D/">Author A</a> </li>
	<li> <a href="/index.cfm/articles/author/Author-E/">Author A</a> </li>
   </ul>
</div>

To pull the links and information into the component, I made a custom Mura display file (a CMF file) that I include in my template. That file started like this:

/xyzsite/includes/display_objects/custom/xyz/dsp_authorsInfo.cfm

<cfloop from="1" to="5" index="x">
   <cfset txt = $.content('Link'&x&'Text')/>
   <cfset lnk = $.content('Link'&x&'Url')/>

   <cfif (len(txt) GT 0) AND (len(lnk) GT 0)>
      <cfoutput>
           <li><a href="#lnk#">#txt#</a></li>
      </cfoutput>
   </cfif>
</cfloop>

In my Extended Attributes I have fields that collect a link and the text to hyperlink for up to 5 links. So here I run a loop from 1 to 5, set my link and text values, and then if both have content I add them as a list item.

When i saved all of this and reloaded an author’s portal page, I saw my links loaded as expected. However, when I opened an actual article written by that author, all I saw at the on the right was “Take a look at some of my favorite sites” then nothing. That is because my extended attributes are part of the main portal page and not the article sub-page. If you look at the code, I am loading Mura’s “content” object. The Mura Programer’s Guide explains that the “…Content scope wraps the CURRENT front end request’s contentBean”. So when I look at the portal page, where the custom link attributes are defined, they are available in the content scope.

So, if I can only get the currently loaded page’s info in the content bean, then how can I get the content from other pages? In my case, the Programmer’s Guide led me to a very simple solution: call the parent object using the getParent() method of the $.content() method. Doing this will return the data from the current’s page’s parent page as a contentBean. With that knowledge I updated my custom display file as so:

/xyzsite/includes/display_objects/custom/xyz/dsp_authorsInfo.cfm

<cfloop from="1" to="5" index="x">
<cfsilent>
   <cfset page = ListLast(cgi.PATH_INFO,'/') />

   <cfif  (page IS 'Author-A')
       OR (page IS 'Author-B')
       OR (page IS 'Author-C')
       OR (page IS 'Author-D')
       OR (page IS 'Author-E')
   >
     <!--- user is on a author portal page where the link values are available --->
     <cfset txt = $.content('Link'&x&'Text')/>
     <cfset lnk = $.content('Link'&x&'Url')/>
   <cfelse>
     <!--- user is on a article page, so grab info from the parent --->
     <cfset parentBn = $.content().getParent() />
     <cfset txt = parentBn.getValue('Link'&x&'Text')/>
     <cfset lnk = parentBn.getValue('Link'&x&'Url')/>
   </cfif>

   <cfif (len(lnk) GT 0) AND (lnk CONTAINS 'mysitedomain.com')>
       <cfset openIn = "_self" />
   <cfelse>
       <cfset openIn = "_blank" />
   </cfif>
</cfsilent>
   <cfif (len(txt) GT 0) AND (len(lnk) GT 0)>
       <cfoutput>
          <li><a href="#lnk#" target="#openIn#">#txt#</a></li>
       </cfoutput>
   </cfif>
</cfloop>

As you can see, at the top I updated my code to determine if the right side component was being loaded on an author’s page, by looking at a CGI var. If so, I set my links the same way I did originally. If not, then I assume the right side component is being loaded on a nested article page, so I first get my parent page’s contentBean, then set my links that way. In addition, I added some code to determine my link’s target value.

This all seems to work well. I would like to dig a little deeper and find out if I can dynamically find out how many attributes my page has. That way I wouldn’t need to hard code the 1 to 5 loop, and could easily add more link pairs in the future.