About

I'm Mike Pope. I live in the Seattle area. I've been a technical writer and editor for over 30 years. I'm interested in software, language, music, movies, books, motorcycles, travel, and ... well, lots of stuff.

Read more ...

Blog Search


(Supports AND)

Google Ads

Feed

Subscribe to the RSS feed for this blog.

See this post for info on full versus truncated feeds.

Quote

What existential journey hasn't been aided by chemistry?

David Shields



Navigation





<November 2017>
SMTWTFS
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

Categories

  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  

Contact

Email me

Blog Statistics

Dates
First entry - 6/27/2003
Most recent entry - 11/17/2017

Totals
Posts - 2460
Comments - 2563
Hits - 1,999,930

Averages
Entries/day - 0.47
Comments/entry - 1.04
Hits/day - 380

Updated every 30 minutes. Last: 3:49 AM Pacific


  02:36 PM

Here's a keen thing I learned about from a Vox article: a Chrome extension named Library Extension that adds library information when you're viewing books on Amazon or Goodreads. The extension tells you whether the book you're interested in is available in one or more library systems.

Let's say you're interested in the book The ABC of How We Learn, so you look it up on Amazon. In the bar at the top of the page, the library extension icon lights up to tell you that you're on an enabled site:


On the actual page where you're viewing book information, the extension displays library information:


If you want to get the book from the library, you click the Borrow button. This sends you to the library site with the book preloaded.

To configure the extension—for example, to tell it which libraries you want to look in—you click the icon in the toolbar, then click Options:


In the options dialog, you find the library you're interested in, then click the add (+) button:


I just started using this, so I don't know whether I'll end up liking it. It seems a bit intrusive to actually inject information into the page, instead of optionally displaying that information in a dialog or something. I also don't know how robust it is. Does the extension rely on Amazon APIs? Does it scrape information from the page? (A strategy known to be fragile.) How reliable will it be in terms of interacting with library sites?

But I like the concept just fine, since it reflects something I do a lot anyway—namely, look up books, then see if I can get them at the library. I'm curious whether others use this extension, or something like it, and what they think.

[categories]   , ,

[1] |


  09:11 PM

Not long ago I posted something about saving your hearing via the diligent use of earplugs if you are around loud things. (In my case, a motorcycle.) I didn't note then that my problem with being able to hear clearly is not new. I've had trouble for a long time hearing conversation in loud restaurants or understanding dialog in movies.

In fact, I had my hearing tested a while ago. Paradoxically, the results said that my hearing is great in some sort of Platonic sense, as in, when tested in ideal conditions in a lab. But Dr. Ears admitted that there was nothing to be done about my filtering problem—being able to pick out from background noise the sounds I actually wanted to hear.

Hearing aids are an option, I suppose. But good hearing aids are shockingly expensive, and often are not covered by insurance. And it's not at all clear to me that they solve this specific problem of attenuating the background noise specifically.

Well, in the creepy way of modern internet advertising, which can apparently read your mind, I recently started seeing ads for something pretty new: "conversation-enhancing headphones." For example, Bose has a product that they call Hearphones. Doppler Labs (which is suing Bose over all this) has a product they call Here Active Listening headphones. (Here, hear, get it?)

If I understand correctly, the devices combine noise cancellation with directional microphones with a kind of equalizer app (on your phone) to do pretty much what I need, namely tune and/or filter noise versus signal. And all at a price that is significantly less than hearing aids (Bose: $600, Doppler: $300). It's true, of course, that you're wearing headphones versus the invisibility of hearing aids. Then again, wearing headphones is pretty normal in a lot of contexts.

I'm pretty excited by all this. In fact, I'd probably go ahead and get a pair of these, but I've been around technology long enough to know that it's not usually a good idea to get version 1 of anything. By the time v3 of these things is available, they should be pretty great, right?

Let me add a linguistic note here as well. The name that Bose has come up with—hearphones—strikes me as so perfect for this device that it feels like it could easily become the genericized term for this class of thing. Any bets?

[categories]   ,

[1] |


  12:24 PM

