Getting to Know Your City

by Matt Blair on November 19, 2011

I’ve lived in or near downtown Portland for nearly ten years now. I spend most of my time in the city on foot, and yet I can still walk down just about any street and find some detail I haven’t noticed before: a curve in a street for no obvious reason, an ornamental feature on a storefont that doesn’t match anything else in sight, a streetcar track peeking up between brick streets, or the remnants of a sign painted directly on a brick wall decades ago.

I see these traces of the past, but I don’t understand them. Our city has a rich history, but we need some way to unlock it.

About a year and a half ago, I was in the process of brainstorming projects related to the City of Portland’s Civic Apps Challenge. At that time, a history app was at the top of my short list of projects. I could imagine what the project would look like and how I could build it, but it was missing the most essential element: history.

There were a few lists of historic places available, but they were thin on details: address, year built, and maybe the name of an architect’s name or firm.

It wouldn’t have been hard to package these lists as an app, but 600+ dots on a map without any cultural, social or historical context just didn’t seem that compelling to me. One source included architectural styles, and I thought about trying to tie that into Wikipedia, but it still didn’t seem all that appealing, especially since the related Wikipedia entries were so varied in quality and availability.

If I was going to spend the time required to build a great app, I wanted to make these locations come alive with story, context, voice and narrative. I wanted to go deeper: Who lived here? What were their lives like? Why did people leave, and who moved in after them – or displaced them? How has the neighborhood changed? What made this city what it is today? You can’t really get much of that from addresses and names alone.

As I imagined ways to build on these lists, I quickly realized that it was becoming a book-sized project. I even wrote a blog post seeking collaborators. I’m not experienced in doing historical research, and I would have been starting from almost nothing. It could take years for me to figure out how to do it well on my own.

With no obvious sources for these stories and narratives, no funding, and lots of other projects in progress, I shelved the idea. I still wanted to create apps that encouraged people to get outside, to walk and explore the streets of this city, and to notice the unnoticed (my ‘urban rambling’ series) but I chose to focus on PDX Trees and Public Art PDX.

A few months later, Max Ogden introduced me to Marc Moscato, director of the Dill Pickle Club, a non-profit which has been leading tours, hosting lectures and reprinting books about many facets of Portland’s past, present and future for the last couple of years. They have relationships with a range of experts who have a detailed knowledge of this region’s history.

Marc outlined a challenge that the DPC staff and board had been discussing: How could they preserve the experiences of their tours and lectures – most of which were only given one time – and make them available to a broader audience?

It’s been nearly a year since that dialogue began, and we’ve spent many many hours imagining and refining the project, with insightful feedback from a lot of different members of the community.

The app and mobile website we’ve planned will be far more than just another downtown guidebook. It’s not just one history of Portland – it’s about many interwoven histories – and it will highlight the diversity of the communities that have lived and worked in downtown Portland, and the neighborhoods they built over the last 150+ years.

Since working on this project, I’ve learned about the Greek community in Old Town/Chinatown, one of many communities featured on SuEnn Ho’s bronze plaques:

A photo of commemorating the Greek community

Bronze plaques in Portland's Old Town/Chinatown

(Photos by James Wilson, who also shot our Kickstarter video)

I’ve learned that Portland’s Japantown once covered a few dozen blocks north and south of Burnside, as shown by this fantastic model in the window of the Oregon Nikkei Legacy Center:

A photo of the model of Japantown at the Oregon Nikkei Legacy Center

Part of the Japantown model

I’ve learned that the New Market Block building, in addition to being one of the best remaining examples of cast-iron architecture on the West Coast, was also inspired by a building in St. Mark’s Square in Venice:

A photo of the New Market Block, built in 1872

New Market Block, built in 1872

And I’ve learned that the Golden West Hotel on the corner of NW Everett and Broadway was built more than 100 years ago to serve African-Americans who worked on the transcontinental railroad:

A photo of the Golden West Hotel

Golden West Hotel

I didn’t know any of this until we started talking to the experts who will contribute to this project. And that’s why we’re doing it.

We’re asking Elias Foley to record and edit high-quality, well-indexed interviews of these experts and historians telling the stories of their neighborhoods and cultures. We’re asking Kate Bingaman-Burt to create illustrations that will give the app a distinct visual character. And our budget includes an honorarium for each of the experts who will contribute, and everyone else who participates in the project. (For the full budget, see our Kickstarter page.)

The project is so much more than an app. In fact, the app budget is only 30% of our fund-raising goal. How can we build an app for that price? It’s simple: we can’t.

Everyone on our team is working on this at a fraction of standard industry rates because we all believe in the importance of this project. We believe that understanding more about our past is essential to the process of deciding who we want to be in the future.

And that’s where you come in: You can help us make this happen by supporting our Kickstarter campaign. All the members of our team are located in Portland, so your pledge supports local artists, working in the local economy.

Please don’t wait: the campaign ends December 5th.

{ 0 comments }

Sending Location Adjustments from iOS to CouchDB

by Matt Blair on March 1, 2011

I’ve been a fan of Portland’s Public Art collection since I first visited the city twelve years ago. Over the last few months, I’ve been working with the Mayor’s office and the Regional Arts & Culture Council to build a map-based iOS app that showcases this art and presents it to a wider audience.

And now, it’s here: Public Art PDX is available for download from the App Store.

Update: Don’t miss the launch video the Mayor’s office put together!

Over the next few weeks, I’ll be blogging about various technical aspects of the project. In this post, I’m going to go into detail about collecting location adjustments from iOS devices.

Where is it, exactly?

The public art data, originally gathered by RACC, was released by the city of Portland as part of the Civic Apps Challenge.

Each record had been automatically geo-coded by address. In many cases, this meant that the coordinates in the database were hundreds or even thousands of meters away from the actual location of the works of art:

An arrow shows the distance between the geo-coded location and actual location, which is just over a kilometer.

Just over a kilometer

The distance between the original geo-coded location of this sculpture and its actual location is just over a kilometer (about two thirds of a mile) as the crow flies, and more than twice that if you walk or drive the road between the two.

With over 400 works of art in the initial dataset, and hundreds more on the way, neither I nor the agencies involved have the capacity to visit and verify all these locations — but our audience does.

In each of my open data projects, I’ve started with the question: How can we put this data into the hands of citizens and visitors in a way that is compelling, engaging and participatory? Crowd-curation of location seemed like a great way to get people actively involved in the initial release of this particular app.

Today’s mobile devices allow someone using an app to send in very accurate locations without ever seeing coordinate values or ID numbers.

In the case of location adjustments, this meant that I could give app users a way to submit corrections to the dataset without ever exposing them to the underlying complexity of UUIDs, negative longitude, significant digits, etc. These kinds of things don’t intimidate technical users, but they could be a barrier to participation for many people who will use this app.

The mobile device is only half the story, though: It doesn’t matter how easy it is to send data if you can’t receive and manage it. That’s where Couch comes in.

Building an API

I’ve used Django to build web and intranet applications in the past, but it does not support building RESTful APIs natively. While working on PDX Trees I found the most popular third-party module for REST unmaintained and problematic, especially for submitting data with POST requests. I got it to work, after lots of troubleshooting and patching, but it was not an experience I was eager to repeat. I don’t like deploying duct-taped code that might break when installing the next security patch or minor framework release.

I learned a little about CouchDB (and GeoCouch) while using Max Ogden’s PDXAPI, and decided to give it a try.

CouchDB is a document database that stores each document as JSON, and makes them available via HTTP verbs like GET and POST. Making an API to receive data is simple: you just create a new database, configure any read-write permissions you need, and submit JSON to it. It’s that easy.

For example, posting data from the command line using curl looks like this:

