Merge with cbbb959fab4c21e240b9820354a8879db3969d55 V01.03
authorYves-Marie Haussonne <1218002+ymph@users.noreply.github.com>
Tue, 29 Nov 2011 15:41:52 +0100
changeset 393 1ec7b057a8bd
parent 392 aa445cd7300e (current diff)
parent 391 698e4280d270 (diff)
child 394 6c24bf2073c9
Merge with cbbb959fab4c21e240b9820354a8879db3969d55
script/virtualenv/res/sqlalchemy-default.tar.gz
--- a/tweetcast/nodejs-bis/client/css/style.css	Tue Nov 29 15:41:15 2011 +0100
+++ b/tweetcast/nodejs-bis/client/css/style.css	Tue Nov 29 15:41:52 2011 +0100
@@ -22,22 +22,169 @@
 }
 
 body {
-	font-family: Helvetica, Arial, sans-serif;
+	font-family: Helvetica, Arial, sans-serif; background-color: #F7F6F6; background-image: url("../img/bgd.jpg"); background-repeat: repeat-x;
+}
+
+b {
+    font-weight: bold;
+}
+
+.highlight {
+    background: #ffff00;
 }
 
 #container {
-    margin: 20px;
+    width: 960px; margin: 0 auto;
+}
+
+#colgauche {
+    float: left; width: 455px; margin-right: 13px;
+}
+
+.barre {
+    float: left; width: 100%;
+}
+
+.greyed {
+    color: #999; font-style: italic;
+}
+
+.rechercheCourante {
+    background: #ffa0ff; font-weight: bold; color: #000080;
+}
+
+/* Menu */
+
+#headlogo {
+    float: left; margin-right: 10px;
 }
 
-/* Barre */
-.barre  {
-    float: left; width: 100%;
+.menu {
+    border-left: 1px solid #C3C3C3;
+    float: left;
+    list-style: none;
+    font-size: 12px;
+    height: 62px; overflow: hidden;
+}
+
+.menu li {
+    background: url("../img/menu_underline.gif") left bottom no-repeat;
+    padding: 3px 0 0 5px;
+    height: 18px;
+    min-width: 80px;
+}
+
+.menu a {
+    color: #000000; text-decoration: none;
+}
+
+.menu a:hover {
+    color: #0099FF;
+}
+
+/* Formulaire */
+
+#twwWrap {
+    float: left; width: 450px; background: #ffffff; padding: 1px; border-width: 1px; border-style: solid solid none solid; border-color: #ababab; margin-top: 6px;
+}
+
+#tweetWriter {
+    width: 430px; padding: 10px; background: #efefef;
 }
 
 /* Liste de Tweets */
 
+#tweetviz {
+    float: left; width: 452px; border: 1px solid #999;
+}
+
+/* Recherche */
+
+#recherche {
+    position: relative; float: left; padding: 2px 0; width: 452px; border-bottom: 1px solid #999;
+}
+
+#recherche input {
+    float: left;
+}
+
+#inp_q {
+    width: 236px; border: none; padding: 1px; margin-left: 2px; height: 17px; font-size: 13px;
+}
+
+#inp_submit, #inp_reset {
+    border: 0; padding: 0; width: 20px; height: 20px; overflow: hidden; text-indent: 800px; background: url(../img/searchcancel.png)
+}
+
+#inp_submit:hover {
+    background-position: -20px 0;
+}
+
+#inp_submit:active {
+    background-position: -40px 0;
+}
+
+#inp_reset {
+    background-position: 0 -20px;
+}
+
+#inp_reset:hover {
+    background-position: -20px -20px;
+}
+
+#inp_reset:active {
+    background-position: -40px -20px;
+}
+
+#time_legende {
+    float: left; margin-left: 30px; width: 30px; height: 20px; background: url(../img/scale.png) left;
+}
+
+#time_scale {
+    float: left; font-size: 12px; margin: 3px 0 0; color: #666; width: 50px; text-align: center;
+}
+
+#time_zoomout, #time_zoomin {
+    float: left; width: 12px; height: 20px; background: url(../img/scale.png);
+}
+
+#time_zoomout {
+    background-position: -30px;
+}
+
+#time_zoomout.inactive {
+    background-position: -54px;
+}
+
+#time_zoomin {
+    background-position: -42px;
+}
+
+#time_zoomin.inactive {
+    background-position: -66px;
+}
+
+#recherche_annot {
+    position: absolute; top: 20px; z-index: 4; background: #ffffff; border: 1px solid #ccc; padding: 4px; font-size: 12px;
+    display: none; box-shadow: 2px 2px 2px rgba(0, 0, 0, .5)
+}
+
+#recherche_annot a {
+    padding: 1px; line-height: 13px; margin: 1px; font-weight: bold; text-decoration: none; color: #000000;
+}
+
+/* Liste des tweets */
+
 #tweetlist {
-	float: left; width: 280px; height: 450px; list-style: none; border: 1px solid #999; color: #585858; cursor: pointer; cursor: hand;
+	float: left; width: 280px; height: 480px; list-style: none; border-right: 1px solid #999; color: #585858; cursor: pointer; cursor: hand; background: #ffffff;
+}
+
+#tweetlist a {
+    text-decoration: none; color: #1985B5;
+}
+
+#tweetlist a:hover {
+    text-decoration: underline; color: #105060;
 }
 
 li.tweet, li.placeholder {
@@ -49,7 +196,7 @@
 }
 
 li.full {
-    width: 270px; height: 84px; border-right: 10px solid #ff0;
+    width: 270px; height: 117px; border-right: 10px solid #ff0;
 }
 
 li.half {
@@ -69,7 +216,7 @@
 }
 
 .full p.tweet_text {
-	font-size: 12px; margin: 5px 0 5px 58px; height: 75px; width: 207px; color: #000000;
+	font-size: 12px; margin: 5px 0 5px 58px; height: 108px; width: 207px; color: #000000;
 }
 
 .half p.tweet_text {
@@ -92,14 +239,10 @@
     margin: 2px; width: 16px; height: 16px;
 }
 
-.full p.created_at {
+p.created_at {
 	font-size: 12px; text-align: center; font-style: italic; color: #999999; width: 58px; overflow: hidden;
 }
 
-.half p.created_at, .icons p {
-    display: none
-}
-
 .annotations {
     position: absolute; margin: 0; padding: 0; top: 0; left: 0; width: 100%; height: 100%; 
 }
@@ -116,26 +259,28 @@
     position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 2; overflow: hidden;
 }
 
+div.tweet_actions {
+    position: absolute; bottom : 2px; right: 4px; font-size: 11px;
+}
+
 /* timeline */
 
 #timeline {
-    float: left; height: 450px; width: 150px; border-width: 1px; border-style: solid solid solid none; border-color: #999;  cursor: pointer; cursor: hand;
+    float: left; height: 480px; width: 150px; border-right: 1px solid #999; cursor: pointer; cursor: hand;
 }
 
-
-
 #scrollcont {
-    float: left; width: 20px; height: 452px; overflow: auto;
+    float: left; width: 20px; height: 480px; overflow: auto;
 }
 
 #scrollin {
-    width: 1px; height: 10000px;
+    width: 1px; height: 8000px;
 }
 
 /* hovertweet */
 
 #hovertweet {
-    position: absolute; display: none; margin: -20px 0 0 15px;
+    position: absolute; display: none; margin: -20px 0 0 15px; z-index: 12;
 }
 
 div.full {
@@ -146,8 +291,46 @@
     position: absolute; width: 10px; height: 18px; left: -9px; top: 13px;  background: url(../img/arrow.png);
 }
 
+/* Colonne de droite */
+
+#coldroite {
+    float: left; width: 492px;
+}
+
+#vlWrap {
+    float: left; border: 5px solid #ffffff; background: #999999; padding: 1px; margin-top: 20px;
+}
+
+#videoLivePlayer {
+    width: 480px; height: 320px; background: #000000;
+}
+
+#out_fleche {
+    float: left; position: relative; width: 492px; height: 14px; background: url(../img/bgnoarrow.png);
+}
+
+#in_fleche {
+    position: absolute; left: 10px; width: 27px; height: 15px; background: url(../img/arrowtop.png);
+}
+
+#accordeon {
+    float: left; width: 492px; list-style: none; background: #777777;
+}
+
+#accordeon li {
+    float: left; width: 480px; margin: 0 1px 1px 1px; padding: 4px; border: 1px solid #ffffff; background: #efefef;
+}
+
+#accordeon li.deplie {
+    background: url(../img/bgdeplie.png) top repeat-x #efefef;
+}
+
 /* Tag Cloud */
 
 #motscles {
-    float: left; width: 400px; height: 100px; text-align: center; border: 1px solid #999; margin: 0 20px;
+    text-align: center;
 }
+
+#motscles span {
+    padding: 2px; cursor: pointer; cursor: hand;
+}
Binary file tweetcast/nodejs-bis/client/img/arrowtop.png has changed
Binary file tweetcast/nodejs-bis/client/img/bgd.jpg has changed
Binary file tweetcast/nodejs-bis/client/img/bgdeplie.png has changed
Binary file tweetcast/nodejs-bis/client/img/bgnoarrow.png has changed
Binary file tweetcast/nodejs-bis/client/img/head_logo.gif has changed
Binary file tweetcast/nodejs-bis/client/img/menu_underline.gif has changed
Binary file tweetcast/nodejs-bis/client/img/placeholder.png has changed
Binary file tweetcast/nodejs-bis/client/img/searchcancel.png has changed
--- a/tweetcast/nodejs-bis/client/index.html	Tue Nov 29 15:41:15 2011 +0100
+++ b/tweetcast/nodejs-bis/client/index.html	Tue Nov 29 15:41:52 2011 +0100
@@ -6,34 +6,78 @@
         <script type="text/javascript" src="js/jquery-1.6.4.min.js"></script>
         <script type="text/javascript" src="config.js"></script>
         <script type="text/javascript">
-        if (typeof STANDALONE_APP == "undefined" || !STANDALONE_APP) {
-            document.write('<script type="text/javascript" src="/socket.io/socket.io.js"><' + '/script>');
-        }
+            if( typeof STANDALONE_APP == "undefined" || !STANDALONE_APP) {
+                document.write('<script type="text/javascript" src="/socket.io/socket.io.js"><' + '/script>');
+            }
         </script>
         <script type="text/javascript" src="js/raphael-min.js"></script>
         <script type="text/javascript" src="js/jquery.mousewheel.min.js"></script>
+        <script type="text/javascript" src="js/underscore-min.js"></script>
         <script type="text/javascript" src="js/script.js"></script>
         <link rel="stylesheet" href="css/style.css" type="text/css" />
     </head>
     <body>
         <div id="container">
-            <div class="barre">
-                <div id="upbutton" onclick="movePos(1)"></div>
+            <div id="colgauche">
+                <div class="barre">
+                    <img id="headlogo" src="img/head_logo.gif" width="171" height="63" />
+                    <ul class="menu">
+                        <li>
+                            <a class="menuLink" href="#">Accueil</a>
+                        </li>
+                        <li>
+                            <a class="menuLink" href="#">Programme</a>
+                        </li>
+                        <li>
+                            <a class="menuLink" href="#">A propos</a>
+                        </li>
+                    </ul>
+                </div>
+                <div id="twwWrap">
+                    <div id="tweetWriter">
+                        <h3>Annotations polémiques</h3>
+                    </div>
+                </div>
+                <div id="tweetviz">
+                    <div class="barre">
+                        <form id="recherche">
+                            <input autocomplete="off" class="greyed" id="inp_q" value="Rechercher" />
+                            <input id="inp_submit" type="submit" />
+                            <input id="inp_reset" type="reset" />
+                            <div id="time_controls">
+                                <div id="time_legende"></div>
+                                <div id="time_scale"></div>
+                                <a href="#" id="time_zoomout"></a>
+                                <a href="#" id="time_zoomin"></a>
+                            </div>
+                            <div id="recherche_annot">
+                                Recherche par annotation : <span id="rech_list_annot"></span><br />
+                            </div>
+                        </form>
+                    </div>
+                    <ul id="tweetlist"></ul>
+                    <div id="timeline"></div>
+                    <div id="scrollcont">
+                        <div id="scrollin"></div>
+                    </div>
+                </div>
             </div>
-            <ul id="tweetlist">
-            </ul>
-            <div id="timeline"></div>
-            <div id="scrollcont">
-                <div id="scrollin"></div>
-            </div>
-            <div class="barre">
-                <div id="downbutton" onclick="movePos(-1)"></div>
+            <div id="coldroite">
+                <div id="vlWrap">
+                    <div id="videoLivePlayer"></div>
+                </div>
+                <div id="out_fleche">
+                    <div id="in_fleche"></div>
+                </div>
+                <ul id="accordeon">
+                    <li><h3>Nuage de mots-clés</h3></li>
+                    <li class="deplie" id="motscles"></li>
+                </ul>
             </div>
         </div>
-            <div id="motscles"></div>
-            <div id="hovertweet">
-                <div id="hovercontent"></div>
-                <div id="hoverarrow"></div>
-            </div>
+        <div id="hovertweet">
+            <div id="hovercontent"></div>
+            <div id="hoverarrow"></div>
+        </div>
     </body>
 </html>
\ No newline at end of file
--- a/tweetcast/nodejs-bis/client/js/script.js	Tue Nov 29 15:41:15 2011 +0100
+++ b/tweetcast/nodejs-bis/client/js/script.js	Tue Nov 29 15:41:52 2011 +0100
@@ -5,35 +5,37 @@
 var socket,
     tlPaper,
     twCx = {
-        zoomLevel : 1,
         followLast : true,
-        position : 0,
+        position : "0",
         date_levels : [
+            3600 * 1000,
             15 * 60 * 1000,
             5 * 60 * 1000,
-            60 * 1000,
-            15 * 1000
+            60 * 1000
         ],
-        timeLevel : 0,
+        timeLevel : 1,
         deltaX : 40,
         tlWidth : 150,
-        tlHeight : 450,
+        tlHeight : 480,
         globalWords : {},
         refMouse : { x : 0, y : 0},
         refPosTl : { x : 0, y : 0},
         tlMouseMoved : false,
-        tlMouseClicked : false
+        tlMouseClicked : false,
+        filtre : null
         },
     tlBuffer = '',
     relHover = [],
     wheelDelta = 0,
+    scrollEnabled = false,
+    scrollExtent = 8000 - 480,
+    lastScrollPos = 0,
     rx_url = /https?:\/\/[0-9a-zA-Z\.%\/-_]+/g,
     rx_word = /[^ \.&;,'"!\?\d\(\)\+\[\]\\\…\-«»:\/]{3,}/g,
     stop_list = [ 'and', 'avec', 'aux', 'car', 'comme', 'dans', 'donc', 'des', 'elle', 'est', 'être', 'eux', 'ils', 'les', 'leur', 'leurs', 'mes', 'mon', 'tes', 'ton', 'notre', 'nos', 'nous', 'ont', 'pas', 'que', 'qui', 'sont', 'the', 'une', 'votre', 'vos', 'vous' ];
 
 function getColor(annotation, lum) {
-//    console.log(annotations[annotation].h, annotations[annotation].s, lum, Raphael.hsl(annotations[annotation].h, annotations[annotation].s, lum))
-    return Raphael.hsl(annotations[annotation].colors.h, annotations[annotation].colors.s, lum);
+    return Raphael.hsl2rgb(annotations[annotation].colors.h, annotations[annotation].colors.s, lum);
 }
 
 function arc(source, target) {
@@ -167,9 +169,16 @@
 }
 
 function trimFDS() {
-    var slices = flattenDateStruct(twCx.timeline, twCx.timeLevel),
+    var slices = flattenDateStruct(twCx.timeline, twCx.timeLevel);
+    while (slices[0].tweets.length == 0) {
+        slices.splice(0,1);
+    }
+    while (slices[slices.length - 1].tweets.length == 0) {
+        slices.pop();
+    }    
+    var centralTweet = ( twCx.centralTweet ? twCx.centralTweet : twCx.tweets[twCx.tweets.length - 1] ),
         delta = 30 * twCx.date_levels[twCx.timeLevel],
-        centre = Math.min(slices[slices.length - 1].end - delta , Math.max(slices[0].start + delta, twCx.tweets[twCx.position].date_value)),
+        centre = Math.min(slices[slices.length - 1].end - delta , Math.max(slices[0].start + delta, centralTweet.date_value)),
         min = centre - delta,
         max = centre + delta;
     while (slices[0].start < min) {
@@ -225,25 +234,27 @@
 }
 
 function selectTweet(tweetid) {
-    var pos = twCx.idIndex.indexOf(tweetid);
-    if (pos != -1) {
-        twCx.position = pos;
-        twCx.followLast = (twCx.position == twCx.tweets.length - 1);
-        updateDisplay()
-    }
+    twCx.position = tweetid;
+    twCx.followLast = (twCx.position == twCx.idIndex[twCx.tweets.length - 1]);
+    updateDisplay();
 }
 
 function goToPos(nPos) {
-    twCx.position = Math.min( twCx.tweets.length - 1, Math.max(0, nPos ) );
-    twCx.followLast = (twCx.position == twCx.tweets.length - 1);
+    twCx.position = twCx.currentIdIndex[Math.min( twCx.currentIdIndex.length - 1, Math.max(0, nPos ) )];
+    twCx.followLast = (!twCx.filtre && nPos == twCx.tweets.length - 1);
     updateDisplay();
 }
 
 function movePos(delta) {
-    goToPos( delta + twCx.position );
+    goToPos( delta + twCx.currentIdIndex.indexOf(twCx.position) );
 }
 
 function tweetToHtml(tweet, className, elName) {
+    
+    function highlight(texte) {
+        return ( twCx.filtre ? texte.replace(twCx.filtre, '<span class="highlight">$1</span>' ) : texte );
+    }
+    
     if (!tweet) {
         return placeHolder(className);
     }
@@ -260,12 +271,12 @@
     if (tweet.annotations.length) {
         html += '<div class="annotations">';
         for (var i in tweet.annotations) {
-            html += '<div class="annotation" style="width:' + (100/tweet.annotations.length) + '%; background:' + getColor(tweet.annotations[i], (className == 'icons' ? .4 : .8)) + '"></div>';
+            html += '<div class="annotation" style="width:' + (100/tweet.annotations.length) + '%; background:' + getColor(tweet.annotations[i], (className == 'icons' ? .4 : .85)).hex + '"></div>';
         }
         html += '</div>';
     }
     html += '<div class="twmain">';
-    a_user = '<a href="http://twitter.com/' + tweet.user.screen_name + '" var target="_blank" title="' + tweet.user.name + '">';
+    a_user = '<a href="http://twitter.com/' + tweet.user.screen_name + '" var target="_blank">';
     html += '<div class="around_img">' + a_user + '<img class="profile_image" src="' + tweet.user.profile_image_url + '" /></a>';
     if (className == 'full') {
         html += '<p class="created_at">' + new Date(tweet.date_value).toTimeString().substr(0,8) + '</p>';
@@ -279,7 +290,8 @@
             entities.push({
                 "start" : tweet.entities.hashtags[i].indices[0],
                 "end" : tweet.entities.hashtags[i].indices[1],
-                "html" : '<a href="http://twitter.com/search?q=%23' + tweet.entities.hashtags[i].text + '" target="_blank">#' + tweet.entities.hashtags[i].text + '</a>'
+                "link" : '<a href="http://twitter.com/search?q=%23' + tweet.entities.hashtags[i].text + '" target="_blank">',
+                "text" : '#' + tweet.entities.hashtags[i].text
             });
         }
         for (var i in tweet.entities.urls) {
@@ -291,23 +303,30 @@
             entities.push({
                 "start" : tweet.entities.urls[i].indices[0],
                 "end" : tweet.entities.urls[i].indices[1],
-                "html" : '<a href="' + linkurl  + '" target="_blank">' + dispurl + '</a>'
+                "link" : '<a href="' + linkurl  + '" target="_blank">',
+                "text" : dispurl
             });
         }
         for (var i in tweet.entities.user_mentions) {
             entities.push({
                 "start" : tweet.entities.user_mentions[i].indices[0],
                 "end" : tweet.entities.user_mentions[i].indices[1],
-                "html" : '<a href="http://twitter.com/' + tweet.entities.user_mentions[i].screen_name + '" target="_blank" title="' + tweet.entities.user_mentions[i].name + '">@' + tweet.entities.user_mentions[i].screen_name + '</a>'
+                "link" : '<a href="http://twitter.com/' + tweet.entities.user_mentions[i].screen_name + '" target="_blank">',
+                "text" : '@' + tweet.entities.user_mentions[i].screen_name
             });
         }
         entities.sort(function(a, b) { return a.start - b.start });
         for (var i in entities) {
-            txt += tweet.text.substring(lastend, entities[i].start) + entities[i].html;
+            txt += highlight( tweet.text.substring(lastend, entities[i].start) ) + entities[i].link + highlight( entities[i].text ) + '</a>';
             lastend = entities[i].end;
         }
-        txt += tweet.text.substring(lastend);
-        html += '<p class="tweet_text"><b>' + a_user + '@' + tweet.user.screen_name + '</b></a>: ' + txt + '</p>';
+        txt += highlight( tweet.text.substring(lastend) );
+        html += '<p class="tweet_text"><b>' + a_user + highlight('@' + tweet.user.screen_name) + '</a>' + ( className == 'full' ? ' (' + tweet.user.name + ')</b><br />' : '</b> : ') + txt + '</p>';
+        if (className == 'full' && el == 'li') {
+            html += '<div class="tweet_actions"><a href="http://twitter.com/intent/tweet?in_reply_to=' + tweet.id + '" target="_blank">répondre</a> · ';
+            html += '<a href="http://twitter.com/intent/retweet?tweet_id=' + tweet.id + '" target="_blank">retweeter</a> · ';
+            html += '<a href="http://twitter.com/intent/favorite?tweet_id=' + tweet.id + '" target="_blank">favori</a></div>';
+        }
     }
     html += '</div></' + el + '>';
     return html;
@@ -340,6 +359,9 @@
 }
 
 function tlPosTweet(tweet, annotation) {
+    if (!twCx.tweets) {
+        return;
+    }
     var x,
         y,
         dt = tweet.date_value,
@@ -436,33 +458,50 @@
 }
 
 function updateDisplay() {
-    var p = twCx.position,
-        l = twCx.tweets.length,
+    if (!twCx.tweets) {
+        return;
+    }
+    if (twCx.filtre) {
+        var tweets = twCx.tweets.filter(function(tweet) {
+            var mention = '@' + tweet.user.screen_name;
+            return ( tweet.text.search(twCx.filtre) != -1 ) || ( mention.search(twCx.filtre) != -1 );
+        });
+        $("#inp_q").val(twCx.filtreTexte + ' (' + tweets.length + ' tweets)');
+        if (tweets.length) {
+            var idIndex = tweets.map(function(tweet) {
+                return tweet.id;
+            });
+            var p = idIndex.indexOf(twCx.position);
+            if (p == -1) {
+                for (p = idIndex.length - 1; p > 0 && idIndex[p] > twCx.position; p--) {
+                }
+            }
+            twCx.position = idIndex[p];
+            twCx.currentIdIndex = idIndex;
+        }
+        
+    } else {
+        twCx.currentIdIndex = twCx.idIndex;
+        var tweets = twCx.tweets;
+        var p = twCx.idIndex.indexOf(twCx.position);
+        if (p == -1) {
+            p = (twCx.followLast ? twCx.idIndex.length - 1 : 0);
+        }
+    }
+
+    var l = tweets.length,
         lines = 0,
         ppy = 0,
         html = '',
         tweetsOnDisplay = [],
         localWords = {};
     
-    if (p == 0) {
-        $("#downbutton").addClass("inactive");
-    } else {
-        $("#downbutton").removeClass("inactive");
-    }
-    
-    if (p == l-1) {
-        $("#upbutton").addClass("inactive");
-    } else {
-        $("#upbutton").removeClass("inactive");
-    }
-    
-    
     function pushTweet(tp, className) {
         if (tp < l && tp >= 0) {
-            html += tweetToHtml(twCx.tweets[tp], className)
+            html += tweetToHtml(tweets[tp], className)
             tweetsOnDisplay.push(tp);
-            for (var i in twCx.tweets[tp].words) {
-                var w = twCx.tweets[tp].words[i];
+            for (var i in tweets[tp].words) {
+                var w = tweets[tp].words[i];
                 if (localWords[w]) {
                     localWords[w].freq++
                 } else {
@@ -476,8 +515,8 @@
                         }
                     }
                 }
-                for (var j in twCx.tweets[tp].annotations) {
-                    localWords[w].annotations[twCx.tweets[tp].annotations[j]]++;
+                for (var j in tweets[tp].annotations) {
+                    localWords[w].annotations[tweets[tp].annotations[j]]++;
                 }
             }
         } else {
@@ -485,97 +524,123 @@
         }
     }
     
-    if (l > p + 18) {
-        lines++;
-        ppy += 20;
-        for (var i = p + 31; i >= p + 18; i--) {
-            pushTweet(i, 'icons');
-        }
-    }
-    if (l > p + 4) {
-        lines++;
-        ppy += 20;
-        for (var i = p + 17; i >= p + 4; i--) {
-            pushTweet(i, 'icons');
-        }
-    }
-    for (var k = 3; k >= 1; k--) {
-        if (l > p + k) {
-            ppy += 47;
+    if (l) {
+    
+        lastScrollPos = Math.floor( scrollExtent * ( 1 - ( p / l ) ) );
+        $("#scrollcont").scrollTop(lastScrollPos);
+        
+        if (l > p + 18) {
             lines++;
-            pushTweet(p + k, 'half');
-        }
-    }
-    pushTweet(p, 'full');
-    var n = p - 1;
-    for (var i = 0; i < Math.min(6, Math.max(3, 6 - lines)); i++) {
-        if (n < 0) {
-            break;
-        }
-        pushTweet(n, 'half');
-        n--;
-    }
-    for (var i = 0; i < 14 * Math.min(4, Math.max(2, 7 - lines)); i++) {
-        if (n < 0) {
-            break;
+            ppy += 20;
+            for (var i = p + 31; i >= p + 18; i--) {
+                pushTweet(i, 'icons');
+            }
         }
-        pushTweet(n, 'icons');
-        n--;
-    }
-    if (html != tlBuffer) {
-        $("#tweetlist").html(html);
-        $(".tweet.full").fadeIn();
-        tlBuffer = html;
-    }
-    
-    for (var j in localWords) {
-        if (localWords[j].freq < 2) delete localWords[j];
-    }
-    var tab = [];
-    for (var j in localWords) {
-        tab.push({
-            "word": j,
-            "freq" : localWords[j].freq,
-            "annotations" : localWords[j].annotations,
-            "score" : localWords[j].freq / Math.log(1+twCx.globalWords[j])
-        });
-    }
-    tab.sort( function(a,b){ return ( b.score - a.score ) }).splice(20);
-    var minfreq = tab[tab.length - 1].score,
-        maxfreq = Math.max(minfreq + .1, tab[0].score),
-        echfreq = 8 / Math.sqrt( maxfreq - minfreq ),
-        html = '';
-    for (var j in tab) {
-        var maxann = 0,
-            ann = "default";
-        for (var k in tab[j].annotations) {
-            if (tab[j].annotations[k] == maxann) {
-                ann = "default";
+        if (l > p + 4) {
+            lines++;
+            ppy += 20;
+            for (var i = p + 17; i >= p + 4; i--) {
+                pushTweet(i, 'icons');
             }
-            if (tab[j].annotations[k] > maxann) {
-                ann = k;
-                maxann = tab[j].annotations[k];
+        }
+        for (var k = 3; k >= 1; k--) {
+            if (l > p + k) {
+                ppy += 47;
+                lines++;
+                pushTweet(p + k, 'half');
             }
         }
-        var coul = (ann == "default" ? '' : ' background: ' + getColor(ann, 1 - .4 * ( tab[j].annotations[ann] / tab[j].freq ) ) + ';"'),
-            fontsize = Math.floor( ( 12 + Math.sqrt( tab[j].score - minfreq ) * echfreq ) );
-        html += '<span style="padding: 2px; line-height: ' + (8 + fontsize) + 'px; font-size: ' + fontsize + 'px;' + coul + '">' + tab[j].word + '</span> ';
+        pushTweet(p, 'full');
+        var n = p - 1;
+        for (var i = 0; i < Math.min(6, Math.max(3, 6 - lines)); i++) {
+            if (n < 0) {
+                break;
+            }
+            pushTweet(n, 'half');
+            n--;
+        }
+        for (var i = 0; i < 14 * Math.min(4, Math.max(2, 7 - lines)); i++) {
+            if (n < 0) {
+                break;
+            }
+            pushTweet(n, 'icons');
+            n--;
+        }
+        if (html != tlBuffer) {
+            $("#tweetlist").html(html);
+            $(".tweet.full").fadeIn();
+            tlBuffer = html;
+        }
+        
+        /* Recherche des mots pertinents correspondant à la sélection */
+        
+        var tab = _(localWords).map(function(v, k) {
+            return {
+                "word": k,
+                "freq" : v.freq,
+                "annotations" : v.annotations,
+                "score" : v.freq / Math.log( 2 + twCx.globalWords[j] )
+            };
+        }).filter(function(v) {
+            return v.freq > 1;
+        });
+        
+        if (tab.length) {
+            
+            tab = _(tab).sortBy( function(a) { return ( - a.score ) }).slice(0,20);
+            var minfreq = _(tab).min( function(a) { return a.freq} ).freq,
+                maxfreq = Math.max(minfreq + .1, _(tab).max( function(a) { return a.freq} ).freq),
+                echfreq = 8 / Math.sqrt( maxfreq - minfreq ),
+                html = '';
+            for (var j in tab) {
+                var maxann = 0,
+                    ann = "default";
+                for (var k in tab[j].annotations) {
+                    if (tab[j].annotations[k] == maxann) {
+                        ann = "default";
+                    }
+                    if (tab[j].annotations[k] > maxann) {
+                        ann = k;
+                        maxann = tab[j].annotations[k];
+                    }
+                }
+                if (ann == "default") {
+                    var coul = '';
+                } else {
+                    var c = getColor(ann, .6),
+                        coul = "background: rgba(" + [ Math.floor(c.r), Math.floor(c.g), Math.floor(c.b), ( tab[j].annotations[ann] / tab[j].freq )].join(',') + ")";
+                }
+                var fontsize = Math.floor( ( 12 + Math.sqrt( tab[j].freq - minfreq ) * echfreq ) );
+                html += '<span style="line-height: ' + (8 + fontsize) + 'px; font-size: ' + fontsize + 'px;' + coul + '" onclick="filtrerTexte(\'' + tab[j].word.replace(/('|")/g, '\\$1') + '\')">' + tab[j].word + '</span> ';
+            }
+            $("#motscles").html(html);
+        } else {
+            $("#motscles").html('');
+        }
+        twCx.centralTweet = tweets[p];
+    } else {
+        $("#tweetlist").html('');
+        tlBuffer = '';
+        $("#motscles").html('');
     }
-    $("#motscles").html(html);
     
     twCx.tlOnDisplay = trimFDS();
     twCx.scaleY = twCx.tlHeight / twCx.tlOnDisplay.length;
     var maxTweets = 0,
         startTl = 0,
-        endTl = twCx.tlOnDisplay.length - 1,
-        startTw = twCx.tweets[tweetsOnDisplay[tweetsOnDisplay.length - 1]].date_value,
-        endTw = twCx.tweets[tweetsOnDisplay[0]].date_value;
+        endTl = twCx.tlOnDisplay.length - 1;
+    if (l) {
+        var startTw = tweets[tweetsOnDisplay[tweetsOnDisplay.length - 1]].date_value,
+            endTw = tweets[tweetsOnDisplay[0]].date_value;
+    }
     for (var i = 0; i < twCx.tlOnDisplay.length; i++) {
-        if (startTw >= twCx.tlOnDisplay[i].start && startTw < twCx.tlOnDisplay[i].end) {
-            startTl = i;
-        }
-        if (endTw >= twCx.tlOnDisplay[i].start && endTw < twCx.tlOnDisplay[i].end) {
-            endTl = i;
+        if (l) {
+            if (startTw >= twCx.tlOnDisplay[i].start && startTw < twCx.tlOnDisplay[i].end) {
+                startTl = i;
+            }
+            if (endTw >= twCx.tlOnDisplay[i].start && endTw < twCx.tlOnDisplay[i].end) {
+                endTl = i;
+            }
         }
         var displayData = {};
         for (var j in annotations) {
@@ -607,31 +672,31 @@
     relHover = null;
     
     // Dessin de la correspondance liste-timeline
-    
-    var startY = twCx.tlHeight - startTl * twCx.scaleY,
-        endY = twCx.tlHeight - ( endTl + 1 ) * twCx.scaleY,
-        path = "M0 " + twCx.tlHeight + "C" + .7*twCx.deltaX + " " + twCx.tlHeight + " " + .3*twCx.deltaX + " " + startY + " " + twCx.deltaX + " " + startY + "L" + twCx.tlWidth + " " + startY + "L" + twCx.tlWidth + " " + endY + "L" + twCx.deltaX + " " + endY + "C" + .3*twCx.deltaX + " " + endY + " " + .7*twCx.deltaX + " 0 0 0";
-    tlPaper.path( path ).attr({ "stroke" : "none", "fill" : "#000080", "opacity" : .2 });
-        
+    if (l) {
+        var startY = twCx.tlHeight - startTl * twCx.scaleY,
+            endY = twCx.tlHeight - ( endTl + 1 ) * twCx.scaleY,
+            path = "M0 " + twCx.tlHeight + "C" + .7*twCx.deltaX + " " + twCx.tlHeight + " " + .3*twCx.deltaX + " " + startY + " " + twCx.deltaX + " " + startY + "L" + twCx.tlWidth + " " + startY + "L" + twCx.tlWidth + " " + endY + "L" + twCx.deltaX + " " + endY + "C" + .3*twCx.deltaX + " " + endY + " " + .7*twCx.deltaX + " 0 0 0";
+        tlPaper.path( path ).attr({ "stroke" : "none", "fill" : "#000080", "opacity" : .2 });
+    }   
     // dessin de la date de début
     
-    tlPaper.text(2, twCx.tlHeight - 7, new Date(twCx.tlOnDisplay[0].start).toTimeString().substr(0,5))
-        .attr({ "text-anchor" : "start", "font-size": "9px" });
+    tlPaper.text(twCx.deltaX / 2, twCx.tlHeight - 7, new Date(twCx.tlOnDisplay[0].start).toTimeString().substr(0,5))
+        .attr({ "text-anchor" : "middle", "font-size": "9px" });
     
     // dessin de la date de fin
     
-    tlPaper.text(2, 7, new Date(twCx.tlOnDisplay[twCx.tlOnDisplay.length - 1].end).toTimeString().substr(0,5))
-        .attr({ "text-anchor" : "start", "font-size": "9px" });
+    tlPaper.text(twCx.deltaX / 2, 7, new Date(twCx.tlOnDisplay[twCx.tlOnDisplay.length - 1].end).toTimeString().substr(0,5))
+        .attr({ "text-anchor" : "middle", "font-size": "9px" });
     
     for (var i = 0; i < twCx.tlOnDisplay.length; i++) {
         var n = 0,
             posY = twCx.tlHeight - ( i + 1 ) * twCx.scaleY;
         for (var j in twCx.tlOnDisplay[i].displayData) {
-            var l = twCx.tlOnDisplay[i].displayData[j].length;
-            if (l > 0) {
-                tlPaper.rect( twCx.deltaX + n * twCx.scaleX, posY, l * twCx.scaleX, twCx.scaleY )
-                    .attr({"stroke" : "none", "fill" : getColor(j, .4) });
-                n += l;
+            var ll = twCx.tlOnDisplay[i].displayData[j].length;
+            if (ll > 0) {
+                tlPaper.rect( twCx.deltaX + n * twCx.scaleX, posY, ll * twCx.scaleX, twCx.scaleY )
+                    .attr({"stroke" : "none", "fill" : getColor(j, .4).hex });
+                n += ll;
             }
         }
         
@@ -639,27 +704,62 @@
         
         if (i < twCx.tlOnDisplay.length - 1 && !(twCx.tlOnDisplay[i].end % 1800000)) {
             tlPaper.path("M0 "+posY+"L" + twCx.tlWidth +" "+posY).attr({"stroke":"#ccc"});
-            tlPaper.text(2, posY, new Date(twCx.tlOnDisplay[i].end).toTimeString().substr(0,5)).attr({ "text-anchor" : "start", "font-size": "9px" });
+            tlPaper.text(twCx.deltaX / 2, posY, new Date(twCx.tlOnDisplay[i].end).toTimeString().substr(0,5)).attr({ "text-anchor" : "middle", "font-size": "9px" });
         }
     }
     
     // dessin du tweet courant
     
-    
-    var posp = tlPosTweet(twCx.tweets[p]);
-    if (posp) {
+    if (l) {
+        
+        if (twCx.filtre) {
+            for (var i = 0; i < tweets.length; i++) {
+                if (i != p) {
+                    var pos = tlPosTweet(tweets[i]);
+                    if (pos) {
+                        drawTweetPos(pos, "#ffccff");
+                    }
+                }
+            }
+            
+        }
         
-        drawTweetPos(posp, "#ffff00");
-        var yy = posp.y - .5 * twCx.scaleY,
-            path = "M0 " + ppy + "C" + ( .7 * twCx.deltaX ) + " " + ppy + " " + ( .2 * twCx.deltaX ) + " " + yy + " " + ( twCx.deltaX ) + " " + yy + "L" + ( posp.x - .5 * twCx.scaleX ) + " " + yy;
-        yy = posp.y + .5 * twCx.scaleY;
-        ppy += 84;
-        path += "L" + ( posp.x - .5 * twCx.scaleX ) + " " + yy + "L" + twCx.deltaX + " " + yy + "C"  + ( .2 * twCx.deltaX ) + " " + yy + " " + ( .7 * twCx.deltaX ) + " " + ppy + " 0 " + ppy;
-        tlPaper.path( path ).attr({"stroke":"#ffff00", "fill" : "#ffff00", "fill-opacity" : .15});
-        
-        drawTweetArcs(twCx.tweets[p], posp, '#800080');
+        var posp = tlPosTweet(tweets[p]);
+        if (posp) {
+            
+            drawTweetPos(posp, "#ffff00");
+            var yy = posp.y - .5 * twCx.scaleY,
+                path = "M0 " + ppy + "C" + ( .7 * twCx.deltaX ) + " " + ppy + " " + ( .2 * twCx.deltaX ) + " " + yy + " " + ( twCx.deltaX ) + " " + yy + "L" + ( posp.x - .5 * twCx.scaleX ) + " " + yy;
+            yy = posp.y + .5 * twCx.scaleY;
+            ppy += 117;
+            path += "L" + ( posp.x - .5 * twCx.scaleX ) + " " + yy + "L" + twCx.deltaX + " " + yy + "C"  + ( .2 * twCx.deltaX ) + " " + yy + " " + ( .7 * twCx.deltaX ) + " " + ppy + " 0 " + ppy;
+            tlPaper.path( path ).attr({"stroke":"#ffff00", "fill" : "#ffff00", "fill-opacity" : .15});
+            
+            drawTweetArcs(tweets[p], posp, '#800080');
+        }
     }
-    
+}
+
+function filtrerAnnotation(annotation) {
+    if (annotations[annotation]) {
+        effectuerFiltrage(annotations[annotation].display_name,
+            new RegExp( "(" + annotations[annotation].keywords.map(function(a) { return a.source }).join("|") + ")", "gi" ) );
+    } else {
+        effectuerFiltrage('', null)
+    }
+}
+
+function filtrerTexte(valeur) {
+    effectuerFiltrage( valeur, valeur ? new RegExp("(" + valeur.replace(/(\W)/g, '\\$1') + ")" ,'gi') : null );
+}
+
+function effectuerFiltrage(filtreTexte, tabRegexp) {
+    $("#recherche_annot").slideUp();
+    $("#inp_q").val(filtreTexte).attr("class","rechercheCourante");
+    twCx.filtreTexte = filtreTexte;
+    twCx.filtre = tabRegexp;
+    twCx.followLast = !tabRegexp && (twCx.position == twCx.idIndex[twCx.idIndex.length - 1]);
+    updateDisplay();
 }
 
 function clicTl(evt) {
@@ -694,11 +794,42 @@
         addTweet(tweets[i]);
     }
     if (twCx.followLast) {
-        twCx.position = twCx.tweets.length - 1;
+        twCx.position = twCx.idIndex[twCx.tweets.length - 1];
     }
     updateDisplay();
 }
 
+function focusOutRecherche() {
+    $("#recherche_annot").slideUp();
+    var inpq = $("#inp_q"),
+        val = inpq.val();
+    if (val == '' || val == twCx.filtreTexte) {
+        if (twCx.filtre) {
+            inpq.attr("class", "rechercheCourante").val(twCx.filtreTexte);
+        } else {
+            inpq.attr("class", "greyed").val("Rechercher");
+        }
+    }
+}
+
+function chaineTimeZoom() {
+    var chaine = "",
+        t = twCx.date_levels[twCx.timeLevel],
+        h = 3600*1000,
+        m = 60*1000,
+        s = 1000,
+        heures = Math.floor(t/h);
+    if (heures) { chaine += heures + ' h. ' };
+    t -= (heures * h);
+    var minutes = Math.floor(t/m);
+    if (minutes) { chaine += minutes + ' min. ' };
+    t -= (minutes * m);
+    if (t) { chaine += Math.floor(t/s) + ' sec.' }
+    $("#time_scale").html(chaine);
+    $("#time_zoomout").attr("class",(twCx.timeLevel == 0 ? "inactive" : ""));
+    $("#time_zoomin").attr("class",(twCx.timeLevel == twCx.date_levels.length - 1 ? "inactive" : ""));
+}
+
 $(document).ready(function() {
     tlPaper = Raphael("timeline", twCx.tlWidth, twCx.tlHeight);
     
@@ -716,7 +847,7 @@
                 addTweet(data.new_tweets[i]);
             }
             if (twCx.followLast) {
-                twCx.position = twCx.tweets.length - 1;
+                twCx.position = twCx.idIndex[twCx.tweets.length - 1];
             }
             updateDisplay();
         });
@@ -724,6 +855,15 @@
         $.getScript("tweetdata.js");
     }
     
+    var html = '';
+    for (var j in annotations) {
+        if (j != "default") {
+            html += '<a href="#" style="background: ' + getColor(j, .7).hex + ';" onclick=filtrerAnnotation(\'' + j + '\'); return false;">' + annotations[j].display_name + '</a> '
+        }
+    }
+    $("#rech_list_annot").html(html);
+    
+    chaineTimeZoom();
     
     $("#tweetlist").mousewheel(function(e, d) {
         wheelDelta += d;
@@ -743,12 +883,27 @@
             }
             if (tl != twCx.timeLevel) {
                 twCx.timeLevel = tl;
+                chaineTimeZoom();
                 updateDisplay();
             }
             wheelDelta = 0;
         }
         return false;
     });
+    $("#time_zoomin").click(function() {
+        if (twCx.timeLevel < twCx.date_levels.length - 1) {
+            twCx.timeLevel++;
+            chaineTimeZoom();
+            updateDisplay();
+        }
+    });
+    $("#time_zoomout").click(function() {
+        if (twCx.timeLevel > 0) {
+            twCx.timeLevel--;
+            chaineTimeZoom();
+            updateDisplay();
+        }
+    });
     $("#timeline, #tweetlist").mouseout(function() {
         twCx.tlMouseClicked = false;
         twCx.tlMouseMoved = false;
@@ -763,16 +918,50 @@
         twCx.tlMouseMoved = false;
         var o = $(this).offset();
         twCx.refMouse = { x : evt.pageX - o.left, y : evt.pageY - o.top };
-        twCx.refPosTl = tlPosTweet(twCx.tweets[twCx.position]) || twCx.refMouse;
+        twCx.refPosTl = tlPosTweet(tweetById(twCx.position)) || twCx.refMouse;
     });
     $("#timeline").mouseup(function(evt) {
         clicTl(evt);
         twCx.tlMouseClicked = false;
         twCx.tlMouseMoved = false;
     });
-    $("#scrollcont").scroll(function(evt) {
-        var p = Math.floor( twCx.tweets.length * ( 1 - $(this).scrollTop() / 9548 ) );
-        goToPos(p);
+    $("#inp_q").focus(function() {
+        $("#recherche_annot").slideDown();
+        $(this).val($(this).val().replace(/ \(.+\)$/, ''))
+        if ($(this).hasClass("greyed")) {
+            $(this).val("");
+        }
+        $(this).attr("class","");
+    });
+    $("#inp_q").focusout(function() {
+        focusOutRecherche();
+    });
+    $("#inp_reset").click(function() {
+        $("#inp_q").val('');
+        if (twCx.filtre) {
+            twCx.filtre = null;
+            updateDisplay();
+        }
+        twCx.filtreTexte = '';
+        focusOutRecherche();
+        return false;
     })
+    $("#recherche").submit(function(evt) {
+        evt.preventDefault();
+        if (!$("#inp_q").hasClass("greyed")) {
+            var valeur = $("#inp_q").val();
+            filtrerTexte(valeur);
+        }
+        return false;
+    });
+    
+    setInterval(function() {
+        var sc = $("#scrollcont");
+        if (sc.scrollTop() != lastScrollPos && twCx.tweets) {
+            var p = Math.floor( twCx.currentIdIndex.length * ( 1 - sc.scrollTop() / scrollExtent ) );
+            goToPos(p);
+        }
+        
+    }, 100)
 });
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tweetcast/nodejs-bis/client/js/underscore-min.js	Tue Nov 29 15:41:52 2011 +0100
@@ -0,0 +1,30 @@
+// Underscore.js 1.2.2
+// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
+// Underscore is freely distributable under the MIT license.
+// Portions of Underscore are inspired or borrowed from Prototype,
+// Oliver Steele's Functional, and John Resig's Micro-Templating.
+// For all details and documentation:
+// http://documentcloud.github.com/underscore
+(function(){function r(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(b.isFunction(a.isEqual))return a.isEqual(c);if(b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return String(a)==String(c);case "[object Number]":return a=+a,c=+c,a!=a?c!=c:a==0?1/a==1/c:a==c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
+c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&r(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(m.call(a,h)&&(f++,!(g=m.call(c,h)&&r(a[h],c[h],d))))break;if(g){for(h in c)if(m.call(c,
+h)&&!f--)break;g=!f}}d.pop();return g}var s=this,F=s._,o={},k=Array.prototype,p=Object.prototype,i=k.slice,G=k.unshift,l=p.toString,m=p.hasOwnProperty,v=k.forEach,w=k.map,x=k.reduce,y=k.reduceRight,z=k.filter,A=k.every,B=k.some,q=k.indexOf,C=k.lastIndexOf,p=Array.isArray,H=Object.keys,t=Function.prototype.bind,b=function(a){return new n(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else typeof define==="function"&&define.amd?
+define("underscore",function(){return b}):s._=b;b.VERSION="1.2.2";var j=b.each=b.forEach=function(a,c,b){if(a!=null)if(v&&a.forEach===v)a.forEach(c,b);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(b,a[e],e,a)===o)break}else for(e in a)if(m.call(a,e)&&c.call(b,a[e],e,a)===o)break};b.map=function(a,c,b){var e=[];if(a==null)return e;if(w&&a.map===w)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=
+d!==void 0;a==null&&(a=[]);if(x&&a.reduce===x)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){a==null&&(a=[]);if(y&&a.reduceRight===y)return e&&(c=b.bind(c,e)),d!==void 0?a.reduceRight(c,d):a.reduceRight(c);a=(b.isArray(a)?a.slice():b.toArray(a)).reverse();return b.reduce(a,c,d,e)};b.find=b.detect=function(a,c,b){var e;
+D(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(z&&a.filter===z)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(A&&a.every===A)return a.every(c,b);j(a,function(a,g,h){if(!(e=e&&c.call(b,a,g,h)))return o});
+return e};var D=b.some=b.any=function(a,c,d){var c=c||b.identity,e=false;if(a==null)return e;if(B&&a.some===B)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return q&&a.indexOf===q?a.indexOf(c)!=-1:b=D(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(c.call?c||a:a[c]).apply(a,d)})};b.pluck=function(a,c){return b.map(a,function(a){return a[c]})};
+b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,computed:b})});return e.value};b.shuffle=function(a){var c=[],b;
+j(a,function(a,f){f==0?c[0]=a:(b=Math.floor(Math.random()*(f+1)),c[f]=c[b],c[b]=a)});return c};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,c){var b=a.criteria,d=c.criteria;return b<d?-1:b>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,c){var b=e(a,c);(d[b]||(d[b]=[])).push(a)});return d};b.sortedIndex=function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e<
+f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=b.tail=function(a,b,d){return i.call(a,b==null||
+d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},[]);return e};b.union=function(){return b.uniq(b.flatten(arguments,
+true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a,c){return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(q&&a.indexOf===q)return a.indexOf(c);
+for(d=0,e=a.length;d<e;d++)if(a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(C&&a.lastIndexOf===C)return a.lastIndexOf(b);for(var d=a.length;d--;)if(a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g};var E=function(){};b.bind=function(a,c){var d,e;if(a.bind===t&&t)return t.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;
+e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));E.prototype=a.prototype;var b=new E,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,c){var d={};c||(c=b.identity);return function(){var b=c.apply(this,arguments);return m.call(d,b)?d[b]:d[b]=a.apply(this,arguments)}};b.delay=
+function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true:a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=
+null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments));return b.apply(this,d)}};b.compose=function(){var a=i.call(arguments);return function(){for(var b=i.call(arguments),d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=H||function(a){if(a!==
+Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)m.call(a,d)&&(b[b.length]=d);return b};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)b[d]!==void 0&&(a[d]=b[d])});return a};b.defaults=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?
+a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(m.call(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};b.isArguments=l.call(arguments)=="[object Arguments]"?function(a){return l.call(a)=="[object Arguments]"}:
+function(a){return!(!a||!m.call(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};
+b.isUndefined=function(a){return a===void 0};b.noConflict=function(){s._=F;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")};b.mixin=function(a){j(b.functions(a),function(c){I(c,b[c]=a[c])})};var J=0;b.uniqueId=function(a){var b=J++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,
+interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape,function(a,b){return"',_.escape("+b.replace(/\\'/g,"'")+"),'"}).replace(d.interpolate,function(a,b){return"',"+b.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,
+"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e(a,b)}};var n=function(a){this._wrapped=a};b.prototype=n.prototype;var u=function(a,c){return c?b(a).chain():a},I=function(a,c){n.prototype[a]=function(){var a=i.call(arguments);G.call(a,this._wrapped);return u(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];n.prototype[a]=function(){b.apply(this._wrapped,
+arguments);return u(this._wrapped,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];n.prototype[a]=function(){return u(b.apply(this._wrapped,arguments),this._chain)}});n.prototype.chain=function(){this._chain=true;return this};n.prototype.value=function(){return this._wrapped}}).call(this);
--- a/web/res/metadataplayer.polemic/src/js/polemic.js	Tue Nov 29 15:41:15 2011 +0100
+++ b/web/res/metadataplayer.polemic/src/js/polemic.js	Tue Nov 29 15:41:52 2011 +0100
@@ -524,7 +524,7 @@
 
 			}		
 			// DRAW UI :: resize border and bgd
-			heightOfChart 	= (yMax-(config.height-yMax));
+			heightOfChart 	= (config.height-yMax);
 			PaperBackground = paper.rect(0,yMax,config.width,heightOfChart).attr({fill:"#fff","stroke-width":0.1,opacity: 0.1});	
 			PaperBorder 	= paper.rect(0,yMax,config.width,1).attr({fill:"#fff",stroke: "none",opacity: 1});	
 			PaperSlider 	= paper.rect(0,20,1,heightOfChart).attr({fill:"#fc00ff",stroke: "none",opacity: 1});