Scott Hanselman

The Weekly Source Code 40 - TweetSharp and Introducing Tweet Sandwich

April 3, '09 Comments [24] Posted in Open Source | Source Code | Windows Client | WPF | XML
Sponsored By

imageI just was at Quiznos hanging out with @QuiznosNick. He's a former Technology Executive who bought a Quiznos Franchise for his retirement. He's a major geek, and while chatting he wonder how he could take orders over Twitter. I wanted to see how easy it'd be to write as a real app. I could use PowerShell or Curl, but it's all in good fun, right?

For no reason at all, here is the thought process and code as I write it. I shall call it Tweet Sandwich.

Step 0 - Make it Pretty

Ok, WPF will do fine. Of course, before I do any work or planning or anything, I'll need an icon. ;) Search the web, find a nice, free non-commercial icon of a sandwich. Make it transparent with Paint.NET, make a 32x32 and a 16x16 at 24 bit color and paste into Visual Studio. Name it app.ico. Waste of time, perhaps, but it motivates me personally to do the pretty stuff first.

Take the Window1, call it Main and setup some controls. Grab a Free Twitter Bird PNG and a picture of a Sandwich, more Paint.NET and I've got a Main Form.

I tell you, being able to use Paint.NET and the clipboard, and a good understanding of how transparency works in Windows is an important skill to have. I'm no artist, but I can hack together a picture of a bird and a sandwich with the best of them.

Tweet Sandwich

What Settings Do I Need to Save

OK. Now, I put the Settings in the Properties dialog for the project.

image

Then I'll put in some small databinding code to make the text boxes in the form fill with the data from the settings.

<Window x:Class="TakeOrdersOverTwitterWPF.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Tweet Sandwich" Height="459" Width="454"
xmlns:local="clr-namespace:TakeOrdersOverTwitterWPF.Properties">
<Window.Resources>
<local:Settings x:Key="settings" />
</Window.Resources>
<Grid>
<GroupBox Header="Settings" Name="groupBox1">
<Grid DataContext="{StaticResource settings}" >
<TextBox Name="twitterUserName" Text="{Binding Path=Default.TwitterUserName}"/>
...etc...

The keys are the Settings Resource that maps to the Properties (Settings) for the app. Then the Binding to the TextBox. Then we save them when the app closes with Settings.Default.Save();

How Often Will I Check For Orders?

Now, I'll setup a Timer to check for orders every five minutes:

DispatcherTimer twitterTimer = null;

private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.twitterTimer = new DispatcherTimer(new TimeSpan(0, 5, 0), DispatcherPriority.Normal, CheckForOrders, this.Dispatcher);
}

private void CheckForOrders(object sender, EventArgs e)
{
...
}

Gotta GET the Twitter Feed now...check the Twitter API. Do I want RSS or an API? The Twitter API has a REST model, and I need to see the replies to QuiznosNick, so I'll need to add some options to my application. I'll need to authenticate as QuiznosNick and ask for his replies list. I need his username and password. I'll probably want to call this API, which will let me see replies since some time. Looks like I can use the Date, or a status id, which is a big number that keeps getting bigger.

statuses/replies

Returns the 20 most recent @replies (status containing @username) for the authenticating user.

URL: http://twitter.com/statuses/replies.format

Formats: xml, json, rss, atom

Method(s): GET

Parameters:

  • since_id.  Optional.  Returns only statuses with an ID greater than (that is, more recent than) the specified ID.  Ex: http://twitter.com/statuses/replies.xml?since_id=12345
  • max_id. Optional.  Returns only statuses with an ID less than (that is, older than) the specified ID.  Ex: http://twitter.com/statuses/replies.xml?max_id=54321
  • since.  Optional.  Narrows the returned results to just those replies created after the specified HTTP-formatted date, up to 24 hours old.  The same behavior is available by setting an If-Modified-Since header in your HTTP request.  Ex: http://twitter.com/statuses/replies.xml?since=Tue%2C+27+Mar+2007+22%3A55%3A48+GMT
  • page.  Optional. Retrieves the 20 next most recent replies.  Ex:http://twitter.com/statuses/replies.xml?page=3

Returns: list of status elements

How Will I Call Twitter?

I could just make a call to Twitter using WebClient and Basic Auth, but since I'll only be paid in Sandwiches, I'll use TweetSharp. It's a smidge overkill for one API call, but it'll let me figure out if TweetSharp is fun or not. I could have also used LinqToTwitter, so try them both out and make your own judgment.

Here's how you would get the replies for an authenticated user using TweetSharp. I might switch this over to DirectMessages, which is less fun, but more secure, if things become a problem.

TwitterClientInfo info = new TwitterClientInfo() { ClientName = "TweetSandwich", ClientVersion = "1.0" };
var twitter = FluentTwitter.CreateRequest(info)
.AuthenticateAs(twitterUserName.Text, Password.Password)
.Statuses()
.Replies().AsXml();

string result = twitter.Request();

At this point, "result" has the XML I want in it.

Text Visualizer (3) 

The general structure of the nodes I'll need is:

statuses
status
created_at
id
text
user
id
name
location

I want "all status's greater than the lastid, and from those, extract the text, user id, name and location, sorting by created_at descending." In LINQ to XML, that might be:

XDocument doc = XDocument.Parse(result);
var statuses = (from d in doc.Descendants("status")
where int.Parse(d.Element("id").Value) > lastOrderNum
where d.Element("text").Value.Contains(orderString.Text)
select new
{
tweetid = int.Parse(d.Element("id").Value),
name = d.Element("user").Element("name").Value,
location = d.Element("user").Element("location").Value,
tweet = d.Element("text").Value,
dateTime = d.Element("created_at").Value.ParseTwitterDateTime()
}).OrderByDescending(t => t.dateTime);

However, TweetSharp has an object model that will deserialize JSON so I don't even need to do this. I can use their objects and still use LINQ, which makes this even cleaner. I can avoid all the strings and the dataType conversions as it's all hidden. Not to mention the hacky ParseTwitterDateTime extension method I got from Wally that he got from Tim Heuer.

TwitterClientInfo info = new TwitterClientInfo() { ClientName = "TweetSandwich", ClientVersion = "1.0" };
var replies = FluentTwitter.CreateRequest(info)
.AuthenticateAs(twitterUserName.Text, Password.Password)
.Statuses()
.Replies()
.Since(lastOrderNum)
.AsJson();

IEnumerable<TwitterStatus> statuses = replies.Request().AsStatuses();

var statusesFiltered = from d in statuses
where d.Id > lastOrderNum
where d.Text.IndexOf(orderString.Text, StringComparison.OrdinalIgnoreCase) != -1
orderby d.CreatedDate descending
select d;

Printing Orders

Now I just need to print them out. Every Quiznos has the same computer and the same printer that they got from the corporate office. I don't care though, I'll just print out an order on whatever default printer they have.

Printing is hard, and I only allocated a few hours to do this, but Printing a "Visual Object" in WPF is easy.

PrintDialog dlg = new PrintDialog();
dlg.PrintVisual(orderCanvas, "Whatever");

I could just make a Canvas with a bunch of controls to represent the last tweeted order, and print that. 

Tweet Sandwich (2)

However, the last time I did anything with Printing it was VB6 and it was hard. How hard it is now to make a real document today in WPF?  I figured I'd find out by trying.

I thought I'd use these FlowDocuments and make one that can show a Tweet. I went File | Add New Item | FlowDocument and call it SandwichOrder.xaml.

Add New Item - TakeOrdersOverTwitterWPF

I made a FlowDocument as a Resource that looked like this I could do it manually, do it in Word and save it, or use an HTML to XAML converter as others have.

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
FontSize="24" FontFamily="Georgia">
<Paragraph>
<TextBlock Text="{Binding Path=User.ScreenName}"/> in
<TextBlock Text="{Binding Path=User.Location}"/>
says on <TextBlock Text="{Binding Path=CreatedDate}"/>:
</Paragraph>
<Paragraph FontFamily="Arial">
<TextBlock Text="{Binding Path=Text}"/>
</Paragraph>
</FlowDocument>

I figured I want to DataBind to it, using the TweetSharp TwitterStatus object. Dynamically creating a document from a resource template, binding to it and printing it seems like a core scenario. Googling around, though found a lot of people having trouble with a few basic things that I was hitting into also.

NOTE: I might be doing this wrong, so I need to ask a WPF expert at Microsoft to see if I'm wrong about some things I think are too hard.

Dynamically Creating a FlowDocument, Data Binding and Printing It

First, I wrote this:

private void PrintOrder(TwitterStatus t)
{
var streamInfo = Application.GetResourceStream(new Uri("resources/SandwichOrder.xaml",UriKind.Relative));
FlowDocument doc = XamlReader.Load(streamInfo.Stream) as FlowDocument;
doc.DataContext = t;
PrintDialog dlg = new PrintDialog();
dlg.PrintDocument(((IDocumentPaginatorSource)doc).DocumentPaginator,"Tweeted Sandwich Order");
}

I felt OK about it, but not awesome. First, it was too hard to get my FlowDocument out of the Embedded Resource. I thought I could do something like App.Resources["SandwichOrder.xaml"]. I also wanted to do lines one and two in all one like like: var doc = FlowDocument.FromResource("SandwichOrder.xaml").

Finally, the weird interface cast in the PrintDocument line was totally counter intuitive. Seemed like PrintDocument should have an overload that takes a FlowDocument.

Then I tried to print. When I printed, the data binding didn't happen. I just got the basic text. More Googling showed there's a threading issue and the binding happens on another thread?

Now I had to add what appears to be the WPF equivalent of "DoEvents" - that big dispatcher call that releases the thread to do pending stuff. This CAN'T be right. I MUST be doing something wrong, so I'll update this post as I learn.

private void PrintOrder(TwitterStatus t)
{
var streamInfo = Application.GetResourceStream(new Uri("resources/SandwichOrder.xaml",UriKind.Relative));
FlowDocument doc = XamlReader.Load(streamInfo.Stream) as FlowDocument;
doc.DataContext = t;
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.SystemIdle, new DispatcherOperationCallback(delegate { return null; }), null);
PrintDialog dlg = new PrintDialog();
dlg.PrintDocument(((IDocumentPaginatorSource)doc).DocumentPaginator,"Tweeted Sandwich Order");
}

After this printing and databinding worked, except the TextBlocks I was using didn't wrap, so the orders got clipped. I tried using a <Run> but they don't support DataBinding. I ended up having to add a BindableRun class as more Googling showed more confusion. Folks have created Bindable Tables also, it seems and this BindableRun pattern seems common. I need to check on why this isn't built in.

Now my FlowDocument looks like this:

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:bt="clr-namespace:TakeOrdersOverTwitterWPF.BindableText;assembly=TakeOrdersOverTwitterWPF"
FontSize="24" FontFamily="Arial">
<Paragraph FontSize="48">Twitter Order</Paragraph>
<Paragraph>
<bt:BindableRun BoundText="{Binding Path=User.Name}" />
(<bt:BindableRun BoundText="{Binding Path=User.ScreenName}" />) in
<bt:BindableRun BoundText="{Binding Path=User.Location}" /> says on
<bt:BindableRun BoundText="{Binding Path=CreatedDate}" /> :
</Paragraph>
<Paragraph FontFamily="Arial">
<bt:BindableRun BoundText="{Binding Text}" />
</Paragraph>
</FlowDocument>

And it prints exactly as it should. So, for printing, to recap, I:

  • Made a Template FlowDocument and embedded it as a Resource
    • Had to use a BindableRun
  • Pulled it out of the resuorce, DataBinding, did a weird dispatcher hack, printed it.

Too much Googling on that one. It wasn't nearly as obvious to print as it was to do the Graphical UI.

image

