I've just put up an update for Encode-O-Matic with the following improvements:
The new name reminds me of the show Friends. Also, I hope they get a new favicon - I don't enjoy the stretched 'b' nor its color scheme.
A while ago I promised to say how an xsltproc Meddler script would be useful and the general answer is its useful for hooking up a client application that wants data from the web in a particular XML format and the data is available on the web but in another XML format. The specific case for this post is a Flickr Search service that includes IE8 Visual Search Suggestions. IE8 wants the Visual Search Suggestions XML format and Flickr gives out search data in their Flickr web API XML format.
So I wrote an XSLT to convert from Flickr Search XML to Visual Suggestions XML and used my xsltproc Meddler script to actually apply this xslt.
After getting this all working I've placed the result in two places: (1) I've updated the xsltproc Meddler script to include this XSLT and an XML file to install it as a search provider - although you'll need to edit the XML to include your own Flickr API key. (2) I've created a service for this so you can just install the Flickr search provider if you're interested in having the functionality and don't care about the implementation. Additionally, to the search provider I've added accelerator preview support to show the Flickr slideshow which I think looks snazzy.
Doing a quick search for this it looks like there's at least one other such implementation, but mine has the distinction of being done through XSLT which I provide, updated XML namespaces to work with the released version of IE8, and I made it so you know its good.
On the topic of made up words: I get made up words for made up things, but there's already a name for cell-phone in English: its "cell-phone". The narrator notes that the book has been translated into English so I guess I'll blame the fictional translator. Anyway, I wasn't bothered by the made up words nearly as much as some folk. Its a good thing I'm long out of college because I can easily imagine confusing the names of actual concepts and people with those from the book, like Hemn space for Hamming distance. Towards the beginning, the description of slines and the post-post-apocalyptic setting reminded me briefly of Idiocracy.
Recently, I've been reading everything of Charles Stross that I can, including about a month ago, The Jennifer Morgue from the surprisingly awesome amalgamation genre of spy thriller and Lovecraft horror. Its the second in a series set in a universe in which magic exists as a form of mathematics and follows Bob Howard programmer/hacker, cube dweller, and begrudging spy who works for a government agency tasked to suppress this knowledge and protect the world from its use. For a taste, try a short story from the series that's freely available on Tor's website, Down on the Farm.
Coincidentally, both Anathem and the Bob Howard series take an interest in the world of Platonic ideals. In the case of Anathem (without spoiling anything) the universe of Platonic ideals, under a different name of course, is debated by the characters to be either just a concept or an actual separate universe and later becomes the underpinning of major events in the book. In the Bob Howard series, magic is applied mathematics that through particular proofs or computations awakens/disturbs/provokes unnamed horrors in the universe of Platonic ideals to produce some desired effect in Bob's universe.
I'm a big fan of the concept of registerProtocolHandler in HTML 5 and in FireFox 3, but not quite the implementation. From a high level, it allows web apps to register themselves as handlers of an URL scheme so for (the canonical) example, GMail can register for the mailto URL scheme. I like the concept:
registerProtocolHandler("info:lccn/{lccnID}", "htttp://www.librarything.com/search_works.php?q={lccnID}", "LibraryThing LCCN")
PowerShell gives us a real CLI for Windows based around .Net stuff. I don't like the creation of a new shell language but I suppose it makes sense given that they want something C# like but not C# exactly since that's much to verbose and strict for a CLI. One of the functions you can override is the TabExpansion function which is used when you tab complete commands. I really like this and so I've added on to the standard implementation to support replacing a variable name with its value, tab completion of available commands, previous command history, and drive names (there not restricted to just one letter in PS).
Learning the new language was a bit of a chore but MSDN helped. A couple of things to note, a statement that has a return value that you don't do anything with is implicitly the return value for the current function. That's why there's no explicit return's in my TabExpansion function. Also, if you're TabExpansion function fails or returns nothing then the builtin TabExpansion function runs which does just filenames. This is why you can see that the standard TabExpansion function doesn't handle normal filenames: it does extra stuff (like method and property completion on variables that represent .Net objects) but if there's no fancy extra stuff to be done it lets the builtin one take a crack.
Here's my TabExpansion function. Probably has bugs, so watch out!
function EscapePath([string] $path, [string] $original)
{
if ($path.Contains(' ') -and !$original.Contains(' '))
{
'"' $path '"';
}
else
{
$path;
}
}
function PathRelativeTo($pathDest, $pathCurrent)
{
if ($pathDest.PSParentPath.ToString().EndsWith($pathCurrent.Path))
{
'.\' $pathDest.name;
}
else
{
$pathDest.FullName;
}
}
# This is the default function to use for tab expansion. It handles simple
# member expansion on variables, variable name expansion and parameter completion
# on commands. It doesn't understand strings so strings containing ; | ( or { may
# cause expansion to fail.
function TabExpansion($line, $lastWord)
{
switch -regex ($lastWord)
{
# Handle property and method expansion...
'(^.*)(\$(\w|\.) )\.(\w*)$' {
$method = [Management.Automation.PSMemberTypes] `
'Method,CodeMethod,ScriptMethod,ParameterizedProperty'
$base = $matches[1]
$expression = $matches[2]
Invoke-Expression ('$val=' $expression)
$pat = $matches[4] '*'
Get-Member -inputobject $val $pat | sort membertype,name |
where { $_.name -notmatch '^[gs]et_'} |
foreach {
if ($_.MemberType -band $method)
{
# Return a method...
$base $expression '.' $_.name '('
}
else {
# Return a property...
$base $expression '.' $_.name
}
}
break;
}
# Handle variable name expansion...
'(^.*\$)([\w\:]*)$' {
$prefix = $matches[1]
$varName = $matches[2]
foreach ($v in Get-Childitem ('variable:' $varName '*'))
{
if ($v.name -eq $varName)
{
$v.value
}
else
{
$prefix $v.name
}
}
break;
}
# Do completion on parameters...
'^-([\w0-9]*)' {
$pat = $matches[1] '*'
# extract the command name from the string
# first split the string into statements and pipeline elements
# This doesn't handle strings however.
$cmdlet = [regex]::Split($line, '[|;]')[-1]
# Extract the trailing unclosed block e.g. ls | foreach { cp
if ($cmdlet -match '\{([^\{\}]*)$')
{
$cmdlet = $matches[1]
}
# Extract the longest unclosed parenthetical expression...
if ($cmdlet -match '\(([^()]*)$')
{
$cmdlet = $matches[1]
}
# take the first space separated token of the remaining string
# as the command to look up. Trim any leading or trailing spaces
# so you don't get leading empty elements.
$cmdlet = $cmdlet.Trim().Split()[0]
# now get the info object for it...
$cmdlet = @(Get-Command -type 'cmdlet,alias' $cmdlet)[0]
# loop resolving aliases...
while ($cmdlet.CommandType -eq 'alias') {
$cmdlet = @(Get-Command -type 'cmdlet,alias' $cmdlet.Definition)[0]
}
# expand the parameter sets and emit the matching elements
foreach ($n in $cmdlet.ParameterSets | Select-Object -expand parameters)
{
$n = $n.name
if ($n -like $pat) { '-' $n }
}
break;
}
default {
$varNameStar = $lastWord '*';
foreach ($n in @(Get-Childitem $varNameStar))
{
$name = PathRelativeTo ($n) ($PWD);
if ($n.PSIsContainer)
{
EscapePath ($name '\') ($lastWord);
}
else
{
EscapePath ($name) ($lastWord);
}
}
if (!$varNameStar.Contains('\'))
{
foreach ($n in @(Get-Command $varNameStar))
{
if ($n.CommandType.ToString().Equals('Application'))
{
foreach ($ext in @((cat Env:PathExt).Split(';')))
{
if ($n.Path.ToString().ToLower().EndsWith(($ext).ToString().ToLower()))
{
EscapePath($n.Path) ($lastWord);
}
}
}
else
{
EscapePath($n.Name) ($lastWord);
}
}
foreach ($n in @(Get-psdrive $varNameStar))
{
EscapePath($n.name ":") ($lastWord);
}
}
foreach ($n in @(Get-History))
{
if ($n.CommandLine.StartsWith($line) -and $n.CommandLine -ne $line)
{
$lastWord $n.CommandLine.Substring($line.Length);
}
}
# Add the original string to the end of the expansion list.
$lastWord;
break;
}
}
}
The names in the following anecdote have been changed. Except for my name (I'm Dave).
I got a new laptop a while back. I had it in my office and Tim came in to ask me something but paused when he saw my laptop. "Oh, is this one of those new touch screen laptops?" he asked, the whole time moving his hand towards my laptop and punctuating his sentence by pressing his finger to the screen. "No" I responded.
Walking down a hallway I heard Winston, one of our managers, say, "Hey Tim!" Winston catches up to me and asks, "Are you almost done with the XYZ bug?" I realized Winston was talking to me and got my name wrong but I figured I'll ignore it and perhaps he'll realize his mistake. Winston continued "I just talked with some people who say they're blocked and waiting for Tim to finish the XYZ bug." "Dave" I said helpfully attempting to diplomatically correct Winston since he apparently hadn't realized his error. "No, it was Jeremy and Bill." Winston said naming the people he had talked to who were waiting for me to fix the XYZ bug. At this point I decided it would be easier to just answer his question and end the conversation than to get into this whole thing. As far as I know, Winston has not gotten my name wrong at any other time.
As noted previously, my page consists of the aggregation of my various feeds and in working on that code recently it was again brought to my attention that everyone has different ways of representing tag metadata in feeds. I made up a list of how my various feed sources represent tags and list that data here so that it might help others in the future.
Source | Feed Type | Tag Markup Scheme | One Tag Per Element | Tag Scheme URI | Human / Machine Names | Example Markup |
---|---|---|---|---|---|---|
LiveJournal | Atom | atom:category | yes | no | no | , (source) |
LiveJournal | RSS 2.0 | rss2:category | yes | no | no |
technical (soure) |
WordPress | RSS 2.0 | rss2:category | yes | no | no |
, (source)
|
Delicious | RSS 1.0 | dc:subject | no | no | no |
photosynth photos 3d tool (source) |
Delicious | RSS 2.0 | rss2:category | yes | yes | no |
domain="http://delicious.com/SequelGuy/"> (source) |
Flickr | Atom | atom:category | yes | yes | no |
term="seattle" (source) |
Flickr | RSS 2.0 | media:category | no | yes | no |
scheme="urn:flickr:tags"> (source) |
YouTube | RSS 2.0 | media:category | no | no | no |
label="Tags"> (source) |
LibraryThing | RSS 2.0 | No explicit tag metadata. | no | no | no | n/a, (source) |
Tag Markup Scheme | Notes | Example |
---|---|---|
Atom Category atom:category xmlns:atom="http://www.w3.org/2005/Atom"
|
|
term="catName"
|
RSS 2.0 category rss2:category empty namespace |
|
domain="tag:deletethis.net,2008:tagscheme">
|
Yahoo Media RSS Module category media:category xmlns:media="http://search.yahoo.com/mrss/"
|
|
scheme="http://dmoz.org"
|
Dublin Core subject dc:subject xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
humor
|
Update 2009-9-14: Added WordPress to the Tag Markup table and namespaces to the Tag Markup Scheme table.