Programming

Date Validation in ColdFusion

Posted in Programming on March 8th, 2010 by Jamie – Be the first to comment

Someone asked me about Date Validation the other day. Here are two simple approaches for use in your CF apps.

Assume that the strDate variable contains your date. On the server-side, you may use IsDate(strDate). On the client side, !isNaN(new Date(strDate)). I don’t know for sure if the client-side code is the best way to do it. There are RE-based techniques, but these are the most concise.

CFML:

    <cfoutput>
      <cfset strDate1 = "2001 Fazuary 1"/>
      <cfset strDate2 = "2001 Feb 1" />

        #IsDate(strDate1)#<br>
        #isDate(strDate2)#

    </cfoutput>

    <!---

    Outputs:

    NO
    YES

    --->

Client-side Javascript:

    <script>
    // This creates a function to test the string.
    // What is this function doing? It takes the
    // strDate string and attempts to convert it into
    // a Date object using the Date constructor.
    // When the Date constructor cannot convert the
    // string, it returns NaN (not a number).
    // So, we wind up testing for NOT NaN using
    // !isNaN. Don't ask me why the Date constructor
    // returns NaN and not NaD (not a date)! =D
    function isDate(strDate) { return !isNaN(new Date(strDate)); }

    var strDate1 = "2001 Fazuary 1",
        strDate2 = "2001 Feb 1";

    alert(
        isDate(strDate1) + '\n' +
        isDate(strDate2)
    );

    //
    // Brings up an alert window that says:
    //
    // false
    // true

    </script>

Bubble Breaker Using Canvas!

Posted in Programming, Software on March 2nd, 2010 by Jamie – 1 Comment

I wanted to try out some canvas element functionality, given that I have a feeling it will steal a lot of Flash’s thunder. I whipped up a bubble-breaker game (the mechanic should be very familiar to you) in a few hours. Enjoy the demo! I may do a quick write up at a later point.

I’ve only tested it in Firefox 3.6. I do not know whether it will work in other browsers.

Demo
Project site

bubble breaker 13x13

bubble breaker 13x13

bubble breaker 30x30

bubble breaker 30x30

Drupal Org Chart – Graph Viz Update

Posted in Programming, Software on February 24th, 2010 by Jamie – Be the first to comment

I have updated the Google Code repository with updates to integrate GraphViz. It expects the PEAR GraphViz package to be installed.  To install it, issue command:

# You must install the beta package.

sudo pear install Image_GraphViz-beta

If you’d rather not mess with PEAR, download the package, extract the class Image_GraphViz, and alter two two lines of code that depend on the PEAR::System package. It should be trivial to change these. They are both basically calls like this:

// create a temporary file with the prefix "graph_"
$file = System::mktemp('graph_');

One possible replacement:

// will use default tmp dir
$file = tempnam('', 'graph_');

Graphiz Problem!

Posted in Libraries on February 20th, 2010 by Jamie – Be the first to comment

I was working on the Drupal OrgChart module tonight, specifically the rendering of the chart image via GraphViz, and I got stuck for at least an hour on a trifle! I planned to use the PEAR library for GraphViz (Image_GraphViz) and I wrote a function using the class it provides. I run the procedure and get weird errors about not being able to find files and such. After debugging for awhile, I find out that there is a property binPath that is not present. I had expected this to point to my install of GraphViz, which I knew to be especially important because it was in a weird macports directory.

It turns out that I had not installed the version I needed! I didn’t realize the version I wanted was beta, and to download a beta package, you need to explicitly state so in the PEAR command.

sudo pear install Image_GraphViz-beta
#instead of
sudo pear install Image_GraphViz

After downloading the most recent package, it turned out my code worked almost perfectly. What a waste of a night!

The past few days, I also worked on a few other modifications. I removed the requirement for a “subordinate_id” field. Also, I made the profile field names options in the administrative settings page.

The project page is here: http://code.google.com/p/drupal-orgchart/.

Drupal Module: Org Chart

Posted in Programming on February 18th, 2010 by Jamie – Be the first to comment

I created an org chart module. It interacts with the profile module to display an organizational hierarchy.

From the project description:

An organizational chart that uses the profile.module. Install in your modules directory. Currently, it uses profile fields to build the chart. It assumes that there will be two fields that hold the following data:

* Employee ID – this can be any alphanumeric identifier
* Supervisor ID – this is the alphanumeric identifier pointing to the current user’s supervisor.

In the administrator settings, you may specify the profile field names which correspond to these values.

There are plans to have two other options for loading the data in the future:

1. A custom external table specific to the module
2. Some flat file

Next on the roadmap is graphviz output.

Check it out!

Stikked Patch

Posted in Software on February 16th, 2010 by Jamie – Be the first to comment

We’ve been using Stikked for an internal pastebin. The current version on Google Code has a few bugs. I modified this code to fix two problems specifically:

  1. The Download Code link was not working properly
  2. The Short URL functionality was not working, as Snipr had deprecated the version of the API that the program was using

Below is a consolidated diff of the changes. You should be able to use it to apply a patch to 0.5.4 if you are having these issues.

stikked.diff

Index: trunk/system/application/models/pastes.php
===================================================================
--- trunk/system/application/models/pastes.php	(revision 1)
+++ trunk/system/application/models/pastes.php	(revision 2)
@@ -156,14 +156,55 @@
 			$data['snipurl'] = false;
 		}
 		else
-		{
-			$target = 'http://snipr.com/site/snip?r=simple&link='.site_url('view/'.$data['pid']);
+		{
+			// this next blob just copied from snipr's examples,
+			// with some modifications of course
+
+			// REQUIRED FIELDS
+			$sniplink  = site_url('view/'.$data['pid']);
+			$snipuser  = $this->config->item('snipr_user');            // YOUR USER ID REQUIRED
+			$snipapi   = $this->config->item('snipr_apikey');               // FIND IN YOUR "SETTINGS" PAGE
+
+			// OPTIONAL FIELDS
+			$snipnick   = '';            // MEANINGFUL NICKNAME FOR SNIPURL
+			$sniptitle  = $data['title'];  // TITLE IF ANY
+			$snippk     = '';                      // PRIVATE KEY IF ANY
+			$snipowner  = '';                      // IF THE SNIP OWNER IS SOMEONE ELSE
+			$snipformat = 'simple';                      // DEFAULT RESPONSE IS IN XML, SEND "simple"
+			                                       // FOR JUST THE SNIPURL
+			$snipformat_includepk = "";            // SET TO "Y" IF YOU WANT THE PRIVATE KEY
+			                                       // RETURNED IN THE SNIPURL ALONG WITH THE ALIAS
+
+			//----------------------------------
+			// NO NEED TO EDIT BEYOND THIS POINT
+			//----------------------------------
+			$URL        = 'http://snipr.com/site/getsnip';
+			$sniplink   = rawurlencode($sniplink);
+			$snipnick   = rawurlencode($snipnick);
+			$sniptitle  = rawurlencode($sniptitle);
+
+
+			$post_data =  'sniplink='  . $sniplink  . '&' .
+			              'snipnick='  . $snipnick  . '&' .
+			              'snipuser='  . $snipuser  . '&' .
+			              'snipapi='   . $snipapi   . '&' .
+			              'sniptitle=' . $sniptitle . '&' .
+			              'snipowner=' . $snipowner . '&' .
+			              'snipformat='. $snipformat. '&' .
+			              'snippk='    . $snippk
+			  ;
+
+
+			$target = $this->config->item('snipr_link');
 			$ch = curl_init();
 			curl_setopt($ch, CURLOPT_URL, $target);
+			curl_setopt($ch, CURLOPT_POST, true);
+			curl_setopt($ch, CURLOPT_HEADER, 0);
+			curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
 			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

 			$data['snipurl'] = curl_exec($ch);
-
+
 			curl_close($ch);

 			if(empty($data['snipurl']))
@@ -189,6 +230,7 @@

 	function checkPaste($seg=2)
 	{
+
 		if($this->uri->segment($seg) == "")
 		{
 			return false;
Index: trunk/system/application/config/routes.php
===================================================================
--- trunk/system/application/config/routes.php	(revision 1)
+++ trunk/system/application/config/routes.php	(revision 2)
@@ -46,6 +46,7 @@
 $route['cron/:any'] = "main/cron";

 $route['view/raw/:any'] = 'main/raw/';
+$route['view/download/:any'] = 'main/download/';
 $route['view/options'] = 'main/view_options';
 $route['view/:any'] = 'main/view';
 $route['lists'] = 'main/lists';
Index: trunk/system/application/config/config.php
===================================================================
--- trunk/system/application/config/config.php	(revision 1)
+++ trunk/system/application/config/config.php	(revision 2)
@@ -308,4 +308,16 @@
 $config['rewrite_short_tags'] = FALSE;

+/*
+|--------------------------------------------------------------------------
+| Snipr Settings - Used for short URL
+|--------------------------------------------------------------------------
+|
+| Settings for Snipr API
+|
+*/
+$config['snipr_link'] = 'http://snipurl.com/site/getsnip';
+$config['snipr_user'] = ''; // snipr user name
+$config['snipr_apikey'] = '';
+
 ?>
\ No newline at end of file
Index: trunk/system/application/views/view/download.php
===================================================================
--- trunk/system/application/views/view/download.php	(revision 1)
+++ trunk/system/application/views/view/download.php	(revision 2)
@@ -1,6 +1,6 @@
 <?php

-header('Content-disposition: attachment');
+header('Content-disposition: attachment;filename='.$title.'.'.$lang_code);
 echo html_entity_decode($raw);

 ?>
\ No newline at end of file
Index: trunk/system/libraries/URI.php
===================================================================
--- trunk/system/libraries/URI.php	(revision 1)
+++ trunk/system/libraries/URI.php	(revision 2)
@@ -186,8 +186,15 @@
 	{
 		if ($str != '' AND $this->config->item('permitted_uri_chars') != '')
 		{
-			if ( ! preg_match("|^[".preg_quote($this->config->item('permitted_uri_chars'))."]+$|i", $str))
+			$matches = array();
+			$pattern = "|^[".preg_quote($this->config->item('permitted_uri_chars'))."]+$|i";
+			if ( ! preg_match($pattern, $str, $matches))
 			{
+				echo '<pre>*'.$str.'*<br>';
+				echo 'allowed: '.$pattern.'<br>';
+				var_dump($matches);
+				var_dump(debug_backtrace());
+				echo '</pre>';
 				exit('The URI you submitted has disallowed characters.');
 			}
 		}

Tron Bot

Posted in Programming on February 12th, 2010 by Jamie – Be the first to comment

I spent a few hours cooking up an entry for this Tron Bot AI Competition. The starter packages they provided made it really easy to enter. I created an entry in python. The competition page is: http://csclub.uwaterloo.ca/contest/

The strategy for my bot:

  1. I tried to implement painter’s flood fill per Wikipedia. This worked okay and I got to around ~300.
  2. Then I implemented A*. The strategy was to get within 5 squares of the enemy, and then flood fill. My reasoning was that if I had a better fill algorithm, I would win at that point.
  3. Next, I tried to implement minimax with alpha-beta pruning. It’s not tested, but it should be fairly close. All I am missing is a utility function (well, that is probably the most impt piece!). For the utility function, I wanted to bisect the playing field by finding the perpendicular bisector between the players, then flood-filling to determine the number of blank spaces in each player’s respective region. I have the bisection algorithm done, but got bored once I started implementing the flood fill.

The project page is, it contains the source as well: http://code.google.com/p/tron-bot-waterloo/

Bot runs:

Stikker

Posted in Programming, Software on February 11th, 2010 by Jamie – Be the first to comment

Some coworkers and I have been working on Stikker, a cli interface for the Stikked FOSS php pastebin. I haven’t used it for awhile, but we recently set it up at work to facilitate code sharing. Unfortunately, it hasn’t been updated recently and there are some things which are broken which I’ll need to address. One of the great things about OSS is that fixing things yourself is possible!

CiteThis! Update 0.17

Posted in Software on February 3rd, 2010 by Jamie – Be the first to comment

I modified CiteThis! with the following features this weekend:

  • Added a citation list box, where you can queue all your citations.
  • Removed the custom citation box from the preferences pane (it was not of use anymore)
  • Fixed APA citation format to include last accessed date.
  • Added some handling of author/titles:
    • If title includes the host name of the site such as “news blah blah – CNN”, then the host name will be removed from the title.
    • If the author ends with any special characters, they will be removed
    • If author contains AP, or Associated Press, that will be stripped.
  • Author determination:
    • Added handling of some common author classes, like when an element has a class called “byline” or “author”
  • Site-specific handling
    • Added handling of some more sites: ABCNews, Fox, CNet, Yahoo News

https://addons.mozilla.org/en-US/firefox/addon/7972

SQL Pivot

Posted in Programming on January 30th, 2010 by Jamie – Be the first to comment

A co-worker asked me about transposing a question response table. I came from a SQL 2000 background, so I was excited to play with the PIVOT command which is available in SQL 2005 and 2008.  It’s a common use case to transpose row-based data into columns. Sometimes it just makes more sense to people to view data this way.

– first, let’s set up a sample table

drop table response
go
Create table response (
-- no primary key
question_fk int, -- some foreign key to another table
response_num int, -- some column to pivot on
response_text varchar(100), -- some text to show in the table
response_type char(1) -- another foreign key
)
go
insert into response values (1, 1, 'response 1.1', 'a')
insert into response values (1, 2, 'response 1.2', 'a')
insert into response values (1, 3, 'response 1.3', 'a')

insert into response values (2, 1, 'response 2.1', 'b')
insert into response values (2, 2, 'response 2.2', 'b')
insert into response values (2, 3, 'response 2.3', 'b')

-- then, we use a pivot command to transpose the table.

select

-- some columns will just be returned as is
response_type,
question_fk,
-- other columns will pivot based on values and adopt the values as
-- their column names. these columns may be aliased into more appropriate names
[1] as col1,
[2] as col2,
[3] as col3 from
( select question_fk, response_num, response_text, response_type from response ) as src
pivot (
min ( response_text ) -- we use an aggregate for the pivot
for response_num in ([1], [2], [3] )
) as piv -- the pivot table needs a name

-- try this in Query Analyzer to see the results.