Monday, December 02, 2013

Massively Parallel Compute as a Service

Back in the Spring of 2012, I asked several panelists at VMWorld to weigh in on vector processing with GPUs as a big data/big compute solution. The response was a resounding "not yet," as the infrastructure has not yet reached commodity level and GPU processing was greatly constrained by memory paging. It now seems like both obstacles are being removed.

Amazon Web Services is now offering EC2 instances that offer up virtualized instances of NVIDIA's Kepler GPUs as "G2" instances. This supports H.264 encoding, OpenCL, CUDA and OpenGL toolsets which allows for more mature toolsets to build apps targeted to these vector processing instances. This kind of support allows for commodity toolchains and commodity infrastructure to allow for massively parallel processing on demand.

Memory paging should soon be addressed by NVIDIA via CUDA 6, and should also be addressed by AMD with its upcoming Kaveri architecture. Once memory addressing is unified, the swapping of memory regions should become unnecessary and allow for memory to be addressed locally without pagination. This simplifies application development, virtualization and hardware architectures considerably.

I believe that very soon we will see vector processing at scale garner as much attention as map/reduce clusters currently do. Massive data parsing has been commoditized, and now we have an opportunity to commoditize massive algorithmic crunching.

Sunday, November 03, 2013

Retrospective: The Raspberry Pi Garage Door Remote + Security System

My rinky-dinky garage security system is now online and in operational use. I still have more tweaks to do - for example, I got rid of the metal backplane within the My Book casing that now serves as my board enclosure because it shielded my WiFi signal, killing the network connection. I'm sure I will continue to tweak the Motion configs to increase framerates and decrease sensitivity. Now that e-mail notifications are working, hopefully I can limit the spurious notifications and just notify on the bigger changes of motion over two seconds in length.

Another measure of success is cost; if I could have purchased a ready-made setup for a marginal increase in cost, it may be better to go with a commercial platform. If the build is overkill and I could have built it with cheaper components, I should scrap this and re-build. Looking at commercial options I couldn't find anything that had both the garage door functionality and the security camera... just one or the other. Chamberlain does sell the MyQ Garage, a pretty nifty home automation product that contains a universal garage door opener and a tilt sensor that is WiFi-enabled and can be paired with a smartphone app. They also sell the MyQ Internet Connectivity Kit, which is more of an Internet-enabled garage door master controller. Neither have a security camera paired with it, but you could easily install a wireless camera separately for around $40. The MyQ solutions are $140 and $120 respectively, giving you a total build cost of $160-$180. Not bad, really.

If you bought every part new, the build list for my lil' setup is:
Raspberry Pi B $40
USB Micro-B cable $2
USB AC Adapter $5
8GB Class10 SD Card $8
802.11n USB dongle $9
Parts for MOSFET switch $5
Universal garage door opener $25
HP HD-3100 webcam $14
Enclosure made of random stuff $0
Total $108

I had most of these parts on-hand, so my actual cost was closer to $70. That means a savings of $90 over a commercial solution. I don't know of a cheaper solution than the Raspberry Pi that could handle a 1280x720 webcam feed and perform motion detection, and a $14 webcam is cheaper than Raspberry Pi's own camera expansion card.

Of course, your time isn't free. The hours spent in construction count - so I tried to estimate how long each step took me:
Tearing down & wiring up garage remote 1 hour
Setting up webcam and Motion 2 hours
Configuring OS & system administration 4 hours
Building web interface 3 hours
Building enclosure 2 hours

All told maybe 12 hours of work, a quarter of which was me figuring out how to render an MJPEG stream on an HTML5 canvas. The web interface can be re-used, as are the system administration steps, so I could probably do another in four hours or so. Four hours and $70 isn't too bad for peace of mind.

Speaking of ease of mind, I'll leave this thread with an ad for Chamberlain's MyQ Garage. I thought I was bad... but these actors have turned garage door anxiety into an existential crisis.

Friday, November 01, 2013

Shutting the Door; Finishing Up the Raspberry Pi Security Camera + Garage Opener Remote

I'm going to be tinkering with this new security camera / Internet-enabled garage door opener for some time... I imagine I'll add environmental monitoring and perhaps even hook it up to the sprinkler system. Even with future expansion in mind, I needed to shield the Raspberry Pi and the remote control board from dust and stray water. The mini protoboard I would likely keep as opposed to soldering a more permanent board, since I wanted the ability to dork around with the GPIO pins that have pull-down resistors built in and possibly add additional controls.

