<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>Sam Danielson - Home</title>
  <id>tag:samdanielson.com,2008:mephisto/</id>
  <generator uri="http://mephistoblog.com" version="0.7.2">Mephisto Noh-Varr</generator>
  <link href="http://samdanielson.com/feed/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://samdanielson.com/" rel="alternate" type="text/html"/>
  <updated>2008-12-20T19:02:02Z</updated>
  <entry xml:base="http://samdanielson.com/">
    <author>
      <name>sam</name>
    </author>
    <id>tag:samdanielson.com,2008-12-20:6318</id>
    <published>2008-12-20T19:00:00Z</published>
    <updated>2008-12-20T19:02:02Z</updated>
    <link href="http://samdanielson.com/2008/12/20/techniques-for-local-viewing-with-wget" rel="alternate" type="text/html"/>
    <title>Techniques for local viewing with wget</title>
<content type="html">
            &lt;p&gt;Wget is a good way to collect interesting websites or HTML e-books for off-line reading. The program is capable of pretty much anything and it took me some trial and error to get reliable results. Some hosts have unfavorable robots.txt files or send different results depending on the user-agent. I've even seen some hosts configured to deny the wget user-agent. After some iteration I have found a good set of options that just works all the time.&lt;/p&gt;

&lt;p&gt;wget -rSNpk -np --execute robots=off -U &quot;Mozilla/5.001 (windows; U; NT4.0; en-us) Gecko/25250101&quot;&lt;/p&gt;

&lt;p&gt;The above line contains the following options in -rSNpk -np. The rest of the line just tells wget to ignore robots.txt and to send a bogus user-agent.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;-r recursive fetching&lt;/li&gt;
&lt;li&gt;-S preserve server modified date&lt;/li&gt;
&lt;li&gt;-N download only if file on server is newer than local copy&lt;/li&gt;
&lt;li&gt;-p fetch page requisites (images, sounds, stylesheets)&lt;/li&gt;
&lt;li&gt;-k convert links for local viewing&lt;/li&gt;
&lt;li&gt;-np no parent, recurses only on siblings and children of a url&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The --follow-ftp option is also useful for some sites having ftp assets, which is common for pdf and video.&lt;/p&gt;

&lt;p&gt;If you don't want to swamp the host there are the following options.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;-w&amp;lt;n&gt; wait n seconds between fetches&lt;/li&gt;
&lt;li&gt;--random-wait modify wait time by 50% to 150%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following line is in my ~/.bashrc&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;alias wgetr=&quot;wget -rSNpk -np --execute robots=off -U \&quot;Mozilla/5.001 (windows; U; NT4.0; en-us) Gecko/25250101\&quot; $@&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Usage: wgetr http://example.com/ebook-with-no-gzipped-download-link&lt;/p&gt;

&lt;p&gt;And that is how I use wget. If it's worth reading it's worth saving.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://samdanielson.com/">
    <author>
      <name>sam</name>
    </author>
    <id>tag:samdanielson.com,2008-12-11:6312</id>
    <published>2008-12-11T19:16:00Z</published>
    <updated>2008-12-12T00:44:57Z</updated>
    <category term="Programming"/>
    <link href="http://samdanielson.com/2008/12/11/vala-is-awesome" rel="alternate" type="text/html"/>
    <title>Vala is Awesome</title>
<content type="html">
            &lt;h3&gt;The GUI Dilemma&lt;/h3&gt;

&lt;p&gt;Linux has many language implementations but I keep finding myself driven to C by quality documentation and faithful implementations. Python, Ruby, and Scheme are all great but docs for bindings are second-hand and I usually need to pull out the original library reference or look at C headers and test-cases to accomplish anything.&lt;/p&gt;

&lt;p&gt;If I want to port to the maemo platform I have to port the bindings too. Just more version hell.&lt;/p&gt;

&lt;p&gt;On top of that there is interpreter lock with internal threads and that isn't good for the GUI. Loading a GtkListStore is already slow enough when calling from C but doing it in an interpreted language means an inner loop with additional marshaling. Database extensions should also be written as efficiently as possible because that makes them more flexible as I don't have to tiptoe around them in SQL; worrying whether my slowness is getting called 10 or 10e6 times per query. Then there's callbacks, like for sorting, which are called nlogn times or worse. If I'm writing asynchronous IO, ListModel loading, database extensions, and sort callbacks in C then there's very little left to do in an interpreted HLL.&lt;/p&gt;

&lt;p&gt;I hate GObject C but I like GObject enough to wish I had used it for some things that are slowly turning into their own private spaghetti hell. Refactoring creates even more opportunities for error and is time consuming. C is hard, let's go shopping :)&lt;/p&gt;

&lt;p&gt;C++ would be a good option if I had a much higher IQ. I can use existing classes but writing a new class without memory leaks, using it properly with exceptions, and looking out for excessive copying is a mental exercise in itself. That's actually a languages strength, lots of meaning in a line, but it's not an abstraction as much as it is a complex macro expansion. It's a fun language but it doesn't offer the blissful ignorance I often want.&lt;/p&gt;

&lt;h3&gt;Introducing Vala&lt;/h3&gt;

&lt;p&gt;With Vala the blissful ignorance is there for the taking, up to a point of course. It is a modern but slightly crippled language that steals as much as possible from C#. It has all the OO features of GObject, including singe inheritance, multiple interfaces, runtime binding, and dynamic properties. Destructors and constructors are supported along with private/protected/public members. There is also a limited &quot;compact&quot; class that avoids GObject for better performance. Structs and types built on machine words like int, float, and bool do not have OO features and have an exact correspondence to C. There is a string type built on GString that supports some useful operators like + and +=. Type inference means variables can be declared simply with the &quot;var&quot; keyword. The type-system also differentiates between nullable and non-nullable types and checks GError exceptions at runtime. Garbage collection is accomplished via reference counting, which is good enough for most things. Vala supports generics with the familiar template-like syntax. All generics appear to be implemented with gpointer, i.e. (void *), instead of creating new code and structures for each instantiated type. For example a &lt;strong&gt;Point2&amp;lt;int&amp;gt; p = {1,2}&lt;/strong&gt; would create a struct containing two gpointers. Function delegates can be defined inline and look like a lambda. Currently, only formal parameters of the lambda may appear in the body. Vala accepts full lexical closures syntactically but the generated C contains undeclared identifiers and does not compile. Vala will most likely implement ref-counted closures in the future via GClosure, or so I hope.&lt;/p&gt;

&lt;p&gt;The language compiles through C and anyone familiar with GObject should be able to read the C output to easily figure out what's going on. I wouldn't hesitate to use a Vala library from C because it's really just GObject under the hood. Bindings are easily implemented in a separate &quot;vapi&quot; file. There is no documentation for vapi at the moment but it really doesn't need much. Marshaling is delegated to GObject at runtime and calling GObject code from Vala doesn't cost any more than calling from C. The whole language is actually syntax sugar for C. It's C++ reinvented with the benefit of C# and Java in the rear-view mirror.&lt;/p&gt;

&lt;p&gt;GObject has a high runtime cost but the Vala designers have created some very useful pockets in the type system to mitigate that issue. Vtable lookup always occurs for interface methods, unfortunately even when the concrete type is known at compile time. Inherited methods are called statically through upcasting so better performance is possible by restricting OO usage to compact classes and inheritance-only method resolution. The pointer overhead in generic structures would probably offset any performance increase from static method binding unless it is used carefully. Unrestricted use of generics would imply using them in interface constraints and those entail virtual method calls anyway. The language also doesn't leverage stack allocation for objects like C++ so instantiation requires heap allocation. Structs have access-controlled members and are normally stack allocated but copy constructors and destructors are still generated for structs to support full-object members. The compiler currently accepts inheritance and interface syntax for struct declarations but ignores it when generating code.&lt;/p&gt;

&lt;p&gt;The roadmap is set for a 1.0 release in March 2009; fingers crossed. Vala is promising because it's conceptually simple, as portable as glib, has decent performance, and plays well with C in both directions.&lt;/p&gt;

&lt;p&gt;PS. I should warn the reader that I just discovered Vala yesterday and my knowledge of it is limited to examining the C output of the version 0.5.2 compiler. Some of this info is probably wrong so this article is As-Is, No Warranty. However, I'd appreciate a comment if I failed to understand something about Vala.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.vala-project.org/doc/vala-draft/&quot;&gt;Vala Documentation (draft)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://live.gnome.org/Vala/Tutorial&quot;&gt;Vala Tutorial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://code.google.com/p/vala-benchmarks/wiki/BenchResults&quot;&gt;Speed Shootout&lt;/a&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://samdanielson.com/">
    <author>
      <name>sam</name>
    </author>
    <id>tag:samdanielson.com,2008-12-02:6308</id>
    <published>2008-12-02T14:08:00Z</published>
    <updated>2008-12-02T19:48:19Z</updated>
    <category term="Rants"/>
    <link href="http://samdanielson.com/2008/12/2/the-port-authority-draft" rel="alternate" type="text/html"/>
    <title>The Port Authority Draft</title>
<content type="html">
            &lt;p&gt;Yesterday I spoke with a man whose supposed infraction of Port
Authority rules may lead to a personal fine of $1000. His crime was
failing to challenge an under-cover officer's undisplayed ID in a
secured area. To tell this story while protecting the innocent I'll
just call him Joe Pilot and say he works for a made-up Westwind
Airlines. The undercover officer is Decoy Dan.&lt;/p&gt;

&lt;p&gt;Decoy Dan approached Joe Pilot in a hallway of a secured area and
started a short conversation. After a few seconds of this Dan
indicated that Joe should come with him because Joe had done something
wrong. Joe obliged and the pair walked a few steps to the chief
pilot's office where Joe learned the extent of his liability.&lt;/p&gt;

&lt;p&gt;The secured area I'm referring to is one of offices, filing cabinets,
desks, lounge chairs, vending machines, lockers, and break rooms. It's
not a busy ramp where alertness is required for physical safety but a
place where crew go to print paperwork for their next flight, relax,
or take a nap. A terrorist would enjoy the area for its access to
aircraft so security is very important. In this area people should
voluntarily raise awareness to abnormal situations for the same reason
they bring any other safety related issues to immediate attention. The
issue here is not whether Joe should have challenged for ID but
whether it was his legal duty.&lt;/p&gt;

&lt;p&gt;Joe was allowed in the secured area because he had an ID badge issued
by Westwind Airlines. The terms and duties of his employment with
Westwind were governed solely by his union contract and there was no
requirement therein for Joe to challenge undisplayed ID. Joe wasn't
even on paid company time during the infraction. The Port Authority
issued badges to vendors and other airport employees but not to
Joe. Joe did not have a Port Authority ID, which is the one Decoy Dan
should have been wearing when he spoke to Joe. Joe had only a company
ID and was required to challenge a Port Authority officer for failure
to display a Port Authority ID.&lt;/p&gt;

&lt;p&gt;Joe's infraction is one of inaction. He didn't DO something illegal
but FAILED TO DO something supposedly required of him. Pilots have
grave responsibility and have agreed to perform certain duties in
accordance with their company employment and FAA certification. Joe
can be held responsible for e.g. failing to check fuel levels before
departure by both the company and the FAA. He has studied his duties
because he is a professional and he performs them voluntarily because
he is a free man who agreed to perform them. The FAA certificate bearing
his signature is proof of that agreement.&lt;/p&gt;

&lt;p&gt;Joe has never had an agreement with the Port Authority and yet they
are holding him responsible for failure to notice and enforce rule
violations committed by their officers. Free people can do anything
that does not infringe on the rights of others. Doing nothing does not
infringe on the rights of others so free people are free to do
nothing. If the Port Authority can conscript Joe into their service
then Joe is not free. This is a back-door draft of formerly free
people into government service.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://samdanielson.com/">
    <author>
      <name>sam</name>
    </author>
    <id>tag:samdanielson.com,2008-07-15:5326</id>
    <published>2008-07-15T20:48:00Z</published>
    <updated>2008-07-15T22:03:24Z</updated>
    <category term="Rants"/>
    <link href="http://samdanielson.com/2008/7/15/why-google-apps-fail" rel="alternate" type="text/html"/>
    <title>Why Google Apps Fail</title>
