<commit_before>(function(window) {

  // vars

  var $ = window.jQuery;
  var document = window.document;
  var dataFields = [];
  var charts = [];
  var data = [];
  var chartListEl = document.getElementById('dashboard-chart-list');
  var fieldsEl = document.getElementById('chart-edit-modal-fields');
  var addChartEl = document.getElementById('dashboard-add-chart');
  var saveChartEl = document.getElementById('chart-edit-save');
  var chartTplEl = document.getElementById('chart-item-tpl');
  var editFormEl = document.getElementById('chart-edit-form');
  var editIdEl = document.getElementById('chart-edit-id');
  var editMessageEl = document.getElementById('chart-edit-message');
  var editFieldsEl = document.getElementById('chart-edit-modal-fields');
  var editFieldsMessageEl = document.getElementById('chart-edit-modal-fields-message');
  var editModalEl = document.getElementById('chart-edit-modal');
  var editNameEl = document.getElementById('chart-edit-name');
  var editTitleEl = document.getElementById('chart-edit-modal-title');
  var editRemoveEl = document.getElementById('chart-edit-remove');

  var chartList = new DataList(
    chartListEl,
    [],
    chartTplEl.innerHTML,
    function(el, data) {
      var nameEl = el.querySelector('[data-name]');
      var chartEl = el.querySelector('[data-chart]');
      nameEl.innerHTML = data.name;
      el.setAttribute('data-id', data._id);
      if ('fields' in data && chartEl) {
        var chartId = 'chart' + Math.ceil((Math.random() * 1000000) + Date.now());
        charts.push({
          chart: Highcharts.StockChart({
            rangeSelector: {
              inputEnabled: false,
              selected: 5
            },
            title: {
              enabled: false
            },
            legend: {
              enabled: true
            },
            yAxis: {
              gridLineColor: '#f2f2f2'
            },
            xAxis: {
                // minRange: 3600 * 1000
            },
            plotOptions: {
              series: {
                marker: {
                  enabled: true,
                  radius: 3
                },
                animation: {
                    duration: 2000
                }
              }
            },
            navigator: {
              adaptToUpdatedData: true
            },
            series: [],
            chart: {
              renderTo: chartEl
            }
          }),
          record: data
        });
      } else {
        window.console.error('Wrong chart data', data);
      }
    },
    function() {
      charts = [];
    },
    function() {
      reflowCharts();
    }
  );

  var fieldsList = new DataList(
    fieldsEl,
    [],
    '
\
      \
        <input type="checkbox" name="fields[]" data-checkbox /> \
      \

',
    function(el, data) {
      var labelEl = el.querySelector('[data-label]');
      var checkboxEl = el.querySelector('[data-checkbox]');
      if (labelEl) {
        labelEl.innerHTML = data;
      }
      if (checkboxEl) {
        checkboxEl.value = data;
      }
    }
  );

  // functions

  function saveChart() {
    hideEditMessage();
    var data = {};
    var id = $(editIdEl).val();
    if (id) {
      data.id = id;
    }
    data.name = $(editNameEl).val();
    data.fields = [];
    $(editFieldsEl).find('input[type="checkbox"]:checked').each(function() {
      data.fields.push($(this).val());
    });
    if (! data.name || data.fields.length === 0) {
      showEditMessage('Fields Name and Data fields are required.', 'danger');
      return {then: function() {}};
    }
    $(editModalEl).modal('hide');
    if (id) {
      return $.post('/chart/' + id, data).then(function() {
        loadCharts();
      });
    } else {
      return $.post('/chart', data).then(function(item) {
        loadCharts();
      });
    }
  }

  function editChart(chartId) {
    hideEditMessage();
    if (dataFields.length === 0) {
      $(editFieldsMessageEl).show();
      $(editFieldsMessageEl).html('You need to send data first for initialize fields. How to do this');
    } else {
      $(editFieldsMessageEl).hide();
    }
    $(editIdEl).val(chartId ? chartId: '');
    $(editNameEl).val('');
    $(editFieldsEl).find('input[type="checkbox"]').removeAttr('checked');
    if (chartId) {
      $(editRemoveEl).show();
      editTitleEl.innerHTML = 'Edit Chart';
      $.get('/chart/'+chartId).then(function(item) {
        $(editNameEl).val(item.name);
        for (var i=0,ln=item.fields.length; i<ln; i++) {
          $(editFieldsEl).find('input[value="'+item.fields[i]+'"]')[0].checked = true;
        }
      });
    } else {
      $(editRemoveEl).hide();
      editTitleEl.innerHTML = 'Add Chart';
    }
    $(editModalEl).modal('show');
  }

  function hideEditChart() {
    $(editModalEl).modal('hide');
  }

  function loadCharts() {
    return $.get('/chart').then(function(items) {
      chartList.update(items);
      insertChartsData(data);
      return items;
    });
  }

  function insertChartsData(items) {
    charts.map(function(chart) {
      var lastTime = 0;
      chart.record.fields.map(function(field) {
        var useSeries = null;
        for (var i=0,ln=chart.chart.series.length; i<ln; i++) {
          if (chart.chart.series[i].name === field) {
            useSeries = chart.chart.series[i];
            break;
          }
        }
        if (! useSeries) {
          useSeries = chart.chart.addSeries({
            name: field,
            data: []
          });
        }
        items.map(function(item) {
          if (field in item) {
            var v = parseFloat(item[field]);
            useSeries.addPoint([item.date, isNaN(v) ? 0: v], false);
          }
          lastTime = item.date;
        });
      });
      chart.chart.redraw();
      // chart.chart.xAxis[0].setExtremes();
    });
  }

  function reflowCharts() {
    charts.map(function(item) {
      item.chart.reflow();
    });
  }

  function showEditMessage(message, type) {
    type = type || 'info';
    $(editMessageEl).removeClass().addClass('alert alert-'+type).html(message).show();
  }

  function hideEditMessage() {
    $(editMessageEl).hide();
  }

  function removeChart(id) {
    return $.ajax({
      url: '/chart/'+id,
      type: 'DELETE'
    });
  }

  // handlers

  $(addChartEl).on('click', function() {
    editChart();
    return false;
  });

  $(saveChartEl).on('click', function() {
    saveChart();
    return false;
  });

  $(chartListEl).on('click', '[data-edit]', function() {
    editChart($(this).parents('[data-chart]').attr('data-id'));
    return false;
  });

  $(editFormEl).on('submit', function() {
    saveChart();
    return false;
  });

  $(editRemoveEl).on('click', function() {
    if (! confirm('Are you sure?')) {
      return false;
    }
    var id = $(editIdEl).val();
    if (! id) {
      return false;
    }
    removeChart(id).then(function() {
      hideEditChart();
      loadCharts();
    });
    return false;
  });

  $.subscribe('dataFieldsUpdated', function(event, items) {
    dataFields = items;
    items = items.filter(function(item) {
      return item !== 'date';
    });
    fieldsList.update(items);
  });

  $.subscribe('dataUpdated', function(event, items) {
    data = items.concat(data);
    setTimeout(function() {
      insertChartsData(items);
    }, 1);
  });

  $.subscribe('pageChanged', function(event, name) {
    if (name !== 'charts') {
      return;
    }
    reflowCharts();
  });

  $.subscribe('userUpdated', function() {
    loadCharts();
  });

})(this);<commit_msg>Fixed charts data.<commit_after>(function(window) {

  // vars

  var $ = window.jQuery;
  var document = window.document;
  var dataFields = [];
  var charts = [];
  var data = [];
  var chartListEl = document.getElementById('dashboard-chart-list');
  var fieldsEl = document.getElementById('chart-edit-modal-fields');
  var addChartEl = document.getElementById('dashboard-add-chart');
  var saveChartEl = document.getElementById('chart-edit-save');
  var chartTplEl = document.getElementById('chart-item-tpl');
  var editFormEl = document.getElementById('chart-edit-form');
  var editIdEl = document.getElementById('chart-edit-id');
  var editMessageEl = document.getElementById('chart-edit-message');
  var editFieldsEl = document.getElementById('chart-edit-modal-fields');
  var editFieldsMessageEl = document.getElementById('chart-edit-modal-fields-message');
  var editModalEl = document.getElementById('chart-edit-modal');
  var editNameEl = document.getElementById('chart-edit-name');
  var editTitleEl = document.getElementById('chart-edit-modal-title');
  var editRemoveEl = document.getElementById('chart-edit-remove');

  var chartList = new DataList(
    chartListEl,
    [],
    chartTplEl.innerHTML,
    function(el, data) {
      var nameEl = el.querySelector('[data-name]');
      var chartEl = el.querySelector('[data-chart]');
      nameEl.innerHTML = data.name;
      el.setAttribute('data-id', data._id);
      if ('fields' in data && chartEl) {
        var chartId = 'chart' + Math.ceil((Math.random() * 1000000) + Date.now());
        charts.push({
          chart: Highcharts.StockChart({
            rangeSelector: {
              inputEnabled: false,
              selected: 5
            },
            title: {
              enabled: false
            },
            legend: {
              enabled: true
            },
            yAxis: {
              gridLineColor: '#f2f2f2'
            },
            xAxis: {
              // minRange: 3600 * 1000
            },
            plotOptions: {
              series: {
                marker: {
                  enabled: true,
                  radius: 3
                },
                animation: {
                  duration: 2000
                }
              }
            },
            navigator: {
              adaptToUpdatedData: true
            },
            series: [],
            chart: {
              renderTo: chartEl
            }
          }),
          record: data
        });
      } else {
        window.console.error('Wrong chart data', data);
      }
    },
    function() {
      charts = [];
    },
    function() {
      reflowCharts();
    }
  );

  var fieldsList = new DataList(
    fieldsEl,
    [],
    '
\
      \
        <input type="checkbox" name="fields[]" data-checkbox /> \
      \

',
    function(el, data) {
      var labelEl = el.querySelector('[data-label]');
      var checkboxEl = el.querySelector('[data-checkbox]');
      if (labelEl) {
        labelEl.innerHTML = data;
      }
      if (checkboxEl) {
        checkboxEl.value = data;
      }
    }
  );

  // functions

  function saveChart() {
    hideEditMessage();
    var data = {};
    var id = $(editIdEl).val();
    if (id) {
      data.id = id;
    }
    data.name = $(editNameEl).val();
    data.fields = [];
    $(editFieldsEl).find('input[type="checkbox"]:checked').each(function() {
      data.fields.push($(this).val());
    });
    if (! data.name || data.fields.length === 0) {
      showEditMessage('Fields Name and Data fields are required.', 'danger');
      return {then: function() {}};
    }
    $(editModalEl).modal('hide');
    if (id) {
      return $.post('/chart/' + id, data).then(function() {
        loadCharts();
      });
    } else {
      return $.post('/chart', data).then(function(item) {
        loadCharts();
      });
    }
  }

  function editChart(chartId) {
    hideEditMessage();
    if (dataFields.length === 0) {
      $(editFieldsMessageEl).show();
      $(editFieldsMessageEl).html('You need to send data first for initialize fields. How to do this');
    } else {
      $(editFieldsMessageEl).hide();
    }
    $(editIdEl).val(chartId ? chartId: '');
    $(editNameEl).val('');
    $(editFieldsEl).find('input[type="checkbox"]').removeAttr('checked');
    if (chartId) {
      $(editRemoveEl).show();
      editTitleEl.innerHTML = 'Edit Chart';
      $.get('/chart/'+chartId).then(function(item) {
        $(editNameEl).val(item.name);
        for (var i=0,ln=item.fields.length; i<ln; i++) {
          $(editFieldsEl).find('input[value="'+item.fields[i]+'"]')[0].checked = true;
        }
      });
    } else {
      $(editRemoveEl).hide();
      editTitleEl.innerHTML = 'Add Chart';
    }
    $(editModalEl).modal('show');
  }

  function hideEditChart() {
    $(editModalEl).modal('hide');
  }

  function loadCharts() {
    return $.get('/chart').then(function(items) {
      chartList.update(items);
      insertChartsData(data);
      return items;
    });
  }

  function insertChartsData(items) {
    charts.map(function(chart) {
      var lastTime = 0;
      chart.record.fields.map(function(field) {
        var useSeries = null;
        for (var i=0,ln=chart.chart.series.length; i<ln; i++) {
          if (chart.chart.series[i].name === field) {
            useSeries = chart.chart.series[i];
            break;
          }
        }
        if (! useSeries) {
          useSeries = chart.chart.addSeries({
            name: field,
            data: []
          });
        }
        items.map(function(item) {
          if (field in item) {
            var v = parseFloat(item[field]);
            useSeries.addPoint([item.dateUnixtime, isNaN(v) ? 0: v], false);
          }
          lastTime = item.date;
        });
      });
      chart.chart.redraw();
      // chart.chart.xAxis[0].setExtremes();
    });
  }

  function reflowCharts() {
    charts.map(function(item) {
      item.chart.reflow();
    });
  }

  function showEditMessage(message, type) {
    type = type || 'info';
    $(editMessageEl).removeClass().addClass('alert alert-'+type).html(message).show();
  }

  function hideEditMessage() {
    $(editMessageEl).hide();
  }

  function removeChart(id) {
    return $.ajax({
      url: '/chart/'+id,
      type: 'DELETE'
    });
  }

  // handlers

  $(addChartEl).on('click', function() {
    editChart();
    return false;
  });

  $(saveChartEl).on('click', function() {
    saveChart();
    return false;
  });

  $(chartListEl).on('click', '[data-edit]', function() {
    editChart($(this).parents('[data-chart]').attr('data-id'));
    return false;
  });

  $(editFormEl).on('submit', function() {
    saveChart();
    return false;
  });

  $(editRemoveEl).on('click', function() {
    if (! confirm('Are you sure?')) {
      return false;
    }
    var id = $(editIdEl).val();
    if (! id) {
      return false;
    }
    removeChart(id).then(function() {
      hideEditChart();
      loadCharts();
    });
    return false;
  });

  $.subscribe('dataFieldsUpdated', function(event, items) {
    dataFields = items;
    items = items.filter(function(item) {
      return item !== 'date';
    });
    fieldsList.update(items);
  });

  $.subscribe('dataUpdated', function(event, items) {
    data = items.concat(data);
    setTimeout(function() {
      insertChartsData(items);
    }, 1);
  });

  $.subscribe('pageChanged', function(event, name) {
    if (name !== 'charts') {
      return;
    }
    reflowCharts();
  });

  $.subscribe('userUpdated', function() {
    loadCharts();
  });

  // execute

  Highcharts.setOptions({
    global: {
      useUTC: false
    }
  });

})(this);<|endoftext|>


<commit_before>const version = require("flying-squid").version;
const entitiesByName=require("minecraft-data")(version).entitiesByName;
const entitiesById=require("minecraft-data")(version).entities;
const Entity = require("prismarine-entity");
const path = require('path');
const requireIndex = require('requireindex');
const plugins = requireIndex(path.join(__dirname,'..', 'plugins'));
const Item = require("prismarine-item")(version);
const UserError = require('flying-squid').UserError;

const Vec3 = require("vec3").Vec3;

module.exports.server=function(serv,options) {
  serv.initEntity = (type, entityType, world, position) => {
    serv.entityMaxId++;
    const entity = new Entity(serv.entityMaxId);

    Object.keys(plugins)
      .filter(pluginName => plugins[pluginName].entity!=undefined)
      .forEach(pluginName => plugins[pluginName].entity(entity, serv, options));

    entity.initEntity(type, entityType, world, position);

    serv.emit("newEntity",entity);

    return entity;
  };

  serv.spawnObject = (type, world, position, {pitch=0,yaw=0,velocity=new Vec3(0,0,0),data=1,itemId,itemDamage=0,pickupTime=undefined,deathTime=undefined}) => {
    const object = serv.initEntity('object', type, world, position.scaled(32).floored());
    object.data = data;
    object.velocity = velocity.scaled(32).floored();
    object.pitch = pitch;
    object.yaw = yaw;
    object.gravity = new Vec3(0, -20*32, 0);
    object.terminalvelocity = new Vec3(27*32, 27*32, 27*32);
    object.friction = new Vec3(15*32, 0, 15*32);
    object.size = new Vec3(0.25*32, 0.25*32, 0.25*32); // Hardcoded, will be dependent on type!
    object.deathTime = deathTime;
    object.pickupTime = pickupTime;
    object.itemId = itemId;
    object.itemDamage = itemDamage;

    object.updateAndSpawn();
  };

  serv.spawnMob = (type, world, position, {pitch=0,yaw=0,headPitch=0,velocity=new Vec3(0,0,0),metadata=[]}={}) => {
    const mob = serv.initEntity('mob', type, world, position.scaled(32).floored());
    mob.name=entitiesById[type].name;
    mob.velocity = velocity.scaled(32).floored();
    mob.pitch = pitch;
    mob.headPitch = headPitch;
    mob.yaw = yaw;
    mob.gravity = new Vec3(0, -20*32, 0);
    mob.terminalvelocity = new Vec3(27*32, 27*32, 27*32);
    mob.friction = new Vec3(15*32, 0, 15*32);
    mob.size = new Vec3(0.75, 1.75, 0.75);
    mob.health = 20;
    mob.metadata = metadata;

    mob.updateAndSpawn();
    return mob;
  };

  serv.destroyEntity = entity => {
    entity._writeOthersNearby('entity_destroy', {
      entityIds: [entity.id]
    });
    delete serv.entities[entity.id];
  };
};

module.exports.player=function(player,serv){
  player.commands.add({
    base: 'spawn',
    info: 'Spawn a mob',
    usage: '/spawn <entity_id>',
    op: true,
    parse(str) {
      const results=str.match(/(\d+)/);
      if (!results) return false;
      return {
        id: parseInt(results[1])
      }
    },
    action({id}) {
      serv.spawnMob(id, player.world, player.position.scaled(1/32), {
        velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10)
      });
    }
  });

  player.commands.add({
    base: 'spawnObject',
    info: 'Spawn an object',
    usage: '/spawnObject <entity_id>',
    op: true,
    parse(str) {
      const results=str.match(/(\d+)/);
      if (!results) return false;
      return {
        id: parseInt(results[1])
      }
    },
    action({id}) {
      serv.spawnObject(id, player.world, player.position.scaled(1/32), {
        velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10)
      });
    }
  });

  player.commands.add({
    base: 'summon',
    info: 'Summon an entity',
    usage: '/summon <entity_name>',
    op: true,
    action(name) {
      const entity=entitiesByName[name];
      if(!entity) {
        player.chat("No entity named "+name);
        return;
      }
      serv.spawnMob(entity.id, player.world, player.position.scaled(1/32), {
        velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10)
      });
    }
  });

  player.commands.add({
    base: 'summonMany',
    info: 'Summon many entities',
    usage: '/summonMany <number> <entity_name>',
    op: true,
    parse(str) {
      var args=str.split(" ");
      if(args.length!=2)
        return false;
      return {number:args[0],name:args[1]};
    },
    action({number,name}) {
      const entity=entitiesByName[name];
      if(!entity) {
        player.chat("No entity named "+name);
        return;
      }
      let s=Math.floor(Math.sqrt(number));
      for(let i=0;i<number;i++)
        serv.spawnMob(entity.id, player.world, player.position.scaled(1/32).offset(Math.floor(i/s*10),0,i%s*10), {
          velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10)
        });
    }
  });

  player.commands.add({
    base: 'pile',
    info: 'make a pile of entities',
    usage: '/pile <entities types>',
    op: true,
    parse(str)  {
      const args=str.split(' ');
      if(args.length==0)
        return false;
      return args
        .map(name => entitiesByName[name])
        .filter(entity => !!entity);
    },
    action(entityTypes) {
      entityTypes.map(entity =>
        serv.spawnMob(entity.id, player.world, player.position.scaled(1/32), {
          velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10)
        }))
        .reduce((prec,entity) => {
          if(prec!=null)
            prec.attach(entity);
          return entity;
        },null);
    }
  });

  player.commands.add({
    base: 'attach',
    info: 'attach an entity on an other entity',
    usage: '/attach <carrier> <attached>',
    op: true,
    parse(str)  {
      const args=str.split(' ');
      if(args.length!=2)
        return false;

      let carrier = player.selectorString(args[0]);
      if(carrier.length==0) throw new UserError("one carrier");
      let attached = player.selectorString(args[1]);
      if(attached.length==0) throw new UserError("one attached");

      return {carrier:carrier[0],attached:attached[0]};
    },
    action({carrier,attached}) {
      carrier.attach(attached);
    }
  });

  player.spawnEntity = entity => {
    player._client.write(entity.spawnPacketName, entity.getSpawnPacket());
    if (typeof entity.itemId != 'undefined') {
      entity.sendMetadata([{
        "key": 10,
        "type": 5,
        "value": {
          blockId: entity.itemId,
          itemDamage: entity.itemDamage,
          itemCount:1
        }
      }]);
    }
    entity.equipment.forEach((equipment,slot) => {
        if (equipment != undefined) player._client.write("entity_equipment", {
          entityId: entity.id,
          slot: slot,
          item: Item.toNotch(equipment)
        });
      }
    )
  };
};

module.exports.entity=function(entity,serv) {
  entity.initEntity=(type, entityType, world, position)=>{
    entity.type = type;
    entity.spawnPacketName = '';
    entity.entityType = entityType;
    entity.world = world;
    entity.position = position;
    entity.lastPositionPlayersUpdated = entity.position.clone();
    entity.nearbyEntities = [];
    entity.viewDistance = 150;
    entity.score = {};

    entity.bornTime = Date.now();
    serv.entities[entity.id] = entity;

    if (entity.type == 'player') entity.spawnPacketName = 'named_entity_spawn';
    else if (entity.type == 'object') entity.spawnPacketName = 'spawn_entity';
    else if (entity.type == 'mob') entity.spawnPacketName = 'spawn_entity_living';
  };

  entity.getSpawnPacket = () => {
    const scaledVelocity = entity.velocity.scaled(8000/32/20).floored(); // from fixed-position/second to unit => 1/8000 blocks per tick
    if (entity.type == 'player') {
      return {
        entityId: entity.id,
        playerUUID: entity._client.uuid,
        x: entity.position.x,
        y: entity.position.y,
        z: entity.position.z,
        yaw: entity.yaw,
        pitch: entity.pitch,
        currentItem: 0,
        metadata: entity.metadata
      }
    } else if (entity.type == 'object') {
      return {
        entityId: entity.id,
        type: entity.entityType,
        x: entity.position.x,
        y: entity.position.y,
        z: entity.position.z,
        pitch: entity.pitch,
        yaw: entity.yaw,
        objectData: {
          intField: entity.data,
          velocityX: scaledVelocity.x,
          velocityY: scaledVelocity.y,
          velocityZ: scaledVelocity.z
        }
      }
    } else if (entity.type == 'mob') {
      return {
        entityId: entity.id,
        type: entity.entityType,
        x: entity.position.x,
        y: entity.position.y,
        z: entity.position.z,
        yaw: entity.yaw,
        pitch: entity.pitch,
        headPitch: entity.headPitch,
        velocityX: scaledVelocity.x,
        velocityY: scaledVelocity.y,
        velocityZ: scaledVelocity.z,
        metadata: entity.metadata
      }
    }
  };

  entity.updateAndSpawn = () => {
    const updatedEntities=entity.getNearby();
    const entitiesToAdd=updatedEntities.filter(e => entity.nearbyEntities.indexOf(e)==-1);
    const entitiesToRemove=entity.nearbyEntities.filter(e => updatedEntities.indexOf(e)==-1);
    if (entity.type == 'player') {
      entity.despawnEntities(entitiesToRemove);
      entitiesToAdd.forEach(entity.spawnEntity);
    }
    entity.lastPositionPlayersUpdated=entity.position.clone();

    const playersToAdd = entitiesToAdd.filter(e => e.type == 'player');
    const playersToRemove = entitiesToRemove.filter(e => e.type == 'player');

    playersToRemove.forEach(p => p.despawnEntities([entity]));
    playersToRemove.forEach(p => p.nearbyEntities=p.getNearby());
    playersToAdd.forEach(p => p.spawnEntity(entity));
    playersToAdd.forEach(p => p.nearbyEntities=p.getNearby());

    entity.nearbyEntities=updatedEntities;
  };

  entity.on("move",() => {
    if(entity.position.distanceTo(entity.lastPositionPlayersUpdated)>2*32)
      entity.updateAndSpawn();
  });

  entity.destroy = () => {
    serv.destroyEntity(entity);
  };

  entity.attach= (attachedEntity,leash=false) =>
  {
    const p={
      entityId:attachedEntity.id,
      vehicleId:entity.id,
      leash:leash
    };
    if(entity.type=='player')
      entity._client.write('attach_entity',p);
    entity._writeOthersNearby('attach_entity',p);
  }

};<commit_msg>adapt to new minecraft-data entities data<commit_after>const version = require("flying-squid").version;
const entitiesByName=require("minecraft-data")(version).entitiesByName;
const mobsById=require("minecraft-data")(version).mobs;
const objectsById=require("minecraft-data")(version).objects;
const Entity = require("prismarine-entity");
const path = require('path');
const requireIndex = require('requireindex');
const plugins = requireIndex(path.join(__dirname,'..', 'plugins'));
const Item = require("prismarine-item")(version);
const UserError = require('flying-squid').UserError;

const Vec3 = require("vec3").Vec3;

module.exports.server=function(serv,options) {
  serv.initEntity = (type, entityType, world, position) => {
    serv.entityMaxId++;
    const entity = new Entity(serv.entityMaxId);

    Object.keys(plugins)
      .filter(pluginName => plugins[pluginName].entity!=undefined)
      .forEach(pluginName => plugins[pluginName].entity(entity, serv, options));

    entity.initEntity(type, entityType, world, position);

    serv.emit("newEntity",entity);

    return entity;
  };

  serv.spawnObject = (type, world, position, {pitch=0,yaw=0,velocity=new Vec3(0,0,0),data=1,itemId,itemDamage=0,pickupTime=undefined,deathTime=undefined}) => {
    const object = serv.initEntity('object', type, world, position.scaled(32).floored());
    object.name=objectsById[type].name;
    object.data = data;
    object.velocity = velocity.scaled(32).floored();
    object.pitch = pitch;
    object.yaw = yaw;
    object.gravity = new Vec3(0, -20*32, 0);
    object.terminalvelocity = new Vec3(27*32, 27*32, 27*32);
    object.friction = new Vec3(15*32, 0, 15*32);
    object.size = new Vec3(0.25*32, 0.25*32, 0.25*32); // Hardcoded, will be dependent on type!
    object.deathTime = deathTime;
    object.pickupTime = pickupTime;
    object.itemId = itemId;
    object.itemDamage = itemDamage;

    object.updateAndSpawn();
  };

  serv.spawnMob = (type, world, position, {pitch=0,yaw=0,headPitch=0,velocity=new Vec3(0,0,0),metadata=[]}={}) => {
    const mob = serv.initEntity('mob', type, world, position.scaled(32).floored());
    mob.name=mobsById[type].name;
    mob.velocity = velocity.scaled(32).floored();
    mob.pitch = pitch;
    mob.headPitch = headPitch;
    mob.yaw = yaw;
    mob.gravity = new Vec3(0, -20*32, 0);
    mob.terminalvelocity = new Vec3(27*32, 27*32, 27*32);
    mob.friction = new Vec3(15*32, 0, 15*32);
    mob.size = new Vec3(0.75, 1.75, 0.75);
    mob.health = 20;
    mob.metadata = metadata;

    mob.updateAndSpawn();
    return mob;
  };

  serv.destroyEntity = entity => {
    entity._writeOthersNearby('entity_destroy', {
      entityIds: [entity.id]
    });
    delete serv.entities[entity.id];
  };
};

module.exports.player=function(player,serv){
  player.commands.add({
    base: 'spawn',
    info: 'Spawn a mob',
    usage: '/spawn <entity_id>',
    op: true,
    parse(str) {
      const results=str.match(/(\d+)/);
      if (!results) return false;
      return {
        id: parseInt(results[1])
      }
    },
    action({id}) {
      serv.spawnMob(id, player.world, player.position.scaled(1/32), {
        velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10)
      });
    }
  });

  player.commands.add({
    base: 'spawnObject',
    info: 'Spawn an object',
    usage: '/spawnObject <entity_id>',
    op: true,
    parse(str) {
      const results=str.match(/(\d+)/);
      if (!results) return false;
      return {
        id: parseInt(results[1])
      }
    },
    action({id}) {
      serv.spawnObject(id, player.world, player.position.scaled(1/32), {
        velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10)
      });
    }
  });

  player.commands.add({
    base: 'summon',
    info: 'Summon an entity',
    usage: '/summon <entity_name>',
    op: true,
    action(name) {
      const entity=entitiesByName[name];
      if(!entity) {
        player.chat("No entity named "+name);
        return;
      }
      if(entity.type=="mob") serv.spawnMob(entity.id, player.world, player.position.scaled(1/32), {
        velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10)
      });
      else if(entity.type=="object") serv.spawnObject(entity.id, player.world, player.position.scaled(1/32), {
        velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10)
      });
    }
  });

  player.commands.add({
    base: 'summonMany',
    info: 'Summon many entities',
    usage: '/summonMany <number> <entity_name>',
    op: true,
    parse(str) {
      var args=str.split(" ");
      if(args.length!=2)
        return false;
      return {number:args[0],name:args[1]};
    },
    action({number,name}) {
      const entity=entitiesByName[name];
      if(!entity) {
        player.chat("No entity named "+name);
        return;
      }
      let s=Math.floor(Math.sqrt(number));
      for(let i=0;i<number;i++) {
        if(entity.type=="mob")
          serv.spawnMob(entity.id, player.world, player.position.scaled(1 / 32).offset(Math.floor(i / s * 10), 0, i % s * 10), {
          velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
        });
        else if(entity.type=="object")
          serv.spawnObject(entity.id, player.world, player.position.scaled(1 / 32).offset(Math.floor(i / s * 10), 0, i % s * 10), {
          velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
        });
      }
    }
  });

  player.commands.add({
    base: 'pile',
    info: 'make a pile of entities',
    usage: '/pile <entities types>',
    op: true,
    parse(str)  {
      const args=str.split(' ');
      if(args.length==0)
        return false;
      return args
        .map(name => entitiesByName[name])
        .filter(entity => !!entity);
    },
    action(entityTypes) {
      entityTypes.map(entity => {
        if(entity.type=="mob") serv.spawnMob(entity.id, player.world, player.position.scaled(1/32), {
          velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10)
        });
        else if(entity.type=="object") serv.spawnObject(entity.id, player.world, player.position.scaled(1/32), {
          velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10)
        });
      })
        .reduce((prec,entity) => {
          if(prec!=null)
            prec.attach(entity);
          return entity;
        },null);
    }
  });

  player.commands.add({
    base: 'attach',
    info: 'attach an entity on an other entity',
    usage: '/attach <carrier> <attached>',
    op: true,
    parse(str)  {
      const args=str.split(' ');
      if(args.length!=2)
        return false;

      let carrier = player.selectorString(args[0]);
      if(carrier.length==0) throw new UserError("one carrier");
      let attached = player.selectorString(args[1]);
      if(attached.length==0) throw new UserError("one attached");

      return {carrier:carrier[0],attached:attached[0]};
    },
    action({carrier,attached}) {
      carrier.attach(attached);
    }
  });

  player.spawnEntity = entity => {
    player._client.write(entity.spawnPacketName, entity.getSpawnPacket());
    if (typeof entity.itemId != 'undefined') {
      entity.sendMetadata([{
        "key": 10,
        "type": 5,
        "value": {
          blockId: entity.itemId,
          itemDamage: entity.itemDamage,
          itemCount:1
        }
      }]);
    }
    entity.equipment.forEach((equipment,slot) => {
        if (equipment != undefined) player._client.write("entity_equipment", {
          entityId: entity.id,
          slot: slot,
          item: Item.toNotch(equipment)
        });
      }
    )
  };
};

module.exports.entity=function(entity,serv) {
  entity.initEntity=(type, entityType, world, position)=>{
    entity.type = type;
    entity.spawnPacketName = '';
    entity.entityType = entityType;
    entity.world = world;
    entity.position = position;
    entity.lastPositionPlayersUpdated = entity.position.clone();
    entity.nearbyEntities = [];
    entity.viewDistance = 150;
    entity.score = {};

    entity.bornTime = Date.now();
    serv.entities[entity.id] = entity;

    if (entity.type == 'player') entity.spawnPacketName = 'named_entity_spawn';
    else if (entity.type == 'object') entity.spawnPacketName = 'spawn_entity';
    else if (entity.type == 'mob') entity.spawnPacketName = 'spawn_entity_living';
  };

  entity.getSpawnPacket = () => {
    const scaledVelocity = entity.velocity.scaled(8000/32/20).floored(); // from fixed-position/second to unit => 1/8000 blocks per tick
    if (entity.type == 'player') {
      return {
        entityId: entity.id,
        playerUUID: entity._client.uuid,
        x: entity.position.x,
        y: entity.position.y,
        z: entity.position.z,
        yaw: entity.yaw,
        pitch: entity.pitch,
        currentItem: 0,
        metadata: entity.metadata
      }
    } else if (entity.type == 'object') {
      return {
        entityId: entity.id,
        type: entity.entityType,
        x: entity.position.x,
        y: entity.position.y,
        z: entity.position.z,
        pitch: entity.pitch,
        yaw: entity.yaw,
        objectData: {
          intField: entity.data,
          velocityX: scaledVelocity.x,
          velocityY: scaledVelocity.y,
          velocityZ: scaledVelocity.z
        }
      }
    } else if (entity.type == 'mob') {
      return {
        entityId: entity.id,
        type: entity.entityType,
        x: entity.position.x,
        y: entity.position.y,
        z: entity.position.z,
        yaw: entity.yaw,
        pitch: entity.pitch,
        headPitch: entity.headPitch,
        velocityX: scaledVelocity.x,
        velocityY: scaledVelocity.y,
        velocityZ: scaledVelocity.z,
        metadata: entity.metadata
      }
    }
  };

  entity.updateAndSpawn = () => {
    const updatedEntities=entity.getNearby();
    const entitiesToAdd=updatedEntities.filter(e => entity.nearbyEntities.indexOf(e)==-1);
    const entitiesToRemove=entity.nearbyEntities.filter(e => updatedEntities.indexOf(e)==-1);
    if (entity.type == 'player') {
      entity.despawnEntities(entitiesToRemove);
      entitiesToAdd.forEach(entity.spawnEntity);
    }
    entity.lastPositionPlayersUpdated=entity.position.clone();

    const playersToAdd = entitiesToAdd.filter(e => e.type == 'player');
    const playersToRemove = entitiesToRemove.filter(e => e.type == 'player');

    playersToRemove.forEach(p => p.despawnEntities([entity]));
    playersToRemove.forEach(p => p.nearbyEntities=p.getNearby());
    playersToAdd.forEach(p => p.spawnEntity(entity));
    playersToAdd.forEach(p => p.nearbyEntities=p.getNearby());

    entity.nearbyEntities=updatedEntities;
  };

  entity.on("move",() => {
    if(entity.position.distanceTo(entity.lastPositionPlayersUpdated)>2*32)
      entity.updateAndSpawn();
  });

  entity.destroy = () => {
    serv.destroyEntity(entity);
  };

  entity.attach= (attachedEntity,leash=false) =>
  {
    const p={
      entityId:attachedEntity.id,
      vehicleId:entity.id,
      leash:leash
    };
    if(entity.type=='player')
      entity._client.write('attach_entity',p);
    entity._writeOthersNearby('attach_entity',p);
  }

};<|endoftext|>


<commit_before>// @flow

export type ElementType = "link" | "clickable" | "frame";

type ElementData = {|
  type: ElementType,
|};

export type Box = {|
  x: number,
  y: number,
  width: number,
  height: number,
|};

export type HintMeasurements = {|
  x: number,
  y: number,
  area: number,
|};

export default class ElementManager {
  maxTrackedElements: number;
  elements: Map<HTMLElement, ElementData>;
  visibleElements: Set<HTMLElement>;
  intersectionObserver: IntersectionObserver;
  mutationObserver: MutationObserver;
  bailed: boolean;

  constructor({ maxTrackedElements }: {| maxTrackedElements: number |}) {
    this.maxTrackedElements = maxTrackedElements;

    this.elements = new Map();
    this.visibleElements = new Set();

    this.intersectionObserver = new IntersectionObserver(
      this.onIntersection.bind(this),
      {}
    );

    this.mutationObserver = new MutationObserver(this.onMutation.bind(this));
    this.bailed = false;
  }

  start() {
    const { documentElement } = document;
    if (documentElement != null) {
      this.addElements(documentElement);
      this.mutationObserver.observe(documentElement, {
        childList: true,
        subtree: true,
      });
    }
  }

  stop() {
    this.intersectionObserver.disconnect();
    this.mutationObserver.disconnect();
    this.elements.clear();
    this.visibleElements.clear();
  }

  // Stop tracking everything except frames (up to `maxTrackedElements` of them).
  bail() {
    if (this.bailed) {
      return;
    }

    this.intersectionObserver.disconnect();
    this.elements.clear();
    this.visibleElements.clear();
    this.bailed = true;

    const { documentElement } = document;
    if (documentElement != null) {
      const frames = document.querySelectorAll("iframe, frame");
      for (const frame of frames) {
        this.addElements(frame);
      }
    }

    console.log("bailed", this);
  }

  onIntersection(entries: Array<IntersectionObserverEntry>) {
    for (const entry of entries) {
      if (entry.isIntersecting) {
        this.visibleElements.add(entry.target);
      } else {
        this.visibleElements.delete(entry.target);
      }
    }
  }

  onMutation(records: Array<MutationRecord>) {
    for (const record of records) {
      for (const node of record.addedNodes) {
        if (node instanceof HTMLElement) {
          this.addElements(node);
          if (this.bailed) {
            return;
          }
        }
      }

      for (const node of record.removedNodes) {
        if (node instanceof HTMLElement) {
          this.removeElements(node);
        }
      }
    }
  }

  addElements(parent: HTMLElement) {
    let { size } = this.elements;
    const elements = [parent, ...parent.querySelectorAll("*")];
    for (const element of elements) {
      const data = getElementData(element);
      if (data != null && (!this.bailed || data.type === "frame")) {
        this.elements.set(element, data);
        this.intersectionObserver.observe(element);
        size++;
        if (size > this.maxTrackedElements) {
          this.bail();
          break;
        }
      }
    }
  }

  removeElements(parent: HTMLElement) {
    const elements = [parent, ...parent.querySelectorAll("*")];
    for (const element of elements) {
      if (this.elements.has(element)) {
        this.elements.delete(element);
        this.intersectionObserver.unobserve(element);
      }
    }
  }

  getVisibleElements(
    types: Set<ElementType>,
    viewports: Array<Box>
  ): Array<{|
    element: HTMLElement,
    data: ElementData,
    measurements: HintMeasurements,
  |}> {
    const candidates = this.bailed
      ? document.documentElement == null
        ? []
        : document.documentElement.querySelectorAll("*")
      : this.visibleElements;

    const range = document.createRange();

    return Array.from(candidates, element => {
      const data = this.bailed
        ? getElementData(element)
        : this.elements.get(element);

      if (data == null) {
        return undefined;
      }

      if (!types.has(data.type)) {
        return undefined;
      }

      const measurements = getMeasurements(element, viewports, range);

      if (measurements == null) {
        return undefined;
      }

      return {
        element,
        data,
        measurements,
      };
    }).filter(Boolean);
  }

  getVisibleFrames(): Array<HTMLIFrameElement | HTMLFrameElement> {
    return Array.from(
      this.visibleElements,
      element =>
        (element instanceof HTMLIFrameElement ||
          element instanceof HTMLFrameElement) &&
        // Needed on reddit.com. There's a Google Ads iframe without `src` where
        // `contentWindow` is null.
        element.contentWindow != null
          ? element
          : undefined
    ).filter(Boolean);
  }
}

function getMeasurements(
  element: HTMLElement,
  viewports: Array<Box>,
  // The `range` is passed in since it is faster to re-use the same one than
  // creating a new one for every element candidate.
  range: Range
): ?HintMeasurements {
  const rect = element.getBoundingClientRect();
  const visibleBox = getVisibleBox(rect, viewports);

  if (visibleBox == null) {
    return undefined;
  }

  // Try to place the hint just before the first letter inside `element`, if
  // any. If the first letter is off-screen, don’t bother with any fancy
  // placement and just place the hint in the middle of `visibleBox`. The first
  // non-empty text node is assumed to come first. That’s not necessarily true
  // due to CSS, but YAGNI until that’s found in the wild. One would think that
  // `range.selectNodeContents(element)` would do essentially the same thing
  // here, but it takes padding and such of child elements into account.
  let textRect = undefined;
  const firstTextNode = getFirstNonEmptyTextNode(element);
  if (firstTextNode != null) {
    range.selectNode(firstTextNode);
    // Use `.getClientRects()` rather than `.getBoundingClientRect()` in case
    // the text is line-wrapped.
    textRect = range.getClientRects()[0];
  }
  const visibleTextBox =
    textRect == null ? undefined : getVisibleBox(textRect, viewports);

  // The box used to choose the position of the hint.
  const pointBox = visibleTextBox == null ? visibleBox : visibleTextBox;

  const { x } = pointBox;
  const y = pointBox.y + pointBox.height / 2;

  // Check that the element isn’t covered. A little bit expensive, but totally
  // worth it since it makes link hints in fixed menus so much easier find.
  // Even if some other part than `(x, y)` is visible, don’t bother if `(x, y)`
  // isn’t visible. Too much work for too little gain. Finally, add 1px to `x`.
  // It feels safer to test 1px into the element rather than at the very edge.
  // `getVisibleBox` guarantees the box to be at least 1px wide.
  const elementAtPoint = document.elementFromPoint(x + 1, y);

  // `.contains` also checks `element === elementAtPoint`.
  if (!element.contains(elementAtPoint)) {
    return undefined;
  }

  return {
    // The coordinates at which to place the hint.
    x,
    y,
    // It’s easy to think that one could optimize by calculating the area from
    // `pointBox` and potentially skip `element.getBoundingClientRect()` for
    // most elements, but remember that `pointBox` most likely just refers to
    // (part of) one text node of the element, not the entire visible area of
    // the element (as `visibleBox` does).
    area: visibleBox.width * visibleBox.height,
  };
}

// Turn a `ClientRect` into a `Box` using the coordinates of the topmost
// viewport. Only the part of the `ClientRect` visible through all viewports end
// up in the `Box`.
function getVisibleBox(passedRect: ClientRect, viewports: Array<Box>): ?Box {
  // No shortcuts (such as summing up viewport x:s and y:s) can be taken here,
  // since each viewport (frame) clips the visible area. We have to loop them
  // all through.
  const visibleRect = viewports.reduceRight(
    (rect, viewport) => ({
      left: viewport.x + Math.max(rect.left, 0),
      right: viewport.x + Math.min(rect.right, viewport.width),
      top: viewport.y + Math.max(rect.top, 0),
      bottom: viewport.y + Math.min(rect.bottom, viewport.height),
    }),
    passedRect
  );

  const width = visibleRect.right - visibleRect.left;
  const height = visibleRect.bottom - visibleRect.top;

  // If `visibleRect` has a non-sensical width or height it means it is not
  // visible within `viewports`.
  return width <= 0 || height <= 0
    ? undefined
    : {
        x: visibleRect.left,
        y: visibleRect.top,
        width,
        height,
      };
}

function getElementData(element: HTMLElement): ?{| type: ElementType |} {
  const type = getElementType(element);
  return type == null ? undefined : { type };
}

function getElementType(element: HTMLElement): ?ElementType {
  switch (element.nodeName) {
    case "A":
      return "link";
    case "BUTTON":
    case "LABEL":
    case "SELECT":
    case "SUMMARY":
    case "TEXTAREA":
      return "clickable";
    case "INPUT":
      // $FlowIgnore: Flow can't know, but `.type` _does_ exist here.
      return element.type === "hidden" ? undefined : "clickable";
    case "FRAME":
    case "IFRAME":
      return "frame";
    default:
      return undefined;
  }
}

function getFirstNonEmptyTextNode(element: HTMLElement): ?Text {
  for (const node of element.childNodes) {
    if (node instanceof Text) {
      if (node.data.trim() !== "") {
        return node;
      }
    } else if (node instanceof HTMLElement) {
      const result = getFirstNonEmptyTextNode(node);
      if (result != null) {
        return result;
      }
    }
  }
  return undefined;
}
<commit_msg>Fix missing hints in frames<commit_after>// @flow

export type ElementType = "link" | "clickable" | "frame";

type ElementData = {|
  type: ElementType,
|};

export type Box = {|
  x: number,
  y: number,
  width: number,
  height: number,
|};

export type HintMeasurements = {|
  x: number,
  y: number,
  area: number,
|};

export default class ElementManager {
  maxTrackedElements: number;
  elements: Map<HTMLElement, ElementData>;
  visibleElements: Set<HTMLElement>;
  intersectionObserver: IntersectionObserver;
  mutationObserver: MutationObserver;
  bailed: boolean;

  constructor({ maxTrackedElements }: {| maxTrackedElements: number |}) {
    this.maxTrackedElements = maxTrackedElements;

    this.elements = new Map();
    this.visibleElements = new Set();

    this.intersectionObserver = new IntersectionObserver(
      this.onIntersection.bind(this),
      {}
    );

    this.mutationObserver = new MutationObserver(this.onMutation.bind(this));
    this.bailed = false;
  }

  start() {
    const { documentElement } = document;
    if (documentElement != null) {
      this.addElements(documentElement);
      this.mutationObserver.observe(documentElement, {
        childList: true,
        subtree: true,
      });
    }
  }

  stop() {
    this.intersectionObserver.disconnect();
    this.mutationObserver.disconnect();
    this.elements.clear();
    this.visibleElements.clear();
  }

  // Stop tracking everything except frames (up to `maxTrackedElements` of them).
  bail() {
    if (this.bailed) {
      return;
    }

    this.intersectionObserver.disconnect();
    this.elements.clear();
    this.visibleElements.clear();
    this.bailed = true;

    const { documentElement } = document;
    if (documentElement != null) {
      const frames = document.querySelectorAll("iframe, frame");
      for (const frame of frames) {
        this.addElements(frame);
      }
    }

    console.log("bailed", this);
  }

  onIntersection(entries: Array<IntersectionObserverEntry>) {
    for (const entry of entries) {
      if (entry.isIntersecting) {
        this.visibleElements.add(entry.target);
      } else {
        this.visibleElements.delete(entry.target);
      }
    }
  }

  onMutation(records: Array<MutationRecord>) {
    for (const record of records) {
      for (const node of record.addedNodes) {
        if (node instanceof HTMLElement) {
          this.addElements(node);
          if (this.bailed) {
            return;
          }
        }
      }

      for (const node of record.removedNodes) {
        if (node instanceof HTMLElement) {
          this.removeElements(node);
        }
      }
    }
  }

  addElements(parent: HTMLElement) {
    let { size } = this.elements;
    const elements = [parent, ...parent.querySelectorAll("*")];
    for (const element of elements) {
      const data = getElementData(element);
      if (data != null && (!this.bailed || data.type === "frame")) {
        this.elements.set(element, data);
        this.intersectionObserver.observe(element);
        size++;
        if (size > this.maxTrackedElements) {
          this.bail();
          break;
        }
      }
    }
  }

  removeElements(parent: HTMLElement) {
    const elements = [parent, ...parent.querySelectorAll("*")];
    for (const element of elements) {
      if (this.elements.has(element)) {
        this.elements.delete(element);
        this.intersectionObserver.unobserve(element);
      }
    }
  }

  getVisibleElements(
    types: Set<ElementType>,
    viewports: Array<Box>
  ): Array<{|
    element: HTMLElement,
    data: ElementData,
    measurements: HintMeasurements,
  |}> {
    const candidates = this.bailed
      ? document.documentElement == null
        ? []
        : document.documentElement.querySelectorAll("*")
      : this.visibleElements;

    const range = document.createRange();

    return Array.from(candidates, element => {
      const data = this.bailed
        ? getElementData(element)
        : this.elements.get(element);

      if (data == null) {
        return undefined;
      }

      if (!types.has(data.type)) {
        return undefined;
      }

      const measurements = getMeasurements(element, viewports, range);

      if (measurements == null) {
        return undefined;
      }

      return {
        element,
        data,
        measurements,
      };
    }).filter(Boolean);
  }

  getVisibleFrames(): Array<HTMLIFrameElement | HTMLFrameElement> {
    return Array.from(
      this.visibleElements,
      element =>
        (element instanceof HTMLIFrameElement ||
          element instanceof HTMLFrameElement) &&
        // Needed on reddit.com. There's a Google Ads iframe without `src` where
        // `contentWindow` is null.
        element.contentWindow != null
          ? element
          : undefined
    ).filter(Boolean);
  }
}

function getMeasurements(
  element: HTMLElement,
  viewports: Array<Box>,
  // The `range` is passed in since it is faster to re-use the same one than
  // creating a new one for every element candidate.
  range: Range
): ?HintMeasurements {
  const rect = element.getBoundingClientRect();
  const visibleBox = getVisibleBox(rect, viewports);

  if (visibleBox == null) {
    return undefined;
  }

  // Try to place the hint just before the first letter inside `element`, if
  // any. If the first letter is off-screen, don’t bother with any fancy
  // placement and just place the hint in the middle of `visibleBox`. The first
  // non-empty text node is assumed to come first. That’s not necessarily true
  // due to CSS, but YAGNI until that’s found in the wild. One would think that
  // `range.selectNodeContents(element)` would do essentially the same thing
  // here, but it takes padding and such of child elements into account.
  let textRect = undefined;
  const firstTextNode = getFirstNonEmptyTextNode(element);
  if (firstTextNode != null) {
    range.selectNode(firstTextNode);
    // Use `.getClientRects()` rather than `.getBoundingClientRect()` in case
    // the text is line-wrapped.
    textRect = range.getClientRects()[0];
  }
  const visibleTextBox =
    textRect == null ? undefined : getVisibleBox(textRect, viewports);

  // The box used to choose the position of the hint.
  const pointBox = visibleTextBox == null ? visibleBox : visibleTextBox;

  const [offsetX, offsetY] = viewports.reduceRight(
    ([x, y], viewport) => [x + viewport.x, y + viewport.y],
    [0, 0]
  );
  console.log("masher", offsetX, offsetY);

  const { x } = pointBox;
  const y = pointBox.y + pointBox.height / 2;

  // Check that the element isn’t covered. A little bit expensive, but totally
  // worth it since it makes link hints in fixed menus so much easier find.
  // Even if some other part than `(x, y)` is visible, don’t bother if `(x, y)`
  // isn’t visible. Too much work for too little gain. Finally, add 1px to `x`.
  // It feels safer to test 1px into the element rather than at the very edge.
  // `getVisibleBox` guarantees the box to be at least 1px wide. Remove
  // `offsetX` and `offsetY` to turn `x` and `y` back to the coordinate system
  // of the current frame.
  const elementAtPoint = document.elementFromPoint(
    x - offsetX + 1,
    y - offsetY
  );

  // `.contains` also checks `element === elementAtPoint`.
  if (!element.contains(elementAtPoint)) {
    return undefined;
  }

  return {
    // The coordinates at which to place the hint.
    x,
    y,
    // It’s easy to think that one could optimize by calculating the area from
    // `pointBox` and potentially skip `element.getBoundingClientRect()` for
    // most elements, but remember that `pointBox` most likely just refers to
    // (part of) one text node of the element, not the entire visible area of
    // the element (as `visibleBox` does).
    area: visibleBox.width * visibleBox.height,
  };
}

// Turn a `ClientRect` into a `Box` using the coordinates of the topmost
// viewport. Only the part of the `ClientRect` visible through all viewports end
// up in the `Box`.
function getVisibleBox(passedRect: ClientRect, viewports: Array<Box>): ?Box {
  // No shortcuts (such as summing up viewport x:s and y:s) can be taken here,
  // since each viewport (frame) clips the visible area. We have to loop them
  // all through.
  const visibleRect = viewports.reduceRight(
    (rect, viewport) => ({
      left: viewport.x + Math.max(rect.left, 0),
      right: viewport.x + Math.min(rect.right, viewport.width),
      top: viewport.y + Math.max(rect.top, 0),
      bottom: viewport.y + Math.min(rect.bottom, viewport.height),
    }),
    passedRect
  );

  const width = visibleRect.right - visibleRect.left;
  const height = visibleRect.bottom - visibleRect.top;

  // If `visibleRect` has a non-sensical width or height it means it is not
  // visible within `viewports`.
  return width <= 0 || height <= 0
    ? undefined
    : {
        x: visibleRect.left,
        y: visibleRect.top,
        width,
        height,
      };
}

function getElementData(element: HTMLElement): ?{| type: ElementType |} {
  const type = getElementType(element);
  return type == null ? undefined : { type };
}

function getElementType(element: HTMLElement): ?ElementType {
  switch (element.nodeName) {
    case "A":
      return "link";
    case "BUTTON":
    case "LABEL":
    case "SELECT":
    case "SUMMARY":
    case "TEXTAREA":
      return "clickable";
    case "INPUT":
      // $FlowIgnore: Flow can't know, but `.type` _does_ exist here.
      return element.type === "hidden" ? undefined : "clickable";
    case "FRAME":
    case "IFRAME":
      return "frame";
    default:
      return undefined;
  }
}

function getFirstNonEmptyTextNode(element: HTMLElement): ?Text {
  for (const node of element.childNodes) {
    if (node instanceof Text) {
      if (node.data.trim() !== "") {
        return node;
      }
    } else if (node instanceof HTMLElement) {
      const result = getFirstNonEmptyTextNode(node);
      if (result != null) {
        return result;
      }
    }
  }
  return undefined;
}
<|endoftext|>


<commit_before>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

const socket = io('/client');
const LOCAL_SAVE_KEY = 'visual-regression-testing-config';

function processTestsData(tests, oldTestsData) {
    tests.forEach((test, idx) => {
        let passed = 0;
        test.index = idx;
        test.results.forEach(result => {
            // Threshold?
            if (result.diffRatio < 0.001) {
                passed++;
            }
            let timestamp = test.lastRun || 0;
            result.diff = result.diff + '?' + timestamp;
            result.actual = result.actual + '?' + timestamp;
            result.expected = result.expected + '?' + timestamp;
        });
        test.percentage = passed === 0 ? 0 : Math.round(passed / test.results.length * 100);
        if (test.percentage === 100) {
            test.summary = 'success';
        }
        else if (test.percentage < 50) {
            test.summary = 'exception';
        }
        else {
            test.summary = 'warning';
        }

        // Keep select status not change.
        if (oldTestsData && oldTestsData[idx]) {
            test.selected = oldTestsData[idx].selected;
        }
        else {
            test.selected = false;
        }
    });
    return tests;
}

const app = new Vue({
    el: '#app',
    data: {
        fullTests: [],
        currentTestName: '',
        sortBy: 'name',
        searchString: '',
        running: false,

        allSelected: false,
        lastSelectedIndex: -1,

        versions: [],

        showIframeDialog: false,
        previewIframeSrc: '',
        previewTitle: '',

        runConfig: {
            noHeadless: false,
            replaySpeed: 5,
            actualVersion: 'local',
            expectedVersion: null,
            renderer: 'canvas',
            threads: 1
        }
    },
    computed: {
        tests() {
            let sortFunc = this.sortBy === 'name'
                ? (a, b) => a.name.localeCompare(b.name)
                : (a, b) => {
                    if (a.percentage === b.percentage) {
                        if (a.actualErrors && b.actualErrors) {
                            if (a.actualErrors.length === b.actualErrors.length) {
                                return a.name.localeCompare(b.name);
                            }
                            else {
                                return b.actualErrors.length - a.actualErrors.length;
                            }
                        }
                        else {
                            return a.name.localeCompare(b.name);
                        }
                    }
                    return a.percentage - b.percentage;
                };

            if (!this.searchString) {
                // Not modify the original tests data.
                return this.fullTests.slice().sort(sortFunc);
            }

            let searchString = this.searchString.toLowerCase();
            return this.fullTests.filter(test => {
                return test.name.toLowerCase().match(searchString);
            }).sort(sortFunc);
        },

        selectedTests() {
            return this.fullTests.filter(test => {
                return test.selected;
            });
        },
        unfinishedTests() {
            return this.fullTests.filter(test => {
                return test.status !== 'finished';
            });
        },
        failedTests() {
            return this.fullTests.filter(test => {
                return test.status === 'finished' && test.summary !== 'success';
            });
        },

        currentTest() {
            let currentTest = this.fullTests.find(item => item.name === this.currentTestName);
            if (!currentTest) {
                currentTest = this.fullTests[0];
            }
            return currentTest;
        },

        currentTestUrl() {
            return window.location.origin + '/test/' + this.currentTestName + '.html';
        },

        currentTestRecordUrl() {
            return window.location.origin + '/test/runTest/recorder/index.html#' + this.currentTestName;
        },

        isSelectAllIndeterminate: {
            get() {
                if (!this.tests.length) {
                    return true;
                }
                return this.tests.some(test => {
                    return test.selected !== this.tests[0].selected;
                });
            },
            set() {}
        }
    },
    methods: {
        goto(url) {
            window.location.hash = '#' + url;
        },
        toggleSort() {
            this.sortBy = this.sortBy === 'name' ? 'percentage' : 'name';
        },
        handleSelectAllChange(val) {
            // Only select filtered tests.
            this.tests.forEach(test => {
                test.selected = val;
            });
            this.isSelectAllIndeterminate = false;
        },
        handleSelect(idx) {
            Vue.nextTick(() => {
                this.lastSelectedIndex = idx;
            });
        },
        handleShiftSelect(idx) {
            if (this.lastSelectedIndex < 0) {
                return;
            }
            let start = Math.min(this.lastSelectedIndex, idx);
            let end = Math.max(this.lastSelectedIndex, idx);
            let selected = !this.tests[idx].selected;   // Will change
            for (let i = start; i < end; i++) {
                this.tests[i].selected = selected;
            }
        },
        runSingleTest(testName) {
            runTests([testName]);
        },
        run(runTarget) {
            let tests;
            if (runTarget === 'selected') {
                tests = this.selectedTests;
            }
            else if (runTarget === 'unfinished') {
                tests = this.unfinishedTests;
            }
            else if (runTarget === 'failed') {
                tests = this.failedTests;
            }
            else {
                tests = this.fullTests;
            }
            runTests(tests.map(test => test.name));
        },
        stopTests() {
            this.running = false;
            socket.emit('stop');
        },

        preview(test, version) {
            let searches = [];

            let ecVersion = test[version + 'Version'];
            if (ecVersion !== 'local') {
                searches.push('__ECDIST__=' + ecVersion);
            }
            if (test.useSVG) {
                searches.push('__RENDERER__=svg');
            }
            let src = test.fileUrl;
            if (searches.length) {
                src = src + '?' + searches.join('&');
            }
            this.previewIframeSrc = `../../${src}`;
            this.previewTitle = src;
            this.showIframeDialog = true;
        }
    }
});

// Save and restore
try {
    Object.assign(app.runConfig, JSON.parse(localStorage.getItem(LOCAL_SAVE_KEY)));
}
catch (e) {}
app.$watch('runConfig', () => {
    localStorage.setItem(LOCAL_SAVE_KEY, JSON.stringify(app.runConfig));
}, {deep: true});

function runTests(tests) {
    if (!tests.length) {
        app.$notify({
            title: 'No test selected.',
            position: 'top-right'
        });
        return;
    }
    if (!app.runConfig.expectedVersion || !app.runConfig.actualVersion) {
        app.$notify({
            title: 'No echarts version selected.',
            position: 'top-right'
        });
        return;
    }
    app.running = true;
    socket.emit('run', {
        tests,
        expectedVersion: app.runConfig.expectedVersion,
        actualVersion: app.runConfig.actualVersion,
        threads: app.runConfig.threads,
        renderer: app.runConfig.renderer,
        noHeadless: app.runConfig.noHeadless,
        replaySpeed: app.runConfig.noHeadless
            ? app.runConfig.replaySpeed
            : 5 // Force run at 5x speed
    });
}

socket.on('connect', () => {
    console.log('Connected');

    app.$el.style.display = 'block';
});

let firstUpdate = true;
socket.on('update', msg => {
    let hasFinishedTest = !!msg.tests.find(test => test.status === 'finished');
    if (!hasFinishedTest && firstUpdate) {
        app.$confirm('It seems you haven\'t run any test yet!
Do you want to start now?', 'Tip', {
            confirmButtonText: 'Yes',
            cancelButtonText: 'No',
            dangerouslyUseHTMLString: true,
            center: true
        }).then(value => {
            runTests(msg.tests.map(test => test.name));
        }).catch(() => {});
    }
    // TODO
    app.running = !!msg.running;
    app.fullTests = processTestsData(msg.tests, app.fullTests);

    firstUpdate = false;
});
socket.on('finish', res => {
    app.$notify({
        type: 'success',
        title: `${res.count} test complete`,
        message: `Cost: ${(res.time / 1000).toFixed(1)} s. Threads: ${res.threads}`,
        position: 'top-right',
        duration: 8000
    });
    console.log(`${res.count} test complete, Cost: ${(res.time / 1000).toFixed(1)} s. Threads: ${res.threads}`);
    app.running = false;
});
socket.on('abort', res => {
    app.$notify({
        type: 'info',
        title: `Aborted`,
        duration: 4000
    });
    app.running = false;
});
socket.on('versions', versions => {
    app.versions = versions.filter(version => {
        return !version.startsWith('2.')
            && !version.match('beta')
            && !version.match('rc');
    }).reverse();
    if (!app.runConfig.expectedVersion) {
        app.runConfig.expectedVersion = app.versions[0];
    }
    app.versions.unshift('local');
});

function updateTestHash() {
    app.currentTestName = window.location.hash.slice(1);
}
updateTestHash();
window.addEventListener('hashchange', updateTestHash);<commit_msg>test(visual): decrease the pass threshold of image diff.<commit_after>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

const socket = io('/client');
const LOCAL_SAVE_KEY = 'visual-regression-testing-config';

function processTestsData(tests, oldTestsData) {
    tests.forEach((test, idx) => {
        let passed = 0;
        test.index = idx;
        test.results.forEach(result => {
            // Threshold?
            if (result.diffRatio < 0.0001) {
                passed++;
            }
            let timestamp = test.lastRun || 0;
            result.diff = result.diff + '?' + timestamp;
            result.actual = result.actual + '?' + timestamp;
            result.expected = result.expected + '?' + timestamp;
        });
        test.percentage = passed === 0 ? 0 : Math.round(passed / test.results.length * 100);
        if (test.percentage === 100) {
            test.summary = 'success';
        }
        else if (test.percentage < 50) {
            test.summary = 'exception';
        }
        else {
            test.summary = 'warning';
        }

        // Keep select status not change.
        if (oldTestsData && oldTestsData[idx]) {
            test.selected = oldTestsData[idx].selected;
        }
        else {
            test.selected = false;
        }
    });
    return tests;
}

const app = new Vue({
    el: '#app',
    data: {
        fullTests: [],
        currentTestName: '',
        sortBy: 'name',
        searchString: '',
        running: false,

        allSelected: false,
        lastSelectedIndex: -1,

        versions: [],

        showIframeDialog: false,
        previewIframeSrc: '',
        previewTitle: '',

        runConfig: {
            noHeadless: false,
            replaySpeed: 5,
            actualVersion: 'local',
            expectedVersion: null,
            renderer: 'canvas',
            threads: 1
        }
    },
    computed: {
        tests() {
            let sortFunc = this.sortBy === 'name'
                ? (a, b) => a.name.localeCompare(b.name)
                : (a, b) => {
                    if (a.percentage === b.percentage) {
                        if (a.actualErrors && b.actualErrors) {
                            if (a.actualErrors.length === b.actualErrors.length) {
                                return a.name.localeCompare(b.name);
                            }
                            else {
                                return b.actualErrors.length - a.actualErrors.length;
                            }
                        }
                        else {
                            return a.name.localeCompare(b.name);
                        }
                    }
                    return a.percentage - b.percentage;
                };

            if (!this.searchString) {
                // Not modify the original tests data.
                return this.fullTests.slice().sort(sortFunc);
            }

            let searchString = this.searchString.toLowerCase();
            return this.fullTests.filter(test => {
                return test.name.toLowerCase().match(searchString);
            }).sort(sortFunc);
        },

        selectedTests() {
            return this.fullTests.filter(test => {
                return test.selected;
            });
        },
        unfinishedTests() {
            return this.fullTests.filter(test => {
                return test.status !== 'finished';
            });
        },
        failedTests() {
            return this.fullTests.filter(test => {
                return test.status === 'finished' && test.summary !== 'success';
            });
        },

        currentTest() {
            let currentTest = this.fullTests.find(item => item.name === this.currentTestName);
            if (!currentTest) {
                currentTest = this.fullTests[0];
            }
            return currentTest;
        },

        currentTestUrl() {
            return window.location.origin + '/test/' + this.currentTestName + '.html';
        },

        currentTestRecordUrl() {
            return window.location.origin + '/test/runTest/recorder/index.html#' + this.currentTestName;
        },

        isSelectAllIndeterminate: {
            get() {
                if (!this.tests.length) {
                    return true;
                }
                return this.tests.some(test => {
                    return test.selected !== this.tests[0].selected;
                });
            },
            set() {}
        }
    },
    methods: {
        goto(url) {
            window.location.hash = '#' + url;
        },
        toggleSort() {
            this.sortBy = this.sortBy === 'name' ? 'percentage' : 'name';
        },
        handleSelectAllChange(val) {
            // Only select filtered tests.
            this.tests.forEach(test => {
                test.selected = val;
            });
            this.isSelectAllIndeterminate = false;
        },
        handleSelect(idx) {
            Vue.nextTick(() => {
                this.lastSelectedIndex = idx;
            });
        },
        handleShiftSelect(idx) {
            if (this.lastSelectedIndex < 0) {
                return;
            }
            let start = Math.min(this.lastSelectedIndex, idx);
            let end = Math.max(this.lastSelectedIndex, idx);
            let selected = !this.tests[idx].selected;   // Will change
            for (let i = start; i < end; i++) {
                this.tests[i].selected = selected;
            }
        },
        runSingleTest(testName) {
            runTests([testName]);
        },
        run(runTarget) {
            let tests;
            if (runTarget === 'selected') {
                tests = this.selectedTests;
            }
            else if (runTarget === 'unfinished') {
                tests = this.unfinishedTests;
            }
            else if (runTarget === 'failed') {
                tests = this.failedTests;
            }
            else {
                tests = this.fullTests;
            }
            runTests(tests.map(test => test.name));
        },
        stopTests() {
            this.running = false;
            socket.emit('stop');
        },

        preview(test, version) {
            let searches = [];

            let ecVersion = test[version + 'Version'];
            if (ecVersion !== 'local') {
                searches.push('__ECDIST__=' + ecVersion);
            }
            if (test.useSVG) {
                searches.push('__RENDERER__=svg');
            }
            let src = test.fileUrl;
            if (searches.length) {
                src = src + '?' + searches.join('&');
            }
            this.previewIframeSrc = `../../${src}`;
            this.previewTitle = src;
            this.showIframeDialog = true;
        }
    }
});

// Save and restore
try {
    Object.assign(app.runConfig, JSON.parse(localStorage.getItem(LOCAL_SAVE_KEY)));
}
catch (e) {}
app.$watch('runConfig', () => {
    localStorage.setItem(LOCAL_SAVE_KEY, JSON.stringify(app.runConfig));
}, {deep: true});

function runTests(tests) {
    if (!tests.length) {
        app.$notify({
            title: 'No test selected.',
            position: 'top-right'
        });
        return;
    }
    if (!app.runConfig.expectedVersion || !app.runConfig.actualVersion) {
        app.$notify({
            title: 'No echarts version selected.',
            position: 'top-right'
        });
        return;
    }
    app.running = true;
    socket.emit('run', {
        tests,
        expectedVersion: app.runConfig.expectedVersion,
        actualVersion: app.runConfig.actualVersion,
        threads: app.runConfig.threads,
        renderer: app.runConfig.renderer,
        noHeadless: app.runConfig.noHeadless,
        replaySpeed: app.runConfig.noHeadless
            ? app.runConfig.replaySpeed
            : 5 // Force run at 5x speed
    });
}

socket.on('connect', () => {
    console.log('Connected');

    app.$el.style.display = 'block';
});

let firstUpdate = true;
socket.on('update', msg => {
    let hasFinishedTest = !!msg.tests.find(test => test.status === 'finished');
    if (!hasFinishedTest && firstUpdate) {
        app.$confirm('It seems you haven\'t run any test yet!
Do you want to start now?', 'Tip', {
            confirmButtonText: 'Yes',
            cancelButtonText: 'No',
            dangerouslyUseHTMLString: true,
            center: true
        }).then(value => {
            runTests(msg.tests.map(test => test.name));
        }).catch(() => {});
    }
    // TODO
    app.running = !!msg.running;
    app.fullTests = processTestsData(msg.tests, app.fullTests);

    firstUpdate = false;
});
socket.on('finish', res => {
    app.$notify({
        type: 'success',
        title: `${res.count} test complete`,
        message: `Cost: ${(res.time / 1000).toFixed(1)} s. Threads: ${res.threads}`,
        position: 'top-right',
        duration: 8000
    });
    console.log(`${res.count} test complete, Cost: ${(res.time / 1000).toFixed(1)} s. Threads: ${res.threads}`);
    app.running = false;
});
socket.on('abort', res => {
    app.$notify({
        type: 'info',
        title: `Aborted`,
        duration: 4000
    });
    app.running = false;
});
socket.on('versions', versions => {
    app.versions = versions.filter(version => {
        return !version.startsWith('2.')
            && !version.match('beta')
            && !version.match('rc');
    }).reverse();
    if (!app.runConfig.expectedVersion) {
        app.runConfig.expectedVersion = app.versions[0];
    }
    app.versions.unshift('local');
});

function updateTestHash() {
    app.currentTestName = window.location.hash.slice(1);
}
updateTestHash();
window.addEventListener('hashchange', updateTestHash);<|endoftext|>


<commit_before>var _ = require('lodash');
var request = require('request');
var Sails = require('../../lib').Sails;
var assert = require('assert');
var fs = require('fs-extra');
var request = require('request');
var appHelper = require('./helpers/appHelper');
var path = require('path');

describe('middleware :: ', function() {

  describe('favicon :: ', function() {

    var appName = 'testApp';

    before(function(done) {
      this.timeout(5000);
      appHelper.build(done);
    });

    after(function() {
      process.chdir('../');
      // appHelper.teardown();
    });

    describe('with no favicon file in the assets folder', function() {

      before(function(done) {
        appHelper.lift(function(err, _sailsServer) {
          assert(!err);
          sailsServer = _sailsServer;
          return done();
        });
      });

      after(function(done) {
        sailsServer.lower(done);
      });

      it('the default sailboat favicon should be provided', function(done) {

        var default_favicon = fs.readFileSync(path.resolve(__dirname, '../../lib/hooks/http/public/favicon.ico'));
        request(
          {
            method: 'GET',
            uri: 'http://localhost:1342/favicon.ico',
          },
          function(err, response, body) {
            assert.equal(default_favicon.toString('utf-8'), body);
            return done();
          }
        );

      });

    });

    describe('with a favicon file in the assets folder', function() {

      var customFaviconPath = path.resolve(__dirname, 'fixtures/favicon.ico');
      before(function(done) {
        console.log(customFaviconPath);
        fs.copySync(customFaviconPath, path.resolve('../', appName, '.tmp/public/favicon.ico'));
        appHelper.lift(function(err, _sailsServer) {
          assert(!err);
          sailsServer = _sailsServer;
          return done();
        });
      });

      after(function(done) {
        sailsServer.lower(done);
      });

      it('the default sailboat favicon should be provided', function(done) {
        var custom_favicon = fs.readFileSync(customFaviconPath);
        request(
          {
            method: 'GET',
            uri: 'http://localhost:1342/favicon.ico',
          },
          function(err, response, body) {
            assert.equal(custom_favicon.toString('utf-8'), body);
            return done();
          }
        );

      });

    });

  });

});
<commit_msg>Remove "custom favicon" test<commit_after>var _ = require('lodash');
var request = require('request');
var Sails = require('../../lib').Sails;
var assert = require('assert');
var fs = require('fs-extra');
var request = require('request');
var appHelper = require('./helpers/appHelper');
var path = require('path');

describe('middleware :: ', function() {

  describe('favicon :: ', function() {

    var appName = 'testApp';

    before(function(done) {
      this.timeout(5000);
      appHelper.build(done);
    });

    after(function() {
      process.chdir('../');
      // appHelper.teardown();
    });

    describe('with no favicon file in the assets folder', function() {

      before(function(done) {
        appHelper.lift(function(err, _sailsServer) {
          assert(!err);
          sailsServer = _sailsServer;
          return done();
        });
      });

      after(function(done) {
        sailsServer.lower(done);
      });

      it('the default sailboat favicon should be provided', function(done) {

        var default_favicon = fs.readFileSync(path.resolve(__dirname, '../../lib/hooks/http/public/favicon.ico'));
        request(
          {
            method: 'GET',
            uri: 'http://localhost:1342/favicon.ico',
          },
          function(err, response, body) {
            assert.equal(default_favicon.toString('utf-8'), body);
            return done();
          }
        );

      });

    });

  });

});
<|endoftext|>


<commit_before>require("should");
var InventoryMovement = require("../../data-util/inventory/inventory-movement-data-util");
var helper = require("../../helper");
var moment = require("moment");
var validate = require("dl-models").validator.inventory.inventoryMovement;

var InventoryMovementManager = require("../../../src/managers/inventory/inventory-movement-manager");
var inventoryMovementManager = null;

//delete unitest data
// var DLModels = require('dl-models');
// var map = DLModels.map;
// var MachineType = DLModels.master.MachineType;

before('#00. connect db', function (done) {
    helper.getDb()
        .then(db => {
            inventoryMovementManager = new InventoryMovementManager(db, {
                username: 'dev'
            });
            done();
        })
        .catch(e => {
            done(e);
        });
});

var createdId;
it("#01. should success when create new data", function (done) {
    InventoryMovement.getNewData()
        .then((data) => inventoryMovementManager.create(data))
        .then((id) => {
            id.should.be.Object();
            createdId = id;
            done();
        })
        .catch((e) => {
            done(e);
        });
});

var createdData;
it(`#02. should success when get created data with id`, function (done) {
    inventoryMovementManager.getSingleById(createdId)
        .then((data) => {
            data.should.instanceof(Object);
            validate(data);
            createdData = data;
            done();
        })
        .catch((e) => {
            done(e);
        });
});

it('#03. should success when create report', function (done) {
    var info = {};
    info.storageId = createdData.storageId;
    info.type = createdData.type;
    info.productId = createdData.productId;
    info.shiftIm = createdData.shiftIm;
    info.dateFrom = moment("1970-01-01").format("YYYY-MM-DD");
    info.dateTo = moment().format("YYYY-MM-DD");

    inventoryMovementManager.getMovementReport(info)
        .then(result => {
            var inventoryMovement = result.data;
            inventoryMovement.should.instanceof(Array);
            inventoryMovement.length.should.not.equal(0);
            done();
        }).catch(e => {
            done(e);
        });
});

var resultForExcelTest = {};
it("#04. should success when read data", function (done) {
    inventoryMovementManager.read({
        filter: {
            _id: createdId
        }
    })
        .then((documents) => {
            resultForExcelTest = documents;
            documents.should.have.property("data");
            documents.data.should.be.instanceof(Array);
            documents.data.length.should.not.equal(0);
            done();
        })
        .catch((e) => {
            done(e);
        });
});

var filter = {};
it('#05. should success when get data for Excel Report', function (done) {
    inventoryMovementManager.getXls(resultForExcelTest, filter)
        .then(xlsData => {
            xlsData.should.have.property('data');
            xlsData.should.have.property('options');
            xlsData.should.have.property('name');
            done();
        }).catch(e => {
            done(e);
        });
});

it("#06. should success when destroy all unit test data", function (done) {
    inventoryMovementManager.destroy(createdData._id)
        .then((result) => {
            result.should.be.Boolean();
            result.should.equal(true);
            done();
        })
        .catch((e) => {
            done(e);
        });
});
<commit_msg>update unit test<commit_after>require("should");
var InventoryMovement = require("../../data-util/inventory/inventory-movement-data-util");
var helper = require("../../helper");
var moment = require("moment");
var validate = require("dl-models").validator.inventory.inventoryMovement;

var InventoryMovementManager = require("../../../src/managers/inventory/inventory-movement-manager");
var inventoryMovementManager = null;

//delete unitest data
// var DLModels = require('dl-models');
// var map = DLModels.map;
// var MachineType = DLModels.master.MachineType;

before('#00. connect db', function (done) {
    helper.getDb()
        .then(db => {
            inventoryMovementManager = new InventoryMovementManager(db, {
                username: 'dev'
            });
            done();
        })
        .catch(e => {
            done(e);
        });
});

var createdId;
it("#01. should success when create new data", function (done) {
    InventoryMovement.getNewData()
        .then((data) => inventoryMovementManager.create(data))
        .then((id) => {
            id.should.be.Object();
            createdId = id;
            done();
        })
        .catch((e) => {
            done(e);
        });
});

var createdData;
it(`#02. should success when get created data with id`, function (done) {
    inventoryMovementManager.getSingleById(createdId)
        .then((data) => {
            data.should.instanceof(Object);
            validate(data);
            createdData = data;
            done();
        })
        .catch((e) => {
            done(e);
        });
});

var resultForExcelTest = {};
it("#03. should success when read data", function (done) {
    inventoryMovementManager.getMovementReport({
        filter: {
            _id: createdId
        }
    })
        .then((documents) => {
            resultForExcelTest = documents;
            documents.should.have.property("data");
            documents.data.should.be.instanceof(Array);
            documents.data.length.should.not.equal(0);
            done();
        })
        .catch((e) => {
            done(e);
        });
});

var filter = {};
it('#04. should success when get data for Excel Report', function (done) {
    inventoryMovementManager.getXls(resultForExcelTest, filter)
        .then(xlsData => {
            xlsData.should.have.property('data');
            xlsData.should.have.property('options');
            xlsData.should.have.property('name');
            done();
        }).catch(e => {
            done(e);
        });
});

it("#05. should success when destroy all unit test data", function (done) {
    inventoryMovementManager.destroy(createdData._id)
        .then((result) => {
            result.should.be.Boolean();
            result.should.equal(true);
            done();
        })
        .catch((e) => {
            done(e);
        });
});
<|endoftext|>


<commit_before>var FooBar = (function () {
    function FooBar() {
        this.name = 'wil';
    }
    return FooBar;
}());
<commit_msg>purge lint violations<commit_after>//var FooBar = (function () {
//    function FooBar() {
//        this.name = 'wil';
//    }
//    return FooBar;
//}());
<|endoftext|>


<commit_before><!-- 多说js加载开始，一个页面只需要加载一次 -->
var duoshuoQuery = {
    short_name: "gefangshuai",
    sso: {
        login: "/sso-login",//替换为你自己的回调地址
        logout: "/sso-logout"//替换为你自己的回调地址
    }

};
(function () {
    var ds = document.createElement('script');
    ds.type = 'text/javascript';
    ds.async = true;
    ds.src = 'http://static.duoshuo.com/embed.js';
    ds.charset = 'UTF-8';
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ds);
})();
<!-- 多说js加载结束，一个页面只需要加载一次 -->
<commit_msg>seo 优化<commit_after><!-- 多说js加载开始，一个页面只需要加载一次 -->
var duoshuoQuery = {
    short_name: "gefangshuai",
    sso: {
        login: "/sso-login",//替换为你自己的回调地址
        logout: "/sso-logout"//替换为你自己的回调地址
    }

};
(function () {
    var ds = document.createElement('script');
    ds.type = 'text/javascript';
    ds.async = true;
    ds.src = 'http://static.duoshuo.com/embed.js';
    ds.charset = 'UTF-8';
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ds);
})();

<!-- 多说js加载结束，一个页面只需要加载一次 -->
<!-- google analytics-->
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-72898178-1', 'auto');
ga('send', 'pageview');<|endoftext|>


<commit_before>var sectionHeight = function() {
  var total    = $(window).height(),
      $section = $('section').css('height','auto');

  if ($section.outerHeight(true) < total) {
    var margin = $section.outerHeight(true) - $section.height();
    $section.height(total - margin - 20);
  } else {
    $section.css('height','auto');
  }
}

$(window).resize(sectionHeight);

$(document).ready(function(){
  $("section h1, section h2").each(function(){
    $("nav ul").append("
" + $(this).text() + "
");
    $(this).attr("id",$(this).text().toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g,''));
    $("nav ul li:first-child a").parent().addClass("active");
  });

  $("nav ul li").on("click", "a", function(event) {
    var position = $($(this).attr("href")).offset().top - 190;
    $("html, body").animate({scrollTop: position}, 400);
    $("nav ul li a").parent().removeClass("active");
    $(this).parent().addClass("active");
    event.preventDefault();
  });

  sectionHeight();

  $('img').load(sectionHeight);
});

fixScale = function(doc) {

  var addEvent = 'addEventListener',
      type = 'gesturestart',
      qsa = 'querySelectorAll',
      scales = [1, 1],
      meta = qsa in doc ? doc[qsa]('meta[name=viewport]') : [];

  function fix() {
    meta.content = 'width=device-width,minimum-scale=' + scales[0] + ',maximum-scale=' + scales[1];
    doc.removeEventListener(type, fix, true);
  }

  if ((meta = meta[meta.length - 1]) && addEvent in doc) {
    fix();
    scales = [.25, 1.6];
    doc[addEvent](type, fix, true);
  }
};<commit_msg>codacy<commit_after>var sectionHeight = function() {
  var total    = $(window).height(),
      $section = $('section').css('height','auto');

  if ($section.outerHeight(true) < total) {
    var margin = $section.outerHeight(true) - $section.height();
    $section.height(total - margin - 20);
  } else {
    $section.css('height','auto');
  }
}

$(window).resize(sectionHeight);

$(document).ready(function(){
  $("section h1, section h2").each(function(){
    $("nav ul").append("
" + $(this).text() + "
");
    $(this).attr("id",$(this).text().toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g,''));
    $("nav ul li:first-child a").parent().addClass("active");
  });

  $("nav ul li").on("click", "a", function(event) {
    var position = $($(this).attr("href")).offset().top - 190;
    $("html, body").animate({scrollTop: position}, 400);
    $("nav ul li a").parent().removeClass("active");
    $(this).parent().addClass("active");
    event.preventDefault();
  });

  sectionHeight();

  $('img').load(sectionHeight);
});

var fixScale = function(doc) {

  var addEvent = 'addEventListener',
      type = 'gesturestart',
      qsa = 'querySelectorAll',
      scales = [1, 1],
      meta = qsa in doc ? doc[qsa]('meta[name=viewport]') : [];

  function fix() {
    meta.content = 'width=device-width,minimum-scale=' + scales[0] + ',maximum-scale=' + scales[1];
    doc.removeEventListener(type, fix, true);
  }

  if ((meta = meta[meta.length - 1]) && addEvent in doc) {
    fix();
    scales = [.25, 1.6];
    doc[addEvent](type, fix, true);
  }
};
<|endoftext|>


<commit_before>'use strict';

app.controller('loginCtrl', ['$scope', 'QLNS', function($scope, QLNS){

}]);<commit_msg>them phuong thuc login va logout<commit_after>'use strict';

app.controller('loginCtrl', ['$scope', 'QLNS', '$window', function($scope, QLNS, $window){

    $scope.admin = {
        TAIKHOAN: '',
        MATKHAU: ''
    };

    // login lấy giá trị TAIKHOAN vs MATKHAU từ form để xét qua API
    $scope.login = function(){
        QLNS.login.POST($scope.admin).then(function(res){
            if(res.data.status === '0'){
                $scope.err = res.data.comment;
            } else {
                $window.location.href = '/';
            }
        });
    };

    // phương thức trả thuộc tính showLogin về false là về trang đang nhập
    $scope.logout = function(){
      QLNS.logout.GET().then(function(){
          $window.location.href = '/login';
      });
    };

}]);<|endoftext|>


<commit_before>'use strict';
var $ = require('jquery');

/* Send with ajax calls to work with api2 */
var apiV2Config = function (options) {
    var defaults = {
        withCredentials: true
    }
    var opts = $.extend({}, defaults, options);
    return function (xhr) {
        xhr.withCredentials = opts.withCredentials;
        xhr.setRequestHeader('Content-Type', 'application/vnd.api+json;');
        xhr.setRequestHeader('Accept', 'application/vnd.api+json; ext=bulk');
    };
};

var unwrap = function (value) {
    return typeof(value) === 'function' ? value() : value;
};

module.exports = {
    apiV2Config: apiV2Config,
    unwrap: unwrap
};
<commit_msg>Add missing semicolon<commit_after>'use strict';
var $ = require('jquery');

/* Send with ajax calls to work with api2 */
var apiV2Config = function (options) {
    var defaults = {
        withCredentials: true
    };
    var opts = $.extend({}, defaults, options);
    return function (xhr) {
        xhr.withCredentials = opts.withCredentials;
        xhr.setRequestHeader('Content-Type', 'application/vnd.api+json;');
        xhr.setRequestHeader('Accept', 'application/vnd.api+json; ext=bulk');
    };
};

var unwrap = function (value) {
    return typeof(value) === 'function' ? value() : value;
};

module.exports = {
    apiV2Config: apiV2Config,
    unwrap: unwrap
};
<|endoftext|>