MEF Preview 9 released

MEF preview 9 has been released on codeplex http://mef.codeplex.com/releases/view/40606.

The only changes are some bug fixes for the .Net version and a couple additions to the SL version.

  • We brought back PackageCatalog but redesigned it under the name DeploymentCatalog and put it in System.ComponentModel.Composition.Initilization.dll
  • We renamed PartCreator to ExportFactory and put it in System.ComponentModel.Composition.Initilization.dll
  • Renamed type PartInitializer to CompositionInitializer
  • Renamed method CompositionHost.InitializeContainer to CompositionHost.Initialize

This drop contains a MEF.sln which loads in VS2008 and builds MEF against .Net 3.5 and MEFSL.sln which loads in VS2008 and builds MEF againts SL3. The API's are pretty much what we are shipping in .Net 4.0 and SL4 SDK respectively. However if you need a .Net 4 version of MEF we suggest that you install the RC version of .Net 4 and if you need an SL4 version of MEF you install the Silverlight 4 beta SDK.

As aways if you have issues or questions related to MEF feel free to post them in our dicsussion forums at http://mef.codeplex.com/Thread/List.aspx.

For some more detailed explanations of the changes in this preview have a look at Mike Taulty's post http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2010/02/17/new-mef-drop-preview-9-on-codeplex.aspx.

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

MEF preview 5 released

My team released the 5th source code preview of MEF (Managed Extensibility Framework). You can get the latest bits at MEF preview 5. A summary of the changes can be found on in the release notes but I will copy them here for convenience. If you have questions or concerns feel free to join the discussion.

Namespace changes

  • System.ComponentModel.Composition – For part authors. This namespace contains the import and export attributes as well as other APIs that part authors are likely to use.
  • System.ComponentModel.Composition.Hosting – For hosters. This namespace contains the CompositionContainer, catalog implementations, and other APIs that hosters are likely to use.

Part discovery changes

  • CompositionOptionsAttribute and DiscoveryMode have been removed.
  • PartNotDiscoverableAttribute replaces [CompositionOptions(DiscoveryMode = DiscoveryMode.Never)]
  • PartCreationPolicyAttribute can be used to specify part creation policy (Replaces CompositionOptionsAttribute.CreationPolicy)
  • By default, exports on a base class will not be included in the exports for a derived class.
  • The PartExportsInheritedAttribute can be applied to a base class to specify that exports on that class will be included in derived classes. NOTE: If this attribute is used, and both the base and derived class have export attributes applied to them, there will be multiple exports created for the same class. Also note that whatever metadata is applied to the export on the base class can’t be added to or overridden by the derived class

Collection imports

  • ImportManyAttribute should now be used on collection imports (in the future, an ImportAttribute will not be interpreted as a collection import even if it is applied to a collection type).
  • Array imports are now supported.

Typed Imports/Exports

  • Imports and Exports now match on type as well as contract.
  • Exporters of string contracts such as [Export(“Foo”)] must now specify the type they expect to be imported as well. e.g. [Export(“Foo”, typeof(string))]

Method exports

  • Method exports can now be imported as custom delegates in addition to Action<…> and Func<…> delegates

Directory Catalog

  • The directory watching functionality has been removed. The Refresh() method has been added to explicitly update the catalog with new assemblies in the directory.

Removal of Caching / new infrastructure

  • The old caching infrastructure has been removed. We’ve added a general purpose API that allows the implementation of catalog caching as well as supporting builders of custom programming models. The APIs are members of the static class System.ComponentModel.Composition.ReflectionModel.ReflectionModelServices. In the future we plan to ship a sample that shows how these APIs can be used to create cached catalogs.

New sample application

  • MEF Studio – a designer hosting sample.

Common compilation errors to expect when migrating previous code bases

  • System.ComponentModel.Composition.Container does not exist -> Add reference to System.ComponentModel.Composition.Hosting namespace
  • CompositionContainer does not contain method AddPart or Compose -> Need to start using CompositionBatch, or one of the helper extension methods ComposeParts or ComposeExportedObjects
  • CompositionOptionsAttribute does not exist -> For CreationPolicy use PartCreationPolicyAttribute
  • INotifyImportCompleted does not exist -> Use IPartImportsSatisfiedNotification interface and change method from ImportCompleted to OnImportsSatisfied
Posted by puzzlehacker | 5 comment(s)
Filed under: , ,

Should MEF support non-shared components?

Hamilton has posted about the question of whether or not MEF should support non-shared as well as shared components (non-shared==factory and shared==singleton in our current public bits). In an ideal world we would love to support both but currently every solution we've come up with to support non-shared components has issues. We could pick a solution that we feel properly balances the advantages and disadvantages but that would require us to foresee exactly how the world is going to use MEF. While we believe we could pick a reasonable balance there is fear that we would pick the wrong balance for the majority of our future users. Therefore one approach to combat this is to not support non-shared components, at least in V1, and see what usage patterns reveal themselves in the wild and target that balance in V2.

Do you feel that it would be a mistake for the MEF team to only support shared/singleton components in V1? Keep in mind that there are patterns, as Hamilton pointed out, to still support non-shared/factory if you needed that support in V1.

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

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 | 1 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..."

More Posts Next page »