<content type="html">
            &lt;p&gt;&lt;a href=&quot;http://www.google.com/a/help/intl/en/index.html&quot;&gt;Google Apps&lt;/a&gt; is(are) the new MS Office complete with spreadsheet, slide presenter, database, and word processor. They all suck. Commonly cited reasons for failure are that the browser is not an OS, Javascript lacks support for concurrency, Javascript is slow, businesses are slow to adapt to new technology, community authorship is already solved by &lt;span class=&quot;caps&quot;&gt;VCS&lt;/span&gt; and wikis, etc. Here&#8217;s the real reason they fail: fighting the last war. Word processors and spreadsheets are generic, where &#8220;generic&#8221; carries the same negative connotation as when applied to performance art.&lt;/p&gt;


	&lt;p&gt;Google shouldn&#8217;t be trying to make generic apps easier to use on the web. Email, &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt;, IM, wikis, forums, and social bookmarking have an evolved interface balancing generality with complexity. They are also not stand alone programs that can have the network part removed like a word processor. Even if all the technical browser/script problems are solved, what will Google Apps offer other than a plethora of features bolted on to something resembling a wiki? It&#8217;s generic.&lt;/p&gt;


	&lt;p&gt;Features can increase generality, but at some level of generality the competing technology becomes Sqlite, Linux, or Java; not MS Word. I&#8217;ve witnessed the humor of a &lt;a href=&quot;https://www.salesforce.com/&quot;&gt;Salesforce&lt;/a&gt; tech-support conference call. My client was using a form that posted to Salesforce and was trying to add some work-flow features on the Salesforce end. What I heard astounded me, the client was getting a lesson in scripting from the tech. I left the call early, glad my part was limited to creating the form. A solution can go in two directions as it becomes more general; more abstract, or more complex. MS Word and Powerpoint embrace complexity. Programming languages lean toward abstraction. Either way, generic solutions are always harder to use.&lt;/p&gt;


	&lt;p&gt;The MS Office suite thrived because it made it easy to share. Embrace, extend, extinguish. One app to open them all! The complexity was necessary for generality, and generality was necessary for sharing. On the isolated PC there wasn&#8217;t room for a special version of Powerpoint for teaching with another for pitching sales. Word had to handle letters, resumes, and instruction manuals, in formats including &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;, text, and binary. It had to interface with Access and embed Excel documents, and each of those programs had to share well with others in the suite. It was a very capable one-size-fits-all solution that was very complex as a result.&lt;/p&gt;


	&lt;p&gt;With the web offering effectively unlimited storage on top of easy distribution and sharing, there is no longer a need for one-size-fits-all suites. New apps can depart from the generic view of the suite and approach problems directly. There should not be a &lt;a href=&quot;http://www.techcrunch.com/2007/04/17/googles-office-suite-complete-google-powerpoint-confirmed/&quot;&gt;Powerpoint of the Web&lt;/a&gt; . Instead, applications should specialize so that one for e.g. teaching aircraft systems or training sales reps will bundle a tailored likeness of Powerpoint. Slides in this new hypothetical software might pull facts from manuals or link to simulations, each of which is another specialized application, reiterating the importance of sharing. Thus, &lt;a href=&quot;/svgpp/bubble.svg&quot;&gt;The Web&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;Google Apps solve the problem of sharing by offering a uniform &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; (so 1990), on the web (so 2000). In contrast the new application suite will have as many APIs as there are applications, and as many applications as there are problems to solve. Google Apps are generic and lame.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://samdanielson.com/">
    <author>
      <name>sam</name>
    </author>
    <id>tag:samdanielson.com,2008-04-15:4931</id>
    <published>2008-04-15T23:01:00Z</published>
    <updated>2008-04-15T23:01:46Z</updated>
    <link href="http://samdanielson.com/2008/4/15/sqlpilot" rel="alternate" type="text/html"/>
    <title>Sqlpilot</title>
<summary type="html">&lt;p&gt;My aviation logbook project, Sqlpilot, recently become usable (for me). I was able to turn my old data into CSV with plenty of grep, sed, awk, sql, manual labor, trial and error, and luck. Sqlpilot is a C program linking to gtk and sqlite. Using a relational database feels like the right way to manage a logbook and I now have a whole new view of my flight log. I've been querying things like average leg time and distance for specific aircraft, number of days with over eight hours of flying, number of approaches flown grouped by month, total time in each aircraft and type, and other interesting trivial things that I would have never known had I not started this project.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;My aviation logbook project, Sqlpilot, recently become usable (for me). I was able to turn my old data into CSV with plenty of grep, sed, awk, sql, manual labor, trial and error, and luck. Sqlpilot is a C program linking to gtk and sqlite. Using a relational database feels like the right way to manage a logbook and I now have a whole new view of my flight log. I've been querying things like average leg time and distance for specific aircraft, number of days with over eight hours of flying, number of approaches flown grouped by month, total time in each aircraft and type, and other interesting trivial things that I would have never known had I not started this project.&lt;/p&gt;
&lt;p&gt;I actually moved it into production without realizing it and my changes quickly became incompatible with the database schema I was using to record my time. Problem was, some of those changes fixed bugs so I had good compatible changes mixed with incompatible ones. I'd read that ad-hoc merging was a strength of git so I imported my svn repository into git and started pulling the good changes from different commits into the working directory. There is no need to explicitly tell git the changes represent a merge. It's like being able to do svn update/revert to set parts of the working tree to different versions and then commit. If I rolled back part of the working tree to an old revision in subversion without explicitly using a merge it would fail to commit. Git doesn't care where changes come from so it works. The way git handles branching is pretty neat too and IMHO it makes subversion's branching look like a clever but inelegant hack. The other neat thing is that I was able to do this in the back of a jet while on my way to work. Storing version history locally is really nice for traveling.&lt;/p&gt;

&lt;p&gt;The interface needs work and I have a list of things to change under the hood but it's usable on my laptop. I've run it in the maemo environment for the Nokia handheld but it really needs a new UI for a small screen. Thanks to glade and gtk-builder that will be easy to do. A few screenshots follow.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://samdanielson.com/assets/2008/4/15/sqlpilot_flights.png&quot; alt=&quot;Sqlpilot Flights&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://samdanielson.com/assets/2008/4/15/sqlpilot_types.png&quot; alt=&quot;Sqlpilot Types&quot; /&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://samdanielson.com/">
    <author>
      <name>sam</name>
    </author>
    <id>tag:samdanielson.com,2008-03-04:4855</id>
    <published>2008-03-04T02:27:00Z</published>
    <updated>2008-03-04T02:35:20Z</updated>
    <link href="http://samdanielson.com/2008/3/4/beans-worth-blogging-about" rel="alternate" type="text/html"/>
    <title>Beans worth Blogging About</title>
<content type="html">
            &lt;p&gt;Tara and I frequent a Thai Restaurant about a half mile from our apartment. Without too much thought I placed an order for something on the menu called Sator Shrimp since I like shrimp and spice doesn&#8217;t bother me. The waiter asked if I had ever had sator before and warned that the dish had a strong smell. That piqued my interest so I stuck with the order. The dish wreaked of odorized propane gas and the flavor of sator defies description. I didn&#8217;t know a plant could taste like that even though I ate things like pine needles and radish leaves as a kid. I finished the dish because I was extremely entertained that someone somewhere actually planted sator beans with the intent of selling them as food. Each bite was like the culinary equivalent of the Jerry Springer Show. After the beans were in my stomach and the sensory-masking effect of curry wore off I began to notice the smell again. It was my breath; onions are to sator what tictacs are to onions.&lt;/p&gt;


	&lt;p&gt;Googling after dinner I found that sator (parkia speciosa) is informally know as a &lt;a href=&quot;http://en.wikipedia.org/wiki/Parkia_speciosa&quot;&gt;Stink Bean&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;I can&#8217;t even believe a plant like sator is legal to grow in the &lt;span class=&quot;caps&quot;&gt;USA&lt;/span&gt; considering growing relatively benign plants like Cannabis can win their owner a prison sentence. We need laws to protect our children from sator now :)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://samdanielson.com/">
    <author>
      <name>sam</name>
    </author>
    <id>tag:samdanielson.com,2008-02-07:4828</id>
    <published>2008-02-07T18:56:00Z</published>
    <updated>2008-02-07T18:58:40Z</updated>
    <category term="Rants"/>
    <link href="http://samdanielson.com/2008/2/7/missing-the-point-misses-the-point" rel="alternate" type="text/html"/>
    <title>"Missing the point", Misses the Point!</title>
<content type="html">
            &lt;p&gt;If there was ever a phrase which should be banned from all discourse it is &#8220;missing the point&#8221;. Missing the point means making an irrelevant conclusion. It&#8217;s similar to a non-sequitur with emphasis on the conclusion rather than the evidence. Instead of saying a conclusion is wrong because the evidence is irrelevant (non sequitur &#8211; does not follow), &#8220;missing the point&#8221; directly attacks the conclusion as irrelevant and therefore wrong.&lt;/p&gt;


	&lt;p&gt;Many Internet discussions have no point and therefore none to miss. Good discussions have many points and that&#8217;s why most comment systems are threaded &#8211; so different points can be clearly discussed! Don&#8217;t tell me I&#8217;m missing the point because I introduce a new spin on things. Instead, be a genius and fork the thread. If you disagree then say so, but how could you disagree if I was truly missing the point? If you rebut irrelevance with anything other than an explanation of why something is irrelevant then your clever rebuttal is non-sequitur since the chain of logic is broken. This is what downmods are for. Use them. &#8220;You&#8217;re missing the point&#8221;, is just a red flag that means irrelevant, obvious, or arrogant statements follow.&lt;/p&gt;


	&lt;p&gt;Which brings me to arrogance. By claiming that I am missing the point you have implied that there is some &#8220;one true&#8221; point that I have missed. How is that even possible? Does each cause have one and only one effect, and vice versa? It&#8217;s nearly the definition of simple-mindedness. Like thought police you seek to limit the scope of discussion to protect the logical purity of your narrow, self-idolizing views though mindlessly repeated idioms. It&#8217;s doubleplus ungood for real discussion.&lt;/p&gt;


	&lt;p&gt;Think I&#8217;m missing the point or full of shit? Consider that Google claims over three times the number of hits for &lt;a href=&quot;http://www.google.com/search?q=%22missing+the+point%22&quot;&gt;missing the point&lt;/a&gt; then for the overused phrases &lt;a href=&quot;http://www.google.com/search?q=%22full+of+shit%22&quot;&gt;full of shit&lt;/a&gt; and &lt;a href=&quot;http://www.google.com/search?q=%22full+of+crap%22&quot;&gt;full of crap&lt;/a&gt; combined. Please stop polluting discussions with this trash.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://samdanielson.com/">
    <author>
      <name>sam</name>
    </author>
    <id>tag:samdanielson.com,2008-01-23:4802</id>
    <published>2008-01-23T00:00:00Z</published>
    <updated>2008-01-23T00:06:39Z</updated>
    <category term="Programming"/>
    <link href="http://samdanielson.com/2008/1/23/haskell-music" rel="alternate" type="text/html"/>
    <title>Haskell Music</title>
<content type="html">
            &lt;p&gt;As part of my effort to seek enlightenment through Haskell I&#8217;ve made some music. It&#8217;s actually sort of neat creating a waveform that when played through a DA resembles something other than white noise. This isn&#8217;t controlling a sequencer &#8211; it&#8217;s just composing functions to make make a sound representation. It&#8217;s a lot like naive ray tracing where all objects are considered for each pixel in that for each sample I sum the waveforms for all notes, many of which are zero since a note only plays for a short duration and is otherwise silent.&lt;/p&gt;


	&lt;p&gt;Notes are made by transforming a sound frequency Signal (Double -&amp;gt; Double) with pitch and amplitude Shifters (Signal -&amp;gt; Signal). For the note envelope I create a signal that represents amplitude and modulate the sound signal with the amp combinator, which is a Modulator (Signal -&amp;gt; Signal -&amp;gt; Signal).&lt;/p&gt;


	&lt;p&gt;One thing missing from this implementation is the ability to write (signal = signal1 + signal2). I now would write (signal t = signal1 t + signal2 t,) since a signal is a function over time. mauke in #haskell (irc.freenode.net) was helpful but I still don&#8217;t understand why some things work the way they do so I chose not to write a (+) instance for signals until I understand it better. The following will play a few measures of Mozart&#8217;s something something as I remember it. I forgot what it&#8217;s called but it&#8217;s in C and it&#8217;s popular.&lt;/p&gt;


	&lt;p&gt;Here&#8217;s an ogg vorbis of the output: &lt;a href=&quot;http://samdanielson.com/assets/2008/1/22/mozart.ogg&quot;&gt;mozart.ogg&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;And the illiterate Haskell.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
-- Compile and listen as follows
-- ghc -o mozart mozart.hs &#38;&#38; ./mozart | mplayer -v -rawaudio rate=16000:channels=1:samplesize=1 -demuxer rawaudio -

import System.IO
import Data.Char

type Signal = Double -&amp;gt; Double
type Shifter = Signal -&amp;gt; Signal
type Modulator = Signal -&amp;gt; Signal -&amp;gt; Signal

main :: IO ()
main = putStr . toBytes . take 200000 . sample 16000 $ sound

sound :: Signal
sound = ampc 0.35 . shifterSum song . pitchc (440 * hstep ** 3 * 2 * pi) $ wave

song :: [Shifter]
song = zipWith (\e p -&amp;gt; amp e . pitchc p) (lhEnvs ++ rhEnvs) (lhPitches ++ rhPitches)

wave :: Signal
wave = flange (\x -&amp;gt; sin (x * 2)) sin

lhPitches :: [Double]
lhPitches = map (* (1/2)) $ [du,so,me,so,du,so,me,so,re,so,fa,so,du,so,me,so] ++
                            [du,la,fa,la,du,so,me,so,re,so,fa,so,du,so,me,so]
lhBegins :: [Double]
lhBegins = take 32 $ toTempo [1..]

-- Applies 0.1 second duration to left hand begin times
-- resulting in a list of complete amplitude envelopes
-- for each note.
lhEnvs :: [Signal]
lhEnvs = map (pianoEnv 0.1) lhBegins

rhPitches :: [Double]
rhPitches = [du,me,so,ti/2,du,re,du,  la,so,du*2,so,fa,me]
rhBegins :: [Double]
rhBegins = toTempo [1,5,7,9,12,12.5,13, 17,21,23,25,28,29]
rhEnvs :: [Signal]
rhEnvs = map (pianoEnv 0.5) rhBegins

-- attack decay sustain release to resemble a piano
-- apply duration and begin for complete envelope signal
pianoEnv :: Double -&amp;gt; Double -&amp;gt; Signal
pianoEnv = env 0.005 0.05 0.4 0.7

-- eigth note tempo
tempo = 160
toTempo :: [Double] -&amp;gt; [Double]
toTempo ts = map (\t -&amp;gt; 60 * t / tempo) ts

-- Sums list of signal shifters and mutes the original signal
shifterSum :: [Shifter] -&amp;gt; Shifter
shifterSum xs = foldr (shifterAdd) (const . const 0) xs

shifterAdd :: Shifter -&amp;gt; Shifter -&amp;gt; Shifter
shifterAdd a b input t = a input t + b input t

-- 1        b
--         / \c_____d
--        /          \
-- 0 ___a/            \e___   Makes an amplitude envelope for a note
--
-- Will div by zero in some cases.
env :: Double -&amp;gt; Double -&amp;gt; Double -&amp;gt; Double -&amp;gt; Double -&amp;gt; Double -&amp;gt; Signal
env attack decay sustain release duration begin t
    | t &amp;lt; a || t &amp;gt;= e = 0
    | t &amp;lt; b           = (t - a) / attack
    | t &amp;lt; c           = 1 - (1 - sustain) * (t - b) / decay
    | t &amp;lt; d           = sustain
    | t &amp;lt; e           = sustain - sustain * (t - d) / release
    where a = begin
          b = a + attack
          c = b + decay
          d = c + duration
          e = d + release

sample :: Double -&amp;gt; Signal -&amp;gt; [Double]
sample rate signal = [signal (t / rate) | t &amp;lt;- [0..]]

-- yuck
toBytes :: [Double] -&amp;gt; [Char]
toBytes = fmap $ chr . clamp 0 255 . (\n -&amp;gt; truncate $ (n + 1) * 127)

clamp min max x
    | x &amp;lt; min = min
    | x &amp;gt; max = max
    | otherwise = x

pitchc :: Double -&amp;gt; Signal -&amp;gt; Signal
pitchc mult input t = input (t * mult)

ampc :: Double -&amp;gt; Signal -&amp;gt; Signal
ampc mult input t = mult * (input t)

amp :: Modulator
amp control input t = (control t) * (input t)

-- only works for control where d/dt = 0
pitch :: Modulator
pitch control input t = input (t * control t)

flange :: Modulator
flange ff w t = w (t + ff t)

hstep = 2 ** (1/12)
du = hstep ** 0
re = hstep ** 2
me = hstep ** 4
fa = hstep ** 5
so = hstep ** 7
la = hstep ** 9
ti = hstep ** 11
&lt;/code&gt;&lt;/pre&gt;
          </content>  </entry>
  <entry xml:base="http://samdanielson.com/">
    <author>
      <name>sam</name>
    </author>
    <id>tag:samdanielson.com,2008-01-09:4793</id>
    <published>2008-01-09T18:31:00Z</published>
    <updated>2008-01-09T18:53:43Z</updated>
    <link href="http://samdanielson.com/2008/1/9/tara-s-blog" rel="alternate" type="text/html"/>
    <title>Tara's Blog</title>
<content type="html">
            &lt;p&gt;&lt;a href=&quot;http://taradanielson.com&quot;&gt;Tara&lt;/a&gt;, my wife, has been maintaining her personal blog primarily with php for templating and no database. Recently she had the desire to add &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt; feeds but since her pages and articles consited of only php files we would need to either scrape the feed from the pages or start using some real blog software. I have been using mephisto so I set that up for her. After we both had done considerable work on templating and transfering content she decided to just retemplate her php setup and worry about &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt; later. I think it was a sound decision. After all, editing in the browser sucks. She&#8217;s been using vim but now prefers the aquamacs style of emacs since I introduced her to that. What can I say? A blog should be nothing more than a directory full of files that gets scanned into an index for display via html or rss. The metadata in liunx is a bit sparse since there is no creation date on files &#8211; just accessed and modified time. Publishing, tagging, and categorization could be handled through symlinks. Search could be a done via grep and cgi but I&#8217;m a little worried about escaping the search string correctly. Comments can be an entirely seperate system for all I care. If only linux wasn&#8217;t so tantilizingly close to a multiuser &lt;span class=&quot;caps&quot;&gt;CMS&lt;/span&gt;/Blog. It&#8217;s close &#8211; but no cigar.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://samdanielson.com/">
    <author>
      <name>sam</name>
    </author>
    <id>tag:samdanielson.com,2008-01-09:4791</id>
    <published>2008-01-09T07:41:00Z</published>
    <updated>2008-01-09T07:59:53Z</updated>
    <category term="Rants"/>
    <link href="http://samdanielson.com/2008/1/9/six-weeks-of-appendicitis" rel="alternate" type="text/html"/>
    <title>Six Weeks of Appendicitis</title>
<content type="html">
            &lt;p&gt;On January 7, 2008 I had my appendix removed more than six weeks after initial symptoms.&lt;/p&gt;


	&lt;p&gt;I began feeling fatigued during a trip on Nov. 22nd. With symptoms of fever, extreme fatigue, and abdominal pain I called in sick and went  home on the 24th. On the 26th I went to a primary care provider and was diagnosed with hematuria caused by a possible kidney infection or stone. I left with a prescription for seven days of steroids and ten days of antibiotics. Ten days later I still felt ill so I returned to the clinic where I again tested positive for hematuria and got a referral to a urologist. The urologist referred me to a CT scan where finally, on the 10th of December, I found the cause of my sickness to be an enlarged appendix. The urologist referred me back to primary care where I received a referral to a surgeon. The surgeon reviewed the CT scan and decided to remove the appendix but advised that since my condition was improving it would be best to allow some healing to occur before cutting. He prescribed some antibiotics and said it would be okay to work but agreed it would be best to consult an aviation medical examiner. The aviation doctor also said that I could work until surgery but cautioned me that I should not work with pain since it was a distraction. Since I was pain free for three days I returned to work on the 17th of December but the altitude changes and turbulence caused my abdominal pain to return. As should be expected the aviation doctor was right, pain is really distracting. I called in sick again and decided to wait until I had recovered from surgery to return to work. The surgeon did a great job and I have had less pain during recovery than I did during much of December. I don&#8217;t need pain medication but I have been using one dose at night to sleep through the minor discomfort of three incisions in my stomach. Finally, almost two months after beginning sick leave I will be fit to return to work. I have used the majority of my sick bank and filed for &lt;span class=&quot;caps&quot;&gt;FMLA&lt;/span&gt;. What should have caused me to miss three weeks of work turned in to seven and a half. The hospital staff, surgeon, urologist, and CT scan folks were excellent and I have great respect for them and their profession.&lt;/p&gt;


	&lt;p&gt;As for so-called primary care, this is not the health care I grew up with and I don&#8217;t really know where to point my finger. The primary care &lt;span class=&quot;caps&quot;&gt;PAC&lt;/span&gt; and her doctor focused on kidney issues due to hematuria and assumed the abdominal pain was associated. Blood and urine were taken for additional testing but the blood results took days to complete. Blood tests confirmed I had an infection of some sort. There was no X-ray, CT, ultrasound, &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt;, or any imaging in the office. Getting imaging done takes a referral and an appointment several days away. &lt;span class=&quot;caps&quot;&gt;A CT&lt;/span&gt; scan would have removed the possibility of a kidney infection or stone. I can only assume that if there was imaging equipment in the office I would have been referred to a surgeon two weeks earlier than I was, maybe even had my appendix removed that same day. Since it takes three to five days to schedule a CT scan it would seem reasonable to begin taking drugs for the most likely problem until the scan could be completed. Even then, I would most likely need a specialist referral and that can take even longer to schedule than a scan. Why can&#8217;t I go to the doctor and get some real tests done so I can get a diagnosis? Do I blame the system or just assume I chose bad primary care? This isn&#8217;t the first clinic I have found in the area. I have been to a few and shopped around. They are all in professional buildings and are staffed by approximately ten doctors and nurses. They have a microscope and a stack of magazines. Any real tests require a referral. I personally think primary care has become nothing more than a sales outlet for pharmaceuticals.&lt;/p&gt;


	&lt;p&gt;While at the hospital I told the nurse about my referral saga and asked if she knew of a primary care clinic that had at least an X-ray machine. She advised that she was not allowed to give recommendations. Fair enough, but she also said the care I received seemed standard. Usually primary care, the place I go with symptoms, is a professional building with very limited equipment. What are these places? All they can do is prescribe drugs and when I&#8217;m sick I may need more than drugs. The hospital is where the real care is but unfortunately I don&#8217;t qualify for that clinic since I actually have insurance and I&#8217;m not a senior citizen. In the end I paid more in co-pays than an emergency room would have cost. My profession as an airline pilot is also incompatible with referrals and waiting since I am essentially grounded until I know what&#8217;s wrong. I can&#8217;t just go to work while I wait for test results for documented symptoms. I am required to have a medical exam every six months and it is clear that going to work sick is illegal, stupid, and a willful violation of the law. Despite the cost I am considering skipping the bullshit and going to a real hospital with real equipment next time I have symptoms.&lt;/p&gt;


	&lt;p&gt;This leads to billing. I have great insurance. It&#8217;s a 90/10 plan with no deductible and a reasonable out-of-pocket maximum. I chose this plan over 100%  coverage because even with my surgery the total cost in premiums and coinsurance is about equal to the cost of 100% coverage. These are the benefits of working for a good company and being part of a strong union like &lt;span class=&quot;caps&quot;&gt;ALPA&lt;/span&gt;. I lost no pay since I had time in my sick bank and &lt;span class=&quot;caps&quot;&gt;FMLA&lt;/span&gt; will keep me in good standing with my employer. This is to say, I am not forgetting to count my blessings.&lt;/p&gt;


	&lt;p&gt;I do, however, have some issues with the billing which make me worry for the day when I have no insurance. A typical test for blood or urine might be billed at six times what the insurance company actually pays. A $380 lab test gets covered at $60 by &lt;span class=&quot;caps&quot;&gt;BCBS&lt;/span&gt;. When I asked how much my CT scan would cost I was told $2000. They billed &lt;span class=&quot;caps&quot;&gt;BCBS&lt;/span&gt; for $850 and &lt;span class=&quot;caps&quot;&gt;BCBS&lt;/span&gt; paid around $500. My bills all share this trait with lab work having by far the greatest discrepancy between what is billed vs. paid. Before the surgery I tried to find out what it would cost but no one could tell me. I signed that I would pay the bill if the insurance company denied my claim without a clue what it would cost. I know it depends on the resources and time used. If I had to stay additional nights in the hospital or have more surgery and blood transfusions it would cost more. Still, why can&#8217;t I get an itemized estimate ahead of time? An accurate estimate would be nice. Don&#8217;t tell me it&#8217;s going to cost $30,000 and then bill the insurance for $6500 while getting paid $4000. This is exactly what would have happened so I didn&#8217;t really mind not having an itemized bill.&lt;/p&gt;


	&lt;p&gt;I have it better than most people in America. Many folks pay larger premiums and have per-person deductibles which for a family can lead to terrible cost. Others have no insurance. Do they pay the full 600% markup on lab work? Primary care is a &lt;span class=&quot;caps&quot;&gt;WTF&lt;/span&gt;. Billing is a &lt;span class=&quot;caps&quot;&gt;WTF&lt;/span&gt;. At least I am alive. Thanks also to my wife for helping me with the innumerable pains and annoyances that happen during illness.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://samdanielson.com/">
    <author>
      <name>sam</name>
    </author>
    <id>tag:samdanielson.com,2007-12-26:4761</id>
    <published>2007-12-26T21:24:00Z</published>
    <updated>2007-12-26T21:40:49Z</updated>
    <category term="Programming"/>
    <link href="http://samdanielson.com/2007/12/26/the-best-tutorial-write-yourself-a-scheme-in-48-hours" rel="alternate" type="text/html"/>
    <title>The Best Tutorial - Write Yourself a Scheme in 48 Hours</title>
<content type="html">
            &lt;p&gt;&lt;a href=&quot;http://halogen.note.amherst.edu/~jdtang/scheme_in_48/tutorial/overview.html&quot;&gt;Write yourself a Scheme in 48 Hours&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;This is the most excited I&#8217;ve been since I learned how to make a character bounce around the screen on my &lt;span class=&quot;caps&quot;&gt;C64&lt;/span&gt;! Learning a new programming style is hard: big programs are difficult to understand and small programs have too little to tweak. How do I learn from a ten line tutorial or a one-hundred line program? The ten line tutorial doesn&#8217;t do anything interesting and forces me to write new code to grow. &lt;span class=&quot;caps&quot;&gt;OTOH&lt;/span&gt;, one-hundred lines of Haskell usually do something neat but I can&#8217;t begin to untangle how. For everyone there is a threshold of complexity, the understanding of which enables creating more complex things. Once this threshold is achieved a person can bootstrap their learning as an autodidact. Below it there is neither enough knowledge to guide their study or test their knowledge for correctness.&lt;/p&gt;


	&lt;p&gt;My capacity for understanding is often far lower than the bootstrapping threshold and my learning stalls as I fumble through tutorials gaining one small bit of knowledge without correlation until one day things begin to click into place. I then wonder how I learned in eight hours what had stumped me for eight months and feel profound appreciation for the wizards that understood it first. It&#8217;s like I was blind and they could see, and now through some miracle I also see. It&#8217;s real sight too, not just a description in words but the real sunrise seen for the first time by the formerly blind. In this case the misfitting pieces were the static algebraic types, monads, type classes, currying, and lazy evaluation of Haskell. It&#8217;s quite a bit to swallow just as the more familiar loops, conditional statements, functions, and variables once were. Many of these things are interdependent and cannot be understood separately. Jonathan Tang begins small and works from the ground up to a larger program, explaining each change so every line&#8217;s purpose is thoroughly understood. The culmination is a very small but capable scheme interpreter that is larger than what I would have understood without my building it. It is a perfect demonstration of the building-block technique of instruction I learned and used as a flight instructor.&lt;/p&gt;


	&lt;p&gt;Mr. Tang put the pieces together concisely. Wow.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://samdanielson.com/">
    <author>
      <name>sam</name>
    </author>
    <id>tag:samdanielson.com,2007-12-26:4760</id>
    <published>2007-12-26T19:35:00Z</published>
    <updated>2007-12-26T20:16:22Z</updated>
    <category term="Rants"/>
    <link href="http://samdanielson.com/2007/12/26/my-documents" rel="alternate" type="text/html"/>
    <title>My Documents</title>
<content type="html">
            Today as my file dialog opened to save a freshly downloaded pdf it defaulted to my $HOME/Documents directory. Why? I have never created a Documents directory and I certainly don't use it. I didn't even know it existed! Where did it come from? Where did Music, Pictures, and Videos come from? I know I deleted them from the default skeleton for Ubuntu and I'm sure the Arch installer didn't put them there. Who decided I needed these things and that I should use them? They're capitalized, don't begin with a '.', and are empty. They are a stupid suggestion and an eyesore. Should I really put all my videos in the same subtree? I don't mind .xinitrc, mail, .bash_history, Desktop, News, etc... These files have a purpose. Documents, Music, Pictures, and Videos are totally useless and empty. Thank you for demonstrating that directories exist. Thank you for causing my file dialog to conveniently default to Documents. If this were Windows I'd have to add a gracious Thank You!!! to all software for assuming that I save everything in My Documents, and for that matter, that everything I save is a Document! I don't even know who I'm thanking. Who's idea was this anyway? Maybe it's my fault for assuming that words have meaning or for not keeping my underwear-drawer perfectly labeled and sorted. Whoever you are please stop creating useless directories in $HOME for the sole purpose of imposing your world view. If I ever get the chance to write to your $HOME I'll create a directory called Idiot's Files and move everything else into that.
          </content>  </entry>
  <entry xml:base="http://samdanielson.com/">
    <author>
      <name>sam</name>
    </author>
    <id>tag:samdanielson.com,2007-12-13:4740</id>
    <published>2007-12-13T18:41:00Z</published>
    <updated>2007-12-13T19:38:58Z</updated>
    <category term="Programming"/>
    <link href="http://samdanielson.com/2007/12/13/xmonad" rel="alternate" type="text/html"/>
    <title>Xmonad</title>
<content type="html">
            &lt;p&gt;Xmonad is an awesome window manager and these are my complements as a fanatical user. The thing I love about Xmonad is that it just seems to get everything right. Wmii, my first favorite tiling WM, really got me interested and I found no fault with it until I used Xmonad.&lt;/p&gt;


	&lt;p&gt;Internally Xmonad manages focus with a zipper data structure. Though there are more naive approaches used in early versions it&#8217;s clear from maintainer &lt;a href=&quot;http://cgi.cse.unsw.edu.au/~dons/blog/2007/05/17&quot;&gt;Don Stewart&#8217;s blog&lt;/a&gt; that a lot of thought went in to my sanity as a user. The sorted order provided by the zipper allows for completely automatic management of my windows. For me, the order reduces my workspace to essentially one dimension. In Wmii I used vim key-bindings to move focus up/down/left/right. In Xmonad I use only two keys for this. In every other window manager Alt+Tab is a total pain due to the random order of the windows or the fact that they need to be manually sorted. Xmonad always inserts and deletes windows in a way which preserves order as if I were inserting or deleting lines from a text file. Better, Xmonad can be extended with, among other things, algorithms to arrange windows based on this order. There are tabbed, grid, and circular layouts to name a few. One interesting extension even arranges windows in a Fibonacci spiral.&lt;/p&gt;


	&lt;p&gt;There&#8217;s plenty of fud floating around about the inextensibility of purely functional programs but Xmonad proves otherwise, at least for Haskell&#8217;s case. I feel like a dog watching TV when viewing the source but I do know this; the extensions manage a variety of state and the code is concise. Oh, and the whole thing runs in a memory image a little larger than an instance of bash.&lt;/p&gt;


	&lt;p&gt;Special thanks to Spencer Janssen for authoring the project. Xmonad is doing everything just right so my Archlinux machine is polished like a Macintosh, only more useful.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://samdanielson.com/">
    <author>
      <name>sam</name>
    </author>
    <id>tag:samdanielson.com,2007-11-18:4734</id>
    <published>2007-11-18T00:37:00Z</published>
    <updated>2007-11-18T01:08:15Z</updated>
    <category term="Programming"/>
    <link href="http://samdanielson.com/2007/11/18/arch-linux-vs-ubuntu" rel="alternate" type="text/html"/>
    <title>Arch Linux vs Ubuntu </title>
<content type="html">
            &lt;p&gt;Yes! Arch is great. For more detail read on.&lt;/p&gt;

&lt;h2&gt;Arch's Appeal&lt;/h2&gt;

&lt;p&gt;The main difference between Arch and Unbuntu is that Arch is designed to be molded whereas Ubuntu is a complete desktop/server distro. Like Ubuntu, most things were configured and worked upon install. Unlike Ubuntu, Arch does not have a default desktop environment although XFCE4 could be considered well supported. Arch will appeal to users who wish to start with a minimal system and a package manager, adding bit by bit until the system is tweaked to their desire.&lt;/p&gt;

&lt;h2&gt;Ubuntu's Appeal&lt;/h2&gt;

&lt;p&gt;Ubuntu is for those who just don't want to mess with it - giving users the choice of a server, or a Gnome / KDE / XFCE desktop. There is also a minimal (alternate) Ubuntu installer for those who want more control. I wont say Ubuntu 'wins' here or anywhere because it's apples and oranges. Yes - Arch vs. Ubuntu is a stupid comparison but if you're like me and you can't help but type X vs. Y into Google before doing anything then maybe identifying some differences isn't so bad. In short, Arch maintains bleeding-edge, occasionally broken, packages with no release cycle whereas Ubuntu needs upgrading (breaking) every six months. Ubuntu is good software with target markets. Arch is good software.&lt;/p&gt;

&lt;h2&gt;Package Management&lt;/h2&gt;

&lt;p&gt;Arch uses a rolling release cycle where major releases consist of a snapshot. For a personal computer, avoiding Ubuntu's six month upgrade cycle is a definite benefit. On the other hand it could cause breakage occasionally, which is why I still prefer Ubuntu (LTS) for my server. Arch packages tend to be more bleeding-edge from what I can tell browsing the repository. For example, the packaged version of GHC in Ubuntu 7.10 is 6.6.1 while Arch will install 6.8.1.&lt;/p&gt;

&lt;p&gt;Pacman, the Arch package manager, is similar to apt. One thing I really like is that headers are bundled with library binaries. This makes sense since headers have a tight coupling to the code they describe. They can also be used as documentation when man pages are weak. With Ubuntu I had the option of not installing headers but that proved to be sort of a PITA when compiling or building a new development system. Ruby gems also uses gcc occasionally and it's nice to avoid the search for *-dev packages. &lt;em&gt;pacman -S imagemagick &amp;amp;&amp;amp; gem install rmagick&lt;/em&gt; just worked.&lt;/p&gt;

&lt;h2&gt;Post Install&lt;/h2&gt;

&lt;p&gt;Everything is installed, configured, and working as per the normal Ubuntu setup. Arch requires a few extra steps to get a desktop environment installed. Here's a few examples.&lt;/p&gt;

&lt;h3&gt;Xorg&lt;/h3&gt;

&lt;p&gt;Unfortunately I had to configure X. I say, 'unfortunately', because I hate configuring X. Best to just install Ubuntu on another partition and copy the xorg.conf. Currently I'm using the open-source ATI drivers since I couldn't get the proprietary ones to install properly. I'll be working on that later.&lt;/p&gt;

&lt;h3&gt;Sound&lt;/h3&gt;

&lt;p&gt;Running &lt;em&gt;alsaconf&lt;/em&gt; asked a few questions and my sound card worked. Easy.&lt;/p&gt;

&lt;h3&gt;Suspend and Resume&lt;/h3&gt;

&lt;p&gt;Suspend and resume with swap and ram work great using the pm-utils package. I had to configure the resume scripts to run &lt;em&gt;alsactl restore&lt;/em&gt; to get sound working after a restore but other than that it was configured perfectly upon install.&lt;/p&gt;

&lt;h3&gt;CPU Frequency Scaling&lt;/h3&gt;

&lt;p&gt;Ubuntu Forums had a great post on this topic. Since it's dealing with the kernel it works on Arch too.
http://ubuntuforums.org/showthread.php?t=248867&lt;/p&gt;

&lt;h2&gt;In Total&lt;/h2&gt;

&lt;p&gt;I'll be using Arch for the foreseeable future, maybe even contributing if I'm ever capable of fixing something. The documentation on their wiki is outstanding and the community has momentum. In general, Ubuntu is great for the automated installation and configuration of everything to include the kitchen sink. Arch is great for a lightweight and fast system with a rolling release cycle and bleeding-edge software.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://samdanielson.com/">
    <author>
      <name>sam</name>
    </author>
    <id>tag:samdanielson.com,2007-11-11:4115</id>
    <published>2007-11-11T19:20:00Z</published>
    <updated>2007-11-14T14:45:19Z</updated>
    <category term="Tutorials - as if"/>
    <link href="http://samdanielson.com/2007/11/11/convert-mythtv-video-for-ipod" rel="alternate" type="text/html"/>
    <title>Convert MythTV Video for IPOD</title>
<content type="html">
            &lt;p&gt;These steps worked on Ubuntu Feisty on a 32 bit system and an Ipod Classic.&lt;/p&gt;

&lt;p&gt;The packaged version of ffmpeg on Ubuntu Feisty wasn't doing the job, giving me this error while trying to convert an mpeg 2 to an mpeg 4: &lt;em&gt;Unsupported codec for output stream #0.1&lt;/em&gt;
Newer versions of Ubuntu may fix this so try your luck with the following command.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
sudo aptitude update
sudo aptitude install ffmpeg
ffmpeg -i inputfile.mpg -b 300 -qmin 3 -qmax 5 -g 300 -ab 96000 -s 320:240 -aspect 4:3 test.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If this doesn't work ffmpeg will need to be compiled locally with the following instructions.&lt;/p&gt;

&lt;h3&gt;1. Uninstall ffmpeg&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;
sudo aptitude remove --purge ffmpeg
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;2. Get the latest ffmpeg source.&lt;/h3&gt;

&lt;p&gt;An svn checkout is also available at http://ffmpeg.mplayerhq.hu/download.html&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
wget http://ffmpeg.mplayerhq.hu/ffmpeg-export-snapshot.tar.bz2
tar -xvjf ffmpeg-export-snapshot.tar.bz2
cd ffmpeg-export-???
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;3. Install compile dependencies.&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;
sudo aptitude install libfaac-dev liba52-dev libdc1394-dev libgsm1-dev libogg-dev libvorbis-dev libxvidcore-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;4. Configure the build, make, and install.&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;
./configure --enable-libxvid --enable-libfaac --enable-gpl --enable-pp --enable-pthreads --enable-libvorbis --enable-libogg --enable-liba52 --enable-libgsm --enable-libdc1394 --disable-debug --enable-shared
make
sudo make install
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;5. Edit shared library configuration.&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;
sudo cp /etc/ld.so.conf /etc/so.conf.bak
echo &quot;echo /usr/local/lib &gt;&gt; /etc/ld.so.conf&quot; | sudo sh
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;6. Update library simlinks.&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;
sudo ldconfig -v
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;7. Make sure bin paths are configured correctly.&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;
which ffmpeg
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This should output /usr/local/bin/ffmpeg. If not, restart the shell and check the PATH variable. Ensure /usr/local/bin comes before /usr/bin and /bin.&lt;/p&gt;

&lt;h3&gt;8. Test it out somewhere.&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;
ffmpeg -i inputfile.mpg -b 300 -qmin 3 -qmax 5 -g 300 -ab 96000 -s 320:240 -aspect 4:3 test.mp4
file test.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That's it. The remaining is icing on the cake.&lt;/p&gt;

&lt;h3&gt;9. Automate it.&lt;/h3&gt;

&lt;p&gt;Make was designed for automating software builds. The advantage in using it to automate file conversion is that it will recognize when no work needs to be done for an output file. Create a directory called ipod which is a sibling of the mythv recordings directory. Place the following make-rule inside a Makefile in that directory.&lt;/p&gt;

&lt;p&gt;File: recordings/../ipod/Makefile&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
%.mp4 : ../recordings/%.mpg
        ffmpeg -i $&amp;lt; -b 300 -qmin 3 -qmax 5 -g 300 -ab 96000 -s 320:240 -aspect 4:3 $@
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Create a script to tell Make which output files to create. In this case it's the basename of each MythTV mpeg with an mp4 extension. Make will use the above rule to figure out how to create an mp4 file with a given name. Make will do nothing if the file already exists and is newer than the input file. Name the script convert and chmod it to 755.&lt;/p&gt;

&lt;p&gt;File: recordings/../ipod/convert&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
#!/bin/sh

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 
export PATH

make `ls ../recordings/*.mpg | sed 's/\.\.\/recordings\///' | sed 's/.mpg$/.mp4/'`
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The ugly recording filenames consist of two parts. 1005_20071004210000.mpg, for exampe. The 1005 is the chanid column in the 'channels' table and the rest is a date and time. Luckily the information about a recording is in the 'recorded' table so that can be used to create pretty names for the new mp4's. Here's a my solution. TIMTOWDI, right?&lt;/p&gt;

&lt;p&gt;File: recordings/../ipod/make-pretty&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
#!/bin/sh

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 
export PATH

mkdir -p pretty

for filename in `ls *.mp4`; do
        basename=`echo $filename | sed 's/.mp4$/.mpg/'`
        prettyname=`mysql -umythtv -p???????? -e &quot;select concat(title, ' ', progstart) as name from recorded where basename = '$basename' limit 1;&quot; --database mythconverg -NE \
        | grep name: | sed 's/name: //' | sed 's/00$//' | sed 's/://g' | sed 's/$/.mp4/'`
        ln -sf &quot;../$filename&quot; &quot;pretty/$prettyname&quot;
done
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Add the following line to /etc/crontab or create a new file called /etc/cron.d/ipod and place it there instead. Be sure to &lt;em&gt;sudo chown -R&lt;/em&gt; the ipod directory to the same user specified in the crontab. Every morning the ipod/pretty directory will be filled with shows to watch on the morning commute.&lt;/p&gt;

&lt;p&gt;File: /etc/cron.d/ipod&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
05 2            * * *   mythtv          cd ???????? &amp;&amp; nice -n19 ./convert &amp;&amp; ./make-pretty
&lt;/code&gt;&lt;/pre&gt;
          </content>  </entry>
</feed>