I rassled a bit recently with a couple of dumb issues when creating some Word macros, so I thought I'd better write these up for my own future reference. To be clear, "dumb" here means that I should already have known this stuff, and I wasted time learning it.

1. Calling subroutines

I was trying to call a sub like this:
Sub SomeMacro
SomeOtherSub(p1, p2)
End Sub
Word got so mad about that SomeOtherSub call:


Turns out that when you call a subroutine in VBA and pass parameters, you do that without parentheses:
SomeOtherSub p1, p2
The parameters can be positional, as here, or named. For the latter, use the := syntax:
SomeOtherSub p1:="a value", p2:="another value" 

2. Exposing subroutines (implicit access modifiers)

Here was another kind of bonehead mistake I made. I wrote a subroutine sort of like this:
Sub MyMacro(param1 As String, param2 As String)
' Code here
End Sub
Then I tried to actually run this macro (Developer > Macros). The macro stubbornly refused to appear in the Macros dialog box. If I was in the macro editor and pressed F5 to try to launch it in the debugger, Word just displayed the Macros dialog box for me to pick which macro to run, but again, did not display the actual macro that I actually wanted to run.

Anyway, long story short (too late, haha), the problem was that the Sub definition included parameters:
Sub MyMacro(param1 As String, param2 As String)
Apparently if a subroutine has parameters like that, VBA considers it to have protected access—it can be called from another macro, but it can't be launched as a main. This makes sense, but it wasn't immediately obvious. What I really wanted was this:
Sub MyMacro()
I had included the parameters by accident (copy/paste error), so it was basically a dumb mistake. I just removed them and then things worked. Well, they worked until VBA ran into the next dumb mistake, whatever that was. (In my code there's always another one.)

[categories]   ,

|


  02:35 PM

Another quick post about Word, primarily for my own benefit (when I forget this later).

Word has several options for how you can paste text:


They are (in order):
  • Keep Source Formatting. This option keeps the original formatting (both character and paragraph formatting), but converts it to direct formatting.

  • Merge Formatting. This option copies basic character formatting (bold, italics, underline) as direct formatting, but does not copy any paragraph formatting.

  • Use Destination Styles. This option copies the text and applies styles that are in the target document. (This option appears only if there matching styles in the target doc.)

  • Keep Text Only. This option copies the text as plain text, with no formatting.
I need the last one (paste plain text) more often than any of the others, so I want it on a keyboard shortcut. You can do this by recording a macro of yourself using the Keep Text Only option. But I realized there's an even easier way—just assign a keyboard shortcut to the built-in PasteTextOnly command.

I keep forgetting that most anything Word can do has a command. If a gesture requires just one command, you can assign a keyboard shortcut directly to it. Maybe writing this out will help me remember.

Update I added a video!


[categories]   , ,

|


  12:01 AM

This is another in a series of blog posts about how I configure Microsoft Word, which I add here primarily for my own reference.

I often use the Style pane, and within that pane, I often want to change the styles that are displayed. Sometimes I want to see all the styles; sometimes just the styles that are defined in the current document; sometimes just the styles currently in use.

You can change this display by using a dialog box. In the Styles pane, click the Options link, and then use the dropdown lists to select which styles to display and how they're ordered, like this:


But that can get to be an annoying number of clicks if you're switching between these display options frequently. So, macros to the rescue. I recorded myself making one of these changes, then created a couple of variations to give me the different displays I want. Here are the macros I currently use, where the sub name is (I hope) self-explanatory:
Sub SetStylesPaneToAllAlphabetical()
ActiveDocument.FormattingShowFilter = wdShowFilterStylesAll
ActiveDocument.StyleSortMethod = wdStyleSortByName
End Sub

Sub SetStylesPaneToInCurrentDocument()
ActiveDocument.FormattingShowFilter = wdShowFilterStylesAvailable
ActiveDocument.StyleSortMethod = wdStyleSortByName
End Sub

Sub SetStylesPaneToInUse()
ActiveDocument.FormattingShowFilter = wdShowFilterStylesInUse
ActiveDocument.StyleSortMethod = wdStyleSortByName
End Sub
To complete the picture, I map the macros to these keyboard shortcuts:

ctrl+shift+p,aSetStylesPaneToAllAlphabetical
ctrl+shift+p,cSetStylesPaneToInCurrentDocument
ctrl+shift+p,uSetStylesPaneToInUse

[categories]   , ,

|


  12:23 AM

I have used Microsoft Word for years—decades—but hardly a week goes by when I don't learn something new. (Including things that are probably pretty well known to others, oh well.) Anyway, TIL about how to use the batch version of auto-formatting in Word. Since I think a lot of people already know this, I'm adding the information here primarily for later reference for myself.

Word has settings to perform "auto-formatting as you type." These include things like converting quotation marks into so-called smart quotes (i.e., typographical quotation marks), converting double hyphens (--) into em-dashes (—), converting typed fractions (1/2) into typographic fractions (½), etc. You set these options in the AutoCorrect dialog box: File > Options > Proofing, AutoCorrect Options button, AutoFormat As You Type tab.

It turns out that Word can also apply these auto-formatting instructions after the fact. In the same AutoCorrect dialog box, there's a tab named just AutoFormat:


This has most of the same options as with auto-format-as-you-type. Here's the neat part: you can get Word to apply these formatting options by pressing alt+ctrl+k. There's no UI gesture, but you can use the feature for customizing the ribbon to add the relevant command to the ribbon or Quick Access Toolbar.

A use case where I can see this working pretty well is if you paste text in from a text editor. (I do this all the time.)

Credit where it's due: I learned about this from the article How to Automatically Format an Existing Document in Word 2013 by Lori Kaufman on the How-To Geek site. As I say, I'm adding this info here primarily for my own benefit. :-)

