How to change the font size in Chrome Developer Tools

When presenting on JavaScript or jQuery I’ll typically spend a lot of time in the Chrome Developer Tools window at the console. The problem is that, depending on the projection facilities and the resolution the fonts can be too small to read.

The Chrome devtools themselves are built out of HTML and CSS so I started digging for how I could edit the stylesheet. You can view the default devtool stylesheet by navigating to chrome-devtools://devtools/devTools.css. You can’t easily edit this though (it’s probably buried as a resource within Chrome), but you can override its styles using the standard custom user stylesheet Custom.css!

Custom.css lives at:

  • Windows: C:Users<user>AppDataLocalGoogleChromeUser DataDefaultUser StyleSheets
  • Mac OS X: ~/Library/Application Support/Google/Chrome/Default/User Stylesheets/

The style(s) to add and override in Custom.css are:

body.platform-mac .monospace, body.platform-mac .source-code {
    font-family: Monaco, monospace;
}

/* Keep .platform-mac to make the rule more specific than the general one above. */
body.platform-mac.platform-mac-snowleopard .monospace,
body.platform-mac.platform-mac-snowleopard .source-code {
    font-size: 11px !important;
    font-family: Menlo, monospace;
}

body.platform-windows .monospace, body.platform-windows .source-code {
    font-size: 12px !important;
    font-family: Consolas, Lucida Console, monospace;
}

body.platform-linux .monospace, body.platform-linux .source-code {
    font-size: 11px !important;
    font-family: dejavu sans mono, monospace;
}

A nice touch is that the styles update automatically as you save Custom.css so you can tweak it on the fly to get the right font-size for your audience.

Chrome DevTools with a larger font-size

Hope that helps!

LESS + CoffeeScript for ASP.NET = LessCoffee

As documented in recent posts, I’ve been tinkering getting the LESS and CoffeeScript compilers running on Windows Script Host. I’ve now got round to wrapping these up as ASP.NET HTTP Handlers so you can easily use them in ASP.NET-based websites. You simply reference the *.less and *.coffee files and they get served up as CSS and JavaScript directly. For example:

<link href="content/style.less" rel="stylesheet">
<script src="content/site.coffee"></script>

No need to install add-ins into Visual Studio or add build steps to your project. The main downside is that it won’t run on non-Windows platforms under Mono (although I’m tempted adapt it to use Mozilla’s SpiderMonkey JavaScript Shell).

If you’re running Visual Studio 2010 then simply use the LessCoffee NuGet package.

PM> Install-Package LessCoffee

If you’re using Visual Studio 2008 you’ll need follow these manual steps:

  • Copy LessCoffee.dll to your web application’s /bin directory
  • Add the following entries to your web.config file:
    <system.web>
        <httpHandlers>
            <add path="*.coffee" type="DotSmart.CoffeeScriptHandler, LessCoffee" verb="*" validate="false"/>
            <add path="*.less" type="DotSmart.LessCssHandler, LessCoffee" verb="*" validate="false"/>
        </httpHandlers>
    </system.web>

    <!-- IIS 7 -->
    <system.webServer>
        <validation validateIntegratedModeConfiguration="false"/>
        <handlers>
            <add path="*.coffee" type="DotSmart.CoffeeScriptHandler, LessCoffee" verb="*" name="DotSmart.CoffeeScriptHandler"/>
            <add path="*.less" type="DotSmart.LessCssHandler, LessCoffee" verb="*" name="DotSmart.LessCssHandler"/>
        </handlers>
    </system.webServer>

If you’re using Windows 2003/IIS 6 then you will need to map the file extensions *.less and *.coffee to aspnet_isapi.dll.

The source is on GitHub, obv: https://github.com/duncansmart/LessCoffee

The simplest way to compile CoffeeScript on Windows

tl;dr: You can compile CoffeeScript on Windows with zero third-party dependencies.

