Gell-Mann Amnesia Effect

The Gell-Mann Amnesia Effect is, simply put,

I believe everything the media tells me except for anything for which I have direct personal knowledge, which they always get wrong.  source

Formulated by Michael Crichton, is named after Murray Gell-Mann, an astrophysicist.  (said Mr. Crichton, “I refer to it by this name because I once discussed it with Murray Gell-Mann, and by dropping a famous name I imply greater importance to myself, and to the effect, than it would otherwise have.”)

Mr. Crichton explained it further in a 2002 speech, “Why Speculate?

Briefly stated, the Gell-Mann Amnesia effect is as follows. You open the newspaper to an article on some subject you know well. In Murray’s case, physics. In mine, show business. You read the article and see the journalist has absolutely no understanding of either the facts or the issues. Often, the article is so wrong it actually presents the story backward – reversing cause and effect. I call these the “wet streets cause rain” stories. Paper’s full of them.

In any case, you read with exasperation or amusement the multiple errors in a story, and then turn the page to national or international affairs, and read as if the rest of the newspaper was somehow more accurate about Palestine than the baloney you just read. You turn the page, and forget what you know.

That is the Gell-Mann Amnesia effect. I’d point out it does not operate in other arenas of life. In ordinary life, if somebody consistently exaggerates or lies to you, you soon discount everything they say. In court, there is the legal doctrine of falsus in uno, falsus in omnibus, which means untruthful in one part, untruthful in all. But when it comes to the media, we believe against evidence that it is probably worth our time to read other parts of the paper. When, in fact, it almost certainly isn’t. The only possible explanation for our behavior is amnesia.

RIP, Mr. Crichton.

 

The General

We all went to see The General at The Cabot, back by a live musical performance.

The General is (very loosely) based on a real-life train theft during the Civil War, but it’s played to some drama and comedy by a prime Buster Keaton.

The true story is that a group of Union spies stole a Confederate train (which was, in fact, named The General) with a plan to damage the rails and generally cause mayhem on their way back to friendly territory.  It didn’t quite work out as planned because they were pursued and (eventually) caught.

The cinematic version takes a few artistic liberties to entertain and “wow” the audience with stunts, as well as adding a love interest and a human side.  It’s considered one of Mr. Keaton’s finest works, and “[he] always said that this was his favorite of his own movies.” (source)  It’s an amazing film to watch, moreso when you realize that the stunts were real, frequently filmed in one take, and as hazardous in real life as they are in the story.

The film that we watched was from a restoration made in 2016, with a new musical arrangement that was played live.  The quality of the film is very good, better than the gif above, while alive music accompaniment is the way it was meant to be enjoyed.

The Cabot is a restored theater in downtown Beverly, MA.  It contains many of the artistic features one would expect from a classic venues.  We had center seats and a great view.  This was our first visit, but won’t be our last.

Photo: © Lauren Poussard

Owls!

I stepped outside with the dog while she did her business and stayed for a minute to look at a “spoke” pattern in the clouds, when I heard an Eastern Screech Owl nearby.

It took me a few minutes to identify it when I got back inside, but my Google-fu is strong today.  The call is a “tremolo” which mated pairs and families use to keep in touch.  I heard it repeat several times.

More information here

Super-Quick Teriyaki Chicken

Ingredients

Sauce

  • 1/3 c. soy sauce
  • 1/4 c. rice wine vinegar
  • 1 tsp. sesame oil
  • 1 1/2 tbsp. honey
  • 2 cloves garlic, minced
  • 2 tsp. finely minced fresh ginger
  • 2 tsp. cornstarch

Everything Else

  • Extra-virgin olive oil
  • 1 lb. boneless skinless chicken breasts, cut into bite-sized pieces
  • Salt and pepper to taste
  • Sliced green onions, for garnish

Steps

  1. Mix the sauce
    1. In a medium bowl, combine:
      • soy sauce
      • vinegar
      • sesame oil
      • honey
      • garlic
      • ginger
      • cornstarch
    2. Whisk until smooth.
  2. Heat oil in a large skillet over medium heat
  3. Add chicken to skillet and season with salt and pepper. Cook until golden and almost cooked through, about 10 minutes.
  4. Pour sauce over chicken and simmer until sauce has thickened slightly and chicken is cooked through.

Goes really well with rice and a veggie.

Originally from https://www.delish.com/cooking/recipe-ideas/recipes/a54003/easy-teriyaki-chicken-recipe/

The Orient Express

My parents upgraded their house, and that included a new elevator to replace their aging stair-chair.

This is the same stair-chair that earned the name ‘The Orient Express’ while we were in high school and Kennon had a house party (without my parents’ knowledge).

Fortunately the stair-chair was not removed after the elevator was installed. Scientific curiosity demanded that we expand human knowledge and answer the burning question: which way is faster?

Kennon and I agreed on the rules: we start at the same place; we would end at the same point on the second floor; both elevators would start at the ground floor; we would walk, not run. Kennon and I both agreed that the stair-chair would probably win.

Meghan was kind enough to take a video of the race.

Results: The stair-chair won by a full second.  A second race was not conducted due to technical difficulties with the stair chair.

Sactional Review, revisited

It has been close to three years since I wrote my original Lovesac Sactional review, so I figured this would be a good time for an update to the review.

We still have the original pieces, plus we’ve added some more: a couple of more bases and backs to make a pair of armless chairs for the dining room, plus a third base for the original ‘couch’ in the living room to make an ‘L’.

  • Our covers have (mostly) held up well.
    • We’ve run some of the covers through the wash a couple of times in order to clean some stairs and general dirt – try that with a regular sewn-on cover!
    • One cover has a thread that started to come out, but it didn’t keep unthreading – it has been stable for a year.  I try to keep that cover away from the heaviest-used sections.
    • We’ve been considering buying a different style of cover, and a bit darker; the standard cover can be a little rough after a while, and the light color that we got shows off dirt.  But oh, the cost!  We’re keeping an eye on sales, which seem to come up periodically.
  • We definitely tell which cushions are newer, as they’re firmer.
    • The cushions seem to firm up a bit if they’re not used.
    • Cushion rotation is a must, but that’s easy.
  • The bases:
    • do get easier to separate over time.
    • are so low to the ground that they don’t capture much trash, which is awesome
    • are not too heavy to slide, and the felt pads do prevent scratching.

Perl’s Open3, Re-Explained

I recently went spelunking into a core Perl module that I previously knew nothing about, IPC::Open3.  After fifteen years of developing in Perl I finally had a reason to use it.

If you’re reading this, it’s probably because you went looking for information on how to use open3 because the module’s documentation is bad.  I mean it’s really, really terrible.

Not only will you not know how to use open3 after reading the docs, you may become convinced that maybe open3 isn’t the module that you need, or maybe it would work but you’d just be better off looking for something else because this is too damn hard to use.

Fear not, intrepid reader, because if I can figure it out so can you.  But I will try to save you some of the leg work I went through. There’s precious little information scattered online, because this isn’t a popular package.  My loss is your gain, hopefully this helps you.

Why IPC::Open3?

When Would I Use IPC::Open3?

open3 is used when you need to open three pipes to another process.  That might be obvious from the name as well as the package’s synopsis:

$pid = open3( \*CHLD_IN,
              \*CHLD_OUT,
              \*CHLD_ERR,
              'some cmd and args',
              'optarg', ...
            );

Why would you do that?  The most obvious situation is when you want to control STDIN, STDOUT, and STDERR simultaneously.  The example I provide below, which is not contrived by the way but adapted from real production code, does exactly that.

There Are Lots Of Modules To Make This Easier, Why Should I Use IPC::Open3?

IPC::Open3 is part of the Perl core.  There’s a lot to be said for using a library that’s already installed and doesn’t have external dependencies vs. pulling in someone’s write-once-read-never Summer of Code academic project.

In addition, the modules that I found only served to hide the complexity of Open3, but they did it badly and didn’t really remove much code compared to what I came up with.

What Else Do I Need?

One of the things that’s not obvious from the Open3 docs are that you’re not going to use IPC::Open3 by itself.  You need a couple of other packages (also part of core) in order to use it effectively.

How I Used IPC::Open3

In our example, we’re going to fork a separate process (using open3) to encrypt a file stream using gpg.  gpg will accept a stream of data, encrypt it, and output to a stream.  We also want to capture errors sent to STDERR.

In a terminal, using bash, this would be really easy: gpg --decrypt < some_file > some_file.pgp 2>err.out

We could do all of this in Perl by writing temporary files, passing special file handle references into gpg as arguments, and capturing STDERR the old fashioned way, all using a normal open().  But where’s the fun in that?

First, lets use the packages we’ll need:

use IO::Handle;
use IO::Select;
use IPC::Open3;

IO::Handle allows us to operate on handles using object methods.  I don’t typically use it, but this code really appreciates it.  IO::Select does the same for select, but it helps even more than IO::Handle here.

use constant INPUT_BUF_SZ  => 2**12;
use constant OUTPUT_BUF_SZ => 2**20;

You might want to experiment to find the best buffer sizes.  The input buffer should not be larger than the pipe buffer on your particular system, else you’ll block trying to put two pounds of bytes into a one pound buffer.

Now, using IO::Handle we’ll create file handles for the stdin, stdout, and stderr that our forked process will read and write to:

my ( $in,
     $out,
     $err,
   ) = ( IO::Handle->new,
         IO::Handle->new,
         IO::Handle->new
       );

Call open3, which (like fork) gives us the PID of our new process.

Note: If we don’t call waitpid later on we’ll create a zombie after we’re done.

my $pid = open3( $in, $out, $err, '/usr/bin/gpg', @gpg_options );

if ( !$pid ) {
    die "failed to open pipe to gpg";
}

One of the features of IO::Select is that it allows us to find out when a handle is blocked. This is important when the output stream is dependent on the input stream, and each stream depends on a pipe of limited size.

We’re going to repeatedly loop over the handles, looking for a stream that is active, and read/write a little bit before continuing to loop.  We do this until both our input and output is exhausted.  It’s pretty likely that they’ll be exhausted at different times, i.e. we’ll be done with the input sometime before we’re done with the output.

As we exhaust each handle we remove it from the selection of possible handles, so that the main loop terminates naturally.

The value passed to can_write and can_read is the number of seconds to wait for the handle to be ready.  Non-zero timeouts cause a noticeable delay, while not setting it at all will cause us to block until the handle is ready, so for now we’ll leave it at zero.

# $unencrypted_fh and $encrypted_fh should be defined as
# handles to real files

my $sel = IO::Select->new;

$sel->add( $in, $out, $err );

# loop until we don't have any handles left

while ( my @handles = ( $self->handles) ) {
    # read until there's nothing left
    #
    # write in small chunks so we don't overfill the buffer
    # and accidentally cause the pipe to block, which will
    # block us
    while ( my @ready = ( $sel->can_write(0) ) ) {
        for my $fh ( @ready ) {
            if ( $fh == $in ) {
                # read a small chunk from your source data
                my $read = read( $unencrypted_fh,
                                 my $bytes,
                                 INPUT_BUF_SZ,
                               );

                # and write it to our forked process
                #
                # if we're out of bytes to read, close the
                # handle
                if ( !$read ) {
                    $sel->remove( $fh );
                    $fh->close;
                }
                else {
                    syswrite( $fh, $bytes );
                }
            }
            else {
                die "unexpected filehandle for input";
            }
        }
    }

    while ( my @ready = ( $sel->can_read(0) ) ) {
        # fetch the contents of STDOUT and send it to the
        # destination
        for my $fh ( @ready ) {
            # this buffer can be much larger, though in the
            # case of gpg it will generally be much smaller
            # than the input was. The process will block if
            # the output pipe is full, so you want to pull as
            # much out as you can.

            my $read = sysread( $fh, my $bytes, OUTPUT_BUF_SZ );

            if ( !$read ) {
                $sel->remove( $fh );
                $fh->close;
            }
            elsif ( $fh == $out ) {
                # $encrypted_fh is whatever we're throwing output
                # into

                syswrite( $encrypted_fh, $bytes ) if $read;
            }
            elsif ( $fh == $err ) {
                print STDERR $bytes;
            }
            else {
                die "unexpected filehandle for output";
            }
        }
    }

    # IO::Handle won't complain if we close a handle that's
    # already closed
    $sel->remove( $in ); $in->close;
    $sel->remove( $out ); $out->close;
    $sel->remove( $err ); $err->close;

    waitpid( $pid, 0 );
}

That’s actually about it.

I keep my buffer for input small, as pipe buffers tend to be small.  If you overload your pipe your program will hang indefinitely (or until an alarm goes off, if you set one).  4096 bytes seems to be the limit, though your own limit may be different.  When in doubt, be conservative and go smaller.

The output buffer can afford to be bigger, up to the limit of available memory (but don’t do that).  In our example of encryption gpg will consume much more than it produces, so a larger buffer doesn’t really buy you anything but if we were decrypting it would be the reverse and a larger buffer would help immensely.