<commit_before>'use strict';

var types = require('../../lib' + (process.env.MOVICO_COV || '') + '/Movico/types.js').types,
    ast = require('../../lib' + (process.env.MOVICO_COV || '') + '/Movico/ast.js').ast,
    list = require('../../lib' + (process.env.MOVICO_COV || '') + '/Data/list.js').list,
    pair = require('../../lib' + (process.env.MOVICO_COV || '') + '/Data/pair.js').pair;

/*
  ======== A Handy Little Nodeunit Reference ========
  https://github.com/caolan/nodeunit

  Test methods:
    test.expect(numAssertions)
    test.done()
  Test assertions:
    test.ok(value, [message])
    test.equal(actual, expected, [message])
    test.notEqual(actual, expected, [message])
    test.(actual, expected, [message])
    test.notDeepEqual(actual, expected, [message])
    test.strictEqual(actual, expected, [message])
    test.notStrictEqual(actual, expected, [message])
    test.throws(block, [error], [message])
    test.doesNotThrow(block, [error], [message])
    test.ifError(value)
*/

exports['types_freevar'] = {
  setUp: function(done) {
    done();
  },

  "Unify native & native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.native("a"),
                          ast.type.native("a")).success().isEmpty(),
              "Unify native");
      test.done();
  },

  "Unify failure native & native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.native("a"),
                          ast.type.native("b")).isFailure(),
              "Unify failure native");
      test.done();
  },

  "Unify variable & native": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.variable("b"),
                                 ast.type.native("a")).success(),
              list(pair("b",ast.type.native("a"))),
              "Unify variable & native");
      test.done();
  },

  "Unify native & variable": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.native("a"),
                                 ast.type.variable("a")).success(),
              list(pair("a",ast.type.native("a"))),
              "Unify variable & native");
      test.done();
  },

  "Unify array native & native": function (test) {
      test.expect(1);
      // Test
      test.equal(types.unify(ast.type.array(ast.type.native("a")),
                             ast.type.native("a")).isSuccess(),
                 false,
                 "Unify array native & native");
      test.done();
  },

  "Unify native & array native": function (test) {
      test.expect(1);
      // Test
      test.equal(types.unify(ast.type.native("a"),
                            ast.type.array(ast.type.native("a"))).isSuccess(),
                 false,
                 "Unify array native & native");
      test.done();
  },

  "Unify array native & array native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.array(ast.type.native("a")),
                          ast.type.array(ast.type.native("a"))).success().isEmpty(),
              "Unify array native & array native");
      test.done();
  },

  "Unify failure array native & array native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.array(ast.type.native("a")),
                          ast.type.array(ast.type.native("b"))).isFailure(),
              "Unify failure array native & array native");
      test.done();
  },

  "Unify array variable & array native": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.array(ast.type.variable("b")),
                                 ast.type.array(ast.type.native("a"))).success(),
                     list(pair("b",ast.type.native("a"))),
                     "Unify array variable & array native");
      test.done();
  },

  "Unify array native & array variable": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.array(ast.type.native("a")),
                                 ast.type.array(ast.type.variable("b"))).success(),
                     list(pair("b",ast.type.native("a"))),
                     "Unify array variable & array native");
      test.done();
  },

  "Unify pair native & native": function (test) {
      test.expect(1);
      // Test
      test.equal(types.unify(ast.type.pair(ast.type.native("a"),ast.type.native("b")),
                             ast.type.native("a")).isSuccess(),
                 false,
                 "Unify pair native & native");
      test.done();
  },

  "Unify failure pair first native & pair native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.pair(ast.type.native("a"),ast.type.native("b")),
                          ast.type.pair(ast.type.native("b"),ast.type.native("b"))).isFailure(),
              "Unify failure pair native & pair native");
      test.done();
  },

  "Unify failure pair second native & pair native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.pair(ast.type.native("a"),ast.type.native("b")),
                          ast.type.pair(ast.type.native("a"),ast.type.native("a"))).isFailure(),
              "Unify failure pair native & pair native");
      test.done();
  },

  "Unify pair variable & pair native": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.pair(ast.type.variable("b"),ast.type.variable("a")),
                                 ast.type.pair(ast.type.native("a"),ast.type.native("b"))).success(),
                     list(pair("a",ast.type.native("b")), pair("b",ast.type.native("a"))),
                     "Unify pair native & pair native");
      test.done();
  },

  "Unify pair native & pair variable": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.pair(ast.type.native("b"),ast.type.native("a")),
                                 ast.type.pair(ast.type.variable("a"),ast.type.variable("b"))).success(),
                     list(pair("b",ast.type.native("a")),pair("a",ast.type.native("b"))),
                     "Unify pair native & pair native");
      test.done();
  },

  "Unify function native & native": function (test) {
      test.expect(1);
      // Test
      test.equal(types.unify(ast.type.abstraction(ast.type.native("a"),ast.type.native("b")),
                             ast.type.native("a")).isSuccess(),
                 false,
                 "Unify function native & native");
      test.done();
  },

  "Unify function native & function native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.abstraction(ast.type.native("a"),ast.type.native("b")),
                          ast.type.abstraction(ast.type.native("a"),ast.type.native("b"))).success().isEmpty(),
              "Unify function native & function native");
      test.done();
  },

  "Unify function failure native & function native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.abstraction(ast.type.native("a"),ast.type.native("b")),
                          ast.type.abstraction(ast.type.native("b"),ast.type.native("a"))).isFailure(),
              "Unify function native & function native");
      test.done();
  },

  "Unify function variable & function native": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.abstraction(ast.type.variable("b"),ast.type.variable("a")),
                                 ast.type.abstraction(ast.type.native("a"),ast.type.native("b"))).success(),
                     list(pair("a",ast.type.native("b")),pair("b",ast.type.native("a"))),
                     "Unify function variable & function native");
      test.done();
  },

  "Unify function native & function variable": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.abstraction(ast.type.native("b"),ast.type.native("a")),
                                 ast.type.abstraction(ast.type.variable("a"),ast.type.variable("b"))).success(),
                     list(pair("b",ast.type.native("a")),pair("a",ast.type.native("b"))),
                     "Unify function native & function variable");
      test.done();
  },

  "Unify function with required subtitution": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.abstraction(ast.type.native("b"),ast.type.variable("a")),
                                 ast.type.abstraction(ast.type.variable("a"),ast.type.native("b"))).success(),
                     list(pair("a",ast.type.native("b"))),
                     "Unify with substitution");
      test.done();
  },

  "Unify failure function with required substitution": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.abstraction(ast.type.native("b"),ast.type.variable("a")),
                          ast.type.abstraction(ast.type.variable("a"),ast.type.native("c"))).isFailure(),
              "Unify failure function native & function native");
      test.done();
  },

};
 <commit_msg>Check cyclic type unification<commit_after>'use strict';

var types = require('../../lib' + (process.env.MOVICO_COV || '') + '/Movico/types.js').types,
    ast = require('../../lib' + (process.env.MOVICO_COV || '') + '/Movico/ast.js').ast,
    list = require('../../lib' + (process.env.MOVICO_COV || '') + '/Data/list.js').list,
    pair = require('../../lib' + (process.env.MOVICO_COV || '') + '/Data/pair.js').pair;

/*
  ======== A Handy Little Nodeunit Reference ========
  https://github.com/caolan/nodeunit

  Test methods:
    test.expect(numAssertions)
    test.done()
  Test assertions:
    test.ok(value, [message])
    test.equal(actual, expected, [message])
    test.notEqual(actual, expected, [message])
    test.(actual, expected, [message])
    test.notDeepEqual(actual, expected, [message])
    test.strictEqual(actual, expected, [message])
    test.notStrictEqual(actual, expected, [message])
    test.throws(block, [error], [message])
    test.doesNotThrow(block, [error], [message])
    test.ifError(value)
*/

