Sunrise Düsseldorf Medienhafen

Got up early again to watch the sunrise. Apologies for the blurriness of the first two pictures. I should have brought a tripod.

Advertisements

Hiking at Baldeneysee

On Saturday I decided to get up early and take the train to Baldeneysee on the river Ruhr to see the sun rise over the lake form Hügel and then hike on the Baldeneysteig trail in the mountains above.

Despite having to rise early on a day off work, this was the most beautiful experience. The weather was perfect for the occasion resulting in the gorgeous pictures you see below.

Sunrise

Hike




Arrival in Kupferdreh


The Case of Low Disk Space because of another User’s Recycle Bin

The Problem

The other day, I got an alert that one machine was running low on disk space. I used WinDirStat to find out that one of the largest folders was a sub-folder of the recycle bin. These folders are named with the Security Identifier (SID) of the user they belong to.

Now I only needed to find out which user this SID belonged to.

The Solution

This article on TechNet provides PowerShell snippets showing which .NET classes to use to translate between Security Identifiers and user names. I evolved these snippets into the following helper functions which as always can be found in my PowerShell Utilities on GitHub.

Function Convert-SidToUsername($SidString)
{
    $sid = New-Object System.Security.Principal.SecurityIdentifier($SidString)
    
    try
    {
       $user = $sid.Translate([System.Security.Principal.NTAccount])
       $result = $user.Value
    }
    catch
    {
        $result = "Unknown user: $SidString"
    }
    return $result
}


Function Convert-UsernameToSid($Domain = "", $Username)
{
    if ($Domain)
    {
        $user = New-Object System.Security.Principal.NTAccount($Domain, $Username)
    }
    else
    {
        $user = New-Object System.Security.Principal.NTAccount($Username)
    }
    try
    {
        $sid = $user.Translate([System.Security.Principal.SecurityIdentifier])
        $result = $sid.Value
    }
    catch
    {
        $result = "Unknown user: $Domain\$Username"
    }
    return $result
}

Knowing their name I could now ask the user to log onto the machine in question an empty their recycle bin.

It might be that with administrative privileges I could delete the SID-named folder myself, but I felt it best not to mess with the internal folder structure of the recycle bin.

The Case of Lightroom Placing all Photos at the End of the Track: Sorting a GPX File

The Problem

Using the Map module of Lightroom and a GPX file containing a track log, photos were supposed to be placed on the track based on the time they were taken. However, Lightroom placed all photos at end of the track, even though photos were taken at various times at various places along the track. Looking in to the GPX file it was verified that there were more suitable track points for Lightroom to match the photos against.

The Cause

It seems that Lightroom expects the track points in the GPX file to be in chronological order (i.e. oldest track point first) and it will associate a photo with the first track point that has a time stamp newer than the photo. In this case, the track points were in descending order (i.e. the end of the track was at the top of the file), so all photos matched this track point and hence placed at the end of the track.

The Solution

GPX files are simply XML files, so I wrote the following PowerShell script to sort the track points by time and save the result to a new GPX file.

[xml]$xml = Get-Content 'MyTrack.gpx'
($points = ($xml.gpx.trk.trkseg.trkpt | Sort-Object -Property time -Descending) ) | Out-Null
$firstPoint = $points[-1]
$points | ForEach-Object { $xml.gpx.trk.trkseg.InsertAfter($_, $firstPoint) } | Out-Null
$xml.Save('MyTrackSorted.gpx')

Since time stamps are in ISO 8601 format they can be sorted as strings.

All output is piped to Out-Null since there are a lot of track points that would otherwise take a long time to print and needlessly slow down the script.

Making this work with multiple track segments in a single file is left as an exercise to the reader.

Reading up on LINQ-equivalents in Python

I have been dabbling a bit in Python recently, even though my main focus is still C#. Hence, one thing I’ve really missed is LINQ. And when I say LINQ, I mostly mean LINQ to Objects and the extension methods on the Enumerable class. I’m not a big fan of the “from… select…where” syntax. While LINQ can be a bit overwhelming at first, there are now quite a few LINQ methods I can no longer do without.

There are two articles by Mark Heath on this topic I can recommend:

What I think this “Pythonic” approach lacks is LINQ’s ability to chain together operations by writing them out left to right, as each LINQ method operating on an instance of IEnumerable returns another IEnumerable.

There are those that say that Python does not need something like LINQ. I disagree. The fluent syntax of LINQ method calls chained together is a major readability improvement over the classic approach of nested function calls.

Luckily, there are open-source projects filling this void, e.g.

  • py-linq is pretty straightforward with methods named exactly as their LINQ counterparts on a class called Enumerable.
  • asq is another one with pretty similar design principles.
  • And then there is RxPy a library for reactive programming in Python which has chaining like LINQ methods and a whole lot more.