runestone
New Instructor Dashboard
I’ve been working on a new instructor dashboard the last week using Plotly + Dash. Its taken a while to wrap my head around the declarative style, and to learn the ins and out of plotly. But I’m getting there. Let me know if you want a closer look and would like to give me feedback! In the meantime here is a preview.
Understanding Entrepreneurship -- Part II -- New Beginnings
Whenever I teach this JTerm course on entrepreneurship, friends and colleagues often ask me “do you miss it?” Meaning do I miss the business world. The answer has always been, “yes, but I love teaching even more.” This year the answer is different, this year the answer is… “yes, and I’m excited to tell you that I’m leaving Luther to start a new company!” Spring Semester of 2018 will be my last semester as a full time faculty member at Luther. I have accepted the separation agreement offered by Luther, and I’m really looking forward to the next chapter in my life and career!
This was not an easy decision – I have enjoyed my time at Luther, and Jane and I could not have asked for a better place to raise our family. JTerm is always a powerful reminder of how great our students are, and how much I enjoy getting to know them beyond the classroom. But, Kaia and Josh have both graduated from college, Kaia is married, in grad school, with a house, and three dogs in Sioux Falls, Josh has a great girlfriend, and a job he likes in Wisconsin. In short, they are launched (yay us!).
We are ready for the next phase of our lives. So, the house in Decorah is for sale and we have a down payment on a condo in downtown Minneapolis! We close and move in September of 2018! The bike trails are out the back door, we have a view of the Stone Arch bridge, the Guthrie is three blocks away, the light rail to the new MNUFC (Loons) stadium is a four block walk! It is a 15 minute bike ride to our friends Brian and Holly for happy hour! What could be better? – Well, if we could convince a few Decorah friends to move to Minneapolis that would be perfect, but we try not to be greedy.
Runestone Interactive, LLC
So, this January I’ve been listening very closely and thinking about how all of these great stories and advice apply to a guy in his mid-50’s. I’m leaving a tenured faculty position, at a college I love dearly to start a new company. Here is what I take away.
We heard the following from a lot of different people: “follow your passion!” Well, I admit I’ve told my students this many many times (although I could write a full post on the perils of telling 19 year olds that they need a passion.) But I have to say that for as much as I enjoy teaching at Luther College, Runestone Interactive has definitely become a passion. Runestone has grown from a small project for 30 Luther students few years ago, to supporting over 20,000 students each day from over 600 institutions around the world. This growth has all happened through word of mouth. No advertising, No booths at trade shows, no sales force, no full time development team! I really think that Runestone could be 2,000,000 students a day with focus and full time effort. – Yes, former students, that is what I think about in the shower in the morning!
The separation incentive offered by Luther gives me the opportunity to start a new company, incorporating what I learned from all the mistakes I made the first time around with Net Perceptions, and all of the experience I’ve gained in the last 15 years of teaching. It gives me one year to figure out if there is a business model that will keep the basic features and the books of Runestone free to everyone, while allowing me to build a small business that pays a salary, and hopefully allows me to bring others on board to work on this with me. It allows me to (1) follow a passion, (2) make the world a better place and (3) to play my part in “righting the wrong” that is textbook publishing today. Yes, $300 for a paperback textbook is a wrong! Wow, count them, that is three awesome reasons to start a company!
Democratizing Textbooks for the 21st Century
In our discussions of Guy Kawasaki’s books during JTerm we talked about companies needing a mantra. I think that the Mantra for Runestone is “Democratizing textbooks for the 21st century”. This could be another whole post, but I’ll just say that there is a huge need for computer scientists and there are a lot of well meaning, (but potentially under-prepared) teachers out there who we can help teach computer science. This is true at the high-school level where computer science is getting traction again, as well as many small colleges where it is almost impossible to find a computer science PhD who is willing to work for what small colleges can pay.
The second piece of Runestone is in the interactive nature of the books. Textbooks should not be static, read-only, words. Textbooks in the 21st century should engage the reader in interactive learning. Textbooks should also give instructors insight into what their students understand and what their students are struggling with… Textbooks should help answer the question “How can I maximize my time in the classroom today?”
Get Uncomfortable
We heard a lot about seeking opportunities that make you uncomfortable. It is through these uncomfortable experiences that you grow. For the last 15 years this has happened through teaching (especially new courses), and traveling to new places (many times with students) and experiencing new cultures. Leaving my faculty position – where I have almost total job security – is definitely a move in an uncomfortable direction. Especially for someone over the age of 50. But, I am convinced this is the right thing to do.
Creating a culture, charting your own course
We heard from a lot of people that had worked in both large and small companies about how great it was to be part of a small organization. in a startup, everything you do is important. From making the coffee in the morning, to setting strategic direction. I get that. I remember those early days from Net Perceptions. I miss those days. I miss that sense of ownership for the whole enterprise. The “shared governance” model used by most small colleges is about as far from agile as you can get.
This course reminded me, yet again, why I admire Jeff Bezos and the culture he has built at Amazon. I was blown away that all of the young people we spoke with at Amazon understood and could talk about many, if not all of, the 14 leadership principles. If you don’t know them here they are:
-
Amazon’s Leadership Principles
-
Customer Obsession
-
Ownership
-
Invent and Simplify
-
Are Right, a Lot
-
Learn and be Curious
-
Hire and Develop the Best
-
Insist on the Highest Standards
-
Think Big
-
Bias for Action
-
Frugality
-
Earn Trust
-
Dive Deep
-
Have Backbone; Disagree and Commit
-
Deliver Results
-
You can get more detail on each of them here. But I can only fantasize what a great company Runestone would be if I put these into action. I also think that higher-ed could benefit from all of these principles, but the conditions are so hard to make this happen!
So as I finish up this post, I have a week until Spring Semester classes begin. Am I sad that this is my last semester? Of course! Luther College is such an integral part of my life – I’m an alumni, a parent of an alumni, a faculty member, and a donor. I’ll only be losing one of those four tags. I look forward to finding new ways that I can serve the college in the future. I’ll also miss the students and all of the energy they bring. I’ll miss watching them grow and develop into the successful entrepreneurs, developers, and managers that so many of them have become. In the meantime, I’m going to enjoy my final semester to the max. I get to teach two of my favorite classes, and I’m eliminating non-essential committee work to go out on a high note!
adventures with flask-cors
-
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 (wlike 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:
-
We want to incorporate authentication into our cross origin strategy.
-
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:
writing a runestone lab the easy way
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:
-
Separate the distribution and development of writing tools from the server.
-
Make a pip installable runestone package.
-
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.
-
-
Re-architect the server side focusing on services for the writing tools
-
Create an authentication service that supports CORS for cross domain AJAX use.
-
Create a standard REST API for logging and storing student data
-
-
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
-
If you are on a Mac you are already done with this step.
-
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
easy publishing with runestone interactive
During my January travels, I also converted this blog from tubmlr, which had been frustrating me for a while, to Octopress, with which I have been very happy. Nothing like hacker level control of your own blog. But more, than just the switch in tools, the move to Octopress inspired me to make it easier for people to publish small or large works using the Runestone tools.
Yesterday, at the Learning @ Scale conference we demoed this new capability. See [the demo here](<http://runestoneinteractive.org/LearningAtScale). To make it super easy to publish:
-
Lecture slides
-
Demonstrations
-
A Tutorial
-
Lab Instructions
-
In class exercises
-
A short module on your favorite topic not covered elsewhere
-
An entire book
Building
You can simply follow the instructions at this new repository: github.com/RunestoneInteractive/RunestoneTools. In a nutshell:
-
Install Sphinx, paver, and paverutils using pip.
-
Clone the repository
-
Edit the index.rst file in source, and add any additional rst files you may want, depending on how complex your project is.
-
run
paver build
Deploying
Now you have a choice. In the build directory you have a nice self contained set of html files, these files are set up to make use of the runestone server invisibly in the background. The static html can be served from any web server. Just drop in the build directory and you are ready to serve. OR, you can now host and deploy your project using GitHub Pages. To host on github pages you need to do three things.
-
Create an empty repository in your github account.
-
run
paver setup_github_pages
and paste in the URL of the new account. -
run paver deploy
Now your pages will be available at: http://youraccount.github.io/YourRepo
If you want to host these pages behind a custom domain name, you can follow the instructions on github for doing so. Hint: Its really easy.
I hope this new capability will inspire lots of people to give these tools a try. I also hope that we can build a repository of resources built with the tools, so that we can all share our teaching ideas. Stay tuned for more on that.
Caveats
All of the features, activecode, codelens, assessment questions, parson’s problems, and more work just fine. The major thing that will not work (yet!) is the login/logout. I need to rework our authentication system in order for this to work. This will for sure need to happen before the end of summer.