PhantomJS not exiting for VSTS hosted builds

I wanted to use Karma to run some legacy AngularJS Jasmine 1.3 unit tests on a VSTS hosted build. There were two problems. First, the latest karma-jasmine wouldn’t work, because Jasmine 2.x no longer supports “runs” and “waitsFor”. The solution is to use karma-jasmine@0.1.0, which comes bundled with Jasmine 1.3. So that solved the problem of the Karma adapter for Jasmine. But which version of Karma corresponds to karma-jasmine@0.1.0? After some digging, we found that karma@0.12.37 works fine.

The second problem, which was far thornier, was that PhantomJS worked fine locally, but not on the VSTS hosted build. PhantomJS simply wouldn’t exit, which caused the build to time out. The solution is to check in phantomjs.exe into source control, and to create and check in a batch script. The batch script does two things: set the PHANTOMJS_BIN environment variable to point to that phantomjs.exe, and run Karma. The detailed steps are as follows:

  1. In a temp folder, run npm install phantomjs-prebuilt.
  2. Copy phantomjs\node_modules\phantomjs-prebuilt\lib\phantom\bin\phantomjs.exe from the temp folder to a folder under source control, and check it in.
  3. Create and check in a file named karma-runner.cmd that has the following contents:
@echo off
REM To run this in your local machine, set BUILD_SOURCESDIRECTORY=C:\path\to\git\repo\folder
%BUILD_SOURCESDIRECTORY%\path\to\.bin\karma start %BUILD_SOURCESDIRECTORY%\path\to\karma.conf.js
  1. In the VSTS build definition, add a step of type Batch Script that points to karma-runner.cmd.

10 October 2017 | Node.js | No Comments

The Monty Hall Problem, Enumerated

The Monty Hall problem is as follows:

You are a contestant in a game show. There are three doors. Behind one of the doors is a car; the other doors, each, a goat. The host asks you to choose a door. After you do so, the host will open one of the other two doors to reveal a goat, and allow you to stick to your choice, or to switch to the other unopened door. Which gives the higher probability to win the car?

It seems that there are a few ways to arrive at the answer, but none of them makes sense to me. In the end I got it by enumerating the only two winning possibilities:

  • Winning possibility #1 (WP1): I choose the car; the host shows me one of the two goats; I stick to my choice.
  • Winning possibility #2 (WP2): I choose a goat; the host shows me the remaining goat; I switch to the car.

For WP1, it is very clear that I have a 1/3 chance of winning the car by sticking to my first choice.

For WP2, I need to choose a goat, and then switch. The probability of choosing a goat is 2/3. Therefore, it is better for me to switch, because I have a higher chance of initially choosing a goat than the car. In other words, to ensure that switching is the winning move, I need to have initially chosen one of the goats; I have a 2/3 chance of initially choosing a goat; therefore I’m better off assuming that I had chosen a goat—which has a higher chance of being true—and then switch to what could only be the car.

Goat it?

15 July 2013 | Uncategorized | 1 Comment

Invoking a post-build batch file in TFS 2010

The scenario: you are using TFS 2010 as your build server, and you would like to deploy files to a remote server upon successful build by invoking a batch file.