[categories]   , ,

|


  09:04 AM

I was reading a thread on a computer forum, and someone asked this question:
Quote:
Your password should contain at least 6 characters

If you're going to require it; don't say "should", say "must".
This set off an interesting discussion on the semantics of should in this context. I've written about this before, so I was interested to hear how people interpreted the example.

Here is a sampling of the more serious posts on the thread:

From the requirements document: "The password entered by the user should be rejected if it does not contain at least six characters." If I received that requirement from my boss, I would make darn sure that the password is rejected. I don't think I would randomly reject some and not others.


The software is being polite; it's anticipating users who do not like being told what to do.


If it says "should" then it is not optional, like in "could". You should be "this tall" to ride this ride.

A number of people pulled out dictionary definitions (Wikitionary, heh). And one person cited RFC 2119 ("Key words for use in RFCs to Indicate Requirement Levels"), which states:

MUST This word, or the terms "REQUIRED" or "SHALL", mean that the definition is an absolute requirement of the specification.

SHOULD This word, or the adjective "RECOMMENDED", mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course.

All of which goes to the original poster's point—the message was ambiguous and should (ha) have been written with must. For those of us who don't keep a mental catalog of RFC recommendations, the more accessible Microsoft style guide says:

Use should only to describe a user action that is recommended, but optional. Use must only to describe a user action that is required.

In documentation, in error messages, in any context where the message needs to be clear and you aren't there to help the reader understand, avoid should when you mean must.

[categories]   , , ,

|


  09:30 PM

I found an interesting intersection recently of two things I think about a lot. One is traffic, a topic of perennial interest to me. The second is data visualizations, something that I'm comparatively new to but very interested in.

Let me back up slightly. Not long ago (maybe in 2013?), the state of Washington introduced variable speed limits in a some areas that are prone to congestion, like on I-5 northbound approaching Seattle:


[source, license, cropped slightly and reduced]

I was traveling with someone (my daughter, I think) who asked "Does that work?" To which my answer was that it could, if people actually obeyed these variable limits[1]. (Which they don't at all.) What's the theory?

On their website, the state explains variable speed limits this way:
Ideally, approaching traffic will slow down and pass through the problem area at a slower but more consistent speed reducing stop and go traffic. By reducing stop and go traffic we’re also reducing the probability of an accident by giving drivers more time to react to changing road conditions. This helps drivers avoid the need to brake sharply as they approach congestion.
Hmmm. This sort of describes the theory, but only in general terms. I also found the following on a different state site, which explains the theory even less, but does include a curious bonus reason (emphasis mine) for variable speed limits:
Variable speed limits offer considerable promise in restoring the credibility of speed limits and improving safety by restricting speeds during adverse conditions.
So let me give it a shot. Imagine that you want to go to the movies. You go to the ticket booth and buy tickets. Let's say that this transaction takes 30 seconds. Just as you finish, someone else walks up to buy their ticket. Just as they finish their 30-second transaction, a third person walks up, and so on. As long as people don't arrive at the ticket booth any more frequently than every 30 seconds, there's never a line.

But let's say that 15 seconds after you started buying your tickets, someone gets in line behind you. That person has to wait 15 seconds. And let's say people arrive at the ticket booth every 15 seconds from then on, but the ticket vender can't go any faster than one transcation per 30 seconds. The result is that the line grows, and it continues to grow as long as people arrive at the queue faster than they can buy tickets. The ticket booth is a bottleneck, and the queue is congestion.

Make sense? Congestion results from people being added to a queue (or otherwise approaching a bottleneck) faster than they can leave it. This is as true for people buying movie tickets as it is for cars approaching a slowdown. If you can prevent people from joining the queue faster than they can leave it, you can reduce the delay. If you're selling movie tickets, I don't know how you prevent people from getting in line. But if you're managing traffic, you can try to keep people out of the congestion by slowing down how fast they get to the point where the slowdown occurs.

Some people have understood this for a long time, and voluntarily slow down when it looks like traffic is heavy ahead. William Beaty has a great article (undated?) in which he dives deep on ways that even a few drivers who behave intelligently in congestion and during merges can improve flow for everyone. And while his suggestions undoubtedly work, they rely on people engaging in non-intuitive behavior, like allowing people to merge (gasp!) and leaving long-ish gaps ahead of them.

Since most people don't have the benefit of Beaty's insights, the state has decided to try variable speed limits: if people won't regulate their own speed in reaction to congestion ahead, the state (the state's computers) will attempt to do it for them.

This brings me to the visualization part of our story. Lewis Lehe is a graduate student in transportation engineering who's created a beautiful, interactive visualization that illustrates bottlenecks. (The viz is actually about the difference between bottlenecks, which I'm interested here, and gridlock.) Lehe's visualization shows cars arriving at and leaving a bottleneck, and you can adjust the arrival rate to see interactively how congestion grows if cars arrive faster than they can leave (or vice versa). Click the link and then play with the viz to get a great sense of how variable speed limits could work.


An interesting promise of self-driving cars, like the one apparently forthcoming from Google, is that they could be a whole lot smarter than human drivers about driving in congested conditions. Assuming, of course, that humans aren't allowed to take control of a car that's driving—per their own sense—exasperatingly slow. That remains to be seen.

[1] In fact, the minimum speed (perhaps by federal law?) is 40 MPH, so there's definitely a bottom limit to when variable speeds could be effective.

[categories]  

|


  09:52 AM

Carrying on with adventures using the Tumblr API. (Part 1, Part 2)

As noted, I decided that I wanted to create a local HTML file out of my downloaded/exported Tumblr posts. In my initial cut, I iterated over the list of TumblrClass instances that I'd assembled from the downloaded posts, and I then wrote out a bunch of hard-coded HTML. This worked, but was inflexible, to say the least—what if I wanted to reorder items or something?

So I fell back on yet another old habit. I created a "template" of the HTML block that I wanted, using known strings in the template that I could swap out for content. Here's the HTML template layout, where strings like %%%posttitle%%% and %%%posturl%%% are placeholders for where I want the HTML to go:
<!-- tumblr_block_template.html -->
<div class="post">
    <div class="posttitle">%%%posttitle%%%</div>
    <div class="postdate">%%%postdate%%%</div>
    <div class="posttext">%%%posttext%%%</div>
    <div class="postsource">%%%postsource%%%</div>
    <div class="posturl"><a href="%%%posturl%%%"
        target="_blank">%%%posturl%%%</a></div>
    <div class="postctr">[%%%postcounter%%%]&nbsp;
        <span class="posttype">%%%posttype%%%</span>
    </div>
</div>
The idea is to read the template, read each TumblrClass item, swap out the appropriate member for the placeholder, and build up a series of these blocks. Here's the code to read the template and build the blocks of content:
html_output = ''
 
html_file = open('c:\\Tumblr\\tumblr_block_template.html', 'r')
html_block_template = html_file.read()
html_file.close()
 
ctr = 0
for p in sorted_posts:
    new_html_block = html_block_template
    ctr += 1
    new_html_block = new_html_block.replace('%%%posttitle%%%', p.post_title)
    new_html_block = new_html_block.replace('%%%postdate%%%', p.post_date)
    new_html_block = new_html_block.replace('%%%posttext%%%', p.post_text)
    new_html_block = new_html_block.replace('%%%postsource%%%', p.post_source)
    new_html_block = new_html_block.replace('%%%posturl%%%', p.post_url)
    new_html_block = new_html_block.replace('%%%postcounter%%%', str(ctr))
    html_output += new_html_block
To embed these <div> blocks into an HTML file, I did the same thing again—I created a template .html file that looks like this:
<!-- tumblr_template.html -->
<html>
<head>
  <link rel="stylesheet" href="tumbl_posts.css" type="text/css">
  <meta http-equiv="content-type" content="text/html;charset=utf-8">
</head>
<body>
<h1>Tumblr Posts</h1>
%%%posts%%%
</body>
</html>
With this in hand, I can read the template .html file and do the swap thing again, and then write out a new file. To actually write the file, I generated a timestamp to use as part of the file name: 'tumbl_bu-' plus %Y-%m-%d-%H-%M-%S plus '.html'.

There was one complication. I got some errors while writing the file out, which turned out to be an issue with Unicode encoding—apparently certain cites that I pasted into Tumblr contain characters that can’t be converted to ASCII, which is the default encoding for writing out a file. The solution there is to use the codecs module to convert. (It’s possible that this is a problem only in Python 2.x.)

Here’s the complete listing for the Python script. (I wrapped some of the lines in a Python-legal way to squeeze them for the blog.)
import datetime,json,requests
import codecs # For converting Unicode in source

class TumblrPost:
def __init__(self,
post_url,
post_date,
post_text,
post_source,
post_title,
post_type):
self.post_url = post_url
self.post_date = post_date
self.post_text = post_text
self.post_source = post_source
self.post_type = post_type
if post_title is None or post_title == '':
self.post_title = ''
else:
self.post_title = post_title

all_posts = [] # List to hold instances of the TumblrPost class
html_output = '' # String to hold the formatted HTML for all the posts
folder_name = 'C:\\Tumblr\\'

# Get the text posts and add them as TumblrPost objects to the all_posts_list
print "Fetching text entries ..."
request_url = 'http://api.tumblr.com/v2/blog/mikepope.tumblr.com/posts/text?api_key=[MY_KEY]'
offset = 0
posts_still_left = True
while posts_still_left:
request_url += "&offset=" + str(offset)
print "\tFetching text entries (%i) ..." % offset
tumblr_response = requests.get(request_url).json()
total_posts = tumblr_response['response']['total_posts']
for post in tumblr_response['response']['posts']:
# See https://www.tumblr.com/docs/en/api/v2#text-posts
p = TumblrPost(post['post_url'],
post['date'],
post['body'], '',
post['title'],
'text') # No source for text posts
all_posts.append(p)
offset += 20
if offset > total_posts:
posts_still_left = False

# Get the quotes posts and add them as TumblrPost objects to the all_posts_list.
print "Fetching quote entries ..."
request_url = 'http://api.tumblr.com/v2/blog/mikepope.tumblr.com/posts/quote?api_key=[MY_KEY]'
offset = 0
posts_still_left = True
while posts_still_left:
request_url += "&offset=" + str(offset)
print "\tFetching quote entries (%i) ..." % offset
tumblr_response = requests.get(request_url).json()
total_posts = tumblr_response['response']['total_posts']
for post in tumblr_response['response']['posts']:
# See https://www.tumblr.com/docs/en/api/v2#quote-posts
p = TumblrPost(post['post_url'],
post['date'],
post['text'],
post['source'], '',
'quote') # No title for quote posts
all_posts.append(p)
offset += 20
if offset > total_posts:
posts_still_left = False

