<commit_before>var schedule = [
{
  date: "12/1",
  author: "ymyzk",
  author_url: "http://www.ymyzk.com",
  entry_title: "CAMPHOR- アドベントカレンダー 2014 を始めます!",
  entry_url: "http://blog.camph.net/news/advent-calendar-2014/"
},
{
  date: "12/2",
  author: "ohmuraken",
  author_url: "https://github.com/ohmuraken",
  entry_title: "彼女のつくりかた (京大11月祭にて)",
  entry_url: "http://blog.camph.net/news/howtomakemygirlfriend2/"
},
{
  date: "12/3",
  author: "morishin",
  author_url: "https://twitter.com/morishin127",
  entry_title: "CAMPHOR-のYo活用",
  entry_url: "http://blog.camph.net/news/useful-yo/"
},
{
  date: "12/4",
  author: "kohey18",
  author_url: "https://github.com/kohey18",
  entry_title: "「hubot start tv」で家のテレビの電源を付ける。",
  entry_url: "http://tech.camph.net/hubot_start_tv/"
},
{
  date: "12/5",
  author: "Shtr28",
  author_url: "https://twitter.com/Shtr28",
  entry_title: "Python 3でお手軽並列計算 ~concurrent.futures を使った ngram 抽出~",
  entry_url: "http://tech.camph.net/python3-concurrent-futures/"
},
{
  date: "12/6",
  author: "yaitaimo",
  author_url: "https://github.com/yaitaimo",
  entry_title: "CAMPHOR-HOUSEの庭を美白した話",
  entry_url: "http://blog.camph.net/news/camphor-house-garden/"
},
{
  date: "12/7",
  author: "tomonkey1",
  author_url: "https://github.com/tomonkey1",
  entry_title: "宅建挑戦記",
  entry_url: "http://blog.camph.net/event/takken/"
},
{
  date: "12/8",
  author: "asadaman",
  author_url: "#",
  entry_title: "ロボットに負けたくない",
  entry_url: "#"
},
{
  date: "12/9",
  author: "akaaariiiiin",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
},
{
  date: "12/10",
  author: "To-Mikasa",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
},
{
  date: "12/11",
  author: "ryota-ka",
  author_url: "http://ryota-ka.me/",
  entry_title: "iOS 初心者が Swift を使ってN日でゲームを作った話",
  entry_url: "#"
},
{
  date: "12/12",
  author: "siriusjack",
  author_url: "#",
  entry_title: "食べられるドングリの見分け方(ドイツ編)",
  entry_url: "#"
},
{
  date: "12/13",
  author: "ivstivs",
  author_url: "https://github.com/ivstivs",
  entry_title: "ProjectileとHelm",
  entry_url: "#"
},
{
  date: "12/14",
  author: "kakenn",
  author_url: "http://shuto.info",
  entry_title: "格安3Dプリンター「daVinci 2.0」を買ってみた。",
  entry_url: "#"
},
{
  date: "12/15",
  author: "ymyzk",
  author_url: "http://www.ymyzk.com",
  entry_title: "sphinxcontrib.httpdomain で RESTful API のドキュメント作成",
  entry_url: "#"
},
{
  date: "12/16",
  author: "cotton_ori",
  author_url: "https://twitter.com/cotton_ori",
  entry_title: "準備中",
  entry_url: "#"
},
{
  date: "12/17",
  author: "pepoipod",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
},
{
  date: "12/18",
  author: "ohmuraken",
  author_url: "#",
  entry_title: "ソーシャルボタンで文字を作る！",
  entry_url: "#"
},
{
  date: "12/19",
  author: "準備中",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
},
{
  date: "12/20",
  author: "準備中",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
},
{
  date: "12/21",
  author: "準備中",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
}
,
{
  date: "12/22",
  author: "準備中",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
}
,
{
  date: "12/23",
  author: "準備中",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
}
,
{
  date: "12/24",
  author: "準備中",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
}
,
{
  date: "12/25",
  author: "準備中",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
}
];
<commit_msg>Update 2014/12/21<commit_after>var schedule = [
{
  date: "12/1",
  author: "ymyzk",
  author_url: "http://www.ymyzk.com",
  entry_title: "CAMPHOR- アドベントカレンダー 2014 を始めます!",
  entry_url: "http://blog.camph.net/news/advent-calendar-2014/"
},
{
  date: "12/2",
  author: "ohmuraken",
  author_url: "https://github.com/ohmuraken",
  entry_title: "彼女のつくりかた (京大11月祭にて)",
  entry_url: "http://blog.camph.net/news/howtomakemygirlfriend2/"
},
{
  date: "12/3",
  author: "morishin",
  author_url: "https://twitter.com/morishin127",
  entry_title: "CAMPHOR-のYo活用",
  entry_url: "http://blog.camph.net/news/useful-yo/"
},
{
  date: "12/4",
  author: "kohey18",
  author_url: "https://github.com/kohey18",
  entry_title: "「hubot start tv」で家のテレビの電源を付ける。",
  entry_url: "http://tech.camph.net/hubot_start_tv/"
},
{
  date: "12/5",
  author: "Shtr28",
  author_url: "https://twitter.com/Shtr28",
  entry_title: "Python 3でお手軽並列計算 ~concurrent.futures を使った ngram 抽出~",
  entry_url: "http://tech.camph.net/python3-concurrent-futures/"
},
{
  date: "12/6",
  author: "yaitaimo",
  author_url: "https://github.com/yaitaimo",
  entry_title: "CAMPHOR-HOUSEの庭を美白した話",
  entry_url: "http://blog.camph.net/news/camphor-house-garden/"
},
{
  date: "12/7",
  author: "tomonkey1",
  author_url: "https://github.com/tomonkey1",
  entry_title: "宅建挑戦記",
  entry_url: "http://blog.camph.net/event/takken/"
},
{
  date: "12/8",
  author: "asadaman",
  author_url: "#",
  entry_title: "ロボットに負けたくない",
  entry_url: "#"
},
{
  date: "12/9",
  author: "akaaariiiiin",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
},
{
  date: "12/10",
  author: "To-Mikasa",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
},
{
  date: "12/11",
  author: "ryota-ka",
  author_url: "http://ryota-ka.me/",
  entry_title: "iOS 初心者が Swift を使ってN日でゲームを作った話",
  entry_url: "#"
},
{
  date: "12/12",
  author: "siriusjack",
  author_url: "#",
  entry_title: "食べられるドングリの見分け方(ドイツ編)",
  entry_url: "#"
},
{
  date: "12/13",
  author: "ivstivs",
  author_url: "https://github.com/ivstivs",
  entry_title: "ProjectileとHelm",
  entry_url: "#"
},
{
  date: "12/14",
  author: "kakenn",
  author_url: "http://shuto.info",
  entry_title: "格安3Dプリンター「daVinci 2.0」を買ってみた。",
  entry_url: "#"
},
{
  date: "12/15",
  author: "ymyzk",
  author_url: "http://www.ymyzk.com",
  entry_title: "sphinxcontrib.httpdomain で RESTful API のドキュメント作成",
  entry_url: "#"
},
{
  date: "12/16",
  author: "cotton_ori",
  author_url: "https://twitter.com/cotton_ori",
  entry_title: "準備中",
  entry_url: "#"
},
{
  date: "12/17",
  author: "pepoipod",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
},
{
  date: "12/18",
  author: "ohmuraken",
  author_url: "#",
  entry_title: "ソーシャルボタンで文字を作る！",
  entry_url: "#"
},
{
  date: "12/19",
  author: "準備中",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
},
{
  date: "12/20",
  author: "準備中",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
},
{
  date: "12/21",
  author: "morishin",
  author_url: "https://twitter.com/morishin127",
  entry_title: "準備中",
  entry_url: "#"
}
,
{
  date: "12/22",
  author: "準備中",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
}
,
{
  date: "12/23",
  author: "準備中",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
}
,
{
  date: "12/24",
  author: "準備中",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
}
,
{
  date: "12/25",
  author: "準備中",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
}
];
<|endoftext|>


<commit_before>var ItemsA = new Meteor.Collection('ItemsA');
var ItemsB = new Meteor.Collection('ItemsB');
var ItemsC = new Meteor.Collection('ItemsC');

var itemCValue = {
  _id: 'the only one',
  number0: 0,
  number1: 123,
  string0: '',
  string1: 'hello',
  bool0: false,
  bool1: true,
  arr0: [],
  arr1: [1, 2, 'hi', {obj: false}, null, {'': null}],
  arr2: [null],
  null: null,
  '': null
};

if (Meteor.isServer) {
  Meteor.methods({
    initDb: function() {
      ItemsA.remove({});
      ItemsB.remove({});
      ItemsC.remove({});
      for (var i = 1; i <= 11; i++) {
        ItemsA.insert({val: i, a: 1, b: 1, x: {a: 1, b: 1}});
        ItemsB.insert({val: i, a: 1, b: 1, x: {a: 1, b: 1}});
      }
      ItemsC.insert(itemCValue);
    }
  });

  Meteor.smartPublish('items', function(l, r) {
    return [
      ItemsA.find({val: {$lt: l}}, {fields: {val: 1, a: 1, 'x.a': 1}}),
      ItemsA.find({val: {$gt: r}}, {fields: {val: 1, b: 1, 'x.b': 1}}),
      ItemsB.find({val: {$lt: r}}, {fields: {val: 1, a: 1, 'x.a': 1}}),
      ItemsB.find({val: {$gt: l}}, {fields: {val: 1, b: 1, 'x.b': 1}}),
      ItemsC.find(),
      ItemsC.find(),
      ItemsC.find(),
    ];
  });
  Meteor.methods({
    updateA6To0: function() {
      ItemsA.update({val: 6}, {$set: {val: 0}});
    }
  });
}

if (Meteor.isClient) {
  Tinytest.addAsync('init', function(test, next) {
    Meteor.call('initDb', function(err) {
      test.isUndefined(err, 'error during initialization: ' + err);
      test.equal(ItemsA.find().count(), 0, 'ItemsA is not empty');
      test.equal(ItemsB.find().count(), 0, 'ItemsB is not empty');
      test.equal(ItemsC.find().count(), 0, 'Items is not empty');
      next();
    });
  });

  function getVals(coll, filter) {
    return _.pluck(coll.find(filter || {}, {fields: {val: 1}}).fetch(), 'val')
  }

  var subscr;
  Tinytest.addAsync('subscription start', function(test, next) {
    subscr = Meteor.subscribe('items', 4, 9, function() {
      test.equal(getVals(ItemsA), [1,2,3,10,11], 'ItemsA is invalid');
      test.equal(getVals(ItemsB), [1,2,3,4,5,6,7,8,9,10,11], 'ItemsB is invalid');

      test.equal(getVals(ItemsA,    {a : 1}), [1,2,3], 'ItemsA.a is invalid');
      test.equal(getVals(ItemsA, {'x.a': 1}), [1,2,3], 'ItemsA.x.a is invalid');
      test.equal(getVals(ItemsA,    {b : 1}), [10,11], 'ItemsA.b is invalid');
      test.equal(getVals(ItemsA, {'x.b': 1}), [10,11], 'ItemsA.x.b is invalid');
      test.equal(getVals(ItemsB,    {a : 1}), [1,2,3,4,5,6,7,8], 'ItemsB.a is invalid');
      test.equal(getVals(ItemsB, {'x.a': 1}), [1,2,3,4,5,6,7,8], 'ItemsB.x.a is invalid');
      test.equal(getVals(ItemsB,    {b : 1}), [5,6,7,8,9,10,11], 'ItemsB.b is invalid');
      test.equal(getVals(ItemsB, {'x.b': 1}), [5,6,7,8,9,10,11], 'ItemsB.x.b is invalid');
      next();
    });
  });

  Tinytest.addAsync('several publications of the same field', function(test, next) {
    test.equal(ItemsC.find().fetch(), [itemCValue], 'ItemsC is incorrect');
    next();
  });

  Tinytest.addAsync('update with element remove', function(test, next) {
    ItemsA.update(ItemsA.findOne({val: 2})._id, {$set: {val: 4}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(getVals(ItemsA), [1,3,10,11], 'ItemsA');
      next();
    });
  });

  Tinytest.addAsync('update with element add', function(test, next) {
    Meteor.call('updateA6To0', function(err, res) {
      test.isUndefined(err, 'error during method call: ' + err);
      test.equal(getVals(ItemsA), [1,3,10,11,0], 'ItemsA');
      next();
    });
  });

  Tinytest.addAsync('update with field add', function(test, next) {
    var id = ItemsB.findOne({val: 2})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 2, a: 1, x: {a: 1}}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 5}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 5, a: 1, b: 1, x: {a: 1, b: 1}}, 'resulting fieldset');
      next();
    });
  });

  Tinytest.addAsync('update with field remove', function(test, next) {
    var id = ItemsB.findOne({val: 5})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 5, a: 1, b: 1, x: {a: 1, b: 1}}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 0}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 0, a: 1, x: {a: 1}}, 'resulting fieldset');
      next();
    });
  });

  Tinytest.addAsync('update with field remove&add', function(test, next) {
    var id = ItemsB.findOne({val: 3})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 3, a: 1, x: {a: 1}}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 12}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 12, b: 1, x: {b: 1}}, 'resulting fieldset');
      next();
    });
  });

  Tinytest.addAsync('update with field add&remove', function(test, next) {
    var id = ItemsB.findOne({val: 10})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 10, b: 1, x: {b: 1}}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 3}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 3, a: 1, x: {a: 1}}, 'resulting fieldset');
      next();
    });
  });
  Tinytest.addAsync('two-stage update with field add&remove (2->1)', function(test, next) {
    var id = ItemsB.findOne({val: 11})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 11, b: 1, x: {b: 1}}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 5.5}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 5.5, a: 1, b: 1, x: {a: 1, b: 1}}, 'intermediate fieldset');

      ItemsB.update(id, {$set: {val: -1}}, function(err, res) {
        test.isUndefined(err, 'error during update: ' + err);
        test.equal(ItemsB.findOne(id), {_id: id, val: -1, a: 1, x: {a: 1}}, 'resulting fieldset');
        next();
      });
    });
  });
  Tinytest.addAsync('two-stage update with field add&remove (1->2)', function(test, next) {
    var id = ItemsB.findOne({val: 1})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 1, a: 1, x: {a: 1}}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 5.5}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 5.5, a: 1, b: 1, x: {a: 1, b: 1}}, 'intermediate fieldset');

      ItemsB.update(id, {$set: {val: 13}}, function(err, res) {
        test.isUndefined(err, 'error during update: ' + err);
        test.equal(ItemsB.findOne(id), {_id: id, val: 13, b: 1, x: {b: 1}}, 'resulting fieldset');
        next();
      });
    });
  });
  Tinytest.addAsync('field unset', function(test, next) {
    var id = ItemsB.findOne({val: 13})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 13, b: 1, x: {b: 1}}, 'initial fieldset');
    ItemsB.update(id, {$unset: {'x.a': 1, b: 1}, $set: {val: 5.5}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 5.5, a: 1, x: {b: 1}}, 'resulting fieldset');
      next();
    });
  });

  Tinytest.addAsync('subscription stop', function(test, next) {
    subscr.stop();
    Meteor.setTimeout(function() {
      test.equal(ItemsA.find().count(), 0, 'ItemsA is not empty');
      test.equal(ItemsB.find().count(), 0, 'ItemsB is not empty');
      next();
    }, 100);
  });
}
<commit_msg>tests/several-cursors.js: added Date, ObjectId and EJSON.binary fields to test<commit_after>var ItemsA = new Meteor.Collection('ItemsA');
var ItemsB = new Meteor.Collection('ItemsB');
var ItemsC = new Meteor.Collection('ItemsC');

var tempBinary = EJSON.newBinary(3);
tempBinary[0] = 1;
tempBinary[1] = 3;
tempBinary[2] = 2;
var itemCValue = {
  _id: new Meteor.Collection.ObjectID('01234567890123456789abcd'),
  number0: 0,
  number1: 123,
  string0: '',
  string1: 'hello',
  bool0: false,
  bool1: true,
  arr0: [],
  arr1: [1, 2, 'hi', {obj: false}, null, {'': null}],
  arr2: [null],
  null: null,
  '': null,
  someDate: new Date('2014-02-23T01:23:45Z'),
  binary: tempBinary,
};

if (Meteor.isServer) {
  Meteor.methods({
    initDb: function() {
      ItemsA.remove({});
      ItemsB.remove({});
      ItemsC.remove({});
      for (var i = 1; i <= 11; i++) {
        ItemsA.insert({val: i, a: 1, b: 1, x: {a: 1, b: 1}});
        ItemsB.insert({val: i, a: 1, b: 1, x: {a: 1, b: 1}});
      }
      ItemsC.insert(itemCValue);
    }
  });

  Meteor.smartPublish('items', function(l, r) {
    return [
      ItemsA.find({val: {$lt: l}}, {fields: {val: 1, a: 1, 'x.a': 1}}),
      ItemsA.find({val: {$gt: r}}, {fields: {val: 1, b: 1, 'x.b': 1}}),
      ItemsB.find({val: {$lt: r}}, {fields: {val: 1, a: 1, 'x.a': 1}}),
      ItemsB.find({val: {$gt: l}}, {fields: {val: 1, b: 1, 'x.b': 1}}),
      ItemsC.find(),
      ItemsC.find(),
      ItemsC.find(),
    ];
  });
  Meteor.methods({
    updateA6To0: function() {
      ItemsA.update({val: 6}, {$set: {val: 0}});
    }
  });
}

if (Meteor.isClient) {
  Tinytest.addAsync('init', function(test, next) {
    Meteor.call('initDb', function(err) {
      test.isUndefined(err, 'error during initialization: ' + err);
      test.equal(ItemsA.find().count(), 0, 'ItemsA is not empty');
      test.equal(ItemsB.find().count(), 0, 'ItemsB is not empty');
      test.equal(ItemsC.find().count(), 0, 'Items is not empty');
      next();
    });
  });

  function getVals(coll, filter) {
    return _.pluck(coll.find(filter || {}, {fields: {val: 1}}).fetch(), 'val')
  }

  var subscr;
  Tinytest.addAsync('subscription start', function(test, next) {
    subscr = Meteor.subscribe('items', 4, 9, function() {
      test.equal(getVals(ItemsA), [1,2,3,10,11], 'ItemsA is invalid');
      test.equal(getVals(ItemsB), [1,2,3,4,5,6,7,8,9,10,11], 'ItemsB is invalid');

      test.equal(getVals(ItemsA,    {a : 1}), [1,2,3], 'ItemsA.a is invalid');
      test.equal(getVals(ItemsA, {'x.a': 1}), [1,2,3], 'ItemsA.x.a is invalid');
      test.equal(getVals(ItemsA,    {b : 1}), [10,11], 'ItemsA.b is invalid');
      test.equal(getVals(ItemsA, {'x.b': 1}), [10,11], 'ItemsA.x.b is invalid');
      test.equal(getVals(ItemsB,    {a : 1}), [1,2,3,4,5,6,7,8], 'ItemsB.a is invalid');
      test.equal(getVals(ItemsB, {'x.a': 1}), [1,2,3,4,5,6,7,8], 'ItemsB.x.a is invalid');
      test.equal(getVals(ItemsB,    {b : 1}), [5,6,7,8,9,10,11], 'ItemsB.b is invalid');
      test.equal(getVals(ItemsB, {'x.b': 1}), [5,6,7,8,9,10,11], 'ItemsB.x.b is invalid');
      next();
    });
  });

  Tinytest.addAsync('several publications of the same field', function(test, next) {
    test.equal(ItemsC.find().fetch(), [itemCValue], 'ItemsC is incorrect');
    next();
  });

  Tinytest.addAsync('update with element remove', function(test, next) {
    ItemsA.update(ItemsA.findOne({val: 2})._id, {$set: {val: 4}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(getVals(ItemsA), [1,3,10,11], 'ItemsA');
      next();
    });
  });

  Tinytest.addAsync('update with element add', function(test, next) {
    Meteor.call('updateA6To0', function(err, res) {
      test.isUndefined(err, 'error during method call: ' + err);
      test.equal(getVals(ItemsA), [1,3,10,11,0], 'ItemsA');
      next();
    });
  });

  Tinytest.addAsync('update with field add', function(test, next) {
    var id = ItemsB.findOne({val: 2})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 2, a: 1, x: {a: 1}}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 5}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 5, a: 1, b: 1, x: {a: 1, b: 1}}, 'resulting fieldset');
      next();
    });
  });

  Tinytest.addAsync('update with field remove', function(test, next) {
    var id = ItemsB.findOne({val: 5})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 5, a: 1, b: 1, x: {a: 1, b: 1}}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 0}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 0, a: 1, x: {a: 1}}, 'resulting fieldset');
      next();
    });
  });

  Tinytest.addAsync('update with field remove&add', function(test, next) {
    var id = ItemsB.findOne({val: 3})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 3, a: 1, x: {a: 1}}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 12}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 12, b: 1, x: {b: 1}}, 'resulting fieldset');
      next();
    });
  });

  Tinytest.addAsync('update with field add&remove', function(test, next) {
    var id = ItemsB.findOne({val: 10})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 10, b: 1, x: {b: 1}}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 3}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 3, a: 1, x: {a: 1}}, 'resulting fieldset');
      next();
    });
  });
  Tinytest.addAsync('two-stage update with field add&remove (2->1)', function(test, next) {
    var id = ItemsB.findOne({val: 11})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 11, b: 1, x: {b: 1}}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 5.5}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 5.5, a: 1, b: 1, x: {a: 1, b: 1}}, 'intermediate fieldset');

      ItemsB.update(id, {$set: {val: -1}}, function(err, res) {
        test.isUndefined(err, 'error during update: ' + err);
        test.equal(ItemsB.findOne(id), {_id: id, val: -1, a: 1, x: {a: 1}}, 'resulting fieldset');
        next();
      });
    });
  });
  Tinytest.addAsync('two-stage update with field add&remove (1->2)', function(test, next) {
    var id = ItemsB.findOne({val: 1})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 1, a: 1, x: {a: 1}}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 5.5}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 5.5, a: 1, b: 1, x: {a: 1, b: 1}}, 'intermediate fieldset');

      ItemsB.update(id, {$set: {val: 13}}, function(err, res) {
        test.isUndefined(err, 'error during update: ' + err);
        test.equal(ItemsB.findOne(id), {_id: id, val: 13, b: 1, x: {b: 1}}, 'resulting fieldset');
        next();
      });
    });
  });
  Tinytest.addAsync('field unset', function(test, next) {
    var id = ItemsB.findOne({val: 13})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 13, b: 1, x: {b: 1}}, 'initial fieldset');
    ItemsB.update(id, {$unset: {'x.a': 1, b: 1}, $set: {val: 5.5}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 5.5, a: 1, x: {b: 1}}, 'resulting fieldset');
      next();
    });
  });

  Tinytest.addAsync('subscription stop', function(test, next) {
    subscr.stop();
    Meteor.setTimeout(function() {
      test.equal(ItemsA.find().count(), 0, 'ItemsA is not empty');
      test.equal(ItemsB.find().count(), 0, 'ItemsB is not empty');
      next();
    }, 100);
  });
}
<|endoftext|>


<commit_before>ItemsA = new Meteor.Collection('ItemsA');
ItemsB = new Meteor.Collection('ItemsB');

if (Meteor.isServer) {
  ItemsA.remove({});
  ItemsB.remove({});
  for (var i = 1; i <= 10; i++) {
    ItemsA.insert({val: i});
    ItemsB.insert({val: i});
  }

  Meteor.smartPublish('items', function(l, r) {
    return [
      ItemsA.find({val: {$lt: l}}),
      ItemsA.find({val: {$gt: r}}),
      ItemsB.find({val: {$lt: r}}),
      ItemsB.find({val: {$gt: l}}),
    ];
  });
  Meteor.methods({
    updateA6To0: function() {
      ItemsA.update({val: 6}, {$set: {val: 0}});
    }
  });
}

if (Meteor.isClient) {
  Tinytest.addAsync('init', function(test, next) {
    test.equal(ItemsA.find().count(), 0, 'ItemsA is not empty');
    test.equal(ItemsB.find().count(), 0, 'ItemsB is not empty');
    next();
  });

  function getVals(coll) {
    return _.pluck(coll.find({}, {fields: {val: 1}}).fetch(), 'val')
  }

  var subscr;
  Tinytest.addAsync('subscription start', function(test, next) {
    subscr = Meteor.subscribe('items', 4, 9, function() {
      test.equal(getVals(ItemsA), [1,2,3,10], 'ItemsA is invalid');
      test.equal(getVals(ItemsB), [1,2,3,4,5,6,7,8,9,10], 'ItemsB is invalid');
      next();
    });
  });

  Tinytest.addAsync('update with element remove', function(test, next) {
    ItemsA.update(ItemsA.findOne({val: 2})._id, {$set: {val: 4}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(getVals(ItemsA), [1,3,10], 'ItemsA');
      next();
    });
  });

  Tinytest.addAsync('update with element add', function(test, next) {
    Meteor.call('updateA6To0', function(err, res) {
      test.isUndefined(err, 'error during method call: ' + err);
      test.equal(getVals(ItemsA), [1,3,10,0], 'ItemsA');
      next();
    });
  });

  Tinytest.addAsync('subscription stop', function(test, next) {
    subscr.stop();
    Meteor.setTimeout(function() {
      test.equal(ItemsA.find().count(), 0, 'ItemsA is not empty');
      test.equal(ItemsB.find().count(), 0, 'ItemsB is not empty');
      next();
    }, 100);
  });
}
<commit_msg>Added more tests with top-level fields filtering<commit_after>ItemsA = new Meteor.Collection('ItemsA');
ItemsB = new Meteor.Collection('ItemsB');

if (Meteor.isServer) {
  ItemsA.remove({});
  ItemsB.remove({});
  for (var i = 1; i <= 10; i++) {
    ItemsA.insert({val: i, a: 1, b: 1});
    ItemsB.insert({val: i, a: 1, b: 1});
  }

  Meteor.smartPublish('items', function(l, r) {
    return [
      ItemsA.find({val: {$lt: l}}, {fields: {val: 1, a: 1}}),
      ItemsA.find({val: {$gt: r}}, {fields: {val: 1, b: 1}}),
      ItemsB.find({val: {$lt: r}}, {fields: {val: 1, a: 1}}),
      ItemsB.find({val: {$gt: l}}, {fields: {val: 1, b: 1}}),
    ];
  });
  Meteor.methods({
    updateA6To0: function() {
      ItemsA.update({val: 6}, {$set: {val: 0}});
    }
  });
}

if (Meteor.isClient) {
  Tinytest.addAsync('init', function(test, next) {
    test.equal(ItemsA.find().count(), 0, 'ItemsA is not empty');
    test.equal(ItemsB.find().count(), 0, 'ItemsB is not empty');
    next();
  });

  function getVals(coll, filter) {
    return _.pluck(coll.find(filter || {}, {fields: {val: 1}}).fetch(), 'val')
  }

  var subscr;
  Tinytest.addAsync('subscription start', function(test, next) {
    subscr = Meteor.subscribe('items', 4, 9, function() {
      test.equal(getVals(ItemsA), [1,2,3,10], 'ItemsA is invalid');
      test.equal(getVals(ItemsB), [1,2,3,4,5,6,7,8,9,10], 'ItemsB is invalid');

      test.equal(getVals(ItemsA, {a: 1}), [1,2,3], 'ItemsA.a is invalid');
      test.equal(getVals(ItemsA, {b: 1}), [10], 'ItemsA.b is invalid');
      test.equal(getVals(ItemsB, {a: 1}), [1,2,3,4,5,6,7,8], 'ItemsB.a is invalid');
      test.equal(getVals(ItemsB, {b: 1}), [5,6,7,8,9,10], 'ItemsB.b is invalid');
      next();
    });
  });

  Tinytest.addAsync('update with element remove', function(test, next) {
    ItemsA.update(ItemsA.findOne({val: 2})._id, {$set: {val: 4}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(getVals(ItemsA), [1,3,10], 'ItemsA');
      next();
    });
  });

  Tinytest.addAsync('update with element add', function(test, next) {
    Meteor.call('updateA6To0', function(err, res) {
      test.isUndefined(err, 'error during method call: ' + err);
      test.equal(getVals(ItemsA), [1,3,10,0], 'ItemsA');
      next();
    });
  });

  Tinytest.addAsync('update with field add', function(test, next) {
    var id = ItemsB.findOne({val: 2})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 2, a: 1}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 5}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 5, a: 1, b: 1}, 'resulting fieldset');
      next();
    });
  });

  Tinytest.addAsync('update with field remove', function(test, next) {
    var id = ItemsB.findOne({val: 5})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 5, a: 1, b: 1}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 0}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 0, a: 1}, 'resulting fieldset');
      next();
    });
  });

  Tinytest.addAsync('update with field remove&add', function(test, next) {
    var id = ItemsB.findOne({val: 3})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 3, a: 1}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 12}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 12, b: 1}, 'resulting fieldset');
      next();
    });
  });
  Tinytest.addAsync('update with field add&remove', function(test, next) {
    var id = ItemsB.findOne({val: 10})._id;
    test.equal(ItemsB.findOne(id), {_id: id, val: 10, b: 1}, 'initial fieldset');
    ItemsB.update(id, {$set: {val: 3}}, function(err, res) {
      test.isUndefined(err, 'error during update: ' + err);
      test.equal(ItemsB.findOne(id), {_id: id, val: 3, a: 1}, 'resulting fieldset');
      next();
    });
  });

  Tinytest.addAsync('subscription stop', function(test, next) {
    subscr.stop();
    Meteor.setTimeout(function() {
      test.equal(ItemsA.find().count(), 0, 'ItemsA is not empty');
      test.equal(ItemsB.find().count(), 0, 'ItemsB is not empty');
      next();
    }, 100);
  });
}
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Decentralized Block Script
// @namespace    http://www.cgranade.com/
// @version      1
// @description  Performs blocking on social media sites based on user-selected
//               blocklists.
// @require      http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @match        http://twitter.com/*
// @match        https://twitter.com/*
// @copyright    2013, Christopher E. Granade. Licensed under the AGPLv3 (see
//               source code).
// ==/UserScript==

/**
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// FUNCTIONS ///////////////////////////////////////////////////////////////////

function loadBlockList(urls) {
    blockList = [];
    urls.forEach(function(url) {
        GM_xmlhttpRequest({
            method: "GET",
            url: url,
            onload: function(response) {
                blockees = $.parseJSON(response.response).twitter;
                blockees.forEach(function (blockee) {
                    blockList = blockList.concat([blockee["screen-name"]]);
                });
    			applyBlockList();
            }
        });
    });
}

function applyBlockList() {
    style.text("");
    blockList.forEach(function(blockee) {
        txt = style.text();
        style.text(txt + "*[data-screen-name=" + blockee + "] {display: none;}\n");
    });
}

// GLOBAL VARIABLES ////////////////////////////////////////////////////////////

// Make a list of sources to load blocklists from. We will initialize this
// when the DOM is ready, to avoid slowdown.
blockListSources = [];

// Note that this decision has ethical consequences! The block list is not
// applied until well after the body is loaded, so harassing content may be seen
// briefly. If this is unacceptable, we should modify this behavior to load
// immediately, even at the cost of introducing slowdown and instabilty.

// Make a list of whom to block so far.
blockList = [];

// Make a style container to hold the block styles.
// TODO: make one per block source, so we can refresh independently.
style = $('');

// MAIN ////////////////////////////////////////////////////////////////////////

$('body').ready(function() {

    // Grab the block sources from the configuration store.
    if (localStorage["blockListSources"] == undefined) {
        // Since we don't have a configuration GUI at the moment,
        // we need a default. This WILL be removed once a GUI is in place,
        // as no one gets to be specially privileged by this script.
        // Right now, this blocklist only blocks the author of this script,
        // to demonstrate the concept.
        blockListSources = ['https://raw.github.com/cgranade/decentralized-blockscript/master/blocklist-example.json'];
    } else {
        blockListSources = localStorage["blockListSources"];
    }

    $('head').append(style);
    loadBlockList(blockListSources);

});
<commit_msg>Added do-nothing GUI.<commit_after>// ==UserScript==
// @name         Decentralized Block Script
// @namespace    http://www.cgranade.com/
// @version      1
// @description  Performs blocking on social media sites based on user-selected
//               blocklists.
// @require      http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @require      http:////netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js
// @match        http://twitter.com/*
// @match        https://twitter.com/*
// @copyright    2013, Christopher E. Granade. Licensed under the AGPLv3 (see
//               source code).
// ==/UserScript==

/**
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// FUNCTIONS ///////////////////////////////////////////////////////////////////

function loadBlockList(urls) {
    blockList = [];
    urls.forEach(function(url) {
        GM_xmlhttpRequest({
            method: "GET",
            url: url,
            onload: function(response) {
                blockees = $.parseJSON(response.response).twitter;
                blockees.forEach(function (blockee) {
                    blockList = blockList.concat([blockee["screen-name"]]);
                });
    			applyBlockList();
            }
        });
    });
}

function applyBlockList() {
    style.text("");
    blockList.forEach(function(blockee) {
        txt = style.text();
        style.text(txt + "*[data-screen-name=" + blockee + "] {display: none;}\n");
    });
}

function createSettingsGUI() {
    // Make an item in the settings dropdown.
    blockListSettingsItem = $('
Blocklist Settings
');
    dashboardItem = $('

');
    dashboardItem.html(
        '
' +
            '
' +
                '
Block Script Settings
' +
            '
' +
            '
' +
            '
' +
            '
' +
                '
' +
                    '<button type="button" class="btn primary-btn">Save</button>' +
                    '<button type="button" class="btn">Cancel</button>' +
                '
' +
            '
' +
        '
');
    dashboardItem.hide();
    $('div.dashboard .module[role="navigation"]').after(dashboardItem);

    $('a', blockListSettingsItem).on("click", function() {
        dashboardItem.show();
    });
    $('#user-dropdown .dropdown-menu').append(blockListSettingsItem);
}

// GLOBAL VARIABLES ////////////////////////////////////////////////////////////

// Make a list of sources to load blocklists from. We will initialize this
// when the DOM is ready, to avoid slowdown.
blockListSources = [];

// Note that this decision has ethical consequences! The block list is not
// applied until well after the body is loaded, so harassing content may be seen
// briefly. If this is unacceptable, we should modify this behavior to load
// immediately, even at the cost of introducing slowdown and instabilty.

// Make a list of whom to block so far.
blockList = [];

// Make a style container to hold the block styles.
// TODO: make one per block source, so we can refresh independently.
style = $('');

// MAIN ////////////////////////////////////////////////////////////////////////

$('body').ready(function() {

    // Grab the block sources from the configuration store.
    if (localStorage["blockListSources"] == undefined) {
        // Since we don't have a configuration GUI at the moment,
        // we need a default. This WILL be removed once a GUI is in place,
        // as no one gets to be specially privileged by this script.
        // Right now, this blocklist only blocks the author of this script,
        // to demonstrate the concept.
        blockListSources = ['https://raw.github.com/cgranade/decentralized-blockscript/master/blocklist-example.json'];
    } else {
        blockListSources = localStorage["blockListSources"];
    }

    $('head').append(style);
    loadBlockList(blockListSources);

    createSettingsGUI();

});
<|endoftext|>


<commit_before>var schedule = [
{
  date: "12/1",
  author: "ymyzk",
  author_url: "http://www.ymyzk.com",
  entry_title: "CAMPHOR- アドベントカレンダー 2014 を始めます!",
  entry_url: "http://blog.camph.net/news/advent-calendar-2014/"
},
{
  date: "12/2",
  author: "ohmuraken",
  author_url: "https://github.com/ohmuraken",
  entry_title: "彼女のつくりかた (京大11月祭にて)",
  entry_url: "http://blog.camph.net/news/howtomakemygirlfriend2/"
},
{
  date: "12/3",
  author: "morishin",
  author_url: "https://twitter.com/morishin127",
  entry_title: "CAMPHOR-のYo活用",
  entry_url: "http://blog.camph.net/news/useful-yo/"
},
{
  date: "12/4",
  author: "kohey18",
  author_url: "https://github.com/kohey18",
  entry_title: "「hubot start tv」で家のテレビの電源を付ける。",
  entry_url: "http://tech.camph.net/hubot_start_tv/"
},
{
  date: "12/5",
  author: "Shtr28",
  author_url: "https://twitter.com/Shtr28",
  entry_title: "Python 3でお手軽並列計算 ~concurrent.futures を使った ngram 抽出~",
  entry_url: "http://tech.camph.net/python3-concurrent-futures/"
},
{
  date: "12/6",
  author: "yaitaimo",
  author_url: "https://github.com/yaitaimo",
  entry_title: "CAMPHOR-HOUSEの庭を美白した話",
  entry_url: "http://blog.camph.net/event/camphor-house-garden/"
},
{
  date: "12/7",
  author: "tomonkey1",
  author_url: "https://github.com/tomonkey1",
  entry_title: "宅建挑戦記",
  entry_url: "http://blog.camph.net/event/takken/"
},
{
  date: "12/8",
  author: "asadaman",
  author_url: "https://github.com/asadaman",
  entry_title: "ロボットに負けたくない",
  entry_url: "http://blog.camph.net/news/robo/"
},
{
  date: "12/9",
  author: "akaaariiiiin",
  author_url: "https://github.com/akaaariiiiin",
  entry_title: "Java の MigLayout",
  entry_url: "http://tech.camph.net/java-miglayout/"
},
{
  date: "12/10",
  author: "To-Mikasa",
  author_url: "https://github.com/To-Mikasa",
  entry_title: "ノンデザイナーがそれっぽいWebデザインを作る話",
  entry_url: "http://blog.camph.net/news/non-designer/"
},
{
  date: "12/11",
  author: "ryota-ka",
  author_url: "http://ryota-ka.me/",
  entry_title: "iOS 初心者が Swift を使って3日でゲームを作った話",
  entry_url: "http://tech.camph.net/an-ios-beginner-made-a-game-app-with-swift-in-3-days/"
},
{
  date: "12/12",
  author: "siriusjack",
  author_url: "https://github.com/siriusjack",
  entry_title: "食べられるドングリの見分け方(ドイツ編)",
  entry_url: "http://blog.camph.net/news/nuts_eating_in_germany/"
},
{
  date: "12/13",
  author: "ivstivs",
  author_url: "https://github.com/ivstivs",
  entry_title: "ProjectileとHelm",
  entry_url: "http://tech.camph.net/projectile-and-helm/"
},
{
  date: "12/14",
  author: "kakenn",
  author_url: "http://shuto.info",
  entry_title: "格安3Dプリンター「daVinci 2.0」を買ってみた。",
  entry_url: "http://blog.camph.net/news/buy-davinci-2-0/"
},
{
  date: "12/15",
  author: "ymyzk",
  author_url: "http://www.ymyzk.com",
  entry_title: "sphinxcontrib.httpdomain で RESTful API のドキュメントを作る",
  entry_url: "https://blog.ymyzk.com/2014/12/restful-api-docs-with-sphinxcontrib-httpdomain/"
},
{
  date: "12/16",
  author: "cotton_ori",
  author_url: "https://twitter.com/cotton_ori",
  entry_title: "知らない人たちとハッカソンに参加した話",
  entry_url: "http://wataori.hatenadiary.jp/entry/2014/12/16/003000"
},
{
  date: "12/17",
  author: "pepoipod",
  author_url: "https://github.com/pepoipod",
  entry_title: "UnityFree + LeapでUnityちゃんを投げを作る",
  entry_url: "http://tech.camph.net/unityfree-leap/"
},
{
  date: "12/18",
  author: "ohmuraken",
  author_url: "https://github.com/ohmuraken",
  entry_title: "京都の学生が集まる町家ワークスペースCAMPHOR- HOUSEの紹介",
  entry_url: "http://blog.camph.net/news/about-house/"
},
{
  date: "12/19",
  author: "kohey18",
  author_url: "https://github.com/kohey18",
  entry_title: "Gyazoの使い方を熱く語るぞ!",
  entry_url: "http://blog.camph.net/tool/useful_gyazo/"
},
{
  date: "12/20",
  author: "murata_atsumi",
  author_url: "https://twitter.com/murata_atsumi",
  entry_title: "ノンデザイナーでもできる！写真を使ったイケてるメイン画像の作り方",
  entry_url: "http://tech.camph.net/mainimage-designing/"
},
{
  date: "12/21",
  author: "morishin",
  author_url: "https://twitter.com/morishin127",
  entry_title: "Pythonでローディングのぐるぐるを表示する",
  entry_url: "http://tech.camph.net/python-guruguru/"
}
,
{
  date: "12/22",
  author: "yaitaimo",
  author_url: "https://github.com/yaitaimo",
  entry_title: "Alfred Workflowsの作り方 — Python Ver. –",
  entry_url: "http://tech.camph.net/alfred-workflows-python/"
}
,
{
  date: "12/23",
  author: "ryota-ka",
  author_url: "http://ryota-ka.me/",
  entry_title: "初心者でもできる！関数型プログラミング入門",
  entry_url: "http://tech.camph.net/functional-php/"
}
,
{
  date: "12/24",
  author: "ohmuraken",
  author_url: "https://github.com/ohmuraken",
  entry_title: "サイボウズさんとSelenium勉強会を開催しました",
  entry_url: "http://blog.camph.net/event/selenium-with-cybozu/"
}
,
{
  date: "12/25",
  author: "準備中",
  author_url: "#",
  entry_title: "準備中",
  entry_url: "#"
}
];
<commit_msg>Update 2014/12/25<commit_after>var schedule = [
{
  date: "12/1",
  author: "ymyzk",
  author_url: "http://www.ymyzk.com",
  entry_title: "CAMPHOR- アドベントカレンダー 2014 を始めます!",
  entry_url: "http://blog.camph.net/news/advent-calendar-2014/"
},
{
  date: "12/2",
  author: "ohmuraken",
  author_url: "https://github.com/ohmuraken",
  entry_title: "彼女のつくりかた (京大11月祭にて)",
  entry_url: "http://blog.camph.net/news/howtomakemygirlfriend2/"
},
{
  date: "12/3",
  author: "morishin",
  author_url: "https://twitter.com/morishin127",
  entry_title: "CAMPHOR-のYo活用",
  entry_url: "http://blog.camph.net/news/useful-yo/"
},
{
  date: "12/4",
  author: "kohey18",
  author_url: "https://github.com/kohey18",
  entry_title: "「hubot start tv」で家のテレビの電源を付ける。",
  entry_url: "http://tech.camph.net/hubot_start_tv/"
},
{
  date: "12/5",
  author: "Shtr28",
  author_url: "https://twitter.com/Shtr28",
  entry_title: "Python 3でお手軽並列計算 ~concurrent.futures を使った ngram 抽出~",
  entry_url: "http://tech.camph.net/python3-concurrent-futures/"
},
{
  date: "12/6",
  author: "yaitaimo",
  author_url: "https://github.com/yaitaimo",
  entry_title: "CAMPHOR-HOUSEの庭を美白した話",
  entry_url: "http://blog.camph.net/event/camphor-house-garden/"
},
{
  date: "12/7",
  author: "tomonkey1",
  author_url: "https://github.com/tomonkey1",
  entry_title: "宅建挑戦記",
  entry_url: "http://blog.camph.net/event/takken/"
},
{
  date: "12/8",
  author: "asadaman",
  author_url: "https://github.com/asadaman",
  entry_title: "ロボットに負けたくない",
  entry_url: "http://blog.camph.net/news/robo/"
},
{
  date: "12/9",
  author: "akaaariiiiin",
  author_url: "https://github.com/akaaariiiiin",
  entry_title: "Java の MigLayout",
  entry_url: "http://tech.camph.net/java-miglayout/"
},
{
  date: "12/10",
  author: "To-Mikasa",
  author_url: "https://github.com/To-Mikasa",
  entry_title: "ノンデザイナーがそれっぽいWebデザインを作る話",
  entry_url: "http://blog.camph.net/news/non-designer/"
},
{
  date: "12/11",
  author: "ryota-ka",
  author_url: "http://ryota-ka.me/",
  entry_title: "iOS 初心者が Swift を使って3日でゲームを作った話",
  entry_url: "http://tech.camph.net/an-ios-beginner-made-a-game-app-with-swift-in-3-days/"
},
{
  date: "12/12",
  author: "siriusjack",
  author_url: "https://github.com/siriusjack",
  entry_title: "食べられるドングリの見分け方(ドイツ編)",
  entry_url: "http://blog.camph.net/news/nuts_eating_in_germany/"
},
{
  date: "12/13",
  author: "ivstivs",
  author_url: "https://github.com/ivstivs",
  entry_title: "ProjectileとHelm",
  entry_url: "http://tech.camph.net/projectile-and-helm/"
},
{
  date: "12/14",
  author: "kakenn",
  author_url: "http://shuto.info",
  entry_title: "格安3Dプリンター「daVinci 2.0」を買ってみた。",
  entry_url: "http://blog.camph.net/news/buy-davinci-2-0/"
},
{
  date: "12/15",
  author: "ymyzk",
  author_url: "http://www.ymyzk.com",
  entry_title: "sphinxcontrib.httpdomain で RESTful API のドキュメントを作る",
  entry_url: "https://blog.ymyzk.com/2014/12/restful-api-docs-with-sphinxcontrib-httpdomain/"
},
{
  date: "12/16",
  author: "cotton_ori",
  author_url: "https://twitter.com/cotton_ori",
  entry_title: "知らない人たちとハッカソンに参加した話",
  entry_url: "http://wataori.hatenadiary.jp/entry/2014/12/16/003000"
},
{
  date: "12/17",
  author: "pepoipod",
  author_url: "https://github.com/pepoipod",
  entry_title: "UnityFree + LeapでUnityちゃんを投げを作る",
  entry_url: "http://tech.camph.net/unityfree-leap/"
},
{
  date: "12/18",
  author: "ohmuraken",
  author_url: "https://github.com/ohmuraken",
  entry_title: "京都の学生が集まる町家ワークスペースCAMPHOR- HOUSEの紹介",
  entry_url: "http://blog.camph.net/news/about-house/"
},
{
  date: "12/19",
  author: "kohey18",
  author_url: "https://github.com/kohey18",
  entry_title: "Gyazoの使い方を熱く語るぞ!",
  entry_url: "http://blog.camph.net/tool/useful_gyazo/"
},
{
  date: "12/20",
  author: "murata_atsumi",
  author_url: "https://twitter.com/murata_atsumi",
  entry_title: "ノンデザイナーでもできる！写真を使ったイケてるメイン画像の作り方",
  entry_url: "http://tech.camph.net/mainimage-designing/"
},
{
  date: "12/21",
  author: "morishin",
  author_url: "https://twitter.com/morishin127",
  entry_title: "Pythonでローディングのぐるぐるを表示する",
  entry_url: "http://tech.camph.net/python-guruguru/"
}
,
{
  date: "12/22",
  author: "yaitaimo",
  author_url: "https://github.com/yaitaimo",
  entry_title: "Alfred Workflowsの作り方 — Python Ver. –",
  entry_url: "http://tech.camph.net/alfred-workflows-python/"
}
,
{
  date: "12/23",
  author: "ryota-ka",
  author_url: "http://ryota-ka.me/",
  entry_title: "初心者でもできる！関数型プログラミング入門",
  entry_url: "http://tech.camph.net/functional-php/"
}
,
{
  date: "12/24",
  author: "ohmuraken",
  author_url: "https://github.com/ohmuraken",
  entry_title: "サイボウズさんとSelenium勉強会を開催しました",
  entry_url: "http://blog.camph.net/event/selenium-with-cybozu/"
}
,
{
  date: "12/25",
  author: "kohey18",
  author_url: "https://github.com/kohey18",
  entry_title: "2014年度 CAMPHOR- Advent Calendar 2014をまとめるよ！",
  entry_url: "#"
}
];
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed 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.
//
////////////////////////////////////////////////////////////////////////////

/* eslint-env es6, node */
/* eslint-disable no-console */

'use strict';

const fs = require('fs');
const path = require('path');

const Realm = require('realm');
const RealmTests = require('../js');

jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;

// Create this method with appropriate implementation for Node testing.
Realm.copyBundledRealmFiles = function() {
    let sourceDir = path.join(__dirname, '../data');
    let destinationDir = path.dirname(Realm.defaultPath);

    for (let filename of fs.readdirSync(sourceDir)) {
        let src = path.join(sourceDir, filename);
        let dest = path.join(destinationDir, filename);

        // If the destination file already exists, then don't overwrite it.
        try {
            fs.accessSync(dest);
            continue;
        } catch (e) {}

        fs.writeFileSync(dest, fs.readFileSync(src));
    }
};

const tests = RealmTests.getTestNames();
for (const suiteName in tests) {
    describe(suiteName, () => {
        beforeEach(() => RealmTests.runTest(suiteName, 'beforeEach'));

        for (const testName of tests[suiteName]) {
            it(testName, (done) => {
                try {
                    let result = RealmTests.runTest(suiteName, testName);
                    if (result instanceof Promise) {
                        result.then(done, done.fail.bind(done));
                    } else {
                        done();
                    }
                }
                catch (e) {
                    done.fail(e);
                }
            });
        }

        afterEach(() => RealmTests.runTest(suiteName, 'afterEach'));
    });
}
<commit_msg>increase jasmine timeout to a ridiculously high value<commit_after>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed 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.
//
////////////////////////////////////////////////////////////////////////////

/* eslint-env es6, node */
/* eslint-disable no-console */

'use strict';

const fs = require('fs');
const path = require('path');

const Realm = require('realm');
const RealmTests = require('../js');

jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;

// Create this method with appropriate implementation for Node testing.
Realm.copyBundledRealmFiles = function() {
    let sourceDir = path.join(__dirname, '../data');
    let destinationDir = path.dirname(Realm.defaultPath);

    for (let filename of fs.readdirSync(sourceDir)) {
        let src = path.join(sourceDir, filename);
        let dest = path.join(destinationDir, filename);

        // If the destination file already exists, then don't overwrite it.
        try {
            fs.accessSync(dest);
            continue;
        } catch (e) {}

        fs.writeFileSync(dest, fs.readFileSync(src));
    }
};

const tests = RealmTests.getTestNames();
for (const suiteName in tests) {
    describe(suiteName, () => {
        beforeEach(() => RealmTests.runTest(suiteName, 'beforeEach'));

        for (const testName of tests[suiteName]) {
            it(testName, (done) => {
                try {
                    let result = RealmTests.runTest(suiteName, testName);
                    if (result instanceof Promise) {
                        result.then(done, done.fail.bind(done));
                    } else {
                        done();
                    }
                }
                catch (e) {
                    done.fail(e);
                }
            });
        }

        afterEach(() => RealmTests.runTest(suiteName, 'afterEach'));
    });
}
<|endoftext|>


<commit_before>'use strict';

const CPU = require('./3502');
const {TRITS_PER_TRYTE, TRYTES_PER_WORD, TRITS_PER_WORD, MAX_TRYTE, MIN_TRYTE, MEMORY_SIZE} = require('./arch');
const {get_trit, set_trit, slice_trits} = require('trit-getset');
const Triterm = require('tritmapped-terminal');
const isInteger = require('is-integer');

// 4 trits in each dimension, xxxx and yyyy
const VIDEO_TRYTE_COUNT = 4;

// '00xxx xyyyy' address -> 'xxxxx' tritmap value
const VIDEO_ADDRESS_SIZE = (3**VIDEO_TRYTE_COUNT * TRITS_PER_TRYTE)**TRYTES_PER_WORD / TRITS_PER_TRYTE;

const Memory = require('./memory');

const MAX_ADDRESS = (3**TRITS_PER_WORD - 1) / 2;
const MIN_ADDRESS = -MAX_ADDRESS;

const VIDEO_ADDRESS_OFFSET = MAX_ADDRESS - VIDEO_ADDRESS_SIZE; // -3281
if (VIDEO_ADDRESS_SIZE + VIDEO_ADDRESS_OFFSET !== MAX_ADDRESS) throw new Error('wrong video address size');

const CHARGEN_ADDRESS = -3282; // 0i111 11110
const CURSOR_ROW_ADDRESS = -3283;
const CURSOR_COL_ADDRESS = -3284;

const TIMER_FREQUENCY_ADDRESS = -3285;

const INT_VECTOR_N_ADDRESS = -29524; const INT_INPUT = -1;
const INT_VECTOR_Z_ADDRESS = -29522; const INT_START = 0;
const INT_VECTOR_P_ADDRESS = -29520; const INT_PULSE = 1;

const CODE_START_ADDRESS = -29518;

const memory = Memory({
  tryteCount: MEMORY_SIZE,
  map: {
    video: {
      start: VIDEO_ADDRESS_OFFSET,                      // -3281      0i111 11111
      end: VIDEO_ADDRESS_SIZE + VIDEO_ADDRESS_OFFSET,   // 29524, end 11111 11111
    },
    chargen: {
      start: CHARGEN_ADDRESS,
      end: CHARGEN_ADDRESS,
    },
    timer: {
      start: TIMER_FREQUENCY_ADDRESS,
      end: TIMER_FREQUENCY_ADDRESS,
    },
  }
});

console.log('memory.map',memory.map);

const term = Triterm({
  addressTryteSize: VIDEO_TRYTE_COUNT,
  tritmap: memory.subarray(memory.map.video.start, memory.map.video.end),
  handleInput: (tt, ev) => {
    if (isInteger(tt)) {
      cpu.interrupt(INT_INPUT, tt);
    }
  },
});

memory.map.video.write = (address, value) => {
  // When writing to video, refresh the terminal canvas
  // TODO: optimize to throttle refresh? refresh rate 60 Hz?/requestAnimationFrame? dirty, only if changes?
  //console.log('video write:',address,value);
  term.tc.refresh();
};

memory.map.chargen.write = (address, value) => {
  console.log('chargen',value);

  var row = memory.read(CURSOR_ROW_ADDRESS);
  var col = memory.read(CURSOR_COL_ADDRESS);

  // wrap-around if row/col out of terminal range
  row %= term.rowCount; if (row < 0) row += term.rowCount;
  col %= term.colCount; if (col < 0) col += term.colCount;

  console.log('COLROW',col,row);

  term.setTTChar(value, col, row);
  // TODO: write to row,col from another memory address value (no trap needed). -3282, -3283? - for cursor
};

const cpu = CPU({
  memory: memory
});

let _timer;
memory.map.timer.write = (address, value) => {
  function fire() {
    let ms = memory.read(TIMER_FREQUENCY_ADDRESS) * 100;
    if (ms < 100) ms = 100;

    console.log(`TIMER FIRE, next=${ms} ms`);
    cpu.interrupt(INT_PULSE); // TODO: pass dt, time since previous fire?

    _timer = window.setTimeout(fire, ms);
  };

  if (_timer === undefined) fire();
};

global.cpu = cpu;

const assembler = require('./as');

var lines = [
    '.org '+CODE_START_ADDRESS,
    'LDA #$ijk',
    'LDA #%ii1i0',
    'LDA #&QF',
    'NOP A',
    'NOP #-121',
    'NOP 29524',
    'LDA #0',
    'BNE #-1',
    'BEQ #+2',
    'HALTN',
    'HALTP',
    'LDA #42',
    'STA 0',

    'LDA #%00i01',
    'PTI A',

    'TAX',

    'LDA #%1111i',    // trit-text 'X'

    '.equ -3282 chargen',
    '.equ -3283 row',
    '.equ -3284 col',

    'STA chargen',

    'LDX #1',
    'STX col',
    'STA chargen',

    'LDX #1',
    'STX row',
    'LDX #2',
    'STX col',
    'STA chargen',

    'LDX #-1',
    'STX row',
    'STA chargen',

    'LDX #0',
    'STX row',
    'LDY #4',
    'STY col',
    'LDX #1',
    'STA chargen',

    'ADC #2',
    'NOT A',
    'STA chargen',  // trit-text red 'Z'

    'LDX #4',
    'INX',
    'STX col',
    'DEC chargen',  // trit-text 'Y'

    'TXA',  // X->A, 5

    // loop 6..19
    'loop:',
    'INC A',
    'STA col',
    'STA chargen',
    'CMP #20',
    //'BNE #-11',
    'BNE loop',

    'LDA #1',
    'STA row',
    'LDA #0',
    'STA col',

    // set input interrupt handler
    '.equ -29524 int_inputL',
    '.equ -29523 int_inputH',
    'LDA #handle_input.low',
    'STA int_inputL',
    'LDA #handle_input.high',
    'STA int_inputH',

    'SEIP', // enable interrupt -1 (keyboard input) TODO: also handle int 1, then can unmask all with CLI

    // set pulse interrupt handler
    '.equ -29520 int_pulseL',
    '.equ -29519 int_pulseH',
    'LDA #handle_pulse.low',
    'STA int_pulseL',
    'LDA #handle_pulse.high',
    'STA int_pulseH',

    'CLI',  // enable all interrupts

    '.equ -10000 cursor_char', // variable
    'LDA #%11iii',   // trit-text '_'
    'STA cursor_char',

    '.equ -3285 timer_freq',
    'LDA #1', // 100 ms
    'STA timer_freq', // triggers interrupt immediately.. TODO: probably should delay! or never returns?

    'HALTZ',

    'handle_pulse:',
    // blinking cursor
    'LDA cursor_char',
    'STA chargen',
    'NEG cursor_char',  // toggle red/green '_'
    'HALTZ',

    // advance terminal to next line
    'next_line:',
    'INC row',
    'LDA #0',
    'STA col',
    'HALTZ',       // TODO: RTI? return from interrupt

    'prev_line:',
    'DEC row',
    'LDA #44',    // TODO: .equ
    'STA col',
    'HALTZ',

    'backspace:',
    'LDA #0',
    'STA chargen', // clear cursor
    'DEC col',
    'LDA col',
    'CMP #-1',
    'BEQ prev_line',
    'LDA #0',     // null to erase TODO: space?
    'STA chargen',
    'HALTZ',

    // interrupt handler:
    'handle_input:',
    'CMP #12',        // trit-text newline
    'BEQ next_line',
    'CMP #0',
    'BEQ backspace',
    'STA chargen',
    'INC col',
    'LDX col',
    '.equ 46 row_count', // TODO: > instead of =
    'CPX #row_count',
    'BEQ next_line',  // TODO: support unresolved forward references in relative labels, offsets..
    'HALTZ',
];

cpu.memory.writeArray(CODE_START_ADDRESS, assembler(lines));
cpu.memory.write(INT_VECTOR_Z_ADDRESS, slice_trits(CODE_START_ADDRESS, 0, 5));
cpu.memory.write(INT_VECTOR_Z_ADDRESS + 1, slice_trits(CODE_START_ADDRESS, 5, 10));

//cpu.pc = cpu.read_int_vector(0);
//cpu.run();

cpu.interrupt(INT_START);

<commit_msg>Fix cursor remnant when advancing to next line with enter<commit_after>'use strict';

const CPU = require('./3502');
const {TRITS_PER_TRYTE, TRYTES_PER_WORD, TRITS_PER_WORD, MAX_TRYTE, MIN_TRYTE, MEMORY_SIZE} = require('./arch');
const {get_trit, set_trit, slice_trits} = require('trit-getset');
const Triterm = require('tritmapped-terminal');
const isInteger = require('is-integer');

// 4 trits in each dimension, xxxx and yyyy
const VIDEO_TRYTE_COUNT = 4;

// '00xxx xyyyy' address -> 'xxxxx' tritmap value
const VIDEO_ADDRESS_SIZE = (3**VIDEO_TRYTE_COUNT * TRITS_PER_TRYTE)**TRYTES_PER_WORD / TRITS_PER_TRYTE;

const Memory = require('./memory');

const MAX_ADDRESS = (3**TRITS_PER_WORD - 1) / 2;
const MIN_ADDRESS = -MAX_ADDRESS;

const VIDEO_ADDRESS_OFFSET = MAX_ADDRESS - VIDEO_ADDRESS_SIZE; // -3281
if (VIDEO_ADDRESS_SIZE + VIDEO_ADDRESS_OFFSET !== MAX_ADDRESS) throw new Error('wrong video address size');

const CHARGEN_ADDRESS = -3282; // 0i111 11110
const CURSOR_ROW_ADDRESS = -3283;
const CURSOR_COL_ADDRESS = -3284;

const TIMER_FREQUENCY_ADDRESS = -3285;

const INT_VECTOR_N_ADDRESS = -29524; const INT_INPUT = -1;
const INT_VECTOR_Z_ADDRESS = -29522; const INT_START = 0;
const INT_VECTOR_P_ADDRESS = -29520; const INT_PULSE = 1;

const CODE_START_ADDRESS = -29518;

const memory = Memory({
  tryteCount: MEMORY_SIZE,
  map: {
    video: {
      start: VIDEO_ADDRESS_OFFSET,                      // -3281      0i111 11111
      end: VIDEO_ADDRESS_SIZE + VIDEO_ADDRESS_OFFSET,   // 29524, end 11111 11111
    },
    chargen: {
      start: CHARGEN_ADDRESS,
      end: CHARGEN_ADDRESS,
    },
    timer: {
      start: TIMER_FREQUENCY_ADDRESS,
      end: TIMER_FREQUENCY_ADDRESS,
    },
  }
});

console.log('memory.map',memory.map);

const term = Triterm({
  addressTryteSize: VIDEO_TRYTE_COUNT,
  tritmap: memory.subarray(memory.map.video.start, memory.map.video.end),
  handleInput: (tt, ev) => {
    if (isInteger(tt)) {
      cpu.interrupt(INT_INPUT, tt);
    }
  },
});

memory.map.video.write = (address, value) => {
  // When writing to video, refresh the terminal canvas
  // TODO: optimize to throttle refresh? refresh rate 60 Hz?/requestAnimationFrame? dirty, only if changes?
  //console.log('video write:',address,value);
  term.tc.refresh();
};

memory.map.chargen.write = (address, value) => {
  console.log('chargen',value);

  var row = memory.read(CURSOR_ROW_ADDRESS);
  var col = memory.read(CURSOR_COL_ADDRESS);

  // wrap-around if row/col out of terminal range
  row %= term.rowCount; if (row < 0) row += term.rowCount;
  col %= term.colCount; if (col < 0) col += term.colCount;

  console.log('COLROW',col,row);

  term.setTTChar(value, col, row);
  // TODO: write to row,col from another memory address value (no trap needed). -3282, -3283? - for cursor
};

const cpu = CPU({
  memory: memory
});

let _timer;
memory.map.timer.write = (address, value) => {
  function fire() {
    let ms = memory.read(TIMER_FREQUENCY_ADDRESS) * 100;
    if (ms < 100) ms = 100;

    console.log(`TIMER FIRE, next=${ms} ms`);
    cpu.interrupt(INT_PULSE); // TODO: pass dt, time since previous fire?

    _timer = window.setTimeout(fire, ms);
  };

  if (_timer === undefined) fire();
};

global.cpu = cpu;

const assembler = require('./as');

var lines = [
    '.org '+CODE_START_ADDRESS,
    'LDA #$ijk',
    'LDA #%ii1i0',
    'LDA #&QF',
    'NOP A',
    'NOP #-121',
    'NOP 29524',
    'LDA #0',
    'BNE #-1',
    'BEQ #+2',
    'HALTN',
    'HALTP',
    'LDA #42',
    'STA 0',

    'LDA #%00i01',
    'PTI A',

    'TAX',

    'LDA #%1111i',    // trit-text 'X'

    '.equ -3282 chargen',
    '.equ -3283 row',
    '.equ -3284 col',

    'STA chargen',

    'LDX #1',
    'STX col',
    'STA chargen',

    'LDX #1',
    'STX row',
    'LDX #2',
    'STX col',
    'STA chargen',

    'LDX #-1',
    'STX row',
    'STA chargen',

    'LDX #0',
    'STX row',
    'LDY #4',
    'STY col',
    'LDX #1',
    'STA chargen',

    'ADC #2',
    'NOT A',
    'STA chargen',  // trit-text red 'Z'

    'LDX #4',
    'INX',
    'STX col',
    'DEC chargen',  // trit-text 'Y'

    'TXA',  // X->A, 5

    // loop 6..19
    'loop:',
    'INC A',
    'STA col',
    'STA chargen',
    'CMP #20',
    //'BNE #-11',
    'BNE loop',

    'LDA #1',
    'STA row',
    'LDA #0',
    'STA col',

    // set input interrupt handler
    '.equ -29524 int_inputL',
    '.equ -29523 int_inputH',
    'LDA #handle_input.low',
    'STA int_inputL',
    'LDA #handle_input.high',
    'STA int_inputH',

    'SEIP', // enable interrupt -1 (keyboard input) TODO: also handle int 1, then can unmask all with CLI

    // set pulse interrupt handler
    '.equ -29520 int_pulseL',
    '.equ -29519 int_pulseH',
    'LDA #handle_pulse.low',
    'STA int_pulseL',
    'LDA #handle_pulse.high',
    'STA int_pulseH',

    'CLI',  // enable all interrupts

    '.equ -10000 cursor_char', // variable
    'LDA #%11iii',   // trit-text '_'
    'STA cursor_char',

    '.equ -3285 timer_freq',
    'LDA #1', // 100 ms
    'STA timer_freq', // triggers interrupt immediately.. TODO: probably should delay! or never returns?

    'HALTZ',

    'handle_pulse:',
    // blinking cursor
    'LDA cursor_char',
    'STA chargen',
    'NEG cursor_char',  // toggle red/green '_'
    'HALTZ',

    // advance terminal to next line
    'next_line:',
    'LDA #0',
    'STA chargen',  // clear cursor
    'INC row',
    'LDA #0',
    'STA col',
    'HALTZ',       // TODO: RTI? return from interrupt

    'prev_line:',
    'DEC row',
    'LDA #44',    // TODO: .equ
    'STA col',
    'HALTZ',

    'backspace:',
    'LDA #0',
    'STA chargen', // clear cursor
    'DEC col',
    'LDA col',
    'CMP #-1',
    'BEQ prev_line',
    'LDA #0',     // null to erase TODO: space?
    'STA chargen',
    'HALTZ',

    // interrupt handler:
    'handle_input:',
    'CMP #12',        // trit-text newline
    'BEQ next_line',
    'CMP #0',
    'BEQ backspace',
    'STA chargen',
    'INC col',
    'LDX col',
    '.equ 46 row_count', // TODO: > instead of =
    'CPX #row_count',
    'BEQ next_line',  // TODO: support unresolved forward references in relative labels, offsets..
    'HALTZ',
];

cpu.memory.writeArray(CODE_START_ADDRESS, assembler(lines));
cpu.memory.write(INT_VECTOR_Z_ADDRESS, slice_trits(CODE_START_ADDRESS, 0, 5));
cpu.memory.write(INT_VECTOR_Z_ADDRESS + 1, slice_trits(CODE_START_ADDRESS, 5, 10));

//cpu.pc = cpu.read_int_vector(0);
//cpu.run();

cpu.interrupt(INT_START);

<|endoftext|>


<commit_before>var archinfo = require('./archinfo.js');
var buildmessage = require('./buildmessage.js');
var files = require('./files.js');
var _ = require('underscore');
import utils from './utils.js';

let nextId = 1;

exports.SourceProcessor = function (options) {
  var self = this;
  self.isopack = options.isopack;
  self.extensions = (options.extensions || []).slice();
  self.filenames = (options.filenames || []).slice();
  self.archMatching = options.archMatching;
  self.isTemplate = !! options.isTemplate;
  self.factoryFunction = options.factoryFunction;
  self.id = `${ options.isopack.displayName() }#${ nextId++ }`;
  self.userPlugin = null;
};
_.extend(exports.SourceProcessor.prototype, {
  // Call the user's factory function to get the actual build plugin object.
  // Note that we're supposed to have one userPlugin per project, so this
  // assumes that each Isopack object is specific to a project.  We don't run
  // this immediately on evaluating Plugin.registerCompiler; we instead wait
  // until the whole plugin file has been evaluated (so that it can use things
  // defined later in the file).
  instantiatePlugin: function () {
    var self = this;
    if (self.userPlugin) {
      throw Error("Called instantiatePlugin twice?");
    }
    // XXX BBP proper error handling --- this is running user-supplied plugin
    // code, and use markBoundary too
    try {
      self.userPlugin = buildmessage.markBoundary(self.factoryFunction).call(
        null);
      // If we have a disk cache directory and the plugin wants it, use it.
      if (self.isopack.pluginCacheDir &&
          self.userPlugin.setDiskCacheDirectory) {
        const markedMethod = buildmessage.markBoundary(
          self.userPlugin.setDiskCacheDirectory.bind(self.userPlugin));
        markedMethod(self.isopack.pluginCacheDir);
      }
    } catch (e) {
      buildmessage.exception(e);
    }
  },
  relevantForArch: function (arch) {
    var self = this;
    return ! self.archMatching || archinfo.matches(arch, self.archMatching);
  }
});

// Represents a set of SourceProcessors available in a given package. They may
// not have conflicting extensions or filenames.
export class SourceProcessorSet {
  constructor(myPackageDisplayName,
              { hardcodeJs, singlePackage, allowConflicts }) {
    // For error messages only.
    this._myPackageDisplayName = myPackageDisplayName;
    // If this represents the SourceProcessors *registered* by a single package
    // (vs those *available* to a package), use different error messages.
    this._singlePackage = singlePackage;
    // If this is being used for *compilers*, we hardcode *.js. If it is being
    // used for linters, we don't.
    this._hardcodeJs = !! hardcodeJs;
    // Multiple linters may be registered on the same extension or filename, but
    // not compilers.
    this._allowConflicts = !! allowConflicts;

    // Map from extension -> [SourceProcessor]
    this._byExtension = {};
    // Map from basename -> [SourceProcessor]
    this._byFilename = {};
    // This is just an duplicate-free list of all SourceProcessors in
    // byExtension or byFilename.
    this.allSourceProcessors = [];
    // extension -> { handler, packageDisplayName, isTemplate, archMatching }
    this._legacyHandlers = {};
  }

  _conflictError(package1, package2, conflict) {
    if (this._singlePackage) {
      buildmessage.error(
        `plugins in package ${ this._myPackageDisplayName } define multiple ` +
          `handlers for ${ conflict }`);
    } else {
      buildmessage.error(
        `conflict: two packages included in ${ this._myPackageDisplayName } ` +
          `(${ package1 } and ${ package2 }) are both trying to handle ` +
          conflict);
    }
  }

  addSourceProcessor(sp) {
    buildmessage.assertInJob();
    this._addSourceProcessorHelper(sp, sp.extensions, this._byExtension, '*.');
    this._addSourceProcessorHelper(sp, sp.filenames, this._byFilename, '');
    // If everything conflicted, then the SourceProcessors will be in
    // allSourceProcessors but not any of the data structures, but in that case
    // the caller should be checking for errors anyway.
    this.allSourceProcessors.push(sp);
  }
  _addSourceProcessorHelper(sp, things, byThing, errorPrefix) {
    buildmessage.assertInJob();

    things.forEach((thing) => {
      if (byThing.hasOwnProperty(thing)) {
        if (this._allowConflicts) {
          byThing[thing].push(sp);
        } else {
          this._conflictError(sp.isopack.displayName(),
                              byThing[thing][0].isopack.displayName(),
                              errorPrefix + thing);
          // recover by ignoring this one
        }
      } else {
        byThing[thing] = [sp];
      }
    });
  }

  addLegacyHandler({ extension, handler, packageDisplayName, isTemplate,
                     archMatching }) {
    if (this._allowConflicts)
      throw Error("linters have no legacy handlers");

    if (this._byExtension.hasOwnProperty(extension)) {
      this._conflictError(packageDisplayName,
                          this._byExtension[extension].isopack.displayName(),
                          '*.' + extension);
      // recover by ignoring
      return;
    }
    if (this._legacyHandlers.hasOwnProperty(extension)) {
      this._conflictError(packageDisplayName,
                          this._legacyHandlers[extension].packageDisplayName,
                          '*.' + extension);
      // recover by ignoring
      return;
    }
    this._legacyHandlers[extension] =
      {handler, packageDisplayName, isTemplate, archMatching};
  }

  // Adds all the source processors (and legacy handlers) from the other set to
  // this one. Logs buildmessage errors on conflict.  Ignores packageDisplayName
  // and singlePackage.  If arch is set, skips SourceProcessors that
  // don't match it.
  merge(otherSet, options = {}) {
    const { arch } = options;
    buildmessage.assertInJob();
    otherSet.allSourceProcessors.forEach((sourceProcessor) => {
      if (! arch || sourceProcessor.relevantForArch(arch)) {
        this.addSourceProcessor(sourceProcessor);
      }
    });
    _.each(otherSet._legacyHandlers, (info, extension) => {
      const { handler, packageDisplayName, isTemplate, archMatching } = info;
      this.addLegacyHandler(
        {extension, handler, packageDisplayName, isTemplate, archMatching});
    });
  }

  // Note: Only returns SourceProcessors, not legacy handlers.
  getByExtension(extension) {
    if (this._allowConflicts)
      throw Error("Can't call getByExtension for linters");

    if (this._byExtension.hasOwnProperty(extension)) {
      return this._byExtension[extension][0];
    }
    return null;
  }

  // Note: Only returns SourceProcessors, not legacy handlers.
  getByFilename(filename) {
    if (this._allowConflicts)
      throw Error("Can't call getByFilename for linters");

    if (this._byFilename.hasOwnProperty(filename)) {
      return this._byFilename[filename][0];
    }
    return null;
  }

  // filename, arch -> SourceClassification
  classifyFilename(filename, arch) {
    // First check to see if a plugin registered for this exact filename.
    if (this._byFilename.hasOwnProperty(filename)) {
      return new SourceClassification('filename', {
        arch,
        sourceProcessors: this._byFilename[filename].slice()
      });
    }

    // Now check to see if a plugin registered for an extension. We prefer
    // longer extensions.
    const parts = filename.split('.');
    // don't use iteration functions, so we can return (and start at #1)
    for (let i = 1; i < parts.length; i++) {
      const extension = parts.slice(i).join('.');
      // We specially handle 'js' in the build tool, because you can't provide a
      // plugin to handle 'js' files, because the plugin would need to be built
      // with JavaScript itself!  Places that hardcode JS are tagged with
      // #HardcodeJs.
      if (this._hardcodeJs && extension === 'js') {
        return new SourceClassification('extension', {extension});
      }

      if (this._byExtension.hasOwnProperty(extension)) {
        return new SourceClassification('extension', {
          arch,
          extension,
          sourceProcessors: this._byExtension[extension]
        });
      }

      if (this._legacyHandlers.hasOwnProperty(extension)) {
        const legacy = this._legacyHandlers[extension];
        if (legacy.archMatching &&
            ! archinfo.matches(arch, legacy.archMatching)) {
          return new SourceClassification('wrong-arch');
        }
        return new SourceClassification('legacy-handler', {
          extension,
          legacyHandler: legacy.handler,
          legacyIsTemplate: legacy.isTemplate
        });
      }
    }

    // Nothing matches; it must be a static asset (or a non-linted file).
    return new SourceClassification('unmatched');
  }

  isEmpty() {
    return _.isEmpty(this._byFilename) && _.isEmpty(this._byExtension) &&
      _.isEmpty(this._legacyHandlers);
  }

  // Returns an options object suitable for passing to
  // `watch.readAndWatchDirectory` to find source files processed by this
  // SourceProcessorSet.
  appReadDirectoryOptions(arch) {
    const include = [];
    const names = [];

    function addExtension(ext) {
      include.push(new RegExp('\\.' + utils.quotemeta(ext) + '$'));
    }
    _.each(this._byExtension, (sourceProcessors, ext) => {
      if (sourceProcessors.some(sp => sp.relevantForArch(arch))) {
        addExtension(ext);
      }
    });
    Object.keys(this._legacyHandlers).forEach(addExtension);
    this._hardcodeJs && addExtension('js');

    _.each(this._byFilename, (sourceProcessors, filename) => {
      if (sourceProcessors.some(sp => sp.relevantForArch(arch))) {
        names.push(filename);
      }
    });
    return {include, names, exclude: []};
  }
}

class SourceClassification {
  constructor(type, {legacyHandler, extension, sourceProcessors,
                     legacyIsTemplate, arch}) {
    const knownTypes = ['extension', 'filename', 'legacy-handler', 'wrong-arch',
                        'unmatched'];
    if (knownTypes.indexOf(type) === -1) {
      throw Error(`Unknown SourceClassification type ${ type }`);
    }
    // This is the only thing we can write to `this` before checking for
    // wrong-arch.
    this.type = type;

    if (type === 'extension' || type === 'filename') {
      if (sourceProcessors) {
        if (! arch) {
          throw Error("need to filter based on arch!");
        }

        // If there's a SourceProcessor (or legacy handler) registered for this
        // file but not for this arch, we want to ignore it instead of
        // processing it or treating it as a static asset. (Note that prior to
        // the batch-plugins project, files added in a package with
        // `api.addFiles('foo.bar')` where *.bar is a web-specific legacy
        // handler (eg) would end up adding 'foo.bar' as a static asset on
        // non-web programs, which was unintended. This didn't happen in apps
        // because initFromAppDir's getSourcesFunc never added them.)
        const filteredSourceProcessors = sourceProcessors.filter(
          (sourceProcessor) => sourceProcessor.relevantForArch(arch)
        );
        if (! filteredSourceProcessors.length) {
          // Wrong architecture! Rewrite this.type and return.  (Note that we
          // haven't written anything else to `this` so far.)
          this.type = 'wrong-arch';
          return;
        }

        this.sourceProcessors = filteredSourceProcessors;
      } else if (!(type === 'extension' && extension === 'js')) {
        // 'extension' and 'filename' classifications need to have at least one
        // SourceProcessor, unless it's the #HardcodeJs special case.
        throw Error(`missing sourceProcessors for ${ type }!`);
      }
    }

    if (type === 'legacy-handler') {
      if (! legacyHandler) {
        throw Error('SourceClassification needs legacyHandler!');
      }
      if (legacyIsTemplate === undefined) {
        throw Error('SourceClassification needs legacyIsTemplate!');
      }
      this.legacyHandler = legacyHandler;
      this.legacyIsTemplate = legacyIsTemplate;
    }

    if (type === 'extension' || type === 'legacy-handler') {
      if (! extension) {
        throw Error('extension SourceClassification needs extension!');
      }
      this.extension = extension;
    }
  }

  isNonLegacySource() {
    return this.type === 'extension' || this.type === 'filename';
  }
}

// This is the base class of the object presented to the user's plugin code.
exports.InputFile = function (resourceSlot) {
};
_.extend(exports.InputFile.prototype, {
  /**
   * @summary Returns the full contents of the file as a buffer.
   * @memberof InputFile
   * @returns {Buffer}
   */
  getContentsAsBuffer: function () {
    throw new Error("Not Implemented");
  },
  /**
   * @summary Returns the name of the package or `null` if the file is not in a
   * package.
   * @memberof InputFile
   * @returns {String}
   */
  getPackageName: function () {
    throw new Error("Not Implemented");
  },
  /**
   * @summary Returns the relative path of file to the package or app root
   * directory. The returned path always uses forward slashes.
   * @memberof InputFile
   * @returns {String}
   */
  getPathInPackage: function () {
    throw new Error("Not Implemented");
  },
  /**
   * @summary Returns a hash string for the file that can be used to implement
   * caching.
   * @memberof InputFile
   * @returns {String}
   */
  getSourceHash: function () {
    throw new Error("Not Implemented");
  },
  /**
   * @summary Returns a string symbol representing the architecture that is
   * targetted by processing this file. Can be used to implement caching.
   * XXX BBP is this doc string good?
   * @memberof InputFile
   * @returns {String}
   */
  getArch: function () {
    throw new Error("Not Implemented");
  },

  /**
   * @summary Returns the full contents of the file as a string.
   * @memberof InputFile
   * @returns {String}
   */
  getContentsAsString: function () {
    var self = this;
    return self.getContentsAsBuffer().toString('utf8');
  },
  /**
   * @summary Returns the filename of the file.
   * @memberof InputFile
   * @returns {String}
   */
  getBasename: function () {
    var self = this;
    return files.pathBasename(self.getPathInPackage());
  },
  /**
   * @summary Returns the directory path relative to the package or app root.
   * The returned path always uses forward slashes.
   * @memberof InputFile
   * @returns {String}
   */
  getDirname: function () {
    var self = this;
    return files.pathDirname(self.getPathInPackage());
  },
  /**
   * @summary Call this method to raise a compilation or linting error for the
   * file.
   * @param {Object} options
   * @param {String} options.message The error message to display.
   * @param {String} [options.sourcePath] The path to display in the error message.
   * @param {Integer} options.line The line number to display in the error message.
   * @param {String} options.func The function name to display in the error message.
   * @memberof InputFile
   */
  error: function (options) {
    var self = this;
    var relPath = self.getPathInPackage();
    buildmessage.error(options.message || ("error building " + relPath), {
      file: options.sourcePath || relPath,
      line: options.line ? options.line : undefined,
      column: options.column ? options.column : undefined,
      func: options.func ? options.func : undefined
    });
  }
});
<commit_msg>missing default argument<commit_after>var archinfo = require('./archinfo.js');
var buildmessage = require('./buildmessage.js');
var files = require('./files.js');
var _ = require('underscore');
import utils from './utils.js';

let nextId = 1;

exports.SourceProcessor = function (options) {
  var self = this;
  self.isopack = options.isopack;
  self.extensions = (options.extensions || []).slice();
  self.filenames = (options.filenames || []).slice();
  self.archMatching = options.archMatching;
  self.isTemplate = !! options.isTemplate;
  self.factoryFunction = options.factoryFunction;
  self.id = `${ options.isopack.displayName() }#${ nextId++ }`;
  self.userPlugin = null;
};
_.extend(exports.SourceProcessor.prototype, {
  // Call the user's factory function to get the actual build plugin object.
  // Note that we're supposed to have one userPlugin per project, so this
  // assumes that each Isopack object is specific to a project.  We don't run
  // this immediately on evaluating Plugin.registerCompiler; we instead wait
  // until the whole plugin file has been evaluated (so that it can use things
  // defined later in the file).
  instantiatePlugin: function () {
    var self = this;
    if (self.userPlugin) {
      throw Error("Called instantiatePlugin twice?");
    }
    // XXX BBP proper error handling --- this is running user-supplied plugin
    // code, and use markBoundary too
    try {
      self.userPlugin = buildmessage.markBoundary(self.factoryFunction).call(
        null);
      // If we have a disk cache directory and the plugin wants it, use it.
      if (self.isopack.pluginCacheDir &&
          self.userPlugin.setDiskCacheDirectory) {
        const markedMethod = buildmessage.markBoundary(
          self.userPlugin.setDiskCacheDirectory.bind(self.userPlugin));
        markedMethod(self.isopack.pluginCacheDir);
      }
    } catch (e) {
      buildmessage.exception(e);
    }
  },
  relevantForArch: function (arch) {
    var self = this;
    return ! self.archMatching || archinfo.matches(arch, self.archMatching);
  }
});

// Represents a set of SourceProcessors available in a given package. They may
// not have conflicting extensions or filenames.
export class SourceProcessorSet {
  constructor(myPackageDisplayName,
              { hardcodeJs, singlePackage, allowConflicts }) {
    // For error messages only.
    this._myPackageDisplayName = myPackageDisplayName;
    // If this represents the SourceProcessors *registered* by a single package
    // (vs those *available* to a package), use different error messages.
    this._singlePackage = singlePackage;
    // If this is being used for *compilers*, we hardcode *.js. If it is being
    // used for linters, we don't.
    this._hardcodeJs = !! hardcodeJs;
    // Multiple linters may be registered on the same extension or filename, but
    // not compilers.
    this._allowConflicts = !! allowConflicts;

    // Map from extension -> [SourceProcessor]
    this._byExtension = {};
    // Map from basename -> [SourceProcessor]
    this._byFilename = {};
    // This is just an duplicate-free list of all SourceProcessors in
    // byExtension or byFilename.
    this.allSourceProcessors = [];
    // extension -> { handler, packageDisplayName, isTemplate, archMatching }
    this._legacyHandlers = {};
  }

  _conflictError(package1, package2, conflict) {
    if (this._singlePackage) {
      buildmessage.error(
        `plugins in package ${ this._myPackageDisplayName } define multiple ` +
          `handlers for ${ conflict }`);
    } else {
      buildmessage.error(
        `conflict: two packages included in ${ this._myPackageDisplayName } ` +
          `(${ package1 } and ${ package2 }) are both trying to handle ` +
          conflict);
    }
  }

  addSourceProcessor(sp) {
    buildmessage.assertInJob();
    this._addSourceProcessorHelper(sp, sp.extensions, this._byExtension, '*.');
    this._addSourceProcessorHelper(sp, sp.filenames, this._byFilename, '');
    // If everything conflicted, then the SourceProcessors will be in
    // allSourceProcessors but not any of the data structures, but in that case
    // the caller should be checking for errors anyway.
    this.allSourceProcessors.push(sp);
  }
  _addSourceProcessorHelper(sp, things, byThing, errorPrefix) {
    buildmessage.assertInJob();

    things.forEach((thing) => {
      if (byThing.hasOwnProperty(thing)) {
        if (this._allowConflicts) {
          byThing[thing].push(sp);
        } else {
          this._conflictError(sp.isopack.displayName(),
                              byThing[thing][0].isopack.displayName(),
                              errorPrefix + thing);
          // recover by ignoring this one
        }
      } else {
        byThing[thing] = [sp];
      }
    });
  }

  addLegacyHandler({ extension, handler, packageDisplayName, isTemplate,
                     archMatching }) {
    if (this._allowConflicts)
      throw Error("linters have no legacy handlers");

    if (this._byExtension.hasOwnProperty(extension)) {
      this._conflictError(packageDisplayName,
                          this._byExtension[extension].isopack.displayName(),
                          '*.' + extension);
      // recover by ignoring
      return;
    }
    if (this._legacyHandlers.hasOwnProperty(extension)) {
      this._conflictError(packageDisplayName,
                          this._legacyHandlers[extension].packageDisplayName,
                          '*.' + extension);
      // recover by ignoring
      return;
    }
    this._legacyHandlers[extension] =
      {handler, packageDisplayName, isTemplate, archMatching};
  }

  // Adds all the source processors (and legacy handlers) from the other set to
  // this one. Logs buildmessage errors on conflict.  Ignores packageDisplayName
  // and singlePackage.  If arch is set, skips SourceProcessors that
  // don't match it.
  merge(otherSet, options = {}) {
    const { arch } = options;
    buildmessage.assertInJob();
    otherSet.allSourceProcessors.forEach((sourceProcessor) => {
      if (! arch || sourceProcessor.relevantForArch(arch)) {
        this.addSourceProcessor(sourceProcessor);
      }
    });
    _.each(otherSet._legacyHandlers, (info, extension) => {
      const { handler, packageDisplayName, isTemplate, archMatching } = info;
      this.addLegacyHandler(
        {extension, handler, packageDisplayName, isTemplate, archMatching});
    });
  }

  // Note: Only returns SourceProcessors, not legacy handlers.
  getByExtension(extension) {
    if (this._allowConflicts)
      throw Error("Can't call getByExtension for linters");

    if (this._byExtension.hasOwnProperty(extension)) {
      return this._byExtension[extension][0];
    }
    return null;
  }

  // Note: Only returns SourceProcessors, not legacy handlers.
  getByFilename(filename) {
    if (this._allowConflicts)
      throw Error("Can't call getByFilename for linters");

    if (this._byFilename.hasOwnProperty(filename)) {
      return this._byFilename[filename][0];
    }
    return null;
  }

  // filename, arch -> SourceClassification
  classifyFilename(filename, arch) {
    // First check to see if a plugin registered for this exact filename.
    if (this._byFilename.hasOwnProperty(filename)) {
      return new SourceClassification('filename', {
        arch,
        sourceProcessors: this._byFilename[filename].slice()
      });
    }

    // Now check to see if a plugin registered for an extension. We prefer
    // longer extensions.
    const parts = filename.split('.');
    // don't use iteration functions, so we can return (and start at #1)
    for (let i = 1; i < parts.length; i++) {
      const extension = parts.slice(i).join('.');
      // We specially handle 'js' in the build tool, because you can't provide a
      // plugin to handle 'js' files, because the plugin would need to be built
      // with JavaScript itself!  Places that hardcode JS are tagged with
      // #HardcodeJs.
      if (this._hardcodeJs && extension === 'js') {
        return new SourceClassification('extension', {extension});
      }

      if (this._byExtension.hasOwnProperty(extension)) {
        return new SourceClassification('extension', {
          arch,
          extension,
          sourceProcessors: this._byExtension[extension]
        });
      }

      if (this._legacyHandlers.hasOwnProperty(extension)) {
        const legacy = this._legacyHandlers[extension];
        if (legacy.archMatching &&
            ! archinfo.matches(arch, legacy.archMatching)) {
          return new SourceClassification('wrong-arch');
        }
        return new SourceClassification('legacy-handler', {
          extension,
          legacyHandler: legacy.handler,
          legacyIsTemplate: legacy.isTemplate
        });
      }
    }

    // Nothing matches; it must be a static asset (or a non-linted file).
    return new SourceClassification('unmatched');
  }

  isEmpty() {
    return _.isEmpty(this._byFilename) && _.isEmpty(this._byExtension) &&
      _.isEmpty(this._legacyHandlers);
  }

  // Returns an options object suitable for passing to
  // `watch.readAndWatchDirectory` to find source files processed by this
  // SourceProcessorSet.
  appReadDirectoryOptions(arch) {
    const include = [];
    const names = [];

    function addExtension(ext) {
      include.push(new RegExp('\\.' + utils.quotemeta(ext) + '$'));
    }
    _.each(this._byExtension, (sourceProcessors, ext) => {
      if (sourceProcessors.some(sp => sp.relevantForArch(arch))) {
        addExtension(ext);
      }
    });
    Object.keys(this._legacyHandlers).forEach(addExtension);
    this._hardcodeJs && addExtension('js');

    _.each(this._byFilename, (sourceProcessors, filename) => {
      if (sourceProcessors.some(sp => sp.relevantForArch(arch))) {
        names.push(filename);
      }
    });
    return {include, names, exclude: []};
  }
}

class SourceClassification {
  constructor(type, {legacyHandler, extension, sourceProcessors,
                     legacyIsTemplate, arch} = {}) {
    const knownTypes = ['extension', 'filename', 'legacy-handler', 'wrong-arch',
                        'unmatched'];
    if (knownTypes.indexOf(type) === -1) {
      throw Error(`Unknown SourceClassification type ${ type }`);
    }
    // This is the only thing we can write to `this` before checking for
    // wrong-arch.
    this.type = type;

    if (type === 'extension' || type === 'filename') {
      if (sourceProcessors) {
        if (! arch) {
          throw Error("need to filter based on arch!");
        }

        // If there's a SourceProcessor (or legacy handler) registered for this
        // file but not for this arch, we want to ignore it instead of
        // processing it or treating it as a static asset. (Note that prior to
        // the batch-plugins project, files added in a package with
        // `api.addFiles('foo.bar')` where *.bar is a web-specific legacy
        // handler (eg) would end up adding 'foo.bar' as a static asset on
        // non-web programs, which was unintended. This didn't happen in apps
        // because initFromAppDir's getSourcesFunc never added them.)
        const filteredSourceProcessors = sourceProcessors.filter(
          (sourceProcessor) => sourceProcessor.relevantForArch(arch)
        );
        if (! filteredSourceProcessors.length) {
          // Wrong architecture! Rewrite this.type and return.  (Note that we
          // haven't written anything else to `this` so far.)
          this.type = 'wrong-arch';
          return;
        }

        this.sourceProcessors = filteredSourceProcessors;
      } else if (!(type === 'extension' && extension === 'js')) {
        // 'extension' and 'filename' classifications need to have at least one
        // SourceProcessor, unless it's the #HardcodeJs special case.
        throw Error(`missing sourceProcessors for ${ type }!`);
      }
    }

    if (type === 'legacy-handler') {
      if (! legacyHandler) {
        throw Error('SourceClassification needs legacyHandler!');
      }
      if (legacyIsTemplate === undefined) {
        throw Error('SourceClassification needs legacyIsTemplate!');
      }
      this.legacyHandler = legacyHandler;
      this.legacyIsTemplate = legacyIsTemplate;
    }

    if (type === 'extension' || type === 'legacy-handler') {
      if (! extension) {
        throw Error('extension SourceClassification needs extension!');
      }
      this.extension = extension;
    }
  }

  isNonLegacySource() {
    return this.type === 'extension' || this.type === 'filename';
  }
}

// This is the base class of the object presented to the user's plugin code.
exports.InputFile = function (resourceSlot) {
};
_.extend(exports.InputFile.prototype, {
  /**
   * @summary Returns the full contents of the file as a buffer.
   * @memberof InputFile
   * @returns {Buffer}
   */
  getContentsAsBuffer: function () {
    throw new Error("Not Implemented");
  },
  /**
   * @summary Returns the name of the package or `null` if the file is not in a
   * package.
   * @memberof InputFile
   * @returns {String}
   */
  getPackageName: function () {
    throw new Error("Not Implemented");
  },
  /**
   * @summary Returns the relative path of file to the package or app root
   * directory. The returned path always uses forward slashes.
   * @memberof InputFile
   * @returns {String}
   */
  getPathInPackage: function () {
    throw new Error("Not Implemented");
  },
  /**
   * @summary Returns a hash string for the file that can be used to implement
   * caching.
   * @memberof InputFile
   * @returns {String}
   */
  getSourceHash: function () {
    throw new Error("Not Implemented");
  },
  /**
   * @summary Returns a string symbol representing the architecture that is
   * targetted by processing this file. Can be used to implement caching.
   * XXX BBP is this doc string good?
   * @memberof InputFile
   * @returns {String}
   */
  getArch: function () {
    throw new Error("Not Implemented");
  },

  /**
   * @summary Returns the full contents of the file as a string.
   * @memberof InputFile
   * @returns {String}
   */
  getContentsAsString: function () {
    var self = this;
    return self.getContentsAsBuffer().toString('utf8');
  },
  /**
   * @summary Returns the filename of the file.
   * @memberof InputFile
   * @returns {String}
   */
  getBasename: function () {
    var self = this;
    return files.pathBasename(self.getPathInPackage());
  },
  /**
   * @summary Returns the directory path relative to the package or app root.
   * The returned path always uses forward slashes.
   * @memberof InputFile
   * @returns {String}
   */
  getDirname: function () {
    var self = this;
    return files.pathDirname(self.getPathInPackage());
  },
  /**
   * @summary Call this method to raise a compilation or linting error for the
   * file.
   * @param {Object} options
   * @param {String} options.message The error message to display.
   * @param {String} [options.sourcePath] The path to display in the error message.
   * @param {Integer} options.line The line number to display in the error message.
   * @param {String} options.func The function name to display in the error message.
   * @memberof InputFile
   */
  error: function (options) {
    var self = this;
    var relPath = self.getPathInPackage();
    buildmessage.error(options.message || ("error building " + relPath), {
      file: options.sourcePath || relPath,
      line: options.line ? options.line : undefined,
      column: options.column ? options.column : undefined,
      func: options.func ? options.func : undefined
    });
  }
});
<|endoftext|>


<commit_before>var pkg = require('./package.json')
var fs  = require('fs')

function minor(a) {
  return [a[0], a[1], Number(a[2]) + 1] }

function feature(a) {
  return [a[0], Number(a[1]) + 1, 0] }

function major(a) {
  return [Number(a[0]) + 1, 0, 0] }

function bump(what, version) {
  return what === 'MAJOR'?    major(version)
  :      what === 'FEATURE'?  feature(version)
  :      /* otherwise */      minor(version) }

pkg.version = bump(process.argv[2], pkg.version.split('.')).join('.')
// fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2))
console.log(pkg.version)
<commit_msg>Fixes bump-version tool<commit_after>var pkg = require('../package.json')
var fs  = require('fs')

function minor(a) {
  return [a[0], a[1], Number(a[2]) + 1] }

function feature(a) {
  return [a[0], Number(a[1]) + 1, 0] }

function major(a) {
  return [Number(a[0]) + 1, 0, 0] }

function bump(what, version) {
  return what === 'MAJOR'?    major(version)
  :      what === 'FEATURE'?  feature(version)
  :      /* otherwise */      minor(version) }

pkg.version = bump(process.argv[2], pkg.version.split('.')).join('.')
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2))
<|endoftext|>