Thursday, December 22, 2011

RealVNC + Vine Server > TightVNC + Max OSX Default VNC

For some time now, I've been using an old Mac Mini as my home server. This setup has a few advantages:

  • Time Machine: two 3 TB external drives, one backed up to the other
  • iTunes Home Sharing: iTunes serves the media collection to two AppleTV's and two sets of AirPort Express-connected speakers (and one printer) all controlled by the Apple Remote App on various iOS devices
  • Unix foundation: offsite backups via rsync+ssh+cron
  • MAMP: painless development platform
  • DVI/HDMI output: server can play hulu/netflix/etc to the connected HD TV
To access the server remotely, I had previously been using the built-in Mac OS X "Screen Sharing" feature (a no-frills VNC server) and TightVNC client. At best, it was a slow, laggy, unstable connection. This setup was functional, but a pain to use.

After some experimentation, I discovered that Vine Server combined RealVNC client is a much better combination in every way. Connection time is instantaneous, lag is drastically reduced to almost native-app speeds, and connection stability is rock-solid. I don't have any hard data to back up my claims, but try it for yourself. The difference is night and day.

You're welcome, internet.

Tuesday, December 13, 2011

Easier Is Better Than Better

Sometimes, easier is better than better--a philosophy that applies to more than just software design.

Thursday, November 10, 2011

Forcing a Client Update of Cached Files

More than once now I've run into an issue where a stubborn browser will not pull a fresh copy of a file down from the server. This can especially be a pain when trying to debug some javascript or CSS. How can you test your changes if the damn client won't request the new code?

Here's a trick: append some junk parms to the end of the file source URL. So instead of

<script src="/Scripts/jquery.form.js" type="text/javascript"></script>

try

<script src="/Scripts/jquery.form.js?12345" type="text/javascript"></script>

As long as your app isn't processing parms on that URL (or at least not parm you added), you should force the client to download the new version.

For something more robust, try appending the current datetime before serving the file. For example, in ASP.NET,

<script src="/Scripts/jquery.form.js?<%:DateTime.Now.ToString("yyyyMMddhhmmss")%>" type="text/javascript"></script>

Friday, November 4, 2011

Going Wallet-less

Simplify.
Made in America.
From recycled plastic even.

Thursday, November 3, 2011

Javascript Pretty Print in Chrome Dev Tools

This is one of several reasons why I develop my javascript in Google Chrome.

Wednesday, October 26, 2011

FileStream and MemoryStream Conversions

Once upon a time, I was had some code like the following:

using (FileStream destStream = new FileStream(writePath, FileMode.Create))
{
 /* 3rd party lib writes to destStream */
}

Trouble was... the 3rd party call had the potential to throw an error. Of course, by then, the file at "writePath" had already been created. This was no good.

Lucky for me, the 3rd party call didn't require a FileStream for writing -- any old Stream implementation would work. So why not a MemoryStream? This way, if the write fails, all I've lost is some to-be-garbage-collected memory.

The following methods helped me move my data between FileStream and MemoryStream objects:

public static MemoryStream ReadFileToMemoryStream(string filePath)
{
 MemoryStream memStream = new MemoryStream();
 using (FileStream fileStream = File.OpenRead(filePath))
 {
  memStream.SetLength(fileStream.Length);
  fileStream.Read(memStream.GetBuffer(), 0, (int)fileStream.Length);
 }
 return memStream;
}

public static void WriteMemoryStreamToFile(MemoryStream memoryStream, string filePath)
{
 WriteMemoryStreamToFile(memoryStream, filePath, FileMode.Create);
}

public static void WriteMemoryStreamToFile(MemoryStream memoryStream, string filePath, FileMode fileMode)
{
 WriteMemoryStreamToFile(memoryStream, filePath, FileMode.Create, FileAccess.Write);
}

public static void WriteMemoryStreamToFile(MemoryStream memoryStream, string filePath, FileMode fileMode, FileAccess fileAccess)
{
 using (var fileStream = new FileStream(filePath, fileMode, fileAccess))
 {
  byte[] data = memoryStream.ToArray();
  fileStream.Write(data, 0, data.Length);
 }
}

Wednesday, October 19, 2011

PDF Viewing Options in Google Chrome