curl -d '{"aKey": "aValue" }' --header "Content-Type: application/json"
     -vX POST http://youraccount.couchone.com/yourdb

Or, if you have JSON data in a text file:

curl -d @some-data.json --header "Content-Type: application/json"
     -vX POST http://youraccount.couchone.com/yourdb

Couch DB has been used in a wide variety of production deployments, it is easy to backup through replication and it adapts easily to changing data and metadata needs. I’m using  CouchBase for this project, which is excellent in terms of scalability and maintenance. I’m a big fan of hosted open-source solutions: letting experts manage the server allows me to focus on my data and how I present it in the app.

The iOS Interface

Now that I had a cloud-based service ready to receive data, I needed to provide a way for people to make the adjustments and send them.

When the app displays details about a specific work of art, it adds a map marker icon next to the location information if the coordinates in the database have not been verified:

Ghost Ship Detail View, with a pin icon next to the location information

Ghost Ship Detail View, with adjustment icon in lower right

If an app user taps that icon, they see a new map view, with a pin in the original geo-coded location of the art and a blue marker showing their current location:

Original and Current Location of Ghost Ship

Original and Current Location

A thumbnail of the work of art appears in the upper left of the screen for reference. The user drags the pin to the actual location of the work of art:

Pin moved to accurate location

Pin moved to accurate location

And then taps the Save button. That’s it.

The app starts to send the information asynchronously, returns to the detail view and thanks the submitter once it receives a response from the server:

Acknowledging their Contribution: A thank you notice to the person adjusting the location

Acknowledging their Contribution

The App Code

Behind the scenes, this is relatively easy to implement in Objective-C.

First, the new coordinates are placed in an NSDictionary object that conforms to the GeoJSON format:

NSArray *coordinateArray =
     [NSArray arrayWithObjects:self.newLongitude,self.newLatitude,nil];
 
NSDictionary *geometryDict = [NSDictionary dictionaryWithObjectsAndKeys:
     coordinateArray,@"coordinates",
     @"Point",@"type",
     nil];

Then I set up an NSDateFormatter for a timestamp:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
 
// uses ISO 8601, as described here: http://www.w3.org/TR/NOTE-datetime
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZ"];

And grab the app version number:

NSString *versionNumber =
     [[[NSBundle mainBundle] infoDictionary]
     valueForKey:@"CFBundleShortVersionString"];

Now I’m ready to create an NSDictionary to hold all the information the app will submit, including the original location, the submitted location, ID numbers, and title, for easy reference in the admin view:

NSDictionary *locationUpdateDict = [NSDictionary dictionaryWithObjectsAndKeys:
   [theArt latitude],@"originalLatitude",
   [theArt longitude],@"originalLongitude",
   geometryDict,@"geometry",
   [theArt couchID],@"publicArtID",
   [theArt recordID],@"recordID",
   [theArt title],@"title",
   @"reported-location",@"type",
   @"submitted",@"reviewStatus",
   [NSString stringWithFormat:
        @"PublicArtPDX v%@ iOS app user", versionNumber],@"submittedBy",
   [dateFormatter stringFromDate:[NSDate date]],@"submittedDate",
   nil];
 
// And don't forget to let go of this:
[dateFormatter release];

Using the json-framework, it takes one line to convert this NSDictionary object into valid JSON:

NSString *jsonToSubmit = [locationUpdateDict JSONRepresentation];

Which looks like this:

{
     "originalLatitude": 45.513289,
     "originalLongitude": -122.668293,
     "geometry": {
     "coordinates": [
             -122.666736579521,
             45.51915887481938
         ],
         "type": "Point"
     },
     "publicArtID": "b916e524b2e1f24e72ac7a81aa530899",
     "recordID": "1839",
     "title": "Ghost Ship"
     "type": "reported-location",
     "reviewStatus": "submitted",
     "submittedBy": "PublicArtPDX v1.0.0 iOS app user",
     "submittedDate": "2011-02-12T15:13:57-0800"
}

And then just a few more lines to set up and submit a POST request to CouchDB using the ASIHTTPRequest library:

// kURLForUpdates is a constant that points to
// the CouchDB database, e.g.:
// http://myinstance.couchone.com/mydatabase
 
NSURL *theURL = [NSURL URLWithString:kURLForUpdates];
 
self.locationSubmitRequest = [ASIHTTPRequest requestWithURL:theURL];
 
[[self locationSubmitRequest] setRequestMethod:@"POST"];
 
[[self locationSubmitRequest] addRequestHeader:@"Content-Type"
                                         value:@"application/json"];
 
[[self locationSubmitRequest] appendPostData:[jsonToSubmit
                           dataUsingEncoding:NSUTF8StringEncoding]];
 
[[self locationSubmitRequest] setDelegate:self];
 
[[self locationSubmitRequest] startAsynchronous];

To limit submissions to certain accounts, I can authenticate the POST request by adding two more lines of code that define the username and password for the request object before starting it:

[[self locationSubmitRequest] setUsername:kUpdateUsername];
[[self locationSubmitRequest] setPassword:kUpdatePassword];

In other projects under development, I want app users to be able to submit private information. CouchBase can handle that, too: switch the URLs to https, and submissions are encrypted en route.

I’m making the request asynchronously so I don’t lock up the main thread. Even though it’s a tiny chunk of data, it can still take a few seconds over cellular, especially if only 2G is available.

You may have noticed that the request is actually a property of the view controller. Why? So I can stop the request if I need to.

If the app dismisses a view that initiated an asynchronous request while the request is still running, the app will crash when the response tries to send a callback message to its delegate.

There are a few scenarios in which the request needs to be stopped: if the user gets tired of waiting and decides to cancel their submission or leave the app, or if the Reachability changes because the cellular connection is lost.

In any of these cases, I can call this method to handle the situation gracefully:

- (void)killRequest {
 
     if ([[self locationSubmitRequest] inProgress]) {
 
         [[self locationSubmitRequest] cancel];
 
         // update UI, if needed
         [MBProgressHUD hideHUDForView:self.view animated:YES];
 
     }
 
}

If the data involved is mission-critical, a method likes could be used to store it for submission later.

Within Couch

In my admin interface, I can view the original location and compare it to the submitted location. If the adjustment makes sense, I push it to the production CouchDB database. The review UI uses a mix of HTML and Javascript for viewing and mapping data and Python with CouchDBKit for moving data between databases. I’ll save details about that process for another post.

Once the scripts have migrated the new location to the production Couch database of public art, it will be rolled into the next datastore release for Core Data on the iPhone.

The app checks a document in CouchDB once a day, and downloads the datastore if it’s newer than what’s on the phone. CouchBase can store and serve the binary file for the data update, too.

In Summary

With CouchDB, I was able to implement a RESTful API to accept data sent from mobile apps in an order of magnitude less time than it would take me to develop and deploy a traditional web application and add a RESTful API to it.

In this particular project, I did not need a public, polished web interface to present the data, I only needed an API to receive data. I was able to do that in three simple steps: adding a database in CouchDB, configuring write access, and submitting JSON via authenticated POST requests. It’s really that easy.

I’m using Couch in other projects which do have web interfaces, including dynamic maps which send geo-queries to CouchDB, like this beta version of the Portland Poetry Posts project.

That project will eventually have an iOS app in addition to the website, with CouchDB handling data for both interfaces, as well as any other apps that other developers build around it.

I’m regularly moving data between CouchDB databases and the web via Javascript, legacy relational databases and text files via Python, and iOS devices via Objective-C. It feels almost native from each language because of the simplicity and flexibility of using HTTP verbs like GET and PUT with JSON payloads.

