Preliminary Inventory of Digital Collections by Jason RonalloIncomplete thoughts on digital libraries.http://jronallo.github.io/blog2014-06-26T07:16:00ZJason RonalloSite moved to http://ronallo.comhttp://jronallo.github.io/blog-moved/2014-10-16T10:00:00Z2014-10-16T10:00:00ZJason Ronallo<h1>This blog has moved to <a href="http://ronallo.com">http://ronallo.com</a></h1><p>Please update your feed reader.</p>A Plugin For Mediaelement.js For Preview Thumbnails on Hover Over the Time Rail Using WebVTThttp://jronallo.github.io/blog/a-plugin-for-mediaelement-js-for-preview-thumbnails-on-hover-over-the-time-rail/2014-06-26T07:16:00Z2014-10-03T12:12:23-04:00Jason Ronallo<p>The time rail or progress bar on video players gives the viewer some indication of how much of the video they’ve watched, what portion of the video remains to be viewed, and how much of the video is buffered. The time rail can also be clicked on to jump to a particular time within the video. But figuring out where in the video you want to go can feel kind of random. You can usually hover over the time rail and move from side to side and see the time that you’d jump to if you clicked, but who knows what you might see when you get there. </p>
<p>Some video players have begun to use the time rail to show video thumbnails on hover in a tooltip. For most videos these thumbnails give a much better idea of what you’ll see when you click to jump to that time. I’ll show you how you can create your own thumbnail previews using HTML5 video.</p>
<p><strong>TL;DR</strong> Use the <a href="https://github.com/jronallo/mep-feature-time-rail-thumbnails">time rail thumbnails plugin for Mediaelement.js</a>.</p>
<h2 id="toc_0">Archival Use Case</h2>
<p>We usually follow agile practices in our <a href="http://en.wikipedia.org/wiki/Archival_processing">archival processing</a>. This style of processing became popularized by the article <a href="http://archivists.metapress.com/content/c741823776k65863/fulltext.pdf">More Product, Less Process: Revamping Traditional Archival Processing</a> by Mark A. Greene and Dennis Meissner. For instance, we don’t read every page of every folder in every box of every collection in order to describe it well enough for us to make the collection accessible to researchers. Over time we may decide to make the materials for a particular collection or parts of a collection more discoverable by doing the work to look closer and add more metadata to our description of the contents. But we try not to allow the perfect from being the enemy of the good enough. Our goal is to make the materials accessible to researchers and not hidden in some box no one knows about.</p>
<p>Some of our collections of videos are <a href="http://d.lib.ncsu.edu/student-leaders">highly curated like for video oral histories</a>. We’ve created transcripts for the whole video. We extract out the most interesting or on topic clips. For each of these video clips we create a WebVTT caption file and an <a href="/blog/using-the-webvtt-ruby-gem-to-display-subtitles-on-the-page/">interface to navigate within the video from the transcript</a>.</p>
<p>At NCSU Libraries we have begun digitizing more archival videos. And for these videos we’re much more likely to treat them like other archival materials. We’re never going to watch every minute of every video about <a href="https://d.lib.ncsu.edu/collections/catalog?f[format][]=Video&f[subject_facet][]=Cucumbers">cucumbers</a> or <a href="https://d.lib.ncsu.edu/collections/catalog?f[format][]=Video&f[subject_facet][]=Agricultural+machinery">agricultural machinery</a> in order to fully describe the contents. Digitization gives us some opportunities to automate the summarization that would be manually done with physical materials. Many of these videos don’t even have dialogue, so even when automated video transcription is more accurate and cheaper we’ll still be left with only the images. In any case, the visual component is a good place to start.</p>
<h2 id="toc_1">Video Thumbnail Previews</h2>
<p>When you hover over the time rail on some video viewers, you see a thumbnail image from the video at that time. YouTube does this for many of its videos. I first saw that this would be possible with HTML5 video when I saw the JW Player page on <a href="http://support.jwplayer.com/customer/portal/articles/1407439-adding-preview-thumbnails">Adding Preview Thumbnails</a>. From there I took the idea to use an image sprite and a WebVTT file to structure which media fragments from the sprite to use in the thumbnail preview. I’ve implemented this as a <a href="https://github.com/jronallo/mep-feature-time-rail-thumbnails">plugin for Mediaelement.js</a>. You can see detailed instructions there on how to use the plugin, but I’ll give the summary here.</p>
<h3 id="toc_2">1. Create an Image Sprite from the Video</h3>
<p>This uses ffmpeg to take a snapshot every 5 seconds in the video and then uses montage (from ImageMagick) to stitch them together into a sprite. This means that only one file needs to be downloaded before you can show the preview thumbnail.</p>
<figure class='code'>
<div>
<pre class="highlight shell">ffmpeg -i <span class="s2">"video-name.mp4"</span> -f image2 -vf <span class="nv">fps</span><span class="o">=</span><span class="nv">fps</span><span class="o">=</span>1/5 video-name-%05d.jpg
montage video-name<span class="k">*</span>jpg -tile 5x -geometry 150x video-name-sprite.jpg</pre>
</div>
</figure>
<h3 id="toc_3">2. Create a WebVTT metadata file</h3>
<p>This is just a standard <a href="http://dev.w3.org/html5/webvtt/">WebVTT</a> file except the cue text is metadata instead of captions. The URL is to an image and uses a <a href="http://www.w3.org/TR/media-frags/">spatial Media Fragment</a> for what part of the sprite to display in the tooltip.</p>
<figure class='code'>
<div>
<pre class="highlight shell">WEBVTT
00:00:00.000 --> 00:00:05.000
http://example.com/video-name-sprite.jpg#xywh<span class="o">=</span>0,0,150,100
00:00:05.000 --> 00:00:10.000
http://example.com/video-name-sprite.jpg#xywh<span class="o">=</span>150,0,150,100
00:00:10.000 --> 00:00:15.000
http://example.com/video-name-sprite.jpg#xywh<span class="o">=</span>300,0,150,100
00:00:15.000 --> 00:00:20.000
http://example.com/video-name-sprite.jpg#xywh<span class="o">=</span>450,0,150,100
00:00:20.000 --> 00:00:25.000
http://example.com/video-name-sprite.jpg#xywh<span class="o">=</span>600,0,150,100
00:00:25.000 --> 00:00:30.000
http://example.com/video-name-sprite.jpg#xywh<span class="o">=</span>0,100,150,100</pre>
</div>
</figure>
<h3 id="toc_4">3. Add the Video Thumbnail Preview Track</h3>
<p>Put the following within the <code><video></code> element.</p>
<figure class='code'>
<div>
<pre class="highlight html"><span class="nt"><track</span> <span class="na">kind=</span><span class="s">"metadata"</span> <span class="na">class=</span><span class="s">"time-rail-thumbnails"</span> <span class="na">src=</span><span class="s">"http://example.com/video-name-sprite.vtt"</span><span class="nt">></track></span></pre>
</div>
</figure>
<h3 id="toc_5">4. Initialize the Plugin</h3>
<p>The following assumes that you’re already using <a href="YKK">Mediaelement.js</a>, jQuery, and have included the <a href="https://github.com/mozilla/vtt.js">vtt.js</a> library. </p>
<figure class='code'>
<div>
<pre class="highlight javascript"><span class="nx">$</span><span class="p">(</span><span class="s1">'video'</span><span class="p">).</span><span class="nx">mediaelementplayer</span><span class="p">({</span>
<span class="na">features</span><span class="p">:</span> <span class="p">[</span><span class="s1">'playpause'</span><span class="p">,</span><span class="s1">'progress'</span><span class="p">,</span><span class="s1">'current'</span><span class="p">,</span><span class="s1">'duration'</span><span class="p">,</span><span class="s1">'tracks'</span><span class="p">,</span><span class="s1">'volume'</span><span class="p">,</span> <span class="s1">'timerailthumbnails'</span><span class="p">],</span>
<span class="na">timeRailThumbnailsSeconds</span><span class="p">:</span> <span class="mi">5</span>
<span class="p">});</span></pre>
</div>
</figure>
<h2 id="toc_6">The Result</h2>
<p><video controls>
<source src="http://jronallo.github.io/mep-feature-time-rail-thumbnails/mep-feature-time-rail-thumbnails-example.mp4" type="video/mp4"/>
<span>Your browser won’t play an MP4. You can <a href="http://jronallo.github.io/mep-feature-time-rail-thumbnails/mep-feature-time-rail-thumbnails-example.mp4">download it instead</a>.</span>
</video></p>
<p>See <a href="http://d.lib.ncsu.edu/collections/catalog/ua024-002-bx0149-066-001">Bug Sprays and Pets</a> with sound.</p>
<h2 id="toc_7">Installation</h2>
<p>The plugin can either be installed using the <a href="https://github.com/jronallo/mep-feature-time-rail-thumbnails#rails">Rails gem</a> or the <a href="https://github.com/jronallo/mep-feature-time-rail-thumbnails#bower">Bower package</a>.</p>
<h2 id="toc_8">MutationObserver</h2>
<p>One of the DOM API features I hadn’t used before is <a href="http://www.w3.org/TR/dom/#mutation-observers">MutationObserver</a>. One thing the thumbnail preview plugin needs to do is know what time is being hovered over on the time rail. I could have calculated this myself, but I wanted to rely on MediaElement.js to provide the information. Maybe there’s a callback in MediaElement.js for when this is updated, but I couldn’t find it. Instead I use a MutationObserver to watch for when MediaElement.js changes the DOM for the default display of a timestamp on hover. Looking at the time code there then allows the plugin to pick the correct cue text to use for the media fragment. MutationObserver is more performant than the now deprecated MutationEvents. I’ve experienced very little latency using a MutationObserver which allows it to trigger lots of events quickly. </p>
<p>The plugin currently only works in the <a href="http://caniuse.com/mutationobserver">browsers that support MutationObserver</a>, which is most current browsers. In browsers that do not support MutationObserver the plugin will do nothing at all and just show the default timestamp on hover. I’d be interested in other ideas on how to solve this kind of problem, though it is nice to know that plugins that rely on another library have tools like MutationObserver around.</p>
<h2 id="toc_9">Other Caveats</h2>
<p>This plugin is brand new and works for me, but there are some caveats. All the images in the sprite must have the same dimensions. The durations for each thumbnail must be consistent. The timestamps currently aren’t really used to determine which thumbnail to display, but is instead faked relying on the consistent durations. The plugin just does some simple addition and plucks out the correct thumbnail from the array of cues. Hopefully in future versions I can address some of these issues.</p>
<h2 id="toc_10">Discoveries</h2>
<p>Having this feature be available for our digitized video, we’ve already found things in our collection that we wouldn’t have seen before. You can see how a <a href="http://d.lib.ncsu.edu/collections/catalog/ua100_014-006-cn0056-004-001#t=545">“Profession with a Future”</a> evidently involves shortening your life by smoking (at about 9:05). I found a <a href="http://d.lib.ncsu.edu/collections/catalog/ua024-002-bx0113-241-001#t=133">spinning spherical display of Soy-O and synthetic meat</a> (at about 2:12). Some videos <a href="http://d.lib.ncsu.edu/collections/catalog/ua024_007-college-days">switch between black & white and color</a> which you wouldn’t know just from the poster image. And there are some videos, like talking heads, that appear from the thumbnails to have no surprises at all. But maybe you like watching <a href="http://d.lib.ncsu.edu/collections/catalog/AV9_FM_1-boiling-process">boiling water</a> for almost 13 minutes.</p>
<p>OK, this isn’t really a discovery in itself, but it is fun to watch a <a href="http://d.lib.ncsu.edu/collections/catalog/ua024-002-bx0147-060-001">head banging JFK</a> as you go back and forth over the time rail. He really likes milk. And Eisenhower had a <a href="https://d.lib.ncsu.edu/collections/catalog/AV2_FM_296-people2people">different speaking style</a>.</p>
<p>You can see this in action for all of our <a href="https://d.lib.ncsu.edu/collections/catalog?f[format][]=Video">videos on the NCSU Libraries' Rare & Unique Digital Collections site</a> and make your own discoveries. Let me know if you find anything interesting.</p>
<h2 id="toc_11">Preview Thumbnail Sprite Reuse</h2>
<p>Since we already had the sprite images for the time rail hover preview, I created another interface to allow a user to jump through a video. Under the video player is a control button that shows a modal with the thumbnail sprite. The sprite alone provides a nice overview of the video that allows you to see very quickly what might be of interest. I used an image map so that the rather large sprite images would only have to be in memory once. (Yes, image maps are still valid in HTML5 and have their legitimate uses.) <a href="https://github.com/stowball/jQuery-rwdImageMaps">jQuery RWD Image Maps</a> allows the map area coordinates to scale up and down across devices. Hovering over a single thumb will show the timestamp for that frame. Clicking a thumbnail will set the current time for the video to be the start time of that section of the video. One advantage of this feature is that it doesn’t require the kind of fine motor skill necessary to hover over the video player time rail and move back and forth to show each of the thumbnails.</p>
<p>This feature has just been added this week and deployed to production this week, so I’m looking for feedback on whether folks find this useful, how to improve it, and any bugs that are encountered.</p>
<h2 id="toc_12">Summarization Services</h2>
<p>I expect that automated summarization services will become increasingly important for researchers as archives do more large-scale digitization of physical collections and collect more born digital resources in bulk. We’re already seeing projects like <a href="https://github.com/edsu/fondz">fondz</a> which autogenerates archival description by extracting the contents of born digital resources. At NCSU Libraries we’re working on other ways to summarize the metadata we create as we ingest born digital collections. As we learn more what summarization services and interfaces are useful for researchers, I hope to see more work done in this area. And this is just the beginning of what we can do with summarizing archival video.</p>
The Lenovo X240 Keyboard and the End/Insert Key With FnLk On as a Software Developer on Linuxhttp://jronallo.github.io/blog/the-lenovo-x240-keyboard-and-the-end-insert-key-with-fnlk-on-as-a-software-developer-on-linux/2014-06-21T20:23:00Z2014-10-03T12:12:23-04:00Jason Ronallo<p>As a software developer I’m using keys like F5 a lot. When I’m doing any writing, I use F6 a lot to turn off and on spell correction underlining. On the Lenovo X240 the function keys are overlaid on the same keys as volume and brightness control. This causes some problems for me. Luckily there’s a solution that works for me under Linux.</p>
<p>To access the function keys you have to also press the Fn key. If most of what you’re doing is reloading a browser and not using the volume control, then this is a problem, so they’ve created a function lock which is enabled by pressing the Fn and Esc/FnLk key. The Fn key lights up and you can press F5 without using the Fn modifier key.</p>
<p>That’s all well and good until you get to another quirk of this keyboard where the Home, End, and Delete keys are in the same function key row in a way that the End key also functions as the Insert key. When function lock is on the End key becomes an Insert key. I don’t ever use the Insert key on a keyboard, so I understand why they combined the End/Insert key. But in this combination it doesn’t work for me as a software developer. I’m continually going between something that needs to be reloaded with F5 and in an editor where I need to quickly go to the end of a line in a program.</p>
<p>Luckily there’s a pretty simple answer to this if you don’t ever need to use the Insert key. I found the <a href="http://askubuntu.com/a/24930">answer on askubuntu</a>.</p>
<p>All I needed to do was run the following:</p>
<figure class='code'>
<div>
<pre class="highlight shell">xmodmap -e <span class="s2">"keycode 118 = End"</span></pre>
</div>
</figure>
<p>And now even when the function keys are locked the End/Insert key always behaves as End. To make this is permanent and the mapping gets loaded with X11 starts, add <code>xmodmap -e "keycode 118 = End"</code> to your <code>~/.xinitrc</code>.</p>
HTML Slide Decks With Synchronized and Interactive Audience Notes Using WebSocketshttp://jronallo.github.io/blog/html-slide-decks-with-synchronized-and-interactive-audience-notes-using-websockets/2014-06-16T13:48:00Z2014-10-03T12:12:23-04:00Jason Ronallo<p>One question I got asked after giving my <a href="http://code4lib.org">Code4Lib</a> <a href="/presentations/code4lib-2014-websockets">presentation on WebSockets</a> was how I created my slides. I’ve <a href="/blog/html-and-pdf-slideshows-with-dzslides/">written about how I create HTML slides before</a>, but this time I added some new features like an audience interface that synchronizes automatically with the slides and allows for audience participation.</p>
<p><strong>TL;DR</strong> I’ve open sourced <a href="https://github.com/jronallo/starterdeck-node">starterdeck-node</a> for creating synchronized and interactive HTML slide decks.</p>
<p>Not every time that I give a presentation am I able to use the technologies that I am talking about within the presentation itself, so I like to do it when I can. I write my slide decks as <a href="http://en.wikipedia.org/wiki/Markdown">Markdown</a> and convert them with <a href="http://johnmacfarlane.net/pandoc/">Pandoc</a> to HTML slides which use <a href="http://paulrouget.com/dzslides/">DZslides</a> for slide sizing and animations. I use a browser to present the slides. Working this way with HTML has allowed me to do things like embed HTML5 video into a <a href="http://jronallo.github.io/presentations/html5-video-now/">presentation on HTML5 video</a> and show examples of the <a href="http://jronallo.github.io/presentations/html5-video-now/presentation/#27.0">JavaScript API</a> and how <a href="http://jronallo.github.io/presentations/html5-video-now/presentation/#32.0">videos can be styled with CSS</a>.</p>
<p>For a <a href="/presentations/code4lib-2014-websockets/">presentation on WebSockets I gave at Code4Lib 2014</a>, I wanted to provide another example from within the presentation itself of what you can do with WebSockets. If you have the <a href="http://websocket-presentation.herokuapp.com/slides">slides</a> and the <a href="http://websocket-presentation.herokuapp.com/audience">audience notes handout page</a> open at the same time, you will see how they are synchronized. (Beware slowness as it is a large self-contained HTML download using data URIs.) When you change to certain slides in the presenter view, new content is revealed in the audience view. Because the slides are just an HTML page, it is possible to make the slides more interactive. WebSockets are used to allow the slides to send messages to each audience members' browser and reveal notes. I am never able to say everything that I would want to in one short 20 minute talk, so this provided me a way to give the audience some supplementary material. </p>
<p>Within the slides I even included a simplistic chat application that allowed the audience to send messages directly to the presenter slides. (Every talk on WebSockets needs a gratuitous chat application.) At the end of the talk I also accepted questions from the audience via an input field. The questions were then delivered to the slides via WebSockets and displayed right within a slide using a little JavaScript. What I like most about this is that even someone who did not feel confident enough to step up to a microphone would have the opportunity to ask an anonymous question. And I even got a <a href="/blog/questions-asked-during-the-presentation-websockets-for-real-time-and-interactive-interfaces-at-code4lib-2014/">few legitimate questions</a> amongst the requests for me to dance.</p>
<p>Another nice side benefit of getting the audience to notes <em>before</em> the presentation starts is that you can include your contact information and Twitter handle on the page.</p>
<p>I have wrapped up all this functionality for creating interactive slide decks into a project called <a href="https://github.com/jronallo/starterdeck-node">starterdeck-node</a>. It includes the WebSocket server and a simple starting point for creating your own slides. It strings together a bunch of different tools to make creating and deploying slide decks like this simpler so you’ll need to look at the requirements. This is still definitely just a tool for hackers, but having this scaffolding in place ought to make the next slide deck easier to create.</p>
<p>Here’s a video where I show <a href="https://github.com/jronallo/starterdeck-node">starterdeck-node</a> at work. Slides on the left; audience notes on the right. </p>
<iframe width="640" height="360" src="https://www.youtube.com/embed/FgO46QbSE5Y?rel=0" frameborder="0" allowfullscreen></iframe>
<h2 id="toc_0">Other Features</h2>
<p>While the new exciting feature added in this version of the project is synchronization between presenter slides and audience notes, there are also lots of other great features if you want to create HTML slide decks. Even if you aren’t going to use the synchronization feature, there are still lots of reasons why you might want to create your HTML slides with starterdeck-node.</p>
<p><strong>Self-contained HTML.</strong> Pandoc uses data-URIs so that the HTML version of your slides have no external dependencies. Everything including images, video, JavaScript, CSS, and fonts are all embedded within a single HTML document. That means that even if there’s no internet connection from the podium you’ll still be able to deliver your presentation.</p>
<p><strong>Onstage view.</strong> Part of what gets built is a DZSlides onstage view where the presenter can see the current slide, next slide, speaker notes, and current time. </p>
<p><strong>Single page view.</strong> This view is a self-contained, single-page layout version of the slides and speaker notes. This is a much nicer way to read a presentation than just flipping through the slides on various slide sharing sites. If you put a lot of work into your talk and are writing speaker notes, this is a great way to reuse them.</p>
<p><strong>PDF backup.</strong> A script is included to create a PDF backup of your presentation. Sometimes you have to use the computer at the podium and it has an old version of IE on it. PDF backup to the rescue. While you won’t get all the features of the HTML presentation you’re still in business. The included Node.js app provides a server so that a headless browser can take screenshots of each slide. These screenshots are then compiled into the PDF. </p>
<h2 id="toc_1">Examples</h2>
<p>I’d love to hear from anyone who tries to use it. I’ll list any examples I hear about below.</p>
<p>Here are some examples of slide decks that have used <a href="https://github.com/jronallo/starterdeck-node">starterdeck-node</a> or <a href="https://github.com/jronallo/starterdeck">starterdeck</a>.</p>
<ul>
<li><a href="/presentations/code4lib-2014-websockets">WebSockets for Real-Time and Interactive Interfaces</a></li>
<li><a href="http://matienzo.org/storage/2014/2014Jun-NYAC/">DPLA NYAC 2014 presentation</a></li>
</ul>
Questions Asked During the Presentation Websockets For Real-time And Interactive Interfaces At Code4lib 2014http://jronallo.github.io/blog/questions-asked-during-the-presentation-websockets-for-real-time-and-interactive-interfaces-at-code4lib-2014/2014-04-07T23:30:00Z2014-10-03T12:12:23-04:00Jason Ronallo<p>During my <a href="http://ronallo.com/presentations/code4lib-2014-websockets/">presentation on WebSockets</a>, there were a couple points where folks in the audience could enter text in an input field that would then show up on a slide. The data was sent to the slides via WebSockets. It is not often that you get a chance to incorporate the technology that you’re talking about directly into how the presentation is given, so it was a lot of fun. At the end of the presentation, I allowed folks to anonymously submit questions directly to the HTML slides via WebSockets.</p>
<p>I ran out of time before I could answer all of the questions that I saw. I’ll try to answer them now.</p>
<p><img src="/images/websocket-presentation/websocket-presentation-questions-1-7cfe09b5.png" /></p>
<h2 id="toc_0">Questions From Slides</h2>
<p>You can see in the <a href="https://www.youtube.com/watch?v=_8MJATYsqbY&feature=share&t=1h38m26s">YouTube video at the end of my presentation (at 1h38m26s)</a> the following questions came in. ([Full presentation starts here[(https://www.youtube.com/watch?v=_8MJATYsqbY&feature=share&t=1h25m37s).) Some lines that came in were not questions at all. For those that are really questions, I’ll answer them now, even if I already answered them.</p>
<h3 id="toc_1">Are you a trained dancer?</h3>
<p>No. Before my presentation I was joking with folks about how little of a presentation I’d have, at least for the interactive bits, if the wireless didn’t work well enough. Tim Shearer suggested I just do an interpretive dance in that eventuality. Luckily it didn’t come to that.</p>
<h3 id="toc_2">When is the dance?</h3>
<p>There was no dance. Initially I thought the dance might happen later, but it didn’t. OK, I’ll admit it, I was never going to dance. </p>
<h3 id="toc_3">Did you have any efficiency problems with the big images and chrome?</h3>
<p>On the big video walls in Hunt Library we often use Web technologies to create the content and Chrome for displaying it on the wall. For the most part we don’t have issues with big images or lots of images on the wall. But there’s a bit of trick happening here. For instance when we display images for <a href="http://d.lib.ncsu.edu/myhuntlibrary/">My #HuntLibrary</a> on the wall, they’re just images from Instagram so only 600x600px. We initially didn’t know how these would look blown up on the video wall, but they end up looking fantastic. So you don’t necessarily need super high resolution images to make a very nice looking display. </p>
<p>Upstairs on the Visualization Wall, I display some digitized special collections images. While the possible resolution on the display is higher, the current effective resolution is only about 202px wide for each MicroTile. The largest image is then only 404px side. In this case we are also using a Djatoka image server to deliver the images. Djatoka has an issue with the quality of its scaling between quality levels where the algorithm chosen can make the images look very poor. How I usually work around this is to pick the quality level that is just above the width required to fit whatever design. Then the browser scales the image down and does a better job making it look OK than the image server would. I don’t know which of these factors effect the look on the Visualization Wall the most, but some images have a stair stepping look on some lines. This especially effects line drawings with diagonal lines, while photographs can look totally acceptable. We’ll keep looking for how to improve the look of images on these walls especially in the browser.</p>
<h3 id="toc_4">Have you got next act after Wikipedia?</h3>
<p>This question is referring to the adaptation of <a href="http://listen.hatnote.com/">Listen to Wikipedia</a> for the Immersion Theater. You can see <a href="https://www.youtube.com/watch?v=gZKkIsWJOt8">video of what this looks like</a> on the big Hunt Library Immersion Theater wall. </p>
<p>I don’t currently have solid plans for developing other content for any of the walls. Some of the work that I and others in the Libraries have done early on has been to help see what’s possible in these spaces and begin to form the cow paths for others to produce content more easily. We answered some big questions. Can we deliver content through the browser? What templates can we create to make this work easier? I think the next act is really for the NCSU Libraries to help more students and researchers to publish and promote their work through these spaces. </p>
<h3 id="toc_5">Is it lunchtime yet?</h3>
<p>In some time zone somewhere, yes. Hopefully during the conference lunch came soon enough for you and was delicious and filling.</p>
<h3 id="toc_6">Could you describe how testing worked more?</h3>
<p>I wish I could think of some good way to test applications that are destined for these kinds of large displays. There’s really no automated testing that is going to help here. <a href="http://www.browserstack.com/">BrowserStack</a> doesn’t have a big video wall that they can take screenshots on. I’ve also thought that it’d be nice to have a webcam trained on the walls so that I could make tweaks from a distance.</p>
<p>But Chrome does have its <a href="https://developers.google.com/chrome-developer-tools/docs/mobile-emulation">screen emulation developer tools</a> which were super helpful for this kind of work. These kinds of tools are useful not just for mobile development, which is how they’re usually promoted, but for designing for very large displays as well. Even on my small workstation monitor I could get a close enough approximation of what something would look like on the wall. Chrome will shrink the content to fit to the available viewport size. I could develop for the exact dimensions of the wall while seeing all of the content shrunk down to fit my desktop. This meant that I could develop and get close enough before trying it out on the wall itself. Being able to design in the browser has huge advantages for this kind of work.</p>
<p>I work at DH Hill Library while these displays are in Hunt Library. I don’t get over there all that often, so I would schedule some time to see the content on the walls when I happened to be over there for a meeting. This meant that there’d often be a lag of a week or two before I could get over there. This was acceptable as this wasn’t the primary project I was working on. </p>
<p>By the time I saw it on the wall, though, we were really just making tweaks for design purposes. We wanted the panels to the left and right of the Listen to Wikipedia visualization to fall along the bezel. We would adjust font sizes for how they felt once you’re in the space. The initial, rough cut work of modifying the design to work in the space was easy, but getting the details just right required several rounds of tweaks and testing. Sometimes I’d ask someone over at Hunt to take a picture with their phone to ensure I’d fixed an issue.</p>
<p>While it would have been possible for me to bring my laptop and sit in front of the wall to work, I personally didn’t find that to work well for me. I can see how it could work to make development much faster, though, and it is possible to work this way. </p>
<h3 id="toc_7">Race condition issues between devices?</h3>
<p>Some spaces could allow you to control a wall from a kiosk and completely avoid any possibility of a race condition. When you allow users to bring their own device as a remote control to your spaces you have some options. You could allow the first remote to connect and lock everyone else out for a period of time. Because of how subscriptions and presence notifications work this would certainly be possible to do.</p>
<p>For Listen to Wikipedia we allow more than one user to control the wall at the same time. Then we use WebSockets to try to keep multiple clients in sync. Even though we attempt to quickly update all the clients, it is certainly possible that there could be race conditions, though it seems unlikely. Because we’re not dealing with persisting data, I don’t really worry about it too much. If one remote submits just after another but before it is synced, then the wall will reflect the last to submit. That’s perfectly acceptable in this case. If a client were to get out of sync with what is on the wall, then any change by that client would just be sent to the wall as is. There’s no attempt to make sure a client had the most recent, freshest version of the data prior to submitting.</p>
<p>While this could be an issue for other use cases, it does not adversely effect the experience here. We do an alright job keeping the clients in sync, but don’t shoot for perfection.</p>
<h3 id="toc_8">How did you find the time to work on this?</h3>
<p>At the time I worked on these I had at least a couple other projects going. When waiting for someone else to finish something before being able to make more progress or on a Friday afternoon, I’d take a look at one of these projects for a little. It meant the progress was slow, but these also weren’t projects that anyone was asking to be delivered on a deadline. I like to have a couple projects of this nature around. If I’ve got a little time, say before a meeting, but not enough for something else, I can pull one of these projects out. </p>
<p>I wonder, though, if this question isn’t more about the <em>why</em> I did these projects. There were multiple motivations. A big motivation was to learn more about WebSockets and how the technology could be applied in the library context. I always like to have a reason to learn new technologies, especially Web technologies, and see how to apply them to other types of applications. And now that I know more about WebSockets I can see other ways to improve the performance and experience of other applications in ways that might not be as overt in their use of the technology as these project were. </p>
<p>For the <a href="http://d.lib.ncsu.edu/collections/now">real-time digital collections view</a> this is integrated into an application I’ve developed and it did not take much to begin adding in some new functionality. We do a great deal of business analytic tracking for this application. The site has excellent SEO for the kind of content we have. I wanted to explore other types of metrics of our success.</p>
<p>The video wall projects allowed us to explore several different questions. What does it take to develop Web content for them? What kinds of tools can we make available for others to develop content? What should the interaction model be? What messaging is most effective? How should we kick off an interaction? Is it possible to develop bring your own device interactions? All of these kinds of questions will help us to make better use of these kinds of spaces. </p>
<h3 id="toc_9">Speed of an unladen swallow?</h3>
<p>I think you’d be better off asking a scientist or a British comedy troupe.</p>
<p><img src="/images/websocket-presentation/websocket-presentation-questions-2-b432216d.png" /></p>
<h2 id="toc_10">Questions From Twitter</h2>
<p><a href="https://twitter.com/mia_out/status/448486332470665216">Mia (@mia_out) tweeted at 11:47 AM on Tue, Mar 25, 2014</a><br>
@ostephens @ronallo out of curiosity, how many interactions compared to visitor numbers? And in-app or relying on phone reader? </p>
<p><a href="https://twitter.com/sebchan/status/448491069018472448">sebchan (@sebchan) tweeted at 0:06 PM on Tue, Mar 25, 2014</a><br>
@ostephens @ronallo (but) what are the other options for ‘interacting’?</p>
<p>This question was in response to how 80% of the interactions with the Listen to Wikipedia application are via QR code. We placed a URL and QR code on the wall for Listen to Wikipedia not knowing which would get the most use.</p>
<p>Unfortunately there’s no simple way I know of to kick off an interaction in these spaces when the user brings their own device. Once when there was a stable exhibit for a week we used a kiosk iPad to control a wall so that the visitor did not need to bring a device. We are considering how a kiosk tablet could be used more generally for this purpose. In cases where the visitor brings their own device it is more complicated. The visitor either must enter a URL or scan a QR code. We try to make the URLs short, but because we wanted to use some simple token authentication they’re at least 4 characters longer than they might otherwise be. I’ve considered using geolocation services as the authentication method, but they are not as exact as we might want them to be for this purpose, especially if the device uses campus wireless rather than GPS. We also did not want to have a further hurdle of asking for permission of the user and potentially being rejected. For the QR code the visitor must have a QR code reader already on their device. The QR code includes the changing token. Using either the URL or QR code sends the visitor to a page in their browser.</p>
<p>Because the walls I’ve placed content on are in public spaces there is no good way to know how many visitors there are compared to the number of interactions. One interesting thing about the Immersion Theater is that I’ll often see folks standing outside of the opening to the space looking in, so even if there where some way to track folks going in and out of the space, that would not include everyone who has viewed the content.</p>
<h2 id="toc_11">Other Questions</h2>
<p>If you have other questions about anything in my <a href="http://ronallo.com/presentations/code4lib-2014-websockets/">presentation</a>, please feel free to ask. (If you submit them through the slides I won’t ever see them, so better to <a href="/about">email or tweet at me</a>.)</p>
HTML and PDF Slideshows Written in Markdown with DZSlides, Pandoc, Guard, Capybara Webkit, and a little Rubyhttp://jronallo.github.io/blog/html-and-pdf-slideshows-with-dzslides/2013-11-08T05:00:00Z2014-10-03T12:12:23-04:00Jason Ronallo<p>I’ve used different HTML slideshow tools in the past, but was never satisfied with them. I didn’t like to have to run a server just for a slideshow. I don’t like when a slideshow requires external dependencies that make it difficult to share the slides. I don’t want to actually have to write a lot of HTML.</p>
<p>I want to write my slides in a single Markdown file. As a backup I always like to have my slides available as a PDF.</p>
<p>For my latest presentations I came up with workflow that I’m satisfied with. Once all the little pieces were stitched together it worked really well for me. I’ll show you how I did it.</p>
<p>I had looked at <a href="http://paulrouget.com/dzslides/">DZSlides</a> before but had always passed it by after seeing what a default slide deck looked like. It wasn’t as flashy as others and doesn’t immediately have all the same features readily available. I looked at it again because I liked the idea that it is a single file template. I also saw that <a href="http://johnmacfarlane.net/pandoc/demo/example9/producing-slide-shows-with-pandoc.html">Pandoc will convert Markdown into a DZSlides slideshow</a>.</p>
<p>To convert my Markdown to DZSlides it was as easy as:</p>
<figure class='code'>
<div>
<pre class="highlight shell">pandoc -w dzslides presentation.md > presentation.html</pre>
</div>
</figure>
<p>What is even better is that Pandoc has settings to embed images and any external files as data URIs within the HTML. So this allows me to maintain a single Markdown file and then share my presentation as a single HTML file including images and all–no external dependencies.</p>
<figure class='code'>
<div>
<pre class="highlight shell">pandoc -w dzslides --standalone --self-contained presentation.md > presentation.html</pre>
</div>
</figure>
<p>The DZSlides default template is rather plain, so you’ll likely want to make some stylistic changes to the CSS. You may also want to add some more JavaScript as part of your presentation or to add features to the slides. For instance I wanted to add a simple way to toggle my speaker notes from showing. In previous HTML slides I’ve wanted to control HTML5 video playback by binding JavaScript to a key. The way I do this is to add in any external styles or scripts directly before the closing body tag after Pandoc does its processing. Here’s the simple script I wrote to do this:</p>
<figure class='code'>
<div>
<pre class="highlight ruby"><span class="c1">#! /usr/bin/env ruby</span>
<span class="c1"># markdown_to_slides.rb</span>
<span class="c1"># Converts a markdown file into a DZslides presentation. Pandoc must be installed.</span>
<span class="c1"># Read in the given CSS file and insert it between style tags just before the close of the body tag.</span>
<span class="n">css</span> <span class="o">=</span> <span class="no">File</span><span class="nf">.read</span><span class="p">(</span><span class="s1">'styles.css'</span><span class="p">)</span>
<span class="n">script</span> <span class="o">=</span> <span class="no">File</span><span class="nf">.read</span><span class="p">(</span><span class="s1">'scripts.js'</span><span class="p">)</span>
<span class="sb">`pandoc -w dzslides --standalone --self-contained presentation.md > presentation.html`</span>
<span class="n">presentation</span> <span class="o">=</span> <span class="no">File</span><span class="nf">.read</span><span class="p">(</span><span class="s1">'presentation.html'</span><span class="p">)</span>
<span class="n">style</span> <span class="o">=</span> <span class="s2">"<style></span><span class="si">#{</span><span class="n">css</span><span class="si">}</span><span class="s2"></style>"</span>
<span class="n">scripts</span> <span class="o">=</span> <span class="s2">"<script></span><span class="si">#{</span><span class="n">script</span><span class="si">}</span><span class="s2"></script>"</span>
<span class="n">presentation</span><span class="nf">.sub!</span><span class="p">(</span><span class="s1">'</body>'</span><span class="p">,</span> <span class="s2">"</span><span class="si">#{</span><span class="n">style</span><span class="si">}#{</span><span class="n">scripts</span><span class="si">}</span><span class="s2"></body>"</span><span class="p">)</span>
<span class="no">File</span><span class="nf">.open</span><span class="p">(</span><span class="s1">'presentation.html'</span><span class="p">,</span> <span class="s1">'w'</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">fh</span><span class="o">|</span>
<span class="n">fh</span><span class="nf">.puts</span> <span class="n">presentation</span>
<span class="k">end</span></pre>
</div>
</figure>
<p>Just follow these naming conventions:</p>
<ul>
<li>Presentation Markdown should be named presentation.md</li>
<li>Output presentation HTML will be named presentation.html</li>
<li>Create a stylesheet in styles.css</li>
<li>Create any JavaScript in a file named scripts.js</li>
<li>You can put images wherever you want, but I usually place them in an images directory.</li>
</ul>
<h2 id="toc_0">Automate the build</h2>
<p>Now what I wanted was for this script to run any time the Markdown file changed. I used <a href="https://github.com/guard/guard">Guard</a> to watch the files and set off the script to convert the Markdown to slides. While I was at it I could also reload the slides in my browser. One trick with <a href="https://github.com/guard/guard-livereload">guard-livereload</a> is to allow your browser to watch local files so that you do not have to have the page behind a server. Here’s my Guardfile:</p>
<figure class='code'>
<div>
<pre class="highlight ruby"><span class="n">guard</span> <span class="s1">'livereload'</span> <span class="k">do</span>
<span class="n">watch</span><span class="p">(</span><span class="s2">"presentation.html"</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">guard</span> <span class="ss">:shell</span> <span class="k">do</span>
<span class="c1"># If any of these change run the script to build presentation.html</span>
<span class="n">watch</span><span class="p">(</span><span class="s1">'presentation.md'</span><span class="p">)</span> <span class="p">{</span><span class="sb">`./markdown_to_slides.rb`</span><span class="p">}</span>
<span class="n">watch</span><span class="p">(</span><span class="s1">'styles.css'</span><span class="p">)</span> <span class="p">{</span><span class="sb">`./markdown_to_slides.rb`</span><span class="p">}</span>
<span class="n">watch</span><span class="p">(</span><span class="s1">'scripts.js'</span><span class="p">)</span> <span class="p">{</span><span class="sb">`./markdown_to_slides.rb`</span><span class="p">}</span>
<span class="n">watch</span><span class="p">(</span><span class="s1">'markdown_to_slides.rb'</span><span class="p">)</span> <span class="p">{</span><span class="sb">`./markdown_to_slides.rb`</span><span class="p">}</span>
<span class="k">end</span></pre>
</div>
</figure>
<p>Add the following to a Gemfile and <code>bundle install</code>:</p>
<figure class='code'>
<div>
<pre class="highlight ruby"><span class="n">source</span> <span class="s1">'http://rubygems.org'</span>
<span class="n">gem</span> <span class="s1">'guard-livereload'</span>
<span class="n">gem</span> <span class="s1">'guard-shell'</span></pre>
</div>
</figure>
<p>Now I have a nice automated way to build my slides, continue to work in Markdown, and have a single file as a result. Just run this:</p>
<figure class='code'>
<div>
<pre class="highlight ruby"><span class="n">bundle</span> <span class="nb">exec</span> <span class="n">guard</span></pre>
</div>
</figure>
<p>Now when any of the files change your HTML presentation will be rebuilt. Whenever the resulting presentation.html is changed, it will trigger livereload and a browser refresh.</p>
<h2 id="toc_1">Slides to PDF</h2>
<p>The last piece I needed was a way to convert the slideshow into a PDF as a backup. I never know what kind of equipment will be set up or whether the browser will be recent enough to work well with the HTML slides. I like being prepared. It makes me feel more comfortable knowing I can fall back to the PDF if needs be. Also some slide deck services will accept a PDF but won’t take an HTML file.</p>
<p>In order to create the PDF I wrote a simple ruby script using <a href="https://github.com/thoughtbot/capybara-webkit">capybara-webkit</a> to drive a headless browser. If you aren’t able to install the dependencies for capybara-webkit you might try some of the other <a href="https://github.com/jnicklas/capybara#drivers">capybara drivers</a>. I did not have luck with the resulting images from selenium. I then used the DZSlides JavaScript API to advance the slides. I do a simple count of how many times to advance based on the number of sections. If you have incremental slides this script would need to be adjusted to work for you.</p>
<p>The Webkit driver is used to take a snapshot of each slide, save it to a screenshots directory, and then ImageMagick’s <code>convert</code> is used to turn the PNGs into a PDF. You could just as well use other tools to stitch the PNGs together into a PDF. The quality of the resulting PDF isn’t great, but it is good enough. Also the capybara-webkit browser does not evaluate @font-face so the fonts will be plain. I’d be very interested if anyone gets better quality using a different browser driver for screenshots.</p>
<figure class='code'>
<div>
<pre class="highlight ruby"><span class="c1">#! /usr/bin/env ruby</span>
<span class="c1"># dzslides2pdf.rb</span>
<span class="c1"># dzslides2pdf.rb http://localhost/presentation_root presentation.html</span>
<span class="nb">require</span> <span class="s1">'capybara/dsl'</span>
<span class="nb">require</span> <span class="s1">'capybara-webkit'</span>
<span class="c1"># require 'capybara/poltergeist'</span>
<span class="nb">require</span> <span class="s1">'fileutils'</span>
<span class="kp">include</span> <span class="no">Capybara</span><span class="o">::</span><span class="no">DSL</span>
<span class="n">base_url</span> <span class="o">=</span> <span class="no">ARGV</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">||</span> <span class="nb">exit</span>
<span class="n">presentation_name</span> <span class="o">=</span> <span class="no">ARGV</span><span class="o">[</span><span class="mi">1</span><span class="o">]</span> <span class="o">||</span> <span class="s1">'presentation.html'</span>
<span class="c1"># temporary file for screenshot</span>
<span class="no">FileUtils</span><span class="nf">.mkdir</span><span class="p">(</span><span class="s1">'./screenshots'</span><span class="p">)</span> <span class="k">unless</span> <span class="no">File</span><span class="nf">.exist?</span><span class="p">(</span><span class="s1">'./screenshots'</span><span class="p">)</span>
<span class="no">Capybara</span><span class="nf">.configure</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
<span class="n">config</span><span class="nf">.run_server</span> <span class="o">=</span> <span class="kp">false</span>
<span class="n">config</span><span class="nf">.default_driver</span>
<span class="n">config</span><span class="nf">.current_driver</span> <span class="o">=</span> <span class="ss">:webkit</span> <span class="c1"># :poltergeist</span>
<span class="n">config</span><span class="nf">.app</span> <span class="o">=</span> <span class="s2">"fake app name"</span>
<span class="n">config</span><span class="nf">.app_host</span> <span class="o">=</span> <span class="n">base_url</span>
<span class="k">end</span>
<span class="n">visit</span> <span class="s1">'/presentation.html'</span> <span class="c1"># visit the first page</span>
<span class="c1"># change the size of the window</span>
<span class="k">if</span> <span class="no">Capybara</span><span class="nf">.current_driver</span> <span class="o">==</span> <span class="ss">:webkit</span>
<span class="n">page</span><span class="nf">.driver.resize_window</span><span class="p">(</span><span class="mi">1024</span><span class="p">,</span><span class="mi">768</span><span class="p">)</span>
<span class="k">end</span>
<span class="nb">sleep</span> <span class="mi">3</span> <span class="c1"># Allow the page to render correctly</span>
<span class="n">page</span><span class="nf">.save_screenshot</span><span class="p">(</span><span class="s2">"./screenshots/screenshot_000.png"</span><span class="p">,</span> <span class="ss">width: </span><span class="mi">1024</span><span class="p">,</span> <span class="ss">height: </span><span class="mi">768</span><span class="p">)</span> <span class="c1"># take screenshot of first page</span>
<span class="c1"># calculate the number of slides in the deck</span>
<span class="n">slide_count</span> <span class="o">=</span> <span class="n">page</span><span class="nf">.body.scan</span><span class="p">(</span><span class="sr">%r{slide level1}</span><span class="p">)</span><span class="nf">.size</span>
<span class="nb">puts</span> <span class="n">slide_count</span>
<span class="p">(</span><span class="n">slide_count</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span><span class="nf">.times</span> <span class="k">do</span> <span class="o">|</span><span class="n">time</span><span class="o">|</span>
<span class="n">slide_number</span> <span class="o">=</span> <span class="n">time</span> <span class="o">+</span> <span class="mi">1</span>
<span class="n">keypress_script</span> <span class="o">=</span> <span class="s2">"Dz.forward();"</span> <span class="c1"># dzslides script for going to next slide</span>
<span class="n">page</span><span class="nf">.execute_script</span><span class="p">(</span><span class="n">keypress_script</span><span class="p">)</span> <span class="c1"># run the script to transition to next slide</span>
<span class="nb">sleep</span> <span class="mi">3</span> <span class="c1"># wait for the slide to fully transition</span>
<span class="c1"># screenshot_and_save_page # take a screenshot</span>
<span class="n">page</span><span class="nf">.save_screenshot</span><span class="p">(</span><span class="s2">"./screenshots/screenshot_</span><span class="si">#{</span><span class="n">slide_number</span><span class="nf">.to_s.rjust</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="s1">'0'</span><span class="p">)</span><span class="si">}</span><span class="s2">.png"</span><span class="p">,</span> <span class="ss">width: </span><span class="mi">1024</span><span class="p">,</span> <span class="ss">height: </span><span class="mi">768</span><span class="p">)</span>
<span class="nb">print</span> <span class="s2">"</span><span class="si">#{</span><span class="n">slide_number</span><span class="si">}</span><span class="s2">. "</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="sb">`convert screenshots/*png presentation.pdf`</span>
<span class="no">FileUtils</span><span class="nf">.rm_r</span><span class="p">(</span><span class="s1">'screenshots'</span><span class="p">)</span>
</pre>
</div>
</figure>
<p>At this point I did have to set this up to be behind a web server. On my local machine I just made a symlink from the root of my Apache htdocs to my working directory for my slideshow. The script can be called with the following.</p>
<figure class='code'>
<div>
<pre class="highlight shell">./dzslides2pdf.rb http://localhost/presentation/root/directory presentation.html</pre>
</div>
</figure>
<h1 id="toc_2">Speaker notes</h1>
<p>One addition that I’ve made is to add some JavaScript for speaker notes. I don’t want to have to embed my slides into another HTML document to get the nice speaker view that DZslides provides. I prefer to just have a section at the bottom of the slides that pops up with my notes. I’m alright with the audience seeing my notes if I should ever need them. So far I haven’t had to use the notes.</p>
<p>I start with adding the following markup to the presentation Markdown file.</p>
<figure class='code'>
<div>
<pre class="highlight html"><span class="nt"><div</span> <span class="na">role=</span><span class="s">"note"</span> <span class="na">class=</span><span class="s">"note"</span><span class="nt">></span>
Hi. I'm Jason Ronallo the Associate Head of Digital Library Initiatives at NCSU Libraries.
<span class="nt"></div></span></pre>
</div>
</figure>
<p>Add some CSS to hide the notes by default but allow for them to display at the bottom of the slide.</p>
<figure class='code'>
<div>
<pre class="highlight css"><span class="nt">div</span><span class="o">[</span><span class="nt">role</span><span class="o">=</span><span class="nt">note</span><span class="o">]</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
<span class="nl">position</span><span class="p">:</span> <span class="nb">absolute</span><span class="p">;</span>
<span class="nl">bottom</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="no">white</span><span class="p">;</span>
<span class="nl">background-color</span><span class="p">:</span> <span class="no">gray</span><span class="p">;</span>
<span class="nl">opacity</span><span class="p">:</span> <span class="m">0.85</span><span class="p">;</span>
<span class="nl">padding</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">12px</span><span class="p">;</span>
<span class="nl">width</span><span class="p">:</span> <span class="m">100</span><span class="err">%</span><span class="p">;</span>
<span class="p">}</span></pre>
</div>
</figure>
<p>Then a bit of JavaScript to show/hide the notes when pressing the “n” key.</p>
<figure class='code'>
<div>
<pre class="highlight javascript"><span class="nb">window</span><span class="p">.</span><span class="nx">onkeypress</span> <span class="o">=</span> <span class="nx">presentation_keypress_check</span><span class="p">;</span>
<span class="kd">function</span> <span class="nx">presentation_keypress_check</span><span class="p">(</span><span class="nx">aEvent</span><span class="p">){</span>
<span class="k">if</span> <span class="p">(</span> <span class="nx">aEvent</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">==</span> <span class="mi">110</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">aEvent</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
<span class="kd">var</span> <span class="nx">notes</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByClassName</span><span class="p">(</span><span class="s1">'note'</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="nx">notes</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">){</span>
<span class="nx">notes</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">style</span><span class="p">.</span><span class="nx">display</span> <span class="o">=</span> <span class="p">(</span><span class="nx">notes</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">style</span><span class="p">.</span><span class="nx">display</span> <span class="o">==</span> <span class="s1">'none'</span> <span class="o">||</span> <span class="o">!</span><span class="nx">notes</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">style</span><span class="p">.</span><span class="nx">display</span><span class="p">)</span> <span class="p">?</span> <span class="s1">'block'</span> <span class="p">:</span> <span class="s1">'none'</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></pre>
</div>
</figure>
<h2 id="toc_3">Outline</h2>
<p>Finally, I like to have an outline I can see of my presentation as I’m writing it. Since the Markdown just uses h1 elements to separate slides, I just use the following simple script to output the outline for my slides.</p>
<figure class='code'>
<div>
<pre class="highlight ruby"><span class="c1">#!/usr/bin/env ruby</span>
<span class="c1"># outline_markdown.rb</span>
<span class="n">file</span> <span class="o">=</span> <span class="no">File</span><span class="nf">.read</span><span class="p">(</span><span class="s1">'presentation.md'</span><span class="p">)</span>
<span class="n">index</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">file</span><span class="nf">.each_line</span> <span class="k">do</span> <span class="o">|</span><span class="n">line</span><span class="o">|</span>
<span class="k">if</span> <span class="sr">/^#\s/</span><span class="nf">.match</span> <span class="n">line</span>
<span class="n">index</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">title</span> <span class="o">=</span> <span class="n">line</span><span class="nf">.sub</span><span class="p">(</span><span class="s1">'#'</span><span class="p">,</span> <span class="n">index</span><span class="nf">.to_s</span><span class="p">)</span>
<span class="nb">puts</span> <span class="n">title</span>
<span class="k">end</span>
<span class="k">end</span></pre>
</div>
</figure>
<h2 id="toc_4">Full Example</h2>
<p>You can see the <a href="https://bitbucket.org/jronallo/big_web_data_presentation_dlf_2013">repo for my latest HTML slide deck created this way</a> for the 2013 DLF Forum where I talked about <a href="/presentations/2013-dlf">Embedded Semantic Markup, schema.org, the Common Crawl, and Web Data Commons: What Big Web Data Means for Libraries and Archives</a>.</p>
<h2 id="toc_5">Conclusion</h2>
<p>I like doing slides where I can write very quickly in Markdown and then have the ability to handcraft the deck or particular slides. I’d be interested to hear if you do something similar.</p>
DLF Forum 2013 presentation: Embedded Semantic Markup, schema.org, the Common Crawl, and Web Data Commonshttp://jronallo.github.io/blog/dlf-forum-2013-presentation-embedded-semantic-markup-schema-org-the-common-crawl-and-web-data-commons/2013-11-04T05:00:00Z2014-10-03T12:12:23-04:00Jason Ronallo<p>I spoke at the <a href="http://www.diglib.org/forums/2013forum/">2013 DLF Forum</a> about <a href="/presentations/2013-dlf">Embedded Semantic Markup, schema.org, the Common Crawl, and Web Data Commons: What Big Web Data Means for Libraries and Archives</a>. My <a href="/presentations/2013-dlf">slides, code, and data</a> are all open.</p>
<p>Here’s the abstract:</p>
<p>Search engines are reaching the limits of natural language processing while wanting to provide more exact answers, not just results, especially for the mobile context. This shift is part of what has spurred progress in how data can be published and consumed on the Web. Broad and simple vocabularies and simplified embedded semantic markup is leading to wider adoption of publishing data in HTML. Libraries and archives can take advantage of new opportunities to make their services and collections more discoverable on the open Web. This presentation will show some examples of what libraries and archives are currently doing and point to future possibilities.</p>
<p>At the same time as this new data is being made available, only a few organizations have the resources to crawl the Web and extract the data. The Common Crawl is helping to make a large repository of Web crawl data available for public use, and Web Data Commons is extracting the data embedded in the Common Crawl and making the resulting linked data available for download. This presentation will share data from original research on how libraries currently fare in this new environment of big Web data. Are libraries and archives represented in the corpus? With this democratization of Web crawl data and lowered expense for consumption of it, what are the opportunities for new library services and collections?</p>