Amsterdam DO’s and DON’Ts – revised 2019 edition

Back in 2012, I wrote a post with travel advice for Amsterdam. We just got back from another trip there, and I thought I’d revise my advice – most of it still applies, but there have been a few changes. So here’s my 2019 Amsterdam DO’s and DON’Ts. Come back in 2026 for another revision!

Amsterdam Dos and Don’ts – 2019 revised edition

We recently spent a week in Amsterdam before and after taking a river cruise through the Netherlands and Belgium; I might eventually post photos from the trip, but in the meantime, I wanted to share some possibly-useful tips for others travelling to Amsterdam and environs.


  • DO tell your credit/debit card companies that you will be using your card in the Netherlands and when you’ll be there.
  • DO get money from ATMs rather than buying it before you leave the US; there are ATMs at the airport and all over town and you’ll get a much better rate. (2019 note: Use bank ATMs if at all possible to get the best exchange rate and lowest fees; avoid Travelex and the like.)
  • DO expect to find some shops which only accept cards and will not accept cash. (2019 note: I saw quite a few shops which were card-only, and a few which were cash-only. I ran into a couple of shops which would not accept Visa or Mastercard credit cards but would accept debit cards.)
  • DON’T get the Travelex “Cash Passport” Chip and PIN card – the exchange rate is hideous and they demand your Social Security number.
  • DO expect to be able to use your US credit card when you are dealing with people – even though the Dutch all have Chip and PIN cards, every credit card machine I saw in a shop could also accept a US magstripe card. (2019 note: Of course, all the machines accepted US chip cards, too; sometimes the shop wanted a signature, but often they didn’t.)
  • (New for 2019) DO expect to use your US credit card to be able to buy train tickets and transport cards from automated machines.
  • DON’T take the option of paying in US Dollars using your credit card. The rate is probably not as good as your card company will give, and if your card has a surcharge for international transactions, you’ll have to pay that surcharge even if the transaction is in US Dollars.
  • DO carry a few Euros in change with you at all times for small purchases and toilets – many public toilets charge between 20–50 cents for access.

Getting into town from the airport

  • DO take the train unless you’re staying far from the city center.
  • 2019 advice: DO expect to be able to use your US credit card at the machines at the train station to buy your ticket.
  • DO buy your train ticket in advance from Belgian Rail; print it at home and bring it with you.
  • DO buy Second Class tickets for this trip unless you have a lot of luggage or can’t manage four steps up or down stairs.
  • DO know that the trains to Centraal Station leave from Schiphol platforms 1 and 2.
  • DON’T get on a “FYRA” train at Schiphol – it will cost you! You want to get on an “IC” train. The trains are marked on the sides of the cars; both use the same platforms.

Getting around town

  • DO walk if you can – the touristy part of Amsterdam is small, and everything of interest is within a 45-minute walk (mostly less). Take public transport only when you’re in a hurry.
  • DO watch out for bicycles and motorbikes, especially when crossing a bike path (and every street has bike paths). Treat them as you would any other fast-moving dangerous vehicle.
  • DON’T be surprised by motorbikes (or bicycles) on the sidewalk, either, though they are usually going slowly there.
  • (2019 changes) DON’T plan on using cash to buy a ticket on a tram, train, or bus. Either buy your ticket (or pass) in advance or use your card to make the purchase.