I had an old Western Digital My Book sitting around with a defunct hard drive, and it appeared to be nearly the right size to house the Raspberry Pi, the garage remote board and a mini breadboard. I decided to gut it and use the housing as an enclosure. I found a few motherboard standoffs in my toolbox, and uses those to keep both boards a few centimeters off of the metal backplate. The drive and controller itself I shelved.

Once I had everything stripped apart, the garage remote was mounted on one side of the board and the Raspberry Pi was mounted on the other. It was a tight fit, but I was able to get the webcam plugged in, the mini breadboard slid in and all the wiring completed within the confines of an old My Book chassis. Using a very technical device I call a "hacksaw," I removed some of the side wall of the enclosure so I could pull out the micro-usb cable for power and bring the webcam so it can be positioned independently.

In the end everything didn't quite fit... the garage remote is bursting out of its seam. However the general look of the device is far better than it was before. The unit is now back sitting on a shelf in the garage, quite content.

I still have some continued tweaks to do, but I think I've now addressed the root question: "is the garage door up?"

Thursday, October 31, 2013

Who Moved My Barn Door?

I really need to stop it with the "Barn Door" titles.

So I now have wired a Raspberry Pi to a garage door remote, created a primitive web interface for it, and attempted some security and stabilization for the supporting applications. Now I am moving on to sending an e-mail with photo attachments of security events that have occurred.

Setting up the mail server within the Ubuntu distribution was a bit of a pain. The Pi can't act as an MTA all on its own thanks to all the relay rules in place across the Interwebs, so instead I had the default exim4 installation route through GMail. I wasn't interested in installing yet another outbound mail system; I would rather leverage what comes packaged by default. I ensured I deployed an application-specific password for exim4, then followed the very helpful instructions from Debian on how to hook it all up with GMail as the outbound SMTP relay.

The default mailutils will not send attachments over e-mail, so instead I installed mutt for a command-line mail client. I can issue e-mails via:
echo "Motion was detected" | mutt -s "Garage Security System" -a /srv/motion/23-20131030184606-00.avi -- somedude@gmail.egg

Once combined with Motion's External Commands, I can build scripts that e-mail off movie files as soon as they end. The mpeg4 format appears to work natively within Android, so video snippets are easy to view once they are e-mailed out.

Now for some polish; I need to construct/find an enclosure and finish the front-end user interface.

Wednesday, October 30, 2013

Your Barn Door is On Display

After I buttressed the Pi as best as I could, I constructed a simple webapp to allow users to view the security cam feed and activate the button on the garage remote. It was surprisingly straight-forward to render an MJPEG feed on an HTML5 canvas, but it took a bit more doings to expose GPIO as a minimal REST call.

Before I could deploy the webapp a few additional packages needed to be deployed for Python to access everything:
  1. Installed python-distribute so we can use Python's easy_install
  2. Installed pip using easy_install (how meta) so we can easily install application dependencies
  3. Installed libapache2-mod-wsgi to permit Apache to act as a Python application server
  4. Cloned the GarageSecurity repository, which includes the Bottle webapp and some admin configs/scripts
  5. Installed GarageSecurity's dependencies using pip install -r pip_requirements.txt
  6. Allowed www-data to access the GPIO port using the WiringPi utility

One big condition I held was that the webapp should not be granted root access, even if it was indirect access with a setuid script. The WiringPi utilities allow one to create GPIO devices handles that can be accessed by an unprivileged user such as www-data. By adding an entry within /etc/rc.local for the WiringPi utility the devices will be created on boot for use by a user within the gpio group. The WiringPi Python libraries then use these devices to control the GPIO pins. This took a few hours of experimentation, and a huge amount of thanks go to Sebastian Ă–sterlund's WiringPi post for helping me figure this out.

One could use a REST framework such as WebIOPi to expose GPIO access over a REST interface, but it looked like this implementation needed privilaged access and the webapp didn't require 99% of the features that WebIOPi ships with. Instead, I leveraged Bottle to expose the WiringPi library as a REST call, which permits a client-side application to issue a remote call and active the garage door remote.

The MJPEG stream provided by Motion for the camera was only bound to the localhost interface, however I proxied it through Apache for external exposure. Multipart MJPEG streams are not directly supported by many browsers anymore; instead it is fairly straightforward exercise to have JavaScript functions fetch the stream and then paint the images directly onto an HTML5 canvas. This surprisingly just took eight lines of JavaScript to accomplish; it took me more time to figure out how to scale the viewport and a button for mobile devices than it took to render the webcam feed.

