<?xml version="1.0" encoding="utf-8"?>
<!--Generated by RSS.NET: http://rss-net.sf.net-->
<rss version="2.0">
  <channel>
    <title>Jonathan Pryor's web log</title>
    <description>Jonathan Pryor's web log</description>
    <link>http://www.jprl.com/Blog/index.html</link>
    <copyright>Jonathan Pryor</copyright>
    <managingEditor>jonpryor@vt.edu (Jonathan Pryor)</managingEditor>
    <pubDate>Tue, 15 Jun 2010 15:23:00 -0500</pubDate>
    <docs>http://backend.userland.com/rss</docs>
    <generator>lb#</generator>
    <item>
      <title>HackWeek V</title>
      <description>
&lt;p&gt;Last week was &lt;a href="https://features.opensuse.org/hackweek"&gt;HackWeek
V&lt;/a&gt;, during which I had small goals, yet had most of the time eaten by
unexpected "roadblocks."&lt;/p&gt;

&lt;p&gt;The week started with my mis-remembering 
&lt;a href="http://www.go-mono.com/docs/index.aspx?link=T:Mono.Options.OptionSet"
&gt;OptionSet&lt;/a&gt; behavior.  I had thought that there was a bug with passing
options containing DOS paths, as I thought the path would be overly split:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
string path = null;
var o = new OptionSet () {
	{ "path=", v =&gt; path = v },
};
o.Parse (new[]{"-path=C:\path"});&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Fortunately, my memory was wrong: this works as expected.  Yay.&lt;/p&gt;

&lt;p&gt;What fails is if the option supports multiple values:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
string key = null, value = null;
var o = new OptionSet () {
	{ "D=", (k, v) =&gt; {key = k; value = v;} },
};
o.Parse (new[]{"-DFOO=C:\path"});&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;The above fails with a &lt;tt&gt;OptionException&lt;/tt&gt;, because the DOS path is
split, so &lt;tt&gt;OptionSet&lt;/tt&gt; attempts to send 3 arguments to an option
expecting 2 arguments.  This isn't allowed.&lt;/p&gt;

&lt;p&gt;The 
&lt;a href="http://lists.ximian.com/pipermail/mono-patches/2010-June/173435.html"
&gt;patch&lt;/a&gt; to fix the above is trivial (most of that patch is for tests).
However, the fix didn't work at first.&lt;/p&gt;

&lt;p&gt;Enter roadblock #1: 
&lt;a href="https://bugzilla.novell.com/show_bug.cgi?id=601772"&gt;String.Split()
can return too many substrings&lt;/a&gt;.  Oops.&lt;/p&gt;

&lt;p&gt;So I 
&lt;a href="http://lists.ximian.com/pipermail/mono-patches/2010-June/173433.html"
&gt;fixed it&lt;/a&gt;.  That only killed a day...&lt;/p&gt;

&lt;p&gt;Next up, I had been sent an email showing that &lt;tt&gt;OptionSet&lt;/tt&gt; had some
bugs when removing by index.  I couldn't let that happen...and being in a TDD
mood, I first wrote some unit tests to describe what the
&lt;a href="http://www.go-mono.com/docs/index.aspx?link=T:System.Collections.Generic.IList`1"
&gt;IList&amp;lt;T&amp;gt;&lt;/a&gt; semantics should be.  Being in an over-engineering mood, I 
wrote a set of
&lt;a
href="http://gitorious.org/cadenza/cadenza/blobs/master/src/Cadenza/Test/Cadenza.Collections/ListContract.cs"
&gt;"contract" tests for &lt;tt&gt;IList&amp;lt;T&amp;gt;&lt;/tt&gt;&lt;/a&gt; in 
&lt;a href="http://gitorious.org/cadenza"&gt;Cadenza&lt;/a&gt;, fixed some 
&lt;a href="http://gitorious.org/cadenza/cadenza/commit/62058bd9de6d617527523bc3ae9fc3f5f57c2f89"
&gt;Cadenza&lt;/a&gt;
&lt;a href="http://gitorious.org/cadenza/cadenza/commit/6ef2be492e56707bc181017660b8aef6067834be"
&gt;bugs&lt;/a&gt; so that Cadenza would pass the new &lt;tt&gt;ListContract&lt;/tt&gt;, then
merged &lt;tt&gt;ListContract&lt;/tt&gt; with the &lt;tt&gt;OptionSet&lt;/tt&gt; tests.&lt;/p&gt;

&lt;p&gt;Then I hit roadblock #2 when 
&lt;a href="http://www.go-mono.com/docs/index.aspx?link=T:System.Collections.ObjectModel.KeyedCollection`2"
&gt;KeyedCollection&amp;lt;TKey, TItem&amp;gt;&lt;/a&gt; wouldn't pass my &lt;tt&gt;ListContract&lt;/tt&gt;
tests, as it wasn't exception safe.  Not willing to give up on
&lt;tt&gt;ListContract&lt;/tt&gt;, I 
&lt;a href="http://lists.ximian.com/pipermail/mono-patches/2010-June/173511.html"
&gt;fixed &lt;tt&gt;KeyedCollection&lt;/tt&gt;&lt;/a&gt; so it would now pass my
&lt;tt&gt;ListContract&lt;/tt&gt; tests, improving compatibility with .NET in the
process, which allowed me to finally 
&lt;a href="http://lists.ximian.com/pipermail/mono-patches/2010-June/173513.html"
&gt;fix the &lt;tt&gt;OptionSet&lt;/tt&gt; bugs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I was then able to fix a 
&lt;a href="https://bugzilla.novell.com/show_bug.cgi?id=573121"&gt;mdoc
export-html&lt;/a&gt; bug in which index files wouldn't always be updated, before
starting to investigate 
&lt;a href="https://bugzilla.novell.com/show_bug.cgi?id=602560"&gt;mdoc assemble
wanting gobs of memory&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While pondering how to figure out why &lt;tt&gt;mdoc assemble&lt;/tt&gt; wanted 400MB
of memory, I asked the folks on 
&lt;a href="http://wiki.freenode-csharp.net/Wiki/"&gt;##csharp on freenode&lt;/a&gt; if
there were any Mono bugs preventing their
&lt;a href="http://wiki.freenode-csharp.net/Wiki/(S(2tmdxl55cmrreqiplbyrviqj))/SpikeLite.ashx?NoRedirect=1"
&gt;SpikeLite&lt;/a&gt; bot from working under Mono.  They kindly directed me toward a
bug in which
&lt;a href="https://bugzilla.novell.com/show_bug.cgi?id=438454"
&gt;AppDomain.ProcessExit was being fired at the wrong time&lt;/a&gt;.  This proved
easier than I feared (I feared it would be beyond me).&lt;/p&gt;

&lt;p&gt;Which left me with pondering a memory "leak." It obviously couldn't be a
leak with a GC and no unmanaged memory to speak of, but what was causing so
much memory to be used?  Thus proceeded lots of
&lt;tt&gt;Console.WriteLine(GC.GetTotalMemory(false))&lt;/tt&gt; calls and reading the
output to see where the memory use was jumping (as, alas I found Mono's memory
profiler to be less than useful for me, and mono's profiler was far slower
than a normal run). This eventually directed me to the problem:&lt;/p&gt;

&lt;p&gt;I needed, at most, two &lt;tt&gt;XmlNode&lt;/tt&gt; values from an
&lt;tt&gt;XmlDocument&lt;/tt&gt;.  An &lt;tt&gt;XmlDocument&lt;/tt&gt; loaded from a file that could
be very small or large-ish (0.5MB).  &lt;i&gt;Thousands&lt;/i&gt; of such files.  At
once.&lt;/p&gt;

&lt;p&gt;That's when it dawned on me that storing &lt;tt&gt;XmlNode&lt;/tt&gt;s in a Dictionary
loaded from thousands of &lt;tt&gt;XmlDocument&lt;/tt&gt;s might not be such a good idea,
as each &lt;tt&gt;XmlNode&lt;/tt&gt; retains a reference to the &lt;tt&gt;XmlDocument&lt;/tt&gt; it
came from, so I was basically copying the entire documentation set into
memory, when I only needed a fraction of it.  Doh!&lt;/p&gt;

&lt;p&gt;The fix was straightforward: keep a temporary &lt;tt&gt;XmlDocument&lt;/tt&gt; around
and call
&lt;a
href="http://www.go-mono.com/docs/index.aspx?link=M:System.Xml.XmlDocument.ImportNode"
&gt;XmlDocument.ImportNode&lt;/a&gt; to preserve just the data I needed.&lt;/p&gt;

&lt;p&gt;Memory use plummeted to less than one tenth what was previously
required.&lt;/p&gt;

&lt;p&gt;Along the way I ran across and reported an 
&lt;a href="http://www.mono-project.com/Microsoft.Build"&gt;xbuild&lt;/a&gt; bug (since
fixed), and 
&lt;a href="https://bugzilla.novell.com/show_bug.cgi?id=612659"&gt;filed a regression
in gmcs which prevented Cadenza from building&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Overall, a productive week, but not at all what I had originally
intended.&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/2010/Jun-15.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/2010/Jun-15.html</guid>
      <pubDate>Tue, 15 Jun 2010 19:23:00 -0500</pubDate>
    </item>
    <item>
      <title>Defending XML-based Build Systems</title>
      <description>
&lt;p&gt;&lt;a href="http://www.codethinked.com/"&gt;Justin Etheredge&lt;/a&gt; recently
suggested that we 
&lt;a href="http://www.codethinked.com/post/2010/04/26/Say-Goodbye-to-NAnt-and-MSBuild-With-IronRuby.aspx"
&gt;Say Goodbye to NAnt and MSBuild for .NET Builds With IronRuby&lt;/a&gt;.  Why?
because they're based on XML.&lt;/p&gt;

&lt;p&gt;He goes on to mention several problems with XML-based build systems,
principally:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;It's not code (unless you're using &lt;a
    href="http://www.w3.org/TR/xslt"&gt;XSLT&lt;/a&gt;, and having maintained XSLTs if
    you need to write them you have my condolences...)&lt;/li&gt;
  &lt;li&gt;Lose existing tooling: editors, debuggers, libraries, etc.&lt;/li&gt;
  &lt;li&gt;Limit creation of custom rules.&lt;/li&gt;
  &lt;li&gt;Require that we write custom tools to workaround the limitations of XML
    build systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;His solution: use Ruby to describe your build process.&lt;/p&gt;

&lt;p&gt;My reaction?  No, &lt;i&gt;no&lt;/i&gt;, for the love of &lt;tt&gt;$deity&lt;/tt&gt; NO!&lt;/p&gt;

&lt;p&gt;Why?  Three reasons: &lt;a href="http://en.wikipedia.org/wiki/GNU_build_system"
&gt;GNU Autotools&lt;/a&gt;, &lt;a href="http://paulmck.livejournal.com/tag/is%20parallel%20programming%20hard"
&gt;Paul E. McKenney's excellent parallel programming series&lt;/a&gt;, and
&lt;a href="http://www.sql.org"&gt;SQL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Wait, what?&lt;/i&gt;  What do those have to do with build systems?
Everything, and nothing.&lt;/p&gt;

&lt;p&gt;The truly fundamental problem is this: "To a man with a hammer, everything
looks like a nail" (reportedly a quote from Mark Twain, but that's neither
here nor there). In this case, the "hammer" is "writing code." But it's more
than that: it's writing 
&lt;a href="http://en.wikipedia.org/wiki/Imperative_programming"&gt;imperative&lt;/a&gt;
code, specifically Ruby code (though the particular language isn't the problem 
I have, rather the imperative aspect).&lt;/p&gt;