Google Chrome comes with its very own PDF viewer. However, as of the date of this post, this viewer cannot display most forms of embedded PDF annotations:
Currently, we do not support 100% of the advanced PDF features found in Adobe Reader, such as certain types of embedded media.
For a workaround, use the URL/address bar to navigate to "about:plugins"--you can also reach this screen from Options >> Under the Hood >> Content Settings >> Plug-ins >> Disable individual plug-ins...

From here, you can disable the "Chrome PDF Viewer" plug-in. Chrome should then download PDFs instead of attempting to open them.

Optionally, if you have Adobe Acrobat Reader installed, you can enable the Adobe Acrobat plug-in which will display embedded annotations correctly.

Friday, October 7, 2011

TightVNC Viewer: Save Connection

Son of a ...

<sigh>

I had been looking for this functionality forever! Right-click the TightVNC Viewer title bar to get all kinds of options, including "Save Connection" which lets you save the current connection info (including the password in plain text, just so you know--not that VNC passwords are very secure anyway, being sent unencrypted and whatnot).

Also in the menu: "Refresh Screen"--good for when an open connection gets broken/locked/frozen.

Thursday, October 6, 2011

Linq-to-Entities: EntityFunctions

Jefe: I have put many beautiful methods in the System.Data.Objects.EntityFunctions class, each of them filled with little suprises.
El Guapo: Many methods?
Jefe: Oh yes, many!
El Guapo: Would you say I have a plethora of methods?
Jefe: A what?
El Guapo: A *plethora*.
Jefe: Oh yes, you have a plethora.
El Guapo: Jefe, what is a plethora?
Jefe: Why, El Guapo?
El Guapo: Well, you told me I have a plethora. And I just would like to know if you know what a plethora is. I would not like to think that a person would tell someone he has a plethora, and then find out that that person has *no idea* what it means to have a plethora.
Jefe: Forgive me, El Guapo. I know that I, Jefe, do not have your superior intellect and education. But could it be that once again, you are angry at something else, and are looking to take it out on me?

I ran across this class while attempting some date comparisons with Linq-to-Entities. See, EF won't let you do this:

var orders = db.Orders.Where(order => order.CreatedOn.Date >= model.CreatedOnStart.Date);

It barfs during runtime with "The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.". But with EntityFunctions, we can still get what we need:

var orders = db.Orders.Where(order => EntityFunctions.TruncateTime(order.CreatedOn) >= EntityFunctions.TruncateTime(model.CreatedOnStart));

Handy indeed.

Thursday, September 29, 2011

Friday, September 23, 2011

User Agent Switching with Google Chrome

I prefer the Chrome development tools to Firefox/Firebug for development, but found myself forced to use Firefox just so I could use the User Agent Switcher plug-in. Fortunately, Chrome allows user agent switching albeit from the command line. All Google tools rock the command line, because Google is old-school like that.

To mimic the iOS Safari browser, construct a shortcut with the following path:

C:\Users\{user}\AppData\Local\Google\Chrome\Application\chrome.exe --user-agent="Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528"

Update: Nevermind, I guess.

Thursday, September 22, 2011

Lorem Ipsum Alternatives

Vanilla lorem ipsum is so last week. Try these instead.

Tuesday, September 20, 2011

jQuery Select Consecutive Elements

Use jQuery .slice(). For example:

// select 2nd thru 4th list items
$('li').slice(1, 3);

In fact, you have to use slice in order to select the last, say, 5, elements of a set:

// select last 5 divs of a set
$('div').slice(-5);

ASP.NET MVC Render a View to a String

Sometimes it can be worthwhile to capture the content of a controller-generated view as a string for returning as JSON or as HTML email body content or whatnot.

Via Crafty Code:

public abstract class MyBaseController : Controller 
{
    protected string RenderPartialViewToString()
    {
        return RenderPartialViewToString(null, null);
    }

    protected string RenderPartialViewToString(string viewName)
    {
        return RenderPartialViewToString(viewName, null);
    }

    protected string RenderPartialViewToString(object model)
    {
        return RenderPartialViewToString(null, model);
    }

    protected string RenderPartialViewToString(string viewName, object model)
    {
        if (string.IsNullOrEmpty(viewName))
            viewName = ControllerContext.RouteData.GetRequiredString("action");

        ViewData.Model = model;

        using (StringWriter sw = new StringWriter()) {
            ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
            ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
            viewResult.View.Render(viewContext, sw);

            return sw.GetStringBuilder().ToString();
        }
    }
}