I’ll cover other aspects of using CouchDB and explain some of the design decisions I made while working on the public art app in future posts.

Until then, enjoy the app — and please let me know what you think!

{ 4 comments }

The Last Few Months

by Matt Blair on February 18, 2011

I’ve been busy finalizing a couple projects for release, as well as working on a few that won’t come out for another month or two, and I’ve really let the blogging go.

Here’s a quick roundup of a few news items since my last post in September:

Trees

I released PDX Trees in October, and it won the Most Appealing App award in Portland’s Civic Apps Challenge. I just posted a progress report.

Poetry Posts

After going through at least three or four incarnations, I’ve cleared out the cruft and made a minimalist map of Poetry Posts around Portland. I credit Laura O. Foster’s article on Powell’s blog (republished on her own site) with lighting the necessary fire.

There will still be an iOS app version at some point, but I’m not sure about the timing. I’ve been collecting data on and off for six months now, and I wanted to make it available to the public in some way now, so there it is.

Delivering Points to MapKit

In January, I presented some of my work with GeoCouch, Core Data and MapKit at a Portland CocoaHeads meeting. I plan to do a full blog post about pulling geo-data from GeoCouch and Core Data when I release the source for the iOS GeoCouch browser. Here’s a sneak peak:

iGeoCouch Showing Fire Stations

Pulling Fire Station Locations from GeoCouch in Real-Time

At the same meeting, Justin Miller explained route-me (an open source alternative to MapKit) and demonstrated his incredible MapBox for iPad, which he built in cooperation with Development Seed. Take a look. It’s very impressive.

Justin conveniently bundled our slides from the presentations.

History

I’ve been gathering notes about a possible history app as I bump into links and resources, and I’ll be doing a followup to my last post on the topic soon.

Finally…

My apps for urban rambling series continues with an exciting announcement next week, and I have a few more apps in the works which won’t appear until late Q1 or Q2. Please stay tuned!

{ 1 comment }

Apps for Urban Rambling

by Matt Blair on September 25, 2010

At least three or four times a week, I set out on foot, without any specific destination in mind.

I might intend to stop at the store on the way home, but that’s an hour or two off in the distance.

Until then, my route is determined by whim, and by whatever catches my ear or eye.

I might turn right down a street for no other reason than I haven’t been there before, or because of the way the light catches a particular wall:

Imagining the view from that window...

Droopy eyebrow window

Or I might hear the branches of a tree creaking in time with the wind.

Or glimpse an unusually-shaped rosemary bush.

Or stumble over a friendly reminder:

Advice

Good Advice

If there is one thread that passes through each of the Civic Apps projects I’m working on, it is this:

I’m an urban rambler, and these are apps for rambling.

(Note for non-residents: In Portland, urban includes the fringes of forests, too.)

When I first glimpsed the the datasets released as part of Civic Apps, I wondered: how can I take this information off the server, right past the desktop, and into the physical world?

My goal is to bring the unseen to the surface, and make it possible to discover elements of our environment that we might not have known were there, whether those are trees or poetry boxes or historical landmarks.

Instead of little placemark icons and comprehensive detail balloons designed for 20+ inch screens, I wanted to transform the data into portable clues to new experiences — the kind that deeply engage the senses, better connect us to our surroundings, and maybe even each other.

My criteria for success won’t be how many people download them, or how many server hits I get, though these are still useful indicators.

My real criteria are harder to measure: how many shoe-sole molecules are added to sidewalks and streets, how many hours are spent moving between the places featured in these apps, and how many aspects of this city are perceived and appreciated in ways they might not have been otherwise.

I have a number of apps in mind for this series. At least two of them will be released in the next few weeks.

Until then, happy rambling.

{ 0 comments }

Exploring Portland’s History?

by Matt Blair on September 23, 2010

There have been at least two different ideas posted to the Civic Apps website suggesting an app based on historical sites in Portland.

