Commits

Chris Nielsen committed a227b5e

Rearrange namespaces.

Comments (0)

Files changed (75)

MinCat.MSBuild/Compressors/Compressor.cs

+ďťżnamespace MinCat.MSBuild.Compressors {
+	using MinCat.MSBuild.Models;
+	using MinCat.MSBuild.Util;
+
+	/// <summary>
+	/// An abstract base class which can be used to create compressor
+	/// utilities.
+	/// </summary>
+	internal abstract class Compressor {
+
+		/// <summary>
+		/// Gets the logging interface.
+		/// </summary>
+		protected ILog Log {
+			get;
+			private set;
+		}
+
+		/// <summary>
+		/// Initializes a new instance of the Compressor class using the
+		/// provided MSBuild task.
+		/// </summary>
+		/// <param name="logger">A logging interface.</param>
+		protected Compressor(ILog logger) {
+			this.Log = logger;
+		}
+
+		/// <summary>
+		/// Compress the prepared file.
+		/// </summary>
+		/// <param name="file">The prepared file to compress.</param>
+		public abstract void Compress(PreparedFile file);
+	}
+}

MinCat.MSBuild/Compressors/YUICompressor/LICENSE.TXT

+YUI Compressor Copyright License Agreement (BSD License)
+
+Copyright (c) 2010, Yahoo! Inc.
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of Yahoo! Inc. nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of Yahoo! Inc.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+This software also requires access to software from the following sources:
+
+The Jarg Library v 1.0 ( http://jargs.sourceforge.net/ ) is available
+under a BSD License – Copyright (c) 2001-2003 Steve Purcell,
+Copyright (c) 2002 Vidar Holen, Copyright (c) 2002 Michal Ceresna and
+Copyright (c) 2005 Ewan Mellor.
+
+The Rhino Library ( http://www.mozilla.org/rhino/ ) is dually available
+under an MPL 1.1/GPL 2.0 license, with portions subject to a BSD license.
+
+Additionally, this software contains modified versions of the following
+component files from the Rhino Library:
+
+[org/mozilla/javascript/Decompiler.java]
+[org/mozilla/javascript/Parser.java]
+[org/mozilla/javascript/Token.java]
+[org/mozilla/javascript/TokenStream.java]
+
+The modified versions of these files are distributed under the MPL v 1.1
+( http://www.mozilla.org/MPL/MPL-1.1.html )

MinCat.MSBuild/Compressors/YUICompressor/YUICompressor.cs

+ďťżnamespace MinCat.MSBuild.Compressors {
+	using System.Diagnostics;
+	using System.Globalization;
+	using System.IO;
+	using System.Linq;
+	using System.Text.RegularExpressions;
+	using MinCat.MSBuild.Exceptions;
+	using MinCat.MSBuild.Models;
+	using MinCat.MSBuild.Properties;
+	using MinCat.MSBuild.Util;
+
+	/// <summary>
+	/// Implementation of the abstract Compressor class that utilizes the YUI
+	/// compressor.
+	/// </summary>
+	internal class YUICompressor : Compressor {
+
+		/// <summary>
+		/// A template of the arguments that are passed to the YUI Compressor.
+		/// </summary>
+		private static string processArguments = string.Format(
+			CultureInfo.InvariantCulture,
+			@"-jar ""{0}{1}Compressors\YUICompressor\yuicompressor-2.4.6.jar""",
+			Path.GetDirectoryName(
+				System.Reflection.Assembly
+					.GetAssembly(typeof(YUICompressor))
+					.Location),
+			Path.DirectorySeparatorChar) +
+			@" --charset UTF-8 --type js -o ""{0}"" ""{1}""";
+
+		/// <summary>
+		/// Initializes a new instance of the YUICompressor class using the
+		/// provided MSBuild task.
+		/// </summary>
+		/// <param name="logger">A valid logging interface.</param>
+		public YUICompressor(ILog logger) : base(logger) {
+			this.Log.LogMessage(Resources.UsingYUICompressor);
+		}
+
+		/// <summary>
+		/// Compress the prepared file.
+		/// </summary>
+		/// <param name="file">The prepared file to compress.</param>
+		public override void Compress(PreparedFile file) {
+
+			using (var process = new Process()) {
+
+				process.StartInfo.FileName = "java.exe";
+				process.StartInfo.Arguments =
+					string.Format(
+						CultureInfo.InvariantCulture,
+						YUICompressor.processArguments,
+						file.Destination,
+						file.Source);
+
+				process.StartInfo.UseShellExecute = false;
+				process.StartInfo.CreateNoWindow = true;
+				process.StartInfo.RedirectStandardOutput = true;
+				process.StartInfo.RedirectStandardError = true;
+
+				try {
+					process.Start();
+				} catch (System.ComponentModel.Win32Exception ex) {
+					throw new FileNotFoundException(
+						Resources.NeedJavaInstalled,
+						ex);
+				}
+
+				process.WaitForExit();
+				string message = process.StandardError.ReadToEnd();
+
+				if (!string.IsNullOrEmpty(message)) {
+					throw new CompressionException(
+						YUICompressor.ParseErrorMessage(message));
+				} else {
+					message = process.StandardOutput.ReadToEnd();
+					if (!string.IsNullOrEmpty(message)) {
+						this.Log.LogMessage(message.Trim());
+					}
+				}
+			}
+		}
+
+		/// <summary>
+		/// Extract relevant error information out of the message that the
+		/// YUI compressor writes to StandardError when something bad happens.
+		/// </summary>
+		/// <param name="message">The contents of StandardError.</param>
+		/// <returns>Relevant error information.</returns>
+		private static string ParseErrorMessage(string message) {
+			Regex isErrorLine = new Regex(@"^\[ERROR\]");
+
+			string[] errorLines = message
+				.Split('\n')
+				.Where(line => isErrorLine.IsMatch(line))
+				.ToArray();
+
+			return (errorLines.Length > 0) ?
+				string.Join("\n", errorLines) :
+				message;
+		}
+	}
+}

MinCat.MSBuild/Compressors/YUICompressor/yuicompressor-2.4.6.jar

Binary file added.

MinCat.MSBuild/Concatenate.cs

+ďťżnamespace MinCat.MSBuild {
+	using System;
+	using Microsoft.Build.Framework;
+	using Microsoft.Build.Utilities;
+
+	/// <summary>
+	/// Concatenate two or more files into a single output file.
+	/// </summary>
+	[Obsolete("Please use Minimize with require or include directives.")]
+	public class Concatenate : Task {
+
+		/// <summary>
+		/// Gets or sets a new-line delimited list of files that will be
+		/// concatenated, in order, into the resulting output file.
+		/// </summary>
+		[Required]
+		public string Input {
+			get;
+			set;
+		}
+
+		/// <summary>
+		/// Gets or sets the filename of the resulting concatenated file.
+		/// </summary>
+		[Required]
+		public string Output {
+			get;
+			set;
+		}
+
+		/// <summary>
+		/// Gets or sets a value indicating whether borders should be inserted
+		/// into the resulting concatenated file. The borders will mark the end
+		/// of one file and beginning of another file. These are safe for use
+		/// with both JavaScript and CSS files.
+		/// </summary>
+		public bool Borders {
+			get;
+			set;
+		}
+
+		/// <summary>
+		/// Concatenate these files into a single file.
+		/// </summary>
+		/// <returns>True if the task succeeds; otherwise false.</returns>
+		public override bool Execute() {
+
+			var logger = new TaskLogger(this.Log);
+
+			var model = new MinCat.MSBuild.Models.Concatenate {
+				Log = logger,
+				Input = this.Input,
+				Output = this.Output,
+				Borders = this.Borders
+			};
+
+			return model.Execute();
+		}
+	}
+}

MinCat.MSBuild/Exceptions/CompressionException.cs

+ďťżnamespace MinCat.MSBuild.Exceptions {
+	using System;
+	using System.Runtime.Serialization;
+
+	/// <summary>
+	/// Describes an error that was reported by the compression engine.
+	/// </summary>
+	[Serializable]
+	public class CompressionException : Exception {
+
+		/// <summary>
+		/// The stack trace that was reported by the compression engine, if
+		/// there was one.
+		/// </summary>
+		private string stackTrace = null;
+
+		/// <summary>
+		/// Initializes a new instance of the CompressionException class with
+		/// the provided error message and inner exception.
+		/// </summary>
+		/// <param name="message">An error message.</param>
+		/// <param name="inner">An inner exception.</param>
+		public CompressionException(string message, Exception inner)
+			: base(message, inner)
+		{
+		}
+
+		/// <summary>
+		/// Initializes a new instance of the CompressionException class using
+		/// the provided error message.
+		/// </summary>
+		/// <param name="message">
+		/// An error message that was reported by the compression engine.
+		/// </param>
+		public CompressionException(string message) : base(message) {
+		}
+
+		/// <summary>
+		/// Initializes a new instance of the CompressionException class.
+		/// </summary>
+		public CompressionException() : base() {
+		}
+
+		/// <summary>
+		/// Initializes a new instance of the CompressionException class using
+		/// the provided error message and stack trace.
+		/// </summary>
+		/// <param name="message">
+		/// An error message that was reported by the compression engine.
+		/// </param>
+		/// <param name="stackTrace">
+		/// A stack trace that was reported by the compression engine.
+		/// </param>
+		public CompressionException(string message, string stackTrace)
+			: base(message)
+		{
+			if (!string.IsNullOrEmpty(stackTrace)) {
+				this.stackTrace = stackTrace;
+			}
+		}
+
+		/// <summary>
+		/// Initializes a new instance of the CompressionException class
+		/// with serialized data.
+		/// </summary>
+		/// <param name="info">
+		/// The SerializationInfo that holds the serialized object data about
+		/// the exception being thrown.
+		/// </param>
+		/// <param name="context">
+		/// The StreamingContext that contains contextual information about
+		/// the source or destination.
+		/// </param>
+		/// <throws cref="System.ArgumentNullException">
+		/// The info parameter is null.
+		/// </throws>
+		/// <throws cref="System.Runtime.Serialization.SerializationException">
+		/// The class name is null or System.Exception.HResult is zero (0).
+		/// </throws>
+		protected CompressionException(
+			SerializationInfo info,
+			StreamingContext context) : base(info, context)
+		{
+			this.stackTrace =
+				info.GetString("CompressionException_stackTrace");
+		}
+
+		/// <summary>
+		/// Gets the stack trace as it was reported by the compression engine,
+		/// if it reported a stack trace at all.
+		/// </summary>
+		public override string StackTrace {
+			get {
+				return this.stackTrace ?? string.Empty;
+			}
+		}
+
+		/// <summary>
+		/// When overridden in a derived class, sets the SerializationInfo with
+		/// information about the exception.
+		/// </summary>
+		/// <param name="info">
+		/// The SerializationInfo that holds the serialized object data about
+		/// the exception being thrown.
+		/// </param>
+		/// <param name="context">
+		/// The StreamingContext that contains contextual information about the
+		/// source or destination.
+		/// </param>
+		/// <throws cref="System.ArgumentNullException">
+		/// The info parameter is a null reference (Nothing in Visual Basic).
+		/// </throws>
+		public override void GetObjectData(
+			SerializationInfo info,
+			StreamingContext context)
+		{
+			info.AddValue(
+				"CompressionException_stackTrace",
+				this.stackTrace);
+
+			base.GetObjectData(info, context);
+		}
+
+	}
+}

MinCat.MSBuild/MinCat.MSBuild.csproj

+ďťż<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <UsingTask TaskName="HgVersionFile" AssemblyFile="..\Resources\MSBuildVersioning.dll" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{88880969-1AC9-4015-832F-75E67183FD3F}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>MinCat.MSBuild</RootNamespace>
+    <AssemblyName>MinCat.MSBuild</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>..\Code Analysis.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>bin\Release\MinCat.MSBuild.XML</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>MinCat.MSBuild.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.Build.Framework" />
+    <Reference Include="Microsoft.Build.Utilities.v4.0" />
+    <Reference Include="System" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Compressors\Compressor.cs" />
+    <Compile Include="Compressors\YUICompressor\YUICompressor.cs" />
+    <Compile Include="Concatenate.cs" />
+    <Compile Include="Exceptions\CompressionException.cs" />
+    <Compile Include="Minimize.cs" />
+    <Compile Include="Models\Concatenate.cs" />
+    <Compile Include="Models\ILog.cs" />
+    <Compile Include="Models\Minimize.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Properties\Resources.Designer.cs">
+      <DependentUpon>Resources.resx</DependentUpon>
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+    </Compile>
+    <Compile Include="Models\TaskLogger.cs" />
+    <None Include="MinCat.MSBuild.snk" />
+    <None Include="Properties\VersionInfo.base.cs" />
+    <Compile Include="Properties\VersionInfo.cs" />
+    <Compile Include="Util\PreparedFile.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config" />
+    <None Include="Compressors\YUICompressor\LICENSE.TXT">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="Compressors\YUICompressor\yuicompressor-2.4.6.jar">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\MinCat\MinCat.csproj">
+      <Project>{31CFD0F2-99C5-4919-8178-73EE4F61BE8E}</Project>
+      <Name>MinCat</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Target Name="BeforeBuild">
+    <HgVersionFile TemplateFile="Properties\VersionInfo.base.cs" DestinationFile="Properties\VersionInfo.cs" />
+  </Target>
+</Project>

MinCat.MSBuild/MinCat.MSBuild.snk

Binary file added.

MinCat.MSBuild/Minimize.cs

+ďťżnamespace MinCat.MSBuild {
+	using Microsoft.Build.Framework;
+	using Microsoft.Build.Utilities;
+
+	/// <summary>
+	/// Minimize one or many JavaScript files.
+	/// </summary>
+	public class Minimize : Task {
+
+		/// <summary>
+		/// Gets or sets the input glob used to locate files to minimize.
+		/// </summary>
+		[Required]
+		public string Input { get; set; }
+
+		/// <summary>
+		/// Gets or sets a value indicating whether borders should be inserted
+		/// into the resulting concatenated file. The borders will mark the end
+		/// of one file and beginning of another file. These are safe for use
+		/// with both JavaScript and CSS files.
+		/// </summary>
+		public bool Borders { get; set; }
+
+		/// <summary>
+		/// Gets or sets the path to the root of this website. This is used to
+		/// resolve rooted relative paths. This defaults to the same folder as
+		/// the project file.
+		/// </summary>
+		public string WebRoot { get; set; }
+
+		/// <summary>
+		/// Gets or sets the output path into which minimized files will be
+		/// placed.
+		/// </summary>
+		public string Outpath { get; set; }
+
+		/// <summary>
+		/// <para>
+		/// Gets or sets the pattern used to generate the output filename.
+		/// </para>
+		/// <list type="table">
+		///     <listheader>
+		///         <term>Pattern</term>
+		///         <description>Meaning</description>
+		///     </listheader>
+		///     <item>
+		///         <term>{Filename}</term>
+		///         <description>
+		///             The original filename, without the extension.
+		///         </description>
+		///     </item>
+		///     <item>
+		///         <term>{Extension}</term>
+		///         <description>
+		///             The original extension, including the dot.
+		///         </description>
+		///     </item>
+		///     <item>
+		///         <term>All other characters</term>
+		///         <description>Literals</description>
+		///     </item>
+		/// </list>
+		/// <para>Defaults to <c>{Filename}-min{Extension}</c></para>
+		/// </summary>
+		public string FilePattern { get; set; }
+
+		/// <summary>
+		/// Executes the task.
+		/// </summary>
+		/// <returns>
+		/// true if the task successfully executed; otherwise, false.
+		/// </returns>
+		public override bool Execute() {
+
+			var logger = new TaskLogger(this.Log);
+
+			var model = new MinCat.MSBuild.Models.Minimize {
+				Log = logger,
+				Input = this.Input,
+				Borders = this.Borders,
+				WebRoot = this.WebRoot,
+				Outpath = this.Outpath,
+				FilePattern = this.FilePattern
+			};
+
+			return model.Execute();
+		}
+	}
+}

MinCat.MSBuild/Models/Concatenate.cs

+ďťżnamespace MinCat.MSBuild.Models {
+	using System;
+	using System.IO;
+	using System.Linq;
+	using MinCat.MSBuild.Properties;
+
+	/// <summary>
+	/// Concatenates files.
+	/// </summary>
+	public class Concatenate {
+
+		/// <summary>
+		/// Gets or sets a logging interface.
+		/// </summary>
+		internal ILog Log {
+			get;
+			set;
+		}
+
+		/// <summary>
+		/// Gets or sets a new-line delimited list of files that will be
+		/// concatenated, in order, into the resulting output file.
+		/// </summary>
+		public string Input {
+			get;
+			set;
+		}
+
+		/// <summary>
+		/// Gets or sets the filename of the resulting concatenated file.
+		/// </summary>
+		public string Output {
+			get;
+			set;
+		}
+
+		/// <summary>
+		/// Gets or sets a value indicating whether borders should be inserted
+		/// into the resulting concatenated file. The borders will mark the end
+		/// of one file and beginning of another file. These are safe for use
+		/// with both JavaScript and CSS files.
+		/// </summary>
+		public bool Borders {
+			get;
+			set;
+		}
+
+		/// <summary>
+		/// Concatenated the specified files into the desired destination file.
+		/// </summary>
+		/// <returns>True upon success; otherwise, false.</returns>
+		internal bool Execute() {
+
+			this.Log.LogMessage(Resources.CreatingFile, this.Output);
+
+			var paths =
+				from path in this.Input.Split(
+					new char[] { '\n' },
+					StringSplitOptions.RemoveEmptyEntries)
+				let trimmed = path.Trim()
+				where string.IsNullOrEmpty(trimmed) == false
+				select trimmed;
+
+			foreach (string path in paths) {
+				this.Log.LogMessage("\t" + path);
+			}
+
+			foreach (string path in paths.Where(p => !File.Exists(p))) {
+				this.Log.LogError(Resources.FileNotFound, path);
+			}
+
+			if (this.Log.HasLoggedErrors == false) {
+
+				if (!this.Borders) {
+
+					File.WriteAllLines(
+						this.Output,
+						from path in paths
+						from line in File.ReadLines(path)
+						select line);
+
+				} else {
+
+					File.WriteAllLines(
+						this.Output,
+						paths.SelectMany(path =>
+							(new string[] {
+								"/* BEGIN: " + path + " */"
+							})
+							.Concat(File.ReadLines(path))
+							.Concat(new string[] {
+								"/* END: " + path + " */"
+							})));
+
+				}
+			}
+
+			return !this.Log.HasLoggedErrors;
+		}
+	}
+}

MinCat.MSBuild/Models/ILog.cs

+ďťżnamespace MinCat.MSBuild.Models {
+	using System;
+
+	/// <summary>
+	/// Define the logging interface, usually filled by MSBuild's TaskLogger.
+	/// </summary>
+	public interface ILog {
+
+		/// <summary>
+		/// Gets a value indicating whether any errors have been logged.
+		/// </summary>
+		bool HasLoggedErrors { get; }
+
+		/// <summary>
+		/// Log a message.
+		/// </summary>
+		/// <param name="message">The message to log.</param>
+		/// <param name="messageArgs">
+		/// Variables to fill into the message's placeholders.
+		/// </param>
+		void LogMessage(string message, params object[] messageArgs);
+
+		/// <summary>
+		/// Log an error message.
+		/// </summary>
+		/// <param name="message">The message to log.</param>
+		/// <param name="messageArgs">
+		/// Variables to fill into the message's placeholders.
+		/// </param>
+		void LogError(string message, params object[] messageArgs);
+
+		/// <summary>
+		/// Log an error message from an exception.
+		/// </summary>
+		/// <param name="exception">The exception</param>
+		/// <param name="showStackTrace">True to show a stack trace.</param>
+		void LogErrorFromException(Exception exception, bool showStackTrace);
+	}
+}

MinCat.MSBuild/Models/Minimize.cs

+ďťżnamespace MinCat.MSBuild.Models {
+	using System;
+	using System.Collections.Generic;
+	using System.IO;
+	using System.Linq;
+	using MinCat;
+	using MinCat.Exception;
+	using MinCat.MSBuild.Compressors;
+	using MinCat.MSBuild.Exceptions;
+	using MinCat.MSBuild.Properties;
+	using MinCat.MSBuild.Util;
+
+	/// <summary>
+	/// Minimizes JavaScript files.
+	/// </summary>
+	public class Minimize {
+
+		/// <summary>
+		/// Gets or sets a logging interface.
+		/// </summary>
+		public ILog Log {
+			get;
+			set;
+		}
+
+		/// <summary>
+		/// Gets or sets the input glob used to locate files to minimize.
+		/// </summary>
+		public string Input {
+			get;
+			set;
+		}
+
+		/// <summary>
+		/// Gets or sets a value indicating whether borders should be inserted
+		/// into the resulting concatenated file. The borders will mark the end
+		/// of one file and beginning of another file. These are safe for use
+		/// with both JavaScript and CSS files.
+		/// </summary>
+		public bool Borders {
+			get;
+			set;
+		}
+
+		/// <summary>
+		/// Gets or sets the path to the root of this website. This is used to
+		/// resolve rooted relative paths. This defaults to the same folder as
+		/// the project file.
+		/// </summary>
+		public string WebRoot {
+			get;
+			set;
+		}
+
+		/// <summary>
+		/// Gets or sets the output path into which minimized files will be
+		/// placed.
+		/// </summary>
+		public string Outpath {
+			get;
+			set;
+		}
+
+		/// <summary>
+		/// Gets or sets the pattern used to generate the output filename.
+		/// </summary>
+		public string FilePattern {
+			get;
+			set;
+		}
+
+		/// <summary>
+		/// Minimize the specified files.
+		/// </summary>
+		/// <returns>True if all files were minimized successfully.</returns>
+		public bool Execute() {
+			this.ValidateParameters();
+
+			RootFile[] files = this.ListFiles(this.Input);
+
+			if (files.Length == 0) {
+				if (!this.Log.HasLoggedErrors) {
+					this.Log.LogMessage(
+						Resources.FilesAreUpToDate,
+						this.Input);
+
+					return true;
+				}
+
+				return false;
+			}
+
+			this.Log.LogMessage(Resources.MinimizingFile, this.Input);
+
+			Compressor compressor = new YUICompressor(this.Log);
+
+			foreach (var file in files) {
+				if (!this.CompressFile(compressor, file)) {
+					return false;
+				}
+			}
+
+			return !this.Log.HasLoggedErrors;
+		}
+
+		/// <summary>
+		/// Validate the parameters passed into this task, assigning default
+		/// values if necessary.
+		/// </summary>
+		private void ValidateParameters() {
+
+			this.WebRoot = string.IsNullOrEmpty(this.WebRoot) ?
+				Directory.GetCurrentDirectory() :
+				Path.GetFullPath(this.WebRoot);
+
+			if (string.IsNullOrEmpty(this.FilePattern)) {
+				this.FilePattern =
+					MinCat.Properties.Settings.Default.DefaultFilePattern;
+			}
+
+			if (string.IsNullOrEmpty(this.Outpath)) {
+				this.Outpath =
+					MinCat.Properties.Settings.Default.DefaultOutPath;
+			}
+		}
+
+		/// <summary>
+		/// Compress a RootFile using the provided compression engine.
+		/// </summary>
+		/// <param name="compressor">The compression engine to use.</param>
+		/// <param name="file">The file to be compressed.</param>
+		/// <returns>
+		/// True if the compression succeeded; otherwise false.
+		/// </returns>
+		private bool CompressFile(Compressor compressor, RootFile file) {
+
+			this.Log.LogMessage("\t" + Path.GetFileName(file.AbsolutePath));
+			PreparedFile prepared = null;
+
+			try {
+				prepared = new PreparedFile(file, this.Borders);
+				compressor.Compress(prepared);
+			} catch (CompressionException ex) {
+
+				this.Log.LogErrorFromException(
+					ex,
+					!string.IsNullOrEmpty(ex.StackTrace));
+
+				return false;
+
+			} finally {
+				if (prepared != null) {
+					prepared.Dispose();
+				}
+			}
+
+			return true;
+		}
+
+		/// <summary>
+		/// Provides a list of files as described by the given glob-syntax,
+		/// if they need to be minimized.
+		/// </summary>
+		/// <param name="glob">The glob to expand</param>
+		/// <returns>A list of files described by the glob.</returns>
+		private RootFile[] ListFiles(string glob) {
+			try {
+
+				return (glob.Contains("*") ?
+					this.ListGlobFiles(glob) :
+					this.ListSingleFile(glob))
+					.Where(file => file.NeedsMinimization)
+					.ToArray();
+
+			} catch (RecursiveReferenceException ex) {
+				this.Log.LogErrorFromException(ex, true);
+			} catch (System.IO.IOException ex) {
+				this.Log.LogErrorFromException(ex, false);
+			}
+
+			return new RootFile[0];
+		}
+
+		/// <summary>
+		/// Provide a list of ScriptFile objects from the specified glob-
+		/// syntax.
+		/// </summary>
+		/// <param name="glob">
+		/// The path to the file that includes a glob.
+		/// </param>
+		/// <returns>A list of matching ScriptFile objects.</returns>
+		private IEnumerable<RootFile> ListGlobFiles(string glob) {
+
+			int idx = glob.LastIndexOf(Path.DirectorySeparatorChar) + 1;
+			string head = glob.Substring(0, idx);
+			string tail = glob.Substring(idx);
+
+			if (
+				head.StartsWith("/", StringComparison.OrdinalIgnoreCase) ||
+					head.StartsWith(
+						"\\", StringComparison.OrdinalIgnoreCase))
+			{
+				head = this.WebRoot;
+			}
+
+			return Directory.GetFiles(head, tail).Select(path =>
+				new RootFile(
+					path,
+					RootFile.GetMinimizedPath(
+						path,
+						this.Outpath,
+						this.FilePattern),
+					this.WebRoot));
+		}
+
+		/// <summary>
+		/// Generate a list of ScriptFile objects from a path that specifies
+		/// only a single file.
+		/// </summary>
+		/// <param name="filePath">The path to the source file.</param>
+		/// <returns>The ScriptFile that describes the source file.</returns>
+		private IEnumerable<RootFile> ListSingleFile(string filePath) {
+
+			if (
+				filePath.StartsWith("/", StringComparison.OrdinalIgnoreCase) ||
+					filePath.StartsWith(
+						"\\", StringComparison.OrdinalIgnoreCase))
+			{
+				filePath = this.WebRoot +
+					Path.DirectorySeparatorChar +
+					filePath.Substring(1);
+			}
+
+			filePath = Path.GetFullPath(filePath);
+
+			string minimizedPath = RootFile.GetMinimizedPath(
+				filePath,
+				this.Outpath,
+				this.FilePattern);
+
+			return new RootFile[] {
+				new RootFile(filePath, minimizedPath, this.WebRoot)
+			};
+		}
+	}
+}

MinCat.MSBuild/Models/TaskLogger.cs

+ďťżnamespace MinCat.MSBuild {
+	using System;
+	using Microsoft.Build.Utilities;
+	using MinCat.MSBuild.Models;
+
+	/// <summary>
+	/// Wrapper around <see cref="TaskLoggingHelper" /> for use outside of a
+	/// testing environment.
+	/// </summary>
+	internal class TaskLogger : ILog {
+
+		/// <summary>
+		/// The <see cref="TaskLoggingHelper" /> to use.
+		/// </summary>
+		private TaskLoggingHelper log;
+
+		/// <summary>
+		/// Initializes a new instance of the <see cref="TaskLogger" /> class.
+		/// </summary>
+		/// <param name="log">The task logger to use.</param>
+		public TaskLogger(TaskLoggingHelper log) {
+			this.log = log;
+		}
+
+		#region ILog Members
+
+		/// <summary>
+		/// Gets a value indicating whether any errors have been logged.
+		/// </summary>
+		public bool HasLoggedErrors {
+			get {
+				return this.log.HasLoggedErrors;
+			}
+		}
+
+		/// <summary>
+		/// Log a message.
+		/// </summary>
+		/// <param name="message">The message to log.</param>
+		/// <param name="messageArgs">
+		/// Variables to fill into the message's placeholders.
+		/// </param>
+		public void LogMessage(string message, params object[] messageArgs) {
+			this.log.LogMessage(message, messageArgs);
+		}
+
+		/// <summary>
+		/// Log an error message.
+		/// </summary>
+		/// <param name="message">The message to log.</param>
+		/// <param name="messageArgs">
+		/// Variables to fill into the message's placeholders.
+		/// </param>
+		public void LogError(string message, params object[] messageArgs) {
+			this.log.LogError(message, messageArgs);
+		}
+
+		/// <summary>
+		/// Log an error message from an exception.
+		/// </summary>
+		/// <param name="exception">The exception</param>
+		/// <param name="showStackTrace">True to show a stack trace.</param>
+		public void LogErrorFromException(
+			Exception exception,
+			bool showStackTrace)
+		{
+			this.log.LogErrorFromException(exception, showStackTrace);
+		}
+
+		#endregion
+	}
+}

MinCat.MSBuild/Properties/AssemblyInfo.cs

+ďťżusing System.Reflection;
+using System.Resources;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("MinCat.MSBuild")]
+[assembly: AssemblyDescription("Provides an MSBuild task for MinCat.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Chris Nielsen")]
+[assembly: AssemblyProduct("MinCat.MSBuild")]
+[assembly: AssemblyCopyright("Copyright Š  2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("17578433-a098-4a2a-8205-06cfa217f2ad")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: System.CLSCompliant(true)]
+[assembly: NeutralResourcesLanguageAttribute("en")]

MinCat.MSBuild/Properties/Resources.Designer.cs

+ďťż//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.269
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace MinCat.MSBuild.Properties {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MinCat.MSBuild.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Creating {0} from:.
+        /// </summary>
+        internal static string CreatingFile {
+            get {
+                return ResourceManager.GetString("CreatingFile", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to {0} could not be found..
+        /// </summary>
+        internal static string FileNotFound {
+            get {
+                return ResourceManager.GetString("FileNotFound", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Not minimizing {0} because all output files are up-to-date with respect to the input files..
+        /// </summary>
+        internal static string FilesAreUpToDate {
+            get {
+                return ResourceManager.GetString("FilesAreUpToDate", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Minimizing {0}:.
+        /// </summary>
+        internal static string MinimizingFile {
+            get {
+                return ResourceManager.GetString("MinimizingFile", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Java must be installed..
+        /// </summary>
+        internal static string NeedJavaInstalled {
+            get {
+                return ResourceManager.GetString("NeedJavaInstalled", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Using YUICompressor 2.4.6.
+        /// </summary>
+        internal static string UsingYUICompressor {
+            get {
+                return ResourceManager.GetString("UsingYUICompressor", resourceCulture);
+            }
+        }
+    }
+}

MinCat.MSBuild/Properties/Resources.resx

+ďťż<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="CreatingFile" xml:space="preserve">
+    <value>Creating {0} from:</value>
+  </data>
+  <data name="FileNotFound" xml:space="preserve">
+    <value>{0} could not be found.</value>
+  </data>
+  <data name="FilesAreUpToDate" xml:space="preserve">
+    <value>Not minimizing {0} because all output files are up-to-date with respect to the input files.</value>
+  </data>
+  <data name="MinimizingFile" xml:space="preserve">
+    <value>Minimizing {0}:</value>
+  </data>
+  <data name="NeedJavaInstalled" xml:space="preserve">
+    <value>Java must be installed.</value>
+  </data>
+  <data name="UsingYUICompressor" xml:space="preserve">
+    <value>Using YUICompressor 2.4.6</value>
+  </data>
+</root>

MinCat.MSBuild/Properties/VersionInfo.base.cs

+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+
+[assembly: SuppressMessage(
+	"Microsoft.Usage",
+	"CA2243:AttributeStringLiteralsShouldParseCorrectly",
+	Justification =
+		"Necessary to sync application version with source control.")]
+
+[assembly: AssemblyInformationalVersion("1.0 ($REVID$.$DIRTY$)")]

MinCat.MSBuild/Properties/VersionInfo.cs

+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+
+[assembly: SuppressMessage(
+	"Microsoft.Usage",
+	"CA2243:AttributeStringLiteralsShouldParseCorrectly",
+	Justification =
+		"Necessary to sync application version with source control.")]
+
+[assembly: AssemblyInformationalVersion("1.0 (b1b5af0aa478.1)")]

MinCat.MSBuild/Util/PreparedFile.cs

+ďťżnamespace MinCat.MSBuild.Util {
+	using System;
+	using System.IO;
+	using System.Linq;
+	using MinCat;
+
+	/// <summary>
+	/// A file containing the results of concatenating all requested script
+	/// files into a single document.
+	/// </summary>
+	internal class PreparedFile : IDisposable {
+
+		/// <summary>
+		/// Gets the absolute path to the prepared source file.
+		/// </summary>
+		internal string Source {
+			get;
+			private set;
+		}
+
+		/// <summary>
+		/// Gets the absolute path to the destination minimized file.
+		/// </summary>
+		internal string Destination {
+			get;
+			private set;
+		}
+
+		/// <summary>
+		/// Initializes a new instance of the PreparedFile class using the
+		/// provided RootFile as a source.
+		/// </summary>
+		/// <param name="rootFile">
+		/// The RootFile that will be prepared.
+		/// </param>
+		/// <param name="borders">
+		/// Include file demarcation borders in the output file.
+		/// </param>
+		internal PreparedFile(RootFile rootFile, bool borders) {
+			this.Source = Path.GetTempFileName();
+
+			this.Destination = rootFile.AbsoluteMinimizedPath;
+
+			File.WriteAllLines(
+				this.Source,
+				rootFile.RequiredFiles.SelectMany(file => file.ReadLines(borders)));
+		}
+
+		#region IDisposable Members
+
+		/// <summary>
+		/// Track whether Dispose has been called.
+		/// </summary>
+		private bool disposed = false;
+
+		/// <summary>
+		/// Implement IDisposable.
+		/// </summary>
+		public void Dispose() {
+			this.Dispose(true);
+			GC.SuppressFinalize(this);
+		}
+
+		/// <summary>
+		/// Finalizes an instance of the PreparedFile class.
+		/// </summary>
+		~PreparedFile() {
+			this.Dispose(false);
+		}
+
+		/// <summary>
+		/// <para>Dispose(bool disposing) executes in two distinct scenarios.
+		/// </para>
+		/// <para>If disposing equals true, the method has been called directly
+		/// or indirectly by a user's code. Managed and unmanaged resources can
+		/// be disposed.</para>
+		/// <para>If disposing equals false, the method has been called by the
+		/// runtime from inside the finalizer and you should not reference
+		/// other objects. Only unmanaged resources can be disposed.</para>
+		/// </summary>
+		/// <param name="disposing">
+		/// True to dispose of both managed and unmanaged resources.
+		/// </param>
+		protected virtual void Dispose(bool disposing) {
+			if (this.disposed == false) {
+				if (disposing) {
+					// Dispose of managed resources here.
+					// We have none in this case.
+				}
+
+				// Dispose of unmanaged resources here.
+				File.Delete(this.Source);
+			}
+		}
+
+		#endregion
+	}
+}

MinCat.MSBuild/app.config

+ďťż<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+</configuration>

MinCat.MVC/MinCat.MVC.cs

+ďťżnamespace MinCat.MVC {
+	using System.IO;
+	using System.Linq;
+	using System.Web;
+	using System.Web.Mvc;
+	using MinCat;
+
+	/// <summary>
+	/// Extension methods for HtmlHelper to load script files that may contain
+	/// require or include directives.
+	/// </summary>
+	public static class Extensions {
+
+		/// <summary>
+		/// Generate the script tags necessary to load the requested file.
+		/// </summary>
+		/// <param name="helper">HtmlHelper instance to extend.</param>
+		/// <param name="src">Relative path to the script file.</param>
+		/// <param name="minimize">
+		/// True to load the minimized version of the file; false to load the
+		/// development version of the file.  Omit to load the minimized
+		/// version for live sites and development version for development
+		/// sites.
+		/// </param>
+		/// <returns>One or many script tags.</returns>
+		public static IHtmlString Script(
+			this HtmlHelper helper,
+			string src,
+			bool? minimize = null)
+		{
+
+			string absolutePath =
+				helper.ViewContext.HttpContext.Server.MapPath(src);
+
+			string minPath =
+				RootFile.GetMinimizedPath(
+					absolutePath,
+					MinCat.Properties.Settings.Default.DefaultOutPath,
+					MinCat.Properties.Settings.Default.DefaultFilePattern);
+
+			bool min;
+
+			if (minimize.HasValue) {
+				min = minimize.Value;
+			} else {
+				#if DEBUG
+					min = false;
+				#else
+					min = true;
+				#endif
+			}
+
+			if (min) {
+				return Extensions.MinimizedFile(minPath);
+			}
+
+			var rootFile = new RootFile(
+				absolutePath,
+				minPath,
+				HttpRuntime.AppDomainAppPath);
+
+			return new HtmlString(string.Join(
+				"\n",
+				rootFile.RequiredFiles.Select(Extensions.MapFileToTag)));
+		}
+
+		/// <summary>
+		/// If we are loading the minimized version, assume that MinCat will
+		/// have produced the minimized file as part of the build process.
+		/// Therefore, we just change the filename so it points to the compiled
+		/// version.
+		/// </summary>
+		/// <param name="minPath">
+		/// The path to the minimized version of the file.
+		/// </param>
+		/// <returns>
+		/// A script tag pointing to the minimized version of the file.
+		/// </returns>
+		private static IHtmlString MinimizedFile(string minPath) {
+			string type = Path.GetExtension(minPath).ToUpperInvariant();
+			minPath = Extensions.GetRootRelativePath(minPath);
+			TagBuilder tag;
+
+			if (type == ".JS") {
+				tag = new TagBuilder("script");
+				tag.Attributes.Add("type", "text/javascript");
+				tag.Attributes.Add("src", minPath);
+			} else {
+				tag = new TagBuilder("link");
+				tag.Attributes.Add("rel", "stylesheet");
+				tag.Attributes.Add("type", "text/css");
+				tag.Attributes.Add("src", minPath);
+			}
+
+			return new HtmlString(tag.ToString());
+		}
+
+		/// <summary>
+		/// Create a script tag that references the given ScriptFile instance.
+		/// </summary>
+		/// <param name="file">The ScriptFile instance.</param>
+		/// <returns>A script tag that references the ScriptFile.</returns>
+		private static string MapFileToTag(ScriptFile file) {
+
+			string type =
+				Path.GetExtension(file.AbsolutePath).ToUpperInvariant();
+
+			TagBuilder tag;
+
+			if (type == ".JS") {
+				tag = new TagBuilder("script");
+				tag.Attributes.Add("type", "text/javascript");
+
+				if (file.HasIncludes == false) {
+					tag.Attributes.Add(
+						"src",
+						Extensions.GetRootRelativePath(file.AbsolutePath));
+
+				} else {
+					tag.InnerHtml = string.Join("\r\n", file.ReadLines(true));
+				}
+
+			// File must be a CSS file.
+			} else if (file.HasIncludes == false) {
+				tag = new TagBuilder("link");
+				tag.Attributes.Add("rel", "stylesheet");
+				tag.Attributes.Add("type", "text/css");
+				tag.Attributes.Add(
+					"href",
+					Extensions.GetRootRelativePath(file.AbsolutePath));
+
+				return tag.ToString(TagRenderMode.SelfClosing);
+			} else {
+				tag = new TagBuilder("style");
+				tag.Attributes.Add("type", "text/css");
+				tag.InnerHtml = string.Join("\r\n", file.ReadLines(true));
+			}
+
+			return tag.ToString();
+		}
+
+		/// <summary>
+		/// Get a root-relative path from the provided absolute path.
+		/// </summary>
+		/// <param name="absolutePath">The absolute path to transform.</param>
+		/// <returns>A path relative to the root of this website.</returns>
+		private static string GetRootRelativePath(string absolutePath) {
+			return VirtualPathUtility.ToAbsolute("~" + absolutePath
+				.Substring(HttpRuntime.AppDomainAppPath.Length - 1)
+				.Replace(
+					Path.DirectorySeparatorChar,
+					Path.AltDirectorySeparatorChar));
+		}
+	}
+}

MinCat.MVC/MinCat.MVC.csproj

+ďťż<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <UsingTask TaskName="HgVersionFile" AssemblyFile="..\Resources\MSBuildVersioning.dll" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{70D8571D-4753-4CC0-84F5-CF1A3F854B70}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>MinCat.MVC</RootNamespace>
+    <AssemblyName>MinCat.MVC</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>..\Code Analysis.ruleset</CodeAnalysisRuleSet>
+    <DocumentationFile>bin\Debug\MinCat.MVC.XML</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>bin\Release\MinCat.MVC.XML</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>MinCat.MVC.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Web" />
+    <Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
+    <Reference Include="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="MinCat.MVC.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <None Include="Properties\VersionInfo.base.cs" />
+    <Compile Include="Properties\VersionInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\MinCat\MinCat.csproj">
+      <Project>{31CFD0F2-99C5-4919-8178-73EE4F61BE8E}</Project>
+      <Name>MinCat</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config" />
+    <None Include="MinCat.MVC.snk" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Target Name="BeforeBuild">
+    <HgVersionFile TemplateFile="Properties\VersionInfo.base.cs" DestinationFile="Properties\VersionInfo.cs" />
+  </Target>
+</Project>

MinCat.MVC/MinCat.MVC.snk

Binary file added.

MinCat.MVC/Properties/AssemblyInfo.cs

+ďťżusing System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("MinCat.MVC")]
+[assembly: AssemblyDescription("MinCat MVC Helper")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Chris Nielsen")]
+[assembly: AssemblyProduct("MinCat.MVC")]
+[assembly: AssemblyCopyright("Copyright Š Chris Nielsen 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ce4773e5-2101-4741-ac6f-e66f0dfc1dd4")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: System.CLSCompliant(true)]

MinCat.MVC/Properties/VersionInfo.base.cs

+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+
+[assembly: SuppressMessage(
+	"Microsoft.Usage",
+	"CA2243:AttributeStringLiteralsShouldParseCorrectly",
+	Justification =
+		"Necessary to sync application version with source control.")]
+
+[assembly: AssemblyInformationalVersion("1.0 ($REVID$.$DIRTY$)")]

MinCat.MVC/Properties/VersionInfo.cs

+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+
+[assembly: SuppressMessage(
+	"Microsoft.Usage",
+	"CA2243:AttributeStringLiteralsShouldParseCorrectly",
+	Justification =
+		"Necessary to sync application version with source control.")]
+
+[assembly: AssemblyInformationalVersion("1.0 (b1b5af0aa478.1)")]

MinCat.MVC/app.config

+<?xml version="1.0"?>
+<configuration>
+<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

MinCat.MVC/bin/Release/Compressors/YUICompressor/LICENSE.TXT

+YUI Compressor Copyright License Agreement (BSD License)
+
+Copyright (c) 2010, Yahoo! Inc.
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of Yahoo! Inc. nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of Yahoo! Inc.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+This software also requires access to software from the following sources:
+
+The Jarg Library v 1.0 ( http://jargs.sourceforge.net/ ) is available
+under a BSD License – Copyright (c) 2001-2003 Steve Purcell,
+Copyright (c) 2002 Vidar Holen, Copyright (c) 2002 Michal Ceresna and
+Copyright (c) 2005 Ewan Mellor.
+
+The Rhino Library ( http://www.mozilla.org/rhino/ ) is dually available
+under an MPL 1.1/GPL 2.0 license, with portions subject to a BSD license.
+
+Additionally, this software contains modified versions of the following
+component files from the Rhino Library:
+
+[org/mozilla/javascript/Decompiler.java]
+[org/mozilla/javascript/Parser.java]
+[org/mozilla/javascript/Token.java]
+[org/mozilla/javascript/TokenStream.java]
+
+The modified versions of these files are distributed under the MPL v 1.1
+( http://www.mozilla.org/MPL/MPL-1.1.html )

MinCat.MVC/bin/Release/Compressors/YUICompressor/yuicompressor-2.4.6.jar

Binary file added.

MinCat.MVC/bin/Release/MinCat.dll

Binary file added.

MinCat.MVC/bin/Release/MinCat.pdb

Binary file added.

MinCat.MVC/bin/Release/MinCatMVC.dll

Binary file added.

MinCat.MVC/bin/Release/MinCatMVC.dll.config

+<?xml version="1.0"?>
+<configuration>
+<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

MinCat.MVC/bin/Release/MinCatMVC.pdb

Binary file added.

MinCat.Tests/MinCat.Tests.csproj

     <AssemblyOriginatorKeyFile>MinCat.Tests.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+    <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
     <Reference Include="System" />
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <Compile Include="MinimizeTest.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <None Include="MinCat.Tests.snk" />
     <None Include="Properties\VersionInfo.base.cs" />
     <Compile Include="Properties\VersionInfo.cs" />
     <Compile Include="RootFileTest.cs" />
     <Compile Include="Models\TestLogger.cs" />
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="..\MinCatMSBuild\MinCatMSBuild.csproj">
+    <ProjectReference Include="..\MinCat.MSBuild\MinCat.MSBuild.csproj">
       <Project>{88880969-1AC9-4015-832F-75E67183FD3F}</Project>
-      <Name>MinCatMSBuild</Name>
+      <Name>MinCat.MSBuild</Name>
     </ProjectReference>