<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>tech.einaregilsson.com</title>
	<atom:link href="http://tech.einaregilsson.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://tech.einaregilsson.com</link>
	<description></description>
	<pubDate>Fri, 21 Mar 2008 15:31:50 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5</generator>
	<language>en</language>
			<item>
		<title>Subtitle Fixer</title>
		<link>http://tech.einaregilsson.com/2008/03/20/subtitle-fixer/</link>
		<comments>http://tech.einaregilsson.com/2008/03/20/subtitle-fixer/#comments</comments>
		<pubDate>Thu, 20 Mar 2008 13:04:13 +0000</pubDate>
		<dc:creator>einar</dc:creator>
		
		<category><![CDATA[code]]></category>

		<category><![CDATA[python]]></category>

		<category><![CDATA[utilities]]></category>

		<guid isPermaLink="false">http://tech.einaregilsson.com/2008/03/20/subtitle-fixer/</guid>
		<description><![CDATA[I was watching a movie on my computer the other day and I had gotten the subtitles for it off the internet, I think from http://opensubtitles.com or something like that. The only problem was that they were a bit out of sync with the picture, about 2 seconds too late. Using a good media player, [...]]]></description>
			<content:encoded><![CDATA[<p>I was watching a movie on my computer the other day and I had gotten the subtitles for it off the internet, I think from <a href="http://opensubtitles.com">http://opensubtitles.com</a> or something like that. The only problem was that they were a bit out of sync with the picture, about 2 seconds too late. Using a good media player, such as <a href="http://videolan.org">VLC</a> you can add an offset to the subtitles every time you watch the movie but I figured I could probably whip up a small script to do it for me so I could just do it once and then have the subtitles correct every time I watched the movie. <span id="more-58"></span> The subtitles were in the .srt format, which is basically just a very simple text file with time information and the text, a typical screen is something like</p>
<pre>
00:20:24,345 --> 00:20:25,200
Hello there.
How are you?
</pre>
<p>So I created a little script, suboffset.py, which takes in the name of a subtitle file and the offset to add to the file in milliseconds, modifies the file contents and writes it back out to the same file. Alternately you can specify - as the filename and then the script will read the file from stdin and write the output to stdout so you can pipe it together to write to another file. The original script was about 10 lines, but just to make it a little more useful I made it a module so you could get access to the script from other scripts and added the stdin option and some comments. You can view the script below or <a href="http://tech.einaregilsson.com/download/suboffset.py">download the actual script here</a>.</p>
<pre><code class="python">#!/usr/bin/python
"""
   Script to offset the time in subtitle files in the .srt format. Script
   takes in the filename and the offset (in milliseconds) to add or
   subtract from the subtitles. It then writes the new subtitles to the
   same file. Alternately you can specify the filename as '-' and then
   the script will read input from stdin and write output to stdout.

"""

__version__   = '1.0'
__author__    = 'Einar Egilsson'
__date__      = 'March 20th 2008'
__url__       = 'http://tech.einaregilsson.com/2008/03/20/subtitle-fixer/' 

import sys, re, datetime

MILLISECOND = 1
SECOND = 1000 * MILLISECOND
MINUTE = 60 * SECOND
HOUR = 60 * MINUTE

def offset_time(time, offset):
    """ Takes in list with [hour, minute, second, millisecond] and returns
        it with offset milliseconds added and normalized
    """
    ms = sum(map(int.__mul__,  time, [HOUR, MINUTE, SECOND, MILLISECOND]))
    ms += offset
    return [ms / HOUR, ms % HOUR / MINUTE, ms % MINUTE / SECOND, ms % SECOND]

def fix_subtitles(lines, offset, output):
    """ Takes in list (lines) with all the lines from the subtitle file, adds
        offset milliseconds to it and writes the file to output.
    """
    for line in lines:
        pattern = r'(\d\d):(\d\d):(\d\d),(\d\d\d) --> (\d\d):(\d\d):(\d\d),(\d\d\d)'
        match = re.match(pattern, line)
        if match:
            nrs = [int(nr) for nr in match.groups(0)]
            start = offset_time(nrs[:4], offset)
            end = offset_time(nrs[4:], offset)
            output.write('%02d:%02d:%02d,%03d' % tuple(start))
            output.write(' --> ')
            output.write('%02d:%02d:%02d,%03d\n' % tuple(end))
        else:
            output.write(line)

def print_header():
    print 'Subtitle Fixer v%s' % __version__
    print 'Author: %s' % __author__
    print __url__
    print ''

if __name__ == '__main__':
    if len(sys.argv) != 3:
        print_header()
        print 'Usage: suboffset.py <filename> <offset-in-milliseconds>&#8216;
        print &#8216;Use - for filename to read from stdin and print to stdout&#8217;
        sys.exit(1)

    offset = int(sys.argv[2])
    file = None
    if sys.argv[1] == &#8216;-&#8217;: #Read from stdin and print to stdout
        fix_subtitles(sys.stdin.readlines(), offset, sys.stdout)
    else: #read from file and write to same file
        file = open(sys.argv[1], &#8216;r&#8217;)
        lines = file.readlines()
        file.close()
        file = open(sys.argv[1], &#8216;w&#8217;)
        fix_subtitles(lines, offset, file)
        file.close()
        print &#8216;Finished adding %s milliseconds to %s&#8217; % (offset, sys.argv[1])
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://tech.einaregilsson.com/2008/03/20/subtitle-fixer/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Developing ASP.NET 1.1 in Visual Studio 2008</title>
		<link>http://tech.einaregilsson.com/2008/01/15/developing-aspnet-1-1-in-visual-studio-2008/</link>
		<comments>http://tech.einaregilsson.com/2008/01/15/developing-aspnet-1-1-in-visual-studio-2008/#comments</comments>
		<pubDate>Tue, 15 Jan 2008 10:42:01 +0000</pubDate>
		<dc:creator>einar</dc:creator>
		
		<category><![CDATA[ASP.NET]]></category>

		<category><![CDATA[C#]]></category>

		<category><![CDATA[Visual Studio]]></category>

		<category><![CDATA[tips &amp; tricks]]></category>

		<guid isPermaLink="false">http://tech.einaregilsson.com/2008/01/15/developing-aspnet-11-in-visual-studio-2008/</guid>
		<description><![CDATA[I have an old ASP.NET 1.1 application that I have to maintain and which for reasons beyond my control can&#8217;t be updated to a later .net version. I hadn&#8217;t touched it in a few months but recently I had to make some small changes and realized I didn&#8217;t even have Visual Studio 2003 anymore. I [...]]]></description>
			<content:encoded><![CDATA[<p>I have an old ASP.NET 1.1 application that I have to maintain and which for reasons beyond my control can&#8217;t be updated to a later .net version. I hadn&#8217;t touched it in a few months but recently I had to make some small changes and realized I didn&#8217;t even have Visual Studio 2003 anymore. I got a new computer a few months ago and I have Visual Studio 2008 and IIS 7 on it but no VS 2003. I didn&#8217;t really want to install it, it&#8217;s pretty old at this point and not very well supported in Vista, and like most programmers I like to play with the shiny new toys, not the old obsolete ones. So I decided to try to maintain this application in Visual Studio 2008. Now, VS 2008 can target different versions of the .NET framework, but only 2.0, 3.0 and 3.5 so I was out of luck. But, thanks to a nice article I found by Jomo Fisher on compiling .NET 1.1 in VS2005 and some extra hacking I got it working pretty well. My setup was IIS 7 on Windows Vista, IIS 6 on Windows XP is pretty much the same although some of the options I point to may be located in different places. So, here&#8217;s what you need to do to develop ASP.NET 1.1 in Visual Studio 2008:<br />
<span id="more-57"></span></p>
<h4>IIS Setup</h4>
<p>Install the .NET 1.1 framework on your computer if it&#8217;s not already installed. Then start a command prompt as an administrator and then type  <strong>%WINDIR%\Microsoft.NET\Framework\v1.1.4322\aspnet_regiis -i</strong>. This will setup asp.net 1.1 to work with IIS 7. Next you should open up the IIS manager. Select &#8216;Application pools&#8217;, and under &#8216;Actions&#8217; on the right side of the screen select &#8216;Add application pool&#8217;. Give the new application pool a name, for instance &#8216;Asp.net 1.1&#8242;, set the framework version to &#8216;v1.1.4322&#8242; and pipeline mode to &#8216;classic&#8217;. Save the application pool.</p>
<h4>Compilation</h4>
<p>Jomo Fisher figured out a very nice way to use the C# 1.1 compiler in Visual Studio 2005 by manipulating some MSBuild target files. <a href="http://blogs.msdn.com/jomo_fisher/archive/2005/04/22/410903.aspx">Follow his instructions</a> for all the  projects in your solution. When that works, goto the project properties, goto the &#8216;Build&#8217; tab and set &#8216;Output path&#8217; to &#8216;bin&#8217;. Jomo&#8217;s method sets the output  path to &#8216;bin\.Net1.1\Debug&#8217; by default which won&#8217;t work for a web application, it needs the assemblies to be directly in the bin folder. Now you should be able to compile your web. If you try any .NET 2.0 specific stuff, like <span style="font-family:courier-new, monospace;">public class F&lt;T&gt;{}</span> you should get a compilation error.</p>
<h4>Debugging</h4>
<p>If you want to debug your web using the .NET 1.1 framework you can&#8217;t use the Visual Studio built-in webserver. That webserver uses the .NET 2.0 framework and even though you&#8217;ve compiled your assemblies using the C# 1.1 compiler, there&#8217;s still the aspx pages themselves that need to be compiled and we want that to happen with the C# 1.1 compiler too. Otherwise you might run into a situation where you think your web is completely working in asp.net 1.1, then you deploy to an actual 1.1 server and it&#8217;ll crash if you accidentally used some 2.0 specific stuff in your aspx files. So what we do is this: Goto project properties and the &#8216;Web&#8217; tab. Under the &#8216;Servers&#8217; section change it so that you&#8217;ve selected &#8216;Use IIS Web server&#8217;. This will show you your project url which you can change. Then press the &#8216;Create virtual directory&#8217; button. You MUST have started Visual Studio as administrator for this to work. Once you&#8217;ve done this you should go back to the IIS manager where you can now see your new virtual directory. Right click on it, press &#8216;Advanced Settings&#8217; and there, under &#8216;Behavior&#8217;, you can select which application pool to use. Change it so that it uses your brand new 1.1 application pool. </p>
<h4>Designer support</h4>
<p>I&#8217;ve got good news and bad news. The good news is that you will be able to view your pages in the designer and lay out things and it will generate the aspx file correctly for you. The bad news is that it won&#8217;t generate the codebehind member variables for you. But theres not much to it, all it means is that when you&#8217;ve added a button and given it an id of &#8216;btnDoStuff&#8217; then you should in your .aspx.cs file create a variable <span style="font-family:courier-new, monospace;">protected Button btnDoStuff;</span>. It&#8217;s a little annoying but you get used to it. It shouldn&#8217;t be too hard to write your own macro to generate members from tags, maybe I&#8217;ll do it someday (or not). Whenever you add a new page you&#8217;ll get compilation errors because of the partial classes. What I usually do is delete the .designer.cs file and remove the &#8216;partial&#8217; keyword from the main class. There&#8217;s also a using statement that references <span style="font-family:courier-new, monospace;">System.Web.UI.WebControls.WebParts</span> that you&#8217;ll have to delete.</p>
<p>I tried one approach which was to have a pre-build event that changed the name of the class in the .designer.cs file and removed the &#8216;partial&#8217; keyword. Then I made my normal class inherit from that class. That worked sometimes but sometimes members would just stop being generated so in the end I figured it wasn&#8217;t worth it and just started deleting the .designer.cs files instead. I still think creating your own macro to generate such a base class could be a good idea though.</p>
<h4>Other issues</h4>
<p>There are some other issues you might run into. Web.Config is one of them. You must remove stuff that wasn&#8217;t there in 1.1, like the &lt;connectionStrings /&gt; section.  Other than that I don&#8217;t know of any major changes, but then again my Web.Config is really simple. And then you have to make sure yourself that you don&#8217;t try to use any of the stuff that wasn&#8217;t in 1.1. That means no masterpages, generics, partial classes or any of the new webcontrols that came with 2.0. Another thing you should be aware of is that you always need to run Visual Studio as administrator for the debugging to work.</p>
<p>And that&#8217;s it. This worked for me, I don&#8217;t know if it&#8217;ll work for you. There&#8217;s some hassle involved, but for me, having some of the cool VS2008 stuff available (hello javascript intellisense) more than makes up for it.</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.einaregilsson.com/2008/01/15/developing-aspnet-1-1-in-visual-studio-2008/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Binary Tree Image</title>
		<link>http://tech.einaregilsson.com/2007/09/20/binary-tree-image/</link>
		<comments>http://tech.einaregilsson.com/2007/09/20/binary-tree-image/#comments</comments>
		<pubDate>Thu, 20 Sep 2007 23:37:33 +0000</pubDate>
		<dc:creator>einar</dc:creator>
		
		<category><![CDATA[C#]]></category>

		<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://tech.einaregilsson.com/2007/09/20/binary-tree-image/</guid>
		<description><![CDATA[Recently I had a school project where we needed to parse a certain grammar into a syntax tree and do some analysis on the code. Everytime I&#8217;ve had to work with trees (which has only been for school projects actually) I&#8217;ve been frustrated because it can be hard to visualize the tree, especially when it [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I had a school project where we needed to parse a certain grammar into a syntax tree and do some analysis on the code. Everytime I&#8217;ve had to work with trees (which has only been for school projects actually) I&#8217;ve been frustrated because it can be hard to visualize the tree, especially when it starts getting large. I&#8217;ve pretty much done two things in that situation, either draw the tree on a piece of paper, which takes a lot of time and is very boring, or try to look through the structure in the debugger, which gives you some idea but is not really very convenient. So, when I was working on this new project I figured I could probably come up with some simple way of displaying the tree while I was working on it. I wanted the solution to be re-usable so I could pull it out again the next time I have to work with binary trees without having to change it to match the new project. So, here&#8217;s what I came up with.<br />
<span id="more-56"></span></p>
<p>I created an interface called INode, which looks like this:</p>
<pre><code class="csharp">
public interface INode
{
    INode Left { get;}
    INode Right { get; }
    string Text { get;}
    object Value { get; }
}
</code></pre>
<p>In every binary tree structure I&#8217;ve ever made the nodes have pretty much looked like this, so this interface should be general enough that I could use it again. Then I created a class called BinaryTreeImage, which takes the root node of the tree as an argument in the constructor. It has four public methods (+ some overloads) that you can use to view the tree:</p>
<pre><code class="csharp">
//The bitmap object for the image
public virtual Bitmap Bitmap

//Saves the image to file as a .jpg
public virtual void Save(string filename)
//Saves the image to file in the specified image format
public virtual void Save(string filename, ImageFormat format)

//Writes the file to an outputstream in jpg format, for instance a response
//stream in an asp.net application
public virtual void WriteToStream(Stream outputStream)
//Writes the file to an outputstream in the specified image format
public virtual void WriteToStream(Stream outputStream, ImageFormat format)

//Saves the file as a temporary jpg file, then launches it so it will open in
//your default jpg editor
public virtual void Show()
</code></pre>
<p>In my current project I just added a -img switch to the program, and if it was set I used the Show() method to launch the image as soon as the tree was parsed. That made it a lot easier to work with and get a better grasp of the trees I was using.</p>
<p>When you draw the binary tree you have to figure out how much space it&#8217;s gonna need to draw all the nodes. The naive way of calculating this is to first find the depth of the tree, then figure out how many nodes can possibly be in the bottom row, with 2<sup>maxdepth-1</sup>, and make the image wide enough to fit all those nodes in. Then you can just draw the nodes at the exact places that they should be if the tree was full and then everything is great, right? Wrong! I tried that approach first and while it works, it has some problems. As soon as you have a tree that&#8217;s more than 5 or 6 levels deep you start getting a reeaally wide tree! If the tree is full than that can&#8217;t be helped, that&#8217;s just how wide the tree has to be. But if you have a pretty sparse tree (like I did) then you start getting some really crappy drawings. For instance, the root node of my syntax tree always had only one childnode. So when I had a few levels I had an image that was something like 3000 pixels wide, but was only using the right 1500 pixels of all that space.</p>
<p>So I thought about how I could fit my tree in as little space as possible and I finally found a solution that works pretty well. Recursion to the rescue! What I do now is use a depth first traversal and on the way back up I calculate the width of every subtree.</p>
<pre><code class="csharp">
protected virtual ImageNode CreateImageNodeTree(INode node)
{
    if (node == null)
        return null;

    ImageNode left = CreateImageNodeTree(node.Left);
    ImageNode right = CreateImageNodeTree(node.Right);
    ImageNode newNode = new ImageNode();
    newNode.Node = node;
    newNode.Left = left;
    newNode.Right = right;

    newNode.RightTreeWidth = (right == null) ? 0 : right.TotalWidth;
    newNode.LeftTreeWidth = (left == null) ? 0 : left.TotalWidth;
    newNode.TotalWidth = newNode.RightTreeWidth + newNode.LeftTreeWidth + NodeWidth + DX;

    return newNode;
}
</code></pre>
<p>So after that I have the right, left  and total width of every subtree. Then I can just start on the root node, draw that in the middle, then call my left child with my co-ordinates and that node will draw itself at parent.X - me.RightTreeWidth and the right node will draw itself at parent.X + me.LeftTreeWidth. And so it goes on recursively until all the nodes are drawn.</p>
<p>I&#8217;m maybe not so good at explaining it, but below you can see how it works. Just add a few nodes to the binary tree and you&#8217;ll see what happens. This is inside the blog template so as the image gets larger it might get clipped off by the sidebar or something, but you can also view the example at <a href="/BinaryTree.html">http://tech.einaregilsson.com/BinaryTree.html</a>. You can also <a href="/download/BinaryTreeImage.cs.html">view the BinaryTreeImage class here</a> or <a href="/download/BinaryTreeImage.zip">download the example project</a> which includes the class, and the webpage to view it with. The code is released under the you-must-let-me-know license. Basically, do what you want with it, but let me know if you use it, just so I&#8217;ll know if anyone else finds it useful <img src='http://tech.einaregilsson.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .<br />
<script type="text/javascript" src="/js/BinaryTreeImage.js"></script></p>
<div style="text-align:center;">
<h3>Binary Tree Image Generator</h3>
<p>Enter a number between 1 and 100</p>
<input type="text" id="number" style="width:40px;" onkeypress="keyPress(event);"/>
&nbsp;&nbsp;<button onclick="addNode();" id="addNr">Add Number</button><br />
<img id="tree" src="/BinaryTreeImageGenerator.ashx?50" alt="Image of binary tree" style="margin:auto; border:dotted 1px grey; background:none; padding:0px; margin:10px;"/>
</div>
]]></content:encoded>
			<wfw:commentRss>http://tech.einaregilsson.com/2007/09/20/binary-tree-image/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Extension development tip</title>
		<link>http://tech.einaregilsson.com/2007/08/26/extension-development-tip/</link>
		<comments>http://tech.einaregilsson.com/2007/08/26/extension-development-tip/#comments</comments>
		<pubDate>Sun, 26 Aug 2007 08:44:08 +0000</pubDate>
		<dc:creator>einar</dc:creator>
		
		<category><![CDATA[extensions]]></category>

		<category><![CDATA[mozilla]]></category>

		<category><![CDATA[tips &amp; tricks]]></category>

		<guid isPermaLink="false">http://tech.einaregilsson.com/2007/08/26/extension-development-tip/</guid>
		<description><![CDATA[If you&#8217;re developing Mozilla Extensions it can be quite annoying to keep packaging your extension after every change, installing it and restarting Firefox/Thunderbird to test your changes. Fortunately there&#8217;s an easier way.

First of all, I don&#8217;t use the jar-inside-xpi style, I just have my chrome in a normal folder inside the xpi and set it [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re developing Mozilla Extensions it can be quite annoying to keep packaging your extension after every change, installing it and restarting Firefox/Thunderbird to test your changes. Fortunately there&#8217;s an easier way.<br />
<span id="more-54"></span><br />
First of all, I don&#8217;t use the jar-inside-xpi style, I just have my chrome in a normal folder inside the xpi and set it up like this in chrome.manifest:</p>
<p>content&nbsp;myextension file:chrome/content/</p>
<p>This way you can just install it once, and then just work on it inside your Mozilla Profile/extensions folder. The folder structure in the installed extension is exactly like it was in my development folder. But still, I don&#8217;t like working directly in the extensions folder. I have all my extensions in SVN and in a /programming/mozilla folder on my drive and I just want to edit them there, instead of editing them in the extensions folder and keep copying them over to the programming folder to commit to SVN. And this can be done, I just saw this described a few weeks ago on some Mozilla page. What you do is this:</p>
<ol>
<li>Leave your extension in your development folder, e.g. c:\programming\mozilla\myextension</li>
<li>In your Mozilla profile/extensions folder, create a text file with the same name as the guid of your extension, for instance myextension&#64;einaregilsson.com. In the text file put just one line, the path to your extension: c:\programming\mozilla\myextension</li>
</ol>
<p>And that&#8217;s it. Now when you restart Firefox it will act like your extension is installed but you can keep working on it right in your programming folder, no packaging or re-installing necessary. As far as I know this only works with Firefox, not Thunderbird, at least not the 1.5 branch.</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.einaregilsson.com/2007/08/26/extension-development-tip/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Run Windows Service as a console program</title>
		<link>http://tech.einaregilsson.com/2007/08/15/run-windows-service-as-a-console-program/</link>
		<comments>http://tech.einaregilsson.com/2007/08/15/run-windows-service-as-a-console-program/#comments</comments>
		<pubDate>Wed, 15 Aug 2007 17:01:27 +0000</pubDate>
		<dc:creator>einar</dc:creator>
		
		<category><![CDATA[C#]]></category>

		<category><![CDATA[code]]></category>

		<category><![CDATA[tips &amp; tricks]]></category>

		<guid isPermaLink="false">http://tech.einaregilsson.com/2007/08/15/run-windows-service-as-a-console-program/</guid>
		<description><![CDATA[Visual Studio and the .NET framework make it really easy to create Windows Services. All you have to do is create a new project, select &#8216;Windows Service&#8217; as your project type and you&#8217;re all set. However, debugging Windows Services in Visual Studio can be a big pain. The recommended way is to use InstallUtil to [...]]]></description>
			<content:encoded><![CDATA[<p>Visual Studio and the .NET framework make it really easy to create Windows Services. All you have to do is create a new project, select &#8216;Windows Service&#8217; as your project type and you&#8217;re all set. However, debugging Windows Services in Visual Studio can be a big pain. The recommended way is to use InstallUtil to install them, and then restart the service and attach the debugger everytime you want to debug it. I wanted <a href="/projects/windows-live-bot/">Windows Live! Bot</a> to be available as a Windows Service, but I also wanted to be able to debug it without the hassle, so here&#8217;s what I came up with: <span id="more-52"></span></p>
<pre><code class="csharp">
using System;
using System.ServiceProcess;

public partial class DemoService : ServiceBase
{
    static void Main(string[] args)
    {
        DemoService service = new DemoService();

        if (Environment.UserInteractive)
        {
            service.OnStart(args);
            Console.WriteLine("Press any key to stop program");
            Console.Read();
            service.OnStop();
        }
        else
        {
            ServiceBase.Run(service);
        }

    }
    public DemoService()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        // TODO: Add code here to start your service.
    }

    protected override void OnStop()
    {
        // TODO: Add code here to perform any tear-down
        //necessary to stop your service.
    }
}

</code></pre>
<p>This will allow you to use your program as either a normal console program or a windows service, with no special builds, #DEBUG directives, command line parameters or anything like that. What it does is in the Main method it checks the &#8216;Environment.UserInteractive&#8217; property. This will be true when it is run from Visual Studio, or when you just click on the .exe file, but false if it&#8217;s being run as a service. When it&#8217;s run from Visual Studio or as a standalone program it will keep running until you press a key, then it will call your OnStop method and then terminate.</p>
<p>Two things to watch out for:</p>
<ol>
<li>You&#8217;ll have to right click on your project in Visual Studio, choose Properties and select the Output type as &#8216;Console application&#8217; for this to work.</li>
<li>If your Main method is not in your service class, you&#8217;ll have to add public methods to your class that can start and stop it, for instance add a <strong>public void StartConsole(string[] args)</strong> that just calls your OnStart, since OnStart and OnStop are protected methods and as such not accessible from other classes.</li>
</ol>
<h3>UPDATE: 16.08.2007</h3>
<p>Reader <a href="http://theimes.com/">Anderson Imes</a> (who has a rather nice <a href="http://theimes.com/archive/2006/12/28/Debugging-Windows-Services-is-a-Pain.aspx">debugging solution of his own</a>) pointed out some things to fix. One thing is that a Windows Service can run many services in the same process, the ServiceBase.Run method can take an array of ServiceBase objects. I still think that the code above is the best way to do it if you have just a single service, just keep the Main method in the service class. But if you&#8217;ve got multiple service objects then that doesn&#8217;t make sense anymore, we want to put our Main method somewhere else. And then we have the problem of not being able to call OnStart in the service objects, since it&#8217;s a protected method. We could define a public StartConsole method in all of them that calls the OnStart method like I described above, but that will get tiresome if you have many objects. Well, there is another way to do it with Reflection which I´ve written here below. The new code is basically the same as the first version, except that it has an array of ServiceBase objects, called servicesToRun, and loops through it, calling each object&#8217;s OnStart method through some neat Reflection tricks. When the user presses a button it will stop all services by calling their Stop method, which in turn calls the OnStop method that all Services must define. </p>
<pre><code class="csharp">using System.ServiceProcess;
using System;
using System.Reflection;

static class Program
{
    static void Main(string[] args)
    {
        ServiceBase[] servicesToRun = new ServiceBase[] { new Service1()
                                                        , new Service2()
                                                        , new Service3()};

        if (Environment.UserInteractive)
        {
            Type type = typeof(ServiceBase);
            BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
            MethodInfo method = type.GetMethod("OnStart", flags);

            foreach (ServiceBase service in servicesToRun)
            {
                method.Invoke(service, new object[] { args });
            }

            Console.WriteLine("Press any key to exit");
            Console.Read();

            foreach (ServiceBase service in servicesToRun)
            {
                service.Stop();
            }

        }
        else
        {
            ServiceBase.Run(servicesToRun);
        }
    }
}
</code></pre>
<p>While using this trick has worked perfectly well for my services, which have all been pretty simple, it might not work for everyone. I&#8217;m sure there are a few things different between Windows Services and console programs that I don&#8217;t know about, and might make the console version of the program behave strangely in some cases. Imes also pointed out that there was no way to test pause-and-resume in the console version. The best way I could think of to mimic service events like these would be to read in keypresses in the main thread and do the appropriate action depending on the key pressed. For instance, instead of the &#8220;Press any key to exit&#8221; message, we might have &#8220;Press p to pause, r to resume, s to stop&#8221; and then the result of Console.Read() could be used to determine which action to take and which methods to call on the Service objects. However, I don&#8217;t have the time and interest to do it right now, so implementing it is left as an exercise for the reader <img src='http://tech.einaregilsson.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.einaregilsson.com/2007/08/15/run-windows-service-as-a-console-program/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Export Haloscan comments</title>
		<link>http://tech.einaregilsson.com/2007/08/13/export-haloscan-comments/</link>
		<comments>http://tech.einaregilsson.com/2007/08/13/export-haloscan-comments/#comments</comments>
		<pubDate>Mon, 13 Aug 2007 09:51:52 +0000</pubDate>
		<dc:creator>einar</dc:creator>
		
		<category><![CDATA[code]]></category>

		<category><![CDATA[haloscan]]></category>

		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://tech.einaregilsson.com/2007/08/13/export-haloscan-comments/</guid>
		<description><![CDATA[A few weeks ago I was helping my sister change her blog. She has a Blogger account but uses Haloscan for comments, since when she started blogging Blogger didn&#8217;t offer comments as a part of their service. That has changed now, so I thought it would be much more convenient to have the comments and [...]]]></description>
			<content:encoded><![CDATA[<p>A few weeks ago I was helping my sister change her blog. She has a Blogger account but uses Haloscan for comments, since when she started blogging Blogger didn&#8217;t offer comments as a part of their service. That has changed now, so I thought it would be much more convenient to have the comments and blog all at the same place. I just needed a way to export her Haloscan comments and import them into Blogger. So I wrote a small Python script to do the exporting for me. <span id="more-47"></span></p>
<p>The script logs into your Haloscan account, makes a http request for each comment and writes them to an .xml file. If the script fails halfway through you can just start it again and it will continue where it left off. A xml file with the name yourusername.xml will be created in your working folder where you start the script. It contains all information about every comment, date, author, url, email, ip, threadid, commentid and text. You can then parse the xml file to import them into other comment systems. Before you download the script, be sure to read the following disclaimer:</p>
<p><strong>DISCLAIMER: This is provided &#8220;AS-IS&#8221;, I make no guarantees that this works, it&#8217;s based on screen scraping so could stop working whenever Haloscan change their pages. </p>
<p>According to the Haloscan Terms of Service (http://www.haloscan.com/privacy/) it&#8217;s not explicitly forbidden to screen scrape their site. HOWEVER, they say:</p>
<p>&#8220;We reserve the right to suspend, delete, or cancel any account/service at any time for any reason.&#8221;</p>
<p>This script makes a new http request for every single comment so if you have thousands of comments and Haloscan doesn&#8217;t approve of you pounding their server and suspends your account and you lose all your comments, I CANNOT BE HELD RESPONSIBLE. USE AT YOUR OWN RISK! You&#8217;ve been warned!</strong></p>
<p>Now that you&#8217;ve read that, you can <a href="/download/haloscan.py">download the script here</a> or <a href="/download/haloscan.py.html">view it syntax highlighted here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.einaregilsson.com/2007/08/13/export-haloscan-comments/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Who has deleted you from MSN?</title>
		<link>http://tech.einaregilsson.com/2007/08/09/who-has-deleted-you-from-msn/</link>
		<comments>http://tech.einaregilsson.com/2007/08/09/who-has-deleted-you-from-msn/#comments</comments>
		<pubDate>Thu, 09 Aug 2007 00:00:30 +0000</pubDate>
		<dc:creator>einar</dc:creator>
		
		<category><![CDATA[C#]]></category>

		<category><![CDATA[code]]></category>

		<category><![CDATA[msn]]></category>

		<guid isPermaLink="false">http://tech.einaregilsson.com/2007/08/09/who-has-deleted-you-from-msn/</guid>
		<description><![CDATA[My wife showed me a website the other day where you could type in your email address and password for MSN Windows Live! Messenger, and it would show you which of your contacts didn&#8217;t have you in their contact lists, either because they&#8217;d never added you, or because they&#8217;d deleted you at some point. It&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>My wife showed me a website the other day where you could type in your email address and password for <del>MSN</del> Windows Live! Messenger, and it would show you which of your contacts didn&#8217;t have you in their contact lists, either because they&#8217;d never added you, or because they&#8217;d deleted you at some point. It&#8217;s a cool idea and a good way to prune some of the contacts that you never speak to from your contact list. But I don&#8217;t really wanna give up my user / pass to some third-party site, even though they promise not to log it anywhere, and most of these sites (at least the ones I saw) tried to make some money by sending advertisements to your contacts while they were checking them, which I definitely didn&#8217;t want. So, since I already have a <a href="/projects/windows-live-bot/" title="Windows Live Bot">project that uses the MSN protocol</a> I figured I could probably whip something up myself. <span id="more-46"></span></p>
<p>(For those that have no interest in the programming and just want to have the program, you can <a href="/download/MsnContactChecker.exe"><strong>download it here</strong></a>, those interested in the implementation can keep reading). To connect to MSN I use the excellent <a href="http://www.xihsolutions.net/dotmsn/">DotMSN</a> library. That takes care of all the hard stuff so all I have to do is connect, loop through the contacts and print out those that are in your contact list but don&#8217;t have you in theirs. Now, I wrote this program in about 20 minutes, so it&#8217;s not the most beautiful code in the world, and the error-handling is almost non-existant, but it works (for me at least <img src='http://tech.einaregilsson.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ), I found 4 contacts that didn&#8217;t have me in their list and promptly deleted them. Here it is:</p>
<pre><code class="csharp">using System;
using DotMSN;

// Author: Einar Egilsson
// http://tech.einaregilsson.com/2007/08/09/who-has-deleted-you-from-msn/
class MsnContactChecker
{
  static Messenger msn = new Messenger();
  static bool done = false;

  static void Main(string[] args) {

    string user, pass;
    Console.Write("\\nMsnContactChecker v1.0\\n");
    Console.Write("See ");
    Console.Write("http://tech.einaregilsson.com/2007/08/09/who-has-deleted-you-from-msn/");
    Console.Write(" for details\\n");
    Console.Write("\\nUsername: ");
    user = Console.ReadLine();
    Console.Write("Password: ");
    pass = Console.ReadLine();

    Console.Write("\\nConnecting to MSN...");
    try {
      msn.SynchronizationCompleted +=
        new Messenger.SynchronizationCompletedHandler(OnSynchronizationCompleted);
      msn.Connect(user.Trim(), pass.Trim());
      Console.WriteLine("done");
      Console.Write("Getting contact list...");

      msn.SynchronizeList();
    } catch (Exception ex) {
      Console.WriteLine("Error: " + ex.Message);
      Console.WriteLine("\\nPress any key to quit program.");
      Console.Read();
    }
    while (!done) {
      System.Threading.Thread.Sleep(1000);
    }
  }

  static void OnSynchronizationCompleted(Messenger msn, EventArgs e)
  {
    Console.WriteLine("done");
    Console.WriteLine("\\nContacts that don't have you in their list:\\n");
    int counter = 0;
    foreach (Contact c in msn.ForwardList) {
      if (!c.OnReverseList &#038;&#038; c.Mail == c.Name) {
        counter++;
        Console.WriteLine(c.Mail);
      } else if (!c.OnReverseList) {
        counter++;
        Console.WriteLine("{0} ({1})", c.Name, c.Mail);
      }
    }

    if (counter == 0) {
      Console.WriteLine("All your contacts have you on their lists.");
    }

    msn.CloseConnection();
    Console.WriteLine("\\nPress any key to quit program.");
    Console.Read();
    done = true;
  }
}
</code></pre>
<p>This should compile both on .NET 1.1 and 2.0. You can <a href="/download/MsnContactChecker.zip"><strong>download the source</strong></a> and play with it. The zip file includes the MsnContactChecker.cs file and the library, DotMSN.dll. It&#8217;s an old version of the library, since that&#8217;s the one I had lying around, but if you want to do something more with this then you should probably upgrade to the latest version. To compile this you can write:</p>
<pre><code>csc.exe MsnContactChecker.cs /r:DotMSN.dll</code></pre>
<p>The compiler, csc.exe, is typically stored at c:\WINDOWS\Microsoft.NET\Framework\v1.1.4322 or c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727 . Or just create a Visual Studio project if you have that. </p>
<p>Or to just get the compiled program you can <a href="/download/MsnContactChecker.exe"><strong>download it here</strong></a>. It&#8217;s just a single executable file, since I used the excellent <a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=22914587-B4AD-4EAE-87CF-B14AE6A939B0">ILMerge tool</a> from Microsoft to merge my .exe file and the DotMSN library into one file. Enjoy <img src='http://tech.einaregilsson.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p>
]]></content:encoded>
			<wfw:commentRss>http://tech.einaregilsson.com/2007/08/09/who-has-deleted-you-from-msn/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Using Wordpress authentication in Zenphoto</title>
		<link>http://tech.einaregilsson.com/2007/08/08/using-wordpress-authentication-in-zenphoto/</link>
		<comments>http://tech.einaregilsson.com/2007/08/08/using-wordpress-authentication-in-zenphoto/#comments</comments>
		<pubDate>Wed, 08 Aug 2007 08:18:15 +0000</pubDate>
		<dc:creator>einar</dc:creator>
		
		<category><![CDATA[code]]></category>

		<category><![CDATA[wordpress]]></category>

		<category><![CDATA[zenphoto]]></category>

		<guid isPermaLink="false">http://tech.einaregilsson.com/2007/08/08/using-wordpress-authentication-in-zenphoto/</guid>
		<description><![CDATA[In a previous post I talked about how to integrate ZenPhoto into Wordpress. After I had done that for my own site I still wasn&#8217;t happy. I didn&#8217;t like the fact that I had to use seperate logins for Wordpress and ZenPhoto, I wanted this to be as integrated as possible. So I figured out [...]]]></description>
			<content:encoded><![CDATA[<p>In a previous post I talked about <a href="http://tech.einaregilsson.com/2007/08/06/integrating-zenphoto-into-wordpress/">how to integrate ZenPhoto into Wordpress</a>. After I had done that for my own site I still wasn&#8217;t happy. I didn&#8217;t like the fact that I had to use seperate logins for Wordpress and ZenPhoto, I wanted this to be as integrated as possible. So I figured out a way to make ZenPhoto ask Wordpress for authentication credentials. In other words, if you&#8217;re logged into Wordpress, you&#8217;re also logged into ZenPhoto. This makes the user/password in the ZenPhoto config file meaningless. Here&#8217;s what you have to do to get this working:<span id="more-39"></span></p>
<p>1. Edit the file auth_zp.php under the zen folder in your ZenPhoto installation, throw away everything in the file, and replace it with this:</p>
<pre><code class="php">&lt;?php
require_once("functions-db.php");

$wp_include = "../wp-config.php";
$i = 0;
while (!file_exists($wp_include) &#038;&#038; $i++ < 10) {
  $wp_include = "../$wp_include";
}
require_once($wp_include);

function zp_loggedin() {
  //Only considered logged in if it's someone with more rights
  //than a Subscriber
  return is_user_logged_in() &#038;&#038; wp_get_current_user()-&gt;user_level >= 2;
}

if (isset($_GET[&quot;logout&quot;]) || isset($_POST[&quot;logout&quot;])) {
  header(&quot;Location: &quot; . get_option(&quot;siteurl&quot;)
       . &quot;/wp-login.php?action=logout&quot;);
  exit();
}

?&gt;
</code></pre>
<p>This technique assumes that your Zenphoto folder is a subfolder of your Wordpress folder. Like here, my Wordpress install is at http://tech.einaregilsson.com/ and my Zenphoto install is at http://tech.einaregilsson.com/photos/. It can be at most 10 levels deep in the folder hierarchy under Wordpress, but it MUST be under the WP folder. </p>
<p>2. Edit the admin-function.php file thats also under the zen folder in your ZenPhoto installation. Find the function printLoginForm and replace it with this:</p>
<pre><code class="php">
function printLoginForm($redirect="/zen/admin.php") {
  if (is_user_logged_in() &#038;&#038; wp_get_current_user()-&gt;user_level == 0) {
    //User is logged in as Subscriber

    $logoutUrl = get_option('siteurl') . "/wp-login.php?action=logout";
    echo "&lt;p&gt;&lt;img src=\"../zen/images/zen-logo.gif\" title=\"Zen Photo\" />&lt;/p&gt;";

    echo "\\n  &lt;div id=\"loginform\"&gt;";
    echo "&lt;div class=\"errorbox\" id=\"message\"&gt;"
       . "&lt;h2>Error: Insufficient privileges.&lt;/h2&gt;"
       . "You are currently logged into Wordpress as a &lt;strong&gt;Subscriber&lt;/strong&gt;. "
       . "Subscribers can't access ZenPhoto Administration. In order to do "
       . "so you must &lt;a href=\"$logoutUrl\"&gt;log out of Wordpress&lt;/a&gt; and "
       . "then log in again with an account that has more rights."
       . "&lt;/div&gt;";
    echo "\\n&lt;/body&gt;";
    echo "\\n&lt;/html&gt;";
  } else {
    $redirect = WEBPATH . $redirect;
    header("Location: ".get_option('siteurl')."/wp-login.php?redirect_to=$redirect");
    exit();
  }
}
</code></pre>
<p>The only tricky thing here was dealing with Wordpress users that only have Subscriber rights. Subscribers shouldn&#8217;t be able to administer ZenPhoto of course, but I didn&#8217;t want to log them out automatically or anything. So I added a special case for them, if a Subscriber tries to access ZenPhoto Administration he will get an error message saying he needs to log in with higher privileges and link to log out of Wordpress. If you already have the basic <a href="http://tech.einaregilsson.com/2007/08/06/integrating-zenphoto-into-wordpress/">ZenPhoto integration</a> working then you&#8217;ll have the ZenPhoto link in your Wordpress admin pages. Subscribers however won&#8217;t see this link, it will only be shown to users with a role of Contributor or higher.</p>
<p>And that&#8217;s it. Now I have my photos using my Wordpress theme, I can edit them in my Wordpress admin, I have a link to the ZenPhoto admin and I can use Wordpress authentication. The integration is complete <img src='http://tech.einaregilsson.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.einaregilsson.com/2007/08/08/using-wordpress-authentication-in-zenphoto/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Integrating ZenPhoto into Wordpress</title>
		<link>http://tech.einaregilsson.com/2007/08/06/integrating-zenphoto-into-wordpress/</link>
		<comments>http://tech.einaregilsson.com/2007/08/06/integrating-zenphoto-into-wordpress/#comments</comments>
		<pubDate>Mon, 06 Aug 2007 00:28:46 +0000</pubDate>
		<dc:creator>einar</dc:creator>
		
		<category><![CDATA[plugins]]></category>

		<category><![CDATA[wordpress]]></category>

		<category><![CDATA[zenphoto]]></category>

		<guid isPermaLink="false">http://tech.einaregilsson.com/2007/08/06/integrating-zenphoto-into-wordpress/</guid>
		<description><![CDATA[ZenPhoto is a great image gallery written in php that I use on another page I have. It has a great admin interface and themes that are simple to use. I wanted to integrate it into a Wordpress blog so I looked around on the net and found a great article about it by a [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://zenphoto.org">ZenPhoto</a> is a great image gallery written in php that I use on another page I have. It has a great admin interface and themes that are simple to use. I wanted to integrate it into a Wordpress blog so I looked around on the net and found a great article about it by a guy named <a href="http://ruzee.com">Steffen Rusitschka</a>. It explains how you can get your ZenPhoto gallery to look like your blog by including some Wordpress pages in your ZenPhoto theme. The article is at <a href="http://www.ruzee.com/blog/2006/06/integrating-zenphoto-into-wordpress/">http://www.ruzee.com/blog/2006/06/integrating-zenphoto-into-wordpress/</a>.</p>
<p>His method works great but there were a few things that bugged me about it. <span id="more-42"></span>First, my ZenPhoto javascript didn&#8217;t work with it, so the inline editing of album descriptions didn&#8217;t work. Also I wanted to be able to edit my ZenPhoto theme files in the Wordpress theme editor. I tweak my theme all the time and I thought it would be much more convenient to be able to do it all in one place. So I figured out a way to make it work. Steffen gets full credit for coming up with the method, my contribution is simply making the javascript and theme editor work correctly, creating a link to the ZenPhoto admin interface from the Wordpress admin interface and packing it all up in a zip file with easy installation instructions. I won&#8217;t explain all the code here, it&#8217;s done quite nicely in Steffens article but for those interested in the implementation it&#8217;s basically this:</p>
<ol>
<li>Make the files in the ZenPhoto theme basically do nothing but include zp-index, zp-image and zp-album from the current Wordpress theme folder. This allows us to edit the theme using the Wordpress theme editor.</li>
<li>Add hooks in Wordpress so the ZenPhoto stylesheet will be included in the &lt;head&gt; element of the page.</li>
<li>Add hooks in Wordpress so the zenJavascript function from ZenPhoto is called on the pages, so the inline editing will work (see head.php for this).</li>
<li>Create a small Wordpress plugin that creates a link to ZenPhoto from the Wordpress admin interface, and gives the zp files pretty names in the Wordpress theme editor (&#8217;ZenPhoto Index&#8217; for zp-index.php, &#8216;ZenPhoto Image&#8217; for zp-image.php etc.).</li>
</ol>
<p>For those that just want to get it working, here are the installation instructions:</p>
<ol>
<li>Download the zip file and unzip.</li>
<li>Copy the wordpress-integration-zp-theme folder into your zenphoto/themes folder.</li>
<li>Go to your ZenPhoto admin web, choose Options and activate the theme called &#8216;Wordpress Integration Theme&#8217;.</li>
<li>Copy the files (zp-index.php, zp-image.php, zp-album.php, zp-style.css) from the wordpress-theme-files folder into your current Wordpress theme folder, /wp-content/themes/yourthemename.</li>
<li>Copy the zen-integration.php file into your Wordpress plugin folder, /wp-content/plugins .</li>
<li>Goto your Wordpress admin interface, choose Plugins, and activate the &#8216;Zen Integration&#8217; plugin. Note that the plugin assumes that your zenphoto folder is directly below your Wordpress folder and is called &#8216;zenphoto&#8217;, &#8216;photos&#8217; or &#8216;gallery&#8217;. If it&#8217;s not, and you want to get the ZenPhoto link from the Wordpress admin interface working you&#8217;ll need to edit the zen-integration.php file, find this line:
<pre><code class="php">$zp_admin_url = ''</code></pre>
<p>And change it to the full url of your ZenPhoto admin page, e.g.</p>
<pre><code class="php">$zp_admin_url = 'http://example.com/foo/bar/zenphoto/zen/admin.php'</code></pre>
<li>There is no step 7, you&#8217;re done!</li>
</ol>
<p>Now you should be able to go to your Wordpress theme editor and see the files &#8216;ZenPhoto Index&#8217;, &#8216;ZenPhoto Album&#8217;, &#8216;ZenPhoto Image&#8217; and &#8216;ZenPhoto Stylesheet&#8217; and you can edit them right there. The files included in the zipfile are meant to be used with the default Wordpress theme, Kubrick, and will probably not look very good on any other theme. It&#8217;s the simplest thing I could come up with, I mostly just changed the default ZenPhoto theme a bit. You should change it to fit your current Wordpress theme. In the files, the ZenPhoto part is always wrapped in a &lt;div id=&#8221;zenphoto&#8221;&gt;, and the ZenPhoto stylesheet prefixes everything with #zenphoto, this is so your ZenPhoto stylesheet won&#8217;t start affecting other parts of your blog.</p>
<p>So, that&#8217;s it I think <img src='http://tech.einaregilsson.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . You can <a href="/download/zen-integration.zip">download the zip file with all the needed file here</a>, let me know if you have any problems with it. You can view it in action at <a href="/photos">http://tech.einaregilsson.com/photos</a>  (Yes, I know it&#8217;s the same picture over and over, it&#8217;s just for demonstration purposes <img src='http://tech.einaregilsson.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ).</p>
<p><strong>UPDATE 01.09.2007:</strong> Fixed bug where error message didn&#8217;t appear when comment was invalid on an image page.<br />
<strong>UPDATE 02.09.2007:</strong> &#8230;and now I fixed the fix, because it was displaying the error message even if there was no error!</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.einaregilsson.com/2007/08/06/integrating-zenphoto-into-wordpress/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Mozilla Extension Generator</title>
		<link>http://tech.einaregilsson.com/2007/08/01/mozilla-extension-generator/</link>
		<comments>http://tech.einaregilsson.com/2007/08/01/mozilla-extension-generator/#comments</comments>
		<pubDate>Wed, 01 Aug 2007 01:00:17 +0000</pubDate>
		<dc:creator>einar</dc:creator>
		
		<category><![CDATA[code]]></category>

		<category><![CDATA[extensions]]></category>

		<category><![CDATA[javascript]]></category>

		<category><![CDATA[mozilla]]></category>

		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://tech.einaregilsson.com/2007/08/01/mozilla-extension-generator/</guid>
		<description><![CDATA[Since I started creating Mozilla extensions I spent a lot of time writing boilerplate code, and copying from one extension from the next. Then I found <a href="http://ted.mielczarek.org/code/mozilla/extensionwiz/">Ted Mielczarek's Extension Generator</a> which is a great page that takes some parameters and creates an extension ready for you to use. I used that for some time but in the end I still kept modifying each extension to fit my own style and include my library functions. So I decided to make my own Mozilla Extension Generator in Python]]></description>
			<content:encoded><![CDATA[<p>Since I started creating Mozilla extensions I spent a lot of time writing boilerplate code, and copying from one extension from the next. Then I found <a href="http://ted.mielczarek.org/code/mozilla/extensionwiz/">Ted Mielczarek&#8217;s Extension Generator</a> which is a great page that takes some parameters and creates an extension ready for you to use. I used that for some time but in the end I still kept modifying each extension to fit my own style and include my library functions. So I decided to make my own Mozilla Extension Generator in Python<span id="more-44"></span>, that would spit out extensions exactly the way I want them. I mostly liked the output of Ted&#8217;s generator so I took an extension from it, modified to fit my style and then created the generator to create it. So if you see similarities between extension my by generator and Ted&#8217;s, that&#8217;s the reason, mine is partially based on his output. I&#8217;ve decided to put the generator on my page for others to download, and they can then tweak it to fit their ideas of what should be in all extensions. </p>
<p>When the script is run the output will look something like this:</p>
<pre class="console">
Mozilla Extension Generator
Copyright (c) 2007 Einar Egilsson (http://tech.einaregilsson.com)

Extension name: My New Extension
Extension code name: MyNewExtension
Extension description: Does this and that
Firefox or Thunderbird (f/t) : f
Include Menu item ? (y/n): y
Include Context menu ? (y/n): y
Author name: Einar Egilsson
Guid: mynewextension@einaregilsson.com
Menu item label: My New MenuItem
Menu item access key: m
Contextmenu item label: My New ContextItem
Contextmenu item access key: c

Creating files...

mynewextension/install.rdf
mynewextension/chrome.manifest
mynewextension/defaults/preferences/mynewextension.js
mynewextension/chrome/content/mynewextension.js
mynewextension/chrome/content/overlay.xul
mynewextension/chrome/skin/overlay.css
mynewextension/chrome/content/mynewextension.png
mynewextension/chrome/content/mynewextensionlib.js
mynewextension/chrome/locale/en-US/mynewextension.dtd
mynewextension/chrome/locale/en-US/mynewextension.properties

Extension complete
</pre>
<p>This will generate all the necessary files for the extension, you can simply go into the folder created, zip it up, name as .xpi and install the extension. The questions are pretty straight forward, just about the only thing you need to know is that Extension code name must be a single word, because it will become a javascript object that all your other code will be wrapped in, to avoid polluting the global namespace. </p>
<p>Now, some features of the generated extension:</p>
<ul>
<li>Localization ready, strings are in .dtd and .properties files</li>
<li>Includes a library file with common function like accessing your prefs, writing to a file and more.</li>
<li>Includes debug functions that output to the javascript console and can be turned off in about:config</li>
<li>Can include menu item and context menu commands</li>
<li>&#8230;and more, just look at the generated files</li>
</ul>
<p>The generator is a single python file that includes all the other files. It should be easy to modify for anyone with a working knowledge of python. There are a few constants at the top that you can tweak, they are:</p>
<pre><code class="python">#Constants
#Fill these out so you won't get prompted for them everytime:
YOUR_NAME       = ''
YOUR_DOMAIN     = '' # if filled out the extension guid will be of
                     #the form extensionname@yourdomain.com
FIREFOX_MIN     = '2.0'
FIREFOX_MAX     = '2.0.0.*'
THUNDERBIRD_MIN = '2.0'
THUNDERBIRD_MAX = '2.0.0.*'
INITIAL_VERSION = '0.9'
</code></pre>
<p>The icon file is also embedded in the file as a base64 encoded string. To replace it with your own file, create a .png image file (34&#215;34 pixels) and run the script below (<a href="/download/base64.py">download</a>) to create the base64 string, then copy it over the existing base64 string in the extension.py file.</p>
<pre><code class="python">import sys, base64

if len(sys.argv) == 1:
    print 'Usage: base64 &lt;filename&gt;'
    sys.exit(0)

b64 = base64.b64encode(open(sys.argv[1], 'rb').read())
i = 0

while i < len(b64):
    print b64[i:i+80]
    i += 80
</code></pre>
<p>And finally, you can <a href="/download/extension.py">download the python script here</a>. You can also <a href="/download/extension.py.html">view it syntax highlighted here</a> but don&#8217;t copy it from there as the syntax highlighting might screw something up. Enjoy <img src='http://tech.einaregilsson.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p>
]]></content:encoded>
			<wfw:commentRss>http://tech.einaregilsson.com/2007/08/01/mozilla-extension-generator/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
