ear-fung.us I’m a programmer. I’m also pro-grammar.

20Nov/090

GIT Versioning System Just Blew My Mind

git-scmTry and follow me here...

I have a source repository on a server and clone the project to my local machine to work on it. I also clone the project on that same server to a web-accessible directory so when I'm done with changes all I have to do is git pull in the web directory and it updates itself to the most recent version.

I was working on a project that needed some files and folders rearranged. It started out something like this:

/*.fla
/*.as
/www/*.php
/www/includes/config.php

I wanted to turn it into:

/*.php
/includes/config.php
/flashsource/*.fla
/flashsource/*.as

Thus, moving all the stuff from the /www/ directory to the root of the project. So I made the changes on the server in the web directory and did a commit and a push to the repository.

Whoops! I forgot that I needed to update that very same config file with some different information in order for it to work on the server (local vs. remote database authentication mumbo-jumbo). So on my local machine (which still had the old folder structure), I made the change and committed it to my local clone.

Anyone who has worked with version control systems knows what most of them (namely SVN) would do if I tried to push the changes to the server - vomit error messages all over my screen. Fingers crossed, I did a git pull to get the most recent version and then a git push to (hopefully) put the changes to the config file.

Holy crap it worked! The pull rearranged my folder structure locally, keeping the change I had previously committed to the config.php file but was smart enough to move the modified and committed config file to the new home I had given it on the server.

A git pull in the web directory to get the changes config file and we were in business.

SVN probably would have exploded in this situation.

22May/090

The Million Dollar Programming Prize

IEEE Spectrum: The Million Dollar Programming Prize

...We have just submitted our latest entry in the year-old Netflix Prize competition, which offers a grand prize of US $1 million for an algorithm that’s 10 percent more accurate than the one Netflix uses to predict customers’ movie preferences. Although we have not reached that milestone, we are hoping at least to do better than anyone else has done so far; if we can make it to 8 p.m. with the best score, we’ll win a $50 000 Progress Prize...

Read the whole article.

14Nov/082

All Sorts of UNIX Timestamp Goodness

I'm writing some tracking software and came upon the need to be able to get the two timestamps (UNIX timestamp: the number of seconds elapsed since midnight Coordinated Universal Time (UTC) of January 1, 1970, not counting leap seconds) of a given period of time. This period of time would be represented in words via a GET parameter in my application. To you, I present my switch statement to produce those two timestamps.

The hardest of all was getting "this week last year". Please note that all weeks begin on Monday.
You can check the resulting timestamps using this cool online timestamp converter.

switch($period)
{
	case "yesterday":
		$timestamp_start = mktime(0, 0, 0, date("n"), date("d")-1, date("Y"));
		$timestamp_stop = mktime(23, 59, 59, date("n"), date("d")-1, date("Y"));
		break;
	case "this_week":
		$timestamp_start = mktime(0, 0, 0, date("n"), date("j"), date("Y")) - ((date("N")-1)*3600*24);
		$timestamp_stop = time();
		break;
	case "this_month":
		$timestamp_start = mktime(0,0,0, date("n"), 1, date("Y"));
		$timestamp_stop = time();
		break;
	case "this_year":
		$timestamp_start = mktime(0,0,0, 1, 1, date("Y"));
		$timestamp_stop = time();
		break;
	case "last_week":
		$timestamp_start = mktime(0, 0, 0, date("n"), date("j")-6, date("Y")) - ((date("N"))*3600*24);
		$timestamp_stop = mktime(23, 59, 59, date("n"), date("j"), date("Y")) - ((date("N"))*3600*24);
		break;
	case "last_month":
		$timestamp_start = mktime(0,0,0,date("n")-1, 1, date("Y"));
		$timestamp_stop =  mktime(23, 59, 59, date("n"), date("d")-date("j"), date("Y"));
		break;
	case "last_year":
		$timestamp_start = mktime(0,0,0,1, 1, date("Y")-1);
		$timestamp_stop = mktime(23,59,59,12,31, date("Y")-1);
		break;
	case "last_half_hour":
		$timestamp_start = mktime(date("h"), date("i")-30, date("s"), date("n"), date("d"), date("Y"));
		$timestamp_stop = time();
		break;
	case "last_hour":
		$timestamp_start = mktime(date("h")-1, date("i"), date("s"), date("n"), date("d"), date("Y"));
		$timestamp_stop = time();
		break;
	case "last_24_hours":
		$timestamp_start = mktime(date("h"), date("i"), date("s"), date("n"), date("d")-1, date("Y"));
		$timestamp_stop = time();
		break;
	case "last_seven_days":
		$timestamp_start = mktime(date("h"), date("i"), date("s"), date("n"), date("d")-7, date("Y"));
		$timestamp_stop = time();
		break;
	case "last_thirty_days":
		$timestamp_start = mktime(date("h"), date("i"), date("s"), date("n"), date("d")-30, date("Y"));
		$timestamp_stop = time();
		break;
	case "same_day_last_week":
		$timestamp_start = mktime(0, 0, 0, date("n"), date("d")-7, date("Y"));
		$timestamp_stop = mktime(23, 59, 59, date("n"), date("d")-7, date("Y"));
		break;
	case "same_week_last_year":
		$timestamp_start = mktime(0, 0, 0, date("n"), date("j"), date("Y")-1)
		- ( (date("N", mktime(0, 0, 0, date("n"), date("j"), date("Y") - 1 ) ) - 1 ) * 86400 );
		$timestamp_stop = mktime(23, 59, 59, date("n"), date("j") + 7, date("Y")-1)
		- ( (date("N", mktime(0, 0, 0, date("n"), date("j"), date("Y") - 1 ) ) - 1 ) * 86400 );
		break;
	case "same_month_last_year":
		$timestamp_start = mktime(0,0,0, date("n"), 1, date("Y") - 1);
		$timestamp_stop = mktime(23, 59, 59, date("n"), date("t"), date("Y") - 1);
		break;
	case "today":
	default:
		$timestamp_start = mktime(0,0,0, date("n"), date("d"), date("Y"));
		$timestamp_stop = time();
		break;
}
1Oct/080

Awesomely Cool: Building an MP3-decoder

blog.bjrn.se: Let’s build an MP3-decoder!

Even though MP3 is probably the single most well known file format and codec on Earth, it’s not very well understood by most programmers – for many encoders/decoders is in the class of software “other people” write, like standard libraries or operating system kernels. This article will attempt to demystify the decoder, with short top-down primers on signal processing and information theory when necessary. Additionally, a small but not full-featured decoder will be written (in Haskell), suited to play around with.

Interesting stuff there.

15Aug/080

AIRLogger – An Adobe AIR Debugging Utility

I've been working in AIR quite a bit lately and have had a need to log certain things to be able to tell exactly what's going in in my application. I thought I'd write a logging class and share it with everyone.

AIRLogger is a quick way to create a log file for debugging an Adobe AIR AJAX application.

All you have to do is include the AIRLogger.js file in your application's window. From there you have access to log anything you want using the command:

log.write("text or variables to be logged");

If the file doesn't already exist, one will be created for you on your desktop called "application.log". Both the location and the file name can be easily changed in the js file. Possible locations could be "desktopDirectory" (default), "applicationDirectory", "applicationStorageDirectory", or a string to the path of your choice. I put it on my desktop for easy access because I'm usually just going to delete the file after I'm done looking at it anyway.

More information and download here.

24Jul/082

script.aculo.us effects in AIR

I'm starting a new Adobe AIR project and was trying to add some snazzy script.aculo.us effects to my application. It worked fine in the preview mode, but when I actually ran the application, I got a sandbox error since AIR is very restrictive on "eval()" statements.

Error: Adobe AIR runtime security violation for JavaScript code
in the application security sandbox (eval)

Turns out that others have had this problem too. script.aculo.us apparently isn't planning on releasing an AIR-compatible version, but I found this great page where a developer re-wrote the code in question.

the offending code in in effects.js at line 254:

    eval('this.render = function(pos){ '+
      'if (this.state=="idle"){this.state="running";'+
      codeForEvent(this.options,'beforeSetup')+
      (this.setup ? 'this.setup();':'')+
      codeForEvent(this.options,'afterSetup')+
      '};if (this.state=="running"){'+
      'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
      'this.position=pos;'+
      codeForEvent(this.options,'beforeUpdate')+
      (this.update ? 'this.update(pos);':'')+
      codeForEvent(this.options,'afterUpdate')+
      '}}');

In order to run this code in an AIR application, it can't be in an eval() statement.
To fix this problem, change that entire code block to:

	/*
	eval('this.render = function(pos){ '+
	'if (this.state=="idle"){this.state="running";'+
	codeForEvent(this.options,'beforeSetup')+
	(this.setup ? 'this.setup();':'')+
	codeForEvent(this.options,'afterSetup')+
	'};if (this.state=="running"){'+
	'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
	'this.position=pos;'+
	codeForEvent(this.options,'beforeUpdate')+
	(this.update ? 'this.update(pos);':'')+
	codeForEvent(this.options,'afterUpdate')+
	'}}');*/
	this.render = function(pos){

		if (this.state=="idle"){
			this.state="running";
			if(this.options["beforeSetupInternal"]) {
			this.options.beforeSetupInternal(this);
			}
			if(this.options["beforeSetup"]) {
				this.options.beforeSetup(this);
		}
		if(this.setup) {
			this.setup();
			}
		if(this.options["afterSetupInternal"]) {
			this.options.afterSetupInternal(this);
			}
		if(this.options["afterSetup"]) {
			this.options.afterSetup(this);
			}
		}
		if (this.state=="running"){
			pos=this.options.transition(pos)*this.fromToDelta+this.options.from;
			this.position=pos;
			if(this.options["beforeUpdateInternal"]) {
				this.options.beforeUpdateInternal(this);
			}
			if(this.options["beforeUpdate"]) {
				this.options.beforeUpdate(this);
			}
			if(this.update) {
				this.update(pos);
			}
			if(this.options["afterUpdateInternal"]) {
				this.options.beforeUpdateInternal(this);
			}
			if(this.options["afterUpdate"]) {
				this.options.beforeUpdate(this);
			}
		}
	}

