# 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)
# Saturday, June 1, 2019

ThingsFallApartThings Fall Apart by Chinua Achebe tells the story of Okonkwo, a self-made man of the Umuofia clan in pre-colonial West Africa. Okonkwo worked hard to overcome the reputation of his lazy and cowardly father, who died with numerous debts. Okonkwo rose from poverty until he had acquired 3 wives, 10 children, a successful farm, and a position of respect and leadership among the clan.

But Okonkwo was also hot-tempered and violent: he would beat his wives and children when they displeased him, and his great strength made him feel he could and should use violence to settle disputes.

His rise to power was interrupted when he accidentally killed a fellow tribesman and was exiled for seven years for this crime. When he returned to the clan, everything had changed:  British colonists have arrived, bringing with them their culture, their laws, and their religion. The society that Okonkwo knew began to disappear, as it was subsumed by the colonists.

Unlike many English novels of this period, Things Fall Apart tells the story of the colonization of Africa from the point of view of the Africans. We see the indigenous people's respect for their ancestors and their focus on doing what is best for the community as a whole; and we see the unpleasantness of their society, such as the killing of a youth to placate angry gods.

We learn about Okonkwo - his strengths and his weaknesses. He is admired for his hard work and his sense of duty; but we also witness his uncontrolled rage and his intolerance.

The point is that we see the complexity of their society - not the ignorant savages so often portrayed by Westerners to justify their methods of "education" and "liberation".

Okonkwo was not a likeable man. But he had his principles and stuck to them, until his world was turned upside down by outsiders. And Achebe leads us toward his inevitable destruction.

Saturday, June 1, 2019 9:58:00 AM (GMT Daylight Time, UTC+01:00)