Scala, Java, Unix, MacOS tutorials (page 131)

Makezine.com has a little article on Google’s AIY kits (DIY machine learning kits), including their Voice and Vision AI kits being for sale at Target. Google also has a terrific page that shows how to put the Voice kit together.

Here’s a great 1999 interview with Jeff Bezos on YouTube. And here’s a transcript of an interview with James Comey, where he says, “so much of what I’ve tried to do as a leader is guardrail around what I think my weaknesses are. Really important to me that I avoid the danger — which I think all humans have, but I know I have — of falling in love with my own view of things, my own righteousness.”

“The new basic principle is that in order to learn to avoid making mistakes, we must learn from our mistakes. To cover up mistakes is, therefore, the greatest intellectual sin.”

~ Karl Popper (a quote from Farnam Street Blog)

If you happen to need a Scala method to perform an MD5 hash on a string, I believe this method works as desired:

// returns a 32-character MD5 hash version of the input string
def md5HashPassword(usPassword: String): String = {
    import java.math.BigInteger
    import java.security.MessageDigest
    val md = MessageDigest.getInstance("MD5")
    val digest: Array[Byte] = md.digest(usPassword.getBytes)
    val bigInt = new BigInteger(1, digest)
    val hashedPassword = bigInt.toString(16).trim
    prependWithZeros(hashedPassword)
}

/**
 * This uses a little magic in that the string I start with is a
 * “format specifier,” and it states that the string it returns
 * should be prepended with blank spaces as needed to make the
 * string length equal to 32. Then I replace those blank spaces
 * with the character `0`.
 */
private def prependWithZeros(pwd: String): String =
    "%1$32s".format(pwd).replace(' ', '0')

In case you’re worried about artificial intelligence (AI), there’s this:

Me: Alexa, cancel the current timer.

Alexa: I don’t have a timer called “current,” but there is one called “Fifteen minute timer.”

Me: *sigh*

If you need to handle a unique constraint in a database table field when writing an add or edit process in a Play Framework application, I hope this example will be helpful. In the end I’ll show:

  • How to write a Play Anorm query that performs a SQL INSERT on a database field that has a unique constraint
  • How to write a Play controller method (Action) that handles that SQL exception
  • How to create a new Form after you catch that exception
  • How to add custom error messages to that form
  • How to redirect control back to your Play template

If you need to see any of those things, I hope the following example is helpful.

The database method

In my case I’m writing a URL-shortening application and I have a unique constraint on a table column named short_uri, so I wrote my database-insert method with Anorm to look like this:

// uses Try b/c `short_uri` has a unique constraint, which can cause an exception
def insertNewUrl(u: Url): Try[Option[Long]] = db.withConnection { implicit c =>
    Try {
        val q = SQL"""
        insert into urls (user_id,long_url,short_uri,notes)
        values (1,${u.longUrl},${u.shortUrl},${u.notes})
    """
        q.executeInsert()  //returns the primary key as an Option
    }
}

I catch the possible unique constraint exception with Try. Because executeInsert returns the primary key inside an Option, this method returns the type Try[Option[Long]]. The key here for the purpose of this example is that the SQL INSERT can fail because of the unique constraint, so I handle the possible exception with Try.

The controller method/action

For me, the harder part in this case is to know what to do in your controller action code. I’m not going to try to explain it all, I’m just going to show my code, and then offer a little explanation:

def handleAddFormSubmission = authenticatedUserAction { implicit request =>
    val formDidNotValidateFunction = { formWithErrors: Form[Url] =>
        BadRequest(views.html.editUrl(0, formWithErrors, addFormSubmitUrl))
    }
    val formValidatedFunction = { data: Url =>
        // form data is valid, try saving to the database
        val url = Url(
            data.id,
            data.longUrl,
            data.shortUrl,
            data.notes
        )
        // there’s a Try here b/c a SQL INSERT can fail due to database constraints
        val pkInOptionInTry: Try[Option[Long]] = urlDao.insertNewUrl(url)
        pkInOptionInTry match {
            case Success(maybePk) => {
                // no exception was throw, so `maybePk` probably has the primary key
                Redirect(routes.UrlAdminController.list())
                    .flashing("info" -> s"URL '${data.shortUrl}' was added.")
            }
            case Failure(e) => {
                // an exception was thrown, so the SQL INSERT failed, probably a duplicate key error
                val formBuiltFromRequest: Form[Url] = form.bindFromRequest()
                val newForm = formBuiltFromRequest.copy(
                    errors = formBuiltFromRequest.errors ++ Seq(
                        FormError("short_uri", "Probably have a duplicate URI in the database."),
                        FormError("short_uri", e.getMessage)
                    )
                )
                BadRequest(views.html.editUrl(0, newForm, addFormSubmitUrl))
            }
        }
    }
    val formValidationResult: Form[Url] = form.bindFromRequest
    formValidationResult.fold(
        formDidNotValidateFunction,
        formValidatedFunction
    )
}

One big key in this method is knowing that you can use Try to easily handle the exception that can be returned by the database access method.

Creating a new Play Form after the error

A second big key is knowing that you can rebuild a Form with either of these two approaches:

val newForm: Form[Url] = form.bindFromRequest()
val newForm: Form[Url] = form.fill(data)

I haven’t looked into the differences between those two possible approaches, but it took me a while to figure out those approaches, so hopefully that knowledge will save someone else time in the future. The key here is that you need to build a new form after the exception that you can pass to your template, and this is how you do that.

Adding custom error messages to the form

Another big key was find out that methods like form.withError(...) and form.withGlobalError(...) don’t work as expected, so I had to write code like this to get my custom error messages to show up in the Play template:

val newForm = formBuiltFromRequest.copy(
    errors = formBuiltFromRequest.errors ++ Seq(
        FormError("short_uri", "Probably have a duplicate URI in the database."),
        FormError("short_uri", e.getMessage)
    )
)

You probably only need one error message there, but since I’m writing this application for myself I don’t mind seeing the output from e.getMessage. Note that this approach binds those error messages to the short_uri field in the template.

The Play template

You might not need to see the Play Framework template to understand what I just showed, but it may help to see the template code, so here it is:

@(
    urlId: Long,
    form: Form[Url],
    postUrl: Call
)(implicit request: RequestHeader, messagesProvider: MessagesProvider)

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")">
    <link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/admin.css")">
</head>

<body id="edit-url">
<div id="content">

    <div id="edit-url-form">

    <h1>URL Shortener</h1>

    @* Flash shows updates to a page *@
    @request.flash.data.map{ case (name, value) =>
        <div>@name: @value</div>
    }

    @* Global errors are not tied to any particular form field *@
    @if(form.hasGlobalErrors) {
        @form.globalErrors.map { error: FormError =>
            <div>
                Error: @error.key: @error.message
            </div>
        }
    }

    @helper.form(postUrl, 'id -> "blog-edit-form") {
        @helper.CSRF.formField

        @* id is 0 for 'add', and is set by the 'edit' process *@
        <input type="hidden" name="id" value='@urlId'>

        @helper.inputText(
            form("long_url"),
            '_label -> "Long URL",
            'placeholder -> "the original, long url",
            'id -> "long_url",
            'size -> 68
        )
        @helper.inputText(
            form("short_uri"),
            '_label -> "Short URI",
            'placeholder -> "the short uri you want",
            'id -> "short_uri",
            'size -> 68
        )
        @helper.textarea(
            form("notes"),
            '_label -> "Notes",
            'id -> "notes",
            'rows -> 5,
            'cols -> 60
        )
        <button>Save</button>
    }

    </div>

</div>

</body>
</html>

I’m not going to bother to explain that code at all, other than to say that the short_uri field in the template is where my custom error message will show up.

As a final note, here’s what those custom form error messages look like in the template (a data-entry form):

The Play Framework form template custom error messages

Summary

