Moodle 2 export participants with group information

A small script to export moodle 2 participants with their group information.

Drag the bookmarklet to your bookmarkbar: Moodle Group Export
You can then click it when you are on the moodle 2 > Users > Enrolled users page to get a csv file of the displayed table.


  • Support for a maximum of 1 group by participant
  • Pop-up has to be enabled

Source Code

var script = document.createElement('script');
script.onload = function(){
var separator = ',';
var pattern = /id=(.*)&/;
var csv = [['userid', 'name','idnumber','email','group'].join(separator)];
$('table.userenrolment').find('tr').each(function(index, tr){
    var r = [];
    var $tr = $(tr);
    var a = $tr.find('a');
    var userid = pattern.exec(a[0])[1];
csv = csv.join("\r\n");"data:application/octet-stream;charset=utf-8," + encodeURIComponent(csv));
script.src = '';

Bonita Studio tutoriel vidéo

Durant le cours d’Intégration des systèmes d’information d’entreprise 2011 du Master en Système d’information de HEC Lausanne, j’ai enregistré une série de vidéos démontrant l’utilisation de Bonita Studio sur un cas pratique “Travel Expenses“.

Les vidéos sont disponibles sur YouTube ( et couvres les thèmes suivants :

  • User Experience
  • sous-processus
  • Données & Données complexe
  • Formulaires
  • Messages
  • connecteur REST groovy
  • connecteur mail
  • connecteur MySQL

Le cas Travel Expenses traite la demande, la consolidation et la vérification de notes de frais pour des voyages de collaborateurs.

  • Enoncé détaillé du cas (Exercice de modélisation BPMN) TravelExpensesEnonce.pdf
  • Enoncé du travail pratique (Exercice Bonita) TravelExpensesBonita.pdf
  • Solultion exemple sous Bonita Studio (Fichiers bar)
  • La solution propose:
    • un processus principal TravelManagement ,
    • qui interagit avec un processus TravelBooking ,
    • et qui a également un sous processus ReportExpenses

Ressources supplémentaires

Pour permettre l’échange des données entres processus avec une seule variable, plusieurs objets complexe ont été créés: TravelPlan contient un Hotel et une liste d’Expense. De plus ces objets ont une méthode toHtml et toString pour faciliter l’affichage dans un formulaire Bonita.

JAR: travel_plan_1.1.jar
GrovoyDoc: travelplan/groovydoc/

Groovy Date
formatage de l’objet Date groovy pour le service REST ou la requète SQL

new Date().format('MM/dd/yyyy')
new Date().format('yyyy-MM-dd')

Expedia REST service
Documentation du service REST utilisé:

Dr. Thibault Estier (Enseignant du cours)
Boris Fritscher (Assistant doctorant, préparation du cas et enregistrement des vidéos)
Alexandre Métrailler (Assistant doctorant, préparation du cas)

Android Conference Application for ECIS2011 and CAiSE’11

Since I did not find any official conference application for either ECIS2011 or CAiSE’11, I decided to make my own version. Thanks to Google’s open source I/O application this was not so hard and the result can be tested here:

ECIS2011 on Android Marketinformation page

CAiSE’11 on Android Marketinformation page

Nice Videos From Recent Talks

A small selection from videos of recent good talks.

JavaScript: The Language
Nice advanced introduction to JavaScript and the new features of ECMAScript5

more all MIX 11 sessions

CHI 2011
Bill Buxton Shows Us His Favorite Tech
Why we need to remember past gadgets!

Google IO 2011
Java Puzzlers – Scraping the Bottom of the Barrel
The one and only java puzzlers, always informative.

Programming Well with Others: Social Skills for Geeks
Insights on geek vs/and management. You might also be interested in the book “Being Geek

HTML5 Showcase for Web Developers: The Wow and the How
Fun stuff with some chrome specific audio and file api, but also standard CSS3 3D animations.

more All Google IO 11 Sessions

ARDrone SDK 1.6 working windows client binary

Since there does not seem to be an official binary of the windows client sample for controlling the ARDrone. I decided to compile the sample project, which is available in the official sdk. Sadly the process of compiling the sample is not straight forward and requires a lot of tweaking [1, 2]. Nonetheless, I finally managed to compile a version, which is working on windows 7 x64 and is compatible with firmware update 1.5.1 of the ARDrone. It can be downloaded here:

ARDrone1.6Win32Client.exe working binary of ARDrone SDK 1.6 win32 client

You will also need to have an update to date version of the DirectX End-User Runtime [3].


Connect Galaxy Tab With ARDrone’s Ad hoc Network

In order to use any of the available ARDrone application for Android, the Samsung Galaxy Tab has to be connected to the ARDrone. Unfortunately, this is done via ad hoc network, a functionality not activated on the Galaxy Tab [1].

As with any problems there are different solutions, one of them is to ROOT the device and replace the WiFi functionality with a patched version.


I) Root the Samsung Galaxy Tab [2] (tested with SuperOneClick v1.9.1)

– Kies Software downloaded from HERE and installed and Tab connected at least once to the pc.
– SuperOnceClick downloaded from HERE

1) Connect your galaxy tab with debugging mode disabled and sync with Kies at least once.
2) Disconnect it and enable debugging mode from Settings>Applications>Development>USB Debugging
3) Connect the tab again to PC and click on home button so that Tab comes out of Kies connection
4) Launch SuperOneClick.exe, on Vista/Seven be sure to run as Administrator (right click run as…)
5) Click on root and wait for 5-10 Mins
6) Reboot when/if told to

