<commit_before>// Copyright Teleportd
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var base = require('./base.js');

/**
 * cache.js
 *
 * a cache implementation for javascript uses LRU as default algorithm to evict
 * elements from the cache when it is full.
 * The cache does not expose a set method for caching value, to cache a value use the
 * get function wich take as a parameter a closure (options.getter) to fetch the value
 *
 * cache.get(key, { getter: getter,
 *                  evict: evict,
 *                  timeout: ... }, cb); // cb(err, value)
 *
 * These are the `getter` params:
 *     @param key to identify the value in the cache
 *     @param cb cb(error,value)
 * Example:
 *  var getter = function(key, cb) {
 *    // retrieves the value as value
 *    cb(null, value);
 *  };
 *
 * The `evict` function takes the value as parameter. Only the evict passed with the
 * getter that has been used to retrieve the value is used at eviction. All subsequent
 * evict passed when retrieving a cached value are *not* called.
 * These are the `evict` params:
 *     @param key the evicted key
 *     @param value the evicted value
 *
 * If a value is not in the cache and there is many conccurent get hits for it,
 * the closure is fired only once. That allows avoinding reddundant calls.
 *
 * The structure of a cache element is the following:
 *     { date: 123456789,      // last access date to this cached element
 *       [value: ...,]         // the cached value
 *       timeout: 123456789,   // date at which to invalidate this cache element
 *       queue: [] }           // the queue of callbacks, empty if already cached
 *
 *
 * @extends {}
 *
 * @param spec {[size] [, interval] [, evict]}
 */
var cache = function(spec, my) {
  my = my || {};
  var _super = {};

  my.size = spec.size || 1000;
  my.interval = spec.interval || 100;
  my.cache = {};
  my.evict = spec.evict || 'LRU';

  my.modes = { LRU: 0,
               MRU: 1,
               RR: 2};

  //public
  var get;                      /* get(key [, options], cb); */
  var invalidate;               /* invalidate(key); */
  var count;                    /* count(); */

  //private
  var runloop;
  var evict = [];

  var that = {};

  /**
   * List of available eviction algorithms. The algorithms used is driven
   * by the current mode: 'LRU', 'MRU', or 'RR'
   * @param count the current cache size
   */
  //LRU (Least Recently Used) algo
  evict[0] = function(count) {
    while(count > my.size ) {
      var min = Date.now();
      var evct;
      for(var s in my.cache) {
        if(my.cache.hasOwnProperty(s)) {
          if(typeof my.cache[s].value !== 'undefined') {
            if(my.cache[s].date < min) {
              min = my.cache[s].date;
              evct = s;
            }
          }
        }
      }
      count--;
      if(typeof evct !== 'undefined') {
        invalidate(evct);
      }
    }
  };

  //MRU (Most Recently Used)
  evict[1] = function(count) {
    while(count > my.size) {
      var max = 0;
      var evct;
      for(var s in my.cache) {
        if(my.cache.hasOwnProperty(s)) {
          if(typeof mycache[s].value !== 'undefined') {
            if(my.cache[s].date > max) {
              max = my.cache[s].date;
              evct = s;
            }
          }
        }
      }
      count--;
      if(typeof evct !== 'undefined')
        invalidate(evct);
    }
  };

  //RR (Random and Replacement)
  evict[2] = function(count) {
    while(count > my.size) {
      var index = Math.floor(count * Math.random());
      var evct;
      for(var s in my.cache) {
        if(my.cache.hasOwnProperty(s)) {
          if(typeof mycache[s].value !== 'undefined') {
            if(count == index)
              evct = s;
          }
        }
      }
      count--;
      if(typeof evct !== 'undefined')
        invalidate(evct);
    }
  };

  /**
   * This is the main cache function that lets user retrieve cached
   * values and set new value in the cache through the getter option.
   * @param key to identify the cached value
   * @param options {getter, timeout}
   *          getter: closure for getting the value to be cached
   *          evict: called when the value is evicted
   *                 (the one passed when getter is used)
   *          timeout: absolute time to invalidate the value
   * @param cb(err, value) the async callback to retrieve the value
   */
  get = function(key, options, cb) {
    if(typeof key !== 'string') return;

    if(typeof my.cache[key] !== 'undefined') {
      if(typeof my.cache[key].value !== 'undefined') {
        my.cache[key].date = Date.now();
        // returns the value
        cb(null, my.cache[key].value);
      }
      else {
        my.cache[key].queue.push(cb);
      }

      // timeout comparison
      if(typeof options.timeout === 'number') {
        var t = Date.now() + options.timeout;
        if(typeof my.cache[key].timeout === 'undefined' ||
           my.cache[key].timeout > t) {
          my.cache[key].timeout = t;
        }
      }

      // we don't update evict here since the value is cached
      // only the evict passed with the getter that has been
      // used is called
    }
    else if(typeof options.getter === 'function') {
      my.cache[key] = { queue: [cb] };

      // timeout setting
      if(typeof options.timeout === 'number') {
        my.cache[key].timeout = Date.now() + options.timeout;
      }
      // evict setting
      if(typeof options.evict === 'function') {
        my.cache[key].evict = options.evict;
      }

      // getter asynchonous call
      options.getter(key, function(err, val) {
        if(!err && typeof val === 'undefined') {
          err = new Error('undefined val returned by getter');
        }

        var queue = my.cache[key].queue;

        if(!err) {
          my.cache[key].date = Date.now();
          my.cache[key].value = val;
          delete my.cache[key].queue;
        }
        else {
          delete my.cache[key];
        }

        queue.forEach(function(cb) {
          cb(err, val);
        });
      });
    }
    else {
      cb();
    }

    var count = that.count();
    if(count > my.size) {
      evict[my.modes[my.evict]](count);
    }
  };

  /**
   * Function for invalidating a value or more from the cache
   * given a key or a regex matching all the keys whose value
   * to be invalidated
   * @param key {string or regex}
   */
  invalidate = function(key) {
    if(typeof key === "string") {
      if(my.cache[key] && typeof my.cache[key].value !== 'undefined') {
        var evct = my.cache[key].evict;
        var value = my.cache[key].value;
        delete my.cache[key];
        if(typeof evct === 'function') {
          evct(key, value);
        }
      }
      return;
    }

    //regex on whole map
    if(typeof key === "object" && key instanceof RegExp) {
      base.forEach(my.cache, function(v, k) {
        if(key.test(k) && typeof my.cache[k].value !== 'undefined') {
          var evct = my.cache[k].evict;
          var value = my.cache[k].value;
          delete my.cache[k];
          if(typeof evct === 'function') {
            evct(k, value);
          }
        }
      });
    }

    if(typeof key === "undefined") {
      base.forEach(my.cache, function(v, k) {
        if(typeof my.cache[k].value !== 'undefined') {
          var evct = my.cache[k].evict;
          var value = my.cache[k].value;
          delete my.cache[k];
          if(typeof evct === 'function') {
            evct(k, value);
          }
        }
      });
    }
  };

  /**
   * Calculates and returns the number of elements
   * @return count the number of elements within the cache.
   */
  count = function() {
    var count = 0;
    for(var s in my.cache) {
      if(my.cache.hasOwnProperty(s)) {
        count ++;
      }
    }
    return count;
  };

  /**
   * Private Function for keeping the cash invalidate expired element at
   * my.interval rate.
   */
  runloop = function() {
    var now = Date.now();
    var expired = [];
    for(var s in my.cache) {
      if(my.cache.hasOwnProperty(s)) {
        if(typeof my.cache[s].timeout === "undefined" ||
           typeof my.cache[s].value === "undefined")
          continue;

        if(now > my.cache[s].timeout) {
          expired.push(s);
        }
      }
    }

    for(var i = 0; i < expired.length; i ++) {
      invalidate(expired[i].key);
    }
  };

  setInterval(runloop, my.interval);

  base.method(that, 'get', get, _super);
  base.method(that, 'invalidate', invalidate, _super);
  base.method(that, 'count', count, _super);

  return that;
}

exports.cache = cache;
<commit_msg>doc fix<commit_after>// Copyright Teleportd
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var base = require('./base.js');

/**
 * cache.js
 *
 * a cache implementation for javascript uses LRU as default algorithm to evict
 * elements from the cache when it is full.
 * The cache does not expose a set method for caching value, to cache a value use the
 * get function wich take as a parameter a closure (options.getter) to fetch the value
 *
 * cache.get(key, { getter: getter,
 *                  evict: evict,
 *                  timeout: 2000 }, cb); // cb(err, value)
 *
 * These are the `getter` params:
 *     @param key to identify the value in the cache
 *     @param cb cb(error,value)
 * Example:
 *  var getter = function(key, cb) {
 *    // retrieves the value as value
 *    cb(null, value);
 *  };
 *
 * The `evict` function takes the value as parameter. Only the evict passed with the
 * getter that has been used to retrieve the value is used at eviction. All subsequent
 * evict passed when retrieving a cached value are *not* called.
 * These are the `evict` params:
 *     @param key the evicted key
 *     @param value the evicted value
 *
 * If a value is not in the cache and there is many conccurent get hits for it,
 * the closure is fired only once. That allows avoinding reddundant calls.
 *
 * The structure of a cache element is the following:
 *     { date: 123456789,      // last access date to this cached element
 *       [value: ...,]         // the cached value
 *       timeout: 123456789,   // date at which to invalidate this cache element
 *       queue: [] }           // the queue of callbacks, empty if already cached
 *
 *
 * @extends {}
 *
 * @param spec {[size] [, interval] [, evict]}
 */
var cache = function(spec, my) {
  my = my || {};
  var _super = {};

  my.size = spec.size || 1000;
  my.interval = spec.interval || 100;
  my.cache = {};
  my.evict = spec.evict || 'LRU';

  my.modes = { LRU: 0,
               MRU: 1,
               RR: 2};

  //public
  var get;                      /* get(key [, options], cb); */
  var invalidate;               /* invalidate(key); */
  var count;                    /* count(); */

  //private
  var runloop;
  var evict = [];

  var that = {};

  /**
   * List of available eviction algorithms. The algorithms used is driven
   * by the current mode: 'LRU', 'MRU', or 'RR'
   * @param count the current cache size
   */
  //LRU (Least Recently Used) algo
  evict[0] = function(count) {
    while(count > my.size ) {
      var min = Date.now();
      var evct;
      for(var s in my.cache) {
        if(my.cache.hasOwnProperty(s)) {
          if(typeof my.cache[s].value !== 'undefined') {
            if(my.cache[s].date < min) {
              min = my.cache[s].date;
              evct = s;
            }
          }
        }
      }
      count--;
      if(typeof evct !== 'undefined') {
        invalidate(evct);
      }
    }
  };

  //MRU (Most Recently Used)
  evict[1] = function(count) {
    while(count > my.size) {
      var max = 0;
      var evct;
      for(var s in my.cache) {
        if(my.cache.hasOwnProperty(s)) {
          if(typeof mycache[s].value !== 'undefined') {
            if(my.cache[s].date > max) {
              max = my.cache[s].date;
              evct = s;
            }
          }
        }
      }
      count--;
      if(typeof evct !== 'undefined')
        invalidate(evct);
    }
  };

  //RR (Random and Replacement)
  evict[2] = function(count) {
    while(count > my.size) {
      var index = Math.floor(count * Math.random());
      var evct;
      for(var s in my.cache) {
        if(my.cache.hasOwnProperty(s)) {
          if(typeof mycache[s].value !== 'undefined') {
            if(count == index)
              evct = s;
          }
        }
      }
      count--;
      if(typeof evct !== 'undefined')
        invalidate(evct);
    }
  };

  /**
   * This is the main cache function that lets user retrieve cached
   * values and set new value in the cache through the getter option.
   * @param key to identify the cached value
   * @param options {getter, evict, timeout}
   *          getter: closure for getting the value to be cached
   *          evict: called when the value is evicted
   *                 (the one passed when getter is used)
   *          timeout: delay before invalidating the value
   * @param cb(err, value) the async callback to retrieve the value
   */
  get = function(key, options, cb) {
    if(typeof key !== 'string') return;

    if(typeof my.cache[key] !== 'undefined') {
      if(typeof my.cache[key].value !== 'undefined') {
        my.cache[key].date = Date.now();
        // returns the value
        cb(null, my.cache[key].value);
      }
      else {
        my.cache[key].queue.push(cb);
      }

      // timeout comparison
      if(typeof options.timeout === 'number') {
        var t = Date.now() + options.timeout;
        if(typeof my.cache[key].timeout === 'undefined' ||
           my.cache[key].timeout > t) {
          my.cache[key].timeout = t;
        }
      }

      // we don't update evict here since the value is cached
      // only the evict passed with the getter that has been
      // used is called
    }
    else if(typeof options.getter === 'function') {
      my.cache[key] = { queue: [cb] };

      // timeout setting
      if(typeof options.timeout === 'number') {
        my.cache[key].timeout = Date.now() + options.timeout;
      }
      // evict setting
      if(typeof options.evict === 'function') {
        my.cache[key].evict = options.evict;
      }

      // getter asynchonous call
      options.getter(key, function(err, val) {
        if(!err && typeof val === 'undefined') {
          err = new Error('undefined val returned by getter');
        }

        var queue = my.cache[key].queue;

        if(!err) {
          my.cache[key].date = Date.now();
          my.cache[key].value = val;
          delete my.cache[key].queue;
        }
        else {
          delete my.cache[key];
        }

        queue.forEach(function(cb) {
          cb(err, val);
        });
      });
    }
    else {
      cb();
    }

    var count = that.count();
    if(count > my.size) {
      evict[my.modes[my.evict]](count);
    }
  };

  /**
   * Function for invalidating a value or more from the cache
   * given a key or a regex matching all the keys whose value
   * to be invalidated
   * @param key {string or regex}
   */
  invalidate = function(key) {
    if(typeof key === "string") {
      if(my.cache[key] && typeof my.cache[key].value !== 'undefined') {
        var evct = my.cache[key].evict;
        var value = my.cache[key].value;
        delete my.cache[key];
        if(typeof evct === 'function') {
          evct(key, value);
        }
      }
      return;
    }

    //regex on whole map
    if(typeof key === "object" && key instanceof RegExp) {
      base.forEach(my.cache, function(v, k) {
        if(key.test(k) && typeof my.cache[k].value !== 'undefined') {
          var evct = my.cache[k].evict;
          var value = my.cache[k].value;
          delete my.cache[k];
          if(typeof evct === 'function') {
            evct(k, value);
          }
        }
      });
    }

    if(typeof key === "undefined") {
      base.forEach(my.cache, function(v, k) {
        if(typeof my.cache[k].value !== 'undefined') {
          var evct = my.cache[k].evict;
          var value = my.cache[k].value;
          delete my.cache[k];
          if(typeof evct === 'function') {
            evct(k, value);
          }
        }
      });
    }
  };

  /**
   * Calculates and returns the number of elements
   * @return count the number of elements within the cache.
   */
  count = function() {
    var count = 0;
    for(var s in my.cache) {
      if(my.cache.hasOwnProperty(s)) {
        count ++;
      }
    }
    return count;
  };

  /**
   * Private Function for keeping the cash invalidate expired element at
   * my.interval rate.
   */
  runloop = function() {
    var now = Date.now();
    var expired = [];
    for(var s in my.cache) {
      if(my.cache.hasOwnProperty(s)) {
        if(typeof my.cache[s].timeout === "undefined" ||
           typeof my.cache[s].value === "undefined")
          continue;

        if(now > my.cache[s].timeout) {
          expired.push(s);
        }
      }
    }

    for(var i = 0; i < expired.length; i ++) {
      invalidate(expired[i].key);
    }
  };

  setInterval(runloop, my.interval);

  base.method(that, 'get', get, _super);
  base.method(that, 'invalidate', invalidate, _super);
  base.method(that, 'count', count, _super);

  return that;
}

exports.cache = cache;
<|endoftext|>


<commit_before>(function () {
    let Encryption = require('Encryption');

    $(document).ready(function () {
        var encryption = new Encryption();

        // Trigger file input on button click
        $('#upload-pdf-file-button-js').on('click', function () {
            //TODO: implement
        });

        // Trigger file input on button click
        $('#create-hash-button-js').on('click', function () {
            //TODO: implement
        });

        // Trigger file input on button click
        $('#generate-keys-button-js').on('click', function () {
            var keyPair = encryption.generateKeyPair();
            alert("Generated keypair :) ");
        });

        $( '' );
    });
})();<commit_msg>little cleanup<commit_after>(function () {
    let Encryption = require('Encryption');

    $(document).ready(function () {
        var encryption = new Encryption();

        $('#upload-pdf-file-button-js').on('click', function () {
            //TODO: implement
        });

        $('#create-hash-button-js').on('click', function () {
            //TODO: implement
        });

        $('#generate-keys-button-js').on('click', function () {
            var keyPair = encryption.generateKeyPair();
            alert("Generated keypair :) ");
        });
    });
})();<|endoftext|>


<commit_before>var Chunk = module.exports = function Chunk() {
  this.data = new Buffer(196864);
  this.data.fill(0);
};

Chunk.prototype.calculate_light = function calculate_light() {
  this.data.fill(0, 98304, 163840);

  var tops = this.initial_light_sky();

  tops.forEach(this.spread_light_sky.apply.bind(this.spread_light_sky, this));
};

Chunk.prototype.initial_light_sky = function initial_light_sky() {
  var tops = [];

  for (var x = 0; x < 16; ++x) {
    for (var z = 0; z < 16; ++z) {
      for (var y = 255; y >= 0 && this.get_block_type(x, z, y) === 0; --y) {
        this.set_light_sky(x, z, y, 15);
      }
      tops.push([x, z, y + 1]);
    }
  }

  return tops;
};

Chunk.prototype.spread_light_sky = function spread_light_sky(x, z, y) {
  var s = this.get_light_sky(x, z, y) - 1;

  if (x >   0) { this.spread_light_sky_apply(x - 1, z,     y,     s); }
  if (x <  15) { this.spread_light_sky_apply(x + 1, z,     y,     s); }
  if (z >   0) { this.spread_light_sky_apply(x,     z - 1, y,     s); }
  if (z <  15) { this.spread_light_sky_apply(x,     z + 1, y,     s); }
  if (y >   0) { this.spread_light_sky_apply(x,     z,     y - 1, s); }
  if (y < 255) { this.spread_light_sky_apply(x,     z,     y + 1, s); }
};

Chunk.prototype.spread_light_sky_apply = function spread_light_sky_apply(x, z, y, s) {
  if (this.get_light_sky(x, z, y) < s) {
    this.set_light_sky(x, z, y, s);
    this.spread_light_sky(x, z, y);
  }
};

Chunk.prototype.get_block_type = function get_block_type(x, z, y) {
  return this.data[x + (z << 4) + (y << 8)];
};

Chunk.prototype.set_block_type = function set_block_type(x, z, y, type) {
  this.data[x + (z << 4) + (y << 8)] = type;

  return this;
};

Chunk.prototype.get_block_meta = function get_block_meta(x, z, y) {
  var index = 65536 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    return this.data[index] >> 4;
  } else {
    return this.data[index] & 0x0f;
  }
};

Chunk.prototype.set_block_meta = function set_block_meta(x, z, y, meta) {
  var index = 65536 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    this.data[index] &= 0x0f;
    this.data[index] |= (meta << 4);
  } else {
    this.data[index] &= 0xf0;
    this.data[index] |= (meta & 0x0f);
  }

  return this;
};

Chunk.prototype.get_light_block = function get_light_block(x, z, y) {
  var index = 98304 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    return this.data[index] >> 4;
  } else {
    return this.data[index] & 0x0f;
  }
};

Chunk.prototype.set_light_block = function set_light_block(x, z, y, light) {
  var index = 98304 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    this.data[index] &= 0x0f;
    this.data[index] |= (light << 4);
  } else {
    this.data[index] &= 0xf0;
    this.data[index] |= (light & 0x0f);
  }

  return this;
};

Chunk.prototype.get_light_sky = function get_light_sky(x, z, y) {
  var index = 131072 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    return this.data[index] >> 4;
  } else {
    return this.data[index] & 0x0f;
  }
};

Chunk.prototype.set_light_sky = function set_light_sky(x, z, y, light) {
  var index = 131072 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    this.data[index] &= 0x0f;
    this.data[index] |= (light << 4);
  } else {
    this.data[index] &= 0xf0;
    this.data[index] |= (light & 0x0f);
  }

  return this;
};

Chunk.prototype.get_additional = function get_additional(x, z, y) {
  var index = 163840 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    return this.data[index] >> 4;
  } else {
    return this.data[index] & 0x0f;
  }
};

Chunk.prototype.set_additional = function set_additional(x, z, y, data) {
  var index = 163840 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    this.data[index] &= 0xf0;
    this.data[index] |= (data & 0x0f);
  } else {
    this.data[index] &= 0x0f;
    this.data[index] |= (data << 4);
  }

  return this;
};

Chunk.prototype.get_biome = function get_biome(x, z, y) {
  return this.data[196608 + x + (z << 4) + (y << 8)];
};

Chunk.prototype.set_biome = function set_biome(x, z, y, biome) {
  this.data[196608 + x + (z << 4) + (y << 8)] = biome;

  return this;
};
<commit_msg>100% more block lighting, 20% less stack overflows<commit_after>var light_block_emit = new Buffer(256),
    light_block_stop = new Buffer(256);

light_block_emit.fill(0);
light_block_stop.fill(15);

light_block_emit[0x0A] = 15;
light_block_emit[0x0B] = 15;
light_block_emit[0x27] = 1;
light_block_emit[0x32] = 14;
light_block_emit[0x33] = 15;
light_block_emit[0x3E] = 14;
light_block_emit[0x4A] = 9;
light_block_emit[0x4C] = 7;
light_block_emit[0x59] = 15;
light_block_emit[0x5A] = 11;
light_block_emit[0x5B] = 15;

light_block_stop[0x00] = 0;
light_block_stop[0x06] = 0;
light_block_stop[0x08] = 2;
light_block_stop[0x09] = 2;
light_block_stop[0x12] = 2;
light_block_stop[0x14] = 0;
light_block_stop[0x25] = 0;
light_block_stop[0x26] = 0;
light_block_stop[0x27] = 0;
light_block_stop[0x28] = 0;
light_block_stop[0x32] = 0;
light_block_stop[0x33] = 0;
light_block_stop[0x34] = 0;
light_block_stop[0x35] = 0;
light_block_stop[0x37] = 0;
light_block_stop[0x40] = 0;
light_block_stop[0x41] = 0;
light_block_stop[0x42] = 0;
light_block_stop[0x43] = 0;
light_block_stop[0x47] = 0;
light_block_stop[0x4b] = 0;
light_block_stop[0x4C] = 0;
light_block_stop[0x4e] = 0;
light_block_stop[0x4f] = 2;
light_block_stop[0x55] = 0;
light_block_stop[0x5A] = 0;
light_block_stop[0x5B] = 0;

var Chunk = module.exports = function Chunk() {
  this.data = new Buffer(196864);
  this.data.fill(0);
};

Chunk.prototype.calculate_light = function calculate_light() {
  this.data.fill(0, 98304, 163840);

  var spread_sky = this.initial_light_sky();
  while (spread_sky.length) {
    var job = spread_sky.shift();
    this.spread_light_sky(job[0], job[1], job[2], spread_sky);
  }

  var spread_block = this.initial_light_block();
  while (spread_block.length) {
    var job = spread_block.shift();
    this.spread_light_block(job[0], job[1], job[2], spread_block);
  }
};

Chunk.prototype.initial_light_sky = function initial_light_sky() {
  var jobs = [];

  for (var x = 0; x < 16; ++x) {
    for (var z = 0; z < 16; ++z) {
      for (var y = 255; y >= 0 && this.get_block_type(x, z, y) === 0; --y) {
        this.set_light_sky(x, z, y, 15);
      }
      jobs.push([x, z, y + 1]);
    }
  }

  return jobs;
};

Chunk.prototype.spread_light_sky = function spread_light_sky(x, z, y, jobs) {
  var s = this.get_light_sky(x, z, y);

  if (x >   0) { this.spread_light_sky_apply(x - 1, z,     y,     s, jobs); }
  if (x <  15) { this.spread_light_sky_apply(x + 1, z,     y,     s, jobs); }
  if (z >   0) { this.spread_light_sky_apply(x,     z - 1, y,     s, jobs); }
  if (z <  15) { this.spread_light_sky_apply(x,     z + 1, y,     s, jobs); }
  if (y >   0) { this.spread_light_sky_apply(x,     z,     y - 1, s, jobs); }
  if (y < 255) { this.spread_light_sky_apply(x,     z,     y + 1, s, jobs); }
};

Chunk.prototype.spread_light_sky_apply = function spread_light_sky_apply(x, z, y, s, jobs) {
  var reduction = light_block_stop[this.get_block_type(x, z, y)],
      result = s - reduction;

  if (this.get_light_sky(x, z, y) < result) {
    this.set_light_sky(x, z, y, result);
    jobs.push([x, z, y]);
  }
};

Chunk.prototype.initial_light_block = function initial_light_block() {
  var jobs = [];

  for (var x = 0; x < 16; ++x) {
    for (var z = 0; z < 16; ++z) {
      for (var y = 0; y < 256; ++y) {
        var light = light_block_emit[this.get_block_type(x, z, y)];
        if (!light) { continue; }
        this.set_light_block(x, z, y, light);
        jobs.push([x, z, y]);
      }
    }
  }

  return jobs;
};

Chunk.prototype.spread_light_block = function spread_light_block(x, z, y, jobs) {
  var s = this.get_light_block(x, z, y) - 1;

  if (x >   0) { this.spread_light_block_apply(x - 1, z,     y,     s, jobs); }
  if (x <  15) { this.spread_light_block_apply(x + 1, z,     y,     s, jobs); }
  if (z >   0) { this.spread_light_block_apply(x,     z - 1, y,     s, jobs); }
  if (z <  15) { this.spread_light_block_apply(x,     z + 1, y,     s, jobs); }
  if (y >   0) { this.spread_light_block_apply(x,     z,     y - 1, s, jobs); }
  if (y < 255) { this.spread_light_block_apply(x,     z,     y + 1, s, jobs); }
};

Chunk.prototype.spread_light_block_apply = function spread_light_block_apply(x, z, y, s, jobs) {
  var reduction = light_block_stop[this.get_block_type(x, z, y)],
      result = s - reduction;

  if (this.get_light_block(x, z, y) < result) {
    this.set_light_block(x, z, y, result);
    jobs.push([x, z, y]);
  }
};

Chunk.prototype.get_block_type = function get_block_type(x, z, y) {
  return this.data[x + (z << 4) + (y << 8)];
};

Chunk.prototype.set_block_type = function set_block_type(x, z, y, type) {
  this.data[x + (z << 4) + (y << 8)] = type;

  return this;
};

Chunk.prototype.get_block_meta = function get_block_meta(x, z, y) {
  var index = 65536 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    return this.data[index] >> 4;
  } else {
    return this.data[index] & 0x0f;
  }
};

Chunk.prototype.set_block_meta = function set_block_meta(x, z, y, meta) {
  var index = 65536 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    this.data[index] &= 0x0f;
    this.data[index] |= (meta << 4);
  } else {
    this.data[index] &= 0xf0;
    this.data[index] |= (meta & 0x0f);
  }

  return this;
};

Chunk.prototype.get_light_block = function get_light_block(x, z, y) {
  var index = 98304 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    return this.data[index] >> 4;
  } else {
    return this.data[index] & 0x0f;
  }
};

Chunk.prototype.set_light_block = function set_light_block(x, z, y, light) {
  var index = 98304 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    this.data[index] &= 0x0f;
    this.data[index] |= (light << 4);
  } else {
    this.data[index] &= 0xf0;
    this.data[index] |= (light & 0x0f);
  }

  return this;
};

Chunk.prototype.get_light_sky = function get_light_sky(x, z, y) {
  var index = 131072 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    return this.data[index] >> 4;
  } else {
    return this.data[index] & 0x0f;
  }
};

Chunk.prototype.set_light_sky = function set_light_sky(x, z, y, light) {
  var index = 131072 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    this.data[index] &= 0x0f;
    this.data[index] |= (light << 4);
  } else {
    this.data[index] &= 0xf0;
    this.data[index] |= (light & 0x0f);
  }

  return this;
};

Chunk.prototype.get_additional = function get_additional(x, z, y) {
  var index = 163840 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    return this.data[index] >> 4;
  } else {
    return this.data[index] & 0x0f;
  }
};

Chunk.prototype.set_additional = function set_additional(x, z, y, data) {
  var index = 163840 + Math.floor((x + (z << 4) + (y << 8)) / 2);

  if (x % 2) {
    this.data[index] &= 0xf0;
    this.data[index] |= (data & 0x0f);
  } else {
    this.data[index] &= 0x0f;
    this.data[index] |= (data << 4);
  }

  return this;
};

Chunk.prototype.get_biome = function get_biome(x, z, y) {
  return this.data[196608 + x + (z << 4) + (y << 8)];
};

Chunk.prototype.set_biome = function set_biome(x, z, y, biome) {
  this.data[196608 + x + (z << 4) + (y << 8)] = biome;

  return this;
};
<|endoftext|>


<commit_before>
module.exports = exports = clean

exports.usage = 'Removes any generated build files and the "out" dir'

/**
 * Module dependencies.
 */

var rm = require('rimraf')
  , glob = require('glob')
  , asyncEmit = require('./util/asyncEmit')
  , createHook = require('./util/hook')
  , targets = []

/**
 * Add the platform-specific targets to remove.
 */

if (process.platform == 'win32') {
  // Remove MSVC project files
  targets.push('Debug')
  targets.push('Release')
  targets.push('*.sln')
  targets.push('*.vcxproj*')
} else {
  // Remove Makefile project files
  targets.push('out')
  targets.push('Makefile.gyp')
  targets.push('*.Makefile')
  targets.push('*.target.gyp.mk')
}
if (process.platform == 'solaris') {
  // Remoge the 'gyp-sun-tool' on Solaris
  targets.push('gyp-sun-tool')
}
if (process.platform == 'darwin') {
  // Remoge the 'gyp-mac-tool' on Darwin
  targets.push('gyp-mac-tool')
}

function clean (gyp, argv, callback) {

  // The list of files to be removed
  var files = []
    , globCount = targets.length
    , counter = 0
    , emitter

  createHook('gyp-clean.js', function (err, _e) {
    if (err) return callback(err)
    emitter = _e
    asyncEmit(emitter, 'before', function (err) {
      if (err) return callback(err)
      doClean()
    })
  })

  function doClean () {
    targets.forEach(function (target) {
      gyp.verbose('globbing', target)

      glob(target, function (err, result) {
        if (err) return callback(err)
        globCount--

        files.push.apply(files, result)
        result.forEach(function (file) {
          counter++
          gyp.verbose('removing', file)

          rm(file, function (err) {
            if (err) return callback(err)
            counter--
            gyp.verbose('removed', file)
            if (counter === 0) {
              gyp.verbose('done removing files', files)
              after()
            }
          })

        })

        if (globCount === 0 && counter === 0) {
          // Nothing to clean!
          gyp.info('nothing to clean')
          after()
        }
      })
    })
  }

  function after () {
    asyncEmit(emitter, 'after', function (err) {
      if (err) return callback(err)
      callback()
    })
  }

}
<commit_msg>Update/simplify the 'clean' command to just remove the "build" directory.<commit_after>
module.exports = exports = clean

exports.usage = 'Removes any generated build files and the "out" dir'

/**
 * Module dependencies.
 */

var rm = require('rimraf')
  , asyncEmit = require('./util/asyncEmit')
  , createHook = require('./util/hook')

function clean (gyp, argv, callback) {

  // Remove the 'build' dir
  var buildDir = 'build'
    , emitter

  createHook('gyp-clean.js', function (err, _e) {
    if (err) return callback(err)
    emitter = _e
    asyncEmit(emitter, 'before', function (err) {
      if (err) return callback(err)
      doClean()
    })
  })

  function doClean () {
    gyp.verbose('removing "build" directory')
    rm(buildDir, after)
  }

  function after () {
    asyncEmit(emitter, 'after', function (err) {
      if (err) return callback(err)
      callback()
    })
  }

}
<|endoftext|>


<commit_before>var munit = global.munit,
	Slice = Array.prototype.slice,
	colors = {
		'bold' : [1, 22],
		'italic' : [3, 23],
		'underline' : [4, 24],
		'inverse' : [7, 27],
		'white' : [37, 39],
		'gray' : [90, 39],
		'black' : [30, 39],
		'blue' : [34, 39],
		'cyan' : [36, 39],
		'green' : [32, 39],
		'magenta' : [35, 39],
		'red' : [31, 39],
		'yellow' : [33, 39]
	};

// Root logger
function color(){
	var args = Slice.call( arguments ), value, message;

	// The first argument belongs to the color code,
	if ( munit.isArray( args[ 0 ] ) ) {
		value = args.shift();
	}

	// Combine args into single message string
	// TODO: use inspection
	message = args.join( ' ' );

	// Print out colored log if passed
	if ( munit.isArray( value ) && process.stdout.isTTY ) {
		return "\033[" + value[ 0 ] + "m" + message + "\033[" + value[ 1 ] + "m";
	}
	else {
		return message;
	}
}

// Create shortcut functions for each color code
color.get = {};
munit.each( colors, function( value, name ) {
	color.get[ name ] = function(){
		var args = Slice.call( arguments );
		args.unshift( value );
		return color.apply( this, args );
	};

	color[ name ] = function(){
		console.log( color.get[ name ].apply( color.get, arguments ) );
	};
});

// Plain output
color.plain = color[ 'default' ] = function(){
	console.log.apply( console.log, Slice.call( arguments ) );
};

// Expose color
color.colors = colors;
munit.color = color;
<commit_msg>-Adding enviorment variable check to force colored output<commit_after>var munit = global.munit,
	Slice = Array.prototype.slice,
	colors = {
		'bold' : [1, 22],
		'italic' : [3, 23],
		'underline' : [4, 24],
		'inverse' : [7, 27],
		'white' : [37, 39],
		'gray' : [90, 39],
		'black' : [30, 39],
		'blue' : [34, 39],
		'cyan' : [36, 39],
		'green' : [32, 39],
		'magenta' : [35, 39],
		'red' : [31, 39],
		'yellow' : [33, 39]
	};

// Root logger
function color(){
	var args = Slice.call( arguments ), value, message;

	// The first argument belongs to the color code,
	if ( munit.isArray( args[ 0 ] ) ) {
		value = args.shift();
	}

	// Combine args into single message string
	// TODO: use inspection
	message = args.join( ' ' );

	// Print out colored log if passed
	if ( munit.isArray( value ) && ( process.stdout.isTTY || process.env.NODE_COLOR_OUTPUT ) ) {
		return "\033[" + value[ 0 ] + "m" + message + "\033[" + value[ 1 ] + "m";
	}
	else {
		return message;
	}
}

// Create shortcut functions for each color code
color.get = {};
munit.each( colors, function( value, name ) {
	color.get[ name ] = function(){
		var args = Slice.call( arguments );
		args.unshift( value );
		return color.apply( this, args );
	};

	color[ name ] = function(){
		console.log( color.get[ name ].apply( color.get, arguments ) );
	};
});

// Plain output
color.plain = color[ 'default' ] = function(){
	console.log.apply( console.log, Slice.call( arguments ) );
};

// Expose color
color.colors = colors;
munit.color = color;
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

declare class StyleSheet {
  disabled: boolean;
  href: string;
  media: MediaList;
  ownerNode: Node;
  parentStyleSheet: ?StyleSheet;
  title: string;
  type: string;
}

declare class StyleSheetList {
  @@iterator(): Iterator<StyleSheet>;
  length: number;
  [index: number]: StyleSheet;
}

declare class MediaList {
  @@iterator(): Iterator<string>;
  mediaText: string;
  length: number;
  item(index: number): ?string;
  deleteMedium(oldMedium: string): void;
  appendMedium(newMedium: string): void;
  [index: number]: string;
}

declare class CSSStyleSheet extends StyleSheet {
  cssRules: CSSRuleList;
  ownerRule: ?CSSRule;
  deleteRule(index: number): void;
  insertRule(rule: string, index: number): void;
}

declare class CSSRule {
  cssText: string;
  parentRule: ?CSSRule;
  parentStyleSheet: ?CSSStyleSheet;
  type: number;
  static STYLE_RULE: number;
  static MEDIA_RULE: number;
  static FONT_FACE_RULE: number;
  static PAGE_RULE: number;
  static IMPORT_RULE: number;
  static CHARSET_RULE: number;
  static UNKNOWN_RULE: number;
  static KEYFRAMES_RULE: number;
  static KEYFRAME_RULE: number;
  static NAMESPACE_RULE: number;
  static COUNTER_STYLE_RULE: number;
  static SUPPORTS_RULE: number;
  static DOCUMENT_RULE: number;
  static FONT_FEATURE_VALUES_RULE: number;
  static VIEWPORT_RULE: number;
  static REGION_STYLE_RULE: number;
}

declare class CSSRuleList {
  @@iterator(): Iterator<CSSRule>;
  length: number;
  item(index: number): ?CSSRule;
  [index: number]: CSSRule;
}

declare class CSSStyleDeclaration {
  @@iterator(): Iterator<string>;
  /* DOM CSS Properties */
  alignContent: string;
  alignItems: string;
  alignSelf: string;
  all: string;
  animation: string;
  animationDelay: string;
  animationDirection: string;
  animationDuration: string;
  animationFillMode: string;
  animationIterationCount: string;
  animationName: string;
  animationPlayState: string;
  animationTimingFunction: string;
  backdropFilter: string;
  webkitBackdropFilter: string;
  backfaceVisibility: string;
  background: string;
  backgroundAttachment: string;
  backgroundBlendMode: string;
  backgroundClip: string;
  backgroundColor: string;
  backgroundImage: string;
  backgroundOrigin: string;
  backgroundPosition: string;
  backgroundPositionX: string;
  backgroundPositionY: string;
  backgroundRepeat: string;
  backgroundSize: string;
  blockSize: string;
  border: string;
  borderBlockEnd: string;
  borderBlockEndColor: string;
  borderBlockEndStyle: string;
  borderBlockEndWidth: string;
  borderBlockStart: string;
  borderBlockStartColor: string;
  borderBlockStartStyle: string;
  borderBlockStartWidth: string;
  borderBottom: string;
  borderBottomColor: string;
  borderBottomLeftRadius: string;
  borderBottomRightRadius: string;
  borderBottomStyle: string;
  borderBottomWidth: string;
  borderCollapse: string;
  borderColor: string;
  borderImage: string;
  borderImageOutset: string;
  borderImageRepeat: string;
  borderImageSlice: string;
  borderImageSource: string;
  borderImageWidth: string;
  borderInlineEnd: string;
  borderInlineEndColor: string;
  borderInlineEndStyle: string;
  borderInlineEndWidth: string;
  borderInlineStart: string;
  borderInlineStartColor: string;
  borderInlineStartStyle: string;
  borderInlineStartWidth: string;
  borderLeft: string;
  borderLeftColor: string;
  borderLeftStyle: string;
  borderLeftWidth: string;
  borderRadius: string;
  borderRight: string;
  borderRightColor: string;
  borderRightStyle: string;
  borderRightWidth: string;
  borderSpacing: string;
  borderStyle: string;
  borderTop: string;
  borderTopColor: string;
  borderTopLeftRadius: string;
  borderTopRightRadius: string;
  borderTopStyle: string;
  borderTopWidth: string;
  borderWidth: string;
  bottom: string;
  boxDecorationBreak: string;
  boxShadow: string;
  boxSizing: string;
  breakAfter: string;
  breakBefore: string;
  breakInside: string;
  captionSide: string;
  clear: string;
  clip: string;
  clipPath: string;
  color: string;
  columns: string;
  columnCount: string;
  columnFill: string;
  columnGap: string;
  columnRule: string;
  columnRuleColor: string;
  columnRuleStyle: string;
  columnRuleWidth: string;
  columnSpan: string;
  columnWidth: string;
  contain: string;
  content: string;
  counterIncrement: string;
  counterReset: string;
  cursor: string;
  direction: string;
  display: string;
  emptyCells: string;
  filter: string;
  flex: string;
  flexBasis: string;
  flexDirection: string;
  flexFlow: string;
  flexGrow: string;
  flexShrink: string;
  flexWrap: string;
  float: string;
  font: string;
  fontFamily: string;
  fontFeatureSettings: string;
  fontKerning: string;
  fontLanguageOverride: string;
  fontSize: string;
  fontSizeAdjust: string;
  fontStretch: string;
  fontStyle: string;
  fontSynthesis: string;
  fontVariant: string;
  fontVariantAlternates: string;
  fontVariantCaps: string;
  fontVariantEastAsian: string;
  fontVariantLigatures: string;
  fontVariantNumeric: string;
  fontVariantPosition: string;
  fontWeight: string;
  grad: string;
  grid: string;
  gridArea: string;
  gridAutoColumns: string;
  gridAutoFlow: string;
  gridAutoPosition: string;
  gridAutoRows: string;
  gridColumn: string;
  gridColumnStart: string;
  gridColumnEnd: string;
  gridRow: string;
  gridRowStart: string;
  gridRowEnd: string;
  gridTemplate: string;
  gridTemplateAreas: string;
  gridTemplateRows: string;
  gridTemplateColumns: string;
  height: string;
  hyphens: string;
  imageRendering: string;
  imageResolution: string;
  imageOrientation: string;
  imeMode: string;
  inherit: string;
  initial: string;
  inlineSize: string;
  isolation: string;
  justifyContent: string;
  left: string;
  letterSpacing: string;
  lineBreak: string;
  lineHeight: string;
  listStyle: string;
  listStyleImage: string;
  listStylePosition: string;
  listStyleType: string;
  margin: string;
  marginBlockEnd: string;
  marginBlockStart: string;
  marginBottom: string;
  marginInlineEnd: string;
  marginInlineStart: string;
  marginLeft: string;
  marginRight: string;
  marginTop: string;
  marks: string;
  mask: string;
  maskType: string;
  maxBlockSize: string;
  maxHeight: string;
  maxInlineSize: string;
  maxWidth: string;
  minBlockSize: string;
  minHeight: string;
  minInlineSize: string;
  minWidth: string;
  mixBlendMode: string;
  mozTransform: string;
  mozTransformOrigin: string;
  mozTransitionDelay: string;
  mozTransitionDuration: string;
  mozTransitionProperty: string;
  mozTransitionTimingFunction: string;
  objectFit: string;
  objectPosition: string;
  offsetBlockEnd: string;
  offsetBlockStart: string;
  offsetInlineEnd: string;
  offsetInlineStart: string;
  opacity: string;
  order: string;
  orphans: string;
  outline: string;
  outlineColor: string;
  outlineOffset: string;
  outlineStyle: string;
  outlineWidth: string;
  overflow: string;
  overflowWrap: string;
  overflowX: string;
  overflowY: string;
  padding: string;
  paddingBlockEnd: string;
  paddingBlockStart: string;
  paddingBottom: string;
  paddingInlineEnd: string;
  paddingInlineStart: string;
  paddingLeft: string;
  paddingRight: string;
  paddingTop: string;
  pageBreakAfter: string;
  pageBreakBefore: string;
  pageBreakInside: string;
  perspective: string;
  perspectiveOrigin: string;
  pointerEvents: string;
  position: string;
  quotes: string;
  rad: string;
  resize: string;
  right: string;
  rubyAlign: string;
  rubyMerge: string;
  rubyPosition: string;
  scrollBehavior: string;
  scrollSnapCoordinate: string;
  scrollSnapDestination: string;
  scrollSnapPointsX: string;
  scrollSnapPointsY: string;
  scrollSnapType: string;
  shapeImageThreshold: string;
  shapeMargin: string;
  shapeOutside: string;
  tableLayout: string;
  tabSize: string;
  textAlign: string;
  textAlignLast: string;
  textCombineUpright: string;
  textDecoration: string;
  textDecorationColor: string;
  textDecorationLine: string;
  textDecorationStyle: string;
  textIndent: string;
  textOrientation: string;
  textOverflow: string;
  textRendering: string;
  textShadow: string;
  textTransform: string;
  textUnderlinePosition: string;
  top: string;
  touchAction: string;
  transform: string;
  transformOrigin: string;
  transformStyle: string;
  transition: string;
  transitionDelay: string;
  transitionDuration: string;
  transitionProperty: string;
  transitionTimingFunction: string;
  turn: string;
  unicodeBidi: string;
  unicodeRange: string;
  verticalAlign: string;
  visibility: string;
  webkitOverflowScrolling: string;
  webkitTransform: string;
  webkitTransformOrigin: string;
  webkitTransitionDelay: string;
  webkitTransitionDuration: string;
  webkitTransitionProperty: string;
  webkitTransitionTimingFunction: string;
  whiteSpace: string;
  widows: string;
  width: string;
  willChange: string;
  wordBreak: string;
  wordSpacing: string;
  wordWrap: string;
  writingMode: string;
  zIndex: string;

  cssFloat: string;
  cssText: string;
  getPropertyPriority(property: string): string;
  getPropertyValue(property:string): string;
  item(index: number): string;
  [index: number]: string;
  length: number;
  parentRule: CSSRule;
  removeProperty(property: string): string;
  setProperty(property: string, value: ?string, priority: ?string): void;
  setPropertyPriority(property: string, priority: string): void;
}

declare class TransitionEvent extends Event {
  elapsedTime: number; // readonly
  pseudoElement: string; // readonly
  propertyName: string; // readonly
}
<commit_msg>[PR] fix(css): userSelect declaration added to CSS declaration<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

declare class StyleSheet {
  disabled: boolean;
  href: string;
  media: MediaList;
  ownerNode: Node;
  parentStyleSheet: ?StyleSheet;
  title: string;
  type: string;
}

declare class StyleSheetList {
  @@iterator(): Iterator<StyleSheet>;
  length: number;
  [index: number]: StyleSheet;
}

declare class MediaList {
  @@iterator(): Iterator<string>;
  mediaText: string;
  length: number;
  item(index: number): ?string;
  deleteMedium(oldMedium: string): void;
  appendMedium(newMedium: string): void;
  [index: number]: string;
}

declare class CSSStyleSheet extends StyleSheet {
  cssRules: CSSRuleList;
  ownerRule: ?CSSRule;
  deleteRule(index: number): void;
  insertRule(rule: string, index: number): void;
}

declare class CSSRule {
  cssText: string;
  parentRule: ?CSSRule;
  parentStyleSheet: ?CSSStyleSheet;
  type: number;
  static STYLE_RULE: number;
  static MEDIA_RULE: number;
  static FONT_FACE_RULE: number;
  static PAGE_RULE: number;
  static IMPORT_RULE: number;
  static CHARSET_RULE: number;
  static UNKNOWN_RULE: number;
  static KEYFRAMES_RULE: number;
  static KEYFRAME_RULE: number;
  static NAMESPACE_RULE: number;
  static COUNTER_STYLE_RULE: number;
  static SUPPORTS_RULE: number;
  static DOCUMENT_RULE: number;
  static FONT_FEATURE_VALUES_RULE: number;
  static VIEWPORT_RULE: number;
  static REGION_STYLE_RULE: number;
}

declare class CSSRuleList {
  @@iterator(): Iterator<CSSRule>;
  length: number;
  item(index: number): ?CSSRule;
  [index: number]: CSSRule;
}

declare class CSSStyleDeclaration {
  @@iterator(): Iterator<string>;
  /* DOM CSS Properties */
  alignContent: string;
  alignItems: string;
  alignSelf: string;
  all: string;
  animation: string;
  animationDelay: string;
  animationDirection: string;
  animationDuration: string;
  animationFillMode: string;
  animationIterationCount: string;
  animationName: string;
  animationPlayState: string;
  animationTimingFunction: string;
  backdropFilter: string;
  webkitBackdropFilter: string;
  backfaceVisibility: string;
  background: string;
  backgroundAttachment: string;
  backgroundBlendMode: string;
  backgroundClip: string;
  backgroundColor: string;
  backgroundImage: string;
  backgroundOrigin: string;
  backgroundPosition: string;
  backgroundPositionX: string;
  backgroundPositionY: string;
  backgroundRepeat: string;
  backgroundSize: string;
  blockSize: string;
  border: string;
  borderBlockEnd: string;
  borderBlockEndColor: string;
  borderBlockEndStyle: string;
  borderBlockEndWidth: string;
  borderBlockStart: string;
  borderBlockStartColor: string;
  borderBlockStartStyle: string;
  borderBlockStartWidth: string;
  borderBottom: string;
  borderBottomColor: string;
  borderBottomLeftRadius: string;
  borderBottomRightRadius: string;
  borderBottomStyle: string;
  borderBottomWidth: string;
  borderCollapse: string;
  borderColor: string;
  borderImage: string;
  borderImageOutset: string;
  borderImageRepeat: string;
  borderImageSlice: string;
  borderImageSource: string;
  borderImageWidth: string;
  borderInlineEnd: string;
  borderInlineEndColor: string;
  borderInlineEndStyle: string;
  borderInlineEndWidth: string;
  borderInlineStart: string;
  borderInlineStartColor: string;
  borderInlineStartStyle: string;
  borderInlineStartWidth: string;
  borderLeft: string;
  borderLeftColor: string;
  borderLeftStyle: string;
  borderLeftWidth: string;
  borderRadius: string;
  borderRight: string;
  borderRightColor: string;
  borderRightStyle: string;
  borderRightWidth: string;
  borderSpacing: string;
  borderStyle: string;
  borderTop: string;
  borderTopColor: string;
  borderTopLeftRadius: string;
  borderTopRightRadius: string;
  borderTopStyle: string;
  borderTopWidth: string;
  borderWidth: string;
  bottom: string;
  boxDecorationBreak: string;
  boxShadow: string;
  boxSizing: string;
  breakAfter: string;
  breakBefore: string;
  breakInside: string;
  captionSide: string;
  clear: string;
  clip: string;
  clipPath: string;
  color: string;
  columns: string;
  columnCount: string;
  columnFill: string;
  columnGap: string;
  columnRule: string;
  columnRuleColor: string;
  columnRuleStyle: string;
  columnRuleWidth: string;
  columnSpan: string;
  columnWidth: string;
  contain: string;
  content: string;
  counterIncrement: string;
  counterReset: string;
  cursor: string;
  direction: string;
  display: string;
  emptyCells: string;
  filter: string;
  flex: string;
  flexBasis: string;
  flexDirection: string;
  flexFlow: string;
  flexGrow: string;
  flexShrink: string;
  flexWrap: string;
  float: string;
  font: string;
  fontFamily: string;
  fontFeatureSettings: string;
  fontKerning: string;
  fontLanguageOverride: string;
  fontSize: string;
  fontSizeAdjust: string;
  fontStretch: string;
  fontStyle: string;
  fontSynthesis: string;
  fontVariant: string;
  fontVariantAlternates: string;
  fontVariantCaps: string;
  fontVariantEastAsian: string;
  fontVariantLigatures: string;
  fontVariantNumeric: string;
  fontVariantPosition: string;
  fontWeight: string;
  grad: string;
  grid: string;
  gridArea: string;
  gridAutoColumns: string;
  gridAutoFlow: string;
  gridAutoPosition: string;
  gridAutoRows: string;
  gridColumn: string;
  gridColumnStart: string;
  gridColumnEnd: string;
  gridRow: string;
  gridRowStart: string;
  gridRowEnd: string;
  gridTemplate: string;
  gridTemplateAreas: string;
  gridTemplateRows: string;
  gridTemplateColumns: string;
  height: string;
  hyphens: string;
  imageRendering: string;
  imageResolution: string;
  imageOrientation: string;
  imeMode: string;
  inherit: string;
  initial: string;
  inlineSize: string;
  isolation: string;
  justifyContent: string;
  left: string;
  letterSpacing: string;
  lineBreak: string;
  lineHeight: string;
  listStyle: string;
  listStyleImage: string;
  listStylePosition: string;
  listStyleType: string;
  margin: string;
  marginBlockEnd: string;
  marginBlockStart: string;
  marginBottom: string;
  marginInlineEnd: string;
  marginInlineStart: string;
  marginLeft: string;
  marginRight: string;
  marginTop: string;
  marks: string;
  mask: string;
  maskType: string;
  maxBlockSize: string;
  maxHeight: string;
  maxInlineSize: string;
  maxWidth: string;
  minBlockSize: string;
  minHeight: string;
  minInlineSize: string;
  minWidth: string;
  mixBlendMode: string;
  mozTransform: string;
  mozTransformOrigin: string;
  mozTransitionDelay: string;
  mozTransitionDuration: string;
  mozTransitionProperty: string;
  mozTransitionTimingFunction: string;
  objectFit: string;
  objectPosition: string;
  offsetBlockEnd: string;
  offsetBlockStart: string;
  offsetInlineEnd: string;
  offsetInlineStart: string;
  opacity: string;
  order: string;
  orphans: string;
  outline: string;
  outlineColor: string;
  outlineOffset: string;
  outlineStyle: string;
  outlineWidth: string;
  overflow: string;
  overflowWrap: string;
  overflowX: string;
  overflowY: string;
  padding: string;
  paddingBlockEnd: string;
  paddingBlockStart: string;
  paddingBottom: string;
  paddingInlineEnd: string;
  paddingInlineStart: string;
  paddingLeft: string;
  paddingRight: string;
  paddingTop: string;
  pageBreakAfter: string;
  pageBreakBefore: string;
  pageBreakInside: string;
  perspective: string;
  perspectiveOrigin: string;
  pointerEvents: string;
  position: string;
  quotes: string;
  rad: string;
  resize: string;
  right: string;
  rubyAlign: string;
  rubyMerge: string;
  rubyPosition: string;
  scrollBehavior: string;
  scrollSnapCoordinate: string;
  scrollSnapDestination: string;
  scrollSnapPointsX: string;
  scrollSnapPointsY: string;
  scrollSnapType: string;
  shapeImageThreshold: string;
  shapeMargin: string;
  shapeOutside: string;
  tableLayout: string;
  tabSize: string;
  textAlign: string;
  textAlignLast: string;
  textCombineUpright: string;
  textDecoration: string;
  textDecorationColor: string;
  textDecorationLine: string;
  textDecorationStyle: string;
  textIndent: string;
  textOrientation: string;
  textOverflow: string;
  textRendering: string;
  textShadow: string;
  textTransform: string;
  textUnderlinePosition: string;
  top: string;
  touchAction: string;
  transform: string;
  transformOrigin: string;
  transformStyle: string;
  transition: string;
  transitionDelay: string;
  transitionDuration: string;
  transitionProperty: string;
  transitionTimingFunction: string;
  turn: string;
  unicodeBidi: string;
  unicodeRange: string;
  userSelect: string;
  verticalAlign: string;
  visibility: string;
  webkitOverflowScrolling: string;
  webkitTransform: string;
  webkitTransformOrigin: string;
  webkitTransitionDelay: string;
  webkitTransitionDuration: string;
  webkitTransitionProperty: string;
  webkitTransitionTimingFunction: string;
  whiteSpace: string;
  widows: string;
  width: string;
  willChange: string;
  wordBreak: string;
  wordSpacing: string;
  wordWrap: string;
  writingMode: string;
  zIndex: string;

  cssFloat: string;
  cssText: string;
  getPropertyPriority(property: string): string;
  getPropertyValue(property:string): string;
  item(index: number): string;
  [index: number]: string;
  length: number;
  parentRule: CSSRule;
  removeProperty(property: string): string;
  setProperty(property: string, value: ?string, priority: ?string): void;
  setPropertyPriority(property: string, priority: string): void;
}

declare class TransitionEvent extends Event {
  elapsedTime: number; // readonly
  pseudoElement: string; // readonly
  propertyName: string; // readonly
}
<|endoftext|>


<commit_before>
import React, { Component, PropTypes } from 'react';
import { StyleSheet, Text, TouchableOpacity, View, ListView } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import MaterialDialog from './MaterialDialog';

import colors from './colors';

export default class MultiPickerMaterialDialog extends Component {

  constructor(props) {
    super(props);

    const { items, selectedItems } = props;
    const rows = buildSelectedRows(items, selectedItems);

    const dataSource = new ListView.DataSource({
      rowHasChanged: (r1, r2) => r1.value !== r2.value || r1.selected !== r2.selected,
    }).cloneWithRows(rows);

    this.state = {
      dataSource,
      rows,
    };
  }

  // Refreshing the dataSource when we refresh any prop (such as visible)
  componentWillReceiveProps(nextProps) {
    const { items, selectedItems } = nextProps;
    const rows = buildSelectedRows(items, selectedItems);
    const dataSource = this
      .state
      .dataSource
      .cloneWithRows(rows);
    this.setState({ dataSource, rows });
  }

  onRowPress(rowID) {
    const rows = [...this.state.rows];
    rows[rowID] = Object.assign({}, rows[rowID], {
      selected: !rows[rowID].selected,
    });
    const dataSource = this
      .state
      .dataSource
      .cloneWithRows(rows);
    this.setState({ dataSource, rows });
  }

  renderRow = (row, sectionID, rowID) => (
    <TouchableOpacity key={row.value} onPress={() => this.onRowPress(rowID)}>
      <View
        style={styles.rowContainer}>
        <View style={styles.iconContainer}>
          <Icon
            name={row.selected
            ? 'check-box'
            : 'check-box-outline-blank'}
            color={this.props.colorAccent}
            size={24} />
        </View>
        <Text
          style={styles.rowText}>{row.label}</Text>
      </View>
    </TouchableOpacity>
    );

  render() {
    return (
      <MaterialDialog
        title={this.props.title}
        titleColor={this.props.titleColor}
        colorAccent={this.props.colorAccent}
        visible={this.props.visible}
        okLabel={this.props.okLabel}
        scrolled={this.props.scrolled}
        onOk={() => this.props.onOk({
          selectedItems: this
          .state
          .rows
          .filter(row => row.selected),
        })}
        cancelLabel={this.props.cancelLabel}
        onCancel={() => {
          this
          .props
          .onCancel();
        }}>
        <ListView dataSource={this.state.dataSource} renderRow={this.renderRow} />
      </MaterialDialog>
    );
  }
}

function buildSelectedRows(items, selectedItems) {
  const rows = items.map(item => Object.assign({}, item, {
    selected: selectedItems.some(i => i.value === item.value),
  }));

  return rows;
}

const styles = StyleSheet.create({
  rowContainer: {
    height: 56,
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'flex-start',
    alignItems: 'center',
  },
  iconContainer:
  {
    marginRight: 16,
  },
  rowText:
  {
    fontFamily: 'sans-serif',
    color: colors.androidPrimaryTextColor,
    fontSize: 16,
  },
});

MultiPickerMaterialDialog.propTypes = {
  visible: PropTypes.bool.isRequired,
  items: PropTypes.arrayOf(PropTypes.object).isRequired,
  selectedItems: PropTypes.arrayOf(PropTypes.object),
  title: PropTypes.string.isRequired,
  titleColor: PropTypes.string,
  colorAccent: PropTypes.string,
  onCancel: PropTypes.func.isRequired,
  onOk: PropTypes.func.isRequired,
  cancelLabel: PropTypes.string,
  okLabel: PropTypes.string,
  scrolled: PropTypes.bool,
};

MultiPickerMaterialDialog.defaultProps = {
  selectedItems: [],
  titleColor: undefined,
  colorAccent: colors.androidColorAccent,
  cancelLabel: undefined,
  okLabel: undefined,
  scrolled: false,
};
<commit_msg>removed blank line<commit_after>import React, { Component, PropTypes } from 'react';
import { StyleSheet, Text, TouchableOpacity, View, ListView } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import MaterialDialog from './MaterialDialog';

import colors from './colors';

export default class MultiPickerMaterialDialog extends Component {

  constructor(props) {
    super(props);

    const { items, selectedItems } = props;
    const rows = buildSelectedRows(items, selectedItems);

    const dataSource = new ListView.DataSource({
      rowHasChanged: (r1, r2) => r1.value !== r2.value || r1.selected !== r2.selected,
    }).cloneWithRows(rows);

    this.state = {
      dataSource,
      rows,
    };
  }

  // Refreshing the dataSource when we refresh any prop (such as visible)
  componentWillReceiveProps(nextProps) {
    const { items, selectedItems } = nextProps;
    const rows = buildSelectedRows(items, selectedItems);
    const dataSource = this
      .state
      .dataSource
      .cloneWithRows(rows);
    this.setState({ dataSource, rows });
  }

  onRowPress(rowID) {
    const rows = [...this.state.rows];
    rows[rowID] = Object.assign({}, rows[rowID], {
      selected: !rows[rowID].selected,
    });
    const dataSource = this
      .state
      .dataSource
      .cloneWithRows(rows);
    this.setState({ dataSource, rows });
  }

  renderRow = (row, sectionID, rowID) => (
    <TouchableOpacity key={row.value} onPress={() => this.onRowPress(rowID)}>
      <View
        style={styles.rowContainer}>
        <View style={styles.iconContainer}>
          <Icon
            name={row.selected
            ? 'check-box'
            : 'check-box-outline-blank'}
            color={this.props.colorAccent}
            size={24} />
        </View>
        <Text
          style={styles.rowText}>{row.label}</Text>
      </View>
    </TouchableOpacity>
    );

  render() {
    return (
      <MaterialDialog
        title={this.props.title}
        titleColor={this.props.titleColor}
        colorAccent={this.props.colorAccent}
        visible={this.props.visible}
        okLabel={this.props.okLabel}
        scrolled={this.props.scrolled}
        onOk={() => this.props.onOk({
          selectedItems: this
          .state
          .rows
          .filter(row => row.selected),
        })}
        cancelLabel={this.props.cancelLabel}
        onCancel={() => {
          this
          .props
          .onCancel();
        }}>
        <ListView dataSource={this.state.dataSource} renderRow={this.renderRow} />
      </MaterialDialog>
    );
  }
}

function buildSelectedRows(items, selectedItems) {
  const rows = items.map(item => Object.assign({}, item, {
    selected: selectedItems.some(i => i.value === item.value),
  }));

  return rows;
}

const styles = StyleSheet.create({
  rowContainer: {
    height: 56,
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'flex-start',
    alignItems: 'center',
  },
  iconContainer:
  {
    marginRight: 16,
  },
  rowText:
  {
    fontFamily: 'sans-serif',
    color: colors.androidPrimaryTextColor,
    fontSize: 16,
  },
});

MultiPickerMaterialDialog.propTypes = {
  visible: PropTypes.bool.isRequired,
  items: PropTypes.arrayOf(PropTypes.object).isRequired,
  selectedItems: PropTypes.arrayOf(PropTypes.object),
  title: PropTypes.string.isRequired,
  titleColor: PropTypes.string,
  colorAccent: PropTypes.string,
  onCancel: PropTypes.func.isRequired,
  onOk: PropTypes.func.isRequired,
  cancelLabel: PropTypes.string,
  okLabel: PropTypes.string,
  scrolled: PropTypes.bool,
};

MultiPickerMaterialDialog.defaultProps = {
  selectedItems: [],
  titleColor: undefined,
  colorAccent: colors.androidColorAccent,
  cancelLabel: undefined,
  okLabel: undefined,
  scrolled: false,
};
<|endoftext|>


<commit_before>/*
 *  Test illustrating GH-1684 and GH-1726.
 *
 *  Run with debugger attached, and:
 *
 *  - StepOut from test1 and test2.
 *
 *  - StepOver the 'return' statement in test1 and test2.
 *
 *  - StepInto anotherFunction in test1 and test2.
 */

/*===
entered test1
entered anotherFunction
entered test2
entered anotherFunction
done
===*/

function anotherFunction() {
    var ret;
    print('entered anotherFunction');
    ret = 'foo' + 123;
    return ret;
}

function test1() {
    print('entered test1');
    return anotherFunction();
}

function test2() {
    var ret;

    print('entered test2');
    ret = anotherFunction();
    return ret;
}

try {
    test1();
    test2();
} catch (e) {
    print(e.stack || e);
}

print('done');
<commit_msg>Add nested tailcall to debugger step test<commit_after>/*
 *  Test illustrating GH-1684, GH-1726, GH1786.
 */

/*===
entered test1
entered anotherFunction
entered test2
entered anotherFunction
===*/

/*
 *  Run with debugger attached, and:
 *
 *  - StepOut from test1 and test2.
 *
 *  - StepOver the 'return' statement in test1 and test2.
 *
 *  - StepInto anotherFunction in test1 and test2.
 */

function anotherFunction() {
    var ret;
    print('entered anotherFunction');
    ret = 'foo' + 123;
    return ret;
}

function test1() {
    print('entered test1');
    return anotherFunction();
}

function test2() {
    var ret;

    print('entered test2');
    ret = anotherFunction();
    return ret;
}

try {
    test1();
    test2();
} catch (e) {
    print(e.stack || e);
}

/*===
before bar
after bar
===*/

/*
 *  Nested case.  The tailcall in a nested call (not occurring in the
 *  function where stepping starts) shouldn't affect line pausing.
 */

function foo() {
    return 1;
}
function bar() {
    return foo();
}
function test() {
    print('before bar');
    bar();  // step over this
    print('after bar');
}

try {
    test();
} catch (e) {
    print(e.stack || e);
}

/*===
done
===*/

print('done');
<|endoftext|>


<commit_before>var _ = require('underscore'),
	keystone = require('../'),
	fs = require('fs'),
	util = require('util'),
	path = require('path'),
	async = require('async'),
	moment = require('moment'),
	utils = require('keystone-utils'),
	mandrillapi = require('mandrill-api');

var templateCache = {};

var defaultConfig = {
	templateExt: 'jade',
	templateEngine: require('jade'),
	templateBasePath: path.normalize(path.join(__dirname, '..', 'templates', 'helpers', 'emails')),
	mandrill: {
		track_opens: true,
		track_clicks: true,
		preserve_recipients: false,
		inline_css: true
	}
};

/** Custom Errors */

var ErrorNoEmailTemplateName = function() {
 	Error.apply(this, arguments);
	Error.captureStackTrace(this, arguments.callee);
	this.message = 'No email templateName specified.';
	this.name = 'ErrorNoEmailTemplateName';
};
util.inherits(ErrorNoEmailTemplateName, Error);

var ErrorEmailsPathNotSet = function() {
	Error.apply(this, arguments);
	Error.captureStackTrace(this, arguments.callee);
	this.message = 'Keystone has not been configured for email support. Set the `emails` option in your configuration.';
	this.name = 'ErrorEmailsPathNotSet';
};
util.inherits(ErrorEmailsPathNotSet, Error);

var ErrorEmailOptionsRequired = function() {
	Error.apply(this, arguments);
	Error.captureStackTrace(this, arguments.callee);
	this.message = 'The keystone.Email class requires a templateName or options argument to be provided.';
	this.name = 'ErrorEmailOptionsRequired';
};
util.inherits(ErrorEmailsPathNotSet, Error);

/** Helper methods */

var getEmailsPath = function() {
	var path = keystone.getPath('emails');
	if (path) {
		return path;
	}
	throw new ErrorEmailsPathNotSet();
};

/**
 * Email Class
 * ===========
 *
 * Helper class for sending emails with Mandrill.
 *
 * New instances take a `templatePath` string which must be a folder in the
 * emails path, and must contain either `templateName/email.templateExt` or `templateName.templateExt`
 * which is used as the template for the HTML part of the email.
 *
 * Once created, emails can be rendered or sent.
 *
 * Requires the `emails` path option and the `mandrill api key` option to be
 * set on Keystone.
 *
 * @api public
 */

var Email = function(options) {

	// Passing a string will use Email.defaults for everything but template name
	if ('string' == typeof(options)) {
		options = {
			templateName: options,
		};
	} else if (!utils.isObject(options)) {
		throw new ErrorEmailOptionsRequired();
	}

	this.templateName = options.templateName;
	this.templateExt = options.templateExt || Email.defaults.templateExt;
	this.templateEngine = options.templateEngine || Email.defaults.templateEngine;
	this.templateBasePath = options.templateBasePath || Email.defaults.templateBasePath;

	if (!this.templateName) {
		throw new ErrorNoEmailtemplateName();
	}

	return this;

};

/**
 * Renders the email and passes it to the callback. Used by `email.send()` but
 * can also be called directly to generate a preview.
 *
 * @param {Object} locals - object of local variables provided to the template
 * @param {Function} callback(err, email)
 *
 * @api public
 */

Email.prototype.render = function(locals, callback) {

	if ('function' === typeof locals && !callback) {
		callback = locals;
		locals = {};
	}

	locals = ('object' === typeof locals) ? locals : {};
	callback = ('function' === typeof callback) ? callback : function() {};

	if (keystone.get('email locals')) {
		_.defaults(locals, keystone.get('email locals'));
	}

	_.defaults(locals, {
		pretty: true,
		_: _,
		moment: moment,
		utils: utils,
		subject: '(no subject)',
		brand: keystone.get('brand'),
		theme: {},
		css: templateCSSMethods
	});

	if (!locals.theme.buttons) {
		locals.theme.buttons = {};
	}

	this.compileTemplate(function(err) {

		if (err) {
			return callback(err);
		}

		var html = templateCache[this.templateName](locals);

		// ensure extended characters are replaced
		html = html.replace(/[\u007f-\uffff]/g, function(c) {
			return '&#x'+('0000'+c.charCodeAt(0).toString(16)).slice(-4)+';';
		});

		// process email rules
		var rules = keystone.get('email rules');

		if (rules) {

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

			_.each(rules, function(rule) {
				if (rule.find && rule.replace) {

					var find = rule.find,
						replace = rule.replace;

					if ('string' === typeof find) {
						find = new RegExp(find, 'gi');
					}

					html = html.replace(find, replace);
				}
			});

		}

		callback(null, {
			subject: locals.subject,
			html: html
		});

	}.bind(this));

};

/**
 * Loads the template. Looks for `templateName.templateExt`, followed by `templateName/email.templateExt`
 *
 * @param {Function} callback(err)
 *
 * @api private
 */

Email.prototype.loadTemplate = function(callback) {

	var fsTemplatePath = path.join(Email.getEmailsPath(), this.templateName + '.' + this.templateExt);

	fs.readFile(fsTemplatePath, function(err, contents) {

		if (err) {
			if (err.code === 'ENOENT') {

				fsTemplatePath = path.join(Email.getEmailsPath(), this.templateName, 'email.' + this.templateExt);

				fs.readFile(fsTemplatePath, function(err, contents) {
					callback(err, fsTemplatePath, contents);
				});

			} else {
				return callback(err);
			}
		} else {
			return callback(err, fsTemplatePath, contents);
		}

	}.bind(this));

};

/**
 * Ensures the template for the email has been compiled
 *
 * @param {Function} callback(err)
 *
 * @api private
 */

Email.prototype.compileTemplate = function(callback) {

	if (keystone.get('env') === 'production' && templateCache[this.templateName]) {
		return process.nextTick(callback);
	}

	this.loadTemplate(function(err, filename, contents) {

		if (err) return callback(err);

		var template = this.templateEngine.compile(contents.toString(), Email.defaults.compilerOptions || { filename: fs.realpathSync(filename), basedir: this.templateBasePath });

		templateCache[this.templateName] = template;

		callback();

	}.bind(this));

};

/**
 * Prepares the email and sends it
 *
 * Options:
 *
 * - mandrill
 *   Initialised Mandrill API instance
 *
 * - tags
 *   Array of tags to send to Mandrill
 *
 * - to
 *   Object / String or Array of Objects / Strings to send to, e.g.
 *   ['jed@team9.com.au', { email: 'jed.watson@gmail.com' }]
 *   { email: 'jed@team9.com.au' }
 *   'jed@team9.com.au'
 *
 * - fromName
 *   Name to send from
 *
 * - fromEmail
 *   Email address to send from
 *
 * For compatibility with older implementations, send supports providing
 * locals and options objects as the first and second arguments, and the
 * callback as the third.
 *
 * @param {Object} options (passed to `email.render()`)
 * @param {Function} callback(err, info)
 *
 * @api private
 */

Email.prototype.send = function(options, callback) {

	var locals = options;

	if (arguments.length === 3 || !utils.isFunction(callback)) {
		callback = arguments[2];
		options = arguments[1] || arguments[0];
	}

	this.render(locals, function(err, email) {

		callback = ('function' === typeof callback) ? callback : function() {};

		if (err) {
			return callback(err);
		}

		if (!utils.isObject(options)) {
			return callback({
				from: 'Email.send',
				key: 'invalid options',
				message: 'options object is required'
			});
		}

		if ('string' === typeof options.from) {
			options.fromName = options.from;
			options.fromEmail = options.from;
		} else if (utils.isObject(options.from)) {
			options.fromName = utils.isObject(options.from.name) ? options.from.name.full : options.from.name;
			options.fromEmail = options.from.email;
		}

		if (!options.fromName || !options.fromEmail) {
			return callback({
				from: 'Email.send',
				key: 'invalid options',
				message: 'options.fromName and options.fromEmail are required'
			});
		}

		if (!options.mandrill) {
			if (!keystone.get('mandrill api key'))
				return callback({
					from: 'Email.send',
					key: 'missing api key',
					message: 'You must either provide a Mandrill API Instance or set the mandrill api key before sending email.'
				});
			options.mandrill = new mandrillapi.Mandrill(keystone.get('mandrill api key'));
		}

		options.tags = utils.isArray(options.tags) ? options.tags : [];
		options.tags.push('sent:' + moment().format('YYYY-MM-DD'));
		options.tags.push(this.templateName);

		if (keystone.get('env') == 'development') {
			options.tags.push('development');
		}

		var recipients = [],
			mergeVars = [];

		options.to = Array.isArray(options.to) ? options.to : [options.to];

		for (var i = 0; i < options.to.length; i++) {

			if ('string' === typeof options.to[i]) {
				options.to[i] = { email: options.to[i] };
			} else if ('object' === typeof options.to[i]) {
				if (!options.to[i].email) {
					return callback({
						from: 'Email.send',
						key: 'invalid recipient',
						message: 'Recipient ' + (i + 1) + ' does not have a valid email address.'
					});
				}
			} else {
				return callback({
					from: 'Email.send',
					key: 'invalid recipient',
					message: 'Recipient ' + (i + 1) + ' is not a string or an object.'
				});
			}

			var recipient = { email: options.to[i].email },
				vars = [{ name: 'email', content: recipient.email }];

			if ('string' === typeof options.to[i].name) {
				recipient.name = options.to[i].name;
				vars.push({ name: 'name', content: options.to[i].name });
			} else if ('object' === typeof options.to[i].name) {
				recipient.name = options.to[i].name.full || '';
				vars.push({ name: 'name', content: options.to[i].name.full || '' });
				vars.push({ name: 'first_name', content: options.to[i].name.first || '' });
				vars.push({ name: 'last_name', content: options.to[i].name.last || '' });
			}

			recipients.push(recipient);

			mergeVars.push({
				rcpt: recipient.email,
				vars: vars
			});
		}

		var onSuccess = function(info) {
			callback(null, info);
		};

		var onFail = function(info) {
			callback({
				from: 'Email.send',
				key: 'send error',
				message: 'Mandrill encountered an error and did not send the emails.',
				info: info
			});
		};

		var message = {
			html: email.html,
			subject: email.subject,
			from_name: options.fromName,
			from_email: options.fromEmail,
			tags: options.tags,
			attachments: options.attachments,
			to: recipients,
			merge_vars: mergeVars,
			async: true
		};

		_.defaults(message, options.mandrillOptions);
		_.defaults(message, Email.defaults.mandrill);

		return process.nextTick(function() {
			options.mandrill.messages.send({ message: message }, onSuccess, onFail);
		});

	}.bind(this));

};

var templateCSSMethods = {
	shadeColor: function(color, percent) {
    	var num = parseInt(color.slice(1),16), amt = Math.round(2.55 * percent), R = (num >> 16) + amt, G = (num >> 8 & 0x00FF) + amt, B = (num & 0x0000FF) + amt;
    	return "#" + (0x1000000 + (R<255?R<1?0:R:255)*0x10000 + (G<255?G<1?0:G:255)*0x100 + (B<255?B<1?0:B:255)).toString(16).slice(1);
	}
};

Email.getEmailsPath = getEmailsPath;
Email.templateCache = templateCache;
Email.templateCSSMethods = templateCSSMethods;
Email.defaults = defaultConfig;

exports = module.exports = Email;
<commit_msg>Improved email.js based on linter<commit_after>var _ = require('underscore'),
	keystone = require('../'),
	fs = require('fs'),
	util = require('util'),
	path = require('path'),
	moment = require('moment'),
	utils = require('keystone-utils'),
	mandrillapi = require('mandrill-api');

var templateCache = {};

var defaultConfig = {
	templateExt: 'jade',
	templateEngine: require('jade'),
	templateBasePath: path.normalize(path.join(__dirname, '..', 'templates', 'helpers', 'emails')),
	mandrill: {
		track_opens: true,
		track_clicks: true,
		preserve_recipients: false,
		inline_css: true
	}
};

/** Custom Errors */

var ErrorNoEmailTemplateName = function() {
 	Error.apply(this, arguments);
	Error.captureStackTrace(this, arguments.callee);
	this.message = 'No email templateName specified.';
	this.name = 'ErrorNoEmailTemplateName';
};
util.inherits(ErrorNoEmailTemplateName, Error);

var ErrorEmailsPathNotSet = function() {
	Error.apply(this, arguments);
	Error.captureStackTrace(this, arguments.callee);
	this.message = 'Keystone has not been configured for email support. Set the `emails` option in your configuration.';
	this.name = 'ErrorEmailsPathNotSet';
};
util.inherits(ErrorEmailsPathNotSet, Error);

var ErrorEmailOptionsRequired = function() {
	Error.apply(this, arguments);
	Error.captureStackTrace(this, arguments.callee);
	this.message = 'The keystone.Email class requires a templateName or options argument to be provided.';
	this.name = 'ErrorEmailOptionsRequired';
};
util.inherits(ErrorEmailsPathNotSet, Error);

/** Helper methods */

var getEmailsPath = function() {
	var path = keystone.getPath('emails');
	if (path) {
		return path;
	}
	throw new ErrorEmailsPathNotSet();
};

/** CSS Helper methods */

var templateCSSMethods = {
	shadeColor: function(color, percent) {
    	var num = parseInt(color.slice(1),16), amt = Math.round(2.55 * percent), R = (num >> 16) + amt, G = (num >> 8 & 0x00FF) + amt, B = (num & 0x0000FF) + amt;
    	return '#' + (0x1000000 + (R<255?R<1?0:R:255)*0x10000 + (G<255?G<1?0:G:255)*0x100 + (B<255?B<1?0:B:255)).toString(16).slice(1);
	}
};

/**
 * Email Class
 * ===========
 *
 * Helper class for sending emails with Mandrill.
 *
 * New instances take a `templatePath` string which must be a folder in the
 * emails path, and must contain either `templateName/email.templateExt` or `templateName.templateExt`
 * which is used as the template for the HTML part of the email.
 *
 * Once created, emails can be rendered or sent.
 *
 * Requires the `emails` path option and the `mandrill api key` option to be
 * set on Keystone.
 *
 * @api public
 */

var Email = function(options) {

	// Passing a string will use Email.defaults for everything but template name
	if ('string' === typeof(options)) {
		options = {
			templateName: options
		};
	} else if (!utils.isObject(options)) {
		throw new ErrorEmailOptionsRequired();
	}

	this.templateName = options.templateName;
	this.templateExt = options.templateExt || Email.defaults.templateExt;
	this.templateEngine = options.templateEngine || Email.defaults.templateEngine;
	this.templateBasePath = options.templateBasePath || Email.defaults.templateBasePath;

	if (!this.templateName) {
		throw new ErrorNoEmailtemplateName();
	}

	return this;

};

/**
 * Renders the email and passes it to the callback. Used by `email.send()` but
 * can also be called directly to generate a preview.
 *
 * @param {Object} locals - object of local variables provided to the template
 * @param {Function} callback(err, email)
 *
 * @api public
 */

Email.prototype.render = function(locals, callback) {

	if ('function' === typeof locals && !callback) {
		callback = locals;
		locals = {};
	}

	locals = ('object' === typeof locals) ? locals : {};
	callback = ('function' === typeof callback) ? callback : function() {};

	if (keystone.get('email locals')) {
		_.defaults(locals, keystone.get('email locals'));
	}

	_.defaults(locals, {
		pretty: true,
		_: _,
		moment: moment,
		utils: utils,
		subject: '(no subject)',
		brand: keystone.get('brand'),
		theme: {},
		css: templateCSSMethods
	});

	if (!locals.theme.buttons) {
		locals.theme.buttons = {};
	}

	this.compileTemplate(function(err) {

		if (err) {
			return callback(err);
		}

		var html = templateCache[this.templateName](locals);

		// ensure extended characters are replaced
		html = html.replace(/[\u007f-\uffff]/g, function(c) {
			return '&#x'+('0000'+c.charCodeAt(0).toString(16)).slice(-4)+';';
		});

		// process email rules
		var rules = keystone.get('email rules');

		if (rules) {

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

			_.each(rules, function(rule) {
				if (rule.find && rule.replace) {

					var find = rule.find,
						replace = rule.replace;

					if ('string' === typeof find) {
						find = new RegExp(find, 'gi');
					}

					html = html.replace(find, replace);
				}
			});

		}

		callback(null, {
			subject: locals.subject,
			html: html
		});

	}.bind(this));

};

/**
 * Loads the template. Looks for `templateName.templateExt`, followed by `templateName/email.templateExt`
 *
 * @param {Function} callback(err)
 *
 * @api private
 */

Email.prototype.loadTemplate = function(callback) {

	var fsTemplatePath = path.join(Email.getEmailsPath(), this.templateName + '.' + this.templateExt);

	fs.readFile(fsTemplatePath, function(err, contents) {

		if (err) {
			if (err.code === 'ENOENT') {

				fsTemplatePath = path.join(Email.getEmailsPath(), this.templateName, 'email.' + this.templateExt);

				fs.readFile(fsTemplatePath, function(err, contents) {
					callback(err, fsTemplatePath, contents);
				});

			} else {
				return callback(err);
			}
		} else {
			return callback(err, fsTemplatePath, contents);
		}

	}.bind(this));

};

/**
 * Ensures the template for the email has been compiled
 *
 * @param {Function} callback(err)
 *
 * @api private
 */

Email.prototype.compileTemplate = function(callback) {

	if (keystone.get('env') === 'production' && templateCache[this.templateName]) {
		return process.nextTick(callback);
	}

	this.loadTemplate(function(err, filename, contents) {

		if (err) return callback(err);

		var template = this.templateEngine.compile(contents.toString(), Email.defaults.compilerOptions || { filename: fs.realpathSync(filename), basedir: this.templateBasePath });

		templateCache[this.templateName] = template;

		callback();

	}.bind(this));

};

/**
 * Prepares the email and sends it
 *
 * Options:
 *
 * - mandrill
 *   Initialised Mandrill API instance
 *
 * - tags
 *   Array of tags to send to Mandrill
 *
 * - to
 *   Object / String or Array of Objects / Strings to send to, e.g.
 *   ['jed@team9.com.au', { email: 'jed.watson@gmail.com' }]
 *   { email: 'jed@team9.com.au' }
 *   'jed@team9.com.au'
 *
 * - fromName
 *   Name to send from
 *
 * - fromEmail
 *   Email address to send from
 *
 * For compatibility with older implementations, send supports providing
 * locals and options objects as the first and second arguments, and the
 * callback as the third.
 *
 * @param {Object} options (passed to `email.render()`)
 * @param {Function} callback(err, info)
 *
 * @api private
 */

Email.prototype.send = function(options, callback) {

	var locals = options;

	if (arguments.length === 3 || !utils.isFunction(callback)) {
		callback = arguments[2];
		options = arguments[1] || arguments[0];
	}

	this.render(locals, function(err, email) {

		callback = ('function' === typeof callback) ? callback : function() {};

		if (err) {
			return callback(err);
		}

		if (!utils.isObject(options)) {
			return callback({
				from: 'Email.send',
				key: 'invalid options',
				message: 'options object is required'
			});
		}

		if ('string' === typeof options.from) {
			options.fromName = options.from;
			options.fromEmail = options.from;
		} else if (utils.isObject(options.from)) {
			options.fromName = utils.isObject(options.from.name) ? options.from.name.full : options.from.name;
			options.fromEmail = options.from.email;
		}

		if (!options.fromName || !options.fromEmail) {
			return callback({
				from: 'Email.send',
				key: 'invalid options',
				message: 'options.fromName and options.fromEmail are required'
			});
		}

		if (!options.mandrill) {
			if (!keystone.get('mandrill api key'))
				return callback({
					from: 'Email.send',
					key: 'missing api key',
					message: 'You must either provide a Mandrill API Instance or set the mandrill api key before sending email.'
				});
			options.mandrill = new mandrillapi.Mandrill(keystone.get('mandrill api key'));
		}

		options.tags = utils.isArray(options.tags) ? options.tags : [];
		options.tags.push('sent:' + moment().format('YYYY-MM-DD'));
		options.tags.push(this.templateName);

		if (keystone.get('env') === 'development') {
			options.tags.push('development');
		}

		var recipients = [],
			mergeVars = [];

		options.to = Array.isArray(options.to) ? options.to : [options.to];

		for (var i = 0; i < options.to.length; i++) {

			if ('string' === typeof options.to[i]) {
				options.to[i] = { email: options.to[i] };
			} else if ('object' === typeof options.to[i]) {
				if (!options.to[i].email) {
					return callback({
						from: 'Email.send',
						key: 'invalid recipient',
						message: 'Recipient ' + (i + 1) + ' does not have a valid email address.'
					});
				}
			} else {
				return callback({
					from: 'Email.send',
					key: 'invalid recipient',
					message: 'Recipient ' + (i + 1) + ' is not a string or an object.'
				});
			}

			var recipient = { email: options.to[i].email },
				vars = [{ name: 'email', content: recipient.email }];

			if ('string' === typeof options.to[i].name) {
				recipient.name = options.to[i].name;
				vars.push({ name: 'name', content: options.to[i].name });
			} else if ('object' === typeof options.to[i].name) {
				recipient.name = options.to[i].name.full || '';
				vars.push({ name: 'name', content: options.to[i].name.full || '' });
				vars.push({ name: 'first_name', content: options.to[i].name.first || '' });
				vars.push({ name: 'last_name', content: options.to[i].name.last || '' });
			}

			recipients.push(recipient);

			mergeVars.push({
				rcpt: recipient.email,
				vars: vars
			});
		}

		var onSuccess = function(info) {
			callback(null, info);
		};

		var onFail = function(info) {
			callback({
				from: 'Email.send',
				key: 'send error',
				message: 'Mandrill encountered an error and did not send the emails.',
				info: info
			});
		};

		var message = {
			html: email.html,
			subject: email.subject,
			from_name: options.fromName,
			from_email: options.fromEmail,
			tags: options.tags,
			attachments: options.attachments,
			to: recipients,
			merge_vars: mergeVars,
			async: true
		};

		_.defaults(message, options.mandrillOptions);
		_.defaults(message, Email.defaults.mandrill);

		return process.nextTick(function() {
			options.mandrill.messages.send({ message: message }, onSuccess, onFail);
		});

	}.bind(this));

};

Email.getEmailsPath = getEmailsPath;
Email.templateCache = templateCache;
Email.templateCSSMethods = templateCSSMethods;
Email.defaults = defaultConfig;

exports = module.exports = Email;
<|endoftext|>