Yet another site to maintain!

ProgrammingCategory Archives

The REAL difference between Android and iOS

Proponents for both sides fit into one of two main categories, the intelligent, savvy users and the fanbois (intentional misspelling). The former are users who understand their specific needs and have chosen a platform that suits both their specific style and taste whilst providing a fantastic experience. The latter are the idiots who, like religious extremists, are unable to find a common ground or are even able to constructively understand why they are in their respective camps.

The real differences

When you break it down it really comes back to the following two differences:

  • Hardware specifications
  • Personalisation

All other features such as productivity, SMS, MMS, Social Networking, etc. are available on basically EVERY phone thus are moot from here on in.

Hardware specifications

Most general users of a device really have NO clue as to what is under the hood on their device, and most rightly don’t really care one way or the other, as long as it does what they want and does it quickly. Power users are really the only ones who want to know what’s available. So for the purposes of this discussion, general users are excluded from this particular subject.

Hardware consistency in the iPhone/iPad department has always made developing for iOS a breeze. It really does emulate the philosophy of Java’s “write once, run anywhere” slogan. Android usually get’s the standard fragmentation spiel right about now, and rightly so in that Android doesn’t provide a consistent deployment platform and has to rely upon API’s to handle older hardware (eg. the ActionBar legacy API’s, etc.)

So what you get in one area you lose out in the other. iPhone/iPad hardware has no variation so if you want certain performance in one area then you’re unable to find a device to suit your needs. Gaming for instance is something that requires rather beefy hardware and that’s what you’d expect to get when buying a Galaxy S4. The good old HTC Desire HD would still probably keep you entertained though it has it’s limitations. Whereas from a developers perspective, if you were trying to do something on a mobile platform that was well and truly beyond the available hardware, then you’re either going to have to restrict your target audience or downgrade your app/game to accommodate the lower hardware spec, much like the way web developers have to downgrade their CSS to deal with old browsers.

In the end, hardware CHOICE is what matters most and in the iPhone/iPad side of the fence there really is only the one brand to choose from. So fragmentation == choice, therefore Android would have to win this round.

Personalisation

Android is renown for its plethora of settings and configuration items as well as its ability to use widgets, change home screen layouts and so on. iOS has sorely missed its opportunity to impress users with these features and has taken a whopping 7 versions of iOS to really get behind this idea. Sure, iOS 6 has widgets and notification updates but lets be honest, iOS 7 has truly embraced this concept and has implemented it rather well.

Though personalisation goes beyond widgets, its the ability to have things exactly how you want them. iOS 7 has made headway in this area though still stifles the user by not going that extra mile to make iOS as configurable as Android. Right from the beginning, Android strived to give the user choice and has done so in ever increasing amounts through time.

On the flip side of this is a very simple fact, something that Apple have known about for a long time. Too many options == decision paralysis. By presenting too many options to the user you either scare the user off completely or confuse the user to no end, and ultimately this reduces the users experience with the device. Droves of Android users fled to the iPhone in the early days simply because it didn’t “just work” how the users wanted it to. By the severe restrictions that iOS imposed upon its users, it relieved the users decision paralysis and made the experience a whole lot better.

That said, the real answer to this problem is that options == freedom. Just because you don’t understand what those options do or don’t really care what those options do is irrelevant. NOT being able to change those options on the other hand == imposition and restriction, the opposite of what we want from our devices and thus, Android would also have to win this round.

Conclusion

Ultimately it comes down to user experience over freedom to use the device in the manner in which you want to, so the biggest difference between the two (major) OS’es is that Android gives the user the CHANCE to be free whereas iOS doesn’t. If you feel that you are happy to live in a closed eco-system controlled by a tyrannical company who does nothing but sue anyone who looks at it wrong then Apple is the best choice for you.

Otherwise, sure, it might take you a bit to get up to speed, but just like the slaves in Spartacus, wanting freedom and HAVING freedom are two different things.

Swift Mailer mail attachment example

After a quick google, all the email attachment examples were crap, using antiquated versions of the library and even PHP v4 code!

