<commit_before>window.requestAnimFrame = (function () {
    return window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            window.msRequestAnimationFrame ||
            function (/* function */ callback, /* DOMElement */ element) {
                window.setTimeout(callback, 1000 / 60);
            };
})();

Animation = function (spriteSheet, startX, startY, frameWidth, frameHeight, frameDuration, frames, loop, reverse) {
    this.spriteSheet = spriteSheet;
    this.startX = startX;
    this.startY = startY;
    this.frameWidth = frameWidth;
    this.frameHeight = frameHeight;
    this.frameDuration = frameDuration;
    this.frames = frames;
    this.totalTime = frameDuration * frames;
    this.elapsedTime = 0;
    this.loop = loop;
    this.reverse = reverse;
}

Animation.prototype.drawFrame = function (tick, context, x, y, scaleBy) {
    this.elapsedTime += tick;
    var scaleBy = scaleBy || 1;
    if (this.loop) {
        if (this.isDone()) {
            this.elapsedTime = 0;
        }
    } else if (this.isDone()) {
        return;
    }
    var index = 0;
    var that = this;
    if (this.reverse) {
        index = that.frames - that.currentFrame() - 1;
    } else {
        index = that.currentFrame();
    }

    var locX = x;
    var locY = y;
    context.drawImage(this.spriteSheet,
                      index * this.frameWidth, this.startY * this.frameHeight,
                      this.frameWidth, this.frameHeight,
                      locX, locY,
                      this.frameWidth * scaleBy, this.frameHeight * scaleBy);
}

Animation.prototype.currentFrame = function () {
    return Math.floor(this.elapsedTime / this.frameDuration);
}

Animation.prototype.isDone = function () {
    return (this.elapsedTime >= this.totalTime);
}

GameEngine = function () {
    this.entities = [];
    this.context = null;
    this.width = null;
    this.height = null;
    this.timer = null;
    this.key = null;
    this.space = null;
}

GameEngine.prototype.init = function (context) {
    this.context = context;
    this.width = this.context.canvas.width;
    this.height = this.context.canvas.height;
    this.timer = new Timer();
    this.startInput();
}

GameEngine.prototype.startInput = function () {
    var that = this;

    this.context.canvas.addEventListener('keydown', function (e) {
        if (String.fromCharCode(e.which) === ' ') {
            that.space = true;
            console.log('space');
        } else if (e.which === 37
                   || e.which === 38
                   || e.which === 39
                   || e.which === 40) {
            that.key = e.which;
            console.log('keydown');
        }
        e.preventDefault();
    }, false);

    this.context.canvas.addEventListener('keyup', function (e) {
        that.key = 0;
        that.space = 0;
    }, false);
}

GameEngine.prototype.start = function () {
    var that = this;
    (gameLoop = function () {
        that.loop();
        requestAnimationFrame(gameLoop, that.context.canvas);
    })();
}

GameEngine.prototype.addEntity = function (entity) {
    this.entities.push(entity);
}

GameEngine.prototype.draw = function (drawCallBack) {
    this.context.clearRect(0, 0, this.context.canvas.width, this.context.canvas.height);
    this.context.save();

    for (var i = 0; i < this.entities.length; i++) {
        this.entities[i].draw(this.context);
    }
    if (drawCallBack) {
        drawCallBack(this);
    }
    this.context.restore();
}

GameEngine.prototype.update = function () {
    for (var i = 0; i < this.entities.length; i++) {
        this.entities[i].update();
    }
}

GameEngine.prototype.loop = function () {
    this.clockTick = this.timer.tick();
    this.update();
    this.draw();
}

Timer = function () {
    this.gameTime = 0;
    this.maxStep = 0.5;
    this.lastTimeStep = 0;
}

Timer.prototype.tick = function () {
    var wallCurrent = Date.now();
    var wallDelta = (wallCurrent - this.lastTimeStep) / 1000;
    this.lastTimeStep = wallCurrent;

    var gameDelta = Math.min(wallDelta, this.maxStep);
    this.gameTime += gameDelta;
    return gameDelta;
}

var Direction = {
    UP: { value: "up", code: 38 },
    LEFT: { value: "left", code: 37 },
    DOWN: { value: "down", code: 40 },
    RIGHT: { value: "right", code: 39 }
}
Object.freeze(Direction);

/* ENTITY - Super class to the heroes, npcs, and enemies. */
Entity = function (game, x, y, spriteSheet, animations) {
    this.game = game;
    this.x = x;
    this.y = y;
    this.direction = Direction.DOWN;
    this.moveRight = true;
    this.health;
    this.spriteSheet = spriteSheet;
    if (animations) {
        this.animations = animations;
        this.move_animation = this.animations.down;
        this.stop_move_animation = this.stopAnimation(this.move_animation);
    }
}

Entity.prototype.changeMoveAnimation = function () {
    switch (this.direction) {
        case Direction.DOWN:
            this.move_animation = this.animations.down;
            break;
        case Direction.UP:
            this.move_animation = this.animations.up;
            break;
        case Direction.LEFT:
            this.move_animation = this.animations.left;
            break;
        case Direction.RIGHT:
            this.move_animation = this.animations.right;
            break;
    }
}

/* Changes the x and y coordinates of the entity depending on which direction they are travelling */
Entity.prototype.changeLocation = function (force_direction) { // force direction used for NPCS. leave param empty for user-controlled characters
    if (force_direction) {

    } else {
        if (this.game.key !== 0 && this.game.key !== null) {
            switch (this.direction) {
                case Direction.DOWN:
                    this.y += 2;
                    break;
                case Direction.UP:
                    this.y -= 2;
                    break;
                case Direction.LEFT:
                    this.x -= 2;
                    break;
                case Direction.RIGHT:
                    this.x += 2;
                    break;
            }
        } else {
            this.stop_move_animation = this.stopAnimation(this.move_animation);
        }
    }
}

/* Tells the entity what direction they should face depending on what key was pressed. */
Entity.prototype.changeDirection = function () {
    if (this.game.space) {
        // code for selecting something with the space bar. I don't think this will be necessary for the prototype.
    } else if (this.game.key === Direction.LEFT.code) {
        this.direction = Direction.LEFT;
    } else if (this.game.key === Direction.UP.code) {
        this.direction = Direction.UP;
    } else if (this.game.key === Direction.RIGHT.code) {
        this.direction = Direction.RIGHT;
    } else if (this.game.key === Direction.DOWN.code) {
        this.direction = Direction.DOWN;
    }
}

/* Returns the last frame of the last animation used, this is used to show the character stopped but still in the last position of the last
    animation. */
Entity.prototype.stopAnimation = function (animation) {
    return new Animation(this.spriteSheet, animation.currentFrame(), animation.startY, animation.frameWidth, animation.frameHeight, animation.frameDuration, 1, true, false);
}

Entity.prototype.draw = function (context) {
    if (this.game.key !== 0 && this.game.key !== null) {
        this.move_animation.drawFrame(this.game.clockTick, context, this.x, this.y, 0.75);
    } else {
        this.stop_move_animation.drawFrame(this.game.clockTick, context, this.x, this.y, 0.75);
    }
}

Entity.prototype.update = function () {
    this.changeDirection();
    this.changeMoveAnimation();
    this.changeLocation();
}

Entity.prototype.reset = function () {

}

Statistics = function (health, attack, defense) {
    this.health = health;
    this.attack = attack;
    this.defense = defense;
}
/* HERO subclasses */

Warrior = function (game) {
    this.game = game;
    this.spriteSheet = ASSET_MANAGER.getAsset("./imgs/warrior.png");
    this.animations = {
        down: new Animation(this.spriteSheet, 0, 10, 64, 64, 0.05, 9, true, false),
        up: new Animation(this.spriteSheet, 0, 8, 64, 64, 0.05, 9, true, false),
        left: new Animation(this.spriteSheet, 0, 9, 64, 64, 0.05, 9, true, false),
        right: new Animation(this.spriteSheet, 0, 11, 64, 64, 0.05, 9, true, false)
    };
    this.x = 50;
    this.y = 50;
    //var stats = new Statistics(50, 20, 10);
    Entity.call(this, game, this.x, this.y, this.spriteSheet, this.animations);
}

Warrior.prototype = new Entity();
Warrior.prototype.constructor = Warrior;

Warrior.prototype.draw = function (context) {
    Entity.prototype.draw.call(this, context);
}

Warrior.prototype.update = function () {
    Entity.prototype.update.call(this);
}

/* ENEMY and subclasses */
Enemy = function (game) {
    this.game = game;
    this.spriteSheet = ASSET_MANAGER.getAsset("./imgs/skeleton.png");
    this.x = 50;
    this.y = 50;
    //this.attackAnimation = new Animation(this.spriteSheet, )
    Entity.call(this, game, this.x, this.y, this.spriteSheet);
}

Enemy.prototype = new Entity();
Enemy.prototype.constructor = Enemy;

Enemy.prototype.draw = function (context) {
    Entity.prototype.draw.call(this, context);
}
Enemy.prototype.update = function () {
    Entity.prototype.update.call(this);
}

Enemy.prototype.attack = function () {

}

/* NPC */

/* BACKGROUND */
Background = function () {
    // "Map" will be a double array of integer values. Each value will correspond to a map tile.
    // "Tiles" will be a key/value mapping. The key will be the integer described above, and the value will be the image of the
    // tile associated with it taken from our condensed tile sheet.
    this.Map = [[]];
    this.Tiles = {};
}

/* Reads a text file that has integers corresponding to map tiles, reads them, and initializes the Map array with the numbers.
    This text file should have rows and columns that match the number of rows and columns of tiles on the map. */
Background.prototype.initializeMap = function (text_file) {

}

/* Loop over Tile sheet found in asset manager, assign an integer to each one and add to Tile object */
Background.prototype.initializeTiles = function () {
    // Tile object might look something like {1: <img>, 2: <img>, 3: <img> ... etc} where the img a tile from the tile sheet.
}

/* Loops over double array called Map, then draws the image of the tile associated with the integer in the map array.
    example: Map[0][0] has a 1, in the Tiles object, 1 is associated with the grass tile, draw the grass tile from 0,0, to 32,32 (or whatever
    size the tile is. */
Background.prototype.draw = function (context) {

}

/* Updates any tiles that need to be animated, such as a door opening. */
Background.prototype.update = function () {

}

<commit_msg>edited a comment<commit_after>window.requestAnimFrame = (function () {
    return window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            window.msRequestAnimationFrame ||
            function (/* function */ callback, /* DOMElement */ element) {
                window.setTimeout(callback, 1000 / 60);
            };
})();

Animation = function (spriteSheet, startX, startY, frameWidth, frameHeight, frameDuration, frames, loop, reverse) {
    this.spriteSheet = spriteSheet;
    this.startX = startX;
    this.startY = startY;
    this.frameWidth = frameWidth;
    this.frameHeight = frameHeight;
    this.frameDuration = frameDuration;
    this.frames = frames;
    this.totalTime = frameDuration * frames;
    this.elapsedTime = 0;
    this.loop = loop;
    this.reverse = reverse;
}