exports['types_freevar'] = {
  setUp: function(done) {
    done();
  },

  "Unify native & native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.native("a"),
                          ast.type.native("a")).success().isEmpty(),
              "Unify native");
      test.done();
  },

  "Unify failure native & native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.native("a"),
                          ast.type.native("b")).isFailure(),
              "Unify failure native");
      test.done();
  },

  "Unify variable & native": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.variable("b"),
                                 ast.type.native("a")).success(),
              list(pair("b",ast.type.native("a"))),
              "Unify variable & native");
      test.done();
  },

  "Unify native & variable": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.native("a"),
                                 ast.type.variable("a")).success(),
              list(pair("a",ast.type.native("a"))),
              "Unify variable & native");
      test.done();
  },

  "Unify array native & native": function (test) {
      test.expect(1);
      // Test
      test.equal(types.unify(ast.type.array(ast.type.native("a")),
                             ast.type.native("a")).isSuccess(),
                 false,
                 "Unify array native & native");
      test.done();
  },

  "Unify native & array native": function (test) {
      test.expect(1);
      // Test
      test.equal(types.unify(ast.type.native("a"),
                            ast.type.array(ast.type.native("a"))).isSuccess(),
                 false,
                 "Unify array native & native");
      test.done();
  },

  "Unify array native & array native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.array(ast.type.native("a")),
                          ast.type.array(ast.type.native("a"))).success().isEmpty(),
              "Unify array native & array native");
      test.done();
  },

  "Unify failure array native & array native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.array(ast.type.native("a")),
                          ast.type.array(ast.type.native("b"))).isFailure(),
              "Unify failure array native & array native");
      test.done();
  },

  "Unify array variable & array native": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.array(ast.type.variable("b")),
                                 ast.type.array(ast.type.native("a"))).success(),
                     list(pair("b",ast.type.native("a"))),
                     "Unify array variable & array native");
      test.done();
  },

  "Unify array native & array variable": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.array(ast.type.native("a")),
                                 ast.type.array(ast.type.variable("b"))).success(),
                     list(pair("b",ast.type.native("a"))),
                     "Unify array variable & array native");
      test.done();
  },

  "Unify pair native & native": function (test) {
      test.expect(1);
      // Test
      test.equal(types.unify(ast.type.pair(ast.type.native("a"),ast.type.native("b")),
                             ast.type.native("a")).isSuccess(),
                 false,
                 "Unify pair native & native");
      test.done();
  },

  "Unify failure pair first native & pair native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.pair(ast.type.native("a"),ast.type.native("b")),
                          ast.type.pair(ast.type.native("b"),ast.type.native("b"))).isFailure(),
              "Unify failure pair native & pair native");
      test.done();
  },

  "Unify failure pair second native & pair native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.pair(ast.type.native("a"),ast.type.native("b")),
                          ast.type.pair(ast.type.native("a"),ast.type.native("a"))).isFailure(),
              "Unify failure pair native & pair native");
      test.done();
  },

  "Unify pair variable & pair native": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.pair(ast.type.variable("b"),ast.type.variable("a")),
                                 ast.type.pair(ast.type.native("a"),ast.type.native("b"))).success(),
                     list(pair("a",ast.type.native("b")), pair("b",ast.type.native("a"))),
                     "Unify pair native & pair native");
      test.done();
  },

  "Unify pair native & pair variable": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.pair(ast.type.native("b"),ast.type.native("a")),
                                 ast.type.pair(ast.type.variable("a"),ast.type.variable("b"))).success(),
                     list(pair("b",ast.type.native("a")),pair("a",ast.type.native("b"))),
                     "Unify pair native & pair native");
      test.done();
  },

  "Unify function native & native": function (test) {
      test.expect(1);
      // Test
      test.equal(types.unify(ast.type.abstraction(ast.type.native("a"),ast.type.native("b")),
                             ast.type.native("a")).isSuccess(),
                 false,
                 "Unify function native & native");
      test.done();
  },

  "Unify function native & function native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.abstraction(ast.type.native("a"),ast.type.native("b")),
                          ast.type.abstraction(ast.type.native("a"),ast.type.native("b"))).success().isEmpty(),
              "Unify function native & function native");
      test.done();
  },

  "Unify function failure native & function native": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.abstraction(ast.type.native("a"),ast.type.native("b")),
                          ast.type.abstraction(ast.type.native("b"),ast.type.native("a"))).isFailure(),
              "Unify function native & function native");
      test.done();
  },

  "Unify function variable & function native": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.abstraction(ast.type.variable("b"),ast.type.variable("a")),
                                 ast.type.abstraction(ast.type.native("a"),ast.type.native("b"))).success(),
                     list(pair("a",ast.type.native("b")),pair("b",ast.type.native("a"))),
                     "Unify function variable & function native");
      test.done();
  },

  "Unify function native & function variable": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.abstraction(ast.type.native("b"),ast.type.native("a")),
                                 ast.type.abstraction(ast.type.variable("a"),ast.type.variable("b"))).success(),
                     list(pair("b",ast.type.native("a")),pair("a",ast.type.native("b"))),
                     "Unify function native & function variable");
      test.done();
  },

  "Unify function with required subtitution": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.abstraction(ast.type.native("b"),ast.type.variable("a")),
                                 ast.type.abstraction(ast.type.variable("a"),ast.type.native("b"))).success(),
                     list(pair("a",ast.type.native("b"))),
                     "Unify with substitution");
      test.done();
  },

  "Unify failure function with required substitution": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.abstraction(ast.type.native("b"),ast.type.variable("a")),
                          ast.type.abstraction(ast.type.variable("a"),ast.type.native("c"))).isFailure(),
              "Unify failure function native & function native");
      test.done();
  },

  "Unify cyclic dependency": function (test) {
      test.expect(1);
      // Test
      test.ok(types.unify(ast.type.variable("a"), ast.type.array(ast.type.variable("a"))).isFailure(),
              "Unify cyclic dependency");
      test.done();
  },

  "Unify same type variable": function (test) {
      test.expect(1);
      // Test
      test.deepEqual(types.unify(ast.type.variable("a"), ast.type.variable("a")).success(),
                     list(),
                     "Unify same type variable");
      test.done();
  },
};
 <|endoftext|>


<commit_before>/*
 *
 * BIC Calendar
 * Llicència Apache
 *
 */

$.fn.bic_calendar = function(options) {

    var opts = $.extend({}, $.fn.bic_calendar.defaults, options);

    this.each(function(){

        var calendario;
        var capaDiasMes;
        var capaTextoMesAnoActual = $('

');

        var id_calendari = "bic_cal_" + Math.floor(Math.random()*99999).toString(36);

        var events = opts.events;

        var dias;
        if ( typeof opts.dias != "undefined" )
            dias = opts.dias;
        else
            dias = ["l", "m", "x", "j", "v", "s", "d"];

        var nombresMes;
        if ( typeof opts.nombresMes != "undefined" )
            nombresMes = opts.nombresMes;
        else
            nombresMes = ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"];

        var show_days;
        if ( typeof opts.show_days != "undefined" )
            show_days = opts.show_days;
        else
            show_days = true;

        var pop_orientation;
        if ( typeof opts.pop_orientation != "undefined" )
            pop_orientation = opts.pop_orientation;
        else
            pop_orientation = 'top';

        var tip_orientation;
        if ( typeof opts.tip_orientation != "undefined" )
            tip_orientation = opts.tip_orientation;
        else
            tip_orientation = 'top';

        var req_ajax;
        if ( typeof opts.req_ajax != "undefined" )
            req_ajax = opts.req_ajax;
        else
            req_ajax = false;

        //element llamado
        var elem = $(this);

        //mostrem el calendari
        mostrarCalendario();

        /*** functions ***/

        //funció para mostrar el calendari
        function mostrarCalendario(){

            //capa con los días del mes
            capaDiasMes = $('
');

            llistar_literals_setmana();

            //un objeto de la clase date para calculo de fechas
            var objFecha = new Date();
            //miro si en el campo INPUT tengo alguna fecha escrita
            var textoFechaEscrita = elem.val();
            if (textoFechaEscrita!= ""){
                if (validarFechaEscrita(textoFechaEscrita)){
                    var arrayFechaEscrita = textoFechaEscrita.split("/");
                    //hago comprobación sobre si el año tiene dos cifras
                    if(arrayFechaEscrita[2].length == 2){
                        if (arrayFechaEscrita[2].charAt(0)=="0"){
                            arrayFechaEscrita[2] = arrayFechaEscrita[2].substring(1);
                        }
                        arrayFechaEscrita[2] = parseInt(arrayFechaEscrita[2]);
                        if (arrayFechaEscrita[2] < 50)
                            arrayFechaEscrita[2] += 2000;
                    }
                    objFecha = new Date(arrayFechaEscrita[2], arrayFechaEscrita[1]-1, arrayFechaEscrita[0])
                }
            }

            //mes y año actuales
            var mes = objFecha.getMonth();
            var ano = objFecha.getFullYear();
            //muestro los días del mes y año dados
            muestraDiasMes(mes, ano);

            //controles para ir al mes siguiente / anterior
            var botonMesSiguiente = $('	');
            botonMesSiguiente.click(function(e){
                e.preventDefault();
                mes = (mes + 1) % 12;
                if (mes==0)
                    ano++;
                canvi_mes(mes, ano);
            })
            var botonMesAnterior = $('	');
            botonMesAnterior.click(function(e){
                e.preventDefault();
                mes = (mes - 1);
                if (mes==-1){
                    ano--;
                    mes = 11;
                }
                canvi_mes(mes, ano);
            })

            //capa para mostrar el texto del mes y ano actual
            var capaTextoMesAno = $('

');
            var capaTextoMesAnoControl = $('	');
            capaTextoMesAno.append(botonMesAnterior);
            capaTextoMesAno.append(capaTextoMesAnoControl);
            capaTextoMesAno.append(botonMesSiguiente);
            capaTextoMesAnoControl.append(capaTextoMesAnoActual);

            //calendario y el borde
            calendario = $('

');
            calendario.prepend(capaTextoMesAno);
            //calendario.append(capaDiasSemana);
            //capaDiasMes.prepend(capaDiasSemana);
            calendario.append(capaDiasMes);

            //inserto el calendario en el documento
            elem.append(calendario);

            check_events(mes, ano);
        }

        function canvi_mes(mes, ano){
            capaDiasMes.empty();
            llistar_literals_setmana();
            muestraDiasMes(mes, ano);
            check_events(mes, ano);
        }

        //funció mostra literals setmana
        function llistar_literals_setmana(){
            if ( show_days != false ){
                var capaDiasSemana = $('
');
                var codigoInsertar = '';
                $(dias).each(function(indice, valor){
                    codigoInsertar += '" + valor + '	';
                });
                codigoInsertar += '
';
                capaDiasSemana.append(codigoInsertar);

                capaDiasMes.append(capaDiasSemana);
            }
        }

        function muestraDiasMes(mes, ano){
            //console.log("muestro (mes, ano): ", mes, " ", ano)
            //muestro en la capaTextoMesAno el mes y ano que voy a dibujar
            capaTextoMesAnoActual.text(nombresMes[mes] + " " + ano);

            //muestro los días del mes
            var contadorDias = 1;

            //calculo la fecha del primer día de este mes
            var primerDia = calculaNumeroDiaSemana(1, mes, ano);
            //calculo el último día del mes
            var ultimoDiaMes = ultimoDia(mes,ano);

            var n_mes = mes + 1;

            var capaDiasMes_string = "";

            //escribo la primera fila de la semana
            for (var i=0; i<7; i++){
                if (i < primerDia){
                    var codigoDia = "";
                    if (i == 0)
                        codigoDia += "
";
                    //si el dia de la semana i es menor que el numero del primer dia de la semana no pongo nada en la celda
                    codigoDia += '	';
                } else {
                    var codigoDia = "";
                    if (i == 0)
                        codigoDia += '
';
                    codigoDia += '' + contadorDias + '';
                    if (i == 6)
                        codigoDia += '
';
                    contadorDias++;
                }
                capaDiasMes_string += codigoDia
            }

            //recorro todos los demás días hasta el final del mes
            var diaActualSemana = 1;
            while (contadorDias <= ultimoDiaMes){
                var codigoDia = "";
                if (diaActualSemana % 7 == 1)
                    codigoDia += "
";
                codigoDia += '' + contadorDias + '	';
                if (diaActualSemana % 7 == 0)
                    codigoDia += "
";
                contadorDias++;
                diaActualSemana++;
                capaDiasMes_string += codigoDia
            }

            //compruebo que celdas me faltan por escribir vacias de la última semana del mes
            diaActualSemana--;
            if (diaActualSemana%7!=0){
                codigoDia = "";
                for (var i=(diaActualSemana%7)+1; i<=7; i++){
                    var codigoDia = "";
                    codigoDia += '	';
                    if (i==7)
                        codigoDia += '
'
                    capaDiasMes_string += codigoDia
                }
            }

            capaDiasMes.append( capaDiasMes_string );
        }
        //función para calcular el número de un día de la semana
        function calculaNumeroDiaSemana(dia,mes,ano){
            var objFecha = new Date(ano, mes, dia);
            var numDia = objFecha.getDay();
            if (numDia == 0)
                numDia = 6;
            else
                numDia--;
            return numDia;
        }

        //función para ver si una fecha es correcta
        function checkdate ( m, d, y ) {
            // función por http://kevin.vanzonneveld.net
            // extraida de las librerías phpjs.org manual en http://www.desarrolloweb.com/manuales/manual-librerias-phpjs.html
            return m > 0 && m < 13 && y > 0 && y < 32768 && d > 0 && d <= (new Date(y, m, 0)).getDate();
        }

        //funcion que devuelve el último día de un mes y año dados
        function ultimoDia(mes,ano){
            var ultimo_dia=28;
            while (checkdate(mes+1,ultimo_dia + 1,ano)){
                ultimo_dia++;
            }
            return ultimo_dia;
        }

        function validarFechaEscrita(fecha){
            var arrayFecha = fecha.split("/");
            if (arrayFecha.length!=3)
                return false;
            return checkdate(arrayFecha[1], arrayFecha[0], arrayFecha[2]);
        }

        function check_events(mes, ano){
            if (req_ajax != false){
                //peticio ajax
                $.ajax({
                    type: req_ajax.type,
                    url: req_ajax.url,
                    data: { mes: mes + 1, ano: ano },
                    dataType: 'json'
                }).done(function( data ) {

                    events = [];

                    $.each(data, function(k,v){
                        events.push(data[k]);
                    });

                    marcarEventos(mes, ano);

                });
            } else {
                marcarEventos(mes, ano);
            }
        }

        function marcarEventos(mes, ano){
            var t_mes = mes + 1;

            for(var i=0; i< events.length; i++) {

                if ( events[i][0].split('/')[1] == t_mes && events[i][0].split('/')[2] == ano ){

                    $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") ).addClass('event');

                    $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") + ' a' ).attr('data-original-title', events[i][1]);

                    //bg
                    if ( events[i][3] )
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") ).css('background', events[i][3]);

                    //link
                    if ( events[i][2] == '' ){
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") + ' a' ).attr('href', 'javascript:false;');
                    } else {
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") + ' a' ).attr('href', events[i][2]);
                    }

                    //tooltip vs popover
                    if ( events[i][4] ){
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") ).addClass('event_popover');
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") + ' a' ).attr('rel', 'popover');
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") + ' a' ).attr('data-content', events[i][4]);
                    } else {
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") ).addClass('event_tooltip');
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") + ' a' ).attr('rel', 'tooltip');
                    }
                }
            }

            $('#' + id_calendari + ' ' + '.event_tooltip a').tooltip({
                placement: tip_orientation
            });
            $('#' + id_calendari + ' ' + '.event_popover a').popover({
                placement: pop_orientation
            });
        }

    /*** --functions-- ***/

    });
    return this;
};

//defaults values
/*$.fn.highlight.defaults = {

    };*/<commit_msg>options of tooltip and popover options of plugin<commit_after>/*
 *
 * BIC Calendar
 * Llicència Apache
 *
 */

$.fn.bic_calendar = function(options) {

    var opts = $.extend({}, $.fn.bic_calendar.defaults, options);

    this.each(function(){

        var calendario;
        var capaDiasMes;
        var capaTextoMesAnoActual = $('

');

        var id_calendari = "bic_cal_" + Math.floor(Math.random()*99999).toString(36);

        var events = opts.events;

        var dias;
        if ( typeof opts.dias != "undefined" )
            dias = opts.dias;
        else
            dias = ["l", "m", "x", "j", "v", "s", "d"];

        var nombresMes;
        if ( typeof opts.nombresMes != "undefined" )
            nombresMes = opts.nombresMes;
        else
            nombresMes = ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"];

        var show_days;
        if ( typeof opts.show_days != "undefined" )
            show_days = opts.show_days;
        else
            show_days = true;

        var popover_options;
        if ( typeof opts.popover_options != "undefined" )
            popover_options = opts.popover_options;
        else
            popover_options = {placement: 'top'};

        var tooltip_options;
        if ( typeof opts.tooltip_options != "undefined" )
            tooltip_options = opts.tooltip_options;
        else
            tooltip_options = {placement: 'top'};

        var req_ajax;
        if ( typeof opts.req_ajax != "undefined" )
            req_ajax = opts.req_ajax;
        else
            req_ajax = false;

        //element llamado
        var elem = $(this);

        //mostrem el calendari
        mostrarCalendario();

        /*** functions ***/

        //funció para mostrar el calendari
        function mostrarCalendario(){

            //capa con los días del mes
            capaDiasMes = $('
');

            llistar_literals_setmana();

            //un objeto de la clase date para calculo de fechas
            var objFecha = new Date();
            //miro si en el campo INPUT tengo alguna fecha escrita
            var textoFechaEscrita = elem.val();
            if (textoFechaEscrita!= ""){
                if (validarFechaEscrita(textoFechaEscrita)){
                    var arrayFechaEscrita = textoFechaEscrita.split("/");
                    //hago comprobación sobre si el año tiene dos cifras
                    if(arrayFechaEscrita[2].length == 2){
                        if (arrayFechaEscrita[2].charAt(0)=="0"){
                            arrayFechaEscrita[2] = arrayFechaEscrita[2].substring(1);
                        }
                        arrayFechaEscrita[2] = parseInt(arrayFechaEscrita[2]);
                        if (arrayFechaEscrita[2] < 50)
                            arrayFechaEscrita[2] += 2000;
                    }
                    objFecha = new Date(arrayFechaEscrita[2], arrayFechaEscrita[1]-1, arrayFechaEscrita[0])
                }
            }

            //mes y año actuales
            var mes = objFecha.getMonth();
            var ano = objFecha.getFullYear();
            //muestro los días del mes y año dados
            muestraDiasMes(mes, ano);

            //controles para ir al mes siguiente / anterior
            var botonMesSiguiente = $('	');
            botonMesSiguiente.click(function(e){
                e.preventDefault();
                mes = (mes + 1) % 12;
                if (mes==0)
                    ano++;
                canvi_mes(mes, ano);
            })
            var botonMesAnterior = $('	');
            botonMesAnterior.click(function(e){
                e.preventDefault();
                mes = (mes - 1);
                if (mes==-1){
                    ano--;
                    mes = 11;
                }
                canvi_mes(mes, ano);
            })

            //capa para mostrar el texto del mes y ano actual
            var capaTextoMesAno = $('

');
            var capaTextoMesAnoControl = $('	');
            capaTextoMesAno.append(botonMesAnterior);
            capaTextoMesAno.append(capaTextoMesAnoControl);
            capaTextoMesAno.append(botonMesSiguiente);
            capaTextoMesAnoControl.append(capaTextoMesAnoActual);

            //calendario y el borde
            calendario = $('

');
            calendario.prepend(capaTextoMesAno);
            //calendario.append(capaDiasSemana);
            //capaDiasMes.prepend(capaDiasSemana);
            calendario.append(capaDiasMes);

            //inserto el calendario en el documento
            elem.append(calendario);

            check_events(mes, ano);
        }

        function canvi_mes(mes, ano){
            capaDiasMes.empty();
            llistar_literals_setmana();
            muestraDiasMes(mes, ano);
            check_events(mes, ano);
        }

        //funció mostra literals setmana
        function llistar_literals_setmana(){
            if ( show_days != false ){
                var capaDiasSemana = $('
');
                var codigoInsertar = '';
                $(dias).each(function(indice, valor){
                    codigoInsertar += '" + valor + '	';
                });
                codigoInsertar += '
';
                capaDiasSemana.append(codigoInsertar);

                capaDiasMes.append(capaDiasSemana);
            }
        }

        function muestraDiasMes(mes, ano){
            //console.log("muestro (mes, ano): ", mes, " ", ano)
            //muestro en la capaTextoMesAno el mes y ano que voy a dibujar
            capaTextoMesAnoActual.text(nombresMes[mes] + " " + ano);

            //muestro los días del mes
            var contadorDias = 1;

            //calculo la fecha del primer día de este mes
            var primerDia = calculaNumeroDiaSemana(1, mes, ano);
            //calculo el último día del mes
            var ultimoDiaMes = ultimoDia(mes,ano);

            var n_mes = mes + 1;

            var capaDiasMes_string = "";

            //escribo la primera fila de la semana
            for (var i=0; i<7; i++){
                if (i < primerDia){
                    var codigoDia = "";
                    if (i == 0)
                        codigoDia += "
";
                    //si el dia de la semana i es menor que el numero del primer dia de la semana no pongo nada en la celda
                    codigoDia += '	';
                } else {
                    var codigoDia = "";
                    if (i == 0)
                        codigoDia += '
';
                    codigoDia += '' + contadorDias + '';
                    if (i == 6)
                        codigoDia += '
';
                    contadorDias++;
                }
                capaDiasMes_string += codigoDia
            }

            //recorro todos los demás días hasta el final del mes
            var diaActualSemana = 1;
            while (contadorDias <= ultimoDiaMes){
                var codigoDia = "";
                if (diaActualSemana % 7 == 1)
                    codigoDia += "
";
                codigoDia += '' + contadorDias + '	';
                if (diaActualSemana % 7 == 0)
                    codigoDia += "
";
                contadorDias++;
                diaActualSemana++;
                capaDiasMes_string += codigoDia
            }

            //compruebo que celdas me faltan por escribir vacias de la última semana del mes
            diaActualSemana--;
            if (diaActualSemana%7!=0){
                codigoDia = "";
                for (var i=(diaActualSemana%7)+1; i<=7; i++){
                    var codigoDia = "";
                    codigoDia += '	';
                    if (i==7)
                        codigoDia += '
'
                    capaDiasMes_string += codigoDia
                }
            }

            capaDiasMes.append( capaDiasMes_string );
        }
        //función para calcular el número de un día de la semana
        function calculaNumeroDiaSemana(dia,mes,ano){
            var objFecha = new Date(ano, mes, dia);
            var numDia = objFecha.getDay();
            if (numDia == 0)
                numDia = 6;
            else
                numDia--;
            return numDia;
        }

        //función para ver si una fecha es correcta
        function checkdate ( m, d, y ) {
            // función por http://kevin.vanzonneveld.net
            // extraida de las librerías phpjs.org manual en http://www.desarrolloweb.com/manuales/manual-librerias-phpjs.html
            return m > 0 && m < 13 && y > 0 && y < 32768 && d > 0 && d <= (new Date(y, m, 0)).getDate();
        }

        //funcion que devuelve el último día de un mes y año dados
        function ultimoDia(mes,ano){
            var ultimo_dia=28;
            while (checkdate(mes+1,ultimo_dia + 1,ano)){
                ultimo_dia++;
            }
            return ultimo_dia;
        }

        function validarFechaEscrita(fecha){
            var arrayFecha = fecha.split("/");
            if (arrayFecha.length!=3)
                return false;
            return checkdate(arrayFecha[1], arrayFecha[0], arrayFecha[2]);
        }

        function check_events(mes, ano){
            if (req_ajax != false){
                //peticio ajax
                $.ajax({
                    type: req_ajax.type,
                    url: req_ajax.url,
                    data: { mes: mes + 1, ano: ano },
                    dataType: 'json'
                }).done(function( data ) {

                    events = [];

                    $.each(data, function(k,v){
                        events.push(data[k]);
                    });

                    marcarEventos(mes, ano);

                });
            } else {
                marcarEventos(mes, ano);
            }
        }

        function marcarEventos(mes, ano){
            var t_mes = mes + 1;

            for(var i=0; i< events.length; i++) {

                if ( events[i][0].split('/')[1] == t_mes && events[i][0].split('/')[2] == ano ){

                    $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") ).addClass('event');

                    $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") + ' a' ).attr('data-original-title', events[i][1]);

                    //bg
                    if ( events[i][3] )
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") ).css('background', events[i][3]);

                    //link
                    if ( events[i][2] == '' ){
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") + ' a' ).attr('href', 'javascript:false;');
                    } else {
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") + ' a' ).attr('href', events[i][2]);
                    }

                    //tooltip vs popover
                    if ( events[i][4] ){
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") ).addClass('event_popover');
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") + ' a' ).attr('rel', 'popover');
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") + ' a' ).attr('data-content', events[i][4]);
                    } else {
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") ).addClass('event_tooltip');
                        $('#' + id_calendari + '_' + events[i][0].replace(/\//g, "_") + ' a' ).attr('rel', 'tooltip');
                    }
                }
            }

            $('#' + id_calendari + ' ' + '.event_tooltip a').tooltip(tooltip_options);
            $('#' + id_calendari + ' ' + '.event_popover a').popover(popover_options);
        }

    /*** --functions-- ***/

    });
    return this;
};

//defaults values
/*$.fn.highlight.defaults = {

    };*/<|endoftext|>


<commit_before>/*jshint node:true, mocha:true*/
/**
 * @author pmeijer / https://github.com/pmeijer
 */

var testFixture = require('../_globals');

describe('AddOnManager', function () {
    'use strict';
    var expect = testFixture.expect,
        AddOnManager = require('../../src/addon/addonmanager'),
        logger = testFixture.logger.fork('AddOnManager');

    describe('starting and stopping monitors using a mock storage', function () {
        var gmeConfig = testFixture.getGmeConfig();

        gmeConfig.addOn.enable = true;
        gmeConfig.addOn.monitorTimeout = 100;

        function StorageMock(manager, done) {
            var self = this;
            this.branchCounter = 0;
            this.deferredCnt = 0;
            this.monitorTimeout = 40;
            this.unMonitorTimeout = 40;

            this.closeBranchTimeout = 5;

            this.openBranch = function (projectId, branchName, updateFn, branchStatusFn, callback) {
                setTimeout(function () {
                    self.branchCounter += 1;
                    callback(null);

                    setTimeout(function () {
                        self.deferredCnt += 1;
                        manager.monitorBranch('dummySession', branchName)
                            .then(function () {
                                self.deferredCnt -= 1;
                                //console.log('monitorBranch');
                            })
                            .catch(done);
                    }, self.monitorTimeout);

                }, 5);
            };

            this.closeBranch = function (projectId, branchName, callback) {
                setTimeout(function () {
                    self.branchCounter -= 1;
                    if (self.branchCounter < 0) {
                        done(new Error('branch counter became negative'));
                    }
                    callback(null);

                    setTimeout(function () {
                        self.deferredCnt += 1;
                        manager.unMonitorBranch('dummySession', branchName)
                            .then(function () {
                                self.deferredCnt -= 1;
                                //console.log('unMonitorBranch');
                            })
                            .catch(done);
                    }, self.unMonitorTimeout);

                }, self.closeBranchTimeout);
            };

        }

        it('should dispatch NO_MONITORS after open branch and closing AFTER the monitor opened the branch',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    branchName = 'test1';
                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    expect(storage.branchCounter).to.equal(0);
                    expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                    expect(manager.branchMonitors).to.deep.equal({});
                    done();
                });

                storage.openBranch('mockProjectId', branchName, null, null, function (/*err*/) {
                    expect(storage.branchCounter).to.equal(1);
                    expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);

                    setTimeout(function () {
                        expect(storage.branchCounter).to.equal(2);
                        expect(manager.branchMonitors[branchName].connectionCnt).to.equal(2);
                        storage.closeBranch('mockProjectId', branchName, function (/*err*/) {
                            expect(storage.branchCounter).to.equal(1);
                        });
                    }, 140);
                });
            }
        );

        it('should dispatch NO_MONITORS after open branch and closing BEFORE the monitor opened the branch',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    branchName = 'test2';
                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    expect(storage.branchCounter).to.equal(0);
                    expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                    expect(manager.branchMonitors).to.deep.equal({});
                    done();
                });

                storage.openBranch('mockProjectId', branchName, null, null, function (/*err*/) {
                    expect(storage.branchCounter).to.equal(1);
                    expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);
                    storage.closeBranch('mockProjectId', branchName, function (/*err*/) {

                    });
                });
            }
        );

        it('should dispatch NO_MONITORS (once) after open branch and closing AFTER the monitor opened the branch' +
            ' and opening branch while monitor is in timeout.',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    branchName = 'test3';
                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    expect(storage.branchCounter).to.equal(0);
                    expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                    expect(manager.branchMonitors).to.deep.equal({});
                    done();
                });

                storage.openBranch('mockProjectId', branchName, null, null, function () {
                    expect(storage.branchCounter).to.equal(1);
                    expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);
                    setTimeout(function () {
                        expect(storage.branchCounter).to.equal(2);
                        expect(manager.branchMonitors[branchName].connectionCnt).to.equal(2);
                        storage.closeBranch('mockProjectId', branchName, function () {
                            expect(storage.branchCounter).to.equal(1);
                            expect(manager.branchMonitors[branchName].connectionCnt).to.equal(2);
                            storage.openBranch('mockProjectId', branchName, null, null, function () {
                                expect(storage.branchCounter).to.equal(2);
                                setTimeout(function () {
                                    expect(manager.branchMonitors[branchName].connectionCnt).to.equal(2);
                                    storage.closeBranch('mockProjectId', branchName, function () {

                                    });
                                }, 120);
                            });
                        });
                    }, 120);
                });
            }
        );

        it('should dispatch NO_MONITORS (twice) after open branch and closing BEFORE the monitor opened the branch' +
            ' and opening branch and closing branch.',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    emptyCnt = 0,
                    branchName = 'test4';

                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    emptyCnt += 1;
                    if (emptyCnt === 2) {
                        expect(storage.branchCounter).to.equal(0);
                        expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                        expect(manager.branchMonitors).to.deep.equal({});
                        done();
                    }
                });

                storage.openBranch('mockProjectId', branchName, null, null, function () {
                    expect(storage.branchCounter).to.equal(1);
                    expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);

                    storage.closeBranch('mockProjectId', branchName, function () {
                        expect(storage.branchCounter).to.equal(0);
                        expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);

                        setTimeout(function () {
                            expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);

                            storage.openBranch('mockProjectId', branchName, null, null, function () {
                                setTimeout(function () {
                                    expect(storage.branchCounter).to.equal(2);
                                    expect(manager.branchMonitors[branchName].connectionCnt).to.equal(2);
                                    storage.closeBranch('mockProjectId', branchName, function () {

                                    });
                                }, 120);
                            });
                        }, 120);
                    });
                });
            }
        );

        it('should dispatch NO_MONITORS (once) after 2 open branches and closing AFTER the monitor opened the branch.',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    branchName = 'test5';

                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    expect(storage.branchCounter).to.equal(0);
                    expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                    expect(manager.branchMonitors).to.deep.equal({});
                    done();
                });

                storage.openBranch('mockProjectId', branchName, null, null, function () {});
                storage.openBranch('mockProjectId', branchName, null, null, function () {
                    expect(storage.branchCounter).to.equal(2);
                    setTimeout(function () {
                        expect(storage.branchCounter).to.equal(3);
                        expect(manager.branchMonitors[branchName].connectionCnt).to.equal(3);
                        storage.closeBranch('mockProjectId', branchName, function () {});
                        storage.closeBranch('mockProjectId', branchName, function () {});
                    }, 120);
                });
            }
        );

        it('should dispatch NO_MONITORS (twice) after 2 open branches and closing AFTER the monitor opened the branch.',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    branchName = 'test6',
                    emptyCnt = 0;

                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    emptyCnt += 1;
                    if (emptyCnt === 2) {
                        expect(storage.branchCounter).to.equal(0);
                        expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                        expect(manager.branchMonitors).to.deep.equal({});
                        done();
                    }
                });

                storage.openBranch('mockProjectId', branchName, null, null, function () {});
                storage.openBranch('mockProjectId', branchName, null, null, function () {
                    expect(storage.branchCounter).to.equal(2);
                    expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);
                    storage.closeBranch('mockProjectId', branchName, function () {});
                    storage.closeBranch('mockProjectId', branchName, function () {});
                });
            }
        );

        it('should enter StopAndStarted and succeed gracefully with one new monitor',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    branchName = 'test7',
                    emptyCnt = 0;

                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    emptyCnt += 1;
                    if (emptyCnt === 2) {
                        expect(storage.branchCounter).to.equal(0);
                        expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                        expect(manager.branchMonitors).to.deep.equal({});
                        done();
                    }
                });

                storage.openBranch('mockProjectId', branchName, null, null, function (/*err*/) {
                    expect(storage.branchCounter).to.equal(1);
                    expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);

                    setTimeout(function () {
                        expect(manager.branchMonitors[branchName].connectionCnt).to.equal(2);
                        // Monitor has connected..

                        storage.closeBranch('mockProjectId', branchName, function (/*err*/) {
                            storage.closeBranchTimeout = 400; //Slow down the branch closing for the monitor.
                            expect(storage.branchCounter).to.equal(1);
                            setTimeout(function () {
                                // Here the timeout should have started and triggered.
                                // But branch still open for monitor..
                                expect(manager.branchMonitors[branchName].connectionCnt).to.equal(1);
                                expect(manager.branchMonitors[branchName].instance.stopRequested).to.equal(true);
                                // At this point we connect a new client.
                                storage.openBranch('mockProjectId', branchName, null, null, function (/*err*/) {
                                    setTimeout(function () {
                                        storage.closeBranchTimeout = 40; //Set it back.
                                        storage.closeBranch('mockProjectId', branchName, function () {});
                                    }, 300);
                                });

                            }, 200);
                        });
                    }, 120);
                });
            }
        );

        it('should enter StopAndStarted and succeed gracefully with two new monitors',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    branchName = 'test7',
                    emptyCnt = 0;

                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    emptyCnt += 1;
                    if (emptyCnt === 2) {
                        expect(storage.branchCounter).to.equal(0);
                        expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                        expect(manager.branchMonitors).to.deep.equal({});
                        done();
                    }
                });

                storage.openBranch('mockProjectId', branchName, null, null, function (/*err*/) {
                    expect(storage.branchCounter).to.equal(1);
                    expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);

                    setTimeout(function () {
                        expect(manager.branchMonitors[branchName].connectionCnt).to.equal(2);
                        // Monitor has connected..

                        storage.closeBranch('mockProjectId', branchName, function (/*err*/) {
                            storage.closeBranchTimeout = 400; //Slow down the branch closing for the monitor.
                            expect(storage.branchCounter).to.equal(1);
                            setTimeout(function () {
                                // Here the timeout should have started and triggered.
                                // But branch still open for monitor..
                                expect(manager.branchMonitors[branchName].connectionCnt).to.equal(1);
                                expect(manager.branchMonitors[branchName].instance.stopRequested).to.equal(true);
                                // At this point we connect a new client.
                                storage.openBranch('mockProjectId', branchName, null, null, function (/*err*/) {});
                                storage.openBranch('mockProjectId', branchName, null, null, function (/*err*/) {
                                    setTimeout(function () {
                                        storage.closeBranchTimeout = 40; //Set it back.
                                        storage.closeBranch('mockProjectId', branchName, function () {});
                                        storage.closeBranch('mockProjectId', branchName, function () {});
                                    }, 300);
                                });

                            }, 200);
                        });
                    }, 120);
                });
            }
        );
    });

});<commit_msg>Run only one addonmanager test.<commit_after>/*jshint node:true, mocha:true*/
/**
 * @author pmeijer / https://github.com/pmeijer
 */

var testFixture = require('../_globals');

describe('AddOnManager', function () {
    'use strict';
    var expect = testFixture.expect,
        AddOnManager = require('../../src/addon/addonmanager'),
        logger = testFixture.logger.fork('AddOnManager');

    describe('starting and stopping monitors using a mock storage', function () {
        var gmeConfig = testFixture.getGmeConfig();

        gmeConfig.addOn.enable = true;
        gmeConfig.addOn.monitorTimeout = 100;

        function StorageMock(manager, done) {
            var self = this;
            this.branchCounter = 0;
            this.deferredCnt = 0;
            this.monitorTimeout = 40;
            this.unMonitorTimeout = 40;

            this.closeBranchTimeout = 5;

            this.openBranch = function (projectId, branchName, updateFn, branchStatusFn, callback) {
                setTimeout(function () {
                    self.branchCounter += 1;
                    callback(null);

                    setTimeout(function () {
                        self.deferredCnt += 1;
                        manager.monitorBranch('dummySession', branchName)
                            .then(function () {
                                self.deferredCnt -= 1;
                                //console.log('monitorBranch');
                            })
                            .catch(done);
                    }, self.monitorTimeout);

                }, 5);
            };

            this.closeBranch = function (projectId, branchName, callback) {
                setTimeout(function () {
                    self.branchCounter -= 1;
                    if (self.branchCounter < 0) {
                        done(new Error('branch counter became negative'));
                    }
                    callback(null);

                    setTimeout(function () {
                        self.deferredCnt += 1;
                        manager.unMonitorBranch('dummySession', branchName)
                            .then(function () {
                                self.deferredCnt -= 1;
                                //console.log('unMonitorBranch');
                            })
                            .catch(done);
                    }, self.unMonitorTimeout);

                }, self.closeBranchTimeout);
            };

        }

        it('should dispatch NO_MONITORS after open branch and closing AFTER the monitor opened the branch',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    branchName = 'test1';
                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    expect(storage.branchCounter).to.equal(0);
                    expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                    expect(manager.branchMonitors).to.deep.equal({});
                    done();
                });

                storage.openBranch('mockProjectId', branchName, null, null, function (/*err*/) {
                    expect(storage.branchCounter).to.equal(1);
                    expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);

                    setTimeout(function () {
                        expect(storage.branchCounter).to.equal(2);
                        expect(manager.branchMonitors[branchName].connectionCnt).to.equal(2);
                        storage.closeBranch('mockProjectId', branchName, function (/*err*/) {
                            expect(storage.branchCounter).to.equal(1);
                        });
                    }, 140);
                });
            }
        );

        it('should dispatch NO_MONITORS after open branch and closing BEFORE the monitor opened the branch',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    branchName = 'test2';
                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    expect(storage.branchCounter).to.equal(0);
                    expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                    expect(manager.branchMonitors).to.deep.equal({});
                    done();
                });

                storage.openBranch('mockProjectId', branchName, null, null, function (/*err*/) {
                    expect(storage.branchCounter).to.equal(1);
                    expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);
                    storage.closeBranch('mockProjectId', branchName, function (/*err*/) {

                    });
                });
            }
        );

        it('should dispatch NO_MONITORS (once) after open branch and closing AFTER the monitor opened the branch' +
            ' and opening branch while monitor is in timeout.',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    branchName = 'test3';
                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    expect(storage.branchCounter).to.equal(0);
                    expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                    expect(manager.branchMonitors).to.deep.equal({});
                    done();
                });

                storage.openBranch('mockProjectId', branchName, null, null, function () {
                    expect(storage.branchCounter).to.equal(1);
                    expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);
                    setTimeout(function () {
                        expect(storage.branchCounter).to.equal(2);
                        expect(manager.branchMonitors[branchName].connectionCnt).to.equal(2);
                        storage.closeBranch('mockProjectId', branchName, function () {
                            expect(storage.branchCounter).to.equal(1);
                            expect(manager.branchMonitors[branchName].connectionCnt).to.equal(2);
                            storage.openBranch('mockProjectId', branchName, null, null, function () {
                                expect(storage.branchCounter).to.equal(2);
                                setTimeout(function () {
                                    expect(manager.branchMonitors[branchName].connectionCnt).to.equal(2);
                                    storage.closeBranch('mockProjectId', branchName, function () {

                                    });
                                }, 120);
                            });
                        });
                    }, 120);
                });
            }
        );

        it('should dispatch NO_MONITORS (twice) after open branch and closing BEFORE the monitor opened the branch' +
            ' and opening branch and closing branch.',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    emptyCnt = 0,
                    branchName = 'test4';

                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    emptyCnt += 1;
                    if (emptyCnt === 2) {
                        expect(storage.branchCounter).to.equal(0);
                        expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                        expect(manager.branchMonitors).to.deep.equal({});
                        done();
                    }
                });

                storage.openBranch('mockProjectId', branchName, null, null, function () {
                    expect(storage.branchCounter).to.equal(1);
                    expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);

                    storage.closeBranch('mockProjectId', branchName, function () {
                        expect(storage.branchCounter).to.equal(0);
                        expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);

                        setTimeout(function () {
                            expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);

                            storage.openBranch('mockProjectId', branchName, null, null, function () {
                                setTimeout(function () {
                                    expect(storage.branchCounter).to.equal(2);
                                    expect(manager.branchMonitors[branchName].connectionCnt).to.equal(2);
                                    storage.closeBranch('mockProjectId', branchName, function () {

                                    });
                                }, 120);
                            });
                        }, 120);
                    });
                });
            }
        );

        it('should dispatch NO_MONITORS (once) after 2 open branches and closing AFTER the monitor opened the branch.',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    branchName = 'test5';

                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    expect(storage.branchCounter).to.equal(0);
                    expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                    expect(manager.branchMonitors).to.deep.equal({});
                    done();
                });

                storage.openBranch('mockProjectId', branchName, null, null, function () {});
                storage.openBranch('mockProjectId', branchName, null, null, function () {
                    expect(storage.branchCounter).to.equal(2);
                    setTimeout(function () {
                        expect(storage.branchCounter).to.equal(3);
                        expect(manager.branchMonitors[branchName].connectionCnt).to.equal(3);
                        storage.closeBranch('mockProjectId', branchName, function () {});
                        storage.closeBranch('mockProjectId', branchName, function () {});
                    }, 120);
                });
            }
        );

        it('should dispatch NO_MONITORS (twice) after 2 open branches and closing AFTER the monitor opened the branch.',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    branchName = 'test6',
                    emptyCnt = 0;

                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    emptyCnt += 1;
                    if (emptyCnt === 2) {
                        expect(storage.branchCounter).to.equal(0);
                        expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                        expect(manager.branchMonitors).to.deep.equal({});
                        done();
                    }
                });

                storage.openBranch('mockProjectId', branchName, null, null, function () {});
                storage.openBranch('mockProjectId', branchName, null, null, function () {
                    expect(storage.branchCounter).to.equal(2);
                    expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);
                    storage.closeBranch('mockProjectId', branchName, function () {});
                    storage.closeBranch('mockProjectId', branchName, function () {});
                });
            }
        );

        it('should enter StopAndStarted and succeed gracefully with one new monitor',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    branchName = 'test7',
                    emptyCnt = 0;

                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    emptyCnt += 1;
                    if (emptyCnt === 2) {
                        expect(storage.branchCounter).to.equal(0);
                        expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                        expect(manager.branchMonitors).to.deep.equal({});
                        done();
                    }
                });

                storage.openBranch('mockProjectId', branchName, null, null, function (/*err*/) {
                    expect(storage.branchCounter).to.equal(1);
                    expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);

                    setTimeout(function () {
                        expect(manager.branchMonitors[branchName].connectionCnt).to.equal(2);
                        // Monitor has connected..

                        storage.closeBranch('mockProjectId', branchName, function (/*err*/) {
                            storage.closeBranchTimeout = 400; //Slow down the branch closing for the monitor.
                            expect(storage.branchCounter).to.equal(1);
                            setTimeout(function () {
                                // Here the timeout should have started and triggered.
                                // But branch still open for monitor..
                                expect(manager.branchMonitors[branchName].connectionCnt).to.equal(1);
                                expect(manager.branchMonitors[branchName].instance.stopRequested).to.equal(true);
                                // At this point we connect a new client.
                                storage.openBranch('mockProjectId', branchName, null, null, function (/*err*/) {
                                    setTimeout(function () {
                                        storage.closeBranchTimeout = 40; //Set it back.
                                        storage.closeBranch('mockProjectId', branchName, function () {});
                                    }, 300);
                                });

                            }, 200);
                        });
                    }, 120);
                });
            }
        );

        it.only('should enter StopAndStarted and succeed gracefully with two new monitors',
            function (done) {
                var manager = new AddOnManager('mockProjectId', logger, gmeConfig),
                    storage = new StorageMock(manager, done),
                    branchName = 'test7',
                    emptyCnt = 0;

                manager.project = {
                    ID_NAME: '_id',
                    loadObject: function () {},
                    insertObject: function () {},
                    loadPaths: function () {}
                };
                manager.storage = storage;

                manager.addEventListener('NO_MONITORS', function () {
                    emptyCnt += 1;
                    if (emptyCnt === 2) {
                        expect(storage.branchCounter).to.equal(0);
                        expect(storage.deferredCnt).to.equal(1); // The monitors own won't have triggered.
                        expect(manager.branchMonitors).to.deep.equal({});
                        done();
                    }
                });

                storage.openBranch('mockProjectId', branchName, null, null, function (/*err*/) {
                    expect(storage.branchCounter).to.equal(1);
                    expect(manager.branchMonitors.hasOwnProperty(branchName)).to.equal(false);

                    setTimeout(function () {
                        expect(manager.branchMonitors[branchName].connectionCnt).to.equal(2);
                        // Monitor has connected..

                        storage.closeBranch('mockProjectId', branchName, function (/*err*/) {
                            storage.closeBranchTimeout = 400; //Slow down the branch closing for the monitor.
                            expect(storage.branchCounter).to.equal(1);
                            setTimeout(function () {
                                // Here the timeout should have started and triggered.
                                // But branch still open for monitor..
                                expect(manager.branchMonitors[branchName].connectionCnt).to.equal(1);
                                expect(manager.branchMonitors[branchName].instance.stopRequested).to.equal(true);
                                // At this point we connect a new client.
                                storage.openBranch('mockProjectId', branchName, null, null, function (/*err*/) {});
                                storage.openBranch('mockProjectId', branchName, null, null, function (/*err*/) {
                                    setTimeout(function () {
                                        storage.closeBranchTimeout = 40; //Set it back.
                                        storage.closeBranch('mockProjectId', branchName, function () {});
                                        storage.closeBranch('mockProjectId', branchName, function () {});
                                    }, 300);
                                });

                            }, 200);
                        });
                    }, 120);
                });
            }
        );
    });

});
<|endoftext|>


<commit_before>/**
 * @file
 */

/**
 * Extract the hit part of the ES result, if it exist
 *
 * @param esRes
 * @param pos
 * @param fld
 * @returns {*}
 */
export function getEsField(esRes, pos, fld) {
  if (esRes && Array.isArray(esRes.hits) && esRes.hits[pos] && esRes.hits[pos]._source && Array.isArray(esRes.hits[pos]._source[fld])) {
    return esRes.hits[pos]._source[fld];
  }
  return [];
}

/**
 * return first occurrence of a given list of fields
 *
 * @param esRes
 * @param pos
 * @param fldList
 * @returns {*}
 */
export function getFirstField(esRes, pos, fldList) {
  let field = '';
  fldList.forEach(function (tag) {
    const fld = getEsField(esRes, pos, tag);
    if (!field && fld[0]) {
      field = fld[0];
    }
  });
  return field;
}

/**
 * Merge default and function given parameters, and translate to ES names
 *
 * @param pars
 * @param defaultParameters
 * @param esParMap
 * @returns {{}}
 */
export function setAndMap(pars, defaultParameters, esParMap) {
  let ret = {};
  Object.keys(defaultParameters).forEach(function (key) {
    ret[esParMap[key]] = pars[key] ? pars[key] : defaultParameters[key];
  });
  return ret;
}

/**
 * sort on ascending distance
 *
 * @param buf
 * @param elements
 * @returns {*|Blob|string|ArrayBuffer}
 */
export function sortDistanceAndSlice(buf, elements) {
  return buf.sort(function (a, b) {
    return (parseInt(a.distance, 10) - parseInt(b.distance, 10));
  }).slice(0, elements);
}

/**
 * sort an array on the index field
 *
 * @param arr
 * @returns {*}
 */
export function indexSort(arr) {
  return arr.sort(function (a, b) {
    if (a.index === b.index) {
      return (a.title > b.title ? 1 : -1);
    }
    return (a.index > b.index ? 1 : -1);
  });
}

/**
 * sort an array on the title field
 *
 * @param arr
 * @returns {*}
 */
export function titleSort(arr) {
  return arr.sort(function (a, b) {
    return (a.title > b.title ? 1 : -1);
  });
}

/**
 * parse a register record and return a consolidated structure
 * To understand where title, notes and like are placed, you have to consult the
 * marc format specifications for dk5
 *
 * @param esRes
 * @param pos
 * @param dk5Tab
 * @returns {*}
 */
export function parseRegisterRecord(esRes, pos, dk5Tab) {
  const ret = {};
  ret.title = '' + getFirstField(esRes, pos, ['630a', '633a', '640a', '600a', '610a', 'a20a']);
  ret.titleDetails = getFirstField(esRes, pos, ['630e', '633e', '640e', '600f', '610e', 'a20b']);
  ret.titleFull = ret.title + (ret.titleDetails ? ' - ' + ret.titleDetails : '');
  ret.index = getFirstField(esRes, pos, ['652m', 'b52m', '652n']);
  console.log('dec', ret.index, '|', dk5Tab[ret.index]);
  ret.decommissioned = ret.index && dk5Tab[ret.index] ? dk5Tab[ret.index].decommissioned : false;
  ret.id = getFirstField(esRes, pos, ['001a']);
  ret.parent = Object.assign({}, dk5Tab[ret.index]);
  const registerWords = getEsField(esRes, pos, 'b52m');
  if (registerWords.length === 0) {
    return ret;
  }

  const registerWordTitle = getEsField(esRes, pos, 'b52y');
  const items = [];
  for (let i = 0; i < registerWords.length; i++) {
    items.push({index: registerWords[i], title: registerWordTitle[i], parent: dk5Tab[registerWords[i]]});
  }
  return Object.assign({}, ret, {items: indexSort(items)});
}

/**
 * Collect systematic notes. Notes are found in field a40
 *
 * @param systRec
 * @param hitPos
 * @param fld
 * @returns {string}
 */
export function createTaggedSystematicNote(systRec, hitPos, fld) {
  let note = getEsField(systRec, hitPos, fld).join('
');
  if (note) {
    note = parseTextAndTagSyst(note, getEsField(systRec, hitPos, fld + 'b'));
  }
  return note;
}

/**
 * Collect register notes. Notes are found in field 651 and b00
 *
 * @param regRecs
 * @param hitPos
 * @param dk5Syst
 * @returns {*|string|String}
 */
export function createTaggedRegisterNote(regRecs, hitPos, dk5Syst) {
  const note = [];
  ['651', 'b00'].forEach((noteTag) => {
    const noteText = getEsField(regRecs, hitPos, noteTag).join('
');
    if (noteText) {
      note.push(parseTextAndTagSyst(noteText, getEsField(regRecs, hitPos, noteTag + 'b'), dk5Syst));
    }
  });
  return note.join('
');
}

/**
 * Parse all register records for notes
 * Notes for the same index, can be found in more than one record
 *
 * @param regRecs
 * @param dk5Syst
 * @returns {{}}
 */
export function parseRegisterForNotes(regRecs, dk5Syst) {
  const notes = {};
  for (let hitPos = 0; hitPos < regRecs.hits.length; hitPos++) {
    const index = getFirstField(regRecs, hitPos, ['652m', '652n', '652d']);
    const note = createTaggedRegisterNote(regRecs, hitPos, dk5Syst);
    if (notes[index]) {
      if (notes[index].indexOf(note) === -1) {
        notes[index] += '
' + note;
      }
    }
    else {
      notes[index] = note;

    }
  }
  return notes;
}

/**
 * Parse all register records for general notes
 *
 * @param regRecs
 * @returns {{}}
 */
export function parseRegisterForGeneralNotes(regRecs) {
  const notes = {};
  for (let hitPos = 0; hitPos < regRecs.hits.length; hitPos++) {
    const noteText = getEsField(regRecs, hitPos, 'b00').join('
');
    if (noteText) {
      const index = getFirstField(regRecs, hitPos, ['652m', '652n', '652d']);
      notes[index] = noteText;
    }
  }
  return notes;
}

/**
 * Parse register records and extract unique words
 *
 * @param regRecs
 * @param wordFields
 * @returns {Array}
 */
export function parseRegisterForUniqueWords(regRecs, wordFields) {
  let uniqueWords = {};
  for (let hitPos = 0; hitPos < regRecs.hits.length; hitPos++) {
    wordFields.forEach((fld) => {
      const wordArr = getEsField(regRecs, hitPos, fld);
      for (let i = 0; i < wordArr.length; i++) {
        wordArr[i].split(/[\s,]+/).forEach((word) => {
          word = word.replace(/^[:\-\.#]+|[:\-\.#]+$|[\"()]+/g, '');
          let num = word.replace(/[\.:-]/g, '');
          if (num.length > 2 && parseInt(num, 10) !== num) {
            uniqueWords[word.toLowerCase()] = true;
          }
        });
      }
    });
  }
  return Object.keys(uniqueWords);
}

/**
 * Parse the note and put systematics in tags
 *
 * @param note
 * @param noteSyst
 * @param dk5Syst
 * @returns {*}
 */
function parseTextAndTagSyst(note, noteSyst, dk5Syst = false) {
  let ret = note;
  let notePos = 0;
  for (let i = 0; i < noteSyst.length; i++) {
    let syst = noteSyst[i];
    const p = ret.indexOf(syst, notePos);
    if (p > -1) {
      const replace = (!dk5Syst || dk5Syst[syst]) ? '<dk>' + syst + '</dk>' : syst;
      ret = ret.substr(0, p) + replace + ret.substr(p + syst.length);
      notePos = p + replace.length;
    }
  }
  return ret;
}
<commit_msg>#215: remove console.log<commit_after>/**
 * @file
 */

/**
 * Extract the hit part of the ES result, if it exist
 *
 * @param esRes
 * @param pos
 * @param fld
 * @returns {*}
 */
export function getEsField(esRes, pos, fld) {
  if (esRes && Array.isArray(esRes.hits) && esRes.hits[pos] && esRes.hits[pos]._source && Array.isArray(esRes.hits[pos]._source[fld])) {
    return esRes.hits[pos]._source[fld];
  }
  return [];
}

/**
 * return first occurrence of a given list of fields
 *
 * @param esRes
 * @param pos
 * @param fldList
 * @returns {*}
 */
export function getFirstField(esRes, pos, fldList) {
  let field = '';
  fldList.forEach(function (tag) {
    const fld = getEsField(esRes, pos, tag);
    if (!field && fld[0]) {
      field = fld[0];
    }
  });
  return field;
}

/**
 * Merge default and function given parameters, and translate to ES names
 *
 * @param pars
 * @param defaultParameters
 * @param esParMap
 * @returns {{}}
 */
export function setAndMap(pars, defaultParameters, esParMap) {
  let ret = {};
  Object.keys(defaultParameters).forEach(function (key) {
    ret[esParMap[key]] = pars[key] ? pars[key] : defaultParameters[key];
  });
  return ret;
}

/**
 * sort on ascending distance
 *
 * @param buf
 * @param elements
 * @returns {*|Blob|string|ArrayBuffer}
 */
export function sortDistanceAndSlice(buf, elements) {
  return buf.sort(function (a, b) {
    return (parseInt(a.distance, 10) - parseInt(b.distance, 10));
  }).slice(0, elements);
}

/**
 * sort an array on the index field
 *
 * @param arr
 * @returns {*}
 */
export function indexSort(arr) {
  return arr.sort(function (a, b) {
    if (a.index === b.index) {
      return (a.title > b.title ? 1 : -1);
    }
    return (a.index > b.index ? 1 : -1);
  });
}

/**
 * sort an array on the title field
 *
 * @param arr
 * @returns {*}
 */
export function titleSort(arr) {
  return arr.sort(function (a, b) {
    return (a.title > b.title ? 1 : -1);
  });
}

/**
 * parse a register record and return a consolidated structure
 * To understand where title, notes and like are placed, you have to consult the
 * marc format specifications for dk5
 *
 * @param esRes
 * @param pos
 * @param dk5Tab
 * @returns {*}
 */
export function parseRegisterRecord(esRes, pos, dk5Tab) {
  const ret = {};
  ret.title = '' + getFirstField(esRes, pos, ['630a', '633a', '640a', '600a', '610a', 'a20a']);
  ret.titleDetails = getFirstField(esRes, pos, ['630e', '633e', '640e', '600f', '610e', 'a20b']);
  ret.titleFull = ret.title + (ret.titleDetails ? ' - ' + ret.titleDetails : '');
  ret.index = getFirstField(esRes, pos, ['652m', 'b52m', '652n']);
  ret.decommissioned = ret.index && dk5Tab[ret.index] ? dk5Tab[ret.index].decommissioned : false;
  ret.id = getFirstField(esRes, pos, ['001a']);
  ret.parent = Object.assign({}, dk5Tab[ret.index]);
  const registerWords = getEsField(esRes, pos, 'b52m');
  if (registerWords.length === 0) {
    return ret;
  }

  const registerWordTitle = getEsField(esRes, pos, 'b52y');
  const items = [];
  for (let i = 0; i < registerWords.length; i++) {
    items.push({index: registerWords[i], title: registerWordTitle[i], parent: dk5Tab[registerWords[i]]});
  }
  return Object.assign({}, ret, {items: indexSort(items)});
}

/**
 * Collect systematic notes. Notes are found in field a40
 *
 * @param systRec
 * @param hitPos
 * @param fld
 * @returns {string}
 */
export function createTaggedSystematicNote(systRec, hitPos, fld) {
  let note = getEsField(systRec, hitPos, fld).join('
');
  if (note) {
    note = parseTextAndTagSyst(note, getEsField(systRec, hitPos, fld + 'b'));
  }
  return note;
}

/**
 * Collect register notes. Notes are found in field 651 and b00
 *
 * @param regRecs
 * @param hitPos
 * @param dk5Syst
 * @returns {*|string|String}
 */
export function createTaggedRegisterNote(regRecs, hitPos, dk5Syst) {
  const note = [];
  ['651', 'b00'].forEach((noteTag) => {
    const noteText = getEsField(regRecs, hitPos, noteTag).join('
');
    if (noteText) {
      note.push(parseTextAndTagSyst(noteText, getEsField(regRecs, hitPos, noteTag + 'b'), dk5Syst));
    }
  });
  return note.join('
');
}

/**
 * Parse all register records for notes
 * Notes for the same index, can be found in more than one record
 *
 * @param regRecs
 * @param dk5Syst
 * @returns {{}}
 */
export function parseRegisterForNotes(regRecs, dk5Syst) {
  const notes = {};
  for (let hitPos = 0; hitPos < regRecs.hits.length; hitPos++) {
    const index = getFirstField(regRecs, hitPos, ['652m', '652n', '652d']);
    const note = createTaggedRegisterNote(regRecs, hitPos, dk5Syst);
    if (notes[index]) {
      if (notes[index].indexOf(note) === -1) {
        notes[index] += '
' + note;
      }
    }
    else {
      notes[index] = note;

    }
  }
  return notes;
}

/**
 * Parse all register records for general notes
 *
 * @param regRecs
 * @returns {{}}
 */
export function parseRegisterForGeneralNotes(regRecs) {
  const notes = {};
  for (let hitPos = 0; hitPos < regRecs.hits.length; hitPos++) {
    const noteText = getEsField(regRecs, hitPos, 'b00').join('
');
    if (noteText) {
      const index = getFirstField(regRecs, hitPos, ['652m', '652n', '652d']);
      notes[index] = noteText;
    }
  }
  return notes;
}

/**
 * Parse register records and extract unique words
 *
 * @param regRecs
 * @param wordFields
 * @returns {Array}
 */
export function parseRegisterForUniqueWords(regRecs, wordFields) {
  let uniqueWords = {};
  for (let hitPos = 0; hitPos < regRecs.hits.length; hitPos++) {
    wordFields.forEach((fld) => {
      const wordArr = getEsField(regRecs, hitPos, fld);
      for (let i = 0; i < wordArr.length; i++) {
        wordArr[i].split(/[\s,]+/).forEach((word) => {
          word = word.replace(/^[:\-\.#]+|[:\-\.#]+$|[\"()]+/g, '');
          let num = word.replace(/[\.:-]/g, '');
          if (num.length > 2 && parseInt(num, 10) !== num) {
            uniqueWords[word.toLowerCase()] = true;
          }
        });
      }
    });
  }
  return Object.keys(uniqueWords);
}

/**
 * Parse the note and put systematics in tags
 *
 * @param note
 * @param noteSyst
 * @param dk5Syst
 * @returns {*}
 */
function parseTextAndTagSyst(note, noteSyst, dk5Syst = false) {
  let ret = note;
  let notePos = 0;
  for (let i = 0; i < noteSyst.length; i++) {
    let syst = noteSyst[i];
    const p = ret.indexOf(syst, notePos);
    if (p > -1) {
      const replace = (!dk5Syst || dk5Syst[syst]) ? '<dk>' + syst + '</dk>' : syst;
      ret = ret.substr(0, p) + replace + ret.substr(p + syst.length);
      notePos = p + replace.length;
    }
  }
  return ret;
}
<|endoftext|>