<commit_before>angular.module('ui.bootstrap.dateparser', [])

.service('dateParser', ['$locale', 'orderByFilter', function($locale, orderByFilter) {

  this.parsers = {};

  var formatCodeToRegex = {
    'yyyy': {
      regex: '\\d{4}',
      apply: function(value) { this.year = +value; }
    },
    'yy': {
      regex: '\\d{2}',
      apply: function(value) { this.year = +value + 2000; }
    },
    'y': {
      regex: '\\d{1,4}',
      apply: function(value) { this.year = +value; }
    },
    'MMMM': {
      regex: $locale.DATETIME_FORMATS.MONTH.join('|'),
      apply: function(value) { this.month = $locale.DATETIME_FORMATS.MONTH.indexOf(value); }
    },
    'MMM': {
      regex: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'),
      apply: function(value) { this.month = $locale.DATETIME_FORMATS.SHORTMONTH.indexOf(value); }
    },
    'MM': {
      regex: '0[1-9]|1[0-2]',
      apply: function(value) { this.month = value - 1; }
    },
    'M': {
      regex: '[1-9]|1[0-2]',
      apply: function(value) { this.month = value - 1; }
    },
    'dd': {
      regex: '[0-2][0-9]{1}|3[0-1]{1}',
      apply: function(value) { this.date = +value; }
    },
    'd': {
      regex: '[1-2]?[0-9]{1}|3[0-1]{1}',
      apply: function(value) { this.date = +value; }
    },
    'EEEE': {
      regex: $locale.DATETIME_FORMATS.DAY.join('|')
    },
    'EEE': {
      regex: $locale.DATETIME_FORMATS.SHORTDAY.join('|')
    }
  };

  function createParser(format) {
    var map = [], regex = format.split('');

    angular.forEach(formatCodeToRegex, function(data, code) {
      var index = format.indexOf(code);

      if (index > -1) {
        format = format.split('');

        regex[index] = '(' + data.regex + ')';
        format[index] = '$'; // Custom symbol to define consumed part of format
        for (var i = index + 1, n = index + code.length; i < n; i++) {
          regex[i] = '';
          format[i] = '$';
        }
        format = format.join('');

        map.push({ index: index, apply: data.apply });
      }
    });

    return {
      regex: new RegExp('^' + regex.join('') + '$'),
      map: orderByFilter(map, 'index')
    };
  }

  this.parse = function(input, format) {
    if ( !angular.isString(input) || !format ) {
      return input;
    }

    format = $locale.DATETIME_FORMATS[format] || format;

    if ( !this.parsers[format] ) {
      this.parsers[format] = createParser(format);
    }

    var parser = this.parsers[format],
        regex = parser.regex,
        map = parser.map,
        results = input.match(regex);

    if ( results && results.length ) {
      var fields = { year: 1900, month: 0, date: 1, hours: 0 }, dt;

      for( var i = 1, n = results.length; i < n; i++ ) {
        var mapper = map[i-1];
        if ( mapper.apply ) {
          mapper.apply.call(fields, results[i]);
        }
      }

      if ( isValid(fields.year, fields.month, fields.date) ) {
        dt = new Date( fields.year, fields.month, fields.date, fields.hours);
      }

      return dt;
    }
  };

  // Check if date is valid for specific month (and year for February).
  // Month: 0 = Jan, 1 = Feb, etc
  function isValid(year, month, date) {
    if ( month === 1 && date > 28) {
        return date === 29 && ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0);
    }

    if ( month === 3 || month === 5 || month === 8 || month === 10) {
        return date < 31;
    }

    return true;
  }
  }])

  .service('jDateParser', ['$locale', 'orderByFilter', function ($locale, orderByFilter) {

    this.parsers = {};

    var formatCodeToRegex = {
      'yyyy': {
        regex: '\\d{4}',
        apply: function (value) {
          this.year = +value;
        }
      },
      'yy': {
        regex: '\\d{2}',
        apply: function (value) {
          this.year = +value + 2000;
        }
      },
      'y': {
        regex: '\\d{1,4}',
        apply: function (value) {
          this.year = +value;
        }
      },
      'MMMM': {
        regex: $locale.DATETIME_FORMATS.MONTH.join('|'),
        apply: function (value) {
          this.month = $locale.DATETIME_FORMATS.MONTH.indexOf(value);
        }
      },
      'MMM': {
        regex: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'),
        apply: function (value) {
          this.month = $locale.DATETIME_FORMATS.SHORTMONTH.indexOf(value);
        }
      },
      'MM': {
        regex: '0[1-9]|1[0-2]',
        apply: function (value) {
          this.month = value - 1;
        }
      },
      'M': {
        regex: '[1-9]|1[0-2]',
        apply: function (value) {
          this.month = value - 1;
        }
      },
      'dd': {
        regex: '[0-2][0-9]{1}|3[0-1]{1}',
        apply: function (value) {
          this.date = +value;
        }
      },
      'd': {
        regex: '[1-2]?[0-9]{1}|3[0-1]{1}',
        apply: function (value) {
          this.date = +value;
        }
      },
      'EEEE': {
        regex: $locale.DATETIME_FORMATS.DAY.join('|')
      },
      'EEE': {
        regex: $locale.DATETIME_FORMATS.SHORTDAY.join('|')
      }
    };

    function createParser(format) {
      var map = [], regex = format.split('');

      angular.forEach(formatCodeToRegex, function (data, code) {
        var index = format.indexOf(code);

        if (index > -1) {
          format = format.split('');

          regex[index] = '(' + data.regex + ')';
          format[index] = '$'; // Custom symbol to define consumed part of format
          for (var i = index + 1, n = index + code.length; i < n; i++) {
            regex[i] = '';
            format[i] = '$';
          }
          format = format.join('');

          map.push({index: index, apply: data.apply});
        }
      });

      return {
        regex: new RegExp('^' + regex.join('') + '$'),
        map: orderByFilter(map, 'index')
      };
    }

    function getJFormat(format) {
      var jformat = '';
      switch (format) {
        case 'yyyy-MM-dd':
          jformat = 'jYYYY-jMM-jDD';
          break;
        case 'dd-MMMM-yyyy':
          jformat = 'jDD-jMMMM-jYYYY';
          break;
        case 'yyyy/MM/dd':
          jformat = 'jYYYY/jMM/jDD';
          break;
        case 'dd.MM.yyyy':
          jformat = 'jDD.jMM.jYYYY';
          break;
        case 'shortDate':
        case 'YY/M/D':
          jformat = 'jYY/jM/jD';
          break;
        case 'dd':
          jformat = 'jDD';
          break;
        case 'MMMM yyyy':
          jformat = 'jMMMM jYYYY';
          break;
        case 'MMMM':
          jformat = 'jMMMM';
          break;
        case 'yyyy':
          jformat = 'jYYYY';
          break;
        case 'yy':
          jformat = 'jYY';
          break;
        case 'mm':
          jformat = 'jMM';
        case 'EEE':
        case 'EEEE':
          jformat = 'E';
          break;
        default :
          jformat = format;
      }
      return jformat;
    }

    this.parse = function (input, format) {
      console.log('parse:');
      input = moment(input, getJFormat(format)).format(format.toUpperCase()); // 2013-8-25 16:40:00
      if (!angular.isString(input) || !format) {
        return input;
      }

      format = $locale.DATETIME_FORMATS[format] || format;

      if (!this.parsers[format]) {
        this.parsers[format] = createParser(format);
      }
      console.log(input);
      console.log(format);
      var parser = this.parsers[format],
        regex = parser.regex,
        map = parser.map,
        results = input.match(regex);
      console.log(parser);
      console.log(regex);
      console.log(map);
      console.log(results);

      if (results && results.length) {
        var fields = {year: 1900, month: 0, date: 1, hours: 0}, dt;

        for (var i = 1, n = results.length; i < n; i++) {
          var mapper = map[i - 1];
          if (mapper.apply) {
            mapper.apply.call(fields, results[i]);
          }
        }
        //  convert input Jalali date to gregorian
        //var tdt = moment(fields.year+'/'+fields.month+'/'+fields.date, 'jYYYY/jM/jD').format('YYYY-M-D') // 2013-8-25
        //var arr = tdt.split('-');
        //angular.forEach(arr,function(v,i){
        //  arr[i] = parseInt(v);
        //});
        if (isValid(fields.year, fields.month, fields.date)) {
          dt = new Date(fields.year, fields.month, fields.date, fields.hours);
        }

        return dt;
      }
    };

    // Check if date is valid for specific month (and year for February).
    // Month: 0 = Jan, 1 = Feb, etc
    function isValid(year, month, date) {
      if (month === 1 && date > 28) {
        return date === 29 && ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0);
      }

      if (month === 3 || month === 5 || month === 8 || month === 10) {
        return date < 31;
      }

      return true;
    }
  }]);

<commit_msg>fix(dateparser): modify typing date manually and clear logs<commit_after>angular.module('ui.bootstrap.dateparser', [])

.service('dateParser', ['$locale', 'orderByFilter', function($locale, orderByFilter) {

  this.parsers = {};

  var formatCodeToRegex = {
    'yyyy': {
      regex: '\\d{4}',
      apply: function(value) { this.year = +value; }
    },
    'yy': {
      regex: '\\d{2}',
      apply: function(value) { this.year = +value + 2000; }
    },
    'y': {
      regex: '\\d{1,4}',
      apply: function(value) { this.year = +value; }
    },
    'MMMM': {
      regex: $locale.DATETIME_FORMATS.MONTH.join('|'),
      apply: function(value) { this.month = $locale.DATETIME_FORMATS.MONTH.indexOf(value); }
    },
    'MMM': {
      regex: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'),
      apply: function(value) { this.month = $locale.DATETIME_FORMATS.SHORTMONTH.indexOf(value); }
    },
    'MM': {
      regex: '0[1-9]|1[0-2]',
      apply: function(value) { this.month = value - 1; }
    },
    'M': {
      regex: '[1-9]|1[0-2]',
      apply: function(value) { this.month = value - 1; }
    },
    'dd': {
      regex: '[0-2][0-9]{1}|3[0-1]{1}',
      apply: function(value) { this.date = +value; }
    },
    'd': {
      regex: '[1-2]?[0-9]{1}|3[0-1]{1}',
      apply: function(value) { this.date = +value; }
    },
    'EEEE': {
      regex: $locale.DATETIME_FORMATS.DAY.join('|')
    },
    'EEE': {
      regex: $locale.DATETIME_FORMATS.SHORTDAY.join('|')
    }
  };

  function createParser(format) {
    var map = [], regex = format.split('');

    angular.forEach(formatCodeToRegex, function(data, code) {
      var index = format.indexOf(code);

      if (index > -1) {
        format = format.split('');

        regex[index] = '(' + data.regex + ')';
        format[index] = '$'; // Custom symbol to define consumed part of format
        for (var i = index + 1, n = index + code.length; i < n; i++) {
          regex[i] = '';
          format[i] = '$';
        }
        format = format.join('');

        map.push({ index: index, apply: data.apply });
      }
    });

    return {
      regex: new RegExp('^' + regex.join('') + '$'),
      map: orderByFilter(map, 'index')
    };
  }

  this.parse = function(input, format) {
    if ( !angular.isString(input) || !format ) {
      return input;
    }

    format = $locale.DATETIME_FORMATS[format] || format;

    if ( !this.parsers[format] ) {
      this.parsers[format] = createParser(format);
    }

    var parser = this.parsers[format],
        regex = parser.regex,
        map = parser.map,
        results = input.match(regex);

    if ( results && results.length ) {
      var fields = { year: 1900, month: 0, date: 1, hours: 0 }, dt;

      for( var i = 1, n = results.length; i < n; i++ ) {
        var mapper = map[i-1];
        if ( mapper.apply ) {
          mapper.apply.call(fields, results[i]);
        }
      }

      if ( isValid(fields.year, fields.month, fields.date) ) {
        dt = new Date( fields.year, fields.month, fields.date, fields.hours);
      }

      return dt;
    }
  };

  // Check if date is valid for specific month (and year for February).
  // Month: 0 = Jan, 1 = Feb, etc
  function isValid(year, month, date) {
    if ( month === 1 && date > 28) {
        return date === 29 && ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0);
    }

    if ( month === 3 || month === 5 || month === 8 || month === 10) {
        return date < 31;
    }

    return true;
  }
  }])

  .service('jDateParser', ['$locale', 'orderByFilter', function ($locale, orderByFilter) {

    this.parsers = {};

    var formatCodeToRegex = {
      'yyyy': {
        regex: '\\d{4}',
        apply: function (value) {
          this.year = +value;
        }
      },
      'yy': {
        regex: '\\d{2}',
        apply: function (value) {
          this.year = +value + 2000;
        }
      },
      'y': {
        regex: '\\d{1,4}',
        apply: function (value) {
          this.year = +value;
        }
      },
      'MMMM': {
        regex: $locale.DATETIME_FORMATS.MONTH.join('|'),
        apply: function (value) {
          this.month = $locale.DATETIME_FORMATS.MONTH.indexOf(value);
        }
      },
      'MMM': {
        regex: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'),
        apply: function (value) {
          this.month = $locale.DATETIME_FORMATS.SHORTMONTH.indexOf(value);
        }
      },
      'MM': {
        regex: '0[1-9]|1[0-2]',
        apply: function (value) {
          this.month = value - 1;
        }
      },
      'M': {
        regex: '[1-9]|1[0-2]',
        apply: function (value) {
          this.month = value - 1;
        }
      },
      'dd': {
        regex: '[0-2][0-9]{1}|3[0-1]{1}',
        apply: function (value) {
          this.date = +value;
        }
      },
      'd': {
        regex: '[1-2]?[0-9]{1}|3[0-1]{1}',
        apply: function (value) {
          this.date = +value;
        }
      },
      'EEEE': {
        regex: $locale.DATETIME_FORMATS.DAY.join('|')
      },
      'EEE': {
        regex: $locale.DATETIME_FORMATS.SHORTDAY.join('|')
      }
    };

    function createParser(format) {
      var map = [], regex = format.split('');

      angular.forEach(formatCodeToRegex, function (data, code) {
        var index = format.indexOf(code);

        if (index > -1) {
          format = format.split('');

          regex[index] = '(' + data.regex + ')';
          format[index] = '$'; // Custom symbol to define consumed part of format
          for (var i = index + 1, n = index + code.length; i < n; i++) {
            regex[i] = '';
            format[i] = '$';
          }
          format = format.join('');

          map.push({index: index, apply: data.apply});
        }
      });

      return {
        regex: new RegExp('^' + regex.join('') + '$'),
        map: orderByFilter(map, 'index')
      };
    }

    function getJFormat(format) {
      var jformat = '';
      switch (format) {
        case 'yyyy-MM-dd':
          jformat = 'jYYYY-jMM-jDD';
          break;
        case 'dd-MMMM-yyyy':
          jformat = 'jDD-jMMMM-jYYYY';
          break;
        case 'yyyy/MM/dd':
          jformat = 'jYYYY/jMM/jDD';
          break;
        case 'dd.MM.yyyy':
          jformat = 'jDD.jMM.jYYYY';
          break;
        case 'shortDate':
        case 'YY/M/D':
          jformat = 'jYY/jM/jD';
          break;
        case 'dd':
          jformat = 'jDD';
          break;
        case 'MMMM yyyy':
          jformat = 'jMMMM jYYYY';
          break;
        case 'MMMM':
          jformat = 'jMMMM';
          break;
        case 'yyyy':
          jformat = 'jYYYY';
          break;
        case 'yy':
          jformat = 'jYY';
          break;
        case 'mm':
          jformat = 'jMM';
        case 'EEE':
        case 'EEEE':
          jformat = 'E';
          break;
        default :
          jformat = format;
      }
      return jformat;
    }

    this.parse = function (input, format) {
      console.log('parse:');
      input = moment(input, getJFormat(format)).format(format.toUpperCase()); // Change Jalali date to Gregorian
      if (!angular.isString(input) || !format) {
        return input;
      }

      format = $locale.DATETIME_FORMATS[format] || format;

      if (!this.parsers[format]) {
        this.parsers[format] = createParser(format);
      }

      var parser = this.parsers[format],
        regex = parser.regex,
        map = parser.map,
        results = input.match(regex);

      if (results && results.length) {
        var fields = {year: 1900, month: 0, date: 1, hours: 0}, dt;

        for (var i = 1, n = results.length; i < n; i++) {
          var mapper = map[i - 1];
          if (mapper.apply) {
            mapper.apply.call(fields, results[i]);
          }
        }

        if (isValid(fields.year, fields.month, fields.date)) {
          dt = new Date(fields.year, fields.month, fields.date, fields.hours);
        }

        return dt;
      }
    };

    // Check if date is valid for specific month (and year for February).
    // Month: 0 = Jan, 1 = Feb, etc
    function isValid(year, month, date) {
      if (month === 1 && date > 28) {
        return date === 29 && ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0);
      }

      if (month === 3 || month === 5 || month === 8 || month === 10) {
        return date < 31;
      }

      return true;
    }
  }]);

<|endoftext|>


<commit_before>'use strict';
const Trait = require('traits.js');

const globalStates = new Map();

const getState = (key) => {
    return globalStates.get(key);
}

const setState = (key, value) => {
    globalStates.set(key, value);
}

const basePrototype = () => {
    return {};
}

const targets = new WeakMap();

// I dont know if I should use let or const for this.. I'll see implications
// later!!!
const TBase = Trait({ filter: Trait.required });

const TAllow = Trait.compose(TBase, Trait({
    filter: function (tar, prop, rec, args) {
        return this.allowedProperties.indexOf(prop) !== -1
    }
}));

const TParamAt = Trait.compose(TBase, Trait({

    idxParam: Trait.required,
    otherParam: Trait.required,
    operatorFn: Trait.required,

    filter: function (tar, prop, rec, args, opType) {
        //Policy NOT! applicable for property reads!!!
        if (opType === 'readProperty') {
            return true;
        }
        /**
         * document.createElement(stringOf(fakeDiv))
         * apply(p,t,args){
         *  if(policy.filter(...)) should change args to the desired type-value in the policy and use it subsequently
         *  return p.apply(t,args)
         * }
         */
        let newVal = this.idxParam(args);
        return this.operatorFn(newVal, this.otherParam);
    }
}));

/**
 * This function is used to prevent abusing toString and valueOf (we should look at other functions like that)
 * example of usage: ParamAt(equals, getVType(0,String), 'iframe')
 * Be sure that the type parameter returns a primitive object (string, number,...)
 */

const getVType = (idx, type) => {
    return (array) => {
        let val = type(array[idx]);
        array[idx] = val;
        return val;
    }
}

const ParamAt = (fn, idx, other) => {
    var paramPrototype = basePrototype();

    paramPrototype.operatorFn = fn;
    paramPrototype.idxParam = idx;
    paramPrototype.otherParam = other;

    return Trait.create(paramPrototype, TParamAt);
}

const TStateOverParams = Trait.compose(TBase, Trait({

    stateKey: Trait.required,
    operatorFn: Trait.required,
    otherParam: Trait.required,

    filter: function () { //TODO check the parameters...
        var obj = getState(this.stateKey);
        var res = this.operatorFn(obj, this.otherParam);
        return res;
    }
}));

const StateFnParam = (fn, key, param) => {

    var stateParamPrototype = basePrototype()

    stateParamPrototype.stateKey = key;
    stateParamPrototype.operatorFn = fn;
    stateParamPrototype.otherParam = param;

    return Trait.create(stateParamPrototype, TStateOverParams);
}

const And = function (...policies) {
    return Trait.create(basePrototype(), Trait.compose(TBase, Trait({
        filter: function (tar, prop, rec, args) {
            for (var policy of policies) {
                if (!policy.filter(tar, prop, rec, args)) {
                    return false;
                }
            }
            return true;
        }
    })))
}

const Not = function (p1) {

    return Trait.create(basePrototype(), Trait.compose(TBase, Trait({
        filter: function (tar, prop, rec, args) {
            return !p1.filter(tar, prop, rec, args);
        }
    })));
}

const Or = function (...policies) {
    return Trait.create(basePrototype(), Trait.compose(TBase, Trait({
        filter: function (tar, prop, rec, args) {
            // se puede mejorar empleando los operadores de JS
            for (var policy of policies) {
                if (policy.filter(tar, prop, rec, args)) {
                    return true;
                }
            }
            return false;
        }
    })))
}

const Allow = function (properties) {
    var proto = basePrototype();
    proto.allowedProperties = properties;
    var allowedPropPolicy = Trait.create(proto, TAllow);
    return allowedPropPolicy;
}

//Combined Policies

const Deny = function (properties) {
    return Not(Allow(properties))
}

const ParamInList = function (idx, list) {
    return ParamAt((y, xs) => {
        xs.indexOf(y) !== -1
    }, idx, list);
}

const findPropertyOwner = function (obj, prop) {
    do {
        if (obj.hasOwnProperty(prop)) {
            return obj;
        }
    } while (obj = Object.getPrototypeOf(obj));
}

const isBuiltin = function (obj) {
    if (global['window']) {
        return ((obj == navigator) || (obj == window) || (obj == document) || (obj == location) && obj) //continue!!
    }
    return false;
}

const installPolicy = (policy) => {

    let notify = (listeners, target, method, receiver, arglist) => {
        if (listeners) {
            for (let listener of listeners) {
                listener.notify(target, method, receiver, arglist)
            }
        }
    }

    return {
        on: function (target) {
            // !!!!!!!!!!!   iterar una sola vez cuando funcione las polizas en la
            // properties !!!!!!!!!!!!!!!...
            let methods = [];
            let properties = [];

            if (isBuiltin(target)) {
                for (let key in target) {
                    let data = target[key];
                    if (data instanceof Function) {
                        methods.push(key);
                    } else if (data) {
                        properties.push(key);
                    }
                }
                //still work todo here
                /* for (let x of properties) {
                    let owner = findPropertyOwner(target, x);
                    if (owner) {
                        var pd = Reflect.getOwnPropertyDescriptor(owner, x);
                        if (pd.configurable && pd.set && !pd.value) {
                            var m = Reflect.defineProperty(target, x, {
                                get: () => {
                                    return target.x;
                                },
                                set: (value) => {
                                    target.x = value
                                }
                            })
                        }
                    }
                }*/

                //proxy on methods
                for (let method of methods) {
                    let fnProxy = new Proxy(target[method], {
                        apply: function (targetFn, thisArg, arglist) {
                            //enforcing
                            if (policy['whenRead']) {
                                for (let pol of policy['whenRead']) {
                                    if (!pol.filter(target, method, undefined, arglist, 'call')) {
                                        throw new Error('[' + method + '] Not allowed!');
                                    }
                                }
                            }
                            //updating listeners
                            notify(policy['readListeners'], target, method, undefined, arglist);
                            return targetFn.apply(thisArg, arglist);
                        }
                    });

                    fnProxy.toString = Function
                        .prototype
                        .toString
                        .bind(target[method]) //Proxies invariants flaws!!!!
                    target[method] = fnProxy;
                }

                return target;

            } else {
                // console.log('no es built in!!'); install the policy in not builtin objects.
                return new Proxy(target, {
                    get: function (tar, property, receiver) {
                        if (tar[property] instanceof Function) {
                            return function (...args) {
                                if (policy['whenRead']) {
                                    for (let pol of policy['whenRead']) {
                                        if (!pol.filter(tar, property, receiver, args, 'call')) {
                                            throw new Error('Read of [' + property + '] is not allowed!');
                                        }
                                    }
                                }
                                notify(policy['readListeners'], tar, property, undefined, args);
                                return tar[property](...args)
                            }
                        } else {

                            if (policy['whenRead']) {
                                for (let pol of policy['whenRead']) {
                                    if (!pol.filter(tar, property, receiver, 'propertyRead')) {
                                        throw new Error('Read of [' + property + '] is not allowed!');
                                    }
                                }
                            }
                            notify(policy['readListeners'], tar, property, undefined, undefined);
                            return Reflect.get(tar, property, receiver);
                        }
                    },
                    set: function (target, property, value, receiver) {
                        if (policy['whenWrite']) {
                            for (let pol of policy['whenWrite']) {
                                if (!pol.filter(target, property, receiver, value, 'call')) {
                                    throw new Error('Write to [' + property + '] is not allowed!');
                                }
                            }
                        }
                        notify(policy['writeListeners'], target, property, undefined, value);
                        return Reflect.set(target, property, value, receiver);
                    }
                });
            }
        },
        onAll: function (targets) {
            for (let item of targets) {
                console.log('target: ' + item);
                this.on(item);
            }
        }
    }
}

var installPolicyCons = function (policy, targetFn) {
    if (targetFn instanceof Function) {
        var proxy = new Proxy(targetFn, {
            construct: function (target, params, newTarget) {
                let image = Reflect.construct(target, params, newTarget);
                image = installPolicy(policy).on(image);
                return image;
            }
        });
        return proxy;
    } else {
        throw new Error('Target must be a contructor!');
    }
}

/**
 * This function is intended to be used for external enforcement mechanisms. The idea is that
 * the provided mechanism call it with the runtime information and guardia should take care of
 * determining the permissions.
 *
 * @param {Object | Function} tar
 * @param {String} prop
 * @param {Object} rec
 * @param {*} args
 * @param {String} hook
 */

const enforce = (tar, prop, rec, args, hook) => {
    if (targets.has(tar)) { // if we already have registered a secured object
        var pols = Array.from(targets.get(tar))
        for (var pol of pols) {
            for (var rpol of pol[hook]) {
                if (!rpol.filter(tar, prop, rec, args))
                    return false;
            }
        }
    }
    return true;
}

const install = (pol, tar) => {
    if (targets.has(tar)) {
        var x = targets.get(tar)
        x.add(pol);
        targets.set(tar, x);
    } else {
        var t = new Set()
        t.add(pol)
        targets.set(tar, t);
    }
}

/**
 * for installing policies on functions
 * pd should { listeners : [] , execPol: []}
 */
const installOnFunction = (pd, fn) => {
    if (tgt instanceof Function) {
        let fnProxy = new Proxy(fn, {
            apply: function (target, thisArg, argumentsList) {
                if (pd.enforce(target, thisArg, argumentsList)) {
                    throw new Error('Not Allowed');
                }
                return Reflect.apply(target, thisArg, argumentsList);
            }
        });
        return fnProxy;
    }
    throw new Error('Not a function');
}

exports.installPolicy = installPolicy;
exports.installPolicyCons = installPolicyCons;
exports.Allow = Allow;
exports.Deny = Deny;
exports.And = And;
exports.Or = Or;
exports.Not = Not;
exports.ParamInList = ParamInList;
exports.ParamAt = ParamAt;
exports.StateFnParam = StateFnParam;
exports.setState = setState;
exports.getState = getState;
exports.getVType = getVType;

//this needs to be tested yet
exports.enforce = enforce;
exports.installOn = install;
<commit_msg>added geolocation<commit_after>'use strict';
const Trait = require('traits.js');

const globalStates = new Map();

const getState = (key) => {
    return globalStates.get(key);
}

const setState = (key, value) => {
    globalStates.set(key, value);
}

const basePrototype = () => {
    return {};
}

const targets = new WeakMap();

// I dont know if I should use let or const for this.. I'll see implications
// later!!!
const TBase = Trait({ filter: Trait.required });

const TAllow = Trait.compose(TBase, Trait({
    filter: function (tar, prop, rec, args) {
        return this.allowedProperties.indexOf(prop) !== -1
    }
}));

const TParamAt = Trait.compose(TBase, Trait({

    idxParam: Trait.required,
    otherParam: Trait.required,
    operatorFn: Trait.required,

    filter: function (tar, prop, rec, args, opType) {
        //Policy NOT! applicable for property reads!!!
        if (opType === 'readProperty') {
            return true;
        }
        /**
         * document.createElement(stringOf(fakeDiv))
         * apply(p,t,args){
         *  if(policy.filter(...)) should change args to the desired type-value in the policy and use it subsequently
         *  return p.apply(t,args)
         * }
         */
        let newVal = this.idxParam(args);
        return this.operatorFn(newVal, this.otherParam);
    }
}));

/**
 * This function is used to prevent abusing toString and valueOf (we should look at other functions like that)
 * example of usage: ParamAt(equals, getVType(0,String), 'iframe')
 * Be sure that the type parameter returns a primitive object (string, number,...)
 */

const getVType = (idx, type) => {
    return (array) => {
        let val = type(array[idx]);
        array[idx] = val;
        return val;
    }
}

const ParamAt = (fn, idx, other) => {
    var paramPrototype = basePrototype();

    paramPrototype.operatorFn = fn;
    paramPrototype.idxParam = idx;
    paramPrototype.otherParam = other;

    return Trait.create(paramPrototype, TParamAt);
}

const TStateOverParams = Trait.compose(TBase, Trait({

    stateKey: Trait.required,
    operatorFn: Trait.required,
    otherParam: Trait.required,

    filter: function () { //TODO check the parameters...
        var obj = getState(this.stateKey);
        var res = this.operatorFn(obj, this.otherParam);
        return res;
    }
}));

const StateFnParam = (fn, key, param) => {

    var stateParamPrototype = basePrototype()

    stateParamPrototype.stateKey = key;
    stateParamPrototype.operatorFn = fn;
    stateParamPrototype.otherParam = param;

    return Trait.create(stateParamPrototype, TStateOverParams);
}

const And = function (...policies) {
    return Trait.create(basePrototype(), Trait.compose(TBase, Trait({
        filter: function (tar, prop, rec, args) {
            for (var policy of policies) {
                if (!policy.filter(tar, prop, rec, args)) {
                    return false;
                }
            }
            return true;
        }
    })))
}

const Not = function (p1) {

    return Trait.create(basePrototype(), Trait.compose(TBase, Trait({
        filter: function (tar, prop, rec, args) {
            return !p1.filter(tar, prop, rec, args);
        }
    })));
}

const Or = function (...policies) {
    return Trait.create(basePrototype(), Trait.compose(TBase, Trait({
        filter: function (tar, prop, rec, args) {
            // se puede mejorar empleando los operadores de JS
            for (var policy of policies) {
                if (policy.filter(tar, prop, rec, args)) {
                    return true;
                }
            }
            return false;
        }
    })))
}

const Allow = function (properties) {
    var proto = basePrototype();
    proto.allowedProperties = properties;
    var allowedPropPolicy = Trait.create(proto, TAllow);
    return allowedPropPolicy;
}

//Combined Policies

const Deny = function (properties) {
    return Not(Allow(properties))
}

const ParamInList = function (idx, list) {
    return ParamAt((y, xs) => {
        xs.indexOf(y) !== -1
    }, idx, list);
}

const findPropertyOwner = function (obj, prop) {
    do {
        if (obj.hasOwnProperty(prop)) {
            return obj;
        }
    } while (obj = Object.getPrototypeOf(obj));
}

const isBuiltin = function (obj) {
    if (global['window']) {
        return ((obj == window) || (obj == document) || (obj == location) || (obj == navigator) || (obj == navigator.geolocation) && obj) //continue!!
    }
    return false;
}

const installPolicy = (policy) => {

    let notify = (listeners, target, method, receiver, arglist) => {
        if (listeners) {
            for (let listener of listeners) {
                listener.notify(target, method, receiver, arglist)
            }
        }
    }

    return {
        on: function (target) {
            // !!!!!!!!!!!   iterar una sola vez cuando funcione las polizas en la
            // properties !!!!!!!!!!!!!!!...
            let methods = [];
            let properties = [];

            if (isBuiltin(target)) {
                for (let key in target) {
                    let data = target[key];
                    if (data instanceof Function) {
                        methods.push(key);
                    } else if (data) {
                        properties.push(key);
                    }
                }
                //still work todo here
                /* for (let x of properties) {
                    let owner = findPropertyOwner(target, x);
                    if (owner) {
                        var pd = Reflect.getOwnPropertyDescriptor(owner, x);
                        if (pd.configurable && pd.set && !pd.value) {
                            var m = Reflect.defineProperty(target, x, {
                                get: () => {
                                    return target.x;
                                },
                                set: (value) => {
                                    target.x = value
                                }
                            })
                        }
                    }
                }*/

                //proxy on methods
                for (let method of methods) {
                    let fnProxy = new Proxy(target[method], {
                        apply: function (targetFn, thisArg, arglist) {
                            //enforcing
                            if (policy['whenRead']) {
                                for (let pol of policy['whenRead']) {
                                    if (!pol.filter(target, method, undefined, arglist, 'call')) {
                                        throw new Error('[' + method + '] Not allowed!');
                                    }
                                }
                            }
                            //updating listeners
                            notify(policy['readListeners'], target, method, undefined, arglist);
                            return targetFn.apply(thisArg, arglist);
                        }
                    });

                    fnProxy.toString = Function
                        .prototype
                        .toString
                        .bind(target[method]) //Proxies invariants flaws!!!!
                    target[method] = fnProxy;
                }

                return target;

            } else {
                // console.log('no es built in!!'); install the policy in not builtin objects.
                return new Proxy(target, {
                    get: function (tar, property, receiver) {
                        if (tar[property] instanceof Function) {
                            return function (...args) {
                                if (policy['whenRead']) {
                                    for (let pol of policy['whenRead']) {
                                        if (!pol.filter(tar, property, receiver, args, 'call')) {
                                            throw new Error('Read of [' + property + '] is not allowed!');
                                        }
                                    }
                                }
                                notify(policy['readListeners'], tar, property, undefined, args);
                                return tar[property](...args)
                            }
                        } else {

                            if (policy['whenRead']) {
                                for (let pol of policy['whenRead']) {
                                    if (!pol.filter(tar, property, receiver, 'propertyRead')) {
                                        throw new Error('Read of [' + property + '] is not allowed!');
                                    }
                                }
                            }
                            notify(policy['readListeners'], tar, property, undefined, undefined);
                            return Reflect.get(tar, property, receiver);
                        }
                    },
                    set: function (target, property, value, receiver) {
                        if (policy['whenWrite']) {
                            for (let pol of policy['whenWrite']) {
                                if (!pol.filter(target, property, receiver, value, 'call')) {
                                    throw new Error('Write to [' + property + '] is not allowed!');
                                }
                            }
                        }
                        notify(policy['writeListeners'], target, property, undefined, value);
                        return Reflect.set(target, property, value, receiver);
                    }
                });
            }
        },
        onAll: function (targets) {
            for (let item of targets) {
                console.log('target: ' + item);
                this.on(item);
            }
        }
    }
}

var installPolicyCons = function (policy, targetFn) {
    if (targetFn instanceof Function) {
        var proxy = new Proxy(targetFn, {
            construct: function (target, params, newTarget) {
                let image = Reflect.construct(target, params, newTarget);
                image = installPolicy(policy).on(image);
                return image;
            }
        });
        return proxy;
    } else {
        throw new Error('Target must be a contructor!');
    }
}

/**
 * This function is intended to be used for external enforcement mechanisms. The idea is that
 * the provided mechanism call it with the runtime information and guardia should take care of
 * determining the permissions.
 *
 * @param {Object | Function} tar
 * @param {String} prop
 * @param {Object} rec
 * @param {*} args
 * @param {String} hook
 */

const enforce = (tar, prop, rec, args, hook) => {
    if (targets.has(tar)) { // if we already have registered a secured object
        var pols = Array.from(targets.get(tar))
        for (var pol of pols) {
            for (var rpol of pol[hook]) {
                if (!rpol.filter(tar, prop, rec, args))
                    return false;
            }
        }
    }
    return true;
}

const install = (pol, tar) => {
    if (targets.has(tar)) {
        var x = targets.get(tar)
        x.add(pol);
        targets.set(tar, x);
    } else {
        var t = new Set()
        t.add(pol)
        targets.set(tar, t);
    }
}

/**
 * for installing policies on functions
 * pd should { listeners : [] , execPol: []}
 */
const installOnFunction = (pd, fn) => {
    if (tgt instanceof Function) {
        let fnProxy = new Proxy(fn, {
            apply: function (target, thisArg, argumentsList) {
                if (pd.enforce(target, thisArg, argumentsList)) {
                    throw new Error('Not Allowed');
                }
                return Reflect.apply(target, thisArg, argumentsList);
            }
        });
        return fnProxy;
    }
    throw new Error('Not a function');
}

exports.installPolicy = installPolicy;
exports.installPolicyCons = installPolicyCons;
exports.Allow = Allow;
exports.Deny = Deny;
exports.And = And;
exports.Or = Or;
exports.Not = Not;
exports.ParamInList = ParamInList;
exports.ParamAt = ParamAt;
exports.StateFnParam = StateFnParam;
exports.setState = setState;
exports.getState = getState;
exports.getVType = getVType;

//this needs to be tested yet
exports.enforce = enforce;
exports.installOn = install;
<|endoftext|>


<commit_before>require('babel/register');
const fs = require('fs');

// model FileData
const FileData = require('./models/FileData.js');

// Initialize database as soon as possible
const mongoose = require('./infra/db-manager');
process.nextTick(() => {
        mongoose.connection.once('connected', () => {
            // drop db to start in a clean state
            console.log('Database intialized');
            mongoose.connection.db.dropDatabase();
        });
})

// const readNodeJsEventLoopPath = "app/fixtures/nodejs-event-loop-explanations.md";
const contextNodeJsEventLoopFile = {
    id: 'nodejs_event_loop',
    path: 'app/fixtures/nodejs-event-loop-explanations.md'
}
const contextReadMeFile = {
    id: 'readme',
    path: 'README.md'
}

// const readDictionaryStream =  createReadStream("app/fixtures/session_dictionary.txt");
// const readSessionStream = createReadStream("app/fixtures/airbnb_session_data.txt");
// // const readNodeJsEventLoopStream =  createReadStream("app/fixtures/nodejs_event_loop.txt");
// const readNodeJsEventLoopStream =  createReadStream("app/fixtures/nodejs-event-loop-explanations.md");
// const readReadmeStream =  createReadStream("README.md");
// const writeLogStream = createWriteStream("app/log/log.txt");
// // const readSessionStream = createReadStream("app/fixtures/session_data.txt");

let lines_ok=0, lines_ko=0;

function saveData(data, resolve, reject)  {
    console.log('saveData '+ this.id)
    const f = new FileData();
    f.value = data;
    f._id = this.id;
    f.save( (err) => {
        if (err){
            console.log('ERR with '+f.id+' : '+err)
            reject(err);
        }
        else{
            console.log('SUCCESS - '+f.id+' added');
            resolve();
        }
    });
}

// const InitDbPromise = new Promise( (resolve, reject) => {
//     process.nextTick ( () => {
//         mongoose.connection.once('connected', () => {
//             // drop db to start in a clean state
//             console.log('Database intialized');
//             mongoose.connection.db.dropDatabase();
//         });

//     })
//     console.log('init db')
//     resolve();
// })

// const readNodeJsEventLoopFilePromise2 = new Promise( (saveData, reject) => {
//     console.log('inside p12');
//     fs.readFile(contextNodeJsEventLoopFile.path);
//     }).then( (err, data) => {
//         console.log('inside callback p1 '+err);
//         console.log(data);
//         console.log(saveData);
//         err ? reject(err) : saveData.call(contextNodeJsEventLoopFile, data)
//     })
const readNodeJsEventLoopFilePromise = new Promise( (resolve, reject) => {
    fs.readFile(contextNodeJsEventLoopFile.path, (err, data) => {
        if (err) {
            reject(err)
        }
        else {
            saveData.call(contextNodeJsEventLoopFile, data, resolve, reject);
        }
    });
})

const readReadMeFilePromise = new Promise( (resolve, reject) => {
    fs.readFile(contextReadMeFile.path, (err, data) => {
        if (err) {
            reject(err)
        }
        else {
            saveData.call(contextReadMeFile, data, resolve, reject);
        }
    });
})

// const readReadmeFilePromise = new Promise( (saveData, reject) => {
//     console.log('inside p2');
//     fs.readFile(contextReadMeFile.path, (err, data) => {
//         console.log('inside callback p2 '+err);
//         err ? reject(err) : saveData.call(contextReadMeFile, data)
//     });
// })

const promises = new Array(readNodeJsEventLoopFilePromise, readReadMeFilePromise);

const runPromises = (promises) => {
    return Promise.all(promises);
}
console.log('before promises');
runPromises(promises).then( () => {
    console.log('the end');
    mongoose.connection.close();

}).catch( (err) => {
    console.log(err);
});
<commit_msg>RawData model and Session data added in promises<commit_after>require('babel/register');
const fs = require('fs');

// model FileData
const FileData = require('./models/FileData.js');

// Initialize database as soon as possible
const mongoose = require('./infra/db-manager');
mongoose.connection.once('connected', () => {
    // drop db to start in a clean state
    console.log('Database intialized');
    mongoose.connection.db.dropDatabase();

    // Start operations
    readNodeJsEventLoopFilePromise()
        .then((id) => {
            console.log(id+' added (step 2)');
            return readReadMeFilePromise();
        })
        .then( () => {
            console.log('before dictionary');
            return readDictionaryPromise();
        })
        .then( (res) => {
            console.log('dictionary added');
            return readSessionPromise(res);
        })
        .then( (id) => {
            console.log(id+' added (the end)');
            mongoose.connection.close();
        }).catch( (err) => {
            console.log(err);
        });
});

const contextNodeJsEventLoopFile = {
    id: 'nodejs_event_loop',
    path: 'app/fixtures/nodejs-event-loop-explanations.md'
};

const contextReadMeFile = {
    id: 'readme',
    path: 'README.md'
};

const contextDictionaryFile = {
    id: 'dictionary',
    path: 'app/fixtures/session_dictionary.txt'
};

const contextSessionFile = {
    id: 'session_data',
    path: 'app/fixtures/airbnb_session_data.txt'
};

const readSessionPromise = (res) => {
    return new Promise( (resolve, reject) => {
        fs.readFile(contextSessionFile.path, (err, data) => {
            if (err) {
                reject(err)
            }
            else {
                const dictionary = res.dictionary;
                const RawData = res.model;
                data = data.toString();
                lines = data.split('\n');
                const rawDataJson = {}
                lines.map( (line) => {
                    var fields = line.split('|');
                    for (var i=0; i< dictionary.length; i++){
                        rawDataJson[dictionary[i]] = fields[i];
                    }
                    let r =  new RawData(rawDataJson)
                    if (r.id_session && r.dim_user_agent){
                        r.device = r.dim_device_app_combo.replace(/(.*) -.*/g,'$1');
                        r.save( (err) => {
                            if (err){
                                console.log('err '+err);
                            }
                        });
                    }
                });
                resolve('session data');

            }
        });
    });
};

const readDictionaryPromise = () => {
    return new Promise( (resolve, reject) => {
        fs.readFile(contextDictionaryFile.path, (err, data) => {
            if (err) {
                reject(err)
            }
            else {
                data = data.toString();
                console.log("read dictionary");
                const dictionary = data.split('|');
                const rawDataSchemaJson = {};
                dictionary.map( (word) => {
                    rawDataSchemaJson[word] = {
                        type: String,
                        required: true,
                    };
                });

                // to ensure the line is relevant (required) and unique (index-uniaue)
                rawDataSchemaJson["id_session"] = {
                    type: String,
                    required: true,
                    index: { unique: true }
                };
                rawDataSchemaJson["device"] = {
                    type: String,
                    required: true
                };
                // initialize RawData schema and model
                const rawDataSchema = mongoose.Schema(rawDataSchemaJson);
                const RawData = mongoose.model("RawData", rawDataSchema);
                const res = {
                    model: RawData,
                    dictionary: dictionary
                }
                resolve(res);
                // saveData.call(contextNodeJsEventLoopFile, data, resolve, reject);
            }
        });
    })
}

function saveData(data, resolve, reject)  {
    // this bind from outside
    console.log('saveData '+ this.id)
    const f = new FileData();
    f.value = data;
    f._id = this.id;
    f.save( (err) => {
        if (err){
            console.log('ERR with '+f.id+' : '+err)
            reject(err);
        }
        else{
            console.log('SUCCESS - '+f.id+' added');
            resolve(this.id);
        }
    });
}

const readNodeJsEventLoopFilePromise = () => {
    return new Promise( (resolve, reject) => {
        fs.readFile(contextNodeJsEventLoopFile.path, (err, data) => {
            if (err) {
                reject(err)
            }
            else {
                saveData.call(contextNodeJsEventLoopFile, data, resolve, reject);
            }
        });
    })
}

const readReadMeFilePromise = () => {
    return new Promise( (resolve, reject) => {
        fs.readFile(contextReadMeFile.path, (err, data) => {
            if (err) {
                reject(err)
            }
            else {
                saveData.call(contextReadMeFile, data, resolve, reject);
            }
        });
    })
}<|endoftext|>


<commit_before>
var overCraftingItem = null;
var craftingCanvasYOffset = 0;
var lastCraftedItem = null;
var totalRows;
var slotCraftingOffsets;
var craftingSlotSize = 16;
var craftingSlotSpacing = 1;
var craftingSlotTotal = craftingSlotSize + craftingSlotSpacing;
function initializeCraftingImage() {
    var offset = 0
    var offsets = {'weapon': offset, 'offhand': offset+=3, 'head': offset+=1,
        'body': offset+=1, 'arms': offset+=1, 'legs': offset+=1, 'feet': offset+=1,
        'back': offset+=1, 'ring': offset += 1};
    slotCraftingOffsets = offsets;
    totalRows = offset + 2;
    craftingCanvas.width = 4 + craftingSlotTotal * 74;
    craftingCanvas.height = 4 + craftingSlotTotal * (totalRows - 1);
    state.craftingContext.font = (craftingSlotSize - 2) + "px sans-serif";
    state.craftingContext.textBaseline = "middle";
    state.craftingContext.textAlign = 'center'
    $.each(offsets, function (slot, offset) {
        for (var i = 0; i < items.length; i++) {
            var x = 2 + (i - 1) * craftingSlotTotal;
            for (var j = 0; j < ifdefor(itemsBySlotAndLevel[slot][i], []).length; j++) {
                var y = 2 + (offset + j) * craftingSlotTotal;
                state.craftingContext.fillStyle = '#888';
                state.craftingContext.fillRect(x, y, craftingSlotSize, craftingSlotSize);
                state.craftingContext.fillStyle = 'white';
                state.craftingContext.fillText('?', x + craftingSlotSize / 2, y + craftingSlotSize / 2);
                var item = itemsBySlotAndLevel[slot][i][j];
                item.craftingX = x;
                item.craftingY = y;
            }
        }
    });
    $(state.craftingViewCanvas).on('mousemove', function () {
        var offset = relativeMousePosition($(this));
        var tx = Math.floor((offset[0] - 2) / craftingSlotTotal);
        var subX = offset[0] - tx * craftingSlotTotal - 2;
        var ty = Math.floor((offset[1] - 2) / craftingSlotTotal);
        var subY = offset[1] - ty * craftingSlotTotal - 2;
        var level = tx + 1;
        var slotOffset = 0;
        var overSlot = 'weapon';
        $.each(offsets, function (slot, offset) {
            if (ty >= offset) {
                slotOffset = offset;
                overSlot = slot;
            }
            return ty >= offset;
        });
        var items = ifdefor(ifdefor(itemsBySlotAndLevel[overSlot], [])[level], []);
        var index = ty - slotOffset;
        var maxLevel = $('.js-levelSelect option').last().attr('value');
        // subX/subY values are used to make sure we don't show hover when mouse
        // is actually in between crafting tiles.
        if (level <= maxLevel && index < items.length && subY <= 16 && subX <= 16) {
            overCraftingItem = items[index];
        } else {
            overCraftingItem = null
        }
        if (mouseDown) {
            setCraftingLevel(level);
        }
    });
    $(state.craftingViewCanvas).on('click', function () {
        var offset = relativeMousePosition($(this));
        var ty = Math.floor((offset[1] - 2) / craftingSlotTotal);
        var level = Math.floor((offset[0] - 2) / craftingSlotTotal) + 1;
        var slotOffset = 0;
        var overSlot = 'weapon';
        $.each(offsets, function (slot, offset) {
            if (ty >= offset) {
                slotOffset = offset;
                overSlot = slot;
            }
            return ty >= offset;
        });
        var items = ifdefor(ifdefor(itemsBySlotAndLevel[overSlot], [])[level], []);
        var index = ty - slotOffset;
        setCraftingLevel(level);
    });
    $(state.craftingViewCanvas).on('mouseout', function () {
        overCraftingItem = null
    });
    drawCraftingViewCanvas();
}
function setCraftingLevel(level) {
    var maxLevel = $('.js-levelSelect option').last().attr('value');
    $('.js-levelSelect').val(Math.min(maxLevel, level));
    updateItemCrafting();
}
function drawCraftingViewCanvas() {
    var canvas = state.craftingViewCanvas;
    var maxLevel = $('.js-levelSelect option').last().attr('value');
    canvas.width = 4 + craftingSlotTotal * maxLevel;
    canvas.height = 4 + craftingSlotTotal * (totalRows - 1);
    var context = state.craftingViewContext;
    var offset = 0;
    var rows = totalRows;
    switch (craftingTypeFilter) {
        case 'all':
            break;
        case 'weapon':
            rows = 3;
            break;
        case 'armor':
            offset = slotCraftingOffsets['offhand'];
            rows = slotCraftingOffsets['feet'] - offset + 1;
            break;
        case 'accessory':
            offset = slotCraftingOffsets['back'];
            rows = slotCraftingOffsets['ring'] - offset + 1;
            break
        default:
            offset = slotCraftingOffsets[craftingTypeFilter];
            rows = 1;
    }
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.fillStyle = '#8F8';
    context.fillRect(0, offset * craftingSlotTotal, 4 + craftingSlotTotal * craftingLevel, 4 + rows * craftingSlotTotal);
    context.drawImage(state.craftingCanvas, 0, 0, Math.min(state.craftingCanvas.width, 2 + craftingSlotTotal * maxLevel), state.craftingCanvas.height,
                      0, 0, Math.min(state.craftingCanvas.width, 2 + craftingSlotTotal * maxLevel), state.craftingCanvas.height);
}

$('.js-raritySelect').on('change', updateItemCrafting);
$('.js-levelSelect').on('change', updateItemCrafting);
$('.js-typeSelect').on('change', updateItemCrafting);
var craftingPointsType = 'coins';
var itemsFilteredByType = [];
var selectedCraftingWeight = 0;
var itemTotalCost = 5;
var craftingLevel = 1;
var craftingTypeFilter = 'all';
function updateItemCrafting() {
    var rarity = $('.js-raritySelect').val();
    craftingLevel = $('.js-levelSelect').val();
    craftingTypeFilter = $('.js-typeSelect').val();
    var playerCurrency = 0;
    var rarityMultiplier = (rarity === 'imbued') ? 5 : 1;
    if (rarity == 'plain') {
        craftingPointsType = 'coins'
    } else {
        craftingPointsType = 'anima'
    }

    var itemsFilteredByLevel = [];
    itemsFilteredByType = [];
    for (var itemLevel = 0; itemLevel <= craftingLevel && itemLevel < items.length; itemLevel++) {
        items[itemLevel].forEach(function (item) {
            itemsFilteredByLevel.push(item);
            if (itemMatchesFilter(item, craftingTypeFilter)) {
                itemsFilteredByType.push(item);
            }
        });
    }
    var typeMultiplier = (itemsFilteredByLevel.length / itemsFilteredByType.length).toFixed(2);
    $('.js-rarityCost').html(points(craftingPointsType, 5 * rarityMultiplier));
    var levelMultiplier = craftingLevel * craftingLevel * craftingLevel;
    $('.js-levelMultiplier').text('x ' + levelMultiplier);
    $('.js-typeMultiplier').text('x ' + typeMultiplier);
    itemTotalCost = Math.ceil(5 * levelMultiplier * typeMultiplier * rarityMultiplier);
    $('.js-craftItem').html('Craft for ' + points(craftingPointsType, itemTotalCost));
    updateCraftButton();
    updateSelectedCraftingWeight();
    drawCraftingViewCanvas();
}
function updateSelectedCraftingWeight() {
    selectedCraftingWeight = 0;
    itemsFilteredByType.forEach(function (item) {
        selectedCraftingWeight += item.craftingWeight;
    });
}
$('.js-craftItem').on('click', function () {
    if (!spend(craftingPointsType, itemTotalCost)) {
        return;
    }
    var craftingRoll = Math.floor(Math.random() * selectedCraftingWeight);
    var index = 0;
    while (craftingRoll > itemsFilteredByType[index].craftingWeight) {
        craftingRoll -= itemsFilteredByType[index].craftingWeight;
        index++;
    }
    if (lastCraftedItem) {
        state.craftingContext.fillStyle = ifdefor(lastCraftedItem.craftedUnique ? '#44ccff' : 'green');
        state.craftingContext.fillRect(lastCraftedItem.craftingX, lastCraftedItem.craftingY, craftingSlotSize, craftingSlotSize);
    }
    var craftedItem = itemsFilteredByType[index];
    itemsFilteredByType.forEach(function (item) {
        item.craftingWeight += item.level * item.level * 5;
    });
    craftedItem.craftingWeight /= 2;
    updateSelectedCraftingWeight();
    var item = makeItem(craftedItem, craftingLevel);
    var rarity = $('.js-raritySelect').val();
    if (rarity === 'enchanted') {
        enchantItemProper(item);
    } else if (rarity === 'imbued') {
        imbueItemProper(item);
    } else {
        // Rolling a plain item has a chance to create a unique if one exists for
        // this base type.
        checkToMakeItemUnique(item);
        if (item.unique) {
            craftedItem.craftedUnique = true;
        }
    }
    craftedItem.crafted = true;
    state.craftingContext.fillStyle = ifdefor(craftedItem.craftedUnique) ? '#0088ff' : 'orange';
    state.craftingContext.fillRect(craftedItem.craftingX, craftedItem.craftingY, craftingSlotSize, craftingSlotSize);
    drawCraftingViewCanvas();
    updateItem(item);
    $('.js-inventory').prepend(item.$item);
    lastCraftedItem = craftedItem;
});
function updateCraftButton() {
    $('.js-craftItem').prop('disabled', itemTotalCost > state[craftingPointsType]);
}

function itemMatchesFilter(item, typeFilter) {
    switch (typeFilter) {
        case 'all':
            return true;
        case 'armor':
            return armorSlots.indexOf(item.slot) >= 0;
        case 'accessory':
            return item.slot == 'ring' || item.slot == 'back';
        default:
            return item.slot === typeFilter;
    }
}

$('.js-mouseContainer').on('mouseover mousemove', checkToShowCraftingToopTip);
function checkToShowCraftingToopTip() {
    if (!overCraftingItem) {
        return;
    }
    if ($popup) {
        if ($popup.data('item') === overCraftingItem) return;
        else $popup.remove();
    }
    var sections;
    if (overCraftingItem.crafted) {
        sections = [overCraftingItem.name, 'Requires level ' + overCraftingItem.level, ''];
        sections.push(bonusHelpText(overCraftingItem.bonuses, true));
        if (ifdefor(overCraftingItem.craftedUnique)) {
            sections.push(tag('div', 'uniqueText', 'Unique Variant:
' + overCraftingItem.unique.displayName + '
' + (100 * overCraftingItem.unique.chance).format(1) + '% chance'));
        }
    } else {
        sections = ['??? ' + overCraftingItem.slot, 'Requires level ' + overCraftingItem.level, ''];
    }
    if (itemsFilteredByType.indexOf(overCraftingItem) >= 0) {
        sections.push('');
        sections.push((100 * overCraftingItem.craftingWeight / selectedCraftingWeight).format(1) + '% chance to craft');
    }
    $popup = $tag('div', 'toolTip js-toolTip', sections.join('
'));
    $popup.data('item', overCraftingItem);
    $popupTarget = null;
    updateToolTip(mousePosition[0], mousePosition[1], $popup);
    $('.js-mouseContainer').append($popup);
}<commit_msg>Update crafting weight formula so that the odds of crafting high level items is never lowered by attempts to craft lower level weapons.<commit_after>
var overCraftingItem = null;
var craftingCanvasYOffset = 0;
var lastCraftedItem = null;
var totalRows;
var slotCraftingOffsets;
var craftingSlotSize = 16;
var craftingSlotSpacing = 1;
var craftingSlotTotal = craftingSlotSize + craftingSlotSpacing;
function initializeCraftingImage() {
    var offset = 0
    var offsets = {'weapon': offset, 'offhand': offset+=3, 'head': offset+=1,
        'body': offset+=1, 'arms': offset+=1, 'legs': offset+=1, 'feet': offset+=1,
        'back': offset+=1, 'ring': offset += 1};
    slotCraftingOffsets = offsets;
    totalRows = offset + 2;
    craftingCanvas.width = 4 + craftingSlotTotal * 74;
    craftingCanvas.height = 4 + craftingSlotTotal * (totalRows - 1);
    state.craftingContext.font = (craftingSlotSize - 2) + "px sans-serif";
    state.craftingContext.textBaseline = "middle";
    state.craftingContext.textAlign = 'center'
    $.each(offsets, function (slot, offset) {
        for (var i = 0; i < items.length; i++) {
            var x = 2 + (i - 1) * craftingSlotTotal;
            for (var j = 0; j < ifdefor(itemsBySlotAndLevel[slot][i], []).length; j++) {
                var y = 2 + (offset + j) * craftingSlotTotal;
                state.craftingContext.fillStyle = '#888';
                state.craftingContext.fillRect(x, y, craftingSlotSize, craftingSlotSize);
                state.craftingContext.fillStyle = 'white';
                state.craftingContext.fillText('?', x + craftingSlotSize / 2, y + craftingSlotSize / 2);
                var item = itemsBySlotAndLevel[slot][i][j];
                item.craftingX = x;
                item.craftingY = y;
            }
        }
    });
    $(state.craftingViewCanvas).on('mousemove', function () {
        var offset = relativeMousePosition($(this));
        var tx = Math.floor((offset[0] - 2) / craftingSlotTotal);
        var subX = offset[0] - tx * craftingSlotTotal - 2;
        var ty = Math.floor((offset[1] - 2) / craftingSlotTotal);
        var subY = offset[1] - ty * craftingSlotTotal - 2;
        var level = tx + 1;
        var slotOffset = 0;
        var overSlot = 'weapon';
        $.each(offsets, function (slot, offset) {
            if (ty >= offset) {
                slotOffset = offset;
                overSlot = slot;
            }
            return ty >= offset;
        });
        var items = ifdefor(ifdefor(itemsBySlotAndLevel[overSlot], [])[level], []);
        var index = ty - slotOffset;
        var maxLevel = $('.js-levelSelect option').last().attr('value');
        // subX/subY values are used to make sure we don't show hover when mouse
        // is actually in between crafting tiles.
        if (level <= maxLevel && index < items.length && subY <= 16 && subX <= 16) {
            overCraftingItem = items[index];
        } else {
            overCraftingItem = null
        }
        if (mouseDown) {
            setCraftingLevel(level);
        }
    });
    $(state.craftingViewCanvas).on('click', function () {
        var offset = relativeMousePosition($(this));
        var ty = Math.floor((offset[1] - 2) / craftingSlotTotal);
        var level = Math.floor((offset[0] - 2) / craftingSlotTotal) + 1;
        var slotOffset = 0;
        var overSlot = 'weapon';
        $.each(offsets, function (slot, offset) {
            if (ty >= offset) {
                slotOffset = offset;
                overSlot = slot;
            }
            return ty >= offset;
        });
        var items = ifdefor(ifdefor(itemsBySlotAndLevel[overSlot], [])[level], []);
        var index = ty - slotOffset;
        setCraftingLevel(level);
    });
    $(state.craftingViewCanvas).on('mouseout', function () {
        overCraftingItem = null
    });
    drawCraftingViewCanvas();
}
function setCraftingLevel(level) {
    var maxLevel = $('.js-levelSelect option').last().attr('value');
    $('.js-levelSelect').val(Math.min(maxLevel, level));
    updateItemCrafting();
}
function drawCraftingViewCanvas() {
    var canvas = state.craftingViewCanvas;
    var maxLevel = $('.js-levelSelect option').last().attr('value');
    canvas.width = 4 + craftingSlotTotal * maxLevel;
    canvas.height = 4 + craftingSlotTotal * (totalRows - 1);
    var context = state.craftingViewContext;
    var offset = 0;
    var rows = totalRows;
    switch (craftingTypeFilter) {
        case 'all':
            break;
        case 'weapon':
            rows = 3;
            break;
        case 'armor':
            offset = slotCraftingOffsets['offhand'];
            rows = slotCraftingOffsets['feet'] - offset + 1;
            break;
        case 'accessory':
            offset = slotCraftingOffsets['back'];
            rows = slotCraftingOffsets['ring'] - offset + 1;
            break
        default:
            offset = slotCraftingOffsets[craftingTypeFilter];
            rows = 1;
    }
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.fillStyle = '#8F8';
    context.fillRect(0, offset * craftingSlotTotal, 4 + craftingSlotTotal * craftingLevel, 4 + rows * craftingSlotTotal);
    context.drawImage(state.craftingCanvas, 0, 0, Math.min(state.craftingCanvas.width, 2 + craftingSlotTotal * maxLevel), state.craftingCanvas.height,
                      0, 0, Math.min(state.craftingCanvas.width, 2 + craftingSlotTotal * maxLevel), state.craftingCanvas.height);
}

$('.js-raritySelect').on('change', updateItemCrafting);
$('.js-levelSelect').on('change', updateItemCrafting);
$('.js-typeSelect').on('change', updateItemCrafting);
var craftingPointsType = 'coins';
var itemsFilteredByType = [];
var selectedCraftingWeight = 0;
var itemTotalCost = 5;
var craftingLevel = 1;
var craftingTypeFilter = 'all';
function updateItemCrafting() {
    var rarity = $('.js-raritySelect').val();
    craftingLevel = $('.js-levelSelect').val();
    craftingTypeFilter = $('.js-typeSelect').val();
    var playerCurrency = 0;
    var rarityMultiplier = (rarity === 'imbued') ? 5 : 1;
    if (rarity == 'plain') {
        craftingPointsType = 'coins'
    } else {
        craftingPointsType = 'anima'
    }

    var itemsFilteredByLevel = [];
    itemsFilteredByType = [];
    for (var itemLevel = 0; itemLevel <= craftingLevel && itemLevel < items.length; itemLevel++) {
        items[itemLevel].forEach(function (item) {
            itemsFilteredByLevel.push(item);
            if (itemMatchesFilter(item, craftingTypeFilter)) {
                itemsFilteredByType.push(item);
            }
        });
    }
    var typeMultiplier = (itemsFilteredByLevel.length / itemsFilteredByType.length).toFixed(2);
    $('.js-rarityCost').html(points(craftingPointsType, 5 * rarityMultiplier));
    var levelMultiplier = craftingLevel * craftingLevel * craftingLevel;
    $('.js-levelMultiplier').text('x ' + levelMultiplier);
    $('.js-typeMultiplier').text('x ' + typeMultiplier);
    itemTotalCost = Math.ceil(5 * levelMultiplier * typeMultiplier * rarityMultiplier);
    $('.js-craftItem').html('Craft for ' + points(craftingPointsType, itemTotalCost));
    updateCraftButton();
    updateSelectedCraftingWeight();
    drawCraftingViewCanvas();
}
function updateSelectedCraftingWeight() {
    selectedCraftingWeight = 0;
    itemsFilteredByType.forEach(function (item) {
        selectedCraftingWeight += item.craftingWeight;
    });
}
$('.js-craftItem').on('click', function () {
    if (!spend(craftingPointsType, itemTotalCost)) {
        return;
    }
    var craftingRoll = Math.floor(Math.random() * selectedCraftingWeight);
    var index = 0;
    while (craftingRoll > itemsFilteredByType[index].craftingWeight) {
        craftingRoll -= itemsFilteredByType[index].craftingWeight;
        index++;
    }
    if (lastCraftedItem) {
        state.craftingContext.fillStyle = ifdefor(lastCraftedItem.craftedUnique ? '#44ccff' : 'green');
        state.craftingContext.fillRect(lastCraftedItem.craftingX, lastCraftedItem.craftingY, craftingSlotSize, craftingSlotSize);
    }
    var craftedItem = itemsFilteredByType[index];
    // This is used to determine what proportion of the crafting weight goes to which item.
    var totalCraftingWeight = 0;
    itemsFilteredByType.forEach(function (item) {
        if (item === craftedItem) return;
        totalCraftingWeight += item.level * item.level * 5;
    });
    // Remove crafting weight from the crafted item and distribute it out proportionally
    // to other items that could have been crafted. This leaves the crafting weight of
    // the selected group the same while decreasing the odds of crafting the same item
    // again and increasing the odds of the highest level items the most.
    var distributedCraftingWeight = craftedItem.craftingWeight / 2;
    craftedItem.craftingWeight -= distributedCraftingWeight;
    itemsFilteredByType.forEach(function (item) {
        item.craftingWeight += distributedCraftingWeight * item.level * item.level * 5 / totalCraftingWeight;
    });
    craftedItem.craftingWeight /= 2;
    updateSelectedCraftingWeight();
    var item = makeItem(craftedItem, craftingLevel);
    var rarity = $('.js-raritySelect').val();
    if (rarity === 'enchanted') {
        enchantItemProper(item);
    } else if (rarity === 'imbued') {
        imbueItemProper(item);
    } else {
        // Rolling a plain item has a chance to create a unique if one exists for
        // this base type.
        checkToMakeItemUnique(item);
        if (item.unique) {
            craftedItem.craftedUnique = true;
        }
    }
    craftedItem.crafted = true;
    state.craftingContext.fillStyle = ifdefor(craftedItem.craftedUnique) ? '#0088ff' : 'orange';
    state.craftingContext.fillRect(craftedItem.craftingX, craftedItem.craftingY, craftingSlotSize, craftingSlotSize);
    drawCraftingViewCanvas();
    updateItem(item);
    $('.js-inventory').prepend(item.$item);
    lastCraftedItem = craftedItem;
});
function updateCraftButton() {
    $('.js-craftItem').prop('disabled', itemTotalCost > state[craftingPointsType]);
}

function itemMatchesFilter(item, typeFilter) {
    switch (typeFilter) {
        case 'all':
            return true;
        case 'armor':
            return armorSlots.indexOf(item.slot) >= 0;
        case 'accessory':
            return item.slot == 'ring' || item.slot == 'back';
        default:
            return item.slot === typeFilter;
    }
}

$('.js-mouseContainer').on('mouseover mousemove', checkToShowCraftingToopTip);
function checkToShowCraftingToopTip() {
    if (!overCraftingItem) {
        return;
    }
    if ($popup) {
        if ($popup.data('item') === overCraftingItem) return;
        else $popup.remove();
    }
    var sections;
    if (overCraftingItem.crafted) {
        sections = [overCraftingItem.name, 'Requires level ' + overCraftingItem.level, ''];
        sections.push(bonusHelpText(overCraftingItem.bonuses, true));
        if (ifdefor(overCraftingItem.craftedUnique)) {
            sections.push(tag('div', 'uniqueText', 'Unique Variant:
' + overCraftingItem.unique.displayName + '
' + (100 * overCraftingItem.unique.chance).format(1) + '% chance'));
        }
    } else {
        sections = ['??? ' + overCraftingItem.slot, 'Requires level ' + overCraftingItem.level, ''];
    }
    if (itemsFilteredByType.indexOf(overCraftingItem) >= 0) {
        sections.push('');
        sections.push((100 * overCraftingItem.craftingWeight / selectedCraftingWeight).format(1) + '% chance to craft');
    }
    $popup = $tag('div', 'toolTip js-toolTip', sections.join('
'));
    $popup.data('item', overCraftingItem);
    $popupTarget = null;
    updateToolTip(mousePosition[0], mousePosition[1], $popup);
    $('.js-mouseContainer').append($popup);
}<|endoftext|>


<commit_before>/**
 * Copyright 2014 - 2015 Solinea, Inc.
 *
 * Licensed under the Solinea Software License Agreement (goldstone),
 * Version 1.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *     http://www.solinea.com/goldstone/LICENSE.pdf
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
This view makes up the "Events" tab of nodeReportView.js
It is sub-classed from GoldstoneBaseView.

Much of the functionality is encompassed by the jQuery
dataTables plugin which is documented at
http://datatables.net/reference/api/

Instantiated on nodeReportView as:

this.eventsReport = new EventsReportView({
    el: '#node-report-panel #eventsReport',
    width: $('#node-report-panel #eventsReport').width(),
    nodeName: hostName,
    globalLookback: ns.globalLookback
});
*/

var EventsReportView = GoldstoneBaseView.extend({

    // initialize empty 'defaults' object that will be used as a container
    // for shared values amongst local functions
    defaults: {},

    urlGen: function() {

        // urlGen is instantiated inside the beforeSend AJAX hook
        // which means it is run again before every dataTables server query

        var now = +new Date();
        // subtracts correct ms from current time
        var lookback = now - (1000 * 60 * this.defaults.globalLookback);
        var urlRouteConstruction = '/core/events?source_name=' +
            this.defaults.hostName + '&created__lte=' + now + '&created__gte=' + lookback;
        this.defaults.url = urlRouteConstruction;
    },

    initialize: function(options) {

        EventsReportView.__super__.initialize.apply(this, arguments);
    },

    processOptions: function() {
        EventsReportView.__super__.processOptions.apply(this, arguments);

        this.defaults.hostName = this.options.nodeName;
        this.defaults.globalLookback = this.options.globalLookback;
    },

    processListeners: function() {
        // this is triggered by a listener set on nodeReportView.js
        this.on('lookbackSelectorChanged', function() {

            // set the lookback based on the global selector
            this.defaults.globalLookback = $('#global-lookback-range').val();

            // trigger a redraw of the table
            $('#events-report-table').dataTable().fnDraw();
        });
    },

    processMargins: function() {
        // overwritten so as not to conflict with super-class'
        // method that will calculate irrelevant margins.
        return null;
    },

    standardInit: function() {
        // overwritten so as not to conflict with super-class'
        // method that will calculate irrelevant margins.
        return null;
    },

    dataPrep: function(data) {
        var ns = this.defaults;
        var self = this;

        // initial result is stringified JSON
        var tableData = JSON.parse(data);

        var finalResults = [];

        _.each(tableData.results, function(item) {

            // if any field is undefined, dataTables throws an alert
            // so set to empty string if otherwise undefined
            item.id = item.id || '';
            item.event_type = item.event_type || '';
            item.source_id = item.source_id || '';
            item.source_name = item.source_name || '';
            item.message = item.message || '';
            item.created = item.created || '';

            finalResults.push([item.created, item.event_type, item.message, item.id, item.source_id, item.source_name]);
        });

        // total/filtered/result feeds the dataTables
        // item count at the bottom of the table
        return {
            recordsTotal: tableData.count,
            recordsFiltered: tableData.count,
            result: finalResults
        };
    },

    drawSearchTable: function(location) {

        var ns = this.defaults;
        var self = this;

        this.hideSpinner();

        var oTable;

        // Params documented at http://datatables.net/reference/option/
        var oTableParams = {
            "info": true,
            "processing": true,
            "lengthChange": true,
            "paging": true,
            "searching": true,
            "order": [
                [0, 'desc']
            ],
            "ordering": true,
            "serverSide": true,
            "ajax": {
                beforeSend: function(obj, settings) {

                    // warning: as dataTable features are enabled/
                    // disabled , check if the structure of settings.
                    // url changes significantly. Be sure to
                    // reference the correct array indices when
                    // comparing, or scraping data

                    self.urlGen();

                    var pageSize = $(self.el).find('select.form-control').val();
                    var searchQuery = $(self.el).find('input.form-control').val();
                    var paginationStart = settings.url.match(/start=\d{1,}&/gi);
                    paginationStart = paginationStart[0].slice(paginationStart[0].indexOf('=') + 1, paginationStart[0].lastIndexOf('&'));
                    var computeStartPage = Math.floor(paginationStart / pageSize) + 1;
                    var urlColumnOrdering = decodeURIComponent(settings.url).match(/order\[0\]\[column\]=\d*/gi);

                    // capture which column was clicked
                    // and which direction the sort is called for

                    var urlOrderingDirection = decodeURIComponent(settings.url).match(/order\[0\]\[dir\]=(asc|desc)/gi);
                    settings.url = self.defaults.url + "&page_size=" + pageSize + "&page=" + computeStartPage;

                    if (searchQuery) {
                        settings.url = settings.url + "&message__prefix=" + searchQuery;
                    }

                    // if no interesting sort, ignore it
                    if (urlColumnOrdering[0] !== "order[0][column]=0" || urlOrderingDirection[0] !== "order[0][dir]=desc") {

                        // or, if something has changed, capture the
                        // column to sort by, and the sort direction

                        var columnLabelHash = {
                            0: 'created',
                            1: 'event_type',
                            2: 'message'
                        };

                        var orderByColumn = urlColumnOrdering[0].slice(urlColumnOrdering[0].indexOf('=') + 1);

                        var orderByDirection = urlOrderingDirection[0].slice(urlOrderingDirection[0].indexOf('=') + 1);

                        var ascDec;
                        if (orderByDirection === 'asc') {
                            ascDec = '';
                        } else {
                            ascDec = '-';
                        }

                        settings.url = settings.url + "&ordering=" +
                            ascDec + columnLabelHash[orderByColumn];
                    }

                },
                dataFilter: function(data) {

                    /* dataFilter is analagous to the purpose of ajax 'success',
                    but you can't also use 'success' as then dataFilter
                    will not be triggered */

                    // spinner rendered upon page-load
                    // will be cleared after the first
                    // data payload is returned
                    self.hideSpinner();

                    // clear any error messages when data begins to flow again
                    self.clearDataErrorMessage();

                    // runs result through this.dataPrep
                    var result = self.dataPrep(data);

                    // dataTables expects JSON encoded result
                    return JSON.stringify(result);
                },
                error: function(error) {
                    // append error message to '.popup-message'
                    self.dataErrorMessage(null, error);
                },
                // tells dataTable to look for 'result' param of result object
                dataSrc: "result"
            },
            "columnDefs": [{
                "name": "created",
                "type": "date",
                "targets": 0,
                "render": function(data, type, full, meta) {
                    return moment(data).format();
                }
            }, {
                "name": "event_type",
                "targets": 1
            }, {
                "name": "message",
                "targets": 2
            }, {
                "name": "id",
                "targets": 3
            }, {
                "name": "source_id",
                "targets": 4
            }, {
                "name": "source_name",
                "targets": 5
            }, {
                "visible": false,
                "targets": [3, 4, 5]
            }]
        };

        // instantiate dataTable
        oTable = $(location).DataTable(oTableParams);
    },

    render: function() {
        $(this.el).append(this.template());
        this.drawSearchTable('#events-report-table');
        return this;
    },

    template: _.template(

        '
' +
        '
' +
        '
' +
        '
' +
        '
 Events Report' +
        '
' +
        '
' +
        '

' +
        '
' +
        '
' +
        '
' +
        '
' +
        'Created	' +
        'Event Type	' +
        'Message	' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
')
});
<commit_msg>Updates nodeReport page eventsReportView to work with updated api.<commit_after>/**
 * Copyright 2014 - 2015 Solinea, Inc.
 *
 * Licensed under the Solinea Software License Agreement (goldstone),
 * Version 1.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *     http://www.solinea.com/goldstone/LICENSE.pdf
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
This view makes up the "Events" tab of nodeReportView.js
It is sub-classed from GoldstoneBaseView.

Much of the functionality is encompassed by the jQuery
dataTables plugin which is documented at
http://datatables.net/reference/api/

Instantiated on nodeReportView as:

this.eventsReport = new EventsReportView({
    el: '#node-report-panel #eventsReport',
    width: $('#node-report-panel #eventsReport').width(),
    nodeName: hostName,
    globalLookback: ns.globalLookback
});
*/

var EventsReportView = GoldstoneBaseView.extend({

    // initialize empty 'defaults' object that will be used as a container
    // for shared values amongst local functions
    defaults: {},

    urlGen: function() {

        // urlGen is instantiated inside the beforeSend AJAX hook
        // which means it is run again before every dataTables server query

        var now = +new Date();
        // subtracts correct ms from current time
        var lookback = now - (1000 * 60 * this.defaults.globalLookback);

        var urlRouteConstruction = '/logging/events/search?host=' +
            this.defaults.hostName +
            '&@timestamp__range={"gte":' + lookback + ',"lte":' + now + '}';

        // makes a route similar to:
        // /logging/events/search?host=rsrc-01&@timestamp__range={"gte":1426019353333,"lte":1427245753333}

        // this will be added by the dataTables beforeSend section:
        // &page_size=10&page=1&log_message__regexp=.*blah.*

        this.defaults.url = urlRouteConstruction;
    },

    initialize: function(options) {

        EventsReportView.__super__.initialize.apply(this, arguments);
    },

    processOptions: function() {
        EventsReportView.__super__.processOptions.apply(this, arguments);

        this.defaults.hostName = this.options.nodeName;
        this.defaults.globalLookback = this.options.globalLookback;
    },

    processListeners: function() {
        // this is triggered by a listener set on nodeReportView.js
        this.on('lookbackSelectorChanged', function() {

            // set the lookback based on the global selector
            this.defaults.globalLookback = $('#global-lookback-range').val();

            // trigger a redraw of the table
            $('#events-report-table').dataTable().fnDraw();
        });
    },

    processMargins: function() {
        // overwritten so as not to conflict with super-class'
        // method that will calculate irrelevant margins.
        return null;
    },

    standardInit: function() {
        // overwritten so as not to conflict with super-class'
        // method that will calculate irrelevant margins.
        return null;
    },

    dataPrep: function(data) {
        var ns = this.defaults;
        var self = this;

        // initial result is stringified JSON
        var tableData = JSON.parse(data);

        var finalResults = [];

        _.each(tableData.results, function(item) {

            // if any field is undefined, dataTables throws an alert
            // so set to empty string if otherwise undefined
            item['@timestamp'] = item['@timestamp'] || '';
            item.event_type = item.event_type || '';
            item.log_message = item.log_message || '';
            item.syslog_severity = item.syslog_severity || '';
            item.host = item.host || '';
            item.syslog_facility = item.syslog_facility || '';

            finalResults.push([item['@timestamp'], item.event_type, item.log_message, item.syslog_severity, item.host, item.syslog_facility]);
        });

        // total/filtered/result feeds the dataTables
        // item count at the bottom of the table
        return {
            recordsTotal: tableData.count,
            recordsFiltered: tableData.count,
            result: finalResults
        };
    },

    drawSearchTable: function(location) {

        var ns = this.defaults;
        var self = this;

        this.hideSpinner();

        var oTable;

        // Params documented at http://datatables.net/reference/option/
        var oTableParams = {
            "info": true,
            "processing": true,
            "lengthChange": true,
            "paging": true,
            "searching": true,
            "order": [
                [0, 'desc']
            ],
            "ordering": true,
            "serverSide": true,
            "ajax": {
                beforeSend: function(obj, settings) {

                    // warning: as dataTable features are enabled/
                    // disabled , check if the structure of settings.
                    // url changes significantly. Be sure to
                    // reference the correct array indices when
                    // comparing, or scraping data

                    self.urlGen();

                    var pageSize = $(self.el).find('select.form-control').val();
                    var searchQuery = $(self.el).find('input.form-control').val();
                    var paginationStart = settings.url.match(/start=\d{1,}&/gi);
                    paginationStart = paginationStart[0].slice(paginationStart[0].indexOf('=') + 1, paginationStart[0].lastIndexOf('&'));
                    var computeStartPage = Math.floor(paginationStart / pageSize) + 1;
                    var urlColumnOrdering = decodeURIComponent(settings.url).match(/order\[0\]\[column\]=\d*/gi);

                    // capture which column was clicked
                    // and which direction the sort is called for

                    var urlOrderingDirection = decodeURIComponent(settings.url).match(/order\[0\]\[dir\]=(asc|desc)/gi);
                    settings.url = self.defaults.url + "&page_size=" + pageSize + "&page=" + computeStartPage;

                    if (searchQuery) {
                        settings.url = settings.url + "&log_message__regexp=.*" + searchQuery +
                            ".*";
                    }

                    // if no interesting sort, ignore it
                    if (urlColumnOrdering[0] !== "order[0][column]=0" || urlOrderingDirection[0] !== "order[0][dir]=desc") {

                        // or, if something has changed, capture the
                        // column to sort by, and the sort direction

                        var columnLabelHash = {
                            0: '@timestamp',
                            1: 'event_type',
                            2: 'log_message'
                        };

                        var orderByColumn = urlColumnOrdering[0].slice(urlColumnOrdering[0].indexOf('=') + 1);

                        var orderByDirection = urlOrderingDirection[0].slice(urlOrderingDirection[0].indexOf('=') + 1);

                        var ascDec;
                        if (orderByDirection === 'asc') {
                            ascDec = '';
                        } else {
                            ascDec = '-';
                        }

                        settings.url = settings.url + "&ordering=" +
                            ascDec + columnLabelHash[orderByColumn];
                    }

                },
                dataFilter: function(data) {

                    /* dataFilter is analagous to the purpose of ajax 'success',
                    but you can't also use 'success' as then dataFilter
                    will not be triggered */

                    // spinner rendered upon page-load
                    // will be cleared after the first
                    // data payload is returned
                    self.hideSpinner();

                    // clear any error messages when data begins to flow again
                    self.clearDataErrorMessage();

                    // runs result through this.dataPrep
                    var result = self.dataPrep(data);

                    // dataTables expects JSON encoded result
                    return JSON.stringify(result);
                },
                error: function(error) {
                    // append error message to '.popup-message'
                    self.dataErrorMessage(null, error);
                },
                // tells dataTable to look for 'result' param of result object
                dataSrc: "result"
            },
            "columnDefs": [{
                "name": "created",
                "type": "date",
                "targets": 0,
                "render": function(data, type, full, meta) {
                    return moment(data).format();
                }
            }, {
                "name": "event_type",
                "targets": 1
            }, {
                "name": "message",
                "targets": 2
            }, {
                "name": "syslog_severity",
                "targets": 3
            }, {
                "name": "host",
                "targets": 4
            }, {
                "name": "syslog_facility",
                "targets": 5
            }, {
                "visible": false,
                "targets": [3, 4, 5]
            }]
        };

        // instantiate dataTable
        oTable = $(location).DataTable(oTableParams);
    },

    render: function() {
        $(this.el).append(this.template());
        this.drawSearchTable('#events-report-table');
        return this;
    },

    template: _.template(

        '
' +
        '
' +
        '
' +
        '
' +
        '
 Events Report' +
        '
' +
        '
' +
        '

' +
        '
' +
        '
' +
        '
' +
        '
' +
        'Created	' +
        'Event Type	' +
        'Message	' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
')
});
<|endoftext|>