Brainfart Saturday

I need to switch coffee brands…

Yesterday, for no apparent reason, I thought it may be a good idea to create a file transfer app that will asynchronously send files in slices(chunks) and still ensure the receiving party’s checksum will mach the sender’s. I was planning on adding public key security to the whole thing, but I can’t seem to get past step 1 without issues.

I tried testing splitting a file into slices and merging them immediately after and it seems to work just fine for small files.

Blob blob = FileUtils.GetBlob("C:\\Users\\Portable\\Downloads\\smalldoc.pdf");

FileUtils.SplitSlices(ref blob);

// Change the filename
blob.Path = "C:\\Users\\Portable\\Downloads\\smalldocCopy.pdf";
// Merge the slices back into one under the new filename
FileUtils.MergeSlices(ref blob);

The head-scratching starts when splitting and merging a large-ish file (50Mb+). The “Size on disk” identical to the original, but the “Size” is smaller than the original Size. Meaning it’s taking up the same disk allocation, but some bits got lost along the way. The funny thing is that if I then split the merged copy and merge it again into another copy, then this third copy is identical to the second. So original is still the odd one out.

I can’t seem to find the reason for this other than I’m missing something really obvious or this is a platform issue. I hope it’s the former because cursing at the latter feels… weird.

Here’s the “Slice” class where data would be stored and sent/received async.

public class Slice
{
	// Slice Id (Checksum / Currently not used)
	public string Id { get; set; }
	
	// File(Blob) Id (Checksum)
	public string SourceId { get; set; }

	// Blob location index
	public int Index { get; set; }

	// Slice byte length
	public int Size { get; set; }

	// Slice data
	public string Data { get; set; }

	public bool Complete { get; set; }

	public Slice()
	{
		Complete = false;
	}
}

And the “Blob” class that use the above slice(s)

public class Blob
{
	// File Id (Checksum)
	public string Id { get; set; }

	// Slice collection
	public SortedDictionary<int, Slice> Slices { get; set; }

	// Save path
	public string Path { get; set; }

	// File size
	public int Size { get; set; }

	// Assembled file size
	public int CompletedSize { get; set; }

	public Blob()
	{
		Slices = new SortedDictionary<int, Slice>();
		Size = 0;
		CompletedSize = 0;
	}
}

And of course, the uglier-than-sin FileUtils class (those with weak hearts, avert your eyes).

public static class FileUtils
{
	private static int _blockSize = 65536;

	public static void SplitSlices(ref Blob blob)
	{
		FileInfo info = new FileInfo(blob.Path);
		string source = info.FullName;
		string dir = info.DirectoryName;

		using (FileStream fs = new FileStream(source, FileMode.Open, FileAccess.Read))
		{
			foreach (KeyValuePair<int, Slice> kv in blob.Slices)
			{
				Slice slice = kv.Value;
				byte[] data = new byte[slice.Size];
				int read = 0;

				fs.Seek(slice.Index, SeekOrigin.Begin);
				if ((read = fs.Read(data, 0, slice.Size)) > 0)
				{
					WriteSlice(ref slice, data, dir);
				}
			}
		}
	}