I know I'm definitely not early to the garage door hacking scene - there are several other projects using Arduino with mobile front-ends, some adapted to use the Raspberry Pi with relays, others with wireless interfaces and mobile webapps. I'm a bit partial to this approach because it has a fairly low part count (one resistor, one MOSFET, some wire, a mini breadboard, one universal garage door remote, a cheap webcam and a Raspberry Pi), it doesn't use relays and the web application does not require privilaged access to low-level resources.

Feel free to check out the evolving webapp - it is now managed under GitHub at I will continue tweaking it a bit and eventually fitting it with some sort of user interface, but I also want to move along and use Motion's External Commands to e-mail me whenever it detects motion. Unfortunately HP's HD-3110 has an auto-focus that keeps kicking on and registering as a motion event, so I might dig deeper to see how to disable the feature. Of course I still need an enclosure as well... right now bare wire and board are just sitting out on a shelf. One stray squirt gun and all is lost.

Tuesday, October 29, 2013

Your Barn Door is Off Its Hinges

I was a bit hasty when I said the next step in building the garage door security camera was constructing a web interface. As any good DevOps guy should know, getting the administrative portions of the host in stable shape is really the next step. I needed to deal with disk space issues, data retention, security and properly setting timezones.

The majority of my tweakings are being recorded within GitHub's GarageSecurity admin folder until I refactor that away. This folder includes config files and modifications that reflect the steps that I took to lock things down, including:
  1. Set the timezone to be local instead of UTC
  2. Build and enforce firewall rules
  3. Ensure that Motion's HTTP Configuration endpoints are disabled
  4. Hide the webcam's MJPEG stream behind an Apache2 proxy
  5. Allow Samba/Apache2 to list the recordings on the LAN
  6. Use an NFS mount instead of local storage for recordings (instead of using a 64 GB compact flash card, use a 2 TB NAS drive
  7. Create a crontab entry to compress & archive yesterday's recordings
  8. Allow userlevel (not root) access to Raspberry Pi's GPIO pins

The timezone issue is more a matter of personal taste. I would rather the time on the server reflect local time, since I will be looking at file timestamps quite frequently. Others may fall in love with UTC. Or Swatch Internet time. Whatever floats your boat. I did notice that tzselect does not appear to persist across reboots; instead I had to use dpkg-reconfigure tzdata.

The primary goal was to secure access to the webcam feed and disallow unauthorized access. Since this is an Ubuntu distribution, I used the Uncomplicated Firewall to only permit traffic across HTTP and SSH ports. This would close the default webcam and control ports that could be exposed by Motion, as well as other running services. The control endpoints were not needed for my purposes, and I'd rather not assume the risk of arbitrary file access. I still wanted to have access to the MJPEG feed coming from Motion... however I wanted the ability to lock it down. In order to provide more granular security controls I proxed the 8081 webcam port from Motion behind Apache2's mod_proxy, where I could define whatever controls I liked within the Apache VirtualHost. Likewise I allowed authenticated users to view the list of recordings using Apache's directory index module so that archived images and recordings could be easily accessed.

Once Motion was appropriately locked down, I moved on to dealing with file storage and archival. Instead of writing to the local SD card, I decided to make an NFS4 mount to a NAS server on the LAN. The amount of file I/O could easily be delt with over 802.11n, and the SAN could also assume the duties of archiving/compressing the files on a daily basis. This keeps the number of files on the mount much lower, allows for greater storage and doesn't wear out the SD card nearly as much. One catch was that the mount was occurring over a wireless interface, so an attempt to mount the filesystem too early would cause the boot process to lock up. I worked around this by using the mount options soft,bg,timeo=14,intr to decrease the operation timeout and allow for retries in the background. By the time the boot processes is complete, a retry operation should be able to successfully mount the drive.

The final security point is one that will be of much greater use once the web interface is written. The RPi.GPIO libraries write to /dev/mem, which means they need root access to work. Rather than grant scripts root access to /dev/mem (which is horrible practice), I enlisted the help of Gordon Henderson's WiringPi project. There are two parts to this implementation: one is the GPIO utility that helps create userspace devices for GPIO control, and the other is the Python library that can access these devices. I created an entry in rc.local that creates a device for GPIO17 in output mode that is accessible by www-data, which in turn can be accessed within a Python script running as the www-data user.

The security is definitely not exhaustive, but it's a solid start to get things rolling. From here I should be able to deploy a web application that exists as the sole entry point for the garage security system, and access controls can be entirely managed through Apache. A rogue user should hopefully be contained within the scope of the www-data user.

Friday, October 25, 2013

Your Barn Door is Closed

I added the security camera functionality to the Raspberry Pi I've been working on, using an inexpensive HP Webcam HD-3110 and the Motion subsystem. Both worked out of the box using the Raspberry Pi and the default (but upgraded to latest) NOOBS installation. Neither had an issue, and I was up and running with a security camera quickly. Another nice thing about Motion is that it exposes several external commands as a means to provide API exposure... so I can integrate a web application or send an e-mail at the start of an event. It would be great to send an e-mail whenever motion is detected, and send the video or photos related to the event.

Once the security camera was working and stable, I added back in the GPIO garage door opener remote that I hacked together. Working together, I now have a security system for the garage that can open and close the garage door from any vantage point. I deployed it up on a shelf, next to the windshield wiper fluid, where the webcam would have a nice perch.

I whipped together a quick Python script that would briefly engage the GPIO pin on the Raspberry Pi, so now I can sit at my laptop and watch the garage door go up and down. Ultimately I will place this feature behind a web application for ease of use. The Python support for Raspberry Pi seems to be a first-class citizen, so I might use Bottle to create a minimalist webapp for exposing the webcam feed and garage door controls.

I still need to build an enclosure... and perhaps upgrade the camera to one without an infrared filter and an array of IR LEDs. The web interface will be the next thing on the docket however.

Tuesday, October 22, 2013

Your Barn Door is Open

One compulsive behavior I can't seem to shake is the fear that I have left the garage door open. I count the squares on the front, I measure the light and shadows, I obsess. To tell the truth, even if I had a magic device that would send me a message every time the garage door opened or shut, I wouldn't trust it. I have to see it.

To feed my neurosis, I began working on a combo surveillance camera / garage door controller with an Internet interface. The first thing I attempted to get working was the method of opening the garage door; up to this point it seems like most efforts have been using a relay to close the switch of the hard-wired "big button" for the garage door opener. I wanted to have the freedom to place the device anywhere I wish, not unlike the garage door keypad that comes with most openers now. A spare Chamberlain universal remote was just sitting in my garage, so I decided to shuck it and rip out the logic board within.

The board actually had a fairly nice layout and a hidden third button. I only needed one button... and a way to trigger it without a physical press. Using a complicated tool called a "screwdriver-like thingee" I pried the physical button off, leaving nothing but the leads behind.

Instead of sharp metal prongs, I got the ole' trusty soldering iron out and melted the solder enough to pull the leads out. I replaced two of the leads with pins for easy breadboarding.

I have a weird affinity towards MOSFETs. I'm not entirely sure why. I have a feeling that my affinity to using a MOSFET instead of a relay is similar to most people's opinions on using an Arduino instead of a Raspberry Pi. With such snobbery in mind, I prototyped out a circuit that would use an N-channel MOSFET to close the circuit instead of a switch.

Bear in mind I paid no attention in 6.002x, so my circuit has less to do with elegance and common sense as it did with "let's slap together a MOSFET and pull down resistor." Still, sending the 2.2V from a GPIO pin into the MOSFET's gate pin allows the circuit to close on the garage door opener, sending the door up and down.

Next up is adding a surveillance to the Raspberry Pi using a USB camera I found lying around. The plan is to try out the Motion subsystem, then adapt things as needed. One particular enhancement I'm keeping my eye on is the Raspberry Pi Infrared Camera, which I might pair with a set of IR LED's and a fisheye lens. Doing so may require some patching of Motion, but should otherwise be straightforward.

Thursday, August 15, 2013

My Electric Slide

I love Hack a Day. I've never actually constructed a featured project, but the site has always been a fantastic read to see what's top on the minds of the hacker front. One particular Hack a Day review caught my eye - "a light following bristlebot as a way to teach science." What I found particularly interesting was how well the build instructions were documented on the Science Buddies site. The background was descriptive without being verbose, the parts were easy to come by from both Fry's & SparkFun, and the component count was nice 'n' low. I wasn't sure if the kids would enjoy it, but I knew that at least I would.

Now bear in mind I attempted to take MIT's 6.002x class before my brain took an enormous sidetrack and instead ended up with a comparative analysis with Stanford's Coursera. While I did find out what a high-voltage pickle looked like, my understanding of Thevenin voltage is limited to indecipherable algebra illustrating the "Thin Mint voltage" of a circuit. I generally don't know what I'm doing, and exploding diodes are not a rare occurrence. It took me considerable research before coming to understand what the three pins of a MOSFET are responsible for. To this day I cannot quite grasp why a pull-down resistor is required for normal operation (even when there is no "bad wiring"). I need simple, otherwise something is going to end up charred and melted.

The project went much better than expected. I performed some initial prototyping to make sure it was easy to teach the kids, and things went surprisingly well out of the gate. We ended up sticking with the project far longer than I expected, and even added our own enhancements to boot. We're now on build #4 and going strong. Directional control is actually quite good, and there was enough room for minor tweaks and improvements on the breadboard.

Conveniently enough, when I placed my initial SparkFun order I also slipped in a Raspberry Pi - Model B as well. In the spirit of teaching electronics while remaining completely selfish, I justified the purchase by teaching Python programming using Minecraft while experimenting with GPIO programming on the sly. I was able to have moderate success teaching Python; I constructed a small lesson plan using Martin O'Hanlon's API tutorial as a reference. That turned into a good weekend software development lesson, however I didn't get as much traction with that project as I did with the bristlebots. Luckily for my ulterior motives, I now had a general purpose postcard computer for more breadboard projects. Several tiny wires later, I was able to get a Python script to blink an LED on a breadboard. Between vibrating toothbrush heads and a $40 miniscule flashing light, I started to brainstorm bigger things.

Now I'm getting back into 6.002x - Circuits & Electronics and starting over again. I'm much more engaged given this new context - and will likely take the class MUCH slower than the real-time course would otherwise allow. Should be fun.

Saturday, February 23, 2013

The Standing Sloth

I returned to work after Thanksgiving last year, sat down at my desk and felt... absolutely gross. There was stuffing in my veins, broccoli cheese casserole in my gut and I could feel my flesh slowly molding around my office chair. The previous summer the Internets were all the rage about the famous infographic detailing how "Sitting is Killing You," and sites such as Lifehacker were consistently running stories of people constructing their own standing desks. I decided enough was enough and decided to try the standing desk thing.

The desk I was using at the time was huge, solid and immobile - a single and secured wooden boat in a 10' by 6' L-shape. There was no freaking way I could elevate it to standing height. At first I thought I would just build something roughly hewn from 2x4's but instead I noticed a blocky, simple accent table at Target. Worst case I thought I could saw off the legs to height.

In addition I had found an older storage ottoman sitting in my garage with a half-broken lid. It was quite nearly the same height as the two accent tables, so I thought I might see if it was of any use as well.

I placed both tables and the ottoman side-by-side on top of the desk. To my surprise the tables were the perfect height for a keyboard, mouse, monitor and a laptop riser. My arms were bent at a 90 degree angle, the top of my monitors were at eye level and I could shift my weight around to avoid locking my knees. For the first two weeks I alternated between sitting and standing... but soon I was standing 6 hours a day.

Here we are, over a year later. The only alteration I have made has been a comfort floor mat to stand on, and then only because I moved to a cement floor. I must admit that people mocked me for a good while... people kept coming into my office asking "what are you doing? Do you really stand all day? Really? REALLY?" And yes, co-workers sitting adjacent to me were treated to being eye-level with my butt all day.

People eventually got accustomed to me standing and even became interested in converting to a standing desk as well. A nice side effect is that it is easier to have conversations with people who walk over... no longer do I have to stare up their nose while someone asks questions from above. I lost (and kept off) ten pounds, which is nice. No more lower back problems either, which may have less to do with standing and more to do with me sitting like an crooked monkey.

Not bad for around $100, half of which was a nice standing mat. All I needed was busted furniture from home, tables made for a college dorm room and a laptop stand.

Thursday, February 21, 2013

Re-Examining Development Platforms

I've been granted an opportunity for perspective lately. I've done my best to steer away from .NET development up until recently - not because I had any particular gripes, but the technology platform just never seemed to be a great fit. C# as a language is pretty great... delegates, tail closure and nullable references are a welcome respite. VisualStudio isn't bad. If you judge IDEs by how many times they make you swear in a given workday, I'd say my four-letter word tally is comparable to that of me using Eclipse. In fact, once my development environment was up and running I thought I might grow to enjoy .NET development.

And then I started to use the foundation classes. First off... I'll acknowledge that no platform has ever been able to get dates and times "right." This is ever more apparent with .NET... who for some inexplicable reason have no real sense of this "epoch" thing that EVERY OTHER PLATFORM USES. Milliseconds since year zero are expressed as... integers? On top of that, time span arithmetic is only accurate when math is done using "ticks," which themselves are not really accurate to 1/10000 of a millisecond. I didn't go for the caesium clock upgrade in my current laptop.

Java developers often complain that anonymous classes are inelegant or verbose within Java. C# has abandoned anonymous classes in lieu of their delegate-based event handling system. However, C# developers exposed to anonymous inner classes actually seem to like them. A common gripe actually turns out to be a nifty feature when you're talking about event handling. The C#/.NET event handling mechanism isn't that fantastic... it's largely just a loose convention for using delegates. No extras or nice GoF listener patterns provided like a PropertyChangeListener.

Zooming out from design patterns and looking at .NET from an enterprise integration pattern perspective, the .NET platform is definitely at a major disadvantage when compared to JVM-based platforms. I've already covered the state of .NET integration frameworks but to recap: it's still nearly five years behind. My time with EasyNetQ has been great, but I still find myself wishing I could use Apache Camel to construct bigger things using common EIP components.

Despite the current rant, I've been fairly complacent with my new development platform. What really stirred things back up for me was when I cracked open the JMeter-Rabbit-AMQP plugin so that I could do RPC-based load testing of EasyNetQ services. Being a JMeter extension, JMeter-Rabbit-AMQP was a Java app that required me to fire up NetBeans once again and do some Java hacking. Once I did... damn. Until I made that sudden switch back I didn't see the huge gap that existed between .NET and Java development. While C# has some advantage over the Java language, the JVM platform is still leaps ahead.

Once you begin talking about instrumentation the gap grows even wider. I have grown accustomed to the fantastic introspection and profiling offered by Java Management Extensions and VisualVM; by contrast Microsoft's laughable implementation of Performance Counters has caused me more problems than it has solved. If it works (and it often doesn't due to permissions issues or outright registry corruption) there is no instrumentation that allows for live modification of managed objects or details on garbage collection. The actual .NET API to create and maintain performance counters is actually not bad, but the Performance Counter UI is so clunky and ill-conceived that it is often difficult to make use of it.

