Thursday, December 17, 2009

What will happen in 2110?

Here is a very interesting article posting predictions for year 2000 made in 1900. Many predictions were quite good!

http://bunchofnerds.com/2008/10/retro/predictions-for-the-year-2000-from-the-year-1900/

So lets start a new prediction thread. What do YOU think the world will consist of in 2110? Comments will be open until the end of 2010.

Thursday, November 12, 2009

AJAX and PHP sessions

One thing that trips up AJAX development is how to persist your PHP session through your AJAX calls. In a browser, the session persists through a cookie that passes the session id upon each request. However with an AJAX call, the browser cookies are not passed and the session is lost.

There are a couple of easy ways around this. First, if your AJAX library supports cookies, you can just set the PHP session id cookie before the call. If you don't have cookie support, then the following "manual" method works quite well.

What you will want to do is pass the session id as a POST or GET variable in your AJAX request. We'll call our variable name "sid".

Here is a jQuery example for passing the sid through as a POST value (in a PHP script):

$.post("test.php", { sid: "<?php echo session_id(); ?>" } );

This will POST the current session id through the form. Next on the PHP side, you must set the session id with this posted value:


<?php
// set session to value from ajax post
session_id($_POST['sid']);
// we now have $_SESSION data!
?>

As for security, be aware that you don't have the same restrictions that come with cookies (domain, date, etc.) so once you pass the session id to javascript, be careful what can be manipulated through javascript code. It's pretty much the same as being aware of javascript getting/setting cookie values themselves.

Hope that helps!

Saturday, October 24, 2009

Being a winning online poker player

You know you are capable of playing great poker, but you continuously lose your bankroll playing online poker. How do you get over this hurdle? What is the secret? There are two important factors.

Factor 1: Don't play on tilt

Winning poker is not about focusing on how much you've won or lost. It's how you handle losing. How often do you get bad beat, then jump right back in and lose more and more? How often do you make a big win, only to lose it all over the course of days or weeks?

So to overcome factor 1: If you get a bad beat or get on a losing streak, force yourself to take a break before playing again. How long or what this is depends on what it takes to get your mind free of the past. Maybe it's a nap. Maybe it's a walk around the house. Maybe it's a jog around the block. The important element is that you are not playing the next game with the predisposition of steaming. Get over it first, then continue playing.

Factor 2: Bankroll management

Losing is a fact of the game, it will happen. To stay alive, you must manage your bankroll. This sounds easy, but it can take a considerable amount of discipline. If you don't want to buy in again, you *must* manage your bankroll, no matter how good you are. A rule of thumb for sit-and-goes and MTTs: Take the buy-in multiplied by # of players. If that amount is greater than your bankroll, move down.

If you get on a losing streak, just stick to the plan. Take a break, and move down in stakes until you can recover.


Follow these rules, and the only way you can lose is by playing bad poker. Hopefully you've gotten past that part :) Good Luck!

Sunday, August 9, 2009

Basecamp PHP API

I needed a complete PHP class for the Basecamp API with a project I'm working on at REBEL. Finding nothing that would fit the bill, I wrote one.

http://code.google.com/p/basecamp-php-api/

Sunday, July 26, 2009

A rant on PHP, quotes and variables

Here are 3 ways to display some text with some PHP variables:

single quotes interspersed with vars:

echo 'My name is ' . $user
. ' and I eat ' . $food['favorite'] . '.';


double quotes interspersed with vars:

echo "My name is " . $user
. " and I eat " . $food['favorite'] . ".";


double quotes with embedded vars:

echo "My name is {$user} and I eat {$food['favorite']}.";

The vast majority of PHP code I come across uses the first two methods, breaking in and out of quotes for each variable. IMHO the third way much easier to read and maintain. Granted there are slight performance differences between them, but not enough to be concerned about. I think the reason that version 3 isn't so popular is because most PHP developers don't learn this type of curly-brace syntax (enabling you to embed complex variables into quoted strings) right away, and therefore rarely think to use it.

Of course you can take things a step further with sprintf and really keep things tidy. Let's take a SQL query for a common example.

Here is the "messy" way:

$sql = "select * from MYTABLE where id=" . (int)$info['id'] . " and firstname = '" . mysql_real_escape_string($info['firstname']) . "' limit " . (int)$limit;

And the much cleaner way:

$sql = sprintf("select *
from MYTABLE
where id=%d
and firstname = '%s'
limit %d",
(int)$info['id'],
mysql_real_escape_string($info['firstname']),
(int)$limit
);


I hope I brought some ideas to light, happy coding.

Thursday, May 14, 2009

Camera image orientation

I was having a confusing problem where images taken from the iPhone camera were being displayed in the wrong orientation. I would take a photo in portrait and save the data to disk. Later when I retrieved the photo it would show up rotated 90 degrees.

The iPhone knows what orientation a photo is taken, and this orientation depends on how the camera is being held when you snap the photo. You can get the orientation value on a UIImage from the property imageOrientation.

When you save the photo, it is possible that this information could get lost, depending on the way you save it. If it does get lost, the UIImageView will assume the photo was taken as a left-side landscape photo, and display it with that orientation.

I ran into a problem when trying to save the camera image with UIImagePNGRepresentation(). For some reason this loses the orientation info. I switched to UIImageJPEGRepresentation() and all is well now.

So basically if you run into the problem, you have 2 choices: Be sure you use a format that preserves orientation data, or rotate the UIImage data directly before saving it to a file.

Wednesday, May 13, 2009

Rotating view around arbitrary point the easy way

I have a UIImageView that I want to rotate around a given point. By default, the layer will rotate around the center of the UIImageView. Trying to change this anchor point involves a bit of work, either move at the beginning and reposition all the view elements, or translating the view, rotating, and translating back. The last option works fine, unless you are trying to use core animation to smoothly rotate the view.

I found out a much easier solution to the whole problem. You could call it a workaround, but it works well without disturbing the view you want rotated.

Basically, you create a new UIView. Place the center point where you want the rotation to occur. Change the size of the view so that the view you want rotated will fit inside. Make your view (you want rotated) a subview of the new view. Now, just rotate the new view, and your subview will be rotated correctly.

Example: lets say we have a UIImageView that is 320x480 (the size of the whole iPhone screen). We want it to rotate from the bottom center instead of its middle. Create a new UIView that is 0,0,320,960. This is basically double the height of the screen, positioned so the bottom half is off the screen, which places the center point right where we want it. Now place your UIImageView inside the new UIView in the top half (visible on the screen.) Now when you rotate the UIView, it will pivot on the bottom center of the screen, and your UIImageView will rotate along with it, as expected.

Friday, May 1, 2009

OS X "burning" image to USB flash drive

I recently downloaded an Ubuntu image for netbooks, and I needed to install this onto a USB flash drive so I could boot it. This is pretty simple with OS X and Disk Utility and dd from the command line. Be sure your flash drive is large enough to hold the disk image.

* Plug the flash drive into a USB port and launch Disk Utility.
* Select the flash drive and press apple+i to bring up the info
* remember the device id, it will be diskN where N is a number, such as disk4
* select the volume (not the device) and click unmount.
* open a terminal window, and type:


sudo dd if=/path/to/file.img of=/dev/disk4 bs=1024


Be sure to use your path to the image file, and the device id you got from disk utility in place of "disk4". You can drag the .img file into the terminal window if you don't want to type the full path to it.

Now wait a bit for the image to be written. When its done you will get something similar to this:


969568+0 records in
969568+0 records out
992837632 bytes transferred in 521.666371 secs (1903204 bytes/sec)

Wednesday, April 1, 2009

Prediction: First Consumer Petabyte Hard Drive?

The first hard drive I owned came with my Amiga 1200, circa 1990. It held 40 megabytes of data, and I believe it was a $500 option. Yes, I said option. The computer happily ran on floppy disks alone, if you so desired. You had to load the OS off of floppy first, then load your programs from other disks. The A1200 came with 2MB of ram, but I loaded it up with an additional 16MB of RAM, costing a healthy $800. That is just sick.

Back to the subject of hard drives. Here is a rough time line for the consumer hard drive. By "consumer", I mean something that fits in a desktop PC form factor that is in the price range for an average consumer.

1980 5MB ~$1,000.00
1992 1GB ~$1,000.00 (1 gigabyte ~ 1000 megabyte)
2007 1TB ~$300.00 (1 terabyte ~ 1000 gigabyte, or 1 million megabyte)
???? 1PB ???? (1 petabyte ~ 1000 terabyte, or 1 million gigabyte)
???? 1EB ???? (1 exabyte ~ 1000 petabyte, or 1 million terabyte)
???? 1ZB ???? (1 zetabyte ~ 1000 exabyte, or 1 million petabyte)
???? 1YB ???? (1 yottabyte ~ 1000 zetabyte, or 1 million exabyte)


The timeline between 5MB and 1GB drives was 12 years.
The timeline between 1GB and 1TB drives was 15 years.
Notice the price drop!

