Tuesday, December 02, 2014

Making a huge PDF into a reasonably-sized one (by tossing superfluous bits) ... in gs(1)

Short version:
$ gs -o reasonable.pdf -sDEVICE=pdfwrite -r300x300 huge.pdf
Last week, I wrote an annual update, a family "newsletter" of sorts. This time, because of the baby (our first grandchild) we had more photos than usual. (We briefly considered having him in every photo, but there actually is one where Baby isn't visible.) I did this in OpenOffice, and then, to send to the printer, I clicked on the "PDF" button. The resulting file was, ahem, huge.
-rw-r--r-- 1 collin 19067843 Nov 30 20:01 Dec2014.pdf
Yes, over 19 million bytes; it was probably because the photos in there were too big. I told openoffice to make them about 2 inches high or whatever, but I guess all the bits were still there (the ".odt" file itself was nearly 12 Mbytes). I did a web search on "downsample pdftk" (no quotes), which led me to this hint, briefly
gs \
  -o output.pdf \
  -sDEVICE=pdfwrite \
  -dPDFSETTINGS=/screen \
I tried this, and the output shrank down to about 70 kbytes. Impressive, but the photos were quite ugly. I mean, they looked OK on the screen, but for printing? Blech. I guess that's what /screen means.

Remembering the old saying, rtfm, I said "man gs" and found:

   Some devices can support different resolutions (densities).  To specify
   the resolution on such a printer, use the "-r" switch:

 gs -sDEVICE= -rx

   For  example,  on a 9-pin Epson-compatible printer, you get the lowest-
   density (fastest) mode with

 gs -sDEVICE=epson -r60x72
"Aha!" I thought. Let me do this:
$ gs -o output.pdf -sDEVICE=pdfwrite -r300x300 Dec2014.pdf
and the result, besides being under 1MB in size, looked great in okular, which is the PDF viewer on my Linux distro.

Tuesday, November 25, 2014

For my Linguist Daughter: a Cryptoquip

I have this urge to explain things that I learn. Yesterday's “Crypt-quip” gives me that opportunity.

The “cryptoquip” is a substitution cipher, where each letter stands for some other letter. For example, they gave us this clue: “W equals L”—which means that throughout the puzzle, every W stands for an L. Our job is to figure out what the other letters stand for, to reveal a groaner of a pun…

R U   J   A M S I P T   I A P E M   J

L M W Z R L   W J T B X J B M   C R Z F   J

Z F R L E   U S M T L F   J L L M T Z,   R   C P X W Q

L J W W   R Z   B J W W R L   B J M W R L.

Okay, the first thing to notice is that we have two one-letter words, represented by “J” and “R”. These have to be “I” and “a”, in either order. If “R” were “a” then the quip would begin “A_ I blah blah I …”; maybe “As I was walking I noticed…”

To tell the truth, though, I didn't even think of that; I just assumed that it began “If a blah blah a …”; it might also be “In a...” or “Is a…”; I didn't think it started off “It a…,” which isn't grammatical. But let’s go with R⇒I and J⇒A and defer the U for a while.

The clue tells us that “W” represents “L”, so that “LJWW” on the last line is “_ALL”. Experience with these groaners suggests the part after the comma, which so far we know is “I ___l_ _all i_…”, most likely will represent “I would call it….” But even without that knowledge, you could probably guess that LJWW means “call”; it's probably not ball, fall, gall, hall, mall, pall, tall, or wall.

If L⇒C, then what does LMWZRL on the 2nd line mean? C_L_IC—too short for “garlic,” besides starting with the wrong letter; C_LBIC? C_LDIC? Wait, didn't I guess that “LJWW RZ” was “CALL IT” (last line)? If so, then Z⇒T and LMWZRL is C_LTIC.

H'm, Not CALTIC (J⇒A hence we can't have M⇒A). CELTIC maybe? One thing about ALL-CAPS in the cryptoquip is that nothing marks proper nouns (or adjectives in this case). I suppose LMWZRL could also be COLTIC (is that a word?) or CULTIC (still possible).