Thanks King Maxemilian!

23Jul/082

Aptana Studio: My New IDE

I've been looking for something to replace the "kludgyness" of Dreamweaver for a while now and I've always shied away from Java applications. However, there are not a lot of great powerful development platforms for the Mac. Sure, there's Coda, and TextMate, both of which are great applications in their own right. But I wanted something more.

Here is my list of things on my wish list for a web development IDE:

  1. Seamless FTP Integration
  2. Seamless SVN Integration
  3. Project and file management
  4. Code Assist

Lo and behold, I found Aptana Studio 1.1!
Yes, it is a java application, but it's based on the Eclipse IDE which is a very full-featured and mature open source project.

The interface can be a bit intimidating at times until you learn what things are called and how to interact with the application.

Aptana Studio does everything in my list and more. One thing I really enjoy is the real time PHP debugging. You're writing some code and in a "validation" window below the text editor will tell you immediately if you have a syntax error. Brilliant!

Another nice feature is that I can browse my SVN repositories right from the main window. Right click on a directory and check it out of SVN as a new project in Aptana Studio. Aptana keeps track of your changes and marks changed files with an * and files not in the repository with a ?. It supports synchronize, commit, update, create patch, apply patch, branch/tag, merge, show history, cleanup, and most important: diff. I think it's SVN support is the Subclipse plugin for Eclipse.