I’ve done a little bit of thinking about how to proceed, and that’s enough to know that it’s beyond the scope of what I can undertake on my own in the next few months.

I’d love to see this app happen. Anyone else?

The Data

The link posted in the comments of that second proposal points to an Excel spreadsheet with nearly 700 points of interest in it. This could be a starting point.

Most records have a street address, but none are geo-coded. Some fields would need to be cleaned up or split before they could be used to selectively query the data. For example, several rows in the year column have multiple values — date built and date remodeled, perhaps? — which would need to be in different columns to enable sorting/filtering based on year. There seem to be some other irregularities which might need to be parsed and researched individually.

An App, As-Is

Once it is cleaned up, the dataset could be hosted on PDXAPI so that it’s re-usable by other projects, too.

The code I’ve written for the PDX Trees app could be adapted to display these historical sites, with some modifications to the data models and detail screens. I have a version that reads directly from PDXAPI and another that reads from Core Data on the iPhone.

The data set has an architectural style listed for most locations, and this could tie in with online reference materials like Wikipedia, where available.

Enhancements

The ideas posted to Civic Apps mentioned integrating stories and imagery for each site. An app rich with historical details, images, and personalities would certainly have a wider appeal than a simple map and text version.

Doing that well would require wrangling and reformatting text and media assets for at least a few hundred sites, and that’s a book-sized project. Unless, of course, someone has already written such a book, and is open to licensing stories and images for re-use in an app.

Are there any stories or story collections available in the public domain, under a Creative Commons license, or some other easily re-usable format?

The same questions for photos: Are there any public domain or CC-licensed photos available?

If not, maybe it would be possible to use government data as an outline or scaffold for crowd-sourced details? That would require broad and sustained community engagement, given the scope of the data.

Collaboration

Over the next few months, I’d be happy to take on some of the data work, re-purpose my existing iPhone code, and start planning for a richer version.

Anyone else want to join in?

{ 6 comments }

PDX Trees: 1.0 and Beyond

by Matt Blair on September 22, 2010

A tagged Heritage Tree

A tagged Heritage Tree

A few months ago, I didn’t even know Portland had heritage trees. And, to be honest, off the top of my head, I couldn’t tell you a single difference between an elm and an oak.

Over the last few weeks, I’ve started to learn, while testing an app I’ve created for the iPhone: PDX Trees.

PDX Trees Screenshot

PDX Trees Screenshot

Version 1.0

With the first release of the PDX Trees iPhone app, I have two primary goals:

  1. To help citizens and visitors alike find, identify and appreciate Portland’s Heritage Trees.
  2. To start building a crowd-sourced, longitudinal, season-sortable collection of images of these trees.

Here’s a list of features I expect will make it into version 1.0:

  • View nearby trees on a map.
  • Tap a pin to show the name, tap the arrow to show all available details for that tree.
  • Tourist mode: if the current location is not available, or the device is outside the scope of the tree data, tree fans will see a default map view so they can browse trees anyway.
  • Email a friend about the tree (includes tree name and location where available)
  • Take and upload photos of a selected tree.
  • Look at photos of the tree taken by other app users.
  • Flag inappropriate photos.
  • Read more about a type of tree from Wikipedia, without leaving the app.

I’m using a few features that are specific to iOS 4.x, so it won’t work on the iPad quite yet, but stay tuned. I’m planning to make sure it works on the iPad by the time iOS 4.2 is released in November.

Bringing it to the Web

Of course, I realize that not everyone has access to an iPhone or an iPod Touch, so it’s important to me to bring this information to other platforms.

Max Ogden has loaded the base data from the City of Portland into PDXAPI. (Thanks, Max!) I converted that to a Core Data-compatible SQLite database so I can install it and query it directly on the phone for better performance.

All the submitted photos collected within my app will also be available via a RESTful API, so they could easily be integrated and re-used by other apps and websites. My plan is to eventually get them into PDXAPI alongside the base tree data.

