Clone all your repositories on another machine

Recently I was configuring a new machine (God, i love Chocolatey) and I wanted to take all the repositories I have under c:/src and clone them on my new machine. Here is how i did that:

# write all remote fetch locations into repositories.txt
find /c/src -type d -mindepth 1 -maxdepth 1 -exec git --work-tree={} --git-dir={}/.git remote -v \; | grep fetch | awk '{print $2}' > repositories.txt

# clone each repository
cat repositories.txt | xargs -l1 git clone

Or as a gist:

A parameterized active pattern to match the first elements of an array

Been writing code in F# for almost a year and never blogged about it. Time to change that ;) Earlier today someone asked the following on twitter:

Is it possible to pattern match the first part of an array in #FSharp? Something like | 1::2::3::tail but for arrays? #lazyweb

I accepted the challenge ;)

let (|Array|_|) pattern toMatch =
    let patternLength = Array.length pattern
    let toMatchLength = Array.length toMatch
    let tailLength = toMatchLength - patternLength

    if patternLength > toMatchLength then
        let firstElementsAreEqual = [ 0 .. (patternLength - 1) ] |> Seq.forall (fun i -> pattern.[i] = toMatch.[i])
        if firstElementsAreEqual then
            Some(Array.sub toMatch patternLength tailLength)
match [|1;2;3|] with
| Array [|1|] tail -> sprintf "bingo %i" (tail |> Array.sum) // the tail is [|2;3|]

Or as a gist:

Comments are disabled on this blog

As of now comments are disabled on this blog. Want to reply? Write your own post and pingback or engage a conversation on twitter with @timvw.

The curious case of trailing spaces in SQL

A while ago I was quite surprised to see that the following query returns 1 instead of 0:

SELECT COUNT(*) WHERE N'Tim' = N'Tim '; -- notice the trailing space

Apparently this is just standard behaviour. Here is an extract from sql1992.txt (Section 8.2 Paragraph 3):

     3) The comparison of two character strings is determined as fol-

            a) If the length in characters of X is not equal to the length
              in characters of Y, then the shorter string is effectively
              replaced, for the purposes of comparison, with a copy of
              itself that has been extended to the length of the longer
              string by concatenation on the right of one or more pad char-
              acters, where the pad character is chosen based on CS. If
              CS has the NO PAD attribute, then the pad character is an
              implementation-dependent character different from any char-
              acter in the character set of X and Y that collates less
              than any string under CS. Otherwise, the pad character is a

            b) The result of the comparison of X and Y is given by the col-
              lating sequence CS.

            c) Depending on the collating sequence, two strings may com-
              pare as equal even if they are of different lengths or con-
              tain different sequences of characters. When the operations
              MAX, MIN, DISTINCT, references to a grouping column, and the
              UNION, EXCEPT, and INTERSECT operators refer to character
              strings, the specific value selected by these operations from
              a set of such equal values is implementation-dependent.

Sample query to demonstrate influence of collation in Sql Server

Lately I had the pleasure to investigate collations and here is a sample query that demonstrates how a collation impacts the behaviour of a query:

WITH [Words] AS (
	SELECT N'Een' AS [word]
	SELECT [word]
	FROM [Words]
	WHERE [word] 
		--COLLATE Latin1_General_CS_AS -- returns Een
		--COLLATE Latin1_General_CI_AI -- returns Een, Eèn and EEN
		--COLLATE LAtin1_General_CI_AS -- returns Een and EEN
		COLLATE Latin1_General_CS_AI -- returns Een and Eèn
		= N'Een';

Copy all mp3 files in Music folder to USB dribe

Copying all mp3 files from my Music folder to a USB drive is pretty easy on my Macbook:

find Music -name *.mp3 -exec cp {} /Volumes/SANDISK \;

Using eID on OS X Mountain Lion

Last week or so I got myself a MacBook Air and I am really loving it so far. Today I needed to use my eID so I installed the middleware application without any hassle but had a hard time configuring Safari. Apparently Apply removed support for PKCS #11 in OS X Mountain Lion. After installing SmartCard Services the certificates appeared in the Keychain and I became able to authenticate on websites using my certificate

Add missing books to iTunes

These days i read most books on my ipad. The problem is that iTunes does not seem to add pdf files when i choose ‘Add Folder’ to the library. So here is a small application that adds them one by one (way too lazy/unmotivated to do this by hand).

Multiclean solution

One of my favorite powershell commands when cleaning up:

$RootFolder = 'C:\tfs'
Get-ChildItem $RootFolder bin -Recurse | Remove-Item -Recurse
Get-ChildItem $RootFolder obj -Recurse | Remove-Item -Recurse

An example of Common Table Expression and Window function usage…

Earlier this week some colleague had been assigned a maintenance task and asked me how I would solve it. Every customer is permitted to have an amount of publications. All excess publications should be removed from the system (only the n most recent ones are permitted to remain on the system).

Here is an example of the Customer table:

CREATE TABLE [dbo].[Customer](
	[CustomerId] [int] IDENTITY(1,1) NOT NULL,
	[CustomerName] [nvarchar](50) NOT NULL,
	[PermittedPublications] [int] NOT NULL

INSERT INTO [dbo].[Customer] 
			([CustomerName], [PermittedPublications]) 
			('timvw', 2),
			('mike', 3);

An example of the customer publications table:

CREATE TABLE [dbo].[Publication](
	[PublicationId] [int] IDENTITY(1,1) NOT NULL,
	[CustomerId] [int] NOT NULL,
	[PublicationName] [nvarchar](50) NOT NULL,
	[PublicationTime] [datetime2] NOT NULL
INSERT INTO [dbo].[Publication] 
			([CustomerId], [PublicationName],[PublicationTime])
			((SELECT [CustomerId] FROM [dbo].[Customer] WHERE [CustomerName] = 'timvw'), 'tim pub1', SYSUTCDATETIME()),
			((SELECT [CustomerId] FROM [dbo].[Customer] WHERE [CustomerName] = 'timvw'), 'tim pub2', SYSUTCDATETIME()),
			((SELECT [CustomerId] FROM [dbo].[Customer] WHERE [CustomerName] = 'timvw'), 'tim pub3', SYSUTCDATETIME()),
			((SELECT [CustomerId] FROM [dbo].[Customer] WHERE [CustomerName] = 'timvw'), 'tim pub4', SYSUTCDATETIME()),
			((SELECT [CustomerId] FROM [dbo].[Customer] WHERE [CustomerName] = 'mike'), 'mike pub1', SYSUTCDATETIME()),
			((SELECT [CustomerId] FROM [dbo].[Customer] WHERE [CustomerName] = 'mike'), 'mike pub2', SYSUTCDATETIME());

My colleague was keen on using some cursor logic, but I demonstrated him how a set-based alternative:

WITH [RankedPublication] AS (
	SELECT [CustomerId]
	      ,ROW_NUMBER() OVER(PARTITION BY [CustomerId] ORDER BY [PublicationTime]) AS [PublicationRank]
	FROM [dbo].[Publication]
), [ExcessPublication] AS (
	SELECT [PublicationId]
	FROM [RankedPublication]
	INNER JOIN [dbo].[Customer] ON [Customer].[CustomerId] = [RankedPublication].[CustomerId]
	WHERE [PublicationRank] > [Customer].[PermittedPublications]
	DELETE FROM [dbo].[Publication]
	WHERE [PublicationId] IN (SELECT [PublicationId] FROM [ExcessPublication]);