In summary, if you wanted to see how to handle Play Framework things like how to handle a SQL exception related to a unique constraint violation; how to create a new form after an exception like that; and how to add custom error messages to a Play form, I hope this example is helpful.

I don’t take too many photos of traffic intersections, but this is a favorite view of Boulder, Colorado and the Rocky Mountains. In this image I am on South Boulder Road, with the city of Boulder directly ahead.

A favorite view of Boulder, Colorado and the Rocky Mountains

Scala FAQ: How do I append or prepend one or more elements to a Vector or Seq class?

Solution

To append or prepend one or more elements to a Vector or Seq, use these methods:

Wow, in the last 48 hours Twitter, GoDaddy, Etsy, and other websites/businesses have sent me emails saying that their privacy policies have changed. The stuff Facebook has gone through (or created, depending on your perspective) seem to be having a rapid ripple effect on the industry.

On April 22, 2018, the Mosaic web browser — the internet’s first major web browser — turned 25 years old. And I’m old enough to remember using it. (Image from this tweet.)

The Mosaic web browser turned 25

As a quick note, here’s a Java method that will round a float to the nearest half value, such as 1.0, 1.5, 2.0, 2.5, etc.:

/**
 * converts as follows:
 * 1.1  -> 1.0
 * 1.3  -> 1.5
 * 2.1  -> 2.0
 * 2.25 -> 2.5
 */
public static float roundToHalf(float f) {
    return Math.round(f * 2) / 2.0f;
}

The comments show how this function converts the example float values to their nearest half value, so I won’t add any more details here. I don’t remember the origin of this algorithm — I just found it in some old code, thought it was clever, and thought I’d share it here.

From a recent email:

Paraprosdokians are figures of speech in which the latter part of a sentence or phrase is surprising or unexpected; frequently humorous. Winston Churchill loved them.
 
1. Where there's a will, I want to be in it.
2. The last thing I want to do is hurt you. But it's still on my list.
3. Since light travels faster than sound, some people appear bright until you hear them speak.
more ...

“Complaining is not a strategy. You have to work with the world as you find it, not as you would have it be.”

~ Jeff Bezos

If you struggle to learn new things, check out this podcast interview with Barbara Oakley. A few years ago I read her book, A Mind for Numbers: How to Excel at Math and Science (Even If You Flunked Algebra), and it was helpful to me, and even influenced my book, Functional Programming, Simplified.

As I noted five days ago, Mollom went out of business so I had to switch this Drupal 8 website to use a different module to control comment spam. I ended up adding two modules that work together, but the side effect of using their best features is that they end up disabling Drupal 8 page caching. This image clearly shows the result that disabling page caching has on CPU use.

Disabling Drupal 8 page caching significantly increases CPU use

“People have a voracious appetite for a better way, and yesterday’s ‘wow’ quickly becomes today’s ‘ordinary.’”

~ Jeff Bezos, Amazon, in his 2017 (2018?) letter to shareholders

In a slightly related note I find that work is easier when you have the attitude that what you’re working on is constantly changing, constantly evolving. If one day you think, “There it is, Product 1.0, I’m done,” you’ll find it mentally hard to come into the office tomorrow to work on the same product. The only constant is change, and if you accept that your job is to be in that process of change, life and work are easier.

As shown in the image, the project known as Dotty will be Scala 3.0.

Dotty will become Scala 3.0

It’s kind of neat when you get royalty checks in multiple currencies. :)

(But one drawback to receiving physical checks is that most tellers here don’t know what to do with them. Each time I’ve received checks in foreign currencies it’s taken 15-30 minutes to deposit them at the local bank.)

Royalty checks in multiple currencies

I like both parts of this tweet. I try to help other people where I can, but in the end you can’t take responsibility for what the other person does or doesn’t do.

Peace requires us to surrend our illusions of control

In general the online Play Framework documentation is excellent, but one area where I needed more help was in seeing more examples of the Anorm syntax. To that end, here are some Anorm query examples, taken from a Play Framework application I worked on recently. But first, a little background about Anorm.