Sunday, May 13, 2012

Add support for LESS to Node.js connect-assetmanager package

The connect-assetmanager Node.js package allows you to combine multiple javascript and CSS files into one and also do other manipulations like minification.

It's part of Mathias Pettersson's (mape) excellent node-express-boilerplate template.

If you're also using LESS for CSS here is some code you can add to get connect-assetmanager to process you're LESS files:

var assetsSettings;
assetsSettings = {
  js: {
    route: /\/static\/js\/[a-z0-9]+\/.*\.js/,
    path: "./public/javascripts/",
    dataType: "javascript",
    files: ["libs/underscore-min.js" "libs/jquery.mobile-1.1.0.min.js", siteConf.uri + "/nowjs/now.js", "site.js"],
    debug: siteConf.debug,
    stale: !siteConf.debug
  },
  css: {
    route: /\/static\/css\/[a-z0-9]+\/.*\.css/,
    path: "./public/stylesheets/",
    dataType: "css",
    files: ["libs/jquery.mobile-1.1.0.min.css", "style.less"],
    debug: siteConf.debug,
    stale: !siteConf.debug,
    preManipulate: {
      "^": [
        function(file, path, index, isLast, callback) {
          var match;
          match = path.match(/\.less$/);
          if ((match != null) && match.length > 0) {
            return less.render(file, function(e, css) {
              return callback(css);
            });
          } else {
            return callback(file);
          }
        }
      ]
    }
  }
};

The import part is the preManipulate line under css but I include my entire assetsSettings from a project to make it easier to understand.

Tuesday, May 1, 2012

MonoTouch JsBridge - Communicate with the UIWebView

Today I'm open sourcing JsBridge for MonoTouch which allows for bidirectional communication between the javascript in your UIWebViews and your native C# code in your MonoTouch app. Go directly to GitHub for the documentation on how to use it.

This project was inspired by doing a project using Appcelerator's Titanium. In fact the javascript used in JsBridge was taken directly from that project, so if you're used to using Titanium you should be right at home using JsBridge.

At this time it requires MonoTouch 5.3.3, which as of 5/1/2012 is in Alpha, because JsBridge needs to register a custom url protocol using NSUrlProtocol.

I'm not 100% satisfied with the implementation of the event listeners on the native side, so I'm open to suggestions on how to make it better. Ideally some day the Xamarin team will implement something like this in a future version. ;)

I've already submitted my first app to use it the iOS AppStore and it relies heavily on bidirectional communication between javascript and native. The app is a remote control for Rdio's new UI. A nicely executed feature by Rdio (even if it came way after the chrome extension remote I made for their first UI ;) ), but unfortunately it doesn't work on iOS partially due to the Rdio servers not supporting the Websockets protocol that the UIWebView has. Using JsBridge I was able to implement the WebSocket connection on the native side and override the Rdio javascript calls that use WebSockets and pass them to the native side and vice versa. I'm quite pleased with the results so far. ;)

Wednesday, March 28, 2012

Solved: Video.Js Playback Error in IE9

TL;DR:

Make sure your server (including Amazon CloudFront) is setting the correct mime type when returning the video file.

For .mp4 files the mime type should be video/mp4

ISSUE:

I spent about an hour baffled why IE9 wouldn't play an H.264 video that Chrome and Firefox played fine.

The only lead I had was this message output by Video.js using console.log:

Video Error[object Object] 

What's more annoying is that IE9 doesn't let you inspect objects that are output by console.log. To get around that you can install the Firebug Lite bookmarklet. Unfortunately in this case the object doesn't give you much more to go on.

I tried swapping videos and found it worked with the sample Video.js video, which usually indicates a mime type issue (which seems to be a recurring issue with Microsoft products).

I was using Amazon CloudFront to server the videos (download style as opposed to streaming) and figured I couldn't set the mime type but it turns out you can:
  1. Go into S3 and find your video file.
  2. Right click and select Properties
  3. Select the Metadata tab
  4. In this case, set KeyContent-Type and Value = video/mp4
  5. Press Save button

Wednesday, February 29, 2012

MonoTouch.Dialog UIPicker

In iOS a UIPicker looks like this:

I'm working on an iPhone application that's built using MonoTouch.Dialog and after a full day of trying to get the MonoTouch.Dialog compatible Picker in ClanceyLib to work, I've decided to package up my work and release it on GitHub.

The main issues with ClanceyLib is that it requires a heavily modified and out of date version of MonoTouch.Dialog. If you try to compile it with the built-in version of MonoTouch.Dialog you'll get the following two errors:

/Users/guivho/Mono/ClanceyLib/ClanceysLib/MT.D/ButtonElement.cs(49,49):
Error CS0115: `ClanceysLib.ButtonElement.GetCell(MonoTouch.Dialog.DialogViewController,
MonoTouch.UIKit.UITableView)' is marked as an override but no suitable
method found to override (CS0115) (ClanceysLib)


/Users/guivho/Mono/ClanceyLib/ClanceysLib/MT.D/ComboBoxElement.cs(49,49):
Error CS0115: `ClanceysLib.ComboBoxElement.GetCell(MonoTouch.Dialog.DialogViewController,
MonoTouch.UIKit.UITableView)' is marked as an override but no suitable
method found to override (CS0115) (ClanceysLib)


