<?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/"
	>

<channel>
	<title>teideal glic deisbhéalach &#187; web</title>
	<atom:link href="http://www.serpentine.com/blog/category/web/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.serpentine.com/blog</link>
	<description>Bryan O&#039;Sullivan&#039;s blog</description>
	<lastBuildDate>Thu, 01 Dec 2011 16:53:49 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Minuscule linkscrape of mischief</title>
		<link>http://www.serpentine.com/blog/2010/01/30/massive-linkscrape-of-mischievous-doom/</link>
		<comments>http://www.serpentine.com/blog/2010/01/30/massive-linkscrape-of-mischievous-doom/#comments</comments>
		<pubDate>Sat, 30 Jan 2010 00:32:26 +0000</pubDate>
		<dc:creator>Bryan O'Sullivan</dc:creator>
				<category><![CDATA[slice-o-life]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[lolwut]]></category>

		<guid isPermaLink="false">http://www.serpentine.com/blog/?p=564</guid>
		<description><![CDATA[While I&#8217;ve been in my corner hacking on low-level Haskell nonsense, apparently someone figured out how to make the internets more better. To wit, a few judiciously curated sources of visual edification: for great justice unhappy hipsters riot right click]]></description>
			<content:encoded><![CDATA[<p>While I&#8217;ve been in my corner hacking on low-level Haskell nonsense, apparently someone figured out how to make the internets more better.</p>
<p>To wit, a few judiciously curated sources of visual edification:</p>
<p><a href="http://forgreatjustice.tumblr.com/post/359166403/dont-worry-im-from-the-internet"><img src="http://27.media.tumblr.com/tumblr_kwz785G6N01qalbabo1_500.jpg" alt="I'm from the internet" /></a>
<br/><a href="http://forgreatjustice.tumblr.com/">for great justice</a></p>
<p><a href="http://unhappyhipsters.com/post/354725045/the-octopus-was-full-of-judgment-dwell-october"><img src="http://27.media.tumblr.com/tumblr_kwvcm5BExl1qam6ylo1_500.jpg" alt="The octopus was full of judgment" /></a><br/>
<a href="http://unhappyhipsters.com/">unhappy hipsters</a></p>
<p><a href="http://riotclitshave.livejournal.com/1693322.html"><img src="http://riotclitshave.com/2010.01/megan-dscf2656jpg.jpeg" alt="Ooooooh" /></a><br/>
<a href="http://riotclitshave.livejournal.com/">riot right click</a></p>]]></content:encoded>
			<wfw:commentRss>http://www.serpentine.com/blog/2010/01/30/massive-linkscrape-of-mischievous-doom/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>A new (well, to me) spam vector: google.com</title>
		<link>http://www.serpentine.com/blog/2008/01/10/a-new-well-to-me-spam-vector-googlecom/</link>
		<comments>http://www.serpentine.com/blog/2008/01/10/a-new-well-to-me-spam-vector-googlecom/#comments</comments>
		<pubDate>Fri, 11 Jan 2008 06:54:03 +0000</pubDate>
		<dc:creator>Bryan O'Sullivan</dc:creator>
				<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.serpentine.com/blog/2008/01/10/a-new-well-to-me-spam-vector-googlecom/</guid>
		<description><![CDATA[This is, I must say, very clever. In my latest round of inbound spam, I&#8217;ve noticed that some senders have begun sending valid links to http://google.com/ in their messages. The technique they&#8217;re using is to obfuscate a target URL inside a Google &#8220;I&#8217;m feeling lucky&#8221; query: this means that the domain near the left of [...]]]></description>
			<content:encoded><![CDATA[<p>This is, I must say, very clever. In my latest round of inbound spam, I&#8217;ve noticed that some senders have begun sending valid links to http://google.com/ in their messages. The technique they&#8217;re using is to obfuscate a target URL inside a Google &#8220;I&#8217;m feeling lucky&#8221; query: this means that the domain near the left of the URL really is google.com and doesn&#8217;t need to be faked, but it immediately reroutes a click to the spammer&#8217;s target, which is difficult to read due to some escaping. This is a cute social engineering attack, riding on Google&#8217;s brand and domain name to gull the unwary into clicking.</p>
<p>An obvious variant of this technique would be to seed a link farm with statistically improbable phrases, such that an &#8220;I&#8217;m feeling lucky&#8221; search for some innocuous but unlikely term, e.g. &#8220;woozy numbat playing kazoo&#8221;, would end up with a spammer&#8217;s site advertising something rather less wholesome as the number one hit. A spammer could even extend the use of SIPs to provide a <a href="http://en.wikipedia.org/wiki/Canary_trap">canary trap</a> to validate email addresses:if the inbound search term is &#8220;feral pet smells linux&#8221;, and we only sent that combination to user@domain.com, then the address must be valid.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.serpentine.com/blog/2008/01/10/a-new-well-to-me-spam-vector-googlecom/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Why is del.icio.us trapped in amber?</title>
		<link>http://www.serpentine.com/blog/2007/08/11/why-is-delicious-trapped-in-amber/</link>
		<comments>http://www.serpentine.com/blog/2007/08/11/why-is-delicious-trapped-in-amber/#comments</comments>
		<pubDate>Sat, 11 Aug 2007 15:49:21 +0000</pubDate>
		<dc:creator>Bryan O'Sullivan</dc:creator>
				<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.serpentine.com/blog/2007/08/11/why-is-delicious-trapped-in-amber/</guid>
		<description><![CDATA[I&#8217;ve had an account on del.icio.us for several years, but I only started using it heavily perhaps a year ago. While it&#8217;s a wonderful site in many respects, I&#8217;ve been surprised and disappointed by what&#8217;s happened since Yahoo acquired the company: nothing at all. Clearly, Yahoo has had no idea what to do with their [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve had an <a href="http://del.icio.us/bos">account on del.icio.us</a> for several years, but I only started using it heavily perhaps a year ago. While it&#8217;s a wonderful site in many respects, I&#8217;ve been surprised and disappointed by what&#8217;s happened since Yahoo acquired the company: nothing at all.</p>
<p>Clearly, Yahoo has had no idea what to do with their acquisition: almost its first reaction to the grafted del.icio.us antibodies was to roll out a homegrown NIH tagging site, the name of which nobody now remembers. Since then, Yahoo hasn&#8217;t even bothered to switch users over to its unified login system as it did with Flickr. Whether you liked that move or not, it was a clear sign that Yahoo had some interest in Flickr.</p>
<p>Prior to the acquisition, I figure that del.icio.us had fulfilled perhaps 5% of its initial promise. In order to grow its user base beyond hardcore power users, the site clearly needed a less hostile user interface; nothing has happened. They could have increased existing user loyalty and retention by making it easier for people to find others with similar interests; nothing has happened. They could have made the site more useful to individuals by helping people understand the evolution of their own interests. Nothing has happened.</p>
<p>It&#8217;s a shame to see that potential go unfulfilled. Even from a business perspective, if Yahoo could quite reasonably not figure out how to squeeze some money out of its acquisition, it could at very little cost to itself be improving its image among the nerdiest of the nerdy by investing in del.icio.us and blowing its geek cred trumpet. Instead, I have a notion that Josh Schachter is languishing in some dungeon in Santa Clara, watching the grains of sand fall through his stock option hourglass, and waiting to make good his escape. What a waste.</p>
<p>I suspect that the same thing is also happening with Flickr, though not to quite the same extent. Take a look at the numbers of pre- and post-acquisition changes to the site and you&#8217;ll see what I mean. Sure, geotagging is cute, but it&#8217;s almost the only significant change in over two years. This sclerosis of small acquisitions doesn&#8217;t make me sanguine for Yahoo&#8217;s future.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.serpentine.com/blog/2007/08/11/why-is-delicious-trapped-in-amber/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Parsing a simple config file in Haskell</title>
		<link>http://www.serpentine.com/blog/2007/01/31/parsing-a-simple-config-file-in-haskell/</link>
		<comments>http://www.serpentine.com/blog/2007/01/31/parsing-a-simple-config-file-in-haskell/#comments</comments>
		<pubDate>Thu, 01 Feb 2007 07:52:04 +0000</pubDate>
		<dc:creator>Bryan O'Sullivan</dc:creator>
				<category><![CDATA[haskell]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.serpentine.com/blog/2007/01/31/parsing-a-simple-config-file-in-haskell/</guid>
		<description><![CDATA[Even though I wrote my Haskell blog helper tool purely for my own use, I don&#8217;t want to store hard-coded strings in it, lest my username and password escape into the wild. This suggests that I need a small config file of some kind. I&#8217;m going to walk through the parser I wrote for this [...]]]></description>
			<content:encoded><![CDATA[<p>Even though I wrote my Haskell <a href="http://www.serpentine.com/blog/2007/01/30/blogging-with-emacs-and-haskell-part-zero/">blog helper
tool</a>
purely for my own use, I don&#8217;t want to store hard-coded strings in it,
lest my username and password escape into the wild.</p>

<p>This suggests that I need a small config file of some kind.  I&#8217;m going
to walk through the parser I wrote for this config file, not as a
tutorial, but as an example of how to solve a simple pratical problem
in Haskell.</p>

<p>The simplest kind of config file format that&#8217;s of any real use tends
to look like this:</p>

<blockquote>
<pre><code># Haskell blog config.

xmlrpc = http://www.example.com/wordpress/xmlrpc.php
editpost = http://www.example.com/wordpress/wp-admin/post.php?action=edit&amp;post=
user = blogdude  # comments flow to the end of a line
password = h8x
</code></pre>
</blockquote>

<p>From inspection, we can see a few informal rules.  Config items are
name/value pairs.  Empty lines are okay, and comments start with
<tt>#</tt>, spanning to the end of a line.</p>

<p>This is a format that&#8217;s easy to parse by hand or with regular
expressions, but I lately prefer to use
<a href="http://www.cs.uu.nl/~daan/parsec.html">Parsec</a> for these kinds of
jobs.  Regexps are difficult to read and debug, and often slower than
Parsec parsers.  Compared to a handwritten parser, a Parsec parser
sacrifices a little performance, but I win in considerably faster
development, clearer code, and excellent error messages &#8220;for free&#8221;.</p>

<p>Here follows the boilerplate for the beginning of the module.  We&#8217;ll
only be exporting two names from <code>ConfigFile</code>.</p>

<pre><code>&gt; module ConfigFile (
&gt;                    Config,
&gt;                    readConfig
&gt;                   ) where
</code></pre>

<p>We&#8217;ll be needing a few modules.</p>

<pre><code>&gt; import Char
&gt; import Control.Monad
&gt; import qualified Data.Map as Map
&gt; import Text.ParserCombinators.Parsec
&gt; import Data.Either
&gt; import Data.Maybe
</code></pre>

<p>The natural result of parsing a config file, at least in my mind, is a
finite map from keys to values, where both are represented as strings.</p>

<pre><code>&gt; type Config = Map.Map String String
</code></pre>

<p>In my case, I&#8217;ll start with the left-hand-side of a config item, which
I&#8217;d like to be a &#8220;C-like&#8221; identifier.  The first character should be
an alphabetic letter or underscore character.  There might be only one
character in an identifier, but if there are more, I&#8217;ll be expansive,
and allow them to be digits, too.</p>

<pre><code>&gt; ident :: Parser String

&gt; ident = do c &lt;- letter &lt;|&gt; char '_'
&gt;            cs &lt;- many (letter &lt;|&gt; digit &lt;|&gt; char '_')
&gt;            return (c:cs)
&gt;       &lt;?&gt; "identifier"
</code></pre>

<p>This definition provides a clear illustration of how readable Parsec
code can be.  (By the way, the <code>&lt;?&gt;</code> means &#8220;this is the name to use
when printing an error message&#8221;.)</p>

<p>When I&#8217;m developing a parser, I like to work from the bottom up,
starting with simple productions and moving &#8220;up the food chain&#8221; as I
debug each production.  I&#8217;ll typically use Parsec&#8217;s <code>parseTest</code>
function repeatedly from within <code>ghci</code> to test each production as I
go.  Testing interactively from within Emacs makes the process even
more efficient; I can reload a module and start testing it with just a
few keystrokes.</p>

<p>The result of a successful match
is as we&#8217;d expect:</p>

<blockquote>
<pre><code>*ConfigFile&gt; parseTest ident "ok"
"ok"
</code></pre>
</blockquote>

<p>Compared with <code>"([a-aA-Z_]\w*)"</code> in Perl-like regexp notation, the
Parsec description of <code>ident</code> is much longer.  But if a match fails,
we get a useful error message, which is a good reason to prefer
Parsec.  (When I use a normal Parsec entry point instead of
<code>parseTest</code>, Parsec will give me a file name in its error message,
too.  Nice!)</p>

<blockquote>
<pre><code>*ConfigFile&gt; parseTest ident "7"
parse error at (line 1, column 1):
unexpected "7"
expecting identifier
</code></pre>
</blockquote>

<p>Comments are easily dealt with.</p>

<pre><code>&gt; comment :: Parser ()

&gt; comment = do char '#'
&gt;              skipMany (noneOf "\r\n")
&gt;         &lt;?&gt; "comment"
</code></pre>

<p>We&#8217;d like to be agnostic about line endings.</p>

<pre><code>&gt; eol :: Parser ()

&gt; eol = do oneOf "\n\r"
&gt;          return ()
&gt;     &lt;?&gt; "end of line"
</code></pre>

<p>Now to parse an actual config item.</p>

<pre><code>&gt; item :: Parser (String, String)

&gt; item = do key &lt;- ident
&gt;           skipMany space
&gt;           char '='
&gt;           skipMany space
&gt;           value &lt;- manyTill anyChar (try eol &lt;|&gt; try comment &lt;|&gt; eof)
&gt;           return (key, rstrip value)
&gt;     where rstrip = reverse . dropWhile isSpace . reverse
</code></pre>

<p>The <code>manyTill</code> combinator builds up a result from each match of the
parser that is its first argument, until the parser that is its second
argument successfully matches.  After matching a config item, we
return it as a pair, stripping any trailing white space from the
value.</p>

<p>A line can either be empty, or contain a comment or a config item.
This makes it a good candidate for using the <code>Maybe</code> class.  If we
match a comment, we&#8217;ll return <code>Nothing</code>; if we match a config item, we
return <code>Just</code> that item.</p>

<pre><code>&gt; line :: Parser (Maybe (String, String))

&gt; line = do skipMany space
&gt;           try (comment &gt;&gt; return Nothing) &lt;|&gt; (item &gt;&gt;= return . Just)
</code></pre>

<p>Note that <code>skipMany space</code> above will happily consume newlines, so we
don&#8217;t need to explicitly check for empty lines.  It also consumes
leading whitespace.</p>

<p>Finally, we need to parse an entire file.  This is an example of how
it helps to spend some time browsing the standard Haskell libraries.
In this case, we&#8217;ll use <code>catMaybe</code> from <code>Data.Maybe</code> to turn our list
of <code>Maybe</code> values into a list of the <code>Just</code> config items (think of it
as dropping all of the <code>Nothing</code> entries from the list, and stripping
the <code>Just</code> from every other entry).</p>

<pre><code>&gt; file :: Parser [(String, String)]

&gt; file = do lines &lt;- many line
&gt;           return (catMaybes lines)
</code></pre>

<p>The <code>readConfig</code> action parses a config file, so it must run in the
<code>IO</code> monad.  If the parse fails, it returns a parse error; on success,
it returns a <code>Config</code> map.</p>

<pre><code>&gt; readConfig :: SourceName -&gt; IO (Either ParseError Config)

&gt; readConfig name =
&gt;     parseFromFile file name &gt;&gt;=
&gt;     return . fmap (foldr (uncurry Map.insert) Map.empty . reverse)
</code></pre>

<p>This is a dauntingly dense definition.  Rather than jumping in to
explain it piecewise, let&#8217;s first turn the code into something more
like &#8220;beginner Haskell&#8221;.</p>

<pre><code>&gt; readConf2 :: SourceName -&gt; IO (Either ParseError Config)

&gt; readConf2 name =
&gt;     do result &lt;- parseFromFile file name
&gt;        return $ case result of
&gt;          Left err -&gt; Left err
&gt;          Right xs -&gt; Right (listToMap (reverse xs))
</code></pre>

<p>Okay!  We get the result of a parse; if the parse was an error, we
pass the error along unmodified.  Otherwise, we turn the list into a
map, and return it.</p>

<pre><code>&gt; listToMap :: [(String, String)] -&gt; Config

&gt; listToMap ((k,v):xs) = Map.insert k v (listToMap xs)
&gt; listToMap []         = Map.empty
</code></pre>

<p>A Haskell programmer with a little bit of experience will notice that
the above function looks almost like a fold from the right of a list.
The only problem is the <code>(k,v)</code> pattern match that we used to &#8220;pick
apart&#8221; the arguments to <code>Map.insert</code>, so that we could pass it the
three arguments it wants.</p>

<blockquote>
<pre><code>Map.insert :: (Ord k) =&gt; k -&gt; v -&gt; Map.Map k v -&gt; Map.Map k v
</code></pre>
</blockquote>

<p>It would be great if <code>Map.insert</code> took arguments, instead of three.
We can fix this problem using <code>uncurry</code>.</p>

<blockquote>
<pre><code>uncurry Map.insert :: (Ord k) =&gt; (k, v) -&gt; Map.Map k v -&gt; Map.Map k v
</code></pre>
</blockquote>

<p>So now we can rewrite <code>listToMap</code> in terms of <code>foldr</code>.</p>

<pre><code>&gt; listToMap3 :: [(String, String)] -&gt; Config

&gt; listToMap3 = foldr (uncurry Map.insert) Map.empty
</code></pre>

<p>We can eliminate the <code>case</code> expression in <code>readConf2</code> by noticing that
<code>Either</code> is an instance of Haskell&#8217;s <code>Functor</code> class.  This means that
we can use the <code>Functor</code> class&#8217;s <code>fmap</code> function.  Calling <code>fmap f</code> on
<code>Left l</code> will return <code>Left l</code>, but <code>fmap f (Right r)</code> will return
<code>Right (f r)</code>, which is exactly what we want.</p>

<p>Knowing about <code>fmap</code> and <code>foldr</code>, it&#8217;s now easy to go backwards from
the relatively chatty definition of <code>readConf2</code> to the more austere
<code>readConfig</code>.</p>

<p>It&#8217;s possible to pare <code>readConfig</code> back even further, so that it&#8217;s
entirely point-free, but this renders the code more confusing, at
least to my eyes.</p>

<pre><code>&gt; readConf3 =
&gt;     (return . fmap (foldr (uncurry Map.insert) Map.empty . reverse) =&lt;&lt;) .
&gt;     parseFromFile file
</code></pre>

<p>I&#8217;m in no way claiming that this parser is the be-all and end-all of
config file parsers.  It doesn&#8217;t care if a value is redefined (it will
use the last definition); it doesn&#8217;t impose any logical structure or
constraints on the contents of a file; and it turns everything into
strings.  But it was quick to write (about an hour, not including the
time to write this article); it doesn&#8217;t have any dependencies on
third-party libraries; and it perfectly fits the needs of my trivial
blog helper.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.serpentine.com/blog/2007/01/31/parsing-a-simple-config-file-in-haskell/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Blogging with Emacs and Haskell, part Zero</title>
		<link>http://www.serpentine.com/blog/2007/01/30/blogging-with-emacs-and-haskell-part-zero/</link>
		<comments>http://www.serpentine.com/blog/2007/01/30/blogging-with-emacs-and-haskell-part-zero/#comments</comments>
		<pubDate>Wed, 31 Jan 2007 05:42:56 +0000</pubDate>
		<dc:creator>Bryan O'Sullivan</dc:creator>
				<category><![CDATA[haskell]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.serpentine.com/blog/2007/01/30/blogging-with-emacs-and-haskell-part-zero/</guid>
		<description><![CDATA[Since I started using WordPress to host my blog, I&#8217;ve generally been fairly pleased with it. Its killer feature has to be Akismet, the built-in spam filter. Akismet has so far killed over 18,000 spam comments for me, or roughly 300 per day in the two months since I switched from Blosxom to WordPress. Perhaps [...]]]></description>
			<content:encoded><![CDATA[<p>Since I started using WordPress to host my blog, I&#8217;ve generally been
fairly pleased with it.  Its killer feature has to be Akismet, the
built-in spam filter.  Akismet has so far killed over 18,000 spam
comments for me, or roughly 300 <em>per day</em> in the two months since I
switched from Blosxom to WordPress.  Perhaps one in fifty spam
comments make it through Akismet&#8217;s filters, at which point they&#8217;re
easily dealt with via the web interface.  So Akismet makes the
difference between manageable comments and having to turn them off
entirely.</p>

<p>One substantial aspect of WordPress that I&#8217;ve been displeased with is,
surprisingly, its support for writing articles.  The &#8220;WYSIWYG&#8221;
JavaScript editor repeatedly loses my formatting, and is slow and
unresponsive besides.  The &#8220;plain&#8221; editing interface isn&#8217;t much better
for me; I like to put code snippets in my blog entries, and it doesn&#8217;t
deal well with these.  And the internal text formatting flow is
baroque.</p>

<p>Fortunately, WordPress provides a remote API via XML-RPC, so it&#8217;s
possible to avoid its authoring interface entirely.  My goal is to be
able to write something like plain text from within Emacs, and have it
turn into a nicely formatted blog posting with a minimum of fuss.</p>

<p>To this end, I spent a couple of hours putting together a small &#8220;blog
helper&#8221; in Haskell.  It uses John Gruber&#8217;s
<a href="http://daringfireball.net/projects/markdown/">Markdown</a> tool to turn
plain text or literate Haskell source into a blog entry, and uses
WordPress&#8217;s XML-RPC interface to publish it for me.</p>

<p>I&#8217;m writing this article as a Markdown-formatted file within Emacs,
and publishing it with a few keystrokes.  Excellent!  Over the next
few articles, I&#8217;ll detail how I did this.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.serpentine.com/blog/2007/01/30/blogging-with-emacs-and-haskell-part-zero/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Mathbin, a pastebin that renders mathematics using LaTeX</title>
		<link>http://www.serpentine.com/blog/2006/12/14/mathbin-a-pastebin-that-renders-mathematics-using-latex/</link>
		<comments>http://www.serpentine.com/blog/2006/12/14/mathbin-a-pastebin-that-renders-mathematics-using-latex/#comments</comments>
		<pubDate>Thu, 14 Dec 2006 08:55:52 +0000</pubDate>
		<dc:creator>Bryan O'Sullivan</dc:creator>
				<category><![CDATA[open source]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.serpentine.com/blog/2006/12/14/mathbin-a-pastebin-that-renders-mathematics-using-latex/</guid>
		<description><![CDATA[If you use IRC to collaborate on a software project, chances are you&#8217;ve come across pastebin.com, a site where you can post snippets of code, program output, patches, and the like, and then give out the URL of the snippet to other people in the channel you&#8217;re working in. A similar site is paste.lisp.org, which [...]]]></description>
			<content:encoded><![CDATA[If you use IRC to collaborate on a software project, chances are you&#8217;ve come across <a target="_blank" href="http://pastebin.com/">pastebin.com</a>, a site where you can post snippets of code, program output, patches, and the like, and then give out the URL of the snippet to other people in the channel you&#8217;re working in. A similar site is <a target="_blank" href="http://paste.lisp.org/">paste.lisp.org</a>, which controls a network of bots that sit in IRC channels and announce newly pasted URLs for you. These seemingly trivial services make it <em>vastly</em> easier to do collaborative development and debugging.

I just ran across a <a target="_blank" href="http://www.mathbin.net/">mathbin.net</a>, a site that takes one step closer to nerd heaven, by allowing you to write mathematical equations using LaTeX&#8217;s notation; it then renders the mathematics as inline images, using LaTeX&#8217;s renderer. The results are beautiful; here&#8217;s an example of the <a target="_blank" href="http://mathworld.wolfram.com/AiryFunctions.html">Airy function</a> defined over real values.
<blockquote><img alt="Airy function" id="image112" src="http://www.serpentine.com/wordpress/wp-content/uploads/2006/12/2289_0.png" /></blockquote>
Of course, you need to speak some LaTeX to be able to generate such beautiful images:
<blockquote>
<pre><code>\mathrm{Ai}(x) = \frac{1}{\pi} \int_0^\infty \cos\left(\frac{t^3}{3} + xt\right) , dt.</code></pre>
</blockquote>
So mathbin is wonderful, but it&#8217;s not for everyone <img src='http://www.serpentine.com/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> ]]></content:encoded>
			<wfw:commentRss>http://www.serpentine.com/blog/2006/12/14/mathbin-a-pastebin-that-renders-mathematics-using-latex/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