Suppose it were CELTIC (M⇒E). Then our puzzle would look like this:

 I _   A   _ E _ _ _ _   _ _ _ _ E   A
 R U   J   A M S I P T   I A P E M   J

 C E L T I C   L A _ _ _ A _ E   _ I T _   A
 L M W Z R L   W J T B X J B M   C R Z F   J

 T _ I C _   _ _ E _ C _   A C C E _ T,   I   _ _ _ L _
 Z F R L E   U S M T L F   J L L M T Z,   R   C P X W Q

 C A L L   I T   _ A L L I C   _ A E L I C
 L J W W   R Z   B J W W R L   B J M W R L.
I see “Celtic” in line 2 and “_aelic” in line 4. Gaelic? If B⇒G then we'd have:
 I _   A   _ E _ _ _ _   _ _ _ _ E   A
 R U   J   A M S I P T   I A P E M   J

 C E L T I C   L A _ G _ A G E   _ I T _   A
 L M W Z R L   W J T B X J B M   C R Z F   J

 T _ I C _   _ _ E _ C _   A C C E _ T,   I   _ _ _ L _
 Z F R L E   U S M T L F   J L L M T Z,   R   C P X W Q

 C A L L   I T   G A L L I C   G A E L I C
 L J W W   R Z   B J W W R L   B J M W R L.
Gallic? As in French? Maybe the first word really is “If”, in which case the _ _ E _ C _ really could be “French”? Then U⇒F, S⇒R, T⇒N and F⇒H and we have
 I F   A   _ E R _ _ N   _ _ _ _ E   A
 R U   J   A M S I P T   I A P E M   J

 C E L T I C   L A N G _ A G E   _ I T H   A
 L M W Z R L   W J T B X J B M   C R Z F   J

 T H I C _   F R E N C H   A C C E N T,   I   _ _ _ L _
 Z F R L E   U S M T L F   J L L M T Z,   R   C P X W Q

 C A L L   I T   G A L L I C   G A E L I C
 L J W W   R Z   B J W W R L   B J M W R L.
OK, lines 2 is “Celtic language with a”—right? Then X⇒U and C⇒W. Turning to line 3, a THICK French accent, yes? So E⇒K. Let's see how that looks now.
 I F   A   _ E R _ _ N   _ _ _ K E   A
 R U   J   A M S I P T   I A P E M   J

 C E L T I C   L A N G U A G E   W I T H   A
 L M W Z R L   W J T B X J B M   C R Z F   J

 T H I C K   F R E N C H   A C C E N T,   I   W _ U L _
 Z F R L E   U S M T L F   J L L M T Z,   R   C P X W Q

 C A L L   I T   G A L L I C   G A E L I C
 L J W W   R Z   B J W W R L   B J M W R L.
Line 3: “…I would”, yes? P⇒O, Q⇒D and line 1 reads
“If a person spoke…”? That's it! A⇒P, I⇒S and we're done:
 I F   A   P E R S O N   S P O K E   A
 R U   J   A M S I P T   I A P E M   J

 C E L T I C   L A N G U A G E   W I T H   A
 L M W Z R L   W J T B X J B M   C R Z F   J

 T H I C K   F R E N C H   A C C E N T,   I   W O U L D
 Z F R L E   U S M T L F   J L L M T Z,   R   C P X W Q

 C A L L   I T   G A L L I C   G A E L I C
 L J W W   R Z   B J W W R L   B J M W R L.
Wasn’t that fun?

Thursday, September 25, 2014


I've been thinking about happiness lately, and some of this has to do with the current sermon series at church—not that my thoughts have been all that spiritual. Many have commented that happiness can't be found by directly pursuing it; rather, happiness comes when we're pursuing something else.

