nLeyten

Ocsigen by example, Part 8: Wizards


In the eighth (and last one with real code) instalment in this series, the topic is the creation of wizard-like interactions via session co-services. By wizard-like we mean a web interaction that is akin to the so called "wizards" used in traditional GUIs. Namely, a discrete series of steps that must be followed sequentially to produce a final result. Each step is displayed in its own page, and corresponds to a separate request to the server.

Given the stateless nature of the HTTP protocol you can imagine that the realisation of a wizard is far from trivial without some help from the development framework. Moreover, the browser as an application environment differs from traditional GUI apps in that the users are free to duplicate browser windows, press the 'back' button, bookmark a certain page, etc. Consider for example a simple wizard consisting of three steps:

  • Step 1: Ask the user for an integer 'x';
  • Step 2: Ask the user for an integer 'y';
  • Step 3: Present the sum of 'x' and 'y'.

You would want your web application to correctly handle the bifurcation caused by the user duplicating the browser window at, for example, step 2. Furthermore, the web application should not get confused if the back button had been used in a complex interaction with multiple bifurcations.

Thankfully, Ocsigen/Eliom offers the facilities to make the creation of wizards fairly simple. Co-services allow for the differentiation of the various steps, even if they all share the same URL. Furthermore, you can declare session co-services, which personalise co-services for each individual user of the website (Eliom automatically sets a cookie on the user's browser for this purpose).

The figure below illustrates with pseudo-code the approach for solving the wizard problem described above (this same pattern can be used for a wizard with any number of steps). Though the handlers for the three steps are presented and declared top-to-bottom, to better understand what is going on the figure should be read bottom-to-top. The general wizard pattern consists of using the handler for step n to register step n+1. Each step is registered via Eliom_predefmod.Xhtml.register_new_post_coservice_for_session, though you could of course also create a wizard using only GET parameters instead of POST ones.

Note that step 3, besides getting value 'y' as a POST parameter, also needs to know about the value 'x' which was given as a parameter to step 2. Now take a look at the signature for wizard3_handler; you will see that with the partial application of value 'x', you get a standard Eliom service handler that furthermore knows about value 'x'. The partial application itself happens in the handler for step 2, during the registration of step 3. This example illustrates how two of the staples of functional programming languages — closures and partial application of functions — are used to great advantage within the Ocsigen/Eliom framework.

To conclude we present the complete code to solve this three-step wizard problem. As with the illustration above, we suggest you read the code by inverse declaration order, ie, by starting at the bottom.

(************************************************************************)
(* Wizard using session coservices with POST parameters. *)
(************************************************************************)

open XHTML.M


(************************************************************************)
(* Declare service "wizard1", the starting point of the wizard,
and fallback routine for the subsequent steps.
*)

let wizard1_service =
Eliom_services.new_service
~path: [""]
~get_params: Eliom_parameters.unit
()


(************************************************************************)
(* The handler for "wizard3", the third and final step of the wizard.
Note that by doing a partial application with parameter X, you get
a function that can be used as a handler for an Eliom service.
*)

let wizard3_handler x sp () y =
let x_str = string_of_int x
and y_str = string_of_int y in
let total = string_of_int (x + y)
in Lwt.return
(html
(head (title (pcdata "Wizard step 3/3")) [])
(body [
p [pcdata ("X : " ^ x_str)];
p [pcdata ("Y : " ^ y_str)];
p [pcdata ("Total : " ^ total)];
]))


(************************************************************************)
(* The handler for "wizard2", the second step of the wizard. Note
that this step registers step 3, and declares the form creation
function for that step. The number X is given as a POST parameter,
and is passed to the subsequent step by partial application.

*)

let wizard2_handler sp () x =
let wizard3_service = Eliom_predefmod.Xhtml.register_new_post_coservice_for_session
~sp
~fallback: wizard1_service
~post_params: (Eliom_parameters.int "y")
(wizard3_handler x) in
let wizard3_form enter_y =
[
fieldset
[
label ~a:[a_for "enter_y"] [pcdata ("Write number Y: ")];
Eliom_predefmod.Xhtml.int_input ~a:[a_id "enter_y"] ~input_type:`Text ~name:enter_y ();
Eliom_predefmod.Xhtml.string_input ~input_type:`Submit ~value:"Send" ()
]
]
in Lwt.return
(html
(head (title (pcdata "Wizard step 2/3")) [])
(body [Eliom_predefmod.Xhtml.post_form wizard3_service sp wizard3_form ()]))


(************************************************************************)
(* The handler for "wizard1", the initial step of the wizard. Note
that this step registers step 2, and declares the form creation
function for that step. Since this is the first step of the
wizard, it takes no parameters itself.
*)

let wizard1_handler sp () () =
let wizard2_service = Eliom_predefmod.Xhtml.register_new_post_coservice_for_session
~sp
~fallback: wizard1_service
~post_params: (Eliom_parameters.int "x")
wizard2_handler in
let wizard2_form enter_x =
[
fieldset
[
label ~a:[a_for "enter_x"] [pcdata ("Write number X: ")];
Eliom_predefmod.Xhtml.int_input ~a:[a_id "enter_x"] ~input_type:`Text ~name:enter_x ();
Eliom_predefmod.Xhtml.string_input ~input_type:`Submit ~value:"Send" ()
]
]
in Lwt.return
(html
(head (title (pcdata "Wizard step 1/3")) [])
(body [Eliom_predefmod.Xhtml.post_form wizard2_service sp wizard2_form ()]))


(************************************************************************)
(* Registration of the first step of the wizard, which also serves
as fallback.
*)

let () = Eliom_predefmod.Xhtml.register wizard1_service wizard1_handler

Ocsigen by example, Part 7: Co-services


Today's example focuses on co-services. A co-service is basically a service that shares its URL with a "parent" service, but which may have different parameters. Co-services are often used together with sessions to personalise a given URL for one specific user.

Since co-services share the same URL, how does Eliom know which one is being invoked? That distinction is made via a special hidden parameter. However, it is nothing that you should be worried about, as it happens transparently to the developer.

The code below is a minimalistic illustration of the possible use for a co-service. I suggest that you use the "view source" functionality of your browser to observe the hidden parameter contained in the page.

(************************************************************************)
(* Coservice demonstration. *)
(************************************************************************)

open XHTML.M


(************************************************************************)
(* Declaration of the "foobar" service. Note that we are not
registering it yet, and therefore we do not provide the handler
at this point.
*)

let foobar_service =
Eliom_services.new_service
~path: [""]
~get_params: Eliom_parameters.unit
()


(************************************************************************)
(* Declaration of the "foobar2" service, which is actually a
coservice for "foobar". Coservices share the same path as
the main service, but may have different parameters.
*)

let foobar2_service =
Eliom_services.new_coservice
~fallback: foobar_service
~get_params: (Eliom_parameters.int "amount")
()


(************************************************************************)
(* Handler for "foobar" service. It displays the current value of
the counter and provides links to reload itself or to invoke the
coservice with different parameters.
*)

let counter = ref 0

let foobar_handler sp () () =
Lwt.return
(html
(head (title (pcdata "")) [])
(body [p [
pcdata "counter is equal to ";
pcdata (string_of_int !counter);
br ();
Eliom_predefmod.Xhtml.a foobar_service sp [pcdata "reload"] ();
br ();
Eliom_predefmod.Xhtml.a foobar2_service sp [pcdata "increment by 1"] 1;
br ();
Eliom_predefmod.Xhtml.a foobar2_service sp [pcdata "increment by 2"] 2;
]]))


(************************************************************************)
(* Handler for the "foobar2" service (the coservice of "foobar").
Note that this handler just increments the counter by the amount
specified in the GET parameter and then invokes the handler of
"foobar" to display the actual page.
*)

let foobar2_handler sp amount () =
counter := !counter + amount;
foobar_handler sp () ()


(************************************************************************)
(* Registration of the services.
*)

let () =
Eliom_predefmod.Xhtml.register foobar_service foobar_handler;
Eliom_predefmod.Xhtml.register foobar2_service foobar2_handler

Ocsigen by example, Part 6: POST services


In the previous instalment of this series, the example illustrated the creation of a form for a GET service. This time we'll see a similar example, but one whose service uses POST instead of GET.

GET and POST are just two of the verbs part of the HTTP specification (other verbs are HEAD, PUT, DELETE, etc). The main visible difference is that a GET request encodes the parameters into the URL, whereas POST does so in the body of the request. It is therefore common that web developers pick one or the other based solely on this distinction. This criterion is however fundamentally wrong. GET should be used only for services that do not cause side-effects, and which are typically idempotent. Using GET disregarding this rule may subject your users to possible cross-site request forgery attacks.

As illustrated by the code below, the first thing to notice about POST services is that they require the declaration of the GET fallback service. The reason is because POST services encode parameters in the body of the request, and therefore their parameters are not recorded if the user bookmarks the URL. This requirement may seem annoying at first, but it fits very well with the emphasis on correctness that permeates Ocsigen/Eliom (and the Ocaml ecosystem in general). Another thing to notice is that function Eliom_predefmod.Xhtml.post_form (the POST counterpart of Eliom_predefmod.Xhtml.get_form) also requires the GET parameters for the service.

When trying this example, I suggest you reload the "coucou" URL after its first invocation via the form. You will see that upon the second invocation the fallback page is displayed, because no POST parameters were specified. (Depending on the browser, simply hitting "reload" will resend the POST parameters; therefore, select the URL and press ENTER for a clean invocation).

(************************************************************************)
(* Services with POST parameters. *)
(************************************************************************)

open XHTML.M
open Eliom_parameters


(************************************************************************)
(* This service is just the fallback for the "coucou" service, and
is never meant to be directly invoked. Eliom forces one to declare
these fallbacks because browsers bookmark only the GET parameters
and not the POST ones. There is therefore a chance the service is
invoked without any POST parameters.
*)

let fallback_handler _ () () =
Lwt.return
(html
(head (title (pcdata "Fallback")) [])
(body [p [pcdata "You've invoked the fallback service for coucou"]]))

let fallback_service =
Eliom_predefmod.Xhtml.register_new_service
~path: ["coucou"]
~get_params: Eliom_parameters.unit
fallback_handler


(************************************************************************)
(* Service "coucou" takes no GET parameters and one POST parameter.
Note that during the service registration the service path is not
indicated, since it will be the same as the fallback's. The same
goes for the GET parameters.
*)

let coucou_handler _ () foo =
Lwt.return
(html
(head (title (pcdata "Coucou")) [])
(body [p [pcdata ("The POST parameter is " ^ foo)]]))

let coucou_service =
Eliom_predefmod.Xhtml.register_new_post_service
~fallback: fallback_service
~post_params: (Eliom_parameters.string "foo")
coucou_handler


(************************************************************************)
(* This function creates a form for the "coucou" service. Note that
proper XHTML forms should be divided into fieldsets, and that any
input widget should have a matching label, as indicated via its ID.
*)

let coucou_form enter_foo =
let enter_foo_label = "enter_foo"
in [
fieldset
[
label ~a:[a_for enter_foo_label] [pcdata "String foo:"];
Eliom_predefmod.Xhtml.string_input ~a:[a_id enter_foo_label] ~input_type:`Text ~name:enter_foo ();
Eliom_predefmod.Xhtml.string_input ~input_type:`Submit ~value:"Click" ()
]
]



(************************************************************************)
(* The "main" service creates a form for the "coucou" POST service.
*)

let main_handler sp () () =
Lwt.return
(html
(head (title (pcdata "Main")) [])
(body [
p [pcdata "Please fill in this form:"];
Eliom_predefmod.Xhtml.post_form coucou_service sp coucou_form ()
]))

let main_service =
Eliom_predefmod.Xhtml.register_new_service
~path: [""]
~get_params: Eliom_parameters.unit
main_handler

Ocsigen by example, Part 5: GET forms


We've previously seen that Eliom ensures that hyperlinks to services are type-safe, ie, you cannot for example provide an alphabetic string (or no parameters at all) to a service that expects an integer. This type-safety is also extended to the creation and validation of XHTML forms. You can therefore provide together with a service a function that creates forms for that service. Eliom — or rather the compiler — makes sure the types are in harmony. Moreover, bear in mind that before invoking a service with any parameters, Eliom first checks that the parameters have values as expected. It will therefore raise an error if the user provided us with an alphabetic string in a form field that required an integer or a float, for example (it is of course possible to provide a custom handler for this sort of error situations instead of relying on the default one — check the Eliom tutorial for details).

Another cool feature is the possibility of Eliom services accepting custom types, and not just the predefined integers, floats, strings, etc. Again, check the tutorial for details.

The code below demonstrates the use of GET forms. It defines a "coucou" service taking three GET parameters of different types, and defines also a function "coucou_form" to create the contents of a form for "coucou". In service "main", this function is used as a parameter to Eliom_predefmod.Xhtml.get_form to actually create the form.

(************************************************************************)
(* Demonstration of forms for services with GET parameters. *)
(************************************************************************)

open XHTML.M
open Eliom_parameters


(************************************************************************)
(* Service "coucou" takes three GET parameters and no POST parameters.
*)
let coucou_handler _ (i, (j, s)) () =
Lwt.return
(html
(head (title (pcdata "Coucou")) [])
(body [p
[
pcdata "You sent: ";
strong [pcdata (string_of_int i)];
pcdata ", ";
strong [pcdata (string_of_float j)];
pcdata " and ";
strong [pcdata s]
]]))


let coucou_service =
Eliom_predefmod.Xhtml.register_new_service
~path: ["coucou"]
~get_params: (Eliom_parameters.int "i" ** (Eliom_parameters.float "j" ** Eliom_parameters.string "s"))
coucou_handler


(************************************************************************)
(* This function is used for building forms for service "coucou".
Note that its parameter is a nested pair defined in the same
fashion as the GET parameters for "coucou". Also note that
proper XHTML forms should make use of fieldsets for logically
dividing the form, and that field labels should be declared
with the

Ocsigen by example, Part 4: suffix parameters


In the examples we've seen so far, GET parameters were passed using the standard scheme (RFC 3986), ie, an ampersand delimited list of key-value assignments. As an alternative, Eliom offers also the possibility of encoding parameters as slash-delimited suffixes to the main URL. For many applications this produces friendlier and cleaner looking URLs.

As an example, consider a service "foobar" taking three integers as parameter: "year", "month", and "day". In the standard scheme, the service could be invoked with today's date by calling "foobar?year=2009&month=3&day=17". Using the suffix scheme, the same invocation becomes "foobar/2009/3/17". You trade the flexibility of specifying parameters by any order for the improved legibility.

The code sample below shows the definition of the service "foobar" using suffix parameters. Note that only the declaration of the service needs to change; any links towards this service created with Eliom_predefmod.Xhtml.a will automatically reflect the new convention (yet another reason to always use Eliom_predefmod.Xhtml.a!).

(************************************************************************)
(* Example for suffix parameters. *)
(************************************************************************)

open XHTML.M
open Eliom_parameters


(************************************************************************)
(* The "foobar" service takes three GET parameters, all integers.
It illustrates the use of Eliom_parameters.suffix to construct
friendlier looking URLs.
*)

let foobar_handler _ (year, (month, day)) () =
let date = (string_of_int year) ^ "/" ^ (string_of_int month) ^ "/" ^ (string_of_int day)
in Lwt.return
(html
(head (title (pcdata "Foobar")) [])
(body [p [pcdata ("The date specified by the GET parameters is " ^ date)]]))


let foobar_service =
Eliom_predefmod.Xhtml.register_new_service
~path: ["foobar"]
~get_params: (Eliom_parameters.suffix
(Eliom_parameters.int "year" **
(Eliom_parameters.int "month" **
Eliom_parameters.int "day")))
foobar_handler


(************************************************************************)
(* The "main" service just provides a link to the "foobar" service.
*)

let main_handler sp () () =
Lwt.return
(html
(head (title (pcdata "Main")) [])
(body [p [Eliom_predefmod.Xhtml.a foobar_service sp [pcdata "Click for foobar"] (2009, (3, 17))]]))

let main_service =
Eliom_predefmod.Xhtml.register_new_service
~path: [""]
~get_params: Eliom_parameters.unit
main_handler

Ocsigen by example, Part 3: delayed service registration


In the example from the previous article, the various services are registered with Eliom upon declaration. Note that we used the function Eliom_predefmod.Xhtml.register_new_service for this purpose. It is however also possible to separate these two actions, by first just declaring a service, and registering it later. You may use function Eliom_services.new_service for the former action, and function Eliom_predefmod.Xhtml.register for the latter.

Why is the separation between the declaration and registration actions useful? The most obvious application lies in services that call each other. Without this feature, you would most likely would need to resort to a "let rec ... and ..." construct, which isn't always the most practical.

The code below depicts two services, "coucou" and "foobar", which call each other. Note that we begin by just declaring each service and that we only register them in the end.

(************************************************************************)
(* Example for delayed registration. *)
(************************************************************************)

open XHTML.M
open Eliom_parameters


(************************************************************************)
(* We begin by declaring services "coucou" and "foobar". The first
takes no parameters, while the second takes a float as a GET
parameter.
*)

let coucou_service =
Eliom_services.new_service
~path: ["coucou"]
~get_params: Eliom_parameters.unit
()

let foobar_service =
Eliom_services.new_service
~path: ["foobar"]
~get_params: (Eliom_parameters.float "x")
()


(************************************************************************)
(* We now build the handler functions for each service. Note how
each handler creates a link to the other service.
*)

let coucou_handler sp () () =
Lwt.return
(html
(head (title (pcdata "Coucou")) [])
(body [p
[
pcdata "Here's a ";
Eliom_predefmod.Xhtml.a foobar_service sp [pcdata "link"] 3.1416;
pcdata " to service foobar";
]]))


let foobar_handler sp x () =
Lwt.return
(html
(head (title (pcdata "Foobar")) [])
(body [p
[
pcdata ("The parameter X is " ^ (string_of_float x));
br ();
pcdata "Here's a ";
Eliom_predefmod.Xhtml.a coucou_service sp [pcdata "link"] ();
pcdata " to service coucou";
]]))



(************************************************************************)
(* Finally we register the declared services and assign to each
one its handler function.
*)

let () =
Eliom_predefmod.Xhtml.register coucou_service coucou_handler;
Eliom_predefmod.Xhtml.register foobar_service foobar_handler

Postscriptum: If you're on the bleeding edge, you may have noted that the ocsigen.conf file I presented in the first chapter of this series needs a tweak in order to work with latest development version of Ocsigen (soon to be version 1.2). The change is minimal: basically, the "hostname" attribute for the host configuration is now called "defaulthostname". Here's the revised file:

<ocsigen>
<server>
<port>8080</port>
<charset>utf-8</charset>
<mimefile>/etc/mime.types</mimefile>
<debugmode/>
<findlib path="/home/dario/.local/lib/ocsigen/METAS"/>
<findlib path="."/>

<extension findlib-package="ocsigen_ext.ocsipersist-sqlite"/>
<extension findlib-package="ocsigen_ext.eliom"/>
<extension findlib-package="ocsigen_ext.staticmod"/>

<host defaulthostname="localhost">
<site dir="">
<eliom findlib-package="module"/>
<static dir="./"/>
</site>
</host>
</server>
</ocsigen>

Ocsigen by example, Part 2: hello world


The second instalment of this series presents the first actual Eliom code sample. You can use the Makefile shown in the first part to compile it, and the META.module and ocsigen.conf files for starting the Ocsigen web server.

This example contains three different services: first, the hello-worldish service "coucou" (so named as a homage of sorts to the convention used in the Eliom tutorial); second, the "foobar" service, which illustrates the use of GET parameters; and third, the "main" service, which makes use of Eliom_predefmod.Xhtml.a to create type safe hyperlinks to the first two services. I suggest you fiddle with the types of the GET parameters — you'll see that Eliom makes good use of the type safety of the Ocaml language by making it impossible to create hyperlinks that pass the wrong type to a service.

(************************************************************************)
(* Simple "Hello World!" Eliom examples. *)
(************************************************************************)

open XHTML.M
open Eliom_parameters


(************************************************************************)
(* The "coucou" service takes no arguments, and just displays a
welcome message with the client's IP address. The IP can be
obtained via the "sp" (server parameters) parameter that is
passed to every handler.
*)

let coucou_handler sp () () =
let greeting = "Hello " ^ (Eliom_sessions.get_remote_ip sp) ^ "!"
in Lwt.return
(html
(head (title (pcdata "Coucou")) [])
(body [p [pcdata greeting]]))

let coucou_service =
Eliom_predefmod.Xhtml.register_new_service
~path: ["coucou"]
~get_params: Eliom_parameters.unit
coucou_handler


(************************************************************************)
(* The "foobar" service takes two GET parameters, an integer "i"
and a string "s". Note that the handler is declared as an
anonymous function instead of as a separate function like we
did with "coucou". Though sometimes useful, this practice can
lead to confusing code; for this reason, this is the only time
we'll use it in this tutorial series.
*)

let foobar_service =
Eliom_predefmod.Xhtml.register_new_service
~path: ["foobar"]
~get_params: (Eliom_parameters.int "i" ** Eliom_parameters.string "s")
(fun _ (i, s) () ->
Lwt.return
(html
(head (title (pcdata "Foobar")) [])
(body [p [pcdata ("The GET parameters are: " ^ (string_of_int i) ^ " and " ^ s)]])))


(************************************************************************)
(* The "main" service just provides links to both the "coucou" and
"foobar" services. Try changing the types of the parameters to
see that the compiler catches any typing inconstencies.
*)

let main_handler sp () () =
Lwt.return
(html
(head (title (pcdata "Main")) [])
(body [
p [
pcdata "Here's a ";
Eliom_predefmod.Xhtml.a coucou_service sp [pcdata "link"] ();
pcdata " to the coucou service"
];
p [
pcdata "And here's a ";
Eliom_predefmod.Xhtml.a foobar_service sp [pcdata "link"] (10, "hello");
pcdata " to the foobar service"
]
]))

let main_service =
Eliom_predefmod.Xhtml.register_new_service
~path: [""]
~get_params: Eliom_parameters.unit
main_handler

Ocsigen by example, Part 1: basic setup


This article is the first of a series I'll be doing on Ocsigen programming. Ocsigen is both a web server and the umbrella name for an Ocaml-based framework that brings the power and safety of functional programming to the world of web development. Strictly speaking, this tutorial is about Eliom, the actual programming framework part of Ocsigen. However, because the two are closely related, and because the name "Ocsigen" has much better recognition, I've used it as a title.

Note that the Ocsigen site already offers a very comprehensive tutorial on Eliom. This series of articles is not intended to compete with it. In fact, I won't be doing any tutoring at all and I'll assume that readers are familiar with the existing tutorial. The goal of this series is simply to present self-contained and documented code samples illustrating various aspects of Eliom programming. These are taken from my own self-study experiments with Eliom, and I'm only sharing them with the hope they might be useful to others.

Let's start with the development setup. All the examples in this series can be compiled with the same Makefile and invoked with the same ocsigen.conf configuration file for the server and META file with findlib information. For the sake of simplicity, you can put all of these files in the same directory and just run the Ocsigen web server from that directory in debug mode by invoking "ocsigen -v -c ocsigen.conf" for the byte-code version or "ocsigen.opt -v -c ocsigen.conf" for the native-code version (if you're running Ocaml >= 3.11). The Makefile is as follows:

NAME=module

all: $(NAME).cma $(NAME).cmxs

%.cma: %.cmo
ocamlc -a -o $@ $+

%.cmxa: %.cmx
ocamlopt -a -o $@ $+

%.cmxs: %.cmxa
ocamlopt -shared -linkall -I `pwd` -o $@ $<

%.cmo: %.ml
ocamlfind ocamlc -thread -package lwt,ocsigen -c $<

%.cmx: %.ml
ocamlfind ocamlopt -thread -package lwt,ocsigen -c $<

clean:
rm -f $(NAME).cm[ioax] $(NAME).cmx[as] $(NAME).[oa]

As for the ocsigen.conf file, it can be defined like the code below (just change the findlib path according to your installation). Note the we're using port 8080 so the server can be started by any user:

<ocsigen>
<server>
<port>8080</port>
<charset>utf-8</charset>
<mimefile>/etc/mime.types</mimefile>
<debugmode/>
<findlib path="/home/dario/.local/lib/ocsigen/METAS"/>
<findlib path="."/>

<extension findlib-package="ocsigen_ext.ocsipersist-sqlite"/>
<extension findlib-package="ocsigen_ext.eliom"/>
<extension findlib-package="ocsigen_ext.staticmod"/>

<host hostname="dual">
<site dir="">
<eliom findlib-package="module"/>
<static dir="./"/>
</site>
</host>
</server>
</ocsigen>

Finally, note that because we rely on findlib for the installation of the module containing the actual code for the web site, we must provide a META file indicating the dependencies and the names of the compiled code units. As per the ocsigen.conf declaration, the name of this file must be META.module:

directory = "."
requires = ""
archive(plugin,byte) = "module.cma"
archive(plugin,native) = "module.cmxs"

And that's it as far as the development setup is concerned. The next article will present the first real example. Stay tuned!

Moglen on the origins of copyright and patents


I mentioned Eben Moglen before on this blog. If you are still not familiar with any of his writings, I strongly suggest you listen to this episode of the Software Freedom Law Show podcast. It features a recording of one of Eben's recent talks on the origins of copyright and patents. It is well worth it, I promise.

A moment of Zen


I recommend a moment of Zen before breakfast. Here's one for the holidays:

Consider the set S of all possible files of length n. A file compressor (such as Gzip, 7-Zip, and many others) is a programme that given any randomly chosen file from S, returns a new file whose size is on average greater than or equal to n.

Meditate on the statement above until you realise its truth. Then, grasshopper, you shall be enlightened.

Note: The "equal to" part is necessary because there is an entire family of compressors (the identity compressor being the most obvious one) that always return a file the same size as the one provided as input.