The MIX 09 conference is well over in the US, and all the content is now available online, all the presentations were recorded. You can even get them all on the one page, instead of search the presentations for each day:
Sunday, April 5, 2009
Monday, March 23, 2009
iPod lap timer parser
The iPod Nano is a beautiful thing. That is unless you want to do something custom. So it is with the lap timer in it. There is no obvious way of synchronising the timer logs with the computer. Even if there is a way in ITunes (I’m pretty sure there isn’t), the point is moot, as I don’t use ITunes (instead I’m using the wonderful ml_ipod plugin for Winamp). This is “suboptimal” if you want to, for example, use the lap timer to chart your jogging progress over the course of a year. You want to crunch those stats in Excel or some such, you certainly aren’t going to copy them from the screen.
The information on the web is a little sparse on this matter, but there are a number of applications that will let you do this. The one that caught my eye was http://wafflesoftware.net/ipodtimer/ which luckily provided source code (Mac OS X only – aren’t we feeling exclusive). A relatively trivial exercise in parsing. The timer format was loosely described in the TimerFormat.txt in the zipped source. At least detailed enough for me to whip up an implementation in C#. Hence this post.
The underlying format is a binary file. Time to dust off .NET’s BinaryReader. The below method ReadTimerEntries(string filepath) will read in an iPod timer file (on my Nano it’s /IPod_Control/device/timer) and produce a list containing the date of the recording, and the associated laps. From there you have all the info you need. Anyway, it works for me, on an iPod Nano (3rd gen). I don’t imagine that the file structure changes much though.
- public partial class Form1 : Form
- {
- public Form1()
- {
- InitializeComponent();
- }
- private void button1_Click(object sender, EventArgs e)
- {
- OpenFileDialog ofd = new OpenFileDialog();
- ofd.FileName = Application.StartupPath;
- DialogResult dr =ofd.ShowDialog();
- if (dr == DialogResult.OK)
- {
- List<TimeEntry> entries = ReadTimerEntries(ofd.FileName);
- foreach (TimeEntry entry in entries)
- {
- System.Diagnostics.Debug.WriteLine(entry.EntryDate.ToString());
- foreach (TimeSpan ts in entry.Laps)
- {
- System.Diagnostics.Debug.WriteLine(ts.ToString());
- }
- }
- }
- }
- public List<TimeEntry> ReadTimerEntries(string filePath)
- {
- List<TimeEntry> results = new List<TimeEntry>();
- //open the file
- var stream = File.OpenRead(filePath);
- BinaryReader br = new BinaryReader(stream);
- br.ReadBytes(4); //start file
- while (!br.ReadBytes(4).SequenceEqual(new byte[] { 0x13, 0, 0, 0xC0 }))
- {
- //first 4 bytes are already consumed
- ReadRound(br, results);
- }
- return results;
- }
- private void ReadRound(BinaryReader br, List<TimeEntry> itemList)
- {
- br.ReadBytes((16 * 5));// guff
- br.ReadBytes(8);// start date
- byte seconds = br.ReadByte();
- byte minutes = br.ReadByte();
- byte hour = br.ReadByte();
- byte day = br.ReadByte();
- byte month = br.ReadByte();
- int year = br.ReadInt16();
- br.ReadByte(); //unknown use
- TimeEntry entry = new TimeEntry();
- entry.EntryDate = new DateTime(year, month, day, hour, minutes, seconds);
- itemList.Add(entry);
- br.ReadBytes(4); //end date
- br.ReadBytes(4); //start laps
- while (!br.ReadBytes(4).SequenceEqual(new byte[] { 0x10, 0, 0, 0xC0 }))
- {
- br.ReadBytes(4); //start lap
- int lapMilliseconds = br.ReadInt32(); //4 bytes
- TimeSpan lapTime = TimeSpan.FromMilliseconds(lapMilliseconds);
- entry.Laps.Add(new TimeSpan(0, 0, 0, 0, lapMilliseconds));
- br.ReadBytes(4); //end lap
- }
- br.ReadBytes(4); //end round
- }
- }
- public class TimeEntry
- {
- public DateTime EntryDate;
- public List<TimeSpan> Laps = new List<TimeSpan>();
- }
Sunday, March 22, 2009
Terminator Salvation – coming to cinemas May 21
Ahh, the Terminator movie that we’ve always wanted – entirely set in the future, focusing on the war between man and machine. I’ve always wondered when they would show the future they hinted at, a void slightly filled by the Terminator TV series (Sarah Connor Chronicles). Another point of note is that this coming instalment is but the beginning of a Terminator revival – part of a new trilogy apparently. And you can’t go wrong with Christian Bale as John Connor.
Thursday, March 5, 2009
Reading database tables in Powershell
Firstly, a correction. Last time I posted about Powershell, I came up with something that did the job, but was, well, a tat long winded. Kind of like building a skyscraper so that you can store garden tools in the basement. Basically I didn’t realise that the Sort cmdlet already had a –Unique switch. Thanks to Stephen Mills for pointing it out:
import-csv c:\mydata.csv | select Category, Subcategory | sort category, subcategory -Unique | Group-Object -Property category
Now to the business at hand – reading database tables. Consider a situation where you’re asked to read in the data in a database table into some readable form, for reference, printing or whatnot. Rather than using SQL Management Studio to query the results, selecting the entire results grid, copying it, pasting into Excel (if available on the same machine), or into a text file, then getting it into Excel – you could just use Powershell to connect to the DB and dump out the results into a HTML table. Behold:
- # Parse Database tables
- # This will connect to a database, do a "select *" on a table or view, and produce a html file with the data in a table.
- # Note: don't forget to loosen up your execution policy "Set-ExecutionPolicy Unrestricted"
- # and the connection string is ADO style : "Data Source=database;Initial Catalog=oesc_offerman;User Id =username;Password=password;Trusted_Connection=False;"
- param (
- $connectionString = $(throw "Specify connection string" ),
- $tableName = $(throw "Specify a table or view name"),
- $outputPath = $(throw "Specify output path")
- )
- echo ("Processing " + $tableName)
- $table = new-object System.Data.DataTable;
- $sqlConn = new-object System.Data.SqlClient.SqlConnection($connectionString);
- $sqlConn.Open();
- $adapter = new-object System.Data.SqlClient.SqlDataAdapter(("select * from " +$tableName),$sqlConn);
- $adapter.Fill($table);
- $sqlConn.Close();
- $table.Rows | ConvertTo-Html | out-file $outputPath
Wednesday, March 4, 2009
Fish blimp
Saturday, February 21, 2009
“SELECT DISTINCT” in Excel and Powershell
Just recently at work we had to import a large dataset into a database, but two of the columns were “category” and “subcategory”. Naturally we wanted these in a separate table, so we needed a way of parsing through the existing data and get the unique categories, and the unique matching subcategories for each.
Excel:
Firstly, there’s the Excel ‘07 way (most likely also possible in other versions too):
Select the two columns that hold your categories and subcategories. Go to the “Advanced” menu item in Filtering:
The presented dialog has the option of “Unique Records Only”
Done, it’s the equivalent of doing a “distinct” in SQL. Now sort the data, and you’re ready to go.
Powershell:
But no discussion of parsing/manipulating data is complete without mentioning Powershell – surely we can do this in PS. Let’s assume that the data was saved in csv form (you could always save your Excel spreadsheet as .csv).
Luckily, there’s already a command that is able to parse csv’s for us: “Import-Csv”. This cmdlet will parse the csv and create objects that have properties named after the columns – in the below image you can see that the object has a “Category” and “SubCategory” property.
Now that we have this collection of objects, use your favourite way of flushing out duplicates. I’m keen on building up a new list, checking on each insert that the same entry doesn’t exist:
- $temp = @{}
- $data | foreach {
- if ($temp.ContainsKey($_.Category))
- {
- #check if subcategory exists, insert subcategory if doesnt
- if ($temp[$_.Category].ContainsValue($_.Subcategory) -eq $false)
- {
- $temp[$_.Category].Add($_.Subcategory, $_.Subcategory);
- }
- }
- else
- {
- #put it in:
- $temp.Add($_.Category, @{$_.Subcategory = $_.Subcategory});
- }
- }
This is all well and good, but there are issues. The "Category” property names are hardcoded, and it depends on an existing $data variable. Ideally we want a cmdlet that can support piping, and will let us specify the names of the columns.
Luckily for us, Powershell is able support the following constructs:
What happened there is by putting the variable in brackets, PS will evaluate the variable and put it in the script. I was able to create a variable $somestring, which had a string value of “Subcategory”. When I used it in brackets, it expanded out to “Subcategory” in the script, and functioned in the same way as $data[2].Subcategory. Neat. This is an invaluable feature in scripting.
So we replacing all places where we previously had “Category” and “Subcategory” with expansions, and add them as required parameters.
Last thing, we need to get rid of the assumption of pre-existing $data variable. Ideally the input will be piped in. No problem, the reserved $input variable is the piped in parameters.
So now we can call it like so:
import-csv c:\MyTest.csv | c:\categoryParser.ps1 "Category" "Subcategory"
The final script looks like this:
- param (
- $categoryName = $(throw "Specify category column name" ),
- $subcategoryName = $(throw "specify subcategory name")
- )
- $temp = @{}
- $input | foreach {
- if ($temp.ContainsKey($_.($categoryName)))
- {
- #check if subcategory exists, insert subcategory if doesnt
- if ($temp[$_.($categoryName)].ContainsValue($_.($subcategoryName)) -eq $false)
- {
- $temp[$_.($categoryName)].Add($_.($subcategoryName), $_.($subcategoryName));
- }
- }
- else
- {
- #put it in:
- $temp.Add($_.($categoryName), @{$_.($subcategoryName) = $_.($subcategoryName)});
- }
- }
- #dump out the output
- $temp
And produces something like this, a hashtable of objects each of which has the category name, and a hashtable of subcategories.
From here it would be easy to traverse them all with two nested foreach loops, and do whatever with them, like generating INSERT statements.
Friday, February 6, 2009
Minotaur in a China Shop
I have a soft spot for independent games – possibly the last bastion of innovation in computer gaming. Came across a very amusing little independent game, about a Minotaur running a fine china shop. The game is 3D, isometric perspective. Runs in the browser. The minotaur isn’t exactly light on his feet, and handles like fridge - thus there are two ways to win – trash your own shop to get an insurance payoff, or service customers. Give it a go – most amusing.
http://blurst.com/minotaur-china-shop/play
Minotaur China Shop Trailer from Flashbang Studios on Vimeo.