I was thinking about this last night. I had paused from whatever I was doing at the computer (it was so important that I don't even remember what it was) to read to Sheri. I read a sentence or two from The New Machine Age but without context it didn't seem all that good a fit. I switched to The Wisdom of the Sadhu, which worked better, though one of the parables didn't really work for her.

After a while I went to the kitchen, remarking that the dog probably wanted her teeth brushed. I opened the cabinet where her dental supplies are kept, and heard her jump from the couch. Her toenails clicked on the hardwood floor as she sped toward the kitchen, and by the time I had the toothpaste on her toothbrush, her forepaws were on my leg as she expressed her joy.

Her joy was contagious, and I remembered hearing that people live longer if they have someone to care for. Come to think of it, I saw a bumper sticker recently: on one side was a large stylized paw-print, and the words were: "Who rescued who?" or maybe "whom"…

Saturday, September 20, 2014

Dishes weren't getting clean in Kenmore Elite dishwasher 665.13422K701

So I noticed that the flatware wasn't getting clean in the dishwasher, and the cups weren't looking so nice either. Things were wet, mostly, but…

I looked at the dishwasher manual for troubleshooting help; no joy. So I did some web searching, and followed their advice (mainly, check for food junk which might impede water flow). The good news was we didn't have food junk impeding the water flow.

So I did some guerilla diagnostics, by which I determined that water was spraying from where it shouldn't (blech). And that the spinning sprayer arms didn't. After getting the kitchen floor quite wet, I noticed a little lever assembly near the axis of the lower spinning sprayer arm; it's in the photo at left. (There's probably a better word for "lever assembly" but I hope you get the idea.)

I zoomed out a bit to take the image at right, which shows the lever in context.

What I noticed was a lot of water shooting out from the gray plastic thingie directly beneath the lever assembly. A plastic ell enters the "floor" of the dishwasher right near there. The lever ought to keep the ell in the floor. When the lever is out of position, water pressure can force the ell out of its position in the floor, and water sprays from where it shouldn't. This reduces water pressure in the (non)-spinning (non)-sprayer arm, resulting in a poor wash.

The next three photos at left show the lever returning to its proper position. Notice the catch, or bracket, that keeps the lever from moving up (vertically).

With the lever locked in place, it holds the ell in its proper position, and the water seems to go where it should, spinning the sprayer arm and giving us clean dishes once again.

I was going to ask why they didn't put that in the manual, but I suspect this lever doesn't get moved very often. Actually, I don't even know how ours got thrown out of whack, but it definitely was.

Network issues solved: replaced D-link DIR-810L by ASUS RT-N66U

Streaming video to our computers, or even audio, was problematic at our house. It had been some months (don't remember how many months exactly), but we had these other issues too:
  • ssh to my ISP's shell server, and after a few minutes, response would become glacial. I mean, type "ls" and it's literally minutes. If I did it right after login, it was fine; it was only after a few minutes it would act constipated.
  • downloads of any size took "forever". We tried to download a map upgrade so the lovely Carol could update her GPS; eventually I wrote a script to kill the download and restart it (fortunately it could pick up from where it left off). It wasn't as straightforward as "wget -c", because we started the download by clicking on some icon, then hitting some button and… (I hate computers.)

    Fortunately, by saying "ps wwx" or something like this I was able to get the program's parameters. The script I wrote involved monitoring the most recently updated file in the most recently updated directory (many files were getting downloaded, with a new directory getting created every so often), then killing and restarting the download process when it looked like things had paused for more than a minute or two.

We have DSL and are supposed to be able to get something like 5-6 Mbits per second. And we often have; we watch streamed video on netflix without problems. So that puzzled me.

On another occasion, Sheri wanted to download a 200-Mbyte package; it never finished. I thought it was the wireless, so I ran a long cable to her computer—not much better. I got the URL and just said "wget" on my own computer, something like this:

collin@p3:/mnt/home/collin> wget -O frsxprodmg https://dl.dropboxusercontent.com/blahblah/FRSXpro3.5.6installer.dmg
--2014-08-26 21:58:03--  https://dl.dropboxusercontent.com/blahblah/FRSXpro3.5.6installer.dmg
Resolving dl.dropboxusercontent.com (dl.dropboxusercontent.com)...,,, ...
Connecting to dl.dropboxusercontent.com (dl.dropboxusercontent.com)||:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 218103808 (208M) [application/x-apple-diskimage]
Saving to: `frsxprodmg'

21% [=======>                               ] 47,504,787   624K/s  eta 4m 36s  ^C^Cc^C^C^C^Z
It sat there, paused, for quite a while. Then, as you can see, I got frustrated and hit some keys to stop it. I then restarted.
collin@p3:/mnt/home/collin> wget -c -O frsxprodmg https://dl.dropboxusercontent.com/blahblah/FRSXpro3.5.6installer.dmg
--2014-08-26 22:00:18--  https://dl.dropboxusercontent.com/blahblah/FRSXpro3.5.6installer.dmg
Resolving dl.dropboxusercontent.com (dl.dropboxusercontent.com)...,,, ...
Connecting to dl.dropboxusercontent.com (dl.dropboxusercontent.com)||:443... connected.
HTTP request sent, awaiting response... 206 PARTIAL CONTENT
Length: 218103808 (208M), 170541677 (163M) remaining [application/x-apple-diskimage]
Saving to: `frsxprodmg'

41% [++++++++=======>                       ] 90,094,310   393K/s  eta 4m 37s  ^C
It hung after another, what, 43 million bytes? I restarted it a few more times, getting varying amounts of data in before the download hung. I was very thankful for "wget -c" but even with that, the experience wasn't pleasant. 18MB, 65MB, 2MB, then about 43MB to finish.

Now I will pause here to remember that we live in an astounding age, where in less than half an hour, we can download something like 200 Mbytes of software and be quite confident that the data were not corrupted during transmission. That said, with all this technology it's supposed to be easier.

It was about at this time that I remembered the issues I'd been having with my ssh (login) sessions to my ISP. Could all this be caused by the router? I asked my ISP's support folks.

They confirmed that yes, this behavior could be caused by a flaky router. In my case it was a D-link DIR-810L, which we've had since October.

They suggested I try without the router. Ooooh, OK, so I logged in as root and unmounted all the NFS. Turned off as many services (xinetd, sshd, etc.) as I could figure out easily, changed the network configuration for DHCP, and connected it directly to the DSL modem (disconnecting the rest of the home network).

But I couldn't connect to anything--had to route add default gw with an "educated" (yeah right) guess. I hate computers.

Once I figured that out, I ran wget and… you guessed it—the entire 207MB+ came down in one shot, about five minutes So it was the old router!

After asking some folks at work, I went shopping. The recommended Buffalo item wasn't available locally, but I was looking for the ASUS RT-N66U dual-band wireless-N900 router. Best Buy (near Home Depot!) had an RT-N66R, but I didn't know what the difference was between 'R' and 'U' so was skittish.

I ended up ordering it from amazon and using "amazon locker" for delivery. This worked quite well. The idea is, rather than having to run over to the UPS office ("What are your hours again?"), I can have it delivered to a nearby 7-11 (open 24 hours a day). Amazon.com emails me a secret code, which I key into the locker thingie, and one of the dozens of doors pops open; inside is my item.

So I got it home and hooked it up. Configuration was a breeze, even though I have a somewhat unusual configuration (default gateway is, not .1.1). The router automagically downloaded a firmware upgrade (this operation went quite quickly, which made me feel confident in my purchase). I then tried the 207MB download, and it came in under five minutes. Whee!

Icing on the cake: logins to the server don't go all molasses-in-January-in-Minnesota on me after a few minutes.

One more thing: I naïvely set the SSIDs to the same thing on both the 5GHz and 2.4GHz wireless networks. This seemed to confuse the macbook air's wireless. (Was it cycling between the two networks, which btw also shared the same password?) After I separated the SSIDs, the problem went away.

Friday, September 12, 2014

42% “efficient”

Suppose a team of coders work on a project, and we say we want code reviews, or maybe inspections. We have estimates for how long various parts will take to code -- adding up to 3 engineer-weeks, say. How much effort (engineer-days) should we allocate to cover code reviews, discussion and rework?

Well, that depends of course on how much time we think it will take to review and discuss and rework the code. Let's suppose for a moment that if my colleague spends a week coding and doing some basic testing, then I will stare at the code for two days. Actually, let's say there are two reviewers, so two of us will stare at the code for two days each.

Then we have a day where three of us meet (in the morning, say) and talk about the code for a while. After 1½ or 2 hours, we go back to our desks and think some more about what we heard, and the person who wrote the code makes some changes. We repeat that but at the end of the day we're all happy with the code.

As I write this, that seems like a lot of review time, but if we do it that way, the total engineer-days spent add up thus:

  • 5 engr-days coding
  • 4 engr-days reviewing (2 reviewers @ 2 days each)
  • 3 engr-days discussion and rework (3 participants @ 1 day each)
Twelve (12) days total, for a thing whose coding estimate was 5 days.

That works out to 5/12 ≈ 42%. In other words, if you have 10 engineer-days available, then at the above rates of "overhead" you can spend only 4.2 days coding; the rest is review, discussion, rework. That doesn't include integration or system test, etc.

Perhaps I have the wrong ratio of (review + discussion + rework) to (code and basic test), but I'll confess to being surprised at the result of 42% given the above.

Monday, August 11, 2014

One size fits… one.

Today's Old Testament reading, from the book of Nehemiah, shows an interesting contrast in the way different people experience God. In chapter 1 of his book, Nehemiah tells us that he was cupbearer (or wine-taster) for the king in Babylon. He heard about the condition of Jerusalem and was very upset that the walls were broken down and the gates destroyed.

In chapter 2, he asks the king to send him “to the city in Judah where my fathers are buried so that I can rebuild it.” He doesn't mention the name Jerusalem (there probably was some sensitivity about that particular city), but the part I found particularly interesting is what came next:

I also said to him, “If it pleases the king, may I have letters to the governors of Trans-Euphrates, so that they will provide me safe-conduct until I arrive in Judah? And may I have a letter to Asaph, keeper of the king's forest, so he will give me timber to make beams for the gates of the citadel by the temple and for the city wall and for the residence I will occupy?”

And because the gracious hand of my God was upon me, the king granted my requests. So I went to the governors of Trans-Euphrates and gave them the king's letters. The king had also sent army officers and cavalry with me.

Nehemiah 2:7-9
What's so interesting about that? Well, maybe not so much in itself, but what I noticed was the contrast with Ezra, which was in the readings from some days past. The part of Ezra I'm thinking of was this:
There, by the Ahava Canal, I proclaimed a fast, so that we might humble ourselves before our God and ask him for a safe journey for us and our children, with all our possessions. I was ashamed to ask the king for soldiers and horsemen to protect us from enemies on the road, because we had told the king, "The gracious hand of our God is on everyone who looks to him, but his great anger is against all who forsake him."

So we fasted and petitioned our God about this, and he answered our prayer.

Ezra 8:21-23
What I take from these two men of God is not that Ezra trusted God and Nehemiah trusted in military escorts. And it's not that Nehemiah was bold and Ezra was timid. What I get is that God deals with us in a way that's suited to us. He knows us individually, knows our personalities and inclinations and strengths and weaknesses (besides our joys and tears and aspirations and disappointments).

He does not treat us like interchangeable parts; he knows us and cares for each one of us. And the way we honor him is something that's unique to each one of us too. How do I love my children? I love each one for who she is. And that gives me a little picture, a little sense of appreciation for how God loves me—he loves me in a way that's different from the way he loves you, and our paths will be different, and that's okay; indeed, it is very good.