<commit_before>/*
 * Kifu.js
 */
(function(window) {

var _Kifu = window.Kifu;

/*
 * Kifu object
 */
var Kifu = (function(source, format) {
  return new Kifu.initialize(source, format);
});

Kifu.extend = Kifu.prototype.extend = function(source) {
  for (var property in source) {
    this[property] = source[property];
  }
  return this;
}

Kifu.prototype.extend({
  parse: function(format) {
    if (format) {
      this._format = format;
    }
    var klass = Kifu.capitalize(this._format);
    this._kifu = Kifu[klass].parse(this._source);
    console.log(this._kifu);
    return this;
  }
});

Kifu.extend({
  initialize: function(source, format) {
    this._source = Kifu.load(source);
    if (format) {
      this.parse(format);
    }
  },

  ajax: function(url, format, func_obj) {
    jQuery.ajax({
      dataType: 'text',
      type:     'GET',
      url:      url,
      success: function(source) {
        func_obj(Kifu(source, format));
      }
    });
  },

  capitalize: function(str) {
    return str.charAt(0).toUpperCase() + str.substr(1);
  },

  load: function(source) {
    var element = document.getElementById(source);
    if (element) {
      return element.innerHTML;
    } else {
      return source;
    }
  },

  noConflict: function() {
    window.Kifu = _Kifu;
    return Kifu;
  }
});

Kifu.initialize.prototype = Kifu.prototype

/*
 * Kifu.Board Object
 */
Kifu.Board = (function() { return new Kifu.Board.initialize(); });
Kifu.Board.extend = Kifu.Board.prototype.extend = Kifu.extend;

Kifu.Board.prototype.extend({
  get: function(x, y) {
    return this._board[x][y];
  },

  hirate: function() {
    this.set(1, 9, 'KY', true);
    this.set(2, 9, 'KE', true);
    this.set(3, 9, 'GI', true);
    this.set(4, 9, 'KI', true);
    this.set(5, 9, 'OU', true);
    this.set(6, 9, 'KI', true);
    this.set(7, 9, 'GI', true);
    this.set(8, 9, 'KE', true);
    this.set(9, 9, 'KY', true);
    this.set(8, 8, 'KA', true);
    this.set(2, 8, 'HI', true);
    for (i = 1; i <= 9; i++) {
      this.set(i, 7, 'FU', true);
    }

    this.set(1, 1, 'KY', false);
    this.set(2, 1, 'KE', false);
    this.set(3, 1, 'GI', false);
    this.set(4, 1, 'KI', false);
    this.set(5, 1, 'OU', false);
    this.set(6, 1, 'KI', false);
    this.set(7, 1, 'GI', false);
    this.set(8, 1, 'KE', false);
    this.set(9, 1, 'KY', false);
    this.set(2, 2, 'KA', false);
    this.set(8, 2, 'HI', false);
    for (i = 1; i <= 9; i++) {
      this.set(i, 3, 'FU', false);
    }

    return this;
  },

  remove: function(x, y, piece) {
    var p = this._board[x][y]['piece'];
    if (!this.trash(x, y, piece)) {
      return false;
    }
    this._pieces[p] += 1;
    return this;
  },

  set: function(x, y, piece, black) {
    this._board[x][y] = {'black': black, 'piece': piece};
    this._pieces[piece] -= 1;
    return this;
  },

  setStand: function(piece, black) {
    var player = black ? 'black' : 'white';
    if (piece == 'AL') {
      for (var p in this._pieces) {
        if (p == 'OU') {
          continue;
        }
        this._stand[player][p] = this._stand[player][p] || 0;
        this._stand[player][p] += this._pieces[p];
        this._pieces[p] = 0;
      }
    } else {
      this._stand[player][piece] = this._stand[player][piece] || 0;
      this._stand[player][piece] += 1;
      this._pieces[piece] -= 1;
    }
    return this;
  },

  toObject: function() {
    return {
      'board':  this._board,
      'pieces': this._pieces,
      'stand':  this._stand
    };
  },

  trash: function(x, y, piece) {
    if (!piece) {
      piece = this._board[x][y]['piece'];
    }
    if (piece != this._board[x][y]['piece']) {
      return false;
    }

    this._board[x][y] = null;
    return this;
  }
});

Kifu.Board.extend({
  initialize: function() {
    this._board  = Kifu.Board.empty();
    this._pieces = Kifu.Board.pieces();
    this._stand  = {'black': {}, 'white': {}};
  },

  empty: function() {
    var board = {};
    for (var i = 1; i <= 9; i++) {
      board[i] = {}
      for (var j = 1; j <= 9; j++) {
        board[i][j] = null;
      }
    }
    return board;
  },

  pieces: function() {
    return {
      'FU': 18,
      'KY':  4,
      'KE':  4,
      'GI':  4,
      'KI':  4,
      'KA':  2,
      'HI':  2,
      'OU':  2
    };
  }
});

Kifu.Board.initialize.prototype = Kifu.Board.prototype

/*
 * Kifu.Csa Object
 */
Kifu.Csa = {
  parse: function(source) {
    var kifu = {
      'board':  Kifu.Board(),
      'format': 'csa',
      'moves':  Kifu.Move()
    };

    var lines = Kifu.Csa.toLines(source);
    for (var i in lines) {
      var line = lines[i];
      Kifu.Csa.parseByLine(line, kifu);
    }

    var board = kifu['board'].toObject();
    kifu['board']  = board['board'];
    kifu['pieces'] = board['pieces'];
    kifu['stand']  = board['stand'];
    kifu['moves']  = kifu['moves'].toArray();

    return kifu;
  },

  parseByLine: function(line, kifu) {
    if (line == '+') {
      kifu['start_player'] = 'black';
      return true;
    } else if (line == '-') {
      kifu['start_player'] = 'white';
      return true;
    } else if (line.substr(0, 3) == "'* ") {
      kifu['moves'].addComment(line.substr(3));
    }

    switch (line.charAt(0)) {
    case '+':
    case '-':
      var from = [line.charAt(1)-'0', line.charAt(2)-'0'];
      var to   = [line.charAt(3)-'0', line.charAt(4)-'0'];
      var piece = line.substr(5, 2);
      kifu['moves'].addMove(from, to, piece);
      break;

    case 'N':
      var player = (line.charAt(1) == '+' ? 'black' : 'white') + 'Player';
      kifu[player] = line.substr(2);
      return true;

    case 'P':
      switch (line.charAt(1)) {
      case 'I':
        kifu['board'].hirate();
        for (var i = 0; ; i++) {
          var p_info = line.substr(2+i*4, 4);
          if (p_info.length < 4) {
            break;
          }
          var x     = p_info.charAt(0) - '0';
          var y     = p_info.charAt(1) - '0';
          var piece = p_info.substr(2);
          kifu['board'].trash(x, y, piece);
        }
        return true;

      case '+':
      case '-':
        var black = line.charAt(1) == '+';
        for (var i = 0; ; i++) {
          var p_info = line.substr(2+i*4, 4);
          if (p_info.length < 4) {
            break;
          }
          var x     = p_info.charAt(0) - '0';
          var y     = p_info.charAt(1) - '0';
          var piece = p_info.substr(2);
          if (x == 0 && y == 0) {
            kifu['board'].setStand(piece, black);
          } else {
            kifu['board'].set(x, y, piece, black);
          }
        }
        return true;

      default:
        var y = line.charAt(1) - '0';
        if (y < 1 || 9 < y) {
          return false;
        }
        for (var i = 0; i < 9; i++) {
          var p_info = line.substr(2+i*3, 3);
          switch (p_info.charAt(0)) {
          case '+':
            var black = true;
            break;
          case '-':
            var black = false;
            break;
          default:
            continue;
          }
          var x     = 9 - i;
          var piece = p_info.substr(1, 2);
          kifu['board'].set(x, y, piece, black);
        }
        return true;
      }
      return false;

    case 'T':
      var period = parseInt(line.substr(1));
      kifu['moves'].addPeriod(period);
      break;

    case 'V':
      kifu['version'] = line.substr(1);
      return true;
    }

    return false;
  },

  toLines: function(source) {
    var lines = source.split("\r\n");
    if (lines.length > 1) {
      return lines;
    }

    lines = source.split("\n");
    if (lines.length > 1) {
      return lines;
    }

    return source.split("\r");
  }
};

/*
 * Kifu.Move Object
 */
Kifu.Move = (function() { return new Kifu.Move.initialize(); });
Kifu.Move.extend = Kifu.Move.prototype.extend = Kifu.extend;

Kifu.Move.prototype.extend({
  addComment: function(comment) {
    this._moves[this._moves.length-1]['comment'] = comment;
    return this;
  },

  addMove: function(from, to, piece) {
    var move = this._moves[this._moves.length-1];
    if (move['piece']) {
      this._moves.push({});
      move = this._moves[this._moves.length-1];
    }

    move['from']  = from;
    move['to']    = to;
    move['piece'] = piece;
    return this;
  },

  addPeriod: function(period) {
    this._moves[this._moves.length-1]['period'] = period;
    return this;
  },

  toArray: function() {
    return this._moves;
  }
});

Kifu.Move.extend({
  initialize: function() {
    this._moves = [{}];
  }
});

Kifu.Move.initialize.prototype = Kifu.Move.prototype

window.Kifu = Kifu;
})(window);

/* vim: set expandtab tabstop=2 shiftwidth=2 softtabstop=2: */
<commit_msg>fixed a bit<commit_after>/*
 * Kifu.js
 */
(function(window) {

var _Kifu = window.Kifu;

/*
 * Kifu object
 */
var Kifu = (function(source, format) {
  return new Kifu.initialize(source, format);
});

Kifu.extend = Kifu.prototype.extend = function(source) {
  for (var property in source) {
    this[property] = source[property];
  }
  return this;
}

Kifu.prototype.extend({
  parse: function(format) {
    if (format) {
      this._format = format;
    }
    var klass = Kifu.capitalize(this._format);
    this._kifu = Kifu[klass].parse(this._source);
    console.log(this._kifu);
    return this;
  }
});

Kifu.extend({
  initialize: function(source, format) {
    this._source = Kifu.load(source);
    if (format) {
      this.parse(format);
    }
  },

  ajax: function(url, format, func_obj) {
    jQuery.ajax({
      dataType: 'text',
      type:     'GET',
      url:      url,
      success: function(source) {
        func_obj(Kifu(source, format));
      }
    });
  },

  capitalize: function(str) {
    return str.charAt(0).toUpperCase() + str.substr(1);
  },

  load: function(source) {
    var element = document.getElementById(source);
    if (element) {
      return element.innerHTML;
    } else {
      return source;
    }
  },

  noConflict: function() {
    window.Kifu = _Kifu;
    return Kifu;
  }
});

Kifu.initialize.prototype = Kifu.prototype

/*
 * Kifu.Board Object
 */
Kifu.Board = (function() { return new Kifu.Board.initialize(); });
Kifu.Board.extend = Kifu.Board.prototype.extend = Kifu.extend;

Kifu.Board.prototype.extend({
  get: function(x, y) {
    return this._board[x][y];
  },

  hirate: function() {
    this.set(1, 9, 'KY', true);
    this.set(2, 9, 'KE', true);
    this.set(3, 9, 'GI', true);
    this.set(4, 9, 'KI', true);
    this.set(5, 9, 'OU', true);
    this.set(6, 9, 'KI', true);
    this.set(7, 9, 'GI', true);
    this.set(8, 9, 'KE', true);
    this.set(9, 9, 'KY', true);
    this.set(8, 8, 'KA', true);
    this.set(2, 8, 'HI', true);
    for (i = 1; i <= 9; i++) {
      this.set(i, 7, 'FU', true);
    }

    this.set(1, 1, 'KY', false);
    this.set(2, 1, 'KE', false);
    this.set(3, 1, 'GI', false);
    this.set(4, 1, 'KI', false);
    this.set(5, 1, 'OU', false);
    this.set(6, 1, 'KI', false);
    this.set(7, 1, 'GI', false);
    this.set(8, 1, 'KE', false);
    this.set(9, 1, 'KY', false);
    this.set(2, 2, 'KA', false);
    this.set(8, 2, 'HI', false);
    for (i = 1; i <= 9; i++) {
      this.set(i, 3, 'FU', false);
    }

    return this;
  },

  remove: function(x, y, piece) {
    var p = this._board[x][y]['piece'];
    if (!this.trash(x, y, piece)) {
      return false;
    }
    this._pieces[p] += 1;
    return this;
  },

  set: function(x, y, piece, black) {
    this._board[x][y] = {'black': black, 'piece': piece};
    this._pieces[piece] -= 1;
    return this;
  },

  setStand: function(piece, black) {
    var player = black ? 'black' : 'white';
    if (piece == 'AL') {
      for (var p in this._pieces) {
        if (p == 'OU') {
          continue;
        }
        this._stand[player][p] = this._stand[player][p] || 0;
        this._stand[player][p] += this._pieces[p];
        this._pieces[p] = 0;
      }
    } else {
      this._stand[player][piece] = this._stand[player][piece] || 0;
      this._stand[player][piece] += 1;
      this._pieces[piece] -= 1;
    }
    return this;
  },

  toObject: function() {
    return {
      'board':  this._board,
      'pieces': this._pieces,
      'stand':  this._stand
    };
  },

  trash: function(x, y, piece) {
    if (!piece) {
      piece = this._board[x][y]['piece'];
    }
    if (piece != this._board[x][y]['piece']) {
      return false;
    }

    this._board[x][y] = null;
    return this;
  }
});

Kifu.Board.extend({
  initialize: function() {
    this._board  = Kifu.Board.empty();
    this._pieces = Kifu.Board.pieces();
    this._stand  = {'black': {}, 'white': {}};
  },

  empty: function() {
    var board = {};
    for (var i = 1; i <= 9; i++) {
      board[i] = {}
      for (var j = 1; j <= 9; j++) {
        board[i][j] = null;
      }
    }
    return board;
  },

  pieces: function() {
    return {
      'FU': 18,
      'KY':  4,
      'KE':  4,
      'GI':  4,
      'KI':  4,
      'KA':  2,
      'HI':  2,
      'OU':  2
    };
  }
});

Kifu.Board.initialize.prototype = Kifu.Board.prototype

/*
 * Kifu.Csa Object
 */
Kifu.Csa = {
  parse: function(source) {
    var kifu = {
      'board':  Kifu.Board(),
      'format': 'csa',
      'moves':  Kifu.Move()
    };

    var lines = Kifu.Csa.toLines(source);
    for (var i in lines) {
      var line = lines[i];
      Kifu.Csa.parseByLine(line, kifu);
    }

    var board = kifu['board'].toObject();
    kifu['board']  = board['board'];
    kifu['pieces'] = board['pieces'];
    kifu['stand']  = board['stand'];
    kifu['moves']  = kifu['moves'].toArray();

    return kifu;
  },

  parseByLine: function(line, kifu) {
    if (line == '+') {
      kifu['start_player'] = 'black';
      return true;
    } else if (line == '-') {
      kifu['start_player'] = 'white';
      return true;
    } else if (line.substr(0, 3) == "'* ") {
      kifu['moves'].addComment(line.substr(3));
    }

    switch (line.charAt(0)) {
    case '+':
    case '-':
      var from = [line.charAt(1)-'0', line.charAt(2)-'0'];
      var to   = [line.charAt(3)-'0', line.charAt(4)-'0'];
      var piece = line.substr(5, 2);
      kifu['moves'].addMove(from, to, piece);
      break;

    case 'N':
      var player = (line.charAt(1) == '+' ? 'black' : 'white') + '_player';
      kifu[player] = line.substr(2);
      return true;

    case 'P':
      switch (line.charAt(1)) {
      case 'I':
        kifu['board'].hirate();
        for (var i = 0; ; i++) {
          var p_info = line.substr(2+i*4, 4);
          if (p_info.length < 4) {
            break;
          }
          var x     = p_info.charAt(0) - '0';
          var y     = p_info.charAt(1) - '0';
          var piece = p_info.substr(2);
          kifu['board'].trash(x, y, piece);
        }
        return true;

      case '+':
      case '-':
        var black = line.charAt(1) == '+';
        for (var i = 0; ; i++) {
          var p_info = line.substr(2+i*4, 4);
          if (p_info.length < 4) {
            break;
          }
          var x     = p_info.charAt(0) - '0';
          var y     = p_info.charAt(1) - '0';
          var piece = p_info.substr(2);
          if (x == 0 && y == 0) {
            kifu['board'].setStand(piece, black);
          } else {
            kifu['board'].set(x, y, piece, black);
          }
        }
        return true;

      default:
        var y = line.charAt(1) - '0';
        if (y < 1 || 9 < y) {
          return false;
        }
        for (var i = 0; i < 9; i++) {
          var p_info = line.substr(2+i*3, 3);
          switch (p_info.charAt(0)) {
          case '+':
            var black = true;
            break;
          case '-':
            var black = false;
            break;
          default:
            continue;
          }
          var x     = 9 - i;
          var piece = p_info.substr(1, 2);
          kifu['board'].set(x, y, piece, black);
        }
        return true;
      }
      return false;

    case 'T':
      var period = parseInt(line.substr(1));
      kifu['moves'].addPeriod(period);
      break;

    case 'V':
      kifu['version'] = line.substr(1);
      return true;
    }

    return false;
  },

  toLines: function(source) {
    var lines = source.split("\r\n");
    if (lines.length > 1) {
      return lines;
    }

    lines = source.split("\n");
    if (lines.length > 1) {
      return lines;
    }

    return source.split("\r");
  }
};

/*
 * Kifu.Move Object
 */
Kifu.Move = (function() { return new Kifu.Move.initialize(); });
Kifu.Move.extend = Kifu.Move.prototype.extend = Kifu.extend;

Kifu.Move.prototype.extend({
  addComment: function(comment) {
    this._moves[this._moves.length-1]['comment'] = comment;
    return this;
  },

  addMove: function(from, to, piece) {
    var move = this._moves[this._moves.length-1];
    if (move['piece']) {
      this._moves.push({});
      move = this._moves[this._moves.length-1];
    }

    move['from']  = from;
    move['to']    = to;
    move['piece'] = piece;
    return this;
  },

  addPeriod: function(period) {
    this._moves[this._moves.length-1]['period'] = period;
    return this;
  },

  toArray: function() {
    return this._moves;
  }
});

Kifu.Move.extend({
  initialize: function() {
    this._moves = [{}];
  }
});

Kifu.Move.initialize.prototype = Kifu.Move.prototype

window.Kifu = Kifu;
})(window);

/* vim: set expandtab tabstop=2 shiftwidth=2 softtabstop=2: */
<|endoftext|>


<commit_before>(function(global, engine) {
    if(typeof module === "object" && typeof module.exports === "object") {
        module.exports = global.document ? engine(global.jQuery, true) :
            function() {
                var cheerio = require('cheerio');
                cheerio.fs = require('fs');
                if(!cheerio) {
                    throw new Error('Lace requires cheerio installed.')
                }
                return engine(cheerio, undefined, true);
            }();
    } else {
        //this 'else' block will render in browser end
        if(!global.jQuery) {
            throw new Error('Lace requires jQuery loaded.')
        }
        engine(global.jQuery);
    }
// Pass this if window is not defined yet
}(typeof window === "undefined" ? this : window, function($, noGlobal, isServer) {

    'use strict';

    var
        lace,

        version = '1.0.0',

        type = {
            undefined: typeof undefined,
            object: typeof {},
            func: typeof function() {
            },
            string: typeof "",
            number: typeof 0
        },

        defaults = {},

        warehouse = {
            //singleton lace for browser end
            singleton: null,
            compiled_dom: null,
            taglets: {},
            scriptlets: {}
        }

    ;

    var Node = function() {
        this.parent = parent;
        this.children = [];
        this.taglet = undefined;
        this.annotations = [];
        this.scope = undefined;
    };

    Node.prototype = {
        __lace__ : {
            compiledElement: undefined
        },
        compiledElement: function() {
            return this.__lace__.compiledElement;
        }
    };

    var Scope = function() {
        this.parent = parent;
    };

    Scope.prototype = {

    };

    var Lace = function() {
    };

    Lace.prototype = {

        version: version,

        constructor: Lace,

        __lace__: {

        },

        compile: function() {

        },

        render: function(html, data) {

        },

        taglet: function(name, def, extend) {
            /* only support object type def of taglet
             TODO: initialize support for function type def */
            if(def == 'extend') {
                //TODO: implement to extend existing taglet with arg extend
            }
            if(typeof def === type.object) {
                warehouse.taglets[name] = new Taglet(name, def);
            }
            return warehouse.taglets[name];
        },

        annotation: function(name, def) {
            if(def === 'extend') {
                //TODO:
            }
            if(typeof def == type.object) {
                warehouse.annotations[name] = new Annotation(name, def);
            }
            return warehouse.annotations[name];
        },

        scriptlet: function(name, def) {

        }

    };

    var Taglet = function(name, def) {
        this.name = name;
        this.__lace__.template = def.template;
    };

    Taglet.prototype = {

        constructor: Taglet,

        __lace__: {
            template: undefined
        },

        compile: function() {
            var self = this;
            self.resolveTemplate();
            $(self.__lace__.template)
        },

        render: function(data) {
            var self = this;
            if(typeof self.__lace__.template === type.undefined) {
                self.compile();
            }
        },

        resolveTemplate: function() {
            var self = this;
            if(typeof self.template === type.string) {
                //TODO: implement for inline template
                return;
            }
            if(!self.template instanceof Array) {
                throw new Error('Template should be inline or array of file paths');
            }
            for(var filepath in self.template) {
                Lace.load(filepath, function(content) {
                    self.template += content;
                });
            }
        }

    };

    var Annotation = function(name, def) {
        this.name = name;
        this.def = def;
    };

    Annotation.prototype = {

        constructor: Annotation,

        key: function() {
            //return annotation key
        },

        val: function() {
            //return current scope value
        },

        compile: function() {

        },

        execute: function(data, annotations, taglet, scope) {
            if(typeof this.def.execute === type.func) {
                this.def.execute(data, annotations, taglet, scope)
            }
        }

    };

    var Scriptlet = function(name, def) {
        this.name = name;
    };

    Scriptlet.prototype = {

        constructor: Scriptlet,

        compile: function() {

        },

        execute: function() {

        }

    };

    Lace.load = function(filepath, callback) {
        if(isServer) {
            $.fs.readFile(filepath, function(err, bytes) {
                if(err) throw err;
                callback(bytes.toString());
            })
        }
        //TODO: implement ajax loading of remote templates
    };

    lace = function() {
        return warehouse.singleton;
    };

    /**
     * initializing lace itself
     * */
    (function() {

        var lace = warehouse.singleton = new Lace();

        lace.taglet('let', {});

        lace.annotation('for', {
            compile: function($el) {

            },
            execute: function(annotation, taglet, scope) {
                if(typeof data )
            }
        })

    })();

    if(typeof noGlobal === type.undefined) {
        window.lace = lace;
    }

    return lace;

}));<commit_msg>lot of modifications<commit_after>(function(global, engine) {
    if(typeof module === "object" && typeof module.exports === "object") {
        module.exports = global.document ? engine(global.jQuery, true) :
            function() {
                var cheerio = require('cheerio');
                cheerio.fs = require('fs');
                if(!cheerio) {
                    throw new Error('Lace requires cheerio installed.')
                }
                return engine(cheerio, undefined, true);
            }();
    } else {
        //this 'else' block will render in browser end
        if(!global.jQuery) {
            throw new Error('Lace requires jQuery loaded.')
        }
        engine(global.jQuery);
    }
// Pass this if window is not defined yet
}(typeof window === "undefined" ? this : window, function($, noGlobal, isServer) {

    'use strict';

    var
        lace,

        version = '1.0.0',

        type = {
            undefined: typeof undefined,
            object: typeof {},
            func: typeof function() {
            },
            string: typeof "",
            number: typeof 0
        },

        defaults = {
            opts: {
                scriptlet: {
                    startWith: '${',
                    endWith: '}'
                }
            }
        },

        warehouse = {
            //singleton lace for browser end
            singleton: null,
            compiled_dom: null,
            taglets: {},
            scriptlets: {}
        },

        defs = {

        }

    ;

    var Scope = function(parent, current) {
        this.parent = parent;
        this.current = current;
    };

    Scope.prototype = {

        constructor: Scope,

        current: function() {

        },

        parent: function() {

        }

    };

    var Lace = function() {
        var root_scope = new Scope({});

    };

    Lace.prototype = {

        version: version,

        constructor: Lace,

        __lace__: {
            definitions: {
                annotations: {},
                scriptlets: {},
                taglets: {}
            },
            instances: {
                annotations: {},
                scriptlets: {},
                taglets: {}
            }
        },

        annotation: function(name, def) {
            if(def === 'extend') {
                //TODO:
            }
            if(typeof def === type.object) {
                this.__lace__.definitions.annotations[name] = def;
            }
            return this.__lace__.instances.annotations[name];
        },

        scriptlet: function(name, def, extend) {
            /* only support object type def of taglet
             TODO: initialize support for function type def */
            if(def == 'extend') {
                //TODO: implement to extend existing taglet with arg extend
            }
            if(typeof def === type.object) {
                this.__lace__.definitions.scriptlets[name] = def;
            }
            return this.__lace__.instances.scriptlets[name];
        },

        taglet: function(name, def, extend) {
            /* only support object type def of taglet
             TODO: initialize support for function type def */
            if(def == 'extend') {
                //TODO: implement to extend existing taglet with arg extend
            }
            if(typeof def === type.object) {
                this.__lace__.definitions.taglets[name] = def;
            }
            return this.__lace__.instances.taglets[name];
        },

        compile: function() {

        },

        render: function(html, data) {

        }

    };

    var Annotation = function(name, value) {
        this.name = name;
        this.value = value;
    };

    Annotation.prototype = {

        constructor: Annotation,

        key: function() {
            //return annotation key
        },

        val: function() {
            //return current scope value
        },

        compile: function() {

        },

        execute: function() {
            if(typeof this.def.execute === type.func) {

            }
        }

    };

    var Scriptlet = function(name) {
        this.name = name;
        this.scriptlets = []; //support inner scriptlets
    };

    Scriptlet.prototype = {

        constructor: Scriptlet,

        compile: function() {

        },

        execute: function() {

        }

    };

    var Taglet = function(name) {
        this.name = name;
        this.annotations = {};
        this.children = [];
    };

    Taglet.prototype = {

        constructor: Taglet,

        __lace__: {
            template: undefined
        },

        compile: function() {
            var self = this;
            self.resolveTemplate();
            $(self.__lace__.template)
        },

        render: function(data) {
            var self = this;
            if(typeof self.__lace__.template === type.undefined) {
                self.compile();
            }
        },

        resolveTemplate: function() {
            var def = lace;
            if(typeof self.__lace__.template === type.string) {
                //TODO: implement for inline template
                return;
            }
            if(!self.template instanceof Array) {
                throw new Error('Template should be inline or array of file paths');
            }
            for(var filepath in self.template) {
                Lace.load(filepath, function(content) {
                    self.template += content;
                });
            }
        }

    };

    Lace.load = function(filepath, callback) {
        if(isServer) {
            $.fs.readFile(filepath, function(err, bytes) {
                if(err) throw err;
                callback(bytes.toString());
            })
        }
        //TODO: implement ajax loading of remote templates
    };

    Lace.isScriptlet = function(target) {
        //TODO: implement pointing defaults to resolved
        return target.indexOf(defaults.opts.scriptlet.startWith) == 0
            && target.indexOf(defaults.opts.scriptlet.endWith) == target.length - defaults.opts.scriptlet.endWith.length
    };

    Lace.pickScriptlet = function(target) {
        var startIdx = target.indexOf(defaults.opts.scriptlet.startWith);
        if(startIdx > -1) {

        }
    };

    lace = function() {
        return warehouse.singleton;
    };

    /**
     * initializing lace itself
     * */
    (function() {

        var lace = warehouse.singleton = new Lace();

        lace.annotation('for', {
            compile: function($el) {

            },
            execute: function() {
                //if(typeof data )
            }
        });

        lace.scriptlet('.', {
            execute: function(idx, arr, raw) {
                lace.scope()[arr[idx-1]][arr[idx+1]]
            }
        });

        lace.taglet('let', {});
    })();

    if(typeof noGlobal === type.undefined) {
        window.lace = lace;
    }

    return lace;

}));<|endoftext|>


<commit_before>/**
 * A base implementation of a linear feedback shift register (LFSR).
 *
 * @class
 *
 * @example Setting an integer seed
 *   var lfsr = new LFSR(3, [3, 2], 6)
 *   console.log(lfsr.current_state, lfsr.current_state.toString(2))
 *   //=> 6, "110"
 *
 * @example Setting a binary seed
 *   var lfsr = new LFSR(3, [3, 2], "110")
 *   console.log(lfsr.current_state, lfsr.current_state.toString(2))
 *   //=> 6, "110"
 *
 * @see https://en.wikipedia.org/wiki/Linear_feedback_shift_register
 * @see http://www.newwaveinstruments.com/resources/articles/m_sequence_linear_feedback_shift_register_lfsr.htm
 */
class LFSR {
  /**
   * @param {number} m - number of taps in the register
   * @param {number[]} [feedback_taps=[1]] - indices of taps that affect the
   *   output (range 1..m inclusive)
   * @param {(number|string)} [seed=1] - starting value for the generator
   */
  constructor(m=1, feedback_taps=[1], seed=1) {
    if (typeof m !== 'number') throw new TypeError('m must be Number')

    // Make sure the entire `m` sequence can be stored in a `Number` even if
    // `feedback_taps` is configured to generate an m-sequence.
    this.m = m
    if (m < 1 || this.maximum_sequence_length > Number.MAX_SAFE_INTEGER) {
      const max_m = ~~(Math.sqrt(Number.MAX_SAFE_INTEGER))
      throw new TypeError(`m must be in the range 1..${max_m} (inclusive)`)
    }

    if (typeof feedback_taps.length === 'undefined') {
      throw new TypeError('feedback_taps must be null or Array')
    }
    // Handle empty array.
    if (!feedback_taps.length) feedback_taps = [1]
    this.feedback_taps = feedback_taps

    if (seed && typeof seed !== 'number' && typeof seed !== 'string') {
      throw new TypeError('seed must be null, Number, or String')
    }
    this.provided_seed = seed
    this.current_state = this.seed
  }

  /**
   * @private
   */
  next() {
    throw new Error('`next` must be implemented by subclasses')
  }

  /**
   * LFSRs have a maximum of `2**m` states. One of those is fairly useless: if
   * seeded with all `0`s, the LFSR will never transition to any other state.
   * However, LFSR can never transition *into* that state, so the maximum
   * sequence length is `2**m - 1`.
   *
   * @return {number} the largest possible number of states for the given `m`
   */
  get maximum_sequence_length() {
    // const max_length = Math.pow(2, this.m) - 1
    // delete this.maximum_sequence_length
    // return this.maximum_sequence_length = max_length
    return Math.pow(2, this.m) - 1
  }

  /**
   * Validates the user's seed and sets a fallback value.
   *
   * @return {number} the validated seed value
   */
  get seed() {
    let bitstring = this.provided_seed

    // Coerce numbers to bitstrings to simplify length sanitization.
    if (typeof bitstring === 'number') bitstring = bitstring.toString(2)

    // Ensure the seed is at most `m` bits long.
    bitstring = bitstring.slice(-this.m)
    // Convert back to a number.
    const seed = parseInt(bitstring, 2)

    // delete this.seed
    // return this.seed = seed
    return seed
  }

  /**
   * Converts the list of tap indices into a corresponding bitmask.
   *
   * @param {number[]} feedback_taps - indices to use as feedback taps
   * @return {number} bitmask of all `m` taps, with a `1` for active taps
   * @private
   *
   * @todo XXX Need to handle Fibonacci vs Galois taps.
   */
  get feedback_tap_mask() {
    const taps = this.feedback_taps

    // Reject any indices outside the range `1..m`.
    const valid = taps.filter((tap_j) => tap_j > 0 && tap_j <= m)

    // `1 << tap_j - 1` makes a one followed by `tap_j - 1` zeroes; that value
    // is then ORed with `mask`, which sets bit `tap_j - 1` of `mask` to `1`.
    let mask = valid.reduce((memo, tap_j) => memo | (1 << tap_j - 1),
                            0)

    // delete this.mask
    // return this.mask = mask
    return mask
  }
}

export default LFSR
<commit_msg>Improved logic and added caching for feedback taps<commit_after>import 'babel-polyfill'

/**
 * Filter an array to unique items.
 *
 * @param {array} array - the array to process
 * @return {array} the unique items in `array`
 * @private
 */
function uniq(array) {
  if (typeof array.length === 'undefined') return []

  const seen = []
  const unique = []

  for (let item of array) {
    if (seen.indexOf(item) === -1) unique.push(item)
    seen.push(item)
  }

  return unique
}

/**
 * A base implementation of a linear feedback shift register (LFSR).
 *
 * @class
 *
 * @example Setting an integer seed
 *   var lfsr = new LFSR(3, [3, 2], 6)
 *   console.log(lfsr.current_state, lfsr.current_state.toString(2))
 *   //=> 6, "110"
 *
 * @example Setting a binary seed
 *   var lfsr = new LFSR(3, [3, 2], "110")
 *   console.log(lfsr.current_state, lfsr.current_state.toString(2))
 *   //=> 6, "110"
 *
 * @see https://en.wikipedia.org/wiki/Linear_feedback_shift_register
 * @see http://www.newwaveinstruments.com/resources/articles/m_sequence_linear_feedback_shift_register_lfsr.htm
 */
class LFSR {
  /**
   * @param {number} m - number of taps in the register
   * @param {number[]} [feedback_taps=[1]] - indices of taps that affect the
   *   output (range 1..m inclusive)
   * @param {(number|string)} [seed=1] - starting value for the generator
   */
  constructor(m=1, feedback_taps=[1], seed=1) {
    if (typeof m !== 'number') throw new TypeError('m must be Number')

    // Make sure the entire `m` sequence can be stored in a `Number` even if
    // `feedback_taps` is configured to generate an m-sequence.
    this.m = m
    if (m < 1 || this.maximum_sequence_length > Number.MAX_SAFE_INTEGER) {
      const max_m = ~~(Math.sqrt(Number.MAX_SAFE_INTEGER))
      throw new TypeError(`m must be in the range 1..${max_m} (inclusive)`)
    }

    if (typeof feedback_taps.length === 'undefined') {
      throw new TypeError('feedback_taps must be null or Array')
    }
    // Handle empty array.
    if (!feedback_taps.length) feedback_taps = [1]
    this.feedback_taps = feedback_taps

    if (seed && typeof seed !== 'number' && typeof seed !== 'string') {
      throw new TypeError('seed must be null, Number, or String')
    }
    this.provided_seed = seed
    this.current_state = this.seed
  }

  /**
   * @private
   */
  next() {
    throw new Error('`next` must be implemented by subclasses')
  }

  /**
   * LFSRs have a maximum of `2**m` states. One of those is fairly useless: if
   * seeded with all `0`s, the LFSR will never transition to any other state.
   * However, LFSR can never transition *into* that state, so the maximum
   * sequence length is `2**m - 1`.
   *
   * @return {number} the largest possible number of states for the given `m`
   */
  get maximum_sequence_length() {
    // const max_length = Math.pow(2, this.m) - 1
    // delete this.maximum_sequence_length
    // return this.maximum_sequence_length = max_length
    return Math.pow(2, this.m) - 1
  }

  /**
   * Validates the user's seed and sets a fallback value.
   *
   * @return {number} the validated seed value
   */
  get seed() {
    let bitstring = this.provided_seed

    // Coerce numbers to bitstrings to simplify length sanitization.
    if (typeof bitstring === 'number') bitstring = bitstring.toString(2)

    // Ensure the seed is at most `m` bits long.
    bitstring = bitstring.slice(-this.m)
    // Convert back to a number.
    const seed = parseInt(bitstring, 2)

    // delete this.seed
    // return this.seed = seed
    return seed
  }

  /**
   * Validate and process feedback tap indices.
   *
   * @return {array} the sanitized tap indices
   * @private
   */
  get sanitized_feedback_taps() {
    if (this._sanitized_feedback_taps) return this._sanitized_feedback_taps

    const taps = this.feedback_taps
    const unique = uniq(taps)

    // Reject any indices outside the range `1..m`.
    const valid = unique.filter((tap_j) => tap_j > 0 && tap_j <= this.m)

    this._sanitized_feedback_taps = valid
    return valid
  }

  /**
   * Converts the list of tap indices into a corresponding bitmask.
   *
   * @return {number} bitmask of all `m` taps, with a `1` for active taps
   * @private
   */
  get feedback_tap_mask() {
    if (this._feedback_tap_mask) return this._feedback_tap_mask

    const taps = this.sanitized_feedback_taps

    // `1 << tap_j - 1` makes a one followed by `tap_j - 1` zeroes; that value
    // is then ORed with `mask`, which sets bit `tap_j - 1` of `mask` to `1`.
    let mask = taps.reduce((memo, tap_j) => memo | (1 << tap_j - 1),
                           0)

    this._feedback_tap_mask = mask
    return mask
  }
}

export default LFSR
<|endoftext|>


<commit_before>'use strict';

var util = require('./util');

/**
 * FKit treats both arrays and strings as *lists*: an array is a list of
 * elements, and a string is a list of characters.
 *
 * Representing strings as lists may be a novel concept for some JavaScript
 * users, but it is quite common in other languages. This seemingly simple
 * abstractions yields a great deal of power: it allows you to apply the same
 * list combinators to both arrays and strings.
 *
 * @summary Working with Lists
 *
 * @module fkit/list
 * @mixes module:fkit/list/base
 * @mixes module:fkit/list/build
 * @mixes module:fkit/list/fold
 * @mixes module:fkit/list/map
 * @mixes module:fkit/list/search
 * @mixes module:fkit/list/set
 * @mixes module:fkit/list/sublist
 * @mixes module:fkit/list/zip
 * @author Josh Bassett
 */
module.exports = util.extend({}, [
  require('./list/base'),
  require('./list/build'),
  require('./list/fold'),
  require('./list/map'),
  require('./list/search'),
  require('./list/set'),
  require('./list/sublist'),
  require('./list/zip'),
]);
<commit_msg>Fix an issue where the sort function weren't included in the fkit module.<commit_after>'use strict';

var util = require('./util');

/**
 * FKit treats both arrays and strings as *lists*: an array is a list of
 * elements, and a string is a list of characters.
 *
 * Representing strings as lists may be a novel concept for some JavaScript
 * users, but it is quite common in other languages. This seemingly simple
 * abstractions yields a great deal of power: it allows you to apply the same
 * list combinators to both arrays and strings.
 *
 * @summary Working with Lists
 *
 * @module fkit/list
 * @mixes module:fkit/list/base
 * @mixes module:fkit/list/build
 * @mixes module:fkit/list/fold
 * @mixes module:fkit/list/map
 * @mixes module:fkit/list/search
 * @mixes module:fkit/list/set
 * @mixes module:fkit/list/sort
 * @mixes module:fkit/list/sublist
 * @mixes module:fkit/list/zip
 * @author Josh Bassett
 */
module.exports = util.extend({}, [
  require('./list/base'),
  require('./list/build'),
  require('./list/fold'),
  require('./list/map'),
  require('./list/search'),
  require('./list/set'),
  require('./list/sort'),
  require('./list/sublist'),
  require('./list/zip'),
]);
<|endoftext|>


<commit_before>/**
 * @file key-cache
 * @author xiaowu
 * @email fe.xiaowu@gmail.com
 */

import {existsSync, writeFileSync, readFileSync, unlinkSync} from 'fs';
import {mkdirsSync, emptyDirSync} from 'fs-extra';
import {resolve} from 'path';
import {createHash} from 'crypto';

export default class KeyCache {
    static options = {
        /**
         * 缓存目录，路径基于当前运行目录
         *
         * @default 安装包里 dirname + .cache
         * @type {String}
         */
        dir: resolve(__dirname, '..', '.cache'),

        /**
         * 保存的时间，单位秒，如果是null则表示一直保存
         *
         * @default null
         * @type {Number|null}
         */
        timeout: null,

        /**
         * 是否使用md5命名缓存文件
         *
         * @default true
         * @type {Boolean}
         */
        md5key: true
    }

    constructor(options = {}) {
        // 合并默认配置
        this.options = {...KeyCache.options, ...options};

        // 解析路径
        this.options.dir = resolve(this.options.dir);

        // 创建缓存目录
        mkdirsSync(this.options.dir);
    }

    /**
     * 设置缓存
     *
     * @param {string} key   key
     * @param {Object|string} value 值
     * @param {Object|undefined} options 可选配置
     * @return {Object} this
     */
    set(key, value, options = {}) {
        if (!key  || 'string' !== typeof key || value === undefined) {
            return this;
        }

        options = {...this.options, ...options};

        let data = {
            __time: null,
            __result: value
        };

        // 如果有过期时间则记录，否则忽略
        if (options.timeout !== null) {
            data.__time = Date.now();
            data.__end = options.timeout;
        }

        // 如果配置的缓存目录不是初始的则创建该目录，防止出错
        if (options.dir !== this.options.dir) {
            mkdirsSync(options.dir);
        }

        // 写入缓存
        writeFileSync(this._getFilePath(key, options), JSON.stringify(data));

        return this;
    }

    /**
     * 获取缓存文件路径
     *
     * @private
     * @param  {string} key key
     * @param {Object|undefined} options 配置参数，如果为空则调用this.options
     *
     * @return {string}     文件绝对路径
     */
    _getFilePath(key, options) {
        let filename;

        options = options || this.options;

        if (options.md5key) {
            let md5 = createHash('md5');
            // unescape encodeURIComponent 兼容中文 md5
            md5.update(unescape(encodeURIComponent(key)));

            filename = md5.digest('hex');
        }
        else {
            // 把文件名中的:替换为空
            filename = String(key).replace(/[^\u4e00-\u9fa5a-zA-Z\_\-0-9]/g, '');

            // 如果替换后为空则使用md5
            if (!filename) {
                return this._getFilePath(key, {...options, ...{md5key: true}});
            }
        }

        return  resolve(options.dir, filename + '.json');
    }

    /**
     * 获取缓存
     *
     * @param  {string} key key
     *
     * @return {Object|string|null}     结果，如果没有找到或者过期则为null
     */
    get(key) {
        let filepath = this._getFilePath(key);

        // 如果文件不存在
        if (!existsSync(filepath)) {
            return null;
        }

        let filedata = readFileSync(filepath).toString();

        try {
            filedata = JSON.parse(filedata);
        }
        catch (e) {
            return null;
        }

        // 如果没有时间就不是key-cache设置的，则忽略
        if (filedata.__time === undefined) {
            return null;
        }

        // 如果设置了时间并且过期了
        // 则删除这个缓存文件
        if (filedata.__time !== null && Date.now() - filedata.__time > filedata.__end * 1000) {
            this.remove(key);
            return null;
        }

        // 如果为undefined则返回null，因为值是fn时不会被JSON.stringify解析
        return filedata.__result !== undefined ? filedata.__result : null;
    }

    /**
     * 删除缓存
     *
     * @param  {string|undefined} key key，如果为空则全部删除
     *
     * @return {Object}     this
     */
    remove(key) {
        // 如果没有key则说明全部删除
        if (!key) {
            emptyDirSync(this.options.dir);
            return this;
        }

        let filepath = this._getFilePath(key);

        // 如果文件不存在
        if (!existsSync(filepath)) {
            return this;
        }

        // 删除文件
        unlinkSync(filepath);

        return this;
    }
}
<commit_msg>change unstable fs.existsSync to stable fs.statSync<commit_after>/**
 * @file key-cache
 * @author xiaowu
 * @email fe.xiaowu@gmail.com
 */

import {statSync, writeFileSync, readFileSync, unlinkSync} from 'fs';
import {mkdirsSync, emptyDirSync} from 'fs-extra';
import {resolve} from 'path';
import {createHash} from 'crypto';

let fileExists = (filePath) => {
    let isExists;
    try {
        let stat = statSync(filePath);
        isExists = stat.isFile();
    }
    catch (e) {
        isExists = false;
    }
    return isExists;
};

export default class KeyCache {
    static options = {
        /**
         * 缓存目录，路径基于当前运行目录
         *
         * @default 安装包里 dirname + .cache
         * @type {String}
         */
        dir: resolve(__dirname, '..', '.cache'),

        /**
         * 保存的时间，单位秒，如果是null则表示一直保存
         *
         * @default null
         * @type {Number|null}
         */
        timeout: null,

        /**
         * 是否使用md5命名缓存文件
         *
         * @default true
         * @type {Boolean}
         */
        md5key: true
    }

    constructor(options = {}) {
        // 合并默认配置
        this.options = {...KeyCache.options, ...options};

        // 解析路径
        this.options.dir = resolve(this.options.dir);

        // 创建缓存目录
        mkdirsSync(this.options.dir);
    }

    /**
     * 设置缓存
     *
     * @param {string} key   key
     * @param {Object|string} value 值
     * @param {Object|undefined} options 可选配置
     * @return {Object} this
     */
    set(key, value, options = {}) {
        if (!key  || 'string' !== typeof key || value === undefined) {
            return this;
        }

        options = {...this.options, ...options};

        let data = {
            __time: null,
            __result: value
        };

        // 如果有过期时间则记录，否则忽略
        if (options.timeout !== null) {
            data.__time = Date.now();
            data.__end = options.timeout;
        }

        // 如果配置的缓存目录不是初始的则创建该目录，防止出错
        if (options.dir !== this.options.dir) {
            mkdirsSync(options.dir);
        }

        // 写入缓存
        writeFileSync(this._getFilePath(key, options), JSON.stringify(data));

        return this;
    }

    /**
     * 获取缓存文件路径
     *
     * @private
     * @param  {string} key key
     * @param {Object|undefined} options 配置参数，如果为空则调用this.options
     *
     * @return {string}     文件绝对路径
     */
    _getFilePath(key, options) {
        let filename;

        options = options || this.options;

        if (options.md5key) {
            let md5 = createHash('md5');
            // unescape encodeURIComponent 兼容中文 md5
            md5.update(unescape(encodeURIComponent(key)));

            filename = md5.digest('hex');
        }
        else {
            // 把文件名中的:替换为空
            filename = String(key).replace(/[^\u4e00-\u9fa5a-zA-Z\_\-0-9]/g, '');

            // 如果替换后为空则使用md5
            if (!filename) {
                return this._getFilePath(key, {...options, ...{md5key: true}});
            }
        }

        return  resolve(options.dir, filename + '.json');
    }

    /**
     * 获取缓存
     *
     * @param  {string} key key
     *
     * @return {Object|string|null}     结果，如果没有找到或者过期则为null
     */
    get(key) {
        let filepath = this._getFilePath(key);

        // 如果文件不存在
        if (!fileExists(filepath)) {
            return null;
        }

        let filedata = readFileSync(filepath).toString();

        try {
            filedata = JSON.parse(filedata);
        }
        catch (e) {
            return null;
        }

        // 如果没有时间就不是key-cache设置的，则忽略
        if (filedata.__time === undefined) {
            return null;
        }

        // 如果设置了时间并且过期了
        // 则删除这个缓存文件
        if (filedata.__time !== null && Date.now() - filedata.__time > filedata.__end * 1000) {
            this.remove(key);
            return null;
        }

        // 如果为undefined则返回null，因为值是fn时不会被JSON.stringify解析
        return filedata.__result !== undefined ? filedata.__result : null;
    }

    /**
     * 删除缓存
     *
     * @param  {string|undefined} key key，如果为空则全部删除
     *
     * @return {Object}     this
     */
    remove(key) {
        // 如果没有key则说明全部删除
        if (!key) {
            emptyDirSync(this.options.dir);
            return this;
        }

        let filepath = this._getFilePath(key);

        // 如果文件不存在
        if (!existsSync(filepath)) {
            return this;
        }

        // 删除文件
        unlinkSync(filepath);

        return this;
    }
}
<|endoftext|>


<commit_before>// === DEFAULT / CUSTOM STYLE ===
// WARNING! always comment out ONE of the two require() calls below.
// 1. use next line to activate CUSTOM STYLE (./src/themes)
require(`./themes/app.${__THEME}.styl`)
// 2. or, use next line to activate DEFAULT QUASAR STYLE
// require(`quasar/dist/quasar.${__THEME}.css`)
// ==============================

import Vue from 'vue'
import Quasar from 'quasar'
import moment from 'moment'

import router from './router'
import i18n from 'i18n'
import auth from 'services/auth'
import socket from 'services/socket'
import chat from 'services/chat'
import FromNow from 'components/FromNow'
import FormattedDate from 'components/FormattedDate'
import Loading from 'components/Loading'
import LangSwitcher from 'components/LangSwitcher'
import MainLayout from 'layouts/MainLayout'

Vue.use(Quasar) // Install Quasar Framework

// global components
Vue.component('from-now', FromNow)
Vue.component('formatted-date', FormattedDate)
Vue.component('loading', Loading)
Vue.component('lang-switcher', LangSwitcher)
Vue.component('main-layout', MainLayout)

moment.locale('de')

// wireup socket to chats
// TODO: make it unsubscribe
socket.subscribe(message => {
  chat.receiveMessage(message)
})

auth.check().then(() => {
  Quasar.start(() => {
    /* eslint-disable no-new */
    new Vue({
      el: '#q-app',
      i18n,
      router,
      render: h => h(require('./App'))
    })
  })
})
<commit_msg>Move imports to top for lint<commit_after>import Vue from 'vue'
import Quasar from 'quasar'
import moment from 'moment'

import router from './router'
import i18n from 'i18n'
import auth from 'services/auth'
import socket from 'services/socket'
import chat from 'services/chat'
import FromNow from 'components/FromNow'
import FormattedDate from 'components/FormattedDate'
import Loading from 'components/Loading'
import LangSwitcher from 'components/LangSwitcher'
import MainLayout from 'layouts/MainLayout'

// === DEFAULT / CUSTOM STYLE ===
// WARNING! always comment out ONE of the two require() calls below.
// 1. use next line to activate CUSTOM STYLE (./src/themes)
require(`./themes/app.${__THEME}.styl`)
// 2. or, use next line to activate DEFAULT QUASAR STYLE
// require(`quasar/dist/quasar.${__THEME}.css`)
// ==============================

Vue.use(Quasar) // Install Quasar Framework

// global components
Vue.component('from-now', FromNow)
Vue.component('formatted-date', FormattedDate)
Vue.component('loading', Loading)
Vue.component('lang-switcher', LangSwitcher)
Vue.component('main-layout', MainLayout)

moment.locale('de')

// wireup socket to chats
// TODO: make it unsubscribe
socket.subscribe(message => {
  chat.receiveMessage(message)
})

auth.check().then(() => {
  Quasar.start(() => {
    /* eslint-disable no-new */
    new Vue({
      el: '#q-app',
      i18n,
      router,
      render: h => h(require('./App'))
    })
  })
})
<|endoftext|>


<commit_before>function getGitref() {
    nw = window.open("");
    nw.document.write("GITREF: __REVISION__");
    return 0;
}

function leadingZero(number) {
    var retval = number;
    if (number < 10) {
        retval = '0' + number;
    }
    return retval;
}

function now() {
    var today = new Date();

    return leadingZero(today.getDate())
        + '.' + leadingZero(today.getMonth() + 1)
        + '.' + leadingZero(today.getFullYear())
        + " " + leadingZero(today.getHours())
        + ":" + leadingZero(today.getMinutes())
        + ":" + leadingZero(today.getSeconds());
}

function getHeader() {
    return "<!DOCTYPE html>\n"
         + "\n"
         + "  \n"
         + "    <title>Innleveringskvittering</title>\n"
         + "    <meta charset=\"utf-8\">\n"
         + "    \n"
         + "  \n"
         + "  \n"
         + "
\n"
         + "
DEICHMANSKE BIBLIOTEK
\n"
         + "      Tlf: 23432900
\n"
         + "      postmottak.deichman@oslo.kommune.no
\n"
         + "
\n"
         + "
Kvittering på innlevert materiale
\n"
         + "      " + now() + "
\n"
         + "
\n"
         + "
\n";
}

function getFooter() {
    return "
\n"
         + "
\n"
         + "
www.deichman.no
\n"
         + "
\n"
         + "  \n"
         + "\n";
}

function getInner(contents) {
    var retval;
    if (contents.firstChild === null) {
        retval = "";
    } else if (contents.firstChild.nodeType !== Node.TEXT_NODE) {
        retval = contents.firstChild.innerText;
    } else {
        retval = contents.innerText.trim();
    }
    return retval;
}

function getRow(table) {
    var data = [];
    var headers = [];

    for (var r = 0, n = table.rows.length; r < n; r++) {
        var rowdata = [];

        for (var c = 0, m = table.rows[r].cells.length; c < m; c++) {
            var contents = table.rows[r].cells[c];
            rowdata[c] = getInner(contents);
        }

        if (r === 0) {
            headers = rowdata;
        } else {
            data[r] = rowdata;
        }
    }

    var string = "";

    for (var i = 1, l = data.length; i < l; i++) {
        for (var k = 0, f = data[i].length; k < f; k++) {
            string += getRequiredFields(headers[k], data[i][k]);
        }
    }

    return string;
}

function getRequiredFields(header, data) {
    var ret = "";
    switch (header) {
        case "Tittel":
            ret = "
" + header + ":	" + data + "
\n";
            break;
        case "Strekkode":
            ret = "
" + header + ":	" + data + "
\n";
            break;
        default:
            break;
    }
    return ret;
}

function getCheckIns() {
    var tables = ["checkedintable", "rfiditems"];
    var returnedItems = "";

    tables.forEach(function (table) {
        var currentTable = document.getElementById(table);
        if (currentTable !== null) {
            returnedItems += getRow(currentTable);
        }
    });

    if (returnedItems !== "") {
        printWindow = window.open("");
        printWindow.document.write(getHeader());
        printWindow.document.write(returnedItems);
        printWindow.document.write(getFooter());
        printWindow.print();
        printWindow.close();
    }
}

if (window.location.href.toLowerCase().indexOf("gitref") > -1) {
    getGitref();
} else {
    getCheckIns();
}
<commit_msg>Yet more styling<commit_after>function getGitref() {
    nw = window.open("");
    nw.document.write("GITREF: __REVISION__");
    return 0;
}

function leadingZero(number) {
    var retval = number;
    if (number < 10) {
        retval = '0' + number;
    }
    return retval;
}

function now() {
    var today = new Date();

    return leadingZero(today.getDate())
        + '.' + leadingZero(today.getMonth() + 1)
        + '.' + leadingZero(today.getFullYear())
        + " " + leadingZero(today.getHours())
        + ":" + leadingZero(today.getMinutes())
        + ":" + leadingZero(today.getSeconds());
}

function getHeader() {
    return "<!DOCTYPE html>\n"
         + "\n"
         + "  \n"
         + "    <title>Innleveringskvittering</title>\n"
         + "    <meta charset=\"utf-8\">\n"
         + "    \n"
         + "  \n"
         + "  \n"
         + "
\n"
         + "
DEICHMANSKE BIBLIOTEK
\n"
         + "      Tlf: 23432900
\n"
         + "      postmottak.deichman@oslo.kommune.no
\n"
         + "
\n"
         + "
Kvittering på innlevert materiale
\n"
         + "      " + now() + "
\n"
         + "
\n"
         + "
\n";
}

function getFooter() {
    return "
\n"
         + "
\n"
         + "
www.deichman.no
\n"
         + "
\n"
         + "  \n"
         + "\n";
}

function getInner(contents) {
    var retval;
    if (contents.firstChild === null) {
        retval = "";
    } else if (contents.firstChild.nodeType !== Node.TEXT_NODE) {
        retval = contents.firstChild.innerText;
    } else {
        retval = contents.innerText.trim();
    }
    return retval;
}

function getRow(table) {
    var data = [];
    var headers = [];

    for (var r = 0, n = table.rows.length; r < n; r++) {
        var rowdata = [];

        for (var c = 0, m = table.rows[r].cells.length; c < m; c++) {
            var contents = table.rows[r].cells[c];
            rowdata[c] = getInner(contents);
        }

        if (r === 0) {
            headers = rowdata;
        } else {
            data[r] = rowdata;
        }
    }

    var string = "";

    for (var i = 1, l = data.length; i < l; i++) {
        for (var k = 0, f = data[i].length; k < f; k++) {
            string += getRequiredFields(headers[k], data[i][k]);
        }
    }

    return string;
}

function getRequiredFields(header, data) {
    var ret = "";
    switch (header) {
        case "Tittel":
            ret = "
" + data + "
\n";
            break;
        case "Strekkode":
            ret = "
" + header + ":	" + data + "
\n";
            break;
        default:
            break;
    }
    return ret;
}

function getCheckIns() {
    var tables = ["checkedintable", "rfiditems"];
    var returnedItems = "";

    tables.forEach(function (table) {
        var currentTable = document.getElementById(table);
        if (currentTable !== null) {
            returnedItems += getRow(currentTable);
        }
    });

    if (returnedItems !== "") {
        printWindow = window.open("");
        printWindow.document.write(getHeader());
        printWindow.document.write(returnedItems);
        printWindow.document.write(getFooter());
        printWindow.print();
        printWindow.close();
    }
}

if (window.location.href.toLowerCase().indexOf("gitref") > -1) {
    getGitref();
} else {
    getCheckIns();
}
<|endoftext|>


<commit_before>import './main.sass'
import 'babel-core/polyfill'
import 'isomorphic-fetch'

import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { ReduxRouter } from 'redux-router'
import { updateStrings as updateTimeAgoStrings } from './vendor/time_ago_in_words'
import { persistStore } from 'redux-persist'
import localforage from 'localforage'
import store from './store'
import * as ACTION_TYPES from './constants/action_types'

import './vendor/embetter'
import './vendor/embetter_initializer'

updateTimeAgoStrings({ about: '' })

const element = (
  <Provider store={store}>
    <ReduxRouter />
  </Provider>
)

const storage = localforage.createInstance({ name: 'ello-webapp' })
const persistor = persistStore(store, { storage, blacklist: ['router', 'modal'] }, () => {
  // this adds the 'more posts' to the existing result if present
  // so that a refresh won't have the 'more posts' button
  store.dispatch({ type: ACTION_TYPES.ADD_NEW_IDS_TO_RESULT })
  ReactDOM.render(element, document.getElementById('root'))
})

// check and update current version and
// only kill off the persisted reducers
if (ENV.APP_VERSION) {
  storage.getItem('APP_VERSION')
    .then((curVersion) => {
      if (curVersion && curVersion !== ENV.APP_VERSION) {
        persistor.purge(['json', 'profile', 'search', 'stream'])
      }
      storage.setItem('APP_VERSION', ENV.APP_VERSION)
    })
}

<commit_msg>Add the accessToken for the time being to main.js<commit_after>import './main.sass'
import 'babel-core/polyfill'
import 'isomorphic-fetch'

import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { ReduxRouter } from 'redux-router'
import { updateStrings as updateTimeAgoStrings } from './vendor/time_ago_in_words'
import { persistStore } from 'redux-persist'
import localforage from 'localforage'
import store from './store'
import * as ACTION_TYPES from './constants/action_types'

import './vendor/embetter'
import './vendor/embetter_initializer'

updateTimeAgoStrings({ about: '' })

const element = (
  <Provider store={store}>
    <ReduxRouter />
  </Provider>
)

const storage = localforage.createInstance({ name: 'ello-webapp' })
const persistor = persistStore(store, { storage, blacklist: ['router', 'modal'] }, () => {
  // this adds the 'more posts' to the existing result if present
  // so that a refresh won't have the 'more posts' button
  store.dispatch({ type: ACTION_TYPES.ADD_NEW_IDS_TO_RESULT })
  ReactDOM.render(element, document.getElementById('root'))
})

// check and update current version and
// only kill off the persisted reducers
if (ENV.APP_VERSION) {
  storage.getItem('APP_VERSION')
    .then((curVersion) => {
      if (curVersion && curVersion !== ENV.APP_VERSION) {
        persistor.purge(['accessToken', 'json', 'profile', 'search', 'stream'])
      }
      storage.setItem('APP_VERSION', ENV.APP_VERSION)
    })
}

<|endoftext|>


<commit_before>var $ = require('jquery')(window);
var Backbone = require('backbone');
var Wreqr = require('../node_modules/backbone.marionette/node_modules/backbone.wreqr');
var Marionette = require('backbone.marionette');
Marionette.$ = Backbone.$ = $;
Backbone.Wreqr = Wreqr;

var MyApp = new Marionette.Application();
MyApp.addInitializer(function(options){
  console.log('initialised app');
});
MyApp.start();
<commit_msg>[refactor] update marionette requires<commit_after>var $ = require('jquery');
var Backbone = require('backbone');
Backbone.$  = $;
var Marionette = require('backbone.marionette');

var MyApp = new Marionette.Application();
MyApp.addInitializer(function(options){
  console.log('initialised app');
});
MyApp.start();
<|endoftext|>


<commit_before>var state = {};

function row() {
  state.accSeaworth++;
  $('#distance').text(++state.distance);
}

function seaworth() {
  if (state.accSeaworth >= state.nextSeaworth) {
    state.accSeaworth = 0;
    // FIXME extract constants to configuration
    // TODO extract pricing function
    state.nextSeaworth = 2 + Math.floor(Math.pow(1.05, ++state.seaworth));
    $('#seaworth').text(state.seaworth);
  }
}

$('#row').click(function () {
  row();
  seaworth();
});

(function () {
  state.distance = 0;
  state.seaworth = 0;
  state.accSeaworth = 0;
  state.nextSeaworth = 3;
}());
<commit_msg>wrapping main js in a module<commit_after>var seaworthy = (function () {
  var state = {};

  function row() {
    state.accSeaworth++;
    $('#distance').text(++state.distance);
  }

  function seaworth() {
    if (state.accSeaworth >= state.nextSeaworth) {
      state.accSeaworth = 0;
      // FIXME extract constants to configuration
      // TODO extract pricing function
      state.nextSeaworth = 2 + Math.floor(Math.pow(1.05, ++state.seaworth));
      $('#seaworth').text(state.seaworth);
    }
  }

  $('#row').click(function () {
    row();
    seaworth();
  });

  (function () {
    state.distance = 0;
    state.seaworth = 0;
    state.accSeaworth = 0;
    state.nextSeaworth = 3;
  }());
}());
<|endoftext|>


<commit_before>{

/**
 * Main program.
 */
setup_elem_picker()
setup_change_propagation()

/**
 * Let the user pick a DOM element and make all quantities inside it editable.
 */
function setup_elem_picker() {
    let last_hovered_elem

    const off_mouseover = on(document.body, 'mouseover', on_mouseover)
    const off_mouseout = on(document.body, 'mouseout', on_mouseout)
    const off_click = on(document.body, 'click', on_click)

    function on_mouseover(evt) {
        last_hovered_elem = evt.target
        add_bg(last_hovered_elem)
    }

    function on_mouseout(evt) {
        remove_bg(evt.target)
    }

    function on_click() {
        remove_bg(last_hovered_elem)
        make_all_quantities_editable(last_hovered_elem)

        off_mouseover()
        off_mouseout()
        off_click()
    }
}

function add_bg(elem) {
    elem.classList.add('ra-ingredient-list-selector')
}

function remove_bg(elem) {
    elem.classList.remove('ra-ingredient-list-selector')
}

function make_all_quantities_editable(elem) {
    elem.normalize()

    const walker = document.createTreeWalker(elem, NodeFilter.SHOW_TEXT)
    let first = true

    while (walker.nextNode()) {
        let match
        while ((match = best_qty_match(walker.currentNode.nodeValue))) {
            const val_num = str_to_num(match)
            if (isNaN(val_num) || !isFinite(val_num)) {
                return
            }

            const span = document.createElement('span')
            span.textContent = match
            span.classList.add('ra-ingredient-input')
            span.setAttribute('contenteditable', 'true')
            span.setAttribute('title', 'Original value: ' + match)
            span.setAttribute('data-ra-original-val-num', val_num)
            span.setAttribute('data-ra-original-val-was-fraction', '' + /½|⅓|⅔|¼|¾|⅕|⅖|⅗|⅘|⅙|⅚|⅐|⅛|⅜|⅝|⅞|⅑|⅒|\/|[Hh]alf/.test(match))

            // Remove the original string and insert the new editable element.
            const second_node = walker.currentNode.splitText(match.index)
            second_node.nodeValue = second_node.nodeValue.substr(match.length)
            walker.currentNode.parentNode.insertBefore(span, second_node)

            if (first) {
                first = false
                select_or_focus(span)
            }

            // Advance the walker to the node after the newly inserted element.
            walker.nextNode()
            walker.nextNode()
        }
    }
}

/**
 * Listen to changes on the editable quantities and propagate them proportionally.
 */
function setup_change_propagation() {
    if (document.body.getAttribute('data-ra-listening') === 'true') {
        return
    }

    on(document.body, 'keyup', evt => {
        if (!evt.target.classList.contains('ra-ingredient-input')) {
            return
        }

        const current_val = str_to_num(evt.target.textContent)
        const original_val = get_original_val_num(evt.target)
        const ratio = current_val / original_val
        if (isNaN(ratio) || !isFinite(ratio)) {
            return
        }

        for (const input of document.getElementsByClassName('ra-ingredient-input')) {
            if (input === evt.target) {
                continue
            }

            const new_val = get_original_val_num(input) * ratio
            const as_fraction = input.getAttribute('data-ra-original-val-was-fraction') === 'true'
                || unit_is_measuring_spoon(input)
            input.textContent = num_to_str(new_val, as_fraction)
        }
    })

    document.body.setAttribute('data-ra-listening', 'true')
}

function unit_is_measuring_spoon(input) {
    const parent = input.parentNode
    const parentText = parent.textContent.trim().length === input.textContent.length
        ? parent.parentNode.textContent
        : parent.textContent

    const measuring_spoon_regexps = ['teaspoon', 'tsp', 'tablespoon', 'tbsp', 'cup']
        .map(spoon => new RegExp('\\b' + spoon + 's?\\b', 'i'))

    for (const regexp of measuring_spoon_regexps) {
        if (regexp.test(parentText)) {
            return true
        }
    }
    return false
}

function get_original_val_num(input) {
    return parseFloat(input.getAttribute('data-ra-original-val-num'))
}

/**
 * Examples of strings matched by these regular expressions:
 *   1. "½", "1½", "1 ½"
 *   2. "1/2", "1 / 2", "1 1/2", "1 1 / 2"
 *   3. "1", "1.2", "1,000", "1,000.2"
 *   4. "1", "1,2", "1.000", "1.000,2"
 *   5. "Half", "half"
 *
 * The meanings of "." and "," are guessed automatically with the assumption
 * that at most 2 decimal places are used.
 *
 * TODO Deal with more textual quantities, e.g. "one", "pair", "couple",
 * "dozen"... "two halves"? "two pairs"? "half a dozen"? "half a pair"!?
 */
const qty_regexps = [
    /([1-9]\d*\s?)?(½|⅓|⅔|¼|¾|⅕|⅖|⅗|⅘|⅙|⅚|⅐|⅛|⅜|⅝|⅞|⅑|⅒)/,
    /([1-9]\d*\s)?[1-9]\d*\s?\/\s?[1-9]\d*/,
    /[1-9](\d|,\d{3})*(\.\d{1,2})?/,
    /[1-9](\d|\.\d{3})*(,\d{1,2})?/,
    /[Hh]alf/
]

function best_qty_match(str) {
    return qty_regexps
        .map(regexp => regexp.exec(str))
        .filter(match => !!match)
        .map(match => match[0])
        .reduce((a, b) => a.length > b.length ? a : b, '')
}

/**
 * Get a numeric value usable in computations out of the given string.
 */
function str_to_num(str) {
    // Remove trailing non-digits, to cover the case when the user is still typing. (But
    // deal with textual quantities before!)
    str = str
        .replace(/[Hh]alf/, '1/2')
        .replace(/[.,/a-zA-Z\s]+$/, '')

    if (!str || !best_qty_match(str)) {
        return
    }

    // A plus sign is prepended to fractions in case there is a number in front of them.
    str = str
        .replace('½', '+1/2')
        .replace('⅓', '+1/3')
        .replace('⅔', '+2/3')
        .replace('¼', '+1/4')
        .replace('¾', '+3/4')
        .replace('⅕', '+1/5')
        .replace('⅖', '+2/5')
        .replace('⅗', '+3/5')
        .replace('⅘', '+4/5')
        .replace('⅙', '+1/6')
        .replace('⅚', '+5/6')
        .replace('⅐', '+1/7')
        .replace('⅛', '+1/8')
        .replace('⅜', '+3/8')
        .replace('⅝', '+5/8')
        .replace('⅞', '+7/8')
        .replace('⅑', '+1/9')
        .replace('⅒', '+1/10')
        .replace(/(\d+)\s+(\d+)\s*\/\s*(\d+)/, '$1+$2/$3')
        .replace(/[.,]([0-9]{3})/g, '$1')
        .replace(',', '.')

    // Only what fits one of the restricted regular expressions is evaluated.
    return eval(str)
}

/**
 * Get a nice string representation of the given number.
 */
function num_to_str(num, as_fraction) {
    if (as_fraction) {
        const fr = get_fraction(num)
        if (fr) {
            return fr
        }
    }

    const str = num.toFixed(1)
    return str.endsWith('.0') ? str.slice(0, -2) : str

    function get_fraction(num) {
        const sensible_fractions = {
            '1/2': 1/2,
            '1/3': 1/3,
            '2/3': 2/3,
            '1/4': 1/4,
            '3/4': 3/4,
            '1/5': 1/5,
            '2/5': 2/5,
            '1/10': 1/10
        }

        for (const fr in sensible_fractions) {
            if (ish(num, sensible_fractions[fr])) {
                return fr
            }
        }
    }
}

/**
 * Check if two numbers are approximately the same, avoiding precission problems.
 */
function ish(n, m) {
    return Math.abs(n - m) <= 0.0000000000000001
}

/**
 * Shortcut for listening to events on DOM elements.
 */
function on(elem, evt, fn) {
    elem.addEventListener(evt, fn)

    return function off() {
        elem.removeEventListener(evt, fn)
    }
}

/**
 * Try to select the contents of the given element, falling back to simply focusing the element.
 */
function select_or_focus(elem) {
    try {
        const range = document.createRange()
        range.selectNodeContents(elem)
        const selection = window.getSelection()
        selection.removeAllRanges()
        selection.addRange(range)
    } catch (e) {
        elem.focus()
    }
}

}
<commit_msg>Fix ish() function...<commit_after>{

/**
 * Main program.
 */
setup_elem_picker()
setup_change_propagation()

/**
 * Let the user pick a DOM element and make all quantities inside it editable.
 */
function setup_elem_picker() {
    let last_hovered_elem

    const off_mouseover = on(document.body, 'mouseover', on_mouseover)
    const off_mouseout = on(document.body, 'mouseout', on_mouseout)
    const off_click = on(document.body, 'click', on_click)

    function on_mouseover(evt) {
        last_hovered_elem = evt.target
        add_bg(last_hovered_elem)
    }

    function on_mouseout(evt) {
        remove_bg(evt.target)
    }

    function on_click() {
        remove_bg(last_hovered_elem)
        make_all_quantities_editable(last_hovered_elem)

        off_mouseover()
        off_mouseout()
        off_click()
    }
}

function add_bg(elem) {
    elem.classList.add('ra-ingredient-list-selector')
}

function remove_bg(elem) {
    elem.classList.remove('ra-ingredient-list-selector')
}

function make_all_quantities_editable(elem) {
    elem.normalize()

    const walker = document.createTreeWalker(elem, NodeFilter.SHOW_TEXT)
    let first = true

    while (walker.nextNode()) {
        let match
        while ((match = best_qty_match(walker.currentNode.nodeValue))) {
            const val_num = str_to_num(match)
            if (isNaN(val_num) || !isFinite(val_num)) {
                return
            }

            const span = document.createElement('span')
            span.textContent = match
            span.classList.add('ra-ingredient-input')
            span.setAttribute('contenteditable', 'true')
            span.setAttribute('title', 'Original value: ' + match)
            span.setAttribute('data-ra-original-val-num', val_num)
            span.setAttribute('data-ra-original-val-was-fraction', '' + /½|⅓|⅔|¼|¾|⅕|⅖|⅗|⅘|⅙|⅚|⅐|⅛|⅜|⅝|⅞|⅑|⅒|\/|[Hh]alf/.test(match))

            // Remove the original string and insert the new editable element.
            const second_node = walker.currentNode.splitText(match.index)
            second_node.nodeValue = second_node.nodeValue.substr(match.length)
            walker.currentNode.parentNode.insertBefore(span, second_node)

            if (first) {
                first = false
                select_or_focus(span)
            }

            // Advance the walker to the node after the newly inserted element.
            walker.nextNode()
            walker.nextNode()
        }
    }
}

/**
 * Listen to changes on the editable quantities and propagate them proportionally.
 */
function setup_change_propagation() {
    if (document.body.getAttribute('data-ra-listening') === 'true') {
        return
    }

    on(document.body, 'keyup', evt => {
        if (!evt.target.classList.contains('ra-ingredient-input')) {
            return
        }

        const current_val = str_to_num(evt.target.textContent)
        const original_val = get_original_val_num(evt.target)
        const ratio = current_val / original_val
        if (isNaN(ratio) || !isFinite(ratio)) {
            return
        }

        for (const input of document.getElementsByClassName('ra-ingredient-input')) {
            if (input === evt.target) {
                continue
            }

            const new_val = get_original_val_num(input) * ratio
            const as_fraction = input.getAttribute('data-ra-original-val-was-fraction') === 'true'
                || unit_is_measuring_spoon(input)
            input.textContent = num_to_str(new_val, as_fraction)
        }
    })

    document.body.setAttribute('data-ra-listening', 'true')
}

function unit_is_measuring_spoon(input) {
    const parent = input.parentNode
    const parentText = parent.textContent.trim().length === input.textContent.length
        ? parent.parentNode.textContent
        : parent.textContent

    const measuring_spoon_regexps = ['teaspoon', 'tsp', 'tablespoon', 'tbsp', 'cup']
        .map(spoon => new RegExp('\\b' + spoon + 's?\\b', 'i'))

    for (const regexp of measuring_spoon_regexps) {
        if (regexp.test(parentText)) {
            return true
        }
    }
    return false
}

function get_original_val_num(input) {
    return parseFloat(input.getAttribute('data-ra-original-val-num'))
}

/**
 * Examples of strings matched by these regular expressions:
 *   1. "½", "1½", "1 ½"
 *   2. "1/2", "1 / 2", "1 1/2", "1 1 / 2"
 *   3. "1", "1.2", "1,000", "1,000.2"
 *   4. "1", "1,2", "1.000", "1.000,2"
 *   5. "Half", "half"
 *
 * The meanings of "." and "," are guessed automatically with the assumption
 * that at most 2 decimal places are used.
 *
 * TODO Deal with more textual quantities, e.g. "one", "pair", "couple",
 * "dozen"... "two halves"? "two pairs"? "half a dozen"? "half a pair"!?
 */
const qty_regexps = [
    /([1-9]\d*\s?)?(½|⅓|⅔|¼|¾|⅕|⅖|⅗|⅘|⅙|⅚|⅐|⅛|⅜|⅝|⅞|⅑|⅒)/,
    /([1-9]\d*\s)?[1-9]\d*\s?\/\s?[1-9]\d*/,
    /[1-9](\d|,\d{3})*(\.\d{1,2})?/,
    /[1-9](\d|\.\d{3})*(,\d{1,2})?/,
    /[Hh]alf/
]

function best_qty_match(str) {
    return qty_regexps
        .map(regexp => regexp.exec(str))
        .filter(match => !!match)
        .map(match => match[0])
        .reduce((a, b) => a.length > b.length ? a : b, '')
}

/**
 * Get a numeric value usable in computations out of the given string.
 */
function str_to_num(str) {
    // Remove trailing non-digits, to cover the case when the user is still typing. (But
    // deal with textual quantities before!)
    str = str
        .replace(/[Hh]alf/, '1/2')
        .replace(/[.,/a-zA-Z\s]+$/, '')

    if (!str || !best_qty_match(str)) {
        return
    }

    // A plus sign is prepended to fractions in case there is a number in front of them.
    str = str
        .replace('½', '+1/2')
        .replace('⅓', '+1/3')
        .replace('⅔', '+2/3')
        .replace('¼', '+1/4')
        .replace('¾', '+3/4')
        .replace('⅕', '+1/5')
        .replace('⅖', '+2/5')
        .replace('⅗', '+3/5')
        .replace('⅘', '+4/5')
        .replace('⅙', '+1/6')
        .replace('⅚', '+5/6')
        .replace('⅐', '+1/7')
        .replace('⅛', '+1/8')
        .replace('⅜', '+3/8')
        .replace('⅝', '+5/8')
        .replace('⅞', '+7/8')
        .replace('⅑', '+1/9')
        .replace('⅒', '+1/10')
        .replace(/(\d+)\s+(\d+)\s*\/\s*(\d+)/, '$1+$2/$3')
        .replace(/[.,]([0-9]{3})/g, '$1')
        .replace(',', '.')

    // Only what fits one of the restricted regular expressions is evaluated.
    return eval(str)
}

/**
 * Get a nice string representation of the given number.
 */
function num_to_str(num, as_fraction) {
    if (as_fraction) {
        const fr = get_fraction(num)
        if (fr) {
            return fr
        }
    }

    const str = num.toFixed(1)
    return str.endsWith('.0') ? str.slice(0, -2) : str

    function get_fraction(num) {
        const sensible_fractions = {
            '1/2': 1/2,
            '1/3': 1/3,
            '2/3': 2/3,
            '1/4': 1/4,
            '3/4': 3/4,
            '1/5': 1/5,
            '2/5': 2/5,
            '1/10': 1/10
        }

        for (const fr in sensible_fractions) {
            if (ish(num, sensible_fractions[fr])) {
                return fr
            }
        }
    }
}

/**
 * Check if two numbers are approximately the same, avoiding precission problems.
 */
function ish(n, m) {
    return Math.abs(n - m) <= 0.00000000000001
}

/**
 * Shortcut for listening to events on DOM elements.
 */
function on(elem, evt, fn) {
    elem.addEventListener(evt, fn)

    return function off() {
        elem.removeEventListener(evt, fn)
    }
}

/**
 * Try to select the contents of the given element, falling back to simply focusing the element.
 */
function select_or_focus(elem) {
    try {
        const range = document.createRange()
        range.selectNodeContents(elem)
        const selection = window.getSelection()
        selection.removeAllRanges()
        selection.addRange(range)
    } catch (e) {
        elem.focus()
    }
}

}
<|endoftext|>


<commit_before>const React = require('react');
const ReactDOM = require('react-dom');
const CreateStore = require('./wiring/create-store');
const AppContainer = require('./containers/App');
const createHistory = require('history').createBrowserHistory;
const History = createHistory();

// Create redux store and sync history with react-router-redux

const initialState = window.__INITIAL_STATE__;
const store = CreateStore(initialState);

// Developer Tools Setup

if (__DEBUG__) {
    if (window.devToolsExtension) {
        window.devToolsExtension.open();
    }
}

// Render Setup

const MOUNT_NODE = document.getElementById('root');

let render = () => {

    const Routes = require('./routes')(store);

    ReactDOM.render(

        <AppContainer
            store={store}
            routes={Routes}
            history={History}
        />,
        MOUNT_NODE
    );
};

// when history changes, reload AppContainer
History.listen((location, action) => {

    render();
});

// Enable HMR and catch runtime errors in RedBox
// This code is excluded from production bundle

if (__DEV__ && module.hot) {

    const RedBox = require('redbox-react').default;
    const renderApp = render;
    const renderError = (error) => {

        ReactDOM.render(<RedBox error={error} />, MOUNT_NODE);
    };

    render = () => {

        try {
            renderApp(Math.random());
        }
        catch (error) {
            console.error(error.stack);
            renderError(error);
        }
    };

    module.hot.accept(['./routes/index'], () => render());
}

// Go!
render();
<commit_msg>add listener to history, for reloading AppContainer when url changes<commit_after>const React = require('react');
const ReactDOM = require('react-dom');
const CreateStore = require('./wiring/create-store');
const AppContainer = require('./containers/App');
const createHistory = require('history').createBrowserHistory;
const History = createHistory();

// Create redux store and sync history with react-router-redux

const initialState = window.__INITIAL_STATE__;
const store = CreateStore(initialState);

// Developer Tools Setup

if (__DEBUG__) {
    if (window.devToolsExtension) {
        window.devToolsExtension.open();
    }
}

// Render Setup

const MOUNT_NODE = document.getElementById('root');

let render = () => {

    const Routes = require('./routes')(store);

    ReactDOM.render(

        <AppContainer
            store={store}
            routes={Routes}
            history={History}
        />,
        MOUNT_NODE
    );
};

// when history changes, reload AppContainer
History.listen((location, action) => {

    render();
});

// Enable HMR and catch runtime errors in RedBox
// This code is excluded from production bundle

if (__DEV__ && module.hot) {

    const RedBox = require('redbox-react').default;
    const renderApp = render;
    const renderError = (error) => {

        ReactDOM.render(<RedBox error={error} />, MOUNT_NODE);
    };

    render = () => {

        try {
            renderApp(Math.random());
        }
        catch (error) {
            console.error(error.stack);
            renderError(error);
        }
    };

    module.hot.accept(['./routes/index'], () => render());
}

// Go!
render();
<|endoftext|>


<commit_before>var React = require('react');

var config = require('./config');
var App = require('./App.jsx');
var Database = require('./Database.js');

var db = new Database(config.localDb, config.serverDb);
React.renderComponent(App({db: db}), document.getElementById('content'));
<commit_msg>Temporarily put the db in the global namespace<commit_after>var React = require('react');

var config = require('./config');
var App = require('./App.jsx');
var Database = require('./Database.js');

//TODO: PUT THE 'var' BACK
db = new Database(config.localDb, config.serverDb);
React.renderComponent(App({db: db}), document.getElementById('content'));
<|endoftext|>


<commit_before>/* globals VERSION COMMITHASH BRANCH */
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
// Raven to use with Sentry.io
import Raven from 'raven-js'
import RavenVue from 'raven-js/plugins/vue'
// Our app
import App from './App'
// Some cool plugins
import VueResource from 'vue-resource'
import VueAnalytics from 'vue-analytics'
// Our components
import About from '@/components/About'
import Settings from '@/components/Settings'
import Stats from '@/components/Stats'
import DayListEl from '@/components/DayListEl'
import ScheduleListEl from '@/components/ScheduleListEl'
// The router
import router from './Router'

// Test if the browser doesn't support console and localStorage
if (typeof console === 'undefined' || typeof localStorage === 'undefined') {
  var errorMsgUnsupported = '
CN Schedule
'
  errorMsgUnsupported += 'You\'re currently using an unsupported browser.
'
  errorMsgUnsupported += 'Please upgrade to the latest version of Chrome, Opera, Brave, Firefox, Microsoft Edge or Safari to continue.
'
  errorMsgUnsupported += 'More details on having a good and updated browser here.'

  document.getElementById('jserror').innerHTML = errorMsgUnsupported
  throw new Error('Unsupported browser')
}

// Test if we can write things to localStorage (IE's "Access Denied" / iOS Private Browsing)
try {
  window.localStorage.setItem('Are You CN', 'What We\'re Sayin\'?')
} catch (error) {
  var errorMsgLS = '
CN Schedule
'
  errorMsgLS += 'This app doesn\'t work with your current browser state.
'
  errorMsgLS += 'iOS users: Private browsing mode breaks the saving/loading feature of the app. Please go to normal mode.
'
  errorMsgLS += 'Internet Explorer users: Your browser doesn\'t allow this website to save local content.'
  errorMsgLS += 'This might be a security measure from your computer or your company.'
  errorMsgLS += 'If you can, add this website to the thrusted sites list or temporarly use an another browser.'

  document.getElementById('jserror').innerHTML = errorMsgLS
  throw new Error('Can\'t write to localStorage')
}

// Stop posting tips
Vue.config.productionTip = false

// Load components
Vue.component('app-about', About)
Vue.component('app-settings', Settings)
Vue.component('schedule-stats', Stats)
Vue.component('day-el', DayListEl)
Vue.component('schedule-el', ScheduleListEl)

// Enable plugins
Raven
  .config('https://c64d65a5b58a4852b77891b64cac04cc@sentry.io/213540', {
    release: VERSION,
    tags: {
      git_commit: COMMITHASH,
      git_branch: BRANCH
    },
    environment: process.env
  })
  .addPlugin(RavenVue, Vue)
  .install()
Vue.use(VueResource)
Vue.use(VueAnalytics, {
  id: 'UA-103935709-2',
  router
})

// Say hi to whoever opens the console
console.log(
  '%cCN Schedule',
  'font-size:70px;color:#fff;text-shadow:0 1px 0 #ccc,0 2px 0 #c9c9c9,0 3px 0 #bbb,0 4px 0 #b9b9b9,0 5px 0 #aaa,0 6px 1px rgba(0,0,0,.1),0 0 5px rgba(0,0,0,.1),0 1px 3px rgba(0,0,0,.3),0 3px 5px rgba(0,0,0,.2),0 5px 10px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.2),0 20px 20px rgba(0,0,0,.15);'
)
console.log(
  '%cby CTOON Webmedia Group' +
  '\nGithub: https://gitlab.com/ctoon/cn-schedule',
  'font-style:italic;'
)
console.log(
  '%cVersion: ' + VERSION +
  '\nCommit: ' + COMMITHASH +
  '\nBranch: ' + BRANCH,
  'color:green;'
)

/* eslint-disable no-new */
// Create vue app
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: { App }
})
<commit_msg>Git~~hub~~<commit_after>/* globals VERSION COMMITHASH BRANCH */
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
// Raven to use with Sentry.io
import Raven from 'raven-js'
import RavenVue from 'raven-js/plugins/vue'
// Our app
import App from './App'
// Some cool plugins
import VueResource from 'vue-resource'
import VueAnalytics from 'vue-analytics'
// Our components
import About from '@/components/About'
import Settings from '@/components/Settings'
import Stats from '@/components/Stats'
import DayListEl from '@/components/DayListEl'
import ScheduleListEl from '@/components/ScheduleListEl'
// The router
import router from './Router'

// Test if the browser doesn't support console and localStorage
if (typeof console === 'undefined' || typeof localStorage === 'undefined') {
  var errorMsgUnsupported = '
CN Schedule
'
  errorMsgUnsupported += 'You\'re currently using an unsupported browser.
'
  errorMsgUnsupported += 'Please upgrade to the latest version of Chrome, Opera, Brave, Firefox, Microsoft Edge or Safari to continue.
'
  errorMsgUnsupported += 'More details on having a good and updated browser here.'

  document.getElementById('jserror').innerHTML = errorMsgUnsupported
  throw new Error('Unsupported browser')
}

// Test if we can write things to localStorage (IE's "Access Denied" / iOS Private Browsing)
try {
  window.localStorage.setItem('Are You CN', 'What We\'re Sayin\'?')
} catch (error) {
  var errorMsgLS = '
CN Schedule
'
  errorMsgLS += 'This app doesn\'t work with your current browser state.
'
  errorMsgLS += 'iOS users: Private browsing mode breaks the saving/loading feature of the app. Please go to normal mode.
'
  errorMsgLS += 'Internet Explorer users: Your browser doesn\'t allow this website to save local content.'
  errorMsgLS += 'This might be a security measure from your computer or your company.'
  errorMsgLS += 'If you can, add this website to the thrusted sites list or temporarly use an another browser.'

  document.getElementById('jserror').innerHTML = errorMsgLS
  throw new Error('Can\'t write to localStorage')
}

// Stop posting tips
Vue.config.productionTip = false

// Load components
Vue.component('app-about', About)
Vue.component('app-settings', Settings)
Vue.component('schedule-stats', Stats)
Vue.component('day-el', DayListEl)
Vue.component('schedule-el', ScheduleListEl)

// Enable plugins
Raven
  .config('https://c64d65a5b58a4852b77891b64cac04cc@sentry.io/213540', {
    release: VERSION,
    tags: {
      git_commit: COMMITHASH,
      git_branch: BRANCH
    },
    environment: process.env
  })
  .addPlugin(RavenVue, Vue)
  .install()
Vue.use(VueResource)
Vue.use(VueAnalytics, {
  id: 'UA-103935709-2',
  router
})

// Say hi to whoever opens the console
console.log(
  '%cCN Schedule',
  'font-size:70px;color:#fff;text-shadow:0 1px 0 #ccc,0 2px 0 #c9c9c9,0 3px 0 #bbb,0 4px 0 #b9b9b9,0 5px 0 #aaa,0 6px 1px rgba(0,0,0,.1),0 0 5px rgba(0,0,0,.1),0 1px 3px rgba(0,0,0,.3),0 3px 5px rgba(0,0,0,.2),0 5px 10px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.2),0 20px 20px rgba(0,0,0,.15);'
)
console.log(
  '%cby CTOON Webmedia Group' +
  '\nGit: https://gitlab.com/ctoon/cn-schedule',
  'font-style:italic;'
)
console.log(
  '%cCommit: ' + COMMITHASH +
  '\nBranch: ' + BRANCH,
  'color:green;'
)

/* eslint-disable no-new */
// Create vue app
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: { App }
})
<|endoftext|>


<commit_before>import React from 'react'
import ReactDOM from 'react-dom'
import createBrowserHistory from 'history/lib/createBrowserHistory'
import { useRouterHistory } from 'react-router'
import { syncHistoryWithStore } from 'react-router-redux'
import createStore from './store/createStore'
import AppContainer from './containers/AppContainer';
import { watchFetchSnapData } from './sagas';

import { effects } from 'redux-saga';

const { call } = effects;

// ========================================================
// Browser History Setup
// ========================================================
const browserHistory = useRouterHistory(createBrowserHistory)({
  basename: __BASENAME__
})

// ========================================================
// Store and History Instantiation
// ========================================================
// Create redux store and sync with react-router-redux. We have installed the
// react-router-redux reducer under the routerKey "router" in src/routes/index.js,
// so we need to provide a custom `selectLocationState` to inform
// react-router-redux of its location.
const initialState = window.___INITIAL_STATE__
const store = createStore(initialState, browserHistory)

store.runSaga(watchFetchSnapData);

const history = syncHistoryWithStore(browserHistory, store, {
  selectLocationState: (state) => state.router
})

//run sagaMiddleware

// ========================================================
// Developer Tools Setup
// ========================================================
if (__DEBUG__) {
  if (window.devToolsExtension) {
    window.devToolsExtension.open()
  }
}

// ========================================================
// Render Setup
// ========================================================
const MOUNT_NODE = document.getElementById('root')

let render = (routerKey = null) => {
  const routes = require('./routes/index').default(store)

  ReactDOM.render(
    <AppContainer
      store={store}
      history={history}
      routes={routes}
      routerKey={routerKey}
    />,
    MOUNT_NODE
  )
}

// Enable HMR and catch runtime errors in RedBox
// This code is excluded from production bundle
if (__DEV__ && module.hot) {
  const renderApp = render
  const renderError = (error) => {
    const RedBox = require('redbox-react')

    ReactDOM.render(<RedBox error={error} />, MOUNT_NODE)
  }
  render = () => {
    try {
      renderApp(Math.random())
    } catch (error) {
      renderError(error)
    }
  }
  module.hot.accept(['./routes/index'], () => render())
}

// ========================================================
// Go!
// ========================================================
render()
<commit_msg>remove usless code<commit_after>import React from 'react'
import ReactDOM from 'react-dom'
import createBrowserHistory from 'history/lib/createBrowserHistory'
import { useRouterHistory } from 'react-router'
import { syncHistoryWithStore } from 'react-router-redux'
import createStore from './store/createStore'
import AppContainer from './containers/AppContainer';
import { watchFetchSnapData } from './sagas';

// ========================================================
// Browser History Setup
// ========================================================
const browserHistory = useRouterHistory(createBrowserHistory)({
  basename: __BASENAME__
})

// ========================================================
// Store and History Instantiation
// ========================================================
// Create redux store and sync with react-router-redux. We have installed the
// react-router-redux reducer under the routerKey "router" in src/routes/index.js,
// so we need to provide a custom `selectLocationState` to inform
// react-router-redux of its location.
const initialState = window.___INITIAL_STATE__
const store = createStore(initialState, browserHistory)

store.runSaga(watchFetchSnapData);

const history = syncHistoryWithStore(browserHistory, store, {
  selectLocationState: (state) => state.router
})

//run sagaMiddleware

// ========================================================
// Developer Tools Setup
// ========================================================
if (__DEBUG__) {
  if (window.devToolsExtension) {
    window.devToolsExtension.open()
  }
}

// ========================================================
// Render Setup
// ========================================================
const MOUNT_NODE = document.getElementById('root')

let render = (routerKey = null) => {
  const routes = require('./routes/index').default(store)

  ReactDOM.render(
    <AppContainer
      store={store}
      history={history}
      routes={routes}
      routerKey={routerKey}
    />,
    MOUNT_NODE
  )
}

// Enable HMR and catch runtime errors in RedBox
// This code is excluded from production bundle
if (__DEV__ && module.hot) {
  const renderApp = render
  const renderError = (error) => {
    const RedBox = require('redbox-react')

    ReactDOM.render(<RedBox error={error} />, MOUNT_NODE)
  }
  render = () => {
    try {
      renderApp(Math.random())
    } catch (error) {
      renderError(error)
    }
  }
  module.hot.accept(['./routes/index'], () => render())
}

// ========================================================
// Go!
// ========================================================
render()
<|endoftext|>


<commit_before>import React from 'react';
import ReactDom from 'react-dom';
import {UltimatePagination} from 'react-ultimate-pagination';

ReactDom.render(<UltimatePagination currentPage={1} totalPages={10}/>, document.getElementById('main'));
<commit_msg>Add configuration form to an example<commit_after>import React from 'react';
import ReactDom from 'react-dom';
import {UltimatePagination} from 'react-ultimate-pagination';

class App extends React.Component {
  constructor() {
    super();

    this.onTotalPagesChange = this.onTotalPagesChange.bind(this);
    this.onCurrentPageChange = this.onCurrentPageChange.bind(this);

    this.state = {
      currentPage: 1,
      totalPages: 10
    };
  }

  onTotalPagesChange(event) {
    this.setState({totalPages: +event.target.value});
  }

  onCurrentPageChange(event) {
    this.setState({currentPage: +event.target.value});
  }

  render() {
    return (

          Total pages:
          <input
            type="number"
            id="totalPages"
            value={this.state.totalPages}
            min="1"
            onChange={this.onTotalPagesChange}
          />

          Current page:
          <input
            type="number"
            id="currentPage"
            value={this.state.currentPage}
            min="1"
            max={this.state.totalPages}
            onChange={this.onCurrentPageChange}
          />

        <UltimatePagination currentPage={this.state.currentPage} totalPages={this.state.totalPages}/>

    );
  }
}

ReactDom.render(<App />, document.getElementById('main'));
<|endoftext|>