Modifs cinecast popcorn-port
authorveltr
Tue, 03 Apr 2012 20:30:12 +0200
branchpopcorn-port
changeset 841 8da49ff273e0
parent 840 ac66e2240e1e
child 842 4ae2247a59f4
Modifs cinecast
src/js/libs/tracemanager.js
src/js/players/player.allocine.js
src/js/pop.js
src/js/site.js.templ
src/js/widgets/annotationsListWidget.js
src/js/widgets/createAnnotationWidget.js
src/js/widgets/traceWidget.js
src/templates/createAnnotationWidget.html
test/integration/allocine_dossier_independant/allocine_test/AcPlayer_v3.0_new.swf
test/integration/allocine_dossier_independant/allocine_test/data_cinecast_new.xml
test/integration/allocine_dossier_independant/css/LdtPlayer.css
test/integration/allocine_dossier_independant/css/img-cinecast/createannbgd.png
test/integration/allocine_dossier_independant/css/img-cinecast/moar.png
test/integration/allocine_dossier_independant/css/img-cinecast/tag.png
test/integration/allocine_dossier_independant/js/LdtPlayer-release.js
test/integration/allocine_dossier_independant/js/libs/tracemanager.js
test/integration/allocine_dossier_independant/polemic-allocine.htm
--- a/src/js/libs/tracemanager.js	Fri Mar 30 18:00:26 2012 +0200
+++ b/src/js/libs/tracemanager.js	Tue Apr 03 20:30:12 2012 +0200
@@ -2,9 +2,13 @@
  * Modelled Trace API
  */
 IriSP.TraceManager = function($) {
-     /*
-      * FIXME: Write proper representation functions (str, json, ...)
-      */
+     // 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 = {
          /*
@@ -14,15 +18,18 @@
          // buffer: [],
          // isReady: false,
          // timer: null,
+         // failureCount: 0,
 
          /* Flush buffer */
          flush: function() {
-             // FIXME: should add a counter to avoid starving the sync
-             // process in case of too many generated obsels.
              // FIXME: add mutex on this.buffer
              if (! this.isReady)
              {
-                 console.log("Sync service not ready");
+                 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 = [];
@@ -34,11 +41,13 @@
                      // 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
+                     // serialized into %22) and ; (rather rare), this
                      // saves some bytes
-                     data = data.replace(/[\/"]/g, function(s){ return s == '/' ? '"' : '/'; }).replace('#','%23');
+                     data = data.replace(/[;"]/g, function(s){ return s == ';' ? '"' : ';'; }).replace(/#/g, '%23');
                      // FIXME: check data length (< 2K is safe)
-                     var request=$('<img/>').attr('src', this.url + 'trace/?data=' + data);
+                     var request=$('<img />').error( function() { this.failureCount += 1; })
+                         .load( function() { this.failureCount = 0; })
+                         .attr('src', this.url + 'trace/?data=' + data);
                  }
                  else
                  {
@@ -50,28 +59,52 @@
                               // Type of the returned data.
                               dataType: "html",
                               error: function(jqXHR, textStatus, errorThrown) {
-                                  // FIXME: not called for JSONP/crossdomain
-                                  console.log("Error when sending buffer:", textStatus);
+                                  if (window.console) window.console.log("Error when sending buffer:", textStatus);
+                                  this.failureCount += 1;
                               },
                               success: function(data, textStatus, jqXHR) {
-                                  // FIXME: parse the returned JSON, and get
-                                  // the updated properties (id, uri...) to apply them to temp items
+                                  // 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() {
-                                                     console.log("Flushing timeout");
                                                      self.flush();
                                                  }, this.timeOut);
              }
@@ -120,6 +153,9 @@
          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;
@@ -137,7 +173,6 @@
          obsels: [],
          /* Trace URI */
          uri: "",
-         sync_mode: "none",
          default_subject: "",
          /* baseuri is used as the base URI to resolve relative
           * attribute-type names in obsels. Strictly speaking, this
@@ -159,16 +194,8 @@
           * synchronisation with server, the trace has to be explicitly saved
           * if needed */
          set_sync_mode: function(mode) {
-             this.sync_mode = mode;
-             if (this.syncservice != null) {
-                 if (mode !== 'none') {
-                     this.syncservice.init();
-                 }
-                 if (mode == 'delayed') {
-                     this.syncservice.start_timer();
-                 } else {
-                     this.syncservice.stop_timer();
-                 }
+             if (this.syncservice !== null) {
+                 this.syncservice.set_sync_mode(mode);
              }
          },
 
@@ -237,38 +264,10 @@
              }
              o.trace = this;
              this.obsels.push(o);
-             if (this.syncservice !== null && this.sync_mode != 'none') {
+             if (this.syncservice !== null)
                  this.syncservice.enqueue(o);
-                 if (this.sync_mode === 'sync') {
-                     // Immediate sync of the obsel.
-                     this.syncservice.flush();
-                 }
-             }
          },
 
-	     obselProbe : function(element, bindingEvent, ObselFunction) {
-			console.log("!!!!!!!!- ICI -!!!!!!!!!");
-			console.log(element);
-			console.log(bindingEvent);
-			console.log(ObselFunction);
-
-	        //var myOPI = self.setInterval("ObselProbeInterval("+element+","+bindingEvent+","+ObselFunction+")",1000);
-			var myOPI = self.setInterval("ObselProbeInterval("+element+")",1000);
-			//var ObselProbeInterval = function(element, bindingEvent, ObselFunction){
-			var ObselProbeInterval = function(element) {
-				console.log("!!!!!!!!- ObselProbeInterval -!!!!!!!!!");
-				console.log($(element).length);
-				/*
-				if($(element).length!=0){
-					$(element).bind(bindingEvent, ObselFunction );
-					this.clearInterval();
-				}else{	console.log("!!!!!!!!- EXISTE PAS -!!!!!!!!!")
-				}
-				*/
-				//
-			};
-
-		 },
          /* Helper methods */
 
          /* Create a new obsel with the given attributes */
@@ -320,7 +319,6 @@
           * purposes. They MUST be defined in the constructor
           * function. */
          trace: undefined,
-		 obselProbe: undefined,
          type: undefined,
          begin: undefined,
          end: undefined,
@@ -334,7 +332,6 @@
          },
 
          get_obsel_type: function() {
-             /* FIXME: maybe we should return a ObselType object. In the meantime, return the URI */
              return this.type;
          },
          get_begin: function() {
@@ -350,7 +347,8 @@
          list_attribute_types: function() {
              var result = [];
              for (var prop in this.attributes) {
-                 result.push(prop);
+                 if (this.hasOwnProperty(prop))
+                     result.push(prop);
              }
              /* FIXME: we return URIs here instead of AttributeType elements */
              return result;
@@ -422,7 +420,8 @@
                  "subject": this.subject
              };
              for (var prop in this.attributes) {
-                 r[prop] = this.attributes[prop];
+                 if (this.hasOwnProperty(prop))
+                     r[prop] = this.attributes[prop];
              }
              return r;
          },
@@ -434,15 +433,20 @@
          toCompactJSON: function() {
              var r = {
                  "@i": this.id,
-                 "@t": (this.trace.shorthands.hasOwnProperty(this.type)
-                        ? this.trace.shorthands[this.type] : this.type),
+                 "@t": (this.trace.shorthands.hasOwnProperty(this.type) ? this.trace.shorthands[this.type] : this.type),
                  "@b": this.begin,
-                 "@e": this.end,
                  "@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) {
-                 var v = this.attributes[prop];
-                 r[prop] = this.trace.shorthands.hasOwnProperty(v) ? this.trace.shorthands[v] : v;
+                 if (this.hasOwnProperty(prop))
+                 {
+                     var v = this.attributes[prop];
+                     r[prop] = this.trace.shorthands.hasOwnProperty(v) ? this.trace.shorthands[v] : v;
+                 }
              }
              return r;
          },
@@ -485,12 +489,14 @@
           */
          init_trace: function(name, params)
          {
-             console.log("init_trace", 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;
          }
@@ -501,5 +507,6 @@
      };
      TraceManager.prototype = TraceManager_prototype;
 
-     return new TraceManager();
+     var tracemanager  = new TraceManager();
+     return tracemanager;
  };
--- a/src/js/players/player.allocine.js	Fri Mar 30 18:00:26 2012 +0200
+++ b/src/js/players/player.allocine.js	Tue Apr 03 20:30:12 2012 +0200
@@ -13,49 +13,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);
         }
     }
 
@@ -75,12 +48,13 @@
     var params = {
         "allowScriptAccess" : "always",
         "wmode": "opaque",
-        "flashvars" : fv
+        "flashvars" : fv,
+        "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);
 
 };
 
@@ -89,7 +63,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();
 };
@@ -101,6 +74,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) {
--- a/src/js/pop.js	Fri Mar 30 18:00:26 2012 +0200
+++ b/src/js/pop.js	Tue Apr 03 20:30:12 2012 +0200
@@ -116,11 +116,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) {
--- a/src/js/site.js.templ	Fri Mar 30 18:00:26 2012 +0200
+++ b/src/js/site.js.templ	Tue Apr 03 20:30:12 2012 +0200
@@ -114,7 +114,7 @@
            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_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 */
--- a/src/js/widgets/annotationsListWidget.js	Fri Mar 30 18:00:26 2012 +0200
+++ b/src/js/widgets/annotationsListWidget.js	Tue Apr 03 20:30:12 2012 +0200
@@ -7,6 +7,7 @@
   this.checkOption('project_url');
   this.checkOption('default_thumbnail');
   this.checkOption("cinecast_version", false);
+  this.checkOption("ajax_url");
   this.searchRe = null;
   this._ajax_cache = [];
   var _this = this;
@@ -73,7 +74,7 @@
 };
 
 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,
@@ -82,6 +83,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()
@@ -140,7 +142,6 @@
             this._Popcorn.trigger("IriSP.search.noMatchFound");
           }
     }
-  
   list = IriSP.underscore(list)
     .chain()
     .sortBy(function(_o) {
@@ -148,10 +149,9 @@
     })
     .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();
 
   
@@ -176,13 +176,11 @@
   }
    
   
-  /* 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();
   
@@ -194,7 +192,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 */
--- a/src/js/widgets/createAnnotationWidget.js	Fri Mar 30 18:00:26 2012 +0200
+++ b/src/js/widgets/createAnnotationWidget.js	Tue Apr 03 20:30:12 2012 +0200
@@ -13,7 +13,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",
+            "moar_tags": "More tags"
         },
         "fr": {
             "submit": "Envoyer",
@@ -26,7 +27,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",
+            "moar_tagz": "Plus de mots-clés"
         }
     }
 );
@@ -42,6 +44,8 @@
   this.checkOption("api_endpoint_template");
   this.checkOption("show_from_field", true);
   this.checkOption("api_method");
+  this.checkOption("random_keywords");
+  this.checkOption("disable_share", false);
                          
   if (!IriSP.null_or_undefined(IriSP.user)) {
       if (!IriSP.null_or_undefined(IriSP.user.avatar)) {
@@ -69,6 +73,20 @@
 };
 
 IriSP.createAnnotationWidget.prototype.draw = function() {
+    var _this = this;
+    if (typeof this._config.remote_keywords != "undefined" && typeof this._config.remote_keywords) {
+        IriSP.jQuery.getJSON(this._config.remote_keywords, function(_json) {
+            _this.keywords = IriSP.underscore(_json.tags).map(function(_tag) {
+                return _tag.meta.description;
+            });
+            _this.drawCallback();
+        });
+    } else {
+        this.drawCallback();
+    }
+}
+
+IriSP.createAnnotationWidget.prototype.drawCallback = function() {
   var _this = this;
   
   var annotationMarkup = IriSP.templToHTML(IriSP.createAnnotationWidget_template, 
@@ -81,17 +99,25 @@
   else {
     this.showStartScreen();
   }
-
+  
+  if (this.random_keywords) {
+      this.selector.find(".Ldt-createAnnotation-keywords li").hide();
+      this.showMoarTagz();
+      this.selector.find('.Ldt-createAnnotation-moar-keywordz').click(function() {
+          _this.showMoarTagz();
+      })
+  }
   // 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 */
 
@@ -152,6 +178,21 @@
   }
 };
 
+IriSP.createAnnotationWidget.prototype.showMoarTagz = function() {
+    for (var j=0; j < this.random_keywords; 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"),
@@ -161,7 +202,7 @@
         ? _contents.replace(_rx,"").replace("  "," ").trim()
         : _contents.trim() + " " + _keyword
     );
-    _field.val(_contents);
+    _field.val(_contents.trim());
     _field.trigger("js_mod");
 }
 
@@ -223,7 +264,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() {
@@ -398,7 +439,17 @@
   meta.created = Date().toString();
   
   // All #hashtags are added to tags
-  annotation.tags = contents.match(/#[^#\s]+\b/gim) || [];
+  var _tags = contents.toLowerCase().match(/#[^#\s]+\b/gim) || [];
+  this.selector.find('.Ldt-createAnnotation-keyword-button').each(function() {
+      var _tx = IriSP.jQuery(this).text(),
+        _rx = IriSP.regexpFromText(_tx);
+        if (_rx.test(contents)) {
+            _tags.push(_tx.toLowerCase())
+        }
+  });
+  
+  annotation.tags = IriSP.underscore.uniq(_tags);
+  
   
   var jsonString = JSON.stringify(apiJson);
   var project_id = this._serializer._data.meta.id;
@@ -436,8 +487,10 @@
     
                         annotation.meta = meta;
                         annotation.meta["id-ref"] = json.annotations[0]["type"];
+                    } else {
+                        annotation.type = "cinecast:UserAnnotation";
                     }
-                        
+                    annotation.is_new = true;
                     // everything is shared so there's no need to propagate the change
                     _this._serializer._data.annotations.push(annotation);
  
--- a/src/js/widgets/traceWidget.js	Fri Mar 30 18:00:26 2012 +0200
+++ b/src/js/widgets/traceWidget.js	Tue Apr 03 20:30:12 2012 +0200
@@ -127,6 +127,7 @@
     }
     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/src/templates/createAnnotationWidget.html	Fri Mar 30 18:00:26 2012 +0200
+++ b/src/templates/createAnnotationWidget.html	Tue Apr 03 20:30:12 2012 +0200
@@ -32,6 +32,9 @@
                 {{/keywords}}
                 </ul>
             </div>
+            {{#random_keywords}}
+                <button class='Ldt-createAnnotation-moar-keywordz'>{{l10n.moar_tagz}}</button>
+            {{/random_keywords}}
             {{/keywords.length}}
             {{#polemic_mode}}
             {{#polemics.length}}
@@ -58,12 +61,14 @@
             <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>
Binary file test/integration/allocine_dossier_independant/allocine_test/AcPlayer_v3.0_new.swf has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/integration/allocine_dossier_independant/allocine_test/data_cinecast_new.xml	Tue Apr 03 20:30:12 2012 +0200
@@ -0,0 +1,198 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<AcVision>
+    <AcVisionVideo refType="mediatheme"
+    ref="18644642"
+    refTitle="La Minute"
+    cmedia="19299288"
+    videoTitle="La Minute N°1033 - Mardi 17 janvier 2012"
+    mediaType="show"
+    genre=""
+    urlGen="/video/emissions/laminute/episode/?cmedia=19299288"
+    ld_path="http://b.fr.mediaplayer.allocine.fr/nmedia/18/64/46/42/19299288_minute_2012_01_17_l_001.flv"
+    md_path="http://h.fr.mediaplayer.allocine.fr/nmedia/18/64/46/42/19299288_minute_2012_01_17_m_001.flv"
+    hd_path="http://hd.fr.mediaplayer.allocine.fr/nmedia/18/64/46/42/19299288_minute_2012_01_17_sd_001.flv"
+    xt_title="19299288_la_minute_emission_allocinetv"
+    thumb=""
+    urlFiche="laminute_home"
+/>
+    <AcVisionVideoSlides>
+        <AcVisionVideoSlide title="La Minute N°1043 - Mardi 31 janvier 2012"
+        thumb="/c_100_80/medias/nmedia/18/64/46/42/19303868_minute_2012_01_31.jpg"
+        link="/video/emissions/laminute/episode/?cmedia=19303868" />
+        <AcVisionVideoSlide title="La Minute N°1042 - Lundi 30 janvier 2012"
+        thumb="/c_100_80/medias/nmedia/18/64/46/42/19303866_minute_2012_01_30.jpg"
+        link="/video/emissions/laminute/episode/?cmedia=19303866" />
+        <AcVisionVideoSlide title="La Minute N°1041 - Samedi 28 janvier 2012"
+        thumb="/c_100_80/medias/nmedia/18/64/46/42/19303864_minute_2012_01_28.jpg"
+        link="/video/emissions/laminute/episode/?cmedia=19303864" />
+        <AcVisionVideoSlide title="La Minute N°1040 - Jeudi 26 janvier 2012"
+        thumb="/c_100_80/medias/nmedia/18/64/46/42/19303192_minute_2012_01_26.jpg"
+        link="/video/emissions/laminute/episode/?cmedia=19303192" />
+        <AcVisionVideoSlide title="La Minute N°1039 - Mercredi 25 janvier 2012"
+        thumb="/c_100_80/medias/nmedia/18/64/46/42/19302927_minute_2012_01_25.jpg"
+        link="/video/emissions/laminute/episode/?cmedia=19302927" />
+        <AcVisionVideoSlide title="La Minute N°1038 - Mardi 24 janvier 2012"
+        thumb="/c_100_80/medias/nmedia/18/64/46/42/19300902_minute_2012_01_24.jpg"
+        link="/video/emissions/laminute/episode/?cmedia=19300902" />
+        <AcVisionVideoSlide title="La Minute N°1037 - Lundi 23 janvier 2012"
+        thumb="/c_100_80/medias/nmedia/18/64/46/42/19300590_minute_2012_01_23.jpg"
+        link="/video/emissions/laminute/episode/?cmedia=19300590" />
+        <AcVisionVideoSlide title="La Minute N°1036 - Vendredi 20 janvier 2012"
+        thumb="/c_100_80/medias/nmedia/18/64/46/42/19300162_minute_2012_01_20.jpg"
+        link="/video/emissions/laminute/episode/?cmedia=19300162" />
+        <AcVisionVideoSlide title="La Minute N°1035 - Jeudi 19 janvier 2012"
+        thumb="/c_100_80/medias/nmedia/18/64/46/42/19299668_minute_2012_01_19.jpg"
+        link="/video/emissions/laminute/episode/?cmedia=19299668" />
+        <AcVisionVideoSlide title="La Minute N°1034 - Mercredi 18 janvier 2012"
+        thumb="/c_100_80/medias/nmedia/18/64/46/42/19299358_minute_2012_01_18.jpg"
+        link="/video/emissions/laminute/episode/?cmedia=19299358" />
+        <AcVisionVideoSlide title="La Minute N°1032 - Lundi 16 janvier 2012"
+        thumb="/c_100_80/medias/nmedia/18/64/46/42/19298693_minute_2012_01_16.jpg"
+        link="/video/emissions/laminute/episode/?cmedia=19298693" />
+        <AcVisionVideoSlide title="La Minute N°1031 - Vendredi 13 janvier 2012"
+        thumb="/c_100_80/medias/nmedia/18/64/46/42/19298503_minute_2012_01_13.jpg"
+        link="/video/emissions/laminute/episode/?cmedia=19298503" />
+        <AcVisionVideoSlide title="La Minute N°1030 - Jeudi 12 janvier 2012"
+        thumb="/c_100_80/medias/nmedia/18/64/46/42/19298131_minute_2012_01_12.jpg"
+        link="/video/emissions/laminute/episode/?cmedia=19298131" />
+
+        <AcVisionVideoSlide title="La Minute N°1029 - Mercredi 11 janvier 2012"
+        thumb="/c_100_80/medias/nmedia/18/64/46/42/19296197_minute_2012_01_11.jpg"
+        link="/video/emissions/laminute/episode/?cmedia=19296197" />
+        <AcVisionVideoSlide title="La Minute N°1028 - Mardi 10 janvier 2012"
+        thumb="/c_100_80/medias/nmedia/18/64/46/42/19290943_minute_2012_01_10.jpg"
+        link="/video/emissions/laminute/episode/?cmedia=19290943" />
+    </AcVisionVideoSlides>
+    <!-- skinSource: update cinecast -->
+    <AcVisionSkin skinSource="allocine_test/skin_fr.swf">
+        <clip nameId="titleTopPostRoll">
+            <label>
+                <![CDATA[AlloCiné présente: | Cliquez ici pour en savoir plus]]>
+            </label>
+        </clip>
+        <clip nameId="mcAddPostRoll" layer1="McAddPostRoll" x="0" y="0">
+            <label>
+                <![CDATA[Vidéo suivante dans|secondes]]>
+            </label>
+        </clip>
+        <clip nameId="bgAddPostRoll" layer1="BgAddPostRoll" y="20"/>
+        <clip nameId="pixAddPostRoll" y="20"/>
+        <clip nameId="titleAddPostRoll" y="30" x="100"/>
+
+        <clip nameId="accountAddPostRoll" x="10" y="2"/>
+        <clip nameId="fondNavPlayer" layer1="FondNavPlayer" width="760" height="36"/>
+        <clip nameId="soundVolume" x="77" y="13" width="36" height="36" layer3="SoundVolumeLayer1" layer2="SoundVolumeLayer2" layer1="SoundVolumeLayer3">
+            <info>
+                <![CDATA[Modifier le volume de la vidéo]]>
+            </info>
+        </clip>
+        <clip nameId="cutSound" x="55" y="13" stateOn="BtCutSoundOn" stateOff="BtCutSoundOff" stateClickOff="BtCutSoundClickOff" stateClickOn="BtCutSoundClickOn">
+            <info>
+                <![CDATA[Couper le son de la vidéo]]>
+            </info>
+        </clip>
+        <clip nameId="puceTimeLine" stateOn="PuceTimeLineOn" stateOff="PuceTimeLineOff"/>
+        <clip nameId="btPlay" x="4" y="11" width="42" height="22" stateOn="BtPlayOn" stateOff="BtPlayOff"/>
+        <clip nameId="btPause" x="4" y="11" width="42" height="22" stateOn="BtPauseOn" stateOff="BtPauseOff"/>
+        <clip nameId="btReplay2" x="4" y="11" width="42" height="22" stateOn="BtReplay2On" stateOff="BtReplay2Off" />
+        <clip nameId="btBigPlay" stateOn="BtBigPlayOn" stateOff="BtBigPlayOff"/>
+
+        <clip nameId="btHd" x="553" y="11" stateOn="BtHdOn" stateOff="BtHdOff" stateClickOn="BtHdClickOn">
+            <info>
+                <![CDATA[Changer la qualité de la vidéo]]>
+            </info>
+        </clip>
+        <clip nameId="btMenu" x="626" y="11" stateOn="BtMenuOn" stateOff="BtMenuOff"/>
+        <clip nameId="btMarque" link="www.allocine.fr" linkTarget="_blank" x="688" y="16" stateOn="BtMarqueOn" stateOff="BtMarqueOff">
+            <info>
+                <![CDATA[Se rendre sur allocine.fr]]>
+            </info>
+        </clip>
+        <clip nameId="btFullScreen" x="593" y="11" stateOn="BtFullScreenOn" stateOff="BtFullScreenOff" stateClickOn="BtFullScreenClickOn" stateClickOff="BtFullScreenClickOff">
+            <info>
+                <![CDATA[Mettre la vidéo en plein écran]]>
+            </info>
+        </clip>
+        <clip nameId="textTimer" x="120" y="13" color="0x444444"/>
+
+        <clip nameId="menuSubtitle" x="330" y="-2" color="0x9ea6b8"/>
+        <clip nameId="menuFlow" x="230" y="-2" color="0x9ea6b8"/>
+        <clip nameId="textTitle" x="215" y="13" color="0x005ea8" />
+        <clip nameId="btClose" stateOn="BtCloseOn" stateOff="BtCloseOff"/>
+        <clip nameId="logo" layer1="Logo" x="0" y="5"/>
+        <clip nameId="timeLine" x="2" y="2" round="false" width="756" height="5" color1="0xD6D6D6" color2="0x898989" color3="0x005ea8"/>
+        <clip nameId="btSearch" x="507" y="12" width="103" height="32" stateOn="BtSearchOn" stateOff="BtSearchOff">
+            <label>
+                <![CDATA[<b>Recherche</b>]]>
+            </label>
+        </clip>
+        <clip nameId="searchEngine">
+            <label>
+                <![CDATA[/recherche/?q=|&x=73&y=14&rub=0]]>
+            </label>
+        </clip>
+        <clip nameId="btCopy" x="360" width="73" height="30" stateOn="BtCopyOn" stateOff="BtCopyOff">
+
+            <label>
+                <![CDATA[<b>Copier</b>]]>
+            </label>
+        </clip>
+        <clip nameId="mcShare">
+            <label>
+                <![CDATA[Permalien :]]>
+            </label>
+        </clip>
+        <clip nameId="mcBlog">
+            <label>
+                <![CDATA[Lecteur exportable :|allocine_blog]]>
+            </label>
+        </clip>
+        <clip nameId="btScrollRight" stateOn="BtScrollRightOn" stateOff="BtScrollRightOff"/>
+        <clip nameId="btScrollLeft" stateOn="BtScrollLeftOn" stateOff="BtScrollLeftOff"/>
+        <clip nameId="btReplay" type="navCenter" action="replayHandler" y="115" stateOn="BtReplayOn" stateOff="BtReplayOff">
+
+            <label>
+                <![CDATA[<b>REJOUER</b>]]>
+            </label>
+        </clip>
+        <clip nameId="btShare" type="navCenter" action="shareHandler" x="110" y="115" stateOn="BtShareOn" stateOff="BtShareOff">
+            <label>
+                <![CDATA[<b>PARTAGER</b>]]>
+            </label>
+        </clip>
+        <clip nameId="btBlog" type="navCenter" action="blogHandler" x="220 " y="115" stateOn="BtBlogOn" stateOff="BtBlogOff">
+            <label>
+                <![CDATA[<b>SUR MON BLOG</b>]]>
+            </label>
+        </clip>
+        <clip nameId="btVideoSim" type="navCenter" action="videoSimHandler" x="330" y="115" stateOn="BtVideoSimOn" stateOff="BtVideoSimOff">
+            <label>
+                <![CDATA[<b>VIDÉOS <br>SIMILAIRES</b>]]>
+
+            </label>
+        </clip>
+        <clip nameId="titleEndScreen" >
+            <label>
+                <![CDATA[<b>Choisissez votre prochaine vidéo </b>]]>
+            </label>
+        </clip>
+        <clip nameId="textError" >
+            <label>
+                <![CDATA[<b>Erreur : cette vidéo n'est pas disponible.</b>]]>
+            </label>
+        </clip>
+        <clip nameId="errorAdBlock" >
+            <label>
+                <![CDATA[Cette vidéo ne se lance pas ?<br>Vous avez probablement activé une extension comme AdBlock dans votre navigateur. Merci de la désactiver et de recharger la page afin de lire cette vidéo.<br>Si votre problème persiste, n’hésitez pas à <b><a href='http://allocine.uservoice.com/forums/30575-allocin-v6-probl-mes-et-erreurs'>nous contacter</a></b> !]]>
+            </label>
+        </clip>
+
+    </AcVisionSkin>
+    <services>
+        <!--service className="McXitiService" nameService="xiti" file="services/xitiService.swf" pathConfig="http://www.allocine.fr/Modules/video/xml/XiTiTag.xml" /-->
+        <service className="McVastService" nameService="vast" file="services/vastService.swf" pathConfig="http://smart.allocine.fr/call/pubx/10936/[part]/7292/S/[timestamp]/[target]" >
+            <![CDATA[<b>Publicité</b> : votre vidéo commence dans | secondes]]>
+        </service>
+        <!---->
+    </services>
+</AcVision>
\ No newline at end of file
--- a/test/integration/allocine_dossier_independant/css/LdtPlayer.css	Fri Mar 30 18:00:26 2012 +0200
+++ b/test/integration/allocine_dossier_independant/css/LdtPlayer.css	Tue Apr 03 20:30:12 2012 +0200
@@ -261,29 +261,67 @@
   margin: 4px 2px;
 }
 
-.Ldt-CtrlSound-SoundState {
+.Ldt-CtrlSound-Full {
   background-position: -120px 0;
 }
 
-.Ldt-CtrlSound-SoundState:hover {
+.Ldt-CtrlSound-Full:hover {
   background-position: -120px -25px;
 }
 
-.Ldt-CtrlSound-SoundState:active {
+.Ldt-CtrlSound-Full:active {
   background-position: -120px -50px;
 }
 
-.Ldt-CtrlSound-MuteState {
+.Ldt-CtrlSound-Mute {
   background-position: -150px 0;
 }
 
-.Ldt-CtrlSound-MuteState:hover {
+.Ldt-CtrlSound-Mute:hover {
   background-position: -150px -25px;
 }
 
-.Ldt-CtrlSound-MuteState:active {
+.Ldt-CtrlSound-Mute:active {
   background-position: -150px -50px;
 }
+
+.Ldt-CtrlSound-Half {
+  background-position: -180px 0;
+}
+
+.Ldt-CtrlSound-Half:hover {
+  background-position: -180px -25px;
+}
+
+.Ldt-CtrlSound-Half:active {
+  background-position: -180px -50px;
+}
+
+.Ldt-Ctrl-Volume-Control {
+  display: none;
+  position: absolute;
+  background:url('img-cinecast/controlbarbgd.png') repeat-x transparent ;
+  height: 34px;
+  width: 100px; top: 30px; right: 0; z-index: 100;
+  padding: 0 2px;
+}
+
+.Ldt-Ctrl-Volume-Bar { 
+    height: 5px; margin: 13px 3px 0; background: #cccccc; border: 1px solid #999999; border-radius: 2px;
+}
+
+.Ldt-Ctrl-Volume-Cursor {
+    position: absolute; top: 6px; width: 6px; height: 19px; background: #a8a8a8; border: 1px solid #999999; border-radius: 2px;
+    cursor: pointer;
+}
+
+.Ldt-Ctrl-Volume-Cursor:hover {
+     background: #cccccc;
+}
+
+.Ldt-Ctrl-Volume-Cursor.ui-draggable-dragging {
+    background: #999999;
+}
     
 .Ldt-cleaner {
   clear:both;
@@ -451,6 +489,7 @@
 
 .Ldt-createAnnotationWidget {
     width: 610px; padding-bottom: 10px; clear: both;
+    color: #fff;
     background: url(img-cinecast/createannbgd.png) no-repeat bottom right;
 }
 
@@ -512,23 +551,26 @@
 /* */
 
 .Ldt-createAnnotation-btnblock {
-   float: left; width: 480px; margin: 5px 0;
 }
 
 .Ldt-createAnnotation-btnblock label {
-    float: left; margin-top: 8px; width: 120px; font-size: 12px; height: 20px; color: #ffffff;
+    float: left; margin-top: 20px; width: 480px; font-size: 14px; color: #ffffff;
 }
 
 /* CINECAST SPECIFIC TAG BUTTONS */
 
+.Ldt-createAnnotation-keywords ul {
+    width: 100%; clear: both;
+}
+
 .Ldt-createAnnotation-keywords li {
-    border: none; margin: 5px 10px 0 0; height: 23px; padding: 0 0 0 15px;
+    border: none; margin: 0 10px 5px 0; height: 23px; padding: 0 0 0 15px;
     background: url(img-cinecast/tag.png) left top no-repeat;
     cursor: pointer;
 }
 
 .Ldt-createAnnotation-keyword-button {
-  font-size: 13px; color: #ffffff; width: 95px;
+  font-size: 13px; color: #ffffff; width: 170px; text-shadow: 1px 1px 1px #000000;
   height: 23px; padding: 0 5px 0 0; border: none; margin: 0;
   background: url(img-cinecast/tag.png) right top no-repeat;
   cursor: pointer;
@@ -543,11 +585,11 @@
 }
 
 .Ldt-createAnnotation-keywords li.Ldt-createAnnotation-active-button {
-  background-position: left -46px; margin: 5px 0 0 0;
+  background-position: left -46px; margin: 0 0 5px 0;
 }
 
 .Ldt-createAnnotation-keywords li.Ldt-createAnnotation-active-button .Ldt-createAnnotation-keyword-button {
-  background-position: right -46px; padding: 0 15px 0 0; width: 105px;
+  background-position: right -46px; padding: 0 15px 0 0; width: 180px;
 }
 /* */
 
@@ -692,12 +734,21 @@
 }
 
 .Ldt-AnnotationsList-Tag-Div {
-  font-size: 13px; color: #ffffff;
+  font-size: 13px; color: #ffffff; text-shadow: 1px 1px 1px #000000;
   height: 19px; padding: 4px 5px 0 0; border: none; margin: 0;
   background: url(img-cinecast/tag.png) right top no-repeat;
     cursor: pointer;
 }
 
+.Ldt-createAnnotation-moar-keywordz {
+    float: right; font-size: 13px; color: #ffffff; text-shadow: 1px 1px 1px #000000;
+    width: 140px; height: 23px; background: url(img-cinecast/moar.png); border: none; margin: 0 15px;
+}
+
+.Ldt-createAnnotation-moar-keywordz:hover {
+    background-position: bottom;
+}
+
 /* Tagcloud */
 
 .Ldt-TagCloud {
Binary file test/integration/allocine_dossier_independant/css/img-cinecast/createannbgd.png has changed
Binary file test/integration/allocine_dossier_independant/css/img-cinecast/moar.png has changed
Binary file test/integration/allocine_dossier_independant/css/img-cinecast/tag.png has changed
--- a/test/integration/allocine_dossier_independant/js/LdtPlayer-release.js	Fri Mar 30 18:00:26 2012 +0200
+++ b/test/integration/allocine_dossier_independant/js/LdtPlayer-release.js	Tue Apr 03 20:30:12 2012 +0200
@@ -1091,10 +1091,11 @@
 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.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>            {{#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>            {{#random_keywords}}                <button class='Ldt-createAnnotation-moar-keywordz'>{{l10n.moar_tagz}}</button>            {{/random_keywords}}            {{/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>            {{^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>";
-IriSP.player_template = "{{! template for the radio player }}<div class='Ldt-controler'>	<div class='Ldt-LeftPlayerControls'>        <div class='Ldt-Ctrl-button Ldt-CtrlPlay Ldt-CtrlPlay-PlayState Ldt-TraceMe' title='{{l10n.play_pause}}'></div>        <div class='Ldt-Ctrl-spacer'></div>        {{^disable_annotate_btn}}    	<div class='Ldt-Ctrl-button Ldt-CtrlAnnotate Ldt-TraceMe' title='{{l10n.annotate}}'></div>        <div class='Ldt-Ctrl-spacer'></div>        {{/disable_annotate_btn}}        {{^disable_search_btn}}        <div class='Ldt-Ctrl-button Ldt-CtrlSearch Ldt-TraceMe' title='{{l10n.search}}'></div>        <div class='Ldt-Ctrl-spacer'></div>        {{/disable_search_btn}}        <div class='LdtSearch'>          <input class='LdtSearchInput Ldt-TraceMe'></input>        </div>	</div>	<div class='Ldt-RightPlayerControls'>        <div class='Ldt-Ctrl-spacer'></div>        <div class='Ldt-Time'>          <div class='Ldt-ElapsedTime' title='{{l10n.elapsed_time}}'>00:00</div>          <div class='Ldt-TimeSeparator'>/</div>          <div class='Ldt-TotalTime' title='{{l10n.total_time}}'>00:00</div>        </div>        <div class='Ldt-Ctrl-spacer'></div>		<div class='Ldt-Ctrl-button Ldt-CtrlSound Ldt-CtrlSound-MuteState Ldt-TraceMe' title='{{l10n.mute_unmute}}'></div>	</div></div>";
+IriSP.player_template = "{{! template for the radio player }}<div class='Ldt-controler'>	<div class='Ldt-LeftPlayerControls'>        <div class='Ldt-Ctrl-button Ldt-CtrlPlay Ldt-CtrlPlay-PlayState Ldt-TraceMe' title='{{l10n.play_pause}}'></div>        <div class='Ldt-Ctrl-spacer'></div>        {{^disable_annotate_btn}}    	<div class='Ldt-Ctrl-button Ldt-CtrlAnnotate Ldt-TraceMe' title='{{l10n.annotate}}'></div>        <div class='Ldt-Ctrl-spacer'></div>        {{/disable_annotate_btn}}        {{^disable_search_btn}}        <div class='Ldt-Ctrl-button Ldt-CtrlSearch Ldt-TraceMe' title='{{l10n.search}}'></div>        <div class='Ldt-Ctrl-spacer'></div>        {{/disable_search_btn}}        <div class='LdtSearch'>          <input class='LdtSearchInput Ldt-TraceMe'></input>        </div>	</div>	<div class='Ldt-RightPlayerControls'>        <div class='Ldt-Ctrl-spacer'></div>        <div class='Ldt-Time'>          <div class='Ldt-ElapsedTime' title='{{l10n.elapsed_time}}'>00:00</div>          <div class='Ldt-TimeSeparator'>/</div>          <div class='Ldt-TotalTime' title='{{l10n.total_time}}'>00:00</div>        </div>        <div class='Ldt-Ctrl-spacer'></div>		<div class='Ldt-Ctrl-button Ldt-CtrlSound Ldt-CtrlSound-Full Ldt-TraceMe' title='{{l10n.mute_unmute}}'></div>	</div>	<div class='Ldt-Ctrl-Volume-Control' title='{{l10n.volume_control}}'>	    <div class='Ldt-Ctrl-Volume-Bar'></div>	    <div class='Ldt-Ctrl-Volume-Cursor'></div>	</div></div>";
 IriSP.search_template = "{{! template for the search container }}<div class='LdtSearchContainer'	style='margin-left: {{margin_left}}; position: absolute; margin-top: -60px;'>	<div class='LdtSearch'		style='display: none; background-color: #EEE; width: 165px; border-color: #CFCFCF; position: absolute; text-align: center;'>		<input class='LdtSearchInput'			style='margin-top: 1px; margin-bottom: 2px;' />	</div></div><div class='cleaner'></div>";
 IriSP.share_template = "{{! social network sharing template }}<a onclick='__IriSP.MyApiPlayer.share(\'delicious\');' title='{{l10n.share_on}} delicious'><span class='share shareDelicious'>&nbsp;</span></a>		<a onclick='__IriSP.MyApiPlayer.share(\'facebook\');' title='{{l10n.share_on}} facebook'> <span class='share shareFacebook'>&nbsp;</span></a><a onclick='__IriSP.MyApiPlayer.share(\'twitter\');' title='{{l10n.share_on}} twitter'>  <span class='share shareTwitter'>&nbsp;</span></a><a onclick='__IriSP.MyApiPlayer.share(\'myspace\');' title='{{l10n.share_on}} Myspace'>  <span class='share shareMySpace'>&nbsp;</span></a>";
 IriSP.sliceWidget_template = "{{! template for the slice widget }}<div class='Ldt-sliceWidget'>  {{! the whole bar }}  <div class='Ldt-sliceBackground'></div>    <div class='Ldt-sliceLeftHandle'></div>  {{! the zone which represents our slice }}  <div class='Ldt-sliceZone'></div>     <div class='Ldt-sliceRightHandle'></div></div>";
@@ -1216,7 +1217,7 @@
 
 /* shortcut to have global variables in templates */
 IriSP.templToHTML = function(template, values) {
-  var params = IriSP.jQuery.extend(
+  var params = IriSP.underscore.extend(
       { "defaults" : IriSP.default_templates_vars,
         "l10n" : IriSP.i18n.getMessages()
         },
@@ -1423,11 +1424,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) {
@@ -1451,6 +1452,22 @@
   }
 };
 
+IriSP.PopcornReplacement.player.prototype.volume = function(val) {
+    if (typeof this.playerFns.getVolume == "undefined" || typeof this.playerFns.setVolume == "undefined") {
+        return false;
+    }
+    var _vol = this.playerFns.getVolume();
+    if (typeof(val) !== "undefined" && parseFloat(val) !== NaN) {
+        val = Math.max(0, Math.min(1, val));
+        if (parseFloat(val) != parseFloat(_vol)) {
+            this.playerFns.setVolume(val);
+            this.trigger("volumechange");
+            _vol = this.playerFns.getVolume();
+        }
+    }
+    return _vol;
+};
+
 IriSP.PopcornReplacement.player.prototype.mute = IriSP.PopcornReplacement.player.prototype.muted;
 
 IriSP.PopcornReplacement.player.prototype.code = function(options) {
@@ -1918,7 +1935,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);
@@ -1948,7 +1968,7 @@
     var spacerDiv = IriSP.guid("LdtPlayer_spacer_");
     this._widgets.push([widgetName, newDiv]);    
 
-    var divTempl = "<div id='{{id}}' style='width: {{width}}px; position: relative;'></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}};'></div";
     
     var divCode = Mustache.to_html(divTempl, {id: newDiv, width: this._width});
@@ -2238,6 +2258,7 @@
 
 /** single point of entry for the metadataplayer */
 IriSP.initPlayer = function(config, metadata_url, libdir, platform_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,
       function() {   
@@ -2248,13 +2269,14 @@
               
               var widgets = IriSP.configureWidgets(pop, layoutManager, config.gui); 
               var modules = IriSP.configureModules(pop, config.modules); 
+              IriSP.jQuery('#Ldt-loader').detach();
       });
-};IriSP.i18n_factory = function() {
+};IriSP.I18n = function() {
     this.messages = {};
     this.base_lang = 'en';
 }
 
-IriSP.i18n_factory.prototype.getLanguage = function(lang) {
+IriSP.I18n.prototype.getLanguage = function(lang) {
     var _lang = (
         typeof lang != "undefined"
         ? lang
@@ -2275,7 +2297,7 @@
     )
 }
 
-IriSP.i18n_factory.prototype.getMessages = function(lang) {
+IriSP.I18n.prototype.getMessages = function(lang) {
     var _lang = this.getLanguage(lang);
     return (
         _lang != null
@@ -2284,7 +2306,7 @@
     );
 }
 
-IriSP.i18n_factory.prototype.getMessage = function(message, lang) {
+IriSP.I18n.prototype.getMessage = function(message, lang) {
     var _msgs = this.getMessages(lang);
     return (
         typeof _msgs[message] != "undefined"
@@ -2293,14 +2315,14 @@
     )
 }
 
-IriSP.i18n_factory.prototype.addMessage = function(lang, messagekey, messagevalue) {
+IriSP.I18n.prototype.addMessage = function(lang, messagekey, messagevalue) {
     if (typeof this.messages[lang] == "undefined") {
         this.messages[lang] = {};
     }
     this.messages[lang][messagekey] = messagevalue;
 }
 
-IriSP.i18n_factory.prototype.addMessages = function(messagesObj) {
+IriSP.I18n.prototype.addMessages = function(messagesObj) {
     var _this = this;
     IriSP.underscore(messagesObj).each(function(_messages, _lang) {
         IriSP.underscore(_messages).each(function(_value, _key) {
@@ -2309,7 +2331,16 @@
     });
 }
 
-IriSP.i18n = new IriSP.i18n_factory();
+IriSP.i18n = new IriSP.I18n();
+
+IriSP.i18n.addMessages({
+    "fr": {
+        "loading_wait": "Chargement en cours, veuillez patienter&hellip;"
+    },
+    "en": {
+        "loading_wait": "Loading, please wait&hellip;"
+    }
+})
 /* To wrap a player the develop should create a new class derived from
 the IriSP.PopcornReplacement.player and defining the correct functions */
 
@@ -2325,54 +2356,27 @@
 
     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);
         }
     }
 
     window.onReady = IriSP.wrap(this, this.ready);
-    //NOT CALLED window.onAllocineStateChange = IriSP.wrap(this, this.stateHandler);
+    window.onAllocineStateChange = IriSP.wrap(this, this.stateHandler);
     window.onTime = IriSP.wrap(this, this.progressHandler);
     
     var _videoUrl = (
@@ -2387,12 +2391,13 @@
     var params = {
         "allowScriptAccess" : "always",
         "wmode": "opaque",
-        "flashvars" : fv
+        "flashvars" : fv,
+        "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);
 
 };
 
@@ -2401,7 +2406,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();
 };
@@ -2413,8 +2417,25 @@
 }
 
 
+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) {
         case 1:
             this.callbacks.onPlay();
@@ -2488,11 +2509,26 @@
         },
         setMute : function(p) {
             if (_this.player) {
-                return p ? _this.player.mute() : _this.player.unMute();
+                if (p) {
+                    _this.player.mute();
+                }
+                else {
+                    _this.player.unMute();
+                }
+            }
+        },
+        getVolume : function() {
+            if (_this.player) {
+                return _this.player.getVolume() / 100;
             } else {
                 return false;
             }
-        }
+        },
+        setVolume : function(p) {
+            if (_this.player) {
+                _this.player.setVolume(Math.floor(100 * p));
+            }
+        },
     }
 
     window.onDailymotionPlayerReady = IriSP.wrap(this, this.ready);
@@ -2559,7 +2595,6 @@
 
 /** jwplayer player wrapper */
 IriSP.PopcornReplacement.jwplayer = function(container, options) {
-
   /* appel du parent pour initialiser les structures communes à tous les players */
   IriSP.PopcornReplacement.player.call(this, container, options);
   
@@ -2572,7 +2607,9 @@
     getPosition: function() { return jwplayer(this.container).getPosition(); },
     seek: function(pos) { return jwplayer(this.container).seek(pos); },
     getMute: function() { return jwplayer(this.container).getMute() },
-    setMute: function(p) { return jwplayer(this.container).setMute(p); }
+    setMute: function(p) { return jwplayer(this.container).setMute(p); },
+    getVolume: function() { return jwplayer(this.container).getVolume() / 100; },
+    setVolume: function(p) { return jwplayer(this.container).setVolume(Math.floor(100*p)); }
   }
 
   options.events = this.callbacks;
@@ -2815,7 +2852,7 @@
                     } else {
                         if (typeof _t['id-ref'] != "undefined") {
                             var _f = IriSP.underscore.find(_this._serializer._data.tags, function(_tag) {
-                                return _tag['id-ref'] == _t.id;
+                                return _tag.id == _t['id-ref'];
                             });
                             if (typeof _f != "undefined") {
                                 return IriSP.get_aliased(_f.meta, ['dc:title', 'title']);
@@ -2872,7 +2909,7 @@
     })
     .first(10)
     .sortBy(function(_o) {
-        return _o.iterator;
+        return (typeof _o.is_new != "undefined" && _o.is_new ? -1 : _o.iterator);
     })
     .value();
   
@@ -2946,13 +2983,13 @@
       if (typeof obj.url == "undefined" || !obj.url) {
           /* only if the annotation isn't present in the document create an
              external link */
-          if (!this.annotations_ids.indexOf(obj.id) != -1) {
+          if (this.annotations_ids.indexOf(obj.id.toLowerCase()) == -1) {
             // braindead url; jacques didn't want to create a new one in the platform,
             // so we append the cutting id to the url.
             obj.url = this.project_url + "/" + media + "/" + 
                          annotations[i].meta.project + "/" +
                          annotations[i].meta["id-ref"] + '#id=' + annotations[i].id;
-            
+                         
             // obj.url = document.location.href.split("#")[0] + "/" + annotation.meta.project;
           }
           }
@@ -2966,13 +3003,9 @@
   /* build a table of the annotations present in the document for faster 
      lookup
   */
-  this.annotations_ids = [];
-  
-  var annotations = this._serializer._data.annotations;
-  var i = 0;
-  for(i = 0; i < annotations.length; i++) {
-    this.annotations_ids.push(annotations[i]["id"]);
-  }
+  this.annotations_ids = IriSP.underscore(this._serializer._data.annotations).map(function(_a) {
+    return _a.id.toLowerCase();
+  });
   
   var _this = this;
     
@@ -3241,7 +3274,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",
+            "moar_tags": "More tags"
         },
         "fr": {
             "submit": "Envoyer",
@@ -3254,7 +3288,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",
+            "moar_tagz": "Plus de mots-clés"
         }
     }
 );
@@ -3270,6 +3305,8 @@
   this.checkOption("api_endpoint_template");
   this.checkOption("show_from_field", true);
   this.checkOption("api_method");
+  this.checkOption("random_keywords");
+  this.checkOption("disable_share", false);
                          
   if (!IriSP.null_or_undefined(IriSP.user)) {
       if (!IriSP.null_or_undefined(IriSP.user.avatar)) {
@@ -3297,6 +3334,20 @@
 };
 
 IriSP.createAnnotationWidget.prototype.draw = function() {
+    var _this = this;
+    if (typeof this._config.remote_keywords != "undefined" && typeof this._config.remote_keywords) {
+        IriSP.jQuery.getJSON(this._config.remote_keywords, function(_json) {
+            _this.keywords = IriSP.underscore(_json.tags).map(function(_tag) {
+                return _tag.meta.description;
+            });
+            _this.drawCallback();
+        });
+    } else {
+        this.drawCallback();
+    }
+}
+
+IriSP.createAnnotationWidget.prototype.drawCallback = function() {
   var _this = this;
   
   var annotationMarkup = IriSP.templToHTML(IriSP.createAnnotationWidget_template, 
@@ -3309,17 +3360,25 @@
   else {
     this.showStartScreen();
   }
-
+  
+  if (this.random_keywords) {
+      this.selector.find(".Ldt-createAnnotation-keywords li").hide();
+      this.showMoarTagz();
+      this.selector.find('.Ldt-createAnnotation-moar-keywordz').click(function() {
+          _this.showMoarTagz();
+      })
+  }
   // 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 */
 
@@ -3380,6 +3439,21 @@
   }
 };
 
+IriSP.createAnnotationWidget.prototype.showMoarTagz = function() {
+    for (var j=0; j < this.random_keywords; 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"),
@@ -3389,7 +3463,7 @@
         ? _contents.replace(_rx,"").replace("  "," ").trim()
         : _contents.trim() + " " + _keyword
     );
-    _field.val(_contents);
+    _field.val(_contents.trim());
     _field.trigger("js_mod");
 }
 
@@ -3451,7 +3525,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() {
@@ -3626,7 +3700,17 @@
   meta.created = Date().toString();
   
   // All #hashtags are added to tags
-  annotation.tags = contents.match(/#[^#\s]+\b/gim) || [];
+  var _tags = contents.toLowerCase().match(/#[^#\s]+\b/gim) || [];
+  this.selector.find('.Ldt-createAnnotation-keyword-button').each(function() {
+      var _tx = IriSP.jQuery(this).text(),
+        _rx = IriSP.regexpFromText(_tx);
+        if (_rx.test(contents)) {
+            _tags.push(_tx.toLowerCase())
+        }
+  });
+  
+  annotation.tags = IriSP.underscore.uniq(_tags);
+  
   
   var jsonString = JSON.stringify(apiJson);
   var project_id = this._serializer._data.meta.id;
@@ -3643,9 +3727,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 */
@@ -3664,8 +3748,10 @@
     
                         annotation.meta = meta;
                         annotation.meta["id-ref"] = json.annotations[0]["type"];
+                    } else {
+                        annotation.type = "cinecast:UserAnnotation";
                     }
-                        
+                    annotation.is_new = true;
                     // everything is shared so there's no need to propagate the change
                     _this._serializer._data.annotations.push(annotation);
  
@@ -3708,7 +3794,9 @@
             "annotate": "Annotate",
             "search": "Search",
             "elapsed_time": "Elapsed time",
-            "total_time": "Total time"
+            "total_time": "Total time",
+            "volume": "Volume",
+            "volume_control": "Volume control"
         },
         "fr": {
             "play_pause": "Lecture/Pause",
@@ -3720,7 +3808,9 @@
             "annotate": "Annoter",
             "search": "Rechercher",
             "elapsed_time": "Durée écoulée",
-            "total_time": "Durée totale"
+            "total_time": "Durée totale",
+            "volume": "Niveau sonore",
+            "volume_control": "Réglage du niveau sonore"
         }
     }
 );
@@ -3750,7 +3840,7 @@
   this._Popcorn.listen("play", IriSP.wrap(this, this.playButtonUpdater));
   this._Popcorn.listen("pause", IriSP.wrap(this, this.playButtonUpdater));
   
-  this._Popcorn.listen("volumechange", IriSP.wrap(this, this.muteButtonUpdater));
+  this._Popcorn.listen("volumechange", IriSP.wrap(this, this.volumeUpdater));
 
   this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.timeDisplayUpdater));  
   // update the time display for the first time.
@@ -3766,7 +3856,20 @@
                                             { self._Popcorn.trigger("IriSP.PlayerWidget.AnnotateButton.clicked"); });
   this.selector.find(".Ldt-CtrlSearch").click(function() { self.searchButtonHandler.call(self); });
   
-  this.selector.find('.Ldt-CtrlSound').click(function() { self.muteHandler.call(self); } );
+	var _volctrl = this.selector.find(".Ldt-Ctrl-Volume-Control");
+    this.selector.find('.Ldt-CtrlSound')
+        .click(function() { self.muteHandler.call(self); } )
+        .mouseover(function() {
+            _volctrl.show();
+        })
+        .mouseout(function() {
+            _volctrl.hide();
+        });
+    _volctrl.mouseover(function() {
+        _volctrl.show();
+    }).mouseout(function() {
+        _volctrl.hide();
+    });
   
   /*
   var searchButtonPos = this.selector.find(".Ldt-CtrlSearch").position();
@@ -3777,8 +3880,19 @@
   // trigger an IriSP.PlayerWidget.MouseOver to the widgets that are interested (i.e : sliderWidget)
   this.selector.hover(function() { self._Popcorn.trigger("IriSP.PlayerWidget.MouseOver"); }, 
                       function() { self._Popcorn.trigger("IriSP.PlayerWidget.MouseOut"); });
+  this.selector.find(".Ldt-Ctrl-Volume-Cursor").draggable({
+      axis: "x",
+      drag: function(event, ui) {
+          var _vol = Math.max(0, Math.min( 1, ui.position.left / (ui.helper.parent().width() - ui.helper.outerWidth())));
+          ui.helper.attr("title",IriSP.i18n.getMessage('volume')+': ' + Math.floor(100*_vol) + '%');
+          self._Popcorn.volume(_vol);
+      },
+      containment: "parent"
+  });
  
-  this.muteButtonUpdater(); /* some player - jwplayer notable - save the state of the mute button between sessions */
+ setTimeout(function() {
+     self.volumeUpdater();
+ }, 1000); /* some player - jwplayer notable - save the state of the mute button between sessions */
 };
 
 /* Update the elasped time div */
@@ -3835,25 +3949,28 @@
 };
 
 IriSP.PlayerWidget.prototype.muteHandler = function() {
-  if (!this._Popcorn.muted()) {    
-      this._Popcorn.mute(true);
-    } else {
-      this._Popcorn.mute(false);
+  this._Popcorn.mute(!this._Popcorn.muted());
+};
+
+IriSP.PlayerWidget.prototype.volumeUpdater = function() {
+    var _muted = this._Popcorn.muted(),
+        _vol = this._Popcorn.volume();
+    if (_vol === false) {
+        _vol = .5;
     }
-};
-
-IriSP.PlayerWidget.prototype.muteButtonUpdater = function() {
-  var status = this._Popcorn.media.muted;
-  
-  if ( status == true ){        
-    this.selector.find(".Ldt-CtrlSound").attr("title", IriSP.i18n.getMessage('unmute'));
-    this.selector.find(".Ldt-CtrlSound").removeClass("Ldt-CtrlSound-MuteState").addClass("Ldt-CtrlSound-SoundState");    
-  } else {
-    this.selector.find(".Ldt-CtrlSound").attr("title", IriSP.i18n.getMessage('mute'));
-    this.selector.find(".Ldt-CtrlSound").removeClass("Ldt-CtrlSound-SoundState").addClass("Ldt-CtrlSound-MuteState");
-  }  
-
-  return;
+    var _soundCtl = this.selector.find(".Ldt-CtrlSound");
+    _soundCtl.removeClass("Ldt-CtrlSound-Mute Ldt-CtrlSound-Half Ldt-CtrlSound-Full");
+    if (_muted) {        
+        _soundCtl.attr("title", IriSP.i18n.getMessage('unmute'))
+            .addClass("Ldt-CtrlSound-Mute");    
+    } else {
+        _soundCtl.attr("title", IriSP.i18n.getMessage('mute'))
+            .addClass(_vol < .5 ? "Ldt-CtrlSound-Half" : "Ldt-CtrlSound-Full" )
+    }
+    var _cursor = this.selector.find(".Ldt-Ctrl-Volume-Cursor");
+    _cursor.css({
+        "left": ( _muted ? 0 : Math.floor(_vol * (_cursor.parent().width() - _cursor.outerWidth())) ) + "px"
+    })
 };
 
 IriSP.PlayerWidget.prototype.showSearchBlock = function() {
@@ -4956,7 +5073,6 @@
       this.selector.css("background", this._config.background);
   }
   this.checkOption('cinecast_version');
-  console.log('Cinecast', this.cinecast_version);
 };
 
 
@@ -4988,7 +5104,7 @@
   // If we've found the correct view, feed the directly the data from the view
   // to jquery sparkline. Otherwise, compute it ourselves.
     if (!IriSP.null_or_undefined(stat_view)) {
-        console.log("sparklinewidget : using stats embedded in the json");
+        //console.log("sparklinewidget : using stats embedded in the json");
         var _results = stat_view.meta.stat.split(",");      
     } else {
         var _annotations = this._serializer._data.annotations,
@@ -5588,8 +5704,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 */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/integration/allocine_dossier_independant/js/libs/tracemanager.js	Tue Apr 03 20:30:12 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;
+ };
--- a/test/integration/allocine_dossier_independant/polemic-allocine.htm	Fri Mar 30 18:00:26 2012 +0200
+++ b/test/integration/allocine_dossier_independant/polemic-allocine.htm	Tue Apr 03 20:30:12 2012 +0200
@@ -21,7 +21,7 @@
                 name : 'awesome_user_name',
                 avatar : 'allocine_test/avatar.png'
             };
-            IriSP.libdir = "/metadataplayer/src/js/libs/";
+            IriSP.libdir = "js/libs/";
             IriSP.defaults.user = function() {
                 return IriSP.user;
             };
@@ -50,12 +50,6 @@
                         lineColor: "#ffffff",
                         fillColor: "#999999"
                     }, {
-                        type : "SliderWidget"
-                    }, {
-                        type : "PlayerWidget",
-                        disable_annotate_btn : true,
-                        disable_search_btn : true
-                    }, {
                         type : "SegmentsWidget",
                         requires : [{
                             type : "TooltipWidget",
@@ -65,23 +59,26 @@
                     }, {
                         type : "createAnnotationWidget",
                         polemic_mode : false,
-                        keywords : ['#vodkaster', '#allocine', '#universcine', '#FauxRaccord', '#SceneCulte', '#navet'],
+                        remote_keywords : 'http://festival.cinecast.fr/configuration.jsonp?jsonp=?',
+                        random_keywords : 3,
+                        disable_share: true,
                         api_endpoint_template : "coucou/{{id}}.json",
                         api_method : 'POST'
                     }, {
                         type: "TraceWidget",
-                        url: "http://192.168.56.101:5000/",
+                     //   js_console : true,
+                        url: "http://traces.advene.org:5000/",
                         requestmode: 'GET',
                         syncmode: "sync"
-                    }]
+                    } ]
                 },
                 player : {
                     type : 'allocine', // player type
                     height : 300,
                     width : 610,
-                    acPlayerUrl : "allocine_test/AcPlayer_v3.0.swf",
-                    autoPlay : "false",
-                    urlAcData : "allocine_test/data_cinecast.xml"
+                    acPlayerUrl : "allocine_test/AcPlayer_v3.0_new.swf",
+                    autoPlay : "true",
+                    urlAcData : "allocine_test/data_cinecast_new.xml"
                 },
                 modules : [{
                     type : "MediaFragment",