A while back I did a post on running the LESS.js compiler on Windows using the venerable and ubiquitous Window Script Host (WSH: providing JavaScript console scripting since Windows 98… when John Resig was still in 8th grade). At the time I tried something similar to generate JavaScript from the wonderful CoffeeScript language, but I couldn’t get it working due to what I assumed were shortcomings in WSH’s JScript engine. There are plenty of other options out there for compiling CoffeeScript, but incur various third-party dependencies as detailed in this StackOverflow question.

But on a whim the other day I revisited it and thankfully now it does work on plain old WSH without any coaxing (not sure what changed, or what I was doing wrong last time). I took the full browser-based coffee-script.js and wrapped it with a simple *.wsf and batch file to handle command-line options.

Download

It’s on github, natch: https://github.com/duncansmart/coffeescript-windows

Usage

To use it, invoke coffee.cmd like so:

coffee input.coffee output.js

You can also pipe to and from it if you are so inclined via stdin/out. Errors are written to stderr.

In the test directory there’s a version of the standard CoffeeScript tests which can be kicked off using test.cmd. Note that the test just attempts to compile the standard set of  *.coffee test files but doesn’t execute them.

Hope it helps; comments appreciated!

First steps with IronJS 0.2

With the release of IronJS 0.2, the code below is the result of a 30-minute play I had this morning, which shows how easy it is to embed a fully .NET JavaScript runtime in your application by simply referencing IronJS.dll.

It’s changed quite a from prior versions and I think you’ll see it has become much easier to host since  Dan Newcombe’s experiments last year.

//reference IronJS.dll
using System;
using System.IO;

class IronJsDoodles
{
    static void Simple()
    {
        var context = new IronJS.Hosting.CSharp.Context();
        object result = context.Execute("1 + 2;");

        Console.WriteLine("{0} ({1})", result, result.GetType());
        // "3 (System.Double)"
    }

    static void InteractingWithGlobal()
    {
        var context = new IronJS.Hosting.CSharp.Context();

        context.SetGlobal("a", 1d);
        context.SetGlobal("b", 2d);
        context.Execute("foo = a + b;");

        double foo = context.GetGlobalAs<double>("foo");

        Console.WriteLine(foo);
        // "3"
    }

    static void AddingHostFunctions()
    {
        var context = new IronJS.Hosting.CSharp.Context();

        // Effectively the same as context.CreatePrintFunction() 🙂
        var print = IronJS.Native.Utils.createHostFunction<Action<string>>(context.Environment,
            delegate(string str)
            {
                Console.WriteLine(str);
            });
        context.SetGlobal("print", print);

        context.Execute("print('Hello IronJS!')");
    }
}

Hope it helps you get started.

Chrome Extension: Amazon UK Search and Switch

I created a very simple Google Chrome extension that:

  • Allows you to search Amazon UK with a right-click
  • Switch back and forth between the UK and US versions of a page

Install it from the Chrome Extensions site.

The latter feature I find myself using all the time. If you follow, say, a book recommendation link to the .com site, but you want to buy  it on the .co.uk site. Alternatively, you may be reading a handful of reviews on the UK site, but over on the US site, there are lots more. When you’re on the Amazon.co.uk/.com site a “page action” icon will appear which, when clicked, will simply replace the amazon.co.uk in the URL with amazon.com or vice-versa.

It was incredibly simple to create. (It took longer to create the icons than write the code!) Extensions are essentially web pages that run in the background and have access to an API for interacting with Chrome: e.g. chrome.contextMenus, chrome.tabs, etc

For example: the search menu was created like so:

chrome.contextMenus.create({
    title: "Search Amazon.co.uk for '%s'",
    contexts:["selection"],
    onclick: function (info, tab) {
        var query = info.selectionText;
        chrome.tabs.create({
            selected: true,
            url: 'http://www.amazon.co.uk/s/ref=nb_sb_noss?url=search-alias%3Daps&amp;field-keywords=' + encodeURIComponent(query)
        });
    }
});

To look at the rest of the source go to the install page, right click the Install button, save the CRX file and unzip it.

In future, I may add an options page so it’s not hard-coded for the UK/US sites and to selectively enable/disable the features.

Hope you find it as useful as I do.

Running the Less.js command-line compiler on Windows

There have been some interesting developments recently in the field of CSS pre-processors. CSS pre-processors work around the very limited syntax of CSS by allowing you to create your stylesheets using a more powerful, expressive syntax which then gets turned into plain CSS for consumption by all the main browsers. A couple of ones that I’ve come across are SASS and LESS. LESS is the one I’ve felt most comfortable with because it’s simply an augmentation of the CSS which allows you to incrementally introduce its syntax into your stylesheets.

For example LESS supports variables:

@brand_color: #4D926F;
#header {
   color: @brand_color;
}
h2 {
   color: @brand_color;
}

nested rules:

#header {
  color: red;
  a {
    font-weight: bold;
  }
}

…mixins, operations on colors and size, etc. Check out the  lesscss.org homepage for more.

LESS was originally a Ruby gem, but now also has implementations on ASP.NET (dotlesscss.org) and PHP. LESS has now (inevitably) been re-implemented in JavaScript by Alexis Sellier (github.com/cloudhead/less.js). As well as supporting pre-processing *.less files into *.css via the command-line, it can also be actually run live, directly in your browser!

<link rel="stylesheet/less" href="stylesheets/main.less" type="text/css" />
<script src="script/less-1.0.38.min.js"></script>

I’m not sure I’m quite ready to take the plunge running it live, in-browser on sites just yet, although maybe I shouldn’t be according to Dmitry Fadeyev:

Wouldn’t live processing lag? Not really. Two reasons for this. One: Less.js has been written from the ground up for great performance, so even browsers with poor JavaScript implementation should still run it very well (Less.js is about 40 times faster than the Ruby implementation—so suffice to say it’s a lot faster.). Two: On modern browsers that support HTML5, Less.js will cache the generated CSS on local storage, making subsequent page loads as fast as pure CSS.

Running on Windows

The command-line compiler lessc is targeted to *nix-based platforms and requires node.js which, the last time I checked, doesn’t run on Windows (UPDATE: it runs fine under Cygwin, there’s a nice simple standalone version here). But Windows has had the ability to run JavaScript directly since the 1990’s using Windows Script Host. So I took the latest distribution copy of less.js from GitHub at https://github.com/cloudhead/less.js/tree/master/dist/ and included it via a *.wsf file and stubbed/faked/implemented a few things like window, document and XMLHttpRequest that less.js assumes will be present (which are presumably provided by node.js?), and added a bit of command-line argument handling.

Download

Browse the code and download from GitHubhttps://github.com/duncansmart/less.js-windows and feel free to fork it and send me pull requests!

Usage

To use it, invoke lessc.wsf via cscript.exe like so:

cscript //nologo lessc.wsf input.less [output.css] [-compress] 

I’ve also added a less.cmd shim which will simplify it to just:

lessc input.less [output.css] [-compress] 

If you don’t specify an output.css the result is written to standard output. The -compress option minifies the output. I’ll look into implementing the other command-line arguments supported by lessc in due course.

I’ve added a couple of test files, so you can see if it’s working like so:

C:codelessc-wsh>lessc test.less
/* Variables */
#header {
  color: #4d926f;
}
h2 {
  color: #4d926f;
}
/* Mixins */
#header {
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  border-radius: 5px;
}
...

Future

I may look into hooking this into Visual Studio’s T4 support so that the *.css files are generated as soon as you save the *.less files in Visual Studio. (UPDATE: See Phil Haack’s T4CSS that does this, instead using  the .NET port of LESS. Thanks to David De Sloovere for pointing this out.)

Update

Mark Lagendijk has created a nice little Windows GUI for the script. Check it out at http://winless.org.

Follow @duncansmart on Twitter

Fixing “Provider: Unspecified error” when querying LDAP with the ADsDSOObject OLEDB Provider

As part of our logon script we have a Windows Script Host script that was failing with “Provider: Unspecified error” (mmn, helpful) but only on some Windows XP machines.

The offending line of code looked like this:

rs = con.Execute("<LDAP://DC=example,DC=com>; (sAMAccountName="+ username +"); ADsPath; subTree")

After some trial and error the fix was this (see if you can spot the difference):

rs = con.Execute("<LDAP://DC=example,DC=com>;(sAMAccountName="+ username +");ADsPath;subTree")

Can you see what it is? No spaces after the semicolons!

Alternatively the SQL-like syntax also seems to be a bit more forgiving:

rs = con.Execute("SELECT ADsPath FROM 'LDAP://DC=example,DC=com' WHERE sAMAccountName='"+ username +"'")

It appears that with some later version of ADSI ADsDSOObject (or to give it its full title, the “OLE DB Provider for Microsoft Directory Services”) the query syntax strictness has been relaxed. In any case “Unspecifed error” appears to mean “Syntax error” in this case.

Setting Google Chrome as the default browser for Adobe AIR apps

UPDATE: Logan Buesching commented to say that Chrome apparently creates “ChromeHTML” shellopen keys except they’re in HKCR (which is why you get a UAC prompt, it’s the machine part of the registry), so you can actually just set HKCUSoftwareClasses.htm to ChromeHTML and you’re done. Logan also goes into more detail as to what’s going on so check out his post.

It seems odd that they end up creating a global HKCR key which ulitimately points to an app that’s installed in a user’s private profile. I’m sure this will cause issues if you have multiple people using your machine. Anyway, I guess this is all a bit moot: this is beta software kids, and I’m sure Google will fix this in due course by release and you may have to undo some of these registry shenanigans for it to work as expected.

Google Chrome was a big hit in the office today. To the extent that many of my colleagues were setting it as their default browser already, even though it’s a beta product. Cwazy.

Unfortunately even if you do click the “Make Google Chrome my default browser” button on the Options page, not all applications that launch hyperlinks comply. One of those is the Twitter client Twhirl, which is an Adobe AIR application (I’m assuming this is an issue with AIR itself rather than Twhirl doing something silly). I deduced what AIR was doing when trying to locate the default browser by using Sysinternals’ Process Monitor (ProcMon). It was using the current user’s “.htm” file association preference: which on my machine was pointing to FirefoxHTML. So I created a new registry key for GoogleChromeHTML that specified the location of chrome.exe as the file opener and pointed the “.htm” setting there, which did the trick.

To make this easier to replicate, and to save having to write tedious explanatory steps detailing exactly what to do – I’ve created a short JScript Windows Script file.

Save the following with a “*.js” file extension (e.g. ChromeDefaultForAIR.js) and run it:

var wshell = new ActiveXObject('WScript.Shell');
var chromePath = wshell.ExpandEnvironmentStrings('%USERPROFILE%\Local Settings\Application Data\Google\Chrome\Application\chrome.exe');
wshell.RegWrite('HKCU\Software\Classes\.htm\',
   'GoogleChromeHTML');
wshell.RegWrite('HKCU\Software\Classes\GoogleChromeHTML\shell\open\command\',
    '"' + chromePath + '" "%1"');

Normal caveats for editing your registry and downloading and running random scripts from some idiot’s blog apply. To revert, set HKCUSoftwareClasses.htm back to FirefoxHTML.

If it helps leave a note in the comments!

Backing up an Exchange Mailbox to a PST file

I’ve never trusted Exchange Server backup 100% ever since Exchange 2000, following a service pack, refused to restore backups from the non-service packed version (yes honestly).

So I’ve always had a 2-pronged approach to backup, do the usual monolithic backup using NTBackup, but also have mailboxes individually backed up as plain old PST files, which Outlook can easily mount to make it easier to do partial restores. In the past I’ve used ExMerge to do this, but it’s a becoming a bit neglected and is very clunky to script: it’s a Windows app (rather than a console app) that’s driven by an INI file.

