Markdown syntax highlighting and conversion in vim

Recently I’ve been playing around with vim as an editor. Since I do most of my writing in a text editor, one of the first functions I found myself looking for was a way to do basic markdown syntax highlighting and formatting. Here’s how I set up my vim environment to do both of that.

Syntax highlighting

PlasticBoy got me most of the way there when it came to syntax highlighting. All I had to do was figure out how it fit into my .vim directory structure, which is a clone of Martin Greffel’s excellent setup. This turned out to be pretty straightforward

  • Save the mkd.vim file to ~/.vim/syntax/mkd.vim
  • Put the following in ~/.vim/ftplugin/mkd.vim:
    " markdown filetype file
    if exists("did\_load\_filetypes")
     finish
    endif
    augroup markdown
     au! BufRead,BufNewFile *.mkd   setfiletype mkd
    augroup END
  • For file type auto detection (i.e. if you want syntax highlighting automatically loaded for files with extensions like .markdown and .mdown), add this to ~/.vim/ftdetect/markdown.vim:
    autocmd BufNewFile,BufReadPost *.mkd,*.markdown,*.mdown set filetype=mkd

Converting a document or selection from Markdown to HTML

Converting markdown to html from inside of vim is nice and easy. In fact, you don’t even need the syntax files installed. You do need the markdown script installed somewhere (say, /usr/local/markdown).

We can take advantage of vim’s command line filtering here, and simply run the markdown command on all or part of the document, right from within vim. To convert the entire document, use the percent sign:

:%!/path/to/markdown --html4tags

If you just want to convert part of a document, say a highlighted visual block, you can just omit the percentage sign:

:!/path/to/markdown --html4tags

Bam! Your document is converted. Neat, huh?

Cookin’ with Veggies

I got word that a friend on Facebook was looking for some vegetarian cookbook options today. Since I’d be spending some time procrastinating a response, I figured hey, why not share? Here’s a list of books I’d reccommend checking out if you are in the market for animal free cooking guides.

Vegetarian Epicure

Anna Thomas’s book is apparently a classic. I haven’t read it, but I’ve been hearing about it for some time. This one also seems harder to find – at least in new condition (maybe it’s out of print?). Powel’s has book two and what looks like a revised version of the original. Amazon seems to have used copies of book one for sale.

Vegetarian Cooking for Everyone

I received this book by Deborah Madison from a friend as a birthday gift. It is fast becoming one of my favorite cooking guides – surpassing both the carnivorous and the meatless options in my library. It’s thoughtful look at ingredients and techniques, in addition to it’s variety of simple and accessible recipies, makes it an indespensible addition to any kitchen. If I was going to start my kitchen library from scratch, this would be one of the first ones there.

The Moosewood Cookbook

Molly Katzen’s Moosewood Cookbook is another legendary title whose original edition appears to be out of print. We have the new version, which sounds like it is significantly different from the original. While we do enjoy cooking from it, I’ve been keeping an eye out for a copy of the original. Amazon seems to have used editions the original, but you might be just as well off looking in your local used book shop.

Shop local

If you are in the viscinity of Real Portland (the one with a view of the Atlantic), the local foodie bookstore Rabelais might have copies of the out of print versions of these books, in addition to Madison’s work. As an aside (as in not-a-veggie-cookbook aside), they also have a stack of signed copies of David Chan’s Momufuku. Get ‘em while they’re hot!

Update: Casey Rosenthal submits the Veganomicon for your consideration. With a title like that, how can you go wrong?

Do you have a favorite veggie cook book? Any leads on where to find out of print or hard to find cookbooks?

Basic Data Reporting with Blackboard

The built in reporting tools available for Blackboard are somewhat limited. To answer specific reporting questions, you may need to run custom SQL queries against the database. What follows are a few rough examples of such queries.

All of the below examples are intended to outline the interactions you might need to answer specific reporting needs. It is important to note that these queries are in no way optimized, and could quite possibly put excess load on your system. Further, some of these are not actually tested (i.e. they are pulled or adapted from memory), and are only included as guides to help you get going in the right direction.

