Compacting CSS on-the-fly

July 2nd, 2009

I’m currently doing quite a lot of work on my ny MVC-version of Imager Gallery. I still have a lot to do before I have anything to release (or even use myself) though but I thought I could release a few snippets that I’ve found useful.

First out is a HttpHandler that will process .css-files and remove any unused whitespace from the file before sending it to the client. I’ve been meaning to write this for a long time but never really had the time until someone posted a link about it over at ASPSidan.se showing their own implementation. Reading up on his post about it I found that it was based on a solution by Sam Collett. Both implementations lacked a few things that I wanted to have so I sat down with Sams code and started improving it, mainly making it a work as a handler for .css-files instead of a Generic Handler wanting a querystring but also adding caching and compiling the regular expression as a static member.

To use this, just pop it in a .cs-file in your your App_Code folder and add it to your web.config (as described in the comments for the class). You also need to configure your IIS to route .css-files through the asp.net process to make it run (not needed under IIS7 or IIS6 configured for MVC). Hope you find it useful!

using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Caching;

namespace HttpHandlers
{
    /// <summary>
    /// Handler for compacting css-files on the fly
    /// Based on solution by Sam Collett found at
    /// http://webdevel.blogspot.com/2007/09/csscompact-webhandler-for-shrinking-css.html
    ///
    /// Needs to be added to web.config under System.Web/httpHandlers like this
    /// <add verb="GET,HEAD" path="*.css" type="HttpHandlers.CssCompactHandler"/>
    ///
    /// For debuing purposes you can append a querystring whenbrowsing to your .css-file
    /// to skip the compacting. It would look like this:
    /// http://mySite/Content/Site.css?noCompact=1
    /// </summary>
    public class CssCompactHandler : IHttpHandler
    {
        // Staticly compiled regex to avoid compiling it each request
        private static Regex RegexRemoval = new Regex(@"^\s+|/\*([^*\\\\]|\*(?!/))+\*/|\r|\n|\t", RegexOptions.Multiline | RegexOptions.Compiled);

        public void ProcessRequest(HttpContext context)
        {
            HttpResponse Response = context.Response;
            HttpRequest Request = context.Request;
            Cache Cache = context.Cache;

            FileInfo fileInfo = new FileInfo(Request.PhysicalPath);
            if (!fileInfo.Exists)
            {
                Response.StatusDescription = "The server has not found anything that matches the requested URI.";
                Response.StatusCode = 404;
                Response.End();
            }

            Response.ContentType = "text/css";
            Response.Cache.SetLastModified(fileInfo.LastWriteTime);

            // If we are in debugmode (set in web.config) then
            // we dont want to cache the css since we are probably
            // still in development
            if (context.IsDebuggingEnabled)
            {
                Response.Cache.SetCacheability(HttpCacheability.NoCache);
            }
            else
            {
                Response.Cache.SetCacheability(HttpCacheability.Public);
                Response.Cache.SetExpires(DateTime.Now.AddDays(1));
            }

            // HEAD requests only need the headers so we skip the
            // content here
            if (Request.HttpMethod != "HEAD")
            {
                string cacheName = string.Format("CssCompactHandlerCache_{0}", fileInfo.FullName);
                string cacheValue = Cache[cacheName] as string;
                if (cacheValue != null && Request.QueryString["noCompact"] == null)
                {
                    Response.Write(cacheValue);
                    Response.End();
                }

                using (StreamReader cssStream = fileInfo.OpenText())
                {
                    string cssContent = cssStream.ReadToEnd();
                    if (Request.QueryString["noCompact"] == null)
                    {
                        cssContent = RegexRemoval.Replace(cssContent, "");

                        // Set up a CacheDependency on the css-file,
                        // this way the cache will be invalidated if
                        // we change the file
                        CacheDependency dependency = new CacheDependency(fileInfo.FullName);
                        Cache.Add(string.Format("CssCompactHandlerCache_{0}", fileInfo.FullName), cssContent, dependency, DateTime.Now.AddYears(1), Cache.NoSlidingExpiration, CacheItemPriority.AboveNormal, null);
                    }
                    Response.Write(cssContent);
                }
            }
        }

        public bool IsReusable
        {
            get
            {
                return true;
            }
        }
    }
}

Uncategorized , , , , , , , ,

RFC2047 decoder in C#

June 17th, 2009

Just spent the evening writing a class to decode RFC2047 strings in C#. It was requested by a user on ASPSidan, a Swedish site dedicated to ASP, ASP.Net and other Microsoft technologies but before I was done someone had already found another implementation on the net. Anyway, the code shouldn’t go to waste so I’m posting it here if anyone needs it.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Globalization;

namespace CrazyBeavers.Net.Mail
{
    public static class RFC2047Decoder
    {
        public static string Parse(string input)
        {
            StringBuilder sb = new StringBuilder();
            StringBuilder currentWord = new StringBuilder();
            bool readingWord = false;

            Int32 i = 0;
            while (i < input.Length)
            {
                char currentChar = input[i];
                char peekAhead;
                switch (currentChar)
                {
                    case '=':
                        peekAhead = (i == input.Length - 1) ? ' ' : input[i + 1];

                        if (peekAhead == '?')
                            readingWord = true;
                        break;

                    case '?':
                        peekAhead = (i == input.Length - 1) ? ' ' : input[i + 1];

                        if (peekAhead == '=')
                        {
                            readingWord = false;

                            currentWord.Append(currentChar);
                            currentWord.Append(peekAhead);

                            sb.Append(ParseEncodedWord(currentWord.ToString()));
                            currentWord = new StringBuilder();

                            i += 2;
                            continue;
                        }
                        break;
                }

                if (readingWord)
                {
                    currentWord.Append(currentChar);
                    i++;
                }
                else
                {
                    sb.Append(currentChar);
                    i++;
                }
            }

            return sb.ToString();
        }

        private static string ParseEncodedWord(string input)
        {
            StringBuilder sb = new StringBuilder();

            if (!input.StartsWith("=?"))
                return input;

            if (!input.EndsWith("?="))
                return input;

            // Get the name of the encoding but skip the leading =?
            string encodingName = input.Substring(2, input.IndexOf("?", 2) - 2);
            Encoding enc = Encoding.GetEncoding(encodingName);

            // Get the type of the encoding
            char type = input[encodingName.Length + 3];

            // Start after the name of the encoding and the other required parts
            Int32 i = encodingName.Length + 5;

            switch (char.ToLowerInvariant(type))
            {
                case 'q':
                    while (i < input.Length)
                    {
                        char currentChar = input[i];
                        char[] peekAhead = new char[2];
                        switch (currentChar)
                        {
                            case '=':
                                peekAhead = (i >= input.Length - 2) ? null : new char[] { input[i + 1], input[i + 2] };

                                if (peekAhead == null)
                                    break;

                                string decodedChar = enc.GetString(new byte[] { Convert.ToByte(new string(peekAhead, 0, 2), 16) });
                                sb.Append(decodedChar);
                                i += 3;
                                break;
                            case '?':
                                if (input[i + 1] == '=')
                                    i += 2;
                                break;
                            default:
                                sb.Append(currentChar);
                                i++;
                                break;
                        }
                    }
                    break;
                case 'b':
                    string baseString = input.Substring(i, input.Length - i - 2);
                    byte[] baseDecoded = Convert.FromBase64String(baseString);
                    sb.Append(enc.GetString(baseDecoded));
                    break;
            }
            return sb.ToString();
        }
    }
}

.Net, Code samples, c# , , , ,

Panoramic picture of Brahehus, Jönköping

June 5th, 2009

Just thought I would post this lovely picture I took during my travel down to Sölvesborg and Sweden Rock Festival 2009. It was taken a few miles north of Jönköping and is composed of six or seven pictues that was merged using Photoshop to get a full panoramic picture.

It seems that Zoomify decreases the quality of the images quite severely but I’m afraid it will have to do with that. I’ll see if I can upload the original picture later on when I get on a faster connection (it took me half an hour to upload the Zoomify images).

Photography , ,

Disabling “Missing XML comment for publicly visible type or member XX”

May 24th, 2009