&lt;p&gt;Which is, to me, the fundamental problem: it's a &lt;i&gt;terrible&lt;/i&gt; base for
any form of higher-level functionality.  Suppose you want to build your
software in parallel (which is where Paul McKenney's series comes in).  Well,
you can't, because your entire build system is based on imperative code, and
unless &lt;i&gt;all&lt;/i&gt; the libraries you're using were written with that in
mind...well, you're screwed.  The imperative code needs to run, and
potentially generate any side effects, and without a "higher-level"
description of what those side effects entail it can't sanely work.&lt;/p&gt;

&lt;p&gt;Want to add a new file to your build (a fairly common thing to do in an
IDE, along with renaming files?) Your IDE needs to be able to understand the
imperative code.  If it doesn't, it just broke your build script.  Fun!&lt;/p&gt;

&lt;p&gt;OK, what about packaging? Well, in order to know what the generated files
are (and where they're located), you'll have to run the entire script and
(somehow) track what files were created.&lt;/p&gt;

&lt;p&gt;Want to write an external tool that does something hitherto unknown?  (As a
terrible example, parse all C# code for &lt;tt&gt;#if HAVE_XXX&lt;/tt&gt; blocks so that a
set of feature tests can be automatically extracted.)  Well, tough -- you have
to embed an IronRuby interpreter, and figure out how to query the interpreter
for the information you want (e.g. all the source files).&lt;/p&gt;

&lt;p&gt;etc., etc.&lt;/p&gt;

&lt;p&gt;My problem with imperative languages is that they're not high-level enough.
&lt;a href="http://paulmck.livejournal.com/18539.html"&gt;McKenney asks what the
good multicore programming languages are&lt;/a&gt;; the answer is 
&lt;a href="http://kernel.org/pub/linux/kernel/people/paulmck/Answers/IsParallelProgrammingHard/GoodFadUgly.html"
&gt;SQL&lt;/a&gt; because it's dedicated ~solely to letting you &lt;i&gt;describe&lt;/i&gt; the
question but leaves the &lt;i&gt;implementation&lt;/i&gt; of the answer to the question 
up to the SQL database.  It's &lt;i&gt;not&lt;/i&gt; imperative, it's &lt;a
href="http://en.wikipedia.org/wiki/Declarative_programming#Logic_programming"
&gt;declarative&lt;/a&gt; (at least until you hit esoteric features such as cursors,
but in principal you can generally stick to a declarative subset).&lt;/p&gt;

&lt;p&gt;OK, so I want a higher-level language to describe targets and dependencies,
and supports faster builds.  To a large degree, 
&lt;a href="http://www.gnu.org/software/make/"&gt;make&lt;/a&gt;(1) supports all that, and
it's the basis of Autotools.  Surely I like that, right?&lt;/p&gt;

&lt;p&gt;The problem with autotools is that it's a mixture of declarative and
imperative code, with Unix shell scripts forming the backbone of the
imperative code (aka the target rules), and these are inherently Unix
specific.  (Possibly &lt;a href="http://twitter.com/jonpryor/status/12511909775"
&gt;Linux&lt;/a&gt; specific, much to my 
&lt;a href="http://twitter.com/jonpryor/status/12513304731"
&gt;consternation&lt;/a&gt;.)  Plus, the format is virtually unreadable by anything
other than &lt;b&gt;make&lt;/b&gt;(1), what with all the language extensions...&lt;/p&gt;

&lt;p&gt;So why XML?&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Because&lt;/i&gt; it's not code, it's &lt;i&gt;data&lt;/i&gt;, which (somewhat) lowers the 
barrier of entry for writing external tools which can parse the format and
Do New Things without needing to support some language which might
not even run on the platform you're using.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Because&lt;/i&gt; it's easily parseable AND verifiable, it's (somewhat) safer
for external automated tools to manipulate the file without screwing you over
"accidentally" -- e.g. adding and removing files from the build via an
IDE.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Because&lt;/i&gt; custom rules are limited, there is a smaller "grammar"
for external tools to understand, making it simpler to write and maintain
them.  It also encourages moving "non-target targets" out of the build system,
simplifying file contents (and facilitating interaction with e.g. IDEs).&lt;/p&gt;

&lt;p&gt;Am I arguing that XML-based build systems are perfect?  Far from it.
I'm instead arguing that small, purpose-specific languages &lt;i&gt;can&lt;/i&gt; (and
often &lt;i&gt;are&lt;/i&gt;) Good Things™, particularly if they permit interoperability
between a variety of tools and people.  XML allows this, if imperfectly.  An
IronRuby-based build system does &lt;i&gt;not&lt;/i&gt;.&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/2010/Apr-26.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/2010/Apr-26.html</guid>
      <pubDate>Mon, 26 Apr 2010 21:24:00 -0500</pubDate>
    </item>
    <item>
      <title>mdoc Repository Format History</title>
      <description>
&lt;p&gt;Time to wrap up this overly long series on
&lt;a href="http://www.mono-project.com/Mdoc"&gt;mdoc&lt;/a&gt;.  We covered:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-07.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-08.html"&gt;Overview &lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-09.html"&gt;Simple usage&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-10.html"&gt;Importing documentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-10-2.html"&gt;Repository XML Schema&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-11.html"&gt;Static HTML customization&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-12.html"&gt;Exporting to Microsoft's XML 
    Documentation format&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-13.html"&gt;Assembling documentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-14.html"&gt;Viewing documentation via ASP.NET&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-15.html"&gt;Caching ASP.NET content&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-15.html"&gt;Assembly versioning&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To close out this series, where did the &lt;tt&gt;mdoc&lt;/tt&gt; repository format 
come from?  It mostly came from Microsoft, actually.&lt;/p&gt;

&lt;p&gt;Taking a step back, "in the beginning," as it were, the Mono project saw
the need for documentation in 
&lt;a href="http://lists.ximian.com/pipermail/mono-docs-list/2002-January/thread.html"
&gt;January 2002&lt;/a&gt;.  I wasn't involved then, but perusing the archives we can
see that 
&lt;a href="http://lists.ximian.com/pipermail/mono-docs-list/2002-February/000027.html"
&gt;&lt;tt&gt;csc /doc&lt;/tt&gt; output was discarded early&lt;/a&gt; because it wouldn't support
translation into multiple languages.  
&lt;a href="http://ndoc.sourceforge.net/"&gt;NDoc&lt;/a&gt; was similarly discarded
because it relied on &lt;tt&gt;csc /doc&lt;/tt&gt; documentation.  I'm sure a related 
problem at the time was that Mono's C# compiler didn't support the 
&lt;tt&gt;/doc&lt;/tt&gt; compiler option (and wouldn't &lt;i&gt;begin&lt;/i&gt; to support 
&lt;tt&gt;/doc&lt;/tt&gt; until 
&lt;a href="http://lists.ximian.com/pipermail/mono-devel-list/2004-April/004815.html"
&gt;April 2004&lt;/a&gt;), so there would be no mechanism to extract any inline 
documentation anyway.&lt;/p&gt;

&lt;p&gt;By 
&lt;a href="http://lists.ximian.com/pipermail/mono-docs-list/2003-April/000463.html"
&gt;April 2003&lt;/a&gt; 
&lt;a href="http://www.ecma-international.org/default.htm"&gt;ECMA&lt;/a&gt;
standardization of the
&lt;a href="http://www.ecma-international.org/publications/standards/Ecma-335.htm"
&gt;Common Language Infrastructure&lt;/a&gt; was apparently in full force, and the
standardization effort included &lt;i&gt;actual&lt;/i&gt; class library documentation.
The ECMA documentation is available within 
&lt;a href="http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.zip"
&gt;ECMA-335.zip&lt;/a&gt;.  The ECMA-335 documentation also included a DTD for the
documentation contained therein, and it was a &lt;i&gt;superset&lt;/i&gt; of the normal C# 
XML documentation.  The additional XML elements provided what XML
documentation lacked: information available from the assembly, such as actual
parameter types, return types, base class types, etc.  There was one problem
with ECMA-335 XML, though: it was &lt;i&gt;gigantic&lt;/i&gt;, throwing everything into a 
single 7MB+ XML file.&lt;/p&gt;

&lt;p&gt;To make this format more version-control friendly (can you imagine
maintaining and viewing diffs on a 7+MB XML file?), Mono "extended" the 
ECMA-335 documentation format by splitting it into one file per type.  This 
forms the fundamental basis of the 
&lt;a href="http://www.go-mono.com/docs/index.aspx?link=man:mdoc(5)"&gt;mdoc
repository format&lt;/a&gt; (and is why I say that the repository format came from
Microsoft, as Microsoft provided the documentation XML and DTD to ECMA).
This is also why tools such as 
&lt;a href="http://www.go-mono.com/docs/index.aspx?link=man:mdoc-assemble(1)"
&gt;mdoc assemble&lt;/a&gt; refer to the format as &lt;tt&gt;ecma&lt;/tt&gt;.
The remainder of the Mono extensions were added in order to fix various
documentation bugs (e.g. to distinguish between &lt;i&gt;ref&lt;/i&gt; vs. &lt;i&gt;out&lt;/i&gt;
parameters, to better support generics), etc.&lt;/p&gt;

&lt;p&gt;In closing this series, I would like to thank everyone who has ever worked
on Monodoc and the surrounding tools and infrastructure.  It wouldn't be
anywhere near as useful without them.&lt;/p&gt;
</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-20.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-20.html</guid>
      <pubDate>Wed, 20 Jan 2010 15:23:00 -0500</pubDate>
    </item>
    <item>
      <title>Assembly Versioning with mdoc</title>
      <description>
&lt;p&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-09.html"&gt;Previously&lt;/a&gt;, we mentioned as an aside
that the &lt;i&gt;Type.xml&lt;/i&gt; files within an mdoc repository contained
&lt;tt&gt;//AssemblyVersion&lt;/tt&gt; elements.  Today we will discuss what they're
for.&lt;/p&gt;

&lt;p&gt;The &lt;tt&gt;//AssemblyVersion&lt;/tt&gt; element records exactly one thing: which 
&lt;a href="http://msdn.microsoft.com/en-us/library/system.reflection.assemblyversionattribute.version.aspx"
&gt;assembly versions&lt;/a&gt; a type and member was found in.  (The assembly
version is specified via the 
&lt;a href="http://msdn.microsoft.com/en-us/library/system.reflection.assemblyversionattribute.aspx"
&gt;AssemblyVersionAttribute&lt;/a&gt; attribute.)  With a normal assembly versioning
policy, this allows &lt;a href="http://www.mono-project.com/Monodoc"&gt;monodoc&lt;/a&gt;
to show two things: which version &lt;i&gt;added&lt;/i&gt; the type/member, and (by
inference) which version(s) &lt;i&gt;removed&lt;/i&gt; the member.&lt;/p&gt;

&lt;p&gt;For example, consider the
&lt;a href="http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.close.aspx"
&gt;NetworkStream.Close&lt;/a&gt; method.  This method was present in 
&lt;a href="http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.close(VS.71).aspx"
&gt;.NET 1.0&lt;/a&gt; which overrode 
&lt;a href="http://msdn.microsoft.com/en-us/library/system.io.stream.close(VS.71).aspx"
&gt;Stream.Close&lt;/a&gt;.  However, in 
&lt;a href="http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.close(VS.80).aspx"
&gt;.NET 2.0&lt;/a&gt; the override was removed entirely.&lt;/p&gt;

&lt;p&gt;The &lt;tt&gt;//AssemblyVersion&lt;/tt&gt; attribute allows the mdoc repository to track
such versioning changes; for example, consider the
&lt;a href="http://anonsvn.mono-project.com/source/branches/mono-2-6/mcs/class/System/Documentation/en/System.Net.Sockets/NetworkStream.xml"
&gt;mdoc-generated NetworkStream.xml&lt;/a&gt; file.  The
&lt;tt&gt;//Member[@MemberName='Close']/AssemblyInfo/AssemblyVersion&lt;/tt&gt;
elements contain &lt;i&gt;only&lt;/i&gt; an entry for &lt;tt&gt;1.0.5000.0&lt;/tt&gt; (corresponding to
.NET 1.1) on line 536.  Compare to the 
&lt;tt&gt;//Member[@MemberName='CanWrite']/AssemblyInfo/AssemblyVersion&lt;/tt&gt;
elements (for the 
&lt;a href="http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.canwrite.aspx"
&gt;NetworkStream.CanWrite&lt;/a&gt; property) which has &lt;tt&gt;//AssemblyVersion&lt;/tt&gt;
elements for 1.0.5000.0 and 2.0.0.0.  From this, we can deduce that 
&lt;tt&gt;NetworkStream.Close&lt;/tt&gt; was present in .NET 1.1, but was removed in .NET
2.0.&lt;/p&gt;

&lt;p&gt;When viewing type and member documentation, &lt;tt&gt;monodoc&lt;/tt&gt; and the 
&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-14.html"&gt;ASP.NET front end&lt;/a&gt; will show the assembly 
versions that have the member:&lt;/p&gt;

&lt;blockquote&gt;&lt;img src="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/monodoc-NetworkStream.Close-versions.png"
  height="513" width="694"
  title="NetworkStream.Close -- notice only 1.0.5000.0 is a listed assembly version."
  alt="NetworkStream.Close -- notice only 1.0.5000.0 is a listed assembly version." /&gt;&lt;/blockquote&gt;

&lt;p&gt;There are two limitations with the version tracking:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It only tracks types and members.  For example, attributes, base
    classes, and interfaces may be added or removed across versions; these are 
    not currently tracked.&lt;/li&gt;
  &lt;li&gt;It uses the assembly version to fill the
    &lt;tt&gt;&amp;lt;AssemblyVersion&amp;gt;&lt;/tt&gt; element.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The second point may sound like a feature (isn't it the point?), but it has
one downfall: auto-generated assembly versions.  You can specify an
auto-generated assembly version by using the &lt;tt&gt;*&lt;/tt&gt; for some components in
the &lt;tt&gt;AssemblyVersionAttribute&lt;/tt&gt; constructor:&lt;/p&gt;

&lt;blockquote&gt;&lt;tt class="code-csharp"&gt;[assembly: AssemblyVersion("1.0.*.*")]&lt;/tt&gt;&lt;/blockquote&gt;

&lt;p&gt;If you do this, &lt;i&gt;every time you rebuild the assembly&lt;/i&gt; the compiler
will dutifully generate a &lt;i&gt;different&lt;/i&gt; assembly number.  For example, the 
first time you might get a compiler version of &lt;tt&gt;1.0.3666.19295&lt;/tt&gt;, while 
the second recompilation the compiler will generate &lt;tt&gt;1.0.3666.19375&lt;/tt&gt;.  
Since &lt;tt&gt;mdoc&lt;/tt&gt; assigns no meaning to the version numbers, it will create
&lt;tt&gt;//AssemblyVersion&lt;/tt&gt; elements for &lt;i&gt;each&lt;/i&gt; distinct version
found.&lt;/p&gt;

&lt;p&gt;The "advantage" is that you can know on which build a member was added.
(If you actually care...)&lt;/p&gt;

&lt;p&gt;The disadvantage is a major bloating of the mdoc repository, as you add at
least 52*(1+&lt;i&gt;M&lt;/i&gt;) bytes &lt;i&gt;to each file&lt;/i&gt; in the mdoc repository &lt;i&gt;for 
each unique assembly version&lt;/i&gt; (where &lt;i&gt;M&lt;/i&gt; is the number of members within
the file, as each member is separately tracked).  It will also make viewing 
the documentation distracting; imagine seeing 10 different version numbers 
for a member, which all differ in the build number.  That much noise would 
make the feature ~useless.&lt;/p&gt;

&lt;p&gt;As such, if you're going to use &lt;tt&gt;mdoc&lt;/tt&gt;, I &lt;i&gt;highly&lt;/i&gt; suggest not
using auto-generated assembly version numbers.&lt;/p&gt;

&lt;p&gt;Next time, we'll wrap up this series with a history of the mdoc repository
format.&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-19.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-19.html</guid>
      <pubDate>Tue, 19 Jan 2010 17:12:00 -0500</pubDate>
    </item>
    <item>
      <title>Caching mdoc's ASP.NET-generated HTML</title>
      <description>
&lt;p&gt;&lt;a todo="TODO" href="mdoc-8.html"&gt;Last time&lt;/a&gt; we discussed configuring
the ASP.NET front-end to display monodoc documentation.  The display of
extension methods within 
&lt;a href="http://www.mono-project.com/Monodoc"&gt;monodoc&lt;/a&gt; and the ASP.NET
front-end is fully dynamic.  This has it's pros and cons.&lt;/p&gt;

&lt;p&gt;On the pro side, if/when you install additional assembled documentatation
sources, those sources will be searched for extension methods and they will be
shown on all matching types.  This is &lt;i&gt;very&lt;/i&gt; cool.&lt;/p&gt;

&lt;p&gt;On the con side, searching for the extension methods and converting
them into HTML takes time -- there is a noticable delay when viewing all members
of a type if there are lots of extension methods.  On heavily loaded servers,
this may be detrimental to overall performance.&lt;/p&gt;

&lt;p&gt;If you're running the ASP.NET front-end, you're not regularly adding
documentation, and you have 
&lt;a href="http://www.mono-project.com/Release_Notes_Mono_2.6"&gt;Mono 2.6&lt;/a&gt;,
you can use the &lt;tt&gt;mdoc export-html-webdoc&lt;/tt&gt; command to pre-render the
HTML files and cache the results.  This will speed up future rendering.&lt;/p&gt;

&lt;p&gt;For example, consider the url
&lt;tt&gt;http://localhost:8080/index.aspx?link=T:System.Collections.Generic.List`1/*&lt;/tt&gt;
(which shows all of the 
&lt;a href="http://localhost:8080/index.aspx?link=T%3aSystem.Collections.Generic.List%601/*"
&gt;List&amp;lt;T&amp;gt; members&lt;/a&gt;).  This is a frameset, and the important frame here 
is &lt;tt&gt;http://localhost:8080/monodoc.ashx?link=T:System.Collections.Generic.List`1/*&lt;/tt&gt;
which contains the member listing (which includes extension methods).  On my
machine, it takes ~2.0s to download this page:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;$ time curl -s \
	'http://localhost:8080/monodoc.ashx?link=T:System.Collections.Generic.List`1/*' \
	&amp;gt; /dev/null

real	0m2.021s
user	0m0.003s
sys	0m0.002s
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;In a world where links 
&lt;a href="http://www.useit.com/papers/responsetime.html"&gt;need to take less than
0.1 seconds to be responsive&lt;/a&gt;, this is...pretty bad.&lt;/p&gt;


&lt;p&gt;After running &lt;tt&gt;mdoc export-html-webdoc netdocs.zip&lt;/tt&gt; 
(which contains the &lt;tt&gt;List&amp;lt;T&amp;gt;&lt;/tt&gt; docs):&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;$ time curl -s \
	'http://localhost:8080/monodoc.ashx?link=T:System.Collections.Generic.List`1/*' \
	&amp;gt; /dev/null

real	0m0.051s
user	0m0.003s
sys	0m0.006s&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;That's nearly 40x faster, and within the 0.1s guideline.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Cache Generation:&lt;/b&gt; to generate the cache files, run 
&lt;tt&gt;mdoc export-html-web ASSEMBLED-FILES&lt;/tt&gt;.  &lt;i&gt;ASSEMBLED-FILES&lt;/i&gt;
consists of the &lt;tt&gt;.tree&lt;/tt&gt; or &lt;tt&gt;.zip&lt;/tt&gt; files which are generated by 
&lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-assemble(1)"
&gt;mdoc assemble&lt;/a&gt; and have been installed into
&lt;tt&gt;$prefix/lib/monodoc/sources&lt;/tt&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;tt class="shell"&gt;$ mdoc export-html-webdoc $prefix/lib/monodoc/sources/Demo.zip&lt;/tt&gt;
&lt;/blockquote&gt;

&lt;p&gt;(Where &lt;tt&gt;$prefix&lt;/tt&gt; is your Mono installation prefix, e.g.
&lt;tt&gt;/usr/lib/monodoc/sources/Demo.zip&lt;/tt&gt;.)&lt;/p&gt;

&lt;p&gt;This will create a directory tree within 
&lt;tt&gt;$prefix/lib/monodoc/sources/cache/Demo&lt;/tt&gt;.  
Restarting the ASP.NET front-end will allow it to use the cache.&lt;/p&gt;

&lt;p&gt;If you don't want to generate the cache in another directory, use the
&lt;tt&gt;-o=PREFIX&lt;/tt&gt; option.  This is useful if you're updating an existing
cache on a live server and you don't want to overwrite/replace the existing
cache (it's a live server!) -- generate the cache elsewhere, then move the
files when the server is offline.&lt;/p&gt;

&lt;p&gt;If you have lots of time on your hands, you could process all assembled
documentation with:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;$ mdoc export-html-webdoc $prefix/lib/monodoc/sources/*.zip&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;b&gt;Limitations:&lt;/b&gt; It should be noted that this is full of limitations, so
you should only use it if performance is &lt;i&gt;really&lt;/i&gt; important.  Limitations
include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The existence of the &lt;tt&gt;cache&lt;/tt&gt; subdirectories are more important than
    any timestamps; if the &lt;tt&gt;.zip&lt;/tt&gt; file is newer than the
    corresponding &lt;tt&gt;cache&lt;/tt&gt; directory, the &lt;tt&gt;cache&lt;/tt&gt; contents will 
    still be returned.&lt;/li&gt;
  &lt;li&gt;It's privy to monodoc internals, and thus you &lt;i&gt;may&lt;/i&gt; need to regenerate
    &lt;i&gt;all&lt;/i&gt; cached documentation whenever you add or remove &lt;tt&gt;.zip&lt;/tt&gt;
    files.  For example, since it can be used to show extension methods, and
    any set of documentation can contain extension methods, adding or removing
    assembled documentation files may render the cached output out of date.&lt;/li&gt;
  &lt;li&gt;&lt;tt&gt;mdoc export-html-webdoc&lt;/tt&gt; processing is &lt;i&gt;slow&lt;/i&gt;.  Processing
    the 2.4KB &lt;tt&gt;Demo.zip&lt;/tt&gt; takes a speedy 1.2s.  Processing the 5.8MB
    &lt;tt&gt;netdocs.zip&lt;/tt&gt; (51MB uncompressed, containing 4810 types with 45267
    members, including &lt;tt&gt;List&amp;lt;T&amp;gt;&lt;/tt&gt; documentation)
    takes an astounding 247m (over 4 hours).  The resulting 
    &lt;tt&gt;cache/netdocs&lt;/tt&gt; directory is 316MB.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next time, we'll cover &lt;tt&gt;mdoc&lt;/tt&gt;'s support for assembly versioning.&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-15.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-15.html</guid>
      <pubDate>Fri, 15 Jan 2010 17:50:00 -0500</pubDate>
    </item>
    <item>
      <title>Configuring the ASP.NET front-end for mdoc</title>
      <description>
&lt;p&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-13.html"&gt;Last time&lt;/a&gt;, we &lt;i&gt;assembled&lt;/i&gt; our
documentation and installed it for use with 
&lt;a href="http://www.mono-project.com/Monodoc"&gt;monodoc&lt;/a&gt;.  This is a
prerequisite for ASP.NET support (as they both use the same system-wide
documentation directory).&lt;/p&gt;

&lt;p&gt;Once the documentation is installed (assuming a Linux distro or OSX with
the relevant command-line tools installed), you can trivially host a web
server which will display the documentation:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="shell"&gt;$ svn co http://anonsvn.mono-project.com/source/branches/mono-2-4/mono-tools/webdoc/
&lt;i&gt;# output omitted...&lt;/i&gt;
$ cd webdoc
$ xsp2&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;You will need to change the &lt;tt&gt;svn co&lt;/tt&gt; command to use the same version
of Mono that is present on your system.  For example, if you have
&lt;a href="http://www.mono-project.com/Release_Notes_Mono_2.6"&gt;Mono 2.6&lt;/a&gt;
installed, change the &lt;tt&gt;mono-2-4&lt;/tt&gt; to &lt;tt&gt;mono-2-6&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;Once &lt;tt&gt;xsp2&lt;/tt&gt; is running, you can point your web browser to
&lt;tt&gt;http://localhost:8080&lt;/tt&gt; to view documentation.  This will show the same 
documentation as &lt;tt&gt;monodoc&lt;/tt&gt; did last time:&lt;/p&gt;

&lt;blockquote&gt;&lt;img src="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/xsp2-Array-extension-methods.png"
  height="512" width="694"
  title="System.Array extension methods -- notice With() is listed"
  alt="System.Array extension methods -- notice With() is listed" /&gt;&lt;/blockquote&gt;

&lt;p&gt;For "real" use, setting up using 
&lt;a href="http://www.apache.org/"&gt;Apache&lt;/a&gt; with 
&lt;a href="http://www.mono-project.com/Mod_mono"&gt;mod_mono&lt;/a&gt; may be preferred
(or any of the other options listed at 
&lt;a href="http://www.mono-project.com/ASP.NET"&gt;Mono's ASP.NET support page&lt;/a&gt;).
Configuring &lt;tt&gt;mod_mono&lt;/tt&gt; or anything other than &lt;tt&gt;xsp2&lt;/tt&gt; is beyond
my meager abilities.&lt;/p&gt;

&lt;p&gt;Next time, we'll discuss improving the ASP.NET front-end's page rendering
performance.&lt;/p&gt;
</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-14.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-14.html</guid>
      <pubDate>Thu, 14 Jan 2010 14:43:00 -0500</pubDate>
    </item>
    <item>
      <title>Assembling Documentation with mdoc</title>
      <description>
&lt;p&gt;We &lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-09.html"&gt;previously&lt;/a&gt; discussed exporting the 
mdoc repository into static HTML files using 
&lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-export-html(1)"
&gt;mdoc export-html&lt;/a&gt; and into a 
&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-12.html"&gt;Microsoft XML Documentation file&lt;/a&gt; with
&lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-export-html(1)"
&gt;mdoc export-msxdoc&lt;/a&gt;.
Today, we'll discuss exporting documentation with
&lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-assemble(1)"
&gt;mdoc assemble&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;tt&gt;mdoc assemble&lt;/tt&gt; is used to 
&lt;a href="http://mono-project.com/Generating_Documentation#Assemble_the_generated_Documentation"
&gt;assemble documentation&lt;/a&gt; for use with the 
&lt;a href="http://www.mono-project.com/Monodoc"&gt;monodoc Documentation
browser&lt;/a&gt; and the 
&lt;a href="http://anonsvn.mono-project.com/source/trunk/mono-tools/webdoc/"
&gt;ASP.NET front-end&lt;/a&gt;.  This involves the following steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Running &lt;tt&gt;mdoc assemble&lt;/tt&gt;.&lt;/li&gt;
  &lt;li&gt;Writing a &lt;tt&gt;.source&lt;/tt&gt; file.&lt;/li&gt;
  &lt;li&gt;Installing the files.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Unfortunately we're taking a diversion from the Windows world, as the
&lt;tt&gt;monodoc&lt;/tt&gt; browser and the ASP.NET front-end won't run under Windows
(due to limitations in the monodoc infrastructure).  I will attempt to fix
these limitations in the future.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Running &lt;tt&gt;mdoc assemble&lt;/tt&gt;&lt;/b&gt;: &lt;tt&gt;mdoc assemble&lt;/tt&gt; has three arguments of
interest:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;tt&gt;-f=&lt;i&gt;FORMAT&lt;/i&gt;&lt;/tt&gt; is used to specify the &lt;i&gt;format&lt;/i&gt; of the 
    files to assemble.  When documenting assemblies you can skip this, as the 
    default format is for mdoc repositories.  This is useful if you want to 
    assemble other materials, such as man pages or plain HTML files.&lt;/li&gt;
  &lt;li&gt;&lt;tt&gt;-o=&lt;i&gt;PREFIX&lt;/i&gt;&lt;/tt&gt; is used to specify the &lt;i&gt;output prefix&lt;/i&gt;.  
    &lt;tt&gt;mdoc assemble&lt;/tt&gt; generates &lt;i&gt;two&lt;/i&gt; files, a &lt;tt&gt;.tree&lt;/tt&gt; and a
    &lt;tt&gt;.zip&lt;/tt&gt; file.  The &lt;i&gt;PREFIX&lt;/i&gt; value is the basename to use for
    these to files.&lt;/li&gt;
  &lt;li&gt;The list of files or directories to process.  Whether these need to be
    files or directories (and related semantics) depends upon the format
    specified; see the &lt;b&gt;FORMATS&lt;/b&gt; section of the 
    &lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-assemble(1)"
    &gt;mdoc-assemble&lt;/a&gt;(1) man page for details.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For our current documentation, we would run:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;$ mdoc assemble -o Demo Documentation/en.docs&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;This will create the files &lt;tt&gt;Demo.tree&lt;/tt&gt; and &lt;tt&gt;Demo.zip&lt;/tt&gt; in the
current working directory.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The .source file&lt;/b&gt; is used to tell the documentation browser where in
the tree the documentation should be inserted.  It's an XML file that contains
two things: a (set of) &lt;tt&gt;/monodoc///node&lt;/tt&gt; elements describing where in the tree
the documentation should be inserted, and &lt;tt&gt;/monodoc/source&lt;/tt&gt; elements
which specify the files to use.  For example:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
&amp;lt;?xml version="1.0"?&amp;gt;
&amp;lt;monodoc&amp;gt;
  &amp;lt;node label="Demo Library" name="Demo-lib" parent="libraries" /&amp;gt;
  &amp;lt;source provider="ecma" basefile="Demo" path="Demo-lib"/&amp;gt;
&amp;lt;/monodoc&amp;gt;&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;The &lt;tt&gt;/monodoc/node&lt;/tt&gt; element describes where in the &lt;tt&gt;monodoc&lt;/tt&gt;
tree the documentation should be placed.  It has three attributes, two of
which are required:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;tt&gt;label&lt;/tt&gt; is the text to display in the tree view.&lt;/li&gt;
  &lt;li&gt;&lt;tt&gt;name&lt;/tt&gt; is the name of the node, so that other nodes and the 
    &lt;tt&gt;/monodoc/source/@path&lt;/tt&gt; attribute may refer to it.&lt;/li&gt;
  &lt;li&gt;&lt;tt&gt;parent&lt;/tt&gt; is optional, and contains the &lt;tt&gt;//node/@name&lt;/tt&gt;
    value of the node which should be the parent of this node.
    This is used to provide a degree of structure.  It should be a value from
    &lt;tt&gt;$prefix/lib/monodoc/monodoc.xml&lt;/tt&gt; in the &lt;tt&gt;//node/@name&lt;/tt&gt;
    attribute values.  Currently these include:
    &lt;ul&gt;
      &lt;li&gt;&lt;tt&gt;languages&lt;/tt&gt; for programming language references, e.g.
        &lt;a href="http://www.go-mono.com/docs/index.aspx?link=root:/ecmaspec"&gt;The
        C# Language Specification&lt;/a&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;tt&gt;libraries&lt;/tt&gt; for class library documentation.&lt;/li&gt;
      &lt;li&gt;&lt;tt&gt;man&lt;/tt&gt; for man pages and other command references.&lt;/li&gt;
      &lt;li&gt;&lt;tt&gt;tools&lt;/tt&gt; and &lt;tt&gt;various&lt;/tt&gt; for anything that doesn't fit in the
        above descriptions.&lt;/li&gt;
    &lt;/ul&gt;
    If not specified and this is the &lt;tt&gt;/monodoc/node&lt;/tt&gt; element, this 
    defaults to the &lt;tt&gt;various&lt;/tt&gt; node.  If this is a nested
    &lt;tt&gt;//node&lt;/tt&gt; element, the &lt;tt&gt;@parent&lt;/tt&gt; attribute defaults to the
    parent &lt;tt&gt;//node&lt;/tt&gt; element (&lt;tt&gt;../@name&lt;/tt&gt;).
    &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;tt&gt;/monodoc/source&lt;/tt&gt; element describes what file basename to
use when looking for the &lt;tt&gt;.tree&lt;/tt&gt; and &lt;tt&gt;.zip&lt;/tt&gt; files.  (By
convention the &lt;tt&gt;.source&lt;/tt&gt;, &lt;tt&gt;.tree&lt;/tt&gt;, and &lt;tt&gt;.zip&lt;/tt&gt; files share
the same basename, but this is not required.  The &lt;tt&gt;.tree&lt;/tt&gt; and
&lt;tt&gt;.zip&lt;/tt&gt; files must share the same basename, but the &lt;tt&gt;.source&lt;/tt&gt;
basename may differ, and will differ if e.g. one &lt;tt&gt;.source&lt;/tt&gt; file pulls
in several &lt;tt&gt;.tree&lt;/tt&gt;/&lt;tt&gt;.zip&lt;/tt&gt; pairs.)  It has three attributes, all
of which are required:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;tt&gt;basefile&lt;/tt&gt; is the file basename of the &lt;tt&gt;.tree&lt;/tt&gt; and
    &lt;tt&gt;.zip&lt;/tt&gt; files.&lt;/li&gt;
  &lt;li&gt;&lt;tt&gt;path&lt;/tt&gt; is the &lt;tt&gt;//node/@name&lt;/tt&gt; value that will be associated
    with the docs within &lt;tt&gt;&lt;i&gt;basefile&lt;/i&gt;.tree&lt;/tt&gt; and 
    &lt;tt&gt;&lt;i&gt;basefile&lt;/i&gt;.zip&lt;/tt&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;tt&gt;provider&lt;/tt&gt; is the &lt;i&gt;format&lt;/i&gt; provided to &lt;tt&gt;mdoc
    assemble&lt;/tt&gt;.  For assembly documentation, this should be
    &lt;tt&gt;ecma&lt;/tt&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;Installing the files.&lt;/b&gt;  Files need to be installed into
&lt;tt&gt;$prefix/lib/monodoc/sources&lt;/tt&gt;.  You can obtain this directory with 
&lt;a href="http://pkg-config.freedesktop.org/wiki/"&gt;pkg-config&lt;/a&gt;(1):&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;$ cp Demo.source Demo.tree Demo.zip \
    `pkg-config monodoc --variable=sourcesdir`&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Now when we run &lt;tt&gt;monodoc&lt;/tt&gt;, we can navigate to the documentation that
was just installed:&lt;/p&gt;

&lt;blockquote&gt;&lt;img src="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Demo-docs-in-monodoc.png" 
  height="513" width="694"
  title="ObjectCoda.With() documentation inside monodoc."
  alt="ObjectCoda.With() documentation inside monodoc." /&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;i&gt;Additionally&lt;/i&gt;, those paying attention on 
&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-10.html"&gt;January 10&lt;/a&gt; will have noticed that the
&lt;tt&gt;With()&lt;/tt&gt; method we documented is an &lt;i&gt;extension method&lt;/i&gt;.
&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/../../2009/Jan-25.html"&gt;Monodoc supports displaying
extension methods&lt;/a&gt; on the relevant type documentation.  In this case,
&lt;tt&gt;With()&lt;/tt&gt; is an extension on &lt;tt&gt;TSource&lt;/tt&gt;, which is, for all intents
and purposes,
&lt;a href="http://www.go-mono.com/docs/index.aspx?link=T:System.Object"
&gt;System.Object&lt;/a&gt;.  Thus, if we view the &lt;tt&gt;System.Object&lt;/tt&gt; docs within
our local monodoc browser, we will see the &lt;tt&gt;With()&lt;/tt&gt; extension
method:&lt;/p&gt;

&lt;blockquote&gt;&lt;img src="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Object-extension-methods.png" 
  height="513" width="694"
  title="System.Object extension methods -- notice With() is listed."
  alt="System.Object extension methods -- notice With() is listed." /&gt;&lt;/blockquote&gt;

&lt;p&gt;In fact, we will see &lt;tt&gt;With()&lt;/tt&gt; listed as an extension method on
&lt;i&gt;all&lt;/i&gt; types (which is arguably a bug, as &lt;tt&gt;static&lt;/tt&gt; types can't have
instance methods...).&lt;/p&gt;

&lt;p&gt;Furthermore, 
&lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-export-html(1)"
&gt;mdoc export-html&lt;/a&gt; will &lt;i&gt;also&lt;/i&gt; list extension methods.
&lt;i&gt;However&lt;/i&gt;, &lt;tt&gt;mdoc export-html&lt;/tt&gt; is far more limited: it will only
look for extension methods within the mdoc repositories being processing, and
it will only list those methods as extension methods on types within the
mdoc repository.  Consequently, &lt;tt&gt;mdoc export-html&lt;/tt&gt; will &lt;i&gt;not&lt;/i&gt; list
e.g.
&lt;a href="http://www.go-mono.com/docs/index.aspx?link=T:System.Linq.Enumerable/*"
&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/a&gt; extension methods on types that implement 
&lt;a href="http://www.go-mono.com/docs/index.aspx?link=T:System.Collections.Generic.IEnumerable`1"
&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/a&gt;.  (It simply lacks the information to do so.)&lt;/p&gt;

&lt;p&gt;Examples of &lt;tt&gt;mdoc export-html&lt;/tt&gt; listings of extension methods can be
found in the
&lt;a href="http://anonsvn.mono-project.com/source/trunk/mcs/tools/mdoc/Test/html.expected/index.html"
&gt;mdoc unit tests&lt;/a&gt; and the
&lt;a href="http://www.jprl.com/Projects/Cadenza/docs/Cadenza.Collections/CachedSequence%601.html#Extension%20Methods"
&gt;Cadenza.Collections.CachedSequence&amp;lt;T&amp;gt;&lt;/a&gt; docs (which lists a million
extension methods because 
&lt;a href="http://www.jprl.com/Projects/Cadenza/docs/Cadenza.Collections/EnumerableCoda.html"
&gt;Cadenza.Collections.EnumerableCoda&lt;/a&gt; contains a million extension
methods on &lt;tt&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/tt&gt;).&lt;/p&gt;

&lt;p&gt;Next time, we'll discuss setting up the 
&lt;a href="http://anonsvn.mono-project.com/source/trunk/mono-tools/webdoc/"
&gt;ASP.NET front end&lt;/a&gt; under Linux.&lt;/p&gt;
</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-13.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-13.html</guid>
      <pubDate>Wed, 13 Jan 2010 14:43:00 -0500</pubDate>
    </item>
    <item>
      <title>Exporting mdoc Repositories to Microsoft XML Documentation</title>
      <description>
&lt;p&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-10.html"&gt;Previously&lt;/a&gt;, we discussed how to write 
documentation and get it into the documentation repository.
We &lt;a todo="TODO" href="mdoc-09.html"&gt;also&lt;/a&gt; discussed exporting the 
documentation into static HTML files using 
&lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-export-html(1)"
&gt;mdoc export-html&lt;/a&gt;.  Today, we'll discuss
&lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-export-msxdoc(1)"
&gt;mdoc export-msxdoc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;tt&gt;mdoc export-msxdoc&lt;/tt&gt; is used to export the documentation within the 
mdoc repository into a &lt;tt&gt;.xml&lt;/tt&gt; file that conforms to the same schema as 
&lt;a href="http://msdn.microsoft.com/en-us/library/3260k4x7%28VS.71%29.aspx"
&gt;csc /doc&lt;/a&gt;.  This allows you, if you so choose, to go entirely to externally
managed documentation (instead of inline XML) and still be able to produce your
&lt;i&gt;Assembly.xml&lt;/i&gt; file so that Visual Studio/etc. can provide code completion
against your assembly.&lt;/p&gt;

&lt;p&gt;There are two ways to invoke it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;$ mdoc export-msxdoc Documentation/en
$ mdoc export-msxdoc -o Demo.xml Documentation/en&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;The primary difference between these is what files are generated.  Within 
each &lt;i&gt;Type.xml&lt;/i&gt; file of the mdoc repository (e.g. 
&lt;a href="http://www.jprl.com/Blog/../Projects/mdoc/blog/2010/Documentation/en/Cadenza/ObjectCoda.xml"
&gt;ObjectCoda.xml&lt;/a&gt;) is a &lt;tt&gt;/Type/AssemblyInfo/AssemblyName&lt;/tt&gt;
element.&lt;/p&gt;

&lt;p&gt;The first command (lacking &lt;tt&gt;-o Demo.xml&lt;/tt&gt;) will generate a &lt;i&gt;set&lt;/i&gt; 
of &lt;tt&gt;.xml&lt;/tt&gt; files, where the filenames are based on the values of the 
&lt;tt&gt;/Type/AssemblyInfo/AssemblyName&lt;/tt&gt; element values, in this case 
&lt;a href="http://www.jprl.com/Blog/../Projects/mdoc/blog/2010/msxdoc/Demo.xml"&gt;Demo.xml&lt;/a&gt;.
Additionally, a
&lt;a href="http://www.jprl.com/Blog/../Projects/mdoc/blog/2010/msxdoc/NamespaceSummaries.xml"
&gt;NamespaceSummaries.xml&lt;/a&gt; file is generated, containing documentation for
any namespaces that were documented (which come from the &lt;tt&gt;ns-*.xml&lt;/tt&gt;
files, e.g. 
&lt;a href="http://www.jprl.com/Blog/../Projects/mdoc/blog/2010/Documentation/en/ns-Cadenza.xml"&gt;
ns-Cadenza.xml&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The second command (which specifies &lt;tt&gt;-o Demo.xml&lt;/tt&gt;) will &lt;i&gt;only&lt;/i&gt; 
generate the specified file (in this case
&lt;a href="http://www.jprl.com/Blog/../Projects/mdoc/blog/2010/msxdoc/Demo.xml"&gt;Demo.xml&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;For this mdoc repository, there is no actual difference between the 
commands (as only one assembly was documented within the repository), except 
for the generation of the &lt;tt&gt;NamespaceSummaries.xml&lt;/tt&gt; file.  However,
if you place documentation from multiple assemblies into the same mdoc 
repository, the first command will properly generate &lt;tt&gt;.xml&lt;/tt&gt; files for 
each assembly, while the latter will generate only a single &lt;tt&gt;.xml&lt;/tt&gt; file 
containing the documentation from &lt;i&gt;all&lt;/i&gt; assemblies.&lt;/p&gt;

&lt;p&gt;Next time, we'll cover &lt;a
href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-assemble(1)"
&gt;mdoc assemble&lt;/a&gt;.&lt;/p&gt;
</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-12.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-12.html</guid>
      <pubDate>Tue, 12 Jan 2010 13:20:00 -0500</pubDate>
    </item>
    <item>
      <title>Customizing mdoc's Static HTML Output</title>
      <description>
&lt;p&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-10.html"&gt;Last time&lt;/a&gt;, we wrote documentation for 
our &lt;tt&gt;Demo.dll&lt;/tt&gt; assembly.  What if we want to improve the looks of those
docs, e.g. to change the colors or add additional navigation links for site
consistency purposes?&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-export-html(1)"
&gt;mdoc export-html&lt;/a&gt; uses three mechanisms to control output:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;tt&gt;--ext=&lt;i&gt;FILE-EXTENSION&lt;/i&gt;&lt;/tt&gt; is used to change the file extension 
    of generated files from &lt;tt&gt;.html&lt;/tt&gt; to &lt;i&gt;FILE-EXTENSION&lt;/i&gt;.
    This is useful if you want to generate e.g. &lt;tt&gt;.aspx&lt;/tt&gt; files instead
    of &lt;tt&gt;.html&lt;/tt&gt; files (the default).&lt;/li&gt;
  &lt;li&gt;&lt;tt&gt;--template=&lt;i&gt;TEMPLATE-FILE&lt;/i&gt;&lt;/tt&gt; specifies an XSLT to use for the 
    layout of all generated files.  If not specified, then the XSLT returned
    by &lt;tt&gt;mdoc export-html --default-template&lt;/tt&gt; is used.&lt;/li&gt;
  &lt;li&gt;HTML 
    &lt;a href="http://www.w3.org/TR/CSS/"&gt;CSS&lt;/a&gt; class names are used throughout
    the documentation, allowing various elements to be customized by providing 
    an alternate stylesheet.  The 
    &lt;a href="http://www.go-mono.com/docs/index.aspx?link=man:mdoc-export-html(1)"
    &gt;mdoc export-html&lt;/a&gt; man page lists the CSS classes that are used.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="http://www.w3.org/TR/xslt"&gt;XSLT&lt;/a&gt; needs to consume an XML 
document that has the following structure:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;&amp;lt;Page&amp;gt;
    &amp;lt;CollectionTitle&amp;gt;&lt;i&gt;Collection Title&lt;/i&gt;&amp;lt;/CollectionTitle&amp;gt;
    &amp;lt;PageTitle&amp;gt;&lt;i&gt;Page Title&lt;/i&gt;&amp;lt;/PageTitle&amp;gt;
    &amp;lt;Summary&amp;gt;&lt;i&gt;Page Summary&lt;/i&gt;&amp;lt;/Summary&amp;gt;
    &amp;lt;Signature&amp;gt;&lt;i&gt;Type Declaration&lt;/i&gt;&amp;lt;/Signature&amp;gt;
    &amp;lt;Remarks&amp;gt;&lt;i&gt;Type Remarks&lt;/i&gt;&amp;lt;/Remarks&amp;gt;
    &amp;lt;Members&amp;gt;&lt;i&gt;Type Members&lt;/i&gt;&amp;lt;/Members&amp;gt;
    &amp;lt;Copyright&amp;gt;&lt;i&gt;Documentation Copyright&lt;/i&gt;&amp;lt;/Copyright&amp;gt;
&amp;lt;/Page&amp;gt;&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;The contents of each of the &lt;tt&gt;//Page/*&lt;/tt&gt; elements contains HTML or 
plain text nodes.  Specifically:&lt;/p&gt;

&lt;blockquote&gt;
&lt;dl&gt;
  &lt;dt&gt;&lt;tt&gt;/Page/CollectionTitle&lt;/tt&gt;&lt;/dt&gt;
  &lt;dd&gt;Contains the Assembly and Namespace name links.&lt;/dd&gt;

  &lt;dt&gt;&lt;tt&gt;/Page/PageTitle&lt;/tt&gt;&lt;/dt&gt;
  &lt;dd&gt;Contains the type name/description.&lt;/dd&gt;

  &lt;dt&gt;&lt;tt&gt;/Page/Summary&lt;/tt&gt;&lt;/dt&gt;
  &lt;dd&gt;Contains the type &lt;tt&gt;&amp;lt;summary/&amp;gt;&lt;/tt&gt; documentation.&lt;/dd&gt;

  &lt;dt&gt;&lt;tt&gt;/Page/Signature&lt;/tt&gt;&lt;/dt&gt;
  &lt;dd&gt;Contains the type signature, e.g. whether
    it's a struct or class, implemented interfaces, etc.&lt;/dd&gt;

  &lt;dt&gt;&lt;tt&gt;/Page/Remarks&lt;/tt&gt;&lt;/dt&gt;
  &lt;dd&gt;Contains type-level &lt;tt&gt;&amp;lt;remarks/&amp;gt;&lt;/tt&gt;.&lt;/dd&gt;

  &lt;dt&gt;&lt;tt&gt;/Page/Members&lt;/tt&gt;&lt;/dt&gt;
  &lt;dd&gt;Contains the documentation for all of the members 
    of the type, including a table for all of the members.&lt;/dd&gt;

  &lt;dt&gt;&lt;tt&gt;/Page/Copyright&lt;/tt&gt;&lt;/dt&gt;
  &lt;dd&gt;Contains copyright information taken from the
    mdoc repository, specifically from
    &lt;a href="http://www.jprl.com/Blog/../Projects/mdoc/blog/2010/Documentation/en/index.xml"
    &gt;index.xml&lt;/a&gt;'s &lt;tt&gt;/Overview/Copyright&lt;/tt&gt; element.&lt;/dd&gt;
&lt;/dl&gt;
&lt;/blockquote&gt;

&lt;p&gt;By providing a custom &lt;tt&gt;--template&lt;/tt&gt; XSLT and/or by providing an
additional CSS file, you have some degree of control over the resulting 
documentation.&lt;/p&gt;

&lt;p&gt;I'll be the first to admit that this isn't a whole lot of flexibility; 
there is no control over what CSS class names are used, nor is there any
control over what is generated within the &lt;tt&gt;/Page//*&lt;/tt&gt; elements.  What
this model &lt;i&gt;does&lt;/i&gt; allow is for controlling the &lt;i&gt;basic&lt;/i&gt; page layout,
e.g. to add a site-wide menu system, allowing documentation to be consistent
with the rest of the site.&lt;/p&gt;

&lt;p&gt;For example, 
&lt;a href="http://www.jprl.com/cgi-bin/gitweb.cgi?p=web-site.git"&gt;my site&lt;/a&gt;
uses 
&lt;a href="http://www.jprl.com/cgi-bin/gitweb.cgi?p=web-site.git;a=blob;h=3df3ac716673020cb960c3824aa0c8eccce40dad;hb=19b36ab771f0338d94fc4e5a987c2693f40c9d8b;f=mono-fuse.template"
&gt;custom&lt;/a&gt;
&lt;a href="http://www.jprl.com/cgi-bin/gitweb.cgi?p=web-site.git;a=blob;h=adbda93bbd91a8263f8a0e07799656556ae43ee2;hb=19b36ab771f0338d94fc4e5a987c2693f40c9d8b;f=ndesk-options.template"
&gt;templates&lt;/a&gt; to provide a uniform look-and-feel with the rest of their
respective sites for the 
&lt;a href="http://www.jprl.com/Projects/mono-fuse/docs/"&gt;Mono.Fuse&lt;/a&gt;
and &lt;a href="http://www.ndesk.org/doc/ndesk-options/"&gt;NDesk.Options&lt;/a&gt;
documentation.&lt;/p&gt;

&lt;p&gt;Next time, we'll cover &lt;tt&gt;mdoc export-msxdoc&lt;/tt&gt;.&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-11.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-11.html</guid>
      <pubDate>Mon, 11 Jan 2010 13:19:00 -0500</pubDate>
    </item>
    <item>
      <title>mdoc XML Schema</title>
      <description>
&lt;p&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-10.html"&gt;Previously&lt;/a&gt;, I mentioned that you
could manually edit the XML files within the mdoc repository.&lt;/p&gt;

&lt;p&gt;What I neglected to mention is that there are only parts of the XML files
that you should edit, and that there is an XML Schema file available for all
docs.&lt;/p&gt;

&lt;p&gt;The &lt;a href="http://www.go-mono.com/docs/index.aspx?link=man:mdoc(5)"
&gt;mdoc(5)&lt;/a&gt; man page lays out which files within the repository (and which
parts of those files) are editable.  In summary, all &lt;tt&gt;ns-*.xml&lt;/tt&gt; files
and the &lt;tt&gt;//Docs&lt;/tt&gt; nodes of all other &lt;tt&gt;.xml&lt;/tt&gt; files are editable,
and they should contain 
&lt;a href="http://msdn.microsoft.com/en-us/library/5ast78ax%28VS.100%29.aspx"
&gt;ye normal XML documentation elements&lt;/a&gt; (which are &lt;i&gt;also&lt;/i&gt; documented
within the &lt;b&gt;mdoc&lt;/b&gt;(5) man page).&lt;/p&gt;

&lt;p&gt;The XML Schema can be found in Mono's SVN, at
&lt;a href="http://anonsvn.mono-project.com/source/trunk/mcs/tools/mdoc/Resources/monodoc-ecma.xsd"
&gt;http://anonsvn.mono-project.com/source/trunk/mcs/tools/mdoc/Resources/monodoc-ecma.xsd&lt;/a&gt;.
&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-10-2.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-10-2.html</guid>
      <pubDate>Sun, 10 Jan 2010 14:22:00 -0500</pubDate>
    </item>
    <item>
      <title>Writing Documentation for mdoc</title>
      <description>
&lt;p&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-09.html"&gt;Last time&lt;/a&gt;, we create an assembly and
used 
&lt;a href="http://www.go-mono.com/docs/index.aspx?link=man:mdoc(1)"&gt;mdoc&lt;/a&gt;
to generate a documentation repository containing
&lt;i&gt;stubs&lt;/i&gt;.  Stubs have some utility -- you can view the types, members, and
parameter types that are currently present -- but they're far from ideal.  We
want &lt;i&gt;actual&lt;/i&gt; documentation.&lt;/p&gt;

&lt;p&gt;Unfortunately, &lt;tt&gt;mdoc&lt;/tt&gt; isn't an AI, and can't write documentation for
you.  It &lt;i&gt;manages&lt;/i&gt; documentation; it doesn't create it.&lt;/p&gt;

&lt;p&gt;How do we get actual documentation into the respository?  There are three
ways:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Manually edit the XML files within the repository directory (if
    following from last time, this would be all &lt;tt&gt;.xml&lt;/tt&gt; files within the 
    &lt;a href="http://www.jprl.com/Blog/../Projects/mdoc/blog/2010/Documentation/en"&gt;Documentation/en&lt;/a&gt;
    directory.&lt;/li&gt;
  &lt;li&gt;Use &lt;tt&gt;monodoc --edit Documentation/en&lt;/tt&gt;.&lt;/li&gt;
  &lt;li&gt;We can continue writing XML documentation within our
    source code.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Manually editing the files should be self-explanatory; it's not exactly
ideal, but it works, and is how I write most of my documentation.&lt;/p&gt;

&lt;p&gt;When using &lt;tt&gt;monodoc --edit Documentation/en&lt;/tt&gt;, the contents of
&lt;tt&gt;Documentation/en&lt;/tt&gt; will be shown sorted in the tree view by it's
assembly name, e.g. in the &lt;b&gt;Mono Documentation &amp;rarr; Demo&lt;/b&gt; node.
When viewing documentation, there are [&lt;u&gt;Edit&lt;/u&gt;] links that, when
clicked, will allow editing the node (which directly edits the files
within &lt;tt&gt;Documentation/en&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;However, I can't recommend &lt;tt&gt;monodoc&lt;/tt&gt; as an actual editor.  It's 
usability is terrible, and has one major usability flaw: when editing method 
overloads, &lt;i&gt;most&lt;/i&gt; of the documentation will be the same (or similar enough 
that you'll want to copy everything anyway), e.g. &lt;tt&gt;&amp;lt;summary/&amp;gt;&lt;/tt&gt;, 
&lt;tt&gt;&amp;lt;param/&amp;gt;&lt;/tt&gt;, etc.  The monodoc editor doesn't allow copying
all of this at once, but only each element &lt;i&gt;individually&lt;/i&gt;.  It makes
for a very &lt;i&gt;slow&lt;/i&gt; experience.&lt;/p&gt;

&lt;p&gt;Which brings us to inline XML documentation.  
&lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-update(1)"
&gt;mdoc update&lt;/a&gt; supports &lt;i&gt;importing&lt;/i&gt; XML documentation as produced by 
&lt;a href="http://msdn.microsoft.com/en-us/library/3260k4x7%28VS.71%29.aspx"
&gt;csc /doc&lt;/a&gt;.  So let's edit our source code to add inline documentation:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
using System;

namespace Cadenza {
    /// &amp;lt;summary&amp;gt;
    ///  Extension methods on &amp;lt;see cref="T:System.Object" /&amp;gt;.
    /// &amp;lt;/summary&amp;gt;
    public static class ObjectCoda {
        /// &amp;lt;typeparam name="TSource"&amp;gt;The type to operate on.&amp;lt;/typeparam&amp;gt;
        /// &amp;lt;typeparam name="TResult"&amp;gt;The type to return.&amp;lt;/typeparam&amp;gt;
        /// &amp;lt;param name="self"&amp;gt;
        ///   A &amp;lt;typeparamref name="TSource" /&amp;gt; containing the value to manipulate.
        ///   This value may be &amp;lt;see langword="null" /&amp;gt; (unlike most other
        ///   extension methods).
        /// &amp;lt;/param&amp;gt;
        /// &amp;lt;param name="selector"&amp;gt;
        ///   A &amp;lt;see cref="T:System.Func{TSource,TResult}" /&amp;gt; which will be
        ///   invoked with &amp;lt;paramref name="self" /&amp;gt; as a parameter.
        /// &amp;lt;/param&amp;gt;
        /// &amp;lt;summary&amp;gt;
        ///   Supports chaining otherwise temporary values.
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;returns&amp;gt;
        ///   The value of type &amp;lt;typeparamref name="TResult" /&amp;gt; returned by
        ///   &amp;lt;paramref name="selector" /&amp;gt;.
        /// &amp;lt;/returns&amp;gt;
        /// &amp;lt;remarks&amp;gt;
        ///   &amp;lt;para&amp;gt;
        ///     &amp;lt;c&amp;gt;With&amp;lt;/c&amp;gt; is useful for easily using an intermediate value within
        ///     an expression "chain" without requiring an explicit variable
        ///     declaration (which is useful for reducing in-scope variables, as no
        ///     variable is explicitly declared).
        ///   &amp;lt;/para&amp;gt;
        ///   &amp;lt;code lang="C#" src="../../example.cs#With" /&amp;gt;
        /// &amp;lt;/remarks&amp;gt;
        /// &amp;lt;exception cref="T:System.ArgumentNullException"&amp;gt;
        ///   &amp;lt;paramref name="selector" /&amp;gt; is &amp;lt;see langword="null" /&amp;gt;.
        /// &amp;lt;/exception&amp;gt;
        public static TResult With&amp;lt;TSource, TResult&amp;gt;(
                this TSource self, 
                Func&amp;lt;TSource, TResult&amp;gt; selector)
        {
            if (selector == null)
                throw new ArgumentNullException ("selector");
            return selector (self);
        }
    }
}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;(As an aside, notice that our file ballooned from 14 lines to 45 lines
because of all the documentation.  This is why I prefer to keep my
documentation external to the source code, as it &lt;i&gt;really&lt;/i&gt; bloats the
source.  Certainly, the IDE can hide comments, but I find that this defeats
the purpose of having comments in the first place.)&lt;/p&gt;

&lt;p&gt;Compile it into an assembly (use &lt;tt&gt;csc&lt;/tt&gt; if running on Windows),
specifying the &lt;tt&gt;/doc&lt;/tt&gt; parameter to extract XML documentation comments:
&lt;/p&gt;
&lt;blockquote&gt;&lt;tt&gt;$ gmcs /t:library /out:Demo.dll /doc:Demo.xml demo.cs&lt;/tt&gt;&lt;/blockquote&gt;

&lt;p&gt;Update our documentation repository, but &lt;i&gt;import&lt;/i&gt;
&lt;tt&gt;Demo.xml&lt;/tt&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;
$ mdoc update -o Documentation/en -i Demo.xml Demo.dll --exceptions=added
Updating: Cadenza.ObjectCoda
Members Added: 0, Members Deleted: 0&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;(No members were added or deleted as we're only changing the documentation,
and didn't add any types or members to the assembly.)&lt;/p&gt;

&lt;p&gt;Now when we view 
&lt;a href="http://www.jprl.com/Blog/../Projects/mdoc/blog/2010/Documentation/en.docs/Cadenza/ObjectCoda.xml"
&gt;ObjectCoda.xml&lt;/a&gt;, we can see the documentation that was present in the
source code.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;However&lt;/i&gt;, notice one other change.  In the documentation we wrote, we
had:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
        ///   &amp;lt;code lang="C#" src="../../example.cs#With" /&amp;gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yet, within &lt;tt&gt;ObjectCoda.xml&lt;/tt&gt;, we have:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
          &amp;lt;code lang="C#" src="../../example.cs#With"&amp;gt;Console.WriteLine(
    args.OrderBy(v =&amp;gt; v)
    .With(c =&amp;gt; c.ElementAt (c.Count()/2)));
&amp;lt;/code&amp;gt;
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;What's going on here?  What's going on is that &lt;tt&gt;mdoc&lt;/tt&gt; will search
for all &lt;tt&gt;&amp;lt;code/&amp;gt;&lt;/tt&gt; elements.  If they contain a
&lt;tt&gt;//code/@src&lt;/tt&gt; attribute, the specified file is read in and inserted
as the &lt;tt&gt;//code&lt;/tt&gt; element's value.  The filename specified in the
&lt;tt&gt;//code/@src&lt;/tt&gt; attribute is relative to the documentation repository
root.  A further extension is that, for C# code, if the filename has an
"anchor", a &lt;tt&gt;#region&lt;/tt&gt; block of the same name is searched for within the
source code.&lt;/p&gt;

&lt;p&gt;The &lt;tt&gt;../../example.cs&lt;/tt&gt; file referenced in the &lt;tt&gt;//code/@src&lt;/tt&gt;
value has the contents:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
using System;
using System.Linq;
using Cadenza;

class Demo {
    public static void Main (string[] args)
    {
        #region With
        Console.WriteLine(
            args.OrderBy(v =&amp;gt; v)
            .With(c =&amp;gt; c.ElementAt (c.Count()/2)));
        #endregion
    }
}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;This makes keeping documentation examples &lt;i&gt;actually compiling&lt;/i&gt; trivial
to support.  For example, 
&lt;a href="http://gitorious.org/cadenza/cadenza/blobs/master/src/Cadenza/Documentation/en/Cadenza/ObjectCoda.xml"
&gt;I'll have documentation refer to my unit tests&lt;/a&gt;, e.g.&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
&amp;lt;code lang="C#" src="../../Test/Cadenza/ObjectTest.cs#With" /&amp;gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;One final point worth mentioning: you can import documentation as often as
you want.  The imported documentation will &lt;i&gt;always overwrite&lt;/i&gt; whatever is
already present within the documentation repository.  Consequently, if you
want to use &lt;tt&gt;mdoc&lt;/tt&gt; for display purposes but want to continue using
inline XML documentation, always import the compiler-generated &lt;tt&gt;.xml&lt;/tt&gt; 
file.&lt;/p&gt;

&lt;p&gt;Now, we can update our HTML documentation:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;$ mdoc export-html -o html Documentation/en
Cadenza.ObjectCoda&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;
&lt;a href="http://www.jprl.com/Blog/../Projects/mdoc/blog/2010/html.docs"&gt;The current &lt;tt&gt;Demo.dll&lt;/tt&gt; documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next time, we'll cover customizing the static HTML output.&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-10.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-10.html</guid>
      <pubDate>Sun, 10 Jan 2010 13:20:00 -0500</pubDate>
    </item>
    <item>
      <title>Using mdoc</title>
      <description>&lt;html&gt;

&lt;p&gt;As mentioned &lt;a href="http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-08.html"&gt;last time&lt;/a&gt;, 
&lt;a href="http://www.go-mono.com/docs/index.aspx?link=man:mdoc%281%29"&gt;mdoc&lt;/a&gt;
is an &lt;i&gt;assembly-based&lt;/i&gt; documentation management system.  Thus, before you
can use &lt;tt&gt;mdoc&lt;/tt&gt; you need an assembly to document.  Let's write some C#
source:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
using System;

namespace Cadenza {
    public static class ObjectCoda {
        public static TResult With&amp;lt;TSource, TResult&amp;gt;(
                this TSource self, 
                Func&amp;lt;TSource, TResult&amp;gt; selector)
        {
            if (selector == null)
                throw new ArgumentNullException ("selector");
            return selector (self);
        }
    }
}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Compile it into an assembly (use &lt;tt&gt;csc&lt;/tt&gt; if running on Windows):&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="shell"&gt;$ gmcs /t:library /out:Demo.dll demo.cs&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Now that we have an assembly, we can create the &lt;i&gt;mdoc repository&lt;/i&gt; for
the &lt;tt&gt;Demo.dll&lt;/tt&gt; assembly, which will contain &lt;i&gt;documentation stubs&lt;/i&gt;
for all publically visible types and members in the assembly:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="shell"&gt;
$ mdoc update -o Documentation/en Demo.dll --exceptions=added
New Type: Cadenza.ObjectCoda
Member Added: public static TResult With&amp;lt;TSource,TResult&amp;gt; (this TSource self, Func&amp;lt;TSource,TResult&amp;gt; selector);
Namespace Directory Created: Cadenza
New Namespace File: Cadenza
Members Added: 1, Members Deleted: 0&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-update(1)"
&gt;mdoc update&lt;/a&gt; is the command for for synchronizing the documentation 
repository with the assembly; it can be run multiple times.  The
&lt;tt&gt;-o&lt;/tt&gt; option specifies where to write the documentation repository.
&lt;tt&gt;Demo.dll&lt;/tt&gt; is the assembly to process; any number of assemblies can be
specified. The &lt;tt&gt;--exceptions&lt;/tt&gt; argument analyzes the IL to
statically determine which exception types can be generated from a member.  (It
is not without some limitations; see the "--exceptions" documentation section.) 
The &lt;tt&gt;added&lt;/tt&gt; argument to &lt;tt&gt;--exceptions&lt;/tt&gt; tells &lt;tt&gt;mdoc&lt;/tt&gt; to add
&lt;tt&gt;&amp;lt;exception/&amp;gt;&lt;/tt&gt; elements only for types and members that have been
added to the repository, not to all types and members in the assembly.  This
is useful for when you've removed &lt;tt&gt;&amp;lt;exception/&amp;gt;&lt;/tt&gt; documentation and
don't want &lt;tt&gt;mdoc&lt;/tt&gt; to re-add them.&lt;/p&gt;

&lt;p&gt;We choose &lt;tt&gt;Documentation/en&lt;/tt&gt; as the documentation repository
location so that we can easily support localizing the documentation into
multiple languages: each directory underneath &lt;tt&gt;Documentation&lt;/tt&gt; would
be named after an &lt;a href="http://en.wikipedia.org/wiki/ISO_639-1"&gt;ISO
639-1&lt;/a&gt; code, e.g. &lt;tt&gt;en&lt;/tt&gt; is for English.  This is only a convention,
and is not required; any directory name can be used.&lt;/p&gt;

&lt;p&gt;Notice that, since &lt;tt&gt;mdoc&lt;/tt&gt; is processing assemblies, it will be able
to work with any language that can generate assemblies, such as Visual
Basic.NET and F#.  It does not require specialized support for each
language.&lt;/p&gt;

&lt;p&gt;Now we have a documentation repository containing XML files; a particularly
relevant file is 
&lt;a href="http://www.jprl.com/Blog/../Projects/mdoc/blog/2010/Documentation/en/Cadenza/ObjectCoda.xml"
&gt;ObjectCoda.xml&lt;/a&gt;, which contains the documentation stubs for our added
type.  I won't show the output here, but if you view it there are three
important things to note:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The XML is full of type information, e.g. the
    &lt;tt&gt;/Type/Members/Member/Parameters/Parameter/@Type&lt;/tt&gt; attribute
    value.&lt;/li&gt;
  &lt;li&gt;The XML contains additional non-documentation information, such as the
    &lt;tt&gt;//AssemblyVersion&lt;/tt&gt; elements.  This will be discussed in a future
    blog posting.&lt;/li&gt;
  &lt;li&gt;The &lt;tt&gt;//Docs&lt;/tt&gt; elements are a &lt;i&gt;container&lt;/i&gt; for the usual 
    &lt;a href="http://msdn.microsoft.com/en-us/library/b2s063f7(VS.71).aspx"&gt;C# 
    XML documentation elements&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of course, a documentation repository isn't very useful on it's own.  We
want to view it!  &lt;tt&gt;mdoc&lt;/tt&gt; provides three ways to view documentation:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-export-html(1)"
    &gt;mdoc export-html&lt;/a&gt;: This command generates a set of static HTML
    files for all types and members found within the documentation repository.
    &lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-assemble(1)"
    &gt;mdoc assemble&lt;/a&gt;: This command 
    &lt;a href="http://www.mono-project.com/Generating_Documentation#Assemble_the_generated_Documentation"
    &gt;"assembles"&lt;/a&gt; the documentation repository into a &lt;tt&gt;.zip&lt;/tt&gt; and 
    &lt;tt&gt;.tree&lt;/tt&gt; file for use with the 
    &lt;a href="http://www.mono-project.com/Monodoc"&gt;monodoc Documentation
    browser&lt;/a&gt; and the 
    &lt;a href="http://anonsvn.mono-project.com/source/trunk/mono-tools/webdoc/"
    &gt;ASP.NET front-end&lt;/a&gt; (which powers 
    &lt;a href="http://www.go-mono.com/docs"&gt;http://www.go-mono.com/docs&lt;/a&gt;).
    &lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-export-msxdoc(1)"
    &gt;mdoc export-msxdoc&lt;/a&gt;: This generates the "traditional" XML file
    which contains only member documentation.  This is for use with IDEs like
    Visual Studio, so that the IDE can show summary documentation while
    editing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We will cover &lt;tt&gt;mdoc assemble&lt;/tt&gt; and &lt;tt&gt;mdoc export-msxdoc&lt;/tt&gt; in
future installments.  For now, to generate static HTML:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="shell"&gt;$ mdoc export-html -o html Documentation/en
Cadenza.ObjectCoda&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;
&lt;a href="http://www.jprl.com/Blog/../Projects/mdoc/blog/2010/html"&gt;The current &lt;tt&gt;Demo.dll&lt;/tt&gt; documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next time we will cover how to write actual documentation instead of just
documentation stubs.&lt;/p&gt;

&lt;/html&gt;
</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-09.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-09.html</guid>
      <pubDate>Sat, 09 Jan 2010 17:28:00 -0500</pubDate>
    </item>
    <item>
      <title>TekPub's Mastering LINQ Challenge</title>
      <description>
&lt;p&gt;&lt;a href="http://www.codethinked.com/"&gt;Justin Etheredge&lt;/a&gt; has posted 
&lt;a href="http://www.codethinked.com/post/2010/01/08/TekPubs-Mastering-LINQ-Challenge.aspx"
&gt;TekPub's Mastering LINQ Challenge&lt;/a&gt;, in which he lays out a "little LINQ
challenge."  The rules:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;You have to blog about a single LINQ query which starts with
    &lt;tt&gt;Enumerable.Range(1,n)&lt;/tt&gt; and produces a list of prime numbers from 
    the range.  Thus, this blog posting.
    (Otherwise I'd rely on
    &lt;a href="http://twitter.com/jonpryor#status_star_7535470987"&gt;my twitter
    response&lt;/a&gt;.)&lt;/li&gt;
  &lt;li&gt;You can't cheat. This is determined by me, and includes hardcoding values
    in the results. You'll know if you cheated.  Part of me wonders if &lt;i&gt;just
    being me&lt;/i&gt; qualifies as cheating, but that might imply that my computer
    self has too large an ego &lt;sup&gt;&amp;lt;/ob-##csharp-meme&amp;gt;&lt;/sup&gt;.&lt;/li&gt;
  &lt;li&gt;Uses no custom LINQ methods.  Here I ponder what constitutes a "custom
    LINQ method."  Is &lt;i&gt;any&lt;/i&gt; extension method a custom LINQ method?  Any
    utility code?&lt;/li&gt;
  &lt;li&gt;Will return all of the prime numbers of the sequence. It doesn't have to 
    be super optimal, but it has to be correct.  Boy is it &lt;i&gt;not&lt;/i&gt; super
    optimal (it's a one liner!), but some improvements could make it better
    (e.g. Memoization, hence the prior question about whether extension
    methods constitute a "custom LINQ method").&lt;/li&gt;
  &lt;li&gt;Be one of the first 5 people to blog a correct answer and 
    &lt;b&gt;then tweet this "I just solved the @tekpub LINQ challenge: &amp;lt;link to
    post&amp;gt;"&lt;/b&gt; will get any single TekPub screencast. The time of your 
    solution will be based on your tweet! So be prompt!
    &lt;p&gt;As far as timliness, I'm writing this blog entry over four hours after
    my tweet, so, uh, so much for timliness.&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;You must link to both &lt;a href="http://www.tekpub.com/"&gt;TekPub's
    website&lt;/a&gt; and 
    &lt;a href="http://www.codethinked.com/post/2010/01/08/TekPubs-Mastering-LINQ-Challenge.aspx"
    &gt;this post&lt;/a&gt; in your blog post.
    &lt;p&gt;Done, and done.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, the quick and dirty, not at all efficent answer (with longer
identifiers as I certainly have more than 140 characters to play with:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
Enumerable.Range(1, n).Where(value =&amp;gt; 
    value &amp;lt;= 3
        ? true
        : Enumerable.Range(2, value - 2)
          .All(divisor =&amp;gt; value % divisor != 0))
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;In English, we take all integers between &lt;tt&gt;1&lt;/tt&gt; and &lt;tt&gt;n&lt;/tt&gt;.  Given
a &lt;tt&gt;value&lt;/tt&gt; from that sequence, if the value is less than 3, it's prime.
If it's greater than three, take all numbers from &lt;tt&gt;2&lt;/tt&gt; until 
&lt;tt&gt;value-1&lt;/tt&gt; and see if any of them divides &lt;tt&gt;value&lt;/tt&gt; with no
remainder.  If none of them divide with no remainder, &lt;tt&gt;value&lt;/tt&gt; is
prime.&lt;/p&gt;

&lt;p&gt;We need to use &lt;tt&gt;value-2&lt;/tt&gt; in the nested &lt;tt&gt;Enumerable.Range&lt;/tt&gt;
call so that we skip the value itself (since we're starting at
&lt;tt&gt;2&lt;/tt&gt;).&lt;/p&gt;

&lt;p&gt;Now, we can improve upon this in a fairly straightforward fashion if we can
use additional code.  For example, if we use 
&lt;a href="http://bartdesmet.net/blogs/bart/archive/2008/10/21/memoization-for-dummies.aspx"
&gt;Bart de Smet's &lt;tt&gt;Memoize&lt;/tt&gt; extension method&lt;/a&gt; on 
&lt;a href="http://msdn.microsoft.com/en-us/library/bb549151.aspx"
&gt;System.Func&amp;lt;T, TResult&amp;gt;&lt;/a&gt;, we can skip the repeated nested
&lt;tt&gt;Enumerable.Range&lt;/tt&gt; call on &lt;i&gt;every&lt;/i&gt; value, as prime numbers don't
change (and thus are prime candidates for caching ;-):&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
Func&amp;lt;int, bool&amp;gt; isPrime = value =&amp;gt; 
    value &amp;lt;= 3
        ? true
        : Enumerable.Range(2, value - 2)
          .All(divisor =&amp;gt; value % divisor != 0))
isPrime = isPrime.Memoize();
Enumerable.Range(1, n).Where(value =&amp;gt; isPrime(value));
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Whether this latter answer matches the rules depends upon the definition of
"single LINQ query" (does the definition of &lt;tt&gt;isPrime&lt;/tt&gt; need to be part
of the LINQ query, or just its use?) and whether Bart's &lt;tt&gt;Memoize&lt;/tt&gt;
extension method qualifies as a "custom LINQ method" (I don't think it is...).
The downside to the memoization is that it's basically a memory leak in
disguise, so I still wouldn't call it "optimal," just that it likely has
better performance characteristics than my original query...&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/2010/Jan-08.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/2010/Jan-08.html</guid>
      <pubDate>Sat, 09 Jan 2010 03:12:00 -0500</pubDate>
    </item>
    <item>
      <title>What is mdoc?</title>
      <description>
&lt;p&gt;&lt;a href="http://www.mono-project.com/Mdoc"&gt;mdoc&lt;/a&gt; is an
&lt;i&gt;assembly-based&lt;/i&gt; documentation management system, which recently 
&lt;a href="http://www.go-mono.com/archive/mdoc-net-2010-01-04.zip"&gt;added support 
for .NET &lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I say "assembly based" because an alternative is &lt;i&gt;source-based&lt;/i&gt;,
which is what "normal"
&lt;a href="http://msdn.microsoft.com/en-us/library/b2s063f7(VS.71).aspx"&gt;C# XML 
documentation&lt;/a&gt;, &lt;a href="http://java.sun.com/j2se/javadoc/"&gt;JavaDoc&lt;/a&gt;,
and &lt;a href="http://perldoc.perl.org/perlpod.html"&gt;perlpod&lt;/a&gt; provide. Unlike
these source-based systems, in &lt;tt&gt;mdoc&lt;/tt&gt; documentation for public types and 
members are not present within source code.  Instead, documentation is stored
&lt;i&gt;externally&lt;/i&gt; (to the source), 
&lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc(5)"&gt;in a
directory of XML files&lt;/a&gt; (hereafter refered to as the mdoc repository).&lt;/p&gt;

&lt;p&gt;Furthermore, &lt;tt&gt;mdoc&lt;/tt&gt; provides commands to:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-update(1)"
    &gt;synchronize&lt;/a&gt; the mdoc repository with an assembly being documented 
    (adding to the repository any types and members added to the
    assembly);&lt;/li&gt;
  &lt;li&gt;to export the mdoc repository into 
    &lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-export-html(1)"
    &gt;HTML&lt;/a&gt; or
    &lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-export-msxdoc(1)"
    &gt;Microsoft's XML format&lt;/a&gt; (for use with an IDE like 
      &lt;a href="http://www.microsoft.com/visualstudio/en-us/default.mspx"&gt;Visual 
      Studio&lt;/a&gt; and &lt;a href="http://monodevelop.com/"&gt;MonoDevelop&lt;/a&gt;);&lt;/li&gt;
  &lt;li&gt;to &lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-validate(1)"
    &gt;validate&lt;/a&gt; the mdoc repository XML schema;&lt;/li&gt;
  &lt;li&gt;to &lt;a href="http://www.go-mono.org/docs/index.aspx?link=man:mdoc-assemble(1)"
    &gt;assemble&lt;/a&gt; the mdoc repository for use with the 
    &lt;a href="http://www.mono-project.com/Monodoc"&gt;Monodoc Documentation
    Browser&lt;/a&gt; and the 
    &lt;a href="http://anonsvn.mono-project.com/source/trunk/mono-tools/webdoc/"
    &gt;ASP.NET front-end&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Why the mdoc repository?&lt;/h3&gt;

&lt;p&gt;Why have a directory of XML files as the mdoc repository?  The mdoc 
repository comes from the need to satisfy two goals:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The 
    &lt;a href="http://msdn.microsoft.com/en-us/library/3260k4x7(VS.71).aspx"
    &gt;compiler-generated /doc&lt;/a&gt; XML contains no type information.&lt;/li&gt;
  &lt;li&gt;Having types is &lt;i&gt;very&lt;/i&gt; useful for HTML output/etc., 
    so the type information must come from &lt;i&gt;somewhere&lt;/i&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Said "somewhere" could be the actual assemblies being documented, but this 
has other downsides (e.g. it would complicate supporting different versions of
the same assembly).  &lt;tt&gt;mdoc&lt;/tt&gt; uses the repository to contain both
documentation and full type information, so that the source assemblies are
&lt;i&gt;only&lt;/i&gt; needed to update the repository (and nothing else).&lt;/p&gt;

&lt;h3&gt;Why use mdoc?&lt;/h3&gt;

&lt;p&gt;Which provides enough background to get to the point: why use
&lt;tt&gt;mdoc&lt;/tt&gt;?&lt;/p&gt;

&lt;p&gt;You would primarily want to use &lt;tt&gt;mdoc&lt;/tt&gt; if you want to view your 
documentation &lt;i&gt;outside&lt;/i&gt; of an IDE, e.g. within a web browser or 
stand-alone documentation browser.  Most &lt;tt&gt;mdoc&lt;/tt&gt; functionality is geared 
toward making documentation viewable (e.g. &lt;tt&gt;mdoc export-html&lt;/tt&gt; and
&lt;tt&gt;mdoc assemble&lt;/tt&gt;), and making the documentation that is viewed more
useful (such as the full type information provided by &lt;tt&gt;mdoc update&lt;/tt&gt; and
the generation of &lt;tt&gt;&amp;lt;exception/&amp;gt;&lt;/tt&gt; elements for documentation
provided by &lt;tt&gt;mdoc update --exceptions&lt;/tt&gt;).&lt;/p&gt;

&lt;p&gt;Next time, we'll discuss how to use &lt;tt&gt;mdoc&lt;/tt&gt;.&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-08.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-08.html</guid>
      <pubDate>Fri, 08 Jan 2010 14:22:00 -0500</pubDate>
    </item>
    <item>
      <title>Re-Introducing mdoc</title>
      <description>
&lt;p&gt;Many moons ago, 
&lt;a href="http://msmvps.com/blogs/jon_skeet/archive/2009/11/06/noda-time-is-born.aspx"
&gt;Jon Skeet announced Noda Time&lt;/a&gt;.  In it he asked:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;How should documentation be created and distributed?&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;Is &lt;a href="http://www.sandcastledocs.com/"&gt;Sandcastle&lt;/a&gt; the best way 
      of building docs? How easy is it to get it running so that any developer 
      can build the docs at any time? (I've previously tried a couple of times, 
      and failed miserable.)&lt;/li&gt;
    &lt;li&gt;Would &lt;a href="http://www.mono-project.com/Monodoc"&gt;Monodoc&lt;/a&gt; be a 
      better approach?&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thus I pondered, "how well does 
&lt;a href="http://www.mono-project.com/Mdoc"&gt;mdoc&lt;/a&gt; support Windows
users?"&lt;/p&gt;

&lt;p&gt;The answer: not very well, particularly in an interop scenario.&lt;/p&gt;

&lt;p&gt;So, lots of bugfixing and a false-start later, and I'd like to announce 
&lt;a href="http://www.go-mono.com/archive/mdoc-net-2010-01-04.zip"&gt;mdoc for 
.NET&lt;/a&gt;.  All the power of mdoc, cross-platform.&lt;/p&gt;

&lt;p&gt;Note that these changes did not make it into 
&lt;a href="http://www.mono-project.com/Release_Notes_Mono_2.6"&gt;Mono 2.6&lt;/a&gt;, and
won't be part of a formal Mono release until 
&lt;a href="http://www.mono-project.com/Roadmap#Upcoming_Releases"&gt;Mono 2.8&lt;/a&gt;.
Consequently, if you want to run things under .NET, you should use the above
ZIP archive.  (You can, of course, install Mono on Windows and then use mdoc
via Mono, you just won't be able to run mdoc under .NET.)&lt;/p&gt;

&lt;p&gt;The changes made since Mono 2.6 include:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Always generate Unix line endings within &lt;tt&gt;mdoc&lt;/tt&gt;-generated XML
    files.  This allows directories to be shared between Windows and Linux
    (e.g. with Samba) without causing lots of differences due to end-of-line
    changes.&lt;/li&gt;
  &lt;li&gt;Fix the &lt;tt&gt;mdoc export-html&lt;/tt&gt; XML stylesheets so that they would
    work under .NET (as &lt;tt&gt;mdoc&lt;/tt&gt; uses XSLT and started relying on several
    Mono bugs).&lt;/li&gt;
  &lt;li&gt;Use 
		&lt;a href="http://msdn.microsoft.com/en-us/library/system.xml.xsl.xslcompiledtransform.aspx"
		&gt;XslCompiledTransform&lt;/a&gt;, as .NET's 
		&lt;a href="http://msdn.microsoft.com/en-us/library/system.xml.xsl.xsltransform.aspx"
		&gt;XslTransform&lt;/a&gt; is &lt;i&gt;really&lt;/i&gt; slow.  
		(Mono's &lt;tt&gt;XslCompiledTransform&lt;/tt&gt; is just a
    wrapper of &lt;tt&gt;XslTransform&lt;/tt&gt;, so this doesn't change things under
    Mono, but under .NET this brought a 3+ minute execution down to 1.7
    &lt;i&gt;seconds&lt;/i&gt;.)&lt;/li&gt;
  &lt;li&gt;Add support for properly converting &lt;tt&gt;&amp;lt;see
    cref="N:SomeNamespace"/&amp;gt;&lt;/tt&gt; links into HTML links.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next time, we'll cover what &lt;tt&gt;mdoc&lt;/tt&gt; is, and why you'd want to use
it.&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-07.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/mdoc/2010/Jan-07.html</guid>
      <pubDate>Thu, 07 Jan 2010 14:19:00 -0500</pubDate>
    </item>
    <item>
      <title>Linq to SQL on Mono 2.6: NerdDinner on Mono</title>
      <description>
&lt;p&gt;&lt;a href="http://www.nerddinner.com"&gt;NerdDinner&lt;/a&gt; is an
&lt;a href="http://www.asp.net/mvc/"&gt;ASP.NET MVC&lt;/a&gt; sample, licensed under
the &lt;a href="http://nerddinner.codeplex.com/license"&gt;Ms-PL&lt;/a&gt; with 
&lt;a href="http://nerddinner.codeplex.com"&gt;sources&lt;/a&gt; hosted at
&lt;a href="http://www.codeplex.com"&gt;CodePlex&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/mono/2009/May-14.html"&gt;Back on May 14th&lt;/a&gt;, I wrote that
NerdDinner could be run under Mono using 
&lt;a href="http://www.mono-project.com/SVN"&gt;trunk&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, I'm pleased to note that the just-released
&lt;a href="http://www.mono-project.com/Release_Notes_Mono_2.6"&gt;Mono 2.6&lt;/a&gt;
&lt;a href="http://www.mono-project.com/Release_Notes_Mono_2.6#LINQ_to_SQL"
&gt;includes these changes&lt;/a&gt;.  Furthermore, thanks to 
&lt;a href="http://ankitjain.org/blog/"&gt;ankit&lt;/a&gt;'s progress on 
&lt;a href="http://www.mono-project.com/Microsoft.Build"&gt;xbuild&lt;/a&gt;, 
installation and setup is easier than before:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Build (or otherwise obtain) 
    &lt;a href="http://www.mono-project.com/Release_Notes_Mono_2.6"&gt;Mono 2.6&lt;/a&gt;.
	  The &lt;a href="http://www.mono-project.com/Parallel_Mono_Environments"&gt;Parallel
    Mono Environments&lt;/a&gt; page may be helpful.
  &lt;/li&gt;
  &lt;li&gt;Download the &lt;a
  href="http://nerddinner.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24504#DownloadId=61450"
    &gt;NerdDinner 1.0 sources&lt;/a&gt; through a web browser.  (&lt;tt&gt;curl&lt;/tt&gt; or
    &lt;tt&gt;wget&lt;/tt&gt; won't work.)
  &lt;/li&gt;
  &lt;li&gt;Extract the NerdDinner sources:
    &lt;blockquote&gt;&lt;pre&gt;
$ mkdir -p $HOME/tmp
$ cd $HOME/tmp
$ unzip "/path/to/NerdDinner 1.0.zip"&lt;/pre&gt;&lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;Build NerdDinner 1.0:
    &lt;blockquote&gt;&lt;pre&gt;
$ cd "$HOME/tmp/NerdDinner 1.0"
$ xbuild NerdDinner/NerdDinner.csproj&lt;/pre&gt;&lt;/blockquote&gt;
    (Unfortunately we can't build just run &lt;tt&gt;xbuild&lt;/tt&gt; (or build
    &lt;tt&gt;NerdDinner.sln&lt;/tt&gt;) as this requires access to the MSTest assemblies
    used by the NerdDinner unit tests, which aren't currently present on
    Mono.)
  &lt;/li&gt;
  &lt;li&gt;Only the web portion runs under Mono,
    as does the data access layer (&lt;tt&gt;System.Data.Linq&lt;/tt&gt;, more
    affectionately known as Linq to SQL).  The database is still &lt;a
    href="http://www.microsoft.com/sqlserver/2008/en/us/default.aspx"&gt;Microsoft
    SQL Server&lt;/a&gt;.
    &lt;a href="http://www.jprl.com/Blog/archive/development/mono/2009/May-14.html#nerddinner-sqlserver-configuration"&gt;Go
    forth and configure the NerdDinner server&lt;/a&gt; (if you don't already have
    one configured).
  &lt;/li&gt;
  &lt;li&gt;Back on the Linux side of things, edit &lt;tt&gt;$HOME/tmp/NerdDinner
    1.0/NerdDinner/ConnectionStrings.config&lt;/tt&gt;, and change the
    &lt;tt&gt;NerdDinnerConnectionString&lt;/tt&gt; connection string to:
&lt;blockquote&gt;&lt;pre&gt;
&amp;lt;add name="NerdDinnerConnectionString"
    connectionString="Data Source=gourry\SQLEXPRESS;
    Initial Catalog=NerdDinner;
    User ID=gourry\jonp;
    Password=123456; 
    Integrated Security=true"/&amp;gt;
&lt;/pre&gt;&lt;/blockquote&gt;
    You will need to adjust the machine name in the Data Source parameter to
    contain your actual computer name, and change the User ID and Password to
    whatever values you chose when configuring SQL Server.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;a href="http://www.jprl.com/Blog/archive/development/mono/2009/May-14.html#nerddinner-membershipprovider"&gt;Configure
    a MembershipProvider for NerdDinner username/password storage.&lt;/a&gt;
  &lt;/li&gt;
  &lt;li&gt;Run the web app:
    &lt;blockquote&gt;&lt;pre&gt;
$ cd "$HOME/tmp/NerdDinner 1.0/NerdDinner"
$ MONO_IOMAP=all xsp2&lt;/pre&gt;&lt;/blockquote&gt;
    The &lt;a href="http://www.mono-project.com/IOMap"&gt;MONO_IOMAP&lt;/a&gt; environment
    variable is needed because some link targets used within NerdDinner
    require case insensitivity.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Some things worth noting &lt;a href="http://www.jprl.com/Blog/archive/development/mono/2009/May-14.html"&gt;since
May&lt;/a&gt;.  First, &lt;a href="http://www.opensuse.org/"&gt;openSUSE&lt;/a&gt; has released 
&lt;a href="http://en.opensuse.org/11.2"&gt;openSUSE 11.2&lt;/a&gt;, which is apparently
more stringent than 11.1.  Consequently, you may need to open the firewall so
that port 8080 is accessible.  You can do this by:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Opening YaST.&lt;/li&gt;
  &lt;li&gt;Starting the Firewall applet.&lt;/li&gt;
  &lt;li&gt;In the Allowed Services area, add the HTTP Server and Mono XSP2 ASP.NET
    Host Service services.&lt;/li&gt;
  &lt;li&gt;Click &lt;u&gt;N&lt;/u&gt;ext, then &lt;u&gt;F&lt;/u&gt;inish.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One other oddity I encountered is that a url of
&lt;tt&gt;http://localhost:8080&lt;/tt&gt; isn't permitted; using &lt;b&gt;telnet&lt;/b&gt;(1) shows
that it attempts to connect to &lt;tt&gt;::1...&lt;/tt&gt; (i.e. a IPv6 address), and the
connection is refused.  Instead, I needed to connect to
&lt;tt&gt;http://127.0.0.1:8080&lt;/tt&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;img src="http://www.jprl.com/Blog/archive/development/mono/2009/NerdDinner.png" alt="NerdDinnner on Linux!" /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/2009/Dec-15.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/2009/Dec-15.html</guid>
      <pubDate>Tue, 15 Dec 2009 20:30:00 -0500</pubDate>
    </item>
    <item>
      <title>Mono.Data.Sqlite &amp;amp; System.Data in MonoTouch 1.2 [Preview]</title>
      <description>
&lt;p&gt;One of the new features that will be present in MonoTouch 1.2 is inclusion
of the System.Data and Mono.Data.Sqlite assemblies.  &lt;i&gt;This is a preview
release of System.Data et. al&lt;/i&gt;; it may not fully work.  
&lt;a href="#mt-sqlite-restrictions"&gt;Known limitations are at the end of this
post&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id="mt-sqlite-meaning"&gt;What Does This Mean?&lt;/h3&gt;

&lt;p&gt;It means that the following assemblies will be
included in MonoTouch 1.2, and thus usable by MonoTouch applications:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;tt&gt;System.Data.dll&lt;/tt&gt;: Reduced; &lt;a href="#mt-sqlite-restrictions"&gt;see below&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;tt&gt;System.Transactions.dll&lt;/tt&gt;: Unchanged.&lt;/li&gt;
  &lt;li&gt;&lt;tt&gt;Mono.Data.Tds.dll&lt;/tt&gt;: Unchanged.&lt;/li&gt;
  &lt;li&gt;&lt;tt&gt;Mono.Data.Sqlite.dll&lt;/tt&gt;: Unchanged, but &lt;a href="#mt-sqlite-restrictions"&gt;see below&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="mt-sqlite-example"&gt;Example?&lt;/h3&gt;
&lt;p&gt;Sure:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
using System;
using System.Data;
using System.IO;
using Mono.Data.Sqlite;

class Demo {
    static void Main (string [] args)
    {
        var connection = GetConnection ();
        using (var cmd = connection.CreateCommand ()) {
            connection.Open ();
            cmd.CommandText = "SELECT * FROM People";
            using (var reader = cmd.ExecuteReader ()) {
                while (reader.Read ()) {
                    Console.Error.Write ("(Row ");
                    Write (reader, 0);
                    for (int i = 1; i &amp;lt; reader.FieldCount; ++i) {
                        Console.Error.Write(" ");
                        Write (reader, i);
                    }
                    Console.Error.WriteLine(")");
                }
            }
            connection.Close ();
        }
    }		

    static SqliteConnection GetConnection()
    {
        var documents = Environment.GetFolderPath (
                Environment.SpecialFolder.Personal);
        string db = Path.Combine (documents, "mydb.db3");
        bool exists = File.Exists (db);
        if (!exists)
            SqliteConnection.CreateFile (db);
        var conn = new SqliteConnection("Data Source=" + db);
        if (!exists) {
            var commands = new[] {
                "CREATE TABLE People (PersonID INTEGER NOT NULL, FirstName ntext, LastName ntext)",
                "INSERT INTO People (PersonID, FirstName, LastName) VALUES (1, 'First', 'Last')",
                "INSERT INTO People (PersonID, FirstName, LastName) VALUES (2, 'Dewey', 'Cheatem')",
                "INSERT INTO People (PersonID, FirstName, LastName) VALUES (3, 'And', 'How')",
            };
            foreach (var cmd in commands)
                using (var c = conn.CreateCommand()) {
                    c.CommandText = cmd;
                    c.CommandType = CommandType.Text;
                    conn.Open ();
                    c.ExecuteNonQuery ();
                    conn.Close ();
                }
        }
        return conn;
    }

    static void Write(SqliteDataReader reader, int index)
    {
        Console.Error.Write("({0} '{1}')", 
                reader.GetName(index), 
                reader [index]);
    }
}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;The above code creates the &lt;tt&gt;Documents/mydb.db3&lt;/tt&gt; SQLite database,
populates it if it doesn't already exist, then executes a SQL query against
the database using normal, standard, ADO.NET mechanisms.&lt;/p&gt;

&lt;h3 id="mt-sqlite-restrictions"&gt;What's Missing?&lt;/h3&gt;

&lt;p&gt;Functionality is missing from &lt;tt&gt;System.Data.dll&lt;/tt&gt; and
&lt;tt&gt;Mono.Data.Sqlite.dll&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;Functionality missing from &lt;b&gt;System.Data.dll&lt;/b&gt; consists of:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Anything requiring &lt;a
    href="http://go-mono.com/docs/index.aspx?link=N:System.CodeDom"
    &gt;System.CodeDom&lt;/a&gt; (e.g. 
    &lt;a href="http://go-mono.com/docs/index.aspx?link=T%3aSystem.Data.TypedDataSetGenerator"
    &gt;System.Data.TypedDataSetGenerator&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;XML config file support (e.g.
    &lt;a href="http://go-mono.com/docs/index.aspx?link=T%3aSystem.Data.Common.DbProviderConfigurationHandler"
    &gt;System.Data.Common.DbProviderConfigurationHandler&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://go-mono.com/docs/index.aspx?link=T%3aSystem.Data.Common.DbProviderFactories"
    &gt;System.Data.Common.DbProviderFactories&lt;/a&gt; (depends on XML config file 
    support)&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://go-mono.com/docs/index.aspx?link=N%3aSystem.Data.OleDb"
    &gt;System.Data.OleDb&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://go-mono.com/docs/index.aspx?link=N%3aSystem.Data.Odbc"
    &gt;System.Data.Odbc&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;The &lt;tt&gt;System.EnterpriseServices.dll&lt;/tt&gt; dependency was 
    &lt;i&gt;removed&lt;/i&gt; from &lt;tt&gt;System.Data.dll&lt;/tt&gt;, resulting in the removal of
    the &lt;a href="http://go-mono.com/docs/index.aspx?link=M%3aSystem.Data.SqlClient.SqlConnection.EnlistDistributedTransaction(System.EnterpriseServices.ITransaction)"
    &gt;SqlConnection.EnlistDistributedTransaction(ITransaction)&lt;/a&gt;
    method.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Meanwhile, &lt;b&gt;Mono.Data.Sqlite.dll&lt;/b&gt; suffered no source code changes, but
instead may be host to a number of &lt;i&gt;runtime&lt;/i&gt; issues (the primary reason
this is a preview release).  &lt;tt&gt;Mono.Data.Sqlite.dll&lt;/tt&gt; binds SQLite 3.5.
iPhoneOS, meanwhile, ships with SQLite 3.0.  Suffice it to say, some things
have changed between the two versions. ;-)&lt;/p&gt;

&lt;p&gt;Thus, the real question is this: what's missing in SQLite 3.0?  The
following functions are used by &lt;tt&gt;Mono.Data.Sqlite.dll&lt;/tt&gt; but are missing
from iPhoneOS's SQLite:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;sqlite3_column_database_name&lt;/li&gt;
  &lt;li&gt;sqlite3_column_database_name16&lt;/li&gt;
  &lt;li&gt;sqlite3_column_origin_name&lt;/li&gt;
  &lt;li&gt;sqlite3_column_origin_name16&lt;/li&gt;
  &lt;li&gt;sqlite3_column_table_name&lt;/li&gt;
  &lt;li&gt;sqlite3_column_table_name16&lt;/li&gt;
  &lt;li&gt;sqlite3_key&lt;/li&gt;
  &lt;li&gt;sqlite3_rekey&lt;/li&gt;
  &lt;li&gt;sqlite3_table_column_metadata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where are these functions used (i.e. what can't you use from
&lt;tt&gt;Mono.Data.Sqlite&lt;/tt&gt;)?   These appear to be related to database schema
querying, e.g. determining at runtime which columns exist on a given table,
such as 
&lt;tt&gt;Mono.Data.Sqlite.SqliteConnection.GetSchema&lt;/tt&gt; (overriding 
&lt;a href="http://go-mono.com/docs/index.aspx?link=M%3aSystem.Data.Common.DbConnection.GetSchema"
&gt;DbConnection.GetSchema&lt;/a&gt;)
and &lt;tt&gt;Mono.Data.Sqlite.SqliteDataReader.GetSchemaTable&lt;/tt&gt; (overriding
&lt;a href="http://go-mono.com/docs/index.aspx?link=M%3aSystem.Data.Common.DbDataReader.GetSchemaTable"
&gt;DbDataReader.GetSchemaTable&lt;/a&gt;).  In short, it seems that anything using
&lt;a href="http://go-mono.com/docs/index.aspx?link=T%3aSystem.Data.DataTable"
&gt;DataTable&lt;/a&gt; is unlikely to work.&lt;/p&gt;

&lt;h3 id="mt-sqlite-why-sqlite"&gt;Why Provide Mono.Data.Sqlite?&lt;/h3&gt;

&lt;p&gt;Why not?  We realize that there are pre-existing SQLite solutions, but felt
that many people would prefer to use the ADO.NET code they're already familiar
with.  Bringing &lt;tt&gt;System.Data&lt;/tt&gt; and &lt;tt&gt;Mono.Data.Sqlite&lt;/tt&gt; to
MonoTouch permits this.&lt;/p&gt;

&lt;h3 id="mt-sqlite-data-binding"&gt;What About Data Binding?&lt;/h3&gt;

&lt;p&gt;Data binding with e.g. a 
&lt;a href="http://go-mono.com/docs/index.aspx?link=T%3aMonoTouch.UIKit.UITableView"
&gt;UITableView&lt;/a&gt; is not currently implemented.&lt;/p&gt;

&lt;h3 id="mt-sqlite-conclusion"&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;I suck at conclusions. :-)&lt;/p&gt;
&lt;p&gt;Hope you enjoy this preview!&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/MonoTouch/2009/Oct-21.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/MonoTouch/2009/Oct-21.html</guid>
      <pubDate>Thu, 22 Oct 2009 03:25:00 -0500</pubDate>
    </item>
    <item>
      <title>Linq to SQL on Mono Update: NerdDinner on Mono</title>
      <description>
&lt;p&gt;&lt;a href="http://www.nerddinner.com"&gt;NerdDinner&lt;/a&gt; is an
&lt;a href="http://www.asp.net/mvc/"&gt;ASP.NET MVC&lt;/a&gt; sample, licensed under
the &lt;a href="http://nerddinner.codeplex.com/license"&gt;Ms-PL&lt;/a&gt; with 
&lt;a href="http://nerddinner.codeplex.com"&gt;sources&lt;/a&gt; hosted at
&lt;a href="http://www.codeplex.com"&gt;CodePlex&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It is now possible to run the web portions of NerdDinner 1.0 on Linux with 
Mono trunk, thanks to &lt;a href="http://twistedcode.net/blog/"&gt;Marek
Habersack&lt;/a&gt; and &lt;a href="http://gonzalo.name/blog/index.html"&gt;Gonzalo
Paniagua Javier&lt;/a&gt;'s help with Mono's ASP.NET and ASP.NET MVC support, and
the &lt;a href="http://groups.google.com/group/dblinq"&gt;DbLinq&lt;/a&gt; community's
assistance with Linq to SQL support.&lt;/p&gt;

&lt;p&gt;This shows a growing level of maturity within Mono's Linq to SQL
implementation.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Build &lt;a href="http://www.mono-project.com"&gt;Mono&lt;/a&gt; from trunk.  The
    &lt;a href="http://www.mono-project.com/Parallel_Mono_Environments"&gt;Parallel
    Mono Environments&lt;/a&gt; page may be helpful.
  &lt;/li&gt;
  &lt;li&gt;Download the &lt;a
  href="http://nerddinner.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24504#DownloadId=61450"
    &gt;NerdDinner 1.0 sources&lt;/a&gt; through a web browser.  (&lt;tt&gt;curl&lt;/tt&gt; or
    &lt;tt&gt;wget&lt;/tt&gt; won't work.)
  &lt;/li&gt;
  &lt;li&gt;Extract the NerdDinner sources:
    &lt;blockquote&gt;&lt;pre&gt;
$ mkdir -p $HOME/tmp
$ cd $HOME/tmp
$ unzip "/path/to/NerdDinner 1.0.zip"&lt;/pre&gt;&lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;Build NerdDinner 1.0:
    &lt;blockquote&gt;&lt;pre&gt;
$ cd "$HOME/tmp/NerdDinner 1.0/NerdDinner"
$ mkdir bin
$ gmcs -t:library -out:bin/NerdDinner.dll -debug+ -recurse:'*.cs' \
    -r:System -r:System.Configuration -r:System.Core \
    -r:System.Data -r:System.Data.Linq -r:System.Web \
    -r:System.Web.Abstractions -r:System.Web.Mvc \
    -r:System.Web.Routing&lt;/pre&gt;&lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li id="nerddinner-sqlserver-configuration"&gt;As mentioned in the introduction, only the web portion runs under Mono,
    as does the data access layer (&lt;tt&gt;System.Data.Linq&lt;/tt&gt;, more
    affectionately known as Linq to SQL).  The database is still &lt;a
    href="http://www.microsoft.com/sqlserver/2008/en/us/default.aspx"&gt;Microsoft
    SQL Server&lt;/a&gt;.  Find yourself a Windows machine, install SQL Server 2008
    (&lt;a href="http://www.microsoft.com/express/sql/default.aspx"&gt;Express&lt;/a&gt;
    is fine), and perform the following bits of configuration:
    &lt;ol type="A"&gt;
      &lt;li&gt;Create the database files:
        &lt;ol type="i"&gt;
          &lt;li&gt;Copy the &lt;tt&gt;NerdDinner_log.ldf&lt;/tt&gt; and &lt;tt&gt;NerdDinner.mdf&lt;/tt&gt;
            files from the &lt;tt&gt;$HOME/tmp/NerdDinner 1.0/NerdDinner/App_Data&lt;/tt&gt;
            directory to your Windows machine, e.g. &lt;tt&gt;C:\tmp&lt;/tt&gt;.&lt;/li&gt;
          &lt;li&gt;Within Windows Explorer, go to &lt;tt&gt;C:\tmp&lt;/tt&gt;, right-click the
            &lt;tt&gt;C:\tmp&lt;/tt&gt; folder, click &lt;b&gt;P&lt;u&gt;r&lt;/u&gt;operties&lt;/b&gt;, click the
            Security tab, click &lt;b&gt;&lt;u&gt;E&lt;/u&gt;dit...&lt;/b&gt;, and add the Full Control,
            MOdify, Read &amp;amp; execute, List folder contents, Read, and Write
            permissions to the User group.  Click OK.&lt;/li&gt;
          &lt;li&gt;Repeat the above permissions modifications for the
            &lt;tt&gt;NerdDinner_log.ldf&lt;/tt&gt; and &lt;tt&gt;NerdDinner.mdf&lt;/tt&gt; files in
            &lt;tt&gt;C:\tmp&lt;/tt&gt;.&lt;/li&gt;
        &lt;/ol&gt;
      &lt;/li&gt;
      &lt;li&gt;Add the NerdDinner database files to Microsoft SQL Server:
        &lt;ol type="i"&gt;
          &lt;li&gt;Start &lt;b&gt;Microsoft SQL Server Management Studio&lt;/b&gt; 
            (Start &amp;rarr; All Programs &amp;rarr; Microsoft SQL Server 2008 &amp;rarr; 
            SQL Server Management Studio).
          &lt;/li&gt;
          &lt;li&gt;Connect to your database instance.&lt;/li&gt;
          &lt;li&gt;Within the &lt;b&gt;Object Explorer&lt;/b&gt; (View &amp;rarr; Object Explorer), 
            right-click the database name and click &lt;b&gt;&lt;u&gt;A&lt;/u&gt;ttach...&lt;/b&gt;.
          &lt;/li&gt;
          &lt;li&gt;Within the &lt;b&gt;Attach Databases&lt;/b&gt; dialog, click the
            &lt;b&gt;&lt;u&gt;A&lt;/u&gt;dd...&lt;/b&gt; button, and choose 
            &lt;tt&gt;C:\tmp\NerdDinner.mdf&lt;/tt&gt; in the &lt;b&gt;Locate Database Files&lt;/b&gt; 
            dialog.  Click &lt;b&gt;OK&lt;/b&gt; in both the &lt;b&gt;Locate Database Files&lt;/b&gt; 
            dialog and the &lt;b&gt;Attach Databases&lt;/b&gt; dialog.&lt;/li&gt;
        &lt;/ol&gt;
      &lt;/li&gt;
      &lt;li&gt;Enable mixed-mode authentication:
        &lt;ol type="i"&gt;
          &lt;li&gt;Start &lt;b&gt;Microsoft SQL Server Management Studio&lt;/b&gt;.&lt;/li&gt;
          &lt;li&gt;Connect to your database instance.&lt;/li&gt;
          &lt;li&gt;Within the &lt;b&gt;Object Explorer&lt;/b&gt;, right-click the database name 
            and click &lt;b&gt;P&lt;u&gt;r&lt;/u&gt;operties&lt;/b&gt;.&lt;/li&gt;
          &lt;li&gt;In the &lt;b&gt;Server Properties&lt;/b&gt; dialog, select the
            &lt;b&gt;Security&lt;/b&gt; page.&lt;/li&gt;
          &lt;li&gt;In the &lt;b&gt;Server authentication&lt;/b&gt; section, select the 
            &lt;b&gt;&lt;u&gt;S&lt;/u&gt;QL Server and Windows Authentication mode&lt;/b&gt; 
            radio button.&lt;/li&gt;
          &lt;li&gt;Click &lt;b&gt;OK&lt;/b&gt;.&lt;/li&gt;
          &lt;li&gt;Restart SQL Server by right-clicking on the database name and
            clicking &lt;b&gt;Rest&lt;u&gt;a&lt;/u&gt;rt&lt;/b&gt;.&lt;/li&gt;
        &lt;/ol&gt;
      &lt;/li&gt;
      &lt;li&gt;Add a SQL Server user:
        &lt;ol type="i"&gt;
          &lt;li&gt;Within &lt;b&gt;SQL Server Management Studio&lt;/b&gt;, connect to the 
            database instance.&lt;/li&gt;
          &lt;li&gt;Within the &lt;b&gt;Object Explorer&lt;/b&gt;, expand
            the &lt;b&gt;Security&lt;/b&gt; &amp;rarr; &lt;b&gt;Logins&lt;/b&gt; tree node.&lt;/li&gt;
          &lt;li&gt;Right-click the &lt;b&gt;Logins&lt;/b&gt; node, and click 
            &lt;b&gt;&lt;u&gt;N&lt;/u&gt;ew Login...&lt;/b&gt;.&lt;/li&gt;
          &lt;li&gt;In the &lt;b&gt;Login - New&lt;/b&gt; dialog, enter a login name.  We'll use
            &lt;tt&gt;jonp&lt;/tt&gt; for discussion purposes.  Select the
            &lt;u&gt;S&lt;/u&gt;QL Server authentication dialog button, and enter a
            password in the &lt;b&gt;&lt;u&gt;P&lt;/u&gt;assword&lt;/b&gt; and 
            &lt;b&gt;&lt;u&gt;C&lt;/u&gt;onform Password&lt;/b&gt; text boxes.  For discussion purposes 
            we'll use &lt;tt&gt;123456&lt;/tt&gt;.&lt;/li&gt;
          &lt;li&gt;Still within the &lt;b&gt;Login - New&lt;/b&gt; dialog, select the 
            &lt;b&gt;User Mapping&lt;/b&gt; page.  In the &lt;b&gt;Users mappe&lt;u&gt;d&lt;/u&gt; to this
            login&lt;/b&gt; section, select the checkbox in the &lt;b&gt;Map&lt;/b&gt; column 
            corresponding to the NerdDinner database.  Within the 
            &lt;b&gt;Database &lt;u&gt;r&lt;/u&gt;ole membership for: NerdDinner&lt;/b&gt; section, 
            select the db_datareader and db_datawriter roles.
            Click &lt;b&gt;OK&lt;/b&gt;.&lt;/li&gt;
        &lt;/ol&gt;
      &lt;/li&gt;
      &lt;li&gt;Enable remote access to SQL Server (&lt;a
        href="http://blogs.msdn.com/sqlexpress/archive/2005/05/05/415084.aspx"
        &gt;see&lt;/a&gt;
        &lt;a href="http://msdn.microsoft.com/en-us/library/bb909712.aspx?ppud=4"
        &gt;also&lt;/a&gt;):
        &lt;ol type="i"&gt;
          &lt;li&gt;Configure SQL Server:
            &lt;ol type="a"&gt;
              &lt;li&gt;Start &lt;b&gt;SQL Server Configuration Manager&lt;/b&gt; 
                (Start &amp;rarr; All Programs &amp;rarr; 
                Microsoft SQL Server 2008 &amp;rarr; 
                Configuration Tools &amp;rarr; SQL Server Configuration Manager).
              &lt;/li&gt;
              &lt;li&gt;In the left-hand pane, select the &lt;b&gt;SQL Server Configuration
                manager (Local) &amp;rarr; SQL Server Network Configuration &amp;rarr; 
                Protocols for &lt;i&gt;Database Instance Name&lt;/i&gt;&lt;/b&gt; node.&lt;/li&gt;
              &lt;li&gt;In the right pane, double click the &lt;b&gt;TCP/IP Protocol&lt;/b&gt; 
                Name.&lt;/li&gt;
              &lt;li&gt;In the &lt;b&gt;Protocol&lt;/b&gt; tab, set &lt;b&gt;Enabled&lt;/b&gt; to 
                &lt;b&gt;Yes&lt;/b&gt;.  Click &lt;b&gt;OK&lt;/b&gt;.&lt;/li&gt;
              &lt;li&gt;In the left-hand pane, go to the &lt;b&gt;SQL Server Configuration
                Manager (Local) &amp;rarr; SQL Server Services&lt;/b&gt; node.&lt;/li&gt;
              &lt;li&gt;In the right pane, double-click 
                &lt;b&gt;SQL Server Browser&lt;/b&gt;.&lt;/li&gt;
              &lt;li&gt;In the &lt;b&gt;Service&lt;/b&gt; tab, set the &lt;b&gt;Start Mode&lt;/b&gt; property 
                to &lt;b&gt;Automatic&lt;/b&gt;.  Click &lt;b&gt;OK&lt;/b&gt;.&lt;/li&gt;
              &lt;li&gt;Right-click &lt;b&gt;SQL Server Browser&lt;/b&gt;, and click 
                &lt;b&gt;&lt;u&gt;S&lt;/u&gt;tart&lt;/b&gt;.&lt;/li&gt;
              &lt;li&gt;Right-click SQL Server, and click &lt;b&gt;Res&lt;u&gt;t&lt;/u&gt;art&lt;/b&gt;.&lt;/li&gt;
            &lt;/ol&gt;
          &lt;/li&gt;
          &lt;li&gt;Configure Windows Firewall
            &lt;ol type="a"&gt;
              &lt;li&gt;Within Windows &lt;b&gt;Control Panel&lt;/b&gt;, open the 
                &lt;b&gt;Windows Firewall&lt;/b&gt; applet.&lt;/li&gt;
              &lt;li&gt;Click the &lt;b&gt;Allow a program through Windows Firewall&lt;/b&gt;
                link.&lt;/li&gt;
              &lt;li&gt;In the &lt;b&gt;Windows Firewall Settings&lt;/b&gt; dialog, click the
                &lt;b&gt;Exceptions&lt;/b&gt; tab.&lt;/li&gt;
              &lt;li&gt;Click &lt;b&gt;Add p&lt;u&gt;r&lt;/u&gt;ogram...&lt;/b&gt;, and add the following 
                programs:
                &lt;ul&gt;
                  &lt;li&gt;&lt;tt&gt;sqlbrowser.exe&lt;/tt&gt; 
                    (&lt;tt&gt;C:\Program Files\Microsoft SQL
                    Server\90\Shared\sqlbrowser.exe&lt;/tt&gt;)&lt;/li&gt;
                  &lt;li&gt;&lt;tt&gt;sqlservr.exe&lt;/tt&gt; (&lt;tt&gt;C:\Program Files\Microsoft SQL
                    Server\MSSQL10.SQLEXPRESS\MSSQL\Binn\sqlservr.exe&lt;/tt&gt;)&lt;/li&gt;
                &lt;/ul&gt;
              &lt;/li&gt;
              &lt;li&gt;Click &lt;b&gt;OK&lt;/b&gt;.&lt;/li&gt;
            &lt;/ol&gt;
          &lt;/li&gt;
        &lt;/ol&gt;
      &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;Back on the Linux side of things, edit &lt;tt&gt;$HOME/tmp/NerdDinner
    1.0/NerdDinner/ConnectionStrings.config&lt;/tt&gt;, and change the
    &lt;tt&gt;NerdDinnerConnectionString&lt;/tt&gt; connection string to:
&lt;blockquote&gt;&lt;pre&gt;
&amp;lt;add name="NerdDinnerConnectionString"
    connectionString="Data Source=gourry\SQLEXPRESS;Initial Catalog=NerdDinner;User ID=jonp;Password=123456;"/&amp;gt;
&lt;/pre&gt;&lt;/blockquote&gt;
    You will need to adjust the machine name in the Data Source parameter to
    contain your actual computer name, and change the User ID and Password to
    whatever values you chose in §5.E.iv.
  &lt;/li&gt;
  &lt;li id="nerddinner-membershipprovider"&gt;NerdDinner makes use of ASP.NET's MembershipProvider functionality, so a
    SQLite database needs to be created to contain the username and password
    information for the NerdDinner site.  This is detailed at the
    &lt;a href="http://www.mono-project.com/FAQ:_ASP.NET#Common_Problems"&gt;ASP.NET
    FAQ&lt;/a&gt; and &lt;a
    href="http://www.mono-project.com/Guide:_Porting_ASP.NET_Applications#Membership.2FRoles.2FProfile_provider_schema"
    &gt;Guide: Porting ASP.NET Applications&lt;/a&gt; pages:
    &lt;blockquote&gt;&lt;pre&gt;
$ cd "$HOME/tmp/NerdDinner 1.0/NerdDinner/App_Data

# Create the commands needed to configure the SQLite database:
$ cat &amp;gt; aspnetdb.sql &amp;lt;&amp;lt;EOF
CREATE TABLE Users (
 pId                                     character(36)           NOT NULL,
 Username                                character varying(255)  NOT NULL,
 ApplicationName                         character varying(255)  NOT NULL,
 Email                                   character varying(128)  NOT NULL,
 Comment                                 character varying(128)  NULL,
 Password                                character varying(255)  NOT NULL,
 PasswordQuestion                        character varying(255)  NULL,
 PasswordAnswer                          character varying(255)  NULL,
 IsApproved                              boolean                 NULL, 
 LastActivityDate                        timestamptz             NULL,
 LastLoginDate                           timestamptz             NULL,
 LastPasswordChangedDate                 timestamptz             NULL,
 CreationDate                            timestamptz             NULL, 
 IsOnLine                                boolean                 NULL,
 IsLockedOut                             boolean                 NULL,
 LastLockedOutDate                       timestamptz             NULL,
 FailedPasswordAttemptCount              integer                 NULL,
 FailedPasswordAttemptWindowStart        timestamptz             NULL,
 FailedPasswordAnswerAttemptCount        integer                 NULL,
 FailedPasswordAnswerAttemptWindowStart  timestamptz             NULL,
 CONSTRAINT users_pkey PRIMARY KEY (pId),
 CONSTRAINT users_username_application_unique UNIQUE (Username, ApplicationName)
);

CREATE INDEX users_email_index ON Users (Email);
CREATE INDEX users_islockedout_index ON Users (IsLockedOut);

CREATE TABLE Roles (
 Rolename                                character varying(255)  NOT NULL,
 ApplicationName                         character varying(255)  NOT NULL,
 CONSTRAINT roles_pkey PRIMARY KEY (Rolename, ApplicationName)
);

CREATE TABLE UsersInRoles (
 Username                                character varying(255)  NOT NULL,
 Rolename                                character varying(255)  NOT NULL,
 ApplicationName                         character varying(255)  NOT NULL,
 CONSTRAINT usersinroles_pkey PRIMARY KEY (Username, Rolename, ApplicationName),
 CONSTRAINT usersinroles_username_fkey FOREIGN KEY (Username, ApplicationName) REFERENCES Users (Username, ApplicationName) ON DELETE CASCADE,
 CONSTRAINT usersinroles_rolename_fkey FOREIGN KEY (Rolename, ApplicationName) REFERENCES Roles (Rolename, ApplicationName) ON DELETE CASCADE
);

CREATE TABLE Profiles (
 pId                                     character(36)           NOT NULL,
 Username                                character varying(255)  NOT NULL,
 ApplicationName                         character varying(255)  NOT NULL,
 IsAnonymous                             boolean                 NULL,
 LastActivityDate                        timestamptz             NULL,
 LastUpdatedDate                         timestamptz             NULL,
 CONSTRAINT profiles_pkey PRIMARY KEY (pId),
 CONSTRAINT profiles_username_application_unique UNIQUE (Username, ApplicationName),
 CONSTRAINT profiles_username_fkey FOREIGN KEY (Username, ApplicationName) REFERENCES Users (Username, ApplicationName) ON DELETE CASCADE
);

CREATE INDEX profiles_isanonymous_index ON Profiles (IsAnonymous);

CREATE TABLE ProfileData (
 pId                                     character(36)           NOT NULL,
 Profile                                 character(36)           NOT NULL,
 Name                                    character varying(255)  NOT NULL,
 ValueString                             text                    NULL,
 ValueBinary                             bytea                   NULL,
 CONSTRAINT profiledata_pkey PRIMARY KEY (pId),
 CONSTRAINT profiledata_profile_name_unique UNIQUE (Profile, Name),
 CONSTRAINT profiledata_profile_fkey FOREIGN KEY (Profile) REFERENCES Profiles (pId) ON DELETE CASCADE
);
EOF

# Create the SQLite database:
$ sqlite3 aspnetdb.sqlite
sqlite&amp;gt; .read aspnetdb.sql
sqlite&amp;gt; .quit&lt;/pre&gt;&lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;Run the web app:
    &lt;blockquote&gt;&lt;pre&gt;
$ MONO_IOMAP=all xsp2&lt;/pre&gt;&lt;/blockquote&gt;
    The &lt;a href="http://www.mono-project.com/IOMap"&gt;MONO_IOMAP&lt;/a&gt; environment
    variable is needed because some link targets used within NerdDinner
    require case insensitivity.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;img src="http://www.jprl.com/Blog/archive/development/mono/2009/NerdDinner.png" alt="NerdDinnner on Linux!" /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/2009/May-14.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/2009/May-14.html</guid>
      <pubDate>Thu, 14 May 2009 18:47:00 -0500</pubDate>
    </item>
    <item>
      <title>Where are all the fuel efficient cars?</title>
      <description>
&lt;p&gt;With my &lt;a href="http://www.jprl.com/Blog/archive/etc/2007/Apr-30.html"
&gt;Verizon&lt;/a&gt; TV service I get &lt;a href="http://www.bbcamerica.com/"&gt;BBC
America&lt;/a&gt;, which includes the wonderful show 
&lt;a href="http://www.topgear.com"&gt;Top Gear&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A few weeks ago I saw their 
&lt;a href="http://www.topgear.com/us/videos/more/endurance-race-to-blackpool/"
&gt;endurance race to Blackpool&lt;/a&gt;, a 750 mile trip from Basel, Switzerland to
Blackpool, UK.  (Which is odd, as 
&lt;a href="http://maps.google.com/maps?f=d&amp;amp;source=s_d&amp;amp;saddr=Basel,+Switzerland&amp;amp;daddr=blackpool,+U.K.&amp;amp;hl=en&amp;amp;geocode=&amp;amp;mra=ls&amp;amp;sll=50.686255,2.343375&amp;amp;sspn=9.429459,18.852539&amp;amp;ie=UTF8&amp;amp;z=6"
&gt;Google Maps&lt;/a&gt; implies that the trip would be 1319km, or 819.5 miles.)&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.topgear.com/us/the_show/bios/jeremy_clarkson"&gt;Jeremy
Clarkson&lt;/a&gt; chose a
&lt;a href="http://www.jaguar.co.uk/uk/en/company/faq_contact_us/ebrochure/Brochure.htm"
&gt;Jaguar XJ6 TDvi&lt;/a&gt; (sorry, no direct link), which gets 32.3mpg, or 
8.7 l/100km.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.topgear.com/us/the_show/bios/james_may"&gt;James May&lt;/a&gt;
chose a
&lt;a href="http://www.subaru.co.uk/Subaru_co_uk/ViewMenu.qed?menuid=M0M5M7"
&gt;Subaru Legacy Diesel&lt;/a&gt; (click &lt;b&gt;Economy&lt;/b&gt;, then &lt;b&gt;2.0D R&lt;/b&gt; for the
mileage), which gets 56.6 mpg, or 5.0 l/100km.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.topgear.com/us/the_show/bios/richard_hammond"&gt;Richard 
Hammond&lt;/a&gt; chose a 
&lt;a href="http://www.volkswagen.co.uk/#/new/polo/which-model/engines/fuel-consumption/"
&gt;Volkswagen Polo Bluemotion&lt;/a&gt;, which was mentioned as getting 74mpg (though 
the above site lists 88.3 mpg, or 3.2 l/100km).&lt;/p&gt;

&lt;p&gt;Unfortunately, these mileages are using UK 
&lt;a href="http://en.wikipedia.org/wiki/Gallon"&gt;gallons&lt;/a&gt;, which are larger
than US gallons.  So, using a handy 
&lt;a href="http://www.markporthouse.net/rangie/fuelconsumptionconversion.htm"
&gt;online calculator&lt;/a&gt;, we see that the &lt;b&gt;Jaguar&lt;/b&gt; gets &lt;b&gt;~27mpg US&lt;/b&gt;, 
the &lt;b&gt;Subaru&lt;/b&gt; gets &lt;b&gt;~47mpg US&lt;/b&gt;, and the 
&lt;b&gt;VW&lt;/b&gt; gets &lt;b&gt;~73.5mpg US&lt;/b&gt;.&lt;/p&gt;

&lt;p&gt;Are there any equivalents to these vehicles in the USA?&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.jaguarusa.com/us/en/xj/models_pricing/specifications/specifications.htm"
&gt;Jaguar&lt;/a&gt; lists 25 mpg for some models (aside: the US site is far more link
friendly than the UK site), which is comparable to the UK Jaguar, so it's
covered.&lt;/p&gt;

&lt;p&gt;Subaru doesn't offer a diesel engine, so nothing is comparable to the 47mpg
that the UK Subaru Legacy gets.&lt;/p&gt;

&lt;p&gt;For Volkswagan, the nearest US equivalent appears to be the 
&lt;a href="http://www.vw.com/jetta/en/us/?tab=tdi"&gt;Jetta TDI&lt;/a&gt;, which gets
41mpg, a far cry from the 73.5 of the Bluemotion.&lt;/p&gt;

&lt;p&gt;Thus, the question: Why don't we have these cars in USA?&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/etc/2009/Apr-12.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/etc/2009/Apr-12.html</guid>
      <pubDate>Sun, 12 Apr 2009 15:15:00 -0500</pubDate>
    </item>
    <item>
      <title>Mono 2.4 and mdoc-update</title>
      <description>
&lt;p&gt;&lt;a href="http://www.mono-project.com/Release_Notes_Mono_2.4"&gt;Mono 2.4 was 
released&lt;/a&gt;, and among the unlisted changes was that 
&lt;a href="http://go-mono.com/docs/index.aspx?tlink=10@man%3amdoc-update(1)"
&gt;mdoc-update&lt;/a&gt; has migrated from using 
&lt;a href="http://go-mono.com/docs/index.aspx?tlink=15@N%3aSystem.Reflection"
&gt;Reflection&lt;/a&gt; to using 
&lt;a href="http://anonsvn.mono-project.com/viewvc/trunk/mcs/class/Mono.Cecil/"
&gt;Mono.Cecil&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are multiple advantages and disadvantages to this migration.  The
disadvantages include slower execution (when I tested, Mono.Cecil took ~10%
longer to do the same task as Reflection) and increased dependencies
(Mono.Cecil is now required).&lt;/p&gt;

&lt;p&gt;I believe that these disadvantages are outweighed by the advantages.
Firstly, the migration makes my life significantly easier.  One of the major
limitations of Reflection is that only one &lt;tt&gt;mscorlib.dll&lt;/tt&gt; can be loaded
into a process.  This means that, in order to support generating documentation
from &lt;tt&gt;mscorlib.dll&lt;/tt&gt; 1.0, there needs to be a version of
&lt;tt&gt;mdoc-update&lt;/tt&gt; that runs under .NET 1.0.  Similarly, to document
&lt;tt&gt;mscorlib.dll&lt;/tt&gt; 2.0, I need a &lt;i&gt;different&lt;/i&gt; version of
&lt;tt&gt;mdoc-update&lt;/tt&gt; which runs under .NET 2.0.  And when .NET 4.0 is released
(with yet another version of &lt;tt&gt;mscorlib.dll&lt;/tt&gt;), I'll need...yet another
version of &lt;tt&gt;mdoc-update&lt;/tt&gt; to run under .NET 4.0.  This is less than
ideal, and using Mono.Cecil allows me to have &lt;i&gt;one&lt;/i&gt; program which
supports every version of &lt;tt&gt;mscorlib.dll&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;This also means that I can use C# 3.0 features within &lt;tt&gt;mdoc-update&lt;/tt&gt;,
as I no longer need to ensure that (most of) &lt;tt&gt;mdoc-update&lt;/tt&gt; can run
under the .NET 1.0 profile.&lt;/p&gt;

&lt;p&gt;Most people won't care about making my life easier, but I do. ;-)&lt;/p&gt;

&lt;p&gt;For everyone else, the most important result of the Mono.Cecil migration is
that &lt;tt&gt;mdoc-update&lt;/tt&gt; now has a suitable base for advanced documentation
generation scenarios which make use of IL analysis.  The first feature making
use of it is new &lt;tt&gt;--exceptions&lt;/tt&gt; functionality, which analyzes member IL 
to determine which exceptions could be generated, and creates stub
&lt;tt&gt;&amp;lt;exception/&amp;gt;&lt;/tt&gt; XML documentation based on that analysis.  This
feature is experimental (see the 
&lt;a href="http://go-mono.com/docs/index.aspx?tlink=10@man%3amdoc-update(1)"
&gt;documentation&lt;/a&gt;), and contains a number of corner cases, but I've already
found it useful for writing 
&lt;a href="http://anonsvn.mono-project.com/viewvc/trunk/rocks/"&gt;Mono.Rocks&lt;/a&gt;
documentation.&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/2009/Mar-31.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/2009/Mar-31.html</guid>
      <pubDate>Tue, 31 Mar 2009 17:13:00 -0500</pubDate>
    </item>
    <item>
      <title>DbLinq and Mono</title>
      <description>
&lt;p&gt;.NET 3.5 introduced 
&lt;a href="http://msdn.microsoft.com/en-us/vbasic/aa904594.aspx"&gt;Language
Integrated Query&lt;/a&gt; (LINQ), which allowed for querying groupings of data
across diverse "paradigms" -- collections (arrays, lists, etc.), XML, and
&lt;a href="http://msdn.microsoft.com/en-us/library/bb425822.aspx"&gt;relational
data&lt;/a&gt;, called LINQ to SQL.  LINQ to SQL support is within the 
&lt;a href="http://msdn.microsoft.com/en-us/library/system.data.linq.aspx"
&gt;System.Data.Linq&lt;/a&gt; assembly, which is one of the assemblies Mono is
currently implementing.&lt;/p&gt;

&lt;p&gt;However, LINQ to SQL has one limitation: it only works with Microsoft SQL
Server and Microsoft SQL Server Compact Edition, leaving numerous other
databases users unable to use this assembly.&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="http://linq.to/db"&gt;DbLinq&lt;/a&gt;, an effort to provide LINQ to
SQL functionality for other databases, including Firebird, Ingres, MySQL,
Oracle, PostgreSql, SQLite, and SQL Server.  DbLinq provides a
&lt;tt&gt;System.Data.Linq&lt;/tt&gt;-compatible implementation for these databases
(compatible implying the same types and methods, but located within a
different namespace).&lt;/p&gt;

&lt;p&gt;Which brings us to &lt;a href="http://mono-project.com"&gt;Mono&lt;/a&gt;.  Mono is
using DbLinq as the foundation for Mono's &lt;tt&gt;System.Data.Linq.dll&lt;/tt&gt;
implementation, allowing Mono's &lt;tt&gt;System.Data.Linq.dll&lt;/tt&gt; to support all
the databases that DbLinq supports.  Mono also has &lt;tt&gt;sqlmetal&lt;/tt&gt; (based on
DbLinq's DbMetal.exe sources), which can be used to generate C# types to 
interact with databases.&lt;/p&gt;

&lt;h3&gt;DbLinq On Mono&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://www.monodevelop.org/"&gt;MonoDevelop&lt;/a&gt; can load the DbLinq
solutions.  However, it has a problem with 
&lt;a href="https://bugzilla.novell.com/show_bug.cgi?id=484752"&gt;building&lt;/a&gt; all
of the projects within the solution.  At the time of this writing, MonoDevelop
can build the following assemblies: &lt;tt&gt;DbLinq.dll&lt;/tt&gt;,
&lt;tt&gt;DbLinq.Sqlite_test_mono_strict.dll&lt;/tt&gt;, &lt;tt&gt;DbLinq.SqlServer.dll&lt;/tt&gt;,
&lt;tt&gt;DbLinq.SqlServer_test.dll&lt;/tt&gt;, &lt;tt&gt;DbLinq.SqlServer_test_ndb.dll&lt;/tt&gt;,
&lt;tt&gt;DbLinq.SqlServer_test_strict.dll&lt;/tt&gt;, and
&lt;tt&gt;DbLinq_test_ndb_strict.dll&lt;/tt&gt;.  The &lt;tt&gt;*_test*&lt;/tt&gt; assemblies are unit
tests, so this leaves the core &lt;tt&gt;DbLinq.dll&lt;/tt&gt; assembly and SQL Server
support.&lt;/p&gt;

&lt;p&gt;Thus, DbLinq is usually built with Visual Studio.NET (the free 
&lt;a href="http://www.microsoft.com/Express/"&gt;Visual Studio Express&lt;/a&gt; can be
used).  Once built, you can run some of the unit tests under Mono:&lt;/p&gt;

&lt;blockquote&gt;
&lt;tt&gt;cd $path_to_dblinq2007_checkout/build.dbg&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;

&lt;tt&gt;# Core tests&lt;/tt&gt;&lt;br /&gt;
&lt;tt&gt;$ for test in DbLinq_test.dll DbLinq_test_ndb_strict.dll DbMetal_test.dll ; do \&lt;/tt&gt;&lt;br /&gt;
&lt;tt&gt;&amp;nbsp;&amp;nbsp;nunit-console2 $test \&lt;/tt&gt;&lt;br /&gt;
&lt;tt&gt;done&lt;/tt&gt;&lt;br /&gt;
&lt;tt&gt;# Verbose output omitted&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;

&lt;tt&gt;# SQLite tests&lt;/tt&gt;&lt;br /&gt;
&lt;tt&gt;$ nunit-console2 DbLinq.Sqlite_test_mono.dll&lt;/tt&gt;&lt;br /&gt;
&lt;tt&gt;# Verbose output omitted&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;

&lt;tt&gt;# Plus many tests for the other providers...&lt;/tt&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most of the tests require an accessible database, so I've been limiting my
current tests to SQLite (as setup is easier).&lt;/p&gt;

&lt;h3&gt;DbLinq In Mono&lt;/h3&gt;

&lt;p&gt;As mentioned before, DbLinq is being used to implement Mono's
&lt;tt&gt;System.Data.Linq.dll&lt;/tt&gt;.  (For those reading the DbLinq source, the
Mono-specific bits are within &lt;tt&gt;MONO_STRICT&lt;/tt&gt; conditional code.)  This
allows us to write code that depends only on .NET assemblies (though this is
of dubious value, as the mechanisms used to support SQLite and other databases
won't work with .NET proper, but it's still a cute trick).&lt;/p&gt;

&lt;p&gt;To play along, you'll need Mono trunk.&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;Grab a SQLite database file to use with LINQ to SQL:
  &lt;blockquote&gt;
   &lt;tt&gt;wget http://dblinq2007.googlecode.com/svn/trunk/src/Northwind.db3&lt;/tt&gt;
  &lt;/blockquote&gt;
 &lt;/li&gt;
 &lt;li&gt;Use &lt;tt&gt;sqlmetal&lt;/tt&gt; to generate C# bindings for the database:
  &lt;blockquote&gt;
   &lt;tt&gt;sqlmetal /namespace:nwind /provider:Sqlite 
   "/conn:Data Source=Northwind.db3" /code:nwind.cs&lt;/tt&gt;
  &lt;/blockquote&gt;
 &lt;/li&gt;
 &lt;li&gt;Write some code to interact with the generated source code:
  &lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
// File: nwind-app.cs
// Compile as: 
//    gmcs nwind-app.cs nwind.cs -r:System.Data \
//    	-r:System.Data.Linq -r:Mono.Data.Sqlite
using System;
using System.Data.Linq;
using System.Linq;

using Mono.Data.Sqlite;

using nwind;

class Test {
    public static void Main ()
    {
        var conn = new SqliteConnection (
                "DbLinqProvider=Sqlite;" + 
                "Data Source=Northwind.db3"
        );
        Main db = new Main (conn);
        var pens =
            from p in db.Products 
            where p.ProductName == "Pen"
            select p;
        foreach (var pen in pens) {
            Console.WriteLine ("     CategoryID: {0}",  pen.CategoryID);
            Console.WriteLine ("   Discontinued: {0}",  pen.Discontinued);
            Console.WriteLine ("      ProductID: {0}",  pen.ProductID);
            Console.WriteLine ("    ProductName: {0}",  pen.ProductName);
            Console.WriteLine ("QuantityPerUnit: {0}",  pen.QuantityPerUnit);
            Console.WriteLine ("   ReorderLevel: {0}",  pen.ReorderLevel);
            Console.WriteLine ("     SupplierID: {0}",  pen.SupplierID);
            Console.WriteLine ("      UnitPrice: {0}",  pen.UnitPrice);
            Console.WriteLine ("   UnitsInStock: {0}",  pen.UnitsInStock);
            Console.WriteLine ("   UnitsOnOrder: {0}",  pen.UnitsOnOrder);
        }
    }
}&lt;/pre&gt;&lt;/blockquote&gt;
 &lt;/li&gt;
 &lt;li&gt;Compile:
  &lt;blockquote&gt;
   &lt;tt&gt;gmcs nwind-app.cs nwind.cs 
    -r:System.Data -r:System.Data.Linq -r:Mono.Data.Sqlite&lt;/tt&gt;
  &lt;/blockquote&gt;
 &lt;/li&gt;
 &lt;li&gt;Run:
  &lt;blockquote&gt;&lt;pre&gt;
$ mono nwind-app.exe 
     CategoryID: 
   Discontinued: False
      ProductID: 1
    ProductName: Pen
QuantityPerUnit: 10
   ReorderLevel: 
     SupplierID: 1
      UnitPrice: 
   UnitsInStock: 12
   UnitsOnOrder: 2&lt;/pre&gt;&lt;/blockquote&gt;
 &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notice that we use the database connection string to specify the database
vendor to use, specifically the &lt;tt&gt;DbLinqProvider&lt;/tt&gt; value specifies the
database vendor, and must be present when connecting to a database other than
Microsoft SQL Server (which is the default vendor).&lt;/p&gt;

&lt;p&gt;If using the &lt;a href="http://msdn.microsoft.com/en-us/library/bb350721.aspx"
&gt;DataContext(string)&lt;/a&gt; constructor directly (and not through a generated
subclass as used above), you should also provide the
&lt;tt&gt;DbLinqConnectionType&lt;/tt&gt; parameter, which is the assembly-qualified type
name to use for the &lt;tt&gt;IDbConnection&lt;/tt&gt; implementation.  This allows you to
use multiple different &lt;tt&gt;IDbConnection&lt;/tt&gt; implementations that use similar
SQL implementations, e.g. &lt;tt&gt;Mono.Data.Sqlite.dll&lt;/tt&gt; and
&lt;tt&gt;System.Data.SQLite.dll&lt;/tt&gt;, both of which wrap the SQLite database.&lt;/p&gt;
</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/2009/Mar-12.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/2009/Mar-12.html</guid>
      <pubDate>Fri, 13 Mar 2009 00:51:00 -0500</pubDate>
    </item>
    <item>
      <title>Extension Method Documentation</title>
      <description>
&lt;p&gt;C# 3.0 adds a new language feature called &lt;i&gt;extension methods&lt;/i&gt;.
Extension methods allow the "addition" of new instance methods to any type,
without modifying the type itself.  This is extremely powerful, arguably
crack-adled, and exists because 
&lt;a href="http://www.charlespetzold.com/etc/DoesVisualStudioRotTheMind.html"
&gt;Visual Studio users can't do anything without code completion&lt;/a&gt; (tongue
firmly in cheek).&lt;/p&gt;

&lt;p&gt;It's also extremely useful, permitting 
&lt;a href="http://msdn.microsoft.com/en-us/library/bb308959.aspx"&gt;LINQ&lt;/a&gt; and
the even more crack-adled thinking in 
&lt;a href="http://www.mono-project.com/Rocks"&gt;Mono.Rocks&lt;/a&gt; (much of which I
wrote, and I'm not entirely sure if the "crack" is in jest or not; sometimes I
wonder...).&lt;/p&gt;

&lt;p&gt;To create an extension method, you first create a &lt;b&gt;static&lt;/b&gt; class.
A method within the static class is an extension method if the first
parameter's type has a &lt;b&gt;this&lt;/b&gt; modifier:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
static class MyExtensions {
    public static string Implode (this IEnumerable&amp;lt;string&amp;gt; self, string separator)
    {
        return string.Join (separator, self.ToArray ());
    }
}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Usage is as if it were a normal instance method:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
string[] a        = {"This", "is", "my", "sentence."};
string   imploded = a.Implode (" ");
// imploded == "This is my sentence."&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Extension methods are &lt;i&gt;entirely&lt;/i&gt; syntactic sugar.  (&lt;i&gt;Nice&lt;/i&gt;
syntactic sugar, nonetheless...).  As such, it doesn't in any way modify
the type that is being extended.  Consequently, it cannot access private
members, nor is the extension method returned when reflecting over the
extended type.  For example, &lt;tt&gt;typeof(string[]).GetMethod("Implode")&lt;/tt&gt;
will return &lt;tt&gt;null&lt;/tt&gt;, as &lt;tt&gt;System.Array&lt;/tt&gt; doesn't have an
&lt;tt&gt;Implode&lt;/tt&gt; method.&lt;/p&gt;

&lt;p&gt;Furthermore, extension methods are only available if you have a
&lt;b&gt;using&lt;/b&gt; declaration for the namespace the extension method type resides
in.  So if the above &lt;tt&gt;MyExtensions&lt;/tt&gt; type resides in the &lt;tt&gt;Example&lt;/tt&gt;
namespace, and a source file doesn't have &lt;tt&gt;using Example;&lt;/tt&gt;, then the
&lt;tt&gt;Implode&lt;/tt&gt; extension method isn't available.&lt;/p&gt;

&lt;p&gt;Earlier I alluded that Visual Studio users can't do anything without code
completion.  Extension methods are thus a boon, as they (potentially) make it
easier to find new functionality, as no new types need to be introduced or
known about in advance.  However, you still need to have an appropriate
&lt;b&gt;using&lt;/b&gt; declaration to bring the methods "in scope," so how does a
developer know what namespaces to use?  The same way a developer knows which
type to use for anything: documentation.&lt;/p&gt;

&lt;p&gt;MSDN online documentation has been enhanced to show which extension methods
are applicable for a given type, e.g. 
&lt;a href="http://msdn.microsoft.com/en-us/library/19e6zeyy.aspx"&gt;The extension
methods for IEnumerable&amp;lt;T&amp;gt;&lt;/a&gt;.  
&lt;a href="http://www.go-mono.com/docs/index.aspx?link=T%3aSystem.Collections.Generic.IEnumerable%601/*"
&gt;Mono has similar documentation support.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This isn't particularly interesting, though.  Part of the utility and
flexibility is that &lt;i&gt;any&lt;/i&gt; type, in &lt;i&gt;any&lt;/i&gt; namespace, can be extended
with extension methods, and the extension methods themselves can be contained 
in any type.&lt;/p&gt;

&lt;p&gt;Obviously, MSDN and Mono documentation online can't know about extension
methods that are not part of the core framework.  Thus, if the e.g. 
&lt;a href="http://www.mono-project.com/Cecil"&gt;Mono.Cecil&lt;/a&gt; or
&lt;a href="http://www.mono-project.com/Gendarme"&gt;Gendarme&lt;/a&gt; frameworks
provided extension methods, the online documentation sites won't be
helpful.&lt;/p&gt;

&lt;p&gt;Which brings us to a
&lt;a href="http://www.mono-project.com/Release_Notes_Mono_2.0"&gt;Mono 2.0&lt;/a&gt;
feature (yes, I'm only now announcing a feature that shipped 3 months ago):&lt;/p&gt;

&lt;blockquote&gt;
  Mono Documentation Tools: the Mono Documentation framework has been upgraded
  to support documenting generics and extension methods.
&lt;/blockquote&gt;

&lt;p&gt;This support consists of four things:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    Enhancing
    &lt;a href="http://www.go-mono.com/docs/monodoc.ashx?tlink=man:mdoc-update(1)"
    &gt;mdoc update&lt;/a&gt; to generate an &lt;tt&gt;/Overview/ExtensionMethods&lt;/tt&gt;
    element within &lt;tt&gt;index.xml&lt;/tt&gt;.  The
    &lt;tt&gt;/Overview/ExtensionMethods&lt;/tt&gt; element contains
    &lt;tt&gt;&amp;lt;ExtensionMethod/&amp;gt;&lt;/tt&gt; elements which in turn contains
    &lt;tt&gt;//Targets/Target&lt;/tt&gt; elements specifying which types the extension
    method is an instance method on, and a &lt;tt&gt;&amp;lt;Member/&amp;gt;&lt;/tt&gt; element
    which is a subset of the actual extension method documentation.
    Developers don't need to edit this copy; it's handled entirely by &lt;tt&gt;mdoc
    update&lt;/tt&gt;.
  &lt;/li&gt;
  &lt;li&gt;
    Enhancing
    &lt;a href="http://www.go-mono.com/docs/monodoc.ashx?tlink=man:mdoc-assemble(1)"
    &gt;mdoc assemble&lt;/a&gt; to look for the &lt;tt&gt;//ExtensionMethod&lt;/tt&gt; elements and
    insert them into the &lt;tt&gt;ExtensionMethods.xml&lt;/tt&gt; file within the 
    generated &lt;tt&gt;.zip&lt;/tt&gt; file.
  &lt;/li&gt;
  &lt;li&gt;
    Enhancing the XML documentation to HTML generation process so that the
    extension methods are listed.  This allows all of 
    &lt;a href="http://www.mono-project.com/Monodoc"&gt;monodoc&lt;/a&gt; and mod,
    &lt;a href="http://www.go-mono.com/docs"&gt;online documentation&lt;/a&gt;, and
    &lt;a href="http://www.go-mono.com/docs/monodoc.ashx?tlink=man:mdoc-export-html(1)"
    &gt;mdoc export-html&lt;/a&gt; to use the underlying infrastructure.
  &lt;/li&gt;
  &lt;li&gt;
    Enhance &lt;tt&gt;monodoc.dll&lt;/tt&gt; to load all &lt;tt&gt;ExtensionMethods.xml&lt;/tt&gt;
    files from all installed &lt;tt&gt;.zip&lt;/tt&gt; files.  This the allows
    &lt;tt&gt;monodoc&lt;/tt&gt; and online documentation mechanisms to show extension
    methods for all installed documentation sources.
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The short of it is that this requires no workflow change to get extension 
methods listed on all extended types.  Just create extension methods, document
them as if they were normal static methods (as they are normal static methods, 
and can be invoked as such), assemble the documentation, and install the 
documentation.&lt;/p&gt;

&lt;p&gt;There is one wrinkle, though: since the &lt;tt&gt;index.xml&lt;/tt&gt; file contains a
subset of the &lt;tt&gt;&amp;lt;Member/&amp;gt;&lt;/tt&gt; documentation, you need to rerun
&lt;tt&gt;mdoc update&lt;/tt&gt; after editing extension method documentation so that
&lt;tt&gt;index.xml&lt;/tt&gt; will have the correct documentation when &lt;tt&gt;mdoc
assemble&lt;/tt&gt; is run.  Otherwise the "summary" extension method documentation
may differ from the actual intended documentation.  This may be improved in a
future release.&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/2009/Jan-25.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/2009/Jan-25.html</guid>
      <pubDate>Sun, 25 Jan 2009 21:16:00 -0500</pubDate>
    </item>
    <item>
      <title>How To Defend Against Software Patent FUD</title>
      <description>
&lt;p&gt;You don't.&lt;/p&gt;

&lt;p&gt;Bwa-ha-ha-ha-ha-ha-ha¹⁰⁰⁰.&lt;/p&gt;

&lt;p&gt;Context: for &lt;i&gt;years&lt;/i&gt;, &lt;a href="http://www.mono-project.com"&gt;Mono&lt;/a&gt;
has been the target of FUD because of potential software patent issues.  For
years the Mono community has attempted to defend from these attack, sometimes
successfully.&lt;/p&gt;

&lt;p&gt;Recently, &lt;a
href="http://lists.ximian.com/pipermail/mono-list/2009-January/040996.html"
&gt;someone asked on mono-list&lt;/a&gt; about ways to pre-emptively answer the FUD so
that it would become a non-issue.  
&lt;a href="http://lists.ximian.com/pipermail/mono-list/2009-January/041038.html"
&gt;I responded&lt;/a&gt;, and had several people suggest that I blog it.  Here we
go.&lt;/p&gt;

&lt;p&gt;To begin, there are several problems with defending against software patent 
FUD, starting with software patents themselves:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href="http://progfree.org/"&gt;Software patents suck.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://perens.com/Articles/PatentFarming.html"&gt;Software patents
    &lt;i&gt;really&lt;/i&gt; suck.&lt;/a&gt; (Specifically, &lt;i&gt;The "Don't Look" Problem&lt;/i&gt;
    section.)&lt;/li&gt;
  &lt;li&gt;&lt;a
  href="http://yro.slashdot.org/article.pl?sid=07/10/16/1230201"&gt;Software
    patents &lt;i&gt;really&lt;/i&gt;, &lt;i&gt;really&lt;/i&gt; suck.&lt;/a&gt;  
    (&lt;a
    href="http://yro.slashdot.org/yro/04/09/23/1213222.shtml?tid=155&amp;amp;tid=1"
    &gt;Related&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;The anti-Mono FUDsters apparently can't see the forest for the
    trees.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I imagine that most people reading this will agree with the first three
points, so it is the fourth that I will attempt to focus on.&lt;/p&gt;

&lt;p&gt;Specifically, the anti-Mono FUDsters seem to spend so much time on a tree
(Microsoft) that they either miss or minimize the forest of &lt;i&gt;actual&lt;/i&gt;
patent problems, patent trolls, etc.&lt;/p&gt;

&lt;p&gt;So for once, &lt;i&gt;I'll&lt;/i&gt; (non-seriously) throw the FUD:&lt;/p&gt;

&lt;p&gt;A long time ago, &lt;a
href="http://www.groupsrv.com/computers/about60863.html"&gt;Wang created a patent
that "covered a method by which a program can get help from another computer
application to complete a task&lt;/a&gt;."  
&lt;a href="http://query.nytimes.com/gst/fullpage.html?res=990CEED81439F930A25757C0A963958260"
&gt;Microsoft licensed the patent from Wang&lt;/a&gt;.  Sun did not.
In 1997, Eastman Kodak Company bought
Wang, thus acquiring this patent.  Kodak then sued Sun, claiming that Java
infringed this patent.  &lt;a
href="http://www.linuxinsider.com/story/37170.html"&gt;Kodak won, and they later
settled out of court&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, for my non-serious steaming pile of FUD, in the form of a question: Did 
Sun acquire the ability to sublicense these patents from Kodak?  
If Sun can sublicense the patents, then GPL'd Java is fine.  If Sun
&lt;i&gt;can't&lt;/i&gt;, then Java cannot be GPL'd, and any company making use of Java
could be subject to a lawsuit from Kodak.&lt;/p&gt;

&lt;p&gt;(I would &lt;i&gt;hope&lt;/i&gt; that this is &lt;i&gt;yes&lt;/i&gt;, but I have no idea, and 
&lt;a
href="http://www.articlearchives.com/law-legal-system/trial-procedure-litigation/448232-1.html"
&gt;the lack of patent sub-licensing has come up before&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;So do we need to worry about Java?  I have no idea.  I mention it to raise
a larger point:&lt;/p&gt;

&lt;p&gt;&lt;i&gt;It Doesn't Matter&lt;/i&gt;.  &lt;i&gt;Anyone&lt;/i&gt; can hold a patent, for
&lt;i&gt;anything&lt;/i&gt;, and sue &lt;i&gt;anyone&lt;/i&gt; at &lt;i&gt;any time&lt;/i&gt;.  Thus, Gnome is not
free of patent issues,  KDE is not free of patent issues, Linux is not free of
patent issues, Python is not free of patent issues, Ruby is not free of
patent issues....  &lt;i&gt;Nothing&lt;/i&gt; is free of patent issues.&lt;/p&gt;

&lt;p&gt;(Consider: do you think that the &lt;a href="http://www.python.org/psf/"&gt;Python 
Software Foundation&lt;/a&gt; has signed a patent license with Kodak?  Has Red Hat?
I doubt it.  Furthermore, I find it hard to believe that something as flexible
as Python wouldn't violate the aforementioned Wang patent, especially when you
get into COM interop/etc. on Windows...)&lt;/p&gt;

&lt;p&gt;Having said the above, a related question becomes: How do you avoid
violating someone's patents?  You don't (insert more laughter).  You
&lt;i&gt;could&lt;/i&gt; try restricting yourself to only using software that's at least
20 years old, but you won't gain many users that way.  It also won't work, for
at least two reasons: (1) submarine patents -- not all patents that would have
been in effect 20 years ago have necessarily expired (though submarine patents
shouldn't exist for ~too much longer); and (2) look at the drug patent
industry, where to prevent patented drugs from "going generic" the drug
companies take the patent-expired drug(s), combine them with other drugs, then
patent the result.  I don't think it will take too long for Software companies
to start doing this if they feel that it's necessary, and once they do, even
using known-patent-expired programs won't be safe, as merely combining them
together may be covered by an unexpired patent.  Yay.&lt;/p&gt;

&lt;p&gt;The only other way to avoid software patents is to perform a patent search,
which is extremely tricky (as software patents are deliberately vague), and if
you miss a patent and get sued over it, you're now liable for treble damages.
You're almost always better to &lt;i&gt;not&lt;/i&gt; look at software patents.  (Isn't it
funny how something that was supposed to "promote the Progress of Science and
useful Arts" can't be used by those it's supposed to help?  Isn't it 
&lt;i&gt;hilarious&lt;/i&gt;?)&lt;/p&gt;

&lt;p&gt;With all this in mind, you can see why patent FUD is hard to fight, because
there's no way to dismiss it.  Software patents are a reality, they're ugly,
but they can't be avoided.  (Yet they must be ignored, to avoid increased
liability.) My problem is that the anti-Mono people only seem to focus on 
patents with respect to Mono and Microsoft, ignoring the rest of the software 
industry.  They're ignoring the (&lt;i&gt;gigantic&lt;/i&gt;) forest so that they can pay 
attention to a single tree, Microsoft.&lt;/p&gt;

&lt;p&gt;What I find even "funnier" is that Microsoft supposedly holds a number of 
patents in a number of areas frequently used by open-source projects, such as
HTML, CSS, C++, XML, and others.  So why don't we ever see any suggestions to
avoid these technologies because the Big Bad Microsoft might sue?&lt;/p&gt;

&lt;p&gt;For that matter, (again) considering how vague software patents tend to be,
wouldn't many Microsoft patents on .NET stand a chance at being applicable
toward Java, Python, and other projects?  (Again) Why just focus on Mono?&lt;/p&gt;

&lt;p&gt;Final note: I am a Software Engineer, not a patent lawyer.  Feel free to
ignore the entire rant, but I would appreciate it if a little more thought
went into all the anti-Mono propaganda.&lt;/p&gt;
</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/2009/Jan-19.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/2009/Jan-19.html</guid>
      <pubDate>Tue, 20 Jan 2009 03:24:00 -0500</pubDate>
    </item>
    <item>
      <title>openSUSE 11.1: Where'd my hostname go?</title>
      <description>
&lt;p&gt;After playing with the openSUSE 11.1 beta releases and final release, I
finally installed it onto my main workstation.  Funny how actually using it
~full-time shows things that were previous missed...&lt;/p&gt;

&lt;p&gt;In this case, what greeted me when I opened a shell was:&lt;/p&gt;

&lt;blockquote&gt;&lt;tt&gt;jon@linux-jcq7$&lt;/tt&gt;&lt;/blockquote&gt;

&lt;p&gt;This was rather unexpected, as this wasn't the hostname I wanted.  No
matter, this was normal after a fresh install (and has been happening for eons).
So off I go to YaST to edit the Network Settings 
(&lt;tt&gt;/sbin/yast2 lan&lt;/tt&gt;)...&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Previously&lt;/i&gt; (i.e. on openSUSE 10.1, 10.2, 10.3, and 11.0), I could go
to the Ho&lt;u&gt;s&lt;/u&gt;tname/DNS tab, to the Hostname and Domain Name section, and
specify a Hostname.  (Whereupon everything would break until the next reboot
as Gnome didn't seem to like the hostname changing on it, but at least I had 
the right hostname!)&lt;/p&gt;

&lt;p&gt;Under openSUSE 11.1, this is disabled when NetworkManager controls things.
(Again, this was not the case under 11.0 and prior releases, even when using
NetworkManager to control things.)&lt;/p&gt;

&lt;p&gt;So how do we change the hostname?  Perusing Control Center brought forth
the Network Connections applet &amp;rarr; Wired tab &amp;rarr; &lt;i&gt;connection name&lt;/i&gt; 
(e.g. System eth0) &amp;rarr; &lt;u&gt;E&lt;/u&gt;dit &amp;rarr; IPv4 Settings tab's DHCP Client
ID textbox.  This was nice to find -- I'd often wondered why setting the DHCP
Client Identifier within YaST Network Settings seemingly had no effect; DHCP
Client ID does work -- but it had no effect during bootup (presumably because
NetworkManager isn't running early enough to set the hostname), so my shell
prompt was still wrong.&lt;/p&gt;

&lt;p&gt;Similarly, the "traditional" technique of hand-editing &lt;tt&gt;/etc/hosts&lt;/tt&gt;
(or using the new-fangled Hostnames YaST applet) seemed to have no effect on
the system name after a reboot.&lt;/p&gt;

&lt;p&gt;So how do we really change the hostname?  Edit &lt;tt&gt;/etc/HOSTNAME&lt;/tt&gt;,
which is a single line file containing the fully-qualified hostname to use
during bootup.&lt;/p&gt;
</description>
      <link>http://www.jprl.com/Blog/archive/development/2008/Dec-21.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/2008/Dec-21.html</guid>
      <pubDate>Mon, 22 Dec 2008 04:01:00 -0500</pubDate>
    </item>
    <item>
      <title>Icecream &amp;amp; Firewalls</title>
      <description>
&lt;p&gt;Earlier this year, &lt;a
href="http://www.gnome.org/~michael/blog/icecream.html"&gt;Michael Meeks described
how to use icecream to speed up builds&lt;/a&gt;.  One problem was that originally
it required disabling the firewall on most systems.  There was an update
mentioning that setting &lt;tt&gt;FW_CONFIGURATIONS_EXT&lt;/tt&gt; could be used to open
up the appropriate ports in the firewall so that things would Just Work.
Alas, that doesn't work for me on openSUSE 11.1.&lt;/p&gt;

&lt;p&gt;Thus, if using the openSUSE Firewall Allowed Services configuration doesn't
work (which is what setting &lt;tt&gt;FW_CONFIGURATIONS_EXT&lt;/tt&gt; modifies), there is 
one alternate strategy to use before disabling the firewall:
manually specify the scheduler system on the daemon systems within the
icecream configuration file:&lt;/p&gt;

&lt;blockquote&gt;&lt;tt&gt;
sudo sed -i 's/ICECREAM_SCHEDULER_HOST=""/ICECREAM_SCHEDULER_HOST="SCHEDULER"/' /etc/sysconfig/icecream
&lt;/tt&gt;&lt;/blockquote&gt;

&lt;p&gt;Replace &lt;tt&gt;SCHEDULER&lt;/tt&gt; with the appropriate host name or IP address of
your scheduler system.&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/2008/Dec-19.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/2008/Dec-19.html</guid>
      <pubDate>Sat, 20 Dec 2008 04:01:00 -0500</pubDate>
    </item>
    <item>
      <title>Announcing NDesk.Options 0.2.1</title>
      <description>
&lt;p&gt;I am pleased to announce the release of 
&lt;a href="http://www.ndesk.org/Options"&gt;NDesk.Options&lt;/a&gt; 0.2.1.
NDesk.Options is a C# program option parser library, inspired by Perl's 
&lt;a href="http://perldoc.perl.org/Getopt/Long.html"&gt;Getopt::Long&lt;/a&gt; 
option parser.&lt;/p&gt;

&lt;p&gt;To download, visit the NDesk.Options web page:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;a href="http://www.ndesk.org/Options"&gt;http://www.ndesk.org/Options&lt;/a&gt;
&lt;/blockquote&gt;

&lt;h3&gt;Usage&lt;/h3&gt;

&lt;p&gt;See &lt;a href="http://www.ndesk.org/Options"&gt;http://www.ndesk.org/Options&lt;/a&gt;
and the 
&lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html"
&gt;OptionSet&lt;/a&gt; documentation for examples.&lt;/p&gt;

&lt;h3&gt;What's New?&lt;/h3&gt;

&lt;p&gt;There have been several minor changes since the previous
&lt;a href="http://www.jprl.com/Blog/archive/development/ndesk.options/2008/../../ndesk.options/2008/Feb-14.html"&gt;0.2.0 release&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The 
    &lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html"
    &gt;OptionSet&lt;/a&gt; base class has been changed from &lt;a 
    href="http://www.go-mono.com/docs/monodoc.ashx?link=T:System.Collections.ObjectModel.Collection`1"
    &gt;Collection&amp;lt;Option&amp;gt;&lt;/a&gt; to &lt;a
    href="http://www.go-mono.com/docs/monodoc.ashx?link=T:System.Collections.ObjectModel.KeyedCollection`2"
    &gt;KeyedCollection&amp;lt;string, Option&amp;gt;&lt;/a&gt;, as
    &lt;tt&gt;KeyedCollection&amp;lt;string, Option&amp;gt;&lt;/tt&gt; is conceptually closer to
    what &lt;tt&gt;OptionSet&lt;/tt&gt; supports: one or more &lt;tt&gt;string&lt;/tt&gt;s as aliases
    for a single &lt;tt&gt;Option&lt;/tt&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a
    href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.GetOptionForName(System.String)"
    &gt;OptionSet.GetOptionForName()&lt;/a&gt; has been deprecated in favor of using &lt;a 
    href="http://www.go-mono.com/docs/monodoc.ashx?link=P:System.Collections.ObjectModel.KeyedCollection`2.Item(`0)"
    &gt;KeyedCollection.Item(string)&lt;/a&gt;.
    &lt;/li&gt;
  &lt;li&gt;C# 2.0 Compatibility.  The unit tests require a C# 3.0 compiler, but the 
    actual option parser and related classes now only require a C# 2.0 
    compiler.&lt;/li&gt;
  &lt;li&gt;Default argument handling support.  This is useful for &lt;i&gt;argument 
    runs&lt;/i&gt;, in which the meaning of later options depends upon a prior
    argument, e.g.: &lt;tt&gt;&lt;a 
    href="http://www.go-mono.com/docs/index.aspx?tlink=8@man%3amdoc-assemble(1)"
    &gt;mdoc-assemble&lt;/a&gt; --format=ecma A B --format=man C&lt;/tt&gt; (where &lt;tt&gt;A&lt;/tt&gt;
    and &lt;tt&gt;B&lt;/tt&gt; are processed with &lt;tt&gt;--format=ecma&lt;/tt&gt; in effect, while
    &lt;tt&gt;C&lt;/tt&gt; is processed with &lt;tt&gt;--format=man&lt;/tt&gt; in effect).&lt;/li&gt;
  &lt;li&gt;The &lt;a
    href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/Option.html#P:NDesk.Options.Option.Description"
    &gt;Option.Description&lt;/a&gt; property can now contain value formatting codes 
    which are used by &lt;a
    href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.WriteOptionDescriptions(System.IO.TextWriter)"
    &gt;OptionSet.WriteOptionDescriptions()&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;The &lt;a
    href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/Option.html#P:NDesk.Options.Option.Description"
    &gt;Option.Description&lt;/a&gt; property is now automatically line-wrapped within &lt;a
    href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.WriteOptionDescriptions(System.IO.TextWriter)"
    &gt;OptionSet.WriteOptionDescriptions()&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;tt&gt;ndesk-options.pc&lt;/tt&gt; fixes for 
    &lt;a href="http://pkg-config.freedesktop.org/wiki/"&gt;pkg-config&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Unit tests now depend on &lt;a href="http://www.nunit.org/"&gt;NUnit&lt;/a&gt; and
    have been split out into separate files.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/ndesk.options/2008/Oct-20.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/ndesk.options/2008/Oct-20.html</guid>
      <pubDate>Tue, 21 Oct 2008 02:26:00 -0500</pubDate>
    </item>
    <item>
      <title>Threading: Lock Nesting</title>
      <description>
&lt;p&gt;&lt;i&gt;a.k.a. Why the Java 1.0 collections were rewritten...&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;Threading is an overly complicated subject, covered in great detail at
other locations and in many books.  However, there is one subject that either
I haven't seen discussed too often, or somehow have managed to miss while
reading the plethora of threading sources, something I'll call &lt;i&gt;lock
nesting depth&lt;/i&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;dl&gt;
    &lt;dt&gt;lock nesting depth&lt;/dt&gt;
    &lt;dd&gt;
      The number of locks that must be acquired and held simultaneously in
      order to perform a given operation.
    &lt;/dd&gt;
  &lt;/dl&gt;
&lt;/blockquote&gt;

&lt;p&gt;In general, the lock nesting depth should be kept as small as possible;
anything else results in extra, possibly unnecessary/extraneous locks, which
serve only to slow down performance for no added benefit.&lt;/p&gt;

&lt;p&gt;First, an aside: why does threading code require locks?  To maintain data
invariants for data shared between threads, preventing the data from being
corrupted.  Note that this is not necessarily the same as producing "correct"
data, as there may be internal locks to prevent internal data corruption but
the resulting output may not be "correct" (in as much as it isn't the output
that we want).&lt;/p&gt;

&lt;p&gt;The prototypical example of "non-corrupting but not correct" output is when
multiple threads write to the (shared) terminal:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
using System;
using System.Threading;

class Test {
	public static void Main ()
	{
		Thread[] threads = new Thread[]{
			new Thread ( () =&amp;gt; { WriteMessage ("Thread 1"); } ),
			new Thread ( () =&amp;gt; { WriteMessage ("Thread 2"); } ),
		};
		foreach (var t in threads)
			t.Start ();
		foreach (var t in threads)
			t.Join ();
	}

	static void WriteMessage (string who)
	{
		Console.Write ("Hello from ");
		Console.Write (who);
		Console.Write ("!\n");
	}
}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Output for the above program can vary from the sensible (and
desirable):&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
$ mono ls.exe 
Hello from Thread 2!
Hello from Thread 1!
$ mono ls.exe 
Hello from Thread 1!
Hello from Thread 2!&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;To the downright "corrupt":&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
Hello from Hello from Hello from Hello from Thread 2!
Thread 1!&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;(This can happen when Thread 1 is interrupted by Thread 2 before it can 
write out its entire message.)&lt;/p&gt;

&lt;p&gt;Notice what's going on here: as far as the system is concerned, what we're
doing is safe -- no data is corrupted, my terminal/shell/operating
system/planet isn't going to go bonkers, everything is well defined.  It's
just that in this circumstance "well defined" doesn't match what I, as the
developer/end user, desired to see: one of the first two sets of output.&lt;/p&gt;

&lt;p&gt;The solution, as always, is to either add a a lock within 
&lt;tt&gt;WriteMessage&lt;/tt&gt; to ensure that the output is serialized as desired:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
	static object o = new object ();
	static void WriteMessage (string who)
	{
		lock (o) {
			Console.Write ("Hello from ");
			Console.Write (who);
			Console.Write ("!\n");
		}
	}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Or to instead ensure that the message can't be split up, working within the
predefined semantics of the terminal:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
	static void WriteMessage (string who)
	{
		string s = "Hello from " + who + "!\n";
		Console.Write (s);
	}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;(Which can oddly generate duplicate messages on Mono; not sure what's up
with that...  
&lt;a href="http://lists.ximian.com/pipermail/mono-list/2008-April/038401.html"
&gt;More here.&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;For the &lt;tt&gt;WriteMessage&lt;/tt&gt; that uses locks, the lock nesting depth is 2,
and this can't be readily improved (because &lt;tt&gt;Console.Write&lt;/tt&gt; is static,
and thus must be thread safe as any thread could execute it at any time).&lt;/p&gt;

&lt;p&gt;Returning to this entry's subtitle, why were the Java 1.0 collections
rewritten?  Because they were all internally thread safe.  This had it's uses, 
should you be sharing a 
&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Hashtable.html"
&gt;Hashtable&lt;/a&gt; or
&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Vector.html"
&gt;Vector&lt;/a&gt; between threads, but even then it was of limited usefulness, as it
only protected the &lt;i&gt;internal&lt;/i&gt; state &lt;i&gt;for a single method call&lt;/i&gt;, not
any state that may require more than one function call.  Consider this
illustrative code which counts the number of times a given token is 
encountered:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
Hashtable data = new Hashtable ();
for (String token : tokens) {
    if (data.containsKey (token)) {
        Integer n = (Integer) data.get (token);
        data.put (token, new Integer (n.intValue() + 1));
    }
    else {
        data.put (token, new Integer (1));
    }
}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Yes, Hashtable is thread safe and thus won't have &lt;i&gt;its&lt;/i&gt; data
corrupted, but it can still corrupt &lt;i&gt;your&lt;/i&gt; data should multiple threads
execute this code against a shared &lt;tt&gt;data&lt;/tt&gt; instance, as there is a race
with the &lt;tt&gt;data.containsKey()&lt;/tt&gt; call, where multiple threads may evaluate
the same token "simultaneously" (read: before the following &lt;tt&gt;data.put&lt;/tt&gt; 
call), and thus each thread would try to call &lt;tt&gt;data.put (token,
new Integer (1))&lt;/tt&gt;.  The result: a missed token.&lt;/p&gt;

&lt;p&gt;The solution is obvious: &lt;i&gt;another&lt;/i&gt; lock, controlled by the developer,
&lt;i&gt;must&lt;/i&gt; be used to ensure valid data:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
Object lock = new Object ();
Hashtable data = new Hashtable ();
for (String token : tokens) {
    synchronized (lock) {
        if (data.containsKey (token)) {
            Integer n = (Integer) data.get (token);
            data.put (token, new Integer (n.intValue() + 1));
        }
        else {
            data.put (token, new Integer (1));
        }
    }
}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Consequently, for &lt;i&gt;all&lt;/i&gt; "non-trivial" code (where "non-trivial" means
"requires more than one method to be called on the collection object in an
atomic fashion") will &lt;i&gt;require&lt;/i&gt; a lock nesting depth of two.
Furthermore, the lock nesting depth would always be at least one, and since 
many functions were not invoked between multiple threads, or the collection 
instance local to that particular method, the synchronization within the 
collection was pure overhead, providing no benefit.&lt;/p&gt;

&lt;p&gt;Which is why in Java 1.2, all of the new collection classes such as 
&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/ArrayList.html"
&gt;ArrayList&lt;/a&gt; and
&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/HashMap.html"
&gt;HashMap&lt;/a&gt;
are explicitly unsynchronized, as are all of the .NET 1.0 and 2.0 collection
types unless you use a synchronized wrapper such as 
&lt;a href="http://www.go-mono.com/docs/index.aspx?link=M%3aSystem.Collections.ArrayList.Synchronized(System.Collections.ArrayList)"
&gt;System.Collections.ArrayList.Synchronized&lt;/a&gt;
(which, again, is frequently of dubious value if you ever need to invoke more
than one method against the collection atomically).&lt;/p&gt;

&lt;p&gt;Finally, the 
&lt;a href="http://msdn.microsoft.com/en-us/library/f857xew0(VS.71).aspx"
&gt;Threading Design Guidelines&lt;/a&gt; of the 
&lt;a href="http://msdn.microsoft.com/en-us/library/czefa0ke(VS.71).aspx"
&gt;.NET Framework Design Guidelines for Class Library Developers&lt;/a&gt; 
(&lt;a href="http://www.amazon.com/Framework-Design-Guidelines-Conventions-Development/dp/0321246756/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1211941515&amp;amp;sr=8-1"
&gt;book&lt;/a&gt;) 
suggests that all static members be thread safe, but instance member &lt;i&gt;by
default&lt;/i&gt; should not be thread safe:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Instance state does not need to be thread safe. By default, class libraries
  should not be thread safe. Adding locks to create thread-safe code decreases
  performance, increases lock contention, and creates the possibility for
  deadlock bugs to occur. In common application models, only one thread at a
  time executes user code, which minimizes the need for thread safety. For this
  reason, the .NET Framework class libraries are not thread safe by default.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Obviously, there are exceptions -- for example, if a static method returns
a shared instance of some class, then all of those instance members must be
thread safe as they can be accessed via the static method 
(&lt;a
href="http://msdn.microsoft.com/en-us/library/system.reflection.assembly.aspx"
&gt;System.Reflection.Assembly&lt;/a&gt; must be thread safe, as an instance of
&lt;tt&gt;Assembly&lt;/tt&gt; is returned by the static method
&lt;a href="http://msdn.microsoft.com/en-us/library/system.reflection.assembly.getexecutingassembly.aspx"
&gt;Assembly.GetExecutingAssembly&lt;/a&gt;).  &lt;i&gt;By default&lt;/i&gt;, though, instance
members should &lt;i&gt;not&lt;/i&gt; be thread safe.&lt;/p&gt;
</description>
      <link>http://www.jprl.com/Blog/archive/development/2008/May-27.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/2008/May-27.html</guid>
      <pubDate>Wed, 28 May 2008 03:24:00 -0500</pubDate>
    </item>
    <item>
      <title>HackWeek Summary</title>
      <description>
&lt;p&gt;In case you missed it, last week was "Hackweek" at Novell.&lt;/p&gt;

&lt;p&gt;My week was less "hacking" and more "spit-and-polish."  In particular:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Wrote &lt;a
    href="http://anonsvn.mono-project.com/source/trunk/monodoc/class/Mono.Posix/en/Mono.Unix/UnixSignal.xml"
    &gt;Mono.Unix.UnixSignal&lt;/a&gt; documentation.  This only took ~1/2 a day.&lt;/li&gt;
  &lt;li&gt;Released &lt;a href="http://www.jprl.com/Blog/archive/development/2008/../ndesk.options/2008/Feb-14.html"
    &gt;NDesk.Options 0.2.0&lt;/a&gt;, which in turn involved the 
    &lt;a href="http://www.jprl.com/Blog/archive/development/2008/../mono/2006/Sep-20.html"&gt;vicious cycle&lt;/a&gt;
    of write documentation (and samples), realize I'm missing something or don't
    like the name, change the library, update the documentation, repeat...
    &lt;p&gt;Consequently, something I &lt;i&gt;thought&lt;/i&gt; would only take another half a
    day wound up taking 3 days, with some changes happening at the last moment
    (the &lt;tt&gt;System.Action`2&lt;/tt&gt; removal, thus removing the need to have two
    different builds depending on whether .NET 2.0 or .NET 3.0 is
    targeted).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Improve &lt;a href="http://www.mono-project.com/Generating_Documentation"
    &gt;monodocs2html&lt;/a&gt; so that the output sucks...well, less.  I won't say
    that it's actually good now, but it is an improvement.  For comparison
    purposes, &lt;a
    href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html"
    &gt;NDesk.Options.OptionSet&lt;/a&gt; documentation output from:
    &lt;ul&gt;
      &lt;li&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/2008/OptionSet.orig.htm"&gt;monodocs2html 1.2.6&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="http://www.jprl.com/Blog/archive/development/2008/OptionSet.svn.htm"&gt;monodocs2html svn&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
    &lt;p&gt;In particular, note that in the 1.2.6 output that there are three
    examples as part of the Remarks documentation, but it's rather difficult
    to tell when one example ends and the next begins (due to the lack of an
    Example header).  The svn version fixes this, adds JavaScript bling so
    that all sections can be collapsed and expanded, and adds a mini "index"
    to the top-left so that it's easier to get to the relevant sections (such
    as skipping the three lengthy examples that precede the Members 
    listing).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had wanted to do other things as well, such as migrate the
monodoc-related programs to use NDesk.Options instead of Mono.GetOptions for
option parsing, but such efforts will have to wait until later...&lt;/p&gt;
</description>
      <link>http://www.jprl.com/Blog/archive/development/2008/Feb-19.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/2008/Feb-19.html</guid>
      <pubDate>Tue, 19 Feb 2008 15:51:00 -0500</pubDate>
    </item>
    <item>
      <title>Announcing NDesk.Options 0.2.0</title>
      <description>
&lt;p&gt;I am pleased to announce the release of 
&lt;a href="http://www.ndesk.org/Options"&gt;NDesk.Options&lt;/a&gt; 0.2.0.
NDesk.Options is a C# program option parser library, inspired by Perl's 
&lt;a href="http://perldoc.perl.org/Getopt/Long.html"&gt;Getopt::Long&lt;/a&gt; 
option parser.&lt;/p&gt;

&lt;p&gt;To download, visit the NDesk.Options web page:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;a href="http://www.ndesk.org/Options"&gt;http://www.ndesk.org/Options&lt;/a&gt;
&lt;/blockquote&gt;

&lt;h3&gt;Usage&lt;/h3&gt;

&lt;p&gt;See &lt;a href="http://www.ndesk.org/Options"&gt;http://www.ndesk.org/Options&lt;/a&gt;
and the 
&lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html"
&gt;OptionSet&lt;/a&gt; documentation for examples.&lt;/p&gt;

&lt;h3&gt;What's New?&lt;/h3&gt;

&lt;p&gt;There have been numerous changes since the previous
&lt;a href="http://www.jprl.com/Blog/archive/development/ndesk.options/2008/../../ndesk.options/2008/Jan-27.html"&gt;0.1.0 release&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Mono 1.9 is now required to build.  (An svn release was previously
    required anyway, so this isn't a surprising requirement.)&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Simplify the API by removing all &lt;tt&gt;OptionSet.Add()&lt;/tt&gt; methods which 
    provided an 
    &lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionContext.html"
    &gt;OptionContext&lt;/a&gt; to the callback function; this includes:
    &lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;tt&gt;OptionSet.Add(string, Action&amp;lt;string, OptionContext&amp;gt;)&lt;/tt&gt;&lt;/li&gt;
      &lt;li&gt;&lt;tt&gt;OptionSet.Add(string, string, Action&amp;lt;string, OptionContext&amp;gt;)&lt;/tt&gt;&lt;/li&gt;
      &lt;li&gt;&lt;tt&gt;OptionSet.Add&amp;lt;T&amp;gt;(string, Action&amp;lt;T, OptionContext&amp;gt;)&lt;/tt&gt;&lt;/li&gt;
      &lt;li&gt;&lt;tt&gt;OptionSet.Add&amp;lt;T&amp;gt;(string, string, Action&amp;lt;T, OptionContext&amp;gt;)&lt;/tt&gt;&lt;/li&gt;
    &lt;/ul&gt;
    &lt;p&gt;If you really need access to an &lt;tt&gt;OptionContext&lt;/tt&gt;, you can 
      &lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.Add(NDesk.Options.Option)"
      &gt;Add&lt;/a&gt; your own 
      &lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/Option.html"
      &gt;Option&lt;/a&gt; and override
      &lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/Option.html#M:NDesk.Options.Option.OnParseComplete(NDesk.Options.OptionContext)"
      &gt;Option.OnParseComplete(OptionContext)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;p&gt;By &lt;a href="http://www.tirania.org/blog"&gt;Miguel&lt;/a&gt;'s request, 
    change the semantics for &lt;tt&gt;Option&lt;/tt&gt;s with &lt;a
    href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionValueType.html#F:NDesk.Options.OptionValueType.Optional"
    &gt;optional&lt;/a&gt; values (arguments that have a type value of `&lt;tt&gt;:&lt;/tt&gt;').  
    Previously, &lt;tt&gt;Option&lt;/tt&gt;s accepting an optional value were virtually 
    identical to &lt;tt&gt;Option&lt;/tt&gt;s accepting a required value; the only place 
    they would differ is at the end of the command line, where if a value was 
    missing for a &lt;tt&gt;Option&lt;/tt&gt; with an optional value no error would occur, 
    while an &lt;tt&gt;Option&lt;/tt&gt; with a required value would generate an error.&lt;/p&gt;
    &lt;p&gt;Now, we introduce the notion of &lt;i&gt;greediness&lt;/i&gt;: required values are
    greedy, and will eat any number of following arguments in order to fulfill
    their requirements.  Optional values are &lt;i&gt;not&lt;/i&gt; greedy, and will
    &lt;i&gt;only&lt;/i&gt; extract a value from the &lt;i&gt;current&lt;/i&gt; argument.&lt;/p&gt;
    &lt;p&gt;By way of example:&lt;/p&gt;
    &lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
string color = null;
var p = new OptionSet () {
    { "-color:", v =&gt; color = v },
};
p.Parse (new string[]{"--color=auto"});     // 1
p.Parse (new string[]{"--color", "auto"});  // 2&lt;/pre&gt;&lt;/blockquote&gt;
    &lt;p&gt;In NDesk.Options 0.1.0, (1) and (2) would be identical and
    &lt;tt&gt;color&lt;/tt&gt; would be given the value &lt;tt&gt;auto&lt;/tt&gt;.  In 0.2.0, they
    are &lt;i&gt;not&lt;/i&gt; identical: (1) would assign the value &lt;tt&gt;auto&lt;/tt&gt; to
    &lt;tt&gt;color&lt;/tt&gt;, while (2) would assign &lt;tt&gt;null&lt;/tt&gt; to &lt;tt&gt;color&lt;/tt&gt;.
    This permits consistency with GNU &lt;b&gt;ls&lt;/b&gt;(1)'s &lt;tt&gt;ls --color&lt;/tt&gt;
    behavior.&lt;/p&gt;
    &lt;p&gt;If a required option were to be specified (by using &lt;tt&gt;=&lt;/tt&gt; instead
    of &lt;tt&gt;:&lt;/tt&gt;), then (1) and (2) would again have identical results.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;NDesk.Options 0.1.0 restricted option bundling to boolean
    &lt;tt&gt;Option&lt;/tt&gt;s.  This restriction has been relaxed so that
    (1) &lt;tt&gt;Option&lt;/tt&gt;s accepting both optional and required values may be
    bundled with boolean &lt;tt&gt;Option&lt;/tt&gt;s, and (2) the optional or required
    value may be bundled as well.  As before, only single character
    &lt;tt&gt;Option&lt;/tt&gt;s may be bundled.
    &lt;p&gt;The logic is as follows: given an argument such as
    &lt;tt&gt;-cvfname&lt;/tt&gt;:&lt;/p&gt;
    &lt;ol&gt;
      &lt;li&gt;&lt;tt&gt;cvfname&lt;/tt&gt; must &lt;i&gt;not&lt;/i&gt; match a registered &lt;tt&gt;Option&lt;/tt&gt;.
        If it does match a registered option, then that is the &lt;tt&gt;Option&lt;/tt&gt;
        that will (eventually) be invoked.&lt;/li&gt;
      &lt;li&gt;&lt;tt&gt;c&lt;/tt&gt; must be a registered option.  If it isn't, then
        &lt;tt&gt;-cvfname&lt;/tt&gt; is returned from 
        &lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.Parse(System.Collections.Generic.IEnumerable%3CSystem.String%3E)"
        &gt;OptionSet.Parse(IEnumerable&amp;lt;string&amp;gt;)&lt;/a&gt;.&lt;/li&gt;
      &lt;li&gt;Each character is looked up; if it's a boolean &lt;tt&gt;Option&lt;/tt&gt;, then
        the associated action is invoked with a non-&lt;tt&gt;null&lt;/tt&gt; value.&lt;/li&gt;
      &lt;li&gt;If instead the character is an &lt;tt&gt;Option&lt;/tt&gt; accepting one or more 
        optional or required values, then the rest of the argument (not
        including the &lt;tt&gt;Option&lt;/tt&gt; character) is used as the value.  This
        also follows the greediness of optional vs. required values: optional
        values will only use the current argument, while required values may
        use the following argument(s) if e.g. the &lt;tt&gt;Option&lt;/tt&gt;'s character
        is the last character in the sequence.&lt;/li&gt;
      &lt;li&gt;If a non-&lt;tt&gt;Option&lt;/tt&gt; character is encountered that is &lt;i&gt;not&lt;/i&gt;
        (a) the first character in the sequence, or (b) used as the value for
        a previous &lt;tt&gt;Option&lt;/tt&gt;, then an 
        &lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionException.html"
        &gt;OptionException&lt;/a&gt; is thrown.&lt;/li&gt;
    &lt;/ol&gt;
    &lt;p&gt;This does The Right Thing for &lt;b&gt;tar&lt;/b&gt;(1)-like option handling, 
      with &lt;tt&gt;tar -cvfname ...&lt;/tt&gt; &lt;i&gt;c&lt;/i&gt;reating (with &lt;i&gt;v&lt;/i&gt;erbose 
      output) the &lt;i&gt;f&lt;/i&gt;ile with the name &lt;i&gt;name&lt;/i&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;tt&gt;Option&lt;/tt&gt;s may now accept (or require) more than one value.  The 
    &lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/Option.html#C:NDesk.Options.Option(System.String,System.String,System.Int32)"
    &gt;Option (string, string, int)&lt;/a&gt; constructor allows specifying how many
    values are accepted/required (depending on whether the &lt;tt&gt;Option&lt;/tt&gt; has
    optional or required values).
    &lt;p&gt;The &lt;tt&gt;Option&lt;/tt&gt; values are available through the
      &lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionContext.html#P:NDesk.Options.OptionContext.OptionValues"
      &gt;OptionContext.OptionValues&lt;/a&gt; collection.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Direct support for &lt;tt&gt;Option&lt;/tt&gt;s accepting/required two values within 
    &lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html"
    &gt;OptionSet&lt;/a&gt;:
    &lt;ul&gt;
      &lt;li&gt;&lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.Add(System.String,NDesk.Options.OptionAction{System.String,System.String})"
        &gt;OptionSet.Add(string, OptionAction&amp;lt;string, string&amp;gt;)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.Add(System.String,System.String,NDesk.Options.OptionAction{System.String,System.String})"
        &gt;OptionSet.Add(string, string, OptionAction&amp;lt;string, string&amp;gt;)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.Add%60%602(System.String,NDesk.Options.OptionAction{%60%600,%60%601})"
        &gt;OptionSet.Add&amp;lt;TKey, TValue&amp;gt; (string, OptionAction&amp;lt;TKey, TValue&amp;gt;)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.Add%60%602(System.String,System.String,NDesk.Options.OptionAction{%60%600,%60%601})"
        &gt;OptionSet.Add&amp;lt;TKey, TValue&amp;gt; (string, string, OptionAction&amp;lt;TKey, TValue&amp;gt;)&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
    &lt;p&gt;This now permits reasonable handling of &lt;b&gt;cc&lt;/b&gt;(1)-style
    parameters:&lt;/p&gt;
    &lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
var macros = new Dictionary&amp;lt;string, string&amp;gt; ();
var p = new OptionSet () {
    { "D:", (k, v) =&gt; { if (k != null) macros.Add (k, v); } },
};
p.Parse (new string[]{"-DNAME1", "-DNAME2=VALUE2"});
    // Adds the keys "NAME1" (with null value) 
    // and "NAME2" (with value "VALUE2") to `macros'.&lt;/pre&gt;&lt;/blockquote&gt;
    &lt;p&gt;Note that an optional value is used; if &lt;tt&gt;D=&lt;/tt&gt; were specified, two
      values would be required, so &lt;tt&gt;-DNAME1 -DNAME2=VALUE2&lt;/tt&gt; would
      insert &lt;i&gt;one&lt;/i&gt; macro -- &lt;tt&gt;NAME1&lt;/tt&gt; -- with the value
      &lt;tt&gt;-DNAME2=VALUE2&lt;/tt&gt;.
    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;When an &lt;tt&gt;Option&lt;/tt&gt; permits more than one value, it may provide a
    list of &lt;i&gt;value separator strings&lt;/i&gt;, strings that may be used to
    separate the multiple values.  If no separators are listed, &lt;tt&gt;=&lt;/tt&gt; and
    &lt;tt&gt;:&lt;/tt&gt; are used as the default (thus permitting the previous
    &lt;tt&gt;-DNAME2=VALUE2&lt;/tt&gt; example to work; &lt;tt&gt;-DNAME2:VALUE2&lt;/tt&gt; would
    have had the same result).
    &lt;p&gt;The value separator strings follow the &lt;tt&gt;:&lt;/tt&gt; or &lt;tt&gt;=&lt;/tt&gt; in the
      &lt;tt&gt;Option&lt;/tt&gt; prototype.  They consist of:&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;The string &lt;i&gt;within&lt;/i&gt; &lt;tt&gt;{&lt;/tt&gt; and &lt;tt&gt;}&lt;/tt&gt;.&lt;/li&gt;
      &lt;li&gt;Any other invidividual character.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;p&gt;Thus, the prototype &lt;tt&gt;M:+-*/&lt;/tt&gt; would use &lt;tt&gt;+&lt;/tt&gt;, &lt;tt&gt;-&lt;/tt&gt;,
      &lt;tt&gt;*&lt;/tt&gt;, or &lt;tt&gt;/&lt;/tt&gt; to split values, so &lt;tt&gt;-M5+2&lt;/tt&gt;,
      &lt;tt&gt;-M5-2&lt;/tt&gt;, &lt;tt&gt;-M5*2&lt;/tt&gt;, and &lt;tt&gt;-M5/2&lt;/tt&gt; all provide two
      values (&lt;tt&gt;5&lt;/tt&gt; and &lt;tt&gt;2&lt;/tt&gt;) to the &lt;tt&gt;M&lt;/tt&gt; option.&lt;/p&gt;
    &lt;p&gt;The prototype &lt;tt&gt;N={--&gt;}{=&gt;}&lt;/tt&gt; would parse both &lt;tt&gt;-NA--&gt;B&lt;/tt&gt;
      and &lt;tt&gt;-NA=&gt;B&lt;/tt&gt; so that &lt;tt&gt;A&lt;/tt&gt; and &lt;tt&gt;B&lt;/tt&gt; are provided as
      the two values to the &lt;tt&gt;N&lt;/tt&gt; option.&lt;/p&gt;
    &lt;p&gt;As a special construct, the separator &lt;tt&gt;{}&lt;/tt&gt; requires that each
      value be a separate argument.  (This makes no sense for &lt;tt&gt;Option&lt;/tt&gt;s
      with optional values.)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Naming consistency improvements: an &lt;i&gt;argument&lt;/i&gt; is an unparsed 
    string, an &lt;i&gt;option&lt;/i&gt; is a parsed argument that corresponds to a
    registered &lt;tt&gt;Option&lt;/tt&gt;, and a &lt;i&gt;prototype&lt;/i&gt; is a description of an
    &lt;tt&gt;Option&lt;/tt&gt;, describing all aliases, the value type, and value
    separators.  This has resulted in method argument name changes.&lt;/li&gt;
  &lt;li&gt;Removal of .NET 3.5 support.  Instead of using &lt;tt&gt;System.Action`2&lt;/tt&gt;
    from System.Core.dll (or providing an internal equivalent), I've just
    defined a &lt;a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionAction%602.html"
    &gt;OptionAction&amp;lt;TKey, TValue&amp;gt;&lt;/a&gt; type.  This simplifies assembly
    versioning.&lt;/li&gt;
&lt;/ul&gt;
</description>
      <link>http://www.jprl.com/Blog/archive/development/ndesk.options/2008/Feb-14.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/ndesk.options/2008/Feb-14.html</guid>
      <pubDate>Thu, 14 Feb 2008 21:42:00 -0500</pubDate>
    </item>
    <item>
      <title>Unix Signal Handling In C#</title>
      <description>
&lt;p&gt;In the beginning, Unix introduced 
&lt;a href="http://linux.die.net/man/2/signal"&gt;signal(2)&lt;/a&gt;, which permits a
process to respond to external "stimuli", such as a keyboard interrupt
(&lt;tt&gt;SIGINT&lt;/tt&gt;), floating-point error (&lt;tt&gt;SIGFPE&lt;/tt&gt;), dereferencing the
&lt;tt&gt;NULL&lt;/tt&gt; pointer (&lt;tt&gt;SIGSEGV&lt;/tt&gt;), and other asynchronous events.
And lo, it was...well, acceptable, really, but there wasn't anything better,
so it at least &lt;i&gt;worked&lt;/i&gt;.  (Microsoft, when faced with the same problem of
allowing processes to perform some custom action upon an external stimuli,
invented 
&lt;a href="http://www.microsoft.com/msj/0197/exception/exception.aspx"
&gt;Structured Exception Handling&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Then, in a wrapping binge, I exposed it for use in C# with 
&lt;a href="http://www.go-mono.com/docs/index.aspx?tlink=0@ecma%3a149%23Stdlib%2fM%2f53"
&gt;Stdlib.signal()&lt;/a&gt;, so that C# code could register signal handlers to be
invoked when a signal occurred.&lt;/p&gt;

&lt;p&gt;The problem?  By their very nature, signals are asynchronous, so even in a 
single-threaded program, you had to be &lt;i&gt;very&lt;/i&gt; careful about what you did, 
as your "normal" thread was certainly in the middle of doing something.  For 
example, calling &lt;a href="http://linux.die.net/man/3/malloc"&gt;malloc(3)&lt;/a&gt; was 
almost certainly a bad idea, because if the process was in the middle of a 
&lt;tt&gt;malloc&lt;/tt&gt; call already, you'd have a reentrant malloc call which could 
corrupt the heap.&lt;/p&gt;

&lt;p&gt;This reentrant property impacts &lt;i&gt;all&lt;/i&gt; functions in the process,
including system calls.  Consequently, a list of functions that were "safe"
for invocation from signal handlers was standardized, and is listed in the
above &lt;tt&gt;signal&lt;/tt&gt; man page; it includes functions such as &lt;tt&gt;read(2)&lt;/tt&gt;
and &lt;tt&gt;write(2)&lt;/tt&gt;, but not functions like e.g. &lt;tt&gt;pwrite(2)&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;Consequently, these limitations and a few other factors led to the general 
recommendation that signal handlers should be as simple as possible, such
as writing to global variable which the main program occasionally polls.&lt;/p&gt;

&lt;p&gt;What's this have to do with &lt;tt&gt;Stdlib.signal()&lt;/tt&gt;, and why was it a
mistake to expose it?  The problem is the
&lt;a href="http://www.mono-project.com/dllimport"&gt;P/Invoke mechanism&lt;/a&gt;, which
allows marshaling C# delegates as a function pointer that can be invoked from
native code.  When the function pointer is invoked, the C# delegate is
eventually executed.&lt;/p&gt;

&lt;p&gt;However, before the C# delegate can be executed, 
&lt;a href="http://lists.ximian.com/pipermail/mono-devel-list/2008-January/026501.html"
&gt;a number of of steps needs to be done first&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;The first thing it does is to ensure the application domain
    for the thread where the signal handler executes actually matches the
    appdomain the delegate comes from, if it isn't it may need to set it and
    do several things that we can't guarantee are signal context safe...&lt;/li&gt;
    &lt;li&gt;If the delegate is of an instance method we also need to retrieve
    the object reference, which may require taking locks...&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the same email, 
&lt;a href="http://www.advogato.org/person/lupus/"&gt;lupus&lt;/a&gt;
suggests an alternate signal handling API that would be safe to use from
managed code.  Later, 
&lt;a href="http://lists.ximian.com/pipermail/mono-devel-list/2008-January/026673.html"
&gt;I provided a possible implementation&lt;/a&gt;.  It amounts to treating the
&lt;tt&gt;UnixSignal&lt;/tt&gt; instance as a glorified global variable, so that it can be
polled to see if the signal has been generated:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
UnixSignal signal = new UnixSignal (Signum.SIGINT);
while (!signal.IsSet) {
  /* normal processing */
}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;There is also an API to permit blocking the current thread until the signal
has been emitted (which also accepts a timeout):&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
UnixSignal signal = new UnixSignal (Signum.SIGINT);
// Wait for SIGINT to be generated within 5 seconds
if (signal.WaitOne (5000, false)) {
    // SIGINT generated
}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Groups of signals may also be waited on:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre class="code-csharp"&gt;
UnixSignal[] signals = new UnixSignal[]{
    new UnixSignal (Signum.SIGINT),
    new UnixSignal (Signum.SIGTERM),
};

// block until a SIGINT or SIGTERM signal is generated.
int which = UnixSignal.WaitAny (signals, -1);

Console.WriteLine ("Got a {0} signal!", signals [which].Signum);&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;This isn't as powerful as the current &lt;tt&gt;Stdlib.signal()&lt;/tt&gt; mechanism,
but it is safe to use, doesn't lead to potentially ill-defined or unwanted
behavior, and is the best that we can readily provide for use by managed
code.&lt;/p&gt;

&lt;p&gt;&lt;tt&gt;Mono.Unix.UnixSignal&lt;/tt&gt; is now in 
&lt;a href="http://anonsvn.mono-project.com/source/trunk/"&gt;svn-HEAD&lt;/a&gt; and the
&lt;a href="http://anonsvn.mono-project.com/source/branches/mono-1-9/"&gt;mono-1-9&lt;/a&gt;
branch, and should be part of the next Mono release.&lt;/p&gt;

</description>
      <link>http://www.jprl.com/Blog/archive/development/mono/2008/Feb-08.html</link>
      <author>jonpryor@vt.edu (Jonathan Pryor)</author>
      <guid isPermaLink="true">http://www.jprl.com/Blog/archive/development/mono/2008/Feb-08.html</guid>
      <pubDate>Fri, 08 Feb 2008 20:32:00 -0500</pubDate>
    </item>
  </channel>
</rss>
