<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7692259130661310484</id><updated>2024-10-03T20:58:30.605+02:00</updated><category term="arch"/><category term="git"/><category term="linux"/><category term="ruby"/><category term="javascript"/><category term="leopard"/><category term="osx"/><category term="pm"/><category term="rails"/><category term="shellscript"/><category term="zsh"/><category term="bitswiki"/><category term="java"/><category term="netbeans"/><category term="nginx"/><category term="nlp"/><category term="php"/><category term="postgresql"/><category term="prolog"/><category term="rant"/><category term="tutorials"/><title type='text'>Obvious Code</title><subtitle type='html'>Bjørn Arild Mæland&#39;s writings on programming and technology.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Chrononaut</name><uri>http://www.blogger.com/profile/04406773041044462142</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bogus.uib.no/~bma025/nysveis.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>22</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-8505861728532060689</id><published>2009-03-11T12:54:00.004+01:00</published><updated>2010-11-22T09:14:35.906+01:00</updated><title type='text'>This blog is now deprecated</title><content type='html'>Please redirect your feed reader to &lt;a href=&quot;http://bmaland.com/&quot;&gt;http://bmaland.com/&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/8505861728532060689/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/8505861728532060689' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/8505861728532060689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/8505861728532060689'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2009/03/this-blog-is-now-deprecated.html' title='This blog is now deprecated'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-4618071795868130393</id><published>2008-11-30T12:38:00.002+01:00</published><updated>2008-11-30T12:44:18.219+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="prolog"/><title type='text'>Working with strings in Prolog</title><content type='html'>Strings in Prolog can be quite confusing if you come from another language. In this short article I will illustrate how they work, mainly by showing different examples and by creating a term that checks if a string is contained within another string.&lt;br /&gt;&lt;br /&gt;First off, strings in Prolog are written in single quotes. Terms written in double quotes are immediately converted to a list of character codes. Therefore, strings can be handed directly to &lt;em&gt;write&lt;/em&gt;. Strings are also atoms.&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;?- &#39;bergen&#39; = String.&lt;br /&gt;String = bergen.&lt;br /&gt;&lt;br /&gt;?- &quot;bergen&quot; = List.&lt;br /&gt;List = [98, 101, 114, 103, 101, 110].&lt;br /&gt;&lt;br /&gt;?- atom(&#39;bergen&#39;).&lt;br /&gt;true.&lt;br /&gt;&lt;br /&gt;?- is_list(&quot;bergen&quot;).&lt;br /&gt;true.&lt;br /&gt;&lt;br /&gt;?- write(&#39;sdf&#39;).&lt;br /&gt;sdf&lt;br /&gt;true.&lt;br /&gt;&lt;br /&gt;?- write(&quot;sdf&quot;).&lt;br /&gt;[115, 100, 102]&lt;br /&gt;true.&lt;br /&gt;&lt;br /&gt;?- writef(&quot;%s&quot;, [&quot;sdf&quot;]).&lt;br /&gt;sdf&lt;br /&gt;true.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Since strings in Prolog are atoms, they naturally cannot be manipulated. So for&lt;br /&gt;certain tasks they need to be converted to char lists. This can be done with&lt;br /&gt;&lt;em&gt;name&lt;/em&gt;. So to print the first character of a string you&#39;ll have to&lt;br /&gt;convert it to a char list first.&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;?- name(&#39;bergen&#39;, CharList), nth0(0, CharList, FirstChar), put(FirstChar).&lt;br /&gt;b&lt;br /&gt;CharList = [98, 101, 114, 103, 101, 110],&lt;br /&gt;FirstChar = 98.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We now know enough to create our term, &lt;em&gt;contains/2&lt;/em&gt;. For illustration,&lt;br /&gt;we will make it work for both strings and char lists, by converting to a char&lt;br /&gt;list when needed. It will succeed if A is contained within B. We&#39;ll need a&lt;br /&gt;utility term for this as well. Note that I am using SWI-Prolog, so I am&lt;br /&gt;utilizing built in terms that might not be available in other implementations.&lt;br /&gt;The full program as well as an example that generates all possible substrings contained within A follows below.&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;&lt;br /&gt;sublist(S, L) :-&lt;br /&gt;  append(_, L2, L),&lt;br /&gt;  append(S, _, L2).&lt;br /&gt;&lt;br /&gt;contains(A, B) :-&lt;br /&gt;  atom(A),&lt;br /&gt;  atom(B),&lt;br /&gt;  name(A, AA),&lt;br /&gt;  name(B, BB),&lt;br /&gt;  contains(AA, BB).&lt;br /&gt;&lt;br /&gt;contains(A, B) :-&lt;br /&gt;  atom(A),&lt;br /&gt;  name(A, AA),&lt;br /&gt;  contains(AA, B).&lt;br /&gt;&lt;br /&gt;%% The empty list is removed mainly for nicer output in the following example.&lt;br /&gt;contains(A, B) :-&lt;br /&gt;  sublist(B, A),&lt;br /&gt;  B \= [].&lt;br /&gt;&lt;br /&gt;?- forall( contains(&#39;bergen&#39;, X) , writef(&quot;%s\n&quot;, [X]) ).&lt;br /&gt;b&lt;br /&gt;be&lt;br /&gt;ber&lt;br /&gt;berg&lt;br /&gt;berge&lt;br /&gt;bergen&lt;br /&gt;e&lt;br /&gt;er&lt;br /&gt;erg&lt;br /&gt;erge&lt;br /&gt;ergen&lt;br /&gt;r&lt;br /&gt;rg&lt;br /&gt;rge&lt;br /&gt;rgen&lt;br /&gt;g&lt;br /&gt;ge&lt;br /&gt;gen&lt;br /&gt;e&lt;br /&gt;en&lt;br /&gt;n&lt;br /&gt;true.&lt;br /&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/4618071795868130393/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/4618071795868130393' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/4618071795868130393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/4618071795868130393'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2008/11/working-with-strings-in-prolog.html' title='Working with strings in Prolog'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-7255470344249657233</id><published>2008-10-26T20:11:00.014+01:00</published><updated>2008-10-27T09:16:35.922+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="nlp"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Experimenting with automatons in Ruby, part 1</title><content type='html'>A finite automaton is an abstract computing device, which more often than not is used to recognize formal languages. One can look at an automaton as a tape reader which consists of a initial state, a set of final states and a set of transitions between states. The automaton &lt;span style=&quot;font-weight: bold;&quot;&gt;accepts&lt;/span&gt; its input if it has reached the end of the input tape and is in a final state.&lt;br /&gt;&lt;br /&gt;For the purpose of language processing we will implement different kinds of automatons in Ruby, starting with the simplest one we can conceive. We&#39;ll start out with a &lt;span style=&quot;font-weight: bold;&quot;&gt;deterministic finite-state automaton&lt;/span&gt; (DFSA). Such an automaton is called deterministic, since it in any given state &lt;span style=&quot;font-style: italic;&quot;&gt;only has one possible transition&lt;/span&gt; for a given input symbol.&lt;br /&gt;&lt;br /&gt;First we need an example language to work with, so I&#39;ve created the &quot;Ruby-language&quot;. It can be described with the following regular expression: /Ru+by/ (yes, DFSA&#39;s correspond to the languages that can be described by (pure) regular expressions). I admit this is a quite boring language, but we have to start somewhere, right? The alphabet for this language is the set {R,u,b,y}.&lt;br /&gt;&lt;br /&gt;To create an automaton for this language we need four states (visualize this as a directed graph):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;q0: &#39;R&#39; -&gt; q1&lt;/li&gt;&lt;li&gt;q1: &#39;u&#39; -&gt; q2&lt;/li&gt;&lt;li&gt;q2: &#39;u&#39; -&gt; q2, &#39;b&#39; -&gt; q3&lt;/li&gt;&lt;li&gt;q3: &#39;y&#39; -&gt; q4&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;The initial state is q0 and the set of final states is {q4}. As you can see there is a cycle at q2 to allow for an (theoretically) infinite amount of &#39;u&#39; characters. Also note that there is no ambiguity of which state is the next one at any given point for any given input. Hence, the automaton is deterministic.&lt;br /&gt;&lt;br /&gt;On to the implementation considerations. One of the most important design decisions is how we should represent the state transitions. For a DFSA almost anything would work,  but we want to choose something flexible. Let&#39;s try with a nested hash:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;{&lt;br /&gt; :q0 =&gt; {&quot;R&quot; =&gt; :q1},&lt;br /&gt; :q1 =&gt; {&quot;u&quot; =&gt; :q2},&lt;br /&gt; :q2 =&gt; {&quot;u&quot; =&gt; :q2, &quot;b&quot; =&gt; :q3},&lt;br /&gt; :q3 =&gt; {&quot;y&quot; =&gt; :q4}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I think this will work quite well. If we look up a given state in the hash, we will get another hash of all the possible transitions. Matching this up with a input tape should be quite easy. I&#39;ve sketched up a spec for how this should work in practice:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;describe &quot;the Ruby-language&quot; do&lt;br /&gt;  before(:each) do&lt;br /&gt;    @r = DFSA.new({&lt;br /&gt;                    :q0 =&gt; {&quot;R&quot; =&gt; :q1},&lt;br /&gt;                    :q1 =&gt; {&quot;u&quot; =&gt; :q2},&lt;br /&gt;                    :q2 =&gt; {&quot;u&quot; =&gt; :q2, &quot;b&quot; =&gt; :q3},&lt;br /&gt;                    :q3 =&gt; {&quot;y&quot; =&gt; :q4}&lt;br /&gt;                  }, :q0, [:q4])&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  it &quot;should recognize valid sentences&quot; do&lt;br /&gt;    @r.should recognize %w(R u b y)&lt;br /&gt;    @r.should recognize %w(R u u u u b y)&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  it &quot;should reject invalid sentences&quot; do&lt;br /&gt;    @r.should_not recognize %w(r u b y)&lt;br /&gt;    @r.should_not recognize %w(R u b)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that we give the input to the automaton as a list (I&#39;ve picked the %w() syntax since it feels kinda Lispy). This is called tokenization, and for now we&#39;ll do it by hand. The second argument to the DFSA constructor is the symbol for the initial state, and the third one is the set of final states. We won&#39;t worry about the actual implementation yet, as we want to let this sink in for a bit.&lt;br /&gt;&lt;br /&gt;The next article in this series will be to create a DSL for setting up the automaton, then I&#39;ll write up on non-deterministic automatons and pushdown automatons. I&#39;ll also show more actual code (I&#39;ll create a GitHub repos for the automaton library). Possibly I&#39;ll get to transducers as well. If you have any suggestions, please leave a comment or ship me an e-mail.</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/7255470344249657233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/7255470344249657233' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/7255470344249657233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/7255470344249657233'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2008/10/experimenting-with-automatons-in-ruby.html' title='Experimenting with automatons in Ruby, part 1'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-819509467746034337</id><published>2008-08-09T03:01:00.004+02:00</published><updated>2008-10-27T08:03:14.631+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="git"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Use your .gitignore as the ignore pattern for echoe</title><content type='html'>&lt;a href=&quot;http://blog.evanweaver.com/articles/2007/01/10/if-you-dont-want-to-hoe-echoe/&quot;&gt;Echoe&lt;/a&gt; is a library for quickly creating gems in Ruby.  I  I&#39;ve hacked up a quick patch for it so you can use your .gitignore file as the manifest ignore pattern. I found it boring to re-list the ignore stuff since it in 99% of the cases (at least for me) already is present in .gitignore.&lt;br /&gt;&lt;br /&gt;I&#39;m sure that the patch doesn&#39;t work perfectly though. I know there is differences between the globbing syntax in gitignore and in Ruby&#39;s File#fnmatch - the latter is stricter. But it still works perfectly for the (small) projects I&#39;ve tried it on.&lt;br /&gt;&lt;br /&gt;Usage goes down like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;Echoe.new(PROJECT) do |p|&lt;br /&gt;...&lt;br /&gt;p.ignore_pattern = FileList[&quot;.gitignore&quot;]&lt;br /&gt;...&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Grab it from my fork on &lt;a href=&quot;http://github.com/Chrononaut/echoe/tree/master&quot;&gt;GitHub&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;UPDATE: &lt;/span&gt;This feature is now included in echoe 3.0.2!</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/819509467746034337/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/819509467746034337' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/819509467746034337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/819509467746034337'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2008/08/use-your-gitignore-as-ignore-pattern.html' title='Use your .gitignore as the ignore pattern for echoe'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-6026937176035162854</id><published>2008-07-21T08:29:00.005+02:00</published><updated>2008-07-21T08:45:00.324+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="php"/><category scheme="http://www.blogger.com/atom/ns#" term="postgresql"/><title type='text'>The lack of Database Abstraction in PHP</title><content type='html'>Unfortunately, almost none of the most popular PHP software supports other databases than MySQL (with &lt;a href=&quot;http://www.mediawiki.org/&quot;&gt;MediaWiki&lt;/a&gt; being a notable exception - it supports Postgres). When you&#39;re used to programming in Ruby, multi-db compatibility is something you just take for granted after a while, because of the excellent ActiveRecord and &lt;a href=&quot;http://datamapper.org/&quot;&gt;DataMapper&lt;/a&gt; projects. In PHP however, this is a real deal breaker. I don&#39;t know if its a cultural problem or a library problem. I did look at &lt;a href=&quot;http://propel.phpdb.org/trac/&quot;&gt;Propel&lt;/a&gt; some time ago, but honestly the Java-esque XML configuration and over-complex API turned me off real quick. If someone could come up with something better, maybe even &lt;a href=&quot;http://wordpress.org/&quot;&gt;WordPress&lt;/a&gt; will support SQLite and PostgreSQL one day...</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/6026937176035162854/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/6026937176035162854' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/6026937176035162854'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/6026937176035162854'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2008/07/lack-of-database-abstraction-in-php.html' title='The lack of Database Abstraction in PHP'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-7675031087270889339</id><published>2008-06-13T17:16:00.003+02:00</published><updated>2008-06-13T17:25:28.026+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="shellscript"/><category scheme="http://www.blogger.com/atom/ns#" term="zsh"/><title type='text'>Zshfully Yours, Gem Shortcuts</title><content type='html'>Stephen Celis provided a slick bash-method for quickly opening and browsing RDocs, over at &lt;a href=&quot;http://stephencelis.com/archive/2008/6/bashfully-yours-gem-shortcuts&quot;&gt;his blog&lt;/a&gt;. I have merely ported the function to zsh. As a slight modification, $BROWSER and $BROWSER_OPTIONS are used instead of just open, so it works cross platform. The code:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;gemdoc() {&lt;br /&gt;  local gemdir=`gem env gemdir`&lt;br /&gt;  $BROWSER $BROWSER_OPTIONS $gemdir/doc/`ls $gemdir/doc/ | grep $1 | sort | tail -1`/rdoc/index.html&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;_gemdoc() {&lt;br /&gt;  compadd $(ls `gem env gemdir`/doc)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;compdef _gemdoc gemdoc&lt;br /&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/7675031087270889339/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/7675031087270889339' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/7675031087270889339'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/7675031087270889339'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2008/06/zshfully-yours-gem-shortcuts.html' title='Zshfully Yours, Gem Shortcuts'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-1052173600043419830</id><published>2008-06-06T00:06:00.002+02:00</published><updated>2008-06-06T00:21:15.694+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="arch"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><title type='text'>Arch Linux: Changing Gnome&#39;s default browser</title><content type='html'>I&#39;m a big fan of &lt;a href=&quot;http://icculus.org/openbox/index.php/Main_Page&quot;&gt;OpenBox,&lt;/a&gt; but out of habit I use a couple of Gnome apps. Most notably Gnome Terminal. For some reason, when I clicked URLs in the terminal they opened in Epiphany. Firefox is still my main browser, so I wanted to change that. I solved it like this:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;sudo pacman -Sy gconf-editor&lt;/li&gt;&lt;li&gt;Run gconf-editor , edit the /desktop/gnome/url-handlers/http(s) keys to your liking. In my case &quot;firefox %s&quot;.&lt;/li&gt;&lt;/ol&gt;That should be it!</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/1052173600043419830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/1052173600043419830' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/1052173600043419830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/1052173600043419830'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2008/06/arch-linux-changing-gnomes-default.html' title='Arch Linux: Changing Gnome&#39;s default browser'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-5720792262753635928</id><published>2008-06-04T19:59:00.002+02:00</published><updated>2008-06-04T20:19:18.409+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="arch"/><category scheme="http://www.blogger.com/atom/ns#" term="shellscript"/><category scheme="http://www.blogger.com/atom/ns#" term="zsh"/><title type='text'>Script for removing orphans in Arch Linux</title><content type='html'>Shell scripting is fun, so I created a small function that removes all orphaned packages as reported by &lt;a href=&quot;http://wiki.archlinux.org/index.php/Pacman&quot;&gt;Pacman&lt;/a&gt;. It calls itself recursively if removing the current orphans revealed any new ones. Tested with &lt;a href=&quot;http://zsh.dotsrc.org/&quot;&gt;zsh&lt;/a&gt; since that is &lt;strike&gt;my personal preference&lt;/strike&gt; the best shell around :) - but it probably runs under bash as well. Here is the code:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;remove_orphans() {&lt;br /&gt; for pkg in `pacman -Qdt|awk -F &#39; &#39; &#39;{ printf(&quot;%s\n&quot;, $1) }&#39;`; do&lt;br /&gt;   sudo pacman -R $pkg&lt;br /&gt; done&lt;br /&gt; if [ `pacman -Qdt|wc -l` -gt 0 ]; then remove_orphans; fi&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/5720792262753635928/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/5720792262753635928' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/5720792262753635928'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/5720792262753635928'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2008/06/script-for-removing-orphans-in-arch.html' title='Script for removing orphans in Arch Linux'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-8192893680209523132</id><published>2008-06-03T18:54:00.002+02:00</published><updated>2008-06-03T19:01:16.806+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="arch"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="netbeans"/><title type='text'>Arch Linux: Alt+gr not working in Java apps</title><content type='html'>I got quite confused when my good old trusty Alt+gr key did not work in NetBeans (since I use Norwegian keyboard layout, this key is essential for progamming). The key worked everywhere except in Java apps, actually. Luckily, I figured out how to fix it:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Install scim.&lt;/li&gt;&lt;li&gt;Add your locale to the scim global config (/etc/scim/global).&lt;/li&gt;&lt;li&gt;Start scim from your xinitrc.&lt;/li&gt;&lt;li&gt;Restart your X server - it now should work!&lt;/li&gt;&lt;/ol&gt;For good measure, here&#39;s my .xinitrc file:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;# SCIM&lt;br /&gt;export XMODIFIERS=&#39;@im=SCIM&#39;&lt;br /&gt;export GTK_IM_MODULE=&quot;scim&quot;&lt;br /&gt;export XIM_PROGRAM=&quot;scim -d&quot;&lt;br /&gt;export QT_IM_MODULE=&quot;scim&quot;&lt;br /&gt;scim -d&lt;br /&gt;# OPENBOX&lt;br /&gt;exec openbox-session&lt;br /&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/8192893680209523132/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/8192893680209523132' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/8192893680209523132'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/8192893680209523132'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2008/06/arch-linux-altgr-not-working-in-java.html' title='Arch Linux: Alt+gr not working in Java apps'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-1296555258769392380</id><published>2008-06-02T21:18:00.003+02:00</published><updated>2008-06-03T19:01:51.024+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="arch"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><title type='text'>Arch Linux: First impressions</title><content type='html'>So, I finally got fed up with Ubuntu. I really wanted to use FreeBSD again - but unfortunately the hardware in this box is not compatible. Arch Linux looked like a decent alternative so I downloaded the  2007.08-2 image and started installing. Misfortune struck again as I had to spend a couple of hours  trying to get wireless working, but everything worked well as soon as I switched to the 2008.04-RC image. I wonder why they don&#39;t link to the RC image on the &lt;a href=&quot;http://archlinux.org/download/&quot;&gt;&quot;Get Arch&quot;&lt;/a&gt; page.&lt;br /&gt;&lt;br /&gt;After some configuration I ended up with a really slick system - It&#39;s amazing how much faster stuff runs on &lt;a href=&quot;http://icculus.org/openbox/index.php/Main_Page&quot;&gt;OpenBox&lt;/a&gt;! Also, the BSD inspired rc.conf and init system made my day. The only real problem I encountered was when I tried to install an older version of a library. Pacman (Arch&#39;s package manager) &lt;span style=&quot;font-style: italic;&quot;&gt;doesn&#39;t support this&lt;/span&gt;. I consider this to be a flaw in the package manager (which all over feels immature compared to apt or BSD ports), and I predict the devs will realize this sooner or later - even though they currently consider it to be a &quot;feature&quot;.&lt;br /&gt;&lt;br /&gt;I find it amusing how things tend to move in cycles. When I started out with Linux ~8 years ago Slackware was the coolest thing around. Then we somehow ended up with Ubuntu. And now the &quot;KISS&quot;-distros are turning into the hippest kids on the block again. If you&#39;re fed up with the bloat, give Arch a try. :)</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/1296555258769392380/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/1296555258769392380' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/1296555258769392380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/1296555258769392380'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2008/06/arch-linux-first-impressions.html' title='Arch Linux: First impressions'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-5044384270765274681</id><published>2008-05-18T22:33:00.002+02:00</published><updated>2008-05-18T22:39:12.570+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><title type='text'>(str)tr for JavaScript</title><content type='html'>I couldn&#39;t find a function resembling Ruby&#39;s tr or PHP&#39;s strtr in JavaScript, so I created one. Here&#39;s the code:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;function tr(str, from, to) {&lt;br /&gt;    var subst;&lt;br /&gt;    for (i = 0; i &lt; from.length; i++) {&lt;br /&gt;        subst = (to[i]) ? to[i] : to[to.length-1];&lt;br /&gt;        str = str.replace(new RegExp(str[str.indexOf(from[i])], &#39;g&#39;), subst);&lt;br /&gt;    }&lt;br /&gt;    return str;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/5044384270765274681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/5044384270765274681' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/5044384270765274681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/5044384270765274681'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2008/05/strtr-for-javascript.html' title='(str)tr for JavaScript'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-4765949337051919624</id><published>2008-05-06T12:57:00.002+02:00</published><updated>2008-05-06T13:03:36.860+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="java"/><title type='text'>Java oddity</title><content type='html'>I really don&#39;t like the fact that you can run static class-methods from an object in Java. In effect, &lt;code&gt;object.staticMethod();&lt;/code&gt; gets translated into something like &lt;code&gt;object.getClass().staticMethod();&lt;/code&gt;. AFAIK, no other language has this &quot;feature&quot;. Is there any reason behind this madness?</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/4765949337051919624/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/4765949337051919624' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/4765949337051919624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/4765949337051919624'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2008/05/java-oddity.html' title='Java oddity'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-2459396431446992158</id><published>2008-01-15T00:07:00.000+01:00</published><updated>2008-01-15T00:11:31.760+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="nginx"/><title type='text'>Nginx 0.5.35 released</title><content type='html'>I don&#39;t know of any feeds that track nginx releases, so this is just a heads up for people that missed the release of nginx 0.5.35. Release notes:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    *) Change: now the ngx_http_userid_module adds start time microseconds &lt;br /&gt;       to the cookie field contains a pid value.&lt;br /&gt;&lt;br /&gt;    *) Change: now the uname(2) is used on Linux instead of procfs.&lt;br /&gt;       Thanks to Ilya Novikov.&lt;br /&gt;&lt;br /&gt;    *) Feature: the &quot;If-Range&quot; request header line support.&lt;br /&gt;       Thanks to Alexander V. Inyukhin.&lt;br /&gt;&lt;br /&gt;    *) Bugfix: in HTTPS mode requests might fail with the &quot;bad write retry&quot; &lt;br /&gt;       error; bug appeared in 0.5.13.&lt;br /&gt;&lt;br /&gt;    *) Bugfix: the STARTTLS in SMTP mode did not work.&lt;br /&gt;       Thanks to Oleg Motienko.&lt;br /&gt;&lt;br /&gt;    *) Bugfix: large_client_header_buffers did not freed before going to &lt;br /&gt;       keep-alive state.&lt;br /&gt;       Thanks to Olexander Shtepa.&lt;br /&gt;&lt;br /&gt;    *) Bugfix: the &quot;limit_rate&quot; directive did not allow to use full &lt;br /&gt;       throughput, even if limit value was very high.&lt;br /&gt;&lt;br /&gt;    *) Bugfix: the $status variable was equal to 0 if a proxied server &lt;br /&gt;       returned response in HTTP/0.9 version.&lt;br /&gt;&lt;br /&gt;    *) Bugfix: if the &quot;?&quot; character was in a &quot;error_page&quot; directive, then &lt;br /&gt;       it was escaped in a proxied request; bug appeared in 0.5.32.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now go and upgrade your servers!</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/2459396431446992158/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/2459396431446992158' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/2459396431446992158'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/2459396431446992158'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2008/01/nginx-053-released.html' title='Nginx 0.5.35 released'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-839525755319700495</id><published>2007-12-06T14:30:00.000+01:00</published><updated>2007-12-06T16:04:57.488+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="rant"/><title type='text'>Public domain?</title><content type='html'>I&#39;m currently reading &quot;&lt;a href=&quot;http://www.amazon.co.uk/Fundamentals-Database-Systems-Ramez-Elmasri/dp/032141506X/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1196951465&amp;amp;sr=8-1&quot;&gt;Fundamentals of database systems&lt;/a&gt;&quot; by Elmasri &amp;amp; Navathe as part of the curriculum in a database course at my University. The book overall isn&#39;t all that bad, but their take on open source databases is really horrid. Quote:&lt;br /&gt;&lt;blockquote&gt;&quot;Personal computers and database system-like software products such as Excel, Visual FoxPro, Access (Microsoft), or SQL Anywhere (Sybase), and public domain products such as MySQL and PostgreSQL are being heavily utilized by users who previously belonged to the category of casual and occasional database users.&quot;&lt;/blockquote&gt;Wow. Public domain? I think they should at least invest two minutes to read up about open source software and open source licences, before they wrote about it. Excel and PostgreSQL in the same sentence? That&#39;s pretty fucked up if you ask me. And they have this highly patronizing tone which goes something like &quot;commercial dbms &gt; *, lol!&quot;. Someone should ship the authors a copy of PostgreSQL, I&#39;m sure they would&#39;ve been amazed if they tried it.</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/839525755319700495/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/839525755319700495' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/839525755319700495'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/839525755319700495'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2007/12/public-domain.html' title='Public domain?'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-4035986211094640133</id><published>2007-11-24T18:41:00.000+01:00</published><updated>2007-11-25T02:26:00.853+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><title type='text'>Easiest way to check IE version with JavaScript</title><content type='html'>Alright, so I needed a easy way to execute custom JavaScript for clients using versions of IE lower than 7. All the scripts Google showed me were really huge and quite outdated. So I took what I found, and turned it into something really lightweight. Note that this is just a quick hack, but so far it seems to be enough for my needs.&lt;br /&gt;&lt;br /&gt;Code:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;var Browser = {&lt;br /&gt;  Version: function() {&lt;br /&gt;    var version = 999; // we assume a sane browser&lt;br /&gt;    if (navigator.appVersion.indexOf(&quot;MSIE&quot;) != -1)&lt;br /&gt;      // bah, IE again, lets downgrade version number&lt;br /&gt;      version = parseFloat(navigator.appVersion.split(&quot;MSIE&quot;)[1]);&lt;br /&gt;    return version;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Which enables me to do stuff like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;if (Browser.Version() &lt; 7) {&lt;br /&gt;  ... // if client is using IE6 or lower, run this code&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;..or this:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;if (Browser.Version() &gt;= 7) {&lt;br /&gt;  ... // if client is using IE7 or a sane browser, run this code&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It will simply return 999 if the browser is non-IE. Is it safe to assume that &lt;code&gt;navigator.appVersion&lt;/code&gt; always will contain &quot;MSIE&quot; in uppercase?</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/4035986211094640133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/4035986211094640133' title='25 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/4035986211094640133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/4035986211094640133'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2007/11/easiest-way-to-check-ie-version-with.html' title='Easiest way to check IE version with JavaScript'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>25</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-479026636898519262</id><published>2007-11-15T10:27:00.000+01:00</published><updated>2007-11-15T10:32:54.598+01:00</updated><title type='text'>Quote of the year</title><content type='html'>&lt;blockquote&gt;&quot;I get a little paranoid when stuff Just Works though so it&#39;s a good thing 99.9% of our customers run Internet Explorer. I&#39;m pretty hard on IE but I will admit to at least one thing it does really well: destroying any sense of pleasantness a developer may feel when building web applications.&quot;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;So true. Taken from &lt;a href=&quot;http://tomayko.com/weblog/2006/12/23/parallels-makes-ie-suck-less&quot;&gt;this post&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/479026636898519262/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/479026636898519262' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/479026636898519262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/479026636898519262'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2007/11/quote-of-year.html' title='Quote of the year'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-6836403197623402109</id><published>2007-10-31T01:52:00.001+01:00</published><updated>2007-10-31T01:52:53.853+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="leopard"/><category scheme="http://www.blogger.com/atom/ns#" term="osx"/><title type='text'>Liberate yourself from the evil transparent menubar</title><content type='html'>In Leopard, of course. Get it &lt;a href=&quot;http://www.eternalstorms.at/utilities/opaquemenubar/&quot;&gt;here&lt;/a&gt;!</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/6836403197623402109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/6836403197623402109' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/6836403197623402109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/6836403197623402109'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2007/10/liberate-yourself-from-evil-transparent.html' title='Liberate yourself from the evil transparent menubar'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-4540854247170395842</id><published>2007-10-31T00:36:00.000+01:00</published><updated>2007-10-31T15:02:27.265+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="git"/><category scheme="http://www.blogger.com/atom/ns#" term="pm"/><title type='text'>Using Git with Lighthouse</title><content type='html'>&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://2.bp.blogspot.com/_sK2umZC9dok/RyfAbNoUhjI/AAAAAAAAAAM/pejsXhXbj8E/s1600-h/screenshot2.jpg&quot;&gt;&lt;img style=&quot;float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;&quot; src=&quot;http://2.bp.blogspot.com/_sK2umZC9dok/RyfAbNoUhjI/AAAAAAAAAAM/pejsXhXbj8E/s320/screenshot2.jpg&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5127278274532378162&quot; /&gt;&lt;/a&gt;I wanted to set up &lt;a href=&quot;http://git.or.cz/&quot;&gt;Git&lt;/a&gt; integration with &lt;a href=&quot;http://www.lighthouseapp.com/&quot;&gt;Lighthouse&lt;/a&gt;. The requirements for this was a bit different from the regular SVN integration, since in SVN every commit goes to a central repository, while Git is distributed. For the projects we wanted to integrate with Lighthouse, we use a shared Git repository which acts like the &quot;main&quot; repos. So when our local commits and changes gets pushed to the main repos, we want it to send a new changeset to Lighthouse, which should include the commit messages of all the new revisions since the previous push. A bit more complex than the Svn use case, but luckily Git provides some nice tools that made it quite easy. Google told me that &lt;a href=&quot;http://forum.activereload.net/forums/6/topics/320&quot;&gt;some other guy made something similar a few days ago&lt;/a&gt;. However, his solution uses a post-commit hook, and thus sends every single commit to Lighthouse. Which wasn&#39;t acceptable for us, since we do a lot of small atomic commits localy. And it works against one of the nicest Git features: quick and easy branches for experimenting, since all the experimental commits would have been exposed to Lighthouse and filled up the overview screen. Summed up, we wanted to be able to make multiple local commits, and then send them as a &quot;revision bundle&quot; to Lighthouse and the main repos.&lt;br /&gt;&lt;br /&gt;I solved this by setting up a both post- and pre-receive hooks on the main repos. I suspect that the pre-receive hook can be avoided, but I did the simplest thing that could possibly work. The pre-receive hook saves the current (pre-push) revision to a temporary text file, so it can be used by the post-receive hook. The post-receive hook runs a Ruby script. Most of it is taken from the script in the earlier link. The coolest line goes like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettycode&quot;&gt;&lt;br /&gt;commit_log = `#{GIT} rev-list --pretty=short &quot;#{oldrev}..#{newrev}&quot; | git shortlog`&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It sums up each authors commits, and shows the commit messages from each of the commits. (You can see this in action on the screenshot at the top of this post) Perfect. The script isn&#39;t as complete or elegant as it should be, but it works for now. I will edit it if I come up with something better. If anyone else makes improvements to this script I would love to hear about it (please leave a comment here, or ship me an email)!&lt;br /&gt;&lt;br /&gt;Pre-receive hook: &lt;a href=&quot;http://pastie.caboo.se/112536&quot;&gt;http://pastie.caboo.se/112536&lt;/a&gt;&lt;br /&gt;Post-receive hook: &lt;a href=&quot;http://pastie.caboo.se/112535&quot;&gt;http://pastie.caboo.se/112535&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/4540854247170395842/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/4540854247170395842' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/4540854247170395842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/4540854247170395842'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2007/10/using-git-with-lighthouse.html' title='Using Git with Lighthouse'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_sK2umZC9dok/RyfAbNoUhjI/AAAAAAAAAAM/pejsXhXbj8E/s72-c/screenshot2.jpg" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-3871478094988848645</id><published>2007-10-30T23:57:00.001+01:00</published><updated>2007-10-30T23:57:43.437+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="git"/><category scheme="http://www.blogger.com/atom/ns#" term="pm"/><title type='text'>Choosing a project management system</title><content type='html'>Last week we were starting up a couple of small projects for some clients. I saw that as a great opportunity to review our choice of project management system. We were currently using &lt;a href=&quot;http://retrospectiva.org/&quot;&gt;Retrospectiva&lt;/a&gt;, a open source rails project. It does the job okay, but it isn&#39;t exactly very pretty, and the usability kinda sucks. This is supposed to get &lt;a href=&quot;http://retrospectiva.org/blog/15&quot;&gt;improved&lt;/a&gt;. Anyway, letting clients into Retrospectiva just didn&#39;t feel right.     Oh, and currently Retrospectiva only supports subversion. And since we&#39;ve transitioned completely to &lt;a href=&quot;http://git.or.cz/&quot;&gt;Git&lt;/a&gt;, thats a problem for us.&lt;br /&gt;&lt;br /&gt;So I went looking for a substitute. I looked a bit at a new Rails app named &lt;a href=&quot;http://whodo.es/home&quot;&gt;WhoDoes&lt;/a&gt;. Its pretty cool, and I really wanted to like it since its extremely cheap compared to &lt;a href=&quot;http://lighthouseapp.com/&quot;&gt;Lighthouse&lt;/a&gt;. It wasn&#39;t quite &quot;it&quot; tho. The biggest problem: it lacks a very basic PM requirement: knowledge capture. You really need to have an external wiki or something, since it doesn&#39;t even have simple pages/messages like Lighthouse. But I bet this app will improve in the future, so it&#39;s something to look out for. So we ended up with Lighthouse, which has a really really beautiful UI. And it&#39;s dead easy to use: everything is a ticket. Client-safe, and a whole lot more fun to use than Retrospectiva! We even got Git integration working, which I will write about next.</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/3871478094988848645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/3871478094988848645' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/3871478094988848645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/3871478094988848645'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2007/10/choosing-project-management-system.html' title='Choosing a project management system'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-3372406226902620705</id><published>2007-10-27T21:51:00.000+02:00</published><updated>2007-10-28T16:48:52.163+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="leopard"/><category scheme="http://www.blogger.com/atom/ns#" term="osx"/><title type='text'>Leopard: First impressions</title><content type='html'>Alright, so Leopard has arrived! On Friday I wiped the harddrive of my MacBook and eagerly installed my new OS. I this post I will present some of my thoughts about it, based a couple of days usage.&lt;br /&gt;&lt;br /&gt;The good:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It&#39;s very convenient that so much quality software ships with the OS. Built-in svn is nice even tho I prefer Git, since a lot of projects use it. I really wanted the Ruby support to be good. But it turned out that I pretty quickly had to change it with a custom install via MacPorts. The built in Ruby simply refused to install the ruby-postgres gem. I gave the exact same params to extconf.rb with the custom Ruby in place, and it just worked. I had to install PostgreSQL 8.2 from source by the way, since the port for it is broken at the moment. Its still very nice that the OS ships with a up to date Ruby tho.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Spaces are cool, even tho I don&#39;t like everything about their behavior. I &lt;span style=&quot;font-style: italic;&quot;&gt;really&lt;/span&gt; want to disable the animated gliding that occurs when you change between spaces.&lt;/li&gt;&lt;li&gt;The new finder feels much better to use.&lt;/li&gt;&lt;li&gt;Safari have gotten a bunch of updates as well, I especially like the new search function.&lt;/li&gt;&lt;li&gt;Its faster than Tiger.&lt;/li&gt;&lt;/ul&gt;The bad:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Transparency which you cant turn off. God, I &lt;span style=&quot;font-style: italic;&quot;&gt;hate&lt;/span&gt; transparent windows.&lt;/li&gt;&lt;li&gt;The new terminal isn&#39;t as good as expected. I switched back to iTerm pretty quickly.&lt;/li&gt;&lt;li&gt;The new dock is way too heavy on the eye candy for my taste.&lt;/li&gt;&lt;/ul&gt;The ugly:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A lot of port breakage, but thats to be expected I guess. And most of them get fixed really quick.&lt;/li&gt;&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/3372406226902620705/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/3372406226902620705' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/3372406226902620705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/3372406226902620705'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2007/10/leopard-first-impressions.html' title='Leopard: First impressions'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-8860923856824342981</id><published>2007-10-25T13:43:00.000+02:00</published><updated>2007-10-25T14:12:45.796+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bitswiki"/><category scheme="http://www.blogger.com/atom/ns#" term="rails"/><title type='text'>A note on UTC support in Rails</title><content type='html'>I was doing some work on &lt;a href=&quot;http://code.google.com/p/bitswiki/&quot;&gt;Bitswiki&lt;/a&gt; yesterday, and figured it would be a good idea to store time data in UTC. I thought this was as easy as uncommenting the &quot;config.active_record.default_timezone = :utc&quot; line in environment.rb, but this was not the case. The models&#39; created_at fields still got populated with my local timezone, even tho Rails claimed it was in UTC. I was quite puzzled. It turned out that it was as easy as adding this to environment.rb (or into its own file in /config/initializers):&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;# Make Time.now return time in UTC&lt;br /&gt;ENV[&#39;TZ&#39;] = &#39;UTC&#39;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Maybe this should have been set implicitly by the default_timezone setting, as you probably want the two in conjunction anyway?</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/8860923856824342981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/8860923856824342981' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/8860923856824342981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/8860923856824342981'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2007/10/note-on-utc-support-in-rails.html' title='A note on UTC support in Rails'/><author><name>Bjørn Arild Mæland</name><uri>http://www.blogger.com/profile/18215577894638007872</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7692259130661310484.post-5674691904659490784</id><published>2007-10-17T20:19:00.000+02:00</published><updated>2007-10-30T12:07:20.323+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="rails"/><category scheme="http://www.blogger.com/atom/ns#" term="tutorials"/><title type='text'>Creating a simple news publishing system in Rails 2.0</title><content type='html'>In this tutorial we will create a simple news publishing system. We&#39;ll also take a look at some of the new Rails 2.0 features, like namespaced routes. Note that I wont do any testing in this tutorial, due to the limited scope. However, I recommend downloading the latest RSpec screencasts over at &lt;a href=&quot;http://smartic.us/&quot;&gt;http://smartic.us/&lt;/a&gt;, to keep up-to-date on the latest testing techniques. Please note that this is my first attempt at writing a tutorial of this kind, so bear with me. Hopefully my writing will improve over time.&lt;br /&gt;&lt;br /&gt;As usual, we&#39;ll start with creating a new project (I assume that you have Rails 1.2.5 installed). You might want to freeze to the latest edge version, but note that this is not required for completing this tutorial. Type this into your shell of choice:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;rails newsmachine&lt;br /&gt;rake rails:freeze:edge (optional)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now we&#39;re ready to roll. Lets set up our database and create some models:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;cd newsmachine&lt;br /&gt;./script/generate model newsitem header:string author:string body:text&lt;br /&gt;rake db:create:all&lt;br /&gt;rake db:migrate&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that in Rails 2.0 we don&#39;t have to specify the created_at/updated_at fields; they are automatically created for us by default. Nice. The new database creation raketasks are also very handy, but note that you probably have to do a little editing on your database.yml file first. I run PostgreSQL, so I had to change the adapter setting. Now we have a database ready, so lets try to create a admin interface. We will use the new namespace routing for this purpose.&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;./script/generate controller &#39;admin/newsitems&#39; index new create&lt;br /&gt;./script/generate controller newsitems index&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that we create two different NewsItems controllers, with two different responsibilities. This helps us partition our code nicely into two clearly defined places. We avoid the &quot;one controller to rule them all&quot;-syndrome, since we get one controller for public consumption and one for admin-only stuff. Now lets delete the public/index.html file, and boot up our server:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;rm public/index.html&lt;br /&gt;./script/server&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Lets add some routes into our routes.rb file:&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;map.root :controller =&gt; &quot;newsitems&quot;&lt;br /&gt;&lt;br /&gt;map.namespace :admin do |admin|&lt;br /&gt;  admin.resources :newsitems&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We are now ready to start writing some actual code. The first thing that we should be able to do, is creating new news items. Head to app/controllers/admin/newsitems_controller and enter the following:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;def index&lt;br /&gt; @newsitems = Newsitem.find(:all)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def new&lt;br /&gt; @newsitem = Newsitem.new&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def create&lt;br /&gt; @newsitem = Newsitem.new(params[:newsitem])&lt;br /&gt; @newsitem.save!&lt;br /&gt; redirect_to :action =&gt; :index&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is pretty basic, but good enough for our example. Now over to index.html.erb, still within the admin scope:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;&amp;lt;h1&amp;gt;Administration&amp;lt;/h1&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;%= link_to &amp;quot;Create new news item&amp;quot;, new_admin_newsitem_url %&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;hr /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;ol&amp;gt;&lt;br /&gt;&amp;lt;% @newsitems.each do |n| %&amp;gt;&lt;br /&gt;&amp;lt;li&amp;gt;&amp;lt;%= n.header %&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;lt;% end %&amp;gt;&lt;br /&gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Try this out by putting your browser over to http://localhost:3000/admin/newsitems/. If it works: yay! If not, maybe you missed something. Or maybe my explanations just sucks. Let me know, leave a comment. Now lets create some news items. new.html.erb:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;&amp;lt;h1&amp;gt;Create a new news item&amp;lt;/h1&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;% form_for ([:admin, @newsitem]) do |f| %&gt;&lt;br /&gt;&amp;lt;%= label(:newsitem, :header, &quot;Header:&quot;) %&gt;&lt;br /&gt;&amp;lt;%= f.text_field :header %&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;%= label(:newsitem, :author, &quot;Author:&quot;) %&gt;&lt;br /&gt;&amp;lt;%= f.text_field :author %&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;%= label(:newsitem, :body, &quot;Body:&quot;) %&gt;&lt;br /&gt;&amp;lt;%= f.text_area :body %&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;%= submit_tag &quot;Create!&quot; %&gt;&lt;br /&gt;&amp;lt;% end %&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The new form_for functionality is really nice. When we give it a ActiveRecord-object, it automatically identifies the correct paths etc. As you would expect, it also supports namespacing when we pass it an array. Another sleek 2.0 feature is builtin http-auth. Yep, plain old simple basic HTTP-authentication. Its a perfect fit for password-protecting small sites like this. First, add a before-filter to the admin controller (app/controllers/admin/newsitems_controller):&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;before_filter :authenticate&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then add the authenticate-method (put the code in as the last method in your controller):&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;private&lt;br /&gt;def authenticate&lt;br /&gt;authenticate_or_request_with_http_basic { |u, p| u == &quot;admin&quot; &amp;amp;&amp;amp; p == &quot;1234&quot; }&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;There you go, a fully functional login-system written in one single line of code. Not bad. Go ahead and test it!&lt;br /&gt;&lt;br /&gt;Ok, now we have a semi-functional admin interface without updating and deleting (but hey, at least we have auth!). Not bad! Lets implement a public view. Head over to index.erb.html for the regular newsitems controller (app/controllers/newsitems_controller):&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;&amp;lt;h1&amp;gt;Newsmachine gives you the news!&amp;lt;/h1&amp;gt;&lt;br /&gt;&amp;lt;%= render :partial =&gt; &quot;newsitem&quot;, :collection =&gt; @newsitems %&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We need a partial, so create a new file called _newsitem.html.erb and enter this:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;br /&gt;&amp;lt;div style=\&amp;quot;background-color: &amp;lt;%= cycle(&amp;quot;#aaa&amp;quot;, &amp;quot;#eee&amp;quot;)%&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;h2&amp;gt;&amp;lt;%= newsitem.header %&amp;gt;&amp;lt;/h2&amp;gt;&lt;br /&gt;&amp;lt;%= simple_format(newsitem.body) %&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;i&amp;gt;Written by &amp;lt;%= newsitem.author %&amp;gt; on &amp;lt;%= newsitem.created_at.to_s(:long) %&amp;gt;&amp;lt;/i&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Check it out, we now got a working site. There is a lot of stuff we could add from here, like Atom-feeds, image support, etc. I might write a part two of this, so any suggestions are greatly appreciated.</content><link rel='replies' type='application/atom+xml' href='http://obvcode.blogspot.com/feeds/5674691904659490784/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/7692259130661310484/5674691904659490784' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/5674691904659490784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7692259130661310484/posts/default/5674691904659490784'/><link rel='alternate' type='text/html' href='http://obvcode.blogspot.com/2007/10/creating-simple-news-publishing-system.html' title='Creating a simple news publishing system in Rails 2.0'/><author><name>Chrononaut</name><uri>http://www.blogger.com/profile/04406773041044462142</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bogus.uib.no/~bma025/nysveis.jpg'/></author><thr:total>4</thr:total></entry></feed>