# Friday, September 21, 2018

FellowshipOfTheRingOn his eleventy-first birthday, hobbit Bilbo Baggins decided to leave Hobbiton. He did so in dramatic fashion, literally disappearing while giving a speech at his birthday party. Bilbo left most of his belongings to his nephew Frodo, including a magic ring he discovered on a journey years earlier.

Neither Bilbo nor Frodo nor the wizard Gandalf knew that the magic ring was cursed. It was created by the evil Sauron, who has returned to take over all of Middle Earth and who desires the ring's power, which will virtually guarantee his success. When Sauron's minions The Ring Wraiths arrive in the Shire seeking the ring, Frodo and his friends flee, traveling across Middle Earth to Rivendell - a city of elves, where Bilbo has been living. At Rivendell, the wise elves decide that the only way to prevent the ring from falling into Sauron's hands is to destroy it. Sadly, the only way to do this is to throw it into the fiery pits of Mount Doom, located far away in the Mordor - home to Sauron.

So, Frodo sets out for Mordor with his 3 hobbit friends, Gandalf, Gimli the Dwarf, Legolas the elf, and two men: Aragorn and Boromir. Along the way, this "fellowship" is beset by treacherous terrain, fierce monsters, and the betrayal of a friend.

The Fellowship of the Ring begins J.R.R. Tolkien's classic Lord of the Rings trilogy.

It takes place a few years after The Hobbit, in the same world with many of the same characters. But it is much darker in tone.

Tolkien is at his best when he is building a world. By the end of the story, we know the beings who populate Middle Earth, the lands in which they live, the languages they speak, and much of their history. Fellowship is an adventure story, but the action is often interrupted by detailed descriptions of the environment. Those who know the story only through Peter Jackson's excellent movie may be disappointed that the book does not advance as fast.

But the depth of detail provided by Tolkien more than makes up for any pacing issues. The reader feels that he knows this world and these characters and why the ring is so important.

I love Tolkien's writing style, which can be at turns ominous and humorous. At his birthday party speech, Bilbo announces: "I don’t know half of you half as well as I should like; and I like less than half of you half as well as you deserve.", which leaves his guests trying to figure out if this was a compliment.

He mixes in much poetry or songs with his work, some of which is quite good. The prophecy of the Ring is told with the following poem:

"All that is gold does not glitter,
Not all those who wander are lost;
The old that is strong does not wither,
Deep roots are not reached by the frost.
From the ashes a fire shall be woken,
A light from the shadows shall spring;
Renewed shall be blade that was broken,
The crownless again shall be king."

And some of Tolkien's writing just sounds epic in its prose: "One Ring to rule them all, One Ring to find them, One Ring to bring them all and in the darkness bind them."

Although listed as volume 1, this is not as much a first book in a trilogy as it is the first chapters in a very long novel, published in 3 volumes to make it easier to consume and market. You should read this volume knowing full well that it is not a complete story: You are committing to the entire series.

And a wonderful story it is.

Friday, September 21, 2018 1:54:00 PM (GMT Daylight Time, UTC+01:00)
# Thursday, September 20, 2018

GCast 14:

Creating an Azure Storage Account

Learn how to create a new Azure Storage account.

Azure | GCast | Screencast | Video
Thursday, September 20, 2018 9:58:00 AM (GMT Daylight Time, UTC+01:00)
# Wednesday, September 19, 2018

An Azure Function App is a good way to deploy code when you don't want the trouble of managing the server on which that code is running. But sometimes, you do want to do something on the server. One example I ran into recently was that I needed to install a node package (in my case, it was azure-storage) for a Function App I had deployed.

Azure provides a way to do this.

Navigate to the Azure Portal and open your Function App. Note the URL of the Function App, as shown in Fig. 1

Fig. 1

The URL takes the following form:


where functionappname is the name you assigned to the Azure Function App.

Open a new browser tab and navigate to the following URL:


where functionappname is the name you assigned to the Azure Function App.

The Kudu page displays as shown in Fig. 2

Fig. 2

Click the Debug console menu (Fig. 3) and click the CMD menu item (Fig. 4).

Fig. 3

Fig. 4

The debug console displays, as shown in Fig. 5

Fig. 5

By default, you should find yourself in the "D:\home" folder. Navigate to the D:\home\site\wwwroot folder, using the following commands as shown in Fig. 6.

cd site
cd wwwroot

Listing 1

Fig. 6

Here you can install node packages required by your functions.

To install azure-storage, I entered the following command:

npm install azure-storage

It took a minute or two for the package to install. But when it finished, my functions were able to use code in this package. 

Azure | node
Wednesday, September 19, 2018 9:47:00 AM (GMT Daylight Time, UTC+01:00)
# Tuesday, September 18, 2018

The Microsoft Bot framework provides the IBotDataStore interface as a mechanism for storing stateful data. When you create a new Bot in Visual Studio, your application is configured by default to store data in memory using the InMemoryDataStore class.

You can see this setup in the following line of the Application_Start() method of  Global.asax.cs :

var store = new InMemoryDataStore();

This is fine for testing, but memory is fragile and temporary; so, you will want a more persistent way to store stateful data in production. You can see this by running the app we created in this article.

If we run the bot described in that article, we can connect to it with the Bot Framework Emulator; then, stop and re-start the app and connect again, as shown in Fig. 1

Fig. 1

Notice that all the stateful information is reset after the app restarts, because the app memory is flushed.

We can modify the app so that it saves stateful data to something more persistent, like Azure Storage. To do this, we must first create a new Azure storage account.

In the Azure Portal, create a new Storage account (Fig. 2). If you have never created an Azure storage account, you can find instructions here.

Fig. 2

Once the account is created, open the "Access keys" blade, as shown in Fig. 3.

Fig. 3

Copy either of the connection strings and save it. You will need to add it to your application.

In the Bot application, open the web.config file and paste the following anywhere directly inside the <configuration> tag.

 <add name="BotAzureStorage" connectionString="StorageConnectionString" /> 

where StorageConnectionString is the connection string you copied from the Azure portal.

Open the Global.asax.cs file and find the following line:

var store = new InMemoryDataStore();

Replace this line with the following code:

var azureStorageConnectionString 
  = System.Configuration.ConfigurationManager.ConnectionStrings["BotAzureStorage"].ConnectionString; 
var store = new TableBotDataStore(azureStorageConnectionString);

Now, compile and run the application.

Use the Bot Emulator to connect to it. Stateful information will now be saved to a Microsoft Azure Storage table named "botdata".

Notice that as you start and stop the app, the stateful data remains the same, as shown in Fig. 4.

Fig. 4

In this article, I showed you how to save stateful data to an Azure Storage table.

You can find this code in the SavingStateToAzureDemo folder of the Bot-Framework-Demos on my GitHub page.  

Tuesday, September 18, 2018 9:34:00 AM (GMT Daylight Time, UTC+01:00)
# Monday, September 17, 2018
Monday, September 17, 2018 9:50:00 AM (GMT Daylight Time, UTC+01:00)
# Sunday, September 16, 2018
Altan2018-45 Altan2018-50
Altan2018-52       Altan2018-55

People filled every seat and stood in the back on the 4th floor of the Irish American Heritage Center in Chicago. Some were fans, some musicians, and some were just curious to see and hear Altan.

For over 30 years, Altan has been performing and recording traditional Celtic music and Thursday evening the quartet performed a free concert as part of the World Music Festival.

For over 2 hours, they delighted the audience with music and stories; originals and traditional folk songs; reels, jigs, and ballads.

Each of the musicians - Mairéad Ní Mhaonaigh (lead vocals and fiddle), Ciarán Curran (bouzouki), Dáithí Sproule (guitar and vocals), and Martin Tourish (accordion) - were masterful in their own right. But it was Ni Mhaonaigh who stole the show with her fiery fiddle playing and angelic voice.

The audience clapped along and some danced up the center aisle, Riverdance-style. By the end, we were all smiling. Those who did not know Altan and those who did not know this type of music and those who did not understand the Gaelic lyrics had been won over. And so had I. It may have been the Guinness served in the back of the room, but more likely it was the excellence of the musicians.

More photos

Sunday, September 16, 2018 9:23:00 AM (GMT Daylight Time, UTC+01:00)
# Saturday, September 15, 2018

IMG_2199Stereophonics are Kelly Jones, Richard Jones, Adam Zindani, and Jamie Morrison. But mostly Kelly Jones. Jones is the lead singer, front man, plays many guitar solos, and writes most of the band's music. This is not to say the rest of the band doesn't contribute. They provided excellent musicianship when the band took the stage at Chicago's Vic Theatre Tuesday night.

IMG_2237Tuesday night, thanks to my friend David, I got my first experience at the Vic and my first experience seeing Stereophonics.

Ramona's Flowers opened with a brief set, playing some solid melodies reminiscent of late 80s alternative rock.

IMG_2250But the theatre was full, and they came to see Stereophonics. The crowd did not just listen. They sang along to almost every song, making their voices heard above the amplification. From my vantage point near the stage, it sounded like Jones had brought a choral along to accompany him.  Stereophonics has a much larger following in the UK than in the US and I heard many British accents in the crowd.

The concert did not disappoint. From their high-energy opening "C'est La Vie" through their 6 encores, the crowd was on its feet most of the night.

IMG_2268They played original songs all night until the very end, when they closed with a rousing rendition of "Sweet Home Chicago", delighting the locals and immigrants in the audience alike.

It was a good experience for me and for the thousands of British expats who packed the theater.

Saturday, September 15, 2018 9:21:00 AM (GMT Daylight Time, UTC+01:00)
# Friday, September 14, 2018

A chatbot provides an electronic exchange between a user and a computer. For example, each exchange might consist of a question from the user and an answer from the computer or a question from the computer and an answer from the user.

As with most interactions that take place across the Internet, a chatbot is, by default, stateless - meaning it remembers nothing from one exchange to the next.

Often, we would like to remember answers from one question to the next or even from one conversation to the next. If the bot asks a person's name, that name could be used to respond to a question asked later in the same conversation; or even in a different conversation.

This is why we implement State in our bots.

There are two key issues when managing state:

  • What is the scope of the data?
  • Where is stateful information stored?

In this article, we will focus on the first question and store all state data in memory.

What is the scope of the data?

The first question we ask ourselves is: When we save the data, when and where will it be seen?

We have 3 options, corresponding to 3 properties of the context (IDialogContext Interface)

  • ConversationData. Data stored here is available to anyone within the current conversation.
  • PrivateConversationData. Data stored here is available to the current user within the current conversation.
  • UserData. Data stored here is available to the current user in any conversation. This means he/she can come back the next day and the bot will remember his/her data.

Each of the 3 options above is a property of the IDialogContext interface. The context object, which is passed into the MessageReceivedAsync, implements this interface, so we can read and write to the appropriate storage by reading and writing to objects stored in context.

Below is a simple example that reads to and writes from the three different storage options.

private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
	var message = await result;
	var channelId = message.ChannelId;
	var conversationId = message.Conversation.Id;
	var userId = message.From.Id;

	var currentTime = DateTime.Now;

	DateTime firstLoginTimeThisConversationAnyUser = DateTime.MinValue;

	context.ConversationData.TryGetValue<DateTime>("FirstLoginTime", out firstLoginTimeThisConversationAnyUser);
	if (firstLoginTimeThisConversationAnyUser == System.DateTime.MinValue)
		firstLoginTimeThisConversationAnyUser = System.DateTime.Now;
		context.ConversationData.SetValue<DateTime>("FirstLoginTime", firstLoginTimeThisConversationAnyUser);

	DateTime firstLoginTimeEverForCurrentUser = DateTime.MinValue;
	context.UserData.TryGetValue<DateTime>("FirstLoginTime", out firstLoginTimeEverForCurrentUser);
	if (firstLoginTimeEverForCurrentUser == System.DateTime.MinValue)
		firstLoginTimeEverForCurrentUser = currentTime;
		context.UserData.SetValue<DateTime>("FirstLoginTime", firstLoginTimeEverForCurrentUser);

	DateTime firstLoginTimeCurrentConversationCurrentUser = DateTime.MinValue;
	context.PrivateConversationData.TryGetValue<DateTime>("FirstLoginTime", out firstLoginTimeCurrentConversationCurrentUser);
	if (firstLoginTimeCurrentConversationCurrentUser == System.DateTime.MinValue)
		firstLoginTimeCurrentConversationCurrentUser = currentTime;
		context.PrivateConversationData.SetValue<DateTime>("FirstLoginTime", firstLoginTimeCurrentConversationCurrentUser);

	var output = $"User: {userId}\nConversation: {conversationId}\nChannel: {channelId}\n\n";
	output += $"A user logged into this converstaion at {firstLoginTimeThisConversationAnyUser}.\n";
	output += $"You first logged into any conversation at {firstLoginTimeEverForCurrentUser}.\n";
	output += $"You first logged into this conversation at {firstLoginTimeCurrentConversationCurrentUser}.";
	await context.PostAsync(output);


  Listing 1

Notice that we are checking each time to see if any new data is returned from a name-value pair ("FirstLoginTime"). If nothing is stored in a value, it will return DateTime.MinValue, which signifies an empty date. In this case, we set the value to the current time.

You can test this with the Bot Framework Emulator (available here and described here).

You can download a Visual Studio Solution that uses the code in Listing 1 from the SavingStateDemo of the Bot-Framework-Demos on my GitHub page.

Launch your bot from Visual Studio and connect to it with the Emulator. Type any message into the textbox and press [ENTER], as shown in Fig. 1.

Fig. 1

You should see information about the user, channel, and conversation; along with the value just stored for the when users (including you) logged into this (or another) conversation. Notice all 3 values are the same because this is your first conversation and you are the first user in this conversation.

Again, type any message in the textbox and press [ENTER]. The values have not changed because they were set as stateful data last time (Fig. 2)

Fig. 2

You can start a new conversation by clicking the ENPOINT on the left, opening a new tab. Type something into this tab's textbox and press [ENTER] (Fig. 3)

Fig. 3

Notice that the user is the same, but the Conversation ID is different.

Therefore, the bot updated the ConversationData and the PrivateConversationData values, but not the UserData value.

In this article, I showed you how to save stateful data from a conversation using the Microsoft Bot Framework.

Friday, September 14, 2018 9:42:00 AM (GMT Daylight Time, UTC+01:00)
# Thursday, September 13, 2018

GCast 13:

Azure Media Services: Closed Captioning

Generate and add closed captioning to your video with Microsoft Azure Media Services.

Thursday, September 13, 2018 7:11:00 AM (GMT Daylight Time, UTC+01:00)
# Wednesday, September 12, 2018

In the previous articles, I showed how to create a new chatbot using the Microsoft Bot Framework and I explained the relevant code in the sample chatbot you created.

In this article, I will show how to extend your bot by adding a new dialog.

Launch Visual Studio and create a new project based on the "Bot Builder Echo Bot", as shown in Fig. 1

Fig. 1

From the Visual Studio menu, select Build | Rebuild Solution.

In the Visual Studio Solution Explorer, right-click the "Dialogs" folder and select Add | Class from the context menu, as shown in Fig. 2.

Fig. 2

A dialog displays, allowing you to name and add a new class, as shown in Fig. 4.

Fig. 3

Enter a name for this dialog class. I chose "TimeDialog.cs", because I plan to add code to display the current time. Click the [Add] button to create this class.

An editor with the default code in it displays. The default code is in Listing 1.

namespace MyBotWithDialog.Dialogs
    public class TimeDialog

Listing 1

Above the class declaration, add the [Serializable] tag.

After the class name, add the following to derive from the IDialog interface.

: IDialog<object>

The IDialog interface requires one method: StartAsync. Add this method as shown in Listing 2.

        public Task StartAsync(IDialogContext context)

            return Task.CompletedTask;

Listing 2

Notice that StartAsync asynchronously calls MessageReceivedAsync, so you will have to add this method, as shown in Listing 3.

        private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
            var activity = await result as Activity;

            // Calculate something for us to return
            int length = (activity.Text ?? string.Empty).Length;

            // Return our reply to the user
            await context.PostAsync($"The time is now {System.DateTime.Now}!");


Listing 3

Note that the output sent back to the channel is a string containing the current time.

Finally, you will need to add using statements at the top to resolve any errors. Add the following to the top of the file.

using Microsoft.Bot.Builder.Dialogs;

using Microsoft.Bot.Connector;

Listing 4

When you are finished, the class should look like Listing 5 below.

using System;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;

namespace MyBotWithDialog.Dialogs
    public class RootDialog : IDialog<object>
        public Task StartAsync(IDialogContext context)

            return Task.CompletedTask;

        private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
            var activity = await result as Activity;

            // Calculate something for us to return
            int length = (activity.Text ?? string.Empty).Length;

            // Return our reply to the user
            await context.PostAsync($"The current time is {System.DateTime.Now}!");


Listing 5

Next, modify the controller to point to your new Dialog. Open MessageController.cs and find the following line of code.

await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());

Replace this line with the following:

await Conversation.SendAsync(activity, () => new Dialogs.TimeDialog());

Now, build and run your bot. When it loads, use the Bot Framework Emulator (available here and described here) to test it.

Connect to your Bot from the Emulator and enter any text in the "Type your message" textbox and press ENTER.

The bot should respond by displaying the current date and time, as shown in Fig. 3.

Fig. 4

In this article, I showed how to create and use a new Dialog class to an Bot Builder Echo Bot project. You can find this code in the NewDialogDemo of the Bot-Framework-Demos on my GitHub page.

Wednesday, September 12, 2018 9:41:00 AM (GMT Daylight Time, UTC+01:00)