Tue
Jul 28
2009

Resharper Shortcuts

A few custom shortcuts because I can never remember which Resharper command they are…

Alt-N: ReSharper.ReSharper_UnitTest_ContextRun
Ctrl-Alt-T: ReSharper.ReSharper_ShowUnitTestExplorer
Ctrl-Alt-R: ReSharper.ReSharper_ShowUnitTestSessions
Ctrl-Alt-E: ReSharper.ReSharper_UnitTest_RunCurrentSession

Visual Studio macro for resetting these bindings:

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports System.Diagnostics
 
Public Module Module1
 
    Public Sub BindShortcuts()
        Bind("ReSharper.ReSharper_UnitTest_ContextRun", "Alt+n")
        Bind("ReSharper.ReSharper_ShowUnitTestExplorer", "Ctrl+Alt+T")
        Bind("ReSharper.ReSharper_ShowUnitTestSessions", "Ctrl+Alt+R")
        Bind("ReSharper.ReSharper_UnitTest_RunCurrentSession", "Ctrl+Alt+E")
        Bind("File.CloseAllButThis", "Ctrl+Alt+Shift+W")
        MsgBox("Done.")
    End Sub
 
    Private Sub Bind(ByVal commandName As String, ByVal globalBinding As String)
        Dim command As Command
        command = DTE.Commands.Item(commandName, 1)
        command.Bindings = "Global::" & globalBinding
    End Sub
 
End Module
Mon
Jan 26
2009

EvoLisa Video

Here is a video of Roger Alsing’s EvoLisa project evolving an image of the Mona Lisa using random polygons.

The video was made using Roger’s source code modified with Dan Bystrom’s FitnessCalculator written in assembler. The program was changed to output a frame whenever the image improves by 5%. The program was run for 16 hours to generate the 660 frames used in the video below. The final image uses 242 polygons (average 6.9 points per polygon) and is the 7,052,061th generation. It only took 48 seconds to generate the first half of this video and the remaining 16 hours to generate the second half.

I used VirtualDub to combine the frames into a video. The music clip is Company I from Philip Glass.

By the way, Vimeo kicks butt on YouTube – higher quality videos and a better interface for uploading/managing videos.

Sun
Jan 25
2009

Anti-Virus Software is Useless

Over the holidays I was infected with multiple viruses. One them was Trojan.Vundo.GCY. It’s job is to download other viruses and malware. I had over a dozen files infected with various viruses causing popups and network slowdown.

I tried 6 or 7 anti-virus / anti-malware products and found they had abysmally low detection rates. The best only finding 30% of infected files. This included software from Symantec Online Security Scan, Eset Nod32 Online Scanner, BitDefender Free Edition, AVG Free Edition, Spyware Doctor from the Google Pack, Malware Byte’s Anti-Malware and Ad-Aware Free.

Perhaps using installed, retail versions would have given better results but I doubt it. All of the companies claim the free/online scanners use the same core engine and virus definitions as their retail products. I suspect this is true as it looks like these companies are competing on features like email integration, phishing protection and real-time scanning. I ran these scans from a fresh, uninfected install so its unlikely that any viruses were actively attempting to hide from a scan.

As a result, I won’t be purchasing anti-virus software in the near future. I will keep AVG Free for quick scanning of files I believe are already clean. That statement shows how little confidence I have in these scanners. Despite this I think they are still good for catching the older viruses propagating among completely unprotected machines.

I did find a useful website: VirusTotal.com lets you upload a file and scan it with almost 50 scanners. Here is an here is an example report). They also have a small utility you can install to get a right-click -> Send To target. You are limited to scanning one file at a time though can you can upload a zip archive to scan several. There are a number of similar websites, but VirusTotal appears to be the best.

My anti-virus/malware strategy:

  • Use AVG Free for quick scanning of files I believe are already clean.
  • Turn off real-time scanning – it’s not worth the performance hit for such low detection rates.
  • Use VirusTotal for scanning suspicious files.
  • Use Chrome and respect the malware warnings.

To recover from an infection:

  • Unplug infected drive.
  • Reinstall Windows on a new drive.
  • Reattached infected drive.
  • Install a virus/malware scanner. Run full/deep scan. Repeat a minimum of 3 times or until you stop finding infections.
  • Copy data from old drive and reformat.

How do you prevent infections?

Fri
Nov 7
2008

Zebra striping

From the article Zebra Striping: Does it Really Help?:

- no difference in speed or accuracy
- 46% preferred it, 33% didn’t care

If you are going to use zebra striping, keep it subtle.

Update: a followup post with more research confirming this approach.

Thu
Nov 6
2008

User Interface Design for Programmers

From Joel Spolsky’s article User Interface Design for Programmers:

- A user interface is well-designed when the program behaves exactly how the user thought it would.
- Don’t provide options unless the user really wants to choose
- Use real-world metaphors
- Affordances
- Consistency with existing standards (good or bad)
- Users don’t read manuals
- Users don’t read anything (make text concise)
- Users can’t control the mouse very well (large click targets)
- Users can’t remember anything

Wed
Apr 30
2008

Upgrading to WordPress 2.5 on BlueHost

WordPress 2.5 was released last month. Why can’t we upgrade using Fantastico? It turns out BlueHost has started their own Fanastico competitor called SimpleScripts. I doubt we’ll be seeing any new Fantastico updates. While Fantastico has had WordPress 2.5 scripts for at least three weeks, BlueHost’s tech support claims they are waiting on Fantastico to release updated scripts. This is the first problem.

The second problem is the recommended migration procedure here and here. It involves FTP clients and pulling database configuration bits from php files. This does not leave a good first impression of a product that is supposed to provide one-click installation and upgrades.

I ended up using the Wordpress Automatic Upgrader Plugin. I still needed to use an FTP client to install the plugin but now I am not dependent on Fanastico or SimpleScripts. This plugin downloads the latest files directly from WordPress so updates should be available as soon as WordPress releases them. I encountered two problems while upgrading to 2.5:

  • The plugin created backups but provided the wrong link to download them. I had to use the FTP client to download them manually. I believe this is because I have installed WordPress into a wordpress\ subfolder rather than into the root.
  • The plugin did not reactivate my plugins. I had to reactivate them manually.

On the positive side, SimpleScripts appears to be a more polished product compared to Fantastico.

Sun
Apr 6
2008

Canon Elph on Steroids

The open source project CHDK has built firmware enhancements for many of Canon’s compact cameras. Some features:

- RAW support
- Extra fast/slow shutter speeds
- In-camera scripting language
- DOF calculator
- AutoISO based on focal length
- Exposure bracketing
- Live histogram
- Highlight clipping indicators
- Detailed battery level indicator
- Teathered shooting
- Loads from SD card on power-up (no permanent changes to firmware)

Some first impressions… The UI is organized but far from user friendly. Lightroom cannot open the RAW files. At high shutter speeds the flash power was too high and there was no flash compensation. I ended up holding a white envelope in front of the flash. I tried taking some high speed photos with the new firmware on my Canon SD500. The best photo was taken with the stock firmware. The high speed shutter wasn’t needed for this shot – the focus and timing were more important. These photos were taken in daylight with no additional lighting beyond the flash.

Canon SD500 with CHDK (1/4000s)
Water drops with SD500 and CHDK firmware (1/4000)

Canon SD500 (1/60s)
Water drops with Point and Shoot

Nikon D40 (1/500s)
Water drops with SLR

I think I will keep it on my camera for the extra information on the display and the scripting. A few links: installing, download, usage, more usage info

Fri
Mar 28
2008

Processing

A friend told me I needed to write more blog posts. I’m not sure if he was interested in what I have to say or just didn’t want to link to a dead blog. Either way I will put down a few more posts!

Take a look at the work from Robert Hodgin at flight404.com. He is using Processing, a programming language created for experimenting with computer graphics. At the core of these images and videos is a model following simple rules of physics (e.g. two positively charged particles will move away from each other) that is affected by the music (e.g. particle size increases with volume). The final image or video isn’t designed, it is the result of programming these rules and letting the model play itself out.

Magnetic Ink
Magnetic Ink

Magnetic, process video

Solar (high definition version, alternate version with lyrics)

Fri
Aug 3
2007

Global exception handling

Some general notes on exception handling:

  • Setup a global exception handler to catch and handle unexpected exceptions.
  • Only catch exceptions where you can take more intelligent action than the global exception handler.
  • Be careful with exceptions on any thread other than the main thread (spawned threads, asynchronous delegates, timers, etc…)
    • In .NET 1.1, the CLR eats any exceptions, killing the thread but allowing your app to continue.
    • In .NET 2.0, unhandled exceptions take down the entire appdomain (more info).

In ASP.NET
1. Add the following to global.asax:

void Application_Error(object sender, EventArgs e) 
{
    Exception ex = Server.GetLastError();
    if (ex is System.Web.HttpUnhandledException)
    {
       ex = ex.InnerException;
    }
    LogHelper.Log.Error("Unhandled exception", ex);
    Server.Transfer("~/Error.aspx");
}

2. Create an Error.aspx page:
Use Server.GetLastError() to retrieve the exception.
Ensure the exception is logged in global.asax in case the Server.Transfer() fails.
Do not display the exception to the user to prevent hackers from gleaning information.

3. If you are using Forms Authentication, add the following to your web.config. It ensures unauthenticated users can see the Error.aspx page in case an error occurs during logon/logoff. You should do the same for any images and stylesheets as well.

<configuration>
	<location path="Error.aspx">
		<system.web>
			<authorization>
				<allow users="?"/>
			</authorization>
		</system.web>
	</location>
</configuration>

4. If you are using AJAX, you have to add an event handler on every page (are there any better solutions?):

protected void ScriptManager1_AsyncPostBackError(object sender, AsyncPostBackErrorEventArgs e)
{
    LogHelper.Log.Error("Unhandled exception during asyncpostback", e.Exception);
    ScriptManager1.AsyncPostBackErrorMessage = 
        "An unexpected error occured. Please try again or contact the Help Desk.";
}

ASP.NET Web Services
The Global.Application_Error does not fire in a web service.

using System;
using System.Web.Services.Protocols;
using TDR.Common.Utility;
 
namespace MySolution.MyProject.SoapExtensions
{
    public class LoggingSoapExtension : SoapExtension
    {
        public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
        {
            return null;
        }
 
        public override object GetInitializer(Type serviceType)
        {
            return null;
        }
 
        public override void Initialize(object initializer)
        {
        }
 
        public override void ProcessMessage(SoapMessage message)
        {
            if (message.Stage == SoapMessageStage.AfterSerialize)
            {
                if (message.Exception != null)
                {
                    LogManager.Log.Error(message.Exception.Message, message.Exception);
                }
            }
        }
    }
}

2. Add this to your web.config:

<system.web>
    <webServices>
        <soapExtensionTypes>
            <add type="MySolution.MyProject.SoapExtensions.LoggingSoapExtension,MySolution" priority="1" group="1" />
        </soapExtensionTypes>
    </webServices>
</system.web>

Note: SoapExtensions are not called when invoking the a webservice from the built-in test webpage.

WinForms, Console Apps and Services
1. Hook into the domain’s unhandled exception event:

static void Main()
{
    AppDomain.CurrentDomain.UnhandledException +=
        new UnhandledExceptionEventHandler(
            CurrentDomain_UnhandledException);
}
 
/// <summary>
/// Log unhandled exceptions that occur anywhere in the appdomain.
/// </summary>
static void CurrentDomain_UnhandledException(object sender, 
                                     UnhandledExceptionEventArgs e)
{
    try 
    {
 
        LogHelper.Log.Error("Unhandled exception.", 
                   e.ExceptionObject as Exception); 
    }
    catch { }
}
Fri
Aug 3
2007

MSBuild Automated Deploy Scripts for Web Applications

These are suggested steps for creating batch scripts that will deploy a solution to DEV, TEST and PROD. If this article looks like it is more complicated than it should be, I agree. I think batch scripts with an XML read/write utility or NAnt would be a better choice:

  • The syntax for batch files and NAnt are both easier to read/understand
  • NAnt allows custom tasks can be written in C# directly in the build file. MSBuild requires a separate assembly (and associated solution and project files).
  • The big advantage with MSBuild is it it built-in. However this advantage is eliminated as we need to use the MSBuildCommunityTasks DLL to read/write config files.