Ripping out the elements you need from ClanceyLib wasn't as easy as I hoped on the first try but I now have it working along with some other improvements:
  • Updated it to hide the keyboard or picker when selecting different cells to edit.
  • Changed so the Items in the Picker list are UIView's for greater customization.
  • Actually has a sample of how to use it. ;)
UPDATE 3/1/2012: It works out of the box with the version of MonoTouch.Dialog that is now packaged with MonoTouch. But, it will not dismiss the picker when selecting a different cell. To enable that feature it requires a custom version of MonoTouch.Dialog and you'll need to comment in 3 lines of code in PickerElement.cs.

I sent a pull request to get my minor change to MonoTouch.Dialog included in the core. If/when it's pulled I will update PickerElement.cs to take advantage of it and the dependency on the custom version of MonoTouch.Dialog will be no more. ;)

Thursday, February 9, 2012

setTimeout Setting Mysterious Callback Parameters

I got burned by this twice in the last month.

Say you want to call the following function after 5 seconds.
function doSomething(optionalParam) {
  // check if optional param passed in.
  if (optionalParam) {
    optionalParam.foo(); // this is where the error sometimes happens.
  }
  // do more stuff.
}

// delay 5 seconds.
setTimeout(doSomething, 5000);

Periodically I was getting undefined errors when trying to call foo(). After some googling, it turns out Gecko browsers have setTimeout pass back an extra parameter indicating the "actual lateness" of the timeout in milliseconds.
https://developer.mozilla.org/en/DOM/window.setTimeout

I haven't run into this with other browsers but to avoid the issue it's best to do the following when your callback functions have optional params (Not having optional params would obviously be even safer).
// delay 5 seconds.
setTimeout(function() {
  doSomething();
}, 5000);

Tuesday, October 25, 2011

Using Siri For Home Automation

I've created a Twilio, Node.js mash up that allows me to control appliances and the thermostat in my house using the iPhone 4S's Siri voice recognition.

Here's a demo of turning on my bedroom fan.



How does this work? From Siri to the end result the chain goes:
  1. Siri 
  2. Twilio SMS number
  3. Node web application
  4. Indigo Web Server
  5. Insteon thermostat/appliance

Let's go through the setup in reverse order in more detail.


Insteon and Indigo

I purchased the following items last year from Amazon to add some basic home automation to my house.

I have a Mac Mini I use as a server which is connected to the PowerLinc Modem via USB. The Indigo software communicates two-way with the Insteon devices in my home via the PowerLinc. In addition to a native iPhone app, the Indigo software has both a web interface and RESTful Api you can use to control your devices.


Node.js Web Application

The Node.js application is the middle man between Twilio and the Indigo web server. When Twilio POSTs the incoming SMS message to the Node app, it parses the message and determines the appropriate Api call to make on the Indigo web server. I wrote some semi-fuzzy logic so the phrases you use don't have to be exact.

For hosting the Node app I picked Heroku because it's convenient to use and free.


Twilio

Setting up Twilio was super easy. I created a Twilio account, purchased a phone number for $1/month, and entered the Url of my Node app that receives the incoming SMS messages.


Siri

To make communicating with my Twilio phone number easy I added a contact called "Gladys" (could be anything but I'm a Portal fan) and associated the Twilio number with her.

I can now control my appliances using the following commands:
  • Tell Gladys to set thermostat to 73
  • Tell Gladys to turn off the bedroom fan


I originally wanted to turn this into a public Siri to Url web service, but I question the demand for such a thing considering trying to make this "generic" would take a lot of time. So if you're interested in adding Siri control to your own use case and don't have programming skills, I'm available for hire and can whip you up something to suite your exact needs. ;)

UPDATE 10/28/2011:
Big thanks to technabob for the coverage! He brought up a good point though, this could easily be faked. Here's a screen shot of my Heroku logs with debugging output on the left and Node.js code for the "fuzzy logic" on the right. Not indisputable evidence but I assure you it's working exactly like it does in the video. ;)

Sunday, October 16, 2011

Windows 7 Registry Entry to Search All File Contents

If you do a search in Windows 7 you may notice that it didn't find some files that you know contain the search terms you are looking for.
This is due to the What to search setting in Windows Explorer under Folder Options -> Search as pictured below.


If you don't have Always search file names and contents selected Windows will only search the files it has indexed.

You can change the setting using the UI as shown above but you can also set it by changing the following Registry setting (which is useful if you want to programmatically set if for users):

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Search\PrimaryProperties\UnindexedLocations]

"SearchOnly"=dword:00000000

Originally I tried to change the following key based on Scott Forsyth's solution for Windows XP and Windows Server 2003 but it didn't work for me on Windows 7:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ContentIndex]

"FilterFilesWithUnknownExtensions"=dword:00000001


As a bonus tip, this is how I found where the Windows 7 registry key was.
  1. Open Registry Editor
  2. Right click the registry hive you suspect the setting to be in (usually either HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE) and select Export and save the .reg file (ex: hklm1.reg)
  3. Change the setting via normal means.
  4. Repeat steps 2 and 3 and save the file with a new name (ex: hklm2.reg).
  5. Use a Diff tool such as the one include with Tortoise SVN or Tortoise Git to search for changes.