This app, modified, could be used to waste dead trees by printing out tweets that contain words. Mark Nijhof is using TweetSharp to tweet what he blogs. It could also make the computer beep when a sandwich order arrives. Oh! There's an idea!

Tomorrow at lunch, I'll present Tweet Sandwich, the first automated Twitter-based Sandwich Ordering System to @QuiznosNick and hope I earned a free sandwich or ten. ;)

Download the Source from SkyDrive

Please offer feedback, as I'm sure there's lots of ways this can be cleaner. For example, a bound listbox of Replies/Orders (starts to look like a real Twitter Client, then.)

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Microsoft ASP.NET MVC 1.0 is now Open Source MS-PL

April 2, '09 Comments [23] Posted in ASP.NET | ASP.NET MVC
Sponsored By

iStock_000003337699XSmall The source for ASP.NET MVC has long been available up at http://www.codeplex.com/aspnet. The source has been "Available" so I usually call this "Source Opened" as opposed to "Open Source."

ASP.NET MVC has been "Free" as in "Gratis" since it started. That means, "Free like Beer." As ScottGu just blogged about moments ago, today, it's also "Libre" as in "Free like Speech." You can do what you want with the source. 

Today, ASP.NET MVC is now Open Source and licensed under MS-PL. That means you can change it, redistribute your changes, even fork it if you want. MS-PL is an OSI-Approved Open Source License and you can read the legalese on their site.

"The Ms-PL contains no platform restrictions and provides broad rights to modify and redistribute the source code."

As a reminder, MEF (Managed Extensibility Framework) is another .NET Framework component that's MS-PL, as is the DLR (Dynamic Language Runtime) and IronRuby. The Ajax Control Toolkit and Silverlight Toolkit is also MS-PL.

These are all baby steps, but more and more folks at The Company are starting to "get it." We won't rest until we've changed the way we do business.

If you like, you can download and install ASP.NET MVC 1.0 from inside of the Web Platform Installer 2.0 directly.

Congrats to ScottGu and PhilHa and the team for making this happen. Now, go bask in the source as the ASP.NET MVC 1.0 download has been updated with a zip of the source. I hope Miguel is dancing today.

If you have any questions about the future, legal stuff, etc, I'll defer them to ScottGu (leave them in his comments).

(This is not an April Fools joke. It's for reals.)

Related Links

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

.NET 4.1 Preview - New Base Class Library (BCL) Extension Methods - RFC

April 1, '09 Comments [16] Posted in ASP.NET | DLR | Javascript | Learning .NET | Microsoft | Musings | Open Source | PHP | Programming | Python | Silverlight | Source Code | Tools | VB | Web Services | Windows Client | XML
Sponsored By

As web programmers, we use a lot of strings to move data around the web. Often we’ll use a string to represent a date or an integer or a boolean. Basically "1" in instead of 1, or "April 1, 2009" rather than a proper ISO-8601 formatted culture-invariant date.

While these strings are flying around via HTTP it's not a huge deal, but sometimes this loose, even sloppy, use of strings can leak into our own code. We might find ourselves leaving the data times as strings longer and longer, or not even bothering to convert them to their proper type at all. This problem is made worse by the proliferation of JSON, and schema-less/namespace-less XML (that I've often called "angle-bracket delimited files" as they're no more useful than CSVs in that point.

.NET 4.0 is pretty much locked down, but version 4.1 still has some really cool "Futures" features that are being argued about. If we don't know the type of a string, or we want to leave the string, as a string, longer than usual, what if we had an class that could be both a string and another type, essentially deferring the decision until the variable is observed. For example:

StringOr<int> userInput= GetUserInput("Quantity"); 
string szUserInput=userInput.StringValue; 
int intUserInput=userInput.OtherValue;

Sometimes you just don't know, or can't know.

This reminds me of a similar, but orthogonal physics concept, that of the Heisenberg Uncertainty Principle. Sometimes you know that an object is a string, and sometimes you know how long it is, but you can’t know both at the same time.

One of my favorite jokes goes:

Heisenberg gets pulled over by the police. The officer asks, “Do you know how fast you were going?” Heisenberg answers, “No, but I know exactly where I am!”

This library doesn't solve THAT issue, with respect to strings, but we’ve got folks in DevDiv working on this and many other metaphysical - and physical - problems as they apply to computer science.

Big thanks to Eilon, who's working hard to get this pushed into the .NET 4.1 Base Class Library. Visit Eilon's blog for more details on this new library, more code, graphics and details on how Intellisense will handle this new case.

Hopefully, someone is working to make this important new library Open Source.

Your thoughts, Dear Reader?

Related Posts

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Paving my machine for a fresh 2009 - First-Pass Must-Haves

March 31, '09 Comments [62] Posted in Tools
Sponsored By

Back in 2006 I paved (or "formatted", or "torched", or "gave "a technical enema") to my main machine and blogged about the what I call the first-pass software I installed on this new fresh machine.

It was time to torch my Atwood Quadpower machine and name it Quadpower7. Time for a clean install, and this time it includes Windows 7 x64 Ultimate.

I know I have a Tools List (that I know needs to be updated, thank you) but what I needed on this new machine was to be as productive as possible as fast as possible. I needed the 80% stuff installed. 

First-Pass Must-Have Apps for a Fresh Machine and a Happy Life

Here's what I installed. Total time from naked drive to productive was about 4 hours. Could have been faster had I downloaded things ahead of time or used CDs.

Windows Utils

  • 7-Zip - Best Zip Tool with the best shell integration.
  • AutoHotkey and the AutoCorrect for English Script - This will change "teh" to "the" everywhere I type. Plus 4700 other common English misspellings.
  • SmartFTP - Love them and gave them money. Got the 64-bit version.
  • Paint.NET - The best free Image Editor in town. Thanks Rick Brewster!
  • Prish Image Resizer - If there's one secret super amazing gem in this list, it's Prish. After I pave my wife's machine this is the ONLY util she insists on. She refuses to even touch the machine - "Is Prish on? No? Don't talk to me." Go get it and bask in the wonder of this glorious little app that's hard to find on the web. Gotta get this man a domain name.
  • Notepad2 3.0 - It's like notepad, but 2. Er, 3.0.

Developer Stuff

Easiest and fastest way to get productive is to use the Web Platform Installer. It also configures IIS, installs VS and SQL, and can install Silverlight tools, etc. if you like. This tool alone saves me HOURS each time I pave a machine.

Organizational Stuff

Blogging Stuff

  • Windows Live Writer - I love this team and I love their product. Also installed the Pre-Code Plugin for my code samples.
  • SnagIt and WindowClippings - SnagIt because their image editor is butter, and WindowClippings because it's amazing with transparency.
  • FeedDemon - I know you guys are all Google Reader and all, but I really prefer to read my blogs in a REAL client. FeedDemon's awesome, it's free, and it's written in Delphi. What's not to like? 

Social Stuff

  • TweetDeck - My current Twitter power-client of choice.
  • Zune - Because the Zune Pass kicks ass, as does Jazmine Sullivan.
  • Messenger - Cuz you gotta chat.
  • Skype and ooVoo - The former so I can talk cheap around the world, and the latter so I can video chat with up to 6 other people in 640x480 high res.

Pretty Stuff

  • Mike Swanson's Windows 7 Theme Pack - Some of Mike's best images for my wallpaper, auto-updating every 30 minutes.
  • VLC Player - For playing any video that I don't feel like getting a Codec for. (Which is fewer and fewer as there's lots of codecs included in Win7.)

And there you go. That was it. There's other stuff, but it's part of the 20% and I'll install them as I need them.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Mix09: Hanselminutes on Channel 9

March 28, '09 Comments [8] Posted in ASP.NET | ASP.NET MVC | Channel9 | Microsoft | Mix | Podcast
Sponsored By

Channel 9 Guy While I was running around Mix09 and the MVP Summit this last few weeks I was taking video with my Flip Ultra and my new Creative Vado HD (I took the Flip Mino HD back, as I thought the quality was poor). I put a bunch of these videos up on Channel 9 and declared it "Hanselminutes On 9." It's not official, but maybe if you leave comments they'll make it a regular thing. Some of the videos are pretty cool. Others, totally useless. ;)

While Channel 9 recompresses my already compressed streams, I want to point out that the letterboxed 16:9 videos were done with the Creative Vado HD, then the aspect ratio was changed with Expression Encoder. The 4:3 videos were done with my regular Flip Ultra. Let me know which ones you prefer more.

If you like this idea, I'll start taking my cameras everywhere and when I talk to interesting people, I'll throw the videos up on Channel 9 as I make them. I started doing this almost two years ago with Rory and a bunch of videos were recorded, but those recordings are lost in the sands of time. Here's the first "pilot" episode of Hanselminutes on 9 with Polita Paulus, though. You can see from the old comments that it was a pretty decent show, that.

Johnny Lee
Johnny Lee on Computer Vision
Wow. I just bumped into Johnny Lee in the halls here at Mix09. I'm a huge fan boi with a man-crush on this dude. You've seen Johnny before on Channel 9 talking to Robert Hess.  Johnny's a legend (in my mind) in the computer vision space, and he put up with me gushing at him here at Mix09. We chatted in the hall about computer vision, what he's working on, how he got the gig at Microsoft and where he sees the future of human-computer-interaction.
Eilon Lipton
Eilon Lipton and the ASP.NET MVC Rumors
In this episode of Hanselminutes on 9, I break into Eilon Lipton's office and demand the real scoop on who or what wrote ASP.NET MVC. The word on the street is that ScottGu wrote the original prototype, codenamed "Scalene" on an airplane. Is this true? I pretend to turn off my camera and fool Eilon, the lead developer on ASP.NET MVC, to give up the goods.
See how he gazes lovingly at me? That's just the kind of bromance that Eilon and I have.
image
Phil Haack on the ASP.NET MVC 1.0 Release
This Hanselminutes on 9 video was filmed at the MVP Summit on the Redmond Campus. I was on campus for the week with my trusty Flip Video camera and I pulled Phil Haack outside and demanded the real scoop on ASP.NET MVC. I beat him about the head and ears and asked questions like "what qualifies you to be a PM at Microsoft!" If you like this kind of hard-hitting journalism, tell the folks at Channel 9 to give "HanselminutesOn9" its own Tag or Category for Pete's Sake! Wink
image 
Joel Spolsky and Jeff Atwood preparing for StackOverflow Keynote
Security is tight here at Mix09 but I've snuck past the guards and followed Joel Spolsky (JoelOnSoftware) and Jeff Atwood (CodingHorror) up the escalator to their Keynote Rehearsal. The fans went wild! Well, one fan. A lady on the escalator recognized them. But still! The air is electric. Let's listen in...
image 
Rob Conery and the MVC Storefront
I'm wandering the halls in Building 42 and bump into the man himself, Rob Conery. This is amazing for a number of reasons, not the least of which being that Rob lives in Hawaii. I put the hot lights up to Rob and get him to confess to a number of transgressions. Turns out he IS still working on the MVC Storefront and will be giving us the source in some form or another. Most likely in the form of source. So, we got that going for us.
image 
Brad Wilson has Lunch
In this completely useless video (you have been warned),  Scott bumps into Brad Wilson in the halls of Building 42 and finds out what Brad is having for lunch. He also says a little about the Data Annotation-based Model Binder that they showed at Mix 09. A glimpse at what is to come in the unholy marriage of ASP.NET MVC and ASP.NET Dynamic Data. I shudder to think of the possibilities. A small shudder, to be clear, but it's there. Almost palpable.

I also want to point out, that while it's not totally obvious, there are some tiny icons next to the images when you get to the Channel 9 site. They look like this:

Picture of Tiny C9 Icons

These icons are clickable and mean each video is available in a number of formats, including portable device ones, and also that you can easily share these links/videos on various social networking sites. So please do.

Enjoy!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.