Archives for the Month of January, 2006

MSH Logo – our design strategy

As I mentioned last time, this series of articles will introduce you to some of the features of Monad’s hosting model.  Before we get into the details of hosting Monad, though, we need to first lay out our conceptual framework.

Our application is a simple WinForms control.  It displays a small triangle (of Logo fame,) and users control movement of the turtle through a small set of commands.  The turtle supports the following:

  • Pen Up
  • Pen Down
  • Forward [steps]
  • Backward [steps]
  • Left [degrees]
  • Right [degrees]
  • Hide
  • Show
  • Some facility for looping
  • Some facility for functions / routines

We will model this set of commands as closely as we can, giving the Turtle class responsibility for everything but looping and routines.

Also, the turtle leaves a trace on the screen whenever it moves while the pen is down.  The .Net Framework already gives us a class to handle the responsibility of being a canvas – via the Graphics class. 

That leaves a question – how should we handle interaction between the turtle and the screen? How will we draw the actual lines?  To solve that, we’ll provide the Turtle with a reference to the Graphics class.  As the turtle moves, it will also be in charge of leaving a trail of ink.

Another option would be to place drawing responsibility with a controller class.  Before every command, it could determine the turtle’s position.  After every command, it could again determine the turtle’s position.  If the turtle’s pen is down, it could draw a line between the two.  However, that approach sounds like a case of Feature Envy.  The controller spends nearly all of its time muddling with properties of the turtle class.  In that case, the turtle should just do the work itself.

So, that’s our general approach.  We’ve designed a sturdy object model, and are ready to go implement it.  We’ll continue next time by integrating it into a GUI.

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

Would you like to contribute to "Monad Hacks"?

Do you have an awesome little script that you want to share with the world?  A Monad administration technique so slick that you want everyone to know about it?

Here's a great chance - the opportunity to include your work in a forthcoming O'Reilly "Monad Hacks" book.

As you might know, one of the great hallmarks of this series is that it includes contributions from enthusiasts worldwide.  I'm continually amazed at the techniques that you all come up with.  It will be great for those techniques to help jump-start the learning process of countless future administrators and power users.

What counts as a hack?

A hack is a "non-obvious solution to an interesting problem."  Do you have some script or technique that solves an interesting administration or scripting task?  Does it involve more than just a straight-forward chunk of code?  If so, then you probably have a hack on your hands.  Keeping your hack concise is a good goal - but concise to the point of obfuscation is not.

Contribute your hack

If you have something that you'd like to contribute, please send an email to monad_hacks@leeholmes.com.  There's no need to send the code just yet, but a description and example would be great.  If your hack fits within the focus and scope of the book, then you could be well on your way to getting your name in print.

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

Awesome AJAX web-based telnet application

A while back, I wrote the article, “A Web-enabled, Monad front end: Monad hosting.”  It was in reference to WebCmd, a neat little Javascript application that emulates an interactive terminal.

I also talked about the fact that it wasn’t really an interactive terminal. 

This falls quite short of the infrastructure required to support an interactive program such as VI. Let alone Emacs 🙂  There's no support for cursor positioning, keyboard polling, and much more. For the Unix world, take a gander at the feature set of the VT100 Terminal Emulation Requirements. For the Windows world, look at the Win32 Console API. To make a fully interactive web-enabled front-end, you would need to implement the equivalent of cmd.exe in Javascript. The performance would be atrocious. So in the end, it's attainable -- but at a very large cost. Once you're done writing that much Javascript, you're likely to start rocking back and forth, whilst arguing with yourself.

Fast forward to today, where the Mike Bergsma leaves the following sleeper comment:

Did it. VT200 emulation. Pure AJAX. SSL It was difficult to say the least. It launches with a CGI script, or it is downloadable.

It’s a comment of understated magnificence.  One in the same vein as Fermat’s famous, "I have a truly marvelous proof of this proposition which this margin is too narrow to contain."

Mike has implemented a web-based telnet application, including support for VT200 terminal emulation.  Mike provides a guest account on his server to test with.  I was able to log in, navigate around the system, get colorful directory listings, use hotkey shortcuts, and even execute heavyweight applications such as VI and Emacs.

Truly amazing – check it out: http://www.koikids.com/!

[Edit: This seems to have moved here: http://www.koikids.com/dashboard.htm ]

 

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

How do I easily load assemblies, when LoadWithPartialName has been deprecated?

There are some very useful parts of the .Net framework (ie: System.Web and System.Windows.Forms) that Monad doesn’t load into its AppDomain by default.  In order to use them, you first load them with one of the Load() methods from the System.Reflection.Assembly class.

At first, the easiest approach seems to be LoadWithPartialName.  You can simply request “System.Windows.Forms” and be done with it:

MSH:73 C:\temp > [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

GAC    Version        Location
---    -------        --------
True   v2.0.50727     C:\WINNT\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a5c561934e...

(you can cast the result to [void] if you don’t want your script to belch the loading information.)

However, the documentation shows this handy method as being deprecated.

This is because the API needs to make too many guesses about what you really want.  Most people don't really want "Whatever version of System.Windows.Forms you can scrounge up from the GAC or current directory."  Most people really want "Microsoft's version of System.Windows.Forms, shipped with .Net 2.0"

This is especially true in the face of breaking changes that may or may not happen to the DLL you want to load.  For applications that need to be reliable, LoadWithPartialName will cause problems.  Suzanne Cook discusses its implications on her blog entry, “Avoid Partial Binds.”

For scripts that you don't mind debugging by hand when things break, you can stick with LoadWithPartialName until it's physically removed from the framework.  However, your best bet is to consciously make the decisions that the LoadWithPartialName method makes on your behalf with the following helper script:

################################################################################
## load-assembly.msh
##
## Loads a given assembly by a more friendly name, while still using the strong
## binding characteristics of Assembly.Load.
##
## Assembly.LoadWithPartialName has been deprecated, as it binds only by display
## name.  It's a convenient shortcut, but opens your application and script, and
## environment  to all sorts of reliability issues, including:
##    backwards incompatibility, forwards incompatibility, breaking changes,
##    and subtle assembly dependency problems.
##
################################################################################
param([string] $assemblyName)

## Our assembly name shortcuts
$assemblyMappings = (
   ("forms""System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
   ("web""System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
)

## List the assembly shortcuts we support
if(-not $assemblyName)
{
   "Please specify an assembly name.  Supported assemblies are: "
   foreach($assembly in $assemblyMappings) { $assembly[0] }
   return
}

## Load the assembly they request
## This fails with an error message if this specific assembly version can't
## be loaded.
foreach($assembly in $assemblyMappings)
{
    if($assemblyName -eq $assembly[0])
    {
        [void] [Reflection.Assembly]::Load($assembly[1])
    }
}

 

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

Now THAT is obfuscated!

You might remember a recent obfuscated Monad script that Adam wrote.  It's impressive, but not as obfuscated as this one

This turned up in a search I was doing -- feed2podcast.com looks like an interesting idea.  Thank goodness they don't index the comments, because the spam sure is piling high there, Adam 🙂

 

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

Monad hosting, an introduction

A topic came up on the newsgroup today that I thought was a good segue into a series of posts that I’ve been working on.  Paraphrased, the question was, “How do I get Monad to do stuff from another .Net language?”

There are two ways to go about this, depending on the requirement.

The first is to cleanly separate your object model from your cmdlet implementation.  You write a class that does what you need it to.  You can invoke that class from .Net like any other class, and write your Cmdlet as a thin wrapper to interact with that same object model.  Think of this as the business logic / UI separation that is so important in designing a good application.

This is the ideal solution if your task and object model do not require access to the facilities that the Monad hosting environment provides.  Those facilities include object pipelines, user interaction, other cmdlets, providers, for example.

For cmdlets that do not require access to the Monad hosting environment, the release notes for Beta 3 describe a technique of accessing them from other .Net languages.  Although it is possible, it is really a release valve.  When access to the cmdlet from outside of Monad is important, developers should strongly prefer to expose both their object model and thin cmdlet wrapper to users.

The second way is to host the Monad engine inside of your application, and have Monad execute the pipelines you specify.  This provides both their application, and their cmdlets with many of the other benefits that come along with the Monad hosting environment.

This latter approach is one that I will illustrate over the next few articles.

 

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

New York Times follow-up on Brooklyn Camera Dealers

I had a phone interview with Michael Brick at the New York Times a few weeks ago about the problems I (and others) have had with certain shady online camera dealers.

His article on that just got printed, and it’s a good read.

Especially interesting is the various official quotes that explain how difficult it is to solve the problem.  Our collective internet rage takes place in a thought-based medium, where anything is possible.  We CC company CEOs on complaint emails, conduct virtual letter writing campaigns, and many other grand schemes for enacting change.  The transition to reality isn’t nearly as high-fidelity, and illustrates a sharp contrast:

"It is a perennial problem for us, particularly in New York, not necessarily for New York customers but for customers around the country," said Anthony Barbera, manager of the Information and Investigations Department of the Better Business Bureau of New York. "It is kind of a gray area, and we don't have enforcement power."

Keeping track of the companies has been a challenge, Mr. Barbera said, because they shift identities, shedding each Web site as it gains a bad reputation.

Without evidence of outright fraud, law enforcement agencies have largely declined to pursue criminal charges. This year, the state attorney general, Eliot Spitzer, mediated four complaints against Price Rite and referred two to the city Department of Consumer Affairs.

"It's just not something we have the resources to pursue, in terms of you need a pattern and you need a number of complaints and a similarity in the pattern in order to put an action together," said Brad Maione, a spokesman for Mr. Spitzer.

However, these places are in business to make money in our thought-based medium.  Blogs and online forums (indexed by the same search engines that drive traffic to these retailers) enable us to choke their supply of customers.  Word of mouth has never been so efficient.

Like mine, Thomas Hawk’s posts, and Don Wiss’ efforts have certainly been the cause of thousands of lost sales for these companies.

[Aside: As somebody correctly points out in Thomas’ comments, my quote in the article uses the word ‘literally’ very incorrectly.  I’m pretty prudish when it comes to that word (and hate its abuse,) so I think it was an incorrect paraphrase.  I could be wrong, though – it was a telephone conversation.]

 

 

Question: Do you _not_ read the newsgroup?

The microsoft.public.windows.server.scripting newsgroup has really blossomed into a useful community for Monad users.  When I post lengthy responses to the newsgroup, I very rarely post them to this blog as well.

So the question is -- how many of you do not read the newsgroup?  Feel free to post your response in either email, or a comment below.  If many of you read only the blogs, then I'll start posting more entries based on newsgroup threads.

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

Add a high-fidelity music input source to your car

I'm rebuilding my computer, so I don't have access to anything I have been planning to blog.  So instead, I thought I'd write about something that is commonly considered difficult -- but is actually quite within the reach of most of us.  Adding a high-fidelity music input source to your car.

If you have an MP3 player (or portable satellite receiver,) the first thing most people try is adding broadcasting the signal to their car stereo via an FM transmitter.  Transmitters designed for personal use are terrible, even under ideal conditions.  When I tried this, I managed to improve reception somewhat by placing the transmitter at the end of a long headphone extension cable.  This lets you place the transmitter as close to the car’s antenna as possible, and also acts as an antenna to increase the signal strength of the FM transmitter.  Doc Searls talks a little bit more about that here.

However, even ideal FM radio is still just FM radio.  Passable sound quality, but not that great, as it is approximately equal to that of a 56 kbps MP3.  The solution?  Add an RCA input to your car stereo.

You can usually get an adapter for about $30, and the “RCA to Mini” cord for about $15.  They plug into the place where the CD changer usually plugs into.  If you have a CD changer already, some will work as a pass-through.  If you are very lucky, your stereo already has the inputs and you just need to get the RCA to Mini cable.
If you have a stock radio in your car, searches like

            “<car name> RCA adapter”
            “<car name> auxiliary input adapter”

should help find the part to do what you need.  If that doesn’t turn up anything (or you have an aftermarket radio,) search for the input adapter that matches its model number.

Installation is usually pretty simple.  Radios are designed to come out pretty easily, so you can usually do it yourself.  It’s easily within the capabilities of somebody that can change a hard-drive in their computer, or build some IKEA furniture.  Just remember not to force anything that doesn’t want to go 🙂  Depending on your model of car, you can usually find plenty of places on the internet that will show how to gain access to the back panel.  The term car junkies use for the radio is “head unit,” so something like

            “replace head unit <car name>”

should give you an overview.  You’re not replacing it, but the instructions will show you how to get access to the back of the radio.  However, if your dash has a lot of pretty custom molding (or you just don’t want to be bothered,) a place like Best Buy should be able to install the part for about $30 in labour.  If you live in the Seattle area, I’ve had a lot of stereo work done at the Best Buy in Bellevue, and I trust their work.

Neat Integration of CodeSmith, MSBuild, Monad and Windows Workflow

Howard van Rooijen, who works for Conchango, just posted a neat integration of CodeSmith, MSBuild, Monad and Windows Workflow for his company’s Community Day.  We spoke about integrating MSBuild with Monad during the Hands on Labs at the PDC (and a few times since,) and it’s cool to see what’s come of his tinkering.

His Congestion Charge Demo simulates London’s Vehicle Congestion Charging System – the automated system that charges a premium for driving within central London during peak hours.

Great stuff!

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]