Adventures with Flask-CORS

As I am working through the new architecture for the Runestone Interactive server I wanted to make sure that I had my authentication model working right from the beginning. The goals for the architecture are as follows: I want people to be able to write and host the static parts of any book on any server. You can think of each page in a book as its own single page application. I want to provide back-end services so that students using any book hosted anywhere can save their programs and answers to quizzes etc. I want to continue to gather research data on how students learn computer science. I want to make the registration and login process as easy as possible. Since the static parts can be hosted anywhere (including a site like interactivepython.org) The interactive parts are going to involve making cross-domain XMLHttpRequests (xhr). Of course the first thing that happens when you have a page hosted on static-site that makes an xhr request to ajax-server is that you get an error. Browsers and sites work together to disallow cross-domain requests to prevent a variety of nasty behaviors. But, there are many times (like now) when you have a legitimate reason for doing this. So, the w3c created the Cross Origin Resource Sharing (CORS) standard to help developers get around this. Cory Dolphin has created an excellent plugin for Flask developers called Flask-CORS. The plugin is a great example of the brilliant design behind Flask and in fact the entire WSGI stack.

The Really Simple Approach

The first thing you find when you start googling about this problem is that there is a seemingly simple solution. If you have control over your AJAX response you simply need to add an HTTP header Access-Control-Allow-Origin: * problem solved. Now everyone in the world can make xhr requests to your server and use the results in their page.