Adding descriptive comments to your code is something that everyone will always tell you to do though in reality many people simply don’t do it. Some are just lazy, some doesn’t see the need of it, some are to stressed out to do it and some things that the c# compiler will warn you about just doesn’t need commenting. Looking at the last category, things that just doesn’t need commenting, we many times find enums. Look at this as a sample.

/// <summary>
///  Datatypes used by the EXIF specification
/// </summary>
public enum ExifDataTypes
{
	UnsignedByte = 1,
	AsciiString = 2,
	UnsignedShort = 3,
	UnsignedLong = 4,
	UnsignedRational = 5,
	SignedByte = 6,
	Undefined = 7,
	SignedShort = 8,
	SignedLong = 9,
	SignedRational = 10,
	SingleFloat = 11,
	DoubleFloat = 12
}

What useful comments could added to this? When compiling I’m getting twelve warnings about this code not being documented though I do have a hard time finding out what I should write about each option since I feel that the names are quite self explanatory. Just adding a dummy comment to each line would get rid of the warnings but also clutter up my code which isn’t really helping me. I could also tell the compiler to ignore all warnings of this type (”/nowarn 1591″ when compiling) though there might be other places in my code where I want to know that I missed a comment.

So no luck just yet. There is however a third method to use. Going back to C there has been a way to communicate with the compiler from your code using directives called “pragmas”. C# have it as well though the standard compiler (csc.exe) only understands two commands, warning and checksum. For my problem, warning was the one I could use.

The code below has a pragma added that tells the compiler not to raise warnings with id 1591 (missing comments) from line 6 to line 19.

/// <summary>
///  Datatypes used by the EXIF specification
/// </summary>
public enum ExifDataTypes
{
#pragma warning disable 1591
	UnsignedByte = 1,
	AsciiString = 2,
	UnsignedShort = 3,
	UnsignedLong = 4,
	UnsignedRational = 5,
	SignedByte = 6,
	Undefined = 7,
	SignedShort = 8,
	SignedLong = 9,
	SignedRational = 10,
	SingleFloat = 11,
	DoubleFloat = 12
#pragma warning restore 1591
}

It still gives me lots of warnings (still have some huge enums for the EXIF class that needs this) but now I have a chance of finding the real warnings and still document the parts of my code that really needs documenting.

.Net, Articles, Code samples, c# , , ,

For each (FOR IN) dropped file in batchfile

May 20th, 2009

I’m a huge fan of batchfiles (.bat) in Windows. They are usually so simple to write and can help you out with automating tasks that otherwise would be a pain in your ass. As an example, here is a little file I’ve set up at work for my coworkers to be able to convert movieclips to .wmv.

@echo off
"J:\PathToOurMovieArchive\ffmpeg.exe" -i %1 -b 1024k -vcodec wmv2 -acodec wmav2 -ar 44100 -ab 48000 -ac 1 -y %1-convertedHQ.wmv
pause

It’s simple enough. Don’t output anything and then execute ffmpeg,exe with the specified parameters taking the first of the dropped files as input. Works great and produces a wmv-movieclip in the same folder as the original file. The problem with this file is that it if you drop two files on this batch it will only convert the first one, which forces you to drag them one by one and then have them run simultaneously which might not be desirable on a slow computer.

To solve this problem I went to the allmight Google and found the FOR IN command. My problem was that it I couldn’t find any samples with it working with dropped files and I couldn’t get it working by just doing FOR %i in (%*). The problem (according to the help for the FOR-command availabile in FOR /?) was that if used in a batchfile I need to designate my variable as %%i instead of %i. After changing that it all worked like charm. So this is how my batchfile ended up, it supports any number of dropped files (well I guess it has a built in limit such as 65335 or something though I’m pretty sure my coworkers won’t drop more then 10 files) and then executes each file in order and not all at once.

@echo off
for %%i in (%*) do "J:\PathToOurMovieArchive\ffmpeg.exe" -i %%i -b 1024k -vcodec wmv2 -acodec wmav2 -ar 44100 -ab 48000 -ac 1 -y %%i-convertedHQ.wmv
pause

I hope that this was to some help for somebody. If you have any other good tips on scripting with batchfiles then please add a comment about it as I’m always eager to learn new things with this great technique.

Code samples, Misc , ,

Fog of war in XNA

January 24th, 2009

