Archive for May, 2008

Journées du Libre – Bruxelles – 6 & 7 juin 2008

Les premières Journées du Libre seront organisées à Bruxelles ces 6 et 7 juin prochains. Il s’agit d’un évènement à entrée libre dont le but est de présenter le monde du libre à un public varié. BeezNest y sera pour présenter Dolibarr, FreeNAS, Dokeos et bien d’autres solutions Open-Source auxquelles nous contribuons ou sur lesquelles nous fournissons des services de consultance, installation et développement. N’hésitez pas à nous rendre visite si vous passez dans le coin!

Categories: Events, French

Flash Plugin for Linux 10 beta – Still no V4L2 support

May 30, 2008 1 comment
Update: Flash 10 Beta 2 reportedly supports V4L2!
See the link to the Flash Developer blog below for more info.

Following comments on various blogs, Flash 10 beta does apparently not support V4L2 either. I really wasn’t even thinking about any feature to add to my Flash plugin except that… well… looks like we’re going to have to wait for another year or so before we can use video capture with the Flash plugin under Linux.

There are various ways you can try and push Adobe into supporting V4L2 (which, I am told, is probably not *that* big a deal code-wise)

  • you can post a comment about this on the Flash Plugin for Linux developer blog (be kind and constructive)
  • you can fill in a bug report or a feature request on Adobe’s website
  • you can blog about it (making Flash problems known to everyone will avoid the wrong people being accused of developing software that doesn’t work under Linux

Let’s hope for some kind of easy-to-implement, free solution soon.

Categories: English, Tech Crunch

Updated Dokeos 1.8.5 page

I’ve updated the Dokeos 1.8.5 page to reflect the fact that we now have a Release Candidate and are very close to the stable release.

This is a time for us (developers) to take a deep breath and analyse things with the satisfaction of someone having done a nice job. Nevertheless, we are very careful not to miss anything, but as usual we count on your help to spot things that really are difficult to see.

We are already thinking about the developments for 1.8.6, which will be only a few and will concentrate (if everything goes as expected) on exercises – making it easier and more reliable to build exams using Dokeos – and web services – making it easier to connect Dokeos to other web systems.

Dokeos 1.8.5 RC1, possible last changes and the close future

We officially released 1.8.5 RC1 tonight, although we might alter the package just for two little microscopic changes tomorrow morning (one concerning SCORM export on Dokeos installs that use a subdirectory of the web server document root, and the other implementing a default hiding of the audiorecorder for the learning path building tool).

I think there’s not much to say, other than it’s a *great* unstable release. I find it amazing how much we can progress with a good team. Not in terms of features (there are new features, and they are all interesting), not even in terms of bug fixing (there are tons of bugfixes, I can’t even remember all of them), but in terms of general stability and structure. From Dokeos 1.6, which was pretty much close to a “toy” software (I might be overdoing it a little bit here ;-)), we got into something… really amazing. We have now a full professional e-learning suite that lets you use pretty much any kind of
media, with an incredibly easy-to-use interface, all in a package that can handle without a problem up to 175000 users. It’s just freaky…

We still know how to improve it even more, but now we’re focusing on testing for 1.8.5 stable (which we will probably release within the two next weeks), so feel free to help us get faster there…

Into 1.8.5, we’ve shipped an incredible amount of security improvements, warning and notice messages (that would otherwise make the logs much larger than necessary) and fixed tons of bugs.

So now the question is “Why do others do more sales?”. Well, a huge part of this answer is: marketing. We have to do a huge effort in marketing in the next few months if we want to be able to continue the Dokeos development (which is very expensive, as is all kind of software that you don’t sell in itself and which doesn’t bring much free help). You can have the best product ever, if nobody knows it, it will be totally forgotten sooner than you think.

So if you have leads, if you think your company might benefit from Dokeos and… – why do I want to say “…if no one else can help, and if you can find them…” ? – … at the same time help a great open-source platform to develop… well, don’t hesitate to contact me! It will be my pleasure to follow the lead.

Subversion and the incoherent linebreak problem

When trying to commit code into a subversion repository, and if the code you want to submit comes from third parties, you might occasionally run into the error “incoherent linebreak”.

This is due to people editing files from Windows, Linux and Mac, which all have different line break characters. Under Windows, it’s \r\n, under Mac it’s \r and finally under Linux it’s \n.

Depending on what system you are usually using to commit your code to SVN, you should replace all the others for yours. This is easily done by asking all external contributors to change their text editor settings to “Linux linebreaks” for example.

If the code you are trying to submit comes from a PHP generator (some translation interface), you can use the following code to do that:

$string = str_replace(array("\r\n","\r"),array("\n","\n"),$string);

If you are reviewing files with VIM, you should be able to do something like:

:% s/\r\n/\n/g
:% s/\r/\n/g

Then try to commit again. The incoherent linebreak error should have disappeared.

Categories: English, Tech Crunch

Adding repetitive events to a simple PHP agenda system


To prepare for RC1, I have to submit the latest database changes for this release. The objective of these changes is specifically to add the management of repeated events to a simple agenda system that doesn’t have them.

So, what’s the big deal? Well, there are two ways I was thinking repeated agenda events could be handled…

  1. create as many events as the repetition needs
  2. add repetition data to the original event to say “this is a repetitive event and it repeats this way…”

Let’s have a look at those two possible ways to do it

“Create many events” solution

The solution seems easy, after all. You just create a series of events and limit the final date to something not too far away, and there you go, you can continue using your system as usual.

There are two shortcomings to this system:

  1. In some cases, you will get *many* events which, if they contain a long description, can eat up your disk space fast (imagine you attach a 30K picture to the event and repeat it every week for the next 10 years, that’s 15MB of data for a simple illustrated event – and 30K is *not* much)
  2. How do you know which event was the first one? And so how do you keep a relationship between the “father” event and its offsprings? And so how do you delete the repeated event if you realise you made a mistake?

If point 2 can easily be avoided by adding a “parent” field to my table structure, and sticking it to each offspring, problem 1 isn’t easily solved.

“Add repetition expression to the original event” solution

If this solution removes the problem 1 from the previous idea, it introduces a few additional flaws:

  1. How do you tell, from a simple week view, if there is a repeated event today or not?
  2. How do you structure the information related to the “repetition” information?
  3. How do you remove one occurrence of the repetition (say one weekly event is cancelled because of the host being in hospital)?

None of these problems is solved easily…

Fortunately, there is a reference: WebCal! WebCal is *the* open-source software that deals with calendars and events of any kind, so it has to have a good solution for us, hasn’t it?

The WebCal solution

WebCal took the second idea but, probably after realising the three shortcomings, had a brilliant idea: store the repeated event’s information into a separate table.

This way of doing things, if implemented properly, ensures:

  1. It is easy to retrieve repeated events as it’s another table, with a much smaller amount of events (however, calculating daily events from repetition metadata might be resource-consuming)
  2. We can store the repetition information in the new table, with a proper way to structure this data (and to store it, retrieve it, update it)
  3. We can use *another* table again to store the exceptions to the repetition cycle
  4. There is no modification to the existing events table

In fact, one the of the most annoying elements of the second solution was that if a lot of events were recorded in the calendar, retrieval of repeated events would potentially highly suffer from other “noise” data.

Having them in a separate table will ensure we only get a few (after all, you can’t really repeat a lot more than 10 events per week, as it will fill your week already!) and our queries will be much faster to check if there is a repeated event today, or this week.

However, this will still use a lot of processing power when calculating when the events are repeated.

This is somehow helped by the fact that they restricted the types of repetition to a minimum of a day, with the following criterias:

daily, monthlyByDate, monthlyByDay, monthlyByDayR, weekly, yearly

Where monthlyByDayR means “monthly by day, restricted” to say that it can be only the second Monday of every month, for example.

We will not implement monthlyByDay nor MonthlyByDayR in this first implementation though, so for time reasons, we will only provide daily, monthlyByDate, weekly and yearly at first.

Implementing it inside Dokeos

So now we have the idea, let’s implement it inside Dokeos.

In Dokeos, we have a *very* simple calendar application. Basically, you add an event, it has a start time, an end time and a description. The table definition looks like this:

CREATE TABLE course_agenda (
id int unsigned NOT NULL auto_increment,
title varchar(200) NOT NULL,
content text,
start_date datetime NOT NULL default ‘0000-00-00 00:00:00’,
end_date datetime NOT NULL default ‘0000-00-00 00:00:00’,

We also happen to have a personal agenda, which is outside of the course context. The table for this one is defined as:

CREATE TABLE personal_agenda (
id int NOT NULL auto_increment,
user int unsigned,
title text,
`text` text,
`date` datetime default NULL,
enddate datetime default NULL,
course varchar(255),
UNIQUE KEY id (id)

(so we have a reference to the user id and the course id here, as well as an additional description text – this structure is very wrong – it wasn’t me, I swear! – and very MySQL-dependent because of the backticks to escape fields that use reserved keywords)

Anyway, so here the idea is that we will have to duplicate the new tables as well, because a personal agenda is global, while a course agenda is restricted to the context of a course.

However, any user can see a screen with the events from his personal agenda *and* the ones from all the courses he’s subscribed to. So even if we don’t have a lot of repeated events, it is still a considerable query we have to do to get them all.
So we have to add, on both sides, two tables with the something approaching the following structure (coming from the WebCalendar code):

CREATE TABLE webcal_entry_repeats (
cal_type VARCHAR(20),
cal_end INT,
cal_frequency INT DEFAULT 1,
cal_days CHAR(7),
PRIMARY KEY (cal_id)

CREATE TABLE webcal_entry_repeats_not (
cal_id INT NOT NULL,
cal_date INT NOT NULL,
PRIMARY KEY ( cal_id, cal_date )

Now we have the structure. How does the interface reflect those additional possibilities?

The insertion side

Well if we keep it simple, we will only have to provide a tickbox to say if this event is repeated or not, and a drop-down list with the three options we are offering: daily, monthlyByDate, weekly or yearly. Finally, an absolute end will have to be given, which we will ask the user to fill in.

This data will then go right to the new database table and, using the current event as a start date, will complete the insertion part of the new feature.

On the querying side though, things are going to be much more complex.

The querying side

Whenever a user goes on a calendar page, he needs to see the repeated events. If a daily view shouldn’t be too complex, a monthly view adds just a little bit to it: we have to check over a wider area.

Let’s start with a daily view. Let’s say we are querying for everything that is happening on the 21st of May. Let’s also say we are only looking at the personal agenda side.

The first thing we do is check for normal events. No worries there, we already do that.

Then, we want to check for repeated events. Because we have a separate table for these, we can easily check all the repeated events that:

  1. have a start date anterior, or equal to the 21st of May ($may21start = mktime(0,0,0,5,21,date(‘Y’));)
  2. have an end date posterior, or equal to the 21st of May ($may21end = mktime(0,0,0,5,21,date(‘Y’))-1;)

Once we have those (let’s say we have only one), we start with the tricky part: calculating whether the repetition occurs today or not. We will use PHP dates massively here to provide an effective date calculation.

As previously mentioned, we have only four types of repetition here, so we can find a formula for each of these types (forgetting for now about exceptions), and create a function for each:


Well, it will happen today considering the conditions above are met, that’s for sure, so consider it part of today’s view. You will still have to calculate the starting and ending time of this new event though. That would look as something like this:

$time_orig_h = date('H',$orig_start);
$time_orig_m = date('i',$orig_start);
$time_orig_s = date('s',$orig_start);
$int_time = (($time_orig_h*60)+$time_orig_m)*60+$time_orig_s; //time in seconds since 00:00:00
$span = $orig_end - $orig_start; //total seconds between start and stop of original event
$current_start =$start + $int_time; //unixtimestamp start of today's event
$current_stop = $start+$int_time+$span; //unixtimestamp stop of today's event


$time_orig = date('Y/n/W/j/N/G/i/s',$event_start_time);
list($y_orig,$m_orig,$w_orig,$d_orig,$dw_orig,$h_orig,$n_orig,$s_orig) = split('/',$time_orig);
$time_now = date('Y/n/W/j/N/G/i/s',time());
list($y_now,$m_now,$w_now,$d_now,$dw_now,$h_now,$n_now,$s_now) = split('/',$time_now);
if((($y_now>$y_orig) OR (($y_now == $y_orig) && ($w_now>$w_orig))) && ($dw_orig == $dw_now))
  $time_orig_end = date('Y/n/W/j/N/G/i/s',$event_end_time);
  list($y_orig_e,$m_orig_e,$w_orig_e,$d_orig_e,$dw_orig_e,$h_orig_e,$n_orig_e,$s_orig_e) = split('/',$time_orig_end);


$time_orig = date('Y/n/j/G/i/s',$event_start_time);
list($y_orig,$m_orig,$d_orig,$h_orig,$n_orig,$s_orig) = split('/',$time_orig);
$time_now = date('Y/n/j/G/i/s',time());
list($y_now,$m_now,$d_now,$h_now,$n_now,$s_now) = split('/',$time_now);
if((($y_now>$y_orig) OR (($y_now == $y_orig) && ($m_now>$m_orig))) && ($d_orig == $d_now))
  $time_orig_end = date('Y/n/j/G/i/s',$event_end_time);
  list($y_orig_e,$m_orig_e,$d_orig_e,$h_orig_e,$n_orig_e,$s_orig_e) = split('/',$time_orig_end);


$time_orig = date('Y/n/j/z/G/i/s',$event_start_time);
list($y_orig,$m_orig,$d_orig,$dy_orig,$h_orig,$n_orig,$s_orig) = split('/',$time_orig);
$time_now = date('Y/n/j/z/G/i/s',time());
list($y_now,$m_now,$d_now,$dy_now,$h_now,$n_now,$s_now) = split('/',$time_now);
if((($y_now>$y_orig) OR (($y_now == $y_orig) && ($m_now>$m_orig))) && ($dy_orig == $dy_now))
  $time_orig_end = date('Y/n/j/G/i/s',$event_end_time);
  list($y_orig_e,$m_orig_e,$d_orig_e,$dy_orig_e,$h_orig_e,$n_orig_e,$s_orig_e) = split('/',$time_orig_end);

For a one-day view, we will use the four formulas as switches inside a checker function, repeat_check_today(), that will either get the event start time and end time or input them directly into some kind of session array, or even print them to screen.

That’s about the same idea for week and month views, so I won’t describe them right now. I didn’t dive into the Dokeos code much, sorry about that.

Yes, OK, but hold on just a second…

I don’t know what you think about all this, but I thought it was a mind-buggingly complicated set of algorithms (and they are even simpified in this example), so I spend a few *hours* trying to make everything perfect, and then I tried it… awfully slow.

And after one more hour of thinking, I finally got back to the first solution. Well, not completely. I mixed the first, the second and the third, so what I have now is this final solution (that works, that is fast and easy to implement).

The chosen solution: a little bit of everything

In short, I add a “parent_event_id” field to the initial agenda table, so I can create any number of events that *depend* on a first parent.

Then I keep my additional tables repeat and repeat_not, to be able to store the corresponding expression that explains how the repetition works, and when there is an exception.

When inserting, I just offer the possibility to repeat the event at a certain frequency until an end date. This triggers the insertion of one parent event (nothing special, nothing in the parent_event_id field), and then I parse the frequency and

  1. record the repetition expression in the “agenda_repeat” table
  2. create as many repeated events as asked for in “agenda”, each of them having a parent_event_id of the parent event

When querying

This means that there is very little to change to the way my application works in order to use those repeated events: they are just displayed as normal events.

If you want to make it possible to get to the parent event, you can check if the parent_event_id is not null, and then display a link to the parent event.

When editing, you actually never offer the possibility to “edit” an event “repetition-wise”, because it would be very difficult to handle. If the user has made a mistake, he can just delete the parent event and all other events will be deleted, and then he can create another one that fixes the previous problem.

If you want to edit one of the child events, you can, it is just a copy related to the parent, but then you can mention specific information about one day’s event.

When deleting, I have left it very limited so far, so you cannot delete one single child event (I am not yet handling repetition exception). You have to mention something in the event’s description to say it’s been cancelled on that specific day (this exception isn’t preserved in iCal exports though).

If you delete the parent event, all children will be deleted as well, whether they have been changed or not.


Although the second solution seemed clean enough, it added a lot of problems of integration with the agenda already there in Dokeos 1.8 (which is quite bad in itself, I must admit).

It also prevents the alteration of any of the event’s repetition, but considering the fact that it is a repeated event and that it has to offer export features (to iCal, for example), there must be a way to express clearly how it is repeated, so we definitely need to have that information. Clicking on one repeated item has to show the details of the original item with an updated time information, and cannot allow for edition (otherwise it’s not clear what we are editing).

There is definitely still room for improvement in the interface provided to the user, but I am quite convinced that structure put in place allow for *any* kind of change now.

If you wanna try out Dokeos 1.8.5 (in beta version at time of writing), head to

Preparing Dokeos 1.8.5 RC1

Next week, we will be releasing an RC1 for Dokeos 1.8.5. The main targets for this version are:

  • fixing SCORM (import, export and reporting)
  • fixing audio recorder and some videoconference minor bugs
  • improving the templating system
  • adding repetitive events to the agenda (and iCal import, as well)

I’m quite annoyed because I will have to update the database structure to allow for repetitive events, but we’re still before RC1 so it is still an “acceptable” change, and apparently it’s been said it would be in 1.8.5, so…

Eclipse 3.2 crashing with Subclipse on Ubuntu 8.04

2008-08-02 update

Although the post is in Spanish, one of my colleagues (and consequently I also did) installed Eclipse Ganymede manually on his Ubuntu 8.04 and it works beautifully (although it uses even more memory). Check out the article.

Original post:

I know, I should report all this properly in the Eclipse bug-tracking utility, but the truth is I don’t know how to explain it. Since I’ve been using Eclipse (about 2 years ago), I get into a systematic crash loop about every 4 months. I have to wait for that long to get some kind of weird behaviour where Eclipse will crash every single time when trying to update a file.

I’ve started to narrow it down… Obviously, it is due to Java 6 and Java 7. I’ve tried running Eclipse (3.2) with GCJ and that works without crashing, but the speed is incredibly slow (takes about 30 seconds to show 80 characters of a line after I’ve input them on my keyboard).

So, based on that, I would say it’s due to Java 6 or 7.

I haven’t been able to narrow it down to a specific use of one plugin though, so I don’t know exactly how good or bad the PHPEclipse plugin is for my system overall, but in any case it doesn’t help.

Now this is a little procedure I’m writing for myself, for 4 months from now, to try and make it easier to re-install completely Eclipse, as it really seems that this is the only way to fix it.

$ apt-get remove eclipse eclipse-platform eclipse-source eclipse-rcp eclipse-pde eclipse-jdt

$ dpkg –purge eclipse eclipse-platform

$ sudo rm -rf /usr/lib/eclipse

$ sudo rm -rf /var/www/.metadata (this is my workspace)

$ sudo rm -rf ~/.eclipse

$ sudo apt-get install eclipse

Then, of course, I have to reinstall all my plugins (subclipse, phpeclipse, epic-perl, xmlbuddy) from inside Eclipse



EPIC Perl:

Every project then needs to be re-built inside Eclipse.

Note that the PHPEclipse in nightly release ( will not work, most of the time. Don’t try, you’ll loose time. The install works and then as soon as you try opening a PHP file it breaks on a “Null pointer exception” error (with the version of Eclipse available in Ubuntu 8.04, that is).

By the way, the most efficient Java runtime environment (JRE) for Eclipse so far is java-6-sun on Ubuntu 8.04, so don’t try to use it with gcj, it’s just incredibly slower. To make it use java-6-sun, make sure that your /etc/eclipse/java_home file contains the line


first, uncommented and before any other JRE line.

Obivously though, after my latest experiment, this does not work. As soon as a file is updated, the Subclipse plugin draws the complete Eclipse IDE down. Removing the Subclipse plugin (1.2.x) fixes the problem. I’m still working on finding the details…

Removing and re-installing the Subclipse plugin can be done (if you have installed it with a user-centered install) by removing all subclipse directories from ~/.eclipse/ and then restarting Eclipse and re-installing it. For some reason, if you don’t clean the directories first, Eclipse won’t let you select the package from the packages list. However, after many attempts, I have successfully identified the bugging factor, and it is the Subclipse plugin. Since I have stopped using it, I have no more problems.


If you are experiencing problems with Eclipse 3.2 on Ubuntu with heavy Subversion usage, I recommend you first try to remove subclipse (you can do that by removing all subclipse directories in ~/.eclipse) and then see if your problem still appears.

I am a bit too busy at the moment to file a complete bug report, but if someone wants to tell me how to do that and who to send it to, I can probably spare a few minutes crashing my Eclipse again.

Categories: Development, English

UTF-8 and resistance to change

Wouldn’t you know… While we (european people at least) are trying to make more and more open-source product use UTF-8 by default, so that we can (finally) share the same encoding with people that use character sets so different from us (mostly Middle to Far-East), resistance to change seems to be an important problem in Japan as well (as everywhere else).

On the php-i18n mailing list (see post here), Dietrich Bollmann took the hassle of posting a list of comments he gets from time to time regarding the implementation of UTF-8 inside websites and e-mails, from web developers and web authors. Let’s give him some space for a large quote and then I’ll give you a few personal views about all this (note that “cellars” actually mean “cellulars/mobile phones”):

Here a list with some of the answers I got (as I got them):

- Most cellars don't work with UTF-8.

...this is the one most important answer I got as lots of
people in Japan use the time they spend in the subway to
read and write their email with their cellar.

Only some cellars work with UTF-8 , most don't. And I often
was told by friends that my email program (I normally use UTF-8 )
"doesn't work correctly" : )  More often I just didn't get any
answer at all...

Based on this experience it is just natural that people don't
switch to UTF-8.  And even if more and more of the newer programs
also work with UTF-8 , probably it will still take a while until
this "tradition" in the Japanese software developer community
will change.

continuing with the answers:

1. I don't like UTF-8.  It is too new, everybody is used to JIS and
  when using UTF-8 there are always lots of problems.
  With JIS things work well out of the box.

2. The file size becomes bigger as there are so many different Characters
  which have to be encoded and Japanese characters are encoded with
  three bytes in UTF-8.

3. There are too many different versions of UTF-8 which create problems.
  There is only one version of JIS which and therefor no version
  problems arise.

4. I only use UTF-8 if absolutely necessary, for example when Chinese
  and Japanese texts are on the same page.

5. when using UTF-8 the characters do not look nice.

6. There is no need for UTF-8 : Japanese and Ascii is all we need in
  normal circumstances, why bother about other languages?

7. Similar Characters are grouped together
  and differences between similar Japanese Characters get lost.

8. Doesn't look good.

9. When only Chinese or only Japanese it looks good, when mixing
  languages the Characters the page gets ugly.

So, what do you think of that? I couldn’t imagine easily that reaction. In fact, it made me think about the North-American reaction to other charsets than ASCII. It’s a strong resistance to change, expressed in many different ways (particularly strong in point 6).

This list is particularly useful in understanding the problems end-users are facing and how things could be improved at the technical level for them to get a better experience with UTF-8.

There is a difference between coding systems and charsets (and I recommend following the link in the side-menu to understand that a bit better), but to be short I think the charset might influence the fonts used, in that every computer has a long list of charsets available and, for each of these charsets, there is a set of fonts (some of them being usable by several charsets, some of them not), that some people actually drew. Now this means that, if the guys that drew the images for “ttf-mikachan” (for UTF-8 ) are not as good as the “xfonts-jisx0213” fonts (JIS only?), then people looking at UTF-8 text will think that, because it’s UTF-8, it actually looks worst, although they could just change fonts and it would look nice too. Changing default fonts, however, is not the easiest thing to do on a computer (and it might just be impossible on mobile devices).

So, if you, out there, are looking into implementing UTF-8 on your website or your e-mail client to communicate with Eastern people, please try to take into account the list of reasons why they don’t like it, and hopefully we’ll all end-up with better applications and a full adoption of UTF-8.

Categories: Development, English, General, Techie Tags: , ,

Dokeos 1.8.5 Beta 2 available

Alright, so I did release a little brother for Dokeos 1.8.5 Beta today. We needed it for a customer of ours which is in development phase, and we had made a series of small but useful improvements to the Beta 1, so we decided that “why not?” and that a little Beta 2 couldn’t be harmful.

It can be downloaded from here

Basically, improvements are:

  • LDAP (tested in authenticated mode and added a field to define which value to search for in trying to recognize a teacher)
  • forum post alerts by e-mail
  • improved interface for creating new documents
  • removal of *many* notice-level warnings
  • speed and info improvements on users lists generation
  • isolation of exercises (was causing problems when opening an exercise from a link)
  • several fixes to buggy statistics for single DB mode
  • fixed courses descriptions bug (couldn’t edit course descriptions)
  • added informational messages in course copy to avoid user confusion

We are still working hard to try and get a definitive stable version out by the end of May or early June. We still intend to add several features to the whole thing (like *maybe* some kind of web services interface) which do not alter existing functions.

Can’t promise anything right now, but I’ll keep you informed.

%d bloggers like this: