<commit_before>var fs = require('fs');
var inquirer = require("inquirer");
var mit = require("./licenses/mit")
var isc = require("./licenses/isc")
var bsd3 = require("./licenses/bsd3")
var apache2 = require("./licenses/apache2")
var unlicense = require("./licenses/unlicense")

module.exports = makeLicense

function makeLicense (args) {

  if (args.license === 'MIT') {
    var questions = copyrightQuestions();
    inquirer.prompt(questions).then(function(answers){
      var license = "The MIT License (MIT)\n\n"
      license += "Copyright (c) "+ answers.years + " " + answers.name;
      license += mit;
      print(license);
    });
  }
  else if (args.license === 'ISC'){
    var questions = copyrightQuestions();
      inquirer.prompt(questions).then(function(answers){
        var license = "Copyright (c) "
        license += answers.years + ", " + answers.name;
        license += isc;
        print(license);
    });
  }
  else if (args.license === 'BSD 2'){
    var questions = copyrightQuestions();
      inquirer.prompt(questions).then(function(answers){
        var license = "Copyright (c) "
        license += answers.years + ", " + answers.name;
        license += bsd2;
        print(license);
    });
  }
  else if (args.license === 'BSD 3'){
    var questions = copyrightQuestions();
      inquirer.prompt(questions).then(function(answers){
        var license = "Copyright (c) "
        license += answers.years + ", " + answers.name;
        license += bsd3;
        print(license);
    });
  }
  else if (args.license === 'Apache 2.0'){
    var questions = copyrightQuestions();
      inquirer.prompt(questions, function(answers){
        var license = "Copyright (c) "
        license += answers.years + ", " + answers.name;
        license += apache2;
        print(license);
    });
  }
  else if (args.license === 'NO LICENSE'){
    var questions = copyrightQuestions();
      inquirer.prompt(questions).then(function(answers){
        var license = "Copyright (c) "
        license += answers.years + ", " + answers.name;
        print(license);
    });
  }
  else if (args.license === 'UNLICENSE') {
    var questions = unlicenseQuestions();
    var filename=''
      inquirer.prompt(questions).then(function(answers){
        filename = answers.filename;
        print(unlicense, filename);
      })
  }
  else{
    throw Error('License Not Found');
  }
}

function copyrightQuestions() {
   var questions = [
      {
        type: "input",
        name: "name",
        message: "Full Name"
      },
      {
        type: "input",
        name: "years",
        message: "Year(s)"
      }
    ];

    return questions;
}

function unlicenseQuestions() {
   var questions = [
      {
        type: "input",
        name: "filename",
        message: "File name",
        default: "UNLICENSE"
      }
    ];
    return questions;
}

function print(license, filename) {
    if (!filename) {
      var filename = "LICENSE";
    }
    var stream = fs.createWriteStream(filename);
    stream.once('open', function(fd) {
      stream.write(license);
      stream.end();
    });
};
<commit_msg>Fix prompt syntax for apache2 license<commit_after>var fs = require('fs');
var inquirer = require("inquirer");
var mit = require("./licenses/mit")
var isc = require("./licenses/isc")
var bsd3 = require("./licenses/bsd3")
var apache2 = require("./licenses/apache2")
var unlicense = require("./licenses/unlicense")

module.exports = makeLicense

function makeLicense (args) {

  if (args.license === 'MIT') {
    var questions = copyrightQuestions();
    inquirer.prompt(questions).then(function(answers){
      var license = "The MIT License (MIT)\n\n"
      license += "Copyright (c) "+ answers.years + " " + answers.name;
      license += mit;
      print(license);
    });
  }
  else if (args.license === 'ISC'){
    var questions = copyrightQuestions();
      inquirer.prompt(questions).then(function(answers){
        var license = "Copyright (c) "
        license += answers.years + ", " + answers.name;
        license += isc;
        print(license);
    });
  }
  else if (args.license === 'BSD 2'){
    var questions = copyrightQuestions();
      inquirer.prompt(questions).then(function(answers){
        var license = "Copyright (c) "
        license += answers.years + ", " + answers.name;
        license += bsd2;
        print(license);
    });
  }
  else if (args.license === 'BSD 3'){
    var questions = copyrightQuestions();
      inquirer.prompt(questions).then(function(answers){
        var license = "Copyright (c) "
        license += answers.years + ", " + answers.name;
        license += bsd3;
        print(license);
    });
  }
  else if (args.license === 'Apache 2.0'){
    var questions = copyrightQuestions();
      inquirer.prompt(questions).then(function(answers){
        var license = "Copyright (c) "
        license += answers.years + ", " + answers.name;
        license += apache2;
        print(license);
    });
  }
  else if (args.license === 'NO LICENSE'){
    var questions = copyrightQuestions();
      inquirer.prompt(questions).then(function(answers){
        var license = "Copyright (c) "
        license += answers.years + ", " + answers.name;
        print(license);
    });
  }
  else if (args.license === 'UNLICENSE') {
    var questions = unlicenseQuestions();
    var filename=''
      inquirer.prompt(questions).then(function(answers){
        filename = answers.filename;
        print(unlicense, filename);
      })
  }
  else{
    throw Error('License Not Found');
  }
}

function copyrightQuestions() {
   var questions = [
      {
        type: "input",
        name: "name",
        message: "Full Name"
      },
      {
        type: "input",
        name: "years",
        message: "Year(s)"
      }
    ];

    return questions;
}

function unlicenseQuestions() {
   var questions = [
      {
        type: "input",
        name: "filename",
        message: "File name",
        default: "UNLICENSE"
      }
    ];
    return questions;
}

function print(license, filename) {
    if (!filename) {
      var filename = "LICENSE";
    }
    var stream = fs.createWriteStream(filename);
    stream.once('open', function(fd) {
      stream.write(license);
      stream.end();
    });
};
<|endoftext|>


<commit_before>
// modules ====================================================
var express = require("express");
var r = require("rethinkdb");
var bluebird = require("bluebird");
//var jwt = require("express-jwt");
//var cors = require("cors");
//var dbModel = new db();
//dbModel.setupDisastersDB();

// configuration ============================================
// config files
//require('../Javascript/mongodb_config.js');
var config = require('./Javascript/rethinkdb_config.js');

var app = express();
//app.use(express.static(__dirname + "/public"));
var port = 3500;        // or var port = process.env.PORT || 3500;
var scrapeCount = 1;
var database = "quake";

// USGS earthquake data feed url
var feedUrl = "earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_month.geojson";

// Fetch data from USGS, transform locations into point objects.
// Insert the data into the 'earthquakes' table.
var refresh = r.table("quakes").insert(r.http(feedUrl)("features").merge(function(item) {
    return {
        geometry: r.point(item("geometry")("coordinates")(0),
            item("geometry")("coordinates")(1))
    }
}), {conflict: "replace"});

// Initial setup, creating the database and table and geospatial
// index on the 'geometry' property, access the above querry and
// populate the table with data
var conn;
r.connect(config.database).then(function(c) {
    conn = c;
    return r.dbCreate(config.database.db).run(conn);
}).then(function() {
    return r.tableCreate("quakes").run(conn);
}).then(function() {
    return r.table("quakes").indexCreate(
        "propertiesTime", r.row('properties')('time'), {multi: true}).run(conn);
}).then(function() {
    return refresh.run(conn);
}).error(function(err) {
    if(err.msg.indexOf("already exists") == -1)
        console.log(err);
}).finally(function () {
    if(conn)
        conn.close();
});

// Use the refresh query above to automatically update the 'earthquake' database
// with new data at 30 minutes intervals and delete the records that are older than 30 days
var time;
setInterval(function() {
    time = new Date();
    console.log("Scrapping number: " + scrapeCount++ + ", current-time: " + time.getHours() + ":" + time.getMinutes() + ":" + time.getSeconds());

    var connect;

    r.connect(config.database).then(function (c) {
        connect = c;

        return bluebird.join(refresh.run(connect), r.table("quakes")
            .filter(r.epochTime(r.row("properties")("time").div(1000)).lt(
                r.now().sub(60 * 60 * 24 * 30))).delete().run(connect));
    }).error(function(err) {
        console.log("Failed to refresh:", err);
    }).finally(function() {
        if (connect)
            connect.close();
    });
}, (30 * 1000 * 60));

// start app =================================================
app.listen(port);
console.log("Scrapper Server running on port: " + port);
exports = module.exports = app;
<commit_msg>Modified the scrapper server<commit_after>
// modules ====================================================
var express = require("express");
var r = require("rethinkdb");
var bluebird = require("bluebird");
//var jwt = require("express-jwt");
//var cors = require("cors");
//var dbModel = new db();
//dbModel.setupDisastersDB();

// configuration ============================================
// config files
//require('../Javascript/mongodb_config.js');
var config = require('./Javascript/rethinkdb_config.js');

var app = express();
//app.use(express.static(__dirname + "/public"));
var port = 3500;        // or var port = process.env.PORT || 3500;
var scrapeCount = 1;
var database = "quake";

// USGS earthquake data feed url
var feedUrl = "earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_month.geojson";

// Fetch data from USGS, transform locations into point objects.
// Insert the data into the 'earthquakes' table.
var refresh = r.table("quakes").insert(r.http(feedUrl)("features").merge(function(item) {
    return {
        geometry: r.point(item("geometry")("coordinates")(0),
            item("geometry")("coordinates")(1))
    }
}), {conflict: "replace"});

// Initial setup, creating the database and table and geospatial
// index on the 'geometry' property, access the above querry and
// populate the table with data
var conn;
r.connect(config.database).then(function(c) {
    conn = c;
    return r.dbCreate(config.database.db).run(conn);
}).then(function() {
    return r.tableCreate("quakes").run(conn);
}).then(function() {
    return r.table("quakes").indexCreate(
        "propertiesTime", r.row('properties')('time'), {multi: true}).run(conn);
}).then(function() {
    return refresh.run(conn);
}).error(function(err) {
    if(err.msg.indexOf("already exists") == -1)
        console.log(err);
}).finally(function () {
    if(conn)
        conn.close();
});

// Use the refresh query above to automatically update the 'earthquake' database
// with new data at 30 minutes intervals and delete the records that are older than 30 days
var time;
setInterval(function() {
    time = new Date();
    console.log("Scrapping number: " + scrapeCount++ + ", current-time: " + time.getHours() + ":" + time.getMinutes() + ":" + time.getSeconds());

    var connect;

    r.connect(config.database).then(function (c) {
        connect = c;

        return bluebird.join(refresh.run(connect), r.table("quakes")
            .filter(r.epochTime(r.row("properties")("time").div(1000)).lt(
                r.now().sub(60 * 60 * 24 * 30))).delete().run(connect));
    }).error(function(err) {
        console.log("Failed to refresh:", err);
    }).finally(function() {
        if (connect)
            connect.close();
    });
}, (300 * 1000 * 60));

// start app =================================================
app.listen(port);
console.log("Scrapper Server running on port: " + port);
exports = module.exports = app;
<|endoftext|>


<commit_before>Groups = {};

Groups.addToGroup = function(groups, user, groupLimit) {
  if(!groups){
    groups = [];
    groups.push([user]);
  } else {
    var target;
    console.log("Limit: " +groupLimit)
    console.log(groups)
    _.each(groups, function(group, index){
      if(group.length < groupLimit) target = index;
    });
    if(target < groups.length){
      groups[target].push(user)
    } else {
      groups.push([user]);
    }
  }
  return groups;
}

Groups.removeFromGroup = function(groups, user, groupLimit) {
  for (var i = groups.length - 1; i >= 0; i--) {
    groups[i] = _.filter(groups[i], function(id){ return id !== user});
  };
  groups = groups.filter(function(group){return group.length > 0});
  return groups;
}

Groups.addToRandomGroup = function(users, groupLimit) {
  return Groups.shuffleIntoGroups(users, groupLimit);
}

Groups.removeFromRandomGroup = function(users, groupLimit) {
  return Groups.shuffleIntoGroups(users, groupLimit);
}

//User IDS
Groups.shuffleIntoGroups = function(users, groupLimit){
  var numGroups = Math.ceil(users.length/groupLimit);
  console.log("Number of groups "+ numGroups)
  var users = Meteor.users.find({_id: {$in: users}}).fetch();
  var dM = generateDMatrix(users);
  var groups = new Array(numGroups);
  users = shuffleArray(users);

  for(var i = 0; i < users.length; i++){
    var user = users[i];
    var bestFit;
    var bestFitDistance = -1;
    var insertEnd = false;

    for(var gi = 0; gi < numGroups && !insertEnd; gi++){
      if(!groups[gi]){
        groups[gi] = [user];
        insertEnd = true;
      } else {
        var gD = Groups.getGroupDistance(groups[gi].concat([user]), dM);
        if(gD > bestFitDistance && groups[gi].length < groupLimit){
          bestFitDistance = gD;
          bestFit = gi;
        }
      }
    }

    if(!insertEnd){
      groups[bestFit].push(user);
    }
  }

  var group_by_id = groups.map(function(group){
    return group.map(function(user){return user._id})
  });

  group_by_id = group_by_id.filter(function(group){return group.length > 0});

  group_by_id.sort(function(a, b){
    return b.length - a.length; // ASC -> a - b; DESC -> b - a
  });

  // no one eats alone
  if (group_by_id.length > 1) {
    var loner_group;
    var smallest_group = 0;
    for (var i = group_by_id.length - 1; i >= 0; i--) {
      if (group_by_id[i].length === 1) {
        loner_group = i;
      } else if (group_by_id[smallest_group].length > group_by_id[i].length) {
        smallest_group = i;
      }
    };

    if (loner_group){
      group_by_id[smallest_group].push(group_by_id[loner_group][0]);
      group_by_id.splice(loner_group, 1);
    }
  }

  return group_by_id;
}

Groups.getGroupDistanceFromIDs = function(group){
  var users = Meteor.users.find({_id: {$in: group}}).fetch();
  var gD = Groups.getGroupDistance(users);
  return gD;
}

//User objects
Groups.getGroupDistance = function(group, matrix){
  var total = 0;
  var count = 0;
  if (group.length < 2) return 0;
  for(var i = 0; i < group.length; i++){
    var userA = group[i];
    for(var j = i+1; j < group.length; j++){
      var userB = group[j];
      count ++;
      if(matrix){
        total += matrix[userA._id][userB._id];
      } else {
        total += Groups.userDistance(userA,userB);
      }
    }
  }
  return total/count;
}

//User objects
function generateDMatrix(users){
  var m = {};
  for (var i = users.length - 1; i >= 0; i--) {
    var user = users[i];
     var userM = {};
     for (var j = users.length - 1; j >= 0; j--) {
       var compUser = users[j];
       userM[compUser._id] = Groups.userDistance(user, compUser);
     };
     m[user._id] = userM;
  };
  return m;
}

function shuffleArray(array) {
  var currentIndex = array.length, temporaryValue, randomIndex ;
  if(array.length < 2) return array;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}

//User objects
Groups.userDistance = function(userA, userB) {
  if (userA._id === userB._id) return 0;
  if(!userA.profile || !userB.profile) return 100;

  console.log('\n====================================\n\nComparing:')
  console.log(userA.profile)
  console.log(userB.profile)
  var distance = 0;

  distance += (userA.profile.gender === userB.profile.gender) ? 0 : 10;

  if (userA.profile.gradYear && userB.profile.gradYear) {
    distance += Math.abs(userA.profile.gradYear - userB.profile.gradYear);
  }

  distance += (userA.profile.program === userB.profile.program) ? 0 : 10;

  console.log('\nDistance: ' + distance);
  console.log('\n====================================\n')
  return distance;
}

// On the server
Meteor.methods({
  getGroupDistance: function (group) {
    return Groups.getGroupDistance(group);
  }
});

<commit_msg>better distance function<commit_after>Groups = {};

Groups.addToGroup = function(groups, user, groupLimit) {
  if(!groups){
    groups = [];
    groups.push([user]);
  } else {
    var target;
    _.each(groups, function(group, index){
      if(group.length < groupLimit) target = index;
    });
    if(target < groups.length){
      groups[target].push(user)
    } else {
      groups.push([user]);
    }
  }
  return groups;
}

Groups.removeFromGroup = function(groups, user, groupLimit) {
  for (var i = groups.length - 1; i >= 0; i--) {
    groups[i] = _.filter(groups[i], function(id){ return id !== user});
  };
  groups = groups.filter(function(group){return group.length > 0});
  return groups;
}

Groups.addToRandomGroup = function(users, groupLimit) {
  return Groups.shuffleIntoGroups(users, groupLimit);
}

Groups.removeFromRandomGroup = function(users, groupLimit) {
  return Groups.shuffleIntoGroups(users, groupLimit);
}

//User IDS
Groups.shuffleIntoGroups = function(users, groupLimit){
  var numGroups = Math.ceil(users.length/groupLimit);
  var users = Meteor.users.find({_id: {$in: users}}).fetch();
  var dM = generateDMatrix(users);
  var groups = new Array(numGroups);
  users = shuffleArray(users);

  for(var i = 0; i < users.length; i++){
    var user = users[i];
    var bestFit;
    var bestFitDistance = -1;
    var insertEnd = false;

    for(var gi = 0; gi < numGroups && !insertEnd; gi++){
      if(!groups[gi]){
        groups[gi] = [user];
        insertEnd = true;
      } else {
        var gD = Groups.getGroupDistance(groups[gi].concat([user]), dM);
        if(gD > bestFitDistance && groups[gi].length < groupLimit){
          bestFitDistance = gD;
          bestFit = gi;
        }
      }
    }

    if(!insertEnd){
      groups[bestFit].push(user);
    }
  }

  var group_by_id = groups.map(function(group){
    return group.map(function(user){return user._id})
  });

  group_by_id = group_by_id.filter(function(group){return group.length > 0});

  group_by_id.sort(function(a, b){
    return b.length - a.length; // ASC -> a - b; DESC -> b - a
  });

  // no one eats alone
  if (group_by_id.length > 1) {
    var loner_group;
    var smallest_group = 0;
    for (var i = group_by_id.length - 1; i >= 0; i--) {
      if (group_by_id[i].length === 1) {
        loner_group = i;
      } else if (group_by_id[smallest_group].length > group_by_id[i].length) {
        smallest_group = i;
      }
    };

    if (loner_group){
      group_by_id[smallest_group].push(group_by_id[loner_group][0]);
      group_by_id.splice(loner_group, 1);
    }
  }

  return group_by_id;
}

Groups.getGroupDistanceFromIDs = function(group){
  var users = Meteor.users.find({_id: {$in: group}}).fetch();
  var gD = Groups.getGroupDistance(users);
  return gD;
}

//User objects
Groups.getGroupDistance = function(group, matrix){
  var total = 0;
  var count = 0;
  if (group.length < 2) return 0;
  for(var i = 0; i < group.length; i++){
    var userA = group[i];
    for(var j = i+1; j < group.length; j++){
      var userB = group[j];
      count ++;
      if(matrix){
        total += matrix[userA._id][userB._id];
      } else {
        total += Groups.userDistance(userA,userB);
      }
    }
  }
  return total/count;
}

//User objects
function generateDMatrix(users){
  var m = {};
  for (var i = users.length - 1; i >= 0; i--) {
    var user = users[i];
     var userM = {};
     for (var j = users.length - 1; j >= 0; j--) {
       var compUser = users[j];
       userM[compUser._id] = Groups.userDistance(user, compUser);
     };
     m[user._id] = userM;
  };
  return m;
}

function shuffleArray(array) {
  var currentIndex = array.length, temporaryValue, randomIndex ;
  if(array.length < 2) return array;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}

//User objects
Groups.userDistance = function(userA, userB) {
  if (userA._id === userB._id) return 0;
  if(!userA.profile || !userB.profile) return 100;

  console.log('\n====================================\n\nComparing:')
  console.log(userA.profile)
  console.log(userB.profile)
  var distance = 0;

  distance += (userA.profile.kwesttrip === userB.profile.kwesttrip) ? 0 : 100;

  if (userA.profile.gradYear && userB.profile.gradYear) {
    var a = userA.profile.section + userA.profile.gradYear.toString();
    var b = userB.profile.section + userB.profile.gradYear.toString();
    distance += (a === b) ? 0 : 50;
  }

  distance += (userA.profile.program === userB.profile.program) ? 0 : 30;

  distance += (userA.profile.gender === userB.profile.gender) ? 0 : 30;

  if (userA.profile.gradYear && userB.profile.gradYear) {
    distance += Math.abs(userA.profile.gradYear - userB.profile.gradYear) * 5;
  }

  console.log('\nDistance: ' + distance);
  console.log('\n====================================\n')
  return distance;
}

// On the server
Meteor.methods({
  getGroupDistance: function (group) {
    return Groups.getGroupDistance(group);
  }
});

<|endoftext|>


<commit_before>Z.Map.include(/** @lends maptalks.Map.prototype */{
    _zoom:function (nextZoomLevel, origin, startScale) {
        if (!this.options['zoomable'] || this._zooming) { return; }
        this._originZoomLevel = this.getZoom();
        nextZoomLevel = this._checkZoomLevel(nextZoomLevel);
        this.onZoomStart(nextZoomLevel);
        var zoomOffset;
        if (origin) {
            origin = new Z.Point(this.width / 2, this.height / 2);
            zoomOffset = this._getZoomCenterOffset(nextZoomLevel, origin, startScale);
        }
        this.onZoomEnd(nextZoomLevel, zoomOffset);
    },

    _zoomAnimation:function (nextZoomLevel, origin, startScale) {
        if (!this.options['zoomable'] || this._zooming) { return; }
        if (Z.Util.isNil(startScale)) {
            startScale = 1;
        }
        if (Z.Util.isNil(this._originZoomLevel)) {
            this._originZoomLevel = this.getZoom();
        }
        nextZoomLevel = this._checkZoomLevel(nextZoomLevel);
        if (this._originZoomLevel === nextZoomLevel) {
            return;
        }

        this.onZoomStart(nextZoomLevel);
        if (!origin) {
            origin = new Z.Point(this.width / 2, this.height / 2);
        }
        this._startZoomAnimation(startScale, origin, nextZoomLevel);
    },

    _startZoomAnimation:function (startScale, transOrigin, nextZoomLevel) {
        var me = this;
        var resolutions = this._getResolutions();
        var endScale = resolutions[this._originZoomLevel] / resolutions[nextZoomLevel];
        var zoomOffset = this._getZoomCenterOffset(nextZoomLevel, transOrigin, startScale);
        if (zoomOffset.x === 0 && zoomOffset.y === 0) {
            //center is out of maxExtent
            transOrigin = new Z.Point(this.width / 2, this.height / 2);
        }
        var duration = this.options['zoomAnimationDuration'] * Math.abs(endScale - startScale) / Math.abs(endScale - 1);
        this._getRenderer().animateZoom(
            {
                startScale : startScale,
                endScale : endScale,
                origin : transOrigin,
                duration : duration
            },
            function () {
                me.onZoomEnd(nextZoomLevel, zoomOffset);
            }
        );
    },

    onZoomStart: function (nextZoomLevel) {
        this._zooming = true;
        this._enablePanAnimation = false;
        /**
          * zoomstart event
          * @event maptalks.Map#zoomstart
          * @type {Object}
          * @property {String} type                    - zoomstart
          * @property {maptalks.Map} target            - the map fires event
          * @property {Number} from                    - zoom level zooming from
          * @property {Number} to                      - zoom level zooming to
          */
        this._fireEvent('zoomstart', {'from' : this._originZoomLevel, 'to': nextZoomLevel});
    },

    onZoomEnd:function (nextZoomLevel, zoomOffset) {
        this._zoomLevel = nextZoomLevel;
        if (zoomOffset) {
            this._offsetCenterByPixel(zoomOffset._multi(-1));
        }
        var _originZoomLevel = this._originZoomLevel;
        this._originZoomLevel = nextZoomLevel;
        this._getRenderer().onZoomEnd();
        this._zooming = false;
        /**
          * zoomend event
          * @event maptalks.Map#zoomend
          * @type {Object}
          * @property {String} type                    - zoomend
          * @property {maptalks.Map} target            - the map fires event
          * @property {Number} from                    - zoom level zooming from
          * @property {Number} to                      - zoom level zooming to
          */
        this._fireEvent('zoomend', {'from' : _originZoomLevel, 'to': nextZoomLevel});
        this.checkSize();
    },

    _checkZoomLevel:function (nextZoomLevel) {
        var maxZoom = this.getMaxZoom(),
            minZoom = this.getMinZoom();
        if (nextZoomLevel < minZoom) {
            nextZoomLevel = minZoom;
        }
        if (nextZoomLevel > maxZoom) {
            nextZoomLevel = maxZoom;
        }
        return nextZoomLevel;
    },

    _getZoomCenterOffset:function (nextZoomLevel, origin, startScale) {
        if (Z.Util.isNil(startScale)) {
            startScale = 1;
        }
        var resolutions = this._getResolutions();
        var zScale;
        var zoomOffset;
        if (nextZoomLevel < this._originZoomLevel) {
            zScale = resolutions[nextZoomLevel + 1] / resolutions[nextZoomLevel];
            zoomOffset = new Z.Point(
                    -(origin.x - this.width / 2) * (startScale - zScale),
                    -(origin.y - this.height / 2) * (startScale - zScale)
                );
        } else {
            zScale = resolutions[nextZoomLevel - 1] / resolutions[nextZoomLevel];
            zoomOffset = new Z.Point(
                    (origin.x - this.width / 2) * (zScale - startScale),
                    (origin.y - this.height / 2) * (zScale - startScale)
                );
        }

        var newCenter = this.containerPointToCoordinate(new Z.Point(this.width / 2 + zoomOffset.x, this.height / 2 + zoomOffset.y));
        if (!this._verifyExtent(newCenter)) {
            return new Z.Point(0, 0);
        }

        return zoomOffset;
    },

    _getZoomMillisecs:function () {
        return 600;
    }
});
<commit_msg>remove unnecessary checkSize<commit_after>Z.Map.include(/** @lends maptalks.Map.prototype */{
    _zoom:function (nextZoomLevel, origin, startScale) {
        if (!this.options['zoomable'] || this._zooming) { return; }
        this._originZoomLevel = this.getZoom();
        nextZoomLevel = this._checkZoomLevel(nextZoomLevel);
        this.onZoomStart(nextZoomLevel);
        var zoomOffset;
        if (origin) {
            origin = new Z.Point(this.width / 2, this.height / 2);
            zoomOffset = this._getZoomCenterOffset(nextZoomLevel, origin, startScale);
        }
        this.onZoomEnd(nextZoomLevel, zoomOffset);
    },

    _zoomAnimation:function (nextZoomLevel, origin, startScale) {
        if (!this.options['zoomable'] || this._zooming) { return; }
        if (Z.Util.isNil(startScale)) {
            startScale = 1;
        }
        if (Z.Util.isNil(this._originZoomLevel)) {
            this._originZoomLevel = this.getZoom();
        }
        nextZoomLevel = this._checkZoomLevel(nextZoomLevel);
        if (this._originZoomLevel === nextZoomLevel) {
            return;
        }

        this.onZoomStart(nextZoomLevel);
        if (!origin) {
            origin = new Z.Point(this.width / 2, this.height / 2);
        }
        this._startZoomAnimation(startScale, origin, nextZoomLevel);
    },

    _startZoomAnimation:function (startScale, transOrigin, nextZoomLevel) {
        var me = this;
        var resolutions = this._getResolutions();
        var endScale = resolutions[this._originZoomLevel] / resolutions[nextZoomLevel];
        var zoomOffset = this._getZoomCenterOffset(nextZoomLevel, transOrigin, startScale);
        if (zoomOffset.x === 0 && zoomOffset.y === 0) {
            //center is out of maxExtent
            transOrigin = new Z.Point(this.width / 2, this.height / 2);
        }
        var duration = this.options['zoomAnimationDuration'] * Math.abs(endScale - startScale) / Math.abs(endScale - 1);
        this._getRenderer().animateZoom(
            {
                startScale : startScale,
                endScale : endScale,
                origin : transOrigin,
                duration : duration
            },
            function () {
                me.onZoomEnd(nextZoomLevel, zoomOffset);
            }
        );
    },

    onZoomStart: function (nextZoomLevel) {
        this._zooming = true;
        this._enablePanAnimation = false;
        /**
          * zoomstart event
          * @event maptalks.Map#zoomstart
          * @type {Object}
          * @property {String} type                    - zoomstart
          * @property {maptalks.Map} target            - the map fires event
          * @property {Number} from                    - zoom level zooming from
          * @property {Number} to                      - zoom level zooming to
          */
        this._fireEvent('zoomstart', {'from' : this._originZoomLevel, 'to': nextZoomLevel});
    },

    onZoomEnd:function (nextZoomLevel, zoomOffset) {
        this._zoomLevel = nextZoomLevel;
        if (zoomOffset && (zoomOffset.x !== 0 || zoomOffset.y !== 0)) {
            this._offsetCenterByPixel(zoomOffset._multi(-1));
        }
        var _originZoomLevel = this._originZoomLevel;
        this._originZoomLevel = nextZoomLevel;
        this._getRenderer().onZoomEnd();
        this._zooming = false;
        /**
          * zoomend event
          * @event maptalks.Map#zoomend
          * @type {Object}
          * @property {String} type                    - zoomend
          * @property {maptalks.Map} target            - the map fires event
          * @property {Number} from                    - zoom level zooming from
          * @property {Number} to                      - zoom level zooming to
          */
        this._fireEvent('zoomend', {'from' : _originZoomLevel, 'to': nextZoomLevel});
    },

    _checkZoomLevel:function (nextZoomLevel) {
        var maxZoom = this.getMaxZoom(),
            minZoom = this.getMinZoom();
        if (nextZoomLevel < minZoom) {
            nextZoomLevel = minZoom;
        }
        if (nextZoomLevel > maxZoom) {
            nextZoomLevel = maxZoom;
        }
        return nextZoomLevel;
    },

    _getZoomCenterOffset:function (nextZoomLevel, origin, startScale) {
        if (Z.Util.isNil(startScale)) {
            startScale = 1;
        }
        var resolutions = this._getResolutions();
        var zScale;
        var zoomOffset;
        if (nextZoomLevel < this._originZoomLevel) {
            zScale = resolutions[nextZoomLevel + 1] / resolutions[nextZoomLevel];
            zoomOffset = new Z.Point(
                    -(origin.x - this.width / 2) * (startScale - zScale),
                    -(origin.y - this.height / 2) * (startScale - zScale)
                );
        } else {
            zScale = resolutions[nextZoomLevel - 1] / resolutions[nextZoomLevel];
            zoomOffset = new Z.Point(
                    (origin.x - this.width / 2) * (zScale - startScale),
                    (origin.y - this.height / 2) * (zScale - startScale)
                );
        }

        var newCenter = this.containerPointToCoordinate(new Z.Point(this.width / 2 + zoomOffset.x, this.height / 2 + zoomOffset.y));
        if (!this._verifyExtent(newCenter)) {
            return new Z.Point(0, 0);
        }

        return zoomOffset;
    },

    _getZoomMillisecs:function () {
        return 600;
    }
});
<|endoftext|>


<commit_before>TModalTextView = kindof(TWindow)
TModalTextView.can.init = function(Desktop, fileName, viewClass, colors) {
	dnaof(this)
	this.title = fileName
	this.scrollBar = TScrollBar.create(colors)
	this.add(this.scrollBar)
	this.viewer = viewClass.create(fileName)
	this.viewer.pal = colors
	this.add(this.viewer)
	this.scrollBar.disabled = true
	this.scrollBar.track = this.viewer.track.bind(this.viewer)
	this.scrollBar.pal = [this.viewer.pal[0], this.viewer.pal[1]]
	this.react(100, keycode.ESCAPE, this.close)//Prompt)
	this.react(100, keycode['o'], this.commandShowOutput)
	this.react(0, keycode.F9, this.commandRun)
	this.react(100, keycode.F9, this.commandRunNew)
	this.actor = this.viewer
	this.runCommand = ''
	this.runCwd = (fileName.split('/'))
	this.runCwd.pop()
	this.runCwd = this.runCwd.join('/')
	var syntax = colors
	this.pal = [syntax[0], syntax[1], syntax[2], syntax[3]]//colors
	this.fileName = fileName
}

TModalTextView.can.runDone = function() {
	this.hideOutput()
}

var fileRunCommands = []
function findFileCmd(name) {
	var n = fileRunCommands
	for (var i = 0; i < n.length; i++) if (n[i].name == name) return n[i]
}

TModalTextView.can.commandRun = function() {
	if (this.runCommand == '') {
		var N = findFileCmd(this.fileName)
		if (N) {
			this.runCommand = N.command
		} else return this.commandRunNew()
	}
	this.viewer.save()
	var o = this.norton.output
	o.size(this.w - 2, this.h - 2) // НАДО: используй window.getInnerSize // а его пока нет
	o.pos(1, 1)
	var f = this.runDone.bind(this)
	this.showOutput()
	o.respawn(this.runCommand, '', this.runCwd, f)
	return true
}

TModalTextView.can.commandRunNew = function() {
	var me = this
	var w = TInputBox.create(50, 'Выполнить', 'Имя файла и передаваемые аргументы', function(text) {
		me.runCommand = text
		var N = findFileCmd(me.fileName)
		if (N) N.command = text; else fileRunCommands.push({name: me.fileName, command: text})

		if (text != '') me.commandRun()
		else messageBox(
			me.getDesktop(),
			'Обратите внимание, что вы ничего не ввели и комманда теперь пустая')
	})
	w.input.setText('node ' + this.fileName.split('/').pop())
	this.getDesktop().showModal(w)
	return true
}

TModalTextView.can.showOutput = function() {
	var me = this, o = me.norton.output
	me.viewer.curLineHilite = false
	me.hide(me.viewer)
	me.hide(me.scrollBar)
	me.add(o)
	me.actor = undefined
	o.disabled = true
}

TModalTextView.can.hideOutput = function() {
	var me = this, o = me.norton.output
	o.disabled = false
	me.remove(me.norton.output)
	o.parent = me.norton
	me.show(me.viewer)
	me.show(me.scrollBar)
	me.actor = me.viewer
	me.repaint()
}

TModalTextView.can.commandShowOutput = function() {
	if (this.actor == this.viewer) this.showOutput()
	else this.hideOutput()
	return true
}

TModalTextView.can.close = function() {
	if (this.viewer.isModified != undefined) this.viewer.savePosState()
	dnaof(this)
}

TModalTextView.can.closePrompt = function() {
	if (this.viewer.isModified == undefined) return this.close() // not an edit
	var me = this
	if (this.viewer.isModified()) {
		var win = TExitSaveCancel.create()
		win.link = this
		this.getDesktop().showModal(win)
	} else this.close()
	return true
}

TModalTextView.can.onKey = function(hand) {
	if (hand.plain && hand.key == keycode.ESCAPE && hand.physical) { // необычное решение
		if (this.viewer.isModified == undefined || this.viewer.isModified() == false) {
			if (hand.down) this.close();
			return true
		}
		else if (hand.down) {
			if (this.warn) this.warn.hidden = false
			else {
				var s = 'Control-Esc: выйти без сохранения'
				this.warn = TDialog.create()
				this.warn.title = 'Файл не сохранён'
				this.warn.size(s.length + 14, 6)
				this.warn.pos((this.w - this.warn.w)>>1, (this.h - this.warn.h)>>1)
				var l
				l = TLabel.create(s), l.pos(5, 5)
				this.warn.add(l, this.warn.w - 10, 1)
				l = TLabel.create('F2 или Control-S: сохранить'), l.pos(5, 5)
				this.warn.add(l, this.warn.w - 10, 1)
				this.add(this.warn)
			}
			this.actor = this.warn
			this.repaint()
		} else {
			if (this.warn) this.warn.hidden = true
			this.actor = this.viewer
		}
		return true
	}
	return dnaof(this, hand)
}

TModalTextView.can.loadFile = function() {
	this.viewer.lines = fs.readFileSync(this.fileName).toString().replace(/\r/g, '').split('\n')
}

TModalTextView.can.size = function(W, H) {
	dnaof(this, W, H)
	this.viewer.size(W - 4, H - 2)
	this.viewer.pos(1, 1)
	this.scrollBar.size(2, H - 2)
	this.scrollBar.pos(W - 2, 1)
}

linesCountStart = 1
symCountStart = 1

TModalTextView.can.draw = function(state) {
	dnaof(this, state)
	if (this.viewer.isModified) {
		var B = this.pal[1] | 0x1000, F = 0x2f2//this.pal[0]
		if (this.viewer.isModified()) this.print(2, this.h-1, ' '+graphChar.on+' ', F, B);
		else this.print(2, this.h-1, ' '+graphChar.off+' ', F, B)
		this.print(7, this.h-1, ' ' + (this.viewer.para+linesCountStart)
			+ ':' + (this.viewer.sym+symCountStart) +' ', this.pal[0], this.pal[1])
	}
}

var filePositions = []
function findFileMem(name) {
	for (var i = 0; i < filePositions.length; i++) {
		var N = filePositions[i]
		if (N.name == name) return N
	}
}

TFileEdit = kindof(TEdit)
TFileEdit.can.init = function(fileName) {
	dnaof(this)
	this.fileName = fileName
	this.text.setText(fs.readFileSync(fileName).toString())
	if (this.fileName.indexOf('.asm') > 0
		|| this.fileName.indexOf('.inc') > 0) this.text.lexer = ASMLexer
	if (this.fileName.indexOf('.sh') > 0) this.text.lexer = ShellLexer
	var N = findFileMem(fileName)
	if (N) {
		this.para = N.para, this.sym = N.sym, this.delta = N.delta
		if (this.para >= this.text.L.length - 1) this.para = this.text.L.length - 1, this.sym = 0
	}
	this.react(0, keycode.F2, this.save)
	this.react(100, keycode['s'], this.save)
	this.react(100, keycode['p'], this.reloadPalette)
}

TFileEdit.can.savePosState = function() {
	var N = findFileMem(this.fileName)
	if (N) {
		N.para = this.para, N.sym = this.sym, N.delta = this.delta
	} else filePositions.push({name: this.fileName, para: this.para, sym: this.sym, delta: this.delta})
}

TFileEdit.can.save = function() {
	try {
		fs.writeFileSync(this.fileName, this.text.getText())
	} catch (e) {
		messageBox(this.getDesktop(), 'Файл "' + this.fileName.split('/').pop() + '" не удалось сохранить, ' + e)
		return true
	}
	this.text.modified = false
	this.savePosState()
	return true
}

TFileEdit.can.isModified = function() {
	return this.text.modified == true
}

TFileEdit.can.reloadPalette = function() {
	this.save()
	require('./palette')
	this.pal = getColor[theme.editor]
	this.repaint()
	return true
}

function viewFileContinue(yes) {
	if (yes == false) return
	if (this.viewer.name == 'TTextView') this.loadFile()
	this.size(this.getDesktop().w, this.getDesktop().h)
	this.getDesktop().showModal(this)
}

viewFile = function(Desktop, fileName, viewClass, colors) {
	var t = TModalTextView.create(Desktop, fileName, viewClass, colors)
	t.parent = Desktop
	try {
		var size = fs.statSync(fileName).size
	} catch (e) {
		messageBox(Desktop, 'Файл "' + fileName.split('/').pop() + '" не удалось открыть')
		return
	}
	var maxSize = 300000
	var f = viewFileContinue.bind(t)
	if (size > maxSize && ((t.viewer.name == 'TTextView') || (t.viewer.name == 'TEdit')) ) {
		messageBox(Desktop, 'Файл ' + fileName.split('/').pop() + ' великоват, '
			+ readableSize(size) + ', открыть всё равно?', f)
	} else f()
	return t
}

<commit_msg>control+C в правке чтобы прибить зависшую прогу<commit_after>TModalTextView = kindof(TWindow)
TModalTextView.can.init = function(Desktop, fileName, viewClass, colors) {
	dnaof(this)
	this.title = fileName
	this.scrollBar = TScrollBar.create(colors)
	this.add(this.scrollBar)
	this.viewer = viewClass.create(fileName)
	this.viewer.pal = colors
	this.add(this.viewer)
	this.scrollBar.disabled = true
	this.scrollBar.track = this.viewer.track.bind(this.viewer)
	this.scrollBar.pal = [this.viewer.pal[0], this.viewer.pal[1]]
	this.react(100, keycode.ESCAPE, this.close)//Prompt)
	this.react(100, keycode['o'], this.commandShowOutput)
	this.react(0, keycode.F9, this.commandRun)
	this.react(100, keycode.F9, this.commandRunNew)
	this.react(100, keycode['c'], this.commandKill)
	this.actor = this.viewer
	this.runCommand = ''
	this.runCwd = (fileName.split('/'))
	this.runCwd.pop()
	this.runCwd = this.runCwd.join('/')
	var syntax = colors
	this.pal = [syntax[0], syntax[1], syntax[2], syntax[3]]//colors
	this.fileName = fileName
}

TModalTextView.can.runDone = function() {
	this.hideOutput()
}

var fileRunCommands = []
function findFileCmd(name) {
	var n = fileRunCommands
	for (var i = 0; i < n.length; i++) if (n[i].name == name) return n[i]
}

TModalTextView.can.commandRun = function() {
	if (this.runCommand == '') {
		var N = findFileCmd(this.fileName)
		if (N) {
			this.runCommand = N.command
		} else return this.commandRunNew()
	}
	this.viewer.save()
	var o = this.norton.output
	o.size(this.w - 2, this.h - 2) // НАДО: используй window.getInnerSize // а его пока нет
	o.pos(1, 1)
	var f = this.runDone.bind(this)
	this.showOutput()
	o.respawn(this.runCommand, '', this.runCwd, f)
	return true
}

TModalTextView.can.commandKill = function() {
	var o = this.norton.output
	o.kill()
	return true
}

TModalTextView.can.commandRunNew = function() {
	var me = this
	var w = TInputBox.create(50, 'Выполнить', 'Имя файла и передаваемые аргументы', function(text) {
		me.runCommand = text
		var N = findFileCmd(me.fileName)
		if (N) N.command = text; else fileRunCommands.push({name: me.fileName, command: text})

		if (text != '') me.commandRun()
		else messageBox(
			me.getDesktop(),
			'Обратите внимание, что вы ничего не ввели и комманда теперь пустая')
	})
	w.input.setText('node ' + this.fileName.split('/').pop())
	this.getDesktop().showModal(w)
	return true
}

TModalTextView.can.showOutput = function() {
	var me = this, o = me.norton.output
	me.viewer.curLineHilite = false
	me.hide(me.viewer)
	me.hide(me.scrollBar)
	me.add(o)
	me.actor = undefined
	o.disabled = true
}

TModalTextView.can.hideOutput = function() {
	var me = this, o = me.norton.output
	o.disabled = false
	me.remove(me.norton.output)
	o.parent = me.norton
	me.show(me.viewer)
	me.show(me.scrollBar)
	me.actor = me.viewer
	me.repaint()
}

TModalTextView.can.commandShowOutput = function() {
	if (this.actor == this.viewer) this.showOutput()
	else this.hideOutput()
	return true
}

TModalTextView.can.close = function() {
	if (this.viewer.isModified != undefined) this.viewer.savePosState()
	dnaof(this)
}

TModalTextView.can.closePrompt = function() {
	if (this.viewer.isModified == undefined) return this.close() // not an edit
	var me = this
	if (this.viewer.isModified()) {
		var win = TExitSaveCancel.create()
		win.link = this
		this.getDesktop().showModal(win)
	} else this.close()
	return true
}

TModalTextView.can.onKey = function(hand) {
	if (hand.plain && hand.key == keycode.ESCAPE && hand.physical) { // необычное решение
		if (this.viewer.isModified == undefined || this.viewer.isModified() == false) {
			if (hand.down) this.close();
			return true
		}
		else if (hand.down) {
			if (this.warn) this.warn.hidden = false
			else {
				var s = 'Control-Esc: выйти без сохранения'
				this.warn = TDialog.create()
				this.warn.title = 'Файл не сохранён'
				this.warn.size(s.length + 14, 6)
				this.warn.pos((this.w - this.warn.w)>>1, (this.h - this.warn.h)>>1)
				var l
				l = TLabel.create(s), l.pos(5, 5)
				this.warn.add(l, this.warn.w - 10, 1)
				l = TLabel.create('F2 или Control-S: сохранить'), l.pos(5, 5)
				this.warn.add(l, this.warn.w - 10, 1)
				this.add(this.warn)
			}
			this.actor = this.warn
			this.repaint()
		} else {
			if (this.warn) this.warn.hidden = true
			this.actor = this.viewer
		}
		return true
	}
	return dnaof(this, hand)
}

TModalTextView.can.loadFile = function() {
	this.viewer.lines = fs.readFileSync(this.fileName).toString().replace(/\r/g, '').split('\n')
}

TModalTextView.can.size = function(W, H) {
	dnaof(this, W, H)
	this.viewer.size(W - 4, H - 2)
	this.viewer.pos(1, 1)
	this.scrollBar.size(2, H - 2)
	this.scrollBar.pos(W - 2, 1)
}

linesCountStart = 1
symCountStart = 1

TModalTextView.can.draw = function(state) {
	dnaof(this, state)
	if (this.viewer.isModified) {
		var B = this.pal[1] | 0x1000, F = 0x2f2//this.pal[0]
		if (this.viewer.isModified()) this.print(2, this.h-1, ' '+graphChar.on+' ', F, B);
		else this.print(2, this.h-1, ' '+graphChar.off+' ', F, B)
		this.print(7, this.h-1, ' ' + (this.viewer.para+linesCountStart)
			+ ':' + (this.viewer.sym+symCountStart) +' ', this.pal[0], this.pal[1])
	}
}

var filePositions = []
function findFileMem(name) {
	for (var i = 0; i < filePositions.length; i++) {
		var N = filePositions[i]
		if (N.name == name) return N
	}
}

TFileEdit = kindof(TEdit)
TFileEdit.can.init = function(fileName) {
	dnaof(this)
	this.fileName = fileName
	this.text.setText(fs.readFileSync(fileName).toString())
	if (this.fileName.indexOf('.asm') > 0
		|| this.fileName.indexOf('.inc') > 0) this.text.lexer = ASMLexer
	if (this.fileName.indexOf('.sh') > 0) this.text.lexer = ShellLexer
	var N = findFileMem(fileName)
	if (N) {
		this.para = N.para, this.sym = N.sym, this.delta = N.delta
		if (this.para >= this.text.L.length - 1) this.para = this.text.L.length - 1, this.sym = 0
	}
	this.react(0, keycode.F2, this.save)
	this.react(100, keycode['s'], this.save)
	this.react(100, keycode['p'], this.reloadPalette)
}

TFileEdit.can.savePosState = function() {
	var N = findFileMem(this.fileName)
	if (N) {
		N.para = this.para, N.sym = this.sym, N.delta = this.delta
	} else filePositions.push({name: this.fileName, para: this.para, sym: this.sym, delta: this.delta})
}

TFileEdit.can.save = function() {
	try {
		fs.writeFileSync(this.fileName, this.text.getText())
	} catch (e) {
		messageBox(this.getDesktop(), 'Файл "' + this.fileName.split('/').pop() + '" не удалось сохранить, ' + e)
		return true
	}
	this.text.modified = false
	this.savePosState()
	return true
}

TFileEdit.can.isModified = function() {
	return this.text.modified == true
}

TFileEdit.can.reloadPalette = function() {
	this.save()
	require('./palette')
	this.pal = getColor[theme.editor]
	this.repaint()
	return true
}

function viewFileContinue(yes) {
	if (yes == false) return
	if (this.viewer.name == 'TTextView') this.loadFile()
	this.size(this.getDesktop().w, this.getDesktop().h)
	this.getDesktop().showModal(this)
}

viewFile = function(Desktop, fileName, viewClass, colors) {
	var t = TModalTextView.create(Desktop, fileName, viewClass, colors)
	t.parent = Desktop
	try {
		var size = fs.statSync(fileName).size
	} catch (e) {
		messageBox(Desktop, 'Файл "' + fileName.split('/').pop() + '" не удалось открыть')
		return
	}
	var maxSize = 300000
	var f = viewFileContinue.bind(t)
	if (size > maxSize && ((t.viewer.name == 'TTextView') || (t.viewer.name == 'TEdit')) ) {
		messageBox(Desktop, 'Файл ' + fileName.split('/').pop() + ' великоват, '
			+ readableSize(size) + ', открыть всё равно?', f)
	} else f()
	return t
}

<|endoftext|>


<commit_before><commit_msg>update post parser<commit_after><|endoftext|>


<commit_before>'use strict';

var fs              = require('fs-extra');
var path            = require('path');
var Builder         = require('../../../lib/models/builder');
var BuildCommand    = require('../../../lib/commands/build');
var commandOptions  = require('../../factories/command-options');
var Promise         = require('../../../lib/ext/promise');
var stub            = require('../../helpers/stub').stub;
var MockProject     = require('../../helpers/mock-project');
var remove          = Promise.denodeify(fs.remove);
var mkTmpDirIn      = require('../../../lib/utilities/mk-tmp-dir-in');
var td              = require('testdouble');

var chai = require('../../chai');
var expect = chai.expect;
var file = chai.file;

var root            = process.cwd();
var tmproot         = path.join(root, 'tmp');

describe('models/builder.js', function() {
  var addon, builder, buildResults, tmpdir;

  describe('Windows CTRL + C Capture', function() {
    var originalPlatform, originalStdin;

    before(function() {
      originalPlatform = process.platform;
      originalStdin = process.platform;
    });

    after(function () {
      Object.defineProperty(process, 'platform', {
        value: originalPlatform
      });

      Object.defineProperty(process, 'stdin', {
        value: originalStdin
      });
    });

    it('enables raw capture on Windows', function() {
      Object.defineProperty(process, 'platform', {
        value: 'win'
      });

      Object.defineProperty(process, 'stdin', {
        value: {
          isTTY: true
        }
      });

      var trapWindowsSignals = td.function();

      builder = new Builder({
        setupBroccoliBuilder: function() { },
        cleanupOnExit: function() { },
        trapWindowsSignals: trapWindowsSignals,
        project: new MockProject()
      });

      builder.trapSignals();
      td.verify(trapWindowsSignals());
    });

    it('does not enable raw capture on non-Windows', function() {
      Object.defineProperty(process, 'platform', {
        value: 'mockOS'
      });

      Object.defineProperty(process, 'stdin', {
        value: {
          isTTY: true
        }
      });

      var trapWindowsSignals = td.function();

      builder = new Builder({
        setupBroccoliBuilder: function() { },
        cleanupOnExit: function() { },
        trapWindowsSignals: trapWindowsSignals,
        project: new MockProject()
      });

      builder.trapSignals();
      td.verify(trapWindowsSignals(), {times: 0, ignoreExtraArgs: true});
    });
  });

  describe('copyToOutputPath', function() {
    beforeEach(function() {
      return mkTmpDirIn(tmproot).then(function(dir) {
        tmpdir = dir;
        builder = new Builder({
          setupBroccoliBuilder: function() { },
          trapSignals: function() { },
          cleanupOnExit: function() { },
          project: new MockProject()
        });
      });
    });

    afterEach(function() {
      return remove(tmproot);
    });

    it('allows for non-existent output-paths at arbitrary depth', function() {
      builder.outputPath = path.join(tmpdir, 'some', 'path', 'that', 'does', 'not', 'exist');

      builder.copyToOutputPath('tests/fixtures/blueprints/basic_2');
      expect(file(path.join(builder.outputPath, 'files', 'foo.txt'))).to.exist;
    });

    var command;

    var parentPath = '..' + path.sep + '..' + path.sep;

    before(function() {
      command = new BuildCommand(commandOptions());

      builder = new Builder({
        setupBroccoliBuilder: function() { },
        trapSignals: function() { },
        cleanupOnExit: function() { },
        project: new MockProject()
      });
    });

    it('when outputPath is root directory ie., `--output-path=/` or `--output-path=C:`', function() {
      var outputPathArg = '--output-path=.';
      var outputPath = command.parseArgs([outputPathArg]).options.outputPath;
      outputPath = outputPath.split(path.sep)[0] + path.sep;
      builder.outputPath = outputPath;

      expect(builder.canDeleteOutputPath(outputPath)).to.equal(false);
    });

    it('when outputPath is project root ie., `--output-path=.`', function() {
      var outputPathArg = '--output-path=.';
      var outputPath = command.parseArgs([outputPathArg]).options.outputPath;
      builder.outputPath = outputPath;

      expect(builder.canDeleteOutputPath(outputPath)).to.equal(false);
    });

    it('when outputPath is a parent directory ie., `--output-path=' + parentPath + '`', function() {
      var outputPathArg = '--output-path=' + parentPath;
      var outputPath = command.parseArgs([outputPathArg]).options.outputPath;
      builder.outputPath = outputPath;

      expect(builder.canDeleteOutputPath(outputPath)).to.equal(false);
    });

    it('allow outputPath to contain the root path as a substring, as long as it is not a parent', function() {
      var outputPathArg = '--output-path=.';
      var outputPath = command.parseArgs([outputPathArg]).options.outputPath;
      outputPath = outputPath.substr(0, outputPath.length - 1);
      builder.outputPath = outputPath;

      expect(builder.canDeleteOutputPath(outputPath)).to.equal(true);
    });
  });

  describe('addons', function() {
    var hooksCalled;

    beforeEach(function() {
      hooksCalled = [];
      addon = {
        name: 'TestAddon',
        preBuild: function() {
          hooksCalled.push('preBuild');

          return Promise.resolve();
        },

        postBuild: function() {
          hooksCalled.push('postBuild');

          return Promise.resolve();
        },

        outputReady: function() {
          hooksCalled.push('outputReady');
        },

        buildError: function() {
          hooksCalled.push('buildError');
        },
      };

      builder = new Builder({
        setupBroccoliBuilder: function() { },
        trapSignals:          function() { },
        cleanupOnExit:        function() { },
        builder: {
          build: function() {
            hooksCalled.push('build');

            return Promise.resolve(buildResults);
          }
        },
        processBuildResult: function(buildResults) { return Promise.resolve(buildResults); },
        project: {
          addons: [addon]
        }
      });

      buildResults = 'build results';
    });

    it('allows addons to add promises preBuild', function() {
      var preBuild = stub(addon, 'preBuild', Promise.resolve());

      return builder.build().then(function() {
        expect(preBuild.called).to.equal(1, 'expected preBuild to be called');
      });
    });

    it('allows addons to add promises postBuild', function() {
      var postBuild = stub(addon, 'postBuild');

      return builder.build().then(function() {
        expect(postBuild.called).to.equal(1, 'expected postBuild to be called');
        expect(postBuild.calledWith[0][0]).to.equal(buildResults, 'expected postBuild to be called with the results');
      });
    });

    it('allows addons to add promises outputReady', function() {
      var outputReady = stub(addon, 'outputReady');

      return builder.build().then(function() {
        expect(outputReady.called).to.equal(1, 'expected outputReady to be called');
        expect(outputReady.calledWith[0][0]).to.equal(buildResults, 'expected outputReady to be called with the results');
      });
    });

    it('hooks are called in the right order', function() {
      return builder.build().then(function() {
        expect(hooksCalled).to.deep.equal(['preBuild', 'build', 'postBuild', 'outputReady']);
      });
    });

    it('should call postBuild before processBuildResult', function() {
      var called = [];

      addon.postBuild = function() {
        called.push('postBuild');
      };

      builder.processBuildResult = function() {
        called.push('processBuildResult');
      };

      return builder.build().then(function() {
        expect(called).to.deep.equal(['postBuild', 'processBuildResult']);
      });
    });

    it('should call outputReady after processBuildResult', function() {
      var called = [];

      builder.processBuildResult = function() {
        called.push('processBuildResult');
      };

      addon.outputReady = function() {
        called.push('outputReady');
      };

      return builder.build().then(function() {
        expect(called).to.deep.equal(['processBuildResult', 'outputReady']);
      });
    });

    it('buildError receives the error object from the errored step', function() {
      var thrownBuildError = new Error('buildError');
      var receivedBuildError;

      addon.buildError = function(errorThrown) {
        receivedBuildError = errorThrown;
      };

      builder.builder.build = function() {
        hooksCalled.push('build');

        return Promise.reject(thrownBuildError);
      };

      return builder.build().then(function() {
        expect(false, 'should not succeed').to.be.ok;
      }).catch(function() {
        expect(receivedBuildError).to.equal(thrownBuildError);
      });
    });

    it('calls buildError and does not call build, postBuild or outputReady when preBuild fails', function() {
      addon.preBuild = function() {
        hooksCalled.push('preBuild');

        return Promise.reject(new Error('preBuild Error'));
      };

      return builder.build().then(function() {
        expect(false, 'should not succeed').to.be.ok;
      }).catch(function() {
        expect(hooksCalled).to.deep.equal(['preBuild', 'buildError']);
      });
    });

    it('calls buildError and does not call postBuild or outputReady when build fails', function() {
      builder.builder.build = function() {
        hooksCalled.push('build');

        return Promise.reject(new Error('build Error'));
      };

      return builder.build().then(function() {
        expect(false, 'should not succeed').to.be.ok;
      }).catch(function() {
        expect(hooksCalled).to.deep.equal(['preBuild', 'build', 'buildError']);
      });
    });

    it('calls buildError when postBuild fails', function() {
      addon.postBuild = function() {
        hooksCalled.push('postBuild');

        return Promise.reject(new Error('preBuild Error'));
      };

      return builder.build().then(function() {
        expect(false, 'should not succeed').to.be.ok;
      }).catch(function() {
        expect(hooksCalled).to.deep.equal(['preBuild', 'build', 'postBuild', 'buildError']);
      });
    });

    it('calls buildError when outputReady fails', function() {
      addon.outputReady = function() {
        hooksCalled.push('outputReady');

        return Promise.reject(new Error('outputReady Error'));
      };

      return builder.build().then(function() {
        expect(false, 'should not succeed').to.be.ok;
      }).catch(function() {
        expect(hooksCalled).to.deep.equal(['preBuild', 'build', 'postBuild', 'outputReady', 'buildError']);
      });
    });
  });
});
<commit_msg>tests/models/builder: Use testdouble for mocks<commit_after>'use strict';

var fs              = require('fs-extra');
var path            = require('path');
var Builder         = require('../../../lib/models/builder');
var BuildCommand    = require('../../../lib/commands/build');
var commandOptions  = require('../../factories/command-options');
var Promise         = require('../../../lib/ext/promise');
var MockProject     = require('../../helpers/mock-project');
var remove          = Promise.denodeify(fs.remove);
var mkTmpDirIn      = require('../../../lib/utilities/mk-tmp-dir-in');
var td              = require('testdouble');

var chai = require('../../chai');
var expect = chai.expect;
var file = chai.file;

var root            = process.cwd();
var tmproot         = path.join(root, 'tmp');

describe('models/builder.js', function() {
  var addon, builder, buildResults, tmpdir;

  describe('Windows CTRL + C Capture', function() {
    var originalPlatform, originalStdin;

    before(function() {
      originalPlatform = process.platform;
      originalStdin = process.platform;
    });

    after(function () {
      Object.defineProperty(process, 'platform', {
        value: originalPlatform
      });

      Object.defineProperty(process, 'stdin', {
        value: originalStdin
      });
    });

    it('enables raw capture on Windows', function() {
      Object.defineProperty(process, 'platform', {
        value: 'win'
      });

      Object.defineProperty(process, 'stdin', {
        value: {
          isTTY: true
        }
      });

      var trapWindowsSignals = td.function();

      builder = new Builder({
        setupBroccoliBuilder: function() { },
        cleanupOnExit: function() { },
        trapWindowsSignals: trapWindowsSignals,
        project: new MockProject()
      });

      builder.trapSignals();
      td.verify(trapWindowsSignals());
    });

    it('does not enable raw capture on non-Windows', function() {
      Object.defineProperty(process, 'platform', {
        value: 'mockOS'
      });

      Object.defineProperty(process, 'stdin', {
        value: {
          isTTY: true
        }
      });

      var trapWindowsSignals = td.function();

      builder = new Builder({
        setupBroccoliBuilder: function() { },
        cleanupOnExit: function() { },
        trapWindowsSignals: trapWindowsSignals,
        project: new MockProject()
      });

      builder.trapSignals();
      td.verify(trapWindowsSignals(), {times: 0, ignoreExtraArgs: true});
    });
  });

  describe('copyToOutputPath', function() {
    beforeEach(function() {
      return mkTmpDirIn(tmproot).then(function(dir) {
        tmpdir = dir;
        builder = new Builder({
          setupBroccoliBuilder: function() { },
          trapSignals: function() { },
          cleanupOnExit: function() { },
          project: new MockProject()
        });
      });
    });

    afterEach(function() {
      return remove(tmproot);
    });

    it('allows for non-existent output-paths at arbitrary depth', function() {
      builder.outputPath = path.join(tmpdir, 'some', 'path', 'that', 'does', 'not', 'exist');

      builder.copyToOutputPath('tests/fixtures/blueprints/basic_2');
      expect(file(path.join(builder.outputPath, 'files', 'foo.txt'))).to.exist;
    });

    var command;

    var parentPath = '..' + path.sep + '..' + path.sep;

    before(function() {
      command = new BuildCommand(commandOptions());

      builder = new Builder({
        setupBroccoliBuilder: function() { },
        trapSignals: function() { },
        cleanupOnExit: function() { },
        project: new MockProject()
      });
    });

    it('when outputPath is root directory ie., `--output-path=/` or `--output-path=C:`', function() {
      var outputPathArg = '--output-path=.';
      var outputPath = command.parseArgs([outputPathArg]).options.outputPath;
      outputPath = outputPath.split(path.sep)[0] + path.sep;
      builder.outputPath = outputPath;

      expect(builder.canDeleteOutputPath(outputPath)).to.equal(false);
    });

    it('when outputPath is project root ie., `--output-path=.`', function() {
      var outputPathArg = '--output-path=.';
      var outputPath = command.parseArgs([outputPathArg]).options.outputPath;
      builder.outputPath = outputPath;

      expect(builder.canDeleteOutputPath(outputPath)).to.equal(false);
    });

    it('when outputPath is a parent directory ie., `--output-path=' + parentPath + '`', function() {
      var outputPathArg = '--output-path=' + parentPath;
      var outputPath = command.parseArgs([outputPathArg]).options.outputPath;
      builder.outputPath = outputPath;

      expect(builder.canDeleteOutputPath(outputPath)).to.equal(false);
    });

    it('allow outputPath to contain the root path as a substring, as long as it is not a parent', function() {
      var outputPathArg = '--output-path=.';
      var outputPath = command.parseArgs([outputPathArg]).options.outputPath;
      outputPath = outputPath.substr(0, outputPath.length - 1);
      builder.outputPath = outputPath;

      expect(builder.canDeleteOutputPath(outputPath)).to.equal(true);
    });
  });

  describe('addons', function() {
    var hooksCalled;

    beforeEach(function() {
      hooksCalled = [];
      addon = {
        name: 'TestAddon',
        preBuild: function() {
          hooksCalled.push('preBuild');

          return Promise.resolve();
        },

        postBuild: function() {
          hooksCalled.push('postBuild');

          return Promise.resolve();
        },

        outputReady: function() {
          hooksCalled.push('outputReady');
        },

        buildError: function() {
          hooksCalled.push('buildError');
        },
      };

      builder = new Builder({
        setupBroccoliBuilder: function() { },
        trapSignals:          function() { },
        cleanupOnExit:        function() { },
        builder: {
          build: function() {
            hooksCalled.push('build');

            return Promise.resolve(buildResults);
          }
        },
        processBuildResult: function(buildResults) { return Promise.resolve(buildResults); },
        project: {
          addons: [addon]
        }
      });

      buildResults = 'build results';
    });

    it('allows addons to add promises preBuild', function() {
      var preBuild = td.replace(addon, 'preBuild', td.function());
      td.when(preBuild(), {ignoreExtraArgs: true}).thenReturn(Promise.resolve());

      return builder.build().then(function() {
        td.verify(preBuild(), {ignoreExtraArgs: true});
      });
    });

    it('allows addons to add promises postBuild', function() {
      var postBuild = td.replace(addon, 'postBuild', td.function());

      return builder.build().then(function() {
        td.verify(postBuild(buildResults), {times: 1});
      });
    });

    it('allows addons to add promises outputReady', function() {
      var outputReady = td.replace(addon, 'outputReady', td.function());

      return builder.build().then(function() {
        td.verify(outputReady(buildResults), {times: 1});
      });
    });

    it('hooks are called in the right order', function() {
      return builder.build().then(function() {
        expect(hooksCalled).to.deep.equal(['preBuild', 'build', 'postBuild', 'outputReady']);
      });
    });

    it('should call postBuild before processBuildResult', function() {
      var called = [];

      addon.postBuild = function() {
        called.push('postBuild');
      };

      builder.processBuildResult = function() {
        called.push('processBuildResult');
      };

      return builder.build().then(function() {
        expect(called).to.deep.equal(['postBuild', 'processBuildResult']);
      });
    });

    it('should call outputReady after processBuildResult', function() {
      var called = [];

      builder.processBuildResult = function() {
        called.push('processBuildResult');
      };

      addon.outputReady = function() {
        called.push('outputReady');
      };

      return builder.build().then(function() {
        expect(called).to.deep.equal(['processBuildResult', 'outputReady']);
      });
    });

    it('buildError receives the error object from the errored step', function() {
      var thrownBuildError = new Error('buildError');
      var receivedBuildError;

      addon.buildError = function(errorThrown) {
        receivedBuildError = errorThrown;
      };

      builder.builder.build = function() {
        hooksCalled.push('build');

        return Promise.reject(thrownBuildError);
      };

      return builder.build().then(function() {
        expect(false, 'should not succeed').to.be.ok;
      }).catch(function() {
        expect(receivedBuildError).to.equal(thrownBuildError);
      });
    });

    it('calls buildError and does not call build, postBuild or outputReady when preBuild fails', function() {
      addon.preBuild = function() {
        hooksCalled.push('preBuild');

        return Promise.reject(new Error('preBuild Error'));
      };

      return builder.build().then(function() {
        expect(false, 'should not succeed').to.be.ok;
      }).catch(function() {
        expect(hooksCalled).to.deep.equal(['preBuild', 'buildError']);
      });
    });

    it('calls buildError and does not call postBuild or outputReady when build fails', function() {
      builder.builder.build = function() {
        hooksCalled.push('build');

        return Promise.reject(new Error('build Error'));
      };

      return builder.build().then(function() {
        expect(false, 'should not succeed').to.be.ok;
      }).catch(function() {
        expect(hooksCalled).to.deep.equal(['preBuild', 'build', 'buildError']);
      });
    });

    it('calls buildError when postBuild fails', function() {
      addon.postBuild = function() {
        hooksCalled.push('postBuild');

        return Promise.reject(new Error('preBuild Error'));
      };

      return builder.build().then(function() {
        expect(false, 'should not succeed').to.be.ok;
      }).catch(function() {
        expect(hooksCalled).to.deep.equal(['preBuild', 'build', 'postBuild', 'buildError']);
      });
    });

    it('calls buildError when outputReady fails', function() {
      addon.outputReady = function() {
        hooksCalled.push('outputReady');

        return Promise.reject(new Error('outputReady Error'));
      };

      return builder.build().then(function() {
        expect(false, 'should not succeed').to.be.ok;
      }).catch(function() {
        expect(hooksCalled).to.deep.equal(['preBuild', 'build', 'postBuild', 'outputReady', 'buildError']);
      });
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

var assert = require('assert');

var getUniqueTypes = require('./lib/get-unique-types.js');
var JsigASTReplacer = require('./lib/jsig-ast-replacer.js');
var JsigAST = require('../ast/');

var THIS_ASSIGNMENT_REGEX = /this\.[a-zA-Z]+\s\=/;

module.exports = StaticTypeInference;

/*  StaticTypeInference class is responsible for ahead of time
    static type inference based on the implementation of a
    function body.

    This is different to the other `TypeInference` class which
    is responsible for usage-based inference of a function. aka
    if a function is being called we can see if the function
    implements the call signature and then "infer" that the
    function must be of that type.

    This class is capable of infering a more "generic" type
    for a function declaration without it being called.

    This is the foundation for the 100% type inference mode
    of the jsig type system.
*/
function StaticTypeInference(meta) {
    this.meta = meta;
    this.counter = 0;
}

StaticTypeInference.prototype.inferFunctionType =
function inferFunctionType(node) {
    var functionText = this.meta.serializeAST(node);
    if (THIS_ASSIGNMENT_REGEX.test(functionText)) {
        return this.inferConstructorType(node);
    }
};

StaticTypeInference.prototype.inferConstructorType =
function inferConstructorType(node) {
    var errorCount = this.meta.countErrors();
    var args = [];
    for (var i = 0; i < node.params.length; i++) {
        args.push(JsigAST.param(
            node.params[i].name,
            JsigAST.inferredLiteral(
                'T' + this.counter++ + ':args[' + i + ']'
            )
        ));
    }

    var returnType = JsigAST.literal('%Void%%UnknownReturn', true);
    var inferredFuncType = JsigAST.functionType({
        result: returnType,
        args: args,
        // TODO: mark thisType as being a special open type
        // TOOD: mark thisType as a special infer ???
        thisArg: JsigAST.param('this', JsigAST.object([], null, {
            open: true
        }))
        // TODO: should we mark generics here or handle that later????
    });

    // console.log('inferredFuncType',
    //     this.meta.serializeType(inferredFuncType));

    var funcName = null;
    if (node.type === 'FunctionDeclaration') {
        funcName = node.id.name;
        var untypedFunc = this.meta.currentScope.getUntypedFunction(funcName);
        var success = this.meta.tryUpdateFunction(funcName, inferredFuncType);
        if (!success) {
            // Inference failed !!
            // TODO: complain about inference failing with an error?
            this.meta.sanityCheckErrorsState(errorCount);
            return null;
        }

        var funcScopes = this.meta.currentScope.getKnownFunctionScope(
            funcName
        ).funcScopes;
        assert(funcScopes.length === 1,
            'cannot infer function declaration for overloaded function'
        );

        var funcScope = funcScopes[0];

        // console.log('info', funcScope);
        // console.log('latest thisType', funcScope.getThisType());

        var foundReturnType = null;
        if (funcScope.knownReturnTypes.length > 0) {
            var uniqueKnownReturnTypes = getUniqueTypes(
                funcScope.knownReturnTypes
            );

            // TODO: grab the smallest union?
            assert(uniqueKnownReturnTypes.length === 1,
                'only support trivial single return funcs');
            foundReturnType = uniqueKnownReturnTypes[0];
        }

        this.meta.tryRevertFunction(
            funcName, this.inferFunctionType, untypedFunc
        );

        // TODO: update func type with the new thisType information
        // TODO: walk the function type and replace the inferred literals
        //      with actual generic literals
        // TODO: rebuild the function type object with generic literals and
        //      its location index tracking.

        // This is the function type that we inferred from trying to force
        // update the function.
        var newFuncType = JsigAST.functionType({
            result: foundReturnType === null ?
                JsigAST.literal('void') : foundReturnType,
            args: inferredFuncType.args,
            thisArg: JsigAST.param('this', funcScope.getThisType())
        });

        var replacer = new InferredLiteralReplacer();
        var astReplacer = new JsigASTReplacer(replacer, true);
        astReplacer.inlineReferences(newFuncType, newFuncType, []);

        var openThisArg = newFuncType.thisArg.value;
        var closedThisArg = JsigAST.param('this', JsigAST.object(
            openThisArg.keyValues,
            null,
            {
                open: false,
                brand: openThisArg.brand,
                inferred: openThisArg.inferred
            }
        ));

        var finalFuncType = JsigAST.functionType({
            result: newFuncType.result,
            args: newFuncType.args,
            thisArg: closedThisArg,
            generics: replacer.generics
        });

        // console.log('static type inference', {
        //     generics: finalFuncType.generics,
        //     funcType: this.meta.serializeType(finalFuncType)
        // });

        return finalFuncType;
    }
};

function InferredLiteralReplacer() {
    this.genericLiteralsTable = Object.create(null);
    this.generics = [];
    this.counter = 0;
}

InferredLiteralReplacer.prototype.replace = function replace(ast, raw, stack) {
    if (ast.type === 'inferredLiteral') {
        return this.replaceInferredLiteral(ast, stack);
    }
};

InferredLiteralReplacer.prototype.replaceInferredLiteral =
function replaceInferredLiteral(ast, stack) {
    if (this.genericLiteralsTable[ast.name]) {
        return this.genericLiteralsTable[ast.name];
    }

    var literal = JsigAST.literal('T' + this.counter++, false);
    this.generics.push(literal.name);
    this.genericLiteralsTable[ast.name] = literal;
    return literal;
};
<commit_msg>static-type-inference: mark constructor as inferred<commit_after>'use strict';

var assert = require('assert');

var getUniqueTypes = require('./lib/get-unique-types.js');
var JsigASTReplacer = require('./lib/jsig-ast-replacer.js');
var JsigAST = require('../ast/');

var THIS_ASSIGNMENT_REGEX = /this\.[a-zA-Z]+\s\=/;

module.exports = StaticTypeInference;

/*  StaticTypeInference class is responsible for ahead of time
    static type inference based on the implementation of a
    function body.

    This is different to the other `TypeInference` class which
    is responsible for usage-based inference of a function. aka
    if a function is being called we can see if the function
    implements the call signature and then "infer" that the
    function must be of that type.

    This class is capable of infering a more "generic" type
    for a function declaration without it being called.

    This is the foundation for the 100% type inference mode
    of the jsig type system.
*/
function StaticTypeInference(meta) {
    this.meta = meta;
    this.counter = 0;
}

StaticTypeInference.prototype.inferFunctionType =
function inferFunctionType(node) {
    var functionText = this.meta.serializeAST(node);
    if (THIS_ASSIGNMENT_REGEX.test(functionText)) {
        return this.inferConstructorType(node);
    }
};

StaticTypeInference.prototype.inferConstructorType =
function inferConstructorType(node) {
    var errorCount = this.meta.countErrors();
    var args = [];
    for (var i = 0; i < node.params.length; i++) {
        args.push(JsigAST.param(
            node.params[i].name,
            JsigAST.inferredLiteral(
                'T' + this.counter++ + ':args[' + i + ']'
            )
        ));
    }

    var returnType = JsigAST.literal('%Void%%UnknownReturn', true);
    var inferredFuncType = JsigAST.functionType({
        result: returnType,
        args: args,
        // TODO: mark thisType as being a special open type
        // TOOD: mark thisType as a special infer ???
        thisArg: JsigAST.param('this', JsigAST.object([], null, {
            open: true
        }))
        // TODO: should we mark generics here or handle that later????
    });

    // console.log('inferredFuncType',
    //     this.meta.serializeType(inferredFuncType));

    var funcName = null;
    if (node.type === 'FunctionDeclaration') {
        funcName = node.id.name;
        var untypedFunc = this.meta.currentScope.getUntypedFunction(funcName);
        var success = this.meta.tryUpdateFunction(funcName, inferredFuncType);
        if (!success) {
            // Inference failed !!
            // TODO: complain about inference failing with an error?
            this.meta.sanityCheckErrorsState(errorCount);
            return null;
        }

        var funcScopes = this.meta.currentScope.getKnownFunctionScope(
            funcName
        ).funcScopes;
        assert(funcScopes.length === 1,
            'cannot infer function declaration for overloaded function'
        );

        var funcScope = funcScopes[0];

        // console.log('info', funcScope);
        // console.log('latest thisType', funcScope.getThisType());

        var foundReturnType = null;
        if (funcScope.knownReturnTypes.length > 0) {
            var uniqueKnownReturnTypes = getUniqueTypes(
                funcScope.knownReturnTypes
            );

            // TODO: grab the smallest union?
            assert(uniqueKnownReturnTypes.length === 1,
                'only support trivial single return funcs');
            foundReturnType = uniqueKnownReturnTypes[0];
        }

        this.meta.tryRevertFunction(
            funcName, this.inferFunctionType, untypedFunc
        );

        // TODO: update func type with the new thisType information
        // TODO: walk the function type and replace the inferred literals
        //      with actual generic literals
        // TODO: rebuild the function type object with generic literals and
        //      its location index tracking.

        // This is the function type that we inferred from trying to force
        // update the function.
        var newFuncType = JsigAST.functionType({
            result: foundReturnType === null ?
                JsigAST.literal('void') : foundReturnType,
            args: inferredFuncType.args,
            thisArg: JsigAST.param('this', funcScope.getThisType())
        });

        var replacer = new InferredLiteralReplacer();
        var astReplacer = new JsigASTReplacer(replacer, true);
        astReplacer.inlineReferences(newFuncType, newFuncType, []);

        var openThisArg = newFuncType.thisArg.value;
        var closedThisArg = JsigAST.param('this', JsigAST.object(
            openThisArg.keyValues,
            null,
            {
                open: false,
                brand: openThisArg.brand,
                inferred: openThisArg.inferred
            }
        ));

        var finalFuncType = JsigAST.functionType({
            result: newFuncType.result,
            args: newFuncType.args,
            thisArg: closedThisArg,
            generics: replacer.generics,
            inferred: true
        });

        // console.log('static type inference', {
        //     generics: finalFuncType.generics,
        //     funcType: this.meta.serializeType(finalFuncType)
        // });

        return finalFuncType;
    }
};

function InferredLiteralReplacer() {
    this.genericLiteralsTable = Object.create(null);
    this.generics = [];
    this.counter = 0;
}

InferredLiteralReplacer.prototype.replace = function replace(ast, raw, stack) {
    if (ast.type === 'inferredLiteral') {
        return this.replaceInferredLiteral(ast, stack);
    }
};

InferredLiteralReplacer.prototype.replaceInferredLiteral =
function replaceInferredLiteral(ast, stack) {
    if (this.genericLiteralsTable[ast.name]) {
        return this.genericLiteralsTable[ast.name];
    }

    var literal = JsigAST.literal('T' + this.counter++, false);
    this.generics.push(literal.name);
    this.genericLiteralsTable[ast.name] = literal;
    return literal;
};
<|endoftext|>


<commit_before>'use strict';

var Crawler = require('../crawler'),
    bitly = require('easy-bitly'),
    async = require('async'),
    bitlyAccessToken = '<bitly access token>';

// To tweet title + shortened link of article on engineering.laterooms.com
var retrieveLits = function (window, callback){
  var document = window.document;
  var $ = window.$;

  $(document).ready(function(){
    var funcs = [];

    var toTweet =
      $('h1 > a').map(function(index, elem){
        var link = elem.href;
        var content = elem.textContent.trim();
        return { link: link , content: content };
      });

    toTweet.each(function(index, item){
      funcs.push(function(asyncCallback){
        bitly.shorten(item.link, bitlyAccessToken, function(error, result){
          var shortUrl = result.data.url.replace('http://', '');
          var toTweet = { identifier: item.link, content: item.content + ' ' + shortUrl };

          asyncCallback(null, toTweet);
        })
      })
    });

    async.parallel(
      funcs,
      function(err, results){
        callback(results);
      }
    );
  });
};

var options = {
  mongoDB: {
    url:                 '<mongodb connection url>',
    collection:          '<mongodb collection>'
  },
  twitter: {
    api_key:             '<twitter api key>',
    api_secret:          '<twitter api secret>',
    access_token:        '<twitter access token>',
    access_token_secret: '<twitter access seret>'
  },
  pages: [{
    url:                  'http://engineering.laterooms.com',
    query:                retrieveLits
  }]
};

var crawler = new Crawler(options);
var run = function() {
  crawler.run().catch(function(error) {
    if (error) {
      console.error('boom!', error);
    }
  });
};

// crawl every 1 hour
var interval = 1000 * 60 * 60;
setInterval(run, interval);
<commit_msg>Updated the example to use env variables<commit_after>'use strict';

var Crawler = require('../crawler'),
    bitly = require('easy-bitly'),
    async = require('async'),
    bitlyAccessToken = process.env.bitly.token || '<bitly access token>';

// To tweet title + shortened link of article on engineering.laterooms.com
var retrieveLits = function (window, callback){
  var document = window.document;
  var $ = window.$;

  $(document).ready(function(){
    var funcs = [];

    var toTweet =
      $('h1 > a').map(function(index, elem){
        var link = elem.href;
        var content = elem.textContent.trim();
        return { link: link , content: content };
      });

    toTweet.each(function(index, item){
      funcs.push(function(asyncCallback){
        bitly.shorten(item.link, bitlyAccessToken, function(error, result){
          var shortUrl = result.data.url.replace('http://', '');
          var toTweet = { identifier: item.link, content: item.content + ' ' + shortUrl };

          asyncCallback(null, toTweet);
        })
      })
    });

    async.parallel(
      funcs,
      function(err, results){
        callback(results);
      }
    );
  });
};

var options = {
  mongoDB: {
    url:                 process.env.mongoUrl || '<mongodb connection url>',
    collection:          process.env.collection || '<mongodb collection>'
  },
  twitter: {
    api_key:             process.env.twitter.api || '<twitter api key>',
    api_secret:          process.env.twitter.apiSecret || '<twitter api secret>',
    access_token:        process.env.twitter.token || '<twitter access token>',
    access_token_secret: process.env.twitter.tokenSecret || '<twitter access seret>'
  },
  pages: [{
    url:                  'http://engineering.laterooms.com',
    query:                retrieveLits
  }]
};

var crawler = new Crawler(options);
var run = function() {
  crawler.run().catch(function(error) {
    if (error) {
      console.error('boom!', error);
    }
  });
};

// crawl every 1 hour
var interval = 1000 * 60 * 60;
setInterval(run, interval);
<|endoftext|>


<commit_before><commit_msg>Optional auth account matchers<commit_after><|endoftext|>