Future Growth

Possible features for the web and/or the iPhone:

  • Search/sort tree by type, displaying results in a list and on a map
  • View trees by year designated
  • View photos by season
  • Add remarkable non-designated trees and collections of trees like the Ainsworth linear arboretum
  • Search for trees within neighborhood regions
  • Use city and state flags to distinguish trees native to Portland and native to Oregon
  • Expand the tree data beyond Portland
  • Nominate trees to become heritage trees from within the app

Availability

I’m working on this app as part of Portland’s Civic Apps challenge. I’m planning to submit it to the App Store as a free app in the next week or two, and I’ll make the source code available around that time, too.

Collaboration

Sound interesting? Want to help?

In particular, I’d love to see web and mobile web versions of this, and an Android app would be great, too!

Contact me for details.

{ 0 comments }

I Think the Orange is Winning…

by Matt Blair on July 25, 2010

I always keep an eye out for examples I can add to my geo-usability presentations (PDF) like the one I gave on January 12th.

ESRI has released apps for the iPhone and iPad, and it seems to be part of a broader iOS strategy. Great! Welcome to the party!

Here’s a screenshot of one of the featured maps in their new iPhone app:

And the blue is definitely surrounded...

The blue is definitely surrounded...

That’s a lot of orange, but what does it represent? Home Depot customers? Reports from the Dutch Resistance?

I don’t get this. This is ESRI. The dominant force in mapping tools. And they push out mapping products like this one without any legends, keys or clues about how to interpret them.

If you know the geography of the US well, you might be able to make some guesses — but then what’s the point of the map?

Clicking the “i” icon to view the details doesn’t help, either:

Nope. No explanation of what the colors mean here...

Nope. No explanation here...

Even in the iPad version, with four times the screen real estate and plenty of room to present supporting materials, they’ve simply stretched the iPhone app interface out to fill the screen.

As we transition from maps as tools for experts to maps for everyone, the assumptions about what an audience knows need to transition as well.

Yes, we can see the colors.

But what does it all mean?

{ Comments on this entry are closed }

They’re Erasing Our Memories

by Matt Blair on February 26, 2010

From the recent Esquire profile of Roger Ebert, a great example of one way the overreach of intellectual property ‘management’ and DRM policies are excising chunks of our cultural memories:

Ebert keeps scrolling down. Below his journal he had embedded video of his first show alone, the balcony seat empty across the aisle. It was a tribute, in three parts. He wants to watch them now, because he wants to remember, but at the bottom of the page there are only three big black squares. In the middle of the squares, white type reads: “Content deleted. This video is no longer available because it has been deleted.” Ebert leans into the screen, trying to figure out what’s happened. He looks across at Chaz. The top half of his face turns red, and his eyes well up again, but this time, it’s not sadness surfacing. He’s shaking. It’s anger.

Chaz looks over his shoulder at the screen. “Those fu — ” she says, catching herself.

They think it’s Disney again — that they’ve taken down the videos. Terms-of-use violation.

This time, the anger lasts long enough for Ebert to write it down. He opens a new page in his text-to-speech program, a blank white sheet. He types in capital letters, stabbing at the keys with his delicate, trembling hands: MY TRIBUTE, appears behind the cursor in the top left corner. ON THE FIRST SHOW AFTER HIS DEATH. But Ebert doesn’t press the button that fires up the speakers. He presses a different button, a button that makes the words bigger. He presses the button again and again and again, the words growing bigger and bigger and bigger until they become too big to fit the screen, now they’re just letters, but he keeps hitting the button, bigger and bigger still, now just shapes and angles, just geometry filling the white screen with black like the three squares. Roger Ebert is shaking, his entire body is shaking, and he’s still hitting the button, bang, bang, bang, and he’s shouting now. He’s standing outside on the street corner and he’s arching his back and he’s shouting at the top of his lungs.

{ Comments on this entry are closed }