In the end... it doesn't matter. You do the best you can with the tenured development stack because ultimately it's not about the underlying technology - it's about the squishy, business-logicy brain inside of it. Keeping that squishy brain... err... braining is the most important thing.

Wednesday, January 30, 2013

Enjoying Walled Gardens

For the fourteen years prior prior to last June I had consistently used some variation of a Dell laptop with Linux - initially RedHat but quickly switching over to SuSE. Occasionally I would dual-boot into Windows to do some gaming, but all of my work and development was done within KDE. I really had no desire to change, even when I was lugging a 12-pound behemoth Precision laptop with openSUSE and Windows 7. Muscle strain aside, I was content with the setup.

The next job I moved to was going to be a switch from my conventional Java development to .NET, so I decided to take the opportunity to change up my workstation as well. I moved away from Wintendo/Linux and moved wholesale into OS X, since my new position delightfully coincided with the release of the latest MacBook Pro’s. Gone was my comfortable NetBeans environment, and instead I had to use VisualStudio within Parallels. No more Linux... and at the time I was confident I would hate OS X and re-build the laptop with KDE 4.

That was eight months ago.

The .NET ecosystem hasn't been fantastic... immersion has not worked in its favor there. The move to OS X has been considerably more pleasant. By and large OS X is still *nix at its heart and ports abound. Even my favorite photo management / digital darkrooom Digikam works within OS X. I haven't really been missing any apps as of yet other than Pidgin. Yeah, there's Adium... but... meh.

The ease of use is much greater as well. The application-based firewall works well, instant messaging integration works (albeit without OTR support), calendaring and mail integration works without issue. By and large things work without any futzing. This is doubly true with the rest of the family; while my attempts to get the household at large on openSUSE + KDE 4 failed miserably, the hand-me-down OS X workstations we've been reusing have been adopted with great enthusiasm. All walks of life have been happy to use 4+ year old iMacs with Snow Leopard, no complaints.

Apple's lustre has been slowly seeping away with the stylish kids of today, but it's hard to deny they've built a solid platform. Yes, it does this by sacrificing your freedom of choice and reducing your hardware upgrade paths. But for now... the walled garden is a damn nice place to just chill out and get some work done.