I've been using this software for about 2 weeks now and It has completely replaced Dreamweaver for me. The only time I've opened Dreamweaver was to grab some FTP settings that were stored there.

One thing I've noticed with Aptana is that is doesn't play well with the Mac OS X Dock. It happily shows up there when launched, but when you try to retain its icon in the dock after closing, the icon turns into a unix executable icon and is linked to "/System/Library/Frameworks/JavaVM.framework/Versions/A/Commands/java". That is very strange behavior. There's even a bunch of open bug reports about this problem specifically.

One way around this, annoying as it may be, was to create an alias of the launching application and put the alias in the dock. Only problem with that is when Aptana Studio is launched there are two icons in the dock. Not a big deal to me till the bug gets fixed.

Overall I'm really enjoying my new development IDE. It launches fast on my Macbook Pro Core 2 Duo and has a snappy interface. I just wish there was an option to "automatically upload on save" like Dreamweaver had. I'm willing to overlook that one shortcoming and work happily in Aptana, but I have a big sign above my monitor that says,

"Upload the file! CMD+SHIFT+U"

If you're tired of Dreamweaver, give Aptana Studio a try.

3Jul/087

My First Objective-C Cocoa Code – “String Between”

I needed a string searching method in Objective-C for a little app I'm writing that searched a string and found substrings in-between two other strings... sort of a poor man's regex. It extends the NSString object so once you've imported it in your main header, you can call the method on an NSString object. I couldn't find anything in the Cocoa API that did what I was looking for so I did it myself.

Here's what I came up with... I present to you: "StringBetween"

StringBetween.h

@interface NSString (StringBetween)

-(NSString *)stringBetween:(NSString*)aString and:(NSString *)bString;

@end

StringBetween.m

#import "StringBetween.h"
@implementation NSString (StringBetween)

-(NSString *)stringBetween:(NSString *)aString and:(NSString *)bString
{
    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];

    //Find the range of the first string
    NSRange aRange = [self rangeOfString:aString options:(NSCaseInsensitiveSearch)];

    if(aRange.length > 0){
        //Make a new range to search for the next string
        NSRange searchRange;
        searchRange.location = aRange.location;
        searchRange.length = [self length] - aRange.location;

        //Find the next string
        NSRange bRange = [self rangeOfString:bString options:(NSCaseInsensitiveSearch) range:searchRange];

        //NSLog(@"%d, %d", aRange.location, aRange.length);
        //NSLog(@"%d, %d", bRange.location, bRange.length);

        if(bRange.length > 0)
        {
            searchRange.location = aRange.location + aRange.length;
            searchRange.length = bRange.location - searchRange.location;

           return [self substringWithRange:searchRange];
        }
    }
    return @"";
    [autoreleasepool release];
}
@end

Here is an actual implementation example:

main.m

#import <cocoa/Cocoa.h>
#import "StringBetween.h"

int main (int argc, const char * argv[]) {

    NSString *thisString = @"The quick brown fox jumped over the lazy dog.";

    NSLog([thisString stringBetween:@"qui" and:@"the"]);
    //Returns @"ck brown fox jumped over "

    NSLog([thisString stringBetween:@"garbage" and:@"more garbage"]);
    //Returns @""

    return 0;
}

I hope I didn't muck up that code too bad. I'm still learning Objective-C.

Here's an X-Code project download if you want to see it in action.
Download this xcode project