Adding a header is pretty simple in Flask. All you need to do is use response.headers.add("Access-Control-Allow-Origin", "*" Problem solved, moving right along to the next programming challenge.

Or maybe not. Minutes later you realize that this is not all that great because you have decorated some of your requests to require a login. That wont be a problem if the static page is served from the same domain because you will automatically get the session cookie, and the Flask-Security extension will eat that cooking and validate things for you. BUT if your static page is not served from the same domain you will not even get the session cookie. Oh Bother. But you also have a second problem. You have probably violated the CORS specification without even meaning to. Really, if I had to read the spec for every web standard I wanted to use I would seriously think about changing careers. But, here is the important part you may not return a CORS header unless the request contains an origin header! Chances are you tested you change with a quick curl call to your endpoint, saw the Access-Control header and were happy. But you sure didn’t give it an origin header on the request when you did that. So to summarize, we have two problems we need to solve: 1. We want to incorporate authentication into our cross origin strategy.
2. We want to be good citizens and follow the spec.

The Smart Approach

The smart approach is to use a nice extension where other people have figured this out, and presumably followed the specification. Enter Flask-CORS. You can enable CORS support with a simple decorator @cross_origin This will automatically add the Access-Control-Allow-Origin: * to responses. As long as your test request includes an Origin. If you are like me you will forget that part, and then wonder why the extension must not be working. So this solves problem 2.

To solve problem 1 here is a snippet of code that works just fine.

@ajax.route('/ajax/page')
@login_required
@cross_origin(supports_credentials=True)
def test():
    return jsonify({'foo':'bar'})

The above responds to the url /ajax/page I have all of my API calls in an ajax blueprint with ajax as part of the url. I’m requiring that the user is logged in before I allow them to access this endpoint. I also want it to be allowed cross origin. This is where the parameter to the @cross_origin comes into play. Supports credentials sets up the CORS response to return an additional CORS header: Access-Control-Allow-Credentials: "true". For one final twist, you need to know that when you have supports_credentials=True you may NOT set Access-Control-Allow-Origin: * You need to be specific and set the origin to the origin that comes in the request headers. To Make this work and try it out from the client side, here is a bit of HTML/Javascript.

<button onclick="corsTest();">TestCORS</button>

<script>
    function corsTest() {
        var xhr = new XMLHttpRequest();
        xhr.withCredentials = true;
        xhr.onload = function () {
            alert(xhr.responseText);
        }
        xhr.onerror = function () {
            alert("error");
        }

        xhr.open("GET", "http://example.com/ajax/page", true)
        xhr.send()
    }
</script>

Note that you need to set xhr.withCredentials in order for your session cookie to be sent along. By default cookies are NOT sent with cross origin requests.

Now, I may end up adding more to this as I discover the intricacies of so called “Non-Simple” requests. That is requests beyond simple GET and POST, as I work on moving my API toward a RESTful API which uses PUT and others. This will nodoubt enlighten me about preflighted requests. Which I can only assume means something different than sitting around in an airport bar waiting for your flight to be called.

There is a lot more detail and background on using CORS at the following two sites:

Unexpected Adventures

Morning Climb to Castelmola

Since the students were planning on sleeping in this morning, Jane and I decided to explore on our own a bit. High above Taormina sits the little town of Castelmola. You can't drive there, you have to climb. And so we did. But when we arrived in the little town we were rewarded with a spectacular view up and down the Ionian coast.


After enjoying the view we decided that a Cannoli and Cafe were in order before we started the hike down. At the end of one small street we found the perfect place. Maria, the proprietor of Gallo Cedro was cutting tomatoes on the terrace. "Prego," she said by way of invitation to come in and sit down. The Cannoli's were first rate. She stuffed them fresh for us and added some chocolate chips and pistachios to top off each end. Perfecto. We were about half done with the Cannolis when she unexpectedly appeared with two shot glasses and a bottle of almond wine. Well it was only 10AM, but we figured when in Sicily... So we had a little digestif to help the cannolis go down.

Gole Alcantara

We returned to the Lemon Tree (the name of our apartments) around 11 and everyone was out of bed and getting themselves awake for the day. We had some discussion about what we might do this afternoon. The gorge, known as Gole Alcantara, sounded like an interesting short hike and there was enthusiasm among the group for a stop at a Sicilian winery.

We made our way to Gole Alcantara and after making a donation to the parking attendant we set out on our short walk down to the gorge. It was beautiful. Of course many of our "kids" wanted nothing more than to play in the water which was quite a problem since we had not brought beach towels or anything for them to dry off with.

As we enjoyed the area, we checked our email to see if we would be able to visit any of the wineries. Unfortunately none of them could accommodate us that afternoon. So... We decided that we could do our own wine tasting back at the Lemon Tree.

Red and White

The wine tasting preparation required another stop at the supermarket where we put a strict limit on the price of wine to be purchased for the tasting. Our goal was to keep it under 100 euros while recognizing that with 13 people each of us would just get a taste of each different bottle. It was quite the production to get six of us to agree on what wine to select. I will say that the Italian construction workers who were supposed to be building another set of shelves in the middle of the aisle we fairly amused/distracted by the blonde haired blue eyed wine aficionados.

While we were in the wine aisle another group was in charge of meat and cheese and fruit. As you can see we put out a pretty good spread. We also agreed that we were "in for the night" as there was no way we were going to drive our mini-vans down or up the winding hill to the Lemon Tree after wine tasting activities.

The wine and cheese went remarkably quickly. Even with a seventh inning swimming stretch between the reds and the whites. I guess it was inevitable that after a bit of wine, some of the people were going to end up in the pool fully clothed.

With the reds, gone, people were in the mood for movies or whatever, and then "the munchies" set in. We had been told that there was at least one Pizzeria that would deliver all the way up the hill, and that Paula would take care of calling and ordering for us. After much trying however it was determined that the pizza places were closed on Monday night. The horror and sorrow of a hungry group of students without pizza. We were totally resigned to a pizza free night when Paula knocked on our door to inform me that the pizzas had arrived! We were saved. And for some reason she was convinced that the students needed a nightcap, and so brought them a complementary bottle of home made limoncello!

Climbing Mount Etna

The van arrived right on schedule, 4:45 AM, and we were all in the courtyard in front of the flat on Triq DePiro ready to go. This is our last group trip together with the Malta students, Spring 2015 edition. It is a bonus trip in the sense that because Jane saved us a bunch of money by doing so much planning for our trips to Rome, Morocco, and Istanbul, that we were able to afford the plane tickets and lodging to get everyone to Sicily. Of course with budget travel comes early morning flights, but nobdy seemed to mind very much. We were, after all, heading for Sicily. What nobody guessed was that we have a distinctly non-budget view from our lodgings for the next three nights!

The flight to Catania is ridiculously short is is just over 100 miles and takes less than 30 minutes, we barely got above 11,000 feet before we started our descent. Our departure time was so early that once we arrived in Catania we had a good hour to wait before the rental car agencies opened up. Yes, we are driving in Sicily. Its part of the plan to keep costs low for this trip. Two mini vans for the group. The plan for the day was to meander our way north to Taormina stopping along the way at Bronte to sample some Pistachios and at Randazzo to check out lava as a building material in a Medieval town.

The highlight of the day was to do some hiking on Mount Etna. It is amazing that there is still snow on the volcano in mid-May and even more so when you consider that the volcano is quite active right now.

We started out together as a group and enjoyed the break from the busy urban vibe of our home in Sliema, stopping for a group photo in this cool clump of trees:
group

Eventually the group splintered with varying degrees of adventurousness, and an unfortunate bruised thigh for Jane due to a loose rock. Some of us persevered up the side of the volcano until the winds became so strong we thought we would blow away. Climbing through the lava is a lot like climbing up a giant sand dune. It is very hard work. It also reminded us of the scenes of Frodo and Sam climbing into Mordor in Return of the King. As we were scrambling our way up, a helicopter flew overhead and hovered over us for a few minutes. I think we all expected to hear a loud voice tell us to turn around and get out of there, but I guess they decided we were harmless and not in harms way as it soon moved on. After we reached our goal we were tired and happy to be there if only for a few minutes to enjoy the view.

If you look close, you can see part of the group on the plateau in the middle right of the picture.

As we began to descend our shoes soon became filled with sharp little pieces of lava. This made the descent quite painful and necessitated a few stops to empty the shoes. At one point I was really glad Emma was standing behind me as she remarked. "I wonder who's glasses these are?" Of course they were mine having just fallen out of my pocket as I was emptying my shoes. That would have been a loss, and impossible to find one pair of transition lenses hiding in miles of black rock.


group

Enjoying Island Life on a warm May Day

Every day is a good day when you are on a boat, in the beautiful blue Mediterranean. After a bit of a mixup on the bus this morning, we got to spend 4 amazing hours with Captain Franz on a boat trip from St. Paul’s bay to Gozo to Comino. Complete with caves, and cliffs, and swimming. Click on the thumbnail below to see the photo gallery for today.

The bus mixup is amusing now that I look at it a day later… We had arranged for van to pick us up at 9:00 to bring us up to St. Paul’s bay. But after waiting and waiting I finally connected with my contact, Rachelle, at the University who handles all our transportation scheduling for us. It turned out the bus company had screwed up the schedule for the day. The solution was to send a coach. The only other vehicle available and in the area. No, not one with horses, a giant bus. Wait by the corner we were told. Oooops wrong corner. More delay. Imagine the 14 of us on a coach that could easily hold 60 people. So we made it to St. Paul’s in Style and in the end were only about 35 minutes late. Thankfully Frans was a very patient captain, and it was no problem to extend our time in the afternoon to make up for our lateness.

Writing a Runestone Lab the Easy Way

Background

As part of the grand reorganization of the various tools and software associated with the Runestone Interactive project I am planning to also write a series of tutorials to help people get started. The major aspects of this reorganization are discussed in detail in the Project Roadmap, but for the sake of some context I can summarize the major efforts as follows:

  1. Separate the distribution and development of writing tools from the server.

    1. Make a pip installable runestone package.
    2. Remove the interconnectedness between the components and Sphinx. In other words support the user of runestone tools in environments like Markdown, and even wysiwyg html editors.
  2. Re-architect the server side focusing on services for the writing tools

    1. Create an authentication service that supports CORS for cross domain AJAX use.
    2. Create a standard REST API for logging and storing student data
  3. Create a web application (or integrate with another) for grading

Since I just completed Part 1.1 I thought it was a good time to talk about how easy it is for you to now use the runestone tools for creating a lab for your students, or lecture notes and presentation materials for your class.

Getting Started

The major steps in getting started are

  • Installing Python
  • Installing the runestone tools
  • Building your first lab

Install Python

  1. If you are on a Mac you are already done with this step.
  2. If you are on Windows you will need to go to Python.org and download Python3.x. The windows installer is a typical installer and you can just click your way through it.

If you are an advanced Python user you may want to may want to create a virtualenvironment for this project but it is not a requirement.

If you are on Windows you may want to edit your PATH environment variable following the instructions here. Again, mac users can ignore this.

Installing the Runestone Components

You are going to need to use the command line for the rest of this tutorial, so start up a Terminal (/Applications/Utilities on a Mac or run PowerShell or cmd.exe on Windows) I will repeat myself here. These commands need to be run from the command line, not from the Python shell.

Run the pip command

$ pip install runestone

Or on Windows if you have not modified your PATH try:

C:\\Python34\Scripts\pip.exe install runestone

From now on I'm only going to give the Mac way of running the commands. If you are on windows you will need to add C:\\Python34\Scripts to the beginning of the command and add .exe to the end.

You can watch as a lot of text goes scrolling by. But as long as you don't get any errors you should be good to go. You only need to do these first two steps once. Once you have installed Python and runestone you will not have to do it again.

Starting your first Runestone Project

Here is a session of me on my computer creating a simple project.

$ mkdir mynewproject
$ cd mynewproject
$ runestone init

This will create a new Runestone project in your current directory.
Do you want to proceed?  [Y/n]: y
Next we need to gather a few pieces of information to create your configuration files
Project name: (one word, no spaces): myhello
path to build dir  [./build]:
require login   [false]:
URL for ajax server  [http://127.0.0.1:8000]:
Your Name  [bmiller]: Brad Miller
Title for this project  [Runestone Default]: My Hello World
Log student actions?  [True]: False
Done.  Type runestone build to build your project

At this point you will have the following files and folders:

mynewproject/
        _static/
        _sources    
        _templates  
        conf.py
        pavement.py
  • The _static folder is for things like images or javscript files.
  • The _sources folder is where you will put your own writing. To start with there are a couple of examples files for you.
  • The _templates folder is for styling. There is a default set of templates that match the runestone interactive look and feel. That is a good thing to start with. Once you become more familiar with the system you may want to customize the templates or even make your own.
  • The conf.py file is used by Sphinx, and contains information from some of the questions you answered when you initialized your project.
  • The pavement.py file is used for building and setting build parameters.

All of these files are important, and you should not delete any of them.

Next run runestone build This command will create a build/mynewproject folder with an index.html file in it. If you want you can now run runestone serve and then go to your browser and open up the following URL http://localhost:8000/index.html Yay! You have a webpage. Feel free to explore a bit to get an idea about some of the components you can use in your lab.

Writing your Own Lab

OK, lets edit _sources/index.rst Initially it looks like this:

=====================
This Is A New Project
=====================


SECTION 1: Introduction
:::::::::::::::::::::::

Congratulations!   If you can see this file you have probably successfully run the ``runestone init`` command.  If you are looking at this as a source file you should now run ``runestone build``  to generate html files.   Once you have run the build command you can run ``runestone serve`` and then view this in your browser at ``http://localhost:8000``

This is just a sample of what you can do.  The index.rst file is the table of contents for your entire project.  You can put all of your writing in the index, or as you will see in the following section you can include additional rst files.  those files may even be in subdirectories that you can reference using a relative path.

The overview section, which follows is an ideal section to look at both online and at the source.  It is pretty easy to see how to write using any of the interactive features just by looking at the examples in ``overview.rst``


SECTION 2: An Overview of the extensions
::::::::::::::::::::::::::::::::::::::::

.. toctree::
   :maxdepth: 2

   overview.rst


SECTION 2: Add more stuff here
::::::::::::::::::::::::::::::

You can add more stuff here.

If you are not familiar with markup languages, this file should still be quite readable to you, and you can probably easily guess what most things do. Runestone uses a markup language called restructuredText. There is a very nice, short tutorial here.

To give you an idea of what you see in the example above, the section that starts with .. toctree:: is called a directive and it creates a table of contents for you. the maxdepth part sets the table of contents to show sections and subsections. And the line with overview.rst indicates that it is a file that should be included in the overall web page. More on all of this later. Our first task is simply going to be to wipe everything out, and start over. Using a plain text editor change index.rst to look like this:

=============
My Sample Lab
=============

Part 1: Turtle Graphics
=======================

In this section we will do the following:

* Create a turtle
* Make the turtle draw a box

.. activecode:: turtle1

   import turtle

   timmy = turtle.Turtle()
   for i in range(4):
       timmy.forward(100)
       timmy.right(90)


Now it is your turn.  Can you modify the program to make timmy draw an octagon instead of a square?

Now save the file and rerun the runestone build command. Everything should build without a problem and you can now run runestone serve and open up http://localhost:8000 from your browser. Notice that you can change the program and rerun it right from your browser.

It is probably obvious that you can create headings and subheadings. Unordered lists are created using * and the runnable code examples are created by the .. activecode:: directive. The name turtle1 must be unique on the webpage, other than that it is not used for too much at this point. The rest of the activecode directive contains plain old python code, but it must be indented to line up with the a in activecode. All indented lines are included as the body of the activecode directive, regular text processing starts at the first unindented line.

There you have it. You have created a very nice little lesson without a lot of hassle. The Runestone and Sphinx tools take care of all of the formatting for you!

Giving Students Browser Access to the Lab

If you have your own webpage hosted on a school server that you normally use for class you can make your Lab available to the students by simply taking the folder mynewproject inside the build folder and putting that on your website. The folder is self contained and can be hosted on any web server.

If you know the IP Address of your own computer and you simply want to give let students bring up the webpage from your computer you can do that too. For example, lets suppose you know that your IP address is 10.0.0.23 Your students can get everything they need from http://10.0.0.23:8000/index.html

Coming Soon

There are many free web hosting solutions out there and you can also choose one of them and upload your project folder for hosting there. I'll cover at least one of them in another tutorial. In fact I think I see a whole series of tutorials in the future on topics such as:

  • Making an online quiz for class
  • Making a lecture or presentation
  • Hosting your lab or quiz on github pages or another online service
  • Using your lab with runestone services

A Tale of Two Scams: In Three Parts

Gastronomic Negotiation

"Sir, you walk past me every night. Please give me a chance! I will give you an appetizer and free baklava for desert!" Really? I honestly don't remember you. I've only walked down this road one other time. "Very Sorry" I say, "I've already got a dinner reservation back at Ocean's 7. " "you will like it!" Says one of the patrons at the current establishment. Another ten steps down the road and we are implored to "Look at my menu." A bit further on we are told "Sir, I have your table ready for you!" The idea that you can bargain for your supper seems so counter productive to me that I just cannot fathom it. Hey, lets see how little I can pay for something I'm about to ingest into my body. The incentives here are all in the wrong direction!

I can only imagine the conversations in the kitchen:

Waiter: One chicken and rice for the cheapskates at table five!

Chef: Oh great, now we know what to do with the gizzard and thigh meat that has been sitting on the floor all night!

No Thank You I will be more than happy to pay a price that puts the chef on my side.

Waiter: Chef the generous folks are back at table seven.

Chef: Great, tell them to order the veal, I've got two extra tender pieces I've been saving for my best customers. Oh, and bring up that 2011 Rombaur Chardonnay from the cellar, I know they will love that.

I think we can all agree on which chef we would rather have cooking our food.

This whole hawking the restaurant thing has been an ongoing saga since we arrived in Istanbul, and we even experienced it in London a couple of weekends ago. I don't remember it being the case in Vietnam or Morocco, and certainly not in Malta, but maybe this has more to do with the onset of high touring season than our location. Now, this is not really a scam (although we have heard stories of the old bait and switch ) so much as an intro to the two things that happened to us today.

Cruising on a Reputable Ferry

Our plan for the day was to take the Ferry up the Bosphorus river to the mouth of the Black Sea. You get to see a lot of Istanbul along the way, then the ferry stops for a couple of hours so you can have lunch or do a little hiking and then comes back. As usual Jane had it all planned out, including a discount for using our museum passes. When we arrived at the waterfront we were immediately accosted by the usual crowd of tour people trying to sell us one of their packages. -- two hour boat trips, three hour boat trips, six hour boat trips... "No, we are going on the ferry!" we would say. "But I can leave sooner. I will take you to the same place, wait for two hours and bring you back. My boat holds 80, it will be much nicer than the ferry and 800 people!" Hmmm, we were intrigued, and a bit horrified that we were even considering this option. But after a bit of negotiation, and multiple confirmations about our destination and pricing we decided to risk it. The captain even threw in a 50% discount on coffee at the nearby snack shack. Run by a relative no doubt. "Just wait here" we were told. So we waited and watched them try to work their magic on other passersby.

After a while, one of them came up to talk to us.

We cannot take you. I cannot do the trip for just your group. It will be better if you take the ferry, down there. There are not enough passengers today, because the bike race is keeping them all away from here. I am sorry.

It was true, there was a big Tour of Istanbul bike race in town, and the weather was a bit dreary, so the pier was sparsely populated. Which also meant that the ferry was not nearly as crowded as Jane's research had led us to believe it would be. So, we carried on with our original plan, got our tickets to the ferry and were on our way.

The cruise was interesting, we got to see some castles, and some amazing real estate. And even a container ship that originated from Valletta! We just can't get away from Malta now. Here is a little slideshow of some photos on the tour.


The shoeshine redemption

After the cruise we had to make our way back into the spice market to buy some of the delicious candy covered "fistik." That is peanuts covered in a syrup and rolled in sesame seeds. We discovered these our last day in Morocco, and were only too happy to find out you can buy them in Turkey as well. Some of the group wanted to hit the archeological museum while others just wanted to wander the spice market some more. So we turned them loose and decided to wander our own way back to the hotel.

As we were passing up one street that was very lightly travelled a shoe shine man dropped his brush in front of us. So, we picked it up and called out to him to give it back. He thanked us and we were on our way. Suddenly he called back to us. He sat down and and said "please," with a look that said let me repay your kindness. We thought how nice, one good turn deserves another. But I had on my hiking shoes, which are not "shineable" and so he offered to shine Jane's black shoes which were definitely in need of some love after all of our travels. He finished up Jane's shoes and then insisted on brushing mine with a toothbrush and some water -- which certainly did not hurt. About this time both Jane and I reached into our pockets for a few coins to tip the guy.

Imagine my surprise when Jane offered him several one lyra coins and he said "no, paper" What? He doesn't want coins he wants paper money? Slowly it dawned on me that we had been played this whole time. He now wanted to be paid the full amount for two shoe shines, which took less than a couple of minutes. I added my coins to Jane's and dumped them in his hand and we turned and walked away. I guess we both got half price shoe shines, and nine turkish lyra (about $3). Lesson learned, and a small price to pay for a story to add to the blog.

Istanbul: Capital of two Empires

"You want a fish!?" Said the night watchman with confusion. "No," I said, "do you have a cork-screw?" doing my best imitation of screwing in a corkscrew and then pulling out the cork. "Ah! One moment" And off he went, out the front door and into the restaurant across the street. Moments later he was back with an excellent corkscrew, which I used to uncork the bottle we had purchased around the corner and then returned to him. After I got back to the room I could not contain my laughter any more. A fish? The fact that he borrowed the corkscrew from the restaurant, which was the very thing that Jane had suggested in the first place. An idea that I soundly rejected. Hi, I know that we didn't eat dinner here or buy anything from you but would you mind terribly if I borrowed your corkscrew to open the bottle of wine I bought at the market around the corner? I just can't imagine myself saything those words.

A glass of wine was a great way to cap off what had been a very full day of touring around the old city of Istanbul. Once known as Constantinople, it was the head of the Christian world. Then under the Ottoman empire it became a Muslim country. Today, Turkey is largly muslim, but the government is a secular government. We began with a tour of Topkapi Palace were we visited the treasury, and the Harem and saw the Sultans private rooms. We also visited the tulip gardens. It is an interesting fact that although Holland is usually celebrated for its tulips, the Dutch took them and transplated the tulips from Istanbul originally!

Tulips

In the hall of mirrors, I told students about recursion.

They did not care.

From the Palace we moved on to the Blue Mosque, one of the icons of Istanbul. There was a really long line to get in, but we made the best of it, while Ben ran into someone with nearly the same last name as him in line. He turned out to be from wisconsin, and has relatives in Decorah. Small world. The line was rather entertaining, as standing in line appears to be optional for many tourists here in Istanbul. However all of the guides team up to try and send the line jumpers to the end. It is interesting to see the reaction of the people who clearly know they are being jerks and getting called out for it. Once we got inside it was amazing. It is so hard to describe this space, like St. Peters in Rome it is just so large that you cannot hope to capture the scale of the whole thing.

Across a very large square from the Blue Mosque is Hagia Sofia. This was once the largest Christian church in the world. Of course it was later supplanted by St. Peters and others. The really interesting thing about Hagia Sofia is that it was converted to a Mosque. Check out the apse of the church in this next picture. Notice that the alcove is not centered. This is because even though the church was sited east to west, the axis was just eleven degrees off of the line to Mecca. Because Muslims do not allow for images in their mosques all of the mosaics were covered in whitewash and then painted over in more typical muslim designs. Except for the Seraphim. Look at the two images below:

Notice that the only difference here is that the face was painted over with a symetric diamond shape. Some of the mosaics that they have begun to uncover and restore are really stunning.

Hagia Sophia

Finally, we visited the cistern under the basilica. You may remember this from James Bond, "To Russia with Love." It is just this giant underground place that used to provide water to the city. But now, it is just stunning:

The Cistern

After all of that we headed back to the hotel for a short rest before we took the students out for a group dinner. We were all plenty exhausted after such an interesting day. Tomorrow, the Grand Bazaar, the Spice Market, and Taksim square.

Biking in London

Think you have done it all in London? The museums, the London Eye, the changing of the guard, the Thames, the list goes on. Here is a great way to spend a day, for almost no money. Rent a Barclay's bike and head for the Regents Canal. This is exactly what we did and it was a fantastic way to enjoy London away from the traffic and the museums.

You'll discover a whole different culture and way of life when you bike along the canal. There are hundreds of narrow small barges that people live on or work the canal on. We saw all walks of life that appeared to be barge owners, from the very wealthy to those who reminded us of the people in Veitnam who lived on their boats with no heat or running water.

The path is fairly narrow, so you have to be alert or you could get wet, which would definitely spoil an otherwise good day. Also you need to remember that pedestrians have the right of way, so just be polite, use your little bell, and don't go too fast! We didn't have any trouble, and we enjoyed all of the scenery and the side trips that are available from the canal path.

On day one we started from Angel, and followed the path toward the London Docklands. It was warm and scenic, and gave us a great taste of barge life on the canal. We wandered around the (free) docklands museum, hoping to learn a bit more about the canals, but were disappointed. The docklands museum is actually a very interesting history of London, so that was not disappointing, just that the museum didn't have anything to say about the canal.

On day two we went the other way, and ended up having lunch in the rather bohemian Camden Market area. We also took a side trip around the zoo and the royal gardens to see some incredible villas that have been built right along the canal.


I love London. It is probably my favorite big city in the world. I think I have visited at least six times. So I have done the museums and most of the good tourist attractions. My top five would be:

  • The Transportation Museum in Covent Garden
  • The science museum in Kensington
  • The Imperial War Museum
  • Our visit to Parliament
  • Westminster Abbey

This was a really great alternative way to spend the better part of two days enjoying London culture from the perspective of a cyclist.

As a bonus part of this post, I do have to admit that I had never done the London Eye until this visit. It was definitely a fun way to get a view of the city. Jane and I both did a little bit of experimenting with time lapse videos on our iPhones. I wish I had brought my tripod so I could have captured the entire circle.


FA Cup Semifinal

The first words I read as my phone synced up email in the passport control line at Luton were "still no tickets." The message went on to explain that the tickets were still supposed to be delivered by eleven PM by someone named Jamie who is running behind schedule.

Wembley Stadium

Getting tickets to the FA cup game is no easy trick. All of the tickets allocated to both clubs (Arsenal and Reading) were sold out to season ticket holders well in advance, so visitors like us are left trying to buy tickets online from third parties at crazy high prices. Yes, its crazy to pay over $300 to go to a soccer match. Yes, I paid it willingly! We did some research, so we think this is a reputable source of tickets but you have to put a certain amount of trust in strangers in order to get your tickets.

After the train ride into Farringdon station we walk over to the apartment we had rented through AirBnB, another exercise in trusting strangers, and are rewarded with exactly the fantastic two bedroom apartment we were promised. The owner met us at the door and showed us around. He had purchased us some breakfast items, and some fruit, and a nice bottle of wine. The apartment is on a Kings Mews street, which is nice and quiet so no problem with street noise either.

Jim and Josh arrived a few minutes later with Jim's luggage. We got a two bedroom so we could share with Jim and so he would not have to spend the entire long weekend in Josh's student housing. Which after seeing it, I am glad we did!

As 11:00 came and went, we still had no tickets. So we were preparing ourselves for the worst, which is really not too bad considering our apartment has a 56 inch big screen for the backup plan. We were all a bit nervous, but found some good entertainment value in the chat that Josh had been having with customer support at the ticket agency.

Cust Serv (23:35:25): How can I help you?

Cust Serv (23:35:29): hi

JMS (23:35:45): Hi Tina, we spoke earlier today about my order #XXXXXX. The tickets still haven't arrived yet.

Cust Serv (23:37:07): I know - i have been told by Jamie that the tickets will arrive at your house by 11am in the morning as he have to do lots of deliveries and was promised by him they will be with you at 11 at latest

Cust Serv (23:37:16): please accept my deepest apologies

JMS (23:37:36): 11am? This is now the fourth promise made by your company to me in the past two days.

JMS (23:37:40): This is unacceptable.

...

JMS (23:46:05): Thanks for your assistance on that. I know it's not your duty, and I am clearly angry, but I will not subject you to that anger.

Cust Serv (23:46:24): A refundable situation sir is where you did not get your goods as ordered and in time to watch the match

Cust Serv (23:46:39): but once again it is not my decision as you understand

JMS (23:46:56): I know that that's a full refund, but I think the stress caused here warrants a special situation.

JMS (23:47:11): But yes, I won't take it up with you! My mistake.

...

JMS (23:52:29): I don't think so. I'm sorry you've had to deal with me today (and plenty others like me I'm sure!) during this busy day. I know you're trying your best, but like I said earlier, my family flew in for this match and would ruin their holiday if this falls through.

Cust Serv (23:52:54): sir - I must say that you are one of the most kindest people I spoke to in this chat support ever!!!

JMS (23:53:17): Haha well I'm glad to hear that. I'm sure customer service can be very testing at times.

Cust Serv (23:53:40): you are very polite and kind despite being angry and dissapointed but you never had it on me at any point of our conversation and I thank you for that

JMS (23:54:26): Well I'm glad it has been a (relatively) positive experience. Hopefully I won't have to chat anyone at your business tomorrow at 11:15! Good night.

Cust Serv (23:54:49): I hope that the only chat you will have tomorrow is to say that you have got the tickets as ordered sir

Cust Serv (23:55:03): good night sir- sweet dreams

Sweet dreams indeed! By 9:00 the next morning, we got the good news that we had tickets in hand. The problem was that they were not in the category we had paid for. They were not bad tickets! In fact they were really good. Row 8 on the first level, but they were in the corner so we would be looking at the field the long way. Since the website said tickets were fully refundable if you did not receive tickets in the category you paid for you were eligible for a full refund. So we got online and complained a bit. The first response was that we had been upgraded, and that these were actually better tickets than we had ordered for this game. LOL.

Shortly after this conversation we received a call saying that they had tickets for us in the area we had ordered. However these were way up in the nosebleed area, and we would be split two and two. about this same time we also noticed that two of our tickets had post-it notes attached with the note that they were Junior tickets. Hmmm, maybe we got the wrong tickets? Maybe they need to swap with us to get these to some guy and his two kids. Well, we reasoned, we don't have to meet this guy and get the other tickets, possession is 90% of the law. So we began to think about breakfast. But before we all met up for breakfast, we got an email from Karen, who had been woken up at 3AM back in the US by a call from Thomas, who wanted us to call him on his mobile.

It turned out that Thomas also had tickets, but said they were "VIP tickets." Karmic payback for being "one of the kindest people I spoke to in this chat support ever"? Maybe! Two of these new tickets included access to a table in the Bobby Moore hospitality area (free pre-game meal and drinks), and two of them were "merely" on the Wembly Gold (free budweiser at halftime) level. So, in less than 12 hours we had gone from zero tickets to tickets that were beyond anything we could have imagined. These tickets would be delivered to us by another delivery person, and then we were to meet Thomas near Wembly to return the four we originally had received. The new courier arrived at our apartment in a shiny white Range Rover, and delivered our packets of tickets. They all looked legit, and we all had great seats right on the halfway line! Now all we had to do was find Thomas and hand over the old tickets. Those young children might get to see the game with their dad yet.

As we made the walk from the Wembley tube station towards the stadium we had many opportunities to sell our four extras. We thought that we might even make a profit, but our honesty and the fact that we had VIP tickets in hand, put us in the mood to carry on to our meeting point and keep up our end of the bargain. It is interesting to think about the business model and operations of a third party ticket seller. They are selling the tickets to us at a significant markup, but the tickets have to come from somewhere. So they have to be able to forecast in advance how many tickets from each area they will probably have, and then they need to get those tickets from the original owners to the new buyers. Its no wonder a lot of the transactions come down to the wire.

Our tickets allowed us into the stadium well in advance of the game so we had plenty of time to soak up the atmosphere and check out all of our food, beverage and gift shop options. As we were standing in the gift shop I saw one young man in Reading blue from head to toe, with a big foam blue finger call out to his dad. His voice was shaking with excitement as his big blue finger pointed to a rack of merchandise. LIVERPOOL he said with longing. The dad just melted into the ground. I guess you can't control who your kids will choose for their football team, even in England.

As a fan of the Men in Blazers show, I was very excited to see that meat pies were available everywhere in the stadium. Tom's pies to be exact. So I enjoyed a very nice Guinness and roast beef pie as a pre-game meal. It is true, they are quite good. flakey crust, stringy tender roast beef and gravy on the inside, just like Sunday dinner back home. So, here is the obligatory food shot! You might also notice the betting sheet on the left side of the photo. You can bet on almost anything right there at the game. Final score, who will score, when will they score, who will score first, etc. It was too complicated for us so we left the betting up to others and saved our money for sausages and more food later.

beef pie

The game itself turned out to be good. It wasn't Arsenal's best performance of the year. But I blame that on Wenger for going away from the lineup that had us winning nine in a row. I would not have substituted Welbeck for Giroud, but I am not the manager. Nevertheless Alexis scored a great goal just before halftime and I was feeling good. A strong pep talk in the locker room and surely we would come out and seal the game with a couple more goals. It turned out that the opposite happened. Reading came out fired up and scored an equalizer, and we looked like we were playing "not to lose" which is our worst strategy. At the end of regulation it was Arsenal 1 - 1 Reading. OVERTIME! We were really getting our moneys worth out of these great seats. As long as we win in overtime and don't go to penalties life is good Which is what happened. shortly before the end of the first extra period Alexis scored again. It was kind of a sad screw up for the Reading keeper, but a victory is a victory!

Corner Kick

On to the FA Cup Final!

Homeward Bound in 77 Days

Somehow the midpoint of this journey escaped my notice. Its not surprising as it has been a busy and amazing two weeks, full of new cultures and new experiences. But, this morning we have time to just relax, watch the sea outside our room, and think about our experiences over the last three months. In total we will be gone for 179 days! That is a long time to be away from family and friends and the comforts of home. But the time has gone by quickly, and will only accelerate as we head towards the end.

I took a few minutes this morning to put together this map. The red pins show everywhere we have been since January 1, 2015 and the green pins show all the places we have yet to visit before we arrive back home on June 28th.

So, what do I take away from this journey so far? I would like to break it up into three themes:

  • The expanse of history
  • The variety of culture
  • The challenges of living away from home

History

I never would have guessed that a new understanding and appreciation for world history would have been one of my biggest takeaways from this experience, but it is certainly shaping up to be that way. A big reason for this has been the history course at the University of Malta, and seeing the evidence of history everywhere you turn. You go to Valletta and you can't escape seeing the walls and the buildings left behind by the Knights of St. John's. You visit other places and see the Megalithic temples or evidence of the Romans or Phonecians or the Ottoman Empire. But what is really cool is that now when we leave Malta I have a much better appreciation for the timescale and the artifacts left behind by these same people in other parts of the Mediterranean.

The scope of the Roman empire is simply amazing. As we were standing among the Roman ruins in Volubilis Morocco, we could just as easily have been standing in Ostia Antica in Italy. The frescos on the floor looked the same, the aqueducts and walls were identical to those we have seen in Italy, France, and Spain. Now we flew, on a jet, and drove in a fast car to all of these places. Its really hard to imagine how an empire like this managed when the way to travel was on horse, or foot, or camel. There was no internet to get word back to headquarters so its easy to imagine that important information would be lost or take many months to get from place to place.

In Malta, the arabic influence is clearly heard in the language, but not so much in the architecture. However now that we have traveled to Morocco and Spain it is interesting to see the influences of the Ottoman empire in both places. It is also interesting to see how all of the different empires recycled and reused materials from their predecessors. Mosques built from the stones of Christian churches and vice versa. Churches that still bear signs of a mosque built from stones taken from a prehistoric temple. I am really excited to visit Istanbul in a few weeks to see this city where Islaam and Christianity have coexisted for so many centuries.

I think that I have developed a better appreciation for the timescale of history. When we hear that at one time Malta was predominantly Muslim, but now Christian, or that the Berbers of Morocco were predominantly Jewish but are now Muslim you wonder how did that happen? Slowly. These are changes that took place over hundreds of years. Longer than the United States has been a country! Back home we might say, look at this old building, it has been around since 1849. That is barely a blip in the timescale of the history here in the Mediterranean. At the same time, I have developed a new appreciation for the importance of preserving our own historical artifacts for future generations to study and learn from.

Cultural Variety

Living on internet time, it is easy to think that everything and everyone has always changed as fast as it does today. But, it is easy to see that this is not true. In the pueblos blancos of Spain, the towns of Malta, and the villages of Vietnam and Cambodia, things don't move so fast. People still fix their old televisions and home appliances rather than just toss them aside after five years. In the medinas of Morocco and the villages of the Mekong delta people still use every part of every animal and plant. Husks of rice kernels are used to fire the kilns for making bricks, every part of the cow or goat or camel is used for something.

I love to observe the old men in the different places that we visit. They are the same everywhere! If I was a better photographer I would ask their permission so that I could take their pictures and share them. On my walk to the University in Malta ther are three guys that sit on the sidewalk every morning, talking and arguing and solving the worlds problems. In Spain we saw them in the small towns, having coffee when we would stop for our own mid-morning break from cycling. Having a coffee, and talking, arguing, and solving the worlds problems. In Morocco they gather for their tea and they talk and they argue and they solve the worlds problems. They supervise local construction projects everywhere. It is the same in Decorah as well: at the Back Home bakery, or the Oneota country club, or happy hour at Rubaiyat. In Decorah, I know the names of most of the men, and am slowly beginning to join their ranks.

Morocco was my first experience in traveling in a predominantly Muslim country. Vietnam and Cambodia are predominantly Buddhist. Malta is strongly Christian. Of course there are big differences in all of these religions, but the main thing that strikes me is that the people who practice any of these religions have much more in common than you might think. Of course, as our Moroccan guide noted, there are crazy Christians and crazy Muslims and crazy Jews who cause trouble, but the non-crazy people want to live good, healthy, peaceful lives. People of all faiths love their children and their neighbors and want to make the world a better place.

Talking about religion, you can't ignore Football (soccer). Soccer is another great unifier of people. If you are a soccer fan, you can find a friend almost anywhere. We have enjoyed watching the English Premier League in every country we have visited. Of course in Spain it was a bit more of a challenge as La Liga dominates here. But we have always been able to find a pub that carries the game. People everywhere know Arsenal and Manchester United. More importantly, they love to talk about their local team. I love to ask the waiters or the porters in the hotels if they are soccer fans and who they support. They are always a bit surprised to find an American that is an avid futball fan. Is soccer really growing in America? How did you become a fan? What will happen with the MLS? Are you happy that Steven Gerrard is joining the LA Galaxy? How many years will it be until the USA dominates in the world cup?

Living away from home

When we left home in January Jane and I talked about how this would be a great experiment. Would we be ready to be snowbirds? Would we miss our friends too much to leave Decorah for six months? What would it be like to make friends in a totally different culture? It turns out that this was a flawed experiment.

Although we have settled in to a flat in Malta its hard to compare this to what it would be like to have our own place in California or Arizona. Although the flat is perfectly livable it is not ours, it is not even something that we would choose if given the chance to look around. And, because we do not own the place and are only there for five months, we can't really change it. No painting, no updating, so Nespresso coffee maker. So we live with what we have, which is very different from how we would do things if it were our own.

I am grateful for my own research work. It has been nice to have some time to really sit back and think about the direction my research and work on Runestone Interactive will need to take over the next few years. I have learned that I am far from ready to retire or give up the exciting work that I do on this project and with students at Luther.

The people we have met in Malta are very nice, but we have not made new friends. Building relationships takes time and investment, and it is hard for others to invest when our time in Malta is so short. It is hard for us to invest when our time is short. It makes us think about being more welcoming and open to new friends back home. It is easy to settle in to the same comfortable group of friends week after week. It is much harder to break out and invite new people into the circle. Mike and Shirley do a much better job of that than anyone!

So, we have settled in to a routine that largely centers around the students and ourselves. Occasionally we have gone out with another couple, but this is fairly rare. We have Skyped or Facetimed with our friends and family back home and have really enjoyed those times as much as anything. Technology is a wonderful way to connect. All of those Jetsons cartoons I watched where they used the video phone have come true. So, although we have always valued our friends, we have learned how important those friendships are on a much deeper level than we knew before.

Although we have traveled many thousands of miles, and logged many nights in hotels and restaurants, it is important to stop and realize that this journey has been an inward journey as well. I am thankful for the growth and learning that this experience has brought so far, and I eagerly await the new experiences yet to come. As we prepare to pack up and head to the airport this afternoon, I find that I cannot say we are going home. Home will come soon, we will be home when we are back in Decorah and with friends and family on Bone Lake.