Here is the MyApp.build file:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 <!--
       MY WEB APPLICATION DEPLOY SCRIPT
 
       To deploy this application use the batch files DeployToXXX.bat
 -->
 <Import Project="..\..\Utilities\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
 
 <PropertyGroup>
 
   <TempFolder>..\..\_tempfolder</TempFolder>
   <DevFolder>\\mydevserver\wwwroot\myapp</DevFolder>
   <TestFolder>\\mytestserver\wwwroot\myapp</TestFolder>
 
 </PropertyGroup>
 
 
 
 <Target Name="DeployToDev">
 
   <AspNetCompiler
       VirtualPath="MyApp"
       PhysicalPath="..\ "
       TargetPath="$(TempFolder)"
       Clean="true"
       Force="true"
       Debug="false"
       Updateable="false" />
 
   <XmlRead XmlFileName="$(TempFolder)\web.config"
            XPath="/configuration/appSettings/add[@key='DEV.Log4NetConnectionString']/@value">
     <Output TaskParameter="Value" PropertyName="Log4NetConnectionString"/>
   </XmlRead>
 
   <XmlUpdate XmlFileName="$(TempFolder)\web.config"
              XPath="/configuration/appSettings/add[@key='Environment']/@value"
              Value="DEV" />
 
   <XmlUpdate XmlFileName="$(TempFolder)\web.config"
              XPath="/configuration/log4net/appender[@type='log4net.Appender.ADONetAppender']/connectionString/@value"
              Value="$(Log4NetConnectionString)" />
 
   <XmlUpdate XmlFileName="$(TempFolder)\web.config"
              XPath="/configuration/system.web/compilation/@debug"
              Value="false" />
 
   <CreateItem
       Include="$(DevFolder)\**\*"
     <Output TaskParameter="Include" ItemName="FilesToCleanFromTarget" />
   </CreateItem>
 
   <Delete Files="@(FilesToCleanFromTarget)" />
 
   <CreateItem
     Include="$(TempFolder)\**\*"
     Exclude="$(TempFolder)\Deploy\*">
     <Output TaskParameter="Include" ItemName="FilesToDeploy"/>
   </CreateItem>
 
   <Copy SourceFiles="@(FilesToDeploy)"
         DestinationFiles="@(FilesToDeploy->'$(DevFolder)\%(RecursiveDir)%(Filename)%(Extension)')"
   />
 
   <RemoveDir Directories="$(TempFolder)" />
 
 </Target>
 
 
 
 <Target Name="DeployToTest">
 
   <CreateItem
       Include="$(DevFolder)\**\*"
       Exclude="$(DevFolder)\Deploy\*">
     <Output TaskParameter="Include" ItemName="FilesToDeploy"/>
   </CreateItem>
 
   <Copy SourceFiles="@(FilesToDeploy)"
         DestinationFiles="@(FilesToDeploy->'$(TestFolder)\%(RecursiveDir)%(Filename)%(Extension)')" />
 
   <XmlRead XmlFileName="$(TestFolder)\web.config"
            XPath="/configuration/appSettings/add[@key='TEST.Log4NetConnectionString']/@value">
     <Output TaskParameter="Value" PropertyName="Log4NetConnectionString"/>
   </XmlRead>
 
   <XmlUpdate XmlFileName="$(TestFolder)\web.config"
              XPath="/configuration/appSettings/add[@key='Environment']/@value"
              Value="TEST" />
 
   <XmlUpdate XmlFileName="$(TestFolder)\web.config"
              XPath="/configuration/log4net/appender[@type='log4net.Appender.ADONetAppender']/connectionString/@value"
              Value="$(Log4NetConnectionString)" />
 
   <XmlUpdate XmlFileName="$(TestFolder)\web.config"
              XPath="/configuration/system.web/compilation/@debug"
              Value="false" />
 
 </Target>
 
 
 
 <Target Name="DeployToProd">
 
   <Copy SourceFiles="$(TestFolder)\web.config"
         DestinationFiles="$(TestFolder)\Web.config.test" />
 
   <XmlRead XmlFileName="$(TestFolder)\web.config"
            XPath="/configuration/appSettings/add[@key='PROD.Log4NetConnectionString']/@value">
     <Output TaskParameter="Value" PropertyName="Log4NetConnectionString"/>
   </XmlRead>
 
   <XmlUpdate XmlFileName="$(TestFolder)\web.config"
              XPath="/configuration/appSettings/add[@key='Environment']/@value"
              Value="PROD" />
 
   <XmlUpdate XmlFileName="$(TestFolder)\web.config"
              XPath="/configuration/log4net/appender[@type='log4net.Appender.ADONetAppender']/connectionString/@value"
              Value="$(Log4NetConnectionString)" />
 
   <XmlUpdate XmlFileName="$(TestFolder)\web.config"
              XPath="/configuration/system.web/compilation/@debug"
              Value="false" />
 
   <Prompt Text="Please ask the production administrator to copy MyApp from test to production. Press Enter when complete."/>
 
   <Copy SourceFiles="$(TestFolder)\Web.config.test"
         DestinationFiles="$(TestFolder)\Web.config" />
   <Delete Files="$(TestFolder)\Web.config.test" />
 
 </Target>
 
</Project>

Then to run use the following batch script:

@echo off
echo.
echo --------------------------------------------------
echo.
echo   Deploy the Application to Dev
echo.
echo   Ensure you have retrieved the latest version
echo   from source control.
echo.
echo --------------------------------------------------
echo.
 
call "%VS80COMNTOOLS%\vsvars32.bat" 
 
set MSBuildCommunityTasksPath=..\..\Utilities\MSBuildCommunityTasks
 
msbuild deploy.build /target:DeployToDev
 
pause

This requires the MSBuildCommunityTasks DLLs. Download, install, copy the DLLs to your project directory under Utilities, checkin to VSS and then uninstall. Placing the DLLs in VSS ensures subsequent developers can use the project without hacking their way through a bunch of dependencies.

Older Posts »

© 2009 Brian Low. All rights reserved.