These queries are focused on Blackboard Learning System 8.x, however they should run just as well on 9.x (Blackboard Learn) releases.

One of the broader questions that you may be trying to ask is, how are people using the system? Since there are any number of contexts in which that question can be answered, we’ll start by breaking it down into more manageable chunks.

Aggregate Tool usage

A broad picture of the tools being employed across the application can give hints about how instructors are using the system to actually teach. For example, we might start by asking how many instructors are using tools like discussion boards and assessments in their courses.

There are no built in reporting methods with which to view specific tool usage in Blackboard. Looking at the database, we are left with some detective work to determine which tables and fields will be most useful. Like all detective work, there is some guessing involved. One good guess is that some of the data we are looking for can be found in the ACTIVITY_ACCUMULATOR table.

We also might be able to guess that the column within the ACTIVITY_ACCUMULATOR named internal_handle has a list of tool identifiers available on the system. From there, we can start building a query to, say, count the most accessed tool pages as listed in the accumulator, grouped by tool and sorted by page view.

SELECT COUNT(*) AS page_views, activity_accumulator.internal_handle
FROM activity_accumulator
WHERE activity_accumulator.event_type = 'COURSE_ACCESS'
GROUP BY activity_accumulator.internal_handle
ORDER BY COUNT(*) DESC

This gives us an idea of the tools available for further inspection, as well as which ones we might want to take a closer look at.

Tool usage by course

Now that we have the tools and their identifiers, we can use the ACTIVITY_ACCUMULATOR table to begin piecing together answers for a more specific set of questions, such as: Which courses are using which tools the most? Are some departments using certain tools more than others? Can we contact instructors that are using specific tools (i.e. in order to get feedback and offer further training)?

Say we wanted an idea of how many instructors were using assessments in their course. If we assume that the cp_test_manager is the handle for the Test Manager in the Control Panel, then by looking at how often the instructor views that tool’s page we can surmise a rough usage pattern. In other words, courses with a significant number of hits to that tool can be assumed to be using said tool in some fashion.

SELECT COUNT(*) AS page_views, course_main.course_name, course_main.course_id
FROM activity_accumulator, course_main
WHERE activity_accumulator.course_pk1 = course_main.pk1 
AND activity_accumulator.internal_handle = 'discussion_board' 
GROUP BY course_main.course_name, course_main.course_id 
ORDER BY page_views DESC;

This can be done with other tools, such as the discussion board, to make educated guesses about its use. Note that since the “cp_” designation appears to indicate a control panel page, hits to the discussion_board page should be assumed to be by all users in the course, and not limited to the instructor in the case of the test manager.

Tool deployment

Learning Objects Campus Pack LX products don’t show up in Blackboard’s internal tool handle tables in the same way as native tools. However, you can get an idea of the usage of these tools by looking at which courses have them installed. Running queries against the CONTENT_HANDLER table will let you see how many blogs or wiki’s have been installed a course.

SELECT course_main.pk1, course_main.course_name, 
course_main.course_id, course_contens.pk1, course_contents.title 
WHERE course_contents.crsmain_pk1 = course_main.pk1 
AND course_contents.cnthndlr_handle = 'resource/x-lobj-journal';

While this may not paint as clear a picture of usage as page view counts, it will still allow you to make general assumptions about pedagogical impacts.

Enrollment and Participation

You can also get an approximate idea of enrollment in a course using data in the activity accumulator. This can be done by joining the acumulator on the course_users and course_main tables. Querying the course user’s role and their last access is often a better indicator of recent activity in a course than the built in “active user” numbers generated by the GUI reporting tools. This is especially true if you are only looking for activity in a course within a specific timeframe, such as a term/semester.

Course usage by term can also be determined by querying on the start date fields if they are populated. In this way you can identify not only course usage in general, but also student vs. faculty usage by term.

If you don’t have start date fields populated in your tables, you may need to query off of other fields. If your course id’s contain term data, for example, you might be able to do something along the lines of “LIKE ‘200809%’”.

Other Usage Metrics and Tools

The administrator manual documents some of the feilds and tables above, but a full schema documentation does not appear to be available at this time. I’ve been told that version 10.x will ship with a fully documented (and public?) schema, but that’s probably more rumor than fact at this point.

How do you aggregate usage on your system? Are there specific tools you use in your reporting process (i.e. Crystal Reports, SAS)? Are you using GUI-side tools like the nascent Project ASTRO? Are there open source tools that you are using? Do you have special queries you run to address certain questions?

Patterns for the Color Blind (and for Craftsmanship)

This type of improvement isn’t limited to the “8% of the male population” that are colorblind – it creates a better user experience for almost every visitor to your site.

Accessibility (and Universal Design) is an integral part of Craftsmanship.

(Via Waxy.org.)

Have Pho, Will Travel

We found out last weekend that one of our favorite restaurants is closing. Or at least it will if no one buys it in the next month or so. The owner/proprietor of Viet Bangkok Cuisine on St. John St. is putting the place up for sale – the whole kit and kaboodle. Apparently he plans on moving next door to the Upside Down State.

From what we understood (and to be fair we were a bit dazed – it’s hard to pay attention when your heart is breaking), they are trying to sell it as a complete package. That would include everything from tablecloths and flatware to the exquisite recipes and sauces in the sale. Here’s hoping someone picks up the spoon.

So if you enjoy Vietnamese or Thai cuisine, I’d highly recommend visiting before they pack up. I’d especially recommend the Pho (the Pho Satay is my personal favorite), as it’s consistently been some of the best I’ve ever had. The Vermicelli Bun (V4, I believe) is also quite good. Their drunken noodle dish also ranks among the better versions I’ve tried.

We now have to decide if we’re going to try and explore the rest of the menu, or savor the dishes we have grown to love, before the doors close. At least we get to say good-bye this time – Binga’s may be the most attractive boarded-up building in town, but it’s still an empty, lonely shell.

This is one of The Real Portland’s best kept secrets – get it before it’s gone.

Update (2009-04-26): We stopped in this weekend for some post-grocery shopping takeout, and heard word that the proprietor’s father may be taking over the business after all. There’s hope yet!

Bard Coffee Roasters

On a tip from Portland Food Map, a few of us dropped by Bard Coffee Roasters for it’s soft opening this afternoon. What a pleasant surprise.

Measuring sticks, old and new

Espresso is the rod by which I judge a coffee shop. Arabica has been my gold standard for some time – the shots there are sweet and nutty, rarely bitter. I haven’t found another place in recent memory, Portland or elsewhere, that pulls a shot like that. The shot I had at Bard was at least as good, if not better than Arabica.

That was just the beginning. The cappuccino was smooth and creamy, leading me to wonder if I’ve ever really had a cap done right. Just like most of the espresso I’ve had in my life, the cap’s have always been a tad on the bitter side. This wasn’t.

Really want to get blown away? Try the breve macciatto. I believe my exact words were, “Wow. Is there cinnamon in this?”. Nope, the friendly barista across the counter replied, just a shot and steamed half-and-half.

The espresso they were pulling today was organic, and (I think) “single origin”. I forgot to ask what single origin means exactly, but I’m fairly certain all of their house brews are organic.

I’m looking forward to trying what I think was referred to as the coffee bar – which is a row of ceramic drip brewers that you can watch your coffee be brewed in. The staff is super friendly. It sounds like the hours are going to be later than any other coffee shop in town.

I brake for Craftsmanship

Perhaps what impressed me the most was Bob, and his passion for the trade. Bob is one of three owners/partners, and I gather is the main roaster. He sat down and joined us for quite a while, and we chatted about a wide range of things – from the philosophical to the geopolitical. Mostly, we talked about coffee.

It isn’t often that you meet someone so enthused about the craftsmanship and delivery of what they are selling. It’s also not often that you get to hang out with a judge for the World Barista Championships. Surely not all of them are this down to earth, or so willing to share, discuss, and debate their knowledge and philosophy.

Here’s hoping Bard sticks around – they may just raise the bar for coffee houses in The Real Portland and beyond.

CakePHP to Rails

In a blog comment, Nate Todd lays out an extensive description of why he switched from a PHP based framework (CakePHP) to Ruby on Rails. The points he makes reflect a lot of what I hear from people coming to rails, and some I’ve made myself – albeit not as eloquently as those you’ll find in Mr. Todd’s comment.

Design in the details

If you haven’t already, go read Jared Spool’s telling of the “$300 million dollar button”:

“The form was simple. The fields were Email Address and Password. The buttons were Login and Register. The link was Forgot Password. It was the login form for the site. It’s a form users encounter all the time. How could they have problems with it?”

Fun article, right? Now check out Greg Linden’s account of Marissa Mayer’s Web 2.0 talk from 2006, and his description of correlating tests at Amazon:

“After a bit of looking, Marissa explained that they found an uncontrolled variable. The page with 10 results took .4 seconds to generate. The page with 30 results took .9 seconds.

Half a second delay caused a 20% drop in traffic. Half a second delay killed user satisfaction.”

These are both a bit old, at least in internet time. However they both drive home an important point. The user experience decisions you make have an impact on your bottom line. Even the tiny, seemingly inconsequential ones.

Just because you are not Google or Amazon with bajillions of users doesn’t make this any less relevant. In fact, it is all the more so. Google and Amazon can afford to lose a few customers – you may not be in so fortunate a position.

An Italian Sandwich

If you find yourself in the Bangor area, don’t miss Giacomo’s. I’m telling you this not just because it’s one of the only places you can get espresso in town – the food is also Chock Full O‘ Yum. I think they explain it best:

“Our sandwiches consist of fine imported meats like mortadella, proscuitto, sopressata, capicola etc. and delicious cheeses like aged provolone and asiago on crusty breads. And we’d always drizzle the bread with extra vigin olive oil.”

In other words, some of the best sandwiches in Maine, if not New England. That said, my favorite combination there is a fresh cannoli and a double shot, enjoyed in the sunny window overlooking downtown Bangor.

Smart Views and Grade Center Problems in Blackboard 8.0.307.0

Some time ago, we received a report of an instructor having problems accessing the grade center within their course. The confirmed behavior resulted in several similar errors (often depending on the browser used) when attempting to load the grade center. These errors all began with the string “An unexpected error occurred while loading the Grade Center”, followed by varying statements, such as:

  • TypeError: this.visibleRows[pos] is null
  • syntax error
  • TypeError: Result of expression ‘a’ [null] is not an object.

After digging up a thread with a helpful post by Eric Knickerbocker that suggested that this might have been caused by an errant “smart View”, we were able to confirm that they had indeed being playing with smart views. That same thread offered a solution involving some URL hacking. This allowed us to get the tool to load appropriately,using a url that looked something like this:

https://your.server.edu/webapps/gradebook/do/instructor/manageCustomViews?course_id=THECOURSEID

While we still have not been able to determine the specific steps to replicate the problem, we have some theories. It may have something to do with smart view attempting to include disabled users in a view. Shortly after purging a data source, we noticed that the problem seemed to have resolved itself – only to return a day later. This was before the instructor had removed all the smart views in the course. A few of the smart views in question were being built on specific users, i.e. the view was created by selecting all the users in the list. It may be that certain logic behind the smart view function is failing when it attempts to access a record that is no longer enabled.

Safety First

If you choose to implement the above solution to get a grade center back, you should back up your data first. Downloading it in the form of a comma separated or tab delimited file will make sure that you have a local copy that is readily accessible.

You can do this by using the same method as described above. For example, to get to the download page without loading the grade center, you should be able to access a url like this:

https://your.server.edu/webapps/gradebook/do/instructor/downloadGradebook?dispatch=viewDownloadOptions&course_id=THECOURSEID

Generating a full course export and archive is also highly recommended before proceeding with something like this.