<?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: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-6905430</id><updated>2011-12-28T19:39:26.701+02:00</updated><title type='text'>Farfetched Blog</title><subtitle type='html'>Mostly tech stuff</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default?start-index=101&amp;max-results=100'/><author><name>farfetched</name><uri>http://www.blogger.com/profile/18048140291179502673</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>131</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6905430.post-242718547875004703</id><published>2010-07-18T19:52:00.005+03:00</published><updated>2010-07-18T21:20:37.336+03:00</updated><title type='text'>Limited video for kids</title><content type='html'>Few parents can completely resist employing the video-as-babysitter.&lt;br /&gt;&lt;br /&gt;Parents that use linux can easily have their computer play just one movie with the following script:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;if [ "$1" ]&lt;br /&gt;then&lt;br /&gt; totem --fullscreen "$@" &amp;amp;&lt;br /&gt;fi&lt;br /&gt;xtrlock&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It starts playing the video(s) you want, but then prevents the kids from playing other videos or engaging in other unsupervised fiddling with the computer.&lt;br /&gt;&lt;br /&gt;xtrlock needs to be installed, easily for example from the standard Ubuntu Software Center in Ubuntu 10.04.&lt;br /&gt;&lt;br /&gt;You can create a Launcher in the panel for this script and a %F paramter, and drag videos to it from the File Browser.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-242718547875004703?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/242718547875004703/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=242718547875004703' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/242718547875004703'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/242718547875004703'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2010_07_01_archive.html#242718547875004703' title='Limited video for kids'/><author><name>farfetched</name><uri>http://www.blogger.com/profile/18048140291179502673</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-3686978044988323373</id><published>2009-07-05T05:30:00.004+03:00</published><updated>2009-07-05T06:37:17.335+03:00</updated><title type='text'>Google Strategy</title><content type='html'>Google has three main strategic product categories.&lt;br /&gt;&lt;br /&gt;Google has login-based services, like Gmail. These are most like other companies' internet services. They also have the most lock-in effect, though Google expends some effort to reduce it (for example allowing downloading and forwarding away email messages). These services enrich Google search data with user identity data.&lt;br /&gt;&lt;br /&gt;Google has internet growth services, like Chrome, Android, and News. In general, companies would like to reduce "substitutes" and increase "complements". Since Google has dominant marketshare of internet search, anything that increases internet use is a complement. Google can run ads on all of these services, and to varying degrees their users are more likely to be Google search users. Developing these services is also a little like Military Keynesianism. It gives Google engineers fun projects to work on, helping Google to get and keep top engineers, who help it to maintain its internet search dominance.&lt;br /&gt;&lt;br /&gt;Google has the internet. Since Google is the king of search, it will vigorously defend the internet against closed competing networks like the new social networks Facebook, LinkedIn, and Twitter. At least three distinct Google projects, though they also occupy the second category,  attempt to open up the social software world: Social Graph API, Open Social, and Wave. This makes Google "the good guys," because they'll always try to bring the fight to the open web, where they have the competitive advantage. Now, if Google didn't have a challenger, it might just release something into the first category (Orkut for example), but when they do have a competitor, everyone will end up being a lot better off. Wave promises to be a wonderful open technology, though it will put a lot of social software companies out of business.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-3686978044988323373?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/3686978044988323373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=3686978044988323373' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/3686978044988323373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/3686978044988323373'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2009_07_01_archive.html#3686978044988323373' title='Google Strategy'/><author><name>farfetched</name><uri>http://www.blogger.com/profile/18048140291179502673</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-5690702599463331572</id><published>2007-07-26T17:44:00.000+03:00</published><updated>2007-07-26T17:50:47.236+03:00</updated><title type='text'>Temporal and Bitemporal in One Sentence</title><content type='html'>Temporal database support allow efficiently answering questions like "What was the state of this entry on Monday?", and bitemporal database support, questions like "What was the state of his entry on Monday, if I had asked on Tuesday?"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-5690702599463331572?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/5690702599463331572/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=5690702599463331572' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/5690702599463331572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/5690702599463331572'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2007_07_01_archive.html#5690702599463331572' title='Temporal and Bitemporal in One Sentence'/><author><name>farfetched</name><uri>http://www.blogger.com/profile/18048140291179502673</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-5911234713930389497</id><published>2007-06-19T00:15:00.001+03:00</published><updated>2007-06-21T19:52:59.962+03:00</updated><title type='text'>Distributed Revision Control Yields Centralized Advantages</title><content type='html'>The new distributed revision control systems (DRCS) have some important advantages for traditional use, apart from the ability to commit without an internet connection.&lt;br /&gt;&lt;br /&gt;DRCS make code review much easier. Instead of using an entirely different system for managing the code review process, developers can check all of their un-reviewed changes into a branch, and merge changes as they get reviewed.&lt;br /&gt;&lt;br /&gt;DRCS can support graduated continuous integration. In sufficiently large projects, continuous integration can cause frequent build breakage.  Instead of having a single, volatile HEAD, subprojects can have their own independent integration branches, which they merge to the superproject integration branch at longer intervals.&lt;br /&gt;&lt;br /&gt;DRCS support "lines of development", or working on multiple independent features. With traditional RCS, once a feature is committed it becomes part of the blob, and may not easily be dealt with as a separate identity.&lt;br /&gt;&lt;br /&gt;The original motivation for DRCS was empowering decoupled open source contributors, so it's mildly ironic that this functionality should be so valuable for BigCo development as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-5911234713930389497?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/5911234713930389497/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=5911234713930389497' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/5911234713930389497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/5911234713930389497'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2007_06_01_archive.html#5911234713930389497' title='Distributed Revision Control Yields Centralized Advantages'/><author><name>farfetched</name><uri>http://www.blogger.com/profile/18048140291179502673</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-6357535833215483325</id><published>2007-05-30T18:58:00.001+03:00</published><updated>2007-05-30T20:25:08.216+03:00</updated><title type='text'>Libertarian OS</title><content type='html'>What would an operating system look like if it were designed to maximize freedom of development? Could we support a web of code to match the existing web of documents?&lt;br /&gt;&lt;br /&gt;It'd need:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A security framework&lt;/li&gt;&lt;li&gt;A dependency framework&lt;/li&gt;&lt;li&gt;No extra baggage&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;For security, programs would be extremely limited by default. They'd have no network, filesystem, or driver access. In order to do anything, they'd use APIs to&lt;br /&gt;&lt;ul&gt;&lt;li&gt;request reading or writing an existing file, selected by the user&lt;/li&gt;&lt;li&gt;request writing a new file&lt;br /&gt;&lt;/li&gt;&lt;li&gt;suggest a url to visit (optionally with post data).&lt;/li&gt;&lt;/ul&gt;This restricted behavior could safely allow running programs from even the least trusted sources. It's in the spirit of the "One laptop per child" project's revolutionary security model &lt;a href="http://wiki.laptop.org/go/Bitfrost"&gt;Bitfrost&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For dependencies, programs should specify urls (possibly self-certifying) of code that they depend on. All code could be cached locally or downloaded anew as desired. This is in the spirit of package management approaches without "side effects", like &lt;a href="http://nix.cs.uu.nl/"&gt;Nix&lt;/a&gt; and &lt;a href="http://0install.net/"&gt;Zero Install&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Once there's a sufficiently powerful dependency framework, we need not hard code any dependency on "standard software" like programming languages or gui toolkits. Programs could be transported in &lt;a href="http://llvm.org/"&gt;llvm&lt;/a&gt; bytecode.&lt;br /&gt;&lt;br /&gt;Implicitly trusted programs could be subject to phishing attacks just as websites currently are, so it would be desirable to have some sort of &lt;a href="http://www.skyhunter.com/marcs/petnames/IntroPetNames.html"&gt;petnames&lt;/a&gt; scheme, as well as a spoof-resistant UI for distinguishing programs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-6357535833215483325?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/6357535833215483325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=6357535833215483325' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/6357535833215483325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/6357535833215483325'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2007_05_01_archive.html#6357535833215483325' title='Libertarian OS'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-114282161284431967</id><published>2006-03-20T04:25:00.000+02:00</published><updated>2007-04-17T14:56:05.280+03:00</updated><title type='text'>Dinosaurs</title><content type='html'>My daughter, 4 years old: Daddy, are dinosaurs kosher?&lt;br /&gt;Me: No.&lt;br /&gt;My daughter: Not even little purple ones?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-114282161284431967?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/114282161284431967/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=114282161284431967' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/114282161284431967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/114282161284431967'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2006_03_01_archive.html#114282161284431967' title='Dinosaurs'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-113979932885574886</id><published>2006-02-13T04:16:00.000+02:00</published><updated>2006-02-13T04:56:56.596+02:00</updated><title type='text'>"Model" in MVC</title><content type='html'>The "Model" in Model-View-Controller architecture does &lt;em&gt;not&lt;/em&gt; refer to the application data model. It refers to the user interface model underlying each widget.&lt;br /&gt;&lt;br /&gt;Think of a text box that accepts date values. When the user types "2006-" and then pauses, the application doesn't yet have a date, so it doesn't have anything to put in its data model. The string "2006-" isn't stored somewhere in the view; it's stored in the model that backs the UI.&lt;br /&gt;&lt;br /&gt;To integrate your UI and your data model, you've got to use data binding code, like the &lt;a href="http://binding.dev.java.net/"&gt;jgoodies derived data binding code&lt;/a&gt;. It would  seem that MVC is more about UI framework implementation than interface.&lt;br /&gt;&lt;br /&gt;This explains why it's so cumbersome to switch between GUI widgets that would appear to represent the same data, like a select box and a group of radio buttons. It'd actually be against the MVC philosophy to support this, because it'd put artificial constraints on the respective widget models.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-113979932885574886?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/113979932885574886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=113979932885574886' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/113979932885574886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/113979932885574886'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2006_02_01_archive.html#113979932885574886' title='&quot;Model&quot; in MVC'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-113314164336601718</id><published>2005-11-28T03:17:00.000+02:00</published><updated>2007-01-22T22:15:48.703+02:00</updated><title type='text'>Consistent Types</title><content type='html'>There's a problem with inconsistent downcalling, which I've been hankering after for a bit, and which C# supports using the "&lt;a href="http://www.csharphelp.com/archives/archive4.html"&gt;new&lt;/a&gt;" keyword.&lt;br /&gt;&lt;br /&gt;The problem is that extension classes aren't really subtypes of extended classes anymore. They violate the &lt;a href="http://www.google.com/search?q=liskov+substitution+principle"&gt;Liskov Substitution Principle&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://farfetched.blogspot.com/2005/10/interfaces-for-encapsulation.html"&gt;Interfaces for encapsulation&lt;/a&gt; don't have this problem.&lt;br /&gt;&lt;br /&gt;(Though it'd be great if all languages had something like c#'s "override" keyword :).)&lt;br /&gt;&lt;br /&gt;UPDATE: I was mistaken. Different methods are called on an object in different static "contexts". For example:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;((ArtisticCowboy)joe).draw()&lt;/code&gt; runs one method, and&lt;br /&gt;&lt;code&gt;((Cowboy)joe).draw()&lt;/code&gt; runs another.&lt;br /&gt;&lt;br /&gt;This is what C# does, but I don't know if it's wise.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-113314164336601718?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/113314164336601718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=113314164336601718' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/113314164336601718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/113314164336601718'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_11_01_archive.html#113314164336601718' title='Consistent Types'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-113206170791953558</id><published>2005-11-17T15:27:00.000+02:00</published><updated>2005-11-17T23:46:27.983+02:00</updated><title type='text'>Future Refactoring UI</title><content type='html'>&lt;a href="http://www.refactoring.com/"&gt;Refactoring&lt;/a&gt; tools have a good case of &lt;a href="http://farfetched.blogspot.com/2005/11/everyone-is-like-me-and-bad-ui.html"&gt;programmer automorphism&lt;/a&gt;. These tools present silly lists of operations like "decompose conditional" and "encapsulate downcast."&lt;br /&gt;&lt;br /&gt;Really, automatic refactoring means the computer automatically makes all appropriate changes to accompany your change. It's all about moving and renaming. The tools should get rid of their complicated interfaces, and just support a mode "don't let me introduce any errors."&lt;br /&gt;&lt;br /&gt;Simple changes are easy to spot, but moves need to be done with Cut&amp;amp;Paste. For example, cutting from one place and pasting to another should fix up the pasted code to work in the new location. It should also fix up callers to the code at the original location so that they now call to the new location. The user shouldn't have to specify what type of code is moving, or what type of move it's making.&lt;br /&gt;&lt;br /&gt;If this could be made fast enough, programmers might want to always work this way. They'd just have to get in the habit of defining before using, and deleting usages before deleting definitions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-113206170791953558?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/113206170791953558/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=113206170791953558' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/113206170791953558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/113206170791953558'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_11_01_archive.html#113206170791953558' title='Future Refactoring UI'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-113226134288944692</id><published>2005-11-16T22:47:00.000+02:00</published><updated>2006-12-19T12:35:26.250+02:00</updated><title type='text'>Everyone is Like Me, and bad UI</title><content type='html'>User interfaces suck because programmers think users care about programs.&lt;br /&gt;&lt;br /&gt;Users do not care about programs. They think, "Just do it," and, "Get out of my face." Programmers love their programs, so they think everyone else does too. &lt;a href="http://www.joelonsoftware.com/uibook/chapters/fog0000000059.html"&gt;For example, they even write programs that hassle users to make implementation decisions.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In general, every person thinks that everyone is just like himself. Worse, every person thinks that everyone is like himself &lt;span style="font-style: italic;"&gt;right now&lt;/span&gt;. In the linked example, even the developers won't care about the implementation a year after they've coded.&lt;br /&gt;&lt;br /&gt;There is a word for this, though it seems seldom used: &lt;a href="http://machaut.uchicago.edu/cgi-bin/WEBSTER.sh?WORD=automorphic"&gt;automorphism&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-113226134288944692?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/113226134288944692/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=113226134288944692' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/113226134288944692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/113226134288944692'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_11_01_archive.html#113226134288944692' title='Everyone is Like Me, and bad UI'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-113069338818509647</id><published>2005-10-30T19:15:00.000+02:00</published><updated>2005-11-28T03:12:24.876+02:00</updated><title type='text'>Interfaces for Encapsulation</title><content type='html'>The python people &lt;a href="http://groups.google.com/group/comp.lang.python/msg/b977ed1312e10b21"&gt;haven't succinctly&lt;/a&gt; explained why python doesn't need "private", "protected", and "public". In one sentence, python doesn't need visibility modifiers becase...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;With sufficiently good refactoring support, encapsulation decisions don't affect code evolution.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Especially according to the XP design principle of &lt;a href="http://www.extremeprogramming.org/rules/collective.html"&gt;collective code ownership&lt;/a&gt;, it's easy to change callers of an interface when the interface changes. Though people reading the code will need to understand the changes, that's far more efficient than making artificial barriers to reuse. Encapsulation is powerful; forced encapsulation is onerous.&lt;br /&gt;&lt;br /&gt;This is true for a single organization, no matter how large its code base. Once code is "published" however, all bets are off. Code obviously can't be refactored across administrative boundaries. That being the case, we should care about &lt;a href="http://www.martinfowler.com/bliki/PublishedInterface.html"&gt;"published" instead of "public"&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For encapsulation of published code, separate interfaces are much more useful than visibility keywords. A class with a single public method is better represented by a separate interface containing a single method. When that interface is published, it never changes. In Java for example, the old interface could be kept in a separate jar file, which clients can continue using even after extended versions become available.&lt;br /&gt;&lt;br /&gt;More originally, we should allow extending code through an interface. Extending through an interface means that new code will never downcall to a method that isn't in the interface. This is an elegant solution to the fragile base class problem. (Someone recently showed me the cute new &lt;a href="http://www.csharphelp.com/archives/archive4.html"&gt;c# modifiers "new" and "override"&lt;/a&gt;. They protect against accidental downcalls, but they don't protect against replacment of methods called by collaborating classes.)&lt;br /&gt;&lt;br /&gt;Extending through an interface might also help with downcalling into unrelated methods with mixins and multiple inheritance. For example, to create an "artistic cowboy" with multiple inheritance, we'll inherit from "artist" and "cowboy". Though we want his artistic nature to be dominant, we don't want the cowboy method "drawAndShoot()" to downcall into the artist method "draw()". We can achieve this by extending artist through an interface that excludes "draw()".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-113069338818509647?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/113069338818509647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=113069338818509647' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/113069338818509647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/113069338818509647'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_10_01_archive.html#113069338818509647' title='Interfaces for Encapsulation'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-112802552087264760</id><published>2005-10-10T23:24:00.000+02:00</published><updated>2005-11-28T03:13:54.313+02:00</updated><title type='text'>DRM and the Little Guy</title><content type='html'>Maybe published work isn't best treated like property, but publishers will certainly fight to keep it that way. Physical media have been pretty good at proxying ownership of information. If general purpose computers can't do as well, then publishers will just adopt special purpose devices instead. Besides keeping consumption cumbersome and inefficient, this'll give binding power to corporations, but not to individuals.&lt;br /&gt;&lt;br /&gt;A general purpose DRM system can have a significant impact on society. If we're going to allow our computers to enter into contracts for us, we need some safeguards to avoid creating an &lt;a href="http://www.gnu.org/philosophy/right-to-read.html"&gt;information dystopia&lt;/a&gt;. The restrictions that we allow publishers to place on consumers should themselves be restricted. Generally, it shouldn't be possible for publishers to artbitrarily revoke access to their work. The set of digitally managed "rights" should be standard, easy to understand, and when possible, it should not require an ongoing relationship with the publisher.&lt;br /&gt;&lt;br /&gt;This task is more difficult from the technology standpoint, and it'll detract from the generality of the full DRM dream, but it could work.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-112802552087264760?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/112802552087264760/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=112802552087264760' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112802552087264760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112802552087264760'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_10_01_archive.html#112802552087264760' title='DRM and the Little Guy'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-112870892970615336</id><published>2005-10-07T21:13:00.000+03:00</published><updated>2006-06-07T04:00:40.483+03:00</updated><title type='text'>Money and Politics</title><content type='html'>&lt;a href="http://www.truthout.org/docs_2005/100605A.shtml"&gt;So long as the only means of engaging in political dialogue is through purchasing expensive television advertising, money will continue by one means or another to dominate American politics.&lt;br /&gt;--Al Gore&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-112870892970615336?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/112870892970615336/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=112870892970615336' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112870892970615336'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112870892970615336'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_10_01_archive.html#112870892970615336' title='Money and Politics'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-112869617455531799</id><published>2005-10-07T16:25:00.000+03:00</published><updated>2005-11-28T03:09:56.973+02:00</updated><title type='text'>Templates for Environments</title><content type='html'>(&lt;a href="http://www.blogger.com/post-edit.g?blogID=6905430&amp;postID=112869617455531799&amp;amp;quickEdit=true#surprising"&gt;The more surprising points are below.&lt;/a&gt;) Templates are useful for maintaining different deploy environments. Any large system needs to have a painless way to run in different environments, at least one "production" environment and one non-production environment. Examples of things that change between environments are: machine names, port numbers, database names.&lt;br /&gt;&lt;br /&gt;Manually switching code from one environment to another is tedious and error-prone, but not all tools can make it completely automatic in all cases (for example, enabling stored procedures to run against differently named databases). Theoretically, templates are also be useful for unifying environment configuration across languages, but they're really essential for languages that don't support the necessary abstraction.&lt;br /&gt;&lt;br /&gt;&lt;a name="surprising"&gt;&lt;/a&gt;Even on platforms that have the necessary support, environment management can get gnarly. For example, java has a great configuration mechanism in the form of "properties" and the improved "preferences". If different sets of property files are used, however, it's easy for the non-production property sets to get out-of-date. The solution is to ensure that only a small fraction of properties are environment specific, and put only those in a separate file.&lt;br /&gt;&lt;br /&gt;Templates generally break tools for live editing. For example, you can't "alter table" in a test database and easily have that change apply to your template. Or use a gui wizard to maintain templatized xml files for your application servers. We'd like to be able to "round-trip" templates, to be able to automatically generate templates from live files, as well as generate live files from templates. For this to be easy, the templates must meet two requirements:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;there must be a one-to-one correspondence between template variables and the values in the environment used to generate templates.&lt;/li&gt;   &lt;li&gt;template values must be unique.&lt;/li&gt; &lt;/ol&gt;An exampe of #1 is that a test environment must have as many different machine names as there are in production, even if those machine names are just aliases. Otherwise, the test environment will lose information.&lt;br /&gt;&lt;br /&gt;An example of #2 is that a machine can't be named "foo" because substituting a template variable like "@FOO_MACHINE@" will also substitute "buffoon" and "foot".&lt;br /&gt;&lt;br /&gt;Otherwise, the template generation will have to get complicated.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-112869617455531799?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/112869617455531799/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=112869617455531799' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112869617455531799'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112869617455531799'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_10_01_archive.html#112869617455531799' title='Templates for Environments'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-112360191947576660</id><published>2005-08-09T17:33:00.000+03:00</published><updated>2005-08-09T18:39:12.340+03:00</updated><title type='text'>Google Maps</title><content type='html'>Google maps should support saving and restoring locations.&lt;br /&gt;&lt;br /&gt;It should also support taking the union of the sets of locations created by different API sites.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-112360191947576660?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/112360191947576660/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=112360191947576660' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112360191947576660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112360191947576660'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_08_01_archive.html#112360191947576660' title='Google Maps'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-112308881563950473</id><published>2005-08-03T19:38:00.000+03:00</published><updated>2005-08-12T22:29:19.806+03:00</updated><title type='text'>Mixin Requirements</title><content type='html'>Proper mixins require two funny features:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;never down-calling into unrelated mixins&lt;/li&gt;   &lt;li&gt;a mechanism for disambiguating constructor parameters&lt;/li&gt; &lt;/ul&gt; Example 1:&lt;pre&gt;&lt;code&gt;class artist:&lt;br /&gt;def draw(self): ...&lt;br /&gt;class cowboy:&lt;br /&gt;def draw(self): ...&lt;br /&gt;def drawAndShoot(): self.draw() ...&lt;br /&gt;artisticCowboy = mixin(artist, cowboy)()&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;code&gt;artisticCowboy.draw()&lt;/code&gt; should call &lt;code&gt;artist.draw&lt;/code&gt;,&lt;br /&gt;but &lt;code&gt;artisticCowboy.drawAndShoot()&lt;/code&gt; should call &lt;code&gt;cowboy.draw&lt;/code&gt;,&lt;br /&gt;without needing to be explicitly specified&lt;br /&gt;&lt;br /&gt;Example 2:&lt;pre&gt;&lt;code&gt;class file:&lt;br /&gt;def __init__(self, root): ...&lt;br /&gt;class plant:&lt;br /&gt;def __init__(self, root): ...&lt;/code&gt;&lt;/pre&gt;we need some mechanism for specifying &lt;code&gt;plant&lt;/code&gt;'s and &lt;code&gt;file&lt;/code&gt;'s constructor parameters independently&lt;br /&gt;&lt;br /&gt;UPDATE: Silly me, number one would be great for multiple inheritance also.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-112308881563950473?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/112308881563950473/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=112308881563950473' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112308881563950473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112308881563950473'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_08_01_archive.html#112308881563950473' title='Mixin Requirements'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-112300384811753721</id><published>2005-08-02T20:30:00.000+03:00</published><updated>2005-08-02T20:30:48.123+03:00</updated><title type='text'>Improving the GUI Editor 2</title><content type='html'>A standard XML format for representing GUIs would be a tremendous boon.&lt;br /&gt;&lt;br /&gt;It would solve the biggest problems with current GUI builders: round-trip-ability and lockin.&lt;br /&gt;&lt;br /&gt;It would enable a single builder to easily support GUIs that run with different languages and widget sets, including HTML.&lt;br /&gt;&lt;br /&gt;The standard should specify the least common denominator, as well as extra features and their fall-backs. It shouldn't specify bindings or fancy template support, but it should specify how builders maintain information for features that they don't handle.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-112300384811753721?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/112300384811753721/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=112300384811753721' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112300384811753721'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112300384811753721'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_08_01_archive.html#112300384811753721' title='Improving the GUI Editor 2'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-112230583742873891</id><published>2005-07-25T16:36:00.000+03:00</published><updated>2005-07-29T18:47:12.546+03:00</updated><title type='text'>Mixins instead of Traits</title><content type='html'>On reflection (no pun intended), I can't see what advantage &lt;a href="http://www.iam.unibe.ch/%7Escg/Research/Traits/"&gt;Traits&lt;/a&gt; have over mixins in a dynamic language like python. Specifically, python doesn't seem to be stuck with a total ordering.&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;import copy&lt;br /&gt;def mixin(*classes):&lt;br /&gt;  c=copy.copy(classes[0])&lt;br /&gt;  if len(classes) &gt; 1:&lt;br /&gt;    c.__bases__ += classes[1:]&lt;br /&gt;  return c()&lt;br /&gt;&lt;br /&gt;class a:&lt;br /&gt; def f(self): return "a.f"&lt;br /&gt; def g(self): return "a.g"&lt;br /&gt;class b:&lt;br /&gt; def f(self): return "b.f"&lt;br /&gt; def g(self): return "b.g"&lt;br /&gt;class c:&lt;br /&gt; def g(self): return a.g(self)&lt;br /&gt;&lt;br /&gt;obj=mixin(c, b, a)&lt;br /&gt;assert(obj.f() == "b.f")&lt;br /&gt;assert(obj.g() == "a.g")&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-112230583742873891?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/112230583742873891/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=112230583742873891' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112230583742873891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112230583742873891'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_07_01_archive.html#112230583742873891' title='Mixins instead of Traits'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-112198543651051460</id><published>2005-07-22T01:04:00.000+03:00</published><updated>2005-07-25T20:51:51.570+03:00</updated><title type='text'>Improve the GUI Editor</title><content type='html'>&lt;a href="http://www.hacknot.info/hacknot/action/showEntry?eid=76"&gt;Beware the GUI Editor&lt;/a&gt; only for a little while. For one thing, Sun is finally fixing wysiwyg layout with &lt;a href="http://weblogs.java.net/blog/zixle/archive/2005/06/"&gt;GroupLayout and assorted swing changes&lt;/a&gt;, and &lt;a href="http://www.netbeans.org/files/documents/4/475/matisse.html"&gt;demonstrated in netbeans&lt;/a&gt;. For most of Beware's other complaints, all we really need is good template support, just like what we've been using with html for a while.&lt;br /&gt;&lt;br /&gt;Just like with html, users usually won't care about the api for manipulating their presentation, but that's OK. (The favored api for html is the javascript dom.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-112198543651051460?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/112198543651051460/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=112198543651051460' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112198543651051460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112198543651051460'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_07_01_archive.html#112198543651051460' title='Improve the GUI Editor'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-112169949877285140</id><published>2005-07-18T18:11:00.000+03:00</published><updated>2006-07-05T23:28:22.920+03:00</updated><title type='text'>Python Shell</title><content type='html'>In the quest for best re-use, I'd like my "shell" programming language to be my main programming language, and to just support some syntactic sugar and extra functionality for interactive use.&lt;br /&gt;&lt;br /&gt;Windowing systems obsolesce job control, leaving tab completion, history, and prompting as the important shell functionality. Python's readline bindings can handle the first two.&lt;br /&gt;&lt;br /&gt;LazyPython and IPython both allow ommitting parantheses, commas, and quotes around function parameters. They use standard python's sys.excepthook, so that they only extend python syntax that would've illegal anyway.&lt;br /&gt;&lt;br /&gt;This has two problems. First, there are cases that don't work, like calling a method without parameters. Second and more importantly, excepthook still throws an exception, and so discards context. That means you can't do:&lt;code&gt;for i in range(n): some_convenient_method i&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;So in order to do it right, we'll have to hack the interpreter, and while we're at it, we could even support working directly with the input. For example, you type &lt;code&gt;some_convenient_method&lt;/code&gt; and then a space, and the interpreter inserts a paranthesis. You always have legal python code. IPython prints the legal python code after you hit return, which isn't as nice.&lt;br /&gt;&lt;br /&gt;Incidentally, until we have interfaces or inference, tab completion can only work with already instantiated objects. (For example you can't complete &lt;code&gt;list().a&lt;/code&gt; to &lt;code&gt;list().append&lt;/code&gt;.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-112169949877285140?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/112169949877285140/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=112169949877285140' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112169949877285140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112169949877285140'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_07_01_archive.html#112169949877285140' title='Python Shell'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-112127054267474868</id><published>2005-07-13T18:40:00.000+03:00</published><updated>2005-07-13T19:02:22.790+03:00</updated><title type='text'>Electronic Paper</title><content type='html'>Should be on my link blog, but wow, &lt;a href="http://www.fujitsu.com/global/news/pr/archives/month/2005/20050713-01.html"&gt;Fujitsu is demonstrating electronic paper&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;Highlights: as easy-to-read as paper, extremely low-power, flexible, color. Product to be available between one and two years (April 2006 to March 2007).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-112127054267474868?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/112127054267474868/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=112127054267474868' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112127054267474868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/112127054267474868'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_07_01_archive.html#112127054267474868' title='Electronic Paper'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111962384844317568</id><published>2005-06-24T16:11:00.000+03:00</published><updated>2005-06-27T16:10:19.160+03:00</updated><title type='text'>Is It You?</title><content type='html'>Rule of thumb: &lt;br /&gt;if you have a bad experience with someone, it's just him. &lt;br /&gt;if you have a bad experience with everyone, it's you.&lt;ul&gt; &lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111962384844317568?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111962384844317568/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111962384844317568' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111962384844317568'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111962384844317568'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_06_01_archive.html#111962384844317568' title='Is It You?'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111935970926432303</id><published>2005-06-21T16:14:00.000+03:00</published><updated>2005-06-21T16:15:09.270+03:00</updated><title type='text'>Oppressive Corporate Firewalls</title><content type='html'>If you're behind an obnoxious corporate firewall, that doesn't allow any internet access except through a web proxy, you can still get out to your unix account.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.chiark.greenend.org.uk/%7Esgtatham/putty/"&gt;Putty&lt;/a&gt; supports SSL tunnelling via SSL out-of-the-box:&lt;br /&gt;&lt;ul&gt; &lt;li&gt;on your server, add "Port 443" to your sshd_config&lt;/li&gt;&lt;li&gt;in putty new session, specify 443 in the port box, and&lt;/li&gt;&lt;li&gt;in its Connection/Proxy category, check HTTP and specify your proxy info&lt;br /&gt;&lt;/li&gt; &lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111935970926432303?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111935970926432303/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111935970926432303' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111935970926432303'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111935970926432303'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_06_01_archive.html#111935970926432303' title='Oppressive Corporate Firewalls'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111928046151119363</id><published>2005-06-20T18:13:00.000+03:00</published><updated>2005-06-20T18:14:21.516+03:00</updated><title type='text'>Perl Best Practices (for corporate coders)</title><content type='html'>In general, use perl for glue code and reports, not for business logic.&lt;br /&gt;&lt;br /&gt; Perl code should be as simple as possible. That means: &lt;ul&gt; &lt;li&gt;Use as few language features as possible.&lt;/li&gt;&lt;li&gt;Use as few lines as possible, as long as they're readable.&lt;/li&gt;&lt;li&gt;Don't overdesign.&lt;/li&gt;&lt;li&gt;Don't try to write perl that looks like java.&lt;/li&gt; &lt;/ul&gt;  Avoid rewriting functionality that is present in the standard library.&lt;br /&gt;&lt;br /&gt; Separate functionality out into multiple small scripts, the smallest meaningful  rerunnable units. For example, have one script handle generating a report and  another script handle distributing it.&lt;br /&gt;&lt;br /&gt; Always "use strict".&lt;br /&gt;&lt;br /&gt; Avoid using $_ in loops except for regular expressions.&lt;br /&gt;&lt;br /&gt; Avoid reversed flow control operators except for error handling ("doSomething or  die()").&lt;br /&gt;&lt;br /&gt; Avoid redundant comments.&lt;br /&gt;&lt;br /&gt; Avoid overloading on context. (e.g. sub fu { wantarray() ? X() : Y() })&lt;br /&gt;&lt;br /&gt; Avoid special symbol variables. Use the long versions and "use English" (e.g. "$INPUT_RECORD_SEPARATOR" instead of $/).  Comment appropriately.&lt;br /&gt;&lt;br /&gt; Avoid using shell tools (e.g "awk", "grep", and even "date" and "cp"). If perl  can do it, do it in perl.&lt;br /&gt;&lt;br /&gt; Prefer "my" over "local".&lt;br /&gt;&lt;br /&gt; Put "my" declarations in the tightest possible scope.&lt;br /&gt;&lt;br /&gt; Have users of modules explicitly import the tokens that they want (e.g. "use  SomeModule qw( SomeFunc $SomVar )").&lt;br /&gt;&lt;br /&gt; Avoid writing huge modules with lots of independent functionality; people are  afraid to change them.&lt;br /&gt;&lt;br /&gt; Avoid writing modules altogether, unless you're absolutely sure that your code  will be reused.&lt;br /&gt;&lt;br /&gt; If you're using references, have the first character of the expression reflect  the type of the expression (e.g. use "$somearrayref-&gt;[3]" instead of  "@$somearrayref[3]").&lt;br /&gt;&lt;br /&gt; If your "configuration" is sufficiently complex (or unchanging) just define at  the top of your script.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111928046151119363?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111928046151119363/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111928046151119363' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111928046151119363'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111928046151119363'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_06_01_archive.html#111928046151119363' title='Perl Best Practices (for corporate coders)'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111817806151682073</id><published>2005-06-08T00:00:00.000+03:00</published><updated>2007-03-21T11:45:33.416+02:00</updated><title type='text'>Next Generation Web</title><content type='html'>The next generation web will be all about abstractions for handling foreign code.&lt;br /&gt;&lt;br /&gt;Of all the desirable features for a development platform, one of the most desirable is the ability to write &lt;em&gt;and deploy&lt;/em&gt; code quickly and easily. This is how people explain the success of the web and web applications like the google suite.&lt;br /&gt;&lt;br /&gt;The next generation web will protect users even from malicious code without requiring much greater responsibility. The new security will have to support three classes of features:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;manage state&lt;/li&gt;   &lt;li&gt;allow the code from one site to affect the user's experience of other sites (like &lt;a href="http://diveintogreasemonkey.org/install/what-is-greasemonkey.html"&gt;greasemonkey&lt;/a&gt; for example)&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;clearly determine what site is responsible for a given interaction (to &lt;a href="http://www.sims.berkeley.edu/%7Erachna/papers/securityskins.pdf"&gt;combat phishing&lt;/a&gt; for example)&lt;br /&gt;&lt;/li&gt; &lt;/ul&gt; Users will never be hassled "are you sure you want to install this extension?"; foreign code will have access to a powerful set of operations that yet poses no threat to the user. On the other hand, users will have to learn something of a new approach just to be able to understand what they'll be seeing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111817806151682073?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111817806151682073/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111817806151682073' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111817806151682073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111817806151682073'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_06_01_archive.html#111817806151682073' title='Next Generation Web'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111713042759817573</id><published>2005-05-26T20:47:00.000+03:00</published><updated>2005-05-26T21:10:22.260+03:00</updated><title type='text'>Another Solution to the Fragile Base Class Problem</title><content type='html'>Here's a simple python implementation of the solution to the fragile base class problem described in &lt;a href="http://citeseer.ist.psu.edu/context/855223/0"&gt;Modular Reasoning in the Presence of Subtyping&lt;/a&gt;, and more accessibly &lt;a href="http://recycledknowledge.blogspot.com/2005/04/divided-classes-having-your.html"&gt;in John Cowan's blog&lt;/a&gt;. It uses classes in place of "divisions".&lt;br /&gt;&lt;pre&gt;class sgd(type):&lt;br /&gt;  def __init__(cls, name, bases, dct):&lt;br /&gt;      overridden_bases = [ base for attr in dct.keys() for base in cls.__mro__ if hasattr(base, attr) and not attr.startswith('__') ]&lt;br /&gt;      required_methods = [ (base,m) for base in overridden_bases for m in base.__dict__ if m not in cls.__dict__ and not m.startswith('__') ]&lt;br /&gt;      if required_methods:&lt;br /&gt;          raise "unimplemented methods:", required_methods&lt;br /&gt;&lt;br /&gt;      super(sgd, cls).__init__(name, bases, dct)&lt;br /&gt;&lt;br /&gt;class sgd_class(object):&lt;br /&gt;  __metaclass__ = sgd&lt;/pre&gt;&lt;br /&gt;and then:&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; class a(sgd_class):&lt;br /&gt;...  def f(self): pass&lt;br /&gt;...  def g(self): pass&lt;br /&gt;... &lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; class b(a): pass&lt;br /&gt;... &lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; class c(a):&lt;br /&gt;...  def f(self): pass&lt;br /&gt;...  def g(self): pass&lt;br /&gt;... &lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; class d(a):&lt;br /&gt;...  def f(self): pass&lt;br /&gt;... &lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;  File "&amp;lt;stdin&amp;gt;", line 1, in ?&lt;br /&gt;  File "x.py", line 12, in __init__&lt;br /&gt;    if required_methods: raise "unimplemented methods:", required_methods&lt;br /&gt;unimplemented methods:: [(&amp;lt;class '__main__.a'&amp;gt;, 'g')]&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111713042759817573?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111713042759817573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111713042759817573' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111713042759817573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111713042759817573'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_05_01_archive.html#111713042759817573' title='Another Solution to the Fragile Base Class Problem'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111626631486922509</id><published>2005-05-16T20:02:00.000+03:00</published><updated>2005-05-16T20:58:34.923+03:00</updated><title type='text'>People Don't Read, and What To Do About It</title><content type='html'>Ever had someone flagrantly not read your email? Try putting the most important stuff at the top.&lt;br /&gt;&lt;br /&gt;Not reading is a lot more prevalent than you think. Most people don't enjoy reading. Even those who do have too little time to read everything they'd like.&lt;br /&gt;&lt;br /&gt;The solution is to write your emails in order of decreasing importance. Don't write in chronological order, or even in logical order. Employ the journalistic technique of "heads, decks, and leads" or headlines, sub-headlines, and leading paragraphs.&lt;br /&gt;&lt;br /&gt;This is most important for messages to groups of people, and for documentation messages. In other situations, there isn't so much motivation to write more text than will be read.&lt;br /&gt;&lt;br /&gt;(This is ironic as a blog post; those who see this post presumably do read. But this advice is for you! You don't realize how unusual you are.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111626631486922509?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111626631486922509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111626631486922509' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111626631486922509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111626631486922509'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_05_01_archive.html#111626631486922509' title='People Don&apos;t Read, and What To Do About It'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111601412471289288</id><published>2005-05-13T22:13:00.000+03:00</published><updated>2005-05-13T22:55:24.740+03:00</updated><title type='text'>Exceptions Are Good For You</title><content type='html'>Languages with exceptions are good for you; they make you realize that your code can be interrupted any time.&lt;br /&gt;&lt;br /&gt;Consider:&lt;blockquote&gt;&lt;code&gt;#read user password without displaying on screen&lt;br /&gt;os.system("stty -echo")&lt;br /&gt;print "Password:",&lt;br /&gt;password = raw_input()&lt;br /&gt;os.system("stty echo")&lt;br /&gt;print&lt;/code&gt;&lt;/blockquote&gt;What happens if the user changes her mind, and kills the program? All subsequent typing in the shell will be invisible! Checking for errors won't help here.&lt;br /&gt;&lt;br /&gt;The only difference in modern languages is that the rest of a program may continue to run even after a function has been interrupted. This creates a new kind of obligation, but not a big one:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;you already have to worry about external state without exceptions (above example)&lt;/li&gt;   &lt;li&gt;you don't have to worry about local function state, because the exception causes it to be thrown out&lt;/li&gt;   &lt;li&gt;you &lt;em&gt;do&lt;/em&gt; now have to worry about non-local state&lt;/li&gt; &lt;/ol&gt;Composable memory transactions would relieve us of even #3; an exception would roll back all the changes.&lt;br /&gt;&lt;br /&gt;An effects system would at least catch the omission; it'd flag a function that makes multiple write calls to objects not mentioned in a &lt;code&gt;finally&lt;/code&gt; cleanup block.&lt;br /&gt;&lt;br /&gt;In languages without exceptions, you have to use a signal handler in the above example; in languages with exceptions, you can use a &lt;code&gt;finally&lt;/code&gt; clause  for the &lt;code&gt;stty echo&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;(In the spirit of the recent exception buzz (Joel Spolsky's popularization of Raymond Chen's rant, and GvR's "resource allocation" work)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111601412471289288?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111601412471289288/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111601412471289288' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111601412471289288'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111601412471289288'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_05_01_archive.html#111601412471289288' title='Exceptions Are Good For You'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111539154057240835</id><published>2005-05-06T17:47:00.000+03:00</published><updated>2006-09-10T14:55:02.090+03:00</updated><title type='text'>Click For Each Page: ACM Queue</title><content type='html'>Some sites have an obnoxious policy of requiring you to page through their content by clicking "next", "next" a bunch of times. Presumably they do this to better gauge interest in the content; the user cared enough to click to the end of the article. (Web browsers don't naturally support reporting back to the server how far the user scrolls in a page or how long a user has a page open (and focused).) Or they could just be incompetent.&lt;br /&gt;&lt;br /&gt;To get around this, you can often click their button "Print This Article" or equivalent.&lt;br /&gt;&lt;br /&gt;For some sites, &lt;span style="font-weight: bold;"&gt;you may have to visit the last section&lt;/span&gt; and then click "Print This Article" there. Cute, eh? This is how I read &lt;a href="http://acmqueue.com/"&gt;ACM Queue&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111539154057240835?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111539154057240835/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111539154057240835' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111539154057240835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111539154057240835'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_05_01_archive.html#111539154057240835' title='Click For Each Page: ACM Queue'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111538914152301418</id><published>2005-05-06T17:07:00.000+03:00</published><updated>2007-02-18T23:45:11.536+02:00</updated><title type='text'>Capacity For Self Deception</title><content type='html'>&lt;p&gt;Someone should start a catalog of memes. It looks like this one started with "Our capacity for self-deception has no known limits." from &lt;a href="http://www.amazon.com/exec/obidos/tg/detail/-/0060663227/002-6168008-3561660"&gt;Ascent of the Mountain, Flight of the Dove: An Invitation to Religious Studies&lt;/a&gt; by  Michael Novak.&lt;/p&gt;&lt;p&gt;Though it's easier to demonstrate this for criminals, it also applies to the best of us.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111538914152301418?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111538914152301418/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111538914152301418' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111538914152301418'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111538914152301418'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_05_01_archive.html#111538914152301418' title='Capacity For Self Deception'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111480338584738420</id><published>2005-04-29T18:47:00.000+03:00</published><updated>2005-04-29T22:36:25.846+03:00</updated><title type='text'>We Need Core Data</title><content type='html'>Something like Apple's new &lt;a href="http://developer.apple.com/macosx/tiger/coredata.html"&gt;Core Data&lt;/a&gt; data-model-framework is long overdue, but we need a standard, free, cross-platform implementation.&lt;br /&gt;&lt;br /&gt;The hierarchical filesystem is not meeting our needs. For all of our documents, we want:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;easy persistence&lt;/li&gt;   &lt;li&gt;undo and redo&lt;/li&gt;   &lt;li&gt;gui prototyping&lt;/li&gt;   &lt;li&gt;revision control&lt;/li&gt;   &lt;li&gt;transactions&lt;/li&gt;&lt;li&gt;search&lt;/li&gt;   &lt;li&gt;annotation&lt;br /&gt;  &lt;/li&gt;  &lt;/ul&gt;(Core Data only provides the first few features.)&lt;br /&gt;&lt;br /&gt;This new API can't handle behavior and stay language/platform independent. That is, it can't support the object oriented approach of only allowing access to state through member functions.&lt;br /&gt;&lt;br /&gt;On the other hand, it would be nice to use regular oop languages to specify the model.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111480338584738420?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111480338584738420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111480338584738420' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111480338584738420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111480338584738420'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_04_01_archive.html#111480338584738420' title='We Need Core Data'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111410875525969692</id><published>2005-04-21T21:32:00.000+03:00</published><updated>2005-04-22T00:59:25.306+03:00</updated><title type='text'>Justification of Python Sequence Subscripts</title><content type='html'>Which notation should be used for slicing a subsequence of &lt;span style="font-style: italic;"&gt;m&lt;/span&gt; through &lt;span style="font-style: italic;"&gt;n&lt;/span&gt; items?&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;&lt;code&gt;myseq[   m : n   ]&lt;/code&gt;&lt;/li&gt;   &lt;li&gt;&lt;code&gt;myseq[   m : n+1 ]&lt;/code&gt;&lt;/li&gt;   &lt;li&gt;&lt;code&gt;myseq[ m-1 : n   ]&lt;/code&gt;&lt;/li&gt;   &lt;li&gt;&lt;code&gt;myseq[ m-1 : n+1 ]&lt;/code&gt;&lt;/li&gt; &lt;/ol&gt;#3 and #4 are silly, because they're inconsistent with the natural way to refer to a single item &lt;code&gt;myseq[m]&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Perl and ruby use #1, which is wrong because you can't iterate down to an empty subsequence with &lt;code&gt;myseq[m:m]&lt;/code&gt;. Representing this with &lt;code&gt;myseq[m:m-1]&lt;/code&gt; is clearly evil, and it breaks completely for m = 0.&lt;br /&gt;&lt;br /&gt;The rationale for indices starting from 0 instead of 1 isn't as strong: that representing the whole list as &lt;code&gt;myseq[0:len(myseq)]&lt;/code&gt; is "nicer" than representing it as &lt;code&gt;myseq[1:len(myseq)+1]&lt;/code&gt;. Perl and ruby don't even have this rationale :).&lt;br /&gt;&lt;br /&gt;Ironically, reverse indices &lt;span style="font-style: italic;"&gt;do&lt;/span&gt; go from 1 to n+1, or rather from -1 to -(n+1). This is fortuitous, because representing reversed(myseq) with myseq[-1::-1] is nicer than representing it with myseq[0::-1]&lt;br /&gt;&lt;br /&gt;inspired by a note from &lt;a href="http://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF"&gt;Dykstra&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111410875525969692?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111410875525969692/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111410875525969692' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111410875525969692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111410875525969692'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_04_01_archive.html#111410875525969692' title='Justification of Python Sequence Subscripts'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111403257131849919</id><published>2005-04-20T23:25:00.000+03:00</published><updated>2005-04-21T17:22:14.510+03:00</updated><title type='text'>Type, Effect, and Inference</title><content type='html'>Effect systems are nice for the same reasons that Type systems are nice, and they're also a big win for &lt;a href="http://www.research.microsoft.com/%7Esimonpj/papers/stm/index.htm"&gt;concurrency&lt;/a&gt; and for &lt;a href="http://recycledknowledge.blogspot.com/2005/04/divided-classes-having-your.html"&gt;encapsulation&lt;/a&gt;. Effects, as I understand them, allow specifying how code reads and writes state.&lt;br /&gt;&lt;br /&gt;If you're wondering how to convince people to create even more code annotation, don't worry; we'll be able to infer effect information from the code itself, just as we can &lt;a href="http://codespeak.net/pypy/index.cgi?doc/translation.html#annotator"&gt;infer type information from the code itself&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Even with perfect inference, explicit annotation will be useful for external data and for specifying contracts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111403257131849919?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111403257131849919/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111403257131849919' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111403257131849919'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111403257131849919'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_04_01_archive.html#111403257131849919' title='Type, Effect, and Inference'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111290696465582856</id><published>2005-04-07T23:43:00.000+03:00</published><updated>2005-04-07T23:49:24.656+03:00</updated><title type='text'>RDF and the WWW</title><content type='html'>Just had an epiphany: RDF is very similar to the world wide web.&lt;br /&gt;&lt;br /&gt;They're both edge-labelled directed graphs.&lt;br /&gt;&lt;br /&gt;Though people generally aren't so careful with their link texts, these are just like RDF predicates. The linking page is the subject, and the linked page is the object.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111290696465582856?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111290696465582856/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111290696465582856' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111290696465582856'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111290696465582856'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_04_01_archive.html#111290696465582856' title='RDF and the WWW'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111290658146761529</id><published>2005-04-07T00:18:00.000+03:00</published><updated>2005-04-07T23:51:39.133+03:00</updated><title type='text'>Tomboy and the Future</title><content type='html'>&lt;a href="http://www.beatniksoftware.com/tomboy/"&gt;Tomboy&lt;/a&gt; is an excellent program for linux.&lt;br /&gt;&lt;br /&gt;It looks like a simple implementation of post-it notes, but it has a few features which make it wonderful:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;automatic save&lt;/li&gt;   &lt;li&gt;ability to easily link any text to a new note (sort of like a wiki)&lt;br /&gt; &lt;/li&gt;   &lt;li&gt;fast full search&lt;/li&gt;   &lt;li&gt;clickable web links&lt;/li&gt; &lt;/ul&gt; There are more features that'd yield incredible power:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;"who links to me?" button&lt;/li&gt;   &lt;li&gt;ability to list nodes that are linked to by all of a set of nodes&lt;/li&gt;   &lt;li&gt;ability to open a node by path, with autocompletion&lt;br /&gt; &lt;/li&gt;   &lt;li&gt;"publish" button, for a single node or for a group of nodes&lt;br /&gt; &lt;/li&gt;   &lt;li&gt;ability to manage the graph graphically&lt;/li&gt; &lt;/ol&gt; #2 would enable the now fashionable &lt;a href="http://en.wikipedia.org/wiki/Folksonomy"&gt;folksonomy&lt;/a&gt; functionality.&lt;br /&gt;#3 would replace bookmarks.&lt;br /&gt;#4 would implement a blog authoring tool.&lt;br /&gt;#5 would give you a &lt;a href="http://en.wikipedia.org/wiki/Mindmapping"&gt;mindmap&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This stuff shouldn't be in a particular application, but should be available to the whole system. It'll be great if this notes application demonstrates of the power of the approach, and motivates people to implement it more widely.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111290658146761529?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111290658146761529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111290658146761529' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111290658146761529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111290658146761529'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_04_01_archive.html#111290658146761529' title='Tomboy and the Future'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111271752826799551</id><published>2005-04-04T22:50:00.000+03:00</published><updated>2007-03-18T12:49:38.153+02:00</updated><title type='text'>Corporate Personhood</title><content type='html'>Here's my attempt to distill the issue of corporate personhood. The best book on the subject that I've seen is &lt;a href="http://www.amazon.com/exec/obidos/tg/detail/-/0743247442"&gt;The Corporation : The Pathological Pursuit of Profit and Power&lt;/a&gt;, by Joel Bakan.&lt;br /&gt;&lt;br /&gt;Corporations are disproportionately powerful, because they concentrate huge amounts of money and therefore political influence. Is this good or bad? On the one hand, "what's good for GE is good for America." On the other hand, corporations by law must pursue no objective over maximizing shareholder value. This means externalizing costs whenever possible. For example, a corporation sells 100,000,000 widgets whose use will kill 100 people. That corporation may not legally settle for a smaller profit in order to make its widgets safer, and thereby save the 100 people. (The "what's good for GE" proponents may counter that the public sector makes such &lt;a href="http://newyorker.com/printables/fact/031013fa_fact"&gt;cold-hearted calculations&lt;/a&gt; all the time, and that the economic activity of the widgets is part of the "rising tide that lifts all boats," making the whole society wealthier and safer.)&lt;br /&gt;&lt;br /&gt;What does this have to do with "corporate personhood?" Corporations concentrate huge amounts of capital, but they defuse almost all responsibility. When a corporation makes a million dollars, that money is shared by all its owners. When a corporation kills a person, that guilt is claimed by no one.&lt;br /&gt;&lt;br /&gt;Though a corporation is fundamentally no more than a financial partnership, the existence of the corporate entity insulates its officers from morality and from the law. A bad action could spring from the combined actions of many members of a corporation, though none of the individual actions is bad. Even when a single member performs a bad action on behalf of the corporation, it's difficult to detect and prosecute. This insulation itself encourages bad behavior, because members' responsibility to the corporation is more pressing than their responsibility to the society and its laws.&lt;br /&gt;&lt;br /&gt;Basing the rights of the corporation on the rights of the person gives corporations additional power. The law gives individuals various rights to protect them from the power of the state (e.g. the Bill of Rights). Sharing these rights with corporations gives them even more power. Treating people and corporations the same allows using a rhetoric of "freedom" to weaken and eliminate regulation, when regulation is the best tool for making corporations consider important externalities, and the only way to correct market failures.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111271752826799551?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111271752826799551/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111271752826799551' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111271752826799551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111271752826799551'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_04_01_archive.html#111271752826799551' title='Corporate Personhood'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111237600457132004</id><published>2005-04-01T20:19:00.000+03:00</published><updated>2006-11-17T21:28:20.396+02:00</updated><title type='text'>Emulating maxdepth for Solaris find</title><content type='html'>Say you want to find files in the top level of a directory that meet a certain condition (e.g. haven't been accessed for at least three days).&lt;br /&gt;&lt;br /&gt;GNU find can do this with "-maxdepth 1", but Solaris find can't. To get the same functionality for Solaris find, you can use this hack:&lt;br /&gt;&lt;code&gt;find /some/path/. &amp;#92;( -type d -a &amp;#92;! -name . -prune &amp;#92;) -o -type f -print&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;That is, first prune all directories that aren't named ".", then print the names of the remaining files. It's important that the path be "/some/path/." instead of "/some/path", because that's what enables special treatment for the top level directory.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111237600457132004?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111237600457132004/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111237600457132004' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111237600457132004'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111237600457132004'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_04_01_archive.html#111237600457132004' title='Emulating maxdepth for Solaris find'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111229007688282784</id><published>2005-03-31T18:59:00.000+02:00</published><updated>2007-03-27T18:33:20.373+02:00</updated><title type='text'>Partial Replacing Lambda?</title><content type='html'>Wonder if &lt;a href="http://www.python.org/peps/pep-0309.html"&gt;partial functions&lt;/a&gt; are going to replace lambda in python3000.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;partial(operator.add, 1)&lt;/code&gt; isn't such an attractive substitute for &lt;code&gt;lambda x: x+1&lt;/code&gt;, but that's more about &lt;code&gt;operator&lt;/code&gt; than it is about &lt;code&gt;partial()&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Maybe &lt;code&gt;partial()+1&lt;/code&gt; should be supported using operator overloading. It'd be especially nice to be able to do &lt;code&gt;partial()+x+y&lt;/code&gt; instead of &lt;code&gt;partial(operator.add, x+y)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This form should probably be a differently named built-in, but built-ins aren't cheap, and the no argument constructor isn't otherwise meangingful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111229007688282784?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111229007688282784/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111229007688282784' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111229007688282784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111229007688282784'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_03_01_archive.html#111229007688282784' title='Partial Replacing Lambda?'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111212915625116326</id><published>2005-03-29T22:41:00.001+02:00</published><updated>2005-03-29T23:06:32.193+02:00</updated><title type='text'>Better Spam Protection Implementation, part 2</title><content type='html'>This post is the second part of my implementation of &lt;a href="http://farfetched.blogspot.com/2004/12/better-spam-protection.html"&gt;Better Spam Protection&lt;/a&gt;; you should start with &lt;a href="http://farfetched.blogspot.com/2005/03/better-spam-protection-implementation.html"&gt;the first part&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Run the following in your account's shell. It will create a directory .tmda and&lt;br /&gt;its contents, and it will append to (or create) your .fetchmailrc.&lt;br /&gt;&lt;br /&gt;You'll have to customize at least places that the word "your" occurs in .tmda/config and .fetchmailrc.&lt;br /&gt;&lt;br /&gt;You'll also have to configure your mail client to use tmda-sendmail instead of the actual sendmail, or else configure it to use tofmipd, that is port 8025 on localhost for the smtp server.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#START OF SCRIPT 2&lt;br /&gt;&lt;br /&gt;mkdir $HOME/.tmda&lt;br /&gt;cd $HOME/.tmda&lt;br /&gt;mkdir filters lists logs pendings responses&lt;br /&gt;touch filters/incoming filters/outgoing logs/in logs/out logs/debug&lt;br /&gt;&lt;br /&gt;tmda-keygen | head -3 | tail -1 &amp;gt; crypt_key&lt;br /&gt;&lt;br /&gt;echo yourlocallogin:yourlocalpass &amp;gt; tofmipd&lt;br /&gt;&lt;br /&gt;cat &amp;gt;&amp;gt;$HOME/.fetchmailrc &amp;lt;&amp;lt;EOF&lt;br /&gt;poll yourpopserver.com protocol pop3 username youruser password yourpass&lt;br /&gt;mda "xtmdaheader youruser@userhost.com | SENDER=%F tmda-filter"&lt;br /&gt;EOF&lt;br /&gt;&lt;br /&gt;chmod 600 . crypt_key tofmipd $HOME/.fetchmailrc&lt;br /&gt;&lt;br /&gt;cat &amp;gt;config &amp;lt;&amp;lt;EOF&lt;br /&gt;USERNAME = 'youruser'&lt;br /&gt;HOSTNAME = 'yourhost.com'&lt;br /&gt;RECIPIENT_DELIMITER = '+' #sendmail&amp;amp;postfix default to +, qmail defaults to -&lt;br /&gt;&lt;br /&gt;#mta (for fetchmail)&lt;br /&gt;MAIL_TRANSFER_AGENT='sendmail'&lt;br /&gt;RECIPIENT_HEADER = 'X-RecFor-Recipient'&lt;br /&gt;&lt;br /&gt;#default tagging method&lt;br /&gt;ACTION_OUTGOING='keyword=sender'&lt;br /&gt;&lt;br /&gt;#features&lt;br /&gt;ACTION_HEADER_INCOMING = 1&lt;br /&gt;X_TMDA_IN_SUBJECT = 1&lt;br /&gt;&lt;br /&gt;#paths&lt;br /&gt;d = os.path.expanduser('~/')+'.tmda/'&lt;br /&gt;CONFIRM_APPEND = d+ 'lists/whitelist_confirmed'&lt;br /&gt;PENDING_WHITELIST_APPEND = d+ 'lists/whitelist'&lt;br /&gt;LOGFILE_INCOMING = d+ 'logs/in'&lt;br /&gt;LOGFILE_OUTGOING = d+ 'logs/out'&lt;br /&gt;LOGFILE_DEBUG = d+ 'logs/debug'&lt;br /&gt;DELIVERY = os.environ['MAIL']&lt;br /&gt;#DELIVERY = '|procmail'&lt;br /&gt;&lt;br /&gt;#use the following line to prevent sending out challenges&lt;br /&gt;#ACTION_EXPIRED_DATED=ACTION_FAIL_DATED=ACTION_FAIL_KEYWORD=ACTION_INCOMING='hold'&lt;br /&gt;EOF&lt;br /&gt;&lt;br /&gt;#END OF SCRIPT 2&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111212915625116326?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111212915625116326/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111212915625116326' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111212915625116326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111212915625116326'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_03_01_archive.html#111212915625116326' title='Better Spam Protection Implementation, part 2'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111212880313287447</id><published>2005-03-29T22:20:00.000+02:00</published><updated>2007-02-08T17:36:24.776+02:00</updated><title type='text'>Better Spam Protection Implementation, part 1</title><content type='html'>As promised, I'm posting instructions for implementing &lt;a href="http://farfetched.blogspot.com/2004/12/better-spam-protection.html"&gt;Better Spam Protection&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;These instructions are intended for people who know what they're doing. These instructions describe my setup, but I didn't try using them to reproduce my setup, so I may have missed something. Because blogspot doesn't support attachments, you'll have to copy from the article text. You can either paste directly into a shell, or into a new file which you can then run.&lt;br /&gt;&lt;br /&gt;This post describes what you should do under root, or at least in an administrator capacity. The next post describes what you should do under your user account.&lt;br /&gt;&lt;br /&gt;First install &lt;a href="http://tmda.net/releases/stable/tmda-1.0.3.tgz"&gt;tmda&lt;/a&gt;, then run the following script as root. Only its first step is necessary for all configurations.&lt;br /&gt;&lt;br /&gt;You're going to need sendmail installed and functioning. To configure sendmail on a new fedora installation you usually just have to set your isp's smtp server on the line of /etc/mail/sendmail.cf that starts with "DS".&lt;br /&gt;&lt;br /&gt;If you don't use pop (or imap), you won't need the xtmdaheader stuff. If you've been using your mail gui to download pop mail, you'll need to make sure that you have fetchmail installed, so that you can start using that instead.&lt;br /&gt;&lt;br /&gt;If your mail clients support using any path to the sendmail binary, you won't need the tofmipd stuff.&lt;br /&gt;&lt;br /&gt;The following script will patch /usr/bin/tmda-inject to enable it to use "sender keywords" and it will install:&lt;br /&gt;/usr/local/bin/tmda-address-random - program to easily create throwaway addresses&lt;br /&gt;/usr/local/xtmdaheader - for fetchmail support&lt;br /&gt;/usr/local/src/xtmdaheader-1.1.c - source code for previous&lt;br /&gt;/etc/init.d/tofmipd - runs tmda-ofmipd on startup, to support mail clients that can't use tmda-sendmail&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#START OF SCRIPT 1&lt;br /&gt;&lt;br /&gt;cat &amp;lt;&amp;lt;EOF | patch /usr/bin/tmda-inject&lt;br /&gt;*** tmda-inject.orig    2005-03-23 15:44:49.417614904 -0500&lt;br /&gt;--- tmda-inject 2005-03-23 15:44:26.931033384 -0500&lt;br /&gt;***************&lt;br /&gt;*** 202,207 ****&lt;br /&gt;--- 202,209 ---- &lt;br /&gt;                 cookie_option + '@' + hostname&lt;br /&gt;     elif cookie_type in ('kw','keyword') and cookie_option:&lt;br /&gt;       # Send a message with a tagged (keyword) address.&lt;br /&gt;+       if cookie_option == 'sender':&lt;br /&gt;+               cookie_option = md5.new(to_address).hexdigest()[:6]&lt;br /&gt;       field = Cookie.make_keyword_address(from_address, cookie_option)&lt;br /&gt;     elif not cookie_type:&lt;br /&gt;         # cookie_type == None means field is a text string&lt;br /&gt;EOF&lt;br /&gt;&lt;br /&gt;cat &amp;gt;/usr/local/bin/tmda-address-random &amp;lt;&amp;lt;EOF&lt;br /&gt;#!/usr/bin/python&lt;br /&gt;import os, string&lt;br /&gt;print "Keyword for the new address, or just hit Enter to randomly generate:"&lt;br /&gt;keyword = raw_input()&lt;br /&gt;os.system('clear')&lt;br /&gt;if not keyword:&lt;br /&gt;       keyword = file('/dev/urandom').read(8).translate(((string.letters+string.digits)*5)[:256])&lt;br /&gt;os.system("tmda-address -k "+keyword)&lt;br /&gt;raw_input()&lt;br /&gt;EOF&lt;br /&gt;&lt;br /&gt;cat &amp;gt;/etc/init.d/tofmipd &amp;lt;&amp;lt;EOF&lt;br /&gt;#!/bin/bash&lt;br /&gt;# description: tofmipd&lt;br /&gt;# chkconfig: 2345 90 10&lt;br /&gt;# source function library&lt;br /&gt;. /etc/rc.d/init.d/functions&lt;br /&gt;&lt;br /&gt;RETVAL=0&lt;br /&gt;&lt;br /&gt;start() {&lt;br /&gt;       action $"Running tofmipd: " su - yourlocalaccount -c tmda-ofmipd&lt;br /&gt;       RETVAL=$?&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;stop() {&lt;br /&gt;       action $"Killing tofmipd: "&lt;br /&gt;       killproc tofmipd&lt;br /&gt;       RETVAL=$?&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;restart() {&lt;br /&gt;       stop&lt;br /&gt;       start&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;case "$1" in&lt;br /&gt; start)&lt;br /&gt;       start&lt;br /&gt;       ;;&lt;br /&gt; stop)&lt;br /&gt;       stop&lt;br /&gt;       ;;&lt;br /&gt; restart|force-reload)&lt;br /&gt;       restart&lt;br /&gt;       ;;&lt;br /&gt; reload)&lt;br /&gt;       ;;&lt;br /&gt; condrestart)&lt;br /&gt;       [ -f "$lockfile" ] &amp;&amp;amp; restart&lt;br /&gt;       ;;&lt;br /&gt; *)&lt;br /&gt;       echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart}"&lt;br /&gt;       exit 1&lt;br /&gt;esac&lt;br /&gt;&lt;br /&gt;exit $RETVAL&lt;br /&gt;EOF&lt;br /&gt;chkconfig --add tofmipd&lt;br /&gt;chkconfig tofmipd on&lt;br /&gt;&lt;br /&gt;cat &amp;gt;/usr/local/src/xtmdaheader-1.1.c &amp;lt;&amp;lt;EOF&lt;br /&gt;// Free to use, copy, modify or whatever.&lt;br /&gt;// Copyright (c) by Hannu Kotipalo&lt;br /&gt;// Version 1.1&lt;br /&gt;// 1.0-1.1:&lt;br /&gt;//      - To and CC - headers checked&lt;br /&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#define false 0&lt;br /&gt;#define true (!false)&lt;br /&gt;#define bool unsigned short&lt;br /&gt;#define bufsize 1024&lt;br /&gt;&lt;br /&gt;char InputLine[bufsize],ReceivedFor[bufsize];&lt;br /&gt;char ToAddress[bufsize],CcAddress[bufsize],TempAddress[bufsize];&lt;br /&gt;char UserName[bufsize];&lt;br /&gt;char DomainName[bufsize];&lt;br /&gt;&lt;br /&gt;bool IsEmptyLine(char*line)&lt;br /&gt;{&lt;br /&gt;       while (*line)&lt;br /&gt;       {&lt;br /&gt;               if (*line&amp;gt;' ') return false;&lt;br /&gt;               line++;&lt;br /&gt;       }&lt;br /&gt;       return true;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;unsigned int FindAt(char* src)&lt;br /&gt;{ // Attention: does not find, if @ is at first char, src[0]&lt;br /&gt;unsigned int i;&lt;br /&gt;       for (i=0; src[i]; i++)&lt;br /&gt;       {&lt;br /&gt;               if (i &amp;gt;= bufsize) return 0;&lt;br /&gt;               if (src[i]=='@') return i;&lt;br /&gt;       }&lt;br /&gt;       return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;bool IsEmailChar(char c)&lt;br /&gt;{&lt;br /&gt;       return (&lt;br /&gt;       ((c&amp;gt;'?') &amp;&amp;amp; (c&amp;lt;='~')) ||&lt;br /&gt;       ((c&amp;gt;'"') &amp;&amp;amp; (c&amp;lt;',')) ||&lt;br /&gt;       ((c&amp;gt;',') &amp;&amp;amp; (c&amp;lt;';')) ||&lt;br /&gt;       (c=='=') ||&lt;br /&gt;       (c=='!'));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;char * CopyEmailAddr(char* dest, char* src)&lt;br /&gt;{&lt;br /&gt;unsigned int i,j;&lt;br /&gt;       i = 0;&lt;br /&gt;       j = FindAt(src);&lt;br /&gt;       if (j)&lt;br /&gt;       {&lt;br /&gt;               while (j &amp;&amp;amp; src[j] &amp;&amp;amp; IsEmailChar(src[j]) ) j--;&lt;br /&gt;               if (!IsEmailChar(src[j])) j++;&lt;br /&gt;               while (IsEmailChar(src[j]))&lt;br /&gt;               {&lt;br /&gt;                       if (i++ &amp;gt;= bufsize) break;&lt;br /&gt;                       *dest++ = src[j++];&lt;br /&gt;               }&lt;br /&gt;               *dest='\0';&lt;br /&gt;               return &amp;src[j];&lt;br /&gt;       }&lt;br /&gt;       return NULL;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void strccpy(char* dest, char* src, char delim)&lt;br /&gt;{&lt;br /&gt;unsigned int i;&lt;br /&gt;       i=0;&lt;br /&gt;       do&lt;br /&gt;       {&lt;br /&gt;               if (i++ &amp;gt;= bufsize) break;&lt;br /&gt;               *dest++ = *src++;&lt;br /&gt;       } while (*src &amp;&amp;amp; (*src != delim));&lt;br /&gt;       *dest++ = '\0';&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;char LowerCase(char c)&lt;br /&gt;{&lt;br /&gt;       if ((c &amp;gt;= 'A') &amp;&amp;amp;&lt;br /&gt;           (c &amp;lt;= 'Z'))&lt;br /&gt;               c |= 0x20;&lt;br /&gt;       return c;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;bool strsubcmp(char *mainstr, char* substr)&lt;br /&gt;{&lt;br /&gt;       while (*substr)&lt;br /&gt;       {&lt;br /&gt;               if (LowerCase(*mainstr++) != LowerCase(*substr++)) return false;&lt;br /&gt;       }&lt;br /&gt;       return true;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#define H_Unknown 0&lt;br /&gt;#define H_Received 1&lt;br /&gt;#define H_Received_for 2&lt;br /&gt;#define H_To 3&lt;br /&gt;#define H_Cc 4&lt;br /&gt;&lt;br /&gt;int main(int argc, char **argv)&lt;br /&gt;{&lt;br /&gt;unsigned int state;&lt;br /&gt;char * r_for;&lt;br /&gt;char * linebrowse;&lt;br /&gt;unsigned int i,ULen,DLen;&lt;br /&gt;char * arg;&lt;br /&gt;       ReceivedFor[0] = '\0';&lt;br /&gt;       ToAddress[0] = '\0';&lt;br /&gt;       CcAddress[0] = '\0';&lt;br /&gt;       ULen=0;&lt;br /&gt;       DLen=0;&lt;br /&gt;       if (argc&amp;gt;1)&lt;br /&gt;       {&lt;br /&gt;               arg = argv[1];&lt;br /&gt;               i = FindAt(arg);&lt;br /&gt;               if (arg[i]=='@')&lt;br /&gt;               {&lt;br /&gt;                       strncpy(UserName,arg,i);&lt;br /&gt;                       strccpy(DomainName,&amp;arg[i+1],' ');&lt;br /&gt;                       ULen=strlen(UserName);&lt;br /&gt;                       DLen=strlen(DomainName);&lt;br /&gt;               }&lt;br /&gt;               //printf("&amp;lt;Debug: Name: %s Domain: %s&amp;gt;",UserName,DomainName);&lt;br /&gt;&lt;br /&gt;       }&lt;br /&gt;       state = H_Unknown;&lt;br /&gt;       while (!feof(stdin))&lt;br /&gt;       {&lt;br /&gt;               fgets(InputLine,bufsize,stdin);&lt;br /&gt;               if (IsEmptyLine(InputLine))&lt;br /&gt;               {&lt;br /&gt;                       printf("X-RecFor-Recipient: ");&lt;br /&gt;                       if (ToAddress[0])&lt;br /&gt;                               printf("%s",ToAddress);&lt;br /&gt;                       else&lt;br /&gt;                       if (CcAddress[0])&lt;br /&gt;                               printf("%s",CcAddress);&lt;br /&gt;                       else&lt;br /&gt;                               printf("%s",ReceivedFor);&lt;br /&gt;                       printf("\n\n");&lt;br /&gt;                       break;&lt;br /&gt;               }&lt;br /&gt;               printf("%s",InputLine);&lt;br /&gt;               if (InputLine[0]&amp;gt;' ')&lt;br /&gt;               { // Enter a header&lt;br /&gt;                       if (strncmp("Received:",InputLine,9)==0)&lt;br /&gt;                       {&lt;br /&gt;                               //printf("&amp;lt;Debug:Found Received-header&amp;gt;\n");&lt;br /&gt;                               state = H_Received;&lt;br /&gt;                       }&lt;br /&gt;                       else&lt;br /&gt;                       if (strncmp("To:",InputLine,3)==0)&lt;br /&gt;                       {&lt;br /&gt;                               //printf("&amp;lt;Debug:Found To-header&amp;gt;\n");&lt;br /&gt;                               state = H_To;&lt;br /&gt;                       }&lt;br /&gt;                       else&lt;br /&gt;                       if (strncmp("Cc:",InputLine,3)==0)&lt;br /&gt;                       {&lt;br /&gt;                               //printf("&lt;&amp;lt;ebug:Found Cc-header&amp;gt;\n");                                 state = H_Cc;                         }                         else                                 state = H_Unknown;                 }                 switch (state)                 {                         case H_Received:                                 if (r_for=strstr(InputLine,"for"))                                 {                                         //printf("&amp;lt;Debug:Found email!&amp;gt;\n");                                         r_for+=3;                                         if (CopyEmailAddr(ReceivedFor,r_for)==NULL)                                                 state = H_Received_for;                                 }                                 break;                         case H_Received_for:                                 // check one line for email address                                 CopyEmailAddr(ReceivedFor,InputLine);                                 state = H_Received;                                 break;                         case H_To:                                 if (ULen)                                 {                                         linebrowse = &amp;InputLine[0];                                         while (linebrowse = CopyEmailAddr(TempAddress,linebrowse))                                         {                                                 i = FindAt(TempAddress);                                                 if (strsubcmp(TempAddress,UserName))                                                 {                                                               if (strsubcmp(&amp;TempAddress[i+1],DomainName))                                                         {                                                                 //printf("&lt;debug:found email=""&gt;\n");&lt;br /&gt;                                                               CopyEmailAddr(ToAddress,TempAddress);&lt;br /&gt;                                                       }&lt;br /&gt;                                               }&lt;br /&gt;                                       }&lt;br /&gt;                               }&lt;br /&gt;                               break;&lt;br /&gt;                       case H_Cc:&lt;br /&gt;                               if (ULen)&lt;br /&gt;                               {&lt;br /&gt;                                       linebrowse = &amp;InputLine[0];&lt;br /&gt;                                       while (linebrowse = CopyEmailAddr(TempAddress,linebrowse))&lt;br /&gt;                                       {&lt;br /&gt;                                               i = FindAt(TempAddress);&lt;br /&gt;                                               if (strsubcmp(TempAddress,UserName))&lt;br /&gt;                                               {&lt;br /&gt;                                                       if (strsubcmp(&amp;TempAddress[i+1],DomainName))&lt;br /&gt;                                                       {&lt;br /&gt;                                                               //printf("&amp;lt;Debug:Found email!&amp;gt;\n");&lt;br /&gt;                                                               CopyEmailAddr(CcAddress,TempAddress);&lt;br /&gt;                                                       }&lt;br /&gt;                                               }&lt;br /&gt;                                       }&lt;br /&gt;                               }&lt;br /&gt;                               break;&lt;br /&gt;&lt;br /&gt;               }&lt;br /&gt;       }&lt;br /&gt;       while (!feof(stdin))&lt;br /&gt;       {&lt;br /&gt;               InputLine[0]='\0';&lt;br /&gt;               fgets(InputLine,bufsize,stdin);&lt;br /&gt;               printf("%s",InputLine);&lt;br /&gt;       }&lt;br /&gt;       return (0);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;EOF&lt;br /&gt;cc /usr/local/src/xtmdaheader-1.1.c -o /usr/local/bin/xtmdaheader&lt;br /&gt;&lt;br /&gt;#END OF SCRIPT 1&lt;/debug:found&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111212880313287447?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111212880313287447/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111212880313287447' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111212880313287447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111212880313287447'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_03_01_archive.html#111212880313287447' title='Better Spam Protection Implementation, part 1'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111159967399935300</id><published>2005-03-23T17:31:00.000+02:00</published><updated>2005-12-29T16:41:25.780+02:00</updated><title type='text'>Humble and Smart</title><content type='html'>The more you learn about something, the more you realize how little you know about it.&lt;br /&gt;&lt;br /&gt;This isn't just philosophy; when people know nothing about a thing, they assume that there's "nothing to it". Then they confidently make decisions based on incomplete information. (It could be because interesting elements exploit the interplay of the simple and the complex. Or it could just be because small details aren't visible at a distance.)&lt;br /&gt;&lt;br /&gt;Paradoxically, bright people are more susceptible to this thinking. Bright people are accustomed to quickly understanding ideas outside of their field of expertise, and this understanding is often superior to experts'. A bright person can start to believe (subconsciously) that much of the work in a field is characterized by lack of understanding.&lt;br /&gt;&lt;br /&gt;This has ramifications for religious leadership. That religious leaders have insight into issues not technically within the sphere of religious practice is a doctrine of Judaism, and probably other religions as well. It's only logical; following Judaism is about living wisely, and someone with a deeper understanding of Judaism should have attained greater wisdom. In order to be truly wise, however, a person must be aware of his limitations. Maybe this awareness can be achieved by encountering sufficiently dramatic examples (for example the abuse cases involving religious leaders in recent years), or maybe it requires learning a little bit about alot of different things.&lt;br /&gt;&lt;br /&gt;(It is troubling to think that G-d confers special wisdom in a way that is completely independent of the natural working of the world. For one thing, thinking that you've got supernatural aid from G-d certainly exacerbates the problem described above. For another, there is no good way to tell when you got it, and when you don't. "Trust in God, but steer away from the rocks", applies here as well.&lt;br /&gt;&lt;br /&gt;At any rate, I don't think Judaism encourages completely ignoring the rules of the physical world. There's a gemara in niddah that gives advice about achieving various goals; in each case the gemara advises both acting according to natural way of the world, and &lt;em&gt;also&lt;/em&gt; praying for success. In this era characterized by hester panim ("G-d hiding His face"), we certainly shouldn't abdicate the responsibility to do our hishtadlus (effort), especially where other people are involved.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111159967399935300?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111159967399935300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111159967399935300' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111159967399935300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111159967399935300'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_03_01_archive.html#111159967399935300' title='Humble and Smart'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111116182329919357</id><published>2005-03-18T17:36:00.000+02:00</published><updated>2005-03-18T18:03:43.300+02:00</updated><title type='text'>Idiomatic Python</title><content type='html'>Programming languages, like human languages, each have their own idiomatic usage. Though there are many different ways to express a single thing, some patterns of expression just feel much more natural.&lt;br /&gt;&lt;br /&gt;The idiomatic style of python is beautiful.&lt;br /&gt;&lt;br /&gt;Here's an example. You'd like to allow categorizing emails using their subjects, by prefixing the normal subject with the category and a colon. So for a message with subject "game on tuesday", you could use subject "sports: game on tuesday". If no category is specified, you'd like to use "misc". Here's the Pythonic way to do it:&lt;br /&gt;&lt;pre&gt;try:&lt;br /&gt;       category, subject = headers['Subject'].split(':')&lt;br /&gt;except:&lt;br /&gt;       category, subject = 'misc', headers['Subject']&lt;/pre&gt;&lt;br /&gt;There are a few different features at work here:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;"It's easier to ask forgiveness than permission"&lt;/li&gt;   &lt;li&gt;Exceptions are used heavily&lt;/li&gt;   &lt;li&gt;Language support for collections is simple and easy&lt;br /&gt;  &lt;/li&gt; &lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111116182329919357?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111116182329919357/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111116182329919357' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111116182329919357'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111116182329919357'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_03_01_archive.html#111116182329919357' title='Idiomatic Python'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111049238020045721</id><published>2005-03-11T00:05:00.000+02:00</published><updated>2005-04-11T04:37:08.796+03:00</updated><title type='text'>"Startups" and Small Businesses</title><content type='html'>At least since the dot-com bubble, the idea of the startup has been enshrouded in glamor. Most recently Paul Graham posted &lt;a href="http://paulgraham.com/start.html"&gt;How to Start a Startup&lt;/a&gt;, but his advice is for dot-com-bubble type startups. He suggests that starting a company means compressing a career of 40 years into 4, and assumes that every new business will either flop or become an industry giant.&lt;br /&gt;&lt;br /&gt;It could be that when Graham says "startup", he means a company that would rather flop than settle for staying small. Only talking about these startups is strange for a few reasons. Many companies consider themselves successful without making a public stock offering, or being bought out for piles of cash. How about creating a successful small company first, on the way to becoming an industry giant later? And which ideas and strategies are appropriate for which goal? These questions are a lot more relevant today than how to handle a Venture Capitalist imposed CEO.&lt;br /&gt;&lt;br /&gt;After all, &lt;a href="http://www.census.gov/epcd/www/smallbus.html#EmpSize"&gt;though more people are employed by big companies, there are many more small companies than big ones&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111049238020045721?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111049238020045721/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111049238020045721' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111049238020045721'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111049238020045721'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_03_01_archive.html#111049238020045721' title='&quot;Startups&quot; and Small Businesses'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111037707278034909</id><published>2005-03-09T16:00:00.000+02:00</published><updated>2005-03-09T16:04:32.780+02:00</updated><title type='text'>Note to Future Self</title><content type='html'>Whenever I put something down in an unusual place, there's a strong chance I will "lose" it.&lt;br /&gt;&lt;br /&gt;Hopefully when I'm older I'll look back at this note and realize that I'm not going senile.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111037707278034909?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111037707278034909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111037707278034909' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111037707278034909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111037707278034909'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_03_01_archive.html#111037707278034909' title='Note to Future Self'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-111029916838290261</id><published>2005-03-08T18:17:00.000+02:00</published><updated>2007-04-02T02:52:45.690+03:00</updated><title type='text'>Ipod Shuffle for Lectures</title><content type='html'>The IPod Shuffle is a wonderful device. One more feature would make it perfect for listening to lecture series (or books on tape or language courses), without bloating its wonderfully simple interface.&lt;br /&gt;&lt;br /&gt;The IPod Shuffle should remember the current "song" after it's turned off.&lt;br /&gt;&lt;br /&gt;So apparently this is supported for purchases from ITunes and Audible. In order to get it to work with anything else, you have to &lt;a href="http://faac.sourceforge.net/oldsite/phorum/read.php?f=1&amp;i=5861&amp;amp;t=5861"&gt;use faac to create .m4b files&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;UPDATE: It works great. If you're using linux, get gnupod, mpg321, and faac. Then you can do something like:&lt;br /&gt;&lt;pre&gt;mkdir /mnt/ipod 2&gt;/dev/null&lt;br /&gt;mount /dev/sda1 /mnt/ipod&lt;br /&gt;for mp3 in *.mp3&lt;br /&gt;do&lt;br /&gt;  m4b=${mp3%.*}.m4b&lt;br /&gt;  mpg321 -w $mp3 | faac -b 10 -c 3500 - -o $m4b&lt;br /&gt;  gnupod_addsong.pl -m /mnt/ipod $m4b&lt;br /&gt;done&lt;br /&gt;mktunes.pl -m /mnt/ipod&lt;br /&gt;umount /mnt/ipod&lt;br /&gt;&lt;/pre&gt;Incidentally, it would be great if gnupod would expose a filesystem-type api to the ipod using fuse.&lt;br /&gt;&lt;br /&gt;UPDATE#2: Don't use gnupod; use the &lt;a href="http://shuffle-db.sourceforge.net/"&gt;iPod shuffle Database Builder&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-111029916838290261?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/111029916838290261/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=111029916838290261' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111029916838290261'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/111029916838290261'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_03_01_archive.html#111029916838290261' title='Ipod Shuffle for Lectures'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110971846431638585</id><published>2005-03-03T00:58:00.000+02:00</published><updated>2006-07-06T10:47:28.646+03:00</updated><title type='text'>Warn of Unsaved Changes Javascript</title><content type='html'>OK, this will get all the javascript out of my system. This one is intensely useful for web "applications". It warns the user if she tries to leave the form with unsubmitted changes, whether leaving by moving to a different page or by closing the window. It requires a recent firefox or ie browser.&lt;pre&gt;&amp;lt;body onLoad="lookForChanges()" onBeforeUnload="return warnOfUnsavedChanges()"&amp;gt;&lt;br /&gt;&amp;lt;form&amp;gt;&lt;br /&gt;&amp;lt;select name=a multiple&gt;&lt;br /&gt; &amp;lt;option value=1&amp;gt;1&lt;br /&gt; &amp;lt;option value=2&amp;gt;2&lt;br /&gt; &amp;lt;option value=3&amp;gt;3&lt;br /&gt;&amp;lt;/select&amp;gt;&lt;br /&gt;&amp;lt;input name=b value=123&amp;gt;&lt;br /&gt;&amp;lt;input type=submit&amp;gt;&lt;br /&gt;&amp;lt;/form&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;script&amp;gt;&lt;br /&gt;var changed = 0;&lt;br /&gt;function recordChange() {&lt;br /&gt; changed = 1;&lt;br /&gt;}&lt;br /&gt;function recordChangeIfChangeKey(myevent) {&lt;br /&gt; if (myevent.which &amp;&amp; !myevent.ctrlKey &amp;&amp; !myevent.ctrlKey)&lt;br /&gt;  recordChange(myevent);&lt;br /&gt;}&lt;br /&gt;function ignoreChange() {&lt;br /&gt; changed = 0;&lt;br /&gt;}&lt;br /&gt;function lookForChanges() {&lt;br /&gt; var origfunc;&lt;br /&gt; for (i = 0; i &lt; document.forms.length; i++) {&lt;br /&gt;  for (j = 0; j &lt; document.forms[i].elements.length; j++) {&lt;br /&gt;   var formField=document.forms[i].elements[j];&lt;br /&gt;   var formFieldType=formField.type.toLowerCase();&lt;br /&gt;   if (formFieldType == 'checkbox' || formFieldType == 'radio') {&lt;br /&gt;    addHandler(formField, 'click', recordChange);&lt;br /&gt;   } else if (formFieldType == 'text' || formFieldType == 'textarea') {&lt;br /&gt;    if (formField.attachEvent) {&lt;br /&gt;     addHandler(formField, 'keypress', recordChange);&lt;br /&gt;    } else {&lt;br /&gt;     addHandler(formField, 'keypress', recordChangeIfChangeKey);&lt;br /&gt;    }&lt;br /&gt;   } else if (formFieldType == 'select-multiple' || formFieldType == 'select-one') {&lt;br /&gt;    addHandler(formField, 'change', recordChange);&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;  addHandler(document.forms[i], 'submit', ignoreChange);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;function warnOfUnsavedChanges() {&lt;br /&gt; if (changed) {&lt;br /&gt;  if ("event" in window) //ie&lt;br /&gt;   event.returnValue = 'You have unsaved changes on this page, which will be discarded if you leave now. Click "Cancel" in order to save them first.';&lt;br /&gt;  else //netscape&lt;br /&gt;   return false;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;function addHandler(target, eventName, handler) {&lt;br /&gt; if (target.attachEvent) {&lt;br /&gt;  target.attachEvent('on'+eventName, handler);&lt;br /&gt; } else {&lt;br /&gt;  target.addEventListener(eventName, handler, false);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110971846431638585?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110971846431638585/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110971846431638585' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110971846431638585'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110971846431638585'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_03_01_archive.html#110971846431638585' title='Warn of Unsaved Changes Javascript'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110971879918962428</id><published>2005-03-02T01:09:00.000+02:00</published><updated>2006-01-24T05:00:19.740+02:00</updated><title type='text'>Telephone Shell Javascript Widget</title><content type='html'>Here's some javascript I wrote to coerce uniformly styled phone numbers. If you don't use any punctuation, it defaults to american style. You can enter unrestricted text &lt;em&gt;after&lt;/em&gt; the number. You should be able to copy the following into an html file to try it out.&lt;br /&gt;&lt;pre&gt;&amp;lt;form&amp;gt;&lt;br /&gt; phone #&amp;lt;input onkeypress="return phone_only(event)"&amp;gt;&lt;br /&gt;&amp;lt;/form&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;script&amp;gt;&lt;br /&gt;function phone_only(myevent) {&lt;br /&gt;        mykey = myevent.keyCode || myevent.which; //ie||netscape&lt;br /&gt;        myfield = myevent.srcElement || myevent.target; //ie||netscape&lt;br /&gt;        if (mykey == 8) //backspace (netscape only)&lt;br /&gt;                return true;&lt;br /&gt;        f = myfield.value;&lt;br /&gt;        g = myfield.value;&lt;br /&gt;        ndigits = f.replace(/-/,'').length;&lt;br /&gt;        ngroupdigits = g.replace(/.*-/,'').length;&lt;br /&gt;        if (ndigits == 0) {&lt;br /&gt;                if (50 &amp;lt;= mykey &amp;amp;&amp;amp; mykey &amp;lt;= 57) { //2-9, can't start with 0 or 1&lt;br /&gt;                        return true;&lt;br /&gt;                } else {&lt;br /&gt;                        return false;&lt;br /&gt;                }&lt;br /&gt;        } else if (ndigits &amp;lt;= 7) { //only need 2 hyphens: 123-456-7&lt;br /&gt;                if (32 &amp;lt;= mykey &amp;&amp; mykey &amp;lt;= 47 &amp;&amp; ngroupdigits != 0) { //punctuation&lt;br /&gt;                        myfield.value += "-";&lt;br /&gt;                        return false;&lt;br /&gt;                } else if (48 &lt;= mykey &amp;&amp; mykey &amp;lt;= 57) { //0-9&lt;br /&gt;                        if ((ngroupdigits % 4) == 3) {&lt;br /&gt;                                myfield.value += "-";&lt;br /&gt;                        }&lt;br /&gt;                        return true;&lt;br /&gt;                } else {&lt;br /&gt;                        return false;&lt;br /&gt;                }&lt;br /&gt;        } else {&lt;br /&gt;                return true;&lt;br /&gt;        }&lt;br /&gt;}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110971879918962428?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110971879918962428/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110971879918962428' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110971879918962428'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110971879918962428'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_03_01_archive.html#110971879918962428' title='Telephone Shell Javascript Widget'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110970055928807860</id><published>2005-03-01T19:28:00.000+02:00</published><updated>2005-03-01T20:12:55.453+02:00</updated><title type='text'>Forms Support in Javascript, not Template</title><content type='html'>Turns out it's pretty simple to populate forms generically in javascript. This means that your template engine doesn't need special html forms support; you can just use a pair of templating "for" loops to create the javascript data structure. You could even grab the data using xmlhttprequest. Html made the the mess, so html can clean it up. &lt;br /&gt;&lt;br /&gt;Here's an example form, followed by the code. You should be able to copy into a file and try it.&lt;br /&gt;&lt;pre&gt;&amp;lt;form&amp;gt;&lt;br /&gt;&amp;lt;input name=a&amp;gt;&lt;br /&gt;&amp;lt;input name=b type=checkbox value=x1&amp;gt;&lt;br /&gt;&amp;lt;input name=b type=checkbox value=y1&amp;gt;&lt;br /&gt;&amp;lt;input name=b type=checkbox value=z1&amp;gt;&lt;br /&gt;&amp;lt;select name=c multiple&amp;gt;&lt;br /&gt; &amp;lt;option value=x2&amp;gt;X2&lt;br /&gt; &amp;lt;option value=y2&amp;gt;Y2&lt;br /&gt; &amp;lt;option value=z2&amp;gt;Z2&lt;br /&gt;&amp;lt;/select&amp;gt;&lt;br /&gt;&amp;lt;button onClick=&amp;quot;populateForm(this.form, {'a':'x0',b:['x1','z1'],'c':['x2','z2']}); return false&amp;quot;&amp;gt;Populate&amp;lt;/button&amp;gt;&lt;br /&gt;&amp;lt;input type=reset&amp;gt;&lt;br /&gt;&amp;lt;/form&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;script&amp;gt;&lt;br /&gt;function populateForm(myForm,myHash) {&lt;br /&gt;     for (var k in myForm) {&lt;br /&gt;             if (!(k in myForm) || !(k in myHash)) continue;&lt;br /&gt;             if (typeof myHash[k] == 'string')&lt;br /&gt;                     myHash[k] = [myHash[k]];&lt;br /&gt;             if (myForm[k].type == 'text') {&lt;br /&gt;                     myForm[k].value = myHash[k][0];&lt;br /&gt;             } else {&lt;br /&gt;                     var field = 'type' in myForm[k] &amp;amp;&amp;amp; myForm[k].type.match('^select') ? 'selected' : 'checked';&lt;br /&gt;                     var selected = Array();&lt;br /&gt;                     for (var i=0; i&amp;lt;myHash[k].length; i++)&lt;br /&gt;                             selected[myHash[k][i]] = 1;&lt;br /&gt;                     for (var i=0; i&amp;lt;myForm[k].length; i++)&lt;br /&gt;                             myForm[k][i][field] = myForm[k][i].value in selected;&lt;br /&gt;             }&lt;br /&gt;     }&lt;br /&gt;}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110970055928807860?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110970055928807860/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110970055928807860' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110970055928807860'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110970055928807860'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_03_01_archive.html#110970055928807860' title='Forms Support in Javascript, not Template'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110903758286004713</id><published>2005-02-22T03:36:00.000+02:00</published><updated>2005-02-25T20:47:55.633+02:00</updated><title type='text'>Even More On Presentation Done Right</title><content type='html'>I changed my mind back; StringTemplate isn't the way to go.&lt;br /&gt;&lt;br /&gt;Templates are neither necessary nor sufficient for separating model and view (presentation). Not necessary because the separation is really accomplished by the model/view protocol, and not sufficient because presentation code can always seep into the model code. In fact, the StringTemplate approach &lt;em&gt;requires&lt;/em&gt; complex views to be implemented in the model code.&lt;br /&gt;&lt;br /&gt;A great m/v separation may be achieved by just having separate code for model and for view, even in the same language. The only requirements are on the data passed from the model to the view:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;it should be available before the view code runs&lt;/li&gt;   &lt;li&gt;it should consist only of lists of lists, and lists of opaque objects&lt;/li&gt; &lt;/ol&gt; Flagrant violations are possible (like the view code writing to a database), but should be easy to spot. The view code isn't artificially limited; it can implement fancy animations or fractal decorations, for example.&lt;br /&gt;&lt;br /&gt;It's probably worth noting explicitly that the view depends on the model and not vice versa.&lt;br /&gt;&lt;br /&gt;Recent javascript interfaces from google seem to contradict requirement number one, but really they just use a lazy loaded model. The view treats the model as if it's present, but because of the model's prohibitive size, each piece is loaded only just before it's needed.&lt;br /&gt;&lt;br /&gt;The StringTemplates author acknowledges that his solution is insufficient to keep view logic out of the model code. The model code could pass data like "the color red" to the view layer. Since StringTemplates is such a simple language, more complex view features must be implemented with the help of model code. Any possible document may be generated, but only with the help of the model code.&lt;br /&gt;&lt;br /&gt;So if m/v separation isn't the point of templates, what is? Separation of roles. The roles of programmer and designer aren't necessarily performed by different people, but they do require different approaches. The designer role includes everything that can be done in a WYSIWYG editor, with all visible elements, "includes", and conditionals. As document formats evolve, this could become part of the normative editor functionality. CSS visibility could be hacked to support conditionals, and XInclude takes care of the rest.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110903758286004713?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110903758286004713/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110903758286004713' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110903758286004713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110903758286004713'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_02_01_archive.html#110903758286004713' title='Even More On Presentation Done Right'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110891760957616519</id><published>2005-02-20T18:12:00.000+02:00</published><updated>2005-02-21T17:38:05.606+02:00</updated><title type='text'>Google Maps and Free Source</title><content type='html'>If you haven't already, check out &lt;a href="http://maps.google.com/"&gt;Google Maps&lt;/a&gt;; it's extremely cool. Besides being a generally superior implementation of maps, it loads new maps &lt;em&gt;without reloading the page&lt;/em&gt; in your browser, just like &lt;a href="http://gmail.com/"&gt;gmail&lt;/a&gt;. After you view a map, its pieces are cached by your browser. This means they're fast, and can be viewed even without an internet connection.&lt;br /&gt;&lt;br /&gt;A yet un-remarked-upon feature of these "network applications" is how similar they are to free source. Though the intellectual property restrictions of google and of free source are just as strict as those of the most proprietary software vendor, the implementations of both google maps and GPL'ed code are available for anyone to poke at. GPL developers have so much faith in their model that they don't worry about commercial competitors, and google developers apparently have so much confidence in their own skills that they don't worry.&lt;br /&gt;&lt;br /&gt;You already have free access to both the google maps client software and the map data. Without too much difficulty, you could extend either. For example, you could use the google client to view your own map data, you could run your own software on the map data (which is already cached on your pc), and people are already &lt;a href="http://libgmail.sourceforge.net/googlemaps.html"&gt;hacking new features onto the whole google maps solution&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The major change in these new applications is that the interface is exposed. With regular google search, you either have to use the Google Web APIs or else screenscrape the html pages. With a little reverse engineering of the new applications, you can access the same interface that's used as part of their normal functioning.&lt;br /&gt;&lt;br /&gt;(The Google Web APIs limit developers to 1000 queries a day, and presumably a higher volume of screenscraping or access to the new APIs would get shut down by Google.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110891760957616519?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110891760957616519/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110891760957616519' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110891760957616519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110891760957616519'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_02_01_archive.html#110891760957616519' title='Google Maps and Free Source'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110753221975463580</id><published>2005-02-20T17:22:00.000+02:00</published><updated>2005-02-24T17:25:16.123+02:00</updated><title type='text'>The Internet Changing Everything</title><content type='html'>&lt;ul&gt;   &lt;li&gt;Traditional categories of media become irrelevant&lt;p&gt;Does a given piece of information belong in a book, an academic paper, a weekly magazine article, an editorial, a letter to the editor? The internet makes the distinctions increasingly irrelevant.&lt;br /&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;The description of an idea may be canonicalized&lt;p&gt;A web page is an expression of an idea that is universally available (at least theoretically). It's easy to refer to, and easy to maintain. The internet will one day provide a distributed wikipedia, in which every idea has a URI and page(s) containing all public human knowledge of that idea.&lt;br /&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;The context of an idea may be completely specified&lt;/li&gt;&lt;p&gt;Traditional bibliographies are klunky in comparison. It will be possible to link a given piece of information with &lt;em&gt;every&lt;/em&gt; other piece of information on which it relies. That metadata will itself be data, subject to easy analysis.&lt;br /&gt;&lt;/p&gt;&lt;/ul&gt;Apologies for early outline version.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110753221975463580?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110753221975463580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110753221975463580' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110753221975463580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110753221975463580'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_02_01_archive.html#110753221975463580' title='The Internet Changing Everything'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110865321687392124</id><published>2005-02-17T16:30:00.000+02:00</published><updated>2006-05-07T02:46:20.906+03:00</updated><title type='text'>URL Features</title><content type='html'>Computers should record all operations on URLs. For example, I should have a list of URLs that I've emailed (along with the recipient and date), that I've instant-messaged, or printed, or transferred, or mentioned in any document.&lt;br /&gt;&lt;br /&gt;"URL" means both local and remote. I should have a full history of every file I've opened (explicitly), even if it wasn't using the browser. Another operation that I want recorded is when I change files, and when I post forms.&lt;br /&gt;&lt;br /&gt;I should get a smarter handling of "cached" and downloaded files. Browsers already have caches, so why I should have to manually make copies of files for speed or reliable access?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110865321687392124?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110865321687392124/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110865321687392124' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110865321687392124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110865321687392124'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_02_01_archive.html#110865321687392124' title='URL Features'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110799036990436077</id><published>2005-02-10T01:06:00.000+02:00</published><updated>2005-02-15T23:57:10.280+02:00</updated><title type='text'>Perl Problems</title><content type='html'>&lt;h2&gt;1 Obscure Features&lt;/h2&gt;  &lt;p&gt;The core language has so many features that even the greatest perl wizard does not know them all. Find a wizard and ask him how many of the following features from the core language he understands (without consulting the manual).&lt;/p&gt;  &lt;ol&gt; &lt;li&gt;&lt;pre&gt; split(' ') vs split(/ /) vs split('') vs split(//)  &lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;pre&gt; $x{'a', 'b'} vs @x{'a', 'b'}&lt;/pre&gt;  &lt;/li&gt;&lt;li&gt;&lt;pre&gt; $[ = 3&lt;/pre&gt;  &lt;/li&gt;&lt;li&gt;&lt;pre&gt; [{foo =&gt; 1, bar =&gt; 2}, "FOO", "BAR"]&lt;/pre&gt; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;And here's a realistic example of idiomatic perl:&lt;/p&gt;  &lt;pre&gt;    sub with_gs_acct_check_digit{"$_[0]-".substr(10-(map$_[2]+=$_,map/\d/?$_[1]++%2?split'',$_*2:$_:0,split'',$_[0])[-1]%10,-1)}&lt;/pre&gt; &lt;p&gt; Since these features usually address a real need, they can be very tempting to use. Even if someone were to do the work to specify a sane perl subset, there is no tool to enforce its use. Often a perl expert isn't aware that the language features that he uses are obscure or difficult for the nonexpert to understand.&lt;/p&gt;  &lt;p&gt;Perl's fast feature accretion is a direct result of its core design philosophy, "There's More Than One Way To Do It".&lt;/p&gt;  &lt;h2&gt;2 Few Errors are Caught by the Compiler&lt;/h2&gt;  &lt;p&gt;Since every new feature is encoded using a fixed set of operators, very few errors actually cause a compiler error.&lt;/p&gt;  &lt;pre&gt;    print "Strings are equal\n" if "abba" == "baba";&lt;/pre&gt; &lt;h3&gt; 2.1 Context Confusion&lt;/h3&gt;  &lt;p&gt;Every perl expression has several entirely different results depending on its "context", the code in which the expression occurs. The following example will trip up even experienced perl coders:&lt;/p&gt;  &lt;pre&gt;    sub myPrint($) {&lt;br /&gt;        my $arg = @_;&lt;br /&gt;        print "the first argument is $arg ?\n";&lt;br /&gt;    }&lt;/pre&gt; &lt;h2&gt; 3 Unsafe Features&lt;/h2&gt;  &lt;p&gt;Many commonly used features are unsafe. The "use strict" directive only catches the most blatant.&lt;/p&gt;  &lt;h3&gt;3.1 $_&lt;/h3&gt;  &lt;p&gt;For example, one of perl's major conveniences is the $_ short-hand for referring to the current index of a loop. The following is great way to print upper-cased versions of some strings. &lt;/p&gt;  &lt;pre&gt;    @t = qw( ibm dell msft );&lt;br /&gt;    for (@t) {&lt;br /&gt;        print uc "$_\n"&lt;br /&gt;    }&lt;/pre&gt; &lt;p&gt; However, if you want to instead use a different function in place of "uc", this code may fail in mysterious ways. Functions called in the body of the loop can alter what the $_ reference refers to, and neither the caller nor the callee may realize the danger.&lt;/p&gt;  &lt;h3&gt;3.2 Exceptions&lt;/h3&gt;  &lt;p&gt;Exception support is inconsistent and dangerous. When most function fail, they just return false and sometimes an error code. Other functions expect to be called in "eval blocks", and will otherwise cause the entire program to terminate (e.g. mkpath from File::Path)&lt;/p&gt;  &lt;h3&gt;3.3 Auto-vivification&lt;/h3&gt;  &lt;p&gt;Another example is auto-vivification, or the on-the-fly creation of datastructures. For the following data structure:&lt;/p&gt;  &lt;pre&gt;    use strict;&lt;br /&gt;    my %myhash1=( "a"=&gt;1, "b"=&gt;2 );&lt;br /&gt;    my %myhash2 =( "myhash1"=&gt;\%myhash1, "c"=&gt;3, "d"=&gt;4 );&lt;/pre&gt; &lt;p&gt; Perl will properly catch the error:  &lt;/p&gt;  &lt;pre&gt;    $myhash3{c}++;            # %myhash3 is not defined&lt;/pre&gt; &lt;p&gt; But will happily allow:  &lt;/p&gt;  &lt;pre&gt;    $myhash2{myhash3}{c}++;   # a new hash will be created!&lt;/pre&gt; &lt;h2&gt; 4 Data Structures&lt;/h2&gt;  &lt;p&gt;Nested data structures in perl are unwieldy. They require using references, and most people are confused by references.  &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110799036990436077?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110799036990436077/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110799036990436077' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110799036990436077'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110799036990436077'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_02_01_archive.html#110799036990436077' title='Perl Problems'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110615748500467729</id><published>2005-02-09T18:15:00.000+02:00</published><updated>2006-01-18T23:29:23.300+02:00</updated><title type='text'>Reusing Software</title><content type='html'>A big difference between software and physical engineering is that software changes greatly over the course of its life. The object oriented programming approach is supposed to make this change easier and more reliable. Instead of duplicating and modifying code, we'd like to extend existing code and make our changes in the extensions.&lt;br /&gt;&lt;br /&gt;There are still a few impediments to reuse in popular platforms. The following is a small collection of research into these impediments.&lt;br /&gt;&lt;br /&gt;There mustn't be conflicts between new symbols added to the base code and the extensions. It wouldn't be difficult for languages to support this better.&lt;br /&gt;&lt;br /&gt;The non-private call graph of public and protected methods in the parent mustn't change.&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.cas.mcmaster.ca/%7Eemil/publications/fragile/"&gt;A Study of the Fragile Base Class Problem&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www-2.cs.cmu.edu/%7Ealdrich/papers/selective-open-recursion.pdf"&gt;Selective Open Recursion&lt;/a&gt;&lt;br /&gt;  &lt;/li&gt;  &lt;/ul&gt; There must be a way to better encapsulate objects.&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;&lt;a href="http://homepages.cwi.nl/%7Edave/writing/papers/ownership.ps.gz"&gt;Ownership Types for Flexible Alias Protection&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a href="http://pmg.csail.mit.edu/%7Echandra/publications/popl03.pdf"&gt;Ownership Types for Object Encapsulation&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt; There must be a way to encapsulate and compose concurrent access to state.&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.research.microsoft.com/%7Esimonpj/papers/stm/index.htm"&gt;Composable memory transactions&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a href="http://www.ifs.uni-linz.ac.at/%7Eecoop/cd/papers/1628/16280205.pdf"&gt;An Object-Oriented Effects System&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a href="http://www.cag.lcs.mit.edu/%7Erinard/paper/vmcai05.purity.pdf"&gt;Purity and Side Effect Analysis for Java Programs&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110615748500467729?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110615748500467729/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110615748500467729' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110615748500467729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110615748500467729'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_02_01_archive.html#110615748500467729' title='Reusing Software'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110496688290704112</id><published>2005-01-27T01:56:00.000+02:00</published><updated>2007-03-24T11:31:48.166+02:00</updated><title type='text'>Software Commodification</title><content type='html'>Though there's been a lot of talk about software commodification (and commoditization), I've never seen the issues formulated simply, so here goes...&lt;br /&gt;&lt;br /&gt;A commodity is any product which meets some agreed upon criteria, such that any instance of that commodity may be substituted for any other. A quart of milk from any supplier will satisfy your cupcake recipe, no matter who produces it, so milk is a commodity. A necktie, however, is subject to all sorts of weird style criteria, so it is not a commodity. It might not even be your color.&lt;br /&gt;&lt;br /&gt;All software programs are commodities in essence. Programs follow logical rules and perform to a specification, but we can't say a given program is a commodity before it has an actual substitute. So commodity nature is revealed when a given piece of software acquires competing alternatives.&lt;br /&gt;&lt;br /&gt;Most software alternatives are not perfect substitutes in the sense that you can switch implementations and barely notice. Usually switching requires retraining the people that use the product and porting the software that uses the product. Vendors obviously want to keep switching as difficult as possible, and techniques for doing so are called "lock-in". By definition, strong lock-in hurts the consumer, but it also usually hurts the consumer by creating an inferior product. A product with strong lock-in will generally be monothilic, have complicated interfaces, and have hidden dependencies.&lt;br /&gt;&lt;br /&gt;Given a choice, anyone (whether selling software or anything else) would prefer to have their product not to be a commodity. This is because markets are especially efficient at setting commodity prices, and this means suppliers will have stiff competition.&lt;br /&gt;&lt;br /&gt;It's worse to have your software product become a commodity. This is because of the nature of software (and any non-physical product). The first copy of your software will cost you $2,000,000 but every subsequent copy will cost you only $2. This means that when someone enters your market, they've already done the hard part, and there's no incentive to leave. More importantly, the price of a software product is completely arbitrary. A price war could bring prices all the way down to zero.&lt;br /&gt;&lt;br /&gt;Free competitors may be particularly formidable. Only with software is free competition realistic, because with physical products, revenue must reliably exceed costs. Free software makes it particularly easy to pool contributions from disparate sources, with very little administrative overhead, and very little reliance on a single controlling entity. (If a maintainer isn't doing a sufficiently good job, then someone may "fork" the development effort.) Free efforts also generally aren't motivated to lock-in.&lt;br /&gt;&lt;br /&gt;All things being equal, it's desirable for software vendors to have the other software that they depend on to be commodified. This is for a few reasons: your dependencies have power over your product, and when your dependencies are cheaper, your overall product solution will be cheaper. There'll be a larger market for your product.&lt;br /&gt;&lt;br /&gt;So if free software is so easy and desirable, how can a commercial software vendor stay in business? By presenting a moving target. Any given software release may be straightforwardly commodified, but the release process may not be. No entity or group of entities will have external incentive to track a series of upgrades. This is partially why "tying" is so important to a large software vendor, because tying is the only way for a mature product to escape commodification.&lt;br /&gt;&lt;br /&gt;Ironically, the vendor is really in the business of selling timely upgrades, a service business which uses the base software product as merely a barrier to entry.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110496688290704112?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110496688290704112/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110496688290704112' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110496688290704112'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110496688290704112'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_01_01_archive.html#110496688290704112' title='Software Commodification'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110676441412937661</id><published>2005-01-26T20:32:00.000+02:00</published><updated>2005-01-26T22:36:16.523+02:00</updated><title type='text'>Intuitive Interfaces</title><content type='html'>An interface can be intuitive for a many reasons:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It works like other similar interfaces that the user has seen. (Green means "go".)&lt;/li&gt;&lt;li&gt;It's logical. (Cars' signalling interface correspond to the way that you turn the wheel.)&lt;/li&gt;&lt;li&gt;It's internally consistent. (The same abstraction works the same way in different contexts.)&lt;/li&gt;&lt;li&gt;It has a shallow learning curve. &lt;ul&gt;&lt;li&gt;It has helpful pointers, ideally inobtrusive. (Examples are popup help bubbles and &lt;a href="http://www.piemenus.com/"&gt;pie menus&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;It allows safe experimentation. (You can "undo" any operation.)&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;It's simple. :)&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110676441412937661?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110676441412937661/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110676441412937661' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110676441412937661'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110676441412937661'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_01_01_archive.html#110676441412937661' title='Intuitive Interfaces'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110674952165799100</id><published>2005-01-26T16:25:00.000+02:00</published><updated>2005-01-26T23:33:09.000+02:00</updated><title type='text'>Python Evolution and AOP</title><content type='html'>An interesting trend in the evolution of the python language is that it has acquired ways of hooking into more and more code points that are not traditionally hooked into.&lt;br /&gt;&lt;br /&gt;For a while, python has had metaclasses, which allow customizing the behavior of whole classes of classes :). These metaclasses allow running code on class creation, and routinely involve customizing object creation.&lt;br /&gt;&lt;br /&gt;In order to &lt;a href="http://naeblis.cx/rtomayko/2005/01/20/getters-setters-fuxors"&gt;obviate java's setter/getter pattern&lt;/a&gt;, python has the ability to run code on getting an attribute or setting an attribute or both.&lt;br /&gt;&lt;br /&gt;Recently, python attained a decorator feature, which allows running code on function/method creation. This feature was originally motivated by wanting to specify things like a method being "static".&lt;br /&gt;&lt;br /&gt;Now there's talk about implementing type-checking use adaption of function/method arguments and return values.&lt;br /&gt;&lt;br /&gt;This trend could seem a lot like Aspect Oriented Programming, but it has the important difference that the path to the hook code is always evident at the hooked code. A main point of AOP is perfect "obliviousness", according to which you can alter the behavior of foreign code without making any modification to it. In python, the main code body can be oblivious of the hook, but it's always preceded by an explicit reference to the hook, almost like an annotation.&lt;br /&gt;&lt;br /&gt;In python, each of these hooking mechanisms has a different syntax, presumably tailored to its primary use case. These features are mostly made possible by python's easy introspection support, and by its uniform "object" treatment of all of these abstractions.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110674952165799100?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110674952165799100/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110674952165799100' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110674952165799100'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110674952165799100'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_01_01_archive.html#110674952165799100' title='Python Evolution and AOP'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110660833395871180</id><published>2005-01-24T21:27:00.000+02:00</published><updated>2006-07-02T22:02:32.680+03:00</updated><title type='text'>Managing Change</title><content type='html'>It's time to release an upgrade to your whiz-bang widget library. If you want to avoid breaking all the code that people have written to use and even extend your library, here's what to do.&lt;br /&gt;&lt;br /&gt;Obviously, don't remove public and protected methods, or change their semantics. For protected methods, this includes having them continue to call other nonprivate methods under the same conditions.&lt;br /&gt;&lt;br /&gt;Less obviously, if you're creating &lt;em&gt;new&lt;/em&gt; public or protected methods, you should move your code to an entirely new class! Someone may have extended your class with a method that has the same signature that you've just added, causing a needless conflict. Under the old class, create proxy classes that delegate every method to the new code. You don't have to worry about the maintenance overhead, because these proxies represent the legacy interface; you shouldn't have to change them later.&lt;br /&gt;&lt;br /&gt;This hints at the fact that your library should be very careful about calling its own nonprivate methods. Calling internal nonprivate methods should be reserved for supported abstractions, because your library will down-call into extensions of these methods. If you don't want to support the abstraction, move the implementation into a private method. Have your internal code call the private method, and have your public method just be a wrapper for clients.&lt;br /&gt;&lt;br /&gt;This approach is not so elegant because it requires code changes in order to support unchanging function. Maybe languages should support using interfaces for encapsulation, so that any symbols not present in the specified interface(s) would be completely hidden. However, all the recent python typechecking and adaption thinking seems to be focused on method calls, not base class specification.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110660833395871180?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110660833395871180/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110660833395871180' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110660833395871180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110660833395871180'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_01_01_archive.html#110660833395871180' title='Managing Change'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110487964665375306</id><published>2005-01-06T23:09:00.000+02:00</published><updated>2007-03-09T02:58:56.486+02:00</updated><title type='text'>Minimum Curriculum</title><content type='html'>Everyone should learn the most important ideas of human civilization. There should be a year-long lecture course that introduces all the "must see" ideas, the best that the human race has found, the stuff that would be tragic for a person to have lived and never learn. Certainly many things require lengthy study to be useful, and many things are already as clear as day to many people, but there are many important ideas of which educated people are ignorant.&lt;br /&gt;&lt;br /&gt;Even if this makes sense for ideas, it certainly makes no sense for art. The survey courses in dance, art history, music history, and world literature probably can't be meaningfully condensed any further. But no one should miss out on the major ideas of the introductory courses in math, astronomy, physics, chemistry, biology, psychology, economics, computer science, philosophy, political science, philosophy, and history. Some ideas fall through the cracks of all of these intro courses. (For example, what about the central points of &lt;a href="http://www.amazon.com/exec/obidos/tg/detail/-/067974195X/104-8889442-9315115?v=glance"&gt;The Death and Life of Great American Cities&lt;/a&gt;?) Some ideas are also too new to make it into conventional courses. For many ideas, only a few minutes explanation would be sufficient.&lt;br /&gt;&lt;br /&gt;Many survey courses take the historical approach, but in this context it would waste too much time. To make it more interesting, the course (and more importantly the reading list) could touch on the limits of human knowledge and current work.&lt;br /&gt;&lt;br /&gt;I originally had this idea in yeshiva, in a spirit of parochialism: "take this course, and then forget about the rest." Ironically, the course would probably not be popular with the insular (even if it were to omit evolution). This idea came back to me recently, thinking about John Rawls. I realized that neither my college survey in humanities nor intro to philosophy mentioned him.&lt;br /&gt;&lt;br /&gt;The following are the ideas that I could come with quickly; please suggest more.&lt;br /&gt;&lt;br /&gt;big bang, scale and elements of the universe, basic probability, limits, idea of calculus, newton's laws, four forces, electricity, nature of light, relativity, phases of matter, entropy, periodic table, cells, virii, bacteria, dna, systems of the body, evolution, milgram study, the unconscious, supply and demand, how a computer works and what a program looks like, urls, kant's categorical imperative, veil of ignorance, a myriad of -isms: utilitarianism, facism/socialism/capitalism(democracy), world religions, epistemology, problem of induction, logic and godel for dummies, mixed-use cities, human history in 30 minutes :), how toilets work&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110487964665375306?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110487964665375306/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110487964665375306' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110487964665375306'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110487964665375306'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_01_01_archive.html#110487964665375306' title='Minimum Curriculum'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110493758826913956</id><published>2005-01-05T17:04:00.000+02:00</published><updated>2007-02-06T04:12:40.883+02:00</updated><title type='text'>G-d Exists, so I could be Wrong</title><content type='html'>From yesterday's new york times article "God (or Not), Physics and, of Course, Love: Scientists Take a Leap":&lt;br /&gt;&lt;p&gt;&lt;strong&gt;David Myers &lt;/strong&gt;&lt;br /&gt;&lt;em&gt;Psychologist, Hope College; author, "Intuition"&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;As a Christian monotheist, I start with two unproven axioms:&lt;/p&gt;  &lt;p&gt;1. There is a God.&lt;/p&gt;  &lt;p&gt;2. It's not me (and it's also not you).&lt;/p&gt;  &lt;p&gt;Together, these axioms imply my surest conviction: that some of my beliefs (and yours) contain error. We are, from dust to dust, finite and fallible. We have dignity but not deity.&lt;/p&gt;  &lt;p&gt;And that is why I further believe that we should &lt;/p&gt;  &lt;p&gt;a) hold all our unproven beliefs with a certain tentativeness (except for this one!), &lt;/p&gt;  &lt;p&gt;b) assess others' ideas with open-minded skepticism, and &lt;/p&gt;  &lt;p&gt;c) freely pursue truth aided by observation and experiment. &lt;/p&gt;  &lt;p&gt;This mix of faith-based humility and skepticism helped fuel the beginnings of modern science, and it has informed my own research and science writing. The whole truth cannot be found merely by searching our own minds, for there is not enough there. So we also put our ideas to the test. If they survive, so much the better for them; if not, so much the worse.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110493758826913956?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110493758826913956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110493758826913956' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110493758826913956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110493758826913956'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_01_01_archive.html#110493758826913956' title='G-d Exists, so I could be Wrong'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110487013978881882</id><published>2005-01-04T18:58:00.000+02:00</published><updated>2007-03-25T23:01:48.733+02:00</updated><title type='text'>Core Assumptions</title><content type='html'>A college friend gave me a compliment; he said that when I argue with someone, I persist only until discovering his assumption that conflicts with my assumptions.&lt;br /&gt;&lt;br /&gt;Wouldn't it be great if all disagreements could be reduced to conflicting core assumptions? If the parties could agree on this reduction, then maybe the assumptions themselves could be meaningfully discussed and compared.&lt;br /&gt;&lt;br /&gt;Of course, I'm thinking of the electoral split of recent times. Could it be that conservatives simply don't accept the idea of the &lt;a href="http://en.wikipedia.org/wiki/Veil_of_ignorance"&gt;Veil of Ignorance&lt;/a&gt;?&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110487013978881882?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110487013978881882/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110487013978881882' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110487013978881882'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110487013978881882'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_01_01_archive.html#110487013978881882' title='Core Assumptions'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110485740419167263</id><published>2005-01-04T17:59:00.000+02:00</published><updated>2007-01-31T06:23:14.200+02:00</updated><title type='text'>Beating Java on Its Own Turf</title><content type='html'>The author of python, &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=85551"&gt;Guido van Rossum is writing some great stuff about type-checking in python&lt;/a&gt;, which will &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=86641"&gt;enable even more specific contracts&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This is exciting because it promises to achieve the safety of java with the simplicity of python. Safety is one of the three technical reasons that people still use java instead of python. The other two are performance and enterprise software. Performance is being addressed by the &lt;a href="http://codespeak.net/pipermail/pypy-dev/2004q4/001677.html"&gt;newly funded&lt;/a&gt; &lt;a href="http://codespeak.net/pypy/"&gt;PyPy&lt;/a&gt;. Python already has much of the java enterprise technology, just not in the form of ballyhooed specifications. (For the remaining technologies, it's not clear that the "enterprise solution" achieves better reliability or scalibility than folks' nonstandard solutions.)&lt;br /&gt;&lt;br /&gt;That the business community seems to care more about these specifications than about the actual technology may be for the same reason that it doesn't greatly prefer Sun's specifying Java over Microsoft's owning .NET. (Without a patent grant, the incomplete .NET standards work is almost worthless.) One would think that having one company write specifications for which many companies can build implementations would be much safer, and would create much more open software. That the wholely proprietary .NET is even considered a contender implies that people only care about the company that writes the interfaces.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110485740419167263?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110485740419167263/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110485740419167263' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110485740419167263'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110485740419167263'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2005_01_01_archive.html#110485740419167263' title='Beating Java on Its Own Turf'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110418065501824654</id><published>2004-12-27T22:44:00.000+02:00</published><updated>2007-04-17T17:24:36.953+03:00</updated><title type='text'>Special Characters and Gmail</title><content type='html'>Not only does gmail filter out ".", it also chops off everything from the first "+".&lt;br /&gt;&lt;br /&gt;This enables using &lt;a href="http://tmda.net/"&gt;tmda&lt;/a&gt; or simply filtering on what address you choose to give. (Similar to how some people give vendors their names with different middle initials, in order to track how their name got onto different lists.)&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110418065501824654?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110418065501824654/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110418065501824654' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110418065501824654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110418065501824654'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_12_01_archive.html#110418065501824654' title='Special Characters and Gmail'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110184460451944150</id><published>2004-12-20T21:49:00.000+02:00</published><updated>2005-01-07T04:19:26.706+02:00</updated><title type='text'>JOtherComboBox</title><content type='html'>Java is a little wack. Its selection box gui widgets have items which are either editable or not. The following is the necessarily verbose way to create an uneditable selection box that allows adding a new item with an explicit action. (Contrast with autocompletion in an editable field, which provides a very low barrier to adding new items.)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;import java.awt.Component;&lt;br /&gt;import java.awt.event.ActionEvent;&lt;br /&gt;import java.awt.event.ActionListener;&lt;br /&gt;import java.awt.event.KeyEvent;&lt;br /&gt;import java.awt.event.KeyListener;&lt;br /&gt;import javax.swing.JComboBox;&lt;br /&gt;import javax.swing.JFrame;&lt;br /&gt;import javax.swing.ComboBoxModel;&lt;br /&gt;import java.util.Vector;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;*&lt;br /&gt;* JComboBox for which selecting a particular item allows editing a new item&lt;br /&gt;*/&lt;br /&gt;public class JOtherComboBox extends JComboBox {&lt;br /&gt;	int otherIndex;&lt;br /&gt;	ActionListener otherItemActionListener = new ActionListener() {&lt;br /&gt;		public void actionPerformed(ActionEvent e) {&lt;br /&gt;			JOtherComboBox widget = JOtherComboBox.this;&lt;br /&gt;			if (widget.getSelectedIndex() == otherIndex) {&lt;br /&gt;				widget.setSelectedItem(null);&lt;br /&gt;				widget.setEditable(true);&lt;br /&gt;&lt;br /&gt;				widget.requestFocus();&lt;br /&gt;				widget.getEditor().getEditorComponent().addKeyListener(new KeyListener() {&lt;br /&gt;					public void keyTyped(KeyEvent e) { work(e); }&lt;br /&gt;					public void keyPressed(KeyEvent e) { work(e); }	&lt;br /&gt;					public void keyReleased(KeyEvent e) { work(e); }&lt;br /&gt;					public void work(KeyEvent e) {&lt;br /&gt;						((Component)e.getSource()).removeKeyListener(this);&lt;br /&gt;						e.consume();&lt;br /&gt;					}&lt;br /&gt;				});						&lt;br /&gt;			} else if (widget.getSelectedIndex() &gt;= 0) {&lt;br /&gt;				widget.setEditable(false);&lt;br /&gt;			}&lt;br /&gt;		}&lt;br /&gt;	};&lt;br /&gt;	&lt;br /&gt;	public JOtherComboBox(Object[] arg0) { super(arg0); init(); }&lt;br /&gt;	public JOtherComboBox(Vector arg0) { super(arg0); init(); }&lt;br /&gt;	public JOtherComboBox(ComboBoxModel arg0) { super(arg0); init(); }&lt;br /&gt;	public JOtherComboBox() { super(); init(); }&lt;br /&gt;&lt;br /&gt;	public void init() {&lt;br /&gt;		this.addActionListener(otherItemActionListener);&lt;br /&gt;	}&lt;br /&gt;&lt;br /&gt;	public int getOtherIndex() {&lt;br /&gt;		return otherIndex;&lt;br /&gt;	}&lt;br /&gt;	&lt;br /&gt;	public void setOtherIndex(int arg0) {&lt;br /&gt;		otherIndex = arg0;&lt;br /&gt;	}&lt;br /&gt;&lt;br /&gt;	public static void main(String[] args) {&lt;br /&gt;		JFrame frame = new JFrame();&lt;br /&gt;		JOtherComboBox comboBox = new JOtherComboBox(new String[] {"one","two","three","four"});&lt;br /&gt;		comboBox.setOtherIndex(2);&lt;br /&gt;		frame.getContentPane().add(comboBox);&lt;br /&gt;		frame.pack();&lt;br /&gt;		frame.setVisible(true);&lt;br /&gt;	}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110184460451944150?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110184460451944150/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110184460451944150' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110184460451944150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110184460451944150'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_12_01_archive.html#110184460451944150' title='JOtherComboBox'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110330245671229973</id><published>2004-12-17T18:46:00.000+02:00</published><updated>2004-12-20T16:44:37.070+02:00</updated><title type='text'>Databases Suck</title><content type='html'>That is, what we refer to as relational database management systems suck. They're too monothilic. An RDBMS typically has&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;a persistent store&lt;/li&gt;   &lt;li&gt;a type system&lt;/li&gt;   &lt;li&gt;indexing features&lt;/li&gt;   &lt;li&gt;a transaction manager&lt;br /&gt; &lt;/li&gt;   &lt;li&gt;a query language&lt;/li&gt;   &lt;li&gt;a network protocol&lt;/li&gt;   &lt;li&gt;usually a full embedded programming language&lt;br /&gt; &lt;/li&gt; &lt;/ul&gt; All this stuff makes them inflexible, and painful to integrate. People like them because they're completely independent of the rest of your code, even to the extent that a human being can often poke at them without application-specific software. They're also standardized-ish.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110330245671229973?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110330245671229973/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110330245671229973' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110330245671229973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110330245671229973'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_12_01_archive.html#110330245671229973' title='Databases Suck'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110329652950592274</id><published>2004-12-17T16:38:00.000+02:00</published><updated>2004-12-17T17:17:35.056+02:00</updated><title type='text'>One Device</title><content type='html'>Even if single-purpose devices often work better, when it comes to mobile devices, people want one device that does everything. Otherwise, it can get to be a lot to carry around.&lt;br /&gt;&lt;br /&gt;So here are the functions that are candidates for integration:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;telephone&lt;/li&gt;   &lt;li&gt;camera&lt;/li&gt;&lt;li&gt;image browser&lt;br /&gt;  &lt;/li&gt;    &lt;li&gt;audio player&lt;/li&gt;   &lt;li&gt;storage media&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;broadcast radio receiver&lt;/li&gt;&lt;li&gt;audio recorder&lt;/li&gt;&lt;li&gt;web browser&lt;/li&gt;   &lt;li&gt;email client&lt;br /&gt;  &lt;/li&gt;    &lt;li&gt;organizer&lt;/li&gt;   &lt;li&gt;video player&lt;/li&gt;&lt;li&gt;video camera&lt;br /&gt;  &lt;/li&gt;  &lt;/ul&gt; Most of these have already been integrated into at least one cell phone product. When will we see it all come together? What a device to have hackable!&lt;br /&gt;&lt;br /&gt;These super-devices will change the world. In order to do it, they'll...&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;use good voice recognition as the primary user interface&lt;/li&gt; &lt;li&gt;embrace a more &lt;a href="http://www.worldofends.com/"&gt;end-to-end&lt;/a&gt; approach&lt;/li&gt;&lt;/ul&gt; Cell phone technology is still very far from end-to-end. Carriers will try to prevent the change, because it will completely overturn their businesses.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110329652950592274?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110329652950592274/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110329652950592274' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110329652950592274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110329652950592274'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_12_01_archive.html#110329652950592274' title='One Device'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110321469980643811</id><published>2004-12-16T17:31:00.000+02:00</published><updated>2005-01-05T16:28:48.426+02:00</updated><title type='text'>Note about Gnome Storage</title><content type='html'>Not only will &lt;a href="http://www.gnome.org/%7Eseth/storage/"&gt;Gnome Storage&lt;/a&gt; make finding documents easy, remove the need for "Save", and therefore &lt;a href="http://farfetched.blogspot.com/2004/11/future-interfaces.html"&gt;simplify task management&lt;/a&gt;, it will also replace a lot of existing interfaces.&lt;br /&gt;&lt;br /&gt;Bookmarks, browser history, email indices, song playlists, photo galleries, "personal information management" views: working with these interfaces composes a large part of the time we spend with computers. Once all their info goes in a common storage layer, there'll be no reason to have many different metadata viewer implementations. (Of course, there'll be a mechanism to customize views.)&lt;br /&gt;&lt;br /&gt;But that's not all. The desktop'll get many of the advantages of the web. We'll be able to create links to any object, whether it's an email message, a song, or a todo item. Any object may be bookmarked, and we'll get a history of all the objects that we've viewed.&lt;br /&gt;&lt;br /&gt;This means big things for the semantic web movement, because it'll create huge amounts of metadata. Not only will we suddenly have easy, standard access to how often we listen to our favorite songs, we'll also know that they're predominantly in the "mp3s from joe" query folder, for example.&lt;br /&gt;&lt;br /&gt;Once most applications can store their data in common, we can give them a common implementation of other fun features, versioning and notification, collaboration and localization.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110321469980643811?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110321469980643811/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110321469980643811' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110321469980643811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110321469980643811'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_12_01_archive.html#110321469980643811' title='Note about Gnome Storage'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110296099364486250</id><published>2004-12-13T19:21:00.000+02:00</published><updated>2006-03-09T08:17:28.273+02:00</updated><title type='text'>No Password for Local Users</title><content type='html'>Do you want to relieve local linux users of having to enter passwords? Follow these steps to disable default remote access, which will make it safe for default accounts to have no password.&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;create a group "remote", and add users to it that may login remotely&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;add the following lines to your /etc/security/access.conf:&lt;pre&gt;+:remote:ALL&lt;br /&gt;-:ALL:localhost&lt;br /&gt;+:ALL:LOCAL&lt;br /&gt;-:ALL:ALL&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;   &lt;li&gt;add the following line to your /etc/pam.d/system-auth:&lt;br /&gt;&lt;pre&gt;account     required      /lib/security/$ISA/pam_access.so&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;add the following line in your /etc/pam.d/su:&lt;pre&gt;auth       required       /lib/security/$ISA/pam_wheel.so use_uid deny group=remote&lt;/pre&gt;&lt;/li&gt; &lt;/ol&gt;If you have a local domain, you might have to tinker more with access.conf, because the "LOCAL" source specification is funny; it matches any host or tty name without a ".".&lt;br /&gt;&lt;br /&gt;This was tested with Fedora Core 2.&lt;br /&gt;&lt;br /&gt;Of course, you could take the converse approach: give everyone a password, and just don't require passwords for local logins to accounts in the "local" group. This approach is probably more robust against configuration changes (e.g. if a service stops including "system-auth" it will allow logging in without a password). The first approach however is nice for granting minimum necessary privilege. Maybe both is best. Presumably the second approach would be done with a line in local service pam.d config:&lt;br /&gt;&lt;pre&gt;auth       sufficient   pam_listfile.so item=user sense=allow file=/etc/localusers onerr=fail&lt;/pre&gt;and this works for gdm at least. "mingetty" (for text logins) is a problem because it shares the "login" pam config with "in.telnetd" for plain-text remote logins. Of course, you could hack it with pam_access again (and /etc/security/group.conf) , but the extra complexity probably isn't worth it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110296099364486250?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110296099364486250/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110296099364486250' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110296099364486250'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110296099364486250'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_12_01_archive.html#110296099364486250' title='No Password for Local Users'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110291067386941759</id><published>2004-12-13T06:00:00.000+02:00</published><updated>2007-04-17T14:47:56.243+03:00</updated><title type='text'>My Daughter</title><content type='html'>My daughter is the coolest. She just turned three. A couple of days ago she was watching the Elmo episode about music. ("Elmo" is a friendly, red furry creature, on a segment of Sesame Street for toddlers. Each Elmo episode has a theme.) Elmo's pet goldfish, Dorothy, had a toy drum in her jar. My daughter observed, "Dorothy can't play the drum because she don't got hands. She also don't got a stick."&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110291067386941759?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110291067386941759/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110291067386941759' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110291067386941759'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110291067386941759'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_12_01_archive.html#110291067386941759' title='My Daughter'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110252568113605826</id><published>2004-12-08T19:06:00.000+02:00</published><updated>2005-01-07T04:21:15.680+02:00</updated><title type='text'>Gcc on Solaris</title><content type='html'>If you're getting&lt;pre&gt;/usr/include/sys/termios.h:376: parse error before `uint32_t'&lt;/pre&gt;then you should be invoking gcc as:&lt;pre&gt;gcc -I/usr/include&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110252568113605826?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110252568113605826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110252568113605826' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110252568113605826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110252568113605826'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_12_01_archive.html#110252568113605826' title='Gcc on Solaris'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110245169547166315</id><published>2004-12-07T21:25:00.000+02:00</published><updated>2007-02-12T13:40:58.576+02:00</updated><title type='text'>Better Spam Protection</title><content type='html'>In short, it's a combination "disposable addresses" and "challenge/response whitelists"...&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Everyone in your addressbook can mail you without qualification&lt;/li&gt;   &lt;li&gt;Everyone can respond to one of your private messages&lt;/li&gt;   &lt;li&gt;Everyone can respond to one of your public messages within a fixed interval of time&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;Everyone else can mail you by confirming their first message by email&lt;/li&gt; &lt;/ol&gt;The "whitelist" refers to #1, and it may also incorporate the address of anyone new that you email. It's insufficient because many people send mail from a different address than they receive mail. #2 solves this problem by embedding a cookie in your return address (e.g. JoeSmith+keyword+8769d5.4f88c3@someISP.com). (Many ISPs allow you to receive messages to your account name appended with a plus or minus followed by any string.)&lt;br /&gt;&lt;br /&gt;You can embed a hash of the address that you're sending to, plus a hash of that hash. The second hash allows you to check that the embedded cookie is valid. The first hash allows you to create a single return address for each address that you send to. If someone who knows that address ever sends you spam, you can blacklist that generated address only.&lt;br /&gt;&lt;br /&gt;When you want to receive responses to a publically posted address, it isn't a question of &lt;span style="font-style: italic;"&gt;whether&lt;/span&gt; you'll want to eventually blacklist the address, but &lt;span style="font-style: italic;"&gt;when&lt;/span&gt;. In that case #3, you can embed a cookie which instead contains the date until which you'll accept unconfirmed messages.&lt;br /&gt;&lt;br /&gt;Even people who can't use the above methods should be able to reach you #4. All of the those people must undergo the slight annoyance of confirming their first message. Their first message will trigger an automatic response from you explaining the situation. They must respond once to that message, and they'll then be added to your whitelist.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://tmda.net/"&gt;TMDA program&lt;/a&gt; does almost all of the work. #2 requires a two line patch. TMDA out-of-the-box is completely unconfigured, but my configuration looks pretty portable. I'll post it after I've been using it for a bit.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110245169547166315?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110245169547166315/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110245169547166315' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110245169547166315'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110245169547166315'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_12_01_archive.html#110245169547166315' title='Better Spam Protection'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110184477724489385</id><published>2004-11-30T21:56:00.000+02:00</published><updated>2006-03-27T11:47:50.200+02:00</updated><title type='text'>Future Interfaces</title><content type='html'>Computer interfaces should be dramatically improved, in the spirit of &lt;a href="http://mpt.phrasewise.com/stories/storyReader$374"&gt;mpt's crufty rant&lt;/a&gt;. He sounds a refrain "We have the technology, so why....?" I don't think we have the technology yet, but we should.&lt;br /&gt;&lt;br /&gt;No one should ever have to "save" a file. This requires a few things:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Unlimited undo and redo&lt;/li&gt;   &lt;li&gt;Files should only be named with &lt;a href="http://www.ietf.org/internet-drafts/draft-mealling-uuid-urn-03.txt"&gt;UUID&lt;/a&gt;s&lt;/li&gt;   &lt;li&gt;Files should be easily searchable using metadata&lt;/li&gt; &lt;/ol&gt; Once we've eliminated the save requirement, we can eliminate the unnatural concept of "open" files and windows. The only natural concept is whether a file is visible or not. Everything else should be a transparent optimization.&lt;br /&gt;&lt;br /&gt;We can't just use unix inodes instead of UUIDs for two reasons: they don't work across multiple filesystems and they can't handle being removed and restored. I don't think there is a stable implementation of the metadata interface yet, though &lt;a href="http://www.gnome.org/%7Eseth/storage/"&gt;Gnome Storage&lt;/a&gt; looks promising.&lt;br /&gt;&lt;br /&gt;Finally, applications will need to support transparent persistence. We can't just use generic checkpointing because it would be so wasteful. (For example, a web browser keeps a lot of stuff in memory, but it really only needs to persist a scrollbar location, a url (and maybe a cached copy of the url, which it'll need apart from the checkpointed image anyway).) Window managers would also have to be better at managing and persisting window arrangements.&lt;br /&gt;&lt;br /&gt;Besides window sizes and locations, we'd like to manage tilesets; we'd like them to remember the fact that we're working with two documents side-by-side. Tzorech iyun, sometimes tilesets just indicate the desire to work on two different things at the same time.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110184477724489385?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110184477724489385/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110184477724489385' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110184477724489385'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110184477724489385'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_11_01_archive.html#110184477724489385' title='Future Interfaces'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110174281032088312</id><published>2004-11-29T16:46:00.000+02:00</published><updated>2006-08-16T23:36:56.096+03:00</updated><title type='text'>Traits for Python</title><content type='html'>Since python already has multiple inheritance, implementing traits isn't a matter of adding new functionality, but of restricting the functionality that's already there.&lt;br /&gt;&lt;br /&gt;The metaclasses below enable preventing classes from having member data and preventing conflicting methods. (Just have your classes inherit from Trait or TraitUser.)&lt;br /&gt;&lt;br /&gt;The next step is solving the Artistic Cowboy Problem in a pythonic fashion.&lt;br /&gt;&lt;br /&gt;If you missed &lt;a href="http://farfetched.blogspot.com/2004/11/traits-for-reuse.html"&gt;my earlier traits entry&lt;/a&gt;, here's the &lt;a href="http://www.iam.unibe.ch/%7Escg/Research/Traits/"&gt;traits homepage&lt;/a&gt; link again.&lt;pre&gt;#!/usr/bin/python&lt;br /&gt;import operator, types, sets&lt;br /&gt;&lt;br /&gt;def get_classdict(cls):&lt;br /&gt;        "get name:attr dict from a class"&lt;br /&gt;        names = dir(cls)&lt;br /&gt;        classdict = {}&lt;br /&gt;        for name in names:&lt;br /&gt;                classdict[name]=getattr(cls, name)&lt;br /&gt;        return classdict&lt;br /&gt;&lt;br /&gt;def get_methods(classdict):&lt;br /&gt;        "get a set of nonsystem methods from a classdict"&lt;br /&gt;        methods = sets.Set()&lt;br /&gt;        for (k,v) in classdict.items():&lt;br /&gt;                if k.startswith('__'): continue&lt;br /&gt;                if type(v) is types.MethodType or type(v) is types.FunctionType:&lt;br /&gt;                        methods.add(k)&lt;br /&gt;        return methods&lt;br /&gt;&lt;br /&gt;class TraitClass(type):&lt;br /&gt;        """Metaclass for classes that may not have state,&lt;br /&gt;        whose conflicting trait methods must be resolved in extenders,&lt;br /&gt;        and who may not extend classes which are not traits."""&lt;br /&gt;&lt;br /&gt;        def __init__(cls, clsname, bases, classdict):&lt;br /&gt;                type.__init__(cls, clsname, bases, classdict)&lt;br /&gt;                cls.conflict_methods = sets.Set()&lt;br /&gt;                all_methods = sets.Set()&lt;br /&gt;                for c in cls.get_method_lists(bases, classdict):&lt;br /&gt;                        methods = get_methods(c)&lt;br /&gt;                        cls.conflict_methods |= all_methods &amp; methods&lt;br /&gt;                        all_methods |= methods&lt;br /&gt;                #propagate conflicting methods from base classes&lt;br /&gt;                for c in bases:&lt;br /&gt;                        if 'conflict_methods' in dir(c):&lt;br /&gt;                                cls.conflict_methods |= c.conflict_methods&lt;br /&gt;                for c in bases:&lt;br /&gt;                        #if c == object: continue&lt;br /&gt;                        if type(c) != TraitClass:&lt;br /&gt;                                cls.handle_base_class(c)&lt;br /&gt;&lt;br /&gt;        def get_method_lists(cls, bases, classdict):&lt;br /&gt;                "traits check for conflicts from parents and from self"&lt;br /&gt;                return map(get_classdict, bases)+[classdict,]&lt;br /&gt;&lt;br /&gt;        def handle_base_class(cls, c):&lt;br /&gt;                "enforce only inheritting traits"&lt;br /&gt;                raise "Trait %s cannot inherit from a class that is not a Trait"%cls.__name__,c.__name__&lt;br /&gt;&lt;br /&gt;        def __new__(cls, clsname, bases, classdict):&lt;br /&gt;                #if a nonexplicit class extends nontraits, make it a trait user&lt;br /&gt;                if classdict.get('__metaclass__') != TraitClass and 0 &amp;lt; len([c for c in bases if type(c) != TraitClass]):&lt;br /&gt;                        classdict['__metaclass__']=TraitUserClass&lt;br /&gt;                #if class is actually a trait, make readonly&lt;br /&gt;                else:  &lt;br /&gt;                        classdict['__slots__']=[]&lt;br /&gt;                return type.__new__(cls, clsname, bases, classdict)&lt;br /&gt;&lt;br /&gt;class TraitUserClass(TraitClass):&lt;br /&gt;        """Metaclass for mostly normal classes,&lt;br /&gt;        that must use single inheritance of nontraits,&lt;br /&gt;        and that implement trait conflict handling"""&lt;br /&gt;&lt;br /&gt;        def __init__(cls, clsname, bases, classdict):&lt;br /&gt;                TraitClass.__init__(cls, clsname, bases, classdict)&lt;br /&gt;&lt;br /&gt;                unresolved = getattr(cls, 'conflict_methods',sets.Set()) - sets.Set(classdict) - sets.Set(dir(getattr(cls,'nontrait_base',None)))&lt;br /&gt;                if len(unresolved) &amp;gt; 0:&lt;br /&gt;                        raise "conflicting methods",unresolved&lt;br /&gt;&lt;br /&gt;        def get_method_lists(cls, bases, classdict):&lt;br /&gt;                "check for conflicts in parent traits"&lt;br /&gt;                nontrait_base = getattr(cls, 'nontrait_base', None)&lt;br /&gt;                return [ get_classdict(c) for c in bases if c != nontrait_base]&lt;br /&gt;&lt;br /&gt;        def handle_base_class(cls, c):&lt;br /&gt;                "enforce single inheritance of nontraits"&lt;br /&gt;                nontrait_base=getattr(cls,'nontrait_base',None)&lt;br /&gt;                if nontrait_base:&lt;br /&gt;                        raise "Trait-using class %s can extend no more than one class that is not a Trait"%cls.__name__, c.__name__&lt;br /&gt;                cls.nontrait_base = c&lt;br /&gt;&lt;br /&gt;        def __new__(cls, clsname, bases, classdict):&lt;br /&gt;                #python weirdness; __metaclass__ doesn't override parent's here&lt;br /&gt;                if classdict['__metaclass__'] == TraitClass:&lt;br /&gt;                        raise "Trait %s cannot inherit from a class that is a TraitUser"%clsname &lt;br /&gt;                return type.__new__(cls, clsname, bases, classdict)&lt;br /&gt;&lt;br /&gt;class Trait: __metaclass__=TraitClass #convenience object&lt;br /&gt;class TraitUser: __metaclass__=TraitUserClass #convenience object&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110174281032088312?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110174281032088312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110174281032088312' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110174281032088312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110174281032088312'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_11_01_archive.html#110174281032088312' title='Traits for Python'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110173957663975738</id><published>2004-11-29T16:43:00.000+02:00</published><updated>2004-11-29T16:47:12.970+02:00</updated><title type='text'>Python Metaclasses are Weird</title><content type='html'>&lt;pre&gt;$ python &amp;lt;&amp;lt;''&lt;br /&gt;&gt; class m1(type): pass&lt;br /&gt;&gt; class m2(m1): pass&lt;br /&gt;&gt; class c2: __metaclass__=m2&lt;br /&gt;&gt; class c1(c2): __metaclass__=m1&lt;br /&gt;&gt; print 'the type of c1 is', type(c1)&lt;br /&gt;&gt;&lt;br /&gt;the type of c1 is &amp;lt;class '__main__.m2'&amp;gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110173957663975738?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110173957663975738/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110173957663975738' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110173957663975738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110173957663975738'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_11_01_archive.html#110173957663975738' title='Python Metaclasses are Weird'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110114606894763503</id><published>2004-11-22T19:54:00.000+02:00</published><updated>2005-01-07T04:21:57.776+02:00</updated><title type='text'>Why XML is Case-Sensitive</title><content type='html'>&lt;h4&gt; 				&lt;a title="permalink: re: Tyranny of the geeks" href="http://dotnetjunkies.com/WebLog/sriram/archive/2004/11/18/32707.aspx#32794"&gt;#&lt;/a&gt; &lt;a name="32794"&gt;&lt;/a&gt;re: Tyranny of the geeks 					&lt;span&gt; 						11/20/2004 1:27 AM 					&lt;/span&gt; 				&lt;a id="Comments.ascx_CommentList__ctl2_NameLink" href="http://www.tbray.org/ongoing/" target="_blank"&gt;Tim Bray&lt;/a&gt; 			&lt;/h4&gt;  			 XML markup is case-sensitive because the cost of monocasing in Unicode is horrible, horrible, horrible. Go look at the source code in your local java or .Net library.&lt;br /&gt;&lt;br /&gt;Also, not only is it expensive, it's just weird. The upper-case of é is different in France and Quebec, and the lower-case of 'I' is different here and in Turkey.&lt;br /&gt;&lt;br /&gt;XML was monocase until quite late in its design, when we ran across this ugliness. I had a Java-language processor called Lark - the world's first - and when XML went case-sensitive, I got a factor of three performance improvement, it was all being spent in toLowerCase(). -Tim&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110114606894763503?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110114606894763503/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110114606894763503' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110114606894763503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110114606894763503'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_11_01_archive.html#110114606894763503' title='Why XML is Case-Sensitive'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110087505903968648</id><published>2004-11-19T16:13:00.000+02:00</published><updated>2007-03-15T02:01:26.196+02:00</updated><title type='text'>The Way to Manage Windows</title><content type='html'>Writing a window manager is hard (just like making war). I've no time to do it, so I'm going to describe my vision here.&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Windows should never overlap. Windows overlap when one &lt;span style="font-style: italic;"&gt;partially &lt;/span&gt;obscures another.&lt;/li&gt;   &lt;li&gt;Windows should only ever be grouped by &lt;span style="font-weight: bold;"&gt;tabs&lt;/span&gt; or &lt;span style="font-weight: bold;"&gt;tiles&lt;/span&gt;.&lt;/li&gt; &lt;/ol&gt; Tiled windows are completely visible, and occupy all the available space because their edges line up. You can see an example in WindowsXP. If you have a bunch of windows open for an application, right clicking on that application's taskbar icon will give you "Tile Horizontally" and "Tile Vertically" commands.&lt;br /&gt;&lt;br /&gt;Tabbed windows only have a single visible window, which also occupies the whole available space. Optionally, the system can display little "tabs" for switching between windows, or it can provide different mechanisms.&lt;br /&gt;&lt;br /&gt;By nesting tiles and tabs, any reasonable window behavior can be represented. "Workspaces" and "virtual desktops" are essentially tabs. "Sticky windows" can be implemented with top-level tiles. The beautiful thing about having so few concepts is that features are available in many contexts.&lt;br /&gt;&lt;br /&gt;I'm still not sure what window operations should be available. Dragging a window to a different tabset or tileset should move it, but should we have a mechanism for swapping tiles? It should be possible to change a window from tile to tab and back, but what mechanism should there be for zooming a tileset?&lt;br /&gt;&lt;br /&gt;Here's a tentative set of operations: each window gets "pull up" and "push down". For tabs, this is pretty self-evident. For tiles, it involves resizing the partner tiles, so that this tile is in the same place despite the push/pull. In addition to push/pull, tabs get an operation "change to tile", and tiles get two operations : "change to selected tab" and "change to unselected tab". These operations are reversible, so tile positions are recorded (and resettable). The dimensions of the window otherwise determine the default horizontal or vertical tile placement. Drag and drop "moves" both tabs and tiles, and they will become tabs and tiles of the drag target, respectively.&lt;br /&gt;&lt;br /&gt;There are window managers that implement tiles, but they all have two problems: they don't use this beautiful dual idea, and they are almost completely unusable.&lt;br /&gt;&lt;br /&gt;Unfortunately, since many applications make unwarranted assumptions, the window manager would have to support the legacy behavior also.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110087505903968648?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110087505903968648/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110087505903968648' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110087505903968648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110087505903968648'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_11_01_archive.html#110087505903968648' title='The Way to Manage Windows'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110081777319413466</id><published>2004-11-19T01:36:00.000+02:00</published><updated>2004-11-19T00:42:53.193+02:00</updated><title type='text'>Editor Feature</title><content type='html'>When I cut Levi from "Reuven, Shimon, and Levi", and I paste it to before Reuven, I want my editor program to do the right thing. That is, I want my editor to display "Levi, Reuven, and Shimon" instead of "LeviReuven, Shimon, and ".&lt;br /&gt;&lt;br /&gt;My java editor should also do the same thing for commas, but it's really inexcusable that java doesn't allow lists to have trailing commas (1,2,3,).&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110081777319413466?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110081777319413466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110081777319413466' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110081777319413466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110081777319413466'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_11_01_archive.html#110081777319413466' title='Editor Feature'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110081691993194723</id><published>2004-11-18T22:08:00.000+02:00</published><updated>2004-11-19T00:28:39.930+02:00</updated><title type='text'>Traits for Reuse</title><content type='html'>&lt;a href="http://www.iam.unibe.ch/%7Escg/Research/Traits/"&gt;Traits&lt;/a&gt; are an exciting development in object oriented programming.&lt;br /&gt;&lt;br /&gt;Traits are collections of methods, like objects without state. These methods are parameterized over other methods, which may be traditional object methods or other traits methods.&lt;br /&gt;&lt;br /&gt;A class may inherit multiple traits, but without the problems of multiple inheritance and mixins . This is because 1) their composition isn't ordered and 2)  they support composition operators for resolving conflicts.&lt;br /&gt;&lt;br /&gt;Traditional classes still have single inheritence, and they contain all the state and glue code. Traditional inheritance is for subtyping, and traits inheritance is for reuse. The developers are quite conservative; they propose traits as an incremental addition to traditional languages. The traits methods may be visualized as code which is simply copied into their composing classes (almost reminiscent of &lt;a href="http://www.cs.berkeley.edu/Research/Projects/harmonia/papers/toomim-linked-editing.pdf"&gt;linked editing&lt;/a&gt;).&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110081691993194723?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110081691993194723/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110081691993194723' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110081691993194723'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110081691993194723'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_11_01_archive.html#110081691993194723' title='Traits for Reuse'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110079201956998178</id><published>2004-11-18T16:56:00.000+02:00</published><updated>2005-01-07T04:22:29.820+02:00</updated><title type='text'>Another Note about Dune</title><content type='html'>(I haven't read Dune recently, but these just occurred to me.)&lt;br /&gt;&lt;br /&gt;In Dune, there's a common theme in reaching for higher spiritual destiny (read "magical powers").&lt;br /&gt;&lt;br /&gt;Throughout the series, people attain prescience and racial memory through "the spice agony", a presumably intensely painful overdose on the mysterious spice drug. It could be that before the BG allow someone to undergo the spice agony, they subject the person to intense pain of an ordinary nature, to determine whether the person will be able to withstand the ordeal.&lt;br /&gt;&lt;br /&gt;Later, we  learn that clones ("gholas") may be awakened to the memories of their other lives by means of an intense psychic conflict (for example, being forced to betray that which they most care about). &lt;br /&gt;&lt;br /&gt;Finally, the Miles Teg character gains, among other powers, the ability to think and move so quickly that he cannot be seen. He gains this ability when he is subjected to extraordinary pain by a contraption meant to probe his memory. The device apparently constructs a full computer synthesis of one's mind.&lt;br /&gt;&lt;br /&gt;The common theme is that these powers are attained by undergoing some sort of existential pain. We don't yet know what's the point of it all, but it's fun to notice the build up.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110079201956998178?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110079201956998178/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110079201956998178' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110079201956998178'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110079201956998178'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_11_01_archive.html#110079201956998178' title='Another Note about Dune'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110078968294330686</id><published>2004-11-18T16:22:00.000+02:00</published><updated>2004-11-18T16:54:42.943+02:00</updated><title type='text'>The End of Even Numbered Linux Releases</title><content type='html'>Until recently, the Linux kernel development followed alternating cycles of adding new features and then stabilizing. The stabilization period was relatively short, and then development would branch off again. People would then be free to make low impact patches to the stable fork, but most developer attention would be focused on the new development fork.&lt;br /&gt;&lt;br /&gt;With the most recent release, Linus has abandoned these alternating cycles. This is partly because new revision control tools allow him to better "cherry-pick", so that he can pull from other developers' own development forks. More importantly, though, the Linux distributions really want to make their own stable releases. They have their own release schedules, which they prefer not to tie to the kernel's schedule. The distribution kernels also get much greater user exposure (and testing) than Linus's own kernel, and so are better positioned to address stability issues.&lt;br /&gt;&lt;br /&gt;The mainline kernel has become the permanent "unstable" kernel, albeit a little less unstable. Now the distributions contribute their patches back to the mainline and allow them to be beta tested there. If you want a rock stable kernel, you should get a distribution kernel, or even an enterprise distribution kernel.&lt;br /&gt;&lt;br /&gt;Years ago, hackers debated whether Linux should remain a hacker system or if it should clean up its act and "go mainstream".  Linux &lt;span style="font-style: italic;"&gt;is &lt;/span&gt;remaining a hacker system, but companies have sprung up to build their own mainstream versions. It's nice that there's a business model in that.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lkml.org/lkml/2004/10/22/377"&gt;Lee Revell describes the current situation nicely.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:78%;"&gt;It remains to be seen whether there's a future for &lt;span style="font-style: italic;"&gt;multiple&lt;/span&gt; distributions. It could be that, just like in the commercial software world, there can be only one. That is,  that network effects may favor a single distirbution gaining the overwhelmingly majority of users.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110078968294330686?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110078968294330686/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110078968294330686' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110078968294330686'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110078968294330686'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_11_01_archive.html#110078968294330686' title='The End of Even Numbered Linux Releases'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110062024288561605</id><published>2004-11-16T17:46:00.000+02:00</published><updated>2007-04-11T13:02:07.883+03:00</updated><title type='text'>My Bookmarklets</title><content type='html'>Boorkmarklets are bookmarks that consist of javascript code. Here are two that I rewrote:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;&lt;a href="javascript:location='http://google.com/search?q=cache:'+location"&gt;Get the current page via the google cache&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a href="javascript:c=window.open('', 'reloader', 'height=150,width=500');c.document.write('&amp;lt;script&amp;gt;var x; function f() { x.location.reload(); setTimeout(\'window.focus()\', 1); document.forms[0].elements[0].value++; setTimeout(\'f()\', 300000); }&amp;lt;/script&amp;gt;reloading '+window.location+' every five minutes&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;form&amp;gt;&amp;lt;input readonly size=5 value=0&amp;gt;&amp;lt;/form&amp;gt;');c.document.close(); c.x=window; c.f()"&gt;Refresh the current page every five minutes until the little window is closed&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt; Right-click on one and select "Bookmark This Link" or "Add to Favorites", and then you'll always be able to use the feature by selecting the bookmark that you created.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110062024288561605?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110062024288561605/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110062024288561605' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110062024288561605'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110062024288561605'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_11_01_archive.html#110062024288561605' title='My Bookmarklets'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-110027841008749816</id><published>2004-11-12T17:39:00.000+02:00</published><updated>2007-03-21T23:56:22.676+02:00</updated><title type='text'>Making Things Easy to Maintain</title><content type='html'>A lot of the cost of software is maintenance. Currently, There Is No Magic Bullet for making maintenance cheap. But there are a lot of best practices which I'm going to try to collect.&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;Make it as simple as possible.&lt;/li&gt;   &lt;li&gt;Use test driven development.&lt;/li&gt;   &lt;li&gt;Keep as little state as possible.&lt;/li&gt; &lt;/ul&gt; And some particular points.&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;Centralize environment configuration.&lt;/li&gt;   &lt;li&gt;Make jobs rerunnable/idempotent whenever possible.&lt;br /&gt;  &lt;/li&gt;   &lt;li&gt;Give temporary resources short-lived unique names.&lt;/li&gt; &lt;/ul&gt; &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-110027841008749816?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/110027841008749816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=110027841008749816' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110027841008749816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/110027841008749816'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_11_01_archive.html#110027841008749816' title='Making Things Easy to Maintain'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-108861118739765004</id><published>2004-11-09T18:58:00.000+02:00</published><updated>2004-11-10T00:02:55.686+02:00</updated><title type='text'>Note About Dune</title><content type='html'>The two most powerful institutions in the Dune series are the Bene Gesserit and the Bene Tleilax.&lt;br /&gt;&lt;br /&gt;The BG is entirely composed of women, and the BT of men. Both houses prefer to exercise their influence quietly, the BG by only manipulating and never controlling directly; BT by assuming a guise of inferiority. In the Dune world, artificial intelligences are absent, so improvement of human beings is the main historic goal. The BG pursue this goal through training the mind and body, and by a "human breeding program", while the BT pursue it through direct genetic engineering. Each institution has its own approach to effective immortality; the BG share the memories of all of their female ancestors, and the BT clone themselves and infuse the clones with their original consciousness.&lt;br /&gt;&lt;br /&gt;The BG incorporates motifs of the Christian Church (and possibly the Jesuits), and the BT of Islam. Both houses pursue a Messianic dream. The dream of the BG is to create the "Kwisatz Haderach", but the dream of BT has not been revealed. The Kwisatz Haderach, among other abilities, will have access to the memories of both his male and female ancestors. It's clear that these schools must somehow synthesize, and in fact this has been alluded to in the last books of the series.&lt;br /&gt;&lt;br /&gt;I predict that this synthesis will involve Judaism. Though much of the Dune lingo is taken from greek and arabic, "Kwisatz Haderach" almost certainly refers to the hebrew &lt;span id="OptionE0" style="color: rgb(0, 0, 153);font-family:david;font-size:11;" dir="rtl"  &gt;קפיצת הדרך&lt;/span&gt; ("skipping of the way") that figures in the Pentateuch and in Chasidic literature. It's a miracle of travelling great distances in a short amount of time. Accordingly, it was the Miles Teg character, and not "Paul Muad'dib" who became the first Kwisatz Haderach.&lt;br /&gt;&lt;br /&gt;Incidentally, Leto, Paul, and Leto II evoke Avraham, Yitzchak, and Yaakov.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-108861118739765004?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/108861118739765004/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=108861118739765004' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/108861118739765004'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/108861118739765004'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_11_01_archive.html#108861118739765004' title='Note About Dune'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109456657234856289</id><published>2004-11-04T17:15:00.000+02:00</published><updated>2007-02-07T06:55:45.176+02:00</updated><title type='text'>On G-d's Side</title><content type='html'>There are two problems with fundamentalism: arrogance and self-service.&lt;br /&gt;&lt;br /&gt;The root cause is that when you decide (on some level) to do the right thing, you get comfortable with the idea that you are doing the right thing.&lt;br /&gt;&lt;br /&gt;Believing that you are doing the right thing can make you arrogant, and it can make you intolerant of people who are doing different things. Believing that you are doing the right thing can cause you to compromise for your own benefit. It's a case of the ends justifying the means, but it's more seductive. You feel that those who are doing good should be enabled to continue doing good. But if you ever flag in your devotion, you're also guilty of hypocrisy.&lt;br /&gt;&lt;br /&gt;The converse danger is paralysis. If you refrain from judging, there's no basis for choice. All the choices that you do make will be weakened.&lt;br /&gt;&lt;br /&gt;Maybe we can just continue to act on our consciences, so long as we realize how little we understand the connection between our efforts and their actual effects.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109456657234856289?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109456657234856289/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109456657234856289' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109456657234856289'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109456657234856289'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_11_01_archive.html#109456657234856289' title='On G-d&apos;s Side'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109951332184962880</id><published>2004-11-03T22:04:00.000+02:00</published><updated>2004-11-03T23:18:11.910+02:00</updated><title type='text'>2004 Election Issues</title><content type='html'>from &lt;a href="http://www.cnn.com/ELECTION/2004/pages/results/states/US/P/00/epolls.0.html"&gt;cnn's exit poll&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;of the people who considered each issue most important, how many of them voted...&lt;br /&gt;&lt;table style="border-collapse: collapse; width: 250pt;"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td align="right"&gt;&lt;br /&gt;&lt;/td&gt;&lt;td align="right"&gt;overall&lt;/td&gt;&lt;td align="right"&gt;for bush&lt;/td&gt;&lt;td align="right"&gt;for kerry&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align="right"&gt;taxes&lt;/td&gt;&lt;td align="right"&gt;5%&lt;/td&gt;&lt;td align="right"&gt;57%&lt;/td&gt;&lt;td align="right"&gt;43%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align="right"&gt;education&lt;/td&gt;&lt;td align="right"&gt;4%&lt;/td&gt;&lt;td align="right"&gt;26%&lt;/td&gt;&lt;td align="right"&gt;73%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align="right"&gt;iraq&lt;/td&gt;&lt;td align="right"&gt;15%&lt;/td&gt;&lt;td align="right"&gt;26%&lt;/td&gt;&lt;td align="right"&gt;73%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align="right"&gt;terrorism&lt;/td&gt;&lt;td align="right"&gt;19%&lt;/td&gt;&lt;td align="right"&gt;86%&lt;/td&gt;&lt;td align="right"&gt;14%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align="right"&gt;economy/jobs&lt;/td&gt;&lt;td align="right"&gt;20%&lt;/td&gt;&lt;td align="right"&gt;18%&lt;/td&gt;&lt;td align="right"&gt;80%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align="right"&gt;moral values&lt;/td&gt;&lt;td align="right"&gt;22%&lt;/td&gt;&lt;td align="right"&gt;80%&lt;/td&gt;&lt;td align="right"&gt;18%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align="right"&gt;health care&lt;/td&gt;&lt;td align="right"&gt;8%&lt;/td&gt;&lt;td align="right"&gt;23%&lt;/td&gt;&lt;td align="right"&gt;77%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;br /&gt;also, people who voted for bush overwhelmingly thought that the economy is doing well, and that we should have invaded iraq. people who voted for kerry overwhelmingly thought the economy is doing poorly, and that we shouldn't have invaded iraq.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109951332184962880?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109951332184962880/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109951332184962880' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109951332184962880'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109951332184962880'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_11_01_archive.html#109951332184962880' title='2004 Election Issues'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109777520277466866</id><published>2004-11-03T19:31:00.000+02:00</published><updated>2004-12-28T19:16:11.696+02:00</updated><title type='text'>Categories of Chumra</title><content type='html'>The idea of the chuma, or stringency, in Orthodox Judaism looms large. G-d appointed the Jewish people His holy nation and gave us His Law, but individuals have always strived to do more. There are actually a few different categories of chumra. Scholars have written about the subject, but in the form of manuals for getting closer to G-d. I'm just describing people's actions as they appear.&lt;br /&gt;&lt;br /&gt;Ever since the disbanding of the Sanhedrin (central government of rabbinic judaism), religious legislation has been somewhat up in the air. This situation leads to the most fashionable type of chumra, the attempt to &lt;span style="font-weight: bold;"&gt;satisfy all the conflicting decisions&lt;/span&gt; made by a group of different decisors.&lt;br /&gt;&lt;br /&gt;The group of decisors is often the rishonim (medieval scholars), and satisfying their decisions inspires many of the famous "Brisker Chumros". These chumros are more compelling when the issue is a matter of Biblical law rather than Rabbinic, but often the provenance itself is also in question. It is literally impossible to always satisfy &lt;span style="font-style: italic;"&gt;all&lt;/span&gt; of the decisions of all the rishonim. [To be written: rashi and rabbenu tam tefillin example, &lt;span style="font-style: italic;"&gt;rov example&lt;/span&gt;]&lt;br /&gt;&lt;br /&gt;As we consider later decisions, it becomes increasingly less clear whether a given position is a chumra or actual halacha. At least for opinions of the rishonim, we usually have a idea of the halacha from the Shulchan Aruch. After that, we often have many different strong positions and no agreed upon principle for deciding amongst them. These questions are usually either less fundamental, or else they deal with technology and new situations.&lt;br /&gt;&lt;br /&gt;A subcategory of satisfying &lt;span style="font-style: italic;"&gt;all &lt;/span&gt;decisions is to &lt;span style="font-weight: bold;"&gt;observe&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; authoritative decisions that are mostly disregarded&lt;/span&gt;. This disregard may be explained away by later authorities, or it may be mysterious. Either way, we are reluctant to suppose that the majority of observant jews are violating halacha, so these decisions take on the status of chumra. An example is Ezra's decree that after seminal emission, men should immerse in the Mikveh before learning or praying.&lt;br /&gt;&lt;br /&gt;Another major category of chumra is that of &lt;span style="font-weight: bold;"&gt;ascetic practices&lt;/span&gt;. In general, the torah encourages--and perhaps requires--embracing life, but historically scholars have valued greater restraint. Maimonides famously praises the ideal of moderation, but his view of moderation looks harsh by today's standards. An example is fasting most Mondays and Thursdays.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Excruciating attention to detail &lt;/span&gt;is another major form of chumra, which some consider to be part of normative halacha. The classic example is that halacha specifies the proper order for tying your shoes. This trend goes back to the Talmud, which wrangles over the exact right place to first break open a loaf of bread. People may try to be meticulous in interpersonal relations as well (for example, not telling a companion at a restaurant that you dislike your meal, lest the waiter overhear and get hurt feelings).&lt;br /&gt;&lt;br /&gt;Many of these chumras evoke awareness of G-d and godliness in every aspect of one's life, even the most picayune. It could be that accomplishing this awareness is more important than the actual details themselves.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Mysticism &lt;/span&gt;informs mainstream halacha, but it also forms a rich body of chumra. Presumably this category need not be limited to the traditional literature, but may include fringe texts, and even personal research into hidden worlds.&lt;br /&gt;&lt;br /&gt;Much of civil law is about compromise, where neither party to a dispute is actually at fault. The Talmud describes "chasidus" as the habit of &lt;span style="font-weight: bold;"&gt;forgoing legal advantage&lt;/span&gt; in many such situations, and exceeding one's pecuniary obligation. [Source in bava kamma]&lt;br /&gt;&lt;br /&gt;The last category of chumra is a biggy: &lt;span style="font-weight: bold;"&gt;do more good&lt;/span&gt;. This means strengthening the pillars of the world: learning more torah, giving effort and money to those in need, and praying more meaningfully.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109777520277466866?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109777520277466866/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109777520277466866' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109777520277466866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109777520277466866'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_11_01_archive.html#109777520277466866' title='Categories of Chumra'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109907245469602113</id><published>2004-10-29T19:46:00.000+02:00</published><updated>2005-01-07T04:23:17.410+02:00</updated><title type='text'>Tradition</title><content type='html'>Anybody who's seen Fiddler On The Roof knows that Judaism is all about Tradition.&lt;br /&gt;&lt;br /&gt;Why should that be?&lt;br /&gt;&lt;br /&gt;Making tradition so central (and not just a particular tradition, but the institution of tradition itself), emphasizes the notion of the Jewish People as an entity, an organism.&lt;br /&gt;&lt;br /&gt;Just as a person grows throughout his life, and interacts with his environment, so too, we are to imagine the Jewish People moving through history.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109907245469602113?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109907245469602113/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109907245469602113' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109907245469602113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109907245469602113'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_10_01_archive.html#109907245469602113' title='Tradition'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109882947998306017</id><published>2004-10-27T01:19:00.000+02:00</published><updated>2005-02-01T22:41:35.256+02:00</updated><title type='text'>Overdue Library Book Notifier</title><content type='html'>UPDATED: allow excluding weekend days from the notification interval.&lt;pre&gt;#!/usr/bin/python&lt;br /&gt;#mail notification of due books on libraries using the Dynix Information Portal&lt;br /&gt;#todo: renew each that is due, and mail only if fail&lt;br /&gt;&lt;br /&gt;import re, time, smtplib&lt;br /&gt;from urllib import urlopen, urlencode&lt;br /&gt;from datetime import datetime, date&lt;br /&gt;&lt;br /&gt;days_warning = 4&lt;br /&gt;excluding_weekends = False&lt;br /&gt;accounts = (&lt;br /&gt;       ("1 2345 67890 1234","1234"),&lt;br /&gt;       ("9 8765 43210 9876","9876"),&lt;br /&gt;)&lt;br /&gt;fromaddr = "somebody@somewhere.com"&lt;br /&gt;toaddrs = ( "somebody@somewhere.com", "somebodyelse@somewhere.com", )&lt;br /&gt;headers = [ "Subject: LIBRARY BOOKS DUE", ]&lt;br /&gt;&lt;br /&gt;url = "http://leopac4.nypl.org/ipac20/ipac.jsp"&lt;br /&gt;params = {&lt;br /&gt;       "menu":"account",&lt;br /&gt;       "aspect":"overview",&lt;br /&gt;       "profile":"dial--3",&lt;br /&gt;       "button":"Login",&lt;br /&gt;}&lt;br /&gt;itemsout_re = re.compile("href=.*?uri=.*?&gt;(.*?)&amp;lt;/a&gt;.*?(\d{2}/\d{2}/\d{2}).*?(\d{2}/\d{2}/\d{4})")&lt;br /&gt;trailing_nonword_re = re.compile("\W*$")&lt;br /&gt;&lt;br /&gt;itemsdue = []&lt;br /&gt;for params["sec1"], params["sec2"] in accounts:&lt;br /&gt;       a = urlopen(url+"?menu=account") #get session ticket&lt;br /&gt;       params["session"] = session = re.search(r"session=([\w\.]+)", a.read()).group(1)&lt;br /&gt;       b = urlopen(url, urlencode(params)) #do login&lt;br /&gt;       c = urlopen(url+"?session="+session+"&amp;menu=account&amp;submenu=itemsout") #get book list&lt;br /&gt;       html_itemsout = c.read()&lt;br /&gt;&lt;br /&gt;       today = date.today()&lt;br /&gt;       if excluding_weekends and (today.weekday() + days_warning) &gt;= 5: #saturday&lt;br /&gt;               days_warning += 2&lt;br /&gt;       for i in itemsout_re.finditer(html_itemsout):&lt;br /&gt;               due = datetime(*time.strptime(i.group(3),"%m/%d/%Y")[:6]).date() - today&lt;br /&gt;               if due.days &lt; days_warning:&lt;br /&gt;                       itemsdue.append((trailing_nonword_re.sub("",i.group(1)),due.days))&lt;br /&gt;&lt;br /&gt;if itemsdue:&lt;br /&gt;       msg = "\n".join(headers+[""])&lt;br /&gt;       for i in itemsdue:&lt;br /&gt;               msg += "\""+i[0]+"\" is due in "+str(i[1])+" days\n"&lt;br /&gt;       smtplib.SMTP('localhost').sendmail(fromaddr, toaddrs, msg)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109882947998306017?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109882947998306017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109882947998306017' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109882947998306017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109882947998306017'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_10_01_archive.html#109882947998306017' title='Overdue Library Book Notifier'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109822308632411514</id><published>2004-10-20T23:56:00.000+02:00</published><updated>2005-10-06T16:01:20.446+03:00</updated><title type='text'>Exceptions</title><content type='html'>There are three broad categories of exceptions that should be handled:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Contract not met by client (either code or supporting configuration)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Resource not available&lt;/li&gt;&lt;li&gt;Programming error in provider code&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Three are three broad ways to handle them:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Try to fix it&lt;ul&gt;&lt;li&gt;Reset state&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Address the issue specified by the exception&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Just do without the functionality&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Present the error&lt;ul&gt;&lt;li&gt;Log it&lt;/li&gt;&lt;li&gt;Report to the user&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;   &lt;/ul&gt; General rules of exceptions:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Throw early&lt;/li&gt;&lt;li&gt;Catch late&lt;/li&gt;&lt;li&gt;Handle exactly once&lt;/li&gt;&lt;li&gt;New exceptions are for new ways of handling&lt;/li&gt;&lt;li&gt;Use "finally" to do cleanup&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Don't throw in constructors&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;If an exception can't be handled differently based on its type, you shouldn't create a new exception class for it.&lt;br /&gt;&lt;br /&gt;With java 1.4 exception wrapping, there's no need to have separate exception classes for separate components.&lt;br /&gt;&lt;br /&gt;Inspired by &lt;a href="http://www.onjava.com/lpt/a/4345"&gt;O'Reilly's Best Practices for Exception Handling.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109822308632411514?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109822308632411514/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109822308632411514' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109822308632411514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109822308632411514'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_10_01_archive.html#109822308632411514' title='Exceptions'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109812065237400159</id><published>2004-10-18T19:21:00.000+02:00</published><updated>2005-01-07T04:23:52.970+02:00</updated><title type='text'>Better Programmers' Editor</title><content type='html'>Programmers' editors should format as you type. Modern editors do this for hiliting, but they should also do it for spacing. For example, if you type:&lt;br /&gt;&lt;pre&gt;    while(true){i+=1;}&lt;/pre&gt;&lt;br /&gt;the editor should immediately display:&lt;br /&gt;&lt;pre&gt;    while (true) {&lt;br /&gt;        i += 1;&lt;br /&gt;    }&lt;/pre&gt;Cursor movement should also ignore that whitespace. (If the cursor is before the "i" above, pressing the left arrow should move the cursor to before the "{".)&lt;br /&gt;&lt;br /&gt;Of course, the editor should also wrap long lines as you type. &lt;br /&gt;&lt;br /&gt;This behavior is described in &lt;a href="http://research.sun.com/projects/jackpot/COM.Sun.Labs.Forest.doc.coset_2000.abs.html"&gt;Displaying and Editing Source Code in Software Engineering Environments&lt;/a&gt;, but I haven't seen an implementation.&lt;br /&gt;&lt;br /&gt;Just found &lt;a href=http://http.cs.berkeley.edu/Research/Projects/harmonia/&gt;Harmonia&lt;/a&gt;, which looks like it does it. An eclipse plugin is in the works.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109812065237400159?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109812065237400159/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109812065237400159' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109812065237400159'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109812065237400159'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_10_01_archive.html#109812065237400159' title='Better Programmers&apos; Editor'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109777281354283554</id><published>2004-10-14T18:44:00.000+02:00</published><updated>2004-11-22T01:58:43.943+02:00</updated><title type='text'>What Politicians Don't Talk About</title><content type='html'>While watching the presidential debates, it occurred to me that there's a lot of relevant stuff that politicians all know, but don't talk about.&lt;br /&gt;&lt;br /&gt;For example, I don't think anyone disputes that a strong motivation for invading Iraq was fear of unfriendly power over America's interests, namely its interest in cheap oil. (Why not Libya?) Presumably there's a good political reason why Kerry also doesn't mention this.&lt;br /&gt;&lt;br /&gt;It goes the other way too; much of what politicians talk about is completely irrelevant.&lt;br /&gt;&lt;br /&gt;Besides being highly cynical, what's wrong with this state of affairs? It insulates much of the electorate from political reality, but you could argue that everyone would be almost as insulated anyway.&lt;br /&gt;&lt;br /&gt;Are the members of one political party disproportionately guilty of this disingenuousness?&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109777281354283554?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109777281354283554/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109777281354283554' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109777281354283554'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109777281354283554'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_10_01_archive.html#109777281354283554' title='What Politicians Don&apos;t Talk About'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109751738345964078</id><published>2004-10-11T19:42:00.000+02:00</published><updated>2005-03-02T00:52:05.630+02:00</updated><title type='text'>Spaces vs. Tabs</title><content type='html'>How should programs be indented, with tabs or with spaces?&lt;br /&gt;&lt;br /&gt;This is not a question of whether the programmer hits the Tab key or the space bar on the keyboard. It's a question of what actually goes in the file, and what happens when people want to use different numbers of spaces to display indentation levels. Literal Tab characters are referred to as "hard tabs", and sequences of Space characters are referred to as "soft tabs".&lt;br /&gt;&lt;br /&gt;(Almost) everyone agrees that a single file should use only one or the other for indentation. Mixing hard and soft tabs has more problems than either of the other two pure approaches, and causes confusion.&lt;br /&gt;&lt;br /&gt;This is a religious war, but both approaches have their advantages:&lt;br /&gt;&lt;br /&gt;Advantages of Soft Tabs&lt;br /&gt;&lt;ol&gt;&lt;li&gt;columns may be arbitrarily aligned&lt;/li&gt;&lt;li&gt;xterm copying doesn't need special handling&lt;br /&gt;&lt;/li&gt;  &lt;/ol&gt;Advantages of Hard Tabs&lt;br /&gt;&lt;ol&gt;&lt;li&gt;backspace and navigation work nicely&lt;/li&gt;&lt;li&gt;number of displayed spaces is customizable&lt;/li&gt;   &lt;li&gt;indentation semantic is represented directly, and already standard&lt;/li&gt;&lt;li&gt;makefiles don't need special handling&lt;br /&gt;&lt;/li&gt; &lt;/ol&gt;&lt;h3&gt;Arbitrary Alignments using Hard Tabs&lt;/h3&gt;With hard tabs, you can't portably line up your comments or constants like this:&lt;br /&gt;&lt;pre&gt;doSomething();                             # this is a silly block of code,&lt;br /&gt;doSomethingElseWithAMuchLongerStatement(); # which has a multi-line comment,&lt;br /&gt;                                           # which extends past the code itself&lt;/pre&gt;&lt;br /&gt;All but the third line could easily be solved by using spaces for tabs that occur after non-whitepace on each line. Some refer to this as a third camp "use tabs for indentation and spaces for alignment", and others reduce it to "use tabs for indentation and eschew alignment".&lt;br /&gt;&lt;br /&gt;Hard tabbing also requires:&lt;br /&gt;&lt;pre&gt;mylist = [&lt;br /&gt;           1,&lt;br /&gt;           2,&lt;br /&gt;           3&lt;br /&gt;]&lt;/pre&gt;instead of&lt;br /&gt;&lt;pre&gt;mylist = [ 1,&lt;br /&gt;           2,&lt;br /&gt;           3&lt;br /&gt;]&lt;/pre&gt; &lt;h3&gt;Xterm Clipboard using Hard Tabs&lt;/h3&gt; Copying from an xterm converts hard tabs to soft tabs, so you have to configure your editor to convert them back.&lt;br /&gt;&lt;h3&gt;Navigation using Soft Tabs&lt;/h3&gt;Just like a single keystroke creates an indentation level, a single keystroke should move the cursor over an indentation level. Modern editors allow you to back up an indentation level using the Backspace key, but don't yet allow you to navigate indentation levels using the arrow keys.&lt;br /&gt;&lt;h3&gt;Customizing the Number of Displayed Spaces using Soft Tabs&lt;/h3&gt; Though it's certainly possible to munge source code in order to customize the tabstop, it's a little risky. Tools for some languages (perl) don't make any guarantees that it can be done reliably. Even if you can do it reliably, you'll have to hack it, and if you also make modifications you'll probably cause bogus diff history.&lt;br /&gt;&lt;h3&gt;Makefiles using Soft Tabs&lt;/h3&gt; The configuration files used by the &lt;code&gt;make&lt;/code&gt; tool require hard tabs, so your editor has to handle this.&lt;br /&gt;&lt;h3&gt;Semantics&lt;br /&gt;&lt;/h3&gt; There is some beauty in representing the semantic unit with a single character, and without extraneous formatting information (sort of like "\n" instead of "\r\n"). Maybe as editors get better at nicely formatting source code, soft tabs will become less attractive.&lt;br /&gt;&lt;h3&gt;Editor Configuration&lt;/h3&gt;vim for soft tabbers: &lt;code&gt;set expandtab | set smarttab&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;and &lt;code&gt;shiftwidth&lt;/code&gt; should be set to configure the number of spaces to use for indentation; &lt;code&gt;tabstop&lt;/code&gt; will be only be consulted for tabs not occurring at the beginning of the line. In order to handle makefiles, use: &lt;tt&gt;au FileType make setlocal noexpandtab&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;vim for hard tabbers: &lt;code&gt;set noexpandtab&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;or maybe use a &lt;a href="http://www.vim.org/scripts/script.php?script_id=231"&gt;script to expand tabs later in the line&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109751738345964078?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109751738345964078/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109751738345964078' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109751738345964078'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109751738345964078'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_10_01_archive.html#109751738345964078' title='Spaces vs. Tabs'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109751329429997854</id><published>2004-10-11T18:25:00.000+02:00</published><updated>2004-10-15T17:18:05.223+02:00</updated><title type='text'>Platform Proliferation</title><content type='html'>Along the lines of the previous post, I hate platform proliferation. Even using the same programming language, code must be rewritten for each platform.&lt;br /&gt;&lt;br /&gt;Windows and Mac each have a couple of platforms, as do the free desktops projects (Gnome and KDE), the major cross platform applications (Mozilla and OpenOffice), and most modern "languages" (e.g. Java, Python, OCaml).&lt;br /&gt;&lt;br /&gt;People love the UNIX interface, in which everything is a file, and a file is a stream of bytes which may have a hierarchical name. That interface now appears to be insufficiently rich, but &lt;a href="http://www.jwz.org/doc/worse-is-better.html"&gt;it's powerful exactly because it's so simple&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Maybe there's a new interface which is comparably simple, but can do 80% of what we want for components? Some examples of difficult modules to support are: graphical user interface, spell-checking, auto-completion, clipboard and search and undo, linking and embedding documents.&lt;br /&gt;&lt;br /&gt;At the &lt;a href="http://www.0xdeadbeef.com/html/2004/07/#200407190952"&gt;Desktop Developer Conference, Havoc Pennington&lt;/a&gt; talked about fragmentation of platforms.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109751329429997854?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109751329429997854/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109751329429997854' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109751329429997854'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109751329429997854'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_10_01_archive.html#109751329429997854' title='Platform Proliferation'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109708622280107087</id><published>2004-10-06T19:49:00.000+02:00</published><updated>2006-09-23T00:51:17.720+03:00</updated><title type='text'>One True Language</title><content type='html'>Techies often insist that it's good that there're many different programming languages, because each language has its strengths. They say that language design is all about making compromises, and that the compromises chosen for each is best for a particular problem domain.&lt;br /&gt;&lt;br /&gt;This is a big mistake. For most applications, the benefit of using a specific language is minimal. The cost, however, of having code written in many different languages is huge. Code written in different languages is difficult to re-use. It's difficult to integrate. It's difficult to learn and support. In short, the language that code is written in is its single biggest dependency, and we are increasing and fracturing dependencies for no good reason. For a recent project at work, I had to write in several different languages: Java, Perl, Csh, SQL / Sybase stored proc language, XML, and a proprietary "Job Information Language". A single language could satisfactorily perform the jobs of all, and it would only need a single toolset.&lt;br /&gt;&lt;br /&gt;Techies like the idea of a large language ecosystem because they love this stuff. They're attached to it, and want to see more of it. They love languages like shoemakers love shoes.&lt;br /&gt;&lt;br /&gt;It almost doesn't matter what the one true language is, but of course I'm going to share some ideas about what I think it should look like.&lt;br /&gt;&lt;br /&gt;The C programming language was an abstraction layer for making code portable. The next abstraction layer should make it &lt;em&gt;as easy as possible to write and maintain code&lt;/em&gt;. All the other requirements are relatively insignificant.&lt;br /&gt;&lt;br /&gt;So the language should be mostly procedural and object oriented. It should have automatic garbage collection. It should have built-in collection classes. It &lt;a href="http://www.mindview.net/WebLog/log-0025"&gt;should be dynamically typed&lt;/a&gt;, but strongly typed.&lt;br /&gt;&lt;h3&gt;The Zen of Python (by Tim Peters)&lt;/h3&gt;Beautiful is better than ugly.&lt;br /&gt;Explicit is better than implicit.&lt;br /&gt;Simple is better than complex.&lt;br /&gt;Complex is better than complicated.&lt;br /&gt;Flat is better than nested.&lt;br /&gt;Sparse is better than dense.&lt;br /&gt;Readability counts.&lt;br /&gt;Special cases aren't special enough to break the rules.&lt;br /&gt;Although practicality beats purity.&lt;br /&gt;Errors should never pass silently.&lt;br /&gt;Unless explicitly silenced.&lt;br /&gt;In the face of ambiguity, refuse the temptation to guess.&lt;br /&gt;There should be one-- and preferably only one --obvious way to do it.&lt;br /&gt;Although that way may not be obvious at first unless you're Dutch.&lt;br /&gt;Now is better than never.&lt;br /&gt;Although never is often better than *right* now.&lt;br /&gt;If the implementation is hard to explain, it's a bad idea.&lt;br /&gt;If the implementation is easy to explain, it may be a good idea.&lt;br /&gt;Namespaces are one honking great idea -- let's do more of those!&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109708622280107087?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109708622280107087/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109708622280107087' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109708622280107087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109708622280107087'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_10_01_archive.html#109708622280107087' title='One True Language'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109456655406629237</id><published>2004-10-05T17:15:00.000+02:00</published><updated>2004-12-07T21:31:59.543+02:00</updated><title type='text'>Property</title><content type='html'>When we talk about "intellectual property" (IP), we've already decided exactly how it should work. Calling it "property" makes us think we should treat it like a sandwich, though it's really more like the proverbial cake that you can eat, and have it too.&lt;br /&gt;&lt;br /&gt;100 years ago, when you bought a book, you &lt;strong&gt;owned&lt;/strong&gt; that book. You could do anything you wanted with your copy of that book except make a copy of it. The government gave publishers the right to prevent copying their books, in order to maximize the amount of publishing that would be done.&lt;br /&gt;&lt;br /&gt;Now, when you buy a book, you haven't bought anything. You've &lt;strong&gt;licensed&lt;/strong&gt; that book. The publisher retains all the rights except for limited reading privileges.&lt;br /&gt;&lt;br /&gt;This isn't yet completely true, but it is the way that everyone already thinks of it. The law considers every digital access to be a "copy", so every use is governed by copyright. "Click-wrap" and "shrink-wrap" allow publishers to easily dispense with traditional copyright, and invent any bizarre license conditions they please. This is only logical, since the publisher owns the work.&lt;br /&gt;&lt;br /&gt;What's wrong with strict intellectual property? Shouldn't the market discourage unreasonable license terms, like &lt;a href="http://www.pigdogs.org/art/adobe.html"&gt;restricting the right to read books aloud&lt;/a&gt;?&lt;br /&gt;&lt;br /&gt;Well this market is inefficient. Publishers consolidate. Publishers are big, and consumers, in general, are small. This makes it difficult for consumers to negotiate. It's a shame that fair use will suffer, but there are two bigger problems with strong IP:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;it's grossly inefficient&lt;/li&gt;&lt;li&gt;it could hamper the "prosumer revolution"&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The internet makes it so easy to publish that potentially every consumer could become a producer of valuable creative work. Creative work is possible only by building on top of existing work. Clearing rights has become significantly more difficult than distribution. Most lawyers don't see anything wrong with increasing the need for lawyering in the world, but everyone else should recognize that the extra transaction costs are prohibitive.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;It's hard to tell how inefficient our current system is, without real systems to compare it to. But it's equally hard to believe that authors are motivated by the potential revenues from their work 100 years from now. Less extreme cases are harder to judge.&lt;br /&gt;&lt;/p&gt; &lt;p&gt;With what should the intellectual property metaphor be replaced?&lt;br /&gt;&lt;/p&gt; &lt;p&gt;Many thinkers advocate "compulsory licensing", which requires everyone to pay a tax for funding new works. The proceeds from this tax would be divided up and awarded to authors based on the results of some sort of polling. It would be difficult to prevent gaming such a system. It would also be difficult to properly poll for derivative works. It would probably require administration to assign weightings to different types of work.&lt;br /&gt;&lt;/p&gt; &lt;p&gt;Alternatively, we could eliminate copyright law altogether, and have publishers just protect new content as best they can. This wouldn't be so different from today, except that content which is eventually freed would then be legal. Books would be the big loser in this scenario, because they are almost impossible to protect. Once comfortable reader devices are available, copying books will become rampant.&lt;br /&gt;&lt;/p&gt; &lt;p&gt;see &lt;a href="http://papers.ssrn.com/sol3/papers.cfm?abstract_id=582602"&gt;Property, Intellectual Property, and Free Riding&lt;/a&gt; and &lt;a href="http://msl1.mit.edu/ESD10/docs/darknet5.pdf"&gt;The Darknet Paper&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109456655406629237?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109456655406629237/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109456655406629237' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109456655406629237'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109456655406629237'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_10_01_archive.html#109456655406629237' title='Property'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109692702160454597</id><published>2004-10-04T23:55:00.000+02:00</published><updated>2004-10-04T23:57:01.606+02:00</updated><title type='text'>Hallel</title><content type='html'>ברוך אתה יהוה אלהינו מלך העולם אשר קדשנו במצותיו וצונו על נתילת לולב&lt;br /&gt;ברוך אתה יהוה אלהינו מלך העולם אשר קדשנו במצותיו וצונו לקרוא את ההלל&lt;br /&gt;&lt;br /&gt;הַלְלוּ-יָהּ:הַלְלוּ, עַבְדֵי יְהוָה; הַלְלוּ, אֶת-שֵׁם יְהוָה. יְהִי שֵׁם יְהוָה מְבֹרָךְ-- מֵעַתָּה, וְעַד-עוֹלָם. מִמִּזְרַח-שֶׁמֶשׁ עַד-מְבוֹאוֹ-- מְהֻלָּל, שֵׁם יְהוָה. רָם עַל-כָּל-גּוֹיִם יְהוָה; עַל הַשָּׁמַיִם כְּבוֹדוֹ. מִי, כַּיהוָה אֱלֹהֵינוּ-- הַמַּגְבִּיהִי לָשָׁבֶת. הַמַּשְׁפִּילִי לִרְאוֹת-- בַּשָּׁמַיִם וּבָאָרֶץ. מְקִימִי מֵעָפָר דָּל; מֵאַשְׁפֹּת, יָרִים אֶבְיוֹן. לְהוֹשִׁיבִי עִם-נְדִיבִים; עִם, נְדִיבֵי עַמּוֹ. מוֹשִׁיבִי, עֲקֶרֶת הַבַּיִת-- אֵם-הַבָּנִים שְׂמֵחָה: הַלְלוּ-יָהּ.&lt;br /&gt;&lt;br /&gt;בְּצֵאת יִשְׂרָאֵל, מִמִּצְרָיִם; בֵּית יַעֲקֹב, מֵעַם לֹעֵז. הָיְתָה יְהוּדָה לְקָדְשׁוֹ; יִשְׂרָאֵל, מַמְשְׁלוֹתָיו. הַיָּם רָאָה, וַיָּנֹס; הַיַּרְדֵּן, יִסֹּב לְאָחוֹר. הֶהָרִים, רָקְדוּ כְאֵילִים; גְּבָעוֹת, כִּבְנֵי-צֹאן. מַה-לְּךָ הַיָּם, כִּי תָנוּס; הַיַּרְדֵּן, תִּסֹּב לְאָחוֹר. הֶהָרִים, תִּרְקְדוּ כְאֵילִים; גְּבָעוֹת, כִּבְנֵי-צֹאן. מִלִּפְנֵי אָדוֹן, חוּלִי אָרֶץ; מִלִּפְנֵי, אֱלוֹהַּ יַעֲקֹב. הַהֹפְכִי הַצּוּר אֲגַם-מָיִם; חַלָּמִישׁ, לְמַעְיְנוֹ-מָיִם.&lt;br /&gt;&lt;br /&gt;לֹא לָנוּ יְהוָה, לֹא-לָנוּ: כִּי-לְשִׁמְךָ, תֵּן כָּבוֹד--עַל-חַסְדְּךָ, עַל-אֲמִתֶּךָ. לָמָּה, יֹאמְרוּ הַגּוֹיִם: אַיֵּה-נָא, אֱלֹהֵיהֶם. וֵאלֹהֵינוּ בַשָּׁמָיִם--כֹּל אֲשֶׁר-חָפֵץ עָשָׂה. עֲצַבֵּיהֶם, כֶּסֶף וְזָהָב; מַעֲשֵׂה, יְדֵי אָדָם. פֶּה-לָהֶם, וְלֹא יְדַבֵּרוּ; עֵינַיִם לָהֶם, וְלֹא יִרְאוּ. אָזְנַיִם לָהֶם, וְלֹא יִשְׁמָעוּ; אַף לָהֶם, וְלֹא יְרִיחוּן. יְדֵיהֶם, וְלֹא יְמִישׁוּן--רַגְלֵיהֶם, וְלֹא יְהַלֵּכוּ; לֹא-יֶהְגּוּ, בִּגְרוֹנָם. כְּמוֹהֶם, יִהְיוּ עֹשֵׂיהֶם-- כֹּל אֲשֶׁר-בֹּטֵחַ בָּהֶם. יִשְׂרָאֵל, בְּטַח בַּיהוָה; עֶזְרָם וּמָגִנָּם הוּא. בֵּית אַהֲרֹן, בִּטְחוּ בַיהוָה; עֶזְרָם וּמָגִנָּם הוּא. יִרְאֵי יְהוָה, בִּטְחוּ בַיהוָה; עֶזְרָם וּמָגִנָּם הוּא.&lt;br /&gt;&lt;br /&gt;יְהוָה, זְכָרָנוּ יְבָרֵךְ: יְבָרֵךְ, אֶת-בֵּית יִשְׂרָאֵל; יְבָרֵךְ, אֶת-בֵּית אַהֲרֹן. יְבָרֵךְ, יִרְאֵי יְהוָה-- הַקְּטַנִּים, עִם-הַגְּדֹלִים. יֹסֵף יְהוָה עֲלֵיכֶם; עֲלֵיכֶם, וְעַל בְּנֵיכֶם. בְּרוּכִים אַתֶּם, לַיהוָה-- עֹשֵׂה, שָׁמַיִם וָאָרֶץ. הַשָּׁמַיִם שָׁמַיִם, לַיהוָה; וְהָאָרֶץ, נָתַן לִבְנֵי-אָדָם. לֹא הַמֵּתִים, יְהַלְלוּ-יָהּ; וְלֹא, כָּל-יֹרְדֵי דוּמָה. וַאֲנַחְנוּ, נְבָרֵךְ יָהּ-- מֵעַתָּה וְעַד-עוֹלָם: הַלְלוּ-יָהּ.&lt;br /&gt;&lt;br /&gt;אָהַבְתִּי, כִּי-יִשְׁמַע יְהוָה-- אֶת-קוֹלִי, תַּחֲנוּנָי. כִּי-הִטָּה אָזְנוֹ לִי; וּבְיָמַי אֶקְרָא. אֲפָפוּנִי, חֶבְלֵי-מָוֶת--וּמְצָרֵי שְׁאוֹל מְצָאוּנִי; צָרָה וְיָגוֹן אֶמְצָא. וּבְשֵׁם-יְהוָה אֶקְרָא: אָנָּה יְהוָה, מַלְּטָה נַפְשִׁי. חַנּוּן יְהוָה וְצַדִּיק; וֵאלֹהֵינוּ מְרַחֵם. שֹׁמֵר פְּתָאיִם יְהוָה; דַּלֹּתִי, וְלִי יְהוֹשִׁיעַ. שׁוּבִי נַפְשִׁי, לִמְנוּחָיְכִי: כִּי-יְהוָה, גָּמַל עָלָיְכִי. כִּי חִלַּצְתָּ נַפְשִׁי, מִמָּוֶת: אֶת-עֵינִי מִן-דִּמְעָה; אֶת-רַגְלִי מִדֶּחִי. אֶתְהַלֵּךְ, לִפְנֵי יְהוָה-- בְּאַרְצוֹת, הַחַיִּים. הֶאֱמַנְתִּי, כִּי אֲדַבֵּר; אֲנִי, עָנִיתִי מְאֹד. אֲנִי, אָמַרְתִּי בְחָפְזִי: כָּל-הָאָדָם כֹּזֵב.&lt;br /&gt;&lt;br /&gt;מָה-אָשִׁיב לַיהוָה-- כָּל-תַּגְמוּלוֹהִי עָלָי. כּוֹס-יְשׁוּעוֹת אֶשָּׂא; וּבְשֵׁם יְהוָה אֶקְרָא. נְדָרַי, לַיהוָה אֲשַׁלֵּם; נֶגְדָה-נָּא, לְכָל-עַמּוֹ. יָקָר, בְּעֵינֵי יְהוָה--הַמָּוְתָה, לַחֲסִידָיו. אָנָּה יְהוָה, כִּי-אֲנִי עַבְדֶּךָ: אֲנִי-עַבְדְּךָ, בֶּן-אֲמָתֶךָ; פִּתַּחְתָּ, לְמוֹסֵרָי. לְךָ-אֶזְבַּח, זֶבַח תּוֹדָה; וּבְשֵׁם יְהוָה אֶקְרָא. נְדָרַי, לַיהוָה אֲשַׁלֵּם; נֶגְדָה-נָּא, לְכָל-עַמּוֹ. בְּחַצְרוֹת, בֵּית יְהוָה-- בְּתוֹכֵכִי יְרוּשָׁלִָם: הַלְלוּ-יָהּ.&lt;br /&gt;&lt;br /&gt;הַלְלוּ אֶת-יְהוָה, כָּל-גּוֹיִם; שַׁבְּחוּהוּ, כָּל-הָאֻמִּים. כִּי גָבַר עָלֵינוּ, חַסְדּוֹ--וֶאֱמֶת-יְהוָה לְעוֹלָם: הַלְלוּ-יָהּ.&lt;br /&gt;&lt;br /&gt;הוֹדוּ לַיהוָה כִּי-טוֹב: כִּי לְעוֹלָם חַסְדּוֹ.&lt;br /&gt;יֹאמַר-נָא יִשְׂרָאֵל: כִּי לְעוֹלָם חַסְדּוֹ.&lt;br /&gt;יֹאמְרוּ-נָא בֵית-אַהֲרֹן: כִּי לְעוֹלָם חַסְדּוֹ.&lt;br /&gt;יֹאמְרוּ-נָא יִרְאֵי יְהוָה: כִּי לְעוֹלָם חַסְדּוֹ.&lt;br /&gt;מִן-הַמֵּצַר, קָרָאתִי יָּהּ; עָנָנִי בַמֶּרְחָב יָהּ. יְהוָה לִי, לֹא אִירָא; מַה-יַּעֲשֶׂה לִי אָדָם. יְהוָה לִי, בְּעֹזְרָי; וַאֲנִי, אֶרְאֶה בְשֹׂנְאָי. טוֹב, לַחֲסוֹת בַּיהוָה-- מִבְּטֹחַ, בָּאָדָם. טוֹב, לַחֲסוֹת בַּיהוָה-- מִבְּטֹחַ, בִּנְדִיבִים. כָּל-גּוֹיִם סְבָבוּנִי; בְּשֵׁם יְהוָה, כִּי אֲמִילַם. סַבּוּנִי גַם-סְבָבוּנִי; בְּשֵׁם יְהוָה, כִּי אֲמִילַם. סַבּוּנִי כִדְבוֹרִים-- דֹּעֲכוּ, כְּאֵשׁ קוֹצִים; בְּשֵׁם יְהוָה, כִּי אֲמִילַם. דַּחֹה דְחִיתַנִי לִנְפֹּל; וַיהוָה עֲזָרָנִי. עָזִּי וְזִמְרָת יָהּ; וַיְהִי-לִי, לִישׁוּעָה. קוֹל, רִנָּה וִישׁוּעָה--בְּאָהֳלֵי צַדִּיקִים; יְמִין יְהוָה, עֹשָׂה חָיִל. יְמִין יְהוָה, רוֹמֵמָה; יְמִין יְהוָה, עֹשָׂה חָיִל. לֹא-אָמוּת כִּי-אֶחְיֶה; וַאֲסַפֵּר, מַעֲשֵׂי יָהּ. יַסֹּר יִסְּרַנִּי יָּהּ; וְלַמָּוֶת, לֹא נְתָנָנִי. פִּתְחוּ-לִי שַׁעֲרֵי-צֶדֶק; אָבֹא-בָם, אוֹדֶה יָהּ. זֶה-הַשַּׁעַר לַיהוָה; צַדִּיקִים, יָבֹאוּ בוֹ. אוֹדְךָ, כִּי עֲנִיתָנִי; וַתְּהִי-לִי, לִישׁוּעָה. אֶבֶן, מָאֲסוּ הַבּוֹנִים-- הָיְתָה, לְרֹאשׁ פִּנָּה. מֵאֵת יְהוָה, הָיְתָה זֹּאת; הִיא נִפְלָאת בְּעֵינֵינוּ. זֶה-הַיּוֹם, עָשָׂה יְהוָה; נָגִילָה וְנִשְׂמְחָה בוֹ.&lt;br /&gt;&lt;br /&gt;אָנָּא יְהוָה, הוֹשִׁיעָה נָּא;&lt;br /&gt;אָנָּא יְהוָה, הַצְלִיחָה נָּא.&lt;br /&gt;&lt;br /&gt;בָּרוּךְ הַבָּא, בְּשֵׁם יְהוָה; בֵּרַכְנוּכֶם, מִבֵּית יְהוָה. אֵל, יְהוָה--וַיָּאֶר-לָנוּ: אִסְרוּ-חַג בַּעֲבֹתִים--עַד קַרְנוֹת, הַמִּזְבֵּחַ. אֵלִי אַתָּה וְאוֹדֶךָּ; אֱלֹהַי, אֲרוֹמְמֶךָּ. הוֹדוּ לַיהוָה כִּי-טוֹב: כִּי לְעוֹלָם חַסְדּוֹ.&lt;br /&gt;&lt;br /&gt;יהללוך יהוה אלהינו כל מעשיך וחסידיך צדיקים עושי רצונך וכל עמך בית ישראל ברנה יודו ויברכו וישבחו ויפארו וירוממו ויעריצו ויקדישו וימליכו את שמך מלכנו כי לך טוב להודות ולשמך נאה לזמר כי מעולם ועד עולם אתה אל ברוך אתה יהוה מלך מהלל בתשבחות&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109692702160454597?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109692702160454597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109692702160454597' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109692702160454597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109692702160454597'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_10_01_archive.html#109692702160454597' title='Hallel'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109629384826492168</id><published>2004-09-27T15:55:00.000+02:00</published><updated>2007-02-20T18:50:15.866+02:00</updated><title type='text'>Open Source/Closed Standards</title><content type='html'>In the quest to open source java, it should be the &lt;em&gt;trademark&lt;/em&gt; that depends on passing a test suite.&lt;br /&gt;&lt;br /&gt;An example which hits the difference: a nonconfirming "John's Java" would be illegal unless I call it something different, but borrowing a linked list implementation for my embedded linux toaster project would be fine. I'd think that trademark affects the big players here more than copyright.&lt;br /&gt;&lt;br /&gt;I'm responding to &lt;a href=http://www.oreillynet.com/pub/wlg/5651&gt;this O' Reilly blog entry&lt;/a&gt;.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109629384826492168?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109629384826492168/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109629384826492168' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109629384826492168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109629384826492168'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_09_01_archive.html#109629384826492168' title='Open Source/Closed Standards'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109586049426694331</id><published>2004-09-22T15:40:00.000+02:00</published><updated>2007-01-17T01:58:36.500+02:00</updated><title type='text'>Complex Systems</title><content type='html'>&amp;quot;A complex system that works is invariably found to have evolved from a simple system that worked.&amp;quot;&lt;br /&gt;--John Gall&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109586049426694331?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109586049426694331/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109586049426694331' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109586049426694331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109586049426694331'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_09_01_archive.html#109586049426694331' title='Complex Systems'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109416163058917716</id><published>2004-09-03T01:17:00.000+03:00</published><updated>2004-09-21T16:48:51.016+03:00</updated><title type='text'>GPL better and worse than you thought</title><content type='html'>&lt;p&gt;&lt;strong&gt;Worse&lt;/strong&gt;, for two reasons:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Anyone can modify GPL'ed software to give it an interface for interacting with proprietary software. Those modifications can even be GPL'ed :).&lt;/li&gt;&lt;li&gt;Anyone can distribute proprietary software which links to GPL'ed software. The proprietary author can claim that his software could instead link to a non-GPL'ed implementation of the interface. It's the &lt;strong&gt;user&lt;/strong&gt; that is performing the linkage, and since the GPL only restricts distribution, he certainly isn't culpable.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Now these reasons only apply to re-use of GPL software with other software. Improvements to GPL'ed software should still be illegal to make proprietary.&lt;/p&gt;&lt;p&gt;If the GPL doesn't prevent proprietary re-use, maybe maintenance costs do. Proprietary projects will have to port their software to new releases of the free software without support, because the the free projects can't incorporate their changes.&lt;/p&gt;&lt;p&gt;Both gcc and the linux kernel appear to benefit from this effect. &lt;a href="http://lkml.org/lkml/1999/2/8/13"&gt;Linus Torvalds has refused to make technical compromises&lt;/a&gt; in order to ease the burden of proprietary module writers (even though their work is apparently legal). &lt;a href="http://gcc.gnu.org/ml/gcc/2001-02/msg00895.html"&gt;Richard Stallman has refused to make gcc more flexible&lt;/a&gt; lest he encourage proprietary extensions.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Better&lt;/strong&gt;, because &lt;a href="http://www.groklaw.net/article.php?story=20040901004705872"&gt;free software is actually less susceptible to patent litigation&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;As a complete non sequitur, &lt;a href="http://blogs.sun.com/roller/comments/bmc/Weblog/the_economics_of_software"&gt;free software is an antidote to lock-in&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109416163058917716?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109416163058917716/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109416163058917716' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109416163058917716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109416163058917716'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_09_01_archive.html#109416163058917716' title='GPL better and worse than you thought'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6905430.post-109414368718379404</id><published>2004-09-02T19:22:00.000+03:00</published><updated>2005-11-18T11:50:13.040+02:00</updated><title type='text'>HTML Screenscraping</title><content type='html'>Cool tool idea: an api that exposes the way a web page appears to a human viewer.&lt;br /&gt;&lt;br /&gt;Such a tool would have ways to find page elements based on relative size and position with respect to other elements. It would allow grabbing "the same column in the next row of this table".&lt;br /&gt;&lt;br /&gt;This would be complicated, of course, by weird formatting hacks whose elements aren't independently visible (like nested tables).&lt;br /&gt;&lt;br /&gt;Even more ambitious would be to support touchy-feely things like finding a table by its "title", when that title is really a semantically unrelated, but visually tied element.&lt;br /&gt;&lt;br /&gt;Using the tool would be a little frustrating, because it would never perfectly track all possible changes to the presentation of a site (e.g. some data may be moved between pages, or split up into multiple tables in the same page). Nevertheless, I think it would be a huge commercial success. It might also be a nice as component in a semantic web migration framework.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6905430-109414368718379404?l=farfetched.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://farfetched.blogspot.com/feeds/109414368718379404/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6905430&amp;postID=109414368718379404' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109414368718379404'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6905430/posts/default/109414368718379404'/><link rel='alternate' type='text/html' href='http://farfetched.blogspot.com/2004_09_01_archive.html#109414368718379404' title='HTML Screenscraping'/><author><name>farfetched</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