You can optionally replace ViewEngines.Engines.FindPartialView with ViewEngines.Engines.FindView.

Monday, September 19, 2011

Silent Football

I have copied the wikipedia article for Silent Football. If wikipedia ever goes down, THIS KNOWLEDGE MUST BE PRESERVED.

Ubuntu Post-Install Notes

This here list is mainly to remind myself what software to grab after a fresh Ubuntu install:
  • xtightvncviewer: my preferred flavor of VNC client software with which to control the Mac Mini connected to the TV
  • openssh-server: standard issue SSH server
  • inkscape: vector graphics; never actually used it, but I'd like to think that I might someday
  • gimp: as of Ubuntu 10.04, no longer comes in default install
  • filezilla: GUI for FTP
  • wireshark: packet sniffer
  • build-essential: base set of dev and deb package builder tools
  • eclipse: IDE for Java, PHP, C++; tons of plugins, very extensible, large user community
  • mono-devel: IDE for .NET languages (C#, VB)
  • vlc: swiss army knife of media players
  • audacity: audio editor
  • gmountiso: small GUI to mount ISOs
  • gparted: partition manager; why doesn't this come in default install?
  • keepassx: encrypted password manager
  • apache2: web server
  • mysql-server: database server
  • postgresql: database server
  • php5: PHP script engine
  • php5-gd: graphics library for PHP
  • php5-cli: PHP command-line execution
  • php5-pgsql: PHP libs to connect to postgre
  • php5-mysql: PHP libs to connect to MySQL
And of course there's a few games:
  • dosbox: DOS emulator
  • wesnoth-all: turn-based strategy game
  • beneath-a-steel-sky: fun story-based RPG
  • flight-of-the-amazon-queen: precursor to Beneath a Steel Sky
And then there's software not in the repos:
Remember to set up a cron-job (crontab -e) for hourly rsync backups:
  • 15 * * * * ~/rsync/backup.sh
All at once now:

sudo apt-get install xtightvncviewer openssh-server inkscape gimp filezilla wireshark build-essential eclipse mono-devel vlc audacity gmountiso gparted keepassx apache2 mysql-server postgresql php5 php5-gd php5-cli php5-pgsql php5-mysql dosbox wesnoth-all beneath-a-steel-sky flight-of-the-amazon-queen

Recommended iPhone Apps

Who care what apps some a-hole on the interwebs has on his iPhone?

iPhone & iPad
  • SoundHound: Preferred over Shazaam for both performance and UI. I wouldn't support Shazaam anyway on philosophical grounds. Don't sue me!
  • VNC Viewer: $10 when I got it, but totally work it. It's an iPhone+iPad dual app, so that's nice. We've got VNC servers set up on all compys in the house, but we use it most with the Mac Mini connected to the TV.
iPhone
  • WeatherBug Elite: Very decent weather app--a steal at $1. Everything you need, none of what you don't. Used to have a huge problem with crashing, but not so much anymore. Why does the built-in weather app suck so much?
  • IMDB: Always good for settling bar bets.  Also does movie showtimes so you can skip Fandango or Movies or whatever other movie app.
  • Flight Control: This week's Cussack move was Pushing Tin and the whole time I was like, "Pfft, I can do that."
  • Plants vs. Zombies: Probably the best game ever.
  • last.fm: Sadly no longer streams for free.
  • mint.com: Finanical tracker and budget tool. Used to be super-light on functionality, but adds more with each update.
  • 360 News: The only news app you'll ever need.
  • Reeder: Syncs with Google Reader. If you don't like Google Reader, then fuck you.
  • Remote: We use this to fire off our tunes from the Mac in the living room to all the AirPort Express speakers in the house. I don't understand why library sharing in the regular iPod app can't match the Remote app on performance.
  • TouchTerm SSH: Gives me a nerd boner. Free when I downloaded it lo these many years ago. Neener. 
iPad
  • GoodReader: Makes the iPad one step closer to being a real laptop.
  • Netflix, ABC, NBC apps: Durr.
  • Reeder for iPad: Bigger version of the iPhone app.
So for the both of you that read my blog, go out and get some apps!

Ubuntu 10.4 Touchpad Fix

So I see this post for the upcoming version of Ubuntu 10.4.  I get the familiar nerd tingle as I head on over ubuntu.com to download the Beta 1 release and geek out on the couch.

First impression: I like it. Standard incremental improvements. Nice theme. Another win for Linux.

Second impression: Unstable. But that's ok, right? It's Beta 1 and it's my own darn fault.

Third impression: That sinking feeling knowling that while my personal docs are all safe and sound on my separate /home partiion, and while all my favorite 'buntu software is just an apt-get away, I've totally blown away the magic grub boot option that gets my crappy laptop touchpad working.

Well, friends... never again. Because now I've got a blog to share my google research project results with the world. And myself.

Now last time it took forever to figure out the touchpad problem because I had nothing solid to throw at google. "ubuntu touchpad problem". Yeah, no.

Fortunately, I remembered it had something to do with adding a command to the grub boot setup, so that helped me get the answer much quicker this time. 

Update GRUB_CMDLINE_LINUX_DEFAULT in the file /etc/default/grub so that it includes "i8042.nomux=1".  Now run update-grub and reboot. I have no idea what it means of what it does, but it fixes my driver conflict issue or whatever the hell was the problem.  I could google it and figure it all out, but I'm going to go watch Zombieland on my iPhone.

Ampache Music Server

Maybe it's because iTunes has pissed me off one too many times, or maybe it's just for the sick, nerdy thrill, but I'm working on setting up my own Ampache music server.

Here's the specs:
  • Old Gateway all-in-one: Pentium III 1.2GHz, 20GB drive, 128MB RAM
  • Two 120GB external WD drives
  • Ubuntu 8.04.2 LTS
  • MySQL 5.0
  • Apache2
  • PHP5
  • Ampache 3.5.4 Stable
This post is just as much for my own documentation purposes as it is to share what I've learned with the net. Still, if you have any questions, feel free to comment.

Server

Let's proceed from a fresh install, shall we? For the record, this is from a vanilla command-line system install of Ubuntu 8.04 LTS -- no X, no GNOME, nothing other than the base system. Step 2: install OpenSSH, grab a beer, and head back downstairs.

Note: Apparently there's an ampache package in the repositories. Who knew? However, I prefer to keep my server and web apps separated. Just a personal preferrence--IT intuition I guess. Proceeding with the install of LAMP packages...

sudo apt-get install apache2 mysql-server php5
We can let apt handle all the dependencies, so that should cover it.

Storage

With a large collection, I need some way to "combine" the two 120GB external drives into one volume. To accomplish this, I used LVM. To install:

# install
sudo apt-get install lvm2
# test the install
sudo modprobe dm-mod
# auto-load the module on boot
sudo echo "dm-mod" >> /etc/modules

Then, using some tips from here, I gathered together the following commands:

# prepare the drives
sudo pvcreate /dev/sda1 /dev/sdb1
# create the volume group "vg" and add the two drives
sudo vgcreate vg /dev/sda1
sudo vgextend vg /dev/sdb1
# get the max size of the vg
sudo vgdisplay vg | grep "Total PE"
# use the "Total PE" amount above to size the logical volume
sudo lvcreate -l 57234 vg -n data
# format (ext3)
sudo mke2fs -j /dev/vg/data
# check the results
df -h
# add the mount command to /etc/fstab
echo "/dev/vg/data /media/data auto relatime,errors=remount-ro 0 1" >> /etc/fstab

Ampache

Grab the latest version of the Ampache source. At the time of this writing, version 3.5.4 was the latest stable build.I used these next commands to copy the download over to my music server:

scp ampache-3.5.4.tar.gz remoteuser@remotehost:/home/remoteuser
tar -xvf ampache-3.5.4.tar.gz

and then create a link between the extracted files and the Apache root:

sudo ln -s /home/remoteuser/ampache-3.5.4 /var/www/ampache

Now a quick trip over to http://remotehost/apache to kick-off Ampache's install wizard.

Tip: For album art support in Ampache, we need the PHP graphics library:

sudo apt-get php5-gd

Troubleshooting Tip: I had some inexperience with Apache which required me to restart the service a couple of times during debugging.

sudo /etc/init.d/apache2 restart

Even after restarting Apache, I was still having issues with Firefox offering to download my Ampache install instead of serving me the page. Clearing the browser cache fixed the issue.

Maintenance

I don't know why exactly, but out of all the steps in this series, this one took me the longest to figure out.

See, the music collection of any true aficionado will always be in a state of evolution. Songs get added, duplicates get deleted, tags get fixed, album art found, ratings assigned, etc. So the first step will be updating the music collection on the music server with any updates to the music collection on the file server. You might say I need some type of "remote syncing" utility. Hmm...

rsync --exclude="*.m4v" --exclude="*.mp4" --archive --verbose --compress --delete remoteuser@remotehost:/path/to/fileserver/collection/ /path/to/musicserver/collection

For those wishing to know more about rsync, RTFM. Suffice to say, this command will keep my collection on the music server an exact mirror copy of the source copy on the file server (except for my m4v/mp4 movies, which cause Ampache to barf on catalog updates).

To automate the process, we'll need to integrate some SSH and scripting. First, we generate a public/private key pair, and then we add the public key to the set of authorized keys on the file server.

ssh-keygen -t rsa -f my_key
scp my_key.pub remoteuser@remotehost:/home/remoteuser/.ssh

Then from the file server:

cat /home/remoteuser/.ssh/*.pub > /home/remoteuser/.ssh/authorized_keys

We can then use a cron job to execute the following script.

#!/bin/sh

RSYNC=/usr/bin/rsync
SSH=/usr/bin/ssh
KEY=/path/to/my/private/key
RUSER=remoteuser
RHOST=remotehost
RPATH=/path/to/remote/music/collection/
LPATH=/path/to/local/music/collection

$RSYNC --exclude="*.m4v" --exclude="*.mp4" --archive --verbose --compress --delete --rsh="$SSH -i $KEY" $RUSER@$RHOST:$RPATH $LPATH

Now that we have our files on the music server up-to-date, we need to refresh the Ampache catalog. Lucky for us, some enterprising soul wrapped up the catalog update logic in an easy-to-call script.


Note: To run a PHP script manually, install the PHP command-line utility:

sudo apt-get php5-cli

Then from the Ampache Wiki:

sudo -u www-data php /var/www/ampache/bin/catalog_update.inc [catalog_name] -a -c -v

The php command needs the path to catalog_update.inc. We can restrict the actions to "add", "clean", or "verify" with the flags at the end. The "sudo -u www-data" bit runs the whole shebang with the rights of the Apache user, thus mimicking what would be done via the UI.

Troubleshooting Tip: If the catalog update is failing, follow the instructions here to enable Ampache logging. It involves editing the config/ampache.cfg.php file. Don't forget to let the apache/www-data user have rights to the logging folder:

sudo mkdir /var/log/ampache
sudo chown www-data /var/log/ampache

Chances are the update routine came upon a file with bad tag, or a tag with some weird character in it, or some other such garbage. Could be Ampache/PHP ran out of memory; happened to me once with a 33MB Allman Brothers m4a file. In that case, adjust the "memory_limit" constant in config/ampache.cfg.php. Don't forget the "memory_limit" in /etc/php5/apache2/php.ini.

Troubleshooting Tip: If you have a good number of m4a files like I do, you'll find that Ampache doesn't much like reading the ID3/quicktime tags. This is a bummer if you want your track info correct in your catalog. One workaround is establishing a good file naming convention for your songs (/path/to/music/[artist]/[album]/[track#] - [track title].[file ext]), and then matching it to the correct "Filename Pattern" and "Folder Pattern" tokens in the the catalog setup. This way, Ampache doesn't even have to read the tags; it can just pick up the info from the file path & file name.

But then what about all that carefully maintained album art? Ampache to the rescue again: if there is a graphic file (jpg, png, etc.) in the album folder, Ampache will identify that as the album art. Your job, should you choose to accept it, is now to store your album art on the file system. There are tools a plenty to accomplish this. I used a dougscript to have iTunes do it for me.

Usage

If you've made it this far, you're done. Head over to your server and enjoy some PHP web-appy goodness.
For those with an iPhone, check out iAmpache from the App Store. It's a pretty basic app, not too many features; but it's free and it gets the job done. When iPhone OS 4.0 comes out, any iPhone models that can multi-task will be able to stream their raging tunes while Getting Things Done.

Update: Extreme bummer. Due to restrictions place on the app by Apple (probably as a proxy for AT&T), the iAmpache will not stream over 3G, only WiFi. Lame. There are plenty of other apps that stream audio over the cell connection, but I guess since neither Apple nor AT&T could control the bit rate/bandwidth usage, they put their foot down.

Update: For those with an Android phone, try Amdroid.

Friendly Neighborhood Tech Support

Great article here by my boy, Scott Hanselman, on how to help set up and maintain Windows systems for friends and family members who are lacking in tech savvy.

Adding my own $0.02:

  • join.me is handy for small stuff, but it might require something more heavy-duty for extended remote maintenance sessions. I haven't tried gotomypc.com yet, but it seems like a more stable solution for hours-long support sessions with lots of rebooting due to installs/uninstalls/updates/etc. Free for 30-days.
  • Install an SSH server for command-line authoritah. You can use DynDNS and their IP updater tool to keep track of dynamic IP addresses.
  • I used to install all kinds of crap back in the day to deal with security: AVG anti-virus, Lavasoft Ad-aware, ZoneLabs firewall, and so on. Today it looks like Microsoft Security Essentials and the built-in Windows firewall (XP and higher) can handle it all by themselves. It really prunes the system tray of a bunch of intimidating icons.
  • Portableapps.com has just about everything anyone could need for software. No more asking to "borrow" your copy of Microsoft Office. The best part is that the PortableApps menu can now update all the apps at once. Perfect.

SSH Server on Windows

Some notes for installing SSH as a service on windows systems:

I like DynDNS.com for maintaining a static link to dynamic IP addresses. My DD-WRT router keeps the IP current, but they also have an updater tool for multiple platforms.

jQuery Simple Date Selector

I was trying forever to find a simple javascript date selector that would do well on mobile applications. Couldn't find one, so I rolled my own. It takes a text or hidden input element and inserts three select elements after it, one each for months, days, and the year. The onchange event for each select copies the selected date back to the input, and the selects are initialized from the input on page load.

The code below should be enough to give you the idea.

The selector follows the jQuery UI widget template (another good widget tutorial here).

// attach widget to input
$(document).ready(function () { 
	$('#mydate').dateselector(); 
});

// some display formatting
Date.prototype.toMMDDYYYY = function () {
    return isNaN(this) ? 'NaN' : [this.getMonth() &gt; 8 ? this.getMonth() + 1 : '0' + (this.getMonth() + 1), this.getDate() &gt; 9 ? this.getDate() : '0' + this.getDate(), this.getFullYear()].join('/')
}

// date selector widget
; (function ($) {
	$.widget("ui.dateselector", {
		options: {},
		shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
		_syncToSelector: function () {
			var self = this;
			var date = new Date($(self.element).val());
			self.$container.find('select:eq(0)').val(date.getMonth());
			self.$container.find('select:eq(1)').val(date.getDate());
			self.$container.find('select:eq(2)').val(date.getFullYear());
		},
		_syncFromSelector: function () {
			var self = this;
			var date = new Date();
			date.setFullYear(self.$container.find('select:eq(2)').val());
			date.setDate(self.$container.find('select:eq(1)').val());
			date.setMonth(self.$container.find('select:eq(0)').val());
			$(self.element).val(date.toMMDDYYYY());
		},
		destroy: function () {
			var self = this;
			if (self.$container) self.$container.remove();
			$.Widget.prototype.destroy.apply(this, arguments);
		},
		_init: function () {
			var self = this;

			var $months = $('<select></select>').change($.proxy(this._syncFromSelector, this));
			for (var i = 0; i &lt; 12; i++) { $('<option></option>').val(i).text(this.shortMonths[i]).appendTo($months); }

			var $days = $('<select></select>').change($.proxy(this._syncFromSelector, this));
			for (var i = 1; i &lt;= 31; i++) { $('<option></option>').val(i).text(i).appendTo($days); }

			var thisYear = new Date().getFullYear();
			var $years = $('<select></select>').change($.proxy(this._syncFromSelector, this));
			for (var i = -2; i &lt;= 2; i++) { $('<option></option>').val(thisYear + i).text(thisYear + i).appendTo($years); }

			self.$container = $('<span class="dateselectorContainer"></span>').append($months).append($days).append($years);

			this._syncToSelector();

			self.element.hide().after(self.$container);
		}
	});
})(jQuery);

Custom Entity Object from Database View

Today's concept-of-the-day: the Entity Framework DefiningQuery.

The DefiningQuery is a customizable XML element in the EF edmx file that allows one to map a raw SQL query to a straight-up Entity POCO.

There are a few, uh, provisos. Ah, a couple of quid pro quo. Still, handy when you're in a tight spot.

You're welcome, internet.


Friday, September 16, 2011

Disable Ctrl+Wheel Zooming in Visual Studio

The bane of any Microsoft developer with a sticky Ctrl key:
http://stackoverflow.com/questions/2861655/how-do-i-disable-zoom-on-control-scroll-in-visual-studio-2010

I like how you have to install an extension to Visual Studio to disable Ctrl-scroll zooming.

We live in dark times, people.

Tuesday, September 13, 2011

Drupal LAMP Install Notes

Enable clean URLs:
  • a2enmod rewrite
  • "AllowOverride All" in /etc/apache2/sites-available/000-default
  • May also need "AccessFileName .htaccess" in there somewhere
Install phpMyAdmin from source:
  • sudo apt-get install mcrypt php5-mcrypt
  • cp /var/www/phpmyadmin/config.template.inc.php /var/www/phpmyadmin/config.inc.php
PHP settings:
  • memory limit around 128MB
  • date.timezone = "US/Central"

Eclipse PDT on Ubuntu

Another victim of my Ubuntu re-install... a working version of PDT in Eclipse.  The repo Eclipse, not the stand-alone downloaded version.  Now, I'm not going to get into the repo vs. stand-alone debate.  For what it's worth, one of the biggest reasons I use and love Linux, specifically Ubuntu, is apt/Synaptic package management.  So nyah.

So, to install PDT for Eclipse, you first need Eclipse.

sudo apt-get install eclipse

Once installed, open it up and head on into the menu "Help >> Install New Software" and click on "Available Software Sites" (I think you can also get to this screen through the Preferences menu).  Add the following:

  • DLTK 2.0 @ http://download.eclipse.org/technology/dltk/updates-dev/2.0/ 
  • PDT 2.2 @ http://download.eclipse.org/tools/pdt/updates/2.2/interim/ 
  • Zend @ http://downloads.zend.com/pdt/ 
  • Galileo Update Site @ http://download.eclipse.org/releases/galileo/

Now from "Help >> Install New Software", "Work with" the PDT link and select the Runtime plugin.  Click Next, accept the license, and pop open a cold one while the install works its magic.  I did have it error out once claiming a missing md5 hash or some such, but I tried it again and it went fine -- chalk it up to a flaky net connection.


See http://wiki.eclipse.org/PDT/Installation for more info.

Cygwin Notes

Just some notes.
  • Missing the "clear" terminal command? Install the "ncurses" package.
  • Always grab "openssh"

(Smart) jQuery Ajax Indicator

Any fool can hook into the jQuery's ajaxStart and ajaxStop functions in order to display an "ajax request in progress" indicator. But what if we want to suppress the display for requests that finish in less than X number of milliseconds? And what if we want to maintain the display actively for Y number of milliseconds (to prevent "bouncing")? Look no further. The markup:

<html>
	<head><!--blah blah--></head>
	<body>
		<div id="notify-container">
			<div class="ui-corner-bl ui-corner-br" id="ajax-loading" style="display: none;">
				Loading...</div>
			</div>
		<div>
		<!--blah blah-->
	</body>
</html>

Throw in some styling:

#notify-container 
{ 
	position: fixed; 
	left: 0; 
	top: 0; 
	width: 100%; 
	height: 0; 
	z-index: 100; 
}
#ajax-loading 
{ 
	position: absolute; 
	display: inline-block; 
	width: 100px; 
	left: 50%; 
	margin-left: -50px; 
	padding: 0.5em 1em 0.6em 1em; 
	font-weight: bold; 
	font-size: 1.1em; 
	text-align: center; 
	background-color: #ffe79c; 
	border: 1px solid #c98400; 
}

Any type of indicator works, really. I prefer a Google-esqe div that slides down from the top of the window, but it could be a spinner gif or an opaqued modal window. Doesn't matter; that's not the relevant part. Here's the magic:

$(document).ready(function () {
	// ajax working indicator
	$('#ajax-loading')
		.ajaxStart(function () {
			var $this = $(this);
			clearTimeout($this.data('waitingToHide'));
			$this.data('waitingToShow', setTimeout(function () { $this.slideDown(); }, 600));
		})
		.ajaxStop(function () {
			var $this = $(this);
			clearTimeout($this.data('waitingToShow'));
			$this.data('waitingToHide', setTimeout(function () { $this.slideUp(); }, 2000));
		});
})

Each call to ajaxStart and ajaxStop introduces the respective show and hide animations via a setTimeout delay. The function handler is saved to the jQuery element's data() store.

The real trick here is that before this happens, the data() store is checked and cleared of any pending animations. In this way, if ajaxStop is called before the show animation, the show animation will be "short-circuited". Similarly, if another call to ajaxStart occurs while the hide animation is pending, the hide animation will be cancelled.

Airport Printer Install for Windows 7

Installing Apple's Bonjour Print Services for Windows? No need!
  1. Get printer's IP address.
  2. Start > Control Panel > Devices and Printers
  3. Add a printer > Add a local printer
  4. Create a new port Standard TCP/IP Port
  5. Enter IP address, "IP_{address}" for the name  
  6. Make sure the box “Query the printer and automatically select the driver to use” is checked.
  7. Choose Custom, then Next.
  8. Select printer driver.

Delete an EFI Partition from Windows 7

The Windows 7 Disk Management tool has issues deleting those pesky EFI partitions so commonly found on Mac-formatted drives. Use the diskpart command utility instead.

Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\Windows\system32>diskpart

Microsoft DiskPart version 6.1.7601
Copyright (C) 1999-2008 Microsoft Corporation.
On computer: RAY

DISKPART> list disk

  Disk ###  Status         Size     Free     Dyn  Gpt
  --------  -------------  -------  -------  ---  ---
  Disk 0    Online          465 GB      0 B
  Disk 1    Online         2794 GB  2794 GB        *

DISKPART> select disk 1

Disk 1 is now the selected disk.

DISKPART> list part

  Partition ###  Type              Size     Offset
  -------------  ----------------  -------  -------
  Partition 1    System             200 MB    24 KB

DISKPART> select part 1

Partition 1 is now the selected partition.

DISKPART> detail part

Partition 1
Type    : c12a7328-f81f-11d2-ba4b-00a0c93ec93b
Hidden  : Yes
Required: No
Attrib  : 0000000000000000
Offset in Bytes: 24576

  Volume ###  Ltr  Label        Fs     Type        Size     Status     Info
  ----------  ---  -----------  -----  ----------  -------  ---------  --------
* Volume 6                      RAW    Partition    200 MB  Healthy    Hidden

DISKPART> delete part override

DiskPart successfully deleted the selected partition.

DISKPART> exit

Leaving DiskPart...

Source: http://superuser.com/questions/56958/can-i-delete-efi-system-partition-without-harming-other-data-on-drive

Syntax Highlighting in Blogger

Simplest way: use google-code-prettify. Add the following to just before the tag in the site template.

<link href="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css" rel="stylesheet" type="text/css"></link>
<script src="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js" type="text/javascript"></script>

Also in the site template, add the following attribute to the <body> element.

<body onload="prettyPrint()">

To use in a post, wrap the code in <pre> tags marked with the class "prettyprint".

<pre class="prettyprint">
*** CODE GOES HERE ***
</pre>

More options:
  • Host the prettify files elsewhere, like sites.google.com or a public folder on dropbox.
  • To display line numbers, add the class "linenums" (or "linenums:{row}", where {row} is the starting row).
  • Override the detected language type with the "lang-{syntax}" class.
  • Try some different style templates.
  • Add "white-space: nowrap; overflow: auto" to the "ol.linenums" css to get scroll bars on long content.
  • Add the following css to hide the blogger nav bar: #navbar-iframe {display: none !important;}
Here's an excerpt from my template near the </head> tag:

...
  
	#navbar-iframe {display: none !important;}
	]]>
    </b:template-skin>
	
	<link href='http://dl.dropbox.com/u/11517241/google-code-prettify/src/prettify.css' rel='stylesheet' type='text/css'/>
	<script src='http://dl.dropbox.com/u/11517241/google-code-prettify/src/prettify.js' type='text/javascript'>  </script>

  </head>

  <body expr:class='&quot;loading&quot; + data:blog.mobileClass' onload='prettyPrint()'>
  
  ...