	public static void WriteSlice(ref Slice slice, byte[] data, string dir)
	{
		string slicePath = SourceFromSlice(slice, dir);
		using (FileStream ofs =
			new FileStream(slicePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
		{
			ofs.Write(data, 0, slice.Size);
			slice.Complete = true;
		}
	}

	public static void MergeSlices(ref Blob blob)
	{
		FileInfo blobInfo = new FileInfo(blob.Path);
		string dir = blobInfo.DirectoryName;

		using (FileStream outfs =
			new FileStream(blobInfo.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
		{
			foreach (KeyValuePair<int, Slice> kv in blob.Slices)
			{
				Slice slice = kv.Value;
				if (slice.Complete)
				{
					byte[] bytes = ReadSlice(ref slice, dir, true);
					outfs.Seek(slice.Index, SeekOrigin.Begin);
					outfs.Write(bytes, 0, slice.Size);

					// Update the completed count
					blob.CompletedSize += slice.Size;
				}
			}
		}
	}

	public static byte[] ReadSlice(ref Slice slice, string dir, bool delAfterReading)
	{
		int read = 0;
		byte[] data = new byte[slice.Size];
		string slicePath = SourceFromSlice(slice, dir);

		using (FileStream ifs = new FileStream(slicePath, FileMode.Open, FileAccess.Read))
		{
			read = ifs.Read(data, 0, slice.Size);
		}

		if (delAfterReading)
			File.Delete(slicePath);

		return data;
	}

	public static void InitBlob(ref Blob blob)
	{
		int sliceCount = 0;
		int sliceSize;

		// Catch remaining byte length after splitting
		int remainder = (blob.Size > _blockSize)? (blob.Size % _blockSize) : 0;

		// If this is a big file that can be split...
		if (blob.Size > _blockSize)
		{
			sliceCount = blob.Size / _blockSize;
			sliceSize = blob.Size / sliceCount;
		}
		else // Slice size same as blob size and only one slice needed
		{
			sliceCount = 1;
			sliceSize = blob.Size;
		}

		for (int i = 0; i < sliceCount; i++)
		{
			Slice slice = new Slice();
			slice.SourceId = blob.Id;
			slice.Size = (i == 0) ? sliceSize + remainder : sliceSize;
			slice.Index = i * slice.Size;

			blob.Slices.Add(slice.Index, slice);
		}
	}

	public static Blob GetBlob(string source)
	{
		Blob blob = new Blob();
		FileInfo info = new FileInfo(source);

		blob.Id = FileId(source);
		blob.Size = LengthToInt(info.Length);
		blob.Path = info.FullName;
		blob.CompletedSize = LengthToInt(info.Length);

		InitBlob(ref blob);
		return blob;
	}

	public static string GetChecksum(string source, string mode = "md5", bool isFile = false)
	{
		byte[] bytes = { };
		Stream fs;

		if (isFile)
			fs = new BufferedStream(File.OpenRead(source), 120000);
		else
			fs = new MemoryStream(Encoding.UTF8.GetBytes(source));

		switch (mode.ToLower())
		{
			case "sha1":
				using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
					bytes = sha1.ComputeHash(fs);
				break;

			case "sha256":
				using (SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider())
					bytes = sha256.ComputeHash(fs);
				break;

			case "sha512":
				using (SHA512CryptoServiceProvider sha512 = new SHA512CryptoServiceProvider())
					bytes = sha512.ComputeHash(fs);
				break;

			case "md5":
			default:
				using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
					bytes = md5.ComputeHash(fs);
				break;
		}

		// Cleanup
		fs.Close();
		fs = null;

		return BitConverter
			.ToString(bytes)
			.Replace("-", "")
			.ToLower();
	}

	private static int LengthToInt(long length)
	{
		return (int)Math.Ceiling((double)length);
	}

	private static string FileId(string source)
	{
		return GetChecksum(new FileInfo(source).FullName, "sha256", true);
	}

	private static string SourceFromSlice(Slice slice, string dir)
	{
		return dir + "\\" + slice.SourceId + "_" + slice.Index + ".slice";
	}
}
Advertisement

Building a jQuery UI Dashboard

Sometimes you have an existing website or template that needs to function as a dashboard. The only solution then is to create drop-in widget functionality without necessarily modifying the HTML. This is a bit of an update to a much older post

The good news is that if the layout is by and large uncluttered and follows a predictable set of elements (key issue), it’s fairly straightforward to give a layout dashboard functionality without actually touching the HTML structure. jQuery and jQuery UI are perfect for this.

The tricky bit is adding any additional elements for control while handling each segment of content as a widget. In this case, every “widget” can be any element that has the CSS class column applied to it which means we can use the existing <h5> title element as the header for it.

Take as an example, my Simply theme which has no “widget-like” functionality whatsoever and the only JavaScript is Modernizr for backwards compatibility since it was recently rewritten in HTML5. But because all the content elements are predictable (there are sections and one level of nested sections that act as columns), it can be turned into a dashboard without touching the rest of the HTML.

You can take a look at a running demo of it and see below for an explanation of what’s going on.

A running demo of "Simply" turned into a dashboard

For this example, I needed the dashboard widgets to be able to be moved around on each row, have the title, content and the article icon changed and of course be able to close them. Naturally, this is only a client-side example. The final version would need to post these changes server-side for saving.

The Procedure

We can first start by adding the jQuery UI theme CSS file right above the original stylesheet. I’m using a customized version of the Smoothness theme. Just a few tweaks to make it match mine.

<link rel="stylesheet" type="text/css" href="themes/jQueryUI/ui-style.css" id="ui-theme" />
<link rel="stylesheet" type="text/css" href="themes/Simply/style.css" id="theme" />

After that we can add the jQuery and jQuery UI libraries to the template. In my project, there was also a need to add a wysiwyg and I had to use their propietary one, but for this example, I can simply use TinyMCE.

For this example, I’m going to put all the scripts into a folder called /lib. This is also where I’ll extract TinyMCE (the jQuery plugin version).

Modernizr, very usefully, can load other scripts by URL, so we can simply do the following right after adding its JS own file :

<script type="text/javascript" src="lib/modernizr.custom.js"></script>
<script type="text/javascript">
	Modernizr.load([{
		load: "https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"
	}, {
		load: "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"
	}, {
		load: "lib/tiny_mce/jquery.tinymce.js"
	}, {
		load: "lib/dash.js"
	}]);
</script>

And that’s all we need to do on the template itself. That last file being called, “dash.js” in the /lib folder is where we’ll put everything else.

dash.js

I’m going to start by adding some custom CSS to this file rather than cluttering up the head section of the template. These are just a few added classes to make the content more presentable.

All this will be added inside the jQuery $(fuction() { }); section.

$('head').append('<style type="text/css">' +
	'.icon { width:75px; height:75px; }' +
	'.ticon { float:left; margin: .3em .5em; width:25px; height:25px; box-shadow:1px 1px 1px #aaa; }' +
	'.ui-dialog { text-align:left; }'+
	'.ui-dialog input[type="text"], .ui-dialog textarea { display:block; width:90%; }' +
	'</style>');

Next, since we’re working with TinyMCE, we’ll store those settings in a variable.

var tinySettings = {
	script_url : 'lib/tiny_mce/tiny_mce.js',
	plugins: "inlinepopups",
	theme: "advanced",
	theme_advanced_buttons1 : "bold,italic,underline,strikethrough," +
		"separator,cut,copy,paste,separator,bullist,numlist," +
		"separator,undo,redo,separator,link,unlink,image",
	theme_advanced_buttons2 : "",
	theme_advanced_buttons3 : "",
	theme_advanced_toolbar_location : "top",
	theme_advanced_toolbar_align : "left",
	theme_advanced_statusbar_location : "bottom",
	width: "100%",
	height: 250,
	content_css : "content.css",
};

You’ll notice the last line refers to a “content.css” file. This basically styles the wysiwyg content as it’s being edited. In my case, this is all it contained…

body {
	font: normal 90% Sans-serif,tahoma,verdana;
	color: #575757;
}

p {
	line-height:170%;
}

Dialogs

Dashboards frequently use dialogs when making changes, presenting confirmations etc… In this case, I just created two dialogs for editing content and to confirm when removing the widget…

function initDialogs() {
	// Close widget dialog
	$('article').append('<div id="dialog-confirm-close-widget" title="Close widget" style="display:none;">' +
		'<span class="ui-icon ui-icon-alert" style="float:left;"></span>' +
		'You are about to delete this widget. Are you sure?</div>');

	// Config widget dialog
	$('article').append('<div id="dialog-config-widget" title="Modify" style="display:none;">' +
		'<form><fieldset><legend>Change widget content</legend>' +
		'<p><label>Title <input type="text" id="widget-title-text" /></label></p>'+
		'<p><label>Content <textarea rows="5" cols="50" id="widget-content-text">Some test content</textarea></label></p>'+
		'<p id="icon-field"><label>Icon URL <span>Will be resized to 75x75 pixels</span><input type="text" id="widget-icon-text" /></label></p>'+
		'</fieldset></form></div>');

	// Create and destroy these dialogs to hide them
	$('#dialog-confirm-close-widget').dialog("destroy");
	$('#dialog-config-widget').dialog("destroy");
}

That textarea will be replaced with TinyMCE later.

3 Little Helpers

Often overlooked, helpers can save a lot of time and help unclutter your JS quite a bit.

The following three check for null or empty strings, initializes and applies TinyMCE to an element with the given settings and removes the wysiwyg after sending the changes back to the textarea… in that order.

function notEmpty(t) {
	if(t) {
		if($.trim(t) != "")
			return true;
	}
	return false
}

function initTiny(t, s) {
	t.tinymce(s);
}

function closeTiny(t) {
	var e = t.attr('id');
	t.val(tinyMCE.get(e).getContent());
	tinyMCE.execCommand('mceRemoveControl', false, e);
}

Widget controls

In jQuery UI, there are ui-icons that we can use here without having to invest extra time to create our own. This also means we can apply our controls to these icons by using something like the “title” or “alt” attribute as the command string. In this case, I opted to use the “title” attribute since I’ll be using these icons in <span> tags.

function setControls(ui) {
	ui = (ui)? ui : $('.ui-icon');
	ui.click(function() {
		var b = $(this);
		var p = b.parentsUntil('.column').parent();
		var i = p.children('img[alt="icon"]:first').eq(0);

		var h = p.children('.ui-widget-header h5:first').eq(0);

		// Control functionality
		switch(b.attr('title').toLowerCase()) {
			case 'config':
				widgetConfig(b, p);
				break;

			case 'toggle':
				widgetToggle(b, p, i);
				break;

			case 'close':
				widgetClose(b, p);
				break;
		}
	});
}

Note, the three widget functions that will “config” (as in edit the content), “toggle” (collapse/expand) and “close” the widgets.

The toggle function is pretty simple. I wanted to minimize the .widget-content class (which we’ll add later), change the minus into a plus on the side of the widget after collapsing and turn the big image icon seen on most of those segments into a smaller one that fits on the header. The .ticon class is what we added to the head earlier.

// Toggle widget
function widgetToggle(b, p, i) {
	// Change the + into - and visa versa
	b.toggleClass('ui-icon-minus').toggleClass('ui-icon-plus');

	// Turn the big icon into a small one or visa versa
	if(i.hasClass('icon'))
		i.switchClass('icon', 'ticon', '300');
	else
		i.switchClass('ticon', 'icon', '300');

	// Show/Hide widget content
	p.children('.widget-content').eq(0).toggle(300);
};

Closing a widget is also pretty straightforward. We’ll be using the closing dialog we added earlier.

// Close widget with dialog
function widgetClose(w, p) {
	$("#dialog-confirm-close-widget").dialog({
		resizable: false,
		modal: true,
		buttons: {
			"Close widget": function() {
				p.toggle('slide', {}, 500, function() {
					p.remove();
				});
				$(this).dialog("close");
			},
			Cancel: function() {
				$(this).dialog("close");
			}
		}
	});
}

The last of the widgets is the config. This is the trickiest part, since we’ll need to create and destroy TinyMCE instances and get input from the dialog and push to the content.

// Modify widget
function widgetConfig(w, p) {

	// Input elements in the dialog
	var dt = $('#widget-title-text');
	var dc = $('#widget-content-text');
	var du = $('#widget-icon-text');

	// Widget elements to change
	var wt = p.children('h5:first').eq(0);
	var wc = p.children('.widget-content').eq(0);

	// If there is no icon on the widget, there's nothing to change
	var wi = p.children('img[alt="icon"]:first');
	if(wi.length > 0) {
		wi = p.children('img[alt="icon"]:first').eq(0);
			$('#icon-field').show();
	}
	else {
		$('#icon-field').hide();
	}

	$("#dialog-config-widget").dialog({
		resizable: false,
		modal: true,
		width: 500,
		open: function() {
			if(wi != null)
				du.val(wi.attr('src'));

			dt.val(wt.text());
			dc.val(wc.html());

			// Initialize TinyMCE
			initTiny(dc, tinySettings);
		},
		buttons: {
			"Save changes": function(e, ui) {

				// Some widgets don't have an icon
				if(wi.length > 0) {
					if(notEmpty(du.val()))
						wi.attr('src', du.val());
				}

				// Remove editor (also gets content from TinyMCE back to textarea)
				closeTiny(dc);

				// Update
				if(notEmpty(dc.val()))
					wc.html(dc.val());

				// Careful here, don't wanna lose the control icons
				if(notEmpty(dt.val())) {
					var ci = wt.children('span.ui-icon');
					wt.html(dt.val());

					// Reset controls
					wt.prepend(ci);
					setControls(ci);
				}

				$(this).dialog("close");
			},
			Cancel: function() {

				// Destroy TinyMCE
				closeTiny(dc);

				$(this).dialog("close");
			}
		}
	});
}

Basically, the above function grabs the text fields from the dialog and puts the existing content on page into them. The user makes some edits and clicks on “Save changes” which causes the script to take the changed content and apply it back to the page. In a real-world example, this content will actually be posted back to the server.

Note: Since the control icons are also located in the title, when we change the title text, we have to make sure that the control icons are spared from any edits.

The Initialization.

This basically takes every section with a “column” class that has a <h5> element inside into a sortable widget. It adds the control icons as <span> tags and wraps the content in a widget-content <div> (which we can minimize) and adds the ui-widget classes from jQuery UI to aid with sorting.

function Init() {

	// Initialize dialogs
	initDialogs();

	// Portlet and sort related CSS classes
	var sortClasses = "ui-widget ui-widget-content ui-helper-clearfix";

	// Set every column segment with h5 element as a sortable widget
	$('.column:has(h5)').each(function() {

		var s = $(this);
		var p = s.parentsUntil('section').parent();
		var h = s.children('h5:first').eq(0);

		if(!p.hasClass('ui-widget'))
			p.addClass(sortClasses);

		// Function icons
		h.addClass('ui-widget-header')
			.prepend('<span class="ui-icon ui-icon-gear" title="Config"></span>')
			.prepend('<span class="ui-icon ui-icon-minus" title="Toggle"></span>')
			.prepend('<span class="ui-icon ui-icon-close" title="Close"></span>');

		// Need this to drag not highlight
		h.disableSelection();

		// Interaction cues
		h.css('cursor', 'move');
		$('.ui-icon').css('cursor', 'pointer');

		// Wrap control stuff (like icons and headers) in a widget-header div
		// and the rest in a widget-content div
		s.children().not('img[alt="icon"], .ui-widget-header, .ui-icon')
			.wrapAll('<div class="widget-content" />');

		s.children().not('widget-content').wrapAll('<div class="widget-header" />');
	});

	// Group sortable widgets in each section to one sort-area
	$('section').has('.column').each(function() {
		$(this).children().not('header,hr')
			.wrapAll('<div class="sort-area" />');
	});

	// Trigger control initialization
	setControls();
}

And lastly, if we don’t have sorting ability, we can’t really call this a dashboard. Ironically the most defining characteristic in dashboards is the most simple to implement once all the wrapper divs are in place.

$(".sort-area").sortable({
	connectWith: ".sort-area",
	opacity: 0.6,
	helper: 'clone',
	dropOnEmpty: true
});

This post was prompted by yet another example of why I have a dim view of project managers.

Can you put together a dashboard for us?

OK, no problem.

We already have the backend completed and a template in place although it doesn’t have any widget markup. Except for the head tag, we need you to not touch the rest of it because we do have other stuff on the page. BTW… We need it in an hour.

@$#& me!

I wish the above was an exaggeration, but sadly, it happens more often than I care to tolerate.

The problem is easy enough to come by. Someone first builds a backend thinking they’ll have all sorts of widget like functionality in the future, but doesn’t develop the front end for any of it. Time goes by… The next developer comes along and decides that since the template is already in place, they’ll finagle the output to be more “widget-like” and create a separate handler to manage user changes. This also explains why so many “legacy” dashboards are notoriously slow.

So now they bring in someone else to drop in a dashboard where there previously existed no frontend for it… And they want it yesterday.

Oh, right New Year resolution…
Less grumpy. Less grumpy. Less grumpy.

Update

Changed the notEmpty(t) function line if(t != “”) into if($.trim(t) != “”).

Symfony : The ASP.Net of PHP

… Well not quite, but I’m sure most ASP.Net programmers would refer to it in this fasion. If you’re coming form another web application framework, then this is well worth looking into.

This project came into focus for us when we had a client with a preexisting web application in need of a drastic rewrite. The catch was the time. We literally had 3 days!!

Well, considering (as I’ve mentioned before) I’m not the greatest PHP programmer out there. In fact, before this, my most extensive work with PHP was a discussion board and FAQ comment system tied to a CRM. But, as they say in England, you’ve got to keep a stiff upper lip at these types of situations.

I would highly recommend downloading Uniform Server if you’re on a Windows machine. It’s, by far, the easiest method of creating a complete Apache/PHP/MySQL platform painlessly for Windows systems. Also of note is the nice admin panel, which, though rather sparse, gets the job done and is easy to use.

The first step is pretty basic. Get your server running and then navigate to W: in a command prompt (This is where the server will mount when running).

Note : The commands to type are in bold white.
c:>w:
w:>cd usrlocalphp
w:usrlocalphp>

Now we’re going to use Pear to access the Symfony repository.
w:usrlocalphp>pear channel-discover pear.symfony-project.com

If your system for some reason cannot identify PHP (some users noted this problem), then use the full path of PHP.
w:usrlocalphp>w:usrlocalphppear channel-discover pear.symfony-project.com

Once that’s done, we’re going to install it
W:usrlocalphp>php -r "readfile('http://pear.php.net/go-pear');" > go-pear

Again, if it doesn’t recognize this, use the full path as the above example.
W:usrlocalphp>w:usrlocalphpphp -r "readfile('http://pear.php.net/go-pear');" > go-pear

Now you will be prompted with a few installation options.

Note: All these are without quotes…

For : “If you wish to abort, press Control-C now, or press Enter to continue: ”
Press : “Enter”

For : “HTTP proxy (http://user:password@proxy.myhost.com:port), or Enter for none:”
Press : “Enter”

For : “1-8, ‘all’ or Enter to continue:” (This is regarding the executable directory)
Press : “Enter”

For : “Would you like to install these as well? [Y/n] :”
Type : “y”

For : “Would you like to alter php.ini ? [Y/n] :”
Type : “y”

Now as of this post, the version you have just installed is the 1.1.x branch. It’s the stable branch and works well.

My suggestion afterwards is to visit the cookbook so you can quickly get in touch with the basics. Also take a peek at the video tutorial on the Admin Generator.  It isn’t very difficult, but be thorough when you go through this. Missed steps or oversights can cause some issues down the road, so double-check your work.

Aside from the command line fiddling and a few manual edits, Symfony can get a great deal accomplished in a very short period of time.

Using the Admin Generator, here is my experimental (and very minimal) MySQL database generated by the tool :

# This is a fix for InnoDB in MySQL >= 4.1.x
# It "suspends judgement" for fkey relationships until are tables are set.
SET FOREIGN_KEY_CHECKS = 0;

#-----------------------------------------------------------------------------
#-- articles
#-----------------------------------------------------------------------------

DROP TABLE IF EXISTS `articles`;

CREATE TABLE `articles`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`title` VARCHAR(255) NOT NULL,
`description` VARCHAR(255),
`content` TEXT,
`abstract` TEXT,
`author_id` INTEGER NOT NULL,
`category_id` INTEGER default NOT NULL,
`is_published` INTEGER,
`date_pub` DATETIME,
`date_created` DATETIME,
PRIMARY KEY (`id`),
INDEX `articles_FI_1` (`author_id`),
CONSTRAINT `articles_FK_1`
FOREIGN KEY (`author_id`)
REFERENCES `users` (`id`),
INDEX `articles_FI_2` (`category_id`),
CONSTRAINT `articles_FK_2`
FOREIGN KEY (`category_id`)
REFERENCES `categories` (`id`)
)Type=InnoDB;

#-----------------------------------------------------------------------------
#-- users
#-----------------------------------------------------------------------------

DROP TABLE IF EXISTS `users`;

CREATE TABLE `users`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`username` VARCHAR(50) NOT NULL,
`password` VARCHAR(50) NOT NULL,
`display_name` VARCHAR(255),
`first_name` VARCHAR(255),
`last_name` VARCHAR(255),
`email` VARCHAR(100) NOT NULL,
`avatar` VARCHAR(255),
`bio` TEXT,
PRIMARY KEY (`id`)
)Type=InnoDB;

#-----------------------------------------------------------------------------
#-- categories
#-----------------------------------------------------------------------------

DROP TABLE IF EXISTS `categories`;

CREATE TABLE `categories`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`title` VARCHAR(255) NOT NULL,
`abstract` TEXT,
`photo` VARCHAR(255),
`is_private` INTEGER,
PRIMARY KEY (`id`)
)Type=InnoDB;

# This restores the fkey checks, after having unset them earlier
SET FOREIGN_KEY_CHECKS = 1;

Not the best example out there, but you can see what I was aiming for.

The great thing about this is that you can very quickly create the basic functionaly of any web application from CMS to CRM to Blog with plenty of flexibility and room to fix errors.
Highly recommended if this is the first time you’re dealing with a web framework. Also, a good way to improve your PHP.

This example was setup on a Vista PC.

MS is now KOS

But that might be a good thing for Microsoft in the longer run…

Ever since the announcement of Windows 7, it seems a vast number of publications seem to be seething over the apparent abandonment of Vista. And MS has felt the wrath from the likes of Dvorak who goes as far as to call Microsoft the “Spandex Granny” in a PC World article.

Are they really abandoning Vista or are they more concerned with abandoning what ties Vista to XP and, by extension, Win2000?

I think it’s more toward the latter.

Microsoft must be aware that it’s not 1995 and that type of tech dream-team domination will never happen again. Then this new impetus must involve setting fire to some of the old-world baggage. Kill it all. While this will also, potentially, kill our application compatibility (even more than it has with Vista) it may not necessarily be outright evil if their final product is genuinly safe, stable, bloat free and, above all else, secure. Who knows, if the above criteria are met, there might even come about stable emulation tools that will still enable apps to function normally.

The gaping holes in Windows security is part Microsoft’s fault, and part the fault of application developers who open up their users’ systems to the Big Bad Wolf of the Net. Why huff and puff when all it takes to compromise a Windows system is a remote hole in an application?

This brings me to the MS apps…

It may be true that the train wreck known as Vista was probably rushed with all the best intentions, it’s a direction that’s new to Microsoft. They’ve made WPF such a big deal, perhaps, to dump what makes MS apps so vulnerable and be able to focus on the OS security itself. Maybe the added features and rendering capability was primarily to entice programmers so they can be better controlled and herded by the OS. It’s a lot easier to keep track of Betsy if she’s in her pen.

I think it’s fair to say, and many other programmers would agree, Microsoft has made programming for Windows so nonchalant, that they have actually encouraged writing shoddy code. This is partly due to the way MS has promoted their development tools, which tend to appeal to the novice programmer. And every Tom, Dick, and Harry has become a self-proclaimed MS application developer. I’m by no means encouraging user un-friendliness, but I am encouraging caution when designing developer apps where proper structure (and practical “best practices”) are emphasized.

There’s a reason why some dangerous roads atop mountains don’t have guard rails. It encourages safe driving. When you have that safety net, you don’t worry as much about being careful. When developer apps are designed with all-or-nothing excecution, where tools recognize potential for unstable behaviour or fail compilation on warning, sure it could be frustrating, but it ensures your app is stable. Though application security is an integral, but seperate topic, in many cases stability = security.

Then there’s the issue of documentation…

While MSDN does a very decent job of listing language capabilities, it isn’t complete. There are many commonly asked questions on developing methods, and sure there are many ways to accomplish the same task… but why are we repeating ourselves? Why not create example desktop applications that implement many of the “best practices” that MS itself seem to be promoting? MS already has an Open Source variant license called the MS Source Available License. Here’s a chance to set a precedent in application development by leading the way.

It’s easy to say don’t develops apps like “this”, do it like “that” instead, but actually seeing the source code implemented will help all novice programmers.

So are we abandoning the Windows we knew? If we’re getting something better in return, maybe it isn’t all that bad. Microsoft has a culture war within the organization to fight in addition to fighting hackers. Its culture of security through obscurity will not work for the foreseeable future as they might have already realized with the flood trojans out there. Hiding errors, obviously, doesn’t work. Maybe building it more securely from scratch will.

In this regard, the MS folks and app developers have a lot to learn from the OpenBSD community. Focus on correctness of code and keeping safe and secure will come more easily. Let’s stop calling the Find Exploit→Patch cycle and proactively ensure the OS and its apps are ready to hit the ground running. If it means killing off all if not most ties to the previous branches in the family, then so be it.

If Old Yeller can’t learn some new tricks or can’t shake loose the myriad of diseases it’s caught from within and without, then it might be time to put him down.

Precompile your Web apps

This gets mentioned a dozen or so times whenever we decide on a launch date for a client site. But it never seems to sink in for some reason. I don’t know if it’s because it’s not considered to be crucial or if people are somehow uncomfortable not being able to read their .aspx files.

There are times you need to include code with your project, but sometimes, consistency and efficiency are more important. Distribute the code seperately!

I know, a lot of people don’t have access to Visual Studio, and others don’t like to use the Express editions for various reasons in certain projects. I’m not excluded in this. I sometimes use Notepad to write quick apps just to save time (or I’m lazy).

Here’s a simple solution:
Create a .bat file in your app directory.
Put this in it..

C:WindowsMicrosoft.NETFrameworkv2.0.50727aspnet_compiler.exe -p C:app -v / C:cmp -u

This line compliles the app with provisions for you to modify it later (-u).

When it’s time to compile your project, just run the .bat file.

There is a detailed explanation of precompilation on MSDN. Replace “C:app” with the destination of your app and “C:cmp” with the output directory you want to compile to. Change the framework version first if you are not using 2.0.

A list of available versions on your computer should be under the /Framework directory. If you don’t have a particular version, it should be listed under Windows Update.