Just thought I should show one of the effects I’ve been working on for my towerdefence-game lately. It’s a simple (but quite nice looking) “fog of war” effect that hides any enemies that are out of sight from the towers. I’ve also added a nice radar tower to demonstrate this (with a cool sweep-effect).

The youtube video sucks I’m afraid, it blurs everything down even though I uploaded a really nice looking highres video. Will update this post with a download link for the original video file later on for those interested in seeing what it should look like.

Update: Here is a link to the original video that I submitted to youtube. It looks A LOT better.

xna , , , , , ,

Towerdefence in XNA

December 25th, 2008

Just thought I should write a short one about a current project of mine. I decided that I wanted to try to make a game (a real game, not just that old pong-clone I made while learning C++ all those years ago) and since I work mostly with managed code it felt quite natural to build my game using a managed framework. For those who don’t know about the XNA Framework I would recommend a visit to XNA Creators Club for some more information.

The game I’m working on (with a tiny bit of help of a friend of mine who still has about 70 lines of code that I haven’t touched in the project) is a realtime strategygame built around the towerdefence concept. Some sort of enemies tries to get from point A to point B without getting killed. To kill them you build different types of towers along the way that hurt them in different ways and hopefully enough to not let them through. For each creature that get to point B you lose a life and when enough get there it’s game over for you. If you want to know more about this type of game http://www.towerdefence.net/ is a great place to go looking.

Below is a short video I recorded from the latest build of the game. It currently only features one type of tower and one type of enemy and they both use some placeholder graphics I made in Paint.Net so don’t expect to much of that. If you happen to have some graphics skills and would like to help out then you are very welcome!

And another thing, it’s also best viewed in fullscreen mode since the video was recorded in 800x600 resolution. Hope you enjoy it!

.Net, Beaver, c#, xna , , , ,

State of everything

December 22nd, 2008

It’s been three weeks since I quit my old job now. Three weeks and I finally feel that I’m getting back to coding for the fun of it. I’m currently going through my old projects seeing what needs to be completed, tidying up my svn repositories, fixing this blog (more on that below) and so on. I’m also working on a small techdemo for a small game I’ve been working on with a friend of mine using XNA that hopefully will turn out as a really fun project and a really cool game. More on that in a later post though.

I’ve been doing some work on this blog the last few days, I changed the url to get it closer to my main site, updated Wordpress to 2.7 (whoa, suddenly I’ll want to write things just to see their awsome GUI), added some stubs to articles and codesnippets that I feel I want to post and I’ve finally added my feed to feedburner to get some stats on my subscribers aswell (and avoid the hassle for everyone to change their subscription url if I decide to move again). The new url to subscribe to is http://feeds.feedburner.com/crazybeavers/blog.

Oh, and I’m home sick today so if this post doesn’t make any sense to you I’ll blame it on my cold.

Beaver, Misc , , , , , ,

New url

December 21st, 2008

I’ve decided to move the blog to a new adress at http://blog.crazybeavers.se/. The old url is still valid for a month or so but I decided not to renew the domain. If you subscribe to my rss-feed (yeah right, like someone does) then you’ll have to update the url to that one as soon as possible.

Beaver, Misc , ,

ASP.Net and metadata

December 19th, 2008

Building great websites have several parts to it. First of all you need a great idea of what to fill the site with, then you’ll need some great technology in the background (sloppy code can achieve lots of great things aswell, but you won’t want to go in there and add things afterwards) and then a great presentation to the users of your site. In this article I will touch two parts of this, the technology (ASP.Net) and the presentation (metadata).

First of all I just want to state that I’m not a believer in all the SEO crap thats out there. I simply believe that if you have a great site that people visit and link to it will rank higher in search engines. A great site though will incorporate lots of things that “SEO experts” are chattering about like validating markup, good titles and things like that but that doesn’t mean it is those parts that put it high in the searchresults.

When working on a new version the CMS I use for CrazyBeaver Softwares website I ran into a really disturbing problem with how ASP.Net handles metadata. Look at the sample below.

<head runat="server">
    <title>My website</title>
    <meta name="keywords" content="" />
</head>

It looks alright doesn’t it? Well if you browse to that page you’ll see that the generated source is different.