sorted_posts = sorted(all_posts,
key=lambda tpost: tpost.post_date,
reverse=True)

print "Creating HTML file ..."

# Read a file that contains the HTML layout of the posts,
# with placeholders for individual bits of data
html_file = open(folder_name + 'tumblr_block_template.html', 'r')
html_block_template = html_file.read()
html_file.close()

ctr = 0
for p in sorted_posts:
new_html_block = html_block_template
ctr += 1
new_html_block = new_html_block.replace('%%%posttitle%%%', p.post_title)
new_html_block = new_html_block.replace('%%%postdate%%%', p.post_date)
new_html_block = new_html_block.replace('%%%posttext%%%', p.post_text)
new_html_block = new_html_block.replace('%%%postsource%%%', p.post_source)
new_html_block = new_html_block.replace('%%%posturl%%%', p.post_url)
new_html_block = new_html_block.replace('%%%postcounter%%%', str(ctr))
new_html_block = new_html_block.replace('%%%posttype%%%', p.post_type)
html_output += new_html_block

# The template has a placeholder for the content that's generated dynamically
html_file = open(folder_name + 'tumblr_template.html', 'r')
html_file_contents = html_file.read()
html_file.close()
html_file_contents = html_file_contents.replace('%%%posts%%%', html_output)

# Open (i.e., create) a new file with the ability to write Unicode.
# See http://stackoverflow.com/questions/934160/write-to-utf-8-file-in-python
file_timestamp = datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')
with codecs.open(folder_name +
'tumbl_bu-' +
file_timestamp +
'.html', 'w', "utf-8-sig") \
as new_html_file:
new_html_file.write(html_file_contents)
new_html_file.close()

print 'Done!'

[categories]  

|


  09:17 PM

I wonder how many people do this. Let’s say I’m reading something on Wikipedia, and a paragraph includes a link that’s seductively drawing my attention away from the current article. In a show of resistance to ADHD, I won’t just click that link—instead, I’ll Ctrl+click it, thus opening the linked page in another tab “for later.”

After some amount of reading, I’ll have, oh, a dozen tabs open in the browser:


Or 20. Or 30. In another exhibit of discipline, I will occasionally drag all of these open tabs from the many and various browser windows I have open into a single browser window. Now, that’s organized.

Perhaps it’s the “for later” part that I’m wondering about. I just checked some of the pages in those tabs in the screenshot. As near as I can tell, the oldest one goes back about three months. Here’s a sampling of the pages I currently have open:
  • The Tumblr API reference
  • Three (!) articles on time perspective.
  • An article on how to use Twitter for business.
  • The article “Complements and Dummies” by John Lawler, a linguist.
  • An article on high-impact training in 4 minutes.
  • An article on how to create effective to-do lists.
  • An article on how to adjust the aim of the headlight on a motorcycle.
  • The syllabus, wiki, and video page for a Coursera course I’m taking.
  • A Wikipedia article about the 1952 steel strike (related to the previous).
You can see that these are all pages that I want to keep handy, ready to read when I get a few spare minutes.

My officemate and I were talking about this today, and it turns out he does something similar. My collection of open tabs has survived several computer reboots (thanks, Chrome!), and my officemate confirms that his collection has persisted through a number of upgrades to Firefox.

It seems like a logical approach would be to bookmark these pages, either in the browser, or using some sort of bookmarking site like Pinterest or (ha) Delicious. Or heck, OneNote or EverNote.

But in my case, tossing a link into any of these is almost the equivalent of throwing it into a black hole. Yes, I have the link, but I don’t make a habit of going back to my saved links and looking for things that had struck my fancy days or weeks or months ago.

No, the habit of keeping these pages open seems to act as a kind of short-term bookmarking. Now and then I might actually click on one of the tabs just to remind myself of why I have all these pages open. For the most part, any given page still looks interesting, so I don’t want to close it. After all, I still intend to read that page Real Soon Now.

[categories]  

[1] |