Do note that the following steps work great in conjunction with Visual Studio T4 Templates, whereby multiple .config files (e.g. Web.Dev.config, Web.Test.config) can be generated from a master template to reflect different connection strings, etc. Oleg Sych has a nice write-up on this. Hint: hand-edit your .csproj file and use the DependentUpon element to keep your project view clean in Visual Studio—multiple .tt files can be nested under the main .tt file.

  1. Make a copy of DefaultTemplate.xaml and check it in. Let’s call it BatchFilePostBuild.xaml.
  2. Open BatchFilePostBuild.xaml in the designer and add 2 new Arguments:
    • BatchFile (Direction = In, Argument type = String, Default value = [blank])
    • BatchFileArguments (Direction = In, Argument type = String, Default value = [blank])
  3. Expand “Run On Agent”. Drag “InvokeProcess” from the Toolbox and place it after “Try Compile, Test, and Associate …”
  4. In the Properties pane for InvokeProcess:
    Property Value
    Arguments BatchFileArguments
    EnvironmentVariables New Dictionary(Of String, String) From {{"SourcesDirectory", SourcesDirectory}, {"BinariesDirectory", BinariesDirectory}}
    FileName BatchFile.Replace("$(SourceDir)", SourcesDirectory)
  5. Double-click InvokeProcess:
    • Drag “WriteBuildMessage” from the Toolbox and place it under stdOutput. Set Importance = High, Message = stdOutput.
    • Drag “WriteBuildWarning” from the Toolbox and place it under stdError. Set Message = stdError.
  6. Save and check in BatchFilePostBuild.xaml.
  7. In Team Explorer, create a new build definition, with its process template being BatchFilePostBuild.xaml.
  8. In the Process tab, there will be 2 properties under Misc:
    Property Value
    BatchFile Here you can specify the path and file name to your batch file relative to $(SourceDir). Refer to the folder structures in the Workspace tab.
    BatchFileArguments A list of arguments separated by spaces. In your batch file, they will be %1, %2, %3, and so on.
  9. Create and check in your batch file. In this batch file you will be able to refer to %SourcesDirectory% and %BinariesDirectory%, in addition to %1, %2, %3, etc. above. Assuming %1 is the environment type (e.g. “Test”) and %2 is the server name, here are some useful commands:
    Clean target folder del /s /q "\\%2\path\to\remote\folder\*"
    Copy directory structure xcopy "%BinariesDirectory%\path\to\folder\*" "\\%2\path\to\remote\folder" /s /y
    Copy Web.Test.config to the Test server copy /y "%BinariesDirectory%\_PublishedWebsites\MyProject\Web.%1.config" "\\%2\path\to\remote\folder\Web.config"
    Start remote Windows service sc \\%2 start "My Windows Service"
    Stop remote Windows service sc \\%2 stop "My Windows Service"
    Dirty wait for around 30 seconds ping -n 30 > NUL

4 June 2012 | .NET | 6 Comments

Exception-handling wrappers for Task.ContinueWith()

The .NET 4 Task Parallel Library is great because you can specify continuations for new threads:

private Task<WebResponse> GetWebResponseAsync(string url)
    var webRequest = WebRequest.Create(url);
    return Task.Factory.FromAsync<WebResponse>(

public void Run(string url)
        .ContinueWith(task => GetWebResponseAsync(url)).Unwrap()
        .ContinueWith(task => Console.WriteLine(task.Result.Headers))
        .ContinueWith(task => StopBusyIndicator());

Otherwise we’d have to handle the result of the async call either in callbacks or in event handlers—messy.

There are two caveats, though, when using Task.ContinueWith(). The first is that we have to sometimes use .Unwrap(). The second is that we have to handle exceptions in the next .ContinueWith(). Otherwise, our exceptions will just get swallowed.

So now:

public void Run(string url)
        .ContinueWith(task => GetWebResponseAsync(url)).Unwrap()
        .ContinueWith(task =>
            if (task.IsFaulted) // handle errors
            else Console.WriteLine(task.Result.Headers);
        .ContinueWith(task => StopBusyIndicator());

There goes our pretty code. Also, imagine the duplication if we do this for every .ContinueWith().

And so, inspired by Stephen Toub’s Processing Sequences of Asynchronous Operations with Tasks, I’ve written drop-in replacements for .ContinueWith() and .Unwrap() that will bubble up exceptions to a .Finally() extension method. Now our code can be clean again:

public void Run(string url)
        .Then(task => GetWebResponseAsync(url))
        .Then(task => Console.WriteLine(task.Result.Headers))
        .Finally(ExceptionHandler, StopBusyIndicator);

Do help yourself to the full source and example usage at github:gist.

28 May 2012 | .NET, C# | 3 Comments

Calling an Oracle function using NHibernate

  1. Tested with NHibernate 2.1.2 and Oracle 11g.
  2. Needs Oracle.DataAccess (not System.Data.OracleClient). Tested with Oracle.DataAccess AMD64.
  3. If your Oracle function returns a scalar value of datatype number, the .NET object will be a Decimal.

NHibernate config:

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <property name="connection.driver_class">

C# code:

var result = nhibernateSession
    .CreateSQLQuery("select GetSomeValue(:p_parameter1) from dual")
    .SetParameter("p_parameter1", parameter1)

// GetSomeValue returns a scalar of datatype number; result will be object of type Decimal

var someValue = Convert.ToInt32(result);

17 January 2012 | Uncategorized | No Comments