<head>
    <title>My website</title>
    <meta name="keywords" />
</head>

Where did my content go? Just because it is empty doesn’t mean it can be removed just like that. If you pay a quick visit to www.w3.org and look at the xhtml specification you’ll see that the content attribute is a REQUIRED attribute of the meta element and therefore shouldn’t be removed. Now I hear you say that it shouldn’t matter since it didn’t convey any information anyway and while that is true the removal of that attribute also made sure that the page won’t generate valid html. Sure, it’s a very small error and won’t stop anything that doesn’t require a strict DTD validation to display the page (and no browsers do that since they wouldn’t be able to browse large parts of the web) but start out small and soon you won’t even bother to close tags properly since the page doesn’t validate anyway.

So, this is a behavior of ASP.Net that we need to work around somehow. There are a few choices here. You could simply loop through the HtmlMeta controls during Page_Load and check if they have empty content. It would look something like this.

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        Control[] headerControls = new Control[Page.Header.Controls.Count];
        Page.Header.Controls.CopyTo(headerControls, 0);

        foreach (Control control in headerControls)
        {
            HtmlMeta meta = control as HtmlMeta;

            if (meta == null)
                continue;

            if (string.IsNullOrEmpty(meta.Content))
            {
                Page.Header.Controls.Remove(control);
                break;
            }
        }
    }
}

Does this look as a good enough solution for you? It will do the work needed for most parts (it won’t remove a completely empty meta for some reason though so a <meta name=”" content=”" />will still fail your validation..) but it isn’t the nicest solution since you’ll need to loop through all controls in your header for every pageview that isn’t a postback. Also, maybe you want to specify an empty content for some reason since you have some other piece of code or application that relies on them being there. So what would be a nicer solution? Well writing an adapter of course! In ASP.Net 2.0 they introduced a cool thing called control adapters which basicly let you override the rendering of an existing webcontrol. In this case we will use it to force the HtmlMeta control to always render a content attribute.

using System.Web.UI;
using System.Web.UI.Adapters;
using System.Web.UI.HtmlControls;

namespace CrazyBeavers.Web.UI.Adapters
{
    public class HtmlMetaAdapter : ControlAdapter
    {
        private static string[] _i8nAttributes = new string[] { "lang", "xml:lang", "dir" };

        protected override void Render(HtmlTextWriter writer)
        {
            HtmlMeta meta = this.Control as HtmlMeta;

            writer.WriteBeginTag("meta");

            if (!string.IsNullOrEmpty(meta.HttpEquiv))
                writer.WriteAttribute("http-equiv", meta.HttpEquiv);

            if (!string.IsNullOrEmpty(meta.Scheme))
                writer.WriteAttribute("scheme", meta.Scheme);

            if (!string.IsNullOrEmpty(meta.Name))
                writer.WriteAttribute("name", meta.Name);

            foreach (string attr in meta.Attributes.Keys)
                foreach (string i18n in _i8nAttributes)
                    if (attr.Equals(i18n, System.StringComparison.InvariantCultureIgnoreCase))
                        writer.WriteAttribute(i18n, meta.Attributes[i18n]);

            writer.WriteAttribute("content", meta.Content);

            writer.Write(HtmlTextWriter.SelfClosingTagEnd);
        }
    }
}

Just drop that piece of code in your App_Code or compile it as an assembly and put it in the Bin-folder on your site. There is still one step that needs to be completed for this to work though. All control adapters needs to be referenced via an browser-file in App_Browsers aswell (which is a really cool thing since you can set conditions and use adapters on certain controls for certain browsers, but more on that some other time). Below is a short sample of my Default.browser-file, it doesn’t use any extra features of the browser-file and just say that I want to use my adapter everywhere.

<browsers>
  <browser refID="Default">
    <controladapters>
      <adapter controlType="System.Web.UI.HtmlControls.HtmlMeta"
               adapterType="CrazyBeavers.Web.UI.Adapters.HtmlMetaAdapter" />
    </controladapters>
  </browser>
</browsers>

There you go, now all your MetaCotrol should always render properly for you even though you don’t put any data at all in them. Feel free to comment on this article if you have other solutions or ideas on how to work around this problem.

.Net, Articles, c# , , , , , ,