II) Copy patched file onto device and overwrite [3]

1) Download wpa_supplicant HERE (use 7-zip to extract) or HERE (zip not tested)
2) upload file onto your device with adb push or connected as an USB drive
3) disable WiFi on the device
4) mount /system as read write ( there is also an app for that mount /system rw )
5) replace /system/wpa_supplicant (if your favorite explorer does not work, try a terminal)
5b1) > su
5b2) > cp /sdcard/wpa_supplicant /system/bin/wpa_supplicant
6) enable WiFi (you can now see and connect to Ad hoc networks!)

On a first test run all applications seem to be able to connect to the ARDrone with firmware 1.5.1: ARDrone Demo, ARDroid, Androne Freeflight.AR (slow video)


Chris Anderson Speaks About Free

If the freemium or other free business model pattern interest you, check out this interview of Chris Anderson about his upcoming book.

The freemium pattern can also be modelled on the business model canvas

checkout for more.

Browsing iTunesU without intalling iTunes

Updated version of the script

On some pages the location-bar information is available (third-level pages), but 1st and 2nd level pages do not have a location-bar. Even in iTunes it has been removed in favor of a location-bar managed by iTunes. I suppose this is done in order to make use of a cached version of the page and speed up loading. Having no location-bar at 2nd level pages is an awkward design choice from Apple. Therefore location-bar has to be managed by the script and 3th level pages need also to be re-adapted to be displayed correctly.

Fixed version can be tested here:[itunesU url]

the new source files are available here:
complete source code at github

index_fixed.groovy – new version with navigation fixed
proxy.groovy – proxy class because iTunes checks user-agent to link to some video files behind a redirect.

The problem

More and more universities publish courses as podcasts on iTunesU and neglect to give a direct access to their content. This hinders sharing of knowledge, because of the obligatory Apple’s iTunes application needed to access iTunesU.

The solution

Emulating the iTunes client: the script can be tested at[itunesU url]

It only needs the url which would open in iTunes and converts it to a displayable webpage.

For example for

Source download

index.groovy version 1 iTunesU xml to html groovy script

Why groovy?

Having experience with Java and Grails development using Groovy especially due to its powerful closures, xml navigation and html building was a obvious choice. Also this project started as a Google AppEngine prototype, but hit the no-user-agent change limitation.


Of the three types of layout used in iTunes U only the two column standard university page view and detailed course view (track list) are supported. The iTunes main site listing and main page three column layout is not supported.

Solution explained

iTunes uses a custom xml page to receive and render its content. This file can be access when switching the user-agent to “iTunes”.
Switching user agent is easy under Firefox with the user-agent switcher add-on
Part of the xml file

<FontStyleSet setName="basic22" normalStyle="helvetica22"
	linkStyle="link" linkPressedStyle="linkPressed" linkRolloverStyle="linkRollover" />
<FontStyleSet setName="normal40" normalStyle="lucida40"
	linkStyle="link" linkPressedStyle="linkPressed" linkRolloverStyle="linkRollover" />
<FontStyleSet setName="normal40Bold" normalStyle="lucida40Bold"
	linkStyle="link" linkPressedStyle="linkPressed" linkRolloverStyle="linkRollover" />
<MatrixView rightInset="0" bottomInset="0" leftInset="0"
	topInset="0" rowFormat="100%,*" viewName="Form">
	<View rightInset="0" bottomInset="0" leftInset="0" topInset="0"
		minWidth="948" minHeight="400">
			<!-- Layer 1 = Banner Image -->
			<!-- BEGIN ReplaceableImageXMLView -->
			<View alt="" height="400" width="600">
				<PictureView proportional="1" verticalAlignment="top"
					shouldBeVisible="true" shadowHeight="0"
					alt="MIT offers a selection of video and audio from several of our groundbreaking projects: MIT OpenCourseWare, MIT World, MIT TechTV, and Visualizing Cultures."
					shadowWidth="0" height="400" width="600"
					addShadowSizes="false" />
			<!-- END ReplaceableImageXMLView -->
			<!-- Layer 2 = link box area -->
			<MatrixView leftInset="0" rightInset="0" topInset="25"
					This ensures we leave enough room for the banner image in the 3
					column view
				<View minHeight="400" />
				<View />
				<VBoxView rightInset="25" bottomInset="0" leftInset="0"
						<VBoxView leftInset="0" rightInset="0" topInset="0"
							<!-- BEGIN description box-->
							<!-- END description box-->
							<!-- START ListBoxStack -->
								<FontStyle name="outlineTitleFontStyle" color="ffffff" />
								<FontStyle name="outlineTextFontStyle" color="ffffff" />
								<!-- BEGIN RoundedBox -->
								<View rightInset="0" bottomInset="0" leftInset="0"
									<Test value="7.0.0" comparison="greater or equal"
										property="iTunes version">
										<!-- BEGIN MaskedView -->
										<View rightInset="0" bottomInset="0" leftInset="0"
											<PictureButtonView rightInset="0" topInset="0"
												bottomInset="0" leftInset="0" alt="" color="rgba(0,0,0,0.75)"
												cap="4" />


The xml file is quite verbose and it takes some time to identify the interesting content.
The hard part of this project was to identify the right way to identify and select the wanted data from the xml tree.

Following are code snippets of the source file with their most important or interesting aspects explained.

First task of the script is to retrieve the xml page by settings the right user-agent [3] and then use the powerful groovy xml parser api [13] to have an easily navigable xml object.

