Archive

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

Introduction

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’,
PRIMARY KEY (id)
)

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_id INT DEFAULT 0 NOT NULL,
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:

daily

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

weekly

$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);
  add_event_to_view(
    $event_title,
    mktime($h_orig,$n_orig,$s_orig,$m_now,$d_orig,$y_now),
    mktime($h_orig_e,$n_orig_e,$s_orig_e,$m_now,$d_orig_e,$y_now)
  );
}

monthlyByDate

$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);
  add_event_to_view(
    $event_title,
    mktime($h_orig,$n_orig,$s_orig,$m_now,$d_orig,$y_now),
    mktime($h_orig_e,$n_orig_e,$s_orig_e,$m_now,$d_orig_e,$y_now)
  );
}

yearly

$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);
  add_event_to_view(
    $event_title,
    mktime($h_orig,$n_orig,$s_orig,$m_now,$d_orig,$y_now),
    mktime($h_orig_e,$n_orig_e,$s_orig_e,$m_now,$d_orig_e,$y_now)
  );
}

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.

Conclusion

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 http://demo.dokeos.com/

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…

%d bloggers like this: