MEF CTP2 released with source code.

My team released MEF CTP2 on codeplex at http://www.codeplex.com/MEF, this time with source code. We also created a number of documents (i.e. wiki pages) and samples that demonstrate how to use MEF.

What problems does MEF solve?

MEF presents a simple solution for the runtime extensibility problem. Until now, any application that wanted to support a plugin model needed to create its own infrastructure from scratch. Those plugins would often be application-specific and could not be reused across multiple implementations.
  • MEF provides a standard way for the host application to expose itself and consume external extensions. Extensions, by their nature, can be reused amongst different applications. However, an extension could still be implemented in a way that is application-specific. Extensions themselves can depend on one another and MEF will make sure they are wired together in the correct order (another thing you won't have to worry about).
  • MEF offers a set of discovery approaches for your application to locate and load available extensions.
  • MEF allows tagging extensions with additional metadata which facilitates rich querying and filtering

[MEF Overview]

By all means please provide us with what you like and\or dislike about MEF at Discussions.

Posted by puzzlehacker | 3 comment(s)
Filed under: ,

First Managed Extensibility Framework (MEF) bits released

Today was a big day for my team because we released the bits for the first CTP of the Managed Extensibility Framework (MEF).

MEF is a framework that allows developers to declare what they need (i.e. Imports) and what they provide (i.e. Exports) and then automatically wire up everything at run-time. While that may be a slight over simplification it is the basic idea and can lead to a very loosely coupled system which can easily be extended and evolve overtime.

The primary goal of this CTP is to get the bits into people’s hands early to gather feedback from the community and feed it back into the product. We have already gotten some good feedback in response to Krzysztof’s blog post about MEF, and some of that feedback has already made its way into the CTP. Rest assured that there are still community asks that we are still actively working hard on.

Keep in mind these bits are very early and you should not get hung up on the names and exact shape of the API’s because they are likely to change. What we would really like is feedback on the basic concepts and any scenarios you feel MEF would be useful for but needs some fine tuning.

To get your hands dirty download the bits and have a look at the sample applications and docs. If you have questions or feedback by all means don’t hesitate to stop by our forum.

Expect so see some more posts from me and some of my teammates (Mitch, David, Krzysztof) on MEF in the coming months.

Enjoy!

Posted by puzzlehacker | with no comments
Filed under: , ,

Opening files from the VS "Quick find combo"

Ctrl+/ is quickly becoming one of my favorite and most used hotkey in Visual Studio. Pressing it will jump you to the "Quick find Combo" with a ">" already type in for you (which means interpret the text as a VS command).

If you are like me you hate hunting through the Solution Explorer looking for files, especially on large solutions, you might be interested in the Ctrl+/ | ">of " command. 

As Robert Prouse explains:

Here is a cool Visual Studio feature that almost nobody knows about. If you want to open up a file in your solution, but can’t be bothered to dig down through your projects and folders to find it, try this,

  1. Click in the Find box in the toolbar,
  2. Type >of followed by a space, then begin the name of the file you are looking for.
  3. An auto-complete drop down will appear as you type filtering all the files in all your projects in your solution. Continue typing until the list is short enough to fine the one you want. Select it and hit enter.
  4. The file will open in the editor.

openfile

[Quickly Find/Open a File in Visual Studio]

The best part of this auto complete drop down is that it actually gives you a flat list view of all the files in the solution which is just plain cool :)

As if that wasn't enough Aaron Lerch posted The Talented Mr. Edit.GoToFindCombo which lists some other cool features of the "Quick find combo".

Posted by puzzlehacker | 4 comment(s)
Filed under: ,

Job openings on the .NET Framework Core Team

We have been incubating ideas about building a simple extensibility framework for some time. Now, as plans for the next version of the .NET Framework crystallize a bit more, we decided to productize the project. As a result, we have opened a job position (and most probably will be opening more) on the .NET Framework team. If you are interested, please see details here and send me an email at “kcwalina at microsoft.com.”

So, what is this extensibility framework? Initially, it will be a low level core .NET Framework feature to make it easy for applications to expose extensibility points and consume extensions. Think about what for example FxCop has to do define rule contracts and load rule implemented by the community. These are the basics, and we can talk about the broader and longer term vision when you come to Redmond for an interview :-)

This is a technical Program Manager position in Redmond, WA, and it’s basically exactly the job I did when I joined Microsoft. Besides working on the Framework features, all Program Managers on the core team have opportunities to work on API design and architecture projects.

[Job Openings on the .NET Framework Core Team]

I'm a developer on Kyzysztof's team and we are looking for a few good people for PM and Dev positions so by all means if you are interested in extensibility and API design please apply.

Posted by puzzlehacker | with no comments
Filed under: ,

2008 Scripting Games - My solutions

Here are my solutions to the 2008 Scripting Games scripting competition. This is a rather large post but I decided one post would be better than posting them all individually, this way they will all be in one place when I want to find them later. I had fun and I learned a lot of new cool things about Powershell while working through the problems. If you are trying to learn Powershell I would definitely recommend working through them to force yourself to learn the details.

Disclaimer: These script samples are by no means perfect but they are the unedited solutions that I submitted so they do solve the problems. They are provided as-is and you should use them at your own risk.

Powershell beginner division

Event 1: Pairing Off
Official Solution
My Solution:

# first char in card is A, 1, 2, 3, 4, 5, 6, 7, 8, 9, T, J, Q, K 
# second char in card is H - Hearts, S - Spades, C - Clubs, D - Diamonds
$cards = @("7S", "5H", "7D", "7C", "KC"); $numPairs = 0; for ($i = 0; $i -lt $cards.Length; $i++)
{ for ($j = $i + 1; $j -lt $cards.Length; $j++) { if ($cards[$i][0] -eq $cards[$j][0]) { $numPairs++; } } } Write-Host $numPairs;

Event 2: True Type
Official Solution
My Solution:

$fonts = Get-Item "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Fonts"
$truetypes = $fonts.Property | where { $_ -match "\(TrueType\)" }

Write-Host "TrueType Fonts:"
$truetypes

Write-Host
Write-Host "TrueType: $($trueTypes.Count)"
Write-Host "Total: $($fonts.ValueCount)"

Event 3: Let’s Get Together
Official Solution
My Solution:

$firstLines = dir "C:\Scripts\*.txt" | % { Get-Content $_ -totalCount 1 }
$firstlines | Out-File -encoding ASCII "c:\scripts\newfile.txt"

Event 4: Count Yourself In
Official Solution
My Solution:

$c=0
Get-Content $MyInvocation.MyCommand.Definition | % { $c += $_.Length }
$c

Event 5: What’s the Difference
Official Solution
My Solution:

param([DateTime] $d)

$t = [DateTime]::Today

$ts = $d - $t
$ms = ($d.Month - $t.Month) + 12 * ($d.Year - $t.Year);

Write-Host ("Days: " + $ts.Days)
Write-Host ("Months: " + $ms)

if ($d.Day -lt $t.Day) { $ms--; }    
                
$ts = $d - $t.AddMonths($ms)

Write-Host ("Months/Days: " + $ms + " / " + $ts.Days)

Event 6: Coffee Break
Official Solution
My Solution:

$cfile = (Get-Content "C:\Scripts\coffee.txt")

$orders = @{}
foreach($o in $cfile)
{
    $d, $c = $o.Split(" ")
    $orders[$d] += [int]$c;
}
$orders.Remove("Office");

$orders.GetEnumerator() | % { Write-Host ($_.Name + " " + $_.Value) }

Event 7: Squashing Bugs
Official Solution
My Solution:

foreach ($i in Get-ChildItem C:\Scripts -recurse)
{
    if (($i.CreationTime -lt ($(Get-Date).AddDays(-10))) -and ($i.Extension -eq ".txt"))
    {
         Copy-Item $i.FullName C:\old
         $i.Name
         $x = $x + 1
    }
}

""
"Total Files: " + $x

Event 8: Random Guess
Official Solution
My Solution:

$r = New-Object System.Random
$low = 1
$high = 50
[int]$num = $r.Next($low, $high)
$guess = $guesses = 0

while ($num -ne $guess)
{
    Write-Host -NoNewline "Guess a number between $low and $high : "
    [int]$guess = Read-Host
    
    if ($guess -lt $num)
    {
        Write-Host "Too Low!"
        $low = $guess
    }
    else
    {
        if($guess -gt $num)
        {
            Write-Host "Too High!"
            $high = $guess
        }
    }
    $guesses++
}

Write-Host "Random number was $num"
Write-Host "Total guesses: $guesses"

Event 9: Pool Party
Official Solution
My Solution:

$adOpenStatic = 3
$adLockOptimistic = 3

$objConnection = New-Object -comobject ADODB.Connection
$objRecordset = New-Object -comobject ADODB.Recordset