iAmsterdam card

  • DO buy the iAmsterdam card.
  • DON’T buy it at the VVV office at Centraal Station – there are long lines. 2019 advice: Buy it at the iAmsterdam shop at Centraal Station (on the IJ side of the station); you can even use your US credit card to buy it from their vending machine!
  • DON’T pre-purchase the card over the Internet, which means picking up the card in person at the VVV office – in that same long line, of course.
  • DO be strategic about the time of day that you activate the pass. It is valid for 24/48/72 hours, not 1/2/3 days. If you activate a 24-hour pass at 11am on Wednesday, you can use it all the rest of that day and then enter a museum before 11am on Thursday and stay there the whole day. This works best for major museums, like the Maritime Museum or the Van Gogh, of course. If you’re really hardcore, you could go to the Maritime Museum at 10am on the last day of your pass and get a ticket, immediately go to another nearby museum and see it, then return to the Maritime Museum because your ticket is good for the entire day.
  • DO realize that the museum pass and the travel pass are completely separate after you buy them; you need not activate them at the same time (or even on the same day).
  • DO realize that the discount offers in the booklet are valid even after your card expires (I think they go to the end of the year); you just need to bring the card and the booklet.
  • DON’T plan to go to the Anne Frank House on the iAmsterdam card. 2019: You have to buy your tickets online in advance (they go on sale exactly 2 months in advance).
  • 2019: DO get your timeslots for the van Gogh Museum as soon as you have your iAmsterdam card numbers.

Sex, drugs, and rock ‘n’ roll

  • DON’T be afraid of walking through the Red Light District (of course, be aware of your surroundings, just as you would anywhere else).
  • DON’T take photos of “red rooms” or the women working in them.
  • DON’T go to a coffeeshop for coffee.

Eating and drinking

  • DO expect the inside of restaurants to be non-smoking (both kinds of smoke).
  • DO expect a lot of [tobacco] smokers just outside of a restaurant.
  • DON’T expect free refills on coffee.
  • DO expect free tap water but you have to ask for it.
  • DO expect service charges to be included in your bill; round up to the next Euro or two if you’re especially pleased. I ran into one restaurant where service was marked as “Not Included” on the bill and tipped about 10% – I have no idea if that was right or not.

Staying connected

  • DO arrange for an international package from your cell carrier (if it’s not already included, as it is with T-Mobile or Google Fi). DON’T use your phone if you don’t have a package – the prices are ridiculous.
  • DO consider getting a local SIM if you want to use a LOT of data.
  • DO look for “Free Wi-Fi” hotspots; many small restaurants offer free Wi-Fi. One near our hotel gave us the password when we stopped to look at their menu and told us the service was available 24/7. We wound up having breakfast there four times!
  • DO look for free Wi-Fi from if you’re near a fast-food chain like McDonalds, Burger King, or Subway.


  • DON’T expect to need to know much (if any) Dutch. All tourist-oriented businesses are completely English-friendly, and almost everyone in the Netherlands seems to speak and understand English.
  • DO try to sound-out written Dutch if you need to figure out a sign; it looks unlike English, but I found it fairly easy.
  • DO say “Dank U Well” (“thank you”).

TIL how to build Python 3.7 with statically-linked libssl and libcrypto

I use a Virtual Private Server on DreamHost to run the Toastmasters District 101 website. For the most part, I’m happy with their service, and with a shell prompt, it’s usually easy to install whatever software I need.

Except Python 3.7. Python 3.7 requires a newer level of OpenSSL than DreamHost offers, and since I don’t have root access on a VPS, I can’t just replace OpenSSL. Compiling a current version and installing it in a directory ($HOME/usr/local) was easy enough:

./config --prefix=$HOME/usr/local --openssldir=$HOME/usr/local/openssl   
make test   
make install   

Building Python 3.7 was also easy, but getting it to use my copy of OpenSSL was not.

At first, I tried adding my OpenSSL to LD_LIBRARY_PATH, which worked, but it made git complain: no version information available (required by ssh), and that seemed unfortunate (and made me worry that I might break other things).

After much searching, I found Python issue 21541, which had the hints I needed to statically-link my copy of OpenSSL into the Python executable.

First, run configure:

./configure --prefix=$HOME/opt/python-3.7.0 --with-openssl=$HOME/usr/local/

Then uncomment and change the section of Modules/Setup dealing with SSL to this:

# Socket module helper for SSL support; you must comment out the other
# socket line above, and possibly edit the SSL variable:
_ssl _ssl.c \
    DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
    L$(SSL)/lib -Wl,-Bsymbolic $(SSL)/lib/libssl.a $(SSL)/lib/libcrypto.a

After that, the usual make && make install worked.

I’ve moved!

Ducklings on the move with mama duckI’ve moved this blog to Linode. It should run a little faster, cost me a little less, and let me do more things with the server.

I took the photo near my house a couple of days ago while I was out for a walk; I was surprised to see a mama duck and her flock of ducklings going the other way!

In Praise of Venice Classic Radio

We like to have light classical music in the background while we’re at home. During most of the year, we usually listen to our local classical station, KDFC, or one of SiriusXM‘s classical channels. But once Thanksgiving rolls around, things change. “Holiday” music begins to creep into the playlist, and as the month goes on, it takes up more and more airtime.

But I’ve found an alternative – Venice Classic Radio. Their playlist is blessedly free from “holiday” music for most of the month – they do play the occasional real classical Christmas piece, but it’s a small part of their programming, and they mostly save it until Christmas Eve and Christmas Day. I heard Silent Night yesterday and Nutcracker today, both of which were very pleasant indeed; they also played Kol Nidre today, much to my surprise.

Check them out any time you want classical music without interruption (they play a 30-second multi-lingual station ID at the top of the hour, but that’s the only announcement you’ll hear) – and especially during December!

Happy Holidays to all, and to all a good night!

TIL why you “lay down” Port

When Jeff was four or five, I thought it would be a nice idea to buy a bottle of Port from his birth year and share it with him on his 21st birthday. I found a bottle of “Late Bottled” Vintage Port at Trader Joe’s (this was before we started going to wineries!) and put it aside.

Jeff’s 21st birthday came – but he was away at college. The bottle sat.

Years passed.

Jeff’s home for the holidays, and I thought New Year’s Eve would be a good time to finally share the Port. I took the bottle out of the closet and tried to open it.

The cork had disintegrated. I managed to get enough of the cork out of the bottle to pour the Port through a strainer and into our glasses – but it was undrinkable.

If only I’d read the back side of the bottle and followed their advice.

back label

Next time for sure!

TIL not to plug an Amazon Echo Dot into my Mac Mini

I recently put an Amazon Echo Dot in my home office. It needs USB power; rather than plug in yet-another-power-adapter, I plugged it into a spare port on a USB hub connected to my Mac Mini.

All was well…until I needed to reboot the Mac. Then I noticed two things:

  • A normal reboot took a long time to show the login screen (more than a minute, versus the usual 10 seconds)
  • Pressing Option during the reboot (to try to reboot from another device) failed – the machine hung, never giving me the screen with devices to try.

I tried resetting NVRAM and the SMC; no dice.

Eventually, I managed to reboot and took a look at the system log; there were many, many error messages like this:

Oct  6 12:52:00 office kernel[0]: 000573.331885 AppleUSB20HubPort@14233000: AppleUSBHostPort::disconnect: persistent enumeration failures

I started disconnecting devices, and when I unplugged the Dot, the messages stopped appearing.

I’m now powering the Dot with its own power supply, plugged into a power strip. It works great, and the Mac Mini is happy, too.

TIL about Python’s “enumerate”

I’ve been writing Python for more than 10 years, and I can’t count the number of times I’ve written code like this:

index = 0
for thing in array:
    do_something_with(index, thing) # Because I care about the index AND the item
    index += 1

But today I learned about the built-in enumerate function which does exactly the same thing, but avoids any chance of getting “index” and “thing” out of sync (not that I’ve ever made that mistake, of course…).

I’m not going to rewrite any old code for fear of adding new bugs, but I’ll remember to enumerate going forward.

Thanks, Dr. Drang!

Adding email addresses to Divi’s “person” module for District 101

The Divi theme is powerful, but it has some quirks. One of those is in the “person” module, which doesn’t provide a place for contact information (phone and email). I wanted to add email for the people listed on the District Leadership Team page; the obvious way was to add the email address to the text for each person, but that felt inelegant.

A quick Google search led me to a free plugin, Person Module Extended by Dani Dwiputra, made available through Divi Space. I installed the plugin, added emails in the appropriate fields, and could have called it a day, except that I wanted to make some changes to the presentation.

Here are the diffs to get the results I wanted:

++ Desktop/person-full-social/dd-person-modules.php 2016-07-24 21:12:21.000000000 -0700
@@ -465,2 +465,12 @@

+        if ( '' !== $member_email ) {
+            $contact = sprintf('<a href="mailto:%1$s" class="et_pb_member_email">%1$s</a>', esc_html( $member_email ) );
+            $contact .= ( '' !== $member_phone ? sprintf(' | <a href="tel://%1$s" class="et_pb_member_phone">%1$s</a>', esc_html( $member_phone ) ) : '' );
+        } else {
+            $contact = ( '' !== $member_phone ? sprintf('<a href="tel://%1$s" class="et_pb_member_phone">%1$s</a>', esc_html( $member_phone ) ) : '' );
+        }
+        if ( '' !== $contact ) {
+            $contact = '<p>' . $contact . '</p>';
+        }
        $output = sprintf(
@@ -471,4 +481,4 @@
+                   %7$s
-                   <p>%7$s  |  %6$s</p>
@@ -483,3 +493,3 @@
            ( '' !== $member_phone ? sprintf( '<a href="tel://%1$s" class="et_pb_member_phone">   %1$s</a>', esc_html( $member_phone ) ) : '' ),
-           ( '' !== $member_email ? sprintf( '<a href="mailto:%1$s" class="et_pb_member_email">   %1$s</a>', esc_html( $member_email ) ) : '' ),
+           $contact,
            ( '' !== $position ? sprintf( '<p class="et_pb_member_position">%1$s</p>', esc_html( $position ) ) : '' ),
@@ -493,2 +503,2 @@
-new DD_Builder_Module_Team_Member;
\ No newline at end of file
+new DD_Builder_Module_Team_Member;
diff -r -U1 Downloads/person-full-social/module-extend.php Desktop/person-full-social/module-extend.php
--- Downloads/person-full-social/module-extend.php  2016-07-20 10:58:09.000000000 -0700
+++ Desktop/person-full-social/module-extend.php    2016-07-24 21:15:17.000000000 -0700
@@ -9,2 +9,3 @@
  * License: GPL2
+ * Modified by David Singer

Thanks, Dani!

Speeding up “Feed Them Social” for District 101

The District 101 Toastmasters website uses the Feed Them Social plugin to add our Facebook and Twitter feeds to our homepage.

It works well, but it can be slow – if it needed to go to Facebook to update its data, it could take as much as 10 seconds to build the page; even if data was in the plugin’s cache, it took a couple of seconds to build the HTML. You can see the shortcodes I had on the home page below.

I thought about writing my own program to mine the Facebook Graph and the Twitter Feed. It would let me produce exactly what I needed, but it would be a perpetual maintenance headache (and I don’t plan to be Webmaster forever). I needed a better answer.

And then it struck me – if I could figure out a way to use the plugin as part of a batch process and save the HTML, I could get the plugin’s processing time out of the critical path, and I wouldn’t have to keep up with changes to the Facebook and Twitter APIs. Here’s what I did:

  • Created a special version of the home page, with the calls to the plugin in the proper place in the page layout (just in case it mattered), but with none of the other features of the home page.
  • Surrounded the calls to the plugin on the special page with flag lines so I could easily pull out the HTML generated by the plugin, using a simple Python program.
  • Made the special page password-protected in WordPress to keep it out of the visible menu structure shown to site visitors.
  • Wrote a script to be called periodically by cron that:
    • used curl to fetch the special page
    • ran the Python program to extract the HTML from Feed Them Social
    • saved the result as a file
  • Replaced the calls to the plugin on the homepage with a couple of lines of PHP to include the saved file as part of the homepage

The result: the homepage loads at least 3.5 seconds faster and looks the same.

Here’s the relevant part of the special page (the calls to FTS are the same as those I used to have on the homepage).

Start Flag
[fts_facebook id=d101tm posts_displayed=page_only type=page]
[fts_twitter twitter_name=d101tm]
End Flag

Here’s the shell script:

# Update the cached static file for social media from Feed Them Social
secret=password for the WordPress page
cd ~/files/social
# The next operation will take a while, so we write to a temporary file
curl -sL "" -d "post_password=$secret" -e " to the special page/" -b /dev/null | $mydir/ > $outfile
# If all went well, we can replace the real file
if [ -n $outfile ]; then
    mv $outfile fts.html
    echo $outfile is zero length!
    exit 1

And here’s the Python program:

#!/usr/bin/env python
""" Extract the HTML generated by Feed Them Social from stdin, write to stdout"""

import sys
startflag = 'Something unlikely to appear on the page'
endflag = 'Something else unlikely to appear on the page'
havestart = False
haveend = False

def findendflag(s):
    """ Returns a tuple: (any data before the endflag,
                          whether the endflag was found) """
    if endflag in s:
        return (s.split(endflag,1)[0], True)
        return (s, False)

for l in sys.stdin.readlines():
    if not havestart:
        res = l.split(startflag,1)
        if len(res) > 1:
            havestart = True
            (l, haveend) = findendflag(res[1])
    elif not haveend:
        (l, haveend) = findendflag(l)

Some Thoughts on the Toastmasters District 101 Website

I’m Webmaster for Toastmasters District 101, which started operations on July 1, 2016. For the previous two years, I had been on the Webmaster team for Toastmasters District 4; District 101 covers the area from Mountain View to Monterey, which was in District 4 until July 1.

As Webmaster for District 101, I had to choose a CMS (I chose WordPress and a theme (Divi)). I had help from other members of the District 101 Foundations team in picking other plug-ins and in creating the content for the website.

This will be the first, and possibly not the last, in a series of postings about the website and the other code I write in support of it. I’m posting here for two reasons:

  • Perhaps it’ll help someone else
  • Perhaps I’ll be able to find it in the future!

You can decide which is the more important reason.

Tweaking The Events Calendar

We chose to use The Events Calendar from Modern Tribe as our calendar tool.

Out of the box, it works well, but I wanted to display some information about the kinds of events we would show on the District Calendar and how to search for an event.

The obvious way to do that was to use the “Add HTML before event content” feature in Advanced Template Settings; unfortunately, when I added the information there, it not only appeared on calendar listings, it appeared when you chose a single event to display (and in that case, there was no search bar available, so it was really confusing!).

I found two ways to get the kind of display I wanted:

  • Override default-template.php by copying it from the-events-calendar/src/views/ to my-child-theme/tribe-events/ and then only calling tribe_events_before_html if I wasn’t displaying a single event; this has the advantage of making the information editable in the Events Calendar settings.
  • Add a new action for the tribe_events_bar_before_template hook that would display my information if and only if the search bar was going to be displayed. This has the disadvantage of requiring me to hard-code the information in my action.

I decided to go with the first choice, which also required me to be sure to use the “Default Events Template” instead of the “Default Page Template” in the Events Calendar settings.

Here’s the diff to create my modified default-template.php file:

@@ -17,7 +17,11 @@
 <div id="tribe-events-pg-template">
-        <?php tribe_events_before_html(); ?>
+    <?php
+        if (!(tribe_is_event() && is_single())) {
+            tribe_events_before_html();
+        };
+    ?>
         <?php tribe_get_view(); ?>
         <?php tribe_events_after_html(); ?>
 </div> <!-- #tribe-events-pg-template -->