Add Tracewidget V01.65
authorRaphael Velt <raph.velt@gmail.com>
Thu, 12 Apr 2012 17:24:24 +0200
changeset 581 7607516bd9f1
parent 580 fba78a21c109
child 582 79b222c29887
Add Tracewidget
web/polemicaltimeline.php
web/res/css/metadataplayer/LdtPlayer.css
web/res/css/metadataplayer/imgs/player-sprites.png
web/res/js/LdtPlayer-release.js
web/res/js/tracemanager.js
--- a/web/polemicaltimeline.php	Thu Apr 12 16:22:41 2012 +0200
+++ b/web/polemicaltimeline.php	Thu Apr 12 17:24:24 2012 +0200
@@ -78,9 +78,8 @@
   		var metadatas = { metadata: {url: "<?php echo($translate->_('config__metadata'));?>", duration: <?php echo($translate->_('config__duration'))?>} };
   		var metadata_key = "metadata";
   		<?php endif;?>
-    IriSP.libdir = "<?php echo(registry_url('libdir','js'));?>";
+    IriSP.libFiles.defaultDir = "<?php echo(registry_url('libdir','js'));?>";
     IriSP.jwplayer_swf_path = "<?php echo(URL_ROOT); ?>res/mediaplayer/player.swf";
-    IriSP.platform_url = "http://ldt.iri.centrepompidou.fr/";
     IriSP.language = "<?php echo($actual) ?>"
     var json_url = metadatas[metadata_key].url;
 
@@ -130,7 +129,13 @@
              container: "TagcloudContainer",
         <?php if (isset($config['hashtag'])) echo "excludeWords: ".json_encode(array($config['hashtag'])).","; ?>
             excludePattern: /^@/
-            }
+        },{
+                        type: "TraceWidget",
+                     //   js_console : true,
+                        url: "http://traces.advene.org:5000/",
+                        requestmode: 'GET',
+                        syncmode: "sync"
+                    }
             ]
         },
       player:{
--- a/web/res/css/metadataplayer/LdtPlayer.css	Thu Apr 12 16:22:41 2012 +0200
+++ b/web/res/css/metadataplayer/LdtPlayer.css	Thu Apr 12 17:24:24 2012 +0200
@@ -329,12 +329,8 @@
     cursor: pointer;
 }
 
-.Ldt-Ctrl-Volume-Cursor:hover {
-     background: #cccccc;
-}
-
-.Ldt-Ctrl-Volume-Cursor.ui-draggable-dragging {
-    background: #999999;
+.Ldt-Ctrl-Volume-Control:hover .Ldt-Ctrl-Volume-Cursor {
+     background: #F7268E;
 }
 
 .Ldt-cleaner {
@@ -879,6 +875,9 @@
 .Ldt-AnnotationsListWidget {
   font-size: 12px;
   font-family: "Arial",  "Verdana", "sans-serif";
+  border: 1px solid #b6b8b8;
+  overflow: auto;
+  max-height: 480px;
 }
 
 ul.Ldt-AnnotationsList-ul {
@@ -897,7 +896,7 @@
 }
 
 .Ldt-AnnotationsList-highlight {
-    background: #cc80ff;
+    background: #F7268E; color: #ffffff;
 }
 
 .Ldt-AnnotationsListWidget a {
@@ -939,7 +938,11 @@
 }
 
 li.Ldt-AnnotationsList-Tag-Li {
-    float: left; margin: 2px; background: #cc0066; color: #fff; padding: 4px;
+    float: left; margin: 2px; background: #0068c4; color: #fff; padding: 4px;
+}
+
+li.Ldt-AnnotationsList-Tag-Li:hover {
+    background: #F7268E;
 }
 
 /* Tagcloud */
Binary file web/res/css/metadataplayer/imgs/player-sprites.png has changed
--- a/web/res/js/LdtPlayer-release.js	Thu Apr 12 16:22:41 2012 +0200
+++ b/web/res/js/LdtPlayer-release.js	Thu Apr 12 17:24:24 2012 +0200
@@ -996,7 +996,7 @@
 "'")+",'"}).replace(d.evaluate||null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};var n=function(a){this._wrapped=a};b.prototype=n.prototype;var u=function(a,c){return c?b(a).chain():a},J=function(a,c){n.prototype[a]=function(){var a=i.call(arguments);H.call(a,this._wrapped);return u(c.apply(b,
 a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];n.prototype[a]=function(){b.apply(this._wrapped,arguments);return u(this._wrapped,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];n.prototype[a]=function(){return u(b.apply(this._wrapped,arguments),this._chain)}});n.prototype.chain=function(){this._chain=true;return this};n.prototype.value=function(){return this._wrapped}}).call(this);
 /* main file */
-
+// Why is it called main ? It only loads the libs !
 
 if ( window.IriSP === undefined && window.__IriSP === undefined ) { 
   /**
@@ -1016,23 +1016,39 @@
 IriSP._ = window._.noConflict();
 IriSP.underscore = IriSP._;
 
-IriSP.loadLibs = function( libs, config, metadata_url, callback ) {
+IriSP.getLib = function(lib) {
+    return (
+        IriSP.libFiles.useCdn && typeof IriSP.libFiles.cdn[lib] == "string"
+        ? IriSP.libFiles.cdn[lib]
+        : (
+            typeof IriSP.libFiles.locations[lib] == "string"
+            ? IriSP.libFiles.locations[lib]
+            : (
+                typeof IriSP.libFiles.inDefaultDir[lib] == "string"
+                ? IriSP.libFiles.defaultDir + IriSP.libFiles.inDefaultDir[lib]
+                : null
+            )
+        )
+    )
+}
+
+IriSP.loadLibs = function( config, metadata_url, callback ) {
     // Localize jQuery variable
 		IriSP.jQuery = null;
-    var $L = $LAB.script(libs.jQuery).script(libs.swfObject).wait()
-                .script(libs.jQueryUI);
+    var $L = $LAB.script(IriSP.getLib("jQuery")).script(IriSP.getLib("swfObject")).wait()
+                .script(IriSP.getLib("jQueryUI"));
                                    
     if (config.player.type === "jwplayer" || config.player.type === "allocine") {
       // load our popcorn.js lookalike
-      $L.script(libs.jwplayer);
+      $L.script(IriSP.getLib("jwplayer"));
     } else {
       // load the real popcorn
-      $L.script(libs.popcorn).script(libs["popcorn.code"]);
+      $L.script(IriSP.getLib("popcorn")).script(IriSP.getLib("popcorn.code"));
       if (config.player.type === "youtube") {
-        $L.script(libs["popcorn.youtube"]);
+        $L.script(IriSP.getLib("popcorn.youtube"));
       } 
       if (config.player.type === "vimeo")
-        $L.script(libs["popcorn.vimeo"]);
+        $L.script(IriSP.getLib("popcorn.vimeo"));
       
       /* do nothing for html5 */
     }       
@@ -1042,10 +1058,10 @@
       if (config.gui.widgets[idx].type === "PolemicWidget" ||
           config.gui.widgets[idx].type === "StackGraphWidget" ||
           config.gui.widgets[idx].type === "SparklineWidget") {        
-        $L.script(libs.raphael);
+        $L.script(IriSP.getLib("raphael"));
       }
       if (config.gui.widgets[idx].type === "TraceWidget") {
-          $L.script(libs.tracemanager)
+          $L.script(IriSP.getLib("tracemanager"))
       }
     }
     
@@ -1053,7 +1069,7 @@
     /*
     for (var idx in config.modules) {
       if (config.modules[idx].type === "PolemicWidget")
-        $L.script(libs.raphaelJs);
+        $L.script(IriSP.getLib("raphaelJs"));
     }
     */
 
@@ -1063,7 +1079,7 @@
       var css_link_jquery = IriSP.jQuery( "<link>", { 
         rel: "stylesheet", 
         type: "text/css", 
-        href: libs.cssjQueryUI,
+        href: IriSP.getLib("cssjQueryUI"),
         'class': "dynamic_css"
       } );
       var css_link_custom = IriSP.jQuery( "<link>", { 
@@ -1089,9 +1105,9 @@
 IriSP.annotation_template = "{{! template for an annotation displayed in a segmentWidget }}<div title='{{divTitle}}' id='{{id}}'	class='Ldt-iri-chapter Ldt-TraceMe' 	style='left: {{startPixel}}px;          width: {{pxWidth}}px;          background-color:{{hexa_color}};'    data-seek='{{seekPlace}}'    thumbnail-url='{{thumbnailUrl}}'	></div>";
 IriSP.annotationWidget_template = "{{! template for the annotation widget }}<div class='Ldt-AnnotationsWidget'>  <!-- ugly div because we want to have a double border -->  <div class='Ldt-Annotation-DoubleBorder'>      <div class='Ldt-AnnotationContent'>          <div class='Ldt-AnnotationShareIcons'>         <a target='_blank' class='Ldt-fbShare Ldt-TraceMe' title='{{i10n.share_on}} Facebook'></a>         <a target='_blank' class='Ldt-TwShare Ldt-TraceMe' title='{{i10n.share_on}} Twitter'></a>         <a target='_blank'  class='Ldt-GplusShare Ldt-TraceMe' title='{{i10n.share_on}} Google+'></a>        </div>        <div class='Ldt-SaTitle'></div>        <div class='Ldt-SaDescription'></div>        <div class='Ldt-SaKeywords'></div>    </div>  </div></div>";
 IriSP.annotation_loading_template = "{{! template shown while the annotation widget is loading }}<div id='Ldt-load-container'><div id='Ldt-loader'>&nbsp;</div> Chargement... </div>";
-IriSP.annotationsListWidget_template = "{{! template for the annotation list widget }}<div class='Ldt-AnnotationsListWidget'>    <ul class='Ldt-AnnotationsList-ul'>        {{#annotations}}        <li id='Ldt-Annotation-li-{{id}}' class='Ldt-AnnotationsList-li Ldt-TraceMe'>            <img class='Ldt-AnnotationsList-Thumbnail' src='{{thumbnail}}' />            <div class='Ldt-AnnotationsList-Duration'>                <span class='Ldt-AnnotationsList-Begin'>{{begin}}</span>                <span class='Ldt-AnnotationsList-TcSeparator'>-</span>                <span class='Ldt-AnnotationsList-End'>{{end}}</span>            </div>            <div class='Ldt-AnnotationsList-Title'>            {{! if the url is not present, it means that the annotation exists            in the current project }}            {{^url}} <a href='#id={{id}}'> {{/url}}            {{! otherwise link to url }}            {{#url}} <a href='{{url}}'> {{/url}}                {{title}}            </a>            </div>            <div class='Ldt-AnnotationsList-Description'>                {{desc}}            </div>            {{#tags.length}}            <ul class='Ldt-AnnotationsList-Tags'>                {{#tags}}                <li class='Ldt-AnnotationsList-Tag-Li'>                    <div class='Ldt-AnnotationsList-Tag-Div'>{{.}}</div>                </li>                {{/tags}}            </ul>            {{/tags.length}}        </li>        {{/annotations}}    </ul></div>";
+IriSP.annotationsListWidget_template = "{{! template for the annotation list widget }}<div class='Ldt-AnnotationsListWidget'>    <ul class='Ldt-AnnotationsList-ul'>        {{#annotations}}        <li id='Ldt-Annotation-li-{{id}}' class='Ldt-AnnotationsList-li Ldt-TraceMe'>            {{^url}} <a href='#id={{id}}'> {{/url}}            {{! otherwise link to url }}            {{#url}} <a href='{{url}}'> {{/url}}                <img class='Ldt-AnnotationsList-Thumbnail' src='{{thumbnail}}' />            </a>            <div class='Ldt-AnnotationsList-Duration'>                <span class='Ldt-AnnotationsList-Begin'>{{begin}}</span>                <span class='Ldt-AnnotationsList-TcSeparator'>-</span>                <span class='Ldt-AnnotationsList-End'>{{end}}</span>            </div>            <div class='Ldt-AnnotationsList-Title'>            {{! if the url is not present, it means that the annotation exists            in the current project }}                {{title}}            </div>            <div class='Ldt-AnnotationsList-Description'>            {{^url}} <a href='#id={{id}}'> {{/url}}            {{! otherwise link to url }}            {{#url}} <a href='{{url}}'> {{/url}}                {{desc}}                </a>            </div>            {{#tags.length}}            <ul class='Ldt-AnnotationsList-Tags'>                {{#tags}}                <li class='Ldt-AnnotationsList-Tag-Li'>                    <div class='Ldt-AnnotationsList-Tag-Div'>{{.}}</div>                </li>                {{/tags}}            </ul>            {{/tags.length}}        </li>        {{/annotations}}    </ul></div>";
 IriSP.arrowWidget_template = "<div class='Ldt-arrowWidget Ldt-arrowLeftEdge'></div>";
-IriSP.createAnnotationWidget_template = "{{! template for the annotation creation widget }}<div class='Ldt-createAnnotationWidget'>    <!-- ugly div because we want to have a double border -->    <div class='Ldt-createAnnotation-DoubleBorder'>        <div class='Ldt-createAnnotation-screen Ldt-createAnnotation-startScreen'>            <div style='margin-bottom: 7px; overflow: auto;'>                <div class='Ldt-createAnnotation-Title'></div>                <div class='Ldt-createAnnotation-TimeFrame'></div>                {{^cinecast_version}} <div class='Ldt-createAnnotation-Minimize Ldt-TraceMe' title='Cancel'></div>                {{/cinecast_version}}            </div>            <div class='Ldt-createAnnotation-Container'>                {{#show_from_field}}                <label>{{l10n.your_name}}&nbsp;: </label><input class='Ldt-createAnnotation-userName Ldt-TraceMe' value='{{user_name}}' />                {{/show_from_field}}                <textarea class='Ldt-createAnnotation-Description Ldt-TraceMe'></textarea>                <div class='Ldt-createAnnotation-userAvatar Ldt-TraceMe'>                    {{^user_avatar}} <img src='https://si0.twimg.com/sticky/default_profile_images/default_profile_1_normal.png'></img>                    {{/user_avatar}}                    {{#user_avatar}} <img src='{{ user_avatar }}'></img>                    {{/user_avatar}}                </div>                <div class='Ldt-createAnnotation-profileArrow'></div>            </div>            <button class='Ldt-createAnnotation-submitButton Ldt-TraceMe'>{{l10n.submit}}</button>            {{#keywords.length}}            <div class='Ldt-createAnnotation-btnblock Ldt-createAnnotation-keywords'>                <label>{{l10n.add_keywords}} :</label>                <ul class='Ldt-floatList'>                {{#keywords}}                    <li><button class='Ldt-createAnnotation-keyword-button Ldt-TraceMe'>{{.}}</button></li>                {{/keywords}}                </ul>            </div>            {{/keywords.length}}            {{#polemic_mode}}            {{#polemics.length}}            <div class='Ldt-createAnnotation-btnblock Ldt-createAnnotation-polemics'>                <label>{{l10n.add_polemic_keywords}} :</label>                <ul class='Ldt-floatList'>                {{#polemics}}                    <li><button class='Ldt-createAnnotation-polemic-{{className}} Ldt-createAnnotation-polemic-button Ldt-TraceMe'>{{keyword}}</button></li>                {{/polemics}}                </ul>            </div>            {{/polemics.length}}            {{/polemic_mode}}        </div>        <div class='Ldt-createAnnotation-screen Ldt-createAnnotation-waitScreen' style='display: none; text-align: center'>            <div class='Ldt-createAnnotation-spinner'></div>            {{l10n.wait_while_processed}}        </div>        <div class='Ldt-createAnnotation-screen Ldt-createAnnotation-errorScreen' style='display: none; text-align: center'>            <div class='Ldt-createAnnotation-Minimize' title='Hide'></div>            {{l10n.error_while_contacting}}        </div>        <div class='Ldt-createAnnotation-screen Ldt-createAnnotation-endScreen' style='display: none'>            <div class='Ldt-createAnnotation-Minimize' title='Hide'></div>            {{l10n.annotation_saved}}            <br>            {{l10n.share_annotation}}            <div style='margin-top: 12px; text-align: center;'>                <a target='_blank' class='Ldt-createAnnotation-endScreen-TweetLink Ldt-TraceMe'></a>                <a target='_blank' class='Ldt-createAnnotation-endScreen-FbLink Ldt-TraceMe'></a>                <a target='_blank' class='Ldt-createAnnotation-endScreen-GplusLink Ldt-TraceMe'></a>            </div>        </div>        <div class='Ldt-floatClear'></div>    </div></div>";
+IriSP.createAnnotationWidget_template = "{{! template for the annotation creation widget }}<div class='Ldt-createAnnotationWidget'>    <!-- ugly div because we want to have a double border -->    <div class='Ldt-createAnnotation-DoubleBorder'>        <div class='Ldt-createAnnotation-screen Ldt-createAnnotation-startScreen'>            <div style='margin-bottom: 7px; overflow: auto;'>                <div class='Ldt-createAnnotation-Title'></div>                <div class='Ldt-createAnnotation-TimeFrame'></div>                {{^cinecast_version}} <div class='Ldt-createAnnotation-Minimize Ldt-TraceMe' title='Cancel'></div>                {{/cinecast_version}}            </div>            <div class='Ldt-createAnnotation-Container'>                {{#show_from_field}}                <label>{{l10n.your_name}}&nbsp;: </label><input class='Ldt-createAnnotation-userName Ldt-TraceMe' value='{{user_name}}' />                {{/show_from_field}}                <textarea class='Ldt-createAnnotation-Description Ldt-TraceMe'></textarea>                <div class='Ldt-createAnnotation-userAvatar Ldt-TraceMe'>                    {{^user_avatar}} <img src='https://si0.twimg.com/sticky/default_profile_images/default_profile_1_normal.png'></img>                    {{/user_avatar}}                    {{#user_avatar}} <img src='{{ user_avatar }}'></img>                    {{/user_avatar}}                </div>                <div class='Ldt-createAnnotation-profileArrow'></div>            </div>            <button class='Ldt-createAnnotation-submitButton Ldt-TraceMe'>{{l10n.submit}}</button>            {{#tags.length}}            <div class='Ldt-createAnnotation-btnblock Ldt-createAnnotation-keywords'>                <label>{{l10n.add_keywords}} :</label>                <ul class='Ldt-floatList'>                {{#tags}}                    <li><button class='Ldt-createAnnotation-keyword-button Ldt-TraceMe' tag-id='{{id}}'>{{meta.description}}</button></li>                {{/tags}}                </ul>            </div>            {{#random_tags}}                <button class='Ldt-createAnnotation-moar-keywordz'>{{l10n.more_tags}}</button>            {{/random_tags}}            {{/tags.length}}            {{#polemic_mode}}            {{#polemics.length}}            <div class='Ldt-createAnnotation-btnblock Ldt-createAnnotation-polemics'>                <label>{{l10n.add_polemic_keywords}} :</label>                <ul class='Ldt-floatList'>                {{#polemics}}                    <li><button class='Ldt-createAnnotation-polemic-{{className}} Ldt-createAnnotation-polemic-button Ldt-TraceMe'>{{keyword}}</button></li>                {{/polemics}}                </ul>            </div>            {{/polemics.length}}            {{/polemic_mode}}        </div>        <div class='Ldt-createAnnotation-screen Ldt-createAnnotation-waitScreen' style='display: none; text-align: center'>            <div class='Ldt-createAnnotation-spinner'></div>            {{l10n.wait_while_processed}}        </div>        <div class='Ldt-createAnnotation-screen Ldt-createAnnotation-errorScreen' style='display: none; text-align: center'>            <div class='Ldt-createAnnotation-Minimize' title='Hide'></div>            {{l10n.error_while_contacting}}        </div>        <div class='Ldt-createAnnotation-screen Ldt-createAnnotation-endScreen' style='display: none'>            <div class='Ldt-createAnnotation-Minimize' title='Hide'></div>            {{l10n.annotation_saved}}            <br>            {{^disable_share}}            {{l10n.share_annotation}}            <div style='margin-top: 12px; text-align: center;'>                <a target='_blank' class='Ldt-createAnnotation-endScreen-TweetLink Ldt-TraceMe'></a>                <a target='_blank' class='Ldt-createAnnotation-endScreen-FbLink Ldt-TraceMe'></a>                <a target='_blank' class='Ldt-createAnnotation-endScreen-GplusLink Ldt-TraceMe'></a>            </div>            {{/disable_share}}        </div>        <div class='Ldt-floatClear'></div>    </div></div>";
 IriSP.createAnnotation_errorMessage_template = "<p class='Ldt-createAnnotation-errorMessage'>  {{l10n.empty_annotation}}</p>";
 IriSP.loading_template = "<div id='Ldt-loader' style='width: {{width}}px; height: {{height}}px;'>{{l10n.loading_wait}}</div>";
 IriSP.overlay_marker_template = "{{! the template for the small bars which is z-indexed over our segment widget }}<div class='Ldt-SegmentPositionMarker' style='background-color: #F7268E;'></div>";
@@ -1286,10 +1302,7 @@
 
 /** issue a call to an url shortener and return the shortened url */
 IriSP.shorten_url = function(url) {
-  if (IriSP.config.shortener.hasOwnProperty("shortening_function"))
-    return IriSP.config.shortener.shortening_function(url);
-    
-  return url;
+  return encodeURIComponent(url);
 };
 
 
@@ -1424,11 +1437,11 @@
 };
     
 IriSP.PopcornReplacement.player.prototype.pause = function() {
-  if ( !this.media.paused ) {
+//  if ( !this.media.paused ) {
     this.media.paused = true;
     this.trigger( "pause" );
     this.playerFns.pause();
-  }
+//  }
 };
 
 IriSP.PopcornReplacement.player.prototype.muted = function(val) {
@@ -1556,15 +1569,16 @@
   this._callbacks = {};
 };
 
-IriSP.DataLoader.prototype.get = function(url, callback) {
-
-  var base_url = url.split("&")[0]
+IriSP.DataLoader.prototype.get = function(url, callback, force_reload) {
+  var base_url = url.split("&")[0];
+  if (typeof force_reload != "undefined" && force_reload && this._cache.hasOwnProperty(base_url)) {
+      delete this._cache[base_url]
+  }
   if (this._cache.hasOwnProperty(base_url)) {
     callback(this._cache[base_url]);
   } else {  
     if (!this._callbacks.hasOwnProperty(base_url)) {
-      this._callbacks[base_url] = [];
-      this._callbacks[base_url].push(callback);   
+      this._callbacks[base_url] = [callback];
       /* we need a closure because this gets lost when it's called back */
   
       // uncomment you don't want to use caching.
@@ -1577,6 +1591,7 @@
                   for (i = 0; i < this._callbacks[base_url].length; i++) {
                     this._callbacks[base_url][i](this._cache[base_url]);                                  
                   }
+                  delete this._callbacks[base_url];
       };
       
       /* automagically choose between json and jsonp */
@@ -1614,8 +1629,11 @@
 IriSP.Serializer.prototype.currentMedia = function() {  
 };
 
-IriSP.Serializer.prototype.sync = function(callback) {  
-  callback.call(this, this._data);  
+IriSP.Serializer.prototype.getDuration = function() {  
+};
+
+IriSP.Serializer.prototype.sync = function(callback) {
+    callback.call(this, this._data);
 };
 
 IriSP.SerializerFactory = function(DataLoader) {
@@ -1626,7 +1644,6 @@
   /* This function returns serializer set-up with the correct
      configuration - takes a metadata struct describing the metadata source
   */
-  
   if (metadataOptions === undefined)
     /* return an empty serializer */
     return IriSP.Serializer("", "");
@@ -1648,157 +1665,147 @@
       return undefined;
   }
 };
-/* site.js - all our site-dependent config : player chrome, cdn locations, etc...*/
-
-IriSP.defaults = {};
-
-/* these objects are filled by configureDefaults. The function doesn't overwrite 
-   defaults that were originally defined by the user.
-*/
-IriSP.lib = {};
-
-/* We need to define those so that the individual settings can be overwritten */
-IriSP.widgetsDefaults = {};
-
-IriSP.paths = {};
-
-IriSP.libdir = "/metadataplayer/src/js/libs/";
-IriSP.jwplayer_swf_path = "../test/libs/player.swf";
-IriSP.platform_url = "http://192.168.56.101/pf";
-IriSP.default_templates_vars = { };
-
-IriSP.language = 'fr';
-
-/** ugly ugly ugly ugly - returns an object defining 
-    the paths to the libs
-    We need it that way cause it's called at runtime by
-    IriSP.configureDefaults.
-*/   
-IriSP.defaults.lib = function(libdir) {
-  if (IriSP.null_or_undefined(libdir))
-    libdir = IriSP.libdir;
-  
-  return { 
-//      jQuery : "http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js",
-    jQuery : libdir + "jquery.min.js",
-//      jQueryUI : "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.17/jquery-ui.js",
-    jQueryUI : libdir + "jquery-ui.min.js",
-//      jQueryToolTip : "http://cdn.jquerytools.org/1.2.4/all/jquery.tools.min.js",
-    jQueryToolTip : libdir + "jquery.tools.min.js",
-//      swfObject : "http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js",
-    swfObject : libdir + "swfobject.js",
-//      cssjQueryUI : "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/base/jquery-ui.css",
-    cssjQueryUI : libdir + "jquery-ui.css",
-      popcorn : libdir + "popcorn.js",
-      jwplayer : libdir + "jwplayer.js",
-      popcornReplacement: libdir + "pop.js",
-      raphael: libdir + "raphael.js",
-      jquery_sparkline: libdir + "jquery.sparkline.js",
-      "popcorn.mediafragment" : libdir + "popcorn.mediafragment.js",
-      "popcorn.code" : libdir + "popcorn.code.js",
-      "popcorn.jwplayer": libdir + "popcorn.jwplayer.js",
-      "popcorn.youtube": libdir + "popcorn.youtube.js",
-      "tracemanager": libdir + "tracemanager.js"
-  };
-};
-
-//Configuration for the player and utility functions.
-// No need to have them configured at runtime
-IriSP.config = {};
-
-IriSP.config.shortener = {
-  // function to call to shorten an url.
-  //shortening_function : IriSP.platform_shorten_url
-};
-
-IriSP.defaults.widgetsDefaults = function(platform_url) { 
-  if (IriSP.null_or_undefined(platform_url))
-    platform_url = IriSP.platform_url;
-  
-  return {
-    "LayoutManager" : {spacer_div_height : "0px" },
-    "PlayerWidget" : {},
-    "AnnotationsWidget": {
-      "share_text" : "I'm watching ",     
-      "fb_link" : "http://www.facebook.com/share.php?u=",
-      "tw_link" : "http://twitter.com/home?status=",
-      "gplus_link" : ""
-      },
-    
+IriSP.language = 'en';
+
+IriSP.libFiles = {
+    defaultDir : "js/libs/",
+    inDefaultDir : {
+        jQuery : "jquery.min.js",
+        jQueryUI : "jquery-ui.min.js",
+        jQueryToolTip : "jquery.tools.min.js",
+        swfObject : "swfobject.js",
+        cssjQueryUI : "jquery-ui.css",
+        popcorn : "popcorn.js",
+        jwplayer : "jwplayer.js",
+        raphael : "raphael.js",
+        "popcorn.mediafragment" : "popcorn.mediafragment.js",
+        "popcorn.code" : "popcorn.code.js",
+        "popcorn.jwplayer" : "popcorn.jwplayer.js",
+        "popcorn.youtube" : "popcorn.youtube.js",
+        "tracemanager" : "tracemanager.js"
+    },
+    locations : {
+        // use to define locations outside defautl_dir
+    },
+    cdn : {
+        jQueryUI : "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.17/jquery-ui.js",
+        jQueryToolTip : "http://cdn.jquerytools.org/1.2.4/all/jquery.tools.min.js",
+        swfObject : "http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js",
+        cssjQueryUI : "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/base/jquery-ui.css"
+    },
+    useCdn : false
+}
+
+IriSP.widgetsDefaults = {
+    "LayoutManager" : {
+        spacer_div_height : 0
+    },
+    "PlayerWidget" : {
+        
+    },
+    "AnnotationsWidget" : {
+        "share_text" : "I'm watching "
+    },
     "TweetsWidget" : {
         default_profile_picture : "https://si0.twimg.com/sticky/default_profile_images/default_profile_1_normal.png",
-        tweet_display_period: 10000 // how long do we show a tweet ?
-        
+        tweet_display_period : 10000 // how long do we show a tweet ?
     },
     "SliderWidget" : {
-        minimize_period: 850 // how long does the slider stays maximized after the user leaves the zone ?
+        minimize_period : 850 // how long does the slider stays maximized after the user leaves the zone ?
+    },
+    "SegmentsWidget" : {
+        cinecast_version : false
     },
     "createAnnotationWidget" : {
-        keywords: ["#amateur", "#digital-studies"],
-        polemic_mode: true, /* enable polemics ? */
-        /* polemics - the corresponding class names defined in the css should be for instance :
-           Ldt-createAnnotation-polemic-positive for positive
-           Ldt-createAnnotation-polemic-equalequal for equalequal, etc.
-        */
-        polemics: [ { "className" : "positive", "keyword" : "++" }, { "className" : "negative", "keyword" : "--" }, { "className" : "reference", "keyword" : "==" }, { "className" : "question", "keyword" : "??" } ], 
-        cinecast_version: false, /* put to false to enable the platform version, true for the festival cinecast one. */
-        
+        tags : [
+            {
+                "id" : "digitalstudies",
+                "meta" : {
+                    "description" : "#digital-studies"
+                }
+            },
+            {
+                "id" : "amateur",
+                "meta" : {
+                    "description" : "#amateur"
+                },
+            }
+        ],
+        remote_tags : false,
+        random_tags : false,
+        show_from_field : false,
+        disable_share : false,
+        polemic_mode : true, /* enable polemics ? */
+        polemics : [{
+            "className" : "positive",
+            "keyword" : "++"
+        }, {
+            "className" : "negative",
+            "keyword" : "--"
+        }, {
+            "className" : "reference",
+            "keyword" : "=="
+        }, {
+            "className" : "question",
+            "keyword" : "??"
+        }],
+        cinecast_version : false, /* put to false to enable the platform version, true for the festival cinecast one. */
+
         /* where does the widget PUT the annotations - this is a mustache template. id refers to the id of the media ans is filled
-           by the widget. 
-        */
-        api_endpoint_template: platform_url + "/ldtplatform/api/ldt/annotations/{{id}}.json",
-        api_method: "PUT"
+         by the widget.
+         */
+        api_endpoint_template : "", // platform_url + "/ldtplatform/api/ldt/annotations/{{id}}.json",
+        api_method : "PUT"
     },
     "SparklineWidget" : {
-        column_width: 10 // the width of a column in pixels.
-    },
-    "Main" : {
-        autoplay: true
+       lineColor : "#7492b4",
+       fillColor : "#aeaeb8",
+       lineWidth : 2,
+       cinecast_version : false
     },
     "AnnotationsListWidget" : {
-        ajax_mode: true, /* use ajax to get information about the annotations.
-                           if set to false, only search in the annotations for the
-                           current project. */
+        ajax_mode : true, /* use ajax to get information about the annotations.
+         if set to false, only search in the annotations for the
+         current project. */
         /* the platform generates some funky urls. We replace them afterwards to point to the
-           correct place - this setting will probably be overwritten by the platform 
-           implementers.
-           Note that the player has to replace the variables between {{ and }} by its own values.
-        */
-        ajax_url: platform_url + "/ldtplatform/api/ldt/segments/{media}/{begin}/{end}", 
-        
-        ajax_granularity: 10000, /* how much ms should we look before and after the
-                                   current timecode */
-      
-        default_thumbnail: "/metadataplayer/src/css/imgs/video_sequence.png",
-        
-        project_url: platform_url + "/ldtplatform/ldt/front/player/" /* the beginning 
-                                                                        of a link to the
-                                                                        new front */
-    } 
-  };
-};
-
-/*
-Override this if you want to change the info the player receives about the user.
-It's typically overrided in server-side templates with user-specific data.
-*/
-IriSP.defaults.user = function() { return {
-      "name" : "Anonymous user",
-      "avatar" : IriSP.paths.imgs + "/user_default_icon.png"
+         correct place - this setting will probably be overwritten by the platform
+         implementers.
+         Note that the player has to replace the variables between {{ and }} by its own values.
+         */
+        ajax_url : "", //platform_url + "/ldtplatform/api/ldt/segments/{{media}}/{{begin}}/{{end}}",
+        ajax_granularity : 10000, /* how much ms should we look before and after the current timecode */
+        default_thumbnail : "http://ldt.iri.centrepompidou.fr/static/site/ldt/css/imgs/video_sequence.png",
+        project_url : "", //platform_url + "/ldtplatform/ldt/front/player/"
+        /* the beginning of a link to the new front */
+        cinecast_version : false,
+        refresh_interval : 10000
+    },
+    "StackGraphWidget" : {
+         defaultcolor : "#585858",
+         tags : [
+            {
+                "keywords" : [ "++" ],
+                "description" : "positif",
+                "color" : "#1D973D"
+            },
+            {
+                "keywords" : [ "--" ],
+                "description" : "negatif",
+                "color" : "#CE0A15"
+            },
+            {
+                "keywords" : [ "==" ],
+                "description" : "reference",
+                "color" : "#C5A62D"  
+            },
+            {
+                "keywords" : [ "??" ],
+                "description" : "question",
+                "color" : "#036AAE"
+            }
+        ],
+        streamgraph : false
     }
-};
-
-
-IriSP.defaults.paths = {
-//  "imgs": "/tweetlive/res/metadataplayer/src/css/imgs"
-  "imgs": "/metadataplayer/src/css/imgs"
-};
-
-
-IriSP.defaults.default_templates_vars = function() { 
-  return {
-  "img_dir" : IriSP.paths.imgs 
-  };
 }/* the widget classes and definitions */
 
 /**
@@ -1858,24 +1865,28 @@
       this.selector.attr("widget-type", this._config.type);
   }
   
-};
-
-// This functions checks for configuration options
-
-IriSP.Widget.prototype.checkOption = function(_name, _default) {
-    this[_name] = (
-        typeof this._config[_name] != "undefined"
-        ? this._config[_name]
-        : (
-            (typeof IriSP.widgetsDefaults[this._config.type] != "undefined" && IriSP.widgetsDefaults[this._config.type][_name] != "undefined")
-            ? IriSP.widgetsDefaults[this._config.type][_name]
-            : (
-                typeof _default != "undefined"
-                ? _default
-                : null
-            )
-        )
-    )
+  // Parsing Widget Defaults
+  var _this = this;
+  
+  if (typeof config.type == "string" && typeof IriSP.widgetsDefaults[config.type] == "object") {
+      IriSP._(IriSP.widgetsDefaults[config.type]).each(function(_v, _k) {
+          if (typeof config[_k] != "undefined") {
+              _this[_k] = config[_k];
+          } else {
+              _this[_k] = _v;
+          }
+      });
+  }
+  
+};
+
+
+IriSP.Widget.prototype.currentMedia = function() {
+    return this._serializer.currentMedia();
+}
+
+IriSP.Widget.prototype.getDuration = function() {
+    return this._serializer.getDuration();
 }
 
 /**
@@ -1935,7 +1946,10 @@
     /* this is a shortcut */
     this.selector = IriSP.jQuery("#" + this._div);
     
-    this.selector.css("width", this._width);
+    this.selector.css({
+        "width": this._width,
+        "clear": "both"
+    });
     
     if (this._height !== undefined)
       this.selector.css("height", this._height);
@@ -1965,8 +1979,8 @@
     var spacerDiv = IriSP.guid("LdtPlayer_spacer_");
     this._widgets.push([widgetName, newDiv]);    
 
-    var divTempl = "<div id='{{id}}' style='width: {{width}}px; position: relative;'></div";
-    var spacerTempl = "<div id='{{spacer_id}}' style='width: {{width}}px; position: relative; height: {{spacer_div_height}};'></div";
+    var divTempl = "<div id='{{id}}' style='width: {{width}}px; position: relative; clear: both;'></div";
+    var spacerTempl = "<div id='{{spacer_id}}' style='width: {{width}}px; position: relative; height: {{spacer_div_height}}px;'></div";
     
     var divCode = Mustache.to_html(divTempl, {id: newDiv, width: this._width});
     var spacerCode = Mustache.to_html(spacerTempl, {spacer_id: spacerDiv, width: this._width,
@@ -2218,54 +2232,18 @@
     return widget;
 };
 
-/** Go through the defaults to set a reasonable value */
-IriSP.configureDefaults = function(libdir, platform_url) {
-  /* the defaults configuration is messy and complicated. There are two things to know :
-     - we want to allow overwriting of defaults - that's why we have IriSP.widgetDefaults
-       and IriSP.defaults.widgetDefaults. The first is filled by the embedder and then fleshed out
-       with the contents of the first. We use underscore.defaults for that, but there's one problem with
-       this function : it doesn't work recursively.
-     - we need to compute some values at runtime instead of at compile time
-  */
-    
-  IriSP.lib = IriSP.underscore.defaults(IriSP.lib, IriSP.defaults.lib(libdir));
-  
-  /* get the factory defaults for the widgets and merge them with the default the user
-     may have defined 
-  */
-  var factory_defaults = IriSP.defaults.widgetsDefaults(platform_url);
-  for(var widget in factory_defaults) {
-  
-      /* create the object if it doesn't exists */
-      if (IriSP.null_or_undefined(IriSP.widgetsDefaults[widget]))
-        IriSP.widgetsDefaults[widget] = {};
-        
-      IriSP.widgetsDefaults[widget] = IriSP.underscore.defaults(IriSP.widgetsDefaults[widget], factory_defaults[widget]);
-  }
-  
-  IriSP.paths = IriSP.underscore.defaults(IriSP.paths, IriSP.defaults.paths);
-  IriSP.default_templates_vars = IriSP.underscore.defaults(IriSP.default_templates_vars, 
-                                       IriSP.defaults.default_templates_vars());
-
-  if (IriSP.null_or_undefined(IriSP.user))
-    IriSP.user = {};
-  
-  IriSP.user = IriSP.underscore.defaults(IriSP.user, IriSP.defaults.user());
-};
-
 /** single point of entry for the metadataplayer */
-IriSP.initPlayer = function(config, metadata_url, libdir, platform_url) {
+IriSP.initPlayer = function(config, metadata_url) {
     document.getElementById(config.gui.container).innerHTML = IriSP.templToHTML(IriSP.loading_template, config.gui);
-    IriSP.configureDefaults(libdir, platform_url);
-    IriSP.loadLibs(IriSP.lib, config, metadata_url,
+    IriSP.loadLibs(config, metadata_url,
       function() {   
               
               var layoutManager = new IriSP.LayoutManager(config.gui);
 
               var pop = IriSP.configurePopcorn(layoutManager, config.player);
               
-              var widgets = IriSP.configureWidgets(pop, layoutManager, config.gui); 
-              var modules = IriSP.configureModules(pop, config.modules); 
+              IriSP._widgets = IriSP.configureWidgets(pop, layoutManager, config.gui); 
+              IriSP._modules = IriSP.configureModules(pop, config.modules); 
               IriSP.jQuery('#Ldt-loader').detach();
       });
 };IriSP.I18n = function() {
@@ -2353,49 +2331,22 @@
 
     this.playerFns = {
         play : function() {
-            if (_this.player) {
-            //    console.log("ask play _this.player = " + _this.player);
-                return _this.player.sendToActionScript("play");
-            } else {
-                return false;
-            }
+            return _this.apiCall("play");
         },
         pause : function() {
-            if (_this.player) {
-            //    console.log("ask pause _this.player = " + _this.player);
-                return _this.player.sendToActionScript("pause");
-            } else {
-                return false;
-            }
+            return _this.apiCall("pause");
         },
         getPosition : function() {
-            if (_this.player) {
-                return _this.player.sendToActionScript("getSeek","return");
-            } else {
-                return 0;
-            }
+            return _this.apiCall("getSeek","return") || 0;
         },
         seek : function(pos) {
-            if (_this.player) {
-                return _this.player.sendToActionScript("seek",pos);
-            } else {
-                return false;
-            }
+            return _this.apiCall("seek",pos);
         },
         getMute : function() {
-            if (_this.player) {
-                return _this.player.sendToActionScript("getMute","return");
-            } else {
-                return false;
-            }
+            return _this.apiCall("getMute","return");
         },
         setMute : function(p) {
-            if (_this.player) {
-                //return p ? _this.player.sendToActionScript("setMute") : _this.player.sendToActionScript("setMute");
-            	_this.player.sendToActionScript("setMute");
-            } else {
-                return false;
-            }
+            return _this.apiCall("setMute", p);
         }
     }
 
@@ -2408,19 +2359,32 @@
         ? options.directVideoPath
         : IriSP.get_aliased(IriSP.__jsonMetadata["medias"][0], ["href","url"])
     );
+    var _flashVars = {
+        "streamFMS" : true,
+        "adVast" : false,
+        "lg" : "fr_cinecast",
+        "autoPlay" : options.autoPlay,
+        "directVideoTitle" : "",
+        "urlAcData" : options.urlAcData,
+        "directVideoPath" : _videoUrl,
+        "host" : "http://allocine.fr"
+    }
     
-    var fv = "streamFMS=true&adVast=false&lg=fr_cinecast&autoPlay=" + options.autoPlay + "&directVideoTitle=&urlAcData=" + options.urlAcData + "&directVideoPath=" + _videoUrl + "&host=http://allocine.fr";
-//    console.log("fv = " + fv);
+    if (typeof IriSP.__jsonMetadata["medias"][0].meta == "object" && typeof IriSP.__jsonMetadata["medias"][0].meta.subtitles == "string") {
+        _flashVars.subTitlePath = IriSP.__jsonMetadata["medias"][0].meta.subtitles;
+    }
     
+
     var params = {
         "allowScriptAccess" : "always",
         "wmode": "opaque",
-        "flashvars" : fv
+        "flashvars" : IriSP.jQuery.param(_flashVars),
+        "allowfullscreen" : true
     };
     var atts = {
         id : this.container
     };
-    swfobject.embedSWF(options.acPlayerUrl, this.container, options.width, options.height, "8", null, null, params, atts);
+    swfobject.embedSWF(options.acPlayerUrl, this.container, options.width, options.height, "10", null, null, params, atts);
 
 };
 
@@ -2429,7 +2393,6 @@
 IriSP.PopcornReplacement.allocine.prototype.ready = function() {
     this.player = document.getElementById(this.container);
     this.player.addEventListener("onStateChange", "onAllocineStateChange");
-    this.player.addEventListener("onVideoProgress", "onAllocineVideoProgress");
     this.player.cueVideoByUrl(this._options.video);
     this.callbacks.onReady();
 };
@@ -2441,6 +2404,23 @@
 }
 
 
+IriSP.PopcornReplacement.allocine.prototype.apiCall = function(_method, _arg) {
+    if (this.player) {
+        try {
+            if (typeof _arg == "undefined") {
+                return this.player.sendToActionScript(_method);
+            } else {
+                return this.player.sendToActionScript(_method, _arg);
+            }
+        } catch(e) {
+            console.error('Exception while requesting AcPlayer for "' + _method + (typeof _arg == "undefined" ? '' : '" with argument "' + _arg ) + '"\n', e);
+            return false;
+        }
+    } else {
+        return false;
+    }
+}
+
 IriSP.PopcornReplacement.allocine.prototype.stateHandler = function(state) {
     console.log("stateHandler");
     switch(state) {
@@ -2770,11 +2750,6 @@
   IriSP.Widget.call(this, Popcorn, config, Serializer);
   this.__counter = 0;
   this.__oldList = [];
- 
-  this.checkOption('ajax_mode');
-  this.checkOption('project_url');
-  this.checkOption('default_thumbnail');
-  this.checkOption("cinecast_version", false);
   this.searchRe = null;
   this._ajax_cache = [];
   var _this = this;
@@ -2801,7 +2776,7 @@
 
 IriSP.AnnotationsListWidget.prototype.searchHandler = function(searchString) {
   this.searchRe = (searchString && searchString.length) ? IriSP.regexpFromText(searchString) : null;
-  if (this.ajax_mode) {
+  if (this.ajax_mode && !this.cinecast_version) {
       var _this = this,
         _annotations = (
             this.searchRe === null
@@ -2831,17 +2806,21 @@
       
     this.selector.html(_html);
     
+    this.selector.find('.Ldt-AnnotationsList-Tag-Li').click(function() {
+        _this._Popcorn.trigger("IriSP.search.triggeredSearch", IriSP.jQuery(this).text().trim());
+    })
+    
     if (this.searchRe !== null) {
         this.selector.find(".Ldt-AnnotationsList-Title a, .Ldt-AnnotationsList-Description")
             .each(function()  {
                 var _$ = IriSP.jQuery(this);
-                _$.html(_$.text().replace(_this.searchRe, '<span class="Ldt-AnnotationsList-highlight">$1</span>'))
+                _$.html(_$.text().trim().replace(_this.searchRe, '<span class="Ldt-AnnotationsList-highlight">$1</span>'))
             })
     }
 };
 
 IriSP.AnnotationsListWidget.prototype.transformAnnotation = function(a) {
-    var _this = this
+    var _this = this;
     return {
         "id" : a.id,
         "title": this.cinecast_version ? IriSP.get_aliased(a.meta, ['creator_name', 'creator']) : a.content.title,
@@ -2850,6 +2829,7 @@
         "end" : IriSP.msToTime(a.end),
         "thumbnail" : (typeof a.meta == "object" && typeof a.meta.thumbnail == "string") ? a.meta.thumbnail : this.default_thumbnail,
         "url" : (typeof a.meta == "object" && typeof a.meta.url == "string") ? a.meta.url : null,
+        "created_at" :(typeof a.meta == "object" && typeof a.meta.created == "string") ? Date.parse(a.meta.created.replace(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}\:\d{2}\:\d{2}).*$/,"$2/$3/$1 $4 UTC+0000")) : null,
         "tags": typeof a.tags == "object"
             ? IriSP.underscore(a.tags)
                 .chain()
@@ -2908,7 +2888,6 @@
             this._Popcorn.trigger("IriSP.search.noMatchFound");
           }
     }
-  
   list = IriSP.underscore(list)
     .chain()
     .sortBy(function(_o) {
@@ -2916,16 +2895,15 @@
     })
     .first(10)
     .sortBy(function(_o) {
-        return _o.iterator;
+        return (_this.cinecast_version ? - _o.created_at : _o.iterator);
     })
     .value();
-  
   var idList = IriSP.underscore.pluck(list, "id").sort();
 
-  
-  if (!IriSP.underscore.isEqual(this.__oldList, idList) || typeof(force_redraw) !== "undefined") {
+  if (!IriSP.underscore.isEqual(this.__oldList, idList) || this.lastSearch !== this.searchRe || typeof(force_redraw) !== "undefined") {
     this.do_redraw(list);
     this.__oldList = idList;
+    this.lastSearch = this.searchRe;
   }
    /* save for next call */
   
@@ -2944,15 +2922,13 @@
   }
    
   
-  /* the platform gives us a special url - of the type : http://path/{media}/{begin}/{end}
+  /* the platform gives us a special url - of the type : http://path/{{media}}/{{begin}}/{{end}}
      we double the braces using regexps and we feed it to mustache to build the correct url
      we have to do that because the platform only knows at run time what view it's displaying.
   */
      
-  var platf_url = IriSP.widgetsDefaults.AnnotationsListWidget.ajax_url
-                                      .replace(/\{/g, '{{').replace(/\}/g, '}}');
-  var media_id = this._serializer.currentMedia()["id"];
-  var duration = this._serializer.getDuration();
+  var media_id = this.currentMedia()["id"];
+  var duration = this.getDuration();
   
   var begin_timecode = (Math.floor(tcode) - 300) * 1000;
   if (begin_timecode < 0)
@@ -2962,7 +2938,7 @@
   if (end_timecode > duration)
     end_timecode = duration;
   
-  var templ = Mustache.to_html(platf_url, {media: media_id, begin: begin_timecode,
+  var templ = Mustache.to_html(this.ajax_url, {media: media_id, begin: begin_timecode,
                                  end: end_timecode});
 
   /* we create on the fly a serializer to get the ajax */
@@ -2983,7 +2959,7 @@
   */
   var l = [];
   
-  var media = this._serializer.currentMedia()["id"];
+  var media = this.currentMedia()["id"];
   
   for (i = 0; i < annotations.length; i++) {
     var obj = this.transformAnnotation(annotations[i])
@@ -3016,13 +2992,33 @@
   
   var _this = this;
     
-    if (!this.ajax_mode) {
+    if (!this.ajax_mode || this.cinecast_version) {
         var _throttled = IriSP.underscore.throttle(function() {
             _this.drawList();
         }, 1500);
         _throttled();
         this._Popcorn.listen("IriSP.createAnnotationWidget.addedAnnotation", _throttled);
         this._Popcorn.listen("timeupdate", _throttled);
+        if (this.cinecast_version) {
+            window.setInterval(function() {
+                var _tmpSerializer = new IriSP.JSONSerializer(IriSP.__dataloader,  _this._config.metadata.src, true);
+                _tmpSerializer.sync(function(json) {
+                    _this.annotations_ids = IriSP.underscore(_this._serializer._data.annotations).map(function(_a) {
+                      return _a.id.toLowerCase();
+                    });
+                    IriSP.underscore(json.annotations).each(function(_a) {
+                        var _j = _this.annotations_ids.indexOf(_a.id);
+                        if (_j == -1) {
+                            _this._serializer._data.annotations.push(_a);
+                            _this.annotations_ids.push(_a.id);
+                        } else {
+                            _this._serializer._data.annotations[_j] = _a;
+                        }
+                        _throttled();
+                    });
+                }, true); // true is for force_refresh
+            },this.refresh_interval);
+        }
   } else {
     /* update the widget when the video has finished loading and when it's seeked and paused */
     this._Popcorn.listen("seeked", IriSP.wrap(this, this.ajaxRedraw));
@@ -3066,7 +3062,7 @@
     var keywords =  "";
     var begin = +annotation.begin / 1000;
     var end = +annotation.end / 1000;
-    var duration = this._serializer.getDuration();
+    var duration = this.getDuration();
     var tags = "";
     
     var title_templ = "{{title}} - ( {{begin}} - {{end}} )";
@@ -3098,15 +3094,10 @@
     this.selector.find(".Ldt-SaKeywords").text(tags);
     
     // update sharing buttons
-    var defaults = IriSP.widgetsDefaults.AnnotationsWidget;
-    var text = defaults.share_text;
-    var fb_link = defaults.fb_link;
-    var tw_link = defaults.tw_link;
-    var gplus_link = defaults.gplus_link;
     var url = document.location.href + "#id=" + annotation.id;
-    this.selector.find(".Ldt-fbShare").attr("href", IriSP.mkFbUrl(url, text));
-    this.selector.find(".Ldt-TwShare").attr("href", IriSP.mkTweetUrl(url, text));
-    this.selector.find(".Ldt-GplusShare").attr("href", IriSP.mkGplusUrl(url, text));
+    this.selector.find(".Ldt-fbShare").attr("href", IriSP.mkFbUrl(url, this.share_text));
+    this.selector.find(".Ldt-TwShare").attr("href", IriSP.mkTweetUrl(url, this.share_text));
+    this.selector.find(".Ldt-GplusShare").attr("href", IriSP.mkGplusUrl(url, this.share_text));
 };
 
 IriSP.AnnotationsWidget.prototype.clearWidget = function() {   
@@ -3220,7 +3211,7 @@
     var begin = (+ currentAnnotation.begin) / 1000;
     var end = (+ currentAnnotation.end) / 1000;
 
-    var duration = this._serializer.getDuration() / 1000;
+    var duration = this.getDuration() / 1000;
     var middle_time = (begin + end) / 2;
     var percents = middle_time / duration;
 
@@ -3281,7 +3272,8 @@
             "empty_annotation": "Your annotation is empty. Please write something before submitting.",
             "annotation_saved": "Thank you, your annotation has been saved.",
             "share_annotation": "Would you like to share it on social networks ?",
-            "share_on": "Share on"
+            "share_on": "Share on",
+            "more_tags": "More tags"
         },
         "fr": {
             "submit": "Envoyer",
@@ -3294,7 +3286,8 @@
             "empty_annotation": "Votre annotation est vide. Merci de rédiger un texte avant de l'envoyer.",
             "annotation_saved": "Merci, votre annotation a été enregistrée.",
             "share_annotation": "Souhaitez-vous la partager sur les réseaux sociaux ?",
-            "share_on": "Partager sur"
+            "share_on": "Partager sur",
+            "more_tags": "Plus de mots-clés"
         }
     }
 );
@@ -3302,14 +3295,6 @@
 IriSP.createAnnotationWidget = function(Popcorn, config, Serializer) {
   IriSP.Widget.call(this, Popcorn, config, Serializer);
   this._hidden = true;
-  
-  this.checkOption("keywords");
-  this.checkOption("polemic_mode", true);
-  this.checkOption("polemics");
-  this.checkOption("cinecast_version", false);
-  this.checkOption("api_endpoint_template");
-  this.checkOption("show_from_field", true);
-  this.checkOption("api_method");
                          
   if (!IriSP.null_or_undefined(IriSP.user)) {
       if (!IriSP.null_or_undefined(IriSP.user.avatar)) {
@@ -3337,6 +3322,18 @@
 };
 
 IriSP.createAnnotationWidget.prototype.draw = function() {
+    var _this = this;
+    if (typeof this.remote_tags == "object") {
+        IriSP.jQuery.getJSON((typeof this.remote_tags.alias == "string" ? this.remote_tags.alias : this.remote_tags.url), function(_json) {
+            _this.tags = _json.tags;
+            _this.drawCallback();
+        });
+    } else {
+        this.drawCallback();
+    }
+}
+
+IriSP.createAnnotationWidget.prototype.drawCallback = function() {
   var _this = this;
   
   var annotationMarkup = IriSP.templToHTML(IriSP.createAnnotationWidget_template, 
@@ -3349,17 +3346,25 @@
   else {
     this.showStartScreen();
   }
-
+  
+  if (this.random_tags) {
+      this.selector.find(".Ldt-createAnnotation-keywords li").hide();
+      this.showMoreTags();
+      this.selector.find('.Ldt-createAnnotation-moar-keywordz').click(function() {
+          _this.showMoreTags();
+      })
+  }
   // Add onclick event to both polemic and keywords buttons
   
-  this.selector.find(".Ldt-createAnnotation-btnblock button").click(function() {
+  this.selector.find(".Ldt-createAnnotation-keyword-button, .Ldt-createAnnotation-polemic-button").click(function() {
       _this.addKeyword(IriSP.jQuery(this).text());
+      return false;
   });
   
   // js_mod is a custom event because there's no simple way to test for a js
   // change in a textfield.                    
   this.selector.find(".Ldt-createAnnotation-Description")
-               .bind("propertychange keyup input paste js_mod", IriSP.wrap(this, this.handleTextChanges));
+               .bind("propertychange keyup input paste click js_mod", IriSP.wrap(this, this.handleTextChanges));
                
   /* the cinecast version of the player is supposed to pause when the user clicks on the button */
 
@@ -3420,6 +3425,21 @@
   }
 };
 
+IriSP.createAnnotationWidget.prototype.showMoreTags = function() {
+    for (var j=0; j < this.random_tags; j++) {
+        var _jq = this.selector.find(".Ldt-createAnnotation-keywords li:hidden");
+        if (_jq.length > 1) {
+            IriSP.jQuery(_jq[Math.floor(_jq.length*Math.random())]).show();
+        } else {
+            _jq.show();
+            break;
+        }     
+    }
+    if (this.selector.find(".Ldt-createAnnotation-keywords li:hidden").length == 0) {
+        this.selector.find('.Ldt-createAnnotation-moar-keywordz').hide();
+    }
+}
+
 /* Handles adding keywords and polemics */
 IriSP.createAnnotationWidget.prototype.addKeyword = function(_keyword) {
     var _field = this.selector.find(".Ldt-createAnnotation-Description"),
@@ -3429,8 +3449,7 @@
         ? _contents.replace(_rx,"").replace("  "," ").trim()
         : _contents.trim() + " " + _keyword
     );
-    _field.val(_contents);
-    _field.trigger("js_mod");
+    _field.val(_contents.trim()).trigger("js_mod");
 }
 
 /** handles clicks on the annotate button. Works only for the non-cinecast version */
@@ -3455,7 +3474,7 @@
     // block the arrow.
     this._Popcorn.trigger("IriSP.ArrowWidget.blockArrow");
     
-    var duration = this._serializer.getDuration();
+    var duration = this.getDuration();
         
     var currentChapter = this._serializer.currentChapitre(currentTime);
 
@@ -3491,7 +3510,7 @@
 /** watch for changes in the textfield and change the buttons accordingly */
 IriSP.createAnnotationWidget.prototype.handleTextChanges = function(event) {
   var contents = this.selector.find(".Ldt-createAnnotation-Description").val();
-  if (this.cinecast_version && !this._Popcorn.media.paused) {
+  if (this.cinecast_version) {
       this._Popcorn.pause();
   }
   this.selector.find(".Ldt-createAnnotation-btnblock button").each(function() {
@@ -3614,23 +3633,28 @@
 
 IriSP.createAnnotationWidget.prototype.sendLdtData = function(contents, callback) {
   var _this = this;
-  var apiJson = {annotations : [{}], meta: {}};
+  var apiJson = {
+      format : "http://advene.org/ns/cinelab/",
+      annotations : [
+        {}
+        ],
+        meta: {}};
   var annotation = apiJson.annotations[0];
   
-  annotation.media = this._serializer.currentMedia()["id"];
+  annotation.media = this.currentMedia()["id"];
   
   if (this.cinecast_version) {   
       annotation.begin = Math.round(this._Popcorn.currentTime() * 1000);
       annotation.end = annotation.begin;      
   } else {
-    var duration = this._serializer.getDuration();    
+    var duration = this.getDuration();    
     annotation.begin = +((duration * (this.sliceLeft / 100)).toFixed(0));
     annotation.end = +((duration * ((this.sliceWidth + this.sliceLeft) / 100)).toFixed(0));
   }
 
   // boundary checks
   annotation.begin = Math.max(0, annotation.begin);
-  annotation.end = Math.min(this._serializer.getDuration(), annotation.end);
+  annotation.end = Math.min(this.getDuration(), annotation.end);
   
   annotation.type = ( this.cinecast_version ? "cinecast:UserAnnotation" : ( this._serializer.getContributions() || "" ));
   if (typeof(annotation.type) === "undefined")
@@ -3665,8 +3689,27 @@
   
   meta.created = Date().toString();
   
-  // All #hashtags are added to tags
-  annotation.tags = contents.match(/#[^#\s]+\b/gim) || [];
+  var _tags = [];
+  IriSP._(this.tags).each(function(_v) {
+      var _rx = IriSP.regexpFromText(_v.meta.description);
+        if (_rx.test(contents)) {
+            _tags.push(_v.id);
+        }
+  });
+
+  if (typeof this.remote_tags == "object") {
+     _tags = IriSP._(_tags).map(function(_t) {
+         return _this.remote_tags.id + ':' + _t
+     });
+    if (typeof apiJson.imports == "undefined") {
+       apiJson.imports = [];
+    }
+    apiJson.imports.push({
+        "id" : this.remote_tags.id,
+        "url" : this.remote_tags.url
+    })
+  }
+  annotation.tags = IriSP.underscore.uniq(_tags);
   
   var jsonString = JSON.stringify(apiJson);
   var project_id = this._serializer._data.meta.id;
@@ -3683,9 +3726,9 @@
       //dataType: 'json',
       success: IriSP.wrap(this, function(json, textStatus, XMLHttpRequest) {                   
                     /* add the annotation to the annotation and tell the world */
-                    if (this.cinecast_version) {
-                        var annotation = json.annotations[0];
-                    } else {
+                    var annotation = json.annotations[0];
+                    
+                    if (!this.cinecast_version) {
                     /* if the media doesn't have a contributions line, we need to add one */
                         if (typeof(this._serializer.getContributions()) === "undefined") {
                           /* set up a basic view */
@@ -3704,12 +3747,19 @@
     
                         annotation.meta = meta;
                         annotation.meta["id-ref"] = json.annotations[0]["type"];
+                    } else {
+                        annotation.type = "cinecast:UserAnnotation";
                     }
-                        
                     // everything is shared so there's no need to propagate the change
-                    _this._serializer._data.annotations.push(annotation);
- 
+                    var _an_ids = IriSP.underscore(this._serializer._data.annotations).map(function(_a) {
+                        return _a.id.toLowerCase();
+                    });
+                    if (_an_ids.indexOf(annotation.id.toLowerCase()) == -1) {
+                        _this._serializer._data.annotations.push(annotation);
+                    }
+                    
                     _this._Popcorn.trigger("IriSP.createAnnotationWidget.addedAnnotation", annotation);
+                    this.selector.find(".Ldt-createAnnotation-Description").val("").trigger("js_mod");
                     callback(annotation);
       }), 
       error: 
@@ -3863,7 +3913,7 @@
   }
   
   // we get it at each call because it may change.
-  var duration = this._serializer.getDuration() / 1000; 
+  var duration = this.getDuration() / 1000; 
   var totalTime = IriSP.secondsToTime(duration);
   var elapsedTime = IriSP.secondsToTime(this._Popcorn.currentTime());
   
@@ -4071,7 +4121,7 @@
     var lineSize      = this.width;        // timeline pixel width 
     var nbrframes     = lineSize/frameSize;     // frame numbers
     var numberOfTweet   = 0;            // number of tweet overide later 
-    var duration      = this._serializer.getDuration();      // timescale width 
+    var duration      = this.getDuration();      // timescale width 
     var frameLength   = lineSize / frameSize;    // frame timescale  
     var timeline;
     var colors  = new Array("","#1D973D","#036AAE","#CE0A15","#C5A62D","#585858");
@@ -4405,7 +4455,7 @@
 IriSP.PolemicWidget.prototype.sliderUpdater = function() {
 
     var time = +this._Popcorn.currentTime();
-    var duration = this._serializer.getDuration();
+    var duration = this.getDuration();
     
     this.paperSlider.attr("width", time * (this.width / (duration / 1000)));
         
@@ -4477,7 +4527,6 @@
   this._Popcorn.listen("IriSP.search.closed", function() { self.searchFieldClosedHandler.call(self); });
   this._Popcorn.listen("IriSP.search.cleared", function() { self.searchFieldClearedHandler.call(self); });
   
-  this.checkOption("cinecast_version");
   this.defaultColors = ["#1f77b4","#aec7e8","#ff7f0e","#ffbb78","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5","#8c564b","#c49c94","#e377c2","#f7b6d2","#7f7f7f","#c7c7c7","#bcbd22","#dbdb8d","#17becf","#9edae5"]
 };
 
@@ -4494,7 +4543,7 @@
   this.positionMarker = this.selector.find(".Ldt-SegmentPositionMarker");
   
   this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.positionUpdater));
-  var duration = this._serializer.getDuration();
+  var duration = this.getDuration();
   
   if (this.cinecast_version) {
       var segments_annotations = IriSP.underscore.filter(
@@ -4661,7 +4710,7 @@
 };
 
 IriSP.SegmentsWidget.prototype.positionUpdater = function() {  
-  var duration = this._serializer.getDuration() / 1000;
+  var duration = this.getDuration() / 1000;
   var time = this._Popcorn.currentTime();
   //var position 	= ((time / duration) * 100).toFixed(2);
   var position 	= ((time / duration) * 100).toFixed(2);
@@ -4888,7 +4937,7 @@
   
   var time = this._Popcorn.currentTime();
 
-  var duration = this._serializer.getDuration() / 1000;
+  var duration = this.getDuration() / 1000;
   var percents = time / duration;
   
   /* we do these complicated calculations to center exactly
@@ -4928,7 +4977,7 @@
   var width = this.sliderBackground.width();
   var relX = event.pageX - parentOffset.left;
 
-  var duration = this._serializer.getDuration() / 1000;
+  var duration = this.getDuration() / 1000;
   var newTime = ((relX / width) * duration).toFixed(2);
 
   this._Popcorn.currentTime(newTime);
@@ -4941,7 +4990,7 @@
   var width = this.sliderBackground.width();
   var relX = event.pageX - parentOffset.left;
 
-  var duration = this._serializer.getDuration() / 1000;
+  var duration = this.getDuration() / 1000;
   var newTime = ((relX / width) * duration).toFixed(2);
 
   this._Popcorn.currentTime(newTime);
@@ -4969,7 +5018,7 @@
 IriSP.SliderWidget.prototype.mouseOutHandler = function(event) {
 
   this.timeOutId = window.setTimeout(IriSP.wrap(this, this.minimizeOnTimeout),
-                                     IriSP.widgetsDefaults.SliderWidget.minimize_period);
+                                     this.minimize_period);
 };
 
 IriSP.SliderWidget.prototype.minimizeOnTimeout = function(event) {
@@ -4998,7 +5047,7 @@
   var width = this.sliderBackground.width();
   var relX = event.originalEvent.pageX - parentOffset.left;
 
-  var duration = this._serializer.getDuration() / 1000;
+  var duration = this.getDuration() / 1000;
   var newTime = ((relX / width) * duration).toFixed(2);
   this._Popcorn.currentTime(newTime);
   
@@ -5012,9 +5061,6 @@
   this._oldAnnotation = null;
   this._results = [];
   
-  this.lineColor = this._config.lineColor || "#7492b4";
-  this.fillColor = this._config.fillColor || "#aeaeb8";
-  this.lineWidth = this._config.lineWidth || 2;
   this.slices = this._config.slices || Math.floor(this.width/20);
   if (!this.width) {
       this.width = this.selector.width();
@@ -5026,7 +5072,6 @@
   if (this._config.background) {
       this.selector.css("background", this._config.background);
   }
-  this.checkOption('cinecast_version');
 };
 
 
@@ -5038,7 +5083,7 @@
 
 /** draw the sparkline using jquery sparkline */
 IriSP.SparklineWidget.prototype.draw = function() {
-    this.duration = this._serializer.getDuration();
+    this.duration = this.getDuration();
     this.paper = new Raphael(this.selector[0], this.width, this.height);
     var _this = this;
   
@@ -5061,11 +5106,16 @@
         //console.log("sparklinewidget : using stats embedded in the json");
         var _results = stat_view.meta.stat.split(",");      
     } else {
-        var _annotations = this._serializer._data.annotations,
-            _sliceDuration = Math.floor( this.duration / this.slices),
+        var _annotations = this._serializer._data.annotations;
+        if (this.cinecast_version) {
+            _annotations = _(_annotations).filter(function(_a) {
+                return _a.type !== "cinecast:MovieExtract";
+            });
+        }
+        var _sliceDuration = Math.floor( this.duration / this.slices),
             _results = _(_.range(this.slices)).map(function(_i) {
                 return _(_annotations).filter(function(_a){
-                    return (_a.begin <= (1 + _i) * _sliceDuration) && (_a.end >= _i * _sliceDuration) && (!_this.cinecast_version || _a.type == "cinecast:UserAnnotation")
+                    return (_a.begin <= (1 + _i) * _sliceDuration) && (_a.end >= _i * _sliceDuration)
                 }).length;
             });
     }
@@ -5158,53 +5208,23 @@
 IriSP.StackGraphWidget.prototype = new IriSP.Widget();
 
 IriSP.StackGraphWidget.prototype.draw = function() {
-    var _ = IriSP._,
-        _defaultTags = [
-            {
-                "keywords" : [ "++" ],
-                "description" : "positif",
-                "color" : "#1D973D"
-            },
-            {
-                "keywords" : [ "--" ],
-                "description" : "negatif",
-                "color" : "#CE0A15"
-            },
-            {
-                "keywords" : [ "==" ],
-                "description" : "reference",
-                "color" : "#C5A62D"  
-            },
-            {
-                "keywords" : [ "??" ],
-                "description" : "question",
-                "color" : "#036AAE"
-            }
-        ],
-        _defaultDefColor = "#585858";
+    var _ = IriSP._;
     this.height =  this._config.height || 50;
     this.width = this.selector.width();
-    this.isStreamGraph = this._config.streamgraph || false;
-    this.sliceCount = this._config.slices || ~~(this.width/(this.isStreamGraph ? 20 : 5));
-    this.tagconf = (this._config.tags
-        ? this._config.tags
-        : _defaultTags);
-    IriSP._(this.tagconf).each(function(_a) {
+    this.slices = this._config.slices || ~~(this.width/(this.streamgraph ? 20 : 5));
+    _(this.tags).each(function(_a) {
         _a.regexp = new RegExp(_(_a.keywords).map(function(_k) {
             return _k.replace(/([\W])/gm,'\\$1');
         }).join("|"),"im")
     });
-    this.defaultcolorconf = (this._config.defaultcolor
-        ? this._config.defaultcolor
-        : _defaultDefColor);
     this.paper = new Raphael(this.selector[0], this.width, this.height);
     this.groups = [];
-    this.duration = this._serializer.getDuration();
+    this.duration = this.getDuration();
     
     var _annotationType = this._serializer.getTweets(),
-        _sliceDuration = ~~ ( this.duration / this.sliceCount),
+        _sliceDuration = ~~ ( this.duration / this.slices),
         _annotations = this._serializer._data.annotations,
-        _groupedAnnotations = _(_.range(this.sliceCount)).map(function(_i) {
+        _groupedAnnotations = _(_.range(this.slices)).map(function(_i) {
             return _(_annotations).filter(function(_a){
                 return (_a.begin <= (1 + _i) * _sliceDuration) && (_a.end >= _i * _sliceDuration)
             });
@@ -5213,25 +5233,25 @@
             return _g.length
         }).length,
         _scale = this.height / _max,
-        _width = this.width / this.sliceCount,
+        _width = this.width / this.slices,
         _showTitle = !this._config.excludeTitle,
         _showDescription = !this._config.excludeDescription;
     
     
-    var _paths = _(this.tagconf).map(function() {
+    var _paths = _(this.tags).map(function() {
         return [];
     });
     _paths.push([]);
     
-    for (var i = 0; i < this.sliceCount; i++) {
+    for (var i = 0; i < this.slices; i++) {
         var _group = _groupedAnnotations[i];
         if (_group) {
-            var _vol = _(this.tagconf).map(function() {
+            var _vol = _(this.tags).map(function() {
                 return 0;
             });
             for (var j = 0; j < _group.length; j++){
            var _txt = (_showTitle ? _group[j].content.title : '') + ' ' + (_showDescription ? _group[j].content.description : '')
-                var _tags = _(this.tagconf).map(function(_tag) {
+                var _tags = _(this.tags).map(function(_tag) {
                         return (_txt.search(_tag.regexp) == -1 ? 0 : 1)
                     }),
                     _nbtags = _(_tags).reduce(function(_a,_b) {
@@ -5249,20 +5269,20 @@
                 _nbneutre = _group.length - _nbtags,
                 _h = _nbneutre * _scale,
                 _base = this.height - _h;
-            if (!this.isStreamGraph) {
+            if (!this.streamgraph) {
                 this.paper.rect(i * _width, _base, _width - 1, _h ).attr({
                     "stroke" : "none",
-                    "fill" : this.defaultcolorconf
+                    "fill" : this.defaultcolor
                 });
             }
            _paths[0].push(_base);
-            for (var j = 0; j < this.tagconf.length; j++) {
+            for (var j = 0; j < this.tags.length; j++) {
                 _h = _vol[j] * _scale;
                 _base = _base - _h;
-                if (!this.isStreamGraph) {
+                if (!this.streamgraph) {
                     this.paper.rect(i * _width, _base, _width - 1, _h ).attr({
                         "stroke" : "none",
-                        "fill" : this.tagconf[j].color
+                        "fill" : this.tags[j].color
                     });
                 }
                 _paths[j+1].push(_base);
@@ -5274,13 +5294,13 @@
             for (var j = 0; j < _paths.length; j++) {
                 _paths[j].push(this.height);
             }
-            this.groups.push(_(this.tagconf).map(function() {
+            this.groups.push(_(this.tags).map(function() {
                 return 0;
             }));
         }
     }
     
-    if (this.isStreamGraph) {
+    if (this.streamgraph) {
         for (var j = _paths.length - 1; j >= 0; j--) {
             var _d = _(_paths[j]).reduce(function(_memo, _v, _k) {
                return _memo + ( _k
@@ -5289,7 +5309,7 @@
             },'') + 'L' + this.width + ' ' + _paths[j][_paths[j].length - 1] + 'L' + this.width + ' ' + this.height + 'L0 ' + this.height;
             this.paper.path(_d).attr({
                 "stroke" : "none",
-                "fill" : (j ? this.tagconf[j-1].color : this.defaultcolorconf)
+                "fill" : (j ? this.tags[j-1].color : this.defaultcolor)
             });
         }
     }
@@ -5315,7 +5335,7 @@
             _this.updateTooltip(_e);
             // Trace
             var relX = _e.pageX - _this.selector.offset().left;
-            var _duration = _this._serializer.getDuration();
+            var _duration = _this.getDuration();
             var _time = parseInt((relX / _this.width) * _duration);
             _this._Popcorn.trigger("IriSP.TraceWidget.MouseEvents", {
                 "widget" : "StackGraphWidget",
@@ -5356,10 +5376,10 @@
 };
 
 IriSP.StackGraphWidget.prototype.updateTooltip = function(event) {
-    var _segment = Math.max(0,Math.min(this.groups.length - 1, Math.floor(this.sliceCount * (event.pageX - this.selector.offset().left)/this.width))),
+    var _segment = Math.max(0,Math.min(this.groups.length - 1, Math.floor(this.slices * (event.pageX - this.selector.offset().left)/this.width))),
         _valeurs = this.groups[_segment],
-        _width = this.width / this.sliceCount,
-        _html = '<ul style="list-style: none; margin: 0; padding: 0;">' + IriSP._(this.tagconf).map(function(_tag, _i) {
+        _width = this.width / this.slices,
+        _html = '<ul style="list-style: none; margin: 0; padding: 0;">' + IriSP._(this.tags).map(function(_tag, _i) {
             return '<li style="clear: both;"><span style="float: left; width: 10px; height: 10px; margin: 2px; background: '
                 + _tag.color
                 + ';"></span>'
@@ -5369,7 +5389,7 @@
                 + '</li>';
         }).join('') + '</ul>';
     this.TooltipWidget._shown = false; // Vraiment, on ne peut pas ouvrir le widget s'il n'est pas encore ouvert ?
-    this.TooltipWidget.show('','',(_segment + .5)* this.width / this.sliceCount, 0);
+    this.TooltipWidget.show('','',(_segment + .5)* this.width / this.slices, 0);
     this.TooltipWidget.selector.find(".tip").html(_html);
     this.rectangleFocus.attr({
         "x" : _segment * _width,
@@ -5658,8 +5678,9 @@
     }
     this.lastEvent = _traceName;
     this.tracer.trace(_traceName, _arg);
-    console.log("trace('" + _traceName + "', " + JSON.stringify(_arg) + ");");
-    
+    if (this._config.js_console) {
+        console.log("tracer.trace('" + _traceName + "', " + JSON.stringify(_arg) + ");");
+    }
 }
 /* a widget that displays tweet - used in conjunction with the polemicWidget */
 
@@ -5682,7 +5703,7 @@
     var title = IriSP.formatTweet(annotation.content.title);
     var img = annotation.content.img.src;
     if (typeof(img) === "undefined" || img === "" || img === "None") {
-      img = IriSP.widgetsDefaults.TweetsWidget.default_profile_picture;
+      img = this.default_profile_picture;
     }
 
     var imageMarkup = IriSP.templToHTML("<img src='{{src}}' alt='user image'></img>", 
@@ -5726,7 +5747,7 @@
   this.drawTweet(annotation);
 
   var time = this._Popcorn.currentTime();  
-  this._timeoutId = window.setTimeout(IriSP.wrap(this, this.clearPanel), IriSP.widgetsDefaults.TweetsWidget.tweet_display_period);
+  this._timeoutId = window.setTimeout(IriSP.wrap(this, this.clearPanel), this.tweet_display_period);
 };
 
 
@@ -5825,7 +5846,7 @@
 /** load JSON-cinelab data and also sort the annotations by start time
     @param callback function to call when the data is ready.
  */
-IriSP.JSONSerializer.prototype.sync = function(callback) {
+IriSP.JSONSerializer.prototype.sync = function(callback, force_refresh) {
   /* we don't have to do much because jQuery handles json for us */
 
   var self = this;
@@ -5847,14 +5868,22 @@
 	  }     
       callback(data);      
   };
-  
-  this._DataLoader.get(this._url, fn);
+  this._DataLoader.get(this._url, fn, force_refresh);
 };
 
 /** @return the metadata about the media being read FIXME: always return the first media. */
 IriSP.JSONSerializer.prototype.currentMedia = function() {  
-  return this._data.medias[0]; /* FIXME: don't hardcode it */
-};
+  return (typeof this._data.medias == "object" && this._data.medias.length) ? this._data.medias[0] : IriSP.__jsonMetadata.medias[0];
+};
+
+IriSP.JSONSerializer.prototype.getDuration = function() {
+    var _m = this.currentMedia();
+    if (_m === null || typeof _m.meta == "undefined") {
+        return 0;
+    }
+    return +(IriSP.get_aliased(_m.meta, ["dc:duration", "duration"]) || 0);
+}
+
 
 /** searches for an annotation which matches title, description and keyword 
    "" matches any field. 
@@ -6236,8 +6265,4 @@
     val = this.getId("Publ");
     
   return val;
-};
-
-IriSP.JSONSerializer.prototype.getDuration = function() {
-    return +(IriSP.get_aliased(this.currentMedia().meta, ["dc:duration", "duration"]) || 0);
-}
+};
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/res/js/tracemanager.js	Thu Apr 12 17:24:24 2012 +0200
@@ -0,0 +1,512 @@
+/*
+ * Modelled Trace API
+ */
+IriSP.TraceManager = function($) {
+     // If there are more than MAX_FAILURE_COUNT synchronisation
+     // failures, then disable synchronisation
+     MAX_FAILURE_COUNT = 20;
+
+     // If there are more than MAX_BUFFER_SIZE obsels in the buffer,
+     // then "compress" them as a single "ktbsFullBuffer"
+     MAX_BUFFER_SIZE = 500;
+
+     var BufferedService_prototype = {
+         /*
+          *  Buffered service for traces
+          */
+         // url: "",
+         // buffer: [],
+         // isReady: false,
+         // timer: null,
+         // failureCount: 0,
+
+         /* Flush buffer */
+         flush: function() {
+             // FIXME: add mutex on this.buffer
+             if (! this.isReady)
+             {
+                 if (window.console) window.console.log("Sync service not ready");
+             } else if (this.failureCount > MAX_FAILURE_COUNT)
+             {
+                 // Disable synchronisation
+                 this.set_sync_mode('none');
+             } else if (this.buffer.length) {
+                 var temp = this.buffer;
+                 this.buffer = [];
+
+                 if (this.mode == 'GET')
+                 {
+                     // GET mode: do some data mangline. We mark the
+                     // "compressed" nature of the generated JSON by
+                     // prefixing it with c
+                     var data = 'c' + JSON.stringify(temp.map(function (o) { return o.toCompactJSON(); }));
+                     // Swap " (very frequent, which will be
+                     // serialized into %22) and ; (rather rare), this
+                     // saves some bytes
+                     data = data.replace(/[;"]/g, function(s){ return s == ';' ? '"' : ';'; }).replace(/#/g, '%23');
+                     // FIXME: check data length (< 2K is safe)
+                     var request=$('<img />').error( function() { this.failureCount += 1; })
+                         .load( function() { this.failureCount = 0; })
+                         .attr('src', this.url + 'trace/?data=' + data);
+                 }
+                 else
+                 {
+                     $.ajax({ url: this.url + 'trace/',
+                              type: 'POST',
+                              contentType: 'application/json',
+                              data: JSON.stringify(temp.map(function (o) { return o.toJSON(); })),
+                              processData: false,
+                              // Type of the returned data.
+                              dataType: "html",
+                              error: function(jqXHR, textStatus, errorThrown) {
+                                  if (window.console) window.console.log("Error when sending buffer:", textStatus);
+                                  this.failureCount += 1;
+                              },
+                              success: function(data, textStatus, jqXHR) {
+                                  // Reset failureCount to 0 as soon as there is 1 valid answer
+                                  this.failureCount = 0;
+                              }
+                            });
+                 }
+             }
+         },
+
+         /* Sync mode: delayed, sync (immediate sync), none (no
+          * synchronisation with server, the trace has to be explicitly saved
+          * if needed */
+         set_sync_mode: function(mode) {
+             this.sync_mode = mode;
+             if (! this.isReady && mode !== "none")
+                 this.init();
+             if (mode == 'delayed') {
+                 this.start_timer();
+             } else {
+                 this.stop_timer();
+             }
+         },
+
+         /* Enqueue an obsel */
+         enqueue: function(obsel) {
+             if (this.buffer.length > MAX_BUFFER_SIZE)
+             {
+                 obsel = new Obsel('ktbsFullBuffer', this.buffer[0].begin,
+                                   this.buffer[this.buffer.length - 1].end, this.buffer[0].subject);
+                 obsel.trace = this.buffer[0].trace;
+                 this.buffer = [];
+             }
+             this.buffer.push(obsel);
+             if (this.sync_mode === 'sync') {
+                 // Immediate sync of the obsel.
+                 this.flush();
+             }
+         },
+
+         start_timer: function() {
+             var self = this;
+             if (this.timer === null) {
+                 this.timer = window.setInterval(function() {
+                                                     self.flush();
+                                                 }, this.timeOut);
+             }
+         },
+
+         stop_timer: function() {
+             if (this.timer !== null) {
+                 window.clearInterval(this.timer);
+                 this.timer = null;
+             }
+         },
+
+         /*
+          * Initialize the sync service
+          */
+         init: function() {
+             var self = this;
+             if (this.isReady)
+                 /* Already initialized */
+                 return;
+             if (this.mode == 'GET')
+             {
+                 var request=$('<img/>').attr('src', this.url + 'login?userinfo={"name":"ktbs4js"}');
+                 // Do not wait for the return, assume it is
+                 // initialized. This assumption will not work anymore
+                 // if login returns some necessary information
+                 this.isReady = true;
+             }
+             else
+             {
+                 $.ajax({ url: this.url + 'login',
+                          type: 'POST',
+                          data: 'userinfo={"name":"ktbs4js"}',
+                          success: function(data, textStatus, jqXHR) {
+                              self.isReady = true;
+                              if (self.buffer.length) {
+                                  self.flush();
+                              }
+                          }
+                        });
+             }
+         }
+     };
+     var BufferedService = function(url, mode) {
+         this.url = url;
+         this.buffer = [];
+         this.isReady = false;
+         this.timer = null;
+         this.failureCount = 0;
+         // sync_mode is either "none", "sync" or "buffered"
+         this.sync_mode = "none";
+         /* mode can be either POST or GET */
+         if (mode == 'POST' || mode == 'GET')
+             this.mode = mode;
+         else
+             this.mode = 'POST';
+         /* Flush buffer every timeOut ms if the sync_mode is delayed */
+         this.timeOut = 2000;
+     };
+     BufferedService.prototype = BufferedService_prototype;
+
+     var Trace_prototype = {
+         /* FIXME: We could/should use a sorted list such as
+          http://closure-library.googlecode.com/svn/docs/class_goog_structs_AvlTree.html
+          to speed up queries based on time */
+         obsels: [],
+         /* Trace URI */
+         uri: "",
+         default_subject: "",
+         /* baseuri is used as the base URI to resolve relative
+          * attribute-type names in obsels. Strictly speaking, this
+          * should rather be expressed as a reference to model, or
+          * more generically, as a qname/URI dict */
+         baseuri: "",
+         /* Mapping of obsel type or property name to a compact
+          * representation (shorthands).
+          */
+         shorthands: null,
+         syncservice: null,
+
+         /* Define the trace URI */
+         set_uri: function(uri) {
+             this.uri = uri;
+         },
+
+         /* Sync mode: delayed, sync (immediate sync), none (no
+          * synchronisation with server, the trace has to be explicitly saved
+          * if needed */
+         set_sync_mode: function(mode) {
+             if (this.syncservice !== null) {
+                 this.syncservice.set_sync_mode(mode);
+             }
+         },
+
+         /*
+          * Return a list of the obsels of this trace matching the parameters
+          */
+         list_obsels: function(_begin, _end, _reverse) {
+             var res;
+             if (typeof _begin !== 'undefined' || typeof _end !== 'undefined') {
+                 /*
+                  * Not optimized yet.
+                  */
+                 res = [];
+                 var l = this.obsels.length;
+                 for (var i = 0; i < l; i++) {
+                     var o = this.obsels[i];
+                     if ((typeof _begin !== 'undefined' && o.begin > _begin) && (typeof _end !== 'undefined' && o.end < _end)) {
+                         res.push(o);
+                     }
+                 }
+             }
+
+             if (typeof _reverse !== 'undefined') {
+                 if (res !== undefined) {
+                     /* Should reverse the whole list. Make a copy. */
+                     res = this.obsels.slice(0);
+                 }
+                 res.sort(function(a, b) { return b.begin - a.begin; });
+                 return res;
+             }
+
+             if (res === undefined) {
+                 res = this.obsels;
+             }
+             return res;
+
+         },
+
+         /*
+          * Return the obsel of this trace identified by the URI, or undefined
+          */
+         get_obsel: function(id) {
+             for (var i = 0; i < this.obsels.length; i++) {
+                 /* FIXME: should check against variations of id/uri, take this.baseuri into account */
+                 if (this.obsels[i].uri === id) {
+                     return this.obsels[i];
+                 }
+             }
+             return undefined;
+         },
+
+         set_default_subject: function(subject) {
+             this.default_subject = subject;
+         },
+
+         get_default_subject: function() {
+             return this.default_subject;
+         },
+
+         /* (type:ObselType, begin:int, end:int?, subject:str?, attributes:[AttributeType=>any]?) */
+         /* Create a new obsel and add it to the trace */
+         create_obsel: function(type, begin, end, subject, _attributes) {
+             var o = new Obsel(type, begin, end, subject);
+             if (typeof _attributes !== 'undefined') {
+                 o.attributes = _attributes;
+             }
+             o.trace = this;
+             this.obsels.push(o);
+             if (this.syncservice !== null)
+                 this.syncservice.enqueue(o);
+         },
+
+         /* Helper methods */
+
+         /* Create a new obsel with the given attributes */
+         trace: function(type, _attributes, _begin, _end, _subject) {
+             var t = (new Date()).getTime();
+             if (typeof begin === 'undefined') {
+                 _begin = t;
+             }
+             if (typeof end === 'undefined') {
+                 _end = _begin;
+             }
+             if (typeof subject === 'undefined') {
+                 _subject = this.default_subject;
+             }
+             if (typeof _attributes === 'undefined') {
+                 _attributes = {};
+             }
+             return this.create_obsel(type, _begin, _end, _subject, _attributes);
+         }
+     };
+
+     var Trace = function(uri, requestmode) {
+         /* FIXME: We could/should use a sorted list such as
+          http://closure-library.googlecode.com/svn/docs/class_goog_structs_AvlTree.html
+          to speed up queries based on time */
+         this.obsels = [];
+         /* Trace URI */
+         if (uri === undefined)
+             uri = "";
+         this.uri = uri;
+         this.sync_mode = "none";
+         this.default_subject = "";
+         this.shorthands = {};
+         /* baseuri is used a the base URI to resolve relative attribute names in obsels */
+         this.baseuri = "";
+
+         this.syncservice = new BufferedService(uri, requestmode);
+         $(window).unload( function () {
+                               if (this.syncservice && this.sync_mode !== 'none') {
+                                   this.syncservice.flush();
+                                   this.syncservice.stop_timer();
+                               }
+                           });
+     };
+     Trace.prototype = Trace_prototype;
+
+     var Obsel_prototype = {
+         /* The following attributes are here for documentation
+          * purposes. They MUST be defined in the constructor
+          * function. */
+         trace: undefined,
+         type: undefined,
+         begin: undefined,
+         end: undefined,
+         subject: undefined,
+         /* Dictionary indexed by ObselType URIs */
+         attributes: {},
+
+         /* Method definitions */
+         get_trace: function() {
+             return this.trace;
+         },
+
+         get_obsel_type: function() {
+             return this.type;
+         },
+         get_begin: function() {
+             return this.begin;
+         },
+         get_end: function() {
+             return this.end;
+         },
+         get_subject: function() {
+             return this.subject;
+         },
+
+         list_attribute_types: function() {
+             var result = [];
+             for (var prop in this.attributes) {
+                 if (this.hasOwnProperty(prop))
+                     result.push(prop);
+             }
+             /* FIXME: we return URIs here instead of AttributeType elements */
+             return result;
+         },
+
+         list_relation_types: function() {
+             /* FIXME: not implemented yet */
+         },
+
+         list_related_obsels: function (rt) {
+             /* FIXME: not implemented yet */
+         },
+         list_inverse_relation_types: function () {
+             /* FIXME: not implemented yet */
+         },
+         list_relating_obsels: function (rt) {
+             /* FIXME: not implemented yet */
+         },
+         /*
+          * Return the value of the given attribute type for this obsel
+          */
+         get_attribute_value: function(at) {
+             if (typeof at === "string")
+                 /* It is a URI */
+                 return this.attributes[at];
+             else
+                 /* FIXME: check that at is instance of AttributeType */
+                 return this.attributes[at.uri];
+         },
+
+
+         /* obsel modification (trace amendment) */
+
+         set_attribute_value: function(at, value) {
+             if (typeof at === "string")
+                 /* It is a URI */
+                 this.attributes[at] = value;
+             /* FIXME: check that at is instance of AttributeType */
+             else
+                 this.attributes[at.uri] = value;
+         },
+
+         del_attribute_value: function(at) {
+             if (typeof at === "string")
+                 /* It is a URI */
+                 delete this.attributes[at];
+             /* FIXME: check that at is instance of AttributeType */
+             else
+                 delete this.attributes[at.uri];
+         },
+
+         add_related_obsel: function(rt, value) {
+             /* FIXME: not implemented yet */
+         },
+
+         del_related_obsel: function(rt, value) {
+             /* FIXME: not implemented yet */
+         },
+
+         /*
+          * Return a JSON representation of the obsel
+          */
+         toJSON: function() {
+             var r = {
+                 "@id": this.id,
+                 "@type": this.type,
+                 "begin": this.begin,
+                 "end": this.end,
+                 "subject": this.subject
+             };
+             for (var prop in this.attributes) {
+                 if (this.hasOwnProperty(prop))
+                     r[prop] = this.attributes[prop];
+             }
+             return r;
+         },
+
+         /*
+          * Return a compact JSON representation of the obsel.
+          * Use predefined + custom shorthands for types/properties
+          */
+         toCompactJSON: function() {
+             var r = {
+                 "@i": this.id,
+                 "@t": (this.trace.shorthands.hasOwnProperty(this.type) ? this.trace.shorthands[this.type] : this.type),
+                 "@b": this.begin,
+                 "@s": this.subject
+             };
+             // Store duration (to save some bytes) and only if it is non-null
+             if (this.begin !== this.end)
+                 r["@d"] = this.end - this.begin;
+
+             for (var prop in this.attributes) {
+                 if (this.hasOwnProperty(prop))
+                 {
+                     var v = this.attributes[prop];
+                     r[prop] = this.trace.shorthands.hasOwnProperty(v) ? this.trace.shorthands[v] : v;
+                 }
+             }
+             return r;
+         },
+
+         toJSONstring: function() {
+             return JSON.stringify(this.toJSON());
+         }
+     };
+
+     var Obsel = function(type, begin, end, subject, attributes) {
+         this.trace = undefined;
+         this.uri = "";
+         this.id = "";
+         this.type = type;
+         this.begin = begin;
+         this.end = end;
+         this.subject = subject;
+         /* Is the obsel synched with the server ? */
+         this.sync_status = false;
+         /* Dictionary indexed by ObselType URIs */
+         this.attributes = {};
+     };
+     Obsel.prototype = Obsel_prototype;
+
+     var TraceManager_prototype = {
+         traces: [],
+         /*
+          * Return the trace with id name
+          * If it was not registered, return undefined.
+          */
+         get_trace: function(name) {
+             return this.traces[name];
+         },
+
+         /*
+          * Explicitly create and initialize a new trace with the given name.
+          * The optional uri parameter allows to initialize the trace URI.
+          *
+          * If another existed with the same name before, then it is replaced by a new one.
+          */
+         init_trace: function(name, params)
+         {
+             if (window.console) window.console.log("init_trace", params);
+             url = params.url ? params.url : "";
+             requestmode = params.requestmode ? params.requestmode : "POST";
+             syncmode = params.syncmode ? params.syncmode : "none";
+             default_subject = params.default_subject ? params.default_subject : "default";
+             var t = new Trace(url, requestmode);
+             t.set_sync_mode(syncmode);
+             t.set_default_subject(default_subject);
+             this.traces[name] = t;
+             return t;
+         }
+     };
+
+     var TraceManager = function() {
+         this.traces = {};
+     };
+     TraceManager.prototype = TraceManager_prototype;
+
+     var tracemanager  = new TraceManager();
+     return tracemanager;
+ };