# Tuesday, June 11, 2019

In a previous article, I described the details of the OCR Service, which is part of the Microsoft Cognitive Services Computer Vision API.

To make this API useful, you need to write some code and build an application that calls this service.

In this article, I will show an example of a JavaScript application that calls the OCR web service.

If you want to follow along, you can find all the code in the "OCRDemo" project, included in this set of demos.

To use this demo project, you will first need to create a Computer Vision API service, as described here.

Read the project's read.me file, which explains the setup you need to do in order to run this with your account.

If you open index.html in the browser, you will see that it displays an image of a poem, along with some controls on the left:

  • A dropdown list to change the poem image
  • A dropdown list to select the language of the poem text
  • A [Get Text] button that calls the web service.

Fig. 1 shows index.html when it first loads:

oj01-WebPage
Fig. 1

    Let's look at the JavaScript that runs when you click the [Get Text] button. You can find it in script.js

    print 'hello world!'$("#GetTextFromPictureButton").click(function () {
         var outputDiv = $("#OutputDiv");
         outputDiv.text("Thinking…");
         var url = $("#ImageUrlDropdown").val();
         var language = $("#LanguageDropdown").val();
    
        try {
             var computerVisionKey = getKey();
         }
         catch(err) {
             outputDiv.html(missingKeyErrorMsg);
             return;
         }
    
        var webSvcUrl = "https://westcentralus.api.cognitive.microsoft.com/vision/v2.0/ocr";
        webSvcUrl = webSvcUrl + "?language=" + language;
        $.ajax({
            type: "POST",
            url: webSvcUrl,
            headers: { "Ocp-Apim-Subscription-Key": computerVisionKey },
            contentType: "application/json",
            data: '{ "Url": "' + url + '" }'
        }).done(function (data) {
            outputDiv.text("");
    
            var regionsOfText = data.regions;
            for (var r = 0; r < regionsOfText.length; h++) {
                var linesOfText = data.regions[r].lines;
                for (var l = 0; l < linesOfText.length; l++) {
                    var output = "";
    
                    var thisLine = linesOfText[l];
                    var words = thisLine.words;
                    for (var w = 0; w < words.length; w++) {
                        var thisWord = words[w];
                        output += thisWord.text;
                        output += " ";
                    }
                    var newDiv = "<div>" + output + "</div>";
                    outputDiv.append(newDiv);
    
                }
                outputDiv.append("<hr>");
            }
    
        }).fail(function (err) {
            $("#OutputDiv").text("ERROR!" + err.responseText);
        });
      

    This code uses jQuery to simplify selecting elements, but raw JavaScript would work just as well.

    On the page is an empty div with the id="OutputDiv"

    In the first two lines, we select this div and set its text to "Thinking…" while the web service is being called.

        var outputDiv = $("#OutputDiv");
        outputDiv.text("Thinking…");

    Next, we get the URL of the image containing the currently displayed poem and the selected language. These both come from the selected items of the two dropdowns.

        var url = $("#ImageUrlDropdown").val(); 
        var language = $("#LanguageDropdown").val();
      

    Then, we get the API key, which is in the getKey() function, which is stored in the getkey.js file. You will need to update this file yourself, adding your own key, as described in the read.me.

        try { 
            var computerVisionKey = getKey(); 
        } 
        catch(err) { 
            outputDiv.html(missingKeyErrorMsg); 
            return; 
        }
      

    Now, it's time to call the web service. My Computer Vision API service was created in the West Central US region, so I've hard-coded the URL. You may need  to change this, if you created your service in a different region.

    I add a querystring parameter to the URL to indicate the slected language.

    Then, I call the web service by submitting an HTTP POST request to the web service URL, passing in the appropriate headers and constructing a JSON document to pass in the request body.

        var webSvcUrl = "https://westcentralus.api.cognitive.microsoft.com/vision/v2.0/ocr";
        webSvcUrl = webSvcUrl + "?language=" + language;
        $.ajax({
            type: "POST",
            url: webSvcUrl,
            headers: { "Ocp-Apim-Subscription-Key": computerVisionKey },
            contentType: "application/json",
            data: '{ "Url": "' + url + '" }'
      

    Finally, I process the results when the HTTP response returns.

    JavaScript is a dynamic language, so I don't need to create any classes to identify the structure of the JSON that is returned; I just need to know the names of each property.

    The returned JSON contains an array of regions; each region contains an array of lines; and each line contains an array of words.

    In this simple example, I simply loop through each word in each line in each region, concatenating them together and adding some HTML to format line breaks.

    Then, I append this HTML to the outputDiv and follow it up with a horizontal rule to emphasize that it is the end.

        }).done(function (data) { 
            outputDiv.text("");
    
            var regionsOfText = data.regions; 
            for (var r = 0; r < regionsOfText.length; h++) { 
                var linesOfText = data.regions[r].lines; 
                for (var l = 0; l < linesOfText.length; l++) { 
                     var output = "";
    
                    var thisLine = linesOfText[l]; 
                    var words = thisLine.words; 
                     for (var w = 0; w < words.length; w++) { 
                         var thisWord = words[w]; 
                        output += thisWord.text; 
                        output += " "; 
                    } 
                     var newDiv = "<div>" + output + "</div>"; 
                     outputDiv.append(newDiv);
    
                } 
                outputDiv.append("<hr>"); 
            }
      

    I also, catch errors that might occur, displaying a generic message in the outputDiv, where the returned text would have been.

        catch(err) { 
            outputDiv.html(missingKeyErrorMsg); 
            return; 
        }
      

    Fig. 2 shows the results after a successful web service call.

    oj02-Results
    Fig. 2

    Try this yourself to see it in action. The process is very similar in other languages.

    Tuesday, June 11, 2019 9:11:00 AM (GMT Daylight Time, UTC+01:00)
    # Monday, June 10, 2019

    Episode 567

    Elton Stoneman on Docker

    Elton Stoneman describes how to manage containers using Docker on a local machine and in the cloud.

    Monday, June 10, 2019 9:52:00 AM (GMT Daylight Time, UTC+01:00)
    # Sunday, June 9, 2019

    ClaudiusTheGod"Claudius the God" continues Robert Graves's fictional translation of the Roman Emperor Claudius's autobiography that he began in "I, Claudius".

    The first novel ended with the assassination of Nero and with Claudius being unexpectedly and reluctantly elevated to Emperor.

    Claudius was born handicapped and undersized and weak and stuttering, so he remained mostly overlooked during his pre-Emperor years, avoiding the (often fatal) power struggles exercised by his family. So, he seems completely unprepared and unqualified for his role as supreme leader. Despite his initial reluctance, Claudius embraces the role, implementing his policies to modernize the Empire and sometimes executing his enemies without trial. During his 13-year reign, he successfully undoes much of the damage caused by the mad Caligula. Overall, he performed better than almost anyone expected.

    At first glance, this seems like a good deal for Claudius.

    But his life is damaged by his relationships with women - particularly with Messalina - his young and beautiful wife - who conspires against him and is unfaithful with literally hundreds of other men. After four marriages, Claudius remains unhappy.

    Once again, Graves does a good job of bringing to life the political intrigue and personal dramas of ancient Rome and her key players. Nearly everyone in this world with ambition is assassinated or plots assassinations or both. Claudius tries to stay above this and is mostly successful for most of his life.

    Previous Roman Emperors had embraced their role as god-king; but Claudius resisted this idea, insisting that he was not a god. In fact, he dreams of Rome eventually rejecting its recent incarnation as a dictatorship and returning to a Republic. His childhood friend the Hebrew king Herod Agrippa takes a different approach, declaring himself to be the prophesied Messiah and is ultimately killed for his arrogance.

    But, Claudius changes with time, as happens to so many with ultimate power. Near the end of his life, Claudius accepted his deification when he discovered the Britons were building temples to him. He begins plotting the succession of the throne - without the best interests of the Empire.

    The full title of this book is "Claudius, the God and his wife, Messalina" and Claudius's full name is Tiberius Claudius Drusus Nero Germanicus. Much like these names, Robert Graves shortens and simplifies the 13-year reign of Emperor Claudius.

    Sunday, June 9, 2019 9:11:00 AM (GMT Daylight Time, UTC+01:00)
    # Saturday, June 8, 2019

    NoLongerAtEaseIn Things Fall Apart, Chinua Achebe introduced us to Okonkwo, a west African tribesman trying to preserve his people's culture as European colonialists invaded his homeland in the late 19th century.

    Achebe's second novel - No Longer at Ease - follows the life and downfall of Okonkwo's grandson Obi decades later.

    Obi returns from a college education in England to begin a life of civil service in his homeland of Nigeria. He returns with high expectations and high ideals, but he finds himself conflicted in every part of his life.

    He wants to help his people, but he has seen the world and known many of its pleasures.

    He wants to marry Clara, but his family and the rest of society disapproves because she is an osu - an inferior caste. And he is tempted by other beauties.

    He resists the temptations of bribery, but many of his friends and colleagues are ready with rationalizations why bribes are acceptable.

    He earns far more than most Nigerians, but he finds himself overwhelmed by his expenses and constrained by the salary of a civil servant.

    Even his education presented conflict. The elders who loaned him for his education instructed him to study Law; but Obi decided he liked English better and switched majors during his tuition.

    Worse, he discovers on his return that Lagos has changed - more modern and more corrupt - from his earlier days. It is the late 1950s and the colonial era is ending and countries like Nigeria are struggling to find their new, post-colonial identity.

    Achebe brings to life the time and his characters in a lyrical, yet straightforward style. He peppers the speech of his character with frequent African proverbs.

    I loved the reference back to the first novel: The rift between Obi's father and grandfather when his father converted to Christianity, rejecting the violence of the past and beginning the family's assimilation.

    No Longer at Ease is a story of Local Culture vs Colonialism; of Idealism vs Practicality; of Individualism vs Duty; of Acceptance of Modern Christianity vs Adherence to an old caste system; and of Tradition vs Progress.

    The reader struggles with these conflicts along with Obi.

    Saturday, June 8, 2019 9:43:00 AM (GMT Daylight Time, UTC+01:00)
    # Friday, June 7, 2019

    The Microsoft Cognitive Services Computer Vision API contains functionality to infer a lot of information about a given image. One capability is to convert pictures of text into text, a process known as "Optical Characer Recognition" or "OCR".

    Performing OCR on an image is simple and inexpensive. It is done through a web service call; but first, you must set up the Computer Vision Service, as described in this article.

    In that article, you were told to save two pieces of information about the service: The API Key and the URL. Here is where you will use them.

    HTTP Endpoint

    The OCR service is a web service. To call it, you send an HTTP POST request to an HTTP endpoint. The endpoint consists of the URL copied above, followed by "vision/v2.0/ocr", followed by some optional querystring parameters (which we will discuss later).

    So, if you create your service in the EAST US Azure region, the copied URL will be

    https://eastus.api.cognitive.microsoft.com/

    and the HTTP endpoint for the OCR service will be

    https://eastus.api.cognitive.microsoft.com/vision/v2.0/ocr

    Querystring Parameters

    The optional querystring parameters are

    language:

    The 2-character language code of the text you are recognizing. This helps the service more accurately and quickly match pictures of words to the words they represent. If you omit this parameter, the system will analyze the text and guess an appropriate language. Currently, the service supports 26 languages. The 2-character code of each supported language is listed in Appendix 1 at the bottom of this article.

    detectOrientation

    "true", if you want the service to adjust the orientation of the image before performing OCR. If you pass "false" or omitting this parameter, the service will assume the image is oriented correctly.

    If you have an image with English text and you want the service to detect and adjust the image's orientation, the above URL becomes:

    https://eastus.api.cognitive.microsoft.com/vision/v2.0/ocr?language=en&detectOrientation=true

    HTTP Headers

    In the header of the HTTP request, you must add the following name/value pairs:

    Ocp-Apim-Subscription-Key

    The API key you copied above

    Content-Type

    The media type of the image you are passing to the service in the body of the HTTP request

    Possible values are:

    • application/json
    • application/octet-stream
    • multipart/form-data

    The value you pass must be consistent with the data in the body.

    If you select "application/json", you must pass in the request body a URL pointing to the image on the public Internet.

    If you select "application/json" or "application/octet-stream", you must pass the actual binary image in the request body.

    Body

    In the body of the HTTP request, you pass the image you want the service to analyze.

    If you selected "application/json" as the Content-Type in the header, pass a URL within a JSON document, with the following format:

    {"url":"image_url"}

    where image_url is a URL pointing to the image you want to recognize.

    Here is an example:

    {"url":"https://www.themeasuredmom.com/wp-content/uploads/2016/03/Slide11.png"}

    If you selected "application/octet-stream" or "multipart/form-data" as the Content-Type in the header, pass the actual binary image in the body of the request.

    The service has some restrictions on the images it can analyze.

    It cannot analyze an image larger than 4MB.

    The width and height of the image must be between 50 and 4,200 pixels

    The image must be one of the following formats: JPEG, PNG, GIF, BMP.

    Sample call with Curl

    Here is an example of a call to the service, using Curl:

    curl -v -X POST "https://eastus.api.cognitive.microsoft.com/vision/v2.0/ocr?language=en&detectOrientation=true" -H "Content-Type: application/json" -H "Ocp-Apim-Subscription-Key: f27c7436c3a64d91a177111a6b594537" --data-ascii "{'url' : 'https://www.themeasuredmom.com/wp-content/uploads/2016/03/Slide11.png'}"

    (NOTE: I modified the key, so it will not work. You will need to replace it with your own key if you want this to work.)

    Response

    If all goes well, you will receive an HTTP 200 (OK) response.

    In the body of that response will be the results of the OCR in JSON format.

    At the top level is the language, textAngle, and orientation

    Below that is an array of 0 or more text regions. Each region represents a block of text within the image.

    Each region contains an array of 0 or more lines of text.

    Each line contains an array of 0 or more words.

    Each region, line, and word contains a bounding box, consisting of the left, top, width, and height of the word(s) within.

    Here is a partial example of the JSON returned from a successful web service call:

    {
        "language": "en",
        "textAngle": 0.0,
        "orientation": "Up",
        "regions": [
            {
                "boundingBox": "147,96,622,1095",
                "lines": [
                    {
                        "boundingBox": "408,96,102,56",
                        "words": [
                            {
                                "boundingBox": "408,96,102,56",
                                "text": "Hey"
                            }
                        ]
                    },
                    {
                        "boundingBox": "282,171,350,45",
                        "words": [
                            {
                                "boundingBox": "282,171,164,45",
                                "text": "Diddle"
                            },
                            {
                                "boundingBox": "468,171,164,45",
                                "text": "Diddle"
                            }
                        ]
                    },
                    etc...
                     }
                ]
            }
        ]
    }
      

    The full JSON can be found in Appendix 2 below.

    Errors

    If an error occurs, the response will not by HTTP 200. It will be an HTTP Response code greater than 400. Additional error information will be in the body of the response.

    Common errors include:

    • Images too large or too small
    • Image not found (It might require a password or be behind a firewall)
    • Invalid image format
    • Incorrect API key
    • Incorrect URL (It must match the API key. If you have multiple services, it’s easy to mix them up)
    • Miscellaneous spelling errors (e.g., not entering a valid language code or misspelling a header parameter)

    In this article, I showed how to call the Cognitive Services OCR Computer Vision Service.

    Appendix 1: Supported languages

    zh-Hans (ChineseSimplified)
    zh-Hant (ChineseTraditional)
    cs (Czech)
    da (Danish)
    nl (Dutch)
    en (English)
    fi (Finnish)
    fr (French)
    de (German)
    el (Greek)
    hu (Hungarian)
    it (Italian)
    ja (Japanese)
    ko (Korean)
    nb (Norwegian)
    pl (Polish)
    pt (Portuguese,
    ru (Russian)
    es (Spanish)
    sv (Swedish)
    tr (Turkish)
    ar (Arabic)
    ro (Romanian)
    sr-Cyrl (SerbianCyrillic)
    sr-Latn (SerbianLatin)
    sk (Slovak)

    Appendix 2: JSON Response Example

    {
        "language": "en",
        "textAngle": 0.0,
        "orientation": "Up",
        "regions": [
            {
                "boundingBox": "147,96,622,1095",
                "lines": [
                    {
                        "boundingBox": "408,96,102,56",
                        "words": [
                            {
                                "boundingBox": "408,96,102,56",
                                "text": "Hey"
                            }
                        ]
                    },
                    {
                        "boundingBox": "282,171,350,45",
                        "words": [
                            {
                                "boundingBox": "282,171,164,45",
                                "text": "Diddle"
                            },
                            {
                                "boundingBox": "468,171,164,45",
                                "text": "Diddle"
                            }
                        ]
                    },
                    {
                        "boundingBox": "239,336,441,46",
                        "words": [
                            {
                                "boundingBox": "239,336,87,46",
                                "text": "Hey"
                            },
                            {
                                "boundingBox": "359,337,144,35",
                                "text": "diddle"
                            },
                            {
                                "boundingBox": "536,337,144,35",
                                "text": "diddle"
                            }
                        ]
                    },
                    {
                        "boundingBox": "169,394,576,35",
                        "words": [
                            {
                                "boundingBox": "169,394,79,35",
                                "text": "The"
                            },
                            {
                                "boundingBox": "279,402,73,27",
                                "text": "cat"
                            },
                            {
                                "boundingBox": "383,394,83,35",
                                "text": "and"
                            },
                            {
                                "boundingBox": "500,394,70,35",
                                "text": "the"
                            },
                            {
                                "boundingBox": "604,394,141,35",
                                "text": "fiddle"
                            }
                        ]
                    },
                    {
                        "boundingBox": "260,452,391,50",
                        "words": [
                            {
                                "boundingBox": "260,452,79,35",
                                "text": "The"
                            },
                            {
                                "boundingBox": "370,467,80,20",
                                "text": "cow"
                            },
                            {
                                "boundingBox": "473,452,178,50",
                                "text": "jumped"
                            }
                        ]
                    },
                    {
                        "boundingBox": "277,509,363,35",
                        "words": [
                            {
                                "boundingBox": "277,524,100,20",
                                "text": "over"
                            },
                            {
                                "boundingBox": "405,509,71,35",
                                "text": "the"
                            },
                            {
                                "boundingBox": "509,524,131,20",
                                "text": "moon."
                            }
                        ]
                    },
                    {
                        "boundingBox": "180,566,551,49",
                        "words": [
                            {
                                "boundingBox": "180,566,79,35",
                                "text": "The"
                            },
                            {
                                "boundingBox": "292,566,103,35",
                                "text": "little"
                            },
                            {
                                "boundingBox": "427,566,82,49",
                                "text": "dog"
                            },
                            {
                                "boundingBox": "546,566,185,49",
                                "text": "laughed"
                            }
                        ]
                    },
                    {
                        "boundingBox": "212,623,493,51",
                        "words": [
                            {
                                "boundingBox": "212,631,42,27",
                                "text": "to"
                            },
                            {
                                "boundingBox": "286,638,72,20",
                                "text": "see"
                            },
                            {
                                "boundingBox": "390,623,96,35",
                                "text": "such"
                            },
                            {
                                "boundingBox": "519,638,20,20",
                                "text": "a"
                            },
                            {
                                "boundingBox": "574,631,131,43",
                                "text": "sport."
                            }
                        ]
                    },
                    {
                        "boundingBox": "301,681,312,35",
                        "words": [
                            {
                                "boundingBox": "301,681,90,35",
                                "text": "And"
                            },
                            {
                                "boundingBox": "425,681,70,35",
                                "text": "the"
                            },
                            {
                                "boundingBox": "528,681,85,35",
                                "text": "dish"
                            }
                        ]
                    },
                    {
                        "boundingBox": "147,738,622,50",
                        "words": [
                            {
                                "boundingBox": "147,753,73,20",
                                "text": "ran"
                            },
                            {
                                "boundingBox": "255,753,114,30",
                                "text": "away"
                            },
                            {
                                "boundingBox": "401,738,86,35",
                                "text": "with"
                            },
                            {
                                "boundingBox": "519,738,71,35",
                                "text": "the"
                            },
                            {
                                "boundingBox": "622,753,147,35",
                                "text": "spoon."
                            }
                        ]
                    },
                    {
                        "boundingBox": "195,1179,364,12",
                        "words": [
                            {
                                "boundingBox": "195,1179,45,12",
                                "text": "Nursery"
                            },
                            {
                                "boundingBox": "242,1179,38,12",
                                "text": "Rhyme"
                            },
                            {
                                "boundingBox": "283,1179,36,9",
                                "text": "Charts"
                            },
                            {
                                "boundingBox": "322,1179,28,12",
                                "text": "from"
                            },
                            {
                                "boundingBox": "517,1179,11,10",
                                "text": "C"
                            },
                            {
                                "boundingBox": "531,1179,28,9",
                                "text": "2017"
                            }
                        ]
                    },
                    {
                        "boundingBox": "631,1179,90,12",
                        "words": [
                            {
                                "boundingBox": "631,1179,9,9",
                                "text": "P"
                            },
                            {
                                "boundingBox": "644,1182,6,6",
                                "text": "a"
                            },
                            {
                                "boundingBox": "655,1182,7,9",
                                "text": "g"
                            },
                            {
                                "boundingBox": "667,1182,7,6",
                                "text": "e"
                            },
                            {
                                "boundingBox": "690,1179,31,12",
                                "text": "7144"
                            }
                        ]
                    }
                ]
            }
        ]
    }
      
    Friday, June 7, 2019 9:09:00 AM (GMT Daylight Time, UTC+01:00)
    # Thursday, June 6, 2019

    GCast 51:

    Creating an Azure Container Instance

    Learn how to create an Azure Container instance from a container repository.

    Azure | GCast | IAAS | Screencast | Video
    Thursday, June 6, 2019 9:15:00 AM (GMT Daylight Time, UTC+01:00)
    # Wednesday, June 5, 2019

    The Microsoft Cognitive Services Computer Vision API contains functionality to infer a lot of information about a given image.

    As of this writing, the API is on version 2.0 and supports the following capabilities:

    Analyze an Image

    Get general information about an image, such as the objects found, what each object is and where it is located. It can even identify potentially pornographic images.

    Analyze Faces

    Find the location of each face in a video and determine information about each face, such as is age, gender, and type of facial hair or glasses.

    Optical Character Recognition (OCR)

    Convert a picture of text into text

    Recognize Celebrities

    Recognize famous people from photos of their face

    Recognize Landmarks

    Recognize famous landmarks, such as the Statue of Liberty or Diamond Head Volcano.

    Analyze Video

    Retrieve keywords to describe a video at different points in time as it plays.

    Generate a Thumbnail

    Change the size and shape of an image, without cropping out the main subject.

    Getting Started

    To get started, you need to create a Computer Vision Service. To do this, navigate to the Azure Portal, login in, click the [Create a resource] button (Fig. 1) and enter "Computer Vision" in the Search box, as shown in Fig. 2.

    cv01-CreateResource
    Fig. 1

    cv02-SearchForComputerVision
    Fig. 2

    A dialog displays, with information about the Computer Vision Service, as shown in Fig. 3.

    cv03-ComputerVisionSplashPage
    Fig. 3

    Click the [Create] button to display the Create Computer Vision Service blade, as shown in Fig. 4.

    cv04-NewSvc
    Fig. 4

    At the "Name" field, enter a name by which you can easily identify this service. This name must be unique among your services, but need not be globally unique.

    At the "Subscription" field, select the Subscription with which you want to associate this service. Most of you will only have one subscription.

    At the "Location" field, select the Azure Region in which to store this service. Consider where the users of this service will be, so you can reduce latency.

    At the "Pricing tier" field, select "F0" to use this service for free or "S1" to incur a small charge for each call to the service. If you select the free service, you will be limited in the number and frequency of calls that can be made.

    At the "Resource group" field, select a resource group in which to store your service or click "Create new" to store it in a newly-created resource group. A resource group is a logical container for Azure resources.

    Click the [Create] button to create the Computer Vision service.

    Usually, it takes less than a minute to create a Computer Vision Service. When Azure has created this service, you can navigate to it by its name or the name of the resource group.

    Two pieces of information are critical when using the service: The Endpoint and the API keys.

    The Endpoint can be found on the service's Overview blade, as shown in Fig. 5.

    cv05-OverviewBlade
    Fig. 5

    The API Keys can be found on the service's "Keys" blade, as shown in Fig. 6. There are 2 keys, in case one key is compromised; you can use the other key, while the first is regenerated, in order to minimize downtime.

    cv06-KeysBlade
    Fig. 6

    Copy the URL and and one of the API keys. You will need it to call the web services. We will describe how to make specific calls in future articles.

    Wednesday, June 5, 2019 4:46:00 PM (GMT Daylight Time, UTC+01:00)
    # Tuesday, June 4, 2019

    GeorgeClinton-1It's a good thing The Aragon Ballroom in Chicago's Uptown has such a large stage. They needed all of it to hold about 20 singers and dancers and rappers and guitarists and horns and drummers that make up George Clinton's Parliament Funkadelic.

    But even with its large size, the Aragon stage could not contain the entire band for the entire concert Friday night.   At least three musicians jumped over the front into the orchestra pit and ran out into the audience during the performance.

    Many years ago, Parliament and Funkadelic were two separate bands (although with largely the same members), but today Clinton has combined them into a single entity - Parliament Funkadelic.

    GeorgeClinton-2Clinton conducted... no, that's not the right word... Directed...? No... He more or less presided over the band's performance, stepping forward occasionally to acknowledge a performer, deliver a few lyrics, or lead the audience in handclapping. In fact, the 77-year old spent much of the concert sitting on a chair in front of the drum set.

    The show started slowly, not helped by failing sound systems and the poor acoustics of the Aragon; but Clinton gained energy as the night went on.

    The crowd expressed most delight when the band broke into their old songs - "Give Up the Funk", "Flashlight", "One Nation Under Groove", ...)

    GeorgeClinton-3With no seats on the ground floor, the audience could not help but dance, clap, and wave their hands through much of the show. It wasn't perfect, but the crowded stage delivered enough to delight those who made it out for the night.

    His health is failing, and his energy is waning, and this will likely be his last tour. But he gave what he could to the crowded ballroom audience, who waited through three warmup acts to see the Rock and Roll Hall of Famer.

    Tuesday, June 4, 2019 9:31:00 AM (GMT Daylight Time, UTC+01:00)
    # Monday, June 3, 2019

    Episode 566

    Hattan Shobokshi on TerraForm

    Hattan Shobokshi describes how to use Terraform to implement Infrastructure As Code.

    Monday, June 3, 2019 9:40:00 AM (GMT Daylight Time, UTC+01:00)
    # Sunday, June 2, 2019

    6/2
    Today I am grateful for the newly-renovated hallways in my building.

    6/1
    Today I am grateful to see George Clinton and Parliament Funkadelic in concert last night.

    5/31
    Today I am grateful to attend the AWS Summit yesterday.

    5/30
    Today I am grateful for a fresh tune-up on my new (to me) bicycle.

    5/29
    Today I am grateful to get my son moved into a new home last night.

    5/28
    Today I am grateful for good health insurance.

    5/27
    Today I am grateful to sleep in my own bed last night.

    5/26
    Today I am grateful for 4 days in Stockholm, one of Europe's great cities.

    5/25
    Today I am grateful to be invited to speak at the DevSum conference in Stockholm for the third time.

    5/24
    Today I am grateful for dinner at a Viking restaurant and fancy drinks with friends last night in Stockholm's Old City.

    5/23
    Today I am grateful for dinner last night with Jay and Mike in Stockholm.

    5/22
    Today I am grateful for 2 days in Copenhagen - my first visit to Denmark.

    5/21
    Today I am grateful for dinner and a long walk through Copenhagen yesterday with Joseph and Deidre.

    5/20
    Today I am grateful for Sunday brunch with Dave, Sue, Gary, and Debora.

    5/19
    Today I am grateful for a full day at home.

    5/18
    Today I am grateful for a week in Germany.

    5/17
    Today I am grateful for a German dinner with my team last night.

    5/16
    Today I am grateful to learn and teach DevOps with Lufthansa this week.

    5/15
    Today I am grateful for my first time staying in Germany in 31 years.

    5/14
    Today I am grateful to experience an Escape Room for the first time yesterday.

    5/13
    Today I am grateful to finally meet my team members in person.

    5/12
    Today I am grateful for:
    -the opportunity to speak at the Chicago Code Camp yesterday
    -an upgrade to Business Class on my transatlantic flight last night.

    5/11
    Today I am grateful to Hattan and Dave for answering my stupid questions the last few days.

    5/10
    Today I am grateful for dinner with Gary last night.

    5/9
    Today I am grateful for Korean burgers and Kimchi fries with Tim last night.

    5/8
    Today I am grateful to see Rev. Al Green in concert last night.

    5/7
    Today I am grateful for a bike ride last night through Chinatown, Pilsen, and the Lower West Side.

    5/6
    Today I am grateful for a visit to the Skokie Northshore Sculpture Park.

    Sunday, June 2, 2019 2:53:12 PM (GMT Daylight Time, UTC+01:00)