In the last article, I showed how to create an Azure Function App. A Function App is not useful by itself: it is just a container for functions, which perform the real work.

Once you have created an Azure Function App, you will want to add one or more Functions to it.

Navigate to the Azure Portal, log in, and open your Function app, as shown in Fig. 1.

Fu01-FunctionApp
Fig. 1

Click either the [+] icon next to the "Functions" section on the left (Fig. 2) or the [New function] button at the bottom (Fig. 3)

Fu02-NewFunctionIcon
Fig. 2

Fu03-NewFunctionButton
Fig. 3

NOTE: If this Function App already contains at least one function, the [New function] button does not display.

The "CHOOSE A DEVELOPMENT ENVIRONMENT" page of the "Azure Functions for .NET - getting started" dialog displays, as shown in Fig. 4

Fu04-ChooseDevEnv
Fig. 4

Select the [In-portal] tile and click the [Continue] button to advance to the "CREATE A FUNCTION" page, as shown in Fig. 5

Fu05-CreateAFunction
Fig. 5

Two triggers are listed: "Webhook+API", which will cause your function to execute after a web service URL is hit; and "Timer", which allows you to schedule your function to run at regular intervals. You can see more triggers by clicking the "More templates…" tile; but, for this demo, select the [Webhook+API] tile and click the [Create] button. After a few seconds, a function is created with an HTTP trigger and some sample code, as shown in Fig. 6.

Fu06-NewFunction
Fig. 6

This sample function accepts a "name" parameter (either in the querystring or in the Body of a POST request) and returns an HTTP 200 (OK) response with the string "Hello, ", followed by the value of the name parameter. If no "name" parameter is supplied,  it returns a 400 (Bad Request) response with an error message.

You can now modify and save this code as you like.

In the next article, I will show you how to test this function within the portal.


An Azure Function allows you to deploy scalable code to the cloud without worrying about the server or other infrastructure issues.

Azure Functions are contained within a Function App, so you need to create a Function App first.  To create a Function App, navigate to the Azure Portal, sign in and click the [Create a resource] button, as shown in Fig. 1.

FA01-CreateAResource
Fig. 1

From the menu, select Compute | Function App, as shown in Fig. 2.

FA02-ComputeFunctionApp
Fig. 2

The "Create Function App" blade displays as shown in Fig. 3

FA03-CreateFunctionAppBlade
Fig. 3

At the "App Name" field, enter a unique name for your Function App.

At the "Subscription" field, select the Azure subscription with which to associate this Function App. Most people will have only one subscription.

At the "Resource Group" field, select "Create new" and enter the name of a Resource Group to create or select "Use existing" and select an existing resource group in which to store your Function App. A Resource Group is an organizational grouping of related assets in Azure.

At the "OS" radio button, select the operating system (Windows or Linux) on which you wish to host your Function App.

At the Hosting plan, select either "Consumption Plan" or "App Service Plan". With the Consumption Plan, you only pay for the time that your functions are running. Since most functions do not run 24 hours a day / 7 days a week, this can be a real cost savings. With the App Service Plan, you pay as long as your functions are available. This is appropriate if you expect clients to be constantly calling your functions.

At the "Location" field, enter a region in which you want your Functions to run. In order to minimize latency, you should select a region close to any resources with which the Functions will interact.

At the "Runtime Stack" dropdown, select one of the platforms. Select ".NET" if you plan to write your code in C# or F#. Select "JavaScript" if you plan to create a node function. Select "Java" if you plan to write your code in Java. As of this writing, Java is in Preview, so performance is not guaranteed.

If you selected "Consumption Plan" hosting plan, you will be prompted for a storage account. Function definitions will be stored in this account. Select an existing storage account or create a new one. I prefer to use a storage account for all my Function Apps in a given Resource Group.

For extra monitoring, turn on Application Insights and select the same region in which your Function App is located. If this region is not available, select a nearby region.

Click the [Create] button to create your Function App.

After your Function App is created, you will want to add a Function to it. I will show how to do this in the next article.


Robert Greene on DevOps

Comments [0]

Episode 537

Robert Greene on DevOps

Robert Greene defines DevOps, discusses its advantages, and describes how to accomplish it with Microsoft tooling.


FrankensteinFrankenstein is the story of Victor Frankenstein, a scientist who discovers a way to re-animate dead tissue and uses this knowledge to build a giant, grotesque creature. Victor is repulsed by his creation and rejects it, which angers the creature and inspires him to seek revenge on his creator by destroying those closest to him.

The story of Frankenstein is familiar to almost everyone - primarily through the 1931 movie and the works that it inspired. But the original novel by Mary Wollstonecraft Shelley, published in 1818 offers much that later interpretations do not.

The novel differs from most later interpretations of the story by how much is given to the creature displays complex feelings and motivations. Unlike Karloff's mute, shuffling monstrosity, Shelley's monster was self-educated, literate, and articulate. He feels the betrayal of his maker and the pain of rejection by the world. He takes out this pain by destroying everyone that Victor loves.

In this classic horror novel, Shelley explores the dangers of playing God, the power of loneliness, and the fear of losing all that we love. She even brings in the responsibilities that fathers have for their children - a topic at least as relevant today as it was 200 years ago. Victor Frankenstein is the ultimate deadbeat dad. he runs from his responsibilities, abandoning his offspring when needed most.

There are two evil creatures in this book. Victor shirks his responsibilities and abandons the creature he created, primarily because of its physical deformities. The monster dreamed of love and acceptance; but turned to evil and violence and revenge when he was rejected by his creator and by the world.

Mary Shelley was a pioneer in the science fiction and the horror genres and the longevity of "Frankenstein" is a testament to this standing.


JeffLorberIt took 40 years of recording for Jeff Lorber to finally win a Grammy. After 6 times a bridesmaid,
"Prototype" by The Jeff Lorber Fusion won the award for Best Contemporary Instrumental Album this January.

And it took just as long for me to finally see The Jeff Lorber Fusion in concert, which I did Wednesday night at The Promontory in Chicago's Hyde Park.

Reserved seating was listed as "Sold Out" but I managed to get a seat at a table, thanks to someone canceling and me showing up an hour before the doors opened.

The concert was a fundraiser for the Musical Arts Institute, so the evening began with performances by a number of members and students of the institute. It was entertaining half hour of music, but the performers definitely amateurs - many of them in their teens.

Not so with the main act. Jeff Lorber is as professional as they come, and he brought technical proficiency with high energy jazz fusion throughout his set.

Lorber played with a trio that included two local Chicagoans, including bassist Michael Manson (director of the Musical Arts Institute), who nearly stole the show with his amazing playing and a face that morphed like a jellyfish.

But it was Jeff Lorber's show and he did not disappoint. The energy remained high throughout the night and every song was great. Highlights included "What's the Deal" and "Test Drive" from his Grammy-winning album; "Montserrat" from "Galaxy"; and "Rain Dance", a song that has been sampled by multiple artists, including Notorious B.I.G., Ariana Grande, Ja Rule, and Mariah Carey.  I don't recall any ballads during the show.

The trio did not play a long set - perhaps 90 minutes - but the audience left feeling we got our money's worth.

Photos


Azure Functions provide a simple way to deploy code in a scalable, cost-effective way.

The beauty of Azure functions is that the developer does not need to worry about where they are deployed. Azure takes care of spinning up a server and other resources at the appropriate time and scaling out a Function as demand increases. The infrastructure is abstracted away from the developer allowing the developer to focus on the code and the business problem.

Azure functions can be written in C#, F#, JavaScript, or Java.

Each Function has a "Trigger" which, as the name implies is an event that causes the function code to run. This can be an HTTP request, a message on a queue or message bus, delivery of an email, data inserted into a blob storage container or CosmosDB database, or a timed interval.

Triggers are just one way that Azure functions can easily connect to other services. There are also bindings available to interact with databases, queues, and other services with a minimum of code.

One nice feature of Azure Function Apps is the "Consumption Plan" pricing model. Selecting this plan means that you are only charged while your function is running, which can save plenty of money - particularly if your app is not running 24 hours a day every day. Of course, you can also choose to run your function as part of an App Service Plan, in which case you will pay for the entire time the function is available, whether or not it is running. This may be desirable if you already have an App Service Plan running and want to include your functions in that same plan.

You can create functions directly in the Azure Portal. Or you can create them locally using tools like Visual Studio and Visual Code and deploy them either directly from the IDE or through your continuous integration processes.

The source code for the Azure Functions run-time is even open source! Check out the code at https://github.com/Azure/azure-functions-host.

You can get a free Azure account at http://azure.com. You can read more about Azure functions at https://docs.microsoft.com/en-us/azure/azure-functions.

In upcoming articles, I'll show you how to create, deploy, test, and manage Azure functions.


GCast 21:

Azure Functions Continuous Deployment

Learn how to configure continuous deployment from GitHub to Azure functions. Each time you push code changes to GitHub, that code is automatically deployed to Azure.


In the last article, I showed how to create a new Azure CosmosDB account. In this article, I will show how to add a database with containers to that account.

Navigate to the Azure portal and sign in; then open your Azure CosmosDB account. You may be directed to either the "Quick start" blade (Fig. 1) or the "Overview" blade (Fig. 2)

Co01-CosmosDBAccountQuickStart
Fig. 1

Co02-CosmosDBAccountOverview
Fig. 2

Open the "Data Explorer" blade, as shown in Fig. 3.

Co03-CosmosDBAccountDataExplorer
Fig. 3

For a newly-created account, no databases are listed.

To create a new database, click the [New Database] button (Fig. 4).

Co04-NewDatabaseButton
Fig. 4

The "New Database" blade displays, as shown in Fig. 5.

Co05-NewDatabaseBlade
Fig. 5

At the "Database id" field, enter a unique id for your database.

Click the [OK] button.

After a few seconds, a new database will display in the "Data Explorer" blade, as shown in Fig. 6.

Co06-Database
Fig. 6

In a CosmosDB database, documents are stored within collections, which help you to organize your data. To create  a new collection, right-click the database and select "New Collection" from the context menu, as shown in Fig. 7

Co07-NewCollectionMenu
Fig. 7

The "Add Collection" blade displays, as shown in Fig. 8

Co08-AddCollectionBlade
Fig. 8

At the "Collection Id" field, enter a name for your collection. Collection names must be unique within a database.

Select the appropriate Storage capacity. If you expect to store a small amount of data, select "Fixed"; for databases expected to grow beyond 10GB, select "Unlimited".

If you select unlimited, you can specify a path within each document to find the Partition Key. A Partition Key is used to determine which data to keep together when distributing data across multiple servers.

At the "Throughput" field, enter the number of 1K documents per second you need to process. You will pay more for higher throughput, so consider whether you need a higher throughput before increasing this value.

Click the [OK] button to create the collection.

The new collection will display beneath the database as shown in Fig. 9. You may need to expand the tree in order to see the collection.

Co09-DBandCollection
Fig. 9

You can write to and read from this collection programmatically or you can upload document within the portal by clicking the [Upload] button, as shown in Fig. 10.

Co10-UploadButton
Fig. 10

Data in a CosmosDB account is stored in databases and collections. This article showed how to create these.


Azure CosmosDB is a flexible, fast, reliable, scalable, geographically distributed NoSQL database.

You can create a CosmosDB account and database in the Azure poral.

Navigate to the Azure portal and login.

Click the [Create a resource] button, as shown in Fig. 1.

CDB01-CreateResourceButton
Fig. 1

From the menu, select Database | Azure CosmosDB, as shown in Fig. 2.

CDB01-DatabaseCosmosDb
Fig. 2

The "Create Azure CosmosDB Account" blade displays, as shown in Fig. 3.

CDB03-CreateAzureCosmosDbAccount
Fig. 3

At the Subscription dropdown, select your Azure subscription. Most of you will have only one subscription.

At the Resource Group dropdown, select an existing resource group or click "Create new" to display the New Resource Group dialog, as shown in Fig. 4.

CDB04-CreateResourceGroup
Fig. 4

In the New Resource Group dialog, enter a unique name for your resource group and click the [OK] button.

At the "API" dropdown, select the API you want to use to access the databases in this account, as shown in Fig. 5.  Options are

  • Core (SQL)
  • MongoDB
  • Cassandra
  • Azure Table
  • Gremlin (graph)

CDB05-Api
Fig. 5

If you are migrating data from another database, you may want to choose the API that resembles your old database in order to minimize changes to the client code accessing the database. If this is a new database, you may wish to choose the API with which you and your team are most familiar.

At the "Location" dropdown, select a region in which to store your data. It is a good idea to keep your data near your users and/or near any services that will interact with your data.

The "Geo-Redundancy" and "Multi-region writes" options allow you to globally distribute your data. There is an extra charge for enabling these features.

You can enable Geo-Redundancy by clicking the [Enable] button next to "Geo-Redundancy". This creates a copy of your data in another nearby region and keeps that data in sync.

Click the [Enable] button next to "Multi-region writes" if you wish to allow data to be written in multiple regions. This will improve the performance when writing data to the database.

Notice the tabs at the top of the page (Fig. 5). The "Basics" tab displays first, but the "Network", "Tags", and "Summary" tabs are also available.

CDB06-Tabs
Fig. 6

The "Network" tab (Fig. 7) allows you to add your CosmosDB account to a specific Virtual Network and Subnet. This is not required.

CDB07-NetworkTab
Fig. 7

The "Tags" tab (Fig. 8) allows you to assign metadata to this CosmosDB account, which may help when grouping together related accounts on a report. This is not required.

CDB08-TagsTab
Fig. 8

The "Summary" tab (Fig. 9) displays all the options you have chosen and validates that you completed the required responses and that all responses are consistent. You can navigate to this tab by clicking the "Summary" tab link at the top or by clicking the [Review + create] button on any other tab.

CDB09-SummaryTab
Fig. 9

Click the [Create] button to begin creating your CosmosDB account. This will take a few minutes. A message displays as shown in Fig. 10 when the account is created and deployed.

CDB10-DeploymentComplete
Fig. 10

As you can see, there are a number of links to documentation and tutorials.

Click the [Go to resource] button to open the CosmosDB account. By default, the "Quick start" blade displays, as shown in Fig. 11.

CDB11-CosmosDBQuickStartPage
Fig. 11

In this article, I showed how to create a new Azure CosmosDB account. In the next article, I will show how to add a database with containers to that account.


Hao Luo on Rust

Comments [0]

Episode 536

Hao Luo on Rust

Hao Luo talks about the Rust programming language, how it works, and how he is using it.


October 2018 Gratitudes

Comments [0]

11/4
Today I am grateful for my first visit to Montreal in almost 12 years.

11/3
Today I am grateful to visit St. Ours, Quebec yesterday - home of some of my ancestors.

11/2
Today I am grateful for Montreal smoked meats and poutine.

11/1
Today I am grateful for dinner last night at a rotating Portuguese restaurant high above Montreal with Brent, LaBrina, and Sarah.

10/31
Today I am grateful to attend my first home Montreal Canadiens game yesterday.

10/30
Today I am grateful for dinner with Nick last night.

10/29
Today I am grateful to attend an exciting Red Wings victory at Little Caesars Arena last night.

10/28
Today I am grateful to be my nephew Sterling's sponsor for his confirmation last night.

10/27
Today I am grateful for dinner last night with Esteban.

10/26
Today I am grateful for a week in Dallas.

10/25
Today I am grateful for dinner last night with Tristan, Joe, Timothy, Sergii, Danny, Denis, and Ashley.

10/24
Today I am grateful to attend a Dallas Stars home game for the first time.

10/23
Today I am grateful for dinner last night with Amanda, Timothy, and Sergii.

10/22
Today I am grateful for Texas BBQ.

10/21
Today I am grateful for all the good restaurants in Chicago.

10/20
Today I am grateful to wake up to this view every morning.

10/19
Today I am grateful for free pound cake and ice cream at the Grand Opening of a local bakery yesterday.

10/18
Today I am grateful for the colors of autumn.

10/17
Today I am grateful for a hot bath last night.

10/16
Today I am grateful for dinner with Corey last night.

10/15
Today I am grateful for dinner with Ryan last night, where I was able to introduce him to his first Chicago-style hot dog.

10/14
Today I am grateful that, after 5 years, 3 roles, and 5 managers, I still enjoy working at Microsoft.

10/13
Today I am grateful for an empty seat next to me on my flights to and from Seattle.

10/12
Today I am grateful for the DJ playing so much non-American music at last night's party.

10/11
Today I am grateful to Brent for bringing to Seattle homemade BBQ to share with us.

10/10
Today I am grateful to learn from my teammates.

10/9
Today I am grateful for dinner last night in downtown Seattle with Brent, Carl, and Michael.

10/8
Today I am grateful to meet Richard for a drink last night.

10/7
Today I am grateful that, for the first time in my life, I have hired someone to clean my home twice a month.


"I, Robot" by Isaac Asimov

Comments [0]
  1. A robot may not injure a human being or, through inaction, allow a human being to come to harm.
  2. A robot must obey the orders given it by human beings except where such orders would conflict with the First Law.
  3. A robot must protect its own existence as long as such protection does not conflict with the First or Second Laws.

These are the 3 laws of robotics. They are built into the core technology of a robot's positronic brain and no robot may violate them. All robotic technology is built on top of these laws, ensuring that robots will be safe.

In the 1940s, Isaac Asimov wrote a series of stories speculating on the future evolution of robots and, in 1950, he compiled them into a single volume titled I, Robot. Although only loosely connected, most of the stories include Dr. Susan Calvin, a  Robopsychologist at U.S. Robotics, the only company able to manufacture these machines.

IRobotMany of the stories in this book revolve around the 3 laws - particularly exploring what happens when the laws come into conflict or when an ambiguous situation makes it difficult for a robot to interpret and apply the laws. The greater the conflict, the more stress placed on a positronic brain, which is why robots need a psychologist and humans need Susan Calvin to help them understand robots.

These stories launched a series of very good Robot novels for Asimov, who eventually tied the universe in which his robots existed into his Empire and Foundation series. Asimov's robots and the Robotics Laws influenced many other books and movies featuring mechanical men; and even influenced the real world field of robotics, as his three laws are often brought up when discussing the ethics of the technology. In fact, the term "robotics" was invented by Asimov and first appeared in a story in this collection.

I, Robot succeeds because it is based on plausible scientific principles and because it raises questions that science would be likely to encounter as it advances. There are no strong characters throughout the series (Calvin is a minor character in most of them), but the story and the ethical questions carry them along well.

My favourite story is "Liar", which is about a robot that gains the ability to read minds and uses this power to do what he believes will bring no harm to humans. It is a parable of the result of good intentions wrongly applied.

I, Robot is a reminder that advancing technology brings with it ethical choices and questions. Any fan of science fiction will enjoy it.


Sometimes, you want to store quotation marks within a string, as in the following example

"Alive", she cried!

In C#, there are at least 4 ways to embed a quote within a string:

  1. Escape quote with a backslash
  2. Precede string with @ and use double quotes
  3. Use the corresponding ASCII character
  4. Use the Hexadecimal Unicode character

Escape with backslash

You can precede any escaped character with a backslash ("\") to preserve that character.

For example:

var lyrics = "\"Alive\", she cried!"
  

Precede with @ and use double quotes

If you precede the string with the "@" character, you can use a double set of quotation marks to indicate a single set of quotation marks within a string.

For example:

var lyrics = @"""Alive"", she cried!"
  

Use the ASCII character

A double quote is the ASCII value 34, so you can append this to your string.

For example:

quote = (char)34 + "Alive" + (char)34 + ", she cried!";
  

Use the Hexadecimal Unicode character

You can escape Unicode characters by preceding the hexadecimal value with "\u". The hexadecimal value of a double quote is 0022, so you can include this in your string.

For example:

quote = "\u0022Alive\u0022, she cried!";
  

These techniques work for many other characters that are difficult to represent within quotation marks, such as line feeds, non-English characters, and non-printing characters.

There are other ways to include quotation marks within a C# string, but these should be enough to get you started.


Episode 535

Rajasa Savant on Serverless Azure

Microsoft Engineer Rajasa Savant describes the "Serverless" technologies available in Microsoft Azure


SecondFoundationSecond Foundation concludes Isaac Asimov's classic Foundation Trilogy

The Mule has taken over much of the galaxy defeating The Foundation and establishing his own empire through the use of his powerful mutant mental powers. He has spent years searching for the hidden Second Foundation established by the psychohistorian Hari Seldon centuries earlier, correctly assuming it is the only viable threat to his reign. But the Second Foundation finds him before he can find it and they have similar - if less powerful mental powers.

The Mule cannot last forever, and he leaves no heir (which is why he is "The Mule"), but he did leave Seldon's plan in shambles by so drastically altering the history of the universe in an unpredictable way.

The second half of this book chronicles the Second Foundation's efforts to rebuild Seldon's plan and set the galaxy back on a path toward a second galactic empire. It features a war between The Mule's successors and the remnants of The Foundation and The Foundation's quest to locate the Second Foundation.

Asimov uses his talent for misdirection multiple times in this book, guiding the reader toward one conclusion and then another, before revealing the true answer. He does this most when identifying who is with the Second Foundation and where it is located.

This volume brings to the fore a theme that lurked under the surface of the first two books: The people of the Foundation know that Seldon's plan almost guarantees their success. They have almost a religious faith in their eventual victory. This helps boost morale during the war, but hinders them as they work to overcome other obstacles. They know that the actions of individuals are insignificant in Seldon's plan and that Seldon's plan predicts their ultimate triumph. So how much effort need they put forth in accomplishing the inevitable? They hold these beliefs even after the disruption of the plan by the actions of the Mule.

One thing that appealed to me about this series is that the principles of using large amounts of data to do predictive analysis has become a huge field of study today. Machine Learning and Big Data are fields that existed since the days of Asimov, but now that cloud computing provides massive compute power at affordable prices, these sciences have gained both power and interest.  Asimov foresaw this 50 years ago.

Later in his life, Asimov returned to writing about the Foundation; but this trilogy began the ideas and remains one of his strongest work. It is well worth reading.


WarOfTheWorldsIt is impossible to overstate the impact The War of the Worlds by H.G. Wells had on science fiction. First published in 1897, this book broke new ground in science fiction - a genre still very much undefined at that time.

An alien invasion; monstrous creatures driving giant machines with long tentacles; weapons that blast an incinerating heat ray. These are now science fiction clichés. But they were original in the nineteenth century.

The War of the Worlds tells the story of a Martian invasion of Earth. Giant cylinders crash into England and strange creatures emerge. They climb into giant armored machines and begin to terrorize London and the surrounding area, killing people and destroying the cities. Although England was a world power at that time, it was no match for the weapons of the Martians. It isn't long before England's existing civilization is wiped out and humans are in hiding from their new overlords.

War of the Worlds is an adventure story, told by an unnamed narrator as he flees the invading monsters. The narrator does not save humanity. He simply observes and reports.

Wells was himself a scientist and he injects a great deal of science into his story - from how evolution affected the appearance of the Martians to how natural selection controls which alien plants survive on Earth and for how long to how gravity would affect the aliens. Even the final fate of the Martians is based in science.

This book is also a morality story. Wells repeatedly uses the analogy that the relationship of Martians to Earth Men is similar to our relationship with the animals of our planet, which we slaughter for food without thinking twice. He refers to us as ants to the Martians, thanks to their enormous head start in evolution, civilization, and technology. More poignantly, Wells compares the Martians' treatment of the British subjects to Britain's treatment of other people in its quest to expand its empire.

Read The War of the Worlds if you want to understand where much of today's science fiction originated.




MartianChroniclesThe Martian Chronicles - Bradbury's first science fiction novel - is less a novel than a collection of short stories. Each story has a different tone and very few characters appear in more than one story; but, they are tied together by presenting a chronological history of man's attempted colonization and terraforming of Mars in the near future.

Bradbury's stories have endured because he humanizes the astronauts and the Martians - showing us their hopes and their flaws. Early explorers discover that Mars is populated by a race not dissimilar to their own: They are humanoid in shape and they live in cities and houses and they marry and have children. They even possess some of the flaws of their Terran counterparts. The first astronauts are killed by jealous husbands or by those who think them delusional for claiming to come from another planet; or by those looking to protect their home world.

But the Martians are not like the Earth men. They are telepathic, and they are far less excited about contact with their sister world.

Earth people came to Mars for adventure, for love, for land, for freedom. One came to exact revenge on those who had burned books on Earth - a precursor to Bradbury's second novel - Fahrenheit 451.

Eventually, rockets from Earth swarm toward Mars, and the invaders try to re-shape the red planet into the world they left behind. The Martians are all but wiped out by the diseases brought by the intruders.

But, just as the encroachers begin to take hold of Mars, a worldwide nuclear war erupts on Earth, halting the immigration, and drawing most of the settlers back home.

It's not hard to see the parallels between earth's colonization of Mars and European colonization or America conquering the western frontier.  The Martian civilization lasted for thousands of years before it was wiped out by us. Earth's replacement civilization lasted about a quarter century. Bradbury has a talent for building into his stories allegories about race and imperialism and the Cold War and Nuclear War and Family values and cultural clashes and the dangers of rapid technological advancement.

Despite an optimistic final story, The Martian Chronicles is a warning of man's callous, careless, reckless, and self-destructive nature.

As one disillusioned astronaut puts it:

"We Earth Men have a talent for ruining big, beautiful things. The only reason we didn't set up hot-dog stands in the midst of the Egyptian temple of Karnak is because it was out of the way and served no large commercial purpose."


FoundationAndEmpireFoundation and Empire is the second book in Isaac Asimov's classic Foundation Trilogy, advancing the story of The Foundation - the civilization founded by Psychohistorian Hari Seldon in order to mitigate the collapse of the galactic empire and shorten the thousands of years of anarchy he foresaw following.

The book is divided into 2 stories: "The General" and "The Mule". Story 1 is interesting but unremarkable.

"The General" details a power struggle between the galactic emperor and Bel Riose - one of his generals. It is hundreds of years after Seldon's death and the  empire has all but collapsed, as he predicted. Riose believes he can thwart Seldon's plan by attacking the Foundation. But he is only one man and Seldon's plan relies on the collective actions of the quintillions of people in the galaxy being more influential than anything that one man can accomplish. In the context of history, it does not matter what individuals do. The universe will move forward regardless. This is a basic assumption of psychohistory.

However, the that assumption falls apart in the second half of the book.

In the second story, we are introduced to The Mule, a powerful mutant born with the ability to control minds. His powers are so strong that he can affect galactic history by himself. This disrupts Seldon's master plan and allows The Mule to begin conquering the galaxy for himself.

The Foundation falls to The Mule; but, when the Mule learns that Seldon established a Second Foundation at the other end of the galaxy, he sets out to find and destroy it. Meanwhile, Foundation loyalists also seek the location of the Second Foundation, so they can warn it about the Mule.

I like how the two stories conflicted with one another. On the surface, they are only slightly related and separated by hundreds of years, but they show both the strength and weakness of math, science, and statistics. The first demonstrates how meaningless a single person, no matter how powerful or how ambitious, can affect a galaxy with quadrillions of people. The second shows exactly the opposite. The Mule's power is strong enough that he disrupts Seldon's entire plan. Further, The Mule's plans are thwarted by a single person.

It is this contradiction that makes Asimov's story so compelling. He takes us in one direction and makes us feel comfortable; then destroys all our assumptions.




AnimalFarmMr.  Jones was a lazy drunk and exploited the animals at Manor Farm. So, the animals, inspired by an eloquent speech by the aging and respected pig Old Major, decide to drive out Jones and take over the farm for themselves. They establish a new government, based on seven commandments of "Animalism", written on the side of the barn, that purport to protect the rights of the animals. 

It isn't long before animals are vying for power and exploiting that power once they have obtained it. The pigs are the most clever, so they take control, and end up revising each commandment to their advantage, grabbing more authority for themselves and becoming more and more like Mr. Jones and other human farmers as time goes on.

The other animals eventually find themselves as oppressed by their new pig overlords as they were by their former human masters. After numerous lies, deceptions, and thievery, the pigs modify the final commandment from "All animals are equal" to "All animals are equal, but some are more equal than others". The citizens of animal farm realize too late that they have traded one master for another equally bad one.

Animal Farm is George Orwell's first great work of fiction and it endures over 70 years after its initial publication. Orwell originally wrote the story as an allegory about the Russian Revolution and how Stalin eventually twisted its goals to his own ends; but Animal Farm is ultimately about how absolute power corrupts absolutely and this lesson can be found in any part of the world or political spectrum.

Napoleon the dictator pig uses many strategies to maintain control - from repeating lies that draw his enemies in an unfavorable light to using violence to suppress any voices. It's frightening how much these tactics are still used successfully today.

Orwell followed up Animal Farm with his classic 1984, another dystopian novel with a similar theme about the corruption of power; but Animal Farm does so more subtly, without the need for a closing speech to explain the methods and motivations of the ruling class. Animal Farm is shorter, but more imaginative than the later work. Animal Farm is a simple fable with a simple plot packed with symbolism. The characters are based on real figures of Soviet Russia (Old Major = Karl Marx; Snowball = Leon Trotsky; Napoleon = Joseph Stalin; Mr. Jones = Tsar Nicholas II), but the story works even if the reader is unfamiliar with that history.


TheHobbitBilbo the Hobbit was content with his life in the Shire when the wizard Gandalf showed up with 13 dwarves, who were told that Bilbo was an experienced burglar and would join them on a dangerous journey to steal back a treasure from evil dragon Smaug.

Bilbo had his reservations, but he also had a wanderlust that overcame his desire for comfort; so, he agreed to join the dwarves on their adventure. They set out across Middle Earth, battling man-eating trolls and man-eating dwarves and man-eating giant spiders before confronting the man-eating dragon surrounded by his mountain of treasure, stolen from the nearby towns he terrorized and destroyed.

The Hobbit by J.R.R. Tolkien is a delightful fairy tale of an odyssey across a magical world filled with fascinating creatures. It is a charming story in its own right, but its greatest contribution is that it introduced us to the world of Middle Earth, a mythical land that later became the setting of Tolkien's classic Lord of the Rings trilogy.

The Hobbit is much lighter than the later trilogy and can be read to and by most children. Yes, there are life-threatening dangers, but many of these are a bit silly and the party often overcomes them in humorous ways.

The story and characters of The Hobbit have become so familiar to us, that one might expect this story would become tiresome. But Tolkien never allows this. He brings us on a remarkable journey with Bilbo, where our hero is transformed from an ordinary Hobbit to an extraordinary hero.

Bilbo is short and chubby and enjoys his breakfast and his pipe far more than adventure. Yet, time and again, it is Bilbo who saves his companions from certain death. Gandalf recognizes Bilbo's potential early and puts him in a position to fulfill his destiny. Ultimately, it is the story of self-discovery for the hobbit.

Count me among the many fans of The Hobbit. I enjoyed the story thirty years ago when I first encountered it. And I enjoyed it again this week. It is not a complex tale, but it has been a source of delight for readers of all ages for generations.




September 2018 Gratitudes

Comments [0]

10/7
Today I am grateful that, for the first time in my life, I have hired someone to clean my home twice a month.

10/6
Today I am grateful to watch last night's thunderstorms from my balcony.

10/5
Today I am grateful for a free flu shot yesterday.

10/4
Today I am grateful to see Jo Ann Dougherty Trio and Bruce Henry at Winter’s Jazz Club - my first visit to this venue.

10/3
Today I am grateful for my new Bluetooth speaker - a gift I received from Tristan last week.

10/2
Today I am grateful that it's October in Chicago and the weather is still nice enough for a long bike ride.

10/1
Today I am grateful I live within walking distance of my church.

9/30
Today I am grateful to celebrate the wedding of Andrew and Lisa last night.

9/29
Today I am grateful to attend the Microsoft Ignite conference this week.

9/28
Today I am grateful to visit Universal Studios theme park last night.

9/27
Today I am grateful to Brian for saving us a table at the restaurant last night.

9/26
Today I am grateful for dinner and drinks last night with folks from Pearson.

9/25
Today I am grateful to re-connect with old friends yesterday.

9/24
Today I am grateful I was asked to be a sponsor for my nephew's confirmation next month.

9/23
Today I am grateful to Doug and Sherree for a place to sleep last night.

9/22
Today I am grateful for dinner with Cameron and family/friends last night in Logan Square. .

9/21
Today I am grateful to present at #VSLive yesterday.

9/20
Today I am grateful to Jeremy for answering my Azure questions yesterday.

9/19
Today I am grateful to Chris for driving me to the car dealer yesterday.

9/18
Today I am grateful for an evening bike ride along Lake Michigan last night.

9/17
Today I am grateful to attend the first Printers Row Art Festival yesterday.

9/16
Today I am grateful to the tow tuck driver who rescued me last night.

9/15
Today I am grateful that my doctor takes the time to thoroughly answer all my questions.

9/14
Today I am grateful to see the traditional Irish band Altan at the Irish American Heritage Center last night.

9/13
Today I am grateful I've been able to make it to the gym every day for the past 2 weeks.

9/12
Today I am grateful to David for introducing me to Stereophonics by taking me to their concert last night.

9/11
Today I am grateful to Michael, who loaned me his clicker and did not complain that it took me 2 months to return it.

9/10
Today I am grateful for a free year of NFL Sunday Ticket.

9/9
Today I am grateful to the lady who bought me dinner last night.

9/8
Today I am grateful to see Billy Joel last night in concert for the first time.

9/7
Today I am grateful for:
-A birthday dinner with Tim last night
-Discovering 2 outdoor concerts in my neighborhood yesterday

9/6
Today I am grateful for a walk around Northerly Island and Burnham Harbor last night.

9/5
Today I am grateful for a 10-mile bike ride around the city yesterday.

9/4
Today I am grateful to sit on my balcony yesterday reading, writing, and watching the storms roll across the city.

9/3
Today I am grateful to celebrate Larissa's birthday with her yesterday.


TheReturnOfTheKingThe Return of the King concludes J.R.R. Tolkien's epic trilogy - The Lord of the Rings.

Lord of the Rings is the story of Good versus Evil; of perseverance in the face adversity; of loyalty in the face of temptation; and of friendship. They battle because they must

Frodo and Sam and Gandalf are motivated by what is right and by a chance to save their friends Sauron and his allies are motivated by a desire to rule the world. They battle because of their greed and power lust. Spoiler alert: The good guys win.

Good triumphs because the good people are motivated to protect their lands and help one another.
Sauron motivates his allies through fear and intimidation. As a result, there is no loyalty and constant infighting among his forces.

Of course, the good guys suffer infighting and doubt in the outcome, but they know their cause is just and they know they can depend on their friends and allies. And ultimately, they win because they assist one another voluntarily, despite great risks to themselves.

Return brings the 3-volume story to its climax. Gandalf, Aragorn, and the others remaining from the Fellowship of volume 1 wage war against Sauron's forces, which distracts the evil sorcerer enough to allow Frodo and Sam a chance to sneak into Mordor and destroy the powerful One Ring at the Cracks of Doom, where it was created.

One should only read The Return of the King as part of the trilogy - not only to understand how the story progressed and how we got to where we are; but to appreciate the evolution that so many of the main characters go through. Gandalf is transformed from gray to white surpassing the power of his master Saruman, who was seduced by Sauron. Merry and Pippin begin book 1 as irresponsible children and end volume 3 as heroes. They literally grow up as they both mature and gain height by drinking Ent Water; Aragorn, known only as a wandering woodsman when we first met him, claims the throne through both his heredity and his heroic actions; Frodo, of course, accomplishes his goal of carrying the ring, though it drags on his mind and his body. But it is Samwise Gamgee ("Sam"), whose loyalty and courage makes Frodo's quest happen. He came to us as a gardener and ended up saving the world, doing so with startling humility.

There are so many more characters in this book that captured my imagination: Faramir, who resisted the temptation that doomed his brother Boromir; and his father Denethor, driven mad by the loss of his son and the seeming hopelessness of the War of the Ring; and Eowyn, who disguised herself as a man to join the battle and fulfills a prophecy by defeating a great enemy.

One even finds great characters among the villains, most especially the pathetic Gollom who literally battles with himself over whether to betray Frodo and seize back the precious ring that he once owned.

I could go on and on. There are so many characters and so much texture to the world Tolkien creates, that this series bears reading multiple times. This was my second time, although my first was decades ago.

If there is any weakness of Return, it is that the story continues for so long after the war has settled. After dealing with the one ring and ending the war, the Hobbits return to the Shire to discover it has been ravaged by orcs and bad hobbits under the influence of the evil wizard Saruman.  It's an interesting story, but a bit of an anti-climax after the long quest to save the world. Still, it does show the strength gained by which our heroic hobbits, who are able to save the Shire without the help of Gandalf or the elves.

But this does not diminish the book or the series, which stands as a classic of high fantasy.  If Tolkien did not create this genre, he certainly defined it. You can see his influence in many who came after him. Terry Brooks's popular Shannara series borrows many characters and storylines from The Lord of the Rings.

Tolkien's story is epic, his writing is poetic, and his characters are memorable.

I am left with the image of Frodo expressing his affection and appreciation for the extreme loyalty shown by his friend Sam, when their demise seems almost certain:

"I'm glad to be with you, Samwise Gamgee, here at the end of all things."

And I am glad this world had Tolkien to give us the world of Middle Earth.


What and Why I Blog

Comments [0]

I began publishing this blog in January 2008 - over 10 years ago. I've been pretty consistent in adding content. I've never gone a calendar month without at least one post and I've averaged about 11 posts per month during that span. But I had never had more than 21 posts in a given month. Until June of this year. In the past 4 months, I've averaged 23.5 posts per month.

Why I write

I'm making more time to write down my thoughts these days because I see value in this. Here are some of the reasons I maintain this blog.

Understand what I'm learning

I spend a lot of time learning new technologies. I read books and articles, I attend sessions, I watch videos, and I ask questions. But the two things that solidify this knowledge are building something with the technology and explaining that technology to others. This blog helps me achieve the latter. Blogging or explaining, forces me to learn areas of the topic I might otherwise miss. I am smarter on a subject after I have blogged about it.

Share knowledge with others

I love to learn, and I love to teach. When I learn something new, I believe there is someone out there who could benefit from learning the same thing. I have received emails from people thanking me for explaining or making them aware of a technology.

Share knowledge with myself

I also use my blog to teach my future self about a technology. Often, I will work with a tool and not return to it for months or years. When I need to remember how to do something, I find it useful to have documented my experiences previously. Many times, I return to this post about how to use GitHub commands, because I don’t use these enough to remember them.

Build credibility

Technical blogging creates the perception that I know what I'm talking about. This was important when I was a consultant, as customers sometimes found me through my blog. This was important when I was seeking employment, as employers knew about my experience and my passion by reading my blog. And this is important as a public speaker, as conference organizers can see that I'm able to explain a topic on which I propose to speak.

Links

As a public speaker, I often give a high-level overview on a technical topic. Often, I will post a slide at the end of my presentation with links to relevant blog posts for those who want to dive deeper.

Practice writing

No matter your profession, effective writing is a valuable skill. But writing is a muscle that needs to be exercised. Blogging provides me an opportunity to write (hopefully) coherent paragraphs and stories. The more I do this and think about it, the better I get at it, which helps me at my day job.

What I write

I write on a variety of topics. Here are a few broad categories into which they fall

Technical overviews

Describe a given technology and why it is important

How-To instructions

These are step-by-step instructions on a technical topic, such as a programming language feature or a software tool.
Example

What I'm doing

If I have a lot of speaking coming up, I will publish a list of upcoming presentations. Of course, you can always find out my speaking schedule at /Schedule.aspx.
Example

What I did

Sometimes I will experience something amazing, like a trip to Europe or South America and I'll share my impressions and experiences.
Example

Conference overviews

After attending a conference that particularly inspired me or taught me, I'll share my thoughts and learnings.

Example

Personal thoughts

Things I believe and why. Sometimes, these are very personal, such as my memories of a friend or family member who passed. Sometimes, I write about philosophical things like the importance of forgiveness. At the beginning of each month, I publish a list of all my daily gratitudes from the previous month.
Example

Career Coaching

I’ve spent much of the last few years of my career coaching others. I’ve learned some important soft skills and I use my blog as a way to share those learnings.
Example

Video

I have 2 ongoing TV shows: Technology and Friends features interviews with technologists about a variety of topics that are of interest  to other technologists. GCast features screencasts showing how to use software tools. I have been a guest host for DevRadio and other shows and I will post links to those videos on my blog.
Example

Podcasts and articles

When I'm a guest on a podcast or interviewed for an article, I link to it from my blog.
Example

Reviews

I read a lot and attend a lot of concerts and theater. I share my impressions of the art I experience.
Book review
Concert review

As you can see, my blog is both a personal and a professional one. Years ago, popular blogger Scott Hanselman gave me some advice - Have a single presence on the web. So, you can discover a lot about me - What I'm thinking, what I'm doing, and what I'm doing, and what I'm learning - here at davidgiard.com.

Thinking of writing a blog?

If you are thinking of writing a blog, I encourage you to do so. It has benefited me, and it could benefit you. Here are some things to think about as you begin.

Write about what you know and what you learn. Don't worry if it's too basic. I write many introductory posts on basic topics. If something is new to me, it's likely also new to someone else.

Don't worry if it's been said before. You may have a way of explaining that is just right for someone.

Identify your audience and your goals. Are you a technical blogger, a patron of the arts, a philosopher, a political pundit? All of the above? A targeted blog can help you focus on what your next article should be. It's worth noting that I don't actually follow this bit of advice. I post enough content that there is something for just about everyone. But it's useful advice when you are starting out and don’t yet have a lot of content.

Always check your spelling and grammar. Your blog engine will probably help with this. If it is insufficient, paste your post into Microsoft Word and press [F7] to check it. Poor spelling and sloppy grammar reflect poorly on the writer.

Find a host and a blog engine. There are many free ones out there. I use DasBlog as my engine and I host on Microsoft Azure. If I were starting today, I might choose a more popular blog engine like WordPress or Drupal.

Maintain discipline. Commit to writing at least one post a month. Set a calendar reminder. Take notes during the month that you can later assemble into a post. Infrequently updated blogs are less interesting. And abandoned blogs are depressing.

Always date your posts. This is especially true for posts about technology, because software changes very fast.

Final thoughts

I really enjoy keeping this blog. I like the fact that others have learned from what I've written, even if "others" means "future me".




GCast 15:

Creating an Azure Web App

Azure Web Apps allow you to host your web sites and applications in the cloud. I walk through the steps of setting up an Azure Web App.



The Microsoft Bot Framework makes it easier to create a chatbot. But a chatbot is only good if your users have a way of calling it. Microsoft bots can be accessed via a number of channels, including Facebook Messenger, Microsoft Teams, Skype, Slack, and Twilio.

Bot Settings

Once you have deployed a bot to Azure, you can view its properties in the Azure Portal, as shown in Fig. 1.

Fig01-BotProperties
Fig. 1

Click "Settings" to display the "Settings" blade, as shown in Fig. 2.

Fig02-BotSettingsBlade
Fig. 2

You will need the "Microsoft App ID" value (Fig. 3)

Fig03-MicrosoftAppId
Fig. 3

Copy this value and save it somewhere, such as in a text file. You will need it later.

Bot Channel

Next, create a Channel for your bot. To do this, do the following:

Click "Channels" to display the "Connect to Channels" blade, as shown in Fig. 4.

Fig04-ChannelsBlade
Fig. 4

Click the "Configure Direct Line Channel" icon (Fig. 5) to display the "Configure Direct Line" dialog (Fig. 6)

Fig05-DirectLineChannelIcon
Fig. 5

Fig06-ConfigureDirectLine
Fig. 6

The Secret Keys are hidden by default. Click the "Show" link next to one of them to display this key, as shown in Fig. 7

Fig07-ShowSecretKey
Fig. 7

Copy this value and save it somewhere, such as in a text file. You will need it later.

Click the [Done] button to close the "Configure Direct Line Channel" dialog.

Create Web Page

Now, you are ready to create a web page to allow users to use your chatbot.

The chat functionality is exposed through web services; but you can simplify calling these by using the Web Chat control. The source code for this open source project is here; but you don't need the source code unless you plan to modify or extend it.

Instead, you can link to the JavaScript file from your HTML with the following tag:


  

Add a div to your web page with the id "mybot", as shown below

Then, add the following JavaScript to configure the WebChat client:

<script>
	BotChat.App({
		'directLine': { 'secret': 'DirectLineSecretKey' },
		'user': { id: 'UserId' },
		'bot': { id: 'MicrosoftAppId' },
		'resize': 'detect'
	}, document.getElementById("mybot"));
</script>
  

where:

  • DirectLineSecretKey is from one of the 'Secret Keys' fields of the Bot's Direct Line channel blade, that you copied earlier.
  • MicrosoftAppId is from the 'Microsoft App Id' field of the bot's 'Settings' blade, that you copied earlier.
  • UserId can be any string you like. These will display in the UI next to text submitted by the user.

The WebChat project also provides a stylesheet that you can use by adding the following tag within the tag:

 href="https://cdn.botframework.com/botframework-webchat/latest/botchat.css" rel="stylesheet" />
  

Below is the full HTML and JavaScript with some dummy values for DirectLineSecretKey, user, and MicrosoftAppId.




    </span>Cubic Chatbot<span style="color: rgb(0, 119, 0);">
     href="https://cdn.botframework.com/botframework-webchat/latest/botchat.css" rel="stylesheet" />


     id="mybot">

In a browser, this page renders as shown in Fig. 8.

Fig08-BotClient
Fig. 8

Fig. 9 shows how it looks when you connect to a bot that echoes back what the user sends.

Fig09-BotClient
Fig. 9

If you want this control to be displayed within another web page, you can add an iframe to that other page, as below.

 src="botclientpage.html">
  

In this article, I showed you how to create a web page that communicates with a Microsoft Bot.


TheTwoTowersI wonder if we shall ever be put into songs or tales. We’re in one, of course; but I mean: put into words, you know, told by the fireside, or read out of a great big book with red and black letters, years and years afterwards. And people will say: "Let’s hear about Frodo and the Ring!" And they’ll say: "Yes, that’s one of my favourite stories."
-Samwise Gamgee

The Fellowship formed in the first book has broken. Frodo and Sam are on their way to Mordor to destroy the evil ring, so that the evil Sauron cannot use its power to conquer Middle Earth; Gandalf is presumed dead after falling into an abyss while battling the Balrog; Merry and Pippin have been kidnapped by Orcs - the same Orcs who killed Boromir; and Legolas, Gimli, and Aragorn traverse the land, seeking allies and battling Sauron's forces.

The first half of The Two Towers follows Legolas, Gimli, Aragorn, Merry, and Pippin until they are united. It is filled with epic battles between mighty armies. The second half of the volume chronicles the journey of Frodo and Sam, as they travel across perilous country to Mordor, guided by the twisted Gollom. The dangers they encounter are smaller, but no less perilous. They are attacked by Gollom and by Orcs and by a giant spider.

The theme of this middle volume of The Lord of the Rings trilogy seems to largely deal with decisions in the face of adversity. Boromir wrestles with his loyalty to the Fellowship and his desire to use the powerful ring to defend his country. Gollom literally argues with himself when debating whether to keep promises he made to Frodo or betray him and seize the ring for himself.

The leaders of Middle Earth know that a war is coming, but many of them need to be convinced to take sides. They delay because they wish to remain neutral, which gives an advantage to the aggressor Sauron and his minion Saruman. Since Tolkien lived through World War II, it's hard to imagine he wasn't thinking of all the countries who hesitated to take on Hitler during his pre-war efforts to expand his power.

The Two Towers is a classic adventure story that keeps the reader in suspense throughout. But, like its predecessors The Fellowship of the Ring, it is best read as part of the trilogy. It is parts 3 and 4 of a 6-part series and each of these parts ends with much unresolved. The characters are wonderful, the world is amazing, and the storytelling is epic.

I am enjoying this journey.


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.


GCast 14:

Creating an Azure Storage Account

Learn how to create a new Azure Storage account.


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

Fig01-FunctionApp
Fig. 1

The URL takes the following form:

https://functionappname.azurewebsites.net

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

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

https://functionappname.scm.azurewebsites.net.

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

The Kudu page displays as shown in Fig. 2

Fig02-Kudu
Fig. 2

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

Fig03-DebugConsole
Fig. 3

Fig04-DebuigConsoleMenu
Fig. 4

The debug console displays, as shown in Fig. 5

Fig05-CommandConsole
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

Fig06-ChangeFolder
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. 


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

Fig01-StartStopInMemory
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.

Fig02-StorageAccount
Fig. 2

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

Fig03-StorageAccessKeys
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 tag.

 
  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.

Fig04-StartStopAzureTable
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.  



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


Stereophonics Invade Chicago

Comments [0]

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.


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 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("FirstLoginTime", out firstLoginTimeThisConversationAnyUser);
	if (firstLoginTimeThisConversationAnyUser == System.DateTime.MinValue)
	{
		firstLoginTimeThisConversationAnyUser = System.DateTime.Now;
		context.ConversationData.SetValue("FirstLoginTime", firstLoginTimeThisConversationAnyUser);
	}

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

	DateTime firstLoginTimeCurrentConversationCurrentUser = DateTime.MinValue;
	context.PrivateConversationData.TryGetValue("FirstLoginTime", out firstLoginTimeCurrentConversationCurrentUser);
	if (firstLoginTimeCurrentConversationCurrentUser == System.DateTime.MinValue)
	{
		firstLoginTimeCurrentConversationCurrentUser = currentTime;
		context.PrivateConversationData.SetValue("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);

	context.Wait(MessageReceivedAsync);
}
  

  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.

Fig01-BotEmulator1
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)

Fig02-BotEmulator2
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)

Fig03-BotEmulatorNewConversation
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.


GCast 13:

Azure Media Services: Closed Captioning

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


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

Fig01-NewBotProject
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.

Fig02-AddClassMenu
Fig. 2

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

Fig03-AddClass
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)
        {
            context.Wait(MessageReceivedAsync);

            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}!");

            context.Wait(MessageReceivedAsync);
        }
  

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
{
    [Serializable]
    public class RootDialog : IDialog<object>
    {
        public Task StartAsync(IDialogContext context)
        {
            context.Wait(MessageReceivedAsync);

            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}!");

            context.Wait(MessageReceivedAsync);
        }
    }
}
  

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.

Fig04-BotFrameworkEmulator
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.


Using Azure Storage

Comments [0]

An Azure storage account gives you the ability to create, store, and manage tables, queues, blobs, and files.

Azure Storage Services

Available Azure storage services are:

Blobs

A blob is any unstructured or semi-structured object that you want to store. Examples include videos, images, and text files. Blob storage is flexible for storing an object without the system having to know much about the object.

Files

Azure Files allow you to store files to Azure and access them as a file share using the standard SMB protocol. Files are built on top of Azure Blob Storage.

Tables

Azure Table Storage provides a simple NoSQL database for your application. Data in an Azure Table is stored as rows. Each row contains a key and one or more properties. You do not need to pre-define these properties beforehand and you can define different properties for different rows in the same table.

Queues

A queue is a popular mechanism for designing asynchronous applications. One application can drop a message onto a queue and another application can pick up that message later and process it. This decoupling allows for scalability, flexibility, and faster response times.

Creating an Azure Storage Account

To create a new Azure Storage Account, navigate to the https://portal.azure.com.

Click the [Create a resource] button; then select Storage | Storage account - blob, file, table, queue from the menu, as shown in Fig. 1

Fig01-NewResource
Fig. 1

The New Storage Account blade displays, as shown in Fig. 2.

Fig02-NewStorage
Fig. 2

At the "name" field, enter a unique name for your storage account. You will be able to access this account through a REST API by sending requests to

https://accountname.core.windows.net

where accountname is the name you enter for your account.

At the "Deployment model" radio button, select "Resource manager".

At the "Account kind" dropdown, select "Storage (general purpose)"

At the "Location" dropdown, select a location in which to create your account. To minimize latency, you should create an account either near you or near the users and applications that will access the data in this account.

At the "Resource Group" field, click the "Create new" link to display the "Create Resource Group" dialog, as shown in Fig. 3.

Fig03-NewResourceGroup
Fig. 3

Enter a unique name for your new resource group and click the [OK] button to close the dialog and return to the previous blade.

Review your Storage Account settings and click the [Create] button to create your new storage account.

After a few seconds, you will be able to access the properties of your Storage Account, manage the account, and connect to the account.

The "Overview" tab (Fig. 4) displays information about the account, along with links to create and manage Blobs, Files, Tables, and Queues.

Fig04-StorageOverview
Fig. 4

Click the "Blobs" link in the "Services" section of the "Overview" tab to create and manage blobs and containers, as shown in Fig. 5.

Fig05-BlobsBlade
Fig. 5

Click the "Files" link in the "Services" section of the "Overview" tab to create and manage files, as shown in Fig. 6.

Fig06-FilesBlade
Fig. 6

Click the "Tables" link in the "Services" section of the "Overview" tab to create and manage tables , as shown in Fig. 7.

Fig07-TablesBlade
Fig. 7

Click the "Queues" link in the "Services" section of the "Overview" tab to create and manage queues, as shown in Fig. 8.

Fig08-QueuesBlade
Fig. 8

Azure Storage gives you many option for storing data in the cloud.



I may be the last person in America to see Billy Joel in concert. Despite not releasing an album in over two decades, Joel tours almost constantly, routinely filling stadiums and arenas. Recently, he performed a record 100th time at Madison Square Garden alone.

And Friday night, he performed for the seventh time at Wrigley Field in Chicago - also a concert record for this venue.

And I was there.

IMG_2164I bought my first Billy Joel album ("The Stranger") in 1977 and played it until the grooves ran out. It was one of the first albums I bout and I memorized every song. Joel must have known I was coming because he played six songs ("Movin' Out (Anthony's Song)", "Scenes from an Italian Restaurant", "Vienna", "Only the Good Die Young", and "She's Always a Woman") from "The Stranger". Interestingly, he did not play "Just the Way You Are", one of the biggest hits of the year.

In fact, he drew from nearly every one of his 12 studio albums. With 33 Top 40 hits and 23 Grammy nominations, he could not play all his hits; but he did play for two and a half hours, delighting a full crowd at the baseball stadium. He combined big hits like

and a surprising aria written by Puccini and sung by his guitarist Mike DelGuidice. Joel also brought background singer Crystal Taliefero to the front to sing "RESPECT" an Otis Redding composition made famous by the late Aretha Franklin.

He left the audience feeling appreciated by not only mentioning Chicago, but by playing parts of Sinatra's "Chicago (My Kind of Town)" twice during his set. His drummer wore a Cubs jersey and shouted "Good luck in the playoffs!" as he left the stage.

For me, the highlights were a moving rendition of "New York State of Mind", a song I've always believed that Joel never got enough credit for; and "River of Dreams" featuring its complex rhythms - a song Joel surprised us with after a series of pop songs in the 1980s.

Everyone sang along and rocked back and forth as the piano man sang his classic "Piano Man" before bowing and waving Good Night. But, of course he returned to the stage and delivered 4(!) upbeat songs for his encore.

Two and a half hours is a long time for anyone to play, particular for a singer in his 60's; but Billy Joel's voice sounds as strong as ever. And his piano playing is still outstanding. And with a solid group of musicians behind him, the crowd left satisfied.

And now that I've seen Billy Joel, I suppose that everyone has.


The Microsoft Bot Framework provides a template that creates a simple bot: The "Bot Builder Echo Bot". It is named this because it echoes back any text you send it, along with the length of that text.

The bot is simply an ASP.NET Web API application that exposes web services to Channel clients. As such, it uses the default routing for Web API applications of "api/controllername"

where controllername is the name of the Controller class with the word “Controller” removed.

A channel will submit an HTTP POST to a URL containing "api/message", which will call the Post method in the MessagesController class. Let's take a look at this class.

    [BotAuthentication]
    public class MessagesController : ApiController
    {
        /// 
        /// POST: api/Messages
        /// Receive a message from a user and reply to it
        /// 
        public async Task Post([FromBody]Activity activity)
        {
            if (activity.GetActivityType() == ActivityTypes.Message)
            {
                await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
            }
            else
            {
                HandleSystemMessage(activity);
            }
            var response = Request.CreateResponse(HttpStatusCode.OK);
            return response;
        }

        private Activity HandleSystemMessage(Activity message)
        {
            string messageType = message.GetActivityType();
            if (messageType == ActivityTypes.DeleteUserData)
            {
                // Implement user deletion here
                // If we handle user deletion, return a real message
            }
            else if (messageType == ActivityTypes.ConversationUpdate)
            {
                // Handle conversation state changes, like members being added and removed
                // Use Activity.MembersAdded and Activity.MembersRemoved and Activity.Action for info
                // Not available in all channels
            }
            else if (messageType == ActivityTypes.ContactRelationUpdate)
            {
                // Handle add/remove from contact lists
                // Activity.From + Activity.Action represent what happened
            }
            else if (messageType == ActivityTypes.Typing)
            {
                // Handle knowing that the user is typing
            }
            else if (messageType == ActivityTypes.Ping)
            {
            }

            return null;
        }
  

Listing 1

A channel posts an activity to the service. If the activity type is anything other than "Message", it calls the HandleSystemMessage method. Notice that nothing is actually implemented in this method. You will have to write this yourself.

However, if the activity type is "Message", the Post method asynchronously calls the Dialogs.RootDialog class. Here is that class:

    [Serializable]
    public class RootDialog : IDialog<object>
    {
        public Task StartAsync(IDialogContext context)
        {
            context.Wait(MessageReceivedAsync);

            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($"You sent {activity.Text} which was {length} characters");

            context.Wait(MessageReceivedAsync);
        }
    }
  

Listing 2

The StartAsync method is called first, which waits for a message to be completely received; then, calls the MessageReceivedAsync method.

This method reads the text of the activity and forms a string that contains the original message text and the length of that text. It then Posts this back to the channel with the line below:

await context.PostAsync($"You sent {activity.Text} which was {length} characters");

Finally, it waits for the next message to come in via the following line

context.Wait(MessageReceivedAsync);

The rest of this project is Web API plumbing, setting up things like routing and where to store state information.

As you can see, this is a fairly simple architecture built on an established framework (Web API). This makes it easier to understand and to modify.

This simple bot is a good starting place that demonstrates the structure of a bot. You can modify this dialog, add new dialogs, or modify the logic as suits your purposes.


<< Older Posts | Newer Posts >>