$objConnection.Open("Provider=Microsoft.Jet.OLEDB.4.0; Data Source= c:\scripts\pool.mdb")
$objRecordset.Open("Select * from SwimmingPool", $objConnection,$adOpenStatic,$adLockOptimistic)

do 
{
    Write-Host ("  Name: " + $objRecordset.Fields.Item("Customer").Value)
    [int]$length = $objRecordset.Fields.Item("Length").Value;
    [int]$width = $objRecordset.Fields.Item("Width").Value;
    [int]$depth = $objRecordset.Fields.Item("Depth").Value;
    [bool]$slope = $objRecordset.Fields.Item("Slope").Value;
    [int]$sstart = $objRecordset.Fields.Item("SStart").Value;
    [int]$send = $objRecordset.Fields.Item("SEnd").Value;
    
    if ($slope)
    {
        Write-Host ("    Volume of Water: " + ($length * $width * (($send + $sstart)/2) * 1000))
    }
    else
    {
        Write-Host ("    Volume of Water: " + ($length * $width * $depth * 1000))
    }
    Write-Host
    $objRecordset.MoveNext()
} until ($objRecordset.EOF -eq $True)


$objRecordset.Close()
$objConnection.Close()

Event 10: Bowling
Official Solution
My Solution:

$arrFrames = 2,5,7,"/",8,1,"X",9,"/",5,3,7,0,4,5,"X",2,0

$frames = $arrFrames -replace "X","10"
for($i = 0; $i -lt $frames.Count; $i++) { if ($frames[$i] -eq "/") { $frames[$i] = 10 - [int]$frames[$i-1]; } }
[int[]]$frames = $frames;

$score = 0;
$fc = 0;
for($i = 0; $i -lt $arrFrames.Count -and $fc -lt 10;)
{
    if ($frames[$i] -eq 10)
    {
        $score += $frames[$i] + $frames[$i+1] + $frames[$i+2];
        $i++; $fc++;
    }
    else
    {
        $fs = $frames[$i] + $frames[$i+1];
        
        $score += $fs;
        $i += 2; $fc++;
        
        if ($fs -eq 10) { $score += $frames[$i]; }
    }
}
$score

Powershell advanced division

Event 1: Could I Get Your Phone Number?
Official Solution
My Solution:

function ConvertLetterToNumber([char] $letter) 
{ switch -regex ($letter) { "[abc]" { return "2"; } "[def]" { return "3"; } "[ghi]" { return "4"; } "[jkl]" { return "5"; } "[mno]" { return "6"; } "[prs]" { return "7"; } "[tuv]" { return "8"; } "[wxy]" { return "9"; } default { return ""; } } } Write-Host -nonewline "Enter phone number (XXXXXXX): "; $number = (Read-Host); if (!($number -match "^\d{7}$")) { Write-Error "Please enter a number in format XXXXXXX"; exit; } $foundWord = $null; $file = [System.IO.File]::OpenText("c:\scripts\wordlist.txt"); while ($word = $file.ReadLine()) { if ($word.Length -eq 7) { $i = 0; while ((ConvertLetterToNumber $word[$i]) -eq $number[$i]) { $i++; } if ($i -eq 7) { $foundWord = $word; break; } } } $file.Close(); if ($foundWord -eq $null) { Write-Host "Sorry no such word 7 letter word in the list!"; } else { Write-Host "Found 7 letter word: $foundWord"; }

Event 2: Skating on Thin Ice
Official Solution
My Solution:

$skaterScores = @();
foreach($skaterLine in (Get-Content "c:\scripts\skaters.txt")) 
{ $name, $scores = $skaterLine -split "," # Sort for easy removal of best and worst score $scores = [int[]]$scores | sort # Calclate avg skiping first and last $total = 0; $scores[1..($scores.Count - 2)] | foreach { $total += $_ } $skaterScores += $name | Add-Member -memberType NoteProperty -Name AvgScore -Value ($total / ($scores.Length - 2)) -passthru } # Rank the skaters by Avg Score $skaterScores = $skaterScores | sort -descending AvgScore # Assign medals to the top three $i = 0; foreach($medal in ("Gold", "Silver", "Bronze"))
{ $skaterScores[$i] | Add-Member -MemberType NoteProperty -Name Medal -Value $medal # Simple Console output #"$medal Medal: $($skaterScores[$i]), $($skaterScores[$i].AvgScore)"; $i++; } # Powershell V2 Gridview output $skaterScores | Select Medal, @{Name="Name"; Expression={$_}}, AvgScore | Out-GridView

Event 3: Instant (Runoff) Winner
Official Solution
My Solution:

$voters = new-object System.Collections.ArrayList;

# Collect the votes from the file
foreach($voteLine in (Get-Content "c:\scripts\votes.txt")) 
{ $vote = new-object System.Collections.ArrayList; $vote.AddRange($voteLine -split ",") [void]$voters.Add($vote) } while($true) { $voteCount = @{} # Tally voting results $voters | % { $voteCount[$_[0]] = $voteCount[$_[0]] + 1; } # Sort voting results $voteCount = $voteCount.GetEnumerator() | sort -descending Value # Did the winner get more than 50% of the vote? if ($voteCount[0].Value * 2 -gt $voters.Count) { Write-Host ("The winner is {0} with {1:P2} of the vote." -f $voteCount[0].Name, ($voteCount[0].Value / $voters.Count)) break; } else { # Clear out the candidate with losted number of votes $voters | % { $_.Remove($voteCount[$voteCount.Count - 1].Name); } } }

Event 4: Image is Everything
Official Solution
My Solution:

Write-Host -nonewline "Enter month (M/YYYY): "
[DateTime]$month = (Read-Host)

# Ensure we are set to the first day of the month
$month = $month.AddDays(-1 * ($month.Day - 1)) 

# Write month header
Write-Host $month.ToString("`n   MMMM yyyy`n")

# Write days of week headers
0..6 | % { Write-Host -nonewline ("{0,6}" -f ([string][DayofWeek]$_).SubString(0, 3)) }

# Figure out the date of the first monday in a set of weeks
$next = $month.AddDays(-1 * [int]$month.DayofWeek)
Write-Host
while ($next.Month -le $month.Month)
{
    # Walk the week and only write the day if the mondy matches
    0..6 | foreach { 
        if ($next.Month -eq $month.Month) { $day = $next.Day } else { $day = "" }
        Write-Host -nonewline ("{0,6}" -f $day)
        $next = $next.AddDays(1) 
    }
    Write-Host
}
Write-Host

Event 5: You Call That a Strong Password?
Official Solution
My Solution:

param([string]$pass)

$strength = 13

Write-Host "Testing password [$pass]..."

$wl = (Get-Content "C:\Scripts\wordlist.txt");

if ($wl -contains $pass) { 
Write-Host -f red "Make sure that the password is not an actual word."; $strength-- }

if ($wl -contains $pass.SubString(0,$pass.Length-1)) { 
Write-Host -f red "Make sure that the password, minus the last letter, is not an actual word."; $strength-- }

if ($wl -contains $pass.SubString(1)) { 
Write-Host -f red "Make sure that the password, minus the first letter, is not an actual word."; $strength-- }

if ($pass -match "0" -and $wl -contains ($pass -replace '0','o')) { 
Write-Host -f red "Make sure that the password does not simply substitute 0 (zero) for the letter o (either an uppercase O or a lowercase o)."; $strength-- }

if ($pass -match "1" -and $wl -contains ($pass -replace '1','l')) { 
Write-Host -f red "Make sure that the password does not simply substitute 1 (one) for the letter l (either an uppercase L or a lowercase l)."; $strength-- }

if ($pass.Length -lt 10 -or $pass.Length -gt 20) { 
Write-Host -f red "Make sure that the password is at least 10 characters long but no more than 20 characters long."; $strength-- }

if ($pass -notmatch "\d") { 
Write-Host -f red "Make sure that the password includes at least one number (the digits 0 through 9)."; $strength-- }

if ($pass -cnotmatch "[A-Z]") { 
Write-Host -f red "Make sure that the password includes at least one uppercase letter."; $strength-- }

if ($pass -cnotmatch "[a-z]") { 
Write-Host -f red "Make sure that the password includes at least one lowercase letter."; $strength-- }

if ($pass -notmatch "[^a-zA-Z0-9]") { 
Write-Host -f red "Make sure that the password includes at least one symbol."; $strength-- }

if ($pass -cmatch "[a-z]{4}") { 
Write-Host -f red "Make sure that the password does not include four (or more) lowercase letters in succession."; $strength-- }

if ($pass -cmatch "[A-Z]{4}") {  
Write-Host -f red "Make sure that the password does not include four (or more) uppercase letters in succession."; $strength-- }

if ($pass -cmatch "(.).*\1") { 
Write-Host -f red "Make sure that the password does not include any duplicate characters."; $strength-- }

$s = "moderately-strong"; $c = "yellow"
if ($strength -le 6) { $s = "weak"; $c = "red" }
if ($strength -ge 11) { $s = "strong"; $c = "green" }

Write-Host
Write-Host -nonewline "A password score of "
Write-Host -nonewline -f $c "$strength"
Write-Host -nonewline "/13 indicates a "
Write-Host -nonewline -f $c "$s"
Write-Host " password."

Event 6: Prime Time
Official Solution
My Solution:

$primes = new-object System.Collections.ArrayList 
$primes.AddRange(2..199)
for ($i = 0; $i -lt $primes.Count; $i++)
{
    for ($j = $i + 1; $j -lt $primes.Count;)
    {
        if ($primes[$j] % $primes[$i] -eq 0)
        {
            $primes.Remove($primes[$j])
        }
        else
        {
            $j++;
        }
    }
}
# Simple Console Output
#$primes

# Powershell V2 GridView
$primes | select @{ Name="Primes"; Expression={ $_.ToString() } } | Out-GridView

Event 7: Play Ball!
Official Solution
My Solution:

$a = "A","B","C","D","E","F"
1..($a.Length-1) | % { ( 1..($a.Length/2) | % { $a[$_-1]+" vs. "+$a[-$_] } ); write-host; [string[]]$x,$y,$z=$a;$a=$x+$z+$y; }

Event 8: Making Beautiful Music
Official Solution
My Solution:

$songs=@()
$names=@{}
$total=0;
foreach ($songLine in (Get-Content "c:\scripts\songlist.csv"))
{
  $name,$title,$length = $songLine.Split(",");
  
  # Ensure no more than 2 of same artist
  if ($names[$name] -ge 2) { continue } $names[$name]++;
  
  $mm,$ss=[int[]]$length.Split(":");
  $time = $mm*60+$ss;

  if ($total + $time -ge 4800) # 80 Mins
  {
    if ($total -gt 4500) { break; } # Done
    continue; # Try next song
  }
  $total += $time;
    
  $song = new-object psobject
  $song | Add-Member NoteProperty "Artist Name" $name
  $song | Add-Member NoteProperty "Song Title"  $title
  $song | Add-Member NoteProperty "Song Length" $length
  $songs += $song
}

$songs | sort "Artist Name"

Write-Host ("`nTotal music time: {0}:{1:00}" -f (($total-$total%60)/60), ($total%60))

Event 9: You’re Twisting My Words
Official Solution
My Solution:

((Get-Content "c:\scripts\alice.txt") -split "\s" | % { $s=[char[]]$_; [System.Array]::Reverse($s); $s -join "" }) -join " "

Event 10: Blackjack!
Official Solution
My Solution:

$suites = "Clubs", "Diamonds", "Hearts", "Spades"
$numStrings = "Ace", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King"

function NextCard { $c,$script:cards = $script:cards; $c }
function ShowYourCards { 
    Write-Host "`nYour cards:"
    $script:yourSum = 0;
    $aces = 0;
    $yourCards | % { if ($_.Value -eq 11) { $aces++ }; $script:yourSum += $_.Value; $_.Name }
    while ($script:yourSum -gt 21 -and $aces -gt 0) { $script:yourSum -= 10; $aces--; }
    Write-Host "Your card total is $yourSum"
}
function ShowDealerCards {
    Write-Host "`nDealer's cards:"
    $script:dealerSum = 0
    $aces = 0;
    $dealerCards  | % { if ($_.Value -eq 11) { $aces++ }; $script:dealerSum += $_.Value; $_.Name }
    while ($script:dealerSum -gt 21 -and $aces -gt 0) { $script:dealerSum -= 10; $aces--; }
    Write-Host "Dealer card total is $dealerSum"
}
function Outcome([bool]$win, [string]$msg) {
    if ($win) {
        Write-Host -ForegroundColor green "`nYou win! $msg"
    }
    else {
        Write-Host -ForegroundColor red "`nYou lose! $msg"
    }
    exit
}

$cards = @()
foreach($suite in $suites) {
    for($i = 0; $i -lt $numStrings.Count; $i++)              {
        $numStr = $numStrings[$i];
        $c = New-Object PsObject
        $c | Add-Member NoteProperty Name $($numStr + " of " + $suite)
        $c | Add-Member NoteProperty Value $(if($i -gt 9){10}else{if($i -eq 0){11}else{$i+1}})
        $cards += $c
    }
}

$rand = New-Object Random
$cards = $cards | sort { $rand.Next() }

$yourCards = @()
$dealerCards = @()

$yourCards += NextCard
$dealerCards += NextCard
$yourCards += NextCard

ShowYourCards
if ($yourSum -eq 21) {
    Outcome $true "Blackjack, you got 21 with two cards."
}
ShowDealerCards
$dealerCards += NextCard
Write-Host 
while ($yourSum -lt 21) {
    Write-Host -NoNewline "Stay (s) or hit (h)? "
    $hitOrStay = Read-Host
    
    if ($hitOrStay -ieq "s") { break; }
    if ($hitOrStay -ieq "h")
    {
        $yourCards += NextCard
        ShowYourCards
    }
}
if ($yourSum -gt 21) {
    Outcome $false "Your total $yourSum is over 21."
}
if ($yourSum -eq 21) {
    Outcome $true "Your total is exactly 21."
}
ShowDealerCards
# Assumes dealer keeps hitting while he is losing and not over 21, unlike most casinos where the stop at 17
while ($dealerSum -lt 21 -and $dealerSum -lt $yourSum) {
    $dealerCards += NextCard
    ShowDealerCards
}
if ($dealerSum -gt 21) {
    Outcome $true "Dealer busted because dealer's $dealerSum is over 21."
}
if ($dealerSum -ge $yourSum) {
    Outcome $false "The dealer's $dealerSum is greater than or equal to your $yourSum."
}
else {
    Outcome $true "Your $yourSum is geater than the dealer's $dealerSum."
}

Sudden death challenge

Event 1: Could I See Some ProgID, Please?
Official Solution
My Solution:

#-1. Enables you to manage the Windows Firewall in Windows XP.
# 2. Enables you to create a remote connection using Windows Script Host.
#-3. Enables you to map printers using Windows Script Host.
# 4. Enables you to perform an XPath query in an XML document.
# 5. Enables you to create an instance of Internet Explorer.
#-6. Enables you to connect to a database.
#-7. Enables you to perform text-to-speech conversions in a script. 
# 8. Enables you to create an instance of Microsoft Excel.
#-9. Enables you to send and create SMTP email.
#-10. Enables you to create an instance of Microsoft Outlook.
#-11. Enables you to work with Windows Remote Management.
# 12. Enables you to access type libraries from a script.
#-13. Enables you to manage Microsoft Indexing Server.
#-14. Enables you to manage Windows Media Player.
# 15. Enables you to manage Windows Update Services.
# 16. Enables you to manage TCP/IP and other network settings.
#-17. Enables you to work with XML documents.
# 18. Enables you to manage fonts.
#-19. Enables you to create a GUID.
#-20. Enables you to convert Active Directory names from one format to another.

Write-Host "ProgID              Description"
Write-Host "ADODB.Connection              6"
Write-Host "HNetCfg.FwMgr                 1"
Write-Host "Microsoft.XMLDOM             17"
Write-Host "SAPI.SpVoice                  7"
Write-Host "NameTranslate                20"
Write-Host "Scriptlet.TypeLib            19"
Write-Host "Outlook.Application          10"
Write-Host "WMPlayer.OCX                 14"
Write-Host "WScript.Network               3"
Write-Host "WSMan.Automation             11"
Write-Host "CDO.Application               9"
Write-Host "Microsoft.ISAdm              13"

Event 2: Typing Isn’t Really Our Thing
Official Solution
My Solution:

$v = get-content c:\scripts\vertical.txt
$t = ""
for($i=0;$i -lt $v[0].Length; $i++){ for ($j=0;$j -lt $v.Count; $j++) { $t += $v[$j][$i] } }
$t

Event 3: What's in a Name?
Official Solution
My Solution:

$pfile = (Get-Content "c:\Scripts\presidents.txt")
$longestFirst = ""
$vowelCount = 0
$alpha = New-Object System.Collections.ArrayList
0..25 | % { [void]$alpha.Add([char]($_ + [int][char]"A")) }

foreach($pr in $pfile)
{
    $last, $first = $pr.Split(",")
    $first = $first.Trim()

    if ($longestFirst.Length -lt $first.Length)
    {
        $longestFirst = $first;
    }
    $alpha.Remove([Char]::ToUpper($first[0]))
    $alpha.Remove([Char]::ToUpper($last[0]))
    
    $pr.ToCharArray() | ? { $_ -match "[aeiouAEIOU]" } | % { $vowelCount++ }
}

Write-Host "Longest first name: $longestFirst"
Write-Host "Letters not in initials:"
$alpha | % { Write-Host $_ }
Write-Host "Total vowel count: $vowelCount"

Event 4: Type By Numbers
Official Solution
My Solution:

$a = (Get-Content "C:\scripts\numbers.txt")
$s = ""
for($i = 0; $i -lt $a.Length; $i+=2) { [int]$c=([string]::Join("",$a[($i)..($i+1)])); $s += [char]$c }
$s

Event 5: WMI From A to Z – er, A to Y
Official Solution
My Solution:

$d = @{ }
$win32Classes = Get-WmiObject -namespace "root\cimv2" -list | ? { $_.Name -match "^Win32_" } 

foreach($w in $win32Classes)
{
    foreach($p in $w.psbase.Properties)
    {
        $c = [char]::ToUpper($p.Name[0]);
        
        if ([char]::IsLetter($c) -and !$d.ContainsKey($c))
        {
            $p | Add-Member -MemberType NoteProperty -Name Property -Value $p.Name
            $p | Add-Member -MemberType NoteProperty -Name Win32Class -Value $w.Name
            $d[$c] = $p
            break; // Lets only get one property from a given class
        }
    }
    if ($d.Count -eq 25) { break; }
}

$d.Values | sort Property | Select Property, Win32Class

Event 6: If at First You Don’t Succeed...
Official Solution
My Solution:

$v = get-content c:\scripts\lettercase.txt
$t=""
$v.ToCharArray() | % {
    if ([char]::IsUpper($_)) { $t += [char]::ToLower($_) } else {
    if ([char]::IsLower($_)) { $t += [char]::ToUpper($_) } else {
    if ([char]::IsDigit($_)) { $t += [int][char]$_-49 } else {
        $t += $_;
    } } }
}
$t

Event 7: Simon Says "Multiply By 4"
Official Solution
My Solution:

$val = "{0:F2}" -f ([Math]::Sqrt([Math]::Pow([Math]::Floor((100 * 2) / 30), 5) * 4) / 45)
$voice = new-object -com SAPI.SpVoice
[void]$voice.Speak($val)

Event 8: The Display’s the Thing
Official Solution
My Solution:

Value               LDAP Display Name
Kenneth             givenName
J                   initials
Myer                sn
712 NE 40th Way     streetAddress
Redmond             l
WA                  st
98052               postalCode
USA                 c
1-425-555-1234      telephoneNumber
kmyer@fabrikam.com  mail

Event 9: The Third Time Was Not a Charm
Official Solution
My Solution:

(Get-Content c:\scripts\symbols.txt) -replace "[^\da-z ]",""

Event 10: Triple Word Scramble
Official Solution
My Solution:

.CSRIIEHRRTOENSWWPOCTIHPT-T

Wscript.Echo
Write-Host
Print

2008 Scripting Games

It’s the third annual Scripting Games, the biggest scripting competition of the year! As a matter of fact, it’s most likely the biggest scripting competition ever. (The fact that it may be the only scripting competition is beside the point.)

The games have already begun on Feb 15 but you have until 8 AM Feb 20 to submit the solutions for the first two events.

If you want to force yourself to learn Powershell (or Perl or VBScript) then I would suggest having a look. Even though I'm not eligible for prizes because I'm a Microsoft employee, I plan on participating to help fill in the gaps of my Powershell skills. I may also try to post my solutions (after the deadline of course :)).

Posted by puzzlehacker | 2 comment(s)
Filed under: , ,

All Outlook object model calls run on the main thread

While writing an Outlook addin, lots of people feel that they should try to help with Outlook performance by running their addin code on a background thread. While this can help in some scenarios it can actually make things worse in others, particularly if the addin is interacting primarily with the Outlook Object Model (OOM). The OOM is run in a single threaded apartment COM server, therefore every COM call is executed on the main thread of outlook.exe.

If an addin is interacting with the OOM from another apartment (i.e. on a background thread or another process) all the calls have to be marshaled to and from the server apartment (i.e. the main thread) which causes some extra overhead. This overhead is why working on a background thread could actually make performance worse and it does not exist if the addin is executing in the same apartment.

Like most things, it is a balancing act and one needs to find the proper balance for their particular situation. Just remember the key to performance is "Measure, Measure, Measure..."

Issues with the XmlSerializer in medium trust environments

In my last post I briefly mentioned that CodeHTMLer had issues running in a medium trust environment. The simple web application front end I created kept failing before it ever got started. It keep hitting a SecurityException nested in an InvalidOperationException which looks something like:

[Exception: System.InvalidOperationException: There was an error reflecting type 'CodeHtmler.Languages'. ---> System.Security.SecurityException: Request failed.
   at System.Reflection.CustomAttribute._CreateCaObject(...)
   at System.Reflection.CustomAttribute.CreateCaObject(...)
   at System.Reflection.CustomAttribute.GetCustomAttributes(...)
   at System.Reflection.CustomAttribute.GetCustomAttributes(...)
   at System.Reflection.RuntimePropertyInfo.GetCustomAttributes(...)
   at System.Xml.Serialization.XmlAttributes..ctor(...)
   at System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(...)
   at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(...)
The action that failed was:
InheritanceDemand
The type of the first permission that failed was:
System.Security.PermissionSet
The Zone of the assembly that failed was:
MyComputer

CodeHTMLer uses the XmlSerializer to read and write the language definitions and it appeared to be what was causing this exceptions to be thrown. I spent a good deal of time trying to figure out why this wasn't working because every thing I read online said the XmlSerializer should actually work in medium trust. After a while of debugging I finally figured out that the problem was caused by some custom attributes.

[XmlAttribute]
[Editor(typeof(HtmlColorEditor), typeof(System.Drawing.Design.UITypeEditor))]
public string Color {...}

Apparently when the XmlSerializer is walking through the custom attributes it runs into the EditorAttribute and then tries to get the type of my custom editor HtmlColorEditor which has UITypeEditor in it's inheritance chain. However UITypeEditor for some reason demands a FullTrust permission set for Inheritance, which is problematic in a medium trust environment. To verify for certain that this was the issue I removed those editor attributes and then the XML serialization worked as expected under medium trust.

Those editor attributes are used by the PropertyGrid, which is my lame way of providing UI to edit the language definitions, so I didn't want to remove them permanently but I also wanted the serialization to work in a medium trust environment. To allow for both the PropertyGrid and the medium trust serialization to work I decided to use the sgen tool to generate the serialization classes statically when I knew I had FullTrust permissions, instead of dynamically at runtime like the generic XmlSerializer class does.

The output of sgen was another assembly, CodeHtmler.XmlSerializers.dll which I then needed to reference and switch the code from using the more general XmlSerializer(typeof(Languages)) to the specific class  LanguagesSerializer(). This was cool because it allowed me to accomplish what I wanted but it in turn forced me to now release two separate assemblies, CodeHtmler.dll and CodeHtmler.XmlSerializers.dll. Wouldn't it be nice if I could get away with just one assembly. It turns out that sgen has this /keep option that will tell it not to delete the temp code files used to build the new assembly. This was great because now I can just take the generated source code for the LanguagesSerializer class and build it as part of my CodeHtmler.dll assembly. Here is the command line I used to do this:

sgen CodeHtmler.dll /keep /force /type:CodeHtmler.Languages

There is a little bit of the chicken and egg problem here because I needed the CodeHtmler.dll to generate the serialization code and I needed serialization code to build CodeHtmler.dll. It really wasn't that big of an issue though because the serialization doesn't actually need to work to run sgen it just needs to be stubbed out so CodeHtmler.dll can be built.

This approach works quite nicely. Now the only issue is that I have to remember to regenerate the serialization code whenever I change any of my serialized classes. Fortunately, I only have a small number of classes I serialize and their serialization interface doesn't change much so I think I can live with this approach.

Added CodeHTMLer project at codeplex

In order to help better manage changes to CodeHTMLer I finally added the project on codeplex at http://codeplex.com/CodeHtmer.

I made a couple of small code updates after I put it up on codeplex:
- Added a new language property DivInlineFont to define the font to use when not using pre tags.
- Added a language definition for F# (thanks to Harry at Blogging in F#)
- Fixed the CodeHTMLer library so it runs in a medium trust environment (needed this because I just moved web hosts and the new one runs in medium trust level, more about the details later).

Thus far codeplex seems pretty cool but I guess I will only be able to realize its full collaboration potential when I actually have more contributors than just myself.

Posted by puzzlehacker | 1 comment(s)
Filed under: ,

Fun with C# functions

Dustin Campbell has an interesting series on C# functions on his Did it with .NET blog.

  1. Fibonacci Numbers, Caching and Closures
  2. What's in a Closure?
  3. Using Automatic Memoization
  4. A Higher Calling
  5. The Art of Currying
  6. Building Functions from Functions, part 1: Partial Application
  7. Building Functions from Functions, part 2: Function Composition

 

Some interesting stuff that ties together a number of C# 2.0 and 3.0 feature sets. Definitely worth a read. Thanks Dustin and keep them coming.

Posted by puzzlehacker | with no comments
Filed under: ,
More Posts Next page »