Anyway, whilst doing some integration work against Exchange for a client I came across Dmitry Streblechenko’s superb Redemption Data Objects library. It is a really easy to use COM wrapper around Extended MAPI – a super-charged version of Collaboration Data Objects (CDO).

Honestly I really can’t understand why Microsoft didn’t ship a library like this (or improve CDO) rather than expecting you to write gnarly C++/COM/MAPI code to do what this library allows you to do easily from .NET code or a script. The Exchange API goalposts move from one release to the next: “Use the M: drive! No, use WebDAV! No, use ExOLEDB!… No, use Web Services!” with the only constant being good old MAPI.

Anyway – here’s part of our PST backup script – it relies on the Redemption Data Objects (RDO) COM DLL being registered. The free developer version pops up a prompt once when you RegSvr32 it, the royalty-free redistributable version is a incredibly reasonable $199.99. RDO relies on MAPI being installed, so grab it here if it’s not present on your system.

/* BackupPst.js */

// e.g. copyMailboxToPst(
           "EXCH01",
           "FredB",
           "c:\backups\fredb.pst",
           "FredB backup")

function copyMailboxToPst(serverName, userName, pstFile, pstName)
{
  var session = new ActiveXObject("Redemption.RDOSession");
  session.LogonExchangeMailbox(userName, serverName);
  WScript.Echo("Logged on to " + session.ExchangeMailboxServerName);

  var mailbox =  session.Stores.DefaultStore;
  var pstStore = session.Stores.AddPSTStore(pstFile, 1, pstName);

  try
  {
    WScript.Echo("Opened " + mailbox.IPMRootFolder.FolderPath);
  }
  catch(err)
  {
    WScript.Echo("Error opening mailbox '" + userName
       + "' (access denied?). " + err.description);
    return;
  }

  foreach(mailbox.IPMRootFolder.Folders, function(folder)
  {
    WScript.Echo(" * " + folder.Name);
    folder.CopyTo(pstStore.IPMRootFolder);
  });

  pstStore.Remove();
}

// Utility to allow enumeration of COM collections
function foreach(collection, fn)
{
  for(var e = new Enumerator(collection); !e.atEnd(); e.moveNext())
  {
    if(fn(e.item()))
      break;
  }
}

This could be further improved for incremental backups by using RDO’s newly introduced wrappers to the “Incremental Change Synchronization” API where you can use the same syncing technology that Outlook’s cached Exchange mode uses!

Draytek Vigor 2800 reboot script

After years of great service, our Draytek Vigor 2800 seems to be having problems after running for a few days of allowing HTTPS in to our network, which is only solved by rebooting the router. For the life of me I can’t upgrade the firmware using either the TFTP or FTP approach. So giving up, I’ve adopted the brute force approach of scheduling a reboot every night. To do this I considered scripting the appropriate Telnet commands to the router, but that would involve some custom or third party code. (Telnet, being a duplex protocol means you can’t simply pipe commands to telnet.exe from a batch file, you have to use something like expect to script a Telnet session.)

The simplest, lowest-tech approach (and they’re always the best, right?) I found was merely to mimic the reboot page on the router web management UI with the following Windows Scripting Host script:

////// RebootRouter.js ////////
// Change these for your environment
var ROUTER_IP = "192.168.0.1";
var ROUTER_USER = "admin";
var ROUTER_PASSWORD = "pA55w0rd";

var http = new ActiveXObject("Microsoft.XMLHTTP");
http.open("POST", "http://" + ROUTER_IP
    + "/cgi-bin/reboot.cgi", false,
    ROUTER_USER, ROUTER_PASSWORD);
http.setRequestHeader("Content-Type",
    "application/x-www-form-urlencoded");
http.send("sReboot=Current&submit=OK");

// For debugging/logging un-comment the following lines:
// WScript.Echo(http.status + " " + http.statusText);
// WScript.Echo(http.responseText);

Save this as RebootRouter.js, update the values accordingly and schedule for a appropriate time using Control Panel > Scheduled Tasks.