<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Adventures in Duality</title>
	<atom:link href="http://cogracenotes.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://cogracenotes.wordpress.com</link>
	<description>Hacking and Haskell</description>
	<lastBuildDate>Tue, 07 Feb 2012 19:22:49 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='cogracenotes.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Adventures in Duality</title>
		<link>http://cogracenotes.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://cogracenotes.wordpress.com/osd.xml" title="Adventures in Duality" />
	<atom:link rel='hub' href='http://cogracenotes.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Hackage at Baltimore</title>
		<link>http://cogracenotes.wordpress.com/2010/10/04/hackage-at-baltimore/</link>
		<comments>http://cogracenotes.wordpress.com/2010/10/04/hackage-at-baltimore/#comments</comments>
		<pubDate>Mon, 04 Oct 2010 16:58:26 +0000</pubDate>
		<dc:creator>cogracenotes</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://cogracenotes.wordpress.com/?p=122</guid>
		<description><![CDATA[After the ICFP 2010 conference proper had come to a close, I came along for some Haskell-related revelry in Baltimore, from Thursday evening (Sept 30) to Sunday night (Oct 3). My paper-reading queue is chock full, and my wallet less so. Anyway, I had a good time and met some amazing people. I was there [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=cogracenotes.wordpress.com&#038;blog=13902430&#038;post=122&#038;subd=cogracenotes&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>After the ICFP 2010 conference proper had come to a close, I came along for some Haskell-related revelry in Baltimore, from Thursday evening (Sept 30) to Sunday night (Oct 3). My paper-reading queue is chock full, and my wallet less so. Anyway, I had a good time and met some amazing people. I was there for a good reason, though.</p>
<p>I gave a talk at the Haskell Implementors&#8217; Workshop about Hackage, which you can find at <a href="http://vimeo.com/15464003">http://vimeo.com/15464003</a>. It&#8217;s 35 minutes in total. </p>
<div class='embed-vimeo' style='text-align:center;'><iframe src='http://player.vimeo.com/video/15464003' width='400' height='300' frameborder='0'></iframe></div>
<p>The presentation part is a straightforward overview. Open discussion starts at about 16:30. You can get the slides <a href="http://www.galois.com/~dons/talks/hiw-2010/gruen-hackage2.pdf">here</a> [PDF].</p>
<p>I hope it gives you a better idea of where Hackage is going. During the weekend, I had some great discussions about Hackage, and comparing functional languages, and finance (of all things). Even better, there was actual solid planning. On Sunday, Duncan Coutts and I materialized a plan for switching over to the new Hackage. It&#8217;s up online at <a href="http://hackage.haskell.org/trac/hackage/wiki/HackageDB/2.0/Switchover">the Hackage trac wiki</a>, and the current revision looks something like this:</p>
<ol>
<li> *Live mirroring (user-immutable, all accounts are historical)
<ul>
<li> Get archive.tar.gz of all ~10,000 packages on Hackage
<li> Investigate unmirrorable packages (e.g. binembed-example, network-info, old-time)
<li> Get cabal-installs pointing at it
   </ul>
<li> Implement backup for newer features (not all essential):
<ul>
<li> Download statistics
<li> Candidates
<li> Preferred versions + deprecation
   </ul>
<li> Get data migration (schema updates) working more smoothly
<li> *Live server beta testing (user-mutable, all accounts are active)
<ul>
<li> Disable registration; main Hackage accounts imported in
<li> Still mirroring the main Hackage
<li> Changes made here will be wiped out when server is fully deployed
   </ul>
<li> Configure server with Apache to support the tracs, support https on Hackage
<li> When ready to deploy: turn off upload on current Hackage
<li> Construct export tarball with these features:
<ul>
<li> core (packages, user db, admin list)
<li> upload (trustees, maintainers)
<li> tags (based on categories, initially)
<li> distro (from current files: arch + debian, eventually exherbo + ubuntu)
<li> download (from logs, give expected format to Galois log holders)
<li> versions (deprecated packages, preferred-versions)
   </ul>
<li> Wipe server state and restore from tarball
<li> *Switch!
</ol>
<p>Throughout all this there will be testing for backups and performance. The starred items are the significant ones that&#8217;ll be announced. They look like &#8220;use it with cabal-install!&#8221;, &#8220;use it as you please unofficially!&#8221;, and &#8220;use it as you please officially!&#8221;. If you&#8217;d like to learn more about some of the ideas behind hackage-server, <a href="http://hackage.haskell.org/trac/hackage/wiki/HackageDB/2.0/Architecture">the architecture document</a> is a good starting point, as well as past blog posts and the <a href="http://code.haskell.org/hackage-server/Distribution/Server/Features/">features themselves</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/cogracenotes.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/cogracenotes.wordpress.com/122/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=cogracenotes.wordpress.com&#038;blog=13902430&#038;post=122&#038;subd=cogracenotes&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://cogracenotes.wordpress.com/2010/10/04/hackage-at-baltimore/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/3bd40df9a068bccc83b33b742c4a869d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">cogracenotes</media:title>
		</media:content>
	</item>
		<item>
		<title>Policy on the New Hackage Server</title>
		<link>http://cogracenotes.wordpress.com/2010/08/14/policy-on-hackage-server/</link>
		<comments>http://cogracenotes.wordpress.com/2010/08/14/policy-on-hackage-server/#comments</comments>
		<pubDate>Sat, 14 Aug 2010 02:00:54 +0000</pubDate>
		<dc:creator>cogracenotes</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://cogracenotes.wordpress.com/?p=115</guid>
		<description><![CDATA[I&#8217;ve been working on the newer hackage-server as part of Google Summer of Code. It has user accounts, editable access control lists (user groups), and a system to hook in any number of pre-upload checks. It can utilize all of these to set the policy for how it filters its data. So how does it [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=cogracenotes.wordpress.com&#038;blog=13902430&#038;post=115&#038;subd=cogracenotes&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve been working on the <a href="http://cogracenotes.wordpress.com/2010/08/08/hackage-on-sparky/">newer hackage-server</a> as part of Google Summer of Code. It has user accounts, editable access control lists (user groups), and a system to hook in any number of pre-upload checks. It can utilize all of these to set the policy for how it filters its data. So how does it do that presently?</p>
<h3> User groups </h3>
<p>There are three important user groups: admins, package trustees, and package maintainers. Some server updates require membership in these groups; membership can be edited with a <a href="http://imgur.com/pMrnz">simple interface</a>.</p>
<ul>
<li> Admins perform administrative tasks. They can create accounts, change anyone&#8217;s password, delete an account, make server backups, and modify the members of the other user groups. They can also modify the package index in ways not allowed by normal uploads.
<li> There is one package maintainer group per package. When a package is uploaded and no versions of it existed previously, the maintainer group is created with the uploader as the sole member. Maintainers can add other maintainers. Members of this group can then upload new versions of the package, edit its preferred versions and deprecated status, upload documentation, manage build reports, and other maintenance tasks. Of course, they don&#8217;t have to.
<li> Package trustees are package maintainers for <em>all</em> packages. They can add and remove maintainers for any package, and perform any action per package that maintainers can.
</ul>
<p>It&#8217;s not set in stone, or even etched on papyrus, who the admins and trustees are actually going to be. Initially, package maintainers will be anyone who&#8217;s uploaded a version of a given package.</p>
<p>Other features provide their own user groups as well. One thing about their implementation is that they are entirely decentralized: there&#8217;s no section in the code which lists all of the user groups. There is a user → group mapping, but it&#8217;s updated only in response to the groups themselves being modified. Other groups, editable by admins, include:</p>
<ul>
<li> Distro maintainers: can indicate which packages are available under which Linux distributions in their binary repositories. This information is available on package pages for those who prefer distro packages, as well as in list form.
<li> Mirrorers: these are accounts for scripts which copy packages from one Hackage to another. Presently this is implemented in a batch-difference mode from hackage-scripts to hackage-server and is run periodically.
</ul>
<h3> Uploading </h3>
<p>Uploading follows these steps:</p>
<ol>
<li> Uploader POSTs to /packages/ with package=[package tarball]
<li> Make sure the user is logged in and get their user info
<li> Put the package file in a temporary directory for incoming files
<li> Get the package&#8217;s cabal file, parse it, and check it&#8217;s valid. Get the package name and version.
<li> Fail if the package version is already in the main database
<li> If maintainers exist for the package, make sure the user is in the maintainer group
<li> Run pre-upload hooks; these can indicate errors and cause the upload to fail
<li> Move the package to blob file storage and add it to the main index
<li> Run all of the post-upload hooks, updating secondary indices to keep them in sync
<li> Redirect to the new package page (or display an error)
</ol>
<h3> Account registration </h3>
<p>I wish I could give you the process for account registration, but the truth is that it&#8217;s still undecided. The present system involves requesting an account via email. This could still work with the new hackage-server, technically. There are a few reasons why this kind of process could be refined: there can be several admins; account creation no longer requires access to the server&#8217;s filesystem (<a href="http://en.wikipedia.org/wiki/.htpasswd">.htpasswd</a>); and account maintenance of all of Hackage is a lot for one person.</p>
<p>Possible approaches include:</p>
<ul>
<li> Admins create accounts, possibly requested from some kind of <a href="http://community.haskell.org/admin/account_request.html">web interface</a>.
<li> Anyone can self-register partial accounts which can do everything but upload, but can e.g. edit tags, write comments, or vote. These can be transformed from partial to total accounts by admins (perhaps also using a ticket system).
<li> Let anyone self-register for an account and start uploading (it&#8217;s worked for <a href="http://rubygems.org/">rubygems.org</a>).
</ul>
<h3> So&#8230; </h3>
<p>The newer hackage-server comes with some nifty defaults, including more detailed ways to maintain packages. There are some guiding principles to consider when making policies: for example, packages shouldn&#8217;t be any harder to upload than they are now (which is not very). Another principle is quality assurance (see &#8220;<a href="http://blog.ezyang.com/2010/08/the-radical-hackage-social-experiment/">A radical Hackage social experiment</a>&#8220;). The above system has been developed with these in mind. Last but not least, there&#8217;s the community&#8217;s experience with current Hackage policies. How can they be improved?</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/cogracenotes.wordpress.com/115/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/cogracenotes.wordpress.com/115/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=cogracenotes.wordpress.com&#038;blog=13902430&#038;post=115&#038;subd=cogracenotes&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://cogracenotes.wordpress.com/2010/08/14/policy-on-hackage-server/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/3bd40df9a068bccc83b33b742c4a869d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">cogracenotes</media:title>
		</media:content>
	</item>
		<item>
		<title>Hackage on Sparky</title>
		<link>http://cogracenotes.wordpress.com/2010/08/08/hackage-on-sparky/</link>
		<comments>http://cogracenotes.wordpress.com/2010/08/08/hackage-on-sparky/#comments</comments>
		<pubDate>Sun, 08 Aug 2010 08:18:43 +0000</pubDate>
		<dc:creator>cogracenotes</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://cogracenotes.wordpress.com/?p=97</guid>
		<description><![CDATA[Hi, Haskellers. It&#8217;s been a while since I finished most of Hackage 2.0&#8242;s internal infrastructure. The site still needs a visual makeover, but I feel that enough of the core functionality is exposed for it to be useful to you guys. The latest from the darcs repository is running at: http://sparky.haskell.org:8080/ This is imported from [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=cogracenotes.wordpress.com&#038;blog=13902430&#038;post=97&#038;subd=cogracenotes&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>Hi, Haskellers. It&#8217;s been a while since I finished most of Hackage 2.0&#8242;s internal infrastructure. The site still needs a visual makeover, but I feel that enough of the core functionality is exposed for it to be useful to you guys. The latest from the <a href="http://code.haskell.org/hackage-server">darcs repository</a> is running at:</p>
<p><a href="http://sparky.haskell.org:8080/">http://sparky.haskell.org:8080/</a></p>
<p>This is imported from <a href="http://hackage.haskell.org">Hackage</a> package data a day or so ago—no user account data. The features currently enabled on the server are package pages, uploading packages, uploading candidates, distribution information, user groups, documentation, build reports, preferred versions, package deprecation, reverse dependencies, download statistics, tags, name search, and a handful of others.</p>
<p>The most important feature, though, and the reason this was a complete rewrite instead of just extending the old server, is that the internal design is modular and <em>meant</em> to be extended easily. If there&#8217;s a feature you don&#8217;t like (say, doing download statistics), it should take very little time to gut it from the application and not compile it in at all. <a href="http://code.haskell.org/hackage-server/Distribution/Server/Features/NameSearch.hs">The NameSearch module</a>, as an example, adds two search indices, a simple search page (at <a href="http://sparky.haskell.org:8080/packages/find">/packages/find</a>), and an OpenSearch plugin with suggestions. Installing it entails adding a line to <a href="http://code.haskell.org/hackage-server/Distribution/Server/Features.hs">Features.hs</a> and writing an HTML view for it. </p>
<h3>Performance</h3>
<p>As far as performance goes: the process of routing a URI, querying data from several sources, and rendering the resultant page takes anywhere from 15ms (for an unadorned package page) to 3 seconds (for long lists of packages with descriptions and tags) on the sparky server. This is the amount of time it takes to fully generate the document as a ByteString, which is then given to the Happstack web framework. <a href="http://pastebin.com/raw.php?i=FVVRw33N">Here are some example times</a>. I expect that switching from xhtml to BlazeHTML, based on the benchmarks so far, would definitely reduce the rendering time; I&#8217;m looking into other places to cut corners, though I&#8217;m no expert here.</p>
<p>Routing itself takes around 1ms, based on the dynamic approach I described <a href="http://cogracenotes.wordpress.com/2010/06/17/hackage-feature-graphs/">in this post</a>. On my laptop, which has faster cores but far fewer of them, crafting a response takes anywhere from 2ms to half a second, and routing takes around 0.2ms, for the same server configuration and package collection.</p>
<p>Unfortunately, sparky itself seems a bit laggy: yesterday it took 30 seconds (!) to request and retrieve a 350KB HTML document which is fully cached in memory, even though it took a fraction of a millisecond to get a ByteString for it. I&#8217;m looking into this.</p>
<h3>Try it out!</h3>
<p>So, take a look around and tell me what you think! If you want to try out your own copy, these <em>should</em> work as a bash shell scripts, if you have <a href="http://www.haskell.org/ghc/">ghc</a>+<a href="http://www.haskell.org/cabal/download.html">cabal-install</a>+<a href="http://hackage.haskell.org/package/alex">alex</a>+<a href="http://hackage.haskell.org/package/happy">happy</a> on your system: <a href="http://hpaste.org/fastcgi/hpaste.fcgi/view?id=28686">import current Hackage data</a> or <a href="http://hpaste.org/fastcgi/hpaste.fcgi/view?id=28685">start a completely new server</a>. (These install the server and use its <a href="http://hackage.haskell.org/trac/hackage/wiki/HackageDB/2.0/CommandLine">command line interface</a>.) Importing the current Hackage dataset requires somewhere in the neighborhood of 750MB of memory (I&#8217;m looking to reduce this) and 600MB to run the server (sparky has 32GB of memory). A brand new server requires just 2MB of memory.</p>
<h3>To do</h3>
<p>The primary goal this summer was to create a server architecture that could handle whatever we as a community need, and implement as much of it in Haskell as possible. I&#8217;m only one person, so there&#8217;s still a lot left to do, short-term and long-term, to get a better Hackage. I&#8217;ve outlined some of these tasks below.</p>
<p>What needs to be done before deploying to hackage.haskell.org?</p>
<ul>
<li> Documentation. It&#8217;s one of the most important things Hackage provides. hackage-server lets maintainers upload documentation tarballs, but <a href="http://hackage.haskell.org/trac/hackage/ticket/517">ticket 517</a> should be resolved so documentation can be more easily generated with Cabal.
<li> Importing download statistics from the last few years. Granted, this is a minor one, but it&#8217;s a big help to have these without a gap in recording.
<li> Stress-testing, in terms of making sure the server performs well and maintains the consistency of internal indices. Make sparky a bit more responsive. Ensure compatibility with cabal-install, including old versions. Double-check security in order to minimize the risk of attacks (replay, DDOS, etc.).
<li> Deciding policy for things like account creation and uploading. I&#8217;ll put up a blog post soon about the policy that hackage-server currently has for these sorts of things, including an overview of the user group system.
<li> Implementing backup for some of the newer features and creating an interface for admins to download backup tarballs.
<li> Make sure the URI scheme is convenient for everyone.
<li> Make robots.txt and set noindex on pages as appropriate.
<li> Arrange for distribution maintainers (for Debian and Arch, presently) to send us updates about which packages they have available. Haskell packages in distribution repositories tend to be simpler to install and more stable, so connecting to them is important.
<li> We need site admins and package trustees!
</ul>
<p>In the short-term future? (these should be implemented, sooner better than later)</p>
<ul>
<li> Build reports: get a system working for cabal-install clients to send build reports, anonymous or non-anonymous, as a replacement/enhancement of the build bot&#8217;s functionality. At present Hackage can accept basic build reports, but this should be gotten right before it&#8217;s enabled, particularly for anonymous reports.
<li> Web interface redesign. Since Hackage has more information to serve, it needs a better way to visually organize it. Anyone with web design chops is welcome. Other things to do here: expose JSON representations for Ajax functionality; rewrite HTML generating-code to use Blaze.
<li> Serve the internals of packages and <a href="http://www.google.com/help/codesearch_packagemap.html">set up a sitemap.xml</a> so they can go on Google Code Search.
<li> Allow modifications to the cabal file without bumping the package version number. Admins can do this, but under some circumstances package maintainers might want to as well.
<li> See if user group information can be stored better internally.
<li> Get an STMP client running on the server to send automated email notifications.
<li> More server-side logging of actions (with user and timestamp): this makes it easier to find out what&#8217;s going on and provide historical data.
</ul>
<p>In the long term future? (looking into the crystal ball)</p>
<ul>
<li> Social features. This includes reviews, voting, contributing content: the little things that let you know your fellow Haskellers are humans and not code-generating automatons (besides mailing lists, IRC, reddit, meetups, conferences, blog posts&#8230;). The more effectively we can connect maintainers and users, the better. Most of these social features would be simple to implement technically. It&#8217;s more difficult to decide which features would actually benefit us as a community and get better-quality packages.
<li> Allow the creation of arbitrary groups of packages. Currently, there&#8217;s a Haskell Platform feature, which puts a little star next to every package that&#8217;s in the platform. Why not lay the groundwork for other package groups?
<li> Insert your idea here
</ul>
<p>There&#8217;s a <a href="http://hackage.haskell.org/trac/hackage/wiki/HackageDB/2.0/Architecture">document in progress</a> about the server internals, and how you can extend Hackage with new features. For the next week, I&#8217;ll be tidying up the code, bug-hunting, writing documentation, and seeing what I can do with transition preparations. Come join #hackage on freenode, if you like, since we&#8217;ll be discussing some of these things in the coming weeks.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/cogracenotes.wordpress.com/97/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/cogracenotes.wordpress.com/97/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=cogracenotes.wordpress.com&#038;blog=13902430&#038;post=97&#038;subd=cogracenotes&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://cogracenotes.wordpress.com/2010/08/08/hackage-on-sparky/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/3bd40df9a068bccc83b33b742c4a869d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">cogracenotes</media:title>
		</media:content>
	</item>
		<item>
		<title>Hackage GSoC status for the 3/7ths mark</title>
		<link>http://cogracenotes.wordpress.com/2010/06/29/hackage-37ths-mark/</link>
		<comments>http://cogracenotes.wordpress.com/2010/06/29/hackage-37ths-mark/#comments</comments>
		<pubDate>Tue, 29 Jun 2010 22:04:56 +0000</pubDate>
		<dc:creator>cogracenotes</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://cogracenotes.wordpress.com/?p=84</guid>
		<description><![CDATA[A week and a half ago I talked about how the new Hackage server is internally structured. What I&#8217;d like to communicate now, to commemorate the Google Summer of Code coding period being exactly 3/7ths of the way through (36 days down, 48 to go), is more of a status report than anything else. (Granted, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=cogracenotes.wordpress.com&#038;blog=13902430&#038;post=84&#038;subd=cogracenotes&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>A week and a half ago <a href="http://cogracenotes.wordpress.com/2010/06/17/hackage-feature-graphs/">I talked about</a> how the new <a href="http://hackage.haskell.org/">Hackage</a> server is internally structured. What I&#8217;d like to communicate now, to commemorate the <a href="http://code.google.com/soc/">Google Summer of Code</a> coding period being exactly 3/7ths of the way through (36 days down, 48 to go), is more of a status report than anything else. (Granted, 3/7ths marks would be more significant if we used base 7 numbers.) I spent last week on a feature-implementing spree. With an emphasis on &#8220;spree&#8221;, and none on doing-anything-else-or-even-leaving-the-house. So I spent the weekend regenerating, and I think it&#8217;s time I reflected on how I&#8217;ve been doing.</p>
<h3> The original schedule </h3>
<p>When I applied to do the Hackage for Summer of Code, I included a tentative schedule. I have not strictly followed it so far, though I didn&#8217;t quite expect to. Here&#8217;s why.</p>
<blockquote><p>1. 2 weeks. Become familiar with codebase and add documentation to declarations as I understand them. Find functionality not in the old server and not covered by the coming weeks and fully port it. Do the same for items in the hackage-server TODO list.
</p></blockquote>
<p>I didn&#8217;t anticipate all of the restructuring that needed to be done, thinking I could mostly append rather than modify. Well, I have substantially altered the already-great codebase into a modular form I&#8217;m pretty happy with, but it nonetheless takes a long time to do so when you&#8217;re starting with a 10,000-line codebase developed over 2 years (now it&#8217;s around 12,000 lines). The old server is mostly fully ported, although it wasn&#8217;t done within the space of these two weeks.</p>
<blockquote><p>2. 1.5 weeks. Get build reports to display and gather useful information: already partially implemented. Use this feature as an opportunity to become even more comfortable refactoring and enhancing the hackage-server source.
</p></blockquote>
<p>Non-anonymous build reports are essentially complete. Anonymous ones are a bundle of privacy pitfalls, so we&#8217;ll have them as separate feature, using a variant on the data structure currently used to house per-package reports. The idea is to publish them to everyone but do so in a way that mostly eliminates identification or cross-referencing. More on this below.</p>
<blockquote><p>3. 1.5 weeks. Get user accounts and settings working, writing a system for web forms, both the dynamic JavaScript kind and static kind. Use this system to get package configurating [sic] settings editable by both package maintainers and Hackage administrators.
</p></blockquote>
<p>I&#8217;ve written precious little HTML and no JavaScript, instead using curl to prod the server and setting up an Arch VM to ensure compliance with the current (soon to be old?) cabal-install. User accounts, digest authentication, and user groups &#8212; essentially access control lists &#8212; are all here. Most of this information is served in text/plain at the moment. Given that the new server will probably require a redesign by more design-minded Haskellers, I&#8217;d rather keep everything minimalistic for the time being. As I mentioned last post, I think the server architecture has a good separation of model and view.</p>
<blockquote><p>4. 1 week. If a viable solutions for changelogs comes up by this point, I’ll implement it here. This might be as simple as a ./changelog file with a simple prescribed format.</p></blockquote>
<p>That&#8217;s this week! At least 100 packages on Hackage already have changelogs. Of those, about two dozen are named changelog.md (they use markdown fix/feature structure, which git uses). The rest have whichever format the author chose, and these formats are all over the place. Some use darcs changes, which is too fine-grained for Hackage. All this is a too non-uniform for an automatic uniform interface. One approach that I can probably code up in a day or two is to have a changelog editable on Hackage. It could be inputted on upload and possibly edited afterwards by maintainers. Otherwise, I&#8217;ll leave this one until &#8220;a viable solution for changelogs comes up&#8221;.</p>
<h3> What&#8217;s been done </h3>
<p>All of the features I listed <a href="http://cogracenotes.wordpress.com/2010/06/17/hackage-feature-graphs/">in the last blog post</a> have been implemented, although not all of it&#8217;s exposed through HTML. Brief descriptions of them are there. The most interesting one, also proving to be the most challenging, is the candidate packages feature, which an enhanced version of the check-pkg CGI script. Here&#8217;s what you can do with it.</p>
<ul>
<li>/packages/candidates/: see the list of candidate packages. POST here to upload a candidate package; candidates for existing packages can only be added by maintainers.</li>
<li>/package/{package}/candidate: see a preview package page for a candidate tarball, with any warnings or errors that would prevent putting it in the main index</li>
<li>/package/{package}/candidate/publish: POST here to put the package in the main index. It has to be a later version than the latest current existing under the name, and only maintainers can do this. If no package exists under the name, these restrictions don&#8217;t apply.</li>
<li>/package/{package}/candidate/{cabal}: get the cabal file for this package </li>
<li>/package/{package}/candidate/{tarball}: get the tarball</li>
</ul>
<h3> In the immediate future </h3>
<p>I&#8217;d like to get the newer server ready for running on <a href="http://sparky.haskell.org:8080/">sparky</a> by the end of the week. It doesn&#8217;t yet look very different from the current Hackage in terms of what web browsers can access.</p>
<p>Currently there are four ways to start up the server. The first is to initialize it on a blank slate and go from there with <code>hackage-server --initialise</code>. Second, you can start it normally with an existing dataset stored by happstack-state, just <code>hackage-server</code>. Otherwise, you can import from an existing source. You can import mostly everything from the old Hackage server, as I described in <a href="http://cogracenotes.wordpress.com/2010/05/27/state-of-the-hackage/">my first post</a>. Alternatively, you can initialize it from a single backup tarball produced by the server.</p>
<p>I&#8217;d like to revamp the interface to make it easier to deploy. Instead of importing directly from old sources, there&#8217;s going to be an auxiliary mode to convert legacy data into a newer backup tarball. Then, the new tarball can be imported directly. I haven&#8217;t had any backup tarballs on hand to test the newer import/export system, though it compiles. This is next on the todo list.</p>
<p>Some features that I&#8217;d like to get done soon are uploading documentation and implementing deprecation. Deprecated packages might still be needed as dependencies, so they&#8217;re kept around and will probably go in the index tarball, but they won&#8217;t be highly visible on any of the HTML pages. Currently documentation will be implemented by uploading tarballs. This is compatible with the current solution, which is to have a dedicated build client. It would be easier to have users upload their own docs, and not have to deal with the build client not being able to do so. This would be simple if .haddock files provided everything neessary for generating HTML docs and linking them with hscolour pages. I&#8217;m not sure if this is the case. Holding onto .haddock files also makes documentation statistics a lot easier. For now, documentation tarball upload is the route I&#8217;m taking.</p>
<p>Another nice feature would be serving directly from package tarballs, preferrably without having to store them in memory or unpack them on the server filesystem. Like the documentation feature, it would use a data structure defined in the hackage-server source: a TarIndexMap. Given a file path, it can efficiently give you the byte offset of the tar entry where that file is stored, and from that retrieve the file directly. There are some downsides here. First, package tarballs are not .tar but .tar.gz, so this might more-than-double the amount of storage required, which unpacking would do anyway. Second, the TarIndexMap of every single package tarball would be kept in memory, although this uses an efficient trie structure, so it&#8217;s not so bad.</p>
<p>There are also some internal server design challenges, which I&#8217;ll describe in the next two paragraphs; skip them if you like. One of them is making URI generation less clunky. Every resource provides enough information to generate its canonical URI given an association list of string pairs. However, this requires passing around the resource itself, which also contains the server function and other things. I&#8217;m considering making a global map that, given the string name of a resource, gives a URI-generating function, which means either passing this mapping to every single server function or setting up a ReaderT monad around Happstack&#8217;s ServerPartT. The other issue is that a URI is not guaranteed; it&#8217;s wrapped in a Maybe, since this system doesn&#8217;t provide the type safety guarantees of libraries like <a href="http://hackage.haskell.org/package/web-routes">web-routes</a>: it&#8217;s &#8216;stringly typed&#8217;.</p>
<p>In addition, user groups are currently totally decentralized, but perhaps they could use some more coordination. The <a href="http://www.mediawiki.org/wiki/Manual:User_rights">MediaWiki system</a> of having a global mapping for which groups are allowed to execute which permissions is pretty good, though in a typical PHP manner, it uses strings to do this. It might be better for each type of group to list what permissions it can do, rather than having this check in code itself, but again this might require passing this mapping to every single server function.</p>
<h3>Memory and performance</h3>
<p>I&#8217;ve done some rudimentary statistics-gathering, but much more will need to be done soon.</p>
<p>For instance, importing from the old Hackage server causes the memory used by the server to reach around 700MB and stay there (any memory allocated by GHC always stays there), and this is only for the current tarball versions. However, this is only needed for initialization, as I mentioned I plan on making a separate mode for legacy import.</p>
<p>By contrast, starting up the server with the current set of package versions occupies 390 MB of memory, although only 148 MB is used by the RTS at any given time. When initializing the server in this mode, 40% of the CPU time is used on garbage collection, but things seem reasonably stable afterwards. The directory storage with the current tarball versions occupies 130 MB disk space, and the happstack-state database is just 17 MB. This database is pretty small comparatively, likely because it doesn&#8217;t include the parsed PackageDescription data structure, which contains lots of fields and lots of strings.</p>
<p>In general, I think I need some modifications to ensure that GHC isn&#8217;t too heap-hungry, I suspect. Heap profiling has proven suspect thus far, since apparently the sever has a special affinitify for ghc-prim:GHC.Types.:, and if I&#8217;m reading it right I find it somewhat hard to believe that over 90% of the sever&#8217;s memory is used on cons cells. On the other hand, maybe there are that many <code>String</code>s and <code>[Dependency]</code>s. I think later on I&#8217;ll be asking the advice of some more senior Haskell hackers to keep memory usage down, even if one of the selling points of Happstack is that all data&#8217;s in memory. (Not entirely true here: the blob storage is used for package tarballs.)</p>
<h3> In the eventual future </h3>
<p>Build reports are a must-do, and at present authenticated clients can submit build reports and build logs. Anonymous reports are tricky though (but still immensely useful), and I know many of you guys wouldn&#8217;t submit reports without them. Statistics need to be done as well; how to take a large amount of these:</p>
<pre>
package: cabal-install-0.6.2
os: linux
arch: i386
compiler: ghc-6.10.4
client: cabal-install-0.6.0
flags: -bytestring-in-base -old-base
dependencies: Cabal-1.6.0.3 HTTP-4000.0.8 [...]
install-outcome: DependencyFailed zlib-0.5.2.0
docs-outcome: NotTried
tests-outcome: NotTried
</pre>
<p>and tell you something useful about them. Perhaps it could tell you that the above report is not recent.</p>
<p>Also, a solution for systematic client-side and server-side caching of HTML hasn&#8217;t come up yet, if this is in the cards at all. Making an ETag-generating function is <a href="http://www.mnot.net/blog/2007/08/07/etags">not a simple matter</a>, particularly when multiple representations of the same resource are served in multiple formats at multiple URIs (sadly, <a href="http://www.gethifi.com/blog/browser-rest-http-accept-headers">I can&#8217;t rely solely on the Accept header</a>, because browser implementers seemingly read RFCs highlighted with black markers).</p>
<p>Finally, there&#8217;s no clear procedure for migrating data, and I&#8217;m still not fully familiar with Happstack state&#8217;s data versioning system. Apparently both data types need to exist at the same time, and then the old one can be discarded. I could probably write a startup mode for this.</p>
<p>The most eventual of future elements is more shiny features. This future will extend beyond this summer, so while some individual features might deserve Summer of Code projects in their own right, I&#8217;ll try to knock out as many of the others as possible. Let the other 4/7ths begin!</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/cogracenotes.wordpress.com/84/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/cogracenotes.wordpress.com/84/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=cogracenotes.wordpress.com&#038;blog=13902430&#038;post=84&#038;subd=cogracenotes&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://cogracenotes.wordpress.com/2010/06/29/hackage-37ths-mark/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/3bd40df9a068bccc83b33b742c4a869d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">cogracenotes</media:title>
		</media:content>
	</item>
		<item>
		<title>Hackage GSoC: Feature graphs and URI trees</title>
		<link>http://cogracenotes.wordpress.com/2010/06/17/hackage-feature-graphs/</link>
		<comments>http://cogracenotes.wordpress.com/2010/06/17/hackage-feature-graphs/#comments</comments>
		<pubDate>Thu, 17 Jun 2010 21:00:23 +0000</pubDate>
		<dc:creator>cogracenotes</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://cogracenotes.wordpress.com/?p=58</guid>
		<description><![CDATA[Hello Haskellers! I&#8217;ve made lengthy strides in the internal structure of the new Hackage server. Amidst implementing features, I&#8217;ve also implemented a reasonably solid top-level organization for them. I&#8217;ll describe some of the technical details of the structure here. Feature graphs Each feature has a listing of the URIs it provides, the user groups it [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=cogracenotes.wordpress.com&#038;blog=13902430&#038;post=58&#038;subd=cogracenotes&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>Hello Haskellers! I&#8217;ve made lengthy strides in the internal structure of the new <a href="http://hackage.haskell.org">Hackage</a> server. Amidst implementing features, I&#8217;ve also implemented a reasonably solid top-level organization for them. I&#8217;ll describe some of the technical details of the structure here.</p>
<h2>Feature graphs</h2>
<p>Each feature has a listing of the URIs it provides, the user groups it needs to authenticate, and the data it needs to store with methods to back up and restore that data. A feature might also define caches for its pages, IO hooks to execute on certain events (like uploading a package), and pretty much anything else: features are arbitary datatypes that implement a HackageFeature typeclass. If feature A depends on feature B, then feature A can extend B&#8217;s URIs with new formats and HTTP methods, use B&#8217;s data and user groups, and register for any of B&#8217;s hooks.</p>
<p>The barebones features are:</p>
<ul>
<li> core: the central functionality set for something to reasonably be called a Hackage server. This serves tarballs, cabal files, and basic listings. The data it maintains are the user database and a map from <code>PackageName</code> to <code>[PkgInfo]</code> (see <a href="http://cogracenotes.wordpress.com/2010/06/07/hackage-modular-features/">previous post</a>). It is possible to create a core-only server with an archive.tar, but it&#8217;s effectively immutable after initialization.</li>
<li> mirror: this allows tarballs to be uploaded directly by special clients, and it is intended for use by secondary Hackages (if any) which need to stay up to date without having to support a userbase. This doesn&#8217;t use its own data, instead manipulating the core&#8217;s.</li>
</ul>
<p><a href="http://imgur.com/Zaxbm.png"><img src="http://imgur.com/Zaxbm.png" width="490px" /></a></p>
<p>Now, take a look at the packages, upload, check, users, distros, and build features. Some of then depend on each other. They all depend on core. html depends on all of them. One way to look at the organization is that they provide the model and controller for data and html provides a view. They are interfaces which provide their own data in a way which html/json/xml/yaml/whichever other features can render in their particular format with a minimal amount of effort.</p>
<p>For example, the packages feature doesn&#8217;t define any of its own URIs, but has a function, <code>PackageId -&gt; IO (Maybe PackageRender)</code>, which the HTML package page calls. The <code>PackageRender</code> type is essentially the One True Resource Representation of a package, and it looks like this:</p>
<pre>data PackageRender = PackageRender {
    -- using the most recently uploaded package as of now
    rendPkgId :: PackageIdentifier,
      -- <a href="http://hackage.haskell.org/package/Vec-0.9.8">Vec-0.9.8</a>
    rendAllVersions :: [Version],
      -- [0.9.0, 0.9.1, 0.9.2, 0.9.3, 0.9.4,
          0.9.5, 0.9.6, 0.9.7, 0.9.8]
    rendDepends :: [[Dependency]],
      -- [[array, base (≤5), ghc-prim, QuickCheck (2.*)]]
    rendExecNames :: [String],
      -- [] (no executables)
    rendLicenseName :: String,
      -- <a href="http://www.opensource.org/licenses/bsd-license.php">BSD 3</a>
    rendMaintainer :: Maybe String,
      -- Just "Scott"
    rendCategory :: [String],
      -- ["Data", "Math"]
    rendRepoHeads :: [(RepoType, String, SourceRepo)],
      -- [] (no repository)
    rendModules :: Maybe ModuleForest,
      -- Just a tree containing Data.Vec.*
    rendHasTarball :: Bool,
      -- True
    rendUploadInfo :: (UTCTime, String),
      -- (Jun 17 2010, "Scott")
    rendOther :: PackageDescription
      -- the <a href="http://hackage.haskell.org/packages/archive/Vec/0.9.8/Vec.cabal">package description</a>
}</pre>
<p>From this, the html feature can make a package page that looks like the <a href="http://hackage.haskell.org/package/Vec-0.9.8">current one</a>, where 95% of its work is HTML formatting via <a href="http://hackage.haskell.org/package/xhtml">Text.XHtml.Strict</a>. A json feature could use the same information to make a data-rich nest of curly braces.</p>
<p>Now, a paragraph or two about a failed approach. I also considered having each feature provide its own HTML. This is perhaps the simplest approach on the face of it. However, it gets tricky to, say, define a package page and then later append to it for newer features. I considered HTML hooks where a feature could provide an interface to anyone who wants to inject <code>Html</code> blocks into its pages. For example, a build reports feature would have to register for a hook so that the main package page can link to the reports page.</p>
<p>This has several disadvantages, the most prominent of which is that it makes it cumbersome to switch to a different HTML-generating library or add new formats. I just accepted that HTML was an exceptionally unmodular thing. Instead, what the HTML feature now does is depend on both the build reports feature and the packages feature, and this also allows free-form HTML instead of copy+paste amalgamations, which I&#8217;ve heard can be rather ugly. The metric to go by here is &#8220;out of all modifications one could imagine making to the server, how can I make them implementable modifying the minimum number of modules?&#8221; (I haven&#8217;t considered using partial derivatives to optimize the minimum&#8230; yet.)</p>
<p>Here is a brief description of the middle features:</p>
<ul>
<li> packages: just package pages</li>
<li> upload: authenticated users can upload new packages, with some checking in place: can&#8217;t overwrite packages, can only upload a new version if a maintainer, and so on. Adds a maintainer/author group for each package. By contrast, the mirror feature overwrites packages without question.</li>
<li> check: checking packages before indexing them and providing candidate packages (see <a href="http://cogracenotes.wordpress.com/2010/06/07/hackage-modular-features/">previous post</a>)</li>
<li> users: user pages, password-changing, currently using core and not storing any data of its own</li>
<li> distros: linking Hackage with Arch, Debian, and any other distribution with package repositories with Haskell binaries. These distributions can PUT and DELETE to Hackage to indicate the addition and removal of these packages.</li>
<li> build: submission of build reports, both anonymous and with full compilation logs</li>
</ul>
<p>And finally, an ad hoc but nonetheless important feature:</p>
<ul>
<li> legacy: a pile of 301 redirects so that <a href="http://hackage.haskell.org/trac/hackage/wiki/HackageDB/2.0/OldURIs">old URIs</a> can mostly work (in particular, links to /cgi-bin/hackage-scripts/package/foobar posted on mailing lists 4 years ago will still work)</li>
</ul>
<p>Features each have their own particular init functions. For instance, the function to initialize the HTML module is currently:</p>
<pre>initHtmlFeature :: CoreFeature -&gt; PackagesFeature -&gt; IO HtmlFeature</pre>
<h2>URI trees</h2>
<p>I would have written this up yesterday but I&#8217;ve spent the last 24 hours implementing a new and improved routing system. All of the magic happens in <code>impl</code>, the <code>ServerPart Response</code> which is given to Happstack&#8217;s <code>simpleHTTP</code>.</p>
<pre>
impl :: Server -&gt; ServerPart Response
impl server =
    renderServerTree (serverConfig server) []
  -- ServerTree ServerResponse
  . fmap serveResource
  -- ServerTree Resource
  . foldl' (\acc res -&gt; addServerNode (resourceLocation res) res acc)
           serverTreeEmpty
  -- [Resource]
  $ concatMap resources (serverFeatures server)
</pre>
<p>This seems pretty terse for what&#8217;s effectively the server&#8217;s main method, but complexity lurks just beneath the surface. It all starts with lists of resources, each server feature providing its own list, which are concatenated into a <code>[Resource]</code>. A <code>Resource</code> contains a URI, and how to respond when that URI is visited for certain combinations of HTTP methods and content-types. Although I&#8217;ve never coded a line of Ruby in my life, I stole some of Rails&#8217; routing syntax for this task (also stolen by the Pylons web framework, apparently). Here&#8217;s how it works:</p>
<ul>
<li> A resource at &#8220;/users/login&#8221; will be run only when /users/login is visited, assuming it&#8217;s a GET request.
<li> A resource at &#8220;/package/:package&#8221; will be run when /package/HDBC is visited, but also when /package/nonexistent-1.0 is entered. It&#8217;s passed <code>[("package", "HDBC")]</code> in the former case, and there are combinators to turn assoc lists into data values (<code>type DynamicPath = [(String, String)]</code> and a combinator <code>withPackagePath :: DynamicPath -&gt; (PackageId -&gt; PkgInfo -&gt; ServerPart Response) -&gt; ServerPart Response</code>). It&#8217;s up to the resource to return a 404 if it can&#8217;t abide by the URI.
<li> A resource at &#8220;/package/:package/doc/&#8230;&#8221; will be run when /package/uvector/doc/ or any subdirectory is visited, and it&#8217;s likewise passed an appropriate assoc list.
<li> I can specify &#8220;/package/:package/:cabal.cabal&#8221;, and when /package/parsec-3.1.0/parsec.cabal is visited, the resource is given <code>[("package", "parsec-3.1.0"), ("cabal", "parsec")]</code> (the extension is stripped off).
<li> And the most complicated one: &#8220;/package/:package.:format&#8221;. This works for /package/QuickCheck (<code>[("package", "QuickCheck"), ("format", "")]</code>), or /package/llvm-0.8.0.2.json (<code>[("package", "llvm-0.8.0.2"), ("format", "json")]</code>). An empty format means to go for the default, in this case HTML.
</ul>
<p>Server trees provide a way for efficiently serving an entire tree of URIs. Starting from an empty server tree, resources are incrementally added, and when two share the same URI format they are combined. For example, the simplified Hackage URI tree is:</p>
<p><a href="http://imgur.com/h71BF.png"><img src="http://imgur.com/h71BF.png" width="490px" /></a></p>
<p>The relevant types are:</p>
<pre>
data ServerTree a = ServerTree {
    nodeResponse :: Maybe a,
    nodeForest :: Map BranchComponent (ServerTree a)
}
</pre>
<pre>
data BranchComponent = StaticBranch String -- /foo
                     | DynamicBranch String -- /:bar
                     | TrailingBranch -- /...
</pre>
<pre>
addServerNode :: Monoid a =&gt; [BranchComponent] -&gt; a
              -&gt; ServerTree a -&gt; ServerTree a
</pre>
<p>Finally, I have a 100-line function for converting resources into something Happstack can read (to be broken up shortly, I hope). It&#8217;s called <code>serveResource</code>, and it&#8217;s how I convert a <code>ServerTree Resource</code> into a <code>ServerTree ServerResponse</code> via <code>ServerTree</code>&#8216;s <code>Functor</code> instance. Then the tree is converted to its final flat form, using Happstack&#8217;s path-munching combinators to traverse each node&#8217;s forest.</p>
<pre>serveResource :: Resource -&gt; ServerResponse</pre>
<pre>
renderServerTree :: Config -&gt; DynamicPath
                 -&gt; ServerTree ServerResponse
                 -&gt; ServerPart Response
</pre>
<p>If this effort is a success, I won&#8217;t have to deal with the <code>ServerTree</code> type in any great detail for the rest of the summer. I&#8217;ve pushed all of the above code to the <a href="http://code.haskell.org/hackage-server">hackage-server</a> repository.</p>
<p>Thanks for perusing my run-through of some of the internal server design and my exploration of the problem domain. I&#8217;ve also been reading the other GSOC blogs, including Marco&#8217;s progress on Immix. I had idly considered applying for that, but given my near-total unfamiliarity with the GHC RTS, I think it would&#8217;ve been more than a bit difficult for me. I can see he&#8217;s doing a great job, too. Still, there are some things I appreciate about using Haskell and not C in my project. Not only does the type system prevent a host of runtime errors, it also forces me to consider all possible sorts of values which can inhabit a given type and write a case for each one. This is something that&#8217;s come in handy a lot in the past few days. Well, now on to actually implementing features in detail. I&#8217;ll keep you all posted.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/cogracenotes.wordpress.com/58/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/cogracenotes.wordpress.com/58/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=cogracenotes.wordpress.com&#038;blog=13902430&#038;post=58&#038;subd=cogracenotes&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://cogracenotes.wordpress.com/2010/06/17/hackage-feature-graphs/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/3bd40df9a068bccc83b33b742c4a869d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">cogracenotes</media:title>
		</media:content>

		<media:content url="http://imgur.com/Zaxbm.png" medium="image" />

		<media:content url="http://imgur.com/h71BF.png" medium="image" />
	</item>
		<item>
		<title>Hackage GSoC: Beginnings of an Infrastructure for Modular Features</title>
		<link>http://cogracenotes.wordpress.com/2010/06/07/hackage-modular-features/</link>
		<comments>http://cogracenotes.wordpress.com/2010/06/07/hackage-modular-features/#comments</comments>
		<pubDate>Mon, 07 Jun 2010 06:32:32 +0000</pubDate>
		<dc:creator>cogracenotes</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://cogracenotes.wordpress.com/?p=33</guid>
		<description><![CDATA[Hi everyone. The process of transforming the Hackage codebase is ongoing, and I&#8217;ve made some sweeping changes and introduced a few regressions. (I&#8217;d more optimistically call them &#8220;todo list items&#8221;.) I&#8217;ve spent 3/4 of the last week working on the code base, and 1/4 reading books and websites and working on the site design. Site [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=cogracenotes.wordpress.com&#038;blog=13902430&#038;post=33&#038;subd=cogracenotes&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>Hi everyone. The process of transforming the <a href="http://hackage.haskell.org">Hackage</a> codebase is ongoing, and I&#8217;ve made some sweeping changes and introduced a few regressions. (I&#8217;d more optimistically call them &#8220;todo list items&#8221;.) I&#8217;ve spent 3/4 of the last week working on the code base, and 1/4 reading books and websites and working on the site design. Site design here refers to the interface that everyone who uses Hackage sees, and I&#8217;ve posted a <a href="http://hackage.haskell.org/trac/hackage/wiki/HackageDB/2.0/URIs">preliminary draft</a> of the proposed URIs.</p>
<p>The goal is to make a REST API which can be read and manipulated by automated clients, and of course perused by web browsers just like the current Hackage. One of the purposes of <a href="http://en.wikipedia.org/wiki/REST">REST</a> (Representational State Transfer) is simplifying state between the client and server by manipulating representation of resources using plain old HTTP.</p>
<p>Those Haskellers who are familiar with REST might point out that documenting an API and setting up URI conventions (like I did on the Hackage wiki) are partly antithetical to the goals of REST, which eschew servers that only understand highly specific remote procedural calls and clients which construct URIs based on hard-coded conventions (coupling). Roy Fielding, the inventor of REST, stresses that <a href="http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven">REST APIs must be hypertext-driven</a>. Don&#8217;t worry: my intention is to make all of the URIs fully discoverable from the server root, whether browsing the HTML representation or, say, a JSON version. The URI page is an aid in design, not documentation. Since there tends to be a one-to-one mapping between each URI/method pair I&#8217;ve listed and each feature I&#8217;d like to implement, it tells me what I have left to do.</p>
<h2>Fine-tuning data structures</h2>
<p>To this end, I&#8217;ve made and committed some changes to <a href="http://code.haskell.org/hackage-server/">hackage-server</a>. Some of time was spent adjusting a few important types, and the rest dealing with the subsequent code breakages. It is still better and safer than doing similar things in a dynamically typed programming language, where I&#8217;d end up either sweeping the entire code base or analyzing call graphs manually to determine what broke. Here&#8217;s an example of a type I altered, the <code>PkgInfo</code> type, which holds information about a specific package version:</code></p>
<pre>data PkgInfo = PkgInfo {
    -- | The name and version represented here
    pkgInfoId :: !PackageIdentifier,
    -- | Parsed information from the cabal file.
    pkgDesc   :: !GenericPackageDescription,
    -- | The current .cabal file text.
    pkgData   :: !ByteString,
    -- | The actual package .tar.gz file, where BlobId
    -- is a filename in the state/blobs/ folder.
    -- The head of the list is the current package tarball.
    pkgTarball :: ![(BlobId, UploadInfo)],
    -- | Previous .cabal file texts, and when they were uploaded.
    pkgDataOld :: ![(ByteString, UploadInfo)],
    -- | When the package was created with the .cabal file.
    pkgUploadData :: !UploadInfo
} deriving (Typeable, Show)</pre>
<pre>type UploadInfo = (UTCTime, UserId)</pre>
<p>The global Hackage state defines a mapping from <code>PackageName</code> to <code>[PkgInfo]</code>. Subtle differences in which types of values are allowed to inhabit <code>PkgInfo</code> have important consequences for package uploading policy. There are a few notable results of this definition.</p>
<ol>
<li> A package can exist without a tarball. This is more significant for importing data to create secondary Hackages than the normal upload process. The more incrementally importing can happen, the simpler it will be. Alternatively, this would allow for a metadata-only Hackage mirror.</li>
<li> Cabal files can be updated, with a complete history, without having to change the version number. This would allow maintainers to expand version brackets or compiler flags, so long as the changes don't break anything (constricting version brackets is more dangerous).</li>
<li> Tarballs can be updated, also with a complete history, without having to change the version number. This probably won't be enabled on the main Hackage, but exceptions can be granted by admins. If an ultra-unstable Hackage mirror came about, as opposed to the somewhat-unstable model we have now, this might be allowed.</li>
</ol>
<h2>Modular RESTful features</h2>
<p>The <code>HackageFeature</code> data structure is intended to encapsulate the behavior of a feature and its state. Features include the core feature set—the minimal functionality that a server must have to be considered a Hackage server, which is serving package tarballs and cabal files—supplemented by user accounts, package pages, reverse dependencies, Linux distro integration, and so on.</p>
<p>The most important field of a feature is the <code>locations :: [(BranchPath, ServerResponse)]</code>. The <code>BranchPath</code> is the generic form of a URI, a list of <code>BranchComponent</code>s. Taking inspiration from <a href="http://guides.rubyonrails.org/routing.html">Ruby on Rails routing</a>, you can construct one with the syntax <code>"/package/:package/reports/:id"</code>, where visiting <code><a href="http://hackage.haskell.org/HDBC/reports/4/" rel="nofollow">http://hackage.haskell.org/HDBC/reports/4/</a></code> will pass <code>[("package", "HDBC"), ("id", "4")]</code> to the code serving build reports. You can define arbitrary <code>ServerPart Response</code>s at a path, or you can use a <code>Resource</code> abstraction which lets you specify different HTTP methods (GET, POST, PUT, and DELETE). This system is still in development.</p>
<h2>HTTP goodies</h2>
<p>Because each resource defines its method set upfront, it's possible to make an <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.2">HTTP OPTIONS method</a> for each one. This is an example of something you get "for free" by structuring resources in certain ways. As I've discovered, there can be an unfortunate trade-off: requiring too much structure makes it unpleasant to extend Hackage with new functionality (having to deal with all of the guts of the server). Too little structure means that those implementing new features can accidentally break the site's design principles and generally cause havoc. A reasonable middle ground is the convention over configuration approach: I'd have plenty of configurable structure internally, and combinators which build on that structure by filling in recommended conventions. This applies particularly to getting the most out of HTTP.</p>
<p>The idea of content negotiation in HTTP is simple, although there's no clear path ahead for implementing it yet. For Hackage, content negotiation consists of responding to preferences in the client's Accept header, which contains MIME types with various priorities. (Other sorts of negotiation include those for languages and encoding.) A web browser like Firefox might send<br />
<code>text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8</code>, and a hypothetical newer cabal-install client would send <code>application/json</code> for miscellaneous data it needs to read.</p>
<p>Authentication functionality is essentially done, although I had originally planned to work on it later this month. The types might still need some tweaking, of course. There is a system of access control lists called <code>UserList</code>s, each of which is a <code>Data.IntSet</code> of <code>UserId</code>s. With this, we can have an extensible hierarchy of user groups, such as site administrators, per-package maintainers, and trustees (allowed to manipulate all packages without possessing other admin functionality). The type signature for the main authentication function is:</p>
<pre>requireHackageAuth :: MonadIO m =&gt; Users -&gt; Maybe UserList
                        -&gt; Maybe AuthType -&gt; ServerPartT m UserId</pre>
<p><code>Users</code> is the type containing the site's entire user database. <code>AuthType</code>, either <code>BasicAuth</code> or <code>DigestAuth</code>, can be passed in to force the type of authentication: either <a href="http://en.wikipedia.org/wiki/Basic_access_authentication">basic</a> or <a href="http://en.wikipedia.org/wiki/Digest_access_authentication">digest</a>. Since all passwords are currently hashed in crypt form. This method either returns the <code>UserId</code>, assuming authentication succeeded, or forces a 401 Unauthorized or 403 Forbidden. With this, we can easily extend it to handle specific tasks:</p>
<pre>requirePackageAuth :: (MonadIO m, Package pkg) =&gt; pkg
                                       -&gt; ServerPartT m UserId
requirePackageAuth pkg = do
    userDb &lt;- query $ GetUserDb
    pkgm   &lt;- query $ GetPackageMaintainers
                            (packageName pkg)
    trust  &lt;- query $ GetHackageTrustees
    let groupSum = Groups.unions [trust, fromMaybe Groups.empty pkgm]
    requireHackageAuth userDb (Just groupSum) Nothing</pre>
<h2>Import/export</h2>
<p>To paraphrase Don's comment on my previous post, we absolutely can't afford to lose any data. Although the <code>state/db/</code> directory contains all of happstack-state's MACID data, and can be periodically backed-up off-site, binary data is by nature easy to mess up and hard to recover. A bit of redundancy in storage is a reasonable safeguard, and there's little more redundant than English, at least compared to bit-packing.</p>
<p>Antoine had implemented an extensive Hackage-to-CSV export/import system, where instead of e.g. having a single bit represent whether an account is enabled or disabled, we use the words "enabled" and "disabled", and put the resulting export tarball in a safe place. Instead of having one centralized system, each <code>HackageFeature</code> should take care of its own data, and so I'd like to work on decentralizing the system in the days ahead. The type signatures, suggested by Duncan, are:</p>
<pre>data HackageFeature = {
    ...
    dumpBackup     :: IO [BackupEntry],
    restoreBackup  :: [BackupEntry] -&gt; IO (),
    ...
}</pre>
<pre>type BackupEntry = ([FilePath], ByteString)</pre>
<h2>Bringing features together</h2>
<p>There are notable tasks remaining for the basic infrastructure, such as implementing this import/export system. Another major one is creating a hook system with the usual dual nature of one part that responds to actions (like uploading pages) and another which edits documents on the fly (like adding sections to a package page). If you have experience with website plugin systems, what are your thoughts on getting this done this in a strongly, safety typed manner?</p>
<p>Having taken a brief tour of the internal server proto-design and the types of functionality that can be implemented with it, I'd like to show how we can leverage these to implement some useful features, some this summer if we as a community approve of them:</p>
<ul>
<li>Build reports, to see if a given package builds on your OS (might save time for unfortunately oft-neglected Windows-users), on your architecture, with your set of dependencies. I would strongly encourage all of you to at least submit anonymized build reports once the feature goes live (check out the <a href="http://darcs.haskell.org/cabal-install/Distribution/Client/BuildReports/">client-side implementation</a>), if not the full build log, although I promise we won't stoop to a "Do you want to submit a build report?" query every single time a build fails: maybe only just the first time :)  Submitting or not is more of a configuration option. Build reports will probably be anonymized for the public interface, but available in full to package maintainers through the <code>requireHackageAuth</code> authentication mechanism.</li>
<li>Reverse dependencies. This is a <code>HackageFeature</code> that doesn't need to define any of its own persistent data, just its own compact index of depedencies that subscribes to a package uploading hook. You can peruse <a href="http://bifunctor.homelinux.net/~roel/hackage/packages/hackage.html">Roel's revdeps Hackage</a>, and if you feel like setting up <a href="http://darcs.haskell.org/hackage-scripts/">hackage-scripts</a> with Apache, you can apply <a href="http://hackage.haskell.org/trac/hackage/ticket/576">his patch</a> to run your own.</li>
<li>Hackage mirrors. It should be simple to write a mirroring client that polls <a href="http://hackage.haskell.org/packages/archive/recent.html">hackage.haskell.org's recent changes</a>, retrieves the new tarballs, and HTTP PUTs them to a mirror with proper authentication.</li>
<li>Candidate package uploads: improved package checking. This would allow you to create a temporary package resource, perhaps available at <code>/package/:package/candidate/</code>, to augment the current checking system. Currently, checking gives you a preview of the package page with any Cabal-generated warnings. Here, you could set up a package on the Hackage website that's not included on the package list or index tarball. It would employ its own mapping from <code>PackageName</code> to <code>PkgInfo</code>. You can make a candidate package go live at any time, even allowing others to install your candidate package before then. This is a slightly different idea from the ultra-unstable zoo of packages I mentioned with <code>PkgInfo</code>, but has similar quality assurance goals.</li>
</ul>
<p><!-- As a side note, I know many people would like to see Hackage better integrated with public repositories like Github or those living on code.haskell.org. This is a half-thought at the moment. --></p>
<p>Thanks for reading what I've been up to. Critique is welcomed.</p>
<p></code></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/cogracenotes.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/cogracenotes.wordpress.com/33/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=cogracenotes.wordpress.com&#038;blog=13902430&#038;post=33&#038;subd=cogracenotes&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://cogracenotes.wordpress.com/2010/06/07/hackage-modular-features/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/3bd40df9a068bccc83b33b742c4a869d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">cogracenotes</media:title>
		</media:content>
	</item>
		<item>
		<title>State of the Hackage</title>
		<link>http://cogracenotes.wordpress.com/2010/05/27/state-of-the-hackage/</link>
		<comments>http://cogracenotes.wordpress.com/2010/05/27/state-of-the-hackage/#comments</comments>
		<pubDate>Thu, 27 May 2010 23:12:34 +0000</pubDate>
		<dc:creator>cogracenotes</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://cogracenotes.wordpress.com/?p=1</guid>
		<description><![CDATA[This summer (2010), I&#8217;ve tasked myself with porting the current Hackage codebase, which is served at hackage.haskell.org to web browsers and cabal-install processes alike, to a newer one which is still in development but nonetheless pretty polished. The older one is known as hackage-scripts, and you can find it here: $ darcs get http://darcs.haskell.org/hackage-scripts/ Its [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=cogracenotes.wordpress.com&#038;blog=13902430&#038;post=1&#038;subd=cogracenotes&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>This summer (2010), I&#8217;ve tasked myself with porting the current Hackage codebase, which is served at <a href="http://hackage.haskell.org">hackage.haskell.org</a> to web browsers and cabal-install processes alike, to a newer one which is still in development but nonetheless pretty polished. The older one is known as hackage-scripts, and you can find it here:</p>
<pre>$ darcs get <a href="http://darcs.haskell.org/hackage-scripts/">http://darcs.haskell.org/hackage-scripts/</a></pre>
<p>Its primary goal is to serve both cabal files (package metadata) for the cabal-install tool to parse and package tarballs for it to compile, and the server uses a glorified directory tree to accomplish this. It also has a minimalistic web interface for finding packages, viewing their metadata, and perusing Haddock-generated documentation. hacakge-scripts uses a combination of static files and <a href="http://hackage.haskell.org/package/cgi">Network.CGI executables</a>, which are invoked by the web server, read information about the request using the <a href="http://en.wikipedia.org/wiki/Common_Gateway_Interface">CGI specification</a>, and then print the HTML response to standard output. Not the least of these scripts is the one that uploads new packages, using either <code>cabal upload</code> or the web interface.</p>
<p>hackage-scripts is portable in that it should run on any standard Apache installation. Unfortunately, it usually doesn&#8217;t run out of the box. The directory tree and static files have to be set up manually, and the Makefile and source code need to be hardcoded with pathnames indicating where the set up is. Even if you can&#8217;t get it running on your own, it is happily chugging away on hackage.haskell.org, which your cabal configs (<code>~/.cabal/config</code>) undoubtedly point to.</p>
<p>The candidate replacement is known simply as hackage-server, and you can get it here in its pre-summer-of-code state:</p>
<pre>$ darcs get <a href="http://code.haskell.org/hackage-server/">http://code.haskell.org/hackage-server/</a></pre>
<p>It uses the <a href="http://happstack.com/">Happstack web framework</a> to deconstruct URIs by their path hierarchy, rather than letting Apache root through a large directory tree of mostly static files. It also uses the <a href="http://hackage.haskell.org/package/happstack-state">happstack-state package</a>, at present keeping approximately 186 MiB of package data for 8376 package versions in memory to serve requests, falling back to the disk for larger files such as the package tarballs.</p>
<p>This summer&#8217;s project is particular in that it involves work on a code base which most Haskellers won&#8217;t install themselves, but provides a service most of us will end up dealing with frequently. This makes it important to get right from an architecture standpoint. Nonetheless, I hope to make it painless to set up a secondary Hackage repository as a drop-in replacement for the main one, potentially allowing you to pull from a variety of sources of varying stabilities. Setting up a server on <code><a href="http://localhost:8080/" rel="nofollow">http://localhost:8080/</a></code> over an empty repository is as easy as changing to the repository&#8217;s top-level Darcs directory for the repository and running</p>
<pre>$ cabal install
$ hackage-server --initialise</pre>
<p>(albeit not as easy if the dependencies end up failing: I had to change the Happstack dependency brackets in hackage-server.cabal from ==0.4.* to ==0.5.* because I use an older base) Setting up a haskell.hackage.org clone with the current tarballs is a bit more complex, but within the realm of science to solve!</p>
<pre style="overflow:auto;">$ cabal install
$ wget -P /tmp <a href="http://hackage.haskell.org/cgi-bin/hackage-scripts/archive.tar">http://hackage.haskell.org/cgi-bin/hackage-scripts/archive.tar</a>
$ wget -P /tmp <a href="http://hackage.haskell.org/packages/archive/00-index.tar.gz">http://hackage.haskell.org/packages/archive/00-index.tar.gz</a>
$ wget -P /tmp <a href="http://hackage.haskell.org/packages/archive/log">http://hackage.haskell.org/packages/archive/log</a>
$ echo 'admin:wywGGkc7Qc/6I' &gt; /tmp/htpasswd
$ echo 'admin' &gt; /tmp/adminlist
$ hackage-server --import-index=/tmp/00-index.tar.gz \
    --import-log=/tmp/log --import-accounts=/tmp/htpasswd \
    --import-archive=/tmp/archive.tar \
    --import-admins=/tmp/adminlist</pre>
<p>Be warned: archive.tar is 128MB at the moment! As for <code>wywGGkc7Qc/6I</code>, it is one of 4096 crypt-salted hashings of the password <code>admin</code>. On Wednesday I implemented <a href="http://en.wikipedia.org/wiki/Digest_access_authentication">digest authentication</a>, which would instead hash <code>admin:hackage:admin</code> in MD5 and use a nonce challenge/response for reasonably secure authentication (the <a href="http://en.wikipedia.org/wiki/Basic_access_authentication">current scheme</a> sends your password in <a href="http://en.wikipedia.org/wiki/Base64" title="Base64">near-plaintext</a> with every request). I found a <a href="http://code.google.com/p/chromium/issues/detail?id=45194">minor Chromium bug</a> in the process, too!</p>
<p>Tersely put, the design goals are for hackage-server to become a more consistent, extensible, modular and (most importantly) runnable Hackage server. This means duplicating the existing functionality, a task mostly done by Antoine Latter and Duncan Coutts in the span of the last two years, and organizing the modules into a URI hierarchy that obeys <a title="Representational State Transfer" href="http://en.wikipedia.org/wiki/Representational_State_Transfer">REST</a> and <a title="Resource Oriented Architecture" href="http://en.wikipedia.org/wiki/Resource_oriented_architecture">ROA</a> principles. I&#8217;ve outlined all of the resources Hackage currently provides (partially listed on the <a href="http://hackage.haskell.org/trac/hackage/wiki/HackageDB#Structure">trac wiki</a>), and I&#8217;m working on a mapping to a new and improved set of URIs.</p>
<p>For the more commonly accessed Hackage URIs (those that have been linked from other websites or hardcoded in cabal), backwards-compatibility is a priority, and mostly already implemented as a series of 301 redirects. Such a legacy redirect system might be considered a &#8220;feature&#8221;, a plug-in functionality which can be enabled and disabled. Part of making the new Hackage modular and hackable is defining a consistent interface for features. Much like <a href="http://www.haskell.org/haskellwiki/Lambdabot">lambdabot</a>&#8216;s Module typeclass, each feature can be defined discretely, and the behavior of the web server becomes the msum of each feature&#8217;s <a href="http://happstack.com/docs/0.5.0/happstack-server/Happstack-Server-SimpleHTTP.html#2">ServerPart Response</a>.</p>
<p>The above is the state of affairs on Day 1 (well, Day 4, but I&#8217;m still getting started with these new-fangled blags!). The title of my proposal is &#8220;<a href="http://cogracenotes.wordpress.com/hackage-proposal/">Infrastructure for a more social Hacakge 2.0</a>&#8220;, not &#8220;A more social Hackage 2.0&#8243;. I expect that the exact array of social services that Hackage will provide will need a hefty bout of fine-tuning and analysis (see also <a href="http://cdsmith.wordpress.com/2010/04/23/enforcing-stability-in-hackage-some-thoughts/">some insightful thoughts on this</a>), so my job is to provide the technical base to make the shiny new features easy to plug in and modify, as well as implementing as many as possible in a mad rush of coding late July and early August.</p>
<p>If you have any kind of wish list for Hackage features, it is imperative that you let me know—eventually. Duncan and others have encouraged me to concentrate on setting up the infrastructure before building features, so at some point I&#8217;ll try to facilitate a community discussion about what you all want to see in our favorite package repository. If you need me, you can find me as Gracenotes on the #haskell and #hackage channels on irc.freenode.net. And best of luck to my fellow gsoc-ers, whose blogs I&#8217;ve linked in the sidebar.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/cogracenotes.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/cogracenotes.wordpress.com/1/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=cogracenotes.wordpress.com&#038;blog=13902430&#038;post=1&#038;subd=cogracenotes&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://cogracenotes.wordpress.com/2010/05/27/state-of-the-hackage/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/3bd40df9a068bccc83b33b742c4a869d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">cogracenotes</media:title>
		</media:content>
	</item>
	</channel>
</rss>