def xml
def conn = new URL(handle).openConnection()
conn.setRequestProperty ( "User-Agent", "iTunes/8.1" )
def putBackTogether = new StringBuffer()
def r = new InputStreamReader ( conn.getInputStream(), "UTF-8" )
char [  ]  cb = new char [ 2048 ]
int amtRead = ( cb )
while  ( amtRead  >  0 )   {
	putBackTogether.append ( cb, 0, amtRead )
	amtRead = ( cb )
xml = putBackTogether.toString()
xml = new XmlSlurper().parseText(xml)

To work around default namespace bugs when recreating a xml string from an xml object the Markupbuilder has to be set to the apple namespace[6].

import groovy.xml.StreamingMarkupBuilder
def getXml(item){
	def outputBuilder = new StreamingMarkupBuilder()
	outputBuilder.encoding = "UTF-8"
	String result = outputBuilder.bind{
		mkp.yield item

Example of the powerful way to generate html code with the groovy MarkupBuilder.

import groovy.xml.StreamingMarkupBuilder
html.html(xmlns:"",lang:"en",'xml:lang':"en") {
	head {
		title xml.Path.PathElement.collect{it.'@displayName'}.join(" > ")
		meta('http-equiv':"X-UA-Compatible", content:"IE=8")
		meta('http-equiv':"content-type",content:"application/xhtml+xml; charset=UTF-8")

Identifying the type of layout the xml file is meant to build is done by looking at a reflection attribute from the first image found in the file.

def topimg = xml.'**'.find{ == "PictureView"}
def reflect = topimg?.'@reflection'==1 //true = course page

Getting page colors from FontStyle tags

def titleFontStyle = xml.'**'.find{ == "FontStyle" && it.'@name' == "normalTitleFontStyle"}?.'@color'
if(titleFontStyle == null){
	titleFontStyle = xml.'**'.find{ == "FontStyle" && it.'@name' == "outlineTitleFontStyle"}?.'@color'

Some more examples of the groovy MarkupBuilder: especially interesting is the mkp.yieldUnescaped [10] method to allow usage of html otherwise automatically converted symbols like &.

body(style:"background: #${xml.'*'.find{ it.'@backColor' != ''}.'@backColor'}"){
		div(class:"span-24 last nav"){
			def list = xml.Path.PathElement
			def last = list.size()-1
			list.eachWithIndex{ pe,i ->
				if(i == 0){
							mkp.yieldUnescaped "&nbsp;"
					a(class:"${i == last ? 'last' : ''}",href:"index.groovy?handle=${pe.text().trim()}", pe.'@displayName')

Being able to identify the right element is sometimes a bit tricky, especially that not all pages seem to follow the same structure rules.

	xml.ScrollView.View.MatrixView.View?.'**'.find{it?.name()== "VBoxView" && it?.parent()?.name()== "VBoxView" && it?.parent()?.parent()?.name()== "VBoxView" && it?.parent()?.parent()?.parent()?.name()== "VBoxView"}?.'*'.findAll{ it?.name() == "TextView"}.each{ text -> p text }
	mkp.yieldUnescaped "&nbsp;"

Usage of the xmlwise library[15] to parse the standard plist part of the xml containing the track list .

import xmlwise.*
div(class:"span-24 last tracklist"){
	table(cellspacing:"1", class:"tablesorter"){
				th ""
				th "Name"
				th "Time"
				th "Artist"
				th "Release Date"
				th ""
			def plist = Plist.fromXml(getXml(xml.TrackList.plist))
			plist.items.eachWithIndex{ track, i ->
				int seconds = (track["duration"] /1000)
				int minutes = seconds % 3600
				int hours = (seconds - minutes) / 3600
				seconds = minutes % 60
				minutes = (minutes - seconds) / 60
				tr(class:i % 2 == 0 ? "even" : "odd"){
					td track["rank"]
					td track["songName"]
					td ((hours > 0 ? String.format("%02d",hours)  + ":" : "")+ String.format("%02d",minutes) + ":" + String.format("%02d",seconds))
					td track["artistName"]
					td track["releaseDate"][0..9]
						a(href:track["previewURL"],rel:"lightbox[set 480 380]",title:track["songName"], "view")
						a(href:track["previewURL"],title:track["songName"], "download")

Resources used for html design

Google Chrome ADBlock without proxy

I found a new way to use the Google Chrome browser without having to install or use a proxy.

The solution is called

Since I use the developer preview channel, I installed adsweep as an extension/plugin.

Quick steps for Chrome-dev with adsweep extension:

  1. Switch chrome to dev channel with the Google Chrome Channel Changer (more info)
  2. Download AdSweep extension AdSweep.crx
  3. Install extension by running chrome from command-line with:
  4. chrome.exe –install-extension=AdSweep.crx

    Chrome is installed by default in your application data profile: for Vista users:

  5. Enable extensions by adding:
    to your Google Chrome Shortcut
  6. Verify that the extension/addon loaded correctly by navigating to chrome-ui://extensions/

Happy browsing, without Ads and proxy!