Merge with a7b169ba0172834acb0ba48d94962f5e08467d93
authorveltr
Tue, 21 Feb 2012 12:12:01 +0100
changeset 15 03c54e8c00dc
parent 14 1cc92b8c3a38 (diff)
parent 12 a7b169ba0172 (current diff)
child 17 3cf3601fb709
Merge with a7b169ba0172834acb0ba48d94962f5e08467d93
client/main.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/compteur.html	Tue Feb 21 12:12:01 2012 +0100
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <meta charset="utf-8" />
+        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+        <title>Bubble-TV</title>
+        <meta name="description" content="" />
+        <link rel="stylesheet" href="css/base-metric.css" />
+        <style type="text/css">
+            #container {
+                width: 300px;
+                height: 300px;
+                margin: 200px auto;
+                padding: 100px;
+                background: #0031ff;
+                color: #fff;
+            }
+            h1 {
+                font-size: 24px;
+            }
+            h2 {
+                font-size: 68px; font-weight: bold; margin: 2px 0;
+            }
+        </style>
+
+        <script type="text/javascript" src="lib/jquery.min.js"></script>
+        <script type="text/javascript" src="lib/protoclass.js"></script>              
+        <script type="text/javascript" src="lib/box2d.js"></script>
+        <script type="text/javascript" src="js/tweetanim.js"></script>
+        <script type="text/javascript" src="js/tweetvote-anim.js"></script>     
+        <script type="text/javascript" src="js/podium.js"></script>
+        <script type="text/javascript" src="js/tweetsource.js"></script>
+        <script type="text/javascript">
+            /* Heure de début de l'émission
+            var startHour = new Date("Feb 24 2012 23:30:00 UTC+0100"); 
+             * */
+            var startHour = new Date() - 120000;
+            
+            /* Mots-clés pour déclencher la recherche
+            var searchKeywords = [ '#lgw', '#legrandwebze', 'webze' ]; 
+             * */
+            var searchKeywords = ['Sarkozy', 'Hollande', 'Bayrou'];
+            
+            var totalTweets = 0;
+            
+            $(function() {
+                
+                myTweetSource = new Btv_TweetSource({
+                    keywords: searchKeywords
+                });
+                
+                myTweetSource.setOnNewTweets(function() {
+                    totalTweets = this.afterDate(startHour).count();
+                });
+                
+                setInterval(function() {
+                    var _aff = parseInt($("#nbtweets").html());
+                    if (_aff < totalTweets) {
+                        if (_aff) {
+                            $("#nbtweets").html(1+_aff);
+                        } else {
+                            $("#nbtweets").html(totalTweets);
+                        }
+                    }
+                }, 200);
+            });
+        </script>
+    </head>
+    <body>
+        <div id="container">
+            <h1>Total des Tweets</h1>
+            <h2 id="nbtweets">0</h2>
+        </div>
+
+    </body>
+</html>
--- a/client/css/controlpanel.css	Tue Feb 21 11:26:01 2012 +0100
+++ b/client/css/controlpanel.css	Tue Feb 21 12:12:01 2012 +0100
@@ -35,7 +35,7 @@
 }
 
 .btv-cp-liste-tweets {
-    width: 310px; height: 160px; border: 1px solid #b0b0b0;
+    width: 310px; height: 220px; border: 1px solid #b0b0b0;
     background: #fefefe; overflow: auto; margin: 4px 0;
 }
 .btv-cp-liste-tweets li {
@@ -54,6 +54,11 @@
 .btv-cp-tweet-from {
     font-weight: bold;
 }
+
+.btv-cp-tweet-remove {
+    background-position: -30px 0;
+}
+
 .btv-cp-liste-tweets li:hover {
     background: #00f; color: #fff;
 }
@@ -68,7 +73,7 @@
 .btv-cp-play-pause {
     display: block; margin: 5px 60px; width: 32px; height: 35px; background: url("../img/playpause.png");
 }
-.btv-cp-status-play {
+.btv-cp-status-play .btv-cp-play-pause {
     background-position: -32px 0;
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/css/main.css	Tue Feb 21 12:12:01 2012 +0100
@@ -0,0 +1,63 @@
+#podium-container {
+    position: absolute;
+    width: 1480px;
+    top: 700px;
+    left: 400px;
+}
+#podium {
+    width: 100%;
+    height: 200px;
+}
+#podium-labels {
+    position: absolute;
+    width: 100%;
+    top: 215px;
+}
+#podium-labels li {
+    float: left;
+    width: 25%;
+    color: #ffffff;
+    text-align: center;
+    font-size: 42px;
+}
+#podium-chiffres {
+    position: absolute;
+    width: 100%;
+    top: 145px;
+}
+#podium-chiffres li {
+    float: left;
+    width: 25%;
+    color: #000000;
+    text-align: center;
+    font-size: 50px;
+    font-weight: bold;
+}
+
+
+#btv-bigtweet {
+    position: absolute;
+    left: 775px;
+    top: 250px;
+    width: 650px;
+    background: #0031ff;
+    padding: 40px;
+    color: #ffffff;
+    font-size: 42px;
+    display: none;
+}
+.btv-bigtweet-image {
+    width: 100px;
+    height: 100px;
+    margin: 0 30px 30px 0;
+    float: left;
+}
+.btv-bigtweet-screen-name {
+    font-weight: bold;
+}
+.btv-bigtweet-name {
+    margin: 10px 0;
+}
+.btv-tweet-text {
+    clear: both;
+}
\ No newline at end of file
Binary file client/img/addshow.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/js/main.js	Tue Feb 21 12:12:01 2012 +0100
@@ -0,0 +1,134 @@
+var myPodium,
+    myTweetSource,
+    myQueueManager;
+
+function updateLastTweetList() {
+    var _filtered = myTweetSource.afterDate(startHour),
+        _txtFilter = $("#btv-cp-champ-filtre").val(),
+        _reFilter = null;
+    if (_txtFilter.length > 1) {
+        _filtered = _filtered.search(_txtFilter);
+        _reFilter = regexpFromText(_txtFilter);
+    }
+    $('#btv-cp-liste-tweets-tout').html(
+        _filtered.reverse().slice(0,20).map(function(_t) {
+            return '<li onclick="addTweetToSelection(\''
+                + _t.id_str
+                + '\'); return false;"><a title="Ajouter à la sélection" href="#"><span class="btv-cp-tweet-date">'
+                + _t.created_at.match(/\d+:\d+:\d+/)[0]
+                + '</span> <span class="btv-cp-tweet-from">'
+                + ( _reFilter ? ('@' + _t.from_user).replace(_reFilter, '<span class="btv-cp-highlight">$1</span>') : ('@' + _t.from_user) )
+                + '</span> <span class="btv-cp-tweet-text">'
+                + ( _reFilter ? _t.text.replace(_reFilter, '<span class="btv-cp-highlight">$1</span>') : _t.text )
+                + '</span><div class="btv-cp-tweet-button btv-cp-tweet-add"></div></a></li>'
+        }).join('')
+    );
+}
+
+function addTweetToSelection(tweetId) {
+    var _t = myTweetSource.tweetById(tweetId);
+    if (_t) {
+        $("#btv-cp-liste-tweets-selection").prepend(
+            '<li><a title="Afficher sur l\'écran" href="#" onclick="showTweetOnScreen(\''
+            + _t.id_str
+            + '\'); return false;"><span class="btv-cp-tweet-date">'
+            + _t.created_at.match(/\d+:\d+:\d+/)[0]
+            + '</span> <span class="btv-cp-tweet-from">@'
+            + _t.from_user
+            + '</span> <span class="btv-cp-tweet-text">'
+            + _t.text
+            + '</span><div class="btv-cp-tweet-button btv-cp-tweet-show"></div></a>'
+            + '<a title="Supprimer de cette liste" href="#" onclick="$(this).parent().detach(); return false;"><div class="btv-cp-tweet-button btv-cp-tweet-remove"></div></a></li>'
+        );
+    }
+}
+
+function showTweetOnScreen(tweetId) {
+    var _t = myTweetSource.tweetById(tweetId);
+    console.log(_t);
+    if (_t) {
+        $("#btv-bigtweet").html('<img class="btv-bigtweet-image" src="'
+        + _t.profile_image_url
+        + '" /><p class="btv-bigtweet-screen-name">'
+        + _t.from_user
+        + '</p><p class="btv-bigtweet-name">'
+        + _t.from_user_name
+        +'</p><p class="btv-bigtweet-text">'
+        + _t.text
+        +'</p>').show();
+        $(".btv-cp-hide-tweets").show();
+    }
+}
+
+$(function() {
+    setInterval(function() {
+        var _t = Math.floor((new Date() - startHour)/1000),
+            _s = _t % 60,
+            _m = Math.floor(_t/60) % 60,
+            _h = Math.floor(_t/3600);
+        $("#btv-cp-temps").html(
+            _h  + ':' + (_m < 10 ? '0' : '') + _m + ':' + (_s < 10 ? '0' : '') + _s
+        )
+    }, 500);
+    myPodium = new Btv_Podium([0,0,0,0], { minHeight: 50 });
+    
+    
+    $("#podium-labels").html(columnKeywords.map(function(_w) {
+        return '<li>' + _w + '</li>'
+    }).join(""));
+    
+    myTweetSource = new Btv_TweetSource({
+        keywords: searchKeywords
+    });
+    
+    myTweetSource.setOnNewTweets(function() {
+        var _filtered = this.afterDate(startHour);
+        $("#btv-cp-nb-tweets").html(_filtered.count());
+        var _counts = [];
+        for (var _i = 0; _i < columnKeywords.length; _i++) {
+            _counts.push(_filtered.search(columnKeywords[_i]).count());
+        }
+        updateLastTweetList();
+        myPodium.update(_counts);
+        $("#podium-chiffres").html(_counts.map(function(_c) {
+            return '<li>' + _c + '</li>'
+        }).join(""));
+    });
+    myQueueManager = new Btv_TweetQueueManager(myTweetSource, function(_t) {
+        var _cat = -1;
+        for (var i = 0; i < columnKeywords.length; i++) {
+            if (_t.text.search(regexpFromText(columnKeywords[i])) != -1) {
+                _cat = i;
+                break;
+            }
+        }
+        if (_cat != -1) {
+            if (_cat == 2) {
+                console.log(_t.text);
+            }
+            _t.cat = _cat;
+            createBallTweetForce(_t);
+        }
+});
+    
+    $("#btv-cp-champ-filtre").keyup(function() {
+        updateLastTweetList();
+    });
+    $("#btv-cp-clear-filtre").click(function() {
+        $("#btv-cp-champ-filtre").val("");
+        updateLastTweetList();
+        return false; 
+    });
+    $("#btv-bigtweet, .btv-cp-hide-tweets").click(function() {
+        $("#btv-bigtweet, .btv-cp-hide-tweets").hide();
+    });
+    $("#btv-cp-cont-pause-amont").click(function() {
+       if (myQueueManager.playPause()) {
+           $(this).removeClass("btv-cp-status-pause");
+           $(this).addClass("btv-cp-status-play");
+       } else {
+           $(this).addClass("btv-cp-status-pause");
+           $(this).removeClass("btv-cp-status-play");
+       }
+    });
+});
\ No newline at end of file
--- a/client/js/podium.js	Tue Feb 21 11:26:01 2012 +0100
+++ b/client/js/podium.js	Tue Feb 21 12:12:01 2012 +0100
@@ -20,12 +20,13 @@
     }
     this.options.width = this.options.width || this._$.width();
     this.options.height = this.options.height || this._$.height();
+    this.options.minHeight = this.options.minHeight || 0;
     this.update(data, true);
 }
 
 Btv_Podium.prototype.update = function(data, noAnimate) {
-    var _data = data || [];
-    var i = 0;
+    var _data = data || [],
+        _oldcount = this._$.children().length;
     while (_data.length > this._$.children().length) {
         var _newCol = document.createElement("div");
         this.$(_newCol).css({
@@ -37,10 +38,6 @@
             "margin-left": 0
         });
         this._$.append(_newCol);
-        i++;
-        if (i > 10) {
-            break;
-        }
     }
     while (_data.length < this._$.children().length) {
         this._$.children().last().detach();
@@ -49,18 +46,21 @@
         var _max = _data.reduce(function(_memo, _val) {
                 return Math.max(_memo, _val);
             }, 1),
-            _scale = this.options.height / _max,
+            _scale = (this.options.height - this.options.minHeight) / _max,
             _spacing = Math.min(this.options.spacing, Math.floor(.5*this.options.width/_data.length)),
             _width = Math.floor(( this.options.width - (_data.length - 1) * _spacing) / _data.length),
             _this = this;
         this._$.children().each(function(_i, _e) {
-            var _height = _scale * _data[_i],
-                _css = {
-                    "margin-top": _this.options.height - _height,
-                    "height": _height,
-                    "width": _width,
-                    "margin-left": (_i ? _spacing : 0)
-                }
+            var _height = Math.floor(_scale * _data[_i] + _this.options.minHeight),
+                _css = {};
+            if (_height != _this.$(_e).height()) {
+                _css["margin-top"] = _this.options.height - _height,
+                _css["height"] = _height
+            }
+            if (_data.length != _oldcount) {
+                _css["width"] = _width;
+                _css["margin-left"] = (_i ? _spacing : 0);
+            }
             if (noAnimate) {
                 _this.$(_e).css(_css); 
             } else {
--- a/client/js/tweetsource.js	Tue Feb 21 11:26:01 2012 +0100
+++ b/client/js/tweetsource.js	Tue Feb 21 12:12:01 2012 +0100
@@ -4,6 +4,10 @@
  * 
  * */
 
+function regexpFromText(_text) {
+    return new RegExp('(' + _text.replace(/\W/gim,'\\$1') + ')','gim');
+}
+
 Btv_TweetArray = function() {
     this.tweets = [];
     this.idIndex = [];
@@ -14,7 +18,11 @@
     this.idIndex.push(_tweet.id_str);
 }
 
-Btv_TweetArray.prototype.addTweet = function(_tweet, _inhibitCallback) {
+Btv_TweetArray.prototype.setOnAdd = function(_callback) {
+    this.onAdd = _callback;
+}
+
+Btv_TweetArray.prototype.addTweet = function(_tweet) {
     if (this.idIndex.indexOf(_tweet.id_str) != -1) {
         return;
     }
@@ -27,6 +35,9 @@
     }
     this.tweets.splice(_pos,0,_tweet);
     this.idIndex.splice(_pos,0,_tweet.id_str);
+    if (typeof this.onAdd == "function") {
+        this.onAdd(_tweet);
+    }
 }
 
 Btv_TweetArray.prototype.addMultipleTweets = function(_multiTweets) {
@@ -40,8 +51,8 @@
     return this.tweets.length;
 }
 
-Btv_TweetArray.prototype.getTweet = function(_i) {
-    return this.tweets(_i);
+Btv_TweetArray.prototype.tweetAtPos = function(_i) {
+    return this.tweets[_i];
 }
 
 Btv_TweetArray.prototype.slice = function(_start, _end) {
@@ -80,7 +91,7 @@
 
 Btv_TweetArray.prototype.search = function(_filter) {
     var _filtered = new Btv_TweetArray(),
-        _reFilter = new RegExp(_filter.replace(/\W/gim,'\\$1'),'gim');
+        _reFilter = regexpFromText(_filter);
     this.each(function(_tweet) {
         var _mention = '@' + _tweet.from_user;
         if (( _tweet.text.search(_reFilter) != -1 ) || ( _mention.search(_reFilter) != -1 )) {
@@ -93,7 +104,7 @@
 Btv_TweetArray.prototype.beforeDate = function(_date) {
     var _filtered = new Btv_TweetArray();
     this.each(function(_tweet) {
-        if (_tweet.date_value < _date) {
+        if (_tweet.date_value <= _date) {
             _filtered.push(_tweet);
         }
     });
@@ -131,7 +142,7 @@
     }
     this.options = _opts;
     var _this = this;
-    this.retrieveInitialTweets()
+    this.retrieveInitialTweets();
     setInterval(function() {
         _this.retrieveNewTweets();
     }, 5000);
@@ -157,18 +168,18 @@
             
             if (_isLast) {
                 _this.loading = false;
-                if (_this.tweetsCallback) {
-                    _this.tweetsCallback();
+                if (typeof _this.onNewTweets == "function") {
+                    _this.onNewTweets();
                 }
             }
         });
     }
     
+    
     if (this.loading) {
         return;
     }
     this.loading = true;
-    
     var _baseurl = "http://search.twitter.com/search.json",
         _currentPage = 0,
         _firstparams = "?q="
@@ -185,7 +196,7 @@
 
 Btv_TweetSource.prototype.retrieveInitialTweets = function() {
     this.retrieveTweets({
-        "pages": 6
+        "pages": 4
     });
 }
 
@@ -196,20 +207,63 @@
     });
 }
 
-Btv_TweetArray.prototype.setTweetsCallback = function(_callback) {
-    this.tweetsCallback = _callback;
+Btv_TweetSource.prototype.setOnNewTweets = function(_callback) {
+    this.onNewTweets = _callback;
+}
+
+Btv_TweetQueueManager = function(_tweetArray, _callback) {
+    this.tweetArray = _tweetArray;
+    this.majorInterval = 10000; // Time slices for calculating the minor Interval setting
+    this.minimumInterval = 1000; // Safe limit to avoid tweets going to the wrong column
+    this.initialBuffer = 20000; // don't start with empty columns, but show the tweets of the last 20000 seconds
+    this.waitIfNoTweets = 2000;
+    this.callback = _callback;
+    this.lastEndTime = new Date().valueOf() - 20000;
+    this.isPaused = false;
+    this.onMajorInterval();
 }
 
-/*
-Btv_TweetSubscriber = function(tweetArray) {
-    this.tweetArray = tweetArray;
-    this.position = 0;
+Btv_TweetQueueManager.prototype.onMinorInterval = function() {
+    if (this.isPaused) {
+        this.waitMinorInterval();
+    } else {
+        var _l = this.currentSlice.count();
+        if (this.position < _l) {
+            this.callback(this.currentSlice.tweetAtPos(this.position));
+            this.position++;
+            this.waitMinorInterval();
+        } else {
+            this.onMajorInterval();
+        }
+    }
+}
+
+Btv_TweetQueueManager.prototype.waitMinorInterval = function() {
+    var _this = this;
+    window.setTimeout(function() {
+        _this.onMinorInterval();
+    }, this.minorInterval);
 }
 
-Btv_TweetSubscriber.getTweets = function() {
-    var _p = this.position,
-        _l = this.tweetArray.count();
-    this.position = _l;
-    return this.tweetArray.slice(_p,_l);
+Btv_TweetQueueManager.prototype.onMajorInterval = function() {
+    this.position = 0;
+    this.currentSlice = this.tweetArray.afterDate(this.lastEndTime);
+    var _l = this.currentSlice.count();
+    if (_l) {
+        this.lastEndTime = this.currentSlice.tweetAtPos(_l - 1).date_value;
+        this.minorInterval = Math.floor(Math.max(this.minimumInterval, this.majorInterval / _l));
+        console.log("Added "+_l+" tweets to the queue, with an interval of "+this.minorInterval+" ms");
+        this.onMinorInterval();
+    } else {
+        var _this = this;
+        console.log("No tweets in the queue, waiting");
+        window.setTimeout(function() {
+            _this.onMajorInterval();
+        }, this.waitIfNoTweets);
+    }
 }
-*/
\ No newline at end of file
+
+Btv_TweetQueueManager.prototype.playPause = function() {
+    this.isPaused = !this.isPaused;
+    return this.isPaused;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/main.html	Tue Feb 21 12:12:01 2012 +0100
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <meta charset="utf-8" />
+        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+        <title>Bubble-TV</title>
+        <meta name="description" content="" />
+        <link rel="stylesheet" href="css/base-metric.css" />
+        <link rel="stylesheet" href="css/controlpanel.css" />
+        <link rel="stylesheet" href="css/main.css" />
+
+        <script type="text/javascript" src="lib/jquery.min.js"></script>        
+        
+        <script type="text/javascript" src="lib/protoclass.js"></script>              
+        <script type="text/javascript" src="lib/box2d.js"></script>
+        <script type="text/javascript" src="js/tweetanim.js"></script>
+        <script type="text/javascript" src="js/tweetvote-anim.js"></script>     
+        <script type="text/javascript" src="js/podium.js"></script>
+        <script type="text/javascript" src="js/tweetsource.js"></script>
+        <script type="text/javascript" src="js/main.js"></script>
+        <script type="text/javascript">
+            /* Heure de début de l'émission
+            var startHour = new Date("Feb 24 2012 23:30:00 UTC+0100"); 
+             * */
+            var startHour = new Date() - 120000;
+            
+            /* Mots-clés pour déclencher la recherche
+            var searchKeywords = [ '#lgw', '#legrandwebze', 'webze' ]; 
+             * */
+            var searchKeywords = ['Sarkozy', 'Hollande', 'Bayrou'];
+            
+            /* Mots-clés correspondant aux colonnes
+            var columnKeywords = [ '#ilReste', '#ilPart', '#cQui', '#change2ton' ];
+             */
+            
+            var columnKeywords = [ 'Hollande', 'Zorglub I°', 'Bayrou', 'Sarkozy' ];
+            
+        </script>
+    </head>
+    <body>
+         <div id="canvas" width="6000" height="2000" style="background-color:#333333;" ></div>
+
+        <div id="btv-global-container">
+            <div id="btv-cp-container">
+                <div class="btv-cp-line">
+                    <div class="btv-cp-element">
+                        <h2>Bubble <b>TV</b></h2>
+                    </div>
+                    <div class="btv-cp-element" id="btv-cp-cont-filtre">
+                        <h3>Rechercher/Filtrer</h3>
+                        <input id="btv-cp-champ-filtre" />
+                        <a href="#" id="btv-cp-clear-filtre">x</a>
+                    </div>
+                    <div class="btv-cp-element btv-cp-cont-liste">
+                        <h3>Derniers tweets</h3>
+                        <ul class="btv-cp-liste-tweets" id="btv-cp-liste-tweets-tout">
+                        </ul>
+                    </div>
+                    <div class="btv-cp-element btv-cp-cont-liste">
+                        <h3>Tweets sélectionnés</h3>
+                        <ul class="btv-cp-liste-tweets" id="btv-cp-liste-tweets-selection">
+                        </ul>
+                        <a class="btv-cp-hide-tweets" href="#" style="display: none;">Cacher le tweet à l'écran</a>
+                    </div>
+                    <div class="btv-cp-element btv-cp-cont-pause btv-cp-status-pause" id="btv-cp-cont-pause-amont">
+                        <h3>Arrivée des tweets</h3>
+                        <a class="btv-cp-play-pause" href="#"></a>
+                    </div>
+                    <div class="btv-cp-element btv-cp-cont-pause btv-cp-status-pause" id="btv-cp-cont-pause-aval">
+                        <h3>Purge des colonnes</h3>
+                        <a class="btv-cp-play-pause" href="#"></a>
+                    </div>
+                    <div class="btv-cp-element btv-cp-compteur">
+                        <h3>Nombre de tweets</h3>
+                        <h4 id="btv-cp-nb-tweets"></h4>
+                    </div>
+                    <div class="btv-cp-element btv-cp-compteur">
+                        <h3>Temps écoulé</h3>
+                        <h4 id="btv-cp-temps">0:00:00</h4>
+                    </div>
+                </div>
+            </div>
+            <div id="podium-container">
+                <div id="podium"></div>
+                <ul id="podium-chiffres">
+                </ul>
+                <ul id="podium-labels">
+                </ul>
+            </div>
+            <div id="btv-bigtweet">
+            </div>
+        </div>
+
+    </body>
+</html>
--- a/client/podium-cp-tweets.html	Tue Feb 21 11:26:01 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,254 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-    <head>
-        <meta charset="utf-8" />
-        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
-        <title>controlpanel</title>
-        <meta name="description" content="" />
-        <link rel="stylesheet" href="css/base-metric.css" />
-        <link rel="stylesheet" href="css/controlpanel.css" />
-        <style type="text/css">
-            #podium-container {
-                position: absolute;
-                width: 1480px;
-                top: 600px;
-                left: 400px;
-            }
-            #podium {
-                width: 100%;
-                height: 300px;
-            }
-            #podium-labels {
-                position: absolute;
-                width: 100%;
-                top: 320px;
-            }
-            #podium-labels li {
-                float: left;
-                width: 25%;
-                color: #ffffff;
-                text-align: center;
-                font-size: 42px;
-            }
-            #podium-chiffres {
-                position: absolute;
-                width: 100%;
-                top: 240px;
-            }
-            #podium-chiffres li {
-                float: left;
-                width: 25%;
-                color: #000000;
-                text-align: center;
-                font-size: 50px;
-                font-weight: bold;
-            }
-            
-            
-            #btv-tweet {
-                position: absolute;
-                left: 775px;
-                top: 250px;
-                width: 650px;
-                background: #0031ff;
-                padding: 40px;
-                color: #ffffff;
-                font-size: 42px;
-                display: none;
-            }
-            .btv-tweet-image {
-                width: 100px;
-                height: 100px;
-                margin: 0 30px 30px 0;
-                float: left;
-            }
-            .btv-tweet-screen-name {
-                font-weight: bold;
-            }
-            .btv-tweet-name {
-                margin: 10px 0;
-            }
-            .btv-tweet-text {
-                clear: both;
-            }
-        </style>
-        
-        <script type="text/javascript" src="lib/jquery.min.js"></script>        
-        
-        <script type="text/javascript" src="lib/protoclass.js"></script>              
-        <script type="text/javascript" src="lib/box2d.js"></script>
-        <script type="text/javascript" src="js/tweetanim.js"></script>
-        <script type="text/javascript" src="js/tweetvote-anim.js"></script>     
-
-        <script type="text/javascript" src="js/podium.js"></script>
-        <script type="text/javascript" src="js/tweetsource.js"></script>
-        <script type="text/javascript">
-            var tzero = new Date() - 120000;
-            
-            function updateLastTweets() {
-                var _filtered = myTweetSource.afterDate(tzero),
-                    _txtFilter = $("#btv-cp-champ-filtre").val(),
-                    _reFilter = null;
-                if (_txtFilter.length > 1) {
-                    _filtered = _filtered.search(_txtFilter);
-                    _reFilter = new RegExp('(' + _txtFilter.replace(/\W/gim,'\\$1') + ')','gim');
-                }
-                $('#btv-cp-liste-tweets-tout').html(
-                    _filtered.reverse().slice(0,20).map(function(_t) {
-                        return '<li onclick="addTweet(\''
-                            + _t.id_str
-                            + '\'); return false;"><a title="Ajouter à la sélection" href="#"><span class="btv-cp-tweet-date">'
-                            + _t.created_at.match(/\d+:\d+:\d+/)[0]
-                            + '</span> <span class="btv-cp-tweet-from">'
-                            + ( _reFilter ? ('@' + _t.from_user).replace(_reFilter, '<span class="btv-cp-highlight">$1</span>') : ('@' + _t.from_user) )
-                            + '</span> <span class="btv-cp-tweet-text">'
-                            + ( _reFilter ? _t.text.replace(_reFilter, '<span class="btv-cp-highlight">$1</span>') : _t.text )
-                            + '</span><div class="btv-cp-tweet-button btv-cp-tweet-add"></div></a></li>'
-                    }).join('')
-                );
-            }
-            
-            function addTweet(tweetId) {
-                var _t = myTweetSource.tweetById(tweetId);
-                if (_t) {
-                    $("#btv-cp-liste-tweets-selection").prepend(
-                        '<li onclick="showTweet(\''
-                            + _t.id_str
-                            + '\'); return false;"><a title="Afficher sur l\'écran" href="#"><span class="btv-cp-tweet-date">'
-                            + _t.created_at.match(/\d+:\d+:\d+/)[0]
-                            + '</span> <span class="btv-cp-tweet-from">@'
-                            + _t.from_user
-                            + '</span> <span class="btv-cp-tweet-text">'
-                            + _t.text
-                            + '</span><div class="btv-cp-tweet-button btv-cp-tweet-show"></div></a></li>'
-                    );
-                }
-                console.log(_t);
-                TweetAnim.queueTweet(_t);
-                TweetAnim.shiftQueue();
-                
-            }
-            
-            function showTweet(tweetId) {
-                var _t = myTweetSource.tweetById(tweetId);
-                if (_t) {
-                    $("#btv-tweet").html('<img class="btv-tweet-image" src="'
-                    + _t.profile_image_url
-                    + '" /><p class="btv-tweet-screen-name">'
-                    + _t.from_user
-                    + '</p><p class="btv-tweet-name">'
-                    + _t.from_user_name
-                    +'</p><p class="btv-tweet-text">'
-                    + _t.text
-                    +'</p>').show();
-                    $(".btv-cp-hide-tweets").show();
-                }
-            }
-            
-            $(function() {
-                setInterval(function() {
-                    var _t = Math.floor((new Date() - tzero)/1000),
-                        _s = _t % 60,
-                        _m = Math.floor(_t/60) % 60,
-                        _h = Math.floor(_t/3600);
-                    $("#btv-cp-temps").html(
-                        _h  + ':' + (_m < 10 ? '0' : '') + _m + ':' + (_s < 10 ? '0' : '') + _s
-                    )
-                }, 500);
-                myPodium = new Btv_Podium([0,0,0,0]);
-                
-                var _keywords = ['Sarkozy', 'Hollande', 'candidat', 'France'];
-                
-                $("#podium-labels").html(_keywords.map(function(_w) {
-                    return '<li>' + _w + '</li>'
-                }).join(""));
-                
-                myTweetSource = new Btv_TweetSource({
-                    keywords: _keywords
-                });
-                
-                myTweetSource.setTweetsCallback(function() {
-                    var _filtered = this.afterDate(tzero);
-                    $("#btv-cp-nb-tweets").html(_filtered.count());
-                    var _counts = [];
-                    for (var _i = 0; _i < _keywords.length; _i++) {
-                        _counts.push(_filtered.search(_keywords[_i]).count());
-                    }
-                    updateLastTweets();
-                    myPodium.update(_counts);
-                    $("#podium-chiffres").html(_counts.map(function(_c) {
-                        return '<li>' + _c + '</li>'
-                    }).join(""));
-                });
-                
-                $("#btv-cp-champ-filtre").keyup(function() {
-                    updateLastTweets();
-                });
-                $("#btv-cp-clear-filtre").click(function() {
-                    $("#btv-cp-champ-filtre").val("");
-                    updateLastTweets();
-                    return false; 
-                });
-                $("#btv-tweet, .btv-cp-hide-tweets").click(function() {
-                    $("#btv-tweet, .btv-cp-hide-tweets").hide();
-                })
-            });
-            
-        </script>
-    </head>
-    <body>
-         <div id="canvas" width="6000" height="2000" style="background-color:#333333;" ></div>
-
-        <div id="btv-global-container">
-            <div id="btv-cp-container">
-                <div class="btv-cp-line">
-                    <div class="btv-cp-element">
-                        <h2>Bubble <b>TV</b></h2>
-                    </div>
-                    <div class="btv-cp-element" id="btv-cp-cont-filtre">
-                        <h3>Rechercher/Filtrer</h3>
-                        <input id="btv-cp-champ-filtre" />
-                        <a href="#" id="btv-cp-clear-filtre">x</a>
-                    </div>
-                    <div class="btv-cp-element btv-cp-cont-liste">
-                        <h3>Derniers tweets</h3>
-                        <ul class="btv-cp-liste-tweets" id="btv-cp-liste-tweets-tout">
-                        </ul>
-                    </div>
-                    <div class="btv-cp-element btv-cp-cont-liste">
-                        <h3>Tweets sélectionnés</h3>
-                        <ul class="btv-cp-liste-tweets" id="btv-cp-liste-tweets-selection">
-                        </ul>
-                        <a class="btv-cp-hide-tweets" href="#" style="display: none;">Cacher le tweet à l'écran</a>
-                    </div>
-                    <div class="btv-cp-element btv-cp-cont-pause" id="btv-cp-cont-pause-amont">
-                        <h3>Arrivée des tweets</h3>
-                        <a class="btv-cp-play-pause btv-cp-status-pause" href="#"></a>
-                    </div>
-                    <div class="btv-cp-element btv-cp-cont-pause" id="btv-cp-cont-pause-aval">
-                        <h3>Purge des colonnes</h3>
-                        <a class="btv-cp-play-pause btv-cp-status-pause" href="#"></a>
-                    </div>
-                    <div class="btv-cp-element btv-cp-compteur">
-                        <h3>Nombre de tweets</h3>
-                        <h4 id="btv-cp-nb-tweets"></h4>
-                    </div>
-                    <div class="btv-cp-element btv-cp-compteur">
-                        <h3>Temps écoulé</h3>
-                        <h4 id="btv-cp-temps">0:00:00</h4>
-                    </div>
-                </div>
-            </div>
-            <div id="podium-container">
-                <div id="podium"></div>
-                <ul id="podium-chiffres">
-                </ul>
-                <ul id="podium-labels">
-                </ul>
-            </div>
-            <div id="btv-tweet">
-            </div>
-        </div>
-
-    </body>
-</html>