Here’s my working example for taking a registration form with a file upload INPUT element that get’s directly attached to an email and sent.

	require_once('swift/lib/swift_required.php');
	$transport = Swift_SendmailTransport::newInstance('/usr/sbin/sendmail -n -t');
	$mailer = Swift_Mailer::newInstance($transport);

	$message = Swift_Message::newInstance('EMAIL SUBJECT')->setFrom('FROM EMAIL ADDRESS')->setTo('TO EMAIL ADDRESS');

	$body = "*** REGISTRATION FORM ***\n\n";
	$body .= 'First Name: ' . \WIC\Core::c()->qs('fname') . "\n";
	$body .= 'Last Name: ' . \WIC\Core::c()->qs('lname') . "\n";
	$body .= 'Address: ' . \WIC\Core::c()->qs('address') . "\n";
	$body .= 'Suburb: ' . \WIC\Core::c()->qs('suburb') . "\n";
	$body .= 'Postcode: ' . \WIC\Core::c()->qs('postcode') . "\n";
	$body .= 'Mobile: ' . \WIC\Core::c()->qs('mobile') . "\n";
	$body .= 'Home: ' . \WIC\Core::c()->qs('home') . "\n";
	$body .= 'Email: ' . \WIC\Core::c()->qs('email') . "\n";
	$body .= 'Keyboard Data Entry Operator: ' . \WIC\Core::c()->qs('data') . "\n";
	$body .= 'Clerical/Administrative: ' . \WIC\Core::c()->qs('administrative') . "\n";
	$body .= 'Additional Skills: ' . \WIC\Core::c()->qs('additional') . "\n";

	if (file_exists('/tmp/' . $_FILES['resume']['name'])) {
		unlink('/tmp/' . $_FILES['resume']['name']);
	}

	move_uploaded_file($_FILES['resume']['tmp_name'], '/tmp/' . $_FILES['resume']['name']);

	$message->setBody($body)->attach(Swift_Attachment::fromPath('/tmp/' . $_FILES['resume']['name']));
	$mailer->send($message);

This simply takes the form fields and dumps them to an email (not pretty I know), but then takes the uploaded file from /tmp/ and then attaches the file contents directly to the email and sends it :)

How to use a SqlDataReader within another SqlDataReader

MSSQL has a restriction on by default which prevents using another SqlDataReader within a SqlDataReader without modification of the Connection String.

For example, say you want to get Table A, then for each record in Table A you want all records linked to Table A in Table B, a pretty normal request, one would typically get each record from SqlDataReader 1, then make a request to another SqlDataReader 2 and grab the child data there.

Doing this off the bat will fail unless you add the following parameter to your Connection String:

SqlConnection con = new SqlConnection("Data Source=[server];Initial Catalog=[dbName];User Id=[user];Password=[pass];MultipleActiveResultSets=true;");

Notice the MultipleActiveResultSets=true; value at the end? Enable this and you’ll be able to create secondary SqlDataReaders within a parent :)

How to remove .svn folders in one hit

I frequently have junior staff members who give me “clean” copies of new projects and upon the initial commit to SVN we find that the commit dies horribly for one reason or another.

Typically the new project will need to be scoured, folder by folder, to rid us of .svn folders from other repo’s which usually is a massive pain in the ass.

So here’s a command (to be used sparingly) “for NEW projects only“, that will wipe your entire project folder clean of all .svn (well, you can change the .svn to anything else such as “_notes”, etc.) in one fell swoop.

find . -name '.svn' | xargs rm -fr

Like I said, this is for new projects only as existing projects with VALID .svn folders will also be destroyed (FUBAR) by it.

SVN and svn:ignore

Just recently we had a dev in my team restore a customers’ site from our backup repo which had images that our customer had since modified and so, our restore process overwrote those images the customer modified. Not a very happy customer ;)

In order to avoid this we simply needed to ignore the folder where our system uploads customer images to, since this folder truly is of no concern to our source management and typically binaries shouldn’t be committed unless they are to be versioned!

Enter SVN:IGNORE

I instructed the dev to add the svn:ignore property to the upload directory but the files still continued to be added to the repo.

svn propset svn:ignore uploads .

Explanation of this command

In order to understand WHAT the dev executed I had to explain what this command was doing. First, svn propset asks SVN to set a property for a working copy.

Second, the property being set is svn:ignore. The value of WHAT is being ignored is “uploads” (ie. we want to ignore the uploads directory).

Lastly, “where” does this directory exist? Well that’s what the period (.) at the end says (ie. it’s the uploads directory in the CURRENT path).

SVN ADD still adds the ignored directory

