All posts by David Davidson

Converting Picasa ini dates to directory dates

One issue I faced in the process of migrating from Picasa to Adobe Lightroom is that Picasa stores event dates in .picasa.ini files. I had spent many hours setting correct dates in my events (folders) and wanted to import them. So I wrote the following C# script (should work for Windows and OS X – I ran in via Mono).

Update: This code is on github @ https://github.com/DavidVeksler/EmbedPicasaProperties

The below will not be updated.

using System;
using System.IO;
 
namespace ConvertPicasaToFolderDates
{
        class MainClass
        {
                private const string IniFileName = @".picasa.ini";
 
                private static void Main(string[] args)
                {
                        string startFolder = @"/Users/davidv/Pictures/";
 
                        Console.WriteLine(startFolder);
 
                        UpdateFoldersInPath(startFolder);
 
                }
 
                private static void UpdateFoldersInPath(string folder)
                {
                        string[] directories = Directory.GetDirectories(folder);
 
                        if (directories.Length > 0)
                                Console.WriteLine("{0} folders in {1}", directories.Length, folder);
 
                        foreach (string directory in directories)
                        {
                                try
                                {
                                        string iniPath = Path.Combine(directory, IniFileName);
 
                                        if (File.Exists(iniPath))
                                        {
                                                Console.WriteLine("Parse " + iniPath);
 
                                                foreach (string line in File.ReadAllLines(iniPath))
                                                {
                                                        // date=29586.603900
                                                        if (!line.StartsWith("date=")) continue;
 
                                                        string dateString = line.Substring(5);
 
                                                        DateTime date = ConverPicasaDateToDateTime(dateString);
 
                                                        DateTime originalTime = Directory.GetCreationTime(directory);
 
                                                        if (originalTime != date && date.Year < 2010)
                                                        {
                                                                Console.WriteLine("{0} to {1}", originalTime, date);
                                                                Directory.SetCreationTime(directory, date);
// (For Mono SetCreationTime did not work correctly, so use SetLastWriteTime.)
                                                                Directory.SetLastWriteTime(directory,date);
                                                        }
 
                                                        break;
                                                }
                                        }
                                }
                                catch (Exception ex)
                                {
                                        Console.WriteLine(ex);
                                }
 
                                try
                                {
                                        UpdateFoldersInPath(directory);
                                }
                                catch (Exception ex)
                                {
                                        Console.WriteLine(ex);
                                }
                        }
                }
 
                // convert =29586.603900 to date time format
                private static DateTime ConverPicasaDateToDateTime(string dateString)
                {
                        var startDate = new DateTime(1900, 1, 1);
 
                        DateTime date = startDate.AddDays(Convert.ToDouble(dateString) -2);
 
                        Console.WriteLine("new date: " + date);
 
                        return date;
                }
        }
}

 

Note on Community Server to WordPress migration

This post has has the full scoop on the process of migrating blogs from Community Server to WordPress, except for this bit: “ultimately, I just wrote a simple regular expression to reformat all the categories so that their names were in the ID attribute.”  Instead of regex, I wrote a a C# script using LINQ to XML:

const string source = @"D:export.xml";
           string source = @"D:export.xml";
            var doc = XDocument.Load(source);
            var categories = new Dictionary();
            foreach (var cat in doc.Elements().First().Elements().Descendants().Where(cat => cat.Name.LocalName == "tag"))
            {
                if (cat.Attribute("id") != null)
                {
                    categories.Add(Convert.ToInt32(cat.Attribute("id").Value), cat.Elements().First().Value);
                }
                else
                {
                    int refId;
                    if (int.TryParse(cat.Attribute("ref").Value, out refId)) // in case it was already run
                    {
                        cat.Attribute("ref").Value = categories[refId];
                    }
                }
            }
            doc.Save(source);

Distributing .Net apps for Windows and OS X

I wanted to distribute the desktop client I made for https://cryptabyte.com/ as a single .exe, without any install or additional DLL’s.  I used ILMerge, a tool from Microsoft Research to merge all the assemblies into one DLL. (If you have the .Net 4.5 beta installed like me, read this  to target .Net 4.0.)  I merged the assemblies with ILMerge:

ILMerge.exe /target:CryptAByte /out:Crypt.exe /targetplatform:"v4,C:Program Files (x86)Reference AssembliesMicrosoftFramework.NETFrameworkv4.0" CryptAByte.exe CryptAByte.CryptoLibrary.dll CryptAByte.Domain.dll Ionic.Zip.dll

ILMerge has the added benefit of making the merged DLL slightly smaller that than the sum of its parts.

I wanted my app to run on OS X too. After I stripped out the Entity Framework Code First data annotations from my data structures, it compiled and ran smoothly on OS X:

Actually, that doesn’t look very good at all. The Mono WinForms color scheme has some kind of sickly yellow tinge to it.  I want to distribute this without requiring Mono to be installed, so I used macpack:

macpack -m:2 -o:. -r:/Library/Frameworks/Mono.framework/Versions/Current/lib/ CryptAByte.Domain.dll CryptAByte.CryptoLibrary.dll Ionic.Zip.dll -n:CryptAByte -a:CryptAByte.exe

The resulting .app was over 300MB!  Looks like I’m going to have to write a native client for OS X.

Monitoring OS X battery usage

Speaking of power usage, there are two nice apps to help monitor battery usage in OS X. CoconutBattery is mostly useful for checking the health of the battery.

 

MiniBatteryLogger is a more advanced tool that monitors power consumption and levels over time. You can use it to see how particular configurations are consuming power.

Another, slightly related app is fseventer. fseventer shows filesystem access in real time and provides nice insight into what apps are using the hard drive.


Note on iOS (iPhone/iPad) background app energy usage

There is some confusion about the impact of background apps on iOS on battery life. Some prominent sources advise “quitting” all background apps to maximize batter life while others say that background apps are suspended and use no battery.

Actually, both statements are true. The confusing part is that iOS does not visually indicate suspended versus running background apps. Some apps are will obviously use power in the background – GPS navigation, instant messaging, or a music player. In other cases, it is not clear.

While there are many apps in the App Store that claim to help “improve” battery life, Apple does not allow access to any API which can have any impact on battery life. The only way to do so is to jailbreak your iPhone/iPad and install an app like BatteryDetective, which can measure how much power background apps and services actually use.  (It also the only app which can tell you how much charge your iPhone battery can retain.)

In my brief testing, I made a few surprises. When an iPhone is not actively being used (the screen is off), the biggest power drain are the various radios: WiFi, 3G and Bluetooth. So first tip is to turn off any service you don’t need. SBSettings is useful in doing so with one tap:

Here are some sample measurements (not intended to be typical) in milli-amp drain in the background: iPod: 50mA, Gmail App: 185mA, Skype: 265mA. I found that some apps are seeming unnecessary energy-hogs: why does Skype use so much power in idle mode? I also found that the built-in Messages app was using way too much power – which went down after I deleted some of four years of received SMS and MMS messages.

BatteryMeter has a manual mode so you can take samples when toggling background services:

Unfortunately, measuring the power usage of apps and services is not practical for most users. So if you want to maximize battery life, just (1) turn off any function/service you don’t need and (2) remember that when and only when an app is doing anything in the background, it will drain the battery.

How often do you read code?

It is very possible and probably common to go through a major team development effort without spending very much time reading other people’s code. It’s possible to spend an entire career like that. If over 90% of the code you read is your own, how will you learn to be a better programmer?  No matter how many thousands of hours you spend programming, if you are doing only what you already know, you will not improve your skills. You must challenge yourself and sometimes fail to improve.

How can you read other people’s code?

  • Read your team members code
  • Read (& refactor) your old code – you probably forgot what you did already
  • Read books on software & algorithms
  • Participate in open source projects
  • Read blogs on software
  • Write a programming blog

A few useful commands for automating VS builds via batch file

(Batch files are not meant to be a substitute for CI)

Getting latest from TFS:

"C:Program Files (x86)Microsoft Visual Studio 10.0Common7IDEtf.exe" get

(use /preview to preview)

Getting latest from Subversion:

"C:Program Files (x86)VisualSVN Serverbinsvn.exe" update "F:webBeta"

Building a Visual Studio solution via MSBuild:

C:WindowsMicrosoft.NETFramework64v4.0.30319MSBuild.exe D:MisesMisesWeb.sln /p:configuration="Debug"

Checking whether the build succeded:

if %errorlevel% neq 0 exit /b %errorlevel%
REM BUILD OK, GO TO NEXT STEP

Copying build output:

xcopy F:webBetaMisesWebbin* F:webMisesbin /Y
REM /Y don’t prompt for overwrite
REM /S recursive
REM /Z restartable mode
REM /D only copy files newer than those at destination
REM More: http://www.computerhope.com/xcopyhlp.htm