So let's hear the predictions. When will the first consumer-ready petabyte drive be available, and what will the average cost be? How aboute exabyte? Zetabyte? Yottabyte?

A Yottabyte is a tough one to grasp. That is ONE TRILLION terabytes. Do you think storage space, or personal computing as we know it, will end at some point, long before these outrageous sizes are a reality?

If history is any indication, the petabyte drive should arrive in 12-15 years, and average $300 or less. I think it will much sooner, cut that time down to about 8 years. The $300 price is probably close.

I also think solid-state disk storage will become the norm, seeing hard drive platters die like the video tape did.

Sunday, March 29, 2009

iPhone 2.2.1 available fonts

Here is a list of the fonts available to the iPhone as of SDK 2.2.1:


Family: Courier
Font: Courier
Font: Courier-BoldOblique
Font: Courier-Oblique
Font: Courier-Bold
Family: AppleGothic
Font: AppleGothic
Family: Arial
Font: ArialMT
Font: Arial-BoldMT
Font: Arial-BoldItalicMT
Font: Arial-ItalicMT
Family: STHeiti TC
Font: STHeitiTC-Light
Font: STHeitiTC-Medium
Family: Hiragino Kaku Gothic ProN
Font: HiraKakuProN-W6
Font: HiraKakuProN-W3
Family: Courier New
Font: CourierNewPS-BoldMT
Font: CourierNewPS-ItalicMT
Font: CourierNewPS-BoldItalicMT
Font: CourierNewPSMT
Family: Zapfino
Font: Zapfino
Family: Arial Unicode MS
Font: ArialUnicodeMS
Family: STHeiti SC
Font: STHeitiSC-Medium
Font: STHeitiSC-Light
Family: American Typewriter
Font: AmericanTypewriter
Font: AmericanTypewriter-Bold
Family: Helvetica
Font: Helvetica-Oblique
Font: Helvetica-BoldOblique
Font: Helvetica
Font: Helvetica-Bold
Family: Marker Felt
Font: MarkerFelt-Thin
Family: Helvetica Neue
Font: HelveticaNeue
Font: HelveticaNeue-Bold
Family: DB LCD Temp
Font: DBLCDTempBlack
Family: Verdana
Font: Verdana-Bold
Font: Verdana-BoldItalic
Font: Verdana
Font: Verdana-Italic
Family: Times New Roman
Font: TimesNewRomanPSMT
Font: TimesNewRomanPS-BoldMT
Font: TimesNewRomanPS-BoldItalicMT
Font: TimesNewRomanPS-ItalicMT
Family: Georgia
Font: Georgia-Bold
Font: Georgia
Font: Georgia-BoldItalic
Font: Georgia-Italic
Family: STHeiti J
Font: STHeitiJ-Medium
Font: STHeitiJ-Light
Family: Arial Rounded MT Bold
Font: ArialRoundedMTBold
Family: Trebuchet MS
Font: TrebuchetMS-Italic
Font: TrebuchetMS
Font: Trebuchet-BoldItalic
Font: TrebuchetMS-Bold
Family: STHeiti K
Font: STHeitiK-Medium
Font: STHeitiK-Light

Wednesday, March 25, 2009

Perl Compatible Regular Expressions with Cocoa

If you want Perl Compatible Regular Expressions with Cocoa, Christopher Bess has created ObjPCRE, a library that makes PCRE easy in Cocoa.

However, there isn't much for documentation, so I thought I'd at least show how to get started. Implementation is pretty straight forward. First, you need to add the following files to your XCode project:

libpcre.a
pcre.h
objpcre.h
objpcre.m

You can find the libpcre.a file in the pcre static lib download, and the other three files are in the source file download. I created a new "PCRE" group folder in my XCode project and dropped them all in there.

Now, its just a matter of using it. So first, lets create a one-liner that search/replaces text in a string. We'll search for "string" and replace it with "foobar".

#import "objpcre.h"

NSString *myText = @"This is my string of text.";
NSLog(@"text before: %@", myText);
[[ObjPCRE regexWithPattern:@"string"] replaceAll:&myText replacement:@"foobar"];
NSLog(@"text after: %@", myText);


There you go, your first one-line to search/replace a string of text inline with perl regular expressions. Now this isn't very interesting, as no regular expressions were used. So now, let's try something useful. How about a regular expression that removes all HTML tags from the string. Lets try to think of a regex that will match every HTML tag:

<.*>

Ok that one is pretty basic. It says match <, followed by zero or more of ANY character, followed by >. This could cause a problem because it can match too much, such as multiple html tags along with any text between them. So we'll go with something a bit more restrictive:

<\w+[^>]*>

Now we will only match <, followed by one or more word characters (letter, number, underscore), followed by zero or more characters that are NOT >, followed by >.


We still have a problem though, this will not match closing HTML tags.

</?\w+[^>]*>

There, now we match tags with 0 or 1 "/" after the opening tag.

Notice that backslashes must be escaped inside @"double quotes", so we use two of them in the string.

#import "objpcre.h"

NSString *myText = @"<title>This is my <b>string</b> of <class name="foo">text</class>.</title>";
NSLog(@"text before: %@", myText);
[[ObjPCRE regexWithPattern:@"</?\\w+[^>]*>"] replaceAll:&myText replacement:@""];
NSLog(@"text after: %@", myText);


And now for something a bit trickier. Let's try extracting all words within [brackets] in the text. This is where ObjPCRE could use some more features! But for now, here is how we accomplish this task. First the regular expression that matches the tags:

\[\w+\]

The brackets have special meaning to PCRE, so we have to escape them. This matches [, followed by one or more word characters, followed by ]. But, lets say we want to capture just the text, without the brackets. We put parenthesis around each subpattern we want to capture. These will have no affect on the regex.

\[(\w+)\]

And now we put this into code. Remember to escape backslashes.

NSString *myText = @"This is [some] more [text] to parse.";

ObjPCRE *pcre = [ObjPCRE regexWithPattern:@"\\[(\\w+)\\]"];

int start = 0;
int len = 0;
int offset = 0;
int i = 0;
while([pcre regexMatches:myText options:0 startOffset:offset]) {
for(i=0; i<[pcre matchCount]; i++) {
NSLog(@"match %d: %@",i,[pcre match:myText atMatchIndex:i]);
}
[pcre match:&start length:&len atMatchIndex:0];
offset = start + len;
}


We call regexMatches for each [bracket] pattern it finds. For each of those we loop over the subpatterns and echo them. The first subpattern is the entire match, followed by each parenthesized subpattern (which we have only one.)

Alright, so that's a start! To continue, check all the functions available in objpcre.h, and also see the documentation on PCRE for all the good regex stuff.

Tuesday, March 24, 2009

Reset a UIScrollView

This has to be the most puzzling thing I've come across in iphone app building thus far. I wanted to "reset" a UIScrollView after pinch zooming and scrolling. It turns out, there is no way to reset the zoom factor on the contentView in a UIScrollView. At least not in the current SDK. You must completely replace the subview of the scroll view to work around it.

I wanted this transition to happen smoothly, so I used some core animation. Here is some working code to get the scroll view to "reset". In my app, I implemented this after a double tap, and after an orientation change.

self.scrollView is the UIScrollView, and self.imageView is the UIImageView subview.


- (void) resetImageZoom {

// animate the transition
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(resetAnimFinish:finished:context:)];
[UIView setAnimationDuration:0.4];

// reset the scrollview and the current image view
self.scrollView.transform = CGAffineTransformIdentity;
self.scrollView.contentOffset = CGPointZero;
self.imageView.frame = self.scrollView.frame;
self.imageView.center = self.scrollView.center;
self.scrollView.contentSize = self.imageView.frame.size;

[UIView commitAnimations];

}

-(void)resetAnimFinish:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {

// make a copy of the image view
UIImageView *copy = [[UIImageView alloc] initWithImage:self.imageView.image];
copy.autoresizingMask = self.imageView.autoresizingMask;
copy.contentMode = self.imageView.contentMode;
copy.frame = self.imageView.frame;
copy.center = self.imageView.center;

// replace the current image view with our copy
[self.imageView removeFromSuperview];
self.imageView = copy;
[self.scrollView addSubview:copy];
[copy release];
}

If you wanted, you could extend UIImageView an implement the NSCopying protocol, then just use the copy convenience method. I chose to copy the object a bit more manually here.

Sunday, March 22, 2009

stripping HTML with objective-c/cocoa

I was looking for a simple way to strip HTML from an NSString. Since NSString has no native regular expression support, I had to resort to other means. I found many posts requiring regex support libs and/or libxml2 support. Bleh. Then I found this simple solution using NSScanner. It worked well for me.

It's not super smart though. I'm guessing it will bork on any stray < or > tags in the text that are not part of HTML markup. Make sure they are escaped.

http://www.rudis.net/content/2009/01/21/flatten-html-content-ie-strip-tags-cocoaobjective-c

I made my own small addition, optionally trimming whitespace too.


