In the last post, we looked at ways to separate content using different pieces of Windows Azure for the benefit of creating a more cost-effective solution using Windows Azure Web Sites (WAWS) and Windows Azure Storage for storing images and other binary/static files. Although we’re looking at this just for cost efficacy, frankly that approach just makes sense from an availability and performance aspect, too. Another fantastic service is Windows Azure Mobile Services (WAMS), but unsurprisingly, it has its own cost structure outlined here: Similar to WAWS, you can have up to 10 services for free. But, the way these services are metered are completely different, and it might change the way we build an application. First, let’s discuss the free tier. The current metering, limited to 100 devices, means that using an authenticated client (that is, any client using the SDK) renders this tier useless for anything other than testing. For example, here’s my low-use application: We’re not really incurring many API calls, but our device count is pretty high. When I designed the app, these meters weren’t in place, but if they were I’d design the app differently. Hopefully, we’ll see some changes in this as the current plan is a bit inflexible. What this means, though, is that for my app to keep working, I need to upgrade to the $25/mo plan. By making a few specific decisions early on, we can build the application to take advantage of both WAMS and WAWS. For example, in WAMS, custom API calls can be made and invoked over HTTP. I leveraged this in Brew Finder for several items: brewerydb’s callback, live tiles, and web services that don’t require authentication. Because these calls are made from “non-devices,” the usage looks like so: I’m not exactly sure why this is showing zero bytes out (it could be for the time duration shown in this graph, it’s not significant enough), but the 0 devices and API calls count is accurate. We also have the option to deploy another WAWS with node.js, if we’d like to stick with server-side javascript. Remember, the database that is used can certainly be shared by any number of WAWS, WAMS, etc. So, if you need to curb back on your API calls, offload that work to a WAWS instead where the calls are not metered if you don’t need WAMS specific features (like authentication). Summary The biggest challenge in developing a cloud backed app is guesstimating the usage. The first step, though, is to understand what is being measured – API calls, devices, bandwidth, CPU time, etc. Keeping the application architecture spread across multiple services for different functions (authentication, live tiles, etc.) is a great way to make the application flexible so you can take advantage of the way each service is metered, bearing in mind this is always subject to change. Having trouble estimating or getting started? Drop me a note or leave a comment on this post. I’d be happy to help you work through some ideas.

One of the great advantages of having a green field cloud-based infrastructure is being able tailor the app using specific features of the platform. Sometimes, cost isn’t an issue. But, many times – particularly for indie devs – it is. Scale isn’t the foremost concern here, and often times dependability isn’t, either. Rather, it’s flexibility and cost. In this post, I’m going to dissect a few ways to take advantage of Azure and save some coin in the process. Estimating Azure costs continues to be one of the most frequent questions I’m asked. First a couple of housekeeping issues: Windows Azure has a pricing calculator that shows the current prices and allows you to turn the knobs and dials to forecast the price. I’m writing this blog post on 7/24/2013, and since prices are dynamic, this post will be dated as prices modulate so keep that in account. Also, I’m doing rough math to keep this simple, and picking zone 1 for bandwidth costs (which is everywhere except East/Southeast Asia where rates are slightly higher). What hat are you wearing today? I’m approaching this as an indie dev who wants to create application services and host content without incurring a big expense. I need reasonable reliability (no under the desk servers, but I don’t need geoloadbalancing, either), and I’m not willing to pay for 2+ servers for an SLA. In short, my apps currently don’t make enough money. These data points below are taken from my current apps you can see on my blog sidebar. Windows Azure Virtual Machines cost $0.02/hr or about $15/mo. If you’re the kind of person who likes to install all kinds of stuff, this might be for you. It’s a good option to keep in mind because unlike most other offerings, this is completely customizable. I could load up this server and support all my apps, if I wanted to, but for now, this isn’t anything I’m interested in. First, let’s look at Windows Azure Web Sites (WAWS). With WAWS, you can easily deploy web sites and apps, but lose some of the customization. You can either spin up an app based off an image (like Wordpress) or deploy your own web site. You can host up to 10 sites for free, or upgrade to shared mode -- required for custom domains and costs about $10/mo. If we stick with Free, we’re metered to about 1 hour of CPU time per day (which means deploying your own chess engine might be a bad idea). This is also sub-metered to make sure we’re not gobbling up too much in any given block of time – here’s an image of the dashboard for my Dark Skies / Windows 8 app: File system storage and memory usage you generally don’t have to worry about. Your app is unlikely to change its size footprint, and you’d have to have a specialized case to warrant memory concerns. The free tier is also limited to 165MB/day of outbound bandwidth per day. This is the one we need to watch. More users often mean more CPU, and can mean higher memory usage, but certainly will linearly impact the bandwidth our app uses. In addition, I can see most of these values plotted for the last week on the dashboard: This WAWS has a very predictable usage pattern. I’m not concerned about the outbound bandwidth yet, but that’s by design. By knowing this value is metered strictly, it’s best to keep images and other static files (such as JS files) elsewhere, such as in blob storage, as those will tear up the 165 MB/day limit. So let’s take a step back for a moment. What is this WAWS doing? It’s serving Windows 8 live tiles for Dark Skies, like so: The ASP.NET MVC based site has an engine that determines the moon’s rise/set times, and passes this down to a view which looks like: <tile>
<visual>
<binding template="TileWideSmallImageAndText03" branding="name">
<image id="1" src="http://lightpollution.blob.core.windows.net
/icons/80/waning_gibbous.png" alt="moon phase"/>
<text id="1">Waning Gibbous
Rises at 09:43 p.m.
Sets at 09:41 a.m.⁺</text>
</binding>
<binding template="TileSquarePeekImageAndText04" branding="name">
<image id="1" src="http://lightpollution.blob.core.windows.net
/icons/150/waning_gibbous.png" alt="moon phase"/>
<text id="1">Waning Gibbous
Rises at 09:43 p.m., sets at 09:41 a.m.⁺</text>
</binding>
</visual>
</tile>
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
There are a number of tiles that get served from this site, and at this point in time, it’s all it does.
Pretty simple for an entire website. All of the moon images are stored in blob storage instead of in the WAWS. This image is pulled by every Windows 8 app updating its live tile, which is about 1,100 requests per hour. The outbound text adds up to about 20MB/day, or about 600MB/mo. If we assume that each one of those requests are displaying a 10 KB image like in the tile above, that’s 1,100 x 24= 26,400 requests * 10 KB = 264,000 KB/day, or 264 MB/day. Ouch! Remember, we’re limited to 165MB/day – so we can keep within those limits by placing the images in blob storage. Blob storage isn’t free, so this would present a decision: do you put the images in blob storage, or keep them in the WAWS but upgrade to the shared tier? Here’s a quick look at the shared tier:
Using a Shared WAWS
There’s no limiting of bandwidth, and we’ll simply pay for what we use. In our above example, 264MB/day is about 7.5 GB/mo. If we look at the data transfer rate page, the first 5 GB/mo is free, followed by $0.12 / GB. Since our total outbound including the raw text puts us at 8 GB/mo, we’re only charged on 3 GB, and spending $0.36/mo on bandwidth. Remember, too, that we upgraded to Shared mode to unlock the restrictions, which is $9.68/mo.
All said, we’re looking at $10.04/mo if we’d like to put the entire site in a single WAWS.
Using Storage
In this example, let’s break out the images (as it currently is in production) and compare costs. Our WAWS is free, and looking at the meters, we’re comfortable within the usage restrictions. The only thing we need to worry about is our blob storage account. Blob storage, if you aren’t familiar with it, is a service that holds any kind of binary data, like files, images, and documents. It’s scalable and an easy way to separate the code of a website from the content, and compares to Amazon’s S3.
Looking at the storage pricing page, our images consume a a few MB at most, so we need to round this cost down to $0.01 as it’s just impossibly small at this scale. Transactions are incurred for every get request, at the cost of $0.01 per 100,000 transactions. Since we’ve got 26,400 requests/day, that’s 792,000 requests/mo, or about $0.08. The outbound bandwidth remains unchanged.
All said, we’re looking at $0.36/mo for bandwidth and $0.09/mo for storage, for a total of $0.45/mo.
Conclusion
Obviously it’s a big cost savings to stick with the free Windows Azure web site and offload the assets into blob storage. We don’t have an SLA on the free tier, but then, if a request fails, it’s a silent fail as the tile skips that update. The user isn’t likely going to notice.
The difference gets a little more interesting when looking at Windows Azure Mobile Services, and I’ll do that in the next post…

This post details features used by Earthquake Explorer, a Windows 8 app that displays earthquake information on Bing maps. Earthquake Explorer was based off of the Earthquakes mashup starter kit on github. Read part 1 here. Read part 2 here. We left off Part 2 talking about creating a compelling live tile in Windows 8. This really is a must-do feature in Windows 8 – primarily because a live tile creates a more compelling app experience. It encourages the user to keep the live tile ‘pinned-left’ (that is, more likely on their primary screen), and encourages the user to open the app more frequently. That equals higher app usage, higher ad impressions, etc. Because the earthquake app is consuming earthquake data on our backend using Windows Azure Mobile Services, it’s trivial to send notifications when new earthquakes are detected. We can send a nice live tile that looks like so: Clearly, this is better than displaying _nothing_, and the map adds a professional look to it. We can also combine this with badges – for example, in Dark Skies, I do something similar when users add new locations to the map, adding a badge notification that displays how many new locations are nearby: The first step in doing this is to determine which tile template to use. Because the map is the main image, this is a pretty simple as we’d want the map to take up the main tile. The place to look is the tile template catalog on MSDN. In this case, TileWideImageAndText02 seems to fit the bill for wide tiles, and TileSquareImage is the bet bet for smaller, square-sized tiles. From the template page: The key here is the tile XML – it’s the same if we’re doing a push notification, if the app is updating its own tile, or if Windows is updating the tile using the TileUpdater using periodic updates. To get the image, we’ll use the Bing Maps REST API, which requires a valid Bing Maps key from the portal site. For a wide tile, we can get a static map using a URL like so, specifying the zoom level (2), centered location (36 latitude, –79 longitude), pushpin location (also at 36 latitude, –79 longitude), and a size of 310x100: http://dev.virtualearth.net/REST/v1/Imagery/Map/Road/36,-79/2?mapSize=310,100&pushpin=36,-79;48&key={your_api_key} Which returns an image like so: From the Windows Azure Mobile Service, it’s fairly simple to send a notification with some code like the below. I’m removing some of the dynamic text to shorten it up a little, but realistically we’d be setting the location of the pin(s) and text of the tile itself dynamically: 1: function sendNotification(channelUri) { 2: 3: var baseImageUrl = "http://dev.virtualearth.net/" + 4: "REST/v1/Imagery/Map/Road/36,-79/2?[mapsize]" + 5: "&pushpin=36,-79;48&key={your_api_key}"; 6: 7: var smallImage = baseImageUrl.replace("[mapsize]", "mapSize=150,150"); 8: var bigImage = baseImageUrl.replace("[mapsize]", "mapSize=310,100"); 9: 10: var payload = "<tile><visual><binding template='TileWideImageAndText02'>" + 11: "<image id='1' src='" + xmlEscape(bigImage) + "' alt='map'/>" + 12: "<text id='1'>Some top line text here</text>" + 13: "<text id='2'>Some bottom line text here</text>" + 14: "</binding>" + 15: "<binding template='TileSquareImage' branding='none'>" + 16: "<image id='1' src='" + xmlEscape(smallImage) + 17: "' alt='map'/></binding></visual></tile>"; 18: 19: var theTag = 'some_identifier'; 20: push.wns.send(channelUri, payload, 'wns/tile', 21: { 22: client_id: 'your ms-app:// id', 23: client_secret: 'your client secret', 24: headers: { 'X-WNS-Tag': theTag } 25: }, 26: function (error, result) { 27: if (error) { 28: console.log("(" + error.statusCode + ") Error sending notification"); 29: } 30: } 31: ); 32: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
(Note: the xmlEscape method is omitted, but is a simple method that escapes special characters for the XML document.) What we’re doing here is using the push.wns (Windows Notification Service) object to send the tile XML directly. If you review the script reference, it is certainly simpler to use the push.wns.sendTileWideImageAndText02 method, but I generally prefer to build the XML directly as done above. The reason is that it allows you to bundle multiple notifications together – such as including both the wide and narrow tile versions. (The other side benefit is that this allows you to enter the application package ID and secret, which should allow a single WAMS to send notifications to multiple applications.)
We’ll look at other mashup examples in future posts!

This post details features used by Earthquake Explorer, a Windows 8 app that displays earthquake information on Bing maps. Earthquake Explorer was based off of the Earthquakes mashup starter kit on github. Read part 1 here. In the first part, we created a Windows Azure Mobile Service to store data as a back end for our mashup. A big benefit of this approach is that it lets us filter/sort/query the data any way we’d like, and our application is now resilient against outages and changes in the schema. In this part, we are going to modify our existing scheduled task to consume the actual USGS data feed and store it in a table. Getting the data is simple, thanks to the nice GeoJSON feed provided by the USGS. Read more about that here: http://earthquake.usgs.gov/earthquakes/feed/v1.0/ From within our scheduled job, we can query it like so: function fetchUSGS() {
console.log('Starting job');
var httpRequest = require('request');
var uri = 'http://earthquake.usgs.gov/earthquakes/feed/v0.1/summary/all_hour.geojson';
httpRequest(uri, function (err, response, body) {
if (err) {
console.warn('Error connecting to service.');
} else if (response.statusCode !== 200) {
console.warn('Unexpected reply.');
} else {
//got reply, process the results
var theData = JSON.parse(response.body);
processData(theData);
}
});
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
We’re making a request to the feed (uri) and specifying the callback as the inline function. There really isn’t any robust error handling, but then, there really isn’t much you can do in the event of an error except just try again the next time the task runs.
Calling JSON.parse() will, naturally, parse the response text into a nice object collection we can parse. If we look at the JSON in fiddler, you can see the structure of the document:
The JSON contains a collection of features, where each feature contains a geometry object, an id string, and a properties object. Either through the documentation on the USGS site, or through examining the results, we’ll need to know the structure of the data.
To make working with the data a bit easier we can create a simple javascript class to hold the data:
function earthquake(item) {
this.latitude = item.geometry.coordinates[1];
this.longitude = item.geometry.coordinates[0];
this.depth = item.geometry.coordinates[2];
this.usgsId = item.id;
this.usgsCode = item.properties.code;
this.tz = item.properties.tz;
this.mag = item.properties.mag;
this.time = item.properties.time;
this.updated = item.properties.updated;
this.place = item.properties.place;
this.timestamp = new Date();
}
The one tricky part here is that the identifier of the earthquake is the USGS ID, but all data in Azure Mobile Services uses a bigint as a primary key. When we’re updating a row in Mobile Services, we’d pass the object into the update method with the appropriate ID (bigint). (Deletes require the bigint ID only.) Yes, this is a slight inefficiency because WAMS uses the surrogate bigint, and the USGS prefers the natural key of the USGS ID, and we will, for simplicity sake, use both depending on the operation. Because we’re requesting the data frequently, each item in the feed will have one of a few states: it may be new (not in the database), it may be in the database already, or it may be in the database but the feed contains updated/revised values.
function processData(json) {
var quakesTable = tables.getTable('earthquakes');
var featureList = json.features;
featureList.forEach(
function (item) {
var eq = new earthquake(item);
quakesTable.where({
usgsId: eq.usgsId
}).read({
success: function (results) {
if (results.length > 0) {
//record exists
eq.id = results[0].id;
eq.timestamp = new Date();
quakesTable.update(eq);
} else {
//record doesn't exist
quakesTable.insert(eq);
//send notification?
//see next blog post
}
}
});
}
);
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
As we iterate through the features, we create an earthquake object from each item. We then check the table for a record with the same USGS ID property. If it already exists, we’ll update the row with the information because details may have changed. Otherwise, we’ll insert it.
There’s a general inefficiency here that we can deal with if we’re so motivated. Each item results in a query to see if the item exists, and then a query to either update or insert. We could simply build a stored procedure that handles either scenario so it’s one call, but because each feed contains about 10 items and this scheduled task is a server-side job, it’s not high on my priority list. With higher volume apps and/or with client apps, this is a modification you should make.
The other nice thing we can do is send notifications when a new earthquake is found. For example, if a new earthquake is found in the feed, we can send a live tile notification which would update the tile to look like so:
For Windows 8 apps, this is really a must-do feature. Do _something_ (anything!) with the live tile – this will differentiate your app. Mobile Services can send notifications to Windows Phone, Windows 8, iOS, and Android, so this is a great way to take the app cross platform. In the next post, we’ll look at how to do a live tile update like the one above.

This post details features used by Earthquake Explorer, a Windows 8 app that displays earthquake information on Bing maps. Earthquake Explorer was based off of the Earthquakes mashup starter kit on github. Creating a mashup is pretty easy in Windows 8 – creating a great one requires a bit more work. In this case, I'm working with the USGS earthquake GeoJSON feeds, a very easy-to-use feed that contains earthquake information for either the past hour, day, week, or month. Overall, it’s a pretty ideal feed. But, if you search for and install virtually any earthquake app in the store, you’ll see the limitations quickly. While some apps allow some lightweight filtering of the data, there really isn’t a concept of search, pagination, and server-side filtering. To solve these limitations, we’d typically need to build out a fairly robust back-end server; fortunately, Windows Azure Mobile Services makes this really easy so let’s get started. First thing you need is a Windows Azure account (here’s a link to get a free trial). To get the pricing stuff out of the way first: Windows Azure Mobile Services currently offers a free tier (even beyond your trial), however, quite likely you’ll want to use a database behind the scenes, and that starts at $4.95/mo. EDIT: Good news! SQL Databases now offers a free tier for up to 20MB databases. Multiple Mobile Services can share the same database as they are all schematized. With your account ready to go, log in to the Windows Azure portal and select Mobile Services in the left nav. Next, click the New button in the bottom left to create a new Mobile Service (which I’ll just refer to as WAMS). The New flyouts are context aware, so it should be ready to create a new WAMS but, just to verify, you should see something like this: After a few moments your service is set up and ready to go. You will need to create a new SQL Database if you don’t already have one. The default page of your WAMS should look like this, and it’s full of great info for creating new or leveraging WAMS in existing apps: Let’s click on the data link highlighted above to create a table to store our data. We’ll call it ‘earthquake’, and we’ll also make it so only scripts and admins can modify the table, all users can read the table, like so: By default, WAMS is configured with dynamic schema, which means we can start inserting right away and the columns will be added dynamically to fit the objects we pass in. This is perfect for development. The next thing we’ll want to do is go over to the scheduled jobs page: After clicking create a scheduled job, give it a name like ‘fetchquakes’ and leave it run on demand only. The job will be created and if you are looking at the details of the job by clicking on it, you’ll see a fairly empty screen – we don’t care about the configuration and schedule right now, we simply want to add a script that runs as part of our job. Click the script button: Let’s start with a simple script. Ideally we’ll go out to the service and use live data, but this will get us started: function fetchquakes() {
var eq = {place: "Los Angeles", mag: 5.3, timestamp: new Date()};
var quakesTable = tables.getTable('earthquake');
quakesTable.insert(eq);
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
If we run this script (by clicking the Run Once button near the bottom/middle of the screen) and then navigate over to our table in the Data tab, we’ll see the row in the table:
The nice part about this, too, is that it did a good job of figuring out the column types:
However, we could go into the database itself and change the column definition if we wanted to. We’ll wrap up the post here to keep this from becoming a book, but in the next post we’ll dive a bit deeper into consuming the live feed and storing that in the database.

Abstract: In Part 4 of of their “Using Windows Azure to Build Back-End Services for Windows 8 apps” series Peter Laudati, Brian Hitney and Andrew Duthie show us how to build the same game leaderboard service on top of Windows Azure Mobile Services. Tune in as Andrew demos for us how to get started as well as lays out what some of the +/- are for using Azure Mobile Services for this kind of service. Check out the full article here. Watch Part 1 | Part 2 | Part 3 After watching this video, follow these next steps: Step #1 – Try Windows Azure: No cost. No obligation. 90-Day FREE trial. Step #2 – Download the Tools for Windows 8 App Development Step #3 – Start building your own Apps for Windows 8 Subscribe to our podcast via iTunes or RSS If you're interested in learning more about the products or solutions discussed in this episode, click on any of the below links for free, in-depth information: Register for our Windows Azure Hands-on Lab Online (HOLO) events today! Windows Azure Hands-on Labs Online Blogs: Brian Hitney’s blog Peter Laudati’s blog Andrew Duthie’s Blog Videos: Microsoft DevRadio: How to Get Started with Windows Azure Microsoft DevRadio: (Part 1) What is Windows Azure Web Sites? Microsoft DevRadio: (Part 2) Windows Azure Web Sites Explained Microsoft DevRadio: How to Integrate TFS Projects with Windows Azure Web Sites Virtual Labs: MSDN Virtual Labs: Windows Azure Download MP3 (Audio only) MP4 (iPod, Zune HD) High Quality MP4 (iPad, PC) Mid Quality MP4 (WP7, HTML5) High Quality WMV (PC, Xbox, MCE)