The dev then issues a standard add command and presto, the uploads directory is added, regardless of the svn:ignore. WTF?!

It turns out that the command being used to add included an asterisk (*) which, on the command line, expands all the entities within the directory, including the uploads directory which we wanted ignored.

Invalid SVN ADD command

svn add --force *

Correct SVN ADD command

svn add --force .

After executing the correct svn add command ALL the folders (and other entities) that need to ignored are correctly ignored :)

Quick MySQL Executor

For a while now I’ve been wanting to access MySQL quickly through a web ui when I haven’t had direct access to the CLI/Workbench/phpMyAdmin and so I finally wrote something that my fellow coders have found useful and have decided to share it with the world.

Please note: This is a TOOL that you should use then remove from the site. This script CAN be used to compromise your MySQL/Web server if found by hackers. Remove this (or secure it properly) after you’ve finished with it (just like a normal tool, put it away in your toolbox when you’re finished with it!)

Download the script here. (WP won’t allow ZIP uploads so download the “PNG” and rename it to “ZIP”).

Please comment on the script/suggest improvements as you see fit and we will built an awesome version for everyone to share!

OMFG! Safari doesn’t recognise YYYY-MM-DD as a valid date format!

Try the following code in safari and see the glorious “Invalid Date” appear:

var myDate = new Date('2012-03-15');

The only solution that I can see is:

var sqlDate = '2012-03-15';
var dateBitz = sqlDate.split('-');
var myDate = new Date(parseInt(dateBitz[0], 10), parseInt(dateBitz[1], 10), parseInt(dateBitz[2], 10));

WTF man!?

Oh I just had to do it q:)

Ok, get your flames ready. Here is a study of App Crashes between Andriod and iOS and you guessed it, my personal favourite comes out on top once again q;)

Android vs iOS

Android vs iOS

Full article goes into more detail and can be found here.

Showing our age

Wow… 30 years ago I received probably the single best present my folks could ever have bought me (yeah yeah, I’ve had better pressies but from a “help shape my future” perspective there was none better).

The Commodore 64 turns 30

After checking out the PC Tech article I started feeling my age a bit :P

Happy Birthday to the computer that introduced me to the world of spaghetti code and computer hardware. I can honestly say that I still have a few 5.25″ disks in my draw at home. Scary!

Flexigrid – Getting the selected row index

Let’s assume that you’re using an INTEGER ID (for the most part this is true), here’s how you would find the row’s ID value that you’ve specified, not the value that Flexigrid will use internally.

Setting up the Table

Let’s create a simple table.

<table class="table1" style="display: none;">
	<tbody>
		<tr>
			<td>
				1
			</td>
			<td>
				Cell 1
			</td>
			<td>
				Cell 2
			</td>
		</tr>
		<tr>
			<td>
				2
			</td>
			<td>
				Cell 3
			</td>
			<td>
				Cell 4
			</td>
		</tr>
	</tbody>
</table>

Setting up the jQuery

Let’s set up the Flexigrid jQuery.


$('.table1').flexigrid({
	colModel: [
		{display: 'ID', name : 'id', width: 0, sortable: false, align: 'left', hide: true},
		{display: 'Column 1', name: 'col1', width: 180, sortable: true, align: 'left'},
		{display: 'Column 2', name: 'col2', width: 180, sortable: true, align: 'left'}
	],
	sortname: "col1",
	sortorder: "asc",
	height: 200,
	singleSelect: true,
	buttons: [
		{name: 'Test', onpress: test}
	]
});

On line 3 we’ve stated that the ID column should be hidden and on line 12 we’ve created a dummy button that will fire a javascript function called test().

Explaining the constraints

At the moment we have a few constraints with this solution:

  1. The ID column can only be an INTEGER (not usually a problem)
  2. The ID column must be the FIRST column (explained below)

If you can get past these constraints then the test function below will retrieve YOUR selected ID.

Defining the Test function

function test(com, grid) {
	$('.trSelected td:first', grid).each(function() {
		alert(parseInt($(this).text(), 10));
	});
}

All we’re doing is looking for Flexigrid’s trSelected class, accessing the TD:FIRST (this is why the ID column has to be the FIRST column) and then accessing the cell’s TEXT method whilst cleaning up all the content by throwing it to parseInt().

You can now do whatever you want with the value! Not too shabby for a sexy grid with no documentation q:P