- (NSString *)flattenHTML:(NSString *)html trimWhiteSpace:(BOOL)trim {

NSScanner *theScanner;
NSString *text = nil;

theScanner = [NSScanner scannerWithString:html];

while ([theScanner isAtEnd] == NO) {

// find start of tag
[theScanner scanUpToString:@"<" intoString:NULL] ;
// find end of tag
[theScanner scanUpToString:@">" intoString:&text] ;

// replace the found tag with a space
//(you can filter multi-spaces out later if you wish)
html = [html stringByReplacingOccurrencesOfString:
[ NSString stringWithFormat:@"%@>", text]
withString:@" "];

} // while //

// trim off whitespace
return trim ? [html stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] : html;

}

Tuesday, February 17, 2009

The World's Hardest iPhone Game


If you've ever played NIM, you know what I'm talking about. It's a game that has been played for centuries with a mathematical strategy to winning. This version places you on a space ship with an on-board computer that loves to insult. Good luck beating him, you'll spend hours trying :)

Mind Nimmer, $0.99 on the iTunes store.

Wednesday, January 28, 2009

1TB mirrored NAS for $377

I wanted to see how cheaply I could build a mirrored Network Attached Storage (NAS) server, yet keep a balance of quality with the build price. Using all Newegg components, I came up with this list:

Wish List


This gets you a decent looking, quiet system with mirrored storage. After formatting, usable space should come in a little under 1TB, as you would expect with 1TB drives. As for OS, I would recommend Solaris 10 and ZFS. All free and very easy to setup a pool of disks with no hardware RAID required (JBOD). Since there are only two drives in this configuration, I'd opt for mirroring. If you add 3 or more drives, then RAIDZ1 would be the better choice (similar to RAID5, 1 drive for parity.)

My basic specs are:

* 4GB RAM (ZFS likes lots of RAM for optimal speed)
* SATA 3.0Gb/s
* GB ethernet
* Firewire

The power supply I chose has 2x12v rails for plenty of power to the hardware. The AMD X2 CPU is very inexpensive, and more than adequate for a file server. Everything in this package has decent prices and overall good reviews from newegg customers.

The system is easily expandable, and it is trivial to setup Samba for network sharing, or NFS, or even plug in Firewire for direct data access. See here for a detailed walk through of the process.

Tuesday, January 27, 2009

Renaming an XCode Project from Command Line

UPDATE: As of Xcode 3.2 you can rename projects from the Projects->Rename dropdown.

Earlier I had posted how to manually rename an XCode project. I have now written a BASH shell script to handle everything automatically. You can find it here.

Thursday, January 22, 2009

Winning A Pinewood Derby Race

A post about this came across Facebook that made me recall my Pinewood Derby experience, so I thought I'd share it. When I was a young cub scout I participated in one Pinewood Derby race and I won first place. Not by a nose, but by over a car length. Here was my strategy (thanks dad.)

First and foremost is weight placement. You want to put as much weight as you possibly can on TOP and CENTER of the car (between the wheels.) That means, do NOT add fancy fenders and whatnot. Only carve away from the block of wood, do not add to it! Doing this, you can keep any and all extra weight directly on top center. I used a simple round fishing weight, drilled a hole through it and screwed it on. I didn't bury it in the body of the car, it sat perched right on top. It didn't look super pretty, but it worked. Keep that weight on top. It's even better to put too much weight on top, and remove wood from the bottom center to correct it! Don't add screws or any weight to the bottom! Of course, make sure your car is exactly the weight maximum, usually 5oz. Add this weight once you get your car all carved up and sanded and looking how you want.

Second tip, make sure the axles are straight, and use graphite if allowed. Make sure there are no burrs or spots on your axle that may slow you down. Some people like to sand and polish the axles. It will probably help, although I didn't do it for my car. (Put the axle in a drill and let it spin as you hold sand paper on it. Go finer and finer, then go to steel wool to polish it.) Most important, make sure they are straight and clean. Give them a spin holding the wheel and axle nailhead-side down, see if it spins freely (30+ secs) and doesn't wobble as it slows up. (A young cub scout had dropped my car before the race, and one of my wheels broke half of the plastic away right on the axle and it wobbled as it slowed up. But my car STILL won by a landslide with this broken wheel!)

Those are the two most critical tips. As for the shape of the car, mine was a pretty simple wedge shape. People talk about aerodynamics, but really these cars aren't moving fast enough to figure in downforce and other crazy engineer talk. You certainly don't want to add anything that will cause an air pocket, so just make sure the car slopes front to back.

Next, clear a spot in your trophy case. Have fun :)