Georgios Papanikolaou Doodle

Today’s doodle celebrates the life of Georgios Papanikolaou, who invented the pap smear.

The Google home page looked like this with the doodle:

Here is the doodle by itself:

The doodle links to a search for his name:

Google I/O 2019 Announcement Recap

In case you missed the recent Google I/O convention, Google has a recap of their I/O announcements conveniently summarized here:
https://www.blog.google/technology/developers/100-things-we-announced-io-19/ .

I really like the new privacy features Google is rolling out, but IMO the best one is number 77 on Google’s list: All Chromebooks launched this year will be Linux-ready right out of the box. The Chromebook is great, but sometimes you need the power of a CLI.

Business Insider: Downloading Google Maps For Offline Use

This recent Business Insider article details how to download Google Maps information to your phone’s local storage, so you can use Maps even when offline or when your phone is unable to get a signal: https://www.businessinsider.com/how-to-use-google-maps-offline .

When I travel, I always have Google Maps save a map of the area I’m travelling to. It’s not always possible to have a working cell signal – in flat Illinois where I live, it’s easy to have cell signal all the time. When I travel to more mountainous regions such as Colorado, I often lose signal due to mountains and hills between me and the signal tower.

Setting Up Sendgrid To Receive Mail

I was setting up a new application to use SendGrid’s inbound parse email function, so here’s some quick documentation. In the Sendgrid dashboard, go under Settings > Inbound Parse:

Sendgrid's settings menu holds the inbound parse option.

Then click on the top blue button: Add host & URL.

Inbound parse screen on Sendgrid. Click the top blue button to continue adding inbound options for your email.

Fill in the screen that comes up with the proper domain, and subdomain (the subdomain is optional). The destination URL is where Sendgrid will POST the email to.

At the domain registrar, set up the proper MX record. Look up the appropriate documentation based on the registrar you use – this is how it looks like on GoDaddy:

Screenshot of the proper MX record on GoDaddy.

In your application, set up a handler to answer the SendGrid request: in the screenshot example above, the handler was located at /inboundmailwebhook/. Any inbound mail gets POSTed as regular form data, which most frameworks can handle automatically.

IBM Watson Natural Language Understanding

I was fiddling with code that worked with IBM Watson’s Natural Language Understanding API, and kept getting the following error:

{
    "error": "invalid request: content is empty",
    "code": 400
}

What happened is that I was calling out to IBM using the following requests Python code (post_data represents a Python object being encoded to JSON):

post_data_string = json.dumps(post_data)
requests.post(endpoint, data=post_data_string, timeout=45, auth=(ibm_user, ibm_pass))

However, it seems that the API insists on having the correct request content type set; i.e. you must set Content-Type: application/json for the IBM Watson servers to notice there is a data body in the POST request. I fixed it by using the json parameter – the requests library for Python automatically inserts the application/json content type when this parameter is used. If you use a different language, you’ll need to set the proper content type in the language’s preferred manner.

requests.post(endpoint, json=post_data, timeout=45, auth=(ibm_user, ibm_pass))

Fun With Google Maps – Solar Panel Edition

I love poking around Google Maps – there are so many unexpected things you can find that are obvious from a top-down view, but are so hard to see at a ground-level view.

I was looking at a Google Maps of the Epcot theme park in Disney World, Florida. Do you see any interesting shape in the screenshot below?

Map of Epcot, located in Disney World, Florida. Includes surroundings of Epcot.

There’s a hidden Mickey in the top left hand corner! The three black circles are arranged into the shape of Mickey Mouse’s head! See the screenshot below for detail:

Google Maps picture of solar panels forming the head of Mickey Mouse.

If you zoom in enough on Google Maps, you’ll notice that this is actually an array of solar panels, generating electricity to feed the Disney theme parks. Notice that there seems to be a dirt access road to the panels and a fence around the entire array. As I said before: this solar panel array would be difficult to see in person, much less the general shape of it; but with Google Maps, the difficult becomes so obvious!

Firestore Add Document – Python

A simple example of adding a document to the Firestore:

    from google.cloud import firestore
    
    #Make a note in the firestore
    firestore_client = firestore.Client()
    doc_ref = firestore_client.collection(u'CollectionsNameHere').add({
        u'propertyone': u'thisisavalue',
        u'propertytwo': 2,
    })
    logging.warning(doc_ref[1].id)

.add returns a tuple of the date that the document was written into the firestore, and a document reference to the written document. .add lets Firestore create a document ID to the written document: to figure out what the ID is, the last line accesses the tuple and pulls out the document ID.

An item that bit me: the official documentation for Firestore states that .add and .doc().set() are equivalent. That’s true, but the returns from both of those functions are different.

Documentation from Google showing .add and .doc.set are the same operation.

.add returns a tuple of the document creation time and then a reference to the added document. However, .set returns a WriteResult, not a tuple. The WriteResult contains the time the document was updated/set in the property update_time. Make sure to use the correct function as necessary.

Set Documentation

Set Documentation - Firestore
WriteResult documentation - Firestore.

Add Documentation

Add documentation - Firestore