Animation.prototype.drawFrame = function (tick, context, x, y, scaleBy) {
    this.elapsedTime += tick;
    var scaleBy = scaleBy || 1;
    if (this.loop) {
        if (this.isDone()) {
            this.elapsedTime = 0;
        }
    } else if (this.isDone()) {
        return;
    }
    var index = 0;
    var that = this;
    if (this.reverse) {
        index = that.frames - that.currentFrame() - 1;
    } else {
        index = that.currentFrame();
    }

    var locX = x;
    var locY = y;
    context.drawImage(this.spriteSheet,
                      index * this.frameWidth, this.startY * this.frameHeight,
                      this.frameWidth, this.frameHeight,
                      locX, locY,
                      this.frameWidth * scaleBy, this.frameHeight * scaleBy);
}

Animation.prototype.currentFrame = function () {
    return Math.floor(this.elapsedTime / this.frameDuration);
}

Animation.prototype.isDone = function () {
    return (this.elapsedTime >= this.totalTime);
}

GameEngine = function () {
    this.entities = [];
    this.context = null;
    this.width = null;
    this.height = null;
    this.timer = null;
    this.key = null;
    this.space = null;
}

GameEngine.prototype.init = function (context) {
    this.context = context;
    this.width = this.context.canvas.width;
    this.height = this.context.canvas.height;
    this.timer = new Timer();
    this.startInput();
}

GameEngine.prototype.startInput = function () {
    var that = this;

    this.context.canvas.addEventListener('keydown', function (e) {
        if (String.fromCharCode(e.which) === ' ') {
            that.space = true;
            console.log('space');
        } else if (e.which === 37
                   || e.which === 38
                   || e.which === 39
                   || e.which === 40) {
            that.key = e.which;
            console.log('keydown');
        }
        e.preventDefault();
    }, false);

    this.context.canvas.addEventListener('keyup', function (e) {
        that.key = 0;
        that.space = 0;
    }, false);
}

GameEngine.prototype.start = function () {
    var that = this;
    (gameLoop = function () {
        that.loop();
        requestAnimationFrame(gameLoop, that.context.canvas);
    })();
}

GameEngine.prototype.addEntity = function (entity) {
    this.entities.push(entity);
}

GameEngine.prototype.draw = function (drawCallBack) {
    this.context.clearRect(0, 0, this.context.canvas.width, this.context.canvas.height);
    this.context.save();

    for (var i = 0; i < this.entities.length; i++) {
        this.entities[i].draw(this.context);
    }
    if (drawCallBack) {
        drawCallBack(this);
    }
    this.context.restore();
}

GameEngine.prototype.update = function () {
    for (var i = 0; i < this.entities.length; i++) {
        this.entities[i].update();
    }
}

GameEngine.prototype.loop = function () {
    this.clockTick = this.timer.tick();
    this.update();
    this.draw();
}

Timer = function () {
    this.gameTime = 0;
    this.maxStep = 0.5;
    this.lastTimeStep = 0;
}

Timer.prototype.tick = function () {
    var wallCurrent = Date.now();
    var wallDelta = (wallCurrent - this.lastTimeStep) / 1000;
    this.lastTimeStep = wallCurrent;

    var gameDelta = Math.min(wallDelta, this.maxStep);
    this.gameTime += gameDelta;
    return gameDelta;
}

var Direction = {
    UP: { value: "up", code: 38 },
    LEFT: { value: "left", code: 37 },
    DOWN: { value: "down", code: 40 },
    RIGHT: { value: "right", code: 39 }
}
Object.freeze(Direction);

/* ENTITY - Super class to the heroes, npcs, and enemies. */
Entity = function (game, x, y, spriteSheet, animations) {
    this.game = game;
    this.x = x;
    this.y = y;
    this.direction = Direction.DOWN;
    this.moveRight = true;
    this.health;
    this.spriteSheet = spriteSheet;
    if (animations) {
        this.animations = animations;
        this.move_animation = this.animations.down;
        this.stop_move_animation = this.stopAnimation(this.move_animation);
    }
}

Entity.prototype.changeMoveAnimation = function () {
    switch (this.direction) {
        case Direction.DOWN:
            this.move_animation = this.animations.down;
            break;
        case Direction.UP:
            this.move_animation = this.animations.up;
            break;
        case Direction.LEFT:
            this.move_animation = this.animations.left;
            break;
        case Direction.RIGHT:
            this.move_animation = this.animations.right;
            break;
    }
}

/* Changes the x and y coordinates of the entity depending on which direction they are travelling */
Entity.prototype.changeLocation = function (force_direction) { // force direction used for NPCS. leave param empty for user-controlled characters
    if (force_direction) {

    } else {
        if (this.game.key !== 0 && this.game.key !== null) {
            switch (this.direction) {
                case Direction.DOWN:
                    this.y += 2;
                    break;
                case Direction.UP:
                    this.y -= 2;
                    break;
                case Direction.LEFT:
                    this.x -= 2;
                    break;
                case Direction.RIGHT:
                    this.x += 2;
                    break;
            }
        } else {
            this.stop_move_animation = this.stopAnimation(this.move_animation);
        }
    }
}

/* Tells the entity what direction they should face depending on what key was pressed. */
Entity.prototype.changeDirection = function () {
    if (this.game.space) {
        // code for selecting something with the space bar. I don't think this will be necessary for the prototype.
    } else if (this.game.key === Direction.LEFT.code) {
        this.direction = Direction.LEFT;
    } else if (this.game.key === Direction.UP.code) {
        this.direction = Direction.UP;
    } else if (this.game.key === Direction.RIGHT.code) {
        this.direction = Direction.RIGHT;
    } else if (this.game.key === Direction.DOWN.code) {
        this.direction = Direction.DOWN;
    }
}

/* Returns the last frame of the last animation used, this is used to show the character stopped but still in the last position of the last
    animation. */
Entity.prototype.stopAnimation = function (animation) {
    return new Animation(this.spriteSheet, animation.currentFrame(), animation.startY, animation.frameWidth, animation.frameHeight, animation.frameDuration, 1, true, false);
}

Entity.prototype.draw = function (context) {
    if (this.game.key !== 0 && this.game.key !== null) {
        this.move_animation.drawFrame(this.game.clockTick, context, this.x, this.y, 0.75);
    } else {
        this.stop_move_animation.drawFrame(this.game.clockTick, context, this.x, this.y, 0.75);
    }
}

Entity.prototype.update = function () {
    this.changeDirection();
    this.changeMoveAnimation();
    this.changeLocation();
}

Entity.prototype.reset = function () {

}

Statistics = function (health, attack, defense) {
    this.health = health;
    this.attack = attack;
    this.defense = defense;
}
/* HERO subclasses */

Warrior = function (game) {
    this.game = game;
    this.spriteSheet = ASSET_MANAGER.getAsset("./imgs/warrior.png");
    this.animations = {
        down: new Animation(this.spriteSheet, 0, 10, 64, 64, 0.05, 9, true, false),
        up: new Animation(this.spriteSheet, 0, 8, 64, 64, 0.05, 9, true, false),
        left: new Animation(this.spriteSheet, 0, 9, 64, 64, 0.05, 9, true, false),
        right: new Animation(this.spriteSheet, 0, 11, 64, 64, 0.05, 9, true, false)
    };
    this.x = 50;
    this.y = 50;
    //var stats = new Statistics(50, 20, 10);
    Entity.call(this, game, this.x, this.y, this.spriteSheet, this.animations);
}

Warrior.prototype = new Entity();
Warrior.prototype.constructor = Warrior;

Warrior.prototype.draw = function (context) {
    Entity.prototype.draw.call(this, context);
}

Warrior.prototype.update = function () {
    Entity.prototype.update.call(this);
}

/* ENEMY and subclasses */
Enemy = function (game) {
    this.game = game;
    this.spriteSheet = ASSET_MANAGER.getAsset("./imgs/skeleton.png");
    this.x = 50;
    this.y = 50;
    //this.attackAnimation = new Animation(this.spriteSheet, )
    Entity.call(this, game, this.x, this.y, this.spriteSheet);
}

Enemy.prototype = new Entity();
Enemy.prototype.constructor = Enemy;

Enemy.prototype.draw = function (context) {
    Entity.prototype.draw.call(this, context);
}
Enemy.prototype.update = function () {
    Entity.prototype.update.call(this);
}

Enemy.prototype.attack = function () {

}

/* NPC */

/* BACKGROUND */
Background = function () {
    // "Map" will be a double array of integer values. Each value will correspond to a map tile.
    // "Tiles" will be a key/value mapping. The key will be the integer described above, and the value will be the image of the
    // tile associated with it taken from our condensed tile sheet.
    this.Map = [[]];
    this.Tiles = {};
}

/* Reads a text file that has integers corresponding to map tiles, reads them, and initializes the Map array with the numbers.
    This text file should have rows and columns that match the number of rows and columns of tiles on the map. */
Background.prototype.initializeMap = function (text_file) {

}

/* Loop over Tile sheet found in asset manager, assign an integer to each one and add to Tile object */
Background.prototype.initializeTiles = function () {
    // Tile object might look something like {1: <img>, 2: <img>, 3: <img> ... etc} where the img is a tile from the tile sheet.
}

/* Loops over double array called Map, then draws the image of the tile associated with the integer in the map array.
    example: Map[0][0] has a 1, in the Tiles object, 1 is associated with the grass tile, draw the grass tile from 0,0, to 32,32 (or whatever
    size the tile is. */
Background.prototype.draw = function (context) {

}

/* Updates any tiles that need to be animated, such as a door opening. */
Background.prototype.update = function () {

}

<|endoftext|>


<commit_before>(function() {

  /**
   * manages all the wizards which render carto
   */
  cdb.admin.mod.CartoWizard = cdb.core.View.extend({

    events: {
      'click  .vis_options a':    '_updateNavigation',
      'click  .wizard_arrows a':  '_onArrowClick'
    },

    initialize: function() {
      _.bindAll(this, '_updateNavigation');

      var self = this;
      self.active = false;
      this.cartoStylesGeneration = new cdb.admin.CartoStyles({
        table: this.options.table
      });

      this.model.bind('change:wizard_properties', this._updateForms, this);

      this.position = 0; // Navigation bar
      this.tabs = new cdb.admin.Tabs();
      this.panels = new cdb.ui.common.TabPane();
      this.addView(this.tabs);
      this.addView(this.panels);
      this.tabs.linkToPanel(this.panels);

      this.tabs.bind('click', this._applyStyle, this);
    },

    _updateForms: function() {
      var self = this;
      if (self.model.get('wizard_properties')) {
        var wizard = self.model.get('wizard_properties');
        var type = wizard.type;
        var p = self.panels.getPane(type);
        if(p) {
          p.setCarpropertiesSilent(wizard.properties);
          self.panels.active(type);
        }
      }
    },

    _onArrowClick: function(ev) {
      this.killEvent(ev);
      var $target = $(ev.target);

      if ($target.hasClass("disabled")) return false;

      var side = $target.attr('href').replace("#","");
      this._moveNavigation(side);
    },

    _updateNavigation: function(ev) {
      // // Get wizard type
      // var wizard    = this.model.get('wizard_properties')
      //   , type      = wizard.type
      //   , $li       = this.$el.find('li a[href="#' + type + '"]').parent()
      //   , new_pos   = $li.index()
      //   , count     = (Math.abs(this.position - new_pos))
      //   , side      = (this.position > new_pos) ? 'left' : 'right';

      // if (count > 0)
      //   this._moveNavigation(side,count);
    },

    _moveNavigation: function(side) {
      if (this.animation) return false;

      var $ul         = this.$el.find("ul.vis_options")
        , gap         = 3
        , list_size   = $ul.find("li").size()
        , move        = $ul.find("li").outerWidth() || 100
        , block_width = $ul.parent().outerWidth() || 380
        , list_width  = list_size * (move + 5/*margin*/)
        , left        = parseInt($ul.css("left").replace("px","")) || 0
        , $right      = this.$el.find('a.right')
        , $left       = this.$el.find('a.left')
        , self        = this;

      // if the list is smaller than the block, we disable the buttons and return
      if (block_width  > list_width ) {
        $left.addClass("disabled");
        $right.addClass("disabled");
        return false
      }

      // Check move
      if (side == "left") {
        if (-(left) < move) {
          move = -left;
        }
        this.position--;
      } else {
        if ((block_width - left) >= list_width) {
          return false;
        } else if ((list_width + left) < move) {
          move = list_width + left;
        }
        this.position++;
      }
      // Check arrows
      if (this.position + gap >= list_size) {
        $right.addClass("disabled");
      } else {
        $right.removeClass("disabled");
      }
      if (this.position==0) {
        $left.addClass("disabled");
      } else {
        $left.removeClass("disabled");
      }
      // Go side
      this.animation = true;
      if (side == "left") {
        $ul.animate({
          'left': '+=' + move + 'px'
        }, 200, function() { self.animation = false; });
      } else {
        $ul.animate({
          left: '-=' + move + 'px'
        }, 200, function() { self.animation = false; });
      }
    },

    _setThumbnails: function() {
      var classes = this.options.table.geomColumnTypes().join("-");
      this.$el.find('.vis_options li a').each(function(i,el){
        $(el).addClass(classes);
      });
    },

    activated: function() {
      var self = this;

      self.active = true;

      // do the same with layer style, if user changes the style too fast
      // lots of tiles are requested to the tile server
      var changeLayerStyle = _.debounce(function(st, sql) {
        var attrs = {
          wizard_properties: self.cartoStylesGeneration.toJSON()
        };
        if(sql) {
          attrs.query =  sql;
          attrs.query_generated = true;
        } else {
          if(self.model.get('query_generated')) {
            attrs.query = null;
            attrs.query_generated = false;
          }
        }
        self.model.set(attrs, {silent: true} );
        self.model.save({tile_style: st}, { wait: true });
      }, 600);

      // this is the sole entry point where the cartocss is changed.
      // wizards only should change cartoStylesGeneration model
      this.cartoStylesGeneration.bind('change:style change:sql', function() {
        changeLayerStyle(
          self.cartoStylesGeneration.get('style'),
          self.cartoStylesGeneration.get('sql')
        );
      }, this);
    },

    deactivated: function() {
      this.active = false;
      this.cartoStylesGeneration.unbind(null, null, this);
    },

    _applyStyle: function(name) {
      this.panels.getActivePane().cartoProperties.trigger('change');//change();
    },

    // depending on the geometry type some wizards should be disabled
    enableTabs: function() {
      var _enableMap = {
        'point': ['polygon', 'bubble', 'density'],
        'line':['polygon', 'choropleth', 'bubble'],
        'polygon': ['polygon', 'choropleth', 'bubble']
      };

      this.tabs.disableAll();

      // enable the wizard suitable for the current geom types
      var geomTypes = this.options.table.geomColumnTypes();
      for(var g in geomTypes) {
        var type = geomTypes[g];
        var toEnable = _enableMap[type];
        for(var e in toEnable) {
          this.tabs.enable(toEnable[e]);
        }
      }

      // we remove the disabled ones and trigger movement to recalculate the arrows
      this.tabs.removeDisabled();
      this._moveNavigation('left');
    },

    render: function() {
      this.$el.append(this.getTemplate('table/menu_modules/views/carto_wizard')());
      this.tabs.setElement(this.$('ul.vis_options'));
      this.panels.setElement(this.$('.forms'));

      // apply tipsy for nav - a
      this.$('ul.vis_options li a').each(function(i,ele) {
        $(ele).tipsy({ gravity: 's', fade: true });
      });

      // render the wizards
      this.panels.addTab('polygon', new SimpleWizard({
        table: this.options.table,
        model: this.cartoStylesGeneration,
        style: this.model.get('style')
      }).render());

      this.panels.addTab('bubble', new BubbleWizard({
        model: this.cartoStylesGeneration,
        table: this.options.table,
        style: this.model.get('style')
      }).render());

      this.panels.addTab('choropleth', new ChoroplethWizard({
        model: this.cartoStylesGeneration,
        table: this.options.table,
        style: this.model.get('style')
      }).render());

      this.panels.addTab('density', new DensityWizard({
        model: this.cartoStylesGeneration,
        table: this.options.table,
        style: this.model.get('style')
      }).render());

      this.panels.active('polygon');
      this._updateForms();
      this.enableTabs();

      // var wizard = this.model.get('wizard_properties')
      //   , type = wizard.type;
      // this._updateNavigation(type);

      this._setThumbnails();
      window.aaa = this;
      return this;
    }

  });

  /**
   * simple wizard tab
   * take this as base for other wizards
   */
  var SimpleWizard = cdb.core.View.extend({

    initialize: function() {
      var self = this;
      this.cartoProperties = new cdb.core.Model();
      this.type = 'polygon';
      this.geomForm = cdb.admin.forms.simple_form[this.options.table.geomColumnTypes()[0]];
      this.setFormProperties();

      //TODO: change this when table support more than one geom type
      this.form = new cdb.forms.Form({
        form_data: this.options.form || this.geomForm,
        model: this.cartoProperties
      });
      this.addView(this.form);

      this._bindChanges();

      this.options.table.bind('change:schema', function() {
        this.setFormProperties();
        this.render();
      }, this);
    },

    _bindChanges: function() {
      var self = this;
      this.cartoProperties.bind('change', function() {
        self.model.set({
          type: self.type,
          properties: _.clone(self.cartoProperties.attributes),
          sql: null
        });
      }, this);
      this.cartoProperties.bind('change:text-name', this.showTextFields, this);
      this.cartoProperties.bind('change:marker-width', function(m, width) {
        this.cartoProperties.set('text-dy', -width);

      }, this);
    },

    showTextFields: function() {
      var self = this;
      var v = self.form.getFieldByName('Label Font');
      var vhalo = self.form.getFieldByName('Label Halo');
      if(self.cartoProperties.get('text-name') === 'None') {
        v && v.hide();
        vhalo && vhalo.hide();
      } else {
        v && v.show();
        vhalo && vhalo.show();
      }
    },

    _unbindChanges: function() {
      this.cartoProperties.unbind(null, null, this);
    },

    // changes properties WITHOUT updating the model, only refresh the
    // UI
    setCarpropertiesSilent: function(p) {
      this._unbindChanges();
      this.cartoProperties.set(p);
      this.showTextFields();
      this._bindChanges();
    },

    render: function() {
      this.$el.html('');

      var $wrapper = $("<div>").addClass("wrapper")
        , $content = $("<div>").addClass("content");

      $content.append(this.form.render().el);
      $wrapper.append($content);

      this.$el.append($wrapper)
      this.showTextFields();

      // Custom scroll actions! :)
      this.custom_scroll = new cdb.admin.CustomScrolls({
        el: $wrapper
      });
      this.addView(this.custom_scroll);

      return this;
    },

    setFormProperties: function() {
      var field = this._searchFieldByName('Label Text');
      if(field) {
        var b = field.form['text-name'].extra = ['None'].concat(this.options.table.columnNamesByType('string').concat(this.options.table.columnNamesByType('number')));
        field.form['text-name'].value = 'None';
      }
    },

    /**
     * search inside the source fields for the field by name.
     * Returns the field
     */
    _searchFieldByName: function(name) {
      return _.find(this.options.form || this.geomForm, function(f) {
        return f.name === name;
      });
    }

  });

  /**
   * bubble
   */
  var BubbleWizard = SimpleWizard.extend({

    initialize: function() {
      this.options.form = cdb.admin.forms.bubble_form;
      this.setFormProperties();
      SimpleWizard.prototype.initialize.call(this);

      this.type = 'bubble';

      this.add_related_model(this.options.table);
      this.options.table.bind('change:schema', function() {
        this.setFormProperties();
        if(!this.options.table.containsColumn(this.cartoProperties.get('property'))) {
          var columns =  this.options.table.columnNamesByType('number');
          if(columns.length) {
            this.cartoProperties.set({ 'property': columns[0] });
          }

        }
        this.render();
      }, this);
    },

    setFormProperties: function() {
      if(this.options && this.options.form && this.options.form.length > 0) {
        var b = this.options.form[0].form.property.extra = this.options.table.columnNamesByType('number');
        this.options.form[0].form.property.value = b[0];
        this.cartoStylesGeneration
      }
    }

  });

  cdb._BubbleWizard = BubbleWizard;

  /**
   * choropleth
   */
  var ChoroplethWizard = SimpleWizard.extend({

    initialize: function() {
      this.options.form = cdb.admin.forms.choropleth[this.options.table.geomColumnTypes()[0]];
      this.setFormProperties();
      SimpleWizard.prototype.initialize.call(this);

      this.type = 'choropleth';

      this.add_related_model(this.options.table);
      this.options.table.bind('change:schema', function() {
        this.setFormProperties();
        if(!this.options.table.containsColumn(this.cartoProperties.get('property'))) {
          var columns =  this.options.table.columnNamesByType('number');
          if(columns.length) {
            this.cartoProperties.set({ 'property': columns[0] });
          }

        }
        this.render();
      }, this);
    },

    setFormProperties: function() {
      // If the table doesn't have any kind of geometry,
      // we avoid rendering the choroplethas

      if(this.options && this.options.form && this.options.form.length > 0) {
        var b = this.options.form[0].form.property.extra = this.options.table.columnNamesByType('number');
        this.options.form[0].form.property.value = b[0];
      }
    }

  });

  cdb._ChoroplethWizard = ChoroplethWizard;

  //cdb._BubbleWizard = BubbleWizard;
  var DensityWizard = SimpleWizard.extend({

    initialize: function() {
      this.options.form = cdb.admin.forms.density;
      SimpleWizard.prototype.initialize.call(this);

      this.type = 'density';

      this.add_related_model(this.options.table);
      this.options.table.bind('change:schema', function() {
        this.render();
      }, this);
    },

    _bindChanges: function() {
      var self = this;
      this.cartoProperties.bind('change', function() {
        var table = self.options.table;
        var prop = 'cartodb_id';

        if(this.cartoProperties.get('geometry_type') === 'Rectangles') {
          self.sql = _.template("WITH hgrid AS (SELECT CDB_RectangleGrid(ST_Expand(CDB_XYZ_Extent({x},{y},{z}), CDB_XYZ_Resolution({z}) * <%= size %>), CDB_XYZ_Resolution({z}) * <%= size %>, CDB_XYZ_Resolution({z}) * <%= size %>) as cell) SELECT hgrid.cell as the_geom_webmercator, count(i.<%=prop%>) as points_count FROM hgrid, <%= table_name %> i where ST_Intersects(i.the_geom_webmercator, hgrid.cell) GROUP BY hgrid.cell")({
            prop: prop,
            table: table.get('name'),
            size: this.cartoProperties.get('polygon-size')
          });

        } else {
          self.sql = _.template("WITH hgrid AS (SELECT CDB_HexagonGrid(ST_Expand(CDB_XYZ_Extent({x},{y},{z}), CDB_XYZ_Resolution({z}) * <%= size %>), CDB_XYZ_Resolution({z}) * <%= size %>) as cell) SELECT hgrid.cell as the_geom_webmercator, count(i.<%=prop%>) as points_count FROM hgrid, <%= table_name %> i where ST_Intersects(i.the_geom_webmercator, hgrid.cell) GROUP BY hgrid.cell")({
            prop: prop,
            table: table.get('name'),
            size: this.cartoProperties.get('polygon-size')
          });
        }
        self.model.set({
          type: self.type,
          properties: _.clone(self.cartoProperties.attributes),
          sql: self.sql
        });
      }, this);
    }
  });

})();
<commit_msg>fixed generated sql for grid<commit_after>(function() {

  /**
   * manages all the wizards which render carto
   */
  cdb.admin.mod.CartoWizard = cdb.core.View.extend({

    events: {
      'click  .vis_options a':    '_updateNavigation',
      'click  .wizard_arrows a':  '_onArrowClick'
    },

    initialize: function() {
      _.bindAll(this, '_updateNavigation');

      var self = this;
      self.active = false;
      this.cartoStylesGeneration = new cdb.admin.CartoStyles({
        table: this.options.table
      });

      this.model.bind('change:wizard_properties', this._updateForms, this);

      this.position = 0; // Navigation bar
      this.tabs = new cdb.admin.Tabs();
      this.panels = new cdb.ui.common.TabPane();
      this.addView(this.tabs);
      this.addView(this.panels);
      this.tabs.linkToPanel(this.panels);

      this.tabs.bind('click', this._applyStyle, this);
    },

    _updateForms: function() {
      var self = this;
      if (self.model.get('wizard_properties')) {
        var wizard = self.model.get('wizard_properties');
        var type = wizard.type;
        var p = self.panels.getPane(type);
        if(p) {
          p.setCarpropertiesSilent(wizard.properties);
          self.panels.active(type);
        }
      }
    },

    _onArrowClick: function(ev) {
      this.killEvent(ev);
      var $target = $(ev.target);

      if ($target.hasClass("disabled")) return false;

      var side = $target.attr('href').replace("#","");
      this._moveNavigation(side);
    },

    _updateNavigation: function(ev) {
      // // Get wizard type
      // var wizard    = this.model.get('wizard_properties')
      //   , type      = wizard.type
      //   , $li       = this.$el.find('li a[href="#' + type + '"]').parent()
      //   , new_pos   = $li.index()
      //   , count     = (Math.abs(this.position - new_pos))
      //   , side      = (this.position > new_pos) ? 'left' : 'right';

      // if (count > 0)
      //   this._moveNavigation(side,count);
    },

    _moveNavigation: function(side) {
      if (this.animation) return false;

      var $ul         = this.$el.find("ul.vis_options")
        , gap         = 3
        , list_size   = $ul.find("li").size()
        , move        = $ul.find("li").outerWidth() || 100
        , block_width = $ul.parent().outerWidth() || 380
        , list_width  = list_size * (move + 5/*margin*/)
        , left        = parseInt($ul.css("left").replace("px","")) || 0
        , $right      = this.$el.find('a.right')
        , $left       = this.$el.find('a.left')
        , self        = this;

      // if the list is smaller than the block, we disable the buttons and return
      if (block_width  > list_width ) {
        $left.addClass("disabled");
        $right.addClass("disabled");
        return false
      }

      // Check move
      if (side == "left") {
        if (-(left) < move) {
          move = -left;
        }
        this.position--;
      } else {
        if ((block_width - left) >= list_width) {
          return false;
        } else if ((list_width + left) < move) {
          move = list_width + left;
        }
        this.position++;
      }
      // Check arrows
      if (this.position + gap >= list_size) {
        $right.addClass("disabled");
      } else {
        $right.removeClass("disabled");
      }
      if (this.position==0) {
        $left.addClass("disabled");
      } else {
        $left.removeClass("disabled");
      }
      // Go side
      this.animation = true;
      if (side == "left") {
        $ul.animate({
          'left': '+=' + move + 'px'
        }, 200, function() { self.animation = false; });
      } else {
        $ul.animate({
          left: '-=' + move + 'px'
        }, 200, function() { self.animation = false; });
      }
    },

    _setThumbnails: function() {
      var classes = this.options.table.geomColumnTypes().join("-");
      this.$el.find('.vis_options li a').each(function(i,el){
        $(el).addClass(classes);
      });
    },

    activated: function() {
      var self = this;

      self.active = true;

      // do the same with layer style, if user changes the style too fast
      // lots of tiles are requested to the tile server
      var changeLayerStyle = _.debounce(function(st, sql) {
        var attrs = {
          wizard_properties: self.cartoStylesGeneration.toJSON()
        };
        if(sql) {
          attrs.query =  sql;
          attrs.query_generated = true;
        } else {
          if(self.model.get('query_generated')) {
            attrs.query = null;
            attrs.query_generated = false;
          }
        }
        self.model.set(attrs, {silent: true} );
        self.model.save({tile_style: st}, { wait: true });
      }, 600);

      // this is the sole entry point where the cartocss is changed.
      // wizards only should change cartoStylesGeneration model
      this.cartoStylesGeneration.bind('change:style change:sql', function() {
        changeLayerStyle(
          self.cartoStylesGeneration.get('style'),
          self.cartoStylesGeneration.get('sql')
        );
      }, this);
    },

    deactivated: function() {
      this.active = false;
      this.cartoStylesGeneration.unbind(null, null, this);
    },

    _applyStyle: function(name) {
      this.panels.getActivePane().cartoProperties.trigger('change');//change();
    },

    // depending on the geometry type some wizards should be disabled
    enableTabs: function() {
      var _enableMap = {
        'point': ['polygon', 'bubble', 'density'],
        'line':['polygon', 'choropleth', 'bubble'],
        'polygon': ['polygon', 'choropleth', 'bubble']
      };

      this.tabs.disableAll();

      // enable the wizard suitable for the current geom types
      var geomTypes = this.options.table.geomColumnTypes();
      for(var g in geomTypes) {
        var type = geomTypes[g];
        var toEnable = _enableMap[type];
        for(var e in toEnable) {
          this.tabs.enable(toEnable[e]);
        }
      }

      // we remove the disabled ones and trigger movement to recalculate the arrows
      this.tabs.removeDisabled();
      this._moveNavigation('left');
    },

    render: function() {
      this.$el.append(this.getTemplate('table/menu_modules/views/carto_wizard')());
      this.tabs.setElement(this.$('ul.vis_options'));
      this.panels.setElement(this.$('.forms'));

      // apply tipsy for nav - a
      this.$('ul.vis_options li a').each(function(i,ele) {
        $(ele).tipsy({ gravity: 's', fade: true });
      });

      // render the wizards
      this.panels.addTab('polygon', new SimpleWizard({
        table: this.options.table,
        model: this.cartoStylesGeneration,
        style: this.model.get('style')
      }).render());

      this.panels.addTab('bubble', new BubbleWizard({
        model: this.cartoStylesGeneration,
        table: this.options.table,
        style: this.model.get('style')
      }).render());

      this.panels.addTab('choropleth', new ChoroplethWizard({
        model: this.cartoStylesGeneration,
        table: this.options.table,
        style: this.model.get('style')
      }).render());

      this.panels.addTab('density', new DensityWizard({
        model: this.cartoStylesGeneration,
        table: this.options.table,
        style: this.model.get('style')
      }).render());

      this.panels.active('polygon');
      this._updateForms();
      this.enableTabs();

      // var wizard = this.model.get('wizard_properties')
      //   , type = wizard.type;
      // this._updateNavigation(type);

      this._setThumbnails();
      window.aaa = this;
      return this;
    }

  });

  /**
   * simple wizard tab
   * take this as base for other wizards
   */
  var SimpleWizard = cdb.core.View.extend({

    initialize: function() {
      var self = this;
      this.cartoProperties = new cdb.core.Model();
      this.type = 'polygon';
      this.geomForm = cdb.admin.forms.simple_form[this.options.table.geomColumnTypes()[0]];
      this.setFormProperties();

      //TODO: change this when table support more than one geom type
      this.form = new cdb.forms.Form({
        form_data: this.options.form || this.geomForm,
        model: this.cartoProperties
      });
      this.addView(this.form);

      this._bindChanges();

      this.options.table.bind('change:schema', function() {
        this.setFormProperties();
        this.render();
      }, this);
    },

    _bindChanges: function() {
      var self = this;
      this.cartoProperties.bind('change', function() {
        self.model.set({
          type: self.type,
          properties: _.clone(self.cartoProperties.attributes),
          sql: null
        });
      }, this);
      this.cartoProperties.bind('change:text-name', this.showTextFields, this);
      this.cartoProperties.bind('change:marker-width', function(m, width) {
        this.cartoProperties.set('text-dy', -width);

      }, this);
    },

    showTextFields: function() {
      var self = this;
      var v = self.form.getFieldByName('Label Font');
      var vhalo = self.form.getFieldByName('Label Halo');
      if(self.cartoProperties.get('text-name') === 'None') {
        v && v.hide();
        vhalo && vhalo.hide();
      } else {
        v && v.show();
        vhalo && vhalo.show();
      }
    },

    _unbindChanges: function() {
      this.cartoProperties.unbind(null, null, this);
    },

    // changes properties WITHOUT updating the model, only refresh the
    // UI
    setCarpropertiesSilent: function(p) {
      this._unbindChanges();
      this.cartoProperties.set(p);
      this.showTextFields();
      this._bindChanges();
    },

    render: function() {
      this.$el.html('');

      var $wrapper = $("<div>").addClass("wrapper")
        , $content = $("<div>").addClass("content");

      $content.append(this.form.render().el);
      $wrapper.append($content);

      this.$el.append($wrapper)
      this.showTextFields();

      // Custom scroll actions! :)
      this.custom_scroll = new cdb.admin.CustomScrolls({
        el: $wrapper
      });
      this.addView(this.custom_scroll);

      return this;
    },

    setFormProperties: function() {
      var field = this._searchFieldByName('Label Text');
      if(field) {
        var b = field.form['text-name'].extra = ['None'].concat(this.options.table.columnNamesByType('string').concat(this.options.table.columnNamesByType('number')));
        field.form['text-name'].value = 'None';
      }
    },

    /**
     * search inside the source fields for the field by name.
     * Returns the field
     */
    _searchFieldByName: function(name) {
      return _.find(this.options.form || this.geomForm, function(f) {
        return f.name === name;
      });
    }

  });

  /**
   * bubble
   */
  var BubbleWizard = SimpleWizard.extend({

    initialize: function() {
      this.options.form = cdb.admin.forms.bubble_form;
      this.setFormProperties();
      SimpleWizard.prototype.initialize.call(this);

      this.type = 'bubble';

      this.add_related_model(this.options.table);
      this.options.table.bind('change:schema', function() {
        this.setFormProperties();
        if(!this.options.table.containsColumn(this.cartoProperties.get('property'))) {
          var columns =  this.options.table.columnNamesByType('number');
          if(columns.length) {
            this.cartoProperties.set({ 'property': columns[0] });
          }

        }
        this.render();
      }, this);
    },

    setFormProperties: function() {
      if(this.options && this.options.form && this.options.form.length > 0) {
        var b = this.options.form[0].form.property.extra = this.options.table.columnNamesByType('number');
        this.options.form[0].form.property.value = b[0];
        this.cartoStylesGeneration
      }
    }

  });

  cdb._BubbleWizard = BubbleWizard;

  /**
   * choropleth
   */
  var ChoroplethWizard = SimpleWizard.extend({

    initialize: function() {
      this.options.form = cdb.admin.forms.choropleth[this.options.table.geomColumnTypes()[0]];
      this.setFormProperties();
      SimpleWizard.prototype.initialize.call(this);

      this.type = 'choropleth';

      this.add_related_model(this.options.table);
      this.options.table.bind('change:schema', function() {
        this.setFormProperties();
        if(!this.options.table.containsColumn(this.cartoProperties.get('property'))) {
          var columns =  this.options.table.columnNamesByType('number');
          if(columns.length) {
            this.cartoProperties.set({ 'property': columns[0] });
          }

        }
        this.render();
      }, this);
    },

    setFormProperties: function() {
      // If the table doesn't have any kind of geometry,
      // we avoid rendering the choroplethas

      if(this.options && this.options.form && this.options.form.length > 0) {
        var b = this.options.form[0].form.property.extra = this.options.table.columnNamesByType('number');
        this.options.form[0].form.property.value = b[0];
      }
    }

  });

  cdb._ChoroplethWizard = ChoroplethWizard;

  //cdb._BubbleWizard = BubbleWizard;
  var DensityWizard = SimpleWizard.extend({

    initialize: function() {
      this.options.form = cdb.admin.forms.density;
      SimpleWizard.prototype.initialize.call(this);

      this.type = 'density';

      this.add_related_model(this.options.table);
      this.options.table.bind('change:schema', function() {
        this.render();
      }, this);
    },

    _bindChanges: function() {
      var self = this;
      this.cartoProperties.bind('change', function() {
        var table = self.options.table;
        var prop = 'cartodb_id';

        if(this.cartoProperties.get('geometry_type') === 'Rectangles') {
          self.sql = _.template("WITH hgrid AS (SELECT CDB_RectangleGrid(ST_Expand(CDB_XYZ_Extent({x},{y},{z}), CDB_XYZ_Resolution({z}) * <%= size %>), CDB_XYZ_Resolution({z}) * <%= size %>, CDB_XYZ_Resolution({z}) * <%= size %>) as cell) SELECT hgrid.cell as the_geom_webmercator, count(i.<%=prop%>) as points_count, 1 as cartodb_id FROM hgrid, <%= table_name %> i where ST_Intersects(i.the_geom_webmercator, hgrid.cell) GROUP BY hgrid.cell")({
            prop: prop,
            table: table.get('name'),
            size: this.cartoProperties.get('polygon-size')
          });

        } else {
          self.sql = _.template("WITH hgrid AS (SELECT CDB_HexagonGrid(ST_Expand(CDB_XYZ_Extent({x},{y},{z}), CDB_XYZ_Resolution({z}) * <%= size %>), CDB_XYZ_Resolution({z}) * <%= size %>) as cell) SELECT hgrid.cell as the_geom_webmercator, count(i.<%=prop%>) as points_count, 1 as cartodb_id FROM hgrid, <%= table_name %> i where ST_Intersects(i.the_geom_webmercator, hgrid.cell) GROUP BY hgrid.cell")({
            prop: prop,
            table: table.get('name'),
            size: this.cartoProperties.get('polygon-size')
          });
        }
        self.model.set({
          type: self.type,
          properties: _.clone(self.cartoProperties.attributes),
          sql: self.sql
        });
      }, this);
    }
  });

})();
<|endoftext|>


<commit_before>var os = require('os');

var Sem, Name, Batch, Examination, Institution, InstitutionCode, final = [], len = 0;	// Globals for same set of students.
var currentSubjects = [];	// Stores the names and subject codes for current set of students.
var previousResult = {};

module.exports = function (data, subjectArray, db, cb) {
	var regexForStudentsLinux = /\d{11}([^]*?)\n\w\w?\*?(\(..?\))?\n\w\w?\n/g;
	var regexForStudentsWindows = /\n\d{11}([^]*?)\n\w\w?\*?(\(..?\))?\r\n\w\w?\r/g;
	// console.log(data)
	// process.exit()
	var regexForStudents;
	if (os.platform() === 'linux') {
		regexForStudents = regexForStudentsLinux;
	} else {
		regexForStudents = regexForStudentsWindows;
	}
	data.forEach((students) => {
		// console.log(students)
		var studentList = students.match(regexForStudents);
		if (studentList) {
			studentList = studentList.map((ele) => (ele.split(os.EOL)));
			// console.log(studentList)
			Sem = students.match(/Sem\.\/Year: (\d+)/)[1];
			Name = students.match(/Programme Name: ([^]*?) Sem/)[1];
			if (students.match(/Batch: ([^]*?) Exa/)) {
				Batch = students.match(/Batch: ([^]*?) Exa/)[1];
				// if (parseInt(Batch) < 2013) {
				// 	return;
				// }
			} else {
				return;
			}
			// Institution = students.match(/Institution: ([^]*?)\r/)[1];
			Institution = students.match(new RegExp('Institution: ([^]*?)' + os.EOL))[1];
			InstitutionCode = students.match(/Institution Code: (\d+)/)[1];
			// Examination = students.match(/Examination: ([^]*?)\r\n/)[1];
			Examination = students.match(new RegExp('Examination: ([^]*?)' + os.EOL))[1];
			if (matchSubjectList()) {
				currentSubjects = subjectArray.shift();
			}
			studentList.forEach((student) => {
				console.log(student)
				if (os.platform() === 'linux') {
					// student.shift();
					student.pop();
				}
				var obj = studentBlueprint();
				if (os.platform() === 'linux') {
					obj.EnrollmentNumber = student.shift();
				} else {
					obj.EnrollmentNumber = student.shift().substr(1);
				}
				obj.Name = student.shift();
				obj.CreditsSecured = student.pop().match(/(\w+)/);
				try {
					obj.CreditsSecured = obj.CreditsSecured[1];
				} catch (e) {
					obj.CreditsSecured = '';
				}
				var present = false;
				// Get rid of unwanted data.
				student.shift(); student.shift();
				while (student.length) {
					var marks = marksBlueprint();
					var id = student.shift();
					marks.Id = id.match(/\w+/)[0];
					marks.Name = getNameFromCurrentList(marks.Id);
					try {
						marks.Credits = id.match(/\((\w+)\)/)[1];
					} catch (e) {  }
					if (student.length) {
						marksValue = student.shift().split(' ');
					} else {
						return;
					}
					marks.Internal = marksValue[0];
					marks.External = marksValue[1];
					var total = student.shift();
					if (!total) continue;
					marks.Total = parseInt(total.match(/\w+/)[0]);
					if (isNaN(marks.Total)) {
						marks.Total = 0;
					} else {
						present = true;
					}
					if (total.match(/\((.+)\)/)) {
						marks.Grade = total.match(/\((.+)\)/)[1];
					}
					obj.Marks.push(marks);
				}
				if (!present) {
					return;
				}
				db.collection('Student').insert(obj, function (err) {
					if (err) {
						console.error(err);
					}
				});
				final[len++] = obj;
			});
		}
	});
	cb(final);
}

var studentBlueprint = function () {
	return {
		'Semester': Sem,
		'Programme': Name,
		'Batch': Batch,
		'Examination': Examination,
		'Institution': Institution,
		'CollegeCode': InstitutionCode,
		'EnrollmentNumber': null,
		'Name': null,
		'Marks': [],
		'CreditsSecured': null
	}
}

var marksBlueprint = function () {
	return {
		'Id': null,
		'Credits': null,
		'Internal': null,
		'External': null,
		'Total': null,
		'Grade': null
	}
}

var matchSubjectList = function () {
	var currentResult = studentBlueprint();
	if (JSON.stringify(currentResult) === JSON.stringify(previousResult)) {
		return false;
	}
	previousResult = currentResult;
	return true;
}

var getNameFromCurrentList = function (id) {
	// console.log('Required', id)
	for (var i = 0; i < currentSubjects.length; i++) {
		// console.log('Current', currentSubjects[i]['_id'])
		if (currentSubjects[i]['_id'] === id) {
			return currentSubjects[i]['Name'];
		}
	}
}<commit_msg>Adding insertMany statement.<commit_after>var os = require('os');

var Sem, Name, Batch, Examination, Institution, InstitutionCode, final = [], len = 0;	// Globals for same set of students.
var currentSubjects = [];	// Stores the names and subject codes for current set of students.
var previousResult = {};

module.exports = function (data, subjectArray, db, cb) {
	var regexForStudentsLinux = /\d{11}([^]*?)\n\w\w?\*?(\(..?\))?\n\w\w?\n/g;
	var regexForStudentsWindows = /\n\d{11}([^]*?)\n\w\w?\*?(\(..?\))?\r\n\w\w?\r/g;
	// console.log(data)
	// process.exit()
	var regexForStudents;
	if (os.platform() === 'linux') {
		regexForStudents = regexForStudentsLinux;
	} else {
		regexForStudents = regexForStudentsWindows;
	}
	data.forEach((students) => {
		// console.log(students)
		var studentList = students.match(regexForStudents);
		if (studentList) {
			studentList = studentList.map((ele) => (ele.split(os.EOL)));
			// console.log(studentList)
			Sem = students.match(/Sem\.\/Year: (\d+)/)[1];
			Name = students.match(/Programme Name: ([^]*?) Sem/)[1];
			if (students.match(/Batch: ([^]*?) Exa/)) {
				Batch = students.match(/Batch: ([^]*?) Exa/)[1];
				// if (parseInt(Batch) < 2013) {
				// 	return;
				// }
			} else {
				return;
			}
			// Institution = students.match(/Institution: ([^]*?)\r/)[1];
			Institution = students.match(new RegExp('Institution: ([^]*?)' + os.EOL))[1];
			InstitutionCode = students.match(/Institution Code: (\d+)/)[1];
			// Examination = students.match(/Examination: ([^]*?)\r\n/)[1];
			Examination = students.match(new RegExp('Examination: ([^]*?)' + os.EOL))[1];
			if (matchSubjectList()) {
				currentSubjects = subjectArray.shift();
			}
			studentList.forEach((student) => {
				console.log(student)
				if (os.platform() === 'linux') {
					// student.shift();
					student.pop();
				}
				var obj = studentBlueprint();
				if (os.platform() === 'linux') {
					obj.EnrollmentNumber = student.shift();
				} else {
					obj.EnrollmentNumber = student.shift().substr(1);
				}
				obj.Name = student.shift();
				obj.CreditsSecured = student.pop().match(/(\w+)/);
				try {
					obj.CreditsSecured = obj.CreditsSecured[1];
				} catch (e) {
					obj.CreditsSecured = '';
				}
				var present = false;
				// Get rid of unwanted data.
				student.shift(); student.shift();
				while (student.length) {
					var marks = marksBlueprint();
					var id = student.shift();
					marks.Id = id.match(/\w+/)[0];
					marks.Name = getNameFromCurrentList(marks.Id);
					try {
						marks.Credits = id.match(/\((\w+)\)/)[1];
					} catch (e) {  }
					if (student.length) {
						marksValue = student.shift().split(' ');
					} else {
						return;
					}
					marks.Internal = marksValue[0];
					marks.External = marksValue[1];
					var total = student.shift();
					if (!total) continue;
					marks.Total = parseInt(total.match(/\w+/)[0]);
					if (isNaN(marks.Total)) {
						marks.Total = 0;
					} else {
						present = true;
					}
					if (total.match(/\((.+)\)/)) {
						marks.Grade = total.match(/\((.+)\)/)[1];
					}
					obj.Marks.push(marks);
				}
				if (!present) {
					return;
				}
				final[len++] = obj;
			});
		}
	});
	db.collection('Student').insertMany(final, { ordered: false }, function (err) {
        if (err) {
           console.error(err);
        }
		cb(final);
	});
}

var studentBlueprint = function () {
	return {
		'Semester': Sem,
		'Programme': Name,
		'Batch': Batch,
		'Examination': Examination,
		'Institution': Institution,
		'CollegeCode': InstitutionCode,
		'EnrollmentNumber': null,
		'Name': null,
		'Marks': [],
		'CreditsSecured': null
	}
}

var marksBlueprint = function () {
	return {
		'Id': null,
		'Credits': null,
		'Internal': null,
		'External': null,
		'Total': null,
		'Grade': null
	}
}

var matchSubjectList = function () {
	var currentResult = studentBlueprint();
	if (JSON.stringify(currentResult) === JSON.stringify(previousResult)) {
		return false;
	}
	previousResult = currentResult;
	return true;
}

var getNameFromCurrentList = function (id) {
	// console.log('Required', id)
	for (var i = 0; i < currentSubjects.length; i++) {
		// console.log('Current', currentSubjects[i]['_id'])
		if (currentSubjects[i]['_id'] === id) {
			return currentSubjects[i]['Name'];
		}
	}
}<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Vanderbilt University, All rights reserved.
 *
 * Author: Zsolt Lattmann
 */

'use strict';
define(['plugin/PluginConfig',
    'plugin/PluginResult',
    'plugin/PluginMessage',
    'plugin/PluginNodeDescription'],
    function (PluginConfig, PluginResult, PluginMessage, PluginNodeDescription) {

        /**
         * Initializes a new instance of a plugin object, which should be a derived class.
         *
         * @constructor
         */
        var PluginBase = function () {
            // set by initialize
            this.logger = null;
            this.blobClient = null;
            this._currentConfig = null;

            // set by configure
            this.core = null;
            this.project = null;
            this.projectName = null;
            this.branchName = null;
            this.branchHash = null;
            this.commitHash = null;
            this.currentHash = null;
            this.rootNode = null;
            this.activeNode = null;
            this.activeSelection = [];
            this.META = null;

            this.result = null;
            this.isConfigured = false;
        };

        //--------------------------------------------------------------------------------------------------------------
        //---------- Methods must be overriden by the derived classes

        /**
         * Main function for the plugin to execute. This will perform the execution.
         * Notes:
         * - do NOT use console.log use this.logger.[error,warning,info,debug] instead
         * - do NOT put any user interaction logic UI, etc. inside this function
         * - callback always have to be called even if error happened
         *
         * @param {function(string, plugin.PluginResult)} callback - the result callback
         */
        PluginBase.prototype.main = function (callback) {
            throw new Error('implement this function in the derived class');
        };

        /**
         * Readable name of this plugin that can contain spaces.
         *
         * @returns {string}
         */
        PluginBase.prototype.getName = function () {
            throw new Error('implement this function in the derived class - getting type automatically is a bad idea,' +
                'when the js scripts are minified names are useless.');
        };

        //--------------------------------------------------------------------------------------------------------------
        //---------- Methods could be overridden by the derived classes

        /**
         * Current version of this plugin using semantic versioning.
         * @returns {string}
         */
        PluginBase.prototype.getVersion = function () {
            return '0.1.0';
        };

        /**
         * A detailed description of this plugin and its purpose. It can be one or more sentences.
         *
         * @returns {string}
         */
        PluginBase.prototype.getDescription = function () {
            return '';
        };

        /**
         * Configuration structure with names, descriptions, minimum, maximum values, default values and
         * type definitions.
         *
         * Example:
         *
         * [{
         *    "name": "logChildrenNames",
         *    "displayName": "Log Children Names",
         *    "description": '',
         *    "value": true, // this is the 'default config'
         *    "valueType": "boolean",
         *    "readOnly": false
         * },{
         *    "name": "logLevel",
         *    "displayName": "Logger level",
         *    "description": '',
         *    "value": "info",
         *    "valueType": "string",
         *    "valueItems": [
         *          "debug",
         *          "info",
         *          "warn",
         *          "error"
         *      ],
         *    "readOnly": false
         * },{
         *    "name": "maxChildrenToLog",
         *    "displayName": "Maximum children to log",
         *    "description": 'Set this parameter to blabla',
         *    "value": 4,
         *    "minValue": 1,
         *    "valueType": "number",
         *    "readOnly": false
         * }]
         *
         * @returns {object[]}
         */
        PluginBase.prototype.getConfigStructure = function () {
            return [];
        };

        //--------------------------------------------------------------------------------------------------------------
        //---------- Methods that can be used by the derived classes

        /**
         * Updates the current success flag with a new value.
         *
         * NewValue = OldValue && Value
         *
         * @param {boolean} value - apply this flag on current success value
         * @param {string|null} message - optional detailed message
         */
        PluginBase.prototype.updateSuccess = function (value, message) {
            var prevSuccess = this.result.getSuccess();
            var newSuccessValue = prevSuccess && value;

            this.result.setSuccess(newSuccessValue);
            var msg = '';
            if (message) {
                msg = ' - ' + message;
            }

            this.logger.debug('Success was updated from ' + prevSuccess + ' to ' + newSuccessValue + msg);
        };

        /**
         * WebGME can export the META types as path and this method updates the generated domain specific types with
         * webgme node objects. These can be used to define the base class of new objects created through the webgme API.
         *
         * @param {object} generatedMETA
         */
        PluginBase.prototype.updateMETA = function (generatedMETA) {
            var name;
            for (name in this.META) {
                if (this.META.hasOwnProperty(name)) {
                    generatedMETA[name] = this.META[name];
                }
            }

            // TODO: check if names are not the same
            // TODO: log if META is out of date
        };

        /**
         * Gets the current configuration of the plugin that was set by the user and plugin manager.
         *
         * @returns {object}
         */
        PluginBase.prototype.getCurrentConfig = function () {
            return this._currentConfig;
        };

        /**
         * Creates a new message for the user and adds it to the result.
         *
         * @param {object} node - webgme object which is related to the message
         * @param {string} message - feedback to the user
         */
        PluginBase.prototype.createMessage = function (node, message) {
            //this occurence of the function will always handle a single node

            var descriptor = new PluginNodeDescription({
                    name: node ? this.core.getAttribute(node, 'name') : "",
                    id: node ? this.core.getPath(node) : ""
                });
            var pluginMessage = new PluginMessage({
                    commitHash: this.currentHash,
                    activeNode: descriptor,
                    message: message
                });

            this.result.addMessage(pluginMessage);
        };

        /**
         * Saves all current changes if there is any to a new commit.
         * If the changes were started from a branch, then tries to fast forward the branch to the new commit.
         * Note: Does NOT handle any merges at this point.
         *
         * @param {string|null} message - commit message
         * @param callback
         */
        PluginBase.prototype.save = function (message, callback) {
            var self = this;

            this.logger.debug('Saving project');

            // Commit changes.
            this.core.persist(this.rootNode, function (err) {
                // TODO: any error here?
                if (err) {
                    self.logger.error(err);
                }
            });

            var newRootHash = this.core.getHash(this.rootNode);

            var commitMessage = '[Plugin] ' + this.getName() + ' (v' + this.getVersion() + ') updated the model.';
            if (message) {
                commitMessage += ' - ' + message;
            }

            this.currentHash = this.project.makeCommit([this.currentHash], newRootHash, commitMessage, function (err) {
                // TODO: any error handling here?
                if (err) {
                    self.logger.error(err);
                }
            });

            if (this.branchName) {
                // try to fast forward branch if there was a branch name defined

                // FIXME: what if master branch is already in a different state?

                this.project.getBranchNames(function (err, branchNames) {
                    if (branchNames.hasOwnProperty(self.branchName)) {
                        var branchHash = branchNames[self.branchName];
                        if (branchHash === self.branchHash) {
                            // the branch does not have any new commits
                            // try to fast forward branch to the current commit
                            self.project.setBranchHash(self.branchName, self.branchHash, self.currentHash, function (err) {
                                if (err) {
                                    // fast forward failed
                                    self.logger.error(err);
                                    self.logger.info('"' + self.branchName + '" was NOT updated');
                                    self.logger.info('Project was saved to ' + self.currentHash + ' commit.');
                                } else {
                                    // successful fast forward of branch to the new commit
                                    self.logger.info('"' + self.branchName + '" was updated to the new commit.');
                                    // roll starting point on success
                                    self.branchHash = self.currentHash;
                                }
                                callback(err);
                            });
                        } else {
                            // branch has changes a merge is required
                            // TODO: try auto-merge, if fails ...
                            self.logger.warn('Cannot fast forward "' + self.branchName + '" branch. Merge is required but not supported yet.');
                            self.logger.info('Project was saved to ' + self.currentHash + ' commit.');
                            callback(null);
                        }
                    } else {
                        // branch was deleted or not found, do nothing
                        self.logger.info('Project was saved to ' + self.currentHash + ' commit.');
                        callback(null);
                    }
                });
                // FIXME: is this call async??
                // FIXME: we are not tracking all commits that we make

            } else {
                // making commits, we have not started from a branch
                this.logger.info('Project was saved to ' + this.currentHash + ' commit.');
                callback(null);
            }
        };

        //--------------------------------------------------------------------------------------------------------------
        //---------- Methods that are used by the Plugin Manager. Derived classes should not use these methods

        /**
         * Initializes the plugin with objects that can be reused within the same plugin instance.
         *
         * @param {logManager} logger - logging capability to console (or file) based on PluginManager configuration
         * @param {blob.BlobClient} blobClient - virtual file system where files can be generated then saved as a zip file.
         */
        PluginBase.prototype.initialize = function (logger, blobClient) {
            if (logger) {
                this.logger = logger;
            } else {
                this.logger = console;
            }

            this.blobClient = blobClient;

            this._currentConfig = null;
            // initialize default configuration
            this.setCurrentConfig(this.getDefaultConfig());

            this.isConfigured = false;
        };

        /**
         * Configures this instance of the plugin for a specific execution. This function is called before the main by
         * the PluginManager.
         * Initializes the result with a new object.
         *
         * @param {PluginContext} config - specific context: project, branch, core, active object and active selection.
         */
        PluginBase.prototype.configure = function (config) {
            this.core = config.core;
            this.project = config.project;
            this.projectName = config.projectName;
            this.branchName = config.branchName;
            this.branchHash = config.branchName ? config.commitHash : null;
            this.commitHash = config.commitHash;
            this.currentHash = config.commitHash;
            this.rootNode = config.rootNode;
            this.activeNode = config.activeNode;
            this.activeSelection = config.activeSelection;
            this.META = config.META;

            this.result = new PluginResult();

            this.isConfigured = true;
        };

        /**
         * Gets the default configuration based on the configuration structure for this plugin.
         *
         * @returns {plugin.PluginConfig}
         */
        PluginBase.prototype.getDefaultConfig = function () {
            var configStructure = this.getConfigStructure();

            var defaultConfig = new PluginConfig();

            for (var i = 0; i < configStructure.length; i += 1) {
                defaultConfig[configStructure[i].name] = configStructure[i].value;
            }

            return defaultConfig;
        };

        /**
         * Sets the current configuration of the plugin.
         *
         * @param {object} newConfig - this is the actual configuration and NOT the configuration structure.
         */
        PluginBase.prototype.setCurrentConfig = function (newConfig) {
            this._currentConfig = newConfig;
        };

        return PluginBase;
    });<commit_msg>Add getMetaType and baseIsMeta helper functions.<commit_after>/*
 * Copyright (C) 2014 Vanderbilt University, All rights reserved.
 *
 * Author: Zsolt Lattmann
 */

'use strict';
define(['plugin/PluginConfig',
    'plugin/PluginResult',
    'plugin/PluginMessage',
    'plugin/PluginNodeDescription'],
    function (PluginConfig, PluginResult, PluginMessage, PluginNodeDescription) {

        /**
         * Initializes a new instance of a plugin object, which should be a derived class.
         *
         * @constructor
         */
        var PluginBase = function () {
            // set by initialize
            this.logger = null;
            this.blobClient = null;
            this._currentConfig = null;

            // set by configure
            this.core = null;
            this.project = null;
            this.projectName = null;
            this.branchName = null;
            this.branchHash = null;
            this.commitHash = null;
            this.currentHash = null;
            this.rootNode = null;
            this.activeNode = null;
            this.activeSelection = [];
            this.META = null;

            this.result = null;
            this.isConfigured = false;
        };

        //--------------------------------------------------------------------------------------------------------------
        //---------- Methods must be overridden by the derived classes

        /**
         * Main function for the plugin to execute. This will perform the execution.
         * Notes:
         * - do NOT use console.log use this.logger.[error,warning,info,debug] instead
         * - do NOT put any user interaction logic UI, etc. inside this function
         * - callback always have to be called even if error happened
         *
         * @param {function(string, plugin.PluginResult)} callback - the result callback
         */
        PluginBase.prototype.main = function (callback) {
            throw new Error('implement this function in the derived class');
        };

        /**
         * Readable name of this plugin that can contain spaces.
         *
         * @returns {string}
         */
        PluginBase.prototype.getName = function () {
            throw new Error('implement this function in the derived class - getting type automatically is a bad idea,' +
                'when the js scripts are minified names are useless.');
        };

        //--------------------------------------------------------------------------------------------------------------
        //---------- Methods could be overridden by the derived classes

        /**
         * Current version of this plugin using semantic versioning.
         * @returns {string}
         */
        PluginBase.prototype.getVersion = function () {
            return '0.1.0';
        };

        /**
         * A detailed description of this plugin and its purpose. It can be one or more sentences.
         *
         * @returns {string}
         */
        PluginBase.prototype.getDescription = function () {
            return '';
        };

        /**
         * Configuration structure with names, descriptions, minimum, maximum values, default values and
         * type definitions.
         *
         * Example:
         *
         * [{
         *    "name": "logChildrenNames",
         *    "displayName": "Log Children Names",
         *    "description": '',
         *    "value": true, // this is the 'default config'
         *    "valueType": "boolean",
         *    "readOnly": false
         * },{
         *    "name": "logLevel",
         *    "displayName": "Logger level",
         *    "description": '',
         *    "value": "info",
         *    "valueType": "string",
         *    "valueItems": [
         *          "debug",
         *          "info",
         *          "warn",
         *          "error"
         *      ],
         *    "readOnly": false
         * },{
         *    "name": "maxChildrenToLog",
         *    "displayName": "Maximum children to log",
         *    "description": 'Set this parameter to blabla',
         *    "value": 4,
         *    "minValue": 1,
         *    "valueType": "number",
         *    "readOnly": false
         * }]
         *
         * @returns {object[]}
         */
        PluginBase.prototype.getConfigStructure = function () {
            return [];
        };

        //--------------------------------------------------------------------------------------------------------------
        //---------- Methods that can be used by the derived classes

        /**
         * Updates the current success flag with a new value.
         *
         * NewValue = OldValue && Value
         *
         * @param {boolean} value - apply this flag on current success value
         * @param {string|null} message - optional detailed message
         */
        PluginBase.prototype.updateSuccess = function (value, message) {
            var prevSuccess = this.result.getSuccess();
            var newSuccessValue = prevSuccess && value;

            this.result.setSuccess(newSuccessValue);
            var msg = '';
            if (message) {
                msg = ' - ' + message;
            }

            this.logger.debug('Success was updated from ' + prevSuccess + ' to ' + newSuccessValue + msg);
        };

        /**
         * WebGME can export the META types as path and this method updates the generated domain specific types with
         * webgme node objects. These can be used to define the base class of new objects created through the webgme API.
         *
         * @param {object} generatedMETA
         */
        PluginBase.prototype.updateMETA = function (generatedMETA) {
            var name;
            for (name in this.META) {
                if (this.META.hasOwnProperty(name)) {
                    generatedMETA[name] = this.META[name];
                }
            }

            // TODO: check if names are not the same
            // TODO: log if META is out of date
        };

        /**
         * Finds and returns the node object defining the meta type for the given node.
         * @param node - Node to be checked for type.
         * @returns {Object} - Node object defining the meta type of node.
         */
        PluginBase.prototype.getMetaType = function (node) {
            var self = this,
                name;
            while (node) {
                name = self.core.getAttribute(node, 'name');
                if (self.META.hasOwnProperty(name) && self.META[name] === node) {
                    break;
                }
                node = self.core.getBase(node);
            }
            return node;
        };

        /**
         * Returns true if node is a direct instance of a meta-type node (or a meta-type node itself).
         * @param node - Node to be checked.
         * @returns {boolean}
         */
        PluginBase.prototype.baseIsMeta = function (node) {
            var self = this,
                baseName,
                baseNode = self.core.getBase(node);
            if (!baseNode) {
                // FCO does not have a base node, by definition function returns true.
                return true;
            }
            baseName = self.core.getAttribute(baseNode, 'name');
            return self.META.hasOwnProperty(baseName) && self.META[baseName] === baseNode;
        };

        /**
         * Gets the current configuration of the plugin that was set by the user and plugin manager.
         *
         * @returns {object}
         */
        PluginBase.prototype.getCurrentConfig = function () {
            return this._currentConfig;
        };

        /**
         * Creates a new message for the user and adds it to the result.
         *
         * @param {object} node - webgme object which is related to the message
         * @param {string} message - feedback to the user
         */
        PluginBase.prototype.createMessage = function (node, message) {
            //this occurence of the function will always handle a single node

            var descriptor = new PluginNodeDescription({
                    name: node ? this.core.getAttribute(node, 'name') : "",
                    id: node ? this.core.getPath(node) : ""
                });
            var pluginMessage = new PluginMessage({
                    commitHash: this.currentHash,
                    activeNode: descriptor,
                    message: message
                });

            this.result.addMessage(pluginMessage);
        };

        /**
         * Saves all current changes if there is any to a new commit.
         * If the changes were started from a branch, then tries to fast forward the branch to the new commit.
         * Note: Does NOT handle any merges at this point.
         *
         * @param {string|null} message - commit message
         * @param callback
         */
        PluginBase.prototype.save = function (message, callback) {
            var self = this;

            this.logger.debug('Saving project');

            // Commit changes.
            this.core.persist(this.rootNode, function (err) {
                // TODO: any error here?
                if (err) {
                    self.logger.error(err);
                }
            });

            var newRootHash = this.core.getHash(this.rootNode);

            var commitMessage = '[Plugin] ' + this.getName() + ' (v' + this.getVersion() + ') updated the model.';
            if (message) {
                commitMessage += ' - ' + message;
            }

            this.currentHash = this.project.makeCommit([this.currentHash], newRootHash, commitMessage, function (err) {
                // TODO: any error handling here?
                if (err) {
                    self.logger.error(err);
                }
            });

            if (this.branchName) {
                // try to fast forward branch if there was a branch name defined

                // FIXME: what if master branch is already in a different state?

                this.project.getBranchNames(function (err, branchNames) {
                    if (branchNames.hasOwnProperty(self.branchName)) {
                        var branchHash = branchNames[self.branchName];
                        if (branchHash === self.branchHash) {
                            // the branch does not have any new commits
                            // try to fast forward branch to the current commit
                            self.project.setBranchHash(self.branchName, self.branchHash, self.currentHash, function (err) {
                                if (err) {
                                    // fast forward failed
                                    self.logger.error(err);
                                    self.logger.info('"' + self.branchName + '" was NOT updated');
                                    self.logger.info('Project was saved to ' + self.currentHash + ' commit.');
                                } else {
                                    // successful fast forward of branch to the new commit
                                    self.logger.info('"' + self.branchName + '" was updated to the new commit.');
                                    // roll starting point on success
                                    self.branchHash = self.currentHash;
                                }
                                callback(err);
                            });
                        } else {
                            // branch has changes a merge is required
                            // TODO: try auto-merge, if fails ...
                            self.logger.warn('Cannot fast forward "' + self.branchName + '" branch. Merge is required but not supported yet.');
                            self.logger.info('Project was saved to ' + self.currentHash + ' commit.');
                            callback(null);
                        }
                    } else {
                        // branch was deleted or not found, do nothing
                        self.logger.info('Project was saved to ' + self.currentHash + ' commit.');
                        callback(null);
                    }
                });
                // FIXME: is this call async??
                // FIXME: we are not tracking all commits that we make

            } else {
                // making commits, we have not started from a branch
                this.logger.info('Project was saved to ' + this.currentHash + ' commit.');
                callback(null);
            }
        };

        //--------------------------------------------------------------------------------------------------------------
        //---------- Methods that are used by the Plugin Manager. Derived classes should not use these methods

        /**
         * Initializes the plugin with objects that can be reused within the same plugin instance.
         *
         * @param {logManager} logger - logging capability to console (or file) based on PluginManager configuration
         * @param {blob.BlobClient} blobClient - virtual file system where files can be generated then saved as a zip file.
         */
        PluginBase.prototype.initialize = function (logger, blobClient) {
            if (logger) {
                this.logger = logger;
            } else {
                this.logger = console;
            }

            this.blobClient = blobClient;

            this._currentConfig = null;
            // initialize default configuration
            this.setCurrentConfig(this.getDefaultConfig());

            this.isConfigured = false;
        };

        /**
         * Configures this instance of the plugin for a specific execution. This function is called before the main by
         * the PluginManager.
         * Initializes the result with a new object.
         *
         * @param {PluginContext} config - specific context: project, branch, core, active object and active selection.
         */
        PluginBase.prototype.configure = function (config) {
            this.core = config.core;
            this.project = config.project;
            this.projectName = config.projectName;
            this.branchName = config.branchName;
            this.branchHash = config.branchName ? config.commitHash : null;
            this.commitHash = config.commitHash;
            this.currentHash = config.commitHash;
            this.rootNode = config.rootNode;
            this.activeNode = config.activeNode;
            this.activeSelection = config.activeSelection;
            this.META = config.META;

            this.result = new PluginResult();

            this.isConfigured = true;
        };

        /**
         * Gets the default configuration based on the configuration structure for this plugin.
         *
         * @returns {plugin.PluginConfig}
         */
        PluginBase.prototype.getDefaultConfig = function () {
            var configStructure = this.getConfigStructure();

            var defaultConfig = new PluginConfig();

            for (var i = 0; i < configStructure.length; i += 1) {
                defaultConfig[configStructure[i].name] = configStructure[i].value;
            }

            return defaultConfig;
        };

        /**
         * Sets the current configuration of the plugin.
         *
         * @param {object} newConfig - this is the actual configuration and NOT the configuration structure.
         */
        PluginBase.prototype.setCurrentConfig = function (newConfig) {
            this._currentConfig = newConfig;
        };

        return PluginBase;
    });<|endoftext|>


<commit_before>module.exports = requireDescriptionCompleteSentence;
module.exports.scopes = ['function'];
module.exports.options = {
    requireDescriptionCompleteSentence: {allowedValues: [true]}
};

var RE_START_WITH_UPPER_CASE = /^[A-Z]/;

/**
 * Checks that a period is next to a word at the end of input.
 *
 * The sentence ending with a new line is also valid.
 */
var RE_END_WITH_PERIOD = /\b[.](\n|$)/;

var RE_END_DESCRIPTION = /\n/g;

var RE_LAST_WORD = /\b(?!.*\b)/;

/**
 * Requires description to be a complete sentence in a jsdoc comment.
 *
 * A complete sentence is defined by starting with an upper letter
 * and ending with a period.
 *
 * @param {(FunctionDeclaration|FunctionExpression)} node
 * @param {Function} err
 */
function requireDescriptionCompleteSentence(node, err) {
    var doc = node.jsdoc;
    if (!doc || !doc.tags.length || !doc.description || !doc.description.length) {
        return;
    }

    var loc = doc.loc.start;

    if (!RE_START_WITH_UPPER_CASE.test(doc.description)) {
        err('Sentence must start with an upper case letter.', {
            line: loc.line + 1,
            column: loc.column + 3
        });
    }

    if (!RE_END_WITH_PERIOD.test(doc.description)) {
        var lines = doc.description.split(RE_END_DESCRIPTION);

        // Find the location last word in the description.
        var line = -1;
        var column = -1;
        for (var i = lines.length -1; i >= 0; i--) {
            if (RE_LAST_WORD.test[lines[i]]) {
                lines = i;
                column = RE_LAST_WORD.search(lines[i]);
                break;
            }
        }
        err('Sentence must end with a period.', {
            line: loc.line + 1 + line,
            column: loc.column + 3 + column
        });
    }
}
<commit_msg>changed to matching word character instead of word boundary<commit_after>module.exports = requireDescriptionCompleteSentence;
module.exports.scopes = ['function'];
module.exports.options = {
    requireDescriptionCompleteSentence: {allowedValues: [true]}
};

var RE_START_WITH_UPPER_CASE = /^[A-Z]/;

/**
 * Checks that a period is next to a word at the end of input.
 *
 * The sentence ending with a new line is also valid.
 */
var RE_END_WITH_PERIOD = /\w[.](\n|$)/;

var RE_END_DESCRIPTION = /\n/g;

var RE_LAST_WORD = /\w(?!.*\w)/g;

/**
 * Requires description to be a complete sentence in a jsdoc comment.
 *
 * A complete sentence is defined by starting with an upper letter
 * and ending with a period.
 *
 * @param {(FunctionDeclaration|FunctionExpression)} node
 * @param {Function} err
 */
function requireDescriptionCompleteSentence(node, err) {
    var doc = node.jsdoc;
    if (!doc || !doc.tags.length || !doc.description || !doc.description.length) {
        return;
    }

    var loc = doc.loc.start;

    if (!RE_START_WITH_UPPER_CASE.test(doc.description)) {
        err('Sentence must start with an upper case letter.', {
            line: loc.line + 1,
            column: loc.column + 3
        });
    }

    if (!RE_END_WITH_PERIOD.test(doc.description)) {
        var lines = doc.description.split(RE_END_DESCRIPTION);

        // Find the location last word in the description.
        var line = -1;
        var column = -1;
        for (var i = lines.length -1; i >= 0; i--) {
            if (RE_LAST_WORD.test[lines[i]]) {
                lines = i;
                column = RE_LAST_WORD.search(lines[i]);
                break;
            }
        }
        err('Sentence must end with a period.', {
            line: loc.line + 1 + line,
            column: loc.column + 3 + column
        });
    }
}
<|endoftext|>


<commit_before>let Plugin = require('../../src/Plugin')
  , node_path = require('path')
  , glob = require('glob')
  , gulp = require('gulp')
  , pug = require("gulp-pug")
;

class PugPlugin extends Plugin {

  static method() {
    return 'pug';
  }

  /**
   *
   * @param {GulpQuery} GulpQuery
   * @param configs
   */
  constructor(GulpQuery, configs) {
    super(GulpQuery, configs);

    /**
     * @type {Object.<String,{from: Array, to: String, completeAmount: Number}>}
     * @private
     */
    this._reportList = {};
  }

  run(task_name, config, callback) {
    let path_to = this.path(config.to);
    let parent_folder = 'parent_folder' in config ? config.parent_folder : null;

    if (!Array.isArray(config.from)) {
      config.from = [config.from];
    }

    let from = [];
    config.from.forEach((path) => {

      path = this.path(parent_folder ? (parent_folder + path) : path);

      if (node_path.basename(path).indexOf('*') !== -1) {
        glob.sync(path).forEach((f) => {
          if (node_path.basename(f).indexOf('_') !== 0) {
            from.push(f);
          }
        });
      } else {
        from.push(path);
      }

    });

    let _src = from;
    let _dest = path_to;
    let reportFunc;

    this._reportList[_src] = {
      from: _src,
      to: _dest,
      completeAmount: 0
    };

    reportFunc = this.reportList.bind(this, task_name, _src);

    return gulp.src(_src)
      .pipe(this.plumber(this.reportError.bind(this, task_name, _src, _dest)))
      .pipe(pug())
      .pipe(gulp.dest(_dest))
      .pipe(this.notify(reportFunc))
      ;
  }

  reportList(task_name, from) {

    if (!(from in this._reportList)) {
      return;
    }

    ++this._reportList[from].completeAmount;

    if (this._reportList[from].completeAmount >= this._reportList[from].from.length) {
      this.report(
        task_name,
        this._reportList[from].from,
        this._reportList[from].to,
        true
      );

      delete this._reportList[from];
    }
  }
}

module.exports = PugPlugin;<commit_msg>pug pretty option<commit_after>let Plugin = require('../../src/Plugin')
  , node_path = require('path')
  , glob = require('glob')
  , gulp = require('gulp')
  , pug = require("gulp-pug")
;

class PugPlugin extends Plugin {

  static method() {
    return 'pug';
  }

  /**
   *
   * @param {GulpQuery} GulpQuery
   * @param configs
   */
  constructor(GulpQuery, configs) {
    super(GulpQuery, configs);

    /**
     * @type {Object.<String,{from: Array, to: String, completeAmount: Number}>}
     * @private
     */
    this._reportList = {};
  }

  run(task_name, config, callback) {
    let path_to = this.path(config.to);
    let parent_folder = 'parent_folder' in config ? config.parent_folder : null;

    if (!Array.isArray(config.from)) {
      config.from = [config.from];
    }

    let from = [];
    config.from.forEach((path) => {

      path = this.path(parent_folder ? (parent_folder + path) : path);

      if (node_path.basename(path).indexOf('*') !== -1) {
        glob.sync(path).forEach((f) => {
          if (node_path.basename(f).indexOf('_') !== 0) {
            from.push(f);
          }
        });
      } else {
        from.push(path);
      }

    });

    let _src = from;
    let _dest = path_to;
    let reportFunc;

    this._reportList[_src] = {
      from: _src,
      to: _dest,
      completeAmount: 0
    };

    reportFunc = this.reportList.bind(this, task_name, _src);

    return gulp.src(_src)
      .pipe(this.plumber(this.reportError.bind(this, task_name, _src, _dest)))
      .pipe(pug({
        pretty: !this.isProduction()
      }))
      .pipe(gulp.dest(_dest))
      .pipe(this.notify(reportFunc))
      ;
  }

  reportList(task_name, from) {

    if (!(from in this._reportList)) {
      return;
    }

    ++this._reportList[from].completeAmount;

    if (this._reportList[from].completeAmount >= this._reportList[from].from.length) {
      this.report(
        task_name,
        this._reportList[from].from,
        this._reportList[from].to,
        true
      );

      delete this._reportList[from];
    }
  }
}

module.exports = PugPlugin;<|endoftext|>


<commit_before>'use strict';

import React from 'react';
import {mount} from 'enzyme';

import <%= name %> from 'components/<%= name %>';

it('<%= name %>', () => {
  const wrapper = mount(
    <<%= name %> />
  );

  expect(wrapper.containsAnyMatchingElements([

This is <%= name %>!

  ])).toBe(true);
});
<commit_msg>add eslint ignore for test<commit_after>'use strict';

import React from 'react';
import {mount} from 'enzyme';

import <%= name %> from 'components/<%= name %>';

it('<%= name %>', () => {
  const wrapper = mount(
    <<%= name %> />
  );

  expect(wrapper.containsAnyMatchingElements([

This is <%= name %>!
 // eslint-disable-line react/jsx-key
  ])).toBe(true);
});
<|endoftext|>