# Friday, August 23, 2019

Recently, I was working on a VM that someone else provided me and I needed to download an executable from the Internet onto this VM. I discovered that the only installed browser on the VM was Internet Explorer 11 and that the browser was configured to prevent anyone from downloading files from the Internet.

I don't know if this is the default setting for IE 11, but here is how to change the setting to allow users to download files.

Open Internet Explorer.

From the menu, select Tools | Internet Options

The "Internet Options" dialog displays. Select the "Security" tab, as shown in Fig. 1.

IE01
Fig. 1

Click the [Custom Level] button. The "Security Settings" dialog displays. Scroll down to the "Downloads/File download" section, as shown in Fig. 2.

IE02
Fig. 2

Select the "Enable" radio button and click the [OK] button. If prompted for confirmation, click [Yes].

Click the [OK] button to close the "Internet Options" dialog.

Now you can download files linked within the browser.

Friday, August 23, 2019 11:17:00 AM (GMT Daylight Time, UTC+01:00)

GCast 62:

Sentiment Analysis Cognitive Service

This video explains the Sentiment Analysis service, which is part of the Text Analytics Cognitive Service.

Friday, August 23, 2019 4:47:19 AM (GMT Daylight Time, UTC+01:00)
# Wednesday, August 21, 2019

A data warehouse ("DW") is an ideal tool for collecting and associated disparate data.

A data warehouse has been a part of Microsoft SQL Server for decades, so it's not surprising that it is also included in Microsoft Azure.

To create a SQL Data Warehouse in Azure, navigate to the Azure Portal, sign in, and click the [Create a resource] button (Fig. 1).

dw01-CreateANewResourceButton
Fig. 1

From the menu, select Databases | SQL Data Warehouse, as shown in Fig. 2

dw02-SqlDataWarehouse
Fig. 2

The "SQL Data Warehouse" dialog displays, allowing you to enter information about your new data warehouse, as shown in Fig. 3

dw03-NewSqlDataWarehouse
Fig. 3

At the "Subscription" field, select the subscription in which you wish to create this data warehouse. Most of you will have only one subscription.

At the "Resource group" field, select an existing resource group or click the "Create new" link to create a new resource group in which to add this data warehouse. A resource group is an organizational unit to keep together related Azure resources.

At the "Data warehouse name" field, enter a unique name for your warehouse.

The "Server" field lists all SQL servers in the selected subscription. Every data warehouse is stored in one SQL Server. Select the SQL Server for this DW or click the "Create new" link to create a new SQL Server.

Clicking "Create new" displays the "New server" blade, as shown in Fig. 4. In this blade, you can enter the server name, location, and admin login credentials for a new server.

dw04-NewServer
Fig. 4

Click the [Review + create] button to display the "Review + create" tab of the "SQL Data Warehouse" dialog, as shown in Fig. 5.

dw05-ReviewCreate
Fig. 5

Click the [Create] button to create a new SQL Data Warehouse. This process may take a few minutes (longer if you also chose to create a new server).

After the Data Warehouse creation is complete, you can navigate to its management page. The "Overview" blade is shown in Fig. 6.

dw06-Overview
Fig. 6

In this article, you learned how to create a new Azure SQL Data Warehouse.

Wednesday, August 21, 2019 3:00:00 PM (GMT Daylight Time, UTC+01:00)
# Sunday, August 18, 2019

HerzogPoor Moses Herzog.

His wife convinced him to buy a house in Chicago; then tried to have him committed; then, left him for his best friend. On top of that, he is denied contact with either of his children.

Moses sets out for Chicago with his later father's antique pistol, 2 bullets, and murder on his mind. But nothing goes right, and his plans fall apart, and he is in an automobile accident and the police discover his loaded pistols.

The action does of Saul Bellow's Herzog does not happen until the novel is at least half over. But the author keeps us engaged through Moses's angst, as his life falls apart. Moses deals with his depression by writing letters - most of which are never sent and many of which are addressed to famous people such as Friedrich Nietzsche and (then-President) Dwight Eisenhower.

Herzog is unstable; but he is not crazy as his shrewish wife asserts. And his letter-writing decreases as he comes to terms with the cards he is dealt.

Bellow's writing is poignant and sad, but sometimes humorous, with lines such as

"Lead me into Penn Station"
and
"Will never understand what women want. What do they want? They eat green salad and drink human blood."

This book will appeal to anyone who has experienced the helplessness of a mid-life crisis; or the pain of betrayal; or the paralysis of uncertainty.

Sunday, August 18, 2019 4:19:00 PM (GMT Daylight Time, UTC+01:00)
# Saturday, August 17, 2019

UbikDeath is very different in the universe of Philip K. Dick's Ubik. Rather than simply ending life or transitioning to an afterlife, the recently dead remain cognizant. If properly preserved, technology exists that allows the living to communicate with the dead - sometimes for years. The consciousness slowly decays over time, after which the deceased finally cease to exist or are reborn anew.

Psychics are common enough in this universe to keep Glen Runciter busy. His company specializes in protecting people from psychic intrusion.

A group of powerful anti-psychics, led by Runciter, travel to the moon to meet with a potential client, where they are attacked and seemingly hurled back in time to the year 1939. But not everything is like the 1939 of their own past and they wonder exactly where they are.

Runciter is a good man and so is his employee Joe Chip. Chip is the perfect hero. He is loyal to his employer and dedicated to finding the truth; but he is financially irresponsible and always lacking funds (a problem when every appliance, device, and door requires a cash fee before it will operate).

Ubik is an imaginative tale of action and drama and speculative science fiction. Dick does an excellent job of taking far-fetched ideas and making them seem plausible. In under 250 pages he builds an entire world; then, destroys that world and creates another.

The story is both dark and humorous.

This novel influenced science fiction for many years after its 1969 publication. Douglas Adams must have read about the annoying talking doors when he wrote them into his Hitchhiker series. At times, we see nested realities, in a way that echoed in the 2010 film "Inception".

The narrative keeps changing our expectations. He keeps us guessing about reality versus illusion and life versus death and past versus present. And that's just the way Philip K. Dick wants it.

Saturday, August 17, 2019 8:21:00 AM (GMT Daylight Time, UTC+01:00)
# Friday, August 16, 2019

In the last article, I walked through the syntax of calling the Bing Spell Check service.

In this article, I will walk through a simple JavaScript application that calls this service.

If you want to follow along this sample is part of my Cognitive Services demos, which you can find on GitHub at https://github.com/DavidGiard/CognitiveSvcsDemos 

This project is found in the "SpellCheckDemo" folder.

Here is the main web page:

Listing 1:

<html>
<head>
    <title>Spell Check Demo</title>
    <script src="scripts/jquery-1.10.2.min.js"></script>
    <script src="scripts/script.js"></script>
    <script src="scripts/getkey.js"></script>
    <link rel="stylesheet" href="css/site.css">
</head>
 <body>
     <h1>Spell Check Demo</h1>
     <div>
         <textarea id="TextToCheck">Life ig buuutiful all the tyme
         </textarea>
     </div>
    <button id="SpellCheckButton">Check Spelling!</button>
     <div id="NewTextDiv"></div>
     <div id="OutputDiv"></div>

</body>
</html>
  

As you can see, the page consists of a text area with some misspelled text; a button; and 2 empty divs.

The page looks like this when rendered in a browser:

scjs01-PageOnLoad
Fig. 1

When the user clicks the button, we want to call the Spell Check service, sending it the text in the text area.

We want to display the values in the web service response in the OutputDiv div; and we want to display some of the raw information in the response in the NewTextDiv div.

Below is the screen after clicking the [Check Spelling] button

scjs02-PageAfterClick

Fig. 2

We need a reference to the outputDiv, so we can easily write to it.

Listing 2:

var outputDiv = document.getElementById("OutputDiv");
  

Next, we bind code to the button's click event, as shown in Listing 3.

Listing 3:

var spellCheckButton = document.getElementById("SpellCheckButton"); 
spellCheckButton.onclick = function () { 
    // Replace this with your Spell Check API key from Aure 
    var subscriptionKey = "xxxxxxxxxxxxxxxxxxxxxxxx"; 

    outputDiv.innerHTML = "Thinking...";

    var textToCheck = document.getElementById("TextToCheck").textContent; 
    var webSvcUrl = "https://api.cognitive.microsoft.com/bing/v7.0/spellcheck/?text=" + textToCheck; 
    webSvcUrl = webSvcUrl + "&mode=proof&mkt=en-US";

    var httpReq = new XMLHttpRequest(); 
    httpReq.open("GET", webSvcUrl, true); 
    httpReq.setRequestHeader("Ocp-Apim-Subscription-Key", subscriptionKey) 
    httpReq.setRequestHeader("contentType", "application/json") 
    httpReq.onload = onSpellCheckSuccess; 
    httpReq.onerror = onSpellCheckError; 
    httpReq.send(null); 
};
  

This code gets the text from the text area and makes an asynchronous HTTP GET request to the Spell Check API, passing the API key in the header. When the API sends a response, this will call the onSpellCheckSuccess or onSpellCheckError function, depending on the success of the call.

Listing 4 shows the onSpellCheckSuccess function:

Listing 4:

function onSpellCheckSuccess(evt) { 
    var req = evt.srcElement; 
    var resp = req.response; 
    var data = JSON.parse(resp);

    var flaggedTokens = data.flaggedTokens; 
    if (data.flaggedTokens.length > 0) { 
        var newText = document.getElementById("TextToCheck").textContent; 
        ; 
        var outputHtml = ""; 
         flaggedTokens.forEach(flaggedToken => { 
            var token = flaggedToken.token; 
            var tokenType = flaggedToken.type; 
            var offset = flaggedToken.offset; 
            var suggestions = flaggedToken.suggestions; 
            outputHtml += "<div>" 
            outputHtml += "<h3>Token: " + token + "</h3>"; 
            outputHtml += "Type: " + tokenType + "<br/>"; 
            outputHtml += "Offset: " + offset + "<br/>"; 
             outputHtml += "<div>Suggestions</div>"; 
            outputHtml += "<ul>";

            if (suggestions.length > 0) { 
                 suggestions.forEach(suggestion => { 
                     outputHtml += "<li>" + suggestion.suggestion; 
                     outputHtml += " (" + (suggestion.score * 100).toFixed(2) + "%)" 
                }); 
                outputHtml += "</ul>"; 
                outputHtml += "</div>";

                newText = replaceTokenWithSuggestion(newText, token, offset, suggestions[0].suggestion) 
            } 
            else { 
                 outputHtml += "<ul><li>No suggestions for this token</ul>"; 
            } 
        });

        newText = "<h2>New Text:</h2>" + newText; 
        var newTextDiv = document.getElementById("NewTextDiv"); 
        newTextDiv.innerHTML = newText;

        outputHtml = "<h2>Details</h2>" + outputHtml; 
        outputDiv.innerHTML = outputHtml;

    } 
    else { 
        outputDiv.innerHTML = "No errors found."; 
    } 
};
  

As you can see, we parse out the JSON object from the response and retrieve each flaggedToken from that object. For each flaggedToken, we output information, such as the original text (or token), the tokenType, and suggested replacements, along with the score of each replacement.

If an error occurs when calling the API service, the onSpellCheckError function is called, as shown in Listing 5.

Listing 5:

function onSpellCheckError(evt) { 
    outputDiv.innerHTML = "An error has occurred!!!"; 
};
  

Finally, we replace each token with the first suggestion, using the code in Listing 6.

Listing 6*:

function replaceTokenWithSuggestion(originalString, oldToken, offset, newWord) { 
    var textBeforeToken = originalString.substring(0, offset);

    var textAfterToken = ""; 
    if (originalString.length > textBeforeToken.length + oldToken.length) { 
        textAfterToken = originalString.substring(offset + oldToken.length, originalString.length); 
    }

    var newString = textBeforeToken + newWord + textAfterToken;

    return newString; 
 }
  

Here is the full JavaScript:

Listing 7:

window.onload = function () {

    var outputDiv = document.getElementById("OutputDiv");
    // var subscriptionKey = getKey();

    var spellCheckButton = document.getElementById("SpellCheckButton");
    spellCheckButton.onclick = function () {
        var subscriptionKey = getKey();
        var textToCheck = document.getElementById("TextToCheck").textContent;

        var webSvcUrl = "https://api.cognitive.microsoft.com/bing/v7.0/spellcheck/?text=" + textToCheck;
        webSvcUrl = webSvcUrl + "&mode=proof&mkt=en-US";

        outputDiv.innerHTML = "Thinking...";

        var httpReq = new XMLHttpRequest();
        httpReq.open("GET", webSvcUrl, true);
        httpReq.setRequestHeader("Ocp-Apim-Subscription-Key", subscriptionKey)
        httpReq.setRequestHeader("contentType", "application/json")
        httpReq.onload = onSpellCheckSuccess;
        httpReq.onerror = onSpellCheckError;
        httpReq.send(null);
    };

    function onSpellCheckSuccess(evt) {
        var req = evt.srcElement;
        var resp = req.response;
        var data = JSON.parse(resp);

        var flaggedTokens = data.flaggedTokens;
        if (data.flaggedTokens.length > 0) {
            var newText = document.getElementById("TextToCheck").textContent;
            ;
            var outputHtml = "";
            flaggedTokens.forEach(flaggedToken => {
                var token = flaggedToken.token;
                var tokenType = flaggedToken.type;
                var offset = flaggedToken.offset;
                var suggestions = flaggedToken.suggestions;
                outputHtml += "<div>"
                outputHtml += "<h3>Token: " + token + "</h3>";
                outputHtml += "Type: " + tokenType + "<br/>";
                outputHtml += "Offset: " + offset + "<br/>";
                outputHtml += "<div>Suggestions</div>";
                outputHtml += "<ul>";

                if (suggestions.length > 0) {
                    suggestions.forEach(suggestion => {
                        outputHtml += "<li>" + suggestion.suggestion;
                        outputHtml += " (" + (suggestion.score * 100).toFixed(2) + "%)" 
                    });
                    outputHtml += "</ul>";
                    outputHtml += "</div>";

                    newText = replaceTokenWithSuggestion(newText, token, offset, suggestions[0].suggestion)
                }
                else {
                    outputHtml += "<ul><li>No suggestions for this token</ul>";
                }
            });

            newText = "<h2>New Text:</h2>" + newText;
            var newTextDiv = document.getElementById("NewTextDiv");
            newTextDiv.innerHTML = newText;

            outputHtml = "<h2>Details</h2>" + outputHtml;
            outputDiv.innerHTML = outputHtml;

        }
        else {
            outputDiv.innerHTML = "No errors found.";
        }
    };

    function onSpellCheckError(evt) {
        outputDiv.innerHTML = "An error has occurred!!!";
    };

    function replaceTokenWithSuggestion(originalString, oldToken, offset, newWord) {
        var textBeforeToken = originalString.substring(0, offset);

        var textAfterToken = "";
        if (originalString.length > textBeforeToken.length + oldToken.length) {
            textAfterToken = originalString.substring(offset + oldToken.length, originalString.length);
        }

        var newString = textBeforeToken + newWord + textAfterToken;

        return newString;
    }

};
  

Hopefully, this sample gives you an idea how to get started building your first app that uses the Bing Spell Check API.



* This code currently has a bug in it: It only works if each suggestion is the same length as the token it replaces. I plan to fix this bug, but I'm publishing now because:

  1. It is not a fatal bug and
  2. It is not relevant to the call to the API, which is the primary point I'm showing in this article.
Friday, August 16, 2019 9:00:00 AM (GMT Daylight Time, UTC+01:00)
# Thursday, August 15, 2019

GCast 61:

Text Recognition C# Demo

In this video, I walk you through a C# application that calls the Text Recognition service, passing in an image of text and retrieving that text.

Thursday, August 15, 2019 8:47:00 AM (GMT Daylight Time, UTC+01:00)
# Wednesday, August 14, 2019

In the last article, I showed how to create a Bing Spell Check service in Azure. Once you have created this service, you can now pass text to a web service to perform spell checking.

Given a text sample, the service checks the spelling of each token in the sample. A token is a word or two word that should be a single word, such as "arti cle", which is a misspelling of the word "article".

It returns an array of unrecognized tokens, along with suggested replacements for these misspelled tokens.

URL and querystring arguments

The URL for the web service is
https://api.cognitive.microsoft.com/bing/v7.0/spellcheck

You can add some optional querystring parameters to this URL:

mode
Set this to "proof" if you want to check for spelling, grammar, and punctuation errors
Set it to "spell" if you only want to check for spelling errors.

If you omit the "mode" querystring argument, it defaults to "proof".

mkt
Set this to the Market Code of the country/language/culture you want to test. This is in the format [Language Code]-[Country Code], such as "en-US" for United States English. A full list of Market Codes can be fond here.

The "Proof" mode supports only en-US,  es-ES, and pt-BR Market Codes.

If you omit the mkt argument, the service will guess the market based on the text. Therefore, it is a good idea to include this value, even though it is optional.

Below is an example of a URL with some querystring values set.

https://api.cognitive.microsoft.com/bing/v7.0/spellcheck?mode=proof&mkt=en-us

POST vs GET

You have the option to submit either an HTTP POST or an HTTP GET request to the URL. We will discuss the differences below.

If you use the GET verb, you pass the text to check in the querystring, as in the following example:

https://api.cognitive.microsoft.com/bing/v7.0/spellcheck?mode=proof&mkt=en-us&text=Life+ig+buuutifull+all+the+tyme

With the GET method, the text is limited to 1,500 characters

If you use the POST verb, the text is passed in the body of the request, as in the following example:

text=Life+ig+buuutifull+all+the+tyme

With the POST method, you can send text up to 10,000 characters long.

Results

If successful, the web service will return an HTTP 200 ("OK") response, along with the following data in JSON format in the body of the response:

_type: "SpellCheck"

An array of "flaggedTokens", representing spelling errors found

Each flaggedToken consists of the following information:

  • offset: The position of the offending token within the text
  • token: The token text
  • type: The reason this token is in this list (usually "UnknownToken")
  • suggestion: An array of suggested replacements for the offending token. Each suggestion consists of the following:
  • score: a value (0-1) indicating the likelihood that this suggestion is the appropriate replacement

Below is an example of a response:

{
   "_type": "SpellCheck",
   "flaggedTokens": [{
     "offset": 5,
     "token": "ig",
     "type": "UnknownToken",
     "suggestions": [{
       "suggestion": "is",
       "score": 0.8922398888897022
     }]
   }, {
     "offset": 8,
     "token": "buuutifull",
     "type": "UnknownToken",
     "suggestions": [{
       "suggestion": "beautiful",
       "score": 0.8922398888897022
     }]
   }, {
     "offset": 27,
     "token": "tyme",
     "type": "UnknownToken",
     "suggestions": [{
       "suggestion": "time",
       "score": 0.8922398888897022
     }]
   }]
 }
  

In this article, I showed how to call the Bing Spell Check service with either a GET or POST HTTP request.

Wednesday, August 14, 2019 8:53:00 AM (GMT Daylight Time, UTC+01:00)

The Bing Spell Check API allows you to call a simple web service to perform spell checking on your text.

Before you get started, you must log into a Microsoft Azure account and create a new Bing Spell Check Service. Here are the steps to do this:

In the Azure Portal, click the [Create a resource] button (Fig. 1); then, search for and select "Bing Spell Check", as shown in Fig. 2.

sc01-CreateResourceButton
Fig. 1

sc02-SearchForBingSpellCheck
Fig. 2

The "Bing Spell Check" (currently on version 7) page displays, which describes the service and provides links to documentation and information about the service, as shown in Fig. 3

sc03-BingSpellCheckLandingPage
Fig. 3

Click the [Create] button to open the "Create" blade, as shown in Fig. 4.

sc04-CreateSpellCheckBlade
Fig. 4

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

At the "Subscription" dropdown, select the subscription in which to create the service. Most of you will have only one subscription.

At the "Pricing Tier" dropdown, select the free or paid tier, as shown in Fig. 5.

sc05-PricingTiers
Fig. 5

The number of calls are severely limited for the free tier, so this is most useful for testing and learning the service. You may only create one free Spell Check service per subscription.

At the "Resource Group" field, select a resource group to associate with this service or click the "Create new" link to associate it with a newly-created resource group. A resource group provides a way to group together related service, making it easier to manage them together.

Click the [Create] button to begin creating the service. This process takes only a few seconds.

Open the service and select the "Keys" blade, as shown in Fig. 6.

sc06-KeysBlade
Fig. 6

Either one of the keys listed on this page must be passed in the header of your web service call.

Save a copy of one of these keys. You will need it when I show you how to call the Bing Spell Check Service in tomorrow’s article.

Wednesday, August 14, 2019 1:46:16 AM (GMT Daylight Time, UTC+01:00)
# Monday, August 12, 2019

Episode 575

Kevin Gates on Cloud Architecture

Cloud Solution Architect Kevin Gates walks us through the architecture of a sample application migrated from on-premise to Azure.

http://www.dreaddontdie.com/

Monday, August 12, 2019 9:17:00 AM (GMT Daylight Time, UTC+01:00)
# Sunday, August 11, 2019

DeathComesForTheArchbishopDeath Comes for the Archbishop by Willa Cather follows the life of Bishop Jean Marie Latour, appointed to lead the new diocese of New Mexico, when the region is annexed by the United States, following the Mexican-American War.

Latour travels to New Mexico from his home in Ohio with his friend and colleague Joseph Vaillant. They encounter many challenges: the rough environment; the lack of roads; a clash of cultures; widespread poverty; murderers who prey on travelers; rogue priests; and those who refuse to recognize the transition of authority to the new archbishop.

In addition to the story of Latour, we hear other tales of the place and time where this novel takes place. One memorable story was of a drunken, ill-tempered priest, who killed a young Indian servant when the boy spilled some food on him. The priest was captured and killed by the locals a few days later.

The story is loosely best on the lives of Jean-Baptiste Lamy and Joseph Projectus Machebeuf, who served as Catholic Bishops in the southwest US during the mid-19th century.

Cather is at her best when describing the New Mexico sky and landscape. She tells a straightforward story without much fanfare and she does a good job of contrasting the personalities of the two missionaries: the stoic Latour and the outgoing Vaillant. Each man loves God and believes in their mission but tackles it in his own way.

Like most biographies, Death Comes for the Archbishop covers the main character’s life to the end. So, while the title comes from the last chapter, it is a bit misleading. The book is far more about the Archbishop's life than about his death. As Latour himself put it: "I shall not die of a cold, my son. I shall die of having lived."

Sunday, August 11, 2019 8:18:00 AM (GMT Daylight Time, UTC+01:00)
# Saturday, August 10, 2019

TropicOfCancerI don't really know how to take Tropic of Cancer by Henry Miller.

The novel is written in the first person and the narrator has the same name as the author. So, am I to believe that Mr. Miller was a sex addict and all his friends were sex addicts and misogynists?

The story follows Miller and his friends - mostly bohemian American expatriates - as they navigate the squalid neighborhoods of Paris searching for sexual partners, artistic fulfillment, and survival. Miller tries to embrace the pleasures of life, sleeping with a variety of prostitutes and other women; but it is a challenge. He doesn't know where his next meal is coming from; but he is still focused on finding his next lay. His wife recently left for New York and he wonders why she has not communicated with him in the months since her departure. He expects her return, but it seems unlikely she will.

Still, it's difficult to feel sorry for Miller and his friends, as their descriptions are littered with misogyny. Virtually, every woman in the novel is referred to as a "c*nt" and most exist only as sexual outlets for Miller and his friends. In one scene, Miller steals his money back from a prostitute when she leaves the room after they have sex.

Many will dismiss this novel because of its strong sexual content. The writing is salacious and often shocking. Many men spend their youths focused on sex; and a few, like Miller, extend this obsession into middle age and this is his and their story.

Although very sexual, I cannot call this writing erotic. At no point did I find myself aroused by the exploits of Miller and his friends.

The novel has an important place in the history of literature. Its explicit sexuality pushed a lot of boundaries when it was first published in 1934. And it was banned as pornographic in the United States for 3 decades, until a 1961 obscenity trial that escalated to the Supreme Court. It is also significant culturally. One can hear Miller's strong influence on the beat writers of the 1950s and 1960s - from his stream-of-consciousness prose to his rejection of society's norms to his casual and frank discussion of alcohol and drug abuse. 

And this book is important for the prose that Miller brings to his writing. Here is how he describes his adopted city:

"Paris is like a whore. From a distance she seems ravishing, you can’t wait until you have her in your arms. And five minutes later you feel empty, disgusted with yourself. You feel tricked."

Tropic of Cancer is worth reading for its influence on literature and for its celebration of the joys of living.

Saturday, August 10, 2019 9:42:00 AM (GMT Daylight Time, UTC+01:00)
# Thursday, August 8, 2019

GCast 60:

Text Recognition Cognitive Service with Binary Images

The Text Recognition Service supports sending a binary image and reading any text in that image. This video shows you how.

Thursday, August 8, 2019 1:24:10 PM (GMT Daylight Time, UTC+01:00)
# Wednesday, August 7, 2019

Santana-41Santana and the Doobie Brothers were two of my favourite bands as I was growing up in suburban Detroit. Sadly, I never had the chance to see either of them in concert. Until this week.

Both bands were on stage Sunday night at the Hollywood Casino Amphitheatre in Tinley Park.

DoobieBrothers-62The Doobie Brothers opened the show with an energetic performance - their trademark funky mix of rock, blues, country, and soul.

Michael McDonald is not part of the current Doobie lineup (a stand-in sang "Takin' It to the Streets"), but the last 1970s core of Tom Johnson, Patrick Simmons, and John McFee were there and this was the version of the band I first fell in love with. This was the first time I've ever seen a warmup act come out for an encore, but the audience loved it when they returned to play "Listen to the Music" and "Black Water" (my personal favourite).

DoobieBrothers-37After a brief intermission, the sun set, the lights dimmed, and Santana opened their set with "Soul Sacrifice", their percussion-heavy instrumental from their 1969 debut album.

The centerpiece of this band is and has always been Carlos Santana, from whom the band takes its name. But Carlos has always surrounded himself with excellent musicians and they proved their prowess tonight. Instrumentals alternated with vocal songs; hits alternated with deep cuts; ballads alternated with songs of high-energy and the band was great throughout. It was particularly special when Carlos took over with a guitar solo. At 72, he remains one of the world's great guitarists. He can showcase his technical prowess and bring emotion to his music.

Santana-76 Santana has been able to stay relevant through five decades by reinventing themselves - not only artistically, but also commercially.

He played to the audience between songs, mentioning the influence of Chicago Blues legend Otis Rush on the arrangement of "Black Magic Woman".

Santana-26 After an encore that included the 1999 mega-hit "Smooth", the band finally left the stage - over 4 hours after the show began.

This was my first visit to the Hollywood Casino Amphitheatre, my first time seeing the Doobie Brothers, and my first time seeing Santana. It was a night to remember.


More Santana photos

More Doobie Brothers photos

Wednesday, August 7, 2019 7:14:00 PM (GMT Daylight Time, UTC+01:00)
# Monday, August 5, 2019

Episode 574

Mercedes Bernard on Dev Together

Mercedes Bernard started Dev Together to connect new software developers with mentors that would help them learn valuable skills. Over a year later, it is popular and spreading to other cities.

Monday, August 5, 2019 4:24:39 PM (GMT Daylight Time, UTC+01:00)
# Sunday, August 4, 2019

8/4

Today I am grateful to attend my building's annual summer party yesterday.

8/3

Today I am grateful for the gym on the 70th floor of the Aon Center.

8/2

Today I am grateful for so many excellent taco places in Chicago.

8/1

Today I am grateful for my bicycle.

7/31

Today I am grateful to find $30 in an old jacket yesterday.

7/30

Today I am grateful to accidentally stumble across a Rev. Sekou concert last night at Millennium Park.

7/29

Today I am grateful for:

-Seeing Peter Frampton in concert last night with my son

-My first visit to Maxwell Street Market

7/28

Today I am grate for:

-an afternoon at the Field Museum with my son

-dinner with my sister-in-law, my nephews, and my sons last night.

7/27

Today I am grateful for 5 years living in Chicago.

7/26

Today I am grateful to see a show at Second City last night.

7/25

Today I am grateful for my first visit to the Tampa Museum of Art.

7/24

Today I am grateful for dinner last night in Tampa with Kevin and Judy.

7/23

Today I am grateful to speak at the Chicago Cloud Conference yesterday.

7/22

Today I am grateful for a weekend in Detroit.

7/21

Today I am grateful for:

-3rd row seats to see Jeff Lynne’s Electric Light Orchestra last night with old friends;

-The hospitality of Ken

7/20

Today I am grateful for:

-breakfast with Josh yesterday

-a chance to see my sister Debbie for the first time since she moved to Hawaii.

7/19

Today I am grateful to deliver a presentation on Azure Functions at Indy Software Artisans in Indianapolis last night - my first user group presentation of 2019!

7/18

Today I am grateful for dinner and drinks last night with Nick and Tim.

7/17

Today I am grateful my espresso machine is cleaned out and now producing a much tastier beverage much more quickly.

7/16

Today I am grateful to celebrate Emilija's birthday with her friends and family at a Costa Rican restaurant yesterday.

7/15

Today I am grateful for a day in Whitefish Bay, WI.

7/14

Today I am grateful to visit the Taste of Chicago last night.

7/13

Today I am grateful for a visit the National Hellenic Museum yesterday.

7/12

Today I am grateful for the 50 years we had with Denise before she left us 10 years ago today.

7/11

Today I am grateful that I finally figure out how to record TV shows and movies off DirectTV.

7/10

Today I am grateful to the Chicago Bicycle Company for fixing my bike seat yesterday.

7/9

Today I am grateful to work with high school students through the Northwestern Academy yesterday.

7/8

Today I am grateful to attend my first Joliet Slammers game yesterday, which concluded with an extra-inning walk-off RBI for the home team.

Sunday, August 4, 2019 3:11:36 PM (GMT Daylight Time, UTC+01:00)
# Saturday, August 3, 2019

PortraitOfTheArtistA Portrait of the Artist as a Young Man is James Joyce's somewhat autobiographical novel. Joyce channels his own childhood and young adulthood through the character of Stephen Dedalus.

The book recounts young Stephen's school years, where he passes through a number of phases. He is at first intimidated by the older students, teachers, and priests at his school, struggling to fit in; later, he pursues the carnal pleasures of life; a sense of guilt turns him away from this life and he considers becoming a priest; after deciding against this, he begins to reject all society's values he grew up with and escapes to a life as an artist. These are major swings in a short time, but they are during his formative years, when Stephen is deciding who he will become. In the end, he turns away from the faith of his youth because so much of it was based on fear of damnation and a rejection of worldly pleasures, and he could not reconcile that with a love of beauty. In doing so, he rejects everything he knows to begin anew in a foreign place.

I don't know how much of Portrait applies to Joyce's own life, but he makes the novel personal, bringing us inside Stephen's mind as he struggles with his conflicts.

If you like books with a lot of action, skip this one. But if you like poetic writing and insights into the evolution of a philosophy, this book may be for you.

Saturday, August 3, 2019 9:57:00 AM (GMT Daylight Time, UTC+01:00)
# Thursday, August 1, 2019

GCast 59:

Cognitive Services Text Recognition service

Learn to extract text from an image using the new Text Recognition service.

Thursday, August 1, 2019 11:53:50 PM (GMT Daylight Time, UTC+01:00)