<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3090914606822911489</id><updated>2026-03-24T11:25:23.930-07:00</updated><category term="repository"/><category term="fedora"/><category term="idea"/><category term="python"/><category term="rdf"/><category term="crigshow"/><category term="metadata"/><category term="identifier"/><category term="formats"/><category term="opinion"/><category term="uuid"/><category term="bloginfo"/><category term="development"/><category term="fun"/><category term="pairtree"/><category term="redis"/><category term="search"/><category term="statistics"/><category term="usage"/><category term="Intro"/><category term="Trackback"/><category term="archive"/><category term="bagit"/><category term="blog"/><category term="citation"/><category term="contenttype"/><category term="creativity"/><category term="curation"/><category term="dev8d python twitter tagging spreadsheet data google"/><category term="diagram"/><category term="encoding"/><category term="event"/><category term="fonts"/><category term="howto"/><category term="linux"/><category term="motivation"/><category term="oaiore"/><category term="oaipmh"/><category term="osdiii"/><category term="packaging"/><category term="play"/><category term="rss"/><category term="serialisation"/><category term="silo"/><category term="unicode"/><title type='text'>Less Talk, More Code</title><subtitle type='html'>Ideas and plans, information from research, and documentation about implementations I have tried to create. Not all of it will be limited to repositories and object stores, but that&#39;s what labels are for!</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>61</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-4239157151754782056</id><published>2010-03-26T03:36:00.000-07:00</published><updated>2010-03-26T03:44:15.375-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="identifier"/><category scheme="http://www.blogger.com/atom/ns#" term="metadata"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="redis"/><category scheme="http://www.blogger.com/atom/ns#" term="repository"/><category scheme="http://www.blogger.com/atom/ns#" term="statistics"/><category scheme="http://www.blogger.com/atom/ns#" term="usage"/><title type='text'>Usage Statistics parsing and querying with redis and python</title><content type='html'>This is an update of my previous dabblings with chomping through log files. To summarise where I am now:&lt;br /&gt;&lt;br /&gt;I have a distributable workflow, loosely coordinated using Redis and Supervisord - redis is used in two fashions: firstly using its lists as queues, buffering the communication between the workers, and secondly as a store, counting and associating the usage with the items and the metadata entities (people, subjects, etc) of those items.&lt;br /&gt;&lt;br /&gt;I have written a very small python logger, that pushes loglines directly onto a redis list, providing me with live updating abilities, as well as manual log file parsing. This is currently switched on for testing in the live repository.&lt;br /&gt;&lt;br /&gt;Current code base is here: &lt;a href=&quot;http://github.com/benosteen/UsageLogAnalysis&quot;&gt;http://github.com/benosteen/UsageLogAnalysis&lt;/a&gt; - it has a good number of things hardcoded to the perculiarities of my log files and repository. However, as part of the &lt;a href=&quot;http://www.cranfieldlibrary.cranfield.ac.uk/pirus2/tiki-index.php&quot;&gt;PIRUS 2 project&lt;/a&gt;, I am turning this into an easily reusable codebase, adding in the ability to push out OpenURLs to PIRUS statistics gatherers.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Overview&lt;/strong&gt;:&lt;br /&gt;&lt;br /&gt;Loglines  -- lpush&#39;d to &#39;q:loglines&#39;&lt;br /&gt;&lt;br /&gt;workers -  &#39;debot.py&#39; - pulls lines from this queue and parses them up, separating them into 4 categories:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt; &lt;li&gt;Any hit by a recognised Bot or spider&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Any view or download made by a real person on an item in the repository&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Any 404, etc&lt;/li&gt;&lt;br /&gt; &lt;li&gt;And anything else&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;and the lines are moved onto 4 (5) queues respectively, q:bothits, q:objectviews (and q:count simultaneously), q:fof, and q:other. I am using prefixes as a convention when working with Redis keys - &quot;q:&quot; will almost always be a queue of some sort. These four queues are consumed by loggers, who commit the logs to disc, segregated into their categories.&lt;br /&gt;&lt;br /&gt;The q:count queue is consumed by a further worker called - count.py. This does a number of jobs, and is the part that actually does the analysis.&lt;br /&gt;&lt;br /&gt;For each repository item logged event, it finds the ID of the item and also whether this was a download of an item&#39;s files. With my repository, both these facts are deducible from the URL itself.&lt;br /&gt;&lt;br /&gt;Given the ID, it checks redis to see if this item has had its metadata analysed before. If it hasn&#39;t, it grabs the metadata for the item from the repositories index (hosted by an instance of Apache Solr) and starts to add connections between metadata entity and ID to the redis index:&lt;br /&gt;&lt;br /&gt;eg say item &quot;pid:1&quot; has the simple metadata of author_name=&#39;Ben&#39; and subjects=&#39;foo, bar&#39;&lt;br /&gt;&lt;br /&gt;create unique IDs from the text by hashing the text and prefix it with the type of the field they came from:&lt;br /&gt;&lt;br /&gt;Prefixes:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;name =&amp;gt; &quot;n:&quot;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;institution =&amp;gt; &quot;i:&quot;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;faculty =&amp;gt; &quot;f:&quot;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;subjects =&amp;gt; &quot;s:&quot;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;keyphrases =&amp;gt; &quot;k:&quot;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;content type =&amp;gt; &quot;type:&quot;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;collection =&amp;gt; &quot;col:&quot;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;thesis type =&amp;gt; &quot;tt:&quot;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;eg&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; from hashlib import md5&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; md5(&quot;Ben&quot;).hexdigest()﻿&lt;br /&gt;&lt;br /&gt;&#39;092f2ba9f39fbc2876e64d12cd662f72&#39;&lt;br /&gt;&lt;br /&gt;So, the hashkey of the &#39;name&#39; &#39;Ben&#39; is &#39;n:﻿﻿092f2ba9f39fbc2876e64d12cd662f72&#39;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Now to make the connections in Redis:&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;Add ID to the set &#39;objectitems&#39; - to keep track of all the IDs (SADD objectitems {ID})&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Set &#39;n:092f2....&#39; to &#39;Ben&#39; (so we can keep a reverse mapping)&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Add &#39;n:092f2...&#39; to &#39;names&#39; set (to make it clearer. KEYS n:* should return an equivalent set)&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Add &#39;n:092f2...&#39; to &#39;e:{id}&#39; eg &quot;e:pid:1&quot; - (e -&amp;gt; prefix for collections of entities. e:{id} is a set of all entities that occur in id)&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Add &#39;e:pid:1&#39; to &#39;e:n:092f2....&#39; (gathers a list of item ids in which this entity &#39;Ben&#39; occurs in)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Repeat for any entity you wish to track.&lt;br /&gt;&lt;br /&gt;To make this more truth-manageable, you should include the id of record with the text when you generate the hashkey. That way, &#39;Ben&#39; appearing in one record will have a different key than &#39;Ben&#39; occuring in another. The assertion that these two entities are the same can easily take place in a different set, (I&#39;m using b: as the prefix for these bundles of asserted equivalence)&lt;br /&gt;&lt;br /&gt;Once you have made these assertions, you can set about counting :)&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Conventions for tracking hits:&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;d[v|d|o]:{id} - set of the dates on which {id} was viewed (v), downloaded from (d) or any other page action (o)&lt;br /&gt;&lt;p style=&quot;padding-left: 30px;&quot;&gt;eg dv:pid:1 -&amp;gt; set of dates on which pid:1 had page views.&lt;/p&gt;&lt;br /&gt;YYYY-MM-DD:{id}:[v|d|o] - set of IP clients that accessed a particular item on a given day - v,d,o as above&lt;br /&gt;&lt;p style=&quot;padding-left: 30px;&quot;&gt;eg 2010-02-03:pid:1:d - set of IP clients that downloaded a file from pid:1 on 2010-02-03&lt;/p&gt;&lt;br /&gt;t:views:{hashkey}, t:dls:{hashkey}, t:other:{hashkey}&lt;br /&gt;&lt;p style=&quot;padding-left: 30px;&quot;&gt;Grand totals of views, downloads or other accesses on a given entity or id. Good for quick lookups.&lt;/p&gt;&lt;br /&gt;Let&#39;s walk through an example: consider that a client of IP 1.2.3.4 visits the record page for this &#39;pid:1&#39; on 2010-01-01:&lt;br /&gt;&lt;br /&gt;ID = pid:1&lt;br /&gt;&lt;br /&gt;Add the User Agent string (&quot;mozilla... etc&quot;) to the &#39;ua:{IP}&#39; set, to keep track of the fingerprints of the visitors.&lt;br /&gt;&lt;br /&gt;Try to add the IP address to the set  - in this case &quot;2010-01-01:pid:1:v&quot;&lt;br /&gt;&lt;br /&gt;If the IP isn&#39;t already in this set (the client hasn&#39;t accessed this page already today) then:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;make sure that &quot;2010-01-01&quot; is a part of the &#39;dv:pid:1&#39; set&lt;/li&gt;&lt;br /&gt; &lt;li&gt;go through all the entities that are part of pid:1 (n:092... etc) and increment their totals by one.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;INCR t:views:n:092...&lt;/li&gt;&lt;br /&gt; &lt;li&gt;INCR t:views:pid:1&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;strong&gt;Now, what about querying?&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Say we wish to look up the activity on a given entity, say for &#39;Ben&#39;?&lt;br /&gt;&lt;br /&gt;First, find the hashkey(s) that exist that are equivalent - either directly using the simple md5sum hash, or by checking which bundles are for this entity.&lt;br /&gt;&lt;br /&gt;You can get the grand totals by simply querying &quot;t:views:key&quot;, &quot;t:dls...&quot; for each key and summing them together.&lt;br /&gt;&lt;br /&gt;You can get more refined answers by getting the set of IDs that this entity is associated with, and querying that to gather all the daily IP sets for them, and summing the answer. This gives me a nice way to generate data suitable for a daily activity sparkline, like:&lt;br /&gt;&lt;br /&gt;&lt;img class=&quot;alignnone&quot; title=&quot;Usage sparkline&quot; src=&quot;http://chart.apis.google.com/chart?chs=400x125&amp;amp;cht=ls&amp;amp;chco=0077CC&amp;amp;chds=0,15&amp;amp;chxt=x&amp;amp;chxl=0:|2009-07-16|2009-09-16|2010-03-17&amp;amp;chd=e:AAAAAAAAAAAAAAAAAAAAAAAAYAAMAAAAAAAMAMAAAAAAYAAAAMMAkMAAAAAAAMAAAAAAYAAAYAAAAAMAAAAAMAAMAAYAAAAAAAAAAAYMAAAAAAAAAAAAMAAAAAAAAAMAAAAAAAAAAMMYAMAAAAAAYAAAAAMAMAMMAAAAMAAAAMAMAAAM8MMkAAAAAAAAAAAMAAAAMAAAAkAYAAMMAMMAAAAAAAAAAAAAAMYAAAAMAMAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMMAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYA&quot; alt=&quot;&quot; width=&quot;400&quot; height=&quot;125&quot; /&gt;&lt;br /&gt;&lt;br /&gt;I have added another set of keys to the store, of the form &#39;geocode:{IP}&#39; that record country code to IP address, which gives me a nice way to plot out graphs like the following also using the google chart API:&lt;br /&gt;&lt;br /&gt;&lt;img class=&quot;alignnone&quot; title=&quot;Usage distribution of an item from the repository&quot; src=&quot;http://chart.apis.google.com/chart?cht=t&amp;amp;chs=440x220&amp;amp;chd=s:_&amp;amp;chf=bg,s,EAF7FE&amp;amp;chtm=world&amp;amp;chco=FFFFFF,FF0000,FFFF00,00FF00&amp;amp;chld=AEGRHKTRDEJPUSKRKWGBUKINEUNLSGSD&amp;amp;chd=t:0,0,0,0,0,0,40,46,0,0,100,6,6,0,0,0&quot; alt=&quot;&quot; width=&quot;440&quot; height=&quot;220&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Python logging to Redis&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;This functionality is mainly in one file in the github repo: &lt;a href=&quot;http://github.com/benosteen/UsageLogAnalysis/blob/master/redislogger.py&quot;&gt;redislogger.py&lt;/a&gt;﻿&lt;br /&gt;&lt;br /&gt;As you can see, most of that file is taken up with a demonstration of how to invoke it! The file that holds the logging configuration which this demo uses is in &lt;a href=&quot;http://github.com/benosteen/UsageLogAnalysis/blob/master/logging.conf.example&quot;&gt;logging.conf.example&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;NB The usage analysis code and UI is very much a WIP&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;but, I just wanted to post quickly on the rough overview on how it is set up and working.&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzww4f1kdJkeeUY0iIC3B2V0qCwxr611RRgOGETI-m4k1bapYpJajNZwJI1P3BbW634Bnbq0cRtZh9Yi_447Gvk4OELlXzfMhDmbZiuR2wEXnqczfT11t63H0vXS1Sr2NNC8txvMKiD_8/s1600/repo_statistics.png&quot;&gt;&lt;img style=&quot;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 369px; height: 400px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzww4f1kdJkeeUY0iIC3B2V0qCwxr611RRgOGETI-m4k1bapYpJajNZwJI1P3BbW634Bnbq0cRtZh9Yi_447Gvk4OELlXzfMhDmbZiuR2wEXnqczfT11t63H0vXS1Sr2NNC8txvMKiD_8/s400/repo_statistics.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5452891365961008498&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMv2OYtnJ5BQTacvRNbkaLLW-Qu-5_uEbidu8G9wJ3kP227kUR2GGhfV2P8rNJWtKQXv9WTG2EIt7F56MHdbcA7jfEPlQ-l-D2A7QVLUyMg8I7siVgNEsQ-iRKZOg332w-QF8XgOfcU6M/s1600/repo_stats_for_item.png&quot;&gt;&lt;img style=&quot;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 358px; height: 400px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMv2OYtnJ5BQTacvRNbkaLLW-Qu-5_uEbidu8G9wJ3kP227kUR2GGhfV2P8rNJWtKQXv9WTG2EIt7F56MHdbcA7jfEPlQ-l-D2A7QVLUyMg8I7siVgNEsQ-iRKZOg332w-QF8XgOfcU6M/s400/repo_stats_for_item.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5452891357278070210&quot; /&gt;&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/4239157151754782056/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/4239157151754782056' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/4239157151754782056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/4239157151754782056'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2010/03/usage-statistics-parsing-and-querying.html' title='Usage Statistics parsing and querying with redis and python'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzww4f1kdJkeeUY0iIC3B2V0qCwxr611RRgOGETI-m4k1bapYpJajNZwJI1P3BbW634Bnbq0cRtZh9Yi_447Gvk4OELlXzfMhDmbZiuR2wEXnqczfT11t63H0vXS1Sr2NNC8txvMKiD_8/s72-c/repo_statistics.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-6383826637269561669</id><published>2010-03-25T08:42:00.000-07:00</published><updated>2010-03-25T09:59:13.023-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="curation"/><category scheme="http://www.blogger.com/atom/ns#" term="pairtree"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="repository"/><category scheme="http://www.blogger.com/atom/ns#" term="silo"/><title type='text'>Curating content from one repository to put into another</title><content type='html'>First you need a little code that I&#39;ve written:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;sudo easy_install recordsilo oaipmhscraper &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(This should install all the dependencies for the following)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To harvest some OAI-PMH records from say... &lt;a href=&quot;http://eprints.soton.ac.uk/perl/oai2&quot;&gt;http://eprints.soton.ac.uk/perl/oai2&lt;/a&gt; :&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First, take a look at the Identify page for the OAI-PMH endpoint: &lt;a href=&quot;http://eprints.soton.ac.uk/perl/oai2?verb=Identify&quot;&gt;http://eprints.soton.ac.uk/perl/oai2?verb=Identify&lt;/a&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The example identifier indicates that the record identifiers start with: &quot;oai:eprints.soton.ac.uk:&quot; - we&#39;ll need this in a bit. Maybe not need, but it&#39;ll make the local storage more... elegant?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Go to a nice clean directory, with enough storage to handle whatever you want to harvest.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;Start a python commandline:&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; from oaipmhscraper import OAIPMHScraper&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;---&gt; NB  OAIPMHScraper(storage_dir, base_oai_url, identifier_uri_prefix)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; oaipmh = OAIPMHScraper(&quot;myrepo&quot;,&lt;/div&gt;&lt;div&gt;                                                         &quot;http://eprints.soton.ac.uk/perl/oai2&quot;, &lt;/div&gt;&lt;div&gt;                                                         &quot;oai:eprints.soton.ac.uk:&quot;)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Let&#39;s have a look at what could be found out about the OAI-PMH endpoint then:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; oaipmh.state&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;{&#39;lastidentified&#39;: &#39;2010-03-25T15:57:15.670552&#39;, &#39;identify&#39;: {&#39;deletedRecord&#39;: &#39;persistent&#39;, &#39;compression&#39;: [], &#39;granularity&#39;: &#39;YYYY-MM-DD&#39;, &#39;baseURL&#39;: &#39;http://eprints.soton.ac.uk/perl/oai2&#39;, &#39;adminEmails&#39;: [&#39;mailto:eprints@soton.ac.uk&#39;], &#39;descriptions&#39;: [&#39;........&#39;], &#39;protocolVersion&#39;: &#39;2.0&#39;, &#39;repositoryName&#39;: &#39;e-Prints Soton&#39;, &#39;earliestDatestamp&#39;: &#39;0001-01-01 00:00:00&#39;}}&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; oaipmh.getMetadataPrefixes()&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;{&#39;oai_dc&#39;: (&#39;http://www.openarchives.org/OAI/2.0/oai_dc.xsd&#39;, &#39;http://www.openarchives.org/OAI/2.0/oai_dc/&#39;), &#39;uketd_dc&#39;: (&#39;http://naca.central.cranfield.ac.uk/ethos-oai/2.0/uketd_dc.xsd&#39;, &#39;http://naca.central.cranfield.ac.uk/ethos-oai/2.0/&#39;)}&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Let&#39;s grab all the oai_dc from all the objects:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; oaipmh.getRecords(&#39;oai_dc&#39;)&lt;/div&gt;&lt;div&gt;...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Go make a cup of coffee or tea.... you&#39;ll get lots of stuff like:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;INFO:OAIPMH Harvester:New object: oai:eprints.soton.ac.uk:1267 found with datestamp 2004-04-27T00:00:00 - storing.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;2010-03-25 16:01:11,807 - OAIPMH Harvester - INFO - New object: oai:eprints.soton.ac.uk:1268 found with datestamp 2005-04-22T00:00:00 - storing.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;INFO:OAIPMH Harvester:New object: oai:eprints.soton.ac.uk:1268 found with datestamp 2005-04-22T00:00:00 - storing.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;2010-03-25 16:01:11,813 - OAIPMH Harvester - INFO - New object: oai:eprints.soton.ac.uk:1269 found with datestamp 2004-04-07T00:00:00 - storing.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;INFO:OAIPMH Harvester:New object: oai:eprints.soton.ac.uk:1269 found with datestamp 2004-04-07T00:00:00 - storing.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;2010-03-25 16:01:11,819 - OAIPMH Harvester - INFO - New object: oai:eprints.soton.ac.uk:1270 found with datestamp 2004-04-07T00:00:00 - storing.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;INFO:OAIPMH Harvester:New object: oai:eprints.soton.ac.uk:1270 found with datestamp 2004-04-07T00:00:00 - storing.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;2010-03-25 16:01:11,824 - OAIPMH Harvester - INFO - New object: oai:eprints.soton.ac.uk:1271 found with datestamp 2004-04-14T00:00:00 - storing.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My advice is to hop to a different terminal window and start to poke around with the content you are getting. The underlying store is a take on the CDL&#39;s Pairtree microspec (pairtree being a minimalist specification for how to structure the access to object-orientated items on a hierarchical filesystem) This model on top of pairtree I&#39;ve called a Silo (in the RecordSilo library I&#39;ve written) and constitutes a basic object model, where each object has a persistent JSON state (r/w-able) and can store any file or file in a subdirectory. It has crude object-level versioning, rather than file-versioning, so you can clone one version, delete/alter/add to it to create a second, curated version for reuse elsewhere without affecting the original.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What makes pairtree attractive is that the files themselves are not altered in form, so normal posix tools can be used on the files without unwrapping, depacking, etc.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Let&#39;s have a look around at what&#39;s been harvested so far into the &quot;myrepo&quot; silo:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&gt;&gt;&gt; from recordsilo import Silo&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; s = Silo(&quot;myrepo&quot;)&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; s.state&lt;/div&gt;&lt;div&gt;{&#39;storage_dir&#39;: &#39;myrepo&#39;, &#39;identifier_uri_prefix&#39;: &#39;oai:eprints.soton.ac.uk:&#39;, &#39;uri_base&#39;: &#39;oai:eprints.soton.ac.uk:&#39;, &#39;base_oai_url&#39;: &#39;http://eprints.soton.ac.uk/perl/oai2&#39;}&#39;}&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; len(s)   # NB this can be a time-consuming operation&lt;/div&gt;&lt;div&gt;&lt;div&gt;1100&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; len(s)&lt;/div&gt;&lt;div&gt;1200&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now let&#39;s look at a record: I&#39;m sure I saw &#39;6102&#39; whizz past as it was harvesting...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; obj = s.get_item(&quot;oai:eprints.soton.ac.uk:6102&quot;)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; obj&lt;/div&gt;&lt;div&gt;{&#39;files&#39;: {&#39;1&#39;: [&#39;oai_dc&#39;]}, &#39;subdir&#39;: {&#39;1&#39;: []}, &#39;versions&#39;: [&#39;1&#39;], &#39;date&#39;: &#39;2004-06-24T00:00:00&#39;, &#39;currentversion&#39;: &#39;1&#39;, &#39;metadata_files&#39;: {&#39;1&#39;: [&#39;oai_dc&#39;]}, &#39;item_id&#39;: &#39;oai:eprints.soton.ac.uk:6102&#39;, &#39;version_dates&#39;: {&#39;1&#39;: &#39;2004-06-24T00:00:00&#39;}, &#39;metadata&#39;: {&#39;identifier&#39;: &#39;oai:eprints.soton.ac.uk:6102&#39;, &#39;firstSeen&#39;: &#39;2004-06-24T00:00:00&#39;, &#39;setSpec&#39;: [&#39;7374617475733D707562&#39;, &#39;7375626A656374733D51:5148:5148333031&#39;, &#39;7375626A656374733D47:4743&#39;, &#39;74797065733D61727469636C65&#39;, &#39;67726F75703D756F732D686B&#39;]}}&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&gt;&gt;&gt; obj.files&lt;/div&gt;&lt;div&gt;[&#39;oai_dc&#39;]&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; obj.versions&lt;/div&gt;&lt;div&gt;[&#39;1&#39;]&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; obj.clone_version(&quot;1&quot;,&quot;workingcopy&quot;)&lt;/div&gt;&lt;div&gt;&#39;workingcopy&#39;&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; obj.versions&lt;/div&gt;&lt;div&gt;[&#39;1&#39;, &#39;workingcopy&#39;]&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; obj.currentversion&lt;/div&gt;&lt;div&gt;&#39;workingcopy&#39;&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; obj.set_version_cursor(&quot;1&quot;)&lt;/div&gt;&lt;div&gt;True&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; obj.set_version_cursor(&quot;workingcopy&quot;)&lt;/div&gt;&lt;div&gt;True&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; obj.files&lt;/div&gt;&lt;div&gt;[&#39;oai_dc&#39;]&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; with obj.get_stream(&quot;oai_dc&quot;) as oai_dc_xml:&lt;/div&gt;&lt;div&gt;...   print oai_dc_xml.read()&lt;/div&gt;&lt;div&gt;... &lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&amp;lt;metadata xmlns=&quot;http://www.openarchives.org/OAI/2.0/&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&gt;&lt;/div&gt;&lt;div&gt;      &amp;lt;oai_dc:dc xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:oai_dc=&quot;http://www.openarchives.org/OAI/2.0/oai_dc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xsi:schemaLocation=&quot;http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd&quot;&gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;dc:title&gt;Population biology of Hirondellea sp. nov. (Amphipoda: Gammaridea: Lysianassoidea) from the Atacama Trench (south-east Pacific Ocean)&amp;lt;/dc:title&gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;dc:creator&gt;Perrone, F.M.&amp;lt;/dc:creator&gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;dc:creator&gt;Dell&#39;Anno, A.&amp;lt;/dc:creator&gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;dc:creator&gt;Danovaro, R.&amp;lt;/dc:creator&gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;dc:creator&gt;Groce, N.D.&amp;lt;/dc:creator&gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;dc:creator&gt;Thurston, M.H.&amp;lt;/dc:creator&gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;dc:subject&gt;QH301 Biology&amp;lt;/dc:subject&gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;dc:subject&gt;GC Oceanography&amp;lt;/dc:subject&gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;dc:description/&gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;dc:publisher/&gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;dc:date&gt;2002&amp;lt;/dc:date&gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;dc:type&gt;Article&amp;lt;/dc:type&gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;dc:type&gt;PeerReviewed&amp;lt;/dc:type&gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;dc:identifier&gt;http://eprints.soton.ac.uk/6102/&amp;lt;/dc:identifier&gt;&amp;lt;/oai_dc:dc&gt;&amp;lt;/metadata&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can add bytestreams as strings:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; obj.put_stream(&quot;foo.txt&quot;, &quot;Some random text!&quot;)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;or as file-like objects:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; with open(&quot;README&quot;, &quot;r&quot;) as readmefile:&lt;/div&gt;&lt;div&gt;...   obj.put_stream(&quot;README&quot;, readmefile)&lt;/div&gt;&lt;div&gt;... &lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; obj.files&lt;/div&gt;&lt;div&gt;[&#39;oai_dc&#39;, &#39;foo.txt&#39;, &#39;README&#39;]&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; obj.set_version_cursor(&quot;1&quot;)&lt;/div&gt;&lt;div&gt;True&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; obj.files&lt;/div&gt;&lt;div&gt;[&#39;oai_dc&#39;]&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;This isn&#39;t the easiest way to browse or poke around the files. It would be nice to see these through a web UI of some kind:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Grab the basic UI code from http://github.com/benosteen/siloserver&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(You&#39;ll need to install web.py and Mako:  sudo easy_install mako web.py)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then edit the silodirectory_conf.py file to point to the location of the Silo - if the directory structure looks like the following:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;myrepo&lt;/div&gt;&lt;div&gt;   |&lt;/div&gt;&lt;div&gt;   ---  Silo directory stuff...&lt;/div&gt;&lt;div&gt;SiloServer&lt;/div&gt;&lt;div&gt;   |&lt;/div&gt;&lt;div&gt;    - dropbox.py&lt;/div&gt;&lt;div&gt;    etc&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You need to change data_dir to &quot;../myrepo&quot; and then you can start the server by running &#39;python dropbox.py&#39;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Point a browser at http://localhost:8080/ and wait a while - that start page loads *every* object in the Silo.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfFUXy1QS09kEMPvteFTMZgcoyXxzUKHFNRx8mFaHyziizQEhfTXBG5E1SrNQq3nWcaj9aCF-fHb9CoVYa2Orz9-PTDd5zW-r6FcdvfXGMn7raHzSVcQLYmGZ-IknYcBVJxZtu0eHIWXM/s1600/dropbox_soton.png&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfFUXy1QS09kEMPvteFTMZgcoyXxzUKHFNRx8mFaHyziizQEhfTXBG5E1SrNQq3nWcaj9aCF-fHb9CoVYa2Orz9-PTDd5zW-r6FcdvfXGMn7raHzSVcQLYmGZ-IknYcBVJxZtu0eHIWXM/s320/dropbox_soton.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5452614612357133122&quot; style=&quot;display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 214px; &quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;And let&#39;s revisit our altered record, at &lt;a href=&quot;http://localhost:8080/oai:eprints.soton.ac.uk:6102&quot;&gt;http://localhost:8080/oai:eprints.soton.ac.uk:6102&lt;/a&gt; &lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfmu0A_OEviiNGRN1TBd4WnubLuGmv-BCaqRcVAkk5l1DivI0IjtbQ0JHDQo1rYlpngINPs8gYSs80Nl5Mk7bLBKYFzZlbpP0UqL0A04Il1zimqxLR5VvlPphbS_8TPI_PIh5wKDnQF0I/s1600/dropbox_6102.png&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfmu0A_OEviiNGRN1TBd4WnubLuGmv-BCaqRcVAkk5l1DivI0IjtbQ0JHDQo1rYlpngINPs8gYSs80Nl5Mk7bLBKYFzZlbpP0UqL0A04Il1zimqxLR5VvlPphbS_8TPI_PIh5wKDnQF0I/s400/dropbox_6102.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5452615019452355138&quot; style=&quot;display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 400px; height: 295px; &quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;So, from this point, I can curate the records as I wish, add files to each item - perhaps licences, PREMIS files, etc - and then push them onto another repository, such as Fedora.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/6383826637269561669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/6383826637269561669' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/6383826637269561669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/6383826637269561669'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2010/03/curating-content-from-one-repository-to.html' title='Curating content from one repository to put into another'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfFUXy1QS09kEMPvteFTMZgcoyXxzUKHFNRx8mFaHyziizQEhfTXBG5E1SrNQq3nWcaj9aCF-fHb9CoVYa2Orz9-PTDd5zW-r6FcdvfXGMn7raHzSVcQLYmGZ-IknYcBVJxZtu0eHIWXM/s72-c/dropbox_soton.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-5117977572954400653</id><published>2010-02-11T03:45:00.000-08:00</published><updated>2010-02-11T06:36:02.562-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="oaipmh"/><category scheme="http://www.blogger.com/atom/ns#" term="pairtree"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="repository"/><title type='text'>My swiss army toolkit for distributed/multiprocessing systems</title><content type='html'>&lt;div&gt;My first confession - I avoid &#39;threading&#39; and shared memory. Avoid it like the plague, not because I cannot do it but because it can be a complete pain to build and maintain relative to the alternatives.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I am very much pro multiprocessing versus multithreading - obviously, there are times when threading is by far the best choice, but I&#39;ve found multiprocessing for the most part it to be quicker, easier and far easier to log, manage and debug than multithreading.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, what do I mean by a &#39;multiprocessing&#39; system? (just to be clear)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;i&gt;A multiprocessing system consists of many concurrently running processes running on one or more machines, and contains some means to distribute messages and persist data between these processes.&lt;/i&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This does not mean that the individual processes cannot multithread themselves, it is just that each process handles a small, well-defined aspect of the system (paralleling the unix commandline tool idiom).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Tools for multiprocess management:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://code.google.com/p/redis&quot;&gt;Redis&lt;/a&gt; - data structure server, providing atomic operations on integers, lists, sets, and sorted lists.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.rabbitmq.com/&quot;&gt;RabbitMQ&lt;/a&gt; - messaging server, based on the AMQP spec. IMO Much cleaner, easier to manage, more flexible and more reliable than all the JMS systems I&#39;ve used.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://supervisord.org/&quot;&gt;Supervisor&lt;/a&gt; - a battle-tested, process manager that can be operated via XML-RPC or HTTP. Enables live control and status of your processes.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Redis has become my swiss army knife of data munging - a store that persists data and which has some very useful atomic operations, such as integer incrementing, list manipulations and very fast set operations. I&#39;ve also used it for some quick-n-dirty process orchestrations (which is how I&#39;ve used it in the example that ends this post.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I&#39;ve also used it for usage statistic parsing and characterisation of miscellaneous XML files too!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;RabbitMQ - a dependable, fast message server which I am primarily using as a buffer for asynchronous operations and task distribution. More boilerplate to use than, say Redis, but by far more suited for that sort of thing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Supervisord - I&#39;ve been told that the ruby project &#39;god&#39; is similar to this - I really have found it very useful, especially on those systems I run remotely. An HTML page to control processes and view logs and stats? what&#39;s not to like!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;Now for a little illustration of a simple multiprocessing solution - in fact, this blog post far, far outweighs the code written and perhaps even overeggs the simple nature of the problem. I typically wouldn&#39;t use supervisor for a simple task like the following, but it seems a suitable example to show how to work it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The ability to asynchronously deliver messages, updates and tasks between your processes is a real boon - it enables quick solutions to normally vexing or time-consuming problems. For example, let&#39;s look at a trivial problem of how to harvest the content from a repository with an OAI-PMH service:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A possible solution needs:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;a process to communicate with the OAI-PMH service to gain the list of identifiers for the items in the repository (with the ability to update itself at a later time). Including the ability to find the serialised form of the full metadata for the item, if it cannot be gotten from the OAI-PMH service (eg Eprints3 XML isn&#39;t often included in the OAI-PMH service, but can be retrieved from the Export function.),&lt;/li&gt;&lt;li&gt;a process that simply downloads files to a point on the disc,&lt;/li&gt;&lt;li&gt;and a service that allows process one to queue jobs for process 2 to download - in this case Redis.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;I told you it would be trivial :)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Installing Redis: (See &lt;a href=&quot;http://code.google.com/p/redis/wiki/QuickStart&quot;&gt;http://code.google.com/p/redis/wiki/QuickStart&lt;/a&gt; for fuller instructions)&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;sudo apt-get install build-essential python-dev python-setuptools [make sure you can build and use easy_install - here shown for debian/ubuntu/etc]&lt;/li&gt;&lt;li&gt;sudo easy_install supervisor&lt;/li&gt;&lt;li&gt;mkdir oaipmh_directory        # A directory to contain all the bits you need&lt;/li&gt;&lt;li&gt;cd oaipmh_directory&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Create a supervisor configuration for the task at hand and save it as supervisord.conf.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;[program:oaipmhgrabber]&lt;/div&gt;&lt;div&gt;autorestart = false&lt;/div&gt;&lt;div&gt;numprocs = 1&lt;/div&gt;&lt;div&gt;autostart = false&lt;/div&gt;&lt;div&gt;redirect_stderr = True&lt;/div&gt;&lt;div&gt;stopwaitsecs = 10&lt;/div&gt;&lt;div&gt;startsecs = 10&lt;/div&gt;&lt;div&gt;priority = 10&lt;/div&gt;&lt;div&gt;command = python harvest.py&lt;/div&gt;&lt;div&gt;startretries = 3&lt;/div&gt;&lt;div&gt;stdout_logfile = workerlogs/harvest.log&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[program:downloader]&lt;/div&gt;&lt;div&gt;autorestart = true&lt;/div&gt;&lt;div&gt;numprocs = 1&lt;/div&gt;&lt;div&gt;autostart = false&lt;/div&gt;&lt;div&gt;redirect_stderr = True&lt;/div&gt;&lt;div&gt;stopwaitsecs = 10&lt;/div&gt;&lt;div&gt;startsecs = 10&lt;/div&gt;&lt;div&gt;priority = 999&lt;/div&gt;&lt;div&gt;command = oaipmh_file_downloader q:download_list&lt;/div&gt;&lt;div&gt;startretries = 3&lt;/div&gt;&lt;div&gt;stdout_logfile = workerlogs/download.log&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[program:redis]&lt;/div&gt;&lt;div&gt;autorestart = true&lt;/div&gt;&lt;div&gt;numprocs = 1&lt;/div&gt;&lt;div&gt;autostart = true&lt;/div&gt;&lt;div&gt;redirect_stderr = True&lt;/div&gt;&lt;div&gt;stopwaitsecs = 10&lt;/div&gt;&lt;div&gt;startsecs = 10&lt;/div&gt;&lt;div&gt;priority = 999&lt;/div&gt;&lt;div&gt;command = path/to/the/redis-server&lt;/div&gt;&lt;div&gt;startretries = 3&lt;/div&gt;&lt;div&gt;stdout_logfile = workerlogs/redis.log&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[unix_http_server]&lt;/div&gt;&lt;div&gt;file = /tmp/supervisor.sock&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[supervisord]&lt;/div&gt;&lt;div&gt;minfds = 1024&lt;/div&gt;&lt;div&gt;minprocs = 200&lt;/div&gt;&lt;div&gt;loglevel = info&lt;/div&gt;&lt;div&gt;logfile = /tmp/supervisord.log&lt;/div&gt;&lt;div&gt;logfile_maxbytes = 50MB&lt;/div&gt;&lt;div&gt;nodaemon = false&lt;/div&gt;&lt;div&gt;pidfile = /tmp/supervisord.pid&lt;/div&gt;&lt;div&gt;logfile_backups = 10&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[supervisorctl]&lt;/div&gt;&lt;div&gt;serverurl = unix:///tmp/supervisor.sock&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[rpcinterface:supervisor]&lt;/div&gt;&lt;div&gt;supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[inet_http_server]&lt;/div&gt;&lt;div&gt;username = guest&lt;/div&gt;&lt;div&gt;password = mypassword&lt;/div&gt;&lt;div&gt;port = 127.0.0.1:9001&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This has a lot of boilerplate on it, so let&#39;s go through it, section by section:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[program:redis] - this controls the redis program. You will need to change the path to the redis server to wherever it was built on your system - eg ~/redis-1.2.1/redis-server&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[program:oaipmhgrabber] and [program:downloader] - these set up the processes, look at the &#39;command&#39; key for the command that is run for them eg downloader has &quot;oaipmh_file_downloader q:download_list&quot; - The OAIPMHScraper package adds in the script, &#39;q:download_list&#39; is the redis-based list that the download tasks appear on. NB we haven&#39;t written harvest.py yet - don&#39;t worry!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;NB very important that autorestart=false in [program:oaipmhgrabber] - if it didn&#39;t, it would eternally repeat - on and on and on - harvesting!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Supervisor boilerplate: [unix_http_server], [supervisord], [supervisorctl]&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;RPC interface control [rpcinterface:supervisor]&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;HTTP interface control - [inet_http_server] - which includes importantly the username and password to log in to the control panel!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, create the log directory:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;mkdir workerlogs&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Let&#39;s now write &#39;harvest.py&#39;: PLEASE use a different OAI2 endpoint url!&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;#!/usr/bin/env python&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;from oaipmhscraper import Eprints3Harvester&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;o = Eprints3Harvester(&quot;repo&quot;, base_oai_url=&quot;http://eprints.maths.ox.ac.uk/cgi/oai2/&quot;)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;o.getRecords(metadataPrefix=&quot;XML&quot;,&lt;/div&gt;&lt;div&gt;                        template=&quot;%(pid)s/%(prefix)s/mieprints-eprint-%(pid)s.xml&quot;)&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;[Note there is a base OAIPMHScraper class, but this simply goes and gets the metadata or Identifiers for a given endpoint and stores whatever XML metadata it gets into a store. The Eprints3 harvester gets the files as well, or tries to.]&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You may have to change the template for other eprints repositories - the above template would result in the following for item 774:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&quot;http://eprints.maths.ox.ac.uk/cgi/export/774/XML/mieprints-eprint-774.xml&quot;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;YMMV for other repositories of course, so you can rewrite this template accordingly.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Your directory should look like this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;--&gt;  harvest.py  supervisord.conf  workerlogs/&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Let&#39;s start the supervisor to make the configuration is correct:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[---] $ supervisord -c supervisord.conf&lt;/div&gt;&lt;div&gt;[---] $ &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now open &lt;a href=&quot;http://localhost:9001/&quot;&gt;http://localhost:9001/&lt;/a&gt; - it should look like the following:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; &quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-PPtzwWxVMAHvn-zQcTEUMo08J_MvO3aQiwkxvOcJnWrMJQ_S0KjHJ7UvBbr06JlROAXmR2LdgBSnVXi1BNwjrlMTZfsirOUZa7Owt79g9hghFPIxvQGPh0BXilh8yn0LdOcSoYPkFIg/s320/supervisor.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5436977506699647938&quot; style=&quot;display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 153px; &quot; /&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;Click on the &#39;redis&#39; name to see the logfile that this is generating - you&#39;ll want to see lines like:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;11 Feb 13:34:32 . 0 clients connected (0 slaves), 2517 bytes in use, 0 shared objects&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;Let&#39;s start the harvest :)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Click on &#39;start&#39; for the oaipmh grabber process and wait - in the configuration file, we told it to wait for the process to stay up for 10 seconds before reporting that it was running, so it should take about that long for the page to refresh.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, let&#39;s see what it is putting onto the queue, before we start the download process (see, easy to debug!)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;python&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; from redis import Redis&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; r = Redis()&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; r.keys(&quot;*&quot;)&lt;/div&gt;&lt;div&gt;&lt;div&gt;[u&#39;q:download_list&#39;]&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; r.llen(&quot;q:download_list&quot;)&lt;/div&gt;&lt;div&gt;351&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; r.llen(&quot;q:download_list&quot;)&lt;/div&gt;&lt;div&gt;361&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; r.llen(&quot;q:download_list&quot;)&lt;/div&gt;&lt;div&gt;370&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; # Still accruing things to download as we speak...&lt;/div&gt;&lt;div&gt;&gt;&gt;&gt; r.lrange(&quot;q:download_list&quot;, 0,0)&lt;/div&gt;&lt;div&gt;[u&#39;{&quot;url&quot;: &quot;http://eprints.maths.ox.ac.uk/cgi/export/774/XML/mieprints-eprint-774.xml&quot;, &quot;filename&quot;: &quot;XML&quot;, &quot;pid&quot;: &quot;oai:generic.eprints.org:774&quot;, &quot;silo&quot;: &quot;repo&quot;}&#39;]&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, let&#39;s switch on the downloader and work on those messages - go back to http://localhost:9001 and start the downloader. Click on the downloader name when the page refreshes to get a &#39;tail&#39; of it&#39;s logfile in the browser.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You should get something like the following:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;INFO:CombineHarvester File downloader:Starting download of XML (from http://eprints.maths.ox.ac.uk/cgi/export/370/XML/mieprints-eprint-370.xml) to object oai:generic.eprints.org:370&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;2010-02-11 13:43:51,284 - CombineHarvester File downloader - INFO - Download completed in 0 seconds&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;INFO:CombineHarvester File downloader:Download completed in 0 seconds&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;2010-02-11 13:43:51,285 - CombineHarvester File downloader - INFO - Saving to Silo repo&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;INFO:CombineHarvester File downloader:Saving to Silo repo&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;2010-02-11 13:43:51,287 - CombineHarvester File downloader - INFO - Starting download of XML (from http://eprints.maths.ox.ac.uk/cgi/export/371/XML/mieprints-eprint-371.xml) to object oai:generic.eprints.org:371&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;INFO:CombineHarvester File downloader:Starting download of XML (from http://eprints.maths.ox.ac.uk/cgi/export/371/XML/mieprints-eprint-371.xml) to object oai:generic.eprints.org:371&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt; So, that will go about and download all the XML (Eprints3 XML) for each item it found in the repository. (I haven&#39;t put in much to stop dupe downloads etc. - exercise for the reader ;))&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How about we try to download the files for each item too? I just so happens I&#39;ve included a little Eprints3 XML parser and method for queuing up the files for download &#39;reprocessRecords&#39; - let&#39;s use this to download the files now - save as download_files.py&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;#!/usr/bin/env python&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;from oaipmhscraper import Eprints3Harvester&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;o = Eprints3Harvester(&quot;repo&quot;, base_oai_url=&quot;http://eprints.maths.ox.ac.uk/cgi/oai2/&quot;)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;o.reprocessRecords()&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;Add this process to the top of the supervisord.conf file:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;[program:queuefilesfordownload]&lt;/div&gt;&lt;div&gt;autorestart = false&lt;/div&gt;&lt;div&gt;numprocs = 1&lt;/div&gt;&lt;div&gt;autostart = false&lt;/div&gt;&lt;div&gt;redirect_stderr = True&lt;/div&gt;&lt;div&gt;stopwaitsecs = 10&lt;/div&gt;&lt;div&gt;startsecs = 10&lt;/div&gt;&lt;div&gt;priority = 999&lt;/div&gt;&lt;div&gt;command = python download_files.py&lt;/div&gt;&lt;div&gt;startretries = 3&lt;/div&gt;&lt;div&gt;stdout_logfile = workerlogs/download_files.log&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, to demonstrate the commandline supervisor controller:&lt;/div&gt;&lt;div&gt;[--] $ supervisorctl&lt;/div&gt;&lt;div&gt;&lt;div&gt;$ supervisorctl &lt;/div&gt;&lt;div&gt;downloader                       RUNNING    pid 20750, uptime 0:15:41&lt;/div&gt;&lt;div&gt;oaipmhgrabber                    STOPPED    Feb 11 01:58 PM&lt;/div&gt;&lt;div&gt;redis                            RUNNING    pid 16291, uptime 0:25:31&lt;/div&gt;&lt;div&gt;supervisor&gt; shutdown&lt;/div&gt;&lt;div&gt;Really shut the remote supervisord process down y/N? y&lt;/div&gt;&lt;div&gt;Shut down&lt;/div&gt;&lt;div&gt;supervisor&gt; &lt;/div&gt;&lt;div&gt;(Press Ctrl+D to leave this terminal)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now restart the supervisor:&lt;/div&gt;&lt;div&gt;[--] $ supervisord -c supervisord.conf&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And refresh http://localhost:9001/&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[NB in the following picture, I reran oaipmhgrabber, so you could see what the status of a normally exiting process looks like]&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimc5BGixgP_RlW_UbVyCXsOPJiZ8xOLhnvKANFqaN960iEPOkj3p6eGwpYLP_kykJe_CzPnlBcF3HgNQYJJ67xkHOQy5XW7Gghc9JSV4pNtWOiOIBJqf6_QbsmNY9whFRIQIHT8DXkoAc/s1600-h/supervisor2.png&quot;&gt;&lt;img style=&quot;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 154px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimc5BGixgP_RlW_UbVyCXsOPJiZ8xOLhnvKANFqaN960iEPOkj3p6eGwpYLP_kykJe_CzPnlBcF3HgNQYJJ67xkHOQy5XW7Gghc9JSV4pNtWOiOIBJqf6_QbsmNY9whFRIQIHT8DXkoAc/s320/supervisor2.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5436986877744042466&quot; /&gt;&lt;/a&gt;Now, switch on the reprocess record worker and tail -f the downloader if you want to watch it work :)&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;What&#39;s a RecordSilo&lt;/b&gt;? (aka How things are stored in the example)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This class is based on CDL&#39;s spec for &lt;a href=&quot;https://confluence.ucop.edu/display/Curation/PairTree&quot;&gt;Pairtree&lt;/a&gt; object storage - each object contains a JSON manifest and is made up of object-level versions. But, it is easier to understand if you have some kind of GUI to poke around with, so I quickly wrote the following dropbox.py server for that end:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Grab the dropbox code and templates from &lt;a href=&quot;http://github.com/benosteen/SiloServer&quot;&gt;http://github.com/benosteen/SiloServer&lt;/a&gt; - unpack it into the same directory as you are in now.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;so that:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[--] $ ls&lt;/div&gt;&lt;div&gt;download_files.py  dropbox.py  dump.rdb  harvest.py  repo  supervisord.conf  templates  workerlogs&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Edit dropbox.py and change the data_dir to equal your repo directory name - in this case, just &quot;repo&quot;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(Make sure you have mako and web.py installed too! sudo easy_install mako web.py)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;then:  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;$ python dropbox.py &lt;/div&gt;&lt;div&gt;http://0.0.0.0:8080/&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Go to http://localhost:8080/ to then see all your objects! This page opens them all, so could take a while :)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1lSAv_fV0QYIeSR2vh4PfB-RGfXtiWx59llBofAQuAF0XN6k0LQNgDUzuWH6ItGCm6ILkIWJtGnf7USRY4bgue3cblCq5qijxpq90wHs73bXA0dcXYilKLBFVklFTROt2m2vQMw_5ZK4/s1600-h/dropbox2.png&quot;&gt;&lt;img style=&quot;cursor:pointer; cursor:hand;width: 320px; height: 245px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1lSAv_fV0QYIeSR2vh4PfB-RGfXtiWx59llBofAQuAF0XN6k0LQNgDUzuWH6ItGCm6ILkIWJtGnf7USRY4bgue3cblCq5qijxpq90wHs73bXA0dcXYilKLBFVklFTROt2m2vQMw_5ZK4/s320/dropbox2.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5436994496886495698&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7Jr_mEl7F1_yRQPQeCDrFCcXtYXtvo3Kw6rx2dngWZ-Vl22tvyntuA7l-Lv6E7zL4E30iwgFvSD7sR_BRHJuwluQ8x452JBOVvdKZxKBIhQxN_UbSGpgcorFcZCxKtmOBi8EtZR6ubMo/s1600-h/dropbox.png&quot;&gt;&lt;img style=&quot;cursor:pointer; cursor:hand;width: 320px; height: 137px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7Jr_mEl7F1_yRQPQeCDrFCcXtYXtvo3Kw6rx2dngWZ-Vl22tvyntuA7l-Lv6E7zL4E30iwgFvSD7sR_BRHJuwluQ8x452JBOVvdKZxKBIhQxN_UbSGpgcorFcZCxKtmOBi8EtZR6ubMo/s320/dropbox.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5436994100879977378&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(I did this on my work computer and may have not put in some dependencies, etc but it worked for me. Let me know if it doesn&#39;t in the comments)&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/5117977572954400653/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/5117977572954400653' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/5117977572954400653'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/5117977572954400653'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2010/02/my-swiss-army-toolkit-for.html' title='My swiss army toolkit for distributed/multiprocessing systems'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-PPtzwWxVMAHvn-zQcTEUMo08J_MvO3aQiwkxvOcJnWrMJQ_S0KjHJ7UvBbr06JlROAXmR2LdgBSnVXi1BNwjrlMTZfsirOUZa7Owt79g9hghFPIxvQGPh0BXilh8yn0LdOcSoYPkFIg/s72-c/supervisor.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-6053583822562222201</id><published>2010-01-18T09:19:00.000-08:00</published><updated>2010-01-18T09:36:09.125-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="redis"/><category scheme="http://www.blogger.com/atom/ns#" term="repository"/><category scheme="http://www.blogger.com/atom/ns#" term="statistics"/><category scheme="http://www.blogger.com/atom/ns#" term="usage"/><title type='text'>Usage stats and Redis</title><content type='html'>Redis has been such a massively useful tool to me. &lt;p&gt;Recently, it has let me cut through access logs munging like a hot knife through butter, all with multiprocessing goodness.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Key things:&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;Using sets to manage botlists:&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&gt;&gt;&gt; from redis import Redis&lt;br /&gt;&gt;&gt;&gt; r = Redis()&lt;br /&gt;&gt;&gt;&gt; for bot in r.smembers(&quot;botlist&quot;):&lt;br /&gt;...   print bot&lt;br /&gt;...&lt;br /&gt;lycos.txt&lt;br /&gt;non_engines.txt&lt;br /&gt;inktomi.txt&lt;br /&gt;misc.txt&lt;br /&gt;askjeeves.txt&lt;br /&gt;oucs_bots&lt;br /&gt;wisenut.txt&lt;br /&gt;altavista.txt&lt;br /&gt;msn.txt&lt;br /&gt;googlebotlist.txt&lt;br /&gt;&gt;&gt;&gt; total = 0&lt;br /&gt;&gt;&gt;&gt; for bot in r.smembers(&quot;botlist&quot;):&lt;br /&gt;...   total = total + r.scard(bot)&lt;br /&gt;...&lt;br /&gt;&gt;&gt;&gt; total&lt;br /&gt;3882&lt;br /&gt;&lt;/p&gt;&lt;p&gt;So, I have 3882 different IP addresses that I have built up that I consider bots.&lt;/p&gt;&lt;p&gt;&lt;i&gt;Keeping counts and avoiding race-conditions&lt;/i&gt;&lt;/p&gt;&lt;p&gt;By using the Redis INCR command, it&#39;s easy to write little workers that run in their own process but which atomically increment counts of hits.&lt;/p&gt;&lt;p&gt;&lt;b&gt;What does the stat system look like?&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;I am treating each line of the Apache-style log as a message that I am passing through a number of workers. &lt;/p&gt;&lt;p&gt;&lt;b&gt;Queues&lt;/b&gt;&lt;/p&gt;&lt;p&gt;All in the same AMQP exchange: (&quot;stats&quot;)&lt;/p&gt;&lt;p&gt;Queue &quot;&lt;b&gt;loglines&lt;/b&gt;&quot; - msg&#39;s = A single log line in the Apache format. Can be sourced from either local logs or from the live service.&lt;/p&gt;&lt;p&gt;&lt;b&gt;loglines&lt;/b&gt; is listened to by a &lt;b&gt;debot.py&lt;/b&gt; worker, just one at the moment. This worker feeds three queues:&lt;/p&gt;&lt;p&gt;Queue &quot;&lt;b&gt;bothits&lt;/b&gt;&quot; - log lines from a request that matches a bot IP&lt;/p&gt;&lt;p&gt;Queue &quot;&lt;b&gt;objectviews&lt;/b&gt;&quot; - log lines from a request that was a record page view or item download&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Queue &quot;&lt;b&gt;other&lt;/b&gt;&quot; - log lines that I am presently not so interested in.&lt;/p&gt;&lt;p&gt;[These three queues are consumed by 3 loggers and these maintain a copy of the logs, pre-separated. These are designed to be temporary parts of the workflow, to be discarded once we know what we want from the logs.]&lt;/p&gt;&lt;p&gt;&lt;b&gt;objectviews&lt;/b&gt; is subscribed to by a &lt;b&gt;count.py&lt;/b&gt; worker which does the heavy crunching as shown below.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Debot.py&lt;/b&gt;&lt;br /&gt;&lt;/p&gt; &lt;p&gt;The first worker is &#39;debot.py&#39; - this does the broad separation and checking of a logged event. In essence, it uses the Redis SISMEMBER command to see if the IP address is in the blacklists and if not, applies a few regex&#39;s to see if it is a record view and/or a download or something else.&lt;/p&gt; &lt;p&gt;&lt;b&gt;Broad Logging&lt;/b&gt;&lt;/p&gt; &lt;p&gt;There are three logger workers that debot.py feeds for &quot;bothits&quot;, &quot;objectviews&quot;, and &quot;other&quot; - these workers just sit and listen on the relevant queue for an apache log line and appends it to the logfile it has open. Saves me having to open/close logger objects or pass anything around.&lt;/p&gt; &lt;p&gt;The logfiles are purely as a record of the processing and so I can skip redoing it if I want to do any further analysis, like tracking individuals, etc.&lt;/p&gt;&lt;p&gt;The loggers also INCR a key in Redis for each line they see - u:objectviews, u:bothits, and u:other as appropriate - these give me a rough idea of how the processing is going.&lt;/p&gt;&lt;p&gt;(And you can generate pretty charts from it too:)&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://chart.apis.google.com/chart?cht=p3&amp;amp;chds=0,9760660&amp;amp;chd=t:368744,9760660,1669552&amp;amp;chs=600x200&amp;amp;chl=Views%7CBots%7COther&quot;&gt;http://chart.apis.google.com/chart?cht=p3&amp;amp;chds=0,9760660&amp;amp;chd=t:368744,9760660,1669552&amp;amp;chs=600x200&amp;amp;chl=Views|Bots|Other&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://chart.apis.google.com/chart?cht=p3&amp;amp;chds=0,9760660&amp;amp;chd=t:368744,9760660,1669552&amp;amp;chs=600x200&amp;amp;chl=Views%7CBots%7COther&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 600px; height: 200px;&quot; src=&quot;http://chart.apis.google.com/chart?cht=p3&amp;amp;chds=0,9760660&amp;amp;chd=t:368744,9760660,1669552&amp;amp;chs=600x200&amp;amp;chl=Views%7CBots%7COther&quot; alt=&quot;&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;(data sourced at a point during the processing - 10million bot hits vs 360k object views/dls)&lt;br /&gt;&lt;/p&gt; &lt;p&gt;&lt;b&gt;Counting hits (metadata and time based)&lt;br /&gt;&lt;/b&gt;&lt;/p&gt; &lt;p&gt;Most of the heavy lifting is in count.py - this is fed from the object views/downloads stream coming from the debot.py worker. It does a number of procedural steps for the metadata:&lt;/p&gt; &lt;ul&gt;&lt;li&gt;Get metadata from ORA&#39;s Solr endpoint (as JSON)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Specifically, get the &#39;authors&#39; (names), subjects/keyphrases, institutions, content types, and collections things appear in.&lt;/li&gt;&lt;li&gt;These fields correspond to certain keys in Redis. Eg names = &#39;number:names&#39; = number of unique names, &#39;n:...&#39; = hits to a given name, etc&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;For each view/dl:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;INCR &#39;ids:XXXXX&#39; where XXXXX is &#39;names&#39;, &#39;subjects&#39;, etc. It&#39;ll return the new value for this, eg 142&lt;/li&gt;&lt;li&gt;SET X:142 to be equal to the text for this new entity, where X is the prefix for the field.&lt;/li&gt;&lt;li&gt;SADD this id (eg X:142) to the relevant set for it, like &#39;names&#39;, &#39;subjects&#39;, etc - This is so we can have an accurate idea of the entities in use even after removing/merging them.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;Reverse lookup:&lt;/i&gt; Hash the text for the entity (eg md5(&quot;John F. Smith&quot;)) and SET r:X:{hash} to be equal to &quot;X:142&quot;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;SET X:views:142 to be equal to 1 to get the ball rolling (or X:dl:142 for downloads)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;If the name is not new:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Hash the text and lookup r:{hash} to get the id (eg n:132)&lt;/li&gt;&lt;li&gt;INCR the item&#39;s counter (eg INCR n:views:132)&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;i&gt;Time-based and other counts:&lt;/i&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;INCR t:{object id} (total hits on that repository object since logs began)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;INCR t:MMYY (total &#39;proper&#39; hits for that month)&lt;/li&gt;&lt;li&gt;INCR t:MMYY:{object id} (total &#39;proper&#39; hits for that repo item that month)&lt;/li&gt;&lt;li&gt;INCR t:MMYY:{entity id} (Total hits for an entity, say &#39;n:132&#39; that month)&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt; &lt;p&gt;A lot of pressure is put on Redis by count.py but it seems to be coping fine. A note for anyone else thinking about this: Redis keeps its datastore in RAM - running out of RAM is a Bad Thing(tm).&lt;/p&gt;&lt;p&gt;I know that I could also just use the md5 hashes as ids, rather than using a second id - I&#39;m still developing this section and this outline just states it how it is now!&lt;br /&gt;&lt;/p&gt; &lt;p&gt;Also, it&#39;s worth noting that if I needed to, I can put remote redis &#39;shards&#39; on other machines and they can just pull log lines from the main objectview queue to process. (It&#39;ll still need to create the id &lt;-&gt; entity name mapping on the main store though or a slave of the main store.)&lt;/p&gt; &lt;p&gt;&lt;b&gt;But why did I do this?&lt;/b&gt;&lt;/p&gt;&lt;p&gt;I thought that it would mean I could handle both legacy logs and live data and have a framework I could put against other systems and in a way that would mean I would write less code and for the system to be more reliable.&lt;/p&gt;&lt;p&gt;So far, I still think this is the case. If people are interested, I&#39;ll abstract out a class or two (eg the metadata lookup function, etc) and stick it on google code. It&#39;s not really a lot of code so far, I think even this outline post is longer....&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/6053583822562222201/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/6053583822562222201' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/6053583822562222201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/6053583822562222201'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2010/01/usage-stats-and-redis.html' title='Usage stats and Redis'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-835548650288731693</id><published>2009-10-15T02:30:00.001-07:00</published><updated>2009-10-15T03:15:56.433-07:00</updated><title type='text'>Python in a Pairtree</title><content type='html'>(Thanks to @anarchivist for the title - I&#39;ll let him take all the &#39;credit&#39;)&lt;br /&gt;&lt;br /&gt;&quot;&lt;a href=&quot;http://www.cdlib.org/inside/diglib/pairtree/pairtreespec.html&quot;&gt;Pairtree&lt;/a&gt;? huh, what&#39;s that?&quot; - in a nutshell it&#39;s &#39;just enough veneer on top of a conventional filesystem&#39; for it to be able to store objects sensibly; a way of storing objects by id on a normal hierarchical filesystem in a pragmatic fashion.  You could just have one directory that holds all the objects, but this would unbalance the filesystem and due to how most are implemented, would result in a less-than-efficient store. Filesystems just don&#39;t deal well with thousands or hundreds of thousands of directories in the same level.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.cdlib.org/inside/diglib/pairtree/pairtreespec.html&quot;&gt;Pairtree&lt;/a&gt; provides enough convention and fanning out of hierarchical directories to both spread the load of storing high numbers of objects, while retaining the ability to treat each object distinctly.&lt;br /&gt;&lt;br /&gt;The &lt;a href=&quot;http://www.cdlib.org/inside/diglib/pairtree/pairtreespec.html&quot;&gt;Pairtree specification&lt;/a&gt; is a compromise between fanning out too much and too little and assumes that the ids used are opaque; that the ids have no meaning and are to all intents and purposes &#39;random&#39;. If your ids are not, for example, they are human-readable words, then you will have to tweak how the ids are split into directories to ensure better performance.&lt;br /&gt;&lt;br /&gt;[I&#39;ll copy&amp;amp;paste some examples from the &lt;a href=&quot;http://www.cdlib.org/inside/diglib/pairtree/pairtreespec.html&quot;&gt;specifications&lt;/a&gt; to illustrate what it does]&lt;br /&gt;&lt;br /&gt;For example, to store objects that have identifiers like the following URI - http://n2t.info/ark:/13030/xt2{some string}&lt;br /&gt;&lt;br /&gt;eg:&lt;br /&gt;&lt;br /&gt;http://n2t.info/ark:/13030/xt2aacd&lt;br /&gt;http://n2t.info/ark:/13030/xt2aaab&lt;br /&gt;http://n2t.info/ark:/13030/xt2aaac&lt;br /&gt;&lt;br /&gt;This works out to look like this on the filesystem:&lt;br /&gt;&lt;pre&gt;current_directory/&lt;br /&gt;|   pairtree_version0_1        [which version of pairtree]&lt;br /&gt;|    ( This directory conforms to Pairtree Version 0.1. Updated spec: )&lt;br /&gt;|    ( http://www.cdlib.org/inside/diglib/pairtree/pairtreespec.html  )&lt;br /&gt;|&lt;br /&gt;|   pairtree_prefix&lt;br /&gt;|    ( http://n2t.info/ark:/13030/xt2                                 )&lt;br /&gt;|&lt;br /&gt;\--- pairtree_root/&lt;br /&gt;|--- aa/&lt;br /&gt;|    |--- cd/&lt;br /&gt;|    |    |--- foo/&lt;br /&gt;|    |    |    |   README.txt&lt;br /&gt;|    |    |    |   thumbnail.gif&lt;br /&gt;|    |    ...&lt;br /&gt;|    |--- ab/ ...&lt;br /&gt;|    |--- af/ ...&lt;br /&gt;|    |--- ag/ ...&lt;br /&gt;|    ...&lt;br /&gt;|--- ab/ ...&lt;br /&gt;...&lt;br /&gt;\--- zz/ ...&lt;br /&gt;     | ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With the object http://n2t.info/ark:/13030/xt2aacd containing a directory &#39;foo&#39;, which itself contains a README and a thumbnail gif.&lt;br /&gt;&lt;br /&gt;Creating this structure by hand is tedious, and luckily for you, you don&#39;t have to (if you use python that is)&lt;br /&gt;&lt;br /&gt;To get the pairtree library that I&#39;ve written, you can either install it from the Pypi site &lt;a href=&quot;http://pypi.python.org/pypi/Pairtree&quot;&gt;http://pypi.python.org/pypi/Pairtree&lt;/a&gt; or if python-setuptools/easy_install is on your system, you can just &lt;code&gt;sudo easy_install pairtree&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;You can find API documentation and a quick start &lt;a href=&quot;http://packages.python.org/Pairtree/&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The quick start should get you up and running in no time at all, but let&#39;s look at how we might store Fedora-like objects on disk using pairtree. (I don&#39;t mean how to replicate how Fedora stores objects on disk, I mean how to make an object store that gives us the basic framework of &#39;objects are bags of stuff&#39;)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt;&gt;&gt; from pairtree import *&lt;br /&gt;&gt;&gt;&gt; f = PairtreeStorageFactory() &lt;br /&gt;&gt;&gt;&gt; fedora = f.get_store(store_dir=&quot;objects&quot;, uri_base=&quot;info:fedora/&quot;)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Right, that&#39;s the basic framework done, let&#39;s add some content:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt;&gt;&gt; obj = fedora.create_object(&#39;changeme:1&#39;)&lt;br /&gt;&gt;&gt;&gt; with open(&#39;somefileofdublincore.xml&#39;, &#39;r&#39;) as dc:&lt;br /&gt;...     obj.add_bytestream(&#39;DC&#39;, dc)&lt;br /&gt;&gt;&gt;&gt; with open(&#39;somearticle.pdf&#39;, &#39;r&#39;) as pdf:&lt;br /&gt;...     obj.add_bytestream(&#39;PDF&#39;, pdf)&lt;br /&gt;&gt;&gt;&gt; obj.add_bytestream(&#39;RELS-EXT&#39;, &quot;&quot;&quot;&amp;lt;rdf:RDF xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot; &lt;br /&gt;                                               xmlns:rel=&quot;info:fedora/fedora-system:def/relations-external#&quot;&gt;&lt;br /&gt;  &amp;lt;rdf:Description rdf:about=&quot;info:fedora/changeme:1&quot;&gt;&lt;br /&gt;    &amp;lt;rel:isMemberOf rdf:resource=&quot;info:fedora/type:article&quot;/&gt;&lt;br /&gt;  &amp;lt;/rdf:Description&gt;&lt;br /&gt;&amp;lt;/rdf:RDF&gt;&quot;&quot;&quot;)                                                                       &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The &lt;code&gt;add_bytestream&lt;/code&gt; method is adaptive - if you pass it something that supports a &lt;code&gt;read()&lt;/code&gt; method, it will attempt to stream out the content in chunks to avoid reading the whole item into memory at once. If not, it will just write the content out as is.&lt;br /&gt;&lt;br /&gt;I hope this gives people some idea on what can be possible with a conventional filesystem, after all, filesystem code is pretty well tested in the majority of cases so why not make use of it.&lt;br /&gt;&lt;br /&gt;(NB the &lt;code&gt;with&lt;/code&gt; python command is a nice way of dealing with file-like objects, made part of the core in python ~2.6 I think. It tries to make sure that the file is closed at the end of the block, equivalent to an &quot;temp = open(foo) - do stuff - temp.close()&quot;)</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/835548650288731693/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/835548650288731693' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/835548650288731693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/835548650288731693'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2009/10/python-in-pairtree.html' title='Python in a Pairtree'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-453105319749927455</id><published>2009-06-19T09:28:00.000-07:00</published><updated>2009-06-19T09:38:40.528-07:00</updated><title type='text'>What is a book if you can print one in 5 minutes?</title><content type='html'>&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;There exists technology now, available in bookshops and certain forward-thinking libraries, to print a book in 5 minutes from pressing Go, to getting the book into your hands.&lt;br /&gt;&lt;br /&gt;This excites me a lot. Yes, that does imply I am a geek, but whatever.&lt;br /&gt;&lt;br /&gt;So, what would I want to do with one? well, printing books that already exist is fun but not grasping the potential. If you can print a book in 5 minutes, for how long must that book have been in existence before you press print? Why can&#39;t we start talking about repurposing corrently licenced or public domain content?&lt;br /&gt;&lt;br /&gt;Well, what I need (and am keen to get going with) is the following:&lt;br /&gt;&lt;br /&gt;1) PDF generator -&amp;gt; pass it an RSS feed of items and it will do it&#39;s best to generate page content from these.&lt;br /&gt;  - blogs/etc: grab the RSS/Atom feed and parse out the useful content&lt;br /&gt;       - Include option to use blog comments or to gather comments/backlinks/tweets from the internet&lt;br /&gt;  - PDFs - simply concatenate the PDF as is into the final PDF&lt;br /&gt;  - Books/other digital items with ORE -&amp;gt; interleave these&lt;br /&gt;     - offer similar comment/backlink option as above&lt;br /&gt;     - ie the book can be added &#39;normally&#39; with the internet-derived comments on the facing page to the book/excerpt they actually refer to, or the discussion can be mirrored with the comments in order and threaded, with the excerpts from the pages being attached to these. Or why not both?&lt;br /&gt;&lt;br /&gt;   - Automated indexes of URLs, dates and commenters can be generated without too much trouble on demand.&lt;br /&gt;   - Full-text indexes will be more demanding to generate, but I am sure that a little money and a crowd-sourced solution can be found.&lt;br /&gt;&lt;br /&gt;2) Ability to (onsite) print these PDFs into a single, (highly sexy) bound volume using a machine such as can be found in many Blackwell&#39;s bookshops today.&lt;br /&gt;&lt;br /&gt;3) A little capital to run competitions, targeting various levels in the university, asking the simple question &quot;If you could print anything you want as a bound book in 5 minutes, what&#39;s the most interesting thing you can think of to print out?&quot;&lt;br /&gt;&lt;br /&gt;&lt;big&gt;&lt;big&gt;&lt;b&gt; Why?&lt;/b&gt;&lt;/big&gt;&lt;/big&gt;&lt;br /&gt;People like books. They work, they don&#39;t need batteries and people who can read can intuitively &lt;i&gt;&#39;work&#39; &lt;/i&gt;a book. But books are not very dynamic. You have to have editors, drafters, publishers, and so on and so forth, and the germination of a book has to be measured in years... right?&lt;br /&gt;&lt;br /&gt;Print on demand smashes that and breaks down conceptions of what a book is. Is it a sacred tome that needs to be safeguarded and lent only to the most worthy? Or is is a snapshot of an ongoing teaching/research process? Or can it simply be a way to print out a notebook with page numbers as you would like them? Can a book be an alive and young collation of works, useful now, but maybe not as critical in a few years?&lt;br /&gt;&lt;br /&gt;Giving people the ability to make and generate their own books offers more potential - what books are they creating? Which generated books garner the most reuse, comments and excitement? Would the comments about the generated works be worth studying and printing in due course? Will people break through the pen-barrier, that taboo of taking pen to a page? Or will we just see people printing wikitravel guides and their flickr account?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Use-cases to give a taste of the possibilities:&lt;/b&gt;&lt;br /&gt;  - Print and share a discussion about an author, with excepts ordered and surrounded by the chronologically ordered and threaded comments made by a research group, a teaching group or even just a book club.&lt;br /&gt;  - Library &#39;cafe&#39; - library can subsidise the printing of existing works for use in the cafe, as long as the books stay in the cafe. Spillages, crumbs are not an issue to these facsimile books.&lt;br /&gt;  - Ability to record and store your terms/years/etc worth of notes in a single volume for posterity. At £5 a go, many students will want this.&lt;br /&gt;  - Test print a Thesis/Dissertation, without the expense of consulting a book binder.&lt;br /&gt;  - Archive in paper a snapshot of a digital labbook implemented on drupal or wordpress.&lt;br /&gt;  - Lecturer&#39;s notes from a given term, to avoid the looseleaf A4 overload spillage that often occurs.&lt;br /&gt;  - Printing of personalised or domain specific notebooks. (ie. a PDF with purposed fields, named columns and uniquely identified pages for recording data in the field - who says a printed book has to be full of info?)&lt;br /&gt;  - Maths sheets/tests/etc&lt;br /&gt;  - Past Papers&lt;br /&gt;&lt;br /&gt;I am humbled by the work done by Russell Davies, Ben Terrett and friends in this area and I can pinpoint the time at which I started to think more about these things to &lt;a href=&quot;http://bookcamp.pbworks.com/&quot;&gt;BookCamp&lt;/a&gt; sponsored by Penguin UK and run by Jeremy Ettinghausen &lt;a href=&quot;http://thepenguinblog.typepad.com/&quot;&gt;(blog)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Please, please see:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;a href=&quot;http://tinyurl.com/9qfoyt&quot;&gt;http://tinyurl.com/9qfoyt&lt;/a&gt;&lt;/b&gt; - Things Our Friends Have Written On The Internet 2008&lt;br /&gt;&lt;br /&gt;Russell Davies UnNotebook: &lt;a href=&quot;http://russelldavies.typepad.com/planning/2009/02/unnotebook.html&quot;&gt;http://russelldavies.typepad.com/planning/2009/02/unnotebook.html&lt;/a&gt;&lt;br /&gt;(&lt;b&gt;&lt;a href=&quot;http://tinyurl.com/cpdllw%29&quot;&gt;http://tinyurl.com/cpdllw&lt;/a&gt;&lt;/b&gt;&lt;a href=&quot;http://tinyurl.com/cpdllw%29&quot;&gt;)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/453105319749927455/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/453105319749927455' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/453105319749927455'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/453105319749927455'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2009/06/what-is-book-if-you-can-print-one-in-5.html' title='What is a book if you can print one in 5 minutes?'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-7690589575666077031</id><published>2009-05-15T02:22:00.001-07:00</published><updated>2009-05-15T02:22:53.865-07:00</updated><title type='text'>RDF + UI + Fedora for object metadata (RDF) editing</title><content type='html'>&lt;div xmlns=&#39;http://www.w3.org/1999/xhtml&#39;&gt;Just a walkthrough of something I am trying to implement at the moment:&lt;br/&gt;&lt;br/&gt;&lt;big&gt;Requirements:&lt;/big&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;For the Web UI:&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;Using jQuery and 3 plugins: jEditable, autocomplete and rdfquery.&lt;br/&gt;&lt;br/&gt;&lt;ul&gt;&lt;li&gt;jeditable: &lt;a href=&#39;http://www.appelsiini.net/projects/jeditable&#39;&gt;http://www.appelsiini.net/projects/jeditable&lt;/a&gt;&lt;/li&gt;&lt;li&gt;jeditable live demo: &lt;a href=&#39;http://www.appelsiini.net/projects/jeditable/default.html&#39;&gt;http://www.appelsiini.net/projects/jeditable/default.html&lt;/a&gt; &amp;lt;-- see this to understand what it gives.&lt;/li&gt;&lt;li&gt;&lt;a href=&#39;http://jquery.bassistance.de/autocomplete/demo/&#39;&gt;http://jquery.bassistance.de/autocomplete/demo/&lt;/a&gt; &amp;lt;-- example autocomplete demo&lt;/li&gt;&lt;li&gt;&lt;a href=&#39;http://code.google.com/p/rdfquery/&#39;&gt;http://code.google.com/p/rdfquery/&lt;/a&gt; from jeni tennison for reading RDFa information from the DOM of an HTML page using javascript.&lt;br/&gt;&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Needed middleware controls from the Web App:&lt;/b&gt;&lt;br/&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;create new session&lt;/b&gt; (specifically, a delta of the RDF expressed in iand&#39;s ChangeSet schema &lt;a href=&#39;http://vocab.org/changeset/schema&#39;&gt;http://vocab.org/changeset/schema&lt;/a&gt; ) &lt;b&gt;POST&lt;i&gt; /{object-id}/{RDF}/session/new&lt;/i&gt;&lt;/b&gt; -&amp;gt; HTTP 201 - session url (includes object id root)&lt;/li&gt;&lt;li&gt;&lt;b&gt;POST&lt;/b&gt; triples to &lt;b&gt;&lt;i&gt;/{session-url}/update&lt;/i&gt;&lt;/b&gt; to add to the &#39;add&#39; and/or &#39;delete&#39; portions&lt;/li&gt;&lt;li&gt;A &lt;b&gt;POST&lt;/b&gt; to /{session-url}/commit or just &lt;b&gt;DELETE&lt;/b&gt; /{session-url}&lt;br/&gt;&lt;/li&gt;&lt;/ol&gt;&lt;i&gt;And all objects typed by rdf:type (multitypes allowed)&lt;/i&gt;&lt;br/&gt;&lt;br/&gt;&lt;big&gt;Workflow:&lt;/big&gt;&lt;br/&gt;&lt;br/&gt;&lt;ol&gt;&lt;li&gt;Template grabs RDF info from object, and then displays it in the typical manner (substituting labels for uris when relevant), but also encodes the values with RDFa. &lt;/li&gt;&lt;li&gt;If the user is auth&#39;d to edit, each of these values has a css class added so that the inline editing for jeditable can act on it.&lt;/li&gt;&lt;li&gt;It then reads for the given type of object the cardinality of the fields present (eg from an OWL markup for the class) and also the other predicates that can be applied to this object. For multivalued predicates, an &#39;add another&#39; type link is appended below. For unused predicates, its up to the template to suggest these - currently, all the objects in the repo can have type specific templates, but for this example, I am considering generics.&lt;/li&gt;&lt;li&gt;For predicates which have usefully typed ranges, ie foaf:knows in our system points to a URI, rather than a string - autocomplete is used to hook into our or maybe anothers index of known labels for uris to suggest correct values. For example, if an author was going to indicate their affiliation to a department here at oxford (BRII project) it would be handy if a correct list of department labels was used. A choice from the list would view as the label, but represent the URI in the page.&lt;/li&gt;&lt;li&gt;When the user clicks on it to change the value, a session is created if none exists stamped with the start time of the edit and the last modified date of the RDF datastream, along with details of the editor, etc.&lt;/li&gt;&lt;li&gt;rdfquery is used to pull the triple from the RDFa in the edited field. When the user submits a change, the rdfa triple is posted to the session url as a &#39;delete&#39; triple and the new one is encoded as an &#39;add&#39; triple.&lt;/li&gt;&lt;li&gt;A simple addition would just post to the session with no &#39;delete&#39; parameter.&lt;/li&gt;&lt;li&gt;The UI should then reflect that the session is live and should be committed when the user is happy with the changes.&lt;/li&gt;&lt;/ol&gt;&lt;ul&gt;&lt;li&gt;On commit, the session would save the changeset to the object being edited, and update the RDF file in question. (so we keep  rdfquery would then update the RDFa in the page to the new values, upon a 200/204 reply.&lt;/li&gt;&lt;li&gt;On cancel, the values would be restored, and the session deleted.&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Commit Notes:&lt;/b&gt;&lt;br/&gt;If the lastmodified date on the datastream is different from the one marked on the session (ie possible conflict), the page information is updated to the most recent and the session is reapplied in the browser, highlighting the conflicts, and a warning given to the user.&lt;br/&gt;&lt;br/&gt;I am thinking of increasing the feedback using a messaging system, while keeping the same optimistic edit model - you can see the status of an item, and that someone else has a session open on it. The degree to the feedback is something I am still thinking about - should the UI highlight or even reflect the values that the other user(s) is editing in realtime? is that useful?&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/7690589575666077031/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/7690589575666077031' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/7690589575666077031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/7690589575666077031'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2009/05/rdf-ui-fedora-for-object-metadata-rdf.html' title='RDF + UI + Fedora for object metadata (RDF) editing'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-3083568477842956016</id><published>2009-03-30T02:43:00.000-07:00</published><updated>2009-03-30T02:50:45.849-07:00</updated><title type='text'>Early evaluation and serialisation of preservation policy decisions.</title><content type='html'>(Apologies, as this has been a draft when I thought it published. I have updated it to reflect changes that have been made since we started doing this.)&lt;br /&gt;&lt;br /&gt;It may be policy to make sure that the archive&#39;s materials are free of computer malware - one part of enacting this policy is running anti-virus and anti-spyware scans of the content. However, malware may be stored in the archive a number of months before it is widely recognised as such. So, the enactment of the policy of &#39;no malware&#39; would mean that content is scanned on ingest, in 3 to 6 months after ingest and one final scan a year later.&lt;br /&gt;&lt;br /&gt;Given that it is possible to monitor when changes occur to the preservation archive, it is not necessary to run continual sweeps of the content held in the archive to assess whether a preservation action is needed or not. Most actions that result from a preservation policy choice can be pre-assigned to an item when it iundergoes a change of state (creation, modification, deletion, extension)&lt;br /&gt;&lt;br /&gt;These decisions for actions (and also the auditable record of them occurring) are recorded inside the object itself and in a bid to reuse a standard rather than reinvent, this serialisation uses the iCal standard. iCal already has a proven capability to mark and schedule events and even handle reoccurring events, and to attach arbitrary information to these individual events.&lt;br /&gt;&lt;br /&gt;For the archive to self-describe and be preservable for the longer term, it is necessary for the actions taken to be archivable in some way too. A human-readable description of the action, alongside a best-effort attempt to describe this in machine-readable terms should be archived and referenced by any event that is an instance of that action. (&#39;best-effort&#39; due to the underwhelming nature of the current semantics and schemas for describe these preservation processes)&lt;br /&gt;&lt;br /&gt;In the Oxford system, an iCal calendar implementation called Darwin Calendar server was initially used to provide a queriable index of the preservation actions, along with a report of what events needed to be queued to be performed on a given day. These actions are queued in the short-term job queues (technically, being held in persistent AMQP queues) for later processing. However, the various iCal server implementations were not lightweight nor stable enough to be easily reused so from this point on, simple indexes are created as needed and retained from the serialised iCal to be used in its stead.&lt;br /&gt;&lt;br /&gt;Preservation actions such as scanning (virii, file-format, etc) are not the only systems to benefit from monitoring the state of an item. Text- and data-mining and analysis, indexing for search indices, dissemination copy production, and so on are all actions that can be driven and kept in line with the content in this way. For example, it is likely that the indices will be altered or benefit from refreshing on a periodic basis and the event of last-indexing can be included in this iCal file as a VJOURNAL event.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;NB&lt;/span&gt; no effort has been made to intertwine the iCal-serialised information with the packaging standard used, as this is heavily expected to both take considerable time and effort, and also severely limit our ability to reuse or migrate content from this packaging standard to a later, newer format. It is being stored as a separate Fedora datastream within the same object it describes, and is registered to be an iCal file containing preservation event information using information stored in the internal RDF manifest.</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/3083568477842956016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/3083568477842956016' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/3083568477842956016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/3083568477842956016'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2009/03/early-evaluation-and-serialisation-of.html' title='Early evaluation and serialisation of preservation policy decisions.'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-462847752063249912</id><published>2009-03-19T07:46:00.000-07:00</published><updated>2009-04-03T11:05:15.285-07:00</updated><title type='text'>We need people!</title><content type='html'>(UPDATE - Grrr.... seems that the concept of persistent URLs is lost on the admin - link below has been removed - see google cached copy &lt;a href=&quot;http://209.85.229.132/search?q=cache:YsdhcWzKWksJ:www.admin.ox.ac.uk/ps/oao/ar/ar3979j.shtml+http://www.admin.ox.ac.uk/ps/oao/ar/ar3979j.shtml&amp;amp;cd=1&amp;amp;hl=en&amp;amp;ct=clnk&quot;&gt;here&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.admin.ox.ac.uk/ps/oao/ar/ar3979j.shtml&quot;&gt;http://www.admin.ox.ac.uk/ps/oao/ar/ar3979j.shtml&lt;/a&gt; - job description.&lt;br /&gt;&lt;br /&gt;Essentially, we need smart people who are willing to join us to do good, innovative stuff; work that isn&#39;t by-the-numbers with room for initiative and ideas.&lt;br /&gt;&lt;br /&gt;Help us turn our digital repository into a digital library, it&#39;ll be fun! Well, maybe not fun, but it will be very interesting at least!&lt;br /&gt;&lt;br /&gt;bulletpoints: python/ruby frameworks, REST, a little SemWeb, ajax, jQuery, AMQP, Atom, JSON, RDF+RDFa, Apache WSGI deployment, VMs, linux, NFS, storage, RAID, etc.</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/462847752063249912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/462847752063249912' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/462847752063249912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/462847752063249912'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2009/03/we-need-people.html' title='We need people!'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-7889113205346661214</id><published>2009-02-25T06:09:00.001-08:00</published><updated>2009-02-25T07:09:26.115-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="creativity"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="event"/><category scheme="http://www.blogger.com/atom/ns#" term="fun"/><category scheme="http://www.blogger.com/atom/ns#" term="idea"/><category scheme="http://www.blogger.com/atom/ns#" term="motivation"/><category scheme="http://www.blogger.com/atom/ns#" term="play"/><title type='text'>Developer Happiness days - why happyness is important</title><content type='html'>&lt;big&gt;&lt;big&gt;&lt;b&gt;Creativity and innovation&lt;/b&gt;&lt;/big&gt;&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;One of the defining qualities of a good innovative developer is creativity and a pragmatic attitude; someone with the &#39;&lt;i&gt;rough consensus, running code&lt;/i&gt;&#39; mentality that pervades good software innovation. This can be seen as the drive to experiment, to turn inspiration and ideas into real, running code or to pathfind by trying out different things. Innovation can often happen when talking about quite separate, seemingly unrelated things, even to the point that most of the time, the &#39;outcomes&#39; of an interaction are impossible to pin down.&lt;br /&gt;&lt;br /&gt;&lt;big&gt;&lt;big&gt;&lt;b&gt;Play, vagueness and communication&lt;/b&gt;&lt;/big&gt;&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Creativity, inspiration, innovation, ideas, fun, and curiousity&lt;/b&gt; are all useful and important when developing software. These words convey concepts that do not thrive in situations that are purely scheduled, didactic, and teacher-pupil focussed. There needs to be an amount of &#39;&lt;b&gt;&lt;i&gt;play&lt;/i&gt;&lt;/b&gt;&#39; in the system (&lt;a href=&quot;http://en.wikipedia.org/wiki/Play_%28engineering%29&quot;&gt;see &#39;Play&#39;.&lt;/a&gt;) While this &#39;&lt;i&gt;&lt;b&gt;play&lt;/b&gt;&lt;/i&gt;&#39; is bad in a tightly regimented system, it is an essential part in a creative system, to allow for new things to develop, new ideas to happen and for &#39;random&#39; interactions to take place.&lt;br /&gt;&lt;br /&gt;Alongside this notion of &lt;i&gt;&lt;b&gt;play&lt;/b&gt;&lt;/i&gt; in an event, there also needs to be an amount of blank space, a &lt;i&gt;&lt;b&gt;vagueness&lt;/b&gt;&lt;/i&gt; to the event. I think that we can agree that much of the usefulness of normal conferences comes from the &#39;coffee breaks&#39; and &#39;lunch breaks&#39;, which are blank spaces of a sort. It is the recognition of this that is important and to factor it in more.&lt;br /&gt;&lt;br /&gt;Note that if a single developer could guess at how things should best be developed in the academic space, they would have done so by now. &lt;i&gt;Pre-compartmentalisation of ideas into &#39;tracks&#39; can kill potential innovation stone-dead.&lt;/i&gt; The distinction between CMSs, repositories and VLE developers is purely semantic and it is detrimental for people involved in one space to not overhear the developments, needs, ideas and issues in another. It is especially counter-productive to further segregate by community, such as having simultaneous Fedora, DSpace and EPrints strands at an event.&lt;br /&gt;&lt;br /&gt;While the inherent and intended &lt;i&gt;&lt;b&gt;vagueness&lt;/b&gt;&lt;/i&gt; provides the potential for cross-fertilisation of ideas, and the room for &lt;i&gt;&lt;b&gt;play&lt;/b&gt;&lt;/i&gt; provides the space, the final ingredient is that of &lt;i&gt;&lt;b&gt;speech, or any communication that takes place with the same ease and at the same speed of speech&lt;/b&gt;&lt;/i&gt;. While some may find the 140 character limit on twitter or identi.ca a strange constraint, this provides a target for people to really think about what they wish to convey and keeps the dialogue from becoming a series of monologues - much like the majority of emails of mailing lists - and keeps it as a dialogue between people.&lt;br /&gt;&lt;br /&gt;&lt;big&gt;&lt;big&gt;&lt;b&gt;Communication and Developers&lt;/b&gt;&lt;/big&gt;&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;One of the dichotomies in the necessity of communication to development is that developers can be shy, initially preferring the false anonymity of textual communication to spoken words between real people. There is a need to provide means for people to break the ice, and to strike up conversations with people that they can recognise as being of like minds. Asking that people&#39;s public online avatars are changed to be pictures of them can help people at an event find those that they have been talking to online and to start talking, face to face.&lt;br /&gt;&lt;br /&gt;On a personal note, one of the most difficult things I have to do when meeting people out in real life is answer the question &#39;What do you do?&#39; - it is much easier when I already know that the person asking the question has a technical background.&lt;br /&gt;&lt;br /&gt;And again, going back to the concept of compartmentalisation - &lt;i&gt;developers who only deal with developers and their managers/peers will build systems that work best for their peers and their managers.&lt;/i&gt; If these people are not the only users then they need to widen their communications. It is important for the developers that do not use their own systems to engage with the people who actually do. They should do this directly, without the potential for garbled dialogue via layers of protocol. This part needs managing in whatever space, both to avoid dominance by loud, disgruntled users and to mitigate anti-social behaviour. By and large, I am optimistic of this process, people tend to want to be thanked, and this simple &lt;i&gt;feedback loop&lt;/i&gt; can be used to help motivate. Making this feedback more disproportionate (a small &#39;thank you&#39; can lead to great effects) and adding in the notion of &lt;i&gt;highscore&lt;/i&gt; can lead to all sorts of interaction and outcomes, most notably being the rapid reinforcement of any behaviour that led to a positive outcome.&lt;br /&gt;&lt;br /&gt;&lt;big&gt;&lt;big&gt;&lt;b&gt;Disproportionate feedback loops and Highscores drive human behaviour&lt;/b&gt;&lt;/big&gt;&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;I&#39;ll just digress quickly to cover what I mean be a &lt;b&gt;&lt;i&gt;disproportionate feedback loop&lt;/i&gt;&lt;/b&gt;: A disproportionate feedback loop is something that encourages a certain behaviour; the input to which is something small and inexpensive, in either time or effort but the output can be large and very rewarding. This pattern can be seen in very many interactions: playing the lottery, [good] video game controls, twitter and facebook, musical instruments, the &#39;who wants to be a millionaire&#39; format, mashups, posting to a blog (&#39;free&#39; comments, auto rss updating, a google-able webpage for each post) etc.&lt;br /&gt;&lt;br /&gt;The &lt;i&gt;&lt;b&gt;natural drive for highscores&lt;/b&gt;&lt;/i&gt; is also worth pointing out. At first glance, is it as simple as considering its use in videogames? How about the concept of getting your &#39;5 fruit and veg a day&#39;? &lt;a href=&quot;http://www.5aday.nhs.uk/topTips/default.html&quot;&gt;http://www.5aday.nhs.uk/topTips/default.html&lt;/a&gt; Running in a marathon against other people? Inbox Zero (&lt;a href=&quot;http://www.slideshare.net/merlinmann/inbox-zero-actionbased-email&quot;&gt;http://www.slideshare.net/merlinmann/inbox-zero-actionbased-email&lt;/a&gt;),  Learning to play different musical scores? Your work being rated highly online? An innovation of yours being commented on by 5 different people in quick succession? Highscores can be very good drivers for human behaviour, addictive to some personalities.&lt;br /&gt;&lt;br /&gt;Why not set up some software highscores? For example, in the world of repositories, how about &#39;Fastest UI for self-submission&#39; - encouraging automatic metadata/datamining, a monthly prize for &#39;Most issue tickets handled&#39; - to the satisfaction of those posting the tickets, and so on.&lt;br /&gt;&lt;br /&gt;It is very easy to over-metricise this - some will purposefully abstain from this and some metrics are truely misleading. In the 90s, there was a push to have lines of code added as a metric to productivity. The false assumption is that lines of code have anything to do with producitivity - code should be lean, but not too lean to maintain.&lt;br /&gt;&lt;br /&gt;So be very careful when adding means to record highscores - they should be flexible, and be fun - if they are no fun for the developers and/or the users, they become a pointless metric, more of an obstacle than a motivation.&lt;br /&gt;&lt;br /&gt;&lt;big&gt;&lt;big&gt;&lt;b&gt;The Dev8D event&lt;/b&gt;&lt;/big&gt;&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;People were free to roam and interact at the Dev8D event and there was no enforced schedule, but twitter and a loudhailer were used to make people aware of things that were going on. Talks and discussions were lined up prior to the event of course, but the event was organised on a wiki which all were free to edit. As experience has told us, the important and sometimes inspired ideas occur in relaxed and informal surroundings where people just talk and share information, such as in a typical social situation like having food and drink.&lt;br /&gt;&lt;br /&gt;As a specific example, look &lt;a href=&quot;http://oxfordrepo.blogspot.com/2009/02/tracking-conferences-at-dev8d-with.html&quot;&gt;at the role of twitter at the event&lt;/a&gt;. Sam Easterby-Smith (&lt;a href=&quot;http://twitter.com/samscam%29&quot;&gt;http://twitter.com/samscam)&lt;/a&gt; created a means to track &#39;developer happiness&#39; and shared the tracking &#39;&lt;a href=&quot;http://samscam.co.uk/happier/&quot;&gt;Happyness-o-meter&#39;&lt;/a&gt; site with us all. This unplanned development inspired me to relay the infomation back to twitter and similarly led to me running an operating system/hardware survey in a very similar fashion.&lt;br /&gt;&lt;br /&gt;To help break the ice and to encourage play, we instituted a number of ideas:&lt;br /&gt;&lt;br /&gt;A &lt;b&gt;wordcloud on each attendees badge&lt;/b&gt;, consisting of whatever we could find of their work online, be it their blog or similar so that it might provide a talking point, or allow people to spot people who write about things they might be interested in learning more about.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The poker chip game&lt;/b&gt; - each attendee was given 5 poker chips at the start of the event, and it was encouraged that chips were to be traded for help, advice or as a way to convey a thank you. The goal was that the top 4 people ranked by amounts of chips at the end of the third day would receive a Dell mini 9 computer. The balance to this was that each chip was also worth a drink at the bar on that day too.&lt;br /&gt;&lt;br /&gt;We were well aware that we&#39;d left a lot of play in this particular system, allowing for lotteries to be set up, people pooling their chips, and so on. As the sole purpose of this was to encourage people to interact, to talk and bargain with each other, and to provide that feedback loop I mentioned earlier, it wasn&#39;t too important how people got the chips as long as it wasn&#39;t underhanded. It was the interaction and the &#39;fun&#39; that we were after. Just as an aside, Dave Flanders deserves the credit for this particular scheme.&lt;br /&gt;&lt;br /&gt;&lt;big&gt;&lt;big&gt;&lt;b&gt;Developer Decathlon&lt;/b&gt;&lt;/big&gt;&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;The basic concept of the &lt;a href=&quot;http://code.google.com/p/developerhappinessdays/wiki/DeveloperDecathlon&quot;&gt;Developer Decathlon&lt;/a&gt; was also reusing these ideas of play and feedback: &quot;&lt;a name=&quot;What_is_the_Developer_Decathlon?&quot;&gt;The Developer Decathlon is a competition at dev8D that enables developers to come together face-to-face to do rapid prototyping of software ideas. [..] &lt;/a&gt; We help facilitate this at dev8D by providing both &#39;real users&#39; and &#39;expert advice&#39; on how to run these rapid prototyping sprints. [..] The &#39;Decathlon&#39; part of the competition represents the &#39;10 users&#39; who will be available on the day to present the biggest issues they have with the apps they use and in turn to help answer developer questions as the prototypes applications are being created.  The developers will have two days to work with the users in creating their prototype applications.&quot;&lt;br /&gt;&lt;br /&gt;The best two submissions will get cash prizes that go to the individual, not to the company or institution that they are affiliated with. The outcomes of which will be made public shortly, once the judging panel have done their work.&lt;br /&gt;&lt;br /&gt;&lt;big&gt;&lt;big&gt;Summary&lt;/big&gt;&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;To foster innovation and to allow for creativity in software development:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Having &lt;b&gt;play&lt;/b&gt; space is &lt;b&gt;important&lt;/b&gt;&lt;/li&gt;&lt;li&gt;Being &lt;b&gt;vague&lt;/b&gt; with aims and &lt;b&gt;flexible&lt;/b&gt; with outcomes is not a bad thing and is &lt;b&gt;vital&lt;/b&gt; for unexpected things to develop - &lt;i&gt;e.g. A project&#39;s outcomes should be under continual re-negotiation as a general rule, not as the exception.&lt;/i&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Encouraging&lt;/b&gt; and &lt;b&gt;enabling&lt;/b&gt; free and easy communication is &lt;b&gt;crucial&lt;/b&gt;.&lt;/li&gt;&lt;li&gt;Be aware of what drives people to do what they do. Push all feedback to be &lt;b&gt;as disproportionate as possible&lt;/b&gt;, allowing both developers and users to benefit, with only putting a relatively trivial amount of input in (this pattern affects web UIs, development cycles, team interaction, etc)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Choose useful highscores&lt;/b&gt; and be prepared to ditch them or change them if they are no longer &lt;b&gt;fun and motivational&lt;/b&gt;.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/7889113205346661214/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/7889113205346661214' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/7889113205346661214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/7889113205346661214'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2009/02/developer-happiness-days-why-happyness.html' title='Developer Happiness days - why happyness is important'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-7013951292415915268</id><published>2009-02-22T18:28:00.001-08:00</published><updated>2009-02-22T18:28:02.027-08:00</updated><title type='text'>Handling Tabular data</title><content type='html'>&lt;div xmlns=&#39;http://www.w3.org/1999/xhtml&#39;&gt;&lt;b&gt;&quot;Storage&quot;&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;I put the s-word in quotes because the storing of the item is actually a very straightforward process - we have been dealing with storing tabular data for computation for a very long time now. Unfortunately, this also means that there are very many ways to capture, edit and present tables of information.&lt;br/&gt;&lt;br/&gt;One realisation to make with regards to preserving access to data coming from research is that there is a huge backlog of data in formats that we shall kindly call &#39;legacy&#39;. Not only is there this issue, but data is being made with tools and systems that effectively &#39;trap&#39; or lock-in a lot of this information - case in point being any research being recorded using Microsoft Access. While the tables of data can often be extracted with some effort, it is normally difficult to impossible to extract the implicit information; how tables interlink, how the Access Form adds information to the dataset, etc.&lt;br/&gt;&lt;br/&gt;It is this implicit knowledge that is the elephant in the room. Very many serialisations, such as SQL &#39;dumps&#39;, csv, xsl and so on, rely on implicit knowledge that is either related to the particulars of the application used to open it, or is actually highly domain specific.&lt;br/&gt;&lt;br/&gt;So, it is trivial and easy to specify a model for storing data, but without also encoding the implied information and without making allowances for the myriad of sources, the model is useless; it would be akin to defining the colour of storage boxes holding bric-a-brac. The datasets need to be characterised, and the implied information recorded in as good a way as possible.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Characterisation&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;The first step is to characterise the dataset that has been marked for archival and reuse. (Strictly, the best first step is to consult with the researcher or research team and help and guide them so that as much of the unsaid knowledge is known by all parties.)&lt;br/&gt;&lt;br/&gt;Some serialisations so a good job of this themselves, *SQL-based serialisations include basic data type information inside the table declarations themselves. As a pragmatic measure, it seems sensible to accept SQL-style table descriptions as a reasonable beginning. Later, we&#39;ll consider the implicit information that also needs to be recorded alongside such a declaration.&lt;br/&gt;&lt;br/&gt;Some others, such as CSV, leave it up to the parsing agent to guess at the type of information included. In these cases, it is important to find out or even deduce the type of data held in each column. Again, this data can be serialised in a SQL table declaration held alongside the original &lt;i&gt;unmodified&lt;/i&gt; dataset.&lt;br/&gt;&lt;br/&gt;(It is assumed that a basic data review will be carried out; does the csv have a consistent number of columns per row, is the version and operating system known for the MySQL that held the data, is there a PI or responsible party for the data, etc.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Implicit information&lt;br/&gt;&lt;/b&gt;&lt;br/&gt;Good teachers are right to point out this simple truth: &quot;don&#39;t forget to write down the obvious!&quot; It may seem obvious that all your data is latin-1 encoded, or that you are using a FAT32 filesystem, or even that you are running in a 32-bit environment, the painful truth is that we can&#39;t guarantee that these aspects won&#39;t affect how the data is held, accessed or stored. There may be systematic issues that we are not aware of, such as the problems with early versions of ZFS causing [, at the time, detected] data corruption, or MySQL truncating fields when serialised in a way that is not anticipated or discovered until later.&lt;br/&gt;&lt;br/&gt;In characterising the legacy sets of data, it is important to realise that there will be loss, especially with the formats and applications that blend presentation with storage. For example, it will require a major effort to attempt to recover the forms and logic bound into the various versions of MS Access. I am even aware of a major dataset, a highly researched dictionary of old english words and phrases, that the final output of which is a Macromedia Authorware application, and the source files are held by an unknown party (that is if they still exist at all) - the Joy of hiring Contractors. In fact, this warrants a slight digression:&lt;br/&gt;&lt;br/&gt;&lt;b&gt;The gap in IT support for research&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;If an academic researcher wishes to gain an external email account at their institution, there is an established protocol for this. Email is so commonplace, it sounds an easy thing to provide, but you need expertise, server hardware, multiuser configuration, adoption of certain access standards (IMAP, POP3, etc), and generally there are very few types of email (text or text with MIME attachments - NB the IM in MIME stands for Internet Mail)&lt;br/&gt;&lt;br/&gt;If a researcher has a need to store tables of data, where do they turn? They should turn to the same department, who will handle the heavy lifting of guiding standards, recording the implicit information and providing standard access APIs to the data. What the IT departments seem to be doing currently is - to carry on the metaphor - handing the researcher the email server software and telling them to get on with it, to configure it as they want. No wonder the resulting legacy systems are as free-form as they are.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Practical measures - Curation&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;Back to specifics now, consider that a set of data has been found to be important, research has been based on it, and it&#39;s been recognised that this dataset needs to be looked after. [This will illustrate the technical measures. Licencing, dialogue with the data owners, and other non-technical analysis and administration is left out, but assumed.]&lt;br/&gt;&lt;br/&gt;First task is to store the incoming data, byte-for-byte, as much as is possible - storing the iso image of the media the data is stored on, storing the SQL dump of a database, etc.&lt;br/&gt;&lt;br/&gt;Analyse the tables of data - record the base types of each column (text, binary, float, decimal, etc) apeing the syntax of a SQL table declaration, as well as trying to identify the key columns.&lt;br/&gt;&lt;br/&gt;Record the inter-table joins between primary and secondary keys, possibly by using a &lt;i&gt;&quot;table.column SAMEAS table.column;&quot;&lt;/i&gt; declaration after the table declarations.&lt;br/&gt;&lt;br/&gt;Likewise, attempt to add information concerning each column, information such as units or any other identifying material.&lt;br/&gt;&lt;br/&gt;Store this table description alongside the recorded tabular data source.&lt;br/&gt;&lt;br/&gt;Form a representation of this data in a well-known, current format such as a MySQL dump. For spreadsheets that are &#39;frozen&#39;, cells that are the results of embedded formula should be calculated and added as fixed values. It is important to record the environment, library and platform that these calculations are made with.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Table description as RDF &lt;/b&gt;(strictly, referencing cols/rows via the URI)&lt;br/&gt;&lt;br/&gt;One syntax I am playing around with is the notion that by appending sensible suffixes to the base URI for a dataset, we can unique specify a row, a column, a region or even a single cell. Simply put:&lt;br/&gt;&lt;br/&gt;http://datasethost/datasets/{data-id}#table/{table-name}/column/{column-id} to reference a whole column&lt;br/&gt;http://datasethost/datasets/{data-id}#table/{table-name}/row/{column-id} to reference a whole row, etc&lt;br/&gt;&lt;br/&gt;[The use of the # in the position it is in will no doubt cause debate. Suffice it to say, this is a pragmatic measure, as I suspect that an intermediary layer will have to take care of dereferencing a GET on these forms in any case.]&lt;br/&gt;&lt;br/&gt;The purpose for this is so that the tabular description can be made using common and established namespaces to describe and characterise the tables of data. Following on from a previous post on extending the BagIt protocol with an RDF manifest, this information can be included in said manifest, alongside the more expected metadata without disrupting or altering how this is handled.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;A possible content type for tabular data&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;By considering the base Fedora repository object model, or the BagIt model, we can apply the above to form a content model for a dataset:&lt;br/&gt;&lt;br/&gt;As a Fedora Object:&lt;br/&gt;&lt;br/&gt;&lt;ul&gt;&lt;li&gt;Original data in whatever forms or formats it arrives in (dsid prefix convention: DATA*)&lt;/li&gt;&lt;li&gt;Binary/textual serialisation in a well-understood format (dsid prefix convention: DERIV*)&lt;/li&gt;&lt;li&gt;&#39;Manifest&#39; of the contents (dsid convention: RELS-INT)&lt;/li&gt;&lt;li&gt;Connections between this dataset and other objects, like articles, etc as well as the RDF description of this item (RELS-EXT)&lt;/li&gt;&lt;li&gt;Basic description of dataset for interoperability (Simple dublin core - DC)&lt;/li&gt;&lt;/ul&gt;&lt;br/&gt;As a BagIt+RDF:&lt;br/&gt;&lt;br/&gt;Zip archive - &lt;br/&gt;&lt;ul&gt;&lt;li&gt;/MANIFEST (list of files and checksums)&lt;/li&gt;&lt;li&gt;/RDFMANIFEST (RELS-INT and RELS-EXT from above)&lt;/li&gt;&lt;li&gt;/data/* (original dataset files/disk images/etc)&lt;/li&gt;&lt;li&gt;/derived/* (normalised/re-rendered datasets in a well known format)&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Presentation - the important part&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;What is described above is the archival of the data. This is a form suited for discovery, but is not in a form suited for reuse. So, what is the possibility?&lt;br/&gt;&lt;br/&gt;BigTable (Google) or HBase (Hadoop) provides a platform where tabular data can be put in a scalable manner. In fact, I would go on to suggest that HBase should be a basic service offered by the IT department of any institution. By providing this database as a service, it should be easier to normalise, and to educate the academic users in a manner that is useful to them, not just to the archivist. Google spreadsheet is an extremely good example of how such a large, scalable database might be presented to the end-user.&lt;br/&gt;&lt;br/&gt;For archival sets with a good (RDF) description of the table, it should be possible to instantiate working versions of the tabular data on a scalable database platform like HBase on demand. Having a policy to put to &#39;sleep&#39; unused datasets can provide a useful comprimise, avoiding having all the tables live but still providing a useful service. &lt;br/&gt;&lt;br/&gt;It should also be noted that the adoption of popular methods of data access should be part of the responsibility of the data providers - this will change as time goes on, and protocols and methods for access alter with fashion. Currently, Atom/RSS feeds of any part of a table of data (the google spreadsheet model) fits very well with the landscape of applications that can reuse this information.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;br/&gt;&lt;ul&gt;&lt;li&gt;Try to record as much information as can be found or derived - from host operating system to column types.&lt;/li&gt;&lt;li&gt;Keep the original dataset byte-for-byte as you recieved it.&lt;/li&gt;&lt;li&gt;Try to maintain a version of the data in a well-understood format&lt;/li&gt;&lt;li&gt;Describe the tables of information in a reusable way, preferably by adopting a machine-readable mechanism&lt;/li&gt;&lt;li&gt;Be prepared to create services that the users want and need, not services that you think they should have.&lt;/li&gt;&lt;/ul&gt;&lt;br/&gt;&lt;br/&gt;&lt;div class=&#39;zemanta-pixie&#39;&gt;&lt;img src=&#39;http://img.zemanta.com/pixy.gif?x-id=38add0ef-8f30-4993-98ab-7ae1db1f0b20&#39; class=&#39;zemanta-pixie-img&#39;/&gt;&lt;/div&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/7013951292415915268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/7013951292415915268' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/7013951292415915268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/7013951292415915268'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2009/02/handling-tabular-data.html' title='Handling Tabular data'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-2171554919526538189</id><published>2009-02-20T03:40:00.000-08:00</published><updated>2009-02-20T04:07:24.997-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="archive"/><category scheme="http://www.blogger.com/atom/ns#" term="bagit"/><category scheme="http://www.blogger.com/atom/ns#" term="oaiore"/><category scheme="http://www.blogger.com/atom/ns#" term="packaging"/><category scheme="http://www.blogger.com/atom/ns#" term="rdf"/><category scheme="http://www.blogger.com/atom/ns#" term="serialisation"/><title type='text'>Pushing the BagIt manifest concept a little further</title><content type='html'>&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;I really like the idea of &lt;a href=&quot;http://www.cdlib.org/inside/diglib/bagit/bagitspec.html&quot;&gt;BagIt&lt;/a&gt; - &lt;b&gt;just enough framework&lt;/b&gt; to transfer files in a way that errors can be detected.&lt;br /&gt;&lt;br /&gt;I really like the idea of &lt;a href=&quot;http://www.w3.org/RDF/&quot;&gt;RDF&lt;/a&gt; - &lt;b&gt;just enough framework&lt;/b&gt; to detail, characterise and interlink resources in an extremely flexible and extendable fashion.&lt;br /&gt;&lt;br /&gt;I really like the 4 rules of &lt;a href=&quot;http://www.w3.org/DesignIssues/LinkedData.html&quot;&gt;Linked Data&lt;/a&gt; - &lt;b&gt;just enough rules&lt;/b&gt; to act as guides; follow the rules and your information will be much more useful to you and the wider world.&lt;br /&gt;&lt;br /&gt;What I do not wish to go near is any format that requires a non-machine-readable profile to understand or a human to reverse-engineer - METS, being a good example of a framework giving you enough rope to hang yourself on.&lt;br /&gt;&lt;br /&gt;So, what&#39;s my use-case? First, I&#39;ll outline what I digital objects I have, and why I handle and express them in the way I have.&lt;br /&gt;&lt;br /&gt;I deal with lists of resources on a day-to-day basis, and what these resources are and the way these resources link together is very important. The metadata associated with the list is also important, as this conveys the perspective of the agent that constructed this list; the &quot;who,what,where,when and why&quot; of the list.&lt;br /&gt;&lt;br /&gt;OAI-ORE is - at a basic level - a specification and a vocabulary, which can be used to depict a list of resources. This is a good thing. But here&#39;s the rub for me - I don&#39;t agree with how ORE semantically places this list. For me, the list is a subjective thing, a facet or perception of linkage between the resources listed. The list *always* implies a context through which the resources are to be viewed. This view leads me to the conclusion that any triples that are *asserted* by the list, such as triples containing an ordering predicate, such as &#39;hasNext&#39; or &#39;hasLast&#39;, these triples must not be in the same graph as the factual triples which would enter the &#39;global&#39; graph, such as list A is called (dc:title) &quot;My photos&quot; and contains resources a,b,c,d and e and was authored by Agent X.&lt;br /&gt;&lt;br /&gt;This is easier to illustrate with an example with everyone&#39;s friends, Alice and Bob:&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhppwar1ysQp2p4vW2vfotOvBUiipVrB8-iAErC2HOHXB7Wf9KeEIAQtGkrLlwhAo5O4xQ0JTJ1A62jKYUrHhGfTu1enAiHJqvKtqVChbDkGZayEBvsYIuEsGAGGCXIjjfczgcBaDZBcKI/?imgmax=800&quot; style=&quot;max-width: 800px;&quot; /&gt;&lt;br /&gt;Now, while Alice and Bob may be &#39;aggregating&#39; some of the same images, this doesn&#39;t mean we can infer much at all. Alice might be researching the development of a fruit fly&#39;s wings based on genetic degredation, and Bob might be researching the fruit fly&#39;s eye structure, looking for clear photos of the front of the fly. It could be even more unrelated in that Bob is actually looking for features on the electron microscope photos caused by dust or pollen.&lt;br /&gt;&lt;br /&gt;So, to cope with contextual assertions (A asserts that &amp;lt;B&amp;gt; &amp;lt;verb C&amp;gt; &amp;lt;D&amp;gt;) there are a couple of well-discussed tactics: Reification, &#39;Promotion&#39; (not sure of the correct term here) and Named Graphs.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Reification is a no-no&lt;/span&gt;. Very bad. Google will tell you all the reasons why this is bad.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;&#39;Promotion&#39; (what the real term for this is, I hope someone will post in the comments.)&lt;/span&gt; &#39;Promotion&#39; is just where a Classed node is introduced to allow contextual information to be added, very useful for adding information about a predicate. For example, consider &amp;lt;Person A&amp;gt; &amp;lt;researches&amp;gt; &amp;lt;ProjectX&amp;gt;. This, I&#39;d argue is a bad triple for any system that will last more than &amp;lt;ProjectX&amp;gt;&#39;s lifespan. We need to classify this triple with temporal information, and perhaps even location information too. So, one solution is to &#39;promote&#39; the &amp;lt;researches&amp;gt; predicate to be of the following form: &amp;lt;Person A&amp;gt; &amp;lt;has_role&amp;gt; &amp;lt;_: type=Researcher&amp;gt;; &amp;lt;_:&amp;gt; &amp;lt;dtstart&amp;gt; &amp;lt;etc&amp;gt;, &amp;lt;_:&amp;gt; &amp;lt;researches&amp;gt; &amp;lt;ProjectX&amp;gt; ...&lt;br /&gt;&lt;br /&gt;From the ORE camp, this promotion comes in the form of a Proxy for each aggregated resource that needs context. So in this way, they have &#39;promoted&#39; the resource, as a kind of promotion to the act of aggregation. Tomayto, Tomarto. The way this works for ORE doesn&#39;t sit well for me though, and the convention for the URI schema here feels very awkward and heavy.&lt;br /&gt;&lt;br /&gt;The third way (and my strong preference) is the &lt;span style=&quot;font-weight: bold;&quot;&gt;Named Graph approach&lt;/span&gt;. Put all the triples that are &lt;b&gt;asserted&lt;/b&gt; by, say Alice, into a resource at URI &amp;lt;Alices-NG&amp;gt; and say something like &amp;lt;Aggregation&amp;gt; &amp;lt;isProvidedContextBy&amp;gt; &amp;lt;Alices-NG&amp;gt;&lt;br /&gt;&lt;br /&gt;For ease of reuse though, I&#39;d suggest that the &lt;b&gt;facts&lt;/b&gt; are left in the global graph, in the aggregation serialisation itself. I am sure that the semantic arguments over what should go where could rage on for eons, my take is that information that is factual or generally useful should be left in the global graph. Like resource mime-type, standards compliance (&#39;conformsTo&#39;, etc), mirroring/alternate format information (&#39;sha1_checksum&#39;, &#39;hasFormat&#39; between a PDF, txt and Word doc versions, etc)&lt;br /&gt;&lt;br /&gt;(There is the murky middle ground of course, like for licencing. But I&#39;d suggest leave to the &#39;owning&#39; aggregation to put it in the global graph.)&lt;br /&gt;&lt;br /&gt;Enough of the digression on RDF!&lt;br /&gt;&lt;br /&gt;So,&lt;span style=&quot;font-weight: bold;&quot;&gt; how to extend BagIt&lt;/span&gt;, taking on board the things I have said above:&lt;br /&gt;&lt;br /&gt;Add alongside the MANIFEST of BagIt (a simple list of files and checksums) an RDF serialisation - RDFMANIFEST.{format} (which in my preference is in N3 or turtle notation, .n3 or .turtle accordingly)&lt;br /&gt;&lt;br /&gt;Copying the modelling of Aggregations from OAI-ORE, and we will say that one BagIt archive is equivalent to one Aggregation. (NB nothing wrong with a BagIt archive of BagIt archives!)&lt;br /&gt;&lt;br /&gt;Re-use the Agent and ore:aggregates concepts and conventions from the OAI-ORE spec to &#39;list&#39; the archive, and give some form of provenance. Add in a simple record for what this archive is meant to be as a whole (attached to the Aggregation class).&lt;br /&gt;&lt;br /&gt;Give each BagIt a URI - in this case, preferably a resolvable URI from which you can download it, but for bulk transfers using SneakerNet or CarFullOfDrivesNet, use a info:BagIt/{id} scheme of your choice.&lt;br /&gt;&lt;br /&gt;URIs for resources in transit are hierarchical, based on location in the archive: &amp;lt;info:BagIt/{book-id}/raw_pages/page1/bookid_page1_0.tiff&amp;gt;&lt;br /&gt;&lt;br /&gt;Checksums, mimetypes and alternates should be added to the RDF Manifest:&lt;br /&gt;&lt;br /&gt;NB &amp;lt;page1&amp;gt; == &amp;lt;info:BagIt/{book-id}/raw_pages/page1/bookid_page1_0.tiff&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&amp;lt;page1&amp;gt; &amp;lt;sha1&amp;gt; &quot;9cbd4aeff71f5d7929b2451c28356c8823d09ab4&quot;;&lt;br /&gt;            &amp;lt;mimetype&amp;gt; &quot;image/tiff&quot;;&lt;br /&gt;            &amp;lt;hasFormat&amp;gt; &amp;lt;info:BagIt/{book-id}/thumbnail_pages/page1/bookid_page1_0.jpg&amp;gt;;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Any assertions, such as page ordering in this case, should be handled as necessary. Just *please* do not use &#39;hasNext&#39;! Use a named graph, use the built in rdf list mechanism, add an RSS 1.0 feed as a resource, anything but hasNext!&lt;br /&gt;&lt;br /&gt;And that&#39;s about it for the format. One last thing to say about using info URIs though - I&#39;d strongly suggest that they are used when the items do not have resolvable (http) URIs, and once transfered, I&#39;d suggest that the info URIs are replaced with the http ones, and the info varients can be kept in a graph for provenance.&lt;br /&gt;&lt;br /&gt;(Please note that I am biased in that this mirrors quite closely the way that the archives here and the way that digital items are held, but I think this works!)&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;zemanta-pixie&quot;&gt;&lt;img src=&quot;http://img.zemanta.com/pixy.gif?x-id=fff61065-2009-49ce-be42-a1a3fc965f2c&quot; class=&quot;zemanta-pixie-img&quot; /&gt;&lt;/div&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/2171554919526538189/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/2171554919526538189' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/2171554919526538189'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/2171554919526538189'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2009/02/pushing-bagit-manifest-concept-little.html' title='Pushing the BagIt manifest concept a little further'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhppwar1ysQp2p4vW2vfotOvBUiipVrB8-iAErC2HOHXB7Wf9KeEIAQtGkrLlwhAo5O4xQ0JTJ1A62jKYUrHhGfTu1enAiHJqvKtqVChbDkGZayEBvsYIuEsGAGGCXIjjfczgcBaDZBcKI/s72-c?imgmax=800" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-3073595490420683868</id><published>2009-02-18T04:18:00.000-08:00</published><updated>2009-02-18T06:52:25.963-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dev8d python twitter tagging spreadsheet data google"/><title type='text'>Tracking conferences (at Dev8D) with python, twitter and tags</title><content type='html'>There was so much going on at http://www.dev8d.org (#dev8d) that it might be foolish for me to attempt to write up what happened.&lt;br /&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;&lt;br /&gt;So, I&#39;ll focus on a small, but to my mind, crucial aspect of it - tag tracking with a focus on &lt;a href=&quot;http://twitter.com/&quot;&gt;Twitter&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;big&gt;&lt;big&gt;The Importance of Tags&lt;/big&gt;&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;First, the tag (#)dev8d was cloudburst over a number of social sites - &lt;a href=&quot;http://www.flickr.com/photos/tags/dev8d/&quot;&gt;Flickr&lt;/a&gt;(dev8d tagged photos), &lt;a href=&quot;http://search.twitter.com/search?q=%23dev8d&quot;&gt;Twitter&lt;/a&gt;(dev8d feed), blogs such as the &lt;a href=&quot;http://dev8d.jiscinvolve.org/&quot;&gt;JISCInvolve Dev8D site&lt;/a&gt;, and so on. This was not just done for publicity, but as a means to track and re-assemble the various inputs to and outputs from the event.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.flickr.com/photos/tags/dev8d/&quot;&gt;Flickr&lt;/a&gt; has some really nice photos on it, shared by people like &lt;a href=&quot;http://www.flickr.com/photos/ianibbo/&quot;&gt;Ian Ibbotson&lt;/a&gt; (who caught &lt;a href=&quot;http://www.flickr.com/photos/ianibbo/3275945388/&quot;&gt;an urban fox&lt;/a&gt; on camera during the event!) While there was an &#39;official&#39; &lt;a href=&quot;http://www.flickr.com/photos/dev8d&quot;&gt;dev8d flickr user&lt;/a&gt;, I expect the most unexpected and most interesting photos to be shared by other people who kindly add on the dev8d tag so we can find them. For conference organisers, this means that there is a pool of images that we can choose from, each with their own provenance so we can contact the owner if we wanted to re-use, or re-publish. Of course, if the owner puts a &lt;a href=&quot;http://creativecommons.org/&quot;&gt;CC licence&lt;/a&gt; on them, it makes things easier :)&lt;br /&gt;&lt;br /&gt;So, asserting a tag or label for an event is a useful thing to do in any case. But, this twinned with using a messaging system like &lt;a href=&quot;http://twitter.com/&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;http://identi.ca/&quot;&gt;Identi.ca&lt;/a&gt;, means that you can coordinate, share, and bring together an event. There was a projector in the Basecamp room, which was either the bar, or one of the large basement rooms at Birkbeck depending on the day. Initially, this was used to run through the basic flow of events, which was primarily organised through the use of a &lt;a href=&quot;http://code.google.com/p/developerhappinessdays/&quot;&gt;wiki&lt;/a&gt;, to which all of us and the attendees were members.&lt;br /&gt;&lt;br /&gt;&lt;big&gt;&lt;big&gt;Projecting the bird&#39;s eye view of the event&lt;/big&gt;&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;I am not entirely sure whose idea it was initially to use the projector to follow the dev8d tag on twitter, auto-refreshing itself every minute, but it would be one or more of the following: Dave Flanders(&lt;a href=&quot;http://twitter.com/dfflanders&quot;&gt;@dfflanders&lt;/a&gt;), Andy McGregor(&lt;a href=&quot;http://twitter.com/andymcg&quot;&gt;@andymcg&lt;/a&gt;) and Dave Tarrant(&lt;a href=&quot;http://twitter.com/davetaz&quot;&gt;@davetaz&lt;/a&gt;) who is aka BitTarrant due to his network wizardry keeping the wifi going despite Birkbeck&#39;s network&#39;s best efforts at stopping any form of useful networking going.&lt;br /&gt;&lt;br /&gt;The funny thing about the feed being there, was that it felt perfectly natural from the start. Almost like a mix of notice board, event liveblog and facebook status updates, but the overall effect was like it was the&lt;i&gt; bird&#39;s eye view&lt;/i&gt; of the entire event, which you could dip into and out of at will, follow up on talks you weren&#39;t even attending, catch interesting links that people posted, and just follow the whole event while doing your own thing.&lt;br /&gt;&lt;br /&gt;&lt;big&gt;&lt;big&gt;Then things got interesting.&lt;/big&gt;&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;From what I heard, a conversation in the bar about developer happiness (involving &lt;a href=&quot;http://twitter.com/rgardler&quot;&gt;@rgardler&lt;/a&gt;?) lead to &lt;a href=&quot;http://samscam.co.uk/&quot;&gt;Sam Easterby-Smith&lt;/a&gt; (&lt;a href=&quot;http://twitter.com/samscam&quot;&gt;@samscam&lt;/a&gt;) to create a script that dug through the dev8d tweets looking for &lt;i&gt;n/m&lt;/i&gt; (like 7/10) and to use that as a mark of happyness e.g.&lt;br /&gt;&lt;blockquote&gt;&lt;a href=&quot;http://twitter.com/samscam&quot;&gt;&quot; @samscam&lt;/a&gt; #dev8d I am seriously 9/10 happy &lt;a href=&quot;http://samscam.co.uk/happier&quot;&gt;http://samscam.co.uk/happier&lt;/a&gt; HOW HAPPY ARE YOU? &quot; &lt;a href=&quot;http://twitter.com/samscam/status/1197185415&quot;&gt; (Tue, 10 Feb 2009 11:17:15)&lt;/a&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzHxye9M5JltvWjkrSk1HYQgugmBZsMRbFAD6n06RWfWoJPm68leoKesHKGzeWnWPPgSLkEKu99G55smNW8AfmBavkyQXj_1EEJ2ZcMJI7vxqvmvbmRKlPyyT2cFIgy7lfSjH-8-R8omI/?imgmax=800&quot; style=&quot;max-width: 800px;&quot; /&gt;&lt;br /&gt;&lt;br /&gt;And computed the average happyness and overall happyness of those who tweeted how they were doing!&lt;br /&gt;&lt;br /&gt;Of course, being friendly, constructive sorts, we knew the best way to help &#39;improve&#39; his happyometer was to try to break it by sending it bad input... *ahem*.&lt;br /&gt;&lt;blockquote&gt;&lt;a href=&quot;http://twitter.com/samscam&quot;&gt;&quot; @samscam&lt;/a&gt; #dev8d based on instant discovery of bugs in the Happier Pipe am now only 3/5 happy &quot; (&lt;a href=&quot;http://twitter.com/samscam/statuses/1197215138&quot;&gt;Tue, 10 Feb 2009 23:05:05&lt;/a&gt;)&lt;br /&gt;&lt;/blockquote&gt;BUT things got fixed, and the community got involved and interested. It caused talk and debate, got people wondering how that it was done, how they could do the same thing and how to take it further.&lt;br /&gt;&lt;br /&gt;At which point, I thought it might be fun to &#39;retweet&#39; the happyness ratings as they change, to keep a running track of things. And so, a purpose for &lt;a href=&quot;http://twitter.com/randomdev8d&quot;&gt;@randomdev8d&lt;/a&gt; was born:&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgI4qreMGP617Acq0GSOOzLdOYYoPKTS7i7m0I03kfW9_3AVaXJkwmFGg-nrmEZptARxnl2KyYdhMaHfQ7ZXHkT27fH7KIjLKWpB2ZeB9IQiE7TA98E2cYG8ejfNnehXJeGIn0tFP81k34/?imgmax=800&quot; style=&quot;max-width: 800px;&quot; /&gt;&lt;br /&gt;&lt;br /&gt;How I did this was fairly simple: I grabbed his page every minute or so, used BeautifulSoup to parse the HTML, got the happyness numbers out and compared it to the last ones the script had seen. If there was a change, it tweeted it and seconds later, the projected tweet feed updated to show the new values - a disproportionate feedback loop, the key to involvement in games; you do something small like press a button or add 4/10 to a message, and you can affect the stock-market ticker of happyness :)&lt;br /&gt;&lt;br /&gt;If I had been able to give my talk on the python code day, the code to do this would contain zero surprises, because I covered 99% of this - so here&#39;s my &lt;a href=&quot;http://developerhappinessdays.googlecode.com/files/dev8d-presentation.pdf&quot;&gt;&#39;slides&#39;&lt;/a&gt;[pdf] - basically a snapshot screencast.&lt;br /&gt;&lt;br /&gt;Here&#39;s the crufty code though that did this:&lt;br /&gt;&lt;blockquote&gt;import time&lt;br /&gt;import simplejson, httplib2, BeautifulSoup&lt;br /&gt;h = httplib2.Http()&lt;br /&gt;h.add_credentials(&#39;randomdev8d&#39;,&#39;PASSWORD&#39;)&lt;br /&gt;happy = httplib2.Http()&lt;br /&gt;o = 130.9&lt;br /&gt;a = 7.7&lt;br /&gt;import urllib&lt;br /&gt;&lt;br /&gt;while True:&lt;br /&gt;print &quot;Checking happiness....&quot;&lt;br /&gt;(resp, content) = happy.request(&#39;http://samscam.co.uk/happier/&#39;)&lt;br /&gt;soup = BeautifulSoup.BeautifulSoup(content)&lt;br /&gt;overallHappyness = soup.findAll(&#39;div&#39;)[2].contents&lt;br /&gt;avergeHappyness = soup.findAll(&#39;div&#39;)[4].contents&lt;br /&gt;over = float(overallHappyness[0])&lt;br /&gt;ave = float(avergeHappyness[0])&lt;br /&gt;print &quot;Overall %s - Average %s&quot; % (over, ave)&lt;br /&gt;omess = &quot;DOWN&quot;&lt;br /&gt;if over &amp;gt; o:&lt;br /&gt;omess = &quot;UP!&quot;&lt;br /&gt;amess = &quot;DOWN&quot;&lt;br /&gt;if ave &amp;gt; a:&lt;br /&gt;amess= &quot;UP!&quot;&lt;br /&gt;if over == o:&lt;br /&gt;omess = &quot;SAME&quot;&lt;br /&gt;if ave == a:&lt;br /&gt;amess = &quot;SAME&quot;&lt;br /&gt;if not (o == over and a == ave):&lt;br /&gt;print &quot;Change!&quot;&lt;br /&gt;o = over&lt;br /&gt;a = ave&lt;br /&gt;tweet = &quot;Overall happiness is now %s(%s), with an average=%s(%s) #dev8d (from http://is.gd/j99q)&quot; % (overallHappyness[0], omess, avergeHappyness[0], amess)&lt;br /&gt;data = {&#39;status&#39;:tweet}&lt;br /&gt;body = urllib.urlencode(data)&lt;br /&gt;(rs,cont) = h.request(&#39;http://www.twitter.com/statuses/update.json&#39;, &quot;POST&quot;, body=body)&lt;br /&gt;else:&lt;br /&gt;print &quot;No change&quot;&lt;br /&gt;time.sleep(120)&lt;br /&gt;&lt;/blockquote&gt;(Available from &lt;a href=&quot;http://pastebin.com/f3d42c348&quot;&gt;http://pastebin.com/f3d42c348&lt;/a&gt; with syntax highlighting - NB this was written beat-poet style, written from A to B with little concern for form. The fact that it works is a miracle, so comment on the code if you must.)&lt;br /&gt;&lt;br /&gt;&lt;big&gt;&lt;big&gt;The grand, official #Dev8D survey!&lt;/big&gt;&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;... which was anything but official, or grand. The happyness-o-meter idea lead BitTarrant and I to think &quot;Wouldn&#39;t it be cool to find out what computers people have brought here?&quot; Essentially, finding out what computer environment developers &lt;i&gt;choose&lt;/i&gt; to use is a very valuable thing - developers choose things which make our lives easier, by and large, so finding out which setups they use by preference to develop or work with could guide later choices, such as being able to actually target the majority of environments for wifi, software, or talks.&lt;br /&gt;&lt;br /&gt;So, on the Wednesday morning, Dave put out the call on @dev8d for people to post the operating systems on the hardware they brought to this event, in the form of OS/HW. I then busied myself with writing a script that hit the twitter search api directly, and parsed it itself. As this was a more intended script, I made sure that it kept track of things properly, pickling its per-person tallys. (You could post up multiple configurations in one or more tweets, and it kept track of it per-person.) This script was a little bloated at 86 lines, so I won&#39;t post it inline - plus, it also showed that I should&#39;ve gone to the regexp lesson, as I got stuck trying to do it with regexp, gave up, and then used whitespace-tokenising... but it worked fine ;)&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://pastebin.com/f2c04719b&quot;&gt;Survey code: http://pastebin.com/f2c04719b&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Survey results:&lt;/span&gt; &lt;a href=&quot;http://spreadsheets.google.com/pub?key=pDKcyrBE6SJqToHzjCs2jaQ&quot;&gt;http://spreadsheets.google.com/pub?key=pDKcyrBE6SJqToHzjCs2jaQ&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;OS:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Linux was the majority at 42%&lt;/span&gt; closely followed by Apple at 37% with MS-based OS at 18% with a stellar showing of one user of OpenSolaris (4%)!&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Hardware type:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;66% were laptops, with 25% of the machines there being classed as netbooks&lt;/span&gt;. 8% of the hardware there were iPhones too, and one person claimed to have brought Amazon EC2 with them ;)&lt;br /&gt;&lt;br /&gt;&lt;big&gt;&lt;big&gt;The post hoc analysis&lt;/big&gt;&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;Now then, having gotten back to normal life, I&#39;ve spent a little time grabbing stuff from twitter and digging through them. Here is the &lt;a href=&quot;http://spreadsheets.google.com/pub?key=pDKcyrBE6SJoJdIcm7mdpBg&quot;&gt;list of the 1300+ tweets with the #dev8d tag in them&lt;/a&gt; published via google docs, and here is some derived things posted by Tony Hirst(&lt;a href=&quot;http://twitter.com/psychemedia&quot;&gt;@psychemedia&lt;/a&gt;) and Chris Wilper(&lt;a href=&quot;http://twitter.com/cwilper&quot;&gt;@cwilper&lt;/a&gt;) seconds after I posted this:&lt;br /&gt;&lt;br /&gt;Tagcloud of twitterer&#39;s:&lt;br /&gt;&lt;a href=&quot;http://www.wordle.net/gallery/wrdl/549364/dev8_twitterers&quot;&gt;http://www.wordle.net/gallery/wrdl/549364/dev8_twitterers&lt;/a&gt; [java needed]&lt;br /&gt;&lt;br /&gt;Tagcloud of tweeted words:&lt;br /&gt;&lt;a href=&quot;http://www.wordle.net/gallery/wrdl/549350/dev8d&quot;&gt;http://www.wordle.net/gallery/wrdl/549350/dev8d&lt;/a&gt; [java needed]&lt;br /&gt;&lt;br /&gt;And a column of all the tweeted links:&lt;br /&gt;&lt;a href=&quot;http://spreadsheets.google.com/pub?key=p1rHUqg4g423-wWQn8arcTg&quot;&gt;http://spreadsheets.google.com/pub?key=p1rHUqg4g423-wWQn8arcTg&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This lead me to dig through them and republish the list of tweets, but try to unminimise the urls and try to grab the &amp;amp;lt;title&amp;gt; tag of the html page it goes to, which you can find here:&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://spreadsheets.google.com/pub?key=pDKcyrBE6SJpwVmV4_4qOdg&quot;&gt;http://spreadsheets.google.com/pub?key=pDKcyrBE6SJpwVmV4_4qOdg&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;(Which incidently, lead me to spot that there was one link to &quot;YouTube - Rick Astley - Never Gonna Give You Up&quot; which means the hacking was all worthwhile :))&lt;br /&gt;&lt;br /&gt;&lt;big&gt;&lt;big&gt;Graphing Happyness&lt;/big&gt;&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;For one, I&#39;ve re-analysed the happyness tweets and posted up the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A &lt;a href=&quot;http://spreadsheets.google.com/pub?key=pDKcyrBE6SJqHVP8Fb7euEA&quot;&gt;full log of happyness with timeline attached to it&lt;/a&gt;,&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://spreadsheets.google.com/pub?key=pDKcyrBE6SJoxj8D7_EWscQ&quot;&gt;The running average, with accompanying timeline,&lt;/a&gt;&lt;/li&gt;&lt;li&gt;and the &lt;a href=&quot;http://spreadsheets.google.com/pub?key=pDKcyrBE6SJp6acAAn77SZQ&quot;&gt;average of the last 10 tweets&lt;/a&gt; in much the same way as before.&lt;/li&gt;&lt;/ul&gt;It is easier to understand the averages as graphs over time of course! You could also use Tony Hirst&#39;s excellent write up here about &lt;a href=&quot;http://ouseful.wordpress.com/2009/02/17/creating-your-own-results-charts-for-surveys-created-with-google-forms/&quot;&gt;creating graphs from google forms and spreadsheets.&lt;/a&gt; I&#39;m having issues embedding the google timeline widget here, so you&#39;ll have to make do with static graphs.&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinOtUr-e8hP9CgY6czBpQkiPa29cwLO4myVLb3qR_86XI9fS8S5H7E4sVPKgvhLDfuHH3kj6nfmR2bAbg-62pc2dBec1WOmr6mFb6fKflSODV4anHi3S5ApOYXuZRhyphenhyphenDTMbwdzzZ67o00/s800/dev8d_running_total_average.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 800px; height: 468px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinOtUr-e8hP9CgY6czBpQkiPa29cwLO4myVLb3qR_86XI9fS8S5H7E4sVPKgvhLDfuHH3kj6nfmR2bAbg-62pc2dBec1WOmr6mFb6fKflSODV4anHi3S5ApOYXuZRhyphenhyphenDTMbwdzzZ67o00/s800/dev8d_running_total_average.png&quot; alt=&quot;&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Average happyness over the course of the event - all tweets counted towards the average.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm7CC7BW5mCI24UMG9gdX5wu004UsabPeB1Ntg4Tklg9Jhcf037eHhay7UAyxhG7i_l7hVPefGcH6rE6yEo0ZSmCOfV7BBLCWJiY8dlvQLplO-d0XeWvcjfBI-eItkaOnl9e8OWRFHvqg/s912/dev8d_last10HappynessTweetsCount.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 912px; height: 510px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm7CC7BW5mCI24UMG9gdX5wu004UsabPeB1Ntg4Tklg9Jhcf037eHhay7UAyxhG7i_l7hVPefGcH6rE6yEo0ZSmCOfV7BBLCWJiY8dlvQLplO-d0XeWvcjfBI-eItkaOnl9e8OWRFHvqg/s912/dev8d_last10HappynessTweetsCount.png&quot; alt=&quot;&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Average happyness, but only the previous 10 tweets counted towards the average making it more reflective of the happyness at that time.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you are wondering about the first dip, that was when we all tried to break Sam&#39;s tracker by sending it bad data, a lot of 0 happyness&#39;s were recorded therefore :) As for the second dip, well, you can see that from the &lt;a href=&quot;http://spreadsheets.google.com/pub?key=pDKcyrBE6SJqHVP8Fb7euEA&quot;&gt;log of happyness&lt;/a&gt;, yourselves :)&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/3073595490420683868/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/3073595490420683868' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/3073595490420683868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/3073595490420683868'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2009/02/tracking-conferences-at-dev8d-with.html' title='Tracking conferences (at Dev8D) with python, twitter and tags'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzHxye9M5JltvWjkrSk1HYQgugmBZsMRbFAD6n06RWfWoJPm68leoKesHKGzeWnWPPgSLkEKu99G55smNW8AfmBavkyQXj_1EEJ2ZcMJI7vxqvmvbmRKlPyyT2cFIgy7lfSjH-8-R8omI/s72-c?imgmax=800" height="72" width="72"/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-4516927983558625883</id><published>2008-12-02T08:12:00.000-08:00</published><updated>2008-12-02T08:19:35.910-08:00</updated><title type='text'>Archive file resiliences</title><content type='html'>&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;&lt;b&gt;Tar format: &lt;a href=&quot;http://en.wikipedia.org/wiki/Tar_%28file_format%29#Format_details&quot;&gt;http://en.wikipedia.org/wiki/Tar_(file_format)#Format_details&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The tar file format seems to be quite robust as a container: the files are put in byte for byte as they are on disc, with a 512 byte header prefix, and the file length padded to fit into 512 byte blocks.&lt;br /&gt;&lt;br /&gt;(Also, quick tip with working with archives on the commandline - the utility &#39;less&#39; can list the contents of many: less test.zip .tar etc)&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Substitution damage:&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;By hacking the header files (using a hexeditor like ghex2), the inbuilt header checksum seems to detected corruption as intended. The normal tar utility will (possibly by default) skip corrupted headers and therefore files, but will find the other files in the archive:&lt;br /&gt;&lt;br /&gt;ben@billpardy:~/tar_testground$ tar -tf test.tar&lt;br /&gt;New document 1.2007_03_07_14_59_58.0&lt;br /&gt;New document 1.2007_09_07_14_18_02.0&lt;br /&gt;New document 1.2007_11_16_12_21_20.0&lt;br /&gt;ben@billpardy:~/tar_testground$ echo $?&lt;br /&gt;0&lt;br /&gt;(tar reports success)&lt;br /&gt;ben@billpardy:~/tar_testground$ ghex2 test.tar&lt;br /&gt;(munge first header a little)&lt;br /&gt;ben@billpardy:~/tar_testground$ tar -tf test.tar&lt;br /&gt;tar: This does not look like a tar archive&lt;br /&gt;tar: Skipping to next header&lt;br /&gt;New document 1.2007_09_07_14_18_02.0&lt;br /&gt;New document 1.2007_11_16_12_21_20.0&lt;br /&gt;tar: Error exit delayed from previous errors&lt;br /&gt;ben@billpardy:~/tar_testground$ echo $?&lt;br /&gt;2&lt;br /&gt;&lt;br /&gt;Which is all well and good, at least you can detect errors which hit important parts of the tar file. But what&#39;s a couple of 512 byte targets in a 100Mb tar file?&lt;br /&gt;&lt;br /&gt;As the files are in the file unaltered, any damage that isn&#39;t in tar header sections or padding is restricted to damaging the file itself and not the files around it. So a few bytes of damage will be contained to the area it occurs in. It is important to make sure that you checksum the files then!&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Additive damage:&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;The tar format is (due to legacy tape concerns) pretty fixed on the 512 block size. Any addition seems to cause the part of the file after the addition to be &#39;unreadable&#39; to the tar utility as it checks only on the 512 byte mark. The exception is - of course - a 512 byte addition (or multiple thereof).&lt;br /&gt;&lt;blockquote&gt;&lt;b&gt;Summary:&lt;/b&gt; the tar format is reasonably robust, in part due to its uncompressed nature and also due to its inbuilt header checksum. Bitwise damage seems to be localised to the area/files it affects. Therefore, if used as, say, a BagIT container, it might be useful for the server to allow individual file re-download, to avoid pulling the entire container again.&lt;br /&gt;&lt;/blockquote&gt;&lt;a href=&quot;http://www.flickr.com/photos/oxfordrepo/3076904031/&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3166/3076904031_c775cfd5ce.jpg?v=0&quot; style=&quot;max-width: 800px;&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ZIP format: &lt;a href=&quot;http://en.wikipedia.org/wiki/ZIP_%28file_format%29#The_format_in_detail&quot;&gt;http://en.wikipedia.org/wiki/ZIP_(file_format)#The_format_in_detail&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Zip has a similar layout to Tar, in that the files are stored sequentially, with the main file table or &#39;central directory&#39; being at the end of a file.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Substitution damage:&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Through similar hacking of the file as in the tar test above, a few important things come out:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It is possible to corrupt individual files, without the ability to unzip being affected. However, like tar, it will report a error (echo $? -&amp;gt; &#39;2&#39;) if the file crc32 doesn&#39;t match the checksum in the central directory.&lt;/li&gt;&lt;ul&gt;&lt;li&gt;BUT, this corruption seemed to only affect the file that the damage was made too. The other files in the archive were unaffected. Which is nice.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Losing the end of the file renders the archive hard to recover.&lt;/li&gt;&lt;li&gt;It does not checksum the central directory, so slight alterations here can cause all sorts of unintended changes: (NB altered a filename in the central directory [a &#39;3&#39;-&amp;gt;&#39;4&#39;])&lt;br /&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;ben@billpardy:~/tar_testground/zip_test/3$ unzip test.zip&lt;br /&gt;Archive:  test.zip&lt;br /&gt;New document 1.2007_0&lt;b&gt;4&lt;/b&gt;_07_14_59_58.0:  mismatching &quot;local&quot; filename (New document 1.2007_0&lt;b&gt;3&lt;/b&gt;_07_14_59_58.0),&lt;br /&gt;        continuing with &quot;central&quot; filename version&lt;br /&gt; inflating: New document 1.2007_04_07_14_59_58.0 &lt;br /&gt; inflating: New document 1.2007_09_07_14_18_02.0 &lt;br /&gt; inflating: New document 1.2007_11_16_12_21_20.0 &lt;br /&gt;ben@billpardy:~/tar_testground/zip_test/3$ echo $?&lt;br /&gt;1&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Note that the unzip utility did error out, but the filename of the file extracted was altered to the &#39;phony&#39; central directory one. It should be New document 1.2007_0&lt;b&gt;3&lt;/b&gt;_07_14_59_58.0&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;i&gt;Additive damage:&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Addition to file region: &lt;/i&gt;This test resulted in quite a surprise for me, it did a lot better than I had anticipated. The unzip utility not only worked out that I had added 3 bytes to the first file in the set, but managed to reroute around that damage so that I could retrieve the subsequent files in the archive:&lt;br /&gt;&lt;blockquote&gt;ben@billpardy:~/tar_testground/zip_test/4$ unzip test.zip&lt;br /&gt;Archive:  test.zip&lt;br /&gt;warning [test.zip]:  3 extra bytes at beginning or within zipfile&lt;br /&gt; (attempting to process anyway)&lt;br /&gt;file #1:  bad zipfile offset (local header sig):  3&lt;br /&gt; (attempting to re-compensate)&lt;br /&gt; inflating: New document 1.2007_03_07_14_59_58.0 &lt;br /&gt; error:  invalid compressed data to inflate&lt;br /&gt;file #2:  bad zipfile offset (local header sig):  1243&lt;br /&gt; (attempting to re-compensate)&lt;br /&gt; inflating: New document 1.2007_09_07_14_18_02.0 &lt;br /&gt; inflating: New document 1.2007_11_16_12_21_20.0 &lt;br /&gt;&lt;/blockquote&gt;&lt;i&gt;Addition to central directory region:&lt;/i&gt; This one was, an anticipated, more devastating. A similar addition of three bytes to the middle of the region gave this result:&lt;br /&gt;&lt;blockquote&gt;ben@billpardy:~/tar_testground/zip_test/5$ unzip test.zip&lt;br /&gt;Archive:  test.zip&lt;br /&gt;warning [test.zip]:  3 extra bytes at beginning or within zipfile&lt;br /&gt; (attempting to process anyway)&lt;br /&gt;error [test.zip]:  reported length of central directory is&lt;br /&gt; -3 bytes too long (Atari STZip zipfile?  J.H.Holm ZIPSPLIT 1.1&lt;br /&gt; zipfile?).  Compensating...&lt;br /&gt; inflating: New document 1.2007_03_07_14_59_58.0 &lt;br /&gt;file #2:  bad zipfile offset (lseek):  -612261888&lt;br /&gt;&lt;/blockquote&gt;It rendered just a single file readable in the archive, but this was still a good result. It might be possible to remove the problem addition, given thorough knowledge of the zip format. However, the most important part is that it errors out, rather than silently failing.&lt;br /&gt;&lt;blockquote&gt;&lt;b&gt;Summary:&lt;/b&gt; the zip format looks quite robust as well, but pay attention to the error codes that the commandline utility (and hopefully, native unzip libraries) emit. Bitwise errors to files do not propagate to the other files, but do do widespread damage to the file in question, due to its compressed nature. It survives additive damage far better than the tar format, able to compensate and retrieve unaffected files.&lt;br /&gt;&lt;/blockquote&gt;&lt;a href=&quot;http://www.flickr.com/photos/oxfordrepo/3076903859/&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3203/3076903859_d9d954f782.jpg?v=0&quot; style=&quot;max-width: 800px;&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Tar.gz &#39;format&#39;:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;This can be seen as a combination of the two archive formats above. On the surface, it is a zip-style archive, but with a single file (the .tar file) and a single entry in the central directory. It shouldn&#39;t take long to realise then, that any change to the bulk of the tar.gz will cause havok thoughout the archive. In fact, a single byte substitution I made to a the file region in a test archive caused all byte sequences of &#39;it&#39; to turn into &#39;:/&#39;. This decimated the XML in the archive, as all files where affected in the same manner.&lt;br /&gt;&lt;blockquote&gt;&lt;b&gt;Summary:&lt;/b&gt; Combine the two archive types above but in a bad way. Errors affect the archive as a whole - damage to any part of the bulk of the archive can cause widespread damage and damage to the end of the file can cause it all to be unreadable.&lt;br /&gt;&lt;/blockquote&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/4516927983558625883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/4516927983558625883' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/4516927983558625883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/4516927983558625883'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2008/12/archive-file-resiliences.html' title='Archive file resiliences'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-280227876627147956</id><published>2008-11-14T08:50:00.000-08:00</published><updated>2008-11-14T08:53:24.716-08:00</updated><title type='text'>Beginning with RDF triplestores - a &amp;#39;survey&amp;#39;</title><content type='html'>&lt;div xmlns=&#39;http://www.w3.org/1999/xhtml&#39;&gt;Like last time, this was prompted by an email that eventually was passed to me. It was a call for opinion - &quot;&lt;tt&gt;&lt;font color=&#39;#737373&#39;&gt;we thought we&#39;d check first to see what software&lt;/font&gt;&lt;/tt&gt;&lt;tt&gt;&lt;font color=&#39;#737373&#39;&gt; either of you recommend or use for an RDF database.&lt;/font&gt;&lt;/tt&gt;&quot;&lt;br/&gt;&lt;br/&gt;It&#39;s a good question.&lt;br/&gt;&lt;br/&gt;In fact, it&#39;s a really great question, as searching for similar advice online results in very few opinions on the subject.&lt;br/&gt;&lt;br/&gt;But which one&#39;s are the best for novices? Which have the best learning curves? which has the easiest install or the shortest time between starting out and being able to query things?&lt;br/&gt;&lt;br/&gt;I&#39;ll try to pose as much as I can as a newcomer which won&#39;t be too hard :) Some of the comments will be my own, and some will be comments from others, but I&#39;ll try to be as honest as I can be to reflect new user expectation and experience and most importantly, developer-attention span. (See the end for some of my reasons for this approach.)&lt;br/&gt;&lt;br/&gt;&lt;em&gt;(Puts on newbie hat and enables PEBKAC mode.)&lt;/em&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Installable (local) triplestores&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Sesame&lt;/b&gt; - &lt;a href=&#39;http://www.openrdf.org/&#39;&gt;http://www.openrdf.org/&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;Simple menu on the left of the website, one called downloads. Great, I&#39;ll give that a whirl. &quot;Download &lt;a href=&#39;http://sourceforge.net/project/showfiles.php?group_id=46509&amp;amp;package_id=168413&#39;&gt;the latest Sesame 2.x release&lt;/a&gt;&quot; looks good to me. Hmm 5 differently named files... I&#39;ll grab the &#39;onejar&#39; file and try to run it. &quot;Failed to load Main-Class manifest attribute from openrdf-sesame-2.2.1-onejar.jar&quot;, okay... so back to the site to find out how to install this thing.&lt;br/&gt;&lt;br/&gt;No links for installation guide... on the &lt;a href=&#39;http://www.openrdf.org/documentation.jsp&#39;&gt;Documentation&lt;/a&gt; page, no link for installation instructions for the sesame 2.2.1 I downloaded, but there is &lt;a href=&#39;http://www.openrdf.org/doc/sesame2/users/&#39;&gt;Sesame 2 user documentation&lt;/a&gt; and &lt;a href=&#39;http://www.openrdf.org/doc/sesame2/system/&#39;&gt;Sesame 2 system documentation&lt;/a&gt;. Phew, after guessing that the user documentation might have the guide, I finally found the &lt;a href=&#39;http://www.openrdf.org/doc/sesame2/users/ch06.html&#39;&gt;installation guide&lt;/a&gt;  (system documentation was about the architecture, not how to administer the system as you might expect.)&lt;br/&gt;&lt;br/&gt;(Developer losing interest...)&lt;br/&gt;&lt;br/&gt;Ah, I see, I need the SDK. I wonder what that &#39;onejar&#39; was then... &quot;The deployment process is container-specific, please consult the&lt;br/&gt;			documentation for your container on how to deploy a web application. &quot; - right, okay... let&#39;s assume that I have a Java background and am not just a user wanting to hook into it from my language of choice, such as php, ruby, python, or dare I say it, javascript.&lt;br/&gt;&lt;br/&gt;(Only Java-friendly developers continue on)&lt;br/&gt;&lt;br/&gt;Right, got Tomcat, and put in the war file... right so, now I need to work out how to use a &lt;a href=&#39;http://www.openrdf.org/doc/sesame2/users/ch07.html#d0e354&#39;&gt;commandline&lt;/a&gt; console tool to set up a &#39;repository&#39;... does this use SVN or CVS then? Oh, it doesn&#39;t do anything unless I end the line with a period. I thought it had hung trying to connect!  &quot;Triple indexes [spoc,posc]&quot; Wha? Well, whatever that was, the test repository is created. Let&#39;s see what&#39;s at http://localhost:8080/openrdf-sesame then. &lt;br/&gt;&lt;br/&gt;&quot;You are currently accessing an OpenRDF Sesame server. This server is&lt;br/&gt;intended to be accessed by dedicated clients, using a specialized&lt;br/&gt;protocol. To access the information on this server through a browser,&lt;br/&gt;we recommend using the OpenRDF Workbench software.&quot;&lt;br/&gt;&lt;br/&gt;Bugger. Google for &quot;sesame clients&quot; then.&lt;br/&gt;&lt;ul&gt;&lt;li&gt;There is a Java client it seems, but it seems to need a lot to get going. Oh, and useful if my application is in Java or in a JVM (jRuby, jython)&lt;br/&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&#39;http://jeenbroekstra.blogspot.com/2008/09/sesame-2-desktop-client.html&#39;&gt;http://jeenbroekstra.blogspot.com/2008/09/sesame-2-desktop-client.html&lt;/a&gt; .Net GUI... not so useful for programmatic stuff&lt;/li&gt;&lt;li&gt;...&lt;/li&gt;&lt;/ul&gt;I&#39;ve pretty much given up at this point. If I knew I needed to use a triplestore then I might have persisted, but if I was just investigating it? I would&#39;ve probably given up earlier.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Mulgara&lt;/b&gt; - &lt;a href=&#39;http://www.mulgara.org/&#39;&gt;http://www.mulgara.org/&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;Nice, they&#39;ve given the frontpage some style, not too keen on orange, but the effort makes it look professional. &quot;&lt;em&gt;Mulgara&lt;/em&gt; is a scalable RDF database written entirely in &lt;strong&gt;&lt;a class=&#39;styleBlack&#39; href=&#39;http://java.com/&#39;&gt;Java&lt;/a&gt;&lt;/strong&gt;.&quot; -&amp;gt; Great, I found what I am looking for, and it warns me it needs Java. &quot;DOWNLOAD NOW&quot; - that&#39;s pretty clear. *click*&lt;br/&gt;&lt;br/&gt;Hmm, where&#39;s the style gone? Lots of download options, but thankfully one is marked by &quot;These released binaries are all that are required for most applications.&quot; so I&#39;ll grab &lt;a href=&#39;http://www.mulgara.org/files/v2.0.6/mulgara-2.0.6-bin.tar.gz&#39;&gt;those&lt;/a&gt;. 25Mb? Wow...&lt;br/&gt;&lt;br/&gt;Okay, it&#39;s downloaded and unpacked now. Let&#39;s see what we&#39;ve got - a &#39;dist/&#39; directory and two jars. Well, I guess I should try to run one (wonder what the licence is, where&#39;s the README?)&lt;br/&gt;&lt;blockquote&gt;&lt;em&gt;Mulgara Semantic Store Version 2.0.6 (Build 2.0.6.local) INFO [main] (EmbeddedMulgaraServer.java:715) - RMI Registry started automatically on port 10990 [main] INFO org.mulgara.server.EmbeddedMulgaraServer  - RMI Registry started automatically on port 1099 INFO [main] (EmbeddedMulgaraServer.java:738) - java.security.policy set to jar:file:/home/ben/Desktop/apache-tomcat-6.0.18/mulgara-2.0.6/dist/mulgara-2.0.6.jar!/conf/mulgara-rmi.policy3 [main] INFO org.mulgara.server.EmbeddedMulgaraServer  - java.security.policy set to jar:file:/home/ben/Desktop/apache-tomcat-6.0.18/mulgara-2.0.6/dist/mulgara-2.0.6.jar!/conf/mulgara-rmi.policy2008-11-14 14:06:39,899 INFO  Database - Host name aliases for this server are: [billpardy, localhost, 127.0.0.1]&lt;/em&gt;&lt;br/&gt;&lt;/blockquote&gt;Well, I guess something has started... back to the site, there is a documentation page and a wiki. A quick view of the official documentation has just confused me, is &lt;a href=&#39;http://docs.mulgara.org/&#39;&gt;this an external site&lt;/a&gt;? No easy link to something like &#39;getting started&#39; or tutorials. I&#39;ve heard of SPARQL, what&#39;s iTQL? nevermind, let&#39;s see if the &lt;a href=&#39;http://www.mulgara.org/trac/wiki&#39;&gt;wiki&lt;/a&gt; is more helpful.&lt;br/&gt;&lt;br/&gt;Let&#39;s try &#39;&lt;a href=&#39;http://www.mulgara.org/trac/wiki/Docs&#39;&gt;Documentation&lt;/a&gt;&#39; - sweet, first link looks like what I want - &lt;a href=&#39;http://www.mulgara.org/trac/wiki/WebUI&#39; class=&#39;wiki&#39;&gt;Web User Interface&lt;/a&gt;.&lt;br/&gt;&lt;blockquote&gt;A default configuration for a standalone Mulgara server runs a set of&lt;br/&gt;web services, including the Web User Interface. The standard&lt;br/&gt;configuration puts uses port 8080, so the web services can be seen by&lt;br/&gt;pointing a browser on the server running Mulgara to &lt;a href=&#39;http://localhost:8080/&#39; class=&#39;ext-link&#39;&gt;&lt;span class=&#39;icon&#39;&gt;http://localhost:8080/&lt;/span&gt;&lt;/a&gt;.&lt;br/&gt;&lt;/blockquote&gt;Ooo cool. *click* &lt;br/&gt;&lt;blockquote&gt;&lt;h2&gt;Available Services&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&#39;http://localhost:8080/sparql&#39;&gt;SPARQL HTTP Service&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&#39;http://localhost:8080/webui&#39;&gt;User Interface&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&#39;http://localhost:8080/webservices&#39;&gt;Web Services&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&#39;http://localhost:8080/tql&#39;&gt;TQL HTTP Service&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;br/&gt;SPARQL, I&#39;ve heard of that. *click* &lt;br/&gt;&lt;blockquote&gt;&lt;h2&gt;HTTP ERROR: 400&lt;/h2&gt;&lt;pre&gt;Query must be supplied&lt;/pre&gt;&lt;p&gt;RequestURI=/sparql/&lt;/p&gt;&lt;p&gt;&lt;i&gt;&lt;small&gt;&lt;a href=&#39;http://jetty.mortbay.org/&#39;&gt;Powered by Jetty://&lt;/a&gt;&lt;/small&gt;&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;I guess that&#39;s the SPARQL api, good to know, but the frontpage could&#39;ve warned me a little. Ah, second link is to the User Interface.&lt;br/&gt;&lt;br/&gt;Good, I can use a drop down to look at lots of example queries, nice. Don&#39;t understand most of them at the moment, but it&#39;s definitely comforting to have examples. They look nothing like SPARQL though... wonder what it is? I&#39;m sure it does SPARQL... was I wrong?&lt;br/&gt;&lt;br/&gt;Quick poke at the HTML shows that it is just POSTing the query text to webui/ExecuteQuery. Looks straightforward to start hacking against too, but probably should password protect this somehow! I wonder how that is done... documentation mentions a &#39;&lt;tt&gt;java.security.policy&#39;&lt;/tt&gt; field:&lt;tt&gt;&lt;br/&gt;&lt;br/&gt;java.security.policy&lt;/tt&gt;&lt;i&gt;&lt;br/&gt;string: URL&lt;/i&gt;: The URL for the security policy file to use.&lt;br/&gt;Default: jar:file:/jar_path!/conf/mulgara-rmi.policy &lt;br/&gt;&lt;blockquote&gt;&lt;p/&gt;&lt;/blockquote&gt;Kinda stumped... will investigate that later, but at least there&#39;s hope. Just be firing off the example queries though shows me stuff, so I&#39;ve got something to work with at least.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Jena&lt;/b&gt; - &lt;a href=&#39;http://jena.sourceforge.net/&#39;&gt;http://jena.sourceforge.net/&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;Front page is pretty clear, even if I don&#39;t understand what all those acronyms are. &lt;a href=&#39;http://jena.sourceforge.net/downloads.html&#39;&gt;downloads&lt;/a&gt; link takes me to a page with an obvious download link, good. (Oh, and sourceforge, you suck. How many frikkin mirrors do I have to try to get this file?)&lt;br/&gt;&lt;br/&gt;Have to put Jena on pause while Sourceforge sorts its life out.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;ARC2&lt;/b&gt; - http://arc.semsol.org/&lt;br/&gt;&lt;br/&gt;Frontpage: &quot;Easy RDF and SPARQL for LAMP systems&quot; Nice, I know of LAMP and I particularly like the word Easy. Let&#39;s see... &lt;a href=&#39;http://arc.semsol.org/download&#39;&gt;Download&lt;/a&gt; is easy to find, and tells me straight away I need PHP 4.3+ and MySQL 4.0.4+ *check* Right, now how do I enable PHP for apache again?... Ah, it helps if I install it first... Okay, done. Dropping the folder into my web space... Hmm nothing does anything. From the documentation, it does look like it is geared to providing a PHP library framework for working with its triplestore and RDF. Hang on, &lt;a href=&#39;http://arc.semsol.org/docs/v2/endpoint&#39;&gt;SPARQL Endpoint Setup&lt;/a&gt; looks like what I want. It wants a database, okay... done, bit of a hassle though.&lt;br/&gt;&lt;br/&gt;Hmm, all I get is &quot;&lt;b&gt;Fatal error&lt;/b&gt;:  Call to undefined function mysql_connect() in &lt;b&gt;/********/arc2/store/ARC2_Store.php&lt;/b&gt; on line &lt;b&gt;53&quot;&lt;br/&gt;&lt;/b&gt;&lt;br/&gt;Of course, install php libraries to access mysql (PEBKAC)... done and I also realise I need to set up the store, like the example in &quot;&lt;a href=&#39;http://arc.semsol.org/docs/v2/getting_started&#39;&gt;Getting Started&lt;/a&gt;&quot;... done (with &lt;a href=&#39;http://pastebin.com/f2ca379e7&#39;&gt;this&lt;/a&gt;) and what does the index page now look like?&lt;br/&gt;&lt;br/&gt;&lt;img src=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNeI5IAK7eEhZs56No-MtI6kUtQCOFPC0rH1EcIIskZNLPFAbdmZg9RWt37NQrOAslhOdSdiIZZs0uOpV4tOReke5C23YrmVtxVVHarDLtzMnOMe9ravP1h5GbxHDrlmOlXuqaEX-WpKs/?imgmax=800&#39; style=&#39;max-width: 800px;&#39;/&gt;&lt;br/&gt;&lt;br/&gt;Yay! there&#39;s like SPARQL and stuff... I guess &#39;load&#39; and &#39;insert&#39; will help me stick stuff in, and &#39;select&#39; looks familiar... Well, it seems to be working at least.&lt;br/&gt;&lt;br/&gt;Unfortunately, it looks like the Jena download from sourceforge is in a world of FAIL for now. Maybe I&#39;ll look at it next time?&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Triplestores in the cloud&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;Talis Platform - &lt;a href=&#39;http://www.talis.com/platform/&#39;&gt;http://www.talis.com/platform/&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;From the frontpage - &quot;&lt;i&gt;Developers using the Platform can spend more of their time building&lt;br /&gt;extraordinary applications and less of their time worrying about how&lt;br /&gt;they will scale their data storage.&lt;/i&gt;&quot; - pretty much want I wanted to hear, so how do I get to play with it?&lt;br/&gt;&lt;br/&gt;There is a &lt;a title=&#39;Get involved&#39; href=&#39;http://www.talis.com/platform/get_involved/index.shtml&#39;&gt;Get involved&lt;/a&gt; link on the left, which rapidly leads me to see the section: &quot;Develop, play and try out&quot; - &lt;a href=&#39;http://n2.talis.com/wiki/Main_Page&#39;&gt;n&lt;sup&gt;2&lt;/sup&gt; developer community &lt;/a&gt; seems to be where it wants me to go. &lt;br/&gt;&lt;br/&gt;Lots of links on the frontpage, takes a few seconds to spot: &quot;&lt;a title=&#39;Join&#39; href=&#39;http://n2.talis.com/wiki/Join&#39;&gt;Join&lt;/a&gt; - join the n² community to get free developer stores and online support&quot; - free, nice word that. So, I just have to email someone? Okay, I can live with that.&lt;br/&gt;&lt;br/&gt;Documentation seems good, lots of choices though, a little hard to spot a single thread to follow to get up to speed, but &lt;a title=&#39;Guides and Tutorials&#39; href=&#39;http://n2.talis.com/wiki/Guides_and_Tutorials&#39;&gt;Guides and Tutorials&lt;/a&gt; looks right to get going with. The &lt;a href=&#39;http://n2.talis.com/wiki/Kniblet_Tutorial&#39;&gt;Kniblet tutorial&lt;/a&gt; (whatever a kniblet is) looks the most beginnerish, and it&#39;s also very PHP focussed, which is either a good thing or a bad thing depending on the user :)&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Commercial triplestores&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Openlink Virtuoso&lt;/b&gt; - &lt;a href=&#39;http://virtuoso.openlinksw.com/&#39;&gt;http://virtuoso.openlinksw.com/&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;Okay, I tried the &lt;a href=&#39;http://download.openlinksw.com/download/&#39;&gt;Download&lt;/a&gt; link, but I am pretty confused by what I&#39;m greeted with: &lt;br/&gt;&lt;br/&gt;&lt;img src=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_D-wyVtVty9qsvu6fW0uisFn0iucbbJVDr1DBfO_J_IzwuVMM30tliATyf0XSzwfydxS7e_Cv_ZKt5TchOqyg97vdO9EmEQ3xTePstxOcxllATP6qqhS9t4Bg51mAt6UimQytcmFBXKQ/?imgmax=800&#39; style=&#39;max-width: 800px;&#39;/&gt;&lt;br/&gt;&lt;br/&gt;Not sure what one to pick just to try it out, it&#39;s late in the day, and my tolerance for all things installable has ended.&lt;br/&gt;&lt;br/&gt;-----------------------------------------&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Why take the http/web-centric, newbie approach to looking at these?&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;&lt;i&gt;Answer: &lt;/i&gt;In part, I am taking this approach because I have a deep belief that it&lt;br/&gt;was only after relational DBs became commoditised - &quot;You want fries&lt;br/&gt;with you MySQL database?&quot; - that the dynamic web kicked off. If we want&lt;br/&gt;the semantic web to kick off, we need to commoditise it or at least, make&lt;br/&gt;it very easy for developers to get started. And I mean &lt;b&gt;&lt;i&gt;EASY&lt;/i&gt;&lt;/b&gt;. A query that I want answered is: &quot;Is there something that fits: &#39;apt-get install&lt;br/&gt;triplestore; r = store(&#39;localhost&#39;), r.add(rdf), r.query(blah)&#39;? &quot; &lt;br/&gt;&lt;br/&gt;(I am particularly interested to see what happens when &lt;a href=&#39;http://tom.opiumfield.com/&#39;&gt;Tom Morris&lt;/a&gt;&#39;s work on &lt;a href=&#39;http://github.com/tommorris/reddy/tree/master&#39;&gt;Reddy&lt;/a&gt; collides with ActiveRecord or activerdf...)&lt;br/&gt;&lt;br/&gt;&lt;b&gt;NB &lt;/b&gt;I&#39;ve short circuited the discovery of software homepages - Imagine&lt;br/&gt;I&#39;ve seen projects stating that they use &quot;XXXXX as a triplestore&quot;. I know&lt;br/&gt;this will likely mean I&#39;ve compared apples to oranges, but as a newbie, how&lt;br/&gt;would I be expected to know this? &quot;Powered by the Talis Platform&quot; and&lt;br/&gt;&quot;Powered by Jena&quot; seem pretty similar on the surface.)&lt;br/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/280227876627147956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/280227876627147956' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/280227876627147956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/280227876627147956'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2008/11/beginning-with-rdf-triplestores.html' title='Beginning with RDF triplestores - a &amp;#39;survey&amp;#39;'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNeI5IAK7eEhZs56No-MtI6kUtQCOFPC0rH1EcIIskZNLPFAbdmZg9RWt37NQrOAslhOdSdiIZZs0uOpV4tOReke5C23YrmVtxVVHarDLtzMnOMe9ravP1h5GbxHDrlmOlXuqaEX-WpKs/s72-c?imgmax=800" height="72" width="72"/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-7367532608884117842</id><published>2008-11-13T06:30:00.000-08:00</published><updated>2008-11-13T06:35:05.914-08:00</updated><title type='text'>A Fedora/Solr Digital Library for Oxford&amp;#39;s &amp;#39;Forced Migration Online&amp;#39;</title><content type='html'>&lt;div xmlns=&#39;http://www.w3.org/1999/xhtml&#39;&gt;(mods:subtitle - Slightly more technical follow-up to the &lt;a href=&#39;http://expertvoices.nsdl.org/hatcheck/2008/11/06/a-fedorasolr-digital-library-for-oxfords-forced-migration-online/&#39;&gt;Fedora Hatcheck piece&lt;/a&gt;.)&lt;br/&gt;&lt;br/&gt;As I have been prompted via email by Phil Cryer (of the &lt;a href=&#39;http://mobot.org/&#39;&gt;Missouri Botanical Garden&lt;/a&gt;) to talk more about how this technically works, I thought it would be best to make it a written post, rather than the more limited email response.&lt;br/&gt;&lt;br/&gt;&lt;big&gt;Background&lt;/big&gt;&lt;br/&gt;&lt;br/&gt;Forced Migration Online (FMO) had a proprietary system, supporting their document needs. It was originally designed for newpaper holdings and applied that model to encoding the mostly paginated documents that FMO held - such that each part was broken up into paragraphs of text, images and the location of all these parts on a page. It even encoded (in its own format) the location of the words on the page when it OCR&#39;d the documents, making per-word higlighting possible. Which is nice.&lt;br/&gt;&lt;br/&gt;However, the backend that powered this was over-priced, and FMO wanted to move to a more open, sustainable platform.&lt;br/&gt;&lt;br/&gt;&lt;big&gt;Enter the DAMS&lt;/big&gt;&lt;br/&gt;&lt;br/&gt;(DAMS = Digital Asset Management System)&lt;br/&gt;&lt;br/&gt;I have been doing work on trying to make a service out of a base of fedora-commons and additional &#39;plugin&#39; services, such as the wonderful Apache Solr and the useful eXist XML db. The end aim is for departments/users/whoever to requisition a &#39;store&#39; with a certain quality of service (solr attached, 50Gb+ etc) but this is not yet an automated process.&lt;br/&gt;&lt;br/&gt;The focus for the store is a very clear separation between storage, management, indexing services and distribution - Normal filesystems, or Sun Honeycomb are the storage, Fedora-commons provides the management + CRUD, solr, eXist, mulgara, sesame, and couchDB can provide potential index and query services, and distribution is handed pragmatically, caching outgoing and mirroring where necessary.&lt;br/&gt;&lt;br/&gt;&lt;big&gt;The FMO &#39;store&#39;&lt;/big&gt;&lt;br/&gt;&lt;br/&gt;From discussions with FMO, and examining the information they held and the way they wished to make use of it, a simple Fedora/Solr store seemed to fufill what they wanted: a persistant store of items with attachments and the ability to search the metadata and retrieve results.&lt;br/&gt;&lt;br/&gt;&lt;big&gt;Bring in the consultants&lt;/big&gt;&lt;br/&gt;&lt;br/&gt;FMO hired Aptivate to do the migration of their data from the proprietary system, in its custom format, to a Fedora/Solr store and trying as much as possible to retain the functionality they had.&lt;br/&gt;&lt;br/&gt;Some points that I think it is important to impress on people here:&lt;br/&gt;&lt;ul&gt;&lt;li&gt;In general, software engineer consultants don&#39;t understand METS or FOXML.&lt;/li&gt;&lt;li&gt;They *really* don&#39;t understand the point of disseminators.&lt;br/&gt;&lt;/li&gt;&lt;li&gt;Having to teach software engineer consultants to do METS/FOXML/bDef&#39;s etc is likely an arduous and costly task.&lt;/li&gt;&lt;li&gt;Consultants add lots of money to do things their team don&#39;t already have the experience to do.&lt;/li&gt;&lt;/ul&gt;So, my conclusion was to not make these things part of the development at all to the extent that I might even have forgotten to mention these things to them except in passing. I helped them install their own local store and helped them with the various interfaces and gotchas of the two software packages. By showing them how I use Fedora and Solr in ora.ouls.ox.ac.uk, they were able to hit the ground running.&lt;br/&gt;&lt;br/&gt;They began by using the REST interface to Fedora and the RESTful interface to Solr. By having them begin by using the simple put/get REST interface to Fedora, they could concentrate on getting used to the nature of Fedora as an objectstore. I think they moved to use the SOAP interface as it better suited their Java background, although I cannot be certain as it wasn&#39;t an issue that came up.&lt;br/&gt;&lt;br/&gt;Once they had developed the migration scripts to their satisfaction, they asked me to give them a store, which I did (but due to hardware and stupid support issues here I am afraid to say I held them up on this.) They fired off their scripts, moved all the content into the fedora with a straightforward layout per object (pdf, metadata, fulltext and thumbnail) The metadata is - from what I can see - the same XML metadata as before - very MARCXML in nature, with &#39;Application_Info&#39; elements having types like &#39;bl:DC.Title&#39;. If necessary, we will strip out the dublin core metadata and put what we can into the DC datastream, but that&#39;s not of particular interest to FMO right now. &lt;br/&gt;&lt;br/&gt;&lt;big&gt;Fedora/Solr notes&lt;/big&gt;&lt;br/&gt;&lt;br/&gt;As for the link between Solr and Fedora? This is very loosely coupled, such that they are running in the same Tomcat container for convenience, but aren&#39;t linked in a hard way. &lt;br/&gt;&lt;br/&gt;I&#39;ve looked at GSearch, which is great for a homogenous collection of items, such that they can be acted on by the same XSLT to produce a suitable record for Solr, but as the metadata was a complete unknown for this project, it wasn&#39;t too suitable.&lt;br/&gt;&lt;br/&gt;Currently, they have one main route into the fedora store, and so, it isn&#39;t hard to simply reindex an item after a change is made, especially for services such as Solr or eXist, which expect to have things change incrementally. I am looking at services such as ActiveMQ for scheduling these index tasks, but more and more I am starting to favour RabbitMQ which seems to be more useful, while retaining the scalability and very robust nature.&lt;br/&gt;&lt;br/&gt;Sending an update to Solr is as simple as an HTTP POST to its /update service, consisting of a XML or JSON packet like &quot;&lt;add&gt;&lt;field name=&#39;id&#39;&gt;changeme:1&lt;/field&gt;&lt;field name=&#39;author&#39;&gt;John Smith&lt;/field&gt;....&lt;/add&gt;&quot; - it uses a transactional model, such that you can push all the changes and additions into the live index via a commit call, without taking the index offline. To query Solr, all manner of clients exist, and it is built to be very simple to interact with, handling facet queries, filtering, ordering and can deliver the results in XML, JSON, PHP or Python directly. It can even do a XSLT transform of the results on the way out, leading to a trivial way to support OpenSearch, Atom feeds and even HTML blocks for embedding in other sites.&lt;br/&gt;&lt;br/&gt;Likewise, to change a PDF in Fedora can be done by a HTTP POST as well. Does it need to be more complicated?&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Last, but not least, a project to watch closely:&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;The &lt;a href=&#39;http://ice.usq.edu.au/projects/fascinator/trac&#39;&gt;Fascinator project&lt;/a&gt;, funded by  &lt;a class=&#39;ext-link&#39; href=&#39;http://www.arrow.edu.au/&#39;&gt;&lt;span class=&#39;icon&#39;&gt;ARROW&lt;/span&gt;&lt;/a&gt;, as part of their mini project scheme, is an Apache &lt;a class=&#39;ext-link&#39; href=&#39;http://lucene.apache.org/solr/&#39;&gt;&lt;span class=&#39;icon&#39;&gt;Solr&lt;/span&gt;&lt;/a&gt; front end to the &lt;a class=&#39;ext-link&#39; href=&#39;http://www.fedora-commons.org/&#39;&gt;&lt;span class=&#39;icon&#39;&gt;Fedora commons&lt;/span&gt;&lt;/a&gt; repository. The goal of the project is to create a simple interface to Fedora that uses a single technology – that’s Solr – to handle all browsing, searching and security. Well worth a look, as it seeks to turn this Fedora/Solr pairing truly into an appliance, with a simple installer and handling the linkage between the two.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/7367532608884117842/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/7367532608884117842' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/7367532608884117842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/7367532608884117842'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2008/11/fedorasolr-digital-library-for-oxford.html' title='A Fedora/Solr Digital Library for Oxford&amp;#39;s &amp;#39;Forced Migration Online&amp;#39;'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-4505259570218961302</id><published>2008-11-13T03:17:00.000-08:00</published><updated>2008-11-13T03:19:28.268-08:00</updated><title type='text'>OCLC - viral licence being added to WorldCat data</title><content type='html'>&lt;div xmlns=&#39;http://www.w3.org/1999/xhtml&#39;&gt;&lt;b&gt;Very short post on this, as I just wanted to highlight a fantastic piece written by &lt;a href=&#39;http://dynamicorange.com/2008/11/06/oclc-record-usage-copyright-contracts-and-the-law/&#39;&gt;Rob Styles about OCLC&#39;s policy changes to WorldCat&lt;/a&gt;&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;In a nutshell, it seems that OCLC’s policy changes have the intention to restrict the usage of the data in order to prevent competing services from appearing. Competing services such as &lt;a href=&#39;http://www.librarything.com/&#39;&gt;LibraryThing&lt;/a&gt; and the &lt;a href=&#39;http://www.archive.org/&#39;&gt;Internet Archive&lt;/a&gt;&#39;s &lt;a href=&#39;http://openlibrary.org/&#39;&gt;Open Library&lt;/a&gt; but unfortunately, it seems that the changes will also impinge on the rights of users to collate citation lists in software such as Zotero, Endnote and others. Read Rob&#39;s post for a well researched view on the changes.&lt;br/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/4505259570218961302/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/4505259570218961302' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/4505259570218961302'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/4505259570218961302'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2008/11/oclc-viral-licence-being-added-to.html' title='OCLC - viral licence being added to WorldCat data'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-6970851823691270308</id><published>2008-11-12T07:40:00.000-08:00</published><updated>2008-11-12T07:42:40.838-08:00</updated><title type='text'>Useful, interesting, inspiring technology/software that is out there that you might not know about.</title><content type='html'>&lt;div xmlns=&#39;http://www.w3.org/1999/xhtml&#39;&gt;(I guess this is more like a filtered link list, but with added comments in case you don&#39;t feel like following the links to find out what it&#39;s all about.. A mix of old, but solid links and a load of tabs that I really should close ;))&lt;br/&gt;&lt;ol&gt;&lt;li&gt;Tahoe - &lt;a href=&#39;http://allmydata.org/%7Ewarner/pycon-tahoe.html&#39;&gt;http://allmydata.org/~warner/pycon-tahoe.html&lt;/a&gt;&lt;blockquote&gt;The &quot;Tahoe&quot; project is a &lt;b&gt;distributed filesystem&lt;/b&gt;, which &lt;b&gt;safely stores files on multiple machines to protect against hardware failures&lt;/b&gt;. Cryptographic tools are used to ensure integrity and confidentiality, and a decentralized architecture minimizes single points of failure. Files can be accessed through a web interface or native system calls (via FUSE). Fine-grained sharing allows individual files or directories to be delegated by passing short URI-like strings through email. Tahoe grids are easy to set up, and can be used by a handful of friends or by a large company for thousands of customers.&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;CouchDB - &lt;a href=&#39;http://incubator.apache.org/couchdb/&#39;&gt;http://incubator.apache.org/couchdb/&lt;/a&gt;&lt;blockquote&gt;&lt;p&gt;Apache CouchDB is a &lt;b&gt;distributed, fault-tolerant and schema-free document-oriented database accessible via a RESTful HTTP/JSON API&lt;/b&gt;. Among other features, it provides robust, incremental replication with bi-directional conflict detection and resolution, and is queryable and indexable using a table-oriented view engine with JavaScript acting as the default view definition language.&lt;/p&gt;&lt;p&gt;CouchDB is written in &lt;a href=&#39;http://erlang.org/&#39;&gt;Erlang&lt;/a&gt;, but can be easily accessed from any environment that provides means to make HTTP requests. There are a multitude of third-party client libraries that make this even easier for a variety of programming languages and environments.&lt;/p&gt;&lt;/blockquote&gt;  &lt;/li&gt;&lt;li&gt;Yahoo Term Extractor - &lt;a href=&#39;http://developer.yahoo.com/search/content/V1/termExtraction.html&#39;&gt;http://developer.yahoo.com/search/content/V1/termExtraction.html&lt;/a&gt;&lt;blockquote&gt;The Term Extraction Web Service &lt;b&gt;provides a list of significant words or phrases extracted from a larger content.&lt;/b&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Kea term extractor (SKOS enabled) - &lt;a href=&#39;http://www.nzdl.org/Kea/&#39;&gt;http://www.nzdl.org/Kea/&lt;/a&gt;&lt;blockquote&gt;KEA is &lt;b&gt;an algorithm for extracting keyphrases from text documents.&lt;/b&gt;         It can be either used for &lt;b&gt;free indexing&lt;/b&gt; or for &lt;b&gt;indexing with         a controlled vocabulary&lt;/b&gt;.&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Piwik - &lt;a href=&#39;http://piwik.org/&#39;&gt;http://piwik.org/&lt;/a&gt;&lt;blockquote&gt;&lt;p&gt;piwik is an open source (GPL license) &lt;b&gt;web analytics software&lt;/b&gt;. It gives interesting reports on your website visitors, your popular pages, the search engines keywords they used, the language they speak… and so much more. &lt;b&gt;piwik aims to be an open source alternative to &lt;a target=&#39;_blank&#39; href=&#39;http://www.google.com/analytics&#39; rel=&#39;nofollow&#39;&gt;Google Analytics&lt;/a&gt;.&lt;/b&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;RabbitMQ - &lt;a href=&#39;http://www.rabbitmq.com/&#39;&gt;http://www.rabbitmq.com/&lt;/a&gt;&lt;blockquote&gt;RabbitMQ is an Open (Mozilla licenced) implementation of &lt;a href=&#39;http://www.rabbitmq.com/faq.html#what-is-amqp&#39;&gt;AMQP&lt;/a&gt;, the emerging standard for &lt;b&gt;high performance enterprise messaging&lt;/b&gt;. Built on top of the Open Telecom Platform (OTP). OTP is used by multiple telecommunications companies 	      to manage switching exchanges for voice calls, VoIP and now video.  These systems are designed to never go down and to handle truly vast user loads.  And because the systems cannot be taken offline, they have to be very flexible, for instance it must be possible to &#39;hot deploy&#39; features and fixes on the fly whilst managing a consistent user SLA.&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Talis Platform - &lt;a href=&#39;http://n2.talis.com/wiki/Main_Page&#39;&gt;http://n2.talis.com/wiki/Main_Page&lt;/a&gt;&lt;blockquote&gt;The Talis Platform provides &lt;b&gt;solid infrastructure for building Semantic Web applications&lt;/b&gt;. Delivered as Software as a Service (SaaS), it dramatically reduces the complexity and cost of storing, indexing, searching and augmenting data. It enables applications to be brought to market rapidly with a smaller initial investment. Developers using the Platform can spend more of their time building extraordinary applications and less of their time worrying about how they will scale their data storage.&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;The Fascinator - &lt;a href=&#39;http://ice.usq.edu.au/projects/fascinator/trac&#39;&gt;http://ice.usq.edu.au/projects/fascinator/trac&lt;/a&gt;&lt;blockquote&gt;The goal of the project is to create &lt;b&gt;a simple interface to Fedora that uses a single technology – that’s Solr – to handle all browsing, searching and security&lt;/b&gt;. This contrasts with solutions that use RDF for browsing by ‘collection’, XACML for security and a text indexer for fulltext search, and in some cases relational database tables as well. We wanted to see if taking out some of these layers makes for a fast application which is easy to configure. So far so good.&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;RDFQuery - &lt;a href=&#39;http://code.google.com/p/rdfquery/&#39;&gt;http://code.google.com/p/rdfquery/&lt;/a&gt;&lt;blockquote&gt;&lt;p&gt;&lt;a name=&#39;Introduction&#39;&gt;This project is for plugins for &lt;/a&gt;&lt;a rel=&#39;nofollow&#39; href=&#39;http://jquery.com/&#39;&gt;jQuery&lt;/a&gt; that enable you to &lt;b&gt;generate and manipulate &lt;a rel=&#39;nofollow&#39; href=&#39;http://www.w3.org/TR/REC-rdf-syntax/&#39;&gt;RDF&lt;/a&gt; within web pages [in javascript]&lt;/b&gt;. There are two main aims of this project: 1) to &lt;b&gt;provide a way of querying and manipulating RDF triples within Javascript&lt;/b&gt; that is as intuitive as jQuery is for querying and manipulating a DOM, and 2) to &lt;b&gt;provide a way of gleaning RDF from elements within a web page&lt;/b&gt;, whether that RDF is represented as &lt;a rel=&#39;nofollow&#39; href=&#39;http://www.w3.org/TR/xhtml-rdfa-primer/&#39;&gt;RDFa&lt;/a&gt; or with a &lt;a rel=&#39;nofollow&#39; href=&#39;http://microformats.org/&#39;&gt;microformat&lt;/a&gt;. &lt;/p&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;eXist - &lt;a href=&#39;http://exist.sourceforge.net/&#39;&gt;http://exist.sourceforge.net/ &lt;br/&gt;&lt;/a&gt;&lt;blockquote&gt;eXist-db is an open source database management system entirely built on XML                technology. &lt;b&gt;It stores XML data according to the XML data model and features                efficient, &lt;a href=&#39;http://www.w3.org/TR/xquery/&#39;&gt;index-based XQuery&lt;/a&gt;&lt;/b&gt; processing. It supports: &lt;br/&gt;&lt;/blockquote&gt;&lt;blockquote&gt; &lt;ul&gt;&lt;li&gt; &lt;a href=&#39;http://www.w3.org/TR/xquery/&#39;&gt;XQuery 1.0&lt;/a&gt; / &lt;a href=&#39;http://www.w3.org/TR/xpath20/&#39;&gt;XPath 2.0&lt;/a&gt; &lt;/li&gt;&lt;li&gt; &lt;a href=&#39;http://www.w3.org/TR/xslt&#39;&gt;XSLT 1.0&lt;/a&gt; (using Apache Xalan) or &lt;a href=&#39;http://www.w3.org/TR/xslt20&#39;&gt;XSLT 2.0&lt;/a&gt; (optional using &lt;a href=&#39;http://saxon.sourceforge.net/&#39;&gt;Saxon&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;HTTP interfaces: &lt;a href=&#39;http://en.wikipedia.org/wiki/Representational_State_Transfer&#39;&gt;REST&lt;/a&gt;, &lt;a href=&#39;http://www.webdav.org/&#39;&gt;WebDAV&lt;/a&gt;, &lt;a href=&#39;http://www.w3.org/TR/soap/&#39;&gt;SOAP&lt;/a&gt;, &lt;a href=&#39;http://en.wikipedia.org/wiki/XML-RPC&#39;&gt;XMLRPC&lt;/a&gt;, &lt;a href=&#39;http://en.wikipedia.org/wiki/Atom_%28standard%29&#39;&gt;Atom Publishing                            Protocol&lt;/a&gt; &lt;/li&gt;&lt;li&gt;XML database specific: XMLDB, XQJ/&lt;a href=&#39;http://jcp.org/en/jsr/detail?id=225&#39;&gt;JSR-225&lt;/a&gt; (under development), &lt;a href=&#39;http://xmldb-org.sourceforge.net/xupdate/&#39;&gt;XUpdate&lt;/a&gt;, XQuery &lt;a href=&#39;http://exist.sourceforge.net/update_ext.html&#39;&gt;update extensions&lt;/a&gt; (to be aligned with the new &lt;a href=&#39;http://www.w3.org/TR/xquery-update-10/&#39;&gt;XQuery Update Facility 1.0&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt; &lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Evergreen - &lt;a href=&#39;http://evergreen-ils.org/&#39;&gt;http://evergreen-ils.org/&lt;/a&gt;&lt;blockquote&gt;Evergreen is an enterprise-class [Open Source] &lt;strong&gt;library automation system&lt;/strong&gt;&lt;br /&gt;that helps library patrons find library materials, and helps libraries&lt;br /&gt;manage, catalog, and circulate those materials, no matter how large or&lt;br /&gt;complex the libraries.&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Apache Solr - &lt;a href=&#39;http://lucene.apache.org/solr/&#39;&gt;http://lucene.apache.org/solr/ &lt;br/&gt;&lt;/a&gt;&lt;blockquote&gt;Solr is an &lt;b&gt;open source enterprise search server based on the&lt;br /&gt;        &lt;a href=&#39;http://lucene.apache.org/java/&#39;&gt;Lucene Java&lt;/a&gt; search library&lt;/b&gt;, with XML/HTTP and JSON APIs,&lt;br /&gt;        hit highlighting, faceted search, caching, replication, a web administration interface and many more features.&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;GATE - &lt;a href=&#39;http://gate.ac.uk/&#39;&gt;http://gate.ac.uk/&lt;/a&gt;&lt;blockquote&gt;GATE is a leading toolkit for text-mining. It bills itself as &quot;the &lt;a href=&#39;http://eclipse.org/&#39;&gt;Eclipse&lt;/a&gt; of Natural Language Engineering,&lt;br /&gt;the &lt;a href=&#39;http://jakarta.apache.org/lucene/&#39;&gt;Lucene&lt;/a&gt; of &lt;a href=&#39;http://gate.ac.uk/ie/index.html&#39;&gt;Information Extraction&quot;&lt;/a&gt; [NB I have yet to use this, but it has the kind of provenance and userbase that makes me feel okay about sharing this link]&lt;br/&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Ubuntu JeOS - &lt;a href=&#39;http://www.ubuntu.com/products/whatisubuntu/serveredition/jeos&#39;&gt;http://www.ubuntu.com/products/whatisubuntu/serveredition/jeos &lt;br/&gt;&lt;/a&gt;&lt;blockquote&gt;&lt;b&gt;Ubuntu Server Edition JeOS (pronounced &quot;Juice&quot;) is an efficient variant&lt;br /&gt;of our server operating system, configured specifically for virtual&lt;br /&gt;appliances&lt;/b&gt;. Currently available as a CD-Rom ISO for download, JeOS is a&lt;br /&gt;specialised installation of Ubuntu Server Edition with a tuned kernel&lt;br /&gt;that only contains the base elements needed to run within a virtualized&lt;br /&gt;environment.&lt;br /&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Synergy2 - &lt;a href=&#39;http://synergy2.sourceforge.net/&#39;&gt;http://synergy2.sourceforge.net/ &lt;br/&gt;&lt;/a&gt;&lt;blockquote&gt;Synergy lets you easily &lt;b&gt;share a single mouse and keyboard between&lt;br /&gt;multiple computers with different operating systems, each with its&lt;br /&gt;own display, without special hardware&lt;/b&gt;.  It&#39;s intended for users&lt;br /&gt;with multiple computers on their desk since each system uses its&lt;br /&gt;own monitor(s).&lt;/blockquote&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/6970851823691270308/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/6970851823691270308' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/6970851823691270308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/6970851823691270308'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2008/11/useful-interesting-inspiring.html' title='Useful, interesting, inspiring technology/software that is out there that you might not know about.'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-1100671889757085657</id><published>2008-10-24T08:09:00.000-07:00</published><updated>2008-10-24T08:12:45.179-07:00</updated><title type='text'>&amp;quot;Expressing Argumentative Discussions in Social Media sites&amp;quot; - and why I like it</title><content type='html'>&lt;div xmlns=&#39;http://www.w3.org/1999/xhtml&#39;&gt;At the moment, there are a lot of problems with the way information is cited or referenced in paper-based research articles, etc and I am deeply concerned that this model is applied to digitally held content. I am by no means first to say the following, and people have put a lot more thought into this field but I can&#39;t find a way out of the situation by using the information that is captured. I find it easier to see the holes when I express it to myself in rough web metaphors:&lt;br/&gt;&lt;ul&gt;&lt;li&gt;a reference list is a big list of &#39;bookmarks&#39;, ordered generally by the order in which they appear in the research paper.&lt;/li&gt;&lt;li&gt;Sometimes a bookmark is included, because everyone else in the field includes the same one, a core text for example.&lt;br/&gt;&lt;/li&gt;&lt;li&gt;There are no tags, no comments and no numbers on how often a given bookmark is used. &lt;br/&gt;&lt;/li&gt;&lt;li&gt;There is no intentional way to find out how often the bookmark appears in other people&#39;s lists. This has to be reverse engineered.&lt;br/&gt;&lt;/li&gt;&lt;li&gt;There is no way to see from the list what the intent of the reference is, whether the author agrees, disagrees, refutes, or relies on the thing in question. &lt;br/&gt;&lt;/li&gt;&lt;li&gt;There are no anchor tags in the referenced articles (normally), so there is little way to reliably refer to a single quote in a text. Articles are often referenced as a whole, rather than to the line, chart, or paragraph.&lt;br/&gt;&lt;/li&gt;&lt;li&gt;The bookmark format varies from publisher to publisher, and from journal to journal&lt;/li&gt;&lt;li&gt;Due to the coase grained citation, a single reference will sometimes be used when the author refers to multiple parts of a given piece of work&lt;/li&gt;&lt;/ul&gt;Now, on a much more positive note, this issue is being tackled. At the VoCamp in Oxford, I talked with CaptSolo about the developments with SIOC and their idea to extend the vocabularies to deal with argumentative discourse. &lt;a href=&#39;http://sdow2008.semanticweb.org/#program&#39;&gt;Their paper is now online at the SDoW2008 site&lt;/a&gt; (or directly to the &lt;a href=&#39;http://ceur-ws.org/Vol-405/paper4.pdf&#39;&gt;pdf&lt;/a&gt;) The essence of this, is an extension to the SIOC vocab, recording the intent of a statement, such as Idea, Issue, Elaboration as well as recording an Argument.&lt;br/&gt;&lt;br/&gt;I (maybe naïvely) have felt that there is a direct parallel to social discourse and academic discourse, to the point where I used the sioc:has_reply property to connect links made in blogs to items held in the archive (using trackbacks and pingbacks, a system in hiatus until I get time to beef up the antispam/moderation facilities) So, to see an argumentation vocab developing makes me more happy :) Hopefully, we can extend this vocab&#39;s intention with more academic-focussed terms.&lt;br/&gt;&lt;br/&gt;What about the citation vocabularies that exist? I think that those that I have looked at suffer from the same issue - they are built to represent what exists in the paper-world, rather than what could exist in the web-world.&lt;br/&gt;&lt;br/&gt;I also want to point out the work of the &lt;a href=&#39;http://imageweb.zoo.ox.ac.uk/wiki/index.php/Spider_Project&#39;&gt;Spider project&lt;/a&gt;, which aims to semantically markup a single journal article, as they have taken significant steps towards showing what could be possible with enhanced citations. Take a look at their &lt;a href=&#39;http://imageweb.zoo.ox.ac.uk/pub/2008/plospaper/latest&#39;&gt;enhanced article&lt;/a&gt;, all sorts of very useful examples of what is possible. Pay special attention to how the &lt;a href=&#39;http://imageweb.zoo.ox.ac.uk/pub/2008/plospaper/latest/#refs&#39;&gt;references&lt;/a&gt; are shown, how they can be reordered, typed and so. Note that I am able to link to the references section in the first place! The part I really find useful is demonstrated by the two references in red in the 2nd paragraph of the &lt;a href=&#39;http://imageweb.zoo.ox.ac.uk/pub/2008/plospaper/latest/#s1&#39;&gt;introduction.&lt;/a&gt; Hover over them to find out what I mean. Note that even though the two references are the same in the reference list (due to this starting as a paper version article) they have been enhanced to popup the reasons and sections referred to in each case.&lt;br/&gt;&lt;br/&gt;In summary then, please think twice when compiling a sparse reference list! Quote the actual section of text if you can and harvard format be damned ;)&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/1100671889757085657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/1100671889757085657' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/1100671889757085657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/1100671889757085657'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2008/10/argumentative-discussions-in-social.html' title='&amp;quot;Expressing Argumentative Discussions in Social Media sites&amp;quot; - and why I like it'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-2547800834242596365</id><published>2008-10-20T08:32:00.000-07:00</published><updated>2008-10-20T08:46:59.507-07:00</updated><title type='text'>Modelling and storing a phonetics database inside a store</title><content type='html'>&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;Long story short, a researcher asked us to store and dissmeninate a DVD containing ~600+ audio files and associated analyses comprising a phonetics database, focussed on the beat of speech.&lt;br /&gt;&lt;br /&gt;This was the request that let me start on something I had planned for a while; a databank of long tail data. This is data that is too small to fit into the plans of Big Data (which have IMO a vanishingly small userbase for reuse) and too large and complex to sit as archived lumps on the web. The system supporting databank is a Fedora-commons install, with a basic Solr implemented for indexing.&lt;br /&gt;&lt;br /&gt;As I haven&#39;t gotten an IP address for the databank machine, I cannot link to things yet, but I will walk through the modelling process. (I&#39;ll add in links to the raw objects once I have a networked VM for the databank)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Analysis: &quot;What have we got here?&quot;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The dataset has been given to us by a researcher called &lt;a href=&quot;http://kochanski.org/gpk/&quot;&gt;Dr. Greg Kochanski&lt;/a&gt;, the data having been burnt onto a DVD-R. He called it the &quot;2008 Oxford Tick1 corpus&quot;. A quick look at the contents showed that it was a collection of files, grouped by file folder into a hierarchy of some sort. First things first, though - this is a DVD-R and very much prone to degradation. As it was the files on the disk that are important, rather than the disc image itself, a quick &quot;tar -cvzf Tick1_backup.tar.gz /media/cdrom0/&quot; made a zipped archive of the files. Remember, burnt DVDs have an integrity halflife of around 1 1/2 -&amp;gt; 2 years (according to a talk I heard at the last SUN-PAsig) and I myself have lost data to unreadable discs.&lt;br /&gt;&lt;br /&gt;Disc contents: &lt;a href=&quot;http://pastebin.com/f74aadacc&quot; target=&quot;_blank&quot;&gt;http://pastebin.com/f74aadacc&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Top-level directory listing:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color:#000099;&quot;&gt;ch  ej  lp  ps  rr  sh  ta&lt;/span&gt; &lt;/b&gt; &lt;a href=&quot;http://pastebin.com/f54072d38&quot;&gt;DB.fiat&lt;/a&gt;      &lt;a href=&quot;http://pastebin.com/f4b438549&quot;&gt;DBsub.fiat&lt;/a&gt;   README.txt&lt;br /&gt;&lt;span style=&quot;color:#000099;&quot;&gt;&lt;b&gt;cw  jf  nh  rb  sb  sl  tw&lt;/b&gt;&lt;/span&gt;  &lt;a href=&quot;http://pastebin.com/f5264fbf8&quot;&gt;DBsent.fiat&lt;/a&gt;  LICENSE.txt&lt;br /&gt;&lt;br /&gt;Each one of the two letter directories holds a number of files, each file seemingly having a subdirectory for it, containing ~6+ data files in a custom format.&lt;br /&gt;&lt;br /&gt;The .fiat top-level files, DB.fiat, etc are in a format roughly described &lt;a href=&quot;http://dls.physics.ucdavis.edu/fiat/fiat.html#form&quot;&gt;here&lt;/a&gt; - the documentation about the data held within each file being targeted for humans. In essence, it looks like a way to add comments and information to a csv file, but it doesn&#39;t seem to support/encourage the line syntax that csv enjoys, like quotes, likely due to it not using any standard csv library. For instance, the same data could be captured and use standard csv libs without any real invention, but I digress.&lt;br /&gt;&lt;br /&gt;Ultimately, by parsing the fiat files, I can get the text spoken in each audio file, some metadata about each one, and some information about how some of the audio is interrelated (by text spoken, type, etc)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Modelling: &quot;How to turn the data into a representation of objects&quot;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;There are very many ways to approach this, but I shall outline the aims I keep in mind, and also the fact that this will always be a compromise between different aims, in part due to the origins of the data.&lt;br /&gt;&lt;br /&gt;I am a fan of sheer curation; I think that this not only is a great way to work, but also the only practical way to deal with this data in the first place. The researcher knows their intentions better than a post-hoc curator. Injecting data modelling/reuse considerations into the working lives of researchers is going to take a very long time. I have other projects focussed on just this, but I don&#39;t see it being the workflow through which the majority of data is piped any time soon.&lt;br /&gt;&lt;br /&gt;In the meantime, the way I believe is best for this type of data is to capture and to curate by addition. Rather than try to get systems to learn the individual ways that researchers will store their stuff, we need to capture whatever they give us and, initially, present that to end-users. In other words, not to sweat it that the data we&#39;ve put out there has a very narrow userbase, as the act of curation and preservation takes time. We need to start putting (cleared) data out there, in parallel to capturing the information necessary for understanding and then preserving the information. By putting the data out there quickly, the researcher feels that they are having an effect and are able to see that what we are doing for them is worth it. This can favourably aid dialogue that you need to have with the researcher (or other related researchers or analysts) to further characterise this data.&lt;br /&gt;&lt;br /&gt;So, step one for me is to describe a physical view of the filesystem in terms of objects and then to represent this description in terms of RDF and Fedora objects. Luckily, this is straightforward, as it&#39;s already pretty intuitive.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;There are groupings&lt;/li&gt;&lt;ul&gt;&lt;li&gt;a top-level containing 10 group folders and a description of the files&lt;/li&gt;&lt;li&gt;Each group folder contains a folder for each recording in its group&lt;/li&gt;&lt;li&gt;Each recording folder contains&lt;/li&gt;&lt;ul&gt;&lt;li&gt;There is a .wav file for each recording&lt;/li&gt;&lt;li&gt;There are 6 analysis .dat files (sound analyses like RMS, f0, etc), dependent and exclusive to each audio file&lt;/li&gt;&lt;li&gt;There are some optional files, dependent and exclusive to each audio file&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Each audio file is symbolically linked into its containing group folder.&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;So, from this, I have 3 types of object: the top-level &#39;dataset&#39; object, a grouping object of some kind, and a recording object, containing the files pertinent to a single recording. (In fact, the two grouping classes are preexisting classes in the archival system here, albeit informally.)&lt;br /&gt;&lt;br /&gt;We can get a crude, but workable representation by using three &#39;different&#39; (marked different in the RELS-EXT ds) fedora objects, and by using the &lt;a href=&quot;http://dublincore.org/documents/dcmi-terms/&quot;&gt;dcterms&lt;/a&gt; &#39;&lt;a href=&quot;http://dublincore.org/documents/dcmi-terms/#terms-isPartOf&quot;&gt;isPartof&lt;/a&gt;&#39; property to indicate the groupings (recording --- dcterms:isPartOf --&amp;gt; grouping)&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3242/2958763018_b0c029244f.jpg&quot; style=&quot;max-width: 800px;&quot; /&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;Curation by addition&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The way I&#39;ve approached this with Fedora objects is to use a datastream with a reserved ID to capture the characteristics of the data being held. At the moment, I am using full RDF stored in a datastream called RELS-INT. (NB I fully expect someone to look at this dataset later in its life and say &#39;RDF? that&#39;s so passé&#39;; the curation of the dataset will be a long-term process that may not end entirely.) RELS-INT is to contain any RDF that cannot be contained by the RELS-EXT datastream. (yes, having two sources for the RDF where one should do is not desirable, but it&#39;s a compromise between how Fedora works, and how i would like it to work.)&lt;br /&gt;&lt;br /&gt;To indicate that the RELS-INT should also be considered when viewing the RELS-EXT, I add an assertion (which slightly abuses the intended range of the dcterms requires property, but reuse before reinvention):&lt;br /&gt;&lt;br /&gt;&amp;lt;info:fedora/{object-id}&amp;gt; &amp;lt;&lt;a href=&quot;http://dublincore.org/documents/dcmi-terms/#terms-requires&quot;&gt;http://dublincore.org/documents/dcmi-terms/#terms-requires&lt;/a&gt;&amp;gt; &amp;lt;info:fedora/{object-id}/RELS-INT&amp;gt; .&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;a name=&quot;terms-requires&quot;&gt;Term Name: requires&lt;/a&gt;  &lt;br /&gt;URI:      &lt;a href=&quot;http://purl.org/dc/terms/requires&quot;&gt;http://purl.org/dc/terms/requires&lt;/a&gt;   &lt;br /&gt;Definition:     A related resource that is required by the described resource to support its function, delivery, or coherence.&lt;/blockquote&gt;I am also using the convention of storing timestamped notes in iCal format within a datastream called EVENTS (I am doing this in a much more widespread fashion throughout) These notes are intended to document the curational/archivist why&#39;s behind changes to the objects, rather than the technical ones, which Fedora can keep track of. As the notes are available to be read, they are intended to describe how this dataset has evolved and why it has been changed or added to.&lt;br /&gt;&lt;br /&gt;An assertion to add then is that the EVENTS datastream contains information pertinent to the provenance of the whole object (into the RELS-INT in this case) I am not happy with the following method, but I am open to suggestions.&lt;br /&gt;&lt;br /&gt;&amp;lt;info:fedora/{object-id}&amp;gt; &amp;lt;&lt;a href=&quot;http://dublincore.org/documents/dcmi-terms/#terms-provenance&quot;&gt;http://dublincore.org/documents/dcmi-terms/#terms-provenance&lt;/a&gt;&amp;gt; &lt;br /&gt;                              [ a &lt;a href=&quot;http://purl.org/dc/terms/ProvenanceStatement&quot;&gt;http://purl.org/dc/terms/ProvenanceStatement&lt;/a&gt; .&lt;br /&gt;                              dc:source &amp;lt;info:fedora/{object-id}/EVENTS&amp;gt; ];&lt;br /&gt;&lt;blockquote&gt;Term Name: provenance&lt;br /&gt;URI: &lt;a href=&quot;http://purl.org/dc/terms/provenance&quot;&gt;http://purl.org/dc/terms/provenance&lt;/a&gt;&lt;br /&gt;Definition: A statement of any changes in ownership and custody of the resource since its creation that are significant for its authenticity, integrity, and interpretation.&lt;br /&gt;Comment: The statement may include a description of any changes successive custodians made to the resource.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;From this point on, the characteristics of the files attached to each object can be recorded in a sensible and extendable manner. My next steps are to add simple dublin core metadata for what I can (both the objects and the individual files) and to indicate how the data is interrelated. I will also add (as an object in the databank) the basic description of the custom data format, which seems to be based loosely on the NASA FITS format, but not based well enough for FITS tools to work on, or to be able to validate the data.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Data Abstracts: &quot;Binding data to traditional formats of research (articles, etc)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;It should be possible to cite a single piece of data, as well as a grouping or even an arbitrary set of data and groupings of data. From a re-use point of view, this citation is a form of data currency that is passed around and re-cited, so it makes sense to make this citation as simple as possible; a data citation as a URL.&lt;br /&gt;&lt;br /&gt;I start from the point of view that a single, generic, perfectly modelled citation format for data will take more time and resources to develop than I have. What I believe I can do though, is enable the more practically focussed case for re-use and the sharing of citations. If a single URL(URI) is created, one which serves as an anchor node to bind together resources and information. It should provide a means for the original citing author to indicate why they had selected this grouping of information, what this grouping of information means at that time and for what reason. I can imagine modelling the simple facts of such a citation in RDF assertions (person, date of citation, etc) but it&#39;s beyond me to imagine a generic but useful way to indicate author intention and perception in the same way. The best I can do is to adopt the model that researchers/academics are most comfortable with, and allow them to record a data &#39;abstract&#39; in the native language.&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;http://farm3.static.flickr.com/2135/2958763034_584738d5e4.jpg&quot; style=&quot;max-width: 800px;&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Hopefully, this will prove a useful hook for researchers to focus on and to link to or from related or derived data. Whilst groupings are typically there to make it easier to understand the underlying data as a whole, the data abstract is there to record an author&#39;s perception of a grouping, based on whatever reasoning they choose to express.&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/2547800834242596365/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/2547800834242596365' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/2547800834242596365'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/2547800834242596365'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2008/10/modelling-and-storing-phonetics.html' title='Modelling and storing a phonetics database inside a store'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://farm4.static.flickr.com/3242/2958763018_b0c029244f_t.jpg" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-2317123182133225178</id><published>2008-10-16T03:39:00.000-07:00</published><updated>2008-10-16T03:55:42.413-07:00</updated><title type='text'>News and updates Oct 2008</title><content type='html'>&lt;div xmlns=&#39;http://www.w3.org/1999/xhtml&#39;&gt;Right, I haven&#39;t forgotten about this blog, just getting all my ducks in a line as it were. Some updates:&lt;br/&gt;&lt;br/&gt;&lt;ul&gt;&lt;li&gt;The JISC bid for eAdministration was successful, titled &quot;Building the Research Information Infrastructure (BRII)&quot;. The project will categorise the research information structure, build vocabularies if necessary, and populate it with information. It will link research outputs (text and data), people, projects, groups, departments, grant/funding information and funding bodys together, using RDF and as many pre-existing vocabularies as is suitable. The first vocab gap we&#39;ve hit is one for funding, and I&#39;ve made a draft RDF schema for this which will be openly published once we&#39;ve worked out a way to make it persistent here at Oxford (trying to get a vocab.ox.ac.uk address)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;One of the final outputs will be a &#39;foafbook&#39; which will re-use data in the BRII store - it will act as a blue book of researchers. Think Cornell&#39;s Vivo, but with the idea of Linked Data firmly in mind.&lt;/li&gt;&lt;li&gt;We are just sorting out a home for this project, and I&#39;ll post up an update as soon as it is there.&lt;br/&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Forced Migration Online (FMO) have completed their archived document migration from a crufty, proprietary store to a ORA-style store (Fedora/Solr) - you can see their preliminary frontend at &lt;a href=&#39;http://fmo.qeh.ox.ac.uk&#39;&gt;http://fmo.qeh.ox.ac.uk.&lt;/a&gt; Be aware that this is a work in progress. We provide the store as a service to them, giving them a Fedora and a Solr to use. They contracted a company called Aptivate to migrate their content, and I believe also to create their frontend. This is a pilot project to show that repositories can be treated in a distributed way, given out like very smart, shared drive space.&lt;/li&gt;&lt;li&gt;We are working to archive and migrate a number of library and historical catalogs. A few projects have a similar aim to provide an architecture and software system to hold medieval catalog research - a record of what libraries existed, and what books and works they held. This is much more complex that a normal catalog, as each assertion is backed by a type of evidence, ranging from the solid (first-hand catalog evidence), to the more loose (handwriting on the front page looks like a certain person who worked at a certain library.) So modelling this informational structure is looking to be very exciting, and we will have to try a number of ways to represent this, starting with RDF due to the interlinked nature of the data. This is related to the kinds of evidence that genealogy uses, and so related ontologies may be of use.&lt;/li&gt;&lt;li&gt;The work on storing and presenting scanned imagery is gearing up. We are investigating storing the sequence of images and associated metadata/ocr text/etc as a single tar file as part of a Fedora object (i.e. a book object will have a catalog record, technical/provenance information and an attached tar file and and a list of file to offset information.)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;This is due to us trying to hit the &#39;sweet spot&#39; for most file systems. A very large number of highly compressed images and little pieces of text does not fit well with most FS internals. We estimate that for a book there will be around [4+PDFs+2xPages] files, or 500+ typically. Just counting up the various sources of scanned media we already have, we are pressing for about 1/2 million books from one source, 200,000 images from another, 54,000 from yet another... it&#39;s adding up real fast.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;We are starting to deal with archiving/curating the &#39;long-tail&#39; of data - small, bespoke datasets that are useful to many, but don&#39;t fall into the realm of Big Data, or Web data. I don&#39;t plan on touching Access/FoxPro databases any time soon though! I am building a Fedora/Solr/eXist box to hold and disseminate these, which should live at databank.ouls.ox.ac.uk very, very shortly. (Just waiting on a new VMware host to grow into, our current one is at capacity.)&lt;br/&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;To give a better idea of the structure, etc, I am writing it up in a second blog post to follow shortly - currently named &quot;Modelling and storing a phonetics database inside a store&quot;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;I am in the process of integrating the Google-analytics-style statistics package at http://piwik.org with the ORA interface, to give relatively live hit counts on a per-item and to build per-collection reports.&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Right now, piwik is capturing the hits and downloads from ORA, but I have yet to add in the count display on each item page, so halfway there :)&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;We are just waiting on a number of departments here to upgrade the version of EPrints they are using for their internal, disciplinary repositories, so that we can begin archiving surrogate copies of the work they wish to put up for this service. (Using ORE descriptions of their items) By doing so, their content becomes exposed in ORA, mirror copies are made (working on a good way to maintain these as content evolves), but they retain the content control, ORA will also act as a registry for their content. It&#39;s only when their service drops do the users get redirected to the mirror copies that ORA holds (think google cache, but a 100% copy).&lt;/li&gt;&lt;li&gt;In the process of battle-testing the Fedora-Honeycomb connection, but as mentioned above, just waiting for a little more hardware before I set to it. Also, we are examining a number of other storage boxes that should plug in under Fedora, using the Honeycomb software, such as the new and shiny Thumper box, &quot;Thor&quot; Sun Fire Xsomething-or-other. Also, getting pretty interested at the idea of MAID storage - massive array of idle disks. Hopefully, this will act like tape, but have a sustainable access speed of disk. Also, a little more green than a tower of spinning hardware.&lt;/li&gt;&lt;li&gt;Planning out the indexer service at the moment. It will use the Solr 1.3 multicore functionality, with a little parsing magic at the ingest side of things to make a generic indexer-as-a-service type system. One use-case is to be able to bring up VM machines with multicore solr on to act as indexers/search engines as needed. An example aim? &quot;Economics want an index that facets on their JEL codes.&quot; POST a schema and ingest indexer to the nearest free indexer, and point the search interface at it once an XMPP message comes back that it is finished.&lt;/li&gt;&lt;li&gt;URI resolvers - still investigating what can be put in place for this, as I strongly wish to avoid coding this myself. Looking at OCLC&#39;s OpenURL and how I can hack it to feed it info:fedora uris and link them to their disseminated location. Also, using a tinyurl type library + simple interface might not be a bad idea for a quick PoC.&lt;br/&gt;&lt;/li&gt;&lt;li&gt;Just to let you all know that we are building up the digital team here, most recently held interviews for the futureArch project but we are looking for about 3 others to hire, due to all the projects we are doing. We will be putting out job adverts as and when we feel up to battling with HR :)&lt;/li&gt;&lt;/ul&gt;That&#39;s most of the more interesting hot topics and projects I am doing at the moment.... phew :)&lt;br/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/2317123182133225178/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/2317123182133225178' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/2317123182133225178'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/2317123182133225178'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2008/10/news-and-updates-oct-2008.html' title='News and updates Oct 2008'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-2621863987788037037</id><published>2008-08-18T05:32:00.000-07:00</published><updated>2008-08-18T05:48:25.790-07:00</updated><title type='text'>Cherry picking the Semantic Web (from Talis&#39;s Nodalities magazine)</title><content type='html'>Just to say that in the &lt;a href=&quot;http://www.talis.com/nodalities&quot;&gt;Talis Nodalities&lt;/a&gt; magazine, &lt;a href=&quot;http://www.talis.com/nodalities/pdf/nodalities_issue3.pdf&quot;&gt;Issue 3 [PDF] page 13&lt;/a&gt; they have published an article of mine about how treating everything - author, department, funder, etc - as an first class object will have knock-on benefits to curation and cataloguing of archived items.&lt;br /&gt;&lt;br /&gt;When I find a good, final version of the article that I haven&#39;t accidentally deleted, I&#39;ll post the text of it here ;) Until then, download the PDF version. Read all the articles actually, they are all good!&lt;br /&gt;&lt;br /&gt;(NB The magazine itself is licensed under the CC-by-sa, which I think is excellent!)</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/2621863987788037037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/2621863987788037037' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/2621863987788037037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/2621863987788037037'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2008/08/cherry-picking-semantic-web-from-taliss.html' title='Cherry picking the Semantic Web (from Talis&#39;s Nodalities magazine)'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-1371143081899015772</id><published>2008-08-18T05:16:00.000-07:00</published><updated>2008-08-19T09:30:50.684-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="crigshow"/><category scheme="http://www.blogger.com/atom/ns#" term="idea"/><title type='text'>DSpace and Fedora *need* opinionated installers.</title><content type='html'>Just to say that both Fedora-Commons and DSpace really, really need opinionated installers that make choices for the user. Getting either installed is a real struggle - which we demonstrated during the Crigshow, so please don&#39;t write in the comments that it is easy, it just isn&#39;t.&lt;br /&gt;&lt;br /&gt;Something that is relatively straightforward to install, is a debian package.&lt;br /&gt;&lt;br /&gt;So, just a plea in the dark, can we set up a race? Who can make their repository software installable as a .deb first? will it be DSpace or Fedora? Who am I going to send a box of cookies to and a thank you note from the entire developer community?&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://wiki.eprints.org/w/Installing_EPrints_3_via_apt_%28Debian/Ubuntu%29&quot;&gt;(EPrints doesnt count in this race; they&#39;ve already done it)&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/1371143081899015772/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/1371143081899015772' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/1371143081899015772'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/1371143081899015772'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2008/08/dspace-and-fedora-need-opinionated.html' title='DSpace and Fedora *need* opinionated installers.'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-7963164596904275017</id><published>2008-08-18T04:47:00.000-07:00</published><updated>2008-08-19T09:30:50.684-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="crigshow"/><title type='text'>Re-using video compression code to aid document quality checking</title><content type='html'>&lt;a href=&quot;http://crigshow.blogspot.com/2008/07/prototype-motion-analysis-to-detect.html&quot;&gt;(Expanding on this video post from the Crigshow)&lt;/a&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;&lt;br /&gt;Problem:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The volume of pages from a large digitisation project can be overwhelming. Add into that the simple fact that all (UK) institutional projects are woefully underfunded and underresourced, it&#39;s surprising that we can cope with them really.&lt;br /&gt;&lt;br /&gt;One issue that repeatedly comes up is the idea of quality assurance; How can we know that a given book has been scanned well? How can we spot images easily? Can we detect if foreign bodies were present in the scan, such as thumbs, fingers or bookmarks?&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;A quick solution:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Inspired by a talk at one of the conference strands at WorldComp, where the author talked about the use of a component of a commonly used video compression standard (MPEG2) to detect degrees of motion and change in a video, without having to analyse the image sequences using a novel, or smart algorithm.&lt;br /&gt;&lt;br /&gt;He talked about using the motion vector stream to be a good rough guide to the amount of change between frames of video.&lt;br /&gt;&lt;br /&gt;So, why did this inspire me?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;MPEG-2 compression is a pretty much a solved problem; there are some very fast and scalable solutions out there today - direct benefit: &lt;span style=&quot;font-weight: bold;&quot;&gt;No new code needs to be written and maintained&lt;/span&gt;&lt;/li&gt;&lt;li&gt;The format is very well understood and stripping out the motion vector stream wouldn&#39;t be tricky. Code exists for this too.&lt;/li&gt;&lt;li&gt;Pages of text in printed documents tend towards being justified so that the two edges of the text columns are straight lines. There is also (typically) a fixed number of lines on a page.&lt;/li&gt;&lt;li&gt;A (comparatively rapid) MPEG2 compression of the scans of a book would have the following qualities:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;The motion vectors between pages of text would either shown little overall change (as differing letters are actually quite similar) or a small, global shift if the page was printed on a slight offset.&lt;/li&gt;&lt;li&gt;The motion vectors between a page of text and a page with an image embedded in text on the next, or a thumb on the edge, would show localised and distinct changes that differ greatly from the overall perspective.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;In fact, a real crude solution could be, just using the vector stream to create a bookmark list for all the suspect changes. This might bring the number of pages to check down to a level that a human mediator could handle.&lt;/li&gt;&lt;/ul&gt;How much needs to be checked?&lt;br /&gt;&lt;br /&gt;Via basic sample survey statistics: to be sure to 95% (±5%) that the scanned images of 300 million pages are okay, just 387 totally random pages need to be checked. However, to be sure that each individual book is okay to the same degree, a book being ~300 pages, 169 pages need to be checked &lt;span style=&quot;font-weight: bold;&quot;&gt;in each book&lt;/span&gt;. I would suggest that the above technique would significantly lower this threshold, but it would be by an empirically found amount.&lt;br /&gt;&lt;br /&gt;Also note that the above figures carry the assumption that the scanning process doesn&#39;t change over time, which of course it does!</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/7963164596904275017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/7963164596904275017' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/7963164596904275017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/7963164596904275017'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2008/08/re-using-video-compression-code-to-aid.html' title='Re-using video compression code to aid document quality checking'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3090914606822911489.post-2742105134406656447</id><published>2008-08-18T03:40:00.000-07:00</published><updated>2008-08-20T05:31:34.099-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="crigshow"/><category scheme="http://www.blogger.com/atom/ns#" term="formats"/><category scheme="http://www.blogger.com/atom/ns#" term="identifier"/><category scheme="http://www.blogger.com/atom/ns#" term="repository"/><title type='text'>The four rules of the web and compound documents</title><content type='html'>A real quirk that truly interests me is the difference in aims between the way documents are typically published and the way that the information within them is reused.&lt;br /&gt;&lt;br /&gt;A published document is normally in a single &#39;format&#39; - a paginated layout, and this may comprise text, numerical charts, diagrams, tables of data and so on.&lt;br /&gt;&lt;br /&gt;My assumption is that, to support a given view or argument, a reference to the entirety of an article is not necessary; The full paper gives the context to the information, but it is much more likely that a small part of this paper contains the novel insight being referenced.&lt;br /&gt;&lt;br /&gt;In the paper-based method, it is difficult to uniquely identify parts of an article as items in their own right. You could reference a page number, give line numbers, or quote a table number, but this doesn&#39;t solve this issue that the author hadn&#39;t put time to considering that a chart, a table or a section of text would be reused.&lt;br /&gt;&lt;br /&gt;So, on the web, where multiple representations of the same information is getting to be commonplace (mashups, rss, microblogs, etc), what can we do to help better fulfill both aims, to show a paginated final version of a document, and also to allow each of the components to exist as items in their own right, with their own URIs (or better, URLs containing some notion of the context e.g.   if /store/article-id gets to the splash page of the article, /store/article-id/paragraph-id will resolve to the text for that paragraph in the article.)&lt;br /&gt;&lt;br /&gt;Note that the four rules of the web (well, of &lt;a href=&quot;http://linkeddata.org/&quot;&gt;Linked Data&lt;/a&gt;) are in essence:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;give everything a name,&lt;br /&gt;&lt;/li&gt;&lt;li&gt;make that name a URL ...&lt;/li&gt;&lt;li&gt;...which results in data about that thing,&lt;br /&gt;&lt;/li&gt;&lt;li&gt;and have it link to other related things. &lt;/li&gt;&lt;/ul&gt;[From &lt;a href=&quot;http://www.w3.org/DesignIssues/LinkedData.html&quot;&gt;TimBL&#39;s originating article&lt;/a&gt;. Also, see this &lt;a href=&quot;http://virtuoso.openlinksw.com/presentations/Creating_Deploying_Exploiting_Linked_Data2/Creating_Deploying_Exploiting_Linked_Data2_TimBL_v3.html#%281%29&quot;&gt;presentation &lt;/a&gt;- a remix of presentations from TimBL and the speaker, &lt;span style=&quot;font-style: italic;font-size:100%;&quot; &gt;&lt;a href=&quot;http://myopenlink.net/dataspace/person/kidehen#this&quot;&gt;&lt;span style=&quot;color: rgb(0, 147, 182); text-decoration: underline;&quot; about=&quot;http://kidehen.idehen.net/dataspace/person/kidehen#this&quot; typeof=&quot;foaf:Person&quot; property=&quot;foaf:name&quot;&gt;Kingsley Idehen&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;span style=&quot;font-size:100%;&quot;&gt; - given at the recent Linked Data Planet conference&lt;/span&gt;]&lt;br /&gt;&lt;br /&gt;I strongly believe that applying this to the individual components of a document is a very good and useful thing.&lt;br /&gt;&lt;br /&gt;One thing first, we have to get over the legal issue of just storing and presenting a bitwise perfect copy of what an author gives us. We need to let author&#39;s know that we may present alternate versions, based on a user&#39;s demands. This actually needs to be the case for preservation and the repository needs to make it part of their submission policy to allow for format migrations, accessibility requirements and so on.&lt;br /&gt;&lt;br /&gt;The system holding the articles needs to be able to clearly indicate versions and show multiple versions for a single record.&lt;br /&gt;&lt;br /&gt;When a compound document is submitted to the archive, a second parallel version should be made by fragmenting the document into paragraphs of text, individual diagrams, tables of data, and other natural elements. One issue that has already come up in testing, is that documents tend to clump multiple, separate diagrams together into a single physical image. It is likely that the only solution to breaking these up to this is going to be a human one, either author/publisher education(unlikely) or by breaking them up by hand.&lt;br /&gt;&lt;br /&gt;I would suggest using a very lightweight, hierarchical structure to record the document&#39;s logical structure. I have yet to settle on basing it on the content XML format inside the OpenDocument format, or on something very lightweight, using HTML elements, which would have a double benefit of being able to be sent directly to a browser to &#39;recreate&#39; the document roughly.&lt;br /&gt;&lt;br /&gt;Summary:&lt;br /&gt;&lt;br /&gt;1) Break apart any compound document into its constituent elements (paragraph level is suggested for text)&lt;br /&gt;2) Make sure that each one of these parts are clearly expressed in the context they are in, using hierarchical URLs, /article/paragraph or even better, /article/page/chart&lt;br /&gt;3) On the article&#39;s splashpage, make a clear distinction between the real article and the broken up version. I would suggest a scheme like Google search&#39;s &#39;View [PDF, PPT, etc] as HTML&#39;. I would assert that many people intuitively understand that this view is not like the original and will look or act differently.&lt;br /&gt;&lt;br /&gt;Some related video blogs from the &lt;a href=&quot;http://crigshow.blogspot.com/&quot;&gt;Crigshow&lt;/a&gt; trip&lt;br /&gt;&lt;a href=&quot;http://crigshow.blogspot.com/2008/07/prototype-extracting-and-finding.html&quot;&gt;Finding and reusing algorithms from published articles&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://crigshow.blogspot.com/2008/07/real-documents-are-complex-objects.html&quot;&gt;OCR&#39;ing documents; Real documents are always complex&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://crigshow.blogspot.com/2008/07/protoype-providing-overviews-of.html&quot;&gt;Providing a systematic overview of how a Research paper is written&lt;/a&gt; - giving each component and each version of a component would have major benefits here</content><link rel='replies' type='application/atom+xml' href='http://oxfordrepo.blogspot.com/feeds/2742105134406656447/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3090914606822911489/2742105134406656447' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/2742105134406656447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3090914606822911489/posts/default/2742105134406656447'/><link rel='alternate' type='text/html' href='http://oxfordrepo.blogspot.com/2008/08/four-rules-of-web-and-compound.html' title='The four rules of the web and compound documents'/><author><name>Ben O&#39;Steen</name><uri>http://www.blogger.com/profile/10330754112283510575</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry></feed>