Dec 18, 2008

Mono.Cecil Profiler

So we have been trying to develop a profiler for a long time.  All the posts seem to require an inordinate amount ofMSIL knowledge or to know C++ to interface with the CLR directly.  Both of these approaches were painful.  All I wanted to do was inject a Profile.Start and Profile.End into our code base for every class giving us a simple profiler.  With Mono.Cecil I could do exactly that, and without Mono installed on my computer.  Go get the original example from the Mono.Cecil website or just download it directly here. There is a dll called lib.  I just added that to my solution in VS2008 and wrote the following simple profiler.



static void Main(string[] args)
string pathBin = @"C:\Users\michael\Documents\Visual Studio 2008\Projects\ConsoleApplication1\ConsoleApplication2\bin\Debug\ConsoleApplication2.exe";

MethodInfo startMethod = typeof(ProfileClient).GetMethod("Start", new Type[] { typeof(string) });
MethodInfo endMethod =typeof(ProfileClient).GetMethod("End", new Type[] { typeof(string) });

AssemblyDefinition assembly = AssemblyFactory.GetAssembly(pathBin);

foreach (TypeDefinition type in assembly.MainModule.Types)
if (type.Name != "<Module>")
foreach (MethodDefinition method in type.Methods)
CilWorker worker = method.Body.CilWorker;
string sentence = method.Name;
MethodReference start=assembly.MainModule.Import(startMethod);
MethodReference end= assembly.MainModule.Import(endMethod);

//Creates the MSIL instruction for inserting the sentence
Instruction startSentence = worker.Create(OpCodes.Ldstr, sentence);
Instruction endSentence= worker.Create(OpCodes.Ldstr, sentence);

List<Instruction> parameters = new List<Instruction>();

//Creates the CIL instruction for calling the start and end
Instruction callStart= worker.Create(OpCodes.Call, start);
Instruction callEnd= worker.Create(OpCodes.Call, end);

//-2 cause you need to go before the return opcode
Instruction lastinstruction= method.Body.Instructions[method.Body.Instructions.Count-2];
worker.InsertAfter(lastinstruction, endSentence);
worker.InsertAfter(endSentence, callEnd);

Instruction firstinstruction = method.Body.Instructions[0];
worker.InsertBefore(firstinstruction, startSentence);
worker.InsertAfter(startSentence, callStart);


AssemblyFactory.SaveAssembly(assembly, pathBin.Replace(".exe","")+"-new-.exe");


public class ProfileClient
public static void Start(string method,params object[] args)
Console.WriteLine("Start " + method+">");

public static void End(string method, params object[] args)
Console.WriteLine(">End "+ method);


class Program
static void Main(string[] args)
Console.WriteLine("My Code2 ");

So if you build the last program and run it, it will output

My Code2

Once you run the second console application and then run ConsoleApplication2-new-.exe you will get

Start Main>

My Code2 ?

>End Main

I’m still not sure where the ? comes from but for now this simple profiler works and will be the basis of our more complex profiler we are planning to start constructing.

Sep 2, 2008

Remove SVN

There is probably an easier way to do this.  I accidentally tried to add a  large directory to a svn repo.  It failed after 3 hours leaving half my directory with .svn folders. Since Tortoise SVN didn't seem to have an option to unbind a folder I wrote this powershell script.



function removesvn
  dir -path $pwd.Path -recurse -force | where{    $_.Name -eq ".svn"} | rm -recurse -force

Aug 26, 2008

Convert Bitmaps to transparent png

Not much to say.  This was really useful with an icon set we were using.


using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

namespace ConsoleApplication2
class Program
static void Main(string[] args)
string directory=@"c:\temp\";
string[] files = Directory.GetFiles(directory, "*.bmp");
foreach (string path in files)
Bitmap bmp = new Bitmap(path);
FileInfo fi = new FileInfo(path);
bmp.Save(directory + fi.Name.Replace(".bmp", "") + ".png", ImageFormat.Png);


Aug 1, 2008

How Asp.Net Requests Page

As our company delved into asynchronous transfers we noticed that we would get a random application hang every now and then.  We suspected and tried to hunt down a threading problem and along the way we learned some interesting things.

First: Asp.Net queues requests by session to prevent this problem.  Here is our test. First we built a new Page Class with some diagnostic info.

namespace WebApplication3
public class TestPage : Page

protected override void OnLoad(EventArgs e)
Debug.Print("strt\t" + this.GetType().Name + "Load" + " " +this.GetHashCode());
Debug.Print(" stop\t" + this.GetType().Name + "Load"+ " " +this.GetHashCode());

protected override void OnPreRender(EventArgs e)
Debug.Print(" strt\t" + this.GetType().Name + "PreR"+ " " +this.GetHashCode());
Debug.Print(" stop\t" + this.GetType().Name + "PreR"+ " " +this.GetHashCode());

Then I setup the Default Page to add iframes to the source.  
public partial class _Default : TestPage
protected void Page_Load(object sender, EventArgs e)
for (int i = 0; i < 20; i++)
HtmlGenericControl control = new HtmlGenericControl("iframe");
control.Attributes.Add("src", "WebForm1.aspx");
Some notes here.  The Thread.Sleep makes sure that the debugger is attached and responding well enough to record things correctly.
Finally WebForm1.aspx.  This thing doesnt do anything but inherit from the TestPage with diagnostic information.
namespace WebApplication3
public partial class WebForm1 : TestPage
protected void Page_Load(object sender, EventArgs e)


Ok so the first run we make sure EnableSessionState="True" 

What this is supposed to do is make sure that only one request happens at a time.  Here is the log.

strt    default_aspxLoad 53576792
stop    default_aspxLoad 53576792
  strt    default_aspxPreR 53576792
   stop    default_aspxPreR 53576792
strt    webform1_aspxLoad 46058179
strt    webform1_aspxLoad 63986957

stop    webform1_aspxLoad 46058179
  strt    webform1_aspxPreR 46058179
   stop    webform1_aspxPreR 46058179
stop    webform1_aspxLoad 63986957
  strt    webform1_aspxPreR 63986957
   stop    webform1_aspxPreR 63986957
strt    webform1_aspxLoad 58678956
stop    webform1_aspxLoad 58678956
  strt    webform1_aspxPreR 58678956
   stop    webform1_aspxPreR 58678956
strt    webform1_aspxLoad 49300528
stop    webform1_aspxLoad 49300528
  strt    webform1_aspxPreR 49300528
   stop    webform1_aspxPreR 49300528
strt    webform1_aspxLoad 8423152
stop    webform1_aspxLoad 8423152
  strt    webform1_aspxPreR 8423152
   stop    webform1_aspxPreR 8423152
strt    webform1_aspxLoad 32996321
stop    webform1_aspxLoad 32996321
  strt    webform1_aspxPreR 32996321
   stop    webform1_aspxPreR 32996321
strt    webform1_aspxLoad 28848020
stop    webform1_aspxLoad 28848020
  strt    webform1_aspxPreR 28848020
   stop    webform1_aspxPreR 28848020
strt    webform1_aspxLoad 66504299
stop    webform1_aspxLoad 66504299
  strt    webform1_aspxPreR 66504299
   stop    webform1_aspxPreR 66504299
strt    webform1_aspxLoad 47123389
stop    webform1_aspxLoad 47123389
  strt    webform1_aspxPreR 47123389
   stop    webform1_aspxPreR 47123389
strt    webform1_aspxLoad 60889463
stop    webform1_aspxLoad 60889463
  strt    webform1_aspxPreR 60889463
   stop    webform1_aspxPreR 60889463
strt    webform1_aspxLoad 16515137
stop    webform1_aspxLoad 16515137
  strt    webform1_aspxPreR 16515137
   stop    webform1_aspxPreR 16515137
strt    webform1_aspxLoad 10378086
stop    webform1_aspxLoad 10378086
  strt    webform1_aspxPreR 10378086
   stop    webform1_aspxPreR 10378086
strt    webform1_aspxLoad 58791803
stop    webform1_aspxLoad 58791803
  strt    webform1_aspxPreR 58791803
   stop    webform1_aspxPreR 58791803
strt    webform1_aspxLoad 45784774
stop    webform1_aspxLoad 45784774
  strt    webform1_aspxPreR 45784774
   stop    webform1_aspxPreR 45784774
strt    webform1_aspxLoad 31806433
stop    webform1_aspxLoad 31806433
  strt    webform1_aspxPreR 31806433
   stop    webform1_aspxPreR 31806433
strt    webform1_aspxLoad 17398656
stop    webform1_aspxLoad 17398656
  strt    webform1_aspxPreR 17398656
   stop    webform1_aspxPreR 17398656
strt    webform1_aspxLoad 62912648
stop    webform1_aspxLoad 62912648
  strt    webform1_aspxPreR 62912648
   stop    webform1_aspxPreR 62912648
strt    webform1_aspxLoad 50833736
stop    webform1_aspxLoad 50833736
  strt    webform1_aspxPreR 50833736
   stop    webform1_aspxPreR 50833736
strt    webform1_aspxLoad 46154167
stop    webform1_aspxLoad 46154167
  strt    webform1_aspxPreR 46154167
   stop    webform1_aspxPreR 46154167
strt    webform1_aspxLoad 63078365
stop    webform1_aspxLoad 63078365
  strt    webform1_aspxPreR 63078365
   stop    webform1_aspxPreR 63078365


So the first request does not seem to be blocking additional requests as seen in red.  Whoops!  We didn't use Session so hasn't made us a session (this is retarded I know).

So we made a change to TestPage.

public class TestPage : Page

protected override void OnLoad(EventArgs e)
Session["dumb"] = true;
Debug.Print("strt\t" + this.GetType().Name + "Load" + " " +this.GetHashCode());
Debug.Print(" stop\t" + this.GetType().Name + "Load"+ " " +this.GetHashCode());

protected override void OnPreRender(EventArgs e)
Debug.Print(" strt\t" + this.GetType().Name + "PreR"+ " " +this.GetHashCode());
Debug.Print(" stop\t" + this.GetType().Name + "PreR"+ " " +this.GetHashCode());




See now we set ["Dumb"]=true.


Ok so here is the next trace with that fix.


strt    default_aspxLoad 6100737
stop    default_aspxLoad 6100737
  strt    default_aspxPreR 6100737
   stop    default_aspxPreR 6100737
strt    webform1_aspxLoad 6299240
stop    webform1_aspxLoad 6299240
  strt    webform1_aspxPreR 6299240
   stop    webform1_aspxPreR 6299240
strt    webform1_aspxLoad 50224890
stop    webform1_aspxLoad 50224890
  strt    webform1_aspxPreR 50224890
   stop    webform1_aspxPreR 50224890
strt    webform1_aspxLoad 51844981
stop    webform1_aspxLoad 51844981
  strt    webform1_aspxPreR 51844981
   stop    webform1_aspxPreR 51844981
strt    webform1_aspxLoad 54842390
stop    webform1_aspxLoad 54842390
  strt    webform1_aspxPreR 54842390
   stop    webform1_aspxPreR 54842390
strt    webform1_aspxLoad 44186085
stop    webform1_aspxLoad 44186085
  strt    webform1_aspxPreR 44186085
   stop    webform1_aspxPreR 44186085
strt    webform1_aspxLoad 307537
stop    webform1_aspxLoad 307537
  strt    webform1_aspxPreR 307537
   stop    webform1_aspxPreR 307537
strt    webform1_aspxLoad 36642531
stop    webform1_aspxLoad 36642531
  strt    webform1_aspxPreR 36642531
   stop    webform1_aspxPreR 36642531
strt    webform1_aspxLoad 8761922
stop    webform1_aspxLoad 8761922
  strt    webform1_aspxPreR 8761922
   stop    webform1_aspxPreR 8761922
strt    webform1_aspxLoad 44283204
stop    webform1_aspxLoad 44283204
  strt    webform1_aspxPreR 44283204
   stop    webform1_aspxPreR 44283204
strt    webform1_aspxLoad 37119060
stop    webform1_aspxLoad 37119060
  strt    webform1_aspxPreR 37119060
   stop    webform1_aspxPreR 37119060
strt    webform1_aspxLoad 46442220
stop    webform1_aspxLoad 46442220
  strt    webform1_aspxPreR 46442220
   stop    webform1_aspxPreR 46442220
strt    webform1_aspxLoad 51538364
stop    webform1_aspxLoad 51538364
  strt    webform1_aspxPreR 51538364
   stop    webform1_aspxPreR 51538364
strt    webform1_aspxLoad 65304700
stop    webform1_aspxLoad 65304700
  strt    webform1_aspxPreR 65304700
   stop    webform1_aspxPreR 65304700
strt    webform1_aspxLoad 45154067
stop    webform1_aspxLoad 45154067
  strt    webform1_aspxPreR 45154067
   stop    webform1_aspxPreR 45154067
strt    webform1_aspxLoad 24313979
stop    webform1_aspxLoad 24313979
  strt    webform1_aspxPreR 24313979
   stop    webform1_aspxPreR 24313979
strt    webform1_aspxLoad 30823158
stop    webform1_aspxLoad 30823158
  strt    webform1_aspxPreR 30823158
   stop    webform1_aspxPreR 30823158
strt    webform1_aspxLoad 32261192
stop    webform1_aspxLoad 32261192
  strt    webform1_aspxPreR 32261192
   stop    webform1_aspxPreR 32261192
strt    webform1_aspxLoad 5695327
stop    webform1_aspxLoad 5695327
  strt    webform1_aspxPreR 5695327
   stop    webform1_aspxPreR 5695327
strt    webform1_aspxLoad 14547257
stop    webform1_aspxLoad 14547257
  strt    webform1_aspxPreR 14547257
   stop    webform1_aspxPreR 14547257
strt    webform1_aspxLoad 65008279
stop    webform1_aspxLoad 65008279
  strt    webform1_aspxPreR 65008279
   stop    webform1_aspxPreR 65008279

So great!  It finally works.  Now lets break it on purpose.  We setup this line in both pages.

Here is our log we can see that the first 2 requests to webform1 are made at the same time causing  a thread exception.

strt    default_aspxLoad 22177797
stop    default_aspxLoad 22177797
  strt    default_aspxPreR 22177797
   stop    default_aspxPreR 22177797
strt    webform1_aspxLoad 58758044
strt    webform1_aspxLoad 60402358
stop    webform1_aspxLoad 60402358
stop    webform1_aspxLoad 58758044
  strt    webform1_aspxPreR 60402358
  strt    webform1_aspxPreR 58758044
   stop    webform1_aspxPreR 60402358
   stop    webform1_aspxPreR 58758044
strt    webform1_aspxLoad 33970112
stop    webform1_aspxLoad 33970112
  strt    webform1_aspxPreR 33970112
   stop    webform1_aspxPreR 33970112
strt    webform1_aspxLoad 12544008
stop    webform1_aspxLoad 12544008
  strt    webform1_aspxPreR 12544008
   stop    webform1_aspxPreR 12544008
strt    webform1_aspxLoad 47231162
stop    webform1_aspxLoad 47231162
  strt    webform1_aspxPreR 47231162
   stop    webform1_aspxPreR 47231162
strt    webform1_aspxLoad 63638306
stop    webform1_aspxLoad 63638306
  strt    webform1_aspxPreR 63638306
   stop    webform1_aspxPreR 63638306
strt    webform1_aspxLoad 57701674
stop    webform1_aspxLoad 57701674
  strt    webform1_aspxPreR 57701674
   stop    webform1_aspxPreR 57701674
strt    webform1_aspxLoad 29746117
stop    webform1_aspxLoad 29746117
  strt    webform1_aspxPreR 29746117
   stop    webform1_aspxPreR 29746117
strt    webform1_aspxLoad 3884878
stop    webform1_aspxLoad 3884878
  strt    webform1_aspxPreR 3884878
   stop    webform1_aspxPreR 3884878
strt    webform1_aspxLoad 45476154
stop    webform1_aspxLoad 45476154
  strt    webform1_aspxPreR 45476154
   stop    webform1_aspxPreR 45476154
strt    webform1_aspxLoad 42317455
stop    webform1_aspxLoad 42317455
  strt    webform1_aspxPreR 42317455
   stop    webform1_aspxPreR 42317455
strt    webform1_aspxLoad 60918874
stop    webform1_aspxLoad 60918874
  strt    webform1_aspxPreR 60918874
   stop    webform1_aspxPreR 60918874
strt    webform1_aspxLoad 54806812
stop    webform1_aspxLoad 54806812
  strt    webform1_aspxPreR 54806812
   stop    webform1_aspxPreR 54806812
strt    webform1_aspxLoad 59055457
stop    webform1_aspxLoad 59055457
  strt    webform1_aspxPreR 59055457
   stop    webform1_aspxPreR 59055457
strt    webform1_aspxLoad 64646201
stop    webform1_aspxLoad 64646201
  strt    webform1_aspxPreR 64646201
   stop    webform1_aspxPreR 64646201
strt    webform1_aspxLoad 62849758
stop    webform1_aspxLoad 62849758
  strt    webform1_aspxPreR 62849758
   stop    webform1_aspxPreR 62849758
strt    webform1_aspxLoad 26235852
stop    webform1_aspxLoad 26235852
  strt    webform1_aspxPreR 26235852
strt    webform1_aspxLoad 2135755
stop    webform1_aspxLoad 2135755
   stop    webform1_aspxPreR 26235852
  strt    webform1_aspxPreR 2135755
   stop    webform1_aspxPreR 2135755
strt    webform1_aspxLoad 6565686
stop    webform1_aspxLoad 6565686
  strt    webform1_aspxPreR 6565686
   stop    webform1_aspxPreR 6565686
strt    webform1_aspxLoad 8372655
stop    webform1_aspxLoad 8372655
  strt    webform1_aspxPreR 8372655
   stop    webform1_aspxPreR 8372655

So in summary only makes one request at a time as long as you initialize the session, set the EnableSessionState=True (which is the default).  So if you think Asp.Net is causing threading issues think again.

Jul 28, 2008

Where are the label's in the world.

This is much less a post of something cool I've done and much more a post about where are all the labels.  Google gave us labels for things like gmail and google docs right?  Sharepoint capitalized on the idea an added their own online labeling.  Vista lets you label a few types of files.  When will someone write a general purpose labeling system that can be used by all the cool new desktop search engines out there?


I'm waiting...........

Jul 24, 2008

Upward Bound Robots : A success


A while back I posted about building a cheap robot for a high school summer camp.  Well the camp is over and I think it was pretty successful.  I was able to build 9 robots for under $30 a piece.  Each robot used an Atmel Butterfly and cheap remote control car.  I will have more ongoing information about how these cars work and how to make your own, but for now enjoy the circle of bots :)



Jul 23, 2008

Where are the digital engineering notebooks?

I am a strong proponent of making everything in my life digital.  I own a tablet PC and spend most of my time working on engineering projects on the computer.  One thing that always drives me nuts is printing out stuff just to go into a engineering notebook.  First I'm waisting paper, second its not the write medium for an entire source code system.  Where are digital engineering notebooks? 

I propose that someone starts a company that is basically a limited access subversion repository ran by lawyers and IT specialist.  Client can use Tortoise SVN or the like to synch their directory changes to the server.  Someone can even have rules in place that require digital signatures before commits can happen.  If a patent dispute ever happens the company can show the directory in its state as of a certain disputed date.

What this gives you:

  • A way to backup your files
  • A clean medium for digital files like source code
  • Worry free notebook maintenance

The company could make a good deal of money charging for space and charging a lot of money for engineering audits. 


Well just a thought!

C# Code to cleanup Startmenu

I image my machine once a semester to clear off all the garbage I installed over the term. (I use partimage in case anyone cares).  Anyway I always have unsused shortcuts left in my startmenu since that lives on my d:\ drive which is where my data and profile are.  I wrote the code below to nuke bad shortcuts and empty shortcut directories.  It doesn't get all the uninstall files and readme links but its good enough!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using IWshRuntimeLibrary;

namespace ConsoleApplication12
class Program
static void Main(string[] args)
string path = @"D:\Michael\Start Menu\";

WshShell shell = new WshShell();
string[] files = Directory.GetFiles(path, "*.lnk", SearchOption.AllDirectories);
List<string> directories = new List<string>();
foreach (string file in files)
IWshShortcut link = shell.CreateShortcut(file) as IWshShortcut;
if (!System.IO.File.Exists(link.TargetPath))
Console.Write("Broken Shortcut");
System.IO.File.Copy(file, Path.Combine("C:\\oldshortcuts", Path.GetFileName(file)), true);
catch { Console.WriteLine("Error copying file and deleting file. Press any key to continue"); Console.ReadLine(); }
//now delete the old shortcuts
foreach (string dir in directories)
if (!Directory.Exists(dir)) { continue; }//we already deleted this!
DirectoryInfo info = new DirectoryInfo(dir);
if (info.GetFiles("*", SearchOption.AllDirectories).Length == 0)
Console.Write("Deleting directory");
catch { Console.WriteLine("Error Removing Directory. Press any key to continue"); Console.ReadLine(); }


Jul 2, 2008

Debugging in IronPythonStudio with PythonEngine

I was charged by the company I work for to add a code editor to our IronPython Application scripting engine. Originally the code editor was supposed to just be a friendly IDE.. but I wanted break points too. PythonStudio seemed like a good choice since it ships as a standalone application and can do Python breakpoints via our friend "the red dot" for break points.

Here is how it all goes together. First I created a class library in PythonStudio. I set a break point in PythonStudio so that my source looks like this.

The next thing I did was build a simple PythonEngine host in C#.

static void Main(string[] args)
EngineOptions eo = new EngineOptions();
eo.ClrDebuggingEnabled = true; //this is important! this turns on debugging!
PythonEngine pe = new PythonEngine(eo);
//create the class def from our code base
pe.ExecuteFile(@"D:\Michael\My Documents\IronPython Studio\ClassLibrary1\ClassLibrary1\");
Console.WriteLine("Please attach Python Studio if you want breakpoints :)");

You can see that I execute the python file from the directory that iron python studio placed its file. If you run this file in or out of debugging nothing happens. Why? Visual Studio doesn’t know about the breakpoints in your iron python studio project yet.

The final piece is attaching PythonStudio to the c# application where the python engine lives. To do this run the application without debugging.

Then in PythonStudio Attach PythonStudio to your c# application.

As you can see my project was called ConsoleApplication9.exe [Don’t we all love the visual studio generated project names]

Hit Enter in the command window once you have attached PythonStudio and watch your break point get hit!

Hit F5 and this will be your final output.

As you can see *most* of the work is done for you. All that is needed is delicate wiring of pieces and parts. Finally a way for us all to embed scripting that is more powerful than VBA and has a better editor than VBA.

IronPython Parser AST walker

I just thought I would post an example of an IronPython 1.1 parser for AST. You can override tons of methods on the ASTWalker class to get the job done.

Parser p=Parser.FromString(new IronPython.Runtime.SystemState(),new CompilerContext(),"a=5+10");
Statement e=p.ParseSingleStatement();
e.Walk(new ExpressionWalker());

public class ExpressionWalker : IronPython.Compiler.Ast.AstWalker
public override void PostWalk(NameExpression node)

Jun 30, 2008

Python Generation using the Code Dom

I was tasked with translating a meta data scripting engine from metadata to ironpython. Luckily, the CodeDom was the solution. I've gotta give those M$ credit here!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.CodeDom;
using IronPython.CodeDom;
using System.CodeDom.Compiler;

namespace TestApp
class Program
static void Main(string[] args)
PythonProvider prov = new PythonProvider();

//Create a test class
StringWriter sw=new StringWriter();
CodeTypeDeclaration targetClass = new CodeTypeDeclaration("testclass");
targetClass.IsClass = true;

System.CodeDom.CodeConstructor cont = new CodeConstructor();
cont.Parameters.Add(new CodeParameterDeclarationExpression("int", "test"));
cont.Name = "testclass";

prov.GenerateCodeFromType(targetClass, sw, new CodeGeneratorOptions());

//create an assignment statement
sw = new StringWriter();
CodeAssignStatement as1 = new CodeAssignStatement(new CodeVariableReferenceExpression("i"), new CodePrimitiveExpression(10));
prov.GenerateCodeFromStatement(as1, sw, new CodeGeneratorOptions());

And the output is...

class testclass(object):
__slots__ = []

def __init__(self, test):

i = 10
Press any key to continue . . .

May 27, 2008

Useful Powershell Script

Have you ever had a list of .ISO's that you needed to burn but were tired of setting each iso to burn individually. I often have this problem when I need to burn for instance the 5 iso's that vista shipped with. Below is a useful powershell script that will scan a directory or directories, find the ISO file, and ship it to ImgBurn. I have it setup so that it deletes the image. All you have to do is wait for the drive to eject your dvd.

function burn()
#get the files and ship them to burn-file
dir -recurse -include *.iso -path c:\,d:\,e:\ | foreach { burn-file $_.FullName }

function burn-file($filename)
#call img burn with the nessessary arguments
. "c:\Program Files\ImgBurn\ImgBurn.exe" /mode ISOWRITE /WAITFORMEDIA /start /close /DELETEIMAGE /EJECT /SRC $filename
#Wait for IMGBURN to finish (right now you can only have one open at a time)
while ( (get-process | where{$_.ProcessName -eq "ImgBurn"}) -ne $null)
#sleep for a bit to let the processor work on burning
Start-Sleep –s 10
#tell the user what file you are still working on
"waiting for $filename to complete"


#call the burn function

kick it on

May 21, 2008

Taking lessons from Web 1.0 and Web 2.0 to create web sync.

With the dawn of Web 2.0 web developers have enjoyed developing rich desktop like clients and speedy flashy websites that they could have never constructed before. Web 2.0 brought us the ability to maintain state while making requests to the server giving users the experience similar to desktop applications. What Web 2.0 didn't provide was a good model for taking results from those requests and operating on them appropriately. All the model controller code we wrote for Web 1.0 is now useless. While this doesn’t sound like a problem from the beginning it is a staggering problem considering all the controls available and that all of them have to be reimplemented in javascript. I'll admit that there are many new libraries out there but they can be difficult to extend.

In review :

Web 2.0

Provides a way to make asynchronous requests
Provides a way of requesting simple lightweight data and translating that to the screen

All the web 1.0 models have to be rewritten
Some operations can be quite weighty on the client end
No clean model of what should happen on the server and what should happen on the client

I wont discuss the success of Web 1.0 but the problems were obvious. Small state changes to a page required the user to redownload the entire page. For some websites this is still a clean model but for most this causes bandwidth issues.

My solution to take the good from both and leave the bad is to build what I am dubbing as "Web Synch". Web synch is a way to take an existing proven web 1.0 architecture like cgi, php, asp, and and give it the advantages of ajax. This takes the models we built in web 1.0 and the asynchrounous technology we developed in web 2.0 and combines them in a powerful new way. This new way operates on the principal of using the web 1.0 models to render a page. Once rendered the server sorts out what has changed. The changes are then shipped to the client rather than the entire page.

Below is a suggested implementation of web synch.

Initial request comes to the server
Page is rendered
Pages rendering is shipped as the response
The response is cached on the server
Page is submitted
Submit is captured and cancelled via "onsubmit" event
Form is serialized

Ajax request made simulating Postback
Second request comes to the server
Page is rendered
rendering compared to the previous request
difference serialized to json (add,update,delete,move)

Page returns from ajax request
JSON is deserialized
changes are merged into the dom

There are a few issues with this idea. One, it is going to require some memory management to store the old rendered page on the server. Two, it will take some processing power to determine changes to the rendered page. Finally, the only way to know that the page has changed is to have well formed html (everything must have ID's).

My first iteration will be targeted for server side and prototype on the client side.

kick it on

Feb 29, 2008

Running Asp.Net without a webserver

If you ever need to generate web pages that are static (for reporting etc) you often find yourself emitting html. Turns out Asp.Net is perfectly suited to do this.

class Program
static void Main(string[] args)
Page pg = new Page();
Label lbl = new Label();
lbl.Text = "Look ma no web server";
StringWriter sw=new StringWriter();
HtmlTextWriter tw = new HtmlTextWriter(sw);

All thats left is to either save the file or embed the file in the embedded ie window. You can leverage all the cool controls of but be sure to remember that there is no way this can postback.

Feb 21, 2008

Getting printf to work in avr-gcc \ winavr

Printf wiring in avr-gcc is fairly easy. First, make sure you add libm.a and printf_flt.a in avrstudio. See project options for help on this. Otherwise the lines below will get you started.

int main(void)

Init(); //init the system
fdevopen(&sys_putchar,NULL);//wire in stdout to sys_putchar
return 0;

//simple function that receive chars from stdout
int sys_putchar(char val,FILE* fle)
//write out to the LCD for now
//Put code here to pump a char to the uart port!
//TODO: uart_putchar
return 0;

Let me know if this doenst work! I wish I would have known about this earlier!

Feb 19, 2008

Hacking Gateways WinPE install disks

So if you hate bloatware on your gateway install disk you've probably done some crazy things to avoid it. I have tried slipstreaming a new xp install with disastrous consequences. My work around and this is awesome..... After gateway copies all the files to your computer it will boot in as a hidden user and show a screen telling you that its running scripts to setup your system. Wait until it has installed your drivers then... ctrl+alt+del and kill the install process. WinPE will shutdown your system and boot you back into windows. Its that easy to avoid bloat ware!

Gateway CX210X

Once done with this I image my machine using the "System Rescue CD" and use PARTIMAGE to image the HD.

The best setup i have found:
  • Get windows running.
  • Split your HDD into two parts (OS,FILES) using gparted on the "System Rescue CD"
  • Make sure your profile is on the FILES drive. (This is a bit tricky).
  • Image the OS drive using PARTIMAGE and a USB Harddrive.
  • Use Microsoft Sync Toy to sync your files with a server (who needs icremental backups?

Why linux hates my tablet

So with all the buzz about Virtual Box's seamless integration I decided to give windows the boot as my desktop enviroment.

What I found... My gateway CX210X does not play well with ubuntu. I had to compile drivers for the pen and it still doesnt work that well. Not only that but there is no way to rotate the screen. Everything else has worked well but its going to be sometime before I go down that route again.

I love ubuntu, hate windows but love my tablet even more than anything!

Dive into robotics

I have been taking a robotics class and have fallen in love with robotics. I am currently planning on teaching a robotic class for High School Students this summer. I will follow up with more information about what I am playing with for this class:

Beetle Bot (6 direction with use of H bridges)
Hex Bug (2 direction)
RC car bot (6 direction but H bridges come for free!)

It turns out RC car bot is the cheapest at $5.77 from walmart who can beat that! I'm planning on using Atmel MicroP's in the class with the AVRUBD firmware. My goal is to build simple line following robots for <$15 a piece.

Jan 3, 2008

Hello World

Hello world! This is my first of many blog entries of random cool things I have figured out in my life as a programmer etc.

Hope you check in soon!