move clent to annot-client subfolder
authorymh <ymh.work@gmail.com>
Thu, 08 Jan 2015 19:15:59 +0100
changeset 80 dd414da0f0bb
parent 79 bd2f2c3f205c
child 81 a6bbf198bd24
move clent to annot-client subfolder
.hgignore
client/README.md
client/annot-client/README.md
client/annot-client/app/annotationclient.html
client/annot-client/app/app.css
client/annot-client/app/app.js
client/annot-client/app/app_controller_test.js
client/annot-client/bower.json
client/annot-client/data/categories.json
client/annot-client/gulpfile.js
client/annot-client/karma-unit.js
client/annot-client/package.json
client/app/annotationclient.html
client/app/app.css
client/app/app.js
client/app/app_controller_test.js
client/bower.json
client/data/categories.json
client/gulpfile.js
client/karma-unit.js
client/package.json
--- a/.hgignore	Wed Oct 29 12:50:30 2014 +0100
+++ b/.hgignore	Thu Jan 08 19:15:59 2015 +0100
@@ -2,9 +2,9 @@
 
 ^utils/pianoroll_test
 ^utils/pianoroll_sample_
-^client/bower_components$
-^client/build$
-^client/node_modules$
+^client/annot-client/bower_components$
+^client/annot-client/build$
+^client/annot-client/node_modules$
 ^.project$
 ^annot-server/mymonsenv$
 ^.pydevproject$
--- a/client/README.md	Wed Oct 29 12:50:30 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-Mons1415 client webapp
-====================
-
-Dev:
----
-
-- `npm install`
-- `node_modules/.bin/gulp`
-- `node_modules/.bin/bower install`
-- eventually `node_modules/.bin/bower install -D <some-packages>`
-
-TODO:
------
-
-- serveur has to send message with success or error code, 
-  then client has to display green or red feedback.
-- unit tests
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annot-client/README.md	Thu Jan 08 19:15:59 2015 +0100
@@ -0,0 +1,17 @@
+Mons1415 client webapp
+====================
+
+Dev:
+---
+
+- `npm install`
+- `node_modules/.bin/gulp`
+- `node_modules/.bin/bower install`
+- eventually `node_modules/.bin/bower install -D <some-packages>`
+
+TODO:
+-----
+
+- serveur has to send message with success or error code, 
+  then client has to display green or red feedback.
+- unit tests
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annot-client/app/annotationclient.html	Thu Jan 08 19:15:59 2015 +0100
@@ -0,0 +1,104 @@
+<!doctype html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <title>Mons by IRI</title>
+  <link rel="stylesheet" href="{{ config['STATIC_URL'] }}/css/lib.css">
+  <link rel="stylesheet" href="{{ config['STATIC_URL'] }}/css/app.css">
+</head>
+<body ng-controller="homeCtrl" ng-app="mons" ng-cloak>
+  <div class="container">
+    <div class="row">
+      <div class="col-md-12">
+      <form role="form">
+        <input class="form-control" placeholder="Nom d'utilisateur" ng-model="username"/>
+      </form>
+      </div>
+    </div>
+    <div class="row">
+      <div class="col-md-12">
+        <form role="form">
+          <autocomplete ng-model="yourchoice" data="allCatLabels" attr-input-class="form-control" attr-placeholder="Catégories..." ></autocomplete>
+        </form>
+      </div>
+    </div>
+    <div class="row mons-content">
+        <div class="mons-button hand return" ng-style="returnVisStyle" ng-click="selectLevel()" ng-init="returnVisStyle={visibility:'hidden'}">
+          <div class="content">
+              <div class="table">
+                <div class="table-cell">
+                  <p class="large-cat">RETOUR</p>
+                </div>
+              </div>
+          </div>
+        </div>
+        <div class="mons-button hand send" id="sendButton" ng-click="sendAnnotation(yourchoice)" ng-class="{'success-border':sendBtnSuccess, 'error-border':sendBtnError}">
+          <div class="content">
+              <div class="table">
+                <div class="table-cell">
+                  <p class="large-cat">ENVOYER</p>
+                  <p class="normal-cat">la catégorie saisie</p>
+                </div>
+              </div>
+          </div>
+        </div>
+    </div>
+    <div class="mons-content">
+      <div ng-show="!selectedlevel">
+          <div class="mons-button hand" ng-repeat="c in data.categories" style="background-color: {{ '{{' }} c.color {{ '}}' }}"
+                                        ng-click="selectLevel(c.label, c.code, c)" ng-class="{'success-border':c.sendSuccess, 'error-border':c.sendError}">
+            <div class="content">
+                <div class="table">
+                  <div class="table-cell">
+                    <p class="large-cat">{{ '{{' }} c.label {{ '}}' }}</p>
+                    <p class="normal-cat">{{ '{{' }} c.prelabel {{ '}}' }}</p>
+                  </div>
+                </div>
+            </div>
+          </div>
+      </div>
+      <div ng-show="selectedlevel">
+          <div class="mons-button hand" ng-repeat="c in selectedlevel" style="background-color: {{ '{{' }} c.color {{ '}}' }}"
+                                        ng-click="sendAnnotation({% raw %} (c.prelabel !== '') ? (c.prelabel + ': ' + c.label) : c.label {% endraw %}, c.code, c)" ng-class="{'success-border':c.sendSuccess, 'error-border':c.sendError}">
+            <div class="content">
+                <div class="table">
+                  <div class="table-cell">
+                    <p class="large-cat">{{ '{{' }} c.label {{ '}}' }}</p>
+                    <p class="normal-cat">{{ '{{' }} c.prelabel {{ '}}' }}</p>
+                  </div>
+                </div>
+            </div>
+          </div>
+      </div>
+    </div>
+    <footer>
+	  {% if logging %}<div class="row">
+	    <pre id="log" style="height: 20em; overflow-y: scroll; background-color: #faa; text-align: left;"></pre>
+      </div>{% endif %}
+      <div class="row">
+        <div class="col-md-12 text-center">
+            mons vBeta - ©IRI-2014
+        </div>
+      </div>
+    </footer>
+    <div class="row messages">
+      <div class="alert" ng-class="{'alert-success':showSuccessAlert, 'alert-danger':!showSuccessAlert}" role="alert" ng-show="showAlertDiv">{{ '{{' }} alertMessage {{ '}}' }}</div>
+    </div>
+  </div>
+  <script type="text/javascript" src="{{ config['STATIC_URL'] }}/js/lib.js"></script>
+  <!--script type="text/javascript" src="{{ pre_static_path }}static/js/templates.js"></script-->
+  <script type="text/javascript" src="{{ config['STATIC_URL'] }}/js/app.js"></script>
+  <script type="text/javascript">
+    angular.module("mons")
+        .value('context', {
+            {% if logging %}logging: true,{% endif %}
+            urls: {
+                dataUrl: "{{ config['STATIC_URL'] }}/data/categories.json"
+            },
+            categories_json: '{% if categories_json %}{{categories_json}}{% endif %}',
+            {% if event_code %}event_code: "{{event_code}}",{% endif %}
+        });
+  </script>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annot-client/app/app.css	Thu Jan 08 19:15:59 2015 +0100
@@ -0,0 +1,93 @@
+.row{
+    margin-top: 10px;
+}
+footer{
+    background: none;
+    color: #000;
+    float: left;
+    font: inherit;
+    position: inherit;
+    width: 100%;
+}
+.hand{
+    cursor: pointer;
+}
+.btn-lg{
+    width: 100%;
+    line-height: 2;
+    font-size: 4vw;
+    background-color: #E6E6E6;
+}
+.row{
+    margin-left: 0;
+    margin-right: 0;
+}
+.mons-content{
+    width: 100%;
+}
+.mons-button{
+    box-sizing: content-box;
+    background-color: #1e1e1e;
+    border: 10px solid #fff;
+    float: left;
+    margin: 0.5%;
+    overflow: hidden;
+    padding-bottom: 20%;
+    position: relative;
+    width: 45%;
+}
+.mons-button .content{
+    box-sizing: content-box;
+    height: 90%;
+    padding: 5%;
+    position: absolute;
+    width: 90%;
+}
+.mons-button .content .table{
+    display: table;
+    height: 100%;
+    width: 100%;
+}
+.mons-button .content .table .table-cell{
+    display: table-cell;
+    text-align: center;
+    vertical-align: middle;
+    text-shadow: 0 0 5px #fff;
+}
+.large-cat{
+    font-size: 300%;
+    font-size: 4vw;
+}
+.normal-cat{
+    font-size: 100%;
+    font-size: 2vw;
+}
+.send{
+    background-color: #4cae4c;
+}
+.return{
+    background-color: #e6e6e6;
+}
+.send, .return{
+    padding-bottom: 15%;
+}
+
+.row input{
+    font-size: 1.2em;
+}
+
+.messages {
+    position: fixed;
+    top: 0;
+    z-index: 7000;
+}
+.success-border{
+    border: 10px solid #3c763d;
+}
+.error-border{
+    border: 10px solid #cb4442;
+}
+
+/*.ng-scope{
+    border: red 1px solid;
+}*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annot-client/app/app.js	Thu Jan 08 19:15:59 2015 +0100
@@ -0,0 +1,232 @@
+(function(){
+    'use strict';
+
+    angular.module('mons', [ 'ngResource', 'ngRoute', 'autocomplete' ])
+        .config(function($routeProvider) {
+            $routeProvider.
+                when('/', {
+                    controller: 'homeCtrl'
+               }).
+               otherwise({
+                   redirectTo: '/'
+               });
+        })
+        .config(function($logProvider){
+            $logProvider.debugEnabled(true);
+        })
+        .service('dataApi', function($resource, context) {
+            //console.log('dataApi',$resource, context);
+            this.dataResource = $resource(context.urls.dataUrl);
+        })
+        .service('dataModel', function(dataApi, context) {
+            //console.log('dataModel',this,dataApi);
+            if(typeof context.categories_json !== 'undefined' && context.categories_json) {
+                this.data = JSON.parse(context.categories_json);
+            }
+            else {
+                this.data = dataApi.dataResource.get();
+            }
+        })
+        .controller('homeCtrl', function($scope, $location, dataModel, context, $interval){
+
+            function getURLParameter(name) {
+                return decodeURI(
+                    (new RegExp(name + '=' + '(.+?)(&|$)').exec(location.search)||[,null])[1]
+                );
+            }
+
+            $scope.data = dataModel.data;
+
+            var process_categories = function(data) {
+                if(typeof data.categories!=='undefined' && data.categories.length>0){
+                    var cats = [];
+                    var nbCat = data.categories.length;
+                    for(var i=0;i<nbCat;i++){
+                        cats.push(data.categories[i].label);
+                        if(typeof data.categories[i].subcategories!=='undefined' && data.categories[i].subcategories.length>0){
+                            var nbSubCat = data.categories[i].subcategories.length;
+                            for(var j=0;j<nbSubCat;j++){
+                                cats.push(data.categories[i].subcategories[j].label);
+                            }
+                        }
+                    }
+                    $scope.allCatLabels = cats;
+                }
+            };
+
+            if (typeof dataModel.data.$promise !== 'undefined') {
+                dataModel.data.$promise.then(process_categories);
+            }
+            else {
+                process_categories(dataModel.data);
+            }
+
+            $scope.selectedlevel = false;
+
+            $scope.currentInterval = false;
+            $scope.showSuccessAlert = false;
+            $scope.showAlertDiv = false;
+            function showAlert(m, success){
+                $scope.alertMessage = m;
+                $scope.showSuccessAlert = success;
+                $scope.showAlertDiv = true;
+                if(!$scope.$$phase) {
+                    $scope.$apply();
+                }
+                if($scope.currentInterval){
+                    $interval.cancel($scope.currentInterval);
+                    $scope.currentInterval = false;
+                }
+                $scope.currentInterval = $interval(function(){ $interval.cancel($scope.currentInterval); $scope.showAlertDiv = false; }, 2000, 1);
+            }
+            $scope.annotPile = [];
+
+
+
+            // Socket management
+            var sock = null;
+            var ellog = null;
+
+            ellog = document.getElementById('log');
+            function log(m) {
+                if(ellog){
+                    ellog.innerHTML += m + '\n';
+                    ellog.scrollTop = ellog.scrollHeight;
+                }
+            }
+
+            var wsuri;
+            if (window.location.protocol === 'file:') {
+                wsuri = 'ws://127.0.0.1:8090/annot';
+            } else {
+                wsuri = 'ws://' + window.location.hostname + ':8090/annot';
+            }
+            
+            var eventCode = context.event_code;
+            if(typeof eventCode==='undefined' || eventCode===''){
+                eventCode = $location.search().event;
+                if(typeof eventCode==='undefined' || eventCode===''){
+                    eventCode = getURLParameter('event');
+                    if(typeof eventCode==='undefined' || eventCode===''){
+                        alert('le code de l\'événement doit être indiqué dans un paramètre de template u dans l\'url selon ?event=CODE_EVENEMENT.');
+                        return;
+                    }
+                }
+            }
+            wsuri = wsuri + '?event=' + eventCode;
+
+            if ('WebSocket' in window) {
+                sock = new WebSocket(wsuri);
+            } else if ('MozWebSocket' in window) {
+                sock = new window.MozWebSocket(wsuri);
+            } else {
+                if(context.logging===true){
+                    log('Browser does not support WebSocket!');
+                }
+                window.location = 'http://autobahn.ws/unsupportedbrowser';
+            }
+
+            if (sock) {
+                sock.onopen = function() {
+                    if(context.logging===true){
+                        log('Connected to ' + wsuri);
+                    }
+                };
+
+                sock.onclose = function(e) {
+                    if(context.logging===true){
+                        log('Connection closed (wasClean = ' + e.wasClean + ', code = ' + e.code + ', reason = ' + e.reason + ')');
+                    }
+                    showAlert('Communication interrompue : la socket vient de se fermer.', false);
+                    sock = null;
+                };
+
+                sock.onmessage = function(e) {
+                    var data_json = JSON.parse(e.data);
+                    //console.log('1', data_json);
+                    if(context.logging){
+                        log('Got message: ' + e.data);
+                    }
+                    //showAlert('Annotation bien reçue.', true);
+                    //console.log('2 message', $scope.annotPile.length);
+                    if($scope.annotPile.length>0){
+                        var c = $scope.annotPile.shift();
+                        //console.log('3 message', c);
+                        //console.log('2',data_json.status,data_json.status==='OK');
+                        var ok = data_json.status==='OK';
+                        var i;
+                        if(c===false){
+                            //showAlert('Annotation envoyée.', true);
+                            $scope.sendBtnSuccess = ok;
+                            $scope.sendBtnError = !ok;
+                            i = $interval(function(){ $interval.cancel(i); $scope.sendBtnSuccess = false; $scope.sendBtnError = false; }, 2000, 1);
+                        }
+                        else{
+                            c.sendSuccess = ok;
+                            c.sendError = !ok;
+                            i = $interval(function(){ $interval.cancel(i); c.sendSuccess = false; c.sendError = false; }, 2000, 1);
+                        }
+                        if(!$scope.$$phase) {
+                            $scope.$apply();
+                        }
+                    }
+                };
+            }
+
+            $scope.sendAnnotation = function(label, code, c){
+                if($scope.username==='' || typeof $scope.username==='undefined'){
+                    showAlert('Vous devez indiquer un nom d\'utilisateur.', false);
+                    return;
+                }
+                if(label==='' || typeof label==='undefined'){
+                    showAlert('Vous devez indiquer un nom de catégorie.', false);
+                    return;
+                }
+                // Send query
+                if (sock) {
+                    if(typeof code==='undefined' || code===''){
+                        code = window.S(label).slugify().s;
+                    }
+                    var new_annot = {
+                            category: {code: code, label: label},
+                            user : $scope.username
+                    };
+                    sock.send(JSON.stringify(new_annot));
+                    if(context.logging===true){
+                        log('Sent: ' + JSON.stringify(new_annot));
+                    }
+                    if(typeof c==='undefined'){
+                        $scope.annotPile.push(false);
+                    }
+                    else{
+                        $scope.annotPile.push(c);
+                    }
+                } else {
+                    showAlert('La socket ne fonctionne pas.', false);
+                    if(context.logging===true){
+                        log('Not connected.');
+                    }
+                }
+            };
+
+            // Interface management
+            $scope.selectLevel = function(label, code, c){
+                if(typeof c==='undefined'){
+                    $scope.returnVisStyle = {visibility:'hidden'};
+                    $scope.selectedlevel = false;
+                    return;
+                }
+                if(typeof c.subcategories!=='undefined' && c.subcategories.length>0){
+                    $scope.selectedlevel = c.subcategories;
+                    $scope.returnVisStyle = {visibility:'show'};
+                }
+                else{
+                    // Send query
+                    //console.log('send ntm', c);
+                    $scope.sendAnnotation(label, code, c);
+                }
+            };
+
+        });
+
+})();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annot-client/app/app_controller_test.js	Thu Jan 08 19:15:59 2015 +0100
@@ -0,0 +1,7 @@
+'use strict';
+
+describe("app_controller_test", function(){
+    it("should assert something",function(){
+        expect(true).toBe(true);
+    })
+})
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annot-client/bower.json	Thu Jan 08 19:15:59 2015 +0100
@@ -0,0 +1,26 @@
+{
+  "name": "mons",
+  "main": "app.js",
+  "version": "0.0.0",
+  "authors": [
+    "IRI"
+  ],
+  "license": "Ceccill-C",
+  "private": true,
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "test",
+    "tests"
+  ],
+  "devDependencies": {
+    "angular": "~1.3",
+    "angular-route": "~1.3",
+    "angular-resource": "~1.3",
+    "angular-bootstrap": "~0.11.0",
+    "allmighty-autocomplete": "*",
+    "bootstrap": "~3.1.1",
+    "string": "*"
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annot-client/data/categories.json	Thu Jan 08 19:15:59 2015 +0100
@@ -0,0 +1,254 @@
+{
+    "categories": [
+        {
+            "label": "Ça me raconte",
+            "prelabel": "",
+            "color": "rgb(121,187,146)",
+            "code": "melodie",
+            "subcategories": [
+                {
+                    "label": "Mélodieux",
+                    "prelabel": "Ça me raconte",
+                    "color": "rgb(121,187,146)",
+                    "code": "cameraconte-melodieux"
+                },
+                {
+                    "label": "Consonnant",
+                    "prelabel": "Ça me raconte",
+                    "color": "rgb(121,187,146)",
+                    "code": "cameraconte-consonnant"
+                },
+                {
+                    "label": "Dissonnant",
+                    "prelabel": "Ça me raconte",
+                    "color": "rgb(121,187,146)",
+                    "code": "cameraconte-dissonnant"
+                },
+                {
+                    "label": "Construction",
+                    "prelabel": "Ça me raconte",
+                    "color": "rgb(121,187,146)",
+                    "code": "cameraconte-construction"
+                },
+                {
+                    "label": "Suspense",
+                    "prelabel": "Ça me raconte",
+                    "color": "rgb(121,187,146)",
+                    "code": "cameraconte-suspens"
+                },
+                {
+                    "label": "Intriguant",
+                    "prelabel": "Ça me raconte",
+                    "color": "rgb(121,187,146)",
+                    "code": "cameraconte-intriguant"
+                },
+                {
+                    "label": "Régulier",
+                    "prelabel": "Ça me raconte",
+                    "color": "rgb(121,187,146)",
+                    "code": "cameraconte-regulier"
+                }
+            ]
+        },
+        {
+            "label": "Ça me bouge",
+            "prelabel": "",
+            "color": "rgb(255,50,50)",
+            "code": "rythme",
+            "subcategories": [
+                {
+                    "label": "Lent",
+                    "prelabel": "Ça me bouge",
+                    "color": "rgb(255,50,50)",
+                    "code": "camebouge-lent"
+                },
+                {
+                    "label": "Rapide",
+                    "prelabel": "Ça me bouge",
+                    "color": "rgb(255,50,50)",
+                    "code": "camebouge-rapide"
+                },
+                {
+                    "label": "Déstructuré",
+                    "prelabel": "Ça me bouge",
+                    "color": "rgb(255,50,50)",
+                    "code": "camebouge-destructure"
+                },
+                {
+                    "label": "Ça swingue",
+                    "prelabel": "Ça me bouge",
+                    "color": "rgb(255,50,50)",
+                    "code": "camebouge-caswingue"
+                }
+            ]
+        },
+        {
+            "label": "Ça se bagarre",
+            "prelabel": "",
+            "color": "rgb(78,144,204)",
+            "code": "gestuelle",
+            "subcategories": [
+                {
+                    "label": "Interaction entre musiciens",
+                    "prelabel": "Ça se bagarre",
+                    "color": "rgb(78,144,204)",
+                    "code": "casebagarre-interaction"
+                },
+                {
+                    "label": "Contact",
+                    "prelabel": "Ça se bagarre",
+                    "color": "rgb(78,144,204)",
+                    "code": "casebagarre-contact"
+                },
+                {
+                    "label": "Théâtralité",
+                    "prelabel": "Ça se bagarre",
+                    "color": "rgb(78,144,204)",
+                    "code": "casebagarre-theatralite"
+                },
+                {
+                    "label": "Danse",
+                    "prelabel": "Ça se bagarre",
+                    "color": "rgb(78,144,204)",
+                    "code": "casebagarre-danse"
+                }
+            ]
+        },
+        {
+            "label": "Ça sonne",
+            "prelabel": "",
+            "color": "rgb(222,139,83)",
+            "code": "a-rejouer",
+            "subcategories": [
+                {
+                    "label": "Piano",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-piano"
+                },
+                {
+                    "label": "Clarinette",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-clarinette"
+                },
+                {
+                    "label": "Saxophone",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-saxophone"
+                },
+                {
+                    "label": "Batterie",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-batterie"
+                },
+                {
+                    "label": "Voix chantée",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-voixchantee"
+                },
+                {
+                    "label": "Guitare",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-guitare"
+                },
+                {
+                    "label": "Synthé",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-synthe"
+                },
+                {
+                    "label": "Voix parlée",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-voixparlee"
+                },
+                {
+                    "label": "Karlax",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-karlax"
+                },
+                {
+                    "label": "Boîte à rythme",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-boitearythme"
+                },
+                {
+                    "label": "Flûte",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-flute"
+                },
+                {
+                    "label": "Violon",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-violon"
+                },
+                {
+                    "label": "Flûte Scoatariu",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-flutescoatariu"
+                },
+                {
+                    "label": "Violoncelle",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-violoncelle"
+                },
+                {
+                    "label": "Accordéon",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-accordeon"
+                },
+                {
+                    "label": "Guitare électrique",
+                    "prelabel": "Ça sonne",
+                    "color": "rgb(222,139,83)",
+                    "code": "casonne-guitareelectrique"
+                }
+            ]
+        },
+        {
+            "label": "À Rejouer",
+            "prelabel": "",
+            "color": "rgb(205,200,63)",
+            "code": "a-rejouer",
+            "subcategories": [
+                {
+                    "label": "À l'identique",
+                    "prelabel": "À Rejouer",
+                    "color": "rgb(205,200,63)",
+                    "code": "a-rejouer-alidentique"
+                },
+                {
+                    "label": "Plus vite",
+                    "prelabel": "À Rejouer",
+                    "color": "rgb(205,200,63)",
+                    "code": "a-rejouer-plus-vite"
+                },
+                {
+                    "label": "Plus lentement",
+                    "prelabel": "À Rejouer",
+                    "color": "rgb(205,200,63)",
+                    "code": "a-rejouer-plus-lentement"
+                },
+                {
+                    "label": "Avec un autre instrument",
+                    "prelabel": "À Rejouer",
+                    "color": "rgb(205,200,63)",
+                    "code": "a-rejouer-autre-instrument"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annot-client/gulpfile.js	Thu Jan 08 19:15:59 2015 +0100
@@ -0,0 +1,139 @@
+var gulp = require('gulp');
+var del = require('del');
+var gutil = require('gulp-util')
+var plugins = require("gulp-load-plugins")({lazy:false});
+
+var templateFolder = '../annot-server/webapp/templates/';
+var templateFileDest = '../annot-server/webapp/templates/annotationclient.html';
+var staticFolder = '../annot-server/static';
+
+var clientBaseName = 'app';
+var vendorBaseName = 'lib';
+
+gulp.task('clean', function (cb) {
+    del([
+        templateFileDest,
+        staticFolder + "/css/app*",
+        staticFolder + "/js/app*",
+        staticFolder + "/data/categories.json",
+    ],{'force':true}, cb);
+});
+
+var scriptsSrc = ['!./app/**/*_test.js','./app/**/*.js'];
+
+gulp.task('scripts', function(){
+    //combine all js files of the app
+    gulp.src(scriptsSrc)
+        .pipe(plugins.jshint())
+        .pipe(plugins.jshint.reporter('default'))
+        .pipe(plugins.jshint.reporter('fail'))
+        .pipe(plugins.concat(clientBaseName+'.js'))
+        .pipe(gulp.dest(staticFolder+'/js'))
+        .pipe(plugins.filesize())
+        .pipe(plugins.uglify())
+        .pipe(plugins.rename(clientBaseName+'.min.js'))
+        .pipe(gulp.dest(staticFolder+'/js'))
+        .pipe(plugins.filesize())
+        .on('error', gutil.log);
+});
+
+
+gulp.task('css', function(){
+    gulp.src('./app/**/*.css')
+        .pipe(plugins.csslint({ 'box-sizing': false }))
+        .pipe(plugins.csslint.reporter())
+        .pipe(plugins.concat(clientBaseName+'.css'))
+        .pipe(gulp.dest(staticFolder+'/css'))
+        .pipe(plugins.filesize())
+        .pipe(plugins.minifyCss({keepBreaks:true}))
+        .pipe(plugins.rename(clientBaseName+'.min.css'))
+        .pipe(gulp.dest(staticFolder+'/css'))
+        .pipe(plugins.filesize());
+});
+
+var vendorJSsrc = [
+  '!./bower_components/**/*.min.js',
+  '!./bower_components/bootstrap/Gruntfile.js',
+  '!./bower_components/bootstrap/grunt/*',
+  '!./bower_components/bootstrap/js/*',
+  '!./bower_components/jquery/src/**/*',
+  '!./bower_components/angular-bootstrap/ui-bootstrap.js',
+  './bower_components/jquery/dist/jquery.js',
+  './bower_components/angular/angular.js',
+  './bower_components/**/*.js'
+];
+
+gulp.task('vendorJS', function(){
+    //concatenate vendor JS files
+    gulp.src(vendorJSsrc)
+        .pipe(plugins.concat('lib.js'))
+        .pipe(gulp.dest(staticFolder+'/js'))
+        .pipe(plugins.filesize())
+        .pipe(plugins.uglify())
+        .pipe(plugins.rename('lib.min.js'))
+        .pipe(gulp.dest(staticFolder+'/js'))
+        .pipe(plugins.filesize())
+        .on('error', gutil.log);
+});
+
+gulp.task('vendorCSS', function(){
+    //concatenate vendor CSS files
+    gulp.src(['!./bower_components/**/*.min.css',
+        './bower_components/**/*.css'])
+        .pipe(plugins.concat(vendorBaseName+'.css'))
+        .pipe(gulp.dest(staticFolder+'/css'))
+        .pipe(plugins.filesize())
+        .pipe(plugins.minifyCss({keepBreaks:true}))
+        .pipe(plugins.rename(vendorBaseName+'.min.css'))
+        .pipe(gulp.dest(staticFolder+'/css'))
+        .pipe(plugins.filesize());
+});
+
+gulp.task('vendorFonts', function(){
+    gulp.src(['./bower_components/**/fonts/*'])
+        .pipe(plugins.flatten())
+        .pipe(gulp.dest(staticFolder+'/css/fonts'));
+});
+
+gulp.task('copy-index', function() {
+    gulp.src('./app/annotationclient.html')
+        .pipe(gulp.dest(templateFolder));
+});
+
+gulp.task('copy-data', function() {
+    gulp.src('./data/**/*')
+        .pipe(gulp.dest(staticFolder+'/data'));
+});
+
+gulp.task('copy-img', function() {
+    gulp.src('./img/**/*')
+        .pipe(gulp.dest(staticFolder+'/img'));
+});
+
+gulp.task('watch',function(){
+    gulp.watch([
+        templateFolder+'/**/*.html',
+        staticFolder+'/**/*.js',
+        staticFolder+'/**/*.css'
+    ], function(event) {
+        return gulp.src(event.path)
+            .pipe(plugins.webserver.reload());
+    });
+    gulp.watch(['./app/**/*.js','!./app/**/*test.js'],['scripts']);
+    gulp.watch('./app/**/*.css',['css']);
+    gulp.watch('./app/annotationclient.html',['copy-index']);
+    gulp.watch('./data/**/*',['copy-data']);
+    gulp.watch('./img/**/*',['copy-img']);
+
+});
+
+gulp.task('connect', function() {
+    gulp.src('build').pipe(
+        plugins.webserver({
+            port: 9000,
+            livereload: true
+        })
+    );
+});
+
+gulp.task('default',['scripts','css','copy-index','copy-data','copy-img','vendorJS','vendorCSS','vendorFonts']);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annot-client/karma-unit.js	Thu Jan 08 19:15:59 2015 +0100
@@ -0,0 +1,70 @@
+// Karma configuration
+// Generated on Thu Mar 27 2014 15:49:13 GMT+0800 (PHT)
+
+module.exports = function(config) {
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: [
+        './build/lib.js',
+        './build/app.js',
+        './build/templates.js',
+        './app/**/*test.js'
+    ],
+
+
+    // list of files to exclude
+    exclude: [
+      
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+    
+    },
+
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['progress'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_DEBUG,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['Chrome'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annot-client/package.json	Thu Jan 08 19:15:59 2015 +0100
@@ -0,0 +1,33 @@
+{
+  "name": "mons",
+  "version": "0.0.0",
+  "description": "Mons client application",
+  "main": "app.js",
+  "repository": {
+    "type": "mercurial",
+    "url": "http://www.iri.centrepompidou.fr/dev/hg/mons"
+  },
+  "author": "IRI",
+  "license": "Cecill-C",
+  "devDependencies": {
+    "bower": "^1.3.12",
+    "del": "^0.1.3",
+    "grunt-cli": "^0.1.13",
+    "gulp": "~3.8.8",
+    "gulp-angular-templatecache": "^1.4.2",
+    "gulp-concat": "~2.4.1",
+    "gulp-csslint": "^0.1.5",
+    "gulp-filesize": "0.0.6",
+    "gulp-flatten": "0.0.4",
+    "gulp-jshint": "~1.8.5",
+    "gulp-load-plugins": "~0.7.0",
+    "gulp-minify-css": "^0.3.10",
+    "gulp-rename": "^1.2.0",
+    "gulp-uglify": "^1.0.1",
+    "gulp-util": "^3.0.1",
+    "gulp-webserver": "^0.8.3",
+    "karma": "^0.12.23",
+    "karma-chrome-launcher": "^0.1.4",
+    "karma-jasmine": "^0.1.5"
+  }
+}
--- a/client/app/annotationclient.html	Wed Oct 29 12:50:30 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-<!doctype html>
-<html>
-<head>
-  <meta charset="utf-8">
-  <meta name="viewport" content="width=device-width, initial-scale=1">
-  <title>Mons by IRI</title>
-  <link rel="stylesheet" href="{{ config['STATIC_URL'] }}/css/lib.css">
-  <link rel="stylesheet" href="{{ config['STATIC_URL'] }}/css/app.css">
-</head>
-<body ng-controller="homeCtrl" ng-app="mons" ng-cloak>
-  <div class="container">
-    <div class="row">
-      <div class="col-md-12">
-      <form role="form">
-        <input class="form-control" placeholder="Nom d'utilisateur" ng-model="username"/>
-      </form>
-      </div>
-    </div>
-    <div class="row">
-      <div class="col-md-12">
-        <form role="form">
-          <autocomplete ng-model="yourchoice" data="allCatLabels" attr-input-class="form-control" attr-placeholder="Catégories..." ></autocomplete>
-        </form>
-      </div>
-    </div>
-    <div class="row mons-content">
-        <div class="mons-button hand return" ng-style="returnVisStyle" ng-click="selectLevel()" ng-init="returnVisStyle={visibility:'hidden'}">
-          <div class="content">
-              <div class="table">
-                <div class="table-cell">
-                  <p class="large-cat">RETOUR</p>
-                </div>
-              </div>
-          </div>
-        </div>
-        <div class="mons-button hand send" id="sendButton" ng-click="sendAnnotation(yourchoice)" ng-class="{'success-border':sendBtnSuccess, 'error-border':sendBtnError}">
-          <div class="content">
-              <div class="table">
-                <div class="table-cell">
-                  <p class="large-cat">ENVOYER</p>
-                  <p class="normal-cat">la catégorie saisie</p>
-                </div>
-              </div>
-          </div>
-        </div>
-    </div>
-    <div class="mons-content">
-      <div ng-show="!selectedlevel">
-          <div class="mons-button hand" ng-repeat="c in data.categories" style="background-color: {{ '{{' }} c.color {{ '}}' }}"
-                                        ng-click="selectLevel(c.label, c.code, c)" ng-class="{'success-border':c.sendSuccess, 'error-border':c.sendError}">
-            <div class="content">
-                <div class="table">
-                  <div class="table-cell">
-                    <p class="large-cat">{{ '{{' }} c.label {{ '}}' }}</p>
-                    <p class="normal-cat">{{ '{{' }} c.prelabel {{ '}}' }}</p>
-                  </div>
-                </div>
-            </div>
-          </div>
-      </div>
-      <div ng-show="selectedlevel">
-          <div class="mons-button hand" ng-repeat="c in selectedlevel" style="background-color: {{ '{{' }} c.color {{ '}}' }}"
-                                        ng-click="sendAnnotation({% raw %} (c.prelabel !== '') ? (c.prelabel + ': ' + c.label) : c.label {% endraw %}, c.code, c)" ng-class="{'success-border':c.sendSuccess, 'error-border':c.sendError}">
-            <div class="content">
-                <div class="table">
-                  <div class="table-cell">
-                    <p class="large-cat">{{ '{{' }} c.label {{ '}}' }}</p>
-                    <p class="normal-cat">{{ '{{' }} c.prelabel {{ '}}' }}</p>
-                  </div>
-                </div>
-            </div>
-          </div>
-      </div>
-    </div>
-    <footer>
-	  {% if logging %}<div class="row">
-	    <pre id="log" style="height: 20em; overflow-y: scroll; background-color: #faa; text-align: left;"></pre>
-      </div>{% endif %}
-      <div class="row">
-        <div class="col-md-12 text-center">
-            mons vBeta - ©IRI-2014
-        </div>
-      </div>
-    </footer>
-    <div class="row messages">
-      <div class="alert" ng-class="{'alert-success':showSuccessAlert, 'alert-danger':!showSuccessAlert}" role="alert" ng-show="showAlertDiv">{{ '{{' }} alertMessage {{ '}}' }}</div>
-    </div>
-  </div>
-  <script type="text/javascript" src="{{ config['STATIC_URL'] }}/js/lib.js"></script>
-  <!--script type="text/javascript" src="{{ pre_static_path }}static/js/templates.js"></script-->
-  <script type="text/javascript" src="{{ config['STATIC_URL'] }}/js/app.js"></script>
-  <script type="text/javascript">
-    angular.module("mons")
-        .value('context', {
-            {% if logging %}logging: true,{% endif %}
-            urls: {
-                dataUrl: "{{ config['STATIC_URL'] }}/data/categories.json"
-            },
-            categories_json: '{% if categories_json %}{{categories_json}}{% endif %}',
-            {% if event_code %}event_code: "{{event_code}}",{% endif %}
-        });
-  </script>
-</body>
-</html>
--- a/client/app/app.css	Wed Oct 29 12:50:30 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-.row{
-    margin-top: 10px;
-}
-footer{
-    background: none;
-    color: #000;
-    float: left;
-    font: inherit;
-    position: inherit;
-    width: 100%;
-}
-.hand{
-    cursor: pointer;
-}
-.btn-lg{
-    width: 100%;
-    line-height: 2;
-    font-size: 4vw;
-    background-color: #E6E6E6;
-}
-.row{
-    margin-left: 0;
-    margin-right: 0;
-}
-.mons-content{
-    width: 100%;
-}
-.mons-button{
-    box-sizing: content-box;
-    background-color: #1e1e1e;
-    border: 10px solid #fff;
-    float: left;
-    margin: 0.5%;
-    overflow: hidden;
-    padding-bottom: 20%;
-    position: relative;
-    width: 45%;
-}
-.mons-button .content{
-    box-sizing: content-box;
-    height: 90%;
-    padding: 5%;
-    position: absolute;
-    width: 90%;
-}
-.mons-button .content .table{
-    display: table;
-    height: 100%;
-    width: 100%;
-}
-.mons-button .content .table .table-cell{
-    display: table-cell;
-    text-align: center;
-    vertical-align: middle;
-    text-shadow: 0 0 5px #fff;
-}
-.large-cat{
-    font-size: 300%;
-    font-size: 4vw;
-}
-.normal-cat{
-    font-size: 100%;
-    font-size: 2vw;
-}
-.send{
-    background-color: #4cae4c;
-}
-.return{
-    background-color: #e6e6e6;
-}
-.send, .return{
-    padding-bottom: 15%;
-}
-
-.row input{
-    font-size: 1.2em;
-}
-
-.messages {
-    position: fixed;
-    top: 0;
-    z-index: 7000;
-}
-.success-border{
-    border: 10px solid #3c763d;
-}
-.error-border{
-    border: 10px solid #cb4442;
-}
-
-/*.ng-scope{
-    border: red 1px solid;
-}*/
--- a/client/app/app.js	Wed Oct 29 12:50:30 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,232 +0,0 @@
-(function(){
-    'use strict';
-
-    angular.module('mons', [ 'ngResource', 'ngRoute', 'autocomplete' ])
-        .config(function($routeProvider) {
-            $routeProvider.
-                when('/', {
-                    controller: 'homeCtrl'
-               }).
-               otherwise({
-                   redirectTo: '/'
-               });
-        })
-        .config(function($logProvider){
-            $logProvider.debugEnabled(true);
-        })
-        .service('dataApi', function($resource, context) {
-            //console.log('dataApi',$resource, context);
-            this.dataResource = $resource(context.urls.dataUrl);
-        })
-        .service('dataModel', function(dataApi, context) {
-            //console.log('dataModel',this,dataApi);
-            if(typeof context.categories_json !== 'undefined' && context.categories_json) {
-                this.data = JSON.parse(context.categories_json);
-            }
-            else {
-                this.data = dataApi.dataResource.get();
-            }
-        })
-        .controller('homeCtrl', function($scope, $location, dataModel, context, $interval){
-
-            function getURLParameter(name) {
-                return decodeURI(
-                    (new RegExp(name + '=' + '(.+?)(&|$)').exec(location.search)||[,null])[1]
-                );
-            }
-
-            $scope.data = dataModel.data;
-
-            var process_categories = function(data) {
-                if(typeof data.categories!=='undefined' && data.categories.length>0){
-                    var cats = [];
-                    var nbCat = data.categories.length;
-                    for(var i=0;i<nbCat;i++){
-                        cats.push(data.categories[i].label);
-                        if(typeof data.categories[i].subcategories!=='undefined' && data.categories[i].subcategories.length>0){
-                            var nbSubCat = data.categories[i].subcategories.length;
-                            for(var j=0;j<nbSubCat;j++){
-                                cats.push(data.categories[i].subcategories[j].label);
-                            }
-                        }
-                    }
-                    $scope.allCatLabels = cats;
-                }
-            };
-
-            if (typeof dataModel.data.$promise !== 'undefined') {
-                dataModel.data.$promise.then(process_categories);
-            }
-            else {
-                process_categories(dataModel.data);
-            }
-
-            $scope.selectedlevel = false;
-
-            $scope.currentInterval = false;
-            $scope.showSuccessAlert = false;
-            $scope.showAlertDiv = false;
-            function showAlert(m, success){
-                $scope.alertMessage = m;
-                $scope.showSuccessAlert = success;
-                $scope.showAlertDiv = true;
-                if(!$scope.$$phase) {
-                    $scope.$apply();
-                }
-                if($scope.currentInterval){
-                    $interval.cancel($scope.currentInterval);
-                    $scope.currentInterval = false;
-                }
-                $scope.currentInterval = $interval(function(){ $interval.cancel($scope.currentInterval); $scope.showAlertDiv = false; }, 2000, 1);
-            }
-            $scope.annotPile = [];
-
-
-
-            // Socket management
-            var sock = null;
-            var ellog = null;
-
-            ellog = document.getElementById('log');
-            function log(m) {
-                if(ellog){
-                    ellog.innerHTML += m + '\n';
-                    ellog.scrollTop = ellog.scrollHeight;
-                }
-            }
-
-            var wsuri;
-            if (window.location.protocol === 'file:') {
-                wsuri = 'ws://127.0.0.1:8090/annot';
-            } else {
-                wsuri = 'ws://' + window.location.hostname + ':8090/annot';
-            }
-            
-            var eventCode = context.event_code;
-            if(typeof eventCode==='undefined' || eventCode===''){
-                eventCode = $location.search().event;
-                if(typeof eventCode==='undefined' || eventCode===''){
-                    eventCode = getURLParameter('event');
-                    if(typeof eventCode==='undefined' || eventCode===''){
-                        alert('le code de l\'événement doit être indiqué dans un paramètre de template u dans l\'url selon ?event=CODE_EVENEMENT.');
-                        return;
-                    }
-                }
-            }
-            wsuri = wsuri + '?event=' + eventCode;
-
-            if ('WebSocket' in window) {
-                sock = new WebSocket(wsuri);
-            } else if ('MozWebSocket' in window) {
-                sock = new window.MozWebSocket(wsuri);
-            } else {
-                if(context.logging===true){
-                    log('Browser does not support WebSocket!');
-                }
-                window.location = 'http://autobahn.ws/unsupportedbrowser';
-            }
-
-            if (sock) {
-                sock.onopen = function() {
-                    if(context.logging===true){
-                        log('Connected to ' + wsuri);
-                    }
-                };
-
-                sock.onclose = function(e) {
-                    if(context.logging===true){
-                        log('Connection closed (wasClean = ' + e.wasClean + ', code = ' + e.code + ', reason = ' + e.reason + ')');
-                    }
-                    showAlert('Communication interrompue : la socket vient de se fermer.', false);
-                    sock = null;
-                };
-
-                sock.onmessage = function(e) {
-                    var data_json = JSON.parse(e.data);
-                    //console.log('1', data_json);
-                    if(context.logging){
-                        log('Got message: ' + e.data);
-                    }
-                    //showAlert('Annotation bien reçue.', true);
-                    //console.log('2 message', $scope.annotPile.length);
-                    if($scope.annotPile.length>0){
-                        var c = $scope.annotPile.shift();
-                        //console.log('3 message', c);
-                        //console.log('2',data_json.status,data_json.status==='OK');
-                        var ok = data_json.status==='OK';
-                        var i;
-                        if(c===false){
-                            //showAlert('Annotation envoyée.', true);
-                            $scope.sendBtnSuccess = ok;
-                            $scope.sendBtnError = !ok;
-                            i = $interval(function(){ $interval.cancel(i); $scope.sendBtnSuccess = false; $scope.sendBtnError = false; }, 2000, 1);
-                        }
-                        else{
-                            c.sendSuccess = ok;
-                            c.sendError = !ok;
-                            i = $interval(function(){ $interval.cancel(i); c.sendSuccess = false; c.sendError = false; }, 2000, 1);
-                        }
-                        if(!$scope.$$phase) {
-                            $scope.$apply();
-                        }
-                    }
-                };
-            }
-
-            $scope.sendAnnotation = function(label, code, c){
-                if($scope.username==='' || typeof $scope.username==='undefined'){
-                    showAlert('Vous devez indiquer un nom d\'utilisateur.', false);
-                    return;
-                }
-                if(label==='' || typeof label==='undefined'){
-                    showAlert('Vous devez indiquer un nom de catégorie.', false);
-                    return;
-                }
-                // Send query
-                if (sock) {
-                    if(typeof code==='undefined' || code===''){
-                        code = window.S(label).slugify().s;
-                    }
-                    var new_annot = {
-                            category: {code: code, label: label},
-                            user : $scope.username
-                    };
-                    sock.send(JSON.stringify(new_annot));
-                    if(context.logging===true){
-                        log('Sent: ' + JSON.stringify(new_annot));
-                    }
-                    if(typeof c==='undefined'){
-                        $scope.annotPile.push(false);
-                    }
-                    else{
-                        $scope.annotPile.push(c);
-                    }
-                } else {
-                    showAlert('La socket ne fonctionne pas.', false);
-                    if(context.logging===true){
-                        log('Not connected.');
-                    }
-                }
-            };
-
-            // Interface management
-            $scope.selectLevel = function(label, code, c){
-                if(typeof c==='undefined'){
-                    $scope.returnVisStyle = {visibility:'hidden'};
-                    $scope.selectedlevel = false;
-                    return;
-                }
-                if(typeof c.subcategories!=='undefined' && c.subcategories.length>0){
-                    $scope.selectedlevel = c.subcategories;
-                    $scope.returnVisStyle = {visibility:'show'};
-                }
-                else{
-                    // Send query
-                    //console.log('send ntm', c);
-                    $scope.sendAnnotation(label, code, c);
-                }
-            };
-
-        });
-
-})();
--- a/client/app/app_controller_test.js	Wed Oct 29 12:50:30 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-'use strict';
-
-describe("app_controller_test", function(){
-    it("should assert something",function(){
-        expect(true).toBe(true);
-    })
-})
\ No newline at end of file
--- a/client/bower.json	Wed Oct 29 12:50:30 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-{
-  "name": "mons",
-  "main": "app.js",
-  "version": "0.0.0",
-  "authors": [
-    "IRI"
-  ],
-  "license": "Ceccill-C",
-  "private": true,
-  "ignore": [
-    "**/.*",
-    "node_modules",
-    "bower_components",
-    "test",
-    "tests"
-  ],
-  "devDependencies": {
-    "angular": "~1.3",
-    "angular-route": "~1.3",
-    "angular-resource": "~1.3",
-    "angular-bootstrap": "~0.11.0",
-    "allmighty-autocomplete": "*",
-    "bootstrap": "~3.1.1",
-    "string": "*"
-  }
-}
--- a/client/data/categories.json	Wed Oct 29 12:50:30 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,254 +0,0 @@
-{
-    "categories": [
-        {
-            "label": "Ça me raconte",
-            "prelabel": "",
-            "color": "rgb(121,187,146)",
-            "code": "melodie",
-            "subcategories": [
-                {
-                    "label": "Mélodieux",
-                    "prelabel": "Ça me raconte",
-                    "color": "rgb(121,187,146)",
-                    "code": "cameraconte-melodieux"
-                },
-                {
-                    "label": "Consonnant",
-                    "prelabel": "Ça me raconte",
-                    "color": "rgb(121,187,146)",
-                    "code": "cameraconte-consonnant"
-                },
-                {
-                    "label": "Dissonnant",
-                    "prelabel": "Ça me raconte",
-                    "color": "rgb(121,187,146)",
-                    "code": "cameraconte-dissonnant"
-                },
-                {
-                    "label": "Construction",
-                    "prelabel": "Ça me raconte",
-                    "color": "rgb(121,187,146)",
-                    "code": "cameraconte-construction"
-                },
-                {
-                    "label": "Suspense",
-                    "prelabel": "Ça me raconte",
-                    "color": "rgb(121,187,146)",
-                    "code": "cameraconte-suspens"
-                },
-                {
-                    "label": "Intriguant",
-                    "prelabel": "Ça me raconte",
-                    "color": "rgb(121,187,146)",
-                    "code": "cameraconte-intriguant"
-                },
-                {
-                    "label": "Régulier",
-                    "prelabel": "Ça me raconte",
-                    "color": "rgb(121,187,146)",
-                    "code": "cameraconte-regulier"
-                }
-            ]
-        },
-        {
-            "label": "Ça me bouge",
-            "prelabel": "",
-            "color": "rgb(255,50,50)",
-            "code": "rythme",
-            "subcategories": [
-                {
-                    "label": "Lent",
-                    "prelabel": "Ça me bouge",
-                    "color": "rgb(255,50,50)",
-                    "code": "camebouge-lent"
-                },
-                {
-                    "label": "Rapide",
-                    "prelabel": "Ça me bouge",
-                    "color": "rgb(255,50,50)",
-                    "code": "camebouge-rapide"
-                },
-                {
-                    "label": "Déstructuré",
-                    "prelabel": "Ça me bouge",
-                    "color": "rgb(255,50,50)",
-                    "code": "camebouge-destructure"
-                },
-                {
-                    "label": "Ça swingue",
-                    "prelabel": "Ça me bouge",
-                    "color": "rgb(255,50,50)",
-                    "code": "camebouge-caswingue"
-                }
-            ]
-        },
-        {
-            "label": "Ça se bagarre",
-            "prelabel": "",
-            "color": "rgb(78,144,204)",
-            "code": "gestuelle",
-            "subcategories": [
-                {
-                    "label": "Interaction entre musiciens",
-                    "prelabel": "Ça se bagarre",
-                    "color": "rgb(78,144,204)",
-                    "code": "casebagarre-interaction"
-                },
-                {
-                    "label": "Contact",
-                    "prelabel": "Ça se bagarre",
-                    "color": "rgb(78,144,204)",
-                    "code": "casebagarre-contact"
-                },
-                {
-                    "label": "Théâtralité",
-                    "prelabel": "Ça se bagarre",
-                    "color": "rgb(78,144,204)",
-                    "code": "casebagarre-theatralite"
-                },
-                {
-                    "label": "Danse",
-                    "prelabel": "Ça se bagarre",
-                    "color": "rgb(78,144,204)",
-                    "code": "casebagarre-danse"
-                }
-            ]
-        },
-        {
-            "label": "Ça sonne",
-            "prelabel": "",
-            "color": "rgb(222,139,83)",
-            "code": "a-rejouer",
-            "subcategories": [
-                {
-                    "label": "Piano",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-piano"
-                },
-                {
-                    "label": "Clarinette",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-clarinette"
-                },
-                {
-                    "label": "Saxophone",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-saxophone"
-                },
-                {
-                    "label": "Batterie",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-batterie"
-                },
-                {
-                    "label": "Voix chantée",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-voixchantee"
-                },
-                {
-                    "label": "Guitare",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-guitare"
-                },
-                {
-                    "label": "Synthé",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-synthe"
-                },
-                {
-                    "label": "Voix parlée",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-voixparlee"
-                },
-                {
-                    "label": "Karlax",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-karlax"
-                },
-                {
-                    "label": "Boîte à rythme",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-boitearythme"
-                },
-                {
-                    "label": "Flûte",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-flute"
-                },
-                {
-                    "label": "Violon",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-violon"
-                },
-                {
-                    "label": "Flûte Scoatariu",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-flutescoatariu"
-                },
-                {
-                    "label": "Violoncelle",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-violoncelle"
-                },
-                {
-                    "label": "Accordéon",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-accordeon"
-                },
-                {
-                    "label": "Guitare électrique",
-                    "prelabel": "Ça sonne",
-                    "color": "rgb(222,139,83)",
-                    "code": "casonne-guitareelectrique"
-                }
-            ]
-        },
-        {
-            "label": "À Rejouer",
-            "prelabel": "",
-            "color": "rgb(205,200,63)",
-            "code": "a-rejouer",
-            "subcategories": [
-                {
-                    "label": "À l'identique",
-                    "prelabel": "À Rejouer",
-                    "color": "rgb(205,200,63)",
-                    "code": "a-rejouer-alidentique"
-                },
-                {
-                    "label": "Plus vite",
-                    "prelabel": "À Rejouer",
-                    "color": "rgb(205,200,63)",
-                    "code": "a-rejouer-plus-vite"
-                },
-                {
-                    "label": "Plus lentement",
-                    "prelabel": "À Rejouer",
-                    "color": "rgb(205,200,63)",
-                    "code": "a-rejouer-plus-lentement"
-                },
-                {
-                    "label": "Avec un autre instrument",
-                    "prelabel": "À Rejouer",
-                    "color": "rgb(205,200,63)",
-                    "code": "a-rejouer-autre-instrument"
-                }
-            ]
-        }
-    ]
-}
\ No newline at end of file
--- a/client/gulpfile.js	Wed Oct 29 12:50:30 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +0,0 @@
-var gulp = require('gulp');
-var del = require('del');
-var gutil = require('gulp-util')
-var plugins = require("gulp-load-plugins")({lazy:false});
-
-var templateFolder = '../annot-server/webapp/templates/';
-var templateFileDest = '../annot-server/webapp/templates/annotationclient.html';
-var staticFolder = '../annot-server/static';
-
-var clientBaseName = 'app';
-var vendorBaseName = 'lib';
-
-gulp.task('clean', function (cb) {
-    del([
-        templateFileDest,
-        staticFolder + "/css/app*",
-        staticFolder + "/js/app*",
-        staticFolder + "/data/categories.json",
-    ],{'force':true}, cb);
-});
-
-var scriptsSrc = ['!./app/**/*_test.js','./app/**/*.js'];
-
-gulp.task('scripts', function(){
-    //combine all js files of the app
-    gulp.src(scriptsSrc)
-        .pipe(plugins.jshint())
-        .pipe(plugins.jshint.reporter('default'))
-        .pipe(plugins.jshint.reporter('fail'))
-        .pipe(plugins.concat(clientBaseName+'.js'))
-        .pipe(gulp.dest(staticFolder+'/js'))
-        .pipe(plugins.filesize())
-        .pipe(plugins.uglify())
-        .pipe(plugins.rename(clientBaseName+'.min.js'))
-        .pipe(gulp.dest(staticFolder+'/js'))
-        .pipe(plugins.filesize())
-        .on('error', gutil.log);
-});
-
-
-gulp.task('css', function(){
-    gulp.src('./app/**/*.css')
-        .pipe(plugins.csslint({ 'box-sizing': false }))
-        .pipe(plugins.csslint.reporter())
-        .pipe(plugins.concat(clientBaseName+'.css'))
-        .pipe(gulp.dest(staticFolder+'/css'))
-        .pipe(plugins.filesize())
-        .pipe(plugins.minifyCss({keepBreaks:true}))
-        .pipe(plugins.rename(clientBaseName+'.min.css'))
-        .pipe(gulp.dest(staticFolder+'/css'))
-        .pipe(plugins.filesize());
-});
-
-var vendorJSsrc = [
-  '!./bower_components/**/*.min.js',
-  '!./bower_components/bootstrap/Gruntfile.js',
-  '!./bower_components/bootstrap/grunt/*',
-  '!./bower_components/bootstrap/js/*',
-  '!./bower_components/jquery/src/**/*',
-  '!./bower_components/angular-bootstrap/ui-bootstrap.js',
-  './bower_components/jquery/dist/jquery.js',
-  './bower_components/angular/angular.js',
-  './bower_components/**/*.js'
-];
-
-gulp.task('vendorJS', function(){
-    //concatenate vendor JS files
-    gulp.src(vendorJSsrc)
-        .pipe(plugins.concat('lib.js'))
-        .pipe(gulp.dest(staticFolder+'/js'))
-        .pipe(plugins.filesize())
-        .pipe(plugins.uglify())
-        .pipe(plugins.rename('lib.min.js'))
-        .pipe(gulp.dest(staticFolder+'/js'))
-        .pipe(plugins.filesize())
-        .on('error', gutil.log);
-});
-
-gulp.task('vendorCSS', function(){
-    //concatenate vendor CSS files
-    gulp.src(['!./bower_components/**/*.min.css',
-        './bower_components/**/*.css'])
-        .pipe(plugins.concat(vendorBaseName+'.css'))
-        .pipe(gulp.dest(staticFolder+'/css'))
-        .pipe(plugins.filesize())
-        .pipe(plugins.minifyCss({keepBreaks:true}))
-        .pipe(plugins.rename(vendorBaseName+'.min.css'))
-        .pipe(gulp.dest(staticFolder+'/css'))
-        .pipe(plugins.filesize());
-});
-
-gulp.task('vendorFonts', function(){
-    gulp.src(['./bower_components/**/fonts/*'])
-        .pipe(plugins.flatten())
-        .pipe(gulp.dest(staticFolder+'/css/fonts'));
-});
-
-gulp.task('copy-index', function() {
-    gulp.src('./app/annotationclient.html')
-        .pipe(gulp.dest(templateFolder));
-});
-
-gulp.task('copy-data', function() {
-    gulp.src('./data/**/*')
-        .pipe(gulp.dest(staticFolder+'/data'));
-});
-
-gulp.task('copy-img', function() {
-    gulp.src('./img/**/*')
-        .pipe(gulp.dest(staticFolder+'/img'));
-});
-
-gulp.task('watch',function(){
-    gulp.watch([
-        templateFolder+'/**/*.html',
-        staticFolder+'/**/*.js',
-        staticFolder+'/**/*.css'
-    ], function(event) {
-        return gulp.src(event.path)
-            .pipe(plugins.webserver.reload());
-    });
-    gulp.watch(['./app/**/*.js','!./app/**/*test.js'],['scripts']);
-    gulp.watch('./app/**/*.css',['css']);
-    gulp.watch('./app/annotationclient.html',['copy-index']);
-    gulp.watch('./data/**/*',['copy-data']);
-    gulp.watch('./img/**/*',['copy-img']);
-
-});
-
-gulp.task('connect', function() {
-    gulp.src('build').pipe(
-        plugins.webserver({
-            port: 9000,
-            livereload: true
-        })
-    );
-});
-
-gulp.task('default',['scripts','css','copy-index','copy-data','copy-img','vendorJS','vendorCSS','vendorFonts']);
--- a/client/karma-unit.js	Wed Oct 29 12:50:30 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-// Karma configuration
-// Generated on Thu Mar 27 2014 15:49:13 GMT+0800 (PHT)
-
-module.exports = function(config) {
-  config.set({
-
-    // base path that will be used to resolve all patterns (eg. files, exclude)
-    basePath: '',
-
-
-    // frameworks to use
-    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
-    frameworks: ['jasmine'],
-
-
-    // list of files / patterns to load in the browser
-    files: [
-        './build/lib.js',
-        './build/app.js',
-        './build/templates.js',
-        './app/**/*test.js'
-    ],
-
-
-    // list of files to exclude
-    exclude: [
-      
-    ],
-
-
-    // preprocess matching files before serving them to the browser
-    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
-    preprocessors: {
-    
-    },
-
-
-    // test results reporter to use
-    // possible values: 'dots', 'progress'
-    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
-    reporters: ['progress'],
-
-
-    // web server port
-    port: 9876,
-
-
-    // enable / disable colors in the output (reporters and logs)
-    colors: true,
-
-
-    // level of logging
-    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
-    logLevel: config.LOG_DEBUG,
-
-
-    // enable / disable watching file and executing tests whenever any file changes
-    autoWatch: true,
-
-
-    // start these browsers
-    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
-    browsers: ['Chrome'],
-
-
-    // Continuous Integration mode
-    // if true, Karma captures browsers, runs the tests and exits
-    singleRun: false
-  });
-};
--- a/client/package.json	Wed Oct 29 12:50:30 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-{
-  "name": "mons",
-  "version": "0.0.0",
-  "description": "Mons client application",
-  "main": "app.js",
-  "repository": {
-    "type": "mercurial",
-    "url": "http://www.iri.centrepompidou.fr/dev/hg/mons"
-  },
-  "author": "IRI",
-  "license": "Cecill-C",
-  "devDependencies": {
-    "bower": "^1.3.12",
-    "del": "^0.1.3",
-    "grunt-cli": "^0.1.13",
-    "gulp": "~3.8.8",
-    "gulp-angular-templatecache": "^1.4.2",
-    "gulp-concat": "~2.4.1",
-    "gulp-csslint": "^0.1.5",
-    "gulp-filesize": "0.0.6",
-    "gulp-flatten": "0.0.4",
-    "gulp-jshint": "~1.8.5",
-    "gulp-load-plugins": "~0.7.0",
-    "gulp-minify-css": "^0.3.10",
-    "gulp-rename": "^1.2.0",
-    "gulp-uglify": "^1.0.1",
-    "gulp-util": "^3.0.1",
-    "gulp-webserver": "^0.8.3",
-    "karma": "^0.12.23",
-    "karma-chrome-launcher": "^0.1.4",
-    "karma-jasmine": "^0.1.5"
-  }
-}