Showing posts with label tools. Show all posts
Showing posts with label tools. Show all posts

Thursday, March 06, 2008

How to Extract Video Still Frames with MPlayer

While working on a video content management system, I was in need of capturing frames from video files so they can be used as a preview for video. The system already had some code in place but it only worked for video encoding in Windows Media format (.wmv extension). That would not do, I thought, not in this day and age when we have so many file formats and video codecs. So I need to able to:

  1. Capture video frames from within .NET code
  2. Capture images from all kinds of different video formats
  3. Not reinvent the wheel while satisfying #1 and #2

Enter MPlayer

Stolen directly from the Information page of MPlayer, "MPlayer is a movie player which runs on many systems (see the documentation). It plays most MPEG/VOB, AVI, Ogg/OGM, VIVO, ASF/WMA/WMV, QT/MOV/MP4, RealMedia, Matroska, NUT, NuppelVideo, FLI, YUV4MPEG, FILM, RoQ, PVA files, supported by many native, XAnim, and Win32 DLL codecs. You can watch VideoCD, SVCD, DVD, 3ivx, DivX 3/4/5 and even WMV movies..". To add my own description, MPlayer is an open source command line video player.

So What

Metallica has an old song called "So What", great tune for the metal heads in all of us. The answer is simple, MPlayer can do a lot more than play video. It can capture images, stream video over http and even transcode video from one format to another (but the last feature is grounds for another article).

Putting It Together

You will need:

Setup

  1. Extract the mPlayer executable (mplayer.exe)
  2. Extract the mPlayer codecs in a directory called "codecs" in the same directory as the mPlayer executable
  3. Add a reference to the mPlayerWrapper project or compiled DLL

Usage

  • Capture with default arguments

    in C#
    // Specify the path to the video file
    string videoFilePath = @"drive letter:\path\to\myVideo.mpg";
    // Declare the mplayer instance with the mplayer executable residing in the
    // same directory as your executable
    mPlayerWrapper mPlayerInstance = new mPlayerWrapper();
    // Capture frames
    mPlayerInstance.captureFrames(videoFilePath);
    

    in VB.NET
    ' Specify the path to the video file
    dim videoFilePath As String = "drive letter:\path\to\myVideo.mpg"
    ' Declare the mplayer instance with the mplayer executable residing in the
    ' same directory as your executable
    dim mPlayerInstance As new mPlayerWrapper()
    ' Capture frames
    mPlayerInstance.captureFrames(videoFilePath)
    

    This will capture 12 frames with 5 second interval between each frame and put them in the same directory as your video file. The filename of each frame will be "myVideo_thumb01.jpg" to "myVideo_thumb12.jpg". Each frame will be scaled to 270x200.
  • Capture arguments
    • mPlayerPath - sets the path where the mPlayer executable (mplayer.exe) is located. The default is in the same directory as your code is executing.
    • currentFilePath - sets the file path to the video file you are using
    • cleanOutputDirectory - deletes all the "jpg" images in the capture output directory before capturing
    • captureInterval - sets the interval at which frames will be captured. Only applicable if using a time interval capture method (as outlined below)
    • numberOfFramesToCapture - the number of frames to be captured
    • captureExactNumberOfFrames - tells the wrapper to attempt to capture the exact number of frames as specified by the "numberOfFramesToCapture" property. This can be used if a file has too few frames but you still want to capture an exact number
    • useTimeSeekToCapture - used to set the wrapper method of capture to seeking through the file instead of capturing a frame at an interval
    • thumbnailPrefix - the prefix to be used when creating the filenames for captured frames. The default is the name of the video with "_thumb" append to it as in "myVideo_thumb01.jpg"
    • capturedFrameWidthHeight - the width:height that each frame will be scaled to. The default is 270:200
    • scaleCapturedFrames - used in conjunction with the "capturedFrameWidthHeight" property to scale down the captured frames. Set to true by default
  • Capture in a different output directory
    in C#
    // Specify the path to the video file
    string videoFilePath = @"drive letter:\path\to\myVideo.mpg";
    // Specify the output directory
    string outputPath = @"drive letter:\path\to\output directory";
    // Declare the mplayer instance with the mplayer executable residing in the
    // same directory as your executable
    mPlayerWrapper mPlayerInstance = new mPlayerWrapper();
    // Capture frames
    mPlayerInstance.captureFrames(videoFilePath, outputPath);
    

    in VB.NET
    ' Specify the path to the video file
    dim videoFilePath As String = "drive letter:\path\to\myVideo.mpg"
    ' Specify the output directory
    dim outputPath As String = @"drive letter:\path\to\output directory"
    ' Declare the mplayer instance with the mplayer executable residing in the
    ' same directory as your executable
    dim mPlayerInstance As new mPlayerWrapper()
    ' Capture frames
    mPlayerInstance.captureFrames(videoFilePath, outputDirectory)
    
  • Using distinct capture methods:
    1. captureFramesWithInterval - by default captures a frame every 5 seconds with up to 12 frames
    2. captureFramesWithTimeSeek - by default captures 1 frame each second with up to 12 frames by seeking through the file
  • Bonus
    • getFileProperties - returns a SortedList of video and audio properties for the file
    • getAudioProperties - returns a SortedList of audio properties for the file
    • getVideoProperties - returns a SortedList of video properties for the file

Downloads

mPlayerWrapper: http://blog.tech-cats.net/examples/dotnet/mPlayerWrapper.dll
mPlayerWrapper Source: http://blog.tech-cats.net/examples/dotnet/mplayerWrapper-v0.1.zip

Tuesday, March 04, 2008

Top 13 Visual Studio Keyboard Shortcuts

My friends in college always made fun of my keyboard obsession. At the time, I knew all the Windows 98 specific shortcut keys and often had no need for the mouse. Keyboard shortcuts still rule in my book. It is amazing that you can get around without using a mouse at all. Master the following Visual Studio shortcuts and your colleagues might stare at you with amazement.

  1. F5: Start your project in debug mode

    vsShortcutsNumber1
  2. F7 & Shift-F7: Show the code windows & Show the designer window

    vsShortcutsNumber2
  3. Alt-Enter: Show the properties panel for a selected object (this is general Windows shortcut that can be used on files and directories)

    vsShortcutsNumber3
  4. F6 / Shift-F6 / Ctrl-Shift-B: Build solution / Build project / Build solution

    vsShortcutsNumber4 
  5. Shift-Alt-C: Add a new class to your project

    vsShortcutsNumber12 
  6. Ctrl-K + Ctrl-C: Comment a selected block of code

    vsShortcutsNumber5
  7. Ctrl-K + Ctrl-U: Un-comment a selected block of code

    vsShortcutsNumber6
  8. Ctrl-M + Ctrl-O / Ctrl-M + Ctrl-P: Collapse all code to definitions / Expand all code (stop collapsing)

    vsShortcutsNumber7
  9. Ctrl-M + Ctrl+M: Expend or collapse a selected code fragment. The code collapsed depends on where the cursor is located

    vsShortcutsNumber8
  10. Ctrl-B + Ctrl-T: Toggle code bookmark

    vsShortcutsNumber9
  11. Ctrl-Alt-P: Attach the debugger to a process. This is insanely useful for debugging ASP.NET web sites without having to start the project in debug mode

    vsShortcutsNumber10
  12. Ctrl-Alt-L: Show the solution explorer

    vsShortcutsNumber11 
  13. Ctrl-Shift-A / Alt-Shift-A: Add a new item to your project / add an existing item to your project

    vsShortcutsNumber13

The above list is my top 13. Did I miss any essential ones? What are yours?

Bonus:

The following work in Visual Studio just like they do in most other Windows application.

Ctrl-N: Add a new file

Ctrl-S: Save file

Ctrl-Z / Ctrl-Y: Undo typing / Redo typing

Ctrl-F: Bring up the "Find" dialog

Ctrl-H: Bring up the "Replace" dialog

Ctrl-Tab: Scroll forward through open windows

Ctrl-Shift-Tab: Scroll backwards through open windows

Wednesday, February 27, 2008

12 Essential Free Tools for .NET Developers

Over my course of .NET development, I have compiled a list of essential free tools for .NET applications. This is not a the alpha or the omega of tools, just a short list that I feel is essential.

  1. SharpDevelop

    http://www.icsharpcode.net/OpenSource/SD/Download
    An open source IDE for .NET. Check out the full feature tour.
  2. Visual Web Developer Express Edition

    http://www.microsoft.com/express/vwd
    Stripped down version of Visual Studio that allows you to write .NET web applications.
  3. TortoiseSVN

    http://tortoisesvn.net/downloads
    There is no better Subversion client for Windows. You need this if you are going to use VisualSVN with Visual Studio.
  4. NAnt

    http://nant.sourceforge.net
    .NET based automation tool that has many built in tasks but could be extended with custom code written in any .NET language.
  5. Snippet Compiler

    http://www.sliver.com/dotnet/SnippetCompiler
    Snippet compiler is a small tool to write and execute small chunks of .NET code without creating a Visual Studio project.
  6. .NET Reflector

    http://www.aisto.com/roeder/dotnet
    Reflector is the class browser, explorer, analyzer and documentation viewer for .NET. Reflector allows to easily view, navigate, search, decompile and analyze .NET assemblies in C#, Visual Basic and IL.
  7. Microsoft SQL Server Management Studio Express

    http://www.microsoft.com/downloads/details.aspx?FamilyID=c243a5ae-4bd1-4e3d-94b8-5a0f62bf7796&displaylang=en
    Tool for database administration and development from Microsoft
  8. Quest Comparison Suite for SQL Server

    http://www.quest.com/Comparison-Suite-for-SQL-Server
    Compare and synchronize database schema and data
  9. XYPlorer

    http://www.xyplorer.com
    Awesome file manager. The older version is completely free.
  10. Convert C# to VB.NET

    http://labs.developerfusion.co.uk/convert/csharp-to-vb.aspx
  11. NAnt Add-In

    http://www.netlogics.ch/devcenter/display/NLC/NAntAddin
    Visual Studio add-in for NAnt integration
  12. NUnit Add-In

    http://www.netlogics.ch/devcenter/display/NLC/NUnitAddin
    Visual Studio add-in for NUnit integration

More Visual Studio add-ins can be found at 15+ Free Visual Studio Add-Ins and 15+ FREE Visual Studio Add-ins - Part 2

Thursday, February 21, 2008

Tools for Authoring NAnt Build Files

NAnt is a great tool for automating many computer tasks. For a quick introduction, check my previous articles Automating Your Computer Tasks with NAnt and Use NAnt and WinRar to Create a Self Extracting Archive. Authoring NAnt build files can be difficult without a good editor and editing XML is not my favorite thing to do anyway. Having to know all the tags and parameters for each NAnt task, makes it even less desirable. Looking at the current options, you can find several tools for authoring NAnt build files:

While the tools above will do the job, it would be nice if you could edit your build files in Visual Studio and have at least the basic intellisense that the IDE provides. It turns out that editing NAnt build files with VS and having code insight is a pretty easy thing to setup. Here is how it is done:

  1. Install the NAnt schema by copying the file "nant.xsd" form the NAnt distribution to "C:\Program Files\Microsoft Visual Studio 8\Xml\Schemas"
  2. Associate NAnt build files (.build) with the Visual Studio XML editor. This can be done in one of two ways:
    • Create a registry merge file with the following contents and merge it in your registry:
      Windows Registry Editor Version 5.00
      
      [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Editors\{412B8852-4F21-413B-9B47-0C9751D3EBFB}\Extensions]
      "build"=dword:00000029
      
    • Make the association through Visual Studio:
      • Open any Visual Studio solution
      • Add a NAnt build file to it
      • Right click on the .build file and choose "Open With"
      • Select "XML Editor" and click on "Set as Default"
  3. Almost there. The last thing is to add the "xmlns" (namespace) attribute to the "project" tag of your build file. If you have copied the NAnt schema file (nant.xsd) to the right place, adding the "xmlns" attribute should list the NAnt schema as one of the available choices. The end result should look like:
    <project
    	name="testProject"
    	default="buildSetup"
    	basedir="."
    	xmlns="http://nant.sf.net/release/0.85/nant.xsd"
    >
    
  4. And Voila! Start typing some XML and you should see a list of NAnt tasks and attributes.

Tuesday, January 29, 2008

Build Your SubSonic DAL with NAnt

SubSonic is a .NET ORM (object relational mapping) tool with plenty of extras. In the ORM market, it can be compared to other tool such as Linq and NHibernate. I chose SubSonic over NHibernate, because of the ease of configuration or Linq, because I am still programming for .NET 2.0. That being said, there are three different ways to generate your data access layer using SubSonic:

  1. Using the command line by calling "sonic.exe"
  2. Using the SubSonic Tools for Visual Studio
  3. Using a build provider. However, this method is only available to web projects.

I was using the second method by installing the tools for Visual Studio. However, that got to be a pain since every time I want to regenerate the data access layer I have to start Visual Studio, wait for it to load, invoke the SubSonic tools, wait for the generation and finally rebuild the project.

So a few days ago I switched to using the first method - the command line. Once I did that, it was a matter of time before I wrote the NAnt build file to do it for me without Visual Studio - generate the data access layer and rebuild the data access layer dll. So here is the build file that can be used stand alone or even invoked through a pre-build event in Visual Studio:

<project name="Ensemble" default="build" basedir=".">
  <!-- The full path to the SubSonic directory where SubSonic.dll is found -->
  <property name="subSonicFullPath" value="c:\Program Files\SubSonic\SubSonic 2.0.3" />

  <!-- The full path to the SubSonic commander -->
  <property name="sonicCommanderFullPath" value="C:\Program Files\SubSonic\SubSonic 2.0.3\SubCommander\sonic.exe" />

  <!-- The command line arguments for the SubSonic commander -->
  <property name="sonicCommanderArguments" value="generate /lang vb" />

  <!-- The root namespace for the project -->
  <property name="build.rootNamespace" value="ensembleVideo" />

  <!-- The build type (release or debug) for the project -->
  <property name="build.config" value="release" />

  <!-- The relative path to the project directory (from the location of the build file) -->
	<property name="targetDirectoryRelativePath" value="../dataAccessLayer" overwrite="false" />

	<!-- The relative path to directory where SubSonic will generated the files (from the project target directory) -->
	<property name="subsonicGeneratedFilesRelativePath" value="generated" />

  <property name="targetDirectoryFullPath" value="${path::get-full-path(targetDirectoryRelativePath)}" overwrite="false" />
  <property name="subsonicGeneratedFilesFullPath" value="${path::combine(targetDirectoryFullPath, 'generated')}" />
	<property name="binDirectory" value="${path::combine(targetDirectoryFullPath, 'bin')}" overwrite="false" />

  <property name="buildDirectoryFullPath" value="${path::combine(binDirectory, build.config)}" overwrite="false" />
  <property name="buildOutput" value="ensembleVideo.dataAccessLayer.dll" />

  <!-- Default build target -->
	<target name="build">
	  <!-- Execute the SubSonic commander to generated the files in the defined "sonicCommanderFullPath" directory -->
	  <exec
    	basedir="${targetDirectoryFullPath}"
    	program="${sonicCommanderFullPath}"
    	commandline="${sonicCommanderArguments} /out "${subsonicGeneratedFilesFullPath}""
    	workingdir="${targetDirectoryFullPath}"
    	failonerror="true" />

    <!-- Execute the vb compiler to compile the SubSonic generated files -->
    <vbc target="library" output="${path::combine(buildDirectoryFullPath, buildOutput)}" rootnamespace="${build.rootNamespace}">
        <imports>
            <import namespace="System" />
            <import namespace="System.Data" />
        </imports>

        <sources>
          <!-- Include all the SubSonic generated files -->
          <include name="${subsonicGeneratedFilesFullPath}\*.vb" />
        </sources>

        <!-- Include a reference to the SubSonic dll -->
        <references basedir="${subSonicFullPath}">
  			  <include name="SubSonic.dll" />
  		  </references>
     </vbc>
	</target>
</project>

Saturday, January 19, 2008

Kick Butt Project Management with Assembla

A few days ago I blogged about Tools for Better Project Management and Organization and this post offers an alternative application for project management. As I mentioned in my pervious post, I highly recommend RedMine as your web based project manager. RedMine is great if you want something that you have complete control over. With complete control however, come the pain of having to install it, configure it and worry about backups. So today, as a part of a project I am involved in, I set on a quest to find something that would be as good as RedMine but without the installation and configuration involved. After evaluating a few different web based project management application (Unfuddle, CodeSpaces, and a few other not worth mentioning), I tried Assembla. I had put in on my list to evaluate a while ago so it was not a new find but I am sorry I did not try it earlier. I am not going to get into much detail on the features but I have to say, the number of features is impressive. Best of all you get all this including 500mb of space for free! Here is a quick overview:

The start page:

Boyan Kostadinov- start -Assembla_1200795708018

The dashboard

Ensemble Video- index -Assembla_1200795731143 

Time entry

Ensemble Video- tasks -Assembla_1200795740736

Milestones

Ensemble Video- Milestones -Assembla_1200795878080

Online chat

Ensemble Video- chat -Assembla_1200795889986

Files repository

Ensemble Video- files -Assembla_1200795897143

Wiki

Ensemble Video- Space Home -Assembla_1200795904674

Trac/SVN integration

Ensemble Video- trac_tool -Assembla_1200795912877

Images repository

Ensemble Video- Images -Assembla_1200795923080

Blog integration with Mephisto

Ensemble Video- mephisto_tool -Assembla_1200795932439

Alerts

Ensemble Video- alerts -Assembla_1200795964174

Additional add-ons

Ensemble Video- edit -Assembla_1200795987596

Monday, January 14, 2008

Tools for Better Project Management and Organization

Organization and project management have turned into very important skills even for developers. With growing demand for automation and the spread of information, companies are consistently working on new ways to organize, restructure and make data accessible.

If you are a developer, at some point in your career, it is very likely that you have run into trouble with a project running over the perceived time frame and/or original specifications. Everyone in the programming word has heard the horror stories of never ending features and lack of project requirements. I would not be honest if I said this has not happened to me. C'est la vie, as the French would say but I am trying to learn something from it.

Over the past few months, I have started to use several tools to keep track of project requirements/bugs/features, log tasks I have worked on/accomplished, and billing related data (tasks, time, invoices, etc).

Project Management

After evaluating about 20 open source projects (thank you SourceForge), and some commercial products, I settled on using a open source project called RedMine. Here is the overview of RedMine's features directly from the web site:

  • Multiple projects support
  • Flexible role based access control.
  • Flexible issue tracking system
  • Gantt chart and calendar
  • News, documents & files management
  • Feeds & email notifications.
  • Per project wiki
  • Per project forums
  • Simple time tracking functionality
  • Custom fields for issues, projects and users
  • SCM integration (SVN, CVS, Mercurial, Bazaar and Darcs)
  • Multiple LDAP authentication support
  • User self-registration support
  • Multilingual support
  • Multiple databases support

You can see a full list of features plus screen shots at the Features page.

Task Logging

The nice folks at Lifehacker have put together an excellent little script for logging your daily tasks. The basics of it are:

  • You setup the script by editing the .vbs file, create a shortcut to it and setup a shortcut key
  • You press the shortcut key and an input box pops up
  • You enter the task/item you want to log and the script writes it with a date plus time to your log file

You can find the full details about it and how to set it up at Geek to Live: Quick-log your work day

Keeping Track of Billing Data

There is more than one tool for the job so choices highly depend on features, preference and price. For my need, I have found that a tool will need a least a minimum set of features:

  • Keep track of clients and projects
  • Log time and description per time spend on project
  • Generate invoices for selected time frame

Considering the above, I can recommend a small windows application called Billing Tracker. The pro version costs $89. I am sure there are plenty of free web based applications that fall in this category too.

Bonus - Keeping Track of your Daily Tasks

Even with all the above, keeping on track with your projects and life can be hard. Not everything falls into a project and sometimes you do not want to create the smallest task as part of your project tracking. On the other hand, if you don't write it down, you will forget it, I do.

So here is where a To-Do list comes in. There are many, many free, web based to-do applications. I use Remember The Milk. Some nice features are:

  • Offline access (with Google Gears)
  • Task categories, lists and locations
  • Reminders
  • Integration with GMail (only for Firefox with an extension) and Google Calendar
  • RSS of your tasks


Conclusion

No matter how you decide to go about it, most important than everything else is your discipline to track and log your work.

Thursday, October 11, 2007

Must Have Tools for Windows Power Users

This is a list of must have tools with inspiration from blog post at http://www.nodans.com/index.cfm/2007/10/10/Dana-Kowalski-sez-Crack-Open-your-Toolbox-and-Share

Launchy: http://www.launchy.net/ - An open source keystroke launcher for Windows
XYPlorer: http://www.xyplorer.com - A windows file manager and explorer replacement
Hamachi: http://hamachi.cc/download/list.php - Software based VPN
FolderShare: http://www.foldershare.com - Sync files/directories between multiple computers
RoboForm: http://www.roboform.com - An automated form filer and password manager
Altiris Software Virtualization: http://www.svsdownloads.com - A virtual engine for applications
Paint.NET: http://www.svsdownloads.com - Free image and photo editing software
Quest Comparison Suite for SQL Server: http://www.quest.com/Comparison-Suite-for-SQL-Server - Free Microsoft SQL server comparison suite

Friday, October 05, 2007

Web Page Syntax Highlighting for ColdFusion - Brush for SyntaxHighlighter

I have been working on a implementing a solution to highlight ColdFusion code snippets when they are being posted on your web site/blog. Highlighting the code according to the appropriate language can make it much easier to read and comprehend (and make it pretty of course). To do this, I have created a ColdFusion syntax "brush" for the JavaScript highlighter SyntaxHighlighter (formally dp.SyntaxHighlighter). In this context, a "brush" is a set of language specific settings for highlighting/prettifying code. SyntaxHighlighter is a pretty cool piece of software and I had some fun and faced some challenges while trying to create ColdFusion specific highlighting brush. Here is a demo of the highlighter at work when given ColdFusion code snippet:

<cfcomponent displayname="applicationController" extends="ModelGlue.unity.controller.Controller" output="false">

<cfscript>
// Set component variables
variables.appConfig = 0;
variables.modelGlueConfig = 0;
variables.rolePermissions = structnew();
variables.userIDWithAdminRights = "";
</cfscript>

<!---
Function: name="changeUserSiteRole"
Created on: 09.25.2007
Updated on: 09.25.2007
Author: Boyan Kostadinov
Arguments: event(ModelGlue.Core.Event)
Return Value: none
Description:
--->
<cffunction name="changeUserSiteRole" access="public" returntype="void" output="false">
 <cfargument name="event" type="ModelGlue.Core.Event">
 <cfset var userID = arguments.event.getValue("userID", 0) />
 <cfset var siteID = arguments.event.getValue("siteID", 0) />
 <cfset var roleID = arguments.event.getValue("roleID", 0) />
 <cfset var showAllUsers = arguments.event.getValue("showAllUsers", false) />

<cfif userID neq 0 and siteID neq 0 and roleID neq 0> <!--- Call the changeUserSiteRole method in the UsersGateway to change the user's role in the specified siteID ---> <cfset variables.usersGateway.changeUserSiteRole(userID, siteID, roleID) /> </cfif>
<cfif showAllUsers> <cfset arguments.event.addResult("allUsers") /> <cfelse> <cfset arguments.event.addResult("singleUser") /> </cfif> </cffunction>
<cffunction name="onQueueComplete" access="public" returntype="void" output="false"> <cfargument name="event" type="any">
<cfset arguments.event.setValue("defaultEvent", getModelGlue().getBean("modelGlueConfiguration").getdefaultEvent()) /> <cfset arguments.event.setValue("appConfig", variables.appConfig) /> <cfset arguments.event.setValue("ApplicationVersion", variables.appConfig.GetConfigSetting("ApplicationVersion")) /> <cfset arguments.event.setValue("ApplicationLastRevisionDate", variables.appConfig.GetConfigSetting("ApplicationLastRevisionDate")) /> <cfset arguments.event.setValue("urlPrefix", variables.defaultTemplate & "?" & arguments.event.getValue("eventValue") & "=") /> <cfset arguments.event.setValue("CurrentPageUrl", getfilefrompath(cgi.script_name) & "?" & cgi.query_string) /> </cffunction>
<cffunction name="onRequestEnd" access="public" returntype="void" output="false"> <cfargument name="event" type="any"> </cffunction>
</cfcomponent>
To install the SyntaxHighlighter on your page:
  1. Get it http://code.google.com/p/syntaxhighlighter/
  2. Extract it somewhere accessable from the web
  3. Add the following code
    <!-- Include the SyntaxHighlighter stylesheet -->
    <style type="text/css" media="screen">@import url("pathToSyntaxHighlighterStyle/syntaxHighlighter.css");</style>
    <!-- Include the core SyntaxHighlighter library -->
    <script language="javascript" src="pathToSyntaxHighlighter/scripts/shCore.js"></script>
    <!-- Include the ColdFusion brush -->
    <script language="javascript" src="pathToSyntaxHighlighter